1
0

Lua Functions DeleteQuest, DeleteAllQuests added (Fix #29). Ward crash issues (Fix #30). Item Scripts now auto bug report to bugs table (Fix #31).

Fix #29 - DeleteQuest(Player, QuestID, ForceDelete) and DeleteAllQuests(Player, ForceDelete) added.
Fix #30 - Ward crash protection
Fix #31 - track item scripts missing on food/drink auto bug report
This commit is contained in:
Emagi 2025-06-13 19:52:37 -04:00
parent 1176a16d43
commit 4c60615c39
8 changed files with 135 additions and 1 deletions

View File

@ -2272,6 +2272,30 @@ void Entity::RemoveWard(int32 spellID) {
}
}
void Entity::RemoveWard(LuaSpell* spell) {
std::unique_lock lock(MWardList);
map<int32, WardInfo*>::iterator itr;
for (itr = m_wardList.begin(); itr != m_wardList.end(); itr++) {
if(itr->second->DeleteWard)
continue;
if(itr->second->Spell == spell) {
itr->second->DeleteWard = true;
}
}
for (itr = m_wardList.begin(); itr != m_wardList.end();) {
if(itr->second->DeleteWard) {
WardInfo* info = itr->second;
itr = m_wardList.erase(itr);
safe_delete(info);
}
else {
itr++;
}
}
}
int32 Entity::CheckWards(Entity* attacker, int32 damage, int8 damage_type) {
std::unique_lock lock(MWardList);
map<int32, WardInfo*>::iterator itr;

View File

@ -1850,6 +1850,7 @@ public:
/// <summary>Removes the ward with the given spell id</summary>
/// <param name='spellID'>The spell id of the ward to remove</param>
void RemoveWard(int32 spellID);
void RemoveWard(LuaSpell* spell);
/// <summary>Subtracts the given damage from the wards</summary>
/// <param name='damage'>The damage to subtract from the wards</param>

View File

@ -3931,6 +3931,53 @@ int EQ2Emu_lua_OfferQuest(lua_State* state) {
return 0;
}
int EQ2Emu_lua_DeleteQuest(lua_State* state) {
if (!lua_interface)
return 0;
Spawn* player = lua_interface->GetSpawn(state);
int32 quest_id = lua_interface->GetInt32Value(state, 2);
bool override_deny_delete = lua_interface->GetBooleanValue(state, 3);
lua_interface->ResetFunctionStack(state);
/* NPC is allowed to be null */
if (player && player->IsPlayer() && quest_id > 0) {
Client* client = ((Player*)player)->GetClient();
if (!client) {
lua_interface->LogError("%s: LUA DeleteQuest command error: client is not set", lua_interface->GetScriptName(state));
}
else {
client->DeleteQuest(quest_id, override_deny_delete);
}
}
else {
lua_interface->LogError("%s: LUA DeleteQuest command error: player is not set or bad quest id %d", lua_interface->GetScriptName(state), quest_id);
}
return 0;
}
int EQ2Emu_lua_DeleteAllQuests(lua_State* state) {
if (!lua_interface)
return 0;
Spawn* player = lua_interface->GetSpawn(state);
bool override_deny_delete = lua_interface->GetBooleanValue(state, 2);
lua_interface->ResetFunctionStack(state);
/* NPC is allowed to be null */
if (player && player->IsPlayer()) {
Client* client = ((Player*)player)->GetClient();
if (!client) {
lua_interface->LogError("%s: LUA DeleteAllQuests command error: client is not set", lua_interface->GetScriptName(state));
}
else {
client->DeleteAllQuests(override_deny_delete);
}
}
else {
lua_interface->LogError("%s: LUA DeleteAllQuests command error: player is not set", lua_interface->GetScriptName(state));
}
return 0;
}
int EQ2Emu_lua_AddQuestPrereqClass(lua_State* state) {
if (!lua_interface)
return 0;

View File

@ -260,6 +260,8 @@ int EQ2Emu_lua_QuestStepIsComplete(lua_State* state);
int EQ2Emu_lua_GetQuestStep(lua_State* state);
int EQ2Emu_lua_RegisterQuest(lua_State* state);
int EQ2Emu_lua_OfferQuest(lua_State* state);
int EQ2Emu_lua_DeleteQuest(lua_State* state);
int EQ2Emu_lua_DeleteAllQuests(lua_State* state);
int EQ2Emu_lua_SetQuestPrereqLevel(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqQuest(lua_State* state);
int EQ2Emu_lua_AddQuestPrereqItem(lua_State* state);

View File

@ -1312,6 +1312,8 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
lua_register(state, "UpdateQuestZone", EQ2Emu_lua_UpdateQuestZone);
lua_register(state, "SetCompletedDescription", EQ2Emu_lua_SetCompletedDescription);
lua_register(state, "OfferQuest", EQ2Emu_lua_OfferQuest);
lua_register(state, "DeleteQuest", EQ2Emu_lua_DeleteQuest);
lua_register(state, "DeleteAllQuests", EQ2Emu_lua_DeleteAllQuests);
lua_register(state, "ProvidesQuest", EQ2Emu_lua_ProvidesQuest);
lua_register(state, "HasQuest", EQ2Emu_lua_HasQuest);
lua_register(state, "HasPendingQuest", EQ2Emu_lua_HasPendingQuest);
@ -1742,10 +1744,14 @@ void LuaInterface::DeletePendingSpells(bool all) {
Spawn* target = spell->zone->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity())
continue;
if(target->IsEntity()) {
((Entity*)target)->RemoveWard(spell);
}
if(!spellDeleted && spell->zone && spell->zone->GetSpellProcess())
spell->zone->GetSpellProcess()->DeleteActiveSpell(spell, true);
spellDeleted = true;
}
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);

View File

@ -3005,6 +3005,19 @@ void SpellProcess::DeleteSpell(LuaSpell* spell)
lua_interface->RemoveCustomSpell(spell->spell->GetSpellID());
safe_delete(spell->spell);
}
if(spell->targets.size() > 0) {
spell->MSpellTargets.readlock(__FUNCTION__, __LINE__);
for (int8 i = 0; i < spell->targets.size(); i++) {
Spawn* target = spell->zone->GetSpawnByID(spell->targets.at(i));
if (!target || !target->IsEntity())
continue;
if(target->IsEntity()) {
((Entity*)target)->RemoveWard(spell);
}
}
spell->MSpellTargets.releasereadlock(__FUNCTION__, __LINE__);
}
lua_interface->SetLuaUserDataStale(spell);

