finished modifiers

This commit is contained in:
Ellpeck 2020-06-08 22:55:33 +02:00
parent 375d2e569e
commit 5e68917902
9 changed files with 88 additions and 55 deletions

View file

@ -30,6 +30,19 @@ namespace TouchyTickets.Attractions {
}
public float Update(GameTime time, TimeSpan passed, ParkMap map, Point position) {
var genRate = this.GetGenerationRate(map, position);
// apply generation rate to ticket amount
this.ticketPercentage += genRate * (float) passed.TotalSeconds;
var total = this.ticketPercentage.Floor();
if (total > 0) {
GameImpl.Instance.Tickets += total;
this.ticketPercentage -= total;
}
// return the generation rate per second
return genRate;
}
public float GetGenerationRate(ParkMap map, Point position) {
var genRate = this.Type.GetGenerationRate();
// apply attraction modifiers
@ -43,15 +56,7 @@ namespace TouchyTickets.Attractions {
genRate *= 2;
if (Upgrade.HauntedHouseModifier.IsActive() && this.Type.Flags.HasFlag(Relaxed) && this.GetSurrounding(map, position, HauntedHouse).Any())
genRate *= 3;
// apply generation rate to ticket amount
this.ticketPercentage += genRate * (float) passed.TotalSeconds;
var total = this.ticketPercentage.Floor();
if (total > 0) {
GameImpl.Instance.Tickets += total;
this.ticketPercentage -= total;
}
// return the generation rate per second
return genRate;
}
@ -68,7 +73,12 @@ namespace TouchyTickets.Attractions {
}
public int GetModifierAmount(AttractionModifier modifier) {
return this.Modifiers.Where(m => m.Modifier == modifier).Sum(m => m.Amount);
return this.Modifiers.Where(m => modifier == null || m.Modifier == modifier).Sum(m => m.Amount);
}
public int GetModifierPrice(AttractionModifier modifier) {
var amount = this.GetModifierAmount(modifier);
return (modifier.InitialPrice * (float) Math.Pow(1 + 0.4F, amount)).Ceil();
}
private IEnumerable<Attraction> GetSurrounding(ParkMap map, Point position, AttractionType type) {

View file

@ -11,8 +11,9 @@ namespace TouchyTickets.Attractions {
public static readonly Dictionary<string, AttractionModifier> Modifiers = new Dictionary<string, AttractionModifier>();
static AttractionModifier() {
Register(new AttractionModifier("Lubricant", 200, AttractionFlags.Cars, 1.05F, Ui.Texture[0, 4]));
Register(new AttractionModifier("LongerQueue", 1000, AttractionFlags.All, 1.01F, Ui.Texture[1, 4]));
Register(new AttractionModifier("Lubricant", 200, AttractionFlags.Cars, 1.02F, Ui.Texture[0, 4]));
Register(new AttractionModifier("LouderMusic", 500, AttractionFlags.Relaxed, 1.05F, Ui.Texture[2, 4]));
Register(new AttractionModifier("LongerQueue", 1000, AttractionFlags.All, 1.1F, Ui.Texture[1, 4]));
}
public readonly string Name;

View file

@ -6,11 +6,8 @@
"ReallyEarnStar": "Cashing in your <i ticket> now would earn you {0}<i star>. It will also remove all placed attractions and reset your <i ticket>. Are you sure?",
"Yes": "Yes",
"Okay": "Okay",
"Add": "Add",
"RequiresTickets": "{0}<i ticket> for 1<i star>. Maximum {1}.",
"AppliedUpgrades": "Active Upgrades",
"Attractions": "Attractions",
"Modifiers": "Modifiers",
"Tutorial1": "Hi! Welcome to Touchy Tickets. To start the game, simply tap the ticket booth to sell a <i ticket>. Start by racking up 50<i ticket>!",
"Tutorial2": "Great! Now, you can buy your first attraction. Access the menu on the right by swiping and purchase a carousel.",
"Tutorial3": "This is your park map. The area inside the fence is what belongs to you. Place the carousel by dragging it to the perfect location and then pressing the button below.",
@ -21,6 +18,9 @@
"Tutorial8": "Alternatively, you can wait a little bit longer and buy multiple <i star> at once with more <i ticket>.",
"Tutorial9": "Now that you have a <i star>, you also have to restart the game. But don't worry: <i star> give you the ability to purchase some great permanent upgrades for your attractions.",
"Tutorial10": "Now, you can rack up more <i ticket> even faster to earn more <i star> to rack up more <i ticket>... you get the point. Have fun!",
"Tutorial11": "Now that you have a couple of attractions, you can start thinking about purchasing modifiers for them! Swipe to access the modifier menu on the far right and purchase a modifier.",
"Tutorial12": "Different kinds of modifiers can be applied to different attractions. Click on one of your attractions and add the modifier to it.",
"Tutorial13": "Modifiers add a ticket sale multiplier to a single attraction. Each attraction can have an infinite amount of any given modifier, so they're a great way to rack up tickets faster.",
"Carousel": "Carousel",
"FoodCourt": "Food Court",
"FerrisWheel": "Ferris Wheel",
@ -33,9 +33,11 @@
"MirrorHouse": "House of Mirrors",
"HauntedHouse": "Haunted House",
"Lubricant": "Slip and Slide",
"LubricantDescription": "A ride's cars are lubricated for greater speed. Works on attractions with cars.",
"LubricantDescription": "The wheels of a ride's cars are lubricated for greater speed.",
"LongerQueue": "Queuete",
"LongerQueueDescription": "The queue length of an attraction is increased. Works on all attractions.",
"LongerQueueDescription": "The queue length of an attraction is increased.",
"LouderMusic": "Audiophobia",
"LouderMusicDescription": "Relaxed rides play louder music, causing riders to leave faster.",
"MapSize1": "Big Park",
"MapSize1Description": "Increases your park's buildable area. Existing attractions are not removed.",
"MapSize2": "Bigger Park",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -114,7 +114,7 @@ namespace TouchyTickets {
if (MlemGame.Input.GetGesture(GestureType.Tap, out var tap)) {
var pos = (camera.ToWorldPos(tap.Position) / Attraction.TileSize).ToPoint();
var attraction = this.GetAttractionAt(pos);
if (attraction != null) {
if (attraction != null && (this.PlacingModifier == null || this.PlacingModifier.IsAffected(attraction))) {
// actually select the top left for easy usage later
this.SelectedPosition = this.attractions.First(kv => kv.Item2 == attraction).Item1;
} else if (GameImpl.Instance.UiSystem.Controls.GetElementUnderPos(tap.Position) == null) {
@ -152,16 +152,21 @@ namespace TouchyTickets {
var selected = this.SelectedPosition.Value;
var attr = this.GetAttractionAt(selected);
foreach (var pos in attr.Type.GetCoveredTiles())
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (selected.ToVector2() + pos.ToVector2()) * tileSize, tileSize), Color.Black * 0.15F * alpha);
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (selected + pos).ToVector2() * tileSize, tileSize), Color.Black * 0.25F * alpha);
}
// draw attractions
foreach (var (pos, attraction) in this.attractions)
foreach (var (pos, attraction) in this.attractions) {
if (this.SelectedPosition != pos && this.PlacingModifier != null && this.PlacingModifier.IsAffected(attraction)) {
foreach (var offset in attraction.Type.GetCoveredTiles())
batch.Draw(batch.GetBlankTexture(), new RectangleF(position + (pos + offset).ToVector2() * tileSize, tileSize), Color.Yellow * 0.25F * alpha);
}
batch.Draw(attraction.Type.TextureRegion, position + pos.ToVector2() * tileSize, Color.White * alpha, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
}
// placing attraction
if (this.PlacingAttraction != null) {
var placingPos = position + this.PlacingPosition.ToVector2() * tileSize;
foreach (var pos in this.PlacingAttraction.Type.GetCoveredTiles())
batch.Draw(batch.GetBlankTexture(), new RectangleF(placingPos + pos.ToVector2() * tileSize, tileSize), Color.Black * 0.15F * alpha);
batch.Draw(batch.GetBlankTexture(), new RectangleF(placingPos + pos.ToVector2() * tileSize, tileSize), Color.Black * 0.25F * alpha);
batch.Draw(this.PlacingAttraction.Type.TextureRegion, placingPos, Color.White * alpha * 0.5F, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
}
}
@ -197,7 +202,7 @@ namespace TouchyTickets {
}
public int GetAttractionAmount(AttractionType type) {
return this.attractions.Count(a => a.Item2.Type == type);
return this.attractions.Count(a => type == null || a.Item2.Type == type);
}
public int GetModifierAmount(AttractionModifier modifier) {

View file

@ -13,7 +13,7 @@ namespace TouchyTickets {
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
});
private const int SaveVersion = 2;
private const int SaveVersion = 3;
public static void Save(GameImpl game) {
var file = GetSaveFile(true);
@ -56,6 +56,11 @@ namespace TouchyTickets {
foreach (var upgrade in game.AppliedUpgrades.Intersect(Upgrade.MapSize))
upgrade.OnApplied();
}
// new tutorial additions need to be forced
if (data.SaveVersion <= 2) {
if (game.Tutorial.CurrentStep > 4)
game.Tutorial.CurrentStep = 4;
}
return true;
}

View file

@ -8,10 +8,16 @@ namespace TouchyTickets {
public class Tutorial {
private static readonly Step[] Steps = {
// introduction
new Step(g => true, "Tutorial1"),
new Step(g => g.Tickets >= AttractionType.Carousel.InitialPrice, "Tutorial2"),
new Step(g => g.DrawMap && g.Map.PlacingAttraction?.Type == AttractionType.Carousel, "Tutorial3"),
new Step(g => g.Map.GetAttractionAmount(AttractionType.Carousel) > 0, "Tutorial4", "Tutorial5", "Tutorial6"),
// modifier tutorial
new Step(g => g.Map.GetAttractionAmount(null) >= 3, "Tutorial11"),
new Step(g => g.Map.PlacingModifier != null, "Tutorial12"),
new Step(g => g.Map.GetModifierAmount(null) > 0, "Tutorial13"),
// star tutorial
new Step(g => g.Tickets >= g.GetStarPrice(), "Tutorial7", "Tutorial8"),
new Step(g => g.Stars > 0, "Tutorial9", "Tutorial10")
};

View file

@ -123,12 +123,7 @@ namespace TouchyTickets {
return;
var map = GameImpl.Instance.Map;
var infoUi = new Group(Anchor.BottomLeft, new Vector2(1));
infoUi.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => {
if (map.SelectedPosition == null)
return string.Empty;
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
return string.Join(" ", attraction.Modifiers.Select(m => $"{m.Amount}<i {m.Modifier.Name}>"));
}, true) {TextScale = 0.15F});
AddSelectedAttractionInfo(infoUi);
infoUi.AddChild(new Button(Anchor.AutoLeft, new Vector2(0.5F, 30), Localization.Get("Back")) {
OnPressed = e2 => this.FadeUi(false, () => this.uiSystem.Remove(e2.Root.Name))
});
@ -220,14 +215,6 @@ namespace TouchyTickets {
IsHidden = true
};
foreach (var modifier in AttractionModifier.Modifiers.Values) {
BigInteger price = 0;
BigInteger CalculatePrice() {
var modAmount = GameImpl.Instance.Map.GetModifierAmount(modifier);
price = (modifier.InitialPrice * (float) Math.Pow(1 + 0.4F, modAmount)).Ceil();
return price;
}
var button = modifierUi.AddChild(new Button(Anchor.AutoLeft, new Vector2(1)) {
SetHeightBasedOnChildren = true,
PositionOffset = new Vector2(0, 1),
@ -236,52 +223,52 @@ namespace TouchyTickets {
if (this.swipeProgress != 0)
return;
var map = GameImpl.Instance.Map;
map.PlacingModifier = modifier;
var infoUi = new Group(Anchor.BottomLeft, new Vector2(1));
infoUi.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => {
if (map.SelectedPosition == null)
return string.Empty;
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
return string.Join(" ", attraction.Modifiers.Select(m => $"{m.Amount}<i {m.Modifier.Name}>"));
}, true) {TextScale = 0.15F});
AddSelectedAttractionInfo(infoUi);
infoUi.AddChild(new Button(Anchor.AutoLeft, new Vector2(0.5F, 30), Localization.Get("Back")) {
OnPressed = e2 => this.FadeUi(false, () => this.uiSystem.Remove(e2.Root.Name))
});
infoUi.AddChild(new Button(Anchor.AutoInlineIgnoreOverflow, new Vector2(0.5F, 30), Localization.Get("Add")) {
var addButton = infoUi.AddChild(new Button(Anchor.AutoInlineIgnoreOverflow, new Vector2(0.5F, 30), string.Empty) {
OnPressed = e2 => {
if (map.SelectedPosition == null)
return;
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
attraction.ApplyModifier(modifier);
GameImpl.Instance.Tickets -= price;
// if we're out of tickets to buy this modifier, automatically go back
if (GameImpl.Instance.Tickets < CalculatePrice())
this.FadeUi(false, () => this.uiSystem.Remove(e2.Root.Name));
GameImpl.Instance.Tickets -= attraction.GetModifierPrice(map.PlacingModifier);
attraction.ApplyModifier(map.PlacingModifier);
},
OnUpdated = (e2, time) => {
var disabled = map.SelectedPosition == null;
if (!disabled) {
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
disabled = attraction == null || !modifier.IsAffected(attraction);
disabled = attraction == null || !map.PlacingModifier.IsAffected(attraction) || GameImpl.Instance.Tickets < attraction.GetModifierPrice(map.PlacingModifier);
}
((Button) e2).IsDisabled = disabled;
}
});
addButton.Text.GetTextCallback = p => {
var price = map.PlacingModifier.InitialPrice;
if (map.SelectedPosition != null) {
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
if (attraction != null && map.PlacingModifier.IsAffected(attraction))
price = attraction.GetModifierPrice(map.PlacingModifier);
}
return PrettyPrintNumber(price) + "<i ticket>";
};
// we want this to render below the main ui while it fades away
this.uiSystem.Add("ModifierInfo", infoUi).Priority = -100;
this.FadeUi(true);
},
OnAreaUpdated = e => CalculatePrice()
}
});
button.OnUpdated += (e, time) => button.IsDisabled = GameImpl.Instance.Tickets < price;
button.OnUpdated += (e, time) => button.IsDisabled = GameImpl.Instance.Tickets < modifier.InitialPrice;
button.AddChild(new Image(Anchor.CenterLeft, new Vector2(0.2F, 40), modifier.Texture) {
Padding = new Vector2(4)
});
var right = button.AddChild(new Group(Anchor.TopRight, new Vector2(0.8F, 1)) {CanBeMoused = false});
right.AddChild(new Paragraph(Anchor.TopLeft, 1, Localization.Get(modifier.Name), true));
right.AddChild(new Paragraph(Anchor.AutoLeft, 1, Localization.Get(modifier.Name + "Description"), true) {TextScale = 0.08F});
right.AddChild(new Paragraph(Anchor.AutoRight, 1, p => PrettyPrintNumber(price) + "<i ticket>", true));
right.AddChild(new Paragraph(Anchor.AutoRight, 1, p => PrettyPrintNumber(modifier.InitialPrice) + "<i ticket>", true));
right.AddChild(new Paragraph(Anchor.BottomLeft, 1, $"x{modifier.Multiplier}<i ticket>", true) {TextScale = 0.08F});
}
this.uiSystem.Add("Modifiers", modifierUi);
@ -436,6 +423,23 @@ namespace TouchyTickets {
CoroutineHandler.Start(Impl());
}
private static void AddSelectedAttractionInfo(Element element) {
var map = GameImpl.Instance.Map;
element.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => {
if (map.SelectedPosition == null)
return string.Empty;
var attraction = map.GetAttractionAt(map.SelectedPosition.Value);
return string.Join(" ", attraction.Modifiers.Select(m => $"{m.Amount}<i {m.Modifier.Name}>"));
}, true));
element.AddChild(new Paragraph(Anchor.AutoCenter, 1, p => {
if (map.SelectedPosition == null)
return string.Empty;
var pos = map.SelectedPosition.Value;
var attraction = map.GetAttractionAt(pos);
return attraction.GetGenerationRate(map, pos).ToString("0.##") + "<i ticket>/s";
}, true));
}
private static void PopulateUpgradeList(Element upgradeList) {
upgradeList.RemoveChildren(c => !(c is ScrollBar));
var reachedActive = false;