Extensive changes to remove SpellTargets write and read mutex locks to avoi ddeadlocks

This commit is contained in:
Emagi 2025-06-22 13:20:07 -04:00
parent 6b0f551552
commit a8eb9c9ebc
7 changed files with 422 additions and 466 deletions

View File

@ -1401,17 +1401,15 @@ int EQ2Emu_lua_SpellHeal(lua_State* state) {
if (((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name)) if (((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name))
success = true; success = true;
} }
if ((!success || luaspell->spell->GetSpellData()->group_spell) && luaspell->targets.size() > 0) { if ((!success || luaspell->spell->GetSpellData()->group_spell) && luaspell->GetTargetCount() > 0) {
Spawn* target = 0; Spawn* target = 0;
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { if ((target = zone->GetSpawnByID(id))) {
if ((target = zone->GetSpawnByID(luaspell->targets[i]))) {
float distance = caster->GetDistance(target, true); float distance = caster->GetDistance(target, true);
((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name); ((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name);
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
success = true; success = true;
} }
if (success) { if (success) {
@ -1494,17 +1492,15 @@ int EQ2Emu_lua_SpellHealPct(lua_State* state) {
if (((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name)) if (((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name))
success = true; success = true;
} }
if ((!success || luaspell->spell->GetSpellData()->group_spell) && luaspell->targets.size() > 0) { if ((!success || luaspell->spell->GetSpellData()->group_spell) && luaspell->GetTargetCount() > 0) {
Spawn* target = 0; Spawn* target = 0;
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { if ((target = zone->GetSpawnByID(id))) {
if ((target = zone->GetSpawnByID(luaspell->targets[i]))) {
float distance = caster->GetDistance(target, true); float distance = caster->GetDistance(target, true);
((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name); ((Entity*)caster)->SpellHeal(target, distance, luaspell, heal_type, min_heal, max_heal, crit_mod, no_calcs, custom_spell_name);
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
success = true; success = true;
} }
if (success) { if (success) {
@ -1751,10 +1747,9 @@ int EQ2Emu_lua_AddHate(lua_State* state) {
if (entity && entity->IsEntity() && amount != 0) { if (entity && entity->IsEntity() && amount != 0) {
if (luaspell && luaspell->caster) { if (luaspell && luaspell->caster) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { Spawn* spawn = zone->GetSpawnByID(id);
Spawn* spawn = zone->GetSpawnByID(luaspell->targets.at(i));
if (spawn && spawn->IsNPC() && spawn->Alive() && spawn->GetZone()) { if (spawn && spawn->IsNPC() && spawn->Alive() && spawn->GetZone()) {
entity->CheckEncounterState((Entity*)spawn); entity->CheckEncounterState((Entity*)spawn);
((NPC*)spawn)->AddHate((Entity*)entity, amount); ((NPC*)spawn)->AddHate((Entity*)entity, amount);
@ -1762,7 +1757,6 @@ int EQ2Emu_lua_AddHate(lua_State* state) {
entity->GetZone()->SendThreatPacket(entity, npc, amount, luaspell->spell->GetName()); entity->GetZone()->SendThreatPacket(entity, npc, amount, luaspell->spell->GetName());
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (npc && npc->IsNPC() && npc->GetZone()) { else if (npc && npc->IsNPC() && npc->GetZone()) {
entity->CheckEncounterState((Entity*)npc); entity->CheckEncounterState((Entity*)npc);
@ -1910,12 +1904,11 @@ int EQ2Emu_lua_SpellDamage(lua_State* state) {
bool race_match = false; bool race_match = false;
bool success = false; bool success = false;
luaspell->resisted = false; luaspell->resisted = false;
if (luaspell->targets.size() > 0) { if (luaspell->GetTargetCount() > 0) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { if ((target = zone->GetSpawnByID(id))) {
if ((target = zone->GetSpawnByID(luaspell->targets[i]))) {
if (race_req.size() > 0) { if (race_req.size() > 0) {
for (int8 i = 0; i < race_req.size(); i++) { for (int8 i = 0; i < race_req.size(); i++) {
@ -1935,7 +1928,6 @@ int EQ2Emu_lua_SpellDamage(lua_State* state) {
} }
} }
success = true; success = true;
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (target) { else if (target) {
@ -2018,12 +2010,11 @@ int EQ2Emu_lua_SpellDamageExt(lua_State* state) {
bool race_match = false; bool race_match = false;
bool success = false; bool success = false;
luaspell->resisted = false; luaspell->resisted = false;
if (luaspell->targets.size() > 0) { if (luaspell->GetTargetCount() > 0) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { if ((target = zone->GetSpawnByID(id))) {
if ((target = zone->GetSpawnByID(luaspell->targets[i]))) {
if (race_req.size() > 0) { if (race_req.size() > 0) {
for (int8 i = 0; i < race_req.size(); i++) { for (int8 i = 0; i < race_req.size(); i++) {
@ -2043,7 +2034,6 @@ int EQ2Emu_lua_SpellDamageExt(lua_State* state) {
} }
} }
success = true; success = true;
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (target) { else if (target) {
@ -2455,10 +2445,9 @@ int EQ2Emu_lua_AddSpellBonus(lua_State* state) {
if (value != 0 && type >= 0) { if (value != 0 && type >= 0) {
if (luaspell && luaspell->spell && luaspell->caster) { if (luaspell && luaspell->spell && luaspell->caster) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { Spawn* target = zone->GetSpawnByID(id);
Spawn* target = zone->GetSpawnByID(luaspell->targets[i]);
if (target) { if (target) {
if (target->IsPlayer()) { if (target->IsPlayer()) {
((Player*)target)->AddSpellBonus(luaspell, type, value, class_req, race_req, faction_req); ((Player*)target)->AddSpellBonus(luaspell, type, value, class_req, race_req, faction_req);
@ -2473,7 +2462,6 @@ int EQ2Emu_lua_AddSpellBonus(lua_State* state) {
lua_interface->LogError("%s: Error applying spell bonus on non entity.", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: Error applying spell bonus on non entity.", lua_interface->GetScriptName(state));
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
if (!(luaspell->effect_bitmask & EFFECT_FLAG_SPELLBONUS)) if (!(luaspell->effect_bitmask & EFFECT_FLAG_SPELLBONUS))
luaspell->effect_bitmask += EFFECT_FLAG_SPELLBONUS; luaspell->effect_bitmask += EFFECT_FLAG_SPELLBONUS;
} }
@ -2599,22 +2587,20 @@ int EQ2Emu_lua_RemoveSpellBonus(lua_State* state) {
else if (luaspell && luaspell->spell) { else if (luaspell && luaspell->spell) {
ZoneServer* zone = nullptr; ZoneServer* zone = nullptr;
if (luaspell->caster != nullptr) if (luaspell->caster != nullptr)
zone = luaspell->caster->GetZone(); zone = luaspell->zone;
if(!zone && spawn) { if(!zone && spawn) {
zone = spawn->GetZone(); // workaround to try to establish a zone to find the targets and remove the spells zone = spawn->GetZone(); // workaround to try to establish a zone to find the targets and remove the spells
} }
Spawn* target = 0; Spawn* target = 0;
if(zone) { if(zone) {
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(luaspell->targets[i]);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->RemoveSpellBonus(luaspell); ((Entity*)target)->RemoveSpellBonus(luaspell);
if (target->IsPlayer()) if (target->IsPlayer())
((Player*)target)->SetCharSheetChanged(true); ((Player*)target)->SetCharSheetChanged(true);
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else { else {
LogWrite(LUA__ERROR, 0, "LUA", "Error removing spell bonus buff %s called by %s, zone is not available.", luaspell->spell ? luaspell->spell->GetName() : "NotSet", spawn ? spawn->GetName() : "N/A"); LogWrite(LUA__ERROR, 0, "LUA", "Error removing spell bonus buff %s called by %s, zone is not available.", luaspell->spell ? luaspell->spell->GetName() : "NotSet", spawn ? spawn->GetName() : "N/A");
@ -2638,11 +2624,10 @@ int EQ2Emu_lua_AddSkillBonus(lua_State* state) {
return 0; return 0;
} }
spell_id = luaspell->spell->GetSpellID(); spell_id = luaspell->spell->GetSpellID();
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(luaspell->targets[i]);
if (target && target->Alive()) { if (target && target->Alive()) {
if (target->IsPlayer()) { if (target->IsPlayer()) {
((Player*)target)->AddSkillBonus(spell_id, skill_id, value); ((Player*)target)->AddSkillBonus(spell_id, skill_id, value);
@ -2664,7 +2649,6 @@ int EQ2Emu_lua_AddSkillBonus(lua_State* state) {
LogWrite(LUA__ERROR, 0, "LUA", "Error applying bonus buff on '%s'. Not a NPC or player.", target->GetName()); LogWrite(LUA__ERROR, 0, "LUA", "Error applying bonus buff on '%s'. Not a NPC or player.", target->GetName());
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (spawn) { else if (spawn) {
if (spawn->IsPlayer()) { if (spawn->IsPlayer()) {
@ -2699,11 +2683,10 @@ int EQ2Emu_lua_RemoveSkillBonus(lua_State* state) {
return 0; return 0;
} }
spell_id = luaspell->spell->GetSpellID(); spell_id = luaspell->spell->GetSpellID();
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(luaspell->targets[i]);
if (target) { if (target) {
if (target->IsPlayer()) { if (target->IsPlayer()) {
((Player*)target)->RemoveSkillBonus(spell_id); ((Player*)target)->RemoveSkillBonus(spell_id);
@ -2720,7 +2703,6 @@ int EQ2Emu_lua_RemoveSkillBonus(lua_State* state) {
LogWrite(LUA__ERROR, 0, "LUA", "Error removing skill bonus on '%s'. Not a NPC or player.", spawn->GetName()); LogWrite(LUA__ERROR, 0, "LUA", "Error removing skill bonus on '%s'. Not a NPC or player.", spawn->GetName());
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (spawn) { else if (spawn) {
if (spawn->IsPlayer()) { if (spawn->IsPlayer()) {
@ -2754,11 +2736,10 @@ int EQ2Emu_lua_AddControlEffect(lua_State* state) {
} }
if (!only_add_spawn && luaspell && luaspell->spell && luaspell->caster && type != 0) { if (!only_add_spawn && luaspell && luaspell->spell && luaspell->caster && type != 0) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(luaspell->targets[i]);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
if (type == CONTROL_EFFECT_TYPE_MEZ) { if (type == CONTROL_EFFECT_TYPE_MEZ) {
((Entity*)target)->AddMezSpell(luaspell); ((Entity*)target)->AddMezSpell(luaspell);
@ -2840,7 +2821,6 @@ int EQ2Emu_lua_AddControlEffect(lua_State* state) {
else else
lua_interface->LogError("%s: Error applying control effect on non entity '%s'.", lua_interface->GetScriptName(state), (target != nullptr) ? target->GetName() : "NO_TARGET"); lua_interface->LogError("%s: Error applying control effect on non entity '%s'.", lua_interface->GetScriptName(state), (target != nullptr) ? target->GetName() : "NO_TARGET");
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (only_add_spawn && spawn && spawn->IsEntity()) { else if (only_add_spawn && spawn && spawn->IsEntity()) {
if (type == CONTROL_EFFECT_TYPE_MEZ) { if (type == CONTROL_EFFECT_TYPE_MEZ) {
@ -2921,11 +2901,10 @@ int EQ2Emu_lua_RemoveControlEffect(lua_State* state) {
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
if (spawn && spawn->IsEntity()) { if (spawn && spawn->IsEntity()) {
if (!only_remove_spawn && luaspell && luaspell->spell && luaspell->caster) { if (!only_remove_spawn && luaspell && luaspell->spell && luaspell->caster) {
ZoneServer* zone = luaspell->caster->GetZone(); ZoneServer* zone = luaspell->zone;
Spawn* target = 0; Spawn* target = 0;
luaspell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : luaspell->GetTargets()) {
for (int32 i = 0; i < luaspell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(luaspell->targets[i]);
if (target) { if (target) {
if (type == CONTROL_EFFECT_TYPE_MEZ) if (type == CONTROL_EFFECT_TYPE_MEZ)
((Entity*)target)->RemoveMezSpell(luaspell); ((Entity*)target)->RemoveMezSpell(luaspell);
@ -2955,7 +2934,6 @@ int EQ2Emu_lua_RemoveControlEffect(lua_State* state) {
lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type); lua_interface->LogError("%s: Unhandled control effect type of %u.", lua_interface->GetScriptName(state), type);
} }
} }
luaspell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else if (only_remove_spawn) { else if (only_remove_spawn) {
if (type == CONTROL_EFFECT_TYPE_MEZ) if (type == CONTROL_EFFECT_TYPE_MEZ)
@ -6578,10 +6556,9 @@ int EQ2Emu_lua_AddWard(lua_State* state) {
bool ward_was_added = false; bool ward_was_added = false;
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { Spawn* target = zone->GetSpawnByID(id);
Spawn* target = zone->GetSpawnByID(spell->targets.at(i));
if (!target) if (!target)
continue; continue;
if (target->IsEntity()) { if (target->IsEntity()) {
@ -6629,7 +6606,6 @@ int EQ2Emu_lua_AddWard(lua_State* state) {
ward_was_added = true; ward_was_added = true;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
if (ward_was_added && spell->caster->IsPlayer()) { if (ward_was_added && spell->caster->IsPlayer()) {
spell->had_dmg_remaining = true; spell->had_dmg_remaining = true;
@ -6651,23 +6627,25 @@ int EQ2Emu_lua_AddToWard(lua_State* state) {
if(!spell || spell->resisted) { if(!spell || spell->resisted) {
return 0; return 0;
} }
ZoneServer* zone = spell->caster->GetZone(); if(!spell->caster || !spell->zone) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); return 0;
if (spell->targets.size() > 0 && zone->GetSpawnByID(spell->targets.at(0))->IsEntity()) { }
Entity* target = (Entity*)zone->GetSpawnByID(spell->targets.at(0)); ZoneServer* zone = spell->zone;
Entity* target = nullptr;
if (auto target_id_opt = spell->GetPrimaryTarget();
target_id_opt && (target = (Entity*)zone->GetSpawnByID(*target_id_opt))) {
ward = target->GetWard(spell->spell->GetSpellID()); ward = target->GetWard(spell->spell->GetSpellID());
if (target && ward) { if (target && ward) {
ward->DamageLeft += amount; ward->DamageLeft += amount;
if (ward->DamageLeft > ward->BaseDamage) if (ward->DamageLeft > ward->BaseDamage)
ward->DamageLeft = ward->BaseDamage; ward->DamageLeft = ward->BaseDamage;
for (int32 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
if (Spawn* spawn = zone->GetSpawnByID(spell->targets.at(i))) if (Spawn* spawn = zone->GetSpawnByID(id))
zone->SendHealPacket(ward->Spell->caster, spawn, HEAL_PACKET_TYPE_REGEN_ABSORB, amount, ward->Spell->spell->GetName()); zone->SendHealPacket(ward->Spell->caster, spawn, HEAL_PACKET_TYPE_REGEN_ABSORB, amount, ward->Spell->spell->GetName());
} }
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
if (ward && spell->caster->IsPlayer()) if (ward && spell->caster->IsPlayer())
ClientPacketFunctions::SendMaintainedExamineUpdate(((Player*)spell->caster)->GetClient(), spell->slot_pos, ward->DamageLeft, 1); ClientPacketFunctions::SendMaintainedExamineUpdate(((Player*)spell->caster)->GetClient(), spell->slot_pos, ward->DamageLeft, 1);
@ -6686,17 +6664,15 @@ int EQ2Emu_lua_GetWardAmountLeft(lua_State* state) {
return 0; return 0;
} }
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); Entity* target = nullptr;
if (spell->caster && spell->caster->GetZone() && spell->targets.size() > 0 && spell->caster->GetZone()->GetSpawnByID(spell->targets.at(0))->IsEntity()) { if (auto target_id_opt = spell->GetPrimaryTarget();
Entity* target = (Entity*)spell->caster->GetZone()->GetSpawnByID(spell->targets.at(0)); target_id_opt && spell->zone && (target = (Entity*)spell->zone->GetSpawnByID(*target_id_opt))) {
WardInfo* ward = target->GetWard(spell->spell->GetSpellID()); WardInfo* ward = target->GetWard(spell->spell->GetSpellID());
if (ward) { if (ward) {
lua_interface->SetInt32Value(state, ward->DamageLeft); lua_interface->SetInt32Value(state, ward->DamageLeft);
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 1; return 1;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 0; return 0;
} }
@ -6714,11 +6690,9 @@ int EQ2Emu_lua_GetWardValue(lua_State* state) {
string type = lua_interface->GetStringValue(state, 2); string type = lua_interface->GetStringValue(state, 2);
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
Entity* target = nullptr;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); if (auto target_id_opt = spell->GetPrimaryTarget();
if (spell->caster && spell->caster->GetZone() && spell->targets.size() > 0 && spell->caster->GetZone()->GetSpawnByID(spell->targets.at(0))->IsEntity()) { target_id_opt && spell->zone && (target = (Entity*)spell->zone->GetSpawnByID(*target_id_opt))) {
Entity* target = (Entity*)spell->caster->GetZone()->GetSpawnByID(spell->targets.at(0));
WardInfo* ward = target->GetWard(spell->spell->GetSpellID()); WardInfo* ward = target->GetWard(spell->spell->GetSpellID());
if (ward) { if (ward) {
if (boost::iequals(type, "damageleft")) if (boost::iequals(type, "damageleft"))
@ -6745,12 +6719,9 @@ int EQ2Emu_lua_GetWardValue(lua_State* state) {
lua_interface->SetInt32Value(state, ward->MaxHitCount); lua_interface->SetInt32Value(state, ward->MaxHitCount);
else else
lua_interface->LogError("%s: LUA GetWardValue command argument type '%s' did not match any options", lua_interface->GetScriptName(state), type.c_str()); lua_interface->LogError("%s: LUA GetWardValue command argument type '%s' did not match any options", lua_interface->GetScriptName(state), type.c_str());
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 1; return 1;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 0; return 0;
} }
@ -6770,21 +6741,19 @@ int EQ2Emu_lua_RemoveWard(lua_State* state) {
return 0; return 0;
} }
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
if(!zone) { if(!zone) {
lua_interface->LogError("%s: RemoveWard error: no valid zone for caster", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: RemoveWard error: no valid zone for caster", lua_interface->GetScriptName(state));
return 0; return 0;
} }
Spawn* target = 0; Spawn* target = 0;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(spell->targets.at(i));
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->RemoveWard(spell->spell->GetSpellID()); ((Entity*)target)->RemoveWard(spell->spell->GetSpellID());
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 0; return 0;
} }
@ -6824,15 +6793,13 @@ int EQ2Emu_lua_Interrupt(lua_State* state)
} }
if (!target && spell) { if (!target && spell) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { target = caster->GetZone()->GetSpawnByID(id);
target = caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
((Entity*)target)->GetZone()->GetSpellProcess()->Interrupted((Entity*)target, caster, SPELL_ERROR_INTERRUPTED); ((Entity*)target)->GetZone()->GetSpellProcess()->Interrupted((Entity*)target, caster, SPELL_ERROR_INTERRUPTED);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else else
caster->GetZone()->GetSpellProcess()->Interrupted((Entity*)target, caster, SPELL_ERROR_INTERRUPTED); caster->GetZone()->GetSpellProcess()->Interrupted((Entity*)target, caster, SPELL_ERROR_INTERRUPTED);
@ -6854,7 +6821,7 @@ int EQ2Emu_lua_Stealth(lua_State* state) {
return 0; return 0;
} }
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
if (spawn) { if (spawn) {
if (spawn->IsEntity()) { if (spawn->IsEntity()) {
@ -6876,9 +6843,8 @@ int EQ2Emu_lua_Stealth(lua_State* state) {
} }
} }
else { else {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { spawn = zone->GetSpawnByID(id);
spawn = zone->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
@ -6897,7 +6863,6 @@ int EQ2Emu_lua_Stealth(lua_State* state) {
break; break;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
} }
@ -7237,16 +7202,14 @@ int EQ2Emu_lua_PlayAnimationString(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->caster && spell->caster->GetZone() && use_all_spelltargets) { if (spell && spell->zone && use_all_spelltargets) {
Spawn* target; Spawn* target;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { target = spell->zone->GetSpawnByID(id);
target = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if(target && (!ignore_self || spawn != target)) { if(target && (!ignore_self || spawn != target)) {
spell->caster->GetZone()->HandleEmote(target, name, opt_target, set_no_target); spell->zone->HandleEmote(target, name, opt_target, set_no_target);
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else { else {
spawn->GetZone()->HandleEmote(spawn, name, opt_target, set_no_target); spawn->GetZone()->HandleEmote(spawn, name, opt_target, set_no_target);
@ -8732,17 +8695,15 @@ int EQ2Emu_lua_AddProc(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->caster && spell->caster->GetZone() && use_all_spelltargets) { if (spell && spell->zone && use_all_spelltargets) {
Spawn* target; Spawn* target;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { target = spell->zone->GetSpawnByID(id);
target = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
((Entity*)target)->AddProc(type, chance, item, spell); ((Entity*)target)->AddProc(type, chance, item, spell);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else else
((Entity*)spawn)->AddProc(type, chance, item, spell); ((Entity*)spawn)->AddProc(type, chance, item, spell);
@ -8788,17 +8749,15 @@ int EQ2Emu_lua_AddProcExt(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->caster && spell->caster->GetZone() && use_all_spelltargets) { if (spell && spell->zone && use_all_spelltargets) {
Spawn* target; Spawn* target;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { target = spell->zone->GetSpawnByID(id);
target = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
((Entity*)target)->AddProc(type, chance, item, spell, damage_type, hp_ratio, below_health, target_health, extended_version); ((Entity*)target)->AddProc(type, chance, item, spell, damage_type, hp_ratio, below_health, target_health, extended_version);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else else
((Entity*)spawn)->AddProc(type, chance, item, spell); ((Entity*)spawn)->AddProc(type, chance, item, spell);
@ -8827,17 +8786,15 @@ int EQ2Emu_lua_RemoveProc(lua_State* state) {
if(spawn && spawn->IsEntity()) { if(spawn && spawn->IsEntity()) {
((Entity*)spawn)->RemoveProc(item, spell); ((Entity*)spawn)->RemoveProc(item, spell);
} }
else if (spell && spell->caster && spell->caster->GetZone()) { else if (spell && spell->zone) {
Spawn* target; Spawn* target;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { target = spell->zone->GetSpawnByID(id);
target = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
((Entity*)target)->RemoveProc(item, spell); ((Entity*)target)->RemoveProc(item, spell);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
spell->caster->RemoveProc(item, spell); spell->caster->RemoveProc(item, spell);
} }
else if (!spawn) { else if (!spawn) {
@ -9180,7 +9137,7 @@ int EQ2Emu_lua_AddSpellTimer(lua_State* state) {
return 0; return 0;
} }
if (!spell || (!spell->caster || !spell->caster->GetZone())) { if (!spell || (!spell->caster || !spell->zone)) {
lua_interface->LogError("%s: LUA AddSpellTimer command error: spell not found, AddSpellTimer must be used in a spell script", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA AddSpellTimer command error: spell not found, AddSpellTimer must be used in a spell script", lua_interface->GetScriptName(state));
return 0; return 0;
} }
@ -9206,7 +9163,7 @@ int EQ2Emu_lua_AddSpellTimer(lua_State* state) {
if (target) if (target)
timer->target = target->GetID(); timer->target = target->GetID();
spell->caster->GetZone()->GetSpellProcess()->AddSpellScriptTimer(timer); spell->zone->GetSpellProcess()->AddSpellScriptTimer(timer);
return 0; return 0;
} }
@ -9232,65 +9189,59 @@ int EQ2Emu_lua_Resurrect(lua_State* state) {
} }
Entity* caster = spell->caster; Entity* caster = spell->caster;
if (!caster) { if (!caster || !caster->GetZone()) {
lua_interface->LogError("%s: LUA command error: could not find caster", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA command error: could not find caster or caster has no zone", lua_interface->GetScriptName(state));
return 0; return 0;
} }
Client* client = 0; Client* client = 0;
PendingResurrection* rez = 0; PendingResurrection* rez = 0;
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
if (!target) { if (!target) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
if (spell->targets.size() > 0) { target = zone->GetSpawnByID(id);
vector<int32> spell_targets = spell->targets; if (!target)
for (int8 i = 0; i < spell_targets.size(); i++) { continue;
target = zone->GetSpawnByID(spell_targets.at(i)); if (!target->IsPlayer())
if (!target) continue;
continue;
if (!target->IsPlayer())
continue;
client = ((Player*)target)->GetClient(); client = ((Player*)target)->GetClient();
if (!client) if (!client)
continue; continue;
rez = client->GetCurrentRez(); rez = client->GetCurrentRez();
if (rez->active) if (rez->active)
continue; continue;
client->GetResurrectMutex()->writelock(__FUNCTION__, __LINE__);
client->GetResurrectMutex()->writelock(__FUNCTION__, __LINE__); rez->active = true;
rez->active = true; rez->caster = caster->GetID();
rez->caster = caster->GetID(); rez->expire_timer = new Timer;
rez->expire_timer = new Timer; int32 duration = spell->spell->GetSpellDuration();
int32 duration = spell->spell->GetSpellDuration(); rez->expire_timer->Start(duration * 100);
rez->expire_timer->Start(duration * 100); rez->hp_perc = hp_perc;
rez->hp_perc = hp_perc; rez->mp_perc = power_perc;
rez->mp_perc = power_perc; rez->range = spell->spell->GetSpellData()->range;
rez->range = spell->spell->GetSpellData()->range; rez->spell_name = spell->spell->GetName();
rez->spell_name = spell->spell->GetName(); if (heal_name.length() > 0)
if (heal_name.length() > 0) rez->heal_name = heal_name;
rez->heal_name = heal_name; else
else rez->heal_name = rez->spell_name;
rez->heal_name = rez->spell_name; rez->orig_spell_id = spell->spell->GetSpellID();
rez->orig_spell_id = spell->spell->GetSpellID(); rez->orig_spell_tier = spell->spell->GetSpellTier();
rez->orig_spell_tier = spell->spell->GetSpellTier(); rez->revive_sickness_spell_id = revive_spell_id;
rez->revive_sickness_spell_id = revive_spell_id; rez->revive_sickness_spell_tier = revive_spell_tier;
rez->revive_sickness_spell_tier = revive_spell_tier; rez->no_calcs = no_calcs;
rez->no_calcs = no_calcs; rez->crit_mod = crit_mod;
rez->crit_mod = crit_mod; rez->spell_visual = spell->spell->GetSpellData()->spell_visual;
rez->spell_visual = spell->spell->GetSpellData()->spell_visual; if (send_window)
if (send_window) client->SendResurrectionWindow();
client->SendResurrectionWindow(); else {
else { target->GetZone()->ResurrectSpawn(target, client);
target->GetZone()->ResurrectSpawn(target, client); rez->should_delete = true;
rez->should_delete = true;
}
client->GetResurrectMutex()->releasewritelock(__FUNCTION__, __LINE__);
} }
client->GetResurrectMutex()->releasewritelock(__FUNCTION__, __LINE__);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
else { else {
if(!target->IsPlayer()) if(!target->IsPlayer())
@ -9357,10 +9308,10 @@ int EQ2Emu_lua_SetVision(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->targets.size() > 0) { if (spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int8 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->GetInfoStruct()->set_vision(vision); ((Entity*)target)->GetInfoStruct()->set_vision(vision);
if (target->IsPlayer()) if (target->IsPlayer())
@ -9395,10 +9346,10 @@ int EQ2Emu_lua_BlurVision(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->targets.size() > 0) { if (spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int8 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->GetInfoStruct()->set_drunk(intensity); ((Entity*)target)->GetInfoStruct()->set_drunk(intensity);
if (target->IsPlayer()) if (target->IsPlayer())
@ -9433,10 +9384,10 @@ int EQ2Emu_lua_BreatheUnderwater(lua_State* state) {
return 0; return 0;
} }
if (spell && spell->targets.size() > 0) { if (spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int8 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->GetInfoStruct()->set_breathe_underwater(breatheUnderwater); ((Entity*)target)->GetInfoStruct()->set_breathe_underwater(breatheUnderwater);
if (target->IsPlayer()) if (target->IsPlayer())
@ -9488,10 +9439,10 @@ int EQ2Emu_lua_SetSpeedMultiplier(lua_State* state) {
if (val > 1.0f) if (val > 1.0f)
val = 1.0f - (val / 100.0f); val = 1.0f - (val / 100.0f);
if (spell && spell->spell && spell->targets.size() > 0) { if (spell && spell->spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int32 i = 0; i != spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* spawn = zone->GetSpawnByID(spell->targets.at(i)); Spawn* spawn = zone->GetSpawnByID(id);
if (spawn && spawn->IsEntity()) { if (spawn && spawn->IsEntity()) {
((Entity*)spawn)->SetSpeedMultiplier(val); ((Entity*)spawn)->SetSpeedMultiplier(val);
if (spawn->IsPlayer()) if (spawn->IsPlayer())
@ -9519,10 +9470,10 @@ int EQ2Emu_lua_SetIllusion(lua_State* state) {
LuaSpell* spell = lua_interface->GetCurrentSpell(state); LuaSpell* spell = lua_interface->GetCurrentSpell(state);
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
if (spell && spell->spell && spell->targets.size() > 0) { if (spell && spell->spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int32 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target) if (target)
target->SetIllusionModel(model); target->SetIllusionModel(model);
} }
@ -9547,10 +9498,10 @@ int EQ2Emu_lua_ResetIllusion(lua_State* state) {
LuaSpell* spell = lua_interface->GetCurrentSpell(state); LuaSpell* spell = lua_interface->GetCurrentSpell(state);
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
if (spell && spell->spell && spell->targets.size() > 0) { if (spell && spell->spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int32 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target) if (target)
target->SetIllusionModel(0); target->SetIllusionModel(0);
} }
@ -9694,13 +9645,11 @@ int EQ2Emu_lua_CureByType(lua_State* state) {
} }
} }
else { else {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
vector<int32> targets = spell->targets; vector<int32> targets = spell->targets;
vector<Entity*> targets_to_cure; vector<Entity*> targets_to_cure;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
@ -9708,7 +9657,6 @@ int EQ2Emu_lua_CureByType(lua_State* state) {
targets_to_cure.push_back((Entity*)target); targets_to_cure.push_back((Entity*)target);
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
vector<Entity*>::iterator itr; vector<Entity*>::iterator itr;
for(itr = targets_to_cure.begin(); itr != targets_to_cure.end(); itr++) { for(itr = targets_to_cure.begin(); itr != targets_to_cure.end(); itr++) {
@ -9746,12 +9694,9 @@ int EQ2Emu_lua_CureByControlEffect(lua_State* state) {
((Entity*)target)->CureDetrimentByControlEffect(cure_count, cure_type, cure_name.length() > 0 ? cure_name : (string)spell->spell->GetName(), spell->caster, cure_level); ((Entity*)target)->CureDetrimentByControlEffect(cure_count, cure_type, cure_name.length() > 0 ? cure_name : (string)spell->spell->GetName(), spell->caster, cure_level);
} }
else { else {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
vector<int32> targets = spell->targets; for (int32 id : spell->GetTargets()) {
target = zone->GetSpawnByID(id);
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
for (int8 i = 0; i < targets.size(); i++) {
target = zone->GetSpawnByID(targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
@ -9759,7 +9704,6 @@ int EQ2Emu_lua_CureByControlEffect(lua_State* state) {
if (((Entity*)target)->GetDetCount() > 0) if (((Entity*)target)->GetDetCount() > 0)
((Entity*)target)->CureDetrimentByControlEffect(cure_count, cure_type, cure_name.length() > 0 ? cure_name : (string)spell->spell->GetName(), spell->caster, cure_level); ((Entity*)target)->CureDetrimentByControlEffect(cure_count, cure_type, cure_name.length() > 0 ? cure_name : (string)spell->spell->GetName(), spell->caster, cure_level);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
} }
@ -9781,12 +9725,12 @@ int EQ2Emu_lua_CancelSpell(lua_State* state) {
return 0; return 0;
} }
if (!spell->caster->GetZone()) { if (!spell->zone) {
lua_interface->LogError("%s: LUA CancelSpell command error: unable to get the zone of the caster", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA CancelSpell command error: unable to get the zone of the caster", lua_interface->GetScriptName(state));
return 0; return 0;
} }
spell->caster->GetZone()->GetSpellProcess()->AddSpellCancel(spell); spell->zone->GetSpellProcess()->AddSpellCancel(spell);
return 0; return 0;
} }
@ -9807,16 +9751,14 @@ int EQ2Emu_lua_RemoveStealth(lua_State* state) {
if (spawn && spawn->IsEntity()) if (spawn && spawn->IsEntity())
((Entity*)spawn)->RemoveStealthSpell(spell); ((Entity*)spawn)->RemoveStealthSpell(spell);
else { else {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { spawn = zone->GetSpawnByID(id);
spawn = zone->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
((Entity*)spawn)->RemoveStealthSpell(spell); ((Entity*)spawn)->RemoveStealthSpell(spell);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
} }
@ -9837,16 +9779,14 @@ int EQ2Emu_lua_RemoveInvis(lua_State* state) {
if (spawn && spawn->IsEntity()) if (spawn && spawn->IsEntity())
((Entity*)spawn)->RemoveInvisSpell(spell); ((Entity*)spawn)->RemoveInvisSpell(spell);
else { else {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { spawn = zone->GetSpawnByID(id);
spawn = zone->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
((Entity*)spawn)->RemoveInvisSpell(spell); ((Entity*)spawn)->RemoveInvisSpell(spell);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
} }
@ -9973,7 +9913,7 @@ int EQ2Emu_lua_RemoveTriggerFromSpell(lua_State* state) {
return 0; return 0;
} }
if (!spell->caster || !spell->caster->GetZone()) { if (!spell->caster || !spell->zone) {
lua_interface->LogError("%s: LUA RemoveTriggerFromSpell command error: caster / caster zone must be set!", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA RemoveTriggerFromSpell command error: caster / caster zone must be set!", lua_interface->GetScriptName(state));
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
return 0; return 0;
@ -9989,7 +9929,7 @@ int EQ2Emu_lua_RemoveTriggerFromSpell(lua_State* state) {
if (remove_count >= spell->num_triggers) { if (remove_count >= spell->num_triggers) {
spell->num_triggers = 0; spell->num_triggers = 0;
if (spell->cancel_after_all_triggers) if (spell->cancel_after_all_triggers)
spell->caster->GetZone()->GetSpellProcess()->AddSpellCancel(spell); spell->zone->GetSpellProcess()->AddSpellCancel(spell);
} }
else { else {
spell->num_triggers -= remove_count; spell->num_triggers -= remove_count;
@ -10064,16 +10004,14 @@ int EQ2Emu_lua_AddImmunitySpell(lua_State* state) {
Entity* entity = ((Entity*)spawn); Entity* entity = ((Entity*)spawn);
entity->AddImmunity(spell, type); entity->AddImmunity(spell, type);
} }
else if(spell->caster && spell->caster->GetZone()) { else if(spell->zone) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { spawn = spell->zone->GetSpawnByID(id);
spawn = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
Entity* entity = ((Entity*)spawn); Entity* entity = ((Entity*)spawn);
entity->AddImmunity(spell, type); entity->AddImmunity(spell, type);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
@ -10101,16 +10039,14 @@ int EQ2Emu_lua_RemoveImmunitySpell(lua_State* state) {
Entity* entity = ((Entity*)spawn); Entity* entity = ((Entity*)spawn);
entity->RemoveImmunity(spell, type); entity->RemoveImmunity(spell, type);
} }
else if(spell->caster && spell->caster->GetZone()) { else if(spell->zone) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { spawn = spell->zone->GetSpawnByID(id);
spawn = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
Entity* entity = ((Entity*)spawn); Entity* entity = ((Entity*)spawn);
entity->RemoveImmunity(spell, type); entity->RemoveImmunity(spell, type);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
@ -10142,16 +10078,14 @@ int EQ2Emu_lua_SetSpellSnareValue(lua_State* state) {
((Entity*)spawn)->SetSnareValue(spell, val); ((Entity*)spawn)->SetSnareValue(spell, val);
} }
else if(spell && spell->caster && spell->caster->GetZone()) { else if(spell && spell->zone) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { spawn = spell->zone->GetSpawnByID(id);
spawn = spell->caster->GetZone()->GetSpawnByID(spell->targets.at(i));
if (!spawn || !spawn->IsEntity()) if (!spawn || !spawn->IsEntity())
continue; continue;
((Entity*)spawn)->SetSnareValue(spell, val); ((Entity*)spawn)->SetSnareValue(spell, val);
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
@ -11356,17 +11290,17 @@ int EQ2Emu_lua_Evac(lua_State* state) {
LuaSpell* spell = lua_interface->GetCurrentSpell(state); LuaSpell* spell = lua_interface->GetCurrentSpell(state);
if(!spell || !spell->caster || !spell->caster->GetZone()) { if(!spell || !spell->caster || !spell->zone) {
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
return 0; return 0;
} }
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
float x = spell->caster->GetZone()->GetSafeX(); float x = spell->zone->GetSafeX();
float y = spell->caster->GetZone()->GetSafeY(); float y = spell->zone->GetSafeY();
float z = spell->caster->GetZone()->GetSafeZ(); float z = spell->zone->GetSafeZ();
float h = spell->caster->GetZone()->GetSafeHeading(); float h = spell->zone->GetSafeHeading();
int numargs = lua_interface->GetNumberOfArgs(state); int numargs = lua_interface->GetNumberOfArgs(state);
@ -11379,9 +11313,8 @@ int EQ2Emu_lua_Evac(lua_State* state) {
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { Spawn* target2 = zone->GetSpawnByID(id);
Spawn* target2 = zone->GetSpawnByID(spell->targets.at(i));
if (!target2) if (!target2)
continue; continue;
@ -11414,14 +11347,12 @@ int EQ2Emu_lua_Evac(lua_State* state) {
client->QueuePacket(packet->serialize()); client->QueuePacket(packet->serialize());
safe_delete(packet); safe_delete(packet);
} }
client->GetCurrentZone()->RemoveSpawn(target2, false, false, true, true); client->GetCurrentZone()->RemoveSpawn(target2, false, false, true, true);
client->GetPlayer()->SetSpawnSentState(target2, SpawnState::SPAWN_STATE_SENT); client->GetPlayer()->SetSpawnSentState(target2, SpawnState::SPAWN_STATE_SENT);
} }
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
return 0; return 0;
@ -12367,10 +12298,10 @@ int EQ2Emu_lua_SetAlignment(lua_State* state) {
lua_interface->ResetFunctionStack(state); lua_interface->ResetFunctionStack(state);
if (spell && spell->targets.size() > 0) { if (spell && spell->GetTargetCount() > 0) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
for (int8 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
Spawn* target = zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = zone->GetSpawnByID(id);
if (target && target->IsEntity()) { if (target && target->IsEntity()) {
((Entity*)target)->GetInfoStruct()->set_alignment((sint8)alignment); ((Entity*)target)->GetInfoStruct()->set_alignment((sint8)alignment);
if (target->IsPlayer()) if (target->IsPlayer())
@ -14367,11 +14298,11 @@ int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state) {
lua_interface->LogError("%s: LUA GetSpellInitialTarget command error, caster does not exist.", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA GetSpellInitialTarget command error, caster does not exist.", lua_interface->GetScriptName(state));
return 0; return 0;
} }
if(!spell->caster->GetZone()) { if(!spell->zone) {
lua_interface->LogError("%s: LUA GetSpellInitialTarget command error, zone does not exist.", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA GetSpellInitialTarget command error, zone does not exist.", lua_interface->GetScriptName(state));
return 0; return 0;
} }
Spawn* spawn = spell->caster->GetZone()->GetSpawnByID(spell->initial_target); Spawn* spawn = spell->zone->GetSpawnByID(spell->initial_target);
if (spawn) { if (spawn) {
lua_interface->SetSpawnValue(state, spawn); lua_interface->SetSpawnValue(state, spawn);
return 1; return 1;
@ -14439,22 +14370,23 @@ int EQ2Emu_lua_GetSpellTargets(lua_State* state) {
lua_interface->LogError("%s: LUA GetSpellTargets command error, caster does not exist.", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA GetSpellTargets command error, caster does not exist.", lua_interface->GetScriptName(state));
return 0; return 0;
} }
if(!spell->caster->GetZone()) { if(!spell->zone) {
lua_interface->LogError("%s: LUA GetSpellTargets command error, zone does not exist.", lua_interface->GetScriptName(state)); lua_interface->LogError("%s: LUA GetSpellTargets command error, zone does not exist.", lua_interface->GetScriptName(state));
return 0; return 0;
} }
if (spell && spell->caster) { if (spell) {
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); std::vector<int32> targets = spell->GetTargets(); // snapshot under lock
lua_createtable(state, spell->targets.size(), 0); lua_createtable(state, targets.size(), 0); // preallocate array size
int newTable = lua_gettop(state); int newTable = lua_gettop(state);
for (int32 i = 0; i < spell->targets.size(); i++) {
Spawn* spawn = zone->GetSpawnByID(spell->targets.at(i)); int i = 0;
for (int32_t id : targets) {
Spawn* spawn = zone->GetSpawnByID(id);
lua_interface->SetSpawnValue(state, spawn); lua_interface->SetSpawnValue(state, spawn);
lua_rawseti(state, newTable, i + 1); lua_rawseti(state, newTable, ++i); // Lua is 1-indexed
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
return 1; return 1;
} }
} }

View File

@ -879,6 +879,9 @@ void LuaInterface::RemoveSpawnFromSpell(LuaSpell* spell, Spawn* spawn) {
((Entity*)spawn)->RemoveSpellBonus(spell); ((Entity*)spawn)->RemoveSpellBonus(spell);
((Entity*)spawn)->RemoveEffectsFromLuaSpell(spell); ((Entity*)spawn)->RemoveEffectsFromLuaSpell(spell);
((Entity*)spawn)->RemoveWard(spell); ((Entity*)spawn)->RemoveWard(spell);
if(spell->spell->GetSpellData()->det_type > 0 && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel))
((Entity*)spawn)->RemoveDetrimentalSpell(spell);
} }
} }
@ -959,33 +962,28 @@ void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool
return; return;
} }
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) {
if(!spell->zone) if(!spell->zone)
break; break;
Spawn* target = spell->zone->GetSpawnByID(spell->targets.at(i)); Spawn* target = spell->zone->GetSpawnByID(id);
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
RemoveSpawnFromSpell(spell, target); RemoveSpawnFromSpell(spell, target);
} }
multimap<int32,int8>::iterator entries; for (const auto& [char_id, pet_type] : spell->GetCharIDTargets()) {
for(entries = spell->char_id_targets.begin(); entries != spell->char_id_targets.end(); entries++) Client* tmpClient = zone_list.GetClientByCharID(char_id);
{
Client* tmpClient = zone_list.GetClientByCharID(entries->first);
if(tmpClient && tmpClient->GetPlayer()) if(tmpClient && tmpClient->GetPlayer())
{ {
RemoveSpawnFromSpell(spell, tmpClient->GetPlayer()); RemoveSpawnFromSpell(spell, tmpClient->GetPlayer());
} }
} }
spell->char_id_targets.clear(); // TODO: reach out to those clients in different spell->ClearCharTargets(); // TODO: reach out to those clients in different
spell->timer.Disable(); spell->timer.Disable();
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
if(removing_all_spells) { if(removing_all_spells) {
if(spell->zone && spell->zone->GetSpellProcess()) { if(spell->zone && spell->zone->GetSpellProcess()) {
spell->zone->GetSpellProcess()->RemoveSpellScriptTimerBySpell(spell); spell->zone->GetSpellProcess()->RemoveSpellScriptTimerBySpell(spell);
@ -1735,10 +1733,8 @@ void LuaInterface::DeletePendingSpells(bool all) {
if(!all) { if(!all) {
// rely on targets the spell->caster could be corrupt // rely on targets the spell->caster could be corrupt
if(spell->targets.size() > 0) { for (int32 id : spell->GetTargets()) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); Spawn* target = spell->zone->GetSpawnByID(id);
for (int8 i = 0; i < spell->targets.size(); i++) {
Spawn* target = spell->zone->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity()) if (!target || !target->IsEntity())
continue; continue;
@ -1746,8 +1742,6 @@ void LuaInterface::DeletePendingSpells(bool all) {
RemoveSpawnFromSpell(spell, target); RemoveSpawnFromSpell(spell, target);
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
}
if(spell->zone && spell->zone->GetSpellProcess()) { if(spell->zone && spell->zone->GetSpellProcess()) {
spell->zone->GetSpellProcess()->DeleteActiveSpell(spell, true); spell->zone->GetSpellProcess()->DeleteActiveSpell(spell, true);
@ -2160,7 +2154,6 @@ LuaSpell* LuaInterface::LoadSpellScript(const char* name) {
spell->interrupted = false; spell->interrupted = false;
spell->last_spellattack_hit = false; spell->last_spellattack_hit = false;
spell->crit = false; spell->crit = false;
spell->MSpellTargets.SetName("LuaSpell.MSpellTargets");
spell->cancel_after_all_triggers = false; spell->cancel_after_all_triggers = false;
spell->num_triggers = 0; spell->num_triggers = 0;
spell->num_calls = 0; spell->num_calls = 0;
@ -2510,7 +2503,6 @@ LuaSpell* LuaInterface::CreateSpellScript(const char* name, lua_State* existStat
new_spell->interrupted = false; new_spell->interrupted = false;
new_spell->crit = false; new_spell->crit = false;
new_spell->last_spellattack_hit = false; new_spell->last_spellattack_hit = false;
new_spell->MSpellTargets.SetName("LuaSpell.MSpellTargets");
new_spell->cancel_after_all_triggers = false; new_spell->cancel_after_all_triggers = false;
new_spell->num_triggers = 0; new_spell->num_triggers = 0;
new_spell->num_calls = 0; new_spell->num_calls = 0;

View File

@ -78,8 +78,10 @@ struct LuaSpell{
int32 initial_caster_char_id; int32 initial_caster_char_id;
int32 initial_target; int32 initial_target;
int32 initial_target_char_id; int32 initial_target_char_id;
mutable std::shared_mutex targets_mutex;
vector<int32> targets; vector<int32> targets;
vector<int32> removed_targets; // previously cancelled, expired, used, so on vector<int32> removed_targets; // previously cancelled, expired, used, so on
mutable std::shared_mutex char_id_targets_mutex;
multimap<int32, int8> char_id_targets; multimap<int32, int8> char_id_targets;
Spell* spell; Spell* spell;
lua_State* state; lua_State* state;
@ -99,13 +101,117 @@ struct LuaSpell{
bool cancel_after_all_triggers; bool cancel_after_all_triggers;
bool had_triggers; bool had_triggers;
bool had_dmg_remaining; bool had_dmg_remaining;
Mutex MSpellTargets;
Mutex MScriptMutex; Mutex MScriptMutex;
int32 effect_bitmask; int32 effect_bitmask;
bool restored; // restored spell cross zone bool restored; // restored spell cross zone
std::atomic<bool> has_proc; std::atomic<bool> has_proc;
ZoneServer* zone; ZoneServer* zone;
int16 initial_caster_level; int16 initial_caster_level;
void AddTarget(int32 target_id) {
std::unique_lock lock(targets_mutex);
targets.push_back(target_id);
}
int32 GetPrimaryTargetID() const {
std::shared_lock lock(targets_mutex);
return targets.empty() ? -1 : targets[0];
}
std::optional<int32_t> GetPrimaryTarget() const {
std::shared_lock lock(targets_mutex);
if (!targets.empty())
return targets[0];
return std::nullopt;
}
std::vector<int32> GetTargets() {
std::shared_lock lock(targets_mutex);
return targets;
}
bool HasNoTargets() const {
std::shared_lock lock(targets_mutex);
return targets.empty();
}
int32 GetTargetCount() const {
std::shared_lock lock(targets_mutex);
return static_cast<int32>(targets.size());
}
bool HasTarget(int32 id) const {
std::shared_lock lock(targets_mutex);
return std::find(targets.begin(), targets.end(), id) != targets.end();
}
std::vector<int32> GetRemovedTargets() const {
std::shared_lock lock(targets_mutex);
return removed_targets;
}
void RemoveTarget(int32 target_id) {
std::unique_lock lock(targets_mutex);
auto& v = targets;
v.erase(std::remove(v.begin(), v.end(), target_id), v.end());
removed_targets.push_back(target_id);
}
void AddRemoveTarget(int32 target_id) {
std::unique_lock lock(targets_mutex);
removed_targets.push_back(target_id);
}
void SwapTargets(std::vector<int32>& new_targets) {
std::unique_lock lock(targets_mutex);
targets.swap(new_targets);
}
void ClearTargets() {
std::unique_lock lock(targets_mutex);
targets.clear();
removed_targets.clear();
}
std::multimap<int32, int8> GetCharIDTargets() const {
std::shared_lock lock(char_id_targets_mutex);
return char_id_targets;
}
void AddCharIDTarget(int32 char_id, int8 value) {
std::unique_lock lock(char_id_targets_mutex);
char_id_targets.insert({char_id, value});
}
bool HasNoCharIDTargets() const {
std::shared_lock lock(char_id_targets_mutex);
return char_id_targets.empty();
}
void RemoveCharIDTarget(int32 char_id) {
std::unique_lock lock(char_id_targets_mutex);
char_id_targets.erase(char_id); // removes all entries with that key
}
void RemoveCharIDTargetAndType(int32 char_id, int8 type) {
std::unique_lock lock(char_id_targets_mutex);
auto range = char_id_targets.equal_range(char_id);
for (auto it = range.first; it != range.second; ++it) {
if (it->second == type) {
char_id_targets.erase(it);
break; // remove only one matching pair
}
}
}
void ClearCharTargets() {
std::unique_lock lock(char_id_targets_mutex);
char_id_targets.clear();
}
}; };
enum class LuaArgType { SINT64, INT64, SINT, INT, FLOAT, STRING, BOOL, SPAWN, ZONE, SKILL, ITEM, QUEST, SPELL /* etc */ }; enum class LuaArgType { SINT64, INT64, SINT, INT, FLOAT, STRING, BOOL, SPAWN, ZONE, SKILL, ITEM, QUEST, SPELL /* etc */ };

View File

@ -7404,13 +7404,11 @@ void Player::SaveSpellEffects()
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->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->initial_caster_level); 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 "); 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 ");
bool firstTarget = true; bool firstTarget = true;
map<Spawn*, int8> targetsInserted; map<Spawn*, int8> targetsInserted;
for (int8 t = 0; t < info->maintained_effects[i].spell->targets.size(); t++) { for (int32 id : info->maintained_effects[i].spell->GetTargets()) {
int32 spawn_id = info->maintained_effects[i].spell->targets.at(t); Spawn* spawn = GetZone()->GetSpawnByID(id);
Spawn* spawn = GetZone()->GetSpawnByID(spawn_id);
LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %u to identify for spell %s", GetName(), spawn_id, info->maintained_effects[i].spell->spell->GetName()); LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %u to identify for spell %s", GetName(), spawn_id, info->maintained_effects[i].spell->spell->GetName());
if(spawn && (spawn->IsPlayer() || spawn->IsPet())) if(spawn && (spawn->IsPlayer() || spawn->IsPet()))
{ {
@ -7446,23 +7444,22 @@ void Player::SaveSpellEffects()
", " + std::to_string(info->maintained_effects[i].slot_pos) + ")"); ", " + std::to_string(info->maintained_effects[i].slot_pos) + ")");
firstTarget = false; firstTarget = false;
} }
} }
multimap<int32,int8>::iterator entries; for (const auto& [char_id, pet_type] : info->maintained_effects[i].spell->GetCharIDTargets()) {
for(entries = info->maintained_effects[i].spell->char_id_targets.begin(); entries != info->maintained_effects[i].spell->char_id_targets.end(); entries++) {
{ if(!firstTarget)
if(!firstTarget) insertTargets.append(", ");
insertTargets.append(", ");
LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target %s (%u) added to spell %s", GetName(), spawn ? spawn->GetName() : "NA", entries->first, info->maintained_effects[i].spell->spell->GetName()); LogWrite(SPELL__DEBUG, 0, "Spell", "%s has target (%u) added to spell %s", GetName(), char_id, info->maintained_effects[i].spell->spell->GetName());
insertTargets.append("(" + std::to_string(caster_char_id) + ", " + std::to_string(entries->first) + ", " + std::to_string(entries->second) + ", " + insertTargets.append("(" + std::to_string(caster_char_id) + ", " + std::to_string(char_id) + ", " + std::to_string(pet_type) + ", " +
std::to_string(DB_TYPE_MAINTAINEDEFFECTS) + ", " + std::to_string(info->maintained_effects[i].spell_id) + ", " + std::to_string(i) + std::to_string(DB_TYPE_MAINTAINEDEFFECTS) + ", " + std::to_string(info->maintained_effects[i].spell_id) + ", " + std::to_string(i) +
", " + std::to_string(info->maintained_effects[i].slot_pos) + ")"); ", " + std::to_string(info->maintained_effects[i].slot_pos) + ")");
firstTarget = false; firstTarget = false;
} }
info->maintained_effects[i].spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__); if(!firstTarget) {
if(!firstTarget) { savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, insertTargets.c_str());
savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, insertTargets.c_str()); }
} }
} }
} }

View File

@ -1133,8 +1133,7 @@ void PlayerGroupManager::UpdateGroupBuffs() {
if (spell && spell->GetSpellData()->group_spell && spell->GetSpellData()->friendly_spell && if (spell && spell->GetSpellData()->group_spell && spell->GetSpellData()->friendly_spell &&
(spell->GetSpellData()->target_type == SPELL_TARGET_GROUP_AE || spell->GetSpellData()->target_type == SPELL_TARGET_RAID_AE)) { (spell->GetSpellData()->target_type == SPELL_TARGET_GROUP_AE || spell->GetSpellData()->target_type == SPELL_TARGET_RAID_AE)) {
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__); luaspell->ClearCharTargets();
luaspell->char_id_targets.clear();
for (target_itr = group->GetMembers()->begin(); target_itr != group->GetMembers()->end(); target_itr++) { for (target_itr = group->GetMembers()->begin(); target_itr != group->GetMembers()->end(); target_itr++) {
group_member = (*target_itr)->member; group_member = (*target_itr)->member;
@ -1152,8 +1151,9 @@ void PlayerGroupManager::UpdateGroupBuffs() {
if (group_member->GetSpellEffect(spell->GetSpellID(), caster)) { if (group_member->GetSpellEffect(spell->GetSpellID(), caster)) {
has_effect = true; has_effect = true;
} }
if (!has_effect && (std::find(luaspell->removed_targets.begin(), std::vector<int32> removed_targets = luaspell->GetRemovedTargets();
luaspell->removed_targets.end(), group_member->GetID()) != luaspell->removed_targets.end())) { if (!has_effect && (std::find(removed_targets.begin(),
removed_targets.end(), group_member->GetID()) != removed_targets.end())) {
continue; continue;
} }
// Check if player is within range of the caster // Check if player is within range of the caster
@ -1246,9 +1246,8 @@ void PlayerGroupManager::UpdateGroupBuffs() {
} }
} }
luaspell->targets.swap(new_target_list); luaspell->SwapTargets(new_target_list);
SpellProcess::AddSelfAndPet(luaspell, caster); SpellProcess::AddSelfAndPet(luaspell, caster);
luaspell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
new_target_list.clear(); new_target_list.clear();
} }
} }

View File

@ -424,6 +424,7 @@ bool SpellProcess::DeleteCasterSpell(Spawn* caster, Spell* spell, string reason)
return ret; return ret;
} }
bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removing_all_spells, Spawn* remove_target, bool zone_shutting_down, bool shared_lock_spell){ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removing_all_spells, Spawn* remove_target, bool zone_shutting_down, bool shared_lock_spell){
if(shared_lock_spell && !removing_all_spells) { if(shared_lock_spell && !removing_all_spells) {
MSpellProcess.lock_shared(); MSpellProcess.lock_shared();
@ -433,30 +434,22 @@ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removi
Spawn* target = 0; Spawn* target = 0;
bool target_valid = false; bool target_valid = false;
if(spell) { if(spell) {
spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); if(remove_target) {
if(remove_target && spell->targets.size() > 1) { for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { if(remove_target->GetID() == id) {
if(remove_target->GetID() == spell->targets.at(i)) {
if(remove_target->IsEntity()){ if(remove_target->IsEntity()){
spell->removed_targets.push_back(remove_target->GetID()); spell->RemoveTarget(remove_target->GetID());
((Entity*)remove_target)->RemoveProc(0, spell); lua_interface->RemoveSpawnFromSpell(spell, remove_target);
((Entity*)remove_target)->RemoveSpellEffect(spell);
((Entity*)remove_target)->RemoveSpellBonus(spell);
if(spell->spell->GetSpellData()->det_type > 0 && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel))
((Entity*)remove_target)->RemoveDetrimentalSpell(spell);
} }
spell->targets.erase(spell->targets.begin()+i, spell->targets.begin()+i+1);
target_valid = true; target_valid = true;
break; break;
} }
} }
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
if(shared_lock_spell && !removing_all_spells) { if(shared_lock_spell && !removing_all_spells) {
MSpellProcess.unlock_shared(); MSpellProcess.unlock_shared();
} }
return target_valid; return target_valid;
} }
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
if (!zone_shutting_down && spell->caster) { // spell->caster ptr cannot be trusted during zone shutdown if (!zone_shutting_down && spell->caster) { // spell->caster ptr cannot be trusted during zone shutdown
if(spell->caster->GetThreatTransfer() && spell->caster->GetThreatTransfer()->Spell == spell) { if(spell->caster->GetThreatTransfer() && spell->caster->GetThreatTransfer()->Spell == spell) {
spell->caster->SetThreatTransfer(nullptr); spell->caster->SetThreatTransfer(nullptr);
@ -490,24 +483,17 @@ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removi
spell->caster->RemoveProc(0, spell); spell->caster->RemoveProc(0, spell);
spell->caster->RemoveMaintainedSpell(spell); spell->caster->RemoveMaintainedSpell(spell);
CheckRemoveTargetFromSpell(spell, removing_all_spells, removing_all_spells); CheckRemoveTargetFromSpell(spell, removing_all_spells, removing_all_spells);
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->zone;
if(zone) { if(zone) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int32 i = 0; i < spell->targets.size(); i++) { target = zone->GetSpawnByID(id);
target = zone->GetSpawnByID(spell->targets.at(i));
if(target && target->IsEntity()){ if(target && target->IsEntity()){
spell->removed_targets.push_back(target->GetID()); spell->RemoveTarget(target->GetID());
((Entity*)target)->RemoveProc(0, spell); lua_interface->RemoveSpawnFromSpell(spell, target);
((Entity*)target)->RemoveSpellEffect(spell);
((Entity*)target)->RemoveSpellBonus(spell);
if(spell->spell->GetSpellData()->det_type > 0 && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel))
((Entity*)target)->RemoveDetrimentalSpell(spell);
} }
else{ else{
spell->caster->RemoveSpellEffect(spell); spell->RemoveTarget(spell->caster->GetID());
spell->caster->RemoveSpellBonus(spell); lua_interface->RemoveSpawnFromSpell(spell, spell->caster);
if(spell->spell->GetSpellData()->det_type > 0 && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel))
spell->caster->RemoveDetrimentalSpell(spell);
} }
if(target && target->IsPlayer() && spell->spell->GetSpellData()->fade_message.length() > 0){ if(target && target->IsPlayer() && spell->spell->GetSpellData()->fade_message.length() > 0){
Client* client = ((Player*)target)->GetClient(); Client* client = ((Player*)target)->GetClient();
@ -528,7 +514,6 @@ bool SpellProcess::DeleteCasterSpell(LuaSpell* spell, string reason, bool removi
} }
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
ret = true; ret = true;
} }
@ -553,10 +538,9 @@ bool SpellProcess::ProcessSpell(LuaSpell* spell, bool first_cast, const char* fu
else if(lua_interface && !spell->interrupted){ else if(lua_interface && !spell->interrupted){
if(all_targets) if(all_targets)
{ {
for(int t=0;t<spell->targets.size();t++) for (int32 id : spell->GetTargets()) {
{ if(spell->zone) {
if(spell->caster->GetZone()) { Spawn* altSpawn = spell->zone->GetSpawnByID(id);
Spawn* altSpawn = spell->caster->GetZone()->GetSpawnByID(spell->targets[t]);
if(altSpawn) if(altSpawn)
{ {
std::string functionCall = ApplyLuaFunction(spell, first_cast, function, timer, altSpawn); std::string functionCall = ApplyLuaFunction(spell, first_cast, function, timer, altSpawn);
@ -1478,7 +1462,7 @@ void SpellProcess::ProcessSpell(ZoneServer* zone, Spell* spell, Entity* caster,
} }
} }
if (lua_spell->targets.size() == 0 && spell->GetSpellData()->max_aoe_targets == 0) if (lua_spell->GetTargetCount() == 0 && spell->GetSpellData()->max_aoe_targets == 0)
{ {
LogWrite(SPELL__ERROR, 0, "Spell", "SpellProcess::ProcessSpell Unable to find any spell targets for spell '%s', spell type: %u, target type %u.", LogWrite(SPELL__ERROR, 0, "Spell", "SpellProcess::ProcessSpell Unable to find any spell targets for spell '%s', spell type: %u, target type %u.",
spell->GetName(), spell->GetSpellData()->spell_type, spell->GetSpellData()->target_type); spell->GetName(), spell->GetSpellData()->spell_type, spell->GetSpellData()->target_type);
@ -1719,9 +1703,9 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
Client* client = 0; Client* client = 0;
if(spell->caster && spell->caster->IsPlayer()) if(spell->caster && spell->caster->IsPlayer())
client = ((Player*)spell->caster)->GetClient(); client = ((Player*)spell->caster)->GetClient();
if (spell->spell->GetSpellData()->max_aoe_targets > 0 && spell->targets.size() == 0) { if (spell->spell->GetSpellData()->max_aoe_targets > 0 && spell->GetTargetCount() == 0) {
GetSpellTargetsTrueAOE(spell); GetSpellTargetsTrueAOE(spell);
if (spell->targets.size() == 0) { if (spell->GetTargetCount() == 0) {
if(client) if(client)
{ {
client->GetPlayer()->UnlockAllSpells(true); client->GetPlayer()->UnlockAllSpells(true);
@ -1772,8 +1756,8 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
ZoneServer* zone = spell->caster->GetZone(); ZoneServer* zone = spell->caster->GetZone();
Spawn* target = 0; Spawn* target = 0;
if(processedSpell){ if(processedSpell){
for (int32 i = 0; i < spell->targets.size(); i++) { for (int32 id : spell->GetTargets()) {
target = zone->GetSpawnByID(spell->targets[i]); target = zone->GetSpawnByID(id);
if (!target) if (!target)
continue; continue;
@ -1815,11 +1799,12 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
return false; return false;
} }
if(!spell->resisted && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel || spell->spell->GetSpellData()->spell_book_type == SPELL_BOOK_TYPE_NOT_SHOWN)) { if(!spell->resisted && (spell->spell->GetSpellDuration() > 0 || spell->spell->GetSpellData()->duration_until_cancel || spell->spell->GetSpellData()->spell_book_type == SPELL_BOOK_TYPE_NOT_SHOWN)) {
for (int32 i = 0; i < spell->targets.size(); i++) { bool firstTarget = true;
for (int32 id : spell->GetTargets()) {
//LogWrite(SPELL__ERROR, 0, "Spell", "No precast function found for %s", ((Entity*)target)->GetName()); //LogWrite(SPELL__ERROR, 0, "Spell", "No precast function found for %s", ((Entity*)target)->GetName());
target = zone->GetSpawnByID(spell->targets.at(i)); target = zone->GetSpawnByID(id);
if (!target && spell->targets.at(i) == spell->caster->GetID()) { if (!target && id == spell->caster->GetID()) {
target = spell->caster; target = spell->caster;
} }
if (!target) { if (!target) {
@ -1828,9 +1813,10 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
} }
continue; continue;
} }
if (i == 0 && !spell->spell->GetSpellData()->not_maintained) { if (firstTarget && !spell->spell->GetSpellData()->not_maintained) {
spell->caster->AddMaintainedSpell(spell); spell->caster->AddMaintainedSpell(spell);
} }
firstTarget = false;
SpellEffects* effect = ((Entity*)target)->GetSpellEffect(spell->spell->GetSpellID()); SpellEffects* effect = ((Entity*)target)->GetSpellEffect(spell->spell->GetSpellID());
if (effect && effect->tier > spell->spell->GetSpellTier()) { if (effect && effect->tier > spell->spell->GetSpellTier()) {
@ -1885,16 +1871,14 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
ho = soloItr->second; ho = soloItr->second;
bool match = false; bool match = false;
LogWrite(SPELL__DEBUG, 0, "HO", "target = %u", ho->GetTarget()); LogWrite(SPELL__DEBUG, 0, "HO", "target = %u", ho->GetTarget());
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (int8 i = 0; i < spell->targets.size(); i++) { LogWrite(SPELL__DEBUG, 0, "HO", "Target ID: %u", id);
LogWrite(SPELL__DEBUG, 0, "HO", "Target ID: %u", spell->targets.at(i)); if (id == ho->GetTarget() || spell->spell->GetSpellData()->friendly_spell) {
if (spell->targets.at(i) == ho->GetTarget() || spell->spell->GetSpellData()->friendly_spell) {
match = true; match = true;
LogWrite(SPELL__DEBUG, 0, "HO", "match found"); LogWrite(SPELL__DEBUG, 0, "HO", "match found");
break; break;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
if(match && !spell->spell) if(match && !spell->spell)
LogWrite(SPELL__ERROR, 0, "HO", "%s: spell->spell is nullptr", client->GetPlayer()->GetName()); LogWrite(SPELL__ERROR, 0, "HO", "%s: spell->spell is nullptr", client->GetPlayer()->GetName());
@ -1921,10 +1905,9 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
if (groupItr != m_groupHO.end()) { if (groupItr != m_groupHO.end()) {
ho = groupItr->second; ho = groupItr->second;
int32 group_id = client->GetPlayer()->GetGroupMemberInfo()->group_id; int32 group_id = client->GetPlayer()->GetGroupMemberInfo()->group_id;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); int32 first_target = spell->GetPrimaryTargetID();
if (((spell->targets.size() > 0 && spell->targets.at(0) == ho->GetTarget()) || spell->spell->GetSpellData()->friendly_spell) if (((first_target != 0xFFFFFFFF && first_target == ho->GetTarget()) || spell->spell->GetSpellData()->friendly_spell)
&& ho->UpdateHeroicOP(spell->spell->GetSpellIconHeroicOp())) { && ho->UpdateHeroicOP(spell->spell->GetSpellIconHeroicOp())) {
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__); world.GetGroupManager()->GroupLock(__FUNCTION__, __LINE__);
deque<GroupMemberInfo*>::iterator itr; deque<GroupMemberInfo*>::iterator itr;
@ -1951,8 +1934,6 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
m_groupHO.erase(groupItr); m_groupHO.erase(groupItr);
} }
} }
else
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
} }
MGroupHO.releasewritelock(__FUNCTION__, __LINE__); MGroupHO.releasewritelock(__FUNCTION__, __LINE__);
@ -2071,14 +2052,12 @@ void SpellProcess::RemoveSpellTimersFromSpawn(Spawn* spawn, bool remove_all, boo
bool foundMatch = false; bool foundMatch = false;
if(spawn != spell->caster) { if(spawn != spell->caster) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); for (int32 id : spell->GetTargets()) {
for (i = 0; i < spell->targets.size(); i++){ if (spawn->GetID() == id){
if (spawn->GetID() == spell->targets.at(i)){
foundMatch = true; foundMatch = true;
break; break;
} }
} }
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
if(foundMatch) { if(foundMatch) {
if (spawn->IsEntity()) if (spawn->IsEntity())
@ -2289,7 +2268,6 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
luaspell->initial_target_char_id = (secondary_target && secondary_target->IsPlayer()) ? ((Player*)secondary_target)->GetCharacterID() : 0; luaspell->initial_target_char_id = (secondary_target && secondary_target->IsPlayer()) ? ((Player*)secondary_target)->GetCharacterID() : 0;
} }
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
// Group AE type NOTE: Add support for RAID AE to affect raid members once raids have been completed // Group AE type NOTE: Add support for RAID AE to affect raid members once raids have been completed
if (target_type == SPELL_TARGET_GROUP_AE || spell_type == SPELL_TYPE_ALLGROUPTARGETS || target_type == SPELL_TARGET_RAID_AE) if (target_type == SPELL_TARGET_GROUP_AE || spell_type == SPELL_TYPE_ALLGROUPTARGETS || target_type == SPELL_TARGET_RAID_AE)
{ {
@ -2418,7 +2396,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
} }
else if (target->IsPlayer() || target->IsBot() || (target->IsNPC() && ((Entity*)target)->GetInfoStruct()->get_friendly_target_npc())) // else it is not raid, group only or group spell else if (target->IsPlayer() || target->IsBot() || (target->IsNPC() && ((Entity*)target)->GetInfoStruct()->get_friendly_target_npc())) // else it is not raid, group only or group spell
AddLuaSpellTarget(luaspell, target->GetID(), false); // return target for single spell AddLuaSpellTarget(luaspell, target->GetID(), false); // return target for single spell
else if ((luaspell->targets.size() < 1) || (!target->IsPet() || (((Entity*)target)->GetOwner() && !((Entity*)target)->GetOwner()->IsPlayer()))) else if ((luaspell->HasNoTargets()) || (!target->IsPet() || (((Entity*)target)->GetOwner() && !((Entity*)target)->GetOwner()->IsPlayer())))
AddLuaSpellTarget(luaspell, caster->GetID(), false); // and if no target, cast on self AddLuaSpellTarget(luaspell, caster->GetID(), false); // and if no target, cast on self
} }
else if (caster->IsNPC()) // caster is an NPC else if (caster->IsNPC()) // caster is an NPC
@ -2562,11 +2540,10 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
} }
} }
} }
luaspell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
if (luaspell && luaspell->targets.size() > 20) if (luaspell && luaspell->GetTargetCount() > 20)
LogWrite(SPELL__WARNING, 0, "Spell", "Warning in %s: Size of targets array is %u", __FUNCTION__, luaspell->targets.size()); LogWrite(SPELL__WARNING, 0, "Spell", "Warning in %s: Size of targets array is %u", __FUNCTION__, luaspell->GetTargetCount());
} }
bool SpellProcess::GetPlayerGroupTargets(Player* target, Spawn* caster, LuaSpell* luaspell, bool bypassSpellChecks, bool bypassRangeChecks) bool SpellProcess::GetPlayerGroupTargets(Player* target, Spawn* caster, LuaSpell* luaspell, bool bypassSpellChecks, bool bypassRangeChecks)
@ -2620,7 +2597,6 @@ void SpellProcess::GetSpellTargetsTrueAOE(LuaSpell* luaspell) {
} }
int32 ignore_target = 0; int32 ignore_target = 0;
std::vector<std::pair<int32, float>> spawns = luaspell->caster->GetZone()->GetAttackableSpawnsByDistance(luaspell->caster, luaspell->spell->GetSpellData()->radius); std::vector<std::pair<int32, float>> spawns = luaspell->caster->GetZone()->GetAttackableSpawnsByDistance(luaspell->caster, luaspell->spell->GetSpellData()->radius);
luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
int32 i = 0; int32 i = 0;
for (const auto& pair : spawns) { for (const auto& pair : spawns) {
if (i == 0){ if (i == 0){
@ -2634,7 +2610,7 @@ void SpellProcess::GetSpellTargetsTrueAOE(LuaSpell* luaspell) {
i++; i++;
if (luaspell->targets.size() >= luaspell->spell->GetSpellData()->max_aoe_targets) if (luaspell->GetTargetCount() >= luaspell->spell->GetSpellData()->max_aoe_targets)
break; break;
int32 target_id = pair.first; int32 target_id = pair.first;
@ -2653,14 +2629,13 @@ void SpellProcess::GetSpellTargetsTrueAOE(LuaSpell* luaspell) {
AddLuaSpellTarget(luaspell, spawn->GetID(), false); AddLuaSpellTarget(luaspell, spawn->GetID(), false);
} }
if (luaspell->targets.size() >= luaspell->spell->GetSpellData()->max_aoe_targets) if (luaspell->GetTargetCount() >= luaspell->spell->GetSpellData()->max_aoe_targets)
break; break;
} }
luaspell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
} }
if (luaspell->targets.size() > 20) if (luaspell->GetTargetCount() > 20)
LogWrite(SPELL__DEBUG, 0, "Spell", "Warning in SpellProcess::GetSpellTargetsTrueAOE Size of targets array is %u", luaspell->targets.size()); LogWrite(SPELL__DEBUG, 0, "Spell", "Warning in SpellProcess::GetSpellTargetsTrueAOE Size of targets array is %u", luaspell->GetTargetCount());
} }
void SpellProcess::AddSpellScriptTimer(SpellScriptTimer* timer) { void SpellProcess::AddSpellScriptTimer(SpellScriptTimer* timer) {
@ -2811,58 +2786,46 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete
MRemoveTargetList.writelock(__FUNCTION__, __LINE__); MRemoveTargetList.writelock(__FUNCTION__, __LINE__);
if (remove_target_list.size() > 0){ if (remove_target_list.size() > 0){
vector<Spawn*> spawnsToRemove; vector<Spawn*> spawnsToRemove;
map<LuaSpell*, vector<int32>*>::iterator remove_itr;
vector<int32>::iterator remove_target_itr; vector<int32>::iterator remove_target_itr;
vector<int32>::iterator target_itr; vector<int32>::iterator target_itr;
vector<int32>* targets;
vector<int32>* remove_targets = 0; vector<int32>* remove_targets = 0;
Spawn* remove_spawn = 0; Spawn* remove_spawn = 0;
bool should_delete = false; bool should_delete = false;
bool dropped_lock = false; bool dropped_lock = false;
bool targets_empty = false; bool targets_empty = false;
for (remove_itr = remove_target_list.begin(); remove_itr != remove_target_list.end(); remove_itr++){ auto it = remove_target_list.find(spell);
if (remove_itr->first == spell){ if (it != remove_target_list.end()) {
targets = &spell->targets; remove_targets = it->second;
remove_targets = remove_itr->second; if (remove_targets){
if (remove_targets && targets){ for (remove_target_itr = remove_targets->begin(); remove_target_itr != remove_targets->end(); remove_target_itr++){
spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); remove_spawn = spell->zone->GetSpawnByID((*remove_target_itr));
for (remove_target_itr = remove_targets->begin(); remove_target_itr != remove_targets->end(); remove_target_itr++){ if (remove_spawn) {
remove_spawn = spell->zone->GetSpawnByID((*remove_target_itr)); bool found_target = false;
if (remove_spawn) { if(remove_spawn->IsPlayer())
bool found_target = false; {
if(remove_spawn->IsPlayer()) spell->RemoveCharIDTarget(((Player*)remove_spawn)->GetCharacterID());
{ }
multimap<int32,int8>::iterator entries; for (int32 id : spell->GetTargets()) {
while((entries = spell->char_id_targets.find(((Player*)remove_spawn)->GetCharacterID())) != spell->char_id_targets.end()) if (remove_spawn->GetID() == id) {
{ found_target = true;
spell->char_id_targets.erase(entries); spell->RemoveTarget(id);
} lua_interface->RemoveSpawnFromSpell(spell, remove_spawn);
} LogWrite(SPELL__DEBUG, 0, "Spell", "%s CheckRemoveTargetFromSpell %s (%u).", spell->spell->GetName(), remove_spawn->GetName(), remove_spawn->GetID());
for (target_itr = targets->begin(); target_itr != targets->end(); target_itr++) { if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end())
if (remove_spawn->GetID() == (*target_itr)) { spawnsToRemove.push_back(remove_spawn);
found_target = true;
((Entity*)remove_spawn)->RemoveProc(0, spell);
((Entity*)remove_spawn)->RemoveMaintainedSpell(spell);
LogWrite(SPELL__DEBUG, 0, "Spell", "%s CheckRemoveTargetFromSpell %s (%u).", spell->spell->GetName(), remove_spawn->GetName(), remove_spawn->GetID());
targets->erase(target_itr);
if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end())
spawnsToRemove.push_back(remove_spawn);
break;
}
}
targets_empty = (targets->size() == 0 && spell->char_id_targets.size() == 0);
if (targets_empty && allow_delete) {
should_delete = true;
break; break;
} }
else if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end()) { }
spawnsToRemove.push_back(remove_spawn); targets_empty = (spell->HasNoTargets() && spell->HasNoCharIDTargets());
} if (targets_empty && allow_delete) {
should_delete = true;
break;
}
else if(remove_spawn && std::find(spawnsToRemove.begin(), spawnsToRemove.end(), remove_spawn) == spawnsToRemove.end()) {
spawnsToRemove.push_back(remove_spawn);
} }
} }
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
break;
} }
} }
@ -3005,18 +2968,13 @@ void SpellProcess::DeleteSpell(LuaSpell* spell)
lua_interface->RemoveCustomSpell(spell->spell->GetSpellID()); lua_interface->RemoveCustomSpell(spell->spell->GetSpellID());
safe_delete(spell->spell); safe_delete(spell->spell);
} }
if(spell->targets.size() > 0) { for (int32 id : spell->GetTargets()) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); Spawn* target = spell->zone->GetSpawnByID(id);
for (int8 i = 0; i < spell->targets.size(); i++) { if (!target || !target->IsEntity())
Spawn* target = spell->zone->GetSpawnByID(spell->targets.at(i)); continue;
if (!target || !target->IsEntity())
continue;
if(target->IsEntity()) { spell->RemoveTarget(target->GetID());
lua_interface->RemoveSpawnFromSpell(spell, target); lua_interface->RemoveSpawnFromSpell(spell, target);
}
}
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
} }
lua_interface->SetLuaUserDataStale(spell); lua_interface->SetLuaUserDataStale(spell);
@ -3078,20 +3036,15 @@ void SpellProcess::DeleteActiveSpell(LuaSpell* spell, bool skipRemoveCurrent) {
bool SpellProcess::AddLuaSpellTarget(LuaSpell* lua_spell, int32 id, bool lock_spell_targets) { bool SpellProcess::AddLuaSpellTarget(LuaSpell* lua_spell, int32 id, bool lock_spell_targets) {
bool ret = false; bool ret = false;
if(lock_spell_targets)
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
if(std::find(lua_spell->targets.begin(), lua_spell->targets.end(), id) != lua_spell->targets.end()) { if(lua_spell->HasTarget(id)) {
ret = true; ret = true;
} }
else if(std::find(lua_spell->removed_targets.begin(), lua_spell->removed_targets.end(), id) == lua_spell->removed_targets.end()) { else if(!lua_spell->HasTarget(id)) {
lua_spell->targets.push_back(id); lua_spell->AddTarget(id);
ret = true; ret = true;
} }
if(lock_spell_targets)
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
return ret; return ret;
} }

View File

@ -8189,9 +8189,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
} }
else else
{ {
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); lua_spell->AddCharIDTarget(player->GetCharacterID(), 0);
lua_spell->char_id_targets.insert(make_pair(player->GetCharacterID(),0));
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
player->MSpellEffects.releasewritelock(); player->MSpellEffects.releasewritelock();
continue; continue;
@ -8219,13 +8217,7 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
info->spell_effects[effect_slot].total_time = total_time; info->spell_effects[effect_slot].total_time = total_time;
info->spell_effects[effect_slot].spell = lua_spell; info->spell_effects[effect_slot].spell = lua_spell;
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); lua_spell->AddCharIDTarget(player->GetCharacterID(), 0);
multimap<int32,int8>::iterator entries;
while((entries = lua_spell->char_id_targets.find(player->GetCharacterID())) != lua_spell->char_id_targets.end())
{
lua_spell->char_id_targets.erase(entries);
}
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
lua_spell->slot_pos = slot_pos; lua_spell->slot_pos = slot_pos;
if(!isExistingLuaSpell) if(!isExistingLuaSpell)
@ -8275,8 +8267,6 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
{ {
if(client != client2) if(client != client2)
{ {
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
if(client2->GetPlayer()->GetPet() && maintained_target_type == PET_TYPE_COMBAT) if(client2->GetPlayer()->GetPet() && maintained_target_type == PET_TYPE_COMBAT)
{ {
restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()->GetPet())); restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()->GetPet()));
@ -8287,29 +8277,16 @@ void WorldDatabase::LoadCharacterSpellEffects(int32 char_id, Client* client, int
restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()->GetCharmedPet())); restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()->GetCharmedPet()));
// target added via restoreSpells // target added via restoreSpells
} }
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
} // end of pet clause } // end of pet clause
else if(client != client2) // maintained type must be 0, so client else if(client != client2) // maintained type must be 0, so client
restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer())); restoreSpells.insert(make_pair(lua_spell, client2->GetPlayer()));
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); lua_spell->RemoveCharIDTargetAndType(target_char, maintained_target_type);
multimap<int32,int8>::iterator entries;
for(entries = lua_spell->char_id_targets.begin(); entries != lua_spell->char_id_targets.end(); entries++)
{
int32 ent_char_id = entries->first;
int8 ent_target_type = entries->second;
if(ent_char_id == target_char && ent_target_type == maintained_target_type)
entries = lua_spell->char_id_targets.erase(entries);
}
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
else else
{ {
lua_spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); lua_spell->AddCharIDTarget(target_char,maintained_target_type);
lua_spell->char_id_targets.insert(make_pair(target_char,maintained_target_type));
lua_spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);
} }
} }
} }