using System.Text.Json.Serialization; using SPTarkov.Server.Core.Models.Common; using SPTarkov.Server.Core.Models.Enums; using SPTarkov.Server.Core.Utils.Collections; using SPTarkov.Server.Core.Utils.Json.Converters; namespace SPTarkov.Server.Core.Models.Spt.Config; public record QuestConfig : BaseConfig { [JsonPropertyName("kind")] public override string Kind { get; set; } = "spt-quest"; /// /// Hours to get/redeem items from quest mail keyed by profile type /// [JsonPropertyName("mailRedeemTimeHours")] public required Dictionary MailRedeemTimeHours { get; set; } /// /// Collection of quests by id only available to usec /// [JsonPropertyName("usecOnlyQuests")] public required HashSet UsecOnlyQuests { get; set; } /// /// Collection of quests by id only available to bears /// [JsonPropertyName("bearOnlyQuests")] public required HashSet BearOnlyQuests { get; set; } /// /// Quests that the keyed game version do not see/access /// [JsonPropertyName("profileBlacklist")] public required Dictionary> ProfileBlacklist { get; set; } /// /// key=questid, gameversions that can see/access quest /// [JsonPropertyName("profileWhitelist")] public required Dictionary> ProfileWhitelist { get; set; } /// /// Holds repeatable quest template ids for pmc's and scav's /// [JsonPropertyName("repeatableQuestTemplateIds")] public required RepeatableQuestTemplates RepeatableQuestTemplates { get; set; } /// /// Show non-seasonal quests be shown to players /// [JsonPropertyName("showNonSeasonalEventQuests")] public required bool ShowNonSeasonalEventQuests { get; set; } /// /// Collection of event quest data keyed by quest id. /// [JsonPropertyName("eventQuests")] public required Dictionary EventQuests { get; set; } /// /// List of repeatable quest configs for; daily, weekly, and daily scav. /// [JsonPropertyName("repeatableQuests")] public required List RepeatableQuests { get; set; } /// /// Maps internal map names to their mongoId: Key - internal :: val - Mongoid /// [JsonPropertyName("locationIdMap")] public required Dictionary LocationIdMap { get; set; } } public record RepeatableQuestTemplates { /// /// Pmc repeatable quest template ids keyed by type of quest /// Keys: elimination, completion, exploration /// [JsonPropertyName("pmc")] public required Dictionary Pmc { get; set; } /// /// Scav repeatable quest template ids keyed by type of quest /// Keys: elimination, completion, exploration, pickup /// [JsonPropertyName("scav")] public required Dictionary Scav { get; set; } } public record EventQuestData { /// /// Name of the event quest /// [JsonPropertyName("name")] public required string Name { get; set; } /// /// Season to which this quest belongs /// [JsonPropertyName("season")] public required SeasonalEventType Season { get; set; } /// /// Start timestamp /// [JsonPropertyName("startTimestamp")] public required long StartTimestamp { get; set; } /// /// End timestamp /// [JsonPropertyName("endTimestamp")] [JsonConverter(typeof(StringToNumberFactoryConverter))] public required long EndTimestamp { get; set; } /// /// Is this quest part of a yearly event, ex: Christmas /// [JsonPropertyName("yearly")] public required bool Yearly { get; set; } } public record RepeatableQuestConfig { /// /// Id for type of repeatable quest /// [JsonPropertyName("id")] public required MongoId Id { get; set; } /// /// Human-readable name for repeatable quest type /// [JsonPropertyName("name")] public required string Name { get; set; } /// /// Side this config belongs to. Note: Random not implemented, do not use! /// [JsonPropertyName("side")] [JsonConverter(typeof(JsonStringEnumConverter))] public required PlayerGroup Side { get; set; } /// /// Types of tasks this config can generate; ex: Elimination /// [JsonPropertyName("types")] public required List Types { get; set; } /// /// How long does the task stay active for after accepting it /// [JsonPropertyName("resetTime")] public required long ResetTime { get; set; } /// /// How many quests should we provide per ResetTime /// [JsonPropertyName("numQuests")] public required int NumQuests { get; set; } /// /// Min player level required to receive a quest from this config /// [JsonPropertyName("minPlayerLevel")] public required int MinPlayerLevel { get; set; } /// /// Reward scaling config /// [JsonPropertyName("rewardScaling")] public required RewardScaling RewardScaling { get; set; } /// /// Location map /// [JsonPropertyName("locations")] public required Dictionary> Locations { get; set; } /// /// Traders that are allowed to generate tasks from this config. /// Includes quest types, reward whitelist, and whether rewards can be weapons. /// [JsonPropertyName("traderWhitelist")] public required List TraderWhitelist { get; set; } /// /// Quest config, holds information on how a task should be generated /// [JsonPropertyName("questConfig")] public required RepeatableQuestTypesConfig QuestConfig { get; set; } /// /// Item base types to block when generating rewards /// [JsonPropertyName("rewardBaseTypeBlacklist")] public required HashSet RewardBaseTypeBlacklist { get; set; } /// /// Item tplIds to ignore when generating rewards /// [JsonPropertyName("rewardBlacklist")] public required HashSet RewardBlacklist { get; set; } /// /// Minimum stack size that an ammo reward should be generated with /// [JsonPropertyName("rewardAmmoStackMinSize")] public required int RewardAmmoStackMinSize { get; set; } /// /// How many free task changes are available from this config /// [JsonPropertyName("freeChangesAvailable")] public required int FreeChangesAvailable { get; set; } /// /// How many free task changes remain from this config /// [JsonPropertyName("freeChanges")] public required int FreeChanges { get; set; } /// /// Should the task replacement category be the same as the one its replacing /// [JsonPropertyName("keepDailyQuestTypeOnReplacement")] public required bool KeepDailyQuestTypeOnReplacement { get; set; } /// /// Reputation standing price for replacing a repeatable /// [JsonPropertyName("standingChangeCost")] public required IList StandingChangeCost { get; set; } } public record RewardScaling { /// /// Levels at which to increase to the next level of reward potential /// [JsonPropertyName("levels")] public required List Levels { get; set; } /// /// Experience reward tiers /// [JsonPropertyName("experience")] public required List Experience { get; set; } /// /// Rouble reward tiers /// [JsonPropertyName("roubles")] public required List Roubles { get; set; } /// /// Gp coin reward tiers /// [JsonPropertyName("gpCoins")] public required List GpCoins { get; set; } /// /// Item amount reward tiers /// [JsonPropertyName("items")] public required List Items { get; set; } /// /// reputation amount reward tiers /// [JsonPropertyName("reputation")] public required List Reputation { get; set; } /// /// Reward spread /// [JsonPropertyName("rewardSpread")] public required double RewardSpread { get; set; } /// /// Skill reward chance tiers /// [JsonPropertyName("skillRewardChance")] public required List SkillRewardChance { get; set; } /// /// Skill reward amount tiers /// [JsonPropertyName("skillPointReward")] public required List SkillPointReward { get; set; } } public record TraderWhitelist { /// /// Trader Id /// [JsonPropertyName("traderId")] public required MongoId TraderId { get; set; } /// /// Human-readable name /// [JsonPropertyName("name")] public required string Name { get; set; } /// /// Quest types this trader can provide: Completion/Exploration/Elimination. /// [JsonPropertyName("questTypes")] public required HashSet QuestTypes { get; set; } /// /// Item categories that the reward can be /// [JsonPropertyName("rewardBaseWhitelist")] public required IEnumerable RewardBaseWhitelist { get; set; } /// /// Can this reward be a weapon? /// [JsonPropertyName("rewardCanBeWeapon")] public required bool RewardCanBeWeapon { get; set; } /// /// Chance that the reward is a weapon /// [JsonPropertyName("weaponRewardChancePercent")] public required double WeaponRewardChancePercent { get; set; } } public record RepeatableQuestTypesConfig { /// /// Defines exploration repeatable task generation parameters /// [JsonPropertyName("Exploration")] public required List ExplorationConfig { get; set; } /// /// Defines completion repeatable task generation parameters /// [JsonPropertyName("Completion")] public required List CompletionConfig { get; set; } /// /// Defines pickup repeatable task generation parameters - TODO: Not implemented/No Data - NOTE: Does not work with dynamicLocale /// [JsonPropertyName("Pickup")] public Pickup? Pickup { get; set; } /// /// Defines elimination repeatable task generation parameters /// [JsonPropertyName("Elimination")] public required List Elimination { get; set; } } public record ExplorationConfig : BaseQuestConfig { /// /// Level range at which elimination tasks should be generated from this config /// [JsonPropertyName("levelRange")] public required MinMax LevelRange { get; set; } /// /// Minimum extract count that a per map extract requirement can be generated with /// [JsonPropertyName("minExtracts")] public required int MinimumExtracts { get; set; } /// /// Maximum extract count that a per map extract requirement can be generated with /// [JsonPropertyName("maxExtracts")] public required int MaximumExtracts { get; set; } /// /// Minimum extract count that a specific extract can be generated with /// [JsonPropertyName("minExtractsWithSpecificExit")] public required int MinimumExtractsWithSpecificExit { get; set; } /// /// Maximum extract count that a specific extract can be generated with /// [JsonPropertyName("maxExtractsWithSpecificExit")] public required int MaximumExtractsWithSpecificExit { get; set; } /// /// Specific extract generation data /// [JsonPropertyName("specificExits")] public required SpecificExits SpecificExits { get; set; } } public record SpecificExits { /// /// Chance that an operational task is generated with a specific extract /// [JsonPropertyName("chance")] public required double Chance { get; set; } /// /// Whitelist of specific extract types /// [JsonPropertyName("passageRequirementWhitelist")] public required HashSet PassageRequirementWhitelist { get; set; } } public record CompletionConfig : BaseQuestConfig { /// /// Level range at which completion tasks should be generated from this config /// [JsonPropertyName("levelRange")] public required MinMax LevelRange { get; set; } /// /// The minimum and maximum amounts that can be requested for an item /// [JsonPropertyName("requestedItemCount")] public required MinMax RequestedItemCount { get; set; } /// /// How many different unique items should be requested /// [JsonPropertyName("uniqueItemCount")] public required MinMax UniqueItemCount { get; set; } /// /// The minimum and maximum amounts that can be requested for bullets - TODO: Not implemented /// [JsonPropertyName("requestedBulletCount")] public required MinMax RequestedBulletCount { get; set; } /// /// Should the item whitelist be used /// [JsonPropertyName("useWhitelist")] public required bool UseWhitelist { get; set; } /// /// Should the item blacklist be used /// [JsonPropertyName("useBlacklist")] public required bool UseBlacklist { get; set; } /// /// Should the supplied items be required FiR /// [JsonPropertyName("requiredItemsAreFiR")] public required bool RequiredItemsAreFiR { get; set; } /// /// Min/Max durability requirements for the item /// [JsonPropertyName("requiredItemMinDurabilityMinMax")] public required MinMax RequiredItemMinDurabilityMinMax { get; set; } /// /// Blacklisted item types to not collect /// [JsonPropertyName("requiredItemTypeBlacklist")] public required HashSet RequiredItemTypeBlacklist { get; set; } } public record Pickup : BaseQuestConfig { [JsonPropertyName("ItemTypeToFetchWithMaxCount")] public List? ItemTypeToFetchWithMaxCount { get; set; } public List? ItemTypesToFetch { get; set; } [JsonPropertyName("maxItemFetchCount")] public int? MaxItemFetchCount { get; set; } } public record PickupTypeWithMaxCount { [JsonPropertyName("itemType")] public string? ItemType { get; set; } [JsonPropertyName("maxPickupCount")] public int? MaximumPickupCount { get; set; } [JsonPropertyName("minPickupCount")] public int? MinimumPickupCount { get; set; } } public record EliminationConfig : BaseQuestConfig { /// /// Level range at which elimination tasks should be generated from this config /// [JsonPropertyName("levelRange")] public required MinMax LevelRange { get; set; } /// /// Target data probabilities /// [JsonPropertyName("targets")] public required List> Targets { get; set; } /// /// Chance that a specific body part is needed as a requirement /// [JsonPropertyName("bodyPartChance")] public required int BodyPartChance { get; set; } /// /// If the specific body part requirement is chosen, pick from these body parts /// [JsonPropertyName("bodyParts")] public required List>> BodyParts { get; set; } /// /// Chance that a specific location modifier is selected /// [JsonPropertyName("specificLocationChance")] public required int SpecificLocationChance { get; set; } /// /// Locations that should be blacklisted as a requirement /// [JsonPropertyName("distLocationBlacklist")] public required HashSet DistLocationBlacklist { get; set; } /// /// Probability that a distance requirement is chosen /// [JsonPropertyName("distProb")] public required double DistanceProbability { get; set; } /// /// Maximum distance in meters that can be chosen /// [JsonPropertyName("maxDist")] public required double MaxDistance { get; set; } /// /// Minimum distance in meters that can be chosen /// [JsonPropertyName("minDist")] public required double MinDistance { get; set; } /// /// Maximum amount of kills that can be chosen /// [JsonPropertyName("maxKills")] public required int MaxKills { get; set; } /// /// Minimum amount of kills that can be chosen /// [JsonPropertyName("minKills")] public required int MinKills { get; set; } /// /// Maximum amount of boss kills that can be chosen /// [JsonPropertyName("maxBossKills")] public required int MaxBossKills { get; set; } /// /// Minimum amount of boss kills that can be chosen /// [JsonPropertyName("minBossKills")] public required int MinBossKills { get; set; } /// /// Maximum amount of PMC kills that can be chosen /// [JsonPropertyName("maxPmcKills")] public required int MaxPmcKills { get; set; } /// /// Minimum amount of PMC kills that can be chosen /// [JsonPropertyName("minPmcKills")] public required int MinPmcKills { get; set; } /// /// Chance that a specific weapon requirement is chosen /// [JsonPropertyName("weaponRequirementChance")] public required int WeaponRequirementChance { get; set; } /// /// Chance that a weapon category requirement is chosen /// [JsonPropertyName("weaponCategoryRequirementChance")] public required int WeaponCategoryRequirementChance { get; set; } /// /// If a weapon category requirement is chosen, pick from these categories /// [JsonPropertyName("weaponCategoryRequirements")] public required List>> WeaponCategoryRequirements { get; set; } /// /// If a weapon requirement is chosen, pick from these weapons /// [JsonPropertyName("weaponRequirements")] public required List>> WeaponRequirements { get; set; } } public record BaseQuestConfig { /// /// Possible skills that can be rewarded expirence points /// [JsonPropertyName("possibleSkillRewards")] public List PossibleSkillRewards { get; set; } } public record BossInfo { /// /// Is this target a boss /// [JsonPropertyName("isBoss")] public bool? IsBoss { get; set; } /// /// Is ths target a PMC /// [JsonPropertyName("isPmc")] public bool? IsPmc { get; set; } }