View File

@ -4098,6 +4098,8 @@ void ClientList::Process() {
struct in_addr in;
in.s_addr = client->GetIP();
LogWrite(WORLD__INFO, 0, "World", "Removing client from ip: %s port: %i", inet_ntoa(in), client->GetPort());
if(client->GetPlayer()->GetClient() == client)
client->GetPlayer()->SetClient(nullptr);
safe_delete(client);
}
}
@ -7124,6 +7126,38 @@ void Client::RemovePendingQuest(int32 quest_id) {
}
}
void Client::DeleteQuest(int32 quest_id, bool override_deny_delete) {
if(quest_id > 0) {
GetPlayer()->MPlayerQuests.readlock(__FUNCTION__, __LINE__);
if(lua_interface && GetPlayer()->player_quests.count(quest_id) > 0) {
Quest* quest = GetPlayer()->player_quests[quest_id];
GetPlayer()->MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
if (quest && (override_deny_delete || quest->CanDeleteQuest())) {
lua_interface->CallQuestFunction(quest, "Deleted", GetPlayer());
RemovePlayerQuest(quest_id);
GetCurrentZone()->SendQuestUpdates(this);
}
}
else {
GetPlayer()->MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
}
}
}
void Client::DeleteAllQuests(bool override_deny_delete) {
std::vector<int32> quest_ids;
map<int32, Quest*>::iterator itr;
GetPlayer()->MPlayerQuests.readlock(__FUNCTION__, __LINE__);
for (std::map<int32, Quest*>::iterator itr = player->player_quests.begin(); itr != player->player_quests.end(); ++itr) {
quest_ids.push_back(itr->first);
}
GetPlayer()->MPlayerQuests.releasereadlock(__FUNCTION__, __LINE__);
for (int32 id : quest_ids) {
DeleteQuest(id, override_deny_delete);
}
}
void Client::SetPlayerQuest(Quest* quest, map<int32, int32>* progress) {
if (!quest || !progress) {
return;
@ -12783,6 +12817,11 @@ void Client::ConsumeFoodDrink(Item* item, int32 slot)
}
}
else {
char msg[512];
snprintf(msg, 512, "ConsumeFoodDrink missing proper item script set %s ID %i", item->name.c_str(), item->details.item_id);
if (!world.CheckTempBugCRC(msg))
commands.Command_ReportBug(this, new Seperator(msg));
Message(CHANNEL_NARRATIVE, "SERVER BUG! Item Script not assigned for consuming '%s'.", item->name.c_str());
return;
}

View File

@ -377,6 +377,8 @@ public:
void AcceptQuest(int32 quest_id);
bool HasPendingQuest(int32 quest_id);
void RemovePendingQuest(int32 quest_id);
void DeleteQuest(int32 quest_id, bool override_deny_delete = false);
void DeleteAllQuests(bool override_deny_delete = false);
void SetPlayerQuest(Quest* quest, map<int32, int32>* progress);
void AddPlayerQuest(Quest* quest, bool call_accepted = true, bool send_packets = true);
void RemovePlayerQuest(int32 id, bool send_update = true, bool delete_quest = true);