Core/Pets: Updated pet summoning for latest client version (5 Call Pet spells and stable size 200)
Port From (https://github.com/TrinityCore/TrinityCore/commit/950db60435e7e513633ff5b22ad7f0ed8b1147e4)
This commit is contained in:
@@ -34,11 +34,13 @@ namespace Framework.Constants
|
||||
|
||||
public enum PetSaveMode
|
||||
{
|
||||
NotInSlot = -1, // for avoid conflict with stable size grow will use negative value
|
||||
AsDeleted = -2, // not saved in fact
|
||||
AsCurrent = 0, // in current slot (with player)
|
||||
FirstStableSlot = 1,
|
||||
LastStableSlot = SharedConst.MaxPetStables, // last in DB stable slot index (including), all higher have same meaning as PET_SAVE_NOT_IN_SLOT
|
||||
AsCurrent = -3, // in current slot (with player)
|
||||
FirstActiveSlot = 0,
|
||||
LastActiveSlot = FirstActiveSlot + SharedConst.MaxActivePets,
|
||||
FirstStableSlot = 5,
|
||||
LastStableSlot = FirstStableSlot + SharedConst.MaxPetStables, // last in DB stable slot index
|
||||
NotInSlot = -1, // for avoid conflict with stable size grow will use negative value
|
||||
}
|
||||
|
||||
public enum PetSpellState
|
||||
|
||||
@@ -219,7 +219,9 @@ namespace Framework.Constants
|
||||
/// <summary>
|
||||
/// Pet Const
|
||||
/// </summary>
|
||||
public const int MaxPetStables = 4;
|
||||
public const int MaxActivePets = 5;
|
||||
public const int MaxPetStables = 200;
|
||||
public const uint CallPetSpellId = 883;
|
||||
public const float PetFollowDist = 1.0f;
|
||||
public const float PetFollowAngle = MathF.PI;
|
||||
public const int MaxSpellCharm = 4;
|
||||
@@ -434,6 +436,16 @@ namespace Framework.Constants
|
||||
{
|
||||
return raceId < Race.Max && raceBits[(int)raceId] >= 0 && raceBits[(int)raceId] < 64 ? (1 << raceBits[(int)raceId]) : 0;
|
||||
}
|
||||
|
||||
public static bool IsActivePetSlot(PetSaveMode slot)
|
||||
{
|
||||
return slot >= PetSaveMode.FirstActiveSlot && slot < PetSaveMode.LastActiveSlot;
|
||||
}
|
||||
|
||||
public static bool IsStabledPetSlot(PetSaveMode slot)
|
||||
{
|
||||
return slot >= PetSaveMode.FirstStableSlot && slot < PetSaveMode.LastStableSlot;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Locale
|
||||
|
||||
@@ -721,7 +721,6 @@ namespace Framework.Database
|
||||
PrepareStatement(CharStatements.UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?");
|
||||
PrepareStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?");
|
||||
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?");
|
||||
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND slot IN (?, ?)");
|
||||
PrepareStatement(CharStatements.DEL_ALL_PET_SPELLS_BY_OWNER, "DELETE FROM pet_spell WHERE guid in (SELECT id FROM character_pet WHERE owner=?)");
|
||||
PrepareStatement(CharStatements.UPD_PET_SPECS_BY_OWNER, "UPDATE character_pet SET specialization = 0 WHERE owner=?");
|
||||
PrepareStatement(CharStatements.INS_PET, "INSERT INTO character_pet (id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization) " +
|
||||
@@ -1353,7 +1352,6 @@ namespace Framework.Database
|
||||
UPD_CHAR_PET_NAME,
|
||||
UPD_CHAR_PET_SLOT_BY_ID,
|
||||
DEL_CHAR_PET_BY_ID,
|
||||
DEL_CHAR_PET_BY_SLOT,
|
||||
DEL_ALL_PET_SPELLS_BY_OWNER,
|
||||
UPD_PET_SPECS_BY_OWNER,
|
||||
INS_PET,
|
||||
|
||||
+69
-53
@@ -96,13 +96,14 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public static Tuple<PetStable.PetInfo, PetSaveMode> GetLoadPetInfo(PetStable stable, uint petEntry, uint petnumber, bool current)
|
||||
public static Tuple<PetStable.PetInfo, PetSaveMode> GetLoadPetInfo(PetStable stable, uint petEntry, uint petnumber, PetSaveMode? slot)
|
||||
{
|
||||
if (petnumber != 0)
|
||||
{
|
||||
// Known petnumber entry
|
||||
if (stable.CurrentPet != null && stable.CurrentPet.PetNumber == petnumber)
|
||||
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||
for (var activeSlot = 0; activeSlot < stable.ActivePets.Length; ++activeSlot)
|
||||
if (stable.ActivePets[activeSlot] != null && stable.ActivePets[activeSlot].PetNumber == petnumber)
|
||||
return Tuple.Create(stable.ActivePets[activeSlot], PetSaveMode.FirstActiveSlot + activeSlot);
|
||||
|
||||
for (var stableSlot = 0; stableSlot < stable.StabledPets.Length; ++stableSlot)
|
||||
if (stable.StabledPets[stableSlot] != null && stable.StabledPets[stableSlot].PetNumber == petnumber)
|
||||
@@ -112,17 +113,24 @@ namespace Game.Entities
|
||||
if (pet.PetNumber == petnumber)
|
||||
return Tuple.Create(pet, PetSaveMode.NotInSlot);
|
||||
}
|
||||
else if (current)
|
||||
else if (slot.HasValue)
|
||||
{
|
||||
// Current pet (slot 0)
|
||||
if (stable.CurrentPet != null)
|
||||
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||
// Current pet
|
||||
if (slot == PetSaveMode.AsCurrent)
|
||||
if (stable.GetCurrentActivePetIndex().HasValue && stable.ActivePets[stable.GetCurrentActivePetIndex().Value] != null)
|
||||
return Tuple.Create(stable.ActivePets[stable.GetCurrentActivePetIndex().Value], (PetSaveMode)stable.GetCurrentActivePetIndex());
|
||||
|
||||
if (slot >= PetSaveMode.FirstActiveSlot && slot < PetSaveMode.LastActiveSlot)
|
||||
if (stable.ActivePets[(int)slot.Value] != null)
|
||||
return Tuple.Create(stable.ActivePets[(int)slot.Value], slot.Value);
|
||||
|
||||
if (slot >= PetSaveMode.FirstStableSlot && slot < PetSaveMode.LastStableSlot)
|
||||
if (stable.StabledPets[(int)slot.Value] != null)
|
||||
return Tuple.Create(stable.StabledPets[(int)slot.Value], slot.Value);
|
||||
}
|
||||
else if (petEntry != 0)
|
||||
{
|
||||
// known petEntry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
|
||||
if (stable.CurrentPet != null && stable.CurrentPet.CreatureId == petEntry)
|
||||
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||
|
||||
foreach (var pet in stable.UnslottedPets)
|
||||
if (pet.CreatureId == petEntry)
|
||||
@@ -131,8 +139,8 @@ namespace Game.Entities
|
||||
else
|
||||
{
|
||||
// Any current or other non-stabled pet (for hunter "call pet")
|
||||
if (stable.CurrentPet != null)
|
||||
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||
if (stable.ActivePets[0] != null)
|
||||
return Tuple.Create(stable.ActivePets[0], PetSaveMode.FirstActiveSlot);
|
||||
|
||||
if (!stable.UnslottedPets.Empty())
|
||||
return Tuple.Create(stable.UnslottedPets.First(), PetSaveMode.NotInSlot);
|
||||
@@ -141,22 +149,22 @@ namespace Game.Entities
|
||||
return Tuple.Create<PetStable.PetInfo, PetSaveMode>(null, PetSaveMode.AsDeleted);
|
||||
}
|
||||
|
||||
public bool LoadPetFromDB(Player owner, uint petEntry = 0, uint petnumber = 0, bool current = false)
|
||||
public bool LoadPetFromDB(Player owner, uint petEntry = 0, uint petnumber = 0, bool current = false, PetSaveMode? forcedSlot = null)
|
||||
{
|
||||
m_loading = true;
|
||||
|
||||
PetStable petStable = owner.GetPetStable();
|
||||
|
||||
ulong ownerid = owner.GetGUID().GetCounter();
|
||||
(PetStable.PetInfo petInfo, PetSaveMode slot) = GetLoadPetInfo(petStable, petEntry, petnumber, current);
|
||||
if (petInfo == null)
|
||||
(PetStable.PetInfo petInfo, PetSaveMode slot) = GetLoadPetInfo(petStable, petEntry, petnumber, forcedSlot);
|
||||
if (petInfo == null || (slot >= PetSaveMode.FirstStableSlot && slot < PetSaveMode.LastStableSlot))
|
||||
{
|
||||
m_loading = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't try to reload the current pet
|
||||
if (petStable.CurrentPet != null && owner.GetPet() != null && petStable.CurrentPet.PetNumber == petInfo.PetNumber)
|
||||
if (petStable.GetCurrentPet() != null && owner.GetPet() != null && petStable.GetCurrentPet().PetNumber == petInfo.PetNumber)
|
||||
return false;
|
||||
|
||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petInfo.CreatedBySpellId, owner.GetMap().GetDifficultyID());
|
||||
@@ -273,36 +281,28 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
// set current pet as current
|
||||
// 0=current
|
||||
// 1..MAX_PET_STABLES in stable slot
|
||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
||||
// 0-4=current
|
||||
// PET_SAVE_NOT_IN_SLOT(-1) = not stable slot (summoning))
|
||||
if (slot == PetSaveMode.NotInSlot)
|
||||
{
|
||||
uint petInfoNumber = petInfo.PetNumber;
|
||||
if (petStable.CurrentPet != null)
|
||||
if (petStable.CurrentPetIndex != 0)
|
||||
owner.RemovePet(null, PetSaveMode.NotInSlot);
|
||||
|
||||
var unslottedPetInfo = petStable.UnslottedPets.Find(unslottedPet => unslottedPet.PetNumber == petInfoNumber);
|
||||
Cypher.Assert(petStable.CurrentPet == null);
|
||||
Cypher.Assert(unslottedPetInfo != null);
|
||||
var unslottedPetIndex = petStable.UnslottedPets.FindIndex(unslottedPet => unslottedPet.PetNumber == petInfoNumber);
|
||||
Cypher.Assert(petStable.CurrentPetIndex == 0);
|
||||
Cypher.Assert(unslottedPetIndex != -1);
|
||||
|
||||
petStable.CurrentPet = unslottedPetInfo;
|
||||
petStable.UnslottedPets.Remove(unslottedPetInfo);
|
||||
|
||||
// old petInfo is no longer valid, refresh it
|
||||
petInfo = petStable.CurrentPet;
|
||||
petStable.SetCurrentUnslottedPetIndex((uint)unslottedPetIndex);
|
||||
}
|
||||
else if (PetSaveMode.FirstStableSlot <= slot && slot <= PetSaveMode.LastStableSlot)
|
||||
else if (PetSaveMode.FirstActiveSlot <= slot && slot <= PetSaveMode.LastActiveSlot)
|
||||
{
|
||||
var index = Array.FindIndex(petStable.StabledPets, pet => pet?.PetNumber == petnumber);
|
||||
var stabledPet = petStable.StabledPets[index];
|
||||
Cypher.Assert(index != -1);
|
||||
var activePetIndex = Array.FindIndex(petStable.ActivePets, pet => pet?.PetNumber == petnumber);
|
||||
|
||||
petStable.StabledPets[index] = petStable.CurrentPet;
|
||||
petStable.CurrentPet = stabledPet;
|
||||
Cypher.Assert(petStable.CurrentPetIndex == 0);
|
||||
Cypher.Assert(activePetIndex != -1);
|
||||
|
||||
// old petInfo pointer is no longer valid, refresh it
|
||||
petInfo = petStable.CurrentPet;
|
||||
petStable.SetCurrentActivePetIndex((uint)activePetIndex);
|
||||
}
|
||||
|
||||
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
||||
@@ -437,8 +437,15 @@ namespace Game.Entities
|
||||
// save auras before possibly removing them
|
||||
_SaveAuras(trans);
|
||||
|
||||
if (mode == PetSaveMode.AsCurrent)
|
||||
{
|
||||
var activeSlot = owner.GetPetStable().GetCurrentActivePetIndex();
|
||||
if (activeSlot.HasValue)
|
||||
mode = (PetSaveMode)activeSlot;
|
||||
}
|
||||
|
||||
// stable and not in slot saves
|
||||
if (mode > PetSaveMode.AsCurrent)
|
||||
if (mode < PetSaveMode.FirstActiveSlot || mode >= PetSaveMode.LastActiveSlot)
|
||||
RemoveAllAuras();
|
||||
|
||||
_SaveSpells(trans);
|
||||
@@ -446,7 +453,7 @@ namespace Game.Entities
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
|
||||
// current/stable/not_in_slot
|
||||
if (mode >= PetSaveMode.AsCurrent)
|
||||
if (mode != PetSaveMode.AsDeleted)
|
||||
{
|
||||
ulong ownerLowGUID = GetOwnerGUID().GetCounter();
|
||||
trans = new SQLTransaction();
|
||||
@@ -456,21 +463,11 @@ namespace Game.Entities
|
||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
||||
trans.Append(stmt);
|
||||
|
||||
// prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
|
||||
if (GetPetType() == PetType.Hunter && (mode == PetSaveMode.AsCurrent || mode == PetSaveMode.LastStableSlot))
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_BY_SLOT);
|
||||
stmt.AddValue(0, ownerLowGUID);
|
||||
stmt.AddValue(1, (short)mode);
|
||||
stmt.AddValue(2, (short)PetSaveMode.NotInSlot);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
// save pet
|
||||
string actionBar = GenerateActionBarData();
|
||||
|
||||
Cypher.Assert(owner.GetPetStable().CurrentPet != null && owner.GetPetStable().CurrentPet.PetNumber == GetCharmInfo().GetPetNumber());
|
||||
FillPetInfo(owner.GetPetStable().CurrentPet);
|
||||
Cypher.Assert(owner.GetPetStable().GetCurrentPet() != null && owner.GetPetStable().GetCurrentPet().PetNumber == GetCharmInfo().GetPetNumber());
|
||||
FillPetInfo(owner.GetPetStable().GetCurrentPet());
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PET);
|
||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
||||
@@ -480,7 +477,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(4, GetLevel());
|
||||
stmt.AddValue(5, m_unitData.PetExperience);
|
||||
stmt.AddValue(6, (byte)GetReactState());
|
||||
stmt.AddValue(7, (byte)mode);
|
||||
stmt.AddValue(7, (owner.GetPetStable().GetCurrentActivePetIndex().HasValue ? (short)owner.GetPetStable().GetCurrentActivePetIndex().Value : (short)PetSaveMode.NotInSlot));
|
||||
stmt.AddValue(8, GetName());
|
||||
stmt.AddValue(9, HasPetFlag(UnitPetFlags.CanBeRenamed) ? 0 : 1);
|
||||
stmt.AddValue(10, curhealth);
|
||||
@@ -1676,6 +1673,8 @@ namespace Game.Entities
|
||||
|
||||
public class PetStable
|
||||
{
|
||||
static uint UnslottedPetIndexMask = 0x80000000;
|
||||
|
||||
public class PetInfo
|
||||
{
|
||||
public string Name;
|
||||
@@ -1695,14 +1694,31 @@ namespace Game.Entities
|
||||
public bool WasRenamed;
|
||||
}
|
||||
|
||||
public PetInfo CurrentPet; // PET_SAVE_AS_CURRENT
|
||||
public uint? CurrentPetIndex; // index into ActivePets or UnslottedPets if highest bit is set
|
||||
public PetInfo[] ActivePets = new PetInfo[SharedConst.MaxActivePets]; // PET_SAVE_FIRST_ACTIVE_SLOT - PET_SAVE_LAST_ACTIVE_SLOT
|
||||
public PetInfo[] StabledPets = new PetInfo[SharedConst.MaxPetStables]; // PET_SAVE_FIRST_STABLE_SLOT - PET_SAVE_LAST_STABLE_SLOT
|
||||
public List<PetInfo> UnslottedPets = new(); // PET_SAVE_NOT_IN_SLOT
|
||||
|
||||
public PetInfo GetUnslottedHunterPet()
|
||||
public PetInfo GetCurrentPet()
|
||||
{
|
||||
return UnslottedPets.Count == 1 && UnslottedPets[0].Type == PetType.Hunter ? UnslottedPets[0] : null;
|
||||
if (!CurrentPetIndex.HasValue)
|
||||
return null;
|
||||
|
||||
uint? activePetIndex = GetCurrentActivePetIndex();
|
||||
if (activePetIndex.HasValue)
|
||||
return ActivePets[activePetIndex.Value] != null ? ActivePets[activePetIndex.Value] : null;
|
||||
|
||||
uint? unslottedPetIndex = GetCurrentUnslottedPetIndex();
|
||||
if (unslottedPetIndex.HasValue)
|
||||
return unslottedPetIndex < UnslottedPets.Count ? UnslottedPets[(int)unslottedPetIndex.Value] : null;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public uint? GetCurrentActivePetIndex() { return CurrentPetIndex.HasValue && ((CurrentPetIndex & UnslottedPetIndexMask) == 0) ? CurrentPetIndex : null; }
|
||||
public void SetCurrentActivePetIndex(uint index) { CurrentPetIndex = index; }
|
||||
uint? GetCurrentUnslottedPetIndex() { return CurrentPetIndex.HasValue && ((CurrentPetIndex & UnslottedPetIndexMask) != 0) ? (CurrentPetIndex & ~UnslottedPetIndexMask) : null; }
|
||||
public void SetCurrentUnslottedPetIndex(uint index) { CurrentPetIndex = index | UnslottedPetIndexMask; }
|
||||
}
|
||||
|
||||
public enum ActiveStates
|
||||
|
||||
@@ -1538,7 +1538,7 @@ namespace Game.Entities
|
||||
m_bgData.taxiPath[1] = result.Read<uint>(8);
|
||||
m_bgData.mountSpell = result.Read<uint>(9);
|
||||
}
|
||||
void _LoadPetStable(SQLResult result)
|
||||
void _LoadPetStable(uint summonedPetNumber, SQLResult result)
|
||||
{
|
||||
if (result.IsEmpty())
|
||||
return;
|
||||
@@ -1568,15 +1568,18 @@ namespace Game.Entities
|
||||
petInfo.CreatedBySpellId = result.Read<uint>(13);
|
||||
petInfo.Type = (PetType)result.Read<byte>(14);
|
||||
petInfo.SpecializationId = result.Read<ushort>(15);
|
||||
if (slot == PetSaveMode.AsCurrent)
|
||||
m_petStable.CurrentPet = petInfo;
|
||||
else if (slot >= PetSaveMode.FirstStableSlot && slot <= PetSaveMode.LastStableSlot)
|
||||
m_petStable.StabledPets[(int)slot - 1] = petInfo;
|
||||
if (slot >= PetSaveMode.FirstActiveSlot && slot < PetSaveMode.LastActiveSlot)
|
||||
m_petStable.ActivePets[(int)slot] = petInfo;
|
||||
else if (slot >= PetSaveMode.FirstStableSlot && slot < PetSaveMode.LastStableSlot)
|
||||
m_petStable.StabledPets[slot - PetSaveMode.FirstStableSlot] = petInfo;
|
||||
else if (slot == PetSaveMode.NotInSlot)
|
||||
m_petStable.UnslottedPets.Add(petInfo);
|
||||
|
||||
} while (result.NextRow());
|
||||
}
|
||||
|
||||
if (Pet.GetLoadPetInfo(m_petStable, 0, summonedPetNumber, null).Item1 != null)
|
||||
m_temporaryUnsummonedPetNumber = summonedPetNumber;
|
||||
}
|
||||
|
||||
|
||||
@@ -3080,8 +3083,7 @@ namespace Game.Entities
|
||||
|
||||
m_taxi.LoadTaxiMask(taximask); // must be before InitTaxiNodesForLevel
|
||||
|
||||
_LoadPetStable(holder.GetResult(PlayerLoginQueryLoad.PetSlots));
|
||||
m_temporaryUnsummonedPetNumber = summonedPetNumber;
|
||||
_LoadPetStable(summonedPetNumber, holder.GetResult(PlayerLoginQueryLoad.PetSlots));
|
||||
|
||||
// Honor system
|
||||
// Update Honor kills data
|
||||
@@ -3590,7 +3592,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(index++, (ushort)m_ExtraFlags);
|
||||
PetStable petStable = GetPetStable();
|
||||
if (petStable != null)
|
||||
stmt.AddValue(index++, petStable.CurrentPet != null && petStable.CurrentPet.Health > 0 ? petStable.CurrentPet.PetNumber : 0); // summonedPetNumber
|
||||
stmt.AddValue(index++, petStable.GetCurrentPet() != null && petStable.GetCurrentPet().Health > 0 ? petStable.GetCurrentPet().PetNumber : 0); // summonedPetNumber
|
||||
else
|
||||
stmt.AddValue(index++, 0); // summonedPetNumber
|
||||
stmt.AddValue(index++, (ushort)atLoginFlags);
|
||||
|
||||
@@ -4701,12 +4701,19 @@ namespace Game.Entities
|
||||
return null;
|
||||
}
|
||||
|
||||
public Pet SummonPet(uint entry, float x, float y, float z, float ang, PetType petType, uint duration)
|
||||
public Pet SummonPet(uint entry, PetSaveMode? slot, float x, float y, float z, float ang, uint duration)
|
||||
{
|
||||
return SummonPet(entry, slot, x, y, z, ang, duration, out _);
|
||||
}
|
||||
|
||||
public Pet SummonPet(uint entry, PetSaveMode? slot, float x, float y, float z, float ang, uint duration, out bool isNew)
|
||||
{
|
||||
isNew = false;
|
||||
|
||||
PetStable petStable = GetOrInitPetStable();
|
||||
|
||||
Pet pet = new(this, petType);
|
||||
if (petType == PetType.Summon && pet.LoadPetFromDB(this, entry, 0, false))
|
||||
Pet pet = new(this, PetType.Summon);
|
||||
if (pet.LoadPetFromDB(this, entry, 0, false, slot))
|
||||
{
|
||||
if (duration > 0)
|
||||
pet.SetDuration(duration);
|
||||
@@ -4718,6 +4725,8 @@ namespace Game.Entities
|
||||
if (entry == 0)
|
||||
return null;
|
||||
|
||||
// only SUMMON_PET are handled here
|
||||
|
||||
pet.Relocate(x, y, z, ang);
|
||||
if (!pet.IsPositionValid())
|
||||
{
|
||||
@@ -4734,7 +4743,7 @@ namespace Game.Entities
|
||||
return null;
|
||||
}
|
||||
|
||||
if (petType == PetType.Summon && petStable.CurrentPet != null)
|
||||
if (petStable.GetCurrentPet() != null)
|
||||
RemovePet(null, PetSaveMode.NotInSlot);
|
||||
|
||||
PhasingHandler.InheritPhaseShift(pet, this);
|
||||
@@ -4747,44 +4756,34 @@ namespace Game.Entities
|
||||
|
||||
SetMinion(pet, true);
|
||||
|
||||
Cypher.Assert(petStable.CurrentPet == null && (petType != PetType.Hunter || petStable.GetUnslottedHunterPet() == null));
|
||||
petStable.CurrentPet = new();
|
||||
pet.FillPetInfo(petStable.CurrentPet);
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case PetType.Summon:
|
||||
// this enables pet details window (Shift+P)
|
||||
pet.GetCharmInfo().SetPetNumber(petNumber, true);
|
||||
pet.SetClass(Class.Mage);
|
||||
pet.SetPetExperience(0);
|
||||
pet.SetPetNextLevelExperience(1000);
|
||||
pet.SetFullHealth();
|
||||
pet.SetFullPower(PowerType.Mana);
|
||||
pet.SetPetNameTimestamp((uint)GameTime.GetGameTime());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// this enables pet details window (Shift+P)
|
||||
pet.GetCharmInfo().SetPetNumber(petNumber, true);
|
||||
pet.SetClass(Class.Mage);
|
||||
pet.SetPetExperience(0);
|
||||
pet.SetPetNextLevelExperience(1000);
|
||||
pet.SetFullHealth();
|
||||
pet.SetFullPower(PowerType.Mana);
|
||||
pet.SetPetNameTimestamp((uint)GameTime.GetGameTime());
|
||||
|
||||
map.AddToMap(pet.ToCreature());
|
||||
|
||||
switch (petType)
|
||||
{
|
||||
case PetType.Summon:
|
||||
pet.InitPetCreateSpells();
|
||||
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
||||
PetSpellInitialize();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Cypher.Assert(petStable.CurrentPetIndex == 0);
|
||||
petStable.SetCurrentUnslottedPetIndex((uint)petStable.UnslottedPets.Count);
|
||||
PetStable.PetInfo petInfo = new();
|
||||
pet.FillPetInfo(petInfo);
|
||||
petStable.UnslottedPets.Add(petInfo);
|
||||
|
||||
pet.InitPetCreateSpells();
|
||||
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
||||
PetSpellInitialize();
|
||||
|
||||
if (duration > 0)
|
||||
pet.SetDuration(duration);
|
||||
|
||||
//ObjectAccessor.UpdateObjectVisibility(pet);
|
||||
|
||||
isNew = true;
|
||||
|
||||
return pet;
|
||||
}
|
||||
|
||||
@@ -4829,49 +4828,22 @@ namespace Game.Entities
|
||||
|
||||
if (pet == null)
|
||||
{
|
||||
if (mode == PetSaveMode.NotInSlot && m_petStable?.CurrentPet != null)
|
||||
{
|
||||
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt.AddValue(0, (short)PetSaveMode.NotInSlot);
|
||||
stmt.AddValue(1, GetGUID().GetCounter());
|
||||
stmt.AddValue(2, m_petStable.CurrentPet.PetNumber);
|
||||
DB.Characters.Execute(stmt);
|
||||
|
||||
m_petStable.UnslottedPets.Add(m_petStable.CurrentPet);
|
||||
m_petStable.CurrentPet = null;
|
||||
}
|
||||
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
||||
if (mode == PetSaveMode.NotInSlot && m_petStable != null && m_petStable.CurrentPetIndex.HasValue)
|
||||
m_petStable.CurrentPetIndex = null;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pet.CombatStop();
|
||||
|
||||
if (returnreagent)
|
||||
{
|
||||
switch (pet.GetEntry())
|
||||
{
|
||||
//warlock pets except imp are removed(?) when logging out
|
||||
case 1860:
|
||||
case 1863:
|
||||
case 417:
|
||||
case 17252:
|
||||
mode = PetSaveMode.NotInSlot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// only if current pet in slot
|
||||
pet.SavePetToDB(mode);
|
||||
|
||||
Cypher.Assert(m_petStable.CurrentPet != null && m_petStable.CurrentPet.PetNumber == pet.GetCharmInfo().GetPetNumber());
|
||||
if (mode == PetSaveMode.NotInSlot)
|
||||
{
|
||||
m_petStable.UnslottedPets.Add(m_petStable.CurrentPet);
|
||||
m_petStable.CurrentPet = null;
|
||||
}
|
||||
else if (mode == PetSaveMode.AsDeleted)
|
||||
m_petStable.CurrentPet = null;
|
||||
PetStable.PetInfo currentPet = m_petStable.GetCurrentPet();
|
||||
Cypher.Assert(currentPet != null && currentPet.PetNumber == pet.GetCharmInfo().GetPetNumber());
|
||||
if (mode == PetSaveMode.NotInSlot || mode == PetSaveMode.AsDeleted)
|
||||
m_petStable.CurrentPetIndex = null;
|
||||
// else if (stable slots) handled in opcode handlers due to required swaps
|
||||
// else (current pet) doesnt need to do anything
|
||||
|
||||
|
||||
@@ -761,7 +761,9 @@ namespace Game.Entities
|
||||
{
|
||||
Player player = ToPlayer();
|
||||
PetStable petStable = player.GetOrInitPetStable();
|
||||
if (petStable.CurrentPet != null || petStable.GetUnslottedHunterPet() != null)
|
||||
|
||||
var freeActiveSlot = Array.FindIndex(petStable.ActivePets, petInfo => petInfo == null);
|
||||
if (freeActiveSlot == -1)
|
||||
return false;
|
||||
|
||||
pet.SetCreatorGUID(GetGUID());
|
||||
@@ -784,8 +786,11 @@ namespace Game.Entities
|
||||
pet.InitPetCreateSpells();
|
||||
pet.SetFullHealth();
|
||||
|
||||
petStable.CurrentPet = new();
|
||||
pet.FillPetInfo(petStable.CurrentPet);
|
||||
petStable.SetCurrentActivePetIndex((uint)freeActiveSlot);
|
||||
|
||||
PetStable.PetInfo petInfo = new();
|
||||
pet.FillPetInfo(petInfo);
|
||||
petStable.ActivePets[freeActiveSlot] = petInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -792,6 +792,10 @@ namespace Game
|
||||
pCurrChar.SetGuildLevel(0);
|
||||
}
|
||||
|
||||
// Send stable contents to display icons on Call Pet spells
|
||||
if (pCurrChar.HasSpell(SharedConst.CallPetSpellId))
|
||||
SendStablePet(ObjectGuid.Empty);
|
||||
|
||||
pCurrChar.GetSession().GetBattlePetMgr().SendJournalLockStatus();
|
||||
|
||||
pCurrChar.SendInitialPacketsBeforeAddToMap();
|
||||
|
||||
@@ -324,7 +324,7 @@ namespace Game
|
||||
GetPlayer().PlayerTalkClass.SendCloseGossip();
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RequestStabledPets)]
|
||||
[WorldPacketHandler(ClientOpcodes.RequestStabledPets, Processing = PacketProcessing.Inplace)]
|
||||
void HandleRequestStabledPets(RequestStabledPets packet)
|
||||
{
|
||||
if (!CheckStableMaster(packet.StableMaster))
|
||||
@@ -353,58 +353,40 @@ namespace Game
|
||||
return;
|
||||
}
|
||||
|
||||
uint petSlot = 0;
|
||||
if (petStable.CurrentPet != null)
|
||||
for (uint petSlot = 0; petSlot < petStable.ActivePets.Length; ++petSlot)
|
||||
{
|
||||
PetStable.PetInfo pet = petStable.CurrentPet;
|
||||
if (petStable.ActivePets[petSlot] == null)
|
||||
continue;
|
||||
|
||||
PetStable.PetInfo pet = petStable.ActivePets[petSlot];
|
||||
PetStableInfo stableEntry;
|
||||
stableEntry.PetSlot = petSlot;
|
||||
stableEntry.PetSlot = petSlot + (int)PetSaveMode.FirstActiveSlot;
|
||||
stableEntry.PetNumber = pet.PetNumber;
|
||||
stableEntry.CreatureID = pet.CreatureId;
|
||||
stableEntry.DisplayID = pet.DisplayId;
|
||||
stableEntry.ExperienceLevel = pet.Level;
|
||||
stableEntry.PetFlags = PetStableinfo.Active;
|
||||
stableEntry.PetName = pet.Name;
|
||||
++petSlot;
|
||||
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
else
|
||||
|
||||
for (uint petSlot = 0; petSlot < petStable.StabledPets.Length; ++petSlot)
|
||||
{
|
||||
PetStable.PetInfo pet = petStable.GetUnslottedHunterPet();
|
||||
if (pet != null)
|
||||
{
|
||||
PetStableInfo stableEntry;
|
||||
stableEntry.PetSlot = petSlot;
|
||||
stableEntry.PetNumber = pet.PetNumber;
|
||||
stableEntry.CreatureID = pet.CreatureId;
|
||||
stableEntry.DisplayID = pet.DisplayId;
|
||||
stableEntry.ExperienceLevel = pet.Level;
|
||||
stableEntry.PetFlags = PetStableinfo.Active;
|
||||
stableEntry.PetName = pet.Name;
|
||||
if (petStable.StabledPets[petSlot] == null)
|
||||
continue;
|
||||
|
||||
++petSlot;
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
}
|
||||
PetStable.PetInfo pet = petStable.StabledPets[petSlot];
|
||||
PetStableInfo stableEntry;
|
||||
stableEntry.PetSlot = petSlot + (int)PetSaveMode.FirstStableSlot;
|
||||
stableEntry.PetNumber = pet.PetNumber;
|
||||
stableEntry.CreatureID = pet.CreatureId;
|
||||
stableEntry.DisplayID = pet.DisplayId;
|
||||
stableEntry.ExperienceLevel = pet.Level;
|
||||
stableEntry.PetFlags = PetStableinfo.Inactive;
|
||||
stableEntry.PetName = pet.Name;
|
||||
|
||||
foreach (var pet in petStable.StabledPets)
|
||||
{
|
||||
if (pet != null)
|
||||
{
|
||||
PetStableInfo stableEntry;
|
||||
stableEntry.PetSlot = petSlot;
|
||||
stableEntry.PetNumber = pet.PetNumber;
|
||||
stableEntry.CreatureID = pet.CreatureId;
|
||||
stableEntry.DisplayID = pet.DisplayId;
|
||||
stableEntry.ExperienceLevel = pet.Level;
|
||||
stableEntry.PetFlags = PetStableinfo.Inactive;
|
||||
stableEntry.PetName = pet.Name;
|
||||
|
||||
++petSlot;
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
packet.Pets.Add(stableEntry);
|
||||
}
|
||||
|
||||
SendPacket(packet);
|
||||
@@ -417,6 +399,152 @@ namespace Game
|
||||
SendPacket(petStableResult);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.SetPetSlot)]
|
||||
void HandleSetPetSlot(SetPetSlot setPetSlot)
|
||||
{
|
||||
if (!CheckStableMaster(setPetSlot.StableMaster) || setPetSlot.DestSlot >= (byte)PetSaveMode.LastStableSlot)
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
GetPlayer().RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting);
|
||||
|
||||
PetStable petStable = GetPlayer().GetPetStable();
|
||||
if (petStable == null)
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
(PetStable.PetInfo srcPet, PetSaveMode srcPetSlot) = Pet.GetLoadPetInfo(petStable, 0, setPetSlot.PetNumber, null);
|
||||
PetSaveMode dstPetSlot = (PetSaveMode)setPetSlot.DestSlot;
|
||||
PetStable.PetInfo dstPet = Pet.GetLoadPetInfo(petStable, 0, 0, dstPetSlot).Item1;
|
||||
|
||||
if (srcPet == null || srcPet.Type != PetType.Hunter)
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dstPet != null && dstPet.Type != PetType.Hunter)
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
PetStable.PetInfo src = null;
|
||||
PetStable.PetInfo dst = null;
|
||||
PetSaveMode? newActivePetIndex = null;
|
||||
|
||||
if (SharedConst.IsActivePetSlot(srcPetSlot) && SharedConst.IsActivePetSlot(dstPetSlot))
|
||||
{
|
||||
// active<.active: only swap ActivePets and CurrentPetIndex (do not despawn pets)
|
||||
src = petStable.ActivePets[srcPetSlot - PetSaveMode.FirstActiveSlot];
|
||||
dst = petStable.ActivePets[dstPetSlot - PetSaveMode.FirstActiveSlot];
|
||||
|
||||
if (petStable.GetCurrentActivePetIndex().Value == (uint)srcPetSlot)
|
||||
newActivePetIndex = dstPetSlot;
|
||||
else if (petStable.GetCurrentActivePetIndex().Value == (uint)dstPetSlot)
|
||||
newActivePetIndex = srcPetSlot;
|
||||
}
|
||||
else if (SharedConst.IsStabledPetSlot(srcPetSlot) && SharedConst.IsStabledPetSlot(dstPetSlot))
|
||||
{
|
||||
// stabled<.stabled: only swap StabledPets
|
||||
src = petStable.StabledPets[srcPetSlot - PetSaveMode.FirstStableSlot];
|
||||
dst = petStable.StabledPets[dstPetSlot - PetSaveMode.FirstStableSlot];
|
||||
}
|
||||
else if (SharedConst.IsActivePetSlot(srcPetSlot) && SharedConst.IsStabledPetSlot(dstPetSlot))
|
||||
{
|
||||
// active<.stabled: swap petStable contents and despawn active pet if it is involved in swap
|
||||
if (petStable.CurrentPetIndex.Value == (uint)srcPetSlot)
|
||||
{
|
||||
Pet oldPet = _player.GetPet();
|
||||
if (oldPet != null && !oldPet.IsAlive())
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
_player.RemovePet(oldPet, PetSaveMode.NotInSlot);
|
||||
}
|
||||
|
||||
if (dstPet != null)
|
||||
{
|
||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(dstPet.CreatureId);
|
||||
if (creatureInfo == null || !creatureInfo.IsTameable(_player.CanTameExoticPets()))
|
||||
{
|
||||
SendPetStableResult(StableResult.CantControlExotic);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
src = petStable.ActivePets[srcPetSlot - PetSaveMode.FirstActiveSlot];
|
||||
dst = petStable.StabledPets[dstPetSlot - PetSaveMode.FirstStableSlot];
|
||||
}
|
||||
else if (SharedConst.IsStabledPetSlot(srcPetSlot) && SharedConst.IsActivePetSlot(dstPetSlot))
|
||||
{
|
||||
// stabled<.active: swap petStable contents and despawn active pet if it is involved in swap
|
||||
if (petStable.CurrentPetIndex.Value == (uint)dstPetSlot)
|
||||
{
|
||||
Pet oldPet = _player.GetPet();
|
||||
if (oldPet != null && !oldPet.IsAlive())
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
return;
|
||||
}
|
||||
|
||||
_player.RemovePet(oldPet, PetSaveMode.NotInSlot);
|
||||
}
|
||||
|
||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(srcPet.CreatureId);
|
||||
if (creatureInfo == null || !creatureInfo.IsTameable(_player.CanTameExoticPets()))
|
||||
{
|
||||
SendPetStableResult(StableResult.CantControlExotic);
|
||||
return;
|
||||
}
|
||||
|
||||
src = petStable.StabledPets[srcPetSlot - PetSaveMode.FirstStableSlot];
|
||||
dst = petStable.ActivePets[dstPetSlot - PetSaveMode.FirstActiveSlot];
|
||||
}
|
||||
|
||||
SQLTransaction trans = new();
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt.AddValue(0, (short)dstPetSlot);
|
||||
stmt.AddValue(1, _player.GetGUID().GetCounter());
|
||||
stmt.AddValue(2, srcPet.PetNumber);
|
||||
trans.Append(stmt);
|
||||
|
||||
if (dstPet != null)
|
||||
{
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID);
|
||||
stmt.AddValue(0, (short)srcPetSlot);
|
||||
stmt.AddValue(1, _player.GetGUID().GetCounter());
|
||||
stmt.AddValue(2, dstPet.PetNumber);
|
||||
trans.Append(stmt);
|
||||
}
|
||||
|
||||
AddTransactionCallback(DB.Characters.AsyncCommitTransaction(trans)).AfterComplete(success =>
|
||||
{
|
||||
var currentPlayerGuid = _player.GetGUID();
|
||||
if (_player && _player.GetGUID() == currentPlayerGuid)
|
||||
{
|
||||
if (success)
|
||||
{
|
||||
Extensions.Swap(ref src, ref dst);
|
||||
if (newActivePetIndex.HasValue)
|
||||
GetPlayer().GetPetStable().SetCurrentActivePetIndex((uint)newActivePetIndex.Value);
|
||||
SendPetStableResult(StableResult.StableSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendPetStableResult(StableResult.InternalError);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.RepairItem, Processing = PacketProcessing.Inplace)]
|
||||
void HandleRepairItem(RepairItem packet)
|
||||
{
|
||||
|
||||
@@ -541,7 +541,7 @@ namespace Game
|
||||
// check it!
|
||||
if (!pet || !pet.IsPet() || pet.ToPet().GetPetType() != PetType.Hunter || !pet.HasPetFlag(UnitPetFlags.CanBeRenamed) ||
|
||||
pet.GetOwnerGUID() != _player.GetGUID() || pet.GetCharmInfo() == null ||
|
||||
petStable == null || petStable.CurrentPet == null || petStable.CurrentPet.PetNumber != pet.GetCharmInfo().GetPetNumber())
|
||||
petStable == null || petStable.GetCurrentPet() == null || petStable.GetCurrentPet().PetNumber != pet.GetCharmInfo().GetPetNumber())
|
||||
return;
|
||||
|
||||
PetNameInvalidReason res = ObjectManager.CheckPetName(name);
|
||||
@@ -561,8 +561,8 @@ namespace Game
|
||||
pet.SetGroupUpdateFlag(GroupUpdatePetFlags.Name);
|
||||
pet.RemovePetFlag(UnitPetFlags.CanBeRenamed);
|
||||
|
||||
petStable.CurrentPet.Name = name;
|
||||
petStable.CurrentPet.WasRenamed = true;
|
||||
petStable.GetCurrentPet().Name = name;
|
||||
petStable.GetCurrentPet().WasRenamed = true;
|
||||
|
||||
PreparedStatement stmt;
|
||||
SQLTransaction trans = new();
|
||||
|
||||
@@ -292,6 +292,22 @@ namespace Game.Networking.Packets
|
||||
public ObjectGuid StableMaster;
|
||||
}
|
||||
|
||||
class SetPetSlot : ClientPacket
|
||||
{
|
||||
public SetPetSlot(WorldPacket packet) : base(packet) { }
|
||||
|
||||
public override void Read()
|
||||
{
|
||||
PetNumber = _worldPacket.ReadUInt32();
|
||||
DestSlot = _worldPacket.ReadUInt8();
|
||||
StableMaster = _worldPacket.ReadPackedGuid();
|
||||
}
|
||||
|
||||
public ObjectGuid StableMaster;
|
||||
public uint PetNumber;
|
||||
public byte DestSlot;
|
||||
}
|
||||
|
||||
//Structs
|
||||
public struct TreasureItem
|
||||
{
|
||||
|
||||
@@ -5148,13 +5148,20 @@ namespace Game.Spells
|
||||
}
|
||||
case SpellEffectName.ResurrectPet:
|
||||
{
|
||||
if (unitCaster == null)
|
||||
Player playerCaster = m_caster.ToPlayer();
|
||||
if (playerCaster == null || playerCaster.GetPetStable() == null)
|
||||
return SpellCastResult.BadTargets;
|
||||
|
||||
Creature pet = unitCaster.GetGuardianPet();
|
||||
Pet pet = playerCaster.GetPet();
|
||||
if (pet != null && pet.IsAlive())
|
||||
return SpellCastResult.AlreadyHaveSummon;
|
||||
|
||||
PetStable petStable = playerCaster.GetPetStable();
|
||||
var deadPetInfo = petStable.ActivePets.FirstOrDefault(petInfo => petInfo?.Health == 0);
|
||||
|
||||
if (deadPetInfo == null)
|
||||
return SpellCastResult.BadTargets;
|
||||
|
||||
break;
|
||||
}
|
||||
// This is generic summon effect
|
||||
@@ -5221,17 +5228,27 @@ namespace Game.Spells
|
||||
Player playerCaster = unitCaster.ToPlayer();
|
||||
if (playerCaster != null && playerCaster.GetPetStable() != null)
|
||||
{
|
||||
var info = Pet.GetLoadPetInfo(playerCaster.GetPetStable(), (uint)spellEffectInfo.MiscValue, 0, false);
|
||||
if (info.Item1 != null)
|
||||
PetSaveMode? petSlot = null;
|
||||
if (spellEffectInfo.MiscValue == 0)
|
||||
{
|
||||
if (info.Item1.Type == PetType.Hunter)
|
||||
petSlot = (PetSaveMode)spellEffectInfo.CalcValue();
|
||||
|
||||
// No pet can be summoned if any pet is dead
|
||||
foreach (var activePet in playerCaster.GetPetStable().ActivePets)
|
||||
{
|
||||
if (info.Item1.Health == 0)
|
||||
if (activePet?.Health == 0)
|
||||
{
|
||||
playerCaster.SendTameFailure(PetTameResult.Dead);
|
||||
return SpellCastResult.DontReport;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var info = Pet.GetLoadPetInfo(playerCaster.GetPetStable(), (uint)spellEffectInfo.MiscValue, 0, petSlot);
|
||||
if (info.Item1 != null)
|
||||
{
|
||||
if (info.Item1.Type == PetType.Hunter)
|
||||
{
|
||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(info.Item1.CreatureId);
|
||||
if (creatureInfo == null || !creatureInfo.IsTameable(playerCaster.CanTameExoticPets()))
|
||||
{
|
||||
@@ -5253,6 +5270,21 @@ namespace Game.Spells
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpellEffectName.DismissPet:
|
||||
{
|
||||
Player playerCaster = m_caster.ToPlayer();
|
||||
if (playerCaster == null)
|
||||
return SpellCastResult.BadTargets;
|
||||
|
||||
Pet pet = playerCaster.GetPet();
|
||||
if (pet == null)
|
||||
return SpellCastResult.NoPet;
|
||||
|
||||
if (!pet.IsAlive())
|
||||
return SpellCastResult.TargetsDead;
|
||||
|
||||
break;
|
||||
}
|
||||
case SpellEffectName.SummonPlayer:
|
||||
{
|
||||
if (!m_caster.IsTypeId(TypeId.Player))
|
||||
|
||||
@@ -2298,27 +2298,34 @@ namespace Game.Spells
|
||||
return;
|
||||
}
|
||||
|
||||
PetSaveMode? petSlot = null;
|
||||
if (petentry == 0)
|
||||
petSlot = (PetSaveMode)damage;
|
||||
|
||||
float x, y, z;
|
||||
owner.GetClosePoint(out x, out y, out z, owner.GetCombatReach());
|
||||
Pet pet = owner.SummonPet(petentry, x, y, z, owner.Orientation, PetType.Summon, 0);
|
||||
if (!pet)
|
||||
Pet pet = owner.SummonPet(petentry, petSlot, x, y, z, owner.Orientation, 0, out bool isNew);
|
||||
if (pet == null)
|
||||
return;
|
||||
|
||||
if (m_caster.IsTypeId(TypeId.Unit))
|
||||
if (isNew)
|
||||
{
|
||||
if (m_caster.ToCreature().IsTotem())
|
||||
pet.SetReactState(ReactStates.Aggressive);
|
||||
else
|
||||
pet.SetReactState(ReactStates.Defensive);
|
||||
if (m_caster.IsCreature())
|
||||
{
|
||||
if (m_caster.ToCreature().IsTotem())
|
||||
pet.SetReactState(ReactStates.Aggressive);
|
||||
else
|
||||
pet.SetReactState(ReactStates.Defensive);
|
||||
}
|
||||
|
||||
pet.SetCreatedBySpell(m_spellInfo.Id);
|
||||
|
||||
// generate new name for summon pet
|
||||
string new_name = Global.ObjectMgr.GeneratePetName(petentry);
|
||||
if (!string.IsNullOrEmpty(new_name))
|
||||
pet.SetName(new_name);
|
||||
}
|
||||
|
||||
pet.SetCreatedBySpell(m_spellInfo.Id);
|
||||
|
||||
// generate new name for summon pet
|
||||
string new_name = Global.ObjectMgr.GeneratePetName(petentry);
|
||||
if (!string.IsNullOrEmpty(new_name))
|
||||
pet.SetName(new_name);
|
||||
|
||||
ExecuteLogEffectSummonObject(effectInfo.Effect, pet);
|
||||
}
|
||||
|
||||
@@ -4012,42 +4019,68 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ResurrectPet)]
|
||||
void EffectSummonDeadPet()
|
||||
void EffectResurrectPet()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.Hit)
|
||||
return;
|
||||
|
||||
if (damage < 0)
|
||||
return;
|
||||
|
||||
Player player = m_caster.ToPlayer();
|
||||
if (player == null)
|
||||
return;
|
||||
|
||||
Pet pet = player.GetPet();
|
||||
if (pet != null && pet.IsAlive())
|
||||
return;
|
||||
// Maybe player dismissed dead pet or pet despawned?
|
||||
bool hadPet = true;
|
||||
|
||||
if (damage < 0)
|
||||
return;
|
||||
|
||||
float x, y, z;
|
||||
player.GetPosition(out x, out y, out z);
|
||||
if (pet == null)
|
||||
if (player.GetPet() == null)
|
||||
{
|
||||
player.SummonPet(0, x, y, z, player.Orientation, PetType.Summon, 0);
|
||||
pet = player.GetPet();
|
||||
PetStable petStable = player.GetPetStable();
|
||||
var deadPetIndex = Array.FindIndex(petStable.ActivePets, petInfo => petInfo?.Health == 0);
|
||||
|
||||
PetSaveMode slot = (PetSaveMode)deadPetIndex;
|
||||
|
||||
player.SummonPet(0, slot, 0f, 0f, 0f, 0f, 0);
|
||||
hadPet = false;
|
||||
}
|
||||
if (pet == null)
|
||||
|
||||
// TODO: Better to fail Hunter's "Revive Pet" at cast instead of here when casting ends
|
||||
Pet pet = player.GetPet(); // Attempt to get current pet
|
||||
if (pet == null || pet.IsAlive())
|
||||
return;
|
||||
|
||||
player.GetMap().CreatureRelocation(pet, x, y, z, player.GetOrientation());
|
||||
// If player did have a pet before reviving, teleport it
|
||||
if (hadPet)
|
||||
{
|
||||
// Reposition the pet's corpse before reviving so as not to grab aggro
|
||||
// We can use a different, more accurate version of GetClosePoint() since we have a pet
|
||||
// Will be used later to reposition the pet if we have one
|
||||
player.GetClosePoint(out float x, out float y, out float z, pet.GetCombatReach(), SharedConst.PetFollowDist, pet.GetFollowAngle());
|
||||
pet.NearTeleportTo(x, y, z, player.GetOrientation());
|
||||
pet.Relocate(x, y, z, player.GetOrientation()); // This is needed so SaveStayPosition() will get the proper coords.
|
||||
}
|
||||
|
||||
pet.SetDynamicFlags(UnitDynFlags.HideModel);
|
||||
pet.SetDynamicFlags(UnitDynFlags.None);
|
||||
pet.RemoveUnitFlag(UnitFlags.Skinnable);
|
||||
pet.SetDeathState(DeathState.Alive);
|
||||
pet.ClearUnitState(UnitState.AllErasable);
|
||||
pet.SetHealth(pet.CountPctFromMaxHealth(damage));
|
||||
|
||||
pet.InitializeAI();
|
||||
player.PetSpellInitialize();
|
||||
// Reset things for when the AI to takes over
|
||||
CharmInfo ci = pet.GetCharmInfo();
|
||||
if (ci != null)
|
||||
{
|
||||
// In case the pet was at stay, we don't want it running back
|
||||
ci.SaveStayPosition();
|
||||
ci.SetIsAtStay(ci.HasCommandState(CommandStates.Stay));
|
||||
|
||||
ci.SetIsFollowing(false);
|
||||
ci.SetIsCommandAttack(false);
|
||||
ci.SetIsCommandFollow(false);
|
||||
ci.SetIsReturning(false);
|
||||
}
|
||||
|
||||
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
||||
}
|
||||
|
||||
|
||||
@@ -405,6 +405,8 @@ namespace Scripts.Spells.Hunter
|
||||
[Script]
|
||||
class spell_hun_tame_beast : SpellScript
|
||||
{
|
||||
static uint[] CallPetSpellIds = { 883, 83242, 83243, 83244, 83245, };
|
||||
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
Player caster = GetCaster().ToPlayer();
|
||||
@@ -427,10 +429,18 @@ namespace Scripts.Spells.Hunter
|
||||
PetStable petStable = caster.GetPetStable();
|
||||
if (petStable != null)
|
||||
{
|
||||
if (petStable.CurrentPet != null)
|
||||
if (petStable.CurrentPetIndex.HasValue)
|
||||
return SpellCastResult.AlreadyHaveSummon;
|
||||
|
||||
if (petStable.GetUnslottedHunterPet() != null)
|
||||
var freeSlotIndex = Array.FindIndex(petStable.ActivePets, petInfo => petInfo == null);
|
||||
if (freeSlotIndex == -1)
|
||||
{
|
||||
caster.SendTameFailure(PetTameResult.TooMany);
|
||||
return SpellCastResult.DontReport;
|
||||
}
|
||||
|
||||
// Check for known Call Pet X spells
|
||||
if (!caster.HasSpell(CallPetSpellIds[freeSlotIndex]))
|
||||
{
|
||||
caster.SendTameFailure(PetTameResult.TooMany);
|
||||
return SpellCastResult.DontReport;
|
||||
|
||||
Reference in New Issue
Block a user