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.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 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 |