melee / ranged effects
[gemrb.git] / gemrb / core / Interface.cpp
blobf88d8b2a5b883efcabd4602d93b614dda70bcb52
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 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include "Interface.h"
27 #include "exports.h"
28 #include "globals.h"
29 #include "strrefs.h"
30 #include "win32def.h"
32 #include "ActorMgr.h"
33 #include "AmbientMgr.h"
34 #include "AnimationMgr.h"
35 #include "ArchiveImporter.h"
36 #include "Audio.h"
37 #include "Calendar.h"
38 #include "DataFileMgr.h"
39 #include "DialogHandler.h"
40 #include "DialogMgr.h"
41 #include "DisplayMessage.h"
42 #include "EffectMgr.h"
43 #include "EffectQueue.h"
44 #include "Factory.h"
45 #include "Game.h"
46 #include "GameData.h"
47 #include "ImageMgr.h"
48 #include "ItemMgr.h"
49 #include "MapMgr.h"
50 #include "MoviePlayer.h"
51 #include "MusicMgr.h"
52 #include "Palette.h"
53 #include "PluginMgr.h"
54 #include "PluginMgr.h"
55 #include "ProjectileServer.h"
56 #include "SaveGameIterator.h"
57 #include "SaveGameMgr.h"
58 #include "ScriptEngine.h"
59 #include "ScriptedAnimation.h"
60 #include "SoundMgr.h"
61 #include "SpellMgr.h"
62 #include "StoreMgr.h"
63 #include "StringMgr.h"
64 #include "TileMap.h"
65 #include "Video.h"
66 #include "WorldMapMgr.h"
67 #include "GUI/Button.h"
68 #include "GUI/Console.h"
69 #include "GUI/GameControl.h"
70 #include "GUI/Label.h"
71 #include "GUI/MapControl.h"
72 #include "GUI/WorldMapControl.h"
73 #include "System/FileStream.h"
74 #include "System/VFS.h"
76 #if defined(__HAIKU__)
77 #include <unistd.h>
78 #endif
80 #include <cstdlib>
81 #include <time.h>
82 #include <vector>
84 GEM_EXPORT Interface* core;
86 #ifdef WIN32
87 GEM_EXPORT HANDLE hConsole;
88 #endif
90 //use DialogF.tlk if the protagonist is female, that's why we leave space
91 static const char dialogtlk[] = "dialog.tlk\0";
93 static int MaximumAbility = 25;
94 static ieWordSigned *strmod = NULL;
95 static ieWordSigned *strmodex = NULL;
96 static ieWordSigned *intmod = NULL;
97 static ieWordSigned *dexmod = NULL;
98 static ieWordSigned *conmod = NULL;
99 static ieWordSigned *chrmod = NULL;
100 static ieWordSigned *lorebon = NULL;
101 static ieWordSigned *wisbon = NULL;
102 static int **reputationmod = NULL;
103 static ieVariable IWD2DeathVarFormat = "_DEAD%s";
104 static ieVariable DeathVarFormat = "SPRITE_IS_DEAD%s";
106 Interface::Interface(int iargc, char* iargv[])
108 argc = iargc;
109 argv = iargv;
110 #ifdef WIN32
111 hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
112 #endif
113 textcolor( LIGHT_WHITE );
114 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB );
116 // default to the correct endianswitch
117 ieWord endiantest = 1;
118 if (((char *)&endiantest)[1] == 1) {
119 // big-endian
120 DataStream::SetEndianSwitch(true);
123 unsigned int i;
124 for(i=0;i<256;i++) {
125 pl_uppercase[i]=(ieByte) toupper(i);
126 pl_lowercase[i]=(ieByte) tolower(i);
129 projserv = NULL;
130 VideoDriverName = "sdl";
131 AudioDriverName = "openal";
132 vars = NULL;
133 tokens = NULL;
134 lists = NULL;
135 RtRows = NULL;
136 sgiterator = NULL;
137 game = NULL;
138 calendar = NULL;
139 worldmap = NULL;
140 CurrentStore = NULL;
141 CurrentContainer = NULL;
142 UseContainer = false;
143 InfoTextPalette = NULL;
144 timer = NULL;
145 displaymsg = NULL;
146 evntmgr = NULL;
147 console = NULL;
148 slottypes = NULL;
149 slotmatrix = NULL;
151 ModalWindow = NULL;
152 tooltip_x = 0;
153 tooltip_y = 0;
154 tooltip_currtextw = 0;
155 tooltip_ctrl = NULL;
156 plugin_flags = NULL;
158 pal16 = NULL;
159 pal32 = NULL;
160 pal256 = NULL;
162 GUIEnhancements = 0;
164 CursorCount = 0;
165 Cursors = NULL;
167 mousescrollspd = 10;
169 ConsolePopped = false;
170 CheatFlag = false;
171 FogOfWar = 1;
172 QuitFlag = QF_NORMAL;
173 EventFlag = EF_CONTROL;
174 #ifndef WIN32
175 CaseSensitive = true; //this is the default value, so CD1/CD2 will be resolved
176 #else
177 CaseSensitive = false;
178 #endif
179 GameOnCD = false;
180 SkipIntroVideos = false;
181 DrawFPS = false;
182 KeepCache = false;
183 TooltipDelay = 100;
184 GUIScriptsPath[0] = 0;
185 GamePath[0] = 0;
186 SavePath[0] = 0;
187 GemRBPath[0] = 0;
188 PluginsPath[0] = 0;
189 CachePath[0] = 0;
190 GemRBOverridePath[0] = 0;
191 GameName[0] = 0;
193 strncpy( GameOverridePath, "override", sizeof(GameOverridePath) );
194 strncpy( GameSoundsPath, "sounds", sizeof(GameSoundsPath) );
195 strncpy( GameScriptsPath, "scripts", sizeof(GameScriptsPath) );
196 strncpy( GamePortraitsPath, "portraits", sizeof(GamePortraitsPath) );
197 strncpy( GameCharactersPath, "characters", sizeof(GameCharactersPath) );
198 strncpy( GameDataPath, "data", sizeof(GameDataPath) );
199 strncpy( INIConfig, "baldur.ini", sizeof(INIConfig) );
200 strncpy( ButtonFont, "STONESML", sizeof(ButtonFont) );
201 strncpy( TooltipFont, "STONESML", sizeof(TooltipFont) );
202 strncpy( MovieFont, "STONESML", sizeof(MovieFont) );
203 strncpy( ScrollCursorBam, "CURSARW", sizeof(ScrollCursorBam) );
204 strncpy( GlobalScript, "BALDUR", sizeof(GlobalScript) );
205 strncpy( WorldMapName[0], "WORLDMAP", sizeof(ieResRef) );
206 memset( WorldMapName[1], 0, sizeof(ieResRef) );
207 strncpy( Palette16, "MPALETTE", sizeof(Palette16) );
208 strncpy( Palette32, "PAL32", sizeof(Palette32) );
209 strncpy( Palette256, "MPAL256", sizeof(Palette256) );
210 strcpy( TooltipBackResRef, "\0" );
211 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
212 strcpy( GroundCircleBam[size], "\0" );
213 GroundCircleScale[size] = 0;
215 TooltipColor.r = 0;
216 TooltipColor.g = 255;
217 TooltipColor.b = 0;
218 TooltipColor.a = 255;
219 TooltipMargin = 10;
221 TooltipBack = NULL;
222 DraggedItem = NULL;
223 DraggedPortrait = 0;
224 DefSound = NULL;
225 DSCount = -1;
226 memset(GameFeatures, 0, sizeof( GameFeatures ));
227 //GameFeatures = 0;
228 //GameFeatures2 = 0;
229 memset( WindowFrames, 0, sizeof( WindowFrames ));
230 memset( GroundCircles, 0, sizeof( GroundCircles ));
231 memset(FogSprites, 0, sizeof( FogSprites ));
232 AreaAliasTable = NULL;
233 ItemExclTable = NULL;
234 ItemDialTable = NULL;
235 ItemDial2Table = NULL;
236 ItemTooltipTable = NULL;
237 update_scripts = false;
239 gamedata = new GameData();
242 #define FreeResourceVector(type, variable) \
244 size_t i=variable.size(); \
245 while(i--) { \
246 if (variable[i]) { \
247 delete variable[i]; \
250 variable.clear(); \
253 //2da lists are ieDword lists allocated by malloc
254 static void Release2daList(void *poi)
256 free( (ieDword *) poi);
259 static void ReleaseItemList(void *poi)
261 delete ((ItemList *) poi);
264 void FreeAbilityTables()
266 if (strmod) {
267 free(strmod);
269 strmod = NULL;
270 if (strmodex) {
271 free(strmodex);
273 strmodex = NULL;
274 if (intmod) {
275 free(intmod);
277 intmod = NULL;
278 if (dexmod) {
279 free(dexmod);
281 dexmod = NULL;
282 if (conmod) {
283 free(conmod);
285 conmod = NULL;
286 if (chrmod) {
287 free(chrmod);
289 chrmod = NULL;
290 if (lorebon) {
291 free(lorebon);
293 lorebon = NULL;
294 if (wisbon) {
295 free(wisbon);
297 wisbon = NULL;
300 void Interface::FreeResRefTable(ieResRef *&table, int &count)
302 if (table) {
303 free( table );
304 count = -1;
308 static void ReleaseItemTooltip(void *poi)
310 free(poi);
313 Interface::~Interface(void)
315 DragItem(NULL,NULL);
316 delete AreaAliasTable;
318 if (music) {
319 music->HardEnd();
321 // stop any ambients which are still enqueued
322 if (AudioDriver) {
323 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
324 if (ambim) ambim->deactivate();
326 //destroy the highest objects in the hierarchy first!
327 delete game;
328 delete calendar;
329 delete worldmap;
331 FreeAbilityTables();
333 if (reputationmod) {
334 for (unsigned int i=0; i<20; i++) {
335 if (reputationmod[i]) {
336 free(reputationmod[i]);
339 free(reputationmod);
340 reputationmod=NULL;
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;
387 delete displaymsg;
389 if (video) {
391 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
392 video->FreeSprite(FogSprites[i]);
395 for(i=0;i<4;i++) {
396 video->FreeSprite(WindowFrames[i]);
399 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
400 for(i=0;i<6;i++) {
401 video->FreeSprite(GroundCircles[size][i]);
405 if (TooltipBack) {
406 for(i=0;i<3;i++) {
407 //freesprite checks for null pointer
408 video->FreeSprite(TooltipBack[i]);
410 delete[] TooltipBack;
412 if (InfoTextPalette) {
413 gamedata->FreePalette(InfoTextPalette);
416 video->SetDragCursor(NULL);
419 delete evntmgr;
421 delete vars;
422 delete tokens;
423 if (lists) {
424 lists->RemoveAll(Release2daList);
425 delete lists;
428 if (RtRows) {
429 RtRows->RemoveAll(ReleaseItemList);
430 delete RtRows;
432 if (ItemExclTable) {
433 ItemExclTable->RemoveAll(NULL);
434 delete ItemExclTable;
436 if (ItemDialTable) {
437 ItemDialTable->RemoveAll(NULL);
438 delete ItemDialTable;
440 if (ItemDial2Table) {
441 ItemDial2Table->RemoveAll(NULL);
442 delete ItemDial2Table;
444 if (ItemTooltipTable) {
445 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
446 delete ItemTooltipTable;
449 Map::ReleaseMemory();
450 Actor::ReleaseMemory();
452 gamedata->ClearCaches();
453 delete gamedata;
454 gamedata = NULL;
456 // Removing all stuff from Cache, except bifs
457 if (!KeepCache) DelTree((const char *) CachePath, true);
460 void Interface::SetWindowFrame(int i, Sprite2D *Picture)
462 video->FreeSprite(WindowFrames[i]);
463 WindowFrames[i]=Picture;
466 GameControl* Interface::StartGameControl()
468 //making sure that our window is the first one
469 if (ConsolePopped) {
470 PopupConsole();
472 DelAllWindows();//deleting ALL windows
473 gamedata->DelTable(0xffffu); //dropping ALL tables
474 Window* gamewin = new Window( 0xffff, 0, 0, (ieWord) Width, (ieWord) Height );
475 gamewin->WindowPack[0]=0;
476 GameControl* gc = new GameControl();
477 gc->XPos = 0;
478 gc->YPos = 0;
479 gc->Width = (ieWord) Width;
480 gc->Height = (ieWord) Height;
481 gc->Owner = gamewin;
482 gc->ControlID = 0x00000000;
483 gc->ControlType = IE_GUI_GAMECONTROL;
484 gamewin->AddControl( gc );
485 AddWindow( gamewin );
486 SetVisible( 0, WINDOW_VISIBLE );
487 //setting the focus to the game control
488 evntmgr->SetFocused(gamewin, gc);
489 if (guiscript->LoadScript( "MessageWindow" )) {
490 guiscript->RunFunction( "MessageWindow", "OnLoad" );
491 gc->UnhideGUI();
494 return gc;
497 /* handle main loop events that might destroy or create windows
498 thus cannot be called from DrawWindows directly
499 these events are pending until conditions are right
501 void Interface::HandleEvents()
503 GameControl *gc = GetGameControl();
504 if (gc && (!gc->Owner || !gc->Owner->Visible)) {
505 gc=NULL;
508 if (EventFlag&EF_SELECTION) {
509 EventFlag&=~EF_SELECTION;
510 guiscript->RunFunction( "GUICommonWindows", "SelectionChanged", false);
513 if (EventFlag&EF_UPDATEANIM) {
514 EventFlag&=~EF_UPDATEANIM;
515 guiscript->RunFunction( "GUICommonWindows", "UpdateAnimation", false);
518 if (EventFlag&EF_PORTRAIT) {
519 ieDword tmp = (ieDword) ~0;
520 vars->Lookup( "PortraitWindow", tmp );
521 if (tmp != (ieDword) ~0) {
522 EventFlag&=~EF_PORTRAIT;
523 guiscript->RunFunction( "GUICommonWindows", "UpdatePortraitWindow" );
527 if (EventFlag&EF_ACTION) {
528 ieDword tmp = (ieDword) ~0;
529 vars->Lookup( "ActionsWindow", tmp );
530 if (tmp != (ieDword) ~0) {
531 EventFlag&=~EF_ACTION;
532 guiscript->RunFunction( "GUICommonWindows", "UpdateActionsWindow" );
536 if ((EventFlag&EF_CONTROL) && gc) {
537 EventFlag&=~EF_CONTROL;
538 guiscript->RunFunction( "MessageWindow", "UpdateControlStatus" );
539 //this is the only value we can use here
540 if (game->ControlStatus & CS_HIDEGUI)
541 gc->HideGUI();
542 else
543 gc->UnhideGUI();
544 return;
546 if ((EventFlag&EF_SHOWMAP) && gc) {
547 ieDword tmp = (ieDword) ~0;
548 vars->Lookup( "OtherWindow", tmp );
549 if (tmp == (ieDword) ~0) {
550 EventFlag &= ~EF_SHOWMAP;
551 guiscript->RunFunction( "GUIMA", "ShowMap" );
553 return;
556 if (EventFlag&EF_SEQUENCER) {
557 EventFlag&=~EF_SEQUENCER;
558 guiscript->RunFunction( "GUIMG", "OpenSequencerWindow" );
559 return;
562 if (EventFlag&EF_IDENTIFY) {
563 EventFlag&=~EF_IDENTIFY;
564 // FIXME: Implement this.
565 guiscript->RunFunction( "GUICommonWindows", "OpenIdentifyWindow" );
566 return;
568 if (EventFlag&EF_OPENSTORE) {
569 EventFlag&=~EF_OPENSTORE;
570 guiscript->RunFunction( "GUISTORE", "OpenStoreWindow" );
571 return;
574 if (EventFlag&EF_EXPANSION) {
575 EventFlag&=~EF_EXPANSION;
576 guiscript->RunFunction( "MessageWindow", "GameExpansion", false );
577 return;
581 /* handle main loop events that might destroy or create windows
582 thus cannot be called from DrawWindows directly
584 void Interface::HandleFlags()
586 //clear events because the context changed
587 EventFlag = EF_CONTROL;
589 if (QuitFlag&(QF_QUITGAME|QF_EXITGAME) ) {
590 // when reaching this, quitflag should be 1 or 2
591 // if Exitgame was set, we'll set Start.py too
592 QuitGame (QuitFlag&QF_EXITGAME);
593 QuitFlag &= ~(QF_QUITGAME|QF_EXITGAME);
596 if (QuitFlag&QF_LOADGAME) {
597 QuitFlag &= ~QF_LOADGAME;
598 LoadGame(LoadGameIndex.get(), VersionOverride );
599 LoadGameIndex.release();
600 //after loading a game, always check if the game needs to be upgraded
603 if (QuitFlag&QF_ENTERGAME) {
604 QuitFlag &= ~QF_ENTERGAME;
605 if (game) {
606 EventFlag|=EF_EXPANSION;
607 timer->Init();
609 //rearrange party slots
610 game->ConsolidateParty();
611 GameControl* gc = StartGameControl();
612 //switch map to protagonist
613 Actor* actor = GetFirstSelectedPC(true);
614 if (actor) {
615 gc->ChangeMap(actor, true);
617 } else {
618 printMessage("Core", "No game to enter...\n", LIGHT_RED);
619 QuitFlag = QF_QUITGAME;
623 if (QuitFlag&QF_CHANGESCRIPT) {
624 QuitFlag &= ~QF_CHANGESCRIPT;
625 guiscript->LoadScript( NextScript );
626 guiscript->RunFunction( NextScript, "OnLoad" );
630 bool GenerateAbilityTables()
632 FreeAbilityTables();
634 //range is: 0 - maximumability
635 int tablesize = MaximumAbility+1;
636 strmod = (ieWordSigned *) malloc (tablesize * 4 * sizeof(ieWordSigned) );
637 if (!strmod)
638 return false;
639 strmodex = (ieWordSigned *) malloc (101 * 4 * sizeof(ieWordSigned) );
640 if (!strmodex)
641 return false;
642 intmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
643 if (!intmod)
644 return false;
645 dexmod = (ieWordSigned *) malloc (tablesize * 3 * sizeof(ieWordSigned) );
646 if (!dexmod)
647 return false;
648 conmod = (ieWordSigned *) malloc (tablesize * 5 * sizeof(ieWordSigned) );
649 if (!conmod)
650 return false;
651 chrmod = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
652 if (!chrmod)
653 return false;
654 lorebon = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
655 if (!lorebon)
656 return false;
657 wisbon = (ieWordSigned *) malloc (tablesize * 1 * sizeof(ieWordSigned) );
658 if (!wisbon)
659 return false;
660 return true;
663 bool Interface::ReadAbilityTable(const ieResRef tablename, ieWordSigned *mem, int columns, int rows)
665 AutoTable tab(tablename);
666 if (!tab) {
667 return false;
669 //this is a hack for rows not starting at 0 in some cases
670 int fix = 0;
671 const char * tmp = tab->GetRowName(0);
672 if (tmp && (tmp[0]!='0')) {
673 fix = atoi(tmp);
674 for (int i=0;i<fix;i++) {
675 for (int j=0;j<columns;j++) {
676 mem[rows*j+i]=(ieWordSigned) strtol(tab->QueryField(0,j),NULL,0 );
680 for (int j=0;j<columns;j++) {
681 for( int i=0;i<rows-fix;i++) {
682 mem[rows*j+i+fix] = (ieWordSigned) strtol(tab->QueryField(i,j),NULL,0 );
685 return true;
688 bool Interface::ReadAbilityTables()
690 bool ret = GenerateAbilityTables();
691 if (!ret)
692 return ret;
693 ret = ReadAbilityTable("strmod", strmod, 4, MaximumAbility + 1);
694 if (!ret)
695 return ret;
696 ret = ReadAbilityTable("strmodex", strmodex, 4, 101);
697 //3rd ed doesn't have strmodex, but has a maximum of 40
698 if (!ret && (MaximumAbility<=25) )
699 return ret;
700 ret = ReadAbilityTable("intmod", intmod, 3, MaximumAbility + 1);
701 if (!ret)
702 return ret;
703 ret = ReadAbilityTable("hpconbon", conmod, 5, MaximumAbility + 1);
704 if (!ret)
705 return ret;
706 if (!HasFeature(GF_3ED_RULES)) {
707 //no lorebon in iwd2???
708 ret = ReadAbilityTable("lorebon", lorebon, 1, MaximumAbility + 1);
709 if (!ret)
710 return ret;
711 //no dexmod in iwd2???
712 ret = ReadAbilityTable("dexmod", dexmod, 3, MaximumAbility + 1);
713 if (!ret)
714 return ret;
716 //this table is a single row (not a single column)
717 ret = ReadAbilityTable("chrmodst", chrmod, MaximumAbility + 1, 1);
718 if (!ret)
719 return ret;
720 if (HasFeature(GF_WISDOM_BONUS)) {
721 ret = ReadAbilityTable("wisxpbon", wisbon, 1, MaximumAbility + 1);
722 if (!ret)
723 return ret;
725 return true;
728 bool Interface::ReadGameTimeTable()
730 AutoTable table("gametime");
731 if (!table) {
732 return false;
735 Time.round_sec = atoi(table->QueryField("ROUND_SECONDS", "DURATION"));
736 Time.turn_sec = atoi(table->QueryField("TURN_SECONDS", "DURATION"));
737 Time.round_size = Time.round_sec * AI_UPDATE_TIME;
738 Time.rounds_per_turn = Time.turn_sec / Time.round_sec;
740 return true;
743 bool Interface::ReadAuxItemTables()
745 int idx;
746 int table;
747 bool flag = true;
749 if (ItemExclTable) {
750 ItemExclTable->RemoveAll(NULL);
751 } else {
752 ItemExclTable = new Variables();
753 ItemExclTable->SetType(GEM_VARIABLES_INT);
755 table = gamedata->LoadTable( "itemexcl" );
757 AutoTable aa;
759 //don't report error when the file doesn't exist
760 if (aa.load("itemexcl")) {
761 idx = aa->GetRowCount();
762 while (idx--) {
763 ieResRef key;
765 strnlwrcpy(key,aa->GetRowName(idx),8);
766 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
767 ItemExclTable->SetAt(key, value);
770 if (ItemDialTable) {
771 ItemDialTable->RemoveAll(NULL);
772 } else {
773 ItemDialTable = new Variables();
774 ItemDialTable->SetType(GEM_VARIABLES_INT);
776 if (ItemDial2Table) {
777 ItemDial2Table->RemoveAll(NULL);
778 } else {
779 ItemDial2Table = new Variables();
780 ItemDial2Table->SetType(GEM_VARIABLES_STRING);
783 //don't report error when the file doesn't exist
784 if (aa.load("itemdial")) {
785 idx = aa->GetRowCount();
786 while (idx--) {
787 ieResRef key, dlgres;
789 strnlwrcpy(key,aa->GetRowName(idx),8);
790 ieDword value = strtol(aa->QueryField(idx,0),NULL,0);
791 ItemDialTable->SetAt(key, value);
792 strnlwrcpy(dlgres,aa->QueryField(idx,1),8);
793 ItemDial2Table->SetAtCopy(key, dlgres);
797 if (ItemTooltipTable) {
798 ItemTooltipTable->RemoveAll(ReleaseItemTooltip);
799 } else {
800 ItemTooltipTable = new Variables();
801 ItemTooltipTable->SetType(GEM_VARIABLES_POINTER);
804 //don't report error when the file doesn't exist
805 if (aa.load("tooltip")) {
806 idx = aa->GetRowCount();
807 while (idx--) {
808 ieResRef key;
809 int *tmppoi = (int *) malloc(sizeof(int)*3);
811 strnlwrcpy(key,aa->GetRowName(idx),8);
812 for (int i=0;i<3;i++) {
813 tmppoi[i] = atoi(aa->QueryField(idx,i));
815 ItemTooltipTable->SetAt(key, (void*)tmppoi);
818 return flag;
821 //Static
822 const char *Interface::GetDeathVarFormat()
824 return DeathVarFormat;
827 int Interface::GetItemExcl(const ieResRef itemname) const
829 ieDword value;
831 if (ItemExclTable && ItemExclTable->Lookup(itemname, value)) {
832 return (int) value;
834 return 0;
837 int Interface::GetItemTooltip(const ieResRef itemname, int header, int identified)
839 int *value = NULL;
841 if (ItemTooltipTable) {
842 void* lookup = NULL;
843 ItemTooltipTable->Lookup(itemname, lookup);
844 value = (int*)lookup;
846 if (value && (value[header]>=0)) {
847 return value[header];
849 Item *item = gamedata->GetItem(itemname);
850 if (!item) {
851 return -1;
853 int ret = identified?item->ItemNameIdentified:item->ItemName;
854 gamedata->FreeItem(item, itemname, 0);
855 return ret;
858 int Interface::GetItemDialStr(const ieResRef itemname) const
860 ieDword value;
862 if (ItemDialTable && ItemDialTable->Lookup(itemname, value)) {
863 return (int) value;
865 return -1;
868 //second value is the item dialog resource returned by this method
869 int Interface::GetItemDialRes(const ieResRef itemname, ieResRef retval) const
871 if (ItemDial2Table && ItemDial2Table->Lookup(itemname, retval, sizeof(ieResRef))) {
872 return 1;
874 return 0;
877 bool Interface::ReadAreaAliasTable(const ieResRef tablename)
879 if (AreaAliasTable) {
880 AreaAliasTable->RemoveAll(NULL);
881 } else {
882 AreaAliasTable = new Variables();
883 AreaAliasTable->SetType(GEM_VARIABLES_INT);
886 AutoTable aa(tablename);
887 if (!aa) {
888 //don't report error when the file doesn't exist
889 return true;
892 int idx = aa->GetRowCount();
893 while (idx--) {
894 ieResRef key;
896 strnlwrcpy(key,aa->GetRowName(idx),8);
897 ieDword value = atoi(aa->QueryField(idx,0));
898 AreaAliasTable->SetAt(key, value);
900 return true;
903 //this isn't const
904 int Interface::GetAreaAlias(const ieResRef areaname) const
906 ieDword value;
908 if (AreaAliasTable && AreaAliasTable->Lookup(areaname, value)) {
909 return (int) value;
911 return -1;
914 bool Interface::ReadMusicTable(const ieResRef tablename, int col) {
915 AutoTable tm(tablename);
916 if (!tm)
917 return false;
919 for (unsigned int i = 0; i < tm->GetRowCount(); i++) {
920 musiclist.push_back(strdup(tm->QueryField(i, col)));
923 return true;
926 bool Interface::ReadDamageTypeTable() {
927 AutoTable tm("dmgtypes");
928 if (!tm)
929 return false;
931 DamageInfoStruct di;
932 for (ieDword i = 0; i < tm->GetRowCount(); i++) {
933 di.strref = displaymsg->GetStringReference(atoi(tm->QueryField(i, 0)));
934 di.resist_stat = TranslateStat(tm->QueryField(i, 1));
935 di.value = strtol(tm->QueryField(i, 2), (char **) NULL, 16);
936 di.iwd_mod_type = atoi(tm->QueryField(i, 3));
937 DamageInfoMap.insert(std::make_pair <ieDword, DamageInfoStruct> ((ieDword)di.value, di));
940 return true;
943 bool Interface::ReadReputationModTable() {
944 AutoTable tm("reputati");
945 if (!tm)
946 return false;
948 reputationmod = (int **) calloc(21, sizeof(int *));
949 int cols = tm->GetColumnCount();
950 for (unsigned int i=0; i<20; i++) {
951 reputationmod[i] = (int *) calloc(cols, sizeof(int));
952 for (int j=0; j<cols; j++) {
953 reputationmod[i][j] = atoi(tm->QueryField(i, j));
957 return true;
960 bool Interface::ReadModalStates()
962 AutoTable table("modal");
963 if (!table)
964 return false;
966 ModalStatesStruct ms;
967 for (unsigned short i = 0; i < table->GetRowCount(); i++) {
968 strncpy(ms.spell, table->QueryField(i, 0), 8);
969 strncpy(ms.action, table->QueryField(i, 1), 16);
970 ms.entering_str = atoi(table->QueryField(i, 2));
971 ms.leaving_str = atoi(table->QueryField(i, 3));
972 ms.failed_str = atoi(table->QueryField(i, 4));
973 ms.aoe_spell = atoi(table->QueryField(i, 5));
974 ModalStates.push_back(ms);
977 return true;
980 //Not a constant anymore, we let the caller set the entry to zero
981 char *Interface::GetMusicPlaylist(int SongType) const {
982 if (SongType < 0 || (unsigned int)SongType >= musiclist.size())
983 return NULL;
985 return musiclist[SongType];
988 static const Color white = {0xff,0xff,0xff,0xff};
989 static const Color black = {0x00,0x00,0x00,0xff};
990 static const Region bg( 0, 0, 100, 30 );
992 /** this is the main loop */
993 void Interface::Main()
995 ieDword FullScreen = 0;
996 ieDword brightness = 10;
997 ieDword contrast = 5;
998 ieDword speed = 10;
1000 vars->Lookup("Full Screen", FullScreen);
1001 video->CreateDisplay( Width, Height, Bpp, FullScreen);
1002 video->SetDisplayTitle( GameName, GameType );
1003 vars->Lookup("Brightness Correction", brightness);
1004 vars->Lookup("Gamma Correction", contrast);
1005 vars->Lookup("Mouse Scroll Speed", speed);
1006 video->SetGamma(brightness, contrast);
1007 SetMouseScrollSpeed((int) speed);
1008 if (vars->Lookup("Tooltips", TooltipDelay)) {
1009 // the games store the slider position*10, not the actual delay
1010 TooltipDelay *= TOOLTIP_DELAY_FACTOR/10;
1013 Font* fps = GetFont( ( unsigned int ) 0 );
1014 char fpsstring[40]={"???.??? fps"};
1015 unsigned long frame = 0, time, timebase;
1016 GetTime(timebase);
1017 double frames = 0.0;
1018 Palette* palette = CreatePalette( white, black );
1019 do {
1020 //don't change script when quitting is pending
1022 while (QuitFlag) {
1023 HandleFlags();
1025 //eventflags are processed only when there is a game
1026 if (EventFlag && game) {
1027 HandleEvents();
1029 HandleGUIBehaviour();
1031 GameLoop();
1032 DrawWindows();
1033 if (DrawFPS) {
1034 frame++;
1035 GetTime( time );
1036 if (time - timebase > 1000) {
1037 frames = ( frame * 1000.0 / ( time - timebase ) );
1038 timebase = time;
1039 frame = 0;
1040 sprintf( fpsstring, "%.3f fps", frames );
1042 video->DrawRect( bg, black );
1043 fps->Print( bg,
1044 ( unsigned char * ) fpsstring, palette,
1045 IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_MIDDLE, true );
1047 } while (video->SwapBuffers() == GEM_OK);
1048 gamedata->FreePalette( palette );
1051 int Interface::ReadResRefTable(const ieResRef tablename, ieResRef *&data)
1053 int count = 0;
1055 if (data) {
1056 free(data);
1057 data = NULL;
1059 AutoTable tm(tablename);
1060 if (!tm) {
1061 printStatus( "ERROR", LIGHT_RED );
1062 printf( "Cannot find %s.2da.\n",tablename );
1063 return 0;
1065 count = tm->GetRowCount();
1066 data = (ieResRef *) calloc( count, sizeof(ieResRef) );
1067 for (int i = 0; i < count; i++) {
1068 strnlwrcpy( data[i], tm->QueryField( i, 0 ), 8 );
1069 //* marks an empty resource
1070 if (data[i][0]=='*') {
1071 data[i][0]=0;
1074 return count;
1077 int Interface::LoadSprites()
1079 ieDword i;
1080 int size;
1081 if (!IsAvailable( IE_2DA_CLASS_ID )) {
1082 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1083 return GEM_ERROR;
1086 //loading cursors
1087 AnimationFactory* anim;
1088 anim = (AnimationFactory*) gamedata->GetFactoryResource("cursors", IE_BAM_CLASS_ID);
1089 if (anim)
1091 CursorCount = anim->GetCycleCount();
1092 Cursors = new Sprite2D * [CursorCount];
1093 for (int i = 0; i < CursorCount; i++) {
1094 Cursors[i] = anim->GetFrame( 0, (ieByte) i );
1097 printMessage( "Core", "Loading Cursors...", WHITE );
1099 // this is the last existing cursor type
1100 if (CursorCount<IE_CURSOR_WAY) {
1101 printStatus( "ERROR", LIGHT_RED );
1102 return GEM_ERROR;
1104 video->SetCursor( Cursors[0], Cursors[1] );
1105 printStatus( "OK", LIGHT_GREEN );
1107 // Load fog-of-war bitmaps
1108 anim = (AnimationFactory*) gamedata->GetFactoryResource("fogowar", IE_BAM_CLASS_ID);
1109 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE );
1110 if (!anim || anim->GetCycleSize( 0 ) != 8) {
1111 // unknown type of fog anim
1112 printStatus( "ERROR", LIGHT_RED );
1113 return GEM_ERROR;
1116 FogSprites[0] = NULL;
1117 FogSprites[1] = anim->GetFrame( 0, 0 );
1118 FogSprites[2] = anim->GetFrame( 1, 0 );
1119 FogSprites[3] = anim->GetFrame( 2, 0 );
1121 FogSprites[4] = video->MirrorSpriteVertical( FogSprites[1], false );
1123 FogSprites[5] = NULL;
1125 FogSprites[6] = video->MirrorSpriteVertical( FogSprites[3], false );
1127 FogSprites[7] = NULL;
1129 FogSprites[8] = video->MirrorSpriteHorizontal( FogSprites[2], false );
1131 FogSprites[9] = video->MirrorSpriteHorizontal( FogSprites[3], false );
1133 FogSprites[10] = NULL;
1134 FogSprites[11] = NULL;
1136 FogSprites[12] = video->MirrorSpriteHorizontal( FogSprites[6], false );
1138 FogSprites[16] = anim->GetFrame( 3, 0 );
1139 FogSprites[17] = anim->GetFrame( 4, 0 );
1140 FogSprites[18] = anim->GetFrame( 5, 0 );
1141 FogSprites[19] = anim->GetFrame( 6, 0 );
1143 FogSprites[20] = video->MirrorSpriteVertical( FogSprites[17], false );
1145 FogSprites[21] = NULL;
1147 FogSprites[23] = NULL;
1149 FogSprites[24] = video->MirrorSpriteHorizontal( FogSprites[18], false );
1151 FogSprites[25] = anim->GetFrame( 7, 0 );
1154 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[25], false );
1155 FogSprites[22] = video->MirrorSpriteHorizontal( tmpsprite, false );
1156 video->FreeSprite( tmpsprite );
1159 FogSprites[26] = NULL;
1160 FogSprites[27] = NULL;
1163 Sprite2D *tmpsprite = video->MirrorSpriteVertical( FogSprites[19], false );
1164 FogSprites[28] = video->MirrorSpriteHorizontal( tmpsprite, false );
1165 video->FreeSprite( tmpsprite );
1168 i = 0;
1169 vars->Lookup("3D Acceleration", i);
1170 if (i) {
1171 for(i=0;i<sizeof(FogSprites)/sizeof(Sprite2D *);i++ ) {
1172 if (FogSprites[i]) {
1173 Sprite2D* alphasprite = video->CreateAlpha( FogSprites[i] );
1174 video->FreeSprite ( FogSprites[i] );
1175 FogSprites[i] = alphasprite;
1180 printStatus( "OK", LIGHT_GREEN );
1182 // Load ground circle bitmaps (PST only)
1183 //block required due to msvc6.0 incompatibility
1184 for (size = 0; size < MAX_CIRCLE_SIZE; size++) {
1185 if (GroundCircleBam[size][0]) {
1186 anim = (AnimationFactory*) gamedata->GetFactoryResource(GroundCircleBam[size], IE_BAM_CLASS_ID);
1187 if (!anim || anim->GetCycleCount() != 6) {
1188 // unknown type of circle anim
1189 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1190 printStatus( "ERROR", LIGHT_RED );
1191 return GEM_ERROR;
1194 for (int i = 0; i < 6; i++) {
1195 Sprite2D* sprite = anim->GetFrame( 0, (ieByte) i );
1196 if (GroundCircleScale[size]) {
1197 GroundCircles[size][i] = video->SpriteScaleDown( sprite, GroundCircleScale[size] );
1198 video->FreeSprite( sprite );
1199 } else {
1200 GroundCircles[size][i] = sprite;
1206 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE );
1207 printStatus( "OK", LIGHT_GREEN );
1209 printMessage( "Core", "Loading Fonts...\n", WHITE );
1210 AutoTable tab("fonts");
1211 if (!tab) {
1212 printStatus( "ERROR", LIGHT_RED );
1213 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1214 return GEM_ERROR;
1215 } else {
1216 PluginHolder<AnimationMgr> bamint(IE_BAM_CLASS_ID);
1217 if (!bamint) {
1218 printStatus( "ERROR", LIGHT_RED );
1219 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1220 return GEM_ERROR;
1222 DataStream* str = NULL;
1224 int count = tab->GetRowCount();
1225 for (int i = 0; i < count; i++) {
1226 const char* ResRef = tab->QueryField( i, 0 );
1227 int needpalette = atoi( tab->QueryField( i, 1 ) );
1228 int first_char = atoi( tab->QueryField( i, 2 ) );
1229 str = gamedata->GetResource( ResRef, IE_BAM_CLASS_ID );
1230 if (!bamint->Open( str, true )) {
1231 continue;
1233 Font* fnt = bamint->GetFont();
1234 if (!fnt) {
1235 continue;
1237 strnlwrcpy( fnt->ResRef, ResRef, 8 );
1238 if (needpalette) {
1240 Color fore = {0xff, 0xff, 0xff, 0};
1241 Color back = {0x00, 0x00, 0x00, 0};
1242 if (!strnicmp( TooltipFont, ResRef, 8) ) {
1243 if (TooltipColor.a==0xff) {
1244 fore = TooltipColor;
1245 } else {
1246 fore = back;
1247 back = TooltipColor;
1250 Palette* pal = CreatePalette( fore, back );
1251 pal->CreateShadedAlphaChannel();
1252 fnt->SetPalette(pal);
1253 gamedata->FreePalette( pal );
1255 fnt->SetFirstChar( (ieByte) first_char );
1256 fonts.push_back( fnt );
1259 if (fonts.size() == 0) {
1260 printMessage( "Core", "No default font loaded! ", WHITE );
1261 printStatus( "ERROR", LIGHT_RED );
1262 return GEM_ERROR;
1264 if (GetFont( ButtonFont ) == NULL) {
1265 printMessage( "Core", "ButtonFont not loaded: ", WHITE );
1266 printf("%s ", ButtonFont);
1267 printStatus( "WARNING", YELLOW );
1269 if (GetFont( MovieFont ) == NULL) {
1270 printMessage( "Core", "MovieFont not loaded: ", WHITE );
1271 printf("%s ", MovieFont);
1272 printStatus( "WARNING", YELLOW );
1274 if (GetFont( TooltipFont ) == NULL) {
1275 printMessage( "Core", "TooltipFont not loaded: ", WHITE );
1276 printf("%s ", TooltipFont);
1277 printStatus( "WARNING", YELLOW );
1280 printMessage( "Core", "Fonts Loaded...", WHITE );
1281 printStatus( "OK", LIGHT_GREEN );
1283 if (TooltipBackResRef[0]) {
1284 anim = (AnimationFactory*) gamedata->GetFactoryResource(TooltipBackResRef, IE_BAM_CLASS_ID);
1285 printMessage( "Core", "Initializing Tooltips...", WHITE );
1286 if (!anim) {
1287 printStatus( "ERROR", LIGHT_RED );
1288 return GEM_ERROR;
1290 TooltipBack = new Sprite2D * [3];
1291 for (int i = 0; i < 3; i++) {
1292 TooltipBack[i] = anim->GetFrame( 0, (ieByte) i );
1293 TooltipBack[i]->XPos = 0;
1294 TooltipBack[i]->YPos = 0;
1296 printStatus( "OK", LIGHT_GREEN );
1299 return GEM_OK;
1302 int Interface::Init()
1304 plugin_flags = new Variables();
1305 plugin_flags->SetType( GEM_VARIABLES_INT );
1307 printMessage( "Core", "Initializing the Event Manager...", WHITE );
1308 evntmgr = new EventMgr();
1310 printMessage( "Core", "Initializing Lists Dictionary...", WHITE );
1311 lists = new Variables();
1312 if (!lists) {
1313 printStatus( "ERROR", LIGHT_RED );
1314 return GEM_ERROR;
1316 lists->SetType( GEM_VARIABLES_POINTER );
1318 printMessage( "Core", "Initializing Variables Dictionary...", WHITE );
1319 vars = new Variables();
1320 if (!vars) {
1321 printStatus( "ERROR", LIGHT_RED );
1322 return GEM_ERROR;
1324 vars->SetType( GEM_VARIABLES_INT );
1325 vars->ParseKey(true);
1327 vars->SetAt( "Volume Ambients", 100 );
1328 vars->SetAt( "Volume Movie", 100 );
1329 vars->SetAt( "Volume Music", 100 );
1330 vars->SetAt( "Volume SFX", 100 );
1331 vars->SetAt( "Volume Voices", 100 );
1332 printStatus( "OK", LIGHT_GREEN );
1334 if (!LoadConfig()) {
1335 return GEM_ERROR;
1337 printMessage( "Core", "Starting Plugin Manager...\n", WHITE );
1338 PluginMgr *plugin = PluginMgr::Get();
1339 plugin->LoadPlugins(PluginsPath);
1340 if (plugin && plugin->GetPluginCount()) {
1341 printMessage( "Core", "Plugin Loading Complete...", WHITE );
1342 printStatus( "OK", LIGHT_GREEN );
1343 } else {
1344 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW);
1345 printStatus( "ERROR", LIGHT_RED );
1346 return GEM_ERROR;
1348 plugin->RunInitializers();
1350 time_t t;
1351 t = time( NULL );
1352 srand( ( unsigned int ) t );
1353 #ifdef _DEBUG
1354 FileStreamPtrCount = 0;
1355 CachedFileStreamPtrCount = 0;
1356 #endif
1357 printMessage( "Core", "GemRB Core Initialization...\n", WHITE );
1358 printStatus( "OK", LIGHT_GREEN );
1359 printMessage( "Core", "Initializing Video Driver...", WHITE );
1360 video = ( Video * ) PluginMgr::Get()->GetDriver(&Video::ID, VideoDriverName.c_str());
1361 if (!video) {
1362 printStatus( "ERROR", LIGHT_RED );
1363 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1364 return GEM_ERROR;
1366 if (video->Init() == GEM_ERROR) {
1367 printStatus( "ERROR", LIGHT_RED );
1368 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1369 return GEM_ERROR;
1371 Color defcolor={255,255,255,200};
1372 SetInfoTextColor(defcolor);
1373 printStatus( "OK", LIGHT_GREEN );
1376 printMessage( "Core", "Initializing Search Path...", WHITE );
1377 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY )) {
1378 printf( "no DirectoryImporter! " );
1379 printStatus( "ERROR", LIGHT_RED );
1380 return GEM_ERROR;
1383 char path[_MAX_PATH];
1385 PathJoin( path, CachePath, NULL);
1386 gamedata->AddSource(path, "Cache", PLUGIN_RESOURCE_DIRECTORY);
1388 PathJoin( path, GemRBOverridePath, "override", GameType, NULL);
1389 gamedata->AddSource(path, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1391 size_t i;
1392 for (i = 0; i < ModPath.size(); ++i)
1393 gamedata->AddSource(ModPath[i].c_str(), "Mod paths", PLUGIN_RESOURCE_DIRECTORY);
1395 PathJoin( path, GemRBOverridePath, "override", "shared", NULL);
1396 gamedata->AddSource(path, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY);
1398 PathJoin( path, GamePath, GameOverridePath, NULL);
1399 gamedata->AddSource(path, "Override", PLUGIN_RESOURCE_DIRECTORY);
1401 PathJoin( path, GamePath, GameSoundsPath, NULL);
1402 gamedata->AddSource(path, "Sounds", PLUGIN_RESOURCE_DIRECTORY);
1404 PathJoin( path, GamePath, GameScriptsPath, NULL);
1405 gamedata->AddSource(path, "Scripts", PLUGIN_RESOURCE_DIRECTORY);
1407 PathJoin( path, GamePath, GamePortraitsPath, NULL);
1408 gamedata->AddSource(path, "Portraits", PLUGIN_RESOURCE_DIRECTORY);
1410 PathJoin( path, GamePath, GameDataPath, NULL);
1411 gamedata->AddSource(path, "Data", PLUGIN_RESOURCE_DIRECTORY);
1413 //IWD2 movies are on the CD but not in the BIF
1414 for (i = 0; i < MAX_CD; i++) {
1415 for (size_t j=0;j<CD[i].size();j++) {
1416 char description[] = {'C', 'D', '1'+i, '/', 'd', 'a', 't', 'a', '\0'};
1417 PathJoin( path, CD[i][j].c_str(), GameDataPath, NULL);
1418 gamedata->AddSource(path, description, PLUGIN_RESOURCE_DIRECTORY);
1422 printStatus( "OK", LIGHT_GREEN );
1426 printMessage( "Core", "Initializing KEY Importer...", WHITE );
1427 char ChitinPath[_MAX_PATH];
1428 PathJoin( ChitinPath, GamePath, "chitin.key", NULL );
1429 if (!gamedata->AddSource(ChitinPath, "chitin.key", PLUGIN_RESOURCE_KEY)) {
1430 printStatus( "ERROR", LIGHT_RED );
1431 return GEM_ERROR;
1433 printStatus( "OK", LIGHT_GREEN );
1436 printMessage( "Core", "Reading Game Options...\n", WHITE );
1437 if (!LoadGemRBINI())
1439 printf( "Cannot Load INI\nTermination in Progress...\n" );
1440 return GEM_ERROR;
1443 //loading baldur.ini
1445 char ini_path[_MAX_PATH];
1446 PathJoin( ini_path, GamePath, INIConfig, NULL );
1447 LoadINI( ini_path );
1448 int i;
1449 for (i = 0; i < 8; i++) {
1450 if (INIConfig[i] == '.')
1451 break;
1452 GameNameResRef[i] = INIConfig[i];
1454 GameNameResRef[i] = 0;
1457 printMessage( "Core", "Creating Projectile Server...\n", WHITE );
1458 projserv = new ProjectileServer();
1459 if (!projserv->GetHighestProjectileNumber()) {
1460 printStatus( "ERROR", LIGHT_RED );
1461 printf( "No projectiles are available...\n" );
1464 printMessage( "Core", "Checking for Dialogue Manager...", WHITE );
1465 if (!IsAvailable( IE_TLK_CLASS_ID )) {
1466 printStatus( "ERROR", LIGHT_RED );
1467 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1468 return GEM_ERROR;
1470 printStatus( "OK", LIGHT_GREEN );
1471 strings = PluginHolder<StringMgr>(IE_TLK_CLASS_ID);
1472 printMessage( "Core", "Loading Dialog.tlk file...", WHITE );
1473 char strpath[_MAX_PATH];
1474 PathJoin( strpath, GamePath, dialogtlk, NULL );
1475 FileStream* fs = new FileStream();
1476 if (!fs->Open( strpath, true )) {
1477 printStatus( "ERROR", LIGHT_RED );
1478 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1479 delete fs;
1480 return GEM_ERROR;
1482 printStatus( "OK", LIGHT_GREEN );
1483 strings->Open( fs, true );
1486 printMessage( "Core", "Loading Palettes...\n", WHITE );
1487 ResourceHolder<ImageMgr> pal16im(Palette16);
1488 if (pal16im)
1489 pal16 = pal16im->GetImage();
1490 ResourceHolder<ImageMgr> pal32im(Palette32);
1491 if (pal32im)
1492 pal32 = pal32im->GetImage();
1493 ResourceHolder<ImageMgr> pal256im(Palette256);
1494 if (pal256im)
1495 pal256 = pal256im->GetImage();
1496 if (!pal16 || !pal32 || !pal256) {
1497 printStatus( "ERROR", LIGHT_RED );
1498 return GEM_ERROR;
1500 printMessage( "Core", "Palettes Loaded\n", WHITE );
1503 if (!IsAvailable( IE_BAM_CLASS_ID )) {
1504 printStatus( "ERROR", LIGHT_RED );
1505 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1506 return GEM_ERROR;
1509 printMessage( "Core", "Initializing stock sounds...\n", WHITE );
1510 DSCount = ReadResRefTable ("defsound", DefSound);
1511 if (DSCount == 0) {
1512 printStatus( "ERROR", LIGHT_RED );
1513 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1514 return GEM_ERROR;
1517 printStatus( "OK", LIGHT_GREEN );
1518 printMessage( "Core", "Broadcasting Event Manager...", WHITE );
1519 video->SetEventMgr( evntmgr );
1520 printStatus( "OK", LIGHT_GREEN );
1521 printMessage( "Core", "Initializing Window Manager...", WHITE );
1522 windowmgr = PluginHolder<WindowMgr>(IE_CHU_CLASS_ID);
1523 if (windowmgr == NULL) {
1524 printStatus( "ERROR", LIGHT_RED );
1525 return GEM_ERROR;
1527 printStatus( "OK", LIGHT_GREEN );
1528 printMessage( "Core", "Initializing GUI Script Engine...", WHITE );
1529 guiscript = PluginHolder<ScriptEngine>(IE_GUI_SCRIPT_CLASS_ID);
1530 if (guiscript == NULL) {
1531 printStatus( "ERROR", LIGHT_RED );
1532 return GEM_ERROR;
1534 if (!guiscript->Init()) {
1535 printStatus( "ERROR", LIGHT_RED );
1536 return GEM_ERROR;
1538 printStatus( "OK", LIGHT_GREEN );
1539 strcpy( NextScript, "Start" );
1541 int ret = LoadSprites();
1542 if (ret) return ret;
1544 printMessage( "Core", "Setting up the Console...", WHITE );
1545 QuitFlag = QF_CHANGESCRIPT;
1546 console = new Console();
1547 console->XPos = 0;
1548 console->YPos = (ieWord) (Height - 25);
1549 console->Width = (ieWord) Width;
1550 console->Height = 25;
1551 if (fonts.size() > 0) {
1552 console->SetFont( fonts[0] );
1555 Sprite2D *tmpsprite = GetCursorSprite();
1556 if (!tmpsprite) {
1557 printStatus( "ERROR", LIGHT_RED );
1558 return GEM_ERROR;
1560 console->SetCursor (tmpsprite);
1561 printStatus( "OK", LIGHT_GREEN );
1563 printMessage( "Core", "Starting up the Sound Driver...", WHITE );
1564 AudioDriver = ( Audio * ) PluginMgr::Get()->GetDriver(&Audio::ID, AudioDriverName.c_str());
1565 if (AudioDriver == NULL) {
1566 printStatus( "ERROR", LIGHT_RED );
1567 return GEM_ERROR;
1569 if (!AudioDriver->Init()) {
1570 printStatus( "ERROR", LIGHT_RED );
1571 return GEM_ERROR;
1573 printStatus( "OK", LIGHT_GREEN );
1575 printMessage( "Core", "Allocating SaveGameIterator...", WHITE );
1576 sgiterator = new SaveGameIterator();
1577 if (sgiterator == NULL) {
1578 printStatus( "ERROR", LIGHT_RED );
1579 return GEM_ERROR;
1581 printStatus( "OK", LIGHT_GREEN );
1583 //no need of strdup, variables do copy the key!
1584 vars->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos );
1585 vars->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements );
1587 printMessage( "Core", "Initializing Token Dictionary...", WHITE );
1588 tokens = new Variables();
1589 if (!tokens) {
1590 printStatus( "ERROR", LIGHT_RED );
1591 return GEM_ERROR;
1593 tokens->SetType( GEM_VARIABLES_STRING );
1594 printStatus( "OK", LIGHT_GREEN );
1596 printMessage( "Core", "Initializing Music Manager...", WHITE );
1597 music = PluginHolder<MusicMgr>(IE_MUS_CLASS_ID);
1598 if (!music) {
1599 printStatus( "ERROR", LIGHT_RED );
1600 return GEM_ERROR;
1602 printStatus( "OK", LIGHT_GREEN );
1604 printMessage("Core", "Loading music list...\n", WHITE );
1605 if (HasFeature( GF_HAS_SONGLIST )) {
1606 ret = ReadMusicTable("songlist", 1);
1607 } else {
1608 /*since bg1 and pst has no .2da for songlist,
1609 we must supply one in the gemrb/override folder.
1610 It should be: music.2da, first column is a .mus filename*/
1611 ret = ReadMusicTable("music", 0);
1613 if (ret) {
1614 printStatus( "OK", LIGHT_GREEN );
1615 } else {
1616 printStatus( "NOT FOUND", YELLOW );
1619 if (HasFeature( GF_RESDATA_INI )) {
1620 printMessage( "Core", "Loading resource data File...", WHITE );
1621 INIresdata = PluginHolder<DataFileMgr>(IE_INI_CLASS_ID);
1622 DataStream* ds = gamedata->GetResource("resdata", IE_INI_CLASS_ID);
1623 if (!INIresdata->Open( ds, true )) {
1624 printStatus( "ERROR", LIGHT_RED );
1625 } else {
1626 printStatus( "OK", LIGHT_GREEN );
1630 if (HasFeature( GF_HAS_PARTY_INI )) {
1631 printMessage( "Core", "Loading precreated teams setup...\n",
1632 WHITE );
1633 INIparty = PluginHolder<DataFileMgr>(IE_INI_CLASS_ID);
1634 FileStream* fs = new FileStream();
1635 char tINIparty[_MAX_PATH];
1636 PathJoin( tINIparty, GamePath, "Party.ini", NULL );
1637 fs->Open( tINIparty, true );
1638 if (!INIparty->Open( fs, true )) {
1639 printStatus( "ERROR", LIGHT_RED );
1640 } else {
1641 printStatus( "OK", LIGHT_GREEN );
1645 if (HasFeature(GF_IWD2_DEATHVARFORMAT)) {
1646 memcpy(DeathVarFormat, IWD2DeathVarFormat, sizeof(ieVariable));
1649 if (HasFeature( GF_HAS_BEASTS_INI )) {
1650 printMessage( "Core", "Loading beasts definition File...\n",
1651 WHITE );
1652 INIbeasts = PluginHolder<DataFileMgr>(IE_INI_CLASS_ID);
1653 FileStream* fs = new FileStream();
1654 char tINIbeasts[_MAX_PATH];
1655 PathJoin( tINIbeasts, GamePath, "beast.ini", NULL );
1656 // FIXME: crashes if file does not open
1657 fs->Open( tINIbeasts, true );
1658 if (!INIbeasts->Open( fs, true )) {
1659 printStatus( "ERROR", LIGHT_RED );
1660 } else {
1661 printStatus( "OK", LIGHT_GREEN );
1664 printMessage( "Core", "Loading quests definition File...\n",
1665 WHITE );
1666 INIquests = PluginHolder<DataFileMgr>(IE_INI_CLASS_ID);
1667 FileStream* fs2 = new FileStream();
1668 char tINIquests[_MAX_PATH];
1669 PathJoin( tINIquests, GamePath, "quests.ini", NULL );
1670 // FIXME: crashes if file does not open
1671 fs2->Open( tINIquests, true );
1672 if (!INIquests->Open( fs2, true )) {
1673 printStatus( "ERROR", LIGHT_RED );
1674 } else {
1675 printStatus( "OK", LIGHT_GREEN );
1678 game = NULL;
1679 calendar = NULL;
1681 timer = new GlobalTimer();
1682 printMessage( "Core", "Bringing up the Global Timer...", WHITE );
1683 if (!timer) {
1684 printStatus( "ERROR", LIGHT_RED );
1685 return GEM_ERROR;
1687 printStatus( "OK", LIGHT_GREEN );
1689 ret = Init_EffectQueue();
1690 printMessage( "Core", "Initializing effects...", WHITE );
1691 if (!ret) {
1692 printStatus( "ERROR", LIGHT_RED );
1693 return GEM_ERROR;
1695 printStatus( "OK", LIGHT_GREEN );
1697 ret = InitItemTypes();
1698 printMessage( "Core", "Initializing Inventory Management...", WHITE );
1699 if (!ret) {
1700 printStatus( "ERROR", LIGHT_RED );
1701 return GEM_ERROR;
1703 printStatus( "OK", LIGHT_GREEN );
1705 displaymsg = new DisplayMessage();
1706 printMessage( "Core", "Initializing string constants...", WHITE );
1707 if (!displaymsg) {
1708 printStatus( "ERROR", LIGHT_RED );
1709 return GEM_ERROR;
1711 printStatus( "OK", LIGHT_GREEN );
1713 ret = ReadRandomItems();
1714 printMessage( "Core", "Initializing random treasure...", WHITE );
1715 if (ret) {
1716 printStatus( "OK", LIGHT_GREEN );
1718 else {
1719 printStatus( "ERROR", LIGHT_RED );
1722 ret = ReadAbilityTables();
1723 printMessage( "Core", "Initializing ability tables...", WHITE );
1724 if (!ret) {
1725 printStatus( "ERROR", LIGHT_RED );
1726 return GEM_ERROR;
1728 printStatus( "OK", LIGHT_GREEN );
1730 ret = ReadReputationModTable();
1731 printMessage( "Core", "Reading reputation mod table...", WHITE);
1732 if (ret) {
1733 printStatus( "OK", LIGHT_GREEN );
1734 } else {
1735 printStatus( "NOT FOUND", LIGHT_RED );
1738 if ( gamedata->Exists("WMAPLAY", IE_2DA_CLASS_ID) ) {
1739 ret = ReadAreaAliasTable( "WMAPLAY" );
1740 printMessage( "Core", "Initializing area aliases...", WHITE );
1741 if (ret) {
1742 printStatus( "OK", LIGHT_GREEN );
1744 else {
1745 printStatus( "NOT FOUND", YELLOW );
1749 ret = ReadGameTimeTable();
1750 printMessage( "Core", "Reading game time table...", WHITE);
1751 if (!ret) {
1752 printStatus( "ERROR", LIGHT_RED );
1753 return GEM_ERROR;
1755 printStatus( "OK", LIGHT_GREEN );
1757 ret = ReadAuxItemTables();
1758 printMessage( "Core", "Reading item tables...", WHITE);
1759 if (!ret) {
1760 printStatus( "ERROR", LIGHT_RED );
1761 return GEM_ERROR;
1763 printStatus( "OK", LIGHT_GREEN );
1765 ret = ReadDamageTypeTable();
1766 printMessage( "Core", "Reading damage type table...", WHITE);
1767 if (!ret) {
1768 printStatus( "ERROR", LIGHT_RED );
1769 } else {
1770 printStatus( "OK", LIGHT_GREEN );
1773 ret = ReadModalStates();
1774 printMessage( "Core", "Reading modal states table...", WHITE);
1775 if (!ret) {
1776 printStatus( "ERROR", LIGHT_RED );
1777 return GEM_ERROR;
1778 } else {
1779 printStatus( "OK", LIGHT_GREEN );
1782 printMessage( "Core", "Reading game script tables...", WHITE);
1783 InitializeIEScript();
1784 printStatus( "OK", LIGHT_GREEN );
1786 printMessage( "Core", "Core Initialization Complete!\n", WHITE );
1788 return GEM_OK;
1791 bool Interface::IsAvailable(SClass_ID filetype) const
1793 return PluginMgr::Get()->IsAvailable( filetype );
1796 WorldMap *Interface::GetWorldMap(const char *map)
1798 int index = worldmap->FindAndSetCurrentMap(map?map:game->CurrentArea);
1799 return worldmap->GetWorldMap(index);
1802 ProjectileServer* Interface::GetProjectileServer() const
1804 return projserv;
1807 Video* Interface::GetVideoDriver() const
1809 return video.get();
1812 Audio* Interface::GetAudioDrv(void) const {
1813 return AudioDriver.get();
1816 const char* Interface::TypeExt(SClass_ID type) const
1818 switch (type) {
1819 case IE_2DA_CLASS_ID:
1820 return ".2da";
1822 case IE_ACM_CLASS_ID:
1823 return ".acm";
1825 case IE_ARE_CLASS_ID:
1826 return ".are";
1828 case IE_BAM_CLASS_ID:
1829 return ".bam";
1831 case IE_BCS_CLASS_ID:
1832 return ".bcs";
1834 case IE_BS_CLASS_ID:
1835 return ".bs";
1837 case IE_BIF_CLASS_ID:
1838 return ".bif";
1840 case IE_BIO_CLASS_ID:
1841 if (HasFeature(GF_BIOGRAPHY_RES)) {
1842 return ".res";
1844 return ".bio";
1846 case IE_BMP_CLASS_ID:
1847 return ".bmp";
1849 case IE_PNG_CLASS_ID:
1850 return ".png";
1852 case IE_CHR_CLASS_ID:
1853 return ".chr";
1855 case IE_CHU_CLASS_ID:
1856 return ".chu";
1858 case IE_CRE_CLASS_ID:
1859 return ".cre";
1861 case IE_DLG_CLASS_ID:
1862 return ".dlg";
1864 case IE_EFF_CLASS_ID:
1865 return ".eff";
1867 case IE_GAM_CLASS_ID:
1868 return ".gam";
1870 case IE_IDS_CLASS_ID:
1871 return ".ids";
1873 case IE_INI_CLASS_ID:
1874 return ".ini";
1876 case IE_ITM_CLASS_ID:
1877 return ".itm";
1879 case IE_MOS_CLASS_ID:
1880 return ".mos";
1882 case IE_MUS_CLASS_ID:
1883 return ".mus";
1885 case IE_MVE_CLASS_ID:
1886 return ".mve";
1888 case IE_OGG_CLASS_ID:
1889 return ".ogg";
1891 case IE_PLT_CLASS_ID:
1892 return ".plt";
1894 case IE_PRO_CLASS_ID:
1895 return ".pro";
1897 case IE_SAV_CLASS_ID:
1898 return ".sav";
1900 case IE_SPL_CLASS_ID:
1901 return ".spl";
1903 case IE_SRC_CLASS_ID:
1904 return ".src";
1906 case IE_STO_CLASS_ID:
1907 return ".sto";
1909 case IE_TIS_CLASS_ID:
1910 return ".tis";
1912 case IE_TLK_CLASS_ID:
1913 return ".tlk";
1915 case IE_TOH_CLASS_ID:
1916 return ".toh";
1918 case IE_TOT_CLASS_ID:
1919 return ".tot";
1921 case IE_VAR_CLASS_ID:
1922 return ".var";
1924 case IE_VVC_CLASS_ID:
1925 return ".vvc";
1927 case IE_WAV_CLASS_ID:
1928 return ".wav";
1930 case IE_WED_CLASS_ID:
1931 return ".wed";
1933 case IE_WFX_CLASS_ID:
1934 return ".wfx";
1936 case IE_WMP_CLASS_ID:
1937 return ".wmp";
1939 return NULL;
1942 void Interface::FreeString(char *&str) const
1944 if (str) {
1945 strings->FreeString(str);
1947 str = NULL;
1950 ieStrRef Interface::UpdateString(ieStrRef strref, const char *text) const
1952 return strings->UpdateString( strref, text );
1955 char* Interface::GetString(ieStrRef strref, ieDword options) const
1957 ieDword flags = 0;
1959 if (!(options & IE_STR_STRREFOFF)) {
1960 vars->Lookup( "Strref On", flags );
1962 return strings->GetString( strref, flags | options );
1965 void Interface::SetFeature(int flag, int position)
1967 if (flag) {
1968 GameFeatures[position>>5] |= 1<<(position&31);
1969 } else {
1970 GameFeatures[position>>5] &= ~(1<<(position&31) );
1973 if (position>=32) {
1974 position-=32;
1975 if (flag) {
1976 GameFeatures2 |= 1 << position;
1977 } else {
1978 GameFeatures2 &= ~( 1 << position );
1980 return;
1982 if (flag) {
1983 GameFeatures |= 1 << position;
1984 } else {
1985 GameFeatures &= ~( 1 << position );
1990 ieDword Interface::HasFeature(int position) const
1992 return GameFeatures[position>>5] & (1<<(position&31));
1994 if (position>=64) {
1995 return GameFeatures3 & ( 1 << (position-64) );
1997 if (position>=32) {
1998 return GameFeatures2 & ( 1 << (position-32) );
2000 return GameFeatures & ( 1 << position );
2004 /** Search directories and load a config file */
2005 bool Interface::LoadConfig(void)
2007 #ifndef WIN32
2008 char path[_MAX_PATH];
2009 char name[_MAX_PATH];
2011 // Find directory where user stores GemRB configurations (~/.gemrb).
2012 // FIXME: Create it if it does not exist
2013 // Use current dir if $HOME is not defined (or bomb out??)
2015 char* s = getenv( "HOME" );
2016 if (s) {
2017 strcpy( UserDir, s );
2018 strcat( UserDir, "/."PACKAGE"/" );
2019 } else {
2020 strcpy( UserDir, "./" );
2023 // Find basename of this program. It does the same as basename (3),
2024 // but that's probably missing on some archs
2025 s = strrchr( argv[0], PathDelimiter );
2026 if (s) {
2027 s++;
2028 } else {
2029 s = argv[0];
2032 strcpy( name, s );
2033 //if (!name[0]) // FIXME: could this happen?
2034 // strcpy (name, PACKAGE); // ugly hack
2036 // If we were called as $0 -c <filename>, load config from filename
2037 if (argc > 2 && ! strcmp("-c", argv[1])) {
2038 if (LoadConfig( argv[2] )) {
2039 return true;
2040 } else {
2041 // Explicitly specified cfg file HAS to be present
2042 return false;
2046 // FIXME: temporary hack, to be deleted??
2047 if (LoadConfig( "GemRB.cfg" )) {
2048 return true;
2051 PathJoin( path, UserDir, name, NULL );
2052 strcat( path, ".cfg" );
2054 if (LoadConfig( path )) {
2055 return true;
2058 #ifdef SYSCONFDIR
2059 PathJoin( path, SYSCONFDIR, name, NULL );
2060 strcat( path, ".cfg" );
2062 if (LoadConfig( path )) {
2063 return true;
2065 #endif
2067 // Don't try with default binary name if we have tried it already
2068 if (!strcmp( name, PACKAGE )) {
2069 return false;
2072 PathJoin( path, UserDir, PACKAGE, NULL );
2073 strcat( path, ".cfg" );
2075 if (LoadConfig( path )) {
2076 return true;
2079 #ifdef SYSCONFDIR
2080 PathJoin( path, SYSCONFDIR, PACKAGE, NULL );
2081 strcat( path, ".cfg" );
2083 if (LoadConfig( path )) {
2084 return true;
2086 #endif
2088 return false;
2089 #else // WIN32
2090 // If we were called as $0 -c <filename>, load config from filename
2091 if (argc > 2 && ! strcmp("-c", argv[1])) {
2092 return LoadConfig( argv[2] );
2093 // Explicitly specified cfg file HAS to be present
2095 strcpy( UserDir, ".\\" );
2096 return LoadConfig( "GemRB.cfg" );
2097 #endif// WIN32
2100 bool Interface::LoadConfig(const char* filename)
2102 FILE* config;
2103 size_t i;
2105 printMessage("Config","Trying to open ", WHITE);
2106 textcolor(LIGHT_WHITE);
2107 printf("%s ", filename);
2108 config = fopen( filename, "rb" );
2109 if (config == NULL) {
2110 printStatus("NOT FOUND", LIGHT_RED);
2111 return false;
2113 char name[65], value[_MAX_PATH + 3];
2115 //once GemRB own format is working well, this might be set to 0
2116 SaveAsOriginal = 1;
2118 while (!feof( config )) {
2119 char rem;
2121 if (fread( &rem, 1, 1, config ) != 1)
2122 break;
2124 if (rem == '#') {
2125 //it should always return 0
2126 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
2127 break;
2128 continue;
2130 fseek( config, -1, SEEK_CUR );
2131 memset(value,'\0',_MAX_PATH + 3);
2132 //the * element is not counted
2133 if (fscanf( config, "%64[^= ] = %[^\r\n]%*[\r\n]", name, value )!=2)
2134 continue;
2135 for (i=_MAX_PATH + 2; i > 0; i--) {
2136 if (value[i] == '\0') continue;
2137 if (value[i] == ' ') {
2138 value[i] = '\0';
2139 } else {
2140 break;
2144 if (false) {
2145 #define CONFIG_INT(str, var) \
2146 } else if (stricmp(name, str) == 0) { \
2147 var ( atoi(value) )
2148 CONFIG_INT("Bpp", Bpp = );
2149 CONFIG_INT("CaseSensitive", CaseSensitive = );
2150 CONFIG_INT("DoubleClickDelay", evntmgr->SetDCDelay);
2151 CONFIG_INT("DrawFPS", DrawFPS = );
2152 CONFIG_INT("EnableCheatKeys", EnableCheatKeys);
2153 CONFIG_INT("EndianSwitch", DataStream::SetEndianSwitch);
2154 CONFIG_INT("FogOfWar", FogOfWar = );
2155 //CONFIG_INT("FullScreen", FullScreen = );
2156 CONFIG_INT("GUIEnhancements", GUIEnhancements = );
2157 CONFIG_INT("GameOnCD", GameOnCD = );
2158 CONFIG_INT("Height", Height = );
2159 CONFIG_INT("KeepCache", KeepCache = );
2160 CONFIG_INT("MultipleQuickSaves", GameControl::MultipleQuickSaves);
2161 CONFIG_INT("RepeatKeyDelay", evntmgr->SetRKDelay);
2162 CONFIG_INT("SaveAsOriginal", SaveAsOriginal = );
2163 CONFIG_INT("ScriptDebugMode", SetScriptDebugMode);
2164 CONFIG_INT("SkipIntroVideos", SkipIntroVideos = );
2165 CONFIG_INT("TooltipDelay", TooltipDelay = );
2166 CONFIG_INT("Width", Width = );
2167 #undef CONFIG_INT
2168 #define CONFIG_STRING(str, var) \
2169 } else if (stricmp(name, str) == 0) { \
2170 strncpy(var, value, sizeof(var))
2171 CONFIG_STRING("GameCharactersPath", GameCharactersPath);
2172 CONFIG_STRING("GameDataPath", GameDataPath);
2173 CONFIG_STRING("GameName", GameName);
2174 CONFIG_STRING("GameOverridePath", GameOverridePath);
2175 CONFIG_STRING("GamePortraitsPath", GamePortraitsPath);
2176 CONFIG_STRING("GameScriptsPath", GameScriptsPath);
2177 CONFIG_STRING("GameSoundsPath", GameSoundsPath);
2178 CONFIG_STRING("GameType", GameType);
2179 #undef CONFIG_STRING
2180 #define CONFIG_STRING(str, var) \
2181 } else if (stricmp(name, str) == 0) { \
2182 var = value
2183 CONFIG_STRING("AudioDriver", AudioDriverName);
2184 CONFIG_STRING("VideoDriver", VideoDriverName);
2185 #undef CONFIG_STRING
2186 #define CONFIG_PATH(str, var) \
2187 } else if (stricmp(name, str) == 0) { \
2188 strncpy(var, value, sizeof(var));
2189 CONFIG_PATH("CachePath", CachePath);
2190 CONFIG_PATH("GUIScriptsPath", GUIScriptsPath);
2191 CONFIG_PATH("GamePath", GamePath);
2192 CONFIG_PATH("GemRBOverridePath", GemRBOverridePath);
2193 CONFIG_PATH("GemRBPath", GemRBPath);
2194 CONFIG_PATH("PluginsPath", PluginsPath);
2195 CONFIG_PATH("SavePath", SavePath);
2196 #undef CONFIG_PATH
2197 } else if (stricmp( name, "ModPath" ) == 0) {
2198 for (char *path = strtok(value,SPathListSeparator);
2199 path;
2200 path = strtok(NULL,SPathListSeparator)) {
2201 ModPath.push_back(path);
2203 } else if (stricmp( name, "SkipPlugin" ) == 0) {
2204 plugin_flags->SetAt( value, PLF_SKIP );
2205 } else if (stricmp( name, "DelayPlugin" ) == 0) {
2206 plugin_flags->SetAt( value, PLF_DELAY );
2207 } else {
2208 for(i=0;i<MAX_CD;i++) {
2209 char keyname[] = { 'C', 'D', '1'+i, '\0' };
2210 if (stricmp(name, keyname) == 0) {
2211 for(char *path = strtok(value, SPathListSeparator);
2212 path;
2213 path = strtok(NULL,SPathListSeparator)) {
2214 CD[i].push_back(path);
2220 fclose( config );
2222 // WARNING: Don't move ResolveFilePath into the loop
2223 // Otherwise, it won't obey CaseSensitive set at the end
2224 // of the config file.
2226 if (stricmp( GameType, "tob" ) == 0) {
2227 strncpy( GameType, "bg2", sizeof(GameType) );
2230 #ifdef DATADIR
2231 if (!GemRBPath[0]) {
2232 strcpy( GemRBPath, DATADIR );
2234 #endif
2235 ResolveFilePath(GemRBPath);
2237 if (!GemRBOverridePath[0]) {
2238 strcpy( GemRBOverridePath, GemRBPath );
2239 } else {
2240 ResolveFilePath(GemRBOverridePath);
2243 if (!PluginsPath[0]) {
2244 #ifdef PLUGINDIR
2245 strcpy( PluginsPath, PLUGINDIR );
2246 #else
2247 PathJoin( PluginsPath, GemRBPath, "plugins", NULL );
2248 #endif
2249 } else {
2250 ResolveFilePath( PluginsPath );
2253 if (!GUIScriptsPath[0]) {
2254 strcpy( GUIScriptsPath, GemRBPath );
2255 } else {
2256 ResolveFilePath( GUIScriptsPath );
2259 if (!GameName[0]) {
2260 strcpy( GameName, GEMRB_STRING );
2263 ResolveFilePath( GamePath );
2265 if (!SavePath[0]) {
2266 // FIXME: maybe should use UserDir instead of GamePath
2267 strcpy( SavePath, GamePath );
2268 } else {
2269 ResolveFilePath( SavePath );
2272 if (! CachePath[0]) {
2273 PathJoin( CachePath, UserDir, "Cache", NULL );
2274 } else {
2275 ResolveFilePath(CachePath);
2278 for (i = 0; i < MAX_CD; ++i) {
2279 if (!CD[i].size()) {
2280 char cd[] = { 'C', 'D', '1'+i, '\0' };
2281 char name[_MAX_PATH];
2283 PathJoin(name, GamePath, cd, NULL);
2284 CD[i].push_back(name);
2285 } else {
2286 size_t cnt = CD[i].size();
2287 while(cnt--) {
2288 ResolveFilePath( CD[i][cnt] );
2293 for (i = 0; i < ModPath.size(); ++i) {
2294 ResolveFilePath(ModPath[i]);
2297 FixPath( GUIScriptsPath, true );
2298 FixPath( PluginsPath, true );
2299 FixPath( GemRBPath, true );
2300 FixPath( GemRBOverridePath, true );
2302 if (GamePath[0]) {
2303 FixPath( GamePath, true );
2306 //FixPath( SavePath, false );
2307 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2308 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2309 FixPath( SavePath, true );
2311 FixPath( CachePath, false );
2312 mkdir( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2313 chmod( CachePath, S_IREAD|S_IWRITE|S_IEXEC );
2315 printStatus( "OK", LIGHT_GREEN );
2317 // Missing GameType is a common users' error
2318 if (!GameType[0]) {
2319 printMessage("Config","GameType was not set in your config file.\n", LIGHT_RED);
2320 return false;
2323 if ( StupidityDetector( CachePath )) {
2324 printMessage("Core"," ",LIGHT_RED);
2325 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath );
2326 return false;
2328 if (!KeepCache) DelTree((const char *) CachePath, false);
2329 FixPath( CachePath, true );
2331 return true;
2334 static void upperlower(int upper, int lower)
2336 pl_uppercase[lower]=(ieByte) upper;
2337 pl_lowercase[upper]=(ieByte) lower;
2340 static const char *game_flags[GF_COUNT+1]={
2341 "HasKaputz", //0 GF_HAS_KAPUTZ
2342 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2343 "HasSongList", //2 GF_HAS_SONGLIST
2344 "TeamMovement", //3 GF_TEAM_MOVEMENT
2345 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2346 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2347 "HasPartyIni", //6 GF_HAS_PARTY_INI
2348 "SoundFolders", //7 GF_SOUNDFOLDERS
2349 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2350 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2351 "HasDPLAYER", //10GF_HAS_DPLAYER
2352 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2353 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2354 "HasDescIcon", //13GF_HAS_DESC_ICON
2355 "HasPickSound", //14GF_HAS_PICK_SOUND
2356 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2357 "AutomapIni", //16GF_AUTOMAP_INI
2358 "SmallFog", //17GF_SMALL_FOG
2359 "ReverseDoor", //18GF_REVERSE_DOOR
2360 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2361 "HasSpellList", //20GF_HAS_SPELLLIST
2362 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2363 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2364 "KnowWorld", //23GF_KNOW_WORLD
2365 "ReverseToHit", //24GF_REVERSE_TOHIT
2366 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2367 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2368 "MagicBit", //27GF_MAGICBIT
2369 "CheckAbilities", //28GF_CHECK_ABILITIES
2370 "ChallengeRating", //29GF_CHALLENGERATING
2371 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2372 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2373 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2374 "SpawnIni", //33GF_SPAWN_INI
2375 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2376 "HasResDataIni", //35GF_RESDATA_INI
2377 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2378 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2379 "3EdRules", //38GF_3ED_RULES
2380 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2381 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2382 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2383 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2384 "ProperBackstab", //43GF_PROPER_BACKSTAB
2385 "OnScreenText", //44GF_ONSCREEN_TEXT
2386 "HasSpecificDamageBonus", //45GF_SPECIFIC_DMG_BONUS
2387 "StrrefSaveGame", //46GF_STRREF_SAVEGAME
2388 "HasWisdomBonusTable",//47GF_WISDOM_BONUS
2389 "BiographyIsRes", //48GF_BIOGRAPHY_RES
2390 "NoBiography", //49GF_NO_BIOGRAPHY
2391 "StealIsAttack", //50GF_STEAL_IS_ATTACK
2392 "CutsceneAreascripts",//51GF_CUTSCENE_AREASCRIPTS
2393 "FlexibleWorldmap", //52GF_FLEXIBLE_WMAP
2394 "AutoSearchHidden", //53GF_AUTOSEARCH_HIDDEN
2395 "PSTStateFlags", //54GF_PST_STATE_FLAGS
2396 "NoDropCanMove", //55GF_NO_DROP_CAN_MOVE
2397 "JournalHasSections", //56GF_JOURNAL_HAS_SECTIONS
2398 "CastingSounds", //57GF_CASTING_SOUNDS
2399 "EnhancedCastingSounds", //58GF_CASTING_SOUNDS2
2400 NULL //for our own safety, this marks the end of the pole
2403 /** Loads gemrb.ini */
2404 bool Interface::LoadGemRBINI()
2406 DataStream* inifile = gamedata->GetResource( "gemrb", IE_INI_CLASS_ID );
2407 if (! inifile) {
2408 printStatus( "ERROR", LIGHT_RED );
2409 return false;
2412 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE );
2413 printf( "%s",inifile->originalfile);
2415 if (!IsAvailable( IE_INI_CLASS_ID )) {
2416 printStatus( "ERROR", LIGHT_RED );
2417 printf( "[Core]: No INI Importer Available.\n" );
2418 return false;
2420 PluginHolder<DataFileMgr> ini(IE_INI_CLASS_ID);
2421 ini->Open( inifile, true ); //autofree
2423 printStatus( "OK", LIGHT_GREEN );
2425 const char *s;
2427 // Resrefs are already initialized in Interface::Interface()
2428 s = ini->GetKeyAsString( "resources", "CursorBAM", NULL );
2429 if (s)
2430 strnlwrcpy( CursorBam, s, 8 ); //console cursor
2432 s = ini->GetKeyAsString( "resources", "ScrollCursorBAM", NULL );
2433 if (s)
2434 strnlwrcpy( ScrollCursorBam, s, 8 );
2436 s = ini->GetKeyAsString( "resources", "ButtonFont", NULL );
2437 if (s)
2438 strnlwrcpy( ButtonFont, s, 8 );
2440 s = ini->GetKeyAsString( "resources", "TooltipFont", NULL );
2441 if (s)
2442 strnlwrcpy( TooltipFont, s, 8 );
2444 s = ini->GetKeyAsString( "resources", "MovieFont", NULL );
2445 if (s)
2446 strnlwrcpy( MovieFont, s, 8 );
2448 s = ini->GetKeyAsString( "resources", "TooltipBack", NULL );
2449 if (s)
2450 strnlwrcpy( TooltipBackResRef, s, 8 );
2452 s = ini->GetKeyAsString( "resources", "TooltipColor", NULL );
2453 if (s) {
2454 if (s[0] == '#') {
2455 unsigned long c = strtoul (s + 1, NULL, 16);
2456 // FIXME: check errno
2457 TooltipColor.r = (unsigned char) (c >> 24);
2458 TooltipColor.g = (unsigned char) (c >> 16);
2459 TooltipColor.b = (unsigned char) (c >> 8);
2460 TooltipColor.a = (unsigned char) (c);
2464 //which stat determines the fist weapon (defaults to class)
2465 Actor::SetFistStat(ini->GetKeyAsInt( "resources", "FistStat", IE_CLASS));
2467 TooltipMargin = ini->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin );
2469 // The format of GroundCircle can be:
2470 // GroundCircleBAM1 = wmpickl/3
2471 // to denote that the bitmap should be scaled down 3x
2472 for (int size = 0; size < MAX_CIRCLE_SIZE; size++) {
2473 char name[30];
2474 sprintf( name, "GroundCircleBAM%d", size+1 );
2475 s = ini->GetKeyAsString( "resources", name, NULL );
2476 if (s) {
2477 const char *pos = strchr( s, '/' );
2478 if (pos) {
2479 GroundCircleScale[size] = atoi( pos+1 );
2480 strncpy( GroundCircleBam[size], s, pos - s );
2481 GroundCircleBam[size][pos - s] = '\0';
2482 } else {
2483 strcpy( GroundCircleBam[size], s );
2488 s = ini->GetKeyAsString( "resources", "NoteString", NULL );
2489 TextArea::SetNoteString(s);
2491 s = ini->GetKeyAsString( "resources", "INIConfig", NULL );
2492 if (s)
2493 strcpy( INIConfig, s );
2495 s = ini->GetKeyAsString( "resources", "Palette16", NULL );
2496 if (s)
2497 strcpy( Palette16, s );
2499 s = ini->GetKeyAsString( "resources", "Palette32", NULL );
2500 if (s)
2501 strcpy( Palette32, s );
2503 s = ini->GetKeyAsString( "resources", "Palette256", NULL );
2504 if (s)
2505 strcpy( Palette256, s );
2507 unsigned int i = (unsigned int) ini->GetKeyAsInt ("charset", "CharCount", 0);
2508 if (i>99) i=99;
2509 while(i--) {
2510 char key[10];
2511 snprintf(key,9,"Letter%d", i+1);
2512 s = ini->GetKeyAsString( "charset", key, NULL );
2513 if (s) {
2514 const char *s2 = strchr(s,',');
2515 if (s2) {
2516 upperlower(atoi(s), atoi(s2+1) );
2521 MaximumAbility = ini->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2523 RedrawTile = ini->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2525 for (i=0;i<GF_COUNT;i++) {
2526 if (!game_flags[i]) {
2527 printf("Fix the game flags!\n");
2528 abort();
2530 SetFeature( ini->GetKeyAsInt( "resources", game_flags[i], 0 ), i );
2531 //printMessage("Option", "", GREEN);
2532 //printf("%s = %s\n", game_flags[i], HasFeature(i)?"yes":"no");
2535 ForceStereo = ini->GetKeyAsInt( "resources", "ForceStereo", 0 );
2537 return true;
2540 Palette* Interface::CreatePalette(const Color &color, const Color &back)
2542 Palette* pal = new Palette();
2543 pal->col[0].r = 0;
2544 pal->col[0].g = 0xff;
2545 pal->col[0].b = 0;
2546 pal->col[0].a = 0;
2547 for (int i = 1; i < 256; i++) {
2548 pal->col[i].r = back.r +
2549 ( unsigned char ) ( ( ( color.r - back.r ) * ( i ) ) / 255.0 );
2550 pal->col[i].g = back.g +
2551 ( unsigned char ) ( ( ( color.g - back.g ) * ( i ) ) / 255.0 );
2552 pal->col[i].b = back.b +
2553 ( unsigned char ) ( ( ( color.b - back.b ) * ( i ) ) / 255.0 );
2554 pal->col[i].a = back.a +
2555 ( unsigned char ) ( ( ( color.a - back.a ) * ( i ) ) / 255.0 );
2557 return pal;
2560 /** No descriptions */
2561 Color* Interface::GetPalette(unsigned index, int colors, Color *pal) const
2563 Image *img;
2564 if (colors == 32) {
2565 img = pal32;
2566 } else if (colors <= 32) {
2567 img = pal16;
2568 } else if (colors == 256) {
2569 img = pal256;
2570 } else {
2571 return pal;
2573 if (index >= img->GetHeight()) {
2574 index = 0;
2576 for (int i = 0; i < colors; i++) {
2577 pal[i] = img->GetPixel(i, index);
2579 return pal;
2581 /** Returns a preloaded Font */
2582 Font* Interface::GetFont(const char *ResRef) const
2584 for (unsigned int i = 0; i < fonts.size(); i++) {
2585 if (strnicmp( fonts[i]->ResRef, ResRef, 8 ) == 0) {
2586 return fonts[i];
2589 return NULL;
2592 Font* Interface::GetFont(unsigned int index) const
2594 if (index >= fonts.size()) {
2595 return NULL;
2597 return fonts[index];
2600 Font* Interface::GetButtonFont() const
2602 return GetFont( ButtonFont );
2605 /** Returns the Event Manager */
2606 EventMgr* Interface::GetEventMgr() const
2608 return evntmgr;
2611 /** Returns the Window Manager */
2612 WindowMgr* Interface::GetWindowMgr() const
2614 return windowmgr.get();
2617 /** Get GUI Script Manager */
2618 ScriptEngine* Interface::GetGUIScriptEngine() const
2620 return guiscript.get();
2623 static EffectRef fx_summon_disable_ref={"AvatarRemovalModifier",NULL,-1};
2625 //NOTE: if there were more summoned creatures, it will return only the last
2626 Actor *Interface::SummonCreature(const ieResRef resource, const ieResRef vvcres, Scriptable *Owner, Actor *target, const Point &position, int eamod, int level, Effect *fx, bool sexmod)
2628 //maximum number of monsters summoned
2629 int cnt=10;
2630 Actor * ab = NULL;
2632 //TODO:
2633 //decrease the number of summoned creatures with the number of already summoned creatures here
2634 //the summoned creatures have a special IE_SPECIFIC
2636 while(cnt--) {
2637 ab = gamedata->GetCreature(resource);
2638 if (!ab) {
2639 return NULL;
2642 if (Owner && Owner->Type==ST_ACTOR) {
2643 ab->LastSummoner = Owner->GetGlobalID();
2645 //Always use Base stats for the recently summoned creature
2647 int enemyally;
2649 if (eamod==EAM_SOURCEALLY || eamod==EAM_SOURCEENEMY) {
2650 if (Owner && Owner->Type==ST_ACTOR) {
2651 enemyally = ((Actor *) Owner)->GetStat(IE_EA)>EA_GOODCUTOFF;
2652 } else {
2653 enemyally = true;
2655 } else {
2656 if (target) {
2657 enemyally = target->GetBase(IE_EA)>EA_GOODCUTOFF;
2658 } else {
2659 enemyally = true;
2663 switch (eamod) {
2664 case EAM_SOURCEALLY:
2665 case EAM_ALLY:
2666 if (enemyally) {
2667 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2668 } else {
2669 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2671 break;
2672 case EAM_SOURCEENEMY:
2673 case EAM_ENEMY:
2674 if (enemyally) {
2675 ab->SetBase(IE_EA, EA_CONTROLLED); //is this the summoned EA?
2676 } else {
2677 ab->SetBase(IE_EA, EA_ENEMY); //is this the summoned EA?
2679 break;
2680 case EAM_NEUTRAL:
2681 ab->SetBase(IE_EA, EA_NEUTRAL);
2682 break;
2683 default:
2684 break;
2687 // mark the summon, but only if they don't have a special sex already
2688 if (sexmod && ab->BaseStats[IE_SEX] < SEX_EXTRA) {
2689 ab->SetBase(IE_SEX, SEX_SUMMON);
2692 Map *map;
2693 if (target) {
2694 map = target->GetCurrentArea();
2695 } else {
2696 map = Owner->GetCurrentArea();
2698 map->AddActor(ab);
2699 ab->SetPosition(position, true, 0);
2700 ab->RefreshEffects(NULL);
2702 if (vvcres[0]) {
2703 ScriptedAnimation* vvc = gamedata->GetScriptedAnimation(vvcres, false);
2704 if (vvc) {
2705 //This is the final position of the summoned creature
2706 //not the original target point
2707 vvc->XPos=ab->Pos.x;
2708 vvc->YPos=ab->Pos.y;
2709 //force vvc to play only once
2710 vvc->PlayOnce();
2711 map->AddVVCell( vvc );
2713 //set up the summon disable effect
2714 Effect *newfx = EffectQueue::CreateEffect(fx_summon_disable_ref, 0, 1, FX_DURATION_ABSOLUTE);
2715 if (newfx) {
2716 newfx->Duration = vvc->GetSequenceDuration(AI_UPDATE_TIME)*9/10 + core->GetGame()->GameTime;
2717 ApplyEffect(newfx, ab, ab);
2722 //remove the xp value of friendly summons
2723 if (ab->BaseStats[IE_EA]<EA_GOODCUTOFF) {
2724 ab->SetBase(IE_XPVALUE, 0);
2726 if (fx) {
2727 ApplyEffect(fx, ab, Owner);
2730 //this check should happen after the fact
2731 level -= ab->GetBase(IE_XP);
2732 if(level<0 || ab->GetBase(IE_XP) == 0) {
2733 break;
2737 return ab;
2740 void Interface::RedrawControls(const char *varname, unsigned int value)
2742 for (unsigned int i = 0; i < windows.size(); i++) {
2743 Window *win = windows[i];
2744 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2745 win->RedrawControls(varname, value);
2750 void Interface::RedrawAll()
2752 for (unsigned int i = 0; i < windows.size(); i++) {
2753 Window *win = windows[i];
2754 if (win != NULL && win->Visible!=WINDOW_INVALID) {
2755 win->Invalidate();
2760 /** Loads a WindowPack (CHUI file) in the Window Manager */
2761 bool Interface::LoadWindowPack(const char* name)
2763 DataStream* stream = gamedata->GetResource( name, IE_CHU_CLASS_ID );
2764 if (stream == NULL) {
2765 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED );
2766 printf( "%s.chu\n", name );
2767 return false;
2769 if (!GetWindowMgr()->Open( stream, true )) {
2770 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED );
2771 printf( "%s.chu\n", name );
2772 return false;
2775 strncpy( WindowPack, name, sizeof( WindowPack ) );
2776 WindowPack[sizeof( WindowPack ) - 1] = '\0';
2778 return true;
2781 /** Loads a Window in the Window Manager */
2782 int Interface::LoadWindow(unsigned short WindowID)
2784 unsigned int i;
2786 for (i = 0; i < windows.size(); i++) {
2787 Window *win = windows[i];
2788 if (win == NULL)
2789 continue;
2790 if (win->Visible==WINDOW_INVALID) {
2791 continue;
2793 if (win->WindowID == WindowID &&
2794 !strnicmp( WindowPack, win->WindowPack, sizeof(WindowPack) )) {
2795 SetOnTop( i );
2796 win->Invalidate();
2797 return i;
2800 Window* win = windowmgr->GetWindow( WindowID );
2801 if (win == NULL) {
2802 return -1;
2804 memcpy( win->WindowPack, WindowPack, sizeof(WindowPack) );
2806 int slot = -1;
2807 for (i = 0; i < windows.size(); i++) {
2808 if (windows[i] == NULL) {
2809 slot = i;
2810 break;
2813 if (slot == -1) {
2814 windows.push_back( win );
2815 slot = ( int ) windows.size() - 1;
2816 } else {
2817 windows[slot] = win;
2819 win->Invalidate();
2820 return slot;
2822 // FIXME: it's a clone of LoadWindow
2823 /** Creates a Window in the Window Manager */
2824 int Interface::CreateWindow(unsigned short WindowID, int XPos, int YPos, unsigned int Width, unsigned int Height, char* Background)
2826 unsigned int i;
2828 for (i = 0; i < windows.size(); i++) {
2829 if (windows[i] == NULL)
2830 continue;
2831 if (windows[i]->WindowID == WindowID && !stricmp( WindowPack,
2832 windows[i]->WindowPack )) {
2833 SetOnTop( i );
2834 windows[i]->Invalidate();
2835 return i;
2839 Window* win = new Window( WindowID, (ieWord) XPos, (ieWord) YPos, (ieWord) Width, (ieWord) Height );
2840 if (Background[0]) {
2841 ResourceHolder<ImageMgr> mos(Background);
2842 if (mos != NULL) {
2843 win->SetBackGround( mos->GetSprite2D(), true );
2844 } else {
2845 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2849 strcpy( win->WindowPack, WindowPack );
2851 int slot = -1;
2852 for (i = 0; i < windows.size(); i++) {
2853 if (windows[i] == NULL) {
2854 slot = i;
2855 break;
2858 if (slot == -1) {
2859 windows.push_back( win );
2860 slot = ( int ) windows.size() - 1;
2861 } else {
2862 windows[slot] = win;
2864 win->Invalidate();
2865 return slot;
2868 /** Sets a Window on the Top */
2869 void Interface::SetOnTop(int Index)
2871 std::vector<int>::iterator t;
2872 for(t = topwin.begin(); t != topwin.end(); ++t) {
2873 if((*t) == Index) {
2874 topwin.erase(t);
2875 break;
2878 if(topwin.size() != 0)
2879 topwin.insert(topwin.begin(), Index);
2880 else
2881 topwin.push_back(Index);
2883 /** Add a window to the Window List */
2884 void Interface::AddWindow(Window * win)
2886 int slot = -1;
2887 for(unsigned int i = 0; i < windows.size(); i++) {
2888 Window *w = windows[i];
2890 if(w==NULL) {
2891 slot = i;
2892 break;
2895 if(slot == -1) {
2896 windows.push_back(win);
2897 slot=(int)windows.size()-1;
2899 else
2900 windows[slot] = win;
2901 win->Invalidate();
2904 /** Get a Control on a Window */
2905 int Interface::GetControl(unsigned short WindowIndex, unsigned long ControlID) const
2907 if (WindowIndex >= windows.size()) {
2908 return -1;
2910 Window* win = windows[WindowIndex];
2911 if (win == NULL) {
2912 return -1;
2914 int i = 0;
2915 while (true) {
2916 Control* ctrl = win->GetControl( (unsigned short) i );
2917 if (ctrl == NULL)
2918 return -1;
2919 if (ctrl->ControlID == ControlID)
2920 return i;
2921 i++;
2924 /** Adjust the Scrolling factor of a control (worldmap atm) */
2925 int Interface::AdjustScrolling(unsigned short WindowIndex,
2926 unsigned short ControlIndex, short x, short y)
2928 if (WindowIndex >= windows.size()) {
2929 return -1;
2931 Window* win = windows[WindowIndex];
2932 if (win == NULL) {
2933 return -1;
2935 Control* ctrl = win->GetControl( ControlIndex );
2936 if (ctrl == NULL) {
2937 return -1;
2939 switch(ctrl->ControlType) {
2940 case IE_GUI_WORLDMAP:
2941 ((WorldMapControl *) ctrl)->AdjustScrolling(x,y);
2942 break;
2943 default: //doesn't work for these
2944 return -1;
2946 return 0;
2949 /** Set the Text of a Control */
2950 int Interface::SetText(unsigned short WindowIndex,
2951 unsigned short ControlIndex, const char* string)
2953 if (WindowIndex >= windows.size()) {
2954 return -1;
2956 Window* win = windows[WindowIndex];
2957 if (win == NULL) {
2958 return -1;
2960 Control* ctrl = win->GetControl( ControlIndex );
2961 if (ctrl == NULL) {
2962 return -1;
2964 return ctrl->SetText( string );
2966 /** Set the Tooltip text of a Control */
2967 int Interface::SetTooltip(unsigned short WindowIndex,
2968 unsigned short ControlIndex, const char* string)
2970 if (WindowIndex >= windows.size()) {
2971 return -1;
2973 Window* win = windows[WindowIndex];
2974 if (win == NULL) {
2975 return -1;
2977 Control* ctrl = win->GetControl( ControlIndex );
2978 if (ctrl == NULL) {
2979 return -1;
2981 return ctrl->SetTooltip( string );
2984 void Interface::DisplayTooltip(int x, int y, Control *ctrl)
2986 if (tooltip_ctrl && tooltip_ctrl == ctrl && tooltip_x == x && tooltip_y == y)
2987 return;
2988 tooltip_x = x;
2989 tooltip_y = y;
2990 tooltip_currtextw = 0;
2991 tooltip_ctrl = ctrl;
2994 int Interface::GetVisible(unsigned short WindowIndex) const
2996 if (WindowIndex >= windows.size()) {
2997 return -1;
2999 Window* win = windows[WindowIndex];
3000 if (win == NULL) {
3001 return -1;
3003 return win->Visible;
3005 /** Set a Window Visible Flag */
3006 int Interface::SetVisible(unsigned short WindowIndex, int visible)
3008 if (WindowIndex >= windows.size()) {
3009 return -1;
3011 Window* win = windows[WindowIndex];
3012 if (win == NULL) {
3013 return -1;
3015 if (visible!=WINDOW_FRONT) {
3016 win->Visible = (char) visible;
3018 switch (visible) {
3019 case WINDOW_GRAYED:
3020 win->Invalidate();
3021 //here is a fallthrough
3022 case WINDOW_INVISIBLE:
3023 //hiding the viewport if the gamecontrol window was made invisible
3024 if (win->WindowID==65535) {
3025 video->SetViewport( 0,0,0,0 );
3027 evntmgr->DelWindow( win );
3028 break;
3030 case WINDOW_VISIBLE:
3031 if (win->WindowID==65535) {
3032 video->SetViewport( win->XPos, win->YPos, win->Width, win->Height);
3034 //here is a fallthrough
3035 case WINDOW_FRONT:
3036 if (win->Visible==WINDOW_VISIBLE) {
3037 evntmgr->AddWindow( win );
3039 win->Invalidate();
3040 SetOnTop( WindowIndex );
3041 break;
3043 return 0;
3047 /** Set the Status of a Control in a Window */
3048 int Interface::SetControlStatus(unsigned short WindowIndex,
3049 unsigned short ControlIndex, unsigned long Status)
3051 //don't set the status of an already invalidated window
3052 Window* win = GetWindow(WindowIndex);
3053 if (win == NULL) {
3054 return -1;
3056 Control* ctrl = win->GetControl( ControlIndex );
3057 if (ctrl == NULL) {
3058 return -1;
3060 if (Status&IE_GUI_CONTROL_FOCUSED) {
3061 evntmgr->SetFocused( win, ctrl);
3063 if (ctrl->ControlType != ((Status >> 24) & 0xff) ) {
3064 return -2;
3066 switch (ctrl->ControlType) {
3067 case IE_GUI_BUTTON:
3068 //Button
3070 Button* btn = ( Button* ) ctrl;
3071 btn->SetState( ( unsigned char ) ( Status & 0x7f ) );
3073 break;
3074 default:
3075 ctrl->Value = Status & 0x7f;
3076 break;
3078 return 0;
3081 /** Show a Window in Modal Mode */
3082 int Interface::ShowModal(unsigned short WindowIndex, int Shadow)
3084 if (WindowIndex >= windows.size()) {
3085 printMessage( "Core", "Window not found", LIGHT_RED );
3086 return -1;
3088 Window* win = windows[WindowIndex];
3089 if (win == NULL) {
3090 printMessage( "Core", "Window already freed", LIGHT_RED );
3091 return -1;
3093 win->Visible = WINDOW_FRONT;
3094 //don't destroy the other window handlers
3095 //evntmgr->Clear();
3096 SetOnTop( WindowIndex );
3097 evntmgr->AddWindow( win );
3098 evntmgr->SetFocused( win, NULL );
3100 ModalWindow = NULL;
3101 DrawWindows();
3102 win->Invalidate();
3104 Color gray = {
3105 0, 0, 0, 128
3107 Color black = {
3108 0, 0, 0, 255
3111 Region r( 0, 0, Width, Height );
3113 if (Shadow == MODAL_SHADOW_GRAY) {
3114 video->DrawRect( r, gray );
3115 } else if (Shadow == MODAL_SHADOW_BLACK) {
3116 video->DrawRect( r, black );
3119 ModalWindow = win;
3120 return 0;
3123 bool Interface::IsFreezed()
3125 return !update_scripts;
3128 void Interface::GameLoop(void)
3130 update_scripts = false;
3131 GameControl *gc = GetGameControl();
3132 if (gc) {
3133 update_scripts = !(gc->GetDialogueFlags() & DF_FREEZE_SCRIPTS);
3136 GSUpdate(update_scripts);
3138 //i'm not sure if this should be here
3140 //in multi player (if we ever get to it), only the server must call this
3141 if (update_scripts) {
3142 if ( game->selected.size() > 0 ) {
3143 gc->ChangeMap(GetFirstSelectedPC(true), false);
3145 // the game object will run the area scripts as well
3146 game->UpdateScripts();
3150 /** handles hardcoded gui behaviour */
3151 void Interface::HandleGUIBehaviour(void)
3153 GameControl *gc = GetGameControl();
3154 if (gc) {
3155 //this variable is used all over in the following hacks
3156 int flg = gc->GetDialogueFlags();
3158 //the following part is a series of hardcoded gui behaviour
3160 //initiating dialog
3161 if (flg & DF_IN_DIALOG) {
3162 // -3 noaction
3163 // -2 close
3164 // -1 open
3165 // choose option
3166 ieDword var = (ieDword) -3;
3167 vars->Lookup("DialogChoose", var);
3168 if ((int) var == -2) {
3169 gc->dialoghandler->EndDialog();
3170 } else if ( (int)var !=-3) {
3171 gc->dialoghandler->DialogChoose(var);
3172 if (!(gc->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW | DF_OPENENDWINDOW)))
3173 guiscript->RunFunction( "GUIWORLD", "NextDialogState" );
3175 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3176 ieDword newvar = 0; vars->Lookup("DialogChoose", newvar);
3177 if (var == (ieDword) -1 || newvar != (ieDword) -1) {
3178 vars->SetAt("DialogChoose", (ieDword) -3);
3181 if (flg & DF_OPENCONTINUEWINDOW) {
3182 guiscript->RunFunction( "GUIWORLD", "OpenContinueMessageWindow" );
3183 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3184 } else if (flg & DF_OPENENDWINDOW) {
3185 guiscript->RunFunction( "GUIWORLD", "OpenEndMessageWindow" );
3186 gc->SetDialogueFlags(DF_OPENCONTINUEWINDOW|DF_OPENENDWINDOW, BM_NAND);
3190 //handling container
3191 if (CurrentContainer && UseContainer) {
3192 if (!(flg & DF_IN_CONTAINER) ) {
3193 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_OR);
3194 guiscript->RunFunction( "CommonWindow", "OpenContainerWindow" );
3196 } else {
3197 if (flg & DF_IN_CONTAINER) {
3198 gc->SetDialogueFlags(DF_IN_CONTAINER, BM_NAND);
3199 guiscript->RunFunction( "CommonWindow", "CloseContainerWindow" );
3202 //end of gui hacks
3206 void Interface::DrawWindows(void)
3208 //here comes the REAL drawing of windows
3209 if (ModalWindow) {
3210 ModalWindow->DrawWindow();
3211 return;
3213 size_t i = topwin.size();
3214 while(i--) {
3215 unsigned int t = topwin[i];
3217 if ( t >=windows.size() )
3218 continue;
3220 //visible ==1 or 2 will be drawn
3221 Window* win = windows[t];
3222 if (win != NULL) {
3223 if (win->Visible == WINDOW_INVALID) {
3224 topwin.erase(topwin.begin()+i);
3225 evntmgr->DelWindow( win );
3226 delete win;
3227 windows[t]=NULL;
3228 } else if (win->Visible) {
3229 win->DrawWindow();
3235 void Interface::DrawTooltip ()
3237 if (! tooltip_ctrl || !tooltip_ctrl->Tooltip)
3238 return;
3240 Font* fnt = GetFont( TooltipFont );
3241 char *tooltip_text = tooltip_ctrl->Tooltip;
3243 int w1 = 0;
3244 int w2 = 0;
3245 int strw = fnt->CalcStringWidth( tooltip_text ) + 8;
3246 int w = strw;
3247 int h = fnt->maxHeight;
3249 if (TooltipBack) {
3250 // animate BG tooltips
3251 // TODO: make tooltip animation an option instead
3252 // of following hard-coded check!
3253 if (TooltipMargin == 5) {
3254 // TODO: make speed an option
3255 int tooltip_anim_speed = 15;
3256 if (tooltip_currtextw < strw) {
3257 tooltip_currtextw += tooltip_anim_speed;
3259 if (tooltip_currtextw > strw) {
3260 tooltip_currtextw = strw;
3262 w = tooltip_currtextw;
3265 h = TooltipBack[0]->Height;
3266 w1 = TooltipBack[1]->Width;
3267 w2 = TooltipBack[2]->Width;
3268 w += TooltipMargin*2;
3269 strw += TooltipMargin*2;
3270 //multiline in case of too much text
3271 if (w>TooltipBack[0]->Width)
3272 strw=w=TooltipBack[0]->Width;
3273 else if (strw>TooltipBack[0]->Width)
3274 strw=TooltipBack[0]->Width;
3277 int strx = tooltip_x - strw / 2;
3278 int y = tooltip_y - h / 2;
3279 // Ensure placement within the screen
3280 if (strx < 0) strx = 0;
3281 else if (strx + strw + w1 + w2 > Width)
3282 strx = Width - strw - w1 - w2;
3283 if (y < 0) y = 0;
3284 else if (y + h > Height)
3285 y = Height - h;
3287 int x = strx + ((strw - w) / 2);
3289 // FIXME: take back[0] from center, not from left end
3290 Region r2 = Region( x, y, w, h );
3291 if (TooltipBack) {
3292 video->BlitSprite( TooltipBack[0], x + TooltipMargin, y, true, &r2 );
3293 video->BlitSprite( TooltipBack[1], x, y, true );
3294 video->BlitSprite( TooltipBack[2], x + w, y, true );
3297 if (TooltipBack) {
3298 r2.x+=TooltipMargin;
3299 strx+=TooltipMargin;
3301 Region textr = Region( strx, y, strw, h );
3302 fnt->Print( r2, textr, (ieByte *) tooltip_text, NULL,
3303 IE_FONT_ALIGN_CENTER | IE_FONT_ALIGN_MIDDLE, true );
3306 //interface for higher level functions, if the window was
3307 //marked for deletion it is not returned
3308 Window* Interface::GetWindow(unsigned short WindowIndex) const
3310 if (WindowIndex < windows.size()) {
3311 Window *win = windows[WindowIndex];
3312 if (win && (win->Visible!=WINDOW_INVALID) ) {
3313 return win;
3316 return NULL;
3319 // this function will determine if wnd is a valid window pointer
3320 // by checking if its WindowID is the same as the reference
3321 bool Interface::IsValidWindow(unsigned short WindowID, Window *wnd) const
3323 size_t WindowIndex = windows.size();
3324 while (WindowIndex--) {
3325 if (windows[WindowIndex] == wnd) {
3326 return wnd->WindowID == WindowID;
3329 return false;
3332 //this function won't delete the window, just mark it for deletion
3333 //it will be deleted in the next DrawWindows cycle
3334 //regardless, the window deleted is inaccessible for gui scripts and
3335 //other high level functions from now
3336 int Interface::DelWindow(unsigned short WindowIndex)
3338 if (WindowIndex >= windows.size()) {
3339 return -1;
3341 Window* win = windows[WindowIndex];
3342 if ((win == NULL) || (win->Visible==WINDOW_INVALID) ) {
3343 printMessage( "Core", "Window deleted again", LIGHT_RED );
3344 return -1;
3346 if (win == ModalWindow) {
3347 ModalWindow = NULL;
3348 RedrawAll(); //marking windows for redraw
3350 evntmgr->DelWindow( win );
3351 win->release();
3352 //re-capturing new (old) modal window if any
3353 size_t tw = topwin.size();
3354 for(size_t i=0;i<tw;i++) {
3355 Window *tmp = windows[topwin[i]];
3356 if (tmp->Visible==WINDOW_FRONT) {
3357 ModalWindow = tmp;
3358 break;
3361 return 0;
3364 void Interface::DelAllWindows()
3366 vars->SetAt("MessageWindow", (ieDword) ~0);
3367 vars->SetAt("OptionsWindow", (ieDword) ~0);
3368 vars->SetAt("PortraitWindow", (ieDword) ~0);
3369 vars->SetAt("ActionsWindow", (ieDword) ~0);
3370 vars->SetAt("TopWindow", (ieDword) ~0);
3371 vars->SetAt("OtherWindow", (ieDword) ~0);
3372 vars->SetAt("FloatWindow", (ieDword) ~0);
3373 for(unsigned int WindowIndex=0; WindowIndex<windows.size();WindowIndex++) {
3374 Window* win = windows[WindowIndex];
3375 delete win;
3377 windows.clear();
3378 topwin.clear();
3379 evntmgr->Clear();
3380 ModalWindow = NULL;
3383 /** Popup the Console */
3384 void Interface::PopupConsole()
3386 ConsolePopped = !ConsolePopped;
3387 RedrawAll();
3388 console->Changed = true;
3391 /** Draws the Console */
3392 void Interface::DrawConsole()
3394 console->Draw( 0, 0 );
3397 /** Get the Sound Manager */
3398 SaveGameIterator* Interface::GetSaveGameIterator() const
3400 return sgiterator;
3402 /** Sends a termination signal to the Video Driver */
3403 bool Interface::Quit(void)
3405 return video->Quit();
3407 /** Returns the variables dictionary */
3408 Variables* Interface::GetDictionary() const
3410 return vars;
3412 /** Returns the token dictionary */
3413 Variables* Interface::GetTokenDictionary() const
3415 return tokens;
3417 /** Get the Music Manager */
3418 MusicMgr* Interface::GetMusicMgr() const
3420 return music.get();
3422 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3423 int Interface::LoadSymbol(const char* ResRef)
3425 int ind = GetSymbolIndex( ResRef );
3426 if (ind != -1) {
3427 return ind;
3429 DataStream* str = gamedata->GetResource( ResRef, IE_IDS_CLASS_ID );
3430 if (!str) {
3431 return -1;
3433 PluginHolder<SymbolMgr> sm(IE_IDS_CLASS_ID);
3434 if (!sm) {
3435 delete str;
3436 return -1;
3438 if (!sm->Open( str, true )) {
3439 return -1;
3441 Symbol s;
3442 strncpy( s.ResRef, ResRef, 8 );
3443 s.sm = sm;
3444 ind = -1;
3445 for (size_t i = 0; i < symbols.size(); i++) {
3446 if (!symbols[i].sm) {
3447 ind = ( int ) i;
3448 break;
3451 if (ind != -1) {
3452 symbols[ind] = s;
3453 return ind;
3455 symbols.push_back( s );
3456 return ( int ) symbols.size() - 1;
3458 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3459 int Interface::GetSymbolIndex(const char* ResRef) const
3461 for (size_t i = 0; i < symbols.size(); i++) {
3462 if (!symbols[i].sm)
3463 continue;
3464 if (strnicmp( symbols[i].ResRef, ResRef, 8 ) == 0)
3465 return ( int ) i;
3467 return -1;
3469 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3470 Holder<SymbolMgr> Interface::GetSymbol(unsigned int index) const
3472 if (index >= symbols.size()) {
3473 return Holder<SymbolMgr>();
3475 if (!symbols[index].sm) {
3476 return Holder<SymbolMgr>();
3478 return symbols[index].sm;
3480 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3481 bool Interface::DelSymbol(unsigned int index)
3483 if (index >= symbols.size()) {
3484 return false;
3486 if (!symbols[index].sm) {
3487 return false;
3489 symbols[index].sm.release();
3490 return true;
3492 /** Plays a Movie */
3493 int Interface::PlayMovie(const char* ResRef)
3495 ResourceHolder<MoviePlayer> mp(ResRef);
3496 if (!mp) {
3497 return -1;
3500 ieDword subtitles = 0;
3501 Font *SubtitleFont = NULL;
3502 Palette *palette = NULL;
3503 ieDword *frames = NULL;
3504 ieDword *strrefs = NULL;
3505 int cnt = 0;
3506 int offset = 0;
3508 //one of these two should exist (they both mean the same thing)
3509 vars->Lookup("Display Movie Subtitles", subtitles);
3510 if (subtitles) {
3511 //HoW flag
3512 cnt=-3;
3513 offset = 3;
3514 } else {
3515 //ToB flag
3516 vars->Lookup("Display Subtitles", subtitles);
3518 AutoTable sttable;
3519 if (subtitles && sttable.load(ResRef)) {
3520 cnt += sttable->GetRowCount();
3521 if (cnt>0) {
3522 frames = (ieDword *) malloc(cnt * sizeof(ieDword) );
3523 strrefs = (ieDword *) malloc(cnt * sizeof(ieDword) );
3524 } else {
3525 cnt = 0;
3527 if (frames && strrefs) {
3528 for (int i=0;i<cnt;i++) {
3529 frames[i] = atoi (sttable->QueryField(i+offset, 0) );
3530 strrefs[i] = atoi (sttable->QueryField(i+offset, 1) );
3533 int r = atoi(sttable->QueryField("red", "frame"));
3534 int g = atoi(sttable->QueryField("green", "frame"));
3535 int b = atoi(sttable->QueryField("blue", "frame"));
3536 SubtitleFont = GetFont (MovieFont); //will change
3537 if (r || g || b) {
3538 if (SubtitleFont) {
3539 Color fore = {(unsigned char) r,(unsigned char) g,(unsigned char) b, 0x00};
3540 Color back = {0x00, 0x00, 0x00, 0x00};
3541 palette = CreatePalette( fore, back );
3546 //shutting down music and ambients before movie
3547 if (music)
3548 music->HardEnd();
3549 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3550 if (ambim) ambim->deactivate();
3551 video->SetMovieFont(SubtitleFont, palette );
3552 mp->CallBackAtFrames(cnt, frames, strrefs);
3553 mp->Play();
3554 gamedata->FreePalette( palette );
3555 if (frames)
3556 free(frames);
3557 if (strrefs)
3558 free(strrefs);
3559 //restarting music
3560 if (music)
3561 music->Start();
3562 if (ambim) ambim->activate();
3563 //this will fix redraw all windows as they looked like
3564 //before the movie
3565 RedrawAll();
3567 //Setting the movie name to 1
3568 vars->SetAt( ResRef, 1 );
3569 return 0;
3572 int Interface::Roll(int dice, int size, int add) const
3574 if (dice < 1) {
3575 return add;
3577 if (size < 1) {
3578 return add;
3580 if (dice > 100) {
3581 return add + dice * size / 2;
3583 for (int i = 0; i < dice; i++) {
3584 add += rand() % size + 1;
3586 return add;
3589 static char bmp_suffix[6]="M.BMP";
3590 static char png_suffix[6]="M.PNG";
3592 int Interface::GetPortraits(TextArea* ta, bool smallorlarge)
3594 int count = 0;
3595 char Path[_MAX_PATH];
3597 if (smallorlarge) {
3598 bmp_suffix[0]='S';
3599 png_suffix[0]='S';
3600 } else {
3601 bmp_suffix[0]='M';
3602 png_suffix[0]='M';
3604 PathJoin( Path, GamePath, GamePortraitsPath, NULL );
3605 DirectoryIterator dir(Path);
3606 if (!dir) {
3607 return -1;
3609 printf( "Looking in %s\n", Path );
3610 do {
3611 char *name = dir.GetName();
3612 if (name[0] == '.')
3613 continue;
3614 if (dir.IsDirectory())
3615 continue;
3616 strupr(name);
3617 char *pos = strstr(name,bmp_suffix);
3618 if (!pos && IsAvailable(IE_PNG_CLASS_ID) ) {
3619 pos = strstr(name,png_suffix);
3621 if (!pos) continue;
3622 pos[1]=0;
3623 count++;
3624 ta->AppendText( name, -1 );
3625 } while (++dir);
3626 return count;
3629 int Interface::GetCharSounds(TextArea* ta)
3631 bool hasfolders;
3632 int count = 0;
3633 char Path[_MAX_PATH];
3635 PathJoin( Path, GamePath, GameSoundsPath, NULL );
3636 hasfolders = ( HasFeature( GF_SOUNDFOLDERS ) != 0 );
3637 DirectoryIterator dir(Path);
3638 if (!dir) {
3639 return -1;
3641 printf( "Looking in %s\n", Path );
3642 do {
3643 char *name = dir.GetName();
3644 if (name[0] == '.')
3645 continue;
3646 if (hasfolders == !dir.IsDirectory())
3647 continue;
3648 if (!hasfolders) {
3649 strupr(name);
3650 char *pos = strstr(name,"A.WAV");
3651 if (!pos) continue;
3652 *pos=0;
3654 count++;
3655 ta->AppendText( name, -1 );
3656 } while (++dir);
3657 return count;
3660 int Interface::GetCharacters(TextArea* ta)
3662 int count = 0;
3663 char Path[_MAX_PATH];
3665 PathJoin( Path, GamePath, GameCharactersPath, NULL );
3666 DirectoryIterator dir(Path);
3667 if (!dir) {
3668 return -1;
3670 printf( "Looking in %s\n", Path );
3671 do {
3672 char *name = dir.GetName();
3673 if (name[0] == '.')
3674 continue;
3675 if (dir.IsDirectory())
3676 continue;
3677 strupr(name);
3678 char *pos = strstr(name,".CHR");
3679 if (!pos) continue;
3680 *pos=0;
3681 count++;
3682 ta->AppendText( name, -1 );
3683 } while (++dir);
3684 return count;
3687 bool Interface::LoadINI(const char* filename)
3689 FILE* config;
3690 config = fopen( filename, "rb" );
3691 if (config == NULL) {
3692 return false;
3694 char name[65], value[_MAX_PATH + 3];
3695 while (!feof( config )) {
3696 name[0] = 0;
3697 value[0] = 0;
3698 char rem;
3700 if (fread( &rem, 1, 1, config ) != 1)
3701 break;
3703 if (( rem == '#' ) ||
3704 ( rem == '[' ) ||
3705 ( rem == '\r' ) ||
3706 ( rem == '\n' ) ||
3707 ( rem == ';' )) {
3708 if (rem == '\r') {
3709 fgetc( config );
3710 continue;
3711 } else if (rem == '\n')
3712 continue;
3714 //it should always return zero
3715 if (fscanf( config, "%*[^\r\n]%*[\r\n]" )!=0)
3716 break;
3717 continue;
3719 fseek( config, -1, SEEK_CUR );
3720 //the * element is not counted
3721 if (fscanf( config, "%[^=]=%[^\r\n]%*[\r\n]", name, value )!=2)
3722 continue;
3723 if (( value[0] >= '0' ) && ( value[0] <= '9' )) {
3724 vars->SetAt( name, atoi( value ) );
3727 fclose( config );
3728 return true;
3731 /** Enables/Disables the Cut Scene Mode */
3732 void Interface::SetCutSceneMode(bool active)
3734 GameControl *gc = GetGameControl();
3735 if (gc) {
3736 gc->SetCutSceneMode( active );
3738 if (game) {
3739 if (active) {
3740 game->ControlStatus |= CS_HIDEGUI;
3741 } else {
3742 game->ControlStatus &= ~CS_HIDEGUI;
3744 SetEventFlag(EF_CONTROL);
3746 video->SetMouseEnabled(!active);
3749 bool Interface::InCutSceneMode() const
3751 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE)!=0;
3754 void Interface::QuitGame(int BackToMain)
3756 SetCutSceneMode(false);
3757 if (timer) {
3758 //clear cutscenes
3759 //clear fade/screenshake effects
3760 timer->Init();
3761 timer->SetFadeFromColor(0);
3764 DelAllWindows(); //delete all windows, including GameControl
3766 //shutting down ingame music
3767 //(do it before deleting the game)
3768 if (music) {
3769 music->HardEnd();
3771 // stop any ambients which are still enqueued
3772 if (AudioDriver) {
3773 AmbientMgr *ambim = AudioDriver->GetAmbientMgr();
3774 if (ambim) ambim->deactivate();
3776 //delete game, worldmap
3777 if (game) {
3778 delete game;
3779 game=NULL;
3781 if (worldmap) {
3782 delete worldmap;
3783 worldmap=NULL;
3785 if (BackToMain) {
3786 strcpy(NextScript, "Start");
3787 QuitFlag |= QF_CHANGESCRIPT;
3789 GSUpdate(true);
3792 void Interface::SetupLoadGame(Holder<SaveGame> sg, int ver_override)
3794 LoadGameIndex = sg;
3795 VersionOverride = ver_override;
3796 QuitFlag |= QF_LOADGAME;
3799 void Interface::LoadGame(SaveGame *sg, int ver_override)
3801 // This function has rather painful error handling,
3802 // as it should swap all the objects or none at all
3803 // and the loading can fail for various reasons
3805 // Yes, it uses goto. Other ways seemed too awkward for me.
3807 strings->CloseAux();
3808 tokens->RemoveAll(NULL); //clearing the token dictionary
3810 if(calendar) delete calendar;
3811 calendar = new Calendar;
3813 DataStream* gam_str = NULL;
3814 DataStream* sav_str = NULL;
3815 DataStream* wmp_str1 = NULL;
3816 DataStream* wmp_str2 = NULL;
3818 Game* new_game = NULL;
3819 WorldMapArray* new_worldmap = NULL;
3821 LoadProgress(10);
3822 if (!KeepCache) DelTree((const char *) CachePath, true);
3823 LoadProgress(15);
3825 if (sg == NULL) {
3826 //Load the Default Game
3827 gam_str = gamedata->GetResource( GameNameResRef, IE_GAM_CLASS_ID );
3828 sav_str = NULL;
3829 wmp_str1 = gamedata->GetResource( WorldMapName[0], IE_WMP_CLASS_ID );
3830 if (WorldMapName[1][0]) {
3831 wmp_str2 = gamedata->GetResource( WorldMapName[1], IE_WMP_CLASS_ID );
3833 } else {
3834 gam_str = sg->GetGame();
3835 sav_str = sg->GetSave();
3836 wmp_str1 = sg->GetWmap(0);
3837 if (WorldMapName[1][0]) {
3838 wmp_str2 = sg->GetWmap(1);
3839 if (!wmp_str2) {
3840 //upgrade an IWD game to HOW
3841 wmp_str2 = gamedata->GetResource( WorldMapName[1], IE_WMP_CLASS_ID );
3846 // These are here because of the goto
3847 PluginHolder<SaveGameMgr> gam_mgr(IE_GAM_CLASS_ID);
3848 PluginHolder<WorldMapMgr> wmp_mgr(IE_WMP_CLASS_ID);
3850 if (!gam_str || !(wmp_str1 || wmp_str2) )
3851 goto cleanup;
3853 // Load GAM file
3854 if (!gam_mgr)
3855 goto cleanup;
3857 if (!gam_mgr->Open( gam_str, true ))
3858 goto cleanup;
3860 new_game = gam_mgr->LoadGame(new Game(), ver_override);
3861 if (!new_game)
3862 goto cleanup;
3864 gam_str = NULL;
3866 // Load WMP (WorldMap) file
3867 if (!wmp_mgr)
3868 goto cleanup;
3870 if (!wmp_mgr->Open( wmp_str1, wmp_str2, true ))
3871 goto cleanup;
3873 new_worldmap = wmp_mgr->GetWorldMapArray( );
3875 wmp_str1 = NULL;
3876 wmp_str2 = NULL;
3878 LoadProgress(20);
3879 // Unpack SAV (archive) file to Cache dir
3880 if (sav_str) {
3881 PluginHolder<ArchiveImporter> ai(IE_BIF_CLASS_ID);
3882 if (ai) {
3883 if (ai->DecompressSaveGame(sav_str) != GEM_OK) {
3884 goto cleanup;
3887 delete sav_str;
3888 sav_str = NULL;
3891 // Let's assume that now is everything loaded OK and swap the objects
3893 delete game;
3894 delete worldmap;
3896 game = new_game;
3897 worldmap = new_worldmap;
3899 strings->OpenAux();
3900 LoadProgress(70);
3901 return;
3902 cleanup:
3903 // Something went wrong, so try to clean after itself
3905 delete new_game;
3906 delete new_worldmap;
3908 delete gam_str;
3909 delete wmp_str1;
3910 delete wmp_str2;
3911 delete sav_str;
3914 /* swapping out old resources */
3915 void Interface::UpdateMasterScript()
3917 if (game) {
3918 game->SetScript( GlobalScript, 0 );
3921 PluginHolder<WorldMapMgr> wmp_mgr(IE_WMP_CLASS_ID);
3922 if (! wmp_mgr)
3923 return;
3925 if (worldmap) {
3926 DataStream *wmp_str1 = gamedata->GetResource( WorldMapName[0], IE_WMP_CLASS_ID );
3927 DataStream *wmp_str2 = gamedata->GetResource( WorldMapName[1], IE_WMP_CLASS_ID );
3929 if (!wmp_mgr->Open( wmp_str1, wmp_str2, true )) {
3930 delete wmp_str1;
3931 delete wmp_str2;
3934 delete worldmap;
3935 worldmap = wmp_mgr->GetWorldMapArray();
3939 bool Interface::HideGCWindow()
3941 Window *window = GetWindow( 0 );
3942 // in the beginning, there's no window at all
3943 if (! window)
3944 return false;
3946 Control* gc = window->GetControl(0);
3947 if (gc->ControlType!=IE_GUI_GAMECONTROL) {
3948 return false;
3950 SetVisible(0, WINDOW_INVISIBLE);
3951 return true;
3954 void Interface::UnhideGCWindow()
3956 Window *window = GetWindow( 0 );
3957 if (!window)
3958 return;
3959 Control* gc = window->GetControl(0);
3960 if (gc->ControlType!=IE_GUI_GAMECONTROL)
3961 return;
3962 SetVisible(0, WINDOW_VISIBLE);
3965 GameControl *Interface::GetGameControl() const
3967 Window *window = GetWindow( 0 );
3968 // in the beginning, there's no window at all
3969 if (! window)
3970 return NULL;
3972 Control* gc = window->GetControl(0);
3973 if (gc == NULL) {
3974 return NULL;
3976 if (gc->ControlType!=IE_GUI_GAMECONTROL) {
3977 return NULL;
3979 return (GameControl *) gc;
3982 bool Interface::InitItemTypes()
3984 if (slotmatrix) {
3985 free(slotmatrix);
3987 AutoTable it("itemtype");
3988 ItemTypes = 0;
3989 if (it) {
3990 ItemTypes = it->GetRowCount(); //number of itemtypes
3991 if (ItemTypes<0) {
3992 ItemTypes = 0;
3994 int InvSlotTypes = it->GetColumnCount();
3995 if (InvSlotTypes > 32) { //bit count limit
3996 InvSlotTypes = 32;
3998 //make sure unsigned int is 32 bits
3999 slotmatrix = (ieDword *) malloc(ItemTypes * sizeof(ieDword) );
4000 for (int i=0;i<ItemTypes;i++) {
4001 unsigned int value = 0;
4002 unsigned int k = 1;
4003 for (int j=0;j<InvSlotTypes;j++) {
4004 if (strtol(it->QueryField(i,j),NULL,0) ) {
4005 value |= k;
4007 k <<= 1;
4009 //we let any items in the inventory
4010 slotmatrix[i] = (ieDword) value | SLOT_INVENTORY;
4014 //slottype describes the inventory structure
4015 Inventory::Init(HasFeature(GF_MAGICBIT));
4016 AutoTable st("slottype");
4017 if (slottypes) {
4018 free(slottypes);
4019 slottypes = NULL;
4021 SlotTypes = 0;
4022 if (st) {
4023 SlotTypes = st->GetRowCount();
4024 //make sure unsigned int is 32 bits
4025 slottypes = (SlotType *) malloc(SlotTypes * sizeof(SlotType) );
4026 memset(slottypes, -1, SlotTypes * sizeof(SlotType) );
4027 for (unsigned int row = 0; row < SlotTypes; row++) {
4028 bool alias;
4029 unsigned int i = (ieDword) strtol(st->GetRowName(row),NULL,0 );
4030 if (i>=SlotTypes) continue;
4031 if (slottypes[i].sloteffects!=0xffffffffu) {
4032 slottypes[row].slot = i;
4033 i=row;
4034 alias = true;
4035 } else {
4036 slottypes[row].slot = i;
4037 alias = false;
4039 slottypes[i].slottype = (ieDword) strtol(st->QueryField(row,0),NULL,0 );
4040 slottypes[i].slotid = (ieDword) strtol(st->QueryField(row,1),NULL,0 );
4041 strnlwrcpy( slottypes[i].slotresref, st->QueryField(row,2), 8 );
4042 slottypes[i].slottip = (ieDword) strtol(st->QueryField(row,3),NULL,0 );
4043 slottypes[i].slotflags = (ieDword) strtol(st->QueryField(row,5),NULL,0 );
4044 //don't fill sloteffects for aliased slots (pst)
4045 if (alias) {
4046 continue;
4048 slottypes[i].sloteffects = (ieDword) strtol(st->QueryField(row,4),NULL,0 );
4049 //setting special slots
4050 if (slottypes[i].slottype&SLOT_ITEM) {
4051 if (slottypes[i].slottype&SLOT_INVENTORY) {
4052 Inventory::SetInventorySlot(i);
4053 } else {
4054 Inventory::SetQuickSlot(i);
4057 switch (slottypes[i].sloteffects) {
4058 //fist slot, not saved, default weapon
4059 case SLOT_EFFECT_FIST: Inventory::SetFistSlot(i); break;
4060 //magic weapon slot, overrides all weapons
4061 case SLOT_EFFECT_MAGIC: Inventory::SetMagicSlot(i); break;
4062 //weapon slot, Equipping marker is relative to it
4063 case SLOT_EFFECT_MELEE: Inventory::SetWeaponSlot(i); break;
4064 //ranged slot
4065 case SLOT_EFFECT_MISSILE: Inventory::SetRangedSlot(i); break;
4066 //right hand
4067 case SLOT_EFFECT_LEFT: Inventory::SetShieldSlot(i); break;
4068 //head (for averting critical hit)
4069 case SLOT_EFFECT_HEAD: Inventory::SetHeadSlot(i); break;
4070 default:;
4074 return (it && st);
4077 ieDword Interface::FindSlot(unsigned int idx) const
4079 ieDword i;
4081 for (i=0;i<SlotTypes;i++) {
4082 if (idx==slottypes[i].slot) {
4083 break;
4086 return i;
4089 ieDword Interface::QuerySlot(unsigned int idx) const
4091 if (idx>=SlotTypes) {
4092 return 0;
4094 return slottypes[idx].slot;
4097 ieDword Interface::QuerySlotType(unsigned int idx) const
4099 if (idx>=SlotTypes) {
4100 return 0;
4102 return slottypes[idx].slottype;
4105 ieDword Interface::QuerySlotID(unsigned int idx) const
4107 if (idx>=SlotTypes) {
4108 return 0;
4110 return slottypes[idx].slotid;
4113 ieDword Interface::QuerySlottip(unsigned int idx) const
4115 if (idx>=SlotTypes) {
4116 return 0;
4118 return slottypes[idx].slottip;
4121 ieDword Interface::QuerySlotEffects(unsigned int idx) const
4123 if (idx>=SlotTypes) {
4124 return 0;
4126 return slottypes[idx].sloteffects;
4129 ieDword Interface::QuerySlotFlags(unsigned int idx) const
4131 if (idx>=SlotTypes) {
4132 return 0;
4134 return slottypes[idx].slotflags;
4137 const char *Interface::QuerySlotResRef(unsigned int idx) const
4139 if (idx>=SlotTypes) {
4140 return "";
4142 return slottypes[idx].slotresref;
4145 // checks the itemtype vs. slottype, and also checks the usability flags
4146 // vs. Actor's stats (alignment, class, race, kit etc.)
4147 int Interface::CanUseItemType(int slottype, Item *item, Actor *actor, bool feedback, bool equipped) const
4149 //inventory is a special case, we allow any items to enter it
4150 if ( slottype==-1 ) {
4151 return SLOT_INVENTORY;
4153 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
4154 //with twohandedness
4155 //As long as this is an Item, use the ITEM constant
4156 //switch for IE_INV_ITEM_* if it is a CREItem
4157 if (item->Flags&IE_ITEM_TWO_HANDED) {
4158 //if the item is twohanded and there are more slots, drop the shield slot
4159 if (slottype&~SLOT_SHIELD) {
4160 slottype&=~SLOT_SHIELD;
4162 if (slottype&SLOT_SHIELD) {
4163 //cannot equip twohanded in offhand
4164 if (feedback) displaymsg->DisplayConstantString(STR_NOT_IN_OFFHAND, 0xf0f0f0);
4165 return 0;
4169 if ( (unsigned int) item->ItemType>=(unsigned int) ItemTypes) {
4170 //invalid itemtype
4171 if (feedback) displaymsg->DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4172 return 0;
4175 //if actor is supplied, check its usability fields
4176 if (actor) {
4177 //constant strings
4178 int idx = actor->Unusable(item);
4179 if (idx) {
4180 if (feedback) displaymsg->DisplayConstantString(idx, 0xf0f0f0);
4181 return 0;
4183 //custom strings
4184 ieStrRef str = actor->Disabled(item->Name, item->ItemType);
4185 if (str && !equipped) {
4186 if (feedback) displaymsg->DisplayString(str, 0xf0f0f0, 0);
4187 return 0;
4191 //if any bit is true, the answer counts as true
4192 int ret = (slotmatrix[item->ItemType]&slottype);
4194 if (!ret) {
4195 if (feedback) displaymsg->DisplayConstantString(STR_WRONGITEMTYPE, 0xf0f0f0);
4196 return 0;
4199 //this warning comes only when feedback is enabled
4200 if (feedback) {
4201 //this was, but that disabled equipping of amber earrings in PST
4202 //if (slotmatrix[item->ItemType]&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4203 if (ret&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4204 //don't ruin the return variable, it contains the usable slot bits
4205 int flg = 0;
4206 if (ret&SLOT_QUIVER) {
4207 if (item->GetWeaponHeader(true)) flg = 1;
4210 if (ret&SLOT_WEAPON) {
4211 //melee
4212 if (item->GetWeaponHeader(false)) flg = 1;
4213 //ranged
4214 if (item->GetWeaponHeader(true)) flg = 1;
4217 if (ret&SLOT_ITEM) {
4218 if (item->GetEquipmentHeaderNumber(0)!=0xffff) flg = 1;
4221 if (!flg) {
4222 displaymsg->DisplayConstantString(STR_UNUSABLEITEM, 0xf0f0f0);
4223 return 0;
4228 return ret;
4231 Label *Interface::GetMessageLabel() const
4233 ieDword WinIndex = (ieDword) -1;
4234 ieDword TAIndex = (ieDword) -1;
4236 vars->Lookup( "OtherWindow", WinIndex );
4237 if (( WinIndex != (ieDword) -1 ) &&
4238 ( vars->Lookup( "MessageLabel", TAIndex ) )) {
4239 Window* win = GetWindow( (unsigned short) WinIndex );
4240 if (win) {
4241 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4242 if (ctrl && ctrl->ControlType==IE_GUI_LABEL)
4243 return (Label *) ctrl;
4246 return NULL;
4249 TextArea *Interface::GetMessageTextArea() const
4251 ieDword WinIndex = (ieDword) -1;
4252 ieDword TAIndex = (ieDword) -1;
4254 vars->Lookup( "MessageWindow", WinIndex );
4255 if (( WinIndex != (ieDword) -1 ) &&
4256 ( vars->Lookup( "MessageTextArea", TAIndex ) )) {
4257 Window* win = GetWindow( (unsigned short) WinIndex );
4258 if (win) {
4259 Control *ctrl = win->GetControl( (unsigned short) TAIndex );
4260 if (ctrl && ctrl->ControlType==IE_GUI_TEXTAREA)
4261 return (TextArea *) ctrl;
4264 return NULL;
4267 static const char *saved_extensions[]={".are",".sto",0};
4268 static const char *saved_extensions_last[]={".tot",".toh",0};
4270 //returns the priority of the file to be saved
4271 //2 - save
4272 //1 - save last
4273 //0 - don't save
4274 int Interface::SavedExtension(const char *filename)
4276 const char *str=strchr(filename,'.');
4277 if (!str) return 0;
4278 int i=0;
4279 while(saved_extensions[i]) {
4280 if (!stricmp(saved_extensions[i], str) ) return 2;
4281 i++;
4283 i=0;
4284 while(saved_extensions_last[i]) {
4285 if (!stricmp(saved_extensions_last[i], str) ) return 1;
4286 i++;
4288 return 0;
4291 static const char *protected_extensions[]={".exe",".dll",".so",0};
4293 //returns true if file should be saved
4294 bool Interface::ProtectedExtension(const char *filename)
4296 const char *str=strchr(filename,'.');
4297 if (!str) return false;
4298 int i=0;
4299 while(protected_extensions[i]) {
4300 if (!stricmp(protected_extensions[i], str) ) return true;
4301 i++;
4303 return false;
4306 void Interface::RemoveFromCache(const ieResRef resref, SClass_ID ClassID)
4308 char filename[_MAX_PATH];
4310 snprintf(filename, _MAX_PATH, "%s%.8s%s", CachePath, resref, TypeExt( ClassID ) );
4311 unlink ( filename);
4314 //this function checks if the path is eligible as a cache
4315 //if it contains a directory, or suspicious file extensions
4316 //we bail out, because the cache will be purged regularly.
4317 bool Interface::StupidityDetector(const char* Pt)
4319 char Path[_MAX_PATH];
4320 strcpy( Path, Pt );
4321 DirectoryIterator dir(Path);
4322 if (!dir) {
4323 printf("\n**cannot open**\n");
4324 return true;
4326 do {
4327 const char *name = dir.GetName();
4328 if (dir.IsDirectory()) {
4329 if (name[0] == '.') {
4330 if (name[1] == '\0')
4331 continue;
4332 if (name[1] == '.' && name[2] == '\0')
4333 continue;
4335 printf("\n**contains another dir**\n");
4336 return true; //a directory in there???
4338 if (ProtectedExtension(name) ) {
4339 printf("\n**contains alien files**\n");
4340 return true; //an executable file in there???
4342 } while (++dir);
4343 //ok, we got a good conscience
4344 return false;
4347 void Interface::DelTree(const char* Pt, bool onlysave)
4349 char Path[_MAX_PATH];
4351 if (!Pt[0]) return; //Don't delete the root filesystem :)
4352 strcpy( Path, Pt );
4353 DirectoryIterator dir(Path);
4354 if (!dir) {
4355 return;
4357 do {
4358 char *name = dir.GetName();
4359 if (dir.IsDirectory())
4360 continue;
4361 if (name[0] == '.')
4362 continue;
4363 if (!onlysave || SavedExtension(name) ) {
4364 char dtmp[_MAX_PATH];
4365 dir.GetFullPath(dtmp);
4366 unlink( dtmp );
4368 } while (++dir);
4371 void Interface::LoadProgress(int percent)
4373 vars->SetAt("Progress", percent);
4374 RedrawControls("Progress", percent);
4375 RedrawAll();
4376 DrawWindows();
4377 video->SwapBuffers();
4380 void Interface::ReleaseDraggedItem()
4382 DraggedItem=NULL; //shouldn't free this
4383 video->SetDragCursor (NULL);
4386 void Interface::DragItem(CREItem *item, const ieResRef Picture)
4388 //We should drop the dragged item and pick this up,
4389 //we shouldn't have a valid DraggedItem at this point.
4390 //Anyway, if there is still a dragged item, it will be destroyed.
4391 if (DraggedItem) {
4392 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW);
4393 delete DraggedItem;
4395 DraggedItem = item;
4396 if (video) {
4397 Sprite2D* DraggedCursor = NULL;
4398 if (item) {
4399 DraggedCursor = gamedata->GetBAMSprite( Picture, 0, 0 );
4401 video->SetDragCursor (DraggedCursor);
4405 void Interface::SetDraggedPortrait(int dp, int idx)
4407 if (idx<0) idx=14;
4408 DraggedPortrait = dp;
4409 if (dp) {
4410 //hmm this might work?
4411 Cursors[idx]->acquire();
4412 video->SetDragCursor(Cursors[idx]);
4413 } else {
4414 video->SetDragCursor(NULL);
4418 bool Interface::ReadItemTable(const ieResRef TableName, const char * Prefix)
4420 ieResRef ItemName;
4421 int i,j;
4423 AutoTable tab(TableName);
4424 if (!tab) {
4425 return false;
4427 i=tab->GetRowCount();
4428 for(j=0;j<i;j++) {
4429 if (Prefix) {
4430 snprintf(ItemName,sizeof(ItemName),"%s%02d",Prefix, j+1);
4431 } else {
4432 strnlwrcpy(ItemName,tab->GetRowName(j), 8);
4434 //Variable elements are free'd, so we have to use malloc
4435 //well, not anymore, we can use ReleaseFunction
4436 int l=tab->GetColumnCount(j);
4437 if (l<1) continue;
4438 int cl = atoi(tab->GetColumnName(0));
4439 ItemList *itemlist = new ItemList(l, cl);
4440 for(int k=0;k<l;k++) {
4441 strnlwrcpy(itemlist->ResRefs[k],tab->QueryField(j,k), 8);
4443 RtRows->SetAt(ItemName, (void*)itemlist);
4445 return true;
4448 bool Interface::ReadRandomItems()
4450 ieResRef RtResRef;
4451 int i;
4453 ieDword difflev=0; //rt norm or rt fury
4454 vars->Lookup("Nightmare Mode", difflev);
4455 if (RtRows) {
4456 RtRows->RemoveAll(ReleaseItemList);
4458 else {
4459 RtRows=new Variables(10, 17); //block size, hash table size
4460 if (!RtRows) {
4461 return false;
4463 RtRows->SetType( GEM_VARIABLES_POINTER );
4465 AutoTable tab("randitem");
4466 if (!tab) {
4467 return false;
4469 if (difflev>=tab->GetColumnCount()) {
4470 difflev = tab->GetColumnCount()-1;
4473 //the gold item
4474 strnlwrcpy( GoldResRef, tab->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4475 if ( GoldResRef[0]=='*' ) {
4476 return false;
4478 strnlwrcpy( RtResRef, tab->QueryField( 1, difflev ), 8);
4479 i=atoi( RtResRef );
4480 if (i<1) {
4481 ReadItemTable( RtResRef, 0 ); //reading the table itself
4482 return true;
4484 if (i>5) {
4485 i=5;
4487 while(i--) {
4488 strnlwrcpy( RtResRef, tab->QueryField(2+i,difflev), 8);
4489 ReadItemTable( RtResRef,tab->GetRowName(2+i) );
4491 return true;
4494 CREItem *Interface::ReadItem(DataStream *str)
4496 CREItem *itm = new CREItem();
4498 str->ReadResRef( itm->ItemResRef );
4499 str->ReadWord( &itm->Expired );
4500 str->ReadWord( &itm->Usages[0] );
4501 str->ReadWord( &itm->Usages[1] );
4502 str->ReadWord( &itm->Usages[2] );
4503 str->ReadDword( &itm->Flags );
4504 if (ResolveRandomItem(itm) ) {
4505 return itm;
4507 delete itm;
4508 return NULL;
4511 #define MAX_LOOP 10
4513 //This function generates random items based on the randitem.2da file
4514 //there could be a loop, but we don't want to freeze, so there is a limit
4515 bool Interface::ResolveRandomItem(CREItem *itm)
4517 if (!RtRows) return true;
4518 for(int loop=0;loop<MAX_LOOP;loop++) {
4519 int i,j,k;
4520 char *endptr;
4521 ieResRef NewItem;
4523 void* lookup;
4524 if ( !RtRows->Lookup( itm->ItemResRef, lookup ) ) {
4525 return true;
4527 ItemList *itemlist = (ItemList*)lookup;
4528 if (itemlist->WeightOdds) {
4529 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4530 i=Roll(2,(itemlist->Count+1)/2,-2);
4531 } else {
4532 i=Roll(1,itemlist->Count,-1);
4534 strnlwrcpy( NewItem, itemlist->ResRefs[i], 8);
4535 char *p=(char *) strchr(NewItem,'*');
4536 if (p) {
4537 *p=0; //doing this so endptr is ok
4538 k=strtol(p+1,NULL,10);
4539 } else {
4540 k=1;
4542 j=strtol(NewItem,&endptr,10);
4543 if (j<1) {
4544 j=1;
4546 if (*endptr) {
4547 strnlwrcpy(itm->ItemResRef, NewItem, 8);
4548 } else {
4549 strnlwrcpy(itm->ItemResRef, GoldResRef, 8);
4551 if ( !memcmp( itm->ItemResRef,"no_drop",8 ) ) {
4552 itm->ItemResRef[0]=0;
4554 if (!itm->ItemResRef[0]) {
4555 return false;
4557 itm->Usages[0]=(ieWord) Roll(j,k,0);
4559 printMessage("Interface"," ",LIGHT_RED);
4560 printf("Loop detected while generating random item:%s\n",itm->ItemResRef);
4561 return false;
4564 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4565 //these functions are needed because Win32 doesn't allow freeing memory from
4566 //another dll. So we allocate all commonly used memories from core
4567 ITMExtHeader *Interface::GetITMExt(int count)
4569 return new ITMExtHeader[count];
4572 SPLExtHeader *Interface::GetSPLExt(int count)
4574 return new SPLExtHeader[count];
4577 Effect *Interface::GetEffect(ieDword opcode)
4579 if (opcode==0xffffffff) {
4580 return NULL;
4582 Effect *fx = new Effect();
4583 if (!fx) {
4584 return NULL;
4586 memset(fx,0,sizeof(Effect));
4587 fx->Opcode=opcode;
4588 return fx;
4591 Effect *Interface::GetFeatures(int count)
4593 return new Effect[count];
4597 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4599 delete [] p;
4600 delete [] e;
4603 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4605 delete [] p;
4606 delete [] e;
4610 WorldMapArray *Interface::NewWorldMapArray(int count)
4612 return new WorldMapArray(count);
4615 Container *Interface::GetCurrentContainer()
4617 return CurrentContainer;
4620 int Interface::CloseCurrentContainer()
4622 UseContainer = false;
4623 if ( !CurrentContainer) {
4624 return -1;
4626 //remove empty ground piles on closeup
4627 CurrentContainer->GetCurrentArea()->TMap->CleanupContainer(CurrentContainer);
4628 CurrentContainer = NULL;
4629 return 0;
4632 void Interface::SetCurrentContainer(Actor *actor, Container *arg, bool flag)
4634 //abort action if the first selected PC isn't the original actor
4635 if (actor!=GetFirstSelectedPC(false)) {
4636 CurrentContainer = NULL;
4637 return;
4639 CurrentContainer = arg;
4640 UseContainer = flag;
4643 Store *Interface::GetCurrentStore()
4645 return CurrentStore;
4648 int Interface::CloseCurrentStore()
4650 if ( !CurrentStore ) {
4651 return -1;
4653 PluginHolder<StoreMgr> sm(IE_STO_CLASS_ID);
4654 if (sm == NULL) {
4655 return -1;
4657 int size = sm->GetStoredFileSize (CurrentStore);
4658 if (size > 0) {
4659 //created streams are always autofree (close file on destruct)
4660 //this one will be destructed when we return from here
4661 FileStream str;
4663 str.Create( CurrentStore->Name, IE_STO_CLASS_ID );
4664 int ret = sm->PutStore (&str, CurrentStore);
4665 if (ret <0) {
4666 printMessage("Core"," ", YELLOW);
4667 printf("Store removed: %s\n", CurrentStore->Name);
4668 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4670 } else {
4671 printMessage("Core"," ", YELLOW);
4672 printf("Store removed: %s\n", CurrentStore->Name);
4673 RemoveFromCache(CurrentStore->Name, IE_STO_CLASS_ID);
4675 //make sure the stream isn't connected to sm, or it will be double freed
4676 delete CurrentStore;
4677 CurrentStore = NULL;
4678 return 0;
4681 Store *Interface::SetCurrentStore(const ieResRef resname, ieDword owner)
4683 if ( CurrentStore ) {
4684 if ( !strnicmp(CurrentStore->Name, resname, 8) ) {
4685 return CurrentStore;
4688 //not simply delete the old store, but save it
4689 CloseCurrentStore();
4692 DataStream* str = gamedata->GetResource( resname, IE_STO_CLASS_ID );
4693 PluginHolder<StoreMgr> sm(IE_STO_CLASS_ID);
4694 if (sm == NULL) {
4695 delete ( str );
4696 return NULL;
4698 if (!sm->Open( str, true )) {
4699 return NULL;
4702 // FIXME - should use some already allocated in core
4703 // not really, only one store is open at a time, then it is
4704 // unloaded, we don't really have to cache it, it will be saved in
4705 // Cache anyway!
4706 CurrentStore = sm->GetStore( new Store() );
4707 if (CurrentStore == NULL) {
4708 return NULL;
4710 strnlwrcpy(CurrentStore->Name, resname, 8);
4711 if (owner) {
4712 CurrentStore->SetOwnerID(owner);
4714 return CurrentStore;
4717 void Interface::SetMouseScrollSpeed(int speed) {
4718 mousescrollspd = (speed+1)*2;
4721 int Interface::GetMouseScrollSpeed() {
4722 return mousescrollspd;
4725 ieStrRef Interface::GetRumour(const ieResRef dlgref)
4727 PluginHolder<DialogMgr> dm(IE_DLG_CLASS_ID);
4728 dm->Open( gamedata->GetResource( dlgref, IE_DLG_CLASS_ID ), true );
4729 Dialog *dlg = dm->GetDialog();
4731 if (!dlg) {
4732 printMessage("Interface"," ", LIGHT_RED);
4733 printf( "Cannot load dialog: %s\n", dlgref );
4734 return (ieStrRef) -1;
4736 Scriptable *pc=game->GetPC( game->GetSelectedPCSingle(), false );
4738 ieStrRef ret = (ieStrRef) -1;
4739 int i = dlg->FindRandomState( pc );
4740 if (i>=0 ) {
4741 ret = dlg->GetState( i )->StrRef;
4743 delete dlg;
4744 return ret;
4747 void Interface::DoTheStoreHack(Store *s)
4749 size_t size = s->PurchasedCategoriesCount * sizeof( ieDword );
4750 s->purchased_categories=(ieDword *) malloc(size);
4752 size = s->CuresCount * sizeof( STOCure );
4753 s->cures=(STOCure *) malloc(size);
4755 size = s->DrinksCount * sizeof( STODrink );
4756 s->drinks=(STODrink *) malloc(size);
4758 for(size=0;size<s->ItemsCount;size++) {
4759 STOItem *si = new STOItem();
4760 memset(si, 0, sizeof(STOItem) );
4761 s->items.push_back( si );
4765 //plays stock sound listed in defsound.2da
4766 void Interface::PlaySound(int index)
4768 if (index<=DSCount) {
4769 AudioDriver->Play(DefSound[index]);
4773 Actor *Interface::GetFirstSelectedPC(bool forced)
4775 int partySize = game->GetPartySize( false );
4776 if (!partySize) return NULL;
4777 for (int i = 0; i < partySize; i++) {
4778 Actor* actor = game->GetPC( i,false );
4779 if (actor->IsSelected()) {
4780 return actor;
4784 if (forced) {
4785 return game->GetPC(0,false);
4787 return NULL;
4790 Actor *Interface::GetFirstSelectedActor()
4792 if (game->selected.size()) {
4793 return game->selected[0];
4795 return NULL;
4798 //this is used only for the console
4799 Sprite2D *Interface::GetCursorSprite()
4801 Sprite2D *spr = gamedata->GetBAMSprite(CursorBam, 0, 0);
4802 if (spr)
4804 if(HasFeature(GF_OVERRIDE_CURSORPOS))
4806 spr->XPos=1;
4807 spr->YPos=spr->Height-1;
4810 return spr;
4813 Sprite2D *Interface::GetScrollCursorSprite(int frameNum, int spriteNum)
4815 return gamedata->GetBAMSprite(ScrollCursorBam, frameNum, spriteNum);
4818 /* we should return -1 if it isn't gold, otherwise return the gold value */
4819 int Interface::CanMoveItem(const CREItem *item) const
4821 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4822 if (!HasFeature(GF_NO_DROP_CAN_MOVE) ) {
4823 if (item->Flags & IE_INV_ITEM_UNDROPPABLE)
4824 return 0;
4826 //not gold, we allow only one single coin ResRef, this is good
4827 //for all of the original games
4828 if (strnicmp(item->ItemResRef, GoldResRef, 8 ) )
4829 return -1;
4830 //gold, returns the gold value (stack size)
4831 return item->Usages[0];
4834 // dealing with applying effects
4835 void Interface::ApplySpell(const ieResRef resname, Actor *actor, Scriptable *caster, int level)
4837 Spell *spell = gamedata->GetSpell(resname);
4838 if (!spell) {
4839 return;
4842 level = spell->GetHeaderIndexFromLevel(level);
4843 EffectQueue *fxqueue = spell->GetEffectBlock(caster, actor->Pos, level);
4845 ApplyEffectQueue(fxqueue, actor, caster, actor->Pos);
4846 delete fxqueue;
4849 void Interface::ApplySpellPoint(const ieResRef resname, Map* area, const Point &pos, Scriptable *caster, int level)
4851 Spell *spell = gamedata->GetSpell(resname);
4852 if (!spell) {
4853 return;
4855 level = spell->GetHeaderIndexFromLevel(level);
4856 Projectile *pro = spell->GetProjectile(caster, level, pos);
4857 pro->SetCaster(caster->GetGlobalID());
4858 area->AddProjectile(pro, caster->Pos, pos);
4861 //-1 means the effect was reflected back to the caster
4862 //0 means the effect was resisted and should be removed
4863 //1 means the effect was applied
4864 int Interface::ApplyEffect(Effect *effect, Actor *actor, Scriptable *caster)
4866 if (!effect) {
4867 return 0;
4870 EffectQueue *fxqueue = new EffectQueue();
4871 //AddEffect now copies the fx data, please delete your effect reference
4872 //if you created it. (Don't delete cached references)
4873 fxqueue->AddEffect( effect );
4874 int res = ApplyEffectQueue(fxqueue, actor, caster);
4875 delete fxqueue;
4876 return res;
4879 int Interface::ApplyEffectQueue(EffectQueue *fxqueue, Actor *actor, Scriptable *caster)
4881 Point p;
4882 p.empty(); //the effect should have all its coordinates already set
4883 return ApplyEffectQueue(fxqueue, actor, caster, p);
4886 int Interface::ApplyEffectQueue(EffectQueue *fxqueue, Actor *actor, Scriptable *caster, Point p)
4888 int res = fxqueue->CheckImmunity ( actor );
4889 if (res) {
4890 if (res == -1 ) {
4891 //bounced back at a nonliving caster
4892 if (caster->Type!=ST_ACTOR) {
4893 return 0;
4895 actor = (Actor *) caster;
4897 fxqueue->SetOwner( caster );
4899 if (fxqueue->AddAllEffects( actor, p )==FX_NOT_APPLIED) {
4900 res=0;
4903 return res;
4906 Effect *Interface::GetEffect(const ieResRef resname, int level, const Point &p)
4908 //Don't free this reference, it is cached!
4909 Effect *effect = gamedata->GetEffect(resname);
4910 if (!effect) {
4911 return NULL;
4913 if (!level) {
4914 level = 1;
4916 effect->Power = level;
4917 effect->PosX=p.x;
4918 effect->PosY=p.y;
4919 return effect;
4922 // dealing with saved games
4923 int Interface::SwapoutArea(Map *map)
4925 PluginHolder<MapMgr> mm(IE_ARE_CLASS_ID);
4926 if (mm == NULL) {
4927 return -1;
4929 int size = mm->GetStoredFileSize (map);
4930 if (size > 0) {
4931 //created streams are always autofree (close file on destruct)
4932 //this one will be destructed when we return from here
4933 FileStream str;
4935 str.Create( map->GetScriptName(), IE_ARE_CLASS_ID );
4936 int ret = mm->PutArea (&str, map);
4937 if (ret <0) {
4938 printMessage("Core"," ", YELLOW);
4939 printf("Area removed: %s\n", map->GetScriptName());
4940 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4942 } else {
4943 printMessage("Core"," ", YELLOW);
4944 printf("Area removed: %s\n", map->GetScriptName());
4945 RemoveFromCache(map->GetScriptName(), IE_ARE_CLASS_ID);
4947 //make sure the stream isn't connected to sm, or it will be double freed
4948 return 0;
4951 int Interface::WriteCharacter(const char *name, Actor *actor)
4953 char Path[_MAX_PATH];
4955 PathJoin( Path, GamePath, GameCharactersPath, NULL );
4956 if (!actor) {
4957 return -1;
4959 PluginHolder<ActorMgr> gm(IE_CRE_CLASS_ID);
4960 if (gm == NULL) {
4961 return -1;
4964 //str is freed
4966 FileStream str;
4968 str.Create( Path, name, IE_CHR_CLASS_ID );
4970 int ret = gm->PutActor(&str, actor, true);
4971 if (ret <0) {
4972 printMessage("Core"," ", YELLOW);
4973 printf("Character cannot be saved: %s\n", name);
4974 return -1;
4978 //write the BIO string
4979 if (!HasFeature(GF_NO_BIOGRAPHY)) {
4980 FileStream str;
4982 str.Create( Path, name, IE_BIO_CLASS_ID );
4983 //never write the string reference into this string
4984 char *tmp = GetString(actor->GetVerbalConstant(VB_BIO),IE_STR_STRREFOFF);
4985 str.Write (tmp, strlen(tmp));
4986 free(tmp);
4988 return 0;
4991 int Interface::WriteGame(const char *folder)
4993 PluginHolder<SaveGameMgr> gm(IE_GAM_CLASS_ID);
4994 if (gm == NULL) {
4995 return -1;
4998 int size = gm->GetStoredFileSize (game);
4999 if (size > 0) {
5000 //created streams are always autofree (close file on destruct)
5001 //this one will be destructed when we return from here
5002 FileStream str;
5004 str.Create( folder, GameNameResRef, IE_GAM_CLASS_ID );
5005 int ret = gm->PutGame (&str, game);
5006 if (ret <0) {
5007 printMessage("Core"," ", YELLOW);
5008 printf("Game cannot be saved: %s\n", folder);
5009 return -1;
5011 } else {
5012 printMessage("Core"," ", YELLOW);
5013 printf("Internal error, game cannot be saved: %s\n", folder);
5014 return -1;
5016 return 0;
5019 int Interface::WriteWorldMap(const char *folder)
5021 PluginHolder<WorldMapMgr> wmm(IE_WMP_CLASS_ID);
5022 if (wmm == NULL) {
5023 return -1;
5026 if (WorldMapName[1][0]) {
5027 worldmap->SetSingle(false);
5030 int size1 = wmm->GetStoredFileSize (worldmap, 0);
5031 int size2 = 1; //just a dummy value
5033 //if size is 0 for the first worldmap, then there is a problem
5034 if (!worldmap->IsSingle() && (size1>0) ) {
5035 size2=wmm->GetStoredFileSize (worldmap, 1);
5038 int ret = 0;
5039 if ((size1 < 0) || (size2<0) ) {
5040 ret=-1;
5041 } else {
5042 //created streams are always autofree (close file on destruct)
5043 //this one will be destructed when we return from here
5044 FileStream str1;
5045 FileStream str2;
5047 str1.Create( folder, WorldMapName[0], IE_WMP_CLASS_ID );
5048 if (!worldmap->IsSingle()) {
5049 str2.Create( folder, WorldMapName[1], IE_WMP_CLASS_ID );
5051 ret = wmm->PutWorldMap (&str1, &str2, worldmap);
5053 if (ret <0) {
5054 printMessage("Core"," ", YELLOW);
5055 printf("Internal error, worldmap cannot be saved: %s\n", folder);
5056 return -1;
5058 return 0;
5061 int Interface::CompressSave(const char *folder)
5063 FileStream str;
5065 str.Create( folder, GameNameResRef, IE_SAV_CLASS_ID );
5066 DirectoryIterator dir(CachePath);
5067 if (!dir) {
5068 return -1;
5070 //BIF and SAV are the same
5071 PluginHolder<ArchiveImporter> ai(IE_BIF_CLASS_ID);
5072 ai->CreateArchive( &str);
5074 //.tot and .toh should be saved last, because they are updated when an .are is saved
5075 int priority=2;
5076 while(priority) {
5077 do {
5078 const char *name = dir.GetName();
5079 if (dir.IsDirectory())
5080 continue;
5081 if (name[0] == '.')
5082 continue;
5083 if (SavedExtension(name)==priority) {
5084 char dtmp[_MAX_PATH];
5085 dir.GetFullPath(dtmp);
5086 FileStream fs;
5087 fs.Open(dtmp, true);
5088 ai->AddToSaveGame(&str, &fs);
5090 } while (++dir);
5091 //reopen list for the second round
5092 priority--;
5093 if (priority>0) {
5094 dir.Rewind();
5097 return 0;
5100 int Interface::GetMaximumAbility() const { return MaximumAbility; }
5102 int Interface::GetStrengthBonus(int column, int value, int ex) const
5104 //to hit, damage, open doors, weight allowance
5105 if (column<0 || column>3)
5106 return -9999;
5108 if (value<0)
5109 value = 0;
5110 else if (value>25)
5111 value = 25;
5113 if (ex<0)
5114 ex=0;
5115 else if (ex>100)
5116 ex=100;
5118 return strmod[column*(MaximumAbility+1)+value]+strmodex[column*101+ex];
5121 // we don't use the stuff maze yet
5122 // IE: bonus skill points are ignored and the plain int mod used!
5123 int Interface::GetIntelligenceBonus(int column, int value) const
5125 if (HasFeature(GF_3ED_RULES)) {
5126 //learn spell, max spell level, max spell number on level, bonus skill points
5127 if (column<0 || column>2) return -9999;
5128 } else {
5129 //learn spell, max spell level, max spell number on level, maze duration dice, maze duration dice size
5130 if (column<0 || column>4) return -9999;
5133 return intmod[column*(MaximumAbility+1)+value];
5136 int Interface::GetDexterityBonus(int column, int value) const
5138 //no dexmod in iwd2 and only one type of modifier
5139 if (HasFeature(GF_3ED_RULES)) {
5140 return (value-10)/2;
5143 //reaction, missile, ac
5144 if (column<0 || column>2)
5145 return -9999;
5147 return dexmod[column*(MaximumAbility+1)+value];
5150 int Interface::GetConstitutionBonus(int column, int value) const
5152 //no conmod in iwd2
5153 if (HasFeature(GF_3ED_RULES)) {
5154 return (value-10)/2;
5157 //normal, warrior, minimum, regen hp, regen fatigue
5158 if (column<0 || column>4)
5159 return -9999;
5161 return conmod[column*(MaximumAbility+1)+value];
5164 int Interface::GetCharismaBonus(int column, int /*value*/) const
5166 // store price reduction
5167 if (column<0 || column>(MaximumAbility-1))
5168 return -9999;
5170 return chrmod[column];
5173 int Interface::GetLoreBonus(int column, int value) const
5175 //no lorebon in iwd2 - lore is a skill
5176 if (HasFeature(GF_3ED_RULES)) return 0;
5178 if (column<0 || column>0)
5179 return -9999;
5181 return lorebon[value];
5184 int Interface::GetWisdomBonus(int column, int value) const
5186 //no wismod in iwd2
5187 if (HasFeature(GF_3ED_RULES)) {
5188 return (value-10)/2;
5191 if (!HasFeature(GF_WISDOM_BONUS)) return 0;
5193 // xp bonus
5194 if (column<0 || column>0)
5195 return -9999;
5197 return wisbon[value];
5200 int Interface::GetReputationMod(int column) const
5202 int reputation = game->Reputation / 10 - 1;
5204 if (column<0 || column>8) {
5205 return -9999;
5207 if (reputation > 19) {
5208 reputation = 19;
5210 if (reputation < 0) {
5211 reputation = 0;
5214 return reputationmod[reputation][column];
5217 // -3, -2 if request is illegal or in cutscene
5218 // -1 if pause is already active
5219 // 0 if pause was not allowed
5220 // 1 if autopause happened
5221 int Interface::Autopause(ieDword flag)
5223 GameControl *gc = GetGameControl();
5224 if (!gc) {
5225 return -3;
5227 if (InCutSceneMode()) {
5228 return -2;
5230 if (gc->GetDialogueFlags()&DF_FREEZE_SCRIPTS) {
5231 return -1;
5233 ieDword autopause_flags = 0;
5235 vars->Lookup("Auto Pause State", autopause_flags);
5236 if (autopause_flags & (1<<flag)) {
5237 displaymsg->DisplayConstantString(STR_AP_UNUSABLE+flag, 0xff0000);
5238 gc->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
5239 return 1;
5241 return 0;
5244 void Interface::RegisterOpcodes(int count, const EffectRef *opcodes)
5246 EffectQueue_RegisterOpcodes(count, opcodes);
5249 void Interface::SetInfoTextColor(const Color &color)
5251 if (InfoTextPalette) {
5252 gamedata->FreePalette(InfoTextPalette);
5254 InfoTextPalette = CreatePalette(color, black);
5257 //todo row?
5258 void Interface::GetResRefFrom2DA(const ieResRef resref, ieResRef resource1, ieResRef resource2, ieResRef resource3)
5260 if (!resource1) {
5261 return;
5263 resource1[0]=0;
5264 if (resource2) {
5265 resource2[0]=0;
5267 if (resource3) {
5268 resource3[0]=0;
5270 AutoTable tab(resref);
5271 if (tab) {
5272 unsigned int cols = tab->GetColumnCount();
5273 unsigned int row = (unsigned int) Roll(1,tab->GetRowCount(),-1);
5274 strnuprcpy(resource1, tab->QueryField(row,0), 8);
5275 if (resource2 && cols>1)
5276 strnuprcpy(resource2, tab->QueryField(row,1), 8);
5277 if (resource3 && cols>2)
5278 strnuprcpy(resource3, tab->QueryField(row,2), 8);
5282 ieDword *Interface::GetListFrom2DAInternal(const ieResRef resref)
5284 ieDword *ret;
5286 AutoTable tab(resref);
5287 if (tab) {
5288 ieDword cnt = tab->GetRowCount();
5289 ret = (ieDword *) malloc((1+cnt)*sizeof(ieDword));
5290 ret[0]=cnt;
5291 while(cnt) {
5292 ret[cnt]=strtol(tab->QueryField(cnt-1, 0),NULL, 0);
5293 cnt--;
5295 return ret;
5297 ret = (ieDword *) malloc(sizeof(ieDword));
5298 ret[0]=0;
5299 return ret;
5302 ieDword* Interface::GetListFrom2DA(const ieResRef tablename)
5304 ieDword *list;
5306 if (!lists->Lookup(tablename, (void *&) list)) {
5307 list = GetListFrom2DAInternal(tablename);
5308 lists->SetAt(tablename, list);
5311 return list;
5314 //returns a numeric value associated with a stat name (symbol) from stats.ids
5315 ieDword Interface::TranslateStat(const char *stat_name)
5317 long tmp;
5319 if (valid_number(stat_name, tmp)) {
5320 return (ieDword) tmp;
5323 int symbol = LoadSymbol( "stats" );
5324 Holder<SymbolMgr> sym = GetSymbol( symbol );
5325 ieDword stat = (ieDword) sym->GetValue( stat_name );
5326 if (stat==(ieDword) ~0) {
5327 printMessage("Core"," ",YELLOW);
5328 printf("Cannot translate symbol: %s\n", stat_name);
5330 return stat;
5333 void Interface::WaitForDisc(int disc_number, const char* path)
5335 GetDictionary()->SetAt( "WaitForDisc", (ieDword) disc_number );
5337 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5338 do {
5339 DrawWindows();
5340 for (size_t i=0;i<CD[disc_number-1].size();i++) {
5341 char name[_MAX_PATH];
5343 PathJoin(name, CD[disc_number-1][i].c_str(),path,NULL);
5344 if (file_exists (name)) {
5345 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5346 return;
5350 } while (video->SwapBuffers() == GEM_OK);
5353 // remove the extraneus EOL newline and carriage return
5354 void Interface::StripLine(char * string, size_t size) {
5355 if (size >= 2 && string[size-2] == '\n') {
5356 string[size-2] = '\0';
5358 if (size >= 3 && string[size-3] == '\r') {
5359 string[size-3] = '\0'; // remove the carriage return too
5363 void Interface::SetNextScript(const char *script)
5365 strncpy( NextScript, script, sizeof(NextScript) );
5366 QuitFlag |= QF_CHANGESCRIPT;
5369 void Interface::SanityCheck(const char *ver) {
5370 if (strcmp(ver, VERSION_GEMRB)) {
5371 printf("version check failed: core version %s doesn't match caller's version %s\n", VERSION_GEMRB, ver);
5372 abort();