/* * exits.cpp * Exit 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 "effects.h" #include "magic.h" #include <sstream> //********************************************************************* // Exit //********************************************************************* Exit::Exit() { zero(name, sizeof(name)); level = trap = 0; zero(desc_key, sizeof(desc_key)); zero(clanFlags, sizeof(clanFlags)); zero(classFlags, sizeof(classFlags)); zero(raceFlags, sizeof(raceFlags)); zero(randExit, sizeof(randExit)); key = toll = 0; size = NO_SIZE; zero(flags, sizeof(flags)); keyArea = passphrase = open = enter = ""; passlang = 0; size = NO_SIZE; hooks.setParent(this); } Exit::~Exit() { if(effects.list.size()) { //BaseRoom* parent = effects.list.front()->getParentRoom(); effects.removeAll(); //parent->removeEffectsIndex(); } } short Exit::getLevel() const { return(level); } bstring Exit::getOpen() const { return(open); } short Exit::getTrap() const { return(trap); } short Exit::getKey() const { return(key); } bstring Exit::getKeyArea() const { return(keyArea); } short Exit::getToll() const { return(toll); } bstring Exit::getPassPhrase() const { return(passphrase); } short Exit::getPassLanguage() const { return(passlang); } Size Exit::getSize() const { return(size); } bstring Exit::getEnter() const { return(enter); } void Exit::setLevel(short lvl) { level = lvl; } void Exit::setOpen(bstring o) { open = o; } void Exit::setTrap(short t) { trap = t; } void Exit::setKey(short k) { key = k; } void Exit::setKeyArea(bstring k) { keyArea = k; } void Exit::setToll(short t) { toll = t; } void Exit::setPassPhrase(bstring phrase) { passphrase = phrase; } void Exit::setPassLanguage(short lang) { passlang = lang; } void Exit::setSize(Size s) { size = s; } void Exit::setEnter(bstring e) { enter = e; } bool Exit::flagIsSet(int flag) const { return(flags[flag/8] & 1<<(flag%8)); } void Exit::setFlag(int flag) { flags[flag/8] |= 1<<(flag%8); } void Exit::clearFlag(int flag) { flags[flag/8] &= ~(1<<(flag%8)); } bool Exit::toggleFlag(int flag) { if(flagIsSet(flag)) clearFlag(flag); else setFlag(flag); return(flagIsSet(flag)); } //********************************************************************* // findExit //********************************************************************* // This function attempts to find the exit specified by the given string // and value by looking through the exit list headed by the second para- // meter. If found, a pointer to the exit is returned. Exit *findExit(Creature* creature, cmd* cmnd, int val, xtag *first_xt) { return(findExit(creature, cmnd->str[val], cmnd->val[val], first_xt)); } Exit *findExit(Creature* creature, bstring str, int val, xtag *first_xt) { xtag *xp = first_xt; Exit *exit=0; int match=0; bool minThree = (creature->getPlayer() && !creature->isStaff() && str.length() < 3); if(!xp) xp = creature->getRoom()->first_ext; while(xp) { exit = xp->ext; xp = xp->next_tag; if(!creature->isStaff()) { if(!creature->canSee(exit)) continue; if( minThree && (exit->flagIsSet(X_CONCEALED) || exit->flagIsSet(X_SECRET)) && strlen(exit->name) > 2 ) continue; } if(!exit->flagIsSet(X_DESCRIPTION_ONLY) || creature->isStaff()) { if(!strncmp(exit->name, str.c_str(), str.length())) match++; } else { if(!strcmp(exit->name, str.c_str())) match++; } if(match == val) return(exit); } return(0); } //********************************************************************* // raceRestrict //********************************************************************* bool Exit::raceRestrict(const Creature* creature) const { bool pass = false; // if no flags are set if( !flagIsSet(X_SEL_DWARF) && !flagIsSet(X_SEL_ELF) && !flagIsSet(X_SEL_HALFELF) && !flagIsSet(X_SEL_HALFLING) && !flagIsSet(X_SEL_HUMAN) && !flagIsSet(X_SEL_ORC) && !flagIsSet(X_SEL_HALFGIANT) && !flagIsSet(X_SEL_GNOME) && !flagIsSet(X_SEL_TROLL) && !flagIsSet(X_SEL_HALFORC) && !flagIsSet(X_SEL_OGRE) && !flagIsSet(X_SEL_DARKELF) && !flagIsSet(X_SEL_GOBLIN) && !flagIsSet(X_SEL_MINOTAUR) && !flagIsSet(X_SEL_SERAPH) && !flagIsSet(X_SEL_KOBOLD) && !flagIsSet(X_SEL_CAMBION) && !flagIsSet(X_SEL_BARBARIAN) && !flagIsSet(X_SEL_KATARAN) && !flagIsSet(X_SEL_TIEFLING) && !flagIsSet(X_RSEL_INVERT) ) return(false); // if the race flag is set and they match, they pass pass = ( (flagIsSet(X_SEL_DWARF) && creature->isRace(DWARF)) || (flagIsSet(X_SEL_ELF) && creature->isRace(ELF)) || (flagIsSet(X_SEL_HALFELF) && creature->isRace(HALFELF)) || (flagIsSet(X_SEL_HALFLING) && creature->isRace(HALFLING)) || (flagIsSet(X_SEL_HUMAN) && creature->isRace(HUMAN)) || (flagIsSet(X_SEL_ORC) && creature->isRace(ORC)) || (flagIsSet(X_SEL_HALFGIANT) && creature->isRace(HALFGIANT)) || (flagIsSet(X_SEL_GNOME) && creature->isRace(GNOME)) || (flagIsSet(X_SEL_TROLL) && creature->isRace(TROLL)) || (flagIsSet(X_SEL_HALFORC) && creature->isRace(HALFORC)) || (flagIsSet(X_SEL_OGRE) && creature->isRace(OGRE)) || (flagIsSet(X_SEL_DARKELF) && creature->isRace(DARKELF)) || (flagIsSet(X_SEL_GOBLIN) && creature->isRace(GOBLIN)) || (flagIsSet(X_SEL_MINOTAUR) && creature->isRace(MINOTAUR)) || (flagIsSet(X_SEL_SERAPH) && creature->isRace(SERAPH)) || (flagIsSet(X_SEL_KOBOLD) && creature->isRace(KOBOLD)) || (flagIsSet(X_SEL_CAMBION) && creature->isRace(CAMBION)) || (flagIsSet(X_SEL_BARBARIAN) && creature->isRace(BARBARIAN)) || (flagIsSet(X_SEL_KATARAN) && creature->isRace(KATARAN)) || (flagIsSet(X_SEL_TIEFLING) && creature->isRace(TIEFLING)) ); if(flagIsSet(X_RSEL_INVERT)) pass = !pass; return(!pass); } //********************************************************************* // classRestrict //********************************************************************* bool Exit::classRestrict(const Creature* creature) const { bool pass = false; // if no flags are set if( !flagIsSet(X_SEL_ASSASSIN) && !flagIsSet(X_SEL_BERSERKER) && !flagIsSet(X_SEL_CLERIC) && !flagIsSet(X_SEL_FIGHTER) && !flagIsSet(X_SEL_MAGE) && !flagIsSet(X_SEL_PALADIN) && !flagIsSet(X_SEL_RANGER) && !flagIsSet(X_SEL_THIEF) && !flagIsSet(X_SEL_VAMPIRE) && !flagIsSet(X_SEL_MONK) && !flagIsSet(X_SEL_DEATHKNIGHT) && !flagIsSet(X_SEL_DRUID) && !flagIsSet(X_SEL_LICH) && !flagIsSet(X_SEL_WEREWOLF) && !flagIsSet(X_SEL_BARD) && !flagIsSet(X_SEL_ROGUE) && !flagIsSet(X_CSEL_INVERT) ) return(false); // if the class flag is set and they match, they pass pass = ( (flagIsSet(X_SEL_ASSASSIN) && creature->getClass() == ASSASSIN) || (flagIsSet(X_SEL_BERSERKER) && creature->getClass() == BERSERKER) || (flagIsSet(X_SEL_CLERIC) && creature->getClass() == CLERIC) || (flagIsSet(X_SEL_FIGHTER) && creature->getClass() == FIGHTER) || (flagIsSet(X_SEL_MAGE) && creature->getClass() == MAGE) || (flagIsSet(X_SEL_PALADIN) && creature->getClass() == PALADIN) || (flagIsSet(X_SEL_RANGER) && creature->getClass() == RANGER) || (flagIsSet(X_SEL_THIEF) && creature->getClass() == THIEF) || (flagIsSet(X_SEL_VAMPIRE) && creature->isEffected("vampirism")) || (flagIsSet(X_SEL_MONK) && creature->getClass() == MONK) || (flagIsSet(X_SEL_DEATHKNIGHT) && creature->getClass() == DEATHKNIGHT) || (flagIsSet(X_SEL_DRUID) && creature->getClass() == DRUID) || (flagIsSet(X_SEL_LICH) && creature->getClass() == LICH) || (flagIsSet(X_SEL_WEREWOLF) && creature->isEffected("lycanthropy")) || (flagIsSet(X_SEL_BARD) && creature->getClass() == BARD) || (flagIsSet(X_SEL_ROGUE) && creature->getClass() == ROGUE) ); if(flagIsSet(X_CSEL_INVERT)) pass = !pass; return(!pass); } //********************************************************************* // clanRestrict //********************************************************************* bool Exit::clanRestrict(const Creature* creature) const { // if the exit requires pledging, let any clan pass if(flagIsSet(X_PLEDGE_ONLY)) return(creature->getClan()!=0); // if no flags are set if( !flagIsSet(X_CLAN_1) && !flagIsSet(X_CLAN_2) && !flagIsSet(X_CLAN_3) && !flagIsSet(X_CLAN_4) && !flagIsSet(X_CLAN_5) && !flagIsSet(X_CLAN_6) && !flagIsSet(X_CLAN_7) && !flagIsSet(X_CLAN_8) && !flagIsSet(X_CLAN_9) && !flagIsSet(X_CLAN_10) && !flagIsSet(X_CLAN_11) && !flagIsSet(X_CLAN_12) ) return(false); // if the clan flag is set and they match, they pass if( (flagIsSet(X_CLAN_1) && creature->getClan() == 1) || (flagIsSet(X_CLAN_2) && creature->getClan() == 2) || (flagIsSet(X_CLAN_3) && creature->getClan() == 3) || (flagIsSet(X_CLAN_4) && creature->getClan() == 4) || (flagIsSet(X_CLAN_5) && creature->getClan() == 5) || (flagIsSet(X_CLAN_6) && creature->getClan() == 6) || (flagIsSet(X_CLAN_7) && creature->getClan() == 7) || (flagIsSet(X_CLAN_8) && creature->getClan() == 8) || (flagIsSet(X_CLAN_9) && creature->getClan() == 9) || (flagIsSet(X_CLAN_10) && creature->getClan() == 10) || (flagIsSet(X_CLAN_11) && creature->getClan() == 11) || (flagIsSet(X_CLAN_12) && creature->getClan() == 12) ) return(false); return(true); } //********************************************************************* // alignRestrict //********************************************************************* bool Exit::alignRestrict(const Creature* creature) const { return( (flagIsSet(X_NO_GOOD_ALIGN) && creature->getAdjustedAlignment() > NEUTRAL) || (flagIsSet(X_NO_EVIL_ALIGN) && creature->getAdjustedAlignment() < NEUTRAL) || (flagIsSet(X_NO_NEUTRAL_ALIGN) && creature->getAdjustedAlignment() == NEUTRAL) ); } //********************************************************************* // getReturnExit //********************************************************************* // Tries to find a return exit. Will only return an exit if there is // only one unique exit back to the parent room. Exit* Exit::getReturnExit(const BaseRoom* parent, BaseRoom** targetRoom) const { (*targetRoom) = target.loadRoom(); if(!*targetRoom) return(0); xtag* xp = (*targetRoom)->first_ext; Exit* exit=0; bool found = false; const AreaRoom* aRoom = parent->getConstAreaRoom(); const Room* uRoom = parent->getConstUniqueRoom(); while(xp) { if(xp->ext->target.mapmarker.getArea()) { if(aRoom && xp->ext->target.mapmarker == aRoom->mapmarker) { if(found) return(0); exit = xp->ext; found = true; } } else { if(uRoom && xp->ext-> target.room == uRoom->info) { if(found) return(0); exit = xp->ext; found = true; } } xp = xp->next_tag; } return(exit); } //********************************************************************* // blockedByStr //********************************************************************* bstring Exit::blockedByStr(char color, bstring spell, bstring effectName, bool detectMagic, bool canSee) const { EffectInfo* effect = 0; std::ostringstream oStr; if(canSee) oStr << "^" << color << "The " << name << " is blocked by a " << spell; else oStr << "^" << color << "A " << spell << " stands in the room"; if(detectMagic) { effect = getEffect(effectName); if(effect->getOwner() != "") oStr << " (cast by " << effect->getOwner() << ")"; } oStr << ".\n"; return(oStr.str()); } //********************************************************************* // showExit //********************************************************************* bool Player::showExit(const Exit* exit, int magicShowHidden) const { if(isStaff()) return(true); return( canSee(exit) && (!exit->flagIsSet(X_SECRET) || magicShowHidden) && !exit->isConcealed(this) && !exit->flagIsSet(X_DESCRIPTION_ONLY) && (isEffected("fly") ? 1:!exit->flagIsSet(X_NEEDS_FLY)) ); } //********************************************************************* // addEffectReturnExit //********************************************************************* // Add an effect to the given exit and the return exit (ie, an exit in // the room it points to that points back to this room) void Exit::addEffectReturnExit(bstring effect, long duration, int strength, const Creature* owner) { BaseRoom *targetRoom=0; addEffect(effect, duration, strength, true, owner->getRoom(), owner); // switch the meaning of exit Exit* exit = getReturnExit(owner->getRoom(), &targetRoom); if(exit) exit->addEffect(effect, duration, strength, true, targetRoom, owner); } //********************************************************************* // removeEffectReturnExit //********************************************************************* // Add an effect to the given exit and the return exit (ie, an exit in // the room it points to that points back to this room) void Exit::removeEffectReturnExit(bstring effect, BaseRoom* rParent) { BaseRoom *targetRoom=0; removeEffect(effect, true, false, rParent); // switch the meaning of exit Exit* exit = getReturnExit(rParent, &targetRoom); if(exit) exit->removeEffect(effect, true, false, targetRoom); } //********************************************************************* // isWall //********************************************************************* bool Exit::isWall(bstring name) const { EffectInfo* effect = getEffect(name); if(!effect) return(false); // a wall of force with "extra" set is temporarily disabled if(effect->getExtra()) return(false); return(true); } //********************************************************************* // isConcealed //********************************************************************* bool Exit::isConcealed(const Creature* viewer) const { if(flagIsSet(X_CONCEALED)) return(true); if(isEffected("concealed") && (!viewer || !viewer->willIgnoreIllusion())) return(true); return(false); }