diff --git a/.gitignore b/.gitignore
index c2b14e19..f50b7cbd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,8 @@ src/*.vsproj/*/Release/
src/*.vsproj/Debug/
src/*.vsproj/Release/
src/*.vsproj/*/ipch/
+# Output files to work around VS's lack of output within the IDE
+bladeslog.txt
# Shader Builder projects
# It's an sqlite3 database and not particularly important, so exclude it
@@ -53,3 +55,6 @@ src/tools/*.sbproj
# Doxygen stuff
src/doxy/html/
src/doxy/doxy_warnings.txt
+
+# Windows junk files
+Thumbs.db
diff --git a/src/BoE.vsproj/Common/Common.vcxproj b/src/BoE.vsproj/Common/Common.vcxproj
index 4a856cce..7b100016 100644
--- a/src/BoE.vsproj/Common/Common.vcxproj
+++ b/src/BoE.vsproj/Common/Common.vcxproj
@@ -11,6 +11,7 @@
+
@@ -45,6 +46,7 @@
+
@@ -96,16 +98,19 @@
+
+
+
{1347FE79-73BD-4176-9280-0FE39E3534E2}
@@ -146,6 +151,7 @@
..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;%(AdditionalIncludeDirectories)
false
/FS %(AdditionalOptions)
+ 4800;4290
Windows
@@ -153,6 +159,10 @@
opengl32.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;sfml-audio.lib;zlib.lib;%(AdditionalDependencies)
false
+
+ call $(ProjectDir)CopyFiles.bat $(SolutionDir)$(Configuration)
+ Copy resource files
+
diff --git a/src/BoE.vsproj/Common/Common.vcxproj.filters b/src/BoE.vsproj/Common/Common.vcxproj.filters
index 6af471e9..9b4dea7a 100644
--- a/src/BoE.vsproj/Common/Common.vcxproj.filters
+++ b/src/BoE.vsproj/Common/Common.vcxproj.filters
@@ -194,6 +194,12 @@
Tools\Header Files
+
+ Classes
+
+
+ Classes
+
@@ -322,5 +328,14 @@
Tools\Source Files
+
+ Tools\Source Files
+
+
+ Tools\Source Files
+
+
+ Tools\Source Files
+
\ No newline at end of file
diff --git a/src/BoE.vsproj/Common/CopyFiles.bat b/src/BoE.vsproj/Common/CopyFiles.bat
new file mode 100644
index 00000000..fe167814
--- /dev/null
+++ b/src/BoE.vsproj/Common/CopyFiles.bat
@@ -0,0 +1,31 @@
+
+@echo off
+echo Copying files...
+set ResourceDir=%1\..\..\..\rsrc
+set TargetDir=%1
+set ScenEdDir=%TargetDir%\"Scenario Editor"
+@echo on
+
+@echo Copying graphics...
+xcopy %ResourceDir%\graphics.exd %ScenEdDir%\graphics.exd /s /y /i /d
+
+@echo Copying sound effects...
+xcopy %ResourceDir%\sounds.exa %ScenEdDir%\sounds.exa /s /y /i /d
+
+@echo Copying dialog definitions...
+xcopy %ResourceDir%\dialogs\*.xml %TargetDir%\data\dialogs /s /y /i /d
+
+@echo Copying fonts...
+xcopy %ResourceDir%\fonts %TargetDir%\data\fonts /s /y /i /d
+
+@echo Copying string lists...
+xcopy %ResourceDir%\strings %TargetDir%\data\strings /s /y /i /d
+
+@echo Copying shaders...
+xcopy %1\..\..\tools\mask.* %TargetDir%\data\shaders /s /y /i /d
+
+@echo Copying base scenarios...
+xcopy %ResourceDir%\"Blades of Exile Bases" %ScenEdDir%\"Blades of Exile Base" /s /y /i /d
+
+@echo Copying scenario files...
+xcopy %ResourceDir%\"Blades of Exile Scenarios" %TargetDir%\"Blades of Exile Scenarios" /s /y /i /d
\ No newline at end of file
diff --git a/src/BoE.vsproj/Game/Blades of Exile.rc b/src/BoE.vsproj/Game/Blades of Exile.rc
index 02a7f919..424b32e2 100644
Binary files a/src/BoE.vsproj/Game/Blades of Exile.rc and b/src/BoE.vsproj/Game/Blades of Exile.rc differ
diff --git a/src/BoE.vsproj/Game/Blades of Exile.vcxproj b/src/BoE.vsproj/Game/Blades of Exile.vcxproj
index 225e595e..04f42e95 100644
--- a/src/BoE.vsproj/Game/Blades of Exile.vcxproj
+++ b/src/BoE.vsproj/Game/Blades of Exile.vcxproj
@@ -53,14 +53,18 @@
WIN32;_DEBUG;_WINDOWS;TIXML_USE_TICPP;%(PreprocessorDefinitions)
- ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;%(AdditionalIncludeDirectories)
+ ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;.;%(AdditionalIncludeDirectories)
+ 4800;4290
Windows
true
- opengl32.lib;sfml-system.lib;sfml-window.lib;sfml-graphics.lib;sfml-audio.lib;zlib.lib;%(AdditionalDependencies)
+ opengl32.lib;sfml-system-d.lib;sfml-window-d.lib;sfml-graphics-d.lib;sfml-audio-d.lib;zlib.lib;%(AdditionalDependencies)
mainCRTStartup
+
+ ..;%(AdditionalIncludeDirectories)
+
@@ -124,6 +128,7 @@
+
diff --git a/src/BoE.vsproj/Game/Blades of Exile.vcxproj.filters b/src/BoE.vsproj/Game/Blades of Exile.vcxproj.filters
index 7f56b160..c3f1d780 100644
--- a/src/BoE.vsproj/Game/Blades of Exile.vcxproj.filters
+++ b/src/BoE.vsproj/Game/Blades of Exile.vcxproj.filters
@@ -159,5 +159,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/src/BoE.vsproj/Game/Resource.h b/src/BoE.vsproj/Game/Resource.h
index 56170d5c..bc686d36 100644
--- a/src/BoE.vsproj/Game/Resource.h
+++ b/src/BoE.vsproj/Game/Resource.h
@@ -2,30 +2,51 @@
// Microsoft Visual C++ generated include file.
// Used by Blades of Exile.rc
//
+#define IDI_BLADESOFEXILE 107
+#define IDC_BLADESOFEXILE 109
+#define IDM_FILE_OPEN 110
+#define IDM_FILE_SAVE 111
+#define IDM_FILE_SAVE_AS 112
+#define IDM_FILE_NEW 113
+#define IDM_FILE_PREFS 114
+#define IDM_FILE_QUIT 115
+#define IDM_OPTIONS_GRAPHIC 116
+#define IDM_OPTIONS_NAME 117
+#define IDM_OPTIONS_NEW 118
+#define IDM_OPTIONS_DELETE 119
+#define IDM_OPTIONS_TALKING 120
+#define IDM_OPTIONS_ENCOUNTER 121
+#define IDM_OPTIONS_STATS 122
+#define IDM_ACTIONS_ALCHEMY 123
+#define IDM_ACTIONS_WAIT 124
+#define IDM_ACTIONS_MAP 125
+#define IDM_MONSTERS_ABOUT 126
+#define IDM_MAGE_ABOUT 127
+#define IDM_PRIEST_ABOUT 128
+#define IDM_FILE_ABORT 129
+#define IDM_LIBRARY_MAGE 130
+#define IDM_LIBRARY_PRIEST 131
+#define IDM_LIBRARY_SKILLS 132
+#define IDM_LIBRARY_ALCHEMY 133
+#define IDM_LIBRARY_TIPS 134
+#define IDM_LIBRARY_INTRO 135
+#define IDM_HELP_INDEX 136
+#define IDM_HELP_OUTDOOR 137
+#define IDM_HELP_COMBAT 138
+#define IDM_HELP_BARRIER 139
+#define IDM_HELP_HINTS 140
+#define IDM_HELP_SPELLS 141
+#define IDM_HELP_ABOUT 142
+#define IDM_HELP_TOWN 143
-#define IDS_APP_TITLE 103
-
-#define IDR_MAINFRAME 128
-#define IDD_BLADESOFEXILE_DIALOG 102
-#define IDD_ABOUTBOX 103
-#define IDM_ABOUT 104
-#define IDM_EXIT 105
-#define IDI_BLADESOFEXILE 107
-#define IDI_SMALL 108
-#define IDC_BLADESOFEXILE 109
-#define IDC_MYICON 2
-#ifndef IDC_STATIC
-#define IDC_STATIC -1
-#endif
// Next default values for new objects
-//
+//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-
-#define _APS_NO_MFC 130
-#define _APS_NEXT_RESOURCE_VALUE 129
-#define _APS_NEXT_COMMAND_VALUE 32771
-#define _APS_NEXT_CONTROL_VALUE 1000
-#define _APS_NEXT_SYMED_VALUE 110
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32774
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 145
#endif
#endif
diff --git a/src/BoE.vsproj/PcEdit/Char Editor.vcxproj b/src/BoE.vsproj/PcEdit/Char Editor.vcxproj
index cc54f084..57a7c927 100644
--- a/src/BoE.vsproj/PcEdit/Char Editor.vcxproj
+++ b/src/BoE.vsproj/PcEdit/Char Editor.vcxproj
@@ -41,6 +41,7 @@
true
+ $(SolutionDir)$(Configuration)\Scenario Editor\
false
@@ -52,7 +53,8 @@
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;TIXML_USE_TICPP;%(PreprocessorDefinitions)
- ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;%(AdditionalIncludeDirectories)
+ ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;.;%(AdditionalIncludeDirectories)
+ 4800;4290
Windows
@@ -84,6 +86,7 @@
+
diff --git a/src/BoE.vsproj/PcEdit/Char Editor.vcxproj.filters b/src/BoE.vsproj/PcEdit/Char Editor.vcxproj.filters
index 0402c0a4..a30cd1b2 100644
--- a/src/BoE.vsproj/PcEdit/Char Editor.vcxproj.filters
+++ b/src/BoE.vsproj/PcEdit/Char Editor.vcxproj.filters
@@ -30,6 +30,9 @@
Source Files
+
+ Source Files
+
diff --git a/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj b/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj
index b3ef575e..577f694f 100644
--- a/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj
+++ b/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj
@@ -41,6 +41,7 @@
true
+ $(SolutionDir)$(Configuration)\Scenario Editor\
false
@@ -52,7 +53,8 @@
Level3
Disabled
WIN32;_DEBUG;_WINDOWS;TIXML_USE_TICPP;%(PreprocessorDefinitions)
- ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;%(AdditionalIncludeDirectories)
+ ..\..\tools\resmgr;..\..\tools\gzstream;..\..\tools;..\..\dialogxml\xml-parser;..\..\dialogxml;..\..\classes;..\..;.;%(AdditionalIncludeDirectories)
+ 4800;4290
Windows
@@ -89,6 +91,7 @@
+
diff --git a/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj.filters b/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj.filters
index b9437549..5f4b11d3 100644
--- a/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj.filters
+++ b/src/BoE.vsproj/ScenEdit/Scen Editor.vcxproj.filters
@@ -44,6 +44,9 @@
Source Files
+
+ Source Files
+
diff --git a/src/boe.actions.cpp b/src/boe.actions.cpp
index bbfebf62..59d689ee 100644
--- a/src/boe.actions.cpp
+++ b/src/boe.actions.cpp
@@ -81,7 +81,8 @@ long dummy;
short store_selling_values[8] = {0,0,0,0,0,0,0,0};
extern cShop active_shop;
-extern short cen_x, cen_y, stat_window,give_delays;//,pc_moves[6];
+extern short cen_x, cen_y, stat_window;//,pc_moves[6];
+extern bool give_delays;
extern eGameMode overall_mode;
extern location to_create;
extern bool All_Done,play_sounds,frills_on,spell_forced,save_maps,monsters_going;
diff --git a/src/boe.fileio.cpp b/src/boe.fileio.cpp
index e8e95b7a..e7443aec 100644
--- a/src/boe.fileio.cpp
+++ b/src/boe.fileio.cpp
@@ -27,7 +27,8 @@
#define DONE_BUTTON_ITEM 1
-extern short give_delays,stat_screen_mode;
+extern short stat_screen_mode;
+extern bool give_delays;
extern eGameMode overall_mode;
extern bool play_sounds,sys_7_avail,save_maps,party_in_memory,in_scen_debug,ghost_mode;
extern location center;
diff --git a/src/boe.graphics.cpp b/src/boe.graphics.cpp
index 59805cff..69584272 100644
--- a/src/boe.graphics.cpp
+++ b/src/boe.graphics.cpp
@@ -29,7 +29,8 @@
#include "boe.menus.h"
extern sf::RenderWindow mainPtr;
-extern short stat_window,give_delays;
+extern short stat_window;
+extern bool give_delays;
extern eGameMode overall_mode;
extern short current_spell_range;
extern bool anim_onscreen,play_sounds,frills_on,startup_loaded,party_in_memory;
@@ -167,6 +168,7 @@ void adjust_window_mode() {
sf::ContextSettings winSettings;
winSettings.stencilBits = 1;
sf::VideoMode desktop = sf::VideoMode::getDesktopMode();
+ hideMenuBar();
// TODO: Make display_mode an enum
if(display_mode == 5) {
@@ -194,6 +196,8 @@ void adjust_window_mode() {
item_sbar->relocate({ul.x + 546,ul.y + 146});
shop_sbar->relocate({ul.x + 258,ul.y + 67});
}
+ init_menubar();
+ showMenuBar();
}
// TODO: Move to boe.startup.cpp
diff --git a/src/boe.graphutil.cpp b/src/boe.graphutil.cpp
index 837487ea..cccfd2e3 100644
--- a/src/boe.graphutil.cpp
+++ b/src/boe.graphutil.cpp
@@ -23,7 +23,8 @@
extern sf::RenderWindow mainPtr;
extern rectangle windRect;
-extern short stat_window,give_delays;
+extern short stat_window;
+extern bool give_delays;
extern eGameMode overall_mode;
extern short current_spell_range;
extern bool anim_onscreen,play_sounds,frills_on,startup_loaded;
diff --git a/src/boe.main.cpp b/src/boe.main.cpp
index 49ce2b77..63912c1d 100644
--- a/src/boe.main.cpp
+++ b/src/boe.main.cpp
@@ -28,6 +28,7 @@
#include "scrollbar.hpp"
#include "boe.menus.h"
#include "cursors.h"
+#include "prefs.hpp"
extern cursor_type arrow_curs[3][3];
extern cursor_type current_cursor;
@@ -91,7 +92,7 @@ eGameMode overall_mode = MODE_STARTUP;
bool first_update = true,anim_onscreen = false,frills_on = true,changed_display_mode = false,suppress_stat_screen = false;
short stat_window = 0,store_modifier;
bool monsters_going = false,boom_anim_active = false;
-short give_delays = 0;
+bool give_delays = false;
sf::RenderWindow mini_map;
//rectangle d_rects[80];
@@ -145,6 +146,7 @@ int main(int /*argc*/, char* argv[]) {
init_directories(argv[0]);
//data_store = (piles_of_stuff_dumping_type *) NewPtr(sizeof(piles_of_stuff_dumping_type));
init_menubar(); // Do this first of all because otherwise a default File and Window menu will be seen
+ sync_prefs();
init_graph_tool();
Initialize();
init_fileio();
@@ -427,19 +429,9 @@ void Mouse_Pressed() {
void close_program() {
// TODO: Ultimately we would like to have cleanup happen automatically, negating the need for this function
//end_music();
-}
-
-void handle_apple_menu(int item_hit) {
-
- switch(item_hit) {
- case 1:
- cChoiceDlog("about-boe").show();
- break;
- default:
-// GetItem (apple_menu,item_hit,desk_acc_name);
-// desk_acc_num = OpenDeskAcc(desk_acc_name);
- break;
- }
+ // On the Mac, prefs are synced automatically. However, doing it manually won't hurt.
+ // On other platforms, we need to do it manually.
+ sync_prefs();
}
void handle_file_menu(int item_hit) {
@@ -603,6 +595,7 @@ void handle_help_menu(int item_hit) {
case 4: dialogToShow = "help-fields"; break;
case 6: dialogToShow = "help-hints"; break;
case 7: dialogToShow = "help-magic"; break;
+ case 10: dialogToShow = "about-boe"; break;
}
if(!dialogToShow.empty())
cChoiceDlog(dialogToShow).show();
@@ -825,7 +818,7 @@ void pause(short length) {
redraw_screen(REFRESH_NONE);
mainPtr.display();
- if(give_delays == 0)
+ if(give_delays)
sf::sleep(time_in_ticks(len));
}
diff --git a/src/boe.main.h b/src/boe.main.h
index b469f16e..4c109ea6 100644
--- a/src/boe.main.h
+++ b/src/boe.main.h
@@ -7,8 +7,6 @@ void Handle_One_Event();
void Handle_Update();
void Mouse_Pressed();
void close_program();
-//void handle_menu_choice(long choice);
-void handle_apple_menu(int item_hit);
void handle_file_menu(int item_hit);
void handle_options_menu(int item_hit);
void handle_help_menu(int item_hit);
diff --git a/src/boe.menus.mac.mm b/src/boe.menus.mac.mm
index 48927e8f..8d86d8df 100644
--- a/src/boe.menus.mac.mm
+++ b/src/boe.menus.mac.mm
@@ -34,7 +34,6 @@ MenuHandle apple_menu,file_menu,extra_menu,help_menu,monster_info_menu,library_m
MenuHandle actions_menu,music_menu,mage_spells_menu,priest_spells_menu;
@interface MenuHandler : NSObject
--(void) appMenu:(id) sender;
-(void) fileMenu:(id) sender;
-(void) optMenu:(id) sender;
-(void) actMenu:(id) sender;
@@ -104,6 +103,9 @@ static void setMenuCallback(NSMenuItem* item, id targ, SEL selector, int num) {
}
void init_menubar() {
+ static bool inited = false;
+ if(inited) return;
+ inited = true;
NSApplication* app = [NSApplication sharedApplication];
[NSBundle loadNibNamed: @"menu" owner: app];
menu_bar_handle = [app mainMenu];
@@ -120,8 +122,7 @@ void init_menubar() {
MenuHandler* handler = [[[MenuHandler alloc] init] retain];
setMenuCallback([help_menu itemAtIndex: 0], handler, @selector(onlineHelp:), 0);
- // TODO: Do away with "handle_apple_menu" and "appMenu" in favour of pushing "About" to the help menu
- setMenuCallback([apple_menu itemWithTitle: @"About Blades of Exile"], handler, @selector(appMenu:), 1);
+ setMenuCallback([apple_menu itemWithTitle: @"About Blades of Exile"], handler, @selector(helpMenu:), 10);
setMenuCallback([apple_menu itemWithTitle: @"Preferences…"], handler, @selector(fileMenu:), 6);
setMenuCallback([apple_menu itemWithTitle: @"Quit Blades of Exile"], handler, @selector(fileMenu:), 8);
// TODO: Check to make sure that Cocoa 0-indexes its menus
@@ -271,7 +272,6 @@ void menu_activate() {
[[file_menu itemWithTitle: @"Save As…"] setEnabled: YES];
}
-void handle_apple_menu(int item_hit);
void handle_file_menu(int item_hit);
void handle_options_menu(int item_hit);
void handle_help_menu(int item_hit);
@@ -281,10 +281,6 @@ void handle_monster_info_menu(int item_hit);
void handle_menu_spell(eSpell spell_picked);
@implementation MenuHandler
--(void) appMenu:(id) sender {
- handle_apple_menu([[sender representedObject] intValue]);
-}
-
-(void) fileMenu:(id) sender {
handle_file_menu([[sender representedObject] intValue]);
}
diff --git a/src/boe.menus.win.cpp b/src/boe.menus.win.cpp
new file mode 100644
index 00000000..7c6b9a40
--- /dev/null
+++ b/src/boe.menus.win.cpp
@@ -0,0 +1,265 @@
+
+#include "boe.menus.h"
+#include
+#include "Resource.h"
+#include "universe.h"
+#include "boe.party.h"
+#include "boe.infodlg.h"
+#include "boe.consts.h"
+#include "spell.hpp"
+
+// Include this last because some #defines in the Windows headers cause compile errors in my headers.
+// Fortunately they're on symbols not used in this file, so this should work.
+#include
+
+// This is the index of each menu on the menubar
+enum {
+ FILE_MENU_POS = 0,
+ OPT_MENU_POS = 1,
+ ACT_MENU_POS = 2,
+ MONST_MENU_POS = 3,
+ MAGE_MENU_POS = 4,
+ PRIEST_MENU_POS = 5,
+ LIB_MENU_POS = 6,
+ HELP_MENU_POS = 7,
+};
+
+extern short on_spell_menu[2][62];
+extern short on_monst_menu[256];
+extern bool party_in_memory;
+extern short current_pc;
+extern cUniverse univ;
+extern eGameMode overall_mode;
+extern sf::RenderWindow mainPtr;
+LONG_PTR mainProc;
+HMENU menuHandle = NULL;
+
+LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam);
+
+void init_menubar() {
+ HWND winHandle = mainPtr.getSystemHandle();
+ if(winHandle == NULL) return;
+ if(menuHandle == NULL)
+ menuHandle = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDC_BLADESOFEXILE));
+ SetMenu(winHandle, menuHandle);
+ // Now we have to do a little hack to handle menu messages.
+ // We replace SFML's window procedure with our own, which checks for menu events and then forwards to SFML's procedure.
+ mainProc = SetWindowLongPtr(winHandle, GWLP_WNDPROC, reinterpret_cast(&menuProc));
+}
+
+void adjust_monst_menu() {
+ if(menuHandle == NULL) return;
+ short i, monst_pos = 0;
+ HMENU monst_menu;
+
+ if(overall_mode == MODE_STARTUP) return;
+
+ monst_menu = GetSubMenu(menuHandle, MONST_MENU_POS);
+ for(i = 0; i < 256; i++) {
+ on_monst_menu[i] = -1;
+ }
+ for(i = 1; i < 256; i++) {
+ if((i == 1) || (univ.party.m_noted[i] > 0)) {
+ on_monst_menu[monst_pos] = i;
+ monst_pos++;
+ }
+ }
+
+ while(GetMenuItemCount(monst_menu) > 2) {
+ RemoveMenu(monst_menu, 2, MF_BYPOSITION);
+ }
+ for(i = 0; i < 256; i++) {
+ if(on_monst_menu[i] >= 0) {
+ std::string monst_name = univ.scenario.scen_monsters[on_monst_menu[i]].m_name;
+ AppendMenuA(monst_menu, MF_STRING | MF_ENABLED, 1000 + i, monst_name.c_str());
+ }
+ }
+ DrawMenuBar(mainPtr.getSystemHandle());
+}
+
+void init_spell_menus() {
+ short i, j;
+
+ for(i = 0; i < 2; i++)
+ for(j = 0; j < 62; j++)
+ on_spell_menu[i][j] = -1;
+}
+
+void adjust_spell_menus() {
+ if(menuHandle == NULL) return;
+ short i, j, spell_pos = 0;
+ HMENU spell_menu;
+ char spell_name[256];
+ short old_on_spell_menu[2][62];
+ bool need_menu_change = false;
+
+ if(overall_mode == MODE_STARTUP || current_pc == 6)
+ return;
+
+ for(i = 0; i < 2; i++)
+ for(j = 0; j < 62; j++)
+ old_on_spell_menu[i][j] = on_spell_menu[i][j];
+
+ spell_menu = GetSubMenu(menuHandle, MAGE_MENU_POS);
+
+ for(i = 0; i < 62; i++) {
+ on_spell_menu[0][i] = -1;
+ }
+ for(i = 0; i < 62; i++)
+ if(pc_can_cast_spell(current_pc, cSpell::fromNum(eSkill::MAGE_SPELLS, i))) {
+ on_spell_menu[0][spell_pos] = i;
+ spell_pos++;
+ }
+ for(i = 0; i < 62; i++)
+ if(on_spell_menu[0][i] != old_on_spell_menu[0][i])
+ need_menu_change = true;
+ if(need_menu_change) {
+ while(GetMenuItemCount(spell_menu) > 2) {
+ RemoveMenu(spell_menu, 2, MF_BYPOSITION);
+ }
+ for(i = 0; i < 62; i++)
+ if(on_spell_menu[0][i] >= 0) {
+ eSpell spell = cSpell::fromNum(eSkill::MAGE_SPELLS, on_spell_menu[0][i]);
+ std::string name = get_str("magic-names", i + 1);
+ if((*spell).cost >= 0)
+ sprintf(spell_name, " L%d - %s, C %d", (*spell).level, name.c_str(), (*spell).cost);
+ else sprintf(spell_name, " L%d - %s, C ?", (*spell).level, name.c_str());
+ AppendMenuA(spell_menu, MF_STRING | MF_ENABLED, 2000 + i, spell_name);
+ }
+ }
+
+ need_menu_change = false;
+ spell_pos = 0;
+
+ spell_menu = GetSubMenu(menuHandle, PRIEST_MENU_POS);
+
+ for(i = 0; i < 62; i++) {
+ on_spell_menu[1][i] = -1;
+ }
+ for(i = 0; i < 62; i++)
+ if(pc_can_cast_spell(current_pc, cSpell::fromNum(eSkill::PRIEST_SPELLS, i))) {
+ on_spell_menu[1][spell_pos] = i;
+ spell_pos++;
+ }
+ for(i = 0; i < 62; i++)
+ if(on_spell_menu[1][i] != old_on_spell_menu[1][i])
+ need_menu_change = true;
+ if(need_menu_change) {
+ while(GetMenuItemCount(spell_menu) > 2) {
+ RemoveMenu(spell_menu, 2, MF_BYPOSITION);
+ }
+ for(i = 0; i < 62; i++)
+ if(on_spell_menu[1][i] >= 0) {
+ eSpell spell = cSpell::fromNum(eSkill::MAGE_SPELLS, on_spell_menu[1][i]);
+ std::string name = get_str("magic-names", i + 101);
+ if((*spell).cost >= 0)
+ sprintf(spell_name, " L%d - %s, C %d", (*spell).level, name.c_str(), (*spell).cost);
+ else sprintf(spell_name, " L%d - %s, C ?", (*spell).level, name.c_str());
+ AppendMenuA(spell_menu, MF_STRING | MF_ENABLED, 2000 + i, spell_name);
+ }
+ }
+
+
+}
+
+void menu_activate() {
+ if(menuHandle == NULL) return;
+ HMENU file_menu = GetSubMenu(menuHandle, FILE_MENU_POS);
+ if(overall_mode == MODE_STARTUP) {
+ EnableMenuItem(menuHandle, OPT_MENU_POS, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, MONST_MENU_POS, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, ACT_MENU_POS, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, MAGE_MENU_POS, MF_GRAYED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, PRIEST_MENU_POS, MF_GRAYED | MF_BYPOSITION);
+
+ EnableMenuItem(file_menu, IDM_FILE_SAVE, MF_GRAYED | MF_BYCOMMAND);
+ if(!party_in_memory) {
+ EnableMenuItem(file_menu, IDM_FILE_SAVE_AS, MF_GRAYED | MF_BYCOMMAND);
+ } else {
+ EnableMenuItem(file_menu, IDM_FILE_SAVE_AS, MF_ENABLED | MF_BYCOMMAND);
+ }
+ } else {
+ EnableMenuItem(menuHandle, OPT_MENU_POS, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, MONST_MENU_POS, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, ACT_MENU_POS, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, MAGE_MENU_POS, MF_ENABLED | MF_BYPOSITION);
+ EnableMenuItem(menuHandle, PRIEST_MENU_POS, MF_ENABLED | MF_BYPOSITION);
+
+ EnableMenuItem(file_menu, IDM_FILE_SAVE, MF_ENABLED | MF_BYCOMMAND);
+ EnableMenuItem(file_menu, IDM_FILE_SAVE_AS, MF_ENABLED | MF_BYCOMMAND);
+ }
+ DrawMenuBar(mainPtr.getSystemHandle());
+}
+
+void hideMenuBar() {
+ SetMenu(mainPtr.getSystemHandle(), NULL);
+ DrawMenuBar(mainPtr.getSystemHandle());
+}
+
+void showMenuBar() {
+ SetMenu(mainPtr.getSystemHandle(), menuHandle);
+ DrawMenuBar(mainPtr.getSystemHandle());
+}
+
+void handle_file_menu(int item_hit);
+void handle_options_menu(int item_hit);
+void handle_help_menu(int item_hit);
+void handle_library_menu(int item_hit);
+void handle_actions_menu(int item_hit);
+void handle_monster_info_menu(int item_hit);
+void handle_menu_spell(eSpell spell_picked);
+
+LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) {
+ if(message == WM_COMMAND) {
+ int cmd = LOWORD(wParam);
+ if(cmd >= 1000 && cmd < 2000) {
+ handle_monster_info_menu(cmd - 1000);
+ } else if(cmd >= 2000 && cmd < 3000) {
+ handle_menu_spell(cSpell::fromNum(eSkill::MAGE_SPELLS, cmd - 2000));
+ } else if(cmd >= 3000 && cmd < 4000) {
+ handle_menu_spell(cSpell::fromNum(eSkill::PRIEST_SPELLS, cmd - 3000));
+ } else switch(cmd) {
+ // File menu
+ case IDM_FILE_NEW: handle_file_menu(4); break;
+ case IDM_FILE_OPEN: handle_file_menu(1); break;
+ case IDM_FILE_ABORT: handle_file_menu(0); break;
+ case IDM_FILE_SAVE: handle_file_menu(2); break;
+ case IDM_FILE_SAVE_AS: handle_file_menu(3); break;
+ case IDM_FILE_PREFS: handle_file_menu(6); break;
+ case IDM_FILE_QUIT: handle_file_menu(8); break;
+ // Options menu
+ case IDM_OPTIONS_GRAPHIC: handle_options_menu(1); break;
+ case IDM_OPTIONS_NAME: handle_options_menu(2); break;
+ case IDM_OPTIONS_NEW: handle_options_menu(3); break;
+ case IDM_OPTIONS_DELETE: handle_options_menu(4); break;
+ case IDM_OPTIONS_TALKING: handle_options_menu(6); break;
+ case IDM_OPTIONS_ENCOUNTER: handle_options_menu(7); break;
+ case IDM_OPTIONS_STATS: handle_options_menu(8); break;
+ // Actions menu
+ case IDM_ACTIONS_ALCHEMY: handle_actions_menu(1); break;
+ case IDM_ACTIONS_WAIT: handle_actions_menu(2); break;
+ case IDM_ACTIONS_MAP: handle_actions_menu(3); break;
+ // Monster/Spell menu About items
+ case IDM_MONSTERS_ABOUT: break;
+ case IDM_MAGE_ABOUT: give_help(209, 0); break;
+ case IDM_PRIEST_ABOUT: give_help(209, 0); break;
+ // Library menu
+ case IDM_LIBRARY_MAGE: handle_library_menu(1); break;
+ case IDM_LIBRARY_PRIEST: handle_library_menu(2); break;
+ case IDM_LIBRARY_ALCHEMY: handle_library_menu(3); break;
+ case IDM_LIBRARY_SKILLS: handle_library_menu(4); break;
+ case IDM_LIBRARY_TIPS: handle_library_menu(5); break;
+ case IDM_LIBRARY_INTRO: handle_library_menu(7); break;
+ // Help menu
+ case IDM_HELP_INDEX: ShellExecuteA(NULL, "open", "https://calref.net/~sylae/boe-doc/game/Contents.html", NULL, NULL, SW_SHOWNORMAL); break;
+ case IDM_HELP_ABOUT: handle_help_menu(10); break;
+ case IDM_HELP_OUTDOOR: handle_help_menu(1); break;
+ case IDM_HELP_TOWN: handle_help_menu(2); break;
+ case IDM_HELP_COMBAT: handle_help_menu(3); break;
+ case IDM_HELP_BARRIER: handle_help_menu(4); break;
+ case IDM_HELP_HINTS: handle_help_menu(6); break;
+ case IDM_HELP_SPELLS: handle_help_menu(7); break;
+ }
+ }
+ return CallWindowProc(reinterpret_cast(mainProc), handle, message, wParam, lParam);
+}
diff --git a/src/boe.party.cpp b/src/boe.party.cpp
index b0c0588c..983a121c 100644
--- a/src/boe.party.cpp
+++ b/src/boe.party.cpp
@@ -242,7 +242,7 @@ void put_party_in_scen(std::string scen_name) {
bool item_took = false;
for(j = 0; j < 6; j++) {
- univ.party[i].status.clear();
+ univ.party[j].status.clear();
if(isSplit(univ.party[j].main_status))
univ.party[j].main_status -= eMainStatus::SPLIT;
univ.party[j].cur_health = univ.party[j].max_health;
diff --git a/src/classes/location.cpp b/src/classes/location.cpp
index 52878f76..179984c6 100644
--- a/src/classes/location.cpp
+++ b/src/classes/location.cpp
@@ -73,7 +73,13 @@ rectangle::rectangle() : top(0), left(0), right(0), bottom(0) {}
rectangle::rectangle(location tl, location br) : top(tl.y), left(tl.x), right(br.x), bottom(br.y) {}
rectangle::rectangle(int t, int l, int b, int r) : top(t), left(l), right(r), bottom(b) {}
rectangle::rectangle(sf::Texture& texture) : top(0), left(0), right(texture.getSize().x), bottom(texture.getSize().y) {}
-rectangle::rectangle(sf::RenderTarget& texture) : top(0), left(0), right(texture.getSize().x), bottom(texture.getSize().y) {}
+rectangle::rectangle(sf::RenderTarget& texture) : top(0), left(0), right(texture.getSize().x), bottom(texture.getSize().y) {
+ // This is a hack to work around the menubar in Windows affecting the rect returned by getSize(), despite the available area being unchanged.
+ extern sf::RenderWindow mainPtr;
+ extern int getMenubarHeight();
+ if(&texture == &mainPtr)
+ bottom += getMenubarHeight();
+}
bool rectangle::contains(location p){
if(p.y >= top && p.y <= bottom && p.x >= left && p.x <= right)
diff --git a/src/classes/regtown.cpp b/src/classes/regtown.cpp
index 55b07e5b..b55845eb 100644
--- a/src/classes/regtown.cpp
+++ b/src/classes/regtown.cpp
@@ -294,6 +294,7 @@ cBigTown::cBigTown(cScenario& scenario, bool init_strings) : cTown(scenario, ini
terrain(i,j) = scenario.default_ground * 2;
lighting(i / 8,j) = 0;
}
+ init_start();
}
cMedTown::cMedTown(cScenario& scenario, bool init_strings) : cTown(scenario, init_strings) {
@@ -310,6 +311,7 @@ cMedTown::cMedTown(cScenario& scenario, bool init_strings) : cTown(scenario, ini
terrain(i,j) = scenario.default_ground * 2;
lighting(i / 8,j) = 0;
}
+ init_start();
}
cTinyTown::cTinyTown(cScenario& scenario, bool init_strings) : cTown(scenario, init_strings) {
@@ -326,6 +328,7 @@ cTinyTown::cTinyTown(cScenario& scenario, bool init_strings) : cTown(scenario, i
terrain(i,j) = scenario.default_ground * 2;
lighting(i / 8,j) = 0;
}
+ init_start();
}
short cBigTown::max_dim() const {
diff --git a/src/classes/town.cpp b/src/classes/town.cpp
index ef8f0a8e..9e842379 100644
--- a/src/classes/town.cpp
+++ b/src/classes/town.cpp
@@ -79,9 +79,8 @@ void cTown::append(legacy::town_record_type& old){
strong_barriers = defy_scrying = defy_mapping = false;
}
-short max_dim[3] = {64,48,32};
cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) {
- short i,s;
+ short i;
location d_loc(100,0);
cTown::cWandering d_wan = {0,0,0,0};
cTown::cItem null_item = {loc(),-1,0,0,0,0,0};
@@ -103,19 +102,6 @@ cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) {
exit_locs[i].x = -1;
exit_locs[i].y = -1;
}
-// s = town->max_dim();
- start_locs[0].x = s / 2;
- start_locs[0].y = 4;
- start_locs[2].x = s / 2;
- start_locs[2].y = s - 5;
- start_locs[1].x = s - 5;
- start_locs[1].y = s / 2;
- start_locs[3].x = 4;
- start_locs[3].y = s / 2;
- in_town_rect.top = 3;
- in_town_rect.bottom = s - 4;
- in_town_rect.left = 3;
- in_town_rect.right = s - 4;
for(i = 0; i < 64; i++)
preset_items[i] = null_item;
max_num_monst = 30000;
@@ -175,6 +161,22 @@ cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) {
}
}
+void cTown::init_start() {
+ short s = this->max_dim();
+ start_locs[0].x = s / 2;
+ start_locs[0].y = 4;
+ start_locs[2].x = s / 2;
+ start_locs[2].y = s - 5;
+ start_locs[1].x = s - 5;
+ start_locs[1].y = s / 2;
+ start_locs[3].x = 4;
+ start_locs[3].y = s / 2;
+ in_town_rect.top = 3;
+ in_town_rect.bottom = s - 4;
+ in_town_rect.left = 3;
+ in_town_rect.right = s - 4;
+}
+
void cTown::cWandering::append(legacy::wandering_type old){
monst[0] = old.monst[0];
monst[1] = old.monst[1];
diff --git a/src/classes/town.h b/src/classes/town.h
index e09fcf3e..f86422e8 100644
--- a/src/classes/town.h
+++ b/src/classes/town.h
@@ -128,6 +128,7 @@ public:
virtual short max_dim() const = 0;
virtual short max_monst() const = 0;
virtual short max_items() const = 0;
+ void init_start();
void set_up_lights();
short light_obscurity(short x,short y); // Obscurity function used for calculating lighting
diff --git a/src/dialogxml/dialog.cpp b/src/dialogxml/dialog.cpp
index b82d9142..fb920dca 100644
--- a/src/dialogxml/dialog.cpp
+++ b/src/dialogxml/dialog.cpp
@@ -9,7 +9,6 @@
#include
#include
#include
-#include
#include "dialog.hpp"
#include "graphtool.h"
#include "soundtool.h"
@@ -176,40 +175,19 @@ template<> pair cDialog::parse(Element& who /*pict*/){
return p;
}
-class dlogStringFilter : public boost::iterator_facade {
- friend class boost::iterator_core_access;
-public:
- using value_type = std::string::value_type;
- using iter_type = std::string::iterator;
-private:
- bool found_nl;
- iter_type base;
- bool equal(const dlogStringFilter& other) const {
- return base == other.base;
- }
- value_type dereference() const {
- if(found_nl) return ' ';
- return *base;
- }
- void increment() {
- if(found_nl) {
+string dlogStringFilter(string toFilter) {
+ string filtered;
+ bool found_nl = false;
+ for(char c : toFilter) {
+ if(c == '\n' || c == '\r') found_nl = true;
+ else if(c != '\t' && c != 0) {
+ if(found_nl && !filtered.empty()) filtered += ' ';
found_nl = false;
- return;
- }
- base++;
- while(*base == '\t' || *base == '\n' || *base == '\r') {
- found_nl = found_nl || *base != '\t';
- base++;
+ filtered += c;
}
}
-public:
- // TODO: This currently assumes that a string's end() iterator can be dereferenced (presumably to produce a null terminator).
- // This is a poor assumption (though it seems to work in practice).
- dlogStringFilter(iter_type base) : found_nl(false), base(base) {
- if(*base == '\t' || *base == '\n' || *base == '\r')
- increment();
- }
-};
+ return filtered;
+}
template<> pair cDialog::parse(Element& who /*text*/){
pair p;
@@ -294,7 +272,7 @@ template<> pair cDialog::parse(Element& who /*text*/){
// TODO: De-magic the | character
if(type == TiXmlNode::ELEMENT && val == "br") content += '|'; // because vertical bar is replaced by a newline when drawing strings
else if(type == TiXmlNode::TEXT)
- copy(dlogStringFilter(val.begin()), dlogStringFilter(val.end()), std::inserter(content, content.end()));
+ content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("text",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
@@ -492,7 +470,7 @@ template<> pair cDialog::parse(Element& who /*button*/){
if(content.length() > 0) throw xBadVal("button",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
// p.second->labelWithKey = true;
}else if(type == TiXmlNode::TEXT)
- copy(dlogStringFilter(val.begin()), dlogStringFilter(val.end()), std::inserter(content, content.end()));
+ content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("button",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
@@ -647,7 +625,7 @@ template<> pair cDialog::parse(Element& who /*LED*/){
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
- copy(dlogStringFilter(val.begin()), dlogStringFilter(val.end()), std::inserter(content, content.end()));
+ content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("led",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
@@ -745,7 +723,7 @@ template<> pair cDialog::parse(Element& who /*field*/){
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
- copy(dlogStringFilter(val.begin()), dlogStringFilter(val.end()), std::inserter(content, content.end()));
+ content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("field",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
@@ -1026,11 +1004,13 @@ bool cDialog::sendInput(cKey key) {
void cDialog::run(){
cDialog* formerTop = topWindow;
+ // TODO: The introduction of the static topWindow means I may be able to use this instead of parent->win; do I still need parent?
+ sf::RenderWindow* parentWin = &(parent ? parent->win : mainPtr);
cursor_type former_curs = current_cursor;
set_cursor(sword_curs);
using kb = sf::Keyboard;
kb::Key k;
- cKey key, pendingKey;
+ cKey key, pendingKey = {true};
sf::Event currentEvent;
std::string itemHit = "";
dialogNotToast = true;
@@ -1047,7 +1027,7 @@ void cDialog::run(){
win.setVisible(true);
makeFrontWindow(parent ? parent-> win : mainPtr);
makeFrontWindow(win);
- ModalSession dlog(win);
+ ModalSession dlog(win, *parentWin);
animTimer.restart();
while(dialogNotToast){
draw();
@@ -1197,11 +1177,10 @@ void cDialog::run(){
itemHit.clear();
}
win.setVisible(false);
- // TODO: The introduction of the static topWindow means I may be able to use this instead of parent->win; do I still need parent?
- sf::RenderWindow* parentWin = &(parent ? parent->win : mainPtr);
while(parentWin->pollEvent(currentEvent));
set_cursor(former_curs);
topWindow = formerTop;
+ makeFrontWindow(*parentWin);
}
template void cDialog::handleTabOrder(string& itemHit, Iter begin, Iter end) {
diff --git a/src/pcedit/pc.graphics.cpp b/src/pcedit/pc.graphics.cpp
index 298fa2ce..3ff31c53 100644
--- a/src/pcedit/pc.graphics.cpp
+++ b/src/pcedit/pc.graphics.cpp
@@ -57,7 +57,7 @@ short store_page_on,store_num_i;
// TODO: The duplication of rectangle here shouldn't be necessary...
rectangle ed_buttons_from[2] = {rectangle{0,0,57,57},rectangle{0,57,57,114}};
short current_pressed_button = -1;
-sf::Texture spec_scen_g; // not actually needed; just here to silence compiler because it's reference in fileio.h
+cCustomGraphics spec_scen_g; // not actually needed; just here to silence compiler because it's referenced in fileio.h
// (actually, it WILL be needed eventually; the same is true about most of the rest of these.)
sf::Texture items_gworld,tiny_obj_gworld,fields_gworld,roads_gworld,boom_gworld,missiles_gworld;
sf::Texture monst_gworld[NUM_MONST_SHEETS],terrain_gworld[NUM_TER_SHEETS],anim_gworld,talkfaces_gworld;
diff --git a/src/pcedit/pc.main.cpp b/src/pcedit/pc.main.cpp
index e2ca8f6f..ce89ff0b 100644
--- a/src/pcedit/pc.main.cpp
+++ b/src/pcedit/pc.main.cpp
@@ -67,9 +67,6 @@ short store_flags[3];
//stored_town_maps_type town_maps;
//stored_outdoor_maps_type o_maps;
-/* Display globals */
-short give_delays = 0; /* XXX this wasn't defined anywhere, is this right? -jmr */
-
/* Prototypes */
int main(int argc, char* argv[]);
void Initialize(void);
@@ -100,8 +97,8 @@ char start_name[256];
//MW specified return type was 'void', changed to ISO C style for Carbonisation -jmr
int main(int /*argc*/, char* argv[]) {
try {
- init_menubar();
init_directories(argv[0]);
+ init_menubar();
Initialize();
init_fileio();
init_main_buttons();
diff --git a/src/scenedit/scen.main.cpp b/src/scenedit/scen.main.cpp
index 070e3040..ac982d4f 100644
--- a/src/scenedit/scen.main.cpp
+++ b/src/scenedit/scen.main.cpp
@@ -75,6 +75,8 @@ rectangle right_sbar_rect;
//Changed to ISO C specified argument and return type.
int main(int, char* argv[]) {
try {
+
+ init_directories(argv[0]);
init_menubar();
//outdoor_record_type dummy_outdoor, *store2;
@@ -83,8 +85,6 @@ int main(int, char* argv[]) {
init_current_terrain();
//create_file();
//ExitToShell();
-
- init_directories(argv[0]);
Initialize();
init_fileio();
init_snd_tool();
diff --git a/src/tools/cursors.h b/src/tools/cursors.h
index 2dd9e863..f89f3210 100644
--- a/src/tools/cursors.h
+++ b/src/tools/cursors.h
@@ -10,6 +10,9 @@
#define BOE_CURSORS_H
#include
+#include
+
+namespace fs = boost::filesystem;
enum cursor_type {
wand_curs = 0,
@@ -43,7 +46,7 @@ enum cursor_type {
class Cursor {
void* ptr;
public:
- Cursor(std::string imgPath, float hotSpotX, float hotSpotY);
+ Cursor(fs::path imgPath, float hotSpotX, float hotSpotY);
~Cursor();
void apply();
};
diff --git a/src/tools/cursors.mac.mm b/src/tools/cursors.mac.mm
index 5d6cd8f9..b1cd0c41 100644
--- a/src/tools/cursors.mac.mm
+++ b/src/tools/cursors.mac.mm
@@ -11,23 +11,6 @@
#include
#include "restypes.hpp"
-cursor_type current_cursor = sword_curs;
-cursor_type arrow_curs[3][3] = {
- {NW_curs, N_curs, NE_curs},
- {W_curs,wait_curs,E_curs},
- {SW_curs, S_curs, SE_curs},
-};
-
-const std::string cursors[25] = {
- "wand", "eyedropper", "brush", "spraycan",
- "eraser", "topleft", "bottomright", "hand",
- "NW", "N", "NE",
- "W", "wait", "E",
- "SW", "S", "SE",
- "sword", "boot", "drop", "target",
- "talk", "key", "look", "watch",
-};
-
static NSImage* imageFromURL(CFURLRef url){
CGImageSourceRef imageSource = CGImageSourceCreateWithURL(url, NULL);
CGImageRef theImage = nil;
diff --git a/src/tools/cursors.win.cpp b/src/tools/cursors.win.cpp
new file mode 100644
index 00000000..28b02866
--- /dev/null
+++ b/src/tools/cursors.win.cpp
@@ -0,0 +1,141 @@
+
+#include "cursors.h"
+#include
+#include
+#include
+#include "restypes.hpp"
+
+extern cursor_type current_cursor;
+extern sf::RenderWindow mainPtr;
+
+const std::string cursors[25] = {
+ "wand", "eyedropper", "brush", "spraycan",
+ "eraser", "topleft", "bottomright", "hand",
+ "NW", "N", "NE",
+ "W", "wait", "E",
+ "SW", "S", "SE",
+ "sword", "boot", "drop", "target",
+ "talk", "key", "look", "watch",
+};
+
+static const COLORREF clrMagenta = RGB(255, 0, 255);
+
+// This function adapted from
+// It loads an image from a file and replaces transparency with magenta.
+// This is probably undesirable in the general case, but since we only expect transparent GIFs, it should work out.
+HBITMAP LoadPicture(std::string filename) {
+ sf::Image gif;
+ gif.loadFromFile(filename);
+ HDC dc = CreateCompatibleDC(NULL);
+ HBITMAP bmp = CreateCompatibleBitmap(dc, gif.getSize().x, gif.getSize().y);
+ SelectObject(dc, &bmp);
+ // Not exactly efficient, but it gets the job done.
+ for(int x = 0; x < gif.getSize().x; x++) {
+ for(int y = 0; y < gif.getSize().y; y++) {
+ sf::Color clr = gif.getPixel(x, y);
+ if(clr == sf::Color::Transparent)
+ SetPixel(dc, x, y, clrMagenta);
+ else SetPixel(dc, x, y, RGB(clr.r, clr.g, clr.b));
+ }
+ }
+ DeleteDC(dc);
+ return bmp;
+}
+
+// This function taken from
+void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, HBITMAP& hAndMaskBitmap, HBITMAP& hXorMaskBitmap) {
+ HDC hDC = GetDC(NULL);
+ HDC hMainDC = CreateCompatibleDC(hDC);
+ HDC hAndMaskDC = CreateCompatibleDC(hDC);
+ HDC hXorMaskDC = CreateCompatibleDC(hDC);
+
+ //Get the dimensions of the source bitmap
+ BITMAP bm;
+ GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
+
+ hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
+ hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight);
+
+ //Select the bitmaps to DC
+ HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
+ HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
+ HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
+
+ //Scan each pixel of the souce bitmap and create the masks
+ COLORREF MainBitPixel;
+ for(int x = 0; x(cursors[which_c]);
+ curs.apply();
+ }
+}
+
+void restore_cursor() {
+ set_cursor(current_cursor);
+}
diff --git a/src/tools/fileio.cpp b/src/tools/fileio.cpp
index 880b82a9..b2c7171e 100644
--- a/src/tools/fileio.cpp
+++ b/src/tools/fileio.cpp
@@ -22,6 +22,7 @@
#include "porting.h"
#include "restypes.hpp"
#include "tarball.hpp"
+#include "cursors.h"
bool cur_scen_is_mac = true, mac_is_intel;
extern sf::Texture items_gworld,tiny_obj_gworld,fields_gworld,roads_gworld,boom_gworld,missiles_gworld;
@@ -43,6 +44,14 @@ static bool load_town_talk(fs::path town_base, short which_town, cSpeech& the_ta
static bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port);
static bool load_party_v2(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there);
+// Cursors included here so that they needn't be unnecessarily duplicated in platform-specific files
+cursor_type current_cursor = sword_curs;
+cursor_type arrow_curs[3][3] = {
+ {NW_curs, N_curs, NE_curs},
+ {W_curs, wait_curs, E_curs},
+ {SW_curs, S_curs, SE_curs},
+};
+
#include
void init_directories(const char* exec_path) {
@@ -54,7 +63,7 @@ void init_directories(const char* exec_path) {
#endif
progDir = progDir.parent_path();
if(progDir.filename() == "Scenario Editor") progDir = progDir.parent_path();
- std::cout << progDir << '\n';
+ std::cout << progDir << std::endl;
// Initialize the resource manager paths
ResMgr::pushPath(progDir/"Scenario Editor"/"graphics.exd"/"mac");
ResMgr::pushPath(progDir/"Scenario Editor"/"graphics.exd"/"mac"/"cursors");
diff --git a/src/tools/graphtool.cpp b/src/tools/graphtool.cpp
index 465ec518..deff6193 100644
--- a/src/tools/graphtool.cpp
+++ b/src/tools/graphtool.cpp
@@ -68,7 +68,7 @@ void init_graph_tool(){
fin.read(vbuf, size);
if(!maskShader.loadFromMemory(vbuf, fbuf)) {
- fprintf(stderr,"Error: Failed to load shaders from %s\nVertex:\n%s\nFragment:\n%s",shaderPath.c_str(),vbuf,fbuf);
+ fprintf(stderr,"Error: Failed to load shaders from %s\nVertex:\n%s\nFragment:\n%s",shaderPath.string().c_str(),vbuf,fbuf);
}
delete[] fbuf;
delete[] vbuf;
diff --git a/src/tools/prefs.win.cpp b/src/tools/prefs.win.cpp
new file mode 100644
index 00000000..8e4a45b3
--- /dev/null
+++ b/src/tools/prefs.win.cpp
@@ -0,0 +1,133 @@
+
+#include "prefs.hpp"
+#include