the start of upgrades!

This commit is contained in:
Ellpeck 2020-06-01 23:02:47 +02:00
parent 6f2eff29cc
commit 3feb5f86da
9 changed files with 177 additions and 37 deletions

View file

@ -38,7 +38,7 @@ namespace TouchyTickets.Attractions {
}
private static void Register(AttractionType type) {
Attractions[type.Name] = type;
Attractions.Add(type.Name, type);
}
public delegate Attraction Constructor(AttractionType type);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
@ -7,12 +8,16 @@ using MLEM.Extensions;
using MLEM.Font;
using MLEM.Startup;
using TouchyTickets.Attractions;
using TouchyTickets.Upgrades;
namespace TouchyTickets {
public class GameImpl : MlemGame {
public static GameImpl Instance { get; private set; }
public readonly ISet<Upgrade> AppliedUpgrades = new HashSet<Upgrade>();
public BigInteger Tickets;
public int TimesRestarted;
public int Stars;
public ParkMap Map;
public Camera Camera { get; private set; }
public Ui Ui { get; private set; }
@ -28,7 +33,7 @@ namespace TouchyTickets {
base.LoadContent();
if (!SaveHandler.Load(this))
this.Map = new ParkMap(10, 10);
this.Map = new ParkMap(12, 12);
this.Ui = new Ui(this.UiSystem);
this.Camera = new Camera(this.GraphicsDevice) {
@ -36,7 +41,7 @@ namespace TouchyTickets {
AutoScaleWithScreen = true,
AutoScaleReferenceSize = new Point(720, 1280),
MaxScale = 24,
MinScale = 3
MinScale = 2
};
}
@ -73,22 +78,8 @@ namespace TouchyTickets {
base.DoDraw(gameTime);
}
public string DisplayTicketCount() {
if (this.Tickets < 1000)
return this.Tickets.ToString();
// thousands
if (this.Tickets < 1000000)
return this.Tickets.ToString("0,.##K");
// millions
if (this.Tickets < 1000000000)
return this.Tickets.ToString("0,,.##M");
// billions
if (this.Tickets < 1000000000000)
return this.Tickets.ToString("0,,,.##B");
// trillions
if (this.Tickets < 1000000000000000)
return this.Tickets.ToString("0,,,,.##T");
return this.Tickets.ToString("0,,,,,.##Q");
public BigInteger GetStarPrice() {
return BigInteger.Pow(1000000, this.TimesRestarted / 2 + 1);
}
}

View file

@ -16,7 +16,7 @@ namespace TouchyTickets {
public class ParkMap {
private static readonly UniformTextureAtlas TilesTexture = new UniformTextureAtlas(MlemGame.LoadContent<Texture2D>("Textures/Tiles"), 16, 16);
private const int AdditionalRadius = 10;
private const int AdditionalRadius = 15;
[DataMember]
public readonly int Width;
[DataMember]
@ -37,12 +37,15 @@ namespace TouchyTickets {
// set up trees
var random = new Random();
for (var i = 0; i < 100; i++) {
var type = random.Next(3);
var x = random.Next(-AdditionalRadius, this.Width + AdditionalRadius);
var y = random.Next(-AdditionalRadius, this.Height + AdditionalRadius);
if (x < 0 || y < 0 || x >= this.Width || y >= this.Width)
for (var x = -AdditionalRadius; x < this.Width + AdditionalRadius; x++) {
for (var y = -AdditionalRadius; y < this.Height + AdditionalRadius; y++) {
if (x >= 0 && y >= 0 && x < this.Width && y < this.Height)
continue;
if (random.Next(15) != 0)
continue;
var type = random.Next(3);
this.treePositions[new Point(x, y)] = type;
}
}
// set up fences
@ -163,5 +166,10 @@ namespace TouchyTickets {
return this.attractions.Count(a => a.Item2.Type == type);
}
public void CopyAttractionsFrom(ParkMap other) {
foreach (var (pos, attraction) in other.attractions)
this.Place(pos, attraction);
}
}
}

View file

@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Newtonsoft.Json;
using TouchyTickets.Upgrades;
namespace TouchyTickets {
public static class SaveHandler {
@ -20,7 +23,10 @@ namespace TouchyTickets {
SaveVersion = SaveVersion,
Tickets = game.Tickets,
LastUpdate = game.LastUpdate,
Map = game.Map
Map = game.Map,
Stars = game.Stars,
TimesRestarted = game.TimesRestarted,
Upgrades = game.AppliedUpgrades.Select(u => u.Name).ToList()
};
Serializer.Serialize(stream, data);
}
@ -35,6 +41,11 @@ namespace TouchyTickets {
game.Tickets = data.Tickets;
game.LastUpdate = data.LastUpdate;
game.Map = data.Map;
game.Stars = data.Stars;
game.TimesRestarted = data.TimesRestarted;
game.AppliedUpgrades.Clear();
foreach (var name in data.Upgrades)
game.AppliedUpgrades.Add(Upgrade.Upgrades[name]);
}
return true;
}
@ -59,6 +70,9 @@ namespace TouchyTickets {
public BigInteger Tickets;
public DateTime LastUpdate;
public ParkMap Map;
public int Stars;
public int TimesRestarted;
public List<string> Upgrades;
}
}

View file

@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="Coroutine" Version="1.0.4" />
<PackageReference Include="MLEM.Startup" Version="3.3.3-190" />
<PackageReference Include="MLEM.Startup" Version="3.3.3-191" />
<PackageReference Include="MonoGame.Framework.Portable" Version="3.7.1.189">
<PrivateAssets>all</PrivateAssets>
</PackageReference>

View file

@ -16,6 +16,7 @@ using MLEM.Textures;
using MLEM.Ui;
using MLEM.Ui.Elements;
using TouchyTickets.Attractions;
using TouchyTickets.Upgrades;
namespace TouchyTickets {
public class Ui {
@ -36,6 +37,7 @@ namespace TouchyTickets {
this.uiSystem.Style.Font = new GenericSpriteFont(MlemGame.LoadContent<SpriteFont>("Fonts/Regular"));
this.uiSystem.Style.TextScale = 0.1F;
this.uiSystem.TextFormatter.AddImage("ticket", Texture[2, 0]);
this.uiSystem.TextFormatter.AddImage("star", Texture[3, 0]);
// main ticket store ui
var rainingTickets = new List<RainingTicket>();
@ -55,7 +57,7 @@ namespace TouchyTickets {
}
};
var ticketGroup = main.AddChild(new Group(Anchor.AutoCenter, new Vector2(1, 0.15F), false));
ticketGroup.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => GameImpl.Instance.DisplayTicketCount(), true) {
ticketGroup.AddChild(new Paragraph(Anchor.AutoCenter, 10000, p => PrettyPrintNumber(GameImpl.Instance.Tickets) + "<i ticket>", true) {
TextScale = 0.3F
});
ticketGroup.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => GameImpl.Instance.Map.TicketsPerSecond.ToString("0.##") + "<i ticket>/s", true) {
@ -71,7 +73,13 @@ namespace TouchyTickets {
}
});
storeGroup.AddChild(new Image(Anchor.TopLeft, Vector2.One, Texture[0, 0, 2, 3]) {
OnPressed = e => GameImpl.Instance.Tickets++,
OnPressed = e => {
#if DEBUG
GameImpl.Instance.Tickets += 500000;
#else
GameImpl.Instance.Tickets++;
#endif
},
CanBeSelected = true,
CanBeMoused = true
});
@ -86,9 +94,6 @@ namespace TouchyTickets {
map.Draw(time, batch, pos, scale, alpha, false, new RectangleF(Vector2.Zero, mapSize * scale));
},
OnPressed = e => {
var map = GameImpl.Instance.Map;
GameImpl.Instance.Camera.LookingPosition = new Vector2(map.Width, map.Height) / 2 * Attraction.TileSize;
var backUi = new Group(Anchor.BottomLeft, new Vector2(1));
backUi.AddChild(new Button(Anchor.AutoInlineIgnoreOverflow, new Vector2(1, 40), "Back") {
OnPressed = e2 => this.FadeUi(false, () => this.uiSystem.Remove(e2.Root.Name))
@ -111,13 +116,12 @@ namespace TouchyTickets {
BigInteger price = 0;
var button = buyUi.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 40)) {
ChildPadding = new Vector2(4),
Padding = new Padding(0, 0, 0, 4),
OnPressed = e => {
var map = GameImpl.Instance.Map;
var pos = new Vector2(map.Width, map.Height) / 2;
GameImpl.Instance.Camera.LookingPosition = (pos + new Vector2(0.5F)) * Attraction.TileSize;
map.PlacingAttraction = attraction.Value.Create();
map.PlacingPosition = pos.ToPoint();
// set placing position to center of camera's view
var (posX, posY) = (GameImpl.Instance.Camera.LookingPosition / Attraction.TileSize).ToPoint();
map.PlacingPosition = new Point(MathHelper.Clamp(posX, 0, map.Width), MathHelper.Clamp(posY, 0, map.Height));
var yesNoUi = new Group(Anchor.BottomLeft, new Vector2(1));
yesNoUi.AddChild(new Button(Anchor.AutoInlineIgnoreOverflow, new Vector2(0.5F, 40), "Back") {
@ -157,7 +161,56 @@ namespace TouchyTickets {
}
this.uiSystem.Add("Buy", buyUi);
this.swipeRelations = new Element[] {main, buyUi};
// upgrade ui
var upgradeUi = new Group(Anchor.TopLeft, Vector2.One, false) {
IsHidden = true,
OnDrawn = (e, time, batch, alpha) => batch.Draw(batch.GetBlankTexture(), e.DisplayArea, ColorExtensions.FromHex(0xff86bccf) * alpha)
};
var upgradeHeader = upgradeUi.AddChild(new Group(Anchor.AutoLeft, new Vector2(1, 0.25F), false));
upgradeHeader.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => GameImpl.Instance.Stars + "<i star>", true) {TextScale = 0.3F});
upgradeHeader.AddChild(new Button(Anchor.AutoCenter, new Vector2(0.8F, 20), "Earn <i star>") {
PositionOffset = new Vector2(0, 4),
OnUpdated = (e, time) => ((Button) e).IsDisabled = GameImpl.Instance.Tickets < GameImpl.Instance.GetStarPrice(),
OnPressed = e => {
var game = GameImpl.Instance;
game.TimesRestarted++;
game.Stars++;
game.Map = new ParkMap(game.Map.Width, game.Map.Height);
game.Tickets = 0;
}
});
upgradeHeader.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => $"Requires {PrettyPrintNumber(GameImpl.Instance.GetStarPrice())}<i ticket>", true) {
PositionOffset = new Vector2(0, 2)
});
var upgradeList = upgradeUi.AddChild(new Panel(Anchor.AutoLeft, new Vector2(1, 0.75F), Vector2.Zero, false, true, new Point(10, 30), false) {
ChildPadding = new Padding(5, 15, 5, 5)
});
foreach (var upgrade in Upgrade.Upgrades.Values) {
var button = upgradeList.AddChild(new Button(Anchor.AutoLeft, new Vector2(1, 40)) {
ChildPadding = new Vector2(4),
OnPressed = e => {
GameImpl.Instance.Stars--;
GameImpl.Instance.AppliedUpgrades.Add(upgrade);
upgrade.OnApplied();
}
});
button.OnUpdated += (e, time) => {
// we want to hide if we're active, or if we still need a dependency to be active
button.IsHidden = Upgrade.IsActive(upgrade) || upgrade.Dependencies.Any(u => !Upgrade.IsActive(u));
button.IsDisabled = GameImpl.Instance.Stars < upgrade.Price;
};
var center = button.AddChild(new Group(Anchor.Center, new Vector2(0.8F, 1), false) {CanBeMoused = false});
center.AddChild(new Paragraph(Anchor.AutoCenter, 1, upgrade.Name, true));
//center.AddChild(new Paragraph(Anchor.AutoCenter, 1, upgrade.Description, true) {TextScale = 0.08F});
var image = button.AddChild(new Image(Anchor.CenterLeft, new Vector2(1), upgrade.Texture) {
Padding = new Vector2(4)
});
button.OnAreaUpdated += e => image.Size = new Vector2(e.DisplayArea.Height / e.Scale);
button.AddChild(new Paragraph(Anchor.CenterRight, 1, p => upgrade.Price + "<i star>", true));
}
this.uiSystem.Add("Upgrade", upgradeUi);
this.swipeRelations = new Element[] {upgradeUi, main, buyUi};
}
public void Update(GameTime time) {
@ -247,5 +300,23 @@ namespace TouchyTickets {
element.Transform = Matrix.Identity;
}
private static string PrettyPrintNumber(BigInteger number) {
if (number < 1000)
return number.ToString();
// thousands
if (number < 1000000)
return number.ToString("0,.##K");
// millions
if (number < 1000000000)
return number.ToString("0,,.##M");
// billions
if (number < 1000000000000)
return number.ToString("0,,,.##B");
// trillions
if (number < 1000000000000000)
return number.ToString("0,,,,.##T");
return number.ToString("0,,,,,.##Q");
}
}
}

56
TouchyTickets/Upgrade.cs Normal file
View file

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using MLEM.Extensions;
using MLEM.Textures;
namespace TouchyTickets.Upgrades {
public class Upgrade {
public static readonly Dictionary<string, Upgrade> Upgrades = new Dictionary<string, Upgrade>();
public static readonly Upgrade[] MapSize = RegisterTiers("MapSize", 10, 1, 0.5F, Ui.Texture[0, 3]);
public readonly string Name;
public readonly int Price;
public readonly TextureRegion Texture;
public readonly Upgrade[] Dependencies;
public Upgrade(string name, int price, TextureRegion texture, params Upgrade[] dependencies) {
this.Name = name;
this.Price = price;
this.Texture = texture;
this.Dependencies = dependencies;
}
private static Upgrade[] RegisterTiers(string name, int amount, int startPrice, float priceIncrease, TextureRegion texture) {
var ret = new Upgrade[amount];
for (var i = 0; i < amount; i++) {
// every tier except first depends on last tier
var deps = i == 0 ? Array.Empty<Upgrade>() : new[] {ret[i - 1]};
var price = (startPrice * (1 + i * priceIncrease)).Floor();
Register(ret[i] = new Upgrade(name + (i + 1), price, texture, deps));
}
return ret;
}
public void OnApplied() {
// map size upgrades
if (MapSize.Contains(this)) {
var oldMap = GameImpl.Instance.Map;
var newMap = new ParkMap(oldMap.Width + 5, oldMap.Height + 5);
newMap.CopyAttractionsFrom(oldMap);
GameImpl.Instance.Map = newMap;
}
}
private static void Register(Upgrade upgrade) {
Upgrades.Add(upgrade.Name, upgrade);
}
public static bool IsActive(Upgrade upgrade) {
return GameImpl.Instance.AppliedUpgrades.Contains(upgrade);
}
}
}