diff --git a/Maple2.Database/Model/Mail.cs b/Maple2.Database/Model/Mail.cs index cfca17f25..0927f3107 100644 --- a/Maple2.Database/Model/Mail.cs +++ b/Maple2.Database/Model/Mail.cs @@ -55,7 +55,7 @@ internal class Mail { [return: NotNullIfNotNull(nameof(other))] public static implicit operator Maple2.Model.Game.Mail?(Mail? other) { - return other == null ? null : new Maple2.Model.Game.Mail { + return other == null ? null : new Maple2.Model.Game.Mail() { ReceiverId = other.ReceiverId, Id = other.Id, SenderId = other.SenderId, diff --git a/Maple2.Database/Storage/Game/GameStorage.Map.cs b/Maple2.Database/Storage/Game/GameStorage.Map.cs index 0ccfb0e43..37cb8cdfc 100644 --- a/Maple2.Database/Storage/Game/GameStorage.Map.cs +++ b/Maple2.Database/Storage/Game/GameStorage.Map.cs @@ -111,11 +111,11 @@ public IList LoadCubesForOwner(long ownerId) { return Context.TrySaveChanges() ? ToPlotInfo(model) : null; } - public PlotInfo? GetSoonestPlotFromExpire() { + public PlotInfo? GetSoonestPlotFromExpire(TimeSpan ugcHomeSaleWaitingTime) { IQueryable maps = Context.UgcMap.Where(map => map.ExpiryTime > DateTimeOffset.MinValue && !map.Indoor); foreach (UgcMap map in maps) { if (map.OwnerId == 0) { - map.ExpiryTime = map.ExpiryTime.Add(Constant.UgcHomeSaleWaitingTime); + map.ExpiryTime = map.ExpiryTime.Add(ugcHomeSaleWaitingTime); } } UgcMap? model = maps.OrderBy(map => map.ExpiryTime).FirstOrDefault(); diff --git a/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs b/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs index 9a3c1d591..187856d3b 100644 --- a/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs +++ b/Maple2.Database/Storage/Metadata/ServerTableMetadataStorage.cs @@ -29,6 +29,7 @@ public class ServerTableMetadataStorage { private readonly Lazy combineSpawnTable; private readonly Lazy enchantOptionTable; private readonly Lazy unlimitedEnchantOptionTable; + private readonly Lazy constantsTable; public InstanceFieldTable InstanceFieldTable => instanceFieldTable.Value; public ScriptConditionTable ScriptConditionTable => scriptConditionTable.Value; @@ -53,6 +54,7 @@ public class ServerTableMetadataStorage { public CombineSpawnTable CombineSpawnTable => combineSpawnTable.Value; public EnchantOptionTable EnchantOptionTable => enchantOptionTable.Value; public UnlimitedEnchantOptionTable UnlimitedEnchantOptionTable => unlimitedEnchantOptionTable.Value; + public ConstantsTable ConstantsTable => constantsTable.Value; public ServerTableMetadataStorage(MetadataContext context) { instanceFieldTable = Retrieve(context, ServerTableNames.INSTANCE_FIELD); @@ -78,6 +80,7 @@ public ServerTableMetadataStorage(MetadataContext context) { combineSpawnTable = Retrieve(context, ServerTableNames.COMBINE_SPAWN); enchantOptionTable = Retrieve(context, ServerTableNames.ENCHANT_OPTION); unlimitedEnchantOptionTable = Retrieve(context, ServerTableNames.UNLIMITED_ENCHANT_OPTION); + constantsTable = Retrieve(context, ServerTableNames.CONSTANTS); } public IEnumerable GetGameEvents() { diff --git a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs index 940694898..514e96d74 100644 --- a/Maple2.File.Ingest/Mapper/ServerTableMapper.cs +++ b/Maple2.File.Ingest/Mapper/ServerTableMapper.cs @@ -1,10 +1,10 @@ -using System.Globalization; -using System.Xml; -using Maple2.Database.Extensions; +using Maple2.Database.Extensions; using Maple2.File.Ingest.Utils; using Maple2.File.IO; using Maple2.File.Parser; using Maple2.File.Parser.Enum; +using Maple2.File.Parser.Flat.Convert; +using Maple2.File.Parser.Xml.Table; using Maple2.File.Parser.Xml.Table.Server; using Maple2.Model; using Maple2.Model.Common; @@ -13,6 +13,11 @@ using Maple2.Model.Game; using Maple2.Model.Game.Shop; using Maple2.Model.Metadata; +using Newtonsoft.Json.Linq; +using System.Globalization; +using System.Numerics; +using System.Reflection; +using System.Xml; using DayOfWeek = System.DayOfWeek; using ExpType = Maple2.Model.Enum.ExpType; using Fish = Maple2.File.Parser.Xml.Table.Server.Fish; @@ -128,6 +133,10 @@ protected override IEnumerable Map() { Name = ServerTableNames.UNLIMITED_ENCHANT_OPTION, Table = ParseUnlimitedEnchantOption(), }; + yield return new ServerTableMetadata { + Name = ServerTableNames.CONSTANTS, + Table = ParseConstants(), + }; } @@ -2135,4 +2144,56 @@ void AddSpecial(Dictionary values, Dictionary propertyLookup = typeof(ConstantsTable).GetProperties() + .ToDictionary(p => p.Name.Trim(), p => p, StringComparer.OrdinalIgnoreCase); + foreach ((string key, Constants.Key constant) in parser.ParseConstants()) { + string trimmedKey = key.Trim(); + if (!propertyLookup.TryGetValue(trimmedKey, out PropertyInfo? property)) continue; + string cleanValue = CleanInput(constant.value.Trim(), trimmedKey, property.PropertyType); + GenericHelper.SetValue(property, constants, cleanValue); + } + return constants; + + string CleanInput(string input, string propName, Type type) { + // check if string contains the ending 'f' for float designation, strip it if it does. + if (type == typeof(float) && input.Contains('f')) { + input = input.TrimEnd('f', 'F'); + } + if (type == typeof(bool)) { + // 1 does not automatically equate to true during bool conversion + if (input == "1") { + input = "true"; + } + // 0 does not automatically equate to false during bool conversion + if (input == "0") { + input = "false"; + } + } + if (type == typeof(TimeSpan)) { + // Special case - dashes (-) are used instead of colons (:) + if (propName == "DailyTrophyResetDate") { + input = input.Replace('-', ':'); + } + // Stored as 0.1 for 100ms + if (propName == "GlobalCubeSkillIntervalTime") { + input = $"0:0:{input}"; + } + // Stored as an int value, convert to friendly input string for TimeSpan parsing + if (propName == "UgcHomeSaleWaitingTime") { + int.TryParse(input, out int result); + input = TimeSpan.FromSeconds(result).ToString(); // TODO: may not be correct conversion to TimeSpan + } + } + if (type == typeof(int)) { + // Remove prefix 0 on integers since they do not convert properly + if (input.Length > 1 && input[0] == '0') { + input = input.Remove(0, 1); + } + } + return input; + } + } } diff --git a/Maple2.File.Ingest/Utils/GenericHelper.cs b/Maple2.File.Ingest/Utils/GenericHelper.cs new file mode 100644 index 000000000..23446cec8 --- /dev/null +++ b/Maple2.File.Ingest/Utils/GenericHelper.cs @@ -0,0 +1,103 @@ +using System.Globalization; +using System.Numerics; +using System.Reflection; + +namespace Maple2.File.Ingest.Utils; + +public static class GenericHelper { + public static void SetValue(PropertyInfo prop, object? obj, object? value) { + if (obj == null && value == null || value == null) return; + HandleNonIConvertibleTypes(prop, ref value); + if (value == null) return; + if (typeof(IConvertible).IsAssignableFrom(prop.PropertyType)) { + TryParseObject(prop.PropertyType, value, out object? result); + prop.SetValue(obj, result); + return; + } + prop.SetValue(obj, value); + } + + private static object? HandleNonIConvertibleTypes(PropertyInfo prop, ref object? value) { + if (value == null) return value; + // Handle TimeSpan type + if (prop.PropertyType == typeof(TimeSpan)) { + TimeSpan.TryParse((string) value, CultureInfo.InvariantCulture, out TimeSpan val); + value = val; + } + // Handle array types (int[], short[], etc.) + if (prop.PropertyType.IsArray) { + var elementType = prop.PropertyType.GetElementType(); + if (elementType == null) return value; + string[] segments = ((string) value).Split(','); + Array destinationArray = Array.CreateInstance(elementType, segments.Length); + for (int i = 0; i < segments.Length; i++) { + if (TryParseObject(elementType, segments[i].Trim(), out object? parseResult)) { + destinationArray.SetValue(parseResult ?? default, i); + }else { + destinationArray.SetValue(elementType.IsValueType ? Activator.CreateInstance(elementType) : null, i); + } + } + value = destinationArray; + } + // Handle Vector3 type + if (prop.PropertyType == typeof(Vector3)) { + string[] parts = ((string) value).Split(','); + bool parseXSuccess = float.TryParse(parts[0], CultureInfo.InvariantCulture, out float x); + bool parseYSuccess = float.TryParse(parts[1], CultureInfo.InvariantCulture, out float y); + bool parseZSuccess = float.TryParse(parts[2], CultureInfo.InvariantCulture, out float z); + if (parts.Length != 3 || parseXSuccess && parseYSuccess && parseZSuccess) { + value = Vector3.Zero; + } else { + value = new Vector3(x, y, z); + } + } + return value; + } + + private static bool TryParseObject(Type? elementType, object? input, out object? result) { + if (elementType == null || input == null) { + result = null; + return false; + } + + string inputString = Convert.ToString(input, CultureInfo.InvariantCulture)!; + + // No TryParse method exists for a string, use the result directly. + if (elementType == typeof(string)) { + result = inputString; + return true; + } + + Type[] argTypes = { + typeof(string), + typeof(IFormatProvider), + elementType.MakeByRefType() + }; + + var method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, argTypes, null); + if (method != null) { + object[] args = [inputString, CultureInfo.InvariantCulture, null!]; + bool success = (bool) method.Invoke(null, args)!; + result = args[2]; + return success; + } + + // Fallback without CultureInfo provided, in case the type does not have a CultureInfo overload. + Type[] simpleArgs = { typeof(string), elementType.MakeByRefType() }; + method = elementType.GetMethod("TryParse", + BindingFlags.Public | BindingFlags.Static, + null, simpleArgs, null); + if (method != null) { + object[] args = { inputString, null! }; + bool success = (bool) method.Invoke(null, args)!; + result = args[1]; + return success; + } + + + result = null; + return false; + } +} diff --git a/Maple2.Model/Common/ServerTableNames.cs b/Maple2.Model/Common/ServerTableNames.cs index 7a328840f..0761b6ea1 100644 --- a/Maple2.Model/Common/ServerTableNames.cs +++ b/Maple2.Model/Common/ServerTableNames.cs @@ -24,4 +24,5 @@ public static class ServerTableNames { public const string COMBINE_SPAWN = "combineSpawn*.xml"; public const string ENCHANT_OPTION = "enchantOption.xml"; public const string UNLIMITED_ENCHANT_OPTION = "unlimitedEnchantOption.xml"; + public const string CONSTANTS = "constants.xml"; } diff --git a/Maple2.Model/Game/Cube/Nurturing.cs b/Maple2.Model/Game/Cube/Nurturing.cs index faad1e1e5..229b87474 100644 --- a/Maple2.Model/Game/Cube/Nurturing.cs +++ b/Maple2.Model/Game/Cube/Nurturing.cs @@ -48,20 +48,20 @@ public Nurturing(long exp, short claimedGiftForStage, long[] playedBy, DateTimeO } } - public void Feed() { + public void Feed(int nurturingEatGrowth) { if (Exp >= NurturingMetadata.RequiredGrowth.Last().Exp) { return; } - Exp += Constant.NurturingEatGrowth; + Exp += nurturingEatGrowth; if (Exp >= NurturingMetadata.RequiredGrowth.First(x => x.Stage == Stage).Exp) { Stage++; } LastFeedTime = DateTimeOffset.Now; } - public bool Play(long accountId) { - if (PlayedBy.Count >= Constant.NurturingPlayMaxCount) { + public bool Play(long accountId, int nurturingEatGrowth, int nurturingPlayMaxCount) { + if (PlayedBy.Count >= nurturingPlayMaxCount) { return false; } @@ -70,7 +70,7 @@ public bool Play(long accountId) { } PlayedBy.Add(accountId); - Feed(); + Feed(nurturingEatGrowth); return true; } diff --git a/Maple2.Model/Game/Mail.cs b/Maple2.Model/Game/Mail.cs index e97dc99a8..ec1faaee4 100644 --- a/Maple2.Model/Game/Mail.cs +++ b/Maple2.Model/Game/Mail.cs @@ -1,6 +1,5 @@ using System.Text; using Maple2.Model.Enum; -using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Tools; using Maple2.Tools.Extensions; @@ -35,11 +34,19 @@ public class Mail : IByteSerializable { // More than 1 item may not display properly public readonly IList Items; + // Specifically for Mail object cloning (Mail.cs:57) public Mail() { TitleArgs = new List<(string Key, string Value)>(); ContentArgs = new List<(string Key, string Value)>(); Items = new List(); - ExpiryTime = DateTimeOffset.UtcNow.AddDays(Constant.MailExpiryDays).ToUnixTimeSeconds(); + // ExpiryTime will be overwritten, no need to set it here with a parameter passing server constant value. + } + + public Mail(int mailExpiryDays) { + TitleArgs = new List<(string Key, string Value)>(); + ContentArgs = new List<(string Key, string Value)>(); + Items = new List(); + ExpiryTime = DateTimeOffset.UtcNow.AddDays(mailExpiryDays).ToUnixTimeSeconds(); } public void Update(Mail other) { diff --git a/Maple2.Model/Game/User/StatAttributes.cs b/Maple2.Model/Game/User/StatAttributes.cs index 28cf8c61f..9c432db3a 100644 --- a/Maple2.Model/Game/User/StatAttributes.cs +++ b/Maple2.Model/Game/User/StatAttributes.cs @@ -13,9 +13,9 @@ public class StatAttributes : IByteSerializable { public int TotalPoints => Sources.Count; public int UsedPoints => Allocation.Count; - public StatAttributes() { + public StatAttributes(IDictionary statLimits) { Sources = new PointSources(); - Allocation = new PointAllocation(); + Allocation = new PointAllocation(statLimits); } public void WriteTo(IByteWriter writer) { @@ -52,6 +52,7 @@ public void WriteTo(IByteWriter writer) { public class PointAllocation : IByteSerializable { private readonly Dictionary points; + private readonly IDictionary statLimits; public BasicAttribute[] Attributes => points.Keys.ToArray(); public int Count => points.Values.Sum(); @@ -59,7 +60,7 @@ public class PointAllocation : IByteSerializable { public int this[BasicAttribute type] { get => points.GetValueOrDefault(type); set { - if (value < 0 || value > StatLimit(type)) { + if (value < 0 || value > StatLimit(type, statLimits)) { return; } if (value == 0) { @@ -71,19 +72,20 @@ public int this[BasicAttribute type] { } } - public PointAllocation() { + public PointAllocation(IDictionary statLimits) { points = new Dictionary(); + this.statLimits = statLimits; } - public static int StatLimit(BasicAttribute type) { + public static int StatLimit(BasicAttribute type, IDictionary statLimits) { return type switch { - BasicAttribute.Strength => Constant.StatPointLimit_str, - BasicAttribute.Dexterity => Constant.StatPointLimit_dex, - BasicAttribute.Intelligence => Constant.StatPointLimit_int, - BasicAttribute.Luck => Constant.StatPointLimit_luk, - BasicAttribute.Health => Constant.StatPointLimit_hp, - BasicAttribute.CriticalRate => Constant.StatPointLimit_cap, - _ => 0, + BasicAttribute.Strength => statLimits.GetValueOrDefault("StatPointLimit_str"), + BasicAttribute.Dexterity => statLimits.GetValueOrDefault("StatPointLimit_dex"), + BasicAttribute.Intelligence => statLimits.GetValueOrDefault("StatPointLimit_int"), + BasicAttribute.Luck => statLimits.GetValueOrDefault("StatPointLimit_luk"), + BasicAttribute.Health => statLimits.GetValueOrDefault("StatPointLimit_hp"), + BasicAttribute.CriticalRate => statLimits.GetValueOrDefault("StatPointLimit_cap"), + _ => 0 }; } diff --git a/Maple2.Model/Metadata/Constants.cs b/Maple2.Model/Metadata/Constants.cs index 43c74bf53..615e751b8 100644 --- a/Maple2.Model/Metadata/Constants.cs +++ b/Maple2.Model/Metadata/Constants.cs @@ -17,8 +17,6 @@ public static class Constant { public const long MesoTokenMax = 100000; public const int MaxSkillTabCount = 3; public const int BuddyMessageLengthMax = 25; - public const int MaxBuddyCount = 100; - public const int MaxBlockCount = 100; public const int GemstoneGrade = 4; public const int LapenshardGrade = 3; public const int InventoryExpandRowCount = 6; @@ -104,26 +102,39 @@ public static class Constant { public const int Grade3WeddingCouponItemId = 20303168; public const int MinStatIntervalTick = 100; public const int HomePollMaxCount = 5; + public const int DummyNpcMale = 2040998; + public const int DummyNpcFemale = 2040999; + public const int NextStateTriggerDefaultTick = 100; public static readonly TimeSpan WorldBossIdleWarningThreshold = TimeSpan.FromMinutes(4); public static readonly TimeSpan WorldBossDespawnThreshold = TimeSpan.FromMinutes(5); public static readonly TimeSpan WorldBossMonitorInterval = TimeSpan.FromSeconds(30); public const int MaxMentees = 3; - public const long FurnishingBaseId = 2870000000000000000; public const bool AllowWaterOnGround = false; - public const int HomeDecorationMaxLevel = 10; - public const bool EnableRollEverywhere = false; public const bool HideHomeCommands = true; - public const int MaxAllowedLatency = 2000; - public const bool DebugTriggers = false; // Set to true to enable debug triggers. (It'll write triggers to files and load triggers from files instead of DB) - public const bool AllowUnicodeInNames = false; // Allow Unicode characters in character and guild names + public const bool MailQuestItems = false; // Mail quest item rewards if inventory is full + public const int MaxClosetMaxCount = 5; + public const int MaxClosetTabNameLength = 10; + public const int CharacterNameLengthMin = 2; + public const int BlockSize = 150; + public const float SouthEast = 0; + public const float NorthEast = 90; + public const float NorthWest = -180; + public const float SouthWest = -90; + public const short HairSlotCount = 30; + public const ShopCurrencyType InitialTierExcessRestockCurrency = ShopCurrencyType.Meso; + public const float UGCShopProfitFee = 0.25f; + public const int UGCShopProfitDelayDays = 10; + public const int PartyFinderListingsPageCount = 12; + public const int ProposalItemId = 11600482; + public const int ClubMaxCount = 3; public static IReadOnlyDictionary ContentRewards { get; } = new Dictionary { { "miniGame", 1005 }, @@ -151,7 +162,9 @@ public static class Constant { { "QueenBeanArenaRound10Reward", 10000018 }, }; - public const bool MailQuestItems = false; // Mail quest item rewards if inventory is full + public static int DummyNpc(Gender gender) => gender is Gender.Female ? DummyNpcFemale : DummyNpcMale; + + #endregion #region Field public static readonly TimeSpan FieldUgcBannerRemoveAfter = TimeSpan.FromHours(4); @@ -190,778 +203,12 @@ public static class Constant { public static readonly bool BlockLoginWithMismatchedMachineId = false; public static readonly int DefaultMaxCharacters = 4; #endregion - #endregion - - #region client constants - public const int MaxClosetMaxCount = 5; - public const int MaxClosetTabNameLength = 10; - public const int WeddingProposeItemID = 11600482; - public const int WeddingInvitationMaxCount = 70; - public const int WeddingProposeCooltime = 2; - public const int WeddingDivorceFieldID = 84000002; - public const int WeddingInvitationMeso = 1000; - public const int WeddingDivorceMeso = 1000000; - public const int WeddingCoolingOffDay = 7; - public const int WeddingPromiseLimitDay = 7; - public const int WeddingHallModifyLimitHour = 3; - public const int WeddingDivorceRequireMarriageDay = 30; - public const int CharacterNameLengthMin = 2; - public const int BlockSize = 150; - public const float SouthEast = 0; - public const float NorthEast = 90; - public const float NorthWest = -180; - public const float SouthWest = -90; - public const short HairSlotCount = 30; - public const ShopCurrencyType InitialTierExcessRestockCurrency = ShopCurrencyType.Meso; - public const float UGCShopProfitFee = 0.25f; - public const int UGCShopProfitDelayDays = 10; - public const int PartyFinderListingsPageCount = 12; - public const int ProposalItemId = 11600482; - #endregion - - #region table/constants.xml - public const float NPCColorScale = 2.0f; - public const float NPCDuration = 0.2f; - public const float PCColorScale = 2.0f; - public const float PCDuration = 0.2f; - public const float GetEXPColorScale = 0.5f; - public const float GetEXPDuration = 0.2f; - public const float AccumulationRatio = 0.1f; - public const float NPCCliffHeight = 50.0f; - public const float NPCRandomDeadPushRate = 0.2f; - public const float CustomizingRotationSpeed = 75.0f; - public const float CustomizingWheelSpeed_Morph = 0.1f; - public const float CustomizingWheelSpeed_Item = 0.1f; - public const float CustomizingWheelSpeed_Makeup = 0.1f; - public const float CustomizingRotationSpeed_Makeup = 1.0f; - public const float CustomizingHairFirstPartHighlight = 0.1f; - public const float CustomizingHairSecondPartHighlight = 1.0f; - public const float LookAtInterval = 15.0f; - public const float LookAtDistanceNPC = 500.0f; - public const float LookAtDistanceCry = 500.0f; - public const bool EnableSkillJumpDown = true; - public const bool EscapeHitMethodSkill = false; - public const bool EscapeHitMethodJump = false; - public const bool EscapeHitMethodMove = false; - public const bool EscapeHitMoveKeyIsDown = false; - public const bool AllowComboAtComboPoint = true; - public const bool CancelSwing_KeyIsDown = true; - public const bool SkillGlobalCooldown = false; - public const bool SkillGlobalCooldown_CheckSameSkill = true; - public const int AttackRotationSpeed = 90; - public const int ChaosModeTime = 20; - public const int ChaosPointPerBlock = 20; - public const int ChaosPointMaxBlock = 1; - public const int ChaosPointGetLevel0 = 1; - public const int ChaosPointGetPoint0 = 120; - public const int ChaosActionGetLevel0 = 15; - public const int ChaosActionGetLevel1 = 25; - public const int ChaosActionGetLevel2 = 55; - public const int ChaosActionGetLevel3 = 95; - public const int ChaosActionGetLevel4 = 145; - public const int OnEnterTriggerClientSideOnlyTick = 100; - public const int OnEnterTriggerDefaultTick = 1000; - public const int TalkTimeover = 60000; - public const int DamageDistance = 2500; - public const int TalkableDistance = 150; - public const bool TalkableFrontOnly = true; - public const int DropIconVisibleDistance = 400; - public const int ChatBalloonDistance = 2000; - public const int HpBarDistance = 9999999; - public const int EmoticonVisibleDistance = 2500; - public const int RegisterUgcDistance = 150; - public const int RegisterUgcDistanceClose = 300; - public const int ConstructUgcDistance = 150; - public const int FunctionCubeDistance = 125; - public const int InteractionDistance = 155; - public const int HouseMarkShowDistance = 2000; - public const int HouseMarkShowClippingUp = 1000; - public const int HouseMarkShowClippingDown = 500; - public const int HouseMarkPopupDistance = 160; - public const int UgcBoundaryStartDistance = 1; - public const int UgcBoundaryEndDistance = 7; - public const int DurationForBoundaryDisplay = 3000; - public static TimeSpan UgcHomeSaleWaitingTime = TimeSpan.FromSeconds(259200); - public const int UgcContainerExpireDurationNormal = 90; - public const int UgcContainerExpireDurationCash = 365; - public const int UgcContainerExpireDurationMeret = 365; - public const int UgcHomeExtensionNoticeDate = 30; - public const int UgcHomePasswordExpireDuration = 86400; - public const bool CubeLiftHeightLimitUp = true; - public const bool CubeLiftHeightLimitDown = true; - public const int CubeCraftSafetyCapID = 11300053; - public const int CubeCraftLightStickLeftID = 13100014; - public const int CubeCraftLightStickRightID = 13100046; - public const float DropIconDistance = 200.0f; - public const int DropIconHeadOffset = 40; - public const int DropItemMaxLength = 300; - public const int DropMoneyMaxLength = 300; - public const float DropItemTargetZPos = 200.0f; - public const float DropItemPickUpVel = 200.0f; - public const float DropItemPickUpGravity = -38.0f; - public const float DropItemPickUpCompleteRotateTime = 0.1f; - public const int DropItemPickUpCompleteRotateVel = 5; - public const int DropMoneyActiveProbability = 0; - public const int DropMoneyProbability = 0; - public const int ChatBalloonDuration = 5000; - public const int BoreWaitingTick = 50000; - public const int OffsetPcHpBar = 32; - public const int OffsetPcNameTag = 30; - public const int OffsetPcChatBalloon = -30; - public const int OffsetPcDamageNumber = 0; - public const int OffsetPcMissionIndicator = 20; - public const int OffsetPcProfileTag = 0; - public const float fOffsetOnTombstoneNameTag = -5.0f; - public const int OffsetNpcHpBar = 5; - public const int OffsetNpcNameTag = 5; - public const int OffsetNpcEmoticon = -30; - public const int OffsetNpcChatBalloon = -30; - public const int OffsetNpcDamageNumber = 0; - public const int OffsetNpcMonologue = 40; - public const int OffsetActionTooltipX = 70; - public const int OffsetActionTooltipY = -40; - public const int OffsetPcPopupMenu = 60; - public const int DamageGap = 30; - public const int DamageRenderCount = 3; - public const int DamageRenderTotalCount = 25; - public const float DamageOtherScale = 0.5f; - public const float DamageOtherAlpha = 0.3f; - public const int DamageEffectMinHPPercent = 30; - public const int DamageEffectCriticalPercent = 10; - public const int questHideTime = 30; - public const int questIntervalTime = 60; - public const int ShopResetChance = 10; - public const int ShopSeedResetTime = 60; - public const int ShopRepurchaseMax = 12; - public const int ShopSellConfirmPrice = 10000; - public const int ShopBuyConfirmPrice = 0; - public const int DashKeyInputDelay = 500; - public const int DashSwimConsumeSP = 20; - public const int DashSwimMoveVel = 2; - public const float Glide_Gravity = 0.0f; - public const float Glide_Height_Limit = 0.0f; - public const float Glide_Horizontal_Accelerate = 0.0f; - public const int Glide_Horizontal_Velocity = 500; - public const float Glide_Vertical_Accelerate = 0.0f; - public const int Glide_Vertical_Velocity = 150; - public const int Glide_Vertical_Vibrate_Amplitude = 300; - public const float Glide_Vertical_Vibrate_Frequency = 1500.0f; - public const bool Glide_Effect = true; - public const string Glide_Effect_Run = "CH/Common/Eff_Fly_Balloon_Run.xml"; - public const string Glide_Effect_Idle = "CH/Common/Eff_Fly_Balloon_Idle.xml"; - public const string Glide_Ani_Idle = "Fly_Idle_A"; - public const string Glide_Ani_Left = "Gliding_Left_A"; - public const string Glide_Ani_Right = "Gliding_Right_A"; - public const string Glide_Ani_Run = "Fly_Run_A"; - public const float ClimbVelocityV = 3.0f; - public const float ClimbVelocityH = 1.5f; - public const int StoreExpandMaxSlotCount = 144; - public const int StoreExpandPrice1Row = 330; - public const int StoreDepositMax = 2000000000; - public const int StoreWithdrawMax = 2000000000; - public const int CameraExtraMoveScaleByMonster = 3; - public const int CameraExtraMoveScaleByMap = 2; - public const int CameraExtraDistance = 200; - public const float CameraFinalLoose = 0.08f; - public const float CameraCurrentLoose = 0.002f; - public const float CameraUpdateLoose = 0.03f; - public const int CameraVelocityInPortalMove = 6000; - public const int ConsumeCritical = 5; - public const int MonologueInterval = 15; - public const int MonologueRandom = 10; - public const int MonologueShowTime = 5; - public const int ShowKillCountMin = 3; - public const int UserRevivalInvincibleTick = 5000; - public const int UserRevivalPenaltyPercent = 15; - public const string UserRevivalIconPath = "./data/resource/image/skill/icon/deathPenalty.png"; - public const string UserRevivalInvincibleIconPath = "./data/resource/image/skill/icon/deathInvincible.png"; - public const int GetExpMinVelocity = 250; - public const int GetExpVelocityPer1Length = 2; - public const string GetExpControlValue0 = "-0.5,0,0.25"; - public const string GetExpControlValue1 = "0.5,-0.25,0.5"; - public const string GetExpTargetPCDummyName = "Eff_Body"; - public const float GetExpTimeAcceleration = 1.02f; - public const float GetExpCollisionRadius = 15.0f; - public const int DayToNightTime = 10000; - public const float MyPCDayTiming = 0.5f; - public const float MyPCNightTiming = 0.5f; - public const float BGMTiming = 0.5f; - public const int dayBaseMinute = 1; - public const int dayMinute = 1439; - public const int nightMinute = 1; - public const int SkipFrameGameObject = 5; - public const int SkipFrameDistanceGameObject = 2000; - public const float RegionSkillFadeOutDuration = 0.3f; - public const int PassengerProfileImageSize = 50; - public const int PassengerProfileImageLifeTime = 3; - public const int PassengerProfileImageShowNumber = 3; - public const int PassengerProfileImageShowCooldown = 57; - public const int PassengerProfileImageShowCooldownParty = 57; - public const int PassengerProfileImageShowRange = 400; - public const int QuestRewardSkillSlotQuestID1 = 1010002; - public const int QuestRewardSkillSlotQuestID2 = 1010003; - public const int QuestRewardSkillSlotQuestID3 = 1010004; - public const int QuestRewardSkillSlotQuestID4 = 1010005; - public const int QuestRewardSkillSlotQuestID5 = 1010010; - public const int QuestRewardSkillSlotItemID1 = 40000000; - public const int QuestRewardSkillSlotItemID2 = 40200001; - public const int QuestRewardSkillSlotItemID3 = 20000001; - public const int QuestRewardSkillSlotItemID4 = 40000055; - public const int QuestRewardSkillSlotItemID5 = 40000056; - public const int UGCCameraDefaultSize = 320; - public const int UGCCameraMinSize = 160; - public const int UGCCameraMaxSize = 640; - public const int UGCCameraSnapshotPreviewTime = 3000; - public const int UGCImgUploadSizeLimit = 1024; - public const int UGCImgFileCountCheck = 200; - public const int WindAmp2Cloak = 1500; - public const float WindPeriod2Cloak = 0.7f; - public const float WindPeriodVar2Cloak = 0.4f; - public const int autoTargetingMaxDegree = 210; - public const float VolumeMyPcToNpc = 1.0f; - public const float VolumeMyPcToObject = 0.5f; - public const float VolumeMyPcToBreakableObject = 0.8f; - public const float VolumeNpcToMyPc = 0.7f; - public const float VolumePcToNpc = 0.3f; - public const float VolumePcToBreakableObject = 0.3f; - public const float VolumeNpcToPc = 0.5f; - public const float VolumeOtherPc = 0.9f; - public const int ItemDropLevelMaxBoundary = 1; - public const float moneyTreeDropHeight = 300.0f; - public const float moneyTreeDropBase = 150.0f; - public const int moneyTreeDropRandom = 200; - public const int WhisperIgnoreTime = 1000; - public const int WhisperMaxCount = 3; - public const int WhisperDurationTime = 3000; - public const float BossHitVibrateFreq = 10.0f; - public const float BossHitVibrateAmp = 5.5f; - public const float BossHitVibrateDamping = 0.7f; - public const float BossHitVibrateDuration = 0.1f; - public const float BossHpBarAutoDetectRange = 1500.0f; - public const float BossHpBarDuration = 5.0f; - public const float FindHoldTargetRange = 230.0f; - public const int FindGrabNodeRange = 2000; - public const string UgcShopCharCameraLookat = "0,0,70"; - public const string UgcShopCharCameraPos = "220,0,0"; - public const int UgcShopCharCameraMinDistance = 150; - public const int UgcShopCharCameraZoomVelocity = 700; - public const string UgcShopCubeCameraLookat = "0,0,80"; - public const string UgcShopCubeCameraPos = "420,0,350"; - public const int UgcShopCubeCameraMinDistance = 450; - public const int UgcShopCubeCameraZoomVelocity = 700; - public const string UgcShopRideeCameraLookat = "10,-5,50"; - public const string UgcShopRideeCameraPos = "275,0,150"; - public const int UgcShopRideeCameraMinDistance = 250; - public const int UgcShopRideeCameraZoomVelocity = 700; - public const int FieldCachingCount = 2; - public const float FieldCachingTime = 300.0f; - public const int FieldCachingMaxCount = 4; - public const int FieldUnloadThreshold = 10; - public const float EffectLODOneStepDistance = 450.0f; - public const float EffectLODTwoStepDistance = 500.0f; - public const float EffectLODThreeStepDistance = 550.0f; - public const int TelescopeFindDistance = 200; - public const int BoatPrice = 500; - public const int QuestGuidePageCount = 3; - public const int QuestGuideMaxCount = 60; - public const float CameraInterpolationTime = 0.4f; - public const int OneTimeWeaponItemID = 15000001; - public const int TransparencyCP = 11399999; - public const int TransparencyEY = 11199999; - public const int TransparencyCL = 11499999; - public const int TransparencyPA = 11599999; - public const int TransparencyMT = 11899999; - public const int TransparencyEA = 11299999; - public const int TransparencyFH = 11099999; - public const int TransparencyGL = 11699999; - public const int TransparencyRI = 12099999; - public const int TransparencySH = 11799999; - public const float DefaultDropItemAlpha = 0.3f; - public const float DropItemPickFailHeight = 50.0f; - public const float DropItemPickFailTime = 0.3f; - public const int TaxiStationFindDistance = 200; - public const int TaxiCallDuration = 3000; - public const int TaxiCallBestDriverDuration = 1000; - public const int TaxiCallBestDriverLevel = 25; - public const int AirTaxiCashCallDuration = 500; - public const int AirTaxiMesoCallDuration = 3000; - public const int TradeRequestDuration = 20; - public const int UserPortalInvincibleTick = 5000; - public const string UserPortalInvincibleIconPath = "./data/resource/image/skill/icon/deathInvincible.png"; - public const int SummonRideeDuration = 1000; - public const int WorldMapAdjustTileX = 0; - public const int WorldMapAdjustTileY = 0; - public const float TimeScalePCScale = 0.1f; - public const float TimeScalePCDuration = 1.0f; - public const int GoToHomeCastingTime = 0; - public const int returnHomeSkill = 100000000; - public const int returnHomeSkillMeret = 100000013; - public const int TutorialIntroSkipTime = 5; - public const string AvatarDefaultItemMale = "10200032,10300198"; - public const string AvatarDefaultItemFemale = "10200033,10300199"; - public const int ModelHouse = 62000027; - public const int TalkCooldown = 1000; - public const int AddressPopupDuration = 3000; - public const int MaxFPS = 120; - public const int UGCShopSellMinPrice = 150; - public const int UGCShopSellMaxPrice = 3000; - public const int UGCShopSaleDay = 90; - public const int UGCShopAdFeeMeret = 30; - public const int UGCShopAdHour = 72; - public const int UGCShopSellingRestrictAmount = 200000; - public const int MeretMarketHomeBannerShowTick = 6000; - public const int BlackMarketSellMinPrice = 100; - public const int BlackMarketSellMaxPrice = 500000000; - public const int BlackMarketSellEndDay = 2; - public const int ItemTransferBlackMarketGrade = 4; - public const int UgcBannerCheckTime = 4; - public const int FastChat_CheckTime = 2000; - public const int FastChat_CheckCount = 5; - public const int SameChat_CheckTime = 3000; - public const int SameChat_CheckCount = 5; - public const int SameChat_RestrictTime = 10000; - public const int FastChat_RestrictTime = 30000; - public const int RestrictChat_AddRestrictTime = 10000; - public const int AccumWarning_AddRestrictTime = 60000; - public const int RestrictWarning_ReleaseTime = 10000; - public const int MaxChatLength = 100; - public const int UsingNoPhysXModelUserCount = 10; - public const int UsingNoPhysXModelActorCount = 10; - public const int UsingNoPhysXModelJointCount = 10; - public const int EmotionBoreAnimProbability = 100; - public const float FallMoveSpeed = 1.0f; - public const int GuildCreatePrice = 2000; - public const int GuildCreateMinLevel = 0; - public const int GuildNameLengthMin = 2; - public const int GuildNameLengthMax = 25; - public const int guildFundMax = 20000; - public const float guildFundRate = 0.1f; - public const int guildExpMaxCountForPlayTime = 2; - public const int guildDonateMeso = 10000; - public const string mirrorGuideMoviePath = "Common/Customize_Hat.usm"; - public const string hairGuideMoviePath = "Common/Customize_Hair.usm"; - public const string makeUpGuideMoviePath = "Common/Customize_MakeUp.usm"; - public const int FastShimmerRadius = 600; - public const int FastShimmerHeight = 450; - public const int SmartRecommendNotify_DurationTick = 15000; - public const int BootyPopupDuration = 3000; - public const bool EnableSoundMute = true; - public const int BossKillSoundRange = 1500; - public const string charCreateGuideMoviePath = "Common/Customize_Intro.usm"; - public const int monsterPeakTimeNotifyDuration = 300; - public const int KeyIsDownSkill_MaxDurationTick = 30000; - public const int shadowWorldBuffHpUp = 70000027; - public const int shadowWorldBuffMoveProtect = 70000032; - public const int AirTaxiItemID = 20300003; - public const int PeriodOfMaidEmployment = 30; - public const int MaidReadyToPay = 7; - public const int MaidAffinityMax = 10; - public const int MeretRevivalDebuffCode = 100000001; - public const float MeretRevivalFeeReduceLimit = 0.5f; - public const int MeretConsumeWorldChat = 30; - public const int MeretConsumeChannelChat = 3; - public const int MeretConsumeSuperChat = 200; - public const int pvpBtiRewardItem = 90000006; - public const int pvpBtiRewardWinnerCount = 30; - public const int pvpBtiRewardLoserCount = 10; - public const int PvpFFAReward1Count = 30; - public const int PvpFFAReward2Count = 25; - public const int PvpFFAReward3Count = 20; - public const int PvpFFAReward4Count = 15; - public const int PvpFFAReward5Count = 15; - public const int PvpFFAReward6Count = 15; - public const int PvpFFAReward7Count = 15; - public const int PvpFFAReward8Count = 10; - public const int PvpFFAReward9Count = 10; - public const int PvpFFAReward10Count = 10; - public const int PvpFFARewardItem = 90000006; - public const int PvpFFAAdditionRewardRate = 0; - public const int MailExpiryDays = 30; - public const int WorldMapBossTooltipCount = 30; - public const int ShowNameTagEnchantItemGrade = 4; - public const int ShowNameTagEnchantLevel = 12; - public const int BossNotifyAbsLevel = 1; - public const int RoomExitWaitSecond = 10; - public const int AdditionalMesoMaxRate = 7; - public const int AdditionalExpMaxRate = 9; - public const int HonorTokenMax = 30000; - public const int KarmaTokenMax = 75000; - public const int LuTokenMax = 2000; - public const int HaviTokenMax = 35000; - public const int ReverseCoinMax = 2000; - public const int MentorTokenMax = 10000; // From KMS - public const int MenteeTokenMax = 35000; // From KMS - public const int CharacterDestroyDivisionLevel = 20; - public const int CharacterDestroyWaitSecond = 86400; - public const int BossShimmerScaleUpActiveDistance = 5000; - public const float BossShimmerScaleUpSize = 3.0f; - public const int ShowNameTagSellerTitle = 10000153; - public const int ShowNameTagChampionTitle = 10000152; - public const int ShowNameTagTrophy1000Title = 10000170; - public const int ShowNameTagTrophy2000Title = 10000171; - public const int ShowNameTagTrophy3000Title = 10000172; - public const int ShowNameTagArchitectTitle = 10000158; - public const float SwimDashSpeed = 5.4f; - public const int UserTriggerStateMax = 10; - public const int UserTriggerEnterActionMax = 3; - public const int UserTriggerConditionMax = 3; - public const int UserTriggerConditionActionMax = 3; - public const int PCBangAdditionalEffectID = 100000006; - public const int PCBangAdditionalEffectExp = 1; - public const int PCBangAdditionalEffectMeso = 2; - public const int PCBangItemDefaultPeriod = 1440; - public const int ShadowWorldAutoReviveDeadAction = 1; - public const int GoodInteriorRecommendUICloseTime = 15; - public const string UGCInfoDetailViewPage = "http://www.nexon.net/en/legal/user-generated-content-policy"; - public const int UGCInfoStoryBookID = 39000038; - public const int HomePasswordUsersKickDelay = 10; - public const string TriggerEditorHelpURL = "http://maplestory2.nexon.net/en/news/article/32326"; - public const int QuestRewardSAIgnoreLevel = 10; - public const int RecallCastingTime = 3000; - public const int PartyRecallMeret = 30; - public const float CashCallMedicLeaveDelay = 0.5f; - public const int characterMaxLevel = 99; // Updated - public const int DropSPEPBallMaxLength = 300; - public const int DropSPEPBallTargetZPos = 100; - public const int DropSPEPBallPickUpVel = 250; - public const int DropSPEPBallPickUpGravity = -120; - public const float DropSPEPBallPickUpCompleteRotateTime = 0.05f; - public const int DropSPEPBallPickUpCompleteRotateVel = 5; - public const int EnchantItemBindingRequireLevel = 1; - public const int enchantSuccessBroadcastingLevel = 12; - public const int EnchantEquipIngredientMaxCount = 1000; - public const int EnchantFailStackUsingMaxCount = 100; - public const int EnchantFailStackTakeMaxCount = 1000; - public const int EnchantEquipIngredientOpenLevel = 11; - public const int EnchantEquipIngredientOpenRank = 4; - public const int EnchantEquipIngredientMaxSuccessProb = 3000; - public const int EnchantFailStackOpenLevel = 1; - public const int EnchantFailStackTakeMaxSuccessProb = 10000; - public const int BankCallDuration = 500; - public const string NoticeDialogUrl = "http://nxcache.nexon.net/maplestory2/ingame-banners/index.html"; - public const string NoticeDialogUrlPubTest = "maview:/Game/BannerTest"; - public const int NoticeDialogOpenSeconds = 5000; - public const int RemakeOptionMaxCount = 10; - public const int FisherBoreDuration = 10000; - public const string fishingStartCastingBarText0 = "s_fishing_start_castingbar_text0"; - public const string fishingStartCastingBarText1 = "s_fishing_start_castingbar_text1"; - public const string fishingStartCastingBarText2 = "s_fishing_start_castingbar_text2"; - public const string fishingStartCastingBarText3 = "s_fishing_start_castingbar_text3"; - public const string fishingStartCastingBarText4 = "s_fishing_start_castingbar_text4"; - public const string fishingStartBalloonText0 = "s_fishing_start_balloon_text0"; - public const string fishingStartBalloonText1 = "s_fishing_start_balloon_text1"; - public const string fishingStartBalloonText2 = "s_fishing_start_balloon_text2"; - public const string fishingStartBalloonText3 = "s_fishing_start_balloon_text3"; - public const string fishingStartBalloonText4 = "s_fishing_start_balloon_text4"; - public const string fishingStartBalloonText5 = "s_fishing_start_balloon_text5"; - public const string fishingStartBalloonText6 = "s_fishing_start_balloon_text6"; - public const string fishingStartBalloonText7 = "s_fishing_start_balloon_text7"; - public const string fishingStartBalloonText8 = "s_fishing_start_balloon_text8"; - public const string fishingStartBalloonText9 = "s_fishing_start_balloon_text9"; - public const string fishFightingCastingBarText0 = "s_fishing_fishfighting_castingbar_text0"; - public const string fishFightingBalloonText0 = "s_fishing_fishfighting_balloon_text0"; - public const string fishFightingBalloonText1 = "s_fishing_fishfighting_balloon_text1"; - public const string fishFightingBalloonText2 = "s_fishing_fishfighting_balloon_text2"; - public const string fishFightingBalloonText3 = "s_fishing_fishfighting_balloon_text3"; - public const string fishFightingBalloonText4 = "s_fishing_fishfighting_balloon_text4"; - public const string fishFightingBalloonText5 = "s_fishing_fishfighting_balloon_text5"; - public const int WorldMapSpecialFunctionNpcID0 = 11001276; - public const string WorldMapSpecialFunctionNpcFrame0 = "airship_enabled"; - public const string WorldMapSpecialFunctionNpcTooltip0 = "s_worldmap_special_function_npc0"; - public const int WorldMapSpecialFunctionNpcID1 = 11001403; - public const string WorldMapSpecialFunctionNpcFrame1 = "airship_enabled"; - public const string WorldMapSpecialFunctionNpcTooltip1 = "s_worldmap_special_function_npc0"; - public const int WarpOpenContinent0 = 102; - public const int WarpOpenContinent1 = 103; - public const int WarpOpenContinent2 = 202; - public const int WarpOpenContinent3 = 105; - public const string WriteMusicDetailWebPage = "http://maplestory2.nexon.net/en/news/article/32329"; - public const int WriteMusicStoryBookID = 39000047; - public const int MusicListenInRadius = 900; - public const int MusicListenOutRadius = 2200; - public const int DungeonRoomMaxRewardCount = 99; - public const int DungeonMatchRecommendPickCount = 6; - public const int DungeonSeasonRankMinLevel = 99; - public const int LimitMeretRevival = 1; - public const int MinimapScaleSkipDuration = 5000; - public const int MinimapScaleSkipSplitPixel = 20; - public const int TradeMinMeso = 100; - public const int TradeMaxMeso = 500000000; - public const int TradeFeePercent = 20; - public const int DailyMissionRequireLevel = 50; - public const int MesoMarketBasePrice = 5000000; - public const int MesoMarketProductUnit0 = 5000000; - public const int MesoMarketBuyPayType = 16; - public const int MesoMarketIconType = 0; - public const string MesoMarketTokenDetailUrl = "http://maplestory2.nexon.net/en/news/article/45213"; - public const int BeautyHairShopGotoFieldID = 52000008; - public const int BeautyHairShopGotoPortalID = 1; - public const int BeautyColorShopGotoFieldID = 52000009; - public const int BeautyColorShopGotoPortalID = 1; - public const int BeautyFaceShopGotoFieldID = 52000010; - public const int BeautyFaceShopGotoPortalID = 1; - public const int BeautyStyleExpandSlotPrice = 980; - public const int BeautyStyleMaxSlotCount = 0; - public const int BeautyStyleDefaultSlotCount = 30; - public const int BeautyStyleExpandSlotCount1time = 3; - public const string CashShopFigureAddressPage = "http://maplestory2.nexon.com/cashshop/address"; - public const int NxaCashChargeWebPageWidth = 650; - public const int NxaCashChargeWebPageHeight = 650; - public const int ItemUnLockTime = 259200; - public const int PropertyProtectionTime = 60; - public const string TencentSecurityWebPage = "http://mxd2.qq.com/safe/index.shtml"; - public const int HomeBankCallDuration = 1000; - public const int HomeBankCallCooldown = 30000; - public const string HomeBankCallSequence = "Object_React_A"; - public const int HomeDoctorCallDuration = 1000; - public const int HomeDoctorCallCooldown = 30000; - public const string HomeDoctorCallSequence = "EmergencyHelicopter_A"; - public const int HomeDoctorNpcID = 11001668; - public const int HomeDoctorScriptID0 = 1; - public const int HomeDoctorScriptID1 = 10; - public const int EnchantMasterScriptID = 31; - public const int RestExpAcquireRate = 10000; - public const int RestExpMaxAcquireRate = 100000; - public const int ApartmentPreviewRequireLevel = 50; - public const int ApartmentPreviewRequireQuestID = 90000060; - public const int KeyboardGuideShowLevel = 13; - public const int extendAutoFishMaxCount = 8; - public const int extendAutoPlayInstrumentMaxCount = 8; - public const int ResetShadowBuffMeret = 100; - public const int InventoryExpandPrice1Row = 390; - public const int VIPServicePeriodLimitDay = 100000000; - public const int VIPMarketCommissionSale = 20; - public const int BreedDuration = 767; - public const int HarvestDuration = 767; - public const int RestartQuestStartField = 52000056; - public const int RestartQuestStartFieldRuneblader = 63000006; - public const int RestartQuestStartFieldStriker = 63000015; - public const int RestartQuestStartFieldSoulBinder = 63000035; - public const int QuestPortalKeepTime = 300; - public const string QuestPortalKeepNif = "Eff_Com_Portal_E_Quest"; - public const int QuestPortalDimensionY = 50; - public const int QuestPortalDimensionZ = 350; - public const int QuestPortalSummonTime = 600; - public const int QuestPortalDistanceFromNpc = 200; - public const int PetChangeNameMeret = 100; - public const int PetRunSpeed = 350; - public const int PetPickDistance = 1050; - public const int PetSummonCastTime = 800; - public const int PetBoreTime = 60000; - public const int PetIdleTime = 70000; - public const int PetTiredTime = 10000; - public const int PetSkillTime = 13000; - public const string PetEffectUse = "Pet/Eff_Pet_Use.xml"; - public const string PetEffectSkill = "Pet/Eff_Pet_Skill.xml"; - public const string PetEffectHappy = "Pet/Eff_Pet_Happy.xml"; - public const string PetGemChatBalloon = "pet"; - public const int PetTrapAreaDistanceEasy = 150; - public const int PetTrapAreaDistanceNormal = 150; - public const int PetTrapAreaDistanceHard = 150; - public const string PetTrapAreaEffectEasy = "Pet/Eff_Pet_TrapInstallArea_easy.xml"; - public const string PetTrapAreaEffectNormal = "Pet/Eff_Pet_TrapInstallArea_normal.xml"; - public const string PetTrapAreaEffectHard = "Pet/Eff_Pet_TrapInstallArea_hard.xml"; - public const string PetTrapAreaEffectOtherUser = "Pet/Eff_Pet_TrapArea_OtherUser.xml"; - public const string PetTamingMaxPointEffect = "Pet/Eff_PetTaming_MaxPoint.xml"; - public const string PetTamingAttackMissEffect = "Pet/Eff_PetTaming_Attack_Miss.xml"; - public const string PetTrapDropItemEffect = "Pet/Eff_PetTrap_DropItem.xml"; - public const int TamingPetEscapeTime = 300; - public const int TamingPetMaxPoint = 10000; - public const int PetNameLengthMin = 2; - public const int PetNameLengthMax = 25; - public const int PetTrapDropVisibleDelay = 2000; - public const int PetMaxLevel = 50; - public const string VisitorBookURL = ""; - public const int OneShotSkillID = 19900061; - public const int BagSlotTabGameCount = 48; - public const int BagSlotTabSkinCount = 150; - public const int BagSlotTabSummonCount = 48; - public const int BagSlotTabMaterialCount = 48; - public const int BagSlotTabMasteryCount = 126; - public const int BagSlotTabLifeCount = 48; - public const int BagSlotTabQuestCount = 48; - public const int BagSlotTabGemCount = 48; - public const int BagSlotTabPetCount = 60; - public const int BagSlotTabPetEquipCount = 48; - public const int BagSlotTabActiveSkillCount = 84; - public const int BagSlotTabCoinCount = 48; - public const int BagSlotTabBadgeCount = 60; - public const int BagSlotTabMiscCount = 84; - public const int BagSlotTabLapenshardCount = 48; - public const int BagSlotTabPieceCount = 48; - public const int BagSlotTabGameCountMax = 48; - public const int BagSlotTabSkinCountMax = 150; - public const int BagSlotTabSummonCountMax = 48; - public const int BagSlotTabMaterialCountMax = 48; - public const int BagSlotTabMasteryCountMax = 48; - public const int BagSlotTabLifeCountMax = 48; - public const int BagSlotTabQuestCountMax = 48; - public const int BagSlotTabGemCountMax = 48; - public const int BagSlotTabPetCountMax = 78; - public const int BagSlotTabPetEquipCountMax = 48; - public const int BagSlotTabActiveSkillCountMax = 48; - public const int BagSlotTabCoinCountMax = 48; - public const int BagSlotTabBadgeCountMax = 48; - public const int BagSlotTabMiscCountMax = 48; - public const int BagSlotTabLapenshardCountMax = 48; - public const int BagSlotTabPieceCountMax = 48; - public const int MasteryObjectInteractionDistance = 150; - public const float GatheringObjectMarkOffsetX = 0.0f; - public const float GatheringObjectMarkOffsetY = 0.0f; - public const float BreedingObjectMarkOffsetX = 0.0f; - public const float BreedingObjectMarkOffsetY = 0.0f; - public const int UGCAttention = 0; - public const int UGCInfringementCenter = 1; - public const string CharacterSelectBoreIdleEffect_Ranger = ""; - public const string CharacterSelectBoreIdleEffect_SoulBinder = ""; - public const int DisableSoloPlayHighLevelDungeon = 0; - public const int MergeSmithScriptID = 10; - public const int AutoPressActionKeyDuration = 500; - public const int WebBrowserSizeWidthMin = 438; - public const int WebBrowserSizeWidthMax = 1700; - public const int WebBrowserSizeHeightMin = 708; - public const int WebBrowserSizeHeightMax = 1003; - public const bool WebBrowserEnableSizingButton = true; - public const int MeretAirTaxiPrice = 15; - public const int GlobalPortalMinLevel = 10; - public const int userMassiveExtraRewardMax = 5; - public const int SkillBookTreeAddTabFeeMeret = 990; - public const int MentorRequireLevel = 50; - public const int MenteeRequireLevel = 30; - public const int MentorMaxWaitingCount = 100; - public const int MenteeMaxReceivedCount = 20; - public const int FindDungeonHelpEasyDungeonLevel = 50; - public const int CoupleEffectCheckTick = 5000; - public const int CoupleEffectCheckRadius = 150; - public const int FameContentsSkyFortressMapID0 = 02000421; - public const int FameContentsSkyFortressMapID1 = 02000422; - public const int FameContentsSkyFortressMapID2 = 52010039; - public const int FameContentsSkyFortressMapID3 = 52010040; - public const int AllianceQuestPickCount = 2; - public const int FieldQuestPickCount = 1; - public const int FameContentsSkyFortressGotoMapID = 02000422; - public const int FameContentsSkyFortressGotoPortalID = 3; - public const int FameContentsRequireQuestID = 91000013; - public const int FameExpedContentsRequireQuestID = 50101050; - public const int DailyPetEnchantMaxCount = 24; - public const int MouseCursorHideTime = 30; - public const int EnchantTransformScriptID = 10; - public const float AutoHideGroupAlpha = 0.6f; - public const int AutoHideGroupHitVisibleTick = 3000; - public const int UgcShopCharRotateStartDegreeY = 178; - public const int UgcShopCharRotateEndDegreeY = 8; - public const int SurvivalScanAdditionalID = 71000052; - public const int MapleSurvivalTopNRanking = 5; - public const string MapleSurvivalSeasonRewardUrl = - "http://maplestory2.nexon.net/en/news/article/32249/mushking-royale-championship-rewards"; - public const int TreeWateringEmotion = 10000; - public const int AdventureLevelLimit = 10000; - public const int AdventureLevelLvUpExp = 1000000; - public const int AdventureLevelMaxExp = 1500000; - public const float AdventureLevelFactor = 0.02f; - public const int AdventureExpFactorElite = 10; - public const int AdventureExpFactorBoss = 100; - public const int AdventureLevelStartLevel = 50; - public const int AdventureLevelLvUpRewardItem = 30001133; - public const int NameColorDeadDuration = 2000; - public const float MesoRevivalFeeReduceLimit = 0.5f; - public const float IngredientFeeReduceLimit = 0.5f; - public const int StatPointLimit_str = 100; - public const int StatPointLimit_dex = 100; - public const int StatPointLimit_int = 100; - public const int StatPointLimit_luk = 100; - public const int StatPointLimit_hp = 100; - public const int StatPointLimit_cap = 60; - public const float GamePadRumbleMultiple = 3.0f; - public const int NurturingEatMaxCount = 0; - public const int NurturingPlayMaxCount = 3; - public const string NurturingQuestTag = "NurturingGhostCats"; - public const int NurturingDuration = 3000; - public const int NurturingInteractionDistance = 150; - public const int NurturingEatGrowth = 10; - public const int NurturingPlayGrowth = 10; - public const int NurturingPlayMailId = 19101804; - public const int NurturingPlayMaxGrowth = 3; - public const int NurturingHungryTime = 1000; - public const int SkillPointLimitLevel1 = 80; - public const int SkillPointLimitLevel2 = 70; - public const int SellPriceNormalMax = 4628; - public const int SellPriceRareMax = 5785; - public const int SellPriceEliteMax = 7405; - public const int SellPriceExcellentMax = 9256; - public const int SellPriceLegendaryMax = 11339; - public const int SellPriceArtifactMax = 13653; - public const string RegionServerUrl_de = "http://ugc.maplestory2.nexon.net/region/region_DE.xml"; - public const string RegionServerUrl_en = "http://ugc.maplestory2.nexon.net/region/region_EN.xml"; - public const string RegionServerUrl_bpo = "http://ugc.maplestory2.nexon.net/region/region_BPO.xml"; - public const int HoldAttackSkillID = 10700252; - public const int TooltipLabelMaxWidth = 408; - public const int ClubNameLengthMin = 2; - public const int ClubNameLengthMax = 25; - public const int ClubMaxCount = 3; - public const int UgcNameLengthMin = 3; - public const int UgcNameLengthMax = 25; - public const int UgcTagLengthMax = 12; - public const int ChangeJobLevel = 60; - public const int LapenshardOpenQuestID = 20002391; - public const int MaidNameLengthMin = 1; - public const int MaidNameLengthMax = 35; - public const int MaidDescLengthMin = 1; - public const int MaidDescLengthMax = 35; - public const int GamePadStickMoveValue = 50; - public const int HighlightMenuUsingLevel = 5; - public const int PartyVoteReadyDurationSeconds = 20; - public const int PartyVoteReadyTagExpireSeconds = 10; - public const int ShieldBarOffsetY = -10; - public const int MouseInteractLimitDistance = 2000; - public const int AutoInstallEquipmentMinLevel = 5; - public const int AutoInstallEquipmentMaxLevel = 49; - public const string PartySearchRegisterComboValues = "4,6,10"; - public const int StatScaleMarkingAdditionalEffect = 70000174; - public const string DungeonRewardFailEmotions = "90200001,90200009,90200005,90200018"; - public const int SummonPetSkillID = 82100001; - public const int UGCMapSetItemEffectCountLimit = 10; - public const string DiscordAppID = "555204064091045904"; - public const int ItemBoxMultiOpenMaxCount = 10; - public const int ItemBoxMultiOpenLimitCount = 500; - public const int BuffBalloonDistance = 3800; - public const int PaybackStartDate = 20191024; - public const int PaybackMailId = 50000020; - public const int PaybackMailPeriodDay = 90; - public const int PaybackMaxRewardMeret = 10000; - public const string PaybackGuideUrl = "http://maplestory2.nexon.com/News/Events"; - public const int DummyNpcMale = 2040998; - public const int DummyNpcFemale = 2040999; - public static int DummyNpc(Gender gender) => gender is Gender.Female ? DummyNpcFemale : DummyNpcMale; - #endregion - - #region server table/constants.xml - public const int NextStateTriggerDefaultTick = 100; - public const int UserRevivalPaneltyTick = 3600000; - public const int UserRevivalPaneltyMinLevel = 10; - public const int maxDeadCount = 3; - public const byte hitPerDeadCount = 5; - public const int FishFightingProp = 3000; + // TODO: Remove once NpcMetadataDistance handles these at runtime, since they are now in DB and parsed through file ingest. + #region Server table/constants.xml public const float NpcLastSightRadius = 1800; public const float NpcLastSightHeightUp = 525; public const float NpcLastSightHeightDown = 225; - - public const int RecoveryHPWaitTick = 1000; - public const int RecoverySPWaitTick = 1000; - public const int RecoveryEPWaitTick = 1000; - public const float FallBoundingAddedDistance = 750f; - - public const int UserBattleDurationTick = 5000; - - public const int SystemShopNPCIDConstruct = 11000486; - public const int SystemShopNpcIDUGCDesign = 11000166; - public const int SystemShopNPCIDHonorToken = 11001562; - public const int SystemShopNPCIDFishing = 11001609; - public const int SystemShopNPCIDMentor = 11003561; - public const int SystemShopNPCIDMentee = 11003562; - - public static TimeSpan GlobalCubeSkillIntervalTime = TimeSpan.FromMilliseconds(100); #endregion } diff --git a/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs new file mode 100644 index 000000000..805078afd --- /dev/null +++ b/Maple2.Model/Metadata/ServerTable/ConstantsTable.cs @@ -0,0 +1,959 @@ +using System.Numerics; + +namespace Maple2.Model.Metadata; + +public record ConstantsTable( + float NPCColorScale = 0f, + float NPCDuration = 0f, + float PCColorScale = 0f, + float PCDuration = 0f, + float GetEXPColorScale = 0f, + float GetEXPDuration = 0f, + float AccumulationRatio = 0f, + float NPCRandomDeadPushRate = 0f, + float CustomizingWheelSpeed_Morph = 0f, + float CustomizingWheelSpeed_Item = 0f, + float CustomizingWheelSpeed_Makeup = 0f, + float CustomizingRotationSpeed_Makeup = 0f, + float CustomizingHairFirstPartHighlight = 0f, + float CustomizingHairSecondPartHighlight = 0f, + float LookAtInterval = 0f, + float LookAtDistanceNPC = 0f, + float LookAtDistanceCry = 0f, + bool EnableSkillJumpDown = false, + bool EscapeHitMethodSkill = false, + bool EscapeHitMethodJump = false, + bool EscapeHitMethodMove = false, + bool EscapeHitMoveKeyIsDown = false, + bool CancelSwing_KeyIsDown = false, + bool SkillGlobalCooldown = false, + bool SkillGlobalCooldown_CheckSameSkill = false, + int DamageDistance = 0, + int TalkableDistance = 0, + bool TalkableFrontOnly = false, + int ChatBalloonDistance = 0, + int HpBarDistance = 0, + int EmoticonVisibleDistance = 0, + int RegistUgcDistance = 0, + int RegistUgcDistanceClose = 0, + int ConstructUgcDistance = 0, + int FunctionCubeDistance = 0, + int InteractionDistance = 0, + int HouseMarkShowDistance = 0, + int HouseMarkShowClippingUp = 0, + int HouseMarkShowClippingDown = 0, + int HouseMarkPopupDistance = 0, + int UgcBoundaryStartDistance = 0, + int UgcBoundaryEndDistance = 0, + int DurationForBoundaryDisplay = 0, + TimeSpan UgcHomeSaleWaitingTime = new(), + int UgcContainerExpireDurationNormal = 0, + int UgcContainerExpireDurationCash = 0, + int UgcContainerExpireDurationMerat = 0, + int UgcHomeExtensionNoticeDate = 0, + int UgcHomePasswordExpireDuration = 0, + bool CubeLiftHeightLimitUp = false, + bool CubeLiftHeightLimitDown = false, + int CubeCraftSafetyCapID = 0, + int CubeCraftLightStickLeftID = 0, + int CubeCraftLightStickRightID = 0, + float DropIconDistance = 0f, + int DropIconHeadOffset = 0, + int DropItemMaxLength = 0, + int DropMoneyMaxLength = 0, + float DropItemTargetZPos = 0f, + float DropItemPickUpVel = 0f, + float DropItemPickUpGravity = 0f, + float DropItemPickUpCompleteRotateTime = 0f, + int DropItemPickUpCompleteRotateVel = 0, + int ChatBalloonDuration = 0, + int BoreWaitingTick = 0, + int OffsetPcHpbar = 0, + int OffsetPcNametag = 0, + int OffsetPcChatballoon = 0, + int OffsetPcDamagenumber = 0, + int OffsetPcProfileTag = 0, + float fOffsetOnTombstoneNameTag = 0f, + int OffsetNpcHpBar = 0, + int OffsetNpcNametag = 0, + int OffsetNpcEmoticon = 0, + int OffsetNpcChatBalloon = 0, + int OffsetNpcDamagenumber = 0, + int OffsetNpcMonologue = 0, + int OffsetActionTooltipX = 0, + int OffsetActionTooltipY = 0, + int OffsetPcPopupMenu = 0, + int DamageGap = 0, + int DamageRenderCount = 0, + int DamageRenderTotalCount = 0, + float DamageOtherScale = 0f, + float DamageOtherAlpha = 0f, + int DamageEffectMinHPPercent = 0, + int DamageEffectCriticalPercent = 0, + int ShopSeedResetTime = 0, + int ShopRepurchaseMax = 0, + int ShopSellConfirmPrice = 0, + int ShopBuyConfirmPrice = 0, + float ClimbVelocityV = 0f, + float ClimbVelocityH = 0f, + int StoreExpandMaxSlotCount = 0, + int StoreExpandPrice1Row = 0, + int StoreDepositMax = 0, + int StoreWithdrawMax = 0, + int CameraExtraMoveScaleByMonster = 0, + int CameraExtraMoveScaleByMap = 0, + int CameraExtraDistance = 0, + float CameraFinalLoose = 0f, + float CameraCurrentLoose = 0f, + float CameraUpdateLoose = 0f, + int CameraVelocityInPortalMove = 0, + int MonologueInterval = 0, + int MonologueRandom = 0, + int MonologueShowTime = 0, + int ShowKillCountMin = 0, + int UserRevivalInvincibleTick = 0, + int UserRevivalPaneltyPercent = 0, + string UserRevivalIconPath = "", + string UserRevivalInvincibleIconPath = "", + int GetExpMinVelocity = 0, + int GetExpVelocityPer1Length = 0, + float[] GetExpControlValue0 = null!, + float[] GetExpControlValue1 = null!, + string GetExpTargetPCDummyName = "", + float GetExpTimeAcceleration = 0f, + float GetExpCollisionRadius = 0f, + int SkipFrameGameObject = 0, + int SkipFrameDistanceGameObject = 0, + float RegionSkillFadeOutDuration = 0f, + int PassengerProfileImageSize = 0, + int PassengerProfileImageLifeTime = 0, + int PassengerProfileImageShowNumber = 0, + int PassengerProfileImageShowCooldown = 0, + int PassengerProfileImageShowCooldownParty = 0, + int PassengerProfileImageShowRange = 0, + int UGCCameraDefaultSize = 0, + int UGCCameraMinSize = 0, + int UGCCameraMaxSize = 0, + int UGCCameraSnapshotPreviewTime = 0, + int UGCImgUploadSizeLimit = 0, + int UGCImgFileCountCheck = 0, + int WindAmp2Cloak = 0, + float WindPeriod2Cloak = 0f, + float WindPeriodVar2Cloak = 0f, + float VolumeMyPcToNpc = 0f, + float VolumeMyPcToObject = 0f, + float VolumeMyPcToBreakableObject = 0f, + float VolumeNpcToMyPc = 0f, + float VolumePcToNpc = 0f, + float VolumePcToBreakableObject = 0f, + float VolumeNpcToPc = 0f, + float VolumeOtherPc = 0f, + int ItemDropLevelMaxBoundry = 0, + float moneyTreeDropHeight = 0f, + float moneyTreeDropBase = 0f, + int moneyTreeDropRandom = 0, + int WisperIgnoreTime = 0, + int WisperMaxCount = 0, + int WisperDurationTime = 0, + float BossHpBarAutoDetectRange = 0f, + float BossHpBarDuration = 0f, + float FindHoldTargetRange = 0f, + int FindGrabNodeRange = 0, + Vector3 UgcshopCharCameraLookat = default, + Vector3 UgcshopCharCameraPos = default, + int UgcshopCharCameraMinDistance = 0, + int UgcshopCharCameraZoomVelocity = 0, + Vector3 UgcshopCubeCameraLookat = default, + Vector3 UgcshopCubeCameraPos = default, + int UgcshopCubeCameraMinDistance = 0, + int UgcshopCubeCameraZoomVelocity = 0, + Vector3 UgcshopRideeCameraLookat = default, + Vector3 UgcshopRideeCameraPos = default, + int UgcshopRideeCameraMinDistance = 0, + int UgcshopRideeCameraZoomVelocity = 0, + int FieldCachingCount = 0, + float FieldCachingTime = 0f, + int FieldCachingMaxCount = 0, + int FieldUnloadThreshold = 0, + float EffectLODOneStepDistance = 0f, + float EffectLODTwoStepDistance = 0f, + float EffectLODThreeStepDistance = 0f, + int TelescopeFindDistance = 0, + int BoatPrice = 0, + int QuestGuidePageCount = 0, + int QuestGuideMaxCount = 0, + float CameraInterpolationTime = 0f, + int TransparencyCP = 0, + int TransparencyEY = 0, + int TransparencyCL = 0, + int TransparencyPA = 0, + int TransparencyMT = 0, + int TransparencyEA = 0, + int TransparencyFH = 0, + int TransparencyGL = 0, + int TransparencyRI = 0, + int TransparencySH = 0, + float DefaultDropItemAlpha = 0f, + float DropItemPickFailHeight = 0f, + float DropItemPickFailTime = 0f, + int TaxiStationFindDistance = 0, + int TaxiCallDuration = 0, + int TaxiCallBestDriverDuration = 0, + int TaxiCallBestDriverLevel = 0, + int AirTaxiCashCallDuration = 0, + int AirTaxiMesoCallDuration = 0, + int TradeRequestDuration = 0, + int UserPortalInvincibleTick = 0, + string UserPortalInvincibleIconPath = "", + int SummonRideeDuration = 0, + int WorldMapAdjustTileX = 0, + int WorldMapAdjustTileY = 0, + float TimeScalePCScale = 0f, + float TimeScalePCDuration = 0f, + int GoToHomeCastingTime = 0, + int returnHomeSkill = 0, + int returnHomeSkillMerat = 0, + int TutorialIntroSkipTime = 0, + int[] AvatarDefaultItemMale = null!, + int[] AvatarDefaultItemFemale = null!, + int TalkCooldown = 0, + int AddressPopupDuration = 0, + int MaxFPS = 0, + int UGCShopSellMinPrice = 0, + int UGCShopSellMaxPrice = 0, + int UGCShopSaleDay = 0, + int UGCShopAdFeeMerat = 0, + int UGCShopAdHour = 0, + int UGCShopSellingRestrictAmount = 0, + int MeratMarketHomeBannerShowTick = 0, + long BlackMarketSellMinPrice = 0, + long BlackMarketSellMaxPrice = 0, + int BlackMarketSellEndDay = 0, + int ItemTransferBlackMarketGrade = 0, + int UgcBannerCheckTime = 0, + int FastChat_CheckTime = 0, + int FastChat_CheckCount = 0, + int SameChat_CheckTime = 0, + int SameChat_CheckCount = 0, + int SameChat_RestrictTime = 0, + int FastChat_RestrictTime = 0, + int RestrictChat_AddRestrictTime = 0, + int AccumWarning_AddRestrictTime = 0, + int RestrictWarning_ReleaseTime = 0, + int MaxChatLength = 0, + int EmotionBoreAnimProbability = 0, + float FallMoveSpeed = 0f, + int GuildCreatePrice = 0, + int GuildCreateMinLevel = 0, + int GuildNameLengthMin = 0, + int GuildNameLengthMax = 0, + float guildFundRate = 0f, + int guildExpMaxCountForPlayTime = 0, + int guildDonateMeso = 0, + int guildStorageGiftNeedPeriod = 0, + int guildStorageItemMail = 0, + string mirrorGuideMoviePath = "", + string hairGuideMoviePath = "", + string makeUpGuideMoviePath = "", + int FastShimmerRadius = 0, + int FastShimmerHeight = 0, + int SmartRecommendNotify_DurationTick = 0, + int BootyPopupDuration = 0, + string charCreateGuideMoviePath = "", + int KeyIsDownSkill_MaxDurationTick = 0, + int MaxBuddyCount = 0, + int MaxBlockCount = 0, + int UserPendingRemoveTime = 0, + int HideCubeDuration = 0, + int DailyTrophyPickDiffLevel = 0, + int dailyAchievePickCount = 0, + int MovementEventDistance = 0, + int HomeReturnPortalKeepTime = 0, + string HomeReturnPortalKeepNif = "", + int HomeReturnPortalDimensionY = 0, + TimeSpan GlobalCubeSkillIntervalTime = new(), + int RoomEnterPortalDurationTick = 0, + int NpcBossCubeSkillCreateHeight = 0, + int NPCUpdateTickNoUser = 0, + int NPCUpdateTickWanderIdle = 0, + int NpcSmallSize = 0, + int NpcMidSize = 0, + int NpcBigSize = 0, + int NpcMidCutline = 0, + int NpcBigCutline = 0, + int NpcHpRegenStartTime = 0, + int NpcBossHpRegenStartTime = 0, + int NpcHpRegenPeriod = 0, + float NpcHpRegenPercent = 0f, + float NpcBossHpRegenPercent = 0f, + int NpcCombatAbandon = 0, + int BossCombatAbandon = 0, + int NpcImpossibleCombatAbandon = 0, + int MobLifeTimeExtend = 0, + float CanGetRewardDistance = 0f, + float CanGetRewardEliteDistance = 0f, + float CanGetRewardBossDistance = 0f, + int ExpLevelMaxBoundry = 0, + int CorpseHitDeadAfterCoolDown = 0, + int CorpseHitDropCoolDown = 0, + int CorpseHitDeadAfterAssistBonusCoolDown = 0, + int CorpseHitDropAssistBonusCoolDown = 0, + int UserBattleDurationTick = 0, + int RecoveryHPWaitTick = 0, + int RecoverySPWaitTick = 0, + int RecoveryEPWaitTick = 0, + int timeResetDead = 0, + int maxDeadCount = 0, + byte hitPerDeadCount = 0, + int spawntimePerDeadCount = 0, + int UserRevivalPaneltyTick = 0, + int UserRevivalPaneltyMinLevel = 0, + int revivalRate = 0, + int ChaosPointGetDefault = 0, + int ChaosPointGetPenaltyLevel = 0, + int ChaosPointGetPenalty = 0, + float FallBoundingAddedDistance = 0f, + int BoatDestinationID = 0, + int NpcKillRecoveryProbability = 0, + int InteractRemoveRetryTick = 0, + int TradeDistance = 0, + int PlayTimeDurationTick = 0, + TimeSpan DailyTrophyResetDate = new(), + float NpcLastingSightRadius = 0f, + float NpcLastingSightHeightUp = 0f, + float NpcLastingSightHeightDown = 0f, + int HoldTimeEventTick = 0, + int OnixItemID = 0, + int BindOnixItemID = 0, + int ChaosOnixItemID = 0, + int BindChaosOnixItemID = 0, + int CrystalItemID = 0, + int ChaosCrystalItemID = 0, + int SkillChaosCrystalItemID = 0, + int RedCrystalItemID = 0, + int BlueCrystalItemID = 0, + int GreenCrystalItemID = 0, + int enchantReturnItemID = 0, + int PetCapsuleItemID = 0, + int shadowWorldBuffHpUp = 0, + int shadowWorldBuffMoveProtect = 0, + int pvpZoneUserGlobalDropID = 0, + int pvpZoneUserIndividualDropID = 0, + int pvpZoneUserDropRank = 0, + int shadowWorldUserGlobalDropID = 0, + int shadowWorldUserIndividualDropID = 0, + int shadowWorldUserDropRank = 0, + int userKillDuration = 0, + int userKillSlayerCount = 0, + int userKillRulerCount = 0, + int SystemShopNPCIDConstruct = 0, + int SystemShopNpcIDUGCDesign = 0, + int SystemShopNPCIDHonorToken = 0, + int SystemShopNPCIDFishing = 0, + int SystemShopNPCIDMentor = 0, + int SystemShopNPCIDMentee = 0, + string BlackMarketOpeningTime = "", + string BlackMarketClosingTime = "", + int BlackMarketCollectWaitSecond = 0, + int GmGlideSkillID = 0, + int normalChannelMin = 0, + int normalChannelUser = 0, + int shadowChannelMin = 0, + int shadowChannelUser = 0, + int dynamicChannelDecreaseTick = 0, + int PeriodOfMaidEmployment = 0, + int MaidReadyToPay = 0, + int MaidAffinityMax = 0, + float invokeEffectTargetCountFactor1 = 0f, + float invokeEffectTargetCountFactor2 = 0f, + float invokeEffectTargetCountFactor3 = 0f, + float invokeEffectTargetCountFactor4 = 0f, + float invokeEffectTargetCountFactor5 = 0f, + float invokeEffectTargetCountFactor6 = 0f, + float invokeEffectTargetCountFactor7 = 0f, + float invokeEffectTargetCountFactor8 = 0f, + float invokeEffectTargetCountFactor9 = 0f, + float invokeEffectTargetCountFactor10 = 0f, + int MeratRevivalDebuffCode = 0, + float MeratRevivalFeeReduceLimit = 0f, + int MeratConsumeWorldChat = 0, + int MeratConsumeChannelChat = 0, + int MeratConsumeSuperChat = 0, + int guildPVPMatchingTime = 0, + int guildPVPWinPoint = 0, + int guildPVPLosePoint = 0, + int[] guildPVPAdditionalEffect = null!, + int ModePvPRecoverySkill = 0, + int ModePvPRecoverySP = 0, + int ModePvPInvincibleTime = 0, + int ModePVPAdditionalEffect = 0, + int ModePvPReviveBuff = 0, + int pvpBtiRewardItem = 0, + int pvpBtiRewardWinnerCount = 0, + int pvpBtiRewardLoserCount = 0, + int PvpGuildRewardItem = 0, + int PvpGuildRewardWinnerCount = 0, + int PvpGuildRewardLoserCount = 0, + int[] ModePVPRedArenaAdditionalEffect = null!, + int ModePvPScoreDead = 0, + int ModePvPScoreKill = 0, + int[] ModePVPBloodMineAdditionalEffect = null!, + int pvpFFAShortComboTick = 0, + int pvpFFALongComboTick = 0, + int pvpFFASlayerCount = 0, + int pvpFFARulerCount = 0, + int PvpFFAReward1Count = 0, + int PvpFFAReward2Count = 0, + int PvpFFAReward3Count = 0, + int PvpFFAReward4Count = 0, + int PvpFFAReward5Count = 0, + int PvpFFAReward6Count = 0, + int PvpFFAReward7Count = 0, + int PvpFFAReward8Count = 0, + int PvpFFAReward9Count = 0, + int PvpFFAReward10Count = 0, + int PvpFFARewardItem = 0, + int PvpFFAAdditionRewardRate = 0, + int rankDuelPvpMatchingTime = 0, + int rankDuelPvpMatchingMinGap = 0, + int[] ModePVPDuelRankArenaAdditionalEffect = null!, + int MailExpiryDays = 0, + int MailExpiryDaysPremium = 0, + int MailExpiryDaysBlackMarket = 0, + int MailExpiryDaysFittingDoll = 0, + int decreaseMaidMoodValue = 0, + int decreaseMaidMoodMinutes = 0, + int WorldmapBossTooltipCount = 0, + int ShowNameTagEnchantItemGrade = 0, + int ShowNameTagEnchantLevel = 0, + int BossNotifyAbsLevel = 0, + int RoomExitWaitSecond = 0, + int AdditionalMesoMaxRate = 0, + int AdditionalExpMaxRate = 0, + int HonorTokenMax = 0, + int KarmaTokenMax = 0, + int LuTokenMax = 0, + int HabiTokenMax = 0, + int ReverseCoinMax = 0, + int MentorTokenMax = 0, // From KMS + int MenteeTokenMax = 0, // From KMS + int CharacterDestroyDivisionLevel = 0, + int CharacterDestroyWaitSecond = 0, + int BossShimmerScaleUpActiveDistance = 0, + float BossShimmerScaleUpSize = 0f, + float SwimDashSpeed = 0f, + int UserTriggerStateMax = 0, + int UserTriggerEnterActionMax = 0, + int UserTriggerConditionMax = 0, + int UserTriggerConditionActionMax = 0, + int PCBangAdditionalEffectID = 0, + int PCBangAdditionalEffectExp = 0, + int PCBangAdditionalEffectMeso = 0, + int PCBangItemDefaultPeriod = 0, + int ShadowWorldAutoReviveDeadAction = 0, + int GoodIteriorRecommendUICloseTime = 0, + string UGCInfoDetailViewPage = "", + int UGCInfoStoryBookID = 0, + int HomePasswordUsersKickDelay = 0, + string TriggerEditorHelpURL = "", + int partyBuffID0 = 0, + int partyBuffID1 = 0, + int returnUserPartyBuffID0 = 0, + int returnUserPartyBuffID1 = 0, + int QuestRewardSAIgnoreLevel = 0, + int ugcmapMaxUserCount = 0, + int RecallCastingTime = 0, + string RecallGuildPortalNif = "", + string RecallPartyPortalNif = "", + string RecallWeddingPortalNif = "", + int PartyRecallMerat = 0, + int RecallPortalKeepTime = 0, + int RecallPartyPortalKeepTime = 0, + float CashCallMedicLeaveDelay = 0f, + int characterSlotBaseCount = 0, + int characterSlotMaxExtraCount = 0, + int HitNPCDropCooldown = 0, + int DropSPEPBallMaxLength = 0, + int DropSPEPBallTargetZPos = 0, + int DropSPEPBallPickUpVel = 0, + int DropSPEPBallPickUpGravity = 0, + float DropSPEPBallPickUpCompleteRotateTime = 0f, + int DropSPEPBallPickUpCompleteRotateVel = 0, + int EnchantItemBindingRequireLevel = 0, + int enchantSuccessBroadcastingLevel = 0, + int EnchantEquipIngredientMaxCount = 0, + int EnchantFailStackUsingMaxCount = 0, + int EnchantFailStackTakeMaxCount = 0, + int EnchantEquipIngredientOpenLevel = 0, + int EnchantEquipIngredientOpenRank = 0, + int EnchantEquipIngredientMaxSuccessProb = 0, + int EnchantFailStackOpenLevel = 0, + int EnchantFailStackTakeMaxSuccessProb = 0, + int EnchantExpRefundMail = 0, + int BankCallDuration = 0, + string NoticeDialogUrl = "", + string NoticeDialogUrlPubTest = "", + int NoticeDialogOpenSeconds = 0, + int RemakeOptionMaxCount = 0, + int fishFightingProp = 0, + int fisherBoreDuration = 0, + string fishingStartCastingBarText0 = "", + string fishingStartCastingBarText1 = "", + string fishingStartCastingBarText2 = "", + string fishingStartCastingBarText3 = "", + string fishingStartCastingBarText4 = "", + string fishingStartBalloonText0 = "", + string fishingStartBalloonText1 = "", + string fishingStartBalloonText2 = "", + string fishingStartBalloonText3 = "", + string fishingStartBalloonText4 = "", + string fishingStartBalloonText5 = "", + string fishingStartBalloonText6 = "", + string fishingStartBalloonText7 = "", + string fishingStartBalloonText8 = "", + string fishingStartBalloonText9 = "", + string fishFightingCastingBarText0 = "", + string fishFightingBalloonText0 = "", + string fishFightingBalloonText1 = "", + string fishFightingBalloonText2 = "", + string fishFightingBalloonText3 = "", + string fishFightingBalloonText4 = "", + string fishFightingBalloonText5 = "", + int WorldmapSpecialFunctionNpcID0 = 0, + string WorldmapSpecialFunctionNpcFrame0 = "", + string WorldmapSpecialFunctionNpcTooltip0 = "", + int WorldmapSpecialFunctionNpcID1 = 0, + string WorldmapSpecialFunctionNpcFrame1 = "", + string WorldmapSpecialFunctionNpcTooltip1 = "", + int WarpOpenContinent0 = 0, + int WarpOpenContinent1 = 0, + int WarpOpenContinent2 = 0, + int WarpOpenContinent3 = 0, + string WriteMusicDetailWebPage = "", + int WriteMusicStoryBookID = 0, + int MusicListenInRadius = 0, + int MusicListenOutRadius = 0, + int MusicEnsembleRadius = 0, + int MusicEnsembleDisplayAdditionalID = 0, + int DungeonRandomMatchBuffID = 0, + int DungeonRoomMaxRewardCount = 0, + int DungeonMatchRecommendPickCount = 0, + int DungeonSeasonRankMinLevel = 0, + int ChaosDungeonReviveBossBuff = 0, + int ChaosDungeonReviveUserDebuff = 0, + int LimitMeratRevival = 0, + int MinimapScaleSkipDuration = 0, + int MinimapScaleSkipSplitPixel = 0, + int TradeMinMeso = 0, + int TradeMaxMeso = 0, + int TradeFeePercent = 0, + int GuideQuestDailyPickCountCommon = 0, + int GuideQuestDailyPickCountDungeon = 0, + int GuideQuestDailyPickCountBoss = 0, + int DailyMissionPickCount = 0, + int DailyMissionRequireLevel = 0, + float NearDropDistance = 0f, + float FarDropDistance = 0f, + int MesoMarketBasePrice = 0, + int MesoMarketProductUnit0 = 0, + int MesoMarketProductUnit1 = 0, + int MesoMarketProductUnit2 = 0, + int MesoMarketProductUnit3 = 0, + int MesoMarketProductUnit4 = 0, + int MesoMarketProductUnit5 = 0, + int MesoMarketProductUnit6 = 0, + int MesoMarketProductUnit7 = 0, + int MesoMarketProductUnit8 = 0, + int MesoMarketProductUnit9 = 0, + int MesoMarketBuyPayType = 0, + int MesoMarketIconType = 0, + int BeautyHairShopGotoFieldID = 0, + int BeautyHairShopGotoPortalID = 0, + int BeautyColorShopGotoFieldID = 0, + int BeautyColorShopGotoPortalID = 0, + int BeautyFaceShopGotoFieldID = 0, + int BeautyFaceShopGotoPortalID = 0, + int DropItemSendMail = 0, + int BeautyStyleExpandSlotPrice = 0, + int BeautyStyleMaxSlotCount = 0, + int BeautyStyleDefaultSlotCount = 0, + int BeautyStyleExpandSlotCount1time = 0, + int LuckyBagCouponItemID = 0, + string CashshopFigureAddressPage = "", + string TencentCashChargeWebPage = "", + int TencentCashChargeWebPageWidth = 0, + int TencentCashChargeWebPageHight = 0, + int NxaCashChargeWebPageWidth = 0, + int NxaCashChargeWebPageHight = 0, + int ItemUnLockTime = 0, + int PropertyProtectionTime = 0, + string TencentSecurityWebPage = "", + int HomeBankCallDuration = 0, + int HomeBankCallCooltime = 0, + string HomeBankCallSequence = "", + int HomeDoctorCallDuration = 0, + int HomeDoctorCallCooltime = 0, + string HomeDoctorCallSequence = "", + int HomeDoctorNpcID = 0, + int HomeDoctorScriptID0 = 0, + int HomeDoctorScriptID1 = 0, + int EnchantMasterScriptID = 0, + int RestExpAcquireRate = 0, + int RestExpMaxAcquireRate = 0, + int ApartmentPreviewRequireLevel = 0, + int ApartmentPreviewRequireQuestID = 0, + int CharacterAbilityDefaultPoint = 0, + int CharacterAbilityResetCoolTimeMinute = 0, + int CharacterAbilityResetMeso = 0, + int CharacterAbilityResetMerat = 0, + int CharacterAbilityOpenQuestID = 0, + int KeyboardGuideShowLevel = 0, + int extendAutoFishMaxCount = 0, + int extendAutoPlayInstrumentMaxCount = 0, + int ResetShadowBuffMerat = 0, + int InventoryExpandPrice1Row = 0, + int VIPServicePeriodLimitDay = 0, + int VIPMarketCommitionSale = 0, + int DungeonMatchNormalTimeOutTick = 0, + int ChaosDungeonHallFieldID = 0, + int ReverseRaidDungeonHallFieldID = 0, + int LapentaDungeonHallFieldID = 0, + int ColosseumDungeonHallFieldID = 0, + int BreedDuration = 0, + int HarvestDuration = 0, + int DungeonRewardUnLimitedMesoPercent = 0, + int DungeonRewardUnLimitedExpPercent = 0, + int RestartQuestStartField = 0, + int RestartQuestStartFieldRuneBlader = 0, + int RestartQuestStartFieldStriker = 0, + int RestartQuestStartFieldSoulBinder = 0, + int QuestPortalKeepTime = 0, + string QuestPortalKeepNif = "", + int QuestPortalDimensionY = 0, + int QuestPortalDimensionZ = 0, + int QuestPortalSummonTime = 0, + int QuestPortalDistanceFromNpc = 0, + int PetChangeNameMerat = 0, + int ConstructAuthorityMax = 0, + int HonorTokenResetDayOfWeek = 0, + int HonorTokenResetTimeHour = 0, + int PetLastAttackSkillCheckTick = 0, + string PetBattleAiPath = "", + int PetRunSpeed = 0, + int PetUpdateTargetInterval = 0, + int PetPickDistance = 0, + int PetSummonCastTime = 0, + int PetBoreTime = 0, + int PetIdleTime = 0, + int PetTiredTime = 0, + int PetSkillTime = 0, + string PetEffectUse = "", + string PetEffectSkill = "", + string PetEffectHappy = "", + string PetGemChatBalloon = "", + int PetTrapAreaDistanceEasy = 0, + int PetTrapAreaDistanceNormal = 0, + int PetTrapAreaDistanceHard = 0, + string PetTrapAreaEffectEasy = "", + string PetTrapAreaEffectNormal = "", + string PetTrapAreaEffectHard = "", + string PetTrapAreaEffectOtherUser = "", + string PetTamingMaxPointEffect = "", + string PetTamingAttackMissEffect = "", + string PetTrapDropItemEffect = "", + float TamingPetEscapeRate = 0f, + int TamingPetEscapeTime = 0, + int TamingPetMaxPoint = 0, + float TamingPetValidDistance = 0f, + int PetNameLengthMin = 0, + int PetNameLengthMax = 0, + int PetTrapDropVisibleDelay = 0, + int PetMaxLevel = 0, + string VisitorBookURL = "", + short[] bagSlotTabGameCount = null!, + short[] bagSlotTabSkinCount = null!, + short[] bagSlotTabSummonCount = null!, + short[] bagSlotTabMaterialCount = null!, + short[] bagSlotTabMasteryCount = null!, + short[] bagSlotTabLifeCount = null!, + short[] bagSlotTabQuestCount = null!, + short[] bagSlotTabGemCount = null!, + short[] bagSlotTabPetCount = null!, + short[] bagSlotTabActiveSkillCount = null!, + short[] bagSlotTabCoinCount = null!, + short[] bagSlotTabBadgeCount = null!, + short[] bagSlotTabMiscCount = null!, + short[] bagSlotTabLapenShardCount = null!, + short[] bagSlotTabPieceCount = null!, + int MasteryObjectInteractionDistance = 0, + float GatheringObjectMarkOffsetX = 0f, + float GatheringObjectMarkOffsetY = 0f, + float BreedingObjectMarkOffsetX = 0f, + float BreedingObjectMarkOffsetY = 0f, + int UGCAttention = 0, + int UGCInfringementCenter = 0, + string CharacterSelectBoreIdleEffect_Ranger = "", + string CharacterSelectBoreIdleEffect_SoulBinder = "", + int DisableSoloPlayHighLevelDungeon = 0, + int DungeonMatchCooldownTime = 0, + int DungeonUnitedRewardCountResetLevel = 0, + int MergeSmithScriptID = 0, + int AutoPressActionKeyDuration = 0, + int WebBrowserSizeWidthMin = 0, + int WebBrowserSizeWidthMax = 0, + int WebBrowserSizeHeightMin = 0, + int WebBrowserSizeHeightMax = 0, + bool WebBrowserEnableSizingButton = false, + string LiveBroadcastURL = "", + string TencentWebURL = "", + int SeasonDataSpareCount = 0, + int WebBrowserPopupSizeWidthMin = 0, + int WebBrowserPopupSizeWidthMax = 0, + int WebBrowserPopupSizeHeightMin = 0, + int WebBrowserPopupSizeHeightMax = 0, + int GlobalPortalMinLevel = 0, + int userMassiveExtraRewardMax = 0, + int SkillBookTreeAddTabFeeMerat = 0, + int MentorRequireLevel = 0, + int MenteeRequireLevel = 0, + int MentorMaxWaitingCount = 0, + int MenteeMaxReceivedCount = 0, + int CoupleEffectCheckTick = 0, + int CoupleEffectCheckRadius = 0, + int FameContentsSkyFortressMapID0 = 0, + int FameContentsSkyFortressMapID1 = 0, + int FameContentsSkyFortressMapID2 = 0, + int FameContentsSkyFortressMapID3 = 0, + int AllianceQuestPickCount = 0, + int FieldQuestPickCount = 0, + int FameContentsSkyFortressGotoMapID = 0, + int FameContentsSkyFortressGotoPortalID = 0, + int FameContentsSkyFortressBridgeID = 0, + int FameContentsMissionAttackCount = 0, + int FameContentsFieldQuestPickAccept = 0, + int FameContentsFieldQuestPickComplete = 0, + int DailyPetEnchantMaxCount = 0, + int MouseCursorHideTime = 0, + int EnchantTransformScriptID = 0, + float AutoHideGroupAlpha = 0f, + int AutoHideGroupHitVisibleTick = 0, + int UgcshopCharRotateStartDegreeY = 0, + int UgcshopCharRotateEndDegreeY = 0, + int TreewateringEmotion = 0, + string ShopProbInfoUrl = "", + int AdventureLevelLimit = 0, + int AdventureLevelLvUpExp = 0, + int AdventureLevelMaxExp = 0, + float AdventureLevelFactor = 0f, + int AdventureExpFactorElite = 0, + int AdventureExpFactorBoss = 0, + int AdventureLevelStartLevel = 0, + int AdventureLevelLvUpRewardItem = 0, + int NameColorDeadDuration = 0, + int ConstructExpMaxCount = 0, + float MesoRevivalFeeReduceLimit = 0f, + float IngredientFeeReduceLimit = 0f, + int StatPointLimit_str = 0, + int StatPointLimit_dex = 0, + int StatPointLimit_int = 0, + int StatPointLimit_luk = 0, + int StatPointLimit_hp = 0, + int StatPointLimit_cap = 0, + float GamePadRumbleMultiple = 0f, + int WorldChampionRewardDays = 0, + int NurturingEatMaxCount = 0, + int NurturingPlayMaxCount = 0, + string NurturingQuestTag = "", + int NurturingDuration = 0, + int NurturingInteractionDistance = 0, + int NurturingEatGrowth = 0, + int NurturingPlayGrowth = 0, + int NurturingPlayMailId = 0, + int NurturingPlayMaxGrowth = 0, + int NurturingHungryTime = 0, + int SkillPointLimitLevel1 = 0, + int SkillPointLimitLevel2 = 0, + int SellPriceNormalMax = 0, + int SellPriceRareMax = 0, + int SellPriceEliteMax = 0, + int SellPriceExcellentMax = 0, + int SellPriceLegendaryMax = 0, + int SellPriceArtifactMax = 0, + string RegionServerUrl_de = "", + string RegionServerUrl_en = "", + string RegionServerUrl_bpo = "", + int TooltipLabelMaxWidth = 0, + int ClubNameLengthMin = 0, + int ClubNameLengthMax = 0, + int UgcNameLengthMin = 0, + int UgcNameLengthMax = 0, + int UgcTagLengthMax = 0, + int ChangeJobLevel = 0, + int[] LapenShardOpenQuestID = null!, + int MaidNameLengthMin = 0, + int MaidNameLengthMax = 0, + int MaidDescLengthMin = 0, + int MaidDescLengthMax = 0, + int GamePadStickMoveValue = 0, + int HighlightMenuUsingLevel = 0, + int PartyVoteReadyDurationSeconds = 0, + int PartyVoteReadyTagExpireSeconds = 0, + int ShieldBarOffsetY = 0, + int MouseInteractLimitDistance = 0, + int AutoInstallEquipmentMinLevel = 0, + int AutoInstallEquipmentMaxLevel = 0, + int[] PartySearchRegisterComboValues = null!, + int FieldWarInstanceEnterableDurationSeconds = 0, + int FieldWarRequirePlayerCount = 0, + int FieldWarRequireAchieveID = 0, + int FieldWarRequireLevel = 0, + int StatScaleMarkingAdditionalEffect = 0, + int[] DungeonRewardFailEmotions = null!, + int SummonPetSkillID = 0, + int UGCMapSetItemEffectCountLimit = 0, + int AdventureLevelMissionResetWeekday = 0, + int ItemBoxMultiOpenMaxCount = 0, + int ItemBoxMultiOpenLimitCount = 0, + int BuffBallonDistance = 0, + int PaybackStartDate = 0, + int PaybackSettleMinutes = 0, + int PaybackMarketProductSnList = 0, + int PaybackMailId = 0, + int PaybackMailPeriodDay = 0, + int PaybackMaxRewardMerat = 0, + string PaybackGuideUrl = "", + DateTime PaybackEndDate = default, + int WeddingProposeItemID = 0, + int WeddingInvitationMaxCount = 0, + int WeddingProposeCooltime = 0, + int WeddingDivorceFieldID = 0, + int WeddingInvitationMeso = 0, + int WeddingDivorceMeso = 0, + int WeddingCoolingOffDay = 0, + int WeddingPromiseLimitDay = 0, + int WeddingHallModifyLimitHour = 0, + int WeddingDivorceRequireMarriageDay = 0, + int AdventureProtectRequireLevel = 0, + int AdventureProtectRequireQuest = 0, + int AdventureProtectCharCreateTime = 0, + int PvpOnePunchReward1Count = 0, + int PvpOnePunchReward2Count = 0, + int PvpOnePunchReward3Count = 0, + int PvpOnePunchReward4Count = 0, + int PvpOnePunchReward5Count = 0, + int PvpOnePunchReward6Count = 0, + int PvpOnePunchReward7Count = 0, + int PvpOnePunchReward8Count = 0, + int PvpOnePunchReward9Count = 0, + int PvpOnePunchReward10Count = 0, + int PvpOnePunchRewardItem = 0, + int PvpOnePunchScoreNpcKill = 0, + int SpecialHairShopID = 0, + int[] GemStoneProbList = null!, + int[] SkinGemStoneProbList = null!, + string PersonalInfoAgreementURL = "", + float BothHandLowDamageRatio = 0f, + float BothHandWeaponDamagePenaltyDiv = 0f, + float BothHandGearScorePenaltyDiv = 0f, + string TencentUserConsultationWebPage = "", + string TencentPricavyGuideWebPage = "", + string TencentThirdPartyInformationSharingListWebPage = "", + int PvpOnePunchUserOpenRewardItem = 0, + string TencentCharacterCreateShutdownLeft = "", + string TencentCharacterCreateShutdownRight = "", + int LeadSkillMaxSlot = 0, + float NPCCliffHeight = 0f, + float CustomizingRotationSpeed = 0f, + bool AllowComboAtComboPoint = false, + int AttackRotationSpeed = 0, + int ChaosModeTime = 0, + int ChaosPointPerBlock = 0, + int ChaosPointMaxBlock = 0, + int ChaosPointGetLevel0 = 0, + int ChaosPointGetPoint0 = 0, + int ChaosActionGetLevel0 = 0, + int ChaosActionGetLevel1 = 0, + int ChaosActionGetLevel2 = 0, + int ChaosActionGetLevel3 = 0, + int ChaosActionGetLevel4 = 0, + int OnEnterTriggerClientSideOnlyTick = 0, + int OnEnterTriggerDefaultTick = 0, + int TalkTimeover = 0, + int DropIconVisibleDistance = 0, + int DropMoneyActiveProbability = 0, + int DropMoneyProbability = 0, + int OffsetPcMissionIndicator = 0, + int questHideTime = 0, + int questIntervalTime = 0, + int ShopResetChance = 0, + int DashKeyInputDelay = 0, + int DashSwimConsumeSP = 0, + int DashSwimMoveVel = 0, + float Glide_Gravity = 0f, + float Glide_Height_Limit = 0f, + float Glide_Horizontal_Accelerate = 0f, + int Glide_Horizontal_Velocity = 0, + float Glide_Vertical_Accelerate = 0f, + int Glide_Vertical_Velocity = 0, + int Glide_Vertical_Vibrate_Amplitude = 0, + float Glide_Vertical_Vibrate_Frequency = 0f, + bool Glide_Effect = false, + string Glide_Effect_Run = "", + string Glide_Effect_Idle = "", + string Glide_Ani_Idle = "", + string Glide_Ani_Left = "", + string Glide_Ani_Right = "", + string Glide_Ani_Run = "", + int ConsumeCritical = 0, + int DayToNightTime = 0, + float myPCdayTiming = 0f, + float myPCNightTiming = 0f, + float BGMTiming = 0f, + int dayBaseMinute = 0, + int dayMinute = 0, + int nightMinute = 0, + int QuestRewardSkillSlotQuestID1 = 0, + int QuestRewardSkillSlotQuestID2 = 0, + int QuestRewardSkillSlotQuestID3 = 0, + int QuestRewardSkillSlotQuestID4 = 0, + int QuestRewardSkillSlotQuestID5 = 0, + int QuestRewardSkillSlotItemID1 = 0, + int QuestRewardSkillSlotItemID2 = 0, + int QuestRewardSkillSlotItemID3 = 0, + int QuestRewardSkillSlotItemID4 = 0, + int QuestRewardSkillSlotItemID5 = 0, + int autoTargetingMaxDegree = 0, + float BossHitVibrateFreq = 0f, + float BossHitVibrateAmp = 0f, + float BossHitVibrateDamping = 0f, + float BossHitVibrateDuration = 0f, + int OneTimeWeaponItemID = 0, + int ModelHouse = 0, + int UsingNoPhysXModelUserCount = 0, + int UsingNoPhysXModelActorCount = 0, + int UsingNoPhysXModelJointCount = 0, + int guildFundMax = 0, + bool EnableSoundMute = false, + int BossKillSoundRange = 0, + int monsterPeakTimeNotifyDuration = 0, + int AirTaxiItemID = 0, + int ShowNameTagSellerTitle = 0, + int ShowNameTagChampionTitle = 0, + int ShowNameTagTrophy1000Title = 0, + int ShowNameTagTrophy2000Title = 0, + int ShowNameTagTrophy3000Title = 0, + int ShowNameTagArchitectTitle = 0, + int characterMaxLevel = 0, + string MesoMarketTokenDetailUrl = "", + int OneShotSkillID = 0, + short[] bagSlotTabPetEquipCount = null!, + int MeratAirTaxiPrice = 0, + int FindDungeonHelpEasyDungeonLevel = 0, + int FameContentsRequireQuestID = 0, + int FameExpedContentsRequireQuestID = 0, + int SurvivalScanAdditionalID = 0, + int MapleSurvivalTopNRanking = 0, + string MapleSurvivalSeasonRewardUrl = "", + int HoldAttackSkillID = 0, + string DiscordAppID = "" +) : ServerTable; diff --git a/Maple2.Model/Metadata/ServerTableMetadata.cs b/Maple2.Model/Metadata/ServerTableMetadata.cs index 097a0b79b..484a6715d 100644 --- a/Maple2.Model/Metadata/ServerTableMetadata.cs +++ b/Maple2.Model/Metadata/ServerTableMetadata.cs @@ -47,4 +47,5 @@ public override int GetHashCode() { [JsonDerivedType(typeof(CombineSpawnTable), typeDiscriminator: "combineSpawn")] [JsonDerivedType(typeof(EnchantOptionTable), typeDiscriminator: "enchantOption")] [JsonDerivedType(typeof(UnlimitedEnchantOptionTable), typeDiscriminator: "unlimitedEnchantOption")] +[JsonDerivedType(typeof(ConstantsTable), typeDiscriminator: "constants")] public abstract record ServerTable; diff --git a/Maple2.Server.Game/Commands/PlayerCommand.cs b/Maple2.Server.Game/Commands/PlayerCommand.cs index c1207348a..bf4577f40 100644 --- a/Maple2.Server.Game/Commands/PlayerCommand.cs +++ b/Maple2.Server.Game/Commands/PlayerCommand.cs @@ -116,6 +116,12 @@ private void Handle(InvocationContext ctx, MasteryType masteryType, int level) { private class LevelCommand : Command { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public LevelCommand(GameSession session) : base("level", "Set player level.") { this.session = session; @@ -127,8 +133,8 @@ public LevelCommand(GameSession session) : base("level", "Set player level.") { private void Handle(InvocationContext ctx, short level) { try { - if (level is < 1 or > Constant.characterMaxLevel) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constant.characterMaxLevel}."); + if (level < 1 || level > Constants.characterMaxLevel) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constants.characterMaxLevel}."); return; } @@ -181,6 +187,12 @@ private void Handle(InvocationContext ctx, long exp) { private class PrestigeCommand : Command { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige level") { this.session = session; @@ -191,8 +203,8 @@ public PrestigeCommand(GameSession session) : base("prestige", "Sets prestige le private void Handle(InvocationContext ctx, int level) { try { - if (level is < 1 or > Constant.AdventureLevelLimit) { - ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constant.AdventureLevelLimit}."); + if (level < 1 || level > Constants.AdventureLevelLimit) { + ctx.Console.Error.WriteLine($"Invalid level: {level}. Must be between 1 and {Constants.AdventureLevelLimit}."); return; } diff --git a/Maple2.Server.Game/Manager/BlackMarketManager.cs b/Maple2.Server.Game/Manager/BlackMarketManager.cs index b95252a88..b2314d9c2 100644 --- a/Maple2.Server.Game/Manager/BlackMarketManager.cs +++ b/Maple2.Server.Game/Manager/BlackMarketManager.cs @@ -16,6 +16,12 @@ namespace Maple2.Server.Game.Manager; public sealed class BlackMarketManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly ILogger logger = Log.Logger.ForContext(); public BlackMarketManager(GameSession session) { @@ -63,7 +69,7 @@ public void Add(long itemUid, long price, int quantity) { AccountId = session.AccountId, CharacterId = session.CharacterId, Deposit = depositFee, - ExpiryTime = DateTime.Now.AddDays(Constant.BlackMarketSellEndDay).ToEpochSeconds(), + ExpiryTime = DateTime.Now.AddDays(Constants.BlackMarketSellEndDay).ToEpochSeconds(), Price = price, Quantity = quantity, }; diff --git a/Maple2.Server.Game/Manager/BuddyManager.cs b/Maple2.Server.Game/Manager/BuddyManager.cs index c4787c0db..96c922e93 100644 --- a/Maple2.Server.Game/Manager/BuddyManager.cs +++ b/Maple2.Server.Game/Manager/BuddyManager.cs @@ -17,6 +17,12 @@ namespace Maple2.Server.Game.Manager; public class BuddyManager : IDisposable { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly IDictionary buddies; private readonly IDictionary blocked; @@ -87,7 +93,7 @@ public void SendInvite(string name, string message) { session.Send(BuddyPacket.Invite(error: s_buddy_err_my_id_ex)); return; } - if (buddies.Count >= Constant.MaxBuddyCount) { + if (buddies.Count >= Constants.MaxBuddyCount) { session.Send(BuddyPacket.Invite(error: s_buddy_err_max_buddy)); return; } @@ -113,7 +119,7 @@ public void SendInvite(string name, string message) { try { db.BeginTransaction(); - if (db.CountBuddy(receiverId) >= Constant.MaxBuddyCount) { + if (db.CountBuddy(receiverId) >= Constants.MaxBuddyCount) { session.Send(BuddyPacket.Invite(name: name, error: s_buddy_err_target_full)); return; } @@ -262,7 +268,7 @@ public void SendBlock(long entryId, string name, string message) { session.Send(BuddyPacket.Block(error: s_buddy_err_unknown)); return; } - if (blocked.Count >= Constant.MaxBlockCount) { + if (blocked.Count >= Constants.MaxBlockCount) { session.Send(BuddyPacket.Block(name: name, error: s_buddy_err_max_block)); return; } diff --git a/Maple2.Server.Game/Manager/BuffManager.cs b/Maple2.Server.Game/Manager/BuffManager.cs index f9e378c22..5941c4a88 100644 --- a/Maple2.Server.Game/Manager/BuffManager.cs +++ b/Maple2.Server.Game/Manager/BuffManager.cs @@ -458,8 +458,10 @@ private void EnterField() { } if (Actor.Field.Metadata.Property.Region == MapRegion.ShadowWorld) { - AddBuff(Actor, Actor, Constant.shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); - AddBuff(Actor, Actor, Constant.shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); + if (Actor is FieldPlayer player) { + AddBuff(Actor, Actor, player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffHpUp, 1, Actor.Field.FieldTick); + AddBuff(Actor, Actor, player.Session.ServerTableMetadata.ConstantsTable.shadowWorldBuffMoveProtect, 1, Actor.Field.FieldTick); + } } } diff --git a/Maple2.Server.Game/Manager/ConfigManager.cs b/Maple2.Server.Game/Manager/ConfigManager.cs index 84a83e35b..56e460cac 100644 --- a/Maple2.Server.Game/Manager/ConfigManager.cs +++ b/Maple2.Server.Game/Manager/ConfigManager.cs @@ -18,6 +18,12 @@ public class ConfigManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly IDictionary keyBinds; private short activeHotBar; private readonly List hotBars; @@ -27,6 +33,8 @@ public class ConfigManager { private readonly IList favoriteDesigners; private readonly IDictionary lapenshards; private readonly IDictionary skillCooldowns; + private readonly IDictionary statLimits; + public long DeathPenaltyEndTick { get => session.Player.Value.Character.DeathTick; private set => session.Player.Value.Character.DeathTick = value; @@ -94,7 +102,16 @@ public ConfigManager(GameStorage.Request db, GameSession session) { skillPoints = load.SkillPoint ?? new SkillPoint(); ExplorationProgress = load.ExplorationProgress; - statAttributes = new StatAttributes(); + statLimits = new Dictionary() { + { "StatPointLimit_str", Constants.StatPointLimit_str }, + { "StatPointLimit_dex", Constants.StatPointLimit_dex }, + { "StatPointLimit_int", Constants.StatPointLimit_int }, + { "StatPointLimit_luk", Constants.StatPointLimit_luk }, + { "StatPointLimit_hp", Constants.StatPointLimit_hp }, + { "StatPointLimit_cap", Constants.StatPointLimit_cap } + }; + + statAttributes = new StatAttributes(statLimits); if (load.StatPoints != null) { foreach ((AttributePointSource source, int amount) in load.StatPoints) { if (source == AttributePointSource.Prestige) { @@ -325,7 +342,7 @@ public void LoadRevival() { /// The tick when the penalty ends, or 0 to reset public void UpdateDeathPenalty(long endTick) { // Skip penalty for low level players - if (session.Player.Value.Character.Level < Constant.UserRevivalPaneltyMinLevel) { + if (session.Player.Value.Character.Level < Constants.UserRevivalPaneltyMinLevel) { return; } @@ -422,7 +439,7 @@ public bool TryGetWardrobe(int index, [NotNullWhen(true)] out Wardrobe? wardrobe #region StatPoints public void AllocateStatPoint(BasicAttribute type) { // Invalid stat type. - if (StatAttributes.PointAllocation.StatLimit(type) <= 0) { + if (StatAttributes.PointAllocation.StatLimit(type, statLimits) <= 0) { return; } @@ -432,7 +449,7 @@ public void AllocateStatPoint(BasicAttribute type) { } // Reached limit for allocation. - if (session.Config.statAttributes.Allocation[type] >= StatAttributes.PointAllocation.StatLimit(type)) { + if (session.Config.statAttributes.Allocation[type] >= StatAttributes.PointAllocation.StatLimit(type, statLimits)) { session.Send(NoticePacket.Message("s_char_info_limit_stat_point")); return; } diff --git a/Maple2.Server.Game/Manager/CurrencyManager.cs b/Maple2.Server.Game/Manager/CurrencyManager.cs index 09bf934c8..bb145dd90 100644 --- a/Maple2.Server.Game/Manager/CurrencyManager.cs +++ b/Maple2.Server.Game/Manager/CurrencyManager.cs @@ -9,6 +9,12 @@ namespace Maple2.Server.Game.Manager; public class CurrencyManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private Currency Currency => session.Player.Value.Currency; public CurrencyManager(GameSession session) { @@ -98,57 +104,57 @@ public long this[CurrencyType type] { long overflow; switch (type) { case CurrencyType.ValorToken: - delta = Math.Min(value, Constant.HonorTokenMax) - Currency.ValorToken; - overflow = Math.Max(0, value - Constant.HonorTokenMax); - Currency.ValorToken = Math.Min(value, Constant.HonorTokenMax); + delta = Math.Min(value, Constants.HonorTokenMax) - Currency.ValorToken; + overflow = Math.Max(0, value - Constants.HonorTokenMax); + Currency.ValorToken = Math.Min(value, Constants.HonorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_honor_token, delta); } break; case CurrencyType.Treva: - delta = Math.Min(value, Constant.KarmaTokenMax) - Currency.Treva; - overflow = Math.Max(0, value - Constant.KarmaTokenMax); - Currency.Treva = Math.Min(value, Constant.KarmaTokenMax); + delta = Math.Min(value, Constants.KarmaTokenMax) - Currency.Treva; + overflow = Math.Max(0, value - Constants.KarmaTokenMax); + Currency.Treva = Math.Min(value, Constants.KarmaTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_karma_token, delta); } break; case CurrencyType.Rue: - delta = Math.Min(value, Constant.LuTokenMax) - Currency.Rue; - overflow = Math.Max(0, value - Constant.LuTokenMax); - Currency.Rue = Math.Min(value, Constant.LuTokenMax); + delta = Math.Min(value, Constants.LuTokenMax) - Currency.Rue; + overflow = Math.Max(0, value - Constants.LuTokenMax); + Currency.Rue = Math.Min(value, Constants.LuTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_lu_token, delta); } break; case CurrencyType.HaviFruit: - delta = Math.Min(value, Constant.HaviTokenMax) - Currency.HaviFruit; - overflow = Math.Max(0, value - Constant.HaviTokenMax); - Currency.HaviFruit = Math.Min(value, Constant.HaviTokenMax); + delta = Math.Min(value, Constants.HabiTokenMax) - Currency.HaviFruit; + overflow = Math.Max(0, value - Constants.HabiTokenMax); + Currency.HaviFruit = Math.Min(value, Constants.HabiTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_habi_token, delta); } break; case CurrencyType.ReverseCoin: - delta = Math.Min(value, Constant.ReverseCoinMax) - Currency.ReverseCoin; - overflow = Math.Max(0, value - Constant.ReverseCoinMax); - Currency.ReverseCoin = Math.Min(value, Constant.ReverseCoinMax); + delta = Math.Min(value, Constants.ReverseCoinMax) - Currency.ReverseCoin; + overflow = Math.Max(0, value - Constants.ReverseCoinMax); + Currency.ReverseCoin = Math.Min(value, Constants.ReverseCoinMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_reverse_coin, delta); } break; case CurrencyType.MentorToken: - delta = Math.Min(value, Constant.MentorTokenMax) - Currency.MentorToken; - overflow = Math.Max(0, value - Constant.MentorTokenMax); - Currency.MentorToken = Math.Min(value, Constant.MentorTokenMax); + delta = Math.Min(value, Constants.MentorTokenMax) - Currency.MentorToken; + overflow = Math.Max(0, value - Constants.MentorTokenMax); + Currency.MentorToken = Math.Min(value, Constants.MentorTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentor_token, delta); } break; case CurrencyType.MenteeToken: - delta = Math.Min(value, Constant.MenteeTokenMax) - Currency.MenteeToken; - overflow = Math.Max(0, value - Constant.MenteeTokenMax); - Currency.MenteeToken = Math.Min(value, Constant.MenteeTokenMax); + delta = Math.Min(value, Constants.MenteeTokenMax) - Currency.MenteeToken; + overflow = Math.Max(0, value - Constants.MenteeTokenMax); + Currency.MenteeToken = Math.Min(value, Constants.MenteeTokenMax); if (delta > 0) { session.ConditionUpdate(ConditionType.get_mentee_token, delta); } diff --git a/Maple2.Server.Game/Manager/ExperienceManager.cs b/Maple2.Server.Game/Manager/ExperienceManager.cs index 2300b62ab..75b01c3a8 100644 --- a/Maple2.Server.Game/Manager/ExperienceManager.cs +++ b/Maple2.Server.Game/Manager/ExperienceManager.cs @@ -13,6 +13,13 @@ namespace Maple2.Server.Game.Manager; public sealed class ExperienceManager { private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private long Exp { get => session.Player.Value.Character.Exp; set => session.Player.Value.Character.Exp = value; @@ -89,7 +96,7 @@ public void OnKill(IActor npc) { } private long GetRestExp(long expGained) { - long addedRestExp = Math.Min(RestExp, (long) (expGained * (Constant.RestExpAcquireRate / 10000.0f))); // convert int to a percentage + long addedRestExp = Math.Min(RestExp, (long) (expGained * (Constants.RestExpAcquireRate / 10000.0f))); // convert int to a percentage RestExp = Math.Max(0, RestExp - addedRestExp); Exp += expGained; return addedRestExp; @@ -175,7 +182,7 @@ public void AddMobExp(int moblevel, float modifier = 1f, long additionalExp = 0) public bool LevelUp() { int startLevel = Level; - for (int level = startLevel; level < Constant.characterMaxLevel; level++) { + for (int level = startLevel; level < Constants.characterMaxLevel; level++) { if (!session.TableMetadata.ExpTable.NextExp.TryGetValue(level, out long expToNextLevel) || expToNextLevel > Exp) { break; } @@ -203,7 +210,7 @@ public bool LevelUp() { } private void AddPrestigeExp(ExpType expType) { - if (Level < Constant.AdventureLevelStartLevel) { + if (Level < Constants.AdventureLevelStartLevel) { return; } @@ -211,19 +218,19 @@ private void AddPrestigeExp(ExpType expType) { return; } - if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constant.AdventureLevelLvUpExp) >= Constant.AdventureLevelLvUpExp) { - amount = (long) (amount * Constant.AdventureLevelFactor); + if (PrestigeCurrentExp - PrestigeExp + (PrestigeLevelsGained * Constants.AdventureLevelLvUpExp) >= Constants.AdventureLevelLvUpExp) { + amount = (long) (amount * Constants.AdventureLevelFactor); } PrestigeCurrentExp = Math.Min(amount + PrestigeCurrentExp, long.MaxValue); int startLevel = PrestigeLevel; - for (int level = startLevel; level < Constant.AdventureLevelLimit; level++) { - if (Constant.AdventureLevelLvUpExp > PrestigeCurrentExp) { + for (int level = startLevel; level < Constants.AdventureLevelLimit; level++) { + if (Constants.AdventureLevelLvUpExp > PrestigeCurrentExp) { break; } - PrestigeCurrentExp -= Constant.AdventureLevelLvUpExp; + PrestigeCurrentExp -= Constants.AdventureLevelLvUpExp; PrestigeLevel++; } session.Send(PrestigePacket.AddExp(PrestigeCurrentExp, amount)); @@ -233,7 +240,7 @@ private void AddPrestigeExp(ExpType expType) { } public void PrestigeLevelUp(int amount = 1) { - PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, Constant.AdventureLevelLimit); + PrestigeLevel = Math.Clamp(PrestigeLevel + amount, amount, Constants.AdventureLevelLimit); PrestigeLevelsGained += amount; session.ConditionUpdate(ConditionType.adventure_level, counter: amount); session.ConditionUpdate(ConditionType.adventure_level_up, counter: amount); @@ -242,7 +249,7 @@ public void PrestigeLevelUp(int amount = 1) { } for (int i = 0; i < amount; i++) { - Item? item = session.Field?.ItemDrop.CreateItem(Constant.AdventureLevelLvUpRewardItem); + Item? item = session.Field?.ItemDrop.CreateItem(Constants.AdventureLevelLvUpRewardItem); if (item == null) { break; } diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs index a68abcf28..22e3fcf0c 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.State.cs @@ -214,15 +214,17 @@ public FieldPortal SpawnPortal(Portal portal, int roomId, Vector3 position = def } public FieldPortal SpawnPortal(QuestSummonPortal metadata, FieldNpc npc, FieldPlayer owner) { - var portal = new Portal(NextLocalId(), metadata.MapId, metadata.PortalId, PortalType.Quest, PortalActionType.Interact, npc.Position.Offset(Constant.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, - new Vector3(Constant.QuestPortalDistanceFromNpc, Constant.QuestPortalDimensionY, Constant.QuestPortalDimensionZ), Constant.QuestPortalDistanceFromNpc, + var portal = new Portal(NextLocalId(), metadata.MapId, metadata.PortalId, PortalType.Quest, PortalActionType.Interact, + npc.Position.Offset(Constants.QuestPortalDistanceFromNpc, npc.Rotation), npc.Rotation, + new Vector3(Constants.QuestPortalDistanceFromNpc, Constants.QuestPortalDimensionY, + Constants.QuestPortalDimensionZ), Constants.QuestPortalDistanceFromNpc, 0, true, false, true); var fieldPortal = new FieldQuestPortal(owner, this, NextLocalId(), portal) { Position = portal.Position, Rotation = portal.Rotation, - EndTick = (FieldTick + (long) TimeSpan.FromSeconds(Constant.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), + EndTick = (FieldTick + (long) TimeSpan.FromSeconds(Constants.QuestPortalKeepTime).TotalMilliseconds).Truncate32(), StartTick = FieldTickInt, - Model = Constant.QuestPortalKeepNif, + Model = Constants.QuestPortalKeepNif, }; fieldPortals[fieldPortal.ObjectId] = fieldPortal; @@ -719,7 +721,7 @@ public void RemoveSkillByTriggerId(int triggerId) { private void AddCubeSkill(SkillMetadata metadata, in Vector3 position, in Vector3 rotation = default) { Vector3 adjustedPosition = position; adjustedPosition.Z += FieldAccelerationStructure.BLOCK_SIZE; - var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int) Constant.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { + var fieldSkill = new FieldSkill(this, NextLocalId(), FieldActor, metadata, (int) Constants.GlobalCubeSkillIntervalTime.TotalMilliseconds, adjustedPosition) { Position = adjustedPosition, Rotation = rotation, Source = SkillSource.Cube, diff --git a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs index 4e6cd94fc..5583f5879 100644 --- a/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs +++ b/Maple2.Server.Game/Manager/Field/FieldManager/FieldManager.cs @@ -55,6 +55,7 @@ public partial class FieldManager : IField { public TriggerCache TriggerCache { get; init; } = null!; public Factory FieldFactory { get; init; } = null!; public IGraphicsContext DebugGraphicsContext { get; init; } = null!; + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -71,6 +72,7 @@ public partial class FieldManager : IField { private readonly Thread thread; private readonly List<(FieldPacketHandler handler, GameSession session, ByteReader reader)> queuedPackets; private bool initialized; + public bool Disposed { get; private set; } private readonly ILogger logger = Log.Logger.ForContext(); @@ -364,7 +366,7 @@ public void EnsurePlayerPosition(FieldPlayer player) { return; } - player.FallDamage(Constant.FallBoundingAddedDistance); + player.FallDamage(Constants.FallBoundingAddedDistance); player.MoveToPosition(player.LastGroundPosition.Align() + new Vector3(0, 0, 150f), default); } diff --git a/Maple2.Server.Game/Manager/FishingManager.cs b/Maple2.Server.Game/Manager/FishingManager.cs index aebd61425..318f4b9f0 100644 --- a/Maple2.Server.Game/Manager/FishingManager.cs +++ b/Maple2.Server.Game/Manager/FishingManager.cs @@ -28,6 +28,8 @@ private FieldGuideObject? GuideObject { private FishingTile? selectedTile; private IDictionary tiles = new Dictionary(); + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; + private readonly ILogger logger = Log.ForContext(); public FishingManager(GameSession session, TableMetadataStorage tableMetadata, ServerTableMetadataStorage serverTableMetadata) { @@ -239,12 +241,12 @@ public FishingError Start(Vector3 position) { selectedFish = fishes.Get(); - int fishingTick = Constant.FisherBoreDuration; + int fishingTick = Constants.fisherBoreDuration; bool hasAutoFish = session.Player.Buffs.HasBuff(BuffEventType.AutoFish); // Fishing Success if (Random.Shared.Next(0, 10000) < selectedFish.BaitProbability) { - if (!hasAutoFish && Random.Shared.Next(0, 10000) < Constant.FishFightingProp) { + if (!hasAutoFish && Random.Shared.Next(0, 10000) < Constants.fishFightingProp) { fishFightGame = true; } diff --git a/Maple2.Server.Game/Manager/ItemMergeManager.cs b/Maple2.Server.Game/Manager/ItemMergeManager.cs index 9d2ba918f..4755bc21b 100644 --- a/Maple2.Server.Game/Manager/ItemMergeManager.cs +++ b/Maple2.Server.Game/Manager/ItemMergeManager.cs @@ -14,6 +14,12 @@ public sealed class ItemMergeManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly ILogger logger = Log.Logger.ForContext(); private Item? upgradeItem; @@ -86,7 +92,7 @@ public void SelectCrystal(long itemUid, long crystalUid) { session.Send(ItemMergePacket.Select(mergeSlot, ItemMerge.CostMultiplier(upgradeItem.Rarity))); if (!session.ScriptMetadata.TryGet(Constant.EmpowermentNpc, out ScriptMetadata? script) || - !script.States.TryGetValue(Constant.MergeSmithScriptID, out ScriptState? state)) { + !script.States.TryGetValue(Constants.MergeSmithScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/Manager/Items/InventoryManager.cs b/Maple2.Server.Game/Manager/Items/InventoryManager.cs index 6fecf069b..5d2b6f0b5 100644 --- a/Maple2.Server.Game/Manager/Items/InventoryManager.cs +++ b/Maple2.Server.Game/Manager/Items/InventoryManager.cs @@ -20,6 +20,12 @@ public class InventoryManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly Dictionary tabs; private readonly List delete; @@ -44,44 +50,44 @@ public InventoryManager(GameStorage.Request db, GameSession session) { } } - private static short BaseSize(InventoryType type) { + private short BaseSize(InventoryType type) { return type switch { - InventoryType.Gear => Constant.BagSlotTabGameCount, - InventoryType.Outfit => Constant.BagSlotTabSkinCount, - InventoryType.Mount => Constant.BagSlotTabSummonCount, - InventoryType.Catalyst => Constant.BagSlotTabMaterialCount, - InventoryType.FishingMusic => Constant.BagSlotTabLifeCount, - InventoryType.Quest => Constant.BagSlotTabQuestCount, - InventoryType.Gemstone => Constant.BagSlotTabGemCount, - InventoryType.Misc => Constant.BagSlotTabMiscCount, - InventoryType.LifeSkill => Constant.BagSlotTabMasteryCount, - InventoryType.Pets => Constant.BagSlotTabPetCount, - InventoryType.Consumable => Constant.BagSlotTabActiveSkillCount, - InventoryType.Currency => Constant.BagSlotTabCoinCount, - InventoryType.Badge => Constant.BagSlotTabBadgeCount, - InventoryType.Lapenshard => Constant.BagSlotTabLapenshardCount, - InventoryType.Fragment => Constant.BagSlotTabPieceCount, + InventoryType.Gear => Constants.bagSlotTabGameCount[0], + InventoryType.Outfit => Constants.bagSlotTabSkinCount[0], + InventoryType.Mount => Constants.bagSlotTabSummonCount[0], + InventoryType.Catalyst => Constants.bagSlotTabMaterialCount[0], + InventoryType.FishingMusic => Constants.bagSlotTabLifeCount[0], + InventoryType.Quest => Constants.bagSlotTabQuestCount[0], + InventoryType.Gemstone => Constants.bagSlotTabGemCount[0], + InventoryType.Misc => Constants.bagSlotTabMiscCount[0], + InventoryType.LifeSkill => Constants.bagSlotTabMasteryCount[0], + InventoryType.Pets => Constants.bagSlotTabPetCount[0], + InventoryType.Consumable => Constants.bagSlotTabActiveSkillCount[0], + InventoryType.Currency => Constants.bagSlotTabCoinCount[0], + InventoryType.Badge => Constants.bagSlotTabBadgeCount[0], + InventoryType.Lapenshard => Constants.bagSlotTabLapenShardCount[0], + InventoryType.Fragment => Constants.bagSlotTabPieceCount[0], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } - private static short MaxExpandSize(InventoryType type) { + private short MaxExpandSize(InventoryType type) { return type switch { - InventoryType.Gear => Constant.BagSlotTabGameCountMax, - InventoryType.Outfit => Constant.BagSlotTabSkinCountMax, - InventoryType.Mount => Constant.BagSlotTabSummonCountMax, - InventoryType.Catalyst => Constant.BagSlotTabMaterialCountMax, - InventoryType.FishingMusic => Constant.BagSlotTabLifeCountMax, - InventoryType.Quest => Constant.BagSlotTabQuestCountMax, - InventoryType.Gemstone => Constant.BagSlotTabGemCountMax, - InventoryType.Misc => Constant.BagSlotTabMiscCountMax, - InventoryType.LifeSkill => Constant.BagSlotTabMasteryCountMax, - InventoryType.Pets => Constant.BagSlotTabPetCountMax, - InventoryType.Consumable => Constant.BagSlotTabActiveSkillCountMax, - InventoryType.Currency => Constant.BagSlotTabCoinCountMax, - InventoryType.Badge => Constant.BagSlotTabBadgeCountMax, - InventoryType.Lapenshard => Constant.BagSlotTabLapenshardCountMax, - InventoryType.Fragment => Constant.BagSlotTabPieceCountMax, + InventoryType.Gear => Constants.bagSlotTabGameCount[1], + InventoryType.Outfit => Constants.bagSlotTabSkinCount[1], + InventoryType.Mount => Constants.bagSlotTabSummonCount[1], + InventoryType.Catalyst => Constants.bagSlotTabMaterialCount[1], + InventoryType.FishingMusic => Constants.bagSlotTabLifeCount[1], + InventoryType.Quest => Constants.bagSlotTabQuestCount[1], + InventoryType.Gemstone => Constants.bagSlotTabGemCount[1], + InventoryType.Misc => Constants.bagSlotTabMiscCount[1], + InventoryType.LifeSkill => Constants.bagSlotTabMasteryCount[1], + InventoryType.Pets => Constants.bagSlotTabPetCount[1], + InventoryType.Consumable => Constants.bagSlotTabActiveSkillCount[1], + InventoryType.Currency => Constants.bagSlotTabCoinCount[1], + InventoryType.Badge => Constants.bagSlotTabBadgeCount[1], + InventoryType.Lapenshard => Constants.bagSlotTabLapenShardCount[1], + InventoryType.Fragment => Constants.bagSlotTabPieceCount[1], _ => throw new ArgumentOutOfRangeException($"Invalid InventoryType: {type}"), }; } @@ -557,7 +563,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - if (session.Currency.Meret < Constant.InventoryExpandPrice1Row) { + if (session.Currency.Meret < Constants.InventoryExpandPrice1Row) { session.Send(ItemInventoryPacket.Error(s_cannot_charge_merat)); return false; } @@ -566,7 +572,7 @@ public bool Expand(InventoryType type, int expandRowCount = Constant.InventoryEx return false; } - session.Currency.Meret -= Constant.InventoryExpandPrice1Row; + session.Currency.Meret -= Constants.InventoryExpandPrice1Row; if (session.Player.Value.Unlock.Expand.ContainsKey(type)) { session.Player.Value.Unlock.Expand[type] = newExpand; } else { diff --git a/Maple2.Server.Game/Manager/Items/StorageManager.cs b/Maple2.Server.Game/Manager/Items/StorageManager.cs index 6ee15adf5..a38a2f5e3 100644 --- a/Maple2.Server.Game/Manager/Items/StorageManager.cs +++ b/Maple2.Server.Game/Manager/Items/StorageManager.cs @@ -15,6 +15,13 @@ public sealed class StorageManager : IDisposable { private const int BATCH_SIZE = 10; private readonly GameSession session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly ItemCollection items; private long mesos; private short expand; @@ -189,11 +196,11 @@ public void WithdrawMesos(long amount) { public void Expand() { lock (session.Item) { short newSize = (short) (items.Size + Constant.InventoryExpandRowCount); - if (newSize > Constant.StoreExpandMaxSlotCount) { + if (newSize > Constants.StoreExpandMaxSlotCount) { session.Send(StorageInventoryPacket.Error(s_store_err_expand_max)); return; } - if (session.Currency.Meret < Constant.StoreExpandPrice1Row) { + if (session.Currency.Meret < Constants.StoreExpandPrice1Row) { session.Send(StorageInventoryPacket.Error(s_cannot_charge_merat)); return; } @@ -203,7 +210,7 @@ public void Expand() { return; } - session.Currency.Meret -= Constant.StoreExpandPrice1Row; + session.Currency.Meret -= Constants.StoreExpandPrice1Row; expand += Constant.InventoryExpandRowCount; Load(); diff --git a/Maple2.Server.Game/Manager/SkillManager.cs b/Maple2.Server.Game/Manager/SkillManager.cs index 45f5c5754..15ffa5a7b 100644 --- a/Maple2.Server.Game/Manager/SkillManager.cs +++ b/Maple2.Server.Game/Manager/SkillManager.cs @@ -12,6 +12,12 @@ namespace Maple2.Server.Game.Manager; public class SkillManager { private readonly GameSession session; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public readonly SkillBook SkillBook; public readonly SkillInfo SkillInfo; @@ -121,11 +127,11 @@ public bool ExpandSkillTabs() { if (SkillBook.MaxSkillTabs >= Constant.MaxSkillTabCount) { return false; } - if (session.Currency.Meret < Constant.SkillBookTreeAddTabFeeMeret) { + if (session.Currency.Meret < Constants.SkillBookTreeAddTabFeeMerat) { return false; } - session.Currency.Meret -= Constant.SkillBookTreeAddTabFeeMeret; + session.Currency.Meret -= Constants.SkillBookTreeAddTabFeeMerat; SkillBook.MaxSkillTabs++; session.Send(SkillBookPacket.Expand(SkillBook)); diff --git a/Maple2.Server.Game/Manager/TradeManager.cs b/Maple2.Server.Game/Manager/TradeManager.cs index c356246b8..e917e31a0 100644 --- a/Maple2.Server.Game/Manager/TradeManager.cs +++ b/Maple2.Server.Game/Manager/TradeManager.cs @@ -1,6 +1,7 @@ using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Manager.Items; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; @@ -21,6 +22,12 @@ private enum TradeState { private readonly Trader receiver; private TradeState state; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => sender.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + private readonly object mutex = new(); public TradeManager(GameSession sender, GameSession receiver) { @@ -34,7 +41,7 @@ public TradeManager(GameSession sender, GameSession receiver) { // End the trade if not accepted before |TradeRequestDuration|. string receiverName = receiver.Player.Value.Character.Name; Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(Constant.TradeRequestDuration)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.TradeRequestDuration)); lock (mutex) { if (state is not (TradeState.Requested or TradeState.Acknowledged)) { return; @@ -168,7 +175,7 @@ public void SetMesos(GameSession caller, long amount) { return; } - if (amount > Constant.TradeMaxMeso) { + if (amount > Constants.TradeMaxMeso) { caller.Send(TradePacket.Error(s_trade_error_invalid_meso)); return; } @@ -247,7 +254,7 @@ private void EndTrade(bool success) { } lock (sender.Session.Item) { - long fee = success ? (long) (Constant.TradeFeePercent / 100f * sender.Mesos) : 0; + long fee = success ? (long) (Constants.TradeFeePercent / 100f * sender.Mesos) : 0; sender.Session.Currency.Meso += sender.Mesos - fee; foreach (Item item in sender.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { @@ -260,7 +267,7 @@ private void EndTrade(bool success) { sender.Clear(); } lock (receiver.Session.Item) { - long fee = success ? (long) (Constant.TradeFeePercent / 100f * receiver.Mesos) : 0; + long fee = success ? (long) (Constants.TradeFeePercent / 100f * receiver.Mesos) : 0; receiver.Session.Currency.Meso += receiver.Mesos - fee; foreach (Item item in receiver.Items) { if (item.Transfer?.Flag.HasFlag(TransferFlag.LimitTrade) == true) { diff --git a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs index d2ba0c346..6c29f60c8 100644 --- a/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs +++ b/Maple2.Server.Game/Model/Field/Actor/ActorStateComponent/MovementStateTasks/MovementState.CleanupTask.cs @@ -1,6 +1,7 @@ -using System.Numerics; -using Maple2.Model.Metadata; +using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Model.Enum; +using System.Numerics; using static Maple2.Server.Game.Model.ActorStateComponent.TaskState; namespace Maple2.Server.Game.Model.ActorStateComponent; @@ -10,6 +11,13 @@ public class NpcCleanupPatrolDataTask : NpcTask { private readonly MovementState movement; private readonly FieldPlayer player; private readonly Vector3? lastPosition; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => player.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override bool CancelOnInterrupt => false; public NpcCleanupPatrolDataTask(FieldPlayer player, TaskState taskState, MovementState movement) : base(taskState, NpcTaskPriority.Cleanup) { @@ -33,7 +41,7 @@ protected override void TaskResumed() { return; } - const float maxDistance = Constant.TalkableDistance * Constant.TalkableDistance; + float maxDistance = Constants.TalkableDistance * Constants.TalkableDistance; // find nearest npc FieldNpc? closestNpc = player.Field.Npcs.Values diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs b/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs index 4208ae688..e22b0867d 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldNpc.cs @@ -1,20 +1,21 @@ -using System.Diagnostics.CodeAnalysis; -using System.Numerics; +using DotRecast.Detour.Crowd; +using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Packets; using Maple2.Server.Game.Manager.Field; +using Maple2.Server.Game.Model.ActorStateComponent; +using Maple2.Server.Game.Model.Enum; using Maple2.Server.Game.Model.Skill; using Maple2.Server.Game.Model.State; using Maple2.Server.Game.Packets; +using Maple2.Server.Game.Session; using Maple2.Tools; using Maple2.Tools.Collision; -using Maple2.Server.Game.Session; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; using static Maple2.Server.Game.Model.ActorStateComponent.TaskState; -using Maple2.Server.Game.Model.Enum; -using Maple2.Server.Core.Packets; -using DotRecast.Detour.Crowd; -using Maple2.Server.Game.Model.ActorStateComponent; using MovementState = Maple2.Server.Game.Model.ActorStateComponent.MovementState; namespace Maple2.Server.Game.Model; diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs index 94c2005c5..52f7a4f46 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPet.cs @@ -3,6 +3,7 @@ using Maple2.Model.Enum; using Maple2.Model.Game; using Maple2.Model.Metadata; +using Maple2.Server.Core.Network; using Maple2.Server.Core.Packets; using Maple2.Server.Game.Manager.Field; using Maple2.Server.Game.Model.Skill; @@ -24,6 +25,12 @@ public sealed class FieldPet : FieldNpc { public int TamingPoint; private long tamingTick; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => Field.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public FieldPet(FieldManager field, int objectId, DtCrowdAgent agent, Npc npc, Item pet, PetMetadata petMetadata, string aiPath, FieldPlayer? owner = null) : base(field, objectId, agent, npc, aiPath) { this.owner = owner; Pet = pet; @@ -64,7 +71,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada } var targetRecord = new DamageRecordTarget(this); - int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Constant.TamingPetMaxPoint); + int damageAmount = TamingPoint - Math.Min(TamingPoint + attack.Pet.TamingPoint, Constants.TamingPetMaxPoint); TamingPoint -= damageAmount; targetRecord.AddDamage(damageAmount == 0 ? DamageType.Miss : DamageType.Normal, damageAmount); @@ -73,7 +80,7 @@ public override void ApplyDamage(IActor caster, DamageRecord damage, SkillMetada IsDead = true; OnDeath(); DropItem(caster); - } else if (TamingPoint >= Constant.TamingPetMaxPoint) { // trap has chance to fail + } else if (TamingPoint >= Constants.TamingPetMaxPoint) { // trap has chance to fail IsDead = true; OnDeath(); DropItem(caster); diff --git a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs index ce3b45acf..8287e2c60 100644 --- a/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs +++ b/Maple2.Server.Game/Model/Field/Actor/FieldPlayer.cs @@ -1,20 +1,28 @@ -using System.Numerics; -using Maple2.Model.Enum; +using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.Model.Metadata.FieldEntity; +using Maple2.Server.Core.Network; using Maple2.Server.Game.Manager; using Maple2.Server.Game.Model.Skill; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; using Maple2.Tools.Collision; using Maple2.Tools.Scheduler; +using System.Numerics; namespace Maple2.Server.Game.Model; public class FieldPlayer : Actor { public readonly GameSession Session; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public Vector3 LastGroundPosition; public override StatsManager Stats => Session.Stats; @@ -168,7 +176,7 @@ public override void Update(long tickCount) { return; } - if (InBattle && tickCount - battleTick > Constant.UserBattleDurationTick) { + if (InBattle && tickCount - battleTick > Constants.UserBattleDurationTick) { InBattle = false; } @@ -402,7 +410,7 @@ public bool Revive(bool instant = false) { // Apply death penalty if field requires it if (Field.Metadata.Property.DeathPenalty) { - Session.Config.UpdateDeathPenalty(Field.FieldTick + Constant.UserRevivalPaneltyTick); + Session.Config.UpdateDeathPenalty(Field.FieldTick + Constants.UserRevivalPaneltyTick); } // Update revival condition @@ -474,7 +482,7 @@ public void ConsumeHp(int amount) { Stat stat = Stats.Values[BasicAttribute.Health]; stat.Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Constant.RecoveryHPWaitTick; + lastRegenTime[BasicAttribute.Health] = Field.FieldTick + Constants.RecoveryHPWaitTick; } Session.Send(StatsPacket.Update(this, BasicAttribute.Health)); @@ -547,7 +555,7 @@ public void ConsumeStamina(int amount, bool noRegen = false) { Stats.Values[BasicAttribute.Stamina].Add(-amount); if (!IsDead) { - lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Constant.RecoveryEPWaitTick; + lastRegenTime[BasicAttribute.Stamina] = Field.FieldTick + Constants.RecoveryEPWaitTick; } Field.Broadcast(StatsPacket.Update(this, BasicAttribute.Stamina)); } diff --git a/Maple2.Server.Game/Model/Field/Tombstone.cs b/Maple2.Server.Game/Model/Field/Tombstone.cs index 4eb54f9b7..5f09e481c 100644 --- a/Maple2.Server.Game/Model/Field/Tombstone.cs +++ b/Maple2.Server.Game/Model/Field/Tombstone.cs @@ -7,6 +7,13 @@ namespace Maple2.Server.Game.Model; public class Tombstone : IByteSerializable { public readonly FieldPlayer Owner; + + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + private ConstantsTable Constants => Owner.Session.ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public int ObjectId => Owner.ObjectId; private byte hitsRemaining; public byte HitsRemaining { @@ -26,7 +33,7 @@ public byte HitsRemaining { public Tombstone(FieldPlayer owner, int totalDeaths) { Owner = owner; - TotalHitCount = (byte) Math.Min(totalDeaths * Constant.hitPerDeadCount, Constant.hitPerDeadCount * Constant.maxDeadCount); + TotalHitCount = (byte) Math.Min(totalDeaths * Constants.hitPerDeadCount, Constants.hitPerDeadCount * Constants.maxDeadCount); hitsRemaining = TotalHitCount; } public void WriteTo(IByteWriter writer) { diff --git a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs index dd3a7c5e2..152c36d17 100644 --- a/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/BeautyHandler.cs @@ -25,7 +25,9 @@ public class BeautyHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required ItemMetadataStorage ItemMetadata { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } - + public required NpcMetadataStorage NpcMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -47,12 +49,6 @@ private enum Command : byte { Voucher = 23, } - #region Autofac Autowired - // ReSharper disable MemberCanBePrivate.Global - public required NpcMetadataStorage NpcMetadata { private get; init; } - // ReSharper restore All - #endregion - public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -351,15 +347,15 @@ private void HandleRandomHair(GameSession session, IByteReader packet) { private void HandleWarp(GameSession session, IByteReader packet) { short type = packet.ReadShort(); int mapId = type switch { - 1 => Constant.BeautyHairShopGotoFieldID, - 3 => Constant.BeautyFaceShopGotoFieldID, - 5 => Constant.BeautyColorShopGotoFieldID, + 1 => Constants.BeautyHairShopGotoFieldID, + 3 => Constants.BeautyFaceShopGotoFieldID, + 5 => Constants.BeautyColorShopGotoFieldID, _ => 0, }; int portalId = type switch { - 1 => Constant.BeautyHairShopGotoPortalID, - 3 => Constant.BeautyFaceShopGotoPortalID, - 5 => Constant.BeautyColorShopGotoPortalID, + 1 => Constants.BeautyHairShopGotoPortalID, + 3 => Constants.BeautyFaceShopGotoPortalID, + 5 => Constants.BeautyColorShopGotoPortalID, _ => 0, }; diff --git a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs index a513f2e05..a18d6f710 100644 --- a/Maple2.Server.Game/PacketHandlers/ClubHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ClubHandler.cs @@ -34,6 +34,8 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -71,7 +73,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (clubName.Length is < Constant.ClubNameLengthMin or > Constant.ClubNameLengthMax) { + if (clubName.Length < Constants.ClubNameLengthMin || clubName.Length > Constants.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } @@ -243,7 +245,7 @@ private void HandleRename(GameSession session, IByteReader packet) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } - if (newName.Length is < Constant.ClubNameLengthMin or > Constant.ClubNameLengthMax) { + if (newName.Length < Constants.ClubNameLengthMin || newName.Length > Constants.ClubNameLengthMax) { session.Send(ClubPacket.Error(ClubError.s_club_err_name_value)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs index 0ea79dfe6..24e86e2cd 100644 --- a/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/FunctionCubeHandler.cs @@ -17,6 +17,8 @@ public class FunctionCubeHandler : FieldPacketHandler { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required FunctionCubeMetadataStorage FunctionCubeMetadataStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadataStorage { private get; init; } + private ConstantsTable Constants => ServerTableMetadataStorage.ConstantsTable; // ReSharper restore All #endregion @@ -148,7 +150,7 @@ private void HandleNurturing(GameSession session, FieldFunctionInteract fieldCub // drop the item session.Field.DropItem(fieldCube.Position, fieldCube.Rotation, rewardItem, owner: session.Player, characterId: session.CharacterId); - nurturing.Feed(); + nurturing.Feed(Constants.NurturingEatGrowth); db.UpdateNurturing(session.AccountId, fieldCube.InteractCube); session.Field.Broadcast(FunctionCubePacket.UpdateFunctionCube(fieldCube.InteractCube)); @@ -163,12 +165,12 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return; } - if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= Constant.NurturingPlayMaxCount) { + if (db.CountNurturingForAccount(cube.InteractCube.Metadata.Id, session.AccountId) >= Constants.NurturingEatMaxCount) { session.Send(NoticePacket.Message("You have already played with the maximum number of pets today. TODO: Find correct string id")); // TODO: Find correct string id return; } - if (!nurturing.Play(session.AccountId)) { + if (!nurturing.Play(session.AccountId, Constants.NurturingEatGrowth, Constants.NurturingEatMaxCount)) { return; } @@ -216,7 +218,7 @@ private void HandlePlayNurturing(GameSession session, Plot plot, FieldFunctionIn return null; } - var mail = new Mail { + var mail = new Mail(Constants.MailExpiryDays) { ReceiverId = ownerId, Type = MailType.System, Content = contentId, diff --git a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs index f54052620..da2722e51 100644 --- a/Maple2.Server.Game/PacketHandlers/GuildHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/GuildHandler.cs @@ -65,7 +65,8 @@ private enum Command : byte { public required WorldClient World { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } public required BanWordStorage BanWordStorage { private get; init; } - + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -193,7 +194,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } - if (guildName.Length is < Constant.GuildNameLengthMin or > Constant.GuildNameLengthMax) { + if (guildName.Length < Constants.GuildNameLengthMin || guildName.Length > Constants.GuildNameLengthMax) { session.Send(GuildPacket.Error(GuildError.s_guild_err_name_value)); return; } @@ -208,11 +209,11 @@ private void HandleCreate(GameSession session, IByteReader packet) { return; } - if (session.Player.Value.Character.Level < Constant.GuildCreateMinLevel) { + if (session.Player.Value.Character.Level < Constants.GuildCreateMinLevel) { session.Send(GuildPacket.Error(GuildError.s_guild_err_not_enough_level)); return; } - if (session.Currency.CanAddMeso(-Constant.GuildCreatePrice) != -Constant.GuildCreatePrice) { + if (session.Currency.CanAddMeso(-Constants.GuildCreatePrice) != -Constants.GuildCreatePrice) { session.Send(GuildPacket.Error(GuildError.s_guild_err_no_money)); return; } @@ -236,7 +237,7 @@ private void HandleCreate(GameSession session, IByteReader packet) { } session.Guild.SetGuild(response.Guild); - session.Currency.Meso -= Constant.GuildCreatePrice; + session.Currency.Meso -= Constants.GuildCreatePrice; session.Guild.Load(); session.Send(GuildPacket.Created(guildName)); diff --git a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs index a876688cc..f9cfa9ec9 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeBankHandler.cs @@ -1,9 +1,11 @@ -using Maple2.Model.Metadata; +using Maple2.Database.Storage; +using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Core.Packets; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Session; +using static Maple2.Server.World.Service.World; namespace Maple2.Server.Game.PacketHandlers; @@ -15,12 +17,19 @@ private enum Command : byte { Premium = 2, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { case Command.Home: long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.StorageCooldown + Constant.HomeBankCallCooldown > time) { + if (session.Player.Value.Character.StorageCooldown + Constants.HomeBankCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs index 2b0e28e15..4445496ba 100644 --- a/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/HomeDoctorHandler.cs @@ -1,10 +1,11 @@ -using Maple2.Model.Enum; +using Maple2.Database.Storage; +using Maple2.Model.Enum; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Core.Packets; using Maple2.Server.Game.LuaFunctions; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Session; namespace Maple2.Server.Game.PacketHandlers; @@ -12,10 +13,17 @@ namespace Maple2.Server.Game.PacketHandlers; public class HomeDoctorHandler : FieldPacketHandler { public override RecvOp OpCode => RecvOp.RequestHomeDoctor; + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override void Handle(GameSession session, IByteReader packet) { if (session.Field is null) return; long time = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - if (session.Player.Value.Character.DoctorCooldown + Constant.HomeDoctorCallCooldown > time) { + if (session.Player.Value.Character.DoctorCooldown + Constants.HomeDoctorCallCooltime > time) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs index aac7be7b5..3147c72a6 100644 --- a/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/ItemLockHandler.cs @@ -1,4 +1,5 @@ -using Maple2.Model.Game; +using Maple2.Database.Storage; +using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; @@ -18,6 +19,13 @@ private enum Command : byte { Commit = 3, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -69,7 +77,7 @@ private static void HandleUnstage(GameSession session, IByteReader packet) { } } - private static void HandleCommit(GameSession session, IByteReader packet) { + private void HandleCommit(GameSession session, IByteReader packet) { bool unlock = packet.ReadBool(); // false - lock|true - unlock lock (session.Item) { @@ -86,7 +94,7 @@ private static void HandleCommit(GameSession session, IByteReader packet) { if (unlock && item.IsLocked) { item.IsLocked = false; - item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(Constant.ItemUnLockTime).ToUnixTimeSeconds(); + item.UnlockTime = DateTimeOffset.UtcNow.AddSeconds(Constants.ItemUnLockTime).ToUnixTimeSeconds(); updatedItems.Add(item); } else if (!unlock && !item.IsLocked) { item.IsLocked = true; diff --git a/Maple2.Server.Game/PacketHandlers/JobHandler.cs b/Maple2.Server.Game/PacketHandlers/JobHandler.cs index 6ba30b8ca..38fc316d8 100644 --- a/Maple2.Server.Game/PacketHandlers/JobHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/JobHandler.cs @@ -1,10 +1,12 @@ -using Maple2.Model; +using Maple2.Database.Storage; +using Maple2.Model; using Maple2.Model.Enum; using Maple2.Model.Game; +using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; -using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Model; +using Maple2.Server.Game.PacketHandlers.Field; using Maple2.Server.Game.Packets; using Maple2.Server.Game.Session; diff --git a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs index 763f3f9ac..0682a6d85 100644 --- a/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MeretMarketHandler.cs @@ -21,6 +21,8 @@ public class MeretMarketHandler : FieldPacketHandler { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -151,10 +153,10 @@ private void HandleListItem(GameSession session, IByteReader packet) { Look = item.Template, Blueprint = item.Blueprint ?? new ItemBlueprint(), Status = UgcMarketListingStatus.Active, - PromotionEndTime = promote ? DateTime.Now.AddHours(Constant.UGCShopAdHour).ToEpochSeconds() : 0, - ListingEndTime = DateTime.Now.AddDays(Constant.UGCShopSaleDay).ToEpochSeconds(), + PromotionEndTime = promote ? DateTime.Now.AddHours(Constants.UGCShopAdHour).ToEpochSeconds() : 0, + ListingEndTime = DateTime.Now.AddDays(Constants.UGCShopSaleDay).ToEpochSeconds(), CreationTime = DateTime.Now.ToEpochSeconds(), - Price = Math.Clamp(price, Constant.UGCShopSellMinPrice, Constant.UGCShopSellMaxPrice), + Price = Math.Clamp(price, Constants.UGCShopSellMinPrice, Constants.UGCShopSellMaxPrice), TabId = tabId, }; @@ -198,8 +200,8 @@ private void HandleRelistItem(GameSession session, IByteReader packet) { } item.Price = price; - item.PromotionEndTime = promote ? DateTime.Now.AddHours(Constant.UGCShopAdHour).ToEpochSeconds() : 0; - item.ListingEndTime = DateTime.Now.AddDays(Constant.UGCShopSaleDay).ToEpochSeconds(); + item.PromotionEndTime = promote ? DateTime.Now.AddHours(Constants.UGCShopAdHour).ToEpochSeconds() : 0; + item.ListingEndTime = DateTime.Now.AddDays(Constants.UGCShopSaleDay).ToEpochSeconds(); item.Status = UgcMarketListingStatus.Active; item.Description = description; item.Tags = tags; diff --git a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs index 7fe758d4a..c41840d88 100644 --- a/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/MesoMarketHandler.cs @@ -25,6 +25,13 @@ private enum Command : byte { Purchase = 8, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -55,11 +62,11 @@ private static void HandleLoad(GameSession session) { session.Send(MesoMarketPacket.MyListings(myListings)); } - private static void HandleCreate(GameSession session, IByteReader packet) { + private void HandleCreate(GameSession session, IByteReader packet) { long amount = packet.ReadLong(); long price = packet.ReadLong(); - if (amount != Constant.MesoMarketBasePrice) { + if (amount != Constants.MesoMarketBasePrice) { session.Send(MesoMarketPacket.Error(s_mesoMarket_error_invalidSaleMoney)); return; } @@ -96,7 +103,7 @@ private static void HandleCreate(GameSession session, IByteReader packet) { } session.Player.Value.Account.MesoMarketListed++; - session.Currency.Meso -= Constant.MesoMarketBasePrice; + session.Currency.Meso -= Constants.MesoMarketBasePrice; session.Send(MesoMarketPacket.Create(listing)); session.Send(MesoMarketPacket.Quota(session.Player.Value.Account.MesoMarketListed, session.Player.Value.Account.MesoMarketPurchased)); } diff --git a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs index f1ffb3df4..7dafbd1ca 100644 --- a/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/NpcTalkHandler.cs @@ -32,6 +32,8 @@ private enum Command : byte { // ReSharper disable MemberCanBePrivate.Global public required NpcMetadataStorage NpcMetadata { private get; init; } public required ScriptMetadataStorage ScriptMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -237,7 +239,7 @@ private void HandleEnchant(GameSession session, IByteReader packet) { case ScriptEventType.EnchantSelect: case ScriptEventType.PeachySelect: if (!session.ScriptMetadata.TryGet(npcId, out ScriptMetadata? script) || - !script.States.TryGetValue(Constant.EnchantMasterScriptID, out ScriptState? state)) { + !script.States.TryGetValue(Constants.EnchantMasterScriptID, out ScriptState? state)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs index 0f8688b2e..78c57561c 100644 --- a/Maple2.Server.Game/PacketHandlers/PartyHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/PartyHandler.cs @@ -36,6 +36,8 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -285,7 +287,8 @@ private void HandleVoteKick(GameSession session, IByteReader packet) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constant.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) > + DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; } @@ -315,7 +318,8 @@ private void HandleReadyCheck(GameSession session) { return; } - if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constant.PartyVoteReadyDurationSeconds) > DateTime.Now && session.Party.Party.Vote != null) { + if (session.Party.Party.LastVoteTime.FromEpochSeconds().AddSeconds(Constants.PartyVoteReadyDurationSeconds) > + DateTime.Now && session.Party.Party.Vote != null) { session.Send(PartyPacket.Error(PartyError.s_party_err_already_vote)); return; } diff --git a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs index 4a94bcd3f..f39dcf765 100644 --- a/Maple2.Server.Game/PacketHandlers/QuestHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/QuestHandler.cs @@ -36,6 +36,8 @@ private enum Command : byte { #region Autofac Autowired // ReSharper disable MemberCanBePrivate.Global public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -265,13 +267,13 @@ private static void HandleCompleteFieldMission(GameSession session, IByteReader session.Quest.CompleteFieldMission(mission); } - private static void HandleSkyFortressTeleport(GameSession session) { - if (!session.Quest.TryGetQuest(Constant.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { + private void HandleSkyFortressTeleport(GameSession session) { + if (!session.Quest.TryGetQuest(Constants.FameContentsRequireQuestID, out Quest? quest) || quest.State != QuestState.Completed) { return; } - session.Send(session.PrepareField(Constant.FameContentsSkyFortressGotoMapID, - Constant.FameContentsSkyFortressGotoPortalID) + session.Send(session.PrepareField(Constants.FameContentsSkyFortressGotoMapID, + Constants.FameContentsSkyFortressGotoPortalID) ? FieldEnterPacket.Request(session.Player) : FieldEnterPacket.Error(MigrationError.s_move_err_default)); } diff --git a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs index b9a9df184..fb3d0f49f 100644 --- a/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/SystemShopHandler.cs @@ -1,4 +1,5 @@ -using Maple2.Model.Game; +using Maple2.Database.Storage; +using Maple2.Model.Game; using Maple2.Model.Metadata; using Maple2.PacketLib.Tools; using Maple2.Server.Core.Constants; @@ -19,6 +20,13 @@ private enum Command : byte { Item = 10, } + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + #endregion + public override void Handle(GameSession session, IByteReader packet) { var command = packet.Read(); switch (command) { @@ -47,11 +55,11 @@ private void HandleArena(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDHonorToken, out NpcMetadata? npc)) { return; } - session.Shop.Load(npc.Basic.ShopId, Constant.SystemShopNPCIDHonorToken); + session.Shop.Load(npc.Basic.ShopId, Constants.SystemShopNPCIDHonorToken); session.Send(SystemShopPacket.Arena()); } @@ -61,7 +69,7 @@ private void HandleFishing(GameSession session, IByteReader packet) { session.Shop.ClearActiveShop(); return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDFishing, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDFishing, out NpcMetadata? npc)) { return; } @@ -76,7 +84,7 @@ private void HandleMentee(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDMentee, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDMentee, out NpcMetadata? npc)) { return; } @@ -91,7 +99,7 @@ private void HandleMentor(GameSession session, IByteReader packet) { return; } - if (!session.NpcMetadata.TryGet(Constant.SystemShopNPCIDMentor, out NpcMetadata? npc)) { + if (!session.NpcMetadata.TryGet(Constants.SystemShopNPCIDMentor, out NpcMetadata? npc)) { return; } diff --git a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs index 7c62abf4a..a70daf02a 100644 --- a/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/TaxiHandler.cs @@ -31,6 +31,8 @@ private enum Command : byte { public required MapMetadataStorage MapMetadata { private get; init; } public required MapEntityStorage EntityMetadata { private get; init; } public required WorldMapGraphStorage WorldMapGraph { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -136,12 +138,12 @@ private void HandleMeretAirTaxi(GameSession session, IByteReader packet) { return; } - if (session.Currency.Meret < Constant.MeretAirTaxiPrice) { - session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_meso)); + if (session.Currency.Meret < Constants.MeratAirTaxiPrice) { + session.Send(NoticePacket.MessageBox(StringCode.s_err_lack_merat)); return; } - session.Currency.Meret -= Constant.MeretAirTaxiPrice; + session.Currency.Meret -= Constants.MeratAirTaxiPrice; session.Send(session.PrepareField(mapId) ? FieldEnterPacket.Request(session.Player) diff --git a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs index 40ecdfe2a..2ed7d7bc0 100644 --- a/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs +++ b/Maple2.Server.Game/PacketHandlers/UserChatHandler.cs @@ -22,6 +22,8 @@ public class UserChatHandler : FieldPacketHandler { // ReSharper disable MemberCanBePrivate.Global public required WorldClient World { private get; init; } public required GameStorage GameStorage { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -180,7 +182,7 @@ private void HandleWorld(GameSession session, string message, ICollection } session.Send(NoticePacket.Notice(NoticePacket.Flags.Alert | NoticePacket.Flags.Message, StringCode.s_worldchat_use_coupon)); } else { - int meretCost = Constant.MeretConsumeWorldChat; + int meretCost = Constants.MeratConsumeWorldChat; if (session.FindEvent(GameEventType.SaleChat).FirstOrDefault()?.Metadata.Data is SaleChat gameEvent) { meretCost -= (int) (meretCost * Convert.ToSingle(gameEvent.WorldChatDiscount) / 10000); } @@ -215,7 +217,7 @@ private void HandleChannel(GameSession session, string message, ICollection item.Enchant?.Enchants) { + if (session.ServerTableMetadata.ConstantsTable.enchantSuccessBroadcastingLevel > item.Enchant?.Enchants) { return; } diff --git a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs index 70bc77d38..6cd5bcda3 100644 --- a/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs +++ b/Maple2.Server.Login/PacketHandlers/CharacterManagementHandler.cs @@ -45,6 +45,8 @@ private enum Command : byte { public required BanWordStorage BanWordStorage { private get; init; } public required ItemMetadataStorage ItemMetadata { private get; init; } public required TableMetadataStorage TableMetadata { private get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { private get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; // ReSharper restore All #endregion @@ -218,8 +220,8 @@ private void HandleDelete(LoginSession session, IByteReader packet) { return; } - if (character.Level >= Constant.CharacterDestroyDivisionLevel) { - character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(Constant.CharacterDestroyWaitSecond).ToUnixTimeSeconds(); + if (character.Level >= Constants.CharacterDestroyDivisionLevel) { + character.DeleteTime = DateTimeOffset.UtcNow.AddSeconds(Constants.CharacterDestroyWaitSecond).ToUnixTimeSeconds(); if (db.UpdateDelete(session.AccountId, characterId, character.DeleteTime)) { session.Send(CharacterListPacket.BeginDelete(characterId, character.DeleteTime)); } else { diff --git a/Maple2.Server.World/Containers/GlobalPortalManager.cs b/Maple2.Server.World/Containers/GlobalPortalManager.cs index bc09af40f..ce3705f9b 100644 --- a/Maple2.Server.World/Containers/GlobalPortalManager.cs +++ b/Maple2.Server.World/Containers/GlobalPortalManager.cs @@ -9,9 +9,15 @@ namespace Maple2.Server.World.Containers; public class GlobalPortalManager : IDisposable { + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + // ReSharper disable UnusedAutoPropertyAccessor.Global public required GameStorage GameStorage { get; init; } public required ServerTableMetadataStorage ServerTableMetadata { get; init; } public required ChannelClientLookup ChannelClients { get; init; } + // ReSharper restore All + // ReSharper restore UnusedAutoPropertyAccessor.Global + #endregion public readonly GlobalPortal Portal; public int Channel; diff --git a/Maple2.Server.World/Containers/PartyLookup.cs b/Maple2.Server.World/Containers/PartyLookup.cs index 29ece3e4c..a3249b955 100644 --- a/Maple2.Server.World/Containers/PartyLookup.cs +++ b/Maple2.Server.World/Containers/PartyLookup.cs @@ -1,23 +1,29 @@ using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; +using Maple2.Database.Storage; using Maple2.Model.Error; using Maple2.Model.Game; using Maple2.Model.Game.Party; +using Maple2.Model.Metadata; namespace Maple2.Server.World.Containers; public class PartyLookup : IDisposable { + #region Autofac Autowired private readonly ChannelClientLookup channelClients; private readonly PlayerInfoLookup playerLookup; private readonly PartySearchLookup partySearchLookup; + private readonly ServerTableMetadataStorage serverTableMetadata; + #endregion private readonly ConcurrentDictionary parties; private int nextPartyId = 1; - public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLookup, PartySearchLookup partySearchLookup) { + public PartyLookup(ChannelClientLookup channelClients, PlayerInfoLookup playerLookup, PartySearchLookup partySearchLookup, ServerTableMetadataStorage serverTableMetadata) { this.channelClients = channelClients; this.playerLookup = playerLookup; this.partySearchLookup = partySearchLookup; + this.serverTableMetadata = serverTableMetadata; parties = new ConcurrentDictionary(); } @@ -59,6 +65,7 @@ public PartyError Create(long leaderId, out int partyId) { var manager = new PartyManager(party) { ChannelClients = channelClients, PartyLookup = this, + ServerTableMetadata = serverTableMetadata }; if (!parties.TryAdd(partyId, manager)) { diff --git a/Maple2.Server.World/Containers/PartyManager.cs b/Maple2.Server.World/Containers/PartyManager.cs index 837254313..6532a099c 100644 --- a/Maple2.Server.World/Containers/PartyManager.cs +++ b/Maple2.Server.World/Containers/PartyManager.cs @@ -1,5 +1,6 @@ using System.Collections.Concurrent; using Grpc.Core; +using Maple2.Database.Storage; using Maple2.Model.Enum; using Maple2.Model.Error; using Maple2.Model.Game; @@ -11,8 +12,17 @@ namespace Maple2.Server.World.Containers; public class PartyManager : IDisposable { + #region Autofac Autowired + // ReSharper disable MemberCanBePrivate.Global + // ReSharper disable UnusedAutoPropertyAccessor.Global public required ChannelClientLookup ChannelClients { get; init; } public required PartyLookup PartyLookup { get; init; } + public required ServerTableMetadataStorage ServerTableMetadata { get; init; } + private ConstantsTable Constants => ServerTableMetadata.ConstantsTable; + // ReSharper restore All + // ReSharper restore UnusedAutoPropertyAccessor.Global + #endregion + public readonly Party Party; private readonly ConcurrentDictionary pendingInvites; @@ -282,7 +292,7 @@ public PartyError StartReadyCheck(long requestorId) { }); Task.Factory.StartNew(() => { - Thread.Sleep(TimeSpan.FromSeconds(Constant.PartyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.PartyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } @@ -394,7 +404,7 @@ public PartyError VoteKick(long requestorId, long targetId) { Task.Factory.StartNew(() => { // TODO: The duration is wrong. - Thread.Sleep(TimeSpan.FromSeconds(Constant.PartyVoteReadyDurationSeconds)); + Thread.Sleep(TimeSpan.FromSeconds(Constants.PartyVoteReadyDurationSeconds)); if (Party.Vote == null) { return; } diff --git a/Maple2.Server.World/Program.cs b/Maple2.Server.World/Program.cs index 1120e7481..1832966fe 100644 --- a/Maple2.Server.World/Program.cs +++ b/Maple2.Server.World/Program.cs @@ -86,6 +86,7 @@ .OnActivated(e => { var channelLookup = e.Context.Resolve(); var playerInfoLookup = e.Context.Resolve(); + var partyLookup = e.Context.Resolve(); channelLookup.InjectDependencies(e.Instance, playerInfoLookup); }) .SingleInstance(); diff --git a/Maple2.Server.World/WorldServer.cs b/Maple2.Server.World/WorldServer.cs index e283c32de..634dedf44 100644 --- a/Maple2.Server.World/WorldServer.cs +++ b/Maple2.Server.World/WorldServer.cs @@ -18,6 +18,7 @@ namespace Maple2.Server.World; public class WorldServer { + #region Autofac Autowired private readonly GameStorage gameStorage; private readonly ChannelClientLookup channelClients; private readonly ServerTableMetadataStorage serverTableMetadata; @@ -25,6 +26,9 @@ public class WorldServer { private readonly GlobalPortalLookup globalPortalLookup; private readonly WorldBossLookup worldBossLookup; private readonly PlayerInfoLookup playerInfoLookup; + private ConstantsTable Constants => serverTableMetadata.ConstantsTable; + #endregion + private readonly Thread thread; private readonly Thread heartbeatThread; private readonly EventQueue scheduler; @@ -422,7 +426,7 @@ public void FieldPlotExpiryCheck() { SetPlotAsPending(db, plot); forfeit = true; // mark as open when 3 days has passed since the expiry time - } else if (plot.OwnerId == 0 && plot.ExpiryTime + Constant.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { + } else if (plot.OwnerId == 0 && plot.ExpiryTime + Constants.UgcHomeSaleWaitingTime.TotalSeconds < DateTimeOffset.UtcNow.ToUnixTimeSeconds()) { logger.Information("Marking plot {PlotId} as open (no owner)", plot.Id); db.SetPlotOpen(plot.Id); // Mark as open } else { @@ -449,7 +453,7 @@ public void FieldPlotExpiryCheck() { } // Schedule next check for the next soonest expiry - PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(); + PlotInfo? nextPlot = db.GetSoonestPlotFromExpire(Constants.UgcHomeSaleWaitingTime); TimeSpan delay; if (nextPlot is not null) { DateTimeOffset nextExpiry = DateTimeOffset.FromUnixTimeSeconds(nextPlot.ExpiryTime);