diff options
-rw-r--r-- | example/scripts/attributes.lua | 74 | ||||
-rw-r--r-- | example/scripts/main.lua | 1 | ||||
-rw-r--r-- | scripts/lua/libmana-constants.lua | 4 | ||||
-rw-r--r-- | src/game-server/being.cpp | 84 | ||||
-rw-r--r-- | src/game-server/being.h | 14 | ||||
-rw-r--r-- | src/game-server/character.cpp | 89 | ||||
-rw-r--r-- | src/game-server/character.h | 10 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 41 | ||||
-rw-r--r-- | src/game-server/monster.h | 8 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 26 |
10 files changed, 174 insertions, 177 deletions
diff --git a/example/scripts/attributes.lua b/example/scripts/attributes.lua new file mode 100644 index 0000000..7009a73 --- /dev/null +++ b/example/scripts/attributes.lua @@ -0,0 +1,74 @@ +--[[ + + This file demonstrates how attributes are getting calculated and how they can + be linked to each other. + + See http://doc.manasource.org/attributes.xml for more info. + +--]] + +local function recalculate_base_attribute(being, attribute) + local old_base = being_get_base_attribute(being, attribute) + local new_base = old_base + if attribute == ATTR_ACCURACY then + -- Provisional + new_base = being_get_modified_attribute(being, ATTR_DEX) + elseif attribute == ATTR_DEFENSE then + new_base = 0.3 * being_get_modified_attribute(being, ATTR_VIT) + elseif attribute == ATTR_DODGE then + -- Provisional + new_base = being_get_modified_attribute(being, ATTR_AGI) + elseif attribute == ATTR_MAGIC_DODGE then + -- TODO + new_base = 1 + elseif attribute == ATTR_MAGIC_DEFENSE then + -- TODO + new_base = 0 + elseif attribute == ATTR_BONUS_ASPD then + -- TODO + new_base = 0 + elseif attribute == ATTR_HP_REGEN then + local hp_per_sec = being_get_modified_attribute(being, ATTR_VIT) * 0.05 + new_base = hp_per_sec * TICKS_PER_HP_REGENERATION / 10 + elseif attribute == ATTR_HP then + local hp = being_get_modified_attribute(being, ATTR_HP) + local max_hp = being_get_modified_attribute(being, ATTR_MAX_HP) + + if hp > max_hp then + new_base = new_base - hp - max_hp + end + elseif attribute == ATTR_MAX_HP then + local vit = being_get_modified_attribute(being, ATTR_VIT) + new_base = (vit + 3) * (vit + 20) * 0.125 + elseif attribute == ATTR_MOVE_SPEED_TPS then + -- Provisional + new_base = 3.0 + being_get_modified_attribute(being, ATTR_AGI) * 0.08 + elseif attribute == ATTR_INV_CAPACITY then + -- Provisional + new_base = 2000 + being_get_modified_attribute(being, ATTR_STR) * 180 + end + + if new_base ~= old_base then + being_set_base_attribute(being, attribute, new_base) + end + +end + +local function update_derived_attributes(being, attribute) + if attribute == ATTR_STR then + recalculate_base_attribute(ATTR_INV_CAPACITY, being) + elseif attribute == ATTR_AGI then + recalculate_base_attribute(ATTR_DODGE, being) + elseif attribute == ATTR_VIT then + recalculate_base_attribute(ATTR_MAX_HP, being) + recalculate_base_attribute(ATTR_HP_REGEN, being) + recalculate_base_attribute(ATTR_DEFENSE, being) + elseif attribute == ATTR_INT then + -- unimplemented + elseif attribute == ATTR_WIL then + -- unimplemented + end +end + +on_recalculate_base_attribute(recalculate_base_attribute) +on_update_derived_attribute(update_derived_attributes) diff --git a/example/scripts/main.lua b/example/scripts/main.lua index 6d8207e..3418385 100644 --- a/example/scripts/main.lua +++ b/example/scripts/main.lua @@ -9,6 +9,7 @@ require "scripts/global_events" require "scripts/special_actions" require "scripts/crafting" +require "scripts/attributes" require "scripts/items/candy" require "scripts/monster/testmonster" diff --git a/scripts/lua/libmana-constants.lua b/scripts/lua/libmana-constants.lua index 9638588..a07df4c 100644 --- a/scripts/lua/libmana-constants.lua +++ b/scripts/lua/libmana-constants.lua @@ -55,6 +55,8 @@ ELEMENT_METAL = 6; ELEMENT_WOOD = 7; ELEMENT_ICE = 8; +TICKS_PER_HP_REGENERATION = 100 + -- Core attributes Id ATTR_STR = 1; ATTR_AGI = 2; @@ -64,7 +66,7 @@ ATTR_DEX = 5; ATTR_WIL = 6; -- Derived attributes Id -ATTR_ACCURACY = 6; +ATTR_ACCURACY = 7; ATTR_DEFENSE = 8; ATTR_DODGE = 9; diff --git a/src/game-server/being.cpp b/src/game-server/being.cpp index d7df2df..2c334b3 100644 --- a/src/game-server/being.cpp +++ b/src/game-server/being.cpp @@ -34,6 +34,11 @@ #include "game-server/statusmanager.h" #include "utils/logger.h" #include "utils/speedconv.h" +#include "scripting/scriptmanager.h" + + +Script::Ref Being::mRecalculateDerivedAttributesCallback; +Script::Ref Being::mRecalculateBaseAttributeCallback; Being::Being(EntityType type): Actor(type), @@ -574,75 +579,64 @@ void Being::setModAttribute(unsigned, double) return; } -bool Being::recalculateBaseAttribute(unsigned attr) +void Being::recalculateBaseAttribute(unsigned attr) { LOG_DEBUG("Being: Received update attribute recalculation request for " << attr << "."); if (!mAttributes.count(attr)) { LOG_DEBUG("Being::recalculateBaseAttribute: " << attr << " not found!"); - return false; + return; } - double newBase = getAttribute(attr); - switch (attr) + // Handle speed conversion inside the engine + if (attr == ATTR_MOVE_SPEED_RAW) { - case ATTR_HP_REGEN: - { - double hpPerSec = getModifiedAttribute(ATTR_VIT) * 0.05; - newBase = (hpPerSec * TICKS_PER_HP_REGENERATION / 10); - } - break; - case ATTR_HP: - double diff; - if ((diff = getModifiedAttribute(ATTR_HP) - - getModifiedAttribute(ATTR_MAX_HP)) > 0) - newBase -= diff; - break; - case ATTR_MAX_HP: - newBase = ((getModifiedAttribute(ATTR_VIT) + 3) - * (getModifiedAttribute(ATTR_VIT) + 20)) * 0.125; - break; - case ATTR_MOVE_SPEED_TPS: - newBase = 3.0 + getModifiedAttribute(ATTR_AGI) * 0.08; // Provisional. - break; - case ATTR_MOVE_SPEED_RAW: - newBase = utils::tpsToRawSpeed( - getModifiedAttribute(ATTR_MOVE_SPEED_TPS)); - break; - case ATTR_INV_CAPACITY: - // Provisional - newBase = 2000.0 + getModifiedAttribute(ATTR_STR) * 180.0; - break; - } - if (newBase != getAttribute(attr)) - { - setAttribute(attr, newBase); - return true; + double newBase = utils::tpsToRawSpeed( + getModifiedAttribute(ATTR_MOVE_SPEED_TPS)); + if (newBase != getAttribute(attr)) + setAttribute(attr, newBase); + return; } - LOG_DEBUG("Being: No changes to sync for attribute '" << attr << "'."); - return false; + + if (!mRecalculateBaseAttributeCallback.isValid()) + return; + + Script *script = ScriptManager::currentState(); + script->setMap(getMap()); + script->prepare(mRecalculateBaseAttributeCallback); + script->push(this); + script->push(attr); + script->execute(); } void Being::updateDerivedAttributes(unsigned attr) { LOG_DEBUG("Being: Updating derived attribute(s) of: " << attr); + + // Handle default actions before handing over to the script engine switch (attr) { case ATTR_MAX_HP: - updateDerivedAttributes(ATTR_HP); case ATTR_HP: raiseUpdateFlags(UPDATEFLAG_HEALTHCHANGE); break; case ATTR_MOVE_SPEED_TPS: - if (getAttribute(attr) > 0.0f) - setAttribute(ATTR_MOVE_SPEED_RAW, utils::tpsToRawSpeed( - getModifiedAttribute(ATTR_MOVE_SPEED_TPS))); - break; - default: - // Do nothing + // Does not make a lot of sense to have in the scripts. + // So handle it here: + recalculateBaseAttribute(ATTR_MOVE_SPEED_RAW); break; } + + if (!mRecalculateDerivedAttributesCallback.isValid()) + return; + + Script *script = ScriptManager::currentState(); + script->setMap(getMap()); + script->prepare(mRecalculateDerivedAttributesCallback); + script->push(this); + script->push(attr); + script->execute(); } void Being::applyStatusEffect(int id, int timer) diff --git a/src/game-server/being.h b/src/game-server/being.h index d5a7358..1d1f420 100644 --- a/src/game-server/being.h +++ b/src/game-server/being.h @@ -238,7 +238,7 @@ class Being : public Actor * attributes if it has changed. * @returns Whether it was changed. */ - virtual bool recalculateBaseAttribute(unsigned); + virtual void recalculateBaseAttribute(unsigned); /** * Attribute has changed, recalculate base value of dependant @@ -297,6 +297,12 @@ class Being : public Actor void setTarget(Being *target) { mTarget = target; } + static void setUpdateDerivedAttributesCallback(Script *script) + { script->assignCallback(mRecalculateDerivedAttributesCallback); } + + static void setRecalculateBaseAttributeCallback(Script *script) + { script->assignCallback(mRecalculateBaseAttributeCallback); } + sigc::signal<void, Being *> signal_died; /** @@ -356,6 +362,12 @@ class Being : public Actor /** The last being emote Id. Used when triggering a being emoticon. */ int mEmoteId; + + /** Called when derived attributes need to get calculated */ + static Script::Ref mRecalculateDerivedAttributesCallback; + + /** Called when a base attribute needs to get calculated */ + static Script::Ref mRecalculateBaseAttributeCallback; }; #endif // BEING_H diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp index a977799..cf5415d 100644 --- a/src/game-server/character.cpp +++ b/src/game-server/character.cpp @@ -464,65 +464,26 @@ void Character::modifiedAllAttribute() } } -bool Character::recalculateBaseAttribute(unsigned attr) +void Character::recalculateBaseAttribute(unsigned attr) { - /* - * `attr' may or may not have changed. Recalculate the base value. - */ + // `attr' may or may not have changed. Recalculate the base value. LOG_DEBUG("Received update attribute recalculation request at Character " "for " << attr << "."); if (!mAttributes.count(attr)) - return false; - double newBase = getAttribute(attr); - - /* - * Calculate new base. - */ - switch (attr) - { - case ATTR_ACCURACY: - newBase = getModifiedAttribute(ATTR_DEX); // Provisional - break; - case ATTR_DEFENSE: - newBase = 0.3 * getModifiedAttribute(ATTR_VIT); - break; - case ATTR_DODGE: - newBase = getModifiedAttribute(ATTR_AGI); // Provisional - break; - case ATTR_MAGIC_DODGE: - newBase = 1.0; - // TODO - break; - case ATTR_MAGIC_DEFENSE: - newBase = 0.0; - // TODO - break; - case ATTR_BONUS_ASPD: - newBase = 0.0; - // TODO - break; - case ATTR_STR: - if (mKnuckleAttackInfo) - { - Damage &knuckleDamage = mKnuckleAttackInfo->getDamage(); - knuckleDamage.base = getModifiedAttribute(ATTR_STR); - knuckleDamage.delta = knuckleDamage.base / 2; - } - break; - default: - return Being::recalculateBaseAttribute(attr); - } + return; - if (newBase != getAttribute(attr)) + if (attr == ATTR_STR && mKnuckleAttackInfo) { - setAttribute(attr, newBase); - updateDerivedAttributes(attr); - return true; + // TODO: dehardcode this + Damage &knuckleDamage = mKnuckleAttackInfo->getDamage(); + knuckleDamage.base = getModifiedAttribute(ATTR_STR); + knuckleDamage.delta = knuckleDamage.base / 2; } - LOG_DEBUG("No changes to sync for attribute '" << attr << "'."); - return false; + Being::recalculateBaseAttribute(attr); + } + void Character::updateDerivedAttributes(unsigned attr) { /* @@ -530,32 +491,8 @@ void Character::updateDerivedAttributes(unsigned attr) */ flagAttribute(attr); - switch(attr) - { - case ATTR_STR: - recalculateBaseAttribute(ATTR_INV_CAPACITY); - break; - case ATTR_AGI: - recalculateBaseAttribute(ATTR_DODGE); - recalculateBaseAttribute(ATTR_MOVE_SPEED_TPS); - break; - case ATTR_VIT: - recalculateBaseAttribute(ATTR_MAX_HP); - recalculateBaseAttribute(ATTR_HP_REGEN); - recalculateBaseAttribute(ATTR_DEFENSE); - break; - case ATTR_INT: - // TODO - break; - case ATTR_DEX: - recalculateBaseAttribute(ATTR_ACCURACY); - break; - case ATTR_WIL: - // TODO - break; - default: - Being::updateDerivedAttributes(attr); - } + + Being::updateDerivedAttributes(attr); } void Character::flagAttribute(int attr) diff --git a/src/game-server/character.h b/src/game-server/character.h index d225081..9c9a545 100644 --- a/src/game-server/character.h +++ b/src/game-server/character.h @@ -251,11 +251,11 @@ class Character : public Being void modifiedAllAttribute(); /** - * Recalculate the base value of an attribute and update derived - * attributes if it has changed. - * @returns Whether it was changed. - */ - bool recalculateBaseAttribute(unsigned); + * Recalculate the base value of an attribute and update derived + * attributes if it has changed. + */ + void recalculateBaseAttribute(unsigned); + /** * Attribute has changed, recalculate base value of dependant diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index 9f30840..7d5ec76 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -488,44 +488,3 @@ void Monster::died() } } } - -bool Monster::recalculateBaseAttribute(unsigned attr) -{ - LOG_DEBUG("Monster: Received update attribute recalculation request for " - << attr << "."); - if (!mAttributes.count(attr)) - { - LOG_DEBUG("Monster::recalculateBaseAttribute: " - << attr << " not found!"); - return false; - } - double newBase = getAttribute(attr); - - switch (attr) - { - // Those a set only at load time. - case ATTR_MAX_HP: - case ATTR_DODGE: - case ATTR_MAGIC_DODGE: - case ATTR_ACCURACY: - case ATTR_DEFENSE: - case ATTR_MAGIC_DEFENSE: - case ATTR_HP_REGEN: - case ATTR_MOVE_SPEED_TPS: - case ATTR_INV_CAPACITY: - // nothing to do. - break; - - // Only HP and Speed Raw updated for monsters - default: - Being::recalculateBaseAttribute(attr); - break; - } - if (newBase != getAttribute(attr)) - { - setAttribute(attr, newBase); - return true; - } - LOG_DEBUG("Monster: No changes to sync for attribute '" << attr << "'."); - return false; -} diff --git a/src/game-server/monster.h b/src/game-server/monster.h index 3313345..93c9f4e 100644 --- a/src/game-server/monster.h +++ b/src/game-server/monster.h @@ -329,14 +329,6 @@ class Monster : public Being */ void forgetTarget(Entity *entity); - /** - * Called when an attribute modifier is changed. - * Recalculate the base value of an attribute and update derived - * attributes if it has changed. - * @returns Whether it was changed. - */ - virtual bool recalculateBaseAttribute(unsigned); - protected: /** * Returns the way the actor blocks pathfinding for other objects. diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 880216d..4e2cd28 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -69,6 +69,30 @@ extern "C" { /** + * on_update_derived_attribute( function(Being*) ): void + * Sets a listener function to handle + * recalculation of derived attributes event. + */ +static int on_update_derived_attribute(lua_State *s) +{ + luaL_checktype(s, 1, LUA_TFUNCTION); + Being::setUpdateDerivedAttributesCallback(getScript(s)); + return 0; +} + + +/** + * on_recalculateBaseAttributeCallback( function(Being*) ): void + * Sets a listener function to the attribute recalculation event. + */ +static int on_recalculate_base_attribute(lua_State *s) +{ + luaL_checktype(s, 1, LUA_TFUNCTION); + Being::setRecalculateBaseAttributeCallback(getScript(s)); + return 0; +} + +/** * on_character_death( function(Character*) ): void * Sets a listener function to the character death event. */ @@ -2582,6 +2606,8 @@ LuaScript::LuaScript(): // Put the callback functions in the scripting environment. static luaL_Reg const callbacks[] = { + { "on_update_derived_attribute", &on_update_derived_attribute }, + { "on_recalculate_base_attribute", &on_recalculate_base_attribute }, { "on_character_death", &on_character_death }, { "on_character_death_accept", &on_character_death_accept }, { "on_character_login", &on_character_login }, |