summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Sehmisch <crush@themanaworld.org>2009-01-22 01:40:38 +0100
committerPhilipp Sehmisch <crush@themanaworld.org>2009-01-22 02:40:56 +0100
commitc014f02719055ce5ec98d9fd0ed9ed2aaeb7b30c (patch)
treeece4bbbbca00d3cba07faf21150abbe64edb2291
parentece7a5e46a92a5cbf88bb72892dfc67dba059859 (diff)
downloadmanaserv-c014f02719055ce5ec98d9fd0ed9ed2aaeb7b30c.tar.gz
manaserv-c014f02719055ce5ec98d9fd0ed9ed2aaeb7b30c.tar.bz2
manaserv-c014f02719055ce5ec98d9fd0ed9ed2aaeb7b30c.tar.xz
manaserv-c014f02719055ce5ec98d9fd0ed9ed2aaeb7b30c.zip
Reduced the size of lua.cpp by putting the class LuaScript and the utility functions in separate files leaving only the script bindings themself. Unified internal and external names of lua script bindings.
-rw-r--r--src/Makefile.am4
-rw-r--r--src/scripting/lua.cpp447
-rw-r--r--src/scripting/luascript.cpp150
-rw-r--r--src/scripting/luascript.hpp89
-rw-r--r--src/scripting/luautil.cpp91
-rw-r--r--src/scripting/luautil.hpp124
6 files changed, 526 insertions, 379 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 41cab96a..c0a4c250 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -204,4 +204,8 @@ endif
if BUILD_LUA
tmwserv_game_SOURCES += \
scripting/lua.cpp
+ scripting/luascript.cpp
+ scripting/luascript.hpp
+ scripting/luautil.cpp
+ scripting/luautil.hpp
endif
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index e711623d..5e66bd8a 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -19,11 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#include <cassert>
-#include <list>
-#include <map>
-#include <set>
-#include <vector>
extern "C" {
#include <lualib.h>
@@ -50,191 +47,16 @@ extern "C" {
#include "game-server/state.hpp"
#include "game-server/trigger.hpp"
#include "net/messageout.hpp"
-#include "scripting/script.hpp"
+#include "scripting/luautil.hpp"
+#include "scripting/luascript.hpp"
#include "utils/logger.h"
-/**
- * Implementation of the Script class for Lua.
- */
-class LuaScript: public Script
-{
- public:
- /**
- * Constructor.
- */
- LuaScript();
-
- /**
- * Destructor.
- */
- ~LuaScript();
-
- void load(char const *);
-
- void prepare(std::string const &);
-
- void push(int);
-
- void push(const std::string &);
-
- void push(Thing *);
-
- int execute();
-
- static void getQuestCallback(Character *, std::string const &,
- std::string const &, void *);
-
- static void getPostCallback(Character *, std::string const &,
- std::string const &, void *);
-
- void processDeathEvent(Being* thing);
-
- private:
-
- lua_State *mState;
- int nbArgs;
- std::string mCurFunction;
-};
-
-static char const registryKey = 0;
-
-
-void raiseScriptError(lua_State *s, const char *format, ...)
-{
- va_list args;
- va_start(args, format);
- char message[1024];
- vsprintf(message, format, args);
- va_end( args );
-
- LOG_WARN("Lua script error: "<<message);
- luaL_error(s, message);
-}
-
-/* Functions below are unsafe, as they assume the script has passed pointers
- to objects which have not yet been destroyed. If the script never keeps
- pointers around, there will be no problem. In order to be safe, the engine
- should replace pointers by local identifiers and store them in a map. By
- listening to the death of objects, it could keep track of pointers still
- valid in the map.
- TODO: do it. */
-
-static NPC *getNPC(lua_State *s, int p)
-{
- if (!lua_islightuserdata(s, p)) return NULL;
- Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
- if (t->getType() != OBJECT_NPC) return NULL;
- return static_cast<NPC *>(t);
-}
-
-static Character *getCharacter(lua_State *s, int p)
-{
- if (!lua_islightuserdata(s, p)) return NULL;
- Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
- if (t->getType() != OBJECT_CHARACTER) return NULL;
- return static_cast<Character *>(t);
-}
-
-static Being *getBeing(lua_State *s, int p)
-{
- if (!lua_islightuserdata(s, p)) return NULL;
- Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
- return static_cast<Being *>(t);
-}
-
-/* Polymorphic wrapper for pushing variables.
- Useful for templates.*/
-void push(lua_State *s, int val)
-{
- lua_pushinteger(s, val);
-}
-void push(lua_State *s, const std::string &val)
-{
- lua_pushstring(s, val.c_str());
-}
-void push(lua_State *s, Thing* val)
-{
- lua_pushlightuserdata(s, val);
-}
-void push(lua_State *s, double val)
-{
- lua_pushnumber(s, val);
-}
-
-/* Pushes an STL LIST */
-template <typename T> void pushSTLContainer(lua_State *s, const std::list<T> &container)
-{
- int len = container.size();
- lua_newtable(s);
- int table = lua_gettop(s);
- typename std::list<T>::const_iterator i;
- i = container.begin();
-
- for (int key = 1; key <= len; key++)
- {
- push(s, key);
- push(s, *i);
- lua_settable(s, table);
- i++;
- }
-}
-
-/* Pushes an STL VECTOR */
-template <typename T> void pushSTLContainer(lua_State *s, const std::vector<T> &container)
-{
- int len = container.size();
- lua_createtable(s, 0, len);
- int table = lua_gettop(s);
-
- for (int key = 0; key < len; key++)
- {
- push(s, key+1);
- push(s, container.at(key).c_str());
- lua_settable(s, table);
- }
-}
-
-/* Pushes an STL MAP */
-template <typename Tkey, typename Tval> void pushSTLContainer(lua_State *s, const std::map<Tkey, Tval> &container)
-{
- int len = container.size();
- lua_createtable(s, 0, len);
- int table = lua_gettop(s);
- typename std::map<Tkey, Tval>::const_iterator i;
- i = container.begin();
-
- for (int key = 1; key <= len; key++)
- {
- push(s, i->first.c_str());
- push(s, i->second.c_str());
- lua_settable(s, table);
- i++;
- }
-}
-
-/* Pushes an STL SET */
-template <typename T> void pushSTLContainer(lua_State *s, const std::set<T> &container)
-{
- int len = container.size();
- lua_newtable(s);
- int table = lua_gettop(s);
- typename std::set<T>::const_iterator i;
- i = container.begin();
-
- for (int key = 1; key <= len; key++)
- {
- push(s, key);
- push(s, *i);
- lua_settable(s, table);
- i++;
- }
-}
/**
* Callback for sending a NPC_MESSAGE.
* tmw.npc_message(npc, character, string)
*/
-static int LuaNpc_Message(lua_State *s)
+static int npc_message(lua_State *s)
{
NPC *p = getNPC(s, 1);
Character *q = getCharacter(s, 2);
@@ -256,7 +78,7 @@ static int LuaNpc_Message(lua_State *s)
* Callback for sending a NPC_CHOICE.
* tmw.npc_choice(npc, character, string...)
*/
-static int LuaNpc_Choice(lua_State *s)
+static int npc_choice(lua_State *s)
{
NPC *p = getNPC(s, 1);
Character *q = getCharacter(s, 2);
@@ -285,7 +107,7 @@ static int LuaNpc_Choice(lua_State *s)
* Callback for creating a NPC on the current map with the current script.
* tmw.npc_create(string name, int id, int x, int y): npc
*/
-static int LuaNpc_Create(lua_State *s)
+static int npc_create(lua_State *s)
{
if (!lua_isstring(s, 1) || !lua_isnumber(s, 2) || !lua_isnumber(s, 3) || !lua_isnumber(s, 4))
{
@@ -316,7 +138,7 @@ static int LuaNpc_Create(lua_State *s)
* Callback for sending a NPC_POST.
* tmw.npc_post(npc, character)
*/
-static int LuaNPC_Post(lua_State *s)
+static int npc_post(lua_State *s)
{
NPC *p = getNPC(s, 1);
Character *q = getCharacter(s, 2);
@@ -338,7 +160,7 @@ static int LuaNPC_Post(lua_State *s)
* Enable a NPC if it has previously disabled
* tmw.npc_enable(npc)
*/
-static int LuaNPC_Enable(lua_State *s)
+static int npc_enable(lua_State *s)
{
NPC *p = getNPC(s, 1);
if (p)
@@ -355,7 +177,7 @@ static int LuaNPC_Enable(lua_State *s)
* Disable a NPC
* tmw.npc_disable(npc)
*/
-static int LuaNPC_Disable(lua_State *s)
+static int npc_disable(lua_State *s)
{
NPC *p = getNPC(s, 1);
if (p)
@@ -371,7 +193,7 @@ static int LuaNPC_Disable(lua_State *s)
* Callback for warping a player to another place.
* tmw.chr_warp(character, nil/int map, int x, int y)
*/
-static int LuaChr_Warp(lua_State *s)
+static int chr_warp(lua_State *s)
{
Character *q = getCharacter(s, 1);
bool b = lua_isnil(s, 2);
@@ -414,7 +236,7 @@ static int LuaChr_Warp(lua_State *s)
* Note: If an insertion fails, extra items are dropped on the floor.
* tmw.chr_inv_change(character, (int id, int nb)...): bool success
*/
-static int LuaChr_InvChange(lua_State *s)
+static int chr_inv_change(lua_State *s)
{
Character *q = getCharacter(s, 1);
if (!q)
@@ -480,7 +302,7 @@ static int LuaChr_InvChange(lua_State *s)
* When an item identifier is zero, money is queried.
* tmw.chr_inv_count(character, int id...): int count...
*/
-static int LuaChr_InvCount(lua_State *s)
+static int chr_inv_count(lua_State *s)
{
Character *q = getCharacter(s, 1);
if (!q)
@@ -509,7 +331,7 @@ static int LuaChr_InvCount(lua_State *s)
* Callback for trading between a player and an NPC.
* tmw.npc_trade(npc, character, bool sell, table items)
*/
-static int LuaNpc_Trade(lua_State *s)
+static int npc_trade(lua_State *s)
{
NPC *p = getNPC(s, 1);
Character *q = getCharacter(s, 2);
@@ -552,7 +374,7 @@ static int LuaNpc_Trade(lua_State *s)
* Returns the Thing type of the given Being
* tmw.being_type(Being *being)
*/
-static int LuaBeing_Type(lua_State *s)
+static int being_type(lua_State *s)
{
if (!lua_isuserdata(s, 1) )
{
@@ -570,7 +392,7 @@ static int LuaBeing_Type(lua_State *s)
* Function for making a being walk to a position
* being_walk(Being *being, int x, int y, int speed)
*/
-static int LuaBeing_Walk(lua_State *s)
+static int being_walk(lua_State *s)
{
if (!lua_isnumber(s, 2) || !lua_isnumber(s, 3) || !lua_isnumber(s, 4))
{
@@ -593,7 +415,7 @@ static int LuaBeing_Walk(lua_State *s)
* Makes the being say something
* tmw.being_say(source, message)
*/
-static int LuaBeing_Say(lua_State *s)
+static int being_say(lua_State *s)
{
if (!lua_isuserdata(s, 1) || !lua_isstring(s, 2) )
{
@@ -620,7 +442,7 @@ static int LuaBeing_Say(lua_State *s)
* Applies combat damage to a being
* tmw.being_damage(victim, value, delta, cth, type, element)
*/
-static int LuaBeing_Damage(lua_State *s)
+static int being_damage(lua_State *s)
{
Being *being = getBeing(s, 1);
@@ -640,7 +462,7 @@ static int LuaBeing_Damage(lua_State *s)
* Gets the attribute for a being
* tmw.being_get_attribute(being, attribute)
*/
-static int LuaBeing_GetAttribute(lua_State *s)
+static int being_get_attribute(lua_State *s)
{
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -669,7 +491,7 @@ static int LuaBeing_GetAttribute(lua_State *s)
* Gets the being's name
* tmw.being_get_name(being)
*/
-static int LuaBeing_GetName(lua_State *s)
+static int being_get_name(lua_State *s)
{
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -687,7 +509,7 @@ static int LuaBeing_GetName(lua_State *s)
/**
* Function for getting the x-coordinate of the position of a being
*/
-static int LuaPosX(lua_State *s)
+static int posX(lua_State *s)
{
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -701,7 +523,7 @@ static int LuaPosX(lua_State *s)
/**
* Function for getting the y-coordinate of the position of a being
*/
-static int LuaPosY(lua_State *s)
+static int posY(lua_State *s)
{
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -716,7 +538,7 @@ static int LuaPosY(lua_State *s)
* Callback for creating a monster on the current map.
* tmw.monster_create(int type, int x, int y)
*/
-static int LuaMonster_Create(lua_State *s)
+static int monster_create(lua_State *s)
{
if (!lua_isnumber(s, 1) || !lua_isnumber(s, 2) || !lua_isnumber(s, 3))
{
@@ -748,7 +570,7 @@ static int LuaMonster_Create(lua_State *s)
q->setPosition(Point(lua_tointeger(s, 2), lua_tointeger(s, 3)));
if (!GameState::insertSafe(q))
{
- LOG_WARN("LuaMonster_Create failed to insert monster");
+ LOG_WARN("Monster_Create failed to insert monster");
return 0;
}
@@ -757,44 +579,11 @@ static int LuaMonster_Create(lua_State *s)
}
/**
- * Called when the server has recovered the value of a quest variable.
- */
-void LuaScript::getQuestCallback(Character *q, std::string const &name,
- std::string const &value, void *data)
-{
- LuaScript *s = static_cast< LuaScript * >(data);
- assert(s->nbArgs == -1);
- lua_getglobal(s->mState, "quest_reply");
- lua_pushlightuserdata(s->mState, q);
- lua_pushstring(s->mState, name.c_str());
- lua_pushstring(s->mState, value.c_str());
- s->nbArgs = 3;
- s->execute();
-}
-
-/**
- * Called when the server has recovered the post for a user
- */
-void LuaScript::getPostCallback(Character *q, std::string const &sender,
- std::string const &letter, void *data)
-{
- // get the script
- LuaScript *s = static_cast<LuaScript*>(data);
- assert(s->nbArgs == -1);
- lua_getglobal(s->mState, "post_reply");
- lua_pushlightuserdata(s->mState, q);
- lua_pushstring(s->mState, sender.c_str());
- lua_pushstring(s->mState, letter.c_str());
- s->nbArgs = 3;
- s->execute();
-}
-
-/**
* Callback for getting a quest variable. Starts a recovery and returns
* immediatly, if the variable is not known yet.
* tmw.chr_get_chest(character, string): nil or string
*/
-static int LuaChr_GetQuest(lua_State *s)
+static int chr_get_quest(lua_State *s)
{
Character *q = getCharacter(s, 1);
char const *m = lua_tostring(s, 2);
@@ -822,7 +611,7 @@ static int LuaChr_GetQuest(lua_State *s)
* Callback for setting a quest variable.
* tmw.chr_set_chest(character, string, string)
*/
-static int LuaChr_SetQuest(lua_State *s)
+static int chr_set_quest(lua_State *s)
{
Character *q = getCharacter(s, 1);
char const *m = lua_tostring(s, 2);
@@ -841,7 +630,7 @@ static int LuaChr_SetQuest(lua_State *s)
* a Lua function is called.
* tmw.trigger_create (x, y, width, height, function, id)
*/
-static int LuaTrigger_Create(lua_State *s)
+static int trigger_create(lua_State *s)
{
//TODO: argument check
if (!lua_isnumber(s, 1) ||
@@ -891,7 +680,7 @@ static int LuaTrigger_Create(lua_State *s)
* global message: tmw.chatmessage (message)
* private massage: tmw.chatmessage (recipent, message)
*/
-static int LuaChatmessage(lua_State *s)
+static int chatmessage(lua_State *s)
{
if (lua_gettop(s) == 2 && lua_isuserdata(s, 1) && lua_isstring(s, 2) )
{
@@ -921,7 +710,7 @@ static int LuaChatmessage(lua_State *s)
* inside of a circular area of the current map.
* tmw.get_beings_in_circle (x, y, radius)
*/
-static int LuaGetBeingsInCircle(lua_State *s)
+static int get_beings_in_circle(lua_State *s)
{
int x = lua_tointeger(s, 1);
int y = lua_tointeger(s, 2);
@@ -959,7 +748,7 @@ static int LuaGetBeingsInCircle(lua_State *s)
/**
* Gets the post for the character
*/
-static int LuaChr_GetPost(lua_State *s)
+static int chr_get_post(lua_State *s)
{
if (lua_isuserdata(s, 1))
{
@@ -983,7 +772,7 @@ static int LuaChr_GetPost(lua_State *s)
* with the being ID when the being dies.
* tmw.note_on_death (being)
*/
-static int LuaNoteOnDeath(lua_State *s)
+static int note_on_death(lua_State *s)
{
if (!lua_islightuserdata(s, 1) || lua_gettop(s) != 1)
{
@@ -1009,7 +798,7 @@ static int LuaNoteOnDeath(lua_State *s)
* Triggers a special effect from the clients effects.xml
* tmw.effect_create (id, x, y)
*/
-static int LuaEffect_Create(lua_State *s)
+static int effect_create(lua_State *s)
{
if (!lua_isnumber(s, 1) ||
!lua_isnumber(s, 2) ||
@@ -1036,7 +825,7 @@ static int LuaEffect_Create(lua_State *s)
* Gets the exp total in a skill of a specific character
* tmw.chr_get_exp (being, skill)
*/
-static int LuaChr_GetExp(lua_State *s)
+static int chr_get_exp(lua_State *s)
{
Character *c = getCharacter(s, 1);
if (!c)
@@ -1065,7 +854,7 @@ static int LuaChr_GetExp(lua_State *s)
* desired.
* tmw.chr_give_exp (being, skill, amount)
*/
-static int LuaChr_GiveExp(lua_State *s)
+static int chr_give_exp(lua_State *s)
{
Character *c = getCharacter(s, 1);
if (!c)
@@ -1093,7 +882,7 @@ static int LuaChr_GiveExp(lua_State *s)
* Returns the exp total necessary to reach a specific skill level.
* tmw.exp_for_level (level)
*/
-static int LuaExpForLevel(lua_State *s)
+static int exp_for_level(lua_State *s)
{
int level = lua_tointeger(s, 1);
@@ -1108,7 +897,7 @@ static int LuaExpForLevel(lua_State *s)
* This function can be removed when there are more useful functions which use
* them.
*/
-static int LuaTest_Tableget(lua_State *s)
+static int test_tableget(lua_State *s)
{
std::list<float> list;
@@ -1154,7 +943,7 @@ static int LuaTest_Tableget(lua_State *s)
/**
* Returns the ID of the current map
*/
-static int LuaGet_MapId(lua_State *s)
+static int get_map_id(lua_State *s)
{
lua_pushlightuserdata(s, (void *)&registryKey);
lua_gettable(s, LUA_REGISTRYINDEX);
@@ -1172,38 +961,38 @@ LuaScript::LuaScript():
// Put some callback functions in the scripting environment.
static luaL_reg const callbacks[] = {
- { "npc_create", &LuaNpc_Create },
- { "npc_message", &LuaNpc_Message },
- { "npc_choice", &LuaNpc_Choice },
- { "npc_trade", &LuaNpc_Trade },
- { "npc_post", &LuaNPC_Post },
- { "npc_enable", &LuaNPC_Enable },
- { "npc_disable", &LuaNPC_Disable },
- { "chr_warp", &LuaChr_Warp },
- { "chr_inv_change", &LuaChr_InvChange },
- { "chr_inv_count", &LuaChr_InvCount },
- { "chr_get_quest", &LuaChr_GetQuest },
- { "chr_set_quest", &LuaChr_SetQuest },
- { "chr_get_post", &LuaChr_GetPost },
- { "chr_get_exp", &LuaChr_GetExp },
- { "chr_give_exp", &LuaChr_GiveExp },
- { "exp_for_level", &LuaExpForLevel },
- { "monster_create", &LuaMonster_Create },
- { "being_type", &LuaBeing_Type },
- { "being_walk", &LuaBeing_Walk },
- { "being_say", &LuaBeing_Say },
- { "being_damage", &LuaBeing_Damage },
- { "being_get_attribute", &LuaBeing_GetAttribute},
- { "being_get_name", &LuaBeing_GetName },
- { "posX", &LuaPosX },
- { "posY", &LuaPosY },
- { "trigger_create", &LuaTrigger_Create },
- { "chatmessage", &LuaChatmessage },
- { "get_beings_in_circle", &LuaGetBeingsInCircle },
- { "note_on_death", &LuaNoteOnDeath },
- { "effect_create", &LuaEffect_Create },
- { "test_tableget", &LuaTest_Tableget },
- { "get_map_id", &LuaGet_MapId },
+ { "npc_create", &npc_create },
+ { "npc_message", &npc_message },
+ { "npc_choice", &npc_choice },
+ { "npc_trade", &npc_trade },
+ { "npc_post", &npc_post },
+ { "npc_enable", &npc_enable },
+ { "npc_disable", &npc_disable },
+ { "chr_warp", &chr_warp },
+ { "chr_inv_change", &chr_inv_change },
+ { "chr_inv_count", &chr_inv_count },
+ { "chr_get_quest", &chr_get_quest },
+ { "chr_set_quest", &chr_set_quest },
+ { "chr_get_post", &chr_get_post },
+ { "chr_get_exp", &chr_get_exp },
+ { "chr_give_exp", &chr_give_exp },
+ { "exp_for_level", &exp_for_level },
+ { "monster_create", &monster_create },
+ { "being_type", &being_type },
+ { "being_walk", &being_walk },
+ { "being_say", &being_say },
+ { "being_damage", &being_damage },
+ { "being_get_attribute", &being_get_attribute },
+ { "being_get_name", &being_get_name },
+ { "posX", &posX },
+ { "posY", &posY },
+ { "trigger_create", &trigger_create },
+ { "chatmessage", &chatmessage },
+ { "get_beings_in_circle", &get_beings_in_circle },
+ { "note_on_death", &note_on_death },
+ { "effect_create", &effect_create },
+ { "test_tableget", &test_tableget },
+ { "get_map_id", &get_map_id },
{ NULL, NULL }
};
luaL_register(mState, "tmw", callbacks);
@@ -1217,103 +1006,3 @@ LuaScript::LuaScript():
loadFile("scripts/libs/libtmw.lua");
}
-LuaScript::~LuaScript()
-{
- lua_close(mState);
-}
-
-void LuaScript::prepare(std::string const &name)
-{
- assert(nbArgs == -1);
- lua_getglobal(mState, name.c_str());
- nbArgs = 0;
- mCurFunction = name;
-}
-
-void LuaScript::push(int v)
-{
- assert(nbArgs >= 0);
- lua_pushinteger(mState, v);
- ++nbArgs;
-}
-
-void LuaScript::push(std::string const &v)
-{
- assert(nbArgs >= 0);
- lua_pushstring(mState, v.c_str());
- ++nbArgs;
-}
-
-void LuaScript::push(Thing *v)
-{
- assert(nbArgs >= 0);
- lua_pushlightuserdata(mState, v);
- ++nbArgs;
-}
-
-int LuaScript::execute()
-{
- assert(nbArgs >= 0);
- int res = lua_pcall(mState, nbArgs, 1, 0);
- nbArgs = -1;
- if (res || !(lua_isnil(mState, 1) || lua_isnumber(mState, 1)))
- {
- char const *s = lua_tostring(mState, 1);
-
- LOG_WARN("Lua Script Error" << std::endl
- << " Script : " << mScriptFile << std::endl
- << " Function: " << mCurFunction << std::endl
- << " Error : " << (s ? s : "") << std::endl);
- lua_pop(mState, 1);
- return 0;
- }
- res = lua_tointeger(mState, 1);
- lua_pop(mState, 1);
- return res;
- mCurFunction = "";
-}
-
-void LuaScript::load(char const *prog)
-{
- int res = luaL_loadstring(mState, prog);
-
- if (res == LUA_ERRSYNTAX)
- {
- LOG_ERROR("Syntax error while loading Lua script.");
- return;
- }
-
- // A Lua chunk is like a function, so "execute" it in order to initialize
- // it.
- res = lua_pcall(mState, 0, 0, 0);
- if (res)
- {
- LOG_ERROR("Failure while initializing Lua script: "
- << lua_tostring(mState, -1));
- lua_settop(mState, 0);
- return;
- }
-}
-
-void LuaScript::processDeathEvent(Being *being)
-{
- prepare("death_notification");
- push(being);
- //TODO: get and push a list of creatures who contributed to killing the
- // being. This might be very interesting for scripting quests.
- execute();
-
- being->removeListener(getScriptDeathListener());
-}
-
-static Script *LuaFactory()
-{
- return new LuaScript();
-}
-
-struct LuaRegister
-{
- LuaRegister() { Script::registerEngine("lua", LuaFactory); }
-};
-
-static LuaRegister dummy;
diff --git a/src/scripting/luascript.cpp b/src/scripting/luascript.cpp
new file mode 100644
index 00000000..d2083952
--- /dev/null
+++ b/src/scripting/luascript.cpp
@@ -0,0 +1,150 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cassert>
+
+#include "luascript.hpp"
+
+#include "game-server/being.hpp"
+
+#include "utils/logger.h"
+
+LuaScript::~LuaScript()
+{
+ lua_close(mState);
+}
+
+void LuaScript::prepare(std::string const &name)
+{
+ assert(nbArgs == -1);
+ lua_getglobal(mState, name.c_str());
+ nbArgs = 0;
+ mCurFunction = name;
+}
+
+void LuaScript::push(int v)
+{
+ assert(nbArgs >= 0);
+ lua_pushinteger(mState, v);
+ ++nbArgs;
+}
+
+void LuaScript::push(std::string const &v)
+{
+ assert(nbArgs >= 0);
+ lua_pushstring(mState, v.c_str());
+ ++nbArgs;
+}
+
+void LuaScript::push(Thing *v)
+{
+ assert(nbArgs >= 0);
+ lua_pushlightuserdata(mState, v);
+ ++nbArgs;
+}
+
+int LuaScript::execute()
+{
+ assert(nbArgs >= 0);
+ int res = lua_pcall(mState, nbArgs, 1, 0);
+ nbArgs = -1;
+ if (res || !(lua_isnil(mState, 1) || lua_isnumber(mState, 1)))
+ {
+ char const *s = lua_tostring(mState, 1);
+
+ LOG_WARN("Lua Script Error" << std::endl
+ << " Script : " << mScriptFile << std::endl
+ << " Function: " << mCurFunction << std::endl
+ << " Error : " << (s ? s : "") << std::endl);
+ lua_pop(mState, 1);
+ return 0;
+ }
+ res = lua_tointeger(mState, 1);
+ lua_pop(mState, 1);
+ return res;
+ mCurFunction = "";
+}
+
+void LuaScript::load(char const *prog)
+{
+ int res = luaL_loadstring(mState, prog);
+
+ if (res == LUA_ERRSYNTAX)
+ {
+ LOG_ERROR("Syntax error while loading Lua script.");
+ return;
+ }
+
+ // A Lua chunk is like a function, so "execute" it in order to initialize
+ // it.
+ res = lua_pcall(mState, 0, 0, 0);
+ if (res)
+ {
+ LOG_ERROR("Failure while initializing Lua script: "
+ << lua_tostring(mState, -1));
+ lua_settop(mState, 0);
+ return;
+ }
+}
+
+void LuaScript::processDeathEvent(Being *being)
+{
+ prepare("death_notification");
+ push(being);
+ //TODO: get and push a list of creatures who contributed to killing the
+ // being. This might be very interesting for scripting quests.
+ execute();
+
+ being->removeListener(getScriptDeathListener());
+}
+
+/**
+ * Called when the server has recovered the value of a quest variable.
+ */
+void LuaScript::getQuestCallback(Character *q, std::string const &name,
+ std::string const &value, void *data)
+{
+ LuaScript *s = static_cast< LuaScript * >(data);
+ assert(s->nbArgs == -1);
+ lua_getglobal(s->mState, "quest_reply");
+ lua_pushlightuserdata(s->mState, q);
+ lua_pushstring(s->mState, name.c_str());
+ lua_pushstring(s->mState, value.c_str());
+ s->nbArgs = 3;
+ s->execute();
+}
+
+/**
+ * Called when the server has recovered the post for a user
+ */
+void LuaScript::getPostCallback(Character *q, std::string const &sender,
+ std::string const &letter, void *data)
+{
+ // get the script
+ LuaScript *s = static_cast<LuaScript*>(data);
+ assert(s->nbArgs == -1);
+ lua_getglobal(s->mState, "post_reply");
+ lua_pushlightuserdata(s->mState, q);
+ lua_pushstring(s->mState, sender.c_str());
+ lua_pushstring(s->mState, letter.c_str());
+ s->nbArgs = 3;
+ s->execute();
+}
diff --git a/src/scripting/luascript.hpp b/src/scripting/luascript.hpp
new file mode 100644
index 00000000..9f1097f7
--- /dev/null
+++ b/src/scripting/luascript.hpp
@@ -0,0 +1,89 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef LUASCRIPT_HPP_INCLUDED
+#define LUASCRIPT_HPP_INCLUDED
+
+extern "C" {
+#include <lualib.h>
+#include <lauxlib.h>
+}
+
+#include "scripting/script.hpp"
+
+/**
+ * Implementation of the Script class for Lua.
+ */
+class LuaScript: public Script
+{
+ public:
+ /**
+ * Constructor.
+ */
+ LuaScript();
+
+ /**
+ * Destructor.
+ */
+ ~LuaScript();
+
+ void load(char const *);
+
+ void prepare(std::string const &);
+
+ void push(int);
+
+ void push(const std::string &);
+
+ void push(Thing *);
+
+ int execute();
+
+ static void getQuestCallback(Character *, std::string const &,
+ std::string const &, void *);
+
+ static void getPostCallback(Character *, std::string const &,
+ std::string const &, void *);
+
+ void processDeathEvent(Being* thing);
+
+ private:
+
+ lua_State *mState;
+ int nbArgs;
+ std::string mCurFunction;
+};
+
+static char const registryKey = 0;
+
+static Script *LuaFactory()
+{
+ return new LuaScript();
+}
+
+struct LuaRegister
+{
+ LuaRegister() { Script::registerEngine("lua", LuaFactory); }
+};
+
+static LuaRegister dummy;
+
+#endif // LUASCRIPT_HPP_INCLUDED
diff --git a/src/scripting/luautil.cpp b/src/scripting/luautil.cpp
new file mode 100644
index 00000000..a18b710f
--- /dev/null
+++ b/src/scripting/luautil.cpp
@@ -0,0 +1,91 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "luautil.hpp"
+
+#include "game-server/character.hpp"
+#include "game-server/npc.hpp"
+
+#include "utils/logger.h"
+
+
+void raiseScriptError(lua_State *s, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char message[1024];
+ vsprintf(message, format, args);
+ va_end( args );
+
+ LOG_WARN("Lua script error: "<<message);
+ luaL_error(s, message);
+}
+
+/* Functions below are unsafe, as they assume the script has passed pointers
+ to objects which have not yet been destroyed. If the script never keeps
+ pointers around, there will be no problem. In order to be safe, the engine
+ should replace pointers by local identifiers and store them in a map. By
+ listening to the death of objects, it could keep track of pointers still
+ valid in the map.
+ TODO: do it. */
+
+NPC *getNPC(lua_State *s, int p)
+{
+ if (!lua_islightuserdata(s, p)) return NULL;
+ Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
+ if (t->getType() != OBJECT_NPC) return NULL;
+ return static_cast<NPC *>(t);
+}
+
+Character *getCharacter(lua_State *s, int p)
+{
+ if (!lua_islightuserdata(s, p)) return NULL;
+ Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
+ if (t->getType() != OBJECT_CHARACTER) return NULL;
+ return static_cast<Character *>(t);
+}
+
+Being *getBeing(lua_State *s, int p)
+{
+ if (!lua_islightuserdata(s, p)) return NULL;
+ Thing *t = static_cast<Thing *>(lua_touserdata(s, p));
+ return static_cast<Being *>(t);
+}
+
+void push(lua_State *s, int val)
+{
+ lua_pushinteger(s, val);
+}
+
+void push(lua_State *s, const std::string &val)
+{
+ lua_pushstring(s, val.c_str());
+}
+
+void push(lua_State *s, Thing* val)
+{
+ lua_pushlightuserdata(s, val);
+}
+
+void push(lua_State *s, double val)
+{
+ lua_pushnumber(s, val);
+}
diff --git a/src/scripting/luautil.hpp b/src/scripting/luautil.hpp
new file mode 100644
index 00000000..79623ab9
--- /dev/null
+++ b/src/scripting/luautil.hpp
@@ -0,0 +1,124 @@
+/*
+ * The Mana World Server
+ * Copyright 2007 The Mana World Development Team
+ *
+ * This file is part of The Mana World.
+ *
+ * The Mana World is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * any later version.
+ *
+ * The Mana World is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Mana World; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _TMWSERV_SCRIPTING_LUAUTIL_HPP
+#define _TMWSERV_SCRIPTING_LUAUTIL_HPP
+
+extern "C" {
+#include <lualib.h>
+#include <lauxlib.h>
+}
+#include <string>
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+
+class Being;
+class NPC;
+class Character;
+class Thing;
+
+void raiseScriptError(lua_State *s, const char *format, ...);
+
+NPC *getNPC(lua_State *s, int p);
+Character *getCharacter(lua_State *s, int p);
+Being *getBeing(lua_State *s, int p);
+
+
+/* Polymorphic wrapper for pushing variables.
+ Useful for templates.*/
+void push(lua_State *s, int val);
+void push(lua_State *s, const std::string &val);
+void push(lua_State *s, Thing* val);
+void push(lua_State *s, double val);
+
+
+/* Pushes an STL LIST */
+template <typename T> void pushSTLContainer(lua_State *s, const std::list<T> &container)
+{
+ int len = container.size();
+ lua_newtable(s);
+ int table = lua_gettop(s);
+ typename std::list<T>::const_iterator i;
+ i = container.begin();
+
+ for (int key = 1; key <= len; key++)
+ {
+ push(s, key);
+ push(s, *i);
+ lua_settable(s, table);
+ i++;
+ }
+}
+
+/* Pushes an STL VECTOR */
+template <typename T> void pushSTLContainer(lua_State *s, const std::vector<T> &container)
+{
+ int len = container.size();
+ lua_createtable(s, 0, len);
+ int table = lua_gettop(s);
+
+ for (int key = 0; key < len; key++)
+ {
+ push(s, key+1);
+ push(s, container.at(key).c_str());
+ lua_settable(s, table);
+ }
+}
+
+/* Pushes an STL MAP */
+template <typename Tkey, typename Tval> void pushSTLContainer(lua_State *s, const std::map<Tkey, Tval> &container)
+{
+ int len = container.size();
+ lua_createtable(s, 0, len);
+ int table = lua_gettop(s);
+ typename std::map<Tkey, Tval>::const_iterator i;
+ i = container.begin();
+
+ for (int key = 1; key <= len; key++)
+ {
+ push(s, i->first.c_str());
+ push(s, i->second.c_str());
+ lua_settable(s, table);
+ i++;
+ }
+}
+
+/* Pushes an STL SET */
+template <typename T> void pushSTLContainer(lua_State *s, const std::set<T> &container)
+{
+ int len = container.size();
+ lua_newtable(s);
+ int table = lua_gettop(s);
+ typename std::set<T>::const_iterator i;
+ i = container.begin();
+
+ for (int key = 1; key <= len; key++)
+ {
+ push(s, key);
+ push(s, *i);
+ lua_settable(s, table);
+ i++;
+ }
+}
+
+#endif