summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Athay <ko2fan@gmail.com>2009-01-27 17:14:34 +0000
committerDavid Athay <ko2fan@gmail.com>2009-01-27 17:14:34 +0000
commitfa5469bd27d117abd98ca58dad61a6378fe8215c (patch)
tree81e04d035dfc54fa9f4cca62523232ce567c9ce6
parentf666fd38beefb554d90503811e5a43d504a18345 (diff)
parentc423c02890cfb4520da0ac75e00d1bd9f1663ce0 (diff)
downloadmanaserv-fa5469bd27d117abd98ca58dad61a6378fe8215c.tar.gz
manaserv-fa5469bd27d117abd98ca58dad61a6378fe8215c.tar.bz2
manaserv-fa5469bd27d117abd98ca58dad61a6378fe8215c.tar.xz
manaserv-fa5469bd27d117abd98ca58dad61a6378fe8215c.zip
Merge branch 'master' of git@gitorious.org:tmwserv/mainline
-rw-r--r--src/Makefile.am6
-rw-r--r--src/account-server/accounthandler.cpp2
-rw-r--r--src/game-server/character.cpp7
-rw-r--r--src/game-server/commandhandler.cpp96
-rw-r--r--src/game-server/item.cpp4
-rw-r--r--src/game-server/itemmanager.cpp29
-rw-r--r--src/game-server/spawnarea.cpp2
-rw-r--r--src/net/netcomputer.cpp16
-rw-r--r--src/net/netcomputer.hpp13
-rw-r--r--src/scripting/lua.cpp468
-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
-rw-r--r--src/scripting/script.cpp6
-rw-r--r--src/scripting/script.hpp5
16 files changed, 677 insertions, 431 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 41cab96a..f8923824 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -203,5 +203,9 @@ endif
if BUILD_LUA
tmwserv_game_SOURCES += \
- scripting/lua.cpp
+ scripting/lua.cpp \
+ scripting/luascript.cpp \
+ scripting/luascript.hpp \
+ scripting/luautil.cpp \
+ scripting/luautil.hpp
endif
diff --git a/src/account-server/accounthandler.cpp b/src/account-server/accounthandler.cpp
index 506d80f8..13c280fd 100644
--- a/src/account-server/accounthandler.cpp
+++ b/src/account-server/accounthandler.cpp
@@ -170,7 +170,7 @@ static void handleLoginMessage(AccountClient &computer, MessageIn &msg)
}
// get the IP address
- int address = computer.getIP();
+ //int address = computer.getIP();
// TODO: Check IP against blacklist
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 780a142b..a17e3d89 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -26,6 +26,7 @@
#include "game-server/character.hpp"
#include "defines.h"
+#include "common/configuration.hpp"
#include "game-server/accountconnection.hpp"
#include "game-server/attackzone.hpp"
#include "game-server/buysell.hpp"
@@ -130,9 +131,9 @@ void Character::respawn()
}
//warp back to spawn point
- static const int spawnMap = 1;
- static const int spawnX = 1024;
- static const int spawnY = 1024;
+ int spawnMap = Configuration::getValue("respawnMap", 1);
+ int spawnX = Configuration::getValue("respawnX", 1024);
+ int spawnY = Configuration::getValue("respawnY", 1024);
GameState::enqueueWarp(this, MapManager::getMap(spawnMap), spawnX, spawnY);
//make alive again
diff --git a/src/game-server/commandhandler.cpp b/src/game-server/commandhandler.cpp
index 5268d131..3c716da5 100644
--- a/src/game-server/commandhandler.cpp
+++ b/src/game-server/commandhandler.cpp
@@ -19,6 +19,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <sstream>
+
#include "defines.h"
#include "commandhandler.hpp"
#include "accountconnection.hpp"
@@ -39,7 +41,7 @@ static void say(const std::string error, Character *player)
GameState::sayTo(player, NULL, error);
}
-static bool handlePermissions(Character *player, unsigned int permissions)
+static bool checkPermission(Character *player, unsigned int permissions)
{
if (player->getAccountLevel() & permissions)
{
@@ -93,25 +95,30 @@ static void handleHelp(Character *player, std::string &args)
{
if (player->getAccountLevel() & AL_PLAYER)
{
- say("Game Master Commands:", player);
+ say("=General Commands=", player);
say("@help [command]", player);
say("@report <bug>", player);
+ say("@where", player);
+ say("@rights", player);
}
if (player->getAccountLevel() & AL_TESTER)
{
+ say("=Tester Commands=", player);
say("@warp <character> <map> <x> <y>", player);
say("@goto <character>", player);
}
if (player->getAccountLevel() & AL_GM)
{
+ say("=Game Master Commands=", player);
say("@recall <character>", player);
say("@ban <character> <length of time>", player);
}
if (player->getAccountLevel() & AL_DEV)
{
+ say("=Developer Commands=", player);
say("@item <character> <item id> <amount>", player);
say("@drop <item id> <amount>", player);
say("@money <character> <amount>", player);
@@ -121,7 +128,7 @@ static void handleHelp(Character *player, std::string &args)
if (player->getAccountLevel() & AL_ADMIN)
{
- say("Administrator Commands", player);
+ say("=Administrator Commands=", player);
say("@reload", player);
say("@setgroup <character> <AL level>", player);
say("@announce <message>", player);
@@ -149,6 +156,7 @@ static void handleWarp(Character *player, std::string &args)
if (character == "" || mapstr == "" || xstr == "" || ystr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @warp <character> <map> <x> <y>", player);
return;
}
@@ -230,6 +238,7 @@ static void handleItem(Character *player, std::string &args)
if (character == "" || itemclass == "" || valuestr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @item <character> <itemID> <amount>", player);
return;
}
@@ -299,6 +308,7 @@ static void handleDrop(Character *player, std::string &args)
if (itemclass == "" || valuestr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @drop <itemID> <amount]>", player);
return;
}
@@ -349,6 +359,7 @@ static void handleMoney(Character *player, std::string &args)
if (character == "" || valuestr == "")
{
say("Invalid number of arguments given", player);
+ say("Usage: @money <character> <amount>", player);
return;
}
@@ -397,6 +408,7 @@ static void handleSpawn(Character *player, std::string &args)
if (monsterclass == "" || valuestr == "")
{
say("Invalid amount of arguments given.", player);
+ say("Usage: @spawn <monsterID> <number>", player);
return;
}
@@ -453,6 +465,7 @@ static void handleGoto(Character *player, std::string &args)
if (character == "")
{
say("Invalid amount of arguments given.", player);
+ say("Usage: @goto <character>", player);
return;
}
@@ -481,6 +494,7 @@ static void handleRecall(Character *player, std::string &args)
if (character == "")
{
say("Invalid amount of arguments given.", player);
+ say("Usage: @recall <character>", player);
return;
}
@@ -518,6 +532,7 @@ static void handleBan(Character *player, std::string &args)
if (character == "" || valuestr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @ban <character> <duration>", player);
return;
}
@@ -562,6 +577,7 @@ static void handleSetGroup(Character *player, std::string &args)
if (character == "" || levelstr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @setgroup <character> <level>", player);
return;
}
@@ -628,6 +644,7 @@ static void handleAttribute(Character *player, std::string &args)
if (character == "" || valuestr == "" || attrstr == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @attribute <character> <attribute> <value>", player);
return;
}
@@ -683,6 +700,7 @@ static void handleReport(Character *player, std::string &args)
if (bugReport == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @report <message>", player);
return;
}
@@ -696,12 +714,44 @@ static void handleAnnounce(Character *player, std::string &args)
if (msg == "")
{
say("Invalid number of arguments given.", player);
+ say("Usage: @announce <message>", player);
return;
}
GameState::sayToAll(msg);
}
+static void handleWhere(Character *player)
+{
+ std::stringstream str;
+ str << "Your current location is map "
+ << player->getMapId()
+ << " ["
+ << player->getPosition().x
+ << ":"
+ << player->getPosition().y
+ << "]";
+ say (str.str(), player);
+}
+
+static void handleRights(Character *player)
+{
+ std::stringstream str;
+ str << "Your rights level is: "
+ << player->getAccountLevel()
+ << " (AL_PLAYER";
+ if (player->getAccountLevel() & AL_TESTER)
+ str << ", AL_TESTER";
+ if (player->getAccountLevel() & AL_GM)
+ str << ", AL_GM";
+ if (player->getAccountLevel() & AL_ADMIN)
+ str << ", AL_ADMIN";
+ str << ")";
+ say(str.str(), player);
+}
+
+
+
void CommandHandler::handleCommand(Character *player,
const std::string &command)
{
@@ -714,76 +764,86 @@ void CommandHandler::handleCommand(Character *player,
// handle the command
if (type == "help")
{
- if (handlePermissions(player, AL_PLAYER))
+ if (checkPermission(player, AL_PLAYER))
handleHelp(player, args);
}
+ else if (type == "where" || type == "location")
+ {
+ if (checkPermission(player, AL_PLAYER))
+ handleWhere(player);
+ }
+ else if (type == "rights" || type == "right" || type == "permission")
+ {
+ if (checkPermission(player, AL_PLAYER))
+ handleRights(player);
+ }
else if (type == "warp")
{
- if (handlePermissions(player, AL_TESTER))
+ if (checkPermission(player, AL_TESTER))
handleWarp(player, args);
}
else if (type == "item")
{
- if (handlePermissions(player, AL_DEV))
+ if (checkPermission(player, AL_DEV))
handleItem(player, args);
}
else if (type == "drop")
{
- if (handlePermissions(player, AL_DEV))
+ if (checkPermission(player, AL_DEV))
handleDrop(player, args);
}
else if (type == "money")
{
- if (handlePermissions(player, AL_DEV))
+ if (checkPermission(player, AL_DEV))
handleMoney(player, args);
}
else if (type == "spawn")
{
- if (handlePermissions(player, AL_DEV))
+ if (checkPermission(player, AL_DEV))
handleSpawn(player, args);
}
else if (type == "goto")
{
- if (handlePermissions(player, AL_TESTER))
+ if (checkPermission(player, AL_TESTER))
handleGoto(player, args);
}
else if (type == "recall")
{
- if (handlePermissions(player, AL_GM))
+ if (checkPermission(player, AL_GM))
handleRecall(player, args);
}
else if (type == "reload")
{
- if (handlePermissions(player, AL_ADMIN))
+ if (checkPermission(player, AL_ADMIN))
handleReload(player);
}
else if (type == "ban")
{
- if (handlePermissions(player, AL_GM))
+ if (checkPermission(player, AL_GM))
handleBan(player, args);
}
else if (type == "setgroup")
{
- if (handlePermissions(player, AL_ADMIN))
+ if (checkPermission(player, AL_ADMIN))
handleSetGroup(player, args);
}
else if (type == "attribute")
{
- if (handlePermissions(player, AL_DEV))
+ if (checkPermission(player, AL_DEV))
handleAttribute(player, args);
}
else if (type == "report")
{
- if (handlePermissions(player, AL_PLAYER))
+ if (checkPermission(player, AL_PLAYER))
handleReport(player, args);
}
else if (type == "announce")
{
- if (handlePermissions(player, AL_ADMIN))
+ if (checkPermission(player, AL_ADMIN))
handleAnnounce(player, args);
}
else
{
- say("command not found", player);
+ say("Command not found. Enter @help to view the list of available commands.", player);
}
}
diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp
index 892be2cf..817c81ec 100644
--- a/src/game-server/item.cpp
+++ b/src/game-server/item.cpp
@@ -147,9 +147,9 @@ bool ItemClass::use(Being *itemUser)
if (mType != ITEM_USABLE) return false;
if (mScript)
{
- mScript->prepare("item_use");
- mScript->push(mDatabaseID);
+ mScript->prepare("use");
mScript->push(itemUser);
+ mScript->push(mDatabaseID); // ID of the item
mScript->execute();
}
mModifiers.applyAttributes(itemUser);
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index 3f67ae8b..e275d1a6 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -135,7 +135,7 @@ void ItemManager::reload()
int value = XML::getProperty(node, "value", 0);
int maxPerSlot = XML::getProperty(node, "max-per-slot", 0);
int sprite = XML::getProperty(node, "sprite_id", 0);
- std::string scriptName = XML::getProperty(node, "script_name", std::string());
+ std::string scriptFile = XML::getProperty(node, "script", "");
std::string attackShape = XML::getProperty(node, "attack-shape", "cone");
std::string attackTarget = XML::getProperty(node, "attack-target", "multi");
int attackRange = XML::getProperty(node, "attack-range", 32);
@@ -172,8 +172,8 @@ void ItemManager::reload()
if (maxPerSlot == 0)
{
- LOG_WARN("Item Manager: Missing max-per-slot property for "
- "item " << id << " in " << itemReferenceFile << '.');
+ //LOG_WARN("Item Manager: Missing max-per-slot property for "
+ // "item " << id << " in " << itemReferenceFile << '.');
maxPerSlot = 1;
}
@@ -193,21 +193,24 @@ void ItemManager::reload()
}
// TODO: Clean this up some
- Script *s = 0;
- std::stringstream filename;
- filename << "scripts/items/" << id << ".lua";
-
- if (ResourceManager::exists(filename.str())) // file exists!
+ if (scriptFile != "")
{
- LOG_INFO("Loading item script: " + filename.str());
- s = Script::create("lua");
- s->loadFile(filename.str());
+ std::stringstream filename;
+ filename << "scripts/items/" << scriptFile;
+ if (ResourceManager::exists(filename.str())) // file exists!
+ {
+ LOG_INFO("Loading item script: " << filename.str());
+ Script *s = Script::create("lua");
+ s->loadFile(filename.str());
+ item->setScript(s);
+ } else {
+ LOG_WARN("Could not find script file \"" << filename.str() << "\" for item #"<<id);
+ }
}
item->setWeight(weight);
item->setCost(value);
item->setMaxPerSlot(maxPerSlot);
- item->setScript(s);
item->setModifiers(modifiers);
item->setSpriteID(sprite ? sprite : id);
++nbItems;
@@ -250,7 +253,7 @@ void ItemManager::reload()
LOG_DEBUG("Item: ID: " << id << ", itemType: " << itemType
<< ", weight: " << weight << ", value: " << value <<
- ", scriptName: " << scriptName << ", maxPerSlot: " << maxPerSlot << ".");
+ ", script: " << scriptFile << ", maxPerSlot: " << maxPerSlot << ".");
}
LOG_INFO("Loaded " << nbItems << " items from "
diff --git a/src/game-server/spawnarea.cpp b/src/game-server/spawnarea.cpp
index db7a01d6..fc493848 100644
--- a/src/game-server/spawnarea.cpp
+++ b/src/game-server/spawnarea.cpp
@@ -85,7 +85,7 @@ void SpawnArea::update()
if (being->getModifiedAttribute(BASE_ATTR_HP) <= 0)
{
- LOG_WARN("Refusing to spawn dead monster " << mSpecy->getType());
+ //LOG_WARN("Refusing to spawn dead monster " << mSpecy->getType());
delete being;
being = 0;
}
diff --git a/src/net/netcomputer.cpp b/src/net/netcomputer.cpp
index 2ce30c02..35b947ae 100644
--- a/src/net/netcomputer.cpp
+++ b/src/net/netcomputer.cpp
@@ -37,14 +37,12 @@ NetComputer::NetComputer(ENetPeer *peer):
{
}
-bool
-NetComputer::isConnected()
+bool NetComputer::isConnected()
{
return (mPeer->state == ENET_PEER_STATE_CONNECTED);
}
-void
-NetComputer::disconnect(const MessageOut &msg)
+void NetComputer::disconnect(const MessageOut &msg)
{
if (isConnected())
{
@@ -61,9 +59,8 @@ NetComputer::disconnect(const MessageOut &msg)
}
}
-void
-NetComputer::send(const MessageOut &msg, bool reliable,
- unsigned int channel)
+void NetComputer::send(const MessageOut &msg, bool reliable,
+ unsigned int channel)
{
LOG_DEBUG("Sending message " << msg << " to " << *this);
@@ -84,8 +81,7 @@ NetComputer::send(const MessageOut &msg, bool reliable,
}
}
-std::ostream&
-operator <<(std::ostream &os, const NetComputer &comp)
+std::ostream &operator <<(std::ostream &os, const NetComputer &comp)
{
// address.host contains the ip-address in network-byte-order
if (utils::processor::isLittleEndian)
@@ -104,7 +100,7 @@ operator <<(std::ostream &os, const NetComputer &comp)
return os;
}
-int NetComputer::getIP()
+int NetComputer::getIP() const
{
return mPeer->address.host;
}
diff --git a/src/net/netcomputer.hpp b/src/net/netcomputer.hpp
index 2c4d706a..10ffe5ae 100644
--- a/src/net/netcomputer.hpp
+++ b/src/net/netcomputer.hpp
@@ -48,8 +48,7 @@ class NetComputer
/**
* Returns <code>true</code> if this computer is connected.
*/
- bool
- isConnected();
+ bool isConnected();
/**
* Disconnects the computer from the server, after sending a message.
@@ -58,8 +57,7 @@ class NetComputer
* NetComputer does not know which handler is sending it
* (could have been chat/game/account)
*/
- void
- disconnect(const MessageOut &msg);
+ void disconnect(const MessageOut &msg);
/**
* Queues a message for sending to a client.
@@ -77,14 +75,13 @@ class NetComputer
* @param channel The channel number of which the packet should
* be sent.
*/
- void
- send(const MessageOut &msg, bool reliable = true,
- unsigned int channel = 0);
+ void send(const MessageOut &msg, bool reliable = true,
+ unsigned int channel = 0);
/**
* Returns IP address of computer in 32bit int form
*/
- int getIP();
+ int getIP() const;
private:
ENetPeer *mPeer; /**< Client peer */
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index e2be2d3f..b9f30f4e 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,190 +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;
-};
-
-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);
@@ -255,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);
@@ -284,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))
{
@@ -315,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);
@@ -337,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)
@@ -354,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)
@@ -370,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);
@@ -413,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)
@@ -479,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)
@@ -508,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);
@@ -551,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) )
{
@@ -569,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))
{
@@ -592,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) )
{
@@ -619,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);
@@ -639,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);
@@ -668,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);
@@ -686,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);
@@ -700,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);
@@ -715,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))
{
@@ -747,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;
}
@@ -756,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);
@@ -821,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);
@@ -840,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) ||
@@ -890,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) )
{
@@ -920,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);
@@ -958,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))
{
@@ -982,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)
{
@@ -1008,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) ||
@@ -1035,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)
@@ -1064,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)
@@ -1089,10 +879,26 @@ static int LuaChr_GiveExp(lua_State *s)
/**
+ * Returns the rights level of a character.
+ * tmw.chr_get_rights (being)
+ */
+static int chr_get_rights(lua_State *s)
+{
+ Character *c = getCharacter(s, 1);
+ if (!c)
+ {
+ raiseScriptError(s, "chr_get_rights called for nonexistent character.");
+ return 0;
+ }
+ lua_pushinteger(s, c->getAccountLevel());
+ return 1;
+}
+
+/**
* 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);
@@ -1107,7 +913,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;
@@ -1150,6 +956,18 @@ static int LuaTest_Tableget(lua_State *s)
return 4;
}
+/**
+ * Returns the ID of the current map
+ */
+static int get_map_id(lua_State *s)
+{
+ lua_pushlightuserdata(s, (void *)&registryKey);
+ lua_gettable(s, LUA_REGISTRYINDEX);
+ Script *t = static_cast<Script *>(lua_touserdata(s, -1));
+ int id = t->getMap()->getID();
+ lua_pushinteger(s, id);
+ return 1;
+}
LuaScript::LuaScript():
nbArgs(-1)
@@ -1159,37 +977,39 @@ 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 },
+ { "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 },
+ { "chr_get_rights", &chr_get_rights },
+ { "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);
@@ -1203,99 +1023,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;
-}
-
-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("Failure while calling Lua function: error=" << res
- << ", type=" << lua_typename(mState, lua_type(mState, 1))
- << ", message=" << (s ? s : ""));
- lua_pop(mState, 1);
- return 0;
- }
- res = lua_tointeger(mState, 1);
- lua_pop(mState, 1);
- return res;
-}
-
-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
diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp
index ea1721f9..a20efb5c 100644
--- a/src/scripting/script.cpp
+++ b/src/scripting/script.cpp
@@ -69,14 +69,18 @@ void Script::update()
execute();
}
-void Script::loadFile(std::string const &name)
+bool Script::loadFile(std::string const &name)
{
int size;
char *buffer = ResourceManager::loadFile(name, size);
if (buffer)
{
+ mScriptFile = name;
load(buffer);
free(buffer);
+ return true;
+ } else {
+ return false;
}
}
diff --git a/src/scripting/script.hpp b/src/scripting/script.hpp
index fad6ad95..c87bf182 100644
--- a/src/scripting/script.hpp
+++ b/src/scripting/script.hpp
@@ -68,7 +68,7 @@ class Script
* Loads a text file into script context and executes its global
* statements.
*/
- virtual void loadFile(std::string const &);
+ virtual bool loadFile(std::string const &);
/**
* Loads a chunk of text and considers it as an NPC handler. This
@@ -129,6 +129,9 @@ class Script
virtual void processDeathEvent(Being* thing) = 0;
+ protected:
+ std::string mScriptFile;
+
private:
MapComposite *mMap;
EventListener mEventListener; /**< Tracking of being deaths. */