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"
76 #if defined(__HAIKU__)
84 GEM_EXPORT Interface
* core
;
87 GEM_EXPORT HANDLE hConsole
;
90 //use DialogF.tlk if the protagonist is female, that's why we leave space
91 static const char dialogtlk
[] = "dialog.tlk\0";
93 static int MaximumAbility
= 25;
94 static ieWordSigned
*strmod
= NULL
;
95 static ieWordSigned
*strmodex
= NULL
;
96 static ieWordSigned
*intmod
= NULL
;
97 static ieWordSigned
*dexmod
= NULL
;
98 static ieWordSigned
*conmod
= NULL
;
99 static ieWordSigned
*chrmod
= NULL
;
100 static ieWordSigned
*lorebon
= NULL
;
101 static ieWordSigned
*wisbon
= NULL
;
102 static int **reputationmod
= NULL
;
103 static ieVariable IWD2DeathVarFormat
= "_DEAD%s";
104 static ieVariable DeathVarFormat
= "SPRITE_IS_DEAD%s";
106 Interface::Interface(int iargc
, char* iargv
[])
111 hConsole
= GetStdHandle( STD_OUTPUT_HANDLE
);
113 textcolor( LIGHT_WHITE
);
114 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB
);
116 // default to the correct endianswitch
117 ieWord endiantest
= 1;
118 if (((char *)&endiantest
)[1] == 1) {
120 DataStream::SetEndianSwitch(true);
125 pl_uppercase
[i
]=(ieByte
) toupper(i
);
126 pl_lowercase
[i
]=(ieByte
) tolower(i
);
130 VideoDriverName
= "sdl";
131 AudioDriverName
= "openal";
141 CurrentContainer
= NULL
;
142 UseContainer
= false;
143 InfoTextPalette
= NULL
;
154 tooltip_currtextw
= 0;
169 ConsolePopped
= false;
172 QuitFlag
= QF_NORMAL
;
173 EventFlag
= EF_CONTROL
;
175 CaseSensitive
= true; //this is the default value, so CD1/CD2 will be resolved
177 CaseSensitive
= false;
180 SkipIntroVideos
= false;
184 GUIScriptsPath
[0] = 0;
190 GemRBOverridePath
[0] = 0;
193 strncpy( GameOverridePath
, "override", sizeof(GameOverridePath
) );
194 strncpy( GameSoundsPath
, "sounds", sizeof(GameSoundsPath
) );
195 strncpy( GameScriptsPath
, "scripts", sizeof(GameScriptsPath
) );
196 strncpy( GamePortraitsPath
, "portraits", sizeof(GamePortraitsPath
) );
197 strncpy( GameCharactersPath
, "characters", sizeof(GameCharactersPath
) );
198 strncpy( GameDataPath
, "data", sizeof(GameDataPath
) );
199 strncpy( INIConfig
, "baldur.ini", sizeof(INIConfig
) );
200 strncpy( ButtonFont
, "STONESML", sizeof(ButtonFont
) );
201 strncpy( TooltipFont
, "STONESML", sizeof(TooltipFont
) );
202 strncpy( MovieFont
, "STONESML", sizeof(MovieFont
) );
203 strncpy( ScrollCursorBam
, "CURSARW", sizeof(ScrollCursorBam
) );
204 strncpy( GlobalScript
, "BALDUR", sizeof(GlobalScript
) );
205 strncpy( WorldMapName
[0], "WORLDMAP", sizeof(ieResRef
) );
206 memset( WorldMapName
[1], 0, sizeof(ieResRef
) );
207 strncpy( Palette16
, "MPALETTE", sizeof(Palette16
) );
208 strncpy( Palette32
, "PAL32", sizeof(Palette32
) );
209 strncpy( Palette256
, "MPAL256", sizeof(Palette256
) );
210 strcpy( TooltipBackResRef
, "\0" );
211 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
212 strcpy( GroundCircleBam
[size
], "\0" );
213 GroundCircleScale
[size
] = 0;
216 TooltipColor
.g
= 255;
218 TooltipColor
.a
= 255;
226 memset(GameFeatures
, 0, sizeof( GameFeatures
));
229 memset( WindowFrames
, 0, sizeof( WindowFrames
));
230 memset( GroundCircles
, 0, sizeof( GroundCircles
));
231 memset(FogSprites
, 0, sizeof( FogSprites
));
232 AreaAliasTable
= NULL
;
233 ItemExclTable
= NULL
;
234 ItemDialTable
= NULL
;
235 ItemDial2Table
= NULL
;
236 ItemTooltipTable
= NULL
;
237 update_scripts
= false;
239 gamedata
= new GameData();
242 #define FreeResourceVector(type, variable) \
244 size_t i=variable.size(); \
247 delete variable[i]; \
253 //2da lists are ieDword lists allocated by malloc
254 static void Release2daList(void *poi
)
256 free( (ieDword
*) poi
);
259 static void ReleaseItemList(void *poi
)
261 delete ((ItemList
*) poi
);
264 void FreeAbilityTables()
300 void Interface::FreeResRefTable(ieResRef
*&table
, int &count
)
308 static void ReleaseItemTooltip(void *poi
)
313 Interface::~Interface(void)
316 delete AreaAliasTable
;
321 // stop any ambients which are still enqueued
323 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
324 if (ambim
) ambim
->deactivate();
326 //destroy the highest objects in the hierarchy first!
334 for (unsigned int i
=0; i
<20; i
++) {
335 if (reputationmod
[i
]) {
336 free(reputationmod
[i
]);
343 PluginMgr::Get()->RunCleanup();
345 ReleaseMemoryActor();
346 EffectQueue_ReleaseMemory();
347 CharAnimations::ReleaseMemory();
350 FreeResRefTable(DefSound
, DSCount
);
358 for (int i
= 0; i
< CursorCount
; i
++) {
359 video
->FreeSprite( Cursors
[i
] );
364 FreeResourceVector( Font
, fonts
);
365 FreeResourceVector( Window
, windows
);
368 for (i
= 0; i
< musiclist
.size(); i
++) {
369 free((void *)musiclist
[i
]);
372 DamageInfoMap
.clear();
391 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
392 video
->FreeSprite(FogSprites
[i
]);
396 video
->FreeSprite(WindowFrames
[i
]);
399 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
401 video
->FreeSprite(GroundCircles
[size
][i
]);
407 //freesprite checks for null pointer
408 video
->FreeSprite(TooltipBack
[i
]);
410 delete[] TooltipBack
;
412 if (InfoTextPalette
) {
413 gamedata
->FreePalette(InfoTextPalette
);
416 video
->SetDragCursor(NULL
);
424 lists
->RemoveAll(Release2daList
);
429 RtRows
->RemoveAll(ReleaseItemList
);
433 ItemExclTable
->RemoveAll(NULL
);
434 delete ItemExclTable
;
437 ItemDialTable
->RemoveAll(NULL
);
438 delete ItemDialTable
;
440 if (ItemDial2Table
) {
441 ItemDial2Table
->RemoveAll(NULL
);
442 delete ItemDial2Table
;
444 if (ItemTooltipTable
) {
445 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
446 delete ItemTooltipTable
;
449 Map::ReleaseMemory();
450 Actor::ReleaseMemory();
452 gamedata
->ClearCaches();
456 // Removing all stuff from Cache, except bifs
457 if (!KeepCache
) DelTree((const char *) CachePath
, true);
460 void Interface::SetWindowFrame(int i
, Sprite2D
*Picture
)
462 video
->FreeSprite(WindowFrames
[i
]);
463 WindowFrames
[i
]=Picture
;
466 GameControl
* Interface::StartGameControl()
468 //making sure that our window is the first one
472 DelAllWindows();//deleting ALL windows
473 gamedata
->DelTable(0xffffu
); //dropping ALL tables
474 Window
* gamewin
= new Window( 0xffff, 0, 0, (ieWord
) Width
, (ieWord
) Height
);
475 gamewin
->WindowPack
[0]=0;
476 GameControl
* gc
= new GameControl();
479 gc
->Width
= (ieWord
) Width
;
480 gc
->Height
= (ieWord
) Height
;
482 gc
->ControlID
= 0x00000000;
483 gc
->ControlType
= IE_GUI_GAMECONTROL
;
484 gamewin
->AddControl( gc
);
485 AddWindow( gamewin
);
486 SetVisible( 0, WINDOW_VISIBLE
);
487 //setting the focus to the game control
488 evntmgr
->SetFocused(gamewin
, gc
);
489 if (guiscript
->LoadScript( "MessageWindow" )) {
490 guiscript
->RunFunction( "MessageWindow", "OnLoad" );
497 /* handle main loop events that might destroy or create windows
498 thus cannot be called from DrawWindows directly
499 these events are pending until conditions are right
501 void Interface::HandleEvents()
503 GameControl
*gc
= GetGameControl();
504 if (gc
&& (!gc
->Owner
|| !gc
->Owner
->Visible
)) {
508 if (EventFlag
&EF_SELECTION
) {
509 EventFlag
&=~EF_SELECTION
;
510 guiscript
->RunFunction( "GUICommonWindows", "SelectionChanged", false);
513 if (EventFlag
&EF_UPDATEANIM
) {
514 EventFlag
&=~EF_UPDATEANIM
;
515 guiscript
->RunFunction( "GUICommonWindows", "UpdateAnimation", false);
518 if (EventFlag
&EF_PORTRAIT
) {
519 ieDword tmp
= (ieDword
) ~0;
520 vars
->Lookup( "PortraitWindow", tmp
);
521 if (tmp
!= (ieDword
) ~0) {
522 EventFlag
&=~EF_PORTRAIT
;
523 guiscript
->RunFunction( "GUICommonWindows", "UpdatePortraitWindow" );
527 if (EventFlag
&EF_ACTION
) {
528 ieDword tmp
= (ieDword
) ~0;
529 vars
->Lookup( "ActionsWindow", tmp
);
530 if (tmp
!= (ieDword
) ~0) {
531 EventFlag
&=~EF_ACTION
;
532 guiscript
->RunFunction( "GUICommonWindows", "UpdateActionsWindow" );
536 if ((EventFlag
&EF_CONTROL
) && gc
) {
537 EventFlag
&=~EF_CONTROL
;
538 guiscript
->RunFunction( "MessageWindow", "UpdateControlStatus" );
539 //this is the only value we can use here
540 if (game
->ControlStatus
& CS_HIDEGUI
)
546 if ((EventFlag
&EF_SHOWMAP
) && gc
) {
547 ieDword tmp
= (ieDword
) ~0;
548 vars
->Lookup( "OtherWindow", tmp
);
549 if (tmp
== (ieDword
) ~0) {
550 EventFlag
&= ~EF_SHOWMAP
;
551 guiscript
->RunFunction( "GUIMA", "ShowMap" );
556 if (EventFlag
&EF_SEQUENCER
) {
557 EventFlag
&=~EF_SEQUENCER
;
558 guiscript
->RunFunction( "GUIMG", "OpenSequencerWindow" );
562 if (EventFlag
&EF_IDENTIFY
) {
563 EventFlag
&=~EF_IDENTIFY
;
564 // FIXME: Implement this.
565 guiscript
->RunFunction( "GUICommonWindows", "OpenIdentifyWindow" );
568 if (EventFlag
&EF_OPENSTORE
) {
569 EventFlag
&=~EF_OPENSTORE
;
570 guiscript
->RunFunction( "GUISTORE", "OpenStoreWindow" );
574 if (EventFlag
&EF_EXPANSION
) {
575 EventFlag
&=~EF_EXPANSION
;
576 guiscript
->RunFunction( "MessageWindow", "GameExpansion", false );
581 /* handle main loop events that might destroy or create windows
582 thus cannot be called from DrawWindows directly
584 void Interface::HandleFlags()
586 //clear events because the context changed
587 EventFlag
= EF_CONTROL
;
589 if (QuitFlag
&(QF_QUITGAME
|QF_EXITGAME
) ) {
590 // when reaching this, quitflag should be 1 or 2
591 // if Exitgame was set, we'll set Start.py too
592 QuitGame (QuitFlag
&QF_EXITGAME
);
593 QuitFlag
&= ~(QF_QUITGAME
|QF_EXITGAME
);
596 if (QuitFlag
&QF_LOADGAME
) {
597 QuitFlag
&= ~QF_LOADGAME
;
598 LoadGame(LoadGameIndex
.get(), VersionOverride
);
599 LoadGameIndex
.release();
600 //after loading a game, always check if the game needs to be upgraded
603 if (QuitFlag
&QF_ENTERGAME
) {
604 QuitFlag
&= ~QF_ENTERGAME
;
606 EventFlag
|=EF_EXPANSION
;
609 //rearrange party slots
610 game
->ConsolidateParty();
611 GameControl
* gc
= StartGameControl();
612 //switch map to protagonist
613 Actor
* actor
= GetFirstSelectedPC(true);
615 gc
->ChangeMap(actor
, true);
618 printMessage("Core", "No game to enter...\n", LIGHT_RED
);
619 QuitFlag
= QF_QUITGAME
;
623 if (QuitFlag
&QF_CHANGESCRIPT
) {
624 QuitFlag
&= ~QF_CHANGESCRIPT
;
625 guiscript
->LoadScript( NextScript
);
626 guiscript
->RunFunction( NextScript
, "OnLoad" );
630 bool GenerateAbilityTables()
634 //range is: 0 - maximumability
635 int tablesize
= MaximumAbility
+1;
636 strmod
= (ieWordSigned
*) malloc (tablesize
* 4 * sizeof(ieWordSigned
) );
639 strmodex
= (ieWordSigned
*) malloc (101 * 4 * sizeof(ieWordSigned
) );
642 intmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
645 dexmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
648 conmod
= (ieWordSigned
*) malloc (tablesize
* 5 * sizeof(ieWordSigned
) );
651 chrmod
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
654 lorebon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
657 wisbon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
663 bool Interface::ReadAbilityTable(const ieResRef tablename
, ieWordSigned
*mem
, int columns
, int rows
)
665 AutoTable
tab(tablename
);
669 //this is a hack for rows not starting at 0 in some cases
671 const char * tmp
= tab
->GetRowName(0);
672 if (tmp
&& (tmp
[0]!='0')) {
674 for (int i
=0;i
<fix
;i
++) {
675 for (int j
=0;j
<columns
;j
++) {
676 mem
[rows
*j
+i
]=(ieWordSigned
) strtol(tab
->QueryField(0,j
),NULL
,0 );
680 for (int j
=0;j
<columns
;j
++) {
681 for( int i
=0;i
<rows
-fix
;i
++) {
682 mem
[rows
*j
+i
+fix
] = (ieWordSigned
) strtol(tab
->QueryField(i
,j
),NULL
,0 );
688 bool Interface::ReadAbilityTables()
690 bool ret
= GenerateAbilityTables();
693 ret
= ReadAbilityTable("strmod", strmod
, 4, MaximumAbility
+ 1);
696 ret
= ReadAbilityTable("strmodex", strmodex
, 4, 101);
697 //3rd ed doesn't have strmodex, but has a maximum of 40
698 if (!ret
&& (MaximumAbility
<=25) )
700 ret
= ReadAbilityTable("intmod", intmod
, 3, MaximumAbility
+ 1);
703 ret
= ReadAbilityTable("hpconbon", conmod
, 5, MaximumAbility
+ 1);
706 if (!HasFeature(GF_3ED_RULES
)) {
707 //no lorebon in iwd2???
708 ret
= ReadAbilityTable("lorebon", lorebon
, 1, MaximumAbility
+ 1);
711 //no dexmod in iwd2???
712 ret
= ReadAbilityTable("dexmod", dexmod
, 3, MaximumAbility
+ 1);
716 //this table is a single row (not a single column)
717 ret
= ReadAbilityTable("chrmodst", chrmod
, MaximumAbility
+ 1, 1);
720 if (HasFeature(GF_WISDOM_BONUS
)) {
721 ret
= ReadAbilityTable("wisxpbon", wisbon
, 1, MaximumAbility
+ 1);
728 bool Interface::ReadGameTimeTable()
730 AutoTable
table("gametime");
735 Time
.round_sec
= atoi(table
->QueryField("ROUND_SECONDS", "DURATION"));
736 Time
.turn_sec
= atoi(table
->QueryField("TURN_SECONDS", "DURATION"));
737 Time
.round_size
= Time
.round_sec
* AI_UPDATE_TIME
;
738 Time
.rounds_per_turn
= Time
.turn_sec
/ Time
.round_sec
;
743 bool Interface::ReadAuxItemTables()
750 ItemExclTable
->RemoveAll(NULL
);
752 ItemExclTable
= new Variables();
753 ItemExclTable
->SetType(GEM_VARIABLES_INT
);
755 table
= gamedata
->LoadTable( "itemexcl" );
759 //don't report error when the file doesn't exist
760 if (aa
.load("itemexcl")) {
761 idx
= aa
->GetRowCount();
765 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
766 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
767 ItemExclTable
->SetAt(key
, value
);
771 ItemDialTable
->RemoveAll(NULL
);
773 ItemDialTable
= new Variables();
774 ItemDialTable
->SetType(GEM_VARIABLES_INT
);
776 if (ItemDial2Table
) {
777 ItemDial2Table
->RemoveAll(NULL
);
779 ItemDial2Table
= new Variables();
780 ItemDial2Table
->SetType(GEM_VARIABLES_STRING
);
783 //don't report error when the file doesn't exist
784 if (aa
.load("itemdial")) {
785 idx
= aa
->GetRowCount();
787 ieResRef key
, dlgres
;
789 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
790 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
791 ItemDialTable
->SetAt(key
, value
);
792 strnlwrcpy(dlgres
,aa
->QueryField(idx
,1),8);
793 ItemDial2Table
->SetAtCopy(key
, dlgres
);
797 if (ItemTooltipTable
) {
798 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
800 ItemTooltipTable
= new Variables();
801 ItemTooltipTable
->SetType(GEM_VARIABLES_POINTER
);
804 //don't report error when the file doesn't exist
805 if (aa
.load("tooltip")) {
806 idx
= aa
->GetRowCount();
809 int *tmppoi
= (int *) malloc(sizeof(int)*3);
811 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
812 for (int i
=0;i
<3;i
++) {
813 tmppoi
[i
] = atoi(aa
->QueryField(idx
,i
));
815 ItemTooltipTable
->SetAt(key
, (void*)tmppoi
);
822 const char *Interface::GetDeathVarFormat()
824 return DeathVarFormat
;
827 int Interface::GetItemExcl(const ieResRef itemname
) const
831 if (ItemExclTable
&& ItemExclTable
->Lookup(itemname
, value
)) {
837 int Interface::GetItemTooltip(const ieResRef itemname
, int header
, int identified
)
841 if (ItemTooltipTable
) {
843 ItemTooltipTable
->Lookup(itemname
, lookup
);
844 value
= (int*)lookup
;
846 if (value
&& (value
[header
]>=0)) {
847 return value
[header
];
849 Item
*item
= gamedata
->GetItem(itemname
);
853 int ret
= identified
?item
->ItemNameIdentified
:item
->ItemName
;
854 gamedata
->FreeItem(item
, itemname
, 0);
858 int Interface::GetItemDialStr(const ieResRef itemname
) const
862 if (ItemDialTable
&& ItemDialTable
->Lookup(itemname
, value
)) {
868 //second value is the item dialog resource returned by this method
869 int Interface::GetItemDialRes(const ieResRef itemname
, ieResRef retval
) const
871 if (ItemDial2Table
&& ItemDial2Table
->Lookup(itemname
, retval
, sizeof(ieResRef
))) {
877 bool Interface::ReadAreaAliasTable(const ieResRef tablename
)
879 if (AreaAliasTable
) {
880 AreaAliasTable
->RemoveAll(NULL
);
882 AreaAliasTable
= new Variables();
883 AreaAliasTable
->SetType(GEM_VARIABLES_INT
);
886 AutoTable
aa(tablename
);
888 //don't report error when the file doesn't exist
892 int idx
= aa
->GetRowCount();
896 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
897 ieDword value
= atoi(aa
->QueryField(idx
,0));
898 AreaAliasTable
->SetAt(key
, value
);
904 int Interface::GetAreaAlias(const ieResRef areaname
) const
908 if (AreaAliasTable
&& AreaAliasTable
->Lookup(areaname
, value
)) {
914 bool Interface::ReadMusicTable(const ieResRef tablename
, int col
) {
915 AutoTable
tm(tablename
);
919 for (unsigned int i
= 0; i
< tm
->GetRowCount(); i
++) {
920 musiclist
.push_back(strdup(tm
->QueryField(i
, col
)));
926 bool Interface::ReadDamageTypeTable() {
927 AutoTable
tm("dmgtypes");
932 for (ieDword i
= 0; i
< tm
->GetRowCount(); i
++) {
933 di
.strref
= displaymsg
->GetStringReference(atoi(tm
->QueryField(i
, 0)));
934 di
.resist_stat
= TranslateStat(tm
->QueryField(i
, 1));
935 di
.value
= strtol(tm
->QueryField(i
, 2), (char **) NULL
, 16);
936 di
.iwd_mod_type
= atoi(tm
->QueryField(i
, 3));
937 DamageInfoMap
.insert(std::make_pair
<ieDword
, DamageInfoStruct
> ((ieDword
)di
.value
, di
));
943 bool Interface::ReadReputationModTable() {
944 AutoTable
tm("reputati");
948 reputationmod
= (int **) calloc(21, sizeof(int *));
949 int cols
= tm
->GetColumnCount();
950 for (unsigned int i
=0; i
<20; i
++) {
951 reputationmod
[i
] = (int *) calloc(cols
, sizeof(int));
952 for (int j
=0; j
<cols
; j
++) {
953 reputationmod
[i
][j
] = atoi(tm
->QueryField(i
, j
));
960 bool Interface::ReadModalStates()
962 AutoTable
table("modal");
966 ModalStatesStruct ms
;
967 for (unsigned short i
= 0; i
< table
->GetRowCount(); i
++) {
968 strncpy(ms
.spell
, table
->QueryField(i
, 0), 8);
969 strncpy(ms
.action
, table
->QueryField(i
, 1), 16);
970 ms
.entering_str
= atoi(table
->QueryField(i
, 2));
971 ms
.leaving_str
= atoi(table
->QueryField(i
, 3));
972 ms
.failed_str
= atoi(table
->QueryField(i
, 4));
973 ms
.aoe_spell
= atoi(table
->QueryField(i
, 5));
974 ModalStates
.push_back(ms
);
980 //Not a constant anymore, we let the caller set the entry to zero
981 char *Interface::GetMusicPlaylist(int SongType
) const {
982 if (SongType
< 0 || (unsigned int)SongType
>= musiclist
.size())
985 return musiclist
[SongType
];
988 static const Color white
= {0xff,0xff,0xff,0xff};
989 static const Color black
= {0x00,0x00,0x00,0xff};
990 static const Region
bg( 0, 0, 100, 30 );
992 /** this is the main loop */
993 void Interface::Main()
995 ieDword FullScreen
= 0;
996 ieDword brightness
= 10;
997 ieDword contrast
= 5;
1000 vars
->Lookup("Full Screen", FullScreen
);
1001 video
->CreateDisplay( Width
, Height
, Bpp
, FullScreen
);
1002 video
->SetDisplayTitle( GameName
, GameType
);
1003 vars
->Lookup("Brightness Correction", brightness
);
1004 vars
->Lookup("Gamma Correction", contrast
);
1005 vars
->Lookup("Mouse Scroll Speed", speed
);
1006 video
->SetGamma(brightness
, contrast
);
1007 SetMouseScrollSpeed((int) speed
);
1008 if (vars
->Lookup("Tooltips", TooltipDelay
)) {
1009 // the games store the slider position*10, not the actual delay
1010 TooltipDelay
*= TOOLTIP_DELAY_FACTOR
/10;
1013 Font
* fps
= GetFont( ( unsigned int ) 0 );
1014 char fpsstring
[40]={"???.??? fps"};
1015 unsigned long frame
= 0, time
, timebase
;
1017 double frames
= 0.0;
1018 Palette
* palette
= CreatePalette( white
, black
);
1020 //don't change script when quitting is pending
1025 //eventflags are processed only when there is a game
1026 if (EventFlag
&& game
) {
1029 HandleGUIBehaviour();
1036 if (time
- timebase
> 1000) {
1037 frames
= ( frame
* 1000.0 / ( time
- timebase
) );
1040 sprintf( fpsstring
, "%.3f fps", frames
);
1042 video
->DrawRect( bg
, black
);
1044 ( unsigned char * ) fpsstring
, palette
,
1045 IE_FONT_ALIGN_LEFT
| IE_FONT_ALIGN_MIDDLE
, true );
1047 } while (video
->SwapBuffers() == GEM_OK
);
1048 gamedata
->FreePalette( palette
);
1051 int Interface::ReadResRefTable(const ieResRef tablename
, ieResRef
*&data
)
1059 AutoTable
tm(tablename
);
1061 printStatus( "ERROR", LIGHT_RED
);
1062 printf( "Cannot find %s.2da.\n",tablename
);
1065 count
= tm
->GetRowCount();
1066 data
= (ieResRef
*) calloc( count
, sizeof(ieResRef
) );
1067 for (int i
= 0; i
< count
; i
++) {
1068 strnlwrcpy( data
[i
], tm
->QueryField( i
, 0 ), 8 );
1069 //* marks an empty resource
1070 if (data
[i
][0]=='*') {
1077 int Interface::LoadSprites()
1081 if (!IsAvailable( IE_2DA_CLASS_ID
)) {
1082 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1087 AnimationFactory
* anim
;
1088 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("cursors", IE_BAM_CLASS_ID
);
1091 CursorCount
= anim
->GetCycleCount();
1092 Cursors
= new Sprite2D
* [CursorCount
];
1093 for (int i
= 0; i
< CursorCount
; i
++) {
1094 Cursors
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1097 printMessage( "Core", "Loading Cursors...", WHITE
);
1099 // this is the last existing cursor type
1100 if (CursorCount
<IE_CURSOR_WAY
) {
1101 printStatus( "ERROR", LIGHT_RED
);
1104 video
->SetCursor( Cursors
[0], Cursors
[1] );
1105 printStatus( "OK", LIGHT_GREEN
);
1107 // Load fog-of-war bitmaps
1108 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("fogowar", IE_BAM_CLASS_ID
);
1109 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE
);
1110 if (!anim
|| anim
->GetCycleSize( 0 ) != 8) {
1111 // unknown type of fog anim
1112 printStatus( "ERROR", LIGHT_RED
);
1116 FogSprites
[0] = NULL
;
1117 FogSprites
[1] = anim
->GetFrame( 0, 0 );
1118 FogSprites
[2] = anim
->GetFrame( 1, 0 );
1119 FogSprites
[3] = anim
->GetFrame( 2, 0 );
1121 FogSprites
[4] = video
->MirrorSpriteVertical( FogSprites
[1], false );
1123 FogSprites
[5] = NULL
;
1125 FogSprites
[6] = video
->MirrorSpriteVertical( FogSprites
[3], false );
1127 FogSprites
[7] = NULL
;
1129 FogSprites
[8] = video
->MirrorSpriteHorizontal( FogSprites
[2], false );
1131 FogSprites
[9] = video
->MirrorSpriteHorizontal( FogSprites
[3], false );
1133 FogSprites
[10] = NULL
;
1134 FogSprites
[11] = NULL
;
1136 FogSprites
[12] = video
->MirrorSpriteHorizontal( FogSprites
[6], false );
1138 FogSprites
[16] = anim
->GetFrame( 3, 0 );
1139 FogSprites
[17] = anim
->GetFrame( 4, 0 );
1140 FogSprites
[18] = anim
->GetFrame( 5, 0 );
1141 FogSprites
[19] = anim
->GetFrame( 6, 0 );
1143 FogSprites
[20] = video
->MirrorSpriteVertical( FogSprites
[17], false );
1145 FogSprites
[21] = NULL
;
1147 FogSprites
[23] = NULL
;
1149 FogSprites
[24] = video
->MirrorSpriteHorizontal( FogSprites
[18], false );
1151 FogSprites
[25] = anim
->GetFrame( 7, 0 );
1154 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[25], false );
1155 FogSprites
[22] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1156 video
->FreeSprite( tmpsprite
);
1159 FogSprites
[26] = NULL
;
1160 FogSprites
[27] = NULL
;
1163 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[19], false );
1164 FogSprites
[28] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1165 video
->FreeSprite( tmpsprite
);
1169 vars
->Lookup("3D Acceleration", i
);
1171 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
1172 if (FogSprites
[i
]) {
1173 Sprite2D
* alphasprite
= video
->CreateAlpha( FogSprites
[i
] );
1174 video
->FreeSprite ( FogSprites
[i
] );
1175 FogSprites
[i
] = alphasprite
;
1180 printStatus( "OK", LIGHT_GREEN
);
1182 // Load ground circle bitmaps (PST only)
1183 //block required due to msvc6.0 incompatibility
1184 for (size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
1185 if (GroundCircleBam
[size
][0]) {
1186 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(GroundCircleBam
[size
], IE_BAM_CLASS_ID
);
1187 if (!anim
|| anim
->GetCycleCount() != 6) {
1188 // unknown type of circle anim
1189 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1190 printStatus( "ERROR", LIGHT_RED
);
1194 for (int i
= 0; i
< 6; i
++) {
1195 Sprite2D
* sprite
= anim
->GetFrame( 0, (ieByte
) i
);
1196 if (GroundCircleScale
[size
]) {
1197 GroundCircles
[size
][i
] = video
->SpriteScaleDown( sprite
, GroundCircleScale
[size
] );
1198 video
->FreeSprite( sprite
);
1200 GroundCircles
[size
][i
] = sprite
;
1206 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1207 printStatus( "OK", LIGHT_GREEN
);
1209 printMessage( "Core", "Loading Fonts...\n", WHITE
);
1210 AutoTable
tab("fonts");
1212 printStatus( "ERROR", LIGHT_RED
);
1213 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1216 PluginHolder
<AnimationMgr
> bamint(IE_BAM_CLASS_ID
);
1218 printStatus( "ERROR", LIGHT_RED
);
1219 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1222 DataStream
* str
= NULL
;
1224 int count
= tab
->GetRowCount();
1225 for (int i
= 0; i
< count
; i
++) {
1226 const char* ResRef
= tab
->QueryField( i
, 0 );
1227 int needpalette
= atoi( tab
->QueryField( i
, 1 ) );
1228 int first_char
= atoi( tab
->QueryField( i
, 2 ) );
1229 str
= gamedata
->GetResource( ResRef
, IE_BAM_CLASS_ID
);
1230 if (!bamint
->Open( str
, true )) {
1233 Font
* fnt
= bamint
->GetFont();
1237 strnlwrcpy( fnt
->ResRef
, ResRef
, 8 );
1240 Color fore
= {0xff, 0xff, 0xff, 0};
1241 Color back
= {0x00, 0x00, 0x00, 0};
1242 if (!strnicmp( TooltipFont
, ResRef
, 8) ) {
1243 if (TooltipColor
.a
==0xff) {
1244 fore
= TooltipColor
;
1247 back
= TooltipColor
;
1250 Palette
* pal
= CreatePalette( fore
, back
);
1251 pal
->CreateShadedAlphaChannel();
1252 fnt
->SetPalette(pal
);
1253 gamedata
->FreePalette( pal
);
1255 fnt
->SetFirstChar( (ieByte
) first_char
);
1256 fonts
.push_back( fnt
);
1259 if (fonts
.size() == 0) {
1260 printMessage( "Core", "No default font loaded! ", WHITE
);
1261 printStatus( "ERROR", LIGHT_RED
);
1264 if (GetFont( ButtonFont
) == NULL
) {
1265 printMessage( "Core", "ButtonFont not loaded: ", WHITE
);
1266 printf("%s ", ButtonFont
);
1267 printStatus( "WARNING", YELLOW
);
1269 if (GetFont( MovieFont
) == NULL
) {
1270 printMessage( "Core", "MovieFont not loaded: ", WHITE
);
1271 printf("%s ", MovieFont
);
1272 printStatus( "WARNING", YELLOW
);
1274 if (GetFont( TooltipFont
) == NULL
) {
1275 printMessage( "Core", "TooltipFont not loaded: ", WHITE
);
1276 printf("%s ", TooltipFont
);
1277 printStatus( "WARNING", YELLOW
);
1280 printMessage( "Core", "Fonts Loaded...", WHITE
);
1281 printStatus( "OK", LIGHT_GREEN
);
1283 if (TooltipBackResRef
[0]) {
1284 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(TooltipBackResRef
, IE_BAM_CLASS_ID
);
1285 printMessage( "Core", "Initializing Tooltips...", WHITE
);
1287 printStatus( "ERROR", LIGHT_RED
);
1290 TooltipBack
= new Sprite2D
* [3];
1291 for (int i
= 0; i
< 3; i
++) {
1292 TooltipBack
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1293 TooltipBack
[i
]->XPos
= 0;
1294 TooltipBack
[i
]->YPos
= 0;
1296 printStatus( "OK", LIGHT_GREEN
);
1302 int Interface::Init()
1304 plugin_flags
= new Variables();
1305 plugin_flags
->SetType( GEM_VARIABLES_INT
);
1307 printMessage( "Core", "Initializing the Event Manager...", WHITE
);
1308 evntmgr
= new EventMgr();
1310 printMessage( "Core", "Initializing Lists Dictionary...", WHITE
);
1311 lists
= new Variables();
1313 printStatus( "ERROR", LIGHT_RED
);
1316 lists
->SetType( GEM_VARIABLES_POINTER
);
1318 printMessage( "Core", "Initializing Variables Dictionary...", WHITE
);
1319 vars
= new Variables();
1321 printStatus( "ERROR", LIGHT_RED
);
1324 vars
->SetType( GEM_VARIABLES_INT
);
1325 vars
->ParseKey(true);
1327 vars
->SetAt( "Volume Ambients", 100 );
1328 vars
->SetAt( "Volume Movie", 100 );
1329 vars
->SetAt( "Volume Music", 100 );
1330 vars
->SetAt( "Volume SFX", 100 );
1331 vars
->SetAt( "Volume Voices", 100 );
1332 printStatus( "OK", LIGHT_GREEN
);
1334 if (!LoadConfig()) {
1337 printMessage( "Core", "Starting Plugin Manager...\n", WHITE
);
1338 PluginMgr
*plugin
= PluginMgr::Get();
1339 plugin
->LoadPlugins(PluginsPath
);
1340 if (plugin
&& plugin
->GetPluginCount()) {
1341 printMessage( "Core", "Plugin Loading Complete...", WHITE
);
1342 printStatus( "OK", LIGHT_GREEN
);
1344 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW
);
1345 printStatus( "ERROR", LIGHT_RED
);
1348 plugin
->RunInitializers();
1352 srand( ( unsigned int ) t
);
1354 FileStreamPtrCount
= 0;
1355 CachedFileStreamPtrCount
= 0;
1357 printMessage( "Core", "GemRB Core Initialization...\n", WHITE
);
1358 printStatus( "OK", LIGHT_GREEN
);
1359 printMessage( "Core", "Initializing Video Driver...", WHITE
);
1360 video
= ( Video
* ) PluginMgr::Get()->GetDriver(&Video::ID
, VideoDriverName
.c_str());
1362 printStatus( "ERROR", LIGHT_RED
);
1363 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1366 if (video
->Init() == GEM_ERROR
) {
1367 printStatus( "ERROR", LIGHT_RED
);
1368 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1371 Color defcolor
={255,255,255,200};
1372 SetInfoTextColor(defcolor
);
1373 printStatus( "OK", LIGHT_GREEN
);
1376 printMessage( "Core", "Initializing Search Path...", WHITE
);
1377 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY
)) {
1378 printf( "no DirectoryImporter! " );
1379 printStatus( "ERROR", LIGHT_RED
);
1383 char path
[_MAX_PATH
];
1385 PathJoin( path
, CachePath
, NULL
);
1386 gamedata
->AddSource(path
, "Cache", PLUGIN_RESOURCE_DIRECTORY
);
1388 PathJoin( path
, GemRBOverridePath
, "override", GameType
, NULL
);
1389 gamedata
->AddSource(path
, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1392 for (i
= 0; i
< ModPath
.size(); ++i
)
1393 gamedata
->AddSource(ModPath
[i
].c_str(), "Mod paths", PLUGIN_RESOURCE_DIRECTORY
);
1395 PathJoin( path
, GemRBOverridePath
, "override", "shared", NULL
);
1396 gamedata
->AddSource(path
, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1398 PathJoin( path
, GamePath
, GameOverridePath
, NULL
);
1399 gamedata
->AddSource(path
, "Override", PLUGIN_RESOURCE_DIRECTORY
);
1401 PathJoin( path
, GamePath
, GameSoundsPath
, NULL
);
1402 gamedata
->AddSource(path
, "Sounds", PLUGIN_RESOURCE_DIRECTORY
);
1404 PathJoin( path
, GamePath
, GameScriptsPath
, NULL
);
1405 gamedata
->AddSource(path
, "Scripts", PLUGIN_RESOURCE_DIRECTORY
);
1407 PathJoin( path
, GamePath
, GamePortraitsPath
, NULL
);
1408 gamedata
->AddSource(path
, "Portraits", PLUGIN_RESOURCE_DIRECTORY
);
1410 PathJoin( path
, GamePath
, GameDataPath
, NULL
);
1411 gamedata
->AddSource(path
, "Data", PLUGIN_RESOURCE_DIRECTORY
);
1413 //IWD2 movies are on the CD but not in the BIF
1414 for (i
= 0; i
< MAX_CD
; i
++) {
1415 for (size_t j
=0;j
<CD
[i
].size();j
++) {
1416 char description
[] = {'C', 'D', '1'+i
, '/', 'd', 'a', 't', 'a', '\0'};
1417 PathJoin( path
, CD
[i
][j
].c_str(), GameDataPath
, NULL
);
1418 gamedata
->AddSource(path
, description
, PLUGIN_RESOURCE_DIRECTORY
);
1422 printStatus( "OK", LIGHT_GREEN
);
1426 printMessage( "Core", "Initializing KEY Importer...", WHITE
);
1427 char ChitinPath
[_MAX_PATH
];
1428 PathJoin( ChitinPath
, GamePath
, "chitin.key", NULL
);
1429 if (!gamedata
->AddSource(ChitinPath
, "chitin.key", PLUGIN_RESOURCE_KEY
)) {
1430 printStatus( "ERROR", LIGHT_RED
);
1433 printStatus( "OK", LIGHT_GREEN
);
1436 printMessage( "Core", "Reading Game Options...\n", WHITE
);
1437 if (!LoadGemRBINI())
1439 printf( "Cannot Load INI\nTermination in Progress...\n" );
1443 //loading baldur.ini
1445 char ini_path
[_MAX_PATH
];
1446 PathJoin( ini_path
, GamePath
, INIConfig
, NULL
);
1447 LoadINI( ini_path
);
1449 for (i
= 0; i
< 8; i
++) {
1450 if (INIConfig
[i
] == '.')
1452 GameNameResRef
[i
] = INIConfig
[i
];
1454 GameNameResRef
[i
] = 0;
1457 printMessage( "Core", "Creating Projectile Server...\n", WHITE
);
1458 projserv
= new ProjectileServer();
1459 if (!projserv
->GetHighestProjectileNumber()) {
1460 printStatus( "ERROR", LIGHT_RED
);
1461 printf( "No projectiles are available...\n" );
1464 printMessage( "Core", "Checking for Dialogue Manager...", WHITE
);
1465 if (!IsAvailable( IE_TLK_CLASS_ID
)) {
1466 printStatus( "ERROR", LIGHT_RED
);
1467 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1470 printStatus( "OK", LIGHT_GREEN
);
1471 strings
= PluginHolder
<StringMgr
>(IE_TLK_CLASS_ID
);
1472 printMessage( "Core", "Loading Dialog.tlk file...", WHITE
);
1473 char strpath
[_MAX_PATH
];
1474 PathJoin( strpath
, GamePath
, dialogtlk
, NULL
);
1475 FileStream
* fs
= new FileStream();
1476 if (!fs
->Open( strpath
, true )) {
1477 printStatus( "ERROR", LIGHT_RED
);
1478 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1482 printStatus( "OK", LIGHT_GREEN
);
1483 strings
->Open( fs
, true );
1486 printMessage( "Core", "Loading Palettes...\n", WHITE
);
1487 ResourceHolder
<ImageMgr
> pal16im(Palette16
);
1489 pal16
= pal16im
->GetImage();
1490 ResourceHolder
<ImageMgr
> pal32im(Palette32
);
1492 pal32
= pal32im
->GetImage();
1493 ResourceHolder
<ImageMgr
> pal256im(Palette256
);
1495 pal256
= pal256im
->GetImage();
1496 if (!pal16
|| !pal32
|| !pal256
) {
1497 printStatus( "ERROR", LIGHT_RED
);
1500 printMessage( "Core", "Palettes Loaded\n", WHITE
);
1503 if (!IsAvailable( IE_BAM_CLASS_ID
)) {
1504 printStatus( "ERROR", LIGHT_RED
);
1505 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1509 printMessage( "Core", "Initializing stock sounds...\n", WHITE
);
1510 DSCount
= ReadResRefTable ("defsound", DefSound
);
1512 printStatus( "ERROR", LIGHT_RED
);
1513 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1517 printStatus( "OK", LIGHT_GREEN
);
1518 printMessage( "Core", "Broadcasting Event Manager...", WHITE
);
1519 video
->SetEventMgr( evntmgr
);
1520 printStatus( "OK", LIGHT_GREEN
);
1521 printMessage( "Core", "Initializing Window Manager...", WHITE
);
1522 windowmgr
= PluginHolder
<WindowMgr
>(IE_CHU_CLASS_ID
);
1523 if (windowmgr
== NULL
) {
1524 printStatus( "ERROR", LIGHT_RED
);
1527 printStatus( "OK", LIGHT_GREEN
);
1528 printMessage( "Core", "Initializing GUI Script Engine...", WHITE
);
1529 guiscript
= PluginHolder
<ScriptEngine
>(IE_GUI_SCRIPT_CLASS_ID
);
1530 if (guiscript
== NULL
) {
1531 printStatus( "ERROR", LIGHT_RED
);
1534 if (!guiscript
->Init()) {
1535 printStatus( "ERROR", LIGHT_RED
);
1538 printStatus( "OK", LIGHT_GREEN
);
1539 strcpy( NextScript
, "Start" );
1541 int ret
= LoadSprites();
1542 if (ret
) return ret
;
1544 printMessage( "Core", "Setting up the Console...", WHITE
);
1545 QuitFlag
= QF_CHANGESCRIPT
;
1546 console
= new Console();
1548 console
->YPos
= (ieWord
) (Height
- 25);
1549 console
->Width
= (ieWord
) Width
;
1550 console
->Height
= 25;
1551 if (fonts
.size() > 0) {
1552 console
->SetFont( fonts
[0] );
1555 Sprite2D
*tmpsprite
= GetCursorSprite();
1557 printStatus( "ERROR", LIGHT_RED
);
1560 console
->SetCursor (tmpsprite
);
1561 printStatus( "OK", LIGHT_GREEN
);
1563 printMessage( "Core", "Starting up the Sound Driver...", WHITE
);
1564 AudioDriver
= ( Audio
* ) PluginMgr::Get()->GetDriver(&Audio::ID
, AudioDriverName
.c_str());
1565 if (AudioDriver
== NULL
) {
1566 printStatus( "ERROR", LIGHT_RED
);
1569 if (!AudioDriver
->Init()) {
1570 printStatus( "ERROR", LIGHT_RED
);
1573 printStatus( "OK", LIGHT_GREEN
);
1575 printMessage( "Core", "Allocating SaveGameIterator...", WHITE
);
1576 sgiterator
= new SaveGameIterator();
1577 if (sgiterator
== NULL
) {
1578 printStatus( "ERROR", LIGHT_RED
);
1581 printStatus( "OK", LIGHT_GREEN
);
1583 //no need of strdup, variables do copy the key!
1584 vars
->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos
);
1585 vars
->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements
);
1587 printMessage( "Core", "Initializing Token Dictionary...", WHITE
);
1588 tokens
= new Variables();
1590 printStatus( "ERROR", LIGHT_RED
);
1593 tokens
->SetType( GEM_VARIABLES_STRING
);
1594 printStatus( "OK", LIGHT_GREEN
);
1596 printMessage( "Core", "Initializing Music Manager...", WHITE
);
1597 music
= PluginHolder
<MusicMgr
>(IE_MUS_CLASS_ID
);
1599 printStatus( "ERROR", LIGHT_RED
);
1602 printStatus( "OK", LIGHT_GREEN
);
1604 printMessage("Core", "Loading music list...\n", WHITE
);
1605 if (HasFeature( GF_HAS_SONGLIST
)) {
1606 ret
= ReadMusicTable("songlist", 1);
1608 /*since bg1 and pst has no .2da for songlist,
1609 we must supply one in the gemrb/override folder.
1610 It should be: music.2da, first column is a .mus filename*/
1611 ret
= ReadMusicTable("music", 0);
1614 printStatus( "OK", LIGHT_GREEN
);
1616 printStatus( "NOT FOUND", YELLOW
);
1619 if (HasFeature( GF_RESDATA_INI
)) {
1620 printMessage( "Core", "Loading resource data File...", WHITE
);
1621 INIresdata
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1622 DataStream
* ds
= gamedata
->GetResource("resdata", IE_INI_CLASS_ID
);
1623 if (!INIresdata
->Open( ds
, true )) {
1624 printStatus( "ERROR", LIGHT_RED
);
1626 printStatus( "OK", LIGHT_GREEN
);
1630 if (HasFeature( GF_HAS_PARTY_INI
)) {
1631 printMessage( "Core", "Loading precreated teams setup...\n",
1633 INIparty
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1634 FileStream
* fs
= new FileStream();
1635 char tINIparty
[_MAX_PATH
];
1636 PathJoin( tINIparty
, GamePath
, "Party.ini", NULL
);
1637 fs
->Open( tINIparty
, true );
1638 if (!INIparty
->Open( fs
, true )) {
1639 printStatus( "ERROR", LIGHT_RED
);
1641 printStatus( "OK", LIGHT_GREEN
);
1645 if (HasFeature(GF_IWD2_DEATHVARFORMAT
)) {
1646 memcpy(DeathVarFormat
, IWD2DeathVarFormat
, sizeof(ieVariable
));
1649 if (HasFeature( GF_HAS_BEASTS_INI
)) {
1650 printMessage( "Core", "Loading beasts definition File...\n",
1652 INIbeasts
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1653 FileStream
* fs
= new FileStream();
1654 char tINIbeasts
[_MAX_PATH
];
1655 PathJoin( tINIbeasts
, GamePath
, "beast.ini", NULL
);
1656 // FIXME: crashes if file does not open
1657 fs
->Open( tINIbeasts
, true );
1658 if (!INIbeasts
->Open( fs
, true )) {
1659 printStatus( "ERROR", LIGHT_RED
);
1661 printStatus( "OK", LIGHT_GREEN
);
1664 printMessage( "Core", "Loading quests definition File...\n",
1666 INIquests
= PluginHolder
<DataFileMgr
>(IE_INI_CLASS_ID
);
1667 FileStream
* fs2
= new FileStream();
1668 char tINIquests
[_MAX_PATH
];
1669 PathJoin( tINIquests
, GamePath
, "quests.ini", NULL
);
1670 // FIXME: crashes if file does not open
1671 fs2
->Open( tINIquests
, true );
1672 if (!INIquests
->Open( fs2
, true )) {
1673 printStatus( "ERROR", LIGHT_RED
);
1675 printStatus( "OK", LIGHT_GREEN
);
1681 timer
= new GlobalTimer();
1682 printMessage( "Core", "Bringing up the Global Timer...", WHITE
);
1684 printStatus( "ERROR", LIGHT_RED
);
1687 printStatus( "OK", LIGHT_GREEN
);
1689 ret
= Init_EffectQueue();
1690 printMessage( "Core", "Initializing effects...", WHITE
);
1692 printStatus( "ERROR", LIGHT_RED
);
1695 printStatus( "OK", LIGHT_GREEN
);
1697 ret
= InitItemTypes();
1698 printMessage( "Core", "Initializing Inventory Management...", WHITE
);
1700 printStatus( "ERROR", LIGHT_RED
);
1703 printStatus( "OK", LIGHT_GREEN
);
1705 displaymsg
= new DisplayMessage();
1706 printMessage( "Core", "Initializing string constants...", WHITE
);
1708 printStatus( "ERROR", LIGHT_RED
);
1711 printStatus( "OK", LIGHT_GREEN
);
1713 ret
= ReadRandomItems();
1714 printMessage( "Core", "Initializing random treasure...", WHITE
);
1716 printStatus( "OK", LIGHT_GREEN
);
1719 printStatus( "ERROR", LIGHT_RED
);
1722 ret
= ReadAbilityTables();
1723 printMessage( "Core", "Initializing ability tables...", WHITE
);
1725 printStatus( "ERROR", LIGHT_RED
);
1728 printStatus( "OK", LIGHT_GREEN
);
1730 ret
= ReadReputationModTable();
1731 printMessage( "Core", "Reading reputation mod table...", WHITE
);
1733 printStatus( "OK", LIGHT_GREEN
);
1735 printStatus( "NOT FOUND", LIGHT_RED
);
1738 if ( gamedata
->Exists("WMAPLAY", IE_2DA_CLASS_ID
) ) {
1739 ret
= ReadAreaAliasTable( "WMAPLAY" );
1740 printMessage( "Core", "Initializing area aliases...", WHITE
);
1742 printStatus( "OK", LIGHT_GREEN
);
1745 printStatus( "NOT FOUND", YELLOW
);
1749 ret
= ReadGameTimeTable();
1750 printMessage( "Core", "Reading game time table...", WHITE
);
1752 printStatus( "ERROR", LIGHT_RED
);
1755 printStatus( "OK", LIGHT_GREEN
);
1757 ret
= ReadAuxItemTables();
1758 printMessage( "Core", "Reading item tables...", WHITE
);
1760 printStatus( "ERROR", LIGHT_RED
);
1763 printStatus( "OK", LIGHT_GREEN
);
1765 ret
= ReadDamageTypeTable();
1766 printMessage( "Core", "Reading damage type table...", WHITE
);
1768 printStatus( "ERROR", LIGHT_RED
);
1770 printStatus( "OK", LIGHT_GREEN
);
1773 ret
= ReadModalStates();
1774 printMessage( "Core", "Reading modal states table...", WHITE
);
1776 printStatus( "ERROR", LIGHT_RED
);
1779 printStatus( "OK", LIGHT_GREEN
);
1782 printMessage( "Core", "Reading game script tables...", WHITE
);
1783 InitializeIEScript();
1784 printStatus( "OK", LIGHT_GREEN
);
1786 printMessage( "Core", "Core Initialization Complete!\n", WHITE
);
1791 bool Interface::IsAvailable(SClass_ID filetype
) const
1793 return PluginMgr::Get()->IsAvailable( filetype
);
1796 WorldMap
*Interface::GetWorldMap(const char *map
)
1798 int index
= worldmap
->FindAndSetCurrentMap(map
?map
:game
->CurrentArea
);
1799 return worldmap
->GetWorldMap(index
);
1802 ProjectileServer
* Interface::GetProjectileServer() const
1807 Video
* Interface::GetVideoDriver() const
1812 Audio
* Interface::GetAudioDrv(void) const {
1813 return AudioDriver
.get();
1816 const char* Interface::TypeExt(SClass_ID type
) const
1819 case IE_2DA_CLASS_ID
:
1822 case IE_ACM_CLASS_ID
:
1825 case IE_ARE_CLASS_ID
:
1828 case IE_BAM_CLASS_ID
:
1831 case IE_BCS_CLASS_ID
:
1834 case IE_BS_CLASS_ID
:
1837 case IE_BIF_CLASS_ID
:
1840 case IE_BIO_CLASS_ID
:
1841 if (HasFeature(GF_BIOGRAPHY_RES
)) {
1846 case IE_BMP_CLASS_ID
:
1849 case IE_PNG_CLASS_ID
:
1852 case IE_CHR_CLASS_ID
:
1855 case IE_CHU_CLASS_ID
:
1858 case IE_CRE_CLASS_ID
:
1861 case IE_DLG_CLASS_ID
:
1864 case IE_EFF_CLASS_ID
:
1867 case IE_GAM_CLASS_ID
:
1870 case IE_IDS_CLASS_ID
:
1873 case IE_INI_CLASS_ID
:
1876 case IE_ITM_CLASS_ID
:
1879 case IE_MOS_CLASS_ID
:
1882 case IE_MUS_CLASS_ID
:
1885 case IE_MVE_CLASS_ID
:
1888 case IE_OGG_CLASS_ID
:
1891 case IE_PLT_CLASS_ID
:
1894 case IE_PRO_CLASS_ID
:
1897 case IE_SAV_CLASS_ID
:
1900 case IE_SPL_CLASS_ID
:
1903 case IE_SRC_CLASS_ID
:
1906 case IE_STO_CLASS_ID
:
1909 case IE_TIS_CLASS_ID
:
1912 case IE_TLK_CLASS_ID
:
1915 case IE_TOH_CLASS_ID
:
1918 case IE_TOT_CLASS_ID
:
1921 case IE_VAR_CLASS_ID
:
1924 case IE_VVC_CLASS_ID
:
1927 case IE_WAV_CLASS_ID
:
1930 case IE_WED_CLASS_ID
:
1933 case IE_WFX_CLASS_ID
:
1936 case IE_WMP_CLASS_ID
:
1942 void Interface::FreeString(char *&str
) const
1945 strings
->FreeString(str
);
1950 ieStrRef
Interface::UpdateString(ieStrRef strref
, const char *text
) const
1952 return strings
->UpdateString( strref
, text
);
1955 char* Interface::GetString(ieStrRef strref
, ieDword options
) const
1959 if (!(options
& IE_STR_STRREFOFF
)) {
1960 vars
->Lookup( "Strref On", flags
);
1962 return strings
->GetString( strref
, flags
| options
);
1965 void Interface::SetFeature(int flag
, int position
)
1968 GameFeatures
[position
>>5] |= 1<<(position
&31);
1970 GameFeatures
[position
>>5] &= ~(1<<(position
&31) );
1976 GameFeatures2 |= 1 << position;
1978 GameFeatures2 &= ~( 1 << position );
1983 GameFeatures |= 1 << position;
1985 GameFeatures &= ~( 1 << position );
1990 ieDword
Interface::HasFeature(int position
) const
1992 return GameFeatures
[position
>>5] & (1<<(position
&31));
1995 return GameFeatures3 & ( 1 << (position-64) );
1998 return GameFeatures2 & ( 1 << (position-32) );
2000 return GameFeatures & ( 1 << position );
2004 /** Search directories and load a config file */
2005 bool Interface::LoadConfig(void)
2008 char path
[_MAX_PATH
];
2009 char name
[_MAX_PATH
];
2011 // Find directory where user stores GemRB configurations (~/.gemrb).
2012 // FIXME: Create it if it does not exist
2013 // Use current dir if $HOME is not defined (or bomb out??)
2015 char* s
= getenv( "HOME" );
2017 strcpy( UserDir
, s
);
2018 strcat( UserDir
, "/."PACKAGE
"/" );
2020 strcpy( UserDir
, "./" );
2023 // Find basename of this program. It does the same as basename (3),
2024 // but that's probably missing on some archs
2025 s
= strrchr( argv
[0], PathDelimiter
);
2033 //if (!name[0]) // FIXME: could this happen?
2034 // strcpy (name, PACKAGE); // ugly hack
2036 // If we were called as $0 -c <filename>, load config from filename
2037 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
2038 if (LoadConfig( argv
[2] )) {
2041 // Explicitly specified cfg file HAS to be present
2046 // FIXME: temporary hack, to be deleted??
2047 if (LoadConfig( "GemRB.cfg" )) {
2051 PathJoin( path
, UserDir
, name
, NULL
);
2052 strcat( path
, ".cfg" );
2054 if (LoadConfig( path
)) {
2059 PathJoin( path
, SYSCONFDIR
, name
, NULL
);
2060 strcat( path
, ".cfg" );
2062 if (LoadConfig( path
)) {
2067 // Don't try with default binary name if we have tried it already
2068 if (!strcmp( name
, PACKAGE
)) {
2072 PathJoin( path
, UserDir
, PACKAGE
, NULL
);
2073 strcat( path
, ".cfg" );
2075 if (LoadConfig( path
)) {
2080 PathJoin( path
, SYSCONFDIR
, PACKAGE
, NULL
);
2081 strcat( path
, ".cfg" );
2083 if (LoadConfig( path
)) {
2090 // If we were called as $0 -c <filename>, load config from filename
2091 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
2092 return LoadConfig( argv
[2] );
2093 // Explicitly specified cfg file HAS to be present
2095 strcpy( UserDir
, ".\\" );
2096 return LoadConfig( "GemRB.cfg" );
2100 bool Interface::LoadConfig(const char* filename
)
2105 printMessage("Config","Trying to open ", WHITE
);
2106 textcolor(LIGHT_WHITE
);
2107 printf("%s ", filename
);
2108 config
= fopen( filename
, "rb" );
2109 if (config
== NULL
) {
2110 printStatus("NOT FOUND", LIGHT_RED
);
2113 char name
[65], value
[_MAX_PATH
+ 3];
2115 //once GemRB own format is working well, this might be set to 0
2118 while (!feof( config
)) {
2121 if (fread( &rem
, 1, 1, config
) != 1)
2125 //it should always return 0
2126 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
2130 fseek( config
, -1, SEEK_CUR
);
2131 memset(value
,'\0',_MAX_PATH
+ 3);
2132 //the * element is not counted
2133 if (fscanf( config
, "%64[^= ] = %[^\r\n]%*[\r\n]", name
, value
)!=2)
2135 for (i
=_MAX_PATH
+ 2; i
> 0; i
--) {
2136 if (value
[i
] == '\0') continue;
2137 if (value
[i
] == ' ') {
2145 #define CONFIG_INT(str, var) \
2146 } else if (stricmp(name, str) == 0) { \
2148 CONFIG_INT("Bpp", Bpp
= );
2149 CONFIG_INT("CaseSensitive", CaseSensitive
= );
2150 CONFIG_INT("DoubleClickDelay", evntmgr
->SetDCDelay
);
2151 CONFIG_INT("DrawFPS", DrawFPS
= );
2152 CONFIG_INT("EnableCheatKeys", EnableCheatKeys
);
2153 CONFIG_INT("EndianSwitch", DataStream::SetEndianSwitch
);
2154 CONFIG_INT("FogOfWar", FogOfWar
= );
2155 //CONFIG_INT("FullScreen", FullScreen = );
2156 CONFIG_INT("GUIEnhancements", GUIEnhancements
= );
2157 CONFIG_INT("GameOnCD", GameOnCD
= );
2158 CONFIG_INT("Height", Height
= );
2159 CONFIG_INT("KeepCache", KeepCache
= );
2160 CONFIG_INT("MultipleQuickSaves", GameControl::MultipleQuickSaves
);
2161 CONFIG_INT("RepeatKeyDelay", evntmgr
->SetRKDelay
);
2162 CONFIG_INT("SaveAsOriginal", SaveAsOriginal
= );
2163 CONFIG_INT("ScriptDebugMode", SetScriptDebugMode
);
2164 CONFIG_INT("SkipIntroVideos", SkipIntroVideos
= );
2165 CONFIG_INT("TooltipDelay", TooltipDelay
= );
2166 CONFIG_INT("Width", Width
= );
2168 #define CONFIG_STRING(str, var) \
2169 } else if (stricmp(name, str) == 0) { \
2170 strncpy(var, value, sizeof(var))
2171 CONFIG_STRING("GameCharactersPath", GameCharactersPath
);
2172 CONFIG_STRING("GameDataPath", GameDataPath
);
2173 CONFIG_STRING("GameName", GameName
);
2174 CONFIG_STRING("GameOverridePath", GameOverridePath
);
2175 CONFIG_STRING("GamePortraitsPath", GamePortraitsPath
);
2176 CONFIG_STRING("GameScriptsPath", GameScriptsPath
);
2177 CONFIG_STRING("GameSoundsPath", GameSoundsPath
);
2178 CONFIG_STRING("GameType", GameType
);
2179 #undef CONFIG_STRING
2180 #define CONFIG_STRING(str, var) \
2181 } else if (stricmp(name, str) == 0) { \
2183 CONFIG_STRING("AudioDriver", AudioDriverName
);
2184 CONFIG_STRING("VideoDriver", VideoDriverName
);
2185 #undef CONFIG_STRING
2186 #define CONFIG_PATH(str, var) \
2187 } else if (stricmp(name, str) == 0) { \
2188 strncpy(var, value, sizeof(var));
2189 CONFIG_PATH("CachePath", CachePath
);
2190 CONFIG_PATH("GUIScriptsPath", GUIScriptsPath
);
2191 CONFIG_PATH("GamePath", GamePath
);
2192 CONFIG_PATH("GemRBOverridePath", GemRBOverridePath
);
2193 CONFIG_PATH("GemRBPath", GemRBPath
);
2194 CONFIG_PATH("PluginsPath", PluginsPath
);
2195 CONFIG_PATH("SavePath", SavePath
);
2197 } else if (stricmp( name
, "ModPath" ) == 0) {
2198 for (char *path
= strtok(value
,SPathListSeparator
);
2200 path
= strtok(NULL
,SPathListSeparator
)) {
2201 ModPath
.push_back(path
);
2203 } else if (stricmp( name
, "SkipPlugin" ) == 0) {
2204 plugin_flags
->SetAt( value
, PLF_SKIP
);
2205 } else if (stricmp( name
, "DelayPlugin" ) == 0) {
2206 plugin_flags
->SetAt( value
, PLF_DELAY
);
2208 for(i
=0;i
<MAX_CD
;i
++) {
2209 char keyname
[] = { 'C', 'D', '1'+i
, '\0' };
2210 if (stricmp(name
, keyname
) == 0) {
2211 for(char *path
= strtok(value
, SPathListSeparator
);
2213 path
= strtok(NULL
,SPathListSeparator
)) {
2214 CD
[i
].push_back(path
);
2222 // WARNING: Don't move ResolveFilePath into the loop
2223 // Otherwise, it won't obey CaseSensitive set at the end
2224 // of the config file.
2226 if (stricmp( GameType
, "tob" ) == 0) {
2227 strncpy( GameType
, "bg2", sizeof(GameType
) );
2231 if (!GemRBPath
[0]) {
2232 strcpy( GemRBPath
, DATADIR
);
2235 ResolveFilePath(GemRBPath
);
2237 if (!GemRBOverridePath
[0]) {
2238 strcpy( GemRBOverridePath
, GemRBPath
);
2240 ResolveFilePath(GemRBOverridePath
);
2243 if (!PluginsPath
[0]) {
2245 strcpy( PluginsPath
, PLUGINDIR
);
2247 PathJoin( PluginsPath
, GemRBPath
, "plugins", NULL
);
2250 ResolveFilePath( PluginsPath
);
2253 if (!GUIScriptsPath
[0]) {
2254 strcpy( GUIScriptsPath
, GemRBPath
);
2256 ResolveFilePath( GUIScriptsPath
);
2260 strcpy( GameName
, GEMRB_STRING
);
2263 ResolveFilePath( GamePath
);
2266 // FIXME: maybe should use UserDir instead of GamePath
2267 strcpy( SavePath
, GamePath
);
2269 ResolveFilePath( SavePath
);
2272 if (! CachePath
[0]) {
2273 PathJoin( CachePath
, UserDir
, "Cache", NULL
);
2275 ResolveFilePath(CachePath
);
2278 for (i
= 0; i
< MAX_CD
; ++i
) {
2279 if (!CD
[i
].size()) {
2280 char cd
[] = { 'C', 'D', '1'+i
, '\0' };
2281 char name
[_MAX_PATH
];
2283 PathJoin(name
, GamePath
, cd
, NULL
);
2284 CD
[i
].push_back(name
);
2286 size_t cnt
= CD
[i
].size();
2288 ResolveFilePath( CD
[i
][cnt
] );
2293 for (i
= 0; i
< ModPath
.size(); ++i
) {
2294 ResolveFilePath(ModPath
[i
]);
2297 FixPath( GUIScriptsPath
, true );
2298 FixPath( PluginsPath
, true );
2299 FixPath( GemRBPath
, true );
2300 FixPath( GemRBOverridePath
, true );
2303 FixPath( GamePath
, true );
2306 //FixPath( SavePath, false );
2307 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2308 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2309 FixPath( SavePath
, true );
2311 FixPath( CachePath
, false );
2312 mkdir( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2313 chmod( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2315 printStatus( "OK", LIGHT_GREEN
);
2317 // Missing GameType is a common users' error
2319 printMessage("Config","GameType was not set in your config file.\n", LIGHT_RED
);
2323 if ( StupidityDetector( CachePath
)) {
2324 printMessage("Core"," ",LIGHT_RED
);
2325 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath
);
2328 if (!KeepCache
) DelTree((const char *) CachePath
, false);
2329 FixPath( CachePath
, true );
2334 static void upperlower(int upper
, int lower
)
2336 pl_uppercase
[lower
]=(ieByte
) upper
;
2337 pl_lowercase
[upper
]=(ieByte
) lower
;
2340 static const char *game_flags
[GF_COUNT
+1]={
2341 "HasKaputz", //0 GF_HAS_KAPUTZ
2342 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2343 "HasSongList", //2 GF_HAS_SONGLIST
2344 "TeamMovement", //3 GF_TEAM_MOVEMENT
2345 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2346 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2347 "HasPartyIni", //6 GF_HAS_PARTY_INI
2348 "SoundFolders", //7 GF_SOUNDFOLDERS
2349 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2350 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2351 "HasDPLAYER", //10GF_HAS_DPLAYER
2352 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2353 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2354 "HasDescIcon", //13GF_HAS_DESC_ICON
2355 "HasPickSound", //14GF_HAS_PICK_SOUND
2356 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2357 "AutomapIni", //16GF_AUTOMAP_INI
2358 "SmallFog", //17GF_SMALL_FOG
2359 "ReverseDoor", //18GF_REVERSE_DOOR
2360 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2361 "HasSpellList", //20GF_HAS_SPELLLIST
2362 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2363 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2364 "KnowWorld", //23GF_KNOW_WORLD
2365 "ReverseToHit", //24GF_REVERSE_TOHIT
2366 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2367 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2368 "MagicBit", //27GF_MAGICBIT
2369 "CheckAbilities", //28GF_CHECK_ABILITIES
2370 "ChallengeRating", //29GF_CHALLENGERATING
2371 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2372 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2373 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2374 "SpawnIni", //33GF_SPAWN_INI
2375 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2376 "HasResDataIni", //35GF_RESDATA_INI
2377 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2378 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2379 "3EdRules", //38GF_3ED_RULES
2380 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2381 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2382 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2383 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2384 "ProperBackstab", //43GF_PROPER_BACKSTAB
2385 "OnScreenText", //44GF_ONSCREEN_TEXT
2386 "HasSpecificDamageBonus", //45GF_SPECIFIC_DMG_BONUS
2387 "StrrefSaveGame", //46GF_STRREF_SAVEGAME
2388 "HasWisdomBonusTable",//47GF_WISDOM_BONUS
2389 "BiographyIsRes", //48GF_BIOGRAPHY_RES
2390 "NoBiography", //49GF_NO_BIOGRAPHY
2391 "StealIsAttack", //50GF_STEAL_IS_ATTACK
2392 "CutsceneAreascripts",//51GF_CUTSCENE_AREASCRIPTS
2393 "FlexibleWorldmap", //52GF_FLEXIBLE_WMAP
2394 "AutoSearchHidden", //53GF_AUTOSEARCH_HIDDEN
2395 "PSTStateFlags", //54GF_PST_STATE_FLAGS
2396 "NoDropCanMove", //55GF_NO_DROP_CAN_MOVE
2397 "JournalHasSections", //56GF_JOURNAL_HAS_SECTIONS
2398 "CastingSounds", //57GF_CASTING_SOUNDS
2399 "EnhancedCastingSounds", //58GF_CASTING_SOUNDS2
2400 NULL
//for our own safety, this marks the end of the pole
2403 /** Loads gemrb.ini */
2404 bool Interface::LoadGemRBINI()
2406 DataStream
* inifile
= gamedata
->GetResource( "gemrb", IE_INI_CLASS_ID
);
2408 printStatus( "ERROR", LIGHT_RED
);
2412 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE
);
2413 printf( "%s",inifile
->originalfile
);
2415 if (!IsAvailable( IE_INI_CLASS_ID
)) {
2416 printStatus( "ERROR", LIGHT_RED
);
2417 printf( "[Core]: No INI Importer Available.\n" );
2420 PluginHolder
<DataFileMgr
> ini(IE_INI_CLASS_ID
);
2421 ini
->Open( inifile
, true ); //autofree
2423 printStatus( "OK", LIGHT_GREEN
);
2427 // Resrefs are already initialized in Interface::Interface()
2428 s
= ini
->GetKeyAsString( "resources", "CursorBAM", NULL
);
2430 strnlwrcpy( CursorBam
, s
, 8 ); //console cursor
2432 s
= ini
->GetKeyAsString( "resources", "ScrollCursorBAM", NULL
);
2434 strnlwrcpy( ScrollCursorBam
, s
, 8 );
2436 s
= ini
->GetKeyAsString( "resources", "ButtonFont", NULL
);
2438 strnlwrcpy( ButtonFont
, s
, 8 );
2440 s
= ini
->GetKeyAsString( "resources", "TooltipFont", NULL
);
2442 strnlwrcpy( TooltipFont
, s
, 8 );
2444 s
= ini
->GetKeyAsString( "resources", "MovieFont", NULL
);
2446 strnlwrcpy( MovieFont
, s
, 8 );
2448 s
= ini
->GetKeyAsString( "resources", "TooltipBack", NULL
);
2450 strnlwrcpy( TooltipBackResRef
, s
, 8 );
2452 s
= ini
->GetKeyAsString( "resources", "TooltipColor", NULL
);
2455 unsigned long c
= strtoul (s
+ 1, NULL
, 16);
2456 // FIXME: check errno
2457 TooltipColor
.r
= (unsigned char) (c
>> 24);
2458 TooltipColor
.g
= (unsigned char) (c
>> 16);
2459 TooltipColor
.b
= (unsigned char) (c
>> 8);
2460 TooltipColor
.a
= (unsigned char) (c
);
2464 //which stat determines the fist weapon (defaults to class)
2465 Actor::SetFistStat(ini
->GetKeyAsInt( "resources", "FistStat", IE_CLASS
));
2467 TooltipMargin
= ini
->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin
);
2469 // The format of GroundCircle can be:
2470 // GroundCircleBAM1 = wmpickl/3
2471 // to denote that the bitmap should be scaled down 3x
2472 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
2474 sprintf( name
, "GroundCircleBAM%d", size
+1 );
2475 s
= ini
->GetKeyAsString( "resources", name
, NULL
);
2477 const char *pos
= strchr( s
, '/' );
2479 GroundCircleScale
[size
] = atoi( pos
+1 );
2480 strncpy( GroundCircleBam
[size
], s
, pos
- s
);
2481 GroundCircleBam
[size
][pos
- s
] = '\0';
2483 strcpy( GroundCircleBam
[size
], s
);
2488 s
= ini
->GetKeyAsString( "resources", "NoteString", NULL
);
2489 TextArea::SetNoteString(s
);
2491 s
= ini
->GetKeyAsString( "resources", "INIConfig", NULL
);
2493 strcpy( INIConfig
, s
);
2495 s
= ini
->GetKeyAsString( "resources", "Palette16", NULL
);
2497 strcpy( Palette16
, s
);
2499 s
= ini
->GetKeyAsString( "resources", "Palette32", NULL
);
2501 strcpy( Palette32
, s
);
2503 s
= ini
->GetKeyAsString( "resources", "Palette256", NULL
);
2505 strcpy( Palette256
, s
);
2507 unsigned int i
= (unsigned int) ini
->GetKeyAsInt ("charset", "CharCount", 0);
2511 snprintf(key
,9,"Letter%d", i
+1);
2512 s
= ini
->GetKeyAsString( "charset", key
, NULL
);
2514 const char *s2
= strchr(s
,',');
2516 upperlower(atoi(s
), atoi(s2
+1) );
2521 MaximumAbility
= ini
->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2523 RedrawTile
= ini
->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2525 for (i
=0;i
<GF_COUNT
;i
++) {
2526 if (!game_flags
[i
]) {
2527 printf("Fix the game flags!\n");
2530 SetFeature( ini
->GetKeyAsInt( "resources", game_flags
[i
], 0 ), i
);
2531 //printMessage("Option", "", GREEN);
2532 //printf("%s = %s\n", game_flags[i], HasFeature(i)?"yes":"no");
2535 ForceStereo
= ini
->GetKeyAsInt( "resources", "ForceStereo", 0 );
2540 Palette
* Interface::CreatePalette(const Color
&color
, const Color
&back
)
2542 Palette
* pal
= new Palette();
2544 pal
->col
[0].g
= 0xff;
2547 for (int i
= 1; i
< 256; i
++) {
2548 pal
->col
[i
].r
= back
.r
+
2549 ( unsigned char ) ( ( ( color
.r
- back
.r
) * ( i
) ) / 255.0 );
2550 pal
->col
[i
].g
= back
.g
+
2551 ( unsigned char ) ( ( ( color
.g
- back
.g
) * ( i
) ) / 255.0 );
2552 pal
->col
[i
].b
= back
.b
+
2553 ( unsigned char ) ( ( ( color
.b
- back
.b
) * ( i
) ) / 255.0 );
2554 pal
->col
[i
].a
= back
.a
+
2555 ( unsigned char ) ( ( ( color
.a
- back
.a
) * ( i
) ) / 255.0 );
2560 /** No descriptions */
2561 Color
* Interface::GetPalette(unsigned index
, int colors
, Color
*pal
) const
2566 } else if (colors
<= 32) {
2568 } else if (colors
== 256) {
2573 if (index
>= img
->GetHeight()) {
2576 for (int i
= 0; i
< colors
; i
++) {
2577 pal
[i
] = img
->GetPixel(i
, index
);
2581 /** Returns a preloaded Font */
2582 Font
* Interface::GetFont(const char *ResRef
) const
2584 for (unsigned int i
= 0; i
< fonts
.size(); i
++) {
2585 if (strnicmp( fonts
[i
]->ResRef
, ResRef
, 8 ) == 0) {
2592 Font
* Interface::GetFont(unsigned int index
) const
2594 if (index
>= fonts
.size()) {
2597 return fonts
[index
];
2600 Font
* Interface::GetButtonFont() const
2602 return GetFont( ButtonFont
);
2605 /** Returns the Event Manager */
2606 EventMgr
* Interface::GetEventMgr() const
2611 /** Returns the Window Manager */
2612 WindowMgr
* Interface::GetWindowMgr() const
2614 return windowmgr
.get();
2617 /** Get GUI Script Manager */
2618 ScriptEngine
* Interface::GetGUIScriptEngine() const
2620 return guiscript
.get();
2623 static EffectRef fx_summon_disable_ref
={"AvatarRemovalModifier",NULL
,-1};
2625 //NOTE: if there were more summoned creatures, it will return only the last
2626 Actor
*Interface::SummonCreature(const ieResRef resource
, const ieResRef vvcres
, Scriptable
*Owner
, Actor
*target
, const Point
&position
, int eamod
, int level
, Effect
*fx
, bool sexmod
)
2628 //maximum number of monsters summoned
2633 //decrease the number of summoned creatures with the number of already summoned creatures here
2634 //the summoned creatures have a special IE_SPECIFIC
2637 ab
= gamedata
->GetCreature(resource
);
2642 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2643 ab
->LastSummoner
= Owner
->GetGlobalID();
2645 //Always use Base stats for the recently summoned creature
2649 if (eamod
==EAM_SOURCEALLY
|| eamod
==EAM_SOURCEENEMY
) {
2650 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2651 enemyally
= ((Actor
*) Owner
)->GetStat(IE_EA
)>EA_GOODCUTOFF
;
2657 enemyally
= target
->GetBase(IE_EA
)>EA_GOODCUTOFF
;
2664 case EAM_SOURCEALLY
:
2667 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2669 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2672 case EAM_SOURCEENEMY
:
2675 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2677 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2681 ab
->SetBase(IE_EA
, EA_NEUTRAL
);
2687 // mark the summon, but only if they don't have a special sex already
2688 if (sexmod
&& ab
->BaseStats
[IE_SEX
] < SEX_EXTRA
) {
2689 ab
->SetBase(IE_SEX
, SEX_SUMMON
);
2694 map
= target
->GetCurrentArea();
2696 map
= Owner
->GetCurrentArea();
2699 ab
->SetPosition(position
, true, 0);
2700 ab
->RefreshEffects(NULL
);
2703 ScriptedAnimation
* vvc
= gamedata
->GetScriptedAnimation(vvcres
, false);
2705 //This is the final position of the summoned creature
2706 //not the original target point
2707 vvc
->XPos
=ab
->Pos
.x
;
2708 vvc
->YPos
=ab
->Pos
.y
;
2709 //force vvc to play only once
2711 map
->AddVVCell( vvc
);
2713 //set up the summon disable effect
2714 Effect
*newfx
= EffectQueue::CreateEffect(fx_summon_disable_ref
, 0, 1, FX_DURATION_ABSOLUTE
);
2716 newfx
->Duration
= vvc
->GetSequenceDuration(AI_UPDATE_TIME
)*9/10 + core
->GetGame()->GameTime
;
2717 ApplyEffect(newfx
, ab
, ab
);
2722 //remove the xp value of friendly summons
2723 if (ab
->BaseStats
[IE_EA
]<EA_GOODCUTOFF
) {
2724 ab
->SetBase(IE_XPVALUE
, 0);
2727 ApplyEffect(fx
, ab
, Owner
);
2730 //this check should happen after the fact
2731 level
-= ab
->GetBase(IE_XP
);
2732 if(level
<0 || ab
->GetBase(IE_XP
) == 0) {
2740 void Interface::RedrawControls(const char *varname
, unsigned int value
)
2742 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2743 Window
*win
= windows
[i
];
2744 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2745 win
->RedrawControls(varname
, value
);
2750 void Interface::RedrawAll()
2752 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2753 Window
*win
= windows
[i
];
2754 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2760 /** Loads a WindowPack (CHUI file) in the Window Manager */
2761 bool Interface::LoadWindowPack(const char* name
)
2763 DataStream
* stream
= gamedata
->GetResource( name
, IE_CHU_CLASS_ID
);
2764 if (stream
== NULL
) {
2765 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED
);
2766 printf( "%s.chu\n", name
);
2769 if (!GetWindowMgr()->Open( stream
, true )) {
2770 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED
);
2771 printf( "%s.chu\n", name
);
2775 strncpy( WindowPack
, name
, sizeof( WindowPack
) );
2776 WindowPack
[sizeof( WindowPack
) - 1] = '\0';
2781 /** Loads a Window in the Window Manager */
2782 int Interface::LoadWindow(unsigned short WindowID
)
2786 for (i
= 0; i
< windows
.size(); i
++) {
2787 Window
*win
= windows
[i
];
2790 if (win
->Visible
==WINDOW_INVALID
) {
2793 if (win
->WindowID
== WindowID
&&
2794 !strnicmp( WindowPack
, win
->WindowPack
, sizeof(WindowPack
) )) {
2800 Window
* win
= windowmgr
->GetWindow( WindowID
);
2804 memcpy( win
->WindowPack
, WindowPack
, sizeof(WindowPack
) );
2807 for (i
= 0; i
< windows
.size(); i
++) {
2808 if (windows
[i
] == NULL
) {
2814 windows
.push_back( win
);
2815 slot
= ( int ) windows
.size() - 1;
2817 windows
[slot
] = win
;
2822 // FIXME: it's a clone of LoadWindow
2823 /** Creates a Window in the Window Manager */
2824 int Interface::CreateWindow(unsigned short WindowID
, int XPos
, int YPos
, unsigned int Width
, unsigned int Height
, char* Background
)
2828 for (i
= 0; i
< windows
.size(); i
++) {
2829 if (windows
[i
] == NULL
)
2831 if (windows
[i
]->WindowID
== WindowID
&& !stricmp( WindowPack
,
2832 windows
[i
]->WindowPack
)) {
2834 windows
[i
]->Invalidate();
2839 Window
* win
= new Window( WindowID
, (ieWord
) XPos
, (ieWord
) YPos
, (ieWord
) Width
, (ieWord
) Height
);
2840 if (Background
[0]) {
2841 ResourceHolder
<ImageMgr
> mos(Background
);
2843 win
->SetBackGround( mos
->GetSprite2D(), true );
2845 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2849 strcpy( win
->WindowPack
, WindowPack
);
2852 for (i
= 0; i
< windows
.size(); i
++) {
2853 if (windows
[i
] == NULL
) {
2859 windows
.push_back( win
);
2860 slot
= ( int ) windows
.size() - 1;
2862 windows
[slot
] = win
;
2868 /** Sets a Window on the Top */
2869 void Interface::SetOnTop(int Index
)
2871 std::vector
<int>::iterator t
;
2872 for(t
= topwin
.begin(); t
!= topwin
.end(); ++t
) {
2878 if(topwin
.size() != 0)
2879 topwin
.insert(topwin
.begin(), Index
);
2881 topwin
.push_back(Index
);
2883 /** Add a window to the Window List */
2884 void Interface::AddWindow(Window
* win
)
2887 for(unsigned int i
= 0; i
< windows
.size(); i
++) {
2888 Window
*w
= windows
[i
];
2896 windows
.push_back(win
);
2897 slot
=(int)windows
.size()-1;
2900 windows
[slot
] = win
;
2904 /** Get a Control on a Window */
2905 int Interface::GetControl(unsigned short WindowIndex
, unsigned long ControlID
) const
2907 if (WindowIndex
>= windows
.size()) {
2910 Window
* win
= windows
[WindowIndex
];
2916 Control
* ctrl
= win
->GetControl( (unsigned short) i
);
2919 if (ctrl
->ControlID
== ControlID
)
2924 /** Adjust the Scrolling factor of a control (worldmap atm) */
2925 int Interface::AdjustScrolling(unsigned short WindowIndex
,
2926 unsigned short ControlIndex
, short x
, short y
)
2928 if (WindowIndex
>= windows
.size()) {
2931 Window
* win
= windows
[WindowIndex
];
2935 Control
* ctrl
= win
->GetControl( ControlIndex
);
2939 switch(ctrl
->ControlType
) {
2940 case IE_GUI_WORLDMAP
:
2941 ((WorldMapControl
*) ctrl
)->AdjustScrolling(x
,y
);
2943 default: //doesn't work for these
2949 /** Set the Text of a Control */
2950 int Interface::SetText(unsigned short WindowIndex
,
2951 unsigned short ControlIndex
, const char* string
)
2953 if (WindowIndex
>= windows
.size()) {
2956 Window
* win
= windows
[WindowIndex
];
2960 Control
* ctrl
= win
->GetControl( ControlIndex
);
2964 return ctrl
->SetText( string
);
2966 /** Set the Tooltip text of a Control */
2967 int Interface::SetTooltip(unsigned short WindowIndex
,
2968 unsigned short ControlIndex
, const char* string
)
2970 if (WindowIndex
>= windows
.size()) {
2973 Window
* win
= windows
[WindowIndex
];
2977 Control
* ctrl
= win
->GetControl( ControlIndex
);
2981 return ctrl
->SetTooltip( string
);
2984 void Interface::DisplayTooltip(int x
, int y
, Control
*ctrl
)
2986 if (tooltip_ctrl
&& tooltip_ctrl
== ctrl
&& tooltip_x
== x
&& tooltip_y
== y
)
2990 tooltip_currtextw
= 0;
2991 tooltip_ctrl
= ctrl
;
2994 int Interface::GetVisible(unsigned short WindowIndex
) const
2996 if (WindowIndex
>= windows
.size()) {
2999 Window
* win
= windows
[WindowIndex
];
3003 return win
->Visible
;
3005 /** Set a Window Visible Flag */
3006 int Interface::SetVisible(unsigned short WindowIndex
, int visible
)
3008 if (WindowIndex
>= windows
.size()) {
3011 Window
* win
= windows
[WindowIndex
];
3015 if (visible
!=WINDOW_FRONT
) {
3016 win
->Visible
= (char) visible
;
3021 //here is a fallthrough
3022 case WINDOW_INVISIBLE
:
3023 //hiding the viewport if the gamecontrol window was made invisible
3024 if (win
->WindowID
==65535) {
3025 video
->SetViewport( 0,0,0,0 );
3027 evntmgr
->DelWindow( win
);
3030 case WINDOW_VISIBLE
:
3031 if (win
->WindowID
==65535) {
3032 video
->SetViewport( win
->XPos
, win
->YPos
, win
->Width
, win
->Height
);
3034 //here is a fallthrough
3036 if (win
->Visible
==WINDOW_VISIBLE
) {
3037 evntmgr
->AddWindow( win
);
3040 SetOnTop( WindowIndex
);
3047 /** Set the Status of a Control in a Window */
3048 int Interface::SetControlStatus(unsigned short WindowIndex
,
3049 unsigned short ControlIndex
, unsigned long Status
)
3051 //don't set the status of an already invalidated window
3052 Window
* win
= GetWindow(WindowIndex
);
3056 Control
* ctrl
= win
->GetControl( ControlIndex
);
3060 if (Status
&IE_GUI_CONTROL_FOCUSED
) {
3061 evntmgr
->SetFocused( win
, ctrl
);
3063 if (ctrl
->ControlType
!= ((Status
>> 24) & 0xff) ) {
3066 switch (ctrl
->ControlType
) {
3070 Button
* btn
= ( Button
* ) ctrl
;
3071 btn
->SetState( ( unsigned char ) ( Status
& 0x7f ) );
3075 ctrl
->Value
= Status
& 0x7f;
3081 /** Show a Window in Modal Mode */
3082 int Interface::ShowModal(unsigned short WindowIndex
, int Shadow
)
3084 if (WindowIndex
>= windows
.size()) {
3085 printMessage( "Core", "Window not found", LIGHT_RED
);
3088 Window
* win
= windows
[WindowIndex
];
3090 printMessage( "Core", "Window already freed", LIGHT_RED
);
3093 win
->Visible
= WINDOW_FRONT
;
3094 //don't destroy the other window handlers
3096 SetOnTop( WindowIndex
);
3097 evntmgr
->AddWindow( win
);
3098 evntmgr
->SetFocused( win
, NULL
);
3111 Region
r( 0, 0, Width
, Height
);
3113 if (Shadow
== MODAL_SHADOW_GRAY
) {
3114 video
->DrawRect( r
, gray
);
3115 } else if (Shadow
== MODAL_SHADOW_BLACK
) {
3116 video
->DrawRect( r
, black
);
3123 bool Interface::IsFreezed()
3125 return !update_scripts
;
3128 void Interface::GameLoop(void)
3130 update_scripts
= false;
3131 GameControl
*gc
= GetGameControl();
3133 update_scripts
= !(gc
->GetDialogueFlags() & DF_FREEZE_SCRIPTS
);
3136 GSUpdate(update_scripts
);
3138 //i'm not sure if this should be here
3140 //in multi player (if we ever get to it), only the server must call this
3141 if (update_scripts
) {
3142 if ( game
->selected
.size() > 0 ) {
3143 gc
->ChangeMap(GetFirstSelectedPC(true), false);
3145 // the game object will run the area scripts as well
3146 game
->UpdateScripts();
3150 /** handles hardcoded gui behaviour */
3151 void Interface::HandleGUIBehaviour(void)
3153 GameControl
*gc
= GetGameControl();
3155 //this variable is used all over in the following hacks
3156 int flg
= gc
->GetDialogueFlags();
3158 //the following part is a series of hardcoded gui behaviour
3161 if (flg
& DF_IN_DIALOG
) {
3166 ieDword var
= (ieDword
) -3;
3167 vars
->Lookup("DialogChoose", var
);
3168 if ((int) var
== -2) {
3169 gc
->dialoghandler
->EndDialog();
3170 } else if ( (int)var
!=-3) {
3171 gc
->dialoghandler
->DialogChoose(var
);
3172 if (!(gc
->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW
| DF_OPENENDWINDOW
)))
3173 guiscript
->RunFunction( "GUIWORLD", "NextDialogState" );
3175 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3176 ieDword newvar
= 0; vars
->Lookup("DialogChoose", newvar
);
3177 if (var
== (ieDword
) -1 || newvar
!= (ieDword
) -1) {
3178 vars
->SetAt("DialogChoose", (ieDword
) -3);
3181 if (flg
& DF_OPENCONTINUEWINDOW
) {
3182 guiscript
->RunFunction( "GUIWORLD", "OpenContinueMessageWindow" );
3183 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3184 } else if (flg
& DF_OPENENDWINDOW
) {
3185 guiscript
->RunFunction( "GUIWORLD", "OpenEndMessageWindow" );
3186 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3190 //handling container
3191 if (CurrentContainer
&& UseContainer
) {
3192 if (!(flg
& DF_IN_CONTAINER
) ) {
3193 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_OR
);
3194 guiscript
->RunFunction( "CommonWindow", "OpenContainerWindow" );
3197 if (flg
& DF_IN_CONTAINER
) {
3198 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_NAND
);
3199 guiscript
->RunFunction( "CommonWindow", "CloseContainerWindow" );
3206 void Interface::DrawWindows(void)
3208 //here comes the REAL drawing of windows
3210 ModalWindow
->DrawWindow();
3213 size_t i
= topwin
.size();
3215 unsigned int t
= topwin
[i
];
3217 if ( t
>=windows
.size() )
3220 //visible ==1 or 2 will be drawn
3221 Window
* win
= windows
[t
];
3223 if (win
->Visible
== WINDOW_INVALID
) {
3224 topwin
.erase(topwin
.begin()+i
);
3225 evntmgr
->DelWindow( win
);
3228 } else if (win
->Visible
) {
3235 void Interface::DrawTooltip ()
3237 if (! tooltip_ctrl
|| !tooltip_ctrl
->Tooltip
)
3240 Font
* fnt
= GetFont( TooltipFont
);
3241 char *tooltip_text
= tooltip_ctrl
->Tooltip
;
3245 int strw
= fnt
->CalcStringWidth( tooltip_text
) + 8;
3247 int h
= fnt
->maxHeight
;
3250 // animate BG tooltips
3251 // TODO: make tooltip animation an option instead
3252 // of following hard-coded check!
3253 if (TooltipMargin
== 5) {
3254 // TODO: make speed an option
3255 int tooltip_anim_speed
= 15;
3256 if (tooltip_currtextw
< strw
) {
3257 tooltip_currtextw
+= tooltip_anim_speed
;
3259 if (tooltip_currtextw
> strw
) {
3260 tooltip_currtextw
= strw
;
3262 w
= tooltip_currtextw
;
3265 h
= TooltipBack
[0]->Height
;
3266 w1
= TooltipBack
[1]->Width
;
3267 w2
= TooltipBack
[2]->Width
;
3268 w
+= TooltipMargin
*2;
3269 strw
+= TooltipMargin
*2;
3270 //multiline in case of too much text
3271 if (w
>TooltipBack
[0]->Width
)
3272 strw
=w
=TooltipBack
[0]->Width
;
3273 else if (strw
>TooltipBack
[0]->Width
)
3274 strw
=TooltipBack
[0]->Width
;
3277 int strx
= tooltip_x
- strw
/ 2;
3278 int y
= tooltip_y
- h
/ 2;
3279 // Ensure placement within the screen
3280 if (strx
< 0) strx
= 0;
3281 else if (strx
+ strw
+ w1
+ w2
> Width
)
3282 strx
= Width
- strw
- w1
- w2
;
3284 else if (y
+ h
> Height
)
3287 int x
= strx
+ ((strw
- w
) / 2);
3289 // FIXME: take back[0] from center, not from left end
3290 Region r2
= Region( x
, y
, w
, h
);
3292 video
->BlitSprite( TooltipBack
[0], x
+ TooltipMargin
, y
, true, &r2
);
3293 video
->BlitSprite( TooltipBack
[1], x
, y
, true );
3294 video
->BlitSprite( TooltipBack
[2], x
+ w
, y
, true );
3298 r2
.x
+=TooltipMargin
;
3299 strx
+=TooltipMargin
;
3301 Region textr
= Region( strx
, y
, strw
, h
);
3302 fnt
->Print( r2
, textr
, (ieByte
*) tooltip_text
, NULL
,
3303 IE_FONT_ALIGN_CENTER
| IE_FONT_ALIGN_MIDDLE
, true );
3306 //interface for higher level functions, if the window was
3307 //marked for deletion it is not returned
3308 Window
* Interface::GetWindow(unsigned short WindowIndex
) const
3310 if (WindowIndex
< windows
.size()) {
3311 Window
*win
= windows
[WindowIndex
];
3312 if (win
&& (win
->Visible
!=WINDOW_INVALID
) ) {
3319 // this function will determine if wnd is a valid window pointer
3320 // by checking if its WindowID is the same as the reference
3321 bool Interface::IsValidWindow(unsigned short WindowID
, Window
*wnd
) const
3323 size_t WindowIndex
= windows
.size();
3324 while (WindowIndex
--) {
3325 if (windows
[WindowIndex
] == wnd
) {
3326 return wnd
->WindowID
== WindowID
;
3332 //this function won't delete the window, just mark it for deletion
3333 //it will be deleted in the next DrawWindows cycle
3334 //regardless, the window deleted is inaccessible for gui scripts and
3335 //other high level functions from now
3336 int Interface::DelWindow(unsigned short WindowIndex
)
3338 if (WindowIndex
>= windows
.size()) {
3341 Window
* win
= windows
[WindowIndex
];
3342 if ((win
== NULL
) || (win
->Visible
==WINDOW_INVALID
) ) {
3343 printMessage( "Core", "Window deleted again", LIGHT_RED
);
3346 if (win
== ModalWindow
) {
3348 RedrawAll(); //marking windows for redraw
3350 evntmgr
->DelWindow( win
);
3352 //re-capturing new (old) modal window if any
3353 size_t tw
= topwin
.size();
3354 for(size_t i
=0;i
<tw
;i
++) {
3355 Window
*tmp
= windows
[topwin
[i
]];
3356 if (tmp
->Visible
==WINDOW_FRONT
) {
3364 void Interface::DelAllWindows()
3366 vars
->SetAt("MessageWindow", (ieDword
) ~0);
3367 vars
->SetAt("OptionsWindow", (ieDword
) ~0);
3368 vars
->SetAt("PortraitWindow", (ieDword
) ~0);
3369 vars
->SetAt("ActionsWindow", (ieDword
) ~0);
3370 vars
->SetAt("TopWindow", (ieDword
) ~0);
3371 vars
->SetAt("OtherWindow", (ieDword
) ~0);
3372 vars
->SetAt("FloatWindow", (ieDword
) ~0);
3373 for(unsigned int WindowIndex
=0; WindowIndex
<windows
.size();WindowIndex
++) {
3374 Window
* win
= windows
[WindowIndex
];
3383 /** Popup the Console */
3384 void Interface::PopupConsole()
3386 ConsolePopped
= !ConsolePopped
;
3388 console
->Changed
= true;
3391 /** Draws the Console */
3392 void Interface::DrawConsole()
3394 console
->Draw( 0, 0 );
3397 /** Get the Sound Manager */
3398 SaveGameIterator
* Interface::GetSaveGameIterator() const
3402 /** Sends a termination signal to the Video Driver */
3403 bool Interface::Quit(void)
3405 return video
->Quit();
3407 /** Returns the variables dictionary */
3408 Variables
* Interface::GetDictionary() const
3412 /** Returns the token dictionary */
3413 Variables
* Interface::GetTokenDictionary() const
3417 /** Get the Music Manager */
3418 MusicMgr
* Interface::GetMusicMgr() const
3422 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3423 int Interface::LoadSymbol(const char* ResRef
)
3425 int ind
= GetSymbolIndex( ResRef
);
3429 DataStream
* str
= gamedata
->GetResource( ResRef
, IE_IDS_CLASS_ID
);
3433 PluginHolder
<SymbolMgr
> sm(IE_IDS_CLASS_ID
);
3438 if (!sm
->Open( str
, true )) {
3442 strncpy( s
.ResRef
, ResRef
, 8 );
3445 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3446 if (!symbols
[i
].sm
) {
3455 symbols
.push_back( s
);
3456 return ( int ) symbols
.size() - 1;
3458 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3459 int Interface::GetSymbolIndex(const char* ResRef
) const
3461 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3464 if (strnicmp( symbols
[i
].ResRef
, ResRef
, 8 ) == 0)
3469 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3470 Holder
<SymbolMgr
> Interface::GetSymbol(unsigned int index
) const
3472 if (index
>= symbols
.size()) {
3473 return Holder
<SymbolMgr
>();
3475 if (!symbols
[index
].sm
) {
3476 return Holder
<SymbolMgr
>();
3478 return symbols
[index
].sm
;
3480 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3481 bool Interface::DelSymbol(unsigned int index
)
3483 if (index
>= symbols
.size()) {
3486 if (!symbols
[index
].sm
) {
3489 symbols
[index
].sm
.release();
3492 /** Plays a Movie */
3493 int Interface::PlayMovie(const char* ResRef
)
3495 ResourceHolder
<MoviePlayer
> mp(ResRef
);
3500 ieDword subtitles
= 0;
3501 Font
*SubtitleFont
= NULL
;
3502 Palette
*palette
= NULL
;
3503 ieDword
*frames
= NULL
;
3504 ieDword
*strrefs
= NULL
;
3508 //one of these two should exist (they both mean the same thing)
3509 vars
->Lookup("Display Movie Subtitles", subtitles
);
3516 vars
->Lookup("Display Subtitles", subtitles
);
3519 if (subtitles
&& sttable
.load(ResRef
)) {
3520 cnt
+= sttable
->GetRowCount();
3522 frames
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3523 strrefs
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3527 if (frames
&& strrefs
) {
3528 for (int i
=0;i
<cnt
;i
++) {
3529 frames
[i
] = atoi (sttable
->QueryField(i
+offset
, 0) );
3530 strrefs
[i
] = atoi (sttable
->QueryField(i
+offset
, 1) );
3533 int r
= atoi(sttable
->QueryField("red", "frame"));
3534 int g
= atoi(sttable
->QueryField("green", "frame"));
3535 int b
= atoi(sttable
->QueryField("blue", "frame"));
3536 SubtitleFont
= GetFont (MovieFont
); //will change
3539 Color fore
= {(unsigned char) r
,(unsigned char) g
,(unsigned char) b
, 0x00};
3540 Color back
= {0x00, 0x00, 0x00, 0x00};
3541 palette
= CreatePalette( fore
, back
);
3546 //shutting down music and ambients before movie
3549 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3550 if (ambim
) ambim
->deactivate();
3551 video
->SetMovieFont(SubtitleFont
, palette
);
3552 mp
->CallBackAtFrames(cnt
, frames
, strrefs
);
3554 gamedata
->FreePalette( palette
);
3562 if (ambim
) ambim
->activate();
3563 //this will fix redraw all windows as they looked like
3567 //Setting the movie name to 1
3568 vars
->SetAt( ResRef
, 1 );
3572 int Interface::Roll(int dice
, int size
, int add
) const
3581 return add
+ dice
* size
/ 2;
3583 for (int i
= 0; i
< dice
; i
++) {
3584 add
+= rand() % size
+ 1;
3589 static char bmp_suffix
[6]="M.BMP";
3590 static char png_suffix
[6]="M.PNG";
3592 int Interface::GetPortraits(TextArea
* ta
, bool smallorlarge
)
3595 char Path
[_MAX_PATH
];
3604 PathJoin( Path
, GamePath
, GamePortraitsPath
, NULL
);
3605 DirectoryIterator
dir(Path
);
3609 printf( "Looking in %s\n", Path
);
3611 char *name
= dir
.GetName();
3614 if (dir
.IsDirectory())
3617 char *pos
= strstr(name
,bmp_suffix
);
3618 if (!pos
&& IsAvailable(IE_PNG_CLASS_ID
) ) {
3619 pos
= strstr(name
,png_suffix
);
3624 ta
->AppendText( name
, -1 );
3629 int Interface::GetCharSounds(TextArea
* ta
)
3633 char Path
[_MAX_PATH
];
3635 PathJoin( Path
, GamePath
, GameSoundsPath
, NULL
);
3636 hasfolders
= ( HasFeature( GF_SOUNDFOLDERS
) != 0 );
3637 DirectoryIterator
dir(Path
);
3641 printf( "Looking in %s\n", Path
);
3643 char *name
= dir
.GetName();
3646 if (hasfolders
== !dir
.IsDirectory())
3650 char *pos
= strstr(name
,"A.WAV");
3655 ta
->AppendText( name
, -1 );
3660 int Interface::GetCharacters(TextArea
* ta
)
3663 char Path
[_MAX_PATH
];
3665 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
3666 DirectoryIterator
dir(Path
);
3670 printf( "Looking in %s\n", Path
);
3672 char *name
= dir
.GetName();
3675 if (dir
.IsDirectory())
3678 char *pos
= strstr(name
,".CHR");
3682 ta
->AppendText( name
, -1 );
3687 bool Interface::LoadINI(const char* filename
)
3690 config
= fopen( filename
, "rb" );
3691 if (config
== NULL
) {
3694 char name
[65], value
[_MAX_PATH
+ 3];
3695 while (!feof( config
)) {
3700 if (fread( &rem
, 1, 1, config
) != 1)
3703 if (( rem
== '#' ) ||
3711 } else if (rem
== '\n')
3714 //it should always return zero
3715 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
3719 fseek( config
, -1, SEEK_CUR
);
3720 //the * element is not counted
3721 if (fscanf( config
, "%[^=]=%[^\r\n]%*[\r\n]", name
, value
)!=2)
3723 if (( value
[0] >= '0' ) && ( value
[0] <= '9' )) {
3724 vars
->SetAt( name
, atoi( value
) );
3731 /** Enables/Disables the Cut Scene Mode */
3732 void Interface::SetCutSceneMode(bool active
)
3734 GameControl
*gc
= GetGameControl();
3736 gc
->SetCutSceneMode( active
);
3740 game
->ControlStatus
|= CS_HIDEGUI
;
3742 game
->ControlStatus
&= ~CS_HIDEGUI
;
3744 SetEventFlag(EF_CONTROL
);
3746 video
->SetMouseEnabled(!active
);
3749 bool Interface::InCutSceneMode() const
3751 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE
)!=0;
3754 void Interface::QuitGame(int BackToMain
)
3756 SetCutSceneMode(false);
3759 //clear fade/screenshake effects
3761 timer
->SetFadeFromColor(0);
3764 DelAllWindows(); //delete all windows, including GameControl
3766 //shutting down ingame music
3767 //(do it before deleting the game)
3771 // stop any ambients which are still enqueued
3773 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3774 if (ambim
) ambim
->deactivate();
3776 //delete game, worldmap
3786 strcpy(NextScript
, "Start");
3787 QuitFlag
|= QF_CHANGESCRIPT
;
3792 void Interface::SetupLoadGame(Holder
<SaveGame
> sg
, int ver_override
)
3795 VersionOverride
= ver_override
;
3796 QuitFlag
|= QF_LOADGAME
;
3799 void Interface::LoadGame(SaveGame
*sg
, int ver_override
)
3801 // This function has rather painful error handling,
3802 // as it should swap all the objects or none at all
3803 // and the loading can fail for various reasons
3805 // Yes, it uses goto. Other ways seemed too awkward for me.
3807 strings
->CloseAux();
3808 tokens
->RemoveAll(NULL
); //clearing the token dictionary
3810 if(calendar
) delete calendar
;
3811 calendar
= new Calendar
;
3813 DataStream
* gam_str
= NULL
;
3814 DataStream
* sav_str
= NULL
;
3815 DataStream
* wmp_str1
= NULL
;
3816 DataStream
* wmp_str2
= NULL
;
3818 Game
* new_game
= NULL
;
3819 WorldMapArray
* new_worldmap
= NULL
;
3822 if (!KeepCache
) DelTree((const char *) CachePath
, true);
3826 //Load the Default Game
3827 gam_str
= gamedata
->GetResource( GameNameResRef
, IE_GAM_CLASS_ID
);
3829 wmp_str1
= gamedata
->GetResource( WorldMapName
[0], IE_WMP_CLASS_ID
);
3830 if (WorldMapName
[1][0]) {
3831 wmp_str2
= gamedata
->GetResource( WorldMapName
[1], IE_WMP_CLASS_ID
);
3834 gam_str
= sg
->GetGame();
3835 sav_str
= sg
->GetSave();
3836 wmp_str1
= sg
->GetWmap(0);
3837 if (WorldMapName
[1][0]) {
3838 wmp_str2
= sg
->GetWmap(1);
3840 //upgrade an IWD game to HOW
3841 wmp_str2
= gamedata
->GetResource( WorldMapName
[1], IE_WMP_CLASS_ID
);
3846 // These are here because of the goto
3847 PluginHolder
<SaveGameMgr
> gam_mgr(IE_GAM_CLASS_ID
);
3848 PluginHolder
<WorldMapMgr
> wmp_mgr(IE_WMP_CLASS_ID
);
3850 if (!gam_str
|| !(wmp_str1
|| wmp_str2
) )
3857 if (!gam_mgr
->Open( gam_str
, true ))
3860 new_game
= gam_mgr
->LoadGame(new Game(), ver_override
);
3866 // Load WMP (WorldMap) file
3870 if (!wmp_mgr
->Open( wmp_str1
, wmp_str2
, true ))
3873 new_worldmap
= wmp_mgr
->GetWorldMapArray( );
3879 // Unpack SAV (archive) file to Cache dir
3881 PluginHolder
<ArchiveImporter
> ai(IE_BIF_CLASS_ID
);
3883 if (ai
->DecompressSaveGame(sav_str
) != GEM_OK
) {
3891 // Let's assume that now is everything loaded OK and swap the objects
3897 worldmap
= new_worldmap
;
3903 // Something went wrong, so try to clean after itself
3906 delete new_worldmap
;
3914 /* swapping out old resources */
3915 void Interface::UpdateMasterScript()
3918 game
->SetScript( GlobalScript
, 0 );
3921 PluginHolder
<WorldMapMgr
> wmp_mgr(IE_WMP_CLASS_ID
);
3926 DataStream
*wmp_str1
= gamedata
->GetResource( WorldMapName
[0], IE_WMP_CLASS_ID
);
3927 DataStream
*wmp_str2
= gamedata
->GetResource( WorldMapName
[1], IE_WMP_CLASS_ID
);
3929 if (!wmp_mgr
->Open( wmp_str1
, wmp_str2
, true )) {
3935 worldmap
= wmp_mgr
->GetWorldMapArray();
3939 bool Interface::HideGCWindow()
3941 Window
*window
= GetWindow( 0 );
3942 // in the beginning, there's no window at all
3946 Control
* gc
= window
->GetControl(0);
3947 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
) {
3950 SetVisible(0, WINDOW_INVISIBLE
);
3954 void Interface::UnhideGCWindow()
3956 Window
*window
= GetWindow( 0 );
3959 Control
* gc
= window
->GetControl(0);
3960 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
)
3962 SetVisible(0, WINDOW_VISIBLE
);
3965 GameControl
*Interface::GetGameControl() const
3967 Window
*window
= GetWindow( 0 );
3968 // in the beginning, there's no window at all
3972 Control
* gc
= window
->GetControl(0);
3976 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
) {
3979 return (GameControl
*) gc
;
3982 bool Interface::InitItemTypes()
3987 AutoTable
it("itemtype");
3990 ItemTypes
= it
->GetRowCount(); //number of itemtypes
3994 int InvSlotTypes
= it
->GetColumnCount();
3995 if (InvSlotTypes
> 32) { //bit count limit
3998 //make sure unsigned int is 32 bits
3999 slotmatrix
= (ieDword
*) malloc(ItemTypes
* sizeof(ieDword
) );
4000 for (int i
=0;i
<ItemTypes
;i
++) {
4001 unsigned int value
= 0;
4003 for (int j
=0;j
<InvSlotTypes
;j
++) {
4004 if (strtol(it
->QueryField(i
,j
),NULL
,0) ) {
4009 //we let any items in the inventory
4010 slotmatrix
[i
] = (ieDword
) value
| SLOT_INVENTORY
;
4014 //slottype describes the inventory structure
4015 Inventory::Init(HasFeature(GF_MAGICBIT
));
4016 AutoTable
st("slottype");
4023 SlotTypes
= st
->GetRowCount();
4024 //make sure unsigned int is 32 bits
4025 slottypes
= (SlotType
*) malloc(SlotTypes
* sizeof(SlotType
) );
4026 memset(slottypes
, -1, SlotTypes
* sizeof(SlotType
) );
4027 for (unsigned int row
= 0; row
< SlotTypes
; row
++) {
4029 unsigned int i
= (ieDword
) strtol(st
->GetRowName(row
),NULL
,0 );
4030 if (i
>=SlotTypes
) continue;
4031 if (slottypes
[i
].sloteffects
!=0xffffffffu
) {
4032 slottypes
[row
].slot
= i
;
4036 slottypes
[row
].slot
= i
;
4039 slottypes
[i
].slottype
= (ieDword
) strtol(st
->QueryField(row
,0),NULL
,0 );
4040 slottypes
[i
].slotid
= (ieDword
) strtol(st
->QueryField(row
,1),NULL
,0 );
4041 strnlwrcpy( slottypes
[i
].slotresref
, st
->QueryField(row
,2), 8 );
4042 slottypes
[i
].slottip
= (ieDword
) strtol(st
->QueryField(row
,3),NULL
,0 );
4043 slottypes
[i
].slotflags
= (ieDword
) strtol(st
->QueryField(row
,5),NULL
,0 );
4044 //don't fill sloteffects for aliased slots (pst)
4048 slottypes
[i
].sloteffects
= (ieDword
) strtol(st
->QueryField(row
,4),NULL
,0 );
4049 //setting special slots
4050 if (slottypes
[i
].slottype
&SLOT_ITEM
) {
4051 if (slottypes
[i
].slottype
&SLOT_INVENTORY
) {
4052 Inventory::SetInventorySlot(i
);
4054 Inventory::SetQuickSlot(i
);
4057 switch (slottypes
[i
].sloteffects
) {
4058 //fist slot, not saved, default weapon
4059 case SLOT_EFFECT_FIST
: Inventory::SetFistSlot(i
); break;
4060 //magic weapon slot, overrides all weapons
4061 case SLOT_EFFECT_MAGIC
: Inventory::SetMagicSlot(i
); break;
4062 //weapon slot, Equipping marker is relative to it
4063 case SLOT_EFFECT_MELEE
: Inventory::SetWeaponSlot(i
); break;
4065 case SLOT_EFFECT_MISSILE
: Inventory::SetRangedSlot(i
); break;
4067 case SLOT_EFFECT_LEFT
: Inventory::SetShieldSlot(i
); break;
4068 //head (for averting critical hit)
4069 case SLOT_EFFECT_HEAD
: Inventory::SetHeadSlot(i
); break;
4077 ieDword
Interface::FindSlot(unsigned int idx
) const
4081 for (i
=0;i
<SlotTypes
;i
++) {
4082 if (idx
==slottypes
[i
].slot
) {
4089 ieDword
Interface::QuerySlot(unsigned int idx
) const
4091 if (idx
>=SlotTypes
) {
4094 return slottypes
[idx
].slot
;
4097 ieDword
Interface::QuerySlotType(unsigned int idx
) const
4099 if (idx
>=SlotTypes
) {
4102 return slottypes
[idx
].slottype
;
4105 ieDword
Interface::QuerySlotID(unsigned int idx
) const
4107 if (idx
>=SlotTypes
) {
4110 return slottypes
[idx
].slotid
;
4113 ieDword
Interface::QuerySlottip(unsigned int idx
) const
4115 if (idx
>=SlotTypes
) {
4118 return slottypes
[idx
].slottip
;
4121 ieDword
Interface::QuerySlotEffects(unsigned int idx
) const
4123 if (idx
>=SlotTypes
) {
4126 return slottypes
[idx
].sloteffects
;
4129 ieDword
Interface::QuerySlotFlags(unsigned int idx
) const
4131 if (idx
>=SlotTypes
) {
4134 return slottypes
[idx
].slotflags
;
4137 const char *Interface::QuerySlotResRef(unsigned int idx
) const
4139 if (idx
>=SlotTypes
) {
4142 return slottypes
[idx
].slotresref
;
4145 // checks the itemtype vs. slottype, and also checks the usability flags
4146 // vs. Actor's stats (alignment, class, race, kit etc.)
4147 int Interface::CanUseItemType(int slottype
, Item
*item
, Actor
*actor
, bool feedback
, bool equipped
) const
4149 //inventory is a special case, we allow any items to enter it
4150 if ( slottype
==-1 ) {
4151 return SLOT_INVENTORY
;
4153 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
4154 //with twohandedness
4155 //As long as this is an Item, use the ITEM constant
4156 //switch for IE_INV_ITEM_* if it is a CREItem
4157 if (item
->Flags
&IE_ITEM_TWO_HANDED
) {
4158 //if the item is twohanded and there are more slots, drop the shield slot
4159 if (slottype
&~SLOT_SHIELD
) {
4160 slottype
&=~SLOT_SHIELD
;
4162 if (slottype
&SLOT_SHIELD
) {
4163 //cannot equip twohanded in offhand
4164 if (feedback
) displaymsg
->DisplayConstantString(STR_NOT_IN_OFFHAND
, 0xf0f0f0);
4169 if ( (unsigned int) item
->ItemType
>=(unsigned int) ItemTypes
) {
4171 if (feedback
) displaymsg
->DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4175 //if actor is supplied, check its usability fields
4178 int idx
= actor
->Unusable(item
);
4180 if (feedback
) displaymsg
->DisplayConstantString(idx
, 0xf0f0f0);
4184 ieStrRef str
= actor
->Disabled(item
->Name
, item
->ItemType
);
4185 if (str
&& !equipped
) {
4186 if (feedback
) displaymsg
->DisplayString(str
, 0xf0f0f0, 0);
4191 //if any bit is true, the answer counts as true
4192 int ret
= (slotmatrix
[item
->ItemType
]&slottype
);
4195 if (feedback
) displaymsg
->DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4199 //this warning comes only when feedback is enabled
4201 //this was, but that disabled equipping of amber earrings in PST
4202 //if (slotmatrix[item->ItemType]&(SLOT_QUIVER|SLOT_WEAPON|SLOT_ITEM)) {
4203 if (ret
&(SLOT_QUIVER
|SLOT_WEAPON
|SLOT_ITEM
)) {
4204 //don't ruin the return variable, it contains the usable slot bits
4206 if (ret
&SLOT_QUIVER
) {
4207 if (item
->GetWeaponHeader(true)) flg
= 1;
4210 if (ret
&SLOT_WEAPON
) {
4212 if (item
->GetWeaponHeader(false)) flg
= 1;
4214 if (item
->GetWeaponHeader(true)) flg
= 1;
4217 if (ret
&SLOT_ITEM
) {
4218 if (item
->GetEquipmentHeaderNumber(0)!=0xffff) flg
= 1;
4222 displaymsg
->DisplayConstantString(STR_UNUSABLEITEM
, 0xf0f0f0);
4231 Label
*Interface::GetMessageLabel() const
4233 ieDword WinIndex
= (ieDword
) -1;
4234 ieDword TAIndex
= (ieDword
) -1;
4236 vars
->Lookup( "OtherWindow", WinIndex
);
4237 if (( WinIndex
!= (ieDword
) -1 ) &&
4238 ( vars
->Lookup( "MessageLabel", TAIndex
) )) {
4239 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4241 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4242 if (ctrl
&& ctrl
->ControlType
==IE_GUI_LABEL
)
4243 return (Label
*) ctrl
;
4249 TextArea
*Interface::GetMessageTextArea() const
4251 ieDword WinIndex
= (ieDword
) -1;
4252 ieDword TAIndex
= (ieDword
) -1;
4254 vars
->Lookup( "MessageWindow", WinIndex
);
4255 if (( WinIndex
!= (ieDword
) -1 ) &&
4256 ( vars
->Lookup( "MessageTextArea", TAIndex
) )) {
4257 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4259 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4260 if (ctrl
&& ctrl
->ControlType
==IE_GUI_TEXTAREA
)
4261 return (TextArea
*) ctrl
;
4267 static const char *saved_extensions
[]={".are",".sto",0};
4268 static const char *saved_extensions_last
[]={".tot",".toh",0};
4270 //returns the priority of the file to be saved
4274 int Interface::SavedExtension(const char *filename
)
4276 const char *str
=strchr(filename
,'.');
4279 while(saved_extensions
[i
]) {
4280 if (!stricmp(saved_extensions
[i
], str
) ) return 2;
4284 while(saved_extensions_last
[i
]) {
4285 if (!stricmp(saved_extensions_last
[i
], str
) ) return 1;
4291 static const char *protected_extensions
[]={".exe",".dll",".so",0};
4293 //returns true if file should be saved
4294 bool Interface::ProtectedExtension(const char *filename
)
4296 const char *str
=strchr(filename
,'.');
4297 if (!str
) return false;
4299 while(protected_extensions
[i
]) {
4300 if (!stricmp(protected_extensions
[i
], str
) ) return true;
4306 void Interface::RemoveFromCache(const ieResRef resref
, SClass_ID ClassID
)
4308 char filename
[_MAX_PATH
];
4310 snprintf(filename
, _MAX_PATH
, "%s%.8s%s", CachePath
, resref
, TypeExt( ClassID
) );
4314 //this function checks if the path is eligible as a cache
4315 //if it contains a directory, or suspicious file extensions
4316 //we bail out, because the cache will be purged regularly.
4317 bool Interface::StupidityDetector(const char* Pt
)
4319 char Path
[_MAX_PATH
];
4321 DirectoryIterator
dir(Path
);
4323 printf("\n**cannot open**\n");
4327 const char *name
= dir
.GetName();
4328 if (dir
.IsDirectory()) {
4329 if (name
[0] == '.') {
4330 if (name
[1] == '\0')
4332 if (name
[1] == '.' && name
[2] == '\0')
4335 printf("\n**contains another dir**\n");
4336 return true; //a directory in there???
4338 if (ProtectedExtension(name
) ) {
4339 printf("\n**contains alien files**\n");
4340 return true; //an executable file in there???
4343 //ok, we got a good conscience
4347 void Interface::DelTree(const char* Pt
, bool onlysave
)
4349 char Path
[_MAX_PATH
];
4351 if (!Pt
[0]) return; //Don't delete the root filesystem :)
4353 DirectoryIterator
dir(Path
);
4358 char *name
= dir
.GetName();
4359 if (dir
.IsDirectory())
4363 if (!onlysave
|| SavedExtension(name
) ) {
4364 char dtmp
[_MAX_PATH
];
4365 dir
.GetFullPath(dtmp
);
4371 void Interface::LoadProgress(int percent
)
4373 vars
->SetAt("Progress", percent
);
4374 RedrawControls("Progress", percent
);
4377 video
->SwapBuffers();
4380 void Interface::ReleaseDraggedItem()
4382 DraggedItem
=NULL
; //shouldn't free this
4383 video
->SetDragCursor (NULL
);
4386 void Interface::DragItem(CREItem
*item
, const ieResRef Picture
)
4388 //We should drop the dragged item and pick this up,
4389 //we shouldn't have a valid DraggedItem at this point.
4390 //Anyway, if there is still a dragged item, it will be destroyed.
4392 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW
);
4397 Sprite2D
* DraggedCursor
= NULL
;
4399 DraggedCursor
= gamedata
->GetBAMSprite( Picture
, 0, 0 );
4401 video
->SetDragCursor (DraggedCursor
);
4405 void Interface::SetDraggedPortrait(int dp
, int idx
)
4408 DraggedPortrait
= dp
;
4410 //hmm this might work?
4411 Cursors
[idx
]->acquire();
4412 video
->SetDragCursor(Cursors
[idx
]);
4414 video
->SetDragCursor(NULL
);
4418 bool Interface::ReadItemTable(const ieResRef TableName
, const char * Prefix
)
4423 AutoTable
tab(TableName
);
4427 i
=tab
->GetRowCount();
4430 snprintf(ItemName
,sizeof(ItemName
),"%s%02d",Prefix
, j
+1);
4432 strnlwrcpy(ItemName
,tab
->GetRowName(j
), 8);
4434 //Variable elements are free'd, so we have to use malloc
4435 //well, not anymore, we can use ReleaseFunction
4436 int l
=tab
->GetColumnCount(j
);
4438 int cl
= atoi(tab
->GetColumnName(0));
4439 ItemList
*itemlist
= new ItemList(l
, cl
);
4440 for(int k
=0;k
<l
;k
++) {
4441 strnlwrcpy(itemlist
->ResRefs
[k
],tab
->QueryField(j
,k
), 8);
4443 RtRows
->SetAt(ItemName
, (void*)itemlist
);
4448 bool Interface::ReadRandomItems()
4453 ieDword difflev
=0; //rt norm or rt fury
4454 vars
->Lookup("Nightmare Mode", difflev
);
4456 RtRows
->RemoveAll(ReleaseItemList
);
4459 RtRows
=new Variables(10, 17); //block size, hash table size
4463 RtRows
->SetType( GEM_VARIABLES_POINTER
);
4465 AutoTable
tab("randitem");
4469 if (difflev
>=tab
->GetColumnCount()) {
4470 difflev
= tab
->GetColumnCount()-1;
4474 strnlwrcpy( GoldResRef
, tab
->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4475 if ( GoldResRef
[0]=='*' ) {
4478 strnlwrcpy( RtResRef
, tab
->QueryField( 1, difflev
), 8);
4481 ReadItemTable( RtResRef
, 0 ); //reading the table itself
4488 strnlwrcpy( RtResRef
, tab
->QueryField(2+i
,difflev
), 8);
4489 ReadItemTable( RtResRef
,tab
->GetRowName(2+i
) );
4494 CREItem
*Interface::ReadItem(DataStream
*str
)
4496 CREItem
*itm
= new CREItem();
4498 str
->ReadResRef( itm
->ItemResRef
);
4499 str
->ReadWord( &itm
->Expired
);
4500 str
->ReadWord( &itm
->Usages
[0] );
4501 str
->ReadWord( &itm
->Usages
[1] );
4502 str
->ReadWord( &itm
->Usages
[2] );
4503 str
->ReadDword( &itm
->Flags
);
4504 if (ResolveRandomItem(itm
) ) {
4513 //This function generates random items based on the randitem.2da file
4514 //there could be a loop, but we don't want to freeze, so there is a limit
4515 bool Interface::ResolveRandomItem(CREItem
*itm
)
4517 if (!RtRows
) return true;
4518 for(int loop
=0;loop
<MAX_LOOP
;loop
++) {
4524 if ( !RtRows
->Lookup( itm
->ItemResRef
, lookup
) ) {
4527 ItemList
*itemlist
= (ItemList
*)lookup
;
4528 if (itemlist
->WeightOdds
) {
4529 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4530 i
=Roll(2,(itemlist
->Count
+1)/2,-2);
4532 i
=Roll(1,itemlist
->Count
,-1);
4534 strnlwrcpy( NewItem
, itemlist
->ResRefs
[i
], 8);
4535 char *p
=(char *) strchr(NewItem
,'*');
4537 *p
=0; //doing this so endptr is ok
4538 k
=strtol(p
+1,NULL
,10);
4542 j
=strtol(NewItem
,&endptr
,10);
4547 strnlwrcpy(itm
->ItemResRef
, NewItem
, 8);
4549 strnlwrcpy(itm
->ItemResRef
, GoldResRef
, 8);
4551 if ( !memcmp( itm
->ItemResRef
,"no_drop",8 ) ) {
4552 itm
->ItemResRef
[0]=0;
4554 if (!itm
->ItemResRef
[0]) {
4557 itm
->Usages
[0]=(ieWord
) Roll(j
,k
,0);
4559 printMessage("Interface"," ",LIGHT_RED
);
4560 printf("Loop detected while generating random item:%s\n",itm
->ItemResRef
);
4564 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4565 //these functions are needed because Win32 doesn't allow freeing memory from
4566 //another dll. So we allocate all commonly used memories from core
4567 ITMExtHeader
*Interface::GetITMExt(int count
)
4569 return new ITMExtHeader
[count
];
4572 SPLExtHeader
*Interface::GetSPLExt(int count
)
4574 return new SPLExtHeader
[count
];
4577 Effect
*Interface::GetEffect(ieDword opcode
)
4579 if (opcode
==0xffffffff) {
4582 Effect
*fx
= new Effect();
4586 memset(fx
,0,sizeof(Effect
));
4591 Effect
*Interface::GetFeatures(int count
)
4593 return new Effect
[count
];
4597 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4603 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4610 WorldMapArray
*Interface::NewWorldMapArray(int count
)
4612 return new WorldMapArray(count
);
4615 Container
*Interface::GetCurrentContainer()
4617 return CurrentContainer
;
4620 int Interface::CloseCurrentContainer()
4622 UseContainer
= false;
4623 if ( !CurrentContainer
) {
4626 //remove empty ground piles on closeup
4627 CurrentContainer
->GetCurrentArea()->TMap
->CleanupContainer(CurrentContainer
);
4628 CurrentContainer
= NULL
;
4632 void Interface::SetCurrentContainer(Actor
*actor
, Container
*arg
, bool flag
)
4634 //abort action if the first selected PC isn't the original actor
4635 if (actor
!=GetFirstSelectedPC(false)) {
4636 CurrentContainer
= NULL
;
4639 CurrentContainer
= arg
;
4640 UseContainer
= flag
;
4643 Store
*Interface::GetCurrentStore()
4645 return CurrentStore
;
4648 int Interface::CloseCurrentStore()
4650 if ( !CurrentStore
) {
4653 PluginHolder
<StoreMgr
> sm(IE_STO_CLASS_ID
);
4657 int size
= sm
->GetStoredFileSize (CurrentStore
);
4659 //created streams are always autofree (close file on destruct)
4660 //this one will be destructed when we return from here
4663 str
.Create( CurrentStore
->Name
, IE_STO_CLASS_ID
);
4664 int ret
= sm
->PutStore (&str
, CurrentStore
);
4666 printMessage("Core"," ", YELLOW
);
4667 printf("Store removed: %s\n", CurrentStore
->Name
);
4668 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4671 printMessage("Core"," ", YELLOW
);
4672 printf("Store removed: %s\n", CurrentStore
->Name
);
4673 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4675 //make sure the stream isn't connected to sm, or it will be double freed
4676 delete CurrentStore
;
4677 CurrentStore
= NULL
;
4681 Store
*Interface::SetCurrentStore(const ieResRef resname
, ieDword owner
)
4683 if ( CurrentStore
) {
4684 if ( !strnicmp(CurrentStore
->Name
, resname
, 8) ) {
4685 return CurrentStore
;
4688 //not simply delete the old store, but save it
4689 CloseCurrentStore();
4692 DataStream
* str
= gamedata
->GetResource( resname
, IE_STO_CLASS_ID
);
4693 PluginHolder
<StoreMgr
> sm(IE_STO_CLASS_ID
);
4698 if (!sm
->Open( str
, true )) {
4702 // FIXME - should use some already allocated in core
4703 // not really, only one store is open at a time, then it is
4704 // unloaded, we don't really have to cache it, it will be saved in
4706 CurrentStore
= sm
->GetStore( new Store() );
4707 if (CurrentStore
== NULL
) {
4710 strnlwrcpy(CurrentStore
->Name
, resname
, 8);
4712 CurrentStore
->SetOwnerID(owner
);
4714 return CurrentStore
;
4717 void Interface::SetMouseScrollSpeed(int speed
) {
4718 mousescrollspd
= (speed
+1)*2;
4721 int Interface::GetMouseScrollSpeed() {
4722 return mousescrollspd
;
4725 ieStrRef
Interface::GetRumour(const ieResRef dlgref
)
4727 PluginHolder
<DialogMgr
> dm(IE_DLG_CLASS_ID
);
4728 dm
->Open( gamedata
->GetResource( dlgref
, IE_DLG_CLASS_ID
), true );
4729 Dialog
*dlg
= dm
->GetDialog();
4732 printMessage("Interface"," ", LIGHT_RED
);
4733 printf( "Cannot load dialog: %s\n", dlgref
);
4734 return (ieStrRef
) -1;
4736 Scriptable
*pc
=game
->GetPC( game
->GetSelectedPCSingle(), false );
4738 ieStrRef ret
= (ieStrRef
) -1;
4739 int i
= dlg
->FindRandomState( pc
);
4741 ret
= dlg
->GetState( i
)->StrRef
;
4747 void Interface::DoTheStoreHack(Store
*s
)
4749 size_t size
= s
->PurchasedCategoriesCount
* sizeof( ieDword
);
4750 s
->purchased_categories
=(ieDword
*) malloc(size
);
4752 size
= s
->CuresCount
* sizeof( STOCure
);
4753 s
->cures
=(STOCure
*) malloc(size
);
4755 size
= s
->DrinksCount
* sizeof( STODrink
);
4756 s
->drinks
=(STODrink
*) malloc(size
);
4758 for(size
=0;size
<s
->ItemsCount
;size
++) {
4759 STOItem
*si
= new STOItem();
4760 memset(si
, 0, sizeof(STOItem
) );
4761 s
->items
.push_back( si
);
4765 //plays stock sound listed in defsound.2da
4766 void Interface::PlaySound(int index
)
4768 if (index
<=DSCount
) {
4769 AudioDriver
->Play(DefSound
[index
]);
4773 Actor
*Interface::GetFirstSelectedPC(bool forced
)
4775 int partySize
= game
->GetPartySize( false );
4776 if (!partySize
) return NULL
;
4777 for (int i
= 0; i
< partySize
; i
++) {
4778 Actor
* actor
= game
->GetPC( i
,false );
4779 if (actor
->IsSelected()) {
4785 return game
->GetPC(0,false);
4790 Actor
*Interface::GetFirstSelectedActor()
4792 if (game
->selected
.size()) {
4793 return game
->selected
[0];
4798 //this is used only for the console
4799 Sprite2D
*Interface::GetCursorSprite()
4801 Sprite2D
*spr
= gamedata
->GetBAMSprite(CursorBam
, 0, 0);
4804 if(HasFeature(GF_OVERRIDE_CURSORPOS
))
4807 spr
->YPos
=spr
->Height
-1;
4813 Sprite2D
*Interface::GetScrollCursorSprite(int frameNum
, int spriteNum
)
4815 return gamedata
->GetBAMSprite(ScrollCursorBam
, frameNum
, spriteNum
);
4818 /* we should return -1 if it isn't gold, otherwise return the gold value */
4819 int Interface::CanMoveItem(const CREItem
*item
) const
4821 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4822 if (!HasFeature(GF_NO_DROP_CAN_MOVE
) ) {
4823 if (item
->Flags
& IE_INV_ITEM_UNDROPPABLE
)
4826 //not gold, we allow only one single coin ResRef, this is good
4827 //for all of the original games
4828 if (strnicmp(item
->ItemResRef
, GoldResRef
, 8 ) )
4830 //gold, returns the gold value (stack size)
4831 return item
->Usages
[0];
4834 // dealing with applying effects
4835 void Interface::ApplySpell(const ieResRef resname
, Actor
*actor
, Scriptable
*caster
, int level
)
4837 Spell
*spell
= gamedata
->GetSpell(resname
);
4842 level
= spell
->GetHeaderIndexFromLevel(level
);
4843 EffectQueue
*fxqueue
= spell
->GetEffectBlock(caster
, actor
->Pos
, level
);
4845 ApplyEffectQueue(fxqueue
, actor
, caster
, actor
->Pos
);
4849 void Interface::ApplySpellPoint(const ieResRef resname
, Map
* area
, const Point
&pos
, Scriptable
*caster
, int level
)
4851 Spell
*spell
= gamedata
->GetSpell(resname
);
4855 level
= spell
->GetHeaderIndexFromLevel(level
);
4856 Projectile
*pro
= spell
->GetProjectile(caster
, level
, pos
);
4857 pro
->SetCaster(caster
->GetGlobalID());
4858 area
->AddProjectile(pro
, caster
->Pos
, pos
);
4861 //-1 means the effect was reflected back to the caster
4862 //0 means the effect was resisted and should be removed
4863 //1 means the effect was applied
4864 int Interface::ApplyEffect(Effect
*effect
, Actor
*actor
, Scriptable
*caster
)
4870 EffectQueue
*fxqueue
= new EffectQueue();
4871 //AddEffect now copies the fx data, please delete your effect reference
4872 //if you created it. (Don't delete cached references)
4873 fxqueue
->AddEffect( effect
);
4874 int res
= ApplyEffectQueue(fxqueue
, actor
, caster
);
4879 int Interface::ApplyEffectQueue(EffectQueue
*fxqueue
, Actor
*actor
, Scriptable
*caster
)
4882 p
.empty(); //the effect should have all its coordinates already set
4883 return ApplyEffectQueue(fxqueue
, actor
, caster
, p
);
4886 int Interface::ApplyEffectQueue(EffectQueue
*fxqueue
, Actor
*actor
, Scriptable
*caster
, Point p
)
4888 int res
= fxqueue
->CheckImmunity ( actor
);
4891 //bounced back at a nonliving caster
4892 if (caster
->Type
!=ST_ACTOR
) {
4895 actor
= (Actor
*) caster
;
4897 fxqueue
->SetOwner( caster
);
4899 if (fxqueue
->AddAllEffects( actor
, p
)==FX_NOT_APPLIED
) {
4906 Effect
*Interface::GetEffect(const ieResRef resname
, int level
, const Point
&p
)
4908 //Don't free this reference, it is cached!
4909 Effect
*effect
= gamedata
->GetEffect(resname
);
4916 effect
->Power
= level
;
4922 // dealing with saved games
4923 int Interface::SwapoutArea(Map
*map
)
4925 PluginHolder
<MapMgr
> mm(IE_ARE_CLASS_ID
);
4929 int size
= mm
->GetStoredFileSize (map
);
4931 //created streams are always autofree (close file on destruct)
4932 //this one will be destructed when we return from here
4935 str
.Create( map
->GetScriptName(), IE_ARE_CLASS_ID
);
4936 int ret
= mm
->PutArea (&str
, map
);
4938 printMessage("Core"," ", YELLOW
);
4939 printf("Area removed: %s\n", map
->GetScriptName());
4940 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4943 printMessage("Core"," ", YELLOW
);
4944 printf("Area removed: %s\n", map
->GetScriptName());
4945 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4947 //make sure the stream isn't connected to sm, or it will be double freed
4951 int Interface::WriteCharacter(const char *name
, Actor
*actor
)
4953 char Path
[_MAX_PATH
];
4955 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
4959 PluginHolder
<ActorMgr
> gm(IE_CRE_CLASS_ID
);
4968 str
.Create( Path
, name
, IE_CHR_CLASS_ID
);
4970 int ret
= gm
->PutActor(&str
, actor
, true);
4972 printMessage("Core"," ", YELLOW
);
4973 printf("Character cannot be saved: %s\n", name
);
4978 //write the BIO string
4979 if (!HasFeature(GF_NO_BIOGRAPHY
)) {
4982 str
.Create( Path
, name
, IE_BIO_CLASS_ID
);
4983 //never write the string reference into this string
4984 char *tmp
= GetString(actor
->GetVerbalConstant(VB_BIO
),IE_STR_STRREFOFF
);
4985 str
.Write (tmp
, strlen(tmp
));
4991 int Interface::WriteGame(const char *folder
)
4993 PluginHolder
<SaveGameMgr
> gm(IE_GAM_CLASS_ID
);
4998 int size
= gm
->GetStoredFileSize (game
);
5000 //created streams are always autofree (close file on destruct)
5001 //this one will be destructed when we return from here
5004 str
.Create( folder
, GameNameResRef
, IE_GAM_CLASS_ID
);
5005 int ret
= gm
->PutGame (&str
, game
);
5007 printMessage("Core"," ", YELLOW
);
5008 printf("Game cannot be saved: %s\n", folder
);
5012 printMessage("Core"," ", YELLOW
);
5013 printf("Internal error, game cannot be saved: %s\n", folder
);
5019 int Interface::WriteWorldMap(const char *folder
)
5021 PluginHolder
<WorldMapMgr
> wmm(IE_WMP_CLASS_ID
);
5026 if (WorldMapName
[1][0]) {
5027 worldmap
->SetSingle(false);
5030 int size1
= wmm
->GetStoredFileSize (worldmap
, 0);
5031 int size2
= 1; //just a dummy value
5033 //if size is 0 for the first worldmap, then there is a problem
5034 if (!worldmap
->IsSingle() && (size1
>0) ) {
5035 size2
=wmm
->GetStoredFileSize (worldmap
, 1);
5039 if ((size1
< 0) || (size2
<0) ) {
5042 //created streams are always autofree (close file on destruct)
5043 //this one will be destructed when we return from here
5047 str1
.Create( folder
, WorldMapName
[0], IE_WMP_CLASS_ID
);
5048 if (!worldmap
->IsSingle()) {
5049 str2
.Create( folder
, WorldMapName
[1], IE_WMP_CLASS_ID
);
5051 ret
= wmm
->PutWorldMap (&str1
, &str2
, worldmap
);
5054 printMessage("Core"," ", YELLOW
);
5055 printf("Internal error, worldmap cannot be saved: %s\n", folder
);
5061 int Interface::CompressSave(const char *folder
)
5065 str
.Create( folder
, GameNameResRef
, IE_SAV_CLASS_ID
);
5066 DirectoryIterator
dir(CachePath
);
5070 //BIF and SAV are the same
5071 PluginHolder
<ArchiveImporter
> ai(IE_BIF_CLASS_ID
);
5072 ai
->CreateArchive( &str
);
5074 //.tot and .toh should be saved last, because they are updated when an .are is saved
5078 const char *name
= dir
.GetName();
5079 if (dir
.IsDirectory())
5083 if (SavedExtension(name
)==priority
) {
5084 char dtmp
[_MAX_PATH
];
5085 dir
.GetFullPath(dtmp
);
5087 fs
.Open(dtmp
, true);
5088 ai
->AddToSaveGame(&str
, &fs
);
5091 //reopen list for the second round
5100 int Interface::GetMaximumAbility() const { return MaximumAbility
; }
5102 int Interface::GetStrengthBonus(int column
, int value
, int ex
) const
5104 //to hit, damage, open doors, weight allowance
5105 if (column
<0 || column
>3)
5118 return strmod
[column
*(MaximumAbility
+1)+value
]+strmodex
[column
*101+ex
];
5121 // we don't use the stuff maze yet
5122 // IE: bonus skill points are ignored and the plain int mod used!
5123 int Interface::GetIntelligenceBonus(int column
, int value
) const
5125 if (HasFeature(GF_3ED_RULES
)) {
5126 //learn spell, max spell level, max spell number on level, bonus skill points
5127 if (column
<0 || column
>2) return -9999;
5129 //learn spell, max spell level, max spell number on level, maze duration dice, maze duration dice size
5130 if (column
<0 || column
>4) return -9999;
5133 return intmod
[column
*(MaximumAbility
+1)+value
];
5136 int Interface::GetDexterityBonus(int column
, int value
) const
5138 //no dexmod in iwd2 and only one type of modifier
5139 if (HasFeature(GF_3ED_RULES
)) {
5140 return (value
-10)/2;
5143 //reaction, missile, ac
5144 if (column
<0 || column
>2)
5147 return dexmod
[column
*(MaximumAbility
+1)+value
];
5150 int Interface::GetConstitutionBonus(int column
, int value
) const
5153 if (HasFeature(GF_3ED_RULES
)) {
5154 return (value
-10)/2;
5157 //normal, warrior, minimum, regen hp, regen fatigue
5158 if (column
<0 || column
>4)
5161 return conmod
[column
*(MaximumAbility
+1)+value
];
5164 int Interface::GetCharismaBonus(int column
, int /*value*/) const
5166 // store price reduction
5167 if (column
<0 || column
>(MaximumAbility
-1))
5170 return chrmod
[column
];
5173 int Interface::GetLoreBonus(int column
, int value
) const
5175 //no lorebon in iwd2 - lore is a skill
5176 if (HasFeature(GF_3ED_RULES
)) return 0;
5178 if (column
<0 || column
>0)
5181 return lorebon
[value
];
5184 int Interface::GetWisdomBonus(int column
, int value
) const
5187 if (HasFeature(GF_3ED_RULES
)) {
5188 return (value
-10)/2;
5191 if (!HasFeature(GF_WISDOM_BONUS
)) return 0;
5194 if (column
<0 || column
>0)
5197 return wisbon
[value
];
5200 int Interface::GetReputationMod(int column
) const
5202 int reputation
= game
->Reputation
/ 10 - 1;
5204 if (column
<0 || column
>8) {
5207 if (reputation
> 19) {
5210 if (reputation
< 0) {
5214 return reputationmod
[reputation
][column
];
5217 // -3, -2 if request is illegal or in cutscene
5218 // -1 if pause is already active
5219 // 0 if pause was not allowed
5220 // 1 if autopause happened
5221 int Interface::Autopause(ieDword flag
)
5223 GameControl
*gc
= GetGameControl();
5227 if (InCutSceneMode()) {
5230 if (gc
->GetDialogueFlags()&DF_FREEZE_SCRIPTS
) {
5233 ieDword autopause_flags
= 0;
5235 vars
->Lookup("Auto Pause State", autopause_flags
);
5236 if (autopause_flags
& (1<<flag
)) {
5237 displaymsg
->DisplayConstantString(STR_AP_UNUSABLE
+flag
, 0xff0000);
5238 gc
->SetDialogueFlags(DF_FREEZE_SCRIPTS
, BM_OR
);
5244 void Interface::RegisterOpcodes(int count
, const EffectRef
*opcodes
)
5246 EffectQueue_RegisterOpcodes(count
, opcodes
);
5249 void Interface::SetInfoTextColor(const Color
&color
)
5251 if (InfoTextPalette
) {
5252 gamedata
->FreePalette(InfoTextPalette
);
5254 InfoTextPalette
= CreatePalette(color
, black
);
5258 void Interface::GetResRefFrom2DA(const ieResRef resref
, ieResRef resource1
, ieResRef resource2
, ieResRef resource3
)
5270 AutoTable
tab(resref
);
5272 unsigned int cols
= tab
->GetColumnCount();
5273 unsigned int row
= (unsigned int) Roll(1,tab
->GetRowCount(),-1);
5274 strnuprcpy(resource1
, tab
->QueryField(row
,0), 8);
5275 if (resource2
&& cols
>1)
5276 strnuprcpy(resource2
, tab
->QueryField(row
,1), 8);
5277 if (resource3
&& cols
>2)
5278 strnuprcpy(resource3
, tab
->QueryField(row
,2), 8);
5282 ieDword
*Interface::GetListFrom2DAInternal(const ieResRef resref
)
5286 AutoTable
tab(resref
);
5288 ieDword cnt
= tab
->GetRowCount();
5289 ret
= (ieDword
*) malloc((1+cnt
)*sizeof(ieDword
));
5292 ret
[cnt
]=strtol(tab
->QueryField(cnt
-1, 0),NULL
, 0);
5297 ret
= (ieDword
*) malloc(sizeof(ieDword
));
5302 ieDword
* Interface::GetListFrom2DA(const ieResRef tablename
)
5306 if (!lists
->Lookup(tablename
, (void *&) list
)) {
5307 list
= GetListFrom2DAInternal(tablename
);
5308 lists
->SetAt(tablename
, list
);
5314 //returns a numeric value associated with a stat name (symbol) from stats.ids
5315 ieDword
Interface::TranslateStat(const char *stat_name
)
5319 if (valid_number(stat_name
, tmp
)) {
5320 return (ieDword
) tmp
;
5323 int symbol
= LoadSymbol( "stats" );
5324 Holder
<SymbolMgr
> sym
= GetSymbol( symbol
);
5325 ieDword stat
= (ieDword
) sym
->GetValue( stat_name
);
5326 if (stat
==(ieDword
) ~0) {
5327 printMessage("Core"," ",YELLOW
);
5328 printf("Cannot translate symbol: %s\n", stat_name
);
5333 void Interface::WaitForDisc(int disc_number
, const char* path
)
5335 GetDictionary()->SetAt( "WaitForDisc", (ieDword
) disc_number
);
5337 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5340 for (size_t i
=0;i
<CD
[disc_number
-1].size();i
++) {
5341 char name
[_MAX_PATH
];
5343 PathJoin(name
, CD
[disc_number
-1][i
].c_str(),path
,NULL
);
5344 if (file_exists (name
)) {
5345 GetGUIScriptEngine()->RunFunction( "GUICommonWindows", "OpenWaitForDiscWindow" );
5350 } while (video
->SwapBuffers() == GEM_OK
);
5353 // remove the extraneus EOL newline and carriage return
5354 void Interface::StripLine(char * string
, size_t size
) {
5355 if (size
>= 2 && string
[size
-2] == '\n') {
5356 string
[size
-2] = '\0';
5358 if (size
>= 3 && string
[size
-3] == '\r') {
5359 string
[size
-3] = '\0'; // remove the carriage return too
5363 void Interface::SetNextScript(const char *script
)
5365 strncpy( NextScript
, script
, sizeof(NextScript
) );
5366 QuitFlag
|= QF_CHANGESCRIPT
;
5369 void Interface::SanityCheck(const char *ver
) {
5370 if (strcmp(ver
, VERSION_GEMRB
)) {
5371 printf("version check failed: core version %s doesn't match caller's version %s\n", VERSION_GEMRB
, ver
);