diff options
-rw-r--r-- | example/items.xml | 2 | ||||
-rw-r--r-- | example/monsters.xml | 2 | ||||
-rw-r--r-- | example/scripts/items/candy.lua | 8 | ||||
-rw-r--r-- | example/scripts/main.lua | 3 | ||||
-rw-r--r-- | example/scripts/monster/testmonster.lua | 8 | ||||
-rw-r--r-- | example/scripts/status/jump.lua | 4 | ||||
-rw-r--r-- | example/scripts/status/plague.lua | 4 | ||||
-rw-r--r-- | src/game-server/item.cpp | 20 | ||||
-rw-r--r-- | src/game-server/item.h | 31 | ||||
-rw-r--r-- | src/game-server/itemmanager.cpp | 51 | ||||
-rw-r--r-- | src/game-server/monster.cpp | 34 | ||||
-rw-r--r-- | src/game-server/monster.h | 27 | ||||
-rw-r--r-- | src/game-server/monstermanager.cpp | 5 | ||||
-rw-r--r-- | src/game-server/statuseffect.cpp | 17 | ||||
-rw-r--r-- | src/game-server/statuseffect.h | 8 | ||||
-rw-r--r-- | src/game-server/statusmanager.cpp | 31 | ||||
-rw-r--r-- | src/game-server/statusmanager.h | 5 | ||||
-rw-r--r-- | src/scripting/lua.cpp | 111 | ||||
-rw-r--r-- | src/scripting/luautil.h | 23 | ||||
-rw-r--r-- | src/utils/string.h | 5 |
20 files changed, 263 insertions, 136 deletions
diff --git a/example/items.xml b/example/items.xml index 730e5729..cdbc3e44 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_candy" /> + <scriptevent activate="use" /> <consumes /> </effect> </item> diff --git a/example/monsters.xml b/example/monsters.xml index f0361915..962b137e 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="on_maggot_strike" + script-event="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 a9c59fe4..f60e687d 100644 --- a/example/scripts/items/candy.lua +++ b/example/scripts/items/candy.lua @@ -2,12 +2,14 @@ Example item script. - Makes the player character say "*munch*munch*munch*" when using this item. + Makes the player character say "*munch*munch*munch*" when using a candy. The HP regeneration effect is handled separately based on the heal value in items.xml. --]] -function use_candy(user) +local candy = mana.get_item_class("candy") + +candy:on("use", function(user) mana.being_say(user, "*munch*munch*munch*") -end +end) diff --git a/example/scripts/main.lua b/example/scripts/main.lua index aeaca63b..6d8207e7 100644 --- a/example/scripts/main.lua +++ b/example/scripts/main.lua @@ -9,3 +9,6 @@ require "scripts/global_events" require "scripts/special_actions" require "scripts/crafting" + +require "scripts/items/candy" +require "scripts/monster/testmonster" diff --git a/example/scripts/monster/testmonster.lua b/example/scripts/monster/testmonster.lua index 2701d24e..63b29179 100644 --- a/example/scripts/monster/testmonster.lua +++ b/example/scripts/monster/testmonster.lua @@ -7,14 +7,14 @@ --]] -function update_monster(mob) +local function update(mob) local r = math.random(0, 200); if r == 0 then mana.being_say(mob, "Roar! I am a boss") end end -function on_maggot_strike(mob, victim, hit) +local function strike(mob, victim, hit) if hit > 0 then mana.being_say(mob, "Take this! "..hit.." damage!") mana.being_say(victim, "Oh Noez!") @@ -23,3 +23,7 @@ function on_maggot_strike(mob, victim, hit) mana.being_say(victim, "Whew...") end end + +local maggot = mana.get_monster_class("maggot") +maggot:on_update(update) +maggot:on("strike", strike) diff --git a/example/scripts/status/jump.lua b/example/scripts/status/jump.lua index 10ad9288..166c90d1 100644 --- a/example/scripts/status/jump.lua +++ b/example/scripts/status/jump.lua @@ -12,7 +12,7 @@ ---------------------------------------------------------------------------------- -function tick_jump(target, ticknumber) +local function tick(target, ticknumber) if (ticknumber % 10 == 0) then mana.being_say(target, "I have the jumping bug!") end @@ -51,3 +51,5 @@ function tick_jump(target, ticknumber) mana.being_apply_status(victim, 2, 6000) mana.being_say(victim, "Now I have the jumping bug") end + +mana.get_status_effect("jumping status"):on_tick(tick) diff --git a/example/scripts/status/plague.lua b/example/scripts/status/plague.lua index 5f33eb87..a43b9d40 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_plague(target, ticknumber) +local function tick(target, ticknumber) if (ticknumber % 10 == 0) then mana.being_say(target, "I have the plague! :( = " .. ticknumber) end @@ -26,3 +26,5 @@ function tick_plague(target, ticknumber) i = i + 1 end end + +mana.get_status_effect("plague"):on_tick(tick) diff --git a/src/game-server/item.cpp b/src/game-server/item.cpp index 979a1bc3..888c90ad 100644 --- a/src/game-server/item.cpp +++ b/src/game-server/item.cpp @@ -64,13 +64,17 @@ ItemEffectScript::~ItemEffectScript() bool ItemEffectScript::apply(Being *itemUser) { - if (!mActivateFunctionName.empty()) + if (mActivateEventName.empty()) + return false; + + Script::Ref function = mItemClass->getEventCallback(mActivateEventName); + if (function.isValid()) { Script *script = ScriptManager::currentState(); script->setMap(itemUser->getMap()); - script->prepare(mActivateFunctionName); + script->prepare(function); script->push(itemUser); - script->push(mItemId); + script->push(mItemClass->getDatabaseID()); script->execute(); // TODO return depending on script execution success. return true; } @@ -79,13 +83,17 @@ bool ItemEffectScript::apply(Being *itemUser) void ItemEffectScript::dispell(Being *itemUser) { - if (!mDispellFunctionName.empty()) + if (mDispellEventName.empty()) + return; + + Script::Ref function = mItemClass->getEventCallback(mDispellEventName); + if (function.isValid()) { Script *script = ScriptManager::currentState(); script->setMap(itemUser->getMap()); - script->prepare(mDispellFunctionName); + script->prepare(function); script->push(itemUser); - script->push(mItemId); + script->push(mItemClass->getDatabaseID()); script->execute(); } } diff --git a/src/game-server/item.h b/src/game-server/item.h index 8cd3ce64..2677589f 100644 --- a/src/game-server/item.h +++ b/src/game-server/item.h @@ -24,8 +24,10 @@ #include <vector> #include "game-server/actor.h" +#include "scripting/script.h" class Being; +class ItemClass; // Indicates the equip slot "cost" to equip an item. struct ItemEquipRequirement { @@ -143,12 +145,12 @@ class ItemEffectConsumes : public ItemEffectInfo class ItemEffectScript : public ItemEffectInfo { public: - ItemEffectScript(int itemId, - const std::string& activateFunctionName, - const std::string& dispellFunctionName): - mItemId(itemId), - mActivateFunctionName(activateFunctionName), - mDispellFunctionName(dispellFunctionName) + ItemEffectScript(ItemClass *itemClass, + const std::string &activateEventName, + const std::string &dispellEventName): + mItemClass(itemClass), + mActivateEventName(activateEventName), + mDispellEventName(dispellEventName) {} ~ItemEffectScript(); @@ -157,9 +159,9 @@ class ItemEffectScript : public ItemEffectInfo void dispell(Being *itemUser); private: - int mItemId; - std::string mActivateFunctionName; - std::string mDispellFunctionName; + ItemClass *mItemClass; + std::string mActivateEventName; + std::string mDispellEventName; }; @@ -234,6 +236,12 @@ class ItemClass const ItemEquipRequirement &getItemEquipRequirement() const { return mEquipReq; } + void setEventCallback(const std::string &event, Script *script) + { script->assignCallback(mEventCallbacks[event]); } + + Script::Ref getEventCallback(const std::string &event) const + { return mEventCallbacks.value(event); } + private: /** * Add an effect to a trigger @@ -282,6 +290,11 @@ class ItemClass */ ItemEquipRequirement mEquipReq; + /** + * Named event callbacks. Can be used in custom item effects. + */ + utils::NameMap<Script::Ref> mEventCallbacks; + friend class ItemManager; }; diff --git a/src/game-server/itemmanager.cpp b/src/game-server/itemmanager.cpp index b334760a..8c74680e 100644 --- a/src/game-server/itemmanager.cpp +++ b/src/game-server/itemmanager.cpp @@ -404,50 +404,25 @@ void ItemManager::readEffectNode(xmlNodePtr effectNode, ItemClass *item) { item->addEffect(new ItemEffectConsumes, triggerTypes.first); } - else if (xmlStrEqual(subNode->name, BAD_CAST "script")) + else if (xmlStrEqual(subNode->name, BAD_CAST "scriptevent")) { - std::string activateFunctionName = XML::getProperty(subNode, - "function", - std::string()); - if (activateFunctionName.empty()) - { - LOG_WARN("Item Manager: Empty function definition " - "for script effect, skipping!"); - continue; - } - - std::string src = XML::getProperty(subNode, "src", std::string()); - if (src.empty()) - { - LOG_WARN("Item Manager: Empty src definition for script effect," - " skipping!"); - continue; - } - std::stringstream filename; - filename << "scripts/items/" << src; - if (!ResourceManager::exists(filename.str())) - { - LOG_WARN("Could not find script file \"" << filename.str() - << "\" for item #" << item->mDatabaseID); - continue; - } - - LOG_INFO("Loading item script: " << filename.str()); - Script *script = ScriptManager::currentState(); - if (!script->loadFile(filename.str())) + std::string activateEventName = XML::getProperty(subNode, + "activate", + std::string()); + if (activateEventName.empty()) { - LOG_WARN("Could not load script file \"" << filename.str() - << "\" for item #" << item->mDatabaseID); + LOG_WARN("Item Manager: Empty name for 'activate' item script " + "event, skipping effect!"); continue; } - std::string dispellFunctionName = XML::getProperty(subNode, - "dispell-function", - std::string()); + std::string dispellEventName = XML::getProperty(subNode, + "dispell", + std::string()); - item->addEffect(new ItemEffectScript(item->mDatabaseID, - activateFunctionName, - dispellFunctionName), + item->addEffect(new ItemEffectScript(item, + activateEventName, + dispellEventName), triggerTypes.first, triggerTypes.second); } diff --git a/src/game-server/monster.cpp b/src/game-server/monster.cpp index 21eeea7c..b82f4638 100644 --- a/src/game-server/monster.cpp +++ b/src/game-server/monster.cpp @@ -28,7 +28,6 @@ #include "game-server/item.h" #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" @@ -140,16 +139,20 @@ void Monster::perform() int hit = performAttack(mTarget, dmg); - if (! mCurrentAttack->scriptFunction.empty() + if (! mCurrentAttack->scriptEvent.empty() && hit > -1) { - Script *script = ScriptManager::currentState(); - script->setMap(getMap()); - script->prepare(mCurrentAttack->scriptFunction); - script->push(this); - script->push(mTarget); - script->push(hit); - script->execute(); + Script::Ref function = mSpecy->getEventCallback(mCurrentAttack->scriptEvent); + if (function.isValid()) + { + Script *script = ScriptManager::currentState(); + script->setMap(getMap()); + script->prepare(function); + script->push(this); + script->push(mTarget); + script->push(hit); + script->execute(); + } } } } @@ -180,11 +183,14 @@ void Monster::update() return; } - Script *script = ScriptManager::currentState(); - script->setMap(getMap()); - script->prepare("update_monster"); - script->push(this); - script->execute(); + if (mSpecy->getUpdateCallback().isValid()) + { + Script *script = ScriptManager::currentState(); + script->setMap(getMap()); + script->prepare(mSpecy->getUpdateCallback()); + script->push(this); + script->execute(); + } // Cancel the rest when we are currently performing an attack if (isTimerRunning(T_M_ATTACK_TIME)) diff --git a/src/game-server/monster.h b/src/game-server/monster.h index 37bbe355..5ccabfa9 100644 --- a/src/game-server/monster.h +++ b/src/game-server/monster.h @@ -28,6 +28,8 @@ #include "game-server/being.h" #include "game-server/eventlistener.h" #include "common/defines.h" +#include "scripting/script.h" +#include "utils/string.h" class ItemClass; class Script; @@ -57,7 +59,7 @@ struct MonsterAttack int preDelay; int aftDelay; int range; - std::string scriptFunction; + std::string scriptEvent; }; typedef std::vector< MonsterAttack *> MonsterAttacks; @@ -197,6 +199,18 @@ class MonsterClass /** Returns script filename */ const std::string &getScript() const { return mScript; } + void setUpdateCallback(Script *script) + { script->assignCallback(mUpdateCallback); } + + void setEventCallback(const std::string &event, Script *script) + { script->assignCallback(mEventCallbacks[event]); } + + Script::Ref getUpdateCallback() const + { return mUpdateCallback; } + + Script::Ref getEventCallback(const std::string &event) const + { return mEventCallbacks.value(event); } + private: unsigned short mId; std::string mName; @@ -217,6 +231,17 @@ class MonsterClass MonsterAttacks mAttacks; std::string mScript; + /** + * A reference to the script function that is called each update. + */ + Script::Ref mUpdateCallback; + + /** + * Named event callbacks. Currently only used for custom attack + * callbacks. + */ + utils::NameMap<Script::Ref> mEventCallbacks; + friend class MonsterManager; friend class Monster; }; diff --git a/src/game-server/monstermanager.cpp b/src/game-server/monstermanager.cpp index bebb74a3..7612ddc1 100644 --- a/src/game-server/monstermanager.cpp +++ b/src/game-server/monstermanager.cpp @@ -243,9 +243,8 @@ void MonsterManager::initialize() att->preDelay = XML::getProperty(subnode, "pre-delay", 1); att->aftDelay = XML::getProperty(subnode, "aft-delay", 0); att->range = XML::getProperty(subnode, "range", 0); - att->scriptFunction = XML::getProperty(subnode, - "script-function", - std::string()); + att->scriptEvent = XML::getProperty(subnode, "script-event", + std::string()); std::string sElement = XML::getProperty(subnode, "element", "neutral"); att->element = elementFromString(sElement); diff --git a/src/game-server/statuseffect.cpp b/src/game-server/statuseffect.cpp index 32e0d621..c101bc02 100644 --- a/src/game-server/statuseffect.cpp +++ b/src/game-server/statuseffect.cpp @@ -20,9 +20,8 @@ #include "game-server/statuseffect.h" -#include "scripting/script.h" -#include "scripting/scriptmanager.h" #include "game-server/being.h" +#include "scripting/scriptmanager.h" StatusEffect::StatusEffect(int id): mId(id) @@ -35,13 +34,13 @@ StatusEffect::~StatusEffect() void StatusEffect::tick(Being *target, int count) { - if (!mTickFunction.empty()) + if (mTickCallback.isValid()) { - Script *script = ScriptManager::currentState(); - script->setMap(target->getMap()); - script->prepare(mTickFunction); - script->push(target); - script->push(count); - script->execute(); + Script *s = ScriptManager::currentState(); + s->setMap(target->getMap()); + s->prepare(mTickCallback); + s->push(target); + s->push(count); + s->execute(); } } diff --git a/src/game-server/statuseffect.h b/src/game-server/statuseffect.h index 2b7a36f8..7da5fdf9 100644 --- a/src/game-server/statuseffect.h +++ b/src/game-server/statuseffect.h @@ -21,7 +21,7 @@ #ifndef STATUSEFFECT_H #define STATUSEFFECT_H -#include <string> +#include "scripting/script.h" class Being; @@ -36,12 +36,12 @@ class StatusEffect int getId() const { return mId; } - void setTickFunction(const std::string &tickFunction) - { mTickFunction = tickFunction; } + void setTickCallback(Script *script) + { script->assignCallback(mTickCallback); } private: int mId; - std::string mTickFunction; + Script::Ref mTickCallback; }; #endif diff --git a/src/game-server/statusmanager.cpp b/src/game-server/statusmanager.cpp index 15203d65..7769ef0f 100644 --- a/src/game-server/statusmanager.cpp +++ b/src/game-server/statusmanager.cpp @@ -33,6 +33,7 @@ typedef std::map< int, StatusEffect * > StatusEffectsMap; static StatusEffectsMap statusEffects; +static utils::NameMap<StatusEffect*> statusEffectsByName; static std::string statusReferenceFile; void StatusManager::initialize(const std::string &file) @@ -59,7 +60,7 @@ void StatusManager::reload() if (!xmlStrEqual(node->name, BAD_CAST "status-effect")) continue; - int id = XML::getProperty(node, "id", 0); + const int id = XML::getProperty(node, "id", 0); if (id < 1) { LOG_WARN("Status Manager: The status ID: " << id << " in " @@ -68,9 +69,24 @@ void StatusManager::reload() continue; } + StatusEffect *statusEffect = new StatusEffect(id); + + const std::string name = XML::getProperty(node, "name", + std::string()); + if (!name.empty()) + { + if (statusEffectsByName.contains(name)) + { + LOG_WARN("StatusManager: name not unique for status effect " + << id); + } + else + { + statusEffectsByName.insert(name, statusEffect); + } + } + 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)); @@ -84,8 +100,6 @@ void StatusManager::reload() modifiers.setAttributeValue(CHAR_ATTR_INTELLIGENCE, XML::getProperty(node, "intelligence", 0)); modifiers.setAttributeValue(CHAR_ATTR_WILLPOWER, XML::getProperty(node, "willpower", 0)); */ - StatusEffect *statusEffect = new StatusEffect(id); - statusEffect->setTickFunction(tickFunction); if (!scriptFile.empty()) { std::stringstream filename; @@ -112,11 +126,16 @@ void StatusManager::deinitialize() delete i->second; } statusEffects.clear(); + statusEffectsByName.clear(); } StatusEffect *StatusManager::getStatus(int statusId) { StatusEffectsMap::const_iterator i = statusEffects.find(statusId); - return i != statusEffects.end() ? i->second : NULL; + return i != statusEffects.end() ? i->second : 0; } +StatusEffect *StatusManager::getStatusByName(const std::string &name) +{ + return statusEffectsByName.value(name); +} diff --git a/src/game-server/statusmanager.h b/src/game-server/statusmanager.h index fc09adb5..8ab321d1 100644 --- a/src/game-server/statusmanager.h +++ b/src/game-server/statusmanager.h @@ -46,6 +46,11 @@ namespace StatusManager * Gets the status having the given ID. */ StatusEffect *getStatus(int statusId); + + /** + * Gets the status having the given name. + */ + StatusEffect *getStatusByName(const std::string &name); } #endif // STATUSMANAGER_H diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 3d59ab98..c6a75d90 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -46,6 +46,8 @@ extern "C" { #include "game-server/postman.h" #include "game-server/quest.h" #include "game-server/state.h" +#include "game-server/statuseffect.h" +#include "game-server/statusmanager.h" #include "game-server/trigger.h" #include "net/messageout.h" #include "scripting/luautil.h" @@ -210,6 +212,27 @@ static int on_get_special_recharge_cost(lua_State *s) return 0; } +static int get_item_class(lua_State *s) +{ + const char *name = luaL_checkstring(s, 1); + LuaItemClass::push(s, itemManager->getItemByName(name)); + return 1; +} + +static int get_monster_class(lua_State *s) +{ + const char *name = luaL_checkstring(s, 1); + LuaMonsterClass::push(s, monsterManager->getMonsterByName(name)); + return 1; +} + +static int get_status_effect(lua_State *s) +{ + const char *name = luaL_checkstring(s, 1); + LuaStatusEffect::push(s, StatusManager::getStatusByName(name)); + return 1; +} + /** * mana.npc_message(NPC*, Character*, string): void * Callback for sending a NPC_MESSAGE. @@ -1507,6 +1530,23 @@ static int posY(lua_State *s) return 0; } +static int monster_class_on_update(lua_State *s) +{ + MonsterClass *monsterClass = LuaMonsterClass::check(s, 1); + luaL_checktype(s, 2, LUA_TFUNCTION); + monsterClass->setUpdateCallback(getScript(s)); + return 0; +} + +static int monster_class_on(lua_State *s) +{ + MonsterClass *monsterClass = LuaMonsterClass::check(s, 1); + const char *event = luaL_checkstring(s, 2); + luaL_checktype(s, 3, LUA_TFUNCTION); + monsterClass->setEventCallback(event, getScript(s)); + return 0; +} + /** * mana.monster_create(int id || string name, int x, int y): Monster* * Callback for creating a monster on the current map. @@ -1620,32 +1660,6 @@ static int monster_remove(lua_State *s) } /** - * mana.monster_load_script(Monster*, string script_filename): void - * loads a LUA script for the given monster. - */ -static int monster_load_script(lua_State *s) -{ - Monster *m = getMonster(s, 1); - if (!m) - { - raiseScriptError(s, "monster_load_script called " - "for a nonexistent monster."); - return 0; - } - - const char *scriptName = luaL_checkstring(s, 2); - if (scriptName[0] == 0) - { - raiseScriptError(s, "monster_load_script called " - "with empty script file name."); - return 0; - } - - m->loadScript(scriptName); - return 0; -} - -/** * mana.chr_get_chest(Character*, string): nil or string * Callback for getting a quest variable. Starts a recovery and returns * immediatly, if the variable is not known yet. @@ -1959,9 +1973,8 @@ static int chr_get_post(lua_State *s) /** * mana.being_register(Being*): void - * Makes the server call the lua functions deathEvent - * and removeEvent when the being dies or is removed - * from the map. + * Makes the server call the on_being_death and on_being_remove callbacks + * when the being dies or is removed from the map. */ static int being_register(lua_State *s) { @@ -2453,6 +2466,15 @@ static int is_walkable(lua_State *s) return 1; } +static int item_class_on(lua_State *s) +{ + ItemClass *itemClass = LuaItemClass::check(s, 1); + const char *event = luaL_checkstring(s, 2); + luaL_checktype(s, 3, LUA_TFUNCTION); + itemClass->setEventCallback(event, getScript(s)); + return 0; +} + /** * mana.drop_item(int x, int y, int id || string name[, int number]): bool * Creates an item stack on the floor. @@ -2651,6 +2673,14 @@ static int map_object_get_type(lua_State *s) return 1; } +static int status_effect_on_tick(lua_State *s) +{ + StatusEffect *statusEffect = LuaStatusEffect::check(s, 1); + luaL_checktype(s, 2, LUA_TFUNCTION); + statusEffect->setTickCallback(getScript(s)); + return 0; +} + /** * mana.announce(text [, sender]) * Does a global announce @@ -2719,6 +2749,9 @@ LuaScript::LuaScript(): { "on_craft", &on_craft }, { "on_use_special", &on_use_special }, { "on_get_special_recharge_cost", &on_get_special_recharge_cost }, + { "get_item_class", &get_item_class }, + { "get_monster_class", &get_monster_class }, + { "get_status_effect", &get_status_effect }, { "npc_create", &npc_create }, { "npc_message", &npc_message }, { "npc_choice", &npc_choice }, @@ -2761,7 +2794,6 @@ LuaScript::LuaScript(): { "monster_get_name", &monster_get_name }, { "monster_change_anger", &monster_change_anger }, { "monster_remove", &monster_remove }, - { "monster_load_script", &monster_load_script }, { "being_apply_status", &being_apply_status }, { "being_remove_status", &being_remove_status }, { "being_has_status", &being_has_status }, @@ -2809,6 +2841,11 @@ LuaScript::LuaScript(): luaL_register(mState, "mana", callbacks); lua_pop(mState, 1); // pop the 'mana' table + static luaL_Reg const members_ItemClass[] = { + { "on", &item_class_on }, + { NULL, NULL } + }; + static luaL_Reg const members_MapObject[] = { { "property", &map_object_get_property }, { "bounds", &map_object_get_bounds }, @@ -2817,7 +2854,21 @@ LuaScript::LuaScript(): { NULL, NULL } }; + static luaL_Reg const members_MonsterClass[] = { + { "on_update", &monster_class_on_update }, + { "on", &monster_class_on }, + { NULL, NULL } + }; + + static luaL_Reg const members_StatusEffect[] = { + { "on_tick", &status_effect_on_tick }, + { NULL, NULL } + }; + + LuaItemClass::registerType(mState, "ItemClass", members_ItemClass); LuaMapObject::registerType(mState, "MapObject", members_MapObject); + LuaMonsterClass::registerType(mState, "MonsterClass", members_MonsterClass); + LuaStatusEffect::registerType(mState, "StatusEffect", members_StatusEffect); // Make script object available to callback functions. lua_pushlightuserdata(mState, const_cast<char *>(®istryKey)); diff --git a/src/scripting/luautil.h b/src/scripting/luautil.h index 049276fe..2fc7543a 100644 --- a/src/scripting/luautil.h +++ b/src/scripting/luautil.h @@ -31,12 +31,14 @@ extern "C" { #include <set> #include <vector> -#include "game-server/map.h" - class Being; -class NPC; class Character; +class ItemClass; +class MapObject; class Monster; +class MonsterClass; +class NPC; +class StatusEffect; class Thing; // Report script errors and interrupt the script. @@ -105,10 +107,16 @@ public: /** * Pushes a userdata reference to the given object on the stack. Either by * creating one, or reusing an existing one. + * + * When a null-pointer is passed for \a object, the value 'nil' is pushed. */ - static int push(lua_State *s, T *object) + static void push(lua_State *s, T *object) { - if (!UserDataCache::retrieve(s, object)) + if (!object) + { + lua_pushnil(s); + } + else if (!UserDataCache::retrieve(s, object)) { void *userData = lua_newuserdata(s, sizeof(T*)); * static_cast<T**>(userData) = object; @@ -118,8 +126,6 @@ public: UserDataCache::insert(s, object); } - - return 1; } /** @@ -138,7 +144,10 @@ private: template <typename T> const char * LuaUserData<T>::mTypeName; +typedef LuaUserData<ItemClass> LuaItemClass; typedef LuaUserData<MapObject> LuaMapObject; +typedef LuaUserData<MonsterClass> LuaMonsterClass; +typedef LuaUserData<StatusEffect> LuaStatusEffect; NPC *getNPC(lua_State *s, int p); diff --git a/src/utils/string.h b/src/utils/string.h index a21081d5..882b1b09 100644 --- a/src/utils/string.h +++ b/src/utils/string.h @@ -105,6 +105,11 @@ namespace utils return result != mMap.end() ? result->second : mDefault; } + T &operator[](const std::string &name) + { + return mMap[toLower(name)]; + } + bool contains(const std::string &name) const { return mMap.find(toLower(name)) != mMap.end(); |