Ver código fonte

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 ano atrás
pai
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);