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.
41 #include "Interface.h"
43 #include "FileStream.h"
44 #include "AnimationMgr.h"
45 #include "ArchiveImporter.h"
46 #include "WorldMapMgr.h"
47 #include "AmbientMgr.h"
50 #include "EffectMgr.h"
52 #include "DialogMgr.h"
53 #include "MapControl.h"
54 #include "EffectQueue.h"
57 #include "ScriptedAnimation.h"
59 #include "PluginMgr.h"
60 #include "StringMgr.h"
61 #include "ScriptEngine.h"
68 #include "SaveGameIterator.h"
70 #include "MoviePlayer.h"
71 #include "GameControl.h"
73 #include "DataFileMgr.h"
74 #include "SaveGameMgr.h"
75 #include "WorldMapControl.h"
77 #include "ProjectileServer.h"
80 #include "PluginMgr.h"
83 GEM_EXPORT Interface
* core
;
86 GEM_EXPORT HANDLE hConsole
;
89 //use DialogF.tlk if the protagonist is female, that's why we leave space
90 static const char dialogtlk
[] = "dialog.tlk\0";
92 static int strref_table
[STRREF_COUNT
];
94 static int MaximumAbility
= 25;
95 static ieWordSigned
*strmod
= NULL
;
96 static ieWordSigned
*strmodex
= NULL
;
97 static ieWordSigned
*intmod
= NULL
;
98 static ieWordSigned
*dexmod
= NULL
;
99 static ieWordSigned
*conmod
= NULL
;
100 static ieWordSigned
*chrmod
= NULL
;
101 static ieWordSigned
*lorebon
= NULL
;
102 static ieVariable IWD2DeathVarFormat
= "_DEAD%s";
103 static ieVariable DeathVarFormat
= "SPRITE_IS_DEAD%s";
105 Interface::Interface(int iargc
, char* iargv
[])
110 hConsole
= GetStdHandle( STD_OUTPUT_HANDLE
);
112 textcolor( LIGHT_WHITE
);
113 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB
);
115 // default to the correct endianswitch
116 ieWord endiantest
= 1;
117 if (((char *)&endiantest
)[1] == 1) {
119 DataStream::SetEndianSwitch(true);
124 pl_uppercase
[i
]=(ieByte
) toupper(i
);
125 pl_lowercase
[i
]=(ieByte
) tolower(i
);
146 CurrentContainer
= NULL
;
147 UseContainer
= false;
148 InfoTextPalette
= NULL
;
158 tooltip_currtextw
= 0;
173 ConsolePopped
= false;
176 QuitFlag
= QF_NORMAL
;
177 EventFlag
= EF_CONTROL
;
179 CaseSensitive
= true; //this is the default value, so CD1/CD2 will be resolved
181 CaseSensitive
= false;
184 SkipIntroVideos
= false;
188 GUIScriptsPath
[0] = 0;
194 GemRBOverridePath
[0] = 0;
196 strncpy( GameOverridePath
, "override", sizeof(GameOverridePath
) );
197 strncpy( GameSoundsPath
, "sounds", sizeof(GameSoundsPath
) );
198 strncpy( GameScriptsPath
, "scripts", sizeof(GameScriptsPath
) );
199 strncpy( GamePortraitsPath
, "portraits", sizeof(GamePortraitsPath
) );
200 strncpy( GameCharactersPath
, "characters", sizeof(GameCharactersPath
) );
201 strncpy( GameDataPath
, "data", sizeof(GameDataPath
) );
202 for (i
= 0; i
< 6; i
++) {
203 strncpy( CD
[i
], "CDi", sizeof(CD
[i
]) );
206 strncpy( INIConfig
, "baldur.ini", sizeof(INIConfig
) );
207 strncpy( ButtonFont
, "STONESML", sizeof(ButtonFont
) );
208 strncpy( TooltipFont
, "STONESML", sizeof(TooltipFont
) );
209 strncpy( MovieFont
, "STONESML", sizeof(MovieFont
) );
210 //strncpy( CursorBam, "CAROT", sizeof(CursorBam) );
211 strncpy( ScrollCursorBam
, "CURSARW", sizeof(ScrollCursorBam
) );
212 strncpy( GlobalScript
, "BALDUR", sizeof(GlobalScript
) );
213 strncpy( WorldMapName
, "WORLDMAP", sizeof(WorldMapName
) );
214 strncpy( Palette16
, "MPALETTE", sizeof(Palette16
) );
215 strncpy( Palette32
, "PAL32", sizeof(Palette32
) );
216 strncpy( Palette256
, "MPAL256", sizeof(Palette256
) );
217 strcpy( TooltipBackResRef
, "\0" );
218 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
219 strcpy( GroundCircleBam
[size
], "\0" );
220 GroundCircleScale
[size
] = 0;
223 TooltipColor
.g
= 255;
225 TooltipColor
.a
= 255;
235 memset( WindowFrames
, 0, sizeof( WindowFrames
));
236 memset( GroundCircles
, 0, sizeof( GroundCircles
));
237 memset(FogSprites
, 0, sizeof( FogSprites
));
238 AreaAliasTable
= NULL
;
239 ItemExclTable
= NULL
;
240 ItemDialTable
= NULL
;
241 ItemDial2Table
= NULL
;
242 ItemTooltipTable
= NULL
;
243 update_scripts
= false;
245 gamedata
= new GameData();
248 #define FreeInterfaceVector(type, variable, member) \
250 std::vector<type>::iterator i; \
251 for(i = (variable).begin(); i != (variable).end(); ++i) { \
254 (*i).member->release(); \
260 #define FreeResourceVector(type, variable) \
262 size_t i=variable.size(); \
265 delete variable[i]; \
271 static void ReleaseItemList(void *poi
)
273 delete ((ItemList
*) poi
);
276 void FreeAbilityTables()
308 void Interface::FreeResRefTable(ieResRef
*&table
, int &count
)
316 static void ReleaseItemTooltip(void *poi
)
321 Interface::~Interface(void)
324 delete AreaAliasTable
;
330 // stop any ambients which are still enqueued
332 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
333 if (ambim
) ambim
->deactivate();
334 AudioDriver
->release();
336 //destroy the highest objects in the hierarchy first!
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();
388 windowmgr
->release();
392 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
393 video
->FreeSprite(FogSprites
[i
]);
397 video
->FreeSprite(WindowFrames
[i
]);
400 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
402 video
->FreeSprite(GroundCircles
[size
][i
]);
408 //freesprite checks for null pointer
409 video
->FreeSprite(TooltipBack
[i
]);
411 delete[] TooltipBack
;
413 if (InfoTextPalette
) {
414 gamedata
->FreePalette(InfoTextPalette
);
417 video
->SetDragCursor(NULL
);
422 guiscript
->release();
427 RtRows
->RemoveAll(ReleaseItemList
);
431 ItemExclTable
->RemoveAll(NULL
);
432 delete ItemExclTable
;
435 ItemDialTable
->RemoveAll(NULL
);
436 delete ItemDialTable
;
438 if (ItemDial2Table
) {
439 ItemDial2Table
->RemoveAll(NULL
);
440 delete ItemDial2Table
;
442 if (ItemTooltipTable
) {
443 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
444 delete ItemTooltipTable
;
447 FreeInterfaceVector( Symbol
, symbols
, sm
);
450 INIquests
->release();
452 INIbeasts
->release();
456 INIresdata
->release();
458 Map::ReleaseMemory();
459 Actor::ReleaseMemory();
461 gamedata
->ClearCaches();
468 // Removing all stuff from Cache, except bifs
469 if (!KeepCache
) DelTree((const char *) CachePath
, true);
472 void Interface::SetWindowFrame(int i
, Sprite2D
*Picture
)
474 video
->FreeSprite(WindowFrames
[i
]);
475 WindowFrames
[i
]=Picture
;
478 GameControl
* Interface::StartGameControl()
480 //making sure that our window is the first one
484 DelAllWindows();//deleting ALL windows
485 gamedata
->DelTable(0xffffu
); //dropping ALL tables
486 Window
* gamewin
= new Window( 0xffff, 0, 0, (ieWord
) Width
, (ieWord
) Height
);
487 gamewin
->WindowPack
[0]=0;
488 GameControl
* gc
= new GameControl();
491 gc
->Width
= (ieWord
) Width
;
492 gc
->Height
= (ieWord
) Height
;
494 gc
->ControlID
= 0x00000000;
495 gc
->ControlType
= IE_GUI_GAMECONTROL
;
496 gamewin
->AddControl( gc
);
497 AddWindow( gamewin
);
498 SetVisible( 0, WINDOW_VISIBLE
);
499 //setting the focus to the game control
500 evntmgr
->SetFocused(gamewin
, gc
);
501 if (guiscript
->LoadScript( "MessageWindow" )) {
502 guiscript
->RunFunction( "OnLoad" );
509 /* handle main loop events that might destroy or create windows
510 thus cannot be called from DrawWindows directly
511 these events are pending until conditions are right
513 void Interface::HandleEvents()
515 GameControl
*gc
= GetGameControl();
516 if (gc
&& (!gc
->Owner
|| !gc
->Owner
->Visible
)) {
521 if (EventFlag
&EF_SELECTION
) {
522 EventFlag
&=~EF_SELECTION
;
523 guiscript
->RunFunction( "SelectionChanged", false);
526 if (EventFlag
&EF_UPDATEANIM
) {
527 EventFlag
&=~EF_UPDATEANIM
;
528 guiscript
->RunFunction( "UpdateAnimation", false);
531 if (EventFlag
&EF_PORTRAIT
) {
532 ieDword tmp
= (ieDword
) ~0;
533 vars
->Lookup( "PortraitWindow", tmp
);
534 if (tmp
!= (ieDword
) ~0) {
535 EventFlag
&=~EF_PORTRAIT
;
536 guiscript
->RunFunction( "UpdatePortraitWindow" );
540 if (EventFlag
&EF_ACTION
) {
541 ieDword tmp
= (ieDword
) ~0;
542 vars
->Lookup( "ActionsWindow", tmp
);
543 if (tmp
!= (ieDword
) ~0) {
544 EventFlag
&=~EF_ACTION
;
545 guiscript
->RunFunction( "UpdateActionsWindow" );
549 if ((EventFlag
&EF_CONTROL
) && gc
) {
550 EventFlag
&=~EF_CONTROL
;
551 guiscript
->RunFunction( "UpdateControlStatus" );
552 //this is the only value we can use here
553 if (game
->ControlStatus
& CS_HIDEGUI
)
559 if ((EventFlag
&EF_SHOWMAP
) && gc
) {
560 ieDword tmp
= (ieDword
) ~0;
561 vars
->Lookup( "OtherWindow", tmp
);
562 if (tmp
== (ieDword
) ~0) {
563 EventFlag
&= ~EF_SHOWMAP
;
564 guiscript
->RunFunction( "ShowMap" );
569 if (EventFlag
&EF_SEQUENCER
) {
570 EventFlag
&=~EF_SEQUENCER
;
571 guiscript
->RunFunction( "OpenSequencerWindow" );
575 if (EventFlag
&EF_IDENTIFY
) {
576 EventFlag
&=~EF_IDENTIFY
;
577 guiscript
->RunFunction( "OpenIdentifyWindow" );
580 if (EventFlag
&EF_OPENSTORE
) {
581 EventFlag
&=~EF_OPENSTORE
;
582 guiscript
->RunFunction( "OpenStoreWindow" );
586 if (EventFlag
&EF_MASTERSCRIPT
) {
587 EventFlag
&=~EF_MASTERSCRIPT
;
588 guiscript
->RunFunction( "UpdateMasterScript" );
594 /* handle main loop events that might destroy or create windows
595 thus cannot be called from DrawWindows directly
597 void Interface::HandleFlags()
599 EventFlag
= EF_CONTROL
; //clear events because the context changed
601 if (QuitFlag
&(QF_QUITGAME
|QF_EXITGAME
) ) {
602 // when reaching this, quitflag should be 1 or 2
603 // if Exitgame was set, we'll set Start.py too
604 QuitGame (QuitFlag
&QF_EXITGAME
);
605 QuitFlag
&= ~(QF_QUITGAME
|QF_EXITGAME
);
608 if (QuitFlag
&QF_LOADGAME
) {
609 QuitFlag
&= ~QF_LOADGAME
;
610 LoadGame(LoadGameIndex
, VersionOverride
);
613 if (QuitFlag
&QF_ENTERGAME
) {
614 QuitFlag
&= ~QF_ENTERGAME
;
618 //rearrange party slots
619 game
->ConsolidateParty();
620 GameControl
* gc
= StartGameControl();
621 //switch map to protagonist
622 Actor
* actor
= game
->FindPC (1);
624 actor
= game
->GetPC (0, false);
627 gc
->ChangeMap(actor
, true);
630 printMessage("Core", "No game to enter...\n", LIGHT_RED
);
631 QuitFlag
= QF_QUITGAME
;
635 if (QuitFlag
&QF_CHANGESCRIPT
) {
636 QuitFlag
&= ~QF_CHANGESCRIPT
;
637 guiscript
->LoadScript( NextScript
);
638 guiscript
->RunFunction( "OnLoad" );
642 bool GenerateAbilityTables()
646 //range is: 0 - maximumability
647 int tablesize
= MaximumAbility
+1;
648 strmod
= (ieWordSigned
*) malloc (tablesize
* 4 * sizeof(ieWordSigned
) );
651 strmodex
= (ieWordSigned
*) malloc (101 * 4 * sizeof(ieWordSigned
) );
654 intmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
657 dexmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
660 conmod
= (ieWordSigned
*) malloc (tablesize
* 5 * sizeof(ieWordSigned
) );
663 chrmod
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
666 lorebon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
672 bool Interface::ReadAbilityTable(const ieResRef tablename
, ieWordSigned
*mem
, int columns
, int rows
)
674 AutoTable
tab(tablename
);
678 //this is a hack for rows not starting at 0 in some cases
680 const char * tmp
= tab
->GetRowName(0);
681 if (tmp
&& (tmp
[0]!='0')) {
683 for (int i
=0;i
<fix
;i
++) {
684 for (int j
=0;j
<columns
;j
++) {
685 mem
[rows
*j
+i
]=(ieWordSigned
) strtol(tab
->QueryField(0,j
),NULL
,0 );
689 for (int j
=0;j
<columns
;j
++) {
690 for( int i
=0;i
<rows
-fix
;i
++) {
691 mem
[rows
*j
+i
+fix
] = (ieWordSigned
) strtol(tab
->QueryField(i
,j
),NULL
,0 );
697 bool Interface::ReadAbilityTables()
699 bool ret
= GenerateAbilityTables();
702 ret
= ReadAbilityTable("strmod", strmod
, 4, MaximumAbility
+ 1);
705 ret
= ReadAbilityTable("strmodex", strmodex
, 4, 101);
706 //3rd ed doesn't have strmodex, but has a maximum of 40
707 if (!ret
&& (MaximumAbility
<=25) )
709 ret
= ReadAbilityTable("intmod", intmod
, 3, MaximumAbility
+ 1);
712 ret
= ReadAbilityTable("hpconbon", conmod
, 5, MaximumAbility
+ 1);
715 if (!HasFeature(GF_3ED_RULES
)) {
716 //no lorebon in iwd2???
717 ret
= ReadAbilityTable("lorebon", lorebon
, 1, MaximumAbility
+ 1);
720 //no dexmod in iwd2???
721 ret
= ReadAbilityTable("dexmod", dexmod
, 3, MaximumAbility
+ 1);
725 //this table is a single row (not a single column)
726 ret
= ReadAbilityTable("chrmodst", chrmod
, MaximumAbility
+ 1, 1);
732 bool Interface::ReadAuxItemTables()
739 ItemExclTable
->RemoveAll(NULL
);
741 ItemExclTable
= new Variables();
742 ItemExclTable
->SetType(GEM_VARIABLES_INT
);
744 table
= gamedata
->LoadTable( "itemexcl" );
748 //don't report error when the file doesn't exist
749 if (aa
.load("itemexcl")) {
750 idx
= aa
->GetRowCount();
754 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
755 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
756 ItemExclTable
->SetAt(key
, value
);
760 ItemDialTable
->RemoveAll(NULL
);
762 ItemDialTable
= new Variables();
763 ItemDialTable
->SetType(GEM_VARIABLES_INT
);
765 if (ItemDial2Table
) {
766 ItemDial2Table
->RemoveAll(NULL
);
768 ItemDial2Table
= new Variables();
769 ItemDial2Table
->SetType(GEM_VARIABLES_STRING
);
772 //don't report error when the file doesn't exist
773 if (aa
.load("itemdial")) {
774 idx
= aa
->GetRowCount();
776 ieResRef key
, dlgres
;
778 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
779 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
780 ItemDialTable
->SetAt(key
, value
);
781 strnlwrcpy(dlgres
,aa
->QueryField(idx
,1),8);
782 ItemDial2Table
->SetAtCopy(key
, dlgres
);
786 if (ItemTooltipTable
) {
787 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
789 ItemTooltipTable
= new Variables();
790 ItemTooltipTable
->SetType(GEM_VARIABLES_POINTER
);
793 //don't report error when the file doesn't exist
794 if (aa
.load("tooltip")) {
795 idx
= aa
->GetRowCount();
798 int *tmppoi
= (int *) malloc(sizeof(int)*3);
800 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
801 for (int i
=0;i
<3;i
++) {
802 tmppoi
[i
] = atoi(aa
->QueryField(idx
,i
));
804 ItemTooltipTable
->SetAt(key
, (void*)tmppoi
);
811 const char *Interface::GetDeathVarFormat()
813 return DeathVarFormat
;
816 int Interface::GetItemExcl(const ieResRef itemname
) const
820 if (ItemExclTable
&& ItemExclTable
->Lookup(itemname
, value
)) {
826 int Interface::GetItemTooltip(const ieResRef itemname
, int header
, int identified
)
830 if (ItemTooltipTable
) {
832 ItemTooltipTable
->Lookup(itemname
, lookup
);
833 value
= (int*)lookup
;
835 if (value
&& (value
[header
]>=0)) {
836 return value
[header
];
838 Item
*item
= gamedata
->GetItem(itemname
);
842 int ret
= identified
?item
->ItemNameIdentified
:item
->ItemName
;
843 gamedata
->FreeItem(item
, itemname
, 0);
847 int Interface::GetItemDialStr(const ieResRef itemname
) const
851 if (ItemDialTable
&& ItemDialTable
->Lookup(itemname
, value
)) {
857 //second value is the item dialog resource returned by this method
858 int Interface::GetItemDialRes(const ieResRef itemname
, ieResRef retval
) const
860 if (ItemDial2Table
&& ItemDial2Table
->Lookup(itemname
, retval
, sizeof(ieResRef
))) {
866 bool Interface::ReadAreaAliasTable(const ieResRef tablename
)
868 if (AreaAliasTable
) {
869 AreaAliasTable
->RemoveAll(NULL
);
871 AreaAliasTable
= new Variables();
872 AreaAliasTable
->SetType(GEM_VARIABLES_INT
);
875 AutoTable
aa(tablename
);
877 //don't report error when the file doesn't exist
881 int idx
= aa
->GetRowCount();
885 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
886 ieDword value
= atoi(aa
->QueryField(idx
,0));
887 AreaAliasTable
->SetAt(key
, value
);
893 int Interface::GetAreaAlias(const ieResRef areaname
) const
897 if (AreaAliasTable
&& AreaAliasTable
->Lookup(areaname
, value
)) {
903 bool Interface::ReadMusicTable(const ieResRef tablename
, int col
) {
904 AutoTable
tm(tablename
);
908 for (unsigned int i
= 0; i
< tm
->GetRowCount(); i
++) {
909 musiclist
.push_back(strdup(tm
->QueryField(i
, col
)));
915 bool Interface::ReadDamageTypeTable() {
916 AutoTable
tm("dmgtypes");
921 for (ieDword i
= 0; i
< tm
->GetRowCount(); i
++) {
922 di
.strref
= core
->GetStringReference(atoi(tm
->QueryField(i
, 0)));
923 di
.resist_stat
= TranslateStat(tm
->QueryField(i
, 1));
924 di
.value
= strtol(tm
->QueryField(i
, 2), (char **) NULL
, 16);
925 di
.iwd_mod_type
= atoi(tm
->QueryField(i
, 3));
926 DamageInfoMap
.insert(std::make_pair
<ieDword
, DamageInfoStruct
> ((ieDword
)di
.value
, di
));
932 bool Interface::ReadModalStates()
934 AutoTable
table("modal");
938 ModalStatesStruct ms
;
939 for (unsigned short i
= 0; i
< table
->GetRowCount(); i
++) {
940 strncpy(ms
.spell
, table
->QueryField(i
, 0), 8);
941 strncpy(ms
.action
, table
->QueryField(i
, 1), 16);
942 ms
.entering_str
= atoi(table
->QueryField(i
, 2));
943 ms
.leaving_str
= atoi(table
->QueryField(i
, 3));
944 ms
.failed_str
= atoi(table
->QueryField(i
, 4));
945 ModalStates
.push_back(ms
);
951 //Not a constant anymore, we let the caller set the entry to zero
952 char *Interface::GetMusicPlaylist(int SongType
) const {
953 if (SongType
< 0 || (unsigned int)SongType
>= musiclist
.size())
956 return musiclist
[SongType
];
959 static const Color white
= {0xff,0xff,0xff,0xff};
960 static const Color black
= {0x00,0x00,0x00,0xff};
961 static const Region
bg( 0, 0, 100, 30 );
963 /** this is the main loop */
964 void Interface::Main()
966 video
->CreateDisplay( Width
, Height
, Bpp
, FullScreen
);
967 video
->SetDisplayTitle( GameName
, GameType
);
968 ieDword brightness
= 10;
969 ieDword contrast
= 5;
971 vars
->Lookup("Brightness Correction", brightness
);
972 vars
->Lookup("Gamma Correction", contrast
);
973 vars
->Lookup("Mouse Scroll Speed", speed
);
974 video
->SetGamma(brightness
, contrast
);
975 SetMouseScrollSpeed((int) speed
);
976 if (vars
->Lookup("Tooltips", TooltipDelay
)) {
977 // the games store the slider position*10, not the actual delay
978 TooltipDelay
*= TOOLTIP_DELAY_FACTOR
/10;
981 Font
* fps
= GetFont( ( unsigned int ) 0 );
982 char fpsstring
[40]={"???.??? fps"};
983 unsigned long frame
= 0, time
, timebase
;
986 Palette
* palette
= CreatePalette( white
, black
);
988 //don't change script when quitting is pending
996 HandleGUIBehaviour();
1003 if (time
- timebase
> 1000) {
1004 frames
= ( frame
* 1000.0 / ( time
- timebase
) );
1007 sprintf( fpsstring
, "%.3f fps", frames
);
1009 video
->DrawRect( bg
, black
);
1011 ( unsigned char * ) fpsstring
, palette
,
1012 IE_FONT_ALIGN_LEFT
| IE_FONT_ALIGN_MIDDLE
, true );
1014 } while (video
->SwapBuffers() == GEM_OK
);
1015 gamedata
->FreePalette( palette
);
1018 bool Interface::ReadStrrefs()
1021 memset(strref_table
,-1,sizeof(strref_table
) );
1022 AutoTable
tab("strings");
1026 for(i
=0;i
<STRREF_COUNT
;i
++) {
1027 strref_table
[i
]=atoi(tab
->QueryField(i
,0));
1032 int Interface::ReadResRefTable(const ieResRef tablename
, ieResRef
*&data
)
1040 AutoTable
tm(tablename
);
1042 printStatus( "ERROR", LIGHT_RED
);
1043 printf( "Cannot find %s.2da.\n",tablename
);
1046 count
= tm
->GetRowCount();
1047 data
= (ieResRef
*) calloc( count
, sizeof(ieResRef
) );
1048 for (int i
= 0; i
< count
; i
++) {
1049 strnlwrcpy( data
[i
], tm
->QueryField( i
, 0 ), 8 );
1050 //* marks an empty resource
1051 if (data
[i
][0]=='*') {
1058 int Interface::LoadSprites()
1062 if (!IsAvailable( IE_2DA_CLASS_ID
)) {
1063 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1068 AnimationFactory
* anim
;
1069 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("cursors", IE_BAM_CLASS_ID
);
1072 CursorCount
= anim
->GetCycleCount();
1073 Cursors
= new Sprite2D
* [CursorCount
];
1074 for (int i
= 0; i
< CursorCount
; i
++) {
1075 Cursors
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1078 printMessage( "Core", "Loading Cursors...", WHITE
);
1080 // this is the last existing cursor type
1081 if (CursorCount
<IE_CURSOR_WAY
) {
1082 printStatus( "ERROR", LIGHT_RED
);
1085 video
->SetCursor( Cursors
[0], Cursors
[1] );
1086 printStatus( "OK", LIGHT_GREEN
);
1088 // Load fog-of-war bitmaps
1089 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("fogowar", IE_BAM_CLASS_ID
);
1090 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE
);
1091 if (!anim
|| anim
->GetCycleSize( 0 ) != 8) {
1092 // unknown type of fog anim
1093 printStatus( "ERROR", LIGHT_RED
);
1097 FogSprites
[0] = NULL
;
1098 FogSprites
[1] = anim
->GetFrame( 0, 0 );
1099 FogSprites
[2] = anim
->GetFrame( 1, 0 );
1100 FogSprites
[3] = anim
->GetFrame( 2, 0 );
1102 FogSprites
[4] = video
->MirrorSpriteVertical( FogSprites
[1], false );
1104 FogSprites
[5] = NULL
;
1106 FogSprites
[6] = video
->MirrorSpriteVertical( FogSprites
[3], false );
1108 FogSprites
[7] = NULL
;
1110 FogSprites
[8] = video
->MirrorSpriteHorizontal( FogSprites
[2], false );
1112 FogSprites
[9] = video
->MirrorSpriteHorizontal( FogSprites
[3], false );
1114 FogSprites
[10] = NULL
;
1115 FogSprites
[11] = NULL
;
1117 FogSprites
[12] = video
->MirrorSpriteHorizontal( FogSprites
[6], false );
1119 FogSprites
[16] = anim
->GetFrame( 3, 0 );
1120 FogSprites
[17] = anim
->GetFrame( 4, 0 );
1121 FogSprites
[18] = anim
->GetFrame( 5, 0 );
1122 FogSprites
[19] = anim
->GetFrame( 6, 0 );
1124 FogSprites
[20] = video
->MirrorSpriteVertical( FogSprites
[17], false );
1126 FogSprites
[21] = NULL
;
1128 FogSprites
[23] = NULL
;
1130 FogSprites
[24] = video
->MirrorSpriteHorizontal( FogSprites
[18], false );
1132 FogSprites
[25] = anim
->GetFrame( 7, 0 );
1135 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[25], false );
1136 FogSprites
[22] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1137 video
->FreeSprite( tmpsprite
);
1140 FogSprites
[26] = NULL
;
1141 FogSprites
[27] = NULL
;
1144 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[19], false );
1145 FogSprites
[28] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1146 video
->FreeSprite( tmpsprite
);
1150 vars
->Lookup("3D Acceleration", i
);
1152 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
1153 if (FogSprites
[i
]) {
1154 Sprite2D
* alphasprite
= video
->CreateAlpha( FogSprites
[i
] );
1155 video
->FreeSprite ( FogSprites
[i
] );
1156 FogSprites
[i
] = alphasprite
;
1161 printStatus( "OK", LIGHT_GREEN
);
1163 // Load ground circle bitmaps (PST only)
1164 //block required due to msvc6.0 incompatibility
1165 for (size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
1166 if (GroundCircleBam
[size
][0]) {
1167 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(GroundCircleBam
[size
], IE_BAM_CLASS_ID
);
1168 if (!anim
|| anim
->GetCycleCount() != 6) {
1169 // unknown type of circle anim
1170 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1171 printStatus( "ERROR", LIGHT_RED
);
1175 for (int i
= 0; i
< 6; i
++) {
1176 Sprite2D
* sprite
= anim
->GetFrame( 0, (ieByte
) i
);
1177 if (GroundCircleScale
[size
]) {
1178 GroundCircles
[size
][i
] = video
->SpriteScaleDown( sprite
, GroundCircleScale
[size
] );
1179 video
->FreeSprite( sprite
);
1181 GroundCircles
[size
][i
] = sprite
;
1187 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1188 printStatus( "OK", LIGHT_GREEN
);
1190 printMessage( "Core", "Loading Fonts...\n", WHITE
);
1191 AutoTable
tab("fonts");
1193 printStatus( "ERROR", LIGHT_RED
);
1194 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1197 AnimationMgr
* bamint
= ( AnimationMgr
* ) GetInterface( IE_BAM_CLASS_ID
);
1199 printStatus( "ERROR", LIGHT_RED
);
1200 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1203 DataStream
* str
= NULL
;
1205 int count
= tab
->GetRowCount();
1206 for (int i
= 0; i
< count
; i
++) {
1207 const char* ResRef
= tab
->QueryField( i
, 0 );
1208 int needpalette
= atoi( tab
->QueryField( i
, 1 ) );
1209 int first_char
= atoi( tab
->QueryField( i
, 2 ) );
1210 str
= gamedata
->GetResource( ResRef
, IE_BAM_CLASS_ID
);
1211 if (!bamint
->Open( str
, true )) {
1214 Font
* fnt
= bamint
->GetFont();
1218 strnlwrcpy( fnt
->ResRef
, ResRef
, 8 );
1221 Color fore
= {0xff, 0xff, 0xff, 0};
1222 Color back
= {0x00, 0x00, 0x00, 0};
1223 if (!strnicmp( TooltipFont
, ResRef
, 8) ) {
1224 if (TooltipColor
.a
==0xff) {
1225 fore
= TooltipColor
;
1228 back
= TooltipColor
;
1231 Palette
* pal
= CreatePalette( fore
, back
);
1232 pal
->CreateShadedAlphaChannel();
1233 fnt
->SetPalette(pal
);
1234 gamedata
->FreePalette( pal
);
1236 fnt
->SetFirstChar( (ieByte
) first_char
);
1237 fonts
.push_back( fnt
);
1241 printMessage( "Core", "Fonts Loaded...", WHITE
);
1242 printStatus( "OK", LIGHT_GREEN
);
1244 if (TooltipBackResRef
[0]) {
1245 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(TooltipBackResRef
, IE_BAM_CLASS_ID
);
1246 printMessage( "Core", "Initializing Tooltips...", WHITE
);
1248 printStatus( "ERROR", LIGHT_RED
);
1251 TooltipBack
= new Sprite2D
* [3];
1252 for (int i
= 0; i
< 3; i
++) {
1253 TooltipBack
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1254 TooltipBack
[i
]->XPos
= 0;
1255 TooltipBack
[i
]->YPos
= 0;
1257 printStatus( "OK", LIGHT_GREEN
);
1263 int Interface::Init()
1265 plugin_flags
= new Variables();
1266 plugin_flags
->SetType( GEM_VARIABLES_INT
);
1268 printMessage( "Core", "Initializing the Event Manager...", WHITE
);
1269 evntmgr
= new EventMgr();
1271 printMessage( "Core", "Initializing Variables Dictionary...", WHITE
);
1272 vars
= new Variables();
1274 printStatus( "ERROR", LIGHT_RED
);
1278 vars
->SetType( GEM_VARIABLES_INT
);
1279 vars
->SetAt( "Volume Ambients", 100 );
1280 vars
->SetAt( "Volume Movie", 100 );
1281 vars
->SetAt( "Volume Music", 100 );
1282 vars
->SetAt( "Volume SFX", 100 );
1283 vars
->SetAt( "Volume Voices", 100 );
1284 printStatus( "OK", LIGHT_GREEN
);
1286 if (!LoadConfig()) {
1289 printMessage( "Core", "Starting Plugin Manager...\n", WHITE
);
1290 PluginMgr
*plugin
= PluginMgr::Get();
1291 plugin
->LoadPlugins(PluginsPath
);
1292 if (plugin
&& plugin
->GetPluginCount()) {
1293 printMessage( "Core", "Plugin Loading Complete...", WHITE
);
1294 printStatus( "OK", LIGHT_GREEN
);
1296 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW
);
1297 printStatus( "ERROR", LIGHT_RED
);
1300 plugin
->RunInitializers();
1304 srand( ( unsigned int ) t
);
1306 FileStreamPtrCount
= 0;
1307 CachedFileStreamPtrCount
= 0;
1309 printMessage( "Core", "GemRB Core Initialization...\n", WHITE
);
1310 printMessage( "Core", "Searching for Video Driver...", WHITE
);
1311 if (!IsAvailable( IE_VIDEO_CLASS_ID
)) {
1312 printStatus( "ERROR", LIGHT_RED
);
1313 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1316 printStatus( "OK", LIGHT_GREEN
);
1317 printMessage( "Core", "Initializing Video Plugin...", WHITE
);
1318 video
= ( Video
* ) GetInterface( IE_VIDEO_CLASS_ID
);
1319 if (video
->Init() == GEM_ERROR
) {
1320 printStatus( "ERROR", LIGHT_RED
);
1321 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1324 Color defcolor
={255,255,255,200};
1325 SetInfoTextColor(defcolor
);
1326 printStatus( "OK", LIGHT_GREEN
);
1329 printMessage( "Core", "Initializing Search Path...", WHITE
);
1330 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY
)) {
1331 printf( "no DirectoryImporter! " );
1332 printStatus( "ERROR", LIGHT_RED
);
1336 char path
[_MAX_PATH
];
1338 PathJoin( path
, core
->CachePath
, NULL
);
1339 gamedata
->AddSource(path
, "Cache", PLUGIN_RESOURCE_DIRECTORY
);
1341 PathJoin( path
, core
->GemRBOverridePath
, "override", core
->GameType
, NULL
);
1342 gamedata
->AddSource(path
, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1344 PathJoin( path
, core
->GemRBOverridePath
, "override", "shared", NULL
);
1345 gamedata
->AddSource(path
, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1347 PathJoin( path
, core
->GamePath
, core
->GameOverridePath
, NULL
);
1348 gamedata
->AddSource(path
, "Override", PLUGIN_RESOURCE_DIRECTORY
);
1350 PathJoin( path
, core
->GamePath
, core
->GameSoundsPath
, NULL
);
1351 gamedata
->AddSource(path
, "Sounds", PLUGIN_RESOURCE_DIRECTORY
);
1353 PathJoin( path
, core
->GamePath
, core
->GameScriptsPath
, NULL
);
1354 gamedata
->AddSource(path
, "Scripts", PLUGIN_RESOURCE_DIRECTORY
);
1356 PathJoin( path
, core
->GamePath
, core
->GamePortraitsPath
, NULL
);
1357 gamedata
->AddSource(path
, "Portraits", PLUGIN_RESOURCE_DIRECTORY
);
1359 PathJoin( path
, core
->GamePath
, core
->GameDataPath
, NULL
);
1360 gamedata
->AddSource(path
, "Data", PLUGIN_RESOURCE_DIRECTORY
);
1362 //IWD2 movies are on the CD but not in the BIF
1363 for (int i
= 0; i
< 6; i
++) {
1364 char description
[] = "CDi/data";
1365 PathJoin( path
, core
->CD
[i
], core
->GameDataPath
, NULL
);
1366 description
[2] = '1' + i
;
1367 gamedata
->AddSource(path
, description
, PLUGIN_RESOURCE_DIRECTORY
);
1370 printStatus( "OK", LIGHT_GREEN
);
1374 printMessage( "Core", "Initializing KEY Importer...", WHITE
);
1375 char ChitinPath
[_MAX_PATH
];
1376 PathJoin( ChitinPath
, GamePath
, "chitin.key", NULL
);
1377 if (!gamedata
->AddSource(ChitinPath
, "chitin.key", PLUGIN_RESOURCE_KEY
)) {
1378 printStatus( "ERROR", LIGHT_RED
);
1381 printStatus( "OK", LIGHT_GREEN
);
1384 printMessage( "Core", "Reading Game Options...\n", WHITE
);
1385 if (!LoadGemRBINI())
1387 printf( "Cannot Load INI\nTermination in Progress...\n" );
1391 //loading baldur.ini
1393 char ini_path
[_MAX_PATH
];
1394 PathJoin( ini_path
, GamePath
, INIConfig
, NULL
);
1395 LoadINI( ini_path
);
1397 for (i
= 0; i
< 8; i
++) {
1398 if (INIConfig
[i
] == '.')
1400 GameNameResRef
[i
] = INIConfig
[i
];
1402 GameNameResRef
[i
] = 0;
1405 printMessage( "Core", "Creating Projectile Server...\n", WHITE
);
1406 projserv
= new ProjectileServer();
1407 if (!projserv
->GetHighestProjectileNumber()) {
1408 printStatus( "ERROR", LIGHT_RED
);
1409 printf( "No projectiles are available...\n" );
1412 printMessage( "Core", "Checking for Dialogue Manager...", WHITE
);
1413 if (!IsAvailable( IE_TLK_CLASS_ID
)) {
1414 printStatus( "ERROR", LIGHT_RED
);
1415 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1418 printStatus( "OK", LIGHT_GREEN
);
1419 strings
= ( StringMgr
* ) GetInterface( IE_TLK_CLASS_ID
);
1420 printMessage( "Core", "Loading Dialog.tlk file...", WHITE
);
1421 char strpath
[_MAX_PATH
];
1422 PathJoin( strpath
, GamePath
, dialogtlk
, NULL
);
1423 FileStream
* fs
= new FileStream();
1424 if (!fs
->Open( strpath
, true )) {
1425 printStatus( "ERROR", LIGHT_RED
);
1426 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1430 printStatus( "OK", LIGHT_GREEN
);
1431 strings
->Open( fs
, true );
1434 printMessage( "Core", "Loading Palettes...\n", WHITE
);
1435 ImageMgr
*im
=( ImageMgr
* ) gamedata
->GetResource( Palette16
, &ImageMgr::ID
);
1436 pal16
= im
->GetImage();
1438 im
= ( ImageMgr
* ) gamedata
->GetResource( Palette32
, &ImageMgr::ID
);
1439 pal32
= im
->GetImage();
1441 im
= ( ImageMgr
* ) gamedata
->GetResource( Palette256
, &ImageMgr::ID
);
1442 pal256
= im
->GetImage();
1444 printMessage( "Core", "Palettes Loaded\n", WHITE
);
1447 if (!IsAvailable( IE_BAM_CLASS_ID
)) {
1448 printStatus( "ERROR", LIGHT_RED
);
1449 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1453 printMessage( "Core", "Initializing stock sounds...\n", WHITE
);
1454 DSCount
= ReadResRefTable ("defsound", DefSound
);
1456 printStatus( "ERROR", LIGHT_RED
);
1457 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1461 printStatus( "OK", LIGHT_GREEN
);
1462 printMessage( "Core", "Broadcasting Event Manager...", WHITE
);
1463 video
->SetEventMgr( evntmgr
);
1464 printStatus( "OK", LIGHT_GREEN
);
1465 printMessage( "Core", "Initializing Window Manager...", WHITE
);
1466 windowmgr
= ( WindowMgr
* ) GetInterface( IE_CHU_CLASS_ID
);
1467 if (windowmgr
== NULL
) {
1468 printStatus( "ERROR", LIGHT_RED
);
1471 printStatus( "OK", LIGHT_GREEN
);
1472 printMessage( "Core", "Initializing GUI Script Engine...", WHITE
);
1473 guiscript
= ( ScriptEngine
* ) GetInterface( IE_GUI_SCRIPT_CLASS_ID
);
1474 if (guiscript
== NULL
) {
1475 printStatus( "ERROR", LIGHT_RED
);
1478 if (!guiscript
->Init()) {
1479 printStatus( "ERROR", LIGHT_RED
);
1482 printStatus( "OK", LIGHT_GREEN
);
1483 strcpy( NextScript
, "Start" );
1485 int ret
= LoadSprites();
1486 if (ret
) return ret
;
1488 Sprite2D
*tmpsprite
= GetCursorSprite();
1489 printMessage( "Core", "Setting up the Console...", WHITE
);
1490 QuitFlag
= QF_CHANGESCRIPT
;
1491 console
= new Console();
1493 console
->YPos
= (ieWord
) (Height
- 25);
1494 console
->Width
= (ieWord
) Width
;
1495 console
->Height
= 25;
1496 console
->SetFont( fonts
[0] );
1498 printStatus( "ERROR", LIGHT_RED
);
1501 console
->SetCursor (tmpsprite
);
1502 printStatus( "OK", LIGHT_GREEN
);
1504 printMessage( "Core", "Starting up the Sound Driver...", WHITE
);
1505 AudioDriver
= ( Audio
* ) GetInterface( IE_AUDIO_CLASS_ID
);
1506 if (AudioDriver
== NULL
) {
1507 printStatus( "ERROR", LIGHT_RED
);
1510 if (!AudioDriver
->Init()) {
1511 printStatus( "ERROR", LIGHT_RED
);
1514 printStatus( "OK", LIGHT_GREEN
);
1516 printMessage( "Core", "Allocating SaveGameIterator...", WHITE
);
1517 sgiterator
= new SaveGameIterator();
1518 if (sgiterator
== NULL
) {
1519 printStatus( "ERROR", LIGHT_RED
);
1522 printStatus( "OK", LIGHT_GREEN
);
1524 //no need of strdup, variables do copy the key!
1525 vars
->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos
);
1526 vars
->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements
);
1528 printMessage( "Core", "Initializing Token Dictionary...", WHITE
);
1529 tokens
= new Variables();
1531 printStatus( "ERROR", LIGHT_RED
);
1534 tokens
->SetType( GEM_VARIABLES_STRING
);
1535 printStatus( "OK", LIGHT_GREEN
);
1537 printMessage( "Core", "Initializing Music Manager...", WHITE
);
1538 music
= ( MusicMgr
* ) GetInterface( IE_MUS_CLASS_ID
);
1540 printStatus( "ERROR", LIGHT_RED
);
1543 printStatus( "OK", LIGHT_GREEN
);
1545 printMessage("Core", "Loading music list...\n", WHITE
);
1546 if (HasFeature( GF_HAS_SONGLIST
)) {
1547 ret
= ReadMusicTable("songlist", 1);
1549 /*since bg1 and pst has no .2da for songlist,
1550 we must supply one in the gemrb/override folder.
1551 It should be: music.2da, first column is a .mus filename*/
1552 ret
= ReadMusicTable("music", 0);
1555 printStatus( "OK", LIGHT_GREEN
);
1557 printStatus( "NOT FOUND", YELLOW
);
1560 if (HasFeature( GF_RESDATA_INI
)) {
1561 printMessage( "Core", "Loading resource data File...", WHITE
);
1562 INIresdata
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1563 DataStream
* ds
= gamedata
->GetResource("resdata", IE_INI_CLASS_ID
);
1564 if (!INIresdata
->Open( ds
, true )) {
1565 printStatus( "ERROR", LIGHT_RED
);
1567 printStatus( "OK", LIGHT_GREEN
);
1571 if (HasFeature( GF_HAS_PARTY_INI
)) {
1572 printMessage( "Core", "Loading precreated teams setup...\n",
1574 INIparty
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1575 FileStream
* fs
= new FileStream();
1576 char tINIparty
[_MAX_PATH
];
1577 PathJoin( tINIparty
, GamePath
, "Party.ini", NULL
);
1578 fs
->Open( tINIparty
, true );
1579 if (!INIparty
->Open( fs
, true )) {
1580 printStatus( "ERROR", LIGHT_RED
);
1582 printStatus( "OK", LIGHT_GREEN
);
1586 if (HasFeature(GF_IWD2_DEATHVARFORMAT
)) {
1587 memcpy(DeathVarFormat
, IWD2DeathVarFormat
, sizeof(ieVariable
));
1590 if (HasFeature( GF_HAS_BEASTS_INI
)) {
1591 printMessage( "Core", "Loading beasts definition File...\n",
1593 INIbeasts
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1594 FileStream
* fs
= new FileStream();
1595 char tINIbeasts
[_MAX_PATH
];
1596 PathJoin( tINIbeasts
, GamePath
, "beast.ini", NULL
);
1597 // FIXME: crashes if file does not open
1598 fs
->Open( tINIbeasts
, true );
1599 if (!INIbeasts
->Open( fs
, true )) {
1600 printStatus( "ERROR", LIGHT_RED
);
1602 printStatus( "OK", LIGHT_GREEN
);
1605 printMessage( "Core", "Loading quests definition File...\n",
1607 INIquests
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1608 FileStream
* fs2
= new FileStream();
1609 char tINIquests
[_MAX_PATH
];
1610 PathJoin( tINIquests
, GamePath
, "quests.ini", NULL
);
1611 // FIXME: crashes if file does not open
1612 fs2
->Open( tINIquests
, true );
1613 if (!INIquests
->Open( fs2
, true )) {
1614 printStatus( "ERROR", LIGHT_RED
);
1616 printStatus( "OK", LIGHT_GREEN
);
1622 timer
= new GlobalTimer();
1623 printMessage( "Core", "Bringing up the Global Timer...", WHITE
);
1625 printStatus( "ERROR", LIGHT_RED
);
1628 printStatus( "OK", LIGHT_GREEN
);
1630 ret
= Init_EffectQueue();
1631 printMessage( "Core", "Initializing effects...", WHITE
);
1633 printStatus( "ERROR", LIGHT_RED
);
1636 printStatus( "OK", LIGHT_GREEN
);
1638 ret
= InitItemTypes();
1639 printMessage( "Core", "Initializing Inventory Management...", WHITE
);
1641 printStatus( "ERROR", LIGHT_RED
);
1644 printStatus( "OK", LIGHT_GREEN
);
1646 ret
= ReadStrrefs();
1647 printMessage( "Core", "Initializing string constants...", WHITE
);
1649 printStatus( "ERROR", LIGHT_RED
);
1652 printStatus( "OK", LIGHT_GREEN
);
1654 ret
= ReadRandomItems();
1655 printMessage( "Core", "Initializing random treasure...", WHITE
);
1657 printStatus( "OK", LIGHT_GREEN
);
1660 printStatus( "ERROR", LIGHT_RED
);
1663 ret
= ReadAbilityTables();
1664 printMessage( "Core", "Initializing ability tables...", WHITE
);
1666 printStatus( "ERROR", LIGHT_RED
);
1669 printStatus( "OK", LIGHT_GREEN
);
1671 if ( gamedata
->Exists("WMAPLAY", IE_2DA_CLASS_ID
) ) {
1672 ret
= ReadAreaAliasTable( "WMAPLAY" );
1673 printMessage( "Core", "Initializing area aliases...", WHITE
);
1675 printStatus( "OK", LIGHT_GREEN
);
1678 printStatus( "NOT FOUND", YELLOW
);
1682 ret
= ReadAuxItemTables();
1683 printMessage( "Core", "Reading item tables...", WHITE
);
1685 printStatus( "ERROR", LIGHT_RED
);
1688 printStatus( "OK", LIGHT_GREEN
);
1690 ret
= ReadDamageTypeTable();
1691 printMessage( "Core", "Reading damage type table...", WHITE
);
1693 printStatus( "ERROR", LIGHT_RED
);
1695 printStatus( "OK", LIGHT_GREEN
);
1698 ret
= ReadModalStates();
1699 printMessage( "Core", "Reading modal states table...", WHITE
);
1701 printStatus( "ERROR", LIGHT_RED
);
1704 printStatus( "OK", LIGHT_GREEN
);
1707 printMessage( "Core", "Reading modal states table...", WHITE
);
1708 InitializeIEScript();
1709 printStatus( "OK", LIGHT_GREEN
);
1711 printMessage( "Core", "Core Initialization Complete!\n", WHITE
);
1716 bool Interface::IsAvailable(SClass_ID filetype
) const
1718 return PluginMgr::Get()->IsAvailable( filetype
);
1721 WorldMap
*Interface::GetWorldMap(const char *map
)
1723 int index
= worldmap
->FindAndSetCurrentMap(map
?map
:game
->CurrentArea
);
1724 return worldmap
->GetWorldMap(index
);
1727 void* Interface::GetInterface(SClass_ID filetype
) const
1729 if (!PluginMgr::Get()) {
1732 return PluginMgr::Get()->GetPlugin( filetype
);
1735 ProjectileServer
* Interface::GetProjectileServer() const
1740 Video
* Interface::GetVideoDriver() const
1745 const char* Interface::TypeExt(SClass_ID type
) const
1748 case IE_2DA_CLASS_ID
:
1751 case IE_ACM_CLASS_ID
:
1754 case IE_ARE_CLASS_ID
:
1757 case IE_BAM_CLASS_ID
:
1760 case IE_BCS_CLASS_ID
:
1763 case IE_BS_CLASS_ID
:
1766 case IE_BIF_CLASS_ID
:
1769 case IE_BMP_CLASS_ID
:
1772 case IE_PNG_CLASS_ID
:
1775 case IE_CHR_CLASS_ID
:
1778 case IE_CHU_CLASS_ID
:
1781 case IE_CRE_CLASS_ID
:
1784 case IE_DLG_CLASS_ID
:
1787 case IE_EFF_CLASS_ID
:
1790 case IE_GAM_CLASS_ID
:
1793 case IE_IDS_CLASS_ID
:
1796 case IE_INI_CLASS_ID
:
1799 case IE_ITM_CLASS_ID
:
1802 case IE_MOS_CLASS_ID
:
1805 case IE_MUS_CLASS_ID
:
1808 case IE_MVE_CLASS_ID
:
1811 case IE_OGG_CLASS_ID
:
1814 case IE_PLT_CLASS_ID
:
1817 case IE_PRO_CLASS_ID
:
1820 case IE_SAV_CLASS_ID
:
1823 case IE_SPL_CLASS_ID
:
1826 case IE_SRC_CLASS_ID
:
1829 case IE_STO_CLASS_ID
:
1832 case IE_TIS_CLASS_ID
:
1835 case IE_TLK_CLASS_ID
:
1838 case IE_TOH_CLASS_ID
:
1841 case IE_TOT_CLASS_ID
:
1844 case IE_VAR_CLASS_ID
:
1847 case IE_VVC_CLASS_ID
:
1850 case IE_WAV_CLASS_ID
:
1853 case IE_WED_CLASS_ID
:
1856 case IE_WFX_CLASS_ID
:
1859 case IE_WMP_CLASS_ID
:
1865 void Interface::FreeString(char *&str
) const
1868 strings
->FreeString(str
);
1873 ieStrRef
Interface::UpdateString(ieStrRef strref
, const char *text
) const
1875 return strings
->UpdateString( strref
, text
);
1878 char* Interface::GetString(ieStrRef strref
, ieDword options
) const
1882 if (!(options
& IE_STR_STRREFOFF
)) {
1883 vars
->Lookup( "Strref On", flags
);
1885 return strings
->GetString( strref
, flags
| options
);
1888 void Interface::SetFeature(int flag
, int position
)
1893 GameFeatures2
|= 1 << position
;
1895 GameFeatures2
&= ~( 1 << position
);
1900 GameFeatures
|= 1 << position
;
1902 GameFeatures
&= ~( 1 << position
);
1906 ieDword
Interface::HasFeature(int position
) const
1909 return GameFeatures2
& ( 1 << (position
-32) );
1911 return GameFeatures
& ( 1 << position
);
1914 /** Search directories and load a config file */
1915 bool Interface::LoadConfig(void)
1918 char path
[_MAX_PATH
];
1919 char name
[_MAX_PATH
];
1921 // Find directory where user stores GemRB configurations (~/.gemrb).
1922 // FIXME: Create it if it does not exist
1923 // Use current dir if $HOME is not defined (or bomb out??)
1925 char* s
= getenv( "HOME" );
1927 strcpy( UserDir
, s
);
1928 strcat( UserDir
, "/."PACKAGE
"/" );
1930 strcpy( UserDir
, "./" );
1933 // Find basename of this program. It does the same as basename (3),
1934 // but that's probably missing on some archs
1935 s
= strrchr( argv
[0], PathDelimiter
);
1943 //if (!name[0]) // FIXME: could this happen?
1944 // strcpy (name, PACKAGE); // ugly hack
1946 // If we were called as $0 -c <filename>, load config from filename
1947 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
1948 if (LoadConfig( argv
[2] )) {
1951 // Explicitly specified cfg file HAS to be present
1956 // FIXME: temporary hack, to be deleted??
1957 if (LoadConfig( "GemRB.cfg" )) {
1961 PathJoin( path
, UserDir
, name
, NULL
);
1962 strcat( path
, ".cfg" );
1964 if (LoadConfig( path
)) {
1969 PathJoin( path
, SYSCONFDIR
, name
, NULL
);
1970 strcat( path
, ".cfg" );
1972 if (LoadConfig( path
)) {
1977 // Don't try with default binary name if we have tried it already
1978 if (!strcmp( name
, PACKAGE
)) {
1982 PathJoin( path
, UserDir
, PACKAGE
, NULL
);
1983 strcat( path
, ".cfg" );
1985 if (LoadConfig( path
)) {
1990 PathJoin( path
, SYSCONFDIR
, PACKAGE
, NULL
);
1991 strcat( path
, ".cfg" );
1993 if (LoadConfig( path
)) {
2000 // If we were called as $0 -c <filename>, load config from filename
2001 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
2002 return LoadConfig( argv
[2] );
2003 // Explicitly specified cfg file HAS to be present
2005 strcpy( UserDir
, ".\\" );
2006 return LoadConfig( "GemRB.cfg" );
2010 bool Interface::LoadConfig(const char* filename
)
2014 printMessage("Config","Trying to open ", WHITE
);
2015 textcolor(LIGHT_WHITE
);
2016 printf("%s ", filename
);
2017 config
= fopen( filename
, "rb" );
2018 if (config
== NULL
) {
2019 printStatus("NOT FOUND", LIGHT_RED
);
2022 char name
[65], value
[_MAX_PATH
+ 3];
2024 //once GemRB own format is working well, this might be set to 0
2027 while (!feof( config
)) {
2030 if (fread( &rem
, 1, 1, config
) != 1)
2034 //it should always return 0
2035 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
2039 fseek( config
, -1, SEEK_CUR
);
2040 memset(value
,'\0',_MAX_PATH
+ 3);
2041 //the * element is not counted
2042 if (fscanf( config
, "%64[^= ] = %[^\r\n]%*[\r\n]", name
, value
)!=2)
2044 for (int i
=_MAX_PATH
+ 2; i
> 0; i
--) {
2045 if (value
[i
] == '\0') continue;
2046 if (value
[i
] == ' ') {
2053 if (stricmp( name
, "Width" ) == 0) {
2054 Width
= atoi( value
);
2055 } else if (stricmp( name
, "Height" ) == 0) {
2056 Height
= atoi( value
);
2057 } else if (stricmp( name
, "Bpp" ) == 0) {
2058 Bpp
= atoi( value
);
2059 } else if (stricmp( name
, "FullScreen" ) == 0) {
2060 FullScreen
= ( atoi( value
) == 0 ) ? false : true;
2061 } else if (stricmp( name
, "GUIEnhancements" ) == 0) {
2062 GUIEnhancements
= ( atoi( value
) == 0 ) ? false : true;
2063 } else if (stricmp( name
, "TooltipDelay" ) == 0) {
2064 TooltipDelay
= atoi( value
);
2065 } else if (stricmp( name
, "DoubleClickDelay" ) == 0) {
2066 evntmgr
->SetDCDelay( atoi( value
) );
2067 } else if (stricmp( name
, "RepeatKeyDelay" ) == 0) {
2068 evntmgr
->SetRKDelay( atoi( value
) );
2069 } else if (stricmp( name
, "SkipIntroVideos" ) == 0) {
2070 SkipIntroVideos
= ( atoi( value
) == 0 ) ? false : true;
2071 } else if (stricmp( name
, "DrawFPS" ) == 0) {
2072 DrawFPS
= ( atoi( value
) == 0 ) ? false : true;
2073 } else if (stricmp( name
, "EnableCheatKeys" ) == 0) {
2074 EnableCheatKeys ( atoi( value
) );
2075 } else if (stricmp( name
, "KeepCache" ) == 0) {
2076 KeepCache
= ( atoi( value
) == 0 ) ? false : true;
2077 } else if (stricmp( name
, "SkipPlugin" ) == 0) {
2078 plugin_flags
->SetAt( value
, PLF_SKIP
);
2079 } else if (stricmp( name
, "DelayPlugin" ) == 0) {
2080 plugin_flags
->SetAt( value
, PLF_DELAY
);
2081 } else if (stricmp( name
, "FogOfWar" ) == 0) {
2082 FogOfWar
= atoi( value
);
2083 } else if (stricmp( name
, "EndianSwitch" ) == 0) {
2084 DataStream::SetEndianSwitch(atoi(value
) );
2085 } else if (stricmp( name
, "CaseSensitive" ) == 0) {
2086 CaseSensitive
= ( atoi( value
) == 0 ) ? false : true;
2087 } else if (stricmp( name
, "MultipleQuickSaves" ) == 0) {
2088 GameControl::MultipleQuickSaves(atoi(value
));
2089 } else if (stricmp( name
, "GameOnCD" ) == 0) {
2090 GameOnCD
= ( atoi( value
) == 0 ) ? false : true;
2091 } else if (stricmp( name
, "GameDataPath" ) == 0) {
2092 strncpy( GameDataPath
, value
, sizeof(GameDataPath
) );
2093 } else if (stricmp( name
, "GameOverridePath" ) == 0) {
2094 strncpy( GameOverridePath
, value
, sizeof(GameOverridePath
) );
2095 } else if (stricmp( name
, "GemRBOverridePath" ) == 0) {
2096 strncpy( GemRBOverridePath
, value
, sizeof(GemRBOverridePath
) );
2097 ResolveFilePath(GemRBOverridePath
);
2098 } else if (stricmp( name
, "GameScriptsPath" ) == 0) {
2099 strncpy( GameScriptsPath
, value
, sizeof(GameScriptsPath
) );
2100 } else if (stricmp( name
, "GameSoundsPath" ) == 0) {
2101 strncpy( GameSoundsPath
, value
, sizeof(GameSoundsPath
) );
2102 } else if (stricmp( name
, "GamePortraitsPath" ) == 0) {
2103 strncpy( GamePortraitsPath
, value
, sizeof(GamePortraitsPath
) );
2104 } else if (stricmp( name
, "GameCharactersPath" ) == 0) {
2105 strncpy( GameCharactersPath
, value
, sizeof(GameCharactersPath
) );
2106 } else if (stricmp( name
, "GameName" ) == 0) {
2107 strncpy( GameName
, value
, sizeof(GameName
) );
2108 } else if (stricmp( name
, "GameType" ) == 0) {
2109 if (stricmp( value
, "tob" ) == 0) {
2110 strncpy( GameType
, "bg2", sizeof(GameType
) );
2112 strncpy( GameType
, value
, sizeof(GameType
) );
2114 } else if (stricmp( name
, "SaveAsOriginal") == 0) {
2115 SaveAsOriginal
= atoi(value
);
2116 } else if (stricmp( name
, "GemRBPath" ) == 0) {
2117 strcpy( GemRBPath
, value
);
2118 ResolveFilePath(GemRBPath
);
2119 } else if (stricmp( name
, "ScriptDebugMode" ) == 0) {
2120 SetScriptDebugMode(atoi(value
));
2121 } else if (stricmp( name
, "CachePath" ) == 0) {
2122 strncpy( CachePath
, value
, sizeof(CachePath
) );
2123 ResolveFilePath(CachePath
);
2124 } else if (stricmp( name
, "GUIScriptsPath" ) == 0) {
2125 strncpy( GUIScriptsPath
, value
, sizeof(GUIScriptsPath
) );
2126 ResolveFilePath( GUIScriptsPath
);
2127 } else if (stricmp( name
, "PluginsPath" ) == 0) {
2128 strncpy( PluginsPath
, value
, sizeof(PluginsPath
) );
2129 ResolveFilePath( PluginsPath
);
2130 } else if (stricmp( name
, "GamePath" ) == 0) {
2131 strncpy( GamePath
, value
, sizeof(GamePath
) );
2132 ResolveFilePath( GamePath
);
2133 } else if (stricmp( name
, "SavePath" ) == 0) {
2134 strncpy( SavePath
, value
, sizeof(SavePath
) );
2135 ResolveFilePath( SavePath
);
2136 } else if (strnicmp( name
, "CD", 2 ) == 0 &&
2137 name
[2] >= '1' && name
[2] <= '5' && name
[3] == 0) {
2138 strncpy( CD
[name
[2]-'1'], value
, sizeof(CD
[name
[2]-'1']) );
2139 ResolveFilePath( CD
[name
[2]-'1'] );
2146 strcpy( GameType
, "gemrb" );
2150 if (!GemRBPath
[0]) {
2151 strcpy( GemRBPath
, DATADIR
);
2155 if (!GemRBOverridePath
[0]) {
2156 strcpy( GemRBOverridePath
, GemRBPath
);
2159 if (!PluginsPath
[0]) {
2161 strcpy( PluginsPath
, PLUGINDIR
);
2163 PathJoin( PluginsPath
, GemRBPath
, "plugins", NULL
);
2167 if (!GUIScriptsPath
[0]) {
2168 strcpy( GUIScriptsPath
, GemRBPath
);
2172 strcpy( GameName
, GEMRB_STRING
);
2176 // FIXME: maybe should use UserDir instead of GamePath
2177 strcpy( SavePath
, GamePath
);
2180 if (! CachePath
[0]) {
2181 PathJoin( CachePath
, UserDir
, "Cache", NULL
);
2185 FixPath( GUIScriptsPath
, true );
2186 FixPath( PluginsPath
, true );
2187 FixPath( GemRBPath
, true );
2188 FixPath( GemRBOverridePath
, true );
2191 FixPath( GamePath
, true );
2194 //FixPath( SavePath, false );
2195 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2196 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2197 FixPath( SavePath
, true );
2199 FixPath( CachePath
, false );
2200 mkdir( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2201 chmod( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2203 printStatus( "OK", LIGHT_GREEN
);
2204 if ( StupidityDetector( CachePath
)) {
2205 printMessage("Core"," ",LIGHT_RED
);
2206 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath
);
2209 if (!KeepCache
) DelTree((const char *) CachePath
, false);
2210 FixPath( CachePath
, true );
2215 static void upperlower(int upper
, int lower
)
2217 pl_uppercase
[lower
]=(ieByte
) upper
;
2218 pl_lowercase
[upper
]=(ieByte
) lower
;
2221 static const char *game_flags
[GF_COUNT
+1]={
2222 "HasKaputz", //0 GF_HAS_KAPUTZ
2223 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2224 "HasSongList", //2 GF_HAS_SONGLIST
2225 "TeamMovement", //3 GF_TEAM_MOVEMENT
2226 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2227 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2228 "HasPartyIni", //6 GF_HAS_PARTY_INI
2229 "SoundFolders", //7 GF_SOUNDFOLDERS
2230 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2231 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2232 "HasDPLAYER", //10GF_HAS_DPLAYER
2233 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2234 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2235 "HasDescIcon", //13GF_HAS_DESC_ICON
2236 "HasPickSound", //14GF_HAS_PICK_SOUND
2237 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2238 "AutomapIni", //16GF_AUTOMAP_INI
2239 "SmallFog", //17GF_SMALL_FOG
2240 "ReverseDoor", //18GF_REVERSE_DOOR
2241 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2242 "HasSpellList", //20GF_HAS_SPELLLIST
2243 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2244 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2245 "KnowWorld", //23GF_KNOW_WORLD
2246 "ReverseToHit", //24GF_REVERSE_TOHIT
2247 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2248 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2249 "MagicBit", //27GF_MAGICBIT
2250 "CheckAbilities", //28GF_CHECK_ABILITIES
2251 "ChallengeRating", //29GF_CHALLENGERATING
2252 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2253 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2254 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2255 "SpawnIni", //33GF_SPAWN_INI
2256 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2257 "HasResDataIni", //35GF_RESDATA_INI
2258 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2259 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2260 "3EdRules", //38GF_3ED_RULES
2261 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2262 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2263 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2264 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2265 "ProperBackstab", //43GF_PROPER_BACKSTAB
2266 "OnScreenText", //44GF_ONSCREEN_TEXT
2267 "HasSpecificDamageBonus", //45GF_SPECIFIC_DMG_BONUS
2268 NULL
//for our own safety, this marks the end of the pole
2271 /** Loads gemrb.ini */
2272 bool Interface::LoadGemRBINI()
2274 DataStream
* inifile
= gamedata
->GetResource( "gemrb", IE_INI_CLASS_ID
);
2276 printStatus( "ERROR", LIGHT_RED
);
2280 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE
);
2281 printf( "%s",inifile
->originalfile
);
2283 if (!IsAvailable( IE_INI_CLASS_ID
)) {
2284 printStatus( "ERROR", LIGHT_RED
);
2285 printf( "[Core]: No INI Importer Available.\n" );
2288 DataFileMgr
* ini
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
2289 ini
->Open( inifile
, true ); //autofree
2291 printStatus( "OK", LIGHT_GREEN
);
2295 // Resrefs are already initialized in Interface::Interface()
2296 s
= ini
->GetKeyAsString( "resources", "CursorBAM", NULL
);
2298 strnlwrcpy( CursorBam
, s
, 8 ); //console cursor
2300 s
= ini
->GetKeyAsString( "resources", "ScrollCursorBAM", NULL
);
2302 strnlwrcpy( ScrollCursorBam
, s
, 8 );
2304 s
= ini
->GetKeyAsString( "resources", "ButtonFont", NULL
);
2306 strnlwrcpy( ButtonFont
, s
, 8 );
2308 s
= ini
->GetKeyAsString( "resources", "TooltipFont", NULL
);
2310 strnlwrcpy( TooltipFont
, s
, 8 );
2312 s
= ini
->GetKeyAsString( "resources", "MovieFont", NULL
);
2314 strnlwrcpy( MovieFont
, s
, 8 );
2316 s
= ini
->GetKeyAsString( "resources", "TooltipBack", NULL
);
2318 strnlwrcpy( TooltipBackResRef
, s
, 8 );
2320 s
= ini
->GetKeyAsString( "resources", "TooltipColor", NULL
);
2323 unsigned long c
= strtoul (s
+ 1, NULL
, 16);
2324 // FIXME: check errno
2325 TooltipColor
.r
= (unsigned char) (c
>> 24);
2326 TooltipColor
.g
= (unsigned char) (c
>> 16);
2327 TooltipColor
.b
= (unsigned char) (c
>> 8);
2328 TooltipColor
.a
= (unsigned char) (c
);
2332 //which stat determines the fist weapon (defaults to class)
2333 Actor::SetFistStat(ini
->GetKeyAsInt( "resources", "FistStat", IE_CLASS
));
2335 TooltipMargin
= ini
->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin
);
2337 // The format of GroundCircle can be:
2338 // GroundCircleBAM1 = wmpickl/3
2339 // to denote that the bitmap should be scaled down 3x
2340 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
2342 sprintf( name
, "GroundCircleBAM%d", size
+1 );
2343 s
= ini
->GetKeyAsString( "resources", name
, NULL
);
2345 const char *pos
= strchr( s
, '/' );
2347 GroundCircleScale
[size
] = atoi( pos
+1 );
2348 strncpy( GroundCircleBam
[size
], s
, pos
- s
);
2349 GroundCircleBam
[size
][pos
- s
] = '\0';
2351 strcpy( GroundCircleBam
[size
], s
);
2356 s
= ini
->GetKeyAsString( "resources", "INIConfig", NULL
);
2358 strcpy( INIConfig
, s
);
2360 s
= ini
->GetKeyAsString( "resources", "Palette16", NULL
);
2362 strcpy( Palette16
, s
);
2364 s
= ini
->GetKeyAsString( "resources", "Palette32", NULL
);
2366 strcpy( Palette32
, s
);
2368 s
= ini
->GetKeyAsString( "resources", "Palette256", NULL
);
2370 strcpy( Palette256
, s
);
2372 unsigned int i
= (unsigned int) ini
->GetKeyAsInt ("charset", "CharCount", 0);
2376 snprintf(key
,9,"Letter%d", i
+1);
2377 s
= ini
->GetKeyAsString( "charset", key
, NULL
);
2379 const char *s2
= strchr(s
,',');
2381 upperlower(atoi(s
), atoi(s2
+1) );
2386 MaximumAbility
= ini
->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2388 RedrawTile
= ini
->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2390 for (i
=0;i
<GF_COUNT
;i
++) {
2391 if (!game_flags
[i
]) {
2392 printf("Fix the game flags!\n");
2395 SetFeature( ini
->GetKeyAsInt( "resources", game_flags
[i
], 0 ), i
);
2396 printMessage("Option", "", GREEN
);
2397 printf("%s = %s\n", game_flags
[i
], HasFeature(i
)?"yes":"no");
2400 ForceStereo
= ini
->GetKeyAsInt( "resources", "ForceStereo", 0 );
2406 Palette
* Interface::CreatePalette(const Color
&color
, const Color
&back
)
2408 Palette
* pal
= new Palette();
2410 pal
->col
[0].g
= 0xff;
2413 for (int i
= 1; i
< 256; i
++) {
2414 pal
->col
[i
].r
= back
.r
+
2415 ( unsigned char ) ( ( ( color
.r
- back
.r
) * ( i
) ) / 255.0 );
2416 pal
->col
[i
].g
= back
.g
+
2417 ( unsigned char ) ( ( ( color
.g
- back
.g
) * ( i
) ) / 255.0 );
2418 pal
->col
[i
].b
= back
.b
+
2419 ( unsigned char ) ( ( ( color
.b
- back
.b
) * ( i
) ) / 255.0 );
2420 pal
->col
[i
].a
= back
.a
+
2421 ( unsigned char ) ( ( ( color
.a
- back
.a
) * ( i
) ) / 255.0 );
2426 /** No descriptions */
2427 Color
* Interface::GetPalette(unsigned index
, int colors
, Color
*pal
) const
2432 } else if (colors
<= 32) {
2434 } else if (colors
== 256) {
2439 if (index
>= img
->GetHeight()) {
2442 for (int i
= 0; i
< colors
; i
++) {
2443 pal
[i
] = img
->GetPixel(i
, index
);
2447 /** Returns a preloaded Font */
2448 Font
* Interface::GetFont(const char *ResRef
) const
2450 for (unsigned int i
= 0; i
< fonts
.size(); i
++) {
2451 if (strnicmp( fonts
[i
]->ResRef
, ResRef
, 8 ) == 0) {
2458 Font
* Interface::GetFont(unsigned int index
) const
2460 if (index
>= fonts
.size()) {
2463 return fonts
[index
];
2466 Font
* Interface::GetButtonFont() const
2468 return GetFont( ButtonFont
);
2471 /** Returns the Event Manager */
2472 EventMgr
* Interface::GetEventMgr() const
2477 /** Returns the Window Manager */
2478 WindowMgr
* Interface::GetWindowMgr() const
2483 /** Get GUI Script Manager */
2484 ScriptEngine
* Interface::GetGUIScriptEngine() const
2489 //NOTE: if there were more summoned creatures, it will return only the last
2490 Actor
*Interface::SummonCreature(const ieResRef resource
, const ieResRef vvcres
, Scriptable
*Owner
, Actor
*target
, Point
&position
, int eamod
, int level
, Effect
*fx
, bool sexmod
)
2492 //maximum number of monsters summoned
2497 //decrease the number of summoned creatures with the number of already summoned creatures here
2498 //the summoned creatures have a special IE_SPECIFIC
2501 ab
= gamedata
->GetCreature(resource
);
2506 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2507 ab
->LastSummoner
= ((Actor
*) Owner
)->GetID();
2509 //Always use Base stats for the recently summoned creature
2513 if (eamod
==EAM_SOURCEALLY
|| eamod
==EAM_SOURCEENEMY
) {
2514 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2515 enemyally
= ((Actor
*) Owner
)->GetStat(IE_EA
)>EA_GOODCUTOFF
;
2521 enemyally
= target
->GetBase(IE_EA
)>EA_GOODCUTOFF
;
2528 case EAM_SOURCEALLY
:
2531 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2533 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2536 case EAM_SOURCEENEMY
:
2539 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2541 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2545 ab
->SetBase(IE_EA
, EA_NEUTRAL
);
2551 // mark the summon, but only if they don't have a special sex already
2552 if (sexmod
&& ab
->BaseStats
[IE_SEX
] < SEX_EXTRA
) {
2553 ab
->SetBase(IE_SEX
, SEX_SUMMON
);
2558 map
= target
->GetCurrentArea();
2560 map
= Owner
->GetCurrentArea();
2563 ab
->SetPosition(position
, true, 0);
2564 ab
->RefreshEffects(NULL
);
2567 ScriptedAnimation
* vvc
= gamedata
->GetScriptedAnimation(vvcres
, false);
2569 //This is the final position of the summoned creature
2570 //not the original target point
2571 vvc
->XPos
=ab
->Pos
.x
;
2572 vvc
->YPos
=ab
->Pos
.y
;
2573 //force vvc to play only once
2575 map
->AddVVCell( vvc
);
2579 //remove the xp value of friendly summons
2580 if (ab
->BaseStats
[IE_EA
]<EA_GOODCUTOFF
) {
2581 ab
->SetBase(IE_XPVALUE
, 0);
2584 ApplyEffect(fx
, ab
, Owner
);
2587 //this check should happen after the fact
2588 level
-= ab
->GetBase(IE_XP
);
2597 void Interface::RedrawControls(const char *varname
, unsigned int value
)
2599 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2600 Window
*win
= windows
[i
];
2601 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2602 win
->RedrawControls(varname
, value
);
2607 void Interface::RedrawAll()
2609 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2610 Window
*win
= windows
[i
];
2611 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2617 /** Loads a WindowPack (CHUI file) in the Window Manager */
2618 bool Interface::LoadWindowPack(const char* name
)
2620 DataStream
* stream
= gamedata
->GetResource( name
, IE_CHU_CLASS_ID
);
2621 if (stream
== NULL
) {
2622 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED
);
2623 printf( "%s.chu\n", name
);
2626 if (!GetWindowMgr()->Open( stream
, true )) {
2627 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED
);
2628 printf( "%s.chu\n", name
);
2632 strncpy( WindowPack
, name
, sizeof( WindowPack
) );
2633 WindowPack
[sizeof( WindowPack
) - 1] = '\0';
2638 /** Loads a Window in the Window Manager */
2639 int Interface::LoadWindow(unsigned short WindowID
)
2643 for (i
= 0; i
< windows
.size(); i
++) {
2644 Window
*win
= windows
[i
];
2647 if (win
->Visible
==WINDOW_INVALID
) {
2650 if (win
->WindowID
== WindowID
&&
2651 !strnicmp( WindowPack
, win
->WindowPack
, sizeof(WindowPack
) )) {
2657 Window
* win
= windowmgr
->GetWindow( WindowID
);
2661 memcpy( win
->WindowPack
, WindowPack
, sizeof(WindowPack
) );
2664 for (i
= 0; i
< windows
.size(); i
++) {
2665 if (windows
[i
] == NULL
) {
2671 windows
.push_back( win
);
2672 slot
= ( int ) windows
.size() - 1;
2674 windows
[slot
] = win
;
2679 // FIXME: it's a clone of LoadWindow
2680 /** Creates a Window in the Window Manager */
2681 int Interface::CreateWindow(unsigned short WindowID
, int XPos
, int YPos
, unsigned int Width
, unsigned int Height
, char* Background
)
2685 for (i
= 0; i
< windows
.size(); i
++) {
2686 if (windows
[i
] == NULL
)
2688 if (windows
[i
]->WindowID
== WindowID
&& !stricmp( WindowPack
,
2689 windows
[i
]->WindowPack
)) {
2691 windows
[i
]->Invalidate();
2696 Window
* win
= new Window( WindowID
, (ieWord
) XPos
, (ieWord
) YPos
, (ieWord
) Width
, (ieWord
) Height
);
2697 if (Background
[0]) {
2698 if (IsAvailable( IE_MOS_CLASS_ID
)) {
2699 ImageMgr
* mos
= ( ImageMgr
* )
2700 gamedata
->GetResource( Background
, &ImageMgr::ID
);
2702 win
->SetBackGround( mos
->GetSprite2D(), true );
2705 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2707 printf( "[Core]: No MOS Importer Available, skipping background\n" );
2710 strcpy( win
->WindowPack
, WindowPack
);
2713 for (i
= 0; i
< windows
.size(); i
++) {
2714 if (windows
[i
] == NULL
) {
2720 windows
.push_back( win
);
2721 slot
= ( int ) windows
.size() - 1;
2723 windows
[slot
] = win
;
2729 /** Sets a Window on the Top */
2730 void Interface::SetOnTop(int Index
)
2732 std::vector
<int>::iterator t
;
2733 for(t
= topwin
.begin(); t
!= topwin
.end(); ++t
) {
2739 if(topwin
.size() != 0)
2740 topwin
.insert(topwin
.begin(), Index
);
2742 topwin
.push_back(Index
);
2744 /** Add a window to the Window List */
2745 void Interface::AddWindow(Window
* win
)
2748 for(unsigned int i
= 0; i
< windows
.size(); i
++) {
2749 Window
*w
= windows
[i
];
2757 windows
.push_back(win
);
2758 slot
=(int)windows
.size()-1;
2761 windows
[slot
] = win
;
2765 /** Get a Control on a Window */
2766 int Interface::GetControl(unsigned short WindowIndex
, unsigned long ControlID
) const
2768 if (WindowIndex
>= windows
.size()) {
2771 Window
* win
= windows
[WindowIndex
];
2777 Control
* ctrl
= win
->GetControl( (unsigned short) i
);
2780 if (ctrl
->ControlID
== ControlID
)
2785 /** Adjust the Scrolling factor of a control (worldmap atm) */
2786 int Interface::AdjustScrolling(unsigned short WindowIndex
,
2787 unsigned short ControlIndex
, short x
, short y
)
2789 if (WindowIndex
>= windows
.size()) {
2792 Window
* win
= windows
[WindowIndex
];
2796 Control
* ctrl
= win
->GetControl( ControlIndex
);
2800 switch(ctrl
->ControlType
) {
2801 case IE_GUI_WORLDMAP
:
2802 ((WorldMapControl
*) ctrl
)->AdjustScrolling(x
,y
);
2804 default: //doesn't work for these
2810 /** Set the Text of a Control */
2811 int Interface::SetText(unsigned short WindowIndex
,
2812 unsigned short ControlIndex
, const char* string
)
2814 if (WindowIndex
>= windows
.size()) {
2817 Window
* win
= windows
[WindowIndex
];
2821 Control
* ctrl
= win
->GetControl( ControlIndex
);
2825 return ctrl
->SetText( string
);
2827 /** Set the Tooltip text of a Control */
2828 int Interface::SetTooltip(unsigned short WindowIndex
,
2829 unsigned short ControlIndex
, const char* string
)
2831 if (WindowIndex
>= windows
.size()) {
2834 Window
* win
= windows
[WindowIndex
];
2838 Control
* ctrl
= win
->GetControl( ControlIndex
);
2842 return ctrl
->SetTooltip( string
);
2845 void Interface::DisplayTooltip(int x
, int y
, Control
*ctrl
)
2847 if (tooltip_ctrl
&& tooltip_ctrl
== ctrl
&& tooltip_x
== x
&& tooltip_y
== y
)
2851 tooltip_currtextw
= 0;
2852 tooltip_ctrl
= ctrl
;
2855 int Interface::GetVisible(unsigned short WindowIndex
) const
2857 if (WindowIndex
>= windows
.size()) {
2860 Window
* win
= windows
[WindowIndex
];
2864 return win
->Visible
;
2866 /** Set a Window Visible Flag */
2867 int Interface::SetVisible(unsigned short WindowIndex
, int visible
)
2869 if (WindowIndex
>= windows
.size()) {
2872 Window
* win
= windows
[WindowIndex
];
2876 if (visible
!=WINDOW_FRONT
) {
2877 win
->Visible
= (char) visible
;
2882 //here is a fallthrough
2883 case WINDOW_INVISIBLE
:
2884 //hiding the viewport if the gamecontrol window was made invisible
2885 if (win
->WindowID
==65535) {
2886 video
->SetViewport( 0,0,0,0 );
2888 evntmgr
->DelWindow( win
);
2891 case WINDOW_VISIBLE
:
2892 if (win
->WindowID
==65535) {
2893 video
->SetViewport( win
->XPos
, win
->YPos
, win
->Width
, win
->Height
);
2895 //here is a fallthrough
2897 if (win
->Visible
==WINDOW_VISIBLE
) {
2898 evntmgr
->AddWindow( win
);
2901 SetOnTop( WindowIndex
);
2908 /** Set the Status of a Control in a Window */
2909 int Interface::SetControlStatus(unsigned short WindowIndex
,
2910 unsigned short ControlIndex
, unsigned long Status
)
2912 //don't set the status of an already invalidated window
2913 Window
* win
= GetWindow(WindowIndex
);
2917 Control
* ctrl
= win
->GetControl( ControlIndex
);
2921 if (Status
&IE_GUI_CONTROL_FOCUSED
) {
2922 evntmgr
->SetFocused( win
, ctrl
);
2924 if (ctrl
->ControlType
!= ((Status
>> 24) & 0xff) ) {
2927 switch (ctrl
->ControlType
) {
2931 Button
* btn
= ( Button
* ) ctrl
;
2932 btn
->SetState( ( unsigned char ) ( Status
& 0x7f ) );
2936 ctrl
->Value
= Status
& 0x7f;
2942 /** Show a Window in Modal Mode */
2943 int Interface::ShowModal(unsigned short WindowIndex
, int Shadow
)
2945 if (WindowIndex
>= windows
.size()) {
2946 printMessage( "Core", "Window not found", LIGHT_RED
);
2949 Window
* win
= windows
[WindowIndex
];
2951 printMessage( "Core", "Window already freed", LIGHT_RED
);
2954 win
->Visible
= WINDOW_FRONT
;
2955 //don't destroy the other window handlers
2957 SetOnTop( WindowIndex
);
2958 evntmgr
->AddWindow( win
);
2959 evntmgr
->SetFocused( win
, NULL
);
2972 Region
r( 0, 0, Width
, Height
);
2974 if (Shadow
== MODAL_SHADOW_GRAY
) {
2975 video
->DrawRect( r
, gray
);
2976 } else if (Shadow
== MODAL_SHADOW_BLACK
) {
2977 video
->DrawRect( r
, black
);
2984 bool Interface::IsFreezed()
2986 return !update_scripts
;
2989 void Interface::GameLoop(void)
2991 update_scripts
= false;
2992 GameControl
*gc
= GetGameControl();
2994 update_scripts
= !(gc
->GetDialogueFlags() & DF_FREEZE_SCRIPTS
);
2997 GSUpdate(update_scripts
);
2999 //i'm not sure if this should be here
3001 //in multi player (if we ever get to it), only the server must call this
3002 if (update_scripts
) {
3003 if ( game
->selected
.size() > 0 ) {
3004 gc
->ChangeMap(core
->GetFirstSelectedPC(true), false);
3006 // the game object will run the area scripts as well
3007 game
->UpdateScripts();
3011 /** handles hardcoded gui behaviour */
3012 void Interface::HandleGUIBehaviour(void)
3014 GameControl
*gc
= GetGameControl();
3016 //this variable is used all over in the following hacks
3017 int flg
= gc
->GetDialogueFlags();
3019 //the following part is a series of hardcoded gui behaviour
3022 if (flg
& DF_IN_DIALOG
) {
3027 ieDword var
= (ieDword
) -3;
3028 vars
->Lookup("DialogChoose", var
);
3029 if ((int) var
== -2) {
3031 } else if ( (int)var
!=-3) {
3032 gc
->DialogChoose(var
);
3033 if (!(gc
->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW
| DF_OPENENDWINDOW
)))
3034 guiscript
->RunFunction( "NextDialogState" );
3036 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3037 ieDword newvar
= 0; vars
->Lookup("DialogChoose", newvar
);
3038 if (var
== (ieDword
) -1 || newvar
!= (ieDword
) -1) {
3039 vars
->SetAt("DialogChoose", (ieDword
) -3);
3042 if (flg
& DF_OPENCONTINUEWINDOW
) {
3043 guiscript
->RunFunction( "OpenContinueMessageWindow" );
3044 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3045 } else if (flg
& DF_OPENENDWINDOW
) {
3046 guiscript
->RunFunction( "OpenEndMessageWindow" );
3047 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3051 //handling container
3052 if (CurrentContainer
&& UseContainer
) {
3053 if (!(flg
& DF_IN_CONTAINER
) ) {
3054 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_OR
);
3055 guiscript
->RunFunction( "OpenContainerWindow" );
3058 if (flg
& DF_IN_CONTAINER
) {
3059 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_NAND
);
3060 guiscript
->RunFunction( "CloseContainerWindow" );
3067 void Interface::DrawWindows(void)
3069 //here comes the REAL drawing of windows
3071 ModalWindow
->DrawWindow();
3074 size_t i
= topwin
.size();
3076 unsigned int t
= topwin
[i
];
3078 if ( t
>=windows
.size() )
3081 //visible ==1 or 2 will be drawn
3082 Window
* win
= windows
[t
];
3084 if (win
->Visible
== WINDOW_INVALID
) {
3085 topwin
.erase(topwin
.begin()+i
);
3086 evntmgr
->DelWindow( win
);
3089 } else if (win
->Visible
) {
3096 void Interface::DrawTooltip ()
3098 if (! tooltip_ctrl
|| !tooltip_ctrl
->Tooltip
)
3101 Font
* fnt
= GetFont( TooltipFont
);
3102 char *tooltip_text
= tooltip_ctrl
->Tooltip
;
3106 int strw
= fnt
->CalcStringWidth( tooltip_text
) + 8;
3108 int h
= fnt
->maxHeight
;
3111 // animate BG tooltips
3112 // TODO: make tooltip animation an option instead
3113 // of following hard-coded check!
3114 if (TooltipMargin
== 5) {
3115 // TODO: make speed an option
3116 int tooltip_anim_speed
= 15;
3117 if (tooltip_currtextw
< strw
) {
3118 tooltip_currtextw
+= tooltip_anim_speed
;
3120 if (tooltip_currtextw
> strw
) {
3121 tooltip_currtextw
= strw
;
3123 w
= tooltip_currtextw
;
3126 h
= TooltipBack
[0]->Height
;
3127 w1
= TooltipBack
[1]->Width
;
3128 w2
= TooltipBack
[2]->Width
;
3129 w
+= TooltipMargin
*2;
3130 strw
+= TooltipMargin
*2;
3131 //multiline in case of too much text
3132 if (w
>TooltipBack
[0]->Width
)
3133 strw
=w
=TooltipBack
[0]->Width
;
3134 else if (strw
>TooltipBack
[0]->Width
)
3135 strw
=TooltipBack
[0]->Width
;
3138 int strx
= tooltip_x
- strw
/ 2;
3139 int y
= tooltip_y
- h
/ 2;
3140 // Ensure placement within the screen
3141 if (strx
< 0) strx
= 0;
3142 else if (strx
+ strw
+ w1
+ w2
> Width
)
3143 strx
= Width
- strw
- w1
- w2
;
3145 else if (y
+ h
> Height
)
3148 int x
= strx
+ ((strw
- w
) / 2);
3150 // FIXME: take back[0] from center, not from left end
3151 Region r2
= Region( x
, y
, w
, h
);
3153 video
->BlitSprite( TooltipBack
[0], x
+ TooltipMargin
, y
, true, &r2
);
3154 video
->BlitSprite( TooltipBack
[1], x
, y
, true );
3155 video
->BlitSprite( TooltipBack
[2], x
+ w
, y
, true );
3159 r2
.x
+=TooltipMargin
;
3160 strx
+=TooltipMargin
;
3162 Region textr
= Region( strx
, y
, strw
, h
);
3163 fnt
->Print( r2
, textr
, (ieByte
*) tooltip_text
, NULL
,
3164 IE_FONT_ALIGN_CENTER
| IE_FONT_ALIGN_MIDDLE
, true );
3167 //interface for higher level functions, if the window was
3168 //marked for deletion it is not returned
3169 Window
* Interface::GetWindow(unsigned short WindowIndex
) const
3171 if (WindowIndex
< windows
.size()) {
3172 Window
*win
= windows
[WindowIndex
];
3173 if (win
&& (win
->Visible
!=WINDOW_INVALID
) ) {
3180 // this function will determine if wnd is a valid window pointer
3181 // by checking if its WindowID is the same as the reference
3182 bool Interface::IsValidWindow(unsigned short WindowID
, Window
*wnd
) const
3184 size_t WindowIndex
= windows
.size();
3185 while (WindowIndex
--) {
3186 if (windows
[WindowIndex
] == wnd
) {
3187 return wnd
->WindowID
== WindowID
;
3193 //this function won't delete the window, just mark it for deletion
3194 //it will be deleted in the next DrawWindows cycle
3195 //regardless, the window deleted is inaccessible for gui scripts and
3196 //other high level functions from now
3197 int Interface::DelWindow(unsigned short WindowIndex
)
3199 if (WindowIndex
>= windows
.size()) {
3202 Window
* win
= windows
[WindowIndex
];
3203 if ((win
== NULL
) || (win
->Visible
==WINDOW_INVALID
) ) {
3204 printMessage( "Core", "Window deleted again", LIGHT_RED
);
3207 if (win
== ModalWindow
) {
3209 RedrawAll(); //marking windows for redraw
3211 evntmgr
->DelWindow( win
);
3213 //re-capturing new (old) modal window if any
3214 size_t tw
= topwin
.size();
3215 for(size_t i
=0;i
<tw
;i
++) {
3216 Window
*tmp
= windows
[topwin
[i
]];
3217 if (tmp
->Visible
==WINDOW_FRONT
) {
3225 void Interface::DelAllWindows()
3227 vars
->SetAt("MessageWindow", (ieDword
) ~0);
3228 vars
->SetAt("OptionsWindow", (ieDword
) ~0);
3229 vars
->SetAt("PortraitWindow", (ieDword
) ~0);
3230 vars
->SetAt("ActionsWindow", (ieDword
) ~0);
3231 vars
->SetAt("TopWindow", (ieDword
) ~0);
3232 vars
->SetAt("OtherWindow", (ieDword
) ~0);
3233 vars
->SetAt("FloatWindow", (ieDword
) ~0);
3234 for(unsigned int WindowIndex
=0; WindowIndex
<windows
.size();WindowIndex
++) {
3235 Window
* win
= windows
[WindowIndex
];
3244 /** Popup the Console */
3245 void Interface::PopupConsole()
3247 ConsolePopped
= !ConsolePopped
;
3249 console
->Changed
= true;
3252 /** Draws the Console */
3253 void Interface::DrawConsole()
3255 console
->Draw( 0, 0 );
3258 /** Get the Sound Manager */
3259 SaveGameIterator
* Interface::GetSaveGameIterator() const
3263 /** Sends a termination signal to the Video Driver */
3264 bool Interface::Quit(void)
3266 return video
->Quit();
3268 /** Returns the variables dictionary */
3269 Variables
* Interface::GetDictionary() const
3273 /** Returns the token dictionary */
3274 Variables
* Interface::GetTokenDictionary() const
3278 /** Get the Music Manager */
3279 MusicMgr
* Interface::GetMusicMgr() const
3283 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3284 int Interface::LoadSymbol(const char* ResRef
)
3286 int ind
= GetSymbolIndex( ResRef
);
3290 DataStream
* str
= gamedata
->GetResource( ResRef
, IE_IDS_CLASS_ID
);
3294 SymbolMgr
* sm
= ( SymbolMgr
* ) GetInterface( IE_IDS_CLASS_ID
);
3299 if (!sm
->Open( str
, true )) {
3305 strncpy( s
.ResRef
, ResRef
, 8 );
3308 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3309 if (symbols
[i
].free
) {
3318 symbols
.push_back( s
);
3319 return ( int ) symbols
.size() - 1;
3321 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3322 int Interface::GetSymbolIndex(const char* ResRef
) const
3324 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3325 if (symbols
[i
].free
)
3327 if (strnicmp( symbols
[i
].ResRef
, ResRef
, 8 ) == 0)
3332 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3333 SymbolMgr
* Interface::GetSymbol(unsigned int index
) const
3335 if (index
>= symbols
.size()) {
3338 if (symbols
[index
].free
) {
3341 return symbols
[index
].sm
;
3343 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3344 bool Interface::DelSymbol(unsigned int index
)
3346 if (index
>= symbols
.size()) {
3349 if (symbols
[index
].free
) {
3352 if (symbols
[index
].sm
)
3353 symbols
[index
].sm
->release();
3354 symbols
[index
].free
= true;
3357 /** Plays a Movie */
3358 int Interface::PlayMovie(const char* ResRef
)
3360 MoviePlayer
* mp
= (MoviePlayer
*) gamedata
->GetResource( ResRef
, &MoviePlayer::ID
);
3365 ieDword subtitles
= 0;
3366 Font
*SubtitleFont
= NULL
;
3367 Palette
*palette
= NULL
;
3368 ieDword
*frames
= NULL
;
3369 ieDword
*strrefs
= NULL
;
3373 //one of these two should exist (they both mean the same thing)
3374 vars
->Lookup("Display Movie Subtitles", subtitles
);
3381 vars
->Lookup("Display Subtitles", subtitles
);
3384 if (subtitles
&& sttable
.load(ResRef
)) {
3385 cnt
+= sttable
->GetRowCount();
3387 frames
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3388 strrefs
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3392 if (frames
&& strrefs
) {
3393 for (int i
=0;i
<cnt
;i
++) {
3394 frames
[i
] = atoi (sttable
->QueryField(i
+offset
, 0) );
3395 strrefs
[i
] = atoi (sttable
->QueryField(i
+offset
, 1) );
3398 int r
= atoi(sttable
->QueryField("red", "frame"));
3399 int g
= atoi(sttable
->QueryField("green", "frame"));
3400 int b
= atoi(sttable
->QueryField("blue", "frame"));
3401 SubtitleFont
= GetFont (MovieFont
); //will change
3404 Color fore
= {(unsigned char) r
,(unsigned char) g
,(unsigned char) b
, 0x00};
3405 Color back
= {0x00, 0x00, 0x00, 0x00};
3406 palette
= CreatePalette( fore
, back
);
3411 //shutting down music and ambients before movie
3414 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3415 if (ambim
) ambim
->deactivate();
3416 video
->SetMovieFont(SubtitleFont
, palette
);
3417 mp
->CallBackAtFrames(cnt
, frames
, strrefs
);
3420 gamedata
->FreePalette( palette
);
3428 if (ambim
) ambim
->activate();
3429 //this will fix redraw all windows as they looked like
3433 //Setting the movie name to 1
3434 vars
->SetAt( ResRef
, 1 );
3438 int Interface::Roll(int dice
, int size
, int add
) const
3447 return add
+ dice
* size
/ 2;
3449 for (int i
= 0; i
< dice
; i
++) {
3450 add
+= rand() % size
+ 1;
3455 static char bmp_suffix
[6]="M.BMP";
3456 static char png_suffix
[6]="M.PNG";
3458 int Interface::GetPortraits(TextArea
* ta
, bool smallorlarge
)
3461 char Path
[_MAX_PATH
];
3470 PathJoin( Path
, GamePath
, GamePortraitsPath
, NULL
);
3471 DIR* dir
= opendir( Path
);
3475 //Lookup the first entry in the Directory
3476 struct dirent
* de
= readdir( dir
);
3481 printf( "Looking in %s\n", Path
);
3483 if (de
->d_name
[0] == '.')
3485 char dtmp
[_MAX_PATH
];
3486 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3489 if ( S_ISDIR( fst
.st_mode
))
3492 char *pos
= strstr(de
->d_name
,bmp_suffix
);
3493 if (!pos
&& IsAvailable(IE_PNG_CLASS_ID
) ) {
3494 pos
= strstr(de
->d_name
,png_suffix
);
3499 ta
->AppendText( de
->d_name
, -1 );
3500 } while (( de
= readdir( dir
) ) != NULL
);
3505 int Interface::GetCharSounds(TextArea
* ta
)
3509 char Path
[_MAX_PATH
];
3511 PathJoin( Path
, GamePath
, GameSoundsPath
, NULL
);
3512 hasfolders
= ( HasFeature( GF_SOUNDFOLDERS
) != 0 );
3513 DIR* dir
= opendir( Path
);
3517 //Lookup the first entry in the Directory
3518 struct dirent
* de
= readdir( dir
);
3523 printf( "Looking in %s\n", Path
);
3525 if (de
->d_name
[0] == '.')
3527 char dtmp
[_MAX_PATH
];
3528 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3531 if (hasfolders
== !S_ISDIR( fst
.st_mode
))
3535 char *pos
= strstr(de
->d_name
,"A.WAV");
3540 ta
->AppendText( de
->d_name
, -1 );
3541 } while (( de
= readdir( dir
) ) != NULL
);
3546 int Interface::GetCharacters(TextArea
* ta
)
3549 char Path
[_MAX_PATH
];
3551 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
3552 DIR* dir
= opendir( Path
);
3556 //Lookup the first entry in the Directory
3557 struct dirent
* de
= readdir( dir
);
3562 printf( "Looking in %s\n", Path
);
3564 if (de
->d_name
[0] == '.')
3566 char dtmp
[_MAX_PATH
];
3567 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3571 char *pos
= strstr(de
->d_name
,".CHR");
3575 ta
->AppendText( de
->d_name
, -1 );
3576 } while (( de
= readdir( dir
) ) != NULL
);
3581 bool Interface::LoadINI(const char* filename
)
3584 config
= fopen( filename
, "rb" );
3585 if (config
== NULL
) {
3588 char name
[65], value
[_MAX_PATH
+ 3];
3589 while (!feof( config
)) {
3594 if (fread( &rem
, 1, 1, config
) != 1)
3597 if (( rem
== '#' ) ||
3605 } else if (rem
== '\n')
3608 //it should always return zero
3609 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
3613 fseek( config
, -1, SEEK_CUR
);
3614 //the * element is not counted
3615 if (fscanf( config
, "%[^=]=%[^\r\n]%*[\r\n]", name
, value
)!=2)
3617 if (( value
[0] >= '0' ) && ( value
[0] <= '9' )) {
3618 vars
->SetAt( name
, atoi( value
) );
3625 /** Enables/Disables the Cut Scene Mode */
3626 void Interface::SetCutSceneMode(bool active
)
3628 GameControl
*gc
= GetGameControl();
3630 gc
->SetCutSceneMode( active
);
3634 game
->ControlStatus
|= CS_HIDEGUI
;
3636 game
->ControlStatus
&= ~CS_HIDEGUI
;
3638 SetEventFlag(EF_CONTROL
);
3640 video
->SetMouseEnabled(!active
);
3643 bool Interface::InCutSceneMode() const
3645 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE
)!=0;
3648 void Interface::QuitGame(int BackToMain
)
3650 SetCutSceneMode(false);
3653 //clear fade/screenshake effects
3655 timer
->SetFadeFromColor(0);
3658 DelAllWindows(); //delete all windows, including GameControl
3660 //shutting down ingame music
3661 //(do it before deleting the game)
3665 // stop any ambients which are still enqueued
3667 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3668 if (ambim
) ambim
->deactivate();
3670 //delete game, worldmap
3680 strcpy(NextScript
, "Start");
3681 QuitFlag
|= QF_CHANGESCRIPT
;
3686 void Interface::SetupLoadGame(int index
, int ver_override
)
3688 LoadGameIndex
= index
;
3689 VersionOverride
= ver_override
;
3690 QuitFlag
|= QF_LOADGAME
;
3693 void Interface::LoadGame(int index
, int ver_override
)
3695 // This function has rather painful error handling,
3696 // as it should swap all the objects or none at all
3697 // and the loading can fail for various reasons
3699 // Yes, it uses goto. Other ways seemed too awkward for me.
3701 strings
->CloseAux();
3702 tokens
->RemoveAll(NULL
); //clearing the token dictionary
3704 if(calendar
) delete calendar
;
3705 calendar
= new Calendar
;
3707 DataStream
* gam_str
= NULL
;
3708 DataStream
* sav_str
= NULL
;
3709 DataStream
* wmp_str
= NULL
;
3711 SaveGameMgr
* gam_mgr
= NULL
;
3712 WorldMapMgr
* wmp_mgr
= NULL
;
3714 Game
* new_game
= NULL
;
3715 WorldMapArray
* new_worldmap
= NULL
;
3718 if (!KeepCache
) DelTree((const char *) CachePath
, true);
3722 //Load the Default Game
3723 gam_str
= gamedata
->GetResource( GameNameResRef
, IE_GAM_CLASS_ID
);
3725 wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3727 SaveGame
* sg
= sgiterator
->GetSaveGame( index
);
3730 gam_str
= sg
->GetGame();
3731 sav_str
= sg
->GetSave();
3732 wmp_str
= sg
->GetWmap();
3736 if (!gam_str
|| !wmp_str
)
3740 gam_mgr
= ( SaveGameMgr
* ) GetInterface( IE_GAM_CLASS_ID
);
3744 if (!gam_mgr
->Open( gam_str
, true ))
3747 new_game
= gam_mgr
->LoadGame(new Game(), ver_override
);
3755 // Load WMP (WorldMap) file
3756 wmp_mgr
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
3760 if (!wmp_mgr
->Open( wmp_str
, true ))
3763 new_worldmap
= wmp_mgr
->GetWorldMapArray( );
3770 // Unpack SAV (archive) file to Cache dir
3772 ArchiveImporter
* ai
= (ArchiveImporter
*)GetInterface(IE_BIF_CLASS_ID
);
3774 if (ai
->DecompressSaveGame(sav_str
) != GEM_OK
) {
3784 // Let's assume that now is everything loaded OK and swap the objects
3790 worldmap
= new_worldmap
;
3796 // Something went wrong, so try to clean after itself
3799 delete new_worldmap
;
3815 /* swapping out old resources */
3816 void Interface::UpdateMasterScript()
3819 game
->SetScript( GlobalScript
, 0 );
3822 WorldMapMgr
* wmp_mgr
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
3827 DataStream
*wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3829 if (!wmp_mgr
->Open( wmp_str
, true )) {
3835 worldmap
= wmp_mgr
->GetWorldMapArray();
3839 // Something went wrong, so try to clean after itself
3843 GameControl
*Interface::GetGameControl() const
3845 Window
*window
= GetWindow( 0 );
3846 // in the beginning, there's no window at all
3850 Control
* gc
= window
->GetControl(0);
3851 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
) {
3854 return (GameControl
*) gc
;
3857 bool Interface::InitItemTypes()
3862 AutoTable
it("itemtype");
3865 ItemTypes
= it
->GetRowCount(); //number of itemtypes
3869 int InvSlotTypes
= it
->GetColumnCount();
3870 if (InvSlotTypes
> 32) { //bit count limit
3873 //make sure unsigned int is 32 bits
3874 slotmatrix
= (ieDword
*) malloc(ItemTypes
* sizeof(ieDword
) );
3875 for (int i
=0;i
<ItemTypes
;i
++) {
3876 unsigned int value
= 0;
3878 for (int j
=0;j
<InvSlotTypes
;j
++) {
3879 if (strtol(it
->QueryField(i
,j
),NULL
,0) ) {
3884 slotmatrix
[i
] = (ieDword
) value
;
3888 //slottype describes the inventory structure
3889 Inventory::Init(HasFeature(GF_MAGICBIT
));
3890 AutoTable
st("slottype");
3897 SlotTypes
= st
->GetRowCount();
3898 //make sure unsigned int is 32 bits
3899 slottypes
= (SlotType
*) malloc(SlotTypes
* sizeof(SlotType
) );
3900 memset(slottypes
, -1, SlotTypes
* sizeof(SlotType
) );
3901 for (unsigned int row
= 0; row
< SlotTypes
; row
++) {
3903 unsigned int i
= (ieDword
) strtol(st
->GetRowName(row
),NULL
,0 );
3904 if (i
>=SlotTypes
) continue;
3905 if (slottypes
[i
].sloteffects
!=0xffffffffu
) {
3906 slottypes
[row
].slot
= i
;
3910 slottypes
[row
].slot
= i
;
3913 slottypes
[i
].slottype
= (ieDword
) strtol(st
->QueryField(row
,0),NULL
,0 );
3914 slottypes
[i
].slotid
= (ieDword
) strtol(st
->QueryField(row
,1),NULL
,0 );
3915 strnlwrcpy( slottypes
[i
].slotresref
, st
->QueryField(row
,2), 8 );
3916 slottypes
[i
].slottip
= (ieDword
) strtol(st
->QueryField(row
,3),NULL
,0 );
3917 //don't fill sloteffects for aliased slots (pst)
3921 slottypes
[i
].sloteffects
= (ieDword
) strtol(st
->QueryField(row
,4),NULL
,0 );
3922 //setting special slots
3923 if (slottypes
[i
].slottype
&SLOT_ITEM
) {
3924 if (slottypes
[i
].slottype
&SLOT_INVENTORY
) {
3925 Inventory::SetInventorySlot(i
);
3927 Inventory::SetQuickSlot(i
);
3930 switch (slottypes
[i
].sloteffects
) {
3931 //fist slot, not saved, default weapon
3932 case SLOT_EFFECT_FIST
: Inventory::SetFistSlot(i
); break;
3933 //magic weapon slot, overrides all weapons
3934 case SLOT_EFFECT_MAGIC
: Inventory::SetMagicSlot(i
); break;
3935 //weapon slot, Equipping marker is relative to it
3936 case SLOT_EFFECT_MELEE
: Inventory::SetWeaponSlot(i
); break;
3938 case SLOT_EFFECT_MISSILE
: Inventory::SetRangedSlot(i
); break;
3940 case SLOT_EFFECT_LEFT
: Inventory::SetShieldSlot(i
); break;
3941 //head (for averting critical hit)
3942 case SLOT_EFFECT_HEAD
: Inventory::SetHeadSlot(i
); break;
3950 ieDword
Interface::FindSlot(unsigned int idx
) const
3954 for (i
=0;i
<SlotTypes
;i
++) {
3955 if (idx
==slottypes
[i
].slot
) {
3962 ieDword
Interface::QuerySlot(unsigned int idx
) const
3964 if (idx
>=SlotTypes
) {
3967 return slottypes
[idx
].slot
;
3970 ieDword
Interface::QuerySlotType(unsigned int idx
) const
3972 if (idx
>=SlotTypes
) {
3975 return slottypes
[idx
].slottype
;
3978 ieDword
Interface::QuerySlotID(unsigned int idx
) const
3980 if (idx
>=SlotTypes
) {
3983 return slottypes
[idx
].slotid
;
3986 ieDword
Interface::QuerySlottip(unsigned int idx
) const
3988 if (idx
>=SlotTypes
) {
3991 return slottypes
[idx
].slottip
;
3994 ieDword
Interface::QuerySlotEffects(unsigned int idx
) const
3996 if (idx
>=SlotTypes
) {
3999 return slottypes
[idx
].sloteffects
;
4002 const char *Interface::QuerySlotResRef(unsigned int idx
) const
4004 if (idx
>=SlotTypes
) {
4007 return slottypes
[idx
].slotresref
;
4010 // checks the itemtype vs. slottype, and also checks the usability flags
4011 // vs. Actor's stats (alignment, class, race, kit etc.)
4012 int Interface::CanUseItemType(int slottype
, Item
*item
, Actor
*actor
, bool feedback
) const
4014 //inventory is a special case, we allow any items to enter it
4015 if ( slottype
==SLOT_ALL
) {
4016 return SLOT_INVENTORY
;
4018 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
4019 //with twohandedness
4020 if ((slottype
&SLOT_SHIELD
) && (slottype
!=SLOT_ANY
) ) {
4021 //As long as this is an Item, use the ITEM constant
4022 //switch for IE_INV_ITEM_* if it is a CREItem
4023 if (item
->Flags
&IE_ITEM_TWO_HANDED
) {
4024 //cannot equip twohanded in offhand
4025 if (feedback
) DisplayConstantString(STR_NOT_IN_OFFHAND
, 0xf0f0f0);
4030 if ( (unsigned int) item
->ItemType
>=(unsigned int) ItemTypes
) {
4032 if (feedback
) DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4036 //if actor is supplied, check its usability fields
4038 ieStrRef str
= actor
->Unusable(item
);
4040 if (feedback
) DisplayConstantString(str
, 0xf0f0f0);
4045 //if any bit is true, the answer counts as true
4046 int ret
= (slotmatrix
[item
->ItemType
]&slottype
);
4047 if (slottype
== SLOT_INVENTORY
|| slottype
== SLOT_ANY
) {
4051 if (feedback
) DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4055 //this warning comes only when feedback is enabled
4057 if (slotmatrix
[item
->ItemType
]&(SLOT_QUIVER
|SLOT_WEAPON
|SLOT_ITEM
)) {
4059 if (slottype
&SLOT_QUIVER
) {
4060 if (item
->GetWeaponHeader(true)) ret
= 1;
4063 if (slottype
&SLOT_WEAPON
) {
4065 if (item
->GetWeaponHeader(false)) ret
= 1;
4067 if (item
->GetWeaponHeader(true)) ret
= 1;
4070 if (slottype
&SLOT_ITEM
) {
4071 if (item
->GetEquipmentHeaderNumber(0)!=0xffff) ret
= 1;
4075 DisplayConstantString(STR_UNUSABLEITEM
, 0xf0f0f0);
4084 Label
*Interface::GetMessageLabel() const
4086 ieDword WinIndex
= (ieDword
) -1;
4087 ieDword TAIndex
= (ieDword
) -1;
4089 vars
->Lookup( "OtherWindow", WinIndex
);
4090 if (( WinIndex
!= (ieDword
) -1 ) &&
4091 ( vars
->Lookup( "MessageLabel", TAIndex
) )) {
4092 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4094 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4095 if (ctrl
&& ctrl
->ControlType
==IE_GUI_LABEL
)
4096 return (Label
*) ctrl
;
4102 TextArea
*Interface::GetMessageTextArea() const
4104 ieDword WinIndex
= (ieDword
) -1;
4105 ieDword TAIndex
= (ieDword
) -1;
4107 vars
->Lookup( "MessageWindow", WinIndex
);
4108 if (( WinIndex
!= (ieDword
) -1 ) &&
4109 ( vars
->Lookup( "MessageTextArea", TAIndex
) )) {
4110 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4112 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4113 if (ctrl
&& ctrl
->ControlType
==IE_GUI_TEXTAREA
)
4114 return (TextArea
*) ctrl
;
4120 void Interface::DisplayString(const char* Text
, Scriptable
*target
) const
4122 Label
*l
= GetMessageLabel();
4124 l
->SetText(Text
, 0);
4126 TextArea
*ta
= GetMessageTextArea();
4128 ta
->AppendText( Text
, -1 );
4131 char *tmp
= strdup(Text
);
4133 target
->DisplayHeadText(tmp
);
4139 static Color ActorColor
[PALSIZE
];
4140 static const char* DisplayFormatName
= "[color=%lX]%s - [/color][p][color=%lX]%s[/color][/p]";
4141 static const char* DisplayFormatAction
= "[color=%lX]%s - [/color][p][color=%lX]%s %s[/color][/p]";
4142 static const char* DisplayFormat
= "[/color][p][color=%lX]%s[/color][/p]";
4143 static const char* DisplayFormatValue
= "[/color][p][color=%lX]%s: %d[/color][/p]";
4144 static const char* DisplayFormatNameString
= "[color=%lX]%s - [/color][p][color=%lX]%s: %s[/color][/p]";
4146 ieStrRef
Interface::GetStringReference(int stridx
) const
4148 return strref_table
[stridx
];
4152 unsigned int Interface::GetSpeakerColor(const char *&name
, const Scriptable
*&speaker
) const
4154 unsigned int speaker_color
;
4156 if(!speaker
) return 0;
4157 switch (speaker
->Type
) {
4159 name
= ((Actor
*) speaker
)->GetName(-1);
4160 GetPalette( ((Actor
*) speaker
)->GetStat(IE_MAJOR_COLOR
) & 0xFF, PALSIZE
, ActorColor
);
4161 speaker_color
= (ActorColor
[4].r
<<16) | (ActorColor
[4].g
<<8) | ActorColor
[4].b
;
4163 case ST_TRIGGER
: case ST_PROXIMITY
: case ST_TRAVEL
:
4164 name
= GetString( ((InfoPoint
*) speaker
)->DialogName
);
4165 speaker_color
= 0xc0c0c0;
4169 speaker_color
= 0x800000;
4172 return speaker_color
;
4176 //simply displaying a constant string
4177 void Interface::DisplayConstantString(int stridx
, unsigned int color
, Scriptable
*target
) const
4179 if (stridx
<0) return;
4180 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4181 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 12);
4182 char* newstr
= ( char* ) malloc( newlen
);
4183 snprintf( newstr
, newlen
, DisplayFormat
, color
, text
);
4185 DisplayString( newstr
, target
);
4189 void Interface::DisplayString(int stridx
, unsigned int color
, ieDword flags
) const
4191 if (stridx
<0) return;
4192 char* text
= GetString( stridx
, flags
);
4193 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 10);
4194 char* newstr
= ( char* ) malloc( newlen
);
4195 snprintf( newstr
, newlen
, DisplayFormat
, color
, text
);
4197 DisplayString( newstr
);
4203 void Interface::DisplayConstantStringValue(int stridx
, unsigned int color
, ieDword value
) const
4205 if (stridx
<0) return;
4206 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4207 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 28);
4208 char* newstr
= ( char* ) malloc( newlen
);
4209 snprintf( newstr
, newlen
, DisplayFormatValue
, color
, text
, (int) value
);
4211 DisplayString( newstr
);
4216 // <charname> - blah blah : whatever
4217 void Interface::DisplayConstantStringNameString(int stridx
, unsigned int color
, int stridx2
, const Scriptable
*actor
) const
4219 unsigned int actor_color
;
4222 if (stridx
<0) return;
4223 actor_color
= GetSpeakerColor(name
, actor
);
4224 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4225 char* text2
= GetString( strref_table
[stridx2
], IE_STR_SOUND
);
4226 int newlen
= (int)(strlen( DisplayFormat
) + strlen(name
) + strlen( text
) + strlen(text2
) + 18);
4227 char* newstr
= ( char* ) malloc( newlen
);
4228 if (strlen(text2
)) {
4229 snprintf( newstr
, newlen
, DisplayFormatNameString
, actor_color
, name
, color
, text
, text2
);
4231 snprintf( newstr
, newlen
, DisplayFormatName
, color
, name
, color
, text
);
4234 FreeString( text2
);
4235 DisplayString( newstr
);
4240 // <charname> - blah blah
4241 void Interface::DisplayConstantStringName(int stridx
, unsigned int color
, const Scriptable
*speaker
) const
4243 unsigned int speaker_color
;
4246 if (stridx
<0) return;
4247 if(!speaker
) return;
4248 speaker_color
= GetSpeakerColor(name
, speaker
);
4249 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
|IE_STR_SPEECH
);
4250 int newlen
= (int)(strlen( DisplayFormatName
) + strlen( name
) +
4251 + strlen( text
) + 18);
4252 char* newstr
= ( char* ) malloc( newlen
);
4253 snprintf( newstr
, newlen
, DisplayFormatName
, speaker_color
, name
, color
,
4256 DisplayString( newstr
);
4260 void Interface::DisplayConstantStringAction(int stridx
, unsigned int color
, const Scriptable
*attacker
, const Scriptable
*target
) const
4262 unsigned int attacker_color
;
4266 if (stridx
<0) return;
4268 GetSpeakerColor(name2
, target
);
4269 attacker_color
= GetSpeakerColor(name1
, attacker
);
4271 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
|IE_STR_SPEECH
);
4272 int newlen
= (int)(strlen( DisplayFormatAction
) + strlen( name1
) +
4273 + strlen( name2
) + strlen( text
) + 18);
4274 char* newstr
= ( char* ) malloc( newlen
);
4275 snprintf( newstr
, newlen
, DisplayFormatAction
, attacker_color
, name1
, color
,
4278 DisplayString( newstr
);
4282 void Interface::DisplayStringName(int stridx
, unsigned int color
, const Scriptable
*speaker
, ieDword flags
) const
4284 unsigned int speaker_color
;
4287 if (stridx
<0) return;
4288 speaker_color
= GetSpeakerColor(name
, speaker
);
4290 char* text
= GetString( stridx
, flags
);
4291 int newlen
= (int)(strlen( DisplayFormatName
) + strlen( name
) +
4292 + strlen( text
) + 10);
4293 char* newstr
= ( char* ) malloc( newlen
);
4294 snprintf( newstr
, newlen
, DisplayFormatName
, speaker_color
, name
, color
, text
);
4296 DisplayString( newstr
);
4300 static const char *saved_extensions
[]={".are",".sto",0};
4301 static const char *saved_extensions_last
[]={".tot",".toh",0};
4303 //returns the priority of the file to be saved
4307 int Interface::SavedExtension(const char *filename
)
4309 const char *str
=strchr(filename
,'.');
4312 while(saved_extensions
[i
]) {
4313 if (!stricmp(saved_extensions
[i
], str
) ) return 2;
4317 while(saved_extensions_last
[i
]) {
4318 if (!stricmp(saved_extensions_last
[i
], str
) ) return 1;
4324 static const char *protected_extensions
[]={".exe",".dll",".so",0};
4326 //returns true if file should be saved
4327 bool Interface::ProtectedExtension(const char *filename
)
4329 const char *str
=strchr(filename
,'.');
4330 if (!str
) return false;
4332 while(protected_extensions
[i
]) {
4333 if (!stricmp(protected_extensions
[i
], str
) ) return true;
4339 void Interface::RemoveFromCache(const ieResRef resref
, SClass_ID ClassID
)
4341 char filename
[_MAX_PATH
];
4343 snprintf(filename
, _MAX_PATH
, "%s%.8s%s", CachePath
, resref
, TypeExt( ClassID
) );
4347 //this function checks if the path is eligible as a cache
4348 //if it contains a directory, or suspicious file extensions
4349 //we bail out, because the cache will be purged regularly.
4350 bool Interface::StupidityDetector(const char* Pt
)
4352 char Path
[_MAX_PATH
];
4354 DIR* dir
= opendir( Path
);
4356 printf("\n**cannot open**\n");
4357 return true; //no directory?
4359 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
4362 printf("\n**cannot read**\n");
4363 return true; //cannot read it?
4366 char dtmp
[_MAX_PATH
];
4368 snprintf( dtmp
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, de
->d_name
);
4370 if (S_ISDIR( fst
.st_mode
)) {
4371 if (de
->d_name
[0] == '.')
4374 printf("\n**contains another dir**\n");
4375 return true; //a directory in there???
4377 if (ProtectedExtension(de
->d_name
) ) {
4379 printf("\n**contains alien files**\n");
4380 return true; //an executable file in there???
4382 } while (( de
= readdir( dir
) ) != NULL
);
4384 //ok, we got a good conscience
4388 void Interface::DelTree(const char* Pt
, bool onlysave
)
4390 char Path
[_MAX_PATH
];
4392 if (!Pt
[0]) return; //Don't delete the root filesystem :)
4394 DIR* dir
= opendir( Path
);
4398 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
4404 char dtmp
[_MAX_PATH
];
4406 snprintf( dtmp
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, de
->d_name
);
4408 if (S_ISDIR( fst
.st_mode
))
4410 if (de
->d_name
[0] == '.')
4412 if (!onlysave
|| SavedExtension(de
->d_name
) ) {
4415 } while (( de
= readdir( dir
) ) != NULL
);
4419 void Interface::LoadProgress(int percent
)
4421 vars
->SetAt("Progress", percent
);
4422 RedrawControls("Progress", percent
);
4425 video
->SwapBuffers();
4428 void Interface::ReleaseDraggedItem()
4430 DraggedItem
=NULL
; //shouldn't free this
4431 video
->SetDragCursor (NULL
);
4434 void Interface::DragItem(CREItem
*item
, const ieResRef Picture
)
4436 //We should drop the dragged item and pick this up,
4437 //we shouldn't have a valid DraggedItem at this point.
4438 //Anyway, if there is still a dragged item, it will be destroyed.
4440 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW
);
4445 Sprite2D
* DraggedCursor
= NULL
;
4447 DraggedCursor
= gamedata
->GetBAMSprite( Picture
, 0, 0 );
4449 video
->SetDragCursor (DraggedCursor
);
4453 void Interface::SetDraggedPortrait(int dp
, int idx
)
4456 DraggedPortrait
= dp
;
4458 //hmm this might work?
4459 Cursors
[idx
]->acquire();
4460 video
->SetDragCursor(Cursors
[idx
]);
4462 video
->SetDragCursor(NULL
);
4466 bool Interface::ReadItemTable(const ieResRef TableName
, const char * Prefix
)
4471 AutoTable
tab(TableName
);
4475 i
=tab
->GetRowCount();
4478 snprintf(ItemName
,sizeof(ItemName
),"%s%02d",Prefix
, j
+1);
4480 strnlwrcpy(ItemName
,tab
->GetRowName(j
), 8);
4482 //Variable elements are free'd, so we have to use malloc
4483 //well, not anymore, we can use ReleaseFunction
4484 int l
=tab
->GetColumnCount(j
);
4486 int cl
= atoi(tab
->GetColumnName(0));
4487 ItemList
*itemlist
= new ItemList(l
, cl
);
4488 for(int k
=0;k
<l
;k
++) {
4489 strnlwrcpy(itemlist
->ResRefs
[k
],tab
->QueryField(j
,k
), 8);
4491 RtRows
->SetAt(ItemName
, (void*)itemlist
);
4496 bool Interface::ReadRandomItems()
4501 ieDword difflev
=0; //rt norm or rt fury
4502 vars
->Lookup("Nightmare Mode", difflev
);
4504 RtRows
->RemoveAll(ReleaseItemList
);
4507 RtRows
=new Variables(10, 17); //block size, hash table size
4511 RtRows
->SetType( GEM_VARIABLES_POINTER
);
4513 AutoTable
tab("randitem");
4517 if (difflev
>=tab
->GetColumnCount()) {
4518 difflev
= tab
->GetColumnCount()-1;
4522 strnlwrcpy( GoldResRef
, tab
->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4523 if ( GoldResRef
[0]=='*' ) {
4526 strnlwrcpy( RtResRef
, tab
->QueryField( 1, difflev
), 8);
4529 ReadItemTable( RtResRef
, 0 ); //reading the table itself
4536 strnlwrcpy( RtResRef
, tab
->QueryField(2+i
,difflev
), 8);
4537 ReadItemTable( RtResRef
,tab
->GetRowName(2+i
) );
4542 CREItem
*Interface::ReadItem(DataStream
*str
)
4544 CREItem
*itm
= new CREItem();
4546 str
->ReadResRef( itm
->ItemResRef
);
4547 str
->ReadWord( &itm
->Expired
);
4548 str
->ReadWord( &itm
->Usages
[0] );
4549 str
->ReadWord( &itm
->Usages
[1] );
4550 str
->ReadWord( &itm
->Usages
[2] );
4551 str
->ReadDword( &itm
->Flags
);
4552 if (ResolveRandomItem(itm
) ) {
4561 //This function generates random items based on the randitem.2da file
4562 //there could be a loop, but we don't want to freeze, so there is a limit
4563 bool Interface::ResolveRandomItem(CREItem
*itm
)
4565 if (!RtRows
) return true;
4566 for(int loop
=0;loop
<MAX_LOOP
;loop
++) {
4572 if ( !RtRows
->Lookup( itm
->ItemResRef
, lookup
) ) {
4575 ItemList
*itemlist
= (ItemList
*)lookup
;
4576 if (itemlist
->WeightOdds
) {
4577 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4578 i
=Roll(2,(itemlist
->Count
+1)/2,-2);
4580 i
=Roll(1,itemlist
->Count
,-1);
4582 strnlwrcpy( NewItem
, itemlist
->ResRefs
[i
], 8);
4583 char *p
=(char *) strchr(NewItem
,'*');
4585 *p
=0; //doing this so endptr is ok
4586 k
=strtol(p
+1,NULL
,10);
4590 j
=strtol(NewItem
,&endptr
,10);
4595 strnlwrcpy(itm
->ItemResRef
, NewItem
, 8);
4597 strnlwrcpy(itm
->ItemResRef
, GoldResRef
, 8);
4599 if ( !memcmp( itm
->ItemResRef
,"no_drop",8 ) ) {
4600 itm
->ItemResRef
[0]=0;
4602 if (!itm
->ItemResRef
[0]) {
4605 itm
->Usages
[0]=(ieWord
) Roll(j
,k
,0);
4607 printMessage("Interface"," ",LIGHT_RED
);
4608 printf("Loop detected while generating random item:%s\n",itm
->ItemResRef
);
4612 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4613 //these functions are needed because Win32 doesn't allow freeing memory from
4614 //another dll. So we allocate all commonly used memories from core
4615 ITMExtHeader
*Interface::GetITMExt(int count
)
4617 return new ITMExtHeader
[count
];
4620 SPLExtHeader
*Interface::GetSPLExt(int count
)
4622 return new SPLExtHeader
[count
];
4625 Effect
*Interface::GetEffect(ieDword opcode
)
4627 if (opcode
==0xffffffff) {
4630 Effect
*fx
= new Effect();
4634 memset(fx
,0,sizeof(Effect
));
4639 Effect
*Interface::GetFeatures(int count
)
4641 return new Effect
[count
];
4645 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4651 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4658 WorldMapArray
*Interface::NewWorldMapArray(int count
)
4660 return new WorldMapArray(count
);
4663 Container
*Interface::GetCurrentContainer()
4665 return CurrentContainer
;
4668 int Interface::CloseCurrentContainer()
4670 UseContainer
= false;
4671 if ( !CurrentContainer
) {
4674 //remove empty ground piles on closeup
4675 CurrentContainer
->GetCurrentArea()->TMap
->CleanupContainer(CurrentContainer
);
4676 CurrentContainer
= NULL
;
4680 void Interface::SetCurrentContainer(Actor
*actor
, Container
*arg
, bool flag
)
4682 //abort action if the first selected PC isn't the original actor
4683 if (actor
!=GetFirstSelectedPC(false)) {
4684 CurrentContainer
= NULL
;
4687 CurrentContainer
= arg
;
4688 UseContainer
= flag
;
4691 Store
*Interface::GetCurrentStore()
4693 return CurrentStore
;
4696 int Interface::CloseCurrentStore()
4698 if ( !CurrentStore
) {
4701 StoreMgr
* sm
= ( StoreMgr
* ) GetInterface( IE_STO_CLASS_ID
);
4705 int size
= sm
->GetStoredFileSize (CurrentStore
);
4707 //created streams are always autofree (close file on destruct)
4708 //this one will be destructed when we return from here
4711 str
.Create( CurrentStore
->Name
, IE_STO_CLASS_ID
);
4712 int ret
= sm
->PutStore (&str
, CurrentStore
);
4714 printMessage("Core"," ", YELLOW
);
4715 printf("Store removed: %s\n", CurrentStore
->Name
);
4716 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4719 printMessage("Core"," ", YELLOW
);
4720 printf("Store removed: %s\n", CurrentStore
->Name
);
4721 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4723 //make sure the stream isn't connected to sm, or it will be double freed
4725 delete CurrentStore
;
4726 CurrentStore
= NULL
;
4730 Store
*Interface::SetCurrentStore(const ieResRef resname
, const ieVariable owner
)
4732 if ( CurrentStore
) {
4733 if ( !strnicmp(CurrentStore
->Name
, resname
, 8) ) {
4734 return CurrentStore
;
4737 //not simply delete the old store, but save it
4738 CloseCurrentStore();
4741 DataStream
* str
= gamedata
->GetResource( resname
, IE_STO_CLASS_ID
);
4742 StoreMgr
* sm
= ( StoreMgr
* ) GetInterface( IE_STO_CLASS_ID
);
4747 if (!sm
->Open( str
, true )) {
4752 // FIXME - should use some already allocated in core
4753 // not really, only one store is open at a time, then it is
4754 // unloaded, we don't really have to cache it, it will be saved in
4756 CurrentStore
= sm
->GetStore( new Store() );
4757 if (CurrentStore
== NULL
) {
4762 strnlwrcpy(CurrentStore
->Name
, resname
, 8);
4764 CurrentStore
->SetOwner(owner
);
4766 return CurrentStore
;
4769 void Interface::SetMouseScrollSpeed(int speed
) {
4770 mousescrollspd
= (speed
+1)*2;
4773 int Interface::GetMouseScrollSpeed() {
4774 return mousescrollspd
;
4777 ieStrRef
Interface::GetRumour(const ieResRef dlgref
)
4779 DialogMgr
* dm
= ( DialogMgr
* ) GetInterface( IE_DLG_CLASS_ID
);
4780 dm
->Open( gamedata
->GetResource( dlgref
, IE_DLG_CLASS_ID
), true );
4781 Dialog
*dlg
= dm
->GetDialog();
4785 printMessage("Interface"," ", LIGHT_RED
);
4786 printf( "Cannot load dialog: %s\n", dlgref
);
4787 return (ieStrRef
) -1;
4789 Scriptable
*pc
=game
->GetPC( game
->GetSelectedPCSingle(), false );
4791 ieStrRef ret
= (ieStrRef
) -1;
4792 int i
= dlg
->FindRandomState( pc
);
4794 ret
= dlg
->GetState( i
)->StrRef
;
4800 void Interface::DoTheStoreHack(Store
*s
)
4802 size_t size
= s
->PurchasedCategoriesCount
* sizeof( ieDword
);
4803 s
->purchased_categories
=(ieDword
*) malloc(size
);
4805 size
= s
->CuresCount
* sizeof( STOCure
);
4806 s
->cures
=(STOCure
*) malloc(size
);
4808 size
= s
->DrinksCount
* sizeof( STODrink
);
4809 s
->drinks
=(STODrink
*) malloc(size
);
4811 for(size
=0;size
<s
->ItemsCount
;size
++)
4812 s
->items
.push_back( new STOItem() );
4815 //plays stock sound listed in defsound.2da
4816 void Interface::PlaySound(int index
)
4818 if (index
<=DSCount
) {
4819 AudioDriver
->Play(DefSound
[index
]);
4823 Actor
*Interface::GetFirstSelectedPC(bool forced
)
4825 int partySize
= game
->GetPartySize( false );
4826 if (!partySize
) return NULL
;
4827 for (int i
= 0; i
< partySize
; i
++) {
4828 Actor
* actor
= game
->GetPC( i
,false );
4829 if (actor
->IsSelected()) {
4835 return game
->GetPC(0,false);
4840 //this is used only for the console
4841 Sprite2D
*Interface::GetCursorSprite()
4843 Sprite2D
*spr
= gamedata
->GetBAMSprite(CursorBam
, 0, 0);
4846 if(HasFeature(GF_OVERRIDE_CURSORPOS
))
4849 spr
->YPos
=spr
->Height
-1;
4855 Sprite2D
*Interface::GetScrollCursorSprite(int frameNum
, int spriteNum
)
4857 return gamedata
->GetBAMSprite(ScrollCursorBam
, frameNum
, spriteNum
);
4860 /* we should return -1 if it isn't gold, otherwise return the gold value */
4861 int Interface::CanMoveItem(const CREItem
*item
) const
4863 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4864 if (item
->Flags
& IE_INV_ITEM_UNDROPPABLE
)
4866 //not gold, we allow only one single coin ResRef, this is good
4867 //for all of the original games
4868 if (strnicmp(item
->ItemResRef
, GoldResRef
, 8 ) )
4870 //gold, returns the gold value (stack size)
4871 return item
->Usages
[0];
4874 // dealing with applying effects
4875 void Interface::ApplySpell(const ieResRef resname
, Actor
*actor
, Scriptable
*caster
, int level
)
4877 Spell
*spell
= gamedata
->GetSpell(resname
);
4882 level
= spell
->GetHeaderIndexFromLevel(level
);
4883 EffectQueue
*fxqueue
= spell
->GetEffectBlock(caster
, actor
->Pos
, level
);
4885 //check effect immunities
4886 int res
= fxqueue
->CheckImmunity ( actor
);
4889 //bounced back at a nonliving caster
4890 if (caster
->Type
!=ST_ACTOR
) {
4894 actor
= (Actor
*) caster
;
4896 fxqueue
->SetOwner( caster
);
4897 fxqueue
->AddAllEffects(actor
, actor
->Pos
);
4902 void Interface::ApplySpellPoint(const ieResRef resname
, Map
* area
, Point
&pos
, Scriptable
*caster
, int level
)
4904 Spell
*spell
= gamedata
->GetSpell(resname
);
4908 level
= spell
->GetHeaderIndexFromLevel(level
);
4909 Projectile
*pro
= spell
->GetProjectile(caster
, level
, pos
);
4910 pro
->SetCaster(caster
->GetGlobalID());
4911 area
->AddProjectile(pro
, caster
->Pos
, pos
);
4914 //-1 means the effect was reflected back to the caster
4915 //0 means the effect was resisted and should be removed
4916 //1 means the effect was applied
4917 int Interface::ApplyEffect(Effect
*effect
, Actor
*actor
, Scriptable
*caster
)
4923 EffectQueue
*fxqueue
= new EffectQueue();
4924 //AddEffect now copies the fx data, please delete your effect reference
4925 //if you created it. (Don't delete cached references)
4926 fxqueue
->AddEffect( effect
);
4928 int res
= fxqueue
->CheckImmunity ( actor
);
4931 //bounced back at a nonliving caster
4932 if (caster
->Type
!=ST_ACTOR
) {
4936 actor
= (Actor
*) caster
;
4938 fxqueue
->SetOwner( caster
);
4941 p
.empty(); //the effect should have all its coordinates already set
4942 if (fxqueue
->AddAllEffects( actor
, p
)==FX_NOT_APPLIED
) {
4950 Effect
*Interface::GetEffect(const ieResRef resname
, int level
, Point
&p
)
4952 //Don't free this reference, it is cached!
4953 Effect
*effect
= gamedata
->GetEffect(resname
);
4960 effect
->Power
= level
;
4966 // dealing with saved games
4967 int Interface::SwapoutArea(Map
*map
)
4969 MapMgr
* mm
= ( MapMgr
* ) GetInterface( IE_ARE_CLASS_ID
);
4973 int size
= mm
->GetStoredFileSize (map
);
4975 //created streams are always autofree (close file on destruct)
4976 //this one will be destructed when we return from here
4979 str
.Create( map
->GetScriptName(), IE_ARE_CLASS_ID
);
4980 int ret
= mm
->PutArea (&str
, map
);
4982 printMessage("Core"," ", YELLOW
);
4983 printf("Area removed: %s\n", map
->GetScriptName());
4984 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4987 printMessage("Core"," ", YELLOW
);
4988 printf("Area removed: %s\n", map
->GetScriptName());
4989 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4991 //make sure the stream isn't connected to sm, or it will be double freed
4996 int Interface::WriteCharacter(const char *name
, Actor
*actor
)
4998 char Path
[_MAX_PATH
];
5000 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
5004 ActorMgr
* gm
= ( ActorMgr
* ) GetInterface( IE_CRE_CLASS_ID
);
5010 str
.Create( Path
, name
, IE_CHR_CLASS_ID
);
5012 //this is not needed, because the chr header writer automatically
5014 //int size = gm->GetStoredFileSize (actor);
5015 int ret
= gm
->PutActor(&str
, actor
, true);
5017 printMessage("Core"," ", YELLOW
);
5018 printf("Character cannot be saved: %s\n", name
);
5024 int Interface::WriteGame(const char *folder
)
5026 SaveGameMgr
* gm
= ( SaveGameMgr
* ) GetInterface( IE_GAM_CLASS_ID
);
5031 int size
= gm
->GetStoredFileSize (game
);
5033 //created streams are always autofree (close file on destruct)
5034 //this one will be destructed when we return from here
5037 str
.Create( folder
, GameNameResRef
, IE_GAM_CLASS_ID
);
5038 int ret
= gm
->PutGame (&str
, game
);
5040 printMessage("Core"," ", YELLOW
);
5041 printf("Game cannot be saved: %s\n", GameNameResRef
);
5044 printMessage("Core"," ", YELLOW
);
5045 printf("Internal error, game cannot be saved: %s\n", GameNameResRef
);
5047 //make sure the stream isn't connected to sm, or it will be double freed
5052 int Interface::WriteWorldMap(const char *folder
)
5054 WorldMapMgr
* wmm
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
5059 int size
= wmm
->GetStoredFileSize (worldmap
);
5061 //created streams are always autofree (close file on destruct)
5062 //this one will be destructed when we return from here
5065 str
.Create( folder
, WorldMapName
, IE_WMP_CLASS_ID
);
5066 int ret
= wmm
->PutWorldMap (&str
, worldmap
);
5068 printMessage("Core"," ", YELLOW
);
5069 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
5072 printMessage("Core"," ", YELLOW
);
5073 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
5075 //make sure the stream isn't connected to sm, or it will be double freed
5080 int Interface::CompressSave(const char *folder
)
5084 str
.Create( folder
, GameNameResRef
, IE_SAV_CLASS_ID
);
5085 DIR* dir
= opendir( CachePath
);
5089 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
5094 //BIF and SAV are the same
5095 ArchiveImporter
* ai
= (ArchiveImporter
*)GetInterface(IE_BIF_CLASS_ID
);
5096 ai
->CreateArchive( &str
);
5098 //.tot and .toh should be saved last, because they are updated when an .are is saved
5102 char dtmp
[_MAX_PATH
];
5104 snprintf( dtmp
, _MAX_PATH
, "%s%s", CachePath
, de
->d_name
);
5106 if (S_ISDIR( fst
.st_mode
))
5108 if (de
->d_name
[0] == '.')
5110 if (SavedExtension(de
->d_name
)==priority
) {
5112 fs
.Open(dtmp
, true);
5113 ai
->AddToSaveGame(&str
, &fs
);
5115 } while (( de
= readdir( dir
) ) != NULL
);
5117 //reopen list for the second round
5120 dir
= opendir( CachePath
);
5121 de
= readdir( dir
);
5128 int Interface::GetMaximumAbility() const { return MaximumAbility
; }
5130 int Interface::GetStrengthBonus(int column
, int value
, int ex
) const
5132 //to hit, damage, open doors, weight allowance
5133 if (column
<0 || column
>3)
5146 return strmod
[column
*(MaximumAbility
+1)+value
]+strmodex
[column
*101+ex
];
5149 //only the first 3 columns are supported
5150 int Interface::GetIntelligenceBonus(int column
, int value
) const
5152 //learn spell, max spell level, max spell number on level
5153 if (column
<0 || column
>2)
5156 return intmod
[column
*(MaximumAbility
+1)+value
];
5159 int Interface::GetDexterityBonus(int column
, int value
) const
5161 //reaction, missile, ac
5162 if (column
<0 || column
>2)
5165 //no dexmod in iwd2???
5166 if (HasFeature(GF_3ED_RULES
)) return 0;
5168 return dexmod
[column
*(MaximumAbility
+1)+value
];
5171 int Interface::GetConstitutionBonus(int column
, int value
) const
5173 //normal, warrior, minimum, regen hp, regen fatigue
5174 if (column
<0 || column
>4)
5177 return conmod
[column
*(MaximumAbility
+1)+value
];
5180 int Interface::GetCharismaBonus(int column
, int value
) const
5183 if (column
<0 || column
>0)
5186 return chrmod
[column
*(MaximumAbility
+1)+value
];
5189 int Interface::GetLoreBonus(int column
, int value
) const
5191 if (column
<0 || column
>0)
5194 //no lorebon in iwd2???
5195 if (HasFeature(GF_3ED_RULES
)) return 0;
5197 return lorebon
[value
];
5200 // -3, -2 if request is illegal or in cutscene
5201 // -1 if pause is already active
5202 // 0 if pause was not allowed
5203 // 1 if autopause happened
5204 int Interface::Autopause(ieDword flag
)
5206 GameControl
*gc
= GetGameControl();
5210 if (InCutSceneMode()) {
5213 if (gc
->GetDialogueFlags()&DF_FREEZE_SCRIPTS
) {
5216 ieDword autopause_flags
= 0;
5218 vars
->Lookup("Auto Pause State", autopause_flags
);
5219 if (autopause_flags
& (1<<flag
)) {
5220 DisplayConstantString(STR_AP_UNUSABLE
+flag
, 0xff0000);
5221 gc
->SetDialogueFlags(DF_FREEZE_SCRIPTS
, BM_OR
);
5227 void Interface::RegisterOpcodes(int count
, const EffectRef
*opcodes
)
5229 EffectQueue_RegisterOpcodes(count
, opcodes
);
5232 void Interface::SetInfoTextColor(Color
&color
)
5234 if (InfoTextPalette
) {
5235 gamedata
->FreePalette(InfoTextPalette
);
5237 InfoTextPalette
= CreatePalette(color
, black
);
5241 void Interface::GetResRefFrom2DA(const ieResRef resref
, ieResRef resource1
, ieResRef resource2
, ieResRef resource3
)
5253 AutoTable
tab(resref
);
5255 unsigned int cols
= tab
->GetColumnCount();
5256 unsigned int row
= (unsigned int) Roll(1,tab
->GetRowCount(),-1);
5257 strnuprcpy(resource1
, tab
->QueryField(row
,0), 8);
5258 if (resource2
&& cols
>1)
5259 strnuprcpy(resource2
, tab
->QueryField(row
,1), 8);
5260 if (resource3
&& cols
>2)
5261 strnuprcpy(resource3
, tab
->QueryField(row
,2), 8);
5265 ieDword
*Interface::GetListFrom2DA(const ieResRef resref
)
5269 AutoTable
tab(resref
);
5271 ieDword cnt
= tab
->GetRowCount();
5272 ret
= (ieDword
*) malloc((1+cnt
)*sizeof(ieDword
));
5275 ret
[cnt
]=strtol(tab
->QueryField(cnt
-1, 0),NULL
, 0);
5280 ret
= (ieDword
*) malloc(sizeof(ieDword
));
5285 //returns a numeric value associated with a stat name (symbol) from stats.ids
5286 ieDword
Interface::TranslateStat(const char *stat_name
)
5290 if (valid_number(stat_name
, tmp
)) {
5291 return (ieDword
) tmp
;
5294 int symbol
= LoadSymbol( "stats" );
5295 SymbolMgr
*sym
= GetSymbol( symbol
);
5296 ieDword stat
= (ieDword
) sym
->GetValue( stat_name
);
5297 if (stat
==(ieDword
) ~0) {
5298 printMessage("Core"," ",YELLOW
);
5299 printf("Cannot translate symbol: %s\n", stat_name
);
5304 void Interface::WaitForDisc(int disc_number
, const char* path
)
5306 GetDictionary()->SetAt( "WaitForDisc", (ieDword
) disc_number
);
5308 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5310 core
->DrawWindows();
5311 if (dir_exists (path
)) {
5312 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5316 } while (video
->SwapBuffers() == GEM_OK
);
5319 // remove the extraneus EOL newline and carriage return
5320 void Interface::StripLine(char * string
, size_t size
) {
5321 if (size
>= 2 && string
[size
-2] == '\n') {
5322 string
[size
-2] = '\0';
5324 if (size
>= 3 && string
[size
-3] == '\r') {
5325 string
[size
-3] = '\0'; // remove the carriage return too
5329 void Interface::SetNextScript(const char *script
)
5331 strncpy( NextScript
, script
, sizeof(NextScript
) );
5332 QuitFlag
|= QF_CHANGESCRIPT
;