/* * creatures.cpp * Functions that work on creatures etc * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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-2012 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ // Mud Includes #include "mud.h" #include "version.h" #include "commands.h" #include "calendar.h" #include "guilds.h" #include "property.h" // C++ includes #include <sstream> #include <iomanip> #include <locale> //******************************************************************** // canSee //******************************************************************** bool Creature::canSeeRoom(const BaseRoom* room, bool p) const { if(isStaff()) return(true); const Player* player = getAsConstPlayer(); // blind people can't see anything if(isBlind()) { if(p) { printColor("^CYou're blind!^x\n"); printColor("^yIt's too dark to see.^x\n"); } return(false); } // magic vision overcomes all darkness if(isEffected("infravision")) return(true); // magic dark can only be overcome by magic vision if(room->isMagicDark()) { if(p) { printColor("^CIt's unnaturally dark here.\n"); printColor("^yIt's too dark to see.\n"); } return(false); } // room is affected by normal darkness if(room->isNormalDark()) { // there are several sources of normal vision bool normal_sight = gConfig->getRace(race)->hasInfravision() || isUndead() || isEffected("lycanthropy") || (player && player->getLight()); // if they can't see, maybe someone else in the room has light for them if(!normal_sight) { for(Player* ply : room->players) { if(ply->getAsPlayer()->getLight()) { normal_sight = true; break; } } } if(!normal_sight) { if(p) printColor("^yIt's too dark to see.\n"); return(false); } } // not any form of dark, then they can see return(true); } bool Creature::canSee(const MudObject* target, bool skip) const { if(!this || !target) return(false); if(target->isCreature()) { const Creature* cTarget = target->getAsConstCreature(); if(cTarget->isPlayer()) { if(cTarget->isDm() && cTarget->flagIsSet(P_DM_INVIS) && !isDm()) return(false); if(cTarget->isCt() && cTarget->flagIsSet(P_DM_INVIS) && !isCt()) return(false); if(cTarget->isStaff() && cTarget->flagIsSet(P_DM_INVIS) && !isStaff()) return(false); if(target->isEffected("incognito") && (getClass() < cTarget->getClass()) && getParent() != cTarget->getParent()) return(false); if(!skip) { if(cTarget->isInvisible() && !isEffected("detect-invisible") && !isStaff()) return(false); if(target->isEffected("mist") && !isEffected("true-sight") && !isStaff()) return(false); } } else { if(!skip) { if(cTarget->isInvisible() && !isEffected("detect-invisible") && !isStaff()) return(false); } } } // End Creature if(target->isExit()) { const Exit* exit = target->getAsConstExit(); if(isStaff()) return(true); // handle NoSee right away if(exit->flagIsSet(X_NO_SEE)) return(false); if(exit->isEffected("invisibility") && !isEffected("detect-invisible")) return(false); } if(target->isObject()) { const Object* object = target->getAsConstObject(); if(isStaff()) return(true); if(object->isEffected("invisibility") && (this && !isEffected("detect-invisible"))) return(false); } return(true); } //******************************************************************** // canEnter //******************************************************************** // Determines if a player/monster can enter the exit provided. If p is not 0, // it will also display a reason why. This only handles absolutely-unable-to- // enter. M_BLOCK_EXIT is not handled because players can still enter those // exits under certain circumstances (ie, flee). // // Pets are handled differently. They obey special rules for rooms because // returning false here would prevent the player from entering the room. bool Creature::canEnter(const Exit *exit, bool p, bool blinking) const { const Calendar* calendar=0; int staff = isStaff(); if(!exit) return(false); if(isMonster()) p = false; if(exit->target.mapmarker.getArea()) { Area *area = gConfig->getArea(exit->target.mapmarker.getArea()); if(!area) return(false); // y coords are stored upside down in the array // impassable terrain if(!area->canPass(this, &exit->target.mapmarker, true)) { if(p) checkStaff("You can't go there!\n"); if(!staff) return(false); } } // pets can go anywhere if(isPet()) return(true); if(!blinking && exit->isWall("wall-of-force")) { if(p) checkStaff("^sA wall of force blocks passage in that direction.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_CLOSED)) { if(p) checkStaff("You have to open it first.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_LOCKED)) { if(p) checkStaff("It's locked.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_STAFF_ONLY) || exit->flagIsSet(X_NO_SEE)) { if(p) checkStaff("You cannot go that way.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_LOOK_ONLY)) { if(p) checkStaff("You may only look through that exit.\n"); if(!staff) return(false); } if(!blinking && exit->getSize() && size > exit->getSize()) { if(p) checkStaff("Only %s and smaller creatures may go there.\n", getSizeName(exit->getSize()).c_str()); if(!staff) return(false); } if( (exit->flagIsSet(X_MALE_ONLY) && getSex() != SEX_MALE) || (exit->flagIsSet(X_FEMALE_ONLY) && getSex() != SEX_FEMALE) ) { if(p) checkStaff("Your sex prevents you from going that way.\n"); if(!staff) return(false); } if( (exit->flagIsSet(X_NIGHT_ONLY) && isDay()) || (exit->flagIsSet(X_DAY_ONLY) && !isDay()) ) { if(p) checkStaff("You may not go that way %s.\n", isDay() ? "during the day" : "at night"); if(!staff) return(false); } if( getConstRoomParent()->getTollkeeper() && (exit->flagIsSet(X_TOLL_TO_PASS) || exit->flagIsSet(X_LEVEL_BASED_TOLL)) ) { if(p) checkStaff("You must pay a toll of %lu gold coins to go through the %s^x.\n", tollcost(this->getAsConstPlayer(), exit, 0), exit->getCName()); if(!staff) return(false); } if(exit->clanRestrict(this)) { if(p) checkStaff("Your allegiance prevents you from going that way.\n"); if(!staff) return(false); } if(exit->classRestrict(this)) { if(p) checkStaff("Your class prevents you from going that way.\n"); if(!staff) return(false); } if(exit->raceRestrict(this)) { if(p) checkStaff("Your race prevents you from going that way.\n"); if(!staff) return(false); } if(exit->alignRestrict(this)) { if(p) checkStaff("Your alignment prevents you from going that way.\n"); if(!staff) return(false); } calendar = gConfig->getCalendar(); if(exit->flagIsSet(X_WINTER) && calendar->whatSeason() == WINTER) { if(p) checkStaff("Heavy winter snows prevent you from going that way.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_SPRING) && calendar->whatSeason() == SPRING) { if(p) checkStaff("Spring floods prevent you from going that way.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_SUMMER) && calendar->whatSeason() == SUMMER) { if(p) checkStaff("The summer heat prevent you from going that way.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_AUTUMN) && calendar->whatSeason() == AUTUMN) { if(p) checkStaff("You cannot go that way in autumn.\n"); if(!staff) return(false); } // we are a player if(isPlayer()) { if(exit->flagIsSet(X_NAKED) && getWeight()) { if(p) checkStaff("You cannot bring anything through that exit.\n"); if(!staff) return(false); } if(!canSee(exit)) { if(p) checkStaff("You don't see that exit.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_NEEDS_FLY) && !isEffected("fly")) { if(p) checkStaff("You must fly to go that way.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_NO_MIST) && isEffected("mist")) { if(p) checkStaff("You may not go that way in mist form.\n"); if(!staff) return(false); } if(exit->flagIsSet(X_MIST_ONLY) && !isEffected("mist")) { if(p) checkStaff(getAsConstPlayer()->canMistNow() ? "You must turn to mist before you can go that way.\n" : "You cannot fit through that exit.\n"); if(!staff) return(false); } const Monster* guard = getConstRoomParent()->getGuardingExit(exit, getAsConstPlayer()); if(guard) { if(p) checkStaff("%M %s.\n", guard, guard->flagIsSet(M_FACTION_NO_GUARD) ? "doesn't like you enough to let you go there" : "blocks your exit"); if(!staff) return(false); } // we are a monster } else { if(exit->flagIsSet(X_MIST_ONLY)) return(false); if(exit->flagIsSet(X_NO_WANDER)) return(false); if(exit->flagIsSet(X_TO_STORAGE_ROOM)) return(false); if(exit->flagIsSet(X_TO_BOUND_ROOM)) return(false); } return(true); } //******************************************************************** // canEnter //******************************************************************** bool Creature::canEnter(const UniqueRoom* room, bool p) const { // staff may always go anywhere bool staff = isStaff(); if(!room) { if(p) print("Off the map in that direction.\n"); if(staff) printColor("^eThat room does not exist.\n"); return(false); } // special rules for pets if(isPet()) { const Monster* mThis = getAsConstMonster(); if( room->isUnderwater() && mThis->getBaseRealm() != WATER && !isEffected("breathe-water") && !doesntBreathe() ) return(false); return(true); } if(isMonster()) p = false; if(size && room->getSize() && size > room->getSize()) { if(p) checkStaff("Only %s and smaller creatures may go there.\n", getSizeName(room->getSize()).c_str()); if(!staff) return(false); } // we are a player if(isPlayer()) { if(room->flagIsSet(R_SHOP_STORAGE)) { if(p) checkStaff("You cannot enter a shop's storage room.\n"); if(!staff) return(false); } if(room->getLowLevel() > level) { if(p) checkStaff("You must be at least level %d to go there.\n", room->getLowLevel()); if(!staff) return(false); } if(level > room->getHighLevel() && room->getHighLevel()) { if(p) checkStaff("Only players under level %d may go there.\n", room->getHighLevel()+1); if(!staff) return(false); } if(room->deityRestrict(this)) { if(p) checkStaff("Only members of the proper faith may go there.\n"); if(!staff) return(false); } if(room->isFull()) { if(p) checkStaff("That room is full.\n"); if(!staff) return(false); } if(room->flagIsSet(R_NO_MIST) && isEffected("mist")) { if(p) checkStaff("You may not enter there in mist form.\n"); if(!staff) return(false); } if(!staff && !flagIsSet(P_PTESTER) && room->isConstruction()) { if(p) print("Off the map in that direction.\n"); return(false); } if(!staff && room->flagIsSet(R_SHOP_STORAGE)) { if(p) print("Off the map in that direction.\n"); return(false); } if(!Property::canEnter(getAsConstPlayer(), room, p)) return(false); // we are a monster } else { // no rules for monsters } return(true); } //******************************************************************** // getWeight //******************************************************************** // This function calculates the total weight that a player (or monster) // is carrying in their inventory. int Creature::getWeight() const { int i=0, n=0; for(Object *obj : objects) { if(!obj->flagIsSet(O_WEIGHTLESS_CONTAINER)) n += obj->getActualWeight(); } for(i=0; i<MAXWEAR; i++) if(ready[i]) n += ready[i]->getActualWeight(); return(n); } //******************************************************************** // maxWeight //******************************************************************** // This function returns the maximum weight a player can be allowed to // hold in their inventory. int Creature::maxWeight() { int n = 20 + strength.getCur(); if(cClass == BERSERKER || isCt()) n += level*10; return(n); } //******************************************************************** // tooBulky //******************************************************************** bool Creature::tooBulky(int n) const { int total=0, i=0, max=0; if(isCt()) return(0); for(Object *obj : objects) { total += obj->getActualBulk(); } for(i=0; i<MAXWEAR; i++) if(ready[i]) total += (ready[i]->getActualBulk()/2); max = getMaxBulk(); return(n + getTotalBulk() > max); } //******************************************************************** // getTotalBulk //******************************************************************** int Creature::getTotalBulk() const { int n=0, i=0; for(Object *obj : objects) { n += obj->getActualBulk(); } for(i=0; i<MAXWEAR; i++) if(ready[i]) n += (ready[i]->getActualBulk()/2); return(n); } //******************************************************************** // getMaxBulk //******************************************************************** int Creature::getMaxBulk() const { switch(size) { case SIZE_FINE: return(10); case SIZE_DIMINUTIVE: return(30); case SIZE_TINY: return(60); case SIZE_SMALL: return(105); case SIZE_LARGE: return(185); case SIZE_HUGE: return(215); case SIZE_GARGANTUAN: return(245); case SIZE_COLOSSAL: return(275); case SIZE_MEDIUM: default: return(140); } } //******************************************************************** // willFit //******************************************************************** bool Creature::willFit(const Object* object) const { if(isStaff()) return(true); if(size && object->getSize()) { if(size == object->getSize()) return(true); // rings must be exact size if(object->getWearflag() == FINGER) return(false); // weapons and shields can be +- 1 category if( ( object->getType() == WEAPON || (object->getType() == ARMOR && object->getWearflag() == SHIELD) ) && abs(size - object->getSize()) == 1 ) return(true); // other armor can only be larger if(object->getType() == ARMOR && size - object->getSize() == -1) return(true); // if its wrong size, it can't be used return(false); } return(true); } //******************************************************************** // canWear //******************************************************************** bool Player::canWear(const Object* object, bool all) const { ASSERTLOG(object); if(!object->getWearflag() || object->getWearflag() == WIELD || object->getWearflag() == HELD) { if(!all) print("You can't wear that.\n"); return(false); } bstring armorType = object->getArmorType(); if( ( object->getType() == ARMOR && !object->isLightArmor() && ( object->getWearflag() == BODY || object->getWearflag() == ARMS || object->getWearflag() == HANDS ) ) && ( ready[HELD-1] && ready[HELD-1]->getType() < 6 ) ) { printColor("You can't wear %P and also use a second weapon.\n", object); printColor("%O would hinder your movement too much.\n", object); return(false); } if( object->getWearflag() != FINGER && object->getWearflag() != SHIELD && object->getType() == ARMOR && !isStaff() && !knowsSkill(armorType) ) { if(!all) printColor("You can't use %P; you lack the ability to wear %s armor.\n", object, armorType.c_str()); return(false); } if( object->getWearflag() == FINGER && ready[FINGER1-1] && ready[FINGER2-1] && ready[FINGER3-1] && ready[FINGER4-1] && ready[FINGER5-1] && ready[FINGER6-1] && ready[FINGER7-1] && ready[FINGER8-1] ) { if(!all) print("You don't have any more fingers left.\n"); return(false); } if(object->getWearflag() != FINGER && ready[object->getWearflag()-1]) { if(!all) { printColor("You cannot wear %1P.\nYou're already wearing %1P.\n", object, ready[object->getWearflag()-1]); } return(false); } if(object->isHeavyArmor() && inCombat() && checkHeavyRestrict("")) { if(!all) { printColor("^RYou're too busy fighting to fumble around with heavy armor right now!^x\n"); } return(false); } return(true); } //******************************************************************** // canUse //******************************************************************** bool Player::canUse(Object* object, bool all) { ASSERTLOG(object); if(object->getType() == WEAPON) { if(object->getWeaponType() == "none") { if(!all) printColor("You lack the skills to wield %P.\n", object); return(false); } if(isStaff()) return(true); // if(!knowsSkill(object->getWeaponType())) { if(!knowsSkill(object->getWeaponCategory())) { if(!all) print("You are not skilled with %s.\n", gConfig->getSkillDisplayName(object->getWeaponType()).c_str()); return(false); } } if(!willFit(object)) { if(!all) printColor("%O isn't the right size for you.\n", object); return(false); } if( size && object->getSize() && size != object->getSize() && object->getWearflag() != HELD-1 ) { if(!all) printColor("Using %P is awkward due to its size.\n", object); } if(object->getShotsCur() < 1 && object->getType() != WAND) { if(!all) print("You can't. It's broken.\n"); return(false); } if(object->doRestrict(this, !all)) return(false); return(true); } //******************************************************************** // canWield //******************************************************************** bool Creature::canWield(const Object* object, int n) const { int wielding=0, holding=0, shield=0, second=0; if(ready[WIELD-1]) wielding = 1; if(ready[HELD-1]) holding = 1; if(ready[HELD-1] && ready[HELD-1]->getType() < ARMOR) second = 1; if(ready[SHIELD-1]) shield = 1; switch (n) { case HOLDOBJ: if(second) { print("You're wielding a weapon in your off hand. You can't hold that.\n"); return(false); } if(holding) { print("You're already holding something.\n"); return(false); } if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD)) { print("Your shield is being held by your off hand. You can't hold that.\n"); return(false); } if(wielding && ready[WIELD-1]->needsTwoHands()) { printColor("You're using both hands to wield %P!\n", ready[WIELD-1]); return(false); } break; case WIELDOBJ: if(holding && object->needsTwoHands()) { printColor("You need both hands to wield %P.\nYou have %P in your off hand.\n", object, ready[HELD-1]); return(false); } if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD) && object->needsTwoHands()) { printColor("You need both hands to wield %P.\n%O uses your off hand.\n", object, ready[SHIELD-1]); return(false); } if(wielding) { printColor("You're already wielding %P.\n", ready[WIELD-1]); return(false); } if(cClass == CLERIC) { bstring objCategory = object->getWeaponCategory(); bstring objType = object->getWeaponType(); switch(deity) { case CERIS: if(objCategory != "crushing" && objCategory != "ranged" && objType != "polearm") { print("%s clerics may only use crushing, pole, and ranged weapons.\n", gConfig->getDeity(deity)->getName().c_str()); return(false); } break; case KAMIRA: if(objCategory == "ranged") { print("%s clerics may not use ranged weapons.\n", gConfig->getDeity(deity)->getName().c_str()); return(false); } break; } } break; case SECONDOBJ: if(second) { printColor("You're already wielding %P in your off hand.\n", ready[HELD-1]); return(false); } if(holding) { printColor("You're already holding %P in your off hand.\n", ready[HELD-1]); return(false); } if(shield && !ready[SHIELD-1]->flagIsSet(O_SMALL_SHIELD)) { printColor("Your shield is being held by your off hand. You can't second %P.\n", object); return(false); } if(object->needsTwoHands()) { printColor("%O requires two hands and cannot be used as a second weapon.\n", object); return(false); } if(wielding && ready[WIELD-1]->needsTwoHands()) { printColor("You're using both hands to wield %P!\n", ready[WIELD-1]); return(false); } if(cClass == RANGER) { if(ready[BODY-1] && !ready[BODY-1]->isLightArmor()) { printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[BODY-1]); return(false); } if(ready[ARMS-1] && !ready[ARMS-1]->isLightArmor()) { printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[ARMS-1]); return(false); } if(ready[HANDS-1] && !ready[HANDS-1]->isLightArmor()) { printColor("You must remove %P to wield a second weapon.\nIt is too heavy.\n", ready[HANDS-1]); return(false); } } break; case SHIELDOBJ: if(shield) { print("You're already wearing a shield.\n"); return(false); } if(holding && !object->flagIsSet(O_SMALL_SHIELD)) { printColor("You are using your shield arm to hold %P.\n", ready[HELD-1]); return(false); } if(wielding && !object->flagIsSet(O_SMALL_SHIELD) && ready[WIELD-1]->needsTwoHands()) { printColor("You're using both arms to wield %P!\n", ready[WIELD-1]); return(false); } break; }// end switch return(true); } //******************************************************************** // getInventoryValue //******************************************************************** unsigned long Creature::getInventoryValue() const { int a=0; long total=0; Object *object3=0; if(isMonster()) return(0); for(Object *object : objects) { if(object->getType() == CONTAINER) { for(Object *insideObject : object->objects) { if(insideObject->getType() == SCROLL || insideObject->getType() == POTION || insideObject->getType() == SONGSCROLL) { continue; } if(insideObject->getShotsCur() < 1 || insideObject->flagIsSet(O_NO_PAWN)) { continue; } if(insideObject->value[GOLD] < 20) { continue; } total += tMIN<unsigned long>(MAXPAWN,insideObject->value[GOLD]/2); total = tMAX<long>(0,tMIN<long>(2000000000,total)); } } if(object->getType() == SCROLL || object->getType() == POTION || object->getType() == SONGSCROLL) { continue; } if( (object->getShotsCur() < 1 && object->getType() != CONTAINER) || object->flagIsSet(O_NO_PAWN) ) { continue; } if(object->value[GOLD] < 20) { continue; } total += tMIN<unsigned long>(MAXPAWN,object->value[GOLD]/2); total = tMAX<long>(0,tMIN<long>(2000000000,total)); } for(a=0;a<MAXWEAR;a++) { if(!ready[a]) continue; object3 = ready[a]; if(object3->getType() == CONTAINER) { for(Object *insideObject : object3->objects) { if(insideObject->getType() == SCROLL || insideObject->getType() == POTION || insideObject->getType() == SONGSCROLL) { continue; } if(insideObject->getShotsCur() < 1 || insideObject->flagIsSet(O_NO_PAWN)) { continue; } if(insideObject->value[GOLD] < 20) { continue; } total += tMIN<unsigned long>(MAXPAWN,insideObject->value[GOLD]); total = tMAX<long>(0,tMIN<long>(2000000000,total)); } } if(object3->getType() == SCROLL || object3->getType()== POTION || object3->getType() == SONGSCROLL) continue; if( (object3->getShotsCur() < 1 && object3->getType() != CONTAINER) || object3->flagIsSet(O_NO_DROP) || object3->flagIsSet(O_NO_PAWN) ) continue; if(object3->value[GOLD] < 20) continue; total+=tMIN<unsigned long>(MAXPAWN,object3->value[GOLD]/2); total = tMAX<long>(0,tMIN<long>(2000000000,total)); } return(total); } //******************************************************************** // save //******************************************************************** // This function saves a player when the game decides to. It does // not issue a message that the player was saved. This should be called // instead of write_ply becuase it handles saving worn items properly // // This function saves a player's char. Since items need to be un-readied // before a player can be saved to a file, this function makes a duplicate // of the player, unreadies everything on the duplicate, and then saves // the duplicate to the file. Afterwards, the duplicate is freed from // memory. int Player::save(bool updateTime, LoadType saveType) { Player* copy=0; Object *obj[MAXWEAR]; int i=0, n=0; // having an update time option, which should be false for offline // operations, prevents aging of chars and keeps last login accurate if(updateTime) { lastLogin = time(0); lasttime[LT_AGE].interval += (lastLogin - lasttime[LT_AGE].ltime); lasttime[LT_AGE].ltime = lastLogin; } copy = new Player; if(!copy) merror("save", FATAL); *copy = *this; for(i=0; i<MAXWEAR; i++) { if(copy->ready[i]) { obj[n] = copy->unequip(i+1, UNEQUIP_ADD_TO_INVENTORY, false, false); obj[n]->setFlag(O_WORN); n++; copy->ready[i] = 0; } } if(copy->getName().empty()) return(1); copy->checkDarkness(); if(copy->saveToFile(saveType) < 0) printf("*** ERROR: saveXml!\n"); for(i=0; i<n; i++) copy->delObj(obj[i], false, false, true, false); copy->setId("-1"); delete copy; return(0); } //********************************************************************* // ableToDoCommand //********************************************************************* bool Creature::ableToDoCommand(const cmd* cmnd) const { if(isMonster()) return(true); if(flagIsSet(P_BRAINDEAD)) { print("You are brain-dead. You can't do that.\n"); return(false); } // unconscious has some special rules if(flagIsSet(P_UNCONSCIOUS)) { // if they're sleeping, let them do only a few things if(cmnd && flagIsSet(P_SLEEPING) && ( cmnd->myCommand->getName() == "wake" || cmnd->myCommand->getName() == "snore" || cmnd->myCommand->getName() == "murmur" || cmnd->myCommand->getName() == "dream" || cmnd->myCommand->getName() == "rollover" ) ) return(true); if(flagIsSet(P_SLEEPING)) print("You can't do that while sleeping.\n"); else print("How can you do that while unconscious?\n"); return(false); } return(true); } //********************************************************************* // inCombat //********************************************************************* // we don't care if they are fighting people in other rooms - // we only care if they're fighting someone in THIS room bool Creature::inCombat(bool countPets) const { return(inCombat(0, countPets)); } // target is used when you want to check for a player being in combat // with a mob BESIDES the one pointed to by creature. bool Creature::inCombat(const Creature* target, bool countPets) const { // people just logging in if(!getParent()) return(false); const Monster* mThis = getAsConstMonster(); if(mThis) { for(Player* ply : getParent()->players) { if(mThis->isEnemy(ply)) return(true); } for(Monster* mons : getParent()->monsters) { if(mThis->isEnemy(mons)) return(true); } } else { for(Monster* mons : getParent()->monsters) { if(mons->isEnemy(this) && (!target || mons != target) && (countPets || !mons->isPet())) return(true); } } return(false); } bool Creature::convertFlag(int flag) { if(flagIsSet(flag)) { clearFlag(flag); return(true); } return(false); } //********************************************************************* // getCrtStr //********************************************************************* bstring Creature::getCrtStr(const Creature* viewer, int flags, int num) const { std::ostringstream crtStr; bstring toReturn = ""; char ch; int mobNum=0; // char *str; if(!this) return("(ERROR: NULL CRT)"); if(viewer) flags |= viewer->displayFlags(); const Player* pThis = getAsConstPlayer(); // Player if(isPlayer()) { // Target is possessing a monster -- Show the monsters name if invis if(flagIsSet(P_ALIASING) && flagIsSet(P_DM_INVIS)) { if(!pThis->getAlias()->flagIsSet(M_NO_PREFIX)) { crtStr << "A " << pThis->getAlias()->getName(); } else crtStr << pThis->getAlias()->getName(); } // Target is a dm, is dm invis, and viewer is not a dm OR // Target is a ct, is dm invis, and viewer is not a dm or ct OR // Target is staff less than a ct and is dm invis, viewier is less than a builder else if((cClass == DUNGEONMASTER && flagIsSet(P_DM_INVIS) && !(flags & ISDM) ) || (cClass == CARETAKER && (flagIsSet(P_DM_INVIS) && !(flags & ISDM) && !(flags & ISCT))) || (flagIsSet(P_DM_INVIS) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) ) { crtStr << "Someone"; } // Target is misted, viewer can't detect mist, or isn't staff else if( isEffected("mist") && !(flags & MIST) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) { crtStr << "A light mist"; } // Target is invisible and viewer doesn't have detect-invis or isn't staff else if(isInvisible() && !(flags & INV) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) { crtStr << "Someone"; } // Can be seen else { crtStr << getName(); if( flagIsSet(P_DM_INVIS ) ) crtStr << " (+)"; // Invis else if(isInvisible()) crtStr << " (*)"; // Misted else if(isEffected("mist")) crtStr << " (m)"; } toReturn = crtStr.str(); return(toReturn); } // Monster // Target is a monster, is invisible, and viewer doesn't have detect-invis or is not staff if(isMonster() && isInvisible() && !(flags & INV) && !(flags & ISDM) && !(flags & ISCT) && !(flags & ISBD)) { crtStr << "Something"; } else { if(num == 0) { if(!flagIsSet(M_NO_PREFIX)) { crtStr << "the "; if(!(flags & NONUM)) { mobNum = ((Monster*)this)->getNumMobs(); if(mobNum>1) { crtStr << getOrdinal(mobNum).c_str(); crtStr << " "; } } crtStr << getName(); } else crtStr << getName(); } else if(num == 1) { if(flagIsSet(M_NO_PREFIX)) crtStr << ""; else { ch = low(getName()[0]); if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u') crtStr << "an "; else crtStr << "a "; } crtStr << getName(); } else if(plural != "") { // use new plural code - on monster crtStr << int_to_text(num); crtStr << " " ; crtStr << plural; } else { char tempStr[2056]; strcpy(tempStr, int_to_text(num)); strcat(tempStr, " "); strcat(tempStr, getCName()); 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'; } crtStr << tempStr; } // Target is magic, and viewer has detect magic on if((flags & MAG) && mFlagIsSet(M_CAN_CAST)) crtStr << " (M)"; } toReturn = crtStr.str(); if(flags & CAP) { int pos = 0; // don't capitalize colors while(toReturn[pos] == '^') pos += 2; toReturn[pos] = up(toReturn[pos]); } return(toReturn); } //********************************************************************* // inSameRoom //********************************************************************* bool Creature::inSameRoom(Creature* target) { return(target && target->getRoomParent() == getRoomParent()); } //********************************************************************* // getLTLeft //********************************************************************* // gets the time left on a LT long Creature::getLTLeft(int myLT, long t) { if(t == -1) t = time(0); long i = lasttime[myLT].ltime + lasttime[myLT].interval; if(i > t) return(i-t); else return(0); } //********************************************************************* // setLastTime //********************************************************************* // Sets a LT void Creature::setLastTime(int myLT, long t, long interval) { lasttime[myLT].interval = tMAX(interval, getLTLeft(myLT, t)); lasttime[myLT].ltime = t; } //********************************************************************* // unApplyTongues //********************************************************************* void Creature::unApplyTongues() { Player* pTarget = getAsPlayer(); if(pTarget) { if(!pTarget->languageIsKnown(LUNKNOWN + pTarget->current_language)) { bstring selfStr = ""; int i; selfStr.append("You can no longer speak"); selfStr.append(get_language_adj(pTarget->current_language)); selfStr.append ("\n"); if(pTarget->languageIsKnown(LUNKNOWN+LCOMMON)) { pTarget->current_language = LCOMMON; } else { // oh no, they don't know common; time to find a language they do know for(i=0; i<LANGUAGE_COUNT; i++) { if(pTarget->languageIsKnown(LUNKNOWN+i)) { pTarget->current_language = i; break; } } } } } }