diff --git a/common/spdat.h b/common/spdat.h index ed180e84f..0a9ce18b9 100644 --- a/common/spdat.h +++ b/common/spdat.h @@ -1312,7 +1312,7 @@ struct SPDat_Spell_Struct // If it is a number between 1-4 it means components[number] is a focus and not to expend it // If it is a valid itemid it means this item is a focus as well // -- NOEXPENDREAGENT1 ... NOEXPENDREAGENT4 -/* 070 */ uint16 formula[EFFECT_COUNT]; // Spell's value formula -- LEVELAFFECT1MOD ... LEVELAFFECT12MOD +/* 070 */ uint32 formula[EFFECT_COUNT]; // Spell's value formula -- LEVELAFFECT1MOD ... LEVELAFFECT12MOD /* 082 */ //int LightType; // probaly another effecttype flag -- LIGHTTYPE /* 083 */ int8 good_effect; //0=detrimental, 1=Beneficial, 2=Beneficial, Group Only -- BENEFICIAL /* 084 */ int activated; // probably another effecttype flag -- ACTIVATED diff --git a/utils/mods/spell_formula.lua b/utils/mods/spell_formula.lua new file mode 100644 index 000000000..fd2e4d738 --- /dev/null +++ b/utils/mods/spell_formula.lua @@ -0,0 +1,92 @@ +function CalcSpellEffectValue_formula(e) + --THE FUNCTIONALITY OF THIS IS FOR ADDING CUSTOM SPELL FORMULAS WITHOUT INTERFERING WITH EXISTING FORMULAS + if (e.formula >= 100000) then + e.IgnoreDefault = true; + else + e.IgnoreDefault = false; + return e; + end + + local result = 0 + local updownsign = 1 + local ubase = e.base_value + local formula = e.formula + local base_value = e.base_value + local max_value = e.max_value + local caster_level = e.caster_level + local spell_id = e.spell_id + local ticsremaining = e.ticsremaining + + if (ubase < 0) then + ubase = 0 - ubase; + end + + if (max_value < base_value and max_value ~= 0) then + --values are calculated down + updownsign = -1; + else + --values are calculated up + updownsign = 1; + end + + --ADD FORMULAS HERE NO NEED TO TOUCH OTHER CODE UNLESS YOU KNOW WHAT YOU ARE DOING!!! + --FORMULA NUMBERS 100,000+++ are considered "custom" and other spells will use normal logic from source!!! + local switch = { + [100000] = function () + result = updownsign * (ubase + (e.self:GetSTR()/2)); --Half strength added to damage! + end, + [100001] = function () + result = (updownsign * (ubase + (caster_level * 2))) * math.random(1,caster_level); -- multiplies final damage randomly from 1 up to caster level! + end, + } + + eq.log_spells( + string.format("[Mob::CalcSpellEffectValue_formula] spell [%i] formula [%i] base [%i] max [%i] lvl [%i] Up/Down [%i]", + e.spell_id, + e.formula, + e.base_value, + e.max_value, + e.caster_level, + updownsign + ) + ); + + local f = switch[e.formula] + if (f) then + f() + else + result = ubase; --DEFAULT YOU MAY CHANGE THIS TO WHATEVER YOU WISH BUT WILL ONLY CHANGE CUSTOM FORMULAS above 100,000 THAT AREN'T IN THE TABLE ABOVE! + end + + local oresult = result; + + --now check result against the allowed maximum + if (max_value ~= 0) then + if (updownsign == 1) then + if (result > max_value) then + result = max_value; + end + else + if (result < max_value) then + result = max_value; + end + end + end + + --if base is less than zero, then the result need to be negative too + if (base_value < 0 and result > 0) then + result = result * -1; + end + + eq.log_spells( + string.format("[Mob::CalcSpellEffectValue_formula] Result: [%i] (orig [%i]) cap [%i]", + result, + oresult, + max_value + ) + ); + + e.ReturnValue = result; + return e; +end + \ No newline at end of file diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index 03fbc3f47..069403a02 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -1580,6 +1580,10 @@ void lua_log_combat(std::string message) { Log(Logs::General, Logs::Combat, message.c_str()); } +void lua_log_spells(std::string message) { + Log(Logs::General, Logs::Spells, message.c_str()); +} + void lua_update_zone_header(std::string type, std::string value) { quest_manager.UpdateZoneHeader(type, value); } @@ -4142,6 +4146,7 @@ luabind::scope lua_register_general() { luabind::def("debug", (void(*)(std::string))&lua_debug), luabind::def("debug", (void(*)(std::string, int))&lua_debug), luabind::def("log_combat", (void(*)(std::string))&lua_log_combat), + luabind::def("log_spells", (void(*)(std::string))&lua_log_spells), luabind::def("seconds_to_time", &lua_seconds_to_time), luabind::def("time_to_seconds", &lua_time_to_seconds), luabind::def("get_hex_color_code", &lua_get_hex_color_code), diff --git a/zone/lua_mod.cpp b/zone/lua_mod.cpp index 84c063dbf..9558563a3 100644 --- a/zone/lua_mod.cpp +++ b/zone/lua_mod.cpp @@ -45,6 +45,7 @@ void LuaMod::Init() m_has_get_exp_for_level = parser_->HasFunction("GetEXPForLevel", package_name_); m_has_get_experience_for_kill = parser_->HasFunction("GetExperienceForKill", package_name_); m_has_common_outgoing_hit_success = parser_->HasFunction("CommonOutgoingHitSuccess", package_name_); + m_has_calc_spell_effect_value_formula = parser_->HasFunction("CalcSpellEffectValue_formula", package_name_); } void PutDamageHitInfo(lua_State *L, luabind::adl::object &e, DamageHitInfo &hit) { @@ -632,4 +633,59 @@ void LuaMod::GetExperienceForKill(Client *self, Mob *against, uint64 &returnValu } } +void LuaMod::CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, int64 &returnValue, bool &ignoreDefault) +{ + int start = lua_gettop(L); + int64 retval = 0; + + try { + if (!m_has_calc_spell_effect_value_formula) { + return; + } + + lua_getfield(L, LUA_REGISTRYINDEX, package_name_.c_str()); + lua_getfield(L, -1, "CalcSpellEffectValue_formula"); + + Lua_Mob l_self(self); + luabind::adl::object e = luabind::newtable(L); + e["self"] = l_self; + e["formula"] = formula; + e["base_value"] = base_value; + e["max_value"] = max_value; + e["caster_level"] = caster_level; + e["spell_id"] = spell_id; + e["ticsremaining"] = ticsremaining; + e.push(L); + + if (lua_pcall(L, 1, 1, 0)) { + std::string error = lua_tostring(L, -1); + parser_->AddError(error); + lua_pop(L, 2); + 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); + } + + auto returnValueObj = ret["ReturnValue"]; + if (luabind::type(returnValueObj) == LUA_TNUMBER) { + returnValue = luabind::object_cast(returnValueObj); + } + } + } + catch (std::exception &ex) { + parser_->AddError(ex.what()); + } + + int end = lua_gettop(L); + int n = end - start; + if (n > 0) { + lua_pop(L, n); + } +} + #endif diff --git a/zone/lua_mod.h b/zone/lua_mod.h index 99dc3cd80..2028d8aed 100644 --- a/zone/lua_mod.h +++ b/zone/lua_mod.h @@ -26,6 +26,7 @@ public: void GetRequiredAAExperience(Client *self, uint32 &returnValue, bool &ignoreDefault); void GetEXPForLevel(Client *self, uint16 level, uint32 &returnValue, bool &ignoreDefault); void GetExperienceForKill(Client *self, Mob *against, uint64 &returnValue, bool &ignoreDefault); + void CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, int64 &returnValue, bool &ignoreDefault); private: LuaParser *parser_; lua_State *L; @@ -40,4 +41,5 @@ private: bool m_has_get_required_aa_experience; bool m_has_get_exp_for_level; bool m_has_get_experience_for_kill; + bool m_has_calc_spell_effect_value_formula; }; diff --git a/zone/lua_parser.cpp b/zone/lua_parser.cpp index 579219580..f8574bfa5 100644 --- a/zone/lua_parser.cpp +++ b/zone/lua_parser.cpp @@ -1494,6 +1494,15 @@ uint64 LuaParser::GetExperienceForKill(Client *self, Mob *against, bool &ignoreD return retval; } +int64 LuaParser::CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, bool &ignoreDefault) +{ + int64 retval = 0; + for (auto &mod : mods_) { + mod.CalcSpellEffectValue_formula(self, formula, base_value, max_value, caster_level, spell_id, ticsremaining, retval, ignoreDefault); + } + return retval; +} + #ifdef BOTS int LuaParser::EventBot( QuestEventID evt, diff --git a/zone/lua_parser.h b/zone/lua_parser.h index 949180108..81bbf339a 100644 --- a/zone/lua_parser.h +++ b/zone/lua_parser.h @@ -207,6 +207,7 @@ public: uint32 GetRequiredAAExperience(Client *self, bool &ignoreDefault); uint32 GetEXPForLevel(Client *self, uint16 level, bool &ignoreDefault); uint64 GetExperienceForKill(Client *self, Mob *against, bool &ignoreDefault); + int64 CalcSpellEffectValue_formula(Mob *self, uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining, bool &ignoreDefault); private: LuaParser(); diff --git a/zone/mob.h b/zone/mob.h index 0c1a2281f..a7fe76593 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -1244,7 +1244,7 @@ public: //uint32 GetInstrumentMod(uint16 spell_id) const; uint32 GetInstrumentMod(uint16 spell_id); int64 CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0,uint16 casterid=0); - int64 CalcSpellEffectValue_formula(int64 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining = 0); + int64 CalcSpellEffectValue_formula(uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining = 0); virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1); uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; } diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp index ba4f7a67d..cf1181fd2 100644 --- a/zone/spell_effects.cpp +++ b/zone/spell_effects.cpp @@ -28,6 +28,7 @@ #include "../common/misc_functions.h" #include "quest_parser_collection.h" +#include "lua_parser.h" #include "string_ids.h" #include "worldserver.h" @@ -3408,8 +3409,18 @@ int64 Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level } // generic formula calculations -int64 Mob::CalcSpellEffectValue_formula(int64 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining) +int64 Mob::CalcSpellEffectValue_formula(uint32 formula, int64 base_value, int64 max_value, int caster_level, uint16 spell_id, int ticsremaining) { +#ifdef LUA_EQEMU + int64 lua_ret = 0; + bool ignoreDefault = false; + lua_ret = LuaParser::Instance()->CalcSpellEffectValue_formula(this, formula, base_value, max_value, caster_level, spell_id, ticsremaining, ignoreDefault); + + if (ignoreDefault) { + return lua_ret; + } +#endif + /* i need those formulas checked!!!!