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.
25 #include "Interface.h"
33 #include "AmbientMgr.h"
34 #include "AnimationMgr.h"
35 #include "ArchiveImporter.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"
50 #include "MoviePlayer.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"
63 #include "StringMgr.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"
80 GEM_EXPORT Interface
* core
;
83 GEM_EXPORT HANDLE hConsole
;
86 //use DialogF.tlk if the protagonist is female, that's why we leave space
87 static const char dialogtlk
[] = "dialog.tlk\0";
89 static int MaximumAbility
= 25;
90 static ieWordSigned
*strmod
= NULL
;
91 static ieWordSigned
*strmodex
= NULL
;
92 static ieWordSigned
*intmod
= NULL
;
93 static ieWordSigned
*dexmod
= NULL
;
94 static ieWordSigned
*conmod
= NULL
;
95 static ieWordSigned
*chrmod
= NULL
;
96 static ieWordSigned
*lorebon
= NULL
;
97 static ieWordSigned
*wisbon
= NULL
;
98 static int **reputationmod
= NULL
;
99 static ieVariable IWD2DeathVarFormat
= "_DEAD%s";
100 static ieVariable DeathVarFormat
= "SPRITE_IS_DEAD%s";
102 Interface::Interface(int iargc
, char* iargv
[])
107 hConsole
= GetStdHandle( STD_OUTPUT_HANDLE
);
109 textcolor( LIGHT_WHITE
);
110 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB
);
112 // default to the correct endianswitch
113 ieWord endiantest
= 1;
114 if (((char *)&endiantest
)[1] == 1) {
116 DataStream::SetEndianSwitch(true);
121 pl_uppercase
[i
]=(ieByte
) toupper(i
);
122 pl_lowercase
[i
]=(ieByte
) tolower(i
);
126 VideoDriverName
= "sdl";
127 AudioDriverName
= "openal";
136 CurrentContainer
= NULL
;
137 UseContainer
= false;
138 InfoTextPalette
= NULL
;
149 tooltip_currtextw
= 0;
164 ConsolePopped
= false;
167 QuitFlag
= QF_NORMAL
;
168 EventFlag
= EF_CONTROL
;
170 CaseSensitive
= true; //this is the default value, so CD1/CD2 will be resolved
172 CaseSensitive
= false;
175 SkipIntroVideos
= false;
179 GUIScriptsPath
[0] = 0;
185 GemRBOverridePath
[0] = 0;
188 strncpy( GameOverridePath
, "override", sizeof(GameOverridePath
) );
189 strncpy( GameSoundsPath
, "sounds", sizeof(GameSoundsPath
) );
190 strncpy( GameScriptsPath
, "scripts", sizeof(GameScriptsPath
) );
191 strncpy( GamePortraitsPath
, "portraits", sizeof(GamePortraitsPath
) );
192 strncpy( GameCharactersPath
, "characters", sizeof(GameCharactersPath
) );
193 strncpy( GameDataPath
, "data", sizeof(GameDataPath
) );
194 strncpy( INIConfig
, "baldur.ini", sizeof(INIConfig
) );
195 strncpy( ButtonFont
, "STONESML", sizeof(ButtonFont
) );
196 strncpy( TooltipFont
, "STONESML", sizeof(TooltipFont
) );
197 strncpy( MovieFont
, "STONESML", sizeof(MovieFont
) );
198 strncpy( ScrollCursorBam
, "CURSARW", sizeof(ScrollCursorBam
) );
199 strncpy( GlobalScript
, "BALDUR", sizeof(GlobalScript
) );
200 strncpy( WorldMapName
, "WORLDMAP", sizeof(WorldMapName
) );
201 strncpy( Palette16
, "MPALETTE", sizeof(Palette16
) );
202 strncpy( Palette32
, "PAL32", sizeof(Palette32
) );
203 strncpy( Palette256
, "MPAL256", sizeof(Palette256
) );
204 strcpy( TooltipBackResRef
, "\0" );
205 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
206 strcpy( GroundCircleBam
[size
], "\0" );
207 GroundCircleScale
[size
] = 0;
210 TooltipColor
.g
= 255;
212 TooltipColor
.a
= 255;
222 memset( WindowFrames
, 0, sizeof( WindowFrames
));
223 memset( GroundCircles
, 0, sizeof( GroundCircles
));
224 memset(FogSprites
, 0, sizeof( FogSprites
));
225 AreaAliasTable
= NULL
;
226 ItemExclTable
= NULL
;
227 ItemDialTable
= NULL
;
228 ItemDial2Table
= NULL
;
229 ItemTooltipTable
= NULL
;
230 update_scripts
= false;
232 gamedata
= new GameData();
235 #define FreeResourceVector(type, variable) \
237 size_t i=variable.size(); \
240 delete variable[i]; \
246 static void ReleaseItemList(void *poi
)
248 delete ((ItemList
*) poi
);
251 void FreeAbilityTables()
287 void Interface::FreeResRefTable(ieResRef
*&table
, int &count
)
295 static void ReleaseItemTooltip(void *poi
)
300 Interface::~Interface(void)
303 delete AreaAliasTable
;
308 // stop any ambients which are still enqueued
310 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
311 if (ambim
) ambim
->deactivate();
313 //destroy the highest objects in the hierarchy first!
321 for (unsigned int i
=0; i
<20; i
++) {
322 if (reputationmod
[i
]) {
323 free(reputationmod
[i
]);
330 PluginMgr::Get()->RunCleanup();
332 ReleaseMemoryActor();
333 EffectQueue_ReleaseMemory();
334 CharAnimations::ReleaseMemory();
337 FreeResRefTable(DefSound
, DSCount
);
345 for (int i
= 0; i
< CursorCount
; i
++) {
346 video
->FreeSprite( Cursors
[i
] );
351 FreeResourceVector( Font
, fonts
);
352 FreeResourceVector( Window
, windows
);
355 for (i
= 0; i
< musiclist
.size(); i
++) {
356 free((void *)musiclist
[i
]);
359 DamageInfoMap
.clear();
378 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
379 video
->FreeSprite(FogSprites
[i
]);
383 video
->FreeSprite(WindowFrames
[i
]);
386 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
388 video
->FreeSprite(GroundCircles
[size
][i
]);
394 //freesprite checks for null pointer
395 video
->FreeSprite(TooltipBack
[i
]);
397 delete[] TooltipBack
;
399 if (InfoTextPalette
) {
400 gamedata
->FreePalette(InfoTextPalette
);
403 video
->SetDragCursor(NULL
);
411 RtRows
->RemoveAll(ReleaseItemList
);
415 ItemExclTable
->RemoveAll(NULL
);
416 delete ItemExclTable
;
419 ItemDialTable
->RemoveAll(NULL
);
420 delete ItemDialTable
;
422 if (ItemDial2Table
) {
423 ItemDial2Table
->RemoveAll(NULL
);
424 delete ItemDial2Table
;
426 if (ItemTooltipTable
) {
427 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
428 delete ItemTooltipTable
;
431 Map::ReleaseMemory();
432 Actor::ReleaseMemory();
434 gamedata
->ClearCaches();
438 // Removing all stuff from Cache, except bifs
439 if (!KeepCache
) DelTree((const char *) CachePath
, true);
442 void Interface::SetWindowFrame(int i
, Sprite2D
*Picture
)
444 video
->FreeSprite(WindowFrames
[i
]);
445 WindowFrames
[i
]=Picture
;
448 GameControl
* Interface::StartGameControl()
450 //making sure that our window is the first one
454 DelAllWindows();//deleting ALL windows
455 gamedata
->DelTable(0xffffu
); //dropping ALL tables
456 Window
* gamewin
= new Window( 0xffff, 0, 0, (ieWord
) Width
, (ieWord
) Height
);
457 gamewin
->WindowPack
[0]=0;
458 GameControl
* gc
= new GameControl();
461 gc
->Width
= (ieWord
) Width
;
462 gc
->Height
= (ieWord
) Height
;
464 gc
->ControlID
= 0x00000000;
465 gc
->ControlType
= IE_GUI_GAMECONTROL
;
466 gamewin
->AddControl( gc
);
467 AddWindow( gamewin
);
468 SetVisible( 0, WINDOW_VISIBLE
);
469 //setting the focus to the game control
470 evntmgr
->SetFocused(gamewin
, gc
);
471 if (guiscript
->LoadScript( "MessageWindow" )) {
472 guiscript
->RunFunction( "MessageWindow", "OnLoad" );
479 /* handle main loop events that might destroy or create windows
480 thus cannot be called from DrawWindows directly
481 these events are pending until conditions are right
483 void Interface::HandleEvents()
485 GameControl
*gc
= GetGameControl();
486 if (gc
&& (!gc
->Owner
|| !gc
->Owner
->Visible
)) {
491 if (EventFlag
&EF_SELECTION
) {
492 EventFlag
&=~EF_SELECTION
;
493 guiscript
->RunFunction( "GUICommonWindows", "SelectionChanged", false);
496 if (EventFlag
&EF_UPDATEANIM
) {
497 EventFlag
&=~EF_UPDATEANIM
;
498 guiscript
->RunFunction( "GUICommonWindows", "UpdateAnimation", false);
501 if (EventFlag
&EF_PORTRAIT
) {
502 ieDword tmp
= (ieDword
) ~0;
503 vars
->Lookup( "PortraitWindow", tmp
);
504 if (tmp
!= (ieDword
) ~0) {
505 EventFlag
&=~EF_PORTRAIT
;
506 guiscript
->RunFunction( "GUICommonWindows", "UpdatePortraitWindow" );
510 if (EventFlag
&EF_ACTION
) {
511 ieDword tmp
= (ieDword
) ~0;
512 vars
->Lookup( "ActionsWindow", tmp
);
513 if (tmp
!= (ieDword
) ~0) {
514 EventFlag
&=~EF_ACTION
;
515 guiscript
->RunFunction( "GUICommonWindows", "UpdateActionsWindow" );
519 if ((EventFlag
&EF_CONTROL
) && gc
) {
520 EventFlag
&=~EF_CONTROL
;
521 guiscript
->RunFunction( "MessageWindow", "UpdateControlStatus" );
522 //this is the only value we can use here
523 if (game
->ControlStatus
& CS_HIDEGUI
)
529 if ((EventFlag
&EF_SHOWMAP
) && gc
) {
530 ieDword tmp
= (ieDword
) ~0;
531 vars
->Lookup( "OtherWindow", tmp
);
532 if (tmp
== (ieDword
) ~0) {
533 EventFlag
&= ~EF_SHOWMAP
;
534 guiscript
->RunFunction( "GUIMA", "ShowMap" );
539 if (EventFlag
&EF_SEQUENCER
) {
540 EventFlag
&=~EF_SEQUENCER
;
541 guiscript
->RunFunction( "GUIMG", "OpenSequencerWindow" );
545 if (EventFlag
&EF_IDENTIFY
) {
546 EventFlag
&=~EF_IDENTIFY
;
547 // FIXME: Implement this.
548 guiscript
->RunFunction( "GUICommonWindows", "OpenIdentifyWindow" );
551 if (EventFlag
&EF_OPENSTORE
) {
552 EventFlag
&=~EF_OPENSTORE
;
553 guiscript
->RunFunction( "GUISTORE", "OpenStoreWindow" );
557 if (EventFlag
&EF_MASTERSCRIPT
) {
558 EventFlag
&=~EF_MASTERSCRIPT
;
559 guiscript
->RunFunction( "MessageWindow", "UpdateMasterScript" );
563 if (EventFlag
&EF_CLOSECONTAINER
) {
564 EventFlag
&=~EF_CLOSECONTAINER
;
565 guiscript
->RunFunction( "GUIWORLD", "CloseContainerWindow" );
570 /* handle main loop events that might destroy or create windows
571 thus cannot be called from DrawWindows directly
573 void Interface::HandleFlags()
575 EventFlag
= EF_CONTROL
; //clear events because the context changed
577 if (QuitFlag
&(QF_QUITGAME
|QF_EXITGAME
) ) {
578 // when reaching this, quitflag should be 1 or 2
579 // if Exitgame was set, we'll set Start.py too
580 QuitGame (QuitFlag
&QF_EXITGAME
);
581 QuitFlag
&= ~(QF_QUITGAME
|QF_EXITGAME
);
584 if (QuitFlag
&QF_LOADGAME
) {
585 QuitFlag
&= ~QF_LOADGAME
;
586 LoadGame(LoadGameIndex
.get(), VersionOverride
);
587 LoadGameIndex
.release();
590 if (QuitFlag
&QF_ENTERGAME
) {
591 QuitFlag
&= ~QF_ENTERGAME
;
595 //rearrange party slots
596 game
->ConsolidateParty();
597 GameControl
* gc
= StartGameControl();
598 //switch map to protagonist
599 Actor
* actor
= GetFirstSelectedPC(true);
601 gc
->ChangeMap(actor
, true);
604 printMessage("Core", "No game to enter...\n", LIGHT_RED
);
605 QuitFlag
= QF_QUITGAME
;
609 if (QuitFlag
&QF_CHANGESCRIPT
) {
610 QuitFlag
&= ~QF_CHANGESCRIPT
;
611 guiscript
->LoadScript( NextScript
);
612 guiscript
->RunFunction( NextScript
, "OnLoad" );
616 bool GenerateAbilityTables()
620 //range is: 0 - maximumability
621 int tablesize
= MaximumAbility
+1;
622 strmod
= (ieWordSigned
*) malloc (tablesize
* 4 * sizeof(ieWordSigned
) );
625 strmodex
= (ieWordSigned
*) malloc (101 * 4 * sizeof(ieWordSigned
) );
628 intmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
631 dexmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
634 conmod
= (ieWordSigned
*) malloc (tablesize
* 5 * sizeof(ieWordSigned
) );
637 chrmod
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
640 lorebon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
643 wisbon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
649 bool Interface::ReadAbilityTable(const ieResRef tablename
, ieWordSigned
*mem
, int columns
, int rows
)
651 AutoTable
tab(tablename
);
655 //this is a hack for rows not starting at 0 in some cases
657 const char * tmp
= tab
->GetRowName(0);
658 if (tmp
&& (tmp
[0]!='0')) {
660 for (int i
=0;i
<fix
;i
++) {
661 for (int j
=0;j
<columns
;j
++) {
662 mem
[rows
*j
+i
]=(ieWordSigned
) strtol(tab
->QueryField(0,j
),NULL
,0 );
666 for (int j
=0;j
<columns
;j
++) {
667 for( int i
=0;i
<rows
-fix
;i
++) {
668 mem
[rows
*j
+i
+fix
] = (ieWordSigned
) strtol(tab
->QueryField(i
,j
),NULL
,0 );
674 bool Interface::ReadAbilityTables()
676 bool ret
= GenerateAbilityTables();
679 ret
= ReadAbilityTable("strmod", strmod
, 4, MaximumAbility
+ 1);
682 ret
= ReadAbilityTable("strmodex", strmodex
, 4, 101);
683 //3rd ed doesn't have strmodex, but has a maximum of 40
684 if (!ret
&& (MaximumAbility
<=25) )
686 ret
= ReadAbilityTable("intmod", intmod
, 3, MaximumAbility
+ 1);
689 ret
= ReadAbilityTable("hpconbon", conmod
, 5, MaximumAbility
+ 1);
692 if (!HasFeature(GF_3ED_RULES
)) {
693 //no lorebon in iwd2???
694 ret
= ReadAbilityTable("lorebon", lorebon
, 1, MaximumAbility
+ 1);
697 //no dexmod in iwd2???
698 ret
= ReadAbilityTable("dexmod", dexmod
, 3, MaximumAbility
+ 1);
702 //this table is a single row (not a single column)
703 ret
= ReadAbilityTable("chrmodst", chrmod
, MaximumAbility
+ 1, 1);
706 if (HasFeature(GF_WISDOM_BONUS
)) {
707 ret
= ReadAbilityTable("wisxpbon", wisbon
, 1, MaximumAbility
+ 1);
714 bool Interface::ReadGameTimeTable()
716 AutoTable
table("gametime");
721 Time
.round_sec
= atoi(table
->QueryField("ROUND_SECONDS", "DURATION"));
722 Time
.turn_sec
= atoi(table
->QueryField("TURN_SECONDS", "DURATION"));
723 Time
.round_size
= Time
.round_sec
* AI_UPDATE_TIME
;
724 Time
.rounds_per_turn
= Time
.turn_sec
/ Time
.round_sec
;
729 bool Interface::ReadAuxItemTables()
736 ItemExclTable
->RemoveAll(NULL
);
738 ItemExclTable
= new Variables();
739 ItemExclTable
->SetType(GEM_VARIABLES_INT
);
741 table
= gamedata
->LoadTable( "itemexcl" );
745 //don't report error when the file doesn't exist
746 if (aa
.load("itemexcl")) {
747 idx
= aa
->GetRowCount();
751 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
752 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
753 ItemExclTable
->SetAt(key
, value
);
757 ItemDialTable
->RemoveAll(NULL
);
759 ItemDialTable
= new Variables();
760 ItemDialTable
->SetType(GEM_VARIABLES_INT
);
762 if (ItemDial2Table
) {
763 ItemDial2Table
->RemoveAll(NULL
);
765 ItemDial2Table
= new Variables();
766 ItemDial2Table
->SetType(GEM_VARIABLES_STRING
);
769 //don't report error when the file doesn't exist
770 if (aa
.load("itemdial")) {
771 idx
= aa
->GetRowCount();
773 ieResRef key
, dlgres
;
775 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
776 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
777 ItemDialTable
->SetAt(key
, value
);
778 strnlwrcpy(dlgres
,aa
->QueryField(idx
,1),8);
779 ItemDial2Table
->SetAtCopy(key
, dlgres
);
783 if (ItemTooltipTable
) {
784 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
786 ItemTooltipTable
= new Variables();
787 ItemTooltipTable
->SetType(GEM_VARIABLES_POINTER
);
790 //don't report error when the file doesn't exist
791 if (aa
.load("tooltip")) {
792 idx
= aa
->GetRowCount();
795 int *tmppoi
= (int *) malloc(sizeof(int)*3);
797 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
798 for (int i
=0;i
<3;i
++) {
799 tmppoi
[i
] = atoi(aa
->QueryField(idx
,i
));
801 ItemTooltipTable
->SetAt(key
, (void*)tmppoi
);
808 const char *Interface::GetDeathVarFormat()
810 return DeathVarFormat
;
813 int Interface::GetItemExcl(const ieResRef itemname
) const
817 if (ItemExclTable
&& ItemExclTable
->Lookup(itemname
, value
)) {
823 int Interface::GetItemTooltip(const ieResRef itemname
, int header
, int identified
)
827 if (ItemTooltipTable
) {
829 ItemTooltipTable
->Lookup(itemname
, lookup
);
830 value
= (int*)lookup
;
832 if (value
&& (value
[header
]>=0)) {
833 return value
[header
];
835 Item
*item
= gamedata
->GetItem(itemname
);
839 int ret
= identified
?item
->ItemNameIdentified
:item
->ItemName
;
840 gamedata
->FreeItem(item
, itemname
, 0);
844 int Interface::GetItemDialStr(const ieResRef itemname
) const
848 if (ItemDialTable
&& ItemDialTable
->Lookup(itemname
, value
)) {
854 //second value is the item dialog resource returned by this method
855 int Interface::GetItemDialRes(const ieResRef itemname
, ieResRef retval
) const
857 if (ItemDial2Table
&& ItemDial2Table
->Lookup(itemname
, retval
, sizeof(ieResRef
))) {
863 bool Interface::ReadAreaAliasTable(const ieResRef tablename
)
865 if (AreaAliasTable
) {
866 AreaAliasTable
->RemoveAll(NULL
);
868 AreaAliasTable
= new Variables();
869 AreaAliasTable
->SetType(GEM_VARIABLES_INT
);
872 AutoTable
aa(tablename
);
874 //don't report error when the file doesn't exist
878 int idx
= aa
->GetRowCount();
882 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
883 ieDword value
= atoi(aa
->QueryField(idx
,0));
884 AreaAliasTable
->SetAt(key
, value
);
890 int Interface::GetAreaAlias(const ieResRef areaname
) const
894 if (AreaAliasTable
&& AreaAliasTable
->Lookup(areaname
, value
)) {
900 bool Interface::ReadMusicTable(const ieResRef tablename
, int col
) {
901 AutoTable
tm(tablename
);
905 for (unsigned int i
= 0; i
< tm
->GetRowCount(); i
++) {
906 musiclist
.push_back(strdup(tm
->QueryField(i
, col
)));
912 bool Interface::ReadDamageTypeTable() {
913 AutoTable
tm("dmgtypes");
918 for (ieDword i
= 0; i
< tm
->GetRowCount(); i
++) {
919 di
.strref
= displaymsg
->GetStringReference(atoi(tm
->QueryField(i
, 0)));
920 di
.resist_stat
= TranslateStat(tm
->QueryField(i
, 1));
921 di
.value
= strtol(tm
->QueryField(i
, 2), (char **) NULL
, 16);
922 di
.iwd_mod_type
= atoi(tm
->QueryField(i
, 3));
923 DamageInfoMap
.insert(std::make_pair
<ieDword
, DamageInfoStruct
> ((ieDword
)di
.value
, di
));
929 bool Interface::ReadReputationModTable() {
930 AutoTable
tm("reputati");
934 reputationmod
= (int **) calloc(21, sizeof(int *));
935 int cols
= tm
->GetColumnCount();
936 for (unsigned int i
=0; i
<20; i
++) {
937 reputationmod
[i
] = (int *) calloc(cols
, sizeof(int));
938 for (int j
=0; j
<cols
; j
++) {
939 reputationmod
[i
][j
] = atoi(tm
->QueryField(i
, j
));
946 bool Interface::ReadModalStates()
948 AutoTable
table("modal");
952 ModalStatesStruct ms
;
953 for (unsigned short i
= 0; i
< table
->GetRowCount(); i
++) {
954 strncpy(ms
.spell
, table
->QueryField(i
, 0), 8);
955 strncpy(ms
.action
, table
->QueryField(i
, 1), 16);
956 ms
.entering_str
= atoi(table
->QueryField(i
, 2));
957 ms
.leaving_str
= atoi(table
->QueryField(i
, 3));
958 ms
.failed_str
= atoi(table
->QueryField(i
, 4));
959 ms
.aoe_spell
= atoi(table
->QueryField(i
, 5));
960 ModalStates
.push_back(ms
);
966 //Not a constant anymore, we let the caller set the entry to zero
967 char *Interface::GetMusicPlaylist(int SongType
) const {
968 if (SongType
< 0 || (unsigned int)SongType
>= musiclist
.size())
971 return musiclist
[SongType
];
974 static const Color white
= {0xff,0xff,0xff,0xff};
975 static const Color black
= {0x00,0x00,0x00,0xff};
976 static const Region
bg( 0, 0, 100, 30 );
978 /** this is the main loop */
979 void Interface::Main()
981 ieDword FullScreen
= 0;
982 ieDword brightness
= 10;
983 ieDword contrast
= 5;
986 vars
->Lookup("FullScreen", FullScreen
);
987 video
->CreateDisplay( Width
, Height
, Bpp
, FullScreen
);
988 video
->SetDisplayTitle( GameName
, GameType
);
989 vars
->Lookup("Brightness Correction", brightness
);
990 vars
->Lookup("Gamma Correction", contrast
);
991 vars
->Lookup("Mouse Scroll Speed", speed
);
992 video
->SetGamma(brightness
, contrast
);
993 SetMouseScrollSpeed((int) speed
);
994 if (vars
->Lookup("Tooltips", TooltipDelay
)) {
995 // the games store the slider position*10, not the actual delay
996 TooltipDelay
*= TOOLTIP_DELAY_FACTOR
/10;
999 Font
* fps
= GetFont( ( unsigned int ) 0 );
1000 char fpsstring
[40]={"???.??? fps"};
1001 unsigned long frame
= 0, time
, timebase
;
1003 double frames
= 0.0;
1004 Palette
* palette
= CreatePalette( white
, black
);
1006 //don't change script when quitting is pending
1014 HandleGUIBehaviour();
1021 if (time
- timebase
> 1000) {
1022 frames
= ( frame
* 1000.0 / ( time
- timebase
) );
1025 sprintf( fpsstring
, "%.3f fps", frames
);
1027 video
->DrawRect( bg
, black
);
1029 ( unsigned char * ) fpsstring
, palette
,
1030 IE_FONT_ALIGN_LEFT
| IE_FONT_ALIGN_MIDDLE
, true );
1032 } while (video
->SwapBuffers() == GEM_OK
);
1033 gamedata
->FreePalette( palette
);
1036 int Interface::ReadResRefTable(const ieResRef tablename
, ieResRef
*&data
)
1044 AutoTable
tm(tablename
);
1046 printStatus( "ERROR", LIGHT_RED
);
1047 printf( "Cannot find %s.2da.\n",tablename
);
1050 count
= tm
->GetRowCount();
1051 data
= (ieResRef
*) calloc( count
, sizeof(ieResRef
) );
1052 for (int i
= 0; i
< count
; i
++) {
1053 strnlwrcpy( data
[i
], tm
->QueryField( i
, 0 ), 8 );
1054 //* marks an empty resource
1055 if (data
[i
][0]=='*') {
1062 int Interface::LoadSprites()
1066 if (!IsAvailable( IE_2DA_CLASS_ID
)) {
1067 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1072 AnimationFactory
* anim
;
1073 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("cursors", IE_BAM_CLASS_ID
);
1076 CursorCount
= anim
->GetCycleCount();
1077 Cursors
= new Sprite2D
* [CursorCount
];
1078 for (int i
= 0; i
< CursorCount
; i
++) {
1079 Cursors
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1082 printMessage( "Core", "Loading Cursors...", WHITE
);
1084 // this is the last existing cursor type
1085 if (CursorCount
<IE_CURSOR_WAY
) {
1086 printStatus( "ERROR", LIGHT_RED
);
1089 video
->SetCursor( Cursors
[0], Cursors
[1] );
1090 printStatus( "OK", LIGHT_GREEN
);
1092 // Load fog-of-war bitmaps
1093 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("fogowar", IE_BAM_CLASS_ID
);
1094 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE
);
1095 if (!anim
|| anim
->GetCycleSize( 0 ) != 8) {
1096 // unknown type of fog anim
1097 printStatus( "ERROR", LIGHT_RED
);
1101 FogSprites
[0] = NULL
;
1102 FogSprites
[1] = anim
->GetFrame( 0, 0 );
1103 FogSprites
[2] = anim
->GetFrame( 1, 0 );
1104 FogSprites
[3] = anim
->GetFrame( 2, 0 );
1106 FogSprites
[4] = video
->MirrorSpriteVertical( FogSprites
[1], false );
1108 FogSprites
[5] = NULL
;
1110 FogSprites
[6] = video
->MirrorSpriteVertical( FogSprites
[3], false );
1112 FogSprites
[7] = NULL
;
1114 FogSprites
[8] = video
->MirrorSpriteHorizontal( FogSprites
[2], false );
1116 FogSprites
[9] = video
->MirrorSpriteHorizontal( FogSprites
[3], false );
1118 FogSprites
[10] = NULL
;
1119 FogSprites
[11] = NULL
;
1121 FogSprites
[12] = video
->MirrorSpriteHorizontal( FogSprites
[6], false );
1123 FogSprites
[16] = anim
->GetFrame( 3, 0 );
1124 FogSprites
[17] = anim
->GetFrame( 4, 0 );
1125 FogSprites
[18] = anim
->GetFrame( 5, 0 );
1126 FogSprites
[19] = anim
->GetFrame( 6, 0 );
1128 FogSprites
[20] = video
->MirrorSpriteVertical( FogSprites
[17], false );
1130 FogSprites
[21] = NULL
;
1132 FogSprites
[23] = NULL
;
1134 FogSprites
[24] = video
->MirrorSpriteHorizontal( FogSprites
[18], false );
1136 FogSprites
[25] = anim
->GetFrame( 7, 0 );
1139 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[25], false );
1140 FogSprites
[22] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1141 video
->FreeSprite( tmpsprite
);
1144 FogSprites
[26] = NULL
;
1145 FogSprites
[27] = NULL
;
1148 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[19], false );
1149 FogSprites
[28] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1150 video
->FreeSprite( tmpsprite
);
1154 vars
->Lookup("3D Acceleration", i
);
1156 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
1157 if (FogSprites
[i
]) {
1158 Sprite2D
* alphasprite
= video
->CreateAlpha( FogSprites
[i
] );
1159 video
->FreeSprite ( FogSprites
[i
] );
1160 FogSprites
[i
] = alphasprite
;
1165 printStatus( "OK", LIGHT_GREEN
);
1167 // Load ground circle bitmaps (PST only)
1168 //block required due to msvc6.0 incompatibility
1169 for (size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
1170 if (GroundCircleBam
[size
][0]) {
1171 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(GroundCircleBam
[size
], IE_BAM_CLASS_ID
);
1172 if (!anim
|| anim
->GetCycleCount() != 6) {
1173 // unknown type of circle anim
1174 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1175 printStatus( "ERROR", LIGHT_RED
);
1179 for (int i
= 0; i
< 6; i
++) {
1180 Sprite2D
* sprite
= anim
->GetFrame( 0, (ieByte
) i
);
1181 if (GroundCircleScale
[size
]) {
1182 GroundCircles
[size
][i
] = video
->SpriteScaleDown( sprite
, GroundCircleScale
[size
] );
1183 video
->FreeSprite( sprite
);
1185 GroundCircles
[size
][i
] = sprite
;
1191 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1192 printStatus( "OK", LIGHT_GREEN
);
1194 printMessage( "Core", "Loading Fonts...\n", WHITE
);
1195 AutoTable
tab("fonts");
1197 printStatus( "ERROR", LIGHT_RED
);
1198 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1201 PluginHolder
<AnimationMgr
> bamint(IE_BAM_CLASS_ID
);
1203 printStatus( "ERROR", LIGHT_RED
);
1204 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1207 DataStream
* str
= NULL
;
1209 int count
= tab
->GetRowCount();
1210 for (int i
= 0; i
< count
; i
++) {
1211 const char* ResRef
= tab
->QueryField( i
, 0 );
1212 int needpalette
= atoi( tab
->QueryField( i
, 1 ) );
1213 int first_char
= atoi( tab
->QueryField( i
, 2 ) );
1214 str
= gamedata
->GetResource( ResRef
, IE_BAM_CLASS_ID
);
1215 if (!bamint
->Open( str
, true )) {
1218 Font
* fnt
= bamint
->GetFont();
1222 strnlwrcpy( fnt
->ResRef
, ResRef
, 8 );
1225 Color fore
= {0xff, 0xff, 0xff, 0};
1226 Color back
= {0x00, 0x00, 0x00, 0};
1227 if (!strnicmp( TooltipFont
, ResRef
, 8) ) {
1228 if (TooltipColor
.a
==0xff) {
1229 fore
= TooltipColor
;
1232 back
= TooltipColor
;
1235 Palette
* pal
= CreatePalette( fore
, back
);
1236 pal
->CreateShadedAlphaChannel();
1237 fnt
->SetPalette(pal
);
1238 gamedata
->FreePalette( pal
);
1240 fnt
->SetFirstChar( (ieByte
) first_char
);
1241 fonts
.push_back( fnt
);
1244 printMessage( "Core", "Fonts Loaded...", WHITE
);
1245 printStatus( "OK", LIGHT_GREEN
);
1247 if (TooltipBackResRef
[0]) {
1248 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(TooltipBackResRef
, IE_BAM_CLASS_ID
);
1249 printMessage( "Core", "Initializing Tooltips...", WHITE
);
1251 printStatus( "ERROR", LIGHT_RED
);
1254 TooltipBack
= new Sprite2D
* [3];
1255 for (int i
= 0; i
< 3; i
++) {
1256 TooltipBack
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1257 TooltipBack
[i
]->XPos
= 0;
1258 TooltipBack
[i
]->YPos
= 0;
1260 printStatus( "OK", LIGHT_GREEN
);
1266 int Interface::Init()
1268 plugin_flags
= new Variables();
1269 plugin_flags
->SetType( GEM_VARIABLES_INT
);
1271 printMessage( "Core", "Initializing the Event Manager...", WHITE
);
1272 evntmgr
= new EventMgr();
1274 printMessage( "Core", "Initializing Variables Dictionary...", WHITE
);
1275 vars
= new Variables();
1277 printStatus( "ERROR", LIGHT_RED
);
1281 vars
->SetType( GEM_VARIABLES_INT
);
1282 vars
->SetAt( "Volume Ambients", 100 );
1283 vars
->SetAt( "Volume Movie", 100 );
1284 vars
->SetAt( "Volume Music", 100 );
1285 vars
->SetAt( "Volume SFX", 100 );
1286 vars
->SetAt( "Volume Voices", 100 );
1287 printStatus( "OK", LIGHT_GREEN
);
1289 if (!LoadConfig()) {
1292 printMessage( "Core", "Starting Plugin Manager...\n", WHITE
);
1293 PluginMgr
*plugin
= PluginMgr::Get();
1294 plugin
->LoadPlugins(PluginsPath
);
1295 if (plugin
&& plugin
->GetPluginCount()) {
1296 printMessage( "Core", "Plugin Loading Complete...", WHITE
);
1297 printStatus( "OK", LIGHT_GREEN
);
1299 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW
);
1300 printStatus( "ERROR", LIGHT_RED
);
1303 plugin
->RunInitializers();
1307 srand( ( unsigned int ) t
);
1309 FileStreamPtrCount
= 0;
1310 CachedFileStreamPtrCount
= 0;
1312 printMessage( "Core", "GemRB Core Initialization...\n", WHITE
);
1313 printStatus( "OK", LIGHT_GREEN
);
1314 printMessage( "Core", "Initializing Video Driver...", WHITE
);
1315 video
= ( Video
* ) PluginMgr::Get()->GetDriver(&Video::ID
, VideoDriverName
.c_str());
1317 printStatus( "ERROR", LIGHT_RED
);
1318 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1321 if (video
->Init() == GEM_ERROR
) {
1322 printStatus( "ERROR", LIGHT_RED
);
1323 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1326 Color defcolor
={255,255,255,200};
1327 SetInfoTextColor(defcolor
);
1328 printStatus( "OK", LIGHT_GREEN
);
1331 printMessage( "Core", "Initializing Search Path...", WHITE
);
1332 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY
)) {
1333 printf( "no DirectoryImporter! " );
1334 printStatus( "ERROR", LIGHT_RED
);
1338 char path
[_MAX_PATH
];
1340 PathJoin( path
, CachePath
, NULL
);
1341 gamedata
->AddSource(path
, "Cache", PLUGIN_RESOURCE_DIRECTORY
);
1343 PathJoin( path
, GemRBOverridePath
, "override", GameType
, NULL
);
1344 gamedata
->AddSource(path
, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1347 for (i
= 0; i
< ModPath
.size(); ++i
)
1348 gamedata
->AddSource(ModPath
[i
].c_str(), "Mod paths", PLUGIN_RESOURCE_DIRECTORY
);
1350 PathJoin( path
, GemRBOverridePath
, "override", "shared", NULL
);
1351 gamedata
->AddSource(path
, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1353 PathJoin( path
, GamePath
, GameOverridePath
, NULL
);
1354 gamedata
->AddSource(path
, "Override", PLUGIN_RESOURCE_DIRECTORY
);
1356 PathJoin( path
, GamePath
, GameSoundsPath
, NULL
);
1357 gamedata
->AddSource(path
, "Sounds", PLUGIN_RESOURCE_DIRECTORY
);
1359 PathJoin( path
, GamePath
, GameScriptsPath
, NULL
);
1360 gamedata
->AddSource(path
, "Scripts", PLUGIN_RESOURCE_DIRECTORY
);
1362 PathJoin( path
, GamePath
, GamePortraitsPath
, NULL
);
1363 gamedata
->AddSource(path
, "Portraits", PLUGIN_RESOURCE_DIRECTORY
);
1365 PathJoin( path
, GamePath
, GameDataPath
, NULL
);
1366 gamedata
->AddSource(path
, "Data", PLUGIN_RESOURCE_DIRECTORY
);
1368 //IWD2 movies are on the CD but not in the BIF
1369 for (i
= 0; i
< MAX_CD
; i
++) {
1370 for (size_t j
=0;j
<CD
[i
].size();j
++) {
1371 char description
[] = {'C', 'D', '1'+i
, '/', 'd', 'a', 't', 'a', '\0'};
1372 PathJoin( path
, CD
[i
][j
].c_str(), GameDataPath
, NULL
);
1373 gamedata
->AddSource(path
, description
, PLUGIN_RESOURCE_DIRECTORY
);
1377 printStatus( "OK", LIGHT_GREEN
);
1381 printMessage( "Core", "Initializing KEY Importer...", WHITE
);
1382 char ChitinPath
[_MAX_PATH
];
1383 PathJoin( ChitinPath
, GamePath
, "chitin.key", NULL
);
1384 if (!gamedata
->AddSource(ChitinPath
, "chitin.key", PLUGIN_RESOURCE_KEY
)) {
1385 printStatus( "ERROR", LIGHT_RED
);
1388 printStatus( "OK", LIGHT_GREEN
);
1391 printMessage( "Core", "Reading Game Options...\n", WHITE
);
1392 if (!LoadGemRBINI())
1394 printf( "Cannot Load INI\nTermination in Progress...\n" );
1398 //loading baldur.ini
1400 char ini_path
[_MAX_PATH
];
1401 PathJoin( ini_path
, GamePath
, INIConfig
, NULL
);
1402 LoadINI( ini_path
);
1404 for (i
= 0; i
< 8; i
++) {
1405 if (INIConfig
[i
] == '.')
1407 GameNameResRef
[i
] = INIConfig
[i
];
1409 GameNameResRef
[i
] = 0;
1412 printMessage( "Core", "Creating Projectile Server...\n", WHITE
);
1413 projserv
= new ProjectileServer();
1414 if (!projserv
->GetHighestProjectileNumber()) {
1415 printStatus( "ERROR", LIGHT_RED
);
1416 printf( "No projectiles are available...\n" );
1419 printMessage( "Core", "Checking for Dialogue Manager...", WHITE
);
1420 if (!IsAvailable( IE_TLK_CLASS_ID
)) {
1421 printStatus( "ERROR", LIGHT_RED
);
1422 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1425 printStatus( "OK", LIGHT_GREEN
);
1426 strings
= PluginHolder
<StringMgr
>(IE_TLK_CLASS_ID
);
1427 printMessage( "Core", "Loading Dialog.tlk file...", WHITE
);
1428 char strpath
[_MAX_PATH
];
1429 PathJoin( strpath
, GamePath
, dialogtlk
, NULL
);
1430 FileStream
* fs
= new FileStream();
1431 if (!fs
->Open( strpath
, true )) {
1432 printStatus( "ERROR", LIGHT_RED
);
1433 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1437 printStatus( "OK", LIGHT_GREEN
);
1438 strings
->Open( fs
, true );
1441 printMessage( "Core", "Loading Palettes...\n", WHITE
);
1442 ResourceHolder
<ImageMgr
> pal16im(Palette16
);
1444 pal16
= pal16im
->GetImage();
1445 ResourceHolder
<ImageMgr
> pal32im(Palette32
);
1447 pal32
= pal32im
->GetImage();
1448 ResourceHolder
<ImageMgr
> pal256im(Palette256
);
1450 pal256
= pal256im
->GetImage();
1451 if (!pal16
|| !pal32
|| !pal256
) {
1452 printStatus( "ERROR", LIGHT_RED
);
1455 printMessage( "Core", "Palettes Loaded\n", WHITE
);
1458 if (!IsAvailable( IE_BAM_CLASS_ID
)) {
1459 printStatus( "ERROR", LIGHT_RED
);
1460 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1464 printMessage( "Core", "Initializing stock sounds...\n", WHITE
);
1465 DSCount
= ReadResRefTable ("defsound", DefSound
);
1467 printStatus( "ERROR", LIGHT_RED
);
1468 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1472 printStatus( "OK", LIGHT_GREEN
);
1473 printMessage( "Core", "Broadcasting Event Manager...", WHITE
);
1474 video
->SetEventMgr( evntmgr
);
1475 printStatus( "OK", LIGHT_GREEN
);
1476 printMessage( "Core", "Initializing Window Manager...", WHITE
);
1477 windowmgr
= PluginHolder
<WindowMgr
>(IE_CHU_CLASS_ID
);
1478 if (windowmgr
== NULL
) {
1479 printStatus( "ERROR", LIGHT_RED
);
1482 printStatus( "OK", LIGHT_GREEN
);
1483 printMessage( "Core", "Initializing GUI Script Engine...", WHITE
);
1484 guiscript
= PluginHolder
<ScriptEngine
>(IE_GUI_SCRIPT_CLASS_ID
);
1485 if (guiscript
== NULL
) {
1486 printStatus( "ERROR", LIGHT_RED
);
1489 if (!guiscript
->Init()) {
1490 printStatus( "ERROR", LIGHT_RED
);
1493 printStatus( "OK", LIGHT_GREEN
);
1494 strcpy( NextScript
, "Start" );
1496 int ret
= LoadSprites();
1497 if (ret
) return ret
;
1499 Sprite2D
*tmpsprite
= GetCursorSprite();
1500 printMessage( "Core", "Setting up the Console...", WHITE
);
1501 QuitFlag
= QF_CHANGESCRIPT
;
1502 console
= new Console();
1504 console
->YPos
= (ieWord
) (Height
- 25);
1505 console
->Width
= (ieWord
) Width
;
1506 console
->Height
= 25;
1507 console
->SetFont( fonts
[0] );
1509 printStatus( "ERROR", LIGHT_RED
);
1512 console
->SetCursor (tmpsprite
);
1513 printStatus( "OK", LIGHT_GREEN
);
1515 printMessage( "Core", "Starting up the Sound Driver...", WHITE
);
1516 AudioDriver
= ( Audio
* ) PluginMgr::Get()->GetDriver(&Audio::ID
, AudioDriverName
.c_str());
1517 if (AudioDriver
== NULL
) {
1518 printStatus( "ERROR", LIGHT_RED
);
1521 if (!AudioDriver
->Init()) {
1522 printStatus( "ERROR", LIGHT_RED
);
1525 printStatus( "OK", LIGHT_GREEN
);
1527 printMessage( "Core", "Allocating SaveGameIterator...", WHITE
);
1528 sgiterator
= new SaveGameIterator();
1529 if (sgiterator
== NULL
) {
1530 printStatus( "ERROR", LIGHT_RED
);
1533 printStatus( "OK", LIGHT_GREEN
);
1535 //no need of strdup, variables do copy the key!
1536 vars
->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos
);
1537 vars
->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements
);
1539 printMessage( "Core", "Initializing Token Dictionary...", WHITE
);
1540 tokens
= new Variables();
1542 printStatus( "ERROR", LIGHT_RED
);
1545 tokens
->SetType( GEM_VARIABLES_STRING
);
1546 printStatus( "OK", LIGHT_GREEN
);
1548 printMessage( "Core", "Initializing Music Manager...", WHITE
);
1549 music
= PluginHolder
<MusicMgr
>(IE_MUS_CLASS_ID
);
1551 printStatus( "ERROR", LIGHT_RED
);
1554 printStatus( "OK", LIGHT_GREEN
);
1556 printMessage("Core", "Loading music list...\n", WHITE
);
1557 if (HasFeature( GF_HAS_SONGLIST
)) {
1558 ret
= ReadMusicTable("songlist", 1);
1560 /*since bg1 and pst has no .2da for songlist,
1561 we must supply one in the gemrb/override folder.
1562 It should be: music.2da, first column is a .mus filename*/
1563 ret
= ReadMusicTable("music", 0);
1566 printStatus( "OK", LIGHT_GREEN
);
1568 printStatus( "NOT FOUND", YELLOW
);
1571 if (HasFeature( GF_RESDATA_INI
)) {
1572 printMessage( "Core", "Loading resource data File...", WHITE
);
1573 INIresdata
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1574 DataStream
* ds
= gamedata
->GetResource("resdata", IE_INI_CLASS_ID
);
1575 if (!INIresdata
->Open( ds
, true )) {
1576 printStatus( "ERROR", LIGHT_RED
);
1578 printStatus( "OK", LIGHT_GREEN
);
1582 if (HasFeature( GF_HAS_PARTY_INI
)) {
1583 printMessage( "Core", "Loading precreated teams setup...\n",
1585 INIparty
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1586 FileStream
* fs
= new FileStream();
1587 char tINIparty
[_MAX_PATH
];
1588 PathJoin( tINIparty
, GamePath
, "Party.ini", NULL
);
1589 fs
->Open( tINIparty
, true );
1590 if (!INIparty
->Open( fs
, true )) {
1591 printStatus( "ERROR", LIGHT_RED
);
1593 printStatus( "OK", LIGHT_GREEN
);
1597 if (HasFeature(GF_IWD2_DEATHVARFORMAT
)) {
1598 memcpy(DeathVarFormat
, IWD2DeathVarFormat
, sizeof(ieVariable
));
1601 if (HasFeature( GF_HAS_BEASTS_INI
)) {
1602 printMessage( "Core", "Loading beasts definition File...\n",
1604 INIbeasts
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1605 FileStream
* fs
= new FileStream();
1606 char tINIbeasts
[_MAX_PATH
];
1607 PathJoin( tINIbeasts
, GamePath
, "beast.ini", NULL
);
1608 // FIXME: crashes if file does not open
1609 fs
->Open( tINIbeasts
, true );
1610 if (!INIbeasts
->Open( fs
, true )) {
1611 printStatus( "ERROR", LIGHT_RED
);
1613 printStatus( "OK", LIGHT_GREEN
);
1616 printMessage( "Core", "Loading quests definition File...\n",
1618 INIquests
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1619 FileStream
* fs2
= new FileStream();
1620 char tINIquests
[_MAX_PATH
];
1621 PathJoin( tINIquests
, GamePath
, "quests.ini", NULL
);
1622 // FIXME: crashes if file does not open
1623 fs2
->Open( tINIquests
, true );
1624 if (!INIquests
->Open( fs2
, true )) {
1625 printStatus( "ERROR", LIGHT_RED
);
1627 printStatus( "OK", LIGHT_GREEN
);
1633 timer
= new GlobalTimer();
1634 printMessage( "Core", "Bringing up the Global Timer...", WHITE
);
1636 printStatus( "ERROR", LIGHT_RED
);
1639 printStatus( "OK", LIGHT_GREEN
);
1641 ret
= Init_EffectQueue();
1642 printMessage( "Core", "Initializing effects...", WHITE
);
1644 printStatus( "ERROR", LIGHT_RED
);
1647 printStatus( "OK", LIGHT_GREEN
);
1649 ret
= InitItemTypes();
1650 printMessage( "Core", "Initializing Inventory Management...", WHITE
);
1652 printStatus( "ERROR", LIGHT_RED
);
1655 printStatus( "OK", LIGHT_GREEN
);
1657 displaymsg
= new DisplayMessage();
1658 printMessage( "Core", "Initializing string constants...", WHITE
);
1660 printStatus( "ERROR", LIGHT_RED
);
1663 printStatus( "OK", LIGHT_GREEN
);
1665 ret
= ReadRandomItems();
1666 printMessage( "Core", "Initializing random treasure...", WHITE
);
1668 printStatus( "OK", LIGHT_GREEN
);
1671 printStatus( "ERROR", LIGHT_RED
);
1674 ret
= ReadAbilityTables();
1675 printMessage( "Core", "Initializing ability tables...", WHITE
);
1677 printStatus( "ERROR", LIGHT_RED
);
1680 printStatus( "OK", LIGHT_GREEN
);
1682 ret
= ReadReputationModTable();
1683 printMessage( "Core", "Reading reputation mod table...", WHITE
);
1685 printStatus( "OK", LIGHT_GREEN
);
1687 printStatus( "NOT FOUND", LIGHT_RED
);
1690 if ( gamedata
->Exists("WMAPLAY", IE_2DA_CLASS_ID
) ) {
1691 ret
= ReadAreaAliasTable( "WMAPLAY" );
1692 printMessage( "Core", "Initializing area aliases...", WHITE
);
1694 printStatus( "OK", LIGHT_GREEN
);
1697 printStatus( "NOT FOUND", YELLOW
);
1701 ret
= ReadGameTimeTable();
1702 printMessage( "Core", "Reading game time table...", WHITE
);
1704 printStatus( "ERROR", LIGHT_RED
);
1707 printStatus( "OK", LIGHT_GREEN
);
1709 ret
= ReadAuxItemTables();
1710 printMessage( "Core", "Reading item tables...", WHITE
);
1712 printStatus( "ERROR", LIGHT_RED
);
1715 printStatus( "OK", LIGHT_GREEN
);
1717 ret
= ReadDamageTypeTable();
1718 printMessage( "Core", "Reading damage type table...", WHITE
);
1720 printStatus( "ERROR", LIGHT_RED
);
1722 printStatus( "OK", LIGHT_GREEN
);
1725 ret
= ReadModalStates();
1726 printMessage( "Core", "Reading modal states table...", WHITE
);
1728 printStatus( "ERROR", LIGHT_RED
);
1731 printStatus( "OK", LIGHT_GREEN
);
1734 printMessage( "Core", "Reading game script tables...", WHITE
);
1735 InitializeIEScript();
1736 printStatus( "OK", LIGHT_GREEN
);
1738 printMessage( "Core", "Core Initialization Complete!\n", WHITE
);
1743 bool Interface::IsAvailable(SClass_ID filetype
) const
1745 return PluginMgr::Get()->IsAvailable( filetype
);
1748 WorldMap
*Interface::GetWorldMap(const char *map
)
1750 int index
= worldmap
->FindAndSetCurrentMap(map
?map
:game
->CurrentArea
);
1751 return worldmap
->GetWorldMap(index
);
1754 ProjectileServer
* Interface::GetProjectileServer() const
1759 Video
* Interface::GetVideoDriver() const
1764 Audio
* Interface::GetAudioDrv(void) const {
1765 return AudioDriver
.get();
1768 const char* Interface::TypeExt(SClass_ID type
) const
1771 case IE_2DA_CLASS_ID
:
1774 case IE_ACM_CLASS_ID
:
1777 case IE_ARE_CLASS_ID
:
1780 case IE_BAM_CLASS_ID
:
1783 case IE_BCS_CLASS_ID
:
1786 case IE_BS_CLASS_ID
:
1789 case IE_BIF_CLASS_ID
:
1792 case IE_BIO_CLASS_ID
:
1793 if (HasFeature(GF_BIOGRAPHY_RES
)) {
1798 case IE_BMP_CLASS_ID
:
1801 case IE_PNG_CLASS_ID
:
1804 case IE_CHR_CLASS_ID
:
1807 case IE_CHU_CLASS_ID
:
1810 case IE_CRE_CLASS_ID
:
1813 case IE_DLG_CLASS_ID
:
1816 case IE_EFF_CLASS_ID
:
1819 case IE_GAM_CLASS_ID
:
1822 case IE_IDS_CLASS_ID
:
1825 case IE_INI_CLASS_ID
:
1828 case IE_ITM_CLASS_ID
:
1831 case IE_MOS_CLASS_ID
:
1834 case IE_MUS_CLASS_ID
:
1837 case IE_MVE_CLASS_ID
:
1840 case IE_OGG_CLASS_ID
:
1843 case IE_PLT_CLASS_ID
:
1846 case IE_PRO_CLASS_ID
:
1849 case IE_SAV_CLASS_ID
:
1852 case IE_SPL_CLASS_ID
:
1855 case IE_SRC_CLASS_ID
:
1858 case IE_STO_CLASS_ID
:
1861 case IE_TIS_CLASS_ID
:
1864 case IE_TLK_CLASS_ID
:
1867 case IE_TOH_CLASS_ID
:
1870 case IE_TOT_CLASS_ID
:
1873 case IE_VAR_CLASS_ID
:
1876 case IE_VVC_CLASS_ID
:
1879 case IE_WAV_CLASS_ID
:
1882 case IE_WED_CLASS_ID
:
1885 case IE_WFX_CLASS_ID
:
1888 case IE_WMP_CLASS_ID
:
1894 void Interface::FreeString(char *&str
) const
1897 strings
->FreeString(str
);
1902 ieStrRef
Interface::UpdateString(ieStrRef strref
, const char *text
) const
1904 return strings
->UpdateString( strref
, text
);
1907 char* Interface::GetString(ieStrRef strref
, ieDword options
) const
1911 if (!(options
& IE_STR_STRREFOFF
)) {
1912 vars
->Lookup( "Strref On", flags
);
1914 return strings
->GetString( strref
, flags
| options
);
1917 void Interface::SetFeature(int flag
, int position
)
1922 GameFeatures2
|= 1 << position
;
1924 GameFeatures2
&= ~( 1 << position
);
1929 GameFeatures
|= 1 << position
;
1931 GameFeatures
&= ~( 1 << position
);
1935 ieDword
Interface::HasFeature(int position
) const
1938 return GameFeatures2
& ( 1 << (position
-32) );
1940 return GameFeatures
& ( 1 << position
);
1943 /** Search directories and load a config file */
1944 bool Interface::LoadConfig(void)
1947 char path
[_MAX_PATH
];
1948 char name
[_MAX_PATH
];
1950 // Find directory where user stores GemRB configurations (~/.gemrb).
1951 // FIXME: Create it if it does not exist
1952 // Use current dir if $HOME is not defined (or bomb out??)
1954 char* s
= getenv( "HOME" );
1956 strcpy( UserDir
, s
);
1957 strcat( UserDir
, "/."PACKAGE
"/" );
1959 strcpy( UserDir
, "./" );
1962 // Find basename of this program. It does the same as basename (3),
1963 // but that's probably missing on some archs
1964 s
= strrchr( argv
[0], PathDelimiter
);
1972 //if (!name[0]) // FIXME: could this happen?
1973 // strcpy (name, PACKAGE); // ugly hack
1975 // If we were called as $0 -c <filename>, load config from filename
1976 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
1977 if (LoadConfig( argv
[2] )) {
1980 // Explicitly specified cfg file HAS to be present
1985 // FIXME: temporary hack, to be deleted??
1986 if (LoadConfig( "GemRB.cfg" )) {
1990 PathJoin( path
, UserDir
, name
, NULL
);
1991 strcat( path
, ".cfg" );
1993 if (LoadConfig( path
)) {
1998 PathJoin( path
, SYSCONFDIR
, name
, NULL
);
1999 strcat( path
, ".cfg" );
2001 if (LoadConfig( path
)) {
2006 // Don't try with default binary name if we have tried it already
2007 if (!strcmp( name
, PACKAGE
)) {
2011 PathJoin( path
, UserDir
, PACKAGE
, NULL
);
2012 strcat( path
, ".cfg" );
2014 if (LoadConfig( path
)) {
2019 PathJoin( path
, SYSCONFDIR
, PACKAGE
, NULL
);
2020 strcat( path
, ".cfg" );
2022 if (LoadConfig( path
)) {
2029 // If we were called as $0 -c <filename>, load config from filename
2030 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
2031 return LoadConfig( argv
[2] );
2032 // Explicitly specified cfg file HAS to be present
2034 strcpy( UserDir
, ".\\" );
2035 return LoadConfig( "GemRB.cfg" );
2039 bool Interface::LoadConfig(const char* filename
)
2044 printMessage("Config","Trying to open ", WHITE
);
2045 textcolor(LIGHT_WHITE
);
2046 printf("%s ", filename
);
2047 config
= fopen( filename
, "rb" );
2048 if (config
== NULL
) {
2049 printStatus("NOT FOUND", LIGHT_RED
);
2052 char name
[65], value
[_MAX_PATH
+ 3];
2054 //once GemRB own format is working well, this might be set to 0
2057 while (!feof( config
)) {
2060 if (fread( &rem
, 1, 1, config
) != 1)
2064 //it should always return 0
2065 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
2069 fseek( config
, -1, SEEK_CUR
);
2070 memset(value
,'\0',_MAX_PATH
+ 3);
2071 //the * element is not counted
2072 if (fscanf( config
, "%64[^= ] = %[^\r\n]%*[\r\n]", name
, value
)!=2)
2074 for (i
=_MAX_PATH
+ 2; i
> 0; i
--) {
2075 if (value
[i
] == '\0') continue;
2076 if (value
[i
] == ' ') {
2084 #define CONFIG_INT(str, var) \
2085 } else if (stricmp(name, str) == 0) { \
2087 CONFIG_INT("Bpp", Bpp
= );
2088 CONFIG_INT("CaseSensitive", CaseSensitive
= );
2089 CONFIG_INT("DoubleClickDelay", evntmgr
->SetDCDelay
);
2090 CONFIG_INT("DrawFPS", DrawFPS
= );
2091 CONFIG_INT("EnableCheatKeys", EnableCheatKeys
);
2092 CONFIG_INT("EndianSwitch", DataStream::SetEndianSwitch
);
2093 CONFIG_INT("FogOfWar", FogOfWar
= );
2094 //CONFIG_INT("FullScreen", FullScreen = );
2095 CONFIG_INT("GUIEnhancements", GUIEnhancements
= );
2096 CONFIG_INT("GameOnCD", GameOnCD
= );
2097 CONFIG_INT("Height", Height
= );
2098 CONFIG_INT("KeepCache", KeepCache
= );
2099 CONFIG_INT("MultipleQuickSaves", GameControl::MultipleQuickSaves
);
2100 CONFIG_INT("RepeatKeyDelay", evntmgr
->SetRKDelay
);
2101 CONFIG_INT("SaveAsOriginal", SaveAsOriginal
= );
2102 CONFIG_INT("ScriptDebugMode", SetScriptDebugMode
);
2103 CONFIG_INT("SkipIntroVideos", SkipIntroVideos
= );
2104 CONFIG_INT("TooltipDelay", TooltipDelay
= );
2105 CONFIG_INT("Width", Width
= );
2107 #define CONFIG_STRING(str, var) \
2108 } else if (stricmp(name, str) == 0) { \
2109 strncpy(var, value, sizeof(var))
2110 CONFIG_STRING("GameCharactersPath", GameCharactersPath
);
2111 CONFIG_STRING("GameDataPath", GameDataPath
);
2112 CONFIG_STRING("GameName", GameName
);
2113 CONFIG_STRING("GameOverridePath", GameOverridePath
);
2114 CONFIG_STRING("GamePortraitsPath", GamePortraitsPath
);
2115 CONFIG_STRING("GameScriptsPath", GameScriptsPath
);
2116 CONFIG_STRING("GameSoundsPath", GameSoundsPath
);
2117 CONFIG_STRING("GameType", GameType
);
2118 #undef CONFIG_STRING
2119 #define CONFIG_STRING(str, var) \
2120 } else if (stricmp(name, str) == 0) { \
2122 CONFIG_STRING("AudioDriver", AudioDriverName
);
2123 CONFIG_STRING("VideoDriver", VideoDriverName
);
2124 #undef CONFIG_STRING
2125 #define CONFIG_PATH(str, var) \
2126 } else if (stricmp(name, str) == 0) { \
2127 strncpy(var, value, sizeof(var));
2128 CONFIG_PATH("CachePath", CachePath
);
2129 CONFIG_PATH("GUIScriptsPath", GUIScriptsPath
);
2130 CONFIG_PATH("GamePath", GamePath
);
2131 CONFIG_PATH("GemRBOverridePath", GemRBOverridePath
);
2132 CONFIG_PATH("GemRBPath", GemRBPath
);
2133 CONFIG_PATH("PluginsPath", PluginsPath
);
2134 CONFIG_PATH("SavePath", SavePath
);
2136 } else if (stricmp( name
, "ModPath" ) == 0) {
2137 for (char *path
= strtok(value
,SPathListSeparator
);
2139 path
= strtok(NULL
,SPathListSeparator
)) {
2140 ModPath
.push_back(path
);
2142 } else if (stricmp( name
, "SkipPlugin" ) == 0) {
2143 plugin_flags
->SetAt( value
, PLF_SKIP
);
2144 } else if (stricmp( name
, "DelayPlugin" ) == 0) {
2145 plugin_flags
->SetAt( value
, PLF_DELAY
);
2147 for(i
=0;i
<MAX_CD
;i
++) {
2148 char keyname
[] = { 'C', 'D', '1'+i
, '\0' };
2149 if (stricmp(name
, keyname
) == 0) {
2150 for(char *path
= strtok(value
, SPathListSeparator
);
2152 path
= strtok(NULL
,SPathListSeparator
)) {
2153 CD
[i
].push_back(path
);
2161 // WARNING: Don't move ResolveFilePath into the loop
2162 // Otherwise, it won't obey CaseSensitive set at the end
2163 // of the config file.
2166 strcpy( GameType
, "gemrb" );
2167 } else if (stricmp( GameType
, "tob" ) == 0) {
2168 strncpy( GameType
, "bg2", sizeof(GameType
) );
2172 if (!GemRBPath
[0]) {
2173 strcpy( GemRBPath
, DATADIR
);
2176 ResolveFilePath(GemRBPath
);
2178 if (!GemRBOverridePath
[0]) {
2179 strcpy( GemRBOverridePath
, GemRBPath
);
2181 ResolveFilePath(GemRBOverridePath
);
2184 if (!PluginsPath
[0]) {
2186 strcpy( PluginsPath
, PLUGINDIR
);
2188 PathJoin( PluginsPath
, GemRBPath
, "plugins", NULL
);
2191 ResolveFilePath( PluginsPath
);
2194 if (!GUIScriptsPath
[0]) {
2195 strcpy( GUIScriptsPath
, GemRBPath
);
2197 ResolveFilePath( GUIScriptsPath
);
2201 strcpy( GameName
, GEMRB_STRING
);
2204 ResolveFilePath( GamePath
);
2207 // FIXME: maybe should use UserDir instead of GamePath
2208 strcpy( SavePath
, GamePath
);
2210 ResolveFilePath( SavePath
);
2213 if (! CachePath
[0]) {
2214 PathJoin( CachePath
, UserDir
, "Cache", NULL
);
2216 ResolveFilePath(CachePath
);
2219 for (i
= 0; i
< MAX_CD
; ++i
) {
2220 if (!CD
[i
].size()) {
2221 char cd
[] = { 'C', 'D', '1'+i
, '\0' };
2222 char name
[_MAX_PATH
];
2224 PathJoin(name
, GamePath
, cd
, NULL
);
2225 CD
[i
].push_back(name
);
2227 size_t cnt
= CD
[i
].size();
2229 ResolveFilePath( CD
[i
][cnt
] );
2234 for (i
= 0; i
< ModPath
.size(); ++i
) {
2235 ResolveFilePath(ModPath
[i
]);
2238 FixPath( GUIScriptsPath
, true );
2239 FixPath( PluginsPath
, true );
2240 FixPath( GemRBPath
, true );
2241 FixPath( GemRBOverridePath
, true );
2244 FixPath( GamePath
, true );
2247 //FixPath( SavePath, false );
2248 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2249 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2250 FixPath( SavePath
, true );
2252 FixPath( CachePath
, false );
2253 mkdir( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2254 chmod( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2256 printStatus( "OK", LIGHT_GREEN
);
2257 if ( StupidityDetector( CachePath
)) {
2258 printMessage("Core"," ",LIGHT_RED
);
2259 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath
);
2262 if (!KeepCache
) DelTree((const char *) CachePath
, false);
2263 FixPath( CachePath
, true );
2268 static void upperlower(int upper
, int lower
)
2270 pl_uppercase
[lower
]=(ieByte
) upper
;
2271 pl_lowercase
[upper
]=(ieByte
) lower
;
2274 static const char *game_flags
[GF_COUNT
+1]={
2275 "HasKaputz", //0 GF_HAS_KAPUTZ
2276 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2277 "HasSongList", //2 GF_HAS_SONGLIST
2278 "TeamMovement", //3 GF_TEAM_MOVEMENT
2279 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2280 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2281 "HasPartyIni", //6 GF_HAS_PARTY_INI
2282 "SoundFolders", //7 GF_SOUNDFOLDERS
2283 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2284 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2285 "HasDPLAYER", //10GF_HAS_DPLAYER
2286 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2287 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2288 "HasDescIcon", //13GF_HAS_DESC_ICON
2289 "HasPickSound", //14GF_HAS_PICK_SOUND
2290 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2291 "AutomapIni", //16GF_AUTOMAP_INI
2292 "SmallFog", //17GF_SMALL_FOG
2293 "ReverseDoor", //18GF_REVERSE_DOOR
2294 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2295 "HasSpellList", //20GF_HAS_SPELLLIST
2296 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2297 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2298 "KnowWorld", //23GF_KNOW_WORLD
2299 "ReverseToHit", //24GF_REVERSE_TOHIT
2300 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2301 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2302 "MagicBit", //27GF_MAGICBIT
2303 "CheckAbilities", //28GF_CHECK_ABILITIES
2304 "ChallengeRating", //29GF_CHALLENGERATING
2305 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2306 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2307 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2308 "SpawnIni", //33GF_SPAWN_INI
2309 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2310 "HasResDataIni", //35GF_RESDATA_INI
2311 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2312 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2313 "3EdRules", //38GF_3ED_RULES
2314 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2315 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2316 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2317 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2318 "ProperBackstab", //43GF_PROPER_BACKSTAB
2319 "OnScreenText", //44GF_ONSCREEN_TEXT
2320 "HasSpecificDamageBonus", //45GF_SPECIFIC_DMG_BONUS
2321 "StrrefSaveGame", //46GF_STRREF_SAVEGAME
2322 "HasWisdomBonusTable",//47GF_WISDOM_BONUS
2323 "BiographyIsRes", //48GF_BIOGRAPHY_RES
2324 "NoBiography", //49GF_NO_BIOGRAPHY
2325 "StealIsAttack", //50GF_STEAL_IS_ATTACK
2326 NULL
//for our own safety, this marks the end of the pole
2329 /** Loads gemrb.ini */
2330 bool Interface::LoadGemRBINI()
2332 DataStream
* inifile
= gamedata
->GetResource( "gemrb", IE_INI_CLASS_ID
);
2334 printStatus( "ERROR", LIGHT_RED
);
2338 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE
);
2339 printf( "%s",inifile
->originalfile
);
2341 if (!IsAvailable( IE_INI_CLASS_ID
)) {
2342 printStatus( "ERROR", LIGHT_RED
);
2343 printf( "[Core]: No INI Importer Available.\n" );
2346 PluginHolder
<DataFileMgr
> ini(IE_INI_CLASS_ID
);
2347 ini
->Open( inifile
, true ); //autofree
2349 printStatus( "OK", LIGHT_GREEN
);
2353 // Resrefs are already initialized in Interface::Interface()
2354 s
= ini
->GetKeyAsString( "resources", "CursorBAM", NULL
);
2356 strnlwrcpy( CursorBam
, s
, 8 ); //console cursor
2358 s
= ini
->GetKeyAsString( "resources", "ScrollCursorBAM", NULL
);
2360 strnlwrcpy( ScrollCursorBam
, s
, 8 );
2362 s
= ini
->GetKeyAsString( "resources", "ButtonFont", NULL
);
2364 strnlwrcpy( ButtonFont
, s
, 8 );
2366 s
= ini
->GetKeyAsString( "resources", "TooltipFont", NULL
);
2368 strnlwrcpy( TooltipFont
, s
, 8 );
2370 s
= ini
->GetKeyAsString( "resources", "MovieFont", NULL
);
2372 strnlwrcpy( MovieFont
, s
, 8 );
2374 s
= ini
->GetKeyAsString( "resources", "TooltipBack", NULL
);
2376 strnlwrcpy( TooltipBackResRef
, s
, 8 );
2378 s
= ini
->GetKeyAsString( "resources", "TooltipColor", NULL
);
2381 unsigned long c
= strtoul (s
+ 1, NULL
, 16);
2382 // FIXME: check errno
2383 TooltipColor
.r
= (unsigned char) (c
>> 24);
2384 TooltipColor
.g
= (unsigned char) (c
>> 16);
2385 TooltipColor
.b
= (unsigned char) (c
>> 8);
2386 TooltipColor
.a
= (unsigned char) (c
);
2390 //which stat determines the fist weapon (defaults to class)
2391 Actor::SetFistStat(ini
->GetKeyAsInt( "resources", "FistStat", IE_CLASS
));
2393 TooltipMargin
= ini
->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin
);
2395 // The format of GroundCircle can be:
2396 // GroundCircleBAM1 = wmpickl/3
2397 // to denote that the bitmap should be scaled down 3x
2398 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
2400 sprintf( name
, "GroundCircleBAM%d", size
+1 );
2401 s
= ini
->GetKeyAsString( "resources", name
, NULL
);
2403 const char *pos
= strchr( s
, '/' );
2405 GroundCircleScale
[size
] = atoi( pos
+1 );
2406 strncpy( GroundCircleBam
[size
], s
, pos
- s
);
2407 GroundCircleBam
[size
][pos
- s
] = '\0';
2409 strcpy( GroundCircleBam
[size
], s
);
2414 s
= ini
->GetKeyAsString( "resources", "NoteString", NULL
);
2415 TextArea::SetNoteString(s
);
2417 s
= ini
->GetKeyAsString( "resources", "INIConfig", NULL
);
2419 strcpy( INIConfig
, s
);
2421 s
= ini
->GetKeyAsString( "resources", "Palette16", NULL
);
2423 strcpy( Palette16
, s
);
2425 s
= ini
->GetKeyAsString( "resources", "Palette32", NULL
);
2427 strcpy( Palette32
, s
);
2429 s
= ini
->GetKeyAsString( "resources", "Palette256", NULL
);
2431 strcpy( Palette256
, s
);
2433 unsigned int i
= (unsigned int) ini
->GetKeyAsInt ("charset", "CharCount", 0);
2437 snprintf(key
,9,"Letter%d", i
+1);
2438 s
= ini
->GetKeyAsString( "charset", key
, NULL
);
2440 const char *s2
= strchr(s
,',');
2442 upperlower(atoi(s
), atoi(s2
+1) );
2447 MaximumAbility
= ini
->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2449 RedrawTile
= ini
->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2451 for (i
=0;i
<GF_COUNT
;i
++) {
2452 if (!game_flags
[i
]) {
2453 printf("Fix the game flags!\n");
2456 SetFeature( ini
->GetKeyAsInt( "resources", game_flags
[i
], 0 ), i
);
2457 //printMessage("Option", "", GREEN);
2458 //printf("%s = %s\n", game_flags[i], HasFeature(i)?"yes":"no");
2461 ForceStereo
= ini
->GetKeyAsInt( "resources", "ForceStereo", 0 );
2466 Palette
* Interface::CreatePalette(const Color
&color
, const Color
&back
)
2468 Palette
* pal
= new Palette();
2470 pal
->col
[0].g
= 0xff;
2473 for (int i
= 1; i
< 256; i
++) {
2474 pal
->col
[i
].r
= back
.r
+
2475 ( unsigned char ) ( ( ( color
.r
- back
.r
) * ( i
) ) / 255.0 );
2476 pal
->col
[i
].g
= back
.g
+
2477 ( unsigned char ) ( ( ( color
.g
- back
.g
) * ( i
) ) / 255.0 );
2478 pal
->col
[i
].b
= back
.b
+
2479 ( unsigned char ) ( ( ( color
.b
- back
.b
) * ( i
) ) / 255.0 );
2480 pal
->col
[i
].a
= back
.a
+
2481 ( unsigned char ) ( ( ( color
.a
- back
.a
) * ( i
) ) / 255.0 );
2486 /** No descriptions */
2487 Color
* Interface::GetPalette(unsigned index
, int colors
, Color
*pal
) const
2492 } else if (colors
<= 32) {
2494 } else if (colors
== 256) {
2499 if (index
>= img
->GetHeight()) {
2502 for (int i
= 0; i
< colors
; i
++) {
2503 pal
[i
] = img
->GetPixel(i
, index
);
2507 /** Returns a preloaded Font */
2508 Font
* Interface::GetFont(const char *ResRef
) const
2510 for (unsigned int i
= 0; i
< fonts
.size(); i
++) {
2511 if (strnicmp( fonts
[i
]->ResRef
, ResRef
, 8 ) == 0) {
2518 Font
* Interface::GetFont(unsigned int index
) const
2520 if (index
>= fonts
.size()) {
2523 return fonts
[index
];
2526 Font
* Interface::GetButtonFont() const
2528 return GetFont( ButtonFont
);
2531 /** Returns the Event Manager */
2532 EventMgr
* Interface::GetEventMgr() const
2537 /** Returns the Window Manager */
2538 WindowMgr
* Interface::GetWindowMgr() const
2540 return windowmgr
.get();
2543 /** Get GUI Script Manager */
2544 ScriptEngine
* Interface::GetGUIScriptEngine() const
2546 return guiscript
.get();
2549 static EffectRef fx_summon_disable_ref
={"AvatarRemovalModifier",NULL
,-1};
2551 //NOTE: if there were more summoned creatures, it will return only the last
2552 Actor
*Interface::SummonCreature(const ieResRef resource
, const ieResRef vvcres
, Scriptable
*Owner
, Actor
*target
, const Point
&position
, int eamod
, int level
, Effect
*fx
, bool sexmod
)
2554 //maximum number of monsters summoned
2559 //decrease the number of summoned creatures with the number of already summoned creatures here
2560 //the summoned creatures have a special IE_SPECIFIC
2563 ab
= gamedata
->GetCreature(resource
);
2568 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2569 ab
->LastSummoner
= ((Actor
*) Owner
)->GetID();
2571 //Always use Base stats for the recently summoned creature
2575 if (eamod
==EAM_SOURCEALLY
|| eamod
==EAM_SOURCEENEMY
) {
2576 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2577 enemyally
= ((Actor
*) Owner
)->GetStat(IE_EA
)>EA_GOODCUTOFF
;
2583 enemyally
= target
->GetBase(IE_EA
)>EA_GOODCUTOFF
;
2590 case EAM_SOURCEALLY
:
2593 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2595 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2598 case EAM_SOURCEENEMY
:
2601 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2603 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2607 ab
->SetBase(IE_EA
, EA_NEUTRAL
);
2613 // mark the summon, but only if they don't have a special sex already
2614 if (sexmod
&& ab
->BaseStats
[IE_SEX
] < SEX_EXTRA
) {
2615 ab
->SetBase(IE_SEX
, SEX_SUMMON
);
2620 map
= target
->GetCurrentArea();
2622 map
= Owner
->GetCurrentArea();
2625 ab
->SetPosition(position
, true, 0);
2626 ab
->RefreshEffects(NULL
);
2629 ScriptedAnimation
* vvc
= gamedata
->GetScriptedAnimation(vvcres
, false);
2631 //This is the final position of the summoned creature
2632 //not the original target point
2633 vvc
->XPos
=ab
->Pos
.x
;
2634 vvc
->YPos
=ab
->Pos
.y
;
2635 //force vvc to play only once
2637 map
->AddVVCell( vvc
);
2639 //set up the summon disable effect
2640 Effect
*newfx
= EffectQueue::CreateEffect(fx_summon_disable_ref
, 0, 1, FX_DURATION_INSTANT_LIMITED
);
2641 newfx
->Duration
= vvc
->GetSequenceDuration(AI_UPDATE_TIME
)*90/100;
2642 ApplyEffect(newfx
, ab
, ab
);
2646 //remove the xp value of friendly summons
2647 if (ab
->BaseStats
[IE_EA
]<EA_GOODCUTOFF
) {
2648 ab
->SetBase(IE_XPVALUE
, 0);
2651 ApplyEffect(fx
, ab
, Owner
);
2654 //this check should happen after the fact
2655 level
-= ab
->GetBase(IE_XP
);
2664 void Interface::RedrawControls(const char *varname
, unsigned int value
)
2666 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2667 Window
*win
= windows
[i
];
2668 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2669 win
->RedrawControls(varname
, value
);
2674 void Interface::RedrawAll()
2676 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2677 Window
*win
= windows
[i
];
2678 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2684 /** Loads a WindowPack (CHUI file) in the Window Manager */
2685 bool Interface::LoadWindowPack(const char* name
)
2687 DataStream
* stream
= gamedata
->GetResource( name
, IE_CHU_CLASS_ID
);
2688 if (stream
== NULL
) {
2689 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED
);
2690 printf( "%s.chu\n", name
);
2693 if (!GetWindowMgr()->Open( stream
, true )) {
2694 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED
);
2695 printf( "%s.chu\n", name
);
2699 strncpy( WindowPack
, name
, sizeof( WindowPack
) );
2700 WindowPack
[sizeof( WindowPack
) - 1] = '\0';
2705 /** Loads a Window in the Window Manager */
2706 int Interface::LoadWindow(unsigned short WindowID
)
2710 for (i
= 0; i
< windows
.size(); i
++) {
2711 Window
*win
= windows
[i
];
2714 if (win
->Visible
==WINDOW_INVALID
) {
2717 if (win
->WindowID
== WindowID
&&
2718 !strnicmp( WindowPack
, win
->WindowPack
, sizeof(WindowPack
) )) {
2724 Window
* win
= windowmgr
->GetWindow( WindowID
);
2728 memcpy( win
->WindowPack
, WindowPack
, sizeof(WindowPack
) );
2731 for (i
= 0; i
< windows
.size(); i
++) {
2732 if (windows
[i
] == NULL
) {
2738 windows
.push_back( win
);
2739 slot
= ( int ) windows
.size() - 1;
2741 windows
[slot
] = win
;
2746 // FIXME: it's a clone of LoadWindow
2747 /** Creates a Window in the Window Manager */
2748 int Interface::CreateWindow(unsigned short WindowID
, int XPos
, int YPos
, unsigned int Width
, unsigned int Height
, char* Background
)
2752 for (i
= 0; i
< windows
.size(); i
++) {
2753 if (windows
[i
] == NULL
)
2755 if (windows
[i
]->WindowID
== WindowID
&& !stricmp( WindowPack
,
2756 windows
[i
]->WindowPack
)) {
2758 windows
[i
]->Invalidate();
2763 Window
* win
= new Window( WindowID
, (ieWord
) XPos
, (ieWord
) YPos
, (ieWord
) Width
, (ieWord
) Height
);
2764 if (Background
[0]) {
2765 if (IsAvailable( IE_MOS_CLASS_ID
)) {
2766 ResourceHolder
<ImageMgr
> mos(Background
);
2768 win
->SetBackGround( mos
->GetSprite2D(), true );
2770 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2772 printf( "[Core]: No MOS Importer Available, skipping background\n" );
2775 strcpy( win
->WindowPack
, WindowPack
);
2778 for (i
= 0; i
< windows
.size(); i
++) {
2779 if (windows
[i
] == NULL
) {
2785 windows
.push_back( win
);
2786 slot
= ( int ) windows
.size() - 1;
2788 windows
[slot
] = win
;
2794 /** Sets a Window on the Top */
2795 void Interface::SetOnTop(int Index
)
2797 std::vector
<int>::iterator t
;
2798 for(t
= topwin
.begin(); t
!= topwin
.end(); ++t
) {
2804 if(topwin
.size() != 0)
2805 topwin
.insert(topwin
.begin(), Index
);
2807 topwin
.push_back(Index
);
2809 /** Add a window to the Window List */
2810 void Interface::AddWindow(Window
* win
)
2813 for(unsigned int i
= 0; i
< windows
.size(); i
++) {
2814 Window
*w
= windows
[i
];
2822 windows
.push_back(win
);
2823 slot
=(int)windows
.size()-1;
2826 windows
[slot
] = win
;
2830 /** Get a Control on a Window */
2831 int Interface::GetControl(unsigned short WindowIndex
, unsigned long ControlID
) const
2833 if (WindowIndex
>= windows
.size()) {
2836 Window
* win
= windows
[WindowIndex
];
2842 Control
* ctrl
= win
->GetControl( (unsigned short) i
);
2845 if (ctrl
->ControlID
== ControlID
)
2850 /** Adjust the Scrolling factor of a control (worldmap atm) */
2851 int Interface::AdjustScrolling(unsigned short WindowIndex
,
2852 unsigned short ControlIndex
, short x
, short y
)
2854 if (WindowIndex
>= windows
.size()) {
2857 Window
* win
= windows
[WindowIndex
];
2861 Control
* ctrl
= win
->GetControl( ControlIndex
);
2865 switch(ctrl
->ControlType
) {
2866 case IE_GUI_WORLDMAP
:
2867 ((WorldMapControl
*) ctrl
)->AdjustScrolling(x
,y
);
2869 default: //doesn't work for these
2875 /** Set the Text of a Control */
2876 int Interface::SetText(unsigned short WindowIndex
,
2877 unsigned short ControlIndex
, const char* string
)
2879 if (WindowIndex
>= windows
.size()) {
2882 Window
* win
= windows
[WindowIndex
];
2886 Control
* ctrl
= win
->GetControl( ControlIndex
);
2890 return ctrl
->SetText( string
);
2892 /** Set the Tooltip text of a Control */
2893 int Interface::SetTooltip(unsigned short WindowIndex
,
2894 unsigned short ControlIndex
, const char* string
)
2896 if (WindowIndex
>= windows
.size()) {
2899 Window
* win
= windows
[WindowIndex
];
2903 Control
* ctrl
= win
->GetControl( ControlIndex
);
2907 return ctrl
->SetTooltip( string
);
2910 void Interface::DisplayTooltip(int x
, int y
, Control
*ctrl
)
2912 if (tooltip_ctrl
&& tooltip_ctrl
== ctrl
&& tooltip_x
== x
&& tooltip_y
== y
)
2916 tooltip_currtextw
= 0;
2917 tooltip_ctrl
= ctrl
;
2920 int Interface::GetVisible(unsigned short WindowIndex
) const
2922 if (WindowIndex
>= windows
.size()) {
2925 Window
* win
= windows
[WindowIndex
];
2929 return win
->Visible
;
2931 /** Set a Window Visible Flag */
2932 int Interface::SetVisible(unsigned short WindowIndex
, int visible
)
2934 if (WindowIndex
>= windows
.size()) {
2937 Window
* win
= windows
[WindowIndex
];
2941 if (visible
!=WINDOW_FRONT
) {
2942 win
->Visible
= (char) visible
;
2947 //here is a fallthrough
2948 case WINDOW_INVISIBLE
:
2949 //hiding the viewport if the gamecontrol window was made invisible
2950 if (win
->WindowID
==65535) {
2951 video
->SetViewport( 0,0,0,0 );
2953 evntmgr
->DelWindow( win
);
2956 case WINDOW_VISIBLE
:
2957 if (win
->WindowID
==65535) {
2958 video
->SetViewport( win
->XPos
, win
->YPos
, win
->Width
, win
->Height
);
2960 //here is a fallthrough
2962 if (win
->Visible
==WINDOW_VISIBLE
) {
2963 evntmgr
->AddWindow( win
);
2966 SetOnTop( WindowIndex
);
2973 /** Set the Status of a Control in a Window */
2974 int Interface::SetControlStatus(unsigned short WindowIndex
,
2975 unsigned short ControlIndex
, unsigned long Status
)
2977 //don't set the status of an already invalidated window
2978 Window
* win
= GetWindow(WindowIndex
);
2982 Control
* ctrl
= win
->GetControl( ControlIndex
);
2986 if (Status
&IE_GUI_CONTROL_FOCUSED
) {
2987 evntmgr
->SetFocused( win
, ctrl
);
2989 if (ctrl
->ControlType
!= ((Status
>> 24) & 0xff) ) {
2992 switch (ctrl
->ControlType
) {
2996 Button
* btn
= ( Button
* ) ctrl
;
2997 btn
->SetState( ( unsigned char ) ( Status
& 0x7f ) );
3001 ctrl
->Value
= Status
& 0x7f;
3007 /** Show a Window in Modal Mode */
3008 int Interface::ShowModal(unsigned short WindowIndex
, int Shadow
)
3010 if (WindowIndex
>= windows
.size()) {
3011 printMessage( "Core", "Window not found", LIGHT_RED
);
3014 Window
* win
= windows
[WindowIndex
];
3016 printMessage( "Core", "Window already freed", LIGHT_RED
);
3019 win
->Visible
= WINDOW_FRONT
;
3020 //don't destroy the other window handlers
3022 SetOnTop( WindowIndex
);
3023 evntmgr
->AddWindow( win
);
3024 evntmgr
->SetFocused( win
, NULL
);
3037 Region
r( 0, 0, Width
, Height
);
3039 if (Shadow
== MODAL_SHADOW_GRAY
) {
3040 video
->DrawRect( r
, gray
);
3041 } else if (Shadow
== MODAL_SHADOW_BLACK
) {
3042 video
->DrawRect( r
, black
);
3049 bool Interface::IsFreezed()
3051 return !update_scripts
;
3054 void Interface::GameLoop(void)
3056 update_scripts
= false;
3057 GameControl
*gc
= GetGameControl();
3059 update_scripts
= !(gc
->GetDialogueFlags() & DF_FREEZE_SCRIPTS
);
3062 GSUpdate(update_scripts
);
3064 //i'm not sure if this should be here
3066 //in multi player (if we ever get to it), only the server must call this
3067 if (update_scripts
) {
3068 if ( game
->selected
.size() > 0 ) {
3069 gc
->ChangeMap(GetFirstSelectedPC(true), false);
3071 // the game object will run the area scripts as well
3072 game
->UpdateScripts();
3076 /** handles hardcoded gui behaviour */
3077 void Interface::HandleGUIBehaviour(void)
3079 GameControl
*gc
= GetGameControl();
3081 //this variable is used all over in the following hacks
3082 int flg
= gc
->GetDialogueFlags();
3084 //the following part is a series of hardcoded gui behaviour
3087 if (flg
& DF_IN_DIALOG
) {
3092 ieDword var
= (ieDword
) -3;
3093 vars
->Lookup("DialogChoose", var
);
3094 if ((int) var
== -2) {
3095 gc
->dialoghandler
->EndDialog();
3096 } else if ( (int)var
!=-3) {
3097 gc
->dialoghandler
->DialogChoose(var
);
3098 if (!(gc
->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW
| DF_OPENENDWINDOW
)))
3099 guiscript
->RunFunction( "GUIWORLD", "NextDialogState" );
3101 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3102 ieDword newvar
= 0; vars
->Lookup("DialogChoose", newvar
);
3103 if (var
== (ieDword
) -1 || newvar
!= (ieDword
) -1) {
3104 vars
->SetAt("DialogChoose", (ieDword
) -3);
3107 if (flg
& DF_OPENCONTINUEWINDOW
) {
3108 guiscript
->RunFunction( "GUIWORLD", "OpenContinueMessageWindow" );
3109 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3110 } else if (flg
& DF_OPENENDWINDOW
) {
3111 guiscript
->RunFunction( "GUIWORLD", "OpenEndMessageWindow" );
3112 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3116 //handling container
3117 if (CurrentContainer
&& UseContainer
) {
3118 if (!(flg
& DF_IN_CONTAINER
) ) {
3119 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_OR
);
3120 guiscript
->RunFunction( "GUIWORLD", "OpenContainerWindow" );
3123 if (flg
& DF_IN_CONTAINER
) {
3124 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_NAND
);
3125 guiscript
->RunFunction( "GUIWORLD", "CloseContainerWindow" );
3132 void Interface::DrawWindows(void)
3134 //here comes the REAL drawing of windows
3136 ModalWindow
->DrawWindow();
3139 size_t i
= topwin
.size();
3141 unsigned int t
= topwin
[i
];
3143 if ( t
>=windows
.size() )
3146 //visible ==1 or 2 will be drawn
3147 Window
* win
= windows
[t
];
3149 if (win
->Visible
== WINDOW_INVALID
) {
3150 topwin
.erase(topwin
.begin()+i
);
3151 evntmgr
->DelWindow( win
);
3154 } else if (win
->Visible
) {
3161 void Interface::DrawTooltip ()
3163 if (! tooltip_ctrl
|| !tooltip_ctrl
->Tooltip
)
3166 Font
* fnt
= GetFont( TooltipFont
);
3167 char *tooltip_text
= tooltip_ctrl
->Tooltip
;
3171 int strw
= fnt
->CalcStringWidth( tooltip_text
) + 8;
3173 int h
= fnt
->maxHeight
;
3176 // animate BG tooltips
3177 // TODO: make tooltip animation an option instead
3178 // of following hard-coded check!
3179 if (TooltipMargin
== 5) {
3180 // TODO: make speed an option
3181 int tooltip_anim_speed
= 15;
3182 if (tooltip_currtextw
< strw
) {
3183 tooltip_currtextw
+= tooltip_anim_speed
;
3185 if (tooltip_currtextw
> strw
) {
3186 tooltip_currtextw
= strw
;
3188 w
= tooltip_currtextw
;
3191 h
= TooltipBack
[0]->Height
;
3192 w1
= TooltipBack
[1]->Width
;
3193 w2
= TooltipBack
[2]->Width
;
3194 w
+= TooltipMargin
*2;
3195 strw
+= TooltipMargin
*2;
3196 //multiline in case of too much text
3197 if (w
>TooltipBack
[0]->Width
)
3198 strw
=w
=TooltipBack
[0]->Width
;
3199 else if (strw
>TooltipBack
[0]->Width
)
3200 strw
=TooltipBack
[0]->Width
;
3203 int strx
= tooltip_x
- strw
/ 2;
3204 int y
= tooltip_y
- h
/ 2;
3205 // Ensure placement within the screen
3206 if (strx
< 0) strx
= 0;
3207 else if (strx
+ strw
+ w1
+ w2
> Width
)
3208 strx
= Width
- strw
- w1
- w2
;
3210 else if (y
+ h
> Height
)
3213 int x
= strx
+ ((strw
- w
) / 2);
3215 // FIXME: take back[0] from center, not from left end
3216 Region r2
= Region( x
, y
, w
, h
);
3218 video
->BlitSprite( TooltipBack
[0], x
+ TooltipMargin
, y
, true, &r2
);
3219 video
->BlitSprite( TooltipBack
[1], x
, y
, true );
3220 video
->BlitSprite( TooltipBack
[2], x
+ w
, y
, true );
3224 r2
.x
+=TooltipMargin
;
3225 strx
+=TooltipMargin
;
3227 Region textr
= Region( strx
, y
, strw
, h
);
3228 fnt
->Print( r2
, textr
, (ieByte
*) tooltip_text
, NULL
,
3229 IE_FONT_ALIGN_CENTER
| IE_FONT_ALIGN_MIDDLE
, true );
3232 //interface for higher level functions, if the window was
3233 //marked for deletion it is not returned
3234 Window
* Interface::GetWindow(unsigned short WindowIndex
) const
3236 if (WindowIndex
< windows
.size()) {
3237 Window
*win
= windows
[WindowIndex
];
3238 if (win
&& (win
->Visible
!=WINDOW_INVALID
) ) {
3245 // this function will determine if wnd is a valid window pointer
3246 // by checking if its WindowID is the same as the reference
3247 bool Interface::IsValidWindow(unsigned short WindowID
, Window
*wnd
) const
3249 size_t WindowIndex
= windows
.size();
3250 while (WindowIndex
--) {
3251 if (windows
[WindowIndex
] == wnd
) {
3252 return wnd
->WindowID
== WindowID
;
3258 //this function won't delete the window, just mark it for deletion
3259 //it will be deleted in the next DrawWindows cycle
3260 //regardless, the window deleted is inaccessible for gui scripts and
3261 //other high level functions from now
3262 int Interface::DelWindow(unsigned short WindowIndex
)
3264 if (WindowIndex
>= windows
.size()) {
3267 Window
* win
= windows
[WindowIndex
];
3268 if ((win
== NULL
) || (win
->Visible
==WINDOW_INVALID
) ) {
3269 printMessage( "Core", "Window deleted again", LIGHT_RED
);
3272 if (win
== ModalWindow
) {
3274 RedrawAll(); //marking windows for redraw
3276 evntmgr
->DelWindow( win
);
3278 //re-capturing new (old) modal window if any
3279 size_t tw
= topwin
.size();
3280 for(size_t i
=0;i
<tw
;i
++) {
3281 Window
*tmp
= windows
[topwin
[i
]];
3282 if (tmp
->Visible
==WINDOW_FRONT
) {
3290 void Interface::DelAllWindows()
3292 vars
->SetAt("MessageWindow", (ieDword
) ~0);
3293 vars
->SetAt("OptionsWindow", (ieDword
) ~0);
3294 vars
->SetAt("PortraitWindow", (ieDword
) ~0);
3295 vars
->SetAt("ActionsWindow", (ieDword
) ~0);
3296 vars
->SetAt("TopWindow", (ieDword
) ~0);
3297 vars
->SetAt("OtherWindow", (ieDword
) ~0);
3298 vars
->SetAt("FloatWindow", (ieDword
) ~0);
3299 for(unsigned int WindowIndex
=0; WindowIndex
<windows
.size();WindowIndex
++) {
3300 Window
* win
= windows
[WindowIndex
];
3309 /** Popup the Console */
3310 void Interface::PopupConsole()
3312 ConsolePopped
= !ConsolePopped
;
3314 console
->Changed
= true;
3317 /** Draws the Console */
3318 void Interface::DrawConsole()
3320 console
->Draw( 0, 0 );
3323 /** Get the Sound Manager */
3324 SaveGameIterator
* Interface::GetSaveGameIterator() const
3328 /** Sends a termination signal to the Video Driver */
3329 bool Interface::Quit(void)
3331 return video
->Quit();
3333 /** Returns the variables dictionary */
3334 Variables
* Interface::GetDictionary() const
3338 /** Returns the token dictionary */
3339 Variables
* Interface::GetTokenDictionary() const
3343 /** Get the Music Manager */
3344 MusicMgr
* Interface::GetMusicMgr() const
3348 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3349 int Interface::LoadSymbol(const char* ResRef
)
3351 int ind
= GetSymbolIndex( ResRef
);
3355 DataStream
* str
= gamedata
->GetResource( ResRef
, IE_IDS_CLASS_ID
);
3359 PluginHolder
<SymbolMgr
> sm(IE_IDS_CLASS_ID
);
3364 if (!sm
->Open( str
, true )) {
3368 strncpy( s
.ResRef
, ResRef
, 8 );
3371 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3372 if (!symbols
[i
].sm
) {
3381 symbols
.push_back( s
);
3382 return ( int ) symbols
.size() - 1;
3384 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3385 int Interface::GetSymbolIndex(const char* ResRef
) const
3387 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3390 if (strnicmp( symbols
[i
].ResRef
, ResRef
, 8 ) == 0)
3395 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3396 Holder
<SymbolMgr
> Interface::GetSymbol(unsigned int index
) const
3398 if (index
>= symbols
.size()) {
3399 return Holder
<SymbolMgr
>();
3401 if (!symbols
[index
].sm
) {
3402 return Holder
<SymbolMgr
>();
3404 return symbols
[index
].sm
;
3406 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3407 bool Interface::DelSymbol(unsigned int index
)
3409 if (index
>= symbols
.size()) {
3412 if (!symbols
[index
].sm
) {
3415 symbols
[index
].sm
.release();
3418 /** Plays a Movie */
3419 int Interface::PlayMovie(const char* ResRef
)
3421 ResourceHolder
<MoviePlayer
> mp(ResRef
);
3426 ieDword subtitles
= 0;
3427 Font
*SubtitleFont
= NULL
;
3428 Palette
*palette
= NULL
;
3429 ieDword
*frames
= NULL
;
3430 ieDword
*strrefs
= NULL
;
3434 //one of these two should exist (they both mean the same thing)
3435 vars
->Lookup("Display Movie Subtitles", subtitles
);
3442 vars
->Lookup("Display Subtitles", subtitles
);
3445 if (subtitles
&& sttable
.load(ResRef
)) {
3446 cnt
+= sttable
->GetRowCount();
3448 frames
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3449 strrefs
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3453 if (frames
&& strrefs
) {
3454 for (int i
=0;i
<cnt
;i
++) {
3455 frames
[i
] = atoi (sttable
->QueryField(i
+offset
, 0) );
3456 strrefs
[i
] = atoi (sttable
->QueryField(i
+offset
, 1) );
3459 int r
= atoi(sttable
->QueryField("red", "frame"));
3460 int g
= atoi(sttable
->QueryField("green", "frame"));
3461 int b
= atoi(sttable
->QueryField("blue", "frame"));
3462 SubtitleFont
= GetFont (MovieFont
); //will change
3465 Color fore
= {(unsigned char) r
,(unsigned char) g
,(unsigned char) b
, 0x00};
3466 Color back
= {0x00, 0x00, 0x00, 0x00};
3467 palette
= CreatePalette( fore
, back
);
3472 //shutting down music and ambients before movie
3475 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3476 if (ambim
) ambim
->deactivate();
3477 video
->SetMovieFont(SubtitleFont
, palette
);
3478 mp
->CallBackAtFrames(cnt
, frames
, strrefs
);
3480 gamedata
->FreePalette( palette
);
3488 if (ambim
) ambim
->activate();
3489 //this will fix redraw all windows as they looked like
3493 //Setting the movie name to 1
3494 vars
->SetAt( ResRef
, 1 );
3498 int Interface::Roll(int dice
, int size
, int add
) const
3507 return add
+ dice
* size
/ 2;
3509 for (int i
= 0; i
< dice
; i
++) {
3510 add
+= rand() % size
+ 1;
3515 static char bmp_suffix
[6]="M.BMP";
3516 static char png_suffix
[6]="M.PNG";
3518 int Interface::GetPortraits(TextArea
* ta
, bool smallorlarge
)
3521 char Path
[_MAX_PATH
];
3530 PathJoin( Path
, GamePath
, GamePortraitsPath
, NULL
);
3531 DirectoryIterator
dir(Path
);
3535 printf( "Looking in %s\n", Path
);
3537 char *name
= dir
.GetName();
3540 if (dir
.IsDirectory())
3543 char *pos
= strstr(name
,bmp_suffix
);
3544 if (!pos
&& IsAvailable(IE_PNG_CLASS_ID
) ) {
3545 pos
= strstr(name
,png_suffix
);
3550 ta
->AppendText( name
, -1 );
3555 int Interface::GetCharSounds(TextArea
* ta
)
3559 char Path
[_MAX_PATH
];
3561 PathJoin( Path
, GamePath
, GameSoundsPath
, NULL
);
3562 hasfolders
= ( HasFeature( GF_SOUNDFOLDERS
) != 0 );
3563 DirectoryIterator
dir(Path
);
3567 printf( "Looking in %s\n", Path
);
3569 char *name
= dir
.GetName();
3572 if (hasfolders
== !dir
.IsDirectory())
3576 char *pos
= strstr(name
,"A.WAV");
3581 ta
->AppendText( name
, -1 );
3586 int Interface::GetCharacters(TextArea
* ta
)
3589 char Path
[_MAX_PATH
];
3591 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
3592 DirectoryIterator
dir(Path
);
3596 printf( "Looking in %s\n", Path
);
3598 char *name
= dir
.GetName();
3601 if (dir
.IsDirectory())
3604 char *pos
= strstr(name
,".CHR");
3608 ta
->AppendText( name
, -1 );
3613 bool Interface::LoadINI(const char* filename
)
3616 config
= fopen( filename
, "rb" );
3617 if (config
== NULL
) {
3620 char name
[65], value
[_MAX_PATH
+ 3];
3621 while (!feof( config
)) {
3626 if (fread( &rem
, 1, 1, config
) != 1)
3629 if (( rem
== '#' ) ||
3637 } else if (rem
== '\n')
3640 //it should always return zero
3641 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
3645 fseek( config
, -1, SEEK_CUR
);
3646 //the * element is not counted
3647 if (fscanf( config
, "%[^=]=%[^\r\n]%*[\r\n]", name
, value
)!=2)
3649 if (( value
[0] >= '0' ) && ( value
[0] <= '9' )) {
3650 vars
->SetAt( name
, atoi( value
) );
3657 /** Enables/Disables the Cut Scene Mode */
3658 void Interface::SetCutSceneMode(bool active
)
3660 GameControl
*gc
= GetGameControl();
3662 gc
->SetCutSceneMode( active
);
3666 game
->ControlStatus
|= CS_HIDEGUI
;
3668 game
->ControlStatus
&= ~CS_HIDEGUI
;
3670 SetEventFlag(EF_CONTROL
);
3672 video
->SetMouseEnabled(!active
);
3675 bool Interface::InCutSceneMode() const
3677 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE
)!=0;
3680 void Interface::QuitGame(int BackToMain
)
3682 SetCutSceneMode(false);
3685 //clear fade/screenshake effects
3687 timer
->SetFadeFromColor(0);
3690 DelAllWindows(); //delete all windows, including GameControl
3692 //shutting down ingame music
3693 //(do it before deleting the game)
3697 // stop any ambients which are still enqueued
3699 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3700 if (ambim
) ambim
->deactivate();
3702 //delete game, worldmap
3712 strcpy(NextScript
, "Start");
3713 QuitFlag
|= QF_CHANGESCRIPT
;
3718 void Interface::SetupLoadGame(Holder
<SaveGame
> sg
, int ver_override
)
3721 VersionOverride
= ver_override
;
3722 QuitFlag
|= QF_LOADGAME
;
3725 void Interface::LoadGame(SaveGame
*sg
, int ver_override
)
3727 // This function has rather painful error handling,
3728 // as it should swap all the objects or none at all
3729 // and the loading can fail for various reasons
3731 // Yes, it uses goto. Other ways seemed too awkward for me.
3733 strings
->CloseAux();
3734 tokens
->RemoveAll(NULL
); //clearing the token dictionary
3736 if(calendar
) delete calendar
;
3737 calendar
= new Calendar
;
3739 DataStream
* gam_str
= NULL
;
3740 DataStream
* sav_str
= NULL
;
3741 DataStream
* wmp_str
= NULL
;
3744 Game
* new_game
= NULL
;
3745 WorldMapArray
* new_worldmap
= NULL
;
3748 if (!KeepCache
) DelTree((const char *) CachePath
, true);
3752 //Load the Default Game
3753 gam_str
= gamedata
->GetResource( GameNameResRef
, IE_GAM_CLASS_ID
);
3755 wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3757 gam_str
= sg
->GetGame();
3758 sav_str
= sg
->GetSave();
3759 wmp_str
= sg
->GetWmap();
3762 // These are here because of the goto
3763 PluginHolder
<SaveGameMgr
> gam_mgr(IE_GAM_CLASS_ID
);
3764 PluginHolder
<WorldMapMgr
> wmp_mgr(IE_WMP_CLASS_ID
);
3766 if (!gam_str
|| !wmp_str
)
3773 if (!gam_mgr
->Open( gam_str
, true ))
3776 new_game
= gam_mgr
->LoadGame(new Game(), ver_override
);
3782 // Load WMP (WorldMap) file
3786 if (!wmp_mgr
->Open( wmp_str
, true ))
3789 new_worldmap
= wmp_mgr
->GetWorldMapArray( );
3794 // Unpack SAV (archive) file to Cache dir
3796 PluginHolder
<ArchiveImporter
> ai(IE_BIF_CLASS_ID
);
3798 if (ai
->DecompressSaveGame(sav_str
) != GEM_OK
) {
3806 // Let's assume that now is everything loaded OK and swap the objects
3812 worldmap
= new_worldmap
;
3818 // Something went wrong, so try to clean after itself
3821 delete new_worldmap
;
3828 /* swapping out old resources */
3829 void Interface::UpdateMasterScript()
3832 game
->SetScript( GlobalScript
, 0 );
3835 PluginHolder
<WorldMapMgr
> wmp_mgr(IE_WMP_CLASS_ID
);
3840 DataStream
*wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3842 if (!wmp_mgr
->Open( wmp_str
, true )) {
3847 worldmap
= wmp_mgr
->GetWorldMapArray();
3851 GameControl
*Interface::GetGameControl() const
3853 Window
*window
= GetWindow( 0 );
3854 // in the beginning, there's no window at all
3858 Control
* gc
= window
->GetControl(0);
3859 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
) {
3862 return (GameControl
*) gc
;
3865 bool Interface::InitItemTypes()
3870 AutoTable
it("itemtype");
3873 ItemTypes
= it
->GetRowCount(); //number of itemtypes
3877 int InvSlotTypes
= it
->GetColumnCount();
3878 if (InvSlotTypes
> 32) { //bit count limit
3881 //make sure unsigned int is 32 bits
3882 slotmatrix
= (ieDword
*) malloc(ItemTypes
* sizeof(ieDword
) );
3883 for (int i
=0;i
<ItemTypes
;i
++) {
3884 unsigned int value
= 0;
3886 for (int j
=0;j
<InvSlotTypes
;j
++) {
3887 if (strtol(it
->QueryField(i
,j
),NULL
,0) ) {
3892 //we let any items in the inventory
3893 slotmatrix
[i
] = (ieDword
) value
| SLOT_INVENTORY
;
3897 //slottype describes the inventory structure
3898 Inventory::Init(HasFeature(GF_MAGICBIT
));
3899 AutoTable
st("slottype");
3906 SlotTypes
= st
->GetRowCount();
3907 //make sure unsigned int is 32 bits
3908 slottypes
= (SlotType
*) malloc(SlotTypes
* sizeof(SlotType
) );
3909 memset(slottypes
, -1, SlotTypes
* sizeof(SlotType
) );
3910 for (unsigned int row
= 0; row
< SlotTypes
; row
++) {
3912 unsigned int i
= (ieDword
) strtol(st
->GetRowName(row
),NULL
,0 );
3913 if (i
>=SlotTypes
) continue;
3914 if (slottypes
[i
].sloteffects
!=0xffffffffu
) {
3915 slottypes
[row
].slot
= i
;
3919 slottypes
[row
].slot
= i
;
3922 slottypes
[i
].slottype
= (ieDword
) strtol(st
->QueryField(row
,0),NULL
,0 );
3923 slottypes
[i
].slotid
= (ieDword
) strtol(st
->QueryField(row
,1),NULL
,0 );
3924 strnlwrcpy( slottypes
[i
].slotresref
, st
->QueryField(row
,2), 8 );
3925 slottypes
[i
].slottip
= (ieDword
) strtol(st
->QueryField(row
,3),NULL
,0 );
3926 //don't fill sloteffects for aliased slots (pst)
3930 slottypes
[i
].sloteffects
= (ieDword
) strtol(st
->QueryField(row
,4),NULL
,0 );
3931 //setting special slots
3932 if (slottypes
[i
].slottype
&SLOT_ITEM
) {
3933 if (slottypes
[i
].slottype
&SLOT_INVENTORY
) {
3934 Inventory::SetInventorySlot(i
);
3936 Inventory::SetQuickSlot(i
);
3939 switch (slottypes
[i
].sloteffects
) {
3940 //fist slot, not saved, default weapon
3941 case SLOT_EFFECT_FIST
: Inventory::SetFistSlot(i
); break;
3942 //magic weapon slot, overrides all weapons
3943 case SLOT_EFFECT_MAGIC
: Inventory::SetMagicSlot(i
); break;
3944 //weapon slot, Equipping marker is relative to it
3945 case SLOT_EFFECT_MELEE
: Inventory::SetWeaponSlot(i
); break;
3947 case SLOT_EFFECT_MISSILE
: Inventory::SetRangedSlot(i
); break;
3949 case SLOT_EFFECT_LEFT
: Inventory::SetShieldSlot(i
); break;
3950 //head (for averting critical hit)
3951 case SLOT_EFFECT_HEAD
: Inventory::SetHeadSlot(i
); break;
3959 ieDword
Interface::FindSlot(unsigned int idx
) const
3963 for (i
=0;i
<SlotTypes
;i
++) {
3964 if (idx
==slottypes
[i
].slot
) {
3971 ieDword
Interface::QuerySlot(unsigned int idx
) const
3973 if (idx
>=SlotTypes
) {
3976 return slottypes
[idx
].slot
;
3979 ieDword
Interface::QuerySlotType(unsigned int idx
) const
3981 if (idx
>=SlotTypes
) {
3984 return slottypes
[idx
].slottype
;
3987 ieDword
Interface::QuerySlotID(unsigned int idx
) const
3989 if (idx
>=SlotTypes
) {
3992 return slottypes
[idx
].slotid
;
3995 ieDword
Interface::QuerySlottip(unsigned int idx
) const
3997 if (idx
>=SlotTypes
) {
4000 return slottypes
[idx
].slottip
;
4003 ieDword
Interface::QuerySlotEffects(unsigned int idx
) const
4005 if (idx
>=SlotTypes
) {
4008 return slottypes
[idx
].sloteffects
;
4011 const char *Interface::QuerySlotResRef(unsigned int idx
) const
4013 if (idx
>=SlotTypes
) {
4016 return slottypes
[idx
].slotresref
;
4019 // checks the itemtype vs. slottype, and also checks the usability flags
4020 // vs. Actor's stats (alignment, class, race, kit etc.)
4021 int Interface::CanUseItemType(int slottype
, Item
*item
, Actor
*actor
, bool feedback
, bool equipped
) const
4023 //inventory is a special case, we allow any items to enter it
4024 if ( slottype
==-1 ) {
4025 return SLOT_INVENTORY
;
4027 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
4028 //with twohandedness
4029 //As long as this is an Item, use the ITEM constant
4030 //switch for IE_INV_ITEM_* if it is a CREItem
4031 if (item
->Flags
&IE_ITEM_TWO_HANDED
) {
4032 //if the item is twohanded and there are more slots, drop the shield slot
4033 if (slottype
&~SLOT_SHIELD
) {
4034 slottype
&=~SLOT_SHIELD
;
4036 if (slottype
&SLOT_SHIELD
) {
4037 //cannot equip twohanded in offhand
4038 if (feedback
) displaymsg
->DisplayConstantString(STR_NOT_IN_OFFHAND
, 0xf0f0f0);
4043 if ( (unsigned int) item
->ItemType
>=(unsigned int) ItemTypes
) {
4045 if (feedback
) displaymsg
->DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4049 //if actor is supplied, check its usability fields
4052 int idx
= actor
->Unusable(item
);
4054 if (feedback
) displaymsg
->DisplayConstantString(idx
, 0xf0f0f0);
4058 ieStrRef str
= actor
->Disabled(item
->Name
, item
->ItemType
);
4059 if (str
&& !equipped
) {
4060 if (feedback
) displaymsg
->DisplayString(str
, 0xf0f0f0, 0);
4065 //if any bit is true, the answer counts as true
4066 int ret
= (slotmatrix
[item
->ItemType
]&slottype
);
4069 if (feedback
) displaymsg
->DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4073 //this warning comes only when feedback is enabled
4075 //this was, but that disabled equipping of amber earrings in PST
4076 //if (slotmatrix[item->ItemType]&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4077 if (ret
&(SLOT_QUIVER
|SLOT_WEAPON
|SLOT_ITEM
)) {
4078 //don't ruin the return variable, it contains the usable slot bits
4080 if (ret
&SLOT_QUIVER
) {
4081 if (item
->GetWeaponHeader(true)) flg
= 1;
4084 if (ret
&SLOT_WEAPON
) {
4086 if (item
->GetWeaponHeader(false)) flg
= 1;
4088 if (item
->GetWeaponHeader(true)) flg
= 1;
4091 if (ret
&SLOT_ITEM
) {
4092 if (item
->GetEquipmentHeaderNumber(0)!=0xffff) flg
= 1;
4096 displaymsg
->DisplayConstantString(STR_UNUSABLEITEM
, 0xf0f0f0);
4105 Label
*Interface::GetMessageLabel() const
4107 ieDword WinIndex
= (ieDword
) -1;
4108 ieDword TAIndex
= (ieDword
) -1;
4110 vars
->Lookup( "OtherWindow", WinIndex
);
4111 if (( WinIndex
!= (ieDword
) -1 ) &&
4112 ( vars
->Lookup( "MessageLabel", TAIndex
) )) {
4113 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4115 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4116 if (ctrl
&& ctrl
->ControlType
==IE_GUI_LABEL
)
4117 return (Label
*) ctrl
;
4123 TextArea
*Interface::GetMessageTextArea() const
4125 ieDword WinIndex
= (ieDword
) -1;
4126 ieDword TAIndex
= (ieDword
) -1;
4128 vars
->Lookup( "MessageWindow", WinIndex
);
4129 if (( WinIndex
!= (ieDword
) -1 ) &&
4130 ( vars
->Lookup( "MessageTextArea", TAIndex
) )) {
4131 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4133 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4134 if (ctrl
&& ctrl
->ControlType
==IE_GUI_TEXTAREA
)
4135 return (TextArea
*) ctrl
;
4141 static const char *saved_extensions
[]={".are",".sto",0};
4142 static const char *saved_extensions_last
[]={".tot",".toh",0};
4144 //returns the priority of the file to be saved
4148 int Interface::SavedExtension(const char *filename
)
4150 const char *str
=strchr(filename
,'.');
4153 while(saved_extensions
[i
]) {
4154 if (!stricmp(saved_extensions
[i
], str
) ) return 2;
4158 while(saved_extensions_last
[i
]) {
4159 if (!stricmp(saved_extensions_last
[i
], str
) ) return 1;
4165 static const char *protected_extensions
[]={".exe",".dll",".so",0};
4167 //returns true if file should be saved
4168 bool Interface::ProtectedExtension(const char *filename
)
4170 const char *str
=strchr(filename
,'.');
4171 if (!str
) return false;
4173 while(protected_extensions
[i
]) {
4174 if (!stricmp(protected_extensions
[i
], str
) ) return true;
4180 void Interface::RemoveFromCache(const ieResRef resref
, SClass_ID ClassID
)
4182 char filename
[_MAX_PATH
];
4184 snprintf(filename
, _MAX_PATH
, "%s%.8s%s", CachePath
, resref
, TypeExt( ClassID
) );
4188 //this function checks if the path is eligible as a cache
4189 //if it contains a directory, or suspicious file extensions
4190 //we bail out, because the cache will be purged regularly.
4191 bool Interface::StupidityDetector(const char* Pt
)
4193 char Path
[_MAX_PATH
];
4195 DirectoryIterator
dir(Path
);
4197 printf("\n**cannot open**\n");
4201 const char *name
= dir
.GetName();
4202 if (dir
.IsDirectory()) {
4203 if (name
[0] == '.') {
4204 if (name
[1] == '\0')
4206 if (name
[1] == '.' && name
[2] == '\0')
4209 printf("\n**contains another dir**\n");
4210 return true; //a directory in there???
4212 if (ProtectedExtension(name
) ) {
4213 printf("\n**contains alien files**\n");
4214 return true; //an executable file in there???
4217 //ok, we got a good conscience
4221 void Interface::DelTree(const char* Pt
, bool onlysave
)
4223 char Path
[_MAX_PATH
];
4225 if (!Pt
[0]) return; //Don't delete the root filesystem :)
4227 DirectoryIterator
dir(Path
);
4232 char *name
= dir
.GetName();
4233 if (dir
.IsDirectory())
4237 if (!onlysave
|| SavedExtension(name
) ) {
4238 char dtmp
[_MAX_PATH
];
4239 dir
.GetFullPath(dtmp
);
4245 void Interface::LoadProgress(int percent
)
4247 vars
->SetAt("Progress", percent
);
4248 RedrawControls("Progress", percent
);
4251 video
->SwapBuffers();
4254 void Interface::ReleaseDraggedItem()
4256 DraggedItem
=NULL
; //shouldn't free this
4257 video
->SetDragCursor (NULL
);
4260 void Interface::DragItem(CREItem
*item
, const ieResRef Picture
)
4262 //We should drop the dragged item and pick this up,
4263 //we shouldn't have a valid DraggedItem at this point.
4264 //Anyway, if there is still a dragged item, it will be destroyed.
4266 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW
);
4271 Sprite2D
* DraggedCursor
= NULL
;
4273 DraggedCursor
= gamedata
->GetBAMSprite( Picture
, 0, 0 );
4275 video
->SetDragCursor (DraggedCursor
);
4279 void Interface::SetDraggedPortrait(int dp
, int idx
)
4282 DraggedPortrait
= dp
;
4284 //hmm this might work?
4285 Cursors
[idx
]->acquire();
4286 video
->SetDragCursor(Cursors
[idx
]);
4288 video
->SetDragCursor(NULL
);
4292 bool Interface::ReadItemTable(const ieResRef TableName
, const char * Prefix
)
4297 AutoTable
tab(TableName
);
4301 i
=tab
->GetRowCount();
4304 snprintf(ItemName
,sizeof(ItemName
),"%s%02d",Prefix
, j
+1);
4306 strnlwrcpy(ItemName
,tab
->GetRowName(j
), 8);
4308 //Variable elements are free'd, so we have to use malloc
4309 //well, not anymore, we can use ReleaseFunction
4310 int l
=tab
->GetColumnCount(j
);
4312 int cl
= atoi(tab
->GetColumnName(0));
4313 ItemList
*itemlist
= new ItemList(l
, cl
);
4314 for(int k
=0;k
<l
;k
++) {
4315 strnlwrcpy(itemlist
->ResRefs
[k
],tab
->QueryField(j
,k
), 8);
4317 RtRows
->SetAt(ItemName
, (void*)itemlist
);
4322 bool Interface::ReadRandomItems()
4327 ieDword difflev
=0; //rt norm or rt fury
4328 vars
->Lookup("Nightmare Mode", difflev
);
4330 RtRows
->RemoveAll(ReleaseItemList
);
4333 RtRows
=new Variables(10, 17); //block size, hash table size
4337 RtRows
->SetType( GEM_VARIABLES_POINTER
);
4339 AutoTable
tab("randitem");
4343 if (difflev
>=tab
->GetColumnCount()) {
4344 difflev
= tab
->GetColumnCount()-1;
4348 strnlwrcpy( GoldResRef
, tab
->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4349 if ( GoldResRef
[0]=='*' ) {
4352 strnlwrcpy( RtResRef
, tab
->QueryField( 1, difflev
), 8);
4355 ReadItemTable( RtResRef
, 0 ); //reading the table itself
4362 strnlwrcpy( RtResRef
, tab
->QueryField(2+i
,difflev
), 8);
4363 ReadItemTable( RtResRef
,tab
->GetRowName(2+i
) );
4368 CREItem
*Interface::ReadItem(DataStream
*str
)
4370 CREItem
*itm
= new CREItem();
4372 str
->ReadResRef( itm
->ItemResRef
);
4373 str
->ReadWord( &itm
->Expired
);
4374 str
->ReadWord( &itm
->Usages
[0] );
4375 str
->ReadWord( &itm
->Usages
[1] );
4376 str
->ReadWord( &itm
->Usages
[2] );
4377 str
->ReadDword( &itm
->Flags
);
4378 if (ResolveRandomItem(itm
) ) {
4387 //This function generates random items based on the randitem.2da file
4388 //there could be a loop, but we don't want to freeze, so there is a limit
4389 bool Interface::ResolveRandomItem(CREItem
*itm
)
4391 if (!RtRows
) return true;
4392 for(int loop
=0;loop
<MAX_LOOP
;loop
++) {
4398 if ( !RtRows
->Lookup( itm
->ItemResRef
, lookup
) ) {
4401 ItemList
*itemlist
= (ItemList
*)lookup
;
4402 if (itemlist
->WeightOdds
) {
4403 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4404 i
=Roll(2,(itemlist
->Count
+1)/2,-2);
4406 i
=Roll(1,itemlist
->Count
,-1);
4408 strnlwrcpy( NewItem
, itemlist
->ResRefs
[i
], 8);
4409 char *p
=(char *) strchr(NewItem
,'*');
4411 *p
=0; //doing this so endptr is ok
4412 k
=strtol(p
+1,NULL
,10);
4416 j
=strtol(NewItem
,&endptr
,10);
4421 strnlwrcpy(itm
->ItemResRef
, NewItem
, 8);
4423 strnlwrcpy(itm
->ItemResRef
, GoldResRef
, 8);
4425 if ( !memcmp( itm
->ItemResRef
,"no_drop",8 ) ) {
4426 itm
->ItemResRef
[0]=0;
4428 if (!itm
->ItemResRef
[0]) {
4431 itm
->Usages
[0]=(ieWord
) Roll(j
,k
,0);
4433 printMessage("Interface"," ",LIGHT_RED
);
4434 printf("Loop detected while generating random item:%s\n",itm
->ItemResRef
);
4438 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4439 //these functions are needed because Win32 doesn't allow freeing memory from
4440 //another dll. So we allocate all commonly used memories from core
4441 ITMExtHeader
*Interface::GetITMExt(int count
)
4443 return new ITMExtHeader
[count
];
4446 SPLExtHeader
*Interface::GetSPLExt(int count
)
4448 return new SPLExtHeader
[count
];
4451 Effect
*Interface::GetEffect(ieDword opcode
)
4453 if (opcode
==0xffffffff) {
4456 Effect
*fx
= new Effect();
4460 memset(fx
,0,sizeof(Effect
));
4465 Effect
*Interface::GetFeatures(int count
)
4467 return new Effect
[count
];
4471 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4477 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4484 WorldMapArray
*Interface::NewWorldMapArray(int count
)
4486 return new WorldMapArray(count
);
4489 Container
*Interface::GetCurrentContainer()
4491 return CurrentContainer
;
4494 int Interface::CloseCurrentContainer()
4496 UseContainer
= false;
4497 if ( !CurrentContainer
) {
4500 //remove empty ground piles on closeup
4501 CurrentContainer
->GetCurrentArea()->TMap
->CleanupContainer(CurrentContainer
);
4502 CurrentContainer
= NULL
;
4506 void Interface::SetCurrentContainer(Actor
*actor
, Container
*arg
, bool flag
)
4508 //abort action if the first selected PC isn't the original actor
4509 if (actor
!=GetFirstSelectedPC(false)) {
4510 CurrentContainer
= NULL
;
4513 CurrentContainer
= arg
;
4514 UseContainer
= flag
;
4517 Store
*Interface::GetCurrentStore()
4519 return CurrentStore
;
4522 int Interface::CloseCurrentStore()
4524 if ( !CurrentStore
) {
4527 PluginHolder
<StoreMgr
> sm(IE_STO_CLASS_ID
);
4531 int size
= sm
->GetStoredFileSize (CurrentStore
);
4533 //created streams are always autofree (close file on destruct)
4534 //this one will be destructed when we return from here
4537 str
.Create( CurrentStore
->Name
, IE_STO_CLASS_ID
);
4538 int ret
= sm
->PutStore (&str
, CurrentStore
);
4540 printMessage("Core"," ", YELLOW
);
4541 printf("Store removed: %s\n", CurrentStore
->Name
);
4542 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4545 printMessage("Core"," ", YELLOW
);
4546 printf("Store removed: %s\n", CurrentStore
->Name
);
4547 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4549 //make sure the stream isn't connected to sm, or it will be double freed
4550 delete CurrentStore
;
4551 CurrentStore
= NULL
;
4555 Store
*Interface::SetCurrentStore(const ieResRef resname
, const ieVariable owner
)
4557 if ( CurrentStore
) {
4558 if ( !strnicmp(CurrentStore
->Name
, resname
, 8) ) {
4559 return CurrentStore
;
4562 //not simply delete the old store, but save it
4563 CloseCurrentStore();
4566 DataStream
* str
= gamedata
->GetResource( resname
, IE_STO_CLASS_ID
);
4567 PluginHolder
<StoreMgr
> sm(IE_STO_CLASS_ID
);
4572 if (!sm
->Open( str
, true )) {
4576 // FIXME - should use some already allocated in core
4577 // not really, only one store is open at a time, then it is
4578 // unloaded, we don't really have to cache it, it will be saved in
4580 CurrentStore
= sm
->GetStore( new Store() );
4581 if (CurrentStore
== NULL
) {
4584 strnlwrcpy(CurrentStore
->Name
, resname
, 8);
4586 CurrentStore
->SetOwner(owner
);
4588 return CurrentStore
;
4591 void Interface::SetMouseScrollSpeed(int speed
) {
4592 mousescrollspd
= (speed
+1)*2;
4595 int Interface::GetMouseScrollSpeed() {
4596 return mousescrollspd
;
4599 ieStrRef
Interface::GetRumour(const ieResRef dlgref
)
4601 PluginHolder
<DialogMgr
> dm(IE_DLG_CLASS_ID
);
4602 dm
->Open( gamedata
->GetResource( dlgref
, IE_DLG_CLASS_ID
), true );
4603 Dialog
*dlg
= dm
->GetDialog();
4606 printMessage("Interface"," ", LIGHT_RED
);
4607 printf( "Cannot load dialog: %s\n", dlgref
);
4608 return (ieStrRef
) -1;
4610 Scriptable
*pc
=game
->GetPC( game
->GetSelectedPCSingle(), false );
4612 ieStrRef ret
= (ieStrRef
) -1;
4613 int i
= dlg
->FindRandomState( pc
);
4615 ret
= dlg
->GetState( i
)->StrRef
;
4621 void Interface::DoTheStoreHack(Store
*s
)
4623 size_t size
= s
->PurchasedCategoriesCount
* sizeof( ieDword
);
4624 s
->purchased_categories
=(ieDword
*) malloc(size
);
4626 size
= s
->CuresCount
* sizeof( STOCure
);
4627 s
->cures
=(STOCure
*) malloc(size
);
4629 size
= s
->DrinksCount
* sizeof( STODrink
);
4630 s
->drinks
=(STODrink
*) malloc(size
);
4632 for(size
=0;size
<s
->ItemsCount
;size
++) {
4633 STOItem
*si
= new STOItem();
4634 memset(si
, 0, sizeof(STOItem
) );
4635 s
->items
.push_back( si
);
4639 //plays stock sound listed in defsound.2da
4640 void Interface::PlaySound(int index
)
4642 if (index
<=DSCount
) {
4643 AudioDriver
->Play(DefSound
[index
]);
4647 Actor
*Interface::GetFirstSelectedPC(bool forced
)
4649 int partySize
= game
->GetPartySize( false );
4650 if (!partySize
) return NULL
;
4651 for (int i
= 0; i
< partySize
; i
++) {
4652 Actor
* actor
= game
->GetPC( i
,false );
4653 if (actor
->IsSelected()) {
4659 return game
->GetPC(0,false);
4664 //this is used only for the console
4665 Sprite2D
*Interface::GetCursorSprite()
4667 Sprite2D
*spr
= gamedata
->GetBAMSprite(CursorBam
, 0, 0);
4670 if(HasFeature(GF_OVERRIDE_CURSORPOS
))
4673 spr
->YPos
=spr
->Height
-1;
4679 Sprite2D
*Interface::GetScrollCursorSprite(int frameNum
, int spriteNum
)
4681 return gamedata
->GetBAMSprite(ScrollCursorBam
, frameNum
, spriteNum
);
4684 /* we should return -1 if it isn't gold, otherwise return the gold value */
4685 int Interface::CanMoveItem(const CREItem
*item
) const
4687 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4688 if (item
->Flags
& IE_INV_ITEM_UNDROPPABLE
)
4690 //not gold, we allow only one single coin ResRef, this is good
4691 //for all of the original games
4692 if (strnicmp(item
->ItemResRef
, GoldResRef
, 8 ) )
4694 //gold, returns the gold value (stack size)
4695 return item
->Usages
[0];
4698 // dealing with applying effects
4699 void Interface::ApplySpell(const ieResRef resname
, Actor
*actor
, Scriptable
*caster
, int level
)
4701 Spell
*spell
= gamedata
->GetSpell(resname
);
4706 level
= spell
->GetHeaderIndexFromLevel(level
);
4707 EffectQueue
*fxqueue
= spell
->GetEffectBlock(caster
, actor
->Pos
, level
);
4709 //check effect immunities
4710 int res
= fxqueue
->CheckImmunity ( actor
);
4713 //bounced back at a nonliving caster
4714 if (caster
->Type
!=ST_ACTOR
) {
4718 actor
= (Actor
*) caster
;
4720 fxqueue
->SetOwner( caster
);
4721 fxqueue
->AddAllEffects(actor
, actor
->Pos
);
4726 void Interface::ApplySpellPoint(const ieResRef resname
, Map
* area
, const Point
&pos
, Scriptable
*caster
, int level
)
4728 Spell
*spell
= gamedata
->GetSpell(resname
);
4732 level
= spell
->GetHeaderIndexFromLevel(level
);
4733 Projectile
*pro
= spell
->GetProjectile(caster
, level
, pos
);
4734 pro
->SetCaster(caster
->GetGlobalID());
4735 area
->AddProjectile(pro
, caster
->Pos
, pos
);
4738 //-1 means the effect was reflected back to the caster
4739 //0 means the effect was resisted and should be removed
4740 //1 means the effect was applied
4741 int Interface::ApplyEffect(Effect
*effect
, Actor
*actor
, Scriptable
*caster
)
4747 EffectQueue
*fxqueue
= new EffectQueue();
4748 //AddEffect now copies the fx data, please delete your effect reference
4749 //if you created it. (Don't delete cached references)
4750 fxqueue
->AddEffect( effect
);
4752 int res
= fxqueue
->CheckImmunity ( actor
);
4755 //bounced back at a nonliving caster
4756 if (caster
->Type
!=ST_ACTOR
) {
4760 actor
= (Actor
*) caster
;
4762 fxqueue
->SetOwner( caster
);
4765 p
.empty(); //the effect should have all its coordinates already set
4766 if (fxqueue
->AddAllEffects( actor
, p
)==FX_NOT_APPLIED
) {
4774 Effect
*Interface::GetEffect(const ieResRef resname
, int level
, const Point
&p
)
4776 //Don't free this reference, it is cached!
4777 Effect
*effect
= gamedata
->GetEffect(resname
);
4784 effect
->Power
= level
;
4790 // dealing with saved games
4791 int Interface::SwapoutArea(Map
*map
)
4793 PluginHolder
<MapMgr
> mm(IE_ARE_CLASS_ID
);
4797 int size
= mm
->GetStoredFileSize (map
);
4799 //created streams are always autofree (close file on destruct)
4800 //this one will be destructed when we return from here
4803 str
.Create( map
->GetScriptName(), IE_ARE_CLASS_ID
);
4804 int ret
= mm
->PutArea (&str
, map
);
4806 printMessage("Core"," ", YELLOW
);
4807 printf("Area removed: %s\n", map
->GetScriptName());
4808 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4811 printMessage("Core"," ", YELLOW
);
4812 printf("Area removed: %s\n", map
->GetScriptName());
4813 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4815 //make sure the stream isn't connected to sm, or it will be double freed
4819 int Interface::WriteCharacter(const char *name
, Actor
*actor
)
4821 char Path
[_MAX_PATH
];
4823 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
4827 PluginHolder
<ActorMgr
> gm(IE_CRE_CLASS_ID
);
4836 str
.Create( Path
, name
, IE_CHR_CLASS_ID
);
4838 int ret
= gm
->PutActor(&str
, actor
, true);
4840 printMessage("Core"," ", YELLOW
);
4841 printf("Character cannot be saved: %s\n", name
);
4846 //write the BIO string
4847 if (!HasFeature(GF_NO_BIOGRAPHY
)) {
4850 str
.Create( Path
, name
, IE_BIO_CLASS_ID
);
4851 //never write the string reference into this string
4852 char *tmp
= GetString(actor
->GetVerbalConstant(VB_BIO
),IE_STR_STRREFOFF
);
4853 str
.Write (tmp
, strlen(tmp
));
4859 int Interface::WriteGame(const char *folder
)
4861 PluginHolder
<SaveGameMgr
> gm(IE_GAM_CLASS_ID
);
4866 int size
= gm
->GetStoredFileSize (game
);
4868 //created streams are always autofree (close file on destruct)
4869 //this one will be destructed when we return from here
4872 str
.Create( folder
, GameNameResRef
, IE_GAM_CLASS_ID
);
4873 int ret
= gm
->PutGame (&str
, game
);
4875 printMessage("Core"," ", YELLOW
);
4876 printf("Game cannot be saved: %s\n", GameNameResRef
);
4879 printMessage("Core"," ", YELLOW
);
4880 printf("Internal error, game cannot be saved: %s\n", GameNameResRef
);
4882 //make sure the stream isn't connected to sm, or it will be double freed
4886 int Interface::WriteWorldMap(const char *folder
)
4888 PluginHolder
<WorldMapMgr
> wmm(IE_WMP_CLASS_ID
);
4893 int size
= wmm
->GetStoredFileSize (worldmap
);
4895 //created streams are always autofree (close file on destruct)
4896 //this one will be destructed when we return from here
4899 str
.Create( folder
, WorldMapName
, IE_WMP_CLASS_ID
);
4900 int ret
= wmm
->PutWorldMap (&str
, worldmap
);
4902 printMessage("Core"," ", YELLOW
);
4903 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
4906 printMessage("Core"," ", YELLOW
);
4907 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
4909 //make sure the stream isn't connected to sm, or it will be double freed
4913 int Interface::CompressSave(const char *folder
)
4917 str
.Create( folder
, GameNameResRef
, IE_SAV_CLASS_ID
);
4918 DirectoryIterator
dir(CachePath
);
4922 //BIF and SAV are the same
4923 PluginHolder
<ArchiveImporter
> ai(IE_BIF_CLASS_ID
);
4924 ai
->CreateArchive( &str
);
4926 //.tot and .toh should be saved last, because they are updated when an .are is saved
4930 const char *name
= dir
.GetName();
4931 if (dir
.IsDirectory())
4935 if (SavedExtension(name
)==priority
) {
4936 char dtmp
[_MAX_PATH
];
4937 dir
.GetFullPath(dtmp
);
4939 fs
.Open(dtmp
, true);
4940 ai
->AddToSaveGame(&str
, &fs
);
4943 //reopen list for the second round
4952 int Interface::GetMaximumAbility() const { return MaximumAbility
; }
4954 int Interface::GetStrengthBonus(int column
, int value
, int ex
) const
4956 //to hit, damage, open doors, weight allowance
4957 if (column
<0 || column
>3)
4970 return strmod
[column
*(MaximumAbility
+1)+value
]+strmodex
[column
*101+ex
];
4973 //only the first 3 columns are supported
4974 int Interface::GetIntelligenceBonus(int column
, int value
) const
4976 //learn spell, max spell level, max spell number on level
4977 if (column
<0 || column
>2)
4980 return intmod
[column
*(MaximumAbility
+1)+value
];
4983 int Interface::GetDexterityBonus(int column
, int value
) const
4985 //reaction, missile, ac
4986 if (column
<0 || column
>2)
4989 //no dexmod in iwd2???
4990 if (HasFeature(GF_3ED_RULES
)) return 0;
4992 return dexmod
[column
*(MaximumAbility
+1)+value
];
4995 int Interface::GetConstitutionBonus(int column
, int value
) const
4997 //normal, warrior, minimum, regen hp, regen fatigue
4998 if (column
<0 || column
>4)
5001 return conmod
[column
*(MaximumAbility
+1)+value
];
5004 int Interface::GetCharismaBonus(int column
, int value
) const
5007 if (column
<0 || column
>0)
5010 return chrmod
[column
*(MaximumAbility
+1)+value
];
5013 int Interface::GetLoreBonus(int column
, int value
) const
5015 if (column
<0 || column
>0)
5018 //no lorebon in iwd2???
5019 if (HasFeature(GF_3ED_RULES
)) return 0;
5021 return lorebon
[value
];
5024 int Interface::GetWisdomBonus(int column
, int value
) const
5027 if (column
<0 || column
>0)
5030 if (!HasFeature(GF_WISDOM_BONUS
)) return 0;
5032 return wisbon
[value
];
5035 int Interface::GetReputationMod(int column
) const
5037 int reputation
= game
->Reputation
/ 10 - 1;
5039 if (column
<0 || column
>8) {
5042 if (reputation
> 19) {
5045 if (reputation
< 0) {
5049 return reputationmod
[reputation
][column
];
5052 // -3, -2 if request is illegal or in cutscene
5053 // -1 if pause is already active
5054 // 0 if pause was not allowed
5055 // 1 if autopause happened
5056 int Interface::Autopause(ieDword flag
)
5058 GameControl
*gc
= GetGameControl();
5062 if (InCutSceneMode()) {
5065 if (gc
->GetDialogueFlags()&DF_FREEZE_SCRIPTS
) {
5068 ieDword autopause_flags
= 0;
5070 vars
->Lookup("Auto Pause State", autopause_flags
);
5071 if (autopause_flags
& (1<<flag
)) {
5072 displaymsg
->DisplayConstantString(STR_AP_UNUSABLE
+flag
, 0xff0000);
5073 gc
->SetDialogueFlags(DF_FREEZE_SCRIPTS
, BM_OR
);
5079 void Interface::RegisterOpcodes(int count
, const EffectRef
*opcodes
)
5081 EffectQueue_RegisterOpcodes(count
, opcodes
);
5084 void Interface::SetInfoTextColor(const Color
&color
)
5086 if (InfoTextPalette
) {
5087 gamedata
->FreePalette(InfoTextPalette
);
5089 InfoTextPalette
= CreatePalette(color
, black
);
5093 void Interface::GetResRefFrom2DA(const ieResRef resref
, ieResRef resource1
, ieResRef resource2
, ieResRef resource3
)
5105 AutoTable
tab(resref
);
5107 unsigned int cols
= tab
->GetColumnCount();
5108 unsigned int row
= (unsigned int) Roll(1,tab
->GetRowCount(),-1);
5109 strnuprcpy(resource1
, tab
->QueryField(row
,0), 8);
5110 if (resource2
&& cols
>1)
5111 strnuprcpy(resource2
, tab
->QueryField(row
,1), 8);
5112 if (resource3
&& cols
>2)
5113 strnuprcpy(resource3
, tab
->QueryField(row
,2), 8);
5117 ieDword
*Interface::GetListFrom2DA(const ieResRef resref
)
5121 AutoTable
tab(resref
);
5123 ieDword cnt
= tab
->GetRowCount();
5124 ret
= (ieDword
*) malloc((1+cnt
)*sizeof(ieDword
));
5127 ret
[cnt
]=strtol(tab
->QueryField(cnt
-1, 0),NULL
, 0);
5132 ret
= (ieDword
*) malloc(sizeof(ieDword
));
5137 //returns a numeric value associated with a stat name (symbol) from stats.ids
5138 ieDword
Interface::TranslateStat(const char *stat_name
)
5142 if (valid_number(stat_name
, tmp
)) {
5143 return (ieDword
) tmp
;
5146 int symbol
= LoadSymbol( "stats" );
5147 Holder
<SymbolMgr
> sym
= GetSymbol( symbol
);
5148 ieDword stat
= (ieDword
) sym
->GetValue( stat_name
);
5149 if (stat
==(ieDword
) ~0) {
5150 printMessage("Core"," ",YELLOW
);
5151 printf("Cannot translate symbol: %s\n", stat_name
);
5156 void Interface::WaitForDisc(int disc_number
, const char* path
)
5158 GetDictionary()->SetAt( "WaitForDisc", (ieDword
) disc_number
);
5160 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5163 for (size_t i
=0;i
<CD
[disc_number
-1].size();i
++) {
5164 char name
[_MAX_PATH
];
5166 PathJoin(name
, CD
[disc_number
-1][i
].c_str(),path
,NULL
);
5167 if (file_exists (name
)) {
5168 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5173 } while (video
->SwapBuffers() == GEM_OK
);
5176 // remove the extraneus EOL newline and carriage return
5177 void Interface::StripLine(char * string
, size_t size
) {
5178 if (size
>= 2 && string
[size
-2] == '\n') {
5179 string
[size
-2] = '\0';
5181 if (size
>= 3 && string
[size
-3] == '\r') {
5182 string
[size
-3] = '\0'; // remove the carriage return too
5186 void Interface::SetNextScript(const char *script
)
5188 strncpy( NextScript
, script
, sizeof(NextScript
) );
5189 QuitFlag
|= QF_CHANGESCRIPT
;
5192 void Interface::SanityCheck(const char *ver
) {
5193 if (strcmp(ver
, VERSION_GEMRB
)) {
5194 printf("version check failed: core version %s doesn't match caller's version %s\n", VERSION_GEMRB
, ver
);