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