1 /***************************************************************************
2 rpgitem.cpp - Item class
3 -------------------
4 begin : Sun Sep 28 2003
5 copyright : (C) 2003 by Gabor Torok
6 email : cctorok@yahoo.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "../common/constants.h"
18 #include "rpgitem.h"
19 #include "spell.h"
20 #include "monster.h"
21 #include "../session.h"
22 #include "../shapepalette.h"
23
24 using namespace std;
25
26 // ###### MS Visual C++ specific ######
27 #if defined(_MSC_VER) && defined(_DEBUG)
28 # define new DEBUG_NEW
29 # undef THIS_FILE
30 static char THIS_FILE[] = __FILE__;
31 #endif
32
33 RpgItem *RpgItem::items[1000];
34
35 // the smaller this number the more likely a container will show up in a room
36 #define CONTAINER_CHANCE 10.0f
37
38 map<int, map<int, vector<const RpgItem*>*>*> RpgItem::typesMap;
39 map<string, const RpgItem *> RpgItem::itemsByName;
40 vector<RpgItem*> RpgItem::containers;
41 vector<RpgItem*> RpgItem::containersNS;
42 vector<RpgItem*> RpgItem::special;
43 int RpgItem::itemCount = 0;
44 std::vector<ItemType> RpgItem::itemTypes;
45 int RpgItem::randomTypes[ITEM_TYPE_COUNT];
46 int RpgItem::randomTypeCount = 0;
47 std::map<std::string, std::string> RpgItem::tagsDescriptions;
48 char *RpgItem::DAMAGE_TYPE_NAME[] = {
49 N_( "Slashing" ),
50 N_( "Piercing" ),
51 N_( "Crushing" )
52 };
53 char RpgItem::DAMAGE_TYPE_LETTER[] = { 'S', 'P', 'C' };
54 //char *RpgItem::influenceTypeName[] = { "AP", "CTH", "DAM" };
55 map<int, vector<string> *> RpgItem::soundMap;
56
57 namespace {
58
59 class Mop {
60 public:
Mop()61 Mop() {}
~Mop()62 ~Mop() {
63 RpgItem::DestroyStatics();
64 }
65 };
66
67 Mop mop;
68
69 }
70
71
72
RpgItem(char * name,char * displayName,int rareness,int type,float weight,int price,char * desc,char * shortDesc,int equip,int shape_index,int minDepth,int minLevel,int maxCharges,int iconTileX,int iconTileY)73 RpgItem::RpgItem( char *name, char *displayName,
74 int rareness, int type, float weight, int price,
75 char *desc, char *shortDesc, int equip, int shape_index,
76 int minDepth, int minLevel,
77 int maxCharges,
78 int iconTileX, int iconTileY ) {
79 this->name = name;
80 this->displayName = displayName;
81 this->rareness = rareness;
82 this->type = type;
83 this->weight = weight;
84 this->price = price;
85 this->desc = desc;
86 this->shortDesc = shortDesc;
87 this->shape_index = shape_index;
88 this->equip = equip;
89 this->minDepth = minDepth;
90 this->minLevel = minLevel;
91 this->maxCharges = maxCharges;
92 this->iconTileX = iconTileX;
93 this->iconTileY = iconTileY;
94 this->containerWidth = 0;
95 this->containerHeight = 0;
96 this->containerTexture[0] = 0;
97
98 // initialize the rest to default values
99
100 // weapon
101 damage = damageType = damageSkill = parry = ap = range = twohanded = 0;
102 for ( int i = 0; i < Skill::SKILL_COUNT; i++ ) {
103 for ( int t = 0; t < INFLUENCE_TYPE_COUNT; t++ ) {
104 for ( int r = 0; r < INFLUENCE_LIMIT_COUNT; r++ ) {
105 this->weaponInfluence[i][t][r].limit = -1;
106 this->weaponInfluence[i][t][r].type = 'L';
107 this->weaponInfluence[i][t][r].base = -1;
108 }
109 }
110 }
111
112 // armor
113 for ( int i = 0; i < DAMAGE_TYPE_COUNT; i++ ) {
114 defense[ i ] = 0;
115 }
116 defenseSkill = dodgePenalty = 0;
117
118 // potion
119 potionPower = potionSkill = potionTime = 0;
120
121 // spells
122 spellLevel = 0;
123 }
124
~RpgItem()125 RpgItem::~RpgItem() {
126 }
127
128 // was in Item with following confusing comment:
129 // this should really be in RpgItem but that class can't reference ShapePalette and shapes.
initItems(ShapePalette * shapePal)130 void RpgItem::initItems( ShapePalette *shapePal ) {
131 ConfigLang *config = ConfigLang::load( "config/item.cfg" );
132 initItemTypes( config );
133 initSounds( config );
134 initTags( config );
135 delete config;
136
137 config = ConfigLang::load( "config/weapon.cfg" );
138 initItemEntries( config, shapePal );
139 delete config;
140
141 config = ConfigLang::load( "config/armor.cfg" );
142 initItemEntries( config, shapePal );
143 delete config;
144
145 config = ConfigLang::load( "config/magicitem.cfg" );
146 initItemEntries( config, shapePal );
147 delete config;
148
149 config = ConfigLang::load( "config/otheritem.cfg" );
150 initItemEntries( config, shapePal );
151 delete config;
152 }
153
154
initItemTypes(ConfigLang * config)155 void RpgItem::initItemTypes( ConfigLang *config ) {
156 vector<ConfigNode*> *v = config->getDocument()->
157 getChildrenByName( "types" );
158 vector<ConfigNode*> *vv = ( *v )[0]->
159 getChildrenByName( "type" );
160
161 char tmp[20];
162 for ( unsigned int i = 0; i < vv->size(); i++ ) {
163 ConfigNode *node = ( *vv )[i];
164
165 Session::instance->getGameAdapter()->setUpdate( _( "Loading Items" ), i, vv->size() );
166
167 ItemType itemType;
168 strcpy( itemType.name, node->getValueAsString( "name" ) );
169 itemType.isWeapon = node->getValueAsBool( "isWeapon" );
170 itemType.isArmor = node->getValueAsBool( "isArmor" );
171 itemType.isRandom = node->getValueAsBool( "isRandom" );
172 itemType.isRanged = node->getValueAsBool( "isRanged" );
173 itemType.hasSpell = node->getValueAsBool( "hasSpell" );
174 itemType.isEnchantable = node->getValueAsBool( "isEnchantable" );
175 strcpy( tmp, node->getValueAsString( "defaultDimension" ) );
176 char *p = strtok( tmp, "," );
177 if ( p ) {
178 itemType.backpackWidth = atoi( p );
179 itemType.backpackHeight = atoi( strtok( NULL, "," ) );
180 } else {
181 itemType.backpackWidth = itemType.backpackHeight = 1;
182 }
183 RpgItem::itemTypes.push_back( itemType );
184
185 if ( itemType.isRandom ) {
186 RpgItem::randomTypes[ RpgItem::randomTypeCount++ ] = RpgItem::itemTypes.size() - 1;
187 }
188 }
189 }
190
initSounds(ConfigLang * config)191 void RpgItem::initSounds( ConfigLang *config ) {
192 vector<ConfigNode*> *v = config->getDocument()->
193 getChildrenByName( "sounds" );
194 char tmp[1000];
195 for ( unsigned int i = 0; i < v->size(); i++ ) {
196 ConfigNode *node = ( *v )[i];
197
198 Session::instance->getGameAdapter()->setUpdate( _( "Loading Items" ), i, v->size() );
199
200 strcpy( tmp, node->getValueAsString( "sounds" ) );
201 char *p = strtok( tmp, "," );
202 int type_index = RpgItem::getTypeByName( p );
203 vector<string> *sounds = NULL;
204 if ( soundMap.find( type_index ) != soundMap.end() ) {
205 sounds = soundMap[type_index];
206 } else {
207 sounds = new vector<string>;
208 soundMap[type_index] = sounds;
209 }
210 p = strtok( NULL, "," );
211 while ( p ) {
212 string f = p;
213 sounds->push_back( f );
214 p = strtok( NULL, "," );
215 }
216 }
217 }
218
initTags(ConfigLang * config)219 void RpgItem::initTags( ConfigLang *config ) {
220 vector<ConfigNode*> *v = config->getDocument()->
221 getChildrenByName( "tags" );
222 if ( v ) {
223 ConfigNode *node = ( *v )[0];
224 map<string, ConfigValue*> *values = node->getValues();
225 for ( map<string, ConfigValue*>::iterator e = values->begin(); e != values->end(); ++e ) {
226 string name = e->first;
227 ConfigValue *value = e->second;
228 RpgItem::tagsDescriptions[ name ] = value->getAsString();
229 }
230 }
231 }
232
initItemEntries(ConfigLang * config,ShapePalette * shapePal)233 void RpgItem::initItemEntries( ConfigLang *config, ShapePalette *shapePal ) {
234 vector<ConfigNode*> *v = config->getDocument()->
235 getChildrenByName( "item" );
236
237 char name[255], displayName[255], type[255], shape[255];
238 char long_description[500], short_description[120];
239 char containerTexture[255];
240 char temp[1000];
241 for ( unsigned int i = 0; i < v->size(); i++ ) {
242 ConfigNode *node = ( *v )[i];
243
244 Session::instance->getGameAdapter()->setUpdate( _( "Loading Items" ), i, v->size() );
245
246 // I:rareness,type,weight,price[,shape_index,[backpack_location[,maxCharges[,min_depth[,min_level]]]]]
247 snprintf( name, 255, node->getValueAsString( "name" ) );
248 snprintf( displayName, 255, node->getValueAsString( "display_name" ) );
249 int rareness = toint( node->getValueAsFloat( "rareness" ) );
250 snprintf( type, 255, node->getValueAsString( "type" ) );
251 float weight = node->getValueAsFloat( "weight" );
252 int price = toint( node->getValueAsFloat( "price" ) );
253
254 snprintf( shape, 255, node->getValueAsString( "shape" ) );
255 int backpack_location = toint( node->getValueAsFloat( "inventory_location" ) );
256 int minDepth = toint( node->getValueAsFloat( "min_depth" ) );
257 int minLevel = toint( node->getValueAsFloat( "min_level" ) );
258 int maxCharges = toint( node->getValueAsFloat( "max_charges" ) );
259
260 snprintf( long_description, 500, node->getValueAsString( "description" ) );
261 snprintf( short_description, 120, node->getValueAsString( "short_description" ) );
262
263 int containerWidth = toint( node->getValueAsFloat( "container_width" ) );
264 int containerHeight = toint( node->getValueAsFloat( "container_height" ) );
265 snprintf( containerTexture, 255, node->getValueAsString( "container_texture" ) );
266
267 // I:tileX,tileY ( from data/tiles.bmp, count is 1-based )
268 snprintf( temp, 1000, node->getValueAsString( "icon" ) );
269 int tileX = atoi( strtok( temp, "," ) );
270 int tileY = atoi( strtok( NULL, "," ) );
271
272 // resolve strings
273 int type_index = RpgItem::getTypeByName( type );
274 //cerr << "item: looking for shape: " << shape << endl;
275 int shape_index = shapePal->findShapeIndexByName( shape );
276 //cerr << "\tindex=" << shape_index << endl;
277
278 RpgItem *last = new RpgItem( name, displayName, rareness, type_index, weight, price,
279 long_description, short_description,
280 backpack_location, shape_index,
281 minDepth, minLevel, maxCharges, tileX - 1, tileY - 1 );
282 last->setContainerWidth( containerWidth );
283 last->setContainerHeight( containerHeight );
284 last->setContainerTexture( containerTexture );
285 //GLShape *s = shapePal->findShapeByName(shape);
286 //RpgItem::addItem(last, s->getWidth(), s->getDepth(), s->getHeight() );
287
288 int w, d, h;
289 shapePal->getShapeDimensions( shape, &w, &d, &h );
290 RpgItem::addItem( last, w, d, h );
291
292 last->setSpellLevel( toint( node->getValueAsFloat( "spell_level" ) ) );
293
294 snprintf( temp, 1000, node->getValueAsString( "tags" ) );
295 char *p = strtok( temp, "," );
296 while ( p ) {
297 string s = p;
298 last->addTag( s );
299 p = strtok( NULL, "," );
300 }
301
302 vector<ConfigNode*> *weapons = node->getChildrenByName( "weapon" );
303 if ( weapons != NULL && !weapons->empty() ) {
304 ConfigNode *weapon = ( *weapons )[0];
305
306 int baseDamage = toint( weapon->getValueAsFloat( "damage" ) );
307 const char *p = weapon->getValueAsString( "damage_type" );
308 int damageType = 0;
309 if ( strlen( p ) ) damageType = RpgItem::getDamageTypeForLetter( p[0] );
310 int skill = Skill::getSkillIndexByName( weapon->getValueAsString( "skill" ) );
311 int parry = toint( weapon->getValueAsFloat( "parry" ) );
312 int ap = toint( weapon->getValueAsFloat( "ap" ) );
313 int range = toint( weapon->getValueAsFloat( "range" ) );
314 if ( range < static_cast<int>( MIN_DISTANCE ) ) range = static_cast<int>( MIN_DISTANCE );
315 int twoHanded = toint( weapon->getValueAsFloat( "two_handed" ) );
316 last->setWeapon( baseDamage, damageType, skill, parry, ap, range, twoHanded );
317 }
318
319 vector<ConfigNode*> *armors = node->getChildrenByName( "armor" );
320 if ( armors != NULL && !armors->empty() ) {
321 ConfigNode *armor = ( *armors )[0];
322
323 // A:defense_vs_slashing,defense_vs_piercing,defense_vs_crushing,skill,dodge_penalty
324 int defense[ RpgItem::DAMAGE_TYPE_COUNT ];
325 defense[ RpgItem::DAMAGE_TYPE_SLASHING ] =
326 toint( armor->getValueAsFloat( "slash_defense" ) );
327 defense[ RpgItem::DAMAGE_TYPE_PIERCING ] =
328 toint( armor->getValueAsFloat( "pierce_defense" ) );
329 defense[ RpgItem::DAMAGE_TYPE_CRUSHING ] =
330 toint( armor->getValueAsFloat( "crush_defense" ) );
331 int skill = Skill::getSkillIndexByName( armor->getValueAsString( "skill" ) );
332 int dodgePenalty = toint( armor->getValueAsFloat( "dodge_penalty" ) );
333 last->setArmor( defense, skill, dodgePenalty );
334 }
335
336 vector<ConfigNode*> *potions = node->getChildrenByName( "potion" );
337 if ( potions != NULL && !potions->empty() ) {
338 ConfigNode *potion = ( *potions )[0];
339
340 // power,potionSkill,[potionTimeInMinutes]
341 int power = toint( potion->getValueAsFloat( "power" ) );
342
343
344 char const* potionSkill = potion->getValueAsString( "skill" );
345 int skill = -1;
346 if ( potionSkill != NULL && strlen( potionSkill ) ) {
347 skill = Skill::getSkillIndexByName( potionSkill );
348 if ( skill < 0 ) {
349 // try special potion 'skills' like HP, AC boosts
350 skill = Constants::getPotionSkillByName( potionSkill );
351 if ( skill == -1 ) {
352 cerr << "*** WARNING: cannot find potion_skill: " << potionSkill << endl;
353 }
354 }
355 }
356
357 int time = toint( potion->getValueAsFloat( "time" ) );
358 last->setPotion( power, skill, time );
359 }
360
361 vector<ConfigNode*> *adjustments = node->getChildrenByName( "skill_adjustment" );
362 for ( unsigned int t = 0; adjustments != NULL && t < adjustments->size(); t++ ) {
363 ConfigNode *adjustment = ( *adjustments )[t];
364
365 int skill = Skill::
366 getSkillByName( adjustment-> getValueAsString( "skill" ) )->getIndex();
367
368 last->decodeInfluenceBlock( skill
369 , adjustment->getChildrenByName( "ap" )
370 , AP_INFLUENCE );
371 last->decodeInfluenceBlock( skill
372 , adjustment->getChildrenByName( "armor" )
373 , AP_INFLUENCE );
374 last->decodeInfluenceBlock( skill
375 , adjustment->getChildrenByName( "cth" )
376 , CTH_INFLUENCE );
377 last->decodeInfluenceBlock( skill
378 , adjustment->getChildrenByName( "damage" )
379 , DAM_INFLUENCE );
380 }
381 }
382 }
383
decodeInfluenceBlock(int skill,vector<ConfigNode * > * nodes,int influenceType)384 void RpgItem::decodeInfluenceBlock( int skill, vector<ConfigNode*> *nodes, int influenceType ) {
385 char tmp[300];
386 if ( nodes ) {
387 ConfigNode *node = ( *nodes )[0];
388 for ( int t = 0; t < INFLUENCE_LIMIT_COUNT; t++ ) {
389 strcpy( tmp, node->getValueAsString( t == MIN_INFLUENCE ? "min" : "max" ) );
390 char *p = strtok( tmp, "," );
391 if ( p ) {
392 WeaponInfluence wi;
393 wi.limit = atoi( p ); // ignore (
394 p = strtok( NULL, "," );
395 wi.type = ( !strcmp( p, "linear" ) ? 'L' : 'E' );
396 p = strtok( NULL, "," );
397 wi.base = atof( p );
398 /*
399 cerr << item->getName() << " skill:" << Skill::skills[skill]->getName() <<
400 " influence: "<<
401 ( influenceType == AP_INFLUENCE ? "ap" : ( influenceType == CTH_INFLUENCE ? "cth" : "dam" ) ) <<
402 " " << ( t == MIN_INFLUENCE ? "min" : "max" ) << " " <<
403 "limie=" << wi.limit << " type=" << wi.type << " base=" << wi.base << endl;
404 */
405 setWeaponInfluence( skill, influenceType, t, wi );
406 }
407 }
408 }
409 }
410
getRandomSound()411 const string RpgItem::getRandomSound() {
412 vector<string> *sounds = NULL;
413 if ( soundMap.find( getType() ) != soundMap.end() ) {
414 sounds = soundMap[getType()];
415 }
416 if ( !sounds || sounds->empty() )
417 return string( "" );
418 string s = ( *sounds )[ Util::dice( sounds->size() ) ];
419 return s;
420 }
421
addItem(RpgItem * item,int width,int depth,int height)422 void RpgItem::addItem( RpgItem *item, int width, int depth, int height ) {
423 // store the item
424 /*
425 cerr << "adding item: " << item->name <<
426 " level=" << item->level <<
427 " type=" << item->type << endl;
428 */
429 items[itemCount++] = item;
430
431 if ( !item->isSpecial() ) {
432 // Add item to type->depth maps
433 map<int, vector<const RpgItem*>*> *depthMap = NULL;
434 if ( typesMap.find( item->type ) != typesMap.end() ) {
435 depthMap = typesMap[( const int )( item->type )];
436 } else {
437 depthMap = new map<int, vector<const RpgItem*>*>();
438 typesMap[item->type] = depthMap;
439 }
440 //cerr << "\ttypesMap.size()=" << typesMap.size() << " type=" << item->type << " (" << itemTypes[item->type].name << ")" << endl;
441
442 // create the min depth map: Add item to every depth level >= item->getMinDepth()
443 for ( int currentDepth = item->getMinDepth(); currentDepth < MAX_MISSION_DEPTH; currentDepth++ ) {
444 // create the vector
445 vector<const RpgItem*> *list = NULL;
446 if ( depthMap->find( currentDepth ) != depthMap->end() ) {
447 list = ( *depthMap )[( const int )( currentDepth )];
448 } else {
449 list = new vector<const RpgItem*>();
450 ( *depthMap )[ currentDepth ] = list;
451 }
452 // cerr << "\tlevelMap.size()=" << levelMap->size() << endl;
453 list->push_back( item );
454 // cerr << "\tlist.size()=" << list->size() << endl;
455 }
456 } else {
457 special.push_back( item );
458 }
459
460 // remember by name
461 string s = item->name;
462 itemsByName[s] = item;
463 // cerr << "*** Stored name=>" << item->name << "< item=" << item << endl;
464
465 // HACK: do not include "corpse" as a valid container...
466 // It should really have a container exclusion flag.
467 if ( item->type == CONTAINER && ( item->name != "Corpse" || item->name != "Backpack" ) ) {
468 if ( width >= depth ) {
469 containersNS.push_back( item );
470 }
471 if ( width <= depth ) {
472 containers.push_back( item );
473 }
474 }
475 }
476
getTypeByName(char * name)477 int RpgItem::getTypeByName( char *name ) {
478 for ( int i = 0; i < static_cast<int>( itemTypes.size() ); i++ ) {
479 if ( !strcmp( itemTypes[ i ].name, name ) ) return i;
480 }
481 cerr << "Can't find type >" << name << "< in " << itemTypes.size() << endl;
482 for ( int i = 0; i < static_cast<int>( itemTypes.size() ); i++ ) {
483 cerr << "\t" << itemTypes[ i ].name << endl;
484 }
485 exit( 1 );
486 }
487
getRandomItem(int depth)488 RpgItem *RpgItem::getRandomItem( int depth ) {
489 return getRandomItemFromTypes( depth, randomTypes, randomTypeCount );
490 }
491
getRandomItemFromTypes(int depth,int types[],int typeCount)492 RpgItem *RpgItem::getRandomItemFromTypes( int depth, int types[], int typeCount ) {
493 if ( depth < 0 ) depth = 0;
494 if ( depth >= MAX_MISSION_DEPTH ) depth = MAX_MISSION_DEPTH - 1;
495
496 int typeIndex = Util::dice( typeCount );
497 map<int, vector<const RpgItem*>*> *depthMap = typesMap[types[typeIndex]];
498 if ( depthMap && !depthMap->empty() ) {
499
500 // Select this depth's list of items. Since an item is on every list
501 // greater than equal to its min. depth, we don't have to roll for
502 // a depth value. (Eg.: a item w. minDepth=2 will be on lists 2-10.
503 vector<const RpgItem*> *list = ( *depthMap )[depth];
504
505 if ( list && !list->empty() ) {
506
507 // create a new list where each item occurs item->rareness times
508 vector<RpgItem*> rareList;
509 for ( int i = 0; i < static_cast<int>( list->size() ); i++ ) {
510 RpgItem *item = ( RpgItem* )( *list )[i];
511 for ( int t = 0; t < item->getRareness(); t++ ) {
512 rareList.push_back( item );
513 }
514 }
515
516 int n = Util::dice( rareList.size() );
517 RpgItem *rpgItem = ( RpgItem* )rareList[n];
518 return rpgItem;
519 }
520 }
521 return NULL;
522 }
523
getRandomContainer()524 RpgItem *RpgItem::getRandomContainer() {
525 int n = static_cast<int>( Util::roll( 0.0f, CONTAINER_CHANCE * containers.size() ) );
526 if ( n >= static_cast<int>( containers.size() ) )
527 return NULL;
528 return containers[n];
529 }
530
getRandomContainerNS()531 RpgItem *RpgItem::getRandomContainerNS() {
532 int n = static_cast<int>( Util::roll( 0.0f, CONTAINER_CHANCE * containersNS.size() ) );
533 if ( n >= static_cast<int>( containersNS.size() ) ) return NULL;
534 return containersNS[n];
535 }
536
getItemByName(char const * name)537 RpgItem *RpgItem::getItemByName( char const* name ) {
538 string s = name;
539 RpgItem *item = ( RpgItem * )itemsByName[s];
540 // cerr << "*** Looking for >" << s << "< found=" << item << endl;
541 return item;
542 }
543
getTagDescription(string tag)544 const char *RpgItem::getTagDescription( string tag ) {
545 if ( RpgItem::tagsDescriptions.find( tag ) != RpgItem::tagsDescriptions.end() ) {
546 return tagsDescriptions[ tag ].c_str();
547 } else {
548 return tag.c_str();
549 }
550 }
551
setWeaponInfluence(int skill,int type,int limit,WeaponInfluence influence)552 void RpgItem::setWeaponInfluence( int skill, int type, int limit, WeaponInfluence influence ) {
553 weaponInfluence[skill][type][limit].limit = influence.limit;
554 weaponInfluence[skill][type][limit].type = influence.type;
555 weaponInfluence[skill][type][limit].base = influence.base;
556 }
557
getWeaponInfluence(int skill,int type,int limit)558 WeaponInfluence *RpgItem::getWeaponInfluence( int skill, int type, int limit ) {
559 return &( weaponInfluence[skill][type][limit] );
560 }
561
getDamageTypeForLetter(char c)562 int RpgItem::getDamageTypeForLetter( char c ) {
563 for ( int i = 0; i < DAMAGE_TYPE_COUNT; i++ ) {
564 //if( _( DAMAGE_TYPE_NAME[ i ] )[0] == c ) return i;
565 if ( DAMAGE_TYPE_LETTER[ i ] == c ) return i;
566 }
567 std::cerr << "*** Error can't find damage type for letter: " << c << std::endl;
568 return DAMAGE_TYPE_SLASHING;
569 }
570
getDamageTypeLetter(int type)571 char RpgItem::getDamageTypeLetter( int type ) {
572 return _( DAMAGE_TYPE_NAME[ type ] )[0];
573 }
574
575
DestroyStatics()576 void RpgItem::DestroyStatics() {
577 // typesMap clear.
578 typedef std::vector<const RpgItem*> ItemVec;
579 typedef std::map<int, ItemVec*> TypeMap;
580 typedef std::map<int, TypeMap*> TypeMapMap;
581 for ( TypeMapMap::iterator itmm = typesMap.begin(); itmm != typesMap.end(); ++itmm ) {
582 for ( TypeMap::iterator itm = itmm->second->begin(); itm != itmm->second->end(); ++itm ) {
583 delete itm->second;
584 }
585 delete itmm->second;
586 }
587 typesMap.clear();
588 // items clear.
589 for ( int i = 0; i < itemCount; ++i ) {
590 delete items[i];
591 }
592 // soundMap clear.
593 typedef std::vector<std::string> StrVec;
594 typedef std::map<int, StrVec *> SoundMap;
595 for ( SoundMap::iterator ism = soundMap.begin(); ism != soundMap.end(); ++ism ) {
596 delete ism->second;
597 }
598 soundMap.clear();
599 }
600