Core/Pets: Pet management refactoring
Port From (https://github.com/TrinityCore/TrinityCore/commit/ca92686b44cc8c53a8991bf02d6e8534797fc115)
This commit is contained in:
@@ -693,13 +693,7 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.DEL_CALENDAR_INVITE, "DELETE FROM calendar_invites WHERE InviteID = ?");
|
PrepareStatement(CharStatements.DEL_CALENDAR_INVITE, "DELETE FROM calendar_invites WHERE InviteID = ?");
|
||||||
|
|
||||||
// Pet
|
// Pet
|
||||||
PrepareStatement(CharStatements.SEL_PET_SLOTS, "SELECT owner, slot FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot");
|
PrepareStatement(CharStatements.SEL_CHAR_PET_IDS, "SELECT id FROM character_pet WHERE owner = ?");
|
||||||
PrepareStatement(CharStatements.SEL_PET_SLOTS_DETAIL, "SELECT owner, id, entry, level, name, modelid FROM character_pet WHERE owner = ? AND slot >= ? AND slot <= ? ORDER BY slot");
|
|
||||||
PrepareStatement(CharStatements.SEL_PET_ENTRY, "SELECT entry FROM character_pet WHERE owner = ? AND id = ? AND slot >= ? AND slot <= ?");
|
|
||||||
PrepareStatement(CharStatements.SEL_PET_SLOT_BY_ID, "SELECT slot, entry FROM character_pet WHERE owner = ? AND id = ?");
|
|
||||||
PrepareStatement(CharStatements.SEL_PET_SPELL_LIST, "SELECT DISTINCT pet_spell.spell FROM pet_spell, character_pet WHERE character_pet.owner = ? AND character_pet.id = pet_spell.guid AND character_pet.id <> ?");
|
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PET, "SELECT id FROM character_pet WHERE owner = ? AND id <> ?");
|
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PETS, "SELECT id FROM character_pet WHERE owner = ?");
|
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME_BY_OWNER, "DELETE FROM character_pet_declinedname WHERE owner = ?");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME, "DELETE FROM character_pet_declinedname WHERE id = ?");
|
||||||
PrepareStatement(CharStatements.INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
PrepareStatement(CharStatements.INS_CHAR_PET_DECLINEDNAME, "INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||||
@@ -722,14 +716,9 @@ namespace Framework.Database
|
|||||||
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
PrepareStatement(CharStatements.INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " +
|
PrepareStatement(CharStatements.INS_PET_AURA_EFFECT, "INSERT INTO pet_aura_effect (guid, casterGuid, spell, effectMask, effectIndex, amount, baseAmount) " +
|
||||||
"VALUES (?, ?, ?, ?, ?, ?, ?)");
|
"VALUES (?, ?, ?, ?, ?, ?, ?)");
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND id = ?");
|
PrepareStatement(CharStatements.SEL_CHAR_PETS, "SELECT id, entry, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND entry = ? AND (slot = ? OR slot > ?)");
|
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PET_BY_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?) ");
|
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY_AND_SLOT, "SELECT id, entry, owner, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ? AND slot = ?");
|
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?");
|
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_OWNER, "DELETE FROM character_pet WHERE owner = ?");
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?");
|
PrepareStatement(CharStatements.UPD_CHAR_PET_NAME, "UPDATE character_pet SET name = ?, renamed = 1 WHERE owner = ? AND id = ?");
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ? AND id <> ?");
|
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_SLOT, "UPDATE character_pet SET slot = ? WHERE owner = ? AND slot = ?");
|
|
||||||
PrepareStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? 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_ID, "DELETE FROM character_pet WHERE id = ?");
|
||||||
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)");
|
PrepareStatement(CharStatements.DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)");
|
||||||
@@ -1356,23 +1345,12 @@ namespace Framework.Database
|
|||||||
DEL_PET_SPELLS,
|
DEL_PET_SPELLS,
|
||||||
DEL_CHAR_PET_BY_OWNER,
|
DEL_CHAR_PET_BY_OWNER,
|
||||||
DEL_CHAR_PET_DECLINEDNAME_BY_OWNER,
|
DEL_CHAR_PET_DECLINEDNAME_BY_OWNER,
|
||||||
SEL_CHAR_PET_BY_ENTRY_AND_SLOT,
|
SEL_CHAR_PET_IDS,
|
||||||
SEL_PET_SLOTS,
|
|
||||||
SEL_PET_SLOTS_DETAIL,
|
|
||||||
SEL_PET_ENTRY,
|
|
||||||
SEL_PET_SLOT_BY_ID,
|
|
||||||
SEL_PET_SPELL_LIST,
|
|
||||||
SEL_CHAR_PET,
|
|
||||||
SEL_CHAR_PETS,
|
SEL_CHAR_PETS,
|
||||||
INS_CHAR_PET,
|
INS_CHAR_PET,
|
||||||
SEL_CHAR_PET_BY_ENTRY,
|
|
||||||
SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2,
|
|
||||||
SEL_CHAR_PET_BY_SLOT,
|
|
||||||
DEL_CHAR_PET_DECLINEDNAME,
|
DEL_CHAR_PET_DECLINEDNAME,
|
||||||
INS_CHAR_PET_DECLINEDNAME,
|
INS_CHAR_PET_DECLINEDNAME,
|
||||||
UPD_CHAR_PET_NAME,
|
UPD_CHAR_PET_NAME,
|
||||||
UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID,
|
|
||||||
UPD_CHAR_PET_SLOT_BY_SLOT,
|
|
||||||
UPD_CHAR_PET_SLOT_BY_ID,
|
UPD_CHAR_PET_SLOT_BY_ID,
|
||||||
DEL_CHAR_PET_BY_ID,
|
DEL_CHAR_PET_BY_ID,
|
||||||
DEL_CHAR_PET_BY_SLOT,
|
DEL_CHAR_PET_BY_SLOT,
|
||||||
|
|||||||
@@ -52,41 +52,23 @@ namespace Game.Chat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Everything looks OK, create new pet
|
// Everything looks OK, create new pet
|
||||||
Pet pet = new(player, PetType.Hunter);
|
Pet pet = player.CreateTamedPetFrom(creatureTarget);
|
||||||
if (!pet.CreateBaseAtCreature(creatureTarget))
|
|
||||||
{
|
|
||||||
handler.SendSysMessage("Error 1");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
creatureTarget.SetDeathState(DeathState.JustDied);
|
// "kill" original creature
|
||||||
creatureTarget.RemoveCorpse();
|
creatureTarget.DespawnOrUnsummon();
|
||||||
creatureTarget.SetHealth(0); // just for nice GM-mode view
|
|
||||||
|
|
||||||
pet.SetCreatorGUID(player.GetGUID());
|
|
||||||
pet.SetFaction(player.GetFaction());
|
|
||||||
|
|
||||||
if (!pet.InitStatsForLevel(creatureTarget.GetLevel()))
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.ChatSystem, "InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
|
|
||||||
handler.SendSysMessage("Error 2");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare visual effect for levelup
|
// prepare visual effect for levelup
|
||||||
pet.SetLevel(creatureTarget.GetLevel() - 1);
|
pet.SetLevel(player.GetLevel() - 1);
|
||||||
|
|
||||||
pet.GetCharmInfo().SetPetNumber(Global.ObjectMgr.GeneratePetNumber(), true);
|
|
||||||
// this enables pet details window (Shift+P)
|
|
||||||
pet.InitPetCreateSpells();
|
|
||||||
pet.SetFullHealth();
|
|
||||||
|
|
||||||
|
// add to world
|
||||||
pet.GetMap().AddToMap(pet.ToCreature());
|
pet.GetMap().AddToMap(pet.ToCreature());
|
||||||
|
|
||||||
// visual effect for levelup
|
// visual effect for levelup
|
||||||
pet.SetLevel(creatureTarget.GetLevel());
|
pet.SetLevel(player.GetLevel());
|
||||||
|
|
||||||
|
// caster have pet now
|
||||||
player.SetMinion(pet, true);
|
player.SetMinion(pet, true);
|
||||||
|
|
||||||
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
pet.SavePetToDB(PetSaveMode.AsCurrent);
|
||||||
player.PetSpellInitialize();
|
player.PetSpellInitialize();
|
||||||
|
|
||||||
|
|||||||
+338
-258
@@ -96,89 +96,95 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadPetFromDB(Player owner, uint petEntry = 0, uint petnumber = 0, bool current = false)
|
public static Tuple<PetStable.PetInfo, PetSaveMode> GetLoadPetInfo(PetStable stable, uint petEntry, uint petnumber, bool current)
|
||||||
{
|
{
|
||||||
m_loading = true;
|
|
||||||
|
|
||||||
ulong ownerid = owner.GetGUID().GetCounter();
|
|
||||||
|
|
||||||
PreparedStatement stmt;
|
|
||||||
|
|
||||||
if (petnumber != 0)
|
if (petnumber != 0)
|
||||||
{
|
{
|
||||||
// Known petnumber entry
|
// Known petnumber entry
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY);
|
if (stable.CurrentPet != null && stable.CurrentPet.PetNumber == petnumber)
|
||||||
stmt.AddValue(0, ownerid);
|
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||||
stmt.AddValue(1, petnumber);
|
|
||||||
|
for (var stableSlot = 0; stableSlot < stable.StabledPets.Length; ++stableSlot)
|
||||||
|
if (stable.StabledPets[stableSlot] != null && stable.StabledPets[stableSlot].PetNumber == petnumber)
|
||||||
|
return Tuple.Create(stable.StabledPets[stableSlot], PetSaveMode.FirstStableSlot + stableSlot);
|
||||||
|
|
||||||
|
foreach (var pet in stable.UnslottedPets)
|
||||||
|
if (pet.CreatureId == petEntry)
|
||||||
|
return Tuple.Create(pet, PetSaveMode.NotInSlot);
|
||||||
}
|
}
|
||||||
else if (current)
|
else if (current)
|
||||||
{
|
{
|
||||||
// Current pet (slot 0)
|
// Current pet (slot 0)
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY_AND_SLOT);
|
if (stable.CurrentPet != null)
|
||||||
stmt.AddValue(0, ownerid);
|
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||||
stmt.AddValue(1, (byte)PetSaveMode.AsCurrent);
|
|
||||||
}
|
}
|
||||||
else if (petEntry != 0)
|
else if (petEntry != 0)
|
||||||
{
|
{
|
||||||
// known petEntry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
|
// known petEntry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PET_BY_ENTRY_AND_SLOT_2);
|
if (stable.CurrentPet != null && stable.CurrentPet.CreatureId == petEntry)
|
||||||
stmt.AddValue(0, ownerid);
|
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||||
stmt.AddValue(1, petEntry);
|
|
||||||
stmt.AddValue(2, (byte)PetSaveMode.AsCurrent);
|
foreach (var pet in stable.UnslottedPets)
|
||||||
stmt.AddValue(3, (byte)PetSaveMode.LastStableSlot);
|
if (pet.CreatureId == petEntry)
|
||||||
|
return Tuple.Create(pet, PetSaveMode.NotInSlot);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Any current or other non-stabled pet (for hunter "call pet")
|
// Any current or other non-stabled pet (for hunter "call pet")
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PET_BY_SLOT);
|
if (stable.CurrentPet != null)
|
||||||
stmt.AddValue(0, ownerid);
|
return Tuple.Create(stable.CurrentPet, PetSaveMode.AsCurrent);
|
||||||
stmt.AddValue(1, (byte)PetSaveMode.AsCurrent);
|
|
||||||
stmt.AddValue(2, (byte)PetSaveMode.LastStableSlot);
|
if (!stable.UnslottedPets.Empty())
|
||||||
|
return Tuple.Create(stable.UnslottedPets.First(), PetSaveMode.NotInSlot);
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLResult result = DB.Characters.Query(stmt);
|
return Tuple.Create<PetStable.PetInfo, PetSaveMode>(null, PetSaveMode.AsDeleted);
|
||||||
if (result.IsEmpty())
|
}
|
||||||
|
|
||||||
|
public bool LoadPetFromDB(Player owner, uint petEntry = 0, uint petnumber = 0, bool current = false)
|
||||||
|
{
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update for case of current pet "slot = 0"
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(petInfo.CreatedBySpellId, owner.GetMap().GetDifficultyID());
|
||||||
petEntry = result.Read<uint>(1);
|
|
||||||
if (petEntry == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint summonSpellId = result.Read<uint>(14);
|
|
||||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(summonSpellId, owner.GetMap().GetDifficultyID());
|
|
||||||
|
|
||||||
bool isTemporarySummon = spellInfo != null && spellInfo.GetDuration() > 0;
|
bool isTemporarySummon = spellInfo != null && spellInfo.GetDuration() > 0;
|
||||||
if (current && isTemporarySummon)
|
if (current && isTemporarySummon)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PetType petType = (PetType)result.Read<byte>(15);
|
if (petInfo.Type == PetType.Hunter)
|
||||||
if (petType == PetType.Hunter)
|
|
||||||
{
|
{
|
||||||
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(petEntry);
|
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(petInfo.CreatureId);
|
||||||
if (creatureInfo == null || !creatureInfo.IsTameable(owner.CanTameExoticPets()))
|
if (creatureInfo == null || !creatureInfo.IsTameable(owner.CanTameExoticPets()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint petId = result.Read<uint>(0);
|
|
||||||
if (current && owner.IsPetNeedBeTemporaryUnsummoned())
|
if (current && owner.IsPetNeedBeTemporaryUnsummoned())
|
||||||
{
|
{
|
||||||
owner.SetTemporaryUnsummonedPetNumber(petId);
|
owner.SetTemporaryUnsummonedPetNumber(petInfo.PetNumber);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map map = owner.GetMap();
|
Map map = owner.GetMap();
|
||||||
if (!Create(map.GenerateLowGuid(HighGuid.Pet), map, petEntry))
|
ulong guid = map.GenerateLowGuid(HighGuid.Pet);
|
||||||
|
|
||||||
|
if (!Create(guid, map, petInfo.CreatureId, petInfo.PetNumber))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PhasingHandler.InheritPhaseShift(this, owner);
|
PhasingHandler.InheritPhaseShift(this, owner);
|
||||||
|
|
||||||
SetPetType(petType);
|
SetPetType(petInfo.Type);
|
||||||
SetFaction(owner.GetFaction());
|
SetFaction(owner.GetFaction());
|
||||||
SetCreatedBySpell(summonSpellId);
|
SetCreatedBySpell(petInfo.CreatedBySpellId);
|
||||||
|
|
||||||
float px, py, pz;
|
float px, py, pz;
|
||||||
if (IsCritter())
|
if (IsCritter())
|
||||||
@@ -197,14 +203,14 @@ namespace Game.Entities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCharmInfo().SetPetNumber(petId, IsPermanentPetFor(owner));
|
GetCharmInfo().SetPetNumber(petInfo.PetNumber, IsPermanentPetFor(owner));
|
||||||
|
|
||||||
SetDisplayId(result.Read<uint>(3));
|
SetDisplayId(petInfo.DisplayId);
|
||||||
SetNativeDisplayId(result.Read<uint>(3));
|
SetNativeDisplayId(petInfo.DisplayId);
|
||||||
uint petlevel = result.Read<ushort>(4);
|
uint petlevel = petInfo.Level;
|
||||||
SetNpcFlags(NPCFlags.None);
|
SetNpcFlags(NPCFlags.None);
|
||||||
SetNpcFlags2(NPCFlags2.None);
|
SetNpcFlags2(NPCFlags2.None);
|
||||||
SetName(result.Read<string>(8));
|
SetName(petInfo.Name);
|
||||||
|
|
||||||
switch (GetPetType())
|
switch (GetPetType())
|
||||||
{
|
{
|
||||||
@@ -218,7 +224,7 @@ namespace Game.Entities
|
|||||||
SetClass(Class.Warrior);
|
SetClass(Class.Warrior);
|
||||||
SetGender(Gender.None);
|
SetGender(Gender.None);
|
||||||
SetSheath(SheathState.Melee);
|
SetSheath(SheathState.Melee);
|
||||||
SetPetFlags(result.Read<bool>(9) ? UnitPetFlags.CanBeAbandoned : UnitPetFlags.CanBeRenamed | UnitPetFlags.CanBeAbandoned);
|
SetPetFlags(petInfo.WasRenamed ? UnitPetFlags.CanBeAbandoned : UnitPetFlags.CanBeRenamed | UnitPetFlags.CanBeAbandoned);
|
||||||
SetUnitFlags(UnitFlags.PlayerControlled); // this enables popup window (pet abandon, cancel)
|
SetUnitFlags(UnitFlags.PlayerControlled); // this enables popup window (pet abandon, cancel)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -231,7 +237,7 @@ namespace Game.Entities
|
|||||||
SetCreatorGUID(owner.GetGUID());
|
SetCreatorGUID(owner.GetGUID());
|
||||||
|
|
||||||
InitStatsForLevel(petlevel);
|
InitStatsForLevel(petlevel);
|
||||||
SetPetExperience(result.Read<uint>(5));
|
SetPetExperience(petInfo.Experience);
|
||||||
|
|
||||||
SynchronizeLevelWithOwner();
|
SynchronizeLevelWithOwner();
|
||||||
|
|
||||||
@@ -244,15 +250,15 @@ namespace Game.Entities
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetReactState((ReactStates)result.Read<byte>(6));
|
SetReactState(petInfo.ReactState);
|
||||||
SetCanModifyStats(true);
|
SetCanModifyStats(true);
|
||||||
|
|
||||||
if (GetPetType() == PetType.Summon && !current) //all (?) summon pets come with full health when called, but not when they are current
|
if (GetPetType() == PetType.Summon && !current) //all (?) summon pets come with full health when called, but not when they are current
|
||||||
SetFullPower(PowerType.Mana);
|
SetFullPower(PowerType.Mana);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint savedhealth = result.Read<uint>(10);
|
uint savedhealth = petInfo.Health;
|
||||||
uint savedmana = result.Read<uint>(11);
|
uint savedmana = petInfo.Mana;
|
||||||
if (savedhealth == 0 && GetPetType() == PetType.Hunter)
|
if (savedhealth == 0 && GetPetType() == PetType.Hunter)
|
||||||
SetDeathState(DeathState.JustDied);
|
SetDeathState(DeathState.JustDied);
|
||||||
else
|
else
|
||||||
@@ -266,102 +272,108 @@ namespace Game.Entities
|
|||||||
// 0=current
|
// 0=current
|
||||||
// 1..MAX_PET_STABLES in stable slot
|
// 1..MAX_PET_STABLES in stable slot
|
||||||
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
// PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
|
||||||
if (result.Read<byte>(7) != 0)
|
if (slot == PetSaveMode.NotInSlot)
|
||||||
{
|
{
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_SLOT_EXCLUDE_ID);
|
var unslottedPetInfo = petStable.UnslottedPets.Find(unslottedPet => unslottedPet.PetNumber == petInfo.PetNumber);
|
||||||
stmt.AddValue(0, (byte)PetSaveMode.NotInSlot);
|
Cypher.Assert(petStable.CurrentPet == null);
|
||||||
stmt.AddValue(1, ownerid);
|
Cypher.Assert(unslottedPetInfo != null);
|
||||||
stmt.AddValue(2, (byte)PetSaveMode.AsCurrent);
|
|
||||||
stmt.AddValue(3, GetCharmInfo().GetPetNumber());
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_ID);
|
petStable.CurrentPet = unslottedPetInfo;
|
||||||
stmt.AddValue(0, (byte)PetSaveMode.AsCurrent);
|
petStable.UnslottedPets.Remove(unslottedPetInfo);
|
||||||
stmt.AddValue(1, ownerid);
|
|
||||||
stmt.AddValue(2, GetCharmInfo().GetPetNumber());
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
// Send fake summon spell cast - this is needed for correct cooldown application for spells
|
||||||
// Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
|
// Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
|
||||||
// @todo pets should be summoned from real cast instead of just faking it?
|
// @todo pets should be summoned from real cast instead of just faking it?
|
||||||
if (summonSpellId != 0)
|
if (petInfo.CreatedBySpellId != 0)
|
||||||
{
|
{
|
||||||
SpellGo spellGo = new();
|
SpellGo spellGo = new();
|
||||||
SpellCastData castData = spellGo.Cast;
|
SpellCastData castData = spellGo.Cast;
|
||||||
|
|
||||||
castData.CasterGUID = owner.GetGUID();
|
castData.CasterGUID = owner.GetGUID();
|
||||||
castData.CasterUnit = owner.GetGUID();
|
castData.CasterUnit = owner.GetGUID();
|
||||||
castData.CastID = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, owner.GetMapId(), summonSpellId, map.GenerateLowGuid(HighGuid.Cast));
|
castData.CastID = ObjectGuid.Create(HighGuid.Cast, SpellCastSource.Normal, owner.GetMapId(), petInfo.CreatedBySpellId, map.GenerateLowGuid(HighGuid.Cast));
|
||||||
castData.SpellID = (int)summonSpellId;
|
castData.SpellID = (int)petInfo.CreatedBySpellId;
|
||||||
castData.CastFlags = SpellCastFlags.Unk9;
|
castData.CastFlags = SpellCastFlags.Unk9;
|
||||||
castData.CastTime = Time.GetMSTime();
|
castData.CastTime = Time.GetMSTime();
|
||||||
owner.SendMessageToSet(spellGo, true);
|
owner.SendMessageToSet(spellGo, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
owner.SetMinion(this, true);
|
owner.SetMinion(this, true);
|
||||||
|
|
||||||
|
if (!isTemporarySummon)
|
||||||
|
GetCharmInfo().LoadPetActionBar(petInfo.ActionBar);
|
||||||
|
|
||||||
map.AddToMap(ToCreature());
|
map.AddToMap(ToCreature());
|
||||||
|
|
||||||
uint timediff = (uint)(GameTime.GetGameTime() - result.Read<uint>(13));
|
|
||||||
_LoadAuras(timediff);
|
|
||||||
|
|
||||||
// load action bar, if data broken will fill later by default spells.
|
|
||||||
if (!isTemporarySummon)
|
|
||||||
{
|
|
||||||
GetCharmInfo().LoadPetActionBar(result.Read<string>(12));
|
|
||||||
|
|
||||||
_LoadSpells();
|
|
||||||
_LoadSpellCooldowns();
|
|
||||||
LearnPetPassives();
|
|
||||||
InitLevelupSpellsForLevel();
|
|
||||||
if (map.IsBattleArena())
|
|
||||||
RemoveArenaAuras();
|
|
||||||
|
|
||||||
CastPetAuras(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.outDebug(LogFilter.Pet, "New Pet has guid {0}", GetGUID().ToString());
|
|
||||||
|
|
||||||
ushort specId = result.Read<ushort>(16);
|
|
||||||
ChrSpecializationRecord petSpec = CliDB.ChrSpecializationStorage.LookupByKey(specId);
|
|
||||||
if (petSpec != null)
|
|
||||||
specId = (ushort)Global.DB2Mgr.GetChrSpecializationByIndex(owner.HasAuraType(AuraType.OverridePetSpecs) ? Class.Max : 0, petSpec.OrderIndex).Id;
|
|
||||||
|
|
||||||
SetSpecialization(specId);
|
|
||||||
|
|
||||||
// The SetSpecialization function will run these functions if the pet's spec is not 0
|
|
||||||
if (GetSpecialization() == 0)
|
|
||||||
{
|
|
||||||
CleanupActionBar(); // remove unknown spells from action bar after load
|
|
||||||
owner.PetSpellInitialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
SetGroupUpdateFlag(GroupUpdatePetFlags.Full);
|
|
||||||
|
|
||||||
if (GetPetType() == PetType.Hunter)
|
|
||||||
{
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_DECLINED_NAME);
|
|
||||||
stmt.AddValue(0, owner.GetGUID().GetCounter());
|
|
||||||
stmt.AddValue(1, GetCharmInfo().GetPetNumber());
|
|
||||||
result = DB.Characters.Query(stmt);
|
|
||||||
|
|
||||||
if (!result.IsEmpty())
|
|
||||||
{
|
|
||||||
_declinedname = new DeclinedName();
|
|
||||||
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
|
|
||||||
{
|
|
||||||
_declinedname.name[i] = result.Read<string>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//set last used pet number (for use in BG's)
|
//set last used pet number (for use in BG's)
|
||||||
if (owner.IsTypeId(TypeId.Player) && IsControlled() && !IsTemporarySummoned() && (GetPetType() == PetType.Summon || GetPetType() == PetType.Hunter))
|
if (owner.IsPlayer() && IsControlled() && !IsTemporarySummoned() && (GetPetType() == PetType.Summon || GetPetType() == PetType.Hunter))
|
||||||
owner.ToPlayer().SetLastPetNumber(petId);
|
owner.ToPlayer().SetLastPetNumber(petInfo.PetNumber);
|
||||||
|
|
||||||
// must be after SetMinion (owner guid check)
|
owner.GetSession().AddQueryHolderCallback(DB.Characters.DelayQueryHolder(new PetLoadQueryHolder(ownerid, petInfo.PetNumber)))
|
||||||
LoadTemplateImmunities();
|
.AfterComplete(holder =>
|
||||||
m_loading = false;
|
{
|
||||||
|
var session = owner.GetSession();
|
||||||
|
var lastSaveTime = petInfo.LastSaveTime;
|
||||||
|
var specializationId = petInfo.SpecializationId;
|
||||||
|
if (session.GetPlayer() != owner || owner.GetPet() != this)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// passing previous checks ensure that 'this' is still valid
|
||||||
|
if (m_removed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint timediff = (uint)(GameTime.GetGameTime() - lastSaveTime);
|
||||||
|
_LoadAuras(holder.GetResult(PetLoginQueryLoad.Auras), holder.GetResult(PetLoginQueryLoad.AuraEffects), timediff);
|
||||||
|
|
||||||
|
// load action bar, if data broken will fill later by default spells.
|
||||||
|
if (!isTemporarySummon)
|
||||||
|
{
|
||||||
|
_LoadSpells(holder.GetResult(PetLoginQueryLoad.Spells));
|
||||||
|
GetSpellHistory().LoadFromDB<Pet>(holder.GetResult(PetLoginQueryLoad.Cooldowns), holder.GetResult(PetLoginQueryLoad.Charges));
|
||||||
|
LearnPetPassives();
|
||||||
|
InitLevelupSpellsForLevel();
|
||||||
|
if (GetMap().IsBattleArena())
|
||||||
|
RemoveArenaAuras();
|
||||||
|
|
||||||
|
CastPetAuras(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.outDebug(LogFilter.Pet, $"New Pet has {GetGUID()}");
|
||||||
|
|
||||||
|
ushort specId = specializationId;
|
||||||
|
var petSpec = CliDB.ChrSpecializationStorage.LookupByKey(specId);
|
||||||
|
if (petSpec != null)
|
||||||
|
specId = (ushort)Global.DB2Mgr.GetChrSpecializationByIndex(owner.HasAuraType(AuraType.OverridePetSpecs) ? Class.Max : 0, petSpec.OrderIndex).Id;
|
||||||
|
|
||||||
|
SetSpecialization(specId);
|
||||||
|
|
||||||
|
// The SetSpecialization function will run these functions if the pet's spec is not 0
|
||||||
|
if (GetSpecialization() == 0)
|
||||||
|
{
|
||||||
|
CleanupActionBar(); // remove unknown spells from action bar after load
|
||||||
|
|
||||||
|
owner.PetSpellInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SetGroupUpdateFlag(GroupUpdatePetFlags.Full);
|
||||||
|
|
||||||
|
if (GetPetType() == PetType.Hunter)
|
||||||
|
{
|
||||||
|
SQLResult result = holder.GetResult(PetLoginQueryLoad.DeclinedNames);
|
||||||
|
if (!result.IsEmpty())
|
||||||
|
{
|
||||||
|
_declinedname = new();
|
||||||
|
for (byte i = 0; i < SharedConst.MaxDeclinedNameCases; ++i)
|
||||||
|
_declinedname.name[i] = result.Read<string>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be after SetMinion (owner guid check)
|
||||||
|
LoadTemplateImmunities();
|
||||||
|
m_loading = false;
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -421,16 +433,6 @@ namespace Game.Entities
|
|||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
// prevent duplicate using slot (except PET_SAVE_NOT_IN_SLOT)
|
|
||||||
if (mode <= PetSaveMode.LastStableSlot)
|
|
||||||
{
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHAR_PET_SLOT_BY_SLOT);
|
|
||||||
stmt.AddValue(0, (byte)PetSaveMode.NotInSlot);
|
|
||||||
stmt.AddValue(1, ownerLowGUID);
|
|
||||||
stmt.AddValue(2, (byte)mode);
|
|
||||||
trans.Append(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
|
// 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))
|
if (GetPetType() == PetType.Hunter && (mode == PetSaveMode.AsCurrent || mode > PetSaveMode.LastStableSlot))
|
||||||
{
|
{
|
||||||
@@ -442,6 +444,11 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
// save pet
|
// save pet
|
||||||
|
string actionBar = GenerateActionBarData();
|
||||||
|
|
||||||
|
Cypher.Assert(owner.GetPetStable().CurrentPet != null && owner.GetPetStable().CurrentPet.PetNumber == GetCharmInfo().GetPetNumber());
|
||||||
|
FillPetInfo(owner.GetPetStable().CurrentPet);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PET);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_PET);
|
||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
||||||
stmt.AddValue(1, GetEntry());
|
stmt.AddValue(1, GetEntry());
|
||||||
@@ -455,11 +462,13 @@ namespace Game.Entities
|
|||||||
stmt.AddValue(9, HasPetFlag(UnitPetFlags.CanBeRenamed) ? 0 : 1);
|
stmt.AddValue(9, HasPetFlag(UnitPetFlags.CanBeRenamed) ? 0 : 1);
|
||||||
stmt.AddValue(10, curhealth);
|
stmt.AddValue(10, curhealth);
|
||||||
stmt.AddValue(11, curmana);
|
stmt.AddValue(11, curmana);
|
||||||
stmt.AddValue(12, GenerateActionBarData());
|
|
||||||
|
stmt.AddValue(12, actionBar);
|
||||||
|
|
||||||
stmt.AddValue(13, GameTime.GetGameTime());
|
stmt.AddValue(13, GameTime.GetGameTime());
|
||||||
stmt.AddValue(14, m_unitData.CreatedBySpell);
|
stmt.AddValue(14, m_unitData.CreatedBySpell);
|
||||||
stmt.AddValue(15, (byte)GetPetType());
|
stmt.AddValue(15, (byte)GetPetType());
|
||||||
stmt.AddValue(16, m_petSpecialization);
|
stmt.AddValue(16, GetSpecialization());
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
DB.Characters.CommitTransaction(trans);
|
DB.Characters.CommitTransaction(trans);
|
||||||
@@ -472,36 +481,55 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DeleteFromDB(uint guidlow)
|
public void FillPetInfo(PetStable.PetInfo petInfo)
|
||||||
|
{
|
||||||
|
petInfo.PetNumber = GetCharmInfo().GetPetNumber();
|
||||||
|
petInfo.CreatureId = GetEntry();
|
||||||
|
petInfo.DisplayId = GetNativeDisplayId();
|
||||||
|
petInfo.Level = (byte)GetLevel();
|
||||||
|
petInfo.Experience = m_unitData.PetExperience;
|
||||||
|
petInfo.ReactState = GetReactState();
|
||||||
|
petInfo.Name = GetName();
|
||||||
|
petInfo.WasRenamed = !HasPetFlag(UnitPetFlags.CanBeRenamed);
|
||||||
|
petInfo.Health = (uint)GetHealth();
|
||||||
|
petInfo.Mana = (uint)GetPower(PowerType.Mana);
|
||||||
|
petInfo.ActionBar = GenerateActionBarData();
|
||||||
|
petInfo.LastSaveTime = (uint)GameTime.GetGameTime();
|
||||||
|
petInfo.CreatedBySpellId = m_unitData.CreatedBySpell;
|
||||||
|
petInfo.Type = GetPetType();
|
||||||
|
petInfo.SpecializationId = GetSpecialization();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DeleteFromDB(uint petNumber)
|
||||||
{
|
{
|
||||||
SQLTransaction trans = new();
|
SQLTransaction trans = new();
|
||||||
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_BY_ID);
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_BY_ID);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_PET_DECLINEDNAME);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_AURA_EFFECTS);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_AURA_EFFECTS);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_AURAS);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_AURAS);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELLS);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELLS);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELL_COOLDOWNS);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELL_COOLDOWNS);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELL_CHARGES);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_PET_SPELL_CHARGES);
|
||||||
stmt.AddValue(0, guidlow);
|
stmt.AddValue(0, petNumber);
|
||||||
trans.Append(stmt);
|
trans.Append(stmt);
|
||||||
|
|
||||||
DB.Characters.CommitTransaction(trans);
|
DB.Characters.CommitTransaction(trans);
|
||||||
@@ -536,72 +564,73 @@ namespace Game.Entities
|
|||||||
switch (m_deathState)
|
switch (m_deathState)
|
||||||
{
|
{
|
||||||
case DeathState.Corpse:
|
case DeathState.Corpse:
|
||||||
|
{
|
||||||
|
if (GetPetType() != PetType.Hunter || m_corpseRemoveTime <= GameTime.GetGameTime())
|
||||||
{
|
{
|
||||||
if (GetPetType() != PetType.Hunter || m_corpseRemoveTime <= GameTime.GetGameTime())
|
Remove(PetSaveMode.NotInSlot); //hunters' pets never get removed because of death, NEVER!
|
||||||
{
|
return;
|
||||||
Remove(PetSaveMode.NotInSlot); //hunters' pets never get removed because of death, NEVER!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DeathState.Alive:
|
case DeathState.Alive:
|
||||||
|
{
|
||||||
|
// unsummon pet that lost owner
|
||||||
|
Player owner = GetOwner();
|
||||||
|
if (owner == null || (!IsWithinDistInMap(owner, GetMap().GetVisibilityRange()) && !IsPossessed()) || (IsControlled() && owner.GetPetGUID().IsEmpty()))
|
||||||
{
|
{
|
||||||
// unsummon pet that lost owner
|
Remove(PetSaveMode.NotInSlot, true);
|
||||||
Player owner = GetOwner();
|
return;
|
||||||
if (owner == null || (!IsWithinDistInMap(owner, GetMap().GetVisibilityRange()) && !IsPossessed()) || (IsControlled() && owner.GetPetGUID().IsEmpty()))
|
}
|
||||||
|
|
||||||
|
if (IsControlled())
|
||||||
|
{
|
||||||
|
if (owner.GetPetGUID() != GetGUID())
|
||||||
{
|
{
|
||||||
Remove(PetSaveMode.NotInSlot, true);
|
Log.outError(LogFilter.Pet, $"Pet {GetEntry()} is not pet of owner {GetOwner().GetName()}, removed");
|
||||||
|
Cypher.Assert(GetPetType() != PetType.Hunter, $"Unexpected unlinked pet found for owner {owner.GetSession().GetPlayerInfo()}");
|
||||||
|
Remove(PetSaveMode.NotInSlot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsControlled())
|
|
||||||
{
|
|
||||||
if (owner.GetPetGUID() != GetGUID())
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Pet, "Pet {0} is not pet of owner {1}, removed", GetEntry(), GetOwner().GetName());
|
|
||||||
Remove(GetPetType() == PetType.Hunter ? PetSaveMode.AsDeleted : PetSaveMode.NotInSlot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_duration > 0)
|
|
||||||
{
|
|
||||||
if (m_duration > diff)
|
|
||||||
m_duration -= (int)diff;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Remove(GetPetType() != PetType.Summon ? PetSaveMode.AsDeleted : PetSaveMode.NotInSlot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//regenerate focus for hunter pets or energy for deathknight's ghoul
|
|
||||||
if (m_focusRegenTimer != 0)
|
|
||||||
{
|
|
||||||
if (m_focusRegenTimer > diff)
|
|
||||||
m_focusRegenTimer -= diff;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (GetPowerType())
|
|
||||||
{
|
|
||||||
case PowerType.Focus:
|
|
||||||
Regenerate(PowerType.Focus);
|
|
||||||
m_focusRegenTimer += PetFocusRegenInterval - diff;
|
|
||||||
if (m_focusRegenTimer == 0)
|
|
||||||
++m_focusRegenTimer;
|
|
||||||
|
|
||||||
// Reset if large diff (lag) causes focus to get 'stuck'
|
|
||||||
if (m_focusRegenTimer > PetFocusRegenInterval)
|
|
||||||
m_focusRegenTimer = PetFocusRegenInterval;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
m_focusRegenTimer = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_duration > 0)
|
||||||
|
{
|
||||||
|
if (m_duration > diff)
|
||||||
|
m_duration -= (int)diff;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Remove(GetPetType() != PetType.Summon ? PetSaveMode.AsDeleted : PetSaveMode.NotInSlot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//regenerate focus for hunter pets or energy for deathknight's ghoul
|
||||||
|
if (m_focusRegenTimer != 0)
|
||||||
|
{
|
||||||
|
if (m_focusRegenTimer > diff)
|
||||||
|
m_focusRegenTimer -= diff;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (GetPowerType())
|
||||||
|
{
|
||||||
|
case PowerType.Focus:
|
||||||
|
Regenerate(PowerType.Focus);
|
||||||
|
m_focusRegenTimer += PetFocusRegenInterval - diff;
|
||||||
|
if (m_focusRegenTimer == 0)
|
||||||
|
++m_focusRegenTimer;
|
||||||
|
|
||||||
|
// Reset if large diff (lag) causes focus to get 'stuck'
|
||||||
|
if (m_focusRegenTimer > PetFocusRegenInterval)
|
||||||
|
m_focusRegenTimer = PetFocusRegenInterval;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_focusRegenTimer = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -714,7 +743,7 @@ namespace Game.Entities
|
|||||||
bool CreateBaseAtTamed(CreatureTemplate cinfo, Map map)
|
bool CreateBaseAtTamed(CreatureTemplate cinfo, Map map)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Pet, "CreateBaseForTamed");
|
Log.outDebug(LogFilter.Pet, "CreateBaseForTamed");
|
||||||
if (!Create(map.GenerateLowGuid(HighGuid.Pet), map, cinfo.Entry))
|
if (!Create(map.GenerateLowGuid(HighGuid.Pet), map, cinfo.Entry, Global.ObjectMgr.GeneratePetNumber()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SetPetNameTimestamp(0);
|
SetPetNameTimestamp(0);
|
||||||
@@ -753,24 +782,8 @@ namespace Game.Entities
|
|||||||
return diet.HasAnyFlag(FoodMask);
|
return diet.HasAnyFlag(FoodMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _LoadSpellCooldowns()
|
void _LoadSpells(SQLResult result)
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL_COOLDOWN);
|
|
||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
|
||||||
SQLResult cooldownsResult = DB.Characters.Query(stmt);
|
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL_CHARGES);
|
|
||||||
SQLResult chargesResult = DB.Characters.Query(stmt);
|
|
||||||
|
|
||||||
GetSpellHistory().LoadFromDB<Pet>(cooldownsResult, chargesResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _LoadSpells()
|
|
||||||
{
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL);
|
|
||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
|
||||||
SQLResult result = DB.Characters.Query(stmt);
|
|
||||||
|
|
||||||
if (!result.IsEmpty())
|
if (!result.IsEmpty())
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
@@ -827,58 +840,52 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _LoadAuras(uint timediff)
|
void _LoadAuras(SQLResult auraResult, SQLResult effectResult, uint timediff)
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Pet, "Loading auras for {0}", GetGUID().ToString());
|
Log.outDebug(LogFilter.Pet, "Loading auras for {0}", GetGUID().ToString());
|
||||||
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_AURA_EFFECT);
|
ObjectGuid casterGuid = default;
|
||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
ObjectGuid itemGuid = default;
|
||||||
|
|
||||||
ObjectGuid casterGuid = new();
|
|
||||||
ObjectGuid itemGuid = new();
|
|
||||||
Dictionary<AuraKey, AuraLoadEffectInfo> effectInfo = new();
|
Dictionary<AuraKey, AuraLoadEffectInfo> effectInfo = new();
|
||||||
SQLResult result = DB.Characters.Query(stmt);
|
|
||||||
if (!result.IsEmpty())
|
if (!effectResult.IsEmpty())
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uint effectIndex = result.Read<byte>(3);
|
uint effectIndex = effectResult.Read<byte>(3);
|
||||||
if (effectIndex < SpellConst.MaxEffects)
|
if (effectIndex < SpellConst.MaxEffects)
|
||||||
{
|
{
|
||||||
casterGuid.SetRawValue(result.Read<byte[]>(0));
|
casterGuid.SetRawValue(effectResult.Read<byte[]>(0));
|
||||||
if (casterGuid.IsEmpty())
|
if (casterGuid.IsEmpty())
|
||||||
casterGuid = GetGUID();
|
casterGuid = GetGUID();
|
||||||
|
|
||||||
AuraKey key = new(casterGuid, itemGuid, result.Read<uint>(1), result.Read<uint>(2));
|
AuraKey key = new(casterGuid, itemGuid, effectResult.Read<uint>(1), effectResult.Read<uint>(2));
|
||||||
if (!effectInfo.ContainsKey(key))
|
if (!effectInfo.ContainsKey(key))
|
||||||
effectInfo[key] = new AuraLoadEffectInfo();
|
effectInfo[key] = new AuraLoadEffectInfo();
|
||||||
|
|
||||||
var info = effectInfo[key];
|
var info = effectInfo[key];
|
||||||
info.Amounts[effectIndex] = result.Read<int>(4);
|
info.Amounts[effectIndex] = effectResult.Read<int>(4);
|
||||||
info.BaseAmounts[effectIndex] = result.Read<int>(5);
|
info.BaseAmounts[effectIndex] = effectResult.Read<int>(5);
|
||||||
}
|
}
|
||||||
} while (result.NextRow());
|
} while (effectResult.NextRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_AURA);
|
if (!auraResult.IsEmpty())
|
||||||
stmt.AddValue(0, GetCharmInfo().GetPetNumber());
|
|
||||||
result = DB.Characters.Query(stmt);
|
|
||||||
if (!result.IsEmpty())
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// NULL guid stored - pet is the caster of the spell - see Pet._SaveAuras
|
// NULL guid stored - pet is the caster of the spell - see Pet._SaveAuras
|
||||||
casterGuid.SetRawValue(result.Read<byte[]>(0));
|
casterGuid.SetRawValue(auraResult.Read<byte[]>(0));
|
||||||
if (casterGuid.IsEmpty())
|
if (casterGuid.IsEmpty())
|
||||||
casterGuid = GetGUID();
|
casterGuid = GetGUID();
|
||||||
|
|
||||||
AuraKey key = new(casterGuid, itemGuid, result.Read<uint>(1), result.Read<uint>(2));
|
AuraKey key = new(casterGuid, itemGuid, auraResult.Read<uint>(1), auraResult.Read<uint>(2));
|
||||||
uint recalculateMask = result.Read<uint>(3);
|
uint recalculateMask = auraResult.Read<uint>(3);
|
||||||
Difficulty difficulty = (Difficulty)result.Read<byte>(4);
|
Difficulty difficulty = (Difficulty)auraResult.Read<byte>(4);
|
||||||
byte stackCount = result.Read<byte>(5);
|
byte stackCount = auraResult.Read<byte>(5);
|
||||||
int maxDuration = result.Read<int>(6);
|
int maxDuration = auraResult.Read<int>(6);
|
||||||
int remainTime = result.Read<int>(7);
|
int remainTime = auraResult.Read<int>(7);
|
||||||
byte remainCharges = result.Read<byte>(8);
|
byte remainCharges = auraResult.Read<byte>(8);
|
||||||
|
|
||||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId, difficulty);
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(key.SpellId, difficulty);
|
||||||
if (spellInfo == null)
|
if (spellInfo == null)
|
||||||
@@ -931,7 +938,7 @@ namespace Game.Entities
|
|||||||
Log.outInfo(LogFilter.Pet, "Added aura spellid {0}, effectmask {1}", spellInfo.Id, key.EffectMask);
|
Log.outInfo(LogFilter.Pet, "Added aura spellid {0}, effectmask {1}", spellInfo.Id, key.EffectMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (result.NextRow());
|
while (auraResult.NextRow());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1152,9 +1159,9 @@ namespace Game.Entities
|
|||||||
PetDefaultSpellsEntry defSpells = Global.SpellMgr.GetPetDefaultSpellsEntry((int)GetEntry());
|
PetDefaultSpellsEntry defSpells = Global.SpellMgr.GetPetDefaultSpellsEntry((int)GetEntry());
|
||||||
if (defSpells != null)
|
if (defSpells != null)
|
||||||
{
|
{
|
||||||
for (byte i = 0; i < SharedConst.MaxCreatureSpellDataSlots; ++i)
|
foreach (uint spellId in defSpells.spellid)
|
||||||
{
|
{
|
||||||
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(defSpells.spellid[i], Difficulty.None);
|
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
|
||||||
if (spellInfo == null)
|
if (spellInfo == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1334,17 +1341,18 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Create(ulong guidlow, Map map, uint Entry)
|
public bool Create(ulong guidlow, Map map, uint entry, uint petNumber)
|
||||||
{
|
{
|
||||||
Cypher.Assert(map);
|
Cypher.Assert(map);
|
||||||
SetMap(map);
|
SetMap(map);
|
||||||
|
|
||||||
_Create(ObjectGuid.Create(HighGuid.Pet, map.GetId(), Entry, guidlow));
|
// TODO: counter should be constructed as (summon_count << 32) | petNumber
|
||||||
|
_Create(ObjectGuid.Create(HighGuid.Pet, map.GetId(), entry, guidlow));
|
||||||
|
|
||||||
m_spawnId = guidlow;
|
m_spawnId = guidlow;
|
||||||
m_originalEntry = Entry;
|
m_originalEntry = entry;
|
||||||
|
|
||||||
if (!InitEntry(Entry))
|
if (!InitEntry(entry))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Force regen flag for player pets, just like we do for players themselves
|
// Force regen flag for player pets, just like we do for players themselves
|
||||||
@@ -1379,8 +1387,8 @@ namespace Game.Entities
|
|||||||
// For general hunter pets skill 270
|
// For general hunter pets skill 270
|
||||||
// Passive 01~10, Passive 00 (20782, not used), Ferocious Inspiration (34457)
|
// Passive 01~10, Passive 00 (20782, not used), Ferocious Inspiration (34457)
|
||||||
// Scale 01~03 (34902~34904, bonus from owner, not used)
|
// Scale 01~03 (34902~34904, bonus from owner, not used)
|
||||||
foreach (var petSet in petStore)
|
foreach (var spellId in petStore)
|
||||||
AddSpell(petSet, ActiveStates.Decide, PetSpellState.New, PetSpellType.Family);
|
AddSpell(spellId, ActiveStates.Decide, PetSpellState.New, PetSpellType.Family);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1420,10 +1428,9 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// if the owner has that pet aura, return true
|
// if the owner has that pet aura, return true
|
||||||
foreach (var petAura in owner.m_petAuras)
|
foreach (var petAura in owner.m_petAuras)
|
||||||
{
|
|
||||||
if (petAura.GetAura(GetEntry()) == aura.GetId())
|
if (petAura.GetAura(GetEntry()) == aura.GetId())
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,7 +1483,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
return base.GetNativeObjectScale();
|
return base.GetNativeObjectScale();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SetDisplayId(uint modelId, float displayScale = 1f)
|
public override void SetDisplayId(uint modelId, float displayScale = 1f)
|
||||||
{
|
{
|
||||||
base.SetDisplayId(modelId, displayScale);
|
base.SetDisplayId(modelId, displayScale);
|
||||||
@@ -1619,9 +1626,9 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public override string GetDebugInfo()
|
public override string GetDebugInfo()
|
||||||
{
|
{
|
||||||
return $"{base.GetDebugInfo()}\nPetType: {GetPetType()}";
|
return $"{base.GetDebugInfo()}\nPetType: {GetPetType()} PetNumber: {GetCharmInfo().GetPetNumber()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeclinedName GetDeclinedNames() { return _declinedname; }
|
public DeclinedName GetDeclinedNames() { return _declinedname; }
|
||||||
|
|
||||||
public new Dictionary<uint, PetSpell> m_spells = new();
|
public new Dictionary<uint, PetSpell> m_spells = new();
|
||||||
@@ -1644,6 +1651,38 @@ namespace Game.Entities
|
|||||||
public PetSpellType type;
|
public PetSpellType type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PetStable
|
||||||
|
{
|
||||||
|
public class PetInfo
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public string ActionBar;
|
||||||
|
public uint PetNumber;
|
||||||
|
public uint CreatureId;
|
||||||
|
public uint DisplayId;
|
||||||
|
public uint Experience;
|
||||||
|
public uint Health;
|
||||||
|
public uint Mana;
|
||||||
|
public uint LastSaveTime;
|
||||||
|
public uint CreatedBySpellId;
|
||||||
|
public ushort SpecializationId;
|
||||||
|
public byte Level = 0;
|
||||||
|
public ReactStates ReactState;
|
||||||
|
public PetType Type = PetType.Max;
|
||||||
|
public bool WasRenamed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PetInfo CurrentPet; // PET_SAVE_AS_CURRENT
|
||||||
|
public PetInfo[] StabledPets = new PetInfo[SharedConst.MaxPetStables]; // PET_SAVE_FIRST_STABLE_SLOT - PET_SAVE_LAST_STABLE_SLOT
|
||||||
|
public uint MaxStabledPets = 0;
|
||||||
|
public List<PetInfo> UnslottedPets = new(); // PET_SAVE_NOT_IN_SLOT
|
||||||
|
|
||||||
|
public PetInfo GetUnslottedHunterPet()
|
||||||
|
{
|
||||||
|
return UnslottedPets.Count == 1 && UnslottedPets[0].Type == PetType.Hunter ? UnslottedPets[0] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum ActiveStates
|
public enum ActiveStates
|
||||||
{
|
{
|
||||||
Passive = 0x01, // 0x01 - passive
|
Passive = 0x01, // 0x01 - passive
|
||||||
@@ -1653,4 +1692,45 @@ namespace Game.Entities
|
|||||||
Reaction = 0x06, // 0x02 | 0x04
|
Reaction = 0x06, // 0x02 | 0x04
|
||||||
Decide = 0x00 // custom
|
Decide = 0x00 // custom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PetLoginQueryLoad
|
||||||
|
{
|
||||||
|
DeclinedNames,
|
||||||
|
Auras,
|
||||||
|
AuraEffects,
|
||||||
|
Spells,
|
||||||
|
Cooldowns,
|
||||||
|
Charges
|
||||||
|
}
|
||||||
|
|
||||||
|
class PetLoadQueryHolder : SQLQueryHolder<PetLoginQueryLoad>
|
||||||
|
{
|
||||||
|
public PetLoadQueryHolder(ulong ownerGuid, uint petNumber)
|
||||||
|
{
|
||||||
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_DECLINED_NAME);
|
||||||
|
stmt.AddValue(0, ownerGuid);
|
||||||
|
stmt.AddValue(1, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.DeclinedNames, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_AURA);
|
||||||
|
stmt.AddValue(0, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.Auras, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_AURA_EFFECT);
|
||||||
|
stmt.AddValue(0, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.AuraEffects, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL);
|
||||||
|
stmt.AddValue(0, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.Spells, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL_COOLDOWN);
|
||||||
|
stmt.AddValue(0, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.Cooldowns, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SPELL_CHARGES);
|
||||||
|
stmt.AddValue(0, petNumber);
|
||||||
|
SetQuery(PetLoginQueryLoad.Charges, stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1538,6 +1538,53 @@ namespace Game.Entities
|
|||||||
m_bgData.taxiPath[1] = result.Read<uint>(8);
|
m_bgData.taxiPath[1] = result.Read<uint>(8);
|
||||||
m_bgData.mountSpell = result.Read<uint>(9);
|
m_bgData.mountSpell = result.Read<uint>(9);
|
||||||
}
|
}
|
||||||
|
void _LoadPetStable(byte petStableSlots, SQLResult result)
|
||||||
|
{
|
||||||
|
if (petStableSlots == 0 && result.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_petStable = new();
|
||||||
|
m_petStable.MaxStabledPets = petStableSlots;
|
||||||
|
if (m_petStable.MaxStabledPets > SharedConst.MaxPetStables)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Player::LoadFromDB: Player ({GetGUID()}) can't have more stable slots than {SharedConst.MaxPetStables}, but has {m_petStable.MaxStabledPets} in DB");
|
||||||
|
m_petStable.MaxStabledPets = SharedConst.MaxPetStables;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||||
|
// SELECT id, entry, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ?
|
||||||
|
if (!result.IsEmpty())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PetStable.PetInfo petInfo = new();
|
||||||
|
petInfo.PetNumber = result.Read<uint>(0);
|
||||||
|
petInfo.CreatureId = result.Read<uint>(1);
|
||||||
|
petInfo.DisplayId = result.Read<uint>(2);
|
||||||
|
petInfo.Level = result.Read<byte>(3);
|
||||||
|
petInfo.Experience = result.Read<uint>(4);
|
||||||
|
petInfo.ReactState = (ReactStates)result.Read<byte>(5);
|
||||||
|
PetSaveMode slot = (PetSaveMode)result.Read<byte>(6);
|
||||||
|
petInfo.Name = result.Read<string>(7);
|
||||||
|
petInfo.WasRenamed = result.Read<bool>(8);
|
||||||
|
petInfo.Health = result.Read<uint>(9);
|
||||||
|
petInfo.Mana = result.Read<uint>(10);
|
||||||
|
petInfo.ActionBar = result.Read<string>(11);
|
||||||
|
petInfo.LastSaveTime = result.Read<uint>(12);
|
||||||
|
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;
|
||||||
|
else if (slot == PetSaveMode.NotInSlot)
|
||||||
|
m_petStable.UnslottedPets.Add(petInfo);
|
||||||
|
|
||||||
|
} while (result.NextRow());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void _SaveInventory(SQLTransaction trans)
|
void _SaveInventory(SQLTransaction trans)
|
||||||
{
|
{
|
||||||
@@ -3039,12 +3086,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
m_taxi.LoadTaxiMask(taximask); // must be before InitTaxiNodesForLevel
|
m_taxi.LoadTaxiMask(taximask); // must be before InitTaxiNodesForLevel
|
||||||
|
|
||||||
m_stableSlots = stable_slots;
|
_LoadPetStable(stable_slots, holder.GetResult(PlayerLoginQueryLoad.PetSlots));
|
||||||
if (m_stableSlots > 4)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Player, "Player can have not more {0} stable slots, but have in DB {1}", 4, m_stableSlots);
|
|
||||||
m_stableSlots = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Honor system
|
// Honor system
|
||||||
// Update Honor kills data
|
// Update Honor kills data
|
||||||
@@ -3411,7 +3453,7 @@ namespace Game.Entities
|
|||||||
stmt.AddValue(index++, GetTalentResetTime());
|
stmt.AddValue(index++, GetTalentResetTime());
|
||||||
stmt.AddValue(index++, GetPrimarySpecialization());
|
stmt.AddValue(index++, GetPrimarySpecialization());
|
||||||
stmt.AddValue(index++, (ushort)m_ExtraFlags);
|
stmt.AddValue(index++, (ushort)m_ExtraFlags);
|
||||||
stmt.AddValue(index++, m_stableSlots);
|
stmt.AddValue(index++, m_petStable != null ? m_petStable.MaxStabledPets : 0);
|
||||||
stmt.AddValue(index++, (ushort)atLoginFlags);
|
stmt.AddValue(index++, (ushort)atLoginFlags);
|
||||||
stmt.AddValue(index++, m_deathExpireTime);
|
stmt.AddValue(index++, m_deathExpireTime);
|
||||||
|
|
||||||
@@ -3551,7 +3593,7 @@ namespace Game.Entities
|
|||||||
stmt.AddValue(index++, GetNumRespecs());
|
stmt.AddValue(index++, GetNumRespecs());
|
||||||
stmt.AddValue(index++, GetPrimarySpecialization());
|
stmt.AddValue(index++, GetPrimarySpecialization());
|
||||||
stmt.AddValue(index++, (ushort)m_ExtraFlags);
|
stmt.AddValue(index++, (ushort)m_ExtraFlags);
|
||||||
stmt.AddValue(index++, m_stableSlots);
|
stmt.AddValue(index++, m_petStable != null ? m_petStable.MaxStabledPets : 0);
|
||||||
stmt.AddValue(index++, (ushort)atLoginFlags);
|
stmt.AddValue(index++, (ushort)atLoginFlags);
|
||||||
stmt.AddValue(index++, GetZoneId());
|
stmt.AddValue(index++, GetZoneId());
|
||||||
stmt.AddValue(index++, m_deathExpireTime);
|
stmt.AddValue(index++, m_deathExpireTime);
|
||||||
@@ -3937,7 +3979,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
// Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
|
// Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
|
||||||
// NOW we can finally clear other DB data related to character
|
// NOW we can finally clear other DB data related to character
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PETS);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PET_IDS);
|
||||||
stmt.AddValue(0, guid);
|
stmt.AddValue(0, guid);
|
||||||
SQLResult resultPets = DB.Characters.Query(stmt);
|
SQLResult resultPets = DB.Characters.Query(stmt);
|
||||||
|
|
||||||
|
|||||||
@@ -130,8 +130,8 @@ namespace Game.Entities
|
|||||||
public bool m_mailsUpdated;
|
public bool m_mailsUpdated;
|
||||||
|
|
||||||
//Pets
|
//Pets
|
||||||
|
PetStable m_petStable;
|
||||||
public List<PetAura> m_petAuras = new();
|
public List<PetAura> m_petAuras = new();
|
||||||
public uint m_stableSlots;
|
|
||||||
uint m_temporaryUnsummonedPetNumber;
|
uint m_temporaryUnsummonedPetNumber;
|
||||||
uint m_lastpetnumber;
|
uint m_lastpetnumber;
|
||||||
|
|
||||||
|
|||||||
@@ -884,7 +884,16 @@ namespace Game.Entities
|
|||||||
public void SetCommandStatusOff(PlayerCommandStates command) { _activeCheats &= ~command; }
|
public void SetCommandStatusOff(PlayerCommandStates command) { _activeCheats &= ~command; }
|
||||||
|
|
||||||
//Pet - Summons - Vehicles
|
//Pet - Summons - Vehicles
|
||||||
|
public PetStable GetPetStable() { return m_petStable; }
|
||||||
|
|
||||||
|
public PetStable GetOrInitPetStable()
|
||||||
|
{
|
||||||
|
if (m_petStable == null)
|
||||||
|
m_petStable = new();
|
||||||
|
|
||||||
|
return m_petStable;
|
||||||
|
}
|
||||||
|
|
||||||
// last used pet number (for BG's)
|
// last used pet number (for BG's)
|
||||||
public uint GetLastPetNumber() { return m_lastpetnumber; }
|
public uint GetLastPetNumber() { return m_lastpetnumber; }
|
||||||
public void SetLastPetNumber(uint petnumber) { m_lastpetnumber = petnumber; }
|
public void SetLastPetNumber(uint petnumber) { m_lastpetnumber = petnumber; }
|
||||||
@@ -892,7 +901,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
//fixme: the pet should still be loaded if the player is not in world
|
//fixme: the pet should still be loaded if the player is not in world
|
||||||
// just not added to the map
|
// just not added to the map
|
||||||
if (IsInWorld)
|
if (m_petStable != null && IsInWorld)
|
||||||
{
|
{
|
||||||
Pet pet = new(this);
|
Pet pet = new(this);
|
||||||
pet.LoadPetFromDB(this, 0, 0, true);
|
pet.LoadPetFromDB(this, 0, 0, true);
|
||||||
@@ -4702,18 +4711,13 @@ namespace Game.Entities
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pet SummonPet(uint entry, float x, float y, float z, float ang, PetType petType, uint duration, bool aliveOnly = false)
|
public Pet SummonPet(uint entry, float x, float y, float z, float ang, PetType petType, uint duration)
|
||||||
{
|
{
|
||||||
Pet pet = new(this, petType);
|
PetStable petStable = GetOrInitPetStable();
|
||||||
if (petType == PetType.Summon && pet.LoadPetFromDB(this, entry))
|
|
||||||
{
|
|
||||||
if (aliveOnly && !pet.IsAlive())
|
|
||||||
{
|
|
||||||
pet.DespawnOrUnsummon();
|
|
||||||
SendTameFailure(PetTameResult.Dead);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Pet pet = new(this, petType);
|
||||||
|
if (petType == PetType.Summon && pet.LoadPetFromDB(this, entry, 0, false))
|
||||||
|
{
|
||||||
if (duration > 0)
|
if (duration > 0)
|
||||||
pet.SetDuration(duration);
|
pet.SetDuration(duration);
|
||||||
|
|
||||||
@@ -4733,8 +4737,8 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map map = GetMap();
|
Map map = GetMap();
|
||||||
uint pet_number = Global.ObjectMgr.GeneratePetNumber();
|
uint petNumber = Global.ObjectMgr.GeneratePetNumber();
|
||||||
if (!pet.Create(map.GenerateLowGuid(HighGuid.Pet), map, entry))
|
if (!pet.Create(map.GenerateLowGuid(HighGuid.Pet), map, entry, petNumber))
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Server, "no such creature entry {0}", entry);
|
Log.outError(LogFilter.Server, "no such creature entry {0}", entry);
|
||||||
return null;
|
return null;
|
||||||
@@ -4750,11 +4754,15 @@ namespace Game.Entities
|
|||||||
|
|
||||||
SetMinion(pet, true);
|
SetMinion(pet, true);
|
||||||
|
|
||||||
|
Cypher.Assert(petStable.CurrentPet == null && (petType != PetType.Hunter || petStable.GetUnslottedHunterPet() == null));
|
||||||
|
petStable.CurrentPet = new();
|
||||||
|
pet.FillPetInfo(petStable.CurrentPet);
|
||||||
|
|
||||||
switch (petType)
|
switch (petType)
|
||||||
{
|
{
|
||||||
case PetType.Summon:
|
case PetType.Summon:
|
||||||
// this enables pet details window (Shift+P)
|
// this enables pet details window (Shift+P)
|
||||||
pet.GetCharmInfo().SetPetNumber(pet_number, true);
|
pet.GetCharmInfo().SetPetNumber(petNumber, true);
|
||||||
pet.SetClass(Class.Mage);
|
pet.SetClass(Class.Mage);
|
||||||
pet.SetPetExperience(0);
|
pet.SetPetExperience(0);
|
||||||
pet.SetPetNextLevelExperience(1000);
|
pet.SetPetNextLevelExperience(1000);
|
||||||
@@ -4848,6 +4856,17 @@ namespace Game.Entities
|
|||||||
// only if current pet in slot
|
// only if current pet in slot
|
||||||
pet.SavePetToDB(mode);
|
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;
|
||||||
|
// else if (stable slots) handled in opcode handlers due to required swaps
|
||||||
|
// else (current pet) doesnt need to do anything
|
||||||
|
|
||||||
SetMinion(pet, false);
|
SetMinion(pet, false);
|
||||||
|
|
||||||
pet.AddObjectToRemoveList();
|
pet.AddObjectToRemoveList();
|
||||||
@@ -4862,7 +4881,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendTameFailure(PetTameResult result)
|
public void SendTameFailure(PetTameResult result)
|
||||||
{
|
{
|
||||||
PetTameFailure petTameFailure = new();
|
PetTameFailure petTameFailure = new();
|
||||||
petTameFailure.Result = (byte)result;
|
petTameFailure.Result = (byte)result;
|
||||||
|
|||||||
@@ -730,7 +730,11 @@ namespace Game.Entities
|
|||||||
|
|
||||||
uint level = creatureTarget.GetLevelForTarget(this) + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget.GetLevelForTarget(this);
|
uint level = creatureTarget.GetLevelForTarget(this) + 5 < GetLevel() ? (GetLevel() - 5) : creatureTarget.GetLevelForTarget(this);
|
||||||
|
|
||||||
InitTamedPet(pet, level, spell_id);
|
if (!InitTamedPet(pet, level, spell_id))
|
||||||
|
{
|
||||||
|
pet.Dispose();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return pet;
|
return pet;
|
||||||
}
|
}
|
||||||
@@ -754,6 +758,11 @@ namespace Game.Entities
|
|||||||
|
|
||||||
bool InitTamedPet(Pet pet, uint level, uint spell_id)
|
bool InitTamedPet(Pet pet, uint level, uint spell_id)
|
||||||
{
|
{
|
||||||
|
Player player = ToPlayer();
|
||||||
|
PetStable petStable = player.GetOrInitPetStable();
|
||||||
|
if (petStable.CurrentPet != null || petStable.GetUnslottedHunterPet() != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
pet.SetCreatorGUID(GetGUID());
|
pet.SetCreatorGUID(GetGUID());
|
||||||
pet.SetFaction(GetFaction());
|
pet.SetFaction(GetFaction());
|
||||||
pet.SetCreatedBySpell(spell_id);
|
pet.SetCreatedBySpell(spell_id);
|
||||||
@@ -773,6 +782,9 @@ namespace Game.Entities
|
|||||||
// this enables pet details window (Shift+P)
|
// this enables pet details window (Shift+P)
|
||||||
pet.InitPetCreateSpells();
|
pet.InitPetCreateSpells();
|
||||||
pet.SetFullHealth();
|
pet.SetFullHealth();
|
||||||
|
|
||||||
|
petStable.CurrentPet = new();
|
||||||
|
pet.FillPetInfo(petStable.CurrentPet);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2820,6 +2820,10 @@ namespace Game
|
|||||||
stmt.AddValue(0, lowGuid);
|
stmt.AddValue(0, lowGuid);
|
||||||
SetQuery(PlayerLoginQueryLoad.CorpseLocation, stmt);
|
SetQuery(PlayerLoginQueryLoad.CorpseLocation, stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_PETS);
|
||||||
|
stmt.AddValue(0, lowGuid);
|
||||||
|
SetQuery(PlayerLoginQueryLoad.PetSlots, stmt);
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GARRISON);
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GARRISON);
|
||||||
stmt.AddValue(0, lowGuid);
|
stmt.AddValue(0, lowGuid);
|
||||||
SetQuery(PlayerLoginQueryLoad.Garrison, stmt);
|
SetQuery(PlayerLoginQueryLoad.Garrison, stmt);
|
||||||
@@ -2938,6 +2942,7 @@ namespace Game
|
|||||||
Currency,
|
Currency,
|
||||||
CufProfiles,
|
CufProfiles,
|
||||||
CorpseLocation,
|
CorpseLocation,
|
||||||
|
PetSlots,
|
||||||
Garrison,
|
Garrison,
|
||||||
GarrisonBlueprints,
|
GarrisonBlueprints,
|
||||||
GarrisonBuildings,
|
GarrisonBuildings,
|
||||||
|
|||||||
@@ -343,59 +343,68 @@ namespace Game
|
|||||||
|
|
||||||
public void SendStablePet(ObjectGuid guid)
|
public void SendStablePet(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_PET_SLOTS_DETAIL);
|
|
||||||
stmt.AddValue(0, guid.GetCounter());
|
|
||||||
stmt.AddValue(1, (byte)PetSaveMode.FirstStableSlot);
|
|
||||||
stmt.AddValue(2, (byte)PetSaveMode.LastStableSlot);
|
|
||||||
|
|
||||||
_queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendStablePetCallback(ObjectGuid guid, SQLResult result)
|
|
||||||
{
|
|
||||||
if (!GetPlayer())
|
|
||||||
return;
|
|
||||||
|
|
||||||
PetStableList packet = new();
|
PetStableList packet = new();
|
||||||
packet.StableMaster = guid;
|
packet.StableMaster = guid;
|
||||||
|
|
||||||
Pet pet = GetPlayer().GetPet();
|
PetStable petStable = GetPlayer().GetPetStable();
|
||||||
|
if (petStable == null)
|
||||||
|
{
|
||||||
|
SendPacket(packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint petSlot = 0;
|
uint petSlot = 0;
|
||||||
// not let move dead pet in slot
|
if (petStable.CurrentPet != null)
|
||||||
if (pet && pet.IsAlive() && pet.GetPetType() == PetType.Hunter)
|
|
||||||
{
|
{
|
||||||
PetStableInfo stableEntry;// = new PetStableInfo();
|
PetStable.PetInfo pet = petStable.CurrentPet;
|
||||||
|
|
||||||
|
PetStableInfo stableEntry;
|
||||||
stableEntry.PetSlot = petSlot;
|
stableEntry.PetSlot = petSlot;
|
||||||
stableEntry.PetNumber = pet.GetCharmInfo().GetPetNumber();
|
stableEntry.PetNumber = pet.PetNumber;
|
||||||
stableEntry.CreatureID = pet.GetEntry();
|
stableEntry.CreatureID = pet.CreatureId;
|
||||||
stableEntry.DisplayID = pet.GetDisplayId();
|
stableEntry.DisplayID = pet.DisplayId;
|
||||||
stableEntry.ExperienceLevel = pet.GetLevel();
|
stableEntry.ExperienceLevel = pet.Level;
|
||||||
stableEntry.PetFlags = PetStableinfo.Active;
|
stableEntry.PetFlags = PetStableinfo.Active;
|
||||||
stableEntry.PetName = pet.GetName();
|
stableEntry.PetName = pet.Name;
|
||||||
++petSlot;
|
++petSlot;
|
||||||
|
|
||||||
packet.Pets.Add(stableEntry);
|
packet.Pets.Add(stableEntry);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (!result.IsEmpty())
|
|
||||||
{
|
{
|
||||||
do
|
PetStable.PetInfo pet = petStable.GetUnslottedHunterPet();
|
||||||
|
if (pet != null)
|
||||||
{
|
{
|
||||||
PetStableInfo stableEntry;// = new PetStableInfo();
|
PetStableInfo stableEntry;
|
||||||
|
|
||||||
stableEntry.PetSlot = petSlot;
|
stableEntry.PetSlot = petSlot;
|
||||||
stableEntry.PetNumber = result.Read<uint>(1); // petnumber
|
stableEntry.PetNumber = pet.PetNumber;
|
||||||
stableEntry.CreatureID = result.Read<uint>(2); // creature entry
|
stableEntry.CreatureID = pet.CreatureId;
|
||||||
stableEntry.DisplayID = result.Read<uint>(5); // creature displayid
|
stableEntry.DisplayID = pet.DisplayId;
|
||||||
stableEntry.ExperienceLevel = result.Read<ushort>(3); // level
|
stableEntry.ExperienceLevel = pet.Level;
|
||||||
stableEntry.PetFlags = PetStableinfo.Inactive;
|
stableEntry.PetFlags = PetStableinfo.Active;
|
||||||
stableEntry.PetName = result.Read<string>(4); // Name
|
stableEntry.PetName = pet.Name;
|
||||||
|
|
||||||
|
++petSlot;
|
||||||
|
packet.Pets.Add(stableEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
++petSlot;
|
||||||
packet.Pets.Add(stableEntry);
|
packet.Pets.Add(stableEntry);
|
||||||
}
|
}
|
||||||
while (result.NextRow());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SendPacket(packet);
|
SendPacket(packet);
|
||||||
|
|||||||
@@ -536,10 +536,12 @@ namespace Game
|
|||||||
bool isdeclined = packet.RenameData.HasDeclinedNames;
|
bool isdeclined = packet.RenameData.HasDeclinedNames;
|
||||||
string name = packet.RenameData.NewName;
|
string name = packet.RenameData.NewName;
|
||||||
|
|
||||||
|
PetStable petStable = _player.GetPetStable();
|
||||||
Pet pet = ObjectAccessor.GetPet(GetPlayer(), petguid);
|
Pet pet = ObjectAccessor.GetPet(GetPlayer(), petguid);
|
||||||
// check it!
|
// check it!
|
||||||
if (!pet || !pet.IsPet() || pet.ToPet().GetPetType() != PetType.Hunter || !pet.HasPetFlag(UnitPetFlags.CanBeRenamed) ||
|
if (!pet || !pet.IsPet() || pet.ToPet().GetPetType() != PetType.Hunter || !pet.HasPetFlag(UnitPetFlags.CanBeRenamed) ||
|
||||||
pet.GetOwnerGUID() != GetPlayer().GetGUID() || pet.GetCharmInfo() == null)
|
pet.GetOwnerGUID() != _player.GetGUID() || pet.GetCharmInfo() == null ||
|
||||||
|
petStable == null || petStable.CurrentPet == null || petStable.CurrentPet.PetNumber != pet.GetCharmInfo().GetPetNumber())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PetNameInvalidReason res = ObjectManager.CheckPetName(name);
|
PetNameInvalidReason res = ObjectManager.CheckPetName(name);
|
||||||
@@ -559,6 +561,9 @@ namespace Game
|
|||||||
pet.SetGroupUpdateFlag(GroupUpdatePetFlags.Name);
|
pet.SetGroupUpdateFlag(GroupUpdatePetFlags.Name);
|
||||||
pet.RemovePetFlag(UnitPetFlags.CanBeRenamed);
|
pet.RemovePetFlag(UnitPetFlags.CanBeRenamed);
|
||||||
|
|
||||||
|
petStable.CurrentPet.Name = name;
|
||||||
|
petStable.CurrentPet.WasRenamed = true;
|
||||||
|
|
||||||
PreparedStatement stmt;
|
PreparedStatement stmt;
|
||||||
SQLTransaction trans = new();
|
SQLTransaction trans = new();
|
||||||
if (isdeclined)
|
if (isdeclined)
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ namespace Game
|
|||||||
return _transactionCallbacks.AddCallback(callback);
|
return _transactionCallbacks.AddCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
SQLQueryHolderCallback<R> AddQueryHolderCallback<R>(SQLQueryHolderCallback<R> callback)
|
public SQLQueryHolderCallback<R> AddQueryHolderCallback<R>(SQLQueryHolderCallback<R> callback)
|
||||||
{
|
{
|
||||||
return (SQLQueryHolderCallback<R>)_queryHolderProcessor.AddCallback(callback);
|
return (SQLQueryHolderCallback<R>)_queryHolderProcessor.AddCallback(callback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5217,6 +5217,35 @@ namespace Game.Spells
|
|||||||
|
|
||||||
if (!unitCaster.GetCharmedGUID().IsEmpty())
|
if (!unitCaster.GetCharmedGUID().IsEmpty())
|
||||||
return SpellCastResult.AlreadyHaveCharm;
|
return SpellCastResult.AlreadyHaveCharm;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
playerCaster.SendTameFailure(PetTameResult.NoPetAvailable);
|
||||||
|
return SpellCastResult.DontReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Item1.Type == PetType.Hunter && info.Item1.Health == 0)
|
||||||
|
{
|
||||||
|
playerCaster.SendTameFailure(PetTameResult.Dead);
|
||||||
|
return SpellCastResult.DontReport;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatureTemplate creatureInfo = Global.ObjectMgr.GetCreatureTemplate(info.Item1.CreatureId);
|
||||||
|
if (creatureInfo == null || !creatureInfo.IsTameable(playerCaster.CanTameExoticPets()))
|
||||||
|
{
|
||||||
|
// if problem in exotic pet
|
||||||
|
if (creatureInfo != null && creatureInfo.IsTameable(true))
|
||||||
|
playerCaster.SendTameFailure(PetTameResult.CantControlExotic);
|
||||||
|
else
|
||||||
|
playerCaster.SendTameFailure(PetTameResult.NoPetAvailable);
|
||||||
|
|
||||||
|
return SpellCastResult.DontReport;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SpellEffectName.SummonPlayer:
|
case SpellEffectName.SummonPlayer:
|
||||||
|
|||||||
@@ -2293,14 +2293,14 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (owner.IsTypeId(TypeId.Player))
|
if (owner.IsTypeId(TypeId.Player))
|
||||||
owner.ToPlayer().RemovePet(OldSummon, (OldSummon.GetPetType() == PetType.Hunter ? PetSaveMode.AsDeleted : PetSaveMode.NotInSlot), false);
|
owner.ToPlayer().RemovePet(OldSummon, PetSaveMode.NotInSlot, false);
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
owner.GetClosePoint(out x, out y, out z, owner.GetCombatReach());
|
owner.GetClosePoint(out x, out y, out z, owner.GetCombatReach());
|
||||||
Pet pet = owner.SummonPet(petentry, x, y, z, owner.Orientation, PetType.Summon, 0, true);
|
Pet pet = owner.SummonPet(petentry, x, y, z, owner.Orientation, PetType.Summon, 0);
|
||||||
if (!pet)
|
if (!pet)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -407,8 +407,8 @@ namespace Scripts.Spells.Hunter
|
|||||||
{
|
{
|
||||||
SpellCastResult CheckCast()
|
SpellCastResult CheckCast()
|
||||||
{
|
{
|
||||||
Unit caster = GetCaster();
|
Player caster = GetCaster().ToPlayer();
|
||||||
if (!caster.IsTypeId(TypeId.Player))
|
if (caster == null)
|
||||||
return SpellCastResult.DontReport;
|
return SpellCastResult.DontReport;
|
||||||
|
|
||||||
if (!GetExplTargetUnit())
|
if (!GetExplTargetUnit())
|
||||||
@@ -421,11 +421,21 @@ namespace Scripts.Spells.Hunter
|
|||||||
return SpellCastResult.Highlevel;
|
return SpellCastResult.Highlevel;
|
||||||
|
|
||||||
// use SMSG_PET_TAME_FAILURE?
|
// use SMSG_PET_TAME_FAILURE?
|
||||||
if (!target.GetCreatureTemplate().IsTameable(caster.ToPlayer().CanTameExoticPets()))
|
if (!target.GetCreatureTemplate().IsTameable(caster.CanTameExoticPets()))
|
||||||
return SpellCastResult.BadTargets;
|
return SpellCastResult.BadTargets;
|
||||||
|
|
||||||
if (!caster.GetPetGUID().IsEmpty())
|
PetStable petStable = caster.GetPetStable();
|
||||||
return SpellCastResult.AlreadyHaveSummon;
|
if (petStable != null)
|
||||||
|
{
|
||||||
|
if (petStable.CurrentPet != null)
|
||||||
|
return SpellCastResult.AlreadyHaveSummon;
|
||||||
|
|
||||||
|
if (petStable.GetUnslottedHunterPet() != null)
|
||||||
|
{
|
||||||
|
caster.SendTameFailure(PetTameResult.TooMany);
|
||||||
|
return SpellCastResult.DontReport;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!caster.GetCharmedGUID().IsEmpty())
|
if (!caster.GetCharmedGUID().IsEmpty())
|
||||||
return SpellCastResult.AlreadyHaveCharm;
|
return SpellCastResult.AlreadyHaveCharm;
|
||||||
|
|||||||
Reference in New Issue
Block a user