[Bug Fix] Fix NPC Reference in EVENT_SPAWN (#2712)

* [Bug Fix] Fix NPC Reference in EVENT_SPAWN

# Notes
- Event parsing was too early and memory wasn't fully allocated, meaning that sometimes you could use the NPC reference and other times you couldn't.
- Most people worked around this by setting timers in `EVENT_SPAWN` then using `EVENT_TIMER` to handle the stuff they wanted to do on spawn.

# Example Code in Perl
```pl
sub EVENT_SPAWN {
	quest::shout($npc->GetCleanName() . " just spawned with an ID of " . $npc->GetID() . " and an NPC Type ID of " . $npc->GetNPCTypeID() . ".");
}```

* Update bot.cpp
This commit is contained in:
Alex King 2023-01-08 11:27:17 -05:00 committed by GitHub
parent 2253e43d2c
commit 0c105a2b91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 26 additions and 21 deletions

View File

@ -8784,14 +8784,14 @@ void EntityList::AddBot(Bot *new_bot, bool send_spawn_packet, bool dont_queue) {
AddToSpawnQueue(new_bot->GetID(), &ns);
safe_delete(ns);
}
parse->EventBot(EVENT_SPAWN, new_bot, nullptr, "", 0);
new_bot->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, new_bot, "", 0, nullptr);
}
bot_list.push_back(new_bot);
mob_list.insert(std::pair<uint16, Mob*>(new_bot->GetID(), new_bot));
parse->EventBot(EVENT_SPAWN, new_bot, nullptr, "", 0);
new_bot->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, new_bot, "", 0, nullptr);
}
}

View File

@ -685,56 +685,61 @@ void EntityList::AddCorpse(Corpse *corpse, uint32 in_id)
corpse_timer.Start();
}
void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue)
void EntityList::AddNPC(NPC *npc, bool send_spawn_packet, bool dont_queue)
{
npc->SetID(GetFreeID());
//If this is not set here we will despawn pets from new AC changes
auto owner_id = npc->GetOwnerID();
if(owner_id) {
if (owner_id) {
auto owner = entity_list.GetMob(owner_id);
if (owner) {
owner->SetPetID(npc->GetID());
}
}
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
uint32 emoteid = npc->GetEmoteID();
if (emoteid != 0)
npc->DoNPCEmote(EQ::constants::EmoteEventTypes::OnSpawn, emoteid);
const auto emote_id = npc->GetEmoteID();
if (emote_id != 0) {
npc->DoNPCEmote(EQ::constants::EmoteEventTypes::OnSpawn, emote_id);
}
npc->SetSpawned();
if (SendSpawnPacket) {
if (dontqueue) { // aka, SEND IT NOW BITCH!
if (send_spawn_packet) {
if (dont_queue) {
auto app = new EQApplicationPacket;
npc->CreateSpawnPacket(app, npc);
QueueClients(npc, app);
npc->SendArmorAppearance();
npc->SetAppearance(npc->GetGuardPointAnim(),false);
if (!npc->IsTargetable())
npc->SetAppearance(npc->GetGuardPointAnim(), false);
if (!npc->IsTargetable()) {
npc->SendTargetable(false);
}
safe_delete(app);
} else {
auto ns = new NewSpawn_Struct;
memset(ns, 0, sizeof(NewSpawn_Struct));
npc->FillSpawnStruct(ns, nullptr); // Not working on player newspawns, so it's safe to use a ForWho of 0
npc->FillSpawnStruct(ns, nullptr);
AddToSpawnQueue(npc->GetID(), &ns);
safe_delete(ns);
}
if (npc->IsFindable())
if (npc->IsFindable()) {
UpdateFindableNPCState(npc, false);
}
}
npc_list.insert(std::pair<uint16, NPC *>(npc->GetID(), npc));
mob_list.insert(std::pair<uint16, Mob *>(npc->GetID(), npc));
parse->EventNPC(EVENT_SPAWN, npc, nullptr, "", 0);
entity_list.ScanCloseMobs(npc->close_mobs, npc, true);
/* Zone controller process EVENT_SPAWN_ZONE */
npc->DispatchZoneControllerEvent(EVENT_SPAWN_ZONE, npc, "", 0, nullptr);
/**
* Set whether NPC was spawned in or out of water
*/
if (zone->HasMap() && zone->HasWaterMap()) {
npc->SetSpawnedInWater(false);
if (zone->watermap->InLiquid(npc->GetPosition())) {

View File

@ -278,7 +278,7 @@ public:
bool MakeTrackPacket(Client* client);
void SendTraders(Client* client);
void AddClient(Client*);
void AddNPC(NPC*, bool SendSpawnPacket = true, bool dontqueue = false);
void AddNPC(NPC*, bool send_spawn_packet = true, bool dont_queue = false);
void AddMerc(Merc*, bool SendSpawnPacket = true, bool dontqueue = false);
void AddCorpse(Corpse* pc, uint32 in_id = 0xFFFFFFFF);
void AddObject(Object*, bool SendSpawnPacket = true);