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"
81 GEM_EXPORT Interface
* core
;
82 GEM_EXPORT GameData
* gamedata
;
85 GEM_EXPORT HANDLE hConsole
;
88 //use DialogF.tlk if the protagonist is female, that's why we leave space
89 static const char dialogtlk
[] = "dialog.tlk\0";
91 static int strref_table
[STRREF_COUNT
];
93 static int MaximumAbility
= 25;
94 static ieWordSigned
*strmod
= NULL
;
95 static ieWordSigned
*strmodex
= NULL
;
96 static ieWordSigned
*intmod
= NULL
;
97 static ieWordSigned
*dexmod
= NULL
;
98 static ieWordSigned
*conmod
= NULL
;
99 static ieWordSigned
*chrmod
= NULL
;
100 static ieWordSigned
*lorebon
= NULL
;
101 static ieVariable IWD2DeathVarFormat
= "_DEAD%s";
102 static ieVariable DeathVarFormat
= "SPRITE_IS_DEAD%s";
104 Interface::Interface(int iargc
, char* iargv
[])
109 hConsole
= GetStdHandle( STD_OUTPUT_HANDLE
);
111 textcolor( LIGHT_WHITE
);
112 printf( "GemRB Core Version v%s Loading...\n", VERSION_GEMRB
);
114 // default to the correct endianswitch
115 ieWord endiantest
= 1;
116 if (((char *)&endiantest
)[1] == 1) {
118 DataStream::SetEndianSwitch(true);
123 pl_uppercase
[i
]=(ieByte
) toupper(i
);
124 pl_lowercase
[i
]=(ieByte
) tolower(i
);
145 CurrentContainer
= NULL
;
146 UseContainer
= false;
147 InfoTextPalette
= NULL
;
157 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();
246 ::gamedata
= gamedata
;
249 #define FreeInterfaceVector(type, variable, member) \
251 std::vector<type>::iterator i; \
252 for(i = (variable).begin(); i != (variable).end(); ++i) { \
254 FreeInterface((*i).member); \
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
;
329 // stop any ambients which are still enqueued
331 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
332 if (ambim
) ambim
->deactivate();
334 //destroy the highest objects in the hierarchy first!
340 for (size_t i
= 0; i
< cleanupFunctions
.size(); i
++)
341 cleanupFunctions
[i
]();
343 ReleaseMemoryActor();
344 EffectQueue_ReleaseMemory();
345 CharAnimations::ReleaseMemory();
348 FreeResRefTable(DefSound
, DSCount
);
353 FreeInterface( music
);
354 FreeInterface( AudioDriver
);
359 for (int i
= 0; i
< CursorCount
; i
++) {
360 video
->FreeSprite( Cursors
[i
] );
365 FreeResourceVector( Font
, fonts
);
366 FreeResourceVector( Window
, windows
);
369 for (i
= 0; i
< musiclist
.size(); i
++) {
370 free((void *)musiclist
[i
]);
373 DamageInfoMap
.clear();
387 FreeInterface( windowmgr
);
391 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
392 video
->FreeSprite(FogSprites
[i
]);
396 video
->FreeSprite(WindowFrames
[i
]);
399 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
401 video
->FreeSprite(GroundCircles
[size
][i
]);
407 //freesprite checks for null pointer
408 video
->FreeSprite(TooltipBack
[i
]);
410 delete[] TooltipBack
;
412 if (InfoTextPalette
) {
413 gamedata
->FreePalette(InfoTextPalette
);
416 video
->SetDragCursor(NULL
);
421 FreeInterface( guiscript
);
426 RtRows
->RemoveAll(ReleaseItemList
);
430 ItemExclTable
->RemoveAll(NULL
);
431 delete ItemExclTable
;
434 ItemDialTable
->RemoveAll(NULL
);
435 delete ItemDialTable
;
437 if (ItemDial2Table
) {
438 ItemDial2Table
->RemoveAll(NULL
);
439 delete ItemDial2Table
;
441 if (ItemTooltipTable
) {
442 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
443 delete ItemTooltipTable
;
446 FreeInterfaceVector( Symbol
, symbols
, sm
);
448 FreeInterface(INIquests
);
449 FreeInterface(INIbeasts
);
450 FreeInterface(INIparty
);
451 FreeInterface(INIresdata
);
453 Map::ReleaseMemory();
454 GameScript::ReleaseMemory();
455 Actor::ReleaseMemory();
457 gamedata
->ClearCaches();
460 FreeInterface( video
);
462 FreeInterface( strings
);
466 // Removing all stuff from Cache, except bifs
467 if (!KeepCache
) DelTree((const char *) CachePath
, true);
470 void Interface::SetWindowFrame(int i
, Sprite2D
*Picture
)
472 video
->FreeSprite(WindowFrames
[i
]);
473 WindowFrames
[i
]=Picture
;
476 GameControl
* Interface::StartGameControl()
478 //making sure that our window is the first one
482 DelAllWindows();//deleting ALL windows
483 gamedata
->DelTable(0xffffu
); //dropping ALL tables
484 Window
* gamewin
= new Window( 0xffff, 0, 0, (ieWord
) Width
, (ieWord
) Height
);
485 gamewin
->WindowPack
[0]=0;
486 GameControl
* gc
= new GameControl();
489 gc
->Width
= (ieWord
) Width
;
490 gc
->Height
= (ieWord
) Height
;
492 gc
->ControlID
= 0x00000000;
493 gc
->ControlType
= IE_GUI_GAMECONTROL
;
494 gamewin
->AddControl( gc
);
495 AddWindow( gamewin
);
496 SetVisible( 0, WINDOW_VISIBLE
);
497 //setting the focus to the game control
498 evntmgr
->SetFocused(gamewin
, gc
);
499 if (guiscript
->LoadScript( "MessageWindow" )) {
500 guiscript
->RunFunction( "OnLoad" );
507 /* handle main loop events that might destroy or create windows
508 thus cannot be called from DrawWindows directly
509 these events are pending until conditions are right
511 void Interface::HandleEvents()
513 GameControl
*gc
= GetGameControl();
514 if (gc
&& (!gc
->Owner
|| !gc
->Owner
->Visible
)) {
519 if (EventFlag
&EF_SELECTION
) {
520 EventFlag
&=~EF_SELECTION
;
521 guiscript
->RunFunction( "SelectionChanged", false);
524 if (EventFlag
&EF_UPDATEANIM
) {
525 EventFlag
&=~EF_UPDATEANIM
;
526 guiscript
->RunFunction( "UpdateAnimation", false);
529 if (EventFlag
&EF_PORTRAIT
) {
530 ieDword tmp
= (ieDword
) ~0;
531 vars
->Lookup( "PortraitWindow", tmp
);
532 if (tmp
!= (ieDword
) ~0) {
533 EventFlag
&=~EF_PORTRAIT
;
534 guiscript
->RunFunction( "UpdatePortraitWindow" );
538 if (EventFlag
&EF_ACTION
) {
539 ieDword tmp
= (ieDword
) ~0;
540 vars
->Lookup( "ActionsWindow", tmp
);
541 if (tmp
!= (ieDword
) ~0) {
542 EventFlag
&=~EF_ACTION
;
543 guiscript
->RunFunction( "UpdateActionsWindow" );
547 if ((EventFlag
&EF_CONTROL
) && gc
) {
548 EventFlag
&=~EF_CONTROL
;
549 guiscript
->RunFunction( "UpdateControlStatus" );
550 //this is the only value we can use here
551 if (game
->ControlStatus
& CS_HIDEGUI
)
557 if ((EventFlag
&EF_SHOWMAP
) && gc
) {
558 ieDword tmp
= (ieDword
) ~0;
559 vars
->Lookup( "OtherWindow", tmp
);
560 if (tmp
== (ieDword
) ~0) {
561 EventFlag
&= ~EF_SHOWMAP
;
562 guiscript
->RunFunction( "ShowMap" );
567 if (EventFlag
&EF_SEQUENCER
) {
568 EventFlag
&=~EF_SEQUENCER
;
569 guiscript
->RunFunction( "OpenSequencerWindow" );
573 if (EventFlag
&EF_IDENTIFY
) {
574 EventFlag
&=~EF_IDENTIFY
;
575 guiscript
->RunFunction( "OpenIdentifyWindow" );
578 if (EventFlag
&EF_OPENSTORE
) {
579 EventFlag
&=~EF_OPENSTORE
;
580 guiscript
->RunFunction( "OpenStoreWindow" );
584 if (EventFlag
&EF_MASTERSCRIPT
) {
585 EventFlag
&=~EF_MASTERSCRIPT
;
586 guiscript
->RunFunction( "UpdateMasterScript" );
592 /* handle main loop events that might destroy or create windows
593 thus cannot be called from DrawWindows directly
595 void Interface::HandleFlags()
597 EventFlag
= EF_CONTROL
; //clear events because the context changed
599 if (QuitFlag
&(QF_QUITGAME
|QF_EXITGAME
) ) {
600 // when reaching this, quitflag should be 1 or 2
601 // if Exitgame was set, we'll set Start.py too
602 QuitGame (QuitFlag
&QF_EXITGAME
);
603 QuitFlag
&= ~(QF_QUITGAME
|QF_EXITGAME
);
606 if (QuitFlag
&QF_LOADGAME
) {
607 QuitFlag
&= ~QF_LOADGAME
;
608 LoadGame(LoadGameIndex
, VersionOverride
);
611 if (QuitFlag
&QF_ENTERGAME
) {
612 QuitFlag
&= ~QF_ENTERGAME
;
616 //rearrange party slots
617 game
->ConsolidateParty();
618 GameControl
* gc
= StartGameControl();
619 //switch map to protagonist
620 Actor
* actor
= game
->FindPC (1);
622 actor
= game
->GetPC (0, false);
625 gc
->ChangeMap(actor
, true);
628 printMessage("Core", "No game to enter...\n", LIGHT_RED
);
629 QuitFlag
= QF_QUITGAME
;
633 if (QuitFlag
&QF_CHANGESCRIPT
) {
634 QuitFlag
&= ~QF_CHANGESCRIPT
;
635 guiscript
->LoadScript( NextScript
);
636 guiscript
->RunFunction( "OnLoad" );
640 bool GenerateAbilityTables()
644 //range is: 0 - maximumability
645 int tablesize
= MaximumAbility
+1;
646 strmod
= (ieWordSigned
*) malloc (tablesize
* 4 * sizeof(ieWordSigned
) );
649 strmodex
= (ieWordSigned
*) malloc (101 * 4 * sizeof(ieWordSigned
) );
652 intmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
655 dexmod
= (ieWordSigned
*) malloc (tablesize
* 3 * sizeof(ieWordSigned
) );
658 conmod
= (ieWordSigned
*) malloc (tablesize
* 5 * sizeof(ieWordSigned
) );
661 chrmod
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
664 lorebon
= (ieWordSigned
*) malloc (tablesize
* 1 * sizeof(ieWordSigned
) );
670 bool Interface::ReadAbilityTable(const ieResRef tablename
, ieWordSigned
*mem
, int columns
, int rows
)
672 AutoTable
tab(tablename
);
676 //this is a hack for rows not starting at 0 in some cases
678 const char * tmp
= tab
->GetRowName(0);
679 if (tmp
&& (tmp
[0]!='0')) {
681 for (int i
=0;i
<fix
;i
++) {
682 for (int j
=0;j
<columns
;j
++) {
683 mem
[rows
*j
+i
]=(ieWordSigned
) strtol(tab
->QueryField(0,j
),NULL
,0 );
687 for (int j
=0;j
<columns
;j
++) {
688 for( int i
=0;i
<rows
-fix
;i
++) {
689 mem
[rows
*j
+i
+fix
] = (ieWordSigned
) strtol(tab
->QueryField(i
,j
),NULL
,0 );
695 bool Interface::ReadAbilityTables()
697 bool ret
= GenerateAbilityTables();
700 ret
= ReadAbilityTable("strmod", strmod
, 4, MaximumAbility
+ 1);
703 ret
= ReadAbilityTable("strmodex", strmodex
, 4, 101);
704 //3rd ed doesn't have strmodex, but has a maximum of 40
705 if (!ret
&& (MaximumAbility
<=25) )
707 ret
= ReadAbilityTable("intmod", intmod
, 3, MaximumAbility
+ 1);
710 ret
= ReadAbilityTable("hpconbon", conmod
, 5, MaximumAbility
+ 1);
713 if (!HasFeature(GF_3ED_RULES
)) {
714 //no lorebon in iwd2???
715 ret
= ReadAbilityTable("lorebon", lorebon
, 1, MaximumAbility
+ 1);
718 //no dexmod in iwd2???
719 ret
= ReadAbilityTable("dexmod", dexmod
, 3, MaximumAbility
+ 1);
723 //this table is a single row (not a single column)
724 ret
= ReadAbilityTable("chrmodst", chrmod
, MaximumAbility
+ 1, 1);
730 bool Interface::ReadAuxItemTables()
737 ItemExclTable
->RemoveAll(NULL
);
739 ItemExclTable
= new Variables();
740 ItemExclTable
->SetType(GEM_VARIABLES_INT
);
742 table
= gamedata
->LoadTable( "itemexcl" );
746 //don't report error when the file doesn't exist
747 if (aa
.load("itemexcl")) {
748 idx
= aa
->GetRowCount();
752 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
753 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
754 ItemExclTable
->SetAt(key
, value
);
758 ItemDialTable
->RemoveAll(NULL
);
760 ItemDialTable
= new Variables();
761 ItemDialTable
->SetType(GEM_VARIABLES_INT
);
763 if (ItemDial2Table
) {
764 ItemDial2Table
->RemoveAll(NULL
);
766 ItemDial2Table
= new Variables();
767 ItemDial2Table
->SetType(GEM_VARIABLES_STRING
);
770 //don't report error when the file doesn't exist
771 if (aa
.load("itemdial")) {
772 idx
= aa
->GetRowCount();
774 ieResRef key
, dlgres
;
776 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
777 ieDword value
= strtol(aa
->QueryField(idx
,0),NULL
,0);
778 ItemDialTable
->SetAt(key
, value
);
779 strnlwrcpy(dlgres
,aa
->QueryField(idx
,1),8);
780 ItemDial2Table
->SetAtCopy(key
, dlgres
);
784 if (ItemTooltipTable
) {
785 ItemTooltipTable
->RemoveAll(ReleaseItemTooltip
);
787 ItemTooltipTable
= new Variables();
788 ItemTooltipTable
->SetType(GEM_VARIABLES_POINTER
);
791 //don't report error when the file doesn't exist
792 if (aa
.load("tooltip")) {
793 idx
= aa
->GetRowCount();
796 int *tmppoi
= (int *) malloc(sizeof(int)*3);
798 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
799 for (int i
=0;i
<3;i
++) {
800 tmppoi
[i
] = atoi(aa
->QueryField(idx
,i
));
802 ItemTooltipTable
->SetAt(key
, (void*)tmppoi
);
809 const char *Interface::GetDeathVarFormat()
811 return DeathVarFormat
;
814 int Interface::GetItemExcl(const ieResRef itemname
) const
818 if (ItemExclTable
&& ItemExclTable
->Lookup(itemname
, value
)) {
824 int Interface::GetItemTooltip(const ieResRef itemname
, int header
, int identified
)
828 if (ItemTooltipTable
) {
830 ItemTooltipTable
->Lookup(itemname
, lookup
);
831 value
= (int*)lookup
;
833 if (value
&& (value
[header
]>=0)) {
834 return value
[header
];
836 Item
*item
= gamedata
->GetItem(itemname
);
840 int ret
= identified
?item
->ItemNameIdentified
:item
->ItemName
;
841 gamedata
->FreeItem(item
, itemname
, 0);
845 int Interface::GetItemDialStr(const ieResRef itemname
) const
849 if (ItemDialTable
&& ItemDialTable
->Lookup(itemname
, value
)) {
855 //second value is the item dialog resource returned by this method
856 int Interface::GetItemDialRes(const ieResRef itemname
, ieResRef retval
) const
858 if (ItemDial2Table
&& ItemDial2Table
->Lookup(itemname
, retval
, sizeof(ieResRef
))) {
864 bool Interface::ReadAreaAliasTable(const ieResRef tablename
)
866 if (AreaAliasTable
) {
867 AreaAliasTable
->RemoveAll(NULL
);
869 AreaAliasTable
= new Variables();
870 AreaAliasTable
->SetType(GEM_VARIABLES_INT
);
873 AutoTable
aa(tablename
);
875 //don't report error when the file doesn't exist
879 int idx
= aa
->GetRowCount();
883 strnlwrcpy(key
,aa
->GetRowName(idx
),8);
884 ieDword value
= atoi(aa
->QueryField(idx
,0));
885 AreaAliasTable
->SetAt(key
, value
);
891 int Interface::GetAreaAlias(const ieResRef areaname
) const
895 if (AreaAliasTable
&& AreaAliasTable
->Lookup(areaname
, value
)) {
901 bool Interface::ReadMusicTable(const ieResRef tablename
, int col
) {
902 AutoTable
tm(tablename
);
906 for (unsigned int i
= 0; i
< tm
->GetRowCount(); i
++) {
907 musiclist
.push_back(strdup(tm
->QueryField(i
, col
)));
913 bool Interface::ReadDamageTypeTable() {
914 AutoTable
tm("dmgtypes");
919 for (ieDword i
= 0; i
< tm
->GetRowCount(); i
++) {
920 di
.strref
= core
->GetStringReference(atoi(tm
->QueryField(i
, 0)));
921 di
.resist_stat
= TranslateStat(tm
->QueryField(i
, 1));
922 di
.value
= strtol(tm
->QueryField(i
, 2), (char **) NULL
, 16);
923 DamageInfoMap
.insert(std::make_pair
<ieDword
, DamageInfoStruct
> ((ieDword
)di
.value
, di
));
929 //Not a constant anymore, we let the caller set the entry to zero
930 char *Interface::GetMusicPlaylist(int SongType
) const {
931 if (SongType
< 0 || (unsigned int)SongType
>= musiclist
.size())
934 return musiclist
[SongType
];
937 static const Color white
= {0xff,0xff,0xff,0xff};
938 static const Color black
= {0x00,0x00,0x00,0xff};
939 static const Region
bg( 0, 0, 100, 30 );
941 /** this is the main loop */
942 void Interface::Main()
944 video
->CreateDisplay( Width
, Height
, Bpp
, FullScreen
);
945 video
->SetDisplayTitle( GameName
, GameType
);
946 ieDword brightness
= 10;
947 ieDword contrast
= 5;
949 vars
->Lookup("Brightness Correction", brightness
);
950 vars
->Lookup("Gamma Correction", contrast
);
951 vars
->Lookup("Mouse Scroll Speed", speed
);
952 video
->SetGamma(brightness
, contrast
);
953 SetMouseScrollSpeed((int) speed
);
954 if (vars
->Lookup("Tooltips", TooltipDelay
)) {
955 // the games store the slider position*10, not the actual delay
956 TooltipDelay
*= TOOLTIP_DELAY_FACTOR
/10;
959 Font
* fps
= GetFont( ( unsigned int ) 0 );
960 char fpsstring
[40]={"???.??? fps"};
961 unsigned long frame
= 0, time
, timebase
;
964 Palette
* palette
= CreatePalette( white
, black
);
966 //don't change script when quitting is pending
974 HandleGUIBehaviour();
981 if (time
- timebase
> 1000) {
982 frames
= ( frame
* 1000.0 / ( time
- timebase
) );
985 sprintf( fpsstring
, "%.3f fps", frames
);
987 video
->DrawRect( bg
, black
);
989 ( unsigned char * ) fpsstring
, palette
,
990 IE_FONT_ALIGN_LEFT
| IE_FONT_ALIGN_MIDDLE
, true );
992 } while (video
->SwapBuffers() == GEM_OK
);
993 gamedata
->FreePalette( palette
);
996 bool Interface::ReadStrrefs()
999 memset(strref_table
,-1,sizeof(strref_table
) );
1000 AutoTable
tab("strings");
1004 for(i
=0;i
<STRREF_COUNT
;i
++) {
1005 strref_table
[i
]=atoi(tab
->QueryField(i
,0));
1010 int Interface::ReadResRefTable(const ieResRef tablename
, ieResRef
*&data
)
1018 AutoTable
tm(tablename
);
1020 printStatus( "ERROR", LIGHT_RED
);
1021 printf( "Cannot find %s.2da.\n",tablename
);
1024 count
= tm
->GetRowCount();
1025 data
= (ieResRef
*) calloc( count
, sizeof(ieResRef
) );
1026 for (int i
= 0; i
< count
; i
++) {
1027 strnlwrcpy( data
[i
], tm
->QueryField( i
, 0 ), 8 );
1028 //* marks an empty resource
1029 if (data
[i
][0]=='*') {
1036 int Interface::LoadSprites()
1040 if (!IsAvailable( IE_2DA_CLASS_ID
)) {
1041 printf( "No 2DA Importer Available.\nTermination in Progress...\n" );
1046 AnimationFactory
* anim
;
1047 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("cursors", IE_BAM_CLASS_ID
);
1050 CursorCount
= anim
->GetCycleCount();
1051 Cursors
= new Sprite2D
* [CursorCount
];
1052 for (int i
= 0; i
< CursorCount
; i
++) {
1053 Cursors
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1056 printMessage( "Core", "Loading Cursors...", WHITE
);
1058 // this is the last existing cursor type
1059 if (CursorCount
<IE_CURSOR_WAY
) {
1060 printStatus( "ERROR", LIGHT_RED
);
1063 video
->SetCursor( Cursors
[0], Cursors
[1] );
1064 printStatus( "OK", LIGHT_GREEN
);
1066 // Load fog-of-war bitmaps
1067 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource("fogowar", IE_BAM_CLASS_ID
);
1068 printMessage( "Core", "Loading Fog-Of-War bitmaps...", WHITE
);
1069 if (!anim
|| anim
->GetCycleSize( 0 ) != 8) {
1070 // unknown type of fog anim
1071 printStatus( "ERROR", LIGHT_RED
);
1075 FogSprites
[0] = NULL
;
1076 FogSprites
[1] = anim
->GetFrame( 0, 0 );
1077 FogSprites
[2] = anim
->GetFrame( 1, 0 );
1078 FogSprites
[3] = anim
->GetFrame( 2, 0 );
1080 FogSprites
[4] = video
->MirrorSpriteVertical( FogSprites
[1], false );
1082 FogSprites
[5] = NULL
;
1084 FogSprites
[6] = video
->MirrorSpriteVertical( FogSprites
[3], false );
1086 FogSprites
[7] = NULL
;
1088 FogSprites
[8] = video
->MirrorSpriteHorizontal( FogSprites
[2], false );
1090 FogSprites
[9] = video
->MirrorSpriteHorizontal( FogSprites
[3], false );
1092 FogSprites
[10] = NULL
;
1093 FogSprites
[11] = NULL
;
1095 FogSprites
[12] = video
->MirrorSpriteHorizontal( FogSprites
[6], false );
1097 FogSprites
[16] = anim
->GetFrame( 3, 0 );
1098 FogSprites
[17] = anim
->GetFrame( 4, 0 );
1099 FogSprites
[18] = anim
->GetFrame( 5, 0 );
1100 FogSprites
[19] = anim
->GetFrame( 6, 0 );
1102 FogSprites
[20] = video
->MirrorSpriteVertical( FogSprites
[17], false );
1104 FogSprites
[21] = NULL
;
1106 FogSprites
[23] = NULL
;
1108 FogSprites
[24] = video
->MirrorSpriteHorizontal( FogSprites
[18], false );
1110 FogSprites
[25] = anim
->GetFrame( 7, 0 );
1113 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[25], false );
1114 FogSprites
[22] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1115 video
->FreeSprite( tmpsprite
);
1118 FogSprites
[26] = NULL
;
1119 FogSprites
[27] = NULL
;
1122 Sprite2D
*tmpsprite
= video
->MirrorSpriteVertical( FogSprites
[19], false );
1123 FogSprites
[28] = video
->MirrorSpriteHorizontal( tmpsprite
, false );
1124 video
->FreeSprite( tmpsprite
);
1128 vars
->Lookup("3D Acceleration", i
);
1130 for(i
=0;i
<sizeof(FogSprites
)/sizeof(Sprite2D
*);i
++ ) {
1131 if (FogSprites
[i
]) {
1132 Sprite2D
* alphasprite
= video
->CreateAlpha( FogSprites
[i
] );
1133 video
->FreeSprite ( FogSprites
[i
] );
1134 FogSprites
[i
] = alphasprite
;
1139 printStatus( "OK", LIGHT_GREEN
);
1141 // Load ground circle bitmaps (PST only)
1142 //block required due to msvc6.0 incompatibility
1143 for (size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
1144 if (GroundCircleBam
[size
][0]) {
1145 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(GroundCircleBam
[size
], IE_BAM_CLASS_ID
);
1146 if (!anim
|| anim
->GetCycleCount() != 6) {
1147 // unknown type of circle anim
1148 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1149 printStatus( "ERROR", LIGHT_RED
);
1153 for (int i
= 0; i
< 6; i
++) {
1154 Sprite2D
* sprite
= anim
->GetFrame( 0, (ieByte
) i
);
1155 if (GroundCircleScale
[size
]) {
1156 GroundCircles
[size
][i
] = video
->SpriteScaleDown( sprite
, GroundCircleScale
[size
] );
1157 video
->FreeSprite( sprite
);
1159 GroundCircles
[size
][i
] = sprite
;
1165 printMessage( "Core", "Loading Ground circle bitmaps...", WHITE
);
1166 printStatus( "OK", LIGHT_GREEN
);
1168 printMessage( "Core", "Loading Fonts...\n", WHITE
);
1169 AutoTable
tab("fonts");
1171 printStatus( "ERROR", LIGHT_RED
);
1172 printf( "Cannot find fonts.2da.\nTermination in Progress...\n" );
1175 AnimationMgr
* bamint
= ( AnimationMgr
* ) GetInterface( IE_BAM_CLASS_ID
);
1177 printStatus( "ERROR", LIGHT_RED
);
1178 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1181 DataStream
* str
= NULL
;
1183 int count
= tab
->GetRowCount();
1184 for (int i
= 0; i
< count
; i
++) {
1185 const char* ResRef
= tab
->QueryField( i
, 0 );
1186 int needpalette
= atoi( tab
->QueryField( i
, 1 ) );
1187 int first_char
= atoi( tab
->QueryField( i
, 2 ) );
1188 str
= gamedata
->GetResource( ResRef
, IE_BAM_CLASS_ID
);
1189 if (!bamint
->Open( str
, true )) {
1192 Font
* fnt
= bamint
->GetFont();
1196 strnlwrcpy( fnt
->ResRef
, ResRef
, 8 );
1199 Color fore
= {0xff, 0xff, 0xff, 0};
1200 Color back
= {0x00, 0x00, 0x00, 0};
1201 if (!strnicmp( TooltipFont
, ResRef
, 8) ) {
1202 if (TooltipColor
.a
==0xff) {
1203 fore
= TooltipColor
;
1206 back
= TooltipColor
;
1209 Palette
* pal
= CreatePalette( fore
, back
);
1210 pal
->CreateShadedAlphaChannel();
1211 fnt
->SetPalette(pal
);
1212 gamedata
->FreePalette( pal
);
1214 fnt
->SetFirstChar( (ieByte
) first_char
);
1215 fonts
.push_back( fnt
);
1217 FreeInterface(bamint
);
1219 printMessage( "Core", "Fonts Loaded...", WHITE
);
1220 printStatus( "OK", LIGHT_GREEN
);
1222 if (TooltipBackResRef
[0]) {
1223 anim
= (AnimationFactory
*) gamedata
->GetFactoryResource(TooltipBackResRef
, IE_BAM_CLASS_ID
);
1224 printMessage( "Core", "Initializing Tooltips...", WHITE
);
1226 printStatus( "ERROR", LIGHT_RED
);
1229 TooltipBack
= new Sprite2D
* [3];
1230 for (int i
= 0; i
< 3; i
++) {
1231 TooltipBack
[i
] = anim
->GetFrame( 0, (ieByte
) i
);
1232 TooltipBack
[i
]->XPos
= 0;
1233 TooltipBack
[i
]->YPos
= 0;
1235 printStatus( "OK", LIGHT_GREEN
);
1241 int Interface::Init()
1243 plugin_flags
= new Variables();
1244 plugin_flags
->SetType( GEM_VARIABLES_INT
);
1246 printMessage( "Core", "Initializing the Event Manager...", WHITE
);
1247 evntmgr
= new EventMgr();
1249 printMessage( "Core", "Initializing Variables Dictionary...", WHITE
);
1250 vars
= new Variables();
1252 printStatus( "ERROR", LIGHT_RED
);
1256 vars
->SetType( GEM_VARIABLES_INT
);
1257 vars
->SetAt( "Volume Ambients", 100 );
1258 vars
->SetAt( "Volume Movie", 100 );
1259 vars
->SetAt( "Volume Music", 100 );
1260 vars
->SetAt( "Volume SFX", 100 );
1261 vars
->SetAt( "Volume Voices", 100 );
1262 printStatus( "OK", LIGHT_GREEN
);
1264 if (!LoadConfig()) {
1267 printMessage( "Core", "Starting Plugin Manager...\n", WHITE
);
1268 plugin
= new PluginMgr( PluginsPath
);
1269 if (plugin
&& plugin
->GetPluginCount()) {
1270 printMessage( "Core", "Plugin Loading Complete...", WHITE
);
1271 printStatus( "OK", LIGHT_GREEN
);
1273 printMessage( "Core", "Plugin Loading Failed, check path...", YELLOW
);
1274 printStatus( "ERROR", LIGHT_RED
);
1279 srand( ( unsigned int ) t
);
1281 FileStreamPtrCount
= 0;
1282 CachedFileStreamPtrCount
= 0;
1284 printMessage( "Core", "GemRB Core Initialization...\n", WHITE
);
1285 printMessage( "Core", "Searching for Video Driver...", WHITE
);
1286 if (!IsAvailable( IE_VIDEO_CLASS_ID
)) {
1287 printStatus( "ERROR", LIGHT_RED
);
1288 printf( "No Video Driver Available.\nTermination in Progress...\n" );
1291 printStatus( "OK", LIGHT_GREEN
);
1292 printMessage( "Core", "Initializing Video Plugin...", WHITE
);
1293 video
= ( Video
* ) GetInterface( IE_VIDEO_CLASS_ID
);
1294 if (video
->Init() == GEM_ERROR
) {
1295 printStatus( "ERROR", LIGHT_RED
);
1296 printf( "Cannot Initialize Video Driver.\nTermination in Progress...\n" );
1299 Color defcolor
={255,255,255,200};
1300 SetInfoTextColor(defcolor
);
1301 printStatus( "OK", LIGHT_GREEN
);
1304 printMessage( "Core", "Initializing Search Path...", WHITE
);
1305 if (!IsAvailable( PLUGIN_RESOURCE_DIRECTORY
)) {
1306 printf( "no DirectoryImporter! " );
1307 printStatus( "ERROR", LIGHT_RED
);
1311 char path
[_MAX_PATH
];
1313 PathJoin( path
, core
->CachePath
, NULL
);
1314 gamedata
->AddSource(path
, "Cache", PLUGIN_RESOURCE_DIRECTORY
);
1316 PathJoin( path
, core
->GemRBOverridePath
, "override", core
->GameType
, NULL
);
1317 gamedata
->AddSource(path
, "GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1319 PathJoin( path
, core
->GemRBOverridePath
, "override", "shared", NULL
);
1320 gamedata
->AddSource(path
, "shared GemRB Override", PLUGIN_RESOURCE_DIRECTORY
);
1322 PathJoin( path
, core
->GamePath
, core
->GameOverridePath
, NULL
);
1323 gamedata
->AddSource(path
, "Override", PLUGIN_RESOURCE_DIRECTORY
);
1325 PathJoin( path
, core
->GamePath
, core
->GameSoundsPath
, NULL
);
1326 gamedata
->AddSource(path
, "Sounds", PLUGIN_RESOURCE_DIRECTORY
);
1328 PathJoin( path
, core
->GamePath
, core
->GameScriptsPath
, NULL
);
1329 gamedata
->AddSource(path
, "Scripts", PLUGIN_RESOURCE_DIRECTORY
);
1331 PathJoin( path
, core
->GamePath
, core
->GamePortraitsPath
, NULL
);
1332 gamedata
->AddSource(path
, "Portraits", PLUGIN_RESOURCE_DIRECTORY
);
1334 PathJoin( path
, core
->GamePath
, core
->GameDataPath
, NULL
);
1335 gamedata
->AddSource(path
, "Data", PLUGIN_RESOURCE_DIRECTORY
);
1337 //IWD2 movies are on the CD but not in the BIF
1338 for (int i
= 0; i
< 6; i
++) {
1339 char description
[] = "CDi/data";
1340 PathJoin( path
, core
->CD
[i
], core
->GameDataPath
, NULL
);
1341 description
[2] = '1' + i
;
1342 gamedata
->AddSource(path
, description
, PLUGIN_RESOURCE_DIRECTORY
);
1345 printStatus( "OK", LIGHT_GREEN
);
1349 printMessage( "Core", "Initializing KEY Importer...", WHITE
);
1350 char ChitinPath
[_MAX_PATH
];
1351 PathJoin( ChitinPath
, GamePath
, "chitin.key", NULL
);
1352 if (!gamedata
->AddSource(ChitinPath
, "chitin.key", PLUGIN_RESOURCE_KEY
)) {
1353 printStatus( "ERROR", LIGHT_RED
);
1356 printStatus( "OK", LIGHT_GREEN
);
1359 printMessage( "Core", "Reading Game Options...\n", WHITE
);
1360 if (!LoadGemRBINI())
1362 printf( "Cannot Load INI\nTermination in Progress...\n" );
1366 //loading baldur.ini
1368 char ini_path
[_MAX_PATH
];
1369 PathJoin( ini_path
, GamePath
, INIConfig
, NULL
);
1370 ResolveFilePath( ini_path
);
1371 LoadINI( ini_path
);
1373 for (i
= 0; i
< 8; i
++) {
1374 if (INIConfig
[i
] == '.')
1376 GameNameResRef
[i
] = INIConfig
[i
];
1378 GameNameResRef
[i
] = 0;
1381 printMessage( "Core", "Creating Projectile Server...\n", WHITE
);
1382 projserv
= new ProjectileServer();
1383 if (!projserv
->GetHighestProjectileNumber()) {
1384 printStatus( "ERROR", LIGHT_RED
);
1385 printf( "No projectiles are available...\n" );
1388 printMessage( "Core", "Checking for Dialogue Manager...", WHITE
);
1389 if (!IsAvailable( IE_TLK_CLASS_ID
)) {
1390 printStatus( "ERROR", LIGHT_RED
);
1391 printf( "No TLK Importer Available.\nTermination in Progress...\n" );
1394 printStatus( "OK", LIGHT_GREEN
);
1395 strings
= ( StringMgr
* ) GetInterface( IE_TLK_CLASS_ID
);
1396 printMessage( "Core", "Loading Dialog.tlk file...", WHITE
);
1397 char strpath
[_MAX_PATH
];
1398 PathJoin( strpath
, GamePath
, dialogtlk
, NULL
);
1399 ResolveFilePath( strpath
);
1400 FileStream
* fs
= new FileStream();
1401 if (!fs
->Open( strpath
, true )) {
1402 printStatus( "ERROR", LIGHT_RED
);
1403 printf( "Cannot find Dialog.tlk.\nTermination in Progress...\n" );
1407 printStatus( "OK", LIGHT_GREEN
);
1408 strings
->Open( fs
, true );
1411 printMessage( "Core", "Loading Palettes...\n", WHITE
);
1412 ImageMgr
*im
=( ImageMgr
* ) gamedata
->GetResource( Palette16
, &ImageMgr::ID
);
1413 pal16
= im
->GetImage();
1415 im
= ( ImageMgr
* ) gamedata
->GetResource( Palette32
, &ImageMgr::ID
);
1416 pal32
= im
->GetImage();
1418 im
= ( ImageMgr
* ) gamedata
->GetResource( Palette256
, &ImageMgr::ID
);
1419 pal256
= im
->GetImage();
1421 printMessage( "Core", "Palettes Loaded\n", WHITE
);
1424 if (!IsAvailable( IE_BAM_CLASS_ID
)) {
1425 printStatus( "ERROR", LIGHT_RED
);
1426 printf( "No BAM Importer Available.\nTermination in Progress...\n" );
1430 printMessage( "Core", "Initializing stock sounds...\n", WHITE
);
1431 DSCount
= ReadResRefTable ("defsound", DefSound
);
1433 printStatus( "ERROR", LIGHT_RED
);
1434 printf( "Cannot find defsound.2da.\nTermination in Progress...\n" );
1438 printStatus( "OK", LIGHT_GREEN
);
1439 printMessage( "Core", "Broadcasting Event Manager...", WHITE
);
1440 video
->SetEventMgr( evntmgr
);
1441 printStatus( "OK", LIGHT_GREEN
);
1442 printMessage( "Core", "Initializing Window Manager...", WHITE
);
1443 windowmgr
= ( WindowMgr
* ) GetInterface( IE_CHU_CLASS_ID
);
1444 if (windowmgr
== NULL
) {
1445 printStatus( "ERROR", LIGHT_RED
);
1448 printStatus( "OK", LIGHT_GREEN
);
1449 printMessage( "Core", "Initializing GUI Script Engine...", WHITE
);
1450 guiscript
= ( ScriptEngine
* ) GetInterface( IE_GUI_SCRIPT_CLASS_ID
);
1451 if (guiscript
== NULL
) {
1452 printStatus( "ERROR", LIGHT_RED
);
1455 if (!guiscript
->Init()) {
1456 printStatus( "ERROR", LIGHT_RED
);
1459 printStatus( "OK", LIGHT_GREEN
);
1460 strcpy( NextScript
, "Start" );
1462 int ret
= LoadSprites();
1463 if (ret
) return ret
;
1465 Sprite2D
*tmpsprite
= GetCursorSprite();
1466 printMessage( "Core", "Setting up the Console...", WHITE
);
1467 QuitFlag
= QF_CHANGESCRIPT
;
1468 console
= new Console();
1470 console
->YPos
= (ieWord
) (Height
- 25);
1471 console
->Width
= (ieWord
) Width
;
1472 console
->Height
= 25;
1473 console
->SetFont( fonts
[0] );
1475 printStatus( "ERROR", LIGHT_RED
);
1478 console
->SetCursor (tmpsprite
);
1479 printStatus( "OK", LIGHT_GREEN
);
1481 printMessage( "Core", "Starting up the Sound Driver...", WHITE
);
1482 AudioDriver
= ( Audio
* ) GetInterface( IE_AUDIO_CLASS_ID
);
1483 if (AudioDriver
== NULL
) {
1484 printStatus( "ERROR", LIGHT_RED
);
1487 if (!AudioDriver
->Init()) {
1488 printStatus( "ERROR", LIGHT_RED
);
1491 printStatus( "OK", LIGHT_GREEN
);
1493 printMessage( "Core", "Allocating SaveGameIterator...", WHITE
);
1494 sgiterator
= new SaveGameIterator();
1495 if (sgiterator
== NULL
) {
1496 printStatus( "ERROR", LIGHT_RED
);
1499 printStatus( "OK", LIGHT_GREEN
);
1501 //no need of strdup, variables do copy the key!
1502 vars
->SetAt( "SkipIntroVideos", (unsigned long)SkipIntroVideos
);
1503 vars
->SetAt( "GUIEnhancements", (unsigned long)GUIEnhancements
);
1505 printMessage( "Core", "Initializing Token Dictionary...", WHITE
);
1506 tokens
= new Variables();
1508 printStatus( "ERROR", LIGHT_RED
);
1511 tokens
->SetType( GEM_VARIABLES_STRING
);
1512 printStatus( "OK", LIGHT_GREEN
);
1514 printMessage( "Core", "Initializing Music Manager...", WHITE
);
1515 music
= ( MusicMgr
* ) GetInterface( IE_MUS_CLASS_ID
);
1517 printStatus( "ERROR", LIGHT_RED
);
1520 printStatus( "OK", LIGHT_GREEN
);
1522 printMessage("Core", "Loading music list...\n", WHITE
);
1523 if (HasFeature( GF_HAS_SONGLIST
)) {
1524 ret
= ReadMusicTable("songlist", 1);
1526 /*since bg1 and pst has no .2da for songlist,
1527 we must supply one in the gemrb/override folder.
1528 It should be: music.2da, first column is a .mus filename*/
1529 ret
= ReadMusicTable("music", 0);
1532 printStatus( "OK", LIGHT_GREEN
);
1534 printStatus( "NOT FOUND", YELLOW
);
1537 if (HasFeature( GF_RESDATA_INI
)) {
1538 printMessage( "Core", "Loading resource data File...", WHITE
);
1539 INIresdata
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1540 DataStream
* ds
= gamedata
->GetResource("resdata", IE_INI_CLASS_ID
);
1541 if (!INIresdata
->Open( ds
, true )) {
1542 printStatus( "ERROR", LIGHT_RED
);
1544 printStatus( "OK", LIGHT_GREEN
);
1548 if (HasFeature( GF_HAS_PARTY_INI
)) {
1549 printMessage( "Core", "Loading precreated teams setup...\n",
1551 INIparty
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1552 FileStream
* fs
= new FileStream();
1553 char tINIparty
[_MAX_PATH
];
1554 PathJoin( tINIparty
, GamePath
, "Party.ini", NULL
);
1555 ResolveFilePath( tINIparty
);
1556 fs
->Open( tINIparty
, true );
1557 if (!INIparty
->Open( fs
, true )) {
1558 printStatus( "ERROR", LIGHT_RED
);
1560 printStatus( "OK", LIGHT_GREEN
);
1564 if (HasFeature(GF_IWD2_DEATHVARFORMAT
)) {
1565 memcpy(DeathVarFormat
, IWD2DeathVarFormat
, sizeof(ieVariable
));
1568 if (HasFeature( GF_HAS_BEASTS_INI
)) {
1569 printMessage( "Core", "Loading beasts definition File...\n",
1571 INIbeasts
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1572 FileStream
* fs
= new FileStream();
1573 char tINIbeasts
[_MAX_PATH
];
1574 PathJoin( tINIbeasts
, GamePath
, "beast.ini", NULL
);
1575 ResolveFilePath( tINIbeasts
);
1576 // FIXME: crashes if file does not open
1577 fs
->Open( tINIbeasts
, true );
1578 if (!INIbeasts
->Open( fs
, true )) {
1579 printStatus( "ERROR", LIGHT_RED
);
1581 printStatus( "OK", LIGHT_GREEN
);
1584 printMessage( "Core", "Loading quests definition File...\n",
1586 INIquests
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
1587 FileStream
* fs2
= new FileStream();
1588 char tINIquests
[_MAX_PATH
];
1589 PathJoin( tINIquests
, GamePath
, "quests.ini", NULL
);
1590 ResolveFilePath( tINIquests
);
1591 // FIXME: crashes if file does not open
1592 fs2
->Open( tINIquests
, true );
1593 if (!INIquests
->Open( fs2
, true )) {
1594 printStatus( "ERROR", LIGHT_RED
);
1596 printStatus( "OK", LIGHT_GREEN
);
1602 timer
= new GlobalTimer();
1603 printMessage( "Core", "Bringing up the Global Timer...", WHITE
);
1605 printStatus( "ERROR", LIGHT_RED
);
1608 printStatus( "OK", LIGHT_GREEN
);
1610 ret
= Init_EffectQueue();
1611 printMessage( "Core", "Initializing effects...", WHITE
);
1613 printStatus( "ERROR", LIGHT_RED
);
1616 printStatus( "OK", LIGHT_GREEN
);
1618 ret
= InitItemTypes();
1619 printMessage( "Core", "Initializing Inventory Management...", WHITE
);
1621 printStatus( "ERROR", LIGHT_RED
);
1624 printStatus( "OK", LIGHT_GREEN
);
1626 ret
= ReadStrrefs();
1627 printMessage( "Core", "Initializing string constants...", WHITE
);
1629 printStatus( "ERROR", LIGHT_RED
);
1632 printStatus( "OK", LIGHT_GREEN
);
1634 ret
= ReadRandomItems();
1635 printMessage( "Core", "Initializing random treasure...", WHITE
);
1637 printStatus( "OK", LIGHT_GREEN
);
1640 printStatus( "ERROR", LIGHT_RED
);
1643 ret
= ReadAbilityTables();
1644 printMessage( "Core", "Initializing ability tables...", WHITE
);
1646 printStatus( "ERROR", LIGHT_RED
);
1649 printStatus( "OK", LIGHT_GREEN
);
1651 if ( gamedata
->Exists("WMAPLAY", IE_2DA_CLASS_ID
) ) {
1652 ret
= ReadAreaAliasTable( "WMAPLAY" );
1653 printMessage( "Core", "Initializing area aliases...", WHITE
);
1655 printStatus( "OK", LIGHT_GREEN
);
1658 printStatus( "NOT FOUND", YELLOW
);
1662 ret
= ReadAuxItemTables();
1663 printMessage( "Core", "Reading item tables...", WHITE
);
1665 printStatus( "ERROR", LIGHT_RED
);
1668 printStatus( "OK", LIGHT_GREEN
);
1670 ret
= ReadDamageTypeTable();
1671 printMessage( "Core", "Reading damage type table...", WHITE
);
1673 printStatus( "ERROR", LIGHT_RED
);
1675 printStatus( "OK", LIGHT_GREEN
);
1678 printMessage( "Core", "Core Initialization Complete!\n", WHITE
);
1683 bool Interface::IsAvailable(SClass_ID filetype
) const
1685 return plugin
->IsAvailable( filetype
);
1688 WorldMap
*Interface::GetWorldMap(const char *map
)
1690 int index
= worldmap
->FindAndSetCurrentMap(map
?map
:game
->CurrentArea
);
1691 return worldmap
->GetWorldMap(index
);
1694 void* Interface::GetInterface(SClass_ID filetype
) const
1699 return plugin
->GetPlugin( filetype
);
1702 ProjectileServer
* Interface::GetProjectileServer() const
1707 Video
* Interface::GetVideoDriver() const
1712 PluginMgr
* Interface::GetPluginMgr() const
1717 void Interface::RegisterCleanup(void (*func
)(void))
1719 cleanupFunctions
.push_back(func
);
1722 const char* Interface::TypeExt(SClass_ID type
) const
1725 case IE_2DA_CLASS_ID
:
1728 case IE_ACM_CLASS_ID
:
1731 case IE_ARE_CLASS_ID
:
1734 case IE_BAM_CLASS_ID
:
1737 case IE_BCS_CLASS_ID
:
1740 case IE_BS_CLASS_ID
:
1743 case IE_BIF_CLASS_ID
:
1746 case IE_BMP_CLASS_ID
:
1749 case IE_PNG_CLASS_ID
:
1752 case IE_CHR_CLASS_ID
:
1755 case IE_CHU_CLASS_ID
:
1758 case IE_CRE_CLASS_ID
:
1761 case IE_DLG_CLASS_ID
:
1764 case IE_EFF_CLASS_ID
:
1767 case IE_GAM_CLASS_ID
:
1770 case IE_IDS_CLASS_ID
:
1773 case IE_INI_CLASS_ID
:
1776 case IE_ITM_CLASS_ID
:
1779 case IE_MOS_CLASS_ID
:
1782 case IE_MUS_CLASS_ID
:
1785 case IE_MVE_CLASS_ID
:
1788 case IE_OGG_CLASS_ID
:
1791 case IE_PLT_CLASS_ID
:
1794 case IE_PRO_CLASS_ID
:
1797 case IE_SAV_CLASS_ID
:
1800 case IE_SPL_CLASS_ID
:
1803 case IE_SRC_CLASS_ID
:
1806 case IE_STO_CLASS_ID
:
1809 case IE_TIS_CLASS_ID
:
1812 case IE_TLK_CLASS_ID
:
1815 case IE_TOH_CLASS_ID
:
1818 case IE_TOT_CLASS_ID
:
1821 case IE_VAR_CLASS_ID
:
1824 case IE_VVC_CLASS_ID
:
1827 case IE_WAV_CLASS_ID
:
1830 case IE_WED_CLASS_ID
:
1833 case IE_WFX_CLASS_ID
:
1836 case IE_WMP_CLASS_ID
:
1842 void Interface::FreeString(char *&str
) const
1845 strings
->FreeString(str
);
1850 ieStrRef
Interface::UpdateString(ieStrRef strref
, const char *text
) const
1852 return strings
->UpdateString( strref
, text
);
1855 char* Interface::GetString(ieStrRef strref
, ieDword options
) const
1859 if (!(options
& IE_STR_STRREFOFF
)) {
1860 vars
->Lookup( "Strref On", flags
);
1862 return strings
->GetString( strref
, flags
| options
);
1865 void Interface::FreeInterface(Plugin
* ptr
)
1867 plugin
->FreePlugin( ptr
);
1870 void Interface::SetFeature(int flag
, int position
)
1875 GameFeatures2
|= 1 << position
;
1877 GameFeatures2
&= ~( 1 << position
);
1882 GameFeatures
|= 1 << position
;
1884 GameFeatures
&= ~( 1 << position
);
1888 ieDword
Interface::HasFeature(int position
) const
1891 return GameFeatures2
& ( 1 << (position
-32) );
1893 return GameFeatures
& ( 1 << position
);
1896 /** Search directories and load a config file */
1897 bool Interface::LoadConfig(void)
1900 char path
[_MAX_PATH
];
1901 char name
[_MAX_PATH
];
1903 // Find directory where user stores GemRB configurations (~/.gemrb).
1904 // FIXME: Create it if it does not exist
1905 // Use current dir if $HOME is not defined (or bomb out??)
1907 char* s
= getenv( "HOME" );
1909 strcpy( UserDir
, s
);
1910 strcat( UserDir
, "/."PACKAGE
"/" );
1912 strcpy( UserDir
, "./" );
1915 // Find basename of this program. It does the same as basename (3),
1916 // but that's probably missing on some archs
1917 s
= strrchr( argv
[0], PathDelimiter
);
1925 //if (!name[0]) // FIXME: could this happen?
1926 // strcpy (name, PACKAGE); // ugly hack
1928 // If we were called as $0 -c <filename>, load config from filename
1929 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
1930 if (LoadConfig( argv
[2] )) {
1933 // Explicitly specified cfg file HAS to be present
1938 // FIXME: temporary hack, to be deleted??
1939 if (LoadConfig( "GemRB.cfg" )) {
1943 PathJoin( path
, UserDir
, name
, NULL
);
1944 strcat( path
, ".cfg" );
1946 if (LoadConfig( path
)) {
1951 PathJoin( path
, SYSCONFDIR
, name
, NULL
);
1952 strcat( path
, ".cfg" );
1954 if (LoadConfig( path
)) {
1959 // Don't try with default binary name if we have tried it already
1960 if (!strcmp( name
, PACKAGE
)) {
1964 PathJoin( path
, UserDir
, PACKAGE
, NULL
);
1965 strcat( path
, ".cfg" );
1967 if (LoadConfig( path
)) {
1972 PathJoin( path
, SYSCONFDIR
, PACKAGE
, NULL
);
1973 strcat( path
, ".cfg" );
1975 if (LoadConfig( path
)) {
1982 // If we were called as $0 -c <filename>, load config from filename
1983 if (argc
> 2 && ! strcmp("-c", argv
[1])) {
1984 return LoadConfig( argv
[2] );
1985 // Explicitly specified cfg file HAS to be present
1987 strcpy( UserDir
, ".\\" );
1988 return LoadConfig( "GemRB.cfg" );
1992 bool Interface::LoadConfig(const char* filename
)
1996 printMessage("Config","Trying to open ", WHITE
);
1997 textcolor(LIGHT_WHITE
);
1998 printf("%s ", filename
);
1999 config
= fopen( filename
, "rb" );
2000 if (config
== NULL
) {
2001 printStatus("NOT FOUND", LIGHT_RED
);
2004 char name
[65], value
[_MAX_PATH
+ 3];
2006 //once GemRB own format is working well, this might be set to 0
2009 while (!feof( config
)) {
2012 if (fread( &rem
, 1, 1, config
) != 1)
2016 //it should always return 0
2017 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
2021 fseek( config
, -1, SEEK_CUR
);
2022 memset(value
,'\0',_MAX_PATH
+ 3);
2023 //the * element is not counted
2024 if (fscanf( config
, "%64[^= ] = %[^\r\n]%*[\r\n]", name
, value
)!=2)
2026 for (int i
=_MAX_PATH
+ 2; i
> 0; i
--) {
2027 if (value
[i
] == '\0') continue;
2028 if (value
[i
] == ' ') {
2035 if (stricmp( name
, "Width" ) == 0) {
2036 Width
= atoi( value
);
2037 } else if (stricmp( name
, "Height" ) == 0) {
2038 Height
= atoi( value
);
2039 } else if (stricmp( name
, "Bpp" ) == 0) {
2040 Bpp
= atoi( value
);
2041 } else if (stricmp( name
, "FullScreen" ) == 0) {
2042 FullScreen
= ( atoi( value
) == 0 ) ? false : true;
2043 } else if (stricmp( name
, "GUIEnhancements" ) == 0) {
2044 GUIEnhancements
= ( atoi( value
) == 0 ) ? false : true;
2045 } else if (stricmp( name
, "TooltipDelay" ) == 0) {
2046 TooltipDelay
= atoi( value
);
2047 } else if (stricmp( name
, "DoubleClickDelay" ) == 0) {
2048 evntmgr
->SetDCDelay( atoi( value
) );
2049 } else if (stricmp( name
, "RepeatKeyDelay" ) == 0) {
2050 evntmgr
->SetRKDelay( atoi( value
) );
2051 } else if (stricmp( name
, "SkipIntroVideos" ) == 0) {
2052 SkipIntroVideos
= ( atoi( value
) == 0 ) ? false : true;
2053 } else if (stricmp( name
, "DrawFPS" ) == 0) {
2054 DrawFPS
= ( atoi( value
) == 0 ) ? false : true;
2055 } else if (stricmp( name
, "EnableCheatKeys" ) == 0) {
2056 EnableCheatKeys ( atoi( value
) );
2057 } else if (stricmp( name
, "KeepCache" ) == 0) {
2058 KeepCache
= ( atoi( value
) == 0 ) ? false : true;
2059 } else if (stricmp( name
, "SkipPlugin" ) == 0) {
2060 plugin_flags
->SetAt( value
, PLF_SKIP
);
2061 } else if (stricmp( name
, "DelayPlugin" ) == 0) {
2062 plugin_flags
->SetAt( value
, PLF_DELAY
);
2063 } else if (stricmp( name
, "FogOfWar" ) == 0) {
2064 FogOfWar
= atoi( value
);
2065 } else if (stricmp( name
, "EndianSwitch" ) == 0) {
2066 DataStream::SetEndianSwitch(atoi(value
) );
2067 } else if (stricmp( name
, "CaseSensitive" ) == 0) {
2068 CaseSensitive
= ( atoi( value
) == 0 ) ? false : true;
2069 } else if (stricmp( name
, "MultipleQuickSaves" ) == 0) {
2070 GameControl::MultipleQuickSaves(atoi(value
));
2071 } else if (stricmp( name
, "GameOnCD" ) == 0) {
2072 GameOnCD
= ( atoi( value
) == 0 ) ? false : true;
2073 } else if (stricmp( name
, "GameDataPath" ) == 0) {
2074 strncpy( GameDataPath
, value
, sizeof(GameDataPath
) );
2075 } else if (stricmp( name
, "GameOverridePath" ) == 0) {
2076 strncpy( GameOverridePath
, value
, sizeof(GameOverridePath
) );
2077 } else if (stricmp( name
, "GemRBOverridePath" ) == 0) {
2078 strncpy( GemRBOverridePath
, value
, sizeof(GemRBOverridePath
) );
2079 } else if (stricmp( name
, "GameScriptsPath" ) == 0) {
2080 strncpy( GameScriptsPath
, value
, sizeof(GameScriptsPath
) );
2081 } else if (stricmp( name
, "GameSoundsPath" ) == 0) {
2082 strncpy( GameSoundsPath
, value
, sizeof(GameSoundsPath
) );
2083 } else if (stricmp( name
, "GamePortraitsPath" ) == 0) {
2084 strncpy( GamePortraitsPath
, value
, sizeof(GamePortraitsPath
) );
2085 } else if (stricmp( name
, "GameCharactersPath" ) == 0) {
2086 strncpy( GameCharactersPath
, value
, sizeof(GameCharactersPath
) );
2087 } else if (stricmp( name
, "GameName" ) == 0) {
2088 strncpy( GameName
, value
, sizeof(GameName
) );
2089 } else if (stricmp( name
, "GameType" ) == 0) {
2090 if (stricmp( value
, "tob" ) == 0) {
2091 strncpy( GameType
, "bg2", sizeof(GameType
) );
2093 strncpy( GameType
, value
, sizeof(GameType
) );
2095 } else if (stricmp( name
, "SaveAsOriginal") == 0) {
2096 SaveAsOriginal
= atoi(value
);
2097 } else if (stricmp( name
, "GemRBPath" ) == 0) {
2098 strcpy( GemRBPath
, value
);
2099 } else if (stricmp( name
, "ScriptDebugMode" ) == 0) {
2100 SetScriptDebugMode(atoi(value
));
2101 } else if (stricmp( name
, "CachePath" ) == 0) {
2102 strncpy( CachePath
, value
, sizeof(CachePath
) );
2103 } else if (stricmp( name
, "GUIScriptsPath" ) == 0) {
2104 strncpy( GUIScriptsPath
, value
, sizeof(GUIScriptsPath
) );
2105 ResolveFilePath( GUIScriptsPath
);
2106 } else if (stricmp( name
, "PluginsPath" ) == 0) {
2107 strncpy( PluginsPath
, value
, sizeof(PluginsPath
) );
2108 ResolveFilePath( PluginsPath
);
2109 } else if (stricmp( name
, "GamePath" ) == 0) {
2110 strncpy( GamePath
, value
, sizeof(GamePath
) );
2111 ResolveFilePath( GamePath
);
2112 } else if (stricmp( name
, "SavePath" ) == 0) {
2113 strncpy( SavePath
, value
, sizeof(SavePath
) );
2114 ResolveFilePath( SavePath
);
2115 } else if (strnicmp( name
, "CD", 2 ) == 0 &&
2116 name
[2] >= '1' && name
[2] <= '5' && name
[3] == 0) {
2117 strncpy( CD
[name
[2]-'1'], value
, sizeof(CD
[name
[2]-'1']) );
2118 ResolveFilePath( CD
[name
[2]-'1'] );
2125 strcpy( GameType
, "gemrb" );
2129 if (!GemRBPath
[0]) {
2130 strcpy( GemRBPath
, DATADIR
);
2134 if (!GemRBOverridePath
[0]) {
2135 strcpy( GemRBOverridePath
, GemRBPath
);
2138 if (!PluginsPath
[0]) {
2140 strcpy( PluginsPath
, PLUGINDIR
);
2142 PathJoin( PluginsPath
, GemRBPath
, "plugins", NULL
);
2146 if (!GUIScriptsPath
[0]) {
2147 strcpy( GUIScriptsPath
, GemRBPath
);
2151 strcpy( GameName
, GEMRB_STRING
);
2155 // FIXME: maybe should use UserDir instead of GamePath
2156 strcpy( SavePath
, GamePath
);
2159 if (! CachePath
[0]) {
2160 PathJoin( CachePath
, UserDir
, "Cache", NULL
);
2164 FixPath( GUIScriptsPath
, true );
2165 FixPath( PluginsPath
, true );
2166 FixPath( GemRBPath
, true );
2167 FixPath( GemRBOverridePath
, true );
2170 FixPath( GamePath
, true );
2173 //FixPath( SavePath, false );
2174 //mkdir( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2175 //chmod( SavePath, S_IREAD|S_IWRITE|S_IEXEC );
2176 FixPath( SavePath
, true );
2178 FixPath( CachePath
, false );
2179 mkdir( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2180 chmod( CachePath
, S_IREAD
|S_IWRITE
|S_IEXEC
);
2182 printStatus( "OK", LIGHT_GREEN
);
2183 if ( StupidityDetector( CachePath
)) {
2184 printMessage("Core"," ",LIGHT_RED
);
2185 printf( "Cache path %s doesn't exist, not a folder or contains alien files!\n", CachePath
);
2188 if (!KeepCache
) DelTree((const char *) CachePath
, false);
2189 FixPath( CachePath
, true );
2194 static void upperlower(int upper
, int lower
)
2196 pl_uppercase
[lower
]=(ieByte
) upper
;
2197 pl_lowercase
[upper
]=(ieByte
) lower
;
2200 static const char *game_flags
[GF_COUNT
+1]={
2201 "HasKaputz", //0 GF_HAS_KAPUTZ
2202 "AllStringsTagged", //1 GF_ALL_STRINGS_TAGGED
2203 "HasSongList", //2 GF_HAS_SONGLIST
2204 "TeamMovement", //3 GF_TEAM_MOVEMENT
2205 "UpperButtonText", //4 GF_UPPER_BUTTON_TEXT
2206 "LowerLabelText", //5 GF_LOWER_LABEL_TEXT
2207 "HasPartyIni", //6 GF_HAS_PARTY_INI
2208 "SoundFolders", //7 GF_SOUNDFOLDERS
2209 "IgnoreButtonFrames", //8 GF_IGNORE_BUTTON_FRAMES
2210 "OneByteAnimationID", //9 GF_ONE_BYTE_ANIMID
2211 "HasDPLAYER", //10GF_HAS_DPLAYER
2212 "HasEXPTABLE", //11GF_HAS_EXPTABLE
2213 "HasBeastsIni", //12GF_HAS_BEASTS_INI
2214 "HasDescIcon", //13GF_HAS_DESC_ICON
2215 "HasPickSound", //14GF_HAS_PICK_SOUND
2216 "IWDMapDimensions", //15GF_IWD_MAP_DIMENSIONS
2217 "AutomapIni", //16GF_AUTOMAP_INI
2218 "SmallFog", //17GF_SMALL_FOG
2219 "ReverseDoor", //18GF_REVERSE_DOOR
2220 "ProtagonistTalks", //19GF_PROTAGONIST_TALKS
2221 "HasSpellList", //20GF_HAS_SPELLLIST
2222 "IWD2ScriptName", //21GF_IWD2_SCRIPTNAME
2223 "DialogueScrolls", //22GF_DIALOGUE_SCROLLS
2224 "KnowWorld", //23GF_KNOW_WORLD
2225 "ReverseToHit", //24GF_REVERSE_TOHIT
2226 "SaveForHalfDamage", //25GF_SAVE_FOR_HALF
2227 "CharNameIsGabber", //26GF_CHARNAMEISGABBER
2228 "MagicBit", //27GF_MAGICBIT
2229 "CheckAbilities", //28GF_CHECK_ABILITIES
2230 "ChallengeRating", //29GF_CHALLENGERATING
2231 "SpellBookIconHack", //30GF_SPELLBOOKICONHACK
2232 "EnhancedEffects", //31GF_ENHANCED_EFFECTS
2233 "DeathOnZeroStat", //32GF_DEATH_ON_ZERO_STAT
2234 "SpawnIni", //33GF_SPAWN_INI
2235 "IWD2DeathVarFormat", //34GF_IWD2_DEATHVARFORMAT
2236 "HasResDataIni", //35GF_RESDATA_INI
2237 "OverrideCursorPos", //36GF_OVERRIDE_CURSORPOS
2238 "BreakableWeapons", //37GF_BREAKABLE_WEAPONS
2239 "3EdRules", //38GF_3ED_RULES
2240 "LevelslotPerClass", //39GF_LEVELSLOT_PER_CLASS
2241 "SelectiveMagicRes", //40GF_SELECTIVE_MAGIC_RES
2242 "HasHideInShadows", //41GF_HAS_HIDE_IN_SHADOWS
2243 "AreaVisitedVar", //42GF_AREA_VISITED_VAR
2244 "ProperBackstab", //43GF_PROPER_BACKSTAB
2245 "OnScreenText", //44GF_ONSCREEN_TEXT
2246 NULL
//for our own safety, this marks the end of the pole
2249 /** Loads gemrb.ini */
2250 bool Interface::LoadGemRBINI()
2252 DataStream
* inifile
= gamedata
->GetResource( "gemrb", IE_INI_CLASS_ID
);
2254 printStatus( "ERROR", LIGHT_RED
);
2258 printMessage( "Core", "Loading game type-specific GemRB setup...\n", WHITE
);
2259 printf( "%s",inifile
->originalfile
);
2261 if (!IsAvailable( IE_INI_CLASS_ID
)) {
2262 printStatus( "ERROR", LIGHT_RED
);
2263 printf( "[Core]: No INI Importer Available.\n" );
2266 DataFileMgr
* ini
= ( DataFileMgr
* ) GetInterface( IE_INI_CLASS_ID
);
2267 ini
->Open( inifile
, true ); //autofree
2269 printStatus( "OK", LIGHT_GREEN
);
2273 // Resrefs are already initialized in Interface::Interface()
2274 s
= ini
->GetKeyAsString( "resources", "CursorBAM", NULL
);
2276 strnlwrcpy( CursorBam
, s
, 8 ); //console cursor
2278 s
= ini
->GetKeyAsString( "resources", "ScrollCursorBAM", NULL
);
2280 strnlwrcpy( ScrollCursorBam
, s
, 8 );
2282 s
= ini
->GetKeyAsString( "resources", "ButtonFont", NULL
);
2284 strnlwrcpy( ButtonFont
, s
, 8 );
2286 s
= ini
->GetKeyAsString( "resources", "TooltipFont", NULL
);
2288 strnlwrcpy( TooltipFont
, s
, 8 );
2290 s
= ini
->GetKeyAsString( "resources", "MovieFont", NULL
);
2292 strnlwrcpy( MovieFont
, s
, 8 );
2294 s
= ini
->GetKeyAsString( "resources", "TooltipBack", NULL
);
2296 strnlwrcpy( TooltipBackResRef
, s
, 8 );
2298 s
= ini
->GetKeyAsString( "resources", "TooltipColor", NULL
);
2301 unsigned long c
= strtoul (s
+ 1, NULL
, 16);
2302 // FIXME: check errno
2303 TooltipColor
.r
= (unsigned char) (c
>> 24);
2304 TooltipColor
.g
= (unsigned char) (c
>> 16);
2305 TooltipColor
.b
= (unsigned char) (c
>> 8);
2306 TooltipColor
.a
= (unsigned char) (c
);
2310 //which stat determines the fist weapon (defaults to class)
2311 Actor::SetFistStat(ini
->GetKeyAsInt( "resources", "FistStat", IE_CLASS
));
2313 TooltipMargin
= ini
->GetKeyAsInt( "resources", "TooltipMargin", TooltipMargin
);
2315 // The format of GroundCircle can be:
2316 // GroundCircleBAM1 = wmpickl/3
2317 // to denote that the bitmap should be scaled down 3x
2318 for (int size
= 0; size
< MAX_CIRCLE_SIZE
; size
++) {
2320 sprintf( name
, "GroundCircleBAM%d", size
+1 );
2321 s
= ini
->GetKeyAsString( "resources", name
, NULL
);
2323 const char *pos
= strchr( s
, '/' );
2325 GroundCircleScale
[size
] = atoi( pos
+1 );
2326 strncpy( GroundCircleBam
[size
], s
, pos
- s
);
2327 GroundCircleBam
[size
][pos
- s
] = '\0';
2329 strcpy( GroundCircleBam
[size
], s
);
2334 s
= ini
->GetKeyAsString( "resources", "INIConfig", NULL
);
2336 strcpy( INIConfig
, s
);
2338 s
= ini
->GetKeyAsString( "resources", "Palette16", NULL
);
2340 strcpy( Palette16
, s
);
2342 s
= ini
->GetKeyAsString( "resources", "Palette32", NULL
);
2344 strcpy( Palette32
, s
);
2346 s
= ini
->GetKeyAsString( "resources", "Palette256", NULL
);
2348 strcpy( Palette256
, s
);
2350 unsigned int i
= (unsigned int) ini
->GetKeyAsInt ("charset", "CharCount", 0);
2354 snprintf(key
,9,"Letter%d", i
+1);
2355 s
= ini
->GetKeyAsString( "charset", key
, NULL
);
2357 const char *s2
= strchr(s
,',');
2359 upperlower(atoi(s
), atoi(s2
+1) );
2364 MaximumAbility
= ini
->GetKeyAsInt ("resources", "MaximumAbility", 25 );
2366 RedrawTile
= ini
->GetKeyAsInt( "resources", "RedrawTile", 0 )!=0;
2368 for (i
=0;i
<GF_COUNT
;i
++) {
2369 if (!game_flags
[i
]) {
2370 printf("Fix the game flags!\n");
2373 SetFeature( ini
->GetKeyAsInt( "resources", game_flags
[i
], 0 ), i
);
2374 printMessage("Option", "", GREEN
);
2375 printf("%s = %s\n", game_flags
[i
], HasFeature(i
)?"yes":"no");
2378 ForceStereo
= ini
->GetKeyAsInt( "resources", "ForceStereo", 0 );
2380 FreeInterface( ini
);
2384 Palette
* Interface::CreatePalette(const Color
&color
, const Color
&back
)
2386 Palette
* pal
= new Palette();
2388 pal
->col
[0].g
= 0xff;
2391 for (int i
= 1; i
< 256; i
++) {
2392 pal
->col
[i
].r
= back
.r
+
2393 ( unsigned char ) ( ( ( color
.r
- back
.r
) * ( i
) ) / 255.0 );
2394 pal
->col
[i
].g
= back
.g
+
2395 ( unsigned char ) ( ( ( color
.g
- back
.g
) * ( i
) ) / 255.0 );
2396 pal
->col
[i
].b
= back
.b
+
2397 ( unsigned char ) ( ( ( color
.b
- back
.b
) * ( i
) ) / 255.0 );
2398 pal
->col
[i
].a
= back
.a
+
2399 ( unsigned char ) ( ( ( color
.a
- back
.a
) * ( i
) ) / 255.0 );
2404 /** No descriptions */
2405 Color
* Interface::GetPalette(unsigned index
, int colors
, Color
*pal
) const
2410 } else if (colors
<= 32) {
2412 } else if (colors
== 256) {
2417 if (index
>= img
->GetHeight()) {
2420 for (int i
= 0; i
< colors
; i
++) {
2421 pal
[i
] = img
->GetPixel(i
, index
);
2425 /** Returns a preloaded Font */
2426 Font
* Interface::GetFont(const char *ResRef
) const
2428 for (unsigned int i
= 0; i
< fonts
.size(); i
++) {
2429 if (strnicmp( fonts
[i
]->ResRef
, ResRef
, 8 ) == 0) {
2436 Font
* Interface::GetFont(unsigned int index
) const
2438 if (index
>= fonts
.size()) {
2441 return fonts
[index
];
2444 Font
* Interface::GetButtonFont() const
2446 return GetFont( ButtonFont
);
2449 /** Returns the Event Manager */
2450 EventMgr
* Interface::GetEventMgr() const
2455 /** Returns the Window Manager */
2456 WindowMgr
* Interface::GetWindowMgr() const
2461 /** Get GUI Script Manager */
2462 ScriptEngine
* Interface::GetGUIScriptEngine() const
2467 //NOTE: if there were more summoned creatures, it will return only the last
2468 Actor
*Interface::SummonCreature(const ieResRef resource
, const ieResRef vvcres
, Scriptable
*Owner
, Actor
*target
, Point
&position
, int eamod
, int level
, Effect
*fx
)
2470 //maximum number of monsters summoned
2475 //decrease the number of summoned creatures with the number of already summoned creatures here
2476 //the summoned creatures have a special IE_SPECIFIC
2479 ab
= gamedata
->GetCreature(resource
);
2484 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2485 ab
->LastSummoner
= ((Actor
*) Owner
)->GetID();
2487 //Always use Base stats for the recently summoned creature
2491 if (eamod
==EAM_SOURCEALLY
|| eamod
==EAM_SOURCEENEMY
) {
2492 if (Owner
&& Owner
->Type
==ST_ACTOR
) {
2493 enemyally
= ((Actor
*) Owner
)->GetStat(IE_EA
)>EA_GOODCUTOFF
;
2499 enemyally
= target
->GetBase(IE_EA
)>EA_GOODCUTOFF
;
2506 case EAM_SOURCEALLY
:
2509 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2511 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2514 case EAM_SOURCEENEMY
:
2517 ab
->SetBase(IE_EA
, EA_CONTROLLED
); //is this the summoned EA?
2519 ab
->SetBase(IE_EA
, EA_ENEMY
); //is this the summoned EA?
2523 ab
->SetBase(IE_EA
, EA_NEUTRAL
);
2531 map
= target
->GetCurrentArea();
2533 map
= Owner
->GetCurrentArea();
2536 ab
->SetPosition(position
, true, 0);
2537 ab
->RefreshEffects(NULL
);
2540 ScriptedAnimation
* vvc
= gamedata
->GetScriptedAnimation(vvcres
, false);
2542 //This is the final position of the summoned creature
2543 //not the original target point
2544 vvc
->XPos
=ab
->Pos
.x
;
2545 vvc
->YPos
=ab
->Pos
.y
;
2546 //force vvc to play only once
2548 map
->AddVVCell( vvc
);
2552 //remove the xp value of friendly summons
2553 if (ab
->BaseStats
[IE_EA
]<EA_GOODCUTOFF
) {
2554 ab
->SetBase(IE_XPVALUE
, 0);
2557 ApplyEffect(fx
, ab
, Owner
);
2560 //this check should happen after the fact
2561 level
-= ab
->GetBase(IE_XP
);
2570 void Interface::RedrawControls(const char *varname
, unsigned int value
)
2572 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2573 Window
*win
= windows
[i
];
2574 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2575 win
->RedrawControls(varname
, value
);
2580 void Interface::RedrawAll()
2582 for (unsigned int i
= 0; i
< windows
.size(); i
++) {
2583 Window
*win
= windows
[i
];
2584 if (win
!= NULL
&& win
->Visible
!=WINDOW_INVALID
) {
2590 /** Loads a WindowPack (CHUI file) in the Window Manager */
2591 bool Interface::LoadWindowPack(const char* name
)
2593 DataStream
* stream
= gamedata
->GetResource( name
, IE_CHU_CLASS_ID
);
2594 if (stream
== NULL
) {
2595 printMessage( "Interface", "Error: Cannot find ", LIGHT_RED
);
2596 printf( "%s.chu\n", name
);
2599 if (!GetWindowMgr()->Open( stream
, true )) {
2600 printMessage( "Interface", "Error: Cannot Load ", LIGHT_RED
);
2601 printf( "%s.chu\n", name
);
2605 strncpy( WindowPack
, name
, sizeof( WindowPack
) );
2606 WindowPack
[sizeof( WindowPack
) - 1] = '\0';
2611 /** Loads a Window in the Window Manager */
2612 int Interface::LoadWindow(unsigned short WindowID
)
2616 for (i
= 0; i
< windows
.size(); i
++) {
2617 Window
*win
= windows
[i
];
2620 if (win
->Visible
==WINDOW_INVALID
) {
2623 if (win
->WindowID
== WindowID
&&
2624 !strnicmp( WindowPack
, win
->WindowPack
, sizeof(WindowPack
) )) {
2630 Window
* win
= windowmgr
->GetWindow( WindowID
);
2634 memcpy( win
->WindowPack
, WindowPack
, sizeof(WindowPack
) );
2637 for (i
= 0; i
< windows
.size(); i
++) {
2638 if (windows
[i
] == NULL
) {
2644 windows
.push_back( win
);
2645 slot
= ( int ) windows
.size() - 1;
2647 windows
[slot
] = win
;
2652 // FIXME: it's a clone of LoadWindow
2653 /** Creates a Window in the Window Manager */
2654 int Interface::CreateWindow(unsigned short WindowID
, int XPos
, int YPos
, unsigned int Width
, unsigned int Height
, char* Background
)
2658 for (i
= 0; i
< windows
.size(); i
++) {
2659 if (windows
[i
] == NULL
)
2661 if (windows
[i
]->WindowID
== WindowID
&& !stricmp( WindowPack
,
2662 windows
[i
]->WindowPack
)) {
2664 windows
[i
]->Invalidate();
2669 Window
* win
= new Window( WindowID
, (ieWord
) XPos
, (ieWord
) YPos
, (ieWord
) Width
, (ieWord
) Height
);
2670 if (Background
[0]) {
2671 if (IsAvailable( IE_MOS_CLASS_ID
)) {
2672 ImageMgr
* mos
= ( ImageMgr
* )
2673 gamedata
->GetResource( Background
, &ImageMgr::ID
);
2675 win
->SetBackGround( mos
->GetSprite2D(), true );
2676 FreeInterface( mos
);
2678 printf( "[Core]: Cannot Load BackGround, skipping\n" );
2680 printf( "[Core]: No MOS Importer Available, skipping background\n" );
2683 strcpy( win
->WindowPack
, WindowPack
);
2686 for (i
= 0; i
< windows
.size(); i
++) {
2687 if (windows
[i
] == NULL
) {
2693 windows
.push_back( win
);
2694 slot
= ( int ) windows
.size() - 1;
2696 windows
[slot
] = win
;
2702 /** Sets a Window on the Top */
2703 void Interface::SetOnTop(int Index
)
2705 std::vector
<int>::iterator t
;
2706 for(t
= topwin
.begin(); t
!= topwin
.end(); ++t
) {
2712 if(topwin
.size() != 0)
2713 topwin
.insert(topwin
.begin(), Index
);
2715 topwin
.push_back(Index
);
2717 /** Add a window to the Window List */
2718 void Interface::AddWindow(Window
* win
)
2721 for(unsigned int i
= 0; i
< windows
.size(); i
++) {
2722 Window
*w
= windows
[i
];
2730 windows
.push_back(win
);
2731 slot
=(int)windows
.size()-1;
2734 windows
[slot
] = win
;
2738 /** Get a Control on a Window */
2739 int Interface::GetControl(unsigned short WindowIndex
, unsigned long ControlID
) const
2741 if (WindowIndex
>= windows
.size()) {
2744 Window
* win
= windows
[WindowIndex
];
2750 Control
* ctrl
= win
->GetControl( (unsigned short) i
);
2753 if (ctrl
->ControlID
== ControlID
)
2758 /** Adjust the Scrolling factor of a control (worldmap atm) */
2759 int Interface::AdjustScrolling(unsigned short WindowIndex
,
2760 unsigned short ControlIndex
, short x
, short y
)
2762 if (WindowIndex
>= windows
.size()) {
2765 Window
* win
= windows
[WindowIndex
];
2769 Control
* ctrl
= win
->GetControl( ControlIndex
);
2773 switch(ctrl
->ControlType
) {
2774 case IE_GUI_WORLDMAP
:
2775 ((WorldMapControl
*) ctrl
)->AdjustScrolling(x
,y
);
2777 default: //doesn't work for these
2783 /** Set the Text of a Control */
2784 int Interface::SetText(unsigned short WindowIndex
,
2785 unsigned short ControlIndex
, const char* string
)
2787 if (WindowIndex
>= windows
.size()) {
2790 Window
* win
= windows
[WindowIndex
];
2794 Control
* ctrl
= win
->GetControl( ControlIndex
);
2798 return ctrl
->SetText( string
);
2800 /** Set the Tooltip text of a Control */
2801 int Interface::SetTooltip(unsigned short WindowIndex
,
2802 unsigned short ControlIndex
, const char* string
)
2804 if (WindowIndex
>= windows
.size()) {
2807 Window
* win
= windows
[WindowIndex
];
2811 Control
* ctrl
= win
->GetControl( ControlIndex
);
2815 return ctrl
->SetTooltip( string
);
2818 void Interface::DisplayTooltip(int x
, int y
, Control
*ctrl
)
2820 if (tooltip_ctrl
&& tooltip_ctrl
== ctrl
&& tooltip_x
== x
&& tooltip_y
== y
)
2824 tooltip_currtextw
= 0;
2825 tooltip_ctrl
= ctrl
;
2828 int Interface::GetVisible(unsigned short WindowIndex
) const
2830 if (WindowIndex
>= windows
.size()) {
2833 Window
* win
= windows
[WindowIndex
];
2837 return win
->Visible
;
2839 /** Set a Window Visible Flag */
2840 int Interface::SetVisible(unsigned short WindowIndex
, int visible
)
2842 if (WindowIndex
>= windows
.size()) {
2845 Window
* win
= windows
[WindowIndex
];
2849 if (visible
!=WINDOW_FRONT
) {
2850 win
->Visible
= (char) visible
;
2855 //here is a fallthrough
2856 case WINDOW_INVISIBLE
:
2857 //hiding the viewport if the gamecontrol window was made invisible
2858 if (win
->WindowID
==65535) {
2859 video
->SetViewport( 0,0,0,0 );
2861 evntmgr
->DelWindow( win
);
2864 case WINDOW_VISIBLE
:
2865 if (win
->WindowID
==65535) {
2866 video
->SetViewport( win
->XPos
, win
->YPos
, win
->Width
, win
->Height
);
2868 //here is a fallthrough
2870 if (win
->Visible
==WINDOW_VISIBLE
) {
2871 evntmgr
->AddWindow( win
);
2874 SetOnTop( WindowIndex
);
2881 /** Set the Status of a Control in a Window */
2882 int Interface::SetControlStatus(unsigned short WindowIndex
,
2883 unsigned short ControlIndex
, unsigned long Status
)
2885 //don't set the status of an already invalidated window
2886 Window
* win
= GetWindow(WindowIndex
);
2890 Control
* ctrl
= win
->GetControl( ControlIndex
);
2894 if (Status
&IE_GUI_CONTROL_FOCUSED
) {
2895 evntmgr
->SetFocused( win
, ctrl
);
2897 if (ctrl
->ControlType
!= ((Status
>> 24) & 0xff) ) {
2900 switch (ctrl
->ControlType
) {
2904 Button
* btn
= ( Button
* ) ctrl
;
2905 btn
->SetState( ( unsigned char ) ( Status
& 0x7f ) );
2909 ctrl
->Value
= Status
& 0x7f;
2915 /** Show a Window in Modal Mode */
2916 int Interface::ShowModal(unsigned short WindowIndex
, int Shadow
)
2918 if (WindowIndex
>= windows
.size()) {
2919 printMessage( "Core", "Window not found", LIGHT_RED
);
2922 Window
* win
= windows
[WindowIndex
];
2924 printMessage( "Core", "Window already freed", LIGHT_RED
);
2927 win
->Visible
= WINDOW_FRONT
;
2928 //don't destroy the other window handlers
2930 SetOnTop( WindowIndex
);
2931 evntmgr
->AddWindow( win
);
2932 evntmgr
->SetFocused( win
, NULL
);
2945 Region
r( 0, 0, Width
, Height
);
2947 if (Shadow
== MODAL_SHADOW_GRAY
) {
2948 video
->DrawRect( r
, gray
);
2949 } else if (Shadow
== MODAL_SHADOW_BLACK
) {
2950 video
->DrawRect( r
, black
);
2957 bool Interface::IsFreezed()
2959 return !update_scripts
;
2962 void Interface::GameLoop(void)
2964 update_scripts
= false;
2965 GameControl
*gc
= GetGameControl();
2967 update_scripts
= !(gc
->GetDialogueFlags() & DF_FREEZE_SCRIPTS
);
2970 GSUpdate(update_scripts
);
2972 //i'm not sure if this should be here
2974 //in multi player (if we ever get to it), only the server must call this
2975 if (update_scripts
) {
2976 if ( game
->selected
.size() > 0 ) {
2977 gc
->ChangeMap(core
->GetFirstSelectedPC(true), false);
2979 // the game object will run the area scripts as well
2980 game
->UpdateScripts();
2984 /** handles hardcoded gui behaviour */
2985 void Interface::HandleGUIBehaviour(void)
2987 GameControl
*gc
= GetGameControl();
2989 //this variable is used all over in the following hacks
2990 int flg
= gc
->GetDialogueFlags();
2992 //the following part is a series of hardcoded gui behaviour
2995 if (flg
& DF_IN_DIALOG
) {
3000 ieDword var
= (ieDword
) -3;
3001 vars
->Lookup("DialogChoose", var
);
3002 if ((int) var
== -2) {
3004 } else if ( (int)var
!=-3) {
3005 gc
->DialogChoose(var
);
3006 if (!(gc
->GetDialogueFlags() & (DF_OPENCONTINUEWINDOW
| DF_OPENENDWINDOW
)))
3007 guiscript
->RunFunction( "NextDialogState" );
3009 // the last node of a dialog can have a new-dialog action! don't interfere in that case
3010 ieDword newvar
= 0; vars
->Lookup("DialogChoose", newvar
);
3011 if (var
== (ieDword
) -1 || newvar
!= (ieDword
) -1) {
3012 vars
->SetAt("DialogChoose", (ieDword
) -3);
3015 if (flg
& DF_OPENCONTINUEWINDOW
) {
3016 guiscript
->RunFunction( "OpenContinueMessageWindow" );
3017 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3018 } else if (flg
& DF_OPENENDWINDOW
) {
3019 guiscript
->RunFunction( "OpenEndMessageWindow" );
3020 gc
->SetDialogueFlags(DF_OPENCONTINUEWINDOW
|DF_OPENENDWINDOW
, BM_NAND
);
3024 //handling container
3025 if (CurrentContainer
&& UseContainer
) {
3026 if (!(flg
& DF_IN_CONTAINER
) ) {
3027 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_OR
);
3028 guiscript
->RunFunction( "OpenContainerWindow" );
3031 if (flg
& DF_IN_CONTAINER
) {
3032 gc
->SetDialogueFlags(DF_IN_CONTAINER
, BM_NAND
);
3033 guiscript
->RunFunction( "CloseContainerWindow" );
3040 void Interface::DrawWindows(void)
3042 //here comes the REAL drawing of windows
3044 ModalWindow
->DrawWindow();
3047 size_t i
= topwin
.size();
3049 unsigned int t
= topwin
[i
];
3051 if ( t
>=windows
.size() )
3054 //visible ==1 or 2 will be drawn
3055 Window
* win
= windows
[t
];
3057 if (win
->Visible
== WINDOW_INVALID
) {
3058 topwin
.erase(topwin
.begin()+i
);
3059 evntmgr
->DelWindow( win
);
3062 } else if (win
->Visible
) {
3069 void Interface::DrawTooltip ()
3071 if (! tooltip_ctrl
|| !tooltip_ctrl
->Tooltip
)
3074 Font
* fnt
= GetFont( TooltipFont
);
3075 char *tooltip_text
= tooltip_ctrl
->Tooltip
;
3079 int strw
= fnt
->CalcStringWidth( tooltip_text
) + 8;
3081 int h
= fnt
->maxHeight
;
3084 // animate BG tooltips
3085 // TODO: make tooltip animation an option instead
3086 // of following hard-coded check!
3087 if (TooltipMargin
== 5) {
3088 // TODO: make speed an option
3089 int tooltip_anim_speed
= 15;
3090 if (tooltip_currtextw
< strw
) {
3091 tooltip_currtextw
+= tooltip_anim_speed
;
3093 if (tooltip_currtextw
> strw
) {
3094 tooltip_currtextw
= strw
;
3096 w
= tooltip_currtextw
;
3099 h
= TooltipBack
[0]->Height
;
3100 w1
= TooltipBack
[1]->Width
;
3101 w2
= TooltipBack
[2]->Width
;
3102 w
+= TooltipMargin
*2;
3103 strw
+= TooltipMargin
*2;
3104 //multiline in case of too much text
3105 if (w
>TooltipBack
[0]->Width
)
3106 strw
=w
=TooltipBack
[0]->Width
;
3107 else if (strw
>TooltipBack
[0]->Width
)
3108 strw
=TooltipBack
[0]->Width
;
3111 int strx
= tooltip_x
- strw
/ 2;
3112 int y
= tooltip_y
- h
/ 2;
3113 // Ensure placement within the screen
3114 if (strx
< 0) strx
= 0;
3115 else if (strx
+ strw
+ w1
+ w2
> Width
)
3116 strx
= Width
- strw
- w1
- w2
;
3118 else if (y
+ h
> Height
)
3121 int x
= strx
+ ((strw
- w
) / 2);
3123 // FIXME: take back[0] from center, not from left end
3124 Region r2
= Region( x
, y
, w
, h
);
3126 video
->BlitSprite( TooltipBack
[0], x
+ TooltipMargin
, y
, true, &r2
);
3127 video
->BlitSprite( TooltipBack
[1], x
, y
, true );
3128 video
->BlitSprite( TooltipBack
[2], x
+ w
, y
, true );
3132 r2
.x
+=TooltipMargin
;
3133 strx
+=TooltipMargin
;
3135 Region textr
= Region( strx
, y
, strw
, h
);
3136 fnt
->Print( r2
, textr
, (ieByte
*) tooltip_text
, NULL
,
3137 IE_FONT_ALIGN_CENTER
| IE_FONT_ALIGN_MIDDLE
, true );
3140 //interface for higher level functions, if the window was
3141 //marked for deletion it is not returned
3142 Window
* Interface::GetWindow(unsigned short WindowIndex
) const
3144 if (WindowIndex
< windows
.size()) {
3145 Window
*win
= windows
[WindowIndex
];
3146 if (win
&& (win
->Visible
!=WINDOW_INVALID
) ) {
3153 // this function will determine if wnd is a valid window pointer
3154 // by checking if its WindowID is the same as the reference
3155 bool Interface::IsValidWindow(unsigned short WindowID
, Window
*wnd
) const
3157 size_t WindowIndex
= windows
.size();
3158 while (WindowIndex
--) {
3159 if (windows
[WindowIndex
] == wnd
) {
3160 return wnd
->WindowID
== WindowID
;
3166 //this function won't delete the window, just mark it for deletion
3167 //it will be deleted in the next DrawWindows cycle
3168 //regardless, the window deleted is inaccessible for gui scripts and
3169 //other high level functions from now
3170 int Interface::DelWindow(unsigned short WindowIndex
)
3172 if (WindowIndex
>= windows
.size()) {
3175 Window
* win
= windows
[WindowIndex
];
3176 if ((win
== NULL
) || (win
->Visible
==WINDOW_INVALID
) ) {
3177 printMessage( "Core", "Window deleted again", LIGHT_RED
);
3180 if (win
== ModalWindow
) {
3182 RedrawAll(); //marking windows for redraw
3184 evntmgr
->DelWindow( win
);
3186 //re-capturing new (old) modal window if any
3187 size_t tw
= topwin
.size();
3188 for(size_t i
=0;i
<tw
;i
++) {
3189 Window
*tmp
= windows
[topwin
[i
]];
3190 if (tmp
->Visible
==WINDOW_FRONT
) {
3198 void Interface::DelAllWindows()
3200 vars
->SetAt("MessageWindow", (ieDword
) ~0);
3201 vars
->SetAt("OptionsWindow", (ieDword
) ~0);
3202 vars
->SetAt("PortraitWindow", (ieDword
) ~0);
3203 vars
->SetAt("ActionsWindow", (ieDword
) ~0);
3204 vars
->SetAt("TopWindow", (ieDword
) ~0);
3205 vars
->SetAt("OtherWindow", (ieDword
) ~0);
3206 vars
->SetAt("FloatWindow", (ieDword
) ~0);
3207 for(unsigned int WindowIndex
=0; WindowIndex
<windows
.size();WindowIndex
++) {
3208 Window
* win
= windows
[WindowIndex
];
3217 /** Popup the Console */
3218 void Interface::PopupConsole()
3220 ConsolePopped
= !ConsolePopped
;
3222 console
->Changed
= true;
3225 /** Draws the Console */
3226 void Interface::DrawConsole()
3228 console
->Draw( 0, 0 );
3231 /** Get the Sound Manager */
3232 SaveGameIterator
* Interface::GetSaveGameIterator() const
3236 /** Sends a termination signal to the Video Driver */
3237 bool Interface::Quit(void)
3239 return video
->Quit();
3241 /** Returns the variables dictionary */
3242 Variables
* Interface::GetDictionary() const
3246 /** Returns the token dictionary */
3247 Variables
* Interface::GetTokenDictionary() const
3251 /** Get the Music Manager */
3252 MusicMgr
* Interface::GetMusicMgr() const
3256 /** Loads an IDS Table, returns -1 on error or the Symbol Table Index on success */
3257 int Interface::LoadSymbol(const char* ResRef
)
3259 int ind
= GetSymbolIndex( ResRef
);
3263 DataStream
* str
= gamedata
->GetResource( ResRef
, IE_IDS_CLASS_ID
);
3267 SymbolMgr
* sm
= ( SymbolMgr
* ) GetInterface( IE_IDS_CLASS_ID
);
3272 if (!sm
->Open( str
, true )) {
3273 FreeInterface( sm
);
3278 strncpy( s
.ResRef
, ResRef
, 8 );
3281 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3282 if (symbols
[i
].free
) {
3291 symbols
.push_back( s
);
3292 return ( int ) symbols
.size() - 1;
3294 /** Gets the index of a loaded Symbol Table, returns -1 on error */
3295 int Interface::GetSymbolIndex(const char* ResRef
) const
3297 for (size_t i
= 0; i
< symbols
.size(); i
++) {
3298 if (symbols
[i
].free
)
3300 if (strnicmp( symbols
[i
].ResRef
, ResRef
, 8 ) == 0)
3305 /** Gets a Loaded Symbol Table by its index, returns NULL on error */
3306 SymbolMgr
* Interface::GetSymbol(unsigned int index
) const
3308 if (index
>= symbols
.size()) {
3311 if (symbols
[index
].free
) {
3314 return symbols
[index
].sm
;
3316 /** Frees a Loaded Symbol Table, returns false on error, true on success */
3317 bool Interface::DelSymbol(unsigned int index
)
3319 if (index
>= symbols
.size()) {
3322 if (symbols
[index
].free
) {
3325 FreeInterface( symbols
[index
].sm
);
3326 symbols
[index
].free
= true;
3329 /** Plays a Movie */
3330 int Interface::PlayMovie(const char* ResRef
)
3332 MoviePlayer
* mp
= (MoviePlayer
*) gamedata
->GetResource( ResRef
, &MoviePlayer::ID
);
3334 FreeInterface( mp
);
3338 ieDword subtitles
= 0;
3339 Font
*SubtitleFont
= NULL
;
3340 Palette
*palette
= NULL
;
3341 ieDword
*frames
= NULL
;
3342 ieDword
*strrefs
= NULL
;
3346 //one of these two should exist (they both mean the same thing)
3347 vars
->Lookup("Display Movie Subtitles", subtitles
);
3354 vars
->Lookup("Display Subtitles", subtitles
);
3357 if (subtitles
&& sttable
.load(ResRef
)) {
3358 cnt
+= sttable
->GetRowCount();
3360 frames
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3361 strrefs
= (ieDword
*) malloc(cnt
* sizeof(ieDword
) );
3365 if (frames
&& strrefs
) {
3366 for (int i
=0;i
<cnt
;i
++) {
3367 frames
[i
] = atoi (sttable
->QueryField(i
+offset
, 0) );
3368 strrefs
[i
] = atoi (sttable
->QueryField(i
+offset
, 1) );
3371 int r
= atoi(sttable
->QueryField("red", "frame"));
3372 int g
= atoi(sttable
->QueryField("green", "frame"));
3373 int b
= atoi(sttable
->QueryField("blue", "frame"));
3374 SubtitleFont
= GetFont (MovieFont
); //will change
3377 Color fore
= {(unsigned char) r
,(unsigned char) g
,(unsigned char) b
, 0x00};
3378 Color back
= {0x00, 0x00, 0x00, 0x00};
3379 palette
= CreatePalette( fore
, back
);
3384 //shutting down music and ambients before movie
3387 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3388 if (ambim
) ambim
->deactivate();
3389 video
->SetMovieFont(SubtitleFont
, palette
);
3390 mp
->CallBackAtFrames(cnt
, frames
, strrefs
);
3392 FreeInterface( mp
);
3393 gamedata
->FreePalette( palette
);
3401 if (ambim
) ambim
->activate();
3402 //this will fix redraw all windows as they looked like
3406 //Setting the movie name to 1
3407 vars
->SetAt( ResRef
, 1 );
3411 int Interface::Roll(int dice
, int size
, int add
) const
3420 return add
+ dice
* size
/ 2;
3422 for (int i
= 0; i
< dice
; i
++) {
3423 add
+= rand() % size
+ 1;
3428 static char bmp_suffix
[6]="M.BMP";
3429 static char png_suffix
[6]="M.PNG";
3431 int Interface::GetPortraits(TextArea
* ta
, bool smallorlarge
)
3434 char Path
[_MAX_PATH
];
3443 PathJoin( Path
, GamePath
, GamePortraitsPath
, NULL
);
3444 ResolveFilePath( Path
);
3445 DIR* dir
= opendir( Path
);
3449 //Lookup the first entry in the Directory
3450 struct dirent
* de
= readdir( dir
);
3455 printf( "Looking in %s\n", Path
);
3457 if (de
->d_name
[0] == '.')
3459 char dtmp
[_MAX_PATH
];
3460 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3463 if ( S_ISDIR( fst
.st_mode
))
3466 char *pos
= strstr(de
->d_name
,bmp_suffix
);
3467 if (!pos
&& IsAvailable(IE_PNG_CLASS_ID
) ) {
3468 pos
= strstr(de
->d_name
,png_suffix
);
3473 ta
->AppendText( de
->d_name
, -1 );
3474 } while (( de
= readdir( dir
) ) != NULL
);
3479 int Interface::GetCharSounds(TextArea
* ta
)
3483 char Path
[_MAX_PATH
];
3485 PathJoin( Path
, GamePath
, GameSoundsPath
, NULL
);
3486 ResolveFilePath( Path
);
3487 hasfolders
= ( HasFeature( GF_SOUNDFOLDERS
) != 0 );
3488 DIR* dir
= opendir( Path
);
3492 //Lookup the first entry in the Directory
3493 struct dirent
* de
= readdir( dir
);
3498 printf( "Looking in %s\n", Path
);
3500 if (de
->d_name
[0] == '.')
3502 char dtmp
[_MAX_PATH
];
3503 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3506 if (hasfolders
== !S_ISDIR( fst
.st_mode
))
3510 char *pos
= strstr(de
->d_name
,"A.WAV");
3515 ta
->AppendText( de
->d_name
, -1 );
3516 } while (( de
= readdir( dir
) ) != NULL
);
3521 int Interface::GetCharacters(TextArea
* ta
)
3524 char Path
[_MAX_PATH
];
3526 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
3527 ResolveFilePath( Path
);
3528 DIR* dir
= opendir( Path
);
3532 //Lookup the first entry in the Directory
3533 struct dirent
* de
= readdir( dir
);
3538 printf( "Looking in %s\n", Path
);
3540 if (de
->d_name
[0] == '.')
3542 char dtmp
[_MAX_PATH
];
3543 PathJoin( dtmp
, Path
, de
->d_name
, NULL
);
3547 char *pos
= strstr(de
->d_name
,".CHR");
3551 ta
->AppendText( de
->d_name
, -1 );
3552 } while (( de
= readdir( dir
) ) != NULL
);
3557 bool Interface::LoadINI(const char* filename
)
3560 config
= fopen( filename
, "rb" );
3561 if (config
== NULL
) {
3564 char name
[65], value
[_MAX_PATH
+ 3];
3565 while (!feof( config
)) {
3570 if (fread( &rem
, 1, 1, config
) != 1)
3573 if (( rem
== '#' ) ||
3581 } else if (rem
== '\n')
3584 //it should always return zero
3585 if (fscanf( config
, "%*[^\r\n]%*[\r\n]" )!=0)
3589 fseek( config
, -1, SEEK_CUR
);
3590 //the * element is not counted
3591 if (fscanf( config
, "%[^=]=%[^\r\n]%*[\r\n]", name
, value
)!=2)
3593 if (( value
[0] >= '0' ) && ( value
[0] <= '9' )) {
3594 vars
->SetAt( name
, atoi( value
) );
3601 /** Enables/Disables the Cut Scene Mode */
3602 void Interface::SetCutSceneMode(bool active
)
3604 GameControl
*gc
= GetGameControl();
3606 gc
->SetCutSceneMode( active
);
3610 game
->ControlStatus
|= CS_HIDEGUI
;
3612 game
->ControlStatus
&= ~CS_HIDEGUI
;
3614 SetEventFlag(EF_CONTROL
);
3616 video
->SetMouseEnabled(!active
);
3619 bool Interface::InCutSceneMode() const
3621 return (GetGameControl()->GetScreenFlags()&SF_DISABLEMOUSE
)!=0;
3624 void Interface::QuitGame(int BackToMain
)
3626 SetCutSceneMode(false);
3629 //clear fade/screenshake effects
3631 timer
->SetFadeFromColor(0);
3634 DelAllWindows(); //delete all windows, including GameControl
3636 //shutting down ingame music
3637 //(do it before deleting the game)
3641 // stop any ambients which are still enqueued
3643 AmbientMgr
*ambim
= AudioDriver
->GetAmbientMgr();
3644 if (ambim
) ambim
->deactivate();
3646 //delete game, worldmap
3656 strcpy(NextScript
, "Start");
3657 QuitFlag
|= QF_CHANGESCRIPT
;
3662 void Interface::SetupLoadGame(int index
, int ver_override
)
3664 LoadGameIndex
= index
;
3665 VersionOverride
= ver_override
;
3666 QuitFlag
|= QF_LOADGAME
;
3669 void Interface::LoadGame(int index
, int ver_override
)
3671 // This function has rather painful error handling,
3672 // as it should swap all the objects or none at all
3673 // and the loading can fail for various reasons
3675 // Yes, it uses goto. Other ways seemed too awkward for me.
3677 strings
->CloseAux();
3678 tokens
->RemoveAll(NULL
); //clearing the token dictionary
3680 if(calendar
) delete calendar
;
3681 calendar
= new Calendar
;
3683 DataStream
* gam_str
= NULL
;
3684 DataStream
* sav_str
= NULL
;
3685 DataStream
* wmp_str
= NULL
;
3687 SaveGameMgr
* gam_mgr
= NULL
;
3688 WorldMapMgr
* wmp_mgr
= NULL
;
3690 Game
* new_game
= NULL
;
3691 WorldMapArray
* new_worldmap
= NULL
;
3694 if (!KeepCache
) DelTree((const char *) CachePath
, true);
3698 //Load the Default Game
3699 gam_str
= gamedata
->GetResource( GameNameResRef
, IE_GAM_CLASS_ID
);
3701 wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3703 SaveGame
* sg
= sgiterator
->GetSaveGame( index
);
3706 gam_str
= sg
->GetGame();
3707 sav_str
= sg
->GetSave();
3708 wmp_str
= sg
->GetWmap();
3712 if (!gam_str
|| !wmp_str
)
3716 gam_mgr
= ( SaveGameMgr
* ) GetInterface( IE_GAM_CLASS_ID
);
3720 if (!gam_mgr
->Open( gam_str
, true ))
3723 new_game
= gam_mgr
->LoadGame(new Game(), ver_override
);
3727 FreeInterface( gam_mgr
);
3731 // Load WMP (WorldMap) file
3732 wmp_mgr
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
3736 if (!wmp_mgr
->Open( wmp_str
, true ))
3739 new_worldmap
= wmp_mgr
->GetWorldMapArray( );
3741 FreeInterface( wmp_mgr
);
3746 // Unpack SAV (archive) file to Cache dir
3748 ArchiveImporter
* ai
= (ArchiveImporter
*)GetInterface(IE_BIF_CLASS_ID
);
3750 if (ai
->DecompressSaveGame(sav_str
) != GEM_OK
) {
3751 FreeInterface( ai
);
3754 FreeInterface( ai
);
3760 // Let's assume that now is everything loaded OK and swap the objects
3766 worldmap
= new_worldmap
;
3772 // Something went wrong, so try to clean after itself
3775 delete new_worldmap
;
3778 FreeInterface( gam_mgr
);
3782 FreeInterface( wmp_mgr
);
3791 /* swapping out old resources */
3792 void Interface::UpdateMasterScript()
3795 game
->SetScript( GlobalScript
, 0 );
3798 WorldMapMgr
* wmp_mgr
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
3803 DataStream
*wmp_str
= gamedata
->GetResource( WorldMapName
, IE_WMP_CLASS_ID
);
3805 if (!wmp_mgr
->Open( wmp_str
, true )) {
3811 worldmap
= wmp_mgr
->GetWorldMapArray();
3815 // Something went wrong, so try to clean after itself
3816 FreeInterface( wmp_mgr
);
3819 GameControl
*Interface::GetGameControl() const
3821 Window
*window
= GetWindow( 0 );
3822 // in the beginning, there's no window at all
3826 Control
* gc
= window
->GetControl(0);
3827 if (gc
->ControlType
!=IE_GUI_GAMECONTROL
) {
3830 return (GameControl
*) gc
;
3833 bool Interface::InitItemTypes()
3838 AutoTable
it("itemtype");
3841 ItemTypes
= it
->GetRowCount(); //number of itemtypes
3845 int InvSlotTypes
= it
->GetColumnCount();
3846 if (InvSlotTypes
> 32) { //bit count limit
3849 //make sure unsigned int is 32 bits
3850 slotmatrix
= (ieDword
*) malloc(ItemTypes
* sizeof(ieDword
) );
3851 for (int i
=0;i
<ItemTypes
;i
++) {
3852 unsigned int value
= 0;
3854 for (int j
=0;j
<InvSlotTypes
;j
++) {
3855 if (strtol(it
->QueryField(i
,j
),NULL
,0) ) {
3860 slotmatrix
[i
] = (ieDword
) value
;
3864 //slottype describes the inventory structure
3865 Inventory::Init(HasFeature(GF_MAGICBIT
));
3866 AutoTable
st("slottype");
3873 SlotTypes
= st
->GetRowCount();
3874 //make sure unsigned int is 32 bits
3875 slottypes
= (SlotType
*) malloc(SlotTypes
* sizeof(SlotType
) );
3876 memset(slottypes
, -1, SlotTypes
* sizeof(SlotType
) );
3877 for (unsigned int row
= 0; row
< SlotTypes
; row
++) {
3879 unsigned int i
= (ieDword
) strtol(st
->GetRowName(row
),NULL
,0 );
3880 if (i
>=SlotTypes
) continue;
3881 if (slottypes
[i
].sloteffects
!=0xffffffffu
) {
3882 slottypes
[row
].slot
= i
;
3886 slottypes
[row
].slot
= i
;
3889 slottypes
[i
].slottype
= (ieDword
) strtol(st
->QueryField(row
,0),NULL
,0 );
3890 slottypes
[i
].slotid
= (ieDword
) strtol(st
->QueryField(row
,1),NULL
,0 );
3891 strnlwrcpy( slottypes
[i
].slotresref
, st
->QueryField(row
,2), 8 );
3892 slottypes
[i
].slottip
= (ieDword
) strtol(st
->QueryField(row
,3),NULL
,0 );
3893 //don't fill sloteffects for aliased slots (pst)
3897 slottypes
[i
].sloteffects
= (ieDword
) strtol(st
->QueryField(row
,4),NULL
,0 );
3898 //setting special slots
3899 if (slottypes
[i
].slottype
&SLOT_ITEM
) {
3900 if (slottypes
[i
].slottype
&SLOT_INVENTORY
) {
3901 Inventory::SetInventorySlot(i
);
3903 Inventory::SetQuickSlot(i
);
3906 switch (slottypes
[i
].sloteffects
) {
3907 //fist slot, not saved, default weapon
3908 case SLOT_EFFECT_FIST
: Inventory::SetFistSlot(i
); break;
3909 //magic weapon slot, overrides all weapons
3910 case SLOT_EFFECT_MAGIC
: Inventory::SetMagicSlot(i
); break;
3911 //weapon slot, Equipping marker is relative to it
3912 case SLOT_EFFECT_MELEE
: Inventory::SetWeaponSlot(i
); break;
3914 case SLOT_EFFECT_MISSILE
: Inventory::SetRangedSlot(i
); break;
3916 case SLOT_EFFECT_LEFT
: Inventory::SetShieldSlot(i
); break;
3917 //head (for averting critical hit)
3918 case SLOT_EFFECT_HEAD
: Inventory::SetHeadSlot(i
); break;
3926 ieDword
Interface::FindSlot(unsigned int idx
) const
3930 for (i
=0;i
<SlotTypes
;i
++) {
3931 if (idx
==slottypes
[i
].slot
) {
3938 ieDword
Interface::QuerySlot(unsigned int idx
) const
3940 if (idx
>=SlotTypes
) {
3943 return slottypes
[idx
].slot
;
3946 ieDword
Interface::QuerySlotType(unsigned int idx
) const
3948 if (idx
>=SlotTypes
) {
3951 return slottypes
[idx
].slottype
;
3954 ieDword
Interface::QuerySlotID(unsigned int idx
) const
3956 if (idx
>=SlotTypes
) {
3959 return slottypes
[idx
].slotid
;
3962 ieDword
Interface::QuerySlottip(unsigned int idx
) const
3964 if (idx
>=SlotTypes
) {
3967 return slottypes
[idx
].slottip
;
3970 ieDword
Interface::QuerySlotEffects(unsigned int idx
) const
3972 if (idx
>=SlotTypes
) {
3975 return slottypes
[idx
].sloteffects
;
3978 const char *Interface::QuerySlotResRef(unsigned int idx
) const
3980 if (idx
>=SlotTypes
) {
3983 return slottypes
[idx
].slotresref
;
3986 // checks the itemtype vs. slottype, and also checks the usability flags
3987 // vs. Actor's stats (alignment, class, race, kit etc.)
3988 int Interface::CanUseItemType(int slottype
, Item
*item
, Actor
*actor
, bool feedback
) const
3990 //inventory is a special case, we allow any items to enter it
3991 if ( slottype
==SLOT_ALL
) {
3992 return SLOT_INVENTORY
;
3994 //if we look for ALL slot types, then SLOT_SHIELD shouldn't interfere
3995 //with twohandedness
3996 if ((slottype
&SLOT_SHIELD
) && (slottype
!=SLOT_ANY
) ) {
3997 //As long as this is an Item, use the ITEM constant
3998 //switch for IE_INV_ITEM_* if it is a CREItem
3999 if (item
->Flags
&IE_ITEM_TWO_HANDED
) {
4000 //cannot equip twohanded in offhand
4001 if (feedback
) DisplayConstantString(STR_NOT_IN_OFFHAND
, 0xf0f0f0);
4006 if ( (unsigned int) item
->ItemType
>=(unsigned int) ItemTypes
) {
4008 if (feedback
) DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4012 //if actor is supplied, check its usability fields
4014 ieStrRef str
= actor
->Unusable(item
);
4016 if (feedback
) DisplayConstantString(str
, 0xf0f0f0);
4021 //if any bit is true, the answer counts as true
4022 int ret
= (slotmatrix
[item
->ItemType
]&slottype
);
4023 if (slottype
== SLOT_INVENTORY
|| slottype
== SLOT_ANY
) {
4027 if (feedback
) DisplayConstantString(STR_WRONGITEMTYPE
, 0xf0f0f0);
4031 //this warning comes only when feedback is enabled
4033 if (slotmatrix
[item
->ItemType
]&(SLOT_QUIVER
|SLOT_WEAPON
|SLOT_ITEM
)) {
4035 if (slottype
&SLOT_QUIVER
) {
4036 if (item
->GetWeaponHeader(true)) ret
= 1;
4039 if (slottype
&SLOT_WEAPON
) {
4041 if (item
->GetWeaponHeader(false)) ret
= 1;
4043 if (item
->GetWeaponHeader(true)) ret
= 1;
4046 if (slottype
&SLOT_ITEM
) {
4047 if (item
->GetEquipmentHeaderNumber(0)!=0xffff) ret
= 1;
4051 DisplayConstantString(STR_UNUSABLEITEM
, 0xf0f0f0);
4060 Label
*Interface::GetMessageLabel() const
4062 ieDword WinIndex
= (ieDword
) -1;
4063 ieDword TAIndex
= (ieDword
) -1;
4065 vars
->Lookup( "OtherWindow", WinIndex
);
4066 if (( WinIndex
!= (ieDword
) -1 ) &&
4067 ( vars
->Lookup( "MessageLabel", TAIndex
) )) {
4068 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4070 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4071 if (ctrl
&& ctrl
->ControlType
==IE_GUI_LABEL
)
4072 return (Label
*) ctrl
;
4078 TextArea
*Interface::GetMessageTextArea() const
4080 ieDword WinIndex
= (ieDword
) -1;
4081 ieDword TAIndex
= (ieDword
) -1;
4083 vars
->Lookup( "MessageWindow", WinIndex
);
4084 if (( WinIndex
!= (ieDword
) -1 ) &&
4085 ( vars
->Lookup( "MessageTextArea", TAIndex
) )) {
4086 Window
* win
= GetWindow( (unsigned short) WinIndex
);
4088 Control
*ctrl
= win
->GetControl( (unsigned short) TAIndex
);
4089 if (ctrl
&& ctrl
->ControlType
==IE_GUI_TEXTAREA
)
4090 return (TextArea
*) ctrl
;
4096 void Interface::DisplayString(const char* Text
, Scriptable
*target
) const
4098 Label
*l
= GetMessageLabel();
4100 l
->SetText(Text
, 0);
4102 TextArea
*ta
= GetMessageTextArea();
4104 ta
->AppendText( Text
, -1 );
4107 char *tmp
= strdup(Text
);
4109 target
->DisplayHeadText(tmp
);
4115 static Color ActorColor
[PALSIZE
];
4116 static const char* DisplayFormatName
= "[color=%lX]%s - [/color][p][color=%lX]%s[/color][/p]";
4117 static const char* DisplayFormatAction
= "[color=%lX]%s - [/color][p][color=%lX]%s %s[/color][/p]";
4118 static const char* DisplayFormat
= "[/color][p][color=%lX]%s[/color][/p]";
4119 static const char* DisplayFormatValue
= "[/color][p][color=%lX]%s: %d[/color][/p]";
4120 static const char* DisplayFormatNameString
= "[color=%lX]%s - [/color][p][color=%lX]%s: %s[/color][/p]";
4122 ieStrRef
Interface::GetStringReference(int stridx
) const
4124 return strref_table
[stridx
];
4128 unsigned int Interface::GetSpeakerColor(const char *&name
, Scriptable
*&speaker
) const
4130 unsigned int speaker_color
;
4132 if(!speaker
) return 0;
4133 switch (speaker
->Type
) {
4135 name
= ((Actor
*) speaker
)->GetName(-1);
4136 GetPalette( ((Actor
*) speaker
)->GetStat(IE_MAJOR_COLOR
) & 0xFF, PALSIZE
, ActorColor
);
4137 speaker_color
= (ActorColor
[4].r
<<16) | (ActorColor
[4].g
<<8) | ActorColor
[4].b
;
4139 case ST_TRIGGER
: case ST_PROXIMITY
: case ST_TRAVEL
:
4140 name
= GetString( ((InfoPoint
*) speaker
)->DialogName
);
4141 speaker_color
= 0xc0c0c0;
4145 speaker_color
= 0x800000;
4148 return speaker_color
;
4152 //simply displaying a constant string
4153 void Interface::DisplayConstantString(int stridx
, unsigned int color
, Scriptable
*target
) const
4155 if (stridx
<0) return;
4156 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4157 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 12);
4158 char* newstr
= ( char* ) malloc( newlen
);
4159 snprintf( newstr
, newlen
, DisplayFormat
, color
, text
);
4161 DisplayString( newstr
, target
);
4165 void Interface::DisplayString(int stridx
, unsigned int color
, ieDword flags
) const
4167 if (stridx
<0) return;
4168 char* text
= GetString( stridx
, flags
);
4169 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 10);
4170 char* newstr
= ( char* ) malloc( newlen
);
4171 snprintf( newstr
, newlen
, DisplayFormat
, color
, text
);
4173 DisplayString( newstr
);
4179 void Interface::DisplayConstantStringValue(int stridx
, unsigned int color
, ieDword value
) const
4181 if (stridx
<0) return;
4182 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4183 int newlen
= (int)(strlen( DisplayFormat
) + strlen( text
) + 28);
4184 char* newstr
= ( char* ) malloc( newlen
);
4185 snprintf( newstr
, newlen
, DisplayFormatValue
, color
, text
, (int) value
);
4187 DisplayString( newstr
);
4192 // <charname> - blah blah : whatever
4193 void Interface::DisplayConstantStringNameString(int stridx
, unsigned int color
, int stridx2
, Scriptable
*actor
) const
4195 unsigned int actor_color
;
4198 if (stridx
<0) return;
4199 actor_color
= GetSpeakerColor(name
, actor
);
4200 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
);
4201 char* text2
= GetString( strref_table
[stridx2
], IE_STR_SOUND
);
4202 int newlen
= (int)(strlen( DisplayFormat
) + strlen(name
) + strlen( text
) + strlen(text2
) + 18);
4203 char* newstr
= ( char* ) malloc( newlen
);
4204 if (strlen(text2
)) {
4205 snprintf( newstr
, newlen
, DisplayFormatNameString
, actor_color
, name
, color
, text
, text2
);
4207 snprintf( newstr
, newlen
, DisplayFormatName
, color
, name
, color
, text
);
4210 FreeString( text2
);
4211 DisplayString( newstr
);
4216 // <charname> - blah blah
4217 void Interface::DisplayConstantStringName(int stridx
, unsigned int color
, Scriptable
*speaker
) const
4219 unsigned int speaker_color
;
4222 if (stridx
<0) return;
4223 if(!speaker
) return;
4224 speaker_color
= GetSpeakerColor(name
, speaker
);
4225 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
|IE_STR_SPEECH
);
4226 int newlen
= (int)(strlen( DisplayFormatName
) + strlen( name
) +
4227 + strlen( text
) + 18);
4228 char* newstr
= ( char* ) malloc( newlen
);
4229 snprintf( newstr
, newlen
, DisplayFormatName
, speaker_color
, name
, color
,
4232 DisplayString( newstr
);
4236 void Interface::DisplayConstantStringAction(int stridx
, unsigned int color
, Scriptable
*attacker
, Scriptable
*target
) const
4238 unsigned int attacker_color
;
4242 if (stridx
<0) return;
4244 GetSpeakerColor(name2
, target
);
4245 attacker_color
= GetSpeakerColor(name1
, attacker
);
4247 char* text
= GetString( strref_table
[stridx
], IE_STR_SOUND
|IE_STR_SPEECH
);
4248 int newlen
= (int)(strlen( DisplayFormatAction
) + strlen( name1
) +
4249 + strlen( name2
) + strlen( text
) + 18);
4250 char* newstr
= ( char* ) malloc( newlen
);
4251 snprintf( newstr
, newlen
, DisplayFormatAction
, attacker_color
, name1
, color
,
4254 DisplayString( newstr
);
4258 void Interface::DisplayStringName(int stridx
, unsigned int color
, Scriptable
*speaker
, ieDword flags
) const
4260 unsigned int speaker_color
;
4263 if (stridx
<0) return;
4264 speaker_color
= GetSpeakerColor(name
, speaker
);
4266 char* text
= GetString( stridx
, flags
);
4267 int newlen
= (int)(strlen( DisplayFormatName
) + strlen( name
) +
4268 + strlen( text
) + 10);
4269 char* newstr
= ( char* ) malloc( newlen
);
4270 snprintf( newstr
, newlen
, DisplayFormatName
, speaker_color
, name
, color
, text
);
4272 DisplayString( newstr
);
4276 static const char *saved_extensions
[]={".are",".sto",0};
4277 static const char *saved_extensions_last
[]={".tot",".toh",0};
4279 //returns the priority of the file to be saved
4283 int Interface::SavedExtension(const char *filename
)
4285 const char *str
=strchr(filename
,'.');
4288 while(saved_extensions
[i
]) {
4289 if (!stricmp(saved_extensions
[i
], str
) ) return 2;
4293 while(saved_extensions_last
[i
]) {
4294 if (!stricmp(saved_extensions_last
[i
], str
) ) return 1;
4300 static const char *protected_extensions
[]={".exe",".dll",".so",0};
4302 //returns true if file should be saved
4303 bool Interface::ProtectedExtension(const char *filename
)
4305 const char *str
=strchr(filename
,'.');
4306 if (!str
) return false;
4308 while(protected_extensions
[i
]) {
4309 if (!stricmp(protected_extensions
[i
], str
) ) return true;
4315 void Interface::RemoveFromCache(const ieResRef resref
, SClass_ID ClassID
)
4317 char filename
[_MAX_PATH
];
4319 snprintf(filename
, _MAX_PATH
, "%s%.8s%s", CachePath
, resref
, TypeExt( ClassID
) );
4323 //this function checks if the path is eligible as a cache
4324 //if it contains a directory, or suspicious file extensions
4325 //we bail out, because the cache will be purged regularly.
4326 bool Interface::StupidityDetector(const char* Pt
)
4328 char Path
[_MAX_PATH
];
4330 DIR* dir
= opendir( Path
);
4332 printf("\n**cannot open**\n");
4333 return true; //no directory?
4335 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
4338 printf("\n**cannot read**\n");
4339 return true; //cannot read it?
4342 char dtmp
[_MAX_PATH
];
4344 snprintf( dtmp
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, de
->d_name
);
4346 if (S_ISDIR( fst
.st_mode
)) {
4347 if (de
->d_name
[0] == '.')
4350 printf("\n**contains another dir**\n");
4351 return true; //a directory in there???
4353 if (ProtectedExtension(de
->d_name
) ) {
4355 printf("\n**contains alien files**\n");
4356 return true; //an executable file in there???
4358 } while (( de
= readdir( dir
) ) != NULL
);
4360 //ok, we got a good conscience
4364 void Interface::DelTree(const char* Pt
, bool onlysave
)
4366 char Path
[_MAX_PATH
];
4368 if (!Pt
[0]) return; //Don't delete the root filesystem :)
4370 DIR* dir
= opendir( Path
);
4374 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
4380 char dtmp
[_MAX_PATH
];
4382 snprintf( dtmp
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, de
->d_name
);
4384 if (S_ISDIR( fst
.st_mode
))
4386 if (de
->d_name
[0] == '.')
4388 if (!onlysave
|| SavedExtension(de
->d_name
) ) {
4391 } while (( de
= readdir( dir
) ) != NULL
);
4395 void Interface::LoadProgress(int percent
)
4397 vars
->SetAt("Progress", percent
);
4398 RedrawControls("Progress", percent
);
4401 video
->SwapBuffers();
4404 void Interface::ReleaseDraggedItem()
4406 DraggedItem
=NULL
; //shouldn't free this
4407 video
->SetDragCursor (NULL
);
4410 void Interface::DragItem(CREItem
*item
, const ieResRef Picture
)
4412 //We should drop the dragged item and pick this up,
4413 //we shouldn't have a valid DraggedItem at this point.
4414 //Anyway, if there is still a dragged item, it will be destroyed.
4416 printMessage("Core","Forgot to call ReleaseDraggedItem when leaving inventory (item destroyed)!\n",YELLOW
);
4421 Sprite2D
* DraggedCursor
= NULL
;
4423 DraggedCursor
= gamedata
->GetBAMSprite( Picture
, 0, 0 );
4425 video
->SetDragCursor (DraggedCursor
);
4429 void Interface::SetDraggedPortrait(int dp
, int idx
)
4432 DraggedPortrait
= dp
;
4434 //hmm this might work?
4435 Cursors
[idx
]->RefCount
++;
4436 video
->SetDragCursor(Cursors
[idx
]);
4438 video
->SetDragCursor(NULL
);
4442 bool Interface::ReadItemTable(const ieResRef TableName
, const char * Prefix
)
4447 AutoTable
tab(TableName
);
4451 i
=tab
->GetRowCount();
4454 snprintf(ItemName
,sizeof(ItemName
),"%s%02d",Prefix
, j
+1);
4456 strnlwrcpy(ItemName
,tab
->GetRowName(j
), 8);
4458 //Variable elements are free'd, so we have to use malloc
4459 //well, not anymore, we can use ReleaseFunction
4460 int l
=tab
->GetColumnCount(j
);
4462 int cl
= atoi(tab
->GetColumnName(0));
4463 ItemList
*itemlist
= new ItemList(l
, cl
);
4464 for(int k
=0;k
<l
;k
++) {
4465 strnlwrcpy(itemlist
->ResRefs
[k
],tab
->QueryField(j
,k
), 8);
4467 RtRows
->SetAt(ItemName
, (void*)itemlist
);
4472 bool Interface::ReadRandomItems()
4477 ieDword difflev
=0; //rt norm or rt fury
4478 vars
->Lookup("Nightmare Mode", difflev
);
4480 RtRows
->RemoveAll(ReleaseItemList
);
4483 RtRows
=new Variables(10, 17); //block size, hash table size
4487 RtRows
->SetType( GEM_VARIABLES_POINTER
);
4489 AutoTable
tab("randitem");
4493 if (difflev
>=tab
->GetColumnCount()) {
4494 difflev
= tab
->GetColumnCount()-1;
4498 strnlwrcpy( GoldResRef
, tab
->QueryField((unsigned int) 0,(unsigned int) 0), 8);
4499 if ( GoldResRef
[0]=='*' ) {
4502 strnlwrcpy( RtResRef
, tab
->QueryField( 1, difflev
), 8);
4505 ReadItemTable( RtResRef
, 0 ); //reading the table itself
4512 strnlwrcpy( RtResRef
, tab
->QueryField(2+i
,difflev
), 8);
4513 ReadItemTable( RtResRef
,tab
->GetRowName(2+i
) );
4518 CREItem
*Interface::ReadItem(DataStream
*str
)
4520 CREItem
*itm
= new CREItem();
4522 str
->ReadResRef( itm
->ItemResRef
);
4523 str
->ReadWord( &itm
->Expired
);
4524 str
->ReadWord( &itm
->Usages
[0] );
4525 str
->ReadWord( &itm
->Usages
[1] );
4526 str
->ReadWord( &itm
->Usages
[2] );
4527 str
->ReadDword( &itm
->Flags
);
4528 if (ResolveRandomItem(itm
) ) {
4537 //This function generates random items based on the randitem.2da file
4538 //there could be a loop, but we don't want to freeze, so there is a limit
4539 bool Interface::ResolveRandomItem(CREItem
*itm
)
4541 if (!RtRows
) return true;
4542 for(int loop
=0;loop
<MAX_LOOP
;loop
++) {
4548 if ( !RtRows
->Lookup( itm
->ItemResRef
, lookup
) ) {
4551 ItemList
*itemlist
= (ItemList
*)lookup
;
4552 if (itemlist
->WeightOdds
) {
4553 //instead of 1d19 we calculate with 2d10 (which also has 19 possible values)
4554 i
=Roll(2,(itemlist
->Count
+1)/2,-2);
4556 i
=Roll(1,itemlist
->Count
,-1);
4558 strnlwrcpy( NewItem
, itemlist
->ResRefs
[i
], 8);
4559 char *p
=(char *) strchr(NewItem
,'*');
4561 *p
=0; //doing this so endptr is ok
4562 k
=strtol(p
+1,NULL
,10);
4566 j
=strtol(NewItem
,&endptr
,10);
4571 strnlwrcpy(itm
->ItemResRef
, NewItem
, 8);
4573 strnlwrcpy(itm
->ItemResRef
, GoldResRef
, 8);
4575 if ( !memcmp( itm
->ItemResRef
,"no_drop",8 ) ) {
4576 itm
->ItemResRef
[0]=0;
4578 if (!itm
->ItemResRef
[0]) {
4581 itm
->Usages
[0]=(ieWord
) Roll(j
,k
,0);
4583 printMessage("Interface"," ",LIGHT_RED
);
4584 printf("Loop detected while generating random item:%s\n",itm
->ItemResRef
);
4588 //now that we store spell name in spl, i guess, we shouldn't pass 'ieResRef name'
4589 //these functions are needed because Win32 doesn't allow freeing memory from
4590 //another dll. So we allocate all commonly used memories from core
4591 ITMExtHeader
*Interface::GetITMExt(int count
)
4593 return new ITMExtHeader
[count
];
4596 SPLExtHeader
*Interface::GetSPLExt(int count
)
4598 return new SPLExtHeader
[count
];
4601 Effect
*Interface::GetEffect(ieDword opcode
)
4603 if (opcode
==0xffffffff) {
4606 Effect
*fx
= new Effect();
4610 memset(fx
,0,sizeof(Effect
));
4615 Effect
*Interface::GetFeatures(int count
)
4617 return new Effect
[count
];
4621 void Interface::FreeITMExt(ITMExtHeader *p, Effect *e)
4627 void Interface::FreeSPLExt(SPLExtHeader *p, Effect *e)
4634 WorldMapArray
*Interface::NewWorldMapArray(int count
)
4636 return new WorldMapArray(count
);
4639 Container
*Interface::GetCurrentContainer()
4641 return CurrentContainer
;
4644 int Interface::CloseCurrentContainer()
4646 UseContainer
= false;
4647 if ( !CurrentContainer
) {
4650 //remove empty ground piles on closeup
4651 CurrentContainer
->GetCurrentArea()->TMap
->CleanupContainer(CurrentContainer
);
4652 CurrentContainer
= NULL
;
4656 void Interface::SetCurrentContainer(Actor
*actor
, Container
*arg
, bool flag
)
4658 //abort action if the first selected PC isn't the original actor
4659 if (actor
!=GetFirstSelectedPC(false)) {
4660 CurrentContainer
= NULL
;
4663 CurrentContainer
= arg
;
4664 UseContainer
= flag
;
4667 Store
*Interface::GetCurrentStore()
4669 return CurrentStore
;
4672 int Interface::CloseCurrentStore()
4674 if ( !CurrentStore
) {
4677 StoreMgr
* sm
= ( StoreMgr
* ) GetInterface( IE_STO_CLASS_ID
);
4681 int size
= sm
->GetStoredFileSize (CurrentStore
);
4683 //created streams are always autofree (close file on destruct)
4684 //this one will be destructed when we return from here
4687 str
.Create( CurrentStore
->Name
, IE_STO_CLASS_ID
);
4688 int ret
= sm
->PutStore (&str
, CurrentStore
);
4690 printMessage("Core"," ", YELLOW
);
4691 printf("Store removed: %s\n", CurrentStore
->Name
);
4692 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4695 printMessage("Core"," ", YELLOW
);
4696 printf("Store removed: %s\n", CurrentStore
->Name
);
4697 RemoveFromCache(CurrentStore
->Name
, IE_STO_CLASS_ID
);
4699 //make sure the stream isn't connected to sm, or it will be double freed
4700 FreeInterface( sm
);
4701 delete CurrentStore
;
4702 CurrentStore
= NULL
;
4706 Store
*Interface::SetCurrentStore(const ieResRef resname
, const ieVariable owner
)
4708 if ( CurrentStore
) {
4709 if ( !strnicmp(CurrentStore
->Name
, resname
, 8) ) {
4710 return CurrentStore
;
4713 //not simply delete the old store, but save it
4714 CloseCurrentStore();
4717 DataStream
* str
= gamedata
->GetResource( resname
, IE_STO_CLASS_ID
);
4718 StoreMgr
* sm
= ( StoreMgr
* ) GetInterface( IE_STO_CLASS_ID
);
4723 if (!sm
->Open( str
, true )) {
4724 FreeInterface( sm
);
4728 // FIXME - should use some already allocated in core
4729 // not really, only one store is open at a time, then it is
4730 // unloaded, we don't really have to cache it, it will be saved in
4732 CurrentStore
= sm
->GetStore( new Store() );
4733 if (CurrentStore
== NULL
) {
4734 FreeInterface( sm
);
4737 FreeInterface( sm
);
4738 strnlwrcpy(CurrentStore
->Name
, resname
, 8);
4740 CurrentStore
->SetOwner(owner
);
4742 return CurrentStore
;
4745 void Interface::SetMouseScrollSpeed(int speed
) {
4746 mousescrollspd
= (speed
+1)*2;
4749 int Interface::GetMouseScrollSpeed() {
4750 return mousescrollspd
;
4753 ieStrRef
Interface::GetRumour(const ieResRef dlgref
)
4755 DialogMgr
* dm
= ( DialogMgr
* ) GetInterface( IE_DLG_CLASS_ID
);
4756 dm
->Open( gamedata
->GetResource( dlgref
, IE_DLG_CLASS_ID
), true );
4757 Dialog
*dlg
= dm
->GetDialog();
4758 FreeInterface( dm
);
4761 printMessage("Interface"," ", LIGHT_RED
);
4762 printf( "Cannot load dialog: %s\n", dlgref
);
4763 return (ieStrRef
) -1;
4765 Scriptable
*pc
=game
->GetPC( game
->GetSelectedPCSingle(), false );
4767 ieStrRef ret
= (ieStrRef
) -1;
4768 int i
= dlg
->FindRandomState( pc
);
4770 ret
= dlg
->GetState( i
)->StrRef
;
4776 void Interface::DoTheStoreHack(Store
*s
)
4778 size_t size
= s
->PurchasedCategoriesCount
* sizeof( ieDword
);
4779 s
->purchased_categories
=(ieDword
*) malloc(size
);
4781 size
= s
->CuresCount
* sizeof( STOCure
);
4782 s
->cures
=(STOCure
*) malloc(size
);
4784 size
= s
->DrinksCount
* sizeof( STODrink
);
4785 s
->drinks
=(STODrink
*) malloc(size
);
4787 for(size
=0;size
<s
->ItemsCount
;size
++)
4788 s
->items
.push_back( new STOItem() );
4791 //plays stock sound listed in defsound.2da
4792 void Interface::PlaySound(int index
)
4794 if (index
<=DSCount
) {
4795 AudioDriver
->Play(DefSound
[index
]);
4799 Actor
*Interface::GetFirstSelectedPC(bool forced
)
4801 int partySize
= game
->GetPartySize( false );
4802 if (!partySize
) return NULL
;
4803 for (int i
= 0; i
< partySize
; i
++) {
4804 Actor
* actor
= game
->GetPC( i
,false );
4805 if (actor
->IsSelected()) {
4811 return game
->GetPC(0,false);
4816 //this is used only for the console
4817 Sprite2D
*Interface::GetCursorSprite()
4819 Sprite2D
*spr
= gamedata
->GetBAMSprite(CursorBam
, 0, 0);
4822 if(HasFeature(GF_OVERRIDE_CURSORPOS
))
4825 spr
->YPos
=spr
->Height
-1;
4831 Sprite2D
*Interface::GetScrollCursorSprite(int frameNum
, int spriteNum
)
4833 return gamedata
->GetBAMSprite(ScrollCursorBam
, frameNum
, spriteNum
);
4836 /* we should return -1 if it isn't gold, otherwise return the gold value */
4837 int Interface::CanMoveItem(const CREItem
*item
) const
4839 //This is an inventory slot, switch to IE_ITEM_* if you use Item
4840 if (item
->Flags
& IE_INV_ITEM_UNDROPPABLE
)
4842 //not gold, we allow only one single coin ResRef, this is good
4843 //for all of the original games
4844 if (strnicmp(item
->ItemResRef
, GoldResRef
, 8 ) )
4846 //gold, returns the gold value (stack size)
4847 return item
->Usages
[0];
4850 // dealing with applying effects
4851 void Interface::ApplySpell(const ieResRef resname
, Actor
*actor
, Scriptable
*caster
, int level
)
4853 Spell
*spell
= gamedata
->GetSpell(resname
);
4858 level
= spell
->GetHeaderIndexFromLevel(level
);
4859 EffectQueue
*fxqueue
= spell
->GetEffectBlock(caster
, actor
->Pos
, level
);
4861 //check effect immunities
4862 int res
= fxqueue
->CheckImmunity ( actor
);
4865 //bounced back at a nonliving caster
4866 if (caster
->Type
!=ST_ACTOR
) {
4870 actor
= (Actor
*) caster
;
4872 fxqueue
->SetOwner( caster
);
4873 fxqueue
->AddAllEffects(actor
, actor
->Pos
);
4878 void Interface::ApplySpellPoint(const ieResRef resname
, Map
* area
, Point
&pos
, Scriptable
*caster
, int level
)
4880 Spell
*spell
= gamedata
->GetSpell(resname
);
4884 level
= spell
->GetHeaderIndexFromLevel(level
);
4885 Projectile
*pro
= spell
->GetProjectile(caster
, level
, pos
);
4886 pro
->SetCaster(caster
->GetGlobalID());
4887 area
->AddProjectile(pro
, caster
->Pos
, pos
);
4890 //-1 means the effect was reflected back to the caster
4891 //0 means the effect was resisted and should be removed
4892 //1 means the effect was applied
4893 int Interface::ApplyEffect(Effect
*effect
, Actor
*actor
, Scriptable
*caster
)
4899 EffectQueue
*fxqueue
= new EffectQueue();
4900 //AddEffect now copies the fx data, please delete your effect reference
4901 //if you created it. (Don't delete cached references)
4902 fxqueue
->AddEffect( effect
);
4904 int res
= fxqueue
->CheckImmunity ( actor
);
4907 //bounced back at a nonliving caster
4908 if (caster
->Type
!=ST_ACTOR
) {
4912 actor
= (Actor
*) caster
;
4914 fxqueue
->SetOwner( caster
);
4917 p
.empty(); //the effect should have all its coordinates already set
4918 if (fxqueue
->AddAllEffects( actor
, p
)==FX_NOT_APPLIED
) {
4926 Effect
*Interface::GetEffect(const ieResRef resname
, int level
, Point
&p
)
4928 //Don't free this reference, it is cached!
4929 Effect
*effect
= gamedata
->GetEffect(resname
);
4936 effect
->Power
= level
;
4942 // dealing with saved games
4943 int Interface::SwapoutArea(Map
*map
)
4945 MapMgr
* mm
= ( MapMgr
* ) GetInterface( IE_ARE_CLASS_ID
);
4949 int size
= mm
->GetStoredFileSize (map
);
4951 //created streams are always autofree (close file on destruct)
4952 //this one will be destructed when we return from here
4955 str
.Create( map
->GetScriptName(), IE_ARE_CLASS_ID
);
4956 int ret
= mm
->PutArea (&str
, map
);
4958 printMessage("Core"," ", YELLOW
);
4959 printf("Area removed: %s\n", map
->GetScriptName());
4960 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4963 printMessage("Core"," ", YELLOW
);
4964 printf("Area removed: %s\n", map
->GetScriptName());
4965 RemoveFromCache(map
->GetScriptName(), IE_ARE_CLASS_ID
);
4967 //make sure the stream isn't connected to sm, or it will be double freed
4968 FreeInterface( mm
);
4972 int Interface::WriteCharacter(const char *name
, Actor
*actor
)
4974 char Path
[_MAX_PATH
];
4976 PathJoin( Path
, GamePath
, GameCharactersPath
, NULL
);
4980 ActorMgr
* gm
= ( ActorMgr
* ) GetInterface( IE_CRE_CLASS_ID
);
4986 str
.Create( Path
, name
, IE_CHR_CLASS_ID
);
4988 //this is not needed, because the chr header writer automatically
4990 //int size = gm->GetStoredFileSize (actor);
4991 int ret
= gm
->PutActor(&str
, actor
, true);
4993 printMessage("Core"," ", YELLOW
);
4994 printf("Character cannot be saved: %s\n", name
);
5000 int Interface::WriteGame(const char *folder
)
5002 SaveGameMgr
* gm
= ( SaveGameMgr
* ) GetInterface( IE_GAM_CLASS_ID
);
5007 int size
= gm
->GetStoredFileSize (game
);
5009 //created streams are always autofree (close file on destruct)
5010 //this one will be destructed when we return from here
5013 str
.Create( folder
, GameNameResRef
, IE_GAM_CLASS_ID
);
5014 int ret
= gm
->PutGame (&str
, game
);
5016 printMessage("Core"," ", YELLOW
);
5017 printf("Game cannot be saved: %s\n", GameNameResRef
);
5020 printMessage("Core"," ", YELLOW
);
5021 printf("Internal error, game cannot be saved: %s\n", GameNameResRef
);
5023 //make sure the stream isn't connected to sm, or it will be double freed
5024 FreeInterface( gm
);
5028 int Interface::WriteWorldMap(const char *folder
)
5030 WorldMapMgr
* wmm
= ( WorldMapMgr
* ) GetInterface( IE_WMP_CLASS_ID
);
5035 int size
= wmm
->GetStoredFileSize (worldmap
);
5037 //created streams are always autofree (close file on destruct)
5038 //this one will be destructed when we return from here
5041 str
.Create( folder
, WorldMapName
, IE_WMP_CLASS_ID
);
5042 int ret
= wmm
->PutWorldMap (&str
, worldmap
);
5044 printMessage("Core"," ", YELLOW
);
5045 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
5048 printMessage("Core"," ", YELLOW
);
5049 printf("Internal error, worldmap cannot be saved: %s\n", WorldMapName
);
5051 //make sure the stream isn't connected to sm, or it will be double freed
5052 FreeInterface( wmm
);
5056 int Interface::CompressSave(const char *folder
)
5060 str
.Create( folder
, GameNameResRef
, IE_SAV_CLASS_ID
);
5061 DIR* dir
= opendir( CachePath
);
5065 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
5070 //BIF and SAV are the same
5071 ArchiveImporter
* ai
= (ArchiveImporter
*)GetInterface(IE_BIF_CLASS_ID
);
5072 ai
->CreateArchive( &str
);
5074 //.tot and .toh should be saved last, because they are updated when an .are is saved
5078 char dtmp
[_MAX_PATH
];
5080 snprintf( dtmp
, _MAX_PATH
, "%s%s", CachePath
, de
->d_name
);
5082 if (S_ISDIR( fst
.st_mode
))
5084 if (de
->d_name
[0] == '.')
5086 if (SavedExtension(de
->d_name
)==priority
) {
5088 fs
.Open(dtmp
, true);
5089 ai
->AddToSaveGame(&str
, &fs
);
5091 } while (( de
= readdir( dir
) ) != NULL
);
5093 //reopen list for the second round
5096 dir
= opendir( CachePath
);
5097 de
= readdir( dir
);
5100 FreeInterface( ai
);
5104 int Interface::GetMaximumAbility() const { return MaximumAbility
; }
5106 int Interface::GetStrengthBonus(int column
, int value
, int ex
) const
5108 //to hit, damage, open doors, weight allowance
5109 if (column
<0 || column
>3)
5122 return strmod
[column
*(MaximumAbility
+1)+value
]+strmodex
[column
*101+ex
];
5125 //only the first 3 columns are supported
5126 int Interface::GetIntelligenceBonus(int column
, int value
) const
5128 //learn spell, max spell level, max spell number on level
5129 if (column
<0 || column
>2)
5132 return intmod
[column
*(MaximumAbility
+1)+value
];
5135 int Interface::GetDexterityBonus(int column
, int value
) const
5137 //reaction, missile, ac
5138 if (column
<0 || column
>2)
5141 //no dexmod in iwd2???
5142 if (HasFeature(GF_3ED_RULES
)) return 0;
5144 return dexmod
[column
*(MaximumAbility
+1)+value
];
5147 int Interface::GetConstitutionBonus(int column
, int value
) const
5149 //normal, warrior, minimum, regen hp, regen fatigue
5150 if (column
<0 || column
>4)
5153 return conmod
[column
*(MaximumAbility
+1)+value
];
5156 int Interface::GetCharismaBonus(int column
, int value
) const
5159 if (column
<0 || column
>0)
5162 return chrmod
[column
*(MaximumAbility
+1)+value
];
5165 int Interface::GetLoreBonus(int column
, int value
) const
5167 if (column
<0 || column
>0)
5170 //no lorebon in iwd2???
5171 if (HasFeature(GF_3ED_RULES
)) return 0;
5173 return lorebon
[value
];
5176 // -3, -2 if request is illegal or in cutscene
5177 // -1 if pause is already active
5178 // 0 if pause was not allowed
5179 // 1 if autopause happened
5180 int Interface::Autopause(ieDword flag
)
5182 GameControl
*gc
= GetGameControl();
5186 if (InCutSceneMode()) {
5189 if (gc
->GetDialogueFlags()&DF_FREEZE_SCRIPTS
) {
5192 ieDword autopause_flags
= 0;
5194 vars
->Lookup("Auto Pause State", autopause_flags
);
5195 if (autopause_flags
& (1<<flag
)) {
5196 DisplayConstantString(STR_AP_UNUSABLE
+flag
, 0xff0000);
5197 gc
->SetDialogueFlags(DF_FREEZE_SCRIPTS
, BM_OR
);
5203 void Interface::RegisterOpcodes(int count
, const EffectRef
*opcodes
)
5205 EffectQueue_RegisterOpcodes(count
, opcodes
);
5208 void Interface::SetInfoTextColor(Color
&color
)
5210 if (InfoTextPalette
) {
5211 gamedata
->FreePalette(InfoTextPalette
);
5213 InfoTextPalette
= CreatePalette(color
, black
);
5217 void Interface::GetResRefFrom2DA(const ieResRef resref
, ieResRef resource1
, ieResRef resource2
, ieResRef resource3
)
5229 AutoTable
tab(resref
);
5231 unsigned int cols
= tab
->GetColumnCount();
5232 unsigned int row
= (unsigned int) Roll(1,tab
->GetRowCount(),-1);
5233 strnuprcpy(resource1
, tab
->QueryField(row
,0), 8);
5234 if (resource2
&& cols
>1)
5235 strnuprcpy(resource2
, tab
->QueryField(row
,1), 8);
5236 if (resource3
&& cols
>2)
5237 strnuprcpy(resource3
, tab
->QueryField(row
,2), 8);
5241 ieDword
*Interface::GetListFrom2DA(const ieResRef resref
)
5245 AutoTable
tab(resref
);
5247 ieDword cnt
= tab
->GetRowCount();
5248 ret
= (ieDword
*) malloc((1+cnt
)*sizeof(ieDword
));
5251 ret
[cnt
]=strtol(tab
->QueryField(cnt
-1, 0),NULL
, 0);
5256 ret
= (ieDword
*) malloc(sizeof(ieDword
));
5261 //returns a numeric value associated with a stat name (symbol) from stats.ids
5262 ieDword
Interface::TranslateStat(const char *stat_name
)
5266 if (valid_number(stat_name
, tmp
)) {
5267 return (ieDword
) tmp
;
5270 int symbol
= LoadSymbol( "stats" );
5271 SymbolMgr
*sym
= GetSymbol( symbol
);
5272 ieDword stat
= (ieDword
) sym
->GetValue( stat_name
);
5273 if (stat
==(ieDword
) ~0) {
5274 printMessage("Core"," ",YELLOW
);
5275 printf("Cannot translate symbol: %s\n", stat_name
);
5280 void Interface::WaitForDisc(int disc_number
, const char* path
)
5282 GetDictionary()->SetAt( "WaitForDisc", (ieDword
) disc_number
);
5284 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5286 core
->DrawWindows();
5287 if (dir_exists (path
)) {
5288 GetGUIScriptEngine()->RunFunction( "OpenWaitForDiscWindow" );
5292 } while (video
->SwapBuffers() == GEM_OK
);
5295 // remove the extraneus EOL newline and carriage return
5296 void Interface::StripLine(char * string
, size_t size
) {
5297 if (size
>= 2 && string
[size
-2] == '\n') {
5298 string
[size
-2] = '\0';
5300 if (size
>= 3 && string
[size
-3] == '\r') {
5301 string
[size
-3] = '\0'; // remove the carriage return too
5305 void Interface::SetNextScript(const char *script
)
5307 strncpy( NextScript
, script
, sizeof(NextScript
) );
5308 QuitFlag
|= QF_CHANGESCRIPT
;