/*
* objects.cpp
* Object routines.
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* Permission to use, modify and distribute is granted via the
* Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
* Contributions by Tim Callahan, Jonathan Hseu
* Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
*
*/
#include "mud.h"
#include "objects.h"
#include "clans.h"
#include "alchemy.h"
//*********************************************************************
// Object
//*********************************************************************
Object::Object() {
int i;
version = "0.00";
memset(name, 0, sizeof(name));
description = effect = "";
memset(key, 0, sizeof(key));
memset(use_output, 0, sizeof(use_output));
memset(use_attack, 0, sizeof(use_attack));
weight = type = adjustment = shotsmax = shotscur = armor =
wearflag = magicpower = level = requiredSkill = clan =
special = delay = quality = effectStrength = effectDuration = 0;
memset(flags, 0, sizeof(flags));
questnum = 0;
first_obj = 0;
parent_obj = 0; parent_room = 0;
parent_crt = 0;
numAttacks = bulk = maxbulk = lotteryCycle = max_unique = uniqueId = 0;
coinCost = shopValue = 0;
size = NO_SIZE;
for(i=0; i<6; i++)
lotteryNumbers[i] = 0;
material = NO_MATERIAL;
keyVal = minStrength = 0;
compass = 0;
recipe = 0;
made = 0;
extra = 0;
hooks.setParent(this);
}
Object::~Object() {
otag *op = first_obj, *temp=0;
if(compass)
delete compass;
alchemyEffects.clear();
compass = 0;
while(op) {
temp = op->next_tag;
delete op->obj;
delete op;
op = temp;
}
}
//*********************************************************************
// init
//*********************************************************************
// Initiate the object - used when the object is first introduced into the
// world.
void Object::init(bool selRandom) {
// this object may turn into another object
if(selRandom)
selectRandom();
if(flagIsSet(O_RANDOM_ENCHANT))
randomEnchant();
loadContainerContents();
setMade();
setFlag(O_JUST_LOADED);
}
//*********************************************************************
// getNewPotion
//*********************************************************************
Object* Object::getNewPotion() {
Object* newPotion = new Object;
newPotion->type = POTION;
strcpy(newPotion->name, "generic potion");
strcpy(newPotion->key[0], "generic");
strcpy(newPotion->key[1], "potion");
newPotion->weight = 1;
newPotion->setFlag(O_SAVE_FULL);
return(newPotion);
}
//*********************************************************************
// doCopy
//*********************************************************************
void Object::doCopy(const Object& o) {
int i=0;
otag *op=0, *fp=0, *prev=0;
moCopy(o);
description = o.description;
for(i=0; i<3; i++)
strcpy(key[i], o.key[i]);
strcpy(use_output, o.use_output);
strcpy(use_attack, o.use_attack);
version = o.version;
weight = o.weight;
type = o.type;
adjustment = o.adjustment;
shotsmax = o.shotsmax;
shotscur = o.shotscur;
damage = o.damage;
armor = o.armor;
wearflag = o.wearflag;
magicpower = o.magicpower;
info = o.info;
level = o.level;
quality = o.quality;
requiredSkill = o.requiredSkill;
clan = o.clan;
special = o.special;
for(i=0; i<OBJ_FLAG_ARRAY_SIZE; i++)
flags[i] = o.flags[i];
questnum = o.questnum;
parent_obj = o.parent_obj;
for(i=0; i<4; i++)
lasttime[i] = o.lasttime[i];
for(i=0; i<3; i++)
in_bag[i] = o.in_bag[i];
parent_room = o.parent_room;
parent_crt = o.parent_crt;
lastMod = o.lastMod;
bulk = o.bulk;
delay = o.delay;
maxbulk = o.maxbulk;
numAttacks = o.numAttacks;
lotteryCycle = o.lotteryCycle;
max_unique = o.max_unique;
coinCost = o.coinCost;
deed = o.deed;
shopValue = o.shopValue;
value.set(o.value);
made = o.made;
keyVal = o.keyVal;
extra = o.extra;
questOwner = o.questOwner;
minStrength = o.minStrength;
material = o.material;
for(i=0; i<6; i++)
lotteryNumbers[i] = o.lotteryNumbers[i];
refund.set(o.refund);
size = o.size;
if(o.compass) {
compass = new MapMarker;
*compass = *o.compass;
}
recipe = o.recipe;
effect = o.effect;
effectDuration = o.effectDuration;
effectStrength = o.effectStrength;
// copy everything contained inside this object
fp = first_obj;
op = o.first_obj;
while(op) {
fp = new otag;
fp->obj = new Object;
*fp->obj = *op->obj;
fp->obj->parent_obj = this;
if(prev)
prev->next_tag = fp;
prev = fp;
fp = fp->next_tag;
op = op->next_tag;
}
std::pair<int, AlchemyEffect> p;
foreach(p, o.alchemyEffects) {
alchemyEffects[p.first] = p.second;
}
subType = o.subType;
std::list<CatRef>::const_iterator it;
randomObjects.clear();
for(it = o.randomObjects.begin() ; it != o.randomObjects.end() ; it++) {
randomObjects.push_back(*it);
}
}
Object& Object::operator=(const Object& o) {
doCopy(o);
return(*this);
}
bool Object::operator==(const Object& o) const {
int i=0;
if( description != o.description ||
version != o.version ||
weight != o.weight ||
type != o.type ||
adjustment != o.adjustment ||
shotsmax != o.shotsmax ||
shotscur != o.shotscur ||
damage != o.damage ||
armor != o.armor ||
wearflag != o.wearflag ||
magicpower != o.magicpower ||
info != o.info ||
level != o.level ||
quality != o.quality ||
requiredSkill != o.requiredSkill ||
clan != o.clan ||
special != o.special ||
questnum != o.questnum ||
lastMod != o.lastMod ||
bulk != o.bulk ||
delay != o.delay ||
maxbulk != o.maxbulk ||
numAttacks != o.numAttacks ||
lotteryCycle != o.lotteryCycle ||
max_unique != o.max_unique ||
coinCost != o.coinCost ||
deed != o.deed ||
shopValue != o.shopValue ||
made != o.made ||
keyVal != o.keyVal ||
extra != o.extra ||
questOwner != o.questOwner ||
minStrength != o.minStrength ||
material != o.material ||
size != o.size ||
recipe != o.recipe ||
effect != o.effect ||
effectDuration != o.effectDuration ||
effectStrength != o.effectStrength ||
subType != o.subType ||
randomObjects.size() != o.randomObjects.size() ||
alchemyEffects.size() != o.alchemyEffects.size() ||
first_obj ||
o.first_obj ||
strcmp(use_output, o.use_output) ||
strcmp(use_attack, o.use_attack) ||
value != o.value ||
refund != o.refund
)
return(false);
for(i=0; i<3; i++)
if(strcmp(key[i], o.key[i]))
return(false);
for(i=0; i<OBJ_FLAG_ARRAY_SIZE; i++)
if(flags[i] != o.flags[i])
return(false);
for(i=0; i<4; i++) {
if( lasttime[i].interval != o.lasttime[i].interval ||
lasttime[i].ltime != o.lasttime[i].ltime ||
lasttime[i].misc != o.lasttime[i].misc
)
return(false);
}
for(i=0; i<3; i++)
if(in_bag[i] != o.in_bag[i])
return(false);
for(i=0; i<6; i++)
if(lotteryNumbers[i] != o.lotteryNumbers[i])
return(false);
if(compass && o.compass) {
if(*compass != *o.compass)
return(false);
} else if(compass || o.compass)
return(false);
/*
std::pair<int, bstring> p;
foreach(p, o.alchemyEffects) {
alchemyEffects.insert(p);
}
*/
std::list<CatRef>::const_iterator rIt, orIt;
rIt = randomObjects.begin();
orIt = o.randomObjects.begin();
for(; rIt != randomObjects.end() ;) {
if(*rIt != *orIt)
return(false);
rIt++;
orIt++;
}
return(true);
}
bool Object::operator!=(const Object& o) const {
return(!(*this==o));
}
bool Object::flagIsSet(int flag) const {
return(flags[flag/8] & 1<<(flag%8));
}
void Object::setFlag(int flag) {
flags[flag/8] |= 1<<(flag%8);
}
void Object::clearFlag(int flag) {
flags[flag/8] &= ~(1<<(flag%8));
}
bool Object::toggleFlag(int flag) {
if(flagIsSet(flag))
clearFlag(flag);
else
setFlag(flag);
return(flagIsSet(flag));
}
bstring Object::getVersion() const {
return(version);
}
void Object::setMade() {
made = time(0);
}
//*********************************************************************
// getActualWeight
//*********************************************************************
// This function computes the total amount of weight of an object and
// all its contents.
int Object::getActualWeight() const {
int n=0;
otag *op=0;
n = weight;
op = first_obj;
while(op) {
if(!op->obj->flagIsSet(O_WEIGHTLESS_CONTAINER))
n += op->obj->getActualWeight();
op = op->next_tag;
}
return(n);
}
//*********************************************************************
// getActualBulk
//*********************************************************************
int Object::getActualBulk() const {
int n=0;
if(flagIsSet(O_BULKLESS_OBJECT))
return(0);
if(bulk <= 0) {
switch(type) {
case WEAPON:
{
bstring category = getWeaponCategory();
if(category == "crushing")
n = 5;
else if(category == "piercing")
n = 4;
else if(category == "slashing")
n = 4;
else if(category == "ranged")
n = 6;
else if(category == "chopping")
n = 8;
else
n = 4;
}
break;
case MONEY:
case POISON:
case POTION:
n = 4;
break;
case ARMOR:
switch(wearflag) {
case BODY:
n = 20;
break;
case ARMS:
n = 12;
break;
case LEGS:
n = 14;
break;
case NECK:
n = 6;
break;
case BELT:
case HANDS:
case HEAD:
case FEET:
case HELD:
case FACE:
n = 4;
break;
case FINGER:
case FINGER2:
case FINGER3:
case FINGER4:
case FINGER5:
case FINGER6:
case FINGER7:
case FINGER8:
n = 1;
break;
case SHIELD:
n = 10;
break;
default:
n =1;
break;
}
break;
case SCROLL:
case WAND:
case SONGSCROLL:
case MISC:
n = 3;
break;
case KEY:
n = 1;
break;
case CONTAINER:
n = 5;
break;
case LIGHTSOURCE:
case BANDAGE:
n = 2;
break;
}
} else
n = bulk;
return(n);
}
//*********************************************************************
// raceRestrict
//*********************************************************************
// become a random object
void Object::selectRandom() {
std::list<CatRef>::const_iterator it;
CatRef cr;
Object* object=0;
int which = randomObjects.size();
// Load all means we will become every object in this list (trade only)
// rather than a random one. Thus, don't use this code.
if(!which || flagIsSet(O_LOAD_ALL))
return;
which = mrand(1, which);
for(it = randomObjects.begin(); it != randomObjects.end(); it++) {
which--;
if(!which) {
cr = *it;
break;
}
}
if(!loadObject(cr, &object))
return;
*this = *object;
delete object;
}
//*********************************************************************
// raceRestrict
//*********************************************************************
bool Object::raceRestrict(const Creature* creature, bool p) const {
if(raceRestrict(creature)) {
if(p) creature->checkStaff("Your race prevents you from using %P.\n", this);
if(!creature->isStaff()) return(true);
}
return(false);
}
bool Object::raceRestrict(const Creature* creature) const {
bool pass = false;
// if no flags are set
if( !flagIsSet(O_SEL_DWARF) &&
!flagIsSet(O_SEL_ELF) &&
!flagIsSet(O_SEL_HALFELF) &&
!flagIsSet(O_SEL_HALFLING) &&
!flagIsSet(O_SEL_HUMAN) &&
!flagIsSet(O_SEL_ORC) &&
!flagIsSet(O_SEL_HALFGIANT) &&
!flagIsSet(O_SEL_GNOME) &&
!flagIsSet(O_SEL_TROLL) &&
!flagIsSet(O_SEL_HALFORC) &&
!flagIsSet(O_SEL_OGRE) &&
!flagIsSet(O_SEL_DARKELF) &&
!flagIsSet(O_SEL_GOBLIN) &&
!flagIsSet(O_SEL_MINOTAUR) &&
!flagIsSet(O_SEL_SERAPH) &&
!flagIsSet(O_SEL_KOBOLD) &&
!flagIsSet(O_SEL_CAMBION) &&
!flagIsSet(O_SEL_BARBARIAN) &&
!flagIsSet(O_SEL_KATARAN) &&
!flagIsSet(O_SEL_TIEFLING) &&
!flagIsSet(O_RSEL_INVERT)
)
return(false);
// if the race flag is set and they match, they pass
pass = (
(flagIsSet(O_SEL_DWARF) && creature->isRace(DWARF)) ||
(flagIsSet(O_SEL_ELF) && creature->isRace(ELF)) ||
(flagIsSet(O_SEL_HALFELF) && creature->isRace(HALFELF)) ||
(flagIsSet(O_SEL_HALFLING) && creature->isRace(HALFLING)) ||
(flagIsSet(O_SEL_HUMAN) && creature->isRace(HUMAN)) ||
(flagIsSet(O_SEL_ORC) && creature->isRace(ORC)) ||
(flagIsSet(O_SEL_HALFGIANT) && creature->isRace(HALFGIANT)) ||
(flagIsSet(O_SEL_GNOME) && creature->isRace(GNOME)) ||
(flagIsSet(O_SEL_TROLL) && creature->isRace(TROLL)) ||
(flagIsSet(O_SEL_HALFORC) && creature->isRace(HALFORC)) ||
(flagIsSet(O_SEL_OGRE) && creature->isRace(OGRE)) ||
(flagIsSet(O_SEL_DARKELF) && creature->isRace(DARKELF)) ||
(flagIsSet(O_SEL_GOBLIN) && creature->isRace(GOBLIN)) ||
(flagIsSet(O_SEL_MINOTAUR) && creature->isRace(MINOTAUR)) ||
(flagIsSet(O_SEL_SERAPH) && creature->isRace(SERAPH)) ||
(flagIsSet(O_SEL_KOBOLD) && creature->isRace(KOBOLD)) ||
(flagIsSet(O_SEL_CAMBION) && creature->isRace(CAMBION)) ||
(flagIsSet(O_SEL_BARBARIAN) && creature->isRace(BARBARIAN)) ||
(flagIsSet(O_SEL_KATARAN) && creature->isRace(KATARAN)) ||
(flagIsSet(O_SEL_TIEFLING) && creature->isRace(TIEFLING))
);
if(flagIsSet(O_RSEL_INVERT)) pass = !pass;
return(!pass);
}
//*********************************************************************
// classRestrict
//*********************************************************************
// We need more information here - we can't just pass/fail them like
// we usually do.
bool Object::classRestrict(const Creature* creature, bool p) const {
if(classRestrict(creature)) {
if(p) creature->checkStaff("Your class prevents you from using %P.\n", this);
if(!creature->isStaff()) return(true);
}
return(false);
}
bool Object::classRestrict(const Creature* creature) const {
bool pass = false;
const Player* player = creature->getConstPlayer();
int cClass = creature->getClass();
if(player && player->getClass() == MAGE && (player->getSecondClass() == ASSASSIN || player->getSecondClass() == THIEF))
cClass = player->getSecondClass();
if(flagIsSet(O_NO_MAGE) && (cClass == MAGE || cClass == LICH))
return(true);
// if no flags are set
if( !flagIsSet(O_SEL_ASSASSIN) &&
!flagIsSet(O_SEL_BERSERKER) &&
!flagIsSet(O_SEL_CLERIC) &&
!flagIsSet(O_SEL_FIGHTER) &&
!flagIsSet(O_SEL_MAGE) &&
!flagIsSet(O_SEL_PALADIN) &&
!flagIsSet(O_SEL_RANGER) &&
!flagIsSet(O_SEL_THIEF) &&
!flagIsSet(O_SEL_VAMPIRE) &&
!flagIsSet(O_SEL_MONK) &&
!flagIsSet(O_SEL_DEATHKNIGHT) &&
!flagIsSet(O_SEL_DRUID) &&
!flagIsSet(O_SEL_LICH) &&
!flagIsSet(O_SEL_WEREWOLF) &&
!flagIsSet(O_SEL_BARD) &&
!flagIsSet(O_SEL_ROGUE) &&
!flagIsSet(O_CSEL_INVERT)
) {
// we need to do some special rules before we say they can use the item
// only blunts for monks
if(wearflag == WIELD && cClass == MONK && getWeaponCategory() != "crushing")
return(true);
// only sharps for wolves
if(wearflag == WIELD && creature->isEffected("lycanthropy") && getWeaponCategory() != "slashing")
return(true);
if(type == ARMOR && (cClass == MONK || creature->isEffected("lycanthropy")))
return(true);
// no rings or shields for monk/wolf/lich
if( (wearflag == FINGER || wearflag == SHIELD) &&
(cClass == MONK || creature->isEffected("lycanthropy") || cClass == LICH) )
return(true);
return(false);
}
// if the class flag is set and they match, they pass
pass = (
(flagIsSet(O_SEL_ASSASSIN) && cClass == ASSASSIN) ||
(flagIsSet(O_SEL_BERSERKER) && cClass == BERSERKER) ||
(flagIsSet(O_SEL_CLERIC) && cClass == CLERIC) ||
(flagIsSet(O_SEL_FIGHTER) && cClass == FIGHTER) ||
(flagIsSet(O_SEL_MAGE) && cClass == MAGE) ||
(flagIsSet(O_SEL_PALADIN) && cClass == PALADIN) ||
(flagIsSet(O_SEL_RANGER) && cClass == RANGER) ||
(flagIsSet(O_SEL_THIEF) && cClass == THIEF) ||
(flagIsSet(O_SEL_VAMPIRE) && creature->isEffected("vampirism")) ||
(flagIsSet(O_SEL_MONK) && cClass == MONK) ||
(flagIsSet(O_SEL_DEATHKNIGHT) && cClass == DEATHKNIGHT) ||
(flagIsSet(O_SEL_DRUID) && cClass == DRUID) ||
(flagIsSet(O_SEL_LICH) && cClass == LICH) ||
(flagIsSet(O_SEL_WEREWOLF) && creature->isEffected("lycanthropy")) ||
(flagIsSet(O_SEL_BARD) && cClass == BARD) ||
(flagIsSet(O_SEL_ROGUE) && cClass == ROGUE)
);
if(flagIsSet(O_CSEL_INVERT)) pass = !pass;
return(!pass);
}
//*********************************************************************
// levelRestrict
//*********************************************************************
bool Object::levelRestrict(const Creature* creature, bool p) const {
if(level > creature->getLevel()) {
if(p) creature->checkStaff("You are not experienced enough to use that.\n");
if(!creature->isStaff()) return(true);
}
return(false);
}
bool Object::skillRestrict(const Creature* creature, bool p) const {
int skillLevel = 0;
bstring skill = "";
if(type == ARMOR) {
skill = getArmorType();
if(skill == "shield" || skill == "ring")
skill = "";
} else if(type == WEAPON) {
skill = getWeaponType();
} else if(flagIsSet(O_FISHING)) {
skill = "fishing";
}
if(skill != "") {
skillLevel = (int)creature->getSkillGained(skill);
if(requiredSkill > skillLevel) {
if(p) creature->checkStaff("You do not have enough training in ^W%s%s^x to use that!\n", skill.c_str(), type == ARMOR ? " armor" : "");
if(!creature->isStaff()) return(true);
}
}
return(false);
}
//*********************************************************************
// levelRestrict
//*********************************************************************
bool Object::alignRestrict(const Creature* creature, bool p) const {
if( (flagIsSet(O_GOOD_ALIGN_ONLY) && creature->getAdjustedAlignment() < NEUTRAL) ||
(flagIsSet(O_EVIL_ALIGN_ONLY) && creature->getAdjustedAlignment() > NEUTRAL) )
{
if(p) {
creature->checkStaff("%O shocks you and you drop it.\n", this);
if(!creature->isStaff())
broadcast(creature->getSock(), creature->getRoom(), "%M is shocked by %P.", creature, this);
}
if(!creature->isStaff()) return(true);
}
return(false);
}
//*********************************************************************
// sexRestrict
//*********************************************************************
bool Object::sexRestrict(const Creature* creature, bool p) const {
Sex sex = creature->getSex();
if(flagIsSet(O_MALE_ONLY) && sex != SEX_MALE) {
if(!p) creature->checkStaff("Only males can use that.\n");
if(!creature->isStaff()) return(true);
}
if(flagIsSet(O_FEMALE_ONLY) && sex != SEX_FEMALE) {
if(!p) creature->checkStaff("Only females can use that.\n");
if(!creature->isStaff()) return(true);
}
if(flagIsSet(O_SEXLESS_ONLY) && sex != SEX_NONE) {
if(!p) creature->checkStaff("Only creatures without a gender can use that.\n");
if(!creature->isStaff()) return(true);
}
return(false);
}
//*********************************************************************
// strRestrict
//*********************************************************************
bool Object::strRestrict(const Creature* creature, bool p) const {
if(minStrength > creature->strength.getCur()) {
if(!p) creature->checkStaff("You are currently not strong enough to use that.\n");
if(!creature->isStaff()) return(true);
}
return(false);
}
//*********************************************************************
// clanRestrict
//*********************************************************************
bool Object::clanRestrict(const Creature* creature, bool p) const {
if(clanRestrict(creature)) {
if(p) creature->checkStaff("Your allegience prevents you from using %P.\n", this);
if(!creature->isStaff()) return(true);
}
return(false);
}
bool Object::clanRestrict(const Creature* creature) const {
int c = creature->getClan();
if(creature->getDeity()) {
const Clan* clan = gConfig->getClanByDeity(creature->getDeity());
if(clan && clan->getId() != 0)
c = clan->getId();
}
// if the object requires pledging, let any clan pass
if(flagIsSet(O_PLEDGED_ONLY))
return(!c);
// if no flags are set
if( !flagIsSet(O_CLAN_1) &&
!flagIsSet(O_CLAN_2) &&
!flagIsSet(O_CLAN_3) &&
!flagIsSet(O_CLAN_4) &&
!flagIsSet(O_CLAN_5) &&
!flagIsSet(O_CLAN_6) &&
!flagIsSet(O_CLAN_7) &&
!flagIsSet(O_CLAN_8) &&
!flagIsSet(O_CLAN_9) &&
!flagIsSet(O_CLAN_10) &&
!flagIsSet(O_CLAN_11) &&
!flagIsSet(O_CLAN_12) )
return(false);
// if the clan flag is set and they match, they pass
if( (flagIsSet(O_CLAN_1) && c == 1) ||
(flagIsSet(O_CLAN_2) && c == 2) ||
(flagIsSet(O_CLAN_3) && c == 3) ||
(flagIsSet(O_CLAN_4) && c == 4) ||
(flagIsSet(O_CLAN_5) && c == 5) ||
(flagIsSet(O_CLAN_6) && c == 6) ||
(flagIsSet(O_CLAN_7) && c == 7) ||
(flagIsSet(O_CLAN_8) && c == 8) ||
(flagIsSet(O_CLAN_9) && c == 9) ||
(flagIsSet(O_CLAN_10) && c == 10) ||
(flagIsSet(O_CLAN_11) && c == 11) ||
(flagIsSet(O_CLAN_12) && c == 12) )
return(false);
return(true);
}
//*********************************************************************
// lawchaoRestrict
//*********************************************************************
bool Object::lawchaoRestrict(const Creature* creature, bool p) const {
if( (flagIsSet(O_CHAOTIC_ONLY) && !creature->flagIsSet(P_CHAOTIC)) ||
(flagIsSet(O_LAWFUL_ONLY) && creature->flagIsSet(P_CHAOTIC)) )
{
if(p) creature->checkStaff("You are unable to use %P.\n", this);
if(!creature->isStaff()) return(true);
}
return(false);
}
//*********************************************************************
// doRestrict
//*********************************************************************
bool Object::doRestrict(Creature* creature, bool p) {
if(clanRestrict(creature, p))
return(true);
if(levelRestrict(creature, p))
return(true);
if(skillRestrict(creature, p))
return(true);
if(strRestrict(creature, p))
return(true);
if(classRestrict(creature, p))
return(true);
if(raceRestrict(creature, p))
return(true);
if(sexRestrict(creature, p))
return(true);
if(clanRestrict(creature, p))
return(true);
if(lawchaoRestrict(creature, p))
return(true);
if(alignRestrict(creature, p)) {
if(p && !creature->isStaff()) {
creature->delObj(this, false, true);
addToRoom(creature->getRoom());
}
return(true);
}
return(false);
}
//*********************************************************************
// getCompass
//*********************************************************************
bstring Object::getCompass(const Creature* creature, bool useName) {
std::ostringstream oStr;
if(useName)
oStr << getObjStr(creature, CAP, 1);
else
oStr << "It";
oStr << " ";
if(!compass) {
oStr << "appears to be broken.\n";
return(oStr.str());
}
MapMarker *mapmarker=0;
if(creature->area_room)
mapmarker = &creature->area_room->mapmarker;
if( !creature->area_room ||
!mapmarker->getArea() ||
!compass->getArea() ||
mapmarker->getArea() != compass->getArea() ||
*mapmarker == *compass
) {
oStr << "is currently spinning in circles.\n";
return(oStr.str());
}
oStr << "points " << mapmarker->direction(compass) << ". The target is "
<< mapmarker->distance(compass) << ".\n";
return(oStr.str());
}
//*********************************************************************
// getObjStr
//*********************************************************************
bstring Object::getObjStr(const Creature* viewer, int flags, int num) const {
std::ostringstream objStr;
bstring toReturn = "";
char ch;
// int mobNum=0;
//
//
// str = xstr[xnum];
// xnum = (xnum + 1)%5;
if(!this)
return("(NULL OBJ");
if(viewer != NULL)
flags |= viewer->displayFlags();
bool irrPlural = false;
if(flagIsSet(O_IRREGULAR_PLURAL) && num > 1) {
char pform[80];
char sform[80];
char pfile[80];
FILE *plural;
sprintf(pfile, "%s/plurals.txt", GAMEPATH);
plural = fopen(pfile, "r");
if(plural != NULL) {
while (!irrPlural && !(feof (plural))) {
fflush(plural);
// get singular form
fgets(sform, sizeof(sform), plural);
sform[strlen(sform)-1] = 0;
if(sform[strlen(sform)-1] == '\r')
sform[strlen(sform)-1] = 0;
fflush(plural);
// get plural form
fgets(pform, sizeof(pform), plural);
pform[strlen(pform)-1] = 0;
if(pform[strlen(pform)-1] == '\r')
pform[strlen(pform)-1] = 0;
if(strcmp(name, sform) == 0) {
objStr << int_to_text(num) << " " << pform;
irrPlural = true;
}
}
fclose(plural);
}
}
if(!irrPlural) {
// Either not an irregular plural, or we couldn't find a match in the irregular plural file
if(num == 0) {
if(!flagIsSet(O_NO_PREFIX)) {
objStr << "the " << name;
} else
objStr << name;
}
else if(num == 1) {
if(flagIsSet(O_NO_PREFIX) || (info.id == 0 && !strcmp(key[0], "gold") && type == MONEY))
objStr << "";
else if(flagIsSet(O_SOME_PREFIX))
objStr << "some ";
else {
ch = low(name[0]);
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
objStr << "an ";
else
objStr << "a ";
}
objStr << name;
}
else {
char tempStr[2056];
strcpy( tempStr, int_to_text(num) );
strcat(tempStr, " ");
if(flagIsSet(O_SOME_PREFIX))
strcat(tempStr, "sets of ");
strcat(tempStr, name);
if(!flagIsSet(O_NO_S_ON_PLURAL) && !flagIsSet(O_SOME_PREFIX)) {
tempStr[strlen(tempStr)+1] = 0;
tempStr[strlen(tempStr)+2] = 0;
if(tempStr[strlen(tempStr)-1] == 's' ||
tempStr[strlen(tempStr)-1] == 'x') {
tempStr[strlen(tempStr)] = 'e';
tempStr[strlen(tempStr)] = 's';
} else
tempStr[strlen(tempStr)] = 's';
}
objStr << tempStr;
}
}
if(flagIsSet(O_NULL_MAGIC) && ((flags & ISDM) || (flags & ISCT))) {
objStr << " (+" << adjustment << ")(n)";
} else if((flags & MAG) && adjustment && !flagIsSet(O_NULL_MAGIC)) {
objStr << " (";
if(adjustment >= 0)
objStr << "+";
objStr << adjustment << ")";
} else if((flags & MAG) && magicpower && !flagIsSet(O_NULL_MAGIC))
objStr << " (M)";
if(flags & ISDM) {
if(flagIsSet(O_HIDDEN))
objStr << " (h)";
if(flagIsSet(O_INVISIBLE))
objStr << " (*)";
if(flagIsSet(O_SCENERY))
objStr << " (s)";
}
toReturn = objStr.str();
if(flags & CAP)
toReturn[0] = up(toReturn[0]);
return(toReturn);
}
//*********************************************************************
// isHeavyArmor
//*********************************************************************
bool Object::isHeavyArmor() const {
// return(type == ARMOR && (subType == "chain" || subType == "plate"));
return(type == ARMOR && subType == "plate");
}
bool Object::isMediumArmor() const {
return(type == ARMOR && subType == "chain");
}
//*********************************************************************
// isLightArmor
//*********************************************************************
bool Object::isLightArmor() const {
return(type == ARMOR && (subType == "cloth" || subType == "leather"));
}
//*********************************************************************
// popBag
//*********************************************************************
// removes an object from the bag, usually when the bag is stolen or destroyed
void Object::popBag(Creature* creature, bool quest, bool drop, bool steal, bool bodypart, bool dissolve) {
Object* object=0;
otag* op = first_obj;
while(op) {
object = op->obj;
op = op->next_tag;
if( (quest && object->questnum) ||
(dissolve && object->flagIsSet(O_RESIST_DISOLVE)) ||
(drop && object->flagIsSet(O_NO_DROP)) ||
(steal && object->flagIsSet(O_NO_STEAL)) ||
(bodypart && object->flagIsSet(O_BODYPART))
) {
del_obj_obj(object, this);
creature->addObj(object);
}
}
}
//*********************************************************************
// isKey
//*********************************************************************
bool Object::isKey(const Room* room, const Exit* exit) const {
// storage room exist must be a storage room key
if(exit->flagIsSet(X_TO_STORAGE_ROOM))
return(!strcmp(name, "storage room key"));
// key numbers must match
if(getKey() != exit->getKey())
return(false);
if(!room)
return(true);
// For the key to work, it must be from the same area
// ie: no using oceancrest keys in highport!
bstring area = exit->getKeyArea();
if(area == "")
area = room->info.area;
if(!info.isArea("") && !info.isArea(area))
return(false);
return(true);
}