/*
....[@@@..[@@@..............[@.................. 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
------------------------------------------------------------------------------
char.cc
*/
#include "config.h"
#include "io.h"
#include "string.h"
#include "llist.h"
#include "indexable.h"
#include "room.h"
#include "affect.h"
#include "spell.h"
#include "char.h"
#include "global.h"
Char::~Char()
{
Object *obj;
Affect *aff;
Attack *att;
while( ( obj = inv.remove() ) )
{
obj->fromWorld();
delete obj;
}
while( ( obj = wearlist.remove() ) )
{
obj->fromWorld();
delete obj;
}
while( ( aff = affects.remove() ) )
delete aff;
while( ( att = attacks.remove() ) )
delete att;
}
Object *Char::getObjInv( const String & arg )
{
Object *obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
inv.next();
if( obj->wearPos() )
continue;
if( obj->isName( arg ) )
return obj;
}
return 0;
}
Object *Char::getSecondObjInv( const String & arg )
{
Object *obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
inv.next();
if( obj->wearPos() )
continue;
if( obj->isName( arg ) )
while( ( obj = inv.peek() ) )
{
inv.next();
if( obj->wearPos() )
continue;
if( obj->isName( arg ) )
return obj;
}
}
return 0;
}
void Char::addObjInv( Object * obj )
{
obj->toChar( this );
carried_weight += obj->getWeight();
carried_count++;
inv.add( obj );
}
void Char::rmObjInv( Object * obj )
{
obj->fromChar();
carried_weight -= obj->getWeight();
carried_count--;
inv.remove( obj );
}
Object *Char::getObjWear( const String & arg )
{
Object *obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
inv.next();
if( !obj->wearPos() )
continue;
if( obj->isName( arg ) )
return obj;
}
return 0;
}
Object *Char::getObjWear( int pos )
{
if( !IS_SET( eq_bits, pos ) )
return 0;
Object *obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
inv.next();
if( obj->wearPos() == pos )
return obj;
}
return 0;
}
int Char::canWear( Object *item, int pos )
{
switch( pos )
{
default: return 0;
case EQ_HEAD: return item->wearBit( WEAR_HEAD );
case EQ_FACE: return item->wearBit( WEAR_FACE );
case EQ_NECK_2:
case EQ_NECK_1: return item->wearBit( WEAR_NECK );
case EQ_BACK: return item->wearBit( WEAR_BACK );
case EQ_BODY: return item->wearBit( WEAR_BODY );
case EQ_ARMS: return item->wearBit( WEAR_ARMS );
case EQ_WRIST_L:
case EQ_WRIST_R: return item->wearBit( WEAR_WRIST );
case EQ_HANDS: return item->wearBit( WEAR_HANDS );
case EQ_HOLD_L:
case EQ_HOLD_R: return item->wearBit( WEAR_HOLD );
case EQ_FINGER_L:
case EQ_FINGER_R: return item->wearBit( WEAR_FINGER );
case EQ_WAIST: return item->wearBit( WEAR_WAIST );
case EQ_LEGS: return item->wearBit( WEAR_LEGS );
case EQ_FEET: return item->wearBit( WEAR_FEET );
case EQ_SHIELD_L:
case EQ_SHIELD_R: return item->wearBit( WEAR_SHIELD );
case EQ_WIELD_L:
case EQ_WIELD_R: return item->wearBit( WEAR_WIELD );
}
}
void Char::wear( Object *obj, int pos )
{
Modifier *mod;
if( obj->wearPos() )
{
Cout<< "Wear( item ) : item already worn\n";
return;
}
// Do eq mods on character, if any
obj->mods.reset();
while( ( mod = obj->mods.peek() ) )
{
obj->mods.next();
modify( mod, true );
}
SET_BIT( eq_bits, pos );
obj->setWearPos( pos );
}
void Char::equip( Object *obj, int bit )
{
switch( bit )
{
case WEAR_HEAD: if( !IS_SET( eq_bits, EQ_HEAD ) )
wear( obj, EQ_HEAD );
return;
case WEAR_NECK: if( !IS_SET( eq_bits, EQ_NECK_1 ) )
wear( obj, EQ_NECK_1 );
else if( !IS_SET( eq_bits, EQ_NECK_2 ) )
wear( obj, EQ_NECK_2 );
return;
case WEAR_BACK: if( !IS_SET( eq_bits, EQ_BACK ) )
wear( obj, EQ_BACK );
return;
case WEAR_BODY: if( !IS_SET( eq_bits, EQ_BODY ) )
wear( obj, EQ_BODY );
return;
case WEAR_ARMS: if( !IS_SET( eq_bits, EQ_ARMS ) )
wear( obj, EQ_ARMS );
return;
case WEAR_WRIST: if( !IS_SET( eq_bits, EQ_WRIST_L ) )
wear( obj, EQ_WRIST_L );
else if( !IS_SET( eq_bits, EQ_WRIST_R ) )
wear( obj, EQ_WRIST_R );
return;
case WEAR_HANDS: if( !IS_SET( eq_bits, EQ_HANDS ) )
wear( obj, EQ_HANDS );
return;
case WEAR_HOLD: if( !IS_SET( eq_bits, EQ_HOLD_L ) )
wear( obj, EQ_HOLD_L );
else if( !IS_SET( eq_bits, EQ_HOLD_R ) )
wear( obj, EQ_HOLD_R );
return;
case WEAR_FINGER: if( !IS_SET( eq_bits, EQ_FINGER_L ) )
wear( obj, EQ_FINGER_L );
else if( !IS_SET( eq_bits, EQ_FINGER_R ) )
wear( obj, EQ_FINGER_R );
return;
case WEAR_WAIST: if( !IS_SET( eq_bits, EQ_WAIST ) )
wear( obj, EQ_WAIST );
return;
case WEAR_LEGS: if( !IS_SET( eq_bits, EQ_LEGS ) )
wear( obj, EQ_LEGS );
return;
case WEAR_FEET: if( !IS_SET( eq_bits, EQ_FEET ) )
wear( obj, EQ_FEET );
return;
// Add checks here for hold/shield/wield combos
case WEAR_SHIELD: if( !IS_SET( eq_bits, EQ_SHIELD_L ) )
wear( obj, EQ_SHIELD_L );
else if( !IS_SET( eq_bits, EQ_SHIELD_R ) )
wear( obj, EQ_SHIELD_R );
return;
case WEAR_WIELD: if( !IS_SET( eq_bits, EQ_WIELD_R ) )
wear( obj, EQ_WIELD_R );
else if( !IS_SET( eq_bits, EQ_WIELD_L) )
wear( obj, EQ_WIELD_L );
return;
default: return;
}
}
void Char::wield( Object * obj, int leftright )
{
// incomplete
equip( obj, WEAR_WIELD );
}
void Char::remove( Object *obj )
{
Modifier *mod;
if( !obj->wearPos() )
return;
// Negate eq mods on character, if any
obj->mods.reset();
while( ( mod = obj->mods.peek() ) )
{
obj->mods.next();
modify( mod, false );
}
CLEAR_BIT( eq_bits, obj->wearPos() );
obj->setWearPos( 0 );
}
void Char::put( Object * obj, Object * container )
{
obj->fromChar();
inv.remove( obj );
container->addObjInv( obj );
}
int Char::getStr () const { return strength; }
int Char::getInt () const { return intel; }
int Char::getWis () const { return wis; }
int Char::getCon () const { return con; }
int Char::getDex () const { return dex; }
int Char::getSpd () const { return speed; }
void Char::get( Object *obj )
{
String str;
in_room->rmObjInv( obj );
if( obj->isGold() )
{
str << "\n\r" << shortdesc << " gets " << obj->getShort() << ".\n\r";
in_room->outAllCharExcept( str, this, 0 );
gold += obj->getValue();
obj->extract();
delete obj;
return;
}
addObjInv( obj );
}
void Char::drop( Object *obj )
{
rmObjInv( obj );
in_room->addObjInv( obj );
}
bool Char::open( Exit * door )
{
char buf[ 256 ];
// Incomplete: add other side
if( door->isOpen() )
return true;
door->rmIsClosed();
sprintf( buf, "%s opens the door.\n\r" );
in_room->outAllCharExcept( buf, this, 0 );
return true;
}
bool Char::close( Exit * door )
{
char buf[ 256 ];
// Incomplete: add other side
if( door->isClosed() )
return true;
door->setIsClosed();
sprintf( buf, "%s closes the door.\n\r" );
in_room->outAllCharExcept( buf, this, 0 );
return true;
}
bool Char::moveDir( int dir )
{
if( dir >= MAX_DIR || !in_room || !in_room->getExit( dir ) )
return false;
char buf[BUF];
const Exit *door = in_room->getExit( dir );
if( ! door )
return false;
Room *to = door->toRoom();
if( ! to )
return false;
if( door->isClosed() )
{
out( "The door is closed.\n\r" );
return false;
}
sprintf( buf, "\n\r%s walks %s.\n\r", shortdesc.chars(), getDirName( dir ) );
in_room->outAllCharExcept( buf, this, 0 );
sprintf( buf, "\n\r%s has arrived.\n\r", shortdesc.chars() );
in_room->rmCharInv( this );
to->addCharInv( this );
in_room->outAllCharExcept( buf, this, 0 );
return true;
}
void Char::fromRoom()
{
in_room = 0;
}
void Char::toRoom( Room *to )
{
in_room = to;
}
void Char::addAffect( Affect *paf )
{
Modifier * mod;
paf->mods.reset();
while( ( mod = paf->mods.peek() ) )
{
modify( mod, true );
paf->mods.next();
}
SET_BIT( aff_bits, paf->getType() );
affects.add( paf );
}
void Char::rmAffect( int aftype )
{
Affect * paf;
Modifier * mod;
affects.reset();
while( ( paf = affects.peek() ) )
{
if( paf->getType() != aftype )
{
affects.next();
continue;
}
affects.remove();
CLEAR_BIT( aff_bits, aftype );
paf->mods.reset();
while( ( mod = paf->mods.peek() ) )
{
modify( mod, false );
paf->mods.next();
}
}
}
void Char::modify( Modifier * mod, bool add )
{
int amt = mod->getAmt();
if( !add )
{
amt = amt * -1;
}
switch( mod->getType() )
{
case MOD_STR: strength += amt; return;
case MOD_DEX: dex += amt; return;
case MOD_INT: intel += amt; return;
case MOD_WIS: wis += amt; return;
case MOD_CON: con += amt; return;
case MOD_SPEED: speed += amt; return;
case MOD_HP: max_hp += amt; return;
case MOD_ARMOR: armor += amt; return;
case MOD_DAMROLL: damroll += amt; return;
case MOD_HITROLL: hitroll += amt; return;
default: return;
}
}
void Char::pulse()
{
int hpgain = max_hp / 10;
int managain = max_mana / 8;
if( !affected( AFF_POISON ) )
{
hp += hpgain;
mana += managain;
}
else
{
hp -= hpgain;
mana -= managain;
}
// Update conditions
if( hp > max_hp )
hp = max_hp;
else if( hp <= 0 )
{
out( "You have DIED from poisoning!!!\n\r" );
}
if( mana > max_mana )
mana = max_mana;
else if( mana < 0 )
mana = 0;
// Update affects
Affect *paf;
affects.reset();
while( ( paf = affects.peek() ) )
{
if( paf->pulse() <= 0 )
{
// remove affect
affects.remove();
Modifier * mod;
paf->mods.reset();
while( ( mod = paf->mods.peek() ) )
{
// remove the modifier (false = negate)
modify( mod, false );
paf->mods.next();
}
CLEAR_BIT( aff_bits, paf->getType() );
const Spell *spell = paf->getSpell();
if( spell )
{
out( "The affects of " );
out( spell->getName() );
out( " wear off.\n\r" );
}
delete paf;
}
affects.next();
}
}
void Char::addAttack()
{
Attack * pattack = new Attack();
attacks.reset();
attacks.add( pattack );
}
void Char::rmAttack()
{
Attack * pattack;
attacks.reset();
pattack = attacks.peek( );
attacks.remove();
delete pattack;
}
void Char::cast( const Spell * spell, Thing * target )
{
spell->cast( this, target );
}
int Char::gainExp( int x )
{
exp += x;
return exp;
}