From dad7873dc51650f6a93f67c63762d92b15404235 Mon Sep 17 00:00:00 2001 From: Emagi Date: Sat, 18 Jan 2025 09:16:35 -0500 Subject: [PATCH] LUA functions added: GetSpellCaster(Spell) and GetCasterSpellLevel(Spell) the Spell field is optional if in a spell script db additionally had field added: alter table character_spell_effects add column caster_level smallint(5) unsigned not null default 0; --- source/WorldServer/LuaFunctions.cpp | 40 ++++++++++++++++++++++++++++ source/WorldServer/LuaFunctions.h | 2 ++ source/WorldServer/LuaInterface.cpp | 4 +++ source/WorldServer/LuaInterface.h | 1 + source/WorldServer/Player.cpp | 8 +++--- source/WorldServer/SpellProcess.cpp | 3 +++ source/WorldServer/WorldDatabase.cpp | 4 ++- 7 files changed, 57 insertions(+), 5 deletions(-) diff --git a/source/WorldServer/LuaFunctions.cpp b/source/WorldServer/LuaFunctions.cpp index ec5e931..dd24080 100644 --- a/source/WorldServer/LuaFunctions.cpp +++ b/source/WorldServer/LuaFunctions.cpp @@ -14298,6 +14298,46 @@ int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state) { return 0; } +int EQ2Emu_lua_GetSpellCaster(lua_State* state) { + LuaSpell* spell = lua_interface->GetSpell(state); + + if(!spell) { + spell = lua_interface->GetCurrentSpell(state); + } + + lua_interface->ResetFunctionStack(state); + if (spell) { + if(!spell->caster) { + lua_interface->LogError("%s: LUA GetSpellCaster command error, caster does not exist.", lua_interface->GetScriptName(state)); + return 0; + } + lua_interface->SetSpawnValue(state, spell->caster); + return 1; + } + else { + lua_interface->LogError("%s: LUA GetSpellCaster command error, could not find spell.", lua_interface->GetScriptName(state)); + } + return 0; +} + +int EQ2Emu_lua_GetCasterSpellLevel(lua_State* state) { + LuaSpell* spell = lua_interface->GetSpell(state); + + if(!spell) { + spell = lua_interface->GetCurrentSpell(state); + } + + lua_interface->ResetFunctionStack(state); + if (spell) { + lua_interface->SetInt32Value(state, spell->initial_caster_level); + return 1; + } + else { + lua_interface->LogError("%s: LUA GetCasterSpellLevel command error, spell does not exist.", lua_interface->GetScriptName(state)); + } + return 0; +} + int EQ2Emu_lua_GetSpellTargets(lua_State* state) { if (!lua_interface) return 0; diff --git a/source/WorldServer/LuaFunctions.h b/source/WorldServer/LuaFunctions.h index 2e9fa65..e593803 100644 --- a/source/WorldServer/LuaFunctions.h +++ b/source/WorldServer/LuaFunctions.h @@ -659,6 +659,8 @@ int EQ2Emu_lua_GetCharacterFlag(lua_State* state); int EQ2Emu_lua_ToggleCharacterFlag(lua_State* state); int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state); +int EQ2Emu_lua_GetSpellCaster(lua_State* state); +int EQ2Emu_lua_GetCasterSpellLevel(lua_State* state); int EQ2Emu_lua_GetSpellTargets(lua_State* state); int EQ2Emu_lua_DespawnByLocationID(lua_State* state); diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index bace2ef..e44b68d 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -1600,6 +1600,8 @@ void LuaInterface::RegisterFunctions(lua_State* state) { lua_register(state, "ToggleCharacterFlag", EQ2Emu_lua_ToggleCharacterFlag); lua_register(state, "GetSpellInitialTarget", EQ2Emu_lua_GetSpellInitialTarget); + lua_register(state, "GetSpellCaster", EQ2Emu_lua_GetSpellCaster); + lua_register(state, "GetCasterSpellLevel", EQ2Emu_lua_GetCasterSpellLevel); lua_register(state, "GetSpellTargets", EQ2Emu_lua_GetSpellTargets); lua_register(state,"DespawnByLocationID", EQ2Emu_lua_DespawnByLocationID); @@ -2114,6 +2116,7 @@ LuaSpell* LuaInterface::LoadSpellScript(const char* name) { spell->initial_caster_char_id = 0; spell->initial_target_char_id = 0; spell->zone = nullptr; + spell->initial_caster_level = 0; MSpells.lock(); current_spells[spell->state] = spell; @@ -2413,6 +2416,7 @@ LuaSpell* LuaInterface::CreateSpellScript(const char* name, lua_State* existStat new_spell->initial_caster_char_id = 0; new_spell->initial_target_char_id = 0; new_spell->zone = nullptr; + new_spell->initial_caster_level = 0; current_spells[new_spell->state] = new_spell; return new_spell; diff --git a/source/WorldServer/LuaInterface.h b/source/WorldServer/LuaInterface.h index bf04c32..791e12e 100644 --- a/source/WorldServer/LuaInterface.h +++ b/source/WorldServer/LuaInterface.h @@ -104,6 +104,7 @@ struct LuaSpell{ bool restored; // restored spell cross zone std::atomic has_proc; ZoneServer* zone; + int16 initial_caster_level; }; class LUAUserData{ diff --git a/source/WorldServer/Player.cpp b/source/WorldServer/Player.cpp index 738ceca..6a545a4 100644 --- a/source/WorldServer/Player.cpp +++ b/source/WorldServer/Player.cpp @@ -7245,13 +7245,13 @@ void Player::SaveSpellEffects() continue; savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, - "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s')", + "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", database.getSafeEscapeString(info->spell_effects[i].spell->spell->GetName()).c_str(), caster_char_id, target_char_id, 0 /*no target_type for spell_effects*/, DB_TYPE_SPELLEFFECTS /* db_effect_type for spell_effects */, info->spell_effects[i].spell->spell->IsCopiedSpell() ? info->spell_effects[i].spell->spell->GetSpellData()->inherited_spell_id : info->spell_effects[i].spell_id, i, info->spell_effects[i].spell->slot_pos, info->spell_effects[i].icon, info->spell_effects[i].icon_backdrop, 0 /* no conc_used for spell_effects */, info->spell_effects[i].tier, info->spell_effects[i].total_time, timestamp, database.getSafeEscapeString(info->spell_effects[i].spell->file_name.c_str()).c_str(), info->spell_effects[i].spell->spell->IsCopiedSpell(), GetCharacterID(), info->spell_effects[i].spell->damage_remaining, info->spell_effects[i].spell->effect_bitmask, info->spell_effects[i].spell->num_triggers, info->spell_effects[i].spell->had_triggers, info->spell_effects[i].spell->cancel_after_all_triggers, - info->spell_effects[i].spell->crit, info->spell_effects[i].spell->last_spellattack_hit, info->spell_effects[i].spell->interrupted, info->spell_effects[i].spell->resisted, info->spell_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->spell_effects[i].spell).c_str()).c_str()); + info->spell_effects[i].spell->crit, info->spell_effects[i].spell->last_spellattack_hit, info->spell_effects[i].spell->interrupted, info->spell_effects[i].spell->resisted, info->spell_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->spell_effects[i].spell).c_str()).c_str(), info->spell_effects[i].spell->initial_caster_level); } if (i < NUM_MAINTAINED_EFFECTS && info->maintained_effects[i].spell_id != 0xFFFFFFFF){ Spawn* spawn = GetZone()->GetSpawnByID(info->maintained_effects[i].spell->initial_target); @@ -7273,12 +7273,12 @@ void Player::SaveSpellEffects() if(info->maintained_effects[i].spell->spell->GetSpellData() && !info->maintained_effects[i].spell->spell->GetSpellData()->duration_until_cancel) timestamp = info->maintained_effects[i].expire_timestamp - Timer::GetCurrentTime2(); savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, - "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s')", + "insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s', %u)", database.getSafeEscapeString(info->maintained_effects[i].name).c_str(), caster_char_id, target_char_id, info->maintained_effects[i].target_type, DB_TYPE_MAINTAINEDEFFECTS /* db_effect_type for maintained_effects */, info->maintained_effects[i].spell->spell->IsCopiedSpell() ? info->maintained_effects[i].spell->spell->GetSpellData()->inherited_spell_id : info->maintained_effects[i].spell_id, i, info->maintained_effects[i].slot_pos, info->maintained_effects[i].icon, info->maintained_effects[i].icon_backdrop, info->maintained_effects[i].conc_used, info->maintained_effects[i].tier, info->maintained_effects[i].total_time, timestamp, database.getSafeEscapeString(info->maintained_effects[i].spell->file_name.c_str()).c_str(), info->maintained_effects[i].spell->spell->IsCopiedSpell(), GetCharacterID(), info->maintained_effects[i].spell->damage_remaining, info->maintained_effects[i].spell->effect_bitmask, info->maintained_effects[i].spell->num_triggers, info->maintained_effects[i].spell->had_triggers, info->maintained_effects[i].spell->cancel_after_all_triggers, - info->maintained_effects[i].spell->crit, info->maintained_effects[i].spell->last_spellattack_hit, info->maintained_effects[i].spell->interrupted, info->maintained_effects[i].spell->resisted, info->maintained_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->maintained_effects[i].spell).c_str()).c_str()); + info->maintained_effects[i].spell->crit, info->maintained_effects[i].spell->last_spellattack_hit, info->maintained_effects[i].spell->interrupted, info->maintained_effects[i].spell->resisted, info->maintained_effects[i].spell->has_damaged, (info->maintained_effects[i].expire_timestamp) == 0xFFFFFFFF ? "" : database.getSafeEscapeString(spellProcess->SpellScriptTimerCustomFunction(info->maintained_effects[i].spell).c_str()).c_str(), info->maintained_effects[i].spell->initial_caster_level); info->maintained_effects[i].spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); std::string insertTargets = string("insert into character_spell_effect_targets (caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos) values "); diff --git a/source/WorldServer/SpellProcess.cpp b/source/WorldServer/SpellProcess.cpp index d7dc1d9..faf14f4 100644 --- a/source/WorldServer/SpellProcess.cpp +++ b/source/WorldServer/SpellProcess.cpp @@ -649,6 +649,7 @@ bool SpellProcess::CastInstant(Spell* spell, Entity* caster, Entity* target, boo } lua_spell->caster = caster; + lua_spell->initial_caster_level = caster->GetInfoStruct()->get_effective_level() != 0 ? caster->GetInfoStruct()->get_effective_level() : caster->GetLevel(); lua_spell->zone = caster->GetZone(); lua_spell->initial_caster_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0; lua_spell->spell = spell; @@ -1069,6 +1070,7 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster, int8 spell_type = spell->GetSpellData()->spell_type; lua_spell->caster = caster; + lua_spell->initial_caster_level = caster->GetInfoStruct()->get_effective_level() != 0 ? caster->GetInfoStruct()->get_effective_level() : caster->GetLevel(); lua_spell->zone = caster->GetZone(); lua_spell->initial_caster_char_id = (caster && caster->IsPlayer()) ? ((Player*)caster)->GetCharacterID() : 0; lua_spell->spell = spell; @@ -1632,6 +1634,7 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster, cast_timer->target_id = target ? target->GetID() : 0; cast_timer->spell = lua_spell; cast_timer->spell->caster = caster; + cast_timer->spell->initial_caster_level = caster->GetInfoStruct()->get_effective_level() != 0 ? caster->GetInfoStruct()->get_effective_level() : caster->GetLevel(); cast_timer->spell->zone = caster->GetZone(); cast_timer->delete_timer = false; cast_timer->timer = new Timer(spell->GetSpellData()->cast_time * 10); diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index a26a7c3..12b6378 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -7971,7 +7971,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int multimap restoreSpells; // Use -1 on type and subtype to turn the enum into an int and make it a 0 index - if (!database_new.Select(&result, "SELECT name, caster_char_id, target_char_id, target_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function FROM character_spell_effects WHERE charid = %u and db_effect_type = %u", char_id, db_spell_type)) { + if (!database_new.Select(&result, "SELECT name, caster_char_id, target_char_id, target_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, has_damaged, custom_function, caster_level FROM character_spell_effects WHERE charid = %u and db_effect_type = %u", char_id, db_spell_type)) { LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg()); return; } @@ -8009,6 +8009,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int int8 resisted = result.GetInt32Str("resisted"); int8 has_damaged = result.GetInt32Str("has_damaged"); std::string custom_function = std::string(result.GetStringStr("custom_function")); + int16 caster_level = result.GetInt16Str("caster_level"); LuaSpell* lua_spell = 0; if(custom_spell) { @@ -8133,6 +8134,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int lua_spell->num_triggers = num_triggers; lua_spell->has_damaged = has_damaged; lua_spell->is_damage_spell = has_damaged; + lua_spell->initial_caster_level = caster_level; } if(lua_spell->initial_target == 0 && target_char_id == 0xFFFFFFFF && player->HasPet())