GameScript: Move initialization out of constructor.
[gemrb.git] / gemrb / core / Interface.cpp
blobb78ce88db1918f5e6f2ed4e44e5fee3da496457b
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"
80 #include "PluginMgr.h"
81 #include "ImageMgr.h"
83 GEM_EXPORT Interface* core;
85 #ifdef WIN32
86 GEM_EXPORT HANDLE hConsole;
87 #endif
89 //use DialogF.tlk if the protagonist is female, that's why we leave space
90 static const char dialogtlk[] = "dialog.tlk\0";
92 static int strref_table[STRREF_COUNT];
94 static int MaximumAbility = 25;
95 static ieWordSigned *strmod = NULL;
96 static ieWordSigned *strmodex = NULL;
97 static ieWordSigned *intmod = NULL;
98 static ieWordSigned *dexmod = NULL;
99 static ieWordSigned *conmod = NULL;
100 static ieWordSigned *chrmod = NULL;
101 static ieWordSigned *lorebon = NULL;
102 static ieVariable IWD2DeathVarFormat = "_DEAD%s";
103 static ieVariable DeathVarFormat = "SPRITE_IS_DEAD%s";
105 Interface::Interface(int iargc, char* iargv[])
107 argc = iargc;
108 argv = iargv;
109 #ifdef WIN32
110 hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
111 #endif
112 textcolor( LIGHT_WHITE );
113 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB );
115 // default to the correct endianswitch
116 ieWord endiantest = 1;
117 if (((char *)&endiantest)[1] == 1) {
118 // big-endian
119 DataStream::SetEndianSwitch(true);
122 unsigned int i;
123 for(i=0;i<256;i++) {
124 pl_uppercase[i]=(ieByte) toupper(i);
125 pl_lowercase[i]=(ieByte) tolower(i);
128 projserv = NULL;
129 video = NULL;
130 AudioDriver = NULL;
131 strings = NULL;
132 guiscript = NULL;
133 windowmgr = NULL;
134 vars = NULL;
135 tokens = NULL;
136 RtRows = NULL;
137 music = NULL;
138 sgiterator = NULL;
139 INIparty = NULL;
140 INIbeasts = NULL;
141 INIquests = NULL;
142 INIresdata = NULL;
143 game = NULL;
144 worldmap = NULL;
145 CurrentStore = NULL;
146 CurrentContainer = NULL;
147 UseContainer = false;
148 InfoTextPalette = NULL;
149 timer = NULL;
150 evntmgr = NULL;
151 console = NULL;
152 slottypes = NULL;
153 slotmatrix = NULL;
155 ModalWindow = NULL;
156 tooltip_x = 0;
157 tooltip_y = 0;
158 tooltip_currtextw = 0;
159 tooltip_ctrl = 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();
248 #define FreeInterfaceVector(type, variable, member) \
250 std::vector<type>::iterator i; \
251 for(i = (variable).begin(); i != (variable).end(); ++i) { \
252 if (!(*i).free) { \
253 if (i->member) \
254 (*i).member->release(); \
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();
328 music->release();
330 // stop any ambients which are still enqueued
331 if (AudioDriver) {
332 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
333 if (ambim) ambim->deactivate();
334 AudioDriver->release();
336 //destroy the highest objects in the hierarchy first!
337 delete game;
338 delete calendar;
339 delete worldmap;
341 FreeAbilityTables();
343 PluginMgr::Get()->RunCleanup();
345 ReleaseMemoryActor();
346 EffectQueue_ReleaseMemory();
347 CharAnimations::ReleaseMemory();
348 delete CurrentStore;
350 FreeResRefTable(DefSound, DSCount);
352 free( slottypes );
353 free( slotmatrix );
355 delete sgiterator;
357 if (Cursors) {
358 for (int i = 0; i < CursorCount; i++) {
359 video->FreeSprite( Cursors[i] );
361 delete[] Cursors;
364 FreeResourceVector( Font, fonts );
365 FreeResourceVector( Window, windows );
367 size_t i;
368 for (i = 0; i < musiclist.size(); i++) {
369 free((void *)musiclist[i]);
372 DamageInfoMap.clear();
374 ModalStates.clear();
376 delete plugin_flags;
378 delete projserv;
380 delete console;
382 delete pal256;
383 delete pal32;
384 delete pal16;
386 delete timer;
388 windowmgr->release();
390 if (video) {
392 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
393 video->FreeSprite(FogSprites[i]);
396 for(i=0;i<4;i++) {
397 video->FreeSprite(WindowFrames[i]);
400 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
401 for(i=0;i<6;i++) {
402 video->FreeSprite(GroundCircles[size][i]);
406 if (TooltipBack) {
407 for(i=0;i<3;i++) {
408 //freesprite checks for null pointer
409 video->FreeSprite(TooltipBack[i]);
411 delete[] TooltipBack;
413 if (InfoTextPalette) {
414 gamedata->FreePalette(InfoTextPalette);
417 video->SetDragCursor(NULL);
420 delete evntmgr;
422 guiscript->release();
424 delete vars;
425 delete tokens;
426 if (RtRows) {
427 RtRows->RemoveAll(ReleaseItemList);
428 delete RtRows;
430 if (ItemExclTable) {
431 ItemExclTable->RemoveAll(NULL);
432 delete ItemExclTable;
434 if (ItemDialTable) {
435 ItemDialTable->RemoveAll(NULL);
436 delete ItemDialTable;
438 if (ItemDial2Table) {
439 ItemDial2Table->RemoveAll(NULL);
440 delete ItemDial2Table;
442 if (ItemTooltipTable) {
443 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
444 delete ItemTooltipTable;
447 FreeInterfaceVector( Symbol, symbols, sm );
449 if (INIquests)
450 INIquests->release();
451 if (INIbeasts)
452 INIbeasts->release();
453 if (INIparty)
454 INIparty->release();
455 if (INIresdata)
456 INIresdata->release();
458 Map::ReleaseMemory();
459 Actor::ReleaseMemory();
461 gamedata->ClearCaches();
462 delete gamedata;
463 gamedata = NULL;
464 video->release();
466 strings->release();
468 // Removing all stuff from Cache, except bifs
469 if (!KeepCache) DelTree((const char *) CachePath, true);
472 void Interface::SetWindowFrame(int i, Sprite2D *Picture)
474 video->FreeSprite(WindowFrames[i]);
475 WindowFrames[i]=Picture;
478 GameControl* Interface::StartGameControl()
480 //making sure that our window is the first one
481 if (ConsolePopped) {
482 PopupConsole();
484 DelAllWindows();//deleting ALL windows
485 gamedata->DelTable(0xffffu); //dropping ALL tables
486 Window* gamewin = new Window( 0xffff, 0, 0, (ieWord) Width, (ieWord) Height );
487 gamewin->WindowPack[0]=0;
488 GameControl* gc = new GameControl();
489 gc->XPos = 0;
490 gc->YPos = 0;
491 gc->Width = (ieWord) Width;
492 gc->Height = (ieWord) Height;
493 gc->Owner = gamewin;
494 gc->ControlID = 0x00000000;
495 gc->ControlType = IE_GUI_GAMECONTROL;
496 gamewin->AddControl( gc );
497 AddWindow( gamewin );
498 SetVisible( 0, WINDOW_VISIBLE );
499 //setting the focus to the game control
500 evntmgr->SetFocused(gamewin, gc);
501 if (guiscript->LoadScript( "MessageWindow" )) {
502 guiscript->RunFunction( "OnLoad" );
503 gc->UnhideGUI();
506 return gc;
509 /* handle main loop events that might destroy or create windows
510 thus cannot be called from DrawWindows directly
511 these events are pending until conditions are right
513 void Interface::HandleEvents()
515 GameControl *gc = GetGameControl();
516 if (gc && (!gc->Owner || !gc->Owner->Visible)) {
517 gc=NULL;
521 if (EventFlag&EF_SELECTION) {
522 EventFlag&=~EF_SELECTION;
523 guiscript->RunFunction( "SelectionChanged", false);
526 if (EventFlag&EF_UPDATEANIM) {
527 EventFlag&=~EF_UPDATEANIM;
528 guiscript->RunFunction( "UpdateAnimation", false);
531 if (EventFlag&EF_PORTRAIT) {
532 ieDword tmp = (ieDword) ~0;
533 vars->Lookup( "PortraitWindow", tmp );
534 if (tmp != (ieDword) ~0) {
535 EventFlag&=~EF_PORTRAIT;
536 guiscript->RunFunction( "UpdatePortraitWindow" );
540 if (EventFlag&EF_ACTION) {
541 ieDword tmp = (ieDword) ~0;
542 vars->Lookup( "ActionsWindow", tmp );
543 if (tmp != (ieDword) ~0) {
544 EventFlag&=~EF_ACTION;
545 guiscript->RunFunction( "UpdateActionsWindow" );
549 if ((EventFlag&EF_CONTROL) && gc) {
550 EventFlag&=~EF_CONTROL;
551 guiscript->RunFunction( "UpdateControlStatus" );
552 //this is the only value we can use here
553 if (game->ControlStatus & CS_HIDEGUI)
554 gc->HideGUI();
555 else
556 gc->UnhideGUI();
557 return;
559 if ((EventFlag&EF_SHOWMAP) && gc) {
560 ieDword tmp = (ieDword) ~0;
561 vars->Lookup( "OtherWindow", tmp );
562 if (tmp == (ieDword) ~0) {
563 EventFlag &= ~EF_SHOWMAP;
564 guiscript->RunFunction( "ShowMap" );
566 return;
569 if (EventFlag&EF_SEQUENCER) {
570 EventFlag&=~EF_SEQUENCER;
571 guiscript->RunFunction( "OpenSequencerWindow" );
572 return;
575 if (EventFlag&EF_IDENTIFY) {
576 EventFlag&=~EF_IDENTIFY;
577 guiscript->RunFunction( "OpenIdentifyWindow" );
578 return;
580 if (EventFlag&EF_OPENSTORE) {
581 EventFlag&=~EF_OPENSTORE;
582 guiscript->RunFunction( "OpenStoreWindow" );
583 return;
586 if (EventFlag&EF_MASTERSCRIPT) {
587 EventFlag&=~EF_MASTERSCRIPT;
588 guiscript->RunFunction( "UpdateMasterScript" );
589 return;
594 /* handle main loop events that might destroy or create windows
595 thus cannot be called from DrawWindows directly
597 void Interface::HandleFlags()
599 EventFlag = EF_CONTROL; //clear events because the context changed
601 if (QuitFlag&(QF_QUITGAME|QF_EXITGAME) ) {
602 // when reaching this, quitflag should be 1 or 2
603 // if Exitgame was set, we'll set Start.py too
604 QuitGame (QuitFlag&QF_EXITGAME);
605 QuitFlag &= ~(QF_QUITGAME|QF_EXITGAME);
608 if (QuitFlag&QF_LOADGAME) {
609 QuitFlag &= ~QF_LOADGAME;
610 LoadGame(LoadGameIndex, VersionOverride );
613 if (QuitFlag&QF_ENTERGAME) {
614 QuitFlag &= ~QF_ENTERGAME;
615 if (game) {
616 timer->Init();
618 //rearrange party slots
619 game->ConsolidateParty();
620 GameControl* gc = StartGameControl();
621 //switch map to protagonist
622 Actor* actor = game->FindPC (1);
623 if (!actor) {
624 actor = game->GetPC (0, false);
626 if (actor) {
627 gc->ChangeMap(actor, true);
629 } else {
630 printMessage("Core", "No game to enter...\n", LIGHT_RED);
631 QuitFlag = QF_QUITGAME;
635 if (QuitFlag&QF_CHANGESCRIPT) {
636 QuitFlag &= ~QF_CHANGESCRIPT;
637 guiscript->LoadScript( NextScript );
638 guiscript->RunFunction( "OnLoad" );
642 bool GenerateAbilityTables()
644 FreeAbilityTables();
646 //range is: 0 - maximumability
647 int tablesize = MaximumAbility+1;
648 strmod = (ieWordSigned *) malloc (tablesize * 4 * sizeof(ieWordSigned) );
649 if (!strmod)
650 return false;
651 strmodex = (ieWordSigned *) malloc (101 * 4 * sizeof(ieWordSigned) );
652 if (!strmodex)
653 return false;
654 intmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
655 if (!intmod)
656 return false;
657 dexmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
658 if (!dexmod)
659 return false;
660 conmod = (ieWordSigned *) malloc (tablesize * 5 * sizeof(ieWordSigned) );
661 if (!conmod)
662 return false;
663 chrmod = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
664 if (!chrmod)
665 return false;
666 lorebon = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
667 if (!lorebon)
668 return false;
669 return true;
672 bool Interface::ReadAbilityTable(const ieResRef tablename, ieWordSigned *mem, int columns, int rows)
674 AutoTable tab(tablename);
675 if (!tab) {
676 return false;
678 //this is a hack for rows not starting at 0 in some cases
679 int fix = 0;
680 const char * tmp = tab->GetRowName(0);
681 if (tmp && (tmp[0]!='0')) {
682 fix = atoi(tmp);
683 for (int i=0;i<fix;i++) {
684 for (int j=0;j<columns;j++) {
685 mem[rows*j+i]=(ieWordSigned) strtol(tab->QueryField(0,j),NULL,0 );
689 for (int j=0;j<columns;j++) {
690 for( int i=0;i<rows-fix;i++) {
691 mem[rows*j+i+fix] = (ieWordSigned) strtol(tab->QueryField(i,j),NULL,0 );
694 return true;
697 bool Interface::ReadAbilityTables()
699 bool ret = GenerateAbilityTables();
700 if (!ret)
701 return ret;
702 ret = ReadAbilityTable("strmod", strmod, 4, MaximumAbility + 1);
703 if (!ret)
704 return ret;
705 ret = ReadAbilityTable("strmodex", strmodex, 4, 101);
706 //3rd ed doesn't have strmodex, but has a maximum of 40
707 if (!ret && (MaximumAbility<=25) )
708 return ret;
709 ret = ReadAbilityTable("intmod", intmod, 3, MaximumAbility + 1);
710 if (!ret)
711 return ret;
712 ret = ReadAbilityTable("hpconbon", conmod, 5, MaximumAbility + 1);
713 if (!ret)
714 return ret;
715 if (!HasFeature(GF_3ED_RULES)) {
716 //no lorebon in iwd2???
717 ret = ReadAbilityTable("lorebon", lorebon, 1, MaximumAbility + 1);
718 if (!ret)
719 return ret;
720 //no dexmod in iwd2???
721 ret = ReadAbilityTable("dexmod", dexmod, 3, MaximumAbility + 1);
722 if (!ret)
723 return ret;
725 //this table is a single row (not a single column)
726 ret = ReadAbilityTable("chrmodst", chrmod, MaximumAbility + 1, 1);
727 if (!ret)
728 return ret;
729 return true;
732 bool Interface::ReadAuxItemTables()
734 int idx;
735 int table;
736 bool flag = true;
738 if (ItemExclTable) {
739 ItemExclTable->RemoveAll(NULL);
740 } else {
741 ItemExclTable = new Variables();
742 ItemExclTable->SetType(GEM_VARIABLES_INT);
744 table = gamedata->LoadTable( "itemexcl" );
746 AutoTable aa;
748 //don't report error when the file doesn't exist
749 if (aa.load("itemexcl")) {
750 idx = aa->GetRowCount();
751 while (idx--) {
752 ieResRef key;
754 strnlwrcpy(key,aa->GetRowName(idx),8);
755 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
756 ItemExclTable->SetAt(key, value);
759 if (ItemDialTable) {
760 ItemDialTable->RemoveAll(NULL);
761 } else {
762 ItemDialTable = new Variables();
763 ItemDialTable->SetType(GEM_VARIABLES_INT);
765 if (ItemDial2Table) {
766 ItemDial2Table->RemoveAll(NULL);
767 } else {
768 ItemDial2Table = new Variables();
769 ItemDial2Table->SetType(GEM_VARIABLES_STRING);
772 //don't report error when the file doesn't exist
773 if (aa.load("itemdial")) {
774 idx = aa->GetRowCount();
775 while (idx--) {
776 ieResRef key, dlgres;
778 strnlwrcpy(key,aa->GetRowName(idx),8);
779 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
780 ItemDialTable->SetAt(key, value);
781 strnlwrcpy(dlgres,aa->QueryField(idx,1),8);
782 ItemDial2Table->SetAtCopy(key, dlgres);
786 if (ItemTooltipTable) {
787 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
788 } else {
789 ItemTooltipTable = new Variables();
790 ItemTooltipTable->SetType(GEM_VARIABLES_POINTER);
793 //don't report error when the file doesn't exist
794 if (aa.load("tooltip")) {
795 idx = aa->GetRowCount();
796 while (idx--) {
797 ieResRef key;
798 int *tmppoi = (int *) malloc(sizeof(int)*3);
800 strnlwrcpy(key,aa->GetRowName(idx),8);
801 for (int i=0;i<3;i++) {
802 tmppoi[i] = atoi(aa->QueryField(idx,i));
804 ItemTooltipTable->SetAt(key, (void*)tmppoi);
807 return flag;
810 //Static
811 const char *Interface::GetDeathVarFormat()
813 return DeathVarFormat;
816 int Interface::GetItemExcl(const ieResRef itemname) const
818 ieDword value;
820 if (ItemExclTable && ItemExclTable->Lookup(itemname, value)) {
821 return (int) value;
823 return 0;
826 int Interface::GetItemTooltip(const ieResRef itemname, int header, int identified)
828 int *value = NULL;
830 if (ItemTooltipTable) {
831 void* lookup = NULL;
832 ItemTooltipTable->Lookup(itemname, lookup);
833 value = (int*)lookup;
835 if (value && (value[header]>=0)) {
836 return value[header];
838 Item *item = gamedata->GetItem(itemname);
839 if (!item) {
840 return -1;
842 int ret = identified?item->ItemNameIdentified:item->ItemName;
843 gamedata->FreeItem(item, itemname, 0);
844 return ret;
847 int Interface::GetItemDialStr(const ieResRef itemname) const
849 ieDword value;
851 if (ItemDialTable && ItemDialTable->Lookup(itemname, value)) {
852 return (int) value;
854 return -1;
857 //second value is the item dialog resource returned by this method
858 int Interface::GetItemDialRes(const ieResRef itemname, ieResRef retval) const
860 if (ItemDial2Table && ItemDial2Table->Lookup(itemname, retval, sizeof(ieResRef))) {
861 return 1;
863 return 0;
866 bool Interface::ReadAreaAliasTable(const ieResRef tablename)
868 if (AreaAliasTable) {
869 AreaAliasTable->RemoveAll(NULL);
870 } else {
871 AreaAliasTable = new Variables();
872 AreaAliasTable->SetType(GEM_VARIABLES_INT);
875 AutoTable aa(tablename);
876 if (!aa) {
877 //don't report error when the file doesn't exist
878 return true;
881 int idx = aa->GetRowCount();
882 while (idx--) {
883 ieResRef key;
885 strnlwrcpy(key,aa->GetRowName(idx),8);
886 ieDword value = atoi(aa->QueryField(idx,0));
887 AreaAliasTable->SetAt(key, value);
889 return true;
892 //this isn't const
893 int Interface::GetAreaAlias(const ieResRef areaname) const
895 ieDword value;
897 if (AreaAliasTable && AreaAliasTable->Lookup(areaname, value)) {
898 return (int) value;
900 return -1;
903 bool Interface::ReadMusicTable(const ieResRef tablename, int col) {
904 AutoTable tm(tablename);
905 if (!tm)
906 return false;
908 for (unsigned int i = 0; i < tm->GetRowCount(); i++) {
909 musiclist.push_back(strdup(tm->QueryField(i, col)));
912 return true;
915 bool Interface::ReadDamageTypeTable() {
916 AutoTable tm("dmgtypes");
917 if (!tm)
918 return false;
920 DamageInfoStruct di;
921 for (ieDword i = 0; i < tm->GetRowCount(); i++) {
922 di.strref = core->GetStringReference(atoi(tm->QueryField(i, 0)));
923 di.resist_stat = TranslateStat(tm->QueryField(i, 1));
924 di.value = strtol(tm->QueryField(i, 2), (char **) NULL, 16);
925 di.iwd_mod_type = atoi(tm->QueryField(i, 3));
926 DamageInfoMap.insert(std::make_pair <ieDword, DamageInfoStruct> ((ieDword)di.value, di));
929 return true;
932 bool Interface::ReadModalStates()
934 AutoTable table("modal");
935 if (!table)
936 return false;
938 ModalStatesStruct ms;
939 for (unsigned short i = 0; i < table->GetRowCount(); i++) {
940 strncpy(ms.spell, table->QueryField(i, 0), 8);
941 strncpy(ms.action, table->QueryField(i, 1), 16);
942 ms.entering_str = atoi(table->QueryField(i, 2));
943 ms.leaving_str = atoi(table->QueryField(i, 3));
944 ms.failed_str = atoi(table->QueryField(i, 4));
945 ModalStates.push_back(ms);
948 return true;
951 //Not a constant anymore, we let the caller set the entry to zero
952 char *Interface::GetMusicPlaylist(int SongType) const {
953 if (SongType < 0 || (unsigned int)SongType >= musiclist.size())
954 return NULL;
956 return musiclist[SongType];
959 static const Color white = {0xff,0xff,0xff,0xff};
960 static const Color black = {0x00,0x00,0x00,0xff};
961 static const Region bg( 0, 0, 100, 30 );
963 /** this is the main loop */
964 void Interface::Main()
966 video->CreateDisplay( Width, Height, Bpp, FullScreen );
967 video->SetDisplayTitle( GameName, GameType );
968 ieDword brightness = 10;
969 ieDword contrast = 5;
970 ieDword speed = 10;
971 vars->Lookup("Brightness Correction", brightness);
972 vars->Lookup("Gamma Correction", contrast);
973 vars->Lookup("Mouse Scroll Speed", speed);
974 video->SetGamma(brightness, contrast);
975 SetMouseScrollSpeed((int) speed);
976 if (vars->Lookup("Tooltips", TooltipDelay)) {
977 // the games store the slider position*10, not the actual delay
978 TooltipDelay *= TOOLTIP_DELAY_FACTOR/10;
981 Font* fps = GetFont( ( unsigned int ) 0 );
982 char fpsstring[40]={"???.??? fps"};
983 unsigned long frame = 0, time, timebase;
984 GetTime(timebase);
985 double frames = 0.0;
986 Palette* palette = CreatePalette( white, black );
987 do {
988 //don't change script when quitting is pending
990 while (QuitFlag) {
991 HandleFlags();
993 if (EventFlag) {
994 HandleEvents();
996 HandleGUIBehaviour();
998 GameLoop();
999 DrawWindows();
1000 if (DrawFPS) {
1001 frame++;
1002 GetTime( time );
1003 if (time - timebase > 1000) {
1004 frames = ( frame * 1000.0 / ( time - timebase ) );
1005 timebase = time;
1006 frame = 0;
1007 sprintf( fpsstring, "%.3f fps", frames );
1009 video->DrawRect( bg, black );
1010 fps->Print( bg,
1011 ( unsigned char * ) fpsstring, palette,
1012 IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_MIDDLE, true );
1014 } while (video->SwapBuffers() == GEM_OK);
1015 gamedata->FreePalette( palette );
1018 bool Interface::ReadStrrefs()
1020 int i;
1021 memset(strref_table,-1,sizeof(strref_table) );
1022 AutoTable tab("strings");
1023 if (!tab) {
1024 return false;
1026 for(i=0;i<STRREF_COUNT;i++) {
1027 strref_table[i]=atoi(tab->QueryField(i,0));
1029 return true;
1032 int Interface::ReadResRefTable(const ieResRef tablename, ieResRef *&data)
1034 int count = 0;
1036 if (data) {
1037 free(data);
1038 data = NULL;
1040 AutoTable tm(tablename);
1041 if (!tm) {
1042 printStatus( "ERROR", LIGHT_RED );
1043 printf( "Cannot find %s.2da.\n",tablename );
1044 return 0;
1046 count = tm->GetRowCount();
1047 data = (ieResRef *) calloc( count, sizeof(ieResRef) );
1048 for (int i = 0; i < count; i++) {
1049 strnlwrcpy( data[i], tm->QueryField( i, 0 ), 8 );
1050 //* marks an empty resource
1051 if (data[i][0]=='*') {
1052 data[i][0]=0;
1055 return count;
1058 int Interface::LoadSprites()
1060 ieDword i;
1061 int size;
1062 if (!IsAvailable( IE_2DA_CLASS_ID )) {
1063 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1064 return GEM_ERROR;
1067 //loading cursors
1068 AnimationFactory* anim;
1069 anim = (AnimationFactory*) gamedata->GetFactoryResource("cursors", IE_BAM_CLASS_ID);
1070 if (anim)
1072 CursorCount = anim->GetCycleCount();
1073 Cursors = new Sprite2D * [CursorCount];
1074 for (int i = 0; i < CursorCount; i++) {
1075 Cursors[i] = anim->GetFrame( 0, (ieByte) i );
1078 printMessage( "Core", "Loading Cursors...", WHITE );
1080 // this is the last existing cursor type
1081 if (CursorCount<IE_CURSOR_WAY) {
1082 printStatus( "ERROR", LIGHT_RED );
1083 return GEM_ERROR;
1085 video->SetCursor( Cursors[0], Cursors[1] );
1086 printStatus( "OK", LIGHT_GREEN );
1088 // Load fog-of-war bitmaps
1089 anim = (AnimationFactory*) gamedata->GetFactoryResource("fogowar", IE_BAM_CLASS_ID);
1090 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE );
1091 if (!anim || anim->GetCycleSize( 0 ) != 8) {
1092 // unknown type of fog anim
1093 printStatus( "ERROR", LIGHT_RED );
1094 return GEM_ERROR;
1097 FogSprites[0] = NULL;
1098 FogSprites[1] = anim->GetFrame( 0, 0 );
1099 FogSprites[2] = anim->GetFrame( 1, 0 );
1100 FogSprites[3] = anim->GetFrame( 2, 0 );
1102 FogSprites[4] = video->MirrorSpriteVertical( FogSprites[1], false );
1104 FogSprites[5] = NULL;
1106 FogSprites[6] = video->MirrorSpriteVertical( FogSprites[3], false );
1108 FogSprites[7] = NULL;
1110 FogSprites[8] = video->MirrorSpriteHorizontal( FogSprites[2], false );
1112 FogSprites[9] = video->MirrorSpriteHorizontal( FogSprites[3], false );
1114 FogSprites[10] = NULL;
1115 FogSprites[11] = NULL;
1117 FogSprites[12] = video->MirrorSpriteHorizontal( FogSprites[6], false );
1119 FogSprites[16] = anim->GetFrame( 3, 0 );
1120 FogSprites[17] = anim->GetFrame( 4, 0 );
1121 FogSprites[18] = anim->GetFrame( 5, 0 );
1122 FogSprites[19] = anim->GetFrame( 6, 0 );
1124 FogSprites[20] = video->MirrorSpriteVertical( FogSprites[17], false );
1126 FogSprites[21] = NULL;
1128 FogSprites[23] = NULL;
1130 FogSprites[24] = video->MirrorSpriteHorizontal( FogSprites[18], false );
1132 FogSprites[25] = anim->GetFrame( 7, 0 );
1135 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[25], false );
1136 FogSprites[22] = video->MirrorSpriteHorizontal( tmpsprite, false );
1137 video->FreeSprite( tmpsprite );
1140 FogSprites[26] = NULL;
1141 FogSprites[27] = NULL;
1144 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[19], false );
1145 FogSprites[28] = video->MirrorSpriteHorizontal( tmpsprite, false );
1146 video->FreeSprite( tmpsprite );
1149 i = 0;
1150 vars->Lookup("3D Acceleration", i);
1151 if (i) {
1152 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
1153 if (FogSprites[i]) {
1154 Sprite2D* alphasprite = video->CreateAlpha( FogSprites[i] );
1155 video->FreeSprite ( FogSprites[i] );
1156 FogSprites[i] = alphasprite;
1161 printStatus( "OK", LIGHT_GREEN );
1163 // Load ground circle bitmaps (PST only)
1164 //block required due to msvc6.0 incompatibility
1165 for (size = 0; size < MAX_CIRCLE_SIZE; size++) {
1166 if (GroundCircleBam[size][0]) {
1167 anim = (AnimationFactory*) gamedata->GetFactoryResource(GroundCircleBam[size], IE_BAM_CLASS_ID);
1168 if (!anim || anim->GetCycleCount() != 6) {
1169 // unknown type of circle anim
1170 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1171 printStatus( "ERROR", LIGHT_RED );
1172 return GEM_ERROR;
1175 for (int i = 0; i < 6; i++) {
1176 Sprite2D* sprite = anim->GetFrame( 0, (ieByte) i );
1177 if (GroundCircleScale[size]) {
1178 GroundCircles[size][i] = video->SpriteScaleDown( sprite, GroundCircleScale[size] );
1179 video->FreeSprite( sprite );
1180 } else {
1181 GroundCircles[size][i] = sprite;
1187 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1188 printStatus( "OK", LIGHT_GREEN );
1190 printMessage( "Core", "Loading Fonts...\n", WHITE );
1191 AutoTable tab("fonts");
1192 if (!tab) {
1193 printStatus( "ERROR", LIGHT_RED );
1194 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1195 return GEM_ERROR;
1196 } else {
1197 AnimationMgr* bamint = ( AnimationMgr* ) GetInterface( IE_BAM_CLASS_ID );
1198 if (!bamint) {
1199 printStatus( "ERROR", LIGHT_RED );
1200 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1201 return GEM_ERROR;
1203 DataStream* str = NULL;
1205 int count = tab->GetRowCount();
1206 for (int i = 0; i < count; i++) {
1207 const char* ResRef = tab->QueryField( i, 0 );
1208 int needpalette = atoi( tab->QueryField( i, 1 ) );
1209 int first_char = atoi( tab->QueryField( i, 2 ) );
1210 str = gamedata->GetResource( ResRef, IE_BAM_CLASS_ID );
1211 if (!bamint->Open( str, true )) {
1212 continue;
1214 Font* fnt = bamint->GetFont();
1215 if (!fnt) {
1216 continue;
1218 strnlwrcpy( fnt->ResRef, ResRef, 8 );
1219 if (needpalette) {
1221 Color fore = {0xff, 0xff, 0xff, 0};
1222 Color back = {0x00, 0x00, 0x00, 0};
1223 if (!strnicmp( TooltipFont, ResRef, 8) ) {
1224 if (TooltipColor.a==0xff) {
1225 fore = TooltipColor;
1226 } else {
1227 fore = back;
1228 back = TooltipColor;
1231 Palette* pal = CreatePalette( fore, back );
1232 pal->CreateShadedAlphaChannel();
1233 fnt->SetPalette(pal);
1234 gamedata->FreePalette( pal );
1236 fnt->SetFirstChar( (ieByte) first_char );
1237 fonts.push_back( fnt );
1239 bamint->release();
1241 printMessage( "Core", "Fonts Loaded...", WHITE );
1242 printStatus( "OK", LIGHT_GREEN );
1244 if (TooltipBackResRef[0]) {
1245 anim = (AnimationFactory*) gamedata->GetFactoryResource(TooltipBackResRef, IE_BAM_CLASS_ID);
1246 printMessage( "Core", "Initializing Tooltips...", WHITE );
1247 if (!anim) {
1248 printStatus( "ERROR", LIGHT_RED );
1249 return GEM_ERROR;
1251 TooltipBack = new Sprite2D * [3];
1252 for (int i = 0; i < 3; i++) {
1253 TooltipBack[i] = anim->GetFrame( 0, (ieByte) i );
1254 TooltipBack[i]->XPos = 0;
1255 TooltipBack[i]->YPos = 0;
1257 printStatus( "OK", LIGHT_GREEN );
1260 return GEM_OK;
1263 int Interface::Init()
1265 plugin_flags = new Variables();
1266 plugin_flags->SetType( GEM_VARIABLES_INT );
1268 printMessage( "Core", "Initializing the Event Manager...", WHITE );
1269 evntmgr = new EventMgr();
1271 printMessage( "Core", "Initializing Variables Dictionary...", WHITE );
1272 vars = new Variables();
1273 if (!vars) {
1274 printStatus( "ERROR", LIGHT_RED );
1275 return GEM_ERROR;
1278 vars->SetType( GEM_VARIABLES_INT );
1279 vars->SetAt( "Volume Ambients", 100 );
1280 vars->SetAt( "Volume Movie", 100 );
1281 vars->SetAt( "Volume Music", 100 );
1282 vars->SetAt( "Volume SFX", 100 );
1283 vars->SetAt( "Volume Voices", 100 );
1284 printStatus( "OK", LIGHT_GREEN );
1286 if (!LoadConfig()) {
1287 return GEM_ERROR;
1289 printMessage( "Core", "Starting Plugin Manager...\n", WHITE );
1290 PluginMgr *plugin = PluginMgr::Get();
1291 plugin->LoadPlugins(PluginsPath);
1292 if (plugin && plugin->GetPluginCount()) {
1293 printMessage( "Core", "Plugin Loading Complete...", WHITE );
1294 printStatus( "OK", LIGHT_GREEN );
1295 } else {
1296 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW);
1297 printStatus( "ERROR", LIGHT_RED );
1298 return GEM_ERROR;
1300 plugin->RunInitializers();
1302 time_t t;
1303 t = time( NULL );
1304 srand( ( unsigned int ) t );
1305 #ifdef _DEBUG
1306 FileStreamPtrCount = 0;
1307 CachedFileStreamPtrCount = 0;
1308 #endif
1309 printMessage( "Core", "GemRB Core Initialization...\n", WHITE );
1310 printMessage( "Core", "Searching for Video Driver...", WHITE );
1311 if (!IsAvailable( IE_VIDEO_CLASS_ID )) {
1312 printStatus( "ERROR", LIGHT_RED );
1313 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1314 return GEM_ERROR;
1316 printStatus( "OK", LIGHT_GREEN );
1317 printMessage( "Core", "Initializing Video Plugin...", WHITE );
1318 video = ( Video * ) GetInterface( IE_VIDEO_CLASS_ID );
1319 if (video->Init() == GEM_ERROR) {
1320 printStatus( "ERROR", LIGHT_RED );
1321 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1322 return GEM_ERROR;
1324 Color defcolor={255,255,255,200};
1325 SetInfoTextColor(defcolor);
1326 printStatus( "OK", LIGHT_GREEN );
1329 printMessage( "Core", "Initializing Search Path...", WHITE );
1330 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY )) {
1331 printf( "no DirectoryImporter! " );
1332 printStatus( "ERROR", LIGHT_RED );
1333 return GEM_ERROR;
1336 char path[_MAX_PATH];
1338 PathJoin( path, core->CachePath, NULL);
1339 gamedata->AddSource(path, "Cache", PLUGIN_RESOURCE_DIRECTORY);
1341 PathJoin( path, core->GemRBOverridePath, "override", core->GameType, NULL);
1342 gamedata->AddSource(path, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1344 PathJoin( path, core->GemRBOverridePath, "override", "shared", NULL);
1345 gamedata->AddSource(path, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1347 PathJoin( path, core->GamePath, core->GameOverridePath, NULL);
1348 gamedata->AddSource(path, "Override", PLUGIN_RESOURCE_DIRECTORY);
1350 PathJoin( path, core->GamePath, core->GameSoundsPath, NULL);
1351 gamedata->AddSource(path, "Sounds", PLUGIN_RESOURCE_DIRECTORY);
1353 PathJoin( path, core->GamePath, core->GameScriptsPath, NULL);
1354 gamedata->AddSource(path, "Scripts", PLUGIN_RESOURCE_DIRECTORY);
1356 PathJoin( path, core->GamePath, core->GamePortraitsPath, NULL);
1357 gamedata->AddSource(path, "Portraits", PLUGIN_RESOURCE_DIRECTORY);
1359 PathJoin( path, core->GamePath, core->GameDataPath, NULL);
1360 gamedata->AddSource(path, "Data", PLUGIN_RESOURCE_DIRECTORY);
1362 //IWD2 movies are on the CD but not in the BIF
1363 for (int i = 0; i < 6; i++) {
1364 char description[] = "CDi/data";
1365 PathJoin( path, core->CD[i], core->GameDataPath, NULL);
1366 description[2] = '1' + i;
1367 gamedata->AddSource(path, description, PLUGIN_RESOURCE_DIRECTORY);
1370 printStatus( "OK", LIGHT_GREEN );
1374 printMessage( "Core", "Initializing KEY Importer...", WHITE );
1375 char ChitinPath[_MAX_PATH];
1376 PathJoin( ChitinPath, GamePath, "chitin.key", NULL );
1377 if (!gamedata->AddSource(ChitinPath, "chitin.key", PLUGIN_RESOURCE_KEY)) {
1378 printStatus( "ERROR", LIGHT_RED );
1379 return GEM_ERROR;
1381 printStatus( "OK", LIGHT_GREEN );
1384 printMessage( "Core", "Reading Game Options...\n", WHITE );
1385 if (!LoadGemRBINI())
1387 printf( "Cannot Load INI\nTermination in Progress...\n" );
1388 return GEM_ERROR;
1391 //loading baldur.ini
1393 char ini_path[_MAX_PATH];
1394 PathJoin( ini_path, GamePath, INIConfig, NULL );
1395 LoadINI( ini_path );
1396 int i;
1397 for (i = 0; i < 8; i++) {
1398 if (INIConfig[i] == '.')
1399 break;
1400 GameNameResRef[i] = INIConfig[i];
1402 GameNameResRef[i] = 0;
1405 printMessage( "Core", "Creating Projectile Server...\n", WHITE );
1406 projserv = new ProjectileServer();
1407 if (!projserv->GetHighestProjectileNumber()) {
1408 printStatus( "ERROR", LIGHT_RED );
1409 printf( "No projectiles are available...\n" );
1412 printMessage( "Core", "Checking for Dialogue Manager...", WHITE );
1413 if (!IsAvailable( IE_TLK_CLASS_ID )) {
1414 printStatus( "ERROR", LIGHT_RED );
1415 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1416 return GEM_ERROR;
1418 printStatus( "OK", LIGHT_GREEN );
1419 strings = ( StringMgr * ) GetInterface( IE_TLK_CLASS_ID );
1420 printMessage( "Core", "Loading Dialog.tlk file...", WHITE );
1421 char strpath[_MAX_PATH];
1422 PathJoin( strpath, GamePath, dialogtlk, NULL );
1423 FileStream* fs = new FileStream();
1424 if (!fs->Open( strpath, true )) {
1425 printStatus( "ERROR", LIGHT_RED );
1426 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1427 delete fs;
1428 return GEM_ERROR;
1430 printStatus( "OK", LIGHT_GREEN );
1431 strings->Open( fs, true );
1434 printMessage( "Core", "Loading Palettes...\n", WHITE );
1435 ImageMgr *im =( ImageMgr * ) gamedata->GetResource( Palette16, &ImageMgr::ID );
1436 pal16 = im->GetImage();
1437 im->release();
1438 im = ( ImageMgr * ) gamedata->GetResource( Palette32, &ImageMgr::ID );
1439 pal32 = im->GetImage();
1440 im->release();
1441 im = ( ImageMgr * ) gamedata->GetResource( Palette256, &ImageMgr::ID );
1442 pal256 = im->GetImage();
1443 im->release();
1444 printMessage( "Core", "Palettes Loaded\n", WHITE );
1447 if (!IsAvailable( IE_BAM_CLASS_ID )) {
1448 printStatus( "ERROR", LIGHT_RED );
1449 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1450 return GEM_ERROR;
1453 printMessage( "Core", "Initializing stock sounds...\n", WHITE );
1454 DSCount = ReadResRefTable ("defsound", DefSound);
1455 if (DSCount == 0) {
1456 printStatus( "ERROR", LIGHT_RED );
1457 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1458 return GEM_ERROR;
1461 printStatus( "OK", LIGHT_GREEN );
1462 printMessage( "Core", "Broadcasting Event Manager...", WHITE );
1463 video->SetEventMgr( evntmgr );
1464 printStatus( "OK", LIGHT_GREEN );
1465 printMessage( "Core", "Initializing Window Manager...", WHITE );
1466 windowmgr = ( WindowMgr * ) GetInterface( IE_CHU_CLASS_ID );
1467 if (windowmgr == NULL) {
1468 printStatus( "ERROR", LIGHT_RED );
1469 return GEM_ERROR;
1471 printStatus( "OK", LIGHT_GREEN );
1472 printMessage( "Core", "Initializing GUI Script Engine...", WHITE );
1473 guiscript = ( ScriptEngine * ) GetInterface( IE_GUI_SCRIPT_CLASS_ID );
1474 if (guiscript == NULL) {
1475 printStatus( "ERROR", LIGHT_RED );
1476 return GEM_ERROR;
1478 if (!guiscript->Init()) {
1479 printStatus( "ERROR", LIGHT_RED );
1480 return GEM_ERROR;
1482 printStatus( "OK", LIGHT_GREEN );
1483 strcpy( NextScript, "Start" );
1485 int ret = LoadSprites();
1486 if (ret) return ret;
1488 Sprite2D *tmpsprite = GetCursorSprite();
1489 printMessage( "Core", "Setting up the Console...", WHITE );
1490 QuitFlag = QF_CHANGESCRIPT;
1491 console = new Console();
1492 console->XPos = 0;
1493 console->YPos = (ieWord) (Height - 25);
1494 console->Width = (ieWord) Width;
1495 console->Height = 25;
1496 console->SetFont( fonts[0] );
1497 if (!tmpsprite) {
1498 printStatus( "ERROR", LIGHT_RED );
1499 return GEM_ERROR;
1501 console->SetCursor (tmpsprite);
1502 printStatus( "OK", LIGHT_GREEN );
1504 printMessage( "Core", "Starting up the Sound Driver...", WHITE );
1505 AudioDriver = ( Audio * ) GetInterface( IE_AUDIO_CLASS_ID );
1506 if (AudioDriver == NULL) {
1507 printStatus( "ERROR", LIGHT_RED );
1508 return GEM_ERROR;
1510 if (!AudioDriver->Init()) {
1511 printStatus( "ERROR", LIGHT_RED );
1512 return GEM_ERROR;
1514 printStatus( "OK", LIGHT_GREEN );
1516 printMessage( "Core", "Allocating SaveGameIterator...", WHITE );
1517 sgiterator = new SaveGameIterator();
1518 if (sgiterator == NULL) {
1519 printStatus( "ERROR", LIGHT_RED );
1520 return GEM_ERROR;
1522 printStatus( "OK", LIGHT_GREEN );
1524 //no need of strdup, variables do copy the key!
1525 vars->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos );
1526 vars->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements );
1528 printMessage( "Core", "Initializing Token Dictionary...", WHITE );
1529 tokens = new Variables();
1530 if (!tokens) {
1531 printStatus( "ERROR", LIGHT_RED );
1532 return GEM_ERROR;
1534 tokens->SetType( GEM_VARIABLES_STRING );
1535 printStatus( "OK", LIGHT_GREEN );
1537 printMessage( "Core", "Initializing Music Manager...", WHITE );
1538 music = ( MusicMgr * ) GetInterface( IE_MUS_CLASS_ID );
1539 if (!music) {
1540 printStatus( "ERROR", LIGHT_RED );
1541 return GEM_ERROR;
1543 printStatus( "OK", LIGHT_GREEN );
1545 printMessage("Core", "Loading music list...\n", WHITE );
1546 if (HasFeature( GF_HAS_SONGLIST )) {
1547 ret = ReadMusicTable("songlist", 1);
1548 } else {
1549 /*since bg1 and pst has no .2da for songlist,
1550 we must supply one in the gemrb/override folder.
1551 It should be: music.2da, first column is a .mus filename*/
1552 ret = ReadMusicTable("music", 0);
1554 if (ret) {
1555 printStatus( "OK", LIGHT_GREEN );
1556 } else {
1557 printStatus( "NOT FOUND", YELLOW );
1560 if (HasFeature( GF_RESDATA_INI )) {
1561 printMessage( "Core", "Loading resource data File...", WHITE );
1562 INIresdata = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1563 DataStream* ds = gamedata->GetResource("resdata", IE_INI_CLASS_ID);
1564 if (!INIresdata->Open( ds, true )) {
1565 printStatus( "ERROR", LIGHT_RED );
1566 } else {
1567 printStatus( "OK", LIGHT_GREEN );
1571 if (HasFeature( GF_HAS_PARTY_INI )) {
1572 printMessage( "Core", "Loading precreated teams setup...\n",
1573 WHITE );
1574 INIparty = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1575 FileStream* fs = new FileStream();
1576 char tINIparty[_MAX_PATH];
1577 PathJoin( tINIparty, GamePath, "Party.ini", NULL );
1578 fs->Open( tINIparty, true );
1579 if (!INIparty->Open( fs, true )) {
1580 printStatus( "ERROR", LIGHT_RED );
1581 } else {
1582 printStatus( "OK", LIGHT_GREEN );
1586 if (HasFeature(GF_IWD2_DEATHVARFORMAT)) {
1587 memcpy(DeathVarFormat, IWD2DeathVarFormat, sizeof(ieVariable));
1590 if (HasFeature( GF_HAS_BEASTS_INI )) {
1591 printMessage( "Core", "Loading beasts definition File...\n",
1592 WHITE );
1593 INIbeasts = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1594 FileStream* fs = new FileStream();
1595 char tINIbeasts[_MAX_PATH];
1596 PathJoin( tINIbeasts, GamePath, "beast.ini", NULL );
1597 // FIXME: crashes if file does not open
1598 fs->Open( tINIbeasts, true );
1599 if (!INIbeasts->Open( fs, true )) {
1600 printStatus( "ERROR", LIGHT_RED );
1601 } else {
1602 printStatus( "OK", LIGHT_GREEN );
1605 printMessage( "Core", "Loading quests definition File...\n",
1606 WHITE );
1607 INIquests = ( DataFileMgr * ) GetInterface( IE_INI_CLASS_ID );
1608 FileStream* fs2 = new FileStream();
1609 char tINIquests[_MAX_PATH];
1610 PathJoin( tINIquests, GamePath, "quests.ini", NULL );
1611 // FIXME: crashes if file does not open
1612 fs2->Open( tINIquests, true );
1613 if (!INIquests->Open( fs2, true )) {
1614 printStatus( "ERROR", LIGHT_RED );
1615 } else {
1616 printStatus( "OK", LIGHT_GREEN );
1619 game = NULL;
1620 calendar = NULL;
1622 timer = new GlobalTimer();
1623 printMessage( "Core", "Bringing up the Global Timer...", WHITE );
1624 if (!timer) {
1625 printStatus( "ERROR", LIGHT_RED );
1626 return GEM_ERROR;
1628 printStatus( "OK", LIGHT_GREEN );
1630 ret = Init_EffectQueue();
1631 printMessage( "Core", "Initializing effects...", WHITE );
1632 if (!ret) {
1633 printStatus( "ERROR", LIGHT_RED );
1634 return GEM_ERROR;
1636 printStatus( "OK", LIGHT_GREEN );
1638 ret = InitItemTypes();
1639 printMessage( "Core", "Initializing Inventory Management...", WHITE );
1640 if (!ret) {
1641 printStatus( "ERROR", LIGHT_RED );
1642 return GEM_ERROR;
1644 printStatus( "OK", LIGHT_GREEN );
1646 ret = ReadStrrefs();
1647 printMessage( "Core", "Initializing string constants...", WHITE );
1648 if (!ret) {
1649 printStatus( "ERROR", LIGHT_RED );
1650 return GEM_ERROR;
1652 printStatus( "OK", LIGHT_GREEN );
1654 ret = ReadRandomItems();
1655 printMessage( "Core", "Initializing random treasure...", WHITE );
1656 if (ret) {
1657 printStatus( "OK", LIGHT_GREEN );
1659 else {
1660 printStatus( "ERROR", LIGHT_RED );
1663 ret = ReadAbilityTables();
1664 printMessage( "Core", "Initializing ability tables...", WHITE );
1665 if (!ret) {
1666 printStatus( "ERROR", LIGHT_RED );
1667 return GEM_ERROR;
1669 printStatus( "OK", LIGHT_GREEN );
1671 if ( gamedata->Exists("WMAPLAY", IE_2DA_CLASS_ID) ) {
1672 ret = ReadAreaAliasTable( "WMAPLAY" );
1673 printMessage( "Core", "Initializing area aliases...", WHITE );
1674 if (ret) {
1675 printStatus( "OK", LIGHT_GREEN );
1677 else {
1678 printStatus( "NOT FOUND", YELLOW );
1682 ret = ReadAuxItemTables();
1683 printMessage( "Core", "Reading item tables...", WHITE);
1684 if (!ret) {
1685 printStatus( "ERROR", LIGHT_RED );
1686 return GEM_ERROR;
1688 printStatus( "OK", LIGHT_GREEN );
1690 ret = ReadDamageTypeTable();
1691 printMessage( "Core", "Reading damage type table...", WHITE);
1692 if (!ret) {
1693 printStatus( "ERROR", LIGHT_RED );
1694 } else {
1695 printStatus( "OK", LIGHT_GREEN );
1698 ret = ReadModalStates();
1699 printMessage( "Core", "Reading modal states table...", WHITE);
1700 if (!ret) {
1701 printStatus( "ERROR", LIGHT_RED );
1702 return GEM_ERROR;
1703 } else {
1704 printStatus( "OK", LIGHT_GREEN );
1707 printMessage( "Core", "Reading modal states table...", WHITE);
1708 InitializeIEScript();
1709 printStatus( "OK", LIGHT_GREEN );
1711 printMessage( "Core", "Core Initialization Complete!\n", WHITE );
1713 return GEM_OK;
1716 bool Interface::IsAvailable(SClass_ID filetype) const
1718 return PluginMgr::Get()->IsAvailable( filetype );
1721 WorldMap *Interface::GetWorldMap(const char *map)
1723 int index = worldmap->FindAndSetCurrentMap(map?map:game->CurrentArea);
1724 return worldmap->GetWorldMap(index);
1727 void* Interface::GetInterface(SClass_ID filetype) const
1729 if (!PluginMgr::Get()) {
1730 return NULL;
1732 return PluginMgr::Get()->GetPlugin( filetype );
1735 ProjectileServer* Interface::GetProjectileServer() const
1737 return projserv;
1740 Video* Interface::GetVideoDriver() const
1742 return video;
1745 const char* Interface::TypeExt(SClass_ID type) const
1747 switch (type) {
1748 case IE_2DA_CLASS_ID:
1749 return ".2da";
1751 case IE_ACM_CLASS_ID:
1752 return ".acm";
1754 case IE_ARE_CLASS_ID:
1755 return ".are";
1757 case IE_BAM_CLASS_ID:
1758 return ".bam";
1760 case IE_BCS_CLASS_ID:
1761 return ".bcs";
1763 case IE_BS_CLASS_ID:
1764 return ".bs";
1766 case IE_BIF_CLASS_ID:
1767 return ".bif";
1769 case IE_BMP_CLASS_ID:
1770 return ".bmp";
1772 case IE_PNG_CLASS_ID:
1773 return ".png";
1775 case IE_CHR_CLASS_ID:
1776 return ".chr";
1778 case IE_CHU_CLASS_ID:
1779 return ".chu";
1781 case IE_CRE_CLASS_ID:
1782 return ".cre";
1784 case IE_DLG_CLASS_ID:
1785 return ".dlg";
1787 case IE_EFF_CLASS_ID:
1788 return ".eff";
1790 case IE_GAM_CLASS_ID:
1791 return ".gam";
1793 case IE_IDS_CLASS_ID:
1794 return ".ids";
1796 case IE_INI_CLASS_ID:
1797 return ".ini";
1799 case IE_ITM_CLASS_ID:
1800 return ".itm";
1802 case IE_MOS_CLASS_ID:
1803 return ".mos";
1805 case IE_MUS_CLASS_ID:
1806 return ".mus";
1808 case IE_MVE_CLASS_ID:
1809 return ".mve";
1811 case IE_OGG_CLASS_ID:
1812 return ".ogg";
1814 case IE_PLT_CLASS_ID:
1815 return ".plt";
1817 case IE_PRO_CLASS_ID:
1818 return ".pro";
1820 case IE_SAV_CLASS_ID:
1821 return ".sav";
1823 case IE_SPL_CLASS_ID:
1824 return ".spl";
1826 case IE_SRC_CLASS_ID:
1827 return ".src";
1829 case IE_STO_CLASS_ID:
1830 return ".sto";
1832 case IE_TIS_CLASS_ID:
1833 return ".tis";
1835 case IE_TLK_CLASS_ID:
1836 return ".tlk";
1838 case IE_TOH_CLASS_ID:
1839 return ".toh";
1841 case IE_TOT_CLASS_ID:
1842 return ".tot";
1844 case IE_VAR_CLASS_ID:
1845 return ".var";
1847 case IE_VVC_CLASS_ID:
1848 return ".vvc";
1850 case IE_WAV_CLASS_ID:
1851 return ".wav";
1853 case IE_WED_CLASS_ID:
1854 return ".wed";
1856 case IE_WFX_CLASS_ID:
1857 return ".wfx";
1859 case IE_WMP_CLASS_ID:
1860 return ".wmp";
1862 return NULL;
1865 void Interface::FreeString(char *&str) const
1867 if (str) {
1868 strings->FreeString(str);
1870 str = NULL;
1873 ieStrRef Interface::UpdateString(ieStrRef strref, const char *text) const
1875 return strings->UpdateString( strref, text );
1878 char* Interface::GetString(ieStrRef strref, ieDword options) const
1880 ieDword flags = 0;
1882 if (!(options & IE_STR_STRREFOFF)) {
1883 vars->Lookup( "Strref On", flags );
1885 return strings->GetString( strref, flags | options );
1888 void Interface::SetFeature(int flag, int position)
1890 if (position>=32) {
1891 position-=32;
1892 if (flag) {
1893 GameFeatures2 |= 1 << position;
1894 } else {
1895 GameFeatures2 &= ~( 1 << position );
1897 return;
1899 if (flag) {
1900 GameFeatures |= 1 << position;
1901 } else {
1902 GameFeatures &= ~( 1 << position );
1906 ieDword Interface::HasFeature(int position) const
1908 if (position>=32) {
1909 return GameFeatures2 & ( 1 << (position-32) );
1911 return GameFeatures & ( 1 << position );
1914 /** Search directories and load a config file */
1915 bool Interface::LoadConfig(void)
1917 #ifndef WIN32
1918 char path[_MAX_PATH];
1919 char name[_MAX_PATH];
1921 // Find directory where user stores GemRB configurations (~/.gemrb).
1922 // FIXME: Create it if it does not exist
1923 // Use current dir if $HOME is not defined (or bomb out??)
1925 char* s = getenv( "HOME" );
1926 if (s) {
1927 strcpy( UserDir, s );
1928 strcat( UserDir, "/."PACKAGE"/" );
1929 } else {
1930 strcpy( UserDir, "./" );
1933 // Find basename of this program. It does the same as basename (3),
1934 // but that's probably missing on some archs
1935 s = strrchr( argv[0], PathDelimiter );
1936 if (s) {
1937 s++;
1938 } else {
1939 s = argv[0];
1942 strcpy( name, s );
1943 //if (!name[0]) // FIXME: could this happen?
1944 // strcpy (name, PACKAGE); // ugly hack
1946 // If we were called as $0 -c <filename>, load config from filename
1947 if (argc > 2 && ! strcmp("-c", argv[1])) {
1948 if (LoadConfig( argv[2] )) {
1949 return true;
1950 } else {
1951 // Explicitly specified cfg file HAS to be present
1952 return false;
1956 // FIXME: temporary hack, to be deleted??
1957 if (LoadConfig( "GemRB.cfg" )) {
1958 return true;
1961 PathJoin( path, UserDir, name, NULL );
1962 strcat( path, ".cfg" );
1964 if (LoadConfig( path )) {
1965 return true;
1968 #ifdef SYSCONFDIR
1969 PathJoin( path, SYSCONFDIR, name, NULL );
1970 strcat( path, ".cfg" );
1972 if (LoadConfig( path )) {
1973 return true;
1975 #endif
1977 // Don't try with default binary name if we have tried it already
1978 if (!strcmp( name, PACKAGE )) {
1979 return false;
1982 PathJoin( path, UserDir, PACKAGE, NULL );
1983 strcat( path, ".cfg" );
1985 if (LoadConfig( path )) {
1986 return true;
1989 #ifdef SYSCONFDIR
1990 PathJoin( path, SYSCONFDIR, PACKAGE, NULL );
1991 strcat( path, ".cfg" );
1993 if (LoadConfig( path )) {
1994 return true;
1996 #endif
1998 return false;
1999 #else // WIN32
2000 // If we were called as $0 -c <filename>, load config from filename
2001 if (argc > 2 && ! strcmp("-c", argv[1])) {
2002 return LoadConfig( argv[2] );
2003 // Explicitly specified cfg file HAS to be present
2005 strcpy( UserDir, ".\\" );
2006 return LoadConfig( "GemRB.cfg" );
2007 #endif// WIN32
2010 bool Interface::LoadConfig(const char* filename)
2012 FILE* config;
2014 printMessage("Config","Trying to open ", WHITE);
2015 textcolor(LIGHT_WHITE);
2016 printf("%s ", filename);
2017 config = fopen( filename, "rb" );
2018 if (config == NULL) {
2019 printStatus("NOT FOUND", LIGHT_RED);
2020 return false;
2022 char name[65], value[_MAX_PATH + 3];
2024 //once GemRB own format is working well, this might be set to 0
2025 SaveAsOriginal = 1;
2027 while (!feof( config )) {
2028 char rem;
2030 if (fread( &rem, 1, 1, config ) != 1)
2031 break;
2033 if (rem == '#') {
2034 //it should always return 0
2035 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
2036 break;
2037 continue;
2039 fseek( config, -1, SEEK_CUR );
2040 memset(value,'\0',_MAX_PATH + 3);
2041 //the * element is not counted
2042 if (fscanf( config, "%64[^= ] = %[^\r\n]%*[\r\n]", name, value )!=2)
2043 continue;
2044 for (int i=_MAX_PATH + 2; i > 0; i--) {
2045 if (value[i] == '\0') continue;
2046 if (value[i] == ' ') {
2047 value[i] = '\0';
2048 } else {
2049 break;
2053 if (stricmp( name, "Width" ) == 0) {
2054 Width = atoi( value );
2055 } else if (stricmp( name, "Height" ) == 0) {
2056 Height = atoi( value );
2057 } else if (stricmp( name, "Bpp" ) == 0) {
2058 Bpp = atoi( value );
2059 } else if (stricmp( name, "FullScreen" ) == 0) {
2060 FullScreen = ( atoi( value ) == 0 ) ? false : true;
2061 } else if (stricmp( name, "GUIEnhancements" ) == 0) {
2062 GUIEnhancements = ( atoi( value ) == 0 ) ? false : true;
2063 } else if (stricmp( name, "TooltipDelay" ) == 0) {
2064 TooltipDelay = atoi( value );
2065 } else if (stricmp( name, "DoubleClickDelay" ) == 0) {
2066 evntmgr->SetDCDelay( atoi( value ) );
2067 } else if (stricmp( name, "RepeatKeyDelay" ) == 0) {
2068 evntmgr->SetRKDelay( atoi( value ) );
2069 } else if (stricmp( name, "SkipIntroVideos" ) == 0) {
2070 SkipIntroVideos = ( atoi( value ) == 0 ) ? false : true;
2071 } else if (stricmp( name, "DrawFPS" ) == 0) {
2072 DrawFPS = ( atoi( value ) == 0 ) ? false : true;
2073 } else if (stricmp( name, "EnableCheatKeys" ) == 0) {
2074 EnableCheatKeys ( atoi( value ) );
2075 } else if (stricmp( name, "KeepCache" ) == 0) {
2076 KeepCache = ( atoi( value ) == 0 ) ? false : true;
2077 } else if (stricmp( name, "SkipPlugin" ) == 0) {
2078 plugin_flags->SetAt( value, PLF_SKIP );
2079 } else if (stricmp( name, "DelayPlugin" ) == 0) {
2080 plugin_flags->SetAt( value, PLF_DELAY );
2081 } else if (stricmp( name, "FogOfWar" ) == 0) {
2082 FogOfWar = atoi( value );
2083 } else if (stricmp( name, "EndianSwitch" ) == 0) {
2084 DataStream::SetEndianSwitch(atoi(value) );
2085 } else if (stricmp( name, "CaseSensitive" ) == 0) {
2086 CaseSensitive = ( atoi( value ) == 0 ) ? false : true;
2087 } else if (stricmp( name, "MultipleQuickSaves" ) == 0) {
2088 GameControl::MultipleQuickSaves(atoi(value));
2089 } else if (stricmp( name, "GameOnCD" ) == 0) {
2090 GameOnCD = ( atoi( value ) == 0 ) ? false : true;
2091 } else if (stricmp( name, "GameDataPath" ) == 0) {
2092 strncpy( GameDataPath, value, sizeof(GameDataPath) );
2093 } else if (stricmp( name, "GameOverridePath" ) == 0) {
2094 strncpy( GameOverridePath, value, sizeof(GameOverridePath) );
2095 } else if (stricmp( name, "GemRBOverridePath" ) == 0) {
2096 strncpy( GemRBOverridePath, value, sizeof(GemRBOverridePath) );
2097 ResolveFilePath(GemRBOverridePath);
2098 } else if (stricmp( name, "GameScriptsPath" ) == 0) {
2099 strncpy( GameScriptsPath, value, sizeof(GameScriptsPath) );
2100 } else if (stricmp( name, "GameSoundsPath" ) == 0) {
2101 strncpy( GameSoundsPath, value, sizeof(GameSoundsPath) );
2102 } else if (stricmp( name, "GamePortraitsPath" ) == 0) {
2103 strncpy( GamePortraitsPath, value, sizeof(GamePortraitsPath) );
2104 } else if (stricmp( name, "GameCharactersPath" ) == 0) {
2105 strncpy( GameCharactersPath, value, sizeof(GameCharactersPath) );
2106 } else if (stricmp( name, "GameName" ) == 0) {
2107 strncpy( GameName, value, sizeof(GameName) );
2108 } else if (stricmp( name, "GameType" ) == 0) {
2109 if (stricmp( value, "tob" ) == 0) {
2110 strncpy( GameType, "bg2", sizeof(GameType) );
2111 } else {
2112 strncpy( GameType, value, sizeof(GameType) );
2114 } else if (stricmp( name, "SaveAsOriginal") == 0) {
2115 SaveAsOriginal = atoi(value);
2116 } else if (stricmp( name, "GemRBPath" ) == 0) {
2117 strcpy( GemRBPath, value );
2118 ResolveFilePath(GemRBPath);
2119 } else if (stricmp( name, "ScriptDebugMode" ) == 0) {
2120 SetScriptDebugMode(atoi(value));
2121 } else if (stricmp( name, "CachePath" ) == 0) {
2122 strncpy( CachePath, value, sizeof(CachePath) );
2123 ResolveFilePath(CachePath);
2124 } else if (stricmp( name, "GUIScriptsPath" ) == 0) {
2125 strncpy( GUIScriptsPath, value, sizeof(GUIScriptsPath) );
2126 ResolveFilePath( GUIScriptsPath );
2127 } else if (stricmp( name, "PluginsPath" ) == 0) {
2128 strncpy( PluginsPath, value, sizeof(PluginsPath) );
2129 ResolveFilePath( PluginsPath );
2130 } else if (stricmp( name, "GamePath" ) == 0) {
2131 strncpy( GamePath, value, sizeof(GamePath) );
2132 ResolveFilePath( GamePath );
2133 } else if (stricmp( name, "SavePath" ) == 0) {
2134 strncpy( SavePath, value, sizeof(SavePath) );
2135 ResolveFilePath( SavePath );
2136 } else if (strnicmp( name, "CD", 2 ) == 0 &&
2137 name[2] >= '1' && name[2] <= '5' && name[3] == 0) {
2138 strncpy( CD[name[2]-'1'], value, sizeof(CD[name[2]-'1']) );
2139 ResolveFilePath( CD[name[2]-'1'] );
2142 fclose( config );
2145 if (!GameType[0]) {
2146 strcpy( GameType, "gemrb" );
2149 #ifdef DATADIR
2150 if (!GemRBPath[0]) {
2151 strcpy( GemRBPath, DATADIR );
2153 #endif
2155 if (!GemRBOverridePath[0]) {
2156 strcpy( GemRBOverridePath, GemRBPath );
2159 if (!PluginsPath[0]) {
2160 #ifdef PLUGINDIR
2161 strcpy( PluginsPath, PLUGINDIR );
2162 #else
2163 PathJoin( PluginsPath, GemRBPath, "plugins", NULL );
2164 #endif
2167 if (!GUIScriptsPath[0]) {
2168 strcpy( GUIScriptsPath, GemRBPath );
2171 if (!GameName[0]) {
2172 strcpy( GameName, GEMRB_STRING );
2175 if (!SavePath[0]) {
2176 // FIXME: maybe should use UserDir instead of GamePath
2177 strcpy( SavePath, GamePath );
2180 if (! CachePath[0]) {
2181 PathJoin( CachePath, UserDir, "Cache", NULL );
2185 FixPath( GUIScriptsPath, true );
2186 FixPath( PluginsPath, true );
2187 FixPath( GemRBPath, true );
2188 FixPath( GemRBOverridePath, true );
2190 if (GamePath[0]) {
2191 FixPath( GamePath, true );
2194 //FixPath( SavePath, false );
2195 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2196 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2197 FixPath( SavePath, true );
2199 FixPath( CachePath, false );
2200 mkdir( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2201 chmod( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2203 printStatus( "OK", LIGHT_GREEN );
2204 if ( StupidityDetector( CachePath )) {
2205 printMessage("Core"," ",LIGHT_RED);
2206 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath );
2207 return false;
2209 if (!KeepCache) DelTree((const char *) CachePath, false);
2210 FixPath( CachePath, true );
2212 return true;
2215 static void upperlower(int upper, int lower)
2217 pl_uppercase[lower]=(ieByte) upper;
2218 pl_lowercase[upper]=(ieByte) lower;
2221 static const char *game_flags[GF_COUNT+1]={
2222 "HasKaputz", //0 GF_HAS_KAPUTZ
2223 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2224 "HasSongList", //2 GF_HAS_SONGLIST
2225 "TeamMovement", //3 GF_TEAM_MOVEMENT
2226 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2227 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2228 "HasPartyIni", //6 GF_HAS_PARTY_INI
2229 "SoundFolders", //7 GF_SOUNDFOLDERS
2230 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2231 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2232 "HasDPLAYER", //10GF_HAS_DPLAYER
2233 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2234 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2235 "HasDescIcon", //13GF_HAS_DESC_ICON
2236 "HasPickSound", //14GF_HAS_PICK_SOUND
2237 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2238 "AutomapIni", //16GF_AUTOMAP_INI
2239 "SmallFog", //17GF_SMALL_FOG
2240 "ReverseDoor", //18GF_REVERSE_DOOR
2241 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2242 "HasSpellList", //20GF_HAS_SPELLLIST
2243 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2244 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2245 "KnowWorld", //23GF_KNOW_WORLD
2246 "ReverseToHit", //24GF_REVERSE_TOHIT
2247 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2248 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2249 "MagicBit", //27GF_MAGICBIT
2250 "CheckAbilities", //28GF_CHECK_ABILITIES
2251 "ChallengeRating", //29GF_CHALLENGERATING
2252 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2253 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2254 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2255 "SpawnIni", //33GF_SPAWN_INI
2256 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2257 "HasResDataIni", //35GF_RESDATA_INI
2258 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2259 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2260 "3EdRules", //38GF_3ED_RULES
2261 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2262 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2263 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2264 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2265 "ProperBackstab", //43GF_PROPER_BACKSTAB
2266 "OnScreenText", //44GF_ONSCREEN_TEXT
2267 "HasSpecificDamageBonus", //45GF_SPECIFIC_DMG_BONUS
2268 NULL //for our own safety, this marks the end of the pole
2271 /** Loads gemrb.ini */
2272 bool Interface::LoadGemRBINI()
2274 DataStream* inifile = gamedata->GetResource( "gemrb", IE_INI_CLASS_ID );
2275 if (! inifile) {
2276 printStatus( "ERROR", LIGHT_RED );
2277 return false;
2280 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE );
2281 printf( "%s",inifile->originalfile);
2283 if (!IsAvailable( IE_INI_CLASS_ID )) {
2284 printStatus( "ERROR", LIGHT_RED );
2285 printf( "[Core]: No INI Importer Available.\n" );
2286 return false;
2288 DataFileMgr* ini = ( DataFileMgr* ) GetInterface( IE_INI_CLASS_ID );
2289 ini->Open( inifile, true ); //autofree
2291 printStatus( "OK", LIGHT_GREEN );
2293 const char *s;
2295 // Resrefs are already initialized in Interface::Interface()
2296 s = ini->GetKeyAsString( "resources", "CursorBAM", NULL );
2297 if (s)
2298 strnlwrcpy( CursorBam, s, 8 ); //console cursor
2300 s = ini->GetKeyAsString( "resources", "ScrollCursorBAM", NULL );
2301 if (s)
2302 strnlwrcpy( ScrollCursorBam, s, 8 );
2304 s = ini->GetKeyAsString( "resources", "ButtonFont", NULL );
2305 if (s)
2306 strnlwrcpy( ButtonFont, s, 8 );
2308 s = ini->GetKeyAsString( "resources", "TooltipFont", NULL );
2309 if (s)
2310 strnlwrcpy( TooltipFont, s, 8 );
2312 s = ini->GetKeyAsString( "resources", "MovieFont", NULL );
2313 if (s)
2314 strnlwrcpy( MovieFont, s, 8 );
2316 s = ini->GetKeyAsString( "resources", "TooltipBack", NULL );
2317 if (s)
2318 strnlwrcpy( TooltipBackResRef, s, 8 );
2320 s = ini->GetKeyAsString( "resources", "TooltipColor", NULL );
2321 if (s) {
2322 if (s[0] == '#') {
2323 unsigned long c = strtoul (s + 1, NULL, 16);
2324 // FIXME: check errno
2325 TooltipColor.r = (unsigned char) (c >> 24);
2326 TooltipColor.g = (unsigned char) (c >> 16);
2327 TooltipColor.b = (unsigned char) (c >> 8);
2328 TooltipColor.a = (unsigned char) (c);
2332 //which stat determines the fist weapon (defaults to class)
2333 Actor::SetFistStat(ini->GetKeyAsInt( "resources", "FistStat", IE_CLASS));
2335 TooltipMargin = ini->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin );
2337 // The format of GroundCircle can be:
2338 // GroundCircleBAM1 = wmpickl/3
2339 // to denote that the bitmap should be scaled down 3x
2340 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
2341 char name[30];
2342 sprintf( name, "GroundCircleBAM%d", size+1 );
2343 s = ini->GetKeyAsString( "resources", name, NULL );
2344 if (s) {
2345 const char *pos = strchr( s, '/' );
2346 if (pos) {
2347 GroundCircleScale[size] = atoi( pos+1 );
2348 strncpy( GroundCircleBam[size], s, pos - s );
2349 GroundCircleBam[size][pos - s] = '\0';
2350 } else {
2351 strcpy( GroundCircleBam[size], s );
2356 s = ini->GetKeyAsString( "resources", "INIConfig", NULL );
2357 if (s)
2358 strcpy( INIConfig, s );
2360 s = ini->GetKeyAsString( "resources", "Palette16", NULL );
2361 if (s)
2362 strcpy( Palette16, s );
2364 s = ini->GetKeyAsString( "resources", "Palette32", NULL );
2365 if (s)
2366 strcpy( Palette32, s );
2368 s = ini->GetKeyAsString( "resources", "Palette256", NULL );
2369 if (s)
2370 strcpy( Palette256, s );
2372 unsigned int i = (unsigned int) ini->GetKeyAsInt ("charset", "CharCount", 0);
2373 if (i>99) i=99;
2374 while(i--) {
2375 char key[10];
2376 snprintf(key,9,"Letter%d", i+1);
2377 s = ini->GetKeyAsString( "charset", key, NULL );
2378 if (s) {
2379 const char *s2 = strchr(s,',');
2380 if (s2) {
2381 upperlower(atoi(s), atoi(s2+1) );
2386 MaximumAbility = ini->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2388 RedrawTile = ini->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2390 for (i=0;i<GF_COUNT;i++) {
2391 if (!game_flags[i]) {
2392 printf("Fix the game flags!\n");
2393 abort();
2395 SetFeature( ini->GetKeyAsInt( "resources", game_flags[i], 0 ), i );
2396 printMessage("Option", "", GREEN);
2397 printf("%s = %s\n", game_flags[i], HasFeature(i)?"yes":"no");
2400 ForceStereo = ini->GetKeyAsInt( "resources", "ForceStereo", 0 );
2402 ini->release();
2403 return true;
2406 Palette* Interface::CreatePalette(const Color &color, const Color &back)
2408 Palette* pal = new Palette();
2409 pal->col[0].r = 0;
2410 pal->col[0].g = 0xff;
2411 pal->col[0].b = 0;
2412 pal->col[0].a = 0;
2413 for (int i = 1; i < 256; i++) {
2414 pal->col[i].r = back.r +
2415 ( unsigned char ) ( ( ( color.r - back.r ) * ( i ) ) / 255.0 );
2416 pal->col[i].g = back.g +
2417 ( unsigned char ) ( ( ( color.g - back.g ) * ( i ) ) / 255.0 );
2418 pal->col[i].b = back.b +
2419 ( unsigned char ) ( ( ( color.b - back.b ) * ( i ) ) / 255.0 );
2420 pal->col[i].a = back.a +
2421 ( unsigned char ) ( ( ( color.a - back.a ) * ( i ) ) / 255.0 );
2423 return pal;
2426 /** No descriptions */
2427 Color* Interface::GetPalette(unsigned index, int colors, Color *pal) const
2429 Image *img;
2430 if (colors == 32) {
2431 img = pal32;
2432 } else if (colors <= 32) {
2433 img = pal16;
2434 } else if (colors == 256) {
2435 img = pal256;
2436 } else {
2437 return pal;
2439 if (index >= img->GetHeight()) {
2440 index = 0;
2442 for (int i = 0; i < colors; i++) {
2443 pal[i] = img->GetPixel(i, index);
2445 return pal;
2447 /** Returns a preloaded Font */
2448 Font* Interface::GetFont(const char *ResRef) const
2450 for (unsigned int i = 0; i < fonts.size(); i++) {
2451 if (strnicmp( fonts[i]->ResRef, ResRef, 8 ) == 0) {
2452 return fonts[i];
2455 return NULL;
2458 Font* Interface::GetFont(unsigned int index) const
2460 if (index >= fonts.size()) {
2461 return NULL;
2463 return fonts[index];
2466 Font* Interface::GetButtonFont() const
2468 return GetFont( ButtonFont );
2471 /** Returns the Event Manager */
2472 EventMgr* Interface::GetEventMgr() const
2474 return evntmgr;
2477 /** Returns the Window Manager */
2478 WindowMgr* Interface::GetWindowMgr() const
2480 return windowmgr;
2483 /** Get GUI Script Manager */
2484 ScriptEngine* Interface::GetGUIScriptEngine() const
2486 return guiscript;
2489 //NOTE: if there were more summoned creatures, it will return only the last
2490 Actor *Interface::SummonCreature(const ieResRef resource, const ieResRef vvcres, Scriptable *Owner, Actor *target, Point &position, int eamod, int level, Effect *fx, bool sexmod)
2492 //maximum number of monsters summoned
2493 int cnt=10;
2494 Actor * ab = NULL;
2496 //TODO:
2497 //decrease the number of summoned creatures with the number of already summoned creatures here
2498 //the summoned creatures have a special IE_SPECIFIC
2500 while(cnt--) {
2501 ab = gamedata->GetCreature(resource);
2502 if (!ab) {
2503 return NULL;
2506 if (Owner && Owner->Type==ST_ACTOR) {
2507 ab->LastSummoner = ((Actor *) Owner)->GetID();
2509 //Always use Base stats for the recently summoned creature
2511 int enemyally;
2513 if (eamod==EAM_SOURCEALLY || eamod==EAM_SOURCEENEMY) {
2514 if (Owner && Owner->Type==ST_ACTOR) {
2515 enemyally = ((Actor *) Owner)->GetStat(IE_EA)>EA_GOODCUTOFF;
2516 } else {
2517 enemyally = true;
2519 } else {
2520 if (target) {
2521 enemyally = target->GetBase(IE_EA)>EA_GOODCUTOFF;
2522 } else {
2523 enemyally = true;
2527 switch (eamod) {
2528 case EAM_SOURCEALLY:
2529 case EAM_ALLY:
2530 if (enemyally) {
2531 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2532 } else {
2533 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2535 break;
2536 case EAM_SOURCEENEMY:
2537 case EAM_ENEMY:
2538 if (enemyally) {
2539 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2540 } else {
2541 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2543 break;
2544 case EAM_NEUTRAL:
2545 ab->SetBase(IE_EA, EA_NEUTRAL);
2546 break;
2547 default:
2548 break;
2551 // mark the summon, but only if they don't have a special sex already
2552 if (sexmod && ab->BaseStats[IE_SEX] < SEX_EXTRA) {
2553 ab->SetBase(IE_SEX, SEX_SUMMON);
2556 Map *map;
2557 if (target) {
2558 map = target->GetCurrentArea();
2559 } else {
2560 map = Owner->GetCurrentArea();
2562 map->AddActor(ab);
2563 ab->SetPosition(position, true, 0);
2564 ab->RefreshEffects(NULL);
2566 if (vvcres[0]) {
2567 ScriptedAnimation* vvc = gamedata->GetScriptedAnimation(vvcres, false);
2568 if (vvc) {
2569 //This is the final position of the summoned creature
2570 //not the original target point
2571 vvc->XPos=ab->Pos.x;
2572 vvc->YPos=ab->Pos.y;
2573 //force vvc to play only once
2574 vvc->PlayOnce();
2575 map->AddVVCell( vvc );
2579 //remove the xp value of friendly summons
2580 if (ab->BaseStats[IE_EA]<EA_GOODCUTOFF) {
2581 ab->SetBase(IE_XPVALUE, 0);
2583 if (fx) {
2584 ApplyEffect(fx, ab, Owner);
2587 //this check should happen after the fact
2588 level -= ab->GetBase(IE_XP);
2589 if(level<0) {
2590 break;
2594 return ab;
2597 void Interface::RedrawControls(const char *varname, unsigned int value)
2599 for (unsigned int i = 0; i < windows.size(); i++) {
2600 Window *win = windows[i];
2601 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2602 win->RedrawControls(varname, value);
2607 void Interface::RedrawAll()
2609 for (unsigned int i = 0; i < windows.size(); i++) {
2610 Window *win = windows[i];
2611 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2612 win->Invalidate();
2617 /** Loads a WindowPack (CHUI file) in the Window Manager */
2618 bool Interface::LoadWindowPack(const char* name)
2620 DataStream* stream = gamedata->GetResource( name, IE_CHU_CLASS_ID );
2621 if (stream == NULL) {
2622 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED );
2623 printf( "%s.chu\n", name );
2624 return false;
2626 if (!GetWindowMgr()->Open( stream, true )) {
2627 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED );
2628 printf( "%s.chu\n", name );
2629 return false;
2632 strncpy( WindowPack, name, sizeof( WindowPack ) );
2633 WindowPack[sizeof( WindowPack ) - 1] = '\0';
2635 return true;
2638 /** Loads a Window in the Window Manager */
2639 int Interface::LoadWindow(unsigned short WindowID)
2641 unsigned int i;
2643 for (i = 0; i < windows.size(); i++) {
2644 Window *win = windows[i];
2645 if (win == NULL)
2646 continue;
2647 if (win->Visible==WINDOW_INVALID) {
2648 continue;
2650 if (win->WindowID == WindowID &&
2651 !strnicmp( WindowPack, win->WindowPack, sizeof(WindowPack) )) {
2652 SetOnTop( i );
2653 win->Invalidate();
2654 return i;
2657 Window* win = windowmgr->GetWindow( WindowID );
2658 if (win == NULL) {
2659 return -1;
2661 memcpy( win->WindowPack, WindowPack, sizeof(WindowPack) );
2663 int slot = -1;
2664 for (i = 0; i < windows.size(); i++) {
2665 if (windows[i] == NULL) {
2666 slot = i;
2667 break;
2670 if (slot == -1) {
2671 windows.push_back( win );
2672 slot = ( int ) windows.size() - 1;
2673 } else {
2674 windows[slot] = win;
2676 win->Invalidate();
2677 return slot;
2679 // FIXME: it's a clone of LoadWindow
2680 /** Creates a Window in the Window Manager */
2681 int Interface::CreateWindow(unsigned short WindowID, int XPos, int YPos, unsigned int Width, unsigned int Height, char* Background)
2683 unsigned int i;
2685 for (i = 0; i < windows.size(); i++) {
2686 if (windows[i] == NULL)
2687 continue;
2688 if (windows[i]->WindowID == WindowID && !stricmp( WindowPack,
2689 windows[i]->WindowPack )) {
2690 SetOnTop( i );
2691 windows[i]->Invalidate();
2692 return i;
2696 Window* win = new Window( WindowID, (ieWord) XPos, (ieWord) YPos, (ieWord) Width, (ieWord) Height );
2697 if (Background[0]) {
2698 if (IsAvailable( IE_MOS_CLASS_ID )) {
2699 ImageMgr* mos = ( ImageMgr* )
2700 gamedata->GetResource( Background, &ImageMgr::ID );
2701 if (mos != NULL) {
2702 win->SetBackGround( mos->GetSprite2D(), true );
2703 mos->release();
2704 } else
2705 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2706 } else
2707 printf( "[Core]: No MOS Importer Available, skipping background\n" );
2710 strcpy( win->WindowPack, WindowPack );
2712 int slot = -1;
2713 for (i = 0; i < windows.size(); i++) {
2714 if (windows[i] == NULL) {
2715 slot = i;
2716 break;
2719 if (slot == -1) {
2720 windows.push_back( win );
2721 slot = ( int ) windows.size() - 1;
2722 } else {
2723 windows[slot] = win;
2725 win->Invalidate();
2726 return slot;
2729 /** Sets a Window on the Top */
2730 void Interface::SetOnTop(int Index)
2732 std::vector<int>::iterator t;
2733 for(t = topwin.begin(); t != topwin.end(); ++t) {
2734 if((*t) == Index) {
2735 topwin.erase(t);
2736 break;
2739 if(topwin.size() != 0)
2740 topwin.insert(topwin.begin(), Index);
2741 else
2742 topwin.push_back(Index);
2744 /** Add a window to the Window List */
2745 void Interface::AddWindow(Window * win)
2747 int slot = -1;
2748 for(unsigned int i = 0; i < windows.size(); i++) {
2749 Window *w = windows[i];
2751 if(w==NULL) {
2752 slot = i;
2753 break;
2756 if(slot == -1) {
2757 windows.push_back(win);
2758 slot=(int)windows.size()-1;
2760 else
2761 windows[slot] = win;
2762 win->Invalidate();
2765 /** Get a Control on a Window */
2766 int Interface::GetControl(unsigned short WindowIndex, unsigned long ControlID) const
2768 if (WindowIndex >= windows.size()) {
2769 return -1;
2771 Window* win = windows[WindowIndex];
2772 if (win == NULL) {
2773 return -1;
2775 int i = 0;
2776 while (true) {
2777 Control* ctrl = win->GetControl( (unsigned short) i );
2778 if (ctrl == NULL)
2779 return -1;
2780 if (ctrl->ControlID == ControlID)
2781 return i;
2782 i++;
2785 /** Adjust the Scrolling factor of a control (worldmap atm) */
2786 int Interface::AdjustScrolling(unsigned short WindowIndex,
2787 unsigned short ControlIndex, short x, short y)
2789 if (WindowIndex >= windows.size()) {
2790 return -1;
2792 Window* win = windows[WindowIndex];
2793 if (win == NULL) {
2794 return -1;
2796 Control* ctrl = win->GetControl( ControlIndex );
2797 if (ctrl == NULL) {
2798 return -1;
2800 switch(ctrl->ControlType) {
2801 case IE_GUI_WORLDMAP:
2802 ((WorldMapControl *) ctrl)->AdjustScrolling(x,y);
2803 break;
2804 default: //doesn't work for these
2805 return -1;
2807 return 0;
2810 /** Set the Text of a Control */
2811 int Interface::SetText(unsigned short WindowIndex,
2812 unsigned short ControlIndex, const char* string)
2814 if (WindowIndex >= windows.size()) {
2815 return -1;
2817 Window* win = windows[WindowIndex];
2818 if (win == NULL) {
2819 return -1;
2821 Control* ctrl = win->GetControl( ControlIndex );
2822 if (ctrl == NULL) {
2823 return -1;
2825 return ctrl->SetText( string );
2827 /** Set the Tooltip text of a Control */
2828 int Interface::SetTooltip(unsigned short WindowIndex,
2829 unsigned short ControlIndex, const char* string)
2831 if (WindowIndex >= windows.size()) {
2832 return -1;
2834 Window* win = windows[WindowIndex];
2835 if (win == NULL) {
2836 return -1;
2838 Control* ctrl = win->GetControl( ControlIndex );
2839 if (ctrl == NULL) {
2840 return -1;
2842 return ctrl->SetTooltip( string );
2845 void Interface::DisplayTooltip(int x, int y, Control *ctrl)
2847 if (tooltip_ctrl && tooltip_ctrl == ctrl && tooltip_x == x && tooltip_y == y)
2848 return;
2849 tooltip_x = x;
2850 tooltip_y = y;
2851 tooltip_currtextw = 0;
2852 tooltip_ctrl = ctrl;
2855 int Interface::GetVisible(unsigned short WindowIndex) const
2857 if (WindowIndex >= windows.size()) {
2858 return -1;
2860 Window* win = windows[WindowIndex];
2861 if (win == NULL) {
2862 return -1;
2864 return win->Visible;
2866 /** Set a Window Visible Flag */
2867 int Interface::SetVisible(unsigned short WindowIndex, int visible)
2869 if (WindowIndex >= windows.size()) {
2870 return -1;
2872 Window* win = windows[WindowIndex];
2873 if (win == NULL) {
2874 return -1;
2876 if (visible!=WINDOW_FRONT) {
2877 win->Visible = (char) visible;
2879 switch (visible) {
2880 case WINDOW_GRAYED:
2881 win->Invalidate();
2882 //here is a fallthrough
2883 case WINDOW_INVISIBLE:
2884 //hiding the viewport if the gamecontrol window was made invisible
2885 if (win->WindowID==65535) {
2886 video->SetViewport( 0,0,0,0 );
2888 evntmgr->DelWindow( win );
2889 break;
2891 case WINDOW_VISIBLE:
2892 if (win->WindowID==65535) {
2893 video->SetViewport( win->XPos, win->YPos, win->Width, win->Height);
2895 //here is a fallthrough
2896 case WINDOW_FRONT:
2897 if (win->Visible==WINDOW_VISIBLE) {
2898 evntmgr->AddWindow( win );
2900 win->Invalidate();
2901 SetOnTop( WindowIndex );
2902 break;
2904 return 0;
2908 /** Set the Status of a Control in a Window */
2909 int Interface::SetControlStatus(unsigned short WindowIndex,
2910 unsigned short ControlIndex, unsigned long Status)
2912 //don't set the status of an already invalidated window
2913 Window* win = GetWindow(WindowIndex);
2914 if (win == NULL) {
2915 return -1;
2917 Control* ctrl = win->GetControl( ControlIndex );
2918 if (ctrl == NULL) {
2919 return -1;
2921 if (Status&IE_GUI_CONTROL_FOCUSED) {
2922 evntmgr->SetFocused( win, ctrl);
2924 if (ctrl->ControlType != ((Status >> 24) & 0xff) ) {
2925 return -2;
2927 switch (ctrl->ControlType) {
2928 case IE_GUI_BUTTON:
2929 //Button
2931 Button* btn = ( Button* ) ctrl;
2932 btn->SetState( ( unsigned char ) ( Status & 0x7f ) );
2934 break;
2935 default:
2936 ctrl->Value = Status & 0x7f;
2937 break;
2939 return 0;
2942 /** Show a Window in Modal Mode */
2943 int Interface::ShowModal(unsigned short WindowIndex, int Shadow)
2945 if (WindowIndex >= windows.size()) {
2946 printMessage( "Core", "Window not found", LIGHT_RED );
2947 return -1;
2949 Window* win = windows[WindowIndex];
2950 if (win == NULL) {
2951 printMessage( "Core", "Window already freed", LIGHT_RED );
2952 return -1;
2954 win->Visible = WINDOW_FRONT;
2955 //don't destroy the other window handlers
2956 //evntmgr->Clear();
2957 SetOnTop( WindowIndex );
2958 evntmgr->AddWindow( win );
2959 evntmgr->SetFocused( win, NULL );
2961 ModalWindow = NULL;
2962 DrawWindows();
2963 win->Invalidate();
2965 Color gray = {
2966 0, 0, 0, 128
2968 Color black = {
2969 0, 0, 0, 255
2972 Region r( 0, 0, Width, Height );
2974 if (Shadow == MODAL_SHADOW_GRAY) {
2975 video->DrawRect( r, gray );
2976 } else if (Shadow == MODAL_SHADOW_BLACK) {
2977 video->DrawRect( r, black );
2980 ModalWindow = win;
2981 return 0;
2984 bool Interface::IsFreezed()
2986 return !update_scripts;
2989 void Interface::GameLoop(void)
2991 update_scripts = false;
2992 GameControl *gc = GetGameControl();
2993 if (gc) {
2994 update_scripts = !(gc->GetDialogueFlags() & DF_FREEZE_SCRIPTS);
2997 GSUpdate(update_scripts);
2999 //i'm not sure if this should be here
3001 //in multi player (if we ever get to it), only the server must call this
3002 if (update_scripts) {
3003 if ( game->selected.size() > 0 ) {
3004 gc->ChangeMap(core->GetFirstSelectedPC(true), false);
3006 // the game object will run the area scripts as well
3007 game->UpdateScripts();
3011 /** handles hardcoded gui behaviour */
3012 void Interface::HandleGUIBehaviour(void)
3014 GameControl *gc = GetGameControl();
3015 if (gc) {
3016 //this variable is used all over in the following hacks
3017 int flg = gc->GetDialogueFlags();
3019 //the following part is a series of hardcoded gui behaviour
3021 //initiating dialog
3022 if (flg & DF_IN_DIALOG) {
3023 // -3 noaction
3024 // -2 close
3025 // -1 open
3026 // choose option
3027 ieDword var = (ieDword) -3;
3028 vars->Lookup("DialogChoose", var);
3029 if ((int) var == -2) {
3030 gc->EndDialog();
3031 } else if ( (int)var !=-3) {
3032 gc->DialogChoose(var);
3033 if (!(gc->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW | DF_OPENENDWINDOW)))
3034 guiscript->RunFunction( "NextDialogState" );
3036 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3037 ieDword newvar = 0; vars->Lookup("DialogChoose", newvar);
3038 if (var == (ieDword) -1 || newvar != (ieDword) -1) {
3039 vars->SetAt("DialogChoose", (ieDword) -3);
3042 if (flg & DF_OPENCONTINUEWINDOW) {
3043 guiscript->RunFunction( "OpenContinueMessageWindow" );
3044 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3045 } else if (flg & DF_OPENENDWINDOW) {
3046 guiscript->RunFunction( "OpenEndMessageWindow" );
3047 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3051 //handling container
3052 if (CurrentContainer && UseContainer) {
3053 if (!(flg & DF_IN_CONTAINER) ) {
3054 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_OR);
3055 guiscript->RunFunction( "OpenContainerWindow" );
3057 } else {
3058 if (flg & DF_IN_CONTAINER) {
3059 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_NAND);
3060 guiscript->RunFunction( "CloseContainerWindow" );
3063 //end of gui hacks
3067 void Interface::DrawWindows(void)
3069 //here comes the REAL drawing of windows
3070 if (ModalWindow) {
3071 ModalWindow->DrawWindow();
3072 return;
3074 size_t i = topwin.size();
3075 while(i--) {
3076 unsigned int t = topwin[i];
3078 if ( t >=windows.size() )
3079 continue;
3081 //visible ==1 or 2 will be drawn
3082 Window* win = windows[t];
3083 if (win != NULL) {
3084 if (win->Visible == WINDOW_INVALID) {
3085 topwin.erase(topwin.begin()+i);
3086 evntmgr->DelWindow( win );
3087 delete win;
3088 windows[t]=NULL;
3089 } else if (win->Visible) {
3090 win->DrawWindow();
3096 void Interface::DrawTooltip ()
3098 if (! tooltip_ctrl || !tooltip_ctrl->Tooltip)
3099 return;
3101 Font* fnt = GetFont( TooltipFont );
3102 char *tooltip_text = tooltip_ctrl->Tooltip;
3104 int w1 = 0;
3105 int w2 = 0;
3106 int strw = fnt->CalcStringWidth( tooltip_text ) + 8;
3107 int w = strw;
3108 int h = fnt->maxHeight;
3110 if (TooltipBack) {
3111 // animate BG tooltips
3112 // TODO: make tooltip animation an option instead
3113 // of following hard-coded check!
3114 if (TooltipMargin == 5) {
3115 // TODO: make speed an option
3116 int tooltip_anim_speed = 15;
3117 if (tooltip_currtextw < strw) {
3118 tooltip_currtextw += tooltip_anim_speed;
3120 if (tooltip_currtextw > strw) {
3121 tooltip_currtextw = strw;
3123 w = tooltip_currtextw;
3126 h = TooltipBack[0]->Height;
3127 w1 = TooltipBack[1]->Width;
3128 w2 = TooltipBack[2]->Width;
3129 w += TooltipMargin*2;
3130 strw += TooltipMargin*2;
3131 //multiline in case of too much text
3132 if (w>TooltipBack[0]->Width)
3133 strw=w=TooltipBack[0]->Width;
3134 else if (strw>TooltipBack[0]->Width)
3135 strw=TooltipBack[0]->Width;
3138 int strx = tooltip_x - strw / 2;
3139 int y = tooltip_y - h / 2;
3140 // Ensure placement within the screen
3141 if (strx < 0) strx = 0;
3142 else if (strx + strw + w1 + w2 > Width)
3143 strx = Width - strw - w1 - w2;
3144 if (y < 0) y = 0;
3145 else if (y + h > Height)
3146 y = Height - h;
3148 int x = strx + ((strw - w) / 2);
3150 // FIXME: take back[0] from center, not from left end
3151 Region r2 = Region( x, y, w, h );
3152 if (TooltipBack) {
3153 video->BlitSprite( TooltipBack[0], x + TooltipMargin, y, true, &r2 );
3154 video->BlitSprite( TooltipBack[1], x, y, true );
3155 video->BlitSprite( TooltipBack[2], x + w, y, true );
3158 if (TooltipBack) {
3159 r2.x+=TooltipMargin;
3160 strx+=TooltipMargin;
3162 Region textr = Region( strx, y, strw, h );
3163 fnt->Print( r2, textr, (ieByte *) tooltip_text, NULL,
3164 IE_FONT_ALIGN_CENTER | IE_FONT_ALIGN_MIDDLE, true );
3167 //interface for higher level functions, if the window was
3168 //marked for deletion it is not returned
3169 Window* Interface::GetWindow(unsigned short WindowIndex) const
3171 if (WindowIndex < windows.size()) {
3172 Window *win = windows[WindowIndex];
3173 if (win && (win->Visible!=WINDOW_INVALID) ) {
3174 return win;
3177 return NULL;
3180 // this function will determine if wnd is a valid window pointer
3181 // by checking if its WindowID is the same as the reference
3182 bool Interface::IsValidWindow(unsigned short WindowID, Window *wnd) const
3184 size_t WindowIndex = windows.size();
3185 while (WindowIndex--) {
3186 if (windows[WindowIndex] == wnd) {
3187 return wnd->WindowID == WindowID;
3190 return false;
3193 //this function won't delete the window, just mark it for deletion
3194 //it will be deleted in the next DrawWindows cycle
3195 //regardless, the window deleted is inaccessible for gui scripts and
3196 //other high level functions from now
3197 int Interface::DelWindow(unsigned short WindowIndex)
3199 if (WindowIndex >= windows.size()) {
3200 return -1;
3202 Window* win = windows[WindowIndex];
3203 if ((win == NULL) || (win->Visible==WINDOW_INVALID) ) {
3204 printMessage( "Core", "Window deleted again", LIGHT_RED );
3205 return -1;
3207 if (win == ModalWindow) {
3208 ModalWindow = NULL;
3209 RedrawAll(); //marking windows for redraw
3211 evntmgr->DelWindow( win );
3212 win->release();
3213 //re-capturing new (old) modal window if any
3214 size_t tw = topwin.size();
3215 for(size_t i=0;i<tw;i++) {
3216 Window *tmp = windows[topwin[i]];
3217 if (tmp->Visible==WINDOW_FRONT) {
3218 ModalWindow = tmp;
3219 break;
3222 return 0;
3225 void Interface::DelAllWindows()
3227 vars->SetAt("MessageWindow", (ieDword) ~0);
3228 vars->SetAt("OptionsWindow", (ieDword) ~0);
3229 vars->SetAt("PortraitWindow", (ieDword) ~0);
3230 vars->SetAt("ActionsWindow", (ieDword) ~0);
3231 vars->SetAt("TopWindow", (ieDword) ~0);
3232 vars->SetAt("OtherWindow", (ieDword) ~0);
3233 vars->SetAt("FloatWindow", (ieDword) ~0);
3234 for(unsigned int WindowIndex=0; WindowIndex<windows.size();WindowIndex++) {
3235 Window* win = windows[WindowIndex];
3236 delete win;
3238 windows.clear();
3239 topwin.clear();
3240 evntmgr->Clear();
3241 ModalWindow = NULL;
3244 /** Popup the Console */
3245 void Interface::PopupConsole()
3247 ConsolePopped = !ConsolePopped;
3248 RedrawAll();
3249 console->Changed = true;
3252 /** Draws the Console */
3253 void Interface::DrawConsole()
3255 console->Draw( 0, 0 );
3258 /** Get the Sound Manager */
3259 SaveGameIterator* Interface::GetSaveGameIterator() const
3261 return sgiterator;
3263 /** Sends a termination signal to the Video Driver */
3264 bool Interface::Quit(void)
3266 return video->Quit();
3268 /** Returns the variables dictionary */
3269 Variables* Interface::GetDictionary() const
3271 return vars;
3273 /** Returns the token dictionary */
3274 Variables* Interface::GetTokenDictionary() const
3276 return tokens;
3278 /** Get the Music Manager */
3279 MusicMgr* Interface::GetMusicMgr() const
3281 return music;
3283 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3284 int Interface::LoadSymbol(const char* ResRef)
3286 int ind = GetSymbolIndex( ResRef );
3287 if (ind != -1) {
3288 return ind;
3290 DataStream* str = gamedata->GetResource( ResRef, IE_IDS_CLASS_ID );
3291 if (!str) {
3292 return -1;
3294 SymbolMgr* sm = ( SymbolMgr* ) GetInterface( IE_IDS_CLASS_ID );
3295 if (!sm) {
3296 delete str;
3297 return -1;
3299 if (!sm->Open( str, true )) {
3300 sm->release();
3301 return -1;
3303 Symbol s;
3304 s.free = false;
3305 strncpy( s.ResRef, ResRef, 8 );
3306 s.sm = sm;
3307 ind = -1;
3308 for (size_t i = 0; i < symbols.size(); i++) {
3309 if (symbols[i].free) {
3310 ind = ( int ) i;
3311 break;
3314 if (ind != -1) {
3315 symbols[ind] = s;
3316 return ind;
3318 symbols.push_back( s );
3319 return ( int ) symbols.size() - 1;
3321 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3322 int Interface::GetSymbolIndex(const char* ResRef) const
3324 for (size_t i = 0; i < symbols.size(); i++) {
3325 if (symbols[i].free)
3326 continue;
3327 if (strnicmp( symbols[i].ResRef, ResRef, 8 ) == 0)
3328 return ( int ) i;
3330 return -1;
3332 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3333 SymbolMgr* Interface::GetSymbol(unsigned int index) const
3335 if (index >= symbols.size()) {
3336 return NULL;
3338 if (symbols[index].free) {
3339 return NULL;
3341 return symbols[index].sm;
3343 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3344 bool Interface::DelSymbol(unsigned int index)
3346 if (index >= symbols.size()) {
3347 return false;
3349 if (symbols[index].free) {
3350 return false;
3352 if (symbols[index].sm)
3353 symbols[index].sm->release();
3354 symbols[index].free = true;
3355 return true;
3357 /** Plays a Movie */
3358 int Interface::PlayMovie(const char* ResRef)
3360 MoviePlayer* mp = (MoviePlayer*) gamedata->GetResource( ResRef, &MoviePlayer::ID );
3361 if (!mp) {
3362 return -1;
3365 ieDword subtitles = 0;
3366 Font *SubtitleFont = NULL;
3367 Palette *palette = NULL;
3368 ieDword *frames = NULL;
3369 ieDword *strrefs = NULL;
3370 int cnt = 0;
3371 int offset = 0;
3373 //one of these two should exist (they both mean the same thing)
3374 vars->Lookup("Display Movie Subtitles", subtitles);
3375 if (subtitles) {
3376 //HoW flag
3377 cnt=-3;
3378 offset = 3;
3379 } else {
3380 //ToB flag
3381 vars->Lookup("Display Subtitles", subtitles);
3383 AutoTable sttable;
3384 if (subtitles && sttable.load(ResRef)) {
3385 cnt += sttable->GetRowCount();
3386 if (cnt>0) {
3387 frames = (ieDword *) malloc(cnt * sizeof(ieDword) );
3388 strrefs = (ieDword *) malloc(cnt * sizeof(ieDword) );
3389 } else {
3390 cnt = 0;
3392 if (frames && strrefs) {
3393 for (int i=0;i<cnt;i++) {
3394 frames[i] = atoi (sttable->QueryField(i+offset, 0) );
3395 strrefs[i] = atoi (sttable->QueryField(i+offset, 1) );
3398 int r = atoi(sttable->QueryField("red", "frame"));
3399 int g = atoi(sttable->QueryField("green", "frame"));
3400 int b = atoi(sttable->QueryField("blue", "frame"));
3401 SubtitleFont = GetFont (MovieFont); //will change
3402 if (r || g || b) {
3403 if (SubtitleFont) {
3404 Color fore = {(unsigned char) r,(unsigned char) g,(unsigned char) b, 0x00};
3405 Color back = {0x00, 0x00, 0x00, 0x00};
3406 palette = CreatePalette( fore, back );
3411 //shutting down music and ambients before movie
3412 if (music)
3413 music->HardEnd();
3414 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3415 if (ambim) ambim->deactivate();
3416 video->SetMovieFont(SubtitleFont, palette );
3417 mp->CallBackAtFrames(cnt, frames, strrefs);
3418 mp->Play();
3419 mp->release();
3420 gamedata->FreePalette( palette );
3421 if (frames)
3422 free(frames);
3423 if (strrefs)
3424 free(strrefs);
3425 //restarting music
3426 if (music)
3427 music->Start();
3428 if (ambim) ambim->activate();
3429 //this will fix redraw all windows as they looked like
3430 //before the movie
3431 RedrawAll();
3433 //Setting the movie name to 1
3434 vars->SetAt( ResRef, 1 );
3435 return 0;
3438 int Interface::Roll(int dice, int size, int add) const
3440 if (dice < 1) {
3441 return add;
3443 if (size < 1) {
3444 return add;
3446 if (dice > 100) {
3447 return add + dice * size / 2;
3449 for (int i = 0; i < dice; i++) {
3450 add += rand() % size + 1;
3452 return add;
3455 static char bmp_suffix[6]="M.BMP";
3456 static char png_suffix[6]="M.PNG";
3458 int Interface::GetPortraits(TextArea* ta, bool smallorlarge)
3460 int count = 0;
3461 char Path[_MAX_PATH];
3463 if (smallorlarge) {
3464 bmp_suffix[0]='S';
3465 png_suffix[0]='S';
3466 } else {
3467 bmp_suffix[0]='M';
3468 png_suffix[0]='M';
3470 PathJoin( Path, GamePath, GamePortraitsPath, NULL );
3471 DIR* dir = opendir( Path );
3472 if (dir == NULL) {
3473 return -1;
3475 //Lookup the first entry in the Directory
3476 struct dirent* de = readdir( dir );
3477 if (de == NULL) {
3478 closedir( dir );
3479 return -1;
3481 printf( "Looking in %s\n", Path );
3482 do {
3483 if (de->d_name[0] == '.')
3484 continue;
3485 char dtmp[_MAX_PATH];
3486 PathJoin( dtmp, Path, de->d_name, NULL );
3487 struct stat fst;
3488 stat( dtmp, &fst );
3489 if ( S_ISDIR( fst.st_mode ))
3490 continue;
3491 strupr(de->d_name);
3492 char *pos = strstr(de->d_name,bmp_suffix);
3493 if (!pos && IsAvailable(IE_PNG_CLASS_ID) ) {
3494 pos = strstr(de->d_name,png_suffix);
3496 if (!pos) continue;
3497 pos[1]=0;
3498 count++;
3499 ta->AppendText( de->d_name, -1 );
3500 } while (( de = readdir( dir ) ) != NULL);
3501 closedir( dir );
3502 return count;
3505 int Interface::GetCharSounds(TextArea* ta)
3507 bool hasfolders;
3508 int count = 0;
3509 char Path[_MAX_PATH];
3511 PathJoin( Path, GamePath, GameSoundsPath, NULL );
3512 hasfolders = ( HasFeature( GF_SOUNDFOLDERS ) != 0 );
3513 DIR* dir = opendir( Path );
3514 if (dir == NULL) {
3515 return -1;
3517 //Lookup the first entry in the Directory
3518 struct dirent* de = readdir( dir );
3519 if (de == NULL) {
3520 closedir( dir );
3521 return -1;
3523 printf( "Looking in %s\n", Path );
3524 do {
3525 if (de->d_name[0] == '.')
3526 continue;
3527 char dtmp[_MAX_PATH];
3528 PathJoin( dtmp, Path, de->d_name, NULL );
3529 struct stat fst;
3530 stat( dtmp, &fst );
3531 if (hasfolders == !S_ISDIR( fst.st_mode ))
3532 continue;
3533 if (!hasfolders) {
3534 strupr(de->d_name);
3535 char *pos = strstr(de->d_name,"A.WAV");
3536 if (!pos) continue;
3537 *pos=0;
3539 count++;
3540 ta->AppendText( de->d_name, -1 );
3541 } while (( de = readdir( dir ) ) != NULL);
3542 closedir( dir );
3543 return count;
3546 int Interface::GetCharacters(TextArea* ta)
3548 int count = 0;
3549 char Path[_MAX_PATH];
3551 PathJoin( Path, GamePath, GameCharactersPath, NULL );
3552 DIR* dir = opendir( Path );
3553 if (dir == NULL) {
3554 return -1;
3556 //Lookup the first entry in the Directory
3557 struct dirent* de = readdir( dir );
3558 if (de == NULL) {
3559 closedir( dir );
3560 return -1;
3562 printf( "Looking in %s\n", Path );
3563 do {
3564 if (de->d_name[0] == '.')
3565 continue;
3566 char dtmp[_MAX_PATH];
3567 PathJoin( dtmp, Path, de->d_name, NULL );
3568 struct stat fst;
3569 stat( dtmp, &fst );
3570 strupr(de->d_name);
3571 char *pos = strstr(de->d_name,".CHR");
3572 if (!pos) continue;
3573 *pos=0;
3574 count++;
3575 ta->AppendText( de->d_name, -1 );
3576 } while (( de = readdir( dir ) ) != NULL);
3577 closedir( dir );
3578 return count;
3581 bool Interface::LoadINI(const char* filename)
3583 FILE* config;
3584 config = fopen( filename, "rb" );
3585 if (config == NULL) {
3586 return false;
3588 char name[65], value[_MAX_PATH + 3];
3589 while (!feof( config )) {
3590 name[0] = 0;
3591 value[0] = 0;
3592 char rem;
3594 if (fread( &rem, 1, 1, config ) != 1)
3595 break;
3597 if (( rem == '#' ) ||
3598 ( rem == '[' ) ||
3599 ( rem == '\r' ) ||
3600 ( rem == '\n' ) ||
3601 ( rem == ';' )) {
3602 if (rem == '\r') {
3603 fgetc( config );
3604 continue;
3605 } else if (rem == '\n')
3606 continue;
3608 //it should always return zero
3609 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
3610 break;
3611 continue;
3613 fseek( config, -1, SEEK_CUR );
3614 //the * element is not counted
3615 if (fscanf( config, "%[^=]=%[^\r\n]%*[\r\n]", name, value )!=2)
3616 continue;
3617 if (( value[0] >= '0' ) && ( value[0] <= '9' )) {
3618 vars->SetAt( name, atoi( value ) );
3621 fclose( config );
3622 return true;
3625 /** Enables/Disables the Cut Scene Mode */
3626 void Interface::SetCutSceneMode(bool active)
3628 GameControl *gc = GetGameControl();
3629 if (gc) {
3630 gc->SetCutSceneMode( active );
3632 if (game) {
3633 if (active) {
3634 game->ControlStatus |= CS_HIDEGUI;
3635 } else {
3636 game->ControlStatus &= ~CS_HIDEGUI;
3638 SetEventFlag(EF_CONTROL);
3640 video->SetMouseEnabled(!active);
3643 bool Interface::InCutSceneMode() const
3645 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE)!=0;
3648 void Interface::QuitGame(int BackToMain)
3650 SetCutSceneMode(false);
3651 if (timer) {
3652 //clear cutscenes
3653 //clear fade/screenshake effects
3654 timer->Init();
3655 timer->SetFadeFromColor(0);
3658 DelAllWindows(); //delete all windows, including GameControl
3660 //shutting down ingame music
3661 //(do it before deleting the game)
3662 if (music) {
3663 music->HardEnd();
3665 // stop any ambients which are still enqueued
3666 if (AudioDriver) {
3667 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3668 if (ambim) ambim->deactivate();
3670 //delete game, worldmap
3671 if (game) {
3672 delete game;
3673 game=NULL;
3675 if (worldmap) {
3676 delete worldmap;
3677 worldmap=NULL;
3679 if (BackToMain) {
3680 strcpy(NextScript, "Start");
3681 QuitFlag |= QF_CHANGESCRIPT;
3683 GSUpdate(true);
3686 void Interface::SetupLoadGame(int index, int ver_override)
3688 LoadGameIndex = index;
3689 VersionOverride = ver_override;
3690 QuitFlag |= QF_LOADGAME;
3693 void Interface::LoadGame(int index, int ver_override)
3695 // This function has rather painful error handling,
3696 // as it should swap all the objects or none at all
3697 // and the loading can fail for various reasons
3699 // Yes, it uses goto. Other ways seemed too awkward for me.
3701 strings->CloseAux();
3702 tokens->RemoveAll(NULL); //clearing the token dictionary
3704 if(calendar) delete calendar;
3705 calendar = new Calendar;
3707 DataStream* gam_str = NULL;
3708 DataStream* sav_str = NULL;
3709 DataStream* wmp_str = NULL;
3711 SaveGameMgr* gam_mgr = NULL;
3712 WorldMapMgr* wmp_mgr = NULL;
3714 Game* new_game = NULL;
3715 WorldMapArray* new_worldmap = NULL;
3717 LoadProgress(15);
3718 if (!KeepCache) DelTree((const char *) CachePath, true);
3719 LoadProgress(20);
3721 if (index == -1) {
3722 //Load the Default Game
3723 gam_str = gamedata->GetResource( GameNameResRef, IE_GAM_CLASS_ID );
3724 sav_str = NULL;
3725 wmp_str = gamedata->GetResource( WorldMapName, IE_WMP_CLASS_ID );
3726 } else {
3727 SaveGame* sg = sgiterator->GetSaveGame( index );
3728 if (!sg)
3729 return;
3730 gam_str = sg->GetGame();
3731 sav_str = sg->GetSave();
3732 wmp_str = sg->GetWmap();
3733 delete sg;
3736 if (!gam_str || !wmp_str)
3737 goto cleanup;
3739 // Load GAM file
3740 gam_mgr = ( SaveGameMgr* ) GetInterface( IE_GAM_CLASS_ID );
3741 if (!gam_mgr)
3742 goto cleanup;
3744 if (!gam_mgr->Open( gam_str, true ))
3745 goto cleanup;
3747 new_game = gam_mgr->LoadGame(new Game(), ver_override);
3748 if (!new_game)
3749 goto cleanup;
3751 gam_mgr->release();
3752 gam_mgr = NULL;
3753 gam_str = NULL;
3755 // Load WMP (WorldMap) file
3756 wmp_mgr = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
3757 if (! wmp_mgr)
3758 goto cleanup;
3760 if (!wmp_mgr->Open( wmp_str, true ))
3761 goto cleanup;
3763 new_worldmap = wmp_mgr->GetWorldMapArray( );
3765 wmp_mgr->release();
3766 wmp_mgr = NULL;
3767 wmp_str = NULL;
3769 LoadProgress(30);
3770 // Unpack SAV (archive) file to Cache dir
3771 if (sav_str) {
3772 ArchiveImporter * ai = (ArchiveImporter*)GetInterface(IE_BIF_CLASS_ID);
3773 if (ai) {
3774 if (ai->DecompressSaveGame(sav_str) != GEM_OK) {
3775 ai->release();
3776 goto cleanup;
3778 ai->release();
3780 delete sav_str;
3781 sav_str = NULL;
3784 // Let's assume that now is everything loaded OK and swap the objects
3786 delete game;
3787 delete worldmap;
3789 game = new_game;
3790 worldmap = new_worldmap;
3792 strings->OpenAux();
3793 LoadProgress(100);
3794 return;
3795 cleanup:
3796 // Something went wrong, so try to clean after itself
3798 delete new_game;
3799 delete new_worldmap;
3801 if (gam_mgr) {
3802 gam_mgr->release();
3803 gam_str = NULL;
3805 if (wmp_mgr) {
3806 wmp_mgr->release();
3807 wmp_str = NULL;
3810 delete gam_str;
3811 delete wmp_str;
3812 delete sav_str;
3815 /* swapping out old resources */
3816 void Interface::UpdateMasterScript()
3818 if (game) {
3819 game->SetScript( GlobalScript, 0 );
3822 WorldMapMgr* wmp_mgr = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
3823 if (! wmp_mgr)
3824 return;
3826 if (worldmap) {
3827 DataStream *wmp_str = gamedata->GetResource( WorldMapName, IE_WMP_CLASS_ID );
3829 if (!wmp_mgr->Open( wmp_str, true )) {
3830 delete wmp_str;
3831 goto cleanup;
3834 delete worldmap;
3835 worldmap = wmp_mgr->GetWorldMapArray();
3838 cleanup:
3839 // Something went wrong, so try to clean after itself
3840 wmp_mgr->release();
3843 GameControl *Interface::GetGameControl() const
3845 Window *window = GetWindow( 0 );
3846 // in the beginning, there's no window at all
3847 if (! window)
3848 return NULL;
3850 Control* gc = window->GetControl(0);
3851 if (gc->ControlType!=IE_GUI_GAMECONTROL) {
3852 return NULL;
3854 return (GameControl *) gc;
3857 bool Interface::InitItemTypes()
3859 if (slotmatrix) {
3860 free(slotmatrix);
3862 AutoTable it("itemtype");
3863 ItemTypes = 0;
3864 if (it) {
3865 ItemTypes = it->GetRowCount(); //number of itemtypes
3866 if (ItemTypes<0) {
3867 ItemTypes = 0;
3869 int InvSlotTypes = it->GetColumnCount();
3870 if (InvSlotTypes > 32) { //bit count limit
3871 InvSlotTypes = 32;
3873 //make sure unsigned int is 32 bits
3874 slotmatrix = (ieDword *) malloc(ItemTypes * sizeof(ieDword) );
3875 for (int i=0;i<ItemTypes;i++) {
3876 unsigned int value = 0;
3877 unsigned int k = 1;
3878 for (int j=0;j<InvSlotTypes;j++) {
3879 if (strtol(it->QueryField(i,j),NULL,0) ) {
3880 value |= k;
3882 k <<= 1;
3884 slotmatrix[i] = (ieDword) value;
3888 //slottype describes the inventory structure
3889 Inventory::Init(HasFeature(GF_MAGICBIT));
3890 AutoTable st("slottype");
3891 if (slottypes) {
3892 free(slottypes);
3893 slottypes = NULL;
3895 SlotTypes = 0;
3896 if (st) {
3897 SlotTypes = st->GetRowCount();
3898 //make sure unsigned int is 32 bits
3899 slottypes = (SlotType *) malloc(SlotTypes * sizeof(SlotType) );
3900 memset(slottypes, -1, SlotTypes * sizeof(SlotType) );
3901 for (unsigned int row = 0; row < SlotTypes; row++) {
3902 bool alias;
3903 unsigned int i = (ieDword) strtol(st->GetRowName(row),NULL,0 );
3904 if (i>=SlotTypes) continue;
3905 if (slottypes[i].sloteffects!=0xffffffffu) {
3906 slottypes[row].slot = i;
3907 i=row;
3908 alias = true;
3909 } else {
3910 slottypes[row].slot = i;
3911 alias = false;
3913 slottypes[i].slottype = (ieDword) strtol(st->QueryField(row,0),NULL,0 );
3914 slottypes[i].slotid = (ieDword) strtol(st->QueryField(row,1),NULL,0 );
3915 strnlwrcpy( slottypes[i].slotresref, st->QueryField(row,2), 8 );
3916 slottypes[i].slottip = (ieDword) strtol(st->QueryField(row,3),NULL,0 );
3917 //don't fill sloteffects for aliased slots (pst)
3918 if (alias) {
3919 continue;
3921 slottypes[i].sloteffects = (ieDword) strtol(st->QueryField(row,4),NULL,0 );
3922 //setting special slots
3923 if (slottypes[i].slottype&SLOT_ITEM) {
3924 if (slottypes[i].slottype&SLOT_INVENTORY) {
3925 Inventory::SetInventorySlot(i);
3926 } else {
3927 Inventory::SetQuickSlot(i);
3930 switch (slottypes[i].sloteffects) {
3931 //fist slot, not saved, default weapon
3932 case SLOT_EFFECT_FIST: Inventory::SetFistSlot(i); break;
3933 //magic weapon slot, overrides all weapons
3934 case SLOT_EFFECT_MAGIC: Inventory::SetMagicSlot(i); break;
3935 //weapon slot, Equipping marker is relative to it
3936 case SLOT_EFFECT_MELEE: Inventory::SetWeaponSlot(i); break;
3937 //ranged slot
3938 case SLOT_EFFECT_MISSILE: Inventory::SetRangedSlot(i); break;
3939 //right hand
3940 case SLOT_EFFECT_LEFT: Inventory::SetShieldSlot(i); break;
3941 //head (for averting critical hit)
3942 case SLOT_EFFECT_HEAD: Inventory::SetHeadSlot(i); break;
3943 default:;
3947 return (it && st);
3950 ieDword Interface::FindSlot(unsigned int idx) const
3952 ieDword i;
3954 for (i=0;i<SlotTypes;i++) {
3955 if (idx==slottypes[i].slot) {
3956 break;
3959 return i;
3962 ieDword Interface::QuerySlot(unsigned int idx) const
3964 if (idx>=SlotTypes) {
3965 return 0;
3967 return slottypes[idx].slot;
3970 ieDword Interface::QuerySlotType(unsigned int idx) const
3972 if (idx>=SlotTypes) {
3973 return 0;
3975 return slottypes[idx].slottype;
3978 ieDword Interface::QuerySlotID(unsigned int idx) const
3980 if (idx>=SlotTypes) {
3981 return 0;
3983 return slottypes[idx].slotid;
3986 ieDword Interface::QuerySlottip(unsigned int idx) const
3988 if (idx>=SlotTypes) {
3989 return 0;
3991 return slottypes[idx].slottip;
3994 ieDword Interface::QuerySlotEffects(unsigned int idx) const
3996 if (idx>=SlotTypes) {
3997 return 0;
3999 return slottypes[idx].sloteffects;
4002 const char *Interface::QuerySlotResRef(unsigned int idx) const
4004 if (idx>=SlotTypes) {
4005 return "";
4007 return slottypes[idx].slotresref;
4010 // checks the itemtype vs. slottype, and also checks the usability flags
4011 // vs. Actor's stats (alignment, class, race, kit etc.)
4012 int Interface::CanUseItemType(int slottype, Item *item, Actor *actor, bool feedback) const
4014 //inventory is a special case, we allow any items to enter it
4015 if ( slottype==SLOT_ALL ) {
4016 return SLOT_INVENTORY;
4018 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
4019 //with twohandedness
4020 if ((slottype&SLOT_SHIELD) && (slottype!=SLOT_ANY) ) {
4021 //As long as this is an Item, use the ITEM constant
4022 //switch for IE_INV_ITEM_* if it is a CREItem
4023 if (item->Flags&IE_ITEM_TWO_HANDED) {
4024 //cannot equip twohanded in offhand
4025 if (feedback) DisplayConstantString(STR_NOT_IN_OFFHAND, 0xf0f0f0);
4026 return 0;
4030 if ( (unsigned int) item->ItemType>=(unsigned int) ItemTypes) {
4031 //invalid itemtype
4032 if (feedback) DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4033 return 0;
4036 //if actor is supplied, check its usability fields
4037 if (actor) {
4038 ieStrRef str = actor->Unusable(item);
4039 if (str) {
4040 if (feedback) DisplayConstantString(str, 0xf0f0f0);
4041 return 0;
4045 //if any bit is true, the answer counts as true
4046 int ret = (slotmatrix[item->ItemType]&slottype);
4047 if (slottype == SLOT_INVENTORY || slottype == SLOT_ANY) {
4048 ret = 1;
4050 if (!ret) {
4051 if (feedback) DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4052 return 0;
4055 //this warning comes only when feedback is enabled
4056 if (feedback) {
4057 if (slotmatrix[item->ItemType]&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4058 ret = 0;
4059 if (slottype&SLOT_QUIVER) {
4060 if (item->GetWeaponHeader(true)) ret = 1;
4063 if (slottype&SLOT_WEAPON) {
4064 //melee
4065 if (item->GetWeaponHeader(false)) ret = 1;
4066 //ranged
4067 if (item->GetWeaponHeader(true)) ret = 1;
4070 if (slottype&SLOT_ITEM) {
4071 if (item->GetEquipmentHeaderNumber(0)!=0xffff) ret = 1;
4074 if (!ret) {
4075 DisplayConstantString(STR_UNUSABLEITEM, 0xf0f0f0);
4076 return 0;
4081 return ret;
4084 Label *Interface::GetMessageLabel() const
4086 ieDword WinIndex = (ieDword) -1;
4087 ieDword TAIndex = (ieDword) -1;
4089 vars->Lookup( "OtherWindow", WinIndex );
4090 if (( WinIndex != (ieDword) -1 ) &&
4091 ( vars->Lookup( "MessageLabel", TAIndex ) )) {
4092 Window* win = GetWindow( (unsigned short) WinIndex );
4093 if (win) {
4094 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4095 if (ctrl && ctrl->ControlType==IE_GUI_LABEL)
4096 return (Label *) ctrl;
4099 return NULL;
4102 TextArea *Interface::GetMessageTextArea() const
4104 ieDword WinIndex = (ieDword) -1;
4105 ieDword TAIndex = (ieDword) -1;
4107 vars->Lookup( "MessageWindow", WinIndex );
4108 if (( WinIndex != (ieDword) -1 ) &&
4109 ( vars->Lookup( "MessageTextArea", TAIndex ) )) {
4110 Window* win = GetWindow( (unsigned short) WinIndex );
4111 if (win) {
4112 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4113 if (ctrl && ctrl->ControlType==IE_GUI_TEXTAREA)
4114 return (TextArea *) ctrl;
4117 return NULL;
4120 void Interface::DisplayString(const char* Text, Scriptable *target) const
4122 Label *l = GetMessageLabel();
4123 if (l) {
4124 l->SetText(Text, 0);
4126 TextArea *ta = GetMessageTextArea();
4127 if (ta) {
4128 ta->AppendText( Text, -1 );
4129 } else {
4130 if(target) {
4131 char *tmp = strdup(Text);
4133 target->DisplayHeadText(tmp);
4138 #define PALSIZE 8
4139 static Color ActorColor[PALSIZE];
4140 static const char* DisplayFormatName = "[color=%lX]%s - [/color][p][color=%lX]%s[/color][/p]";
4141 static const char* DisplayFormatAction = "[color=%lX]%s - [/color][p][color=%lX]%s %s[/color][/p]";
4142 static const char* DisplayFormat = "[/color][p][color=%lX]%s[/color][/p]";
4143 static const char* DisplayFormatValue = "[/color][p][color=%lX]%s: %d[/color][/p]";
4144 static const char* DisplayFormatNameString = "[color=%lX]%s - [/color][p][color=%lX]%s: %s[/color][/p]";
4146 ieStrRef Interface::GetStringReference(int stridx) const
4148 return strref_table[stridx];
4152 unsigned int Interface::GetSpeakerColor(const char *&name, const Scriptable *&speaker) const
4154 unsigned int speaker_color;
4156 if(!speaker) return 0;
4157 switch (speaker->Type) {
4158 case ST_ACTOR:
4159 name = ((Actor *) speaker)->GetName(-1);
4160 GetPalette( ((Actor *) speaker)->GetStat(IE_MAJOR_COLOR) & 0xFF, PALSIZE, ActorColor );
4161 speaker_color = (ActorColor[4].r<<16) | (ActorColor[4].g<<8) | ActorColor[4].b;
4162 break;
4163 case ST_TRIGGER: case ST_PROXIMITY: case ST_TRAVEL:
4164 name = GetString( ((InfoPoint *) speaker)->DialogName );
4165 speaker_color = 0xc0c0c0;
4166 break;
4167 default:
4168 name = "";
4169 speaker_color = 0x800000;
4170 break;
4172 return speaker_color;
4176 //simply displaying a constant string
4177 void Interface::DisplayConstantString(int stridx, unsigned int color, Scriptable *target) const
4179 if (stridx<0) return;
4180 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4181 int newlen = (int)(strlen( DisplayFormat ) + strlen( text ) + 12);
4182 char* newstr = ( char* ) malloc( newlen );
4183 snprintf( newstr, newlen, DisplayFormat, color, text );
4184 FreeString( text );
4185 DisplayString( newstr, target);
4186 free( newstr );
4189 void Interface::DisplayString(int stridx, unsigned int color, ieDword flags) const
4191 if (stridx<0) return;
4192 char* text = GetString( stridx, flags);
4193 int newlen = (int)(strlen( DisplayFormat) + strlen( text ) + 10);
4194 char* newstr = ( char* ) malloc( newlen );
4195 snprintf( newstr, newlen, DisplayFormat, color, text );
4196 FreeString( text );
4197 DisplayString( newstr );
4198 free( newstr );
4201 // String format is
4202 // blah : whatever
4203 void Interface::DisplayConstantStringValue(int stridx, unsigned int color, ieDword value) const
4205 if (stridx<0) return;
4206 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4207 int newlen = (int)(strlen( DisplayFormat ) + strlen( text ) + 28);
4208 char* newstr = ( char* ) malloc( newlen );
4209 snprintf( newstr, newlen, DisplayFormatValue, color, text, (int) value );
4210 FreeString( text );
4211 DisplayString( newstr );
4212 free( newstr );
4215 // String format is
4216 // <charname> - blah blah : whatever
4217 void Interface::DisplayConstantStringNameString(int stridx, unsigned int color, int stridx2, const Scriptable *actor) const
4219 unsigned int actor_color;
4220 const char *name;
4222 if (stridx<0) return;
4223 actor_color = GetSpeakerColor(name, actor);
4224 char* text = GetString( strref_table[stridx], IE_STR_SOUND );
4225 char* text2 = GetString( strref_table[stridx2], IE_STR_SOUND );
4226 int newlen = (int)(strlen( DisplayFormat ) + strlen(name) + strlen( text ) + strlen(text2) + 18);
4227 char* newstr = ( char* ) malloc( newlen );
4228 if (strlen(text2)) {
4229 snprintf( newstr, newlen, DisplayFormatNameString, actor_color, name, color, text, text2 );
4230 } else {
4231 snprintf( newstr, newlen, DisplayFormatName, color, name, color, text );
4233 FreeString( text );
4234 FreeString( text2 );
4235 DisplayString( newstr );
4236 free( newstr );
4239 // String format is
4240 // <charname> - blah blah
4241 void Interface::DisplayConstantStringName(int stridx, unsigned int color, const Scriptable *speaker) const
4243 unsigned int speaker_color;
4244 const char *name;
4246 if (stridx<0) return;
4247 if(!speaker) return;
4248 speaker_color = GetSpeakerColor(name, speaker);
4249 char* text = GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
4250 int newlen = (int)(strlen( DisplayFormatName ) + strlen( name ) +
4251 + strlen( text ) + 18);
4252 char* newstr = ( char* ) malloc( newlen );
4253 snprintf( newstr, newlen, DisplayFormatName, speaker_color, name, color,
4254 text );
4255 FreeString( text );
4256 DisplayString( newstr );
4257 free( newstr );
4260 void Interface::DisplayConstantStringAction(int stridx, unsigned int color, const Scriptable *attacker, const Scriptable *target) const
4262 unsigned int attacker_color;
4263 const char *name1;
4264 const char *name2;
4266 if (stridx<0) return;
4268 GetSpeakerColor(name2, target);
4269 attacker_color = GetSpeakerColor(name1, attacker);
4271 char* text = GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
4272 int newlen = (int)(strlen( DisplayFormatAction ) + strlen( name1 ) +
4273 + strlen( name2 ) + strlen( text ) + 18);
4274 char* newstr = ( char* ) malloc( newlen );
4275 snprintf( newstr, newlen, DisplayFormatAction, attacker_color, name1, color,
4276 text, name2);
4277 FreeString( text );
4278 DisplayString( newstr );
4279 free( newstr );
4282 void Interface::DisplayStringName(int stridx, unsigned int color, const Scriptable *speaker, ieDword flags) const
4284 unsigned int speaker_color;
4285 const char *name;
4287 if (stridx<0) return;
4288 speaker_color = GetSpeakerColor(name, speaker);
4290 char* text = GetString( stridx, flags);
4291 int newlen = (int)(strlen( DisplayFormatName ) + strlen( name ) +
4292 + strlen( text ) + 10);
4293 char* newstr = ( char* ) malloc( newlen );
4294 snprintf( newstr, newlen, DisplayFormatName, speaker_color, name, color, text );
4295 FreeString( text );
4296 DisplayString( newstr );
4297 free( newstr );
4300 static const char *saved_extensions[]={".are",".sto",0};
4301 static const char *saved_extensions_last[]={".tot",".toh",0};
4303 //returns the priority of the file to be saved
4304 //2 - save
4305 //1 - save last
4306 //0 - don't save
4307 int Interface::SavedExtension(const char *filename)
4309 const char *str=strchr(filename,'.');
4310 if (!str) return 0;
4311 int i=0;
4312 while(saved_extensions[i]) {
4313 if (!stricmp(saved_extensions[i], str) ) return 2;
4314 i++;
4316 i=0;
4317 while(saved_extensions_last[i]) {
4318 if (!stricmp(saved_extensions_last[i], str) ) return 1;
4319 i++;
4321 return 0;
4324 static const char *protected_extensions[]={".exe",".dll",".so",0};
4326 //returns true if file should be saved
4327 bool Interface::ProtectedExtension(const char *filename)
4329 const char *str=strchr(filename,'.');
4330 if (!str) return false;
4331 int i=0;
4332 while(protected_extensions[i]) {
4333 if (!stricmp(protected_extensions[i], str) ) return true;
4334 i++;
4336 return false;
4339 void Interface::RemoveFromCache(const ieResRef resref, SClass_ID ClassID)
4341 char filename[_MAX_PATH];
4343 snprintf(filename, _MAX_PATH, "%s%.8s%s", CachePath, resref, TypeExt( ClassID ) );
4344 unlink ( filename);
4347 //this function checks if the path is eligible as a cache
4348 //if it contains a directory, or suspicious file extensions
4349 //we bail out, because the cache will be purged regularly.
4350 bool Interface::StupidityDetector(const char* Pt)
4352 char Path[_MAX_PATH];
4353 strcpy( Path, Pt );
4354 DIR* dir = opendir( Path );
4355 if (dir == NULL) {
4356 printf("\n**cannot open**\n");
4357 return true; //no directory?
4359 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
4360 if (de == NULL) {
4361 closedir( dir );
4362 printf("\n**cannot read**\n");
4363 return true; //cannot read it?
4365 do {
4366 char dtmp[_MAX_PATH];
4367 struct stat fst;
4368 snprintf( dtmp, _MAX_PATH, "%s%s%s", Path, SPathDelimiter, de->d_name );
4369 stat( dtmp, &fst );
4370 if (S_ISDIR( fst.st_mode )) {
4371 if (de->d_name[0] == '.')
4372 continue;
4373 closedir( dir );
4374 printf("\n**contains another dir**\n");
4375 return true; //a directory in there???
4377 if (ProtectedExtension(de->d_name) ) {
4378 closedir( dir );
4379 printf("\n**contains alien files**\n");
4380 return true; //an executable file in there???
4382 } while (( de = readdir( dir ) ) != NULL);
4383 closedir( dir );
4384 //ok, we got a good conscience
4385 return false;
4388 void Interface::DelTree(const char* Pt, bool onlysave)
4390 char Path[_MAX_PATH];
4392 if (!Pt[0]) return; //Don't delete the root filesystem :)
4393 strcpy( Path, Pt );
4394 DIR* dir = opendir( Path );
4395 if (dir == NULL) {
4396 return;
4398 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
4399 if (de == NULL) {
4400 closedir( dir );
4401 return;
4403 do {
4404 char dtmp[_MAX_PATH];
4405 struct stat fst;
4406 snprintf( dtmp, _MAX_PATH, "%s%s%s", Path, SPathDelimiter, de->d_name );
4407 stat( dtmp, &fst );
4408 if (S_ISDIR( fst.st_mode ))
4409 continue;
4410 if (de->d_name[0] == '.')
4411 continue;
4412 if (!onlysave || SavedExtension(de->d_name) ) {
4413 unlink( dtmp );
4415 } while (( de = readdir( dir ) ) != NULL);
4416 closedir( dir );
4419 void Interface::LoadProgress(int percent)
4421 vars->SetAt("Progress", percent);
4422 RedrawControls("Progress", percent);
4423 RedrawAll();
4424 DrawWindows();
4425 video->SwapBuffers();
4428 void Interface::ReleaseDraggedItem()
4430 DraggedItem=NULL; //shouldn't free this
4431 video->SetDragCursor (NULL);
4434 void Interface::DragItem(CREItem *item, const ieResRef Picture)
4436 //We should drop the dragged item and pick this up,
4437 //we shouldn't have a valid DraggedItem at this point.
4438 //Anyway, if there is still a dragged item, it will be destroyed.
4439 if (DraggedItem) {
4440 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW);
4441 delete DraggedItem;
4443 DraggedItem = item;
4444 if (video) {
4445 Sprite2D* DraggedCursor = NULL;
4446 if (item) {
4447 DraggedCursor = gamedata->GetBAMSprite( Picture, 0, 0 );
4449 video->SetDragCursor (DraggedCursor);
4453 void Interface::SetDraggedPortrait(int dp, int idx)
4455 if (idx<0) idx=14;
4456 DraggedPortrait = dp;
4457 if (dp) {
4458 //hmm this might work?
4459 Cursors[idx]->acquire();
4460 video->SetDragCursor(Cursors[idx]);
4461 } else {
4462 video->SetDragCursor(NULL);
4466 bool Interface::ReadItemTable(const ieResRef TableName, const char * Prefix)
4468 ieResRef ItemName;
4469 int i,j;
4471 AutoTable tab(TableName);
4472 if (!tab) {
4473 return false;
4475 i=tab->GetRowCount();
4476 for(j=0;j<i;j++) {
4477 if (Prefix) {
4478 snprintf(ItemName,sizeof(ItemName),"%s%02d",Prefix, j+1);
4479 } else {
4480 strnlwrcpy(ItemName,tab->GetRowName(j), 8);
4482 //Variable elements are free'd, so we have to use malloc
4483 //well, not anymore, we can use ReleaseFunction
4484 int l=tab->GetColumnCount(j);
4485 if (l<1) continue;
4486 int cl = atoi(tab->GetColumnName(0));
4487 ItemList *itemlist = new ItemList(l, cl);
4488 for(int k=0;k<l;k++) {
4489 strnlwrcpy(itemlist->ResRefs[k],tab->QueryField(j,k), 8);
4491 RtRows->SetAt(ItemName, (void*)itemlist);
4493 return true;
4496 bool Interface::ReadRandomItems()
4498 ieResRef RtResRef;
4499 int i;
4501 ieDword difflev=0; //rt norm or rt fury
4502 vars->Lookup("Nightmare Mode", difflev);
4503 if (RtRows) {
4504 RtRows->RemoveAll(ReleaseItemList);
4506 else {
4507 RtRows=new Variables(10, 17); //block size, hash table size
4508 if (!RtRows) {
4509 return false;
4511 RtRows->SetType( GEM_VARIABLES_POINTER );
4513 AutoTable tab("randitem");
4514 if (!tab) {
4515 return false;
4517 if (difflev>=tab->GetColumnCount()) {
4518 difflev = tab->GetColumnCount()-1;
4521 //the gold item
4522 strnlwrcpy( GoldResRef, tab->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4523 if ( GoldResRef[0]=='*' ) {
4524 return false;
4526 strnlwrcpy( RtResRef, tab->QueryField( 1, difflev ), 8);
4527 i=atoi( RtResRef );
4528 if (i<1) {
4529 ReadItemTable( RtResRef, 0 ); //reading the table itself
4530 return true;
4532 if (i>5) {
4533 i=5;
4535 while(i--) {
4536 strnlwrcpy( RtResRef, tab->QueryField(2+i,difflev), 8);
4537 ReadItemTable( RtResRef,tab->GetRowName(2+i) );
4539 return true;
4542 CREItem *Interface::ReadItem(DataStream *str)
4544 CREItem *itm = new CREItem();
4546 str->ReadResRef( itm->ItemResRef );
4547 str->ReadWord( &itm->Expired );
4548 str->ReadWord( &itm->Usages[0] );
4549 str->ReadWord( &itm->Usages[1] );
4550 str->ReadWord( &itm->Usages[2] );
4551 str->ReadDword( &itm->Flags );
4552 if (ResolveRandomItem(itm) ) {
4553 return itm;
4555 delete itm;
4556 return NULL;
4559 #define MAX_LOOP 10
4561 //This function generates random items based on the randitem.2da file
4562 //there could be a loop, but we don't want to freeze, so there is a limit
4563 bool Interface::ResolveRandomItem(CREItem *itm)
4565 if (!RtRows) return true;
4566 for(int loop=0;loop<MAX_LOOP;loop++) {
4567 int i,j,k;
4568 char *endptr;
4569 ieResRef NewItem;
4571 void* lookup;
4572 if ( !RtRows->Lookup( itm->ItemResRef, lookup ) ) {
4573 return true;
4575 ItemList *itemlist = (ItemList*)lookup;
4576 if (itemlist->WeightOdds) {
4577 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4578 i=Roll(2,(itemlist->Count+1)/2,-2);
4579 } else {
4580 i=Roll(1,itemlist->Count,-1);
4582 strnlwrcpy( NewItem, itemlist->ResRefs[i], 8);
4583 char *p=(char *) strchr(NewItem,'*');
4584 if (p) {
4585 *p=0; //doing this so endptr is ok
4586 k=strtol(p+1,NULL,10);
4587 } else {
4588 k=1;
4590 j=strtol(NewItem,&endptr,10);
4591 if (j<1) {
4592 j=1;
4594 if (*endptr) {
4595 strnlwrcpy(itm->ItemResRef, NewItem, 8);
4596 } else {
4597 strnlwrcpy(itm->ItemResRef, GoldResRef, 8);
4599 if ( !memcmp( itm->ItemResRef,"no_drop",8 ) ) {
4600 itm->ItemResRef[0]=0;
4602 if (!itm->ItemResRef[0]) {
4603 return false;
4605 itm->Usages[0]=(ieWord) Roll(j,k,0);
4607 printMessage("Interface"," ",LIGHT_RED);
4608 printf("Loop detected while generating random item:%s\n",itm->ItemResRef);
4609 return false;
4612 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4613 //these functions are needed because Win32 doesn't allow freeing memory from
4614 //another dll. So we allocate all commonly used memories from core
4615 ITMExtHeader *Interface::GetITMExt(int count)
4617 return new ITMExtHeader[count];
4620 SPLExtHeader *Interface::GetSPLExt(int count)
4622 return new SPLExtHeader[count];
4625 Effect *Interface::GetEffect(ieDword opcode)
4627 if (opcode==0xffffffff) {
4628 return NULL;
4630 Effect *fx = new Effect();
4631 if (!fx) {
4632 return NULL;
4634 memset(fx,0,sizeof(Effect));
4635 fx->Opcode=opcode;
4636 return fx;
4639 Effect *Interface::GetFeatures(int count)
4641 return new Effect[count];
4645 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4647 delete [] p;
4648 delete [] e;
4651 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4653 delete [] p;
4654 delete [] e;
4658 WorldMapArray *Interface::NewWorldMapArray(int count)
4660 return new WorldMapArray(count);
4663 Container *Interface::GetCurrentContainer()
4665 return CurrentContainer;
4668 int Interface::CloseCurrentContainer()
4670 UseContainer = false;
4671 if ( !CurrentContainer) {
4672 return -1;
4674 //remove empty ground piles on closeup
4675 CurrentContainer->GetCurrentArea()->TMap->CleanupContainer(CurrentContainer);
4676 CurrentContainer = NULL;
4677 return 0;
4680 void Interface::SetCurrentContainer(Actor *actor, Container *arg, bool flag)
4682 //abort action if the first selected PC isn't the original actor
4683 if (actor!=GetFirstSelectedPC(false)) {
4684 CurrentContainer = NULL;
4685 return;
4687 CurrentContainer = arg;
4688 UseContainer = flag;
4691 Store *Interface::GetCurrentStore()
4693 return CurrentStore;
4696 int Interface::CloseCurrentStore()
4698 if ( !CurrentStore ) {
4699 return -1;
4701 StoreMgr* sm = ( StoreMgr* ) GetInterface( IE_STO_CLASS_ID );
4702 if (sm == NULL) {
4703 return -1;
4705 int size = sm->GetStoredFileSize (CurrentStore);
4706 if (size > 0) {
4707 //created streams are always autofree (close file on destruct)
4708 //this one will be destructed when we return from here
4709 FileStream str;
4711 str.Create( CurrentStore->Name, IE_STO_CLASS_ID );
4712 int ret = sm->PutStore (&str, CurrentStore);
4713 if (ret <0) {
4714 printMessage("Core"," ", YELLOW);
4715 printf("Store removed: %s\n", CurrentStore->Name);
4716 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4718 } else {
4719 printMessage("Core"," ", YELLOW);
4720 printf("Store removed: %s\n", CurrentStore->Name);
4721 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4723 //make sure the stream isn't connected to sm, or it will be double freed
4724 sm->release();
4725 delete CurrentStore;
4726 CurrentStore = NULL;
4727 return 0;
4730 Store *Interface::SetCurrentStore(const ieResRef resname, const ieVariable owner)
4732 if ( CurrentStore ) {
4733 if ( !strnicmp(CurrentStore->Name, resname, 8) ) {
4734 return CurrentStore;
4737 //not simply delete the old store, but save it
4738 CloseCurrentStore();
4741 DataStream* str = gamedata->GetResource( resname, IE_STO_CLASS_ID );
4742 StoreMgr* sm = ( StoreMgr* ) GetInterface( IE_STO_CLASS_ID );
4743 if (sm == NULL) {
4744 delete ( str );
4745 return NULL;
4747 if (!sm->Open( str, true )) {
4748 sm->release();
4749 return NULL;
4752 // FIXME - should use some already allocated in core
4753 // not really, only one store is open at a time, then it is
4754 // unloaded, we don't really have to cache it, it will be saved in
4755 // Cache anyway!
4756 CurrentStore = sm->GetStore( new Store() );
4757 if (CurrentStore == NULL) {
4758 sm->release();
4759 return NULL;
4761 sm->release();
4762 strnlwrcpy(CurrentStore->Name, resname, 8);
4763 if (owner) {
4764 CurrentStore->SetOwner(owner);
4766 return CurrentStore;
4769 void Interface::SetMouseScrollSpeed(int speed) {
4770 mousescrollspd = (speed+1)*2;
4773 int Interface::GetMouseScrollSpeed() {
4774 return mousescrollspd;
4777 ieStrRef Interface::GetRumour(const ieResRef dlgref)
4779 DialogMgr* dm = ( DialogMgr* ) GetInterface( IE_DLG_CLASS_ID );
4780 dm->Open( gamedata->GetResource( dlgref, IE_DLG_CLASS_ID ), true );
4781 Dialog *dlg = dm->GetDialog();
4782 dm->release();
4784 if (!dlg) {
4785 printMessage("Interface"," ", LIGHT_RED);
4786 printf( "Cannot load dialog: %s\n", dlgref );
4787 return (ieStrRef) -1;
4789 Scriptable *pc=game->GetPC( game->GetSelectedPCSingle(), false );
4791 ieStrRef ret = (ieStrRef) -1;
4792 int i = dlg->FindRandomState( pc );
4793 if (i>=0 ) {
4794 ret = dlg->GetState( i )->StrRef;
4796 delete dlg;
4797 return ret;
4800 void Interface::DoTheStoreHack(Store *s)
4802 size_t size = s->PurchasedCategoriesCount * sizeof( ieDword );
4803 s->purchased_categories=(ieDword *) malloc(size);
4805 size = s->CuresCount * sizeof( STOCure );
4806 s->cures=(STOCure *) malloc(size);
4808 size = s->DrinksCount * sizeof( STODrink );
4809 s->drinks=(STODrink *) malloc(size);
4811 for(size=0;size<s->ItemsCount;size++)
4812 s->items.push_back( new STOItem() );
4815 //plays stock sound listed in defsound.2da
4816 void Interface::PlaySound(int index)
4818 if (index<=DSCount) {
4819 AudioDriver->Play(DefSound[index]);
4823 Actor *Interface::GetFirstSelectedPC(bool forced)
4825 int partySize = game->GetPartySize( false );
4826 if (!partySize) return NULL;
4827 for (int i = 0; i < partySize; i++) {
4828 Actor* actor = game->GetPC( i,false );
4829 if (actor->IsSelected()) {
4830 return actor;
4834 if (forced) {
4835 return game->GetPC(0,false);
4837 return NULL;
4840 //this is used only for the console
4841 Sprite2D *Interface::GetCursorSprite()
4843 Sprite2D *spr = gamedata->GetBAMSprite(CursorBam, 0, 0);
4844 if (spr)
4846 if(HasFeature(GF_OVERRIDE_CURSORPOS))
4848 spr->XPos=1;
4849 spr->YPos=spr->Height-1;
4852 return spr;
4855 Sprite2D *Interface::GetScrollCursorSprite(int frameNum, int spriteNum)
4857 return gamedata->GetBAMSprite(ScrollCursorBam, frameNum, spriteNum);
4860 /* we should return -1 if it isn't gold, otherwise return the gold value */
4861 int Interface::CanMoveItem(const CREItem *item) const
4863 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4864 if (item->Flags & IE_INV_ITEM_UNDROPPABLE)
4865 return 0;
4866 //not gold, we allow only one single coin ResRef, this is good
4867 //for all of the original games
4868 if (strnicmp(item->ItemResRef, GoldResRef, 8 ) )
4869 return -1;
4870 //gold, returns the gold value (stack size)
4871 return item->Usages[0];
4874 // dealing with applying effects
4875 void Interface::ApplySpell(const ieResRef resname, Actor *actor, Scriptable *caster, int level)
4877 Spell *spell = gamedata->GetSpell(resname);
4878 if (!spell) {
4879 return;
4882 level = spell->GetHeaderIndexFromLevel(level);
4883 EffectQueue *fxqueue = spell->GetEffectBlock(caster, actor->Pos, level);
4885 //check effect immunities
4886 int res = fxqueue->CheckImmunity ( actor );
4887 if (res) {
4888 if (res == -1) {
4889 //bounced back at a nonliving caster
4890 if (caster->Type!=ST_ACTOR) {
4891 delete fxqueue;
4892 return;
4894 actor = (Actor *) caster;
4896 fxqueue->SetOwner( caster );
4897 fxqueue->AddAllEffects(actor, actor->Pos);
4899 delete fxqueue;
4902 void Interface::ApplySpellPoint(const ieResRef resname, Map* area, Point &pos, Scriptable *caster, int level)
4904 Spell *spell = gamedata->GetSpell(resname);
4905 if (!spell) {
4906 return;
4908 level = spell->GetHeaderIndexFromLevel(level);
4909 Projectile *pro = spell->GetProjectile(caster, level, pos);
4910 pro->SetCaster(caster->GetGlobalID());
4911 area->AddProjectile(pro, caster->Pos, pos);
4914 //-1 means the effect was reflected back to the caster
4915 //0 means the effect was resisted and should be removed
4916 //1 means the effect was applied
4917 int Interface::ApplyEffect(Effect *effect, Actor *actor, Scriptable *caster)
4919 if (!effect) {
4920 return 0;
4923 EffectQueue *fxqueue = new EffectQueue();
4924 //AddEffect now copies the fx data, please delete your effect reference
4925 //if you created it. (Don't delete cached references)
4926 fxqueue->AddEffect( effect );
4928 int res = fxqueue->CheckImmunity ( actor );
4929 if (res) {
4930 if (res == -1 ) {
4931 //bounced back at a nonliving caster
4932 if (caster->Type!=ST_ACTOR) {
4933 delete fxqueue;
4934 return 0;
4936 actor = (Actor *) caster;
4938 fxqueue->SetOwner( caster );
4939 Point p;
4941 p.empty(); //the effect should have all its coordinates already set
4942 if (fxqueue->AddAllEffects( actor, p )==FX_NOT_APPLIED) {
4943 res=0;
4946 delete fxqueue;
4947 return res;
4950 Effect *Interface::GetEffect(const ieResRef resname, int level, Point &p)
4952 //Don't free this reference, it is cached!
4953 Effect *effect = gamedata->GetEffect(resname);
4954 if (!effect) {
4955 return NULL;
4957 if (!level) {
4958 level = 1;
4960 effect->Power = level;
4961 effect->PosX=p.x;
4962 effect->PosY=p.y;
4963 return effect;
4966 // dealing with saved games
4967 int Interface::SwapoutArea(Map *map)
4969 MapMgr* mm = ( MapMgr* ) GetInterface( IE_ARE_CLASS_ID );
4970 if (mm == NULL) {
4971 return -1;
4973 int size = mm->GetStoredFileSize (map);
4974 if (size > 0) {
4975 //created streams are always autofree (close file on destruct)
4976 //this one will be destructed when we return from here
4977 FileStream str;
4979 str.Create( map->GetScriptName(), IE_ARE_CLASS_ID );
4980 int ret = mm->PutArea (&str, map);
4981 if (ret <0) {
4982 printMessage("Core"," ", YELLOW);
4983 printf("Area removed: %s\n", map->GetScriptName());
4984 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4986 } else {
4987 printMessage("Core"," ", YELLOW);
4988 printf("Area removed: %s\n", map->GetScriptName());
4989 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4991 //make sure the stream isn't connected to sm, or it will be double freed
4992 mm->release();
4993 return 0;
4996 int Interface::WriteCharacter(const char *name, Actor *actor)
4998 char Path[_MAX_PATH];
5000 PathJoin( Path, GamePath, GameCharactersPath, NULL );
5001 if (!actor) {
5002 return -1;
5004 ActorMgr* gm = ( ActorMgr* ) GetInterface( IE_CRE_CLASS_ID );
5005 if (gm == NULL) {
5006 return -1;
5008 FileStream str;
5010 str.Create( Path, name, IE_CHR_CLASS_ID );
5012 //this is not needed, because the chr header writer automatically
5013 //calls it
5014 //int size = gm->GetStoredFileSize (actor);
5015 int ret = gm->PutActor(&str, actor, true);
5016 if (ret <0) {
5017 printMessage("Core"," ", YELLOW);
5018 printf("Character cannot be saved: %s\n", name);
5020 gm->release();
5021 return 0;
5024 int Interface::WriteGame(const char *folder)
5026 SaveGameMgr* gm = ( SaveGameMgr* ) GetInterface( IE_GAM_CLASS_ID );
5027 if (gm == NULL) {
5028 return -1;
5031 int size = gm->GetStoredFileSize (game);
5032 if (size > 0) {
5033 //created streams are always autofree (close file on destruct)
5034 //this one will be destructed when we return from here
5035 FileStream str;
5037 str.Create( folder, GameNameResRef, IE_GAM_CLASS_ID );
5038 int ret = gm->PutGame (&str, game);
5039 if (ret <0) {
5040 printMessage("Core"," ", YELLOW);
5041 printf("Game cannot be saved: %s\n", GameNameResRef);
5043 } else {
5044 printMessage("Core"," ", YELLOW);
5045 printf("Internal error, game cannot be saved: %s\n", GameNameResRef);
5047 //make sure the stream isn't connected to sm, or it will be double freed
5048 gm->release();
5049 return 0;
5052 int Interface::WriteWorldMap(const char *folder)
5054 WorldMapMgr* wmm = ( WorldMapMgr* ) GetInterface( IE_WMP_CLASS_ID );
5055 if (wmm == NULL) {
5056 return -1;
5059 int size = wmm->GetStoredFileSize (worldmap);
5060 if (size > 0) {
5061 //created streams are always autofree (close file on destruct)
5062 //this one will be destructed when we return from here
5063 FileStream str;
5065 str.Create( folder, WorldMapName, IE_WMP_CLASS_ID );
5066 int ret = wmm->PutWorldMap (&str, worldmap);
5067 if (ret <0) {
5068 printMessage("Core"," ", YELLOW);
5069 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName);
5071 } else {
5072 printMessage("Core"," ", YELLOW);
5073 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName);
5075 //make sure the stream isn't connected to sm, or it will be double freed
5076 wmm->release();
5077 return 0;
5080 int Interface::CompressSave(const char *folder)
5082 FileStream str;
5084 str.Create( folder, GameNameResRef, IE_SAV_CLASS_ID );
5085 DIR* dir = opendir( CachePath );
5086 if (dir == NULL) {
5087 return -1;
5089 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
5090 if (de == NULL) {
5091 closedir( dir );
5092 return -1;
5094 //BIF and SAV are the same
5095 ArchiveImporter * ai = (ArchiveImporter*)GetInterface(IE_BIF_CLASS_ID);
5096 ai->CreateArchive( &str);
5098 //.tot and .toh should be saved last, because they are updated when an .are is saved
5099 int priority=2;
5100 while(priority) {
5101 do {
5102 char dtmp[_MAX_PATH];
5103 struct stat fst;
5104 snprintf( dtmp, _MAX_PATH, "%s%s", CachePath, de->d_name );
5105 stat( dtmp, &fst );
5106 if (S_ISDIR( fst.st_mode ))
5107 continue;
5108 if (de->d_name[0] == '.')
5109 continue;
5110 if (SavedExtension(de->d_name)==priority) {
5111 FileStream fs;
5112 fs.Open(dtmp, true);
5113 ai->AddToSaveGame(&str, &fs);
5115 } while (( de = readdir( dir ) ) != NULL);
5116 closedir( dir );
5117 //reopen list for the second round
5118 priority--;
5119 if (priority>0) {
5120 dir = opendir( CachePath );
5121 de = readdir( dir );
5124 ai->release();
5125 return 0;
5128 int Interface::GetMaximumAbility() const { return MaximumAbility; }
5130 int Interface::GetStrengthBonus(int column, int value, int ex) const
5132 //to hit, damage, open doors, weight allowance
5133 if (column<0 || column>3)
5134 return -9999;
5136 if (value<0)
5137 value = 0;
5138 else if (value>25)
5139 value = 25;
5141 if (ex<0)
5142 ex=0;
5143 else if (ex>100)
5144 ex=100;
5146 return strmod[column*(MaximumAbility+1)+value]+strmodex[column*101+ex];
5149 //only the first 3 columns are supported
5150 int Interface::GetIntelligenceBonus(int column, int value) const
5152 //learn spell, max spell level, max spell number on level
5153 if (column<0 || column>2)
5154 return -9999;
5156 return intmod[column*(MaximumAbility+1)+value];
5159 int Interface::GetDexterityBonus(int column, int value) const
5161 //reaction, missile, ac
5162 if (column<0 || column>2)
5163 return -9999;
5165 //no dexmod in iwd2???
5166 if (HasFeature(GF_3ED_RULES)) return 0;
5168 return dexmod[column*(MaximumAbility+1)+value];
5171 int Interface::GetConstitutionBonus(int column, int value) const
5173 //normal, warrior, minimum, regen hp, regen fatigue
5174 if (column<0 || column>4)
5175 return -9999;
5177 return conmod[column*(MaximumAbility+1)+value];
5180 int Interface::GetCharismaBonus(int column, int value) const
5182 //?reaction
5183 if (column<0 || column>0)
5184 return -9999;
5186 return chrmod[column*(MaximumAbility+1)+value];
5189 int Interface::GetLoreBonus(int column, int value) const
5191 if (column<0 || column>0)
5192 return -9999;
5194 //no lorebon in iwd2???
5195 if (HasFeature(GF_3ED_RULES)) return 0;
5197 return lorebon[value];
5200 // -3, -2 if request is illegal or in cutscene
5201 // -1 if pause is already active
5202 // 0 if pause was not allowed
5203 // 1 if autopause happened
5204 int Interface::Autopause(ieDword flag)
5206 GameControl *gc = GetGameControl();
5207 if (!gc) {
5208 return -3;
5210 if (InCutSceneMode()) {
5211 return -2;
5213 if (gc->GetDialogueFlags()&DF_FREEZE_SCRIPTS) {
5214 return -1;
5216 ieDword autopause_flags = 0;
5218 vars->Lookup("Auto Pause State", autopause_flags);
5219 if (autopause_flags & (1<<flag)) {
5220 DisplayConstantString(STR_AP_UNUSABLE+flag, 0xff0000);
5221 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5222 return 1;
5224 return 0;
5227 void Interface::RegisterOpcodes(int count, const EffectRef *opcodes)
5229 EffectQueue_RegisterOpcodes(count, opcodes);
5232 void Interface::SetInfoTextColor(Color &color)
5234 if (InfoTextPalette) {
5235 gamedata->FreePalette(InfoTextPalette);
5237 InfoTextPalette = CreatePalette(color, black);
5240 //todo row?
5241 void Interface::GetResRefFrom2DA(const ieResRef resref, ieResRef resource1, ieResRef resource2, ieResRef resource3)
5243 if (!resource1) {
5244 return;
5246 resource1[0]=0;
5247 if (resource2) {
5248 resource2[0]=0;
5250 if (resource3) {
5251 resource3[0]=0;
5253 AutoTable tab(resref);
5254 if (tab) {
5255 unsigned int cols = tab->GetColumnCount();
5256 unsigned int row = (unsigned int) Roll(1,tab->GetRowCount(),-1);
5257 strnuprcpy(resource1, tab->QueryField(row,0), 8);
5258 if (resource2 && cols>1)
5259 strnuprcpy(resource2, tab->QueryField(row,1), 8);
5260 if (resource3 && cols>2)
5261 strnuprcpy(resource3, tab->QueryField(row,2), 8);
5265 ieDword *Interface::GetListFrom2DA(const ieResRef resref)
5267 ieDword *ret;
5269 AutoTable tab(resref);
5270 if (tab) {
5271 ieDword cnt = tab->GetRowCount();
5272 ret = (ieDword *) malloc((1+cnt)*sizeof(ieDword));
5273 ret[0]=cnt;
5274 while(cnt) {
5275 ret[cnt]=strtol(tab->QueryField(cnt-1, 0),NULL, 0);
5276 cnt--;
5278 return ret;
5280 ret = (ieDword *) malloc(sizeof(ieDword));
5281 ret[0]=0;
5282 return ret;
5285 //returns a numeric value associated with a stat name (symbol) from stats.ids
5286 ieDword Interface::TranslateStat(const char *stat_name)
5288 long tmp;
5290 if (valid_number(stat_name, tmp)) {
5291 return (ieDword) tmp;
5294 int symbol = LoadSymbol( "stats" );
5295 SymbolMgr *sym = GetSymbol( symbol );
5296 ieDword stat = (ieDword) sym->GetValue( stat_name );
5297 if (stat==(ieDword) ~0) {
5298 printMessage("Core"," ",YELLOW);
5299 printf("Cannot translate symbol: %s\n", stat_name);
5301 return stat;
5304 void Interface::WaitForDisc(int disc_number, const char* path)
5306 GetDictionary()->SetAt( "WaitForDisc", (ieDword) disc_number );
5308 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5309 do {
5310 core->DrawWindows();
5311 if (dir_exists (path)) {
5312 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5313 break;
5316 } while (video->SwapBuffers() == GEM_OK);
5319 // remove the extraneus EOL newline and carriage return
5320 void Interface::StripLine(char * string, size_t size) {
5321 if (size >= 2 && string[size-2] == '\n') {
5322 string[size-2] = '\0';
5324 if (size >= 3 && string[size-3] == '\r') {
5325 string[size-3] = '\0'; // remove the carriage return too
5329 void Interface::SetNextScript(const char *script)
5331 strncpy( NextScript, script, sizeof(NextScript) );
5332 QuitFlag |= QF_CHANGESCRIPT;