summaryrefslogtreecommitdiff
path: root/src/scripting
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-02-28 23:37:23 +0100
committerThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-03-02 18:12:20 +0100
commitba5b55f3eba0aa3898c5fe42de9838b22473c24a (patch)
tree465e70d3bc4671b75f1af763d866eafa459f5d6f /src/scripting
parent05bb880a3b0ebe401bac83b7a2400aa315161f9c (diff)
downloadmanaserv-ba5b55f3eba0aa3898c5fe42de9838b22473c24a.tar.gz
manaserv-ba5b55f3eba0aa3898c5fe42de9838b22473c24a.tar.bz2
manaserv-ba5b55f3eba0aa3898c5fe42de9838b22473c24a.tar.xz
manaserv-ba5b55f3eba0aa3898c5fe42de9838b22473c24a.zip
Use callbacks for handling character death and respawn
Rather than relying on the availability of global functions with certain predefined names, the Lua script now calls API functions to set which function should be called on these global events. This mechanism should make it easier to avoid name collisions in the global namespace, which is important now that there is only a single script state. For these global events this was not likely to become a problem, but this solution can also be used for callbacks on specific item or monster types, or even allow setting callbacks on certain instances. Reviewed-by: Erik Schilling Reviewed-by: Yohann Ferreira
Diffstat (limited to 'src/scripting')
-rw-r--r--src/scripting/lua.cpp26
-rw-r--r--src/scripting/luascript.cpp20
-rw-r--r--src/scripting/luascript.h4
-rw-r--r--src/scripting/script.cpp2
-rw-r--r--src/scripting/script.h33
-rw-r--r--src/scripting/scriptmanager.cpp13
-rw-r--r--src/scripting/scriptmanager.h5
7 files changed, 81 insertions, 22 deletions
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 9aec6b3f..7a94ce24 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -74,6 +74,30 @@ static Script *getScript(lua_State *s)
/**
+ * mana.on_character_death( function(Character*) ): void
+ * Sets a listener function to the character death event.
+ */
+static int on_character_death(lua_State *s)
+{
+ luaL_checktype(s, 1, LUA_TFUNCTION);
+ Character::setDeathCallback(getScript(s));
+ return 0;
+}
+
+/**
+ * mana.on_character_death_accept( function(Character*) ): void
+ * Sets a listener function that is called when the player clicks on the OK
+ * button after the death message appeared. It should be used to implement the
+ * respawn mechanic.
+ */
+static int on_character_death_accept(lua_State *s)
+{
+ luaL_checktype(s, 1, LUA_TFUNCTION);
+ Character::setDeathAcceptedCallback(getScript(s));
+ return 0;
+}
+
+/**
* mana.npc_message(NPC*, Character*, string): void
* Callback for sending a NPC_MESSAGE.
*/
@@ -2564,6 +2588,8 @@ LuaScript::LuaScript():
// Put the callback functions in the scripting environment.
static luaL_Reg const callbacks[] = {
+ { "on_character_death", &on_character_death },
+ { "on_character_death_accept", &on_character_death_accept },
{ "npc_create", &npc_create },
{ "npc_message", &npc_message },
{ "npc_choice", &npc_choice },
diff --git a/src/scripting/luascript.cpp b/src/scripting/luascript.cpp
index c487aa67..605302e6 100644
--- a/src/scripting/luascript.cpp
+++ b/src/scripting/luascript.cpp
@@ -35,6 +35,15 @@ LuaScript::~LuaScript()
lua_close(mState);
}
+void LuaScript::prepare(Ref function)
+{
+ assert(nbArgs == -1);
+ lua_rawgeti(mState, LUA_REGISTRYINDEX, function);
+ assert(lua_isfunction(mState, -1));
+ nbArgs = 0;
+ mCurFunction = "<callback>"; // We don't know the function name
+}
+
void LuaScript::prepare(const std::string &name)
{
assert(nbArgs == -1);
@@ -108,6 +117,17 @@ int LuaScript::execute()
mCurFunction.clear();
}
+void LuaScript::assignCallback(Script::Ref &function)
+{
+ assert(lua_isfunction(mState, -1));
+
+ // If there is already a callback set, replace it
+ if (function != NoRef)
+ luaL_unref(mState, LUA_REGISTRYINDEX, function);
+
+ function = luaL_ref(mState, LUA_REGISTRYINDEX);
+}
+
void LuaScript::load(const char *prog, const char *name)
{
int res = luaL_loadbuffer(mState, prog, std::strlen(prog), name);
diff --git a/src/scripting/luascript.h b/src/scripting/luascript.h
index 0d59703c..6f2bceee 100644
--- a/src/scripting/luascript.h
+++ b/src/scripting/luascript.h
@@ -44,6 +44,8 @@ class LuaScript : public Script
void load(const char *prog, const char *name);
+ void prepare(Ref function);
+
void prepare(const std::string &);
void push(int);
@@ -56,6 +58,8 @@ class LuaScript : public Script
int execute();
+ void assignCallback(Ref &function);
+
static void getQuestCallback(Character *, const std::string &,
const std::string &, void *);
diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp
index db44bd57..66720842 100644
--- a/src/scripting/script.cpp
+++ b/src/scripting/script.cpp
@@ -34,6 +34,8 @@ typedef std::map< std::string, Script::Factory > Engines;
static Engines *engines = NULL;
+Script::Ref Script::NoRef = -1;
+
Script::Script():
mMap(NULL),
mEventListener(&scriptEventDispatch)
diff --git a/src/scripting/script.h b/src/scripting/script.h
index bd143114..b475a0f0 100644
--- a/src/scripting/script.h
+++ b/src/scripting/script.h
@@ -21,11 +21,12 @@
#ifndef SCRIPTING_SCRIPT_H
#define SCRIPTING_SCRIPT_H
-#include <string>
-
-#include "game-server/character.h"
+#include "common/inventorydata.h"
#include "game-server/eventlistener.h"
+#include <list>
+#include <string>
+
class MapComposite;
class Thing;
@@ -35,7 +36,9 @@ class Thing;
class Script
{
public:
-
+ /**
+ * Defines a function that creates a Script instance.
+ */
typedef Script *(*Factory)();
/**
@@ -48,6 +51,15 @@ class Script
*/
static Script *create(const std::string &engine);
+ /**
+ * A reference to a script object. It's just an integer, but the
+ * typedef makes the purpose of the variable clear.
+ *
+ * Variables of this type should be initialized to Script::NoRef.
+ */
+ typedef int Ref;
+ static Ref NoRef;
+
Script();
virtual ~Script() {}
@@ -81,6 +93,12 @@ class Script
virtual void update();
/**
+ * Prepares a call to the referenced function.
+ * Only one function can be prepared at once.
+ */
+ virtual void prepare(Ref function) = 0;
+
+ /**
* Prepares a call to the given function.
* Only one function can be prepared at once.
*/
@@ -117,6 +135,13 @@ class Script
virtual int execute() = 0;
/**
+ * Assigns the current callback to the given \a function.
+ *
+ * Where the callback exactly comes from is up to the script engine.
+ */
+ virtual void assignCallback(Ref &function) = 0;
+
+ /**
* Sets associated map.
*/
void setMap(MapComposite *m)
diff --git a/src/scripting/scriptmanager.cpp b/src/scripting/scriptmanager.cpp
index 52515699..d58379f6 100644
--- a/src/scripting/scriptmanager.cpp
+++ b/src/scripting/scriptmanager.cpp
@@ -49,19 +49,6 @@ Script *ScriptManager::currentState()
// TODO: Have some generic event mechanism rather than calling global functions
-bool ScriptManager::executeGlobalEventFunction(const std::string &function, Being* obj)
-{
- bool isScriptHandled = false;
- _currentState->setMap(obj->getMap());
- _currentState->prepare(function);
- _currentState->push(obj);
- _currentState->execute();
- _currentState->setMap(NULL);
- isScriptHandled = true; // TODO: don't set to true when execution failed
- return isScriptHandled;
-}
-
-
void ScriptManager::addDataToSpecial(int id, Special *special)
{
/* currently only gets the recharge cost.
diff --git a/src/scripting/scriptmanager.h b/src/scripting/scriptmanager.h
index 7560c343..ade76c19 100644
--- a/src/scripting/scriptmanager.h
+++ b/src/scripting/scriptmanager.h
@@ -56,11 +56,6 @@ bool loadMainScript(const std::string &file);
*/
Script *currentState();
-
-/**
- * Runs a global function from the global event script file
- */
-bool executeGlobalEventFunction(const std::string &function, Being *obj);
void addDataToSpecial(int specialId, Special *special);
bool performSpecialAction(int specialId, Being *caster);
bool performCraft(Being *crafter, const std::list<InventoryItem> &recipe);