summaryrefslogtreecommitdiff
path: root/src/game-server
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-03-02 23:17:07 +0100
committerThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-03-03 21:24:45 +0100
commit84c87cc99be29a694f0ffe83ab7a06ae433bb0cd (patch)
tree9180b67970e62707ee0fe2fee19cbe2e0b829122 /src/game-server
parentf872528771f0b71741fb36ddf70f2ae23f54c1e3 (diff)
downloadmanaserv-84c87cc99be29a694f0ffe83ab7a06ae433bb0cd.tar.gz
manaserv-84c87cc99be29a694f0ffe83ab7a06ae433bb0cd.tar.bz2
manaserv-84c87cc99be29a694f0ffe83ab7a06ae433bb0cd.tar.xz
manaserv-84c87cc99be29a694f0ffe83ab7a06ae433bb0cd.zip
Use callbacks for items, monsters and status effects
Previously, global function names were defined in the respective XML definitions of items, monsters and status effects. This was reasonable when they all had the same state, but now they're sharing the single global Lua state. Now the Lua API provides access to the ItemClass, MonsterClass and StatusEffect instances, on which callbacks for both standard and custom events can be explicitly set. Reviewed-by: Erik Schilling
Diffstat (limited to 'src/game-server')
-rw-r--r--src/game-server/item.cpp20
-rw-r--r--src/game-server/item.h31
-rw-r--r--src/game-server/itemmanager.cpp51
-rw-r--r--src/game-server/monster.cpp34
-rw-r--r--src/game-server/monster.h27
-rw-r--r--src/game-server/monstermanager.cpp5
-rw-r--r--src/game-server/statuseffect.cpp17
-rw-r--r--src/game-server/statuseffect.h8
-rw-r--r--src/game-server/statusmanager.cpp31
-rw-r--r--src/game-server/statusmanager.h5
10 files changed, 139 insertions, 90 deletions
diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp
index 979a1bc3..888c90ad 100644
--- a/src/game-server/item.cpp
+++ b/src/game-server/item.cpp
@@ -64,13 +64,17 @@ ItemEffectScript::~ItemEffectScript()
bool ItemEffectScript::apply(Being *itemUser)
{
- if (!mActivateFunctionName.empty())
+ if (mActivateEventName.empty())
+ return false;
+
+ Script::Ref function = mItemClass->getEventCallback(mActivateEventName);
+ if (function.isValid())
{
Script *script = ScriptManager::currentState();
script->setMap(itemUser->getMap());
- script->prepare(mActivateFunctionName);
+ script->prepare(function);
script->push(itemUser);
- script->push(mItemId);
+ script->push(mItemClass->getDatabaseID());
script->execute(); // TODO return depending on script execution success.
return true;
}
@@ -79,13 +83,17 @@ bool ItemEffectScript::apply(Being *itemUser)
void ItemEffectScript::dispell(Being *itemUser)
{
- if (!mDispellFunctionName.empty())
+ if (mDispellEventName.empty())
+ return;
+
+ Script::Ref function = mItemClass->getEventCallback(mDispellEventName);
+ if (function.isValid())
{
Script *script = ScriptManager::currentState();
script->setMap(itemUser->getMap());
- script->prepare(mDispellFunctionName);
+ script->prepare(function);
script->push(itemUser);
- script->push(mItemId);
+ script->push(mItemClass->getDatabaseID());
script->execute();
}
}
diff --git a/src/game-server/item.h b/src/game-server/item.h
index 8cd3ce64..2677589f 100644
--- a/src/game-server/item.h
+++ b/src/game-server/item.h
@@ -24,8 +24,10 @@
#include <vector>
#include "game-server/actor.h"
+#include "scripting/script.h"
class Being;
+class ItemClass;
// Indicates the equip slot "cost" to equip an item.
struct ItemEquipRequirement {
@@ -143,12 +145,12 @@ class ItemEffectConsumes : public ItemEffectInfo
class ItemEffectScript : public ItemEffectInfo
{
public:
- ItemEffectScript(int itemId,
- const std::string& activateFunctionName,
- const std::string& dispellFunctionName):
- mItemId(itemId),
- mActivateFunctionName(activateFunctionName),
- mDispellFunctionName(dispellFunctionName)
+ ItemEffectScript(ItemClass *itemClass,
+ const std::string &activateEventName,
+ const std::string &dispellEventName):
+ mItemClass(itemClass),
+ mActivateEventName(activateEventName),
+ mDispellEventName(dispellEventName)
{}
~ItemEffectScript();
@@ -157,9 +159,9 @@ class ItemEffectScript : public ItemEffectInfo
void dispell(Being *itemUser);
private:
- int mItemId;
- std::string mActivateFunctionName;
- std::string mDispellFunctionName;
+ ItemClass *mItemClass;
+ std::string mActivateEventName;
+ std::string mDispellEventName;
};
@@ -234,6 +236,12 @@ class ItemClass
const ItemEquipRequirement &getItemEquipRequirement() const
{ return mEquipReq; }
+ void setEventCallback(const std::string &event, Script *script)
+ { script->assignCallback(mEventCallbacks[event]); }
+
+ Script::Ref getEventCallback(const std::string &event) const
+ { return mEventCallbacks.value(event); }
+
private:
/**
* Add an effect to a trigger
@@ -282,6 +290,11 @@ class ItemClass
*/
ItemEquipRequirement mEquipReq;
+ /**
+ * Named event callbacks. Can be used in custom item effects.
+ */
+ utils::NameMap<Script::Ref> mEventCallbacks;
+
friend class ItemManager;
};
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index b334760a..8c74680e 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -404,50 +404,25 @@ void ItemManager::readEffectNode(xmlNodePtr effectNode, ItemClass *item)
{
item->addEffect(new ItemEffectConsumes, triggerTypes.first);
}
- else if (xmlStrEqual(subNode->name, BAD_CAST "script"))
+ else if (xmlStrEqual(subNode->name, BAD_CAST "scriptevent"))
{
- std::string activateFunctionName = XML::getProperty(subNode,
- "function",
- std::string());
- if (activateFunctionName.empty())
- {
- LOG_WARN("Item Manager: Empty function definition "
- "for script effect, skipping!");
- continue;
- }
-
- std::string src = XML::getProperty(subNode, "src", std::string());
- if (src.empty())
- {
- LOG_WARN("Item Manager: Empty src definition for script effect,"
- " skipping!");
- continue;
- }
- std::stringstream filename;
- filename << "scripts/items/" << src;
- if (!ResourceManager::exists(filename.str()))
- {
- LOG_WARN("Could not find script file \"" << filename.str()
- << "\" for item #" << item->mDatabaseID);
- continue;
- }
-
- LOG_INFO("Loading item script: " << filename.str());
- Script *script = ScriptManager::currentState();
- if (!script->loadFile(filename.str()))
+ std::string activateEventName = XML::getProperty(subNode,
+ "activate",
+ std::string());
+ if (activateEventName.empty())
{
- LOG_WARN("Could not load script file \"" << filename.str()
- << "\" for item #" << item->mDatabaseID);
+ LOG_WARN("Item Manager: Empty name for 'activate' item script "
+ "event, skipping effect!");
continue;
}
- std::string dispellFunctionName = XML::getProperty(subNode,
- "dispell-function",
- std::string());
+ std::string dispellEventName = XML::getProperty(subNode,
+ "dispell",
+ std::string());
- item->addEffect(new ItemEffectScript(item->mDatabaseID,
- activateFunctionName,
- dispellFunctionName),
+ item->addEffect(new ItemEffectScript(item,
+ activateEventName,
+ dispellEventName),
triggerTypes.first,
triggerTypes.second);
}
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index 21eeea7c..b82f4638 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -28,7 +28,6 @@
#include "game-server/item.h"
#include "game-server/mapcomposite.h"
#include "game-server/state.h"
-#include "scripting/script.h"
#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/speedconv.h"
@@ -140,16 +139,20 @@ void Monster::perform()
int hit = performAttack(mTarget, dmg);
- if (! mCurrentAttack->scriptFunction.empty()
+ if (! mCurrentAttack->scriptEvent.empty()
&& hit > -1)
{
- Script *script = ScriptManager::currentState();
- script->setMap(getMap());
- script->prepare(mCurrentAttack->scriptFunction);
- script->push(this);
- script->push(mTarget);
- script->push(hit);
- script->execute();
+ Script::Ref function = mSpecy->getEventCallback(mCurrentAttack->scriptEvent);
+ if (function.isValid())
+ {
+ Script *script = ScriptManager::currentState();
+ script->setMap(getMap());
+ script->prepare(function);
+ script->push(this);
+ script->push(mTarget);
+ script->push(hit);
+ script->execute();
+ }
}
}
}
@@ -180,11 +183,14 @@ void Monster::update()
return;
}
- Script *script = ScriptManager::currentState();
- script->setMap(getMap());
- script->prepare("update_monster");
- script->push(this);
- script->execute();
+ if (mSpecy->getUpdateCallback().isValid())
+ {
+ Script *script = ScriptManager::currentState();
+ script->setMap(getMap());
+ script->prepare(mSpecy->getUpdateCallback());
+ script->push(this);
+ script->execute();
+ }
// Cancel the rest when we are currently performing an attack
if (isTimerRunning(T_M_ATTACK_TIME))
diff --git a/src/game-server/monster.h b/src/game-server/monster.h
index 37bbe355..5ccabfa9 100644
--- a/src/game-server/monster.h
+++ b/src/game-server/monster.h
@@ -28,6 +28,8 @@
#include "game-server/being.h"
#include "game-server/eventlistener.h"
#include "common/defines.h"
+#include "scripting/script.h"
+#include "utils/string.h"
class ItemClass;
class Script;
@@ -57,7 +59,7 @@ struct MonsterAttack
int preDelay;
int aftDelay;
int range;
- std::string scriptFunction;
+ std::string scriptEvent;
};
typedef std::vector< MonsterAttack *> MonsterAttacks;
@@ -197,6 +199,18 @@ class MonsterClass
/** Returns script filename */
const std::string &getScript() const { return mScript; }
+ void setUpdateCallback(Script *script)
+ { script->assignCallback(mUpdateCallback); }
+
+ void setEventCallback(const std::string &event, Script *script)
+ { script->assignCallback(mEventCallbacks[event]); }
+
+ Script::Ref getUpdateCallback() const
+ { return mUpdateCallback; }
+
+ Script::Ref getEventCallback(const std::string &event) const
+ { return mEventCallbacks.value(event); }
+
private:
unsigned short mId;
std::string mName;
@@ -217,6 +231,17 @@ class MonsterClass
MonsterAttacks mAttacks;
std::string mScript;
+ /**
+ * A reference to the script function that is called each update.
+ */
+ Script::Ref mUpdateCallback;
+
+ /**
+ * Named event callbacks. Currently only used for custom attack
+ * callbacks.
+ */
+ utils::NameMap<Script::Ref> mEventCallbacks;
+
friend class MonsterManager;
friend class Monster;
};
diff --git a/src/game-server/monstermanager.cpp b/src/game-server/monstermanager.cpp
index bebb74a3..7612ddc1 100644
--- a/src/game-server/monstermanager.cpp
+++ b/src/game-server/monstermanager.cpp
@@ -243,9 +243,8 @@ void MonsterManager::initialize()
att->preDelay = XML::getProperty(subnode, "pre-delay", 1);
att->aftDelay = XML::getProperty(subnode, "aft-delay", 0);
att->range = XML::getProperty(subnode, "range", 0);
- att->scriptFunction = XML::getProperty(subnode,
- "script-function",
- std::string());
+ att->scriptEvent = XML::getProperty(subnode, "script-event",
+ std::string());
std::string sElement = XML::getProperty(subnode,
"element", "neutral");
att->element = elementFromString(sElement);
diff --git a/src/game-server/statuseffect.cpp b/src/game-server/statuseffect.cpp
index 32e0d621..c101bc02 100644
--- a/src/game-server/statuseffect.cpp
+++ b/src/game-server/statuseffect.cpp
@@ -20,9 +20,8 @@
#include "game-server/statuseffect.h"
-#include "scripting/script.h"
-#include "scripting/scriptmanager.h"
#include "game-server/being.h"
+#include "scripting/scriptmanager.h"
StatusEffect::StatusEffect(int id):
mId(id)
@@ -35,13 +34,13 @@ StatusEffect::~StatusEffect()
void StatusEffect::tick(Being *target, int count)
{
- if (!mTickFunction.empty())
+ if (mTickCallback.isValid())
{
- Script *script = ScriptManager::currentState();
- script->setMap(target->getMap());
- script->prepare(mTickFunction);
- script->push(target);
- script->push(count);
- script->execute();
+ Script *s = ScriptManager::currentState();
+ s->setMap(target->getMap());
+ s->prepare(mTickCallback);
+ s->push(target);
+ s->push(count);
+ s->execute();
}
}
diff --git a/src/game-server/statuseffect.h b/src/game-server/statuseffect.h
index 2b7a36f8..7da5fdf9 100644
--- a/src/game-server/statuseffect.h
+++ b/src/game-server/statuseffect.h
@@ -21,7 +21,7 @@
#ifndef STATUSEFFECT_H
#define STATUSEFFECT_H
-#include <string>
+#include "scripting/script.h"
class Being;
@@ -36,12 +36,12 @@ class StatusEffect
int getId() const
{ return mId; }
- void setTickFunction(const std::string &tickFunction)
- { mTickFunction = tickFunction; }
+ void setTickCallback(Script *script)
+ { script->assignCallback(mTickCallback); }
private:
int mId;
- std::string mTickFunction;
+ Script::Ref mTickCallback;
};
#endif
diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp
index 15203d65..7769ef0f 100644
--- a/src/game-server/statusmanager.cpp
+++ b/src/game-server/statusmanager.cpp
@@ -33,6 +33,7 @@
typedef std::map< int, StatusEffect * > StatusEffectsMap;
static StatusEffectsMap statusEffects;
+static utils::NameMap<StatusEffect*> statusEffectsByName;
static std::string statusReferenceFile;
void StatusManager::initialize(const std::string &file)
@@ -59,7 +60,7 @@ void StatusManager::reload()
if (!xmlStrEqual(node->name, BAD_CAST "status-effect"))
continue;
- int id = XML::getProperty(node, "id", 0);
+ const int id = XML::getProperty(node, "id", 0);
if (id < 1)
{
LOG_WARN("Status Manager: The status ID: " << id << " in "
@@ -68,9 +69,24 @@ void StatusManager::reload()
continue;
}
+ StatusEffect *statusEffect = new StatusEffect(id);
+
+ const std::string name = XML::getProperty(node, "name",
+ std::string());
+ if (!name.empty())
+ {
+ if (statusEffectsByName.contains(name))
+ {
+ LOG_WARN("StatusManager: name not unique for status effect "
+ << id);
+ }
+ else
+ {
+ statusEffectsByName.insert(name, statusEffect);
+ }
+ }
+
std::string scriptFile = XML::getProperty(node, "script", std::string());
- std::string tickFunction = XML::getProperty(node, "tick-function",
- std::string());
//TODO: Get these modifiers
/*
modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
@@ -84,8 +100,6 @@ void StatusManager::reload()
modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0));
modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
*/
- StatusEffect *statusEffect = new StatusEffect(id);
- statusEffect->setTickFunction(tickFunction);
if (!scriptFile.empty())
{
std::stringstream filename;
@@ -112,11 +126,16 @@ void StatusManager::deinitialize()
delete i->second;
}
statusEffects.clear();
+ statusEffectsByName.clear();
}
StatusEffect *StatusManager::getStatus(int statusId)
{
StatusEffectsMap::const_iterator i = statusEffects.find(statusId);
- return i != statusEffects.end() ? i->second : NULL;
+ return i != statusEffects.end() ? i->second : 0;
}
+StatusEffect *StatusManager::getStatusByName(const std::string &name)
+{
+ return statusEffectsByName.value(name);
+}
diff --git a/src/game-server/statusmanager.h b/src/game-server/statusmanager.h
index fc09adb5..8ab321d1 100644
--- a/src/game-server/statusmanager.h
+++ b/src/game-server/statusmanager.h
@@ -46,6 +46,11 @@ namespace StatusManager
* Gets the status having the given ID.
*/
StatusEffect *getStatus(int statusId);
+
+ /**
+ * Gets the status having the given name.
+ */
+ StatusEffect *getStatusByName(const std::string &name);
}
#endif // STATUSMANAGER_H