Plugin: Call Plugin::release directly, rather than through Interface and PluginMgr.
[gemrb.git] / gemrb / core / GameData.cpp
blob106e2addaf3f790850871e4765fded9d180ac6e9
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.
21 #include <cstdio>
22 #include "GameData.h"
24 #include "Actor.h"
25 #include "Cache.h"
26 #include "Factory.h"
27 #include "Item.h"
28 #include "Spell.h"
29 #include "Effect.h"
30 #include "ActorMgr.h"
31 #include "FileStream.h"
32 #include "Interface.h"
33 #include "SpellMgr.h"
34 #include "ItemMgr.h"
35 #include "EffectMgr.h"
36 #include "Game.h"
37 #include "ResourceDesc.h"
38 #include "AnimationMgr.h"
39 #include "ImageMgr.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
60 if (!poi) return;
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) \
67 { \
68 std::vector<type>::iterator i; \
69 for(i = (variable).begin(); i != (variable).end(); ++i) { \
70 if ((*i).refcount) { \
71 (*i).member->release(); \
72 (*i).refcount = 0; \
73 } \
74 } \
77 GameData::GameData()
79 factory = new Factory();
82 GameData::~GameData()
84 FreeInterfaceVector( Table, tables, tm );
85 delete factory;
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 );
99 if (!ds)
100 return 0;
102 ActorMgr* actormgr = ( ActorMgr* ) core->GetInterface( IE_CRE_CLASS_ID );
103 if (!actormgr->Open( ds, true )) {
104 actormgr->release();
105 return 0;
107 Actor* actor = actormgr->GetActor(PartySlot);
108 actormgr->release();
109 return actor;
112 int GameData::LoadCreature(const char* ResRef, unsigned int PartySlot, bool character)
114 DataStream *stream;
116 Actor* actor;
117 if (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 )) {
127 actormgr->release();
128 return -1;
130 actor = actormgr->GetActor(PartySlot);
131 actormgr->release();
132 } else {
133 actor = GetCreature(ResRef, PartySlot);
136 if ( !actor ) {
137 return -1;
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 );
144 } else {
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 );
152 else {
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 );
161 if (ind != -1) {
162 tables[ind].refcount++;
163 return ind;
165 //printf("(%s) Table not found... Loading from file\n", ResRef);
166 DataStream* str = GetResource( ResRef, IE_2DA_CLASS_ID );
167 if (!str) {
168 return -1;
170 TableMgr* tm = ( TableMgr* ) core->GetInterface( IE_2DA_CLASS_ID );
171 if (!tm) {
172 delete str;
173 return -1;
175 if (!tm->Open( str, true )) {
176 tm->release();
177 return -1;
179 Table t;
180 t.refcount = 1;
181 strncpy( t.ResRef, ResRef, 8 );
182 t.tm = tm;
183 ind = -1;
184 for (size_t i = 0; i < tables.size(); i++) {
185 if (tables[i].refcount == 0) {
186 ind = ( int ) i;
187 break;
190 if (ind != -1) {
191 tables[ind] = t;
192 return ind;
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)
202 continue;
203 if (strnicmp( tables[i].ResRef, ResRef, 8 ) == 0)
204 return ( int ) i;
206 return -1;
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()) {
212 return NULL;
214 if (tables[index].refcount == 0) {
215 return NULL;
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 );
225 tables.clear();
226 return true;
228 if (index >= tables.size()) {
229 return false;
231 if (tables[index].refcount == 0) {
232 return false;
234 tables[index].refcount--;
235 if (tables[index].refcount == 0)
236 if (tables[index].tm)
237 tables[index].tm->release();
238 return true;
241 Palette *GameData::GetPalette(const ieResRef resname)
243 Palette *palette = (Palette *) PaletteCache.GetResource(resname);
244 if (palette) {
245 return palette;
247 //additional hack for allowing NULL's
248 if (PaletteCache.RefCount(resname)!=-1) {
249 return NULL;
251 ImageMgr* im = ( ImageMgr* )
252 GetResource( resname, &ImageMgr::ID );
253 if (im == NULL) {
254 PaletteCache.SetAt(resname, NULL);
255 return NULL;
258 palette = new Palette();
259 im->GetPalette(256,palette->col);
260 im->release();
261 palette->named=true;
262 PaletteCache.SetAt(resname, (void *) palette);
263 return palette;
266 void GameData::FreePalette(Palette *&pal, const ieResRef name)
268 int res;
270 if (!pal) {
271 return;
273 if (!name || !name[0]) {
274 if(pal->named) {
275 printf("Palette is supposed to be named, but got no name!\n");
276 abort();
277 } else {
278 pal->Release();
279 pal=NULL;
281 return;
283 if (!pal->named) {
284 printf("Unnamed palette, it should be %s!\n", name);
285 abort();
287 res=PaletteCache.DecRef((void *) pal, name, true);
288 if (res<0) {
289 printMessage( "Core", "Corrupted Palette cache encountered (reference count went below zero), ", LIGHT_RED );
290 printf( "Palette name is: %.8s\n", name);
291 abort();
293 if (!res) {
294 pal->Release();
296 pal = NULL;
299 Item* GameData::GetItem(const ieResRef resname)
301 Item *item = (Item *) ItemCache.GetResource(resname);
302 if (item) {
303 return item;
305 DataStream* str = GetResource( resname, IE_ITM_CLASS_ID );
306 ItemMgr* sm = ( ItemMgr* ) core->GetInterface( IE_ITM_CLASS_ID );
307 if (sm == NULL) {
308 delete ( str );
309 return NULL;
311 if (!sm->Open( str, true )) {
312 sm->release();
313 return NULL;
316 item = new Item();
317 //this is required for storing the 'source'
318 strnlwrcpy(item->Name, resname, 8);
319 sm->GetItem( item );
320 if (item == NULL) {
321 sm->release();
322 return NULL;
325 sm->release();
326 ItemCache.SetAt(resname, (void *) item);
327 return item;
330 //you can supply name for faster access
331 void GameData::FreeItem(Item const *itm, const ieResRef name, bool free)
333 int res;
335 res=ItemCache.DecRef((void *) itm, name, free);
336 if (res<0) {
337 printMessage( "Core", "Corrupted Item cache encountered (reference count went below zero), ", LIGHT_RED );
338 printf( "Item name is: %.8s\n", name);
339 abort();
341 if (res) return;
342 if (free) delete itm;
345 Spell* GameData::GetSpell(const ieResRef resname, bool silent)
347 Spell *spell = (Spell *) SpellCache.GetResource(resname);
348 if (spell) {
349 return spell;
351 DataStream* str = GetResource( resname, IE_SPL_CLASS_ID, silent );
352 SpellMgr* sm = ( SpellMgr* ) core->GetInterface( IE_SPL_CLASS_ID );
353 if (sm == NULL) {
354 delete ( str );
355 return NULL;
357 if (!sm->Open( str, true )) {
358 sm->release();
359 return NULL;
362 spell = new Spell();
363 //this is required for storing the 'source'
364 strnlwrcpy(spell->Name, resname, 8);
365 sm->GetSpell( spell, silent );
366 if (spell == NULL) {
367 sm->release();
368 return NULL;
371 sm->release();
373 SpellCache.SetAt(resname, (void *) spell);
374 return spell;
377 void GameData::FreeSpell(Spell *spl, const ieResRef name, bool free)
379 int res;
381 res=SpellCache.DecRef((void *) spl, name, free);
382 if (res<0) {
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);
385 abort();
387 if (res) return;
388 if (free) delete spl;
391 Effect* GameData::GetEffect(const ieResRef resname)
393 Effect *effect = (Effect *) EffectCache.GetResource(resname);
394 if (effect) {
395 return effect;
397 DataStream* str = GetResource( resname, IE_EFF_CLASS_ID );
398 EffectMgr* em = ( EffectMgr* ) core->GetInterface( IE_EFF_CLASS_ID );
399 if (em == NULL) {
400 delete ( str );
401 return NULL;
403 if (!em->Open( str, true )) {
404 em->release();
405 return NULL;
408 effect = em->GetEffect(new Effect() );
409 if (effect == NULL) {
410 em->release();
411 return NULL;
414 em->release();
416 EffectCache.SetAt(resname, (void *) effect);
417 return effect;
420 void GameData::FreeEffect(Effect *eff, const ieResRef name, bool free)
422 int res;
424 res=EffectCache.DecRef((void *) eff, name, free);
425 if (res<0) {
426 printMessage( "Core", "Corrupted Effect cache encountered (reference count went below zero), ", LIGHT_RED );
427 printf( "Effect name is: %.8s\n", name);
428 abort();
430 if (res) return;
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);
443 } else {
444 AnimationFactory *af = (AnimationFactory *)
445 GetFactoryResource( effect, IE_BAM_CLASS_ID, IE_NORMAL );
446 if (af) {
447 ret = new ScriptedAnimation();
448 ret->LoadAnimationFactory( af, doublehint?2:0);
451 if (ret) {
452 strnlwrcpy(ret->ResName, effect, 8);
454 return ret;
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)
461 Sprite2D *tspr;
462 AnimationFactory* af = ( AnimationFactory* )
463 GetFactoryResource( ResRef, IE_BAM_CLASS_ID, IE_NORMAL );
464 if (!af) return 0;
465 if (cycle == -1)
466 tspr = af->GetFrameWithoutCycle( (unsigned short) frame );
467 else
468 tspr = af->GetFrame( (unsigned short) frame, (unsigned char) cycle );
469 return tspr;
472 void* GameData::GetFactoryResource(const char* resname, SClass_ID type,
473 unsigned char mode, bool silent)
475 int fobjindex = factory->IsLoaded(resname,type);
476 // already cached
477 if ( fobjindex != -1)
478 return factory->GetFactoryObject( fobjindex );
480 // empty resref
481 if (!strcmp(resname, ""))
482 return NULL;
484 switch (type) {
485 case IE_BAM_CLASS_ID:
487 DataStream* ret = GetResource( resname, type, silent );
488 if (ret) {
489 AnimationMgr* ani = ( AnimationMgr* )
490 core->GetInterface( IE_BAM_CLASS_ID );
491 if (!ani)
492 return NULL;
493 ani->Open( ret, true );
494 AnimationFactory* af = ani->GetAnimationFactory( resname, mode );
495 ani->release();
496 factory->AddFactoryObject( af );
497 return af;
499 return NULL;
501 case IE_BMP_CLASS_ID:
503 ImageMgr* img = (ImageMgr*) GetResource( resname, &ImageMgr::ID );
504 if (img) {
505 ImageFactory* fact = img->GetImageFactory( resname );
506 img->release();
507 factory->AddFactoryObject( fact );
508 return fact;
511 return NULL;
513 default:
514 printf( "\n" );
515 printMessage( "KEYImporter", " ", WHITE );
516 printf( "%s files are not supported.\n", core->TypeExt( type ) );
517 return NULL;