diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index bdaae385a..3ef216d4f 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -2198,4 +2198,24 @@ namespace Framework.Constants ContentTuningPvpLevelDamageScaling = 14, ContentTuningPvpItemLevelDamageScaling = 15, } + + public enum BattlePetSpeciesFlags : ushort + { + NoRename = 0x01, + WellKnown = 0x02, + NotAccountWide = 0x04, + Capturable = 0x08, + NotTradable = 0x10, + HideFromJournal = 0x20, + LegacyAccountUnique = 0x40, + CantBattle = 0x80, + HordeOnly = 0x100, + AllianceOnly = 0x200, + Boss = 0x400, + RandomDisplay = 0x800, + NoLicenseRequired = 0x1000, + AddsAllowedWithBoss = 0x2000, + HideUntilLearned = 0x4000, + MatchPlayerHighPetLevel = 0x8000 + } } diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index 52ce9bc6c..99cf8cfa3 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -51,7 +51,7 @@ namespace Framework.Constants /// public const int MaxBattlePetSpeciesId = 3159; public const int MaxPetBattleSlots = 3; - public const int MaxBattlePetsPerSpecies = 3; + public const int DefaultMaxBattlePetsPerSpecies = 3; public const int BattlePetCageItemId = 82800; public const int DefaultSummonBattlePetSpell = 118301; @@ -2823,4 +2823,18 @@ namespace Framework.Constants All = 0xFF } + + public enum BattlePetDbFlags : ushort + { + None = 0x00, + Favorite = 0x01, + Converted = 0x02, + Revoked = 0x04, + LockedForConvert = 0x08, + Ability0Selection = 0x10, + Ability1Selection = 0x20, + Ability2Selection = 0x40, + FanfareNeeded = 0x80, + DisplayOverridden = 0x100 + } } diff --git a/Source/Game/BattlePets/BattlePetManager.cs b/Source/Game/BattlePets/BattlePetManager.cs index 164184ac6..c7e2513b5 100644 --- a/Source/Game/BattlePets/BattlePetManager.cs +++ b/Source/Game/BattlePets/BattlePetManager.cs @@ -151,9 +151,9 @@ namespace Game.BattlePets BattlePetSpeciesRecord speciesEntry = CliDB.BattlePetSpeciesStorage.LookupByKey(species); if (speciesEntry != null) { - if (GetPetCount(species) >= SharedConst.MaxBattlePetsPerSpecies) + if (HasMaxPetCount(speciesEntry)) { - Log.outError(LogFilter.Misc, "Battlenet account with id {0} has more than 3 battle pets of species {1}", _owner.GetBattlenetAccountId(), species); + Log.outError(LogFilter.Misc, "Battlenet account with id {0} has more than maximum battle pets of species {1}", _owner.GetBattlenetAccountId(), species); continue; } @@ -277,6 +277,9 @@ namespace Game.BattlePets if (battlePetSpecies == null) // should never happen return; + if (!battlePetSpecies.GetFlags().HasFlag(BattlePetSpeciesFlags.WellKnown)) // Not learnable + return; + BattlePet pet = new(); pet.PacketInfo.Guid = ObjectGuid.Create(HighGuid.BattlePet, Global.ObjectMgr.GetGenerator(HighGuid.BattlePet).Generate()); pet.PacketInfo.Species = species; @@ -314,11 +317,38 @@ namespace Game.BattlePets _owner.GetPlayer().RemoveSpell(speciesEntry.SummonSpellID);*/ } + public void ClearFanfare(ObjectGuid guid) + { + BattlePet pet = GetPet(guid); + if (pet == null) + return; + + pet.PacketInfo.Flags &= (ushort)~BattlePetDbFlags.FanfareNeeded; + + if (pet.SaveInfo != BattlePetSaveInfo.New) + pet.SaveInfo = BattlePetSaveInfo.Changed; + } + + bool IsPetInSlot(ObjectGuid guid) + { + foreach (BattlePetSlot slot in _slots) + if (slot.Pet.Guid == guid) + return true; + + return false; + } + public byte GetPetCount(uint species) { return (byte)_pets.Values.Count(battlePet => battlePet.PacketInfo.Species == species && battlePet.SaveInfo != BattlePetSaveInfo.Removed); } + public bool HasMaxPetCount(BattlePetSpeciesRecord speciesEntry) + { + int maxPetsPerSpecies = speciesEntry.GetFlags().HasFlag(BattlePetSpeciesFlags.LegacyAccountUnique) ? 1 : SharedConst.DefaultMaxBattlePetsPerSpecies; + return GetPetCount(speciesEntry.Id) >= maxPetsPerSpecies; + } + public uint GetPetUniqueSpeciesCount() { HashSet speciesIds = new(); @@ -358,6 +388,17 @@ namespace Game.BattlePets if (pet == null) return; + var battlePetSpecies = CliDB.BattlePetSpeciesStorage.LookupByKey(pet.PacketInfo.Species); + if (battlePetSpecies != null) + if (battlePetSpecies.GetFlags().HasFlag(BattlePetSpeciesFlags.NotTradable)) + return; + + if (IsPetInSlot(guid)) + return; + + if (pet.PacketInfo.Health < pet.PacketInfo.MaxHealth) + return; + List dest = new(); if (_owner.GetPlayer().CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, SharedConst.BattlePetCageItemId, 1) != InventoryResult.Ok) @@ -372,7 +413,6 @@ namespace Game.BattlePets item.SetModifier(ItemModifier.BattlePetLevel, pet.PacketInfo.Level); item.SetModifier(ItemModifier.BattlePetDisplayId, pet.PacketInfo.CreatureID); - // FIXME: "You create: ." - item name missing in chat _owner.GetPlayer().SendNewItem(item, 1, true, false); RemovePet(guid); diff --git a/Source/Game/DataStorage/Structs/B_Records.cs b/Source/Game/DataStorage/Structs/B_Records.cs index 30883d46a..97a1797ed 100644 --- a/Source/Game/DataStorage/Structs/B_Records.cs +++ b/Source/Game/DataStorage/Structs/B_Records.cs @@ -73,7 +73,9 @@ namespace Game.DataStorage public int CardUIModelSceneID; public int LoadoutUIModelSceneID; public int CovenantID; - } + + public BattlePetSpeciesFlags GetFlags() { return (BattlePetSpeciesFlags)Flags; } +} public sealed class BattlePetSpeciesStateRecord { diff --git a/Source/Game/Handlers/BattlePetHandler.cs b/Source/Game/Handlers/BattlePetHandler.cs index 540a899af..fa25cc600 100644 --- a/Source/Game/Handlers/BattlePetHandler.cs +++ b/Source/Game/Handlers/BattlePetHandler.cs @@ -77,6 +77,12 @@ namespace Game } } + [WorldPacketHandler(ClientOpcodes.BattlePetClearFanfare)] + void HandleBattlePetClearFanfare(BattlePetClearFanfare battlePetClearFanfare) + { + GetBattlePetMgr().ClearFanfare(battlePetClearFanfare.PetGuid); + } + [WorldPacketHandler(ClientOpcodes.CageBattlePet)] void HandleCageBattlePet(CageBattlePet cageBattlePet) { diff --git a/Source/Game/Networking/Packets/BattlePetPackets.cs b/Source/Game/Networking/Packets/BattlePetPackets.cs index e6eda0142..1d661baaf 100644 --- a/Source/Game/Networking/Packets/BattlePetPackets.cs +++ b/Source/Game/Networking/Packets/BattlePetPackets.cs @@ -172,6 +172,18 @@ namespace Game.Networking.Packets public FlagsControlType ControlType; } + class BattlePetClearFanfare : ClientPacket + { + public BattlePetClearFanfare(WorldPacket packet) : base(packet) { } + + public override void Read() + { + PetGuid = _worldPacket.ReadPackedGuid(); + } + + public ObjectGuid PetGuid; + } + class CageBattlePet : ClientPacket { public CageBattlePet(WorldPacket packet) : base(packet) { } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 198b2ba2c..cd153db0b 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5439,7 +5439,7 @@ namespace Game.Spells return; } - if (battlePetMgr.GetPetCount(speciesId) >= SharedConst.MaxBattlePetsPerSpecies) + if (battlePetMgr.HasMaxPetCount(speciesEntry)) { battlePetMgr.SendError(BattlePetError.CantHaveMorePetsOfThatType, creatureId); // or speciesEntry.CreatureID SendCastResult(SpellCastResult.CantAddBattlePet);