summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-15 06:35:03 +0000
committerGuillaume Melquiond <guillaume.melquiond@gmail.com>2007-08-15 06:35:03 +0000
commit99548fb47fee447b5f22d5338501ac574086c4fd (patch)
treefcef60aed6d7d0f04437249815af36c25461c5dd
parent2fa455ff7870dc09d75bb89a897c7c1d26eb9020 (diff)
downloadmanaserv-99548fb47fee447b5f22d5338501ac574086c4fd.tar.gz
manaserv-99548fb47fee447b5f22d5338501ac574086c4fd.tar.bz2
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--ChangeLog8
-rw-r--r--data/scripts/libtmw.lua111
-rw-r--r--data/test.lua112
-rw-r--r--src/game-server/testing.cpp39
-rw-r--r--src/scripting/lua.cpp1
-rw-r--r--src/scripting/script.cpp25
-rw-r--r--src/scripting/script.hpp16
7 files changed, 183 insertions, 129 deletions
diff --git a/ChangeLog b/ChangeLog
index c9a03ffa..e499a94b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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 00000000..c4a14b6f
--- /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 f9ffb8fe..28dbf0e8 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 f32ca68c..4f57631a 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 0fc3283d..34415a27 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 12aa0d18..3e19305d 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 136ae9ff..65fc0044 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.
*/