summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/manaserv.xml30
-rw-r--r--example/clientdata/mana-skills.xml3
-rw-r--r--example/clientdata/maps/desert.tmx18
-rw-r--r--example/clientdata/monsters.xml3
-rw-r--r--example/clientdata/tilesets/tmw_desert_spacing.pngbin0 -> 37830 bytes
-rw-r--r--example/serverdata/maps.xml4
-rw-r--r--example/serverdata/permissions.xml42
-rw-r--r--example/serverdata/scripts/bomtest.lua7
-rw-r--r--scripts/lua/libmana-constants.lua103
-rw-r--r--scripts/lua/libmana.lua448
-rw-r--r--scripts/lua/npclib.lua103
-rw-r--r--src/common/resourcemanager.cpp3
-rw-r--r--src/scripting/lua.cpp3
13 files changed, 752 insertions, 15 deletions
diff --git a/docs/manaserv.xml b/docs/manaserv.xml
index f487432..909400a 100644
--- a/docs/manaserv.xml
+++ b/docs/manaserv.xml
@@ -1,5 +1,5 @@
<?xml version="1.0"?>
-<!--
+<!--
An example configuration file for ~/.manaserv.xml
Documentation: http://doc.manasource.org/manaserv.xml
@@ -10,7 +10,7 @@
<configuration>
<!-- Database configuration ***************************************************
- Uncomment one of the following parts according to the database backend you
+ Uncomment one of the following parts according to the database backend you
would like to use.
-->
@@ -38,7 +38,7 @@
optional, default="mana"
-->
<!--
-<option name="mysql_hostname" value="localhost"/>
+<option name="mysql_hostname" value="localhost"/>
<option name="mysql_port" value="3306"/>
<option name="mysql_database" value="mana"/>
<option name="mysql_username" value="mana"/>
@@ -46,8 +46,8 @@
-->
-<!--
- PostgreSQL specific configuration.
+<!--
+ PostgreSQL specific configuration.
TODO!
-->
@@ -84,23 +84,25 @@
-->
<option name="net_gameServerAddress" value="localhost"/>
<option name="net_gameServerPort" value="9604"/>
-
- <!--Paths to data files-->
+
+ <!-- Paths to data files -->
+ <option name="serverPath" value="." />
<option name="clientDataPath" value="example/clientdata" />
<option name="serverDataPath" value="example/serverdata" />
-
- <!-- Gameplay-related config option-->
- <option name="visualRange" value="448"/>
+
+ <!-- Gameplay-related config option -->
+ <option name="visualRange" value="448"/>
<option name="respawnMap" value="4"/>
<option name="respawnX" value="1000"/>
<option name="respawnY" value="1000"/>
<option name="defaultPvp" value="free" />
<option name="floorItemDecayTime" value="10" />
<option name="hpRegenBreakAfterHit" value="50" />
-
- <!-- Network-related config options-->
+
+ <!-- Network-related config options -->
<option name="net_maxClients" value="1000"/>
- <!-- Account-creation-related config options-->
+
+ <!-- Account-creation-related config options -->
<option name="account_allowRegister" value="1" />
<option name="account_denyRegisterReason" value="The server administrator has disabled automatic registration!" />
<option name="account_minEmailLength" value="7" />
@@ -109,6 +111,7 @@
<option name="account_maxNameLength" value="16" />
<option name="account_minPasswordLength" value="6" />
<option name="account_maxPasswordLength" value="25" />
+
<!-- Character-creation-related config options -->
<option name="char_numHairStyles" value="17" />
<option name="char_numHairColors" value="9" />
@@ -117,6 +120,7 @@
<option name="char_maxNameLength" value="25" />
<option name="char_maxCharacters" value="3" />
<option name="char_startingPoints" value="60" />
+
<!-- Chat-related config options -->
<option name="chat_maxChannelNameLength" value="15" />
<!-- I noticed the following configuration-like enumeration values which are never checked:
diff --git a/example/clientdata/mana-skills.xml b/example/clientdata/mana-skills.xml
new file mode 100644
index 0000000..118450c
--- /dev/null
+++ b/example/clientdata/mana-skills.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<skills>
+</skills>
diff --git a/example/clientdata/maps/desert.tmx b/example/clientdata/maps/desert.tmx
new file mode 100644
index 0000000..f35f548
--- /dev/null
+++ b/example/clientdata/maps/desert.tmx
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="orthogonal" width="40" height="40" tilewidth="32" tileheight="32">
+ <tileset firstgid="1" name="Desert" tilewidth="32" tileheight="32" spacing="1" margin="1">
+ <image source="../tilesets/tmw_desert_spacing.png"/>
+ </tileset>
+ <layer name="Ground" width="40" height="40">
+ <data encoding="base64" compression="gzip">
+ H4sIAAAAAAAAA+2Y2QrCMBBFo31wA+sCrlirdd/q/3+dIzZUhtAmMRlH6cPBBlJyvDO2g5EQIvJIFwiBnudzbLgp/JYMvH4lv2dWI2AMTBj4qKgBdSBA3j7OmgIzA+ZAC2gDHYIsVsDagMSj36HAbwOcgO0X/YrySzTzpPDbMfS7Iy/sdxGv/r8S++Gew+uyvHBfuvBT/Q4OKD95XeaHc3WV3x6tpY9pfr7riz0xx6x+upwd+DUymiJ/FxURaO6TLD70C0U+X8jvWkRHc5/qPhu/scjniz4wKGGouU91n8/eoyYW6jmHk2dM6GMzm1F43bJPnWfn+/sncXS+Ljp+T6d7tpfSL2Xoh/uam59Nfd/nCyq/1MAPZ8ktP1WtOftR5mczm1H6/QsxA4dfAWfF7b/BqsYVFZ/xABSXR5cAGQAA
+ </data>
+ </layer>
+ <objectgroup name="Objects" width="40" height="40">
+ <object name="Main script" type="SCRIPT" x="16" y="25" width="167" height="10">
+ <properties>
+ <property name="FILENAME" value="scripts/bomtest.lua"/>
+ </properties>
+ </object>
+ </objectgroup>
+</map>
diff --git a/example/clientdata/monsters.xml b/example/clientdata/monsters.xml
new file mode 100644
index 0000000..21ddc80
--- /dev/null
+++ b/example/clientdata/monsters.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<monsters>
+</monsters>
diff --git a/example/clientdata/tilesets/tmw_desert_spacing.png b/example/clientdata/tilesets/tmw_desert_spacing.png
new file mode 100644
index 0000000..4e9995c
--- /dev/null
+++ b/example/clientdata/tilesets/tmw_desert_spacing.png
Binary files differ
diff --git a/example/serverdata/maps.xml b/example/serverdata/maps.xml
new file mode 100644
index 0000000..9467385
--- /dev/null
+++ b/example/serverdata/maps.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<maps>
+ <map id="1" name="desert" />
+</maps>
diff --git a/example/serverdata/permissions.xml b/example/serverdata/permissions.xml
new file mode 100644
index 0000000..f2eeae3
--- /dev/null
+++ b/example/serverdata/permissions.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<permissions>
+ <class level="1">
+ <alias>player</alias>
+ <allow>@help</allow>
+ <allow>@where</allow>
+ <allow>@rights</allow>
+ <allow>@report</allow>
+ </class>
+ <class level="2">
+ <alias>tester</alias>
+ <allow>@warp</allow>
+ </class>
+ <class level="3">
+ <alias>dev</alias>
+ <allow>@item</allow>
+ <allow>@drop</allow>
+ <allow>@money</allow>
+ <allow>@spawn</allow>
+ <allow>@attribute</allow>
+ </class>
+ <class level="4">
+ <alias>gm</alias>
+ <allow>@goto</allow>
+ <allow>@recall</allow>
+ <allow>@ban</allow>
+ <allow>@history</allow>
+ </class>
+ <class level="5">
+ </class>
+ <class level="6">
+ </class>
+ <class level="7">
+ </class>
+ <class level="8">
+ <alias>admin</alias>
+ <allow>@reload</allow>
+ <allow>@givepermission</allow>
+ <allow>@takepermission</allow>
+ <allow>@announce</allow>
+ </class>
+</permissions>
diff --git a/example/serverdata/scripts/bomtest.lua b/example/serverdata/scripts/bomtest.lua
new file mode 100644
index 0000000..d4b0212
--- /dev/null
+++ b/example/serverdata/scripts/bomtest.lua
@@ -0,0 +1,7 @@
+-------------------------------------------------------------------------------
+-- This file verifies that an UTF-8 BOM is correctly handled by manaserv ------
+
+function testUtf8Bom()
+ -- Dummy function, the test is really about whether the hidden BOM at the
+ -- start of this file is skipped before tripping the Lua parser.
+end
diff --git a/scripts/lua/libmana-constants.lua b/scripts/lua/libmana-constants.lua
new file mode 100644
index 0000000..227b93f
--- /dev/null
+++ b/scripts/lua/libmana-constants.lua
@@ -0,0 +1,103 @@
+-------------------------------------------------------------
+-- Mana Support Library Constants --
+-- --
+-- Some useful numeric values for use by other scripts. --
+-- --
+----------------------------------------------------------------------------------
+-- Copyright 2008 The Mana World Development Team --
+-- --
+-- This file is part of The Mana Server. --
+-- --
+-- The Mana Server 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. --
+----------------------------------------------------------------------------------
+
+DAMAGE_PHYSICAL = 0
+DAMAGE_MAGICAL = 1
+DAMAGE_OTHER = 2
+
+ELEMENT_NEUTRAL = 0
+ELEMENT_FIRE = 1
+ELEMENT_WATER = 2
+ELEMENT_EARTH = 3
+ELEMENT_AIR = 4
+ELEMENT_LIGHTNING = 5
+ELEMENT_METAL = 6
+ELEMENT_WOOD = 7
+ELEMENT_ICE = 8
+
+ATTR_PHY_ATK_MIN = 0
+ATTR_PHY_ATK_DELTA = 1
+ATTR_MAG_ATK = 2
+ATTR_PHY_RES = 3
+ATTR_MAG_RES = 4
+ATTR_EVADE = 5
+ATTR_HIT = 6
+ATTR_HP = 7
+ATTR_HP_REGEN = 8
+ELEM_NEUTRAL = 9
+ELEM_FIRE = 10
+ELEM_WATER = 11
+ELEM_EARTH = 12
+ELEM_AIR = 13
+ELEM_SACRED = 14
+ELEM_DEATH = 15
+ATTR_STRENGTH = 16
+ATTR_AGILITY = 17
+ATTR_DEXTERITY = 18
+ATTR_VITALITY = 19
+ATTR_INTELLIGENCE = 20
+ATTR_WILLPOWER = 21
+SKILL_WEAPON_NONE = 100
+SKILL_WEAPON_KNIFE = 101
+SKILL_WEAPON_SWORD = 102
+SKILL_WEAPON_POLEARM = 103
+SKILL_WEAPON_STAFF = 104
+SKILL_WEAPON_WHIP = 105
+SKILL_WEAPON_BOW = 106
+SKILL_WEAPON_SHOOTING = 107
+SKILL_WEAPON_MACE = 108
+SKILL_WEAPON_AXE = 109
+SKILL_WEAPON_THROWN = 110
+
+TILESIZE = 32
+HOURS = 3600
+MINUTES = 60
+
+TYPE_ITEM = 0;
+TYPE_ACTOR = 1;
+TYPE_NPC = 2;
+TYPE_MONSTER = 3;
+TYPE_CHARACTER = 4;
+TYPE_EFFECT = 5;
+TYPE_OTHER = 6;
+
+ACTION_STAND = 0;
+ACTION_WALK = 1;
+ACTION_ATTACK = 2;
+ACTION_SIT = 3;
+ACTION_DEAD = 4;
+ACTION_HURT = 5;
+
+DIRECTION_DEFAULT = 0;
+DIRECTION_UP = 1;
+DIRECTION_DOWN = 2;
+DIRECTION_LEFT = 3;
+DIRECTION_RIGHT = 4;
+DIRECTION_INVALID = 5;
+
+EMOTE_DISGUST = 10000;
+EMOTE_SURPRISE = 10001;
+EMOTE_HAPPY = 10002;
+EMOTE_SAD = 10003;
+EMOTE_EVIL = 10004;
+EMOTE_WINK = 10005;
+EMOTE_ANGEL = 10006;
+EMOTE_BLUSH = 10007;
+EMOTE_TONGUE = 10008;
+EMOTE_GRIN = 10009;
+EMOTE_UPSET = 10010;
+EMOTE_PERTURBED = 10011;
+EMOTE_SPEECH = 10012;
+EMOTE_BLAH = 10013;
diff --git a/scripts/lua/libmana.lua b/scripts/lua/libmana.lua
new file mode 100644
index 0000000..8ea5168
--- /dev/null
+++ b/scripts/lua/libmana.lua
@@ -0,0 +1,448 @@
+-------------------------------------------------------------
+-- Mana Support Library --
+-- --
+-- Functions which are called by the game engine and --
+-- helper functions useful for writing other scripts. --
+-- --
+----------------------------------------------------------------------------------
+-- Copyright 2008 The Mana World Development Team --
+-- --
+-- This file is part of The Mana Server. --
+-- --
+-- The Mana Server 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. --
+----------------------------------------------------------------------------------
+
+require "scripts/lua/libmana-constants"
+
+
+-- Table that associates to each NPC pointer the handler function that is
+-- called when a player starts talking to an NPC.
+local npc_talk_functs = {}
+local npc_update_functs = {}
+
+-- Table that associates to each Character pointer its state with respect to
+-- NPCs (only one at a time). A state is an array with four fields:
+-- . 1: pointer to the NPC the player is currently talking to.
+-- . 2: coroutine running the NPC handler.
+-- . 3: next event the NPC expects from the server.
+-- (1 = npc_next, 2 = npc_choose, 3 = quest_reply, 4 = 1+3)
+-- . 4: countdown (in minutes) before the state is deleted.
+-- . 5: name of the expected quest variable. (optional)
+local states = {}
+
+-- Array containing the function registered by atinit.
+local init_fun = {}
+
+-- Tick timer used during update to clean obsolete states.
+local timer
+
+-- Creates an NPC and associates the given handler.
+-- Note: Cannot be called until map initialization has started.
+function create_npc(name, id, x, y, talkfunct, updatefunct)
+ local npc = mana.npc_create(name, id, x, y)
+ if talkfunct then npc_talk_functs[npc] = talkfunct end
+ if updatefunct then npc_update_functs[npc] = updatefunct end
+ return npc
+end
+
+-- Waits for the player to acknowledge the previous message, if any.
+function do_wait()
+ coroutine.yield(0)
+end
+
+-- Sends an npc message to a player.
+-- Note: Does not wait for the player to acknowledge the message.
+function do_message(npc, ch, msg)
+ -- Wait for the arrival of a pending acknowledgment, if any.
+ coroutine.yield(0)
+ mana.npc_message(npc, ch, msg)
+ -- An acknowledgment is pending, but do not wait for its arrival.
+ coroutine.yield(1)
+end
+
+-- Sends an NPC question to a player and waits for its answer.
+function do_choice(npc, ch, ...)
+ -- Wait for the arrival of a pending acknowledgment, if any.
+ coroutine.yield(0)
+ mana.npc_choice(npc, ch, ...)
+ -- Wait for player choice.
+ return coroutine.yield(2)
+end
+
+-- Sends an NPC integer ask to a player and waits for its answer.
+function do_ask_integer(npc, ch, min_num, max_num, ...)
+ -- Wait for the arrival of a pending acknowledgment, if any.
+ coroutine.yield(0)
+ mana.npc_ask_integer(npc, ch, min_num, max_num, ...)
+ -- Wait for player answer.
+ return coroutine.yield(2)
+end
+
+-- Sends an NPC string ask to a player and waits for its answer.
+function do_ask_string(npc, ch)
+ -- Wait for the arrival of a pending acknowledgment, if any.
+ coroutine.yield(0)
+ mana.npc_ask_string(npc, ch)
+ -- Wait for player answer.
+ return coroutine.yield(2)
+end
+
+-- Sends an NPC request to send letter to a player and waits for them to
+-- send the letter.
+function do_post(npc, ch)
+ coroutine.yield(0)
+ mana.npc_post(npc, ch)
+ return coroutine.yield(1)
+end
+
+-- Gets the value of a quest variable.
+-- Calling this function while an acknowledment is pending is desirable, so
+-- that lag cannot be perceived by the player.
+function get_quest_var(ch, name)
+ -- Query the server and return immediatly if a value is available.
+ local value = mana.chr_get_quest(ch, name)
+ if value then return value end
+ -- Wait for database reply.
+ return coroutine.yield(3, name)
+end
+
+-- Gets the post for a user.
+function getpost(ch)
+ mana.chr_get_post(ch)
+ return coroutine.yield(3)
+end
+
+-- Processes as much of an NPC handler as possible.
+local function process_npc(w, ...)
+ local co = w[2]
+ local pending = (w[3] == 4)
+ local first = true
+ while true do
+ local b, v, u
+ if first then
+ -- First time, resume with the arguments the coroutine was waiting for.
+ b, v, u = coroutine.resume(co, ...)
+ first = false
+ else
+ -- Otherwise, simply resume.
+ b, v, u = coroutine.resume(co)
+ end
+
+ if not b then print("LUA error: ", v)end
+
+ if not b or not v then
+ -- Either there was an error, or the handler just finished its work.
+ return
+ elseif v == 2 then
+ -- The coroutine needs a user choice from the server, so wait for it.
+ w[3] = 2
+ break
+ elseif v == 3 then
+ -- The coroutine needs the value of a quest variable from the server.
+ w[5] = u
+ if pending then
+ -- The coroutine has also sent a message to the user, so do not
+ -- forget about it, as it would flood the user with new messages.
+ w[3] = 4
+ else
+ w[3] = 3
+ end
+ break
+ elseif pending then
+ -- The coroutine is about to interact with the user. But the previous
+ -- action has not been acknowledged by the user yet, so wait for it.
+ w[3] = 1
+ break
+ elseif v == 1 then
+ -- A message has just been sent. But the coroutine can keep going in case
+ -- there is still some work to do while waiting for user acknowledgment.
+ pending = true
+ end
+ end
+ -- Restore the countdown, as there was some activity.
+ w[4] = 5
+ return true
+end
+
+-- Called by the game whenever a player starts talking to an NPC.
+-- Creates a coroutine based on the registered NPC handler.
+function npc_start(npc, ch)
+ states[ch] = nil
+ local h = npc_talk_functs[npc]
+ if not h then return end
+ local w = { npc, coroutine.create(h) }
+ if process_npc(w, npc, ch) then
+ states[ch] = w
+ if not timer then
+ timer = 600
+ end
+ end
+ -- coroutine.resume(w)
+ -- do_npc_close(npc, ch)
+end
+
+function do_npc_close(npc, ch)
+ mana.npc_end(npc, ch)
+end
+
+-- Called by the game whenever a player keeps talking to an NPC.
+-- Checks that the NPC expects it, and processes the respective coroutine.
+function npc_next(npc, ch)
+ local w = states[ch]
+ if w then
+ local w3 = w[3]
+ if w3 == 4 then
+ w[3] = 3
+ return
+ elseif w3 == 1 and process_npc(w) then
+ return
+ end
+ end
+ states[ch] = nil
+end
+
+-- Called by the game whenever a player selects a particular reply.
+-- Checks that the NPC expects it, and processes the respective coroutine.
+function npc_choose(npc, ch, u)
+ local w = states[ch]
+ if not (w and w[1] == npc and w[3] == 2 and process_npc(w, u)) then
+ states[ch] = nil
+ end
+end
+
+function npc_integer(npc, ch, u)
+ local w = states[ch]
+ if not (w and w[1] == npc and w[3] == 2 and process_npc(w, u)) then
+ states[ch] = nil
+ end
+end
+
+function npc_string(npc, ch, u)
+ local w = states[ch]
+ if not (w and w[1] == npc and w[3] == 2 and process_npc(w, u)) then
+ states[ch] = nil
+ end
+end
+
+-- Called by the game when a player sends a letter.
+function npc_post(npc, ch, sender, letter)
+ local w = states[ch]
+ if not (w and w[1] == npc and w[3] == 1 and process_npc(w, sender, letter)) then
+ states[ch] = nil
+ end
+end
+
+-- Called by the game whenever the value of a quest variable is known.
+-- Checks that the NPC expects it, and processes the respective coroutine.
+-- Note: the check for NPC correctness is missing, but it should never matter.
+function quest_reply(ch, name, value)
+ local w = states[ch]
+ if w then
+ local w3 = w[3]
+ if (w3 == 3 or w3 == 4) and w[5] == name then
+ w[5] = nil
+ if process_npc(w, value) then
+ return
+ end
+ end
+ end
+ states[ch] = nil
+end
+
+function post_reply(ch, sender, letter)
+ local w = states[ch]
+ if w then
+ local w3 = w[3]
+ if (w3 == 3 or w3 == 4) then
+ if process_npc(w, sender, letter) then
+ return
+ end
+ end
+ end
+ states[ch] = nil
+end
+
+-- Called by the game every tick for each NPC.
+function npc_update(npc)
+ local h = npc_update_functs[npc];
+ if h then h(npc) end;
+end
+
+-- Called by the game every tick.
+-- Checks for scheduled function calls
+-- Cleans obsolete connections.
+function update()
+ -- check the scheduler
+ check_schedule()
+
+ -- Run every minute only, in order not to overload the server.
+ if not timer then return end
+ timer = timer - 1
+ 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
+
+-- Registers a function so that is is executed during map initialization.
+function atinit(f)
+ init_fun[#init_fun + 1] = f
+end
+
+-- Called by the game for creating NPCs embedded into maps.
+-- Delays the creation until map initialization is performed.
+-- Note: Assumes that the "npc_handler" global field contains the NPC handler.
+function create_npc_delayed(name, id, x, y)
+ -- Bind the name to a local variable first, as it will be reused.
+ local h = npc_handler
+ atinit(function() create_npc(name, id, x, y, h, nil) end)
+ npc_handler = nil
+end
+
+-- Called during map initialization.
+-- Executes all the functions registered by atinit.
+function initialize()
+ for i,f in ipairs(init_fun) do
+ f()
+ end
+ init_fun = nil
+end
+
+
+-- SCHEDULER
+
+-- Table of scheduled jobs. A job is an array with 3 elements:
+-- 0: the UNIX timestamp when it is executed
+-- 1: the function which is executed
+-- 2: nil when it is a one-time job. Repetition interval is seconds when it is
+-- a repeated job.
+local scheduler_jobs = {}
+
+-- compare function used to sort the scheduler_jobs table.
+-- the jobs which come first are at the end of the table.
+local function job_cmp(job1, job2)
+ return (job1[0] > job2[0])
+end
+
+-- checks for jobs which have to be executed, executes them and reschedules
+-- them when they are repeated jobs.
+function check_schedule()
+ if #scheduler_jobs==0 then return end
+ while os.time() > scheduler_jobs[#scheduler_jobs][0] do
+ -- retreive the job and remove it from the schedule
+ job = scheduler_jobs[#scheduler_jobs]
+ table.remove(scheduler_jobs)
+ -- reschedule the job when it is a repeated job
+ if job[2] then
+ schedule_every(job[2], job[1])
+ end
+ -- execute the job
+ job[1]()
+ end
+end
+
+-- schedules a function call to be executed once in n seconds
+function schedule_in(seconds, funct)
+ local job = {}
+ job[0] = os.time() + seconds
+ job[1] = funct
+ job[2] = nil
+ table.insert(scheduler_jobs, job)
+ table.sort(scheduler_jobs, job_cmp)
+end
+
+-- schedules a function call to be executed at regular intervals of n seconds
+function schedule_every(seconds, funct)
+ local job = {}
+ job[0] = os.time() + seconds
+ job[1] = funct
+ job[2] = seconds
+ table.insert(scheduler_jobs, job)
+ table.sort(scheduler_jobs, job_cmp)
+end
+
+
+-- DEATH NOTIFICATIONS
+local ondeath_functs = {}
+local onremove_functs = {}
+
+-- requests the gameserver to notify the script engine when the being
+-- dies and adds a script function to be executed in this case.
+function on_death(being, funct)
+ if ondeath_functs[being] == nil then
+ ondeath_functs[being] = {}
+ end
+ table.insert(ondeath_functs[being], funct)
+ mana.being_register(being)
+end
+
+-- requests the gameserver to notify the script engine when the being
+-- dies and adds a script function to be executed in this case.
+function on_remove(being, funct)
+ if onremove_functs[being] == nil then
+ onremove_functs[being] = {}
+ end
+ table.insert(onremove_functs[being], funct)
+ mana.being_register(being)
+end
+
+-- called by the engine when a registred being dies.
+function death_notification(being)
+ if type(ondeath_functs[being]) == "table" then
+ for i,funct in pairs(ondeath_functs[being]) do
+ funct()
+ end
+ ondeath_functs[being] = nil
+ end
+end
+
+-- called by the engine when a registred being is removed.
+function remove_notification(being)
+ if type(onremove_functs[being]) == "table" then
+ for i,funct in pairs(onremove_functs[being]) do
+ funct()
+ end
+ onremove_functs[being] = nil
+ ondeath_functs[being] = nil
+ end
+end
+
+
+-- Below are some convenience methods added to the engine API
+
+mana.chr_money_change = function(ch, amount)
+ return mana.chr_inv_change(ch, 0, amount)
+end
+
+mana.chr_money = function(ch)
+ return mana.chr_inv_count(ch, 0)
+end
+
+
+
+function cast(ch, arg)
+ if arg == 1 then
+ mana.being_say(ch, "Kaaame...Haaame... HAAAAAA!")
+ end
+ if arg == 2 then
+ mana.being_say(ch, "HAA-DOKEN!")
+ end
+ if arg == 3 then
+ mana.being_say(ch, "Sonic BOOM")
+ end
+
+end
diff --git a/scripts/lua/npclib.lua b/scripts/lua/npclib.lua
new file mode 100644
index 0000000..9edfcbd
--- /dev/null
+++ b/scripts/lua/npclib.lua
@@ -0,0 +1,103 @@
+----------------------------------------------------------
+-- Library for commonly used NPC scripts --
+-- --
+-- --
+-- Any NPC update function or talk function which could --
+-- be used for NPCs on more than one map should be --
+-- placed here. --
+-- --
+----------------------------------------------------------------------------------
+-- Copyright 2008 The Mana World Development Team --
+-- --
+-- This file is part of The Mana Server. --
+-- --
+-- The Mana Server 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. --
+----------------------------------------------------------------------------------
+
+module("npclib", package.seeall);
+
+
+-- Update function walkaround_small
+-- makes the NPC walk around in a 64x64 pixel square around its start location.
+-- Useful for NPCs which are supposed to stay on a specific spot but
+-- move a bit from time to time.
+
+local wasmall_timer = {}
+local wasmall_startx = {}
+local wasmall_starty = {}
+
+function walkaround_small(npc)
+ if not wasmall_timer[npc] then
+ wasmall_timer[npc] = 1
+ wasmall_startx[npc] = mana.posX(npc)
+ wasmall_starty[npc] = mana.posY(npc)
+ end
+
+ wasmall_timer[npc] = wasmall_timer[npc] + 1
+
+ if wasmall_timer[npc] == 100 then
+ wasmall_timer[npc] = math.random(1, 10)
+ local x = math.random(-32, 32) + wasmall_startx[npc]
+ local y = math.random(-32, 32) + wasmall_starty[npc]
+ mana.being_walk(npc, x, y, 2)
+ end
+end
+
+
+-- Update function walkaround_wide
+-- makes the NPC walk around in a 256x256 pixel square around its start
+-- location. Useful for NPCs which are supposed to be found near a specific
+-- location but not nailed to the floor.
+
+local wawide_timer = {}
+local wawide_startx = {}
+local wawide_starty = {}
+
+function walkaround_wide(npc)
+ if not wawide_timer[npc] then
+ wawide_timer[npc] = 1
+ wawide_startx[npc] = mana.posX(npc)
+ wawide_starty[npc] = mana.posY(npc)
+ end
+
+ wawide_timer[npc] = wawide_timer[npc] + 1
+
+ if wawide_timer[npc] == 50 then
+ wawide_timer[npc] = math.random(1, 10)
+ local x = math.random(-128, 128) + wawide_startx[npc]
+ local y = math.random(-128, 128) + wawide_starty[npc]
+ mana.being_walk(npc, x, y, 2)
+ end
+end
+
+
+-- Update function walkaround_map
+-- makes the NPC wander around the whole map. Useful when the players are
+-- supposed to search a bit for the NPC.
+
+local wam_timer = {}
+
+function walkaround_map(npc)
+ if not wam_timer[npc] then
+ wam_timer[npc] = 1
+ end
+
+ wam_timer[npc] = wam_timer[npc] + 1
+
+ if wam_timer[npc] == 50 then
+ wam_timer[npc] = math.random(1, 10)
+ local x = math.random(-128, 128) + mana.posX(npc)
+ local y = math.random(-128, 128) + mana.posY(npc)
+ mana.being_walk(npc, x, y, 2)
+ end
+end
+
+-- Allows passage of more information to an NPC's talk function
+function talk(f, ...)
+ local a = {...}
+ return function(npc, ch)
+ f(npc, ch, a)
+ end
+end
diff --git a/src/common/resourcemanager.cpp b/src/common/resourcemanager.cpp
index 8db4546..5d2a8cf 100644
--- a/src/common/resourcemanager.cpp
+++ b/src/common/resourcemanager.cpp
@@ -41,11 +41,14 @@ void ResourceManager::initialize()
{
PHYSFS_permitSymbolicLinks(1);
+ const std::string serverPath =
+ Configuration::getValue("serverPath", ".");
const std::string clientDataPath =
Configuration::getValue("clientDataPath", "example/clientdata");
const std::string serverDataPath =
Configuration::getValue("serverDataPath", "example/serverdata");
+ PHYSFS_addToSearchPath(serverPath.c_str(), 1);
PHYSFS_addToSearchPath(clientDataPath.c_str(), 1);
PHYSFS_addToSearchPath(serverDataPath.c_str(), 1);
}
diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp
index 507b348..ca91624 100644
--- a/src/scripting/lua.cpp
+++ b/src/scripting/lua.cpp
@@ -1694,6 +1694,5 @@ LuaScript::LuaScript():
lua_settable(mState, LUA_REGISTRYINDEX);
lua_settop(mState, 0);
- loadFile("scripts/libs/libmana.lua");
+ loadFile("scripts/lua/libmana.lua");
}
-