/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@falcon.mercer.peachnet.edu
MUD++ development mailing list mudpp-list@spice.com
------------------------------------------------------------------------------
object.cc
*/
#include "io.h"
#include "string.h"
#include "index.h"
#include "indexable.h"
#include "room.h"
#include "llist.h"
#include "repop.h"
#include "bit.h"
#include "spell.h"
#include "affect.h"
#include "combat.h"
#include "char.h"
#include "area.h"
#include "object.h"
#include "global.h"
// All wear locations are not possible for example
// if you are double wielding, then no light or shield
const bitType wear_bit_list[] =
{
{"undefined", WEAR_NONE },
{"head", WEAR_HEAD },
{"neck", WEAR_NECK },
{"back", WEAR_BACK },
{"body", WEAR_BODY },
{"arms", WEAR_ARMS },
{"wrist", WEAR_WRIST },
{"hands", WEAR_HANDS },
{"held", WEAR_HOLD },
{"finger", WEAR_FINGER },
{"waist", WEAR_WAIST },
{"legs", WEAR_LEGS },
{"feet", WEAR_FEET },
{"shield", WEAR_SHIELD },
{"wield", WEAR_WIELD },
{0, 0}
};
const bitType obj_bit_list[] =
{
{"unused", OBJ_UNUSED },
{"invisible", OBJ_INVISIBLE },
{"hidden", OBJ_HIDDEN },
{"notake", OBJ_NOTAKE },
{"nodrop", OBJ_NODROP },
{"edible", OBJ_EDIBLE },
{"nosave", OBJ_NOSAVE },
{"good", OBJ_GOOD },
{"evil", OBJ_EVIL },
{"antigood", OBJ_ANTIGOOD },
{"antievil", OBJ_ANTIEVIL },
{"antineutral", OBJ_ANTINEUTRAL },
{"magic", OBJ_MAGIC },
{"glow", OBJ_GLOW },
{"sanctuary", OBJ_SANCTUARY },
{"poisoned", OBJ_POISONED },
{0, 0}
};
const bitType obj_type_list[] =
{
{"unused", ITEM_UNUSED },
{"trash", ITEM_TRASH },
{"jewel", ITEM_JEWEL },
{"gold", ITEM_GOLD },
{"container", ITEM_CONTAINER },
{"liquid-container", ITEM_LIQUID_CONTAINER },
{"armor", ITEM_ARMOR },
{"cloth", ITEM_CLOTH },
{"weapon", ITEM_WEAPON },
{"staff", ITEM_STAFF },
{"wand", ITEM_WAND },
{"orb", ITEM_ORB },
{"corpse", ITEM_CORPSE },
{"energy", ITEM_ENERGY },
{"scroll", ITEM_SCROLL },
{"potion", ITEM_POTION },
{"food", ITEM_FOOD },
{"key", ITEM_KEY },
{"staff", ITEM_STAFF },
{0, 0}
};
const bitType dam_types[] =
{
{"none", NONE },
{"punch", PUNCH },
{"kick", KICK },
{"crush", CRUSH },
{"pierce", PIERCE },
{"slash", SLASH },
{"whip", WHIP },
{0, 0 }
};
const char *wear_pos_list[] =
{
"undefined",
"<worn on head>",
"<worn on face>",
"<worn on neck>",
"<worn on neck>",
"<worn on back>",
"<worn on body>",
"<worn on arms>",
"<worn on left wrist>",
"<worn on right wrist>",
"<worn on hands>",
"<held in left>",
"<held in right>",
"<worn on left finger>",
"<worn on right finger>",
"<worn on waist>",
"<worn on legs>",
"<worn on feet>",
"<shield left>",
"<shield right>",
"<wielded left>",
"<wielded right>",
""
};
Object::~Object()
{
// Extract and destroy all objects inside this one
// Add a bug check here later if non-containers have inv
Object *obj;
while( ( obj = inv.remove() ) )
{
// remove from global list
obj->fromWorld();
// deleting obj destroys any objects inside obj if it is container
delete obj;
}
if( repop )
repop->setPtr( 0 );
}
// Remove all links between object and world
// After extract we can safely do anything with object that
// we want including deleting it. This could all be in the
// destructor but my opinion on self-removing destructor methods
// is they cause more bugs than they are worth.
void Object::extract()
{
if( in_room )
in_room->inv.remove( this );
else if( in_obj )
in_obj->rmObjInv( this );
else if( in_char )
in_char->inv.remove( this );
objects.remove( this );
}
int Object::readProtoFrom( InFile &in )
{
char buf[ BUF ];
if( *in.getword( buf ) != '{' )
{
in.error( "Object::ReadFromFile() - expected '{' not found." );
}
setName( in.getstring( buf ) );
setShort( in.getstring( buf ) );
setLong( in.getstring( buf ) );
in.getword( buf );
obj_type = getObjType( buf );
// The items are grouped by type for future expansion
// because I know they will begin to differ soon.
switch( obj_type )
{
case ITEM_KEY:
default:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_WEAPON:
in.getword( buf );
value[0] = getDamType( buf );
if( value[0] == NONE )
{
Cout << "BUG: Invalid dam type " << buf << " for " << getShort() << endl;
}
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_FOOD:
case ITEM_ARMOR:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_ORB:
case ITEM_WAND:
case ITEM_STAFF:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_SCROLL:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
in.getstring( buf );
value[ 6 ] = 0; // (long) languageLookup( in.getstring( buf ) );
break;
case ITEM_POTION:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
}
in.getbitfield( obj_bits );
in.getbitfield( wear_bits );
in.getnum(); // security for now
cost = in.getnum();
weight = in.getnum();
/*level = */ in.getnum();
Spell *sp;
Modifier *mod;
Affect *aff;
int modAmt;
int modLoc;
// int spellLevel;
while( 1 )
{
switch( *in.getword( buf ) )
{
case '}': return 0;
// Affect
case 'A': in.getword( buf );
in.getstring( buf );
in.getnum();
in.getword( buf );
continue;
// Spell
case 'S': in.getword( buf );
in.getstring( buf );
/* spellLevel = */ in.getnum();
sp = (Spell *)lookupSpell( buf );
spells.add( sp );
in.getword( buf );
continue;
// Modifier
case 'M': in.getword( buf );
in.getword( buf );
modAmt = in.getnum();
if( ( modLoc = getModType( buf ) ) != -1 )
{
mod = new Modifier( modLoc, modAmt );
mods.addTop( mod );
}
in.getword( buf );
continue;
default:
in.error( "Object::ReadFromFile() - expected '}' at end of Object." );
}
}
return 0;
}
// Differs from readProtoFrom()
// readFrom reads a persistent object with such values
// as timer, charges, etc. which aren't stored in the prototype
int Object::readFrom( InFile &in )
{
char buf[ BUF ];
if( *in.getword( buf ) != '{' )
{
in.error( "Object::ReadFromFile() - expected '{' not found." );
}
setName( in.getstring( buf ) );
setShort( in.getstring( buf ) );
setLong( in.getstring( buf ) );
in.getword( buf );
obj_type = getObjType( buf );
// The items are grouped by type for future expansion
// because I know they will begin to differ soon.
switch( obj_type )
{
case ITEM_KEY:
default:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_WEAPON:
in.getword( buf );
value[0] = getDamType( buf );
if( value[0] == NONE )
{
Cout << "BUG: Invalid dam type " << buf << " for " << getShort() << endl;
}
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_FOOD:
case ITEM_ARMOR:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_ORB:
case ITEM_WAND:
case ITEM_STAFF:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
case ITEM_SCROLL:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
in.getstring( buf );
value[ 6 ] = 0; // (long) languageLookup( in.getstring( buf ) );
break;
case ITEM_POTION:
value[ 0 ] = in.getnum();
value[ 1 ] = in.getnum();
value[ 2 ] = in.getnum();
value[ 3 ] = in.getnum();
value[ 4 ] = in.getnum();
value[ 5 ] = in.getnum();
value[ 6 ] = in.getnum();
break;
}
in.getbitfield( obj_bits );
in.getbitfield( wear_bits );
in.getnum(); // security for now
cost = in.getnum();
weight = in.getnum();
/*level = */ in.getnum();
// Persistent values
timer = in.getnum();
wear_pos = in.getnum();
// end
Spell *sp;
Modifier *mod;
Affect *aff;
int modAmt;
int modLoc;
// int spellLevel;
while( 1 )
{
switch( *in.getword( buf ) )
{
case '}': return 0;
// Affect
case 'A': in.getword( buf );
in.getstring( buf );
in.getnum();
in.getword( buf );
continue;
// Spell
case 'S': in.getword( buf );
in.getstring( buf );
/* spellLevel = */ in.getnum();
sp = (Spell *)lookupSpell( buf );
spells.add( sp );
in.getword( buf );
continue;
// Modifier
case 'M': in.getword( buf );
in.getword( buf );
modAmt = in.getnum();
if( ( modLoc = getModType( buf ) ) != -1 )
{
mod = new Modifier( modLoc, modAmt );
mods.addTop( mod );
}
in.getword( buf );
continue;
default:
in.error( "Object::ReadFromFile() - expected '}' at end of Object." );
}
}
return 0;
}
int Object::writeProtoTo( OutFile &out ) const
{
out << "{" << endl;
out << name << TERM_CHAR << endl;
out << shortdesc << TERM_CHAR << endl;
out << longdesc << TERM_CHAR << endl;
out << getObjTypeName( obj_type ) << endl;
switch( obj_type )
{
case ITEM_KEY:
default:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_WEAPON:
out << getDamTypeName( value[ 0 ] ) << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_FOOD:
case ITEM_ARMOR:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_ORB:
case ITEM_WAND:
case ITEM_STAFF:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_SCROLL:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< "none~" // value[ 6 ]
<< endl;
break;
case ITEM_POTION:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
}
out.putbitfield( obj_bits, MAX_OBJ_BIT_FIELDS );
out << endl;
out.putbitfield( wear_bits, MAX_WEAR_BIT_FIELDS );
out << endl;
out << 1 /* security */ << " " << cost << " " << weight << " "
<< 1 /*level*/ << " " << endl;
Spell *sp;
spells.reset();
while( ( sp = spells.peek() ) )
{
spells.next();
out << "S{" << sp->getName() << "~}\n";
}
Modifier *mod;
mods.reset();
while( ( mod = mods.peek() ) )
{
mods.next();
out << "M{" << mod->getName() << ' ' << mod->getAmt() << "}\n";
}
Affect *aff;
affects.reset();
while( ( aff = affects.peek() ) )
{
affects.next();
out << "A{~ -1}\n";
}
out << "}" << endl;
return 1;
}
// Write a persistent object to file, use readFrom()
// to reload object, not readProtoFrom()
int Object::writeTo( OutFile &out ) const
{
out << "{" << endl;
out << name << TERM_CHAR << endl;
out << shortdesc << TERM_CHAR << endl;
out << longdesc << TERM_CHAR << endl;
out << getObjTypeName( obj_type ) << endl;
switch( obj_type )
{
case ITEM_KEY:
default:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_WEAPON:
out << getDamTypeName( value[ 0 ] ) << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_FOOD:
case ITEM_ARMOR:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_ORB:
case ITEM_WAND:
case ITEM_STAFF:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
case ITEM_SCROLL:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< "none~" // value[ 6 ]
<< endl;
break;
case ITEM_POTION:
out << value[ 0 ] << ' '
<< value[ 1 ] << ' '
<< value[ 2 ] << ' '
<< value[ 3 ] << ' '
<< value[ 4 ] << ' '
<< value[ 5 ] << ' '
<< value[ 6 ] << ' '
<< endl;
break;
}
out.putbitfield( obj_bits, MAX_OBJ_BIT_FIELDS );
out << endl;
out.putbitfield( wear_bits, MAX_WEAR_BIT_FIELDS );
out << endl;
out << 1 /* security */ << " " << cost << " " << weight << " "
<< 1 /*level*/ << " " << endl;
// Write persistent data
out << timer << ' ' << wear_pos << endl;
// end
Spell *sp;
spells.reset();
while( ( sp = spells.peek() ) )
{
spells.next();
out << "S{" << sp->getName() << "~}\n";
}
Modifier *mod;
mods.reset();
while( ( mod = mods.peek() ) )
{
mods.next();
out << "M{" << mod->getName() << ' ' << mod->getAmt() << "}\n";
}
Affect *aff;
affects.reset();
while( ( aff = affects.peek() ) )
{
affects.next();
out << "A{~ -1}\n";
}
out << "}" << endl;
return 1;
}
const char *Object::showWearBits()
{
static char buf[ BUF ];
*buf = '\0';
for( int i = 0; wear_bit_list[ i ].name; i++ )
{
if( IS_SET( wear_bits, wear_bit_list[ i ].val ) )
sprintf( buf+strlen(buf), "(%s)", wear_bit_list[ i ].name );
}
return buf;
}
const char *Object::typeName()
{
return getObjTypeName( obj_type );
}
int Object::getType()
{
return obj_type;
}
void Object::setType( int type )
{
obj_type = type;
}
bool Object::isWearable()
{
for( int i = 0; i < MAX_WEAR_BIT_FIELDS; i++ )
if( wear_bits[ i ] )
return true;
return false;
}
int Object::wearBit( int bit )
{
return IS_SET( wear_bits, bit );
}
void Object::toggleWearBit( int bit )
{
TOGGLE_BIT( wear_bits, bit );
}
void Object::setWearPos( int pos )
{
if( pos <= EQ_MAX )
wear_pos = pos;
}
int Object::wearPos()
{
return wear_pos;
}
int Object::worn()
{
return wearPos();
}
void Object::fromChar()
{
#ifdef DEBUG
if( !inChar() )
{
Cout << "BUG: Object::fromChar - not carried.\n";
return;
}
#endif
in_char = 0;
}
void Object::toChar( Char *ch )
{
#ifdef DEBUG
if( inRoom() || inChar() || inObj() )
{
Cout << "BUG: Object::toChar - already owned.\n";
return;
}
#endif
in_char = ch;
}
void Object::fromRoom()
{
#ifdef DEBUG
if( !inRoom() )
{
Cout << "BUG: Object::fromRoom - not in room.\n";
return;
}
#endif
in_room = 0;
}
void Object::toRoom( Room *toRoom )
{
#ifdef DEBUG
if( inRoom() || inChar() || inObj() )
{
Cout << "BUG: Object::toRoom - already owned.\n";
return;
}
#endif
in_room = toRoom;
}
// Leave to caller to assert obj isObject
void Object::toObj( Object * obj )
{
#ifdef DEBUG
if( inRoom() || inChar() || inObj() )
{
Cout << "BUG: Object::toObj - already owned.\n";
return;
}
#endif
in_obj = obj;
}
void Object::fromObj()
{
#ifdef DEBUG
if( !inObj() )
{
Cout << "BUG: Object::fromObj - not in object.\n";
return;
}
#endif
in_obj = 0;
}
void Object::toWorld()
{
objects.add( this );
}
void Object::fromWorld()
{
objects.remove( this );
}
void Object::addObjInv( Object * obj )
{
obj->toObj( this );
weight += obj->getWeight();
inv.add( obj );
}
Object * Object::getObjInv( const char * str )
{
Object * obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
if( obj->isName( str ) )
return obj;
}
return 0;
}
Object * Object::getObjInv( const String & str )
{
Object * obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
if( obj->isName( str ) )
return obj;
}
return 0;
}
void Object::rmObjInv( Object * obj )
{
obj->fromObj();
weight -= obj->getWeight();
inv.remove( obj );
}
void Object::resetInv()
{
inv.reset();
}
Object * Object::getCurObjInv()
{
return inv.peek();
}
Object * Object::getNextObjInv()
{
Object * obj = inv.peek();
inv.next();
return obj;
}
int Object::getWeightCap()
{
if( obj_type != ITEM_CONTAINER && obj_type != ITEM_LIQUID_CONTAINER )
return 0;
return value[0];
}
int Object::getVolCap()
{
if( obj_type != ITEM_CONTAINER && obj_type != ITEM_LIQUID_CONTAINER )
return 0;
return value[1];
}
int Object::getWeightContained()
{
if( obj_type != ITEM_CONTAINER && obj_type != ITEM_LIQUID_CONTAINER )
return 0;
return value[2];
}
int Object::getVolContained()
{
if( obj_type != ITEM_CONTAINER && obj_type != ITEM_LIQUID_CONTAINER )
return 0;
return value[3];
}
Spell * Object::getSpell1()
{
spells.reset();
if( spells.peek() )
return spells.peek();
return (Spell *)spellNone;
}
Spell * Object::getSpell2()
{
spells.reset();
if( spells.peek() )
spells.next();
if( spells.peek() )
return spells.peek();
return (Spell*)spellNone;
}
Spell * Object::getSpell3()
{
return (Spell*)spellNone;
}
Spell * Object::getSpell4()
{
return (Spell*)spellNone;
}
void Object::cast( Thing * target )
{
Spell * sp;
spells.reset();
while( ( sp = spells.peek() ) )
{
spells.next();
sp->cast( this, target );
}
}
const char *getObjBitName( int flag )
{
for( int i = 1; obj_bit_list[i].name; i++ )
{
if( flag == obj_bit_list[i].val )
return obj_bit_list[i].name;
}
return "";
}
int getObjBit( const char *str )
{
int len = strlen( str );
for( int i = 1; obj_bit_list[i].name; i++ )
{
if( *str != *obj_bit_list[i].name )
continue;
if( !strncmp( str, obj_bit_list[i].name, len ))
return obj_bit_list[i].val;
}
return 0;
}
const char *getObjTypeName( int type )
{
for( int i = 1; obj_type_list[i].name; i++ )
{
if( type == obj_type_list[i].val )
return obj_type_list[i].name;
}
return "undefined";
}
int getObjType( const char *str )
{
int len = strlen( str );
for( int i = 1; obj_type_list[i].name; i++ )
{
if( *str != *obj_type_list[i].name )
continue;
if( !strncmp( str, obj_type_list[i].name, len ))
return obj_type_list[i].val;
}
return -1;
}
const char *getWearPosName( int pos )
{
return wear_pos_list[pos];
}
const char *getWearBitName( int bit )
{
for( int i = 1; wear_bit_list[i].name; i++ )
{
if( bit == wear_bit_list[i].val )
return wear_bit_list[i].name;
}
return "undefined";
}
int getWearBit( const char *name )
{
int len = strlen( name );
for( int i=1; wear_bit_list[i].name; i++ )
{
if( *wear_bit_list[i].name != *name )
continue;
if( !strncmp( name, wear_bit_list[i].name, len ) )
return wear_bit_list[i].val;
}
return 0;
}
Object * lookupObj( const Index & x )
{
Object *obj;
Area *area;
LList<Area> tlist = areas;
tlist.reset();
while( ( area = tlist.peek() ) )
{
tlist.next();
// No scope means global search
if( !x.getScope() )
if( ( obj = area->lookupObj( x ) ) )
return obj;
if( area->getKey() == x.getScope() )
break;
}
if( area )
return area->lookupObj( x );
return 0;
}
Object * lookupObj( const String & x )
{
return lookupObj( Index( x ) );
}
Object * lookupObj( const char * x )
{
return lookupObj( Index( x ) );
}
const char * damTypeName( int val )
{
return getBitName( dam_types, val );
}