Browse Source

Fix crash on setting pet stats after summon, owner was not set, fixed pets not surviving camp and popping back into game, added prespawn script to SummonPet

Emagi 1 year ago
parent
commit
7a2d357e16

+ 3 - 0
EQ2/source/WorldServer/Entity.cpp

@@ -3652,6 +3652,9 @@ bool Entity::SetInfoStructFloat(std::string field, float value)
 Entity*	Entity::GetOwner() {
 	Entity* ent = nullptr;
 
+	if(!GetZone()) {
+		return ent;
+	}
 	Spawn* spawn = GetZone()->GetSpawnByID(owner);
 	if ( spawn && spawn->IsEntity() )
 		ent = (Entity*)spawn;

+ 15 - 9
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -5329,15 +5329,6 @@ int EQ2Emu_lua_SummonPet(lua_State* state) {
 	pet->SetZ(spawn->GetZ());
 	pet->SetLocation(spawn->GetLocation());
 	pet->SetHeading(spawn->GetHeading());
-	spawn->GetZone()->AddSpawn(pet);
-
-	
-	const char* spawn_script = world.GetSpawnScript(pet_id);
-	if(spawn_script && lua_interface->GetSpawnScript(spawn_script) != 0){
-		spawn->SetSpawnScript(string(spawn_script));
-		spawn->GetZone()->CallSpawnScript(spawn, SPAWN_SCRIPT_SPAWN);
-	}
-
 
 	std::string petName = std::string("");
 	if(spawn->IsEntity()) {
@@ -5402,6 +5393,21 @@ int EQ2Emu_lua_SummonPet(lua_State* state) {
 	}
 	// Add the "Pet Options" entity command to the pet
 	pet->AddSecondaryEntityCommand("Pet Options", 10.0f, "petoptions", "", 0, 0);
+	
+	const char* spawn_script = world.GetSpawnScript(pet_id);
+	bool runScript = false;
+	if(spawn_script && lua_interface->GetSpawnScript(spawn_script) != 0){
+		runScript = true;
+		pet->SetSpawnScript(string(spawn_script));
+		spawn->GetZone()->CallSpawnScript(pet, SPAWN_SCRIPT_PRESPAWN);
+	}
+	
+	spawn->GetZone()->AddSpawn(pet);
+	
+	if(runScript){
+		spawn->GetZone()->CallSpawnScript(pet, SPAWN_SCRIPT_SPAWN);
+	}
+	
 	// Set the pet as the return value for this function
 	lua_interface->SetSpawnValue(state, pet);
 	return 1;

+ 1 - 1
EQ2/source/WorldServer/LuaInterface.cpp

@@ -598,7 +598,7 @@ std::string LuaInterface::AddSpawnPointers(LuaSpell* spell, bool first_cast, boo
 			Spawn* new_target = spell->caster->GetZone()->GetSpawnByID(spell->initial_target);
 			SetSpawnValue(spell->state, new_target);
 		}
-				else if(spell->caster && spell->caster->GetTarget())
+		else if(spell->caster && spell->caster->GetTarget())
 			SetSpawnValue(spell->state, spell->caster->GetTarget());
 		else
 			SetSpawnValue(spell->state, 0);

+ 7 - 1
EQ2/source/WorldServer/NPC_AI.cpp

@@ -53,7 +53,13 @@ Brain::~Brain() {
 }
 
 void Brain::Think() {
-
+	if (m_body->IsPet() && m_body->GetOwner() && m_body->GetOwner()->IsPlayer()) {
+		Player* player = (Player*)m_body->GetOwner();
+		if(player->GetInfoStruct()->get_pet_id() == 0) {
+			player->GetInfoStruct()->set_pet_id(player->GetIDWithPlayerSpawn(m_body));
+			player->SetCharSheetChanged(true);
+		}
+	}
 	// Get the entity this NPC hates the most,
 	// GetMostHated() will handle dead spawns so no need to check the health in this function
 	Entity* target = GetMostHated();

+ 4 - 8
EQ2/source/WorldServer/Spawn.cpp

@@ -457,10 +457,6 @@ void Spawn::InitializeFooterPacketData(Player* player, PacketStruct* footer) {
 
 EQ2Packet* Spawn::spawn_serialize(Player* player, int16 version, int16 offset, int32 value, int16 offset2, int16 offset3, int16 offset4, int32 value2) {
 	// If spawn is NPC AND is pet && owner is a player && owner is the player passed to this function && player's char sheet pet id is 0
-	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner()->IsPlayer() && player == ((NPC*)this)->GetOwner() && player->GetInfoStruct()->get_pet_id() == 0) {
-		((Player*)((NPC*)this)->GetOwner())->GetInfoStruct()->set_pet_id(player->spawn_id);
-		player->SetCharSheetChanged(true);
-	}
 	m_Update.writelock(__FUNCTION__, __LINE__);
 
 	int16 index = 0;
@@ -1416,7 +1412,7 @@ void Spawn::SetHP(sint32 new_val, bool setUpdateFlags){
 	if ( IsPlayer() && new_val == 0 ) // fixes on death not showing hp update for players
 		((Player*)this)->SetCharSheetChanged(true);
 
-	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner()->IsPlayer()) {
+	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner() && ((NPC*)this)->GetOwner()->IsPlayer()) {
 		Player* player = (Player*)((NPC*)this)->GetOwner();
 		if (player->GetPet() && player->GetCharmedPet()) {
 			if (this == player->GetPet()) {
@@ -1446,7 +1442,7 @@ void Spawn::SetTotalHP(sint32 new_val){
 			world.GetGroupManager()->SendGroupUpdate(((Entity*)this)->GetGroupMemberInfo()->group_id);
 	}
 
-	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner()->IsPlayer()) {
+	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner() != nullptr && ((NPC*)this)->GetOwner()->IsPlayer()) {
 		Player* player = (Player*)((NPC*)this)->GetOwner();
 		if (basic_info.max_hp && player->GetPet() && player->GetCharmedPet()) {
 			if (this == player->GetPet()) {
@@ -1505,7 +1501,7 @@ void Spawn::SetPower(sint32 power, bool setUpdateFlags){
 			world.GetGroupManager()->SendGroupUpdate(((Entity*)this)->GetGroupMemberInfo()->group_id);
 	}
 
-	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner()->IsPlayer()) {
+	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner() != nullptr && ((NPC*)this)->GetOwner()->IsPlayer()) {
 		Player* player = (Player*)((NPC*)this)->GetOwner();
 		if (player->GetPet() && player->GetCharmedPet()) {
 			if (this == player->GetPet()) {
@@ -1536,7 +1532,7 @@ void Spawn::SetTotalPower(sint32 new_val)
 			world.GetGroupManager()->SendGroupUpdate(((Entity*)this)->GetGroupMemberInfo()->group_id);
 	}
 
-	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner()->IsPlayer()) {
+	if (IsNPC() && ((NPC*)this)->IsPet() && ((NPC*)this)->GetOwner() != nullptr && ((NPC*)this)->GetOwner()->IsPlayer()) {
 		Player* player = (Player*)((NPC*)this)->GetOwner();
 		if (player->GetPet() && player->GetCharmedPet()) {
 			if (this == player->GetPet()) {

+ 8 - 3
EQ2/source/WorldServer/zoneserver.cpp

@@ -3256,6 +3256,7 @@ void ZoneServer::RemoveClient(Client* client)
 {
 	Guild *guild;
 
+	bool dismissPets = false;
 	if(client)
 	{			
 		if (client->GetPlayer()) 
@@ -3304,7 +3305,7 @@ void ZoneServer::RemoveClient(Client* client)
 				LogWrite(ZONE__DEBUG, 0, "Zone", "Removing client '%s' (%u) due to Camp/Quit...", client->GetPlayer()->GetName(), client->GetPlayer()->GetCharacterID());
 			}
 				
-				((Entity*)client->GetPlayer())->DismissAllPets();
+				dismissPets = true;
 			//}
 		}
 		else
@@ -3319,6 +3320,12 @@ void ZoneServer::RemoveClient(Client* client)
 				((Bot*)spawn)->Camp();
 		}
 
+		client->SaveSpells();
+		
+		if(dismissPets) {
+				((Entity*)client->GetPlayer())->DismissAllPets();
+		}
+		
 		MClientList.writelock(__FUNCTION__, __LINE__);
 		LogWrite(ZONE__DEBUG, 0, "Zone", "Calling clients.Remove(client)...");
 		UpdateClientSpawnMap(client->GetPlayer(), 0); // address spawn map being prematurely cleared when client list is active
@@ -3331,8 +3338,6 @@ void ZoneServer::RemoveClient(Client* client)
 		LogWrite(ZONE__INFO, 0, "Zone", "Scheduling client '%s' for removal.", client->GetPlayer()->GetName());
 		database.ToggleCharacterOnline(client, 0);
 		
-		client->SaveSpells();
-		
 		client->GetPlayer()->DeleteSpellEffects(true);
 		
 		RemoveSpawn(client->GetPlayer(), false, true, true, true, true);