diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/manaserv_protocol.h | 1 | ||||
-rw-r--r-- | src/game-server/abilitycomponent.cpp | 14 | ||||
-rw-r--r-- | src/game-server/abilitycomponent.h | 14 | ||||
-rw-r--r-- | src/game-server/abilitymanager.cpp | 22 | ||||
-rw-r--r-- | src/game-server/abilitymanager.h | 7 | ||||
-rw-r--r-- | src/game-server/character.cpp | 22 | ||||
-rw-r--r-- | src/game-server/character.h | 4 | ||||
-rw-r--r-- | src/game-server/commandhandler.cpp | 2 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 55 | ||||
-rw-r--r-- | src/scripting/luautil.cpp | 12 | ||||
-rw-r--r-- | src/scripting/luautil.h | 28 |
11 files changed, 141 insertions, 40 deletions
diff --git a/src/common/manaserv_protocol.h b/src/common/manaserv_protocol.h index 05e5fd5..498e35f 100644 --- a/src/common/manaserv_protocol.h +++ b/src/common/manaserv_protocol.h @@ -149,6 +149,7 @@ enum { GPMSG_ABILITY_STATUS = 0x0293, // { B abilityID, D current, D max, D recharge } PGMSG_USE_ABILITY_ON_POINT = 0x0294, // B abilityID, W*2 position GPMSG_ABILITY_REMOVED = 0x0295, // B abilityID + GPMSG_ABILITY_COOLDOWN = 0x0296, // W ticks to wait PGMSG_SAY = 0x02A0, // S text GPMSG_SAY = 0x02A1, // W being id, S text GPMSG_NPC_CHOICE = 0x02B0, // W being id, { S text }* diff --git a/src/game-server/abilitycomponent.cpp b/src/game-server/abilitycomponent.cpp index eac5f1c..5b27be1 100644 --- a/src/game-server/abilitycomponent.cpp +++ b/src/game-server/abilitycomponent.cpp @@ -77,6 +77,9 @@ bool AbilityComponent::takeAbility(int id) bool AbilityComponent::abilityUseCheck(AbilityMap::iterator it) { + if (!mCooldown.expired()) + return false; + if (it == mAbilities.end()) { LOG_INFO("Character uses ability " << it->first @@ -123,6 +126,7 @@ void AbilityComponent::useAbilityOnBeing(Entity &user, int id, Entity *b) if (ability.abilityInfo->autoconsume) { ability.currentPoints = 0; signal_ability_changed.emit(id); + startCooldown(user, ability.abilityInfo); } //tell script engine to cast the spell @@ -151,6 +155,7 @@ void AbilityComponent::useAbilityOnPoint(Entity &user, int id, int x, int y) if (ability.abilityInfo->autoconsume) { ability.currentPoints = 0; signal_ability_changed.emit(id); + startCooldown(user, ability.abilityInfo); } //tell script engine to cast the spell @@ -201,6 +206,15 @@ bool AbilityComponent::setAbilityMana(int id, int mana) return false; } +void AbilityComponent::startCooldown( + Entity &entity, const AbilityManager::AbilityInfo *abilityInfo) +{ + unsigned cooldownAttribute = abilityInfo->cooldownAttribute; + auto *bc = entity.getComponent<BeingComponent>(); + mCooldown.set((int)bc->getModifiedAttribute(cooldownAttribute)); + signal_cooldown_activated.emit(); +} + void AbilityComponent::attributeChanged(Entity *entity, unsigned attr) { for (auto &abilityIt : mAbilities) diff --git a/src/game-server/abilitycomponent.h b/src/game-server/abilitycomponent.h index ae48e91..c44dcb7 100644 --- a/src/game-server/abilitycomponent.h +++ b/src/game-server/abilitycomponent.h @@ -23,6 +23,7 @@ #include "game-server/abilitymanager.h" #include "game-server/component.h" +#include "game-server/timeout.h" #include <sigc++/signal.h> @@ -65,13 +66,19 @@ public: bool setAbilityMana(int id, int mana); + void startCooldown(Entity &entity, + const AbilityManager::AbilityInfo *abilityInfo); + int remainingCooldown() const; + sigc::signal<void, int> signal_ability_changed; sigc::signal<void, int> signal_ability_took; - + sigc::signal<void> signal_cooldown_activated; private: bool abilityUseCheck(AbilityMap::iterator it); void attributeChanged(Entity *entity, unsigned attr); + Timeout mCooldown; + AbilityMap mAbilities; }; @@ -105,4 +112,9 @@ inline const AbilityMap &AbilityComponent::getAbilities() const return mAbilities; } +inline int AbilityComponent::remainingCooldown() const +{ + return mCooldown.remaining(); +} + #endif /* ABILITYCOMPONENT_H_ */ diff --git a/src/game-server/abilitymanager.cpp b/src/game-server/abilitymanager.cpp index eb828e8..0657c2c 100644 --- a/src/game-server/abilitymanager.cpp +++ b/src/game-server/abilitymanager.cpp @@ -100,6 +100,8 @@ void AbilityManager::readAbilityNode(xmlNodePtr abilityNode, int neededMana = XML::getProperty(abilityNode, "needed", 0); int rechargeAttribute = XML::getProperty(abilityNode, "rechargeattribute", 0); + int cooldownAttribute = XML::getProperty(abilityNode, + "cooldownattribute", 0); bool autoconsume = XML::getBoolProperty(abilityNode, "autoconsume", true); if (rechargeable && neededMana <= 0) @@ -118,6 +120,7 @@ void AbilityManager::readAbilityNode(xmlNodePtr abilityNode, newInfo->rechargeable = rechargeable; newInfo->neededPoints = neededMana; newInfo->rechargeAttribute = rechargeAttribute; + newInfo->cooldownAttribute = cooldownAttribute; newInfo->autoconsume = autoconsume; newInfo->target = getTargetByString(XML::getProperty(abilityNode, "target", @@ -177,8 +180,25 @@ const std::string AbilityManager::getCategoryName(int id) const return it != mAbilitiesInfo.end() ? it->second->categoryName : ""; } -AbilityManager::AbilityInfo *AbilityManager::getAbilityInfo(int id) +AbilityManager::AbilityInfo *AbilityManager::getAbilityInfo(int id) const { AbilitiesInfo::const_iterator it = mAbilitiesInfo.find(id); return it != mAbilitiesInfo.end() ? it->second : 0; } + +AbilityManager::AbilityInfo *AbilityManager::getAbilityInfo( + const std::string &category, + const std::string &name) const +{ + std::string key = utils::toLower(category) + "_" + utils::toLower(name); + return getAbilityInfo(key); +} + +AbilityManager::AbilityInfo *AbilityManager::getAbilityInfo( + const std::string &abilityName) const +{ + if (mNamedAbilitiesInfo.contains(abilityName)) + return mNamedAbilitiesInfo.value(abilityName); + else + return 0; +} diff --git a/src/game-server/abilitymanager.h b/src/game-server/abilitymanager.h index 2d23c48..9e315b7 100644 --- a/src/game-server/abilitymanager.h +++ b/src/game-server/abilitymanager.h @@ -44,6 +44,7 @@ public: id(0), rechargeable(false), rechargeAttribute(0), + cooldownAttribute(0), neededPoints(0), autoconsume(true), target(TARGET_BEING) @@ -54,6 +55,7 @@ public: std::string categoryName; bool rechargeable; unsigned rechargeAttribute; + unsigned cooldownAttribute; unsigned neededPoints; bool autoconsume; TargetMode target; @@ -91,7 +93,10 @@ public: const std::string getAbilityName(int id) const; const std::string getCategoryName(int id) const; - AbilityInfo *getAbilityInfo(int id); + AbilityInfo *getAbilityInfo(int id) const; + AbilityInfo *getAbilityInfo(const std::string &category, + const std::string &name) const; + AbilityInfo *getAbilityInfo(const std::string &abilityName) const; void readAbilityCategoryNode(xmlNodePtr node, const std::string &filename); diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index 0fa1e10..3d23e3a 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -82,6 +82,7 @@ CharacterComponent::CharacterComponent(Entity &entity, MessageIn &msg): mLevelProgress(0), mUpdateLevelProgress(false), mRecalculateLevel(true), + mSendAbilityCooldown(false), mParty(0), mTransaction(TRANS_NONE), mTalkNpcId(0), @@ -127,10 +128,14 @@ CharacterComponent::CharacterComponent(Entity &entity, MessageIn &msg): mKnuckleAttackInfo = new AttackInfo(0, knuckleDamage, 7, 3, 0); combatcomponent->addAttack(mKnuckleAttackInfo); + auto *abilityComponent = new AbilityComponent(entity); entity.addComponent(abilityComponent); abilityComponent->signal_ability_changed.connect( sigc::mem_fun(this, &CharacterComponent::abilityStatusChanged)); + abilityComponent->signal_cooldown_activated.connect( + sigc::mem_fun(this, + &CharacterComponent::abilityCooldownActivated)); // Get character data. mDatabaseID = msg.readInt32(); @@ -170,6 +175,9 @@ void CharacterComponent::update(Entity &entity) if (!mModifiedAbilities.empty()) sendAbilityUpdate(entity); + + if (mSendAbilityCooldown) + sendAbilityCooldownUpdate(entity); } void CharacterComponent::characterDied(Entity *being) @@ -214,6 +222,11 @@ void CharacterComponent::abilityStatusChanged(int id) mModifiedAbilities.insert(id); } +void CharacterComponent::abilityCooldownActivated() +{ + mSendAbilityCooldown = true; +} + void CharacterComponent::sendAbilityUpdate(Entity &entity) { auto *beingComponent = entity.getComponent<BeingComponent>(); @@ -240,6 +253,15 @@ void CharacterComponent::sendAbilityUpdate(Entity &entity) gameHandler->sendTo(mClient, msg); } +void CharacterComponent::sendAbilityCooldownUpdate(Entity &entity) +{ + MessageOut msg(GPMSG_ABILITY_COOLDOWN); + auto *abilityComponent = entity.getComponent<AbilityComponent>(); + msg.writeInt16(abilityComponent->remainingCooldown()); + gameHandler->sendTo(mClient, msg); + mSendAbilityCooldown = false; +} + void CharacterComponent::cancelTransaction() { TransactionType t = mTransaction; diff --git a/src/game-server/character.h b/src/game-server/character.h index a67436c..78d27ec 100644 --- a/src/game-server/character.h +++ b/src/game-server/character.h @@ -429,12 +429,15 @@ class CharacterComponent : public Component void recalculateLevel(Entity &entity); void abilityStatusChanged(int id); + void abilityCooldownActivated(); /** * Informs the client about his characters abilities charge status */ void sendAbilityUpdate(Entity &entity); + void sendAbilityCooldownUpdate(Entity &entity); + enum TransactionType { TRANS_NONE, TRANS_TRADE, TRANS_BUYSELL }; @@ -468,6 +471,7 @@ class CharacterComponent : public Component int mCorrectionPoints; /**< Unused attribute correction points */ bool mUpdateLevelProgress; /**< Flag raised when percent to next level changed */ bool mRecalculateLevel; /**< Flag raised when the character level might have increased */ + bool mSendAbilityCooldown; unsigned char mAccountLevel; /**< Account level of the user. */ int mParty; /**< Party id of the character */ TransactionType mTransaction; /**< Trade/buy/sell action the character is involved in. */ diff --git a/src/game-server/commandhandler.cpp b/src/game-server/commandhandler.cpp index 3e74835..e54b9ea 100644 --- a/src/game-server/commandhandler.cpp +++ b/src/game-server/commandhandler.cpp @@ -1710,7 +1710,7 @@ static void handleRechargeAbility(Entity *player, std::string &args) else abilityId = abilityManager->getId(ability); - AbilityManager::AbilityInfo *info = + const AbilityManager::AbilityInfo *info = abilityManager->getAbilityInfo(abilityId); if (!info) diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index fd48f9b..3fd1651 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -1293,9 +1293,10 @@ static int chr_set_quest(lua_State *s) static int entity_set_ability_mana(lua_State *s) { Entity *c = checkCharacter(s, 1); - const int ability = checkAbility(s, 2); + auto *abilityInfo = checkAbility(s, 2); const int mana = luaL_checkint(s, 3); - if (!c->getComponent<AbilityComponent>()->setAbilityMana(ability, mana)) + if (!c->getComponent<AbilityComponent>()->setAbilityMana(abilityInfo->id, + mana)) { luaL_error(s, "set_ability_mana called with ability " @@ -1318,14 +1319,35 @@ static int entity_get_ability_mana(lua_State *s) { Entity *c = checkCharacter(s, 1); auto *abilityComponent = c->getComponent<AbilityComponent>(); - const int ability = checkAbility(s, 2); - AbilityMap::iterator it = abilityComponent->findAbility(ability); + auto *abilityInfo = checkAbility(s, 2); + AbilityMap::iterator it = abilityComponent->findAbility(abilityInfo->id); luaL_argcheck(s, it != abilityComponent->getAbilities().end(), 2, "character does not have ability"); lua_pushinteger(s, it->second.currentPoints); return 1; } +/** LUA entity:cooldown_ability (being) + * entity:cooldown_ability(int abilityid) + * entity:cooldown_ability(string abilityname) + ** + * Starts the cooldown of the passed ability. No other ability will be useable + * in this time. + * + * You do not need to call this if the attribute is set to ''autoconsume''. + * + * **Note:** When passing the ''abilityname'' as parameter make sure that it is + * formatted in this way: <setname>_<abilityname> (for eg. "Magic_Healingspell"). + */ +static int entity_cooldown_ability(lua_State *s) +{ + Entity *c = checkCharacter(s, 1); + auto *abilityComponent = c->getComponent<AbilityComponent>(); + auto *abilityInfo = checkAbility(s, 2); + abilityComponent->startCooldown(*c, abilityInfo); + return 0; +} + /** LUA entity:walk (being) * entity:walk(int pixelX, int pixelY [, int walkSpeed]) ** @@ -2298,10 +2320,11 @@ static int entity_give_ability(lua_State *s) { // cost_type is ignored until we have more than one cost type Entity *c = checkCharacter(s, 1); - const int ability = checkAbility(s, 2); + auto *abilityInfo = checkAbility(s, 2); const int currentMana = luaL_optint(s, 3, 0); - c->getComponent<AbilityComponent>()->giveAbility(ability, currentMana); + c->getComponent<AbilityComponent>()->giveAbility(abilityInfo->id, + currentMana); return 0; } @@ -2864,11 +2887,8 @@ static int get_distance(lua_State *s) */ static int get_ability_info(lua_State *s) { - const int ability = checkAbility(s, 1); - AbilityManager::AbilityInfo *info = - abilityManager->getAbilityInfo(ability); - luaL_argcheck(s, info, 1, "invalid ability"); - LuaAbilityInfo::push(s, info); + auto *abilityInfo = checkAbility(s, 1); + LuaAbilityInfo::push(s, abilityInfo); return 1; } @@ -2882,7 +2902,7 @@ static int get_ability_info(lua_State *s) */ static int abilityinfo_get_name(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); push(s, info->name); return 1; } @@ -2897,7 +2917,7 @@ static int abilityinfo_get_name(lua_State *s) */ static int abilityinfo_get_needed_mana(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); lua_pushinteger(s, info->neededPoints); return 1; } @@ -2913,7 +2933,7 @@ static int abilityinfo_get_needed_mana(lua_State *s) */ static int abilityinfo_is_rechargeable(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); lua_pushboolean(s, info->rechargeable); return 1; } @@ -2929,7 +2949,7 @@ static int abilityinfo_is_rechargeable(lua_State *s) */ static int abilityinfo_on_use(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); Script *script = getScript(s); luaL_checktype(s, 2, LUA_TFUNCTION); script->assignCallback(info->useCallback); @@ -2947,7 +2967,7 @@ static int abilityinfo_on_use(lua_State *s) */ static int abilityinfo_on_recharged(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); Script *script = getScript(s); luaL_checktype(s, 2, LUA_TFUNCTION); script->assignCallback(info->rechargedCallback); @@ -2965,7 +2985,7 @@ static int abilityinfo_on_recharged(lua_State *s) */ static int abilitiyinfo_get_category(lua_State *s) { - AbilityManager::AbilityInfo *info = LuaAbilityInfo::check(s, 1); + auto *info = LuaAbilityInfo::check(s, 1); push(s, info->categoryName); return 1; } @@ -3685,6 +3705,7 @@ LuaScript::LuaScript(): { "unequip_item", entity_unequip_item }, { "set_ability_mana", entity_set_ability_mana }, { "ability_mana", entity_get_ability_mana }, + { "cooldown_ability", entity_cooldown_ability }, { "walk", entity_walk }, { "damage", entity_damage }, { "heal", entity_heal }, diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp index f21e489..f889aa6 100644 --- a/src/scripting/luautil.cpp +++ b/src/scripting/luautil.cpp @@ -223,14 +223,16 @@ int checkSkill(lua_State *s, int p) return id; } -int checkAbility(lua_State *s, int p) +AbilityManager::AbilityInfo *checkAbility(lua_State *s, int p) { + AbilityManager::AbilityInfo *abilityInfo; if (lua_isnumber(s, p)) - return luaL_checkint(s, p); + abilityInfo = abilityManager->getAbilityInfo(luaL_checkint(s, p)); + else + abilityInfo = abilityManager->getAbilityInfo(luaL_checkstring(s, p)); - int id = abilityManager->getId(luaL_checkstring(s, p)); - luaL_argcheck(s, id != 0, p, "invalid ability name"); - return id; + luaL_argcheck(s, abilityInfo != nullptr, p, "invalid ability"); + return abilityInfo; } diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h index 2f3c15c..9ea11c0 100644 --- a/src/scripting/luautil.h +++ b/src/scripting/luautil.h @@ -168,20 +168,20 @@ typedef LuaUserData<MonsterClass> LuaMonsterClass; typedef LuaUserData<StatusEffect> LuaStatusEffect; typedef LuaUserData<AbilityManager::AbilityInfo> LuaAbilityInfo; -Script * getScript(lua_State *s); - -ItemClass * getItemClass(lua_State *s, int p); -MonsterClass * getMonsterClass(lua_State *s, int p); - -Entity * checkActor(lua_State *s, int p); -Entity * checkBeing(lua_State *s, int p); -Entity * checkCharacter(lua_State *s, int p); -ItemClass * checkItemClass(lua_State *s, int p); -Entity * checkMonster(lua_State *s, int p); -MonsterClass * checkMonsterClass(lua_State *s, int p); -Entity * checkNpc(lua_State *s, int p); -int checkSkill(lua_State *s, int p); -int checkAbility(lua_State *s, int p); +Script * getScript(lua_State *s); + +ItemClass * getItemClass(lua_State *s, int p); +MonsterClass * getMonsterClass(lua_State *s, int p); + +Entity * checkActor(lua_State *s, int p); +Entity * checkBeing(lua_State *s, int p); +Entity * checkCharacter(lua_State *s, int p); +ItemClass * checkItemClass(lua_State *s, int p); +Entity * checkMonster(lua_State *s, int p); +MonsterClass * checkMonsterClass(lua_State *s, int p); +Entity * checkNpc(lua_State *s, int p); +int checkSkill(lua_State *s, int p); +AbilityManager::AbilityInfo *checkAbility(lua_State *s, int p); MapComposite * checkCurrentMap(lua_State *s, Script *script = 0); Script::Thread* checkCurrentThread(lua_State *s, Script *script = 0); |