From c1ff7812d814200e016fd3d13a0473c2c286e296 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 5 Oct 2019 00:21:48 -0400 Subject: [PATCH] Zone objective abstraction, cleanup --- core/assets/bundles/bundle.properties | 7 +- .../io/anuke/mindustry/content/Blocks.java | 14 +-- core/src/io/anuke/mindustry/core/Control.java | 2 +- core/src/io/anuke/mindustry/core/Logic.java | 4 + .../io/anuke/mindustry/game/Objective.java | 12 ++ .../io/anuke/mindustry/game/Objectives.java | 38 ++++++ .../io/anuke/mindustry/type/ItemStack.java | 4 + core/src/io/anuke/mindustry/type/Zone.java | 44 ++++++- .../ui/dialogs/CustomRulesDialog.java | 20 ++- .../mindustry/ui/dialogs/DeployDialog.java | 2 +- .../mindustry/ui/dialogs/LoadoutDialog.java | 118 +++++++++--------- .../mindustry/ui/dialogs/ZoneInfoDialog.java | 14 ++- 12 files changed, 182 insertions(+), 97 deletions(-) create mode 100644 core/src/io/anuke/mindustry/game/Objective.java create mode 100644 core/src/io/anuke/mindustry/game/Objectives.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 650e4c293e..3613fc242b 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -391,8 +391,9 @@ donate = Donate abandon = Abandon abandon.text = This zone and all its resources will be lost to the enemy. locked = Locked -complete = [lightgray]Reach: -zone.requirement = Wave {0} in zone {1} +complete = [lightgray]Complete: +zone.requirement.wave = Wave {0} in {1} +zone.requirement = Destroy core: {0} resume = Resume Zone:\n[lightgray]{0} bestwave = [lightgray]Best Wave: {0} launch = < LAUNCH > @@ -406,7 +407,7 @@ configure = Configure Loadout configure.locked = [lightgray]Unlock configuring loadout: Wave {0}. configure.invalid = Amount must be a number between 0 and {0}. zone.unlocked = [lightgray]{0} unlocked. -zone.requirement.complete = Wave {0} reached:\n{1} zone requirements met. +zone.requirements.met = {0}: zone requirements met. zone.config.complete = Wave {0} reached:\nLoadout config unlocked. zone.resources = [lightgray]Resources Detected: zone.objective = [lightgray]Objective: [accent]{0} diff --git a/core/src/io/anuke/mindustry/content/Blocks.java b/core/src/io/anuke/mindustry/content/Blocks.java index 573ad8a832..0fa8f44e5c 100644 --- a/core/src/io/anuke/mindustry/content/Blocks.java +++ b/core/src/io/anuke/mindustry/content/Blocks.java @@ -965,12 +965,12 @@ public class Blocks implements ContentList{ //region liquid mechanicalPump = new Pump("mechanical-pump"){{ - requirements(Category.liquid, ItemStack.with(Items.copper, 15, Items.lead, 10)); + requirements(Category.liquid, ItemStack.with(Items.copper, 15, Items.metaglass, 10)); pumpAmount = 0.1f; }}; rotaryPump = new Pump("rotary-pump"){{ - requirements(Category.liquid, ItemStack.with(Items.copper, 70, Items.lead, 50, Items.silicon, 20, Items.titanium, 35)); + requirements(Category.liquid, ItemStack.with(Items.copper, 70, Items.metaglass, 50, Items.silicon, 20, Items.titanium, 35)); pumpAmount = 0.8f; consumes.power(0.15f); liquidCapacity = 30f; @@ -979,7 +979,7 @@ public class Blocks implements ContentList{ }}; thermalPump = new Pump("thermal-pump"){{ - requirements(Category.liquid, ItemStack.with(Items.copper, 80, Items.lead, 65, Items.silicon, 30, Items.titanium, 40, Items.thorium, 35)); + requirements(Category.liquid, ItemStack.with(Items.copper, 80, Items.metaglass, 70, Items.silicon, 30, Items.titanium, 40, Items.thorium, 35)); pumpAmount = 1.5f; consumes.power(0.30f); liquidCapacity = 40f; @@ -993,13 +993,13 @@ public class Blocks implements ContentList{ }}; pulseConduit = new Conduit("pulse-conduit"){{ - requirements(Category.liquid, ItemStack.with(Items.titanium, 1, Items.metaglass, 1)); + requirements(Category.liquid, ItemStack.with(Items.titanium, 2, Items.metaglass, 1)); liquidCapacity = 16f; health = 90; }}; liquidRouter = new LiquidRouter("liquid-router"){{ - requirements(Category.liquid, ItemStack.with(Items.titanium, 2, Items.metaglass, 2)); + requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 2)); liquidCapacity = 20f; }}; @@ -1011,11 +1011,11 @@ public class Blocks implements ContentList{ }}; liquidJunction = new LiquidJunction("liquid-junction"){{ - requirements(Category.liquid, ItemStack.with(Items.titanium, 2, Items.metaglass, 2)); + requirements(Category.liquid, ItemStack.with(Items.graphite, 2, Items.metaglass, 2)); }}; bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{ - requirements(Category.liquid, ItemStack.with(Items.titanium, 4, Items.metaglass, 4)); + requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 8)); range = 4; hasPower = false; }}; diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 771dbba8d4..2dcbcb42c0 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -146,7 +146,7 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(ZoneRequireCompleteEvent.class, e -> { - ui.hudfrag.showToast(Core.bundle.format("zone.requirement.complete", state.wave, e.zone.localizedName)); + ui.hudfrag.showToast(Core.bundle.format("zone.requirements.met", e.zone.localizedName)); }); Events.on(ZoneConfigureCompleteEvent.class, e -> { diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index c0544f70bf..34014ba874 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -180,6 +180,10 @@ public class Logic implements ApplicationListener{ Effects.effect(Fx.launch, tile); } + if(world.getZone() != null){ + world.getZone().setLaunched(); + } + Time.runTask(30f, () -> { for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){ for(Item item : content.items()){ diff --git a/core/src/io/anuke/mindustry/game/Objective.java b/core/src/io/anuke/mindustry/game/Objective.java new file mode 100644 index 0000000000..1ed588d4a3 --- /dev/null +++ b/core/src/io/anuke/mindustry/game/Objective.java @@ -0,0 +1,12 @@ +package io.anuke.mindustry.game; + +/** Defines a specific objective for a game. */ +public interface Objective{ + + /** @return whether this objective is met. */ + boolean complete(); + + /** @return the string displayed when this objective is completed, in imperative form. + * e.g. when the objective is 'complete 10 waves', this would display "complete 10 waves".*/ + String display(); +} diff --git a/core/src/io/anuke/mindustry/game/Objectives.java b/core/src/io/anuke/mindustry/game/Objectives.java new file mode 100644 index 0000000000..a2ca6d506b --- /dev/null +++ b/core/src/io/anuke/mindustry/game/Objectives.java @@ -0,0 +1,38 @@ +package io.anuke.mindustry.game; + +/** Holds objective classes. */ +public class Objectives{ + + public static class WaveObjective implements Objective{ + public int wave; + + public WaveObjective(int wave){ + this.wave = wave; + } + + protected WaveObjective(){} + + @Override + public boolean complete(){ + return false; + } + + @Override + public String display(){ + return null; + } + } + + public static class LaunchObjective implements Objective{ + + @Override + public boolean complete(){ + return false; + } + + @Override + public String display(){ + return null; + } + } +} diff --git a/core/src/io/anuke/mindustry/type/ItemStack.java b/core/src/io/anuke/mindustry/type/ItemStack.java index 9e428716dc..4ea87f5605 100644 --- a/core/src/io/anuke/mindustry/type/ItemStack.java +++ b/core/src/io/anuke/mindustry/type/ItemStack.java @@ -19,6 +19,10 @@ public class ItemStack implements Comparable{ item = Items.copper; } + public ItemStack copy(){ + return new ItemStack(item, amount); + } + public boolean equals(ItemStack other){ return other != null && other.item == item && other.amount == amount; } diff --git a/core/src/io/anuke/mindustry/type/Zone.java b/core/src/io/anuke/mindustry/type/Zone.java index 3a499996c4..42969fa00b 100644 --- a/core/src/io/anuke/mindustry/type/Zone.java +++ b/core/src/io/anuke/mindustry/type/Zone.java @@ -5,8 +5,8 @@ import io.anuke.arc.collection.*; import io.anuke.arc.function.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.layout.*; -import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; @@ -74,7 +74,7 @@ public class Zone extends UnlockableContent{ } for(ZoneRequirement other : zoneRequirements){ - if(other.zone.bestWave() < other.wave){ + if(!other.isComplete()){ return false; } } @@ -104,6 +104,23 @@ public class Zone extends UnlockableContent{ defaultStartingItems.each(stack -> startingItems.add(new ItemStack(stack.item, stack.amount))); } + public boolean hasLaunched(){ + return Core.settings.getBool(name + "-launched", false); + } + + public void setLaunched(){ + if(!hasLaunched() && getRules().attackMode){ + for(Zone zone : content.zones()){ + ZoneRequirement req = Structs.find(zone.zoneRequirements, f -> f.zone == this); + if(req != null && req.isComplete()){ + Events.fire(new ZoneRequireCompleteEvent(zone, this)); + } + } + } + Core.settings.put(name + "-launched", true); + data.modified(); + } + public void updateWave(int wave){ int value = Core.settings.getInt(name + "-wave", 0); if(value < wave){ @@ -112,7 +129,7 @@ public class Zone extends UnlockableContent{ for(Zone zone : content.zones()){ ZoneRequirement req = Structs.find(zone.zoneRequirements, f -> f.zone == this); - if(req != null && wave == req.wave + 1){ + if(req != null && wave == req.wave + 1 && req.isComplete()){ Events.fire(new ZoneRequireCompleteEvent(zone, this)); } } @@ -127,7 +144,8 @@ public class Zone extends UnlockableContent{ return Core.settings.getInt(name + "-wave", 0); } - public boolean isCompleted(){ + /** @return whether initial conditions to launch are met. */ + public boolean isLaunchMet(){ return bestWave() >= conditionWave; } @@ -208,19 +226,33 @@ public class Zone extends UnlockableContent{ return ContentType.zone; } + /* public static class ZoneRequirement{ + public @NonNull Zone zone; - public @NonNull int wave; + public int wave; public ZoneRequirement(Zone zone, int wave){ this.zone = zone; this.wave = wave; } + public ZoneRequirement(Zone zone){ + this.zone = zone; + } + protected ZoneRequirement(){ } + public boolean isComplete(){ + if(zone.getRules().attackMode){ + return zone.hasLaunched(); + }else{ + return zone.bestWave() >= wave; + } + } + public static ZoneRequirement[] with(Object... objects){ ZoneRequirement[] out = new ZoneRequirement[objects.length / 2]; for(int i = 0; i < objects.length; i += 2){ @@ -228,6 +260,6 @@ public class Zone extends UnlockableContent{ } return out; } - } + }*/ } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java index 10f418c1de..ae1a63ea71 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java @@ -1,16 +1,14 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.function.*; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.scene.ui.layout.Table; +import io.anuke.arc.graphics.*; +import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; -import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.content.Items; -import io.anuke.mindustry.game.Rules; -import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.type.ItemStack; -import io.anuke.mindustry.type.ItemType; +import io.anuke.mindustry.content.*; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.type.*; import static io.anuke.mindustry.Vars.tilesize; @@ -69,13 +67,11 @@ public class CustomRulesDialog extends FloatingDialog{ main.addButton("$configure", () -> loadoutDialog.show( Blocks.coreShard.itemCapacity, - () -> rules.loadout, + rules.loadout, () -> { rules.loadout.clear(); rules.loadout.add(new ItemStack(Items.copper, 100)); - }, - () -> {}, () -> {}, - item -> item.type == ItemType.material + }, () -> {}, () -> {} )).left().width(300f); main.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java index 86841152e8..c04816139b 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java @@ -129,7 +129,7 @@ public class DeployDialog extends FloatingDialog{ button.defaults().colspan(2); button.row(); - button.add(Core.bundle.format("save.wave", color + slot.getWave())); + button.add(Core.bundle.format("save", color + slot.getWave())); button.row(); button.label(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime())); button.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java index 9e541990e6..fc5b560678 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java @@ -2,9 +2,7 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.*; import io.anuke.arc.collection.*; -import io.anuke.arc.function.*; import io.anuke.arc.input.*; -import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.game.*; @@ -16,10 +14,12 @@ import static io.anuke.mindustry.Vars.*; public class LoadoutDialog extends FloatingDialog{ private Runnable hider; - private Supplier> supplier; + //private Supplier> supplier; private Runnable resetter; private Runnable updater; - private Predicate filter; + private Array stacks = new Array<>(); + private Array originalStacks = new Array<>(); + //private Predicate filter; private Table items; private int capacity; @@ -33,54 +33,37 @@ public class LoadoutDialog extends FloatingDialog{ } }); - cont.add(items = new Table()).left(); + cont.pane(t -> items = t.margin(10f)).left(); shown(this::setup); hidden(() -> { + originalStacks.selectFrom(stacks, s -> s.amount > 0); + updater.run(); if(hider != null){ hider.run(); } }); - cont.row(); + buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f); - cont.addButton("$add", () -> { - FloatingDialog dialog = new FloatingDialog(""); - dialog.setFillParent(false); - for(Item item : content.items().select(item -> filter.test(item) && item.type == ItemType.material && supplier.get().find(stack -> stack.item == item) == null)){ - TextButton button = dialog.cont.addButton("", Styles.cleart, () -> { - dialog.hide(); - supplier.get().add(new ItemStack(item, 0)); - updater.run(); - setup(); - }).size(300f, 36f).get(); - button.clearChildren(); - button.left(); - button.addImage(item.icon(Cicon.small)).size(8 * 3).pad(4); - button.add(item.localizedName); - dialog.cont.row(); - } - dialog.show(); - }).size(100f, 40).left().disabled(b -> !content.items().contains(item -> filter.test(item) && !supplier.get().contains(stack -> stack.item == item))); - - cont.row(); - cont.addButton("$settings.reset", () -> { + buttons.addImageTextButton("$settings.reset", Icon.refreshSmall, () -> { resetter.run(); updater.run(); setup(); }).size(210f, 64f); - - cont.row(); - cont.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f); } - public void show(int capacity, Supplier> supplier, Runnable reseter, Runnable updater, Runnable hider, Predicate filter){ + public void show(int capacity, Array stacks, Runnable reseter, Runnable updater, Runnable hider){ + this.originalStacks = stacks; + this.stacks = stacks.map(ItemStack::copy); + this.stacks.addAll(content.items().select(i -> i.type == ItemType.material && + !stacks.contains(stack -> stack.item == i)).map(i -> new ItemStack(i, 0))); + this.stacks.sort(Structs.comparingInt(s -> s.item.id)); this.resetter = reseter; - this.supplier = supplier; this.updater = updater; this.capacity = capacity; this.hider = hider; - this.filter = filter; + //this.filter = filter; show(); } @@ -88,41 +71,54 @@ public class LoadoutDialog extends FloatingDialog{ items.clearChildren(); items.left(); float bsize = 40f; - int step = 50; - for(ItemStack stack : supplier.get()){ - items.addButton("x", Styles.clearPartialt, () -> { - supplier.get().remove(stack); - updater.run(); - setup(); - }).size(bsize); + int i = 0; - items.addButton("-", Styles.clearPartialt, () -> { - stack.amount = Math.max(stack.amount - step, 0); - updater.run(); - }).size(bsize); + for(ItemStack stack : stacks){ + items.table(Tex.pane, t -> { + t.margin(4).marginRight(8).left(); + t.addButton("-", Styles.cleart, () -> { + stack.amount = Math.max(stack.amount - step(stack.amount), 0); + updater.run(); + }).size(bsize); - items.addButton("+", Styles.clearPartialt, () -> { - stack.amount = Math.min(stack.amount + step, capacity); - updater.run(); - }).size(bsize); + t.addButton("+", Styles.cleart, () -> { + stack.amount = Math.min(stack.amount + step(stack.amount), capacity); + updater.run(); + }).size(bsize); - items.addImageButton(Icon.pencilSmaller, Styles.clearPartial2i, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> { - if(Strings.canParsePostiveInt(str)){ - int amount = Strings.parseInt(str); - if(amount >= 0 && amount <= capacity){ - stack.amount = amount; - updater.run(); - return; + t.addImageButton(Icon.pencilSmaller, Styles.cleari, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> { + if(Strings.canParsePostiveInt(str)){ + int amount = Strings.parseInt(str); + if(amount >= 0 && amount <= capacity){ + stack.amount = amount; + updater.run(); + return; + } } - } - ui.showInfo(Core.bundle.format("configure.invalid", capacity)); - })).size(bsize); + ui.showInfo(Core.bundle.format("configure.invalid", capacity)); + })).size(bsize); - items.addImage(stack.item.icon(Cicon.small)).size(8 * 3).padRight(4).padLeft(4); - items.label(() -> stack.amount + "").left(); + t.addImage(stack.item.icon(Cicon.small)).size(8 * 3).padRight(4).padLeft(4); + t.label(() -> stack.amount + "").left().width(90f); + }).pad(2).left().fillX(); - items.row(); + + if(++i % 2 == 0 || (mobile && Core.graphics.isPortrait())){ + items.row(); + } + } + } + + private int step(int amount){ + if(amount < 1000){ + return 100; + }else if(amount < 2000){ + return 200; + }else if(amount < 5000){ + return 500; + }else{ + return 1000; } } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java index ab943f8f5b..e2827648de 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java @@ -66,10 +66,12 @@ public class ZoneInfoDialog extends FloatingDialog{ req.table(r -> { r.add("$complete").colspan(2).left(); r.row(); - for(ZoneRequirement other : zone.zoneRequirements){ + for(ZoneRequirement zreq : zone.zoneRequirements){ r.addImage(Icon.terrain).padRight(4); - r.add(Core.bundle.format("zone.requirement", other.wave, other.zone.localizedName())).color(Color.lightGray); - r.addImage(other.zone.bestWave() >= other.wave ? Icon.checkSmall : Icon.cancelSmall, other.zone.bestWave() >= other.wave ? Color.lightGray : Color.scarlet).padLeft(3); + r.add(!zreq.zone.getRules().attackMode ? + Core.bundle.format("zone.requirement.wave", zreq.wave, zreq.zone.localizedName()) : + Core.bundle.format("zone.requirement", zreq.zone.localizedName)).color(Color.lightGray); + r.addImage(zreq.isComplete() ? Icon.checkSmall : Icon.cancelSmall, zreq.isComplete() ? Color.lightGray : Color.scarlet).padLeft(3); r.row(); } }); @@ -82,8 +84,8 @@ public class ZoneInfoDialog extends FloatingDialog{ r.add("$research.list").colspan(2).left(); r.row(); for(Block block : zone.blockRequirements){ - r.addImage(block.icon(Cicon.small)).size(8 * 3).padRight(4); - r.add(block.localizedName).color(Color.lightGray); + r.addImage(block.icon(Cicon.small)).size(8 * 3).padRight(5); + r.add(block.localizedName).color(Color.lightGray).left(); r.addImage(data.isUnlocked(block) ? Icon.checkSmall : Icon.cancelSmall, data.isUnlocked(block) ? Color.lightGray : Color.scarlet).padLeft(3); r.row(); } @@ -136,7 +138,7 @@ public class ZoneInfoDialog extends FloatingDialog{ cont.row(); cont.addButton(zone.canConfigure() ? "$configure" : Core.bundle.format("configure.locked", zone.configureWave), - () -> loadout.show(zone.loadout.core().itemCapacity, zone::getStartingItems, zone::resetStartingItems, zone::updateLaunchCost, rebuildItems, item -> data.getItem(item) > 0 && item.type == ItemType.material) + () -> loadout.show(zone.loadout.core().itemCapacity, zone.getStartingItems(), zone::resetStartingItems, zone::updateLaunchCost, rebuildItems) ).fillX().pad(3).disabled(b -> !zone.canConfigure()); } cont.marginRight(12f);