diff options
author | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-08-15 06:35:03 +0000 |
---|---|---|
committer | Guillaume Melquiond <guillaume.melquiond@gmail.com> | 2007-08-15 06:35:03 +0000 |
commit | 99548fb47fee447b5f22d5338501ac574086c4fd (patch) | |
tree | fcef60aed6d7d0f04437249815af36c25461c5dd | |
parent | 2fa455ff7870dc09d75bb89a897c7c1d26eb9020 (diff) | |
download | manaserv-99548fb47fee447b5f22d5338501ac574086c4fd.tar.gz manaserv-99548fb47fee447b5f22d5338501ac574086c4fd.tar.xz manaserv-99548fb47fee447b5f22d5338501ac574086c4fd.zip |
Added helper functions for loading files and NPCs as scripts. Put Lua helpers into a separate library automatically loaded into new contexts.
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | data/scripts/libtmw.lua | 111 | ||||
-rw-r--r-- | data/test.lua | 112 | ||||
-rw-r--r-- | src/game-server/testing.cpp | 39 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 1 | ||||
-rw-r--r-- | src/scripting/script.cpp | 25 | ||||
-rw-r--r-- | src/scripting/script.hpp | 16 |
7 files changed, 183 insertions, 129 deletions
@@ -1,3 +1,11 @@ +2007-08-15 Guillaume Melquiond <guillaume.melquiond@gmail.com> + + * src/scripting/script.cpp, src/scripting/script.hpp: Added helper + functions for loading files and NPCs as scripts. + * src/scripting/lua.cpp, data/scripts/libtmw.lua: Put the Lua helpers + into a separate library automatically loaded into new contexts. + * src/game-server/testing.cpp, data/test.lua: Updated testing files. + 2007-08-14 Guillaume Melquiond <guillaume.melquiond@gmail.com> * src/serialize/characterdata.hpp, src/common/inventorydata.hpp, diff --git a/data/scripts/libtmw.lua b/data/scripts/libtmw.lua new file mode 100644 index 0000000..c4a14b6 --- /dev/null +++ b/data/scripts/libtmw.lua @@ -0,0 +1,111 @@ +------------------ +-- Support code -- +------------------ + +function create_npc(id, x, y, handler) + local npc = tmw.obj_create_npc(id, x, y) + npcs[npc] = handler +end + +function do_message(npc, ch, msg) + tmw.msg_npc_message(npc, ch, msg) + coroutine.yield(1) +end + +function do_choice(npc, ch, ...) + tmw.msg_npc_choice(npc, ch, ...) + return coroutine.yield(2) +end + +-- Called whenever a player starts talking to an NPC. +-- Creates a coroutine based on the register NPC handler. +function npc_start(npc, ch) + local h = npcs[npc] + if not h then return end + local co = coroutine.create(h) + local b, v = coroutine.resume(co, npc, ch) + if b and v then + states[ch] = {npc, co, v, 5} + if not timer then + timer = 600 + end + end +end + +-- Called whenever a player keeps talking to an NPC. +-- Checks that the NPC expects it, and resumes the respective coroutine. +function npc_next(npc, ch) + local w = states[ch] + if w and w[1] == npc and w[3] == 1 then + local b, v = coroutine.resume(w[2]) + if b and v then + w[3] = v + w[4] = 5 + else + states[ch] = nil + end + end +end + +-- Called whenever a player selects a particular reply. +-- Checks that the NPC expects it, and resumes the respective coroutine. +function npc_choose(npc, ch, u) + local w = states[ch] + if w and w[1] == npc and w[3] == 2 then + local b, v = coroutine.resume(w[2], u) + if b and v then + w[3] = v + w[4] = 5 + else + states[ch] = nil + end + end +end + +function npc_update(npc) +end + +function update() + -- Run every minute only, in order not to overload the server. + if not timer then return end + timer = timer - 10 + if timer ~= 0 then return end + -- Free connections that have been inactive for 3-4 minutes. + for k, w in pairs(states) do + local t = w[4] - 1 + if t == 0 then + states[k] = nil + else + w[4] = t + end + end + -- Restart timer if there are still some pending states. + if next(states) then + timer = 600 + else + timer = nil + end +end + +function atinit(f) + init_fun[#init_fun + 1] = f +end + +function create_npc_delayed(id, x, y) + -- Bind the name to a local variable first, as it will be reused. + local h = npc_handler + atinit(function() create_npc(id, x, y, h) end) + npc_handler = nil +end + +function initialize() + for i,f in ipairs(init_fun) do + f() + end + init_fun = nil +end + +npcs = {} +states = {} +init_fun = {} + diff --git a/data/test.lua b/data/test.lua index f9ffb8f..28dbf0e 100644 --- a/data/test.lua +++ b/data/test.lua @@ -1,107 +1,11 @@ ------------------- --- Support code -- ------------------- - --- NOTE: Could be put into a separate library - -function create_npc(id, x, y, handler) - local npc = tmw.obj_create_npc(id, x, y) - npcs[npc] = handler -end - -function do_message(npc, ch, msg) - tmw.msg_npc_message(npc, ch, msg) - coroutine.yield(1) -end - -function do_choice(npc, ch, ...) - tmw.msg_npc_choice(npc, ch, ...) - return coroutine.yield(2) -end - --- Called whenever a player starts talking to an NPC. --- Creates a coroutine based on the register NPC handler. -function npc_start(npc, ch) - local h = npcs[npc] - if not h then return end - local co = coroutine.create(h) - local b, v = coroutine.resume(co, npc, ch) - if b and v then - states[ch] = {npc, co, v, 5} - if not timer then - timer = 600 - end - end -end - --- Called whenever a player keeps talking to an NPC. --- Checks that the NPC expects it, and resumes the respective coroutine. -function npc_next(npc, ch) - local w = states[ch] - if w and w[1] == npc and w[3] == 1 then - local b, v = coroutine.resume(w[2]) - if b and v then - w[3] = v - w[4] = 5 - else - states[ch] = nil - end - end -end - --- Called whenever a player selects a particular reply. --- Checks that the NPC expects it, and resumes the respective coroutine. -function npc_choose(npc, ch, u) - local w = states[ch] - if w and w[1] == npc and w[3] == 2 then - local b, v = coroutine.resume(w[2], u) - if b and v then - w[3] = v - w[4] = 5 - else - states[ch] = nil - end - end -end - -function npc_update(npc) -end - -function update() - -- Run every minute only, in order not to overload the server. - if not timer then return end - timer = timer - 10 - if timer ~= 0 then return end - -- Free connections that have been inactive for 3-4 minutes. - for k, w in pairs(states) do - local t = w[4] - 1 - if t == 0 then - states[k] = nil - else - w[4] = t - end - end - -- Restart timer if there are still some pending states. - if next(states) then - timer = 600 - else - timer = nil - end -end - -npcs = {} -states = {} - -------------- -- Map code -- -------------- -function initialize() +atinit(function() create_npc(110, 50 * 32 + 16, 19 * 32 + 16, my_npc1) - create_npc(107, 53 * 32 + 16, 21 * 32 + 16, my_npc2) - create_npc(107, 53 * 32 + 16, 23 * 32 + 16, my_npc3) create_npc(108, 51 * 32 + 16, 25 * 32 + 16, my_npc4) -end +end) function my_npc1(npc, ch) do_message(npc, ch, "Hello! I am the testing NPC") @@ -128,18 +32,6 @@ function my_npc1(npc, ch) end end -npc2_times = 1 - -function my_npc2(npc, ch) - do_message(npc, ch, "You know what?") - do_message(npc, ch, string.format("I have already asked this question %d times today.", npc2_times)) - npc2_times = npc2_times + 1 -end - -function my_npc3(npc, ch) - do_message(npc, ch, "Don't you think the guy behind me is my evil twin?") -end - function my_npc4(npc, ch) do_message(npc, ch, "Where do you want to go?") local v = do_choice(npc, ch, "Map 1", "Map 3") diff --git a/src/game-server/testing.cpp b/src/game-server/testing.cpp index f32ca68..4f57631 100644 --- a/src/game-server/testing.cpp +++ b/src/game-server/testing.cpp @@ -4,15 +4,11 @@ #include <cassert> -#include "defines.h" -#include "resourcemanager.h" #include "game-server/gamehandler.hpp" #include "game-server/item.hpp" #include "game-server/itemmanager.hpp" #include "game-server/mapcomposite.hpp" -#include "game-server/mapmanager.hpp" #include "game-server/state.hpp" -#include "net/messageout.hpp" #include "scripting/script.hpp" static void dropItem(MapComposite *map, int x, int y, int type) @@ -26,29 +22,40 @@ static void dropItem(MapComposite *map, int x, int y, int type) GameState::insert(i); } +static char const *npc1 = + "npc2_times = 1\n" + "function npc_handler(npc, ch)\n" + " do_message(npc, ch, \"You know what?\")\n" + " do_message(npc, ch, string.format(\"I have already asked this question %d times today.\", npc2_times))\n" + " npc2_times = npc2_times + 1\n" + "end\n"; + +static char const *npc2 = + "function npc_handler(npc, ch)\n" + " do_message(npc, ch, \"Don't you think the guy behind me is my evil twin?\")\n" + "end\n"; + void testingMap(MapComposite *map) { switch (map->getID()) { case 1: { - // Drop some items + // Drop some items. dropItem(map, 58 * 32 + 16, 20 * 32 + 16, 508); dropItem(map, 58 * 32 + 16, 21 * 32 + 16, 524); - // Associate a script - Script *s = Script::create("lua"); - if (s) + // Create a Lua context. + if (Script *s = Script::create("lua")) { - ResourceManager *resman = ResourceManager::getInstance(); - int fileSize; - char *buffer = (char *)resman->loadFile("test.lua", fileSize); - if (buffer) - { - s->load(buffer); - free(buffer); - } + // Load a script. + s->loadFile("test.lua"); + + // Create two NPCs. + s->loadNPC(107, 53 * 32 + 16, 21 * 32 + 16, npc1); + s->loadNPC(107, 53 * 32 + 16, 23 * 32 + 16, npc2); + // Associate the script context to the map. map->setScript(s); s->setMap(map); s->prepare("initialize"); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 0fc3283..34415a2 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -356,6 +356,7 @@ LuaScript::LuaScript(): lua_settable(mState, LUA_REGISTRYINDEX); lua_settop(mState, 0); + loadFile("scripts/libtmw.lua"); } LuaScript::~LuaScript() diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp index 12aa0d1..3e19305 100644 --- a/src/scripting/script.cpp +++ b/src/scripting/script.cpp @@ -23,9 +23,11 @@ #include <map> -#include "utils/logger.h" #include "scripting/script.hpp" +#include "resourcemanager.h" +#include "utils/logger.h" + typedef std::map< std::string, Script::Factory > Engines; static Engines *engines = NULL; @@ -60,3 +62,24 @@ void Script::update() execute(); } +void Script::loadFile(std::string const &name) +{ + ResourceManager *resman = ResourceManager::getInstance(); + int size; + char *buffer = (char *)resman->loadFile(name, size); + if (buffer) + { + load(buffer); + free(buffer); + } +} + +void Script::loadNPC(int id, int x, int y, char const *prog) +{ + load(prog); + prepare("create_npc_delayed"); + push(id); + push(x); + push(y); + execute(); +} diff --git a/src/scripting/script.hpp b/src/scripting/script.hpp index 136ae9f..65fc004 100644 --- a/src/scripting/script.hpp +++ b/src/scripting/script.hpp @@ -53,12 +53,24 @@ class Script virtual ~Script() {} /** - * Loads a chunk of text into the script context and executes - * its global statements. + * Loads a chunk of text into script context and executes its global + * statements. */ virtual void load(char const *) = 0; /** + * Loads a text file into script context and executes its global + * statements. + */ + virtual void loadFile(std::string const &); + + /** + * Loads a chunk of text and considers it as an NPC handler. This + * handler will later be used to create the given NPC. + */ + virtual void loadNPC(int id, int x, int y, char const *); + + /** * Called every tick for the script to manage its data. * Calls the "update" function of the script by default. */ |