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.
31 #include "FileStream.h"
32 #include "Interface.h"
35 #include "EffectMgr.h"
37 #include "ResourceDesc.h"
38 #include "AnimationMgr.h"
40 #include "ImageFactory.h"
42 static void ReleaseItem(void *poi
)
44 delete ((Item
*) poi
);
47 static void ReleaseSpell(void *poi
)
49 delete ((Spell
*) poi
);
52 static void ReleaseEffect(void *poi
)
54 delete ((Effect
*) poi
);
57 static void ReleasePalette(void *poi
)
59 //we allow nulls, but we shouldn't release them
61 //as long as palette has its own refcount, this should be Release
62 ((Palette
*) poi
)->Release();
65 // TODO: this is duplicated from Interface.cpp
66 #define FreeInterfaceVector(type, variable, member) \
68 std::vector<type>::iterator i; \
69 for(i = (variable).begin(); i != (variable).end(); ++i) { \
70 if ((*i).refcount) { \
71 (*i).member->release(); \
79 factory
= new Factory();
84 FreeInterfaceVector( Table
, tables
, tm
);
88 void GameData::ClearCaches()
90 ItemCache
.RemoveAll(ReleaseItem
);
91 SpellCache
.RemoveAll(ReleaseSpell
);
92 EffectCache
.RemoveAll(ReleaseEffect
);
93 PaletteCache
.RemoveAll(ReleasePalette
);
96 Actor
*GameData::GetCreature(const char* ResRef
, unsigned int PartySlot
)
98 DataStream
* ds
= GetResource( ResRef
, IE_CRE_CLASS_ID
);
102 ActorMgr
* actormgr
= ( ActorMgr
* ) core
->GetInterface( IE_CRE_CLASS_ID
);
103 if (!actormgr
->Open( ds
, true )) {
107 Actor
* actor
= actormgr
->GetActor(PartySlot
);
112 int GameData::LoadCreature(const char* ResRef
, unsigned int PartySlot
, bool character
)
118 char nPath
[_MAX_PATH
], fName
[16];
119 snprintf( fName
, sizeof(fName
), "%s.chr", ResRef
);
120 PathJoin( nPath
, core
->GamePath
, "characters", fName
, NULL
);
121 ResolveFilePath( nPath
);
122 FileStream
*fs
= new FileStream();
123 fs
-> Open( nPath
, true );
124 stream
= (DataStream
*) fs
;
125 ActorMgr
* actormgr
= ( ActorMgr
* ) core
->GetInterface( IE_CRE_CLASS_ID
);
126 if (!actormgr
->Open( stream
, true )) {
130 actor
= actormgr
->GetActor(PartySlot
);
133 actor
= GetCreature(ResRef
, PartySlot
);
140 //both fields are of length 9, make this sure!
141 memcpy(actor
->Area
, core
->GetGame()->CurrentArea
, sizeof(actor
->Area
) );
142 if (actor
->BaseStats
[IE_STATE_ID
] & STATE_DEAD
) {
143 actor
->SetStance( IE_ANI_TWITCH
);
145 actor
->SetStance( IE_ANI_AWAKE
);
147 actor
->SetOrientation( 0, false );
149 if ( PartySlot
!= 0 ) {
150 return core
->GetGame()->JoinParty( actor
, JP_JOIN
|JP_INITPOS
);
153 return core
->GetGame()->AddNPC( actor
);
157 /** Loads a 2DA Table, returns -1 on error or the Table Index on success */
158 int GameData::LoadTable(const ieResRef ResRef
)
160 int ind
= GetTableIndex( ResRef
);
162 tables
[ind
].refcount
++;
165 //printf("(%s) Table not found... Loading from file\n", ResRef);
166 DataStream
* str
= GetResource( ResRef
, IE_2DA_CLASS_ID
);
170 TableMgr
* tm
= ( TableMgr
* ) core
->GetInterface( IE_2DA_CLASS_ID
);
175 if (!tm
->Open( str
, true )) {
181 strncpy( t
.ResRef
, ResRef
, 8 );
184 for (size_t i
= 0; i
< tables
.size(); i
++) {
185 if (tables
[i
].refcount
== 0) {
194 tables
.push_back( t
);
195 return ( int ) tables
.size() - 1;
197 /** Gets the index of a loaded table, returns -1 on error */
198 int GameData::GetTableIndex(const char* ResRef
) const
200 for (size_t i
= 0; i
< tables
.size(); i
++) {
201 if (tables
[i
].refcount
== 0)
203 if (strnicmp( tables
[i
].ResRef
, ResRef
, 8 ) == 0)
208 /** Gets a Loaded Table by its index, returns NULL on error */
209 TableMgr
* GameData::GetTable(unsigned int index
) const
211 if (index
>= tables
.size()) {
214 if (tables
[index
].refcount
== 0) {
217 return tables
[index
].tm
;
220 /** Frees a Loaded Table, returns false on error, true on success */
221 bool GameData::DelTable(unsigned int index
)
223 if (index
==0xffffffff) {
224 FreeInterfaceVector( Table
, tables
, tm
);
228 if (index
>= tables
.size()) {
231 if (tables
[index
].refcount
== 0) {
234 tables
[index
].refcount
--;
235 if (tables
[index
].refcount
== 0)
236 if (tables
[index
].tm
)
237 tables
[index
].tm
->release();
241 Palette
*GameData::GetPalette(const ieResRef resname
)
243 Palette
*palette
= (Palette
*) PaletteCache
.GetResource(resname
);
247 //additional hack for allowing NULL's
248 if (PaletteCache
.RefCount(resname
)!=-1) {
251 ImageMgr
* im
= ( ImageMgr
* )
252 GetResource( resname
, &ImageMgr::ID
);
254 PaletteCache
.SetAt(resname
, NULL
);
258 palette
= new Palette();
259 im
->GetPalette(256,palette
->col
);
262 PaletteCache
.SetAt(resname
, (void *) palette
);
266 void GameData::FreePalette(Palette
*&pal
, const ieResRef name
)
273 if (!name
|| !name
[0]) {
275 printf("Palette is supposed to be named, but got no name!\n");
284 printf("Unnamed palette, it should be %s!\n", name
);
287 res
=PaletteCache
.DecRef((void *) pal
, name
, true);
289 printMessage( "Core", "Corrupted Palette cache encountered (reference count went below zero), ", LIGHT_RED
);
290 printf( "Palette name is: %.8s\n", name
);
299 Item
* GameData::GetItem(const ieResRef resname
)
301 Item
*item
= (Item
*) ItemCache
.GetResource(resname
);
305 DataStream
* str
= GetResource( resname
, IE_ITM_CLASS_ID
);
306 ItemMgr
* sm
= ( ItemMgr
* ) core
->GetInterface( IE_ITM_CLASS_ID
);
311 if (!sm
->Open( str
, true )) {
317 //this is required for storing the 'source'
318 strnlwrcpy(item
->Name
, resname
, 8);
326 ItemCache
.SetAt(resname
, (void *) item
);
330 //you can supply name for faster access
331 void GameData::FreeItem(Item
const *itm
, const ieResRef name
, bool free
)
335 res
=ItemCache
.DecRef((void *) itm
, name
, free
);
337 printMessage( "Core", "Corrupted Item cache encountered (reference count went below zero), ", LIGHT_RED
);
338 printf( "Item name is: %.8s\n", name
);
342 if (free
) delete itm
;
345 Spell
* GameData::GetSpell(const ieResRef resname
, bool silent
)
347 Spell
*spell
= (Spell
*) SpellCache
.GetResource(resname
);
351 DataStream
* str
= GetResource( resname
, IE_SPL_CLASS_ID
, silent
);
352 SpellMgr
* sm
= ( SpellMgr
* ) core
->GetInterface( IE_SPL_CLASS_ID
);
357 if (!sm
->Open( str
, true )) {
363 //this is required for storing the 'source'
364 strnlwrcpy(spell
->Name
, resname
, 8);
365 sm
->GetSpell( spell
, silent
);
373 SpellCache
.SetAt(resname
, (void *) spell
);
377 void GameData::FreeSpell(Spell
*spl
, const ieResRef name
, bool free
)
381 res
=SpellCache
.DecRef((void *) spl
, name
, free
);
383 printMessage( "Core", "Corrupted Spell cache encountered (reference count went below zero), ", LIGHT_RED
);
384 printf( "Spell name is: %.8s or %.8s\n", name
, spl
->Name
);
388 if (free
) delete spl
;
391 Effect
* GameData::GetEffect(const ieResRef resname
)
393 Effect
*effect
= (Effect
*) EffectCache
.GetResource(resname
);
397 DataStream
* str
= GetResource( resname
, IE_EFF_CLASS_ID
);
398 EffectMgr
* em
= ( EffectMgr
* ) core
->GetInterface( IE_EFF_CLASS_ID
);
403 if (!em
->Open( str
, true )) {
408 effect
= em
->GetEffect(new Effect() );
409 if (effect
== NULL
) {
416 EffectCache
.SetAt(resname
, (void *) effect
);
420 void GameData::FreeEffect(Effect
*eff
, const ieResRef name
, bool free
)
424 res
=EffectCache
.DecRef((void *) eff
, name
, free
);
426 printMessage( "Core", "Corrupted Effect cache encountered (reference count went below zero), ", LIGHT_RED
);
427 printf( "Effect name is: %.8s\n", name
);
431 if (free
) delete eff
;
434 //if the default setup doesn't fit for an animation
435 //create a vvc for it!
436 ScriptedAnimation
* GameData::GetScriptedAnimation( const char *effect
, bool doublehint
)
438 ScriptedAnimation
*ret
= NULL
;
440 if (Exists( effect
, IE_VVC_CLASS_ID
) ) {
441 DataStream
*ds
= GetResource( effect
, IE_VVC_CLASS_ID
);
442 ret
= new ScriptedAnimation(ds
, true);
444 AnimationFactory
*af
= (AnimationFactory
*)
445 GetFactoryResource( effect
, IE_BAM_CLASS_ID
, IE_NORMAL
);
447 ret
= new ScriptedAnimation();
448 ret
->LoadAnimationFactory( af
, doublehint
?2:0);
452 strnlwrcpy(ret
->ResName
, effect
, 8);
457 // Return single BAM frame as a sprite. Use if you want one frame only,
458 // otherwise it's not efficient
459 Sprite2D
* GameData::GetBAMSprite(const ieResRef ResRef
, int cycle
, int frame
)
462 AnimationFactory
* af
= ( AnimationFactory
* )
463 GetFactoryResource( ResRef
, IE_BAM_CLASS_ID
, IE_NORMAL
);
466 tspr
= af
->GetFrameWithoutCycle( (unsigned short) frame
);
468 tspr
= af
->GetFrame( (unsigned short) frame
, (unsigned char) cycle
);
472 void* GameData::GetFactoryResource(const char* resname
, SClass_ID type
,
473 unsigned char mode
, bool silent
)
475 int fobjindex
= factory
->IsLoaded(resname
,type
);
477 if ( fobjindex
!= -1)
478 return factory
->GetFactoryObject( fobjindex
);
481 if (!strcmp(resname
, ""))
485 case IE_BAM_CLASS_ID
:
487 DataStream
* ret
= GetResource( resname
, type
, silent
);
489 AnimationMgr
* ani
= ( AnimationMgr
* )
490 core
->GetInterface( IE_BAM_CLASS_ID
);
493 ani
->Open( ret
, true );
494 AnimationFactory
* af
= ani
->GetAnimationFactory( resname
, mode
);
496 factory
->AddFactoryObject( af
);
501 case IE_BMP_CLASS_ID
:
503 ImageMgr
* img
= (ImageMgr
*) GetResource( resname
, &ImageMgr::ID
);
505 ImageFactory
* fact
= img
->GetImageFactory( resname
);
507 factory
->AddFactoryObject( fact
);
515 printMessage( "KEYImporter", " ", WHITE
);
516 printf( "%s files are not supported.\n", core
->TypeExt( type
) );