diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 06486d2db..d65efd183 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -103,6 +103,7 @@ SET(common_sources tinyxml/tinyxml.cpp tinyxml/tinyxmlerror.cpp tinyxml/tinyxmlparser.cpp + util/directory.cpp util/uuid.cpp ) @@ -257,6 +258,7 @@ SET(common_headers tinyxml/tinystr.h tinyxml/tinyxml.h util/memory_stream.h + util/directory.h util/uuid.h ) @@ -366,6 +368,8 @@ SOURCE_GROUP(TinyXML FILES SOURCE_GROUP(Util FILES util/memory_stream.h + util/directory.cpp + util/directory.h util/uuid.cpp util/uuid.h ) diff --git a/zone/attack.cpp b/zone/attack.cpp index 2b9d081bf..0cdce489f 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "water_map.h" #include "worldserver.h" #include "zone.h" +#include "lua_parser.h" #include #include @@ -1237,6 +1238,15 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts) return; Log(Logs::Detail, Logs::Combat, "%s::DoAttack vs %s base %d min %d offense %d tohit %d skill %d", GetName(), other->GetName(), hit.base_damage, hit.min_damage, hit.offense, hit.tohit, hit.skill); + +#ifdef LUA_EQEMU + try { + LuaParser::Instance()->DoAttack(this, other, hit, opts); + } catch(IgnoreDefaultException) { + return; + } +#endif + // check to see if we hit.. if (other->AvoidDamage(this, hit)) { int strike_through = itembonuses.StrikeThrough + spellbonuses.StrikeThrough + aabonuses.StrikeThrough; diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 92f0adbea..1b58379bb 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -10,8 +10,14 @@ #include #include -#include "masterentity.h" #include "../common/spdat.h" +#include "../common/util/directory.h" +#include "masterentity.h" +#include "questmgr.h" +#include "zone.h" +#include "zone_config.h" + +#include "lua_parser.h" #include "lua_bit.h" #include "lua_entity.h" #include "lua_item.h" @@ -31,10 +37,6 @@ #include "lua_spawn.h" #include "lua_packet.h" #include "lua_general.h" -#include "questmgr.h" -#include "zone.h" -#include "zone_config.h" -#include "lua_parser.h" #include "lua_encounter.h" const char *LuaEvents[_LargestEventID] = { @@ -135,6 +137,75 @@ std::map> lua_encounter_events_regi std::map lua_encounters_loaded; std::map lua_encounters; +void LuaParser::DoAttack(Mob *self, Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts) +{ + int start = lua_gettop(L); + bool ignoreDefault = false; + + for (auto &mod : mods_) { + try { + lua_getfield(L, LUA_REGISTRYINDEX, mod.c_str()); + lua_getfield(L, -1, "DoAttack"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + + luabind::adl::object e = luabind::newtable(L); + luabind::adl::object lua_hit = luabind::newtable(L); + lua_hit["base_damage"] = hit.base_damage; + lua_hit["damage_done"] = hit.damage_done; + lua_hit["offense"] = hit.offense; + lua_hit["tohit"] = hit.tohit; + lua_hit["hand"] = hit.hand; + lua_hit["skill"] = (int)hit.skill; + + e["self"] = luabind::adl::object(L, l_self); + e["other"] = luabind::adl::object(L, l_other); + e["hit"] = lua_hit; + if (opts) { + luabind::adl::object lua_opts = luabind::newtable(L); + lua_opts["damage_percent"] = opts->damage_percent; + lua_opts["damage_flat"] = opts->damage_flat; + lua_opts["armor_pen_percent"] = opts->armor_pen_percent; + lua_opts["armor_pen_flat"] = opts->armor_pen_flat; + lua_opts["crit_percent"] = opts->crit_percent; + lua_opts["crit_flat"] = opts->crit_flat; + lua_opts["hate_percent"] = opts->hate_percent; + lua_opts["hate_flat"] = opts->hate_flat; + lua_opts["hit_chance"] = opts->hit_chance; + lua_opts["melee_damage_bonus_flat"] = opts->melee_damage_bonus_flat; + lua_opts["skilldmgtaken_bonus_flat"] = opts->skilldmgtaken_bonus_flat; + e["opts"] = lua_opts; + } + else { + e["opts"] = luabind::nil; + } + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + AddError(error); + } + } + catch (std::exception &ex) { + std::string error = "Lua Exception: "; + error += std::string(ex.what()); + AddError(error); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + } + + if (ignoreDefault) { + throw IgnoreDefaultException(); + } +} + LuaParser::LuaParser() { for(int i = 0; i < _LargestEventID; ++i) { NPCArgumentDispatch[i] = handle_npc_null; @@ -797,6 +868,7 @@ void LuaParser::Init() { void LuaParser::ReloadQuests() { loaded_.clear(); errors_.clear(); + mods_.clear(); lua_encounter_events_registered.clear(); lua_encounters_loaded.clear(); @@ -828,7 +900,7 @@ void LuaParser::ReloadQuests() { #ifdef SANITIZE_LUA_LIBS //io lua_pushnil(L); - lua_setglobal(L, "io"); + //lua_setglobal(L, "io"); //some os/debug are okay some are not lua_getglobal(L, "os"); @@ -949,6 +1021,17 @@ void LuaParser::ReloadQuests() { } } } + + EQ::Directory dir("mods"); + std::vector mods; + dir.GetFiles(mods); + + for (auto &mod : mods) { + if (mod.find_first_of(".lua") != std::string::npos) { + LoadScript("mods/" + mod, mod); + mods_.push_back(mod); + } + } } void LuaParser::LoadScript(std::string filename, std::string package_name) { diff --git a/zone/lua_parser.h b/zone/lua_parser.h index 003c936ce..d23d963dd 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "zone_config.h" @@ -30,9 +31,17 @@ namespace luabind { } } +class IgnoreDefaultException : std::exception { +public: + IgnoreDefaultException() { }; + IgnoreDefaultException(const exception&) { }; + IgnoreDefaultException& operator= (const exception&) { return *this; } + virtual ~IgnoreDefaultException() { } + virtual const char* what() const { return "Ignore Default Action"; } +}; + class LuaParser : public QuestInterface { public: - LuaParser(); ~LuaParser(); virtual int EventNPC(QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, @@ -81,7 +90,19 @@ public: virtual int DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, uint32 spell_id, uint32 extra_data, std::vector *extra_pointers); + static LuaParser* Instance() { + static LuaParser inst; + return &inst; + } + + //Mod Extensions + void DoAttack(Mob *self, Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts); + private: + LuaParser(); + LuaParser(const LuaParser&); + LuaParser& operator=(const LuaParser&); + int _EventNPC(std::string package_name, QuestEventID evt, NPC* npc, Mob *init, std::string data, uint32 extra_data, std::vector *extra_pointers, luabind::adl::object *l_func = nullptr); int _EventPlayer(std::string package_name, QuestEventID evt, Client *client, std::string data, uint32 extra_data, @@ -95,12 +116,12 @@ private: void LoadScript(std::string filename, std::string package_name); bool HasFunction(std::string function, std::string package_name); - void ClearStates(); void MapFunctions(lua_State *L); QuestEventID ConvertLuaEvent(QuestEventID evt); std::map vars_; std::map loaded_; + std::vector mods_; lua_State *L; NPCArgumentHandler NPCArgumentDispatch[_LargestEventID]; diff --git a/zone/net.cpp b/zone/net.cpp index 982b45d02..f51d50bb4 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -391,8 +391,7 @@ int main(int argc, char** argv) { parse = new QuestParserCollection(); #ifdef LUA_EQEMU - auto lua_parser = new LuaParser(); - parse->RegisterQuestInterface(lua_parser, "lua"); + parse->RegisterQuestInterface(LuaParser::Instance(), "lua"); #endif #ifdef EMBPERL @@ -565,10 +564,6 @@ int main(int argc, char** argv) { safe_delete(perl_parser); #endif -#ifdef LUA_EQEMU - safe_delete(lua_parser); -#endif - safe_delete(Config); if (zone != 0)