diff --git a/TsRandomizer/ItemTracker/ItemTrackerState.cs b/TsRandomizer/ItemTracker/ItemTrackerState.cs index 313b95ad..7f742833 100644 --- a/TsRandomizer/ItemTracker/ItemTrackerState.cs +++ b/TsRandomizer/ItemTracker/ItemTrackerState.cs @@ -105,7 +105,7 @@ internal static ItemTrackerState FromItemLocationMap(IEnumerable i static void SetMemberForItem(ItemTrackerState trackerState, ItemIdentifier itemInfo) { - if (!ItemToMemberMap.TryGetValue(itemInfo, out Expression> expression)) + if (!ItemToMemberMap.TryGetValue(itemInfo, out var expression)) return; var memberExpression = (MemberExpression)expression.Body; diff --git a/TsRandomizer/LevelObjects/ItemManipulator.cs b/TsRandomizer/LevelObjects/ItemManipulator.cs index fe604d71..4b472c0a 100644 --- a/TsRandomizer/LevelObjects/ItemManipulator.cs +++ b/TsRandomizer/LevelObjects/ItemManipulator.cs @@ -9,7 +9,7 @@ namespace TsRandomizer.LevelObjects { abstract class ItemManipulator : ItemManipulator where T : Mobile { - public readonly T TypedObject; + public readonly new T TypedObject; protected ItemManipulator(T typedObject, ItemLocation itemLocation) : base(typedObject, itemLocation) { diff --git a/TsRandomizer/LevelObjects/LevelObject.cs b/TsRandomizer/LevelObjects/LevelObject.cs index 20bc24b4..431eed8b 100644 --- a/TsRandomizer/LevelObjects/LevelObject.cs +++ b/TsRandomizer/LevelObjects/LevelObject.cs @@ -14,13 +14,13 @@ using TsRandomizer.Randomisation; using TsRandomizer.ReplacementObjects; using TsRandomizer.Screens; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; namespace TsRandomizer.LevelObjects { abstract class LevelObject : LevelObject where T : Mobile { - public readonly T TypedObject; + public readonly new T TypedObject; protected LevelObject(T typedObject) : base(typedObject) { @@ -104,7 +104,7 @@ public static void AwardFirstFrameItem(Dictionary itemDictionary, Pro public static void Update( Level level, GameplayScreen gameplayScreen, ItemLocationMap itemLocations, - bool roomChanged, SeedOptions seedOptions, GameSettingsCollection gameSettings, + bool roomChanged, SeedOptions seedOptions, SettingCollection gameSettings, ScreenManager screenManager) { if (roomChanged) @@ -138,7 +138,7 @@ public static void AwardFirstFrameItem(Dictionary itemDictionary, Pro var lunais = level.MainHero; if (roomChanged || newItems.Any()) AwardFirstFrameItem(itemsDictionary, lunais); - if ((bool)gameSettings.DamageRando.CurrentValue) + if (gameSettings.DamageRando.Value) OrbDamageManager.UpdateOrbDamage(level.GameSave, level.MainHero); KnownItemIds.Clear(); @@ -151,7 +151,8 @@ public static void AwardFirstFrameItem(Dictionary itemDictionary, Pro level.GameSave.AddConcussion(); } - static void OnChangeRoom(Level level, ItemLocationMap itemLocations, SeedOptions seedOptions, GameSettingsCollection gameSettings, ScreenManager screenManager) + static void OnChangeRoom(Level level, ItemLocationMap itemLocations, SeedOptions seedOptions, + SettingCollection gameSettings, ScreenManager screenManager) { #if DEBUG level.GameSave.AddItem(level, new ItemIdentifier(EInventoryRelicType.Dash)); diff --git a/TsRandomizer/LevelObjects/Other/MerchantCrowNPC.cs b/TsRandomizer/LevelObjects/Other/MerchantCrowNPC.cs index b0f35ad6..dcc2898c 100644 --- a/TsRandomizer/LevelObjects/Other/MerchantCrowNPC.cs +++ b/TsRandomizer/LevelObjects/Other/MerchantCrowNPC.cs @@ -3,15 +3,15 @@ using Timespinner.GameObjects.BaseClasses; using TsRandomizer.Extensions; using TsRandomizer.IntermediateObjects; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; namespace TsRandomizer.LevelObjects.Other { [TimeSpinnerType("Timespinner.GameObjects.NPCs.MerchantCrowNPC")] class MerchantCrowNpc : LevelObject { + readonly MerchantInventory merchandiseInventory = new MerchantInventory(); - MerchantInventory _merchandiseInventory = new MerchantInventory(); public MerchantCrowNpc(Mobile typedObject) : base(typedObject) { @@ -19,27 +19,26 @@ public MerchantCrowNpc(Mobile typedObject) : base(typedObject) protected override void Initialize(SeedOptions options) { - GameSettingsCollection gameSettings = new GameSettingsCollection(); - gameSettings.LoadSettingsFromFile(); - string fillType = (string)gameSettings.ShopFill.CurrentValue; + var gameSettings = GameSettingsLoader.LoadSettingsFromFile(); + var fillType = gameSettings.ShopFill.Value; if (fillType == "Vanilla") return; PlayerInventory inventory = Dynamic._level.GameSave.Inventory; // Only sell warp shards if Pyramid Key is aquired (and allowed in settings) - if ((bool)gameSettings.ShopWarpShards.CurrentValue && inventory.RelicInventory.IsRelicActive(EInventoryRelicType.PyramidsKey)) - _merchandiseInventory.AddItem(EInventoryUseItemType.WarpCard); + if (gameSettings.ShopWarpShards.Value && inventory.RelicInventory.IsRelicActive(EInventoryRelicType.PyramidsKey)) + merchandiseInventory.AddItem(EInventoryUseItemType.WarpCard); if (fillType == "Empty") { - Dynamic._merchandiseInventory = _merchandiseInventory; + Dynamic._merchandiseInventory = merchandiseInventory; return; } if (fillType == "Random") { - Random random = new Random((int)options.Flags); - for (int i = 0; i < 8; i++) + var random = new Random((int)options.Flags); + for (var i = 0; i < 8; i++) { var item = Helper.GetAllLoot().SelectRandom(random); // Give half of the items to each era. Needs to be done after the random advances @@ -47,31 +46,31 @@ protected override void Initialize(SeedOptions options) if ((Dynamic._isInPresent && (i % 2 == 0) || !Dynamic._isInPresent && (i % 2 != 0))) continue; if (item.LootType == LootType.Equipment) - _merchandiseInventory.AddItem((EInventoryEquipmentType)item.ItemId); + merchandiseInventory.AddItem((EInventoryEquipmentType)item.ItemId); else - _merchandiseInventory.AddItem((EInventoryUseItemType)item.ItemId); + merchandiseInventory.AddItem((EInventoryUseItemType)item.ItemId); } - Dynamic._merchandiseInventory = _merchandiseInventory; + Dynamic._merchandiseInventory = merchandiseInventory; return; } // Default case, streamlined inventory for randomizer players if (Dynamic._isInPresent) { - _merchandiseInventory.AddItem(EInventoryUseItemType.FuturePotion); - _merchandiseInventory.AddItem(EInventoryUseItemType.FutureEther); + merchandiseInventory.AddItem(EInventoryUseItemType.FuturePotion); + merchandiseInventory.AddItem(EInventoryUseItemType.FutureEther); } else { - _merchandiseInventory.AddItem(EInventoryUseItemType.Potion); - _merchandiseInventory.AddItem(EInventoryUseItemType.Ether); + merchandiseInventory.AddItem(EInventoryUseItemType.Potion); + merchandiseInventory.AddItem(EInventoryUseItemType.Ether); } - _merchandiseInventory.AddItem(EInventoryUseItemType.Biscuit); - _merchandiseInventory.AddItem(EInventoryUseItemType.Antidote); - _merchandiseInventory.AddItem(EInventoryUseItemType.SandBottle); - _merchandiseInventory.AddItem(EInventoryUseItemType.ChaosHeal); + merchandiseInventory.AddItem(EInventoryUseItemType.Biscuit); + merchandiseInventory.AddItem(EInventoryUseItemType.Antidote); + merchandiseInventory.AddItem(EInventoryUseItemType.SandBottle); + merchandiseInventory.AddItem(EInventoryUseItemType.ChaosHeal); - Dynamic._merchandiseInventory = _merchandiseInventory; + Dynamic._merchandiseInventory = merchandiseInventory; } } } diff --git a/TsRandomizer/LevelObjects/RoomTriggers.cs b/TsRandomizer/LevelObjects/RoomTriggers.cs index c50f9c6b..f04a2438 100644 --- a/TsRandomizer/LevelObjects/RoomTriggers.cs +++ b/TsRandomizer/LevelObjects/RoomTriggers.cs @@ -15,7 +15,7 @@ using TsRandomizer.Randomisation; using TsRandomizer.Randomisation.ItemPlacers; using TsRandomizer.Screens; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; namespace TsRandomizer.LevelObjects { @@ -293,16 +293,16 @@ static RoomTrigger() } readonly RoomItemKey key; - readonly Action trigger; + readonly Action trigger; - public RoomTrigger(int levelId, int roomId, Action triggerMethod) + public RoomTrigger(int levelId, int roomId, Action triggerMethod) { key = new RoomItemKey(levelId, roomId); trigger = triggerMethod; } public static void OnChangeRoom( - Level level, SeedOptions seedOptions, GameSettingsCollection gameSettings, ItemLocationMap itemLocations, ScreenManager screenManager, + Level level, SeedOptions seedOptions, SettingCollection gameSettings, ItemLocationMap itemLocations, ScreenManager screenManager, int levelId, int roomId) { var roomKey = new RoomItemKey(levelId, roomId); diff --git a/TsRandomizer/Program.cs b/TsRandomizer/Program.cs index ef9c9834..2bb781e5 100644 --- a/TsRandomizer/Program.cs +++ b/TsRandomizer/Program.cs @@ -4,8 +4,6 @@ using System.Text; using SDL2; using TsRandomizer.Extensions; -using TsRandomizer.Screens.Settings; -using TsRandomizer.Screens.Settings.GameSettingObjects; namespace TsRandomizer { diff --git a/TsRandomizer/Randomisation/ItemPlacers/ItemLocationRandomizer.cs b/TsRandomizer/Randomisation/ItemPlacers/ItemLocationRandomizer.cs index 2c25b52b..5f522588 100644 --- a/TsRandomizer/Randomisation/ItemPlacers/ItemLocationRandomizer.cs +++ b/TsRandomizer/Randomisation/ItemPlacers/ItemLocationRandomizer.cs @@ -4,7 +4,7 @@ using Timespinner.GameAbstractions.Inventory; using TsRandomizer.Extensions; using TsRandomizer.IntermediateObjects; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; using R = TsRandomizer.Randomisation.Requirement; namespace TsRandomizer.Randomisation.ItemPlacers @@ -13,7 +13,7 @@ abstract class ItemLocationRandomizer { protected readonly Seed Seed; protected readonly SeedOptions SeedOptions; - protected readonly GameSettingsCollection GameSettings; + protected readonly SettingCollection settings; protected readonly ItemInfoProvider ItemInfoProvider; protected readonly ItemUnlockingMap UnlockingMap; @@ -27,10 +27,7 @@ protected ItemLocationRandomizer(Seed seed, ItemInfoProvider itemInfoProvider, I SeedOptions = seed.Options; ItemInfoProvider = itemInfoProvider; UnlockingMap = unlockingMap; - GameSettings = new GameSettingsCollection(); - GameSettings.LoadSettingsFromFile(); - - + settings = GameSettingsLoader.LoadSettingsFromFile(); itemsToRemoveFromGame = new List { @@ -141,11 +138,9 @@ void PutStarterProgressionItemInReachableLocation(Random random, ItemLocationMap PutItemAtLocation(starterProgressionItem, location); } - static bool ShouldGiveLightwall(Random random, ItemInfo starterProgressionItem) - { - return (starterProgressionItem.Identifier == new ItemIdentifier(EInventoryOrbType.Barrier, EOrbSlot.Spell)) - && random.Next(1, 5) == 1; - } + static bool ShouldGiveLightwall(Random random, ItemInfo starterProgressionItem) => + (starterProgressionItem.Identifier == new ItemIdentifier(EInventoryOrbType.Barrier, EOrbSlot.Spell)) + && random.Next(1, 5) == 1; protected void GiveOrbsToMom(Random random, ItemLocationMap itemLocations, bool useLightwallAsSpell) { @@ -166,7 +161,7 @@ protected void GiveOrbsToMom(Random random, ItemLocationMap itemLocations, bool protected void PlaceGassMaskInALegalSpot(Random random, ItemLocationMap itemLocations) { var levelIdsToAvoid = new List(3) { 1 }; - R minimalMawRequirements = R.None; + var minimalMawRequirements = R.None; if (!SeedOptions.Inverted) { @@ -228,7 +223,7 @@ void FixProgressiveNonProgressionItemsInSameRoom(Random random, ItemLocationMap .Where(l => l.ItemInfo is ProgressiveItemInfo) .GroupBy(l => l.ItemInfo); - foreach (IGrouping progressiveItemLocations in progressiveItemLocationsPerType) + foreach (var progressiveItemLocations in progressiveItemLocationsPerType) { RoomItemKey roomkey = null; @@ -283,10 +278,7 @@ List GenerateItemList(ItemLocationMap itemLocations) return itemlist; } - void AddExtraItems(List itemlist) - { - itemlist.AddRange(itemsToAddToGame); - } + void AddExtraItems(List itemlist) => itemlist.AddRange(itemsToAddToGame); void AddFamiliars(List itemlist) { diff --git a/TsRandomizer/Screens/Settings/GameSettingsScreen.cs b/TsRandomizer/Screens/GameSettingsScreen.cs similarity index 79% rename from TsRandomizer/Screens/Settings/GameSettingsScreen.cs rename to TsRandomizer/Screens/GameSettingsScreen.cs index 352ea707..080fcc55 100644 --- a/TsRandomizer/Screens/Settings/GameSettingsScreen.cs +++ b/TsRandomizer/Screens/GameSettingsScreen.cs @@ -8,10 +8,10 @@ using TsRandomizer.Randomisation; using TsRandomizer.Screens.Menu; using TsRandomizer.Screens.SeedSelection; -using TsRandomizer.Screens.Settings.GameSettingObjects; +using TsRandomizer.Settings; +using TsRandomizer.Settings.GameSettingObjects; - -namespace TsRandomizer.Screens.Settings +namespace TsRandomizer.Screens { [TimeSpinnerType("Timespinner.GameStateManagement.Screens.PauseMenu.JournalMenuScreen")] // ReSharper disable once UnusedMember.Global @@ -25,8 +25,8 @@ class GameSettingsScreen : Screen TimeSpinnerType.Get("Timespinner.GameStateManagement.Screens.PauseMenu.JournalMenuScreen"); readonly SeedSelectionMenuScreen seedSelectionScreen; - GameSettingsCollection gameSettings; - GameSettingCategoryInfo[] settingCategories; + + SettingCollection settings; bool IsUsedAsGameSettingsMenu => seedSelectionScreen != null; GCM gcm; @@ -40,6 +40,8 @@ public override void Initialize(ItemLocationMap itemLocationMap, GCM gameContent Dynamic._menuTitle = "Game Settings"; + settings = GameSettingsLoader.LoadSettingsFromFile(); + ResetMenu(); } @@ -68,9 +70,9 @@ static GameSave GetSave(SeedOptionsCollection options) return save; } - object CreateDefaultsMenu(GameSetting[] settings) + object CreateDefaultsMenu() { - var defaultsMenu = MenuEntry.Create("Defaults", () => OnDefaultsSelected(settings)).AsTimeSpinnerMenuEntry(); + var defaultsMenu = MenuEntry.Create("Defaults", OnDefaultsSelected).AsTimeSpinnerMenuEntry(); defaultsMenu.AsDynamic().Description = "Restore all values to their defaults"; defaultsMenu.AsDynamic().IsCenterAligned = false; @@ -78,40 +80,22 @@ object CreateDefaultsMenu(GameSetting[] settings) return defaultsMenu; } - void OnDefaultsSelected(GameSetting[] settings) + void OnDefaultsSelected() { - foreach (var setting in settings) - setting.SetValue(setting.DefaultValue); + settings = new SettingCollection(); - gameSettings.WriteSettings(); + GameSettingsLoader.WriteSettings(settings); ResetMenu(); } void ResetMenu() { - gameSettings = new GameSettingsCollection(); - gameSettings.LoadSettingsFromFile(); - - settingCategories = new [] - { - new GameSettingCategoryInfo { - Name = "Stats", - Description = "Settings related to player stat scaling.", - Settings = new GameSetting[] { gameSettings.DamageRando } - }, - new GameSettingCategoryInfo { - Name = "Loot", - Description = "Settings related to shop inventory and loot.", - Settings = new GameSetting[] { gameSettings.ShopMultiplier, gameSettings.ShopFill, gameSettings.ShopWarpShards } - } - }; - ClearAllSubmenus(); var menuEntryList = new object[0].ToList(MenuEntryType); - foreach (var category in settingCategories) + foreach (var category in SettingCollection.Categories) { var submenu = MenuEntry.Create(category.Name, () => CreateMenuForCategory(category)); @@ -121,14 +105,7 @@ void ResetMenu() menuEntryList.Add(submenu.AsTimeSpinnerMenuEntry()); } - var allSettings = new GameSetting[] { - gameSettings.DamageRando, - gameSettings.ShopFill, - gameSettings.ShopMultiplier, - gameSettings.ShopWarpShards - }; - - menuEntryList.Add(CreateDefaultsMenu(allSettings)); + menuEntryList.Add(CreateDefaultsMenu()); ((object)Dynamic._primaryMenuCollection).AsDynamic()._entries = menuEntryList; ((object)Dynamic._selectedMenuCollection).AsDynamic().SetSelectedIndex(0); @@ -154,8 +131,8 @@ void CreateMenuForCategory(GameSettingCategoryInfo category) var collection = FetchCollection(category.Name); var submenu = (IList)collection.AsDynamic()._entries; - foreach (var setting in category.Settings) - submenu.Add(CreateMenuForSetting(setting)); + foreach (var settingFunc in category.SettingsPerCategory) + submenu.Add(CreateMenuForSetting(settingFunc(settings))); // Exclude submenu defaults for now, enable when they don't wipe the current view // submenu.Add(CreateDefaultsMenu(category.Settings)); @@ -190,14 +167,14 @@ object FetchCollection(string submenu) object CreateMenuForSetting(GameSetting setting) { - var menuEntry = MenuEntry.Create(setting.Name, () => CreateToggleForSetting(setting)).AsTimeSpinnerMenuEntry(); + var menuEntry = MenuEntry.Create(setting.Name, () => ToggleSetting(setting)).AsTimeSpinnerMenuEntry(); SetCurrentSettingText(menuEntry, setting); return menuEntry; } - void CreateToggleForSetting(GameSetting setting) + void ToggleSetting(GameSetting setting) { switch (setting) { @@ -233,7 +210,7 @@ void CreateToggleForSetting(GameSetting setting) return; } - gameSettings.WriteSettings(); + GameSettingsLoader.WriteSettings(settings); var selectedMenu = ((object)Dynamic._selectedMenuCollection).AsDynamic(); diff --git a/TsRandomizer/Screens/GameplayScreen.cs b/TsRandomizer/Screens/GameplayScreen.cs index df6631f3..5dc1d437 100644 --- a/TsRandomizer/Screens/GameplayScreen.cs +++ b/TsRandomizer/Screens/GameplayScreen.cs @@ -1,6 +1,5 @@ using System; using System.Reflection; -using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; using Archipelago.MultiClient.Net.Enums; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; @@ -17,7 +16,7 @@ using TsRandomizer.ItemTracker; using TsRandomizer.LevelObjects; using TsRandomizer.Randomisation; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; namespace TsRandomizer.Screens { @@ -34,7 +33,7 @@ class GameplayScreen : Screen RoomSpecification currentRoom; SeedOptions seedOptions; - GameSettingsCollection gameSettings; + SettingCollection gameSettings; Level Level => (Level)Dynamic._level; dynamic LevelReflected => Level.AsDynamic(); @@ -63,8 +62,7 @@ public override void Initialize(ItemLocationMap _, GCM gameContentManager) Console.Out.WriteLine($"Seed: {seed}"); seedOptions = seed.Value.Options; - gameSettings = new GameSettingsCollection(); - gameSettings.LoadSettingsFromFile(); + gameSettings = GameSettingsLoader.LoadSettingsFromFile(); try { @@ -83,7 +81,7 @@ public override void Initialize(ItemLocationMap _, GCM gameContentManager) LevelReflected._random = new DeRandomizer(LevelReflected._random, seed.Value); ItemManipulator.Initialize(ItemLocations); - if ((bool)gameSettings.DamageRando.CurrentValue) + if (gameSettings.DamageRando.Value) OrbDamageManager.PopulateOrbLookups(Level.GameSave); if (seedOptions.Archipelago) diff --git a/TsRandomizer/Screens/SeedSelection/SeedSelectionMenuScreen.cs b/TsRandomizer/Screens/SeedSelection/SeedSelectionMenuScreen.cs index 03a9719f..38d210cc 100644 --- a/TsRandomizer/Screens/SeedSelection/SeedSelectionMenuScreen.cs +++ b/TsRandomizer/Screens/SeedSelection/SeedSelectionMenuScreen.cs @@ -11,8 +11,8 @@ using TsRandomizer.IntermediateObjects; using TsRandomizer.Randomisation; using TsRandomizer.Screens.Menu; -using TsRandomizer.Screens.Settings; using SDL2; +using TsRandomizer.Settings; using Keys = Microsoft.Xna.Framework.Input.Keys; namespace TsRandomizer.Screens.SeedSelection diff --git a/TsRandomizer/Screens/Settings/GameSetting.cs b/TsRandomizer/Screens/Settings/GameSetting.cs deleted file mode 100644 index 702e0fe4..00000000 --- a/TsRandomizer/Screens/Settings/GameSetting.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Newtonsoft.Json; - -namespace TsRandomizer.Screens.Settings -{ - public abstract class GameSetting - { - [JsonProperty] - public object CurrentValue { get; protected set; } - [JsonIgnore] - public string Name { get; set; } - [JsonIgnore] - public string Description { get; set; } - [JsonIgnore] - public object DefaultValue { get; } - [JsonIgnore] - public bool CanBeChangedInGame { get; set; } - - public GameSetting(string name, string description, object defaultValue, bool canBeChangedInGame) - { - Name = name; - Description = description; - DefaultValue = defaultValue; - CanBeChangedInGame = canBeChangedInGame; - CurrentValue = DefaultValue; - } - - public GameSetting(SettingsConstants constants, GameSetting setting) - { - DefaultValue = constants.DefaultValue; - Description = constants.Description; - Name = constants.Name; - } - - public GameSetting() { } - - public virtual void SetValue(object input) => CurrentValue = input; - - public bool IsDefault() => CurrentValue == DefaultValue; - } -} diff --git a/TsRandomizer/Screens/Settings/GameSettingCategoryInfo.cs b/TsRandomizer/Screens/Settings/GameSettingCategoryInfo.cs deleted file mode 100644 index 46021109..00000000 --- a/TsRandomizer/Screens/Settings/GameSettingCategoryInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TsRandomizer.Screens.Settings -{ - class GameSettingCategoryInfo - { - public string Name { get; set; } - public string Description { get; set; } - public GameSetting[] Settings { get; set; } - } -} diff --git a/TsRandomizer/Screens/Settings/GameSettingObjects/NumberGameSetting.cs b/TsRandomizer/Screens/Settings/GameSettingObjects/NumberGameSetting.cs deleted file mode 100644 index b02a6449..00000000 --- a/TsRandomizer/Screens/Settings/GameSettingObjects/NumberGameSetting.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace TsRandomizer.Screens.Settings.GameSettingObjects -{ - public class NumberGameSetting : GameSetting - { - public double MinimumValue { get; } - public double MaximumValue { get; } - - [JsonIgnore()] - public double StepValue { get; set; } - [JsonIgnore()] - public bool AllowDecimals { get; set; } - - public override void SetValue(dynamic input) - { - if (!double.IsNaN(input)) - { - double value = input; - if (AllowDecimals) - base.SetValue(value); - else - base.SetValue(Math.Round(value)); - } - else - { - base.SetValue(DefaultValue); - } - } - - public NumberGameSetting(string name, string description, double defaultValue, double minValue, double maxValue, double stepValue, bool allowDecimals, bool canBeChangedInGame) : base(name, description, defaultValue, canBeChangedInGame) - { - MinimumValue = minValue; - MaximumValue = maxValue; - StepValue = stepValue; - AllowDecimals = allowDecimals; - - SetValue(defaultValue); - } - - [JsonConstructor] - public NumberGameSetting() { } - - public NumberGameSetting(NumberSettingsConstants constants, NumberGameSetting settings) : base(constants, settings) - { - StepValue = constants.StepValue; - MinimumValue = constants.MinimumValue; - MaximumValue = constants.MaximumValue; - AllowDecimals = constants.AllowDecimals; - - SetValue(settings.CurrentValue); - - } - } -} diff --git a/TsRandomizer/Screens/Settings/GameSettingObjects/OnOffGameSetting.cs b/TsRandomizer/Screens/Settings/GameSettingObjects/OnOffGameSetting.cs deleted file mode 100644 index 2474a887..00000000 --- a/TsRandomizer/Screens/Settings/GameSettingObjects/OnOffGameSetting.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Newtonsoft.Json; - -namespace TsRandomizer.Screens.Settings.GameSettingObjects -{ - public class OnOffGameSetting : GameSetting - { - [JsonConstructor] - public OnOffGameSetting(string name, string description, bool defaultValue, bool canBeToggledInGame) - : base(name, description, defaultValue, canBeToggledInGame) - { - - } - public OnOffGameSetting(SettingsConstants constants, OnOffGameSetting settings) : base(constants, settings) - { - SetValue(settings.CurrentValue); - } - } -} diff --git a/TsRandomizer/Screens/Settings/GameSettingObjects/SpecificValuesGameSetting.cs b/TsRandomizer/Screens/Settings/GameSettingObjects/SpecificValuesGameSetting.cs deleted file mode 100644 index 0f2f382f..00000000 --- a/TsRandomizer/Screens/Settings/GameSettingObjects/SpecificValuesGameSetting.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using System.Collections.Generic; -using Newtonsoft.Json; - -namespace TsRandomizer.Screens.Settings.GameSettingObjects -{ - public class SpecificValuesGameSetting : GameSetting - { - public List AllowedValues { get; private set; } - - public override void SetValue(object input) - { - try - { - string value = (string)input; - if (AllowedValues.Contains(value)) - base.SetValue(input); - else - base.SetValue(DefaultValue); - } - catch - { - Console.WriteLine("SpecificValuesGameSetting: Can't set value. Input was not a string."); - } - - } - - public SpecificValuesGameSetting(string name, string description, string defaultValue, List allowedValues, bool canBeChangedInGame) - : base(name, description, defaultValue, canBeChangedInGame) - { - AllowedValues = allowedValues; - - SetValue(defaultValue); - } - - [JsonConstructor] - public SpecificValuesGameSetting() { } - - public SpecificValuesGameSetting(SpecificValueSettingsConstants constants, SpecificValuesGameSetting settings) : base(constants, settings) - { - AllowedValues = constants.AllowedValues; - - SetValue(settings.CurrentValue); - } - } -} diff --git a/TsRandomizer/Screens/Settings/GameSettingsCollection.cs b/TsRandomizer/Screens/Settings/GameSettingsCollection.cs deleted file mode 100644 index 3b5af19b..00000000 --- a/TsRandomizer/Screens/Settings/GameSettingsCollection.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Newtonsoft.Json; -using TsRandomizer.Screens.Settings.GameSettingObjects; - -namespace TsRandomizer.Screens.Settings -{ - public class SettingsConstants - { - public string Name; - public string Description; - public object DefaultValue; - } - - public class NumberSettingsConstants : SettingsConstants - { - public double MinimumValue; - public double MaximumValue; - public double StepValue; - public bool AllowDecimals; - } - - public class SpecificValueSettingsConstants : SettingsConstants - { - public List AllowedValues; - } - - public class GameSettingsCollection - { - static readonly SettingsConstants DamageRandoConstants = new SettingsConstants - { - Name = "Damage Randomizer", - Description = "Adds a high chance to make orb damage very low, and a low chance to make orb damage very, very high", - DefaultValue = false - }; - - static readonly SpecificValueSettingsConstants ShopFillConstants = new SpecificValueSettingsConstants - { - Name = "Shop Inventory", - Description = "Sets the items for sale in Merchant Crow's shops. Options: [Default,Random,Vanilla,Empty]", - DefaultValue = "Default", - AllowedValues = new List { "Default", "Random", "Vanilla", "Empty" } - }; - - static readonly NumberSettingsConstants ShopMultiplierConstants = new NumberSettingsConstants - { - Name = "Shop Price Multiplier", - Description = "Multiplier for the cost of items in the shop. Set to 0 for free shops", - DefaultValue = 1, - StepValue = 0.5, - MinimumValue = 0, - MaximumValue = 10, - AllowDecimals = true - }; - - static readonly SettingsConstants ShopWarpShardsConstants = new SettingsConstants - { - Name = "Always Sell Warp Shards", - Description = "Shops always sell warp shards (when keys possessed), ignoring inventory setting.", - DefaultValue = true - }; - - [JsonIgnore] - public string Path { get; } - public OnOffGameSetting DamageRando { get; set; } - public SpecificValuesGameSetting ShopFill { get; set; } - public NumberGameSetting ShopMultiplier { get; set; } - public OnOffGameSetting ShopWarpShards { get; set; } - - public GameSettingsCollection() - { - string dir = "settings/"; - if (CreateSettingsDirectory(dir)) - { - var settingsFiles = GetSettingsFiles(dir); - if (settingsFiles == null) - { - Console.WriteLine("Error reading from settings directory."); - return; - } - if (settingsFiles.Count() > 0) - { - var defaultFile = settingsFiles.First(); - Path = defaultFile; - } - else - { - Console.WriteLine("No settings file found. Creating..."); - Path = dir + "settings.json"; - - DamageRando = new OnOffGameSetting(DamageRandoConstants.Name, DamageRandoConstants.Description, false, false); - ShopFill = new SpecificValuesGameSetting(ShopFillConstants.Name, ShopFillConstants.Description, "Default", ShopFillConstants.AllowedValues, false); - ShopMultiplier = new NumberGameSetting(ShopMultiplierConstants.Name, ShopMultiplierConstants.Description, 1, 0, 10, 1, true, true); - ShopWarpShards = new OnOffGameSetting(ShopWarpShardsConstants.Name, ShopWarpShardsConstants.Description, true, true); - - WriteSettings(); //write settings file with default values - } - } - else - { - Console.WriteLine("Error finding or creating settings directory."); - } - } - - public void LoadSettingsFromFile() - { - try - { - if (File.Exists(Path)) - { - var settingsString = File.ReadAllText(Path); - var settings = JsonConvert.DeserializeObject(settingsString); - - DamageRando = new OnOffGameSetting(DamageRandoConstants, settings.DamageRando); - ShopFill = new SpecificValuesGameSetting(ShopFillConstants, settings.ShopFill); - ShopMultiplier = new NumberGameSetting(ShopMultiplierConstants, settings.ShopMultiplier); - ShopWarpShards = new OnOffGameSetting(ShopWarpShardsConstants, settings.ShopWarpShards); - - WriteSettings(); // write to file to ensure any missing settings are added with defaults - } - else - { - Console.WriteLine("Settings file not found: " + Path); - } - } - catch - { - Console.WriteLine("Error loading settings from " + Path); - } - } - - public bool WriteSettings() - { - try - { - string jsonSettings = JsonConvert.SerializeObject(this, Formatting.Indented); - - File.WriteAllText(Path, jsonSettings); - - Console.WriteLine($"Writing settings for: {this}"); - Console.WriteLine($"Writing settings as: {jsonSettings}"); - - return true; - } - catch (Exception exc) - { - Console.WriteLine($"Error writing settings: {exc}"); - - return false; - } - } - - public bool CreateSettingsDirectory(string dir) - { - try - { - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - return true; - } - catch - { - return false; - } - } - - public IEnumerable GetSettingsFiles(string dir) - { - try - { - return Directory.GetFiles(dir).ToList().Where(f => f.EndsWith(".json")); - } - catch - { - return null; - } - } - } -} diff --git a/TsRandomizer/Screens/ShopMenuScreen.cs b/TsRandomizer/Screens/ShopMenuScreen.cs index c3dde056..0ead3a7d 100644 --- a/TsRandomizer/Screens/ShopMenuScreen.cs +++ b/TsRandomizer/Screens/ShopMenuScreen.cs @@ -1,11 +1,9 @@ using System.Collections; using System.Linq; -using System.Collections.Generic; using Timespinner.GameStateManagement.ScreenManager; using TsRandomizer.Extensions; using TsRandomizer.IntermediateObjects; -using TsRandomizer.Screens.Menu; -using TsRandomizer.Screens.Settings; +using TsRandomizer.Settings; namespace TsRandomizer.Screens { @@ -15,13 +13,12 @@ class ShopMenuScreen : Screen { public ShopMenuScreen(ScreenManager screenManager, GameScreen screen) : base(screenManager, screen) { - GameSettingsCollection gameSettings = new GameSettingsCollection(); - gameSettings.LoadSettingsFromFile(); - double shopMultiplier = (double)gameSettings.ShopMultiplier.CurrentValue; + var gameSettings = GameSettingsLoader.LoadSettingsFromFile(); + // Menu count varies on relics/items/equipment etc. being in inventory // Last menu is always helper functions that don't have an _items // but aren't otherwise distinguishable - foreach (int i in Enumerable.Range(0, ((IList)Dynamic._subMenuCollections).Count - 1)) + foreach (var i in Enumerable.Range(0, ((IList)Dynamic._subMenuCollections).Count - 1)) { var shopMenu = ((IList)Dynamic._subMenuCollections)[i].AsDynamic(); foreach (object shopMenuEntry in shopMenu._items) @@ -33,7 +30,7 @@ public ShopMenuScreen(ScreenManager screenManager, GameScreen screen) : base(scr shopMenuEntry.AsDynamic().ShopPrice = 2000; currentPrice = shopMenuEntry.AsDynamic().ShopPrice; } - shopMenuEntry.AsDynamic().ShopPrice = (int)(currentPrice * shopMultiplier); + shopMenuEntry.AsDynamic().ShopPrice = (int)(currentPrice * gameSettings.ShopMultiplier.Value); } } } diff --git a/TsRandomizer/Settings/GameSettingCategoryInfo.cs b/TsRandomizer/Settings/GameSettingCategoryInfo.cs new file mode 100644 index 00000000..d0d9a9a1 --- /dev/null +++ b/TsRandomizer/Settings/GameSettingCategoryInfo.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using TsRandomizer.Settings.GameSettingObjects; + +namespace TsRandomizer.Settings +{ + public class GameSettingCategoryInfo + { + [JsonIgnore] + public string Name { get; set; } + + [JsonIgnore] + public string Description { get; set; } + + [JsonIgnore] + public List> SettingsPerCategory; + } +} diff --git a/TsRandomizer/Settings/GameSettingObjects/GameSetting.cs b/TsRandomizer/Settings/GameSettingObjects/GameSetting.cs new file mode 100644 index 00000000..9b9cdd0d --- /dev/null +++ b/TsRandomizer/Settings/GameSettingObjects/GameSetting.cs @@ -0,0 +1,48 @@ +using Newtonsoft.Json; + +namespace TsRandomizer.Settings.GameSettingObjects +{ + public abstract class GameSetting + { + public dynamic CurrentValue { get; protected set; } + + [JsonIgnore] + public string Category { get; } + [JsonIgnore] + public string Name { get; } + [JsonIgnore] + public string Description { get; } + [JsonIgnore] + public object DefaultValue { get; } + [JsonIgnore] + public bool CanBeChangedInGame { get; } + + protected GameSetting(string category, string name, string description, object defaultValue, bool canBeChangedInGame) + { + Category = category; + Name = name; + Description = description; + DefaultValue = defaultValue; + CanBeChangedInGame = canBeChangedInGame; + CurrentValue = DefaultValue; + } + + // ReSharper disable once PublicConstructorInAbstractClass + public GameSetting() { } + + public virtual void SetValue(object input) => CurrentValue = input; + } + + public abstract class GameSetting : GameSetting + { + public T Value => (T)CurrentValue; + + protected GameSetting(string category, string name, string description, T defaultValue, bool canBeChangedInGame) + : base(category, name, description, defaultValue, canBeChangedInGame) + { + } + + // ReSharper disable once PublicConstructorInAbstractClass + public GameSetting() { } + } +} diff --git a/TsRandomizer/Settings/GameSettingObjects/NumberGameSetting.cs b/TsRandomizer/Settings/GameSettingObjects/NumberGameSetting.cs new file mode 100644 index 00000000..5c5fd778 --- /dev/null +++ b/TsRandomizer/Settings/GameSettingObjects/NumberGameSetting.cs @@ -0,0 +1,41 @@ +using Newtonsoft.Json; + +namespace TsRandomizer.Settings.GameSettingObjects +{ + public class NumberGameSetting : GameSetting + { + public double MinimumValue { get; } + public double MaximumValue { get; } + + [JsonIgnore] + public double StepValue { get; set; } + + public override void SetValue(dynamic input) + { + if (!double.IsNaN(input)) + { + double value = input; + + base.SetValue(value); + } + else + { + base.SetValue(DefaultValue); + } + } + + public NumberGameSetting(string category, string name, string description, float minValue, float maxValue, float stepValue, + float? defaultValue = null, bool canBeChangedInGame = false) + : base(category, name, description, defaultValue ?? minValue, canBeChangedInGame) + { + MinimumValue = minValue; + MaximumValue = maxValue; + StepValue = stepValue; + + SetValue(defaultValue ?? minValue); + } + + [JsonConstructor] + public NumberGameSetting() { } + } +} diff --git a/TsRandomizer/Settings/GameSettingObjects/OnOffGameSetting.cs b/TsRandomizer/Settings/GameSettingObjects/OnOffGameSetting.cs new file mode 100644 index 00000000..3cb49f3b --- /dev/null +++ b/TsRandomizer/Settings/GameSettingObjects/OnOffGameSetting.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace TsRandomizer.Settings.GameSettingObjects +{ + public class OnOffGameSetting : GameSetting + { + [JsonConstructor] + public OnOffGameSetting(string category, string name, string description, bool defaultValue = false, bool canBeToggledInGame = false) + : base(category, name, description, defaultValue, canBeToggledInGame) + { + + } + } +} diff --git a/TsRandomizer/Settings/GameSettingObjects/SpecificValuesGameSetting.cs b/TsRandomizer/Settings/GameSettingObjects/SpecificValuesGameSetting.cs new file mode 100644 index 00000000..a31a2eb0 --- /dev/null +++ b/TsRandomizer/Settings/GameSettingObjects/SpecificValuesGameSetting.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace TsRandomizer.Settings.GameSettingObjects +{ + public class SpecificValuesGameSetting : GameSetting + { + public List AllowedValues { get; } + + public override void SetValue(object input) + { + try + { + var value = input.ToString(); + if (AllowedValues.Contains(value)) + base.SetValue(input); + else + base.SetValue(DefaultValue); + } + catch + { + Console.WriteLine("SpecificValuesGameSetting: Can't set value. Input was not a string."); + } + + } + + public SpecificValuesGameSetting(string category, string name, string description, List allowedValues, + string defaultValue = "Default", bool canBeChangedInGame = false) + : base(category, name, description, defaultValue, canBeChangedInGame) + { + AllowedValues = allowedValues; + + SetValue(defaultValue); + } + + [JsonConstructor] + public SpecificValuesGameSetting() { } + } +} diff --git a/TsRandomizer/Screens/Settings/GameSettingObjects/StringGameSetting.cs b/TsRandomizer/Settings/GameSettingObjects/StringGameSetting.cs similarity index 60% rename from TsRandomizer/Screens/Settings/GameSettingObjects/StringGameSetting.cs rename to TsRandomizer/Settings/GameSettingObjects/StringGameSetting.cs index 69b56a90..c1af9cd7 100644 --- a/TsRandomizer/Screens/Settings/GameSettingObjects/StringGameSetting.cs +++ b/TsRandomizer/Settings/GameSettingObjects/StringGameSetting.cs @@ -1,9 +1,10 @@  -namespace TsRandomizer.Screens.Settings.GameSettingObjects +namespace TsRandomizer.Settings.GameSettingObjects { - public class StringGameSetting : GameSetting + public class StringGameSetting : GameSetting { public int MaxLength { get; } + public override void SetValue(dynamic input) { if (input is string) @@ -16,12 +17,14 @@ public override void SetValue(dynamic input) else { if (value.Length > MaxLength) value = value.Substring(0, MaxLength - 1); + base.SetValue(value); } } } - public StringGameSetting(string name, string description, string defaultValue, int maxLength, bool canBeChangedInGame) : base(name, description, defaultValue, canBeChangedInGame) + public StringGameSetting(string category, string name, string description, string defaultValue, int maxLength, bool canBeChangedInGame) + : base(category, name, description, defaultValue, canBeChangedInGame) { MaxLength = maxLength; diff --git a/TsRandomizer/Settings/GameSettingsLoader.cs b/TsRandomizer/Settings/GameSettingsLoader.cs new file mode 100644 index 00000000..d9049660 --- /dev/null +++ b/TsRandomizer/Settings/GameSettingsLoader.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using TsRandomizer.Settings.GameSettingObjects; + +namespace TsRandomizer.Settings +{ + public class SettingCollection + { + public static readonly GameSettingCategoryInfo[] Categories = { + new GameSettingCategoryInfo { Name = "Stats", Description = "Settings related to player stat scaling.", + SettingsPerCategory = new List> { + s => s.DamageRando + }}, + new GameSettingCategoryInfo { Name = "Loot", Description = "Settings related to shop inventory and loot.", + SettingsPerCategory = new List> { + s => s.ShopFill, s => s.ShopMultiplier, s => s.ShopWarpShards + }} + }; + + public OnOffGameSetting DamageRando = new OnOffGameSetting("Stat", "Damage Randomizer", + "Adds a high chance to make orb damage very low, and a low chance to make orb damage very, very high"); + + public SpecificValuesGameSetting ShopFill = new SpecificValuesGameSetting("Loot", "Shop Inventory", + "Sets the items for sale in Merchant Crow's shops. Options: [Default,Random,Vanilla,Empty]", + new List { "Default", "Random", "Vanilla", "Empty" }); + + public NumberGameSetting ShopMultiplier = new NumberGameSetting("Loot", "Shop Price Multiplier", + "Multiplier for the cost of items in the shop. Set to 0 for free shops", 0, 10, 1); + + public OnOffGameSetting ShopWarpShards = new OnOffGameSetting("Loot", "Always Sell Warp Shards", + "Shops always sell warp shards (when keys possessed), ignoring inventory setting."); + } + + public static class GameSettingsLoader + { + const string SettingSubFolderName = "settings"; + + public static SettingCollection LoadSettingsFromFile() + { + SettingCollection settings; + + var file = GetSettingsFilePath(); + + try + { + if (!File.Exists(file)) + { + settings = new SettingCollection(); + } + else + { + var settingsString = File.ReadAllText(file); + settings = JsonConvert.DeserializeObject(settingsString); + } + + Console.WriteLine("Settings file not found: " + file); + } + catch + { + Console.WriteLine("Error loading settings from " + SettingSubFolderName); + + settings = new SettingCollection(); + } + + WriteSettings(settings); // write to file to ensure any missing settings are added with defaults + + return settings; + } + + public static void WriteSettings(SettingCollection settings) + { + try + { + var jsonSettings = JsonConvert.SerializeObject(settings, Formatting.Indented); + + var filename = GetSettingsFilePath(); + + File.WriteAllText(filename, jsonSettings); + + Console.WriteLine($"Writing settings as: {jsonSettings}"); + } + catch (Exception e) + { + Console.WriteLine($"Error writing settings: {e}"); + } + } + + static void CreateSettingsDirectoryIfNotExists() + { + try + { + if (!Directory.Exists(SettingSubFolderName)) + Directory.CreateDirectory(SettingSubFolderName); + } + catch + { + } + } + + static string GetSettingsFilePath() + { + CreateSettingsDirectoryIfNotExists(); + + return Directory + .EnumerateFiles(SettingSubFolderName, "*.json") + .FirstOrDefault() ?? "settings.json"; + } + } +} diff --git a/TsRandomizer/TsRandomizer.csproj b/TsRandomizer/TsRandomizer.csproj index 1bb3ff28..56566360 100644 --- a/TsRandomizer/TsRandomizer.csproj +++ b/TsRandomizer/TsRandomizer.csproj @@ -217,16 +217,16 @@ - - - - - - + + + + + + - - + +