/* * magic1.cpp * User routines dealing with magic spells. Potions, wands, scrolls, and casting are all covered. * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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 "move.h" #include "magic.h" #include "commands.h" #include "craft.h" #include "unique.h" #include "effects.h" #include "alchemy.h" void spellShortcut(char *spell) { if(!strcasecmp(spell, "m")) strcpy(spell, "mend"); if(!strcasecmp(spell, "v")) strcpy(spell, "vigor"); if(!strcasecmp(spell, "d-i")) strcpy(spell, "detect-invis"); if(!strcasecmp(spell, "d-m")) strcpy(spell, "detect-magic"); } int doMpCheck(Creature* target, int splno) { // If required MP is set to -1, the spell function is reponsible for verifying // the caster has enough MP, otherwise it is checked here int reqMp = getSpellMp(splno); if(reqMp != -1) { if(!target->checkMp(reqMp)) return(0); // Handle spell fail here now if the spell doesn't handle mp on it's own if(!(splno == S_VIGOR || splno == S_MEND_WOUNDS) && spell_fail(target, CAST)) { // Reduced spell fails to half mp target->subMp(MAX(1,reqMp/2)); return(0); } } return(reqMp); } //********************************************************************* // cmdCast //********************************************************************* // wrapper for doCast because doCast returns more information than we want int cmdCast(Creature* creature, cmd* cmnd) { doCast(creature, cmnd); return(0); } //********************************************************************* // cmdCast //********************************************************************* // This function allows a creature to cast a magical spell. It looks at // the second parsed word to find out if the spell-name is valid, and // then calls the appropriate spell function. CastResult doCast(Creature* creature, cmd* cmnd) { long i=0, t=0; int (*fn)(SpellFn); int c=0, match=0, n=0, num=0, lvl=0, reqMp=0; ctag *cp=0; Player* player = creature->getMaster(); bool offensive=false, self = (!player || player == creature); Creature* listen = (player ? player : creature); SpellData data; if(player) { player->clearFlag(P_AFK); player->setFishing(false); if(!player->ableToDoCommand()) return(CAST_RESULT_FAILURE); } if(creature->getClass() == BERSERKER) { listen->print("Cast? BAH! Magic is for the weak! Bash and cut instead!\n"); return(CAST_RESULT_FAILURE); } if(player && player->getClass() == FIGHTER && !player->getSecondClass() && player->flagIsSet(P_PTESTER)) { listen->print("You lack training in the arcane arts.\n"); return(CAST_RESULT_FAILURE); } if(cmnd->num < 2) { if(self) listen->print("Cast what?\n"); else listen->print("Tell %N to cast what?\n", creature); return(CAST_RESULT_FAILURE); } // always let staff cast if(!player || !player->isStaff()) { if(creature->isEffected("confusion") || creature->isEffected("drunkenness")) { if(self) listen->print("Your mind is too clouded for that right now.\n"); else listen->print("%M's mind is too clouded for that right now.\n", creature); return(CAST_RESULT_CURRENT_FAILURE); } if(player && player->isBlind()) { listen->printColor("^CYou can't see to direct the incantation!\n"); return(CAST_RESULT_CURRENT_FAILURE); } if(creature->isBlind()) { listen->printColor("^C%M can't see to direct the incantation!\n", creature); return(CAST_RESULT_CURRENT_FAILURE); } if(player && !player->canSpeak()) { listen->printColor("^yYou can't speak the incantation!\n"); return(CAST_RESULT_CURRENT_FAILURE); } if(!creature->canSpeak()) { listen->printColor("^y%M can't speak the incantation!\n", creature); return(CAST_RESULT_CURRENT_FAILURE); } } spellShortcut(cmnd->str[1]); do { if(!strcmp(cmnd->str[1], get_spell_name(c))) { match = 1; data.splno = c; break; } else if(!strncmp(cmnd->str[1], get_spell_name(c), strlen(cmnd->str[1]))) { match++; data.splno = c; } c++; } while(get_spell_num(c) != -1); if(match == 0) { listen->print("That spell does not exist.\n"); return(CAST_RESULT_FAILURE); } else if(match > 1) { listen->print("Spell name is not unique.\n"); return(CAST_RESULT_FAILURE); } if(!creature->spellIsKnown(get_spell_num(data.splno))) { if(self) listen->print("You don't know that spell.\n"); else listen->print("%M doesn't know that spell.\n", creature); return(CAST_RESULT_FAILURE); } if( creature->getRoom()->flagIsSet(R_NO_MAGIC) && !creature->checkStaff("Nothing happens.\n") ) return(CAST_RESULT_FAILURE); if( player == creature && player->flagIsSet(P_SITTING) && data.splno != S_VIGOR && data.splno != S_MEND_WOUNDS && data.splno != S_BLESS && data.splno != S_PROTECTION && data.splno != S_HEAL ) { listen->print("You cannot cast that while sitting.\n"); return(CAST_RESULT_FAILURE); } if(player == creature) i = MAX(LT(creature, LT_SPELL), creature->lasttime[LT_READ_SCROLL].interval + 2); else i = LT(creature, LT_SPELL); t = time(0); if(t < i && i != MAXINT) { listen->pleaseWait(i-t); return(CAST_RESULT_CURRENT_FAILURE); } num = get_spell_lvl(data.splno); if(num == 3) lvl = 5; else if(num == 4) lvl = 10; else if(num == 5) lvl = 16; else if(num == 6) lvl = 16; else lvl = 0; if(player == creature && !player->isCt() && num > 0) { if( (num == 3 && player->getLevel() < 5) || (num == 4 && player->getLevel() < 10) || (num == 5 && player->getLevel() < 16) || (num == 6 && player->getLevel() < 16) ) { listen->print("You must be at least level %d to cast that spell.\n", lvl); return(CAST_RESULT_FAILURE); } } if(!player || !player->isStaff()) { cp = creature->getRoom()->first_mon; while(cp) { if(cp->crt->flagIsSet(M_ANTI_MAGIC_AURA)) { broadcast(NULL, creature->getRoom(), "^B%M glows bright blue.", cp->crt); if(self) listen->printColor("^yYour spell fails.\n"); else listen->printColor("^y%M's spell fails.\n", creature); return(CAST_RESULT_SPELL_FAILURE); } cp = cp->next_tag; } } reqMp = doMpCheck(creature, data.splno); if(!reqMp) return(CAST_RESULT_CURRENT_FAILURE); fn = get_spell_function(data.splno); data.set(CAST, get_spell_school(data.splno), 0, creature); if(!data.check(creature)) return(CAST_RESULT_FAILURE); offensive = (int(*)(SpellFn, char*, osp_t*))fn == splOffensive || (int(*)(SpellFn, char*, osp_t*))fn == splMultiOffensive; if(offensive) { for(c=0; ospell[c].splno != get_spell_num(data.splno); c++) if(ospell[c].splno == -1) return(CAST_RESULT_FAILURE); n = ((int(*)(SpellFn, const char*, osp_t*))*fn) (creature, cmnd, &data, get_spell_name(data.splno), &ospell[c]); } else { n = ((int(*)(SpellFn))*fn) (creature, cmnd, &data); } // Spell failed or didn't cast if(!n) return(CAST_RESULT_SPELL_FAILURE); // If reqMp is valid, subtract the mp here if(reqMp != -1) creature->subMp(reqMp); if(player) { player->statistics.cast(); player->unhide(); } if(player != creature) creature->unhide(); creature->lasttime[LT_SPELL].ltime = t; if(player != creature) { creature->lasttime[LT_SPELL].interval = 4; creature->updateAttackTimer(true, DEFAULT_WEAPON_DELAY); return(CAST_RESULT_SUCCESS); } switch(player->getClass()) { case DUNGEONMASTER: case CARETAKER: player->lasttime[LT_SPELL].interval = 0; break; case MAGE: if(player->getSecondClass() == MAGE || player->getSecondClass() == ASSASSIN) player->lasttime[LT_SPELL].interval = 4; else player->lasttime[LT_SPELL].interval = 3; break; case BUILDER: case LICH: player->lasttime[LT_SPELL].interval = 3; break; case BARD: case VAMPIRE: case PALADIN: case DRUID: player->lasttime[LT_SPELL].interval = 4; break; case CLERIC: if(player->getSecondClass() == ASSASSIN) player->lasttime[LT_SPELL].interval = 5; else player->lasttime[LT_SPELL].interval = 4; break; case FIGHTER: if(player->getSecondClass() == MAGE) { bool heavy = false; for(int z = 0 ; z < MAXWEAR ; z++) { if(player->ready[z] && (player->ready[z]->isHeavyArmor() || player->ready[z]->isMediumArmor())) { player->printColor("^W%P^x hinders your movement!\n",player->ready[z]); heavy = true; break; } } if(heavy) player->lasttime[LT_SPELL].interval = 5; else player->lasttime[LT_SPELL].interval = 4; } else player->lasttime[LT_SPELL].interval = 5; break; case THIEF: player->lasttime[LT_SPELL].interval = 5; break; default: player->lasttime[LT_SPELL].interval = 5; break; } // casting time settings for some specific spells override standard // casting delays for classes. -TC switch(data.splno) { case S_REJUVENATE: player->lasttime[LT_SPELL].interval = 20L; break; } // improve schools of magic // Can't improve evocation spells by casting on yourself if(data.skill != "" && (data.school != EVOCATION || !self)) player->checkImprove(data.skill, true); return(CAST_RESULT_SUCCESS); } //********************************************************************* // cmdTeach //********************************************************************* // This function allowsspell-casters to teach other players basic spells int cmdTeach(Player* player, cmd* cmnd) { Creature* target=0; int splno=0, c=0, match=0; bstring skill = ""; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 3) { player->print("Teach whom what?\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } if(!player->canSpeak()) { player->printColor("^yYou can't speak to do that!\n"); return(0); } if(!player->isStaff()) { if((player->getClass() != MAGE && player->getClass() != CLERIC)) { player->print("Only mages and clerics may teach spells.\n"); return(0); } if(player->getSecondClass()) { player->print("Only true mages and clerics are able to teach.\n"); return(0); } } else if(player->getClass() == BUILDER) { if(!player->canBuildMonsters()) return(cmdNoAuth(player)); if(!player->checkBuilder(player->parent_rom)) { player->print("Error: room number not in any of your alotted ranges.\n"); return(0); } } target = player->getRoom()->findCreature(player, cmnd->str[1], cmnd->val[1], false); if(!target || target == player) { player->print("You don't see that person here.\n"); return(0); } if(target->flagIsSet(P_LINKDEAD) && target->isPlayer()) { player->print("%M doesn't want to be taught right now.\n", target); return(0); } spellShortcut(cmnd->str[2]); do { if(!strcmp(cmnd->str[2], get_spell_name(c))) { match = 1; splno = c; break; } else if(!strncmp(cmnd->str[2], get_spell_name(c), strlen(cmnd->str[2]))) { match++; splno = c; } c++; } while(get_spell_num(c) != -1); if(match == 0) { player->print("That spell does not exist.\n"); return(0); } else if(match > 1) { player->print("Spell name is not unique.\n"); return(0); } if(!player->spellIsKnown(get_spell_num(splno))) { player->print("You don't know that spell.\n"); return(0); } if(!player->isStaff()) { if(player->getClass() == CLERIC && get_spell_num(splno) != 0 && get_spell_num(splno) != 3 && get_spell_num(splno) != 4) { player->print("You may not teach that spell to anyone.\n"); return(0); } if(player->getClass() == CLERIC && (get_spell_num(splno) == 3) && target->getClass() != CLERIC && target->getClass() != PALADIN) { player->print("You may only teach that spell to clerics and paladins.\n"); return(0); } if(player->getClass() == MAGE && get_spell_num(splno) != 2 && get_spell_num(splno) != 5 && get_spell_num(splno) != 27 && get_spell_num(splno) != 28) { player->print("You may not teach that spell to anyone.\n"); return(0); } if(target->isMonster()) { player->print("You may not teach spells to monsters.\n"); return(0); } } else if(player->getClass() == BUILDER) { if(target->isPlayer()) { player->print("You may not teach spells to players.\n"); return(0); } } if(target->isPlayer() && !player->isDm() && get_spell_num(splno) != 2 && get_spell_num(splno) != 5 && get_spell_num(splno) != 27 && get_spell_num(splno) != 28 && get_spell_num(splno) != 0 && get_spell_num(splno) != 3 && get_spell_num(splno) != 4) { player->print("You may not teach those spells to anyone.\n"); return(0); } player->unhide(); if(target->spellIsKnown(get_spell_num(splno)) && target->isMonster() && player->isStaff()) { logn("log.teach", "%s caused %s to forget %s.\n", player->name, target->name, get_spell_name(splno)); player->print("Spell \"%s\" removed from %N's memory.\n", get_spell_name(splno), target); target->forgetSpell(get_spell_num(splno)); } else if(target->spellIsKnown(get_spell_num(splno)) && target->isPlayer() && player->isDm()) { logn("log.teach", "%s caused %s to forget %s.\n", player->name, target->name, get_spell_name(splno)); player->print("Spell \"%s\" removed from %N's memory.\n", get_spell_name(splno), target); target->forgetSpell(get_spell_num(splno)); } else { if(target->isPlayer()) { skill = spellSkill(get_spell_school(splno)); if(skill != "") { if(!player->knowsSkill(skill)) { player->print("You are unable to teach %s spells.\n", gConfig->getSkillDisplayName(skill).c_str()); return(0); } if(!target->knowsSkill(skill)) { player->print("%M is unable to learn %s spells.\n", target, gConfig->getSkillDisplayName(skill).c_str()); return(0); } } } target->learnSpell(get_spell_num(splno)); target->print("%M teaches you the %s spell.\n", player, get_spell_name(splno)); player->print("Spell \"%s\" taught to %N.\n", get_spell_name(splno), target); if(!player->flagIsSet(P_DM_INVIS) && !player->flagIsSet(P_INCOGNITO)) { broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M taught %N the %s spell.", player, target, get_spell_name(splno)); } } return(0); } //********************************************************************* // cmdStudy //********************************************************************* // This function allows a player to study a scroll, and learn the spell // that is on it. int cmdStudy(Player* player, cmd* cmnd) { Object *object=0; bstring skill = ""; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 2) { player->print("Study what?\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } object = findObject(player, player->first_obj, cmnd); if(!object) { player->print("You don't have that.\n"); return(0); } if(object->getType() != SCROLL && object->getType() != SONGSCROLL && !object->getRecipe()) { player->print("That's not a scroll.\n"); return(0); } if(object->doRestrict(player, true)) return(0); player->unhide(); if(!object->getRecipe() && (object->getMagicpower() - 1 < 0 || object->getMagicpower() - 1 > MAXSPELL)) { player->print("Error: Bad Scroll.\n"); broadcast(isCt, "^y%s has a bad scroll!\n", player->name); loge("Study: %s has a bad scroll.\n", player->name); return(0); } if(object->getRecipe()) { Recipe* recipe = gConfig->getRecipe(object->getRecipe()); if(!recipe) { player->print("Error: Bad Recipe.\n"); broadcast(isCt, "^y%s has a bad recipe!^x\n", player->name); loge("Study: %s has a bad recipe.\n", player->name); return(0); } player->checkFreeSkills(recipe->getSkill()); if(recipe->getSkill() != "" && !player->knowsSkill(recipe->getSkill())) { player->print("Sorry, you don't have enough training in %s to learn that recipe.\n", recipe->getSkill().c_str()); return(0); } player->printColor("You learn the art of making %s.\n", recipe->getResultName().c_str()); player->learnRecipe(recipe); } else if(object->getType() == SCROLL) { skill = spellSkill(get_spell_school(object->getMagicpower() - 1)); if(skill != "" && !player->knowsSkill(skill)) { player->print("You are unable to learn %s spells.\n", gConfig->getSkillDisplayName(skill).c_str()); return(0); } player->print("You learn the %s spell.\n", get_spell_name(object->getMagicpower() - 1)); player->learnSpell(object->getMagicpower() - 1); } else if(object->getType() == SONGSCROLL) { player->print("You learn the song of %s.\n", get_song_name(object->getMagicpower() - 1)); player->learnSong(object->getMagicpower() - 1); } player->printColor("%O disintegrates!\n", object); broadcast(player->getSock(), player->getRoom(), "%M studies %1P.", player, object); player->delObj(object, true); delete object; return(0); } //********************************************************************* // cmdReadScroll //********************************************************************* // This function allows a player to read a scroll and cause its magical // spell to be cast. If a third word is used in the command, then that // player or monster will be the target of the spell. int cmdReadScroll(Player* player, cmd* cmnd) { Object *object=0; int (*fn)(SpellFn); long i=0, t=0; int n=0, match=0, c=0; ctag *cp=0; bool dimensionalFailure=false; SpellData data; fn = 0; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 2) { player->print("Read what?\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } object = findObject(player, player->first_obj, cmnd); if(!object || !cmnd->val[1]) { for(n = 0; n < MAXWEAR; n++) { if(!player->ready[n]) continue; if(keyTxtEqual(player->ready[n], cmnd->str[1])) match++; else continue; if(match == cmnd->val[1] || !cmnd->val[1]) { object = player->ready[n]; break; } } } if(!object) { player->print("You don't have that.\n"); return(0); } if(object->getSpecial()) { n = special_obj(player, cmnd, SP_MAPSC); if(n != -2) return(MAX(0, n)); } if(object->getType() != SCROLL) { player->print("That's not a scroll.\n"); return(0); } if(object->doRestrict(player, true)) return(0); if( (player->getRoom()->flagIsSet(R_NO_MAGIC)) || (object->getMagicpower() - 1 < 0) ) { player->print("Nothing happens.\n"); return(0); } i = MAX(LT(player, LT_READ_SCROLL), player->lasttime[LT_SPELL].ltime + 2); t = time(0); if(i > t) { player->pleaseWait(i - t); return(0); } cp = player->getRoom()->first_mon; while(cp) { if(cp->crt->flagIsSet(M_ANTI_MAGIC_AURA)) { broadcast(NULL, player->getRoom(), "^B%M glows bright blue.", cp->crt); player->print("Nothing happens.\n"); return(0); } cp = cp->next_tag; } player->unhide(); player->lasttime[LT_READ_SCROLL].ltime = t; player->lasttime[LT_READ_SCROLL].interval = 3; if(LT(player, LT_PLAYER_BITE) <= t) { player->lasttime[LT_PLAYER_BITE].ltime = t; player->lasttime[LT_PLAYER_BITE].interval = 3L; } if(object->getMagicpower() - 1 < 0 || object->getMagicpower() - 1 > MAXSPELL) { player->print("Error: Bad Scroll.\n"); broadcast(isCt, "^y%s has a bad scroll!\n", player->name); loge("Readscroll: %s has a bad scroll.\n", player->name); return(0); } if(spell_fail(player, SCROLL)) { player->printColor("%O disintegrates.\n", object); player->delObj(object, true); delete object; return(0); } data.splno = object->getMagicpower() - 1; fn = get_spell_function(data.splno); data.set(SCROLL, get_spell_school(data.splno), object, player); if(!data.check(player)) return(0); // check for dimensional anchor if(hinderedByDimensionalAnchor(data.splno) && player->checkDimensionalAnchor()) dimensionalFailure = true; // if the spell failed due to dimensional anchor, don't even run this if(!dimensionalFailure) { if((int(*)(SpellFn, char*, osp_t*))fn == splOffensive || (int(*)(SpellFn, char*, osp_t*))fn == splMultiOffensive) { for(c = 0; ospell[c].splno != get_spell_num(data.splno); c++) if(ospell[c].splno == -1) return(0); n = ((int(*)(SpellFn, const char*, osp_t*))*fn) (player, cmnd, &data, get_spell_name(data.splno), &ospell[c]); } else { n = ((int(*)(SpellFn))*fn) (player, cmnd, &data); } } if(n || dimensionalFailure) { if(object->use_output[0] && !dimensionalFailure) player->printColor("%s\n", object->use_output); player->printColor("%O disintegrates.\n", object); player->delObj(object, true); delete object; } return(0); } //********************************************************************* // consume //********************************************************************* // This function allows players to drink potions / eat food, thereby casting any // spell it was meant to contain. // return 0 on failure, 1 on drink, 2 on deleted object // lagprot means we can bypass int endConsume(Object* object, Player* player, bool forceDelete=false) { if(object->flagIsSet(O_EATABLE)) { player->print("Food eaten.\n"); broadcast(player->getSock(), player->getRoom(), "%M eats %1P.", player, object); } else { player->print("Potion drank.\n"); broadcast(player->getSock(), player->getRoom(), "%M drinks %1P.", player, object); } if(!forceDelete) object->decShotscur(); if(forceDelete || object->getShotscur() < 1) { if(object->flagIsSet(O_EATABLE)) player->printColor("You ate all of %P.\n", object); else player->printColor("You drank all of %P.\n", object); player->delObj(object, true); delete object; return(2); } return(1); } int consume(Player* player, Object* object, cmd* cmnd) { int c=0, splno=0, n=0; int (*fn)(SpellFn); bool dimensionalFailure=false; bool eat = object->flagIsSet(O_EATABLE), drink=object->flagIsSet(O_DRINKABLE) || object->getType() == POTION; const bstring& effect = object->getEffect(); fn = 0; if(player->isStaff() && object->getType() != POTION && !strcmp(cmnd->str[0], "eat")) { broadcast(player->getSock(), player->getRoom(), "%M eats %1P.", player, object); player->printColor("You ate %P.\n", object); player->delObj(object); delete object; return(0); } if(!strcmp(cmnd->str[0], "eat")) { if(!eat && !player->checkStaff("You may not eat that.\n")) return(0); } else { if(!drink && !player->checkStaff("You may not drink that.\n")) return(0); } if(object->doRestrict(player, true)) return(0); // Handle Alchemy Potions if(object->isAlchemyPotion()) { if(object->consumeAlchemyPotion(player)) return(endConsume(object,player)); else return(0); } // they are eating a non-potion object if( object->getShotscur() < 1 || (object->getMagicpower() - 1 < 0) || object->getType() != POTION ) { player->unhide(); if(object->use_output[0]) player->printColor("%s\n", object->use_output); // some food can heal you if(object->flagIsSet(O_CONSUME_HEAL) && !player->isUndead()) player->hp.increase(object->damage.roll()); return(endConsume(object, player, true)); } if(player->getRoom()->flagIsSet(R_NO_POTION)) { if(!player->checkStaff("%O starts to %s before you %s it.\n", object, eat ? "get moldy" : "evaporate", eat ? "eat" : "drink")) return(0); } player->unhide(); if(object->getMagicpower() - 1 < 0 || object->getMagicpower() - 1 > MAXSPELL) { player->print("Error: Bad Potion.\n"); broadcast(isCt, "^y%s has a bad potion!\n", player->name); loge("Quaff: %s has a bad potion.\n", player->name); return(0); } splno = object->getMagicpower() - 1; fn = get_spell_function(splno); // check for dimensional anchor if(hinderedByDimensionalAnchor(splno) && player->checkDimensionalAnchor()) dimensionalFailure = true; // if the spell failed due to dimensional anchor, don't even run this if(!dimensionalFailure) { SpellData data; data.splno = splno; data.set(POTION, get_spell_school(data.splno), object, player); if( (int(*)(SpellFn, char*, osp_t*))fn == splOffensive || (int(*)(SpellFn, char*, osp_t*))fn == splMultiOffensive ) { for(c = 0; ospell[c].splno != get_spell_num(data.splno); c++) if(ospell[c].splno == -1) return(0); n = ((int(*)(SpellFn, const char*, osp_t*))*fn) (player, cmnd, &data, get_spell_name(data.splno), &ospell[c]); } else { n = ((int(*)(SpellFn))*fn) (player, cmnd, &data); } } if(n || dimensionalFailure) { player->statistics.potion(); if(object->use_output[0] && !dimensionalFailure) player->printColor("%s\n", object->use_output); return(endConsume(object, player)); } return(0); } // drink wrapper int cmdConsume(Player* player, cmd* cmnd) { Object *object=0; int n=0, match=0; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 2) { if(strcmp(cmnd->str[0], "eat")) { player->print("Drink what?\n"); } else { player->print("Eat what?\n"); } return(0); } object = findObject(player, player->first_obj, cmnd); if(!object || !cmnd->val[1]) { for(n = 0; n < MAXWEAR; n++) { if(!player->ready[n]) continue; if(keyTxtEqual(player->ready[n], cmnd->str[1])) match++; else continue; if(match == cmnd->val[1] || !cmnd->val[1]) { object = player->ready[n]; break; } } } if(!object) { player->print("You don't have that.\n"); return(0); } consume(player, object, cmnd); return(0); } //********************************************************************* // cmdUseWand //********************************************************************* // This function allows players to zap a wand or staff at another player // or monster. int cmdUseWand(Player* player, cmd* cmnd) { Object *object=0; long i=0, t=0; int (*fn)(SpellFn); bool dimensionalFailure=false; int match=0, n=0, c=0; ctag *cp=0; SpellData data; if(!player->ableToDoCommand()) return(0); if(cmnd->num < 2) { player->print("Use what?\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } object = findObject(player, player->first_obj, cmnd); if(!object || !cmnd->val[1]) { for(n = 0; n < MAXWEAR; n++) { if(!player->ready[n]) continue; if(keyTxtEqual(player->ready[n], cmnd->str[1])) match++; else continue; if(match == cmnd->val[1] || !cmnd->val[1]) { object = player->ready[n]; break; } } } if(!object) { object = findObject(player, player->getRoom()->first_obj, cmnd); if(object && !object->flagIsSet(O_CAN_USE_FROM_FLOOR)) { player->print("You don't have that.\n"); return(0); } } if(!object) { player->print("You don't have that.\n"); return(0); } if(object->getType() != WAND) { player->print("That's not a wand or staff.\n"); return(0); } if(object->doRestrict(player, true)) return(0); if(object->getShotscur() < 1) { player->print("It's used up.\n"); return(0); } if( (player->getRoom()->flagIsSet(R_NO_MAGIC)) || (object->getMagicpower() < 1) ) { player->print("Nothing happens.\n"); return(0); } i = MAX(LT(player, LT_SPELL), player->lasttime[LT_READ_SCROLL].interval + 2); t = time(0); if(!player->isCt() && i > t) { player->pleaseWait(i - t); return(0); } player->unhide(); cp = player->getRoom()->first_mon; while(cp) { if(cp->crt->flagIsSet(M_ANTI_MAGIC_AURA)) { broadcast(NULL, player->getRoom(), "^B%M glows bright blue.", cp->crt); player->printColor("%O sputters and smokes.\n", object); return(0); } cp = cp->next_tag; } data.splno = object->getMagicpower() - 1; if(data.splno < 0 || data.splno > MAXSPELL) { player->print("Error: Bad Wand.\n"); broadcast(isCt, "^y%s has a bad wand!\n", player->name); loge("Study: %s has a bad wand.\n", player->name); return(0); } data.set(WAND, get_spell_school(data.splno), object, player); if(!data.check(player, true)) return(0); player->lasttime[LT_SPELL].ltime = t; player->lasttime[LT_SPELL].interval = 3; player->statistics.wand(); if(spell_fail(player, WAND)) { if(!object->flagIsSet(O_CAN_USE_FROM_FLOOR)) object->decShotscur(); if(object->getShotscur() < 1 && Unique::isUnique(object)) { player->delObj(object, true); delete object; } return(0); } fn = get_spell_function(data.splno); n = 0; // check for dimensional anchor if(hinderedByDimensionalAnchor(data.splno) && player->checkDimensionalAnchor()) dimensionalFailure = true; // if the spell failed due to dimensional anchor, don't even run this if(!dimensionalFailure) { if( (int(*)(SpellFn, char*, osp_t*))fn == splOffensive || (int(*)(SpellFn, char*, osp_t*))fn == splMultiOffensive ) { for(c = 0; ospell[c].splno != get_spell_num(data.splno); c++) if(ospell[c].splno == -1) return(0); n = ((int(*)(SpellFn, const char*, osp_t*))*fn) (player, cmnd, &data, get_spell_name(data.splno), &ospell[c]); } else { // if(!object->flagIsSet(ODDICE)) // Flag isn't used best i can tell n = ((int(*)(SpellFn))*fn) (player, cmnd, &data); } // else // n = (*fn) (player, cmnd, WAND, object); } if(n || dimensionalFailure) { if(object->use_output[0] && !dimensionalFailure) player->printColor("%s\n", object->use_output); if(!object->flagIsSet(O_CAN_USE_FROM_FLOOR)) object->decShotscur(); if(object->getShotscur() < 1 && Unique::isUnique(object)) { player->delObj(object, true); delete object; } } return(0); } //********************************************************************* // cmdRecall //********************************************************************* // wrapper for the useRecallPotion function int cmdRecall(Player* player, cmd* cmnd) { useRecallPotion(player, 1, 0); return(0); } //********************************************************************* // recallLog //********************************************************************* // does the logging for a lag-protect hazy void recallLog(Player* player, bstring name, bstring cname, bstring room) { std::ostringstream log; log << "### " << player->name << "(L" << player->getLevel() << ") hazied (" << name << ") "; if(cname != "") log << "(out of bag: " << cname << ") "; log << "due to lag protection. HP: " << player->hp.getCur() << "/" << player->hp.getMax() << ". Room: " << room << " to " << player->getRoom()->fullName() << "."; broadcast(isWatcher, "^C%s", log.str().c_str()); logn("log.lprotect", "%s", log.str().c_str()); } //********************************************************************* // recallCheckBag //********************************************************************* // This handles searching through a bag for hazy, since using a hazy // inside a bag means we need to reduce its shots. Plus, del_obj_crt // used from consume doesnt handle deleting it properly int recallCheckBag(Player* player, Object *cont, cmd* cmnd, int show, int log) { Object *object=NULL; otag *cop=0, *prev=0; int drank=0, first=1; bstring room = player->getRoom()->fullName(), name = ""; prev = cont->first_obj; cop = cont->first_obj; while(cop) { object = cop->obj; cop = cop->next_tag; name = object->name; if(object->getMagicpower() == (S_WORD_OF_RECALL+1) && object->getType() == POTION) { if(show) player->printColor("Recall potion found in %s: %s. Initiating auto-recall.\n", cont->name, name.c_str()); drank = consume(player, object, cmnd); if(drank) { if(log) recallLog(player, name, cont->name, room); return(1); } if(show) player->print("Unable to use potion. Continuing search.\n"); } // don't move prev if we're at the first object if(!first) prev = prev->next_tag; first=0; } return(0); } //********************************************************************* // useRecallPotion //********************************************************************* // used for recall command and lagprotect int useRecallPotion(Player* player, int show, int log) { cmd *cmnd; Object *object=NULL; otag *op=0; int i=0; bstring room = player->getRoom()->fullName(), name = ""; if(player->flagIsSet(P_ANCHOR)) { player->print("%s will not work while you are protected by a dimensional anchor.\n", log ? "Automatic recall" : "The recall command"); return(0); } // the functions we call want a command... // so we'll give them a fake one cmnd = new cmd; cmnd->num = 2; player->print("Beginning recall sequence.\n"); // do they have anything on their person? for(i=0; i<MAXWEAR; i++) { object = player->ready[i]; if(object) { name = object->name; if(object->getMagicpower() == (S_WORD_OF_RECALL+1) && object->getType() == POTION) { if(show) player->printColor("Recall potion found: %s. Initiating auto-recall.\n", name.c_str()); if(consume(player, object, cmnd)) { if(log) recallLog(player, name, "", room); return(1); } if(show) player->print("Unable to use potion. Continuing search.\n"); } if(object->getType() == CONTAINER) if(recallCheckBag(player, object, cmnd, show, log)) return(1); } } // check through their inventory op = player->first_obj; while(op) { object = op->obj; op = op->next_tag; name = object->name; // is this object it? if(object->getMagicpower() == (S_WORD_OF_RECALL+1) && object->getType() == POTION) { if(show) player->printColor("Recall potion found: %s. Initiating auto-recall.\n", name.c_str()); if(consume(player, object, cmnd)) { if(log) recallLog(player, name, "", room); return(1); } if(show) player->print("Unable to use potion. Continuing search.\n"); } // in a container? if(object->getType() == CONTAINER) { if(recallCheckBag(player, object, cmnd, show, log)) return(1); } } player->print("No recall potions found!\n"); return(0); } //********************************************************************* // logCast //********************************************************************* void logCast(Creature* caster, Creature* target, bstring spell, bool dmToo) { Player* pCaster = caster->getPlayer(); if(!pCaster || !pCaster->isStaff() || (!dmToo && pCaster->isDm())) return; log_immort(true, pCaster, "%s cast an %s spell on %s in room %s.\n", caster->name, spell.c_str(), target ? target->name : "self", caster->getRoom()->fullName().c_str()); } //********************************************************************* // splGeneric //********************************************************************* int splGeneric(Creature* player, cmd* cmnd, SpellData* spellData, const char* article, const char* spell, bstring effect, int strength, long duration) { Creature* target=0; if(cmnd->num == 2) { target = player; if(spellData->how == CAST) { player->print("You cast %s %s spell.\n", article, spell); broadcast(player->getSock(), player->getRoom(), "%M casts %s %s spell.", player, article, spell); } } else { if(noPotion(player, spellData)) return(0); cmnd->str[2][0] = up(cmnd->str[2][0]); target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false); if(!target) { player->print("You don't see that player here.\n"); return(0); } if(checkRefusingMagic(player, target)) return(0); if((effect == "drain-shield" || effect == "undead-ward") && target->isUndead()) { player->print("The spell fizzles.\n%M naturally resisted your spell.\n", target); return(0); } broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts %s %s spell on %N.", player, article, spell, target); target->print("%M casts %s on you.\n", player, spell); player->print("You cast %s %s spell on %N.\n", article, spell, target); } if(target->inCombat(false)) player->smashInvis(); if( target->hasPermEffect(effect) || (effect == "heat-protection" && target->hasPermEffect("alwayswarm")) || (effect == "warmth" && target->hasPermEffect("alwayscold")) ) { player->print("The spell didn't take hold.\n"); return(0); } // these spells will counteract porphyria if((effect == "drain-shield" || effect == "undead-ward") && target->isEffected("porphyria")) target->removeEffect("porphyria"); if(spellData->how == CAST) { if(player->getRoom()->magicBonus()) player->print("The room's magical properties increase the power of your spell.\n"); if(!target->addEffect(effect, player, FROM_CREATURE, true, player)) return(0); } else { target->addEffect(effect); } if(strength || duration) { EffectInfo* eff = target->getEffect(effect); if(strength) eff->setStrength(strength); if(duration) eff->setDuration(duration); } return(1); } //********************************************************************* // cmdTransmute //********************************************************************* // This allows a mage to recharge a wand provided they know the // spell of the wand and have enough gold. int cmdTransmute(Player* player, cmd* cmnd) { Object *object=0; unsigned long cost=0; if(!player->ableToDoCommand()) return(0); if(!player->isCt()) { if(!player->knowsSkill("transmute")) { player->print("You haven't a clue as to how to transmute anything!\n"); return(0); } if(player->isBlind()) { player->printColor("^CYou're blind!\n"); return(0); } if(player->ready[WIELD-1]) { player->print("Your hands are too full to do that.\n"); return(0); } } if(!player->ready[HELD-1] || player->ready[HELD-1]->getType() != WAND) { player->print("You must hold the wand you wish to recharge.\n"); return(0); } object = player->ready[HELD-1]; if(object->getShotscur()) { player->printColor("That %P still has magic in it.\n", object); return(0); } if(!player->spellIsKnown(object->getMagicpower() - 1)) { player->print("You don't know the spell of this wand.\n"); return(0); } if(object->getMagicpower() == (S_TELEPORT+1) || object->getMagicpower() == (S_WORD_OF_RECALL+1)) { player->print("Your transmutation fails.\n"); return(0); } // TODO: SKILLS: throw in a skill level check cost = (unsigned)(1000 * object->getShotsmax()); if(object->flagIsSet(O_NO_FIX)) cost *= 2; if(player->coins[GOLD] < cost || cost < 1) { player->print("You don't have enough gold.\n"); return(0); } player->coins.sub(cost, GOLD); if(!player->isCt() && !dec_daily(&player->daily[DL_RCHRG])) { player->print("You have recharged enough wands for one day.\n"); return(0); } if(spell_fail(player, CAST)) { int dmg = 0; player->print("The wand glows bright red and explodes!\n"); broadcast(player->getSock(), player->getRoom(), "A wand explodes in %s's hand!\n", player->name); if(player->chkSave(SPL, player, -1)) { dmg = mrand(5, 10); player->print("You managed to avoid most of the explosion.\n"); } else dmg = mrand(10, 20); player->doDamage(player, dmg, CHECK_DIE); player->checkImprove("transmute", false); player->unequip(HELD, UNEQUIP_DELETE); return(0); } // success! object->setShotscur(object->getShotsmax()); player->printColor("You successfully recharge the %s.\n", object->name); player->checkImprove("transmute", true); return(0); } //********************************************************************* // teleport_trap //********************************************************************* // This functions allows a player to be teleported via a trap. void teleport_trap(Player* player) { BaseRoom *newRoom=0; if(player->isStaff()) return; newRoom = player->teleportWhere(); player->deleteFromRoom(); player->addToRoom(newRoom); player->doPetFollow(); player->print("Your body is violently pulled in all directions.\n"); // player->hp.getCur() -= player->hp.getMax()/2; player->doDamage(player, player->hp.getMax()/2, NO_CHECK); player->hp.setCur(MAX(5, player->hp.getCur())); // This is all done so a teleport trap // will not be abused for exploring. player->smashInvis(); player->lasttime[LT_SPELL].ltime = time(0); player->lasttime[LT_SPELL].interval = 120L; player->stun(mrand(20,95)); } //********************************************************************* // rock_slide //********************************************************************* void rock_slide(Player* player) { Player *target=0; int dmg=0; ctag *cp=0; cp = player->getRoom()->first_ply; while(cp) { target = cp->crt->getPlayer(); cp = cp->next_tag; if(!target) continue; dmg = mrand(10, 20); if(target->getClass() == LICH) dmg *= 2; if(target->chkSave(LCK, target, 0)) dmg /=2; target->printColor("Falling rocks crush you for %s%d^x damage.\n", target->customColorize("*CC:DAMAGE*"), dmg); target->doDamage(target, dmg, NO_CHECK); if(target->hp.getCur() < 1) { target->print("You are crushed to death by falling rocks.\n"); target->die(ROCKS); } } } //********************************************************************* // splBlind //********************************************************************* // The blind spell prevents a player or monster from seeing. The spell // results in a penalty on attacks, and an inability look at objects // players, rooms, or inventory. Also a player or monster cannot read. int splBlind(Creature* player, cmd* cmnd, SpellData* spellData) { Creature* target=0; if(player->getClass() == BUILDER) { player->print("You cannot cast this spell.\n"); return(0); } // blind self if(cmnd->num == 2) { target = player; if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) { player->print("You are blind and can no longer see.\n"); broadcast(player->getSock(), player->getRoom(), "%M casts blindness on %sself.", player, player->himHer()); } else if(spellData->how == POTION) player->print("Everything goes dark.\n"); // blind a monster or player } else { if(noPotion(player, spellData)) return(0); target = player->getRoom()->findCreature(player, cmnd->str[2], cmnd->val[2], false); if(!target || target == player) { player->print("That's not here.\n"); return(0); } if(!player->canAttack(target)) return(0); player->smashInvis(); target->wake("Terrible nightmares disturb your sleep!"); if(target->chkSave(SPL, player, 0) && !player->isCt()) { target->print("%M tried to cast a blind spell on you!\n", player); broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M tried to cast a blind spell on %N!", player, target); player->print("Your spell fizzles.\n"); return(0); } if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) { player->print("Blindness spell cast on %s.\n", target->name); broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M casts a blindness spell on %N.", player, target); target->print("%M casts a blindness spell on you.\n", player); } if(target->isMonster()) { target->getMonster()->addEnmCrt(player); } } if(target->isPlayer()) { if(player->isCt()) target->setFlag(P_DM_BLINDED); } if(spellData->how == CAST && player->isPlayer()) player->getPlayer()->statistics.offensiveCast(); if(!player->isCt()) target->addEffect("blindness", 180 - (target->constitution.getCur()/10), 1, true, player); else target->addEffect("blindness", 600, 1); return(1); } //********************************************************************* // spell_fail //********************************************************************* // This function returns 1 if the casting of a spell fails, and 0 if it is // sucessful. int spell_fail(Creature* player, int how) { Player *pPlayer = player->getPlayer(); int chance=0, n=0; if(how == POTION) return(0); if(!pPlayer) return(0); n = mrand(1, 100); if(pPlayer) pPlayer->computeLuck(); switch (pPlayer->getClass()) { case ASSASSIN: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 30; break; case BERSERKER: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5); break; case VAMPIRE: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 60; break; case CLERIC: case DRUID: case BARD: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 65; break; case FIGHTER: if(pPlayer->getSecondClass() == MAGE) chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 75; else chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 10; break; case MAGE: case LICH: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 75; break; case MONK: case WEREWOLF: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 6) + 25; break; case PALADIN: case DEATHKNIGHT: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 50; break; case RANGER: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 4) + 56; break; case THIEF: if(pPlayer->getSecondClass() == MAGE) chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 5) + 75; else chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 6) + 22; break; case ROGUE: chance = ((pPlayer->getLevel() + bonus((int) pPlayer->intelligence.getCur())) * 6) + 22; break; default: return(0); } chance = chance * (pPlayer->getLuck() / 30); if(n > chance) { player->printColor("^yYour spell fails.\n"); return(1); } else return(0); } //********************************************************************* // splJudgement //********************************************************************* // This function allows a DM to teleport themself or another player to jail int splJudgement(Creature* player, cmd* cmnd, SpellData* spellData) { Player *target=0; Room *new_rom=0; if(!player->isPlayer() || (!player->isCt() && spellData->how == CAST)) { player->print("That spell does not exist.\n"); return(0); } if(!player->spellIsKnown(S_JUDGEMENT) && spellData->how == CAST) { player->print("You are unable to pass judgement at this time.\n"); return(0); } CatRef cr; cr.setArea("jail"); cr.id = 1; if(!loadRoom(cr, &new_rom)) { player->print("Spell failure.\n"); return(0); } // Cast judgement on yourself if(cmnd->num == 2) { target = player->getPlayer(); if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) { player->print("You pass judgement upon yourself.\n"); broadcast(player->getSock(), player->getRoom(), "%M casts word of Judgement on %sself.", player, player->himHer()); } else if(spellData->how == POTION) { player->print("You find yourself elsewhere.\n"); broadcast(player->getSock(), player->getRoom(), "%M drinks a potion of judgement and disapears.", player, player->himHer()); } // Cast word of judgement on another player } else { if(noPotion(player, spellData)) return(0); cmnd->str[2][0] = up(cmnd->str[2][0]); target = player->getRoom()->findPlayer(player, cmnd, 2); if(!target) { player->print("That player is not here.\n"); return(0); } if(spellData->how == CAST || spellData->how == SCROLL || spellData->how == WAND) { player->print("You pass judgemet on %N.\n", target); target->print("%M passes judgement on you.\nYou have been judged.\n", player); broadcast(player->getSock(), target->getSock(), player->getRoom(), "%M passes judgement on %N.", player, target); logCast(player, target, "judgement", true); broadcast("The skies grow dark, and a fog begins to cover the ground.\nA shrill voice proclaims, \"Judgement has been passed upon %N\".\n", target); } } target->deleteFromRoom(); target->addToRoom(new_rom); return(1); } //********************************************************************* // cmdBarkskin //********************************************************************* int cmdBarkskin(Player *player, cmd *cmnd) { long i=0, t = time(0); int adjustment=0; player->clearFlag(P_AFK); if(!player->ableToDoCommand()) return(0); if(!player->knowsSkill("barkskin")) { player->print("You don't know how to turn your skin to bark.\n"); return(0); } if(player->getRoom()->flagIsSet(R_ETHEREAL_PLANE)) { player->print("That is not possible here.\n"); return(0); } if(player->flagIsSet(P_OUTLAW)) { player->print("You are unable to do that right now.\n"); return(0); } if(player->isEffected("barkskin")) { player->print("Your skin is already made of bark.\n"); return(0); } if(player->inCombat(false)) { player->print("Not in the middle of combat.\n"); return(0); } i = player->lasttime[LT_BARKSKIN].ltime + player->lasttime[LT_BARKSKIN].interval; if(i>t && !player->isCt()) { player->pleaseWait(i-t); return(0); } // TODO: SKILLS: add skill level check player->smashInvis(); player->unhide(); broadcast(player->getSock(), player->getRoom(), "%M's skin turns to bark.", player); adjustment = mrand(3,6); player->addEffect("barkskin", 120, adjustment, true, player); player->printColor("^yYour skin turns to bark.\n"); player->checkImprove("barkskin", true); player->lasttime[LT_BARKSKIN].ltime = t; player->lasttime[LT_BARKSKIN].interval = 600; player->computeAC(); return(0); } //********************************************************************* // cmdCommune //********************************************************************* int cmdCommune(Player *player, cmd *cmnd) { long i=0, t = time(0), first_exit=0; int chance=0; Room* uRoom=0; AreaRoom* aRoom=0; xtag *xp=0; ctag *cp=0; player->clearFlag(P_AFK); if(!player->ableToDoCommand()) return(0); if(!player->knowsSkill("commune")) { player->print("You don't know how to commune with nature.\n"); return(0); } if(!player->getRoom()->isOutdoors()) { player->print("You can only commune with nature while outdoors.\n"); return(0); } i = player->lasttime[LT_PRAY].ltime; if(t - i < 60L && !player->isCt()) { player->pleaseWait(60L-t+i); return(0); } int level = (int)player->getSkillLevel(("commune")); chance = MIN(85, level * 20 + bonus((int) player->piety.getCur())); if(player->isStaff()) chance = 100; if(mrand(1, 100) <= chance) { player->print("You successfully commune with nature.\n"); player->print("You sense any living creatures in your surroundings.\n"); xp = player->getRoom()->first_ext; first_exit = 1; while(xp) { if(xp->ext->flagIsSet(X_DESCRIPTION_ONLY) || xp->ext->flagIsSet(X_SECRET) || xp->ext->isConcealed(player) || xp->ext->flagIsSet(X_DM_ONLY) || xp->ext->flagIsSet(X_CLOSED) || xp->ext->flagIsSet(X_NO_SEE)) { xp = xp->next_tag; continue; } if(!first_exit) player->print("\n"); player->print("%s:\n", xp->ext->name); first_exit = 0; if(!Move::getRoom(player, xp->ext, &uRoom, &aRoom, true)) { xp = xp->next_tag; continue; } if(uRoom) cp = uRoom->first_ply; else cp = aRoom->first_ply; while(cp) { if(cp->crt->isUndead() && !player->isCt()) { cp = cp->next_tag; continue; } if(cp->crt->flagIsSet(P_DM_INVIS) && !player->isDm()) { cp = cp->next_tag; continue; } if(cp->crt->isInvisible() && !player->isEffected("detect-invisible") && !player->isCt()) { cp = cp->next_tag; continue; } player->print(" %M\n", cp->crt); cp = cp->next_tag; } if(uRoom) cp = uRoom->first_mon; else cp = aRoom->first_mon; while(cp) { if(cp->crt->isUndead() && !player->isCt()) { cp = cp->next_tag; continue; } if(cp->crt->isPet() && !player->isCt()) { cp = cp->next_tag; continue; } if(cp->crt->isUndead() && !player->isCt()) { cp = cp->next_tag; continue; } if(cp->crt->isInvisible() && !player->isEffected("detect-invisible") && !player->isCt()) { cp = cp->next_tag; continue; } player->print(" %s\n", cp->crt->name); cp = cp->next_tag; } xp = xp->next_tag; } player->checkImprove("commune", true); player->lasttime[LT_PRAY].interval = 60L; } else { player->print("You failed to commune with nature.\n"); broadcast(player->getSock(), player->getRoom(), "%M tries to commune with nature.", player); player->checkImprove("commune", false); player->lasttime[LT_PRAY].ltime = 10L; } player->lasttime[LT_PRAY].ltime = t; return(0); } //********************************************************************* // cmdEndurance //********************************************************************* // This allows druids to speed walk like everyone used to be able to // This has been disabled in cmd.c int cmdEndurance(Player *player, cmd *cmnd) { long i, t; int chance; player->clearFlag(P_AFK); if(!player->ableToDoCommand()) return(0); if(!player->knowsSkill("endurance")) { player->print("You lack the training for endurance.\n"); return(0); } if(player->flagIsSet(P_RUNNING)) { player->print("You are already able to run long distances.\n"); return(0); } i = player->lasttime[LT_ENDURANCE].ltime; t = time(0); if(t - i < 600L) { player->pleaseWait(600L-t+i); return(0); } int level = (int)player->getSkillLevel("endurance"); chance = MIN(85, level * 5 + bonus((int) player->dexterity.getCur())*5); if(mrand(1, 100) <= chance) { player->print("You are now able to run long distances.\n"); player->checkImprove("endurance", true); broadcast(player->getSock(), player->getRoom(), "%M is now prepared to run long distances.", player); player->setFlag(P_RUNNING); player->lasttime[LT_ENDURANCE].ltime = t; player->lasttime[LT_ENDURANCE].interval = 120L + 60L * (level / 5) + bonus((int) player->constitution.getCur())*30L; } else { player->print("You failed prepare yourself for long distance running.\n"); player->checkImprove("endurance", false); broadcast(player->getSock(), player->getRoom(), "%M attempts to prepare for a run.",player); player->lasttime[LT_ENDURANCE].ltime = t - 590L; } return(0); } //********************************************************************* // isMageLich //********************************************************************* bool isMageLich(const Creature* creature) { if( creature->getClass() != MAGE && (creature->isPlayer() && creature->getConstPlayer()->getSecondClass() != MAGE) && creature->getClass() != LICH && !creature->isCt() ) { creature->print("The arcane nature of that spell eludes you.\n"); return(false); } return(true); } //********************************************************************* // noPotion //********************************************************************* bool noPotion(Creature* player, SpellData* spellData) { if(spellData->how == POTION) { player->print("You can only use a potion on yourself.\n"); return(1); } return(0); }