diff --git a/source/WorldServer/LuaInterface.cpp b/source/WorldServer/LuaInterface.cpp index 37d760d..bace2ef 100644 --- a/source/WorldServer/LuaInterface.cpp +++ b/source/WorldServer/LuaInterface.cpp @@ -822,7 +822,7 @@ lua_State* LuaInterface::LoadLuaFile(const char* name) { return 0; } -void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool can_delete, string reason, bool removing_all_spells) { +void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool can_delete, string reason, bool removing_all_spells, bool return_after_call_remove, Spawn* overrideTarget) { if(call_remove_function){ lua_getglobal(spell->state, "remove"); if (!lua_isfunction(spell->state, lua_gettop(spell->state))){ @@ -835,7 +835,9 @@ void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool lua_pushlightuserdata(spell->state, spawn_wrapper); if(spell->caster && (spell->initial_target || spell->caster->GetTarget())){ spawn_wrapper = new LUASpawnWrapper(); - if(!spell->initial_target) + if(overrideTarget) + spawn_wrapper->spawn = overrideTarget; + else if(!spell->initial_target) spawn_wrapper->spawn = spell->caster->GetTarget(); else if(spell->caster->GetZone()) { spawn_wrapper->spawn = spell->caster->GetZone()->GetSpawnByID(spell->initial_target); @@ -890,6 +892,9 @@ void LuaInterface::RemoveSpell(LuaSpell* spell, bool call_remove_function, bool ResetFunctionStack(spell->state); } + if(return_after_call_remove) + return; + spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); if(spell->caster) { for (int8 i = 0; i < spell->targets.size(); i++) { diff --git a/source/WorldServer/LuaInterface.h b/source/WorldServer/LuaInterface.h index cd26c55..bf04c32 100644 --- a/source/WorldServer/LuaInterface.h +++ b/source/WorldServer/LuaInterface.h @@ -194,7 +194,7 @@ public: bool LoadRegionScript(const char* name); LuaSpell* LoadSpellScript(string name); LuaSpell* LoadSpellScript(const char* name); - void RemoveSpell(LuaSpell* spell, bool call_remove_function = true, bool can_delete = true, string reason = "", bool removing_all_spells = false); + void RemoveSpell(LuaSpell* spell, bool call_remove_function = true, bool can_delete = true, string reason = "", bool removing_all_spells = false, bool return_after_call_remove = false, Spawn* overrideTarget = nullptr); Spawn* GetSpawn(lua_State* state, int8 arg_num = 1); Item* GetItem(lua_State* state, int8 arg_num = 1); Quest* GetQuest(lua_State* state, int8 arg_num = 1); diff --git a/source/WorldServer/Spawn.cpp b/source/WorldServer/Spawn.cpp index e62f77b..67551b6 100644 --- a/source/WorldServer/Spawn.cpp +++ b/source/WorldServer/Spawn.cpp @@ -4082,15 +4082,16 @@ void Spawn::SetSpawnGroupList(vector* list, Mutex* mutex){ MSpawnGroup = mutex; } -void Spawn::RemoveSpawnFromGroup(bool erase_all){ - SetSpawnGroupID(0); +void Spawn::RemoveSpawnFromGroup(bool erase_all, bool ignore_death){ + if(!ignore_death) + SetSpawnGroupID(0); bool del = false; if(MSpawnGroup){ MSpawnGroup->writelock(__FUNCTION__, __LINE__); if(spawn_group_list){ vector::iterator itr; Spawn* spawn = 0; - if(spawn_group_list->size() == 1) + if(spawn_group_list->size() == 1 && !ignore_death) erase_all = true; for(itr = spawn_group_list->begin(); itr != spawn_group_list->end(); itr++){ spawn = *itr; diff --git a/source/WorldServer/Spawn.h b/source/WorldServer/Spawn.h index c09fb92..73b6ef5 100644 --- a/source/WorldServer/Spawn.h +++ b/source/WorldServer/Spawn.h @@ -1099,7 +1099,7 @@ public: int32 GetSpawnGroupID(); void AddSpawnToGroup(Spawn* spawn); void SetSpawnGroupList(vector* list, Mutex* mutex); - void RemoveSpawnFromGroup(bool erase_all = false); + void RemoveSpawnFromGroup(bool erase_all = false, bool ignore_death = false); void SetRunningTo(Spawn* spawn){ running_to = spawn->GetID(); } Spawn* GetRunningTo(); diff --git a/source/WorldServer/SpellProcess.cpp b/source/WorldServer/SpellProcess.cpp index 3da35ba..3e02ddd 100644 --- a/source/WorldServer/SpellProcess.cpp +++ b/source/WorldServer/SpellProcess.cpp @@ -1704,6 +1704,11 @@ void SpellProcess::ProcessEntityCommand(ZoneServer* zone, EntityCommand* entity_ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_heroic_opp){ if(!spell || !spell->caster || !spell->spell || spell->interrupted) return false; + + if(spell->spell->GetSpellData()->duration1 > 0){ + AddActiveSpell(spell); + } + Client* client = 0; if(spell->caster && spell->caster->IsPlayer()) client = ((Player*)spell->caster)->GetClient(); @@ -1716,6 +1721,7 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her SendSpellBookUpdate(client); } spell->caster->GetZone()->SendSpellFailedPacket(client, SPELL_ERROR_NO_TARGETS_IN_RANGE); + DeleteActiveSpell(spell, true); return false; } } @@ -1733,17 +1739,23 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her zone->RemoveTargetFromSpell(conflictSpell, tmpTarget); } } - - MutexList::iterator itr = active_spells.begin(); + bool processedSpell = false; bool allTargets = (spell->spell->GetSpellData()->spell_type == SPELL_TYPE_ALLGROUPTARGETS); + if (!processedSpell) processedSpell = ProcessSpell(spell, true, 0, 0, allTargets); + if(spell->resisted && spell->spell->GetSpellData()->duration1) { + DeleteActiveSpell(spell, true); + } // Quick hack to prevent a crash on spells that zones the caster (Gate) - if (!spell->caster) + if (!spell->caster) { + if(spell->spell->GetSpellData()->duration1) + DeleteActiveSpell(spell, true); return true; + } Skill* skill = spell->caster->GetSkillByID(spell->spell->GetSpellData()->mastery_skill, false); // trigger potential skill increase if we succeed in casting a mastery skill and it still has room to grow (against this spell) @@ -1805,6 +1817,7 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her else{ if (!passive) SendFinishedCast(spell, client); + DeleteActiveSpell(spell, true); 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)) { @@ -1839,8 +1852,6 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her } } - active_spells.Add(spell); - if (spell->num_triggers > 0) ClientPacketFunctions::SendMaintainedExamineUpdate(client, spell->slot_pos, spell->num_triggers, 0); if (spell->damage_remaining > 0) @@ -1855,9 +1866,7 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her spell->timer.SetTimer(spell->spell->GetSpellData()->call_frequency*100); else spell->timer.SetTimer(spell->spell->GetSpellData()->duration1*100); - if (active_spells.count(spell) < 1) { - active_spells.Add(spell); - } + AddActiveSpell(spell); } // if the caster is a player and the spell is a tradeskill spell check for a tradeskill event @@ -2824,7 +2833,8 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete remove_spawn = spell->caster->GetZone()->GetSpawnByID((*remove_target_itr)); if (remove_spawn) { - if(remove_spawn && remove_spawn->IsPlayer()) + bool found_target = false; + if(remove_spawn->IsPlayer()) { multimap::iterator entries; while((entries = spell->char_id_targets.find(((Player*)remove_spawn)->GetCharacterID())) != spell->char_id_targets.end()) @@ -2834,6 +2844,7 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete } for (target_itr = targets->begin(); target_itr != targets->end(); target_itr++) { if (remove_spawn->GetID() == (*target_itr)) { + 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()); @@ -2845,9 +2856,18 @@ void SpellProcess::CheckRemoveTargetFromSpell(LuaSpell* spell, bool allow_delete } if (targets->size() == 0 && spell->char_id_targets.size() == 0 && allow_delete) { spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__); + if(found_target) + lua_interface->RemoveSpell(spell, true, false, !remove_spawn->Alive() ? "target_dead" : "target_removed", false, true, remove_spawn); should_delete = true; break; } + else { + spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__); + // call remove function "on death" + if(found_target) + lua_interface->RemoveSpell(spell, true, false, !remove_spawn->Alive() ? "target_dead" : "target_removed", false, true, remove_spawn); + spell->MSpellTargets.writelock(__FUNCTION__, __LINE__); + } } } spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__); diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index 2599ad6..c76b274 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -4331,7 +4331,7 @@ Spawn* ZoneServer::GetSpawnGroup(int32 id){ for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) { spawn = itr->second; if(spawn){ - if(spawn->GetSpawnGroupID() == id){ + if(spawn->Alive() && spawn->GetSpawnGroupID() == id){ ret = spawn; quick_group_id_lookup.Put(id, spawn->GetID()); break; @@ -6798,7 +6798,7 @@ void ZoneServer::RemoveSpawnSupportFunctions(Spawn* spawn, bool lock_spell_proce if (spawn->GetSpawnGroupID() > 0) { int32 group_id = spawn->GetSpawnGroupID(); - spawn->RemoveSpawnFromGroup(); + spawn->RemoveSpawnFromGroup(false, (spawn->IsEntity() && !spawn->Alive()) ? true : false); if (spawn_group_map.count(group_id) > 0) spawn_group_map.Get(group_id).Remove(spawn->GetID()); }