Move EventMgr to GUI.
[gemrb.git] / gemrb / core / GameData.cpp
blob27b066120754c48d86663b7c0448ec8a5366e56d
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 "GameData.h"
23 #include "ActorMgr.h"
24 #include "AnimationMgr.h"
25 #include "Cache.h"
26 #include "Effect.h"
27 #include "EffectMgr.h"
28 #include "Factory.h"
29 #include "FileStream.h"
30 #include "Game.h"
31 #include "ImageFactory.h"
32 #include "ImageMgr.h"
33 #include "Interface.h"
34 #include "Item.h"
35 #include "ItemMgr.h"
36 #include "ResourceDesc.h"
37 #include "Spell.h"
38 #include "SpellMgr.h"
39 #include "Scriptable/Actor.h"
41 #include <cstdio>
43 static void ReleaseItem(void *poi)
45 delete ((Item *) poi);
48 static void ReleaseSpell(void *poi)
50 delete ((Spell *) poi);
53 static void ReleaseEffect(void *poi)
55 delete ((Effect *) poi);
58 static void ReleasePalette(void *poi)
60 //we allow nulls, but we shouldn't release them
61 if (!poi) return;
62 //as long as palette has its own refcount, this should be Release
63 ((Palette *) poi)->Release();
66 GEM_EXPORT GameData* gamedata;
68 GameData::GameData()
70 factory = new Factory();
73 GameData::~GameData()
75 delete factory;
78 void GameData::ClearCaches()
80 ItemCache.RemoveAll(ReleaseItem);
81 SpellCache.RemoveAll(ReleaseSpell);
82 EffectCache.RemoveAll(ReleaseEffect);
83 PaletteCache.RemoveAll(ReleasePalette);
86 Actor *GameData::GetCreature(const char* ResRef, unsigned int PartySlot)
88 DataStream* ds = GetResource( ResRef, IE_CRE_CLASS_ID );
89 if (!ds)
90 return 0;
92 PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
93 if (!actormgr->Open( ds, true )) {
94 return 0;
96 Actor* actor = actormgr->GetActor(PartySlot);
97 return actor;
100 int GameData::LoadCreature(const char* ResRef, unsigned int PartySlot, bool character)
102 DataStream *stream;
104 Actor* actor;
105 if (character) {
106 char nPath[_MAX_PATH], fName[16];
107 snprintf( fName, sizeof(fName), "%s.chr", ResRef);
108 PathJoin( nPath, core->GamePath, "characters", fName, NULL );
109 FileStream *fs = new FileStream();
110 fs -> Open( nPath, true );
111 stream = (DataStream *) fs;
112 PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
113 if (!actormgr->Open( stream, true )) {
114 return -1;
116 actor = actormgr->GetActor(PartySlot);
117 } else {
118 actor = GetCreature(ResRef, PartySlot);
121 if ( !actor ) {
122 return -1;
125 //both fields are of length 9, make this sure!
126 memcpy(actor->Area, core->GetGame()->CurrentArea, sizeof(actor->Area) );
127 if (actor->BaseStats[IE_STATE_ID] & STATE_DEAD) {
128 actor->SetStance( IE_ANI_TWITCH );
129 } else {
130 actor->SetStance( IE_ANI_AWAKE );
132 actor->SetOrientation( 0, false );
134 if ( PartySlot != 0 ) {
135 return core->GetGame()->JoinParty( actor, JP_JOIN|JP_INITPOS );
137 else {
138 return core->GetGame()->AddNPC( actor );
142 /** Loads a 2DA Table, returns -1 on error or the Table Index on success */
143 int GameData::LoadTable(const ieResRef ResRef)
145 int ind = GetTableIndex( ResRef );
146 if (ind != -1) {
147 tables[ind].refcount++;
148 return ind;
150 //printf("(%s) Table not found... Loading from file\n", ResRef);
151 DataStream* str = GetResource( ResRef, IE_2DA_CLASS_ID );
152 if (!str) {
153 return -1;
155 PluginHolder<TableMgr> tm(IE_2DA_CLASS_ID);
156 if (!tm) {
157 delete str;
158 return -1;
160 if (!tm->Open( str, true )) {
161 return -1;
163 Table t;
164 t.refcount = 1;
165 strncpy( t.ResRef, ResRef, 8 );
166 t.tm = tm;
167 ind = -1;
168 for (size_t i = 0; i < tables.size(); i++) {
169 if (tables[i].refcount == 0) {
170 ind = ( int ) i;
171 break;
174 if (ind != -1) {
175 tables[ind] = t;
176 return ind;
178 tables.push_back( t );
179 return ( int ) tables.size() - 1;
181 /** Gets the index of a loaded table, returns -1 on error */
182 int GameData::GetTableIndex(const char* ResRef) const
184 for (size_t i = 0; i < tables.size(); i++) {
185 if (tables[i].refcount == 0)
186 continue;
187 if (strnicmp( tables[i].ResRef, ResRef, 8 ) == 0)
188 return ( int ) i;
190 return -1;
192 /** Gets a Loaded Table by its index, returns NULL on error */
193 Holder<TableMgr> GameData::GetTable(unsigned int index) const
195 if (index >= tables.size()) {
196 return NULL;
198 if (tables[index].refcount == 0) {
199 return NULL;
201 return tables[index].tm;
204 /** Frees a Loaded Table, returns false on error, true on success */
205 bool GameData::DelTable(unsigned int index)
207 if (index==0xffffffff) {
208 tables.clear();
209 return true;
211 if (index >= tables.size()) {
212 return false;
214 if (tables[index].refcount == 0) {
215 return false;
217 tables[index].refcount--;
218 if (tables[index].refcount == 0)
219 if (tables[index].tm)
220 tables[index].tm.release();
221 return true;
224 Palette *GameData::GetPalette(const ieResRef resname)
226 Palette *palette = (Palette *) PaletteCache.GetResource(resname);
227 if (palette) {
228 return palette;
230 //additional hack for allowing NULL's
231 if (PaletteCache.RefCount(resname)!=-1) {
232 return NULL;
234 ResourceHolder<ImageMgr> im(resname);
235 if (im == NULL) {
236 PaletteCache.SetAt(resname, NULL);
237 return NULL;
240 palette = new Palette();
241 im->GetPalette(256,palette->col);
242 palette->named=true;
243 PaletteCache.SetAt(resname, (void *) palette);
244 return palette;
247 void GameData::FreePalette(Palette *&pal, const ieResRef name)
249 int res;
251 if (!pal) {
252 return;
254 if (!name || !name[0]) {
255 if(pal->named) {
256 printf("Palette is supposed to be named, but got no name!\n");
257 abort();
258 } else {
259 pal->Release();
260 pal=NULL;
262 return;
264 if (!pal->named) {
265 printf("Unnamed palette, it should be %s!\n", name);
266 abort();
268 res=PaletteCache.DecRef((void *) pal, name, true);
269 if (res<0) {
270 printMessage( "Core", "Corrupted Palette cache encountered (reference count went below zero), ", LIGHT_RED );
271 printf( "Palette name is: %.8s\n", name);
272 abort();
274 if (!res) {
275 pal->Release();
277 pal = NULL;
280 Item* GameData::GetItem(const ieResRef resname)
282 Item *item = (Item *) ItemCache.GetResource(resname);
283 if (item) {
284 return item;
286 DataStream* str = GetResource( resname, IE_ITM_CLASS_ID );
287 PluginHolder<ItemMgr> sm(IE_ITM_CLASS_ID);
288 if (!sm) {
289 delete ( str );
290 return NULL;
292 if (!sm->Open( str, true )) {
293 return NULL;
296 item = new Item();
297 //this is required for storing the 'source'
298 strnlwrcpy(item->Name, resname, 8);
299 sm->GetItem( item );
300 if (item == NULL) {
301 return NULL;
304 ItemCache.SetAt(resname, (void *) item);
305 return item;
308 //you can supply name for faster access
309 void GameData::FreeItem(Item const *itm, const ieResRef name, bool free)
311 int res;
313 res=ItemCache.DecRef((void *) itm, name, free);
314 if (res<0) {
315 printMessage( "Core", "Corrupted Item cache encountered (reference count went below zero), ", LIGHT_RED );
316 printf( "Item name is: %.8s\n", name);
317 abort();
319 if (res) return;
320 if (free) delete itm;
323 Spell* GameData::GetSpell(const ieResRef resname, bool silent)
325 Spell *spell = (Spell *) SpellCache.GetResource(resname);
326 if (spell) {
327 return spell;
329 DataStream* str = GetResource( resname, IE_SPL_CLASS_ID, silent );
330 PluginHolder<SpellMgr> sm(IE_SPL_CLASS_ID);
331 if (!sm) {
332 delete ( str );
333 return NULL;
335 if (!sm->Open( str, true )) {
336 return NULL;
339 spell = new Spell();
340 //this is required for storing the 'source'
341 strnlwrcpy(spell->Name, resname, 8);
342 sm->GetSpell( spell, silent );
343 if (spell == NULL) {
344 return NULL;
347 SpellCache.SetAt(resname, (void *) spell);
348 return spell;
351 void GameData::FreeSpell(Spell *spl, const ieResRef name, bool free)
353 int res;
355 res=SpellCache.DecRef((void *) spl, name, free);
356 if (res<0) {
357 printMessage( "Core", "Corrupted Spell cache encountered (reference count went below zero), ", LIGHT_RED );
358 printf( "Spell name is: %.8s or %.8s\n", name, spl->Name);
359 abort();
361 if (res) return;
362 if (free) delete spl;
365 Effect* GameData::GetEffect(const ieResRef resname)
367 Effect *effect = (Effect *) EffectCache.GetResource(resname);
368 if (effect) {
369 return effect;
371 DataStream* str = GetResource( resname, IE_EFF_CLASS_ID );
372 PluginHolder<EffectMgr> em(IE_EFF_CLASS_ID);
373 if (!em) {
374 delete ( str );
375 return NULL;
377 if (!em->Open( str, true )) {
378 return NULL;
381 effect = em->GetEffect(new Effect() );
382 if (effect == NULL) {
383 return NULL;
386 EffectCache.SetAt(resname, (void *) effect);
387 return effect;
390 void GameData::FreeEffect(Effect *eff, const ieResRef name, bool free)
392 int res;
394 res=EffectCache.DecRef((void *) eff, name, free);
395 if (res<0) {
396 printMessage( "Core", "Corrupted Effect cache encountered (reference count went below zero), ", LIGHT_RED );
397 printf( "Effect name is: %.8s\n", name);
398 abort();
400 if (res) return;
401 if (free) delete eff;
404 //if the default setup doesn't fit for an animation
405 //create a vvc for it!
406 ScriptedAnimation* GameData::GetScriptedAnimation( const char *effect, bool doublehint)
408 ScriptedAnimation *ret = NULL;
410 if (Exists( effect, IE_VVC_CLASS_ID ) ) {
411 DataStream *ds = GetResource( effect, IE_VVC_CLASS_ID );
412 ret = new ScriptedAnimation(ds, true);
413 } else {
414 AnimationFactory *af = (AnimationFactory *)
415 GetFactoryResource( effect, IE_BAM_CLASS_ID, IE_NORMAL );
416 if (af) {
417 ret = new ScriptedAnimation();
418 ret->LoadAnimationFactory( af, doublehint?2:0);
421 if (ret) {
422 strnlwrcpy(ret->ResName, effect, 8);
424 return ret;
427 // Return single BAM frame as a sprite. Use if you want one frame only,
428 // otherwise it's not efficient
429 Sprite2D* GameData::GetBAMSprite(const ieResRef ResRef, int cycle, int frame)
431 Sprite2D *tspr;
432 AnimationFactory* af = ( AnimationFactory* )
433 GetFactoryResource( ResRef, IE_BAM_CLASS_ID, IE_NORMAL );
434 if (!af) return 0;
435 if (cycle == -1)
436 tspr = af->GetFrameWithoutCycle( (unsigned short) frame );
437 else
438 tspr = af->GetFrame( (unsigned short) frame, (unsigned char) cycle );
439 return tspr;
442 void* GameData::GetFactoryResource(const char* resname, SClass_ID type,
443 unsigned char mode, bool silent)
445 int fobjindex = factory->IsLoaded(resname,type);
446 // already cached
447 if ( fobjindex != -1)
448 return factory->GetFactoryObject( fobjindex );
450 // empty resref
451 if (!strcmp(resname, ""))
452 return NULL;
454 switch (type) {
455 case IE_BAM_CLASS_ID:
457 DataStream* ret = GetResource( resname, type, silent );
458 if (ret) {
459 PluginHolder<AnimationMgr> ani(IE_BAM_CLASS_ID);
460 if (!ani)
461 return NULL;
462 ani->Open( ret, true );
463 AnimationFactory* af = ani->GetAnimationFactory( resname, mode );
464 factory->AddFactoryObject( af );
465 return af;
467 return NULL;
469 case IE_BMP_CLASS_ID:
471 ResourceHolder<ImageMgr> img(resname);
472 if (img) {
473 ImageFactory* fact = img->GetImageFactory( resname );
474 factory->AddFactoryObject( fact );
475 return fact;
478 return NULL;
480 default:
481 printf( "\n" );
482 printMessage( "KEYImporter", " ", WHITE );
483 printf( "%s files are not supported.\n", core->TypeExt( type ) );
484 return NULL;