/* * SkillCommand.cpp * Skills that can be performed as a command * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * 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 * */ #include "mud.h" int getFindWhere(TargetType targetType) { switch(targetType) { case TARGET_MONSTER: return(FIND_MON_ROOM); case TARGET_PLAYER: return(FIND_PLY_ROOM); case TARGET_CREATURE: return(FIND_MON_ROOM | FIND_PLY_ROOM); case TARGET_OBJECT: return(FIND_OBJ_EQUIPMENT | FIND_OBJ_INVENTORY | FIND_OBJ_ROOM); case TARGET_OBJECT_CREATURE: return(FIND_OBJ_EQUIPMENT | FIND_OBJ_INVENTORY | FIND_OBJ_ROOM | FIND_MON_ROOM | FIND_PLY_ROOM); case TARGET_EXIT: return(FIND_EXIT); case TARGET_MUDOBJECT: return(FIND_MON_ROOM | FIND_PLY_ROOM | FIND_OBJ_EQUIPMENT | FIND_OBJ_INVENTORY | FIND_OBJ_ROOM | FIND_EXIT); default: break; } return(0); } int cmdSkill(Creature* creature, cmd* cmnd) { Player *player = creature->getAsPlayer(); *creature << "Attempting to use the " << cmnd->myCommand->getName() << " skill\n"; if(!creature->ableToDoCommand(cmnd)) return(0); bstring str = cmnd->myCommand->getName(); SkillCommand* skillCmd = dynamic_cast<SkillCommand*>(cmnd->myCommand); if(!skillCmd) { *creature << "Invalid skill!\n"; return(0); } Skill* skill = creature->getSkill(cmnd->myCommand->getName()); if(!skill) { *creature << "You don't know how to " << cmnd->myCommand->getName() << "\n"; return(0); } if(!skillCmd->checkResources(creature)) return(0); MudObject* target = NULL; Container* parent = creature->getParent(); TargetType targetType = skillCmd->getTargetType(); int findFlags = 0; if(skillCmd->getTargetType() != TARGET_NONE) { bstring toFind = cmnd->str[1]; int num = cmnd->val[1]; target = creature->findTarget(getFindWhere(skillCmd->getTargetType()), 0, toFind, num); // Assumption: If it's offensive, it's usable on creatures if(!target && skillCmd->isOffensive() && creature->hasAttackableTarget()) target = creature->getTarget(); if(!target) { *creature << "You can't find '" << toFind << "'.\n"; return(0); } } else { target = creature; } if(skillCmd->isOffensive()) { if(target->isCreature()) { if(!creature->canAttack(target->getAsCreature(), false)) { return(0); } } } if(skillCmd->hasCooldown()) { if(!skill->checkTimer(creature, true)) return(0); skill->updateTimer(); } if(skillCmd->getUsesAttackTimer()) { if(!creature->checkAttackTimer()) return(0); creature->updateAttackTimer(); } *creature << "You attempt to " << skillCmd->getName() << " " << target << "\n"; bool result = skillCmd->runScript(creature, target, skill); if(skillCmd->hasCooldown()) { if(result) skill->modifyDelay(skillCmd->getCooldown()); else skill->modifyDelay(skillCmd->getFailCooldown()); } // TODO: Track last skill for future combos return(0); } //********************************************************************* // checkAttackTimer //********************************************************************* // Return: true if the attack timer has expired, false if not bool Skill::checkTimer(Creature* creature, bool displayFail) { long i; if(!((i = timer.getTimeLeft()) == 0)) { if(displayFail) creature->pleaseWait(i/10.0); // if(!creature->isDm()) return(false); } return(true); } //********************************************************************* // UpdateTimer //********************************************************************* void Skill::updateTimer(bool setDelay, int delay) { if(!setDelay) { timer.update(); } else { timer.update(delay); } } //********************************************************************* // modifyDelay //********************************************************************* void Skill::modifyDelay(int amt) { timer.modifyDelay(amt); } //********************************************************************* // setAttackDelay //********************************************************************* void Skill::setDelay(int newDelay) { timer.setDelay(newDelay); } bool SkillCommand::getUsesAttackTimer() const { return(usesAttackTimer); } bool SkillCommand::hasCooldown() const { return(cooldown != 0); } int SkillCommand::getCooldown() const { return(cooldown); } int SkillCommand::getFailCooldown() const { return(failCooldown); } bool SkillCommand::runScript(Creature* actor, MudObject* target, Skill* skill) { try { object localNamespace( (handle<>(PyDict_New()))); object skillModule( (handle<>(PyImport_ImportModule("skillLib"))) ); localNamespace["skillLib"] = skillModule; localNamespace["skill"] = ptr(skill); localNamespace["skillCmd"] = ptr(this); // Default retVal is true localNamespace["retVal"] = true; addMudObjectToDictionary(localNamespace, "actor", actor); addMudObjectToDictionary(localNamespace, "target", target); gServer->runPython(pyScript, localNamespace); bool retVal = extract<bool>(localNamespace["retVal"]); //std::cout << "runScript returning: " << retVal << std::endl; return(retVal); } catch( error_already_set) { gServer->handlePythonError(); } return(false); } TargetType SkillCommand::getTargetType() const { return(targetType); } bool SkillCommand::isOffensive() const { return(offensive); } //******************************************************************************** // CheckResource //******************************************************************************** // Checks that the given resource type has sufficient resources left bool Creature::checkResource(ResourceType resType, int resCost) { bool retVal = true; switch(resType) { case RES_NONE: retVal = true; break; case RES_GOLD: retVal = coins[GOLD] >= resCost; break; case RES_MANA: retVal = mp.getCur() >= resCost; break; case RES_HIT_POINTS: retVal = hp.getCur() >= resCost; break; case RES_FOCUS: if(!getAsPlayer()) retVal = false; else retVal = getAsPlayer()->focus.getCur() >= resCost; break; case RES_ENERGY: // no energy for now retVal = false; break; default: // Unknown resource, we don't have it retVal = false; break; } return(retVal); } //******************************************************************************** // SubResource //******************************************************************************** // Removes resCost of given resource; does not check for sufficient resources, // as it assumes that has been checked elsewhere void Creature::subResource(ResourceType resType, int resCost) { switch(resType) { case RES_NONE: return; case RES_GOLD: //return(coins[GOLD] >= resCost); coins.sub(resCost, GOLD); return; case RES_MANA: mp.decrease(resCost); return; case RES_HIT_POINTS: hp.decrease(resCost); return; case RES_FOCUS: if(!getAsPlayer()) return; getAsPlayer()->focus.decrease(resCost); return; case RES_ENERGY: // no energy for now return; default: // Unknown resource, we don't have it return; } } //******************************************************************************** // GetResourceName //******************************************************************************** bstring getResourceName(ResourceType resType) { switch(resType) { case RES_NONE: default: return("(Unknown)"); case RES_GOLD: return("gold coins"); case RES_MANA: return("magic points"); case RES_HIT_POINTS: return("hit points"); case RES_FOCUS: return("focus"); case RES_ENERGY: return("energy"); } } //******************************************************************** //* Check Resources //******************************************************************** // Returns: True - Sufficient resources // False - Insufficient resources bool SkillCommand::checkResources(Creature* creature) { for(SkillCost& res : resources) { if(!creature->checkResource(res.resource, res.cost)) { bstring failMsg = bstring("You need to have at least ") + res.cost + " " + getResourceName(res.resource) + ".\n"; return(creature->checkStaff(failMsg.c_str())); } } return(true); } void SkillCommand::subResources(Creature* creature) { for(SkillCost& res : resources) { creature->subResource(res.resource, res.cost); } } int SkillCommand::execute(Creature* player, cmd* cmnd) { return((fn)(player, cmnd)); }