diff --git a/Ideas.md b/Ideas.md index 223604e..149118f 100644 --- a/Ideas.md +++ b/Ideas.md @@ -17,10 +17,6 @@ - Upgrade that allows you to set park placement templates - Multiple levels, each level allows more rides to be put into the template - When a new park is started, the template is automatically populated as soon as there are enough tickets -- Upgrade that increases the amount of modifiers on each ride - - Advanced version that adds modifiers to each ride automatically, regardless of whether they already contain them # Gameplay options -- Edit park templates -- Set the minimum amount of tickets required for auto-buyers of any kind to take effect -- Set the amount of time between auto-buy attempts \ No newline at end of file +- Edit park templates \ No newline at end of file diff --git a/TouchyTickets/Attractions/Attraction.cs b/TouchyTickets/Attractions/Attraction.cs index e4c1b9c..fd05ee8 100644 --- a/TouchyTickets/Attractions/Attraction.cs +++ b/TouchyTickets/Attractions/Attraction.cs @@ -28,7 +28,7 @@ namespace TouchyTickets.Attractions { this.Type = type; } - public double Update(GameTime time, TimeSpan passed, ParkMap map, Point position) { + public double Update(TimeSpan passed, ParkMap map, Point position) { var genRate = this.GetGenerationRate(map, position); // apply generation rate to ticket amount this.ticketPercentage += genRate * passed.TotalSeconds; diff --git a/TouchyTickets/Attractions/AttractionModifier.cs b/TouchyTickets/Attractions/AttractionModifier.cs index 29e11ac..738776e 100644 --- a/TouchyTickets/Attractions/AttractionModifier.cs +++ b/TouchyTickets/Attractions/AttractionModifier.cs @@ -39,6 +39,16 @@ namespace TouchyTickets.Attractions { return (attraction.Type.Flags & this.affectedFlags) != 0; } + public bool Buy(Attraction attraction) { + var price = attraction.GetModifierPrice(this); + if (GameImpl.Instance.Tickets < price) + return false; + GameImpl.Instance.Tickets -= price; + GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", (float) price, "Modifier", this.Name); + attraction.ApplyModifier(this); + return true; + } + private static AttractionModifier Register(AttractionModifier type) { Modifiers.Add(type.Name, type); return type; diff --git a/TouchyTickets/Content/Localization/Localization.json b/TouchyTickets/Content/Localization/Localization.json index 347ceb1..a718898 100644 --- a/TouchyTickets/Content/Localization/Localization.json +++ b/TouchyTickets/Content/Localization/Localization.json @@ -22,6 +22,11 @@ "Rate": "Rate", "Attractions": "Attractions", "Modifiers": "Modifiers", + "GameplayOptions": "Gameplay", + "OtherOptions": "Other", + "AutoBuyEnabled": "Auto-Buying Enabled", + "MinTicketsForAutoBuy": "Min Tickets for Auto-Buying", + "AutoBuyInterval": "Auto-Buying Interval/s", "----- Tutorial -----": "", "Tutorial1": "Hi! Welcome to Touchy Tickets. To start the game, simply tap the ticket booth to sell a . Start by racking up 50!", "Tutorial2": "Great! Now, you can buy your first attraction. Access the menu on the right by swiping and purchase a carousel.", @@ -89,6 +94,10 @@ "ModifierIncrease2Description": "Increases the amount of ride modifiers placed at once to 5.", "ModifierIncrease3": "Modified Most", "ModifierIncrease3Description": "Increases the amount of ride modifiers placed at once to 10.", + "AutoPlaceModifiers1": "Magically Modified", + "AutoPlaceModifiers1Description": "More modifiers will automatically be bought for rides that already have them. Limits can be set in the Options screen.", + "AutoPlaceModifiers2": "Mighty Modified", + "AutoPlaceModifiers2Description": "More modifiers will automatically be bought for rides, even if they don't have them yet. Limits can be set in the Options screen.", "FoodCourtModifier": "Tasty Treats", "FoodCourtModifierDescription": "Doubles sales for all attractions adjacent to food courts.", "FerrisWheelModifier": "Crowded Pods", diff --git a/TouchyTickets/Content/Textures/Ui.aseprite b/TouchyTickets/Content/Textures/Ui.aseprite index 5c0d65a..a269a90 100644 Binary files a/TouchyTickets/Content/Textures/Ui.aseprite and b/TouchyTickets/Content/Textures/Ui.aseprite differ diff --git a/TouchyTickets/Content/Textures/Ui.png b/TouchyTickets/Content/Textures/Ui.png index d862bc9..4428b2f 100644 Binary files a/TouchyTickets/Content/Textures/Ui.png and b/TouchyTickets/Content/Textures/Ui.png differ diff --git a/TouchyTickets/GameImpl.cs b/TouchyTickets/GameImpl.cs index e9dd9ea..3a58ded 100644 --- a/TouchyTickets/GameImpl.cs +++ b/TouchyTickets/GameImpl.cs @@ -68,28 +68,17 @@ namespace TouchyTickets { MaxScale = 24, MinScale = 2 }; + + // update the map once to make sure that catching up happens during loading + this.UpdateMapOnce(); } protected override void DoUpdate(GameTime gameTime) { base.DoUpdate(gameTime); if (this.Map != null) { - var now = DateTime.Now; - if (this.LastUpdate != default) { - var passed = now - this.LastUpdate; - // if more than 1 second passed, the app is minimized or a save was loaded, so we penalize - var toSimulate = passed.TotalSeconds >= 1 ? new TimeSpan(passed.Ticks / 2) : passed; - - var lastTickets = this.Tickets; - this.Map.Update(gameTime, toSimulate); - var generated = this.Tickets - lastTickets; - - // if 10 or more seconds passed, we display a message - if (Options.Instance.WhileYouWereAwayMessage && passed.TotalSeconds >= 10 && generated > 0) - Ui.DisplayWhileYouWereAway(passed, generated); - } - this.LastUpdate = now; - + // update the map + this.UpdateMapOnce(); // save every 3 seconds this.saveCounter += gameTime.ElapsedGameTime.TotalSeconds; if (this.saveCounter >= 3) { @@ -129,5 +118,20 @@ namespace TouchyTickets { return (int) BigInteger.Min(3, this.Tickets / this.GetStarPrice()); } + private void UpdateMapOnce() { + var now = DateTime.Now; + if (this.LastUpdate != default) { + var lastTickets = this.Tickets; + var passed = now - this.LastUpdate; + this.Map.Update(passed, passed.TotalSeconds >= 1); + var generated = this.Tickets - lastTickets; + + // if 10 or more seconds passed, we display a message + if (Options.Instance.WhileYouWereAwayMessage && passed.TotalSeconds >= 10 && generated > 0) + Ui.DisplayWhileYouWereAway(passed, generated); + } + this.LastUpdate = now; + } + } } \ No newline at end of file diff --git a/TouchyTickets/Options.cs b/TouchyTickets/Options.cs index 8f16205..9ecce2c 100644 --- a/TouchyTickets/Options.cs +++ b/TouchyTickets/Options.cs @@ -31,6 +31,12 @@ namespace TouchyTickets { } } private bool keepScreenOn; + [DataMember] + public bool AutoBuyEnabled = true; + [DataMember] + public int MinTicketsForAutoBuy = 50000; + [DataMember] + public float AutoBuyIntervalSecs = 60; public static void Save() { var file = GetOptionsFile(true); diff --git a/TouchyTickets/ParkMap.cs b/TouchyTickets/ParkMap.cs index 29eacfb..657e06d 100644 --- a/TouchyTickets/ParkMap.cs +++ b/TouchyTickets/ParkMap.cs @@ -33,6 +33,7 @@ namespace TouchyTickets { public Point PlacingPosition; public Point? SelectedPosition; private bool draggingAttraction; + private TimeSpan autoBuyCounter; public ParkMap(int width, int height) { this.Width = width; @@ -68,15 +69,29 @@ namespace TouchyTickets { } } - public void Update(GameTime time, TimeSpan passed) { + public void Update(TimeSpan passed, bool wasAway) { + var toSimulate = wasAway ? new TimeSpan(passed.Ticks / 2) : passed; + + // handle auto-buying + this.autoBuyCounter += toSimulate; + if (this.autoBuyCounter.TotalSeconds >= Options.Instance.AutoBuyIntervalSecs) { + this.autoBuyCounter = TimeSpan.Zero; + this.TryAutoBuy(); + } + + // update tickets this.TicketsPerRide.Clear(); this.TicketsPerSecond = 0; foreach (var (pos, attraction) in this.attractions) { - var genPerSecond = attraction.Update(time, passed, this, pos); + var genPerSecond = attraction.Update(toSimulate, this, pos); // store ride statistics this.TicketsPerRide.TryGetValue(attraction.Type, out var curr); this.TicketsPerRide[attraction.Type] = curr + genPerSecond; this.TicketsPerSecond += genPerSecond; + + // after each attraction has sold their tickets, try auto-buying again if we were away + if (wasAway && passed.TotalSeconds >= Options.Instance.AutoBuyIntervalSecs) + this.TryAutoBuy(); } // map movement @@ -229,5 +244,29 @@ namespace TouchyTickets { return newMap; } + private void TryAutoBuy() { + if (!Options.Instance.AutoBuyEnabled) + return; + while (GameImpl.Instance.Tickets >= Options.Instance.MinTicketsForAutoBuy) { + var success = false; + + // auto-buy modifiers + if (Upgrade.AutoPlaceModifiers[0].IsActive()) { + foreach (var modifier in AttractionModifier.Modifiers.Values) { + var match = this.attractions.Select(pa => pa.Item2).Where(modifier.IsAffected); + // if we don't have level 2, we only want to increase existing modifiers + if (!Upgrade.AutoPlaceModifiers[1].IsActive()) + match = match.Where(a => a.GetModifierAmount(modifier) > 0); + var attraction = match.OrderBy(a => a.GetModifierAmount(modifier)).FirstOrDefault(); + if (attraction != null && modifier.Buy(attraction)) + success = true; + } + } + + if (!success) + break; + } + } + } } \ No newline at end of file diff --git a/TouchyTickets/Ui.cs b/TouchyTickets/Ui.cs index 1f7680e..177737b 100644 --- a/TouchyTickets/Ui.cs +++ b/TouchyTickets/Ui.cs @@ -255,12 +255,8 @@ namespace TouchyTickets { } for (var i = 0; i < placeAmount; i++) { - var price = attraction.GetModifierPrice(map.PlacingModifier); - if (GameImpl.Instance.Tickets < price) + if (!map.PlacingModifier.Buy(attraction)) break; - GameImpl.Instance.Tickets -= price; - GameImpl.Instance.Platform.AddResourceEvent(true, "Tickets", (float) price, "Modifier", modifier.Name); - attraction.ApplyModifier(map.PlacingModifier); } attraction.Wobble(); }, @@ -376,6 +372,37 @@ namespace TouchyTickets { ChildPadding = new Padding(5, 15, 5, 5), PreventParentSpill = true }); + + optionList.AddChild(new Paragraph(Anchor.AutoCenter, 1, Localization.Get("GameplayOptions"), true) { + TextScale = 0.12F + }); + optionList.AddChild(new Checkbox(Anchor.AutoLeft, new Vector2(1, 20), Localization.Get("AutoBuyEnabled"), Options.Instance.AutoBuyEnabled) { + OnCheckStateChange = (e, value) => { + Options.Instance.AutoBuyEnabled = value; + Options.Save(); + }, + PositionOffset = new Vector2(0, 1) + }); + optionList.AddChild(new Paragraph(Anchor.AutoLeft, 1, Localization.Get("MinTicketsForAutoBuy"))); + var num = optionList.AddChild(ElementHelper.NumberField(Anchor.AutoLeft, new Vector2(1, 20), Options.Instance.MinTicketsForAutoBuy, 1000, null, (t, value) => { + if (int.TryParse(value, out Options.Instance.MinTicketsForAutoBuy)) + Options.Save(); + })); + num.PositionOffset = new Vector2(0, 1); + optionList.AddChild(new Paragraph(Anchor.AutoLeft, 1, p => Localization.Get("AutoBuyInterval") + ": " + Options.Instance.AutoBuyIntervalSecs)); + optionList.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 20), 10, 299) { + PositionOffset = new Vector2(0, 1), + CurrentValue = Options.Instance.AutoBuyIntervalSecs - 1, + OnValueChanged = (s, v) => { + Options.Instance.AutoBuyIntervalSecs = (int) v + 1; + Options.Save(); + } + }); + + optionList.AddChild(new Paragraph(Anchor.AutoCenter, 1, Localization.Get("OtherOptions"), true) { + PositionOffset = new Vector2(0, 10), + TextScale = 0.12F + }); optionList.AddChild(new Paragraph(Anchor.AutoLeft, 1, p => Localization.Get("RainingTicketLimit") + ": " + Options.Instance.RainingTicketLimit)); optionList.AddChild(new Slider(Anchor.AutoLeft, new Vector2(1, 20), 10, 500) { PositionOffset = new Vector2(0, 1), @@ -499,7 +526,7 @@ namespace TouchyTickets { uiSystem.AutoScaleWithScreen = true; uiSystem.AutoScaleReferenceSize = new Point(720, 1280); uiSystem.Style.Font = new GenericSpriteFont(Assets.Font); - uiSystem.Style.PanelTexture = uiSystem.Style.ScrollBarBackground = uiSystem.Style.CheckboxTexture = new NinePatch(Assets.UiTexture[2, 1], 4); + uiSystem.Style.PanelTexture = uiSystem.Style.TextFieldTexture = uiSystem.Style.ScrollBarBackground = uiSystem.Style.CheckboxTexture = new NinePatch(Assets.UiTexture[2, 1], 4); uiSystem.Style.ButtonTexture = uiSystem.Style.ScrollBarScrollerTexture = new NinePatch(Assets.UiTexture[3, 1], 4); uiSystem.Style.CheckboxCheckmark = Assets.UiTexture[4, 1]; uiSystem.Style.TextScale = 0.1F; diff --git a/TouchyTickets/Upgrade.cs b/TouchyTickets/Upgrade.cs index cfc2cc1..a52ccb5 100644 --- a/TouchyTickets/Upgrade.cs +++ b/TouchyTickets/Upgrade.cs @@ -12,6 +12,7 @@ namespace TouchyTickets { public static readonly Upgrade[] MapSize = RegisterTiers("MapSize", 5, 1, 1, new Point(0, 3)); public static readonly Upgrade[] TapIncrease = RegisterTiers("TapIncrease", 3, 1, 0.5F, new Point(6, 3)); public static readonly Upgrade[] ModifierIncrease = RegisterTiers("ModifierIncrease", 3, 1, 1.5F, new Point(9, 3)); + public static readonly Upgrade[] AutoPlaceModifiers = RegisterTiers("AutoPlaceModifiers", 2, 6, 1, new Point(10, 3)); public static readonly Upgrade FerrisWheelModifier = Register(new Upgrade("FerrisWheelModifier", 1, new Point(2, 3))); public static readonly Upgrade NatureModifier = Register(new Upgrade("NatureModifier", 1, new Point(8, 3))); public static readonly Upgrade FoodCourtModifier = Register(new Upgrade("FoodCourtModifier", 2, new Point(1, 3)));