diff --git a/zone/CMakeLists.txt b/zone/CMakeLists.txt index afa58f50c..0c2c9bd63 100644 --- a/zone/CMakeLists.txt +++ b/zone/CMakeLists.txt @@ -51,6 +51,7 @@ SET(zone_sources lua_item.cpp lua_iteminst.cpp lua_mob.cpp + lua_mod.cpp lua_npc.cpp lua_object.cpp lua_packet.cpp @@ -174,6 +175,7 @@ SET(zone_headers lua_item.h lua_iteminst.h lua_mob.h + lua_mod.h lua_npc.h lua_object.h lua_packet.h diff --git a/zone/attack.cpp b/zone/attack.cpp index b0465553a..583f8ab01 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1306,6 +1306,16 @@ void Mob::DoAttack(Mob *other, DamageHitInfo &hit, ExtraAttackOptions *opts) // IsFromSpell added to allow spell effects to use Attack. (Mainly for the Rampage AA right now.) bool Client::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) { +#ifdef LUA_EQEMU + bool lua_ret = false; + bool ignoreDefault = false; + lua_ret = LuaParser::Instance()->ClientAttack(this, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + if (ignoreDefault) { + return lua_ret; + } +#endif + if (!other) { SetTarget(nullptr); Log(Logs::General, Logs::Error, "A null Mob object was passed to Client::Attack() for evaluation!"); @@ -1829,6 +1839,16 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) { +#ifdef LUA_EQEMU + bool lua_ret = false; + bool ignoreDefault = false; + lua_ret = LuaParser::Instance()->NPCAttack(this, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + if (ignoreDefault) { + return lua_ret; + } +#endif + if (!other) { SetTarget(nullptr); Log(Logs::General, Logs::Error, "A null Mob object was passed to NPC::Attack() for evaluation!"); @@ -2827,6 +2847,8 @@ uint8 Mob::GetWeaponDamageBonus(const EQEmu::ItemData *weapon, bool offhand) } return damage_bonus; } + + return 0; } int Mob::GetHandToHandDamage(void) diff --git a/zone/bot.cpp b/zone/bot.cpp index c66fdeb56..683faf1f2 100644 --- a/zone/bot.cpp +++ b/zone/bot.cpp @@ -22,6 +22,7 @@ #include "object.h" #include "doors.h" #include "quest_parser_collection.h" +#include "lua_parser.h" #include "../common/string_util.h" #include "../common/say_link.h" @@ -3857,6 +3858,16 @@ void Bot::AddToHateList(Mob* other, uint32 hate, int32 damage, bool iYellForHelp } bool Bot::Attack(Mob* other, int Hand, bool FromRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts) { +#ifdef LUA_EQEMU + bool lua_ret = false; + bool ignoreDefault = false; + lua_ret = LuaParser::Instance()->BotAttack(this, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + if (ignoreDefault) { + return lua_ret; + } +#endif + if (!other) { SetTarget(nullptr); Log(Logs::General, Logs::Error, "A null Mob object was passed to Bot::Attack for evaluation!"); diff --git a/zone/lua_mod.cpp b/zone/lua_mod.cpp new file mode 100644 index 000000000..48dc29e66 --- /dev/null +++ b/zone/lua_mod.cpp @@ -0,0 +1,778 @@ +#include "lua.hpp" +#include +#include + +#include "../common/spdat.h" +#include "masterentity.h" +#include "questmgr.h" +#include "zone.h" +#include "zone_config.h" + +#include "lua_parser.h" +#include "lua_mod.h" +#include "lua_bit.h" +#include "lua_entity.h" +#include "lua_item.h" +#include "lua_iteminst.h" +#include "lua_mob.h" +#include "lua_hate_list.h" +#include "lua_client.h" +#include "lua_inventory.h" +#include "lua_npc.h" +#include "lua_spell.h" +#include "lua_entity_list.h" +#include "lua_group.h" +#include "lua_raid.h" +#include "lua_corpse.h" +#include "lua_object.h" +#include "lua_door.h" +#include "lua_spawn.h" +#include "lua_packet.h" +#include "lua_general.h" +#include "lua_encounter.h" +#include "lua_stat_bonuses.h" + +void LuaMod::Init() +{ + m_has_client_attack = parser_->HasFunction("ClientAttack", package_name_); + m_has_npc_attack = parser_->HasFunction("NPCAttack", package_name_); + m_has_bot_attack = parser_->HasFunction("BotAttack", package_name_); + m_has_melee_mitigation = parser_->HasFunction("MeleeMitigation", package_name_); + m_has_apply_damage_table = parser_->HasFunction("ApplyDamageTable", package_name_); + m_has_avoid_damage = parser_->HasFunction("AvoidDamage", package_name_); + m_has_check_hit_chance = parser_->HasFunction("CheckHitChance", package_name_); + m_has_do_special_attack_damage = parser_->HasFunction("DoSpecialAttackDamage", package_name_); + m_has_do_ranged_attack_dmg = parser_->HasFunction("DoRangedAttackDmg", package_name_); + m_has_do_archery_attack_dmg = parser_->HasFunction("DoArcheryAttackDmg", package_name_); + m_has_do_throwing_attack_dmg = parser_->HasFunction("DoThrowingAttackDmg", package_name_); + m_has_do_melee_skill_attack_dmg = parser_->HasFunction("DoMeleeSkillAttackDmg", package_name_); +} + +void PutDamageHitInfo(lua_State *L, luabind::adl::object &e, DamageHitInfo &hit) { + 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["hit"] = lua_hit; +} + +void GetDamageHitInfo(luabind::adl::object &ret, DamageHitInfo &hit) { + auto luaHitTable = ret["hit"]; + if (luabind::type(luaHitTable) == LUA_TTABLE) { + auto base_damage = luaHitTable["base_damage"]; + auto damage_done = luaHitTable["damage_done"]; + auto offense = luaHitTable["offense"]; + auto tohit = luaHitTable["tohit"]; + auto hand = luaHitTable["hand"]; + auto skill = luaHitTable["skill"]; + + if (luabind::type(base_damage) == LUA_TNUMBER) { + hit.base_damage = luabind::object_cast(base_damage); + } + + if (luabind::type(damage_done) == LUA_TNUMBER) { + hit.damage_done = luabind::object_cast(damage_done); + } + + if (luabind::type(offense) == LUA_TNUMBER) { + hit.offense = luabind::object_cast(offense); + } + + if (luabind::type(tohit) == LUA_TNUMBER) { + hit.tohit = luabind::object_cast(tohit); + } + + if (luabind::type(hand) == LUA_TNUMBER) { + hit.hand = luabind::object_cast(hand); + } + + if (luabind::type(skill) == LUA_TNUMBER) { + hit.skill = (EQEmu::skills::SkillType)luabind::object_cast(skill); + } + } +} + +void PutExtraAttackOptions(lua_State *L, luabind::adl::object &e, ExtraAttackOptions *opts) { + 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; + } +} + +void GetExtraAttackOptions(luabind::adl::object &ret, ExtraAttackOptions *opts) { + if (opts) { + auto luaOptsTable = ret["opts"]; + if (luabind::type(luaOptsTable) == LUA_TTABLE) { + auto damage_percent = luaOptsTable["damage_percent"]; + auto damage_flat = luaOptsTable["damage_flat"]; + auto armor_pen_percent = luaOptsTable["armor_pen_percent"]; + auto armor_pen_flat = luaOptsTable["armor_pen_flat"]; + auto crit_percent = luaOptsTable["crit_percent"]; + auto crit_flat = luaOptsTable["crit_flat"]; + auto hate_percent = luaOptsTable["hate_percent"]; + auto hate_flat = luaOptsTable["hate_flat"]; + auto hit_chance = luaOptsTable["hit_chance"]; + auto melee_damage_bonus_flat = luaOptsTable["melee_damage_bonus_flat"]; + auto skilldmgtaken_bonus_flat = luaOptsTable["skilldmgtaken_bonus_flat"]; + + if (luabind::type(damage_percent) == LUA_TNUMBER) { + opts->damage_percent = luabind::object_cast(damage_percent); + } + + if (luabind::type(damage_flat) == LUA_TNUMBER) { + opts->damage_flat = luabind::object_cast(damage_flat); + } + + if (luabind::type(armor_pen_percent) == LUA_TNUMBER) { + opts->armor_pen_percent = luabind::object_cast(armor_pen_percent); + } + + if (luabind::type(armor_pen_flat) == LUA_TNUMBER) { + opts->armor_pen_flat = luabind::object_cast(armor_pen_flat); + } + + if (luabind::type(crit_percent) == LUA_TNUMBER) { + opts->crit_percent = luabind::object_cast(crit_percent); + } + + if (luabind::type(crit_flat) == LUA_TNUMBER) { + opts->crit_flat = luabind::object_cast(crit_flat); + } + + if (luabind::type(hate_percent) == LUA_TNUMBER) { + opts->hate_percent = luabind::object_cast(hate_percent); + } + + if (luabind::type(hate_flat) == LUA_TNUMBER) { + opts->hate_flat = luabind::object_cast(hate_flat); + } + + if (luabind::type(hit_chance) == LUA_TNUMBER) { + opts->hit_chance = luabind::object_cast(hit_chance); + } + + if (luabind::type(melee_damage_bonus_flat) == LUA_TNUMBER) { + opts->melee_damage_bonus_flat = luabind::object_cast(melee_damage_bonus_flat); + } + + if (luabind::type(skilldmgtaken_bonus_flat) == LUA_TNUMBER) { + opts->skilldmgtaken_bonus_flat = luabind::object_cast(skilldmgtaken_bonus_flat); + } + } + } +} + +bool LuaMod::ClientAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + bool retval = false; + + if (!m_has_client_attack) { + return retval; + } + + retval = CommonAttack("ClientAttack", self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + + return retval; +} + +bool LuaMod::NPCAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + bool retval = false; + + if (!m_has_npc_attack) { + return retval; + } + + retval = CommonAttack("NPCAttack", self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + + return retval; +} + +bool LuaMod::BotAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + bool retval = false; + + if (!m_has_bot_attack) { + return retval; + } + + retval = CommonAttack("BotAttack", self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + + return retval; +} + +bool LuaMod::CommonAttack(const std::string &fn, Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) { + bool retval = false; + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, fn.c_str()); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["Hand"] = Hand; + e["bRiposte"] = bRiposte; + e["IsStrikethrough"] = IsStrikethrough; + e["IsFromSpell"] = IsFromSpell; + + PutExtraAttackOptions(L, e, opts); + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return retval; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + + auto returnValueObj = ret["ReturnValue"]; + if (luabind::type(returnValueObj) == LUA_TBOOLEAN) { + retval = luabind::object_cast(returnValueObj); + } + + GetExtraAttackOptions(ret, opts); + } + + return retval; +} + +void LuaMod::MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault) { + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_melee_mitigation) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "MeleeMitigation"); + + Lua_Mob l_self(self); + Lua_Mob l_other(attacker); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + + PutDamageHitInfo(L, e, hit); + PutExtraAttackOptions(L, e, opts); + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + + GetDamageHitInfo(ret, hit); + GetExtraAttackOptions(ret, opts); + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +void LuaMod::ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault) { + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_apply_damage_table) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "ApplyDamageTable"); + + Lua_Mob l_self(self); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + + PutDamageHitInfo(L, e, hit); + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + + GetDamageHitInfo(ret, hit); + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +bool LuaMod::AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &ignoreDefault) { + int start = lua_gettop(L); + ignoreDefault = false; + bool retval = false; + + try { + if (!m_has_avoid_damage) { + return retval; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "AvoidDamage"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + + PutDamageHitInfo(L, e, hit); + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return retval; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + + auto returnValueObj = ret["ReturnValue"]; + if (luabind::type(returnValueObj) == LUA_TBOOLEAN) { + retval = luabind::object_cast(returnValueObj); + } + + GetDamageHitInfo(ret, hit); + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + + return retval; +} + +bool LuaMod::CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &ignoreDefault) { + int start = lua_gettop(L); + ignoreDefault = false; + bool retval = false; + + try { + if (!m_has_check_hit_chance) { + return retval; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "CheckHitChance"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + + PutDamageHitInfo(L, e, hit); + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return retval; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + + auto returnValueObj = ret["ReturnValue"]; + if (luabind::type(returnValueObj) == LUA_TBOOLEAN) { + retval = luabind::object_cast(returnValueObj); + } + + GetDamageHitInfo(ret, hit); + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } + + return retval; +} + +void LuaMod::DoSpecialAttackDamage(Mob *self, Mob *who, EQEmu::skills::SkillType skill, int32 base_damage, int32 min_damage, int32 hate_override, int ReuseTime, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_do_special_attack_damage) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "DoSpecialAttackDamage"); + + Lua_Mob l_self(self); + Lua_Mob l_other(who); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["skill"] = (int)skill; + e["base_damage"] = base_damage; + e["min_damage"] = min_damage; + e["hate_override"] = hate_override; + e["ReuseTime"] = ReuseTime; + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +void LuaMod::DoRangedAttackDmg(Mob *self, Mob *other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_do_ranged_attack_dmg) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "DoRangedAttackDmg"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["Launch"] = Launch; + e["damage_mod"] = damage_mod; + e["chance_mod"] = chance_mod; + e["skill"] = (int)skill; + e["speed"] = speed; + e["IDFile"] = IDFile ? IDFile : ""; + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +void LuaMod::DoArcheryAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemInstance *Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, uint32 ammo_id, const EQEmu::ItemData *AmmoItem, int AmmoSlot, float speed, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_do_archery_attack_dmg) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "DoArcheryAttackDmg"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + Lua_ItemInst l_RangeWeapon(const_cast(RangeWeapon)); + Lua_ItemInst l_Ammo(const_cast(Ammo)); + Lua_Item l_AmmoItem(const_cast(AmmoItem)); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["RangeWeapon"] = l_RangeWeapon; + e["Ammo"] = l_Ammo; + e["weapon_damage"] = weapon_damage; + e["chance_mod"] = chance_mod; + e["focus"] = focus; + e["ReuseTime"] = ReuseTime; + e["range_id"] = range_id; + e["ammo_id"] = ammo_id; + e["AmmoItem"] = l_AmmoItem; + e["AmmoSlot"] = AmmoSlot; + e["speed"] = speed; + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +void LuaMod::DoThrowingAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemData *AmmoItem, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, int AmmoSlot, float speed, bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_do_throwing_attack_dmg) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "DoThrowingAttackDmg"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + Lua_ItemInst l_RangeWeapon(const_cast(RangeWeapon)); + Lua_Item l_AmmoItem(const_cast(AmmoItem)); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["RangeWeapon"] = l_RangeWeapon; + e["weapon_damage"] = weapon_damage; + e["chance_mod"] = chance_mod; + e["focus"] = focus; + e["ReuseTime"] = ReuseTime; + e["range_id"] = range_id; + e["AmmoItem"] = l_AmmoItem; + e["AmmoSlot"] = AmmoSlot; + e["speed"] = speed; + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + +void LuaMod::DoMeleeSkillAttackDmg(Mob *self, Mob *other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime, + bool &ignoreDefault) +{ + int start = lua_gettop(L); + ignoreDefault = false; + + try { + if (!m_has_do_melee_skill_attack_dmg) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "DoMeleeSkillAttackDmg"); + + Lua_Mob l_self(self); + Lua_Mob l_other(other); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["other"] = l_other; + e["weapon_damage"] = weapon_damage; + e["skillinuse"] = (int)skillinuse; + e["chance_mod"] = chance_mod; + e["focus"] = focus; + e["CanRiposte"] = CanRiposte; + e["ReuseTime"] = ReuseTime; + + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 1); + return; + } + + if (lua_type(L, -1) == LUA_TTABLE) { + luabind::adl::object ret(luabind::from_stack(L, -1)); + auto IgnoreDefaultObj = ret["IgnoreDefault"]; + if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { + ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} \ No newline at end of file diff --git a/zone/lua_mod.h b/zone/lua_mod.h new file mode 100644 index 000000000..73792e25c --- /dev/null +++ b/zone/lua_mod.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +struct lua_State; + +class LuaParser; +class LuaMod +{ +public: + LuaMod(lua_State *ls, LuaParser *lp, const std::string &package_name) { + L = ls; + parser_ = lp; + package_name_ = package_name; + Init(); + } + ~LuaMod() { } + void Init(); + + bool ClientAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + bool NPCAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + bool BotAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + bool CommonAttack(const std::string &fn, Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + void MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault); + void ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault); + bool AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &ignoreDefault); + bool CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &ignoreDefault); + void DoSpecialAttackDamage(Mob *self, Mob *who, EQEmu::skills::SkillType skill, int32 base_damage, int32 min_damage, int32 hate_override, int ReuseTime, bool &ignoreDefault); + void DoRangedAttackDmg(Mob *self, Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile, bool &ignoreDefault); + void DoArcheryAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemInstance *Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, uint32 ammo_id, const EQEmu::ItemData *AmmoItem, int AmmoSlot, float speed, bool &ignoreDefault); + void DoThrowingAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemData *AmmoItem, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, int AmmoSlot, float speed, bool &ignoreDefault); + void DoMeleeSkillAttackDmg(Mob *self, Mob *other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime, + bool &ignoreDefault); +private: + LuaParser *parser_; + lua_State *L; + std::string package_name_; + + bool m_has_client_attack; + bool m_has_npc_attack; + bool m_has_bot_attack; + bool m_has_melee_mitigation; + bool m_has_apply_damage_table; + bool m_has_avoid_damage; + bool m_has_check_hit_chance; + bool m_has_do_special_attack_damage; + bool m_has_do_ranged_attack_dmg; + bool m_has_do_archery_attack_dmg; + bool m_has_do_throwing_attack_dmg; + bool m_has_do_melee_skill_attack_dmg; +}; diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 12a02623e..8748494c7 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -960,7 +960,7 @@ void LuaParser::ReloadQuests() { char file_name[256] = { 0 }; while (fgets(file_name, 256, load_order) != nullptr) { LoadScript("mods/" + std::string(file_name), file_name); - mods_.push_back(file_name); + mods_.push_back(LuaMod(L, this, file_name)); } fclose(load_order); @@ -971,7 +971,6 @@ void LuaParser::ReloadQuests() { if (n > 0) { lua_pop(L, n); } - } void LuaParser::LoadScript(std::string filename, std::string package_name) { @@ -1256,355 +1255,6 @@ int LuaParser::DispatchEventSpell(QuestEventID evt, NPC* npc, Client *client, ui return ret; } -void PutDamageHitInfo(lua_State *L, luabind::adl::object &e, DamageHitInfo &hit) { - 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["hit"] = lua_hit; -} - -void GetDamageHitInfo(luabind::adl::object &ret, DamageHitInfo &hit) { - auto luaHitTable = ret["hit"]; - if (luabind::type(luaHitTable) == LUA_TTABLE) { - auto base_damage = luaHitTable["base_damage"]; - auto damage_done = luaHitTable["damage_done"]; - auto offense = luaHitTable["offense"]; - auto tohit = luaHitTable["tohit"]; - auto hand = luaHitTable["hand"]; - auto skill = luaHitTable["skill"]; - - if (luabind::type(base_damage) == LUA_TNUMBER) { - hit.base_damage = luabind::object_cast(base_damage); - } - - if (luabind::type(damage_done) == LUA_TNUMBER) { - hit.damage_done = luabind::object_cast(damage_done); - } - - if (luabind::type(offense) == LUA_TNUMBER) { - hit.offense = luabind::object_cast(offense); - } - - if (luabind::type(tohit) == LUA_TNUMBER) { - hit.tohit = luabind::object_cast(tohit); - } - - if (luabind::type(hand) == LUA_TNUMBER) { - hit.hand = luabind::object_cast(hand); - } - - if (luabind::type(skill) == LUA_TNUMBER) { - hit.skill = (EQEmu::skills::SkillType)luabind::object_cast(skill); - } - } -} - -void PutExtraAttackOptions(lua_State *L, luabind::adl::object &e, ExtraAttackOptions *opts) { - 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; - } -} - -void GetExtraAttackOptions(luabind::adl::object &ret, ExtraAttackOptions *opts) { - if (opts) { - auto luaOptsTable = ret["opts"]; - if (luabind::type(luaOptsTable) == LUA_TTABLE) { - auto damage_percent = luaOptsTable["damage_percent"]; - auto damage_flat = luaOptsTable["damage_flat"]; - auto armor_pen_percent = luaOptsTable["armor_pen_percent"]; - auto armor_pen_flat = luaOptsTable["armor_pen_flat"]; - auto crit_percent = luaOptsTable["crit_percent"]; - auto crit_flat = luaOptsTable["crit_flat"]; - auto hate_percent = luaOptsTable["hate_percent"]; - auto hate_flat = luaOptsTable["hate_flat"]; - auto hit_chance = luaOptsTable["hit_chance"]; - auto melee_damage_bonus_flat = luaOptsTable["melee_damage_bonus_flat"]; - auto skilldmgtaken_bonus_flat = luaOptsTable["skilldmgtaken_bonus_flat"]; - - if (luabind::type(damage_percent) == LUA_TNUMBER) { - opts->damage_percent = luabind::object_cast(damage_percent); - } - - if (luabind::type(damage_flat) == LUA_TNUMBER) { - opts->damage_flat = luabind::object_cast(damage_flat); - } - - if (luabind::type(armor_pen_percent) == LUA_TNUMBER) { - opts->armor_pen_percent = luabind::object_cast(armor_pen_percent); - } - - if (luabind::type(armor_pen_flat) == LUA_TNUMBER) { - opts->armor_pen_flat = luabind::object_cast(armor_pen_flat); - } - - if (luabind::type(crit_percent) == LUA_TNUMBER) { - opts->crit_percent = luabind::object_cast(crit_percent); - } - - if (luabind::type(crit_flat) == LUA_TNUMBER) { - opts->crit_flat = luabind::object_cast(crit_flat); - } - - if (luabind::type(hate_percent) == LUA_TNUMBER) { - opts->hate_percent = luabind::object_cast(hate_percent); - } - - if (luabind::type(hate_flat) == LUA_TNUMBER) { - opts->hate_flat = luabind::object_cast(hate_flat); - } - - if (luabind::type(hit_chance) == LUA_TNUMBER) { - opts->hit_chance = luabind::object_cast(hit_chance); - } - - if (luabind::type(melee_damage_bonus_flat) == LUA_TNUMBER) { - opts->melee_damage_bonus_flat = luabind::object_cast(melee_damage_bonus_flat); - } - - if (luabind::type(skilldmgtaken_bonus_flat) == LUA_TNUMBER) { - opts->skilldmgtaken_bonus_flat = luabind::object_cast(skilldmgtaken_bonus_flat); - } - } - } -} - -void LuaParser::MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault) { - int start = lua_gettop(L); - ignoreDefault = false; - - for (auto &mod : mods_) { - try { - if (!HasFunction("MeleeMitigation", mod)) { - continue; - } - - lua_getfield(L, LUA_REGISTRYINDEX, mod.c_str()); - lua_getfield(L, -1, "MeleeMitigation"); - - Lua_Mob l_self(self); - Lua_Mob l_other(attacker); - luabind::adl::object e = luabind::newtable(L); - e["self"] = l_self; - e["other"] = l_other; - - PutDamageHitInfo(L, e, hit); - PutExtraAttackOptions(L, e, opts); - - e.push(L); - - if (lua_pcall(L, 1, 1, 0)) { - std::string error = lua_tostring(L, -1); - AddError(error); - lua_pop(L, 1); - continue; - } - - if (lua_type(L, -1) == LUA_TTABLE) { - luabind::adl::object ret(luabind::from_stack(L, -1)); - auto IgnoreDefaultObj = ret["IgnoreDefault"]; - if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { - ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); - } - - GetDamageHitInfo(ret, hit); - GetExtraAttackOptions(ret, opts); - } - } - catch (std::exception &ex) { - AddError(ex.what()); - } - } - - int end = lua_gettop(L); - int n = end - start; - if (n > 0) { - lua_pop(L, n); - } -} - -void LuaParser::ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault) { - int start = lua_gettop(L); - ignoreDefault = false; - - for (auto &mod : mods_) { - try { - if (!HasFunction("ApplyDamageTable", mod)) { - continue; - } - - lua_getfield(L, LUA_REGISTRYINDEX, mod.c_str()); - lua_getfield(L, -1, "ApplyDamageTable"); - - Lua_Mob l_self(self); - luabind::adl::object e = luabind::newtable(L); - e["self"] = l_self; - - PutDamageHitInfo(L, e, hit); - e.push(L); - - if (lua_pcall(L, 1, 1, 0)) { - std::string error = lua_tostring(L, -1); - AddError(error); - lua_pop(L, 1); - continue; - } - - if (lua_type(L, -1) == LUA_TTABLE) { - luabind::adl::object ret(luabind::from_stack(L, -1)); - auto IgnoreDefaultObj = ret["IgnoreDefault"]; - if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { - ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); - } - - GetDamageHitInfo(ret, hit); - } - } - catch (std::exception &ex) { - AddError(ex.what()); - } - } - - int end = lua_gettop(L); - int n = end - start; - if (n > 0) { - lua_pop(L, n); - } -} - -bool LuaParser::AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &ignoreDefault) { - int start = lua_gettop(L); - ignoreDefault = false; - bool retval = false; - - for (auto &mod : mods_) { - try { - if (!HasFunction("AvoidDamage", mod)) { - continue; - } - - lua_getfield(L, LUA_REGISTRYINDEX, mod.c_str()); - lua_getfield(L, -1, "AvoidDamage"); - - Lua_Mob l_self(self); - Lua_Mob l_other(other); - luabind::adl::object e = luabind::newtable(L); - e["self"] = l_self; - e["other"] = l_other; - - PutDamageHitInfo(L, e, hit); - e.push(L); - - if (lua_pcall(L, 1, 1, 0)) { - std::string error = lua_tostring(L, -1); - AddError(error); - lua_pop(L, 1); - continue; - } - - if (lua_type(L, -1) == LUA_TTABLE) { - luabind::adl::object ret(luabind::from_stack(L, -1)); - auto IgnoreDefaultObj = ret["IgnoreDefault"]; - if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { - ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); - } - - auto returnValueObj = ret["ReturnValue"]; - if (luabind::type(returnValueObj) == LUA_TBOOLEAN) { - retval = luabind::object_cast(returnValueObj); - } - - GetDamageHitInfo(ret, hit); - } - } - catch (std::exception &ex) { - AddError(ex.what()); - } - } - - int end = lua_gettop(L); - int n = end - start; - if (n > 0) { - lua_pop(L, n); - } - - return retval; -} - -bool LuaParser::CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &ignoreDefault) { - int start = lua_gettop(L); - ignoreDefault = false; - bool retval = false; - - for (auto &mod : mods_) { - try { - if (!HasFunction("CheckHitChance", mod)) { - continue; - } - - lua_getfield(L, LUA_REGISTRYINDEX, mod.c_str()); - lua_getfield(L, -1, "CheckHitChance"); - - Lua_Mob l_self(self); - Lua_Mob l_other(other); - luabind::adl::object e = luabind::newtable(L); - e["self"] = l_self; - e["other"] = l_other; - - PutDamageHitInfo(L, e, hit); - e.push(L); - - if (lua_pcall(L, 1, 1, 0)) { - std::string error = lua_tostring(L, -1); - AddError(error); - lua_pop(L, 1); - continue; - } - - if (lua_type(L, -1) == LUA_TTABLE) { - luabind::adl::object ret(luabind::from_stack(L, -1)); - auto IgnoreDefaultObj = ret["IgnoreDefault"]; - if (luabind::type(IgnoreDefaultObj) == LUA_TBOOLEAN) { - ignoreDefault = ignoreDefault || luabind::object_cast(IgnoreDefaultObj); - } - - auto returnValueObj = ret["ReturnValue"]; - if (luabind::type(returnValueObj) == LUA_TBOOLEAN) { - retval = luabind::object_cast(returnValueObj); - } - - GetDamageHitInfo(ret, hit); - } - } - catch (std::exception &ex) { - AddError(ex.what()); - } - } - - int end = lua_gettop(L); - int n = end - start; - if (n > 0) { - lua_pop(L, n); - } - - return retval; -} - QuestEventID LuaParser::ConvertLuaEvent(QuestEventID evt) { switch(evt) { case EVENT_SLAY: @@ -1629,3 +1279,103 @@ QuestEventID LuaParser::ConvertLuaEvent(QuestEventID evt) { } #endif + +bool LuaParser::ClientAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + bool retval = false; + for (auto &mod : mods_) { + retval = mod.ClientAttack(self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + } + + return retval; +} + +bool LuaParser::NPCAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + bool retval = false; + for (auto &mod : mods_) { + retval = mod.NPCAttack(self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + } + + return retval; +} + +bool LuaParser::BotAttack(Mob *self, Mob *other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + bool retval = false; + for (auto &mod : mods_) { + retval = mod.BotAttack(self, other, Hand, bRiposte, IsStrikethrough, IsFromSpell, opts, ignoreDefault); + } + + return retval; +} + +void LuaParser::MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.MeleeMitigation(self, attacker, hit, opts, ignoreDefault); + } +} + +void LuaParser::ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.ApplyDamageTable(self, hit, ignoreDefault); + } +} + +bool LuaParser::AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool & ignoreDefault) +{ + bool retval = false; + for (auto &mod : mods_) { + retval = mod.AvoidDamage(self, other, hit, ignoreDefault); + } + return retval; +} + +bool LuaParser::CheckHitChance(Mob *self, Mob *other, DamageHitInfo &hit, bool &ignoreDefault) +{ + bool retval = false; + for (auto &mod : mods_) { + retval = mod.CheckHitChance(self, other, hit, ignoreDefault); + } + return retval; +} + +void LuaParser::DoSpecialAttackDamage(Mob *self, Mob *who, EQEmu::skills::SkillType skill, int32 base_damage, int32 min_damage, int32 hate_override, int ReuseTime, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.DoSpecialAttackDamage(self, who, skill, base_damage, min_damage, hate_override, ReuseTime, ignoreDefault); + } +} + +void LuaParser::DoRangedAttackDmg(Mob *self, Mob *other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.DoRangedAttackDmg(self, other, Launch, damage_mod, chance_mod, skill, speed, IDFile, ignoreDefault); + } +} + +void LuaParser::DoArcheryAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemInstance *Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, uint32 ammo_id, const EQEmu::ItemData *AmmoItem, int AmmoSlot, float speed, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.DoArcheryAttackDmg(self, other, RangeWeapon, Ammo, weapon_damage, chance_mod, focus, ReuseTime, range_id, ammo_id, AmmoItem, AmmoSlot, speed, ignoreDefault); + } +} + +void LuaParser::DoThrowingAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemData *AmmoItem, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, int AmmoSlot, float speed, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.DoThrowingAttackDmg(self, other, RangeWeapon, AmmoItem, weapon_damage, chance_mod, focus, ReuseTime, range_id, AmmoSlot, speed, ignoreDefault); + } +} + +void LuaParser::DoMeleeSkillAttackDmg(Mob *self, Mob *other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, + int ReuseTime, bool &ignoreDefault) +{ + for (auto &mod : mods_) { + mod.DoMeleeSkillAttackDmg(self, other, weapon_damage, skillinuse, chance_mod, focus, CanRiposte, ReuseTime, ignoreDefault); + } +} diff --git a/zone/lua_parser.h b/zone/lua_parser.h index a0f0fea89..0d1f1256c 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -10,6 +10,7 @@ #include #include "zone_config.h" +#include "lua_mod.h" extern const ZoneConfig *Config; @@ -86,11 +87,24 @@ public: return &inst; } + bool HasFunction(std::string function, std::string package_name); + //Mod Extensions + bool ClientAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + bool NPCAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); + bool BotAttack(Mob *self, Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool IsFromSpell, ExtraAttackOptions *opts, bool &ignoreDefault); void MeleeMitigation(Mob *self, Mob *attacker, DamageHitInfo &hit, ExtraAttackOptions *opts, bool &ignoreDefault); void ApplyDamageTable(Mob *self, DamageHitInfo &hit, bool &ignoreDefault); bool AvoidDamage(Mob *self, Mob *other, DamageHitInfo &hit, bool &ignoreDefault); bool CheckHitChance(Mob *self, Mob* other, DamageHitInfo &hit, bool &ignoreDefault); + void DoSpecialAttackDamage(Mob *self, Mob *who, EQEmu::skills::SkillType skill, int32 base_damage, int32 min_damage, int32 hate_override, int ReuseTime, bool &ignoreDefault); + void DoRangedAttackDmg(Mob *self, Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile, bool &ignoreDefault); + void DoArcheryAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemInstance *Ammo, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, uint32 ammo_id, const EQEmu::ItemData *AmmoItem, int AmmoSlot, float speed, bool &ignoreDefault); + void DoThrowingAttackDmg(Mob *self, Mob *other, const EQEmu::ItemInstance *RangeWeapon, const EQEmu::ItemData *AmmoItem, uint16 weapon_damage, int16 chance_mod, int16 focus, + int ReuseTime, uint32 range_id, int AmmoSlot, float speed, bool &ignoreDefault); + void DoMeleeSkillAttackDmg(Mob *self, Mob *other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime, + bool &ignoreDefault); private: LuaParser(); @@ -109,13 +123,12 @@ private: std::vector *extra_pointers); void LoadScript(std::string filename, std::string package_name); - bool HasFunction(std::string function, std::string package_name); void MapFunctions(lua_State *L); QuestEventID ConvertLuaEvent(QuestEventID evt); std::map vars_; std::map loaded_; - std::vector mods_; + std::vector mods_; lua_State *L; NPCArgumentHandler NPCArgumentDispatch[_LargestEventID]; diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index ef97aee39..ed3f39074 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -23,6 +23,7 @@ #include "entity.h" #include "mob.h" #include "string_ids.h" +#include "lua_parser.h" #include @@ -137,6 +138,15 @@ int Mob::GetBaseSkillDamage(EQEmu::skills::SkillType skill, Mob *target) void Mob::DoSpecialAttackDamage(Mob *who, EQEmu::skills::SkillType skill, int32 base_damage, int32 min_damage, int32 hate_override, int ReuseTime) { +#ifdef LUA_EQEMU + bool ignoreDefault = false; + LuaParser::Instance()->DoSpecialAttackDamage(this, who, skill, base_damage, min_damage, hate_override, ReuseTime, ignoreDefault); + + if (ignoreDefault) { + return; + } +#endif + // this really should go through the same code as normal melee damage to // pick up all the special behavior there @@ -758,6 +768,15 @@ void Mob::DoArcheryAttackDmg(Mob *other, const EQEmu::ItemInstance *RangeWeapon, uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, uint32 ammo_id, const EQEmu::ItemData *AmmoItem, int AmmoSlot, float speed) { +#ifdef LUA_EQEMU + bool ignoreDefault = false; + LuaParser::Instance()->DoArcheryAttackDmg(this, other, RangeWeapon, Ammo, weapon_damage, chance_mod, focus, ReuseTime, range_id, ammo_id, AmmoItem, AmmoSlot, speed, ignoreDefault); + + if (ignoreDefault) { + return; + } +#endif + if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || @@ -1138,6 +1157,15 @@ void NPC::RangedAttack(Mob* other) void NPC::DoRangedAttackDmg(Mob* other, bool Launch, int16 damage_mod, int16 chance_mod, EQEmu::skills::SkillType skill, float speed, const char *IDFile) { +#ifdef LUA_EQEMU + bool ignoreDefault = false; + LuaParser::Instance()->DoRangedAttackDmg(this, other, Launch, damage_mod, chance_mod, skill, speed, IDFile, ignoreDefault); + + if (ignoreDefault) { + return; + } +#endif + if ((other == nullptr || (other->HasDied())) || HasDied() || @@ -1302,6 +1330,15 @@ void Mob::DoThrowingAttackDmg(Mob *other, const EQEmu::ItemInstance *RangeWeapon uint16 weapon_damage, int16 chance_mod, int16 focus, int ReuseTime, uint32 range_id, int AmmoSlot, float speed) { +#ifdef LUA_EQEMU + bool ignoreDefault = false; + LuaParser::Instance()->DoThrowingAttackDmg(this, other, RangeWeapon, AmmoItem, weapon_damage, chance_mod, focus, ReuseTime, range_id, AmmoSlot, speed, ignoreDefault); + + if (ignoreDefault) { + return; + } +#endif + if ((other == nullptr || ((IsClient() && CastToClient()->dead) || (other->IsClient() && other->CastToClient()->dead)) || HasDied() || (!IsAttackAllowed(other)) || (other->GetInvul() || other->GetSpecialAbility(IMMUNE_MELEE)))) { @@ -2086,6 +2123,15 @@ int Mob::TryAssassinate(Mob *defender, EQEmu::skills::SkillType skillInUse) void Mob::DoMeleeSkillAttackDmg(Mob *other, uint16 weapon_damage, EQEmu::skills::SkillType skillinuse, int16 chance_mod, int16 focus, bool CanRiposte, int ReuseTime) { +#ifdef LUA_EQEMU + bool ignoreDefault = false; + LuaParser::Instance()->DoMeleeSkillAttackDmg(this, other, weapon_damage, skillinuse, chance_mod, focus, CanRiposte, ReuseTime, ignoreDefault); + + if (ignoreDefault) { + return; + } +#endif + if (!CanDoSpecialAttack(other)) return;