1
0

call spell remove function for reason "target_dead" and "target_removed" also address the long delay between calling the remove function and the death of a spawn. Lastly made it so we can reference the spawn group id after death for a spawn since we remove it from a spawn group.

This commit is contained in:
Emagi 2025-01-16 12:29:24 -05:00
parent e20b45eedd
commit 3efce0abd6
6 changed files with 44 additions and 18 deletions

View File

@ -822,7 +822,7 @@ lua_State* LuaInterface::LoadLuaFile(const char* name) {
return 0; 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){ if(call_remove_function){
lua_getglobal(spell->state, "remove"); lua_getglobal(spell->state, "remove");
if (!lua_isfunction(spell->state, lua_gettop(spell->state))){ 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); lua_pushlightuserdata(spell->state, spawn_wrapper);
if(spell->caster && (spell->initial_target || spell->caster->GetTarget())){ if(spell->caster && (spell->initial_target || spell->caster->GetTarget())){
spawn_wrapper = new LUASpawnWrapper(); 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(); spawn_wrapper->spawn = spell->caster->GetTarget();
else if(spell->caster->GetZone()) { else if(spell->caster->GetZone()) {
spawn_wrapper->spawn = spell->caster->GetZone()->GetSpawnByID(spell->initial_target); 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); ResetFunctionStack(spell->state);
} }
if(return_after_call_remove)
return;
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__); spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
if(spell->caster) { if(spell->caster) {
for (int8 i = 0; i < spell->targets.size(); i++) { for (int8 i = 0; i < spell->targets.size(); i++) {

View File

@ -194,7 +194,7 @@ public:
bool LoadRegionScript(const char* name); bool LoadRegionScript(const char* name);
LuaSpell* LoadSpellScript(string name); LuaSpell* LoadSpellScript(string name);
LuaSpell* LoadSpellScript(const char* 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); Spawn* GetSpawn(lua_State* state, int8 arg_num = 1);
Item* GetItem(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); Quest* GetQuest(lua_State* state, int8 arg_num = 1);

View File

@ -4082,15 +4082,16 @@ void Spawn::SetSpawnGroupList(vector<Spawn*>* list, Mutex* mutex){
MSpawnGroup = mutex; MSpawnGroup = mutex;
} }
void Spawn::RemoveSpawnFromGroup(bool erase_all){ void Spawn::RemoveSpawnFromGroup(bool erase_all, bool ignore_death){
SetSpawnGroupID(0); if(!ignore_death)
SetSpawnGroupID(0);
bool del = false; bool del = false;
if(MSpawnGroup){ if(MSpawnGroup){
MSpawnGroup->writelock(__FUNCTION__, __LINE__); MSpawnGroup->writelock(__FUNCTION__, __LINE__);
if(spawn_group_list){ if(spawn_group_list){
vector<Spawn*>::iterator itr; vector<Spawn*>::iterator itr;
Spawn* spawn = 0; Spawn* spawn = 0;
if(spawn_group_list->size() == 1) if(spawn_group_list->size() == 1 && !ignore_death)
erase_all = true; erase_all = true;
for(itr = spawn_group_list->begin(); itr != spawn_group_list->end(); itr++){ for(itr = spawn_group_list->begin(); itr != spawn_group_list->end(); itr++){
spawn = *itr; spawn = *itr;

View File

@ -1099,7 +1099,7 @@ public:
int32 GetSpawnGroupID(); int32 GetSpawnGroupID();
void AddSpawnToGroup(Spawn* spawn); void AddSpawnToGroup(Spawn* spawn);
void SetSpawnGroupList(vector<Spawn*>* list, Mutex* mutex); void SetSpawnGroupList(vector<Spawn*>* 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(); } void SetRunningTo(Spawn* spawn){ running_to = spawn->GetID(); }
Spawn* GetRunningTo(); Spawn* GetRunningTo();

View File

@ -1704,6 +1704,11 @@ void SpellProcess::ProcessEntityCommand(ZoneServer* zone, EntityCommand* entity_
bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_heroic_opp){ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_heroic_opp){
if(!spell || !spell->caster || !spell->spell || spell->interrupted) if(!spell || !spell->caster || !spell->spell || spell->interrupted)
return false; return false;
if(spell->spell->GetSpellData()->duration1 > 0){
AddActiveSpell(spell);
}
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();
@ -1716,6 +1721,7 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
SendSpellBookUpdate(client); SendSpellBookUpdate(client);
} }
spell->caster->GetZone()->SendSpellFailedPacket(client, SPELL_ERROR_NO_TARGETS_IN_RANGE); spell->caster->GetZone()->SendSpellFailedPacket(client, SPELL_ERROR_NO_TARGETS_IN_RANGE);
DeleteActiveSpell(spell, true);
return false; return false;
} }
} }
@ -1734,16 +1740,22 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
} }
} }
MutexList<LuaSpell*>::iterator itr = active_spells.begin();
bool processedSpell = false; bool processedSpell = false;
bool allTargets = (spell->spell->GetSpellData()->spell_type == SPELL_TYPE_ALLGROUPTARGETS); bool allTargets = (spell->spell->GetSpellData()->spell_type == SPELL_TYPE_ALLGROUPTARGETS);
if (!processedSpell) if (!processedSpell)
processedSpell = ProcessSpell(spell, true, 0, 0, allTargets); 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) // 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; return true;
}
Skill* skill = spell->caster->GetSkillByID(spell->spell->GetSpellData()->mastery_skill, false); 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) // 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{ else{
if (!passive) if (!passive)
SendFinishedCast(spell, client); SendFinishedCast(spell, client);
DeleteActiveSpell(spell, true);
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)) {
@ -1839,8 +1852,6 @@ bool SpellProcess::CastProcessedSpell(LuaSpell* spell, bool passive, bool in_her
} }
} }
active_spells.Add(spell);
if (spell->num_triggers > 0) if (spell->num_triggers > 0)
ClientPacketFunctions::SendMaintainedExamineUpdate(client, spell->slot_pos, spell->num_triggers, 0); ClientPacketFunctions::SendMaintainedExamineUpdate(client, spell->slot_pos, spell->num_triggers, 0);
if (spell->damage_remaining > 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); spell->timer.SetTimer(spell->spell->GetSpellData()->call_frequency*100);
else else
spell->timer.SetTimer(spell->spell->GetSpellData()->duration1*100); spell->timer.SetTimer(spell->spell->GetSpellData()->duration1*100);
if (active_spells.count(spell) < 1) { AddActiveSpell(spell);
active_spells.Add(spell);
}
} }
// if the caster is a player and the spell is a tradeskill spell check for a tradeskill event // 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)); remove_spawn = spell->caster->GetZone()->GetSpawnByID((*remove_target_itr));
if (remove_spawn) { if (remove_spawn) {
if(remove_spawn && remove_spawn->IsPlayer()) bool found_target = false;
if(remove_spawn->IsPlayer())
{ {
multimap<int32,int8>::iterator entries; multimap<int32,int8>::iterator entries;
while((entries = spell->char_id_targets.find(((Player*)remove_spawn)->GetCharacterID())) != spell->char_id_targets.end()) 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++) { for (target_itr = targets->begin(); target_itr != targets->end(); target_itr++) {
if (remove_spawn->GetID() == (*target_itr)) { if (remove_spawn->GetID() == (*target_itr)) {
found_target = true;
((Entity*)remove_spawn)->RemoveProc(0, spell); ((Entity*)remove_spawn)->RemoveProc(0, spell);
((Entity*)remove_spawn)->RemoveMaintainedSpell(spell); ((Entity*)remove_spawn)->RemoveMaintainedSpell(spell);
LogWrite(SPELL__DEBUG, 0, "Spell", "%s CheckRemoveTargetFromSpell %s (%u).", spell->spell->GetName(), remove_spawn->GetName(), remove_spawn->GetID()); 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) { if (targets->size() == 0 && spell->char_id_targets.size() == 0 && allow_delete) {
spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__); 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; should_delete = true;
break; 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__); spell->MSpellTargets.releasewritelock(__FUNCTION__, __LINE__);

View File

@ -4331,7 +4331,7 @@ Spawn* ZoneServer::GetSpawnGroup(int32 id){
for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) { for (itr = spawn_list.begin(); itr != spawn_list.end(); itr++) {
spawn = itr->second; spawn = itr->second;
if(spawn){ if(spawn){
if(spawn->GetSpawnGroupID() == id){ if(spawn->Alive() && spawn->GetSpawnGroupID() == id){
ret = spawn; ret = spawn;
quick_group_id_lookup.Put(id, spawn->GetID()); quick_group_id_lookup.Put(id, spawn->GetID());
break; break;
@ -6798,7 +6798,7 @@ void ZoneServer::RemoveSpawnSupportFunctions(Spawn* spawn, bool lock_spell_proce
if (spawn->GetSpawnGroupID() > 0) { if (spawn->GetSpawnGroupID() > 0) {
int32 group_id = spawn->GetSpawnGroupID(); int32 group_id = spawn->GetSpawnGroupID();
spawn->RemoveSpawnFromGroup(); spawn->RemoveSpawnFromGroup(false, (spawn->IsEntity() && !spawn->Alive()) ? true : false);
if (spawn_group_map.count(group_id) > 0) if (spawn_group_map.count(group_id) > 0)
spawn_group_map.Get(group_id).Remove(spawn->GetID()); spawn_group_map.Get(group_id).Remove(spawn->GetID());
} }