TableMgr: Add function to get default value.
[gemrb.git] / gemrb / core / GameData.cpp
blob22d9d48bbb2369eef484068fe1b646ee99cb7c83
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 GEM_EXPORT GameData* gamedata;
67 GameData::GameData()
69 factory = new Factory();
72 GameData::~GameData()
74 delete factory;
77 void GameData::ClearCaches()
79 ItemCache.RemoveAll(ReleaseItem);
80 SpellCache.RemoveAll(ReleaseSpell);
81 EffectCache.RemoveAll(ReleaseEffect);
82 PaletteCache.RemoveAll(ReleasePalette);
85 Actor *GameData::GetCreature(const char* ResRef, unsigned int PartySlot)
87 DataStream* ds = GetResource( ResRef, IE_CRE_CLASS_ID );
88 if (!ds)
89 return 0;
91 PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
92 if (!actormgr->Open( ds, true )) {
93 return 0;
95 Actor* actor = actormgr->GetActor(PartySlot);
96 return actor;
99 int GameData::LoadCreature(const char* ResRef, unsigned int PartySlot, bool character)
101 DataStream *stream;
103 Actor* actor;
104 if (character) {
105 char nPath[_MAX_PATH], fName[16];
106 snprintf( fName, sizeof(fName), "%s.chr", ResRef);
107 PathJoin( nPath, core->GamePath, "characters", fName, NULL );
108 FileStream *fs = new FileStream();
109 fs -> Open( nPath, true );
110 stream = (DataStream *) fs;
111 PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
112 if (!actormgr->Open( stream, true )) {
113 return -1;
115 actor = actormgr->GetActor(PartySlot);
116 } else {
117 actor = GetCreature(ResRef, PartySlot);
120 if ( !actor ) {
121 return -1;
124 //both fields are of length 9, make this sure!
125 memcpy(actor->Area, core->GetGame()->CurrentArea, sizeof(actor->Area) );
126 if (actor->BaseStats[IE_STATE_ID] & STATE_DEAD) {
127 actor->SetStance( IE_ANI_TWITCH );
128 } else {
129 actor->SetStance( IE_ANI_AWAKE );
131 actor->SetOrientation( 0, false );
133 if ( PartySlot != 0 ) {
134 return core->GetGame()->JoinParty( actor, JP_JOIN|JP_INITPOS );
136 else {
137 return core->GetGame()->AddNPC( actor );
141 /** Loads a 2DA Table, returns -1 on error or the Table Index on success */
142 int GameData::LoadTable(const ieResRef ResRef)
144 int ind = GetTableIndex( ResRef );
145 if (ind != -1) {
146 tables[ind].refcount++;
147 return ind;
149 //printf("(%s) Table not found... Loading from file\n", ResRef);
150 DataStream* str = GetResource( ResRef, IE_2DA_CLASS_ID );
151 if (!str) {
152 return -1;
154 PluginHolder<TableMgr> tm(IE_2DA_CLASS_ID);
155 if (!tm) {
156 delete str;
157 return -1;
159 if (!tm->Open( str, true )) {
160 return -1;
162 Table t;
163 t.refcount = 1;
164 strncpy( t.ResRef, ResRef, 8 );
165 t.tm = tm;
166 ind = -1;
167 for (size_t i = 0; i < tables.size(); i++) {
168 if (tables[i].refcount == 0) {
169 ind = ( int ) i;
170 break;
173 if (ind != -1) {
174 tables[ind] = t;
175 return ind;
177 tables.push_back( t );
178 return ( int ) tables.size() - 1;
180 /** Gets the index of a loaded table, returns -1 on error */
181 int GameData::GetTableIndex(const char* ResRef) const
183 for (size_t i = 0; i < tables.size(); i++) {
184 if (tables[i].refcount == 0)
185 continue;
186 if (strnicmp( tables[i].ResRef, ResRef, 8 ) == 0)
187 return ( int ) i;
189 return -1;
191 /** Gets a Loaded Table by its index, returns NULL on error */
192 Holder<TableMgr> GameData::GetTable(unsigned int index) const
194 if (index >= tables.size()) {
195 return NULL;
197 if (tables[index].refcount == 0) {
198 return NULL;
200 return tables[index].tm;
203 /** Frees a Loaded Table, returns false on error, true on success */
204 bool GameData::DelTable(unsigned int index)
206 if (index==0xffffffff) {
207 tables.clear();
208 return true;
210 if (index >= tables.size()) {
211 return false;
213 if (tables[index].refcount == 0) {
214 return false;
216 tables[index].refcount--;
217 if (tables[index].refcount == 0)
218 if (tables[index].tm)
219 tables[index].tm.release();
220 return true;
223 Palette *GameData::GetPalette(const ieResRef resname)
225 Palette *palette = (Palette *) PaletteCache.GetResource(resname);
226 if (palette) {
227 return palette;
229 //additional hack for allowing NULL's
230 if (PaletteCache.RefCount(resname)!=-1) {
231 return NULL;
233 ResourceHolder<ImageMgr> im(resname);
234 if (im == NULL) {
235 PaletteCache.SetAt(resname, NULL);
236 return NULL;
239 palette = new Palette();
240 im->GetPalette(256,palette->col);
241 palette->named=true;
242 PaletteCache.SetAt(resname, (void *) palette);
243 return palette;
246 void GameData::FreePalette(Palette *&pal, const ieResRef name)
248 int res;
250 if (!pal) {
251 return;
253 if (!name || !name[0]) {
254 if(pal->named) {
255 printf("Palette is supposed to be named, but got no name!\n");
256 abort();
257 } else {
258 pal->Release();
259 pal=NULL;
261 return;
263 if (!pal->named) {
264 printf("Unnamed palette, it should be %s!\n", name);
265 abort();
267 res=PaletteCache.DecRef((void *) pal, name, true);
268 if (res<0) {
269 printMessage( "Core", "Corrupted Palette cache encountered (reference count went below zero), ", LIGHT_RED );
270 printf( "Palette name is: %.8s\n", name);
271 abort();
273 if (!res) {
274 pal->Release();
276 pal = NULL;
279 Item* GameData::GetItem(const ieResRef resname)
281 Item *item = (Item *) ItemCache.GetResource(resname);
282 if (item) {
283 return item;
285 DataStream* str = GetResource( resname, IE_ITM_CLASS_ID );
286 PluginHolder<ItemMgr> sm(IE_ITM_CLASS_ID);
287 if (!sm) {
288 delete ( str );
289 return NULL;
291 if (!sm->Open( str, true )) {
292 return NULL;
295 item = new Item();
296 //this is required for storing the 'source'
297 strnlwrcpy(item->Name, resname, 8);
298 sm->GetItem( item );
299 if (item == NULL) {
300 return NULL;
303 ItemCache.SetAt(resname, (void *) item);
304 return item;
307 //you can supply name for faster access
308 void GameData::FreeItem(Item const *itm, const ieResRef name, bool free)
310 int res;
312 res=ItemCache.DecRef((void *) itm, name, free);
313 if (res<0) {
314 printMessage( "Core", "Corrupted Item cache encountered (reference count went below zero), ", LIGHT_RED );
315 printf( "Item name is: %.8s\n", name);
316 abort();
318 if (res) return;
319 if (free) delete itm;
322 Spell* GameData::GetSpell(const ieResRef resname, bool silent)
324 Spell *spell = (Spell *) SpellCache.GetResource(resname);
325 if (spell) {
326 return spell;
328 DataStream* str = GetResource( resname, IE_SPL_CLASS_ID, silent );
329 PluginHolder<SpellMgr> sm(IE_SPL_CLASS_ID);
330 if (!sm) {
331 delete ( str );
332 return NULL;
334 if (!sm->Open( str, true )) {
335 return NULL;
338 spell = new Spell();
339 //this is required for storing the 'source'
340 strnlwrcpy(spell->Name, resname, 8);
341 sm->GetSpell( spell, silent );
342 if (spell == NULL) {
343 return NULL;
346 SpellCache.SetAt(resname, (void *) spell);
347 return spell;
350 void GameData::FreeSpell(Spell *spl, const ieResRef name, bool free)
352 int res;
354 res=SpellCache.DecRef((void *) spl, name, free);
355 if (res<0) {
356 printMessage( "Core", "Corrupted Spell cache encountered (reference count went below zero), ", LIGHT_RED );
357 printf( "Spell name is: %.8s or %.8s\n", name, spl->Name);
358 abort();
360 if (res) return;
361 if (free) delete spl;
364 Effect* GameData::GetEffect(const ieResRef resname)
366 Effect *effect = (Effect *) EffectCache.GetResource(resname);
367 if (effect) {
368 return effect;
370 DataStream* str = GetResource( resname, IE_EFF_CLASS_ID );
371 PluginHolder<EffectMgr> em(IE_EFF_CLASS_ID);
372 if (!em) {
373 delete ( str );
374 return NULL;
376 if (!em->Open( str, true )) {
377 return NULL;
380 effect = em->GetEffect(new Effect() );
381 if (effect == NULL) {
382 return NULL;
385 EffectCache.SetAt(resname, (void *) effect);
386 return effect;
389 void GameData::FreeEffect(Effect *eff, const ieResRef name, bool free)
391 int res;
393 res=EffectCache.DecRef((void *) eff, name, free);
394 if (res<0) {
395 printMessage( "Core", "Corrupted Effect cache encountered (reference count went below zero), ", LIGHT_RED );
396 printf( "Effect name is: %.8s\n", name);
397 abort();
399 if (res) return;
400 if (free) delete eff;
403 //if the default setup doesn't fit for an animation
404 //create a vvc for it!
405 ScriptedAnimation* GameData::GetScriptedAnimation( const char *effect, bool doublehint)
407 ScriptedAnimation *ret = NULL;
409 if (Exists( effect, IE_VVC_CLASS_ID ) ) {
410 DataStream *ds = GetResource( effect, IE_VVC_CLASS_ID );
411 ret = new ScriptedAnimation(ds, true);
412 } else {
413 AnimationFactory *af = (AnimationFactory *)
414 GetFactoryResource( effect, IE_BAM_CLASS_ID, IE_NORMAL );
415 if (af) {
416 ret = new ScriptedAnimation();
417 ret->LoadAnimationFactory( af, doublehint?2:0);
420 if (ret) {
421 strnlwrcpy(ret->ResName, effect, 8);
423 return ret;
426 // Return single BAM frame as a sprite. Use if you want one frame only,
427 // otherwise it's not efficient
428 Sprite2D* GameData::GetBAMSprite(const ieResRef ResRef, int cycle, int frame)
430 Sprite2D *tspr;
431 AnimationFactory* af = ( AnimationFactory* )
432 GetFactoryResource( ResRef, IE_BAM_CLASS_ID, IE_NORMAL );
433 if (!af) return 0;
434 if (cycle == -1)
435 tspr = af->GetFrameWithoutCycle( (unsigned short) frame );
436 else
437 tspr = af->GetFrame( (unsigned short) frame, (unsigned char) cycle );
438 return tspr;
441 void* GameData::GetFactoryResource(const char* resname, SClass_ID type,
442 unsigned char mode, bool silent)
444 int fobjindex = factory->IsLoaded(resname,type);
445 // already cached
446 if ( fobjindex != -1)
447 return factory->GetFactoryObject( fobjindex );
449 // empty resref
450 if (!strcmp(resname, ""))
451 return NULL;
453 switch (type) {
454 case IE_BAM_CLASS_ID:
456 DataStream* ret = GetResource( resname, type, silent );
457 if (ret) {
458 PluginHolder<AnimationMgr> ani(IE_BAM_CLASS_ID);
459 if (!ani)
460 return NULL;
461 ani->Open( ret, true );
462 AnimationFactory* af = ani->GetAnimationFactory( resname, mode );
463 factory->AddFactoryObject( af );
464 return af;
466 return NULL;
468 case IE_BMP_CLASS_ID:
470 ResourceHolder<ImageMgr> img(resname);
471 if (img) {
472 ImageFactory* fact = img->GetImageFactory( resname );
473 factory->AddFactoryObject( fact );
474 return fact;
477 return NULL;
479 default:
480 printf( "\n" );
481 printMessage( "KEYImporter", " ", WHITE );
482 printf( "%s files are not supported.\n", core->TypeExt( type ) );
483 return NULL;