diff options
author | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2012-02-26 22:06:10 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2012-03-02 18:12:07 +0100 |
commit | 34ac0d64e23f2b2d3981dbb0ea72157f334805dd (patch) | |
tree | 114b1f7a65956c097f7a59078292c9fa29c6451f | |
parent | e896d0b0125b48e12d43d99ace4498e56d968d50 (diff) | |
download | manaserv-34ac0d64e23f2b2d3981dbb0ea72157f334805dd.tar.gz manaserv-34ac0d64e23f2b2d3981dbb0ea72157f334805dd.tar.bz2 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
28 files changed, 271 insertions, 277 deletions
diff --git a/docs/manaserv.xml.example b/docs/manaserv.xml.example index b742c467..a2171e9c 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 18e3889e..730e5729 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 ba882cc8..f0361915 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 a740ce6a..5ab7c9a4 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 9938943b..fa094a8d 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 3410747a..10ad9288 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 5f98268e..5f33eb87 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 7b613c4f..fda90836 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 361fd7db..8b13911f 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 1b5ad942..ecefab4f 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 66fbd160..819da1c1 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 6904e0fc..b59177ca 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 980db785..979a1bc3 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 f7c380f1..8cd3ce64 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 ffbdce89..b334760a 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 daf15611..c3b3c36a 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 99590566..c9090008 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 988b0ed8..49296911 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 6e40fb24..21eeea7c 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 fe68a8a8..37bbe355 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 930c475b..471cc7c3 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 9f917110..32e0d621 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 3aa4d843..2b7a36f8 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 66c2642a..15203d65 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 722979fd..db44bd57 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 a7737512..bd143114 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 00000000..52515699 --- /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 00000000..7560c343 --- /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 |