summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/manaserv.xml.example2
-rw-r--r--example/items.xml2
-rw-r--r--example/monsters.xml2
-rw-r--r--example/scripts/items/candy.lua2
-rw-r--r--example/scripts/monster/testmonster.lua4
-rw-r--r--example/scripts/status/jump.lua2
-rw-r--r--example/scripts/status/plague.lua2
-rw-r--r--example/status-effects.xml2
-rw-r--r--scripts/lua/libmana.lua4
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/game-server/character.cpp10
-rw-r--r--src/game-server/commandhandler.cpp4
-rw-r--r--src/game-server/item.cpp28
-rw-r--r--src/game-server/item.h8
-rw-r--r--src/game-server/itemmanager.cpp19
-rw-r--r--src/game-server/main-game.cpp13
-rw-r--r--src/game-server/mapcomposite.cpp57
-rw-r--r--src/game-server/mapcomposite.h9
-rw-r--r--src/game-server/monster.cpp42
-rw-r--r--src/game-server/monster.h6
-rw-r--r--src/game-server/state.cpp17
-rw-r--r--src/game-server/statuseffect.cpp18
-rw-r--r--src/game-server/statuseffect.h9
-rw-r--r--src/game-server/statusmanager.cpp9
-rw-r--r--src/scripting/script.cpp90
-rw-r--r--src/scripting/script.h17
-rw-r--r--src/scripting/scriptmanager.cpp98
-rw-r--r--src/scripting/scriptmanager.h70
28 files changed, 271 insertions, 277 deletions
diff --git a/docs/manaserv.xml.example b/docs/manaserv.xml.example
index b742c46..a2171e9 100644
--- a/docs/manaserv.xml.example
+++ b/docs/manaserv.xml.example
@@ -297,7 +297,7 @@
<!-- Scripting configuration ********************************************** -->
- <option name="script_defaultEngine" value="lua"/>
+ <option name="script_engine" value="lua"/>
<option name="script_mainFile" value="scripts/main.lua"/>
<!-- End of scripting configuration *************************************** -->
diff --git a/example/items.xml b/example/items.xml
index 18e3889..730e572 100644
--- a/example/items.xml
+++ b/example/items.xml
@@ -68,7 +68,7 @@
max-per-slot="30"
value="15">
<effect trigger="activation">
- <script src="candy.lua" function="use" />
+ <script src="candy.lua" function="use_candy" />
<consumes />
</effect>
</item>
diff --git a/example/monsters.xml b/example/monsters.xml
index ba882cc..f036191 100644
--- a/example/monsters.xml
+++ b/example/monsters.xml
@@ -78,7 +78,7 @@ exp<TAG>: Tells how much experience point a monster is giving up
damage-factor="1"
range="32"
animation="attack"
- script-function="strike"
+ script-function="on_maggot_strike"
/>
<script>testmonster.lua</script> <!-- only Proof of Concept-->
</monster>
diff --git a/example/scripts/items/candy.lua b/example/scripts/items/candy.lua
index a740ce6..5ab7c9a 100644
--- a/example/scripts/items/candy.lua
+++ b/example/scripts/items/candy.lua
@@ -12,6 +12,6 @@
-- 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. --
----------------------------------------------------------------------------------
-function use(user)
+function use_candy(user)
mana.being_say(user, "*munch*munch*munch*")
end
diff --git a/example/scripts/monster/testmonster.lua b/example/scripts/monster/testmonster.lua
index 9938943..fa094a8 100644
--- a/example/scripts/monster/testmonster.lua
+++ b/example/scripts/monster/testmonster.lua
@@ -8,14 +8,14 @@
-- Software Foundation; either version 2 of the License, or any later version. --
----------------------------------------------------------------------------------
-function update(mob)
+function update_monster(mob)
local r = math.random(0, 200);
if r == 0 then
mana.being_say(mob, "Roar! I am a boss")
end
end
-function strike(mob, victim, hit)
+function on_maggot_strike(mob, victim, hit)
if hit > 0 then
mana.being_say(mob, "Take this! "..hit.." damage!")
mana.being_say(victim, "Oh Noez!")
diff --git a/example/scripts/status/jump.lua b/example/scripts/status/jump.lua
index 3410747..10ad928 100644
--- a/example/scripts/status/jump.lua
+++ b/example/scripts/status/jump.lua
@@ -12,7 +12,7 @@
----------------------------------------------------------------------------------
-function tick(target, ticknumber)
+function tick_jump(target, ticknumber)
if (ticknumber % 10 == 0) then
mana.being_say(target, "I have the jumping bug!")
end
diff --git a/example/scripts/status/plague.lua b/example/scripts/status/plague.lua
index 5f98268..5f33eb8 100644
--- a/example/scripts/status/plague.lua
+++ b/example/scripts/status/plague.lua
@@ -12,7 +12,7 @@
-- Software Foundation; either version 2 of the License, or any later version. --
----------------------------------------------------------------------------------
-function tick(target, ticknumber)
+function tick_plague(target, ticknumber)
if (ticknumber % 10 == 0) then
mana.being_say(target, "I have the plague! :( = " .. ticknumber)
end
diff --git a/example/status-effects.xml b/example/status-effects.xml
index 7b613c4..fda9083 100644
--- a/example/status-effects.xml
+++ b/example/status-effects.xml
@@ -5,11 +5,13 @@
persistent-particle-effect="true"
start-particle="graphics/particles/green-bubbles.particle.xml"
script="plague.lua"
+ tick-function="tick_plague"
/>
<status-effect name="Jumping Status" id="2"
icon="icons/icon-feather.xml"
persistent-particle-effect="true"
start-particle="graphics/particles/magic.white.xml"
script="jump.lua"
+ tick-function="tick_jump"
/>
</status-effects>
diff --git a/scripts/lua/libmana.lua b/scripts/lua/libmana.lua
index 361fd7d..8b13911 100644
--- a/scripts/lua/libmana.lua
+++ b/scripts/lua/libmana.lua
@@ -318,13 +318,13 @@ function create_npc_delayed(name, id, x, y)
npc_handler = nil
end
--- Called during map initialization.
+-- Called during map initialization, for each map.
-- Executes all the functions registered by atinit.
function initialize()
for i,f in ipairs(init_fun) do
f()
end
- init_fun = nil
+ init_fun = {}
end
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1b5ad94..ecefab4 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -256,6 +256,8 @@ SET(SRCS_MANASERVGAME
game-server/trigger.cpp
scripting/script.h
scripting/script.cpp
+ scripting/scriptmanager.h
+ scripting/scriptmanager.cpp
utils/base64.h
utils/base64.cpp
utils/mathutils.h
diff --git a/src/game-server/character.cpp b/src/game-server/character.cpp
index 66fbd16..819da1c 100644
--- a/src/game-server/character.cpp
+++ b/src/game-server/character.cpp
@@ -39,7 +39,7 @@
#include "game-server/skillmanager.h"
#include "game-server/state.h"
#include "game-server/trade.h"
-#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "net/messagein.h"
#include "net/messageout.h"
#include "serialize/characterdata.h"
@@ -197,7 +197,7 @@ void Character::perform()
void Character::died()
{
Being::died();
- Script::executeGlobalEventFunction("on_chr_death", this);
+ ScriptManager::executeGlobalEventFunction("on_chr_death", this);
}
void Character::respawn()
@@ -215,7 +215,7 @@ void Character::respawn()
mTarget = NULL;
// Execute respawn script
- if (Script::executeGlobalEventFunction("on_chr_death_accept", this))
+ if (ScriptManager::executeGlobalEventFunction("on_chr_death_accept", this))
return;
// Script-controlled respawning didn't work - fall back to hardcoded logic.
@@ -250,7 +250,7 @@ void Character::useSpecial(int id)
//tell script engine to cast the spell
special->currentMana = 0;
- Script::performSpecialAction(id, this);
+ ScriptManager::performSpecialAction(id, this);
mSpecialUpdateNeeded = true;
return;
}
@@ -693,7 +693,7 @@ void Character::giveSpecial(int id)
if (mSpecials.find(id) == mSpecials.end())
{
Special *s = new Special();
- Script::addDataToSpecial(id, s);
+ ScriptManager::addDataToSpecial(id, s);
mSpecials[id] = s;
mSpecialUpdateNeeded = true;
}
diff --git a/src/game-server/commandhandler.cpp b/src/game-server/commandhandler.cpp
index 6904e0f..b59177c 100644
--- a/src/game-server/commandhandler.cpp
+++ b/src/game-server/commandhandler.cpp
@@ -33,7 +33,7 @@
#include "game-server/monstermanager.h"
#include "game-server/state.h"
-#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "common/configuration.h"
#include "common/permissionmanager.h"
@@ -1408,7 +1408,7 @@ static void handleCraft(Character *player, std::string &args)
// pass to script engine. The engine is responsible for all
// further processing of the crafting operation, including
// outputting an error message when the recipe is invalid.
- Script::performCraft(player, recipe);
+ ScriptManager::performCraft(player, recipe);
}
}
diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp
index 980db78..979a1bc 100644
--- a/src/game-server/item.cpp
+++ b/src/game-server/item.cpp
@@ -30,6 +30,7 @@
#include "game-server/being.h"
#include "game-server/state.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
bool ItemEffectAttrMod::apply(Being *itemUser)
{
@@ -59,18 +60,18 @@ void ItemEffectAutoAttack::dispell(Being *itemUser)
ItemEffectScript::~ItemEffectScript()
{
- delete mScript;
}
bool ItemEffectScript::apply(Being *itemUser)
{
- if (mScript && !mActivateFunctionName.empty())
+ if (!mActivateFunctionName.empty())
{
- mScript->setMap(itemUser->getMap());
- mScript->prepare(mActivateFunctionName);
- mScript->push(itemUser);
- mScript->push(mItemId);
- mScript->execute(); // TODO return depending on script execution success.
+ Script *script = ScriptManager::currentState();
+ script->setMap(itemUser->getMap());
+ script->prepare(mActivateFunctionName);
+ script->push(itemUser);
+ script->push(mItemId);
+ script->execute(); // TODO return depending on script execution success.
return true;
}
return false;
@@ -78,13 +79,14 @@ bool ItemEffectScript::apply(Being *itemUser)
void ItemEffectScript::dispell(Being *itemUser)
{
- if (mScript && !mDispellFunctionName.empty())
+ if (!mDispellFunctionName.empty())
{
- mScript->setMap(itemUser->getMap());
- mScript->prepare(mDispellFunctionName);
- mScript->push(itemUser);
- mScript->push(mItemId);
- mScript->execute();
+ Script *script = ScriptManager::currentState();
+ script->setMap(itemUser->getMap());
+ script->prepare(mDispellFunctionName);
+ script->push(itemUser);
+ script->push(mItemId);
+ script->execute();
}
}
diff --git a/src/game-server/item.h b/src/game-server/item.h
index f7c380f..8cd3ce6 100644
--- a/src/game-server/item.h
+++ b/src/game-server/item.h
@@ -26,7 +26,6 @@
#include "game-server/actor.h"
class Being;
-class Script;
// Indicates the equip slot "cost" to equip an item.
struct ItemEquipRequirement {
@@ -144,11 +143,10 @@ class ItemEffectConsumes : public ItemEffectInfo
class ItemEffectScript : public ItemEffectInfo
{
public:
- ItemEffectScript(int itemId, Script *script,
+ ItemEffectScript(int itemId,
const std::string& activateFunctionName,
const std::string& dispellFunctionName):
- mItemId(0),
- mScript(script),
+ mItemId(itemId),
mActivateFunctionName(activateFunctionName),
mDispellFunctionName(dispellFunctionName)
{}
@@ -157,9 +155,9 @@ class ItemEffectScript : public ItemEffectInfo
bool apply(Being *itemUser);
void dispell(Being *itemUser);
+
private:
int mItemId;
- Script *mScript;
std::string mActivateFunctionName;
std::string mDispellFunctionName;
};
diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp
index ffbdce8..b334760 100644
--- a/src/game-server/itemmanager.cpp
+++ b/src/game-server/itemmanager.cpp
@@ -26,6 +26,7 @@
#include "game-server/item.h"
#include "game-server/skillmanager.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include <map>
@@ -401,7 +402,7 @@ void ItemManager::readEffectNode(xmlNodePtr effectNode, ItemClass *item)
}
else if (xmlStrEqual(subNode->name, BAD_CAST "consumes"))
{
- item->addEffect(new ItemEffectConsumes(), triggerTypes.first);
+ item->addEffect(new ItemEffectConsumes, triggerTypes.first);
}
else if (xmlStrEqual(subNode->name, BAD_CAST "script"))
{
@@ -432,29 +433,19 @@ void ItemManager::readEffectNode(xmlNodePtr effectNode, ItemClass *item)
}
LOG_INFO("Loading item script: " << filename.str());
-
- std::string engineName =
- Script::determineEngineByFilename(filename.str());
- Script *script = Script::create(engineName);
+ Script *script = ScriptManager::currentState();
if (!script->loadFile(filename.str()))
{
- // Delete the script as it's invalid.
- delete script;
-
LOG_WARN("Could not load script file \"" << filename.str()
- << "\" for item #" << item->mDatabaseID);
+ << "\" for item #" << item->mDatabaseID);
continue;
}
- for_each_xml_child_node(scriptSubNode, subNode)
- {
- // TODO: Load variables from variable subnodes
- }
std::string dispellFunctionName = XML::getProperty(subNode,
"dispell-function",
std::string());
- item->addEffect(new ItemEffectScript(item->mDatabaseID, script,
+ item->addEffect(new ItemEffectScript(item->mDatabaseID,
activateFunctionName,
dispellFunctionName),
triggerTypes.first,
diff --git a/src/game-server/main-game.cpp b/src/game-server/main-game.cpp
index daf1561..c3b3c36 100644
--- a/src/game-server/main-game.cpp
+++ b/src/game-server/main-game.cpp
@@ -52,7 +52,7 @@
#include "net/bandwidth.h"
#include "net/connectionhandler.h"
#include "net/messageout.h"
-#include "scripting/luascript.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/processorutils.h"
#include "utils/stringfilter.h"
@@ -71,7 +71,7 @@ using utils::Logger;
#define DEFAULT_MONSTERSDB_FILE "monsters.xml"
#define DEFAULT_STATUSDB_FILE "status-effects.xml"
#define DEFAULT_PERMISSION_FILE "permissions.xml"
-#define DEFAULT_GLOBAL_EVENT_SCRIPT_FILE "scripts/main.lua"
+#define DEFAULT_MAIN_SCRIPT_FILE "scripts/main.lua"
static int const WORLD_TICK_SKIP = 2; /** tolerance for lagging behind in world calculation) **/
@@ -127,6 +127,7 @@ static void initializeServer()
stringFilter = new utils::StringFilter;
ResourceManager::initialize();
+ ScriptManager::initialize(); // Depends on ResourceManager
if (MapManager::initialize(DEFAULT_MAPSDB_FILE) < 1)
{
LOG_FATAL("The Game Server can't find any valid/available maps.");
@@ -139,10 +140,9 @@ static void initializeServer()
StatusManager::initialize(DEFAULT_STATUSDB_FILE);
PermissionManager::initialize(DEFAULT_PERMISSION_FILE);
- const std::string mainScriptFile =
- Configuration::getValue("script_mainFile",
- DEFAULT_GLOBAL_EVENT_SCRIPT_FILE);
- Script::loadGlobalEventScript(mainScriptFile);
+ std::string mainScript = Configuration::getValue("script_mainFile",
+ DEFAULT_MAIN_SCRIPT_FILE);
+ ScriptManager::loadMainScript(mainScript);
// --- Initialize the global handlers
// FIXME: Make the global handlers global vars or part of a bigger
@@ -194,6 +194,7 @@ static void deinitializeServer()
delete itemManager; itemManager = 0;
MapManager::deinitialize();
StatusManager::deinitialize();
+ ScriptManager::deinitialize();
PHYSFS_deinit();
}
diff --git a/src/game-server/mapcomposite.cpp b/src/game-server/mapcomposite.cpp
index 9959056..c909000 100644
--- a/src/game-server/mapcomposite.cpp
+++ b/src/game-server/mapcomposite.cpp
@@ -34,6 +34,7 @@
#include "game-server/spawnarea.h"
#include "game-server/trigger.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/point.h"
@@ -458,7 +459,6 @@ MapZone& MapContent::getZone(const Point &pos) const
MapComposite::MapComposite(int id, const std::string &name):
mMap(NULL),
mContent(NULL),
- mScript(NULL),
mName(name),
mID(id)
{
@@ -468,7 +468,6 @@ MapComposite::~MapComposite()
{
delete mMap;
delete mContent;
- delete mScript;
}
bool MapComposite::activate()
@@ -494,12 +493,10 @@ bool MapComposite::activate()
else
mPvPRules = PVP_NONE;
- if (Script *s = getScript())
- {
- s->setMap(this);
- s->prepare("initialize");
- s->execute();
- }
+ Script *s = ScriptManager::currentState();
+ s->setMap(this);
+ s->prepare("initialize");
+ s->execute();
return true;
}
@@ -730,25 +727,12 @@ void MapComposite::initializeContent()
int npcId = utils::stringToInt(object->getProperty("NPC_ID"));
std::string scriptText = object->getProperty("SCRIPT");
- if (!mScript)
- {
- // Determine script engine by xml property
- std::string scriptEngineName = object->getProperty("ENGINE");
- if (scriptEngineName.empty())
- {
- // Set engine to default value and print warning
- scriptEngineName = Configuration::getValue("script_defaultEngine", "lua");
- LOG_WARN("No script engine specified for map script \""
- + mName + "\", falling back to default");
- }
- mScript = Script::create(scriptEngineName);
- }
-
if (npcId && !scriptText.empty())
{
- mScript->loadNPC(object->getName(), npcId,
- object->getX(), object->getY(),
- scriptText.c_str());
+ Script *script = ScriptManager::currentState();
+ script->loadNPC(object->getName(), npcId,
+ object->getX(), object->getY(),
+ scriptText.c_str());
}
else
{
@@ -760,33 +744,16 @@ void MapComposite::initializeContent()
std::string scriptFilename = object->getProperty("FILENAME");
std::string scriptText = object->getProperty("TEXT");
- if (!mScript)
- {
- // Determine script engine by xml property
- std::string scriptEngineName = object->getProperty("ENGINE");
- if (!scriptFilename.empty() && scriptEngineName.empty())
- {
- // Engine property is empty - determine by filename
- scriptEngineName = Script::determineEngineByFilename(scriptFilename);
- }
- else if (scriptEngineName.empty())
- {
- // Set engine to default value and print warning
- scriptEngineName = Configuration::getValue("script_defaultEngine", "lua");
- LOG_WARN("No script engine specified for map script \""
- + mName + "\", falling back to default");
- }
- mScript = Script::create(scriptEngineName);
- }
+ Script *script = ScriptManager::currentState();
if (!scriptFilename.empty())
{
- mScript->loadFile(scriptFilename);
+ script->loadFile(scriptFilename);
}
else if (!scriptText.empty())
{
std::string name = "'" + object->getName() + "'' in " + mName;
- mScript->load(scriptText.c_str(), name.c_str());
+ script->load(scriptText.c_str(), name.c_str());
}
else
{
diff --git a/src/game-server/mapcomposite.h b/src/game-server/mapcomposite.h
index 988b0ed..4929691 100644
--- a/src/game-server/mapcomposite.h
+++ b/src/game-server/mapcomposite.h
@@ -33,7 +33,6 @@ class Map;
class MapComposite;
class Point;
class Rectangle;
-class Script;
class Thing;
struct MapContent;
@@ -249,13 +248,6 @@ class MapComposite
{ return mMap; }
/**
- * Gets the associated script. Returns 0 when no scripts or inline
- * NPCs are used on this map!
- */
- Script *getScript() const
- { return mScript; }
-
- /**
* Returns whether the map is active on this server or not.
*/
bool isActive() const
@@ -351,7 +343,6 @@ class MapComposite
Map *mMap; /**< Actual map. */
MapContent *mContent; /**< Entities on the map. */
- Script *mScript; /**< Script associated to this map. */
std::string mName; /**< Name of the map. */
unsigned short mID; /**< ID of the map. */
/** Cached persistent variables */
diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp
index 6e40fb2..21eeea7 100644
--- a/src/game-server/monster.cpp
+++ b/src/game-server/monster.cpp
@@ -29,6 +29,7 @@
#include "game-server/mapcomposite.h"
#include "game-server/state.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/speedconv.h"
@@ -49,7 +50,6 @@ static MonsterTargetEventDispatch monsterTargetEventDispatch;
Monster::Monster(MonsterClass *specy):
Being(OBJECT_MONSTER),
mSpecy(specy),
- mScript(NULL),
mTargetListener(&monsterTargetEventDispatch),
mOwner(NULL),
mCurrentAttack(NULL)
@@ -108,10 +108,6 @@ Monster::Monster(MonsterClass *specy):
Monster::~Monster()
{
- // Remove the monster's script if it has one
- if (mScript)
- delete mScript;
-
// Remove death listeners.
for (std::map<Being *, int>::iterator i = mAnger.begin(),
i_end = mAnger.end(); i != i_end; ++i)
@@ -145,15 +141,15 @@ void Monster::perform()
int hit = performAttack(mTarget, dmg);
if (! mCurrentAttack->scriptFunction.empty()
- && mScript
&& hit > -1)
{
- mScript->setMap(getMap());
- mScript->prepare(mCurrentAttack->scriptFunction);
- mScript->push(this);
- mScript->push(mTarget);
- mScript->push(hit);
- mScript->execute();
+ Script *script = ScriptManager::currentState();
+ script->setMap(getMap());
+ script->prepare(mCurrentAttack->scriptFunction);
+ script->push(this);
+ script->push(mTarget);
+ script->push(hit);
+ script->execute();
}
}
}
@@ -183,13 +179,12 @@ void Monster::update()
}
return;
}
- else if(mScript)
- {
- mScript->setMap(getMap());
- mScript->prepare("update");
- mScript->push(this);
- mScript->execute();
- }
+
+ Script *script = ScriptManager::currentState();
+ script->setMap(getMap());
+ script->prepare("update_monster");
+ script->push(this);
+ script->execute();
// Cancel the rest when we are currently performing an attack
if (isTimerRunning(T_M_ATTACK_TIME))
@@ -324,10 +319,6 @@ void Monster::update()
void Monster::loadScript(const std::string &scriptName)
{
- // A script may have already been loaded for this monster
- delete mScript;
- mScript = 0;
-
if (scriptName.length() == 0)
return;
@@ -336,10 +327,7 @@ void Monster::loadScript(const std::string &scriptName)
if (ResourceManager::exists(filename.str()))
{
LOG_INFO("Loading monster script: " << filename.str());
- std::string engineName =
- Script::determineEngineByFilename(filename.str());
- mScript = Script::create(engineName);
- mScript->loadFile(filename.str());
+ ScriptManager::currentState()->loadFile(filename.str());
}
else
{
diff --git a/src/game-server/monster.h b/src/game-server/monster.h
index fe68a8a..37bbe35 100644
--- a/src/game-server/monster.h
+++ b/src/game-server/monster.h
@@ -328,12 +328,6 @@ class Monster : public Being
MonsterClass *mSpecy;
- /**
- * Stores individual script for the monster, when NULL the script
- * from mSpecy is used.
- */
- Script *mScript;
-
/** Aggression towards other beings. */
std::map<Being *, int> mAnger;
diff --git a/src/game-server/state.cpp b/src/game-server/state.cpp
index 930c475..471cc7c 100644
--- a/src/game-server/state.cpp
+++ b/src/game-server/state.cpp
@@ -37,6 +37,7 @@
#include "game-server/trade.h"
#include "net/messageout.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/point.h"
#include "utils/speedconv.h"
@@ -75,7 +76,7 @@ static std::map< std::string, std::string > mScriptVariables;
*/
static void updateMap(MapComposite *map)
{
- // 1. update object status.
+ // Update object status
const std::vector< Thing * > &things = map->getEverything();
for (std::vector< Thing * >::const_iterator it = things.begin(),
it_end = things.end(); it != it_end; ++it)
@@ -83,19 +84,13 @@ static void updateMap(MapComposite *map)
(*it)->update();
}
- // 2. run scripts.
- if (Script *s = map->getScript())
- {
- s->update();
- }
-
- // 3. perform actions.
+ // Perform actions
for (BeingIterator it(map->getWholeMapIterator()); it; ++it)
{
(*it)->perform();
}
- // 4. move objects around and update zones.
+ // Move objects around and update zones.
for (BeingIterator it(map->getWholeMapIterator()); it; ++it)
{
(*it)->move();
@@ -450,6 +445,8 @@ void GameState::update(int worldTime)
dbgLockObjects = true;
# endif
+ ScriptManager::currentState()->update();
+
// Update game state (update AI, etc.)
const MapManager::Maps &maps = MapManager::getMaps();
for (MapManager::Maps::const_iterator m = maps.begin(),
@@ -457,9 +454,7 @@ void GameState::update(int worldTime)
{
MapComposite *map = m->second;
if (!map->isActive())
- {
continue;
- }
updateMap(map);
diff --git a/src/game-server/statuseffect.cpp b/src/game-server/statuseffect.cpp
index 9f91711..32e0d62 100644
--- a/src/game-server/statuseffect.cpp
+++ b/src/game-server/statuseffect.cpp
@@ -21,27 +21,27 @@
#include "game-server/statuseffect.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "game-server/being.h"
StatusEffect::StatusEffect(int id):
- mId(id),
- mScript(0)
+ mId(id)
{
}
StatusEffect::~StatusEffect()
{
- delete mScript;
}
void StatusEffect::tick(Being *target, int count)
{
- if (mScript)
+ if (!mTickFunction.empty())
{
- mScript->setMap(target->getMap());
- mScript->prepare("tick");
- mScript->push(target);
- mScript->push(count);
- mScript->execute();
+ Script *script = ScriptManager::currentState();
+ script->setMap(target->getMap());
+ script->prepare(mTickFunction);
+ script->push(target);
+ script->push(count);
+ script->execute();
}
}
diff --git a/src/game-server/statuseffect.h b/src/game-server/statuseffect.h
index 3aa4d84..2b7a36f 100644
--- a/src/game-server/statuseffect.h
+++ b/src/game-server/statuseffect.h
@@ -21,7 +21,8 @@
#ifndef STATUSEFFECT_H
#define STATUSEFFECT_H
-class Script;
+#include <string>
+
class Being;
class StatusEffect
@@ -35,12 +36,12 @@ class StatusEffect
int getId() const
{ return mId; }
- void setScript(Script *script)
- { mScript = script; }
+ void setTickFunction(const std::string &tickFunction)
+ { mTickFunction = tickFunction; }
private:
int mId;
- Script *mScript;
+ std::string mTickFunction;
};
#endif
diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp
index 66c2642..15203d6 100644
--- a/src/game-server/statusmanager.cpp
+++ b/src/game-server/statusmanager.cpp
@@ -23,6 +23,7 @@
#include "common/resourcemanager.h"
#include "game-server/statuseffect.h"
#include "scripting/script.h"
+#include "scripting/scriptmanager.h"
#include "utils/logger.h"
#include "utils/xml.h"
@@ -68,6 +69,8 @@ void StatusManager::reload()
}
std::string scriptFile = XML::getProperty(node, "script", std::string());
+ std::string tickFunction = XML::getProperty(node, "tick-function",
+ std::string());
//TODO: Get these modifiers
/*
modifiers.setAttributeValue(BASE_ATTR_PHY_ATK_MIN, XML::getProperty(node, "attack-min", 0));
@@ -82,6 +85,7 @@ void StatusManager::reload()
modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0));
*/
StatusEffect *statusEffect = new StatusEffect(id);
+ statusEffect->setTickFunction(tickFunction);
if (!scriptFile.empty())
{
std::stringstream filename;
@@ -89,11 +93,8 @@ void StatusManager::reload()
if (ResourceManager::exists(filename.str())) // file exists!
{
LOG_INFO("Loading status script: " << filename.str());
- std::string engineName =
- Script::determineEngineByFilename(filename.str());
- Script *s = Script::create(engineName);
+ Script *s = ScriptManager::currentState();
s->loadFile(filename.str());
- statusEffect->setScript(s);
} else {
LOG_WARN("Could not find script file \"" << filename.str()
<< "\" for status #"<<id);
diff --git a/src/scripting/script.cpp b/src/scripting/script.cpp
index 722979f..db44bd5 100644
--- a/src/scripting/script.cpp
+++ b/src/scripting/script.cpp
@@ -33,7 +33,6 @@
typedef std::map< std::string, Script::Factory > Engines;
static Engines *engines = NULL;
-Script *Script::globalEventScript = NULL;
Script::Script():
mMap(NULL),
@@ -107,92 +106,3 @@ void Script::loadNPC(const std::string &name, int id, int x, int y,
push(y);
execute();
}
-
-bool Script::loadGlobalEventScript(const std::string &file)
-{
- std::string engineName = determineEngineByFilename(file);
- if (Script *script = Script::create(engineName))
- {
- globalEventScript = script;
- return globalEventScript->loadFile(file);
- }
- return false;
-}
-
-bool Script::executeGlobalEventFunction(const std::string &function, Being* obj)
-{
- bool isScriptHandled = false;
- if (Script *script = globalEventScript)
- {
- script->setMap(obj->getMap());
- script->prepare(function);
- script->push(obj);
- script->execute();
- script->setMap(NULL);
- isScriptHandled = true; // TODO: don't set to true when execution failed
- }
- return isScriptHandled;
-}
-
-
-void Script::addDataToSpecial(int id, Special *special)
-{
- /* currently only gets the recharge cost.
- TODO: get any other info in a similar way, but
- first we have to agree on what other
- info we actually want to provide.
- */
- if (special)
- {
- if (Script *script = globalEventScript)
- {
- script->prepare("get_special_recharge_cost");
- script->push(id);
- int scriptReturn = script->execute();
- special->neededMana = scriptReturn;
- }
- }
-
-}
-
-bool Script::performSpecialAction(int specialId, Being *caster)
-{
- if (Script *script = globalEventScript)
- {
- script->prepare("use_special");
- script->push(caster);
- script->push(specialId);
- script->execute();
- }
- return true;
-}
-
-bool Script::performCraft(Being *crafter,
- const std::list<InventoryItem> &recipe)
-{
- if (Script *script = globalEventScript)
- {
- script->prepare("on_craft");
- script->push(crafter);
- script->push(recipe);
- script->execute();
- }
- return true;
-}
-
-std::string Script::determineEngineByFilename(const std::string &filename)
-{
- std::string ext = filename.substr(filename.find_last_of(".") + 1);
-
- if (ext == "lua")
- {
- return "lua";
- }
- else
- {
- // Set to default engine and print warning
- LOG_WARN("Unknown file extension for script \""
- + filename + "\", falling back to default script engine");
- return Configuration::getValue("script_defaultEngine", "lua");
- }
-}
diff --git a/src/scripting/script.h b/src/scripting/script.h
index a773751..bd14311 100644
--- a/src/scripting/script.h
+++ b/src/scripting/script.h
@@ -135,21 +135,6 @@ class Script
virtual void processRemoveEvent(Thing *thing) = 0;
- /**
- * Loads the global event script file
- */
- static bool loadGlobalEventScript(const std::string &file);
-
- /**
- * Runs a function from the global event script file
- */
- static bool executeGlobalEventFunction(const std::string &function, Being *obj);
- static void addDataToSpecial(int specialId, Special *special);
- static bool performSpecialAction(int specialId, Being *caster);
- static bool performCraft(Being *crafter, const std::list<InventoryItem> &recipe);
-
- static std::string determineEngineByFilename(const std::string &filename);
-
protected:
std::string mScriptFile;
@@ -157,8 +142,6 @@ class Script
MapComposite *mMap;
EventListener mEventListener; /**< Tracking of being deaths. */
- static Script *globalEventScript;
-
friend struct ScriptEventDispatch;
};
diff --git a/src/scripting/scriptmanager.cpp b/src/scripting/scriptmanager.cpp
new file mode 100644
index 0000000..5251569
--- /dev/null
+++ b/src/scripting/scriptmanager.cpp
@@ -0,0 +1,98 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2012 The Mana Developers
+ *
+ * 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.
+ *
+ * The Mana Server 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 Server. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "scriptmanager.h"
+
+#include "common/configuration.h"
+#include "scripting/script.h"
+
+static Script *_currentState;
+
+void ScriptManager::initialize()
+{
+ const std::string engine = Configuration::getValue("script_engine", "lua");
+ _currentState = Script::create(engine);
+}
+
+void ScriptManager::deinitialize()
+{
+ delete _currentState;
+ _currentState = 0;
+}
+
+bool ScriptManager::loadMainScript(const std::string &file)
+{
+ return _currentState->loadFile(file);
+}
+
+Script *ScriptManager::currentState()
+{
+ return _currentState;
+}
+
+// TODO: Have some generic event mechanism rather than calling global functions
+
+bool ScriptManager::executeGlobalEventFunction(const std::string &function, Being* obj)
+{
+ bool isScriptHandled = false;
+ _currentState->setMap(obj->getMap());
+ _currentState->prepare(function);
+ _currentState->push(obj);
+ _currentState->execute();
+ _currentState->setMap(NULL);
+ isScriptHandled = true; // TODO: don't set to true when execution failed
+ return isScriptHandled;
+}
+
+
+void ScriptManager::addDataToSpecial(int id, Special *special)
+{
+ /* currently only gets the recharge cost.
+ TODO: get any other info in a similar way, but
+ first we have to agree on what other
+ info we actually want to provide.
+ */
+ if (special)
+ {
+ _currentState->prepare("get_special_recharge_cost");
+ _currentState->push(id);
+ int scriptReturn = _currentState->execute();
+ special->neededMana = scriptReturn;
+ }
+}
+
+bool ScriptManager::performSpecialAction(int specialId, Being *caster)
+{
+ _currentState->prepare("use_special");
+ _currentState->push(caster);
+ _currentState->push(specialId);
+ _currentState->execute();
+ return true;
+}
+
+bool ScriptManager::performCraft(Being *crafter,
+ const std::list<InventoryItem> &recipe)
+{
+ _currentState->prepare("on_craft");
+ _currentState->push(crafter);
+ _currentState->push(recipe);
+ _currentState->execute();
+ return true;
+}
diff --git a/src/scripting/scriptmanager.h b/src/scripting/scriptmanager.h
new file mode 100644
index 0000000..7560c34
--- /dev/null
+++ b/src/scripting/scriptmanager.h
@@ -0,0 +1,70 @@
+/*
+ * The Mana Server
+ * Copyright (C) 2012 The Mana Developers
+ *
+ * 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.
+ *
+ * The Mana Server 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 Server. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef SCRIPTMANAGER_H
+#define SCRIPTMANAGER_H
+
+#include "game-server/character.h"
+
+#include <string>
+
+class Script;
+class Special;
+
+/**
+ * Manages the script states. In fact at the moment it simply provides access
+ * to the single global script state, but in the future it is planned to allow
+ * reloading the scripts while the server is running, by keeping old script
+ * states around until they are no longer in use.
+ */
+namespace ScriptManager {
+
+/**
+ * Initializes the script manager by creating the script state.
+ */
+void initialize();
+
+/**
+ * Deinitializes the script manager by deleting the script state.
+ */
+void deinitialize();
+
+/**
+ * Loads the main script file.
+ */
+bool loadMainScript(const std::string &file);
+
+/**
+ * Returns the current global script state.
+ */
+Script *currentState();
+
+
+/**
+ * Runs a global function from the global event script file
+ */
+bool executeGlobalEventFunction(const std::string &function, Being *obj);
+void addDataToSpecial(int specialId, Special *special);
+bool performSpecialAction(int specialId, Being *caster);
+bool performCraft(Being *crafter, const std::list<InventoryItem> &recipe);
+
+} // namespace ScriptManager
+
+#endif // SCRIPTMANAGER_H