From 4b798e7cab5fc2b3099d17ceefbfa6b6ad17b7a4 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sat, 11 Feb 2023 23:28:57 -0500 Subject: [PATCH] Core/Players: Several currency fixes and improvements Port From (https://github.com/TrinityCore/TrinityCore/commit/03918978c166c9fb191117a0cae9ba1285bf0e37) --- Source/Framework/Constants/CliDBConst.cs | 46 ++ Source/Framework/Constants/ItemConst.cs | 11 +- Source/Framework/Constants/PlayerConst.cs | 108 ++++ Source/Framework/Constants/SharedConst.cs | 4 - .../Constants/Spells/SpellAuraConst.cs | 2 +- .../Database/Databases/CharacterDatabase.cs | 6 +- Source/Game/Achievements/CriteriaHandler.cs | 4 +- Source/Game/Chat/Commands/ModifyCommands.cs | 2 +- Source/Game/Conditions/ConditionManager.cs | 2 +- Source/Game/DataStorage/Structs/C_Records.cs | 54 ++ Source/Game/Entities/Player/Player.DB.cs | 38 +- Source/Game/Entities/Player/Player.Fields.cs | 4 +- Source/Game/Entities/Player/Player.Items.cs | 8 +- Source/Game/Entities/Player/Player.PvP.cs | 2 +- Source/Game/Entities/Player/Player.Quest.cs | 20 +- Source/Game/Entities/Player/Player.Talents.cs | 2 +- Source/Game/Entities/Player/Player.cs | 521 ++++++++++-------- Source/Game/Garrisons/Garrisons.cs | 4 +- Source/Game/Networking/Packets/MiscPackets.cs | 25 +- Source/Game/Reputation/ReputationManager.cs | 9 +- Source/Game/Server/WorldConfig.cs | 28 - Source/Game/Spells/Spell.cs | 2 +- Source/Game/Spells/SpellEffects.cs | 14 +- Source/Game/Spells/TraitManager.cs | 2 +- Source/WorldServer/WorldServer.conf.dist | 32 -- 25 files changed, 603 insertions(+), 347 deletions(-) diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index 15813813b..71db1c2e1 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -997,6 +997,52 @@ namespace Framework.Constants Max } + [Flags] + public enum CurrencyTypesFlags : uint + { + Tradable = 0x00000001, // NYI + AppearsInLootWindow = 0x00000002, // NYI + ComputedWeeklyMaximum = 0x00000004, // NYI + _100_Scaler = 0x00000008, + NoLowLevelDrop = 0x00000010, // NYI + IgnoreMaxQtyOnLoad = 0x00000020, + LogOnWorldChange = 0x00000040, // NYI + TrackQuantity = 0x00000080, + ResetTrackedQuantity = 0x00000100, // NYI + UpdateVersionIgnoreMax = 0x00000200, + SuppressChatMessageOnVersionChange = 0x00000400, + SingleDropInLoot = 0x00000800, // NYI + HasWeeklyCatchup = 0x00001000, // NYI + DoNotCompressChat = 0x00002000, // NYI + DoNotLogAcquisitionToBi = 0x00004000, // NYI + NoRaidDrop = 0x00008000, // NYI + NotPersistent = 0x00010000, // NYI + Deprecated = 0x00020000, // NYI + DynamicMaximum = 0x00040000, + SuppressChatMessages = 0x00080000, + DoNotToast = 0x00100000, // NYI + DestroyExtraOnLoot = 0x00200000, // NYI + DontShowTotalInTooltip = 0x00400000, // NYI + DontCoalesceInLootWindow = 0x00800000, // NYI + AccountWide = 0x01000000, // NYI + AllowOverflowMailer = 0x02000000, // NYI + HideAsReward = 0x04000000, // NYI + HasWarmodeBonus = 0x08000000, // NYI + IsAllianceOnly = 0x10000000, + IsHordeOnly = 0x20000000, + LimitWarmodeBonusOncePerTooltip = 0x40000000, // NYI + DeprecatedCurrencyFlag = 0x80000000 // this flag itself is deprecated, not currency that has it + } + + [Flags] + public enum CurrencyTypesFlagsB + { + UseTotalEarnedForEarned = 0x01, + ShowQuestXPGainInTooltip = 0x02, // NYI + NoNotificationMailOnOfflineProgress = 0x04, // NYI + BattlenetVirtualCurrency = 0x08 // NYI + } + [Flags] public enum BattlemasterListFlags : int { diff --git a/Source/Framework/Constants/ItemConst.cs b/Source/Framework/Constants/ItemConst.cs index 622ab370f..5f163b9e0 100644 --- a/Source/Framework/Constants/ItemConst.cs +++ b/Source/Framework/Constants/ItemConst.cs @@ -1282,20 +1282,13 @@ namespace Framework.Constants MawPower = 4 } - public enum CurrencyFlags - { - Tradeable = 0x01, - // ... - HighPrecision = 0x08, - // ... - } - public enum CurrencyTypes { JusticePoints = 395, ValorPoints = 396, ApexisCrystals = 823, - Azerite = 1553 + Azerite = 1553, + AncientMana = 1155 } public enum PlayerCurrencyState diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index c54ac3eb1..39115fcb9 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -60,6 +60,8 @@ namespace Framework.Constants public const uint WarmodeEnlistedSpellOutside = 269083; public const uint SpellExperienceEliminated = 206662; + + public const uint CurrencyMaxCapAncientMana = 2000; } public struct MoneyConstants @@ -818,4 +820,110 @@ namespace Framework.Constants RatedPvPReward = 17, CorruptedLoot = 19 } + + [Flags] + public enum CurrencyDbFlags + { + None = 0x00, + IgnoreMaxQtyOnload = 0x01, + Reuse1 = 0x02, + InBackpack = 0x04, + UnusedInUI = 0x08, + Reuse2 = 0x10, + + UnusedFlags = (IgnoreMaxQtyOnload | Reuse1 | Reuse2), + ClientFlags = (0x1F & ~UnusedFlags) + } + + public enum CurrencyDestroyReason + { + Cheat = 0, + Spell = 1, + VersionUpdate = 2, + QuestTurnin = 3, + Vendor = 4, + Trade = 5, + Capped = 6, + Garrison = 7, + DroppedToCorpse = 8, + BonusRoll = 9, + FactionConversion = 10, + FulfillCraftingOrder = 11, + Last = 12 + } + + public enum CurrencyGainSource + { + ConvertOldItem = 0, + ConvertOldPvPCurrency = 1, + ItemRefund = 2, + QuestReward = 3, + Cheat = 4, + Vendor = 5, + PvPKillCredit = 6, + PvPMetaCredit = 7, + PvPScriptedAward = 8, + Loot = 9, + UpdatingVersion = 10, + LFGReward = 11, + Trade = 12, + Spell = 13, + ItemDeletion = 14, + RatedBattleground = 15, + RandomBattleground = 16, + Arena = 17, + ExceededMaxQty = 18, + PvPCompletionBonus = 19, + Script = 20, + GuildBankWithdrawal = 21, + Pushloot = 22, + GarrisonBuilding = 23, + PvPDrop = 24, + GarrisonFollowerActivation = 25, + GarrisonBuildingRefund = 26, + GarrisonMissionReward = 27, + GarrisonResourceOverTime = 28, + QuestRewardIgnoreCaps = 29, + GarrisonTalent = 30, + GarrisonWorldQuestBonus = 31, + PvPHonorReward = 32, + BonusRoll = 33, + AzeriteRespec = 34, + WorldQuestReward = 35, + WorldQuestRewardIgnoreCaps = 36, + FactionConversion = 37, + DailyQuestReward = 38, + DailyQuestWarModeReward = 39, + WeeklyQuestReward = 40, + WeeklyQuestWarModeReward = 41, + AccountCopy = 42, + WeeklyRewardChest = 43, + GarrisonTalentTreeReset = 44, + DailyReset = 45, + AddConduitToCollection = 46, + Barbershop = 47, + ConvertItemsToCurrencyValue = 48, + PvPTeamContribution = 49, + Transmogrify = 50, + AuctionDeposit = 51, + PlayerTrait = 52, + PhBuffer_53 = 53, + PhBuffer_54 = 54, + RenownRepGain = 55, + CraftingOrder = 56, + CatalystBalancing = 57, + CatalystCraft = 58, + ProfessionInitialAward = 59, + PlayerTraitRefund = 60, + Last = 61 + } + + [Flags] + public enum CurrencyGainFlags + { + None = 0x00, + BonusAward = 0x01, + DroppedFromDeath = 0x02, + FromAccountServer = 0x04 + } } diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index b42c4b3c7..87b5fe7ca 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -1635,13 +1635,9 @@ namespace Framework.Constants CreatureFamilyFleeDelay, CreaturePickpocketRefill, CreatureStopForPlayer, - CurrencyMaxApexisCrystals, - CurrencyMaxJusticePoints, CurrencyResetDay, CurrencyResetHour, CurrencyResetInterval, - CurrencyStartApexisCrystals, - CurrencyStartJusticePoints, DailyQuestResetTimeHour, DbcEnforceItemAttributes, DeathBonesBgOrArena, diff --git a/Source/Framework/Constants/Spells/SpellAuraConst.cs b/Source/Framework/Constants/Spells/SpellAuraConst.cs index 667cbbfd0..69acacb20 100644 --- a/Source/Framework/Constants/Spells/SpellAuraConst.cs +++ b/Source/Framework/Constants/Spells/SpellAuraConst.cs @@ -358,7 +358,7 @@ namespace Framework.Constants ModMoneyGain = 348, // Modifies gold gains from source: [Misc = 0, Quests][Misc = 1, Loot] ModCurrencyGain = 349, Unk350 = 350, - ModCurrencyCategoryGainPct = 351, //NYI + ModCurrencyCategoryGainPct = 351, Unk352 = 352, ModCamouflage = 353, // Nyi ModHealingDonePctVersusTargetHealth = 354, // Restoration Shaman Mastery - Mod Healing Based On Target'S Health (Less = More Healing) diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index a0f5a598b..aba8ee7d0 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -333,9 +333,9 @@ namespace Framework.Database "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); // Currency - PrepareStatement(CharStatements.SEL_PLAYER_CURRENCY, "SELECT Currency, Quantity, WeeklyQuantity, TrackedQuantity, Flags FROM character_currency WHERE CharacterGuid = ?"); - PrepareStatement(CharStatements.UPD_PLAYER_CURRENCY, "UPDATE character_currency SET Quantity = ?, WeeklyQuantity = ?, TrackedQuantity = ?, Flags = ? WHERE CharacterGuid = ? AND Currency = ?"); - PrepareStatement(CharStatements.REP_PLAYER_CURRENCY, "REPLACE INTO character_currency (CharacterGuid, Currency, Quantity, WeeklyQuantity, TrackedQuantity, Flags) VALUES (?, ?, ?, ?, ?, ?)"); + PrepareStatement(CharStatements.SEL_PLAYER_CURRENCY, "SELECT Currency, Quantity, WeeklyQuantity, TrackedQuantity, IncreasedCapQuantity, EarnedQuantity, Flags FROM character_currency WHERE CharacterGuid = ?"); + PrepareStatement(CharStatements.UPD_PLAYER_CURRENCY, "UPDATE character_currency SET Quantity = ?, WeeklyQuantity = ?, TrackedQuantity = ?, IncreasedCapQuantity = ?, EarnedQuantity = ?, Flags = ? WHERE CharacterGuid = ? AND Currency = ?"); + PrepareStatement(CharStatements.REP_PLAYER_CURRENCY, "REPLACE INTO character_currency (CharacterGuid, Currency, Quantity, WeeklyQuantity, TrackedQuantity, IncreasedCapQuantity, EarnedQuantity, Flags) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_PLAYER_CURRENCY, "DELETE FROM character_currency WHERE CharacterGuid = ?"); // Account data diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index 62443a638..bde33929f 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -1904,7 +1904,7 @@ namespace Game.Achievements break; } case ModifierTreeType.PlayerHasTrackedCurrencyEqualOrGreaterThan: // 121 - if (referencePlayer.GetTrackedCurrencyCount(reqValue) < secondaryAsset) + if (referencePlayer.GetCurrencyTrackedQuantity(reqValue) < secondaryAsset) return false; break; case ModifierTreeType.PlayerMapInstanceType: // 122 @@ -2665,7 +2665,7 @@ namespace Game.Achievements return false; } case ModifierTreeType.PlayerHasCurrencyEqual: // 209 - if (referencePlayer.GetCurrency(reqValue) != secondaryAsset) + if (referencePlayer.GetCurrencyQuantity(reqValue) != secondaryAsset) return false; break; case ModifierTreeType.MinimumAverageItemHighWaterMarkForSpec: // 210 NYI diff --git a/Source/Game/Chat/Commands/ModifyCommands.cs b/Source/Game/Chat/Commands/ModifyCommands.cs index 319ab0648..2e9c4cbc4 100644 --- a/Source/Game/Chat/Commands/ModifyCommands.cs +++ b/Source/Game/Chat/Commands/ModifyCommands.cs @@ -655,7 +655,7 @@ namespace Game.Chat if (amount == 0) return false; - target.ModifyCurrency(currencyId, (int)amount, true, true); + target.ModifyCurrency(currencyId, (int)amount, CurrencyGainSource.Cheat, CurrencyDestroyReason.Cheat); return true; } diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index c5ae3b298..f3617a3aa 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -2258,7 +2258,7 @@ namespace Game for (var i = 0; i < condition.CurrencyID.Length; ++i) { if (condition.CurrencyID[i] != 0) - results[i] = player.GetCurrency(condition.CurrencyID[i]) >= condition.CurrencyCount[i]; + results[i] = player.GetCurrencyQuantity(condition.CurrencyID[i]) >= condition.CurrencyCount[i]; } if (!PlayerConditionLogic(condition.CurrencyLogic, results)) diff --git a/Source/Game/DataStorage/Structs/C_Records.cs b/Source/Game/DataStorage/Structs/C_Records.cs index 439279c89..c6a330dd8 100644 --- a/Source/Game/DataStorage/Structs/C_Records.cs +++ b/Source/Game/DataStorage/Structs/C_Records.cs @@ -538,6 +538,60 @@ namespace Game.DataStorage public uint RechargingAmountPerCycle; public uint RechargingCycleDurationMS; public int[] Flags = new int[2]; + + public CurrencyTypesFlags GetFlags() { return (CurrencyTypesFlags)Flags[0]; } + public CurrencyTypesFlagsB GetFlagsB() { return (CurrencyTypesFlagsB)Flags[1]; } + + // Helpers + public int GetScaler() + { + return GetFlags().HasFlag(CurrencyTypesFlags._100_Scaler) ? 100 : 1; + } + + public bool HasMaxEarnablePerWeek() + { + return MaxEarnablePerWeek != 0 || GetFlags().HasFlag(CurrencyTypesFlags.ComputedWeeklyMaximum); + } + + public bool HasMaxQuantity(bool onLoad = false, bool onUpdateVersion = false) + { + if (onLoad && GetFlags().HasFlag(CurrencyTypesFlags.IgnoreMaxQtyOnLoad)) + return false; + + if (onUpdateVersion && GetFlags().HasFlag(CurrencyTypesFlags.UpdateVersionIgnoreMax)) + return false; + + return MaxQty != 0 || MaxQtyWorldStateID != 0 || GetFlags().HasFlag(CurrencyTypesFlags.DynamicMaximum); + } + + public bool HasTotalEarned() + { + return GetFlagsB().HasFlag(CurrencyTypesFlagsB.UseTotalEarnedForEarned); + } + + public bool IsAlliance() + { + return GetFlags().HasFlag(CurrencyTypesFlags.IsAllianceOnly); + } + + public bool IsHorde() + { + return GetFlags().HasFlag(CurrencyTypesFlags.IsHordeOnly); + } + + public bool IsSuppressingChatLog(bool onUpdateVersion = false) + { + if ((onUpdateVersion && GetFlags().HasFlag(CurrencyTypesFlags.SuppressChatMessageOnVersionChange)) || + GetFlags().HasFlag(CurrencyTypesFlags.SuppressChatMessages)) + return true; + + return false; + } + + public bool IsTrackingQuantity() + { + return GetFlags().HasFlag(CurrencyTypesFlags.TrackQuantity); + } } public sealed class CurveRecord diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index db0b83240..9b0c2a594 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -653,7 +653,9 @@ namespace Game.Entities cur.Quantity = result.Read(1); cur.WeeklyQuantity = result.Read(2); cur.TrackedQuantity = result.Read(3); - cur.Flags = result.Read(4); + cur.IncreasedCapQuantity = result.Read(4); + cur.EarnedQuantity = result.Read(5); + cur.Flags = (CurrencyDbFlags)result.Read(6); _currencyStorage.Add(currencyID, cur); } while (result.NextRow()); @@ -1946,39 +1948,43 @@ namespace Game.Entities void _SaveCurrency(SQLTransaction trans) { PreparedStatement stmt; - foreach (var pair in _currencyStorage) + foreach (var (id, currency) in _currencyStorage) { - CurrencyTypesRecord entry = CliDB.CurrencyTypesStorage.LookupByKey(pair.Key); + CurrencyTypesRecord entry = CliDB.CurrencyTypesStorage.LookupByKey(id); if (entry == null) // should never happen continue; - switch (pair.Value.state) + switch (currency.state) { case PlayerCurrencyState.New: stmt = CharacterDatabase.GetPreparedStatement(CharStatements.REP_PLAYER_CURRENCY); stmt.AddValue(0, GetGUID().GetCounter()); - stmt.AddValue(1, pair.Key); - stmt.AddValue(2, pair.Value.Quantity); - stmt.AddValue(3, pair.Value.WeeklyQuantity); - stmt.AddValue(4, pair.Value.TrackedQuantity); - stmt.AddValue(5, pair.Value.Flags); + stmt.AddValue(1, id); + stmt.AddValue(2, currency.Quantity); + stmt.AddValue(3, currency.WeeklyQuantity); + stmt.AddValue(4, currency.TrackedQuantity); + stmt.AddValue(5, currency.IncreasedCapQuantity); + stmt.AddValue(6, currency.EarnedQuantity); + stmt.AddValue(7, (byte)currency.Flags); trans.Append(stmt); break; case PlayerCurrencyState.Changed: stmt = CharacterDatabase.GetPreparedStatement(CharStatements.UPD_PLAYER_CURRENCY); - stmt.AddValue(0, pair.Value.Quantity); - stmt.AddValue(1, pair.Value.WeeklyQuantity); - stmt.AddValue(2, pair.Value.TrackedQuantity); - stmt.AddValue(3, pair.Value.Flags); - stmt.AddValue(4, GetGUID().GetCounter()); - stmt.AddValue(5, pair.Key); + stmt.AddValue(0, currency.Quantity); + stmt.AddValue(1, currency.WeeklyQuantity); + stmt.AddValue(2, currency.TrackedQuantity); + stmt.AddValue(3, currency.IncreasedCapQuantity); + stmt.AddValue(4, currency.EarnedQuantity); + stmt.AddValue(5, (byte)currency.Flags); + stmt.AddValue(6, GetGUID().GetCounter()); + stmt.AddValue(7, id); trans.Append(stmt); break; default: break; } - pair.Value.state = PlayerCurrencyState.Unchanged; + currency.state = PlayerCurrencyState.Unchanged; } } diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 727933003..50d4d8b48 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -346,7 +346,9 @@ namespace Game.Entities public uint Quantity; public uint WeeklyQuantity; public uint TrackedQuantity; - public byte Flags; + public uint IncreasedCapQuantity; + public uint EarnedQuantity; + public CurrencyDbFlags Flags; } public class SpecializationInfo diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 3df8c5b75..ecc6113dc 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -122,7 +122,7 @@ namespace Game.Entities uint count = iece.CurrencyCount[i]; uint currencyid = iece.CurrencyID[i]; if (count != 0 && currencyid != 0) - ModifyCurrency(currencyid, (int)count, true, true); + AddCurrency(currencyid, count, CurrencyGainSource.ItemRefund); } // Grant back money @@ -2452,7 +2452,7 @@ namespace Game.Entities continue; if (iece.CurrencyID[i] != 0) - ModifyCurrency(iece.CurrencyID[i], -(int)(iece.CurrencyCount[i] * stacks), true, true); + RemoveCurrency(iece.CurrencyID[i], (int)(iece.CurrencyCount[i] * stacks), CurrencyDestroyReason.Vendor); } } @@ -3178,7 +3178,7 @@ namespace Game.Entities return false; } - ModifyCurrency(currency, (int)count, true, true); + AddCurrency(currency, count, CurrencyGainSource.Vendor); if (iece != null) { for (byte i = 0; i < ItemConst.MaxItemExtCostItems; ++i) @@ -3197,7 +3197,7 @@ namespace Game.Entities if (iece.Flags.HasAnyFlag((byte)((uint)ItemExtendedCostFlags.RequireSeasonEarned1 << i))) continue; - ModifyCurrency(iece.CurrencyID[i], -(int)(iece.CurrencyCount[i] * stacks), false, true); + RemoveCurrency(iece.CurrencyID[i], (int)(iece.CurrencyCount[i] * stacks), CurrencyDestroyReason.Vendor); } } diff --git a/Source/Game/Entities/Player/Player.PvP.cs b/Source/Game/Entities/Player/Player.PvP.cs index 4525f32b3..58771a3f2 100644 --- a/Source/Game/Entities/Player/Player.PvP.cs +++ b/Source/Game/Entities/Player/Player.PvP.cs @@ -235,7 +235,7 @@ namespace Game.Entities var rewardCurrencyTypes = Global.DB2Mgr.GetRewardPackCurrencyTypesByRewardID(rewardPackEntry.Id); foreach (RewardPackXCurrencyTypeRecord currency in rewardCurrencyTypes) - ModifyCurrency(currency.CurrencyTypeID, currency.Quantity); + AddCurrency(currency.CurrencyTypeID, (uint)currency.Quantity/* TODO: CurrencyGainSource */); var rewardPackXItems = Global.DB2Mgr.GetRewardPackItemsByRewardID(rewardPackEntry.Id); foreach (RewardPackXItemRecord rewardPackXItem in rewardPackXItems) diff --git a/Source/Game/Entities/Player/Player.Quest.cs b/Source/Game/Entities/Player/Player.Quest.cs index 0b79f8ab7..adff7e5c8 100644 --- a/Source/Game/Entities/Player/Player.Quest.cs +++ b/Source/Game/Entities/Player/Player.Quest.cs @@ -968,7 +968,7 @@ namespace Game.Entities DestroyItemCount((uint)obj.ObjectID, (uint)obj.Amount, true); break; case QuestObjectiveType.Currency: - ModifyCurrency((uint)obj.ObjectID, -obj.Amount, false, true); + RemoveCurrency((uint)obj.ObjectID, obj.Amount, CurrencyDestroyReason.QuestTurnin); break; } } @@ -1006,6 +1006,14 @@ namespace Game.Entities } } + CurrencyGainSource currencyGainSource = CurrencyGainSource.QuestReward; + if (quest.IsDaily()) + currencyGainSource = CurrencyGainSource.DailyQuestReward; + else if (quest.IsWeekly()) + currencyGainSource = CurrencyGainSource.WeeklyQuestReward; + else if (quest.IsWorldQuest()) + currencyGainSource = CurrencyGainSource.WorldQuestReward; + switch (rewardType) { case LootItemType.Item: @@ -1036,7 +1044,7 @@ namespace Game.Entities { for (uint i = 0; i < SharedConst.QuestRewardChoicesCount; ++i) if (quest.RewardChoiceItemId[i] != 0 && quest.RewardChoiceItemType[i] == LootItemType.Currency && quest.RewardChoiceItemId[i] == rewardId) - ModifyCurrency(quest.RewardChoiceItemId[i], (int)quest.RewardChoiceItemCount[i]); + AddCurrency(quest.RewardChoiceItemId[i], quest.RewardChoiceItemCount[i], currencyGainSource); } break; } @@ -1044,7 +1052,7 @@ namespace Game.Entities for (byte i = 0; i < SharedConst.QuestRewardCurrencyCount; ++i) { if (quest.RewardCurrencyId[i] != 0) - ModifyCurrency(quest.RewardCurrencyId[i], (int)quest.RewardCurrencyCount[i]); + AddCurrency(quest.RewardCurrencyId[i], quest.RewardCurrencyCount[i], currencyGainSource); } uint skill = quest.RewardSkillId; @@ -2139,7 +2147,7 @@ namespace Game.Entities else if (obj.Type == QuestObjectiveType.HaveCurrency) { uint reqCurrencyCount = (uint)obj.Amount; - uint curCurrencyCount = GetCurrency((uint)obj.ObjectID); + uint curCurrencyCount = GetCurrencyQuantity((uint)obj.ObjectID); SetQuestObjectiveData(obj, (int)Math.Min(reqCurrencyCount, curCurrencyCount)); } } @@ -2489,7 +2497,7 @@ namespace Game.Entities switch (objectiveType) { case QuestObjectiveType.Currency: - objectiveIsNowComplete = GetCurrency((uint)objectId) + addCount >= objective.Amount; + objectiveIsNowComplete = GetCurrencyQuantity((uint)objectId) + addCount >= objective.Amount; break; case QuestObjectiveType.LearnSpell: objectiveIsNowComplete = addCount != 0; @@ -2941,7 +2949,7 @@ namespace Game.Entities { SendQuestGiverStatusMultiple(m_clientGUIDs); } - + public void SendQuestGiverStatusMultiple(List guids) { QuestGiverStatusMultiple response = new(); diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index ac8e5e4f4..f3e8ff5d4 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -1043,7 +1043,7 @@ namespace Game.Entities ModifyMoney(-amount); break; case TraitCurrencyType.CurrencyTypesBased: - ModifyCurrency((uint)traitCurrency.CurrencyTypesID, -amount); + RemoveCurrency((uint)traitCurrency.CurrencyTypesID, amount /* TODO: CurrencyDestroyReason */); break; default: break; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 1adee5286..217d69f9c 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -243,8 +243,6 @@ namespace Game.Entities InitRunes(); SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.Coinage), (ulong)WorldConfig.GetIntValue(WorldCfg.StartPlayerMoney)); - SetCreateCurrency(CurrencyTypes.ApexisCrystals, WorldConfig.GetUIntValue(WorldCfg.CurrencyStartApexisCrystals)); - SetCreateCurrency(CurrencyTypes.JusticePoints, WorldConfig.GetUIntValue(WorldCfg.CurrencyStartJusticePoints)); // Played time m_Last_tick = GameTime.GetGameTime(); @@ -1083,23 +1081,223 @@ namespace Game.Entities SendPacket(petSpells); } - //Currency - Money - void SetCreateCurrency(CurrencyTypes id, uint count, bool printLog = true) + //Currency + void SetCreateCurrency(CurrencyTypes id, uint amount) { - var playerCurrency = _currencyStorage.LookupByKey(id); - if (playerCurrency == null) + SetCreateCurrency((uint)id, amount); + } + + void SetCreateCurrency(uint id, uint amount) + { + if (!_currencyStorage.ContainsKey(id)) { - PlayerCurrency cur = new(); - cur.state = PlayerCurrencyState.New; - cur.Quantity = count; - cur.WeeklyQuantity = 0; - cur.TrackedQuantity = 0; - cur.Flags = 0; - _currencyStorage[(uint)id] = cur; + PlayerCurrency playerCurrency = new(); + playerCurrency.state = PlayerCurrencyState.New; + playerCurrency.Quantity = amount; + _currencyStorage.Add(id, playerCurrency); } } - public uint GetCurrency(uint id) + public void ModifyCurrency(uint id, int amount, CurrencyGainSource gainSource = CurrencyGainSource.Cheat, CurrencyDestroyReason destroyReason = CurrencyDestroyReason.Cheat) + { + if (amount == 0) + return; + + CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(id); + Cypher.Assert(currency != null); + + // Check faction + if ((currency.IsAlliance() && GetTeam() != Team.Alliance) || + (currency.IsHorde() && GetTeam() != Team.Horde)) + return; + + // Check award condition + if (currency.AwardConditionID != 0) + { + PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(currency.AwardConditionID); + if (playerCondition != null && !ConditionManager.IsPlayerMeetingCondition(this, playerCondition)) + return; + } + + bool isGainOnRefund = false; + + if (gainSource == CurrencyGainSource.ItemRefund || + gainSource == CurrencyGainSource.GarrisonBuildingRefund || + gainSource == CurrencyGainSource.PlayerTraitRefund) + isGainOnRefund = true; + + if (amount > 0 && !isGainOnRefund && gainSource != CurrencyGainSource.Vendor) + { + amount = (int)(amount * GetTotalAuraMultiplierByMiscValue(AuraType.ModCurrencyGain, (int)id)); + amount = (int)(amount * GetTotalAuraMultiplierByMiscValue(AuraType.ModCurrencyCategoryGainPct, currency.CategoryID)); + } + + int scaler = currency.GetScaler(); + + // Currency that is immediately converted into reputation with that faction instead + FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(currency.FactionID); + if (factionEntry != null) + { + amount /= scaler; + GetReputationMgr().ModifyReputation(factionEntry, amount, false, true); + return; + } + + // Azerite + if (id == (uint)CurrencyTypes.Azerite) + { + if (amount > 0) + { + Item heartOfAzeroth = GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); + if (heartOfAzeroth != null) + heartOfAzeroth.ToAzeriteItem().GiveXP((ulong)amount); + } + return; + } + + var playerCurrency = _currencyStorage.LookupByKey(id); + if (playerCurrency == null) + { + playerCurrency = new(); + playerCurrency.state = PlayerCurrencyState.New; + _currencyStorage.Add(id, playerCurrency); + } + + // Weekly cap + uint weeklyCap = GetCurrencyWeeklyCap(currency); + if (weeklyCap != 0 && amount > 0 && (playerCurrency.WeeklyQuantity + amount) > weeklyCap) + if (!isGainOnRefund) // Ignore weekly cap for refund + amount = (int)(weeklyCap - playerCurrency.WeeklyQuantity); + + // Max cap + uint maxCap = GetCurrencyMaxQuantity(currency, false, gainSource == CurrencyGainSource.UpdatingVersion); + if (maxCap != 0 && amount > 0 && (playerCurrency.Quantity + amount) > maxCap) + amount = (int)(maxCap - playerCurrency.Quantity); + + // Underflow protection + if (amount < 0 && Math.Abs(amount) > playerCurrency.Quantity) + amount = (int)(playerCurrency.Quantity * -1); + + if (amount == 0) + return; + + if (playerCurrency.state != PlayerCurrencyState.New) + playerCurrency.state = PlayerCurrencyState.Changed; + + playerCurrency.Quantity += (uint)amount; + + if (amount > 0 && !isGainOnRefund) // Ignore total values update for refund + { + if (weeklyCap != 0) + playerCurrency.WeeklyQuantity += (uint)amount; + + if (currency.IsTrackingQuantity()) + playerCurrency.TrackedQuantity += (uint)amount; + + if (currency.HasTotalEarned()) + playerCurrency.EarnedQuantity += (uint)amount; + + UpdateCriteria(CriteriaType.CurrencyGained, id, (ulong)amount); + } + + CurrencyChanged(id, amount); + + SetCurrency packet = new(); + packet.Type = currency.Id; + packet.Quantity = (int)playerCurrency.Quantity; + packet.Flags = CurrencyGainFlags.None; // TODO: Check when flags are applied + + if ((playerCurrency.WeeklyQuantity / currency.GetScaler()) > 0) + packet.WeeklyQuantity = (int)playerCurrency.WeeklyQuantity; + + if (currency.HasMaxQuantity(false, gainSource == CurrencyGainSource.UpdatingVersion)) + packet.MaxQuantity = (int)GetCurrencyMaxQuantity(currency); + + if (currency.HasTotalEarned()) + packet.TotalEarned = (int)playerCurrency.EarnedQuantity; + + packet.SuppressChatLog = currency.IsSuppressingChatLog(gainSource == CurrencyGainSource.UpdatingVersion); + packet.QuantityChange = amount; + + if (amount > 0) + packet.QuantityGainSource = gainSource; + else + packet.QuantityLostSource = destroyReason; + + // TODO: FirstCraftOperationID, LastSpendTime & Toasts + SendPacket(packet); + } + + public void AddCurrency(uint id, uint amount, CurrencyGainSource gainSource = CurrencyGainSource.Cheat) + { + ModifyCurrency(id, (int)amount, gainSource); + } + + public void RemoveCurrency(uint id, int amount, CurrencyDestroyReason destroyReason = CurrencyDestroyReason.Cheat) + { + ModifyCurrency(id, -amount, default, destroyReason); + } + + public void IncreaseCurrencyCap(uint id, uint amount) + { + if (amount == 0) + return; + + CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(id); + Cypher.Assert(currency != null); + + // Check faction + if ((currency.IsAlliance() && GetTeam() != Team.Alliance) || + (currency.IsHorde() && GetTeam() != Team.Horde)) + return; + + // Check dynamic maximum flag + if (!currency.GetFlags().HasFlag(CurrencyTypesFlags.DynamicMaximum)) + return; + + // Ancient mana maximum cap + if (id == (uint)CurrencyTypes.AncientMana) + { + uint maxQuantity = GetCurrencyMaxQuantity(currency); + + if ((maxQuantity + amount) > PlayerConst.CurrencyMaxCapAncientMana) + amount = PlayerConst.CurrencyMaxCapAncientMana - maxQuantity; + } + + var playerCurrency = _currencyStorage.LookupByKey(id); + if (playerCurrency == null) + { + playerCurrency = new(); + playerCurrency.state = PlayerCurrencyState.New; + playerCurrency.IncreasedCapQuantity = amount; + _currencyStorage[id] = playerCurrency; + } + else + { + playerCurrency.IncreasedCapQuantity += amount; + } + + if (playerCurrency.state != PlayerCurrencyState.New) + playerCurrency.state = PlayerCurrencyState.Changed; + + SetCurrency packet = new(); + packet.Type = currency.Id; + packet.Quantity = (int)playerCurrency.Quantity; + packet.Flags = CurrencyGainFlags.None; + + if ((playerCurrency.WeeklyQuantity / currency.GetScaler()) > 0) + packet.WeeklyQuantity = (int)playerCurrency.WeeklyQuantity; + + if (currency.IsTrackingQuantity()) + packet.TrackedQuantity = (int)playerCurrency.TrackedQuantity; + + packet.MaxQuantity = (int)GetCurrencyMaxQuantity(currency); + packet.SuppressChatLog = currency.IsSuppressingChatLog(); + + SendPacket(packet); + } + + public uint GetCurrencyQuantity(uint id) { var playerCurrency = _currencyStorage.LookupByKey(id); if (playerCurrency == null) @@ -1108,169 +1306,7 @@ namespace Game.Entities return playerCurrency.Quantity; } - public void ModifyCurrency(uint id, int count, bool printLog = true, bool ignoreMultipliers = false) - { - if (count == 0) - return; - - CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(id); - Cypher.Assert(currency != null); - - if (!ignoreMultipliers) - count *= (int)GetTotalAuraMultiplierByMiscValue(AuraType.ModCurrencyGain, (int)id); - - // Currency that is immediately converted into reputation with that faction instead - FactionRecord factionEntry = CliDB.FactionStorage.LookupByKey(currency.FactionID); - if (factionEntry != null) - { - if (currency.Flags[0].HasAnyFlag((int)CurrencyFlags.HighPrecision)) - count /= 100; - GetReputationMgr().ModifyReputation(factionEntry, count, false, true); - return; - } - - if (id == (uint)CurrencyTypes.Azerite) - { - if (count > 0) - { - Item heartOfAzeroth = GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth, ItemSearchLocation.Everywhere); - if (heartOfAzeroth != null) - heartOfAzeroth.ToAzeriteItem().GiveXP((ulong)count); - } - return; - } - - uint oldTotalCount = 0; - uint oldWeekCount = 0; - uint oldTrackedCount = 0; - - var playerCurrency = _currencyStorage.LookupByKey(id); - if (playerCurrency == null) - { - PlayerCurrency cur = new(); - cur.state = PlayerCurrencyState.New; - cur.Quantity = 0; - cur.WeeklyQuantity = 0; - cur.TrackedQuantity = 0; - cur.Flags = 0; - _currencyStorage[id] = cur; - playerCurrency = _currencyStorage.LookupByKey(id); - } - else - { - oldTotalCount = playerCurrency.Quantity; - oldWeekCount = playerCurrency.WeeklyQuantity; - oldTrackedCount = playerCurrency.TrackedQuantity; - } - - // count can't be more then weekCap if used (weekCap > 0) - uint weekCap = GetCurrencyWeekCap(currency); - if (weekCap != 0 && count > weekCap) - count = (int)weekCap; - - // count can't be more then totalCap if used (totalCap > 0) - uint totalCap = GetCurrencyTotalCap(currency); - if (totalCap != 0 && count > totalCap) - count = (int)totalCap; - - int newTrackedCount = (int)(oldTrackedCount) + (count > 0 ? count : 0); - if (newTrackedCount < 0) - newTrackedCount = 0; - - int newTotalCount = (int)oldTotalCount + count; - if (newTotalCount < 0) - newTotalCount = 0; - - int newWeekCount = (int)oldWeekCount + (count > 0 ? count : 0); - if (newWeekCount < 0) - newWeekCount = 0; - - // if we get more then weekCap just set to limit - if (weekCap != 0 && weekCap < newWeekCount) - { - newWeekCount = (int)weekCap; - // weekCap - oldWeekCount always >= 0 as we set limit before! - newTotalCount = (int)(oldTotalCount + (weekCap - oldWeekCount)); - } - - // if we get more then totalCap set to maximum; - if (totalCap != 0 && totalCap < newTotalCount) - { - newTotalCount = (int)totalCap; - newWeekCount = (int)weekCap; - } - - if (newTotalCount != oldTotalCount) - { - if (playerCurrency.state != PlayerCurrencyState.New) - playerCurrency.state = PlayerCurrencyState.Changed; - - CurrencyChanged(id, count); - - playerCurrency.Quantity = (uint)newTotalCount; - playerCurrency.WeeklyQuantity = (uint)newWeekCount; - playerCurrency.TrackedQuantity = (uint)newTrackedCount; - - if (count > 0) - UpdateCriteria(CriteriaType.CurrencyGained, id, (uint)count); - - _currencyStorage[id] = playerCurrency; - - SetCurrency packet = new(); - packet.Type = id; - packet.Quantity = newTotalCount; - packet.SuppressChatLog = !printLog; - packet.WeeklyQuantity = newWeekCount; - packet.TrackedQuantity = newTrackedCount; - packet.Flags = playerCurrency.Flags; - packet.QuantityChange = count; - - SendPacket(packet); - } - } - - public bool HasCurrency(uint id, uint count) - { - var playerCurrency = _currencyStorage.LookupByKey(id); - return playerCurrency != null && playerCurrency.Quantity >= count; - } - public uint GetCurrencyWeekCap(CurrencyTypes id) - { - CurrencyTypesRecord entry = CliDB.CurrencyTypesStorage.LookupByKey((uint)id); - if (entry == null) - return 0; - - return GetCurrencyWeekCap(entry); - } - public uint GetCurrencyWeekCap(CurrencyTypesRecord currency) - { - return currency.MaxEarnablePerWeek; - } - uint GetCurrencyTotalCap(CurrencyTypesRecord currency) - { - uint cap = currency.MaxQty; - - switch ((CurrencyTypes)currency.Id) - { - case CurrencyTypes.ApexisCrystals: - { - uint apexiscap = WorldConfig.GetUIntValue(WorldCfg.CurrencyMaxApexisCrystals); - if (apexiscap > 0) - cap = apexiscap; - break; - } - case CurrencyTypes.JusticePoints: - { - uint justicecap = WorldConfig.GetUIntValue(WorldCfg.CurrencyMaxJusticePoints); - if (justicecap > 0) - cap = justicecap; - break; - } - } - - return cap; - } - uint GetCurrencyOnWeek(CurrencyTypes id) + public uint GetCurrencyWeeklyQuantity(uint id) { var playerCurrency = _currencyStorage.LookupByKey(id); if (playerCurrency == null) @@ -1278,12 +1314,60 @@ namespace Game.Entities return playerCurrency.WeeklyQuantity; } - public uint GetTrackedCurrencyCount(uint id) + + public uint GetCurrencyTrackedQuantity(uint id) { - if (!_currencyStorage.ContainsKey(id)) + var playerCurrency = _currencyStorage.LookupByKey(id); + if (playerCurrency == null) return 0; - return _currencyStorage[id].TrackedQuantity; + return playerCurrency.TrackedQuantity; + } + + uint GetCurrencyIncreasedCapQuantity(uint id) + { + var playerCurrency = _currencyStorage.LookupByKey(id); + if (playerCurrency == null) + return 0; + + return playerCurrency.IncreasedCapQuantity; + } + + public uint GetCurrencyMaxQuantity(CurrencyTypesRecord currency, bool onLoad = false, bool onUpdateVersion = false) + { + if (!currency.HasMaxQuantity(onLoad, onUpdateVersion)) + return 0; + + uint maxQuantity = currency.MaxQty; + if (currency.MaxQtyWorldStateID != 0) + maxQuantity = (uint)Global.WorldStateMgr.GetValue(currency.MaxQtyWorldStateID, GetMap()); + + uint increasedCap = 0; + if (currency.GetFlags().HasFlag(CurrencyTypesFlags.DynamicMaximum)) + increasedCap = GetCurrencyIncreasedCapQuantity(currency.Id); + + return maxQuantity + increasedCap; + } + + uint GetCurrencyWeeklyCap(uint id) + { + CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(id); + if (currency == null) + return 0; + + return GetCurrencyWeeklyCap(currency); + } + + uint GetCurrencyWeeklyCap(CurrencyTypesRecord currency) + { + // TODO: CurrencyTypeFlags::ComputedWeeklyMaximum + return currency.MaxEarnablePerWeek; + } + + public bool HasCurrency(uint id, uint amount) + { + var playerCurrency = _currencyStorage.LookupByKey(id); + return playerCurrency != null && playerCurrency.Quantity >= amount; } //Action Buttons - CUF Profile @@ -1810,7 +1894,7 @@ namespace Game.Entities // remove all dyn objects RemoveAllDynObjects(); - + // remove all areatriggers entities RemoveAllAreaTriggers(); @@ -5796,49 +5880,50 @@ namespace Game.Entities return true; } - void SendNewCurrency(uint id) - { - var Curr = _currencyStorage.LookupByKey(id); - if (Curr == null) - return; - - CurrencyTypesRecord entry = CliDB.CurrencyTypesStorage.LookupByKey(id); - if (entry == null) // should never happen - return; - - SetupCurrency packet = new(); - SetupCurrency.Record record = new(); - record.Type = entry.Id; - record.Quantity = Curr.Quantity; - record.WeeklyQuantity = Curr.WeeklyQuantity; - record.MaxWeeklyQuantity = GetCurrencyWeekCap(entry); - record.TrackedQuantity = Curr.TrackedQuantity; - record.Flags = Curr.Flags; - - packet.Data.Add(record); - - SendPacket(packet); - } - void SendCurrencies() { SetupCurrency packet = new(); - foreach (var pair in _currencyStorage) + foreach (var (id, currency) in _currencyStorage) { - CurrencyTypesRecord entry = CliDB.CurrencyTypesStorage.LookupByKey(pair.Key); - - // not send init meta currencies. - if (entry == null || entry.CategoryID == 89) //CURRENCY_CATEGORY_META_CONQUEST + CurrencyTypesRecord currencyRecord = CliDB.CurrencyTypesStorage.LookupByKey(id); + if (currencyRecord == null) continue; + // Check faction + if ((currencyRecord.IsAlliance() && GetTeam() != Team.Alliance) || + (currencyRecord.IsHorde() && GetTeam() != Team.Horde)) + continue; + + // Check award condition + if (currencyRecord.AwardConditionID != 0) + { + PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(currencyRecord.AwardConditionID); + if (playerCondition != null && !ConditionManager.IsPlayerMeetingCondition(this, playerCondition)) + continue; + } + SetupCurrency.Record record = new(); - record.Type = entry.Id; - record.Quantity = pair.Value.Quantity; - record.WeeklyQuantity = pair.Value.WeeklyQuantity; - record.MaxWeeklyQuantity = GetCurrencyWeekCap(entry); - record.TrackedQuantity = pair.Value.TrackedQuantity; - record.Flags = pair.Value.Flags; + record.Type = currencyRecord.Id; + record.Quantity = currency.Quantity; + + if ((currency.WeeklyQuantity / currencyRecord.GetScaler()) > 0) + record.WeeklyQuantity = currency.WeeklyQuantity; + + if (currencyRecord.HasMaxEarnablePerWeek()) + record.MaxWeeklyQuantity = GetCurrencyWeeklyCap(currencyRecord); + + if (currencyRecord.IsTrackingQuantity()) + record.TrackedQuantity = currency.TrackedQuantity; + + if (currencyRecord.HasTotalEarned()) + record.TotalEarned = (int)currency.EarnedQuantity; + + if (currencyRecord.HasMaxQuantity(true)) + record.MaxQuantity = (int)GetCurrencyMaxQuantity(currencyRecord, true); + + record.Flags = (byte)currency.Flags; + record.Flags = (byte)(record.Flags & ~(int)CurrencyDbFlags.UnusedFlags); packet.Data.Add(record); } @@ -7365,11 +7450,11 @@ namespace Game.Entities } //Helpers - public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action) + public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action) { PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, 0, 0, false, 0, "", null, null, sender, action); } - public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action, string popupText, uint popupMoney, bool coded) + public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action, string popupText, uint popupMoney, bool coded) { PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, 0, 0, coded, popupMoney, popupText, null, null, sender, action); } diff --git a/Source/Game/Garrisons/Garrisons.cs b/Source/Game/Garrisons/Garrisons.cs index 86fe8e6a9..54d8ed150 100644 --- a/Source/Game/Garrisons/Garrisons.cs +++ b/Source/Game/Garrisons/Garrisons.cs @@ -369,7 +369,7 @@ namespace Game.Garrisons map.AddToMap(go); } - _owner.ModifyCurrency(building.CurrencyTypeID, -building.CurrencyQty, false, true); + _owner.RemoveCurrency(building.CurrencyTypeID, building.CurrencyQty, CurrencyDestroyReason.Garrison); _owner.ModifyMoney(-building.GoldCost * MoneyConstants.Gold, false); if (oldBuildingId != 0) @@ -409,7 +409,7 @@ namespace Game.Garrisons GarrBuildingRecord constructing = CliDB.GarrBuildingStorage.LookupByKey(buildingRemoved.GarrBuildingID); // Refund construction/upgrade cost - _owner.ModifyCurrency(constructing.CurrencyTypeID, constructing.CurrencyQty, false, true); + _owner.AddCurrency(constructing.CurrencyTypeID, (uint)constructing.CurrencyQty, CurrencyGainSource.GarrisonBuildingRefund); _owner.ModifyMoney(constructing.GoldCost * MoneyConstants.Gold, false); if (constructing.UpgradeLevel > 1) diff --git a/Source/Game/Networking/Packets/MiscPackets.cs b/Source/Game/Networking/Packets/MiscPackets.cs index b996b1f67..c23732131 100644 --- a/Source/Game/Networking/Packets/MiscPackets.cs +++ b/Source/Game/Networking/Packets/MiscPackets.cs @@ -91,15 +91,20 @@ namespace Game.Networking.Packets { _worldPacket.WriteUInt32(Type); _worldPacket.WriteInt32(Quantity); - _worldPacket.WriteUInt32(Flags); + _worldPacket.WriteUInt32((uint)Flags); + _worldPacket.WriteInt32(Toasts.Count); + + foreach (var toast in Toasts) + toast.Write(_worldPacket); + _worldPacket.WriteBit(WeeklyQuantity.HasValue); _worldPacket.WriteBit(TrackedQuantity.HasValue); _worldPacket.WriteBit(MaxQuantity.HasValue); _worldPacket.WriteBit(TotalEarned.HasValue); _worldPacket.WriteBit(SuppressChatLog); _worldPacket.WriteBit(QuantityChange.HasValue); - _worldPacket.WriteBit(QuantityLostSource.HasValue); _worldPacket.WriteBit(QuantityGainSource.HasValue); + _worldPacket.WriteBit(QuantityLostSource.HasValue); _worldPacket.WriteBit(FirstCraftOperationID.HasValue); _worldPacket.WriteBit(LastSpendTime.HasValue); _worldPacket.FlushBits(); @@ -119,11 +124,11 @@ namespace Game.Networking.Packets if (QuantityChange.HasValue) _worldPacket.WriteInt32(QuantityChange.Value); - if (QuantityLostSource.HasValue) - _worldPacket.WriteInt32(QuantityLostSource.Value); - if (QuantityGainSource.HasValue) - _worldPacket.WriteInt32(QuantityGainSource.Value); + _worldPacket.WriteInt32((int)QuantityGainSource.Value); + + if (QuantityLostSource.HasValue) + _worldPacket.WriteInt32((int)QuantityLostSource.Value); if (FirstCraftOperationID.HasValue) _worldPacket.WriteUInt32(FirstCraftOperationID.Value); @@ -134,15 +139,15 @@ namespace Game.Networking.Packets public uint Type; public int Quantity; - public uint Flags; + public CurrencyGainFlags Flags; public List Toasts = new(); public int? WeeklyQuantity; public int? TrackedQuantity; public int? MaxQuantity; public int? TotalEarned; public int? QuantityChange; - public int? QuantityGainSource; - public int? QuantityLostSource; + public CurrencyGainSource? QuantityGainSource; + public CurrencyDestroyReason? QuantityLostSource; public uint? FirstCraftOperationID; public long? LastSpendTime; public bool SuppressChatLog; @@ -223,7 +228,7 @@ namespace Game.Networking.Packets public int? MaxQuantity; public int? TotalEarned; public long? LastSpendTime; - public byte Flags; // 0 = none, + public byte Flags; } } diff --git a/Source/Game/Reputation/ReputationManager.cs b/Source/Game/Reputation/ReputationManager.cs index adb678d72..c7b4aa57d 100644 --- a/Source/Game/Reputation/ReputationManager.cs +++ b/Source/Game/Reputation/ReputationManager.cs @@ -221,7 +221,7 @@ namespace Game CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(renownFactionEntry.RenownCurrencyID); if (currency != null) - return (int)_player.GetCurrency(currency.Id); + return (int)_player.GetCurrencyQuantity(currency.Id); return 0; } @@ -245,7 +245,7 @@ namespace Game CurrencyTypesRecord currency = CliDB.CurrencyTypesStorage.LookupByKey(renownFactionEntry.RenownCurrencyID); if (currency != null) - return (int)currency.MaxQty; + return (int)_player.GetCurrencyMaxQuantity(currency); return 0; } @@ -481,7 +481,7 @@ namespace Game if (factionState != null) { // Ignore renown reputation already raised to the maximum level - if (HasMaximumRenownReputation(factionEntry)) + if (HasMaximumRenownReputation(factionEntry) && standing > 0) { factionState.needSend = false; factionState.needSave = false; @@ -547,8 +547,9 @@ namespace Game factionState.VisualStandingIncrease = reputationChange; + // If the reputation is decreased by command, we will send CurrencyDestroyReason::Cheat if (oldRenownLevel != newRenownLevel) - _player.ModifyCurrency(currency.Id, newRenownLevel - oldRenownLevel, false); + _player.ModifyCurrency(currency.Id, newRenownLevel - oldRenownLevel, CurrencyGainSource.RenownRepGain, CurrencyDestroyReason.Cheat); } } diff --git a/Source/Game/Server/WorldConfig.cs b/Source/Game/Server/WorldConfig.cs index ece5e3273..326d196ef 100644 --- a/Source/Game/Server/WorldConfig.cs +++ b/Source/Game/Server/WorldConfig.cs @@ -503,34 +503,6 @@ namespace Game Values[WorldCfg.CurrencyResetInterval] = 7; } - Values[WorldCfg.CurrencyStartApexisCrystals] = GetDefaultValue("Currency.StartApexisCrystals", 0); - if ((int)Values[WorldCfg.CurrencyStartApexisCrystals] < 0) - { - Log.outError(LogFilter.ServerLoading, "Currency.StartApexisCrystals ({0}) must be >= 0, set to default 0.", Values[WorldCfg.CurrencyStartApexisCrystals]); - Values[WorldCfg.CurrencyStartApexisCrystals] = 0; - } - Values[WorldCfg.CurrencyMaxApexisCrystals] = GetDefaultValue("Currency.MaxApexisCrystals", 20000); - if ((int)Values[WorldCfg.CurrencyMaxApexisCrystals] < 0) - { - Log.outError(LogFilter.ServerLoading, "Currency.MaxApexisCrystals ({0}) can't be negative. Set to default 20000.", Values[WorldCfg.CurrencyMaxApexisCrystals]); - Values[WorldCfg.CurrencyMaxApexisCrystals] = 20000; - } - Values[WorldCfg.CurrencyMaxApexisCrystals] = (int)Values[WorldCfg.CurrencyMaxApexisCrystals] * 100; //precision mod - - Values[WorldCfg.CurrencyStartJusticePoints] = GetDefaultValue("Currency.StartJusticePoints", 0); - if ((int)Values[WorldCfg.CurrencyStartJusticePoints] < 0) - { - Log.outError(LogFilter.ServerLoading, "Currency.StartJusticePoints ({0}) must be >= 0, set to default 0.", Values[WorldCfg.CurrencyStartJusticePoints]); - Values[WorldCfg.CurrencyStartJusticePoints] = 0; - } - Values[WorldCfg.CurrencyMaxJusticePoints] = GetDefaultValue("Currency.MaxJusticePoints", 4000); - if ((int)Values[WorldCfg.CurrencyMaxJusticePoints] < 0) - { - Log.outError(LogFilter.ServerLoading, "Currency.MaxJusticePoints ({0}) can't be negative. Set to default 4000.", Values[WorldCfg.CurrencyMaxJusticePoints]); - Values[WorldCfg.CurrencyMaxJusticePoints] = 4000; - } - Values[WorldCfg.CurrencyMaxJusticePoints] = (int)Values[WorldCfg.CurrencyMaxJusticePoints] * 100; //precision mod - Values[WorldCfg.MaxRecruitAFriendBonusPlayerLevel] = GetDefaultValue("RecruitAFriend.MaxLevel", 60); if ((int)Values[WorldCfg.MaxRecruitAFriendBonusPlayerLevel] > (int)Values[WorldCfg.MaxPlayerLevel]) { diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index d657515fe..d509e35b4 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -4495,7 +4495,7 @@ namespace Game.Spells } foreach (var reagentsCurrency in m_spellInfo.ReagentsCurrency) - p_caster.ModifyCurrency(reagentsCurrency.CurrencyTypesID, -reagentsCurrency.CurrencyCount, false, true); + p_caster.RemoveCurrency(reagentsCurrency.CurrencyTypesID, -reagentsCurrency.CurrencyCount, CurrencyDestroyReason.Spell); } void HandleThreatSpells() diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 6b708f302..c29aef668 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -4729,7 +4729,7 @@ namespace Game.Spells if (!CliDB.CurrencyTypesStorage.ContainsKey(effectInfo.MiscValue)) return; - unitTarget.ToPlayer().ModifyCurrency((uint)effectInfo.MiscValue, damage); + unitTarget.ToPlayer().ModifyCurrency((uint)effectInfo.MiscValue, damage, CurrencyGainSource.Spell, CurrencyDestroyReason.Spell); } [SpellEffectHandler(SpellEffectName.CastButton)] @@ -4847,6 +4847,18 @@ namespace Game.Spells } } + [SpellEffectHandler(SpellEffectName.IncreseCurrencyCap)] + void EffectIncreaseCurrencyCap() + { + if (effectHandleMode != SpellEffectHandleMode.HitTarget) + return; + + if (damage <= 0) + return; + + unitTarget.ToPlayer()?.IncreaseCurrencyCap((uint)effectInfo.MiscValue, (uint)damage); + } + [SpellEffectHandler(SpellEffectName.SummonRafFriend)] void EffectSummonRaFFriend() { diff --git a/Source/Game/Spells/TraitManager.cs b/Source/Game/Spells/TraitManager.cs index b8da57fc5..dcc366ec2 100644 --- a/Source/Game/Spells/TraitManager.cs +++ b/Source/Game/Spells/TraitManager.cs @@ -384,7 +384,7 @@ namespace Game if (!currencies.ContainsKey((int)currency.Id)) currencies[(int)currency.Id] = 0; - currencies[(int)currency.Id] += (int)player.GetCurrency((uint)currency.CurrencyTypesID); + currencies[(int)currency.Id] += (int)player.GetCurrencyQuantity((uint)currency.CurrencyTypesID); break; case TraitCurrencyType.TraitSourced: var currencySources = _traitCurrencySourcesByCurrency.LookupByKey(currency.Id); diff --git a/Source/WorldServer/WorldServer.conf.dist b/Source/WorldServer/WorldServer.conf.dist index 2504bd1cf..4e8a07a09 100644 --- a/Source/WorldServer/WorldServer.conf.dist +++ b/Source/WorldServer/WorldServer.conf.dist @@ -3904,38 +3904,6 @@ Currency.ResetDay = 3 Currency.ResetHour = 6 -# -# Currency.StartApexisCrystals -# Amount of Apexis Crystals that new players will start with -# Default: 0 (with precision) -# - -Currency.StartApexisCrystals = 0 - -# -# Currency.MaxApexisCrystals -# Amount Apexis Crystals a player can have -# Default: 20000 -# - -Currency.MaxApexisCrystals = 20000 - -# -# Currency.StartJusticePoints -# Amount of justice points that new players will start with -# Default: 0 (with precision) -# - -Currency.StartJusticePoints = 0 - -# -# Currency.MaxJusticePoints -# Amount justice points a player can have -# Default: 4000 -# - -Currency.MaxJusticePoints = 4000 - # ###################################################################################################