summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--example/scripts/attributes.lua74
-rw-r--r--example/scripts/main.lua1
-rw-r--r--scripts/lua/libmana-constants.lua4
-rw-r--r--src/game-server/being.cpp84
-rw-r--r--src/game-server/being.h14
-rw-r--r--src/game-server/character.cpp89
-rw-r--r--src/game-server/character.h10
-rw-r--r--src/game-server/monster.cpp41
-rw-r--r--src/game-server/monster.h8
-rw-r--r--src/scripting/lua.cpp26
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 },