Switch to using -I to find includes, rather than relative paths.
[gemrb.git] / gemrb / plugins / Core / Interface.cpp
blobf84648e12a9aa7c33d0a7bd5d3350953290d3a85
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003-2005 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #ifndef INTERFACE
22 #define INTERFACE
23 #endif
25 #include "exports.h"
26 #include "win32def.h"
27 #include "globals.h"
28 #include "strrefs.h"
30 #include <stdlib.h>
31 #include <time.h>
32 #include <vector>
34 #ifdef WIN32
35 #include <direct.h>
36 #include <io.h>
37 #else
38 #include <dirent.h>
39 #endif
41 #include "Interface.h"
42 #include "Audio.h"
43 #include "FileStream.h"
44 #include "AnimationMgr.h"
45 #include "ArchiveImporter.h"
46 #include "WorldMapMgr.h"
47 #include "AmbientMgr.h"
48 #include "ItemMgr.h"
49 #include "SpellMgr.h"
50 #include "EffectMgr.h"
51 #include "StoreMgr.h"
52 #include "DialogMgr.h"
53 #include "MapControl.h"
54 #include "EffectQueue.h"
55 #include "MapMgr.h"
56 #include "TileMap.h"
57 #include "ScriptedAnimation.h"
58 #include "Video.h"
59 #include "PluginMgr.h"
60 #include "StringMgr.h"
61 #include "ScriptEngine.h"
62 #include "ActorMgr.h"
63 #include "Factory.h"
64 #include "Console.h"
65 #include "Label.h"
66 #include "Button.h"
67 #include "SoundMgr.h"
68 #include "SaveGameIterator.h"
69 #include "MusicMgr.h"
70 #include "MoviePlayer.h"
71 #include "GameControl.h"
72 #include "Game.h"
73 #include "DataFileMgr.h"
74 #include "SaveGameMgr.h"
75 #include "WorldMapControl.h"
76 #include "Palette.h"
77 #include "ProjectileServer.h"
78 #include "GameData.h"
79 #include "Calendar.h"
81 GEM_EXPORT Interface* core;
82 GEM_EXPORT GameData* gamedata;
84 #ifdef WIN32
85 GEM_EXPORT HANDLE hConsole;
86 #endif
88 //use DialogF.tlk if the protagonist is female, that's why we leave space
89 static const char dialogtlk[] = "dialog.tlk\0";
91 static int strref_table[STRREF_COUNT];
93 static int MaximumAbility = 25;
94 static ieWordSigned *strmod = NULL;
95 static ieWordSigned *strmodex = NULL;
96 static ieWordSigned *intmod = NULL;
97 static ieWordSigned *dexmod = NULL;
98 static ieWordSigned *conmod = NULL;
99 static ieWordSigned *chrmod = NULL;
100 static ieWordSigned *lorebon = NULL;
101 static ieVariable IWD2DeathVarFormat = "_DEAD%s";
102 static ieVariable DeathVarFormat = "SPRITE_IS_DEAD%s";
104 Interface::Interface(int iargc, char* iargv[])
106 argc = iargc;
107 argv = iargv;
108 #ifdef WIN32
109 hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
110 #endif
111 textcolor( LIGHT_WHITE );
112 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB );
114 // default to the correct endianswitch
115 ieWord endiantest = 1;
116 if (((char *)&endiantest)[1] == 1) {
117 // big-endian
118 DataStream::SetEndianSwitch(true);
121 unsigned int i;
122 for(i=0;i<256;i++) {
123 pl_uppercase[i]=(ieByte) toupper(i);
124 pl_lowercase[i]=(ieByte) tolower(i);
127 projserv = NULL;
128 video = NULL;
129 AudioDriver = NULL;
130 strings = NULL;
131 guiscript = NULL;
132 windowmgr = NULL;
133 vars = NULL;
134 tokens = NULL;
135 RtRows = NULL;
136 music = NULL;
137 sgiterator = NULL;
138 INIparty = NULL;
139 INIbeasts = NULL;
140 INIquests = NULL;
141 INIresdata = NULL;
142 game = NULL;
143 worldmap = NULL;
144 CurrentStore = NULL;
145 CurrentContainer = NULL;
146 UseContainer = false;
147 InfoTextPalette = NULL;
148 timer = NULL;
149 evntmgr = NULL;
150 console = NULL;
151 slottypes = NULL;
152 slotmatrix = NULL;
154 ModalWindow = NULL;
155 tooltip_x = 0;
156 tooltip_y = 0;
157 tooltip_currtextw = 0;
158 tooltip_ctrl = NULL;
159 plugin = NULL;
160 plugin_flags = NULL;
162 pal16 = NULL;
163 pal32 = NULL;
164 pal256 = NULL;
166 GUIEnhancements = 0;
168 CursorCount = 0;
169 Cursors = NULL;
171 mousescrollspd = 10;
173 ConsolePopped = false;
174 CheatFlag = false;
175 FogOfWar = 1;
176 QuitFlag = QF_NORMAL;
177 EventFlag = EF_CONTROL;
178 #ifndef WIN32
179 CaseSensitive = true; //this is the default value, so CD1/CD2 will be resolved
180 #else
181 CaseSensitive = false;
182 #endif
183 GameOnCD = false;
184 SkipIntroVideos = false;
185 DrawFPS = false;
186 KeepCache = false;
187 TooltipDelay = 100;
188 GUIScriptsPath[0] = 0;
189 GamePath[0] = 0;
190 SavePath[0] = 0;
191 GemRBPath[0] = 0;
192 PluginsPath[0] = 0;
193 CachePath[0] = 0;
194 GemRBOverridePath[0] = 0;
195 GameName[0] = 0;
196 strncpy( GameOverridePath, "override", sizeof(GameOverridePath) );
197 strncpy( GameSoundsPath, "sounds", sizeof(GameSoundsPath) );
198 strncpy( GameScriptsPath, "scripts", sizeof(GameScriptsPath) );
199 strncpy( GamePortraitsPath, "portraits", sizeof(GamePortraitsPath) );
200 strncpy( GameCharactersPath, "characters", sizeof(GameCharactersPath) );
201 strncpy( GameDataPath, "data", sizeof(GameDataPath) );
202 for (i = 0; i < 6; i++) {
203 strncpy( CD[i], "CDi", sizeof(CD[i]) );
204 CD[i][2] = '1' + i;
206 strncpy( INIConfig, "baldur.ini", sizeof(INIConfig) );
207 strncpy( ButtonFont, "STONESML", sizeof(ButtonFont) );
208 strncpy( TooltipFont, "STONESML", sizeof(TooltipFont) );
209 strncpy( MovieFont, "STONESML", sizeof(MovieFont) );
210 //strncpy( CursorBam, "CAROT", sizeof(CursorBam) );
211 strncpy( ScrollCursorBam, "CURSARW", sizeof(ScrollCursorBam) );
212 strncpy( GlobalScript, "BALDUR", sizeof(GlobalScript) );
213 strncpy( WorldMapName, "WORLDMAP", sizeof(WorldMapName) );
214 strncpy( Palette16, "MPALETTE", sizeof(Palette16) );
215 strncpy( Palette32, "PAL32", sizeof(Palette32) );
216 strncpy( Palette256, "MPAL256", sizeof(Palette256) );
217 strcpy( TooltipBackResRef, "\0" );
218 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
219 strcpy( GroundCircleBam[size], "\0" );
220 GroundCircleScale[size] = 0;
222 TooltipColor.r = 0;
223 TooltipColor.g = 255;
224 TooltipColor.b = 0;
225 TooltipColor.a = 255;
226 TooltipMargin = 10;
228 TooltipBack = NULL;
229 DraggedItem = NULL;
230 DraggedPortrait = 0;
231 DefSound = NULL;
232 DSCount = -1;
233 GameFeatures = 0;
234 GameFeatures2 = 0;
235 memset( WindowFrames, 0, sizeof( WindowFrames ));
236 memset( GroundCircles, 0, sizeof( GroundCircles ));
237 memset(FogSprites, 0, sizeof( FogSprites ));
238 AreaAliasTable = NULL;
239 ItemExclTable = NULL;
240 ItemDialTable = NULL;
241 ItemDial2Table = NULL;
242 ItemTooltipTable = NULL;
243 update_scripts = false;
245 gamedata = new GameData();
246 ::gamedata = gamedata;
249 #define FreeInterfaceVector(type, variable, member) \
251 std::vector<type>::iterator i; \
252 for(i = (variable).begin(); i != (variable).end(); ++i) { \
253 if (!(*i).free) { \
254 FreeInterface((*i).member); \
255 (*i).free = true; \
260 #define FreeResourceVector(type, variable) \
262 size_t i=variable.size(); \
263 while(i--) { \
264 if (variable[i]) { \
265 delete variable[i]; \
268 variable.clear(); \
271 static void ReleaseItemList(void *poi)
273 delete ((ItemList *) poi);
276 void FreeAbilityTables()
278 if (strmod) {
279 free(strmod);
281 strmod = NULL;
282 if (strmodex) {
283 free(strmodex);
285 strmodex = NULL;
286 if (intmod) {
287 free(intmod);
289 intmod = NULL;
290 if (dexmod) {
291 free(dexmod);
293 dexmod = NULL;
294 if (conmod) {
295 free(conmod);
297 conmod = NULL;
298 if (chrmod) {
299 free(chrmod);
301 chrmod = NULL;
302 if (lorebon) {
303 free(lorebon);
305 lorebon = NULL;
308 void Interface::FreeResRefTable(ieResRef *&table, int &count)
310 if (table) {
311 free( table );
312 count = -1;
316 static void ReleaseItemTooltip(void *poi)
318 free(poi);
321 Interface::~Interface(void)
323 DragItem(NULL,NULL);
324 delete AreaAliasTable;
326 if (music) {
327 music->HardEnd();
329 // stop any ambients which are still enqueued
330 if (AudioDriver) {
331 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
332 if (ambim) ambim->deactivate();
334 //destroy the highest objects in the hierarchy first!
335 delete game;
336 delete calendar;
337 delete worldmap;
339 FreeAbilityTables();
340 for (size_t i = 0; i < cleanupFunctions.size(); i++)
341 cleanupFunctions[i]();
343 ReleaseMemoryActor();
344 EffectQueue_ReleaseMemory();
345 CharAnimations::ReleaseMemory();
346 delete CurrentStore;
348 FreeResRefTable(DefSound, DSCount);
350 free( slottypes );
351 free( slotmatrix );
353 FreeInterface( music );
354 FreeInterface( AudioDriver );
356 delete sgiterator;
358 if (Cursors) {
359 for (int i = 0; i < CursorCount; i++) {
360 video->FreeSprite( Cursors[i] );
362 delete[] Cursors;
365 FreeResourceVector( Font, fonts );
366 FreeResourceVector( Window, windows );
368 unsigned int i;
369 for (i = 0; i < musiclist.size(); i++) {
370 free((void *)musiclist[i]);
373 DamageInfoMap.clear();
375 delete plugin_flags;
377 delete projserv;
379 delete console;
381 delete pal256;
382 delete pal32;
383 delete pal16;
385 delete timer;
387 FreeInterface( windowmgr );
389 if (video) {
391 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
392 video->FreeSprite(FogSprites[i]);
395 for(i=0;i<4;i++) {
396 video->FreeSprite(WindowFrames[i]);
399 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
400 for(i=0;i<6;i++) {
401 video->FreeSprite(GroundCircles[size][i]);
405 if (TooltipBack) {
406 for(i=0;i<3;i++) {
407 //freesprite checks for null pointer
408 video->FreeSprite(TooltipBack[i]);
410 delete[] TooltipBack;
412 if (InfoTextPalette) {
413 gamedata->FreePalette(InfoTextPalette);
416 video->SetDragCursor(NULL);
419 delete evntmgr;
421 FreeInterface( guiscript );
423 delete vars;
424 delete tokens;
425 if (RtRows) {
426 RtRows->RemoveAll(ReleaseItemList);
427 delete RtRows;
429 if (ItemExclTable) {
430 ItemExclTable->RemoveAll(NULL);
431 delete ItemExclTable;
433 if (ItemDialTable) {
434 ItemDialTable->RemoveAll(NULL);
435 delete ItemDialTable;
437 if (ItemDial2Table) {
438 ItemDial2Table->RemoveAll(NULL);
439 delete ItemDial2Table;
441 if (ItemTooltipTable) {
442 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
443 delete ItemTooltipTable;
446 FreeInterfaceVector( Symbol, symbols, sm );
448 FreeInterface(INIquests);
449 FreeInterface(INIbeasts);
450 FreeInterface(INIparty);
451 FreeInterface(INIresdata);
453 Map::ReleaseMemory();
454 GameScript::ReleaseMemory();
455 Actor::ReleaseMemory();
457 gamedata->ClearCaches();
458 delete gamedata;
459 gamedata = NULL;
460 FreeInterface( video );
462 FreeInterface( strings );
464 delete plugin;
466 // Removing all stuff from Cache, except bifs
467 if (!KeepCache) DelTree((const char *) CachePath, true);
470 void Interface::SetWindowFrame(int i, Sprite2D *Picture)
472 video->FreeSprite(WindowFrames[i]);
473 WindowFrames[i]=Picture;
476 GameControl* Interface::StartGameControl()
478 //making sure that our window is the first one
479 if (ConsolePopped) {
480 PopupConsole();
482 DelAllWindows();//deleting ALL windows
483 gamedata->DelTable(0xffffu); //dropping ALL tables
484 Window* gamewin = new Window( 0xffff, 0, 0, (ieWord) Width, (ieWord) Height );
485 gamewin->WindowPack[0]=0;
486 GameControl* gc = new GameControl();
487 gc->XPos = 0;
488 gc->YPos = 0;
489 gc->Width = (ieWord) Width;
490 gc->Height = (ieWord) Height;
491 gc->Owner = gamewin;
492 gc->ControlID = 0x00000000;
493 gc->ControlType = IE_GUI_GAMECONTROL;
494 gamewin->AddControl( gc );
495 AddWindow( gamewin );
496 SetVisible( 0, WINDOW_VISIBLE );
497 //setting the focus to the game control
498 evntmgr->SetFocused(gamewin, gc);
499 if (guiscript->LoadScript( "MessageWindow" )) {
500 guiscript->RunFunction( "OnLoad" );
501 gc->UnhideGUI();
504 return gc;
507 /* handle main loop events that might destroy or create windows
508 thus cannot be called from DrawWindows directly
509 these events are pending until conditions are right
511 void Interface::HandleEvents()
513 GameControl *gc = GetGameControl();
514 if (gc && (!gc->Owner || !gc->Owner->Visible)) {
515 gc=NULL;
519 if (EventFlag&EF_SELECTION) {
520 EventFlag&=~EF_SELECTION;
521 guiscript->RunFunction( "SelectionChanged", false);
524 if (EventFlag&EF_UPDATEANIM) {
525 EventFlag&=~EF_UPDATEANIM;
526 guiscript->RunFunction( "UpdateAnimation", false);
529 if (EventFlag&EF_PORTRAIT) {
530 ieDword tmp = (ieDword) ~0;
531 vars->Lookup( "PortraitWindow", tmp );
532 if (tmp != (ieDword) ~0) {
533 EventFlag&=~EF_PORTRAIT;
534 guiscript->RunFunction( "UpdatePortraitWindow" );
538 if (EventFlag&EF_ACTION) {
539 ieDword tmp = (ieDword) ~0;
540 vars->Lookup( "ActionsWindow", tmp );
541 if (tmp != (ieDword) ~0) {
542 EventFlag&=~EF_ACTION;
543 guiscript->RunFunction( "UpdateActionsWindow" );
547 if ((EventFlag&EF_CONTROL) && gc) {
548 EventFlag&=~EF_CONTROL;
549 guiscript->RunFunction( "UpdateControlStatus" );
550 //this is the only value we can use here
551 if (game->ControlStatus & CS_HIDEGUI)
552 gc->HideGUI();
553 else
554 gc->UnhideGUI();
555 return;
557 if ((EventFlag&EF_SHOWMAP) && gc) {
558 ieDword tmp = (ieDword) ~0;
559 vars->Lookup( "OtherWindow", tmp );
560 if (tmp == (ieDword) ~0) {
561 EventFlag &= ~EF_SHOWMAP;
562 guiscript->RunFunction( "ShowMap" );
564 return;
567 if (EventFlag&EF_SEQUENCER) {
568 EventFlag&=~EF_SEQUENCER;
569 guiscript->RunFunction( "OpenSequencerWindow" );
570 return;
573 if (EventFlag&EF_IDENTIFY) {
574 EventFlag&=~EF_IDENTIFY;
575 guiscript->RunFunction( "OpenIdentifyWindow" );
576 return;
578 if (EventFlag&EF_OPENSTORE) {
579 EventFlag&=~EF_OPENSTORE;
580 guiscript->RunFunction( "OpenStoreWindow" );
581 return;
584 if (EventFlag&EF_MASTERSCRIPT) {
585 EventFlag&=~EF_MASTERSCRIPT;
586 guiscript->RunFunction( "UpdateMasterScript" );
587 return;
592 /* handle main loop events that might destroy or create windows
593 thus cannot be called from DrawWindows directly
595 void Interface::HandleFlags()
597 EventFlag = EF_CONTROL; //clear events because the context changed
599 if (QuitFlag&(QF_QUITGAME|QF_EXITGAME) ) {
600 // when reaching this, quitflag should be 1 or 2
601 // if Exitgame was set, we'll set Start.py too
602 QuitGame (QuitFlag&QF_EXITGAME);
603 QuitFlag &= ~(QF_QUITGAME|QF_EXITGAME);
606 if (QuitFlag&QF_LOADGAME) {
607 QuitFlag &= ~QF_LOADGAME;
608 LoadGame(LoadGameIndex, VersionOverride );
611 if (QuitFlag&QF_ENTERGAME) {
612 QuitFlag &= ~QF_ENTERGAME;
613 if (game) {
614 timer->Init();
616 //rearrange party slots
617 game->ConsolidateParty();
618 GameControl* gc = StartGameControl();
619 //switch map to protagonist
620 Actor* actor = game->FindPC (1);
621 if (!actor) {
622 actor = game->GetPC (0, false);
624 if (actor) {
625 gc->ChangeMap(actor, true);
627 } else {
628 printMessage("Core", "No game to enter...\n", LIGHT_RED);
629 QuitFlag = QF_QUITGAME;
633 if (QuitFlag&QF_CHANGESCRIPT) {
634 QuitFlag &= ~QF_CHANGESCRIPT;
635 guiscript->LoadScript( NextScript );
636 guiscript->RunFunction( "OnLoad" );
640 bool GenerateAbilityTables()
642 FreeAbilityTables();
644 //range is: 0 - maximumability
645 int tablesize = MaximumAbility+1;
646 strmod = (ieWordSigned *) malloc (tablesize * 4 * sizeof(ieWordSigned) );
647 if (!strmod)
648 return false;
649 strmodex = (ieWordSigned *) malloc (101 * 4 * sizeof(ieWordSigned) );
650 if (!strmodex)
651 return false;
652 intmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
653 if (!intmod)
654 return false;
655 dexmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
656 if (!dexmod)
657 return false;
658 conmod = (ieWordSigned *) malloc (tablesize * 5 * sizeof(ieWordSigned) );
659 if (!conmod)
660 return false;
661 chrmod = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
662 if (!chrmod)
663 return false;
664 lorebon = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
665 if (!lorebon)
666 return false;
667 return true;
670 bool Interface::ReadAbilityTable(const ieResRef tablename, ieWordSigned *mem, int columns, int rows)
672 AutoTable tab(tablename);
673 if (!tab) {
674 return false;
676 //this is a hack for rows not starting at 0 in some cases
677 int fix = 0;
678 const char * tmp = tab->GetRowName(0);
679 if (tmp && (tmp[0]!='0')) {
680 fix = atoi(tmp);
681 for (int i=0;i<fix;i++) {
682 for (int j=0;j<columns;j++) {
683 mem[rows*j+i]=(ieWordSigned) strtol(tab->QueryField(0,j),NULL,0 );
687 for (int j=0;j<columns;j++) {
688 for( int i=0;i<rows-fix;i++) {
689 mem[rows*j+i+fix] = (ieWordSigned) strtol(tab->QueryField(i,j),NULL,0 );
692 return true;
695 bool Interface::ReadAbilityTables()
697 bool ret = GenerateAbilityTables();
698 if (!ret)
699 return ret;
700 ret = ReadAbilityTable("strmod", strmod, 4, MaximumAbility + 1);
701 if (!ret)
702 return ret;
703 ret = ReadAbilityTable("strmodex", strmodex, 4, 101);
704 //3rd ed doesn't have strmodex, but has a maximum of 40
705 if (!ret && (MaximumAbility<=25) )
706 return ret;
707 ret = ReadAbilityTable("intmod", intmod, 3, MaximumAbility + 1);
708 if (!ret)
709 return ret;
710 ret = ReadAbilityTable("hpconbon", conmod, 5, MaximumAbility + 1);
711 if (!ret)
712 return ret;
713 if (!HasFeature(GF_3ED_RULES)) {
714 //no lorebon in iwd2???
715 ret = ReadAbilityTable("lorebon", lorebon, 1, MaximumAbility + 1);
716 if (!ret)
717 return ret;
718 //no dexmod in iwd2???
719 ret = ReadAbilityTable("dexmod", dexmod, 3, MaximumAbility + 1);
720 if (!ret)
721 return ret;
723 //this table is a single row (not a single column)
724 ret = ReadAbilityTable("chrmodst", chrmod, MaximumAbility + 1, 1);
725 if (!ret)
726 return ret;
727 return true;
730 bool Interface::ReadAuxItemTables()
732 int idx;
733 int table;
734 bool flag = true;
736 if (ItemExclTable) {
737 ItemExclTable->RemoveAll(NULL);
738 } else {
739 ItemExclTable = new Variables();
740 ItemExclTable->SetType(GEM_VARIABLES_INT);
742 table = gamedata->LoadTable( "itemexcl" );
744 AutoTable aa;
746 //don't report error when the file doesn't exist
747 if (aa.load("itemexcl")) {
748 idx = aa->GetRowCount();
749 while (idx--) {
750 ieResRef key;
752 strnlwrcpy(key,aa->GetRowName(idx),8);
753 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
754 ItemExclTable->SetAt(key, value);
757 if (ItemDialTable) {
758 ItemDialTable->RemoveAll(NULL);
759 } else {
760 ItemDialTable = new Variables();
761 ItemDialTable->SetType(GEM_VARIABLES_INT);
763 if (ItemDial2Table) {
764 ItemDial2Table->RemoveAll(NULL);
765 } else {
766 ItemDial2Table = new Variables();
767 ItemDial2Table->SetType(GEM_VARIABLES_STRING);
770 //don't report error when the file doesn't exist
771 if (aa.load("itemdial")) {
772 idx = aa->GetRowCount();
773 while (idx--) {
774 ieResRef key, dlgres;
776 strnlwrcpy(key,aa->GetRowName(idx),8);
777 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
778 ItemDialTable->SetAt(key, value);
779 strnlwrcpy(dlgres,aa->QueryField(idx,1),8);
780 ItemDial2Table->SetAtCopy(key, dlgres);
784 if (ItemTooltipTable) {
785 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
786 } else {
787 ItemTooltipTable = new Variables();
788 ItemTooltipTable->SetType(GEM_VARIABLES_POINTER);
791 //don't report error when the file doesn't exist
792 if (aa.load("tooltip")) {
793 idx = aa->GetRowCount();
794 while (idx--) {
795 ieResRef key;
796 int *tmppoi = (int *) malloc(sizeof(int)*3);
798 strnlwrcpy(key,aa->GetRowName(idx),8);
799 for (int i=0;i<3;i++) {
800 tmppoi[i] = atoi(aa->QueryField(idx,i));
802 ItemTooltipTable->SetAt(key, (void*)tmppoi);
805 return flag;
808 //Static
809 const char *Interface::GetDeathVarFormat()
811 return DeathVarFormat;
814 int Interface::GetItemExcl(const ieResRef itemname) const
816 ieDword value;
818 if (ItemExclTable && ItemExclTable->Lookup(itemname, value)) {
819 return (int) value;
821 return 0;
824 int Interface::GetItemTooltip(const ieResRef itemname, int header, int identified)
826 int *value = NULL;
828 if (ItemTooltipTable) {
829 void* lookup = NULL;
830 ItemTooltipTable->Lookup(itemname, lookup);
831 value = (int*)lookup;
833 if (value && (value[header]>=0)) {
834 return value[header];
836 Item *item = gamedata->GetItem(itemname);
837 if (!item) {
838 return -1;
840 int ret = identified?item->ItemNameIdentified:item->ItemName;
841 gamedata->FreeItem(item, itemname, 0);
842 return ret;
845 int Interface::GetItemDialStr(const ieResRef itemname) const
847 ieDword value;
849 if (ItemDialTable && ItemDialTable->Lookup(itemname, value)) {
850 return (int) value;
852 return -1;
855 //second value is the item dialog resource returned by this method
856 int Interface::GetItemDialRes(const ieResRef itemname, ieResRef retval) const
858 if (ItemDial2Table && ItemDial2Table->Lookup(itemname, retval, sizeof(ieResRef))) {
859 return 1;
861 return 0;
864 bool Interface::ReadAreaAliasTable(const ieResRef tablename)
866 if (AreaAliasTable) {
867 AreaAliasTable->RemoveAll(NULL);
868 } else {
869 AreaAliasTable = new Variables();
870 AreaAliasTable->SetType(GEM_VARIABLES_INT);
873 AutoTable aa(tablename);
874 if (!aa) {
875 //don't report error when the file doesn't exist
876 return true;
879 int idx = aa->GetRowCount();
880 while (idx--) {
881 ieResRef key;
883 strnlwrcpy(key,aa->GetRowName(idx),8);
884 ieDword value = atoi(aa->QueryField(idx,0));
885 AreaAliasTable->SetAt(key, value);
887 return true;
890 //this isn't const
891 int Interface::GetAreaAlias(const ieResRef areaname) const
893 ieDword value;
895 if (AreaAliasTable && AreaAliasTable->Lookup(areaname, value)) {
896 return (int) value;
898 return -1;
901 bool Interface::ReadMusicTable(const ieResRef tablename, int col) {
902 AutoTable tm(tablename);
903 if (!tm)
904 return false;
906 for (unsigned int i = 0; i < tm->GetRowCount(); i++) {
907 musiclist.push_back(strdup(tm->QueryField(i, col)));
910 return true;
913 bool Interface::ReadDamageTypeTable() {
914 AutoTable tm("dmgtypes");
915 if (!tm)
916 return false;
918 DamageInfoStruct di;
919 for (ieDword i = 0; i < tm->GetRowCount(); i++) {
920 di.strref = core->GetStringReference(atoi(tm->QueryField(i, 0)));
921 di.resist_stat = TranslateStat(tm->QueryField(i, 1));
922 di.value = strtol(tm->QueryField(i, 2), (char **) NULL, 16);
923 DamageInfoMap.insert(std::make_pair <ieDword, DamageInfoStruct> ((ieDword)di.value, di));
926 return true;
929 //Not a constant anymore, we let the caller set the entry to zero
930 char *Interface::GetMusicPlaylist(int SongType) const {
931 if (SongType < 0 || (unsigned int)SongType >= musiclist.size())
932 return NULL;
934 return musiclist[SongType];
937 static const Color white = {0xff,0xff,0xff,0xff};
938 static const Color black = {0x00,0x00,0x00,0xff};
939 static const Region bg( 0, 0, 100, 30 );
941 /** this is the main loop */
942 void Interface::Main()
944 video->CreateDisplay( Width, Height, Bpp, FullScreen );
945 video->SetDisplayTitle( GameName, GameType );
946 ieDword brightness = 10;
947 ieDword contrast = 5;
948 ieDword speed = 10;
949 vars->Lookup("Brightness Correction", brightness);
950 vars->Lookup("Gamma Correction", contrast);
951 vars->Lookup("Mouse Scroll Speed", speed);
952 video->SetGamma(brightness, contrast);
953 SetMouseScrollSpeed((int) speed);
954 if (vars->Lookup("Tooltips", TooltipDelay)) {
955 // the games store the slider position*10, not the actual delay
956 TooltipDelay *= TOOLTIP_DELAY_FACTOR/10;
959 Font* fps = GetFont( ( unsigned int ) 0 );
960 char fpsstring[40]={"???.??? fps"};
961 unsigned long frame = 0, time, timebase;
962 GetTime(timebase);
963 double frames = 0.0;
964 Palette* palette = CreatePalette( white, black );
965 do {
966 //don't change script when quitting is pending
968 while (QuitFlag) {
969 HandleFlags();
971 if (EventFlag) {
972 HandleEvents();
974 HandleGUIBehaviour();
976 GameLoop();
977 DrawWindows();
978 if (DrawFPS) {
979 frame++;
980 GetTime( time );
981 if (time - timebase > 1000) {
982 frames = ( frame * 1000.0 / ( time - timebase ) );
983 timebase = time;
984 frame = 0;
985 sprintf( fpsstring, "%.3f fps", frames );
987 video->DrawRect( bg, black );
988 fps->Print( bg,
989 ( unsigned char * ) fpsstring, palette,
990 IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_MIDDLE, true );
992 } while (video->SwapBuffers() == GEM_OK);
993 gamedata->FreePalette( palette );
996 bool Interface::ReadStrrefs()
998 int i;
999 memset(strref_table,-1,sizeof(strref_table) );
1000 AutoTable tab("strings");
1001 if (!tab) {
1002 return false;
1004 for(i=0;i<STRREF_COUNT;i++) {
1005 strref_table[i]=atoi(tab->QueryField(i,0));
1007 return true;
1010 int Interface::ReadResRefTable(const ieResRef tablename, ieResRef *&data)
1012 int count = 0;
1014 if (data) {
1015 free(data);
1016 data = NULL;
1018 AutoTable tm(tablename);
1019 if (!tm) {
1020 printStatus( "ERROR", LIGHT_RED );
1021 printf( "Cannot find %s.2da.\n",tablename );
1022 return 0;
1024 count = tm->GetRowCount();
1025 data = (ieResRef *) calloc( count, sizeof(ieResRef) );
1026 for (int i = 0; i < count; i++) {
1027 strnlwrcpy( data[i], tm->QueryField( i, 0 ), 8 );
1028 //* marks an empty resource
1029 if (data[i][0]=='*') {
1030 data[i][0]=0;
1033 return count;
1036 int Interface::LoadSprites()
1038 ieDword i;
1039 int size;
1040 if (!IsAvailable( IE_2DA_CLASS_ID )) {
1041 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1042 return GEM_ERROR;
1045 //loading cursors
1046 AnimationFactory* anim;
1047 anim = (AnimationFactory*) gamedata->GetFactoryResource("cursors", IE_BAM_CLASS_ID);
1048 if (anim)
1050 CursorCount = anim->GetCycleCount();
1051 Cursors = new Sprite2D * [CursorCount];
1052 for (int i = 0; i < CursorCount; i++) {
1053 Cursors[i] = anim->GetFrame( 0, (ieByte) i );
1056 printMessage( "Core", "Loading Cursors...", WHITE );
1058 // this is the last existing cursor type
1059 if (CursorCount<IE_CURSOR_WAY) {
1060 printStatus( "ERROR", LIGHT_RED );
1061 return GEM_ERROR;
1063 video->SetCursor( Cursors[0], Cursors[1] );
1064 printStatus( "OK", LIGHT_GREEN );
1066 // Load fog-of-war bitmaps
1067 anim = (AnimationFactory*) gamedata->GetFactoryResource("fogowar", IE_BAM_CLASS_ID);
1068 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE );
1069 if (!anim || anim->GetCycleSize( 0 ) != 8) {
1070 // unknown type of fog anim
1071 printStatus( "ERROR", LIGHT_RED );
1072 return GEM_ERROR;
1075 FogSprites[0] = NULL;
1076 FogSprites[1] = anim->GetFrame( 0, 0 );
1077 FogSprites[2] = anim->GetFrame( 1, 0 );
1078 FogSprites[3] = anim->GetFrame( 2, 0 );
1080 FogSprites[4] = video->MirrorSpriteVertical( FogSprites[1], false );
1082 FogSprites[5] = NULL;
1084 FogSprites[6] = video->MirrorSpriteVertical( FogSprites[3], false );
1086 FogSprites[7] = NULL;
1088 FogSprites[8] = video->MirrorSpriteHorizontal( FogSprites[2], false );
1090 FogSprites[9] = video->MirrorSpriteHorizontal( FogSprites[3], false );
1092 FogSprites[10] = NULL;
1093 FogSprites[11] = NULL;
1095 FogSprites[12] = video->MirrorSpriteHorizontal( FogSprites[6], false );
1097 FogSprites[16] = anim->GetFrame( 3, 0 );
1098 FogSprites[17] = anim->GetFrame( 4, 0 );
1099 FogSprites[18] = anim->GetFrame( 5, 0 );
1100 FogSprites[19] = anim->GetFrame( 6, 0 );
1102 FogSprites[20] = video->MirrorSpriteVertical( FogSprites[17], false );
1104 FogSprites[21] = NULL;
1106 FogSprites[23] = NULL;
1108 FogSprites[24] = video->MirrorSpriteHorizontal( FogSprites[18], false );
1110 FogSprites[25] = anim->GetFrame( 7, 0 );
1113 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[25], false );
1114 FogSprites[22] = video->MirrorSpriteHorizontal( tmpsprite, false );
1115 video->FreeSprite( tmpsprite );
1118 FogSprites[26] = NULL;
1119 FogSprites[27] = NULL;
1122 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[19], false );
1123 FogSprites[28] = video->MirrorSpriteHorizontal( tmpsprite, false );
1124 video->FreeSprite( tmpsprite );
1127 i = 0;
1128 vars->Lookup("3D Acceleration", i);
1129 if (i) {
1130 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
1131 if (FogSprites[i]) {
1132 Sprite2D* alphasprite = video->CreateAlpha( FogSprites[i] );
1133 video->FreeSprite ( FogSprites[i] );
1134 FogSprites[i] = alphasprite;
1139 printStatus( "OK", LIGHT_GREEN );
1141 // Load ground circle bitmaps (PST only)
1142 //block required due to msvc6.0 incompatibility
1143 for (size = 0; size < MAX_CIRCLE_SIZE; size++) {
1144 if (GroundCircleBam[size][0]) {
1145 anim = (AnimationFactory*) gamedata->GetFactoryResource(GroundCircleBam[size], IE_BAM_CLASS_ID);
1146 if (!anim || anim->GetCycleCount() != 6) {
1147 // unknown type of circle anim
1148 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1149 printStatus( "ERROR", LIGHT_RED );
1150 return GEM_ERROR;
1153 for (int i = 0; i < 6; i++) {
1154 Sprite2D* sprite = anim->GetFrame( 0, (ieByte) i );
1155 if (GroundCircleScale[size]) {
1156 GroundCircles[size][i] = video->SpriteScaleDown( sprite, GroundCircleScale[size] );
1157 video->FreeSprite( sprite );
1158 } else {
1159 GroundCircles[size][i] = sprite;
1165 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1166 printStatus( "OK", LIGHT_GREEN );
1168 printMessage( "Core", "Loading Fonts...\n", WHITE );
1169 AutoTable tab("fonts");
1170 if (!tab) {
1171 printStatus( "ERROR", LIGHT_RED );
1172 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1173 return GEM_ERROR;
1174 } else {
1175 AnimationMgr* bamint = ( AnimationMgr* ) GetInterface( IE_BAM_CLASS_ID );
1176 if (!bamint) {
1177 printStatus( "ERROR", LIGHT_RED );
1178 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1179 return GEM_ERROR;
1181 DataStream* str = NULL;
1183 int count = tab->GetRowCount();
1184 for (int i = 0; i < count; i++) {
1185 const char* ResRef = tab->QueryField( i, 0 );
1186 int needpalette = atoi( tab->QueryField( i, 1 ) );
1187 int first_char = atoi( tab->QueryField( i, 2 ) );
1188 str = gamedata->GetResource( ResRef, IE_BAM_CLASS_ID );
1189 if (!bamint->Open( str, true )) {
1190 continue;
1192 Font* fnt = bamint->GetFont();
1193 if (!fnt) {
1194 continue;
1196 strnlwrcpy( fnt->ResRef, ResRef, 8 );
1197 if (needpalette) {
1199 Color fore = {0xff, 0xff, 0xff, 0};
1200 Color back = {0x00, 0x00, 0x00, 0};
1201 if (!strnicmp( TooltipFont, ResRef, 8) ) {
1202 if (TooltipColor.a==0xff) {
1203 fore = TooltipColor;
1204 } else {
1205 fore = back;
1206 back = TooltipColor;
1209 Palette* pal = CreatePalette( fore, back );
1210 pal->CreateShadedAlphaChannel();
1211 fnt->SetPalette(pal);
1212 gamedata->FreePalette( pal );
1214 fnt->SetFirstChar( (ieByte) first_char );
1215 fonts.push_back( fnt );
1217 FreeInterface(bamint);
1219 printMessage( "Core", "Fonts Loaded...", WHITE );
1220 printStatus( "OK", LIGHT_GREEN );
1222 if (TooltipBackResRef[0]) {
1223 anim = (AnimationFactory*) gamedata->GetFactoryResource(TooltipBackResRef, IE_BAM_CLASS_ID);
1224 printMessage( "Core", "Initializing Tooltips...", WHITE );
1225 if (!anim) {
1226 printStatus( "ERROR", LIGHT_RED );
1227 return GEM_ERROR;
1229 TooltipBack = new Sprite2D * [3];
1230 for (int i = 0; i < 3; i++) {
1231 TooltipBack[i] = anim->GetFrame( 0, (ieByte) i );
1232 TooltipBack[i]->XPos = 0;
1233 TooltipBack[i]->YPos = 0;
1235 printStatus( "OK", LIGHT_GREEN );
1238 return GEM_OK;
1241 int Interface::Init()
1243 plugin_flags = new Variables();
1244 plugin_flags->SetType( GEM_VARIABLES_INT );
1246 printMessage( "Core", "Initializing the Event Manager...", WHITE );
1247 evntmgr = new EventMgr();
1249 printMessage( "Core", "Initializing Variables Dictionary...", WHITE );
1250 vars = new Variables();
1251 if (!vars) {
1252 printStatus( "ERROR", LIGHT_RED );
1253 return GEM_ERROR;
1256 vars->SetType( GEM_VARIABLES_INT );
1257 vars->SetAt( "Volume Ambients", 100 );
1258 vars->SetAt( "Volume Movie", 100 );
1259 vars->SetAt( "Volume Music", 100 );
1260 vars->SetAt( "Volume SFX", 100 );
1261 vars->SetAt( "Volume Voices", 100 );
1262 printStatus( "OK", LIGHT_GREEN );
1264 if (!LoadConfig()) {
1265 return GEM_ERROR;
1267 printMessage( "Core", "Starting Plugin Manager...\n", WHITE );
1268 plugin = new PluginMgr( PluginsPath );
1269 if (plugin && plugin->GetPluginCount()) {
1270 printMessage( "Core", "Plugin Loading Complete...", WHITE );
1271 printStatus( "OK", LIGHT_GREEN );
1272 } else {
1273 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW);
1274 printStatus( "ERROR", LIGHT_RED );
1275 return GEM_ERROR;
1277 time_t t;
1278 t = time( NULL );
1279 srand( ( unsigned int ) t );
1280 #ifdef _DEBUG
1281 FileStreamPtrCount = 0;
1282 CachedFileStreamPtrCount = 0;
1283 #endif
1284 printMessage( "Core", "GemRB Core Initialization...\n", WHITE );
1285 printMessage( "Core", "Searching for Video Driver...", WHITE );
1286 if (!IsAvailable( IE_VIDEO_CLASS_ID )) {
1287 printStatus( "ERROR", LIGHT_RED );
1288 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1289 return GEM_ERROR;
1291 printStatus( "OK", LIGHT_GREEN );
1292 printMessage( "Core", "Initializing Video Plugin...", WHITE );
1293 video = ( Video * ) GetInterface( IE_VIDEO_CLASS_ID );
1294 if (video->Init() == GEM_ERROR) {
1295 printStatus( "ERROR", LIGHT_RED );
1296 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1297 return GEM_ERROR;
1299 Color defcolor={255,255,255,200};
1300 SetInfoTextColor(defcolor);
1301 printStatus( "OK", LIGHT_GREEN );
1304 printMessage( "Core", "Initializing Search Path...", WHITE );
1305 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY )) {
1306 printf( "no DirectoryImporter! " );
1307 printStatus( "ERROR", LIGHT_RED );
1308 return GEM_ERROR;
1311 char path[_MAX_PATH];
1313 PathJoin( path, core->CachePath, NULL);
1314 gamedata->AddSource(path, "Cache", PLUGIN_RESOURCE_DIRECTORY);
1316 PathJoin( path, core->GemRBOverridePath, "override", core->GameType, NULL);
1317 gamedata->AddSource(path, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1319 PathJoin( path, core->GemRBOverridePath, "override", "shared", NULL);
1320 gamedata->AddSource(path, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1322 PathJoin( path, core->GamePath, core->GameOverridePath, NULL);
1323 gamedata->AddSource(path, "Override", PLUGIN_RESOURCE_DIRECTORY);
1325 PathJoin( path, core->GamePath, core->GameSoundsPath, NULL);
1326 gamedata->AddSource(path, "Sounds", PLUGIN_RESOURCE_DIRECTORY);
1328 PathJoin( path, core->GamePath, core->GameScriptsPath, NULL);
1329 gamedata->AddSource(path, "Scripts", PLUGIN_RESOURCE_DIRECTORY);
1331 PathJoin( path, core->GamePath, core->GamePortraitsPath, NULL);
1332 gamedata->AddSource(path, "Portraits", PLUGIN_RESOURCE_DIRECTORY);
1334 PathJoin( path, core->GamePath, core->GameDataPath, NULL);
1335 gamedata->AddSource(path, "Data", PLUGIN_RESOURCE_DIRECTORY);
1337 //IWD2 movies are on the CD but not in the BIF
1338 for (int i = 0; i < 6; i++) {
1339 char description[] = "CDi/data";
1340 PathJoin( path, core->CD[i], core->GameDataPath, NULL);
1341 description[2] = '1' + i;
1342 gamedata->AddSource(path, description, PLUGIN_RESOURCE_DIRECTORY);
1345 printStatus( "OK", LIGHT_GREEN );
1349 printMessage( "Core", "Initializing KEY Importer...", WHITE );
1350 char ChitinPath[_MAX_PATH];
1351 PathJoin( ChitinPath, GamePath, "chitin.key", NULL );
1352 if (!gamedata->AddSource(ChitinPath, "chitin.key", PLUGIN_RESOURCE_KEY)) {
1353 printStatus( "ERROR", LIGHT_RED );
1354 return GEM_ERROR;
1356 printStatus( "OK", LIGHT_GREEN );
1359 printMessage( "Core", "Reading Game Options...\n", WHITE );
1360 if (!LoadGemRBINI())
1362 printf( "Cannot Load INI\nTermination in Progress...\n" );
1363 return GEM_ERROR;
1366 //loading baldur.ini
1368 char ini_path[_MAX_PATH];
1369 PathJoin( ini_path, GamePath, INIConfig, NULL );
1370 ResolveFilePath( ini_path );
1371 LoadINI( ini_path );
1372 int i;
1373 for (i = 0; i < 8; i++) {
1374 if (INIConfig[i] == '.')
1375 break;
1376 GameNameResRef[i] = INIConfig[i];
1378 GameNameResRef[i] = 0;
1381 printMessage( "Core", "Creating Projectile Server...\n", WHITE );
1382 projserv = new ProjectileServer();
1383 if (!projserv->GetHighestProjectileNumber()) {
1384 printStatus( "ERROR", LIGHT_RED );
1385 printf( "No projectiles are available...\n" );
1388 printMessage( "Core", "Checking for Dialogue Manager...", WHITE );
1389 if (!IsAvailable( IE_TLK_CLASS_ID )) {
1390 printStatus( "ERROR", LIGHT_RED );
1391 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1392 return GEM_ERROR;
1394 printStatus( "OK", LIGHT_GREEN );
1395 strings = ( StringMgr * ) GetInterface( IE_TLK_CLASS_ID );
1396 printMessage( "Core", "Loading Dialog.tlk file...", WHITE );
1397 char strpath[_MAX_PATH];
1398 PathJoin( strpath, GamePath, dialogtlk, NULL );
1399 ResolveFilePath( strpath );
1400 FileStream* fs = new FileStream();
1401 if (!fs->Open( strpath, true )) {
1402 printStatus( "ERROR", LIGHT_RED );
1403 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1404 delete fs;
1405 return GEM_ERROR;
1407 printStatus( "OK", LIGHT_GREEN );
1408 strings->Open( fs, true );
1411 printMessage( "Core", "Loading Palettes...\n", WHITE );
1412 ImageMgr *im =( ImageMgr * ) gamedata->GetResource( Palette16, &ImageMgr::ID );
1413 pal16 = im->GetImage();
1414 FreeInterface(im);
1415 im = ( ImageMgr * ) gamedata->GetResource( Palette32, &ImageMgr::ID );
1416 pal32 = im->GetImage();
1417 FreeInterface(im);
1418 im = ( ImageMgr * ) gamedata->GetResource( Palette256, &ImageMgr::ID );
1419 pal256 = im->GetImage();
1420 FreeInterface(im);
1421 printMessage( "Core", "Palettes Loaded\n", WHITE );
1424 if (!IsAvailable( IE_BAM_CLASS_ID )) {
1425 printStatus( "ERROR", LIGHT_RED );
1426 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1427 return GEM_ERROR;
1430 printMessage( "Core", "Initializing stock sounds...\n", WHITE );
1431 DSCount = ReadResRefTable ("defsound", DefSound);
1432 if (DSCount == 0) {
1433 printStatus( "ERROR", LIGHT_RED );
1434 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1435 return GEM_ERROR;
1438 printStatus( "OK", LIGHT_GREEN );
1439 printMessage( "Core", "Broadcasting Event Manager...", WHITE );
1440 video->SetEventMgr( evntmgr );
1441 printStatus( "OK", LIGHT_GREEN );
1442 printMessage( "Core", "Initializing Window Manager...", WHITE );
1443 windowmgr = ( WindowMgr * ) GetInterface( IE_CHU_CLASS_ID );
1444 if (windowmgr == NULL) {
1445 printStatus( "ERROR", LIGHT_RED );
1446 return GEM_ERROR;
1448 printStatus( "OK", LIGHT_GREEN );
1449 printMessage( "Core", "Initializing GUI Script Engine...", WHITE );
1450 guiscript = ( ScriptEngine * ) GetInterface( IE_GUI_SCRIPT_CLASS_ID );
1451 if (guiscript == NULL) {
1452 printStatus( "ERROR", LIGHT_RED );
1453 return GEM_ERROR;
1455 if (!guiscript->Init()) {
1456 printStatus( "ERROR", LIGHT_RED );
1457 return GEM_ERROR;
1459 printStatus( "OK", LIGHT_GREEN );
1460 strcpy( NextScript, "Start" );
1462 int ret = LoadSprites();
1463 if (ret) return ret;
1465 Sprite2D *tmpsprite = GetCursorSprite();
1466 printMessage( "Core", "Setting up the Console...", WHITE );
1467 QuitFlag = QF_CHANGESCRIPT;
1468 console = new Console();
1469 console->XPos = 0;
1470 console->YPos = (ieWord) (Height - 25);
1471 console->Width = (ieWord) Width;
1472 console->Height = 25;
1473 console->SetFont( fonts[0] );
1474 if (!tmpsprite) {
1475 printStatus( "ERROR", LIGHT_RED );
1476 return GEM_ERROR;
1478 console->SetCursor (tmpsprite);
1479 printStatus( "OK", LIGHT_GREEN );
1481 printMessage( "Core", "Starting up the Sound Driver...", WHITE );
1482 AudioDriver = ( Audio * ) GetInterface( IE_AUDIO_CLASS_ID );
1483 if (AudioDriver == NULL) {
1484 printStatus( "ERROR", LIGHT_RED );
1485 return GEM_ERROR;
1487 if (!AudioDriver->Init()) {
1488 printStatus( "ERROR", LIGHT_RED );
1489 return GEM_ERROR;
1491 printStatus( "OK", LIGHT_GREEN );
1493 printMessage( "Core", "Allocating SaveGameIterator...", WHITE );
1494 sgiterator = new SaveGameIterator();
1495 if (sgiterator == NULL) {
1496 printStatus( "ERROR", LIGHT_RED );
1497 return GEM_ERROR;
1499 printStatus( "OK", LIGHT_GREEN );
1501 //no need of strdup, variables do copy the key!
1502 vars->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos );
1503 vars->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements );
1505 printMessage( "Core", "Initializing Token Dictionary...", WHITE );
1506 tokens = new Variables();
1507 if (!tokens) {
1508 printStatus( "ERROR", LIGHT_RED );
1509 return GEM_ERROR;
1511 tokens->SetType( GEM_VARIABLES_STRING );
1512 printStatus( "OK", LIGHT_GREEN );
1514 printMessage( "Core", "Initializing Music Manager...", WHITE );
1515 music = ( MusicMgr * ) GetInterface( IE_MUS_CLASS_ID );
1516 if (!music) {
1517 printStatus( "ERROR", LIGHT_RED );
1518 return GEM_ERROR;
1520 printStatus( "OK", LIGHT_GREEN );
1522 printMessage("Core", "Loading music list...\n", WHITE );
1523 if (HasFeature( GF_HAS_SONGLIST )) {
1524 ret = ReadMusicTable("songlist", 1);
1525 } else {
1526 /*since bg1 and pst has no .2da for songlist,
1527 we must supply one in the gemrb/override folder.
1528 It should be: music.2da, first column is a .mus filename*/
1529 ret = ReadMusicTable("music", 0);
1531 if (ret) {
1532 printStatus( "OK", LIGHT_GREEN );
1533 } else {
1534 printStatus( "NOT FOUND", YELLOW );
1537 if (HasFeature( GF_RESDATA_INI )) {
1538 printMessage( "Core", "Loading resource data File...", WHITE );
1539 INIresdata = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1540 DataStream* ds = gamedata->GetResource("resdata", IE_INI_CLASS_ID);
1541 if (!INIresdata->Open( ds, true )) {
1542 printStatus( "ERROR", LIGHT_RED );
1543 } else {
1544 printStatus( "OK", LIGHT_GREEN );
1548 if (HasFeature( GF_HAS_PARTY_INI )) {
1549 printMessage( "Core", "Loading precreated teams setup...\n",
1550 WHITE );
1551 INIparty = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1552 FileStream* fs = new FileStream();
1553 char tINIparty[_MAX_PATH];
1554 PathJoin( tINIparty, GamePath, "Party.ini", NULL );
1555 ResolveFilePath( tINIparty );
1556 fs->Open( tINIparty, true );
1557 if (!INIparty->Open( fs, true )) {
1558 printStatus( "ERROR", LIGHT_RED );
1559 } else {
1560 printStatus( "OK", LIGHT_GREEN );
1564 if (HasFeature(GF_IWD2_DEATHVARFORMAT)) {
1565 memcpy(DeathVarFormat, IWD2DeathVarFormat, sizeof(ieVariable));
1568 if (HasFeature( GF_HAS_BEASTS_INI )) {
1569 printMessage( "Core", "Loading beasts definition File...\n",
1570 WHITE );
1571 INIbeasts = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1572 FileStream* fs = new FileStream();
1573 char tINIbeasts[_MAX_PATH];
1574 PathJoin( tINIbeasts, GamePath, "beast.ini", NULL );
1575 ResolveFilePath( tINIbeasts );
1576 // FIXME: crashes if file does not open
1577 fs->Open( tINIbeasts, true );
1578 if (!INIbeasts->Open( fs, true )) {
1579 printStatus( "ERROR", LIGHT_RED );
1580 } else {
1581 printStatus( "OK", LIGHT_GREEN );
1584 printMessage( "Core", "Loading quests definition File...\n",
1585 WHITE );
1586 INIquests = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1587 FileStream* fs2 = new FileStream();
1588 char tINIquests[_MAX_PATH];
1589 PathJoin( tINIquests, GamePath, "quests.ini", NULL );
1590 ResolveFilePath( tINIquests );
1591 // FIXME: crashes if file does not open
1592 fs2->Open( tINIquests, true );
1593 if (!INIquests->Open( fs2, true )) {
1594 printStatus( "ERROR", LIGHT_RED );
1595 } else {
1596 printStatus( "OK", LIGHT_GREEN );
1599 game = NULL;
1600 calendar = NULL;
1602 timer = new GlobalTimer();
1603 printMessage( "Core", "Bringing up the Global Timer...", WHITE );
1604 if (!timer) {
1605 printStatus( "ERROR", LIGHT_RED );
1606 return GEM_ERROR;
1608 printStatus( "OK", LIGHT_GREEN );
1610 ret = Init_EffectQueue();
1611 printMessage( "Core", "Initializing effects...", WHITE );
1612 if (!ret) {
1613 printStatus( "ERROR", LIGHT_RED );
1614 return GEM_ERROR;
1616 printStatus( "OK", LIGHT_GREEN );
1618 ret = InitItemTypes();
1619 printMessage( "Core", "Initializing Inventory Management...", WHITE );
1620 if (!ret) {
1621 printStatus( "ERROR", LIGHT_RED );
1622 return GEM_ERROR;
1624 printStatus( "OK", LIGHT_GREEN );
1626 ret = ReadStrrefs();
1627 printMessage( "Core", "Initializing string constants...", WHITE );
1628 if (!ret) {
1629 printStatus( "ERROR", LIGHT_RED );
1630 return GEM_ERROR;
1632 printStatus( "OK", LIGHT_GREEN );
1634 ret = ReadRandomItems();
1635 printMessage( "Core", "Initializing random treasure...", WHITE );
1636 if (ret) {
1637 printStatus( "OK", LIGHT_GREEN );
1639 else {
1640 printStatus( "ERROR", LIGHT_RED );
1643 ret = ReadAbilityTables();
1644 printMessage( "Core", "Initializing ability tables...", WHITE );
1645 if (!ret) {
1646 printStatus( "ERROR", LIGHT_RED );
1647 return GEM_ERROR;
1649 printStatus( "OK", LIGHT_GREEN );
1651 if ( gamedata->Exists("WMAPLAY", IE_2DA_CLASS_ID) ) {
1652 ret = ReadAreaAliasTable( "WMAPLAY" );
1653 printMessage( "Core", "Initializing area aliases...", WHITE );
1654 if (ret) {
1655 printStatus( "OK", LIGHT_GREEN );
1657 else {
1658 printStatus( "NOT FOUND", YELLOW );
1662 ret = ReadAuxItemTables();
1663 printMessage( "Core", "Reading item tables...", WHITE);
1664 if (!ret) {
1665 printStatus( "ERROR", LIGHT_RED );
1666 return GEM_ERROR;
1668 printStatus( "OK", LIGHT_GREEN );
1670 ret = ReadDamageTypeTable();
1671 printMessage( "Core", "Reading damage type table...", WHITE);
1672 if (!ret) {
1673 printStatus( "ERROR", LIGHT_RED );
1674 } else {
1675 printStatus( "OK", LIGHT_GREEN );
1678 printMessage( "Core", "Core Initialization Complete!\n", WHITE );
1680 return GEM_OK;
1683 bool Interface::IsAvailable(SClass_ID filetype) const
1685 return plugin->IsAvailable( filetype );
1688 WorldMap *Interface::GetWorldMap(const char *map)
1690 int index = worldmap->FindAndSetCurrentMap(map?map:game->CurrentArea);
1691 return worldmap->GetWorldMap(index);
1694 void* Interface::GetInterface(SClass_ID filetype) const
1696 if (!plugin) {
1697 return NULL;
1699 return plugin->GetPlugin( filetype );
1702 ProjectileServer* Interface::GetProjectileServer() const
1704 return projserv;
1707 Video* Interface::GetVideoDriver() const
1709 return video;
1712 PluginMgr* Interface::GetPluginMgr() const
1714 return plugin;
1717 void Interface::RegisterCleanup(void (*func)(void))
1719 cleanupFunctions.push_back(func);
1722 const char* Interface::TypeExt(SClass_ID type) const
1724 switch (type) {
1725 case IE_2DA_CLASS_ID:
1726 return ".2da";
1728 case IE_ACM_CLASS_ID:
1729 return ".acm";
1731 case IE_ARE_CLASS_ID:
1732 return ".are";
1734 case IE_BAM_CLASS_ID:
1735 return ".bam";
1737 case IE_BCS_CLASS_ID:
1738 return ".bcs";
1740 case IE_BS_CLASS_ID:
1741 return ".bs";
1743 case IE_BIF_CLASS_ID:
1744 return ".bif";
1746 case IE_BMP_CLASS_ID:
1747 return ".bmp";
1749 case IE_PNG_CLASS_ID:
1750 return ".png";
1752 case IE_CHR_CLASS_ID:
1753 return ".chr";
1755 case IE_CHU_CLASS_ID:
1756 return ".chu";
1758 case IE_CRE_CLASS_ID:
1759 return ".cre";
1761 case IE_DLG_CLASS_ID:
1762 return ".dlg";
1764 case IE_EFF_CLASS_ID:
1765 return ".eff";
1767 case IE_GAM_CLASS_ID:
1768 return ".gam";
1770 case IE_IDS_CLASS_ID:
1771 return ".ids";
1773 case IE_INI_CLASS_ID:
1774 return ".ini";
1776 case IE_ITM_CLASS_ID:
1777 return ".itm";
1779 case IE_MOS_CLASS_ID:
1780 return ".mos";
1782 case IE_MUS_CLASS_ID:
1783 return ".mus";
1785 case IE_MVE_CLASS_ID:
1786 return ".mve";
1788 case IE_OGG_CLASS_ID:
1789 return ".ogg";
1791 case IE_PLT_CLASS_ID:
1792 return ".plt";
1794 case IE_PRO_CLASS_ID:
1795 return ".pro";
1797 case IE_SAV_CLASS_ID:
1798 return ".sav";
1800 case IE_SPL_CLASS_ID:
1801 return ".spl";
1803 case IE_SRC_CLASS_ID:
1804 return ".src";
1806 case IE_STO_CLASS_ID:
1807 return ".sto";
1809 case IE_TIS_CLASS_ID:
1810 return ".tis";
1812 case IE_TLK_CLASS_ID:
1813 return ".tlk";
1815 case IE_TOH_CLASS_ID:
1816 return ".toh";
1818 case IE_TOT_CLASS_ID:
1819 return ".tot";
1821 case IE_VAR_CLASS_ID:
1822 return ".var";
1824 case IE_VVC_CLASS_ID:
1825 return ".vvc";
1827 case IE_WAV_CLASS_ID:
1828 return ".wav";
1830 case IE_WED_CLASS_ID:
1831 return ".wed";
1833 case IE_WFX_CLASS_ID:
1834 return ".wfx";
1836 case IE_WMP_CLASS_ID:
1837 return ".wmp";
1839 return NULL;
1842 void Interface::FreeString(char *&str) const
1844 if (str) {
1845 strings->FreeString(str);
1847 str = NULL;
1850 ieStrRef Interface::UpdateString(ieStrRef strref, const char *text) const
1852 return strings->UpdateString( strref, text );
1855 char* Interface::GetString(ieStrRef strref, ieDword options) const
1857 ieDword flags = 0;
1859 if (!(options & IE_STR_STRREFOFF)) {
1860 vars->Lookup( "Strref On", flags );
1862 return strings->GetString( strref, flags | options );
1865 void Interface::FreeInterface(Plugin* ptr)
1867 plugin->FreePlugin( ptr );
1870 void Interface::SetFeature(int flag, int position)
1872 if (position>=32) {
1873 position-=32;
1874 if (flag) {
1875 GameFeatures2 |= 1 << position;
1876 } else {
1877 GameFeatures2 &= ~( 1 << position );
1879 return;
1881 if (flag) {
1882 GameFeatures |= 1 << position;
1883 } else {
1884 GameFeatures &= ~( 1 << position );
1888 ieDword Interface::HasFeature(int position) const
1890 if (position>=32) {
1891 return GameFeatures2 & ( 1 << (position-32) );
1893 return GameFeatures & ( 1 << position );
1896 /** Search directories and load a config file */
1897 bool Interface::LoadConfig(void)
1899 #ifndef WIN32
1900 char path[_MAX_PATH];
1901 char name[_MAX_PATH];
1903 // Find directory where user stores GemRB configurations (~/.gemrb).
1904 // FIXME: Create it if it does not exist
1905 // Use current dir if $HOME is not defined (or bomb out??)
1907 char* s = getenv( "HOME" );
1908 if (s) {
1909 strcpy( UserDir, s );
1910 strcat( UserDir, "/."PACKAGE"/" );
1911 } else {
1912 strcpy( UserDir, "./" );
1915 // Find basename of this program. It does the same as basename (3),
1916 // but that's probably missing on some archs
1917 s = strrchr( argv[0], PathDelimiter );
1918 if (s) {
1919 s++;
1920 } else {
1921 s = argv[0];
1924 strcpy( name, s );
1925 //if (!name[0]) // FIXME: could this happen?
1926 // strcpy (name, PACKAGE); // ugly hack
1928 // If we were called as $0 -c <filename>, load config from filename
1929 if (argc > 2 && ! strcmp("-c", argv[1])) {
1930 if (LoadConfig( argv[2] )) {
1931 return true;
1932 } else {
1933 // Explicitly specified cfg file HAS to be present
1934 return false;
1938 // FIXME: temporary hack, to be deleted??
1939 if (LoadConfig( "GemRB.cfg" )) {
1940 return true;
1943 PathJoin( path, UserDir, name, NULL );
1944 strcat( path, ".cfg" );
1946 if (LoadConfig( path )) {
1947 return true;
1950 #ifdef SYSCONFDIR
1951 PathJoin( path, SYSCONFDIR, name, NULL );
1952 strcat( path, ".cfg" );
1954 if (LoadConfig( path )) {
1955 return true;
1957 #endif
1959 // Don't try with default binary name if we have tried it already
1960 if (!strcmp( name, PACKAGE )) {
1961 return false;
1964 PathJoin( path, UserDir, PACKAGE, NULL );
1965 strcat( path, ".cfg" );
1967 if (LoadConfig( path )) {
1968 return true;
1971 #ifdef SYSCONFDIR
1972 PathJoin( path, SYSCONFDIR, PACKAGE, NULL );
1973 strcat( path, ".cfg" );
1975 if (LoadConfig( path )) {
1976 return true;
1978 #endif
1980 return false;
1981 #else // WIN32
1982 // If we were called as $0 -c <filename>, load config from filename
1983 if (argc > 2 && ! strcmp("-c", argv[1])) {
1984 return LoadConfig( argv[2] );
1985 // Explicitly specified cfg file HAS to be present
1987 strcpy( UserDir, ".\\" );
1988 return LoadConfig( "GemRB.cfg" );
1989 #endif// WIN32
1992 bool Interface::LoadConfig(const char* filename)
1994 FILE* config;
1996 printMessage("Config","Trying to open ", WHITE);
1997 textcolor(LIGHT_WHITE);
1998 printf("%s ", filename);
1999 config = fopen( filename, "rb" );
2000 if (config == NULL) {
2001 printStatus("NOT FOUND", LIGHT_RED);
2002 return false;
2004 char name[65], value[_MAX_PATH + 3];
2006 //once GemRB own format is working well, this might be set to 0
2007 SaveAsOriginal = 1;
2009 while (!feof( config )) {
2010 char rem;
2012 if (fread( &rem, 1, 1, config ) != 1)
2013 break;
2015 if (rem == '#') {
2016 //it should always return 0
2017 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
2018 break;
2019 continue;
2021 fseek( config, -1, SEEK_CUR );
2022 memset(value,'\0',_MAX_PATH + 3);
2023 //the * element is not counted
2024 if (fscanf( config, "%64[^= ] = %[^\r\n]%*[\r\n]", name, value )!=2)
2025 continue;
2026 for (int i=_MAX_PATH + 2; i > 0; i--) {
2027 if (value[i] == '\0') continue;
2028 if (value[i] == ' ') {
2029 value[i] = '\0';
2030 } else {
2031 break;
2035 if (stricmp( name, "Width" ) == 0) {
2036 Width = atoi( value );
2037 } else if (stricmp( name, "Height" ) == 0) {
2038 Height = atoi( value );
2039 } else if (stricmp( name, "Bpp" ) == 0) {
2040 Bpp = atoi( value );
2041 } else if (stricmp( name, "FullScreen" ) == 0) {
2042 FullScreen = ( atoi( value ) == 0 ) ? false : true;
2043 } else if (stricmp( name, "GUIEnhancements" ) == 0) {
2044 GUIEnhancements = ( atoi( value ) == 0 ) ? false : true;
2045 } else if (stricmp( name, "TooltipDelay" ) == 0) {
2046 TooltipDelay = atoi( value );
2047 } else if (stricmp( name, "DoubleClickDelay" ) == 0) {
2048 evntmgr->SetDCDelay( atoi( value ) );
2049 } else if (stricmp( name, "RepeatKeyDelay" ) == 0) {
2050 evntmgr->SetRKDelay( atoi( value ) );
2051 } else if (stricmp( name, "SkipIntroVideos" ) == 0) {
2052 SkipIntroVideos = ( atoi( value ) == 0 ) ? false : true;
2053 } else if (stricmp( name, "DrawFPS" ) == 0) {
2054 DrawFPS = ( atoi( value ) == 0 ) ? false : true;
2055 } else if (stricmp( name, "EnableCheatKeys" ) == 0) {
2056 EnableCheatKeys ( atoi( value ) );
2057 } else if (stricmp( name, "KeepCache" ) == 0) {
2058 KeepCache = ( atoi( value ) == 0 ) ? false : true;
2059 } else if (stricmp( name, "SkipPlugin" ) == 0) {
2060 plugin_flags->SetAt( value, PLF_SKIP );
2061 } else if (stricmp( name, "DelayPlugin" ) == 0) {
2062 plugin_flags->SetAt( value, PLF_DELAY );
2063 } else if (stricmp( name, "FogOfWar" ) == 0) {
2064 FogOfWar = atoi( value );
2065 } else if (stricmp( name, "EndianSwitch" ) == 0) {
2066 DataStream::SetEndianSwitch(atoi(value) );
2067 } else if (stricmp( name, "CaseSensitive" ) == 0) {
2068 CaseSensitive = ( atoi( value ) == 0 ) ? false : true;
2069 } else if (stricmp( name, "MultipleQuickSaves" ) == 0) {
2070 GameControl::MultipleQuickSaves(atoi(value));
2071 } else if (stricmp( name, "GameOnCD" ) == 0) {
2072 GameOnCD = ( atoi( value ) == 0 ) ? false : true;
2073 } else if (stricmp( name, "GameDataPath" ) == 0) {
2074 strncpy( GameDataPath, value, sizeof(GameDataPath) );
2075 } else if (stricmp( name, "GameOverridePath" ) == 0) {
2076 strncpy( GameOverridePath, value, sizeof(GameOverridePath) );
2077 } else if (stricmp( name, "GemRBOverridePath" ) == 0) {
2078 strncpy( GemRBOverridePath, value, sizeof(GemRBOverridePath) );
2079 } else if (stricmp( name, "GameScriptsPath" ) == 0) {
2080 strncpy( GameScriptsPath, value, sizeof(GameScriptsPath) );
2081 } else if (stricmp( name, "GameSoundsPath" ) == 0) {
2082 strncpy( GameSoundsPath, value, sizeof(GameSoundsPath) );
2083 } else if (stricmp( name, "GamePortraitsPath" ) == 0) {
2084 strncpy( GamePortraitsPath, value, sizeof(GamePortraitsPath) );
2085 } else if (stricmp( name, "GameCharactersPath" ) == 0) {
2086 strncpy( GameCharactersPath, value, sizeof(GameCharactersPath) );
2087 } else if (stricmp( name, "GameName" ) == 0) {
2088 strncpy( GameName, value, sizeof(GameName) );
2089 } else if (stricmp( name, "GameType" ) == 0) {
2090 if (stricmp( value, "tob" ) == 0) {
2091 strncpy( GameType, "bg2", sizeof(GameType) );
2092 } else {
2093 strncpy( GameType, value, sizeof(GameType) );
2095 } else if (stricmp( name, "SaveAsOriginal") == 0) {
2096 SaveAsOriginal = atoi(value);
2097 } else if (stricmp( name, "GemRBPath" ) == 0) {
2098 strcpy( GemRBPath, value );
2099 } else if (stricmp( name, "ScriptDebugMode" ) == 0) {
2100 SetScriptDebugMode(atoi(value));
2101 } else if (stricmp( name, "CachePath" ) == 0) {
2102 strncpy( CachePath, value, sizeof(CachePath) );
2103 } else if (stricmp( name, "GUIScriptsPath" ) == 0) {
2104 strncpy( GUIScriptsPath, value, sizeof(GUIScriptsPath) );
2105 ResolveFilePath( GUIScriptsPath );
2106 } else if (stricmp( name, "PluginsPath" ) == 0) {
2107 strncpy( PluginsPath, value, sizeof(PluginsPath) );
2108 ResolveFilePath( PluginsPath );
2109 } else if (stricmp( name, "GamePath" ) == 0) {
2110 strncpy( GamePath, value, sizeof(GamePath) );
2111 ResolveFilePath( GamePath );
2112 } else if (stricmp( name, "SavePath" ) == 0) {
2113 strncpy( SavePath, value, sizeof(SavePath) );
2114 ResolveFilePath( SavePath );
2115 } else if (strnicmp( name, "CD", 2 ) == 0 &&
2116 name[2] >= '1' && name[2] <= '5' && name[3] == 0) {
2117 strncpy( CD[name[2]-'1'], value, sizeof(CD[name[2]-'1']) );
2118 ResolveFilePath( CD[name[2]-'1'] );
2121 fclose( config );
2124 if (!GameType[0]) {
2125 strcpy( GameType, "gemrb" );
2128 #ifdef DATADIR
2129 if (!GemRBPath[0]) {
2130 strcpy( GemRBPath, DATADIR );
2132 #endif
2134 if (!GemRBOverridePath[0]) {
2135 strcpy( GemRBOverridePath, GemRBPath );
2138 if (!PluginsPath[0]) {
2139 #ifdef PLUGINDIR
2140 strcpy( PluginsPath, PLUGINDIR );
2141 #else
2142 PathJoin( PluginsPath, GemRBPath, "plugins", NULL );
2143 #endif
2146 if (!GUIScriptsPath[0]) {
2147 strcpy( GUIScriptsPath, GemRBPath );
2150 if (!GameName[0]) {
2151 strcpy( GameName, GEMRB_STRING );
2154 if (!SavePath[0]) {
2155 // FIXME: maybe should use UserDir instead of GamePath
2156 strcpy( SavePath, GamePath );
2159 if (! CachePath[0]) {
2160 PathJoin( CachePath, UserDir, "Cache", NULL );
2164 FixPath( GUIScriptsPath, true );
2165 FixPath( PluginsPath, true );
2166 FixPath( GemRBPath, true );
2167 FixPath( GemRBOverridePath, true );
2169 if (GamePath[0]) {
2170 FixPath( GamePath, true );
2173 //FixPath( SavePath, false );
2174 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2175 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2176 FixPath( SavePath, true );
2178 FixPath( CachePath, false );
2179 mkdir( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2180 chmod( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2182 printStatus( "OK", LIGHT_GREEN );
2183 if ( StupidityDetector( CachePath )) {
2184 printMessage("Core"," ",LIGHT_RED);
2185 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath );
2186 return false;
2188 if (!KeepCache) DelTree((const char *) CachePath, false);
2189 FixPath( CachePath, true );
2191 return true;
2194 static void upperlower(int upper, int lower)
2196 pl_uppercase[lower]=(ieByte) upper;
2197 pl_lowercase[upper]=(ieByte) lower;
2200 static const char *game_flags[GF_COUNT+1]={
2201 "HasKaputz", //0 GF_HAS_KAPUTZ
2202 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2203 "HasSongList", //2 GF_HAS_SONGLIST
2204 "TeamMovement", //3 GF_TEAM_MOVEMENT
2205 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2206 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2207 "HasPartyIni", //6 GF_HAS_PARTY_INI
2208 "SoundFolders", //7 GF_SOUNDFOLDERS
2209 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2210 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2211 "HasDPLAYER", //10GF_HAS_DPLAYER
2212 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2213 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2214 "HasDescIcon", //13GF_HAS_DESC_ICON
2215 "HasPickSound", //14GF_HAS_PICK_SOUND
2216 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2217 "AutomapIni", //16GF_AUTOMAP_INI
2218 "SmallFog", //17GF_SMALL_FOG
2219 "ReverseDoor", //18GF_REVERSE_DOOR
2220 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2221 "HasSpellList", //20GF_HAS_SPELLLIST
2222 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2223 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2224 "KnowWorld", //23GF_KNOW_WORLD
2225 "ReverseToHit", //24GF_REVERSE_TOHIT
2226 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2227 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2228 "MagicBit", //27GF_MAGICBIT
2229 "CheckAbilities", //28GF_CHECK_ABILITIES
2230 "ChallengeRating", //29GF_CHALLENGERATING
2231 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2232 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2233 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2234 "SpawnIni", //33GF_SPAWN_INI
2235 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2236 "HasResDataIni", //35GF_RESDATA_INI
2237 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2238 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2239 "3EdRules", //38GF_3ED_RULES
2240 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2241 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2242 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2243 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2244 "ProperBackstab", //43GF_PROPER_BACKSTAB
2245 "OnScreenText", //44GF_ONSCREEN_TEXT
2246 NULL //for our own safety, this marks the end of the pole
2249 /** Loads gemrb.ini */
2250 bool Interface::LoadGemRBINI()
2252 DataStream* inifile = gamedata->GetResource( "gemrb", IE_INI_CLASS_ID );
2253 if (! inifile) {
2254 printStatus( "ERROR", LIGHT_RED );
2255 return false;
2258 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE );
2259 printf( "%s",inifile->originalfile);
2261 if (!IsAvailable( IE_INI_CLASS_ID )) {
2262 printStatus( "ERROR", LIGHT_RED );
2263 printf( "[Core]: No INI Importer Available.\n" );
2264 return false;
2266 DataFileMgr* ini = ( DataFileMgr* ) GetInterface( IE_INI_CLASS_ID );
2267 ini->Open( inifile, true ); //autofree
2269 printStatus( "OK", LIGHT_GREEN );
2271 const char *s;
2273 // Resrefs are already initialized in Interface::Interface()
2274 s = ini->GetKeyAsString( "resources", "CursorBAM", NULL );
2275 if (s)
2276 strnlwrcpy( CursorBam, s, 8 ); //console cursor
2278 s = ini->GetKeyAsString( "resources", "ScrollCursorBAM", NULL );
2279 if (s)
2280 strnlwrcpy( ScrollCursorBam, s, 8 );
2282 s = ini->GetKeyAsString( "resources", "ButtonFont", NULL );
2283 if (s)
2284 strnlwrcpy( ButtonFont, s, 8 );
2286 s = ini->GetKeyAsString( "resources", "TooltipFont", NULL );
2287 if (s)
2288 strnlwrcpy( TooltipFont, s, 8 );
2290 s = ini->GetKeyAsString( "resources", "MovieFont", NULL );
2291 if (s)
2292 strnlwrcpy( MovieFont, s, 8 );
2294 s = ini->GetKeyAsString( "resources", "TooltipBack", NULL );
2295 if (s)
2296 strnlwrcpy( TooltipBackResRef, s, 8 );
2298 s = ini->GetKeyAsString( "resources", "TooltipColor", NULL );
2299 if (s) {
2300 if (s[0] == '#') {
2301 unsigned long c = strtoul (s + 1, NULL, 16);
2302 // FIXME: check errno
2303 TooltipColor.r = (unsigned char) (c >> 24);
2304 TooltipColor.g = (unsigned char) (c >> 16);
2305 TooltipColor.b = (unsigned char) (c >> 8);
2306 TooltipColor.a = (unsigned char) (c);
2310 //which stat determines the fist weapon (defaults to class)
2311 Actor::SetFistStat(ini->GetKeyAsInt( "resources", "FistStat", IE_CLASS));
2313 TooltipMargin = ini->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin );
2315 // The format of GroundCircle can be:
2316 // GroundCircleBAM1 = wmpickl/3
2317 // to denote that the bitmap should be scaled down 3x
2318 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
2319 char name[30];
2320 sprintf( name, "GroundCircleBAM%d", size+1 );
2321 s = ini->GetKeyAsString( "resources", name, NULL );
2322 if (s) {
2323 const char *pos = strchr( s, '/' );
2324 if (pos) {
2325 GroundCircleScale[size] = atoi( pos+1 );
2326 strncpy( GroundCircleBam[size], s, pos - s );
2327 GroundCircleBam[size][pos - s] = '\0';
2328 } else {
2329 strcpy( GroundCircleBam[size], s );
2334 s = ini->GetKeyAsString( "resources", "INIConfig", NULL );
2335 if (s)
2336 strcpy( INIConfig, s );
2338 s = ini->GetKeyAsString( "resources", "Palette16", NULL );
2339 if (s)
2340 strcpy( Palette16, s );
2342 s = ini->GetKeyAsString( "resources", "Palette32", NULL );
2343 if (s)
2344 strcpy( Palette32, s );
2346 s = ini->GetKeyAsString( "resources", "Palette256", NULL );
2347 if (s)
2348 strcpy( Palette256, s );
2350 unsigned int i = (unsigned int) ini->GetKeyAsInt ("charset", "CharCount", 0);
2351 if (i>99) i=99;
2352 while(i--) {
2353 char key[10];
2354 snprintf(key,9,"Letter%d", i+1);
2355 s = ini->GetKeyAsString( "charset", key, NULL );
2356 if (s) {
2357 const char *s2 = strchr(s,',');
2358 if (s2) {
2359 upperlower(atoi(s), atoi(s2+1) );
2364 MaximumAbility = ini->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2366 RedrawTile = ini->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2368 for (i=0;i<GF_COUNT;i++) {
2369 if (!game_flags[i]) {
2370 printf("Fix the game flags!\n");
2371 abort();
2373 SetFeature( ini->GetKeyAsInt( "resources", game_flags[i], 0 ), i );
2374 printMessage("Option", "", GREEN);
2375 printf("%s = %s\n", game_flags[i], HasFeature(i)?"yes":"no");
2378 ForceStereo = ini->GetKeyAsInt( "resources", "ForceStereo", 0 );
2380 FreeInterface( ini );
2381 return true;
2384 Palette* Interface::CreatePalette(const Color &color, const Color &back)
2386 Palette* pal = new Palette();
2387 pal->col[0].r = 0;
2388 pal->col[0].g = 0xff;
2389 pal->col[0].b = 0;
2390 pal->col[0].a = 0;
2391 for (int i = 1; i < 256; i++) {
2392 pal->col[i].r = back.r +
2393 ( unsigned char ) ( ( ( color.r - back.r ) * ( i ) ) / 255.0 );
2394 pal->col[i].g = back.g +
2395 ( unsigned char ) ( ( ( color.g - back.g ) * ( i ) ) / 255.0 );
2396 pal->col[i].b = back.b +
2397 ( unsigned char ) ( ( ( color.b - back.b ) * ( i ) ) / 255.0 );
2398 pal->col[i].a = back.a +
2399 ( unsigned char ) ( ( ( color.a - back.a ) * ( i ) ) / 255.0 );
2401 return pal;
2404 /** No descriptions */
2405 Color* Interface::GetPalette(unsigned index, int colors, Color *pal) const
2407 Image *img;
2408 if (colors == 32) {
2409 img = pal32;
2410 } else if (colors <= 32) {
2411 img = pal16;
2412 } else if (colors == 256) {
2413 img = pal256;
2414 } else {
2415 return pal;
2417 if (index >= img->GetHeight()) {
2418 index = 0;
2420 for (int i = 0; i < colors; i++) {
2421 pal[i] = img->GetPixel(i, index);
2423 return pal;
2425 /** Returns a preloaded Font */
2426 Font* Interface::GetFont(const char *ResRef) const
2428 for (unsigned int i = 0; i < fonts.size(); i++) {
2429 if (strnicmp( fonts[i]->ResRef, ResRef, 8 ) == 0) {
2430 return fonts[i];
2433 return NULL;
2436 Font* Interface::GetFont(unsigned int index) const
2438 if (index >= fonts.size()) {
2439 return NULL;
2441 return fonts[index];
2444 Font* Interface::GetButtonFont() const
2446 return GetFont( ButtonFont );
2449 /** Returns the Event Manager */
2450 EventMgr* Interface::GetEventMgr() const
2452 return evntmgr;
2455 /** Returns the Window Manager */
2456 WindowMgr* Interface::GetWindowMgr() const
2458 return windowmgr;
2461 /** Get GUI Script Manager */
2462 ScriptEngine* Interface::GetGUIScriptEngine() const
2464 return guiscript;
2467 //NOTE: if there were more summoned creatures, it will return only the last
2468 Actor *Interface::SummonCreature(const ieResRef resource, const ieResRef vvcres, Scriptable *Owner, Actor *target, Point &position, int eamod, int level, Effect *fx)
2470 //maximum number of monsters summoned
2471 int cnt=10;
2472 Actor * ab = NULL;
2474 //TODO:
2475 //decrease the number of summoned creatures with the number of already summoned creatures here
2476 //the summoned creatures have a special IE_SPECIFIC
2478 while(cnt--) {
2479 ab = gamedata->GetCreature(resource);
2480 if (!ab) {
2481 return NULL;
2484 if (Owner && Owner->Type==ST_ACTOR) {
2485 ab->LastSummoner = ((Actor *) Owner)->GetID();
2487 //Always use Base stats for the recently summoned creature
2489 int enemyally;
2491 if (eamod==EAM_SOURCEALLY || eamod==EAM_SOURCEENEMY) {
2492 if (Owner && Owner->Type==ST_ACTOR) {
2493 enemyally = ((Actor *) Owner)->GetStat(IE_EA)>EA_GOODCUTOFF;
2494 } else {
2495 enemyally = true;
2497 } else {
2498 if (target) {
2499 enemyally = target->GetBase(IE_EA)>EA_GOODCUTOFF;
2500 } else {
2501 enemyally = true;
2505 switch (eamod) {
2506 case EAM_SOURCEALLY:
2507 case EAM_ALLY:
2508 if (enemyally) {
2509 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2510 } else {
2511 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2513 break;
2514 case EAM_SOURCEENEMY:
2515 case EAM_ENEMY:
2516 if (enemyally) {
2517 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2518 } else {
2519 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2521 break;
2522 case EAM_NEUTRAL:
2523 ab->SetBase(IE_EA, EA_NEUTRAL);
2524 break;
2525 default:
2526 break;
2529 Map *map;
2530 if (target) {
2531 map = target->GetCurrentArea();
2532 } else {
2533 map = Owner->GetCurrentArea();
2535 map->AddActor(ab);
2536 ab->SetPosition(position, true, 0);
2537 ab->RefreshEffects(NULL);
2539 if (vvcres[0]) {
2540 ScriptedAnimation* vvc = gamedata->GetScriptedAnimation(vvcres, false);
2541 if (vvc) {
2542 //This is the final position of the summoned creature
2543 //not the original target point
2544 vvc->XPos=ab->Pos.x;
2545 vvc->YPos=ab->Pos.y;
2546 //force vvc to play only once
2547 vvc->PlayOnce();
2548 map->AddVVCell( vvc );
2552 //remove the xp value of friendly summons
2553 if (ab->BaseStats[IE_EA]<EA_GOODCUTOFF) {
2554 ab->SetBase(IE_XPVALUE, 0);
2556 if (fx) {
2557 ApplyEffect(fx, ab, Owner);
2560 //this check should happen after the fact
2561 level -= ab->GetBase(IE_XP);
2562 if(level<0) {
2563 break;
2567 return ab;
2570 void Interface::RedrawControls(const char *varname, unsigned int value)
2572 for (unsigned int i = 0; i < windows.size(); i++) {
2573 Window *win = windows[i];
2574 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2575 win->RedrawControls(varname, value);
2580 void Interface::RedrawAll()
2582 for (unsigned int i = 0; i < windows.size(); i++) {
2583 Window *win = windows[i];
2584 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2585 win->Invalidate();
2590 /** Loads a WindowPack (CHUI file) in the Window Manager */
2591 bool Interface::LoadWindowPack(const char* name)
2593 DataStream* stream = gamedata->GetResource( name, IE_CHU_CLASS_ID );
2594 if (stream == NULL) {
2595 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED );
2596 printf( "%s.chu\n", name );
2597 return false;
2599 if (!GetWindowMgr()->Open( stream, true )) {
2600 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED );
2601 printf( "%s.chu\n", name );
2602 return false;
2605 strncpy( WindowPack, name, sizeof( WindowPack ) );
2606 WindowPack[sizeof( WindowPack ) - 1] = '\0';
2608 return true;
2611 /** Loads a Window in the Window Manager */
2612 int Interface::LoadWindow(unsigned short WindowID)
2614 unsigned int i;
2616 for (i = 0; i < windows.size(); i++) {
2617 Window *win = windows[i];
2618 if (win == NULL)
2619 continue;
2620 if (win->Visible==WINDOW_INVALID) {
2621 continue;
2623 if (win->WindowID == WindowID &&
2624 !strnicmp( WindowPack, win->WindowPack, sizeof(WindowPack) )) {
2625 SetOnTop( i );
2626 win->Invalidate();
2627 return i;
2630 Window* win = windowmgr->GetWindow( WindowID );
2631 if (win == NULL) {
2632 return -1;
2634 memcpy( win->WindowPack, WindowPack, sizeof(WindowPack) );
2636 int slot = -1;
2637 for (i = 0; i < windows.size(); i++) {
2638 if (windows[i] == NULL) {
2639 slot = i;
2640 break;
2643 if (slot == -1) {
2644 windows.push_back( win );
2645 slot = ( int ) windows.size() - 1;
2646 } else {
2647 windows[slot] = win;
2649 win->Invalidate();
2650 return slot;
2652 // FIXME: it's a clone of LoadWindow
2653 /** Creates a Window in the Window Manager */
2654 int Interface::CreateWindow(unsigned short WindowID, int XPos, int YPos, unsigned int Width, unsigned int Height, char* Background)
2656 unsigned int i;
2658 for (i = 0; i < windows.size(); i++) {
2659 if (windows[i] == NULL)
2660 continue;
2661 if (windows[i]->WindowID == WindowID && !stricmp( WindowPack,
2662 windows[i]->WindowPack )) {
2663 SetOnTop( i );
2664 windows[i]->Invalidate();
2665 return i;
2669 Window* win = new Window( WindowID, (ieWord) XPos, (ieWord) YPos, (ieWord) Width, (ieWord) Height );
2670 if (Background[0]) {
2671 if (IsAvailable( IE_MOS_CLASS_ID )) {
2672 ImageMgr* mos = ( ImageMgr* )
2673 gamedata->GetResource( Background, &ImageMgr::ID );
2674 if (mos != NULL) {
2675 win->SetBackGround( mos->GetSprite2D(), true );
2676 FreeInterface( mos );
2677 } else
2678 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2679 } else
2680 printf( "[Core]: No MOS Importer Available, skipping background\n" );
2683 strcpy( win->WindowPack, WindowPack );
2685 int slot = -1;
2686 for (i = 0; i < windows.size(); i++) {
2687 if (windows[i] == NULL) {
2688 slot = i;
2689 break;
2692 if (slot == -1) {
2693 windows.push_back( win );
2694 slot = ( int ) windows.size() - 1;
2695 } else {
2696 windows[slot] = win;
2698 win->Invalidate();
2699 return slot;
2702 /** Sets a Window on the Top */
2703 void Interface::SetOnTop(int Index)
2705 std::vector<int>::iterator t;
2706 for(t = topwin.begin(); t != topwin.end(); ++t) {
2707 if((*t) == Index) {
2708 topwin.erase(t);
2709 break;
2712 if(topwin.size() != 0)
2713 topwin.insert(topwin.begin(), Index);
2714 else
2715 topwin.push_back(Index);
2717 /** Add a window to the Window List */
2718 void Interface::AddWindow(Window * win)
2720 int slot = -1;
2721 for(unsigned int i = 0; i < windows.size(); i++) {
2722 Window *w = windows[i];
2724 if(w==NULL) {
2725 slot = i;
2726 break;
2729 if(slot == -1) {
2730 windows.push_back(win);
2731 slot=(int)windows.size()-1;
2733 else
2734 windows[slot] = win;
2735 win->Invalidate();
2738 /** Get a Control on a Window */
2739 int Interface::GetControl(unsigned short WindowIndex, unsigned long ControlID) const
2741 if (WindowIndex >= windows.size()) {
2742 return -1;
2744 Window* win = windows[WindowIndex];
2745 if (win == NULL) {
2746 return -1;
2748 int i = 0;
2749 while (true) {
2750 Control* ctrl = win->GetControl( (unsigned short) i );
2751 if (ctrl == NULL)
2752 return -1;
2753 if (ctrl->ControlID == ControlID)
2754 return i;
2755 i++;
2758 /** Adjust the Scrolling factor of a control (worldmap atm) */
2759 int Interface::AdjustScrolling(unsigned short WindowIndex,
2760 unsigned short ControlIndex, short x, short y)
2762 if (WindowIndex >= windows.size()) {
2763 return -1;
2765 Window* win = windows[WindowIndex];
2766 if (win == NULL) {
2767 return -1;
2769 Control* ctrl = win->GetControl( ControlIndex );
2770 if (ctrl == NULL) {
2771 return -1;
2773 switch(ctrl->ControlType) {
2774 case IE_GUI_WORLDMAP:
2775 ((WorldMapControl *) ctrl)->AdjustScrolling(x,y);
2776 break;
2777 default: //doesn't work for these
2778 return -1;
2780 return 0;
2783 /** Set the Text of a Control */
2784 int Interface::SetText(unsigned short WindowIndex,
2785 unsigned short ControlIndex, const char* string)
2787 if (WindowIndex >= windows.size()) {
2788 return -1;
2790 Window* win = windows[WindowIndex];
2791 if (win == NULL) {
2792 return -1;
2794 Control* ctrl = win->GetControl( ControlIndex );
2795 if (ctrl == NULL) {
2796 return -1;
2798 return ctrl->SetText( string );
2800 /** Set the Tooltip text of a Control */
2801 int Interface::SetTooltip(unsigned short WindowIndex,
2802 unsigned short ControlIndex, const char* string)
2804 if (WindowIndex >= windows.size()) {
2805 return -1;
2807 Window* win = windows[WindowIndex];
2808 if (win == NULL) {
2809 return -1;
2811 Control* ctrl = win->GetControl( ControlIndex );
2812 if (ctrl == NULL) {
2813 return -1;
2815 return ctrl->SetTooltip( string );
2818 void Interface::DisplayTooltip(int x, int y, Control *ctrl)
2820 if (tooltip_ctrl && tooltip_ctrl == ctrl && tooltip_x == x && tooltip_y == y)
2821 return;
2822 tooltip_x = x;
2823 tooltip_y = y;
2824 tooltip_currtextw = 0;
2825 tooltip_ctrl = ctrl;
2828 int Interface::GetVisible(unsigned short WindowIndex) const
2830 if (WindowIndex >= windows.size()) {
2831 return -1;
2833 Window* win = windows[WindowIndex];
2834 if (win == NULL) {
2835 return -1;
2837 return win->Visible;
2839 /** Set a Window Visible Flag */
2840 int Interface::SetVisible(unsigned short WindowIndex, int visible)
2842 if (WindowIndex >= windows.size()) {
2843 return -1;
2845 Window* win = windows[WindowIndex];
2846 if (win == NULL) {
2847 return -1;
2849 if (visible!=WINDOW_FRONT) {
2850 win->Visible = (char) visible;
2852 switch (visible) {
2853 case WINDOW_GRAYED:
2854 win->Invalidate();
2855 //here is a fallthrough
2856 case WINDOW_INVISIBLE:
2857 //hiding the viewport if the gamecontrol window was made invisible
2858 if (win->WindowID==65535) {
2859 video->SetViewport( 0,0,0,0 );
2861 evntmgr->DelWindow( win );
2862 break;
2864 case WINDOW_VISIBLE:
2865 if (win->WindowID==65535) {
2866 video->SetViewport( win->XPos, win->YPos, win->Width, win->Height);
2868 //here is a fallthrough
2869 case WINDOW_FRONT:
2870 if (win->Visible==WINDOW_VISIBLE) {
2871 evntmgr->AddWindow( win );
2873 win->Invalidate();
2874 SetOnTop( WindowIndex );
2875 break;
2877 return 0;
2881 /** Set the Status of a Control in a Window */
2882 int Interface::SetControlStatus(unsigned short WindowIndex,
2883 unsigned short ControlIndex, unsigned long Status)
2885 //don't set the status of an already invalidated window
2886 Window* win = GetWindow(WindowIndex);
2887 if (win == NULL) {
2888 return -1;
2890 Control* ctrl = win->GetControl( ControlIndex );
2891 if (ctrl == NULL) {
2892 return -1;
2894 if (Status&IE_GUI_CONTROL_FOCUSED) {
2895 evntmgr->SetFocused( win, ctrl);
2897 if (ctrl->ControlType != ((Status >> 24) & 0xff) ) {
2898 return -2;
2900 switch (ctrl->ControlType) {
2901 case IE_GUI_BUTTON:
2902 //Button
2904 Button* btn = ( Button* ) ctrl;
2905 btn->SetState( ( unsigned char ) ( Status & 0x7f ) );
2907 break;
2908 default:
2909 ctrl->Value = Status & 0x7f;
2910 break;
2912 return 0;
2915 /** Show a Window in Modal Mode */
2916 int Interface::ShowModal(unsigned short WindowIndex, int Shadow)
2918 if (WindowIndex >= windows.size()) {
2919 printMessage( "Core", "Window not found", LIGHT_RED );
2920 return -1;
2922 Window* win = windows[WindowIndex];
2923 if (win == NULL) {
2924 printMessage( "Core", "Window already freed", LIGHT_RED );
2925 return -1;
2927 win->Visible = WINDOW_FRONT;
2928 //don't destroy the other window handlers
2929 //evntmgr->Clear();
2930 SetOnTop( WindowIndex );
2931 evntmgr->AddWindow( win );
2932 evntmgr->SetFocused( win, NULL );
2934 ModalWindow = NULL;
2935 DrawWindows();
2936 win->Invalidate();
2938 Color gray = {
2939 0, 0, 0, 128
2941 Color black = {
2942 0, 0, 0, 255
2945 Region r( 0, 0, Width, Height );
2947 if (Shadow == MODAL_SHADOW_GRAY) {
2948 video->DrawRect( r, gray );
2949 } else if (Shadow == MODAL_SHADOW_BLACK) {
2950 video->DrawRect( r, black );
2953 ModalWindow = win;
2954 return 0;
2957 bool Interface::IsFreezed()
2959 return !update_scripts;
2962 void Interface::GameLoop(void)
2964 update_scripts = false;
2965 GameControl *gc = GetGameControl();
2966 if (gc) {
2967 update_scripts = !(gc->GetDialogueFlags() & DF_FREEZE_SCRIPTS);
2970 GSUpdate(update_scripts);
2972 //i'm not sure if this should be here
2974 //in multi player (if we ever get to it), only the server must call this
2975 if (update_scripts) {
2976 if ( game->selected.size() > 0 ) {
2977 gc->ChangeMap(core->GetFirstSelectedPC(true), false);
2979 // the game object will run the area scripts as well
2980 game->UpdateScripts();
2984 /** handles hardcoded gui behaviour */
2985 void Interface::HandleGUIBehaviour(void)
2987 GameControl *gc = GetGameControl();
2988 if (gc) {
2989 //this variable is used all over in the following hacks
2990 int flg = gc->GetDialogueFlags();
2992 //the following part is a series of hardcoded gui behaviour
2994 //initiating dialog
2995 if (flg & DF_IN_DIALOG) {
2996 // -3 noaction
2997 // -2 close
2998 // -1 open
2999 // choose option
3000 ieDword var = (ieDword) -3;
3001 vars->Lookup("DialogChoose", var);
3002 if ((int) var == -2) {
3003 gc->EndDialog();
3004 } else if ( (int)var !=-3) {
3005 gc->DialogChoose(var);
3006 if (!(gc->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW | DF_OPENENDWINDOW)))
3007 guiscript->RunFunction( "NextDialogState" );
3009 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3010 ieDword newvar = 0; vars->Lookup("DialogChoose", newvar);
3011 if (var == (ieDword) -1 || newvar != (ieDword) -1) {
3012 vars->SetAt("DialogChoose", (ieDword) -3);
3015 if (flg & DF_OPENCONTINUEWINDOW) {
3016 guiscript->RunFunction( "OpenContinueMessageWindow" );
3017 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3018 } else if (flg & DF_OPENENDWINDOW) {
3019 guiscript->RunFunction( "OpenEndMessageWindow" );
3020 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3024 //handling container
3025 if (CurrentContainer && UseContainer) {
3026 if (!(flg & DF_IN_CONTAINER) ) {
3027 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_OR);
3028 guiscript->RunFunction( "OpenContainerWindow" );
3030 } else {
3031 if (flg & DF_IN_CONTAINER) {
3032 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_NAND);
3033 guiscript->RunFunction( "CloseContainerWindow" );
3036 //end of gui hacks
3040 void Interface::DrawWindows(void)
3042 //here comes the REAL drawing of windows
3043 if (ModalWindow) {
3044 ModalWindow->DrawWindow();
3045 return;
3047 size_t i = topwin.size();
3048 while(i--) {
3049 unsigned int t = topwin[i];
3051 if ( t >=windows.size() )
3052 continue;
3054 //visible ==1 or 2 will be drawn
3055 Window* win = windows[t];
3056 if (win != NULL) {
3057 if (win->Visible == WINDOW_INVALID) {
3058 topwin.erase(topwin.begin()+i);
3059 evntmgr->DelWindow( win );
3060 delete win;
3061 windows[t]=NULL;
3062 } else if (win->Visible) {
3063 win->DrawWindow();
3069 void Interface::DrawTooltip ()
3071 if (! tooltip_ctrl || !tooltip_ctrl->Tooltip)
3072 return;
3074 Font* fnt = GetFont( TooltipFont );
3075 char *tooltip_text = tooltip_ctrl->Tooltip;
3077 int w1 = 0;
3078 int w2 = 0;
3079 int strw = fnt->CalcStringWidth( tooltip_text ) + 8;
3080 int w = strw;
3081 int h = fnt->maxHeight;
3083 if (TooltipBack) {
3084 // animate BG tooltips
3085 // TODO: make tooltip animation an option instead
3086 // of following hard-coded check!
3087 if (TooltipMargin == 5) {
3088 // TODO: make speed an option
3089 int tooltip_anim_speed = 15;
3090 if (tooltip_currtextw < strw) {
3091 tooltip_currtextw += tooltip_anim_speed;
3093 if (tooltip_currtextw > strw) {
3094 tooltip_currtextw = strw;
3096 w = tooltip_currtextw;
3099 h = TooltipBack[0]->Height;
3100 w1 = TooltipBack[1]->Width;
3101 w2 = TooltipBack[2]->Width;
3102 w += TooltipMargin*2;
3103 strw += TooltipMargin*2;
3104 //multiline in case of too much text
3105 if (w>TooltipBack[0]->Width)
3106 strw=w=TooltipBack[0]->Width;
3107 else if (strw>TooltipBack[0]->Width)
3108 strw=TooltipBack[0]->Width;
3111 int strx = tooltip_x - strw / 2;
3112 int y = tooltip_y - h / 2;
3113 // Ensure placement within the screen
3114 if (strx < 0) strx = 0;
3115 else if (strx + strw + w1 + w2 > Width)
3116 strx = Width - strw - w1 - w2;
3117 if (y < 0) y = 0;
3118 else if (y + h > Height)
3119 y = Height - h;
3121 int x = strx + ((strw - w) / 2);
3123 // FIXME: take back[0] from center, not from left end
3124 Region r2 = Region( x, y, w, h );
3125 if (TooltipBack) {
3126 video->BlitSprite( TooltipBack[0], x + TooltipMargin, y, true, &r2 );
3127 video->BlitSprite( TooltipBack[1], x, y, true );
3128 video->BlitSprite( TooltipBack[2], x + w, y, true );
3131 if (TooltipBack) {
3132 r2.x+=TooltipMargin;
3133 strx+=TooltipMargin;
3135 Region textr = Region( strx, y, strw, h );
3136 fnt->Print( r2, textr, (ieByte *) tooltip_text, NULL,
3137 IE_FONT_ALIGN_CENTER | IE_FONT_ALIGN_MIDDLE, true );
3140 //interface for higher level functions, if the window was
3141 //marked for deletion it is not returned
3142 Window* Interface::GetWindow(unsigned short WindowIndex) const
3144 if (WindowIndex < windows.size()) {
3145 Window *win = windows[WindowIndex];
3146 if (win && (win->Visible!=WINDOW_INVALID) ) {
3147 return win;
3150 return NULL;
3153 // this function will determine if wnd is a valid window pointer
3154 // by checking if its WindowID is the same as the reference
3155 bool Interface::IsValidWindow(unsigned short WindowID, Window *wnd) const
3157 size_t WindowIndex = windows.size();
3158 while (WindowIndex--) {
3159 if (windows[WindowIndex] == wnd) {
3160 return wnd->WindowID == WindowID;
3163 return false;
3166 //this function won't delete the window, just mark it for deletion
3167 //it will be deleted in the next DrawWindows cycle
3168 //regardless, the window deleted is inaccessible for gui scripts and
3169 //other high level functions from now
3170 int Interface::DelWindow(unsigned short WindowIndex)
3172 if (WindowIndex >= windows.size()) {
3173 return -1;
3175 Window* win = windows[WindowIndex];
3176 if ((win == NULL) || (win->Visible==WINDOW_INVALID) ) {
3177 printMessage( "Core", "Window deleted again", LIGHT_RED );
3178 return -1;
3180 if (win == ModalWindow) {
3181 ModalWindow = NULL;
3182 RedrawAll(); //marking windows for redraw
3184 evntmgr->DelWindow( win );
3185 win->release();
3186 //re-capturing new (old) modal window if any
3187 size_t tw = topwin.size();
3188 for(size_t i=0;i<tw;i++) {
3189 Window *tmp = windows[topwin[i]];
3190 if (tmp->Visible==WINDOW_FRONT) {
3191 ModalWindow = tmp;
3192 break;
3195 return 0;
3198 void Interface::DelAllWindows()
3200 vars->SetAt("MessageWindow", (ieDword) ~0);
3201 vars->SetAt("OptionsWindow", (ieDword) ~0);
3202 vars->SetAt("PortraitWindow", (ieDword) ~0);
3203 vars->SetAt("ActionsWindow", (ieDword) ~0);
3204 vars->SetAt("TopWindow", (ieDword) ~0);
3205 vars->SetAt("OtherWindow", (ieDword) ~0);
3206 vars->SetAt("FloatWindow", (ieDword) ~0);
3207 for(unsigned int WindowIndex=0; WindowIndex<windows.size();WindowIndex++) {
3208 Window* win = windows[WindowIndex];
3209 delete win;
3211 windows.clear();
3212 topwin.clear();
3213 evntmgr->Clear();
3214 ModalWindow = NULL;
3217 /** Popup the Console */
3218 void Interface::PopupConsole()
3220 ConsolePopped = !ConsolePopped;
3221 RedrawAll();
3222 console->Changed = true;
3225 /** Draws the Console */
3226 void Interface::DrawConsole()
3228 console->Draw( 0, 0 );
3231 /** Get the Sound Manager */
3232 SaveGameIterator* Interface::GetSaveGameIterator() const
3234 return sgiterator;
3236 /** Sends a termination signal to the Video Driver */
3237 bool Interface::Quit(void)
3239 return video->Quit();
3241 /** Returns the variables dictionary */
3242 Variables* Interface::GetDictionary() const
3244 return vars;
3246 /** Returns the token dictionary */
3247 Variables* Interface::GetTokenDictionary() const
3249 return tokens;
3251 /** Get the Music Manager */
3252 MusicMgr* Interface::GetMusicMgr() const
3254 return music;
3256 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3257 int Interface::LoadSymbol(const char* ResRef)
3259 int ind = GetSymbolIndex( ResRef );
3260 if (ind != -1) {
3261 return ind;
3263 DataStream* str = gamedata->GetResource( ResRef, IE_IDS_CLASS_ID );
3264 if (!str) {
3265 return -1;
3267 SymbolMgr* sm = ( SymbolMgr* ) GetInterface( IE_IDS_CLASS_ID );
3268 if (!sm) {
3269 delete str;
3270 return -1;
3272 if (!sm->Open( str, true )) {
3273 FreeInterface( sm );
3274 return -1;
3276 Symbol s;
3277 s.free = false;
3278 strncpy( s.ResRef, ResRef, 8 );
3279 s.sm = sm;
3280 ind = -1;
3281 for (size_t i = 0; i < symbols.size(); i++) {
3282 if (symbols[i].free) {
3283 ind = ( int ) i;
3284 break;
3287 if (ind != -1) {
3288 symbols[ind] = s;
3289 return ind;
3291 symbols.push_back( s );
3292 return ( int ) symbols.size() - 1;
3294 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3295 int Interface::GetSymbolIndex(const char* ResRef) const
3297 for (size_t i = 0; i < symbols.size(); i++) {
3298 if (symbols[i].free)
3299 continue;
3300 if (strnicmp( symbols[i].ResRef, ResRef, 8 ) == 0)
3301 return ( int ) i;
3303 return -1;
3305 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3306 SymbolMgr* Interface::GetSymbol(unsigned int index) const
3308 if (index >= symbols.size()) {
3309 return NULL;
3311 if (symbols[index].free) {
3312 return NULL;
3314 return symbols[index].sm;
3316 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3317 bool Interface::DelSymbol(unsigned int index)
3319 if (index >= symbols.size()) {
3320 return false;
3322 if (symbols[index].free) {
3323 return false;
3325 FreeInterface( symbols[index].sm );
3326 symbols[index].free = true;
3327 return true;
3329 /** Plays a Movie */
3330 int Interface::PlayMovie(const char* ResRef)
3332 MoviePlayer* mp = (MoviePlayer*) gamedata->GetResource( ResRef, &MoviePlayer::ID );
3333 if (!mp) {
3334 FreeInterface( mp );
3335 return -1;
3338 ieDword subtitles = 0;
3339 Font *SubtitleFont = NULL;
3340 Palette *palette = NULL;
3341 ieDword *frames = NULL;
3342 ieDword *strrefs = NULL;
3343 int cnt = 0;
3344 int offset = 0;
3346 //one of these two should exist (they both mean the same thing)
3347 vars->Lookup("Display Movie Subtitles", subtitles);
3348 if (subtitles) {
3349 //HoW flag
3350 cnt=-3;
3351 offset = 3;
3352 } else {
3353 //ToB flag
3354 vars->Lookup("Display Subtitles", subtitles);
3356 AutoTable sttable;
3357 if (subtitles && sttable.load(ResRef)) {
3358 cnt += sttable->GetRowCount();
3359 if (cnt>0) {
3360 frames = (ieDword *) malloc(cnt * sizeof(ieDword) );
3361 strrefs = (ieDword *) malloc(cnt * sizeof(ieDword) );
3362 } else {
3363 cnt = 0;
3365 if (frames && strrefs) {
3366 for (int i=0;i<cnt;i++) {
3367 frames[i] = atoi (sttable->QueryField(i+offset, 0) );
3368 strrefs[i] = atoi (sttable->QueryField(i+offset, 1) );
3371 int r = atoi(sttable->QueryField("red", "frame"));
3372 int g = atoi(sttable->QueryField("green", "frame"));
3373 int b = atoi(sttable->QueryField("blue", "frame"));
3374 SubtitleFont = GetFont (MovieFont); //will change
3375 if (r || g || b) {
3376 if (SubtitleFont) {
3377 Color fore = {(unsigned char) r,(unsigned char) g,(unsigned char) b, 0x00};
3378 Color back = {0x00, 0x00, 0x00, 0x00};
3379 palette = CreatePalette( fore, back );
3384 //shutting down music and ambients before movie
3385 if (music)
3386 music->HardEnd();
3387 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3388 if (ambim) ambim->deactivate();
3389 video->SetMovieFont(SubtitleFont, palette );
3390 mp->CallBackAtFrames(cnt, frames, strrefs);
3391 mp->Play();
3392 FreeInterface( mp );
3393 gamedata->FreePalette( palette );
3394 if (frames)
3395 free(frames);
3396 if (strrefs)
3397 free(strrefs);
3398 //restarting music
3399 if (music)
3400 music->Start();
3401 if (ambim) ambim->activate();
3402 //this will fix redraw all windows as they looked like
3403 //before the movie
3404 RedrawAll();
3406 //Setting the movie name to 1
3407 vars->SetAt( ResRef, 1 );
3408 return 0;
3411 int Interface::Roll(int dice, int size, int add) const
3413 if (dice < 1) {
3414 return add;
3416 if (size < 1) {
3417 return add;
3419 if (dice > 100) {
3420 return add + dice * size / 2;
3422 for (int i = 0; i < dice; i++) {
3423 add += rand() % size + 1;
3425 return add;
3428 static char bmp_suffix[6]="M.BMP";
3429 static char png_suffix[6]="M.PNG";
3431 int Interface::GetPortraits(TextArea* ta, bool smallorlarge)
3433 int count = 0;
3434 char Path[_MAX_PATH];
3436 if (smallorlarge) {
3437 bmp_suffix[0]='S';
3438 png_suffix[0]='S';
3439 } else {
3440 bmp_suffix[0]='M';
3441 png_suffix[0]='M';
3443 PathJoin( Path, GamePath, GamePortraitsPath, NULL );
3444 ResolveFilePath( Path );
3445 DIR* dir = opendir( Path );
3446 if (dir == NULL) {
3447 return -1;
3449 //Lookup the first entry in the Directory
3450 struct dirent* de = readdir( dir );
3451 if (de == NULL) {
3452 closedir( dir );
3453 return -1;
3455 printf( "Looking in %s\n", Path );
3456 do {
3457 if (de->d_name[0] == '.')
3458 continue;
3459 char dtmp[_MAX_PATH];
3460 PathJoin( dtmp, Path, de->d_name, NULL );
3461 struct stat fst;
3462 stat( dtmp, &fst );
3463 if ( S_ISDIR( fst.st_mode ))
3464 continue;
3465 strupr(de->d_name);
3466 char *pos = strstr(de->d_name,bmp_suffix);
3467 if (!pos && IsAvailable(IE_PNG_CLASS_ID) ) {
3468 pos = strstr(de->d_name,png_suffix);
3470 if (!pos) continue;
3471 pos[1]=0;
3472 count++;
3473 ta->AppendText( de->d_name, -1 );
3474 } while (( de = readdir( dir ) ) != NULL);
3475 closedir( dir );
3476 return count;
3479 int Interface::GetCharSounds(TextArea* ta)
3481 bool hasfolders;
3482 int count = 0;
3483 char Path[_MAX_PATH];
3485 PathJoin( Path, GamePath, GameSoundsPath, NULL );
3486 ResolveFilePath( Path );
3487 hasfolders = ( HasFeature( GF_SOUNDFOLDERS ) != 0 );
3488 DIR* dir = opendir( Path );
3489 if (dir == NULL) {
3490 return -1;
3492 //Lookup the first entry in the Directory
3493 struct dirent* de = readdir( dir );
3494 if (de == NULL) {
3495 closedir( dir );
3496 return -1;
3498 printf( "Looking in %s\n", Path );
3499 do {
3500 if (de->d_name[0] == '.')
3501 continue;
3502 char dtmp[_MAX_PATH];
3503 PathJoin( dtmp, Path, de->d_name, NULL );
3504 struct stat fst;
3505 stat( dtmp, &fst );
3506 if (hasfolders == !S_ISDIR( fst.st_mode ))
3507 continue;
3508 if (!hasfolders) {
3509 strupr(de->d_name);
3510 char *pos = strstr(de->d_name,"A.WAV");
3511 if (!pos) continue;
3512 *pos=0;
3514 count++;
3515 ta->AppendText( de->d_name, -1 );
3516 } while (( de = readdir( dir ) ) != NULL);
3517 closedir( dir );
3518 return count;
3521 int Interface::GetCharacters(TextArea* ta)
3523 int count = 0;
3524 char Path[_MAX_PATH];
3526 PathJoin( Path, GamePath, GameCharactersPath, NULL );
3527 ResolveFilePath( Path );
3528 DIR* dir = opendir( Path );
3529 if (dir == NULL) {
3530 return -1;
3532 //Lookup the first entry in the Directory
3533 struct dirent* de = readdir( dir );
3534 if (de == NULL) {
3535 closedir( dir );
3536 return -1;
3538 printf( "Looking in %s\n", Path );
3539 do {
3540 if (de->d_name[0] == '.')
3541 continue;
3542 char dtmp[_MAX_PATH];
3543 PathJoin( dtmp, Path, de->d_name, NULL );
3544 struct stat fst;
3545 stat( dtmp, &fst );
3546 strupr(de->d_name);
3547 char *pos = strstr(de->d_name,".CHR");
3548 if (!pos) continue;
3549 *pos=0;
3550 count++;
3551 ta->AppendText( de->d_name, -1 );
3552 } while (( de = readdir( dir ) ) != NULL);
3553 closedir( dir );
3554 return count;
3557 bool Interface::LoadINI(const char* filename)
3559 FILE* config;
3560 config = fopen( filename, "rb" );
3561 if (config == NULL) {
3562 return false;
3564 char name[65], value[_MAX_PATH + 3];
3565 while (!feof( config )) {
3566 name[0] = 0;
3567 value[0] = 0;
3568 char rem;
3570 if (fread( &rem, 1, 1, config ) != 1)
3571 break;
3573 if (( rem == '#' ) ||
3574 ( rem == '[' ) ||
3575 ( rem == '\r' ) ||
3576 ( rem == '\n' ) ||
3577 ( rem == ';' )) {
3578 if (rem == '\r') {
3579 fgetc( config );
3580 continue;
3581 } else if (rem == '\n')
3582 continue;
3584 //it should always return zero
3585 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
3586 break;
3587 continue;
3589 fseek( config, -1, SEEK_CUR );
3590 //the * element is not counted
3591 if (fscanf( config, "%[^=]=%[^\r\n]%*[\r\n]", name, value )!=2)
3592 continue;
3593 if (( value[0] >= '0' ) && ( value[0] <= '9' )) {
3594 vars->SetAt( name, atoi( value ) );
3597 fclose( config );
3598 return true;
3601 /** Enables/Disables the Cut Scene Mode */
3602 void Interface::SetCutSceneMode(bool active)
3604 GameControl *gc = GetGameControl();
3605 if (gc) {
3606 gc->SetCutSceneMode( active );
3608 if (game) {
3609 if (active) {
3610 game->ControlStatus |= CS_HIDEGUI;
3611 } else {
3612 game->ControlStatus &= ~CS_HIDEGUI;
3614 SetEventFlag(EF_CONTROL);
3616 video->SetMouseEnabled(!active);
3619 bool Interface::InCutSceneMode() const
3621 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE)!=0;
3624 void Interface::QuitGame(int BackToMain)
3626 SetCutSceneMode(false);
3627 if (timer) {
3628 //clear cutscenes
3629 //clear fade/screenshake effects
3630 timer->Init();
3631 timer->SetFadeFromColor(0);
3634 DelAllWindows(); //delete all windows, including GameControl
3636 //shutting down ingame music
3637 //(do it before deleting the game)
3638 if (music) {
3639 music->HardEnd();
3641 // stop any ambients which are still enqueued
3642 if (AudioDriver) {
3643 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3644 if (ambim) ambim->deactivate();
3646 //delete game, worldmap
3647 if (game) {
3648 delete game;
3649 game=NULL;
3651 if (worldmap) {
3652 delete worldmap;
3653 worldmap=NULL;
3655 if (BackToMain) {
3656 strcpy(NextScript, "Start");
3657 QuitFlag |= QF_CHANGESCRIPT;
3659 GSUpdate(true);
3662 void Interface::SetupLoadGame(int index, int ver_override)
3664 LoadGameIndex = index;
3665 VersionOverride = ver_override;
3666 QuitFlag |= QF_LOADGAME;
3669 void Interface::LoadGame(int index, int ver_override)
3671 // This function has rather painful error handling,
3672 // as it should swap all the objects or none at all
3673 // and the loading can fail for various reasons
3675 // Yes, it uses goto. Other ways seemed too awkward for me.
3677 strings->CloseAux();
3678 tokens->RemoveAll(NULL); //clearing the token dictionary
3680 if(calendar) delete calendar;
3681 calendar = new Calendar;
3683 DataStream* gam_str = NULL;
3684 DataStream* sav_str = NULL;
3685 DataStream* wmp_str = NULL;
3687 SaveGameMgr* gam_mgr = NULL;
3688 WorldMapMgr* wmp_mgr = NULL;
3690 Game* new_game = NULL;
3691 WorldMapArray* new_worldmap = NULL;
3693 LoadProgress(15);
3694 if (!KeepCache) DelTree((const char *) CachePath, true);
3695 LoadProgress(20);
3697 if (index == -1) {
3698 //Load the Default Game
3699 gam_str = gamedata->GetResource( GameNameResRef, IE_GAM_CLASS_ID );
3700 sav_str = NULL;
3701 wmp_str = gamedata->GetResource( WorldMapName, IE_WMP_CLASS_ID );
3702 } else {
3703 SaveGame* sg = sgiterator->GetSaveGame( index );
3704 if (!sg)
3705 return;
3706 gam_str = sg->GetGame();
3707 sav_str = sg->GetSave();
3708 wmp_str = sg->GetWmap();
3709 delete sg;
3712 if (!gam_str || !wmp_str)
3713 goto cleanup;
3715 // Load GAM file
3716 gam_mgr = ( SaveGameMgr* ) GetInterface( IE_GAM_CLASS_ID );
3717 if (!gam_mgr)
3718 goto cleanup;
3720 if (!gam_mgr->Open( gam_str, true ))
3721 goto cleanup;
3723 new_game = gam_mgr->LoadGame(new Game(), ver_override);
3724 if (!new_game)
3725 goto cleanup;
3727 FreeInterface( gam_mgr );
3728 gam_mgr = NULL;
3729 gam_str = NULL;
3731 // Load WMP (WorldMap) file
3732 wmp_mgr = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
3733 if (! wmp_mgr)
3734 goto cleanup;
3736 if (!wmp_mgr->Open( wmp_str, true ))
3737 goto cleanup;
3739 new_worldmap = wmp_mgr->GetWorldMapArray( );
3741 FreeInterface( wmp_mgr );
3742 wmp_mgr = NULL;
3743 wmp_str = NULL;
3745 LoadProgress(30);
3746 // Unpack SAV (archive) file to Cache dir
3747 if (sav_str) {
3748 ArchiveImporter * ai = (ArchiveImporter*)GetInterface(IE_BIF_CLASS_ID);
3749 if (ai) {
3750 if (ai->DecompressSaveGame(sav_str) != GEM_OK) {
3751 FreeInterface( ai );
3752 goto cleanup;
3754 FreeInterface( ai );
3756 delete sav_str;
3757 sav_str = NULL;
3760 // Let's assume that now is everything loaded OK and swap the objects
3762 delete game;
3763 delete worldmap;
3765 game = new_game;
3766 worldmap = new_worldmap;
3768 strings->OpenAux();
3769 LoadProgress(100);
3770 return;
3771 cleanup:
3772 // Something went wrong, so try to clean after itself
3774 delete new_game;
3775 delete new_worldmap;
3777 if (gam_mgr) {
3778 FreeInterface( gam_mgr );
3779 gam_str = NULL;
3781 if (wmp_mgr) {
3782 FreeInterface( wmp_mgr );
3783 wmp_str = NULL;
3786 delete gam_str;
3787 delete wmp_str;
3788 delete sav_str;
3791 /* swapping out old resources */
3792 void Interface::UpdateMasterScript()
3794 if (game) {
3795 game->SetScript( GlobalScript, 0 );
3798 WorldMapMgr* wmp_mgr = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
3799 if (! wmp_mgr)
3800 return;
3802 if (worldmap) {
3803 DataStream *wmp_str = gamedata->GetResource( WorldMapName, IE_WMP_CLASS_ID );
3805 if (!wmp_mgr->Open( wmp_str, true )) {
3806 delete wmp_str;
3807 goto cleanup;
3810 delete worldmap;
3811 worldmap = wmp_mgr->GetWorldMapArray();
3814 cleanup:
3815 // Something went wrong, so try to clean after itself
3816 FreeInterface( wmp_mgr );
3819 GameControl *Interface::GetGameControl() const
3821 Window *window = GetWindow( 0 );
3822 // in the beginning, there's no window at all
3823 if (! window)
3824 return NULL;
3826 Control* gc = window->GetControl(0);
3827 if (gc->ControlType!=IE_GUI_GAMECONTROL) {
3828 return NULL;
3830 return (GameControl *) gc;
3833 bool Interface::InitItemTypes()
3835 if (slotmatrix) {
3836 free(slotmatrix);
3838 AutoTable it("itemtype");
3839 ItemTypes = 0;
3840 if (it) {
3841 ItemTypes = it->GetRowCount(); //number of itemtypes
3842 if (ItemTypes<0) {
3843 ItemTypes = 0;
3845 int InvSlotTypes = it->GetColumnCount();
3846 if (InvSlotTypes > 32) { //bit count limit
3847 InvSlotTypes = 32;
3849 //make sure unsigned int is 32 bits
3850 slotmatrix = (ieDword *) malloc(ItemTypes * sizeof(ieDword) );
3851 for (int i=0;i<ItemTypes;i++) {
3852 unsigned int value = 0;
3853 unsigned int k = 1;
3854 for (int j=0;j<InvSlotTypes;j++) {
3855 if (strtol(it->QueryField(i,j),NULL,0) ) {
3856 value |= k;
3858 k <<= 1;
3860 slotmatrix[i] = (ieDword) value;
3864 //slottype describes the inventory structure
3865 Inventory::Init(HasFeature(GF_MAGICBIT));
3866 AutoTable st("slottype");
3867 if (slottypes) {
3868 free(slottypes);
3869 slottypes = NULL;
3871 SlotTypes = 0;
3872 if (st) {
3873 SlotTypes = st->GetRowCount();
3874 //make sure unsigned int is 32 bits
3875 slottypes = (SlotType *) malloc(SlotTypes * sizeof(SlotType) );
3876 memset(slottypes, -1, SlotTypes * sizeof(SlotType) );
3877 for (unsigned int row = 0; row < SlotTypes; row++) {
3878 bool alias;
3879 unsigned int i = (ieDword) strtol(st->GetRowName(row),NULL,0 );
3880 if (i>=SlotTypes) continue;
3881 if (slottypes[i].sloteffects!=0xffffffffu) {
3882 slottypes[row].slot = i;
3883 i=row;
3884 alias = true;
3885 } else {
3886 slottypes[row].slot = i;
3887 alias = false;
3889 slottypes[i].slottype = (ieDword) strtol(st->QueryField(row,0),NULL,0 );
3890 slottypes[i].slotid = (ieDword) strtol(st->QueryField(row,1),NULL,0 );
3891 strnlwrcpy( slottypes[i].slotresref, st->QueryField(row,2), 8 );
3892 slottypes[i].slottip = (ieDword) strtol(st->QueryField(row,3),NULL,0 );
3893 //don't fill sloteffects for aliased slots (pst)
3894 if (alias) {
3895 continue;
3897 slottypes[i].sloteffects = (ieDword) strtol(st->QueryField(row,4),NULL,0 );
3898 //setting special slots
3899 if (slottypes[i].slottype&SLOT_ITEM) {
3900 if (slottypes[i].slottype&SLOT_INVENTORY) {
3901 Inventory::SetInventorySlot(i);
3902 } else {
3903 Inventory::SetQuickSlot(i);
3906 switch (slottypes[i].sloteffects) {
3907 //fist slot, not saved, default weapon
3908 case SLOT_EFFECT_FIST: Inventory::SetFistSlot(i); break;
3909 //magic weapon slot, overrides all weapons
3910 case SLOT_EFFECT_MAGIC: Inventory::SetMagicSlot(i); break;
3911 //weapon slot, Equipping marker is relative to it
3912 case SLOT_EFFECT_MELEE: Inventory::SetWeaponSlot(i); break;
3913 //ranged slot
3914 case SLOT_EFFECT_MISSILE: Inventory::SetRangedSlot(i); break;
3915 //right hand
3916 case SLOT_EFFECT_LEFT: Inventory::SetShieldSlot(i); break;
3917 //head (for averting critical hit)
3918 case SLOT_EFFECT_HEAD: Inventory::SetHeadSlot(i); break;
3919 default:;
3923 return (it && st);
3926 ieDword Interface::FindSlot(unsigned int idx) const
3928 ieDword i;
3930 for (i=0;i<SlotTypes;i++) {
3931 if (idx==slottypes[i].slot) {
3932 break;
3935 return i;
3938 ieDword Interface::QuerySlot(unsigned int idx) const
3940 if (idx>=SlotTypes) {
3941 return 0;
3943 return slottypes[idx].slot;
3946 ieDword Interface::QuerySlotType(unsigned int idx) const
3948 if (idx>=SlotTypes) {
3949 return 0;
3951 return slottypes[idx].slottype;
3954 ieDword Interface::QuerySlotID(unsigned int idx) const
3956 if (idx>=SlotTypes) {
3957 return 0;
3959 return slottypes[idx].slotid;
3962 ieDword Interface::QuerySlottip(unsigned int idx) const
3964 if (idx>=SlotTypes) {
3965 return 0;
3967 return slottypes[idx].slottip;
3970 ieDword Interface::QuerySlotEffects(unsigned int idx) const
3972 if (idx>=SlotTypes) {
3973 return 0;
3975 return slottypes[idx].sloteffects;
3978 const char *Interface::QuerySlotResRef(unsigned int idx) const
3980 if (idx>=SlotTypes) {
3981 return "";
3983 return slottypes[idx].slotresref;
3986 // checks the itemtype vs. slottype, and also checks the usability flags
3987 // vs. Actor's stats (alignment, class, race, kit etc.)
3988 int Interface::CanUseItemType(int slottype, Item *item, Actor *actor, bool feedback) const
3990 //inventory is a special case, we allow any items to enter it
3991 if ( slottype==SLOT_ALL ) {
3992 return SLOT_INVENTORY;
3994 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
3995 //with twohandedness
3996 if ((slottype&SLOT_SHIELD) && (slottype!=SLOT_ANY) ) {
3997 //As long as this is an Item, use the ITEM constant
3998 //switch for IE_INV_ITEM_* if it is a CREItem
3999 if (item->Flags&IE_ITEM_TWO_HANDED) {
4000 //cannot equip twohanded in offhand
4001 if (feedback) DisplayConstantString(STR_NOT_IN_OFFHAND, 0xf0f0f0);
4002 return 0;
4006 if ( (unsigned int) item->ItemType>=(unsigned int) ItemTypes) {
4007 //invalid itemtype
4008 if (feedback) DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4009 return 0;
4012 //if actor is supplied, check its usability fields
4013 if (actor) {
4014 ieStrRef str = actor->Unusable(item);
4015 if (str) {
4016 if (feedback) DisplayConstantString(str, 0xf0f0f0);
4017 return 0;
4021 //if any bit is true, the answer counts as true
4022 int ret = (slotmatrix[item->ItemType]&slottype);
4023 if (slottype == SLOT_INVENTORY || slottype == SLOT_ANY) {
4024 ret = 1;
4026 if (!ret) {
4027 if (feedback) DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4028 return 0;
4031 //this warning comes only when feedback is enabled
4032 if (feedback) {
4033 if (slotmatrix[item->ItemType]&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4034 ret = 0;
4035 if (slottype&SLOT_QUIVER) {
4036 if (item->GetWeaponHeader(true)) ret = 1;
4039 if (slottype&SLOT_WEAPON) {
4040 //melee
4041 if (item->GetWeaponHeader(false)) ret = 1;
4042 //ranged
4043 if (item->GetWeaponHeader(true)) ret = 1;
4046 if (slottype&SLOT_ITEM) {
4047 if (item->GetEquipmentHeaderNumber(0)!=0xffff) ret = 1;
4050 if (!ret) {
4051 DisplayConstantString(STR_UNUSABLEITEM, 0xf0f0f0);
4052 return 0;
4057 return ret;
4060 Label *Interface::GetMessageLabel() const
4062 ieDword WinIndex = (ieDword) -1;
4063 ieDword TAIndex = (ieDword) -1;
4065 vars->Lookup( "OtherWindow", WinIndex );
4066 if (( WinIndex != (ieDword) -1 ) &&
4067 ( vars->Lookup( "MessageLabel", TAIndex ) )) {
4068 Window* win = GetWindow( (unsigned short) WinIndex );
4069 if (win) {
4070 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4071 if (ctrl && ctrl->ControlType==IE_GUI_LABEL)
4072 return (Label *) ctrl;
4075 return NULL;
4078 TextArea *Interface::GetMessageTextArea() const
4080 ieDword WinIndex = (ieDword) -1;
4081 ieDword TAIndex = (ieDword) -1;
4083 vars->Lookup( "MessageWindow", WinIndex );
4084 if (( WinIndex != (ieDword) -1 ) &&
4085 ( vars->Lookup( "MessageTextArea", TAIndex ) )) {
4086 Window* win = GetWindow( (unsigned short) WinIndex );
4087 if (win) {
4088 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4089 if (ctrl && ctrl->ControlType==IE_GUI_TEXTAREA)
4090 return (TextArea *) ctrl;
4093 return NULL;
4096 void Interface::DisplayString(const char* Text, Scriptable *target) const
4098 Label *l = GetMessageLabel();
4099 if (l) {
4100 l->SetText(Text, 0);
4102 TextArea *ta = GetMessageTextArea();
4103 if (ta) {
4104 ta->AppendText( Text, -1 );
4105 } else {
4106 if(target) {
4107 char *tmp = strdup(Text);
4109 target->DisplayHeadText(tmp);
4114 #define PALSIZE 8
4115 static Color ActorColor[PALSIZE];
4116 static const char* DisplayFormatName = "[color=%lX]%s - [/color][p][color=%lX]%s[/color][/p]";
4117 static const char* DisplayFormatAction = "[color=%lX]%s - [/color][p][color=%lX]%s %s[/color][/p]";
4118 static const char* DisplayFormat = "[/color][p][color=%lX]%s[/color][/p]";
4119 static const char* DisplayFormatValue = "[/color][p][color=%lX]%s: %d[/color][/p]";
4120 static const char* DisplayFormatNameString = "[color=%lX]%s - [/color][p][color=%lX]%s: %s[/color][/p]";
4122 ieStrRef Interface::GetStringReference(int stridx) const
4124 return strref_table[stridx];
4128 unsigned int Interface::GetSpeakerColor(const char *&name, Scriptable *&speaker) const
4130 unsigned int speaker_color;
4132 if(!speaker) return 0;
4133 switch (speaker->Type) {
4134 case ST_ACTOR:
4135 name = ((Actor *) speaker)->GetName(-1);
4136 GetPalette( ((Actor *) speaker)->GetStat(IE_MAJOR_COLOR) & 0xFF, PALSIZE, ActorColor );
4137 speaker_color = (ActorColor[4].r<<16) | (ActorColor[4].g<<8) | ActorColor[4].b;
4138 break;
4139 case ST_TRIGGER: case ST_PROXIMITY: case ST_TRAVEL:
4140 name = GetString( ((InfoPoint *) speaker)->DialogName );
4141 speaker_color = 0xc0c0c0;
4142 break;
4143 default:
4144 name = "";
4145 speaker_color = 0x800000;
4146 break;
4148 return speaker_color;
4152 //simply displaying a constant string
4153 void Interface::DisplayConstantString(int stridx, unsigned int color, Scriptable *target) const
4155 if (stridx<0) return;
4156 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4157 int newlen = (int)(strlen( DisplayFormat ) + strlen( text ) + 12);
4158 char* newstr = ( char* ) malloc( newlen );
4159 snprintf( newstr, newlen, DisplayFormat, color, text );
4160 FreeString( text );
4161 DisplayString( newstr, target);
4162 free( newstr );
4165 void Interface::DisplayString(int stridx, unsigned int color, ieDword flags) const
4167 if (stridx<0) return;
4168 char* text = GetString( stridx, flags);
4169 int newlen = (int)(strlen( DisplayFormat) + strlen( text ) + 10);
4170 char* newstr = ( char* ) malloc( newlen );
4171 snprintf( newstr, newlen, DisplayFormat, color, text );
4172 FreeString( text );
4173 DisplayString( newstr );
4174 free( newstr );
4177 // String format is
4178 // blah : whatever
4179 void Interface::DisplayConstantStringValue(int stridx, unsigned int color, ieDword value) const
4181 if (stridx<0) return;
4182 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4183 int newlen = (int)(strlen( DisplayFormat ) + strlen( text ) + 28);
4184 char* newstr = ( char* ) malloc( newlen );
4185 snprintf( newstr, newlen, DisplayFormatValue, color, text, (int) value );
4186 FreeString( text );
4187 DisplayString( newstr );
4188 free( newstr );
4191 // String format is
4192 // <charname> - blah blah : whatever
4193 void Interface::DisplayConstantStringNameString(int stridx, unsigned int color, int stridx2, Scriptable *actor) const
4195 unsigned int actor_color;
4196 const char *name;
4198 if (stridx<0) return;
4199 actor_color = GetSpeakerColor(name, actor);
4200 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4201 char* text2 = GetString( strref_table[stridx2], IE_STR_SOUND );
4202 int newlen = (int)(strlen( DisplayFormat ) + strlen(name) + strlen( text ) + strlen(text2) + 18);
4203 char* newstr = ( char* ) malloc( newlen );
4204 if (strlen(text2)) {
4205 snprintf( newstr, newlen, DisplayFormatNameString, actor_color, name, color, text, text2 );
4206 } else {
4207 snprintf( newstr, newlen, DisplayFormatName, color, name, color, text );
4209 FreeString( text );
4210 FreeString( text2 );
4211 DisplayString( newstr );
4212 free( newstr );
4215 // String format is
4216 // <charname> - blah blah
4217 void Interface::DisplayConstantStringName(int stridx, unsigned int color, Scriptable *speaker) const
4219 unsigned int speaker_color;
4220 const char *name;
4222 if (stridx<0) return;
4223 if(!speaker) return;
4224 speaker_color = GetSpeakerColor(name, speaker);
4225 char* text = GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
4226 int newlen = (int)(strlen( DisplayFormatName ) + strlen( name ) +
4227 + strlen( text ) + 18);
4228 char* newstr = ( char* ) malloc( newlen );
4229 snprintf( newstr, newlen, DisplayFormatName, speaker_color, name, color,
4230 text );
4231 FreeString( text );
4232 DisplayString( newstr );
4233 free( newstr );
4236 void Interface::DisplayConstantStringAction(int stridx, unsigned int color, Scriptable *attacker, Scriptable *target) const
4238 unsigned int attacker_color;
4239 const char *name1;
4240 const char *name2;
4242 if (stridx<0) return;
4244 GetSpeakerColor(name2, target);
4245 attacker_color = GetSpeakerColor(name1, attacker);
4247 char* text = GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
4248 int newlen = (int)(strlen( DisplayFormatAction ) + strlen( name1 ) +
4249 + strlen( name2 ) + strlen( text ) + 18);
4250 char* newstr = ( char* ) malloc( newlen );
4251 snprintf( newstr, newlen, DisplayFormatAction, attacker_color, name1, color,
4252 text, name2);
4253 FreeString( text );
4254 DisplayString( newstr );
4255 free( newstr );
4258 void Interface::DisplayStringName(int stridx, unsigned int color, Scriptable *speaker, ieDword flags) const
4260 unsigned int speaker_color;
4261 const char *name;
4263 if (stridx<0) return;
4264 speaker_color = GetSpeakerColor(name, speaker);
4266 char* text = GetString( stridx, flags);
4267 int newlen = (int)(strlen( DisplayFormatName ) + strlen( name ) +
4268 + strlen( text ) + 10);
4269 char* newstr = ( char* ) malloc( newlen );
4270 snprintf( newstr, newlen, DisplayFormatName, speaker_color, name, color, text );
4271 FreeString( text );
4272 DisplayString( newstr );
4273 free( newstr );
4276 static const char *saved_extensions[]={".are",".sto",0};
4277 static const char *saved_extensions_last[]={".tot",".toh",0};
4279 //returns the priority of the file to be saved
4280 //2 - save
4281 //1 - save last
4282 //0 - don't save
4283 int Interface::SavedExtension(const char *filename)
4285 const char *str=strchr(filename,'.');
4286 if (!str) return 0;
4287 int i=0;
4288 while(saved_extensions[i]) {
4289 if (!stricmp(saved_extensions[i], str) ) return 2;
4290 i++;
4292 i=0;
4293 while(saved_extensions_last[i]) {
4294 if (!stricmp(saved_extensions_last[i], str) ) return 1;
4295 i++;
4297 return 0;
4300 static const char *protected_extensions[]={".exe",".dll",".so",0};
4302 //returns true if file should be saved
4303 bool Interface::ProtectedExtension(const char *filename)
4305 const char *str=strchr(filename,'.');
4306 if (!str) return false;
4307 int i=0;
4308 while(protected_extensions[i]) {
4309 if (!stricmp(protected_extensions[i], str) ) return true;
4310 i++;
4312 return false;
4315 void Interface::RemoveFromCache(const ieResRef resref, SClass_ID ClassID)
4317 char filename[_MAX_PATH];
4319 snprintf(filename, _MAX_PATH, "%s%.8s%s", CachePath, resref, TypeExt( ClassID ) );
4320 unlink ( filename);
4323 //this function checks if the path is eligible as a cache
4324 //if it contains a directory, or suspicious file extensions
4325 //we bail out, because the cache will be purged regularly.
4326 bool Interface::StupidityDetector(const char* Pt)
4328 char Path[_MAX_PATH];
4329 strcpy( Path, Pt );
4330 DIR* dir = opendir( Path );
4331 if (dir == NULL) {
4332 printf("\n**cannot open**\n");
4333 return true; //no directory?
4335 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
4336 if (de == NULL) {
4337 closedir( dir );
4338 printf("\n**cannot read**\n");
4339 return true; //cannot read it?
4341 do {
4342 char dtmp[_MAX_PATH];
4343 struct stat fst;
4344 snprintf( dtmp, _MAX_PATH, "%s%s%s", Path, SPathDelimiter, de->d_name );
4345 stat( dtmp, &fst );
4346 if (S_ISDIR( fst.st_mode )) {
4347 if (de->d_name[0] == '.')
4348 continue;
4349 closedir( dir );
4350 printf("\n**contains another dir**\n");
4351 return true; //a directory in there???
4353 if (ProtectedExtension(de->d_name) ) {
4354 closedir( dir );
4355 printf("\n**contains alien files**\n");
4356 return true; //an executable file in there???
4358 } while (( de = readdir( dir ) ) != NULL);
4359 closedir( dir );
4360 //ok, we got a good conscience
4361 return false;
4364 void Interface::DelTree(const char* Pt, bool onlysave)
4366 char Path[_MAX_PATH];
4368 if (!Pt[0]) return; //Don't delete the root filesystem :)
4369 strcpy( Path, Pt );
4370 DIR* dir = opendir( Path );
4371 if (dir == NULL) {
4372 return;
4374 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
4375 if (de == NULL) {
4376 closedir( dir );
4377 return;
4379 do {
4380 char dtmp[_MAX_PATH];
4381 struct stat fst;
4382 snprintf( dtmp, _MAX_PATH, "%s%s%s", Path, SPathDelimiter, de->d_name );
4383 stat( dtmp, &fst );
4384 if (S_ISDIR( fst.st_mode ))
4385 continue;
4386 if (de->d_name[0] == '.')
4387 continue;
4388 if (!onlysave || SavedExtension(de->d_name) ) {
4389 unlink( dtmp );
4391 } while (( de = readdir( dir ) ) != NULL);
4392 closedir( dir );
4395 void Interface::LoadProgress(int percent)
4397 vars->SetAt("Progress", percent);
4398 RedrawControls("Progress", percent);
4399 RedrawAll();
4400 DrawWindows();
4401 video->SwapBuffers();
4404 void Interface::ReleaseDraggedItem()
4406 DraggedItem=NULL; //shouldn't free this
4407 video->SetDragCursor (NULL);
4410 void Interface::DragItem(CREItem *item, const ieResRef Picture)
4412 //We should drop the dragged item and pick this up,
4413 //we shouldn't have a valid DraggedItem at this point.
4414 //Anyway, if there is still a dragged item, it will be destroyed.
4415 if (DraggedItem) {
4416 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW);
4417 delete DraggedItem;
4419 DraggedItem = item;
4420 if (video) {
4421 Sprite2D* DraggedCursor = NULL;
4422 if (item) {
4423 DraggedCursor = gamedata->GetBAMSprite( Picture, 0, 0 );
4425 video->SetDragCursor (DraggedCursor);
4429 void Interface::SetDraggedPortrait(int dp, int idx)
4431 if (idx<0) idx=14;
4432 DraggedPortrait = dp;
4433 if (dp) {
4434 //hmm this might work?
4435 Cursors[idx]->RefCount++;
4436 video->SetDragCursor(Cursors[idx]);
4437 } else {
4438 video->SetDragCursor(NULL);
4442 bool Interface::ReadItemTable(const ieResRef TableName, const char * Prefix)
4444 ieResRef ItemName;
4445 int i,j;
4447 AutoTable tab(TableName);
4448 if (!tab) {
4449 return false;
4451 i=tab->GetRowCount();
4452 for(j=0;j<i;j++) {
4453 if (Prefix) {
4454 snprintf(ItemName,sizeof(ItemName),"%s%02d",Prefix, j+1);
4455 } else {
4456 strnlwrcpy(ItemName,tab->GetRowName(j), 8);
4458 //Variable elements are free'd, so we have to use malloc
4459 //well, not anymore, we can use ReleaseFunction
4460 int l=tab->GetColumnCount(j);
4461 if (l<1) continue;
4462 int cl = atoi(tab->GetColumnName(0));
4463 ItemList *itemlist = new ItemList(l, cl);
4464 for(int k=0;k<l;k++) {
4465 strnlwrcpy(itemlist->ResRefs[k],tab->QueryField(j,k), 8);
4467 RtRows->SetAt(ItemName, (void*)itemlist);
4469 return true;
4472 bool Interface::ReadRandomItems()
4474 ieResRef RtResRef;
4475 int i;
4477 ieDword difflev=0; //rt norm or rt fury
4478 vars->Lookup("Nightmare Mode", difflev);
4479 if (RtRows) {
4480 RtRows->RemoveAll(ReleaseItemList);
4482 else {
4483 RtRows=new Variables(10, 17); //block size, hash table size
4484 if (!RtRows) {
4485 return false;
4487 RtRows->SetType( GEM_VARIABLES_POINTER );
4489 AutoTable tab("randitem");
4490 if (!tab) {
4491 return false;
4493 if (difflev>=tab->GetColumnCount()) {
4494 difflev = tab->GetColumnCount()-1;
4497 //the gold item
4498 strnlwrcpy( GoldResRef, tab->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4499 if ( GoldResRef[0]=='*' ) {
4500 return false;
4502 strnlwrcpy( RtResRef, tab->QueryField( 1, difflev ), 8);
4503 i=atoi( RtResRef );
4504 if (i<1) {
4505 ReadItemTable( RtResRef, 0 ); //reading the table itself
4506 return true;
4508 if (i>5) {
4509 i=5;
4511 while(i--) {
4512 strnlwrcpy( RtResRef, tab->QueryField(2+i,difflev), 8);
4513 ReadItemTable( RtResRef,tab->GetRowName(2+i) );
4515 return true;
4518 CREItem *Interface::ReadItem(DataStream *str)
4520 CREItem *itm = new CREItem();
4522 str->ReadResRef( itm->ItemResRef );
4523 str->ReadWord( &itm->Expired );
4524 str->ReadWord( &itm->Usages[0] );
4525 str->ReadWord( &itm->Usages[1] );
4526 str->ReadWord( &itm->Usages[2] );
4527 str->ReadDword( &itm->Flags );
4528 if (ResolveRandomItem(itm) ) {
4529 return itm;
4531 delete itm;
4532 return NULL;
4535 #define MAX_LOOP 10
4537 //This function generates random items based on the randitem.2da file
4538 //there could be a loop, but we don't want to freeze, so there is a limit
4539 bool Interface::ResolveRandomItem(CREItem *itm)
4541 if (!RtRows) return true;
4542 for(int loop=0;loop<MAX_LOOP;loop++) {
4543 int i,j,k;
4544 char *endptr;
4545 ieResRef NewItem;
4547 void* lookup;
4548 if ( !RtRows->Lookup( itm->ItemResRef, lookup ) ) {
4549 return true;
4551 ItemList *itemlist = (ItemList*)lookup;
4552 if (itemlist->WeightOdds) {
4553 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4554 i=Roll(2,(itemlist->Count+1)/2,-2);
4555 } else {
4556 i=Roll(1,itemlist->Count,-1);
4558 strnlwrcpy( NewItem, itemlist->ResRefs[i], 8);
4559 char *p=(char *) strchr(NewItem,'*');
4560 if (p) {
4561 *p=0; //doing this so endptr is ok
4562 k=strtol(p+1,NULL,10);
4563 } else {
4564 k=1;
4566 j=strtol(NewItem,&endptr,10);
4567 if (j<1) {
4568 j=1;
4570 if (*endptr) {
4571 strnlwrcpy(itm->ItemResRef, NewItem, 8);
4572 } else {
4573 strnlwrcpy(itm->ItemResRef, GoldResRef, 8);
4575 if ( !memcmp( itm->ItemResRef,"no_drop",8 ) ) {
4576 itm->ItemResRef[0]=0;
4578 if (!itm->ItemResRef[0]) {
4579 return false;
4581 itm->Usages[0]=(ieWord) Roll(j,k,0);
4583 printMessage("Interface"," ",LIGHT_RED);
4584 printf("Loop detected while generating random item:%s\n",itm->ItemResRef);
4585 return false;
4588 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4589 //these functions are needed because Win32 doesn't allow freeing memory from
4590 //another dll. So we allocate all commonly used memories from core
4591 ITMExtHeader *Interface::GetITMExt(int count)
4593 return new ITMExtHeader[count];
4596 SPLExtHeader *Interface::GetSPLExt(int count)
4598 return new SPLExtHeader[count];
4601 Effect *Interface::GetEffect(ieDword opcode)
4603 if (opcode==0xffffffff) {
4604 return NULL;
4606 Effect *fx = new Effect();
4607 if (!fx) {
4608 return NULL;
4610 memset(fx,0,sizeof(Effect));
4611 fx->Opcode=opcode;
4612 return fx;
4615 Effect *Interface::GetFeatures(int count)
4617 return new Effect[count];
4621 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4623 delete [] p;
4624 delete [] e;
4627 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4629 delete [] p;
4630 delete [] e;
4634 WorldMapArray *Interface::NewWorldMapArray(int count)
4636 return new WorldMapArray(count);
4639 Container *Interface::GetCurrentContainer()
4641 return CurrentContainer;
4644 int Interface::CloseCurrentContainer()
4646 UseContainer = false;
4647 if ( !CurrentContainer) {
4648 return -1;
4650 //remove empty ground piles on closeup
4651 CurrentContainer->GetCurrentArea()->TMap->CleanupContainer(CurrentContainer);
4652 CurrentContainer = NULL;
4653 return 0;
4656 void Interface::SetCurrentContainer(Actor *actor, Container *arg, bool flag)
4658 //abort action if the first selected PC isn't the original actor
4659 if (actor!=GetFirstSelectedPC(false)) {
4660 CurrentContainer = NULL;
4661 return;
4663 CurrentContainer = arg;
4664 UseContainer = flag;
4667 Store *Interface::GetCurrentStore()
4669 return CurrentStore;
4672 int Interface::CloseCurrentStore()
4674 if ( !CurrentStore ) {
4675 return -1;
4677 StoreMgr* sm = ( StoreMgr* ) GetInterface( IE_STO_CLASS_ID );
4678 if (sm == NULL) {
4679 return -1;
4681 int size = sm->GetStoredFileSize (CurrentStore);
4682 if (size > 0) {
4683 //created streams are always autofree (close file on destruct)
4684 //this one will be destructed when we return from here
4685 FileStream str;
4687 str.Create( CurrentStore->Name, IE_STO_CLASS_ID );
4688 int ret = sm->PutStore (&str, CurrentStore);
4689 if (ret <0) {
4690 printMessage("Core"," ", YELLOW);
4691 printf("Store removed: %s\n", CurrentStore->Name);
4692 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4694 } else {
4695 printMessage("Core"," ", YELLOW);
4696 printf("Store removed: %s\n", CurrentStore->Name);
4697 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4699 //make sure the stream isn't connected to sm, or it will be double freed
4700 FreeInterface( sm );
4701 delete CurrentStore;
4702 CurrentStore = NULL;
4703 return 0;
4706 Store *Interface::SetCurrentStore(const ieResRef resname, const ieVariable owner)
4708 if ( CurrentStore ) {
4709 if ( !strnicmp(CurrentStore->Name, resname, 8) ) {
4710 return CurrentStore;
4713 //not simply delete the old store, but save it
4714 CloseCurrentStore();
4717 DataStream* str = gamedata->GetResource( resname, IE_STO_CLASS_ID );
4718 StoreMgr* sm = ( StoreMgr* ) GetInterface( IE_STO_CLASS_ID );
4719 if (sm == NULL) {
4720 delete ( str );
4721 return NULL;
4723 if (!sm->Open( str, true )) {
4724 FreeInterface( sm );
4725 return NULL;
4728 // FIXME - should use some already allocated in core
4729 // not really, only one store is open at a time, then it is
4730 // unloaded, we don't really have to cache it, it will be saved in
4731 // Cache anyway!
4732 CurrentStore = sm->GetStore( new Store() );
4733 if (CurrentStore == NULL) {
4734 FreeInterface( sm );
4735 return NULL;
4737 FreeInterface( sm );
4738 strnlwrcpy(CurrentStore->Name, resname, 8);
4739 if (owner) {
4740 CurrentStore->SetOwner(owner);
4742 return CurrentStore;
4745 void Interface::SetMouseScrollSpeed(int speed) {
4746 mousescrollspd = (speed+1)*2;
4749 int Interface::GetMouseScrollSpeed() {
4750 return mousescrollspd;
4753 ieStrRef Interface::GetRumour(const ieResRef dlgref)
4755 DialogMgr* dm = ( DialogMgr* ) GetInterface( IE_DLG_CLASS_ID );
4756 dm->Open( gamedata->GetResource( dlgref, IE_DLG_CLASS_ID ), true );
4757 Dialog *dlg = dm->GetDialog();
4758 FreeInterface( dm );
4760 if (!dlg) {
4761 printMessage("Interface"," ", LIGHT_RED);
4762 printf( "Cannot load dialog: %s\n", dlgref );
4763 return (ieStrRef) -1;
4765 Scriptable *pc=game->GetPC( game->GetSelectedPCSingle(), false );
4767 ieStrRef ret = (ieStrRef) -1;
4768 int i = dlg->FindRandomState( pc );
4769 if (i>=0 ) {
4770 ret = dlg->GetState( i )->StrRef;
4772 delete dlg;
4773 return ret;
4776 void Interface::DoTheStoreHack(Store *s)
4778 size_t size = s->PurchasedCategoriesCount * sizeof( ieDword );
4779 s->purchased_categories=(ieDword *) malloc(size);
4781 size = s->CuresCount * sizeof( STOCure );
4782 s->cures=(STOCure *) malloc(size);
4784 size = s->DrinksCount * sizeof( STODrink );
4785 s->drinks=(STODrink *) malloc(size);
4787 for(size=0;size<s->ItemsCount;size++)
4788 s->items.push_back( new STOItem() );
4791 //plays stock sound listed in defsound.2da
4792 void Interface::PlaySound(int index)
4794 if (index<=DSCount) {
4795 AudioDriver->Play(DefSound[index]);
4799 Actor *Interface::GetFirstSelectedPC(bool forced)
4801 int partySize = game->GetPartySize( false );
4802 if (!partySize) return NULL;
4803 for (int i = 0; i < partySize; i++) {
4804 Actor* actor = game->GetPC( i,false );
4805 if (actor->IsSelected()) {
4806 return actor;
4810 if (forced) {
4811 return game->GetPC(0,false);
4813 return NULL;
4816 //this is used only for the console
4817 Sprite2D *Interface::GetCursorSprite()
4819 Sprite2D *spr = gamedata->GetBAMSprite(CursorBam, 0, 0);
4820 if (spr)
4822 if(HasFeature(GF_OVERRIDE_CURSORPOS))
4824 spr->XPos=1;
4825 spr->YPos=spr->Height-1;
4828 return spr;
4831 Sprite2D *Interface::GetScrollCursorSprite(int frameNum, int spriteNum)
4833 return gamedata->GetBAMSprite(ScrollCursorBam, frameNum, spriteNum);
4836 /* we should return -1 if it isn't gold, otherwise return the gold value */
4837 int Interface::CanMoveItem(const CREItem *item) const
4839 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4840 if (item->Flags & IE_INV_ITEM_UNDROPPABLE)
4841 return 0;
4842 //not gold, we allow only one single coin ResRef, this is good
4843 //for all of the original games
4844 if (strnicmp(item->ItemResRef, GoldResRef, 8 ) )
4845 return -1;
4846 //gold, returns the gold value (stack size)
4847 return item->Usages[0];
4850 // dealing with applying effects
4851 void Interface::ApplySpell(const ieResRef resname, Actor *actor, Scriptable *caster, int level)
4853 Spell *spell = gamedata->GetSpell(resname);
4854 if (!spell) {
4855 return;
4858 level = spell->GetHeaderIndexFromLevel(level);
4859 EffectQueue *fxqueue = spell->GetEffectBlock(caster, actor->Pos, level);
4861 //check effect immunities
4862 int res = fxqueue->CheckImmunity ( actor );
4863 if (res) {
4864 if (res == -1) {
4865 //bounced back at a nonliving caster
4866 if (caster->Type!=ST_ACTOR) {
4867 delete fxqueue;
4868 return;
4870 actor = (Actor *) caster;
4872 fxqueue->SetOwner( caster );
4873 fxqueue->AddAllEffects(actor, actor->Pos);
4875 delete fxqueue;
4878 void Interface::ApplySpellPoint(const ieResRef resname, Map* area, Point &pos, Scriptable *caster, int level)
4880 Spell *spell = gamedata->GetSpell(resname);
4881 if (!spell) {
4882 return;
4884 level = spell->GetHeaderIndexFromLevel(level);
4885 Projectile *pro = spell->GetProjectile(caster, level, pos);
4886 pro->SetCaster(caster->GetGlobalID());
4887 area->AddProjectile(pro, caster->Pos, pos);
4890 //-1 means the effect was reflected back to the caster
4891 //0 means the effect was resisted and should be removed
4892 //1 means the effect was applied
4893 int Interface::ApplyEffect(Effect *effect, Actor *actor, Scriptable *caster)
4895 if (!effect) {
4896 return 0;
4899 EffectQueue *fxqueue = new EffectQueue();
4900 //AddEffect now copies the fx data, please delete your effect reference
4901 //if you created it. (Don't delete cached references)
4902 fxqueue->AddEffect( effect );
4904 int res = fxqueue->CheckImmunity ( actor );
4905 if (res) {
4906 if (res == -1 ) {
4907 //bounced back at a nonliving caster
4908 if (caster->Type!=ST_ACTOR) {
4909 delete fxqueue;
4910 return 0;
4912 actor = (Actor *) caster;
4914 fxqueue->SetOwner( caster );
4915 Point p;
4917 p.empty(); //the effect should have all its coordinates already set
4918 if (fxqueue->AddAllEffects( actor, p )==FX_NOT_APPLIED) {
4919 res=0;
4922 delete fxqueue;
4923 return res;
4926 Effect *Interface::GetEffect(const ieResRef resname, int level, Point &p)
4928 //Don't free this reference, it is cached!
4929 Effect *effect = gamedata->GetEffect(resname);
4930 if (!effect) {
4931 return NULL;
4933 if (!level) {
4934 level = 1;
4936 effect->Power = level;
4937 effect->PosX=p.x;
4938 effect->PosY=p.y;
4939 return effect;
4942 // dealing with saved games
4943 int Interface::SwapoutArea(Map *map)
4945 MapMgr* mm = ( MapMgr* ) GetInterface( IE_ARE_CLASS_ID );
4946 if (mm == NULL) {
4947 return -1;
4949 int size = mm->GetStoredFileSize (map);
4950 if (size > 0) {
4951 //created streams are always autofree (close file on destruct)
4952 //this one will be destructed when we return from here
4953 FileStream str;
4955 str.Create( map->GetScriptName(), IE_ARE_CLASS_ID );
4956 int ret = mm->PutArea (&str, map);
4957 if (ret <0) {
4958 printMessage("Core"," ", YELLOW);
4959 printf("Area removed: %s\n", map->GetScriptName());
4960 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4962 } else {
4963 printMessage("Core"," ", YELLOW);
4964 printf("Area removed: %s\n", map->GetScriptName());
4965 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4967 //make sure the stream isn't connected to sm, or it will be double freed
4968 FreeInterface( mm );
4969 return 0;
4972 int Interface::WriteCharacter(const char *name, Actor *actor)
4974 char Path[_MAX_PATH];
4976 PathJoin( Path, GamePath, GameCharactersPath, NULL );
4977 if (!actor) {
4978 return -1;
4980 ActorMgr* gm = ( ActorMgr* ) GetInterface( IE_CRE_CLASS_ID );
4981 if (gm == NULL) {
4982 return -1;
4984 FileStream str;
4986 str.Create( Path, name, IE_CHR_CLASS_ID );
4988 //this is not needed, because the chr header writer automatically
4989 //calls it
4990 //int size = gm->GetStoredFileSize (actor);
4991 int ret = gm->PutActor(&str, actor, true);
4992 if (ret <0) {
4993 printMessage("Core"," ", YELLOW);
4994 printf("Character cannot be saved: %s\n", name);
4996 FreeInterface(gm);
4997 return 0;
5000 int Interface::WriteGame(const char *folder)
5002 SaveGameMgr* gm = ( SaveGameMgr* ) GetInterface( IE_GAM_CLASS_ID );
5003 if (gm == NULL) {
5004 return -1;
5007 int size = gm->GetStoredFileSize (game);
5008 if (size > 0) {
5009 //created streams are always autofree (close file on destruct)
5010 //this one will be destructed when we return from here
5011 FileStream str;
5013 str.Create( folder, GameNameResRef, IE_GAM_CLASS_ID );
5014 int ret = gm->PutGame (&str, game);
5015 if (ret <0) {
5016 printMessage("Core"," ", YELLOW);
5017 printf("Game cannot be saved: %s\n", GameNameResRef);
5019 } else {
5020 printMessage("Core"," ", YELLOW);
5021 printf("Internal error, game cannot be saved: %s\n", GameNameResRef);
5023 //make sure the stream isn't connected to sm, or it will be double freed
5024 FreeInterface( gm );
5025 return 0;
5028 int Interface::WriteWorldMap(const char *folder)
5030 WorldMapMgr* wmm = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
5031 if (wmm == NULL) {
5032 return -1;
5035 int size = wmm->GetStoredFileSize (worldmap);
5036 if (size > 0) {
5037 //created streams are always autofree (close file on destruct)
5038 //this one will be destructed when we return from here
5039 FileStream str;
5041 str.Create( folder, WorldMapName, IE_WMP_CLASS_ID );
5042 int ret = wmm->PutWorldMap (&str, worldmap);
5043 if (ret <0) {
5044 printMessage("Core"," ", YELLOW);
5045 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName);
5047 } else {
5048 printMessage("Core"," ", YELLOW);
5049 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName);
5051 //make sure the stream isn't connected to sm, or it will be double freed
5052 FreeInterface( wmm );
5053 return 0;
5056 int Interface::CompressSave(const char *folder)
5058 FileStream str;
5060 str.Create( folder, GameNameResRef, IE_SAV_CLASS_ID );
5061 DIR* dir = opendir( CachePath );
5062 if (dir == NULL) {
5063 return -1;
5065 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
5066 if (de == NULL) {
5067 closedir( dir );
5068 return -1;
5070 //BIF and SAV are the same
5071 ArchiveImporter * ai = (ArchiveImporter*)GetInterface(IE_BIF_CLASS_ID);
5072 ai->CreateArchive( &str);
5074 //.tot and .toh should be saved last, because they are updated when an .are is saved
5075 int priority=2;
5076 while(priority) {
5077 do {
5078 char dtmp[_MAX_PATH];
5079 struct stat fst;
5080 snprintf( dtmp, _MAX_PATH, "%s%s", CachePath, de->d_name );
5081 stat( dtmp, &fst );
5082 if (S_ISDIR( fst.st_mode ))
5083 continue;
5084 if (de->d_name[0] == '.')
5085 continue;
5086 if (SavedExtension(de->d_name)==priority) {
5087 FileStream fs;
5088 fs.Open(dtmp, true);
5089 ai->AddToSaveGame(&str, &fs);
5091 } while (( de = readdir( dir ) ) != NULL);
5092 closedir( dir );
5093 //reopen list for the second round
5094 priority--;
5095 if (priority>0) {
5096 dir = opendir( CachePath );
5097 de = readdir( dir );
5100 FreeInterface( ai );
5101 return 0;
5104 int Interface::GetMaximumAbility() const { return MaximumAbility; }
5106 int Interface::GetStrengthBonus(int column, int value, int ex) const
5108 //to hit, damage, open doors, weight allowance
5109 if (column<0 || column>3)
5110 return -9999;
5112 if (value<0)
5113 value = 0;
5114 else if (value>25)
5115 value = 25;
5117 if (ex<0)
5118 ex=0;
5119 else if (ex>100)
5120 ex=100;
5122 return strmod[column*(MaximumAbility+1)+value]+strmodex[column*101+ex];
5125 //only the first 3 columns are supported
5126 int Interface::GetIntelligenceBonus(int column, int value) const
5128 //learn spell, max spell level, max spell number on level
5129 if (column<0 || column>2)
5130 return -9999;
5132 return intmod[column*(MaximumAbility+1)+value];
5135 int Interface::GetDexterityBonus(int column, int value) const
5137 //reaction, missile, ac
5138 if (column<0 || column>2)
5139 return -9999;
5141 //no dexmod in iwd2???
5142 if (HasFeature(GF_3ED_RULES)) return 0;
5144 return dexmod[column*(MaximumAbility+1)+value];
5147 int Interface::GetConstitutionBonus(int column, int value) const
5149 //normal, warrior, minimum, regen hp, regen fatigue
5150 if (column<0 || column>4)
5151 return -9999;
5153 return conmod[column*(MaximumAbility+1)+value];
5156 int Interface::GetCharismaBonus(int column, int value) const
5158 //?reaction
5159 if (column<0 || column>0)
5160 return -9999;
5162 return chrmod[column*(MaximumAbility+1)+value];
5165 int Interface::GetLoreBonus(int column, int value) const
5167 if (column<0 || column>0)
5168 return -9999;
5170 //no lorebon in iwd2???
5171 if (HasFeature(GF_3ED_RULES)) return 0;
5173 return lorebon[value];
5176 // -3, -2 if request is illegal or in cutscene
5177 // -1 if pause is already active
5178 // 0 if pause was not allowed
5179 // 1 if autopause happened
5180 int Interface::Autopause(ieDword flag)
5182 GameControl *gc = GetGameControl();
5183 if (!gc) {
5184 return -3;
5186 if (InCutSceneMode()) {
5187 return -2;
5189 if (gc->GetDialogueFlags()&DF_FREEZE_SCRIPTS) {
5190 return -1;
5192 ieDword autopause_flags = 0;
5194 vars->Lookup("Auto Pause State", autopause_flags);
5195 if (autopause_flags & (1<<flag)) {
5196 DisplayConstantString(STR_AP_UNUSABLE+flag, 0xff0000);
5197 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5198 return 1;
5200 return 0;
5203 void Interface::RegisterOpcodes(int count, const EffectRef *opcodes)
5205 EffectQueue_RegisterOpcodes(count, opcodes);
5208 void Interface::SetInfoTextColor(Color &color)
5210 if (InfoTextPalette) {
5211 gamedata->FreePalette(InfoTextPalette);
5213 InfoTextPalette = CreatePalette(color, black);
5216 //todo row?
5217 void Interface::GetResRefFrom2DA(const ieResRef resref, ieResRef resource1, ieResRef resource2, ieResRef resource3)
5219 if (!resource1) {
5220 return;
5222 resource1[0]=0;
5223 if (resource2) {
5224 resource2[0]=0;
5226 if (resource3) {
5227 resource3[0]=0;
5229 AutoTable tab(resref);
5230 if (tab) {
5231 unsigned int cols = tab->GetColumnCount();
5232 unsigned int row = (unsigned int) Roll(1,tab->GetRowCount(),-1);
5233 strnuprcpy(resource1, tab->QueryField(row,0), 8);
5234 if (resource2 && cols>1)
5235 strnuprcpy(resource2, tab->QueryField(row,1), 8);
5236 if (resource3 && cols>2)
5237 strnuprcpy(resource3, tab->QueryField(row,2), 8);
5241 ieDword *Interface::GetListFrom2DA(const ieResRef resref)
5243 ieDword *ret;
5245 AutoTable tab(resref);
5246 if (tab) {
5247 ieDword cnt = tab->GetRowCount();
5248 ret = (ieDword *) malloc((1+cnt)*sizeof(ieDword));
5249 ret[0]=cnt;
5250 while(cnt) {
5251 ret[cnt]=strtol(tab->QueryField(cnt-1, 0),NULL, 0);
5252 cnt--;
5254 return ret;
5256 ret = (ieDword *) malloc(sizeof(ieDword));
5257 ret[0]=0;
5258 return ret;
5261 //returns a numeric value associated with a stat name (symbol) from stats.ids
5262 ieDword Interface::TranslateStat(const char *stat_name)
5264 long tmp;
5266 if (valid_number(stat_name, tmp)) {
5267 return (ieDword) tmp;
5270 int symbol = LoadSymbol( "stats" );
5271 SymbolMgr *sym = GetSymbol( symbol );
5272 ieDword stat = (ieDword) sym->GetValue( stat_name );
5273 if (stat==(ieDword) ~0) {
5274 printMessage("Core"," ",YELLOW);
5275 printf("Cannot translate symbol: %s\n", stat_name);
5277 return stat;
5280 void Interface::WaitForDisc(int disc_number, const char* path)
5282 GetDictionary()->SetAt( "WaitForDisc", (ieDword) disc_number );
5284 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5285 do {
5286 core->DrawWindows();
5287 if (dir_exists (path)) {
5288 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5289 break;
5292 } while (video->SwapBuffers() == GEM_OK);
5295 // remove the extraneus EOL newline and carriage return
5296 void Interface::StripLine(char * string, size_t size) {
5297 if (size >= 2 && string[size-2] == '\n') {
5298 string[size-2] = '\0';
5300 if (size >= 3 && string[size-3] == '\r') {
5301 string[size-3] = '\0'; // remove the carriage return too
5305 void Interface::SetNextScript(const char *script)
5307 strncpy( NextScript, script, sizeof(NextScript) );
5308 QuitFlag |= QF_CHANGESCRIPT;