summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-02-26 22:06:10 +0100
committerThorbjørn Lindeijer <thorbjorn@lindeijer.nl>2012-03-02 18:12:07 +0100
commit34ac0d64e23f2b2d3981dbb0ea72157f334805dd (patch)
tree114b1f7a65956c097f7a59078292c9fa29c6451f
parente896d0b0125b48e12d43d99ace4498e56d968d50 (diff)
downloadmanaserv-34ac0d64e23f2b2d3981dbb0ea72157f334805dd.tar.gz
manaserv-34ac0d64e23f2b2d3981dbb0ea72157f334805dd.tar.xz
manaserv-34ac0d64e23f2b2d3981dbb0ea72157f334805dd.zip
Merged all the different Lua states into one
No more Lua state for each status effect, monster, item effect or map. All scripts are loaded into the same state. This should be more efficient overall and make it easier to implement dynamic reloading of the scripts in the future. Now, this introduces the problem of name collisions between different Lua scripts. For now this is solved by using more specific function names, like 'tick_plague' and 'tick_jump' rather than just 'tick'. The plan is however to get rid of these globals, and register these callbacks from the script, so that they can be local functions without the danger of colliding with other scripts. Reviewed-by: Erik Schilling Reviewed-by: Yohann Ferreira
-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