diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/account-server/accounthandler.cpp | 2 | ||||
-rw-r--r-- | src/game-server/character.cpp | 7 | ||||
-rw-r--r-- | src/game-server/commandhandler.cpp | 96 | ||||
-rw-r--r-- | src/game-server/item.cpp | 4 | ||||
-rw-r--r-- | src/game-server/itemmanager.cpp | 29 | ||||
-rw-r--r-- | src/game-server/spawnarea.cpp | 2 | ||||
-rw-r--r-- | src/net/netcomputer.cpp | 16 | ||||
-rw-r--r-- | src/net/netcomputer.hpp | 13 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 468 | ||||
-rw-r--r-- | src/scripting/luascript.cpp | 150 | ||||
-rw-r--r-- | src/scripting/luascript.hpp | 89 | ||||
-rw-r--r-- | src/scripting/luautil.cpp | 91 | ||||
-rw-r--r-- | src/scripting/luautil.hpp | 124 | ||||
-rw-r--r-- | src/scripting/script.cpp | 6 | ||||
-rw-r--r-- | src/scripting/script.hpp | 5 |
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 *)®istryKey); 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 *)®istryKey); 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 *)®istryKey); 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 *)®istryKey); 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 *)®istryKey); + 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", ¬e_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. */ |