From c6826a6c7e32f9b13b5b31fc2e87ab8bd3f44763 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 28 Jul 2020 14:28:58 -0400 Subject: [PATCH] Initial implementation of Anuken/Mindustry-Suggestions/issues/327 --- core/assets/scripts/base.js | 2 + core/assets/scripts/global.js | 79 ++-------- core/src/mindustry/content/Blocks.java | 2 +- core/src/mindustry/content/Fx.java | 2 +- core/src/mindustry/content/SectorPresets.java | 2 +- core/src/mindustry/core/FileTree.java | 7 +- core/src/mindustry/editor/WaveGraph.java | 138 ++++++++++++++++++ core/src/mindustry/editor/WaveInfoDialog.java | 105 +++++-------- core/src/mindustry/input/InputHandler.java | 3 +- core/src/mindustry/mod/Scripts.java | 6 +- core/src/mindustry/ui/Styles.java | 13 +- 11 files changed, 215 insertions(+), 144 deletions(-) create mode 100644 core/src/mindustry/editor/WaveGraph.java diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js index a846580923..fd26193065 100755 --- a/core/assets/scripts/base.js +++ b/core/assets/scripts/base.js @@ -1,3 +1,5 @@ +"use strict"; + const log = function(context, obj){ Vars.mods.getScripts().log(context, String(obj)) } diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index 5d2f80aec7..4bbf0aa1c5 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -1,5 +1,7 @@ //Generated class. Do not modify. +"use strict"; + const log = function(context, obj){ Vars.mods.getScripts().log(context, String(obj)) } @@ -8,6 +10,10 @@ const onEvent = function(event, handler){ Vars.mods.getScripts().onEvent(event, handler) } +const readString = path => Vars.mods.getScripts().readString(path) + +const readBytes = path => Vars.mods.getScripts().readBytes(path) + var scriptName = "base.js" var modName = "none" @@ -24,73 +30,12 @@ const extend = function(classType, params){ const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) Call = Packages.mindustry.gen.Call -importPackage(Packages.mindustry.world.blocks.power) -importPackage(Packages.mindustry.game) -importPackage(Packages.arc.scene) -importPackage(Packages.mindustry.maps.filters) -importPackage(Packages.mindustry.gen) -importPackage(Packages.arc.struct) -importPackage(Packages.mindustry.world.meta) -importPackage(Packages.arc.func) -importPackage(Packages.arc.math) -importPackage(Packages.mindustry.type) -importPackage(Packages.mindustry.world.blocks.environment) -importPackage(Packages.arc.scene.actions) -importPackage(Packages.arc.math.geom) -importPackage(Packages.mindustry.world.consumers) -importPackage(Packages.mindustry.graphics) -importPackage(Packages.arc.graphics) -importPackage(Packages.mindustry.world.blocks.units) -importPackage(Packages.mindustry.world.blocks.distribution) -importPackage(Packages.mindustry.world.blocks) -importPackage(Packages.mindustry.ui) -importPackage(Packages.mindustry.core) -importPackage(Packages.arc.scene.ui) -importPackage(Packages.arc.scene.ui.layout) -importPackage(Packages.mindustry.entities.comp) -importPackage(Packages.mindustry.ui.fragments) -importPackage(Packages.mindustry.entities) -importPackage(Packages.mindustry.ai.formations) -importPackage(Packages.arc.scene.utils) -importPackage(Packages.mindustry.world.blocks.campaign) -importPackage(Packages.mindustry.content) -importPackage(Packages.mindustry.world.blocks.storage) -importPackage(Packages.mindustry.world.meta.values) -importPackage(Packages.mindustry.world) -importPackage(Packages.mindustry.world.blocks.experimental) -importPackage(Packages.arc.scene.event) -importPackage(Packages.mindustry.graphics.g3d) -importPackage(Packages.mindustry.ui.dialogs) -importPackage(Packages.mindustry.world.blocks.defense) -importPackage(Packages.mindustry.maps) -importPackage(Packages.mindustry.world.blocks.legacy) -importPackage(Packages.mindustry.ctype) -importPackage(Packages.mindustry.world.blocks.defense.turrets) -importPackage(Packages.mindustry.world.draw) -importPackage(Packages.mindustry.editor) -importPackage(Packages.mindustry.entities.bullet) -importPackage(Packages.mindustry.logic) -importPackage(Packages.arc.scene.style) -importPackage(Packages.mindustry.audio) -importPackage(Packages.mindustry.entities.units) -importPackage(Packages.mindustry.world.blocks.production) -importPackage(Packages.mindustry.ai.formations.patterns) -importPackage(Packages.mindustry.input) -importPackage(Packages.arc.util) -importPackage(Packages.mindustry.world.blocks.sandbox) -importPackage(Packages.mindustry.ai) -importPackage(Packages.mindustry.async) -importPackage(Packages.mindustry.world.blocks.liquid) -importPackage(Packages.arc) -importPackage(Packages.mindustry.ai.types) -importPackage(Packages.mindustry.world.modules) importPackage(Packages.arc.graphics.g2d) -importPackage(Packages.mindustry.ui.layout) -importPackage(Packages.mindustry.maps.generators) -importPackage(Packages.mindustry.world.blocks.payloads) -importPackage(Packages.mindustry.world.producers) -importPackage(Packages.mindustry) -importPackage(Packages.mindustry.maps.planet) +importPackage(Packages.mindustry.gen) +importPackage(Packages.arc.math) +importPackage(Packages.arc.graphics) +importPackage(Packages.arc.util) +importPackage(Packages.arc) const PlayerIpUnbanEvent = Packages.mindustry.game.EventType.PlayerIpUnbanEvent const PlayerIpBanEvent = Packages.mindustry.game.EventType.PlayerIpBanEvent const PlayerUnbanEvent = Packages.mindustry.game.EventType.PlayerUnbanEvent @@ -120,12 +65,14 @@ const ZoneRequireCompleteEvent = Packages.mindustry.game.EventType.ZoneRequireCo const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent +const SectorLoseEvent = Packages.mindustry.game.EventType.SectorLoseEvent const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent const LineConfirmEvent = Packages.mindustry.game.EventType.LineConfirmEvent +const TurnEvent = Packages.mindustry.game.EventType.TurnEvent const WaveEvent = Packages.mindustry.game.EventType.WaveEvent const ResetEvent = Packages.mindustry.game.EventType.ResetEvent const PlayEvent = Packages.mindustry.game.EventType.PlayEvent diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 3b58e7ad88..fcba533e1e 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1280,7 +1280,7 @@ public class Blocks implements ContentList{ //region storage coreShard = new CoreBlock("core-shard"){{ - requirements(Category.effect, BuildVisibility.hidden, with(Items.copper, 1000, Items.lead, 1000)); + requirements(Category.effect, BuildVisibility.hidden, with(Items.copper, 2000, Items.lead, 1000)); alwaysUnlocked = true; unitType = UnitTypes.alpha; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 6cbcc79268..2ff065ad34 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -96,7 +96,7 @@ public class Fx{ Fill.square(x, y, 1f * size, 45f); }), - itemTransfer = new Effect(30f, e -> { + itemTransfer = new Effect(10f, e -> { if(!(e.data instanceof Position)) return; Position to = e.data(); Tmp.v1.set(e.x, e.y).interpolate(Tmp.v2.set(to), e.fin(), Interp.pow3) diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java index 1161dc2159..366887c2f2 100644 --- a/core/src/mindustry/content/SectorPresets.java +++ b/core/src/mindustry/content/SectorPresets.java @@ -22,7 +22,7 @@ public class SectorPresets implements ContentList{ conditionWave = 5; launchPeriod = 5; rules = r -> { - r.winWave = 30; + r.winWave = 20; }; }}; diff --git a/core/src/mindustry/core/FileTree.java b/core/src/mindustry/core/FileTree.java index 589809c986..f94c75eeb7 100644 --- a/core/src/mindustry/core/FileTree.java +++ b/core/src/mindustry/core/FileTree.java @@ -15,11 +15,16 @@ public class FileTree implements FileHandleResolver{ /** Gets an asset file.*/ public Fi get(String path){ + return get(path, false); + } + + /** Gets an asset file.*/ + public Fi get(String path, boolean safe){ if(files.containsKey(path)){ return files.get(path); }else if(files.containsKey("/" + path)){ return files.get("/" + path); - }else if(Core.files == null){ //headless + }else if(Core.files == null && !safe){ //headless return Fi.get(path); }else{ return Core.files.internal(path); diff --git a/core/src/mindustry/editor/WaveGraph.java b/core/src/mindustry/editor/WaveGraph.java new file mode 100644 index 0000000000..143a5839df --- /dev/null +++ b/core/src/mindustry/editor/WaveGraph.java @@ -0,0 +1,138 @@ +package mindustry.editor; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.*; +import arc.util.pooling.*; +import mindustry.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.type.*; +import mindustry.ui.*; + +public class WaveGraph extends Table{ + public Seq groups = new Seq<>(); + public int from, to = 20; + + private int[][] values; + private OrderedSet used = new OrderedSet<>(); + private int max; + private Table colors; + private ObjectSet hidden = new ObjectSet<>(); + + public WaveGraph(){ + background(Tex.pane); + + rect((x, y, width, height) -> { + Lines.stroke(Scl.scl(3f)); + Lines.precise(true); + + float offsetX = Scl.scl(30f), offsetY = Scl.scl(20f); + + float graphX = x + offsetX, graphY = y + offsetY, graphW = width - offsetX, graphH = height - offsetY; + float spacing = graphW / (values.length - 1); + + for(UnitType type : used){ + Draw.color(color(type)); + Draw.alpha(parentAlpha); + Lines.beginLine(); + for(int i = 0; i < values.length; i++){ + int val = values[i][type.id]; + + float cx = graphX + i*spacing, cy = 2f + graphY + val * (graphH - 4f) / max; + Lines.linePoint(cx, cy); + } + Lines.endLine(); + } + + GlyphLayout lay = Pools.obtain(GlyphLayout.class, GlyphLayout::new); + BitmapFont font = Fonts.outline; + + lay.setText(font, "1"); + + //how many numbers can fit here + float totalMarks = (height - offsetY - getMarginBottom() *2f - 1f) / (lay.height * 2); + + int markSpace = Math.max(1, Mathf.ceil(max / totalMarks)); + + Draw.color(Color.lightGray); + for(int i = 0; i < max; i += markSpace){ + float cy = 2f + y + i * (height - 4f) / max + offsetY, cx = x + offsetX; + //Lines.line(cx, cy, cx + len, cy); + + lay.setText(font, "" + i); + + font.draw("" + i, cx, cy + lay.height/2f - Scl.scl(3f), Align.right); + } + + float len = 4f; + + for(int i = 0; i < values.length; i++){ + float cy = y, cx = x + graphW / (values.length - 1) * i + offsetX; + + Lines.line(cx, cy, cx, cy + len); + } + + Pools.free(lay); + + Lines.precise(false); + Draw.reset(); + }).pad(4).padBottom(10).grow(); + + row(); + + table(t -> colors = t).growX(); + } + + public void rebuild(){ + values = new int[to - from + 1][Vars.content.units().size]; + used.clear(); + max = 1; + + for(int i = from; i <= to; i++){ + int index = i - from; + + for(SpawnGroup spawn : groups){ + int spawned = spawn.getUnitsSpawned(i); + values[index][spawn.type.id] += spawned; + if(spawned > 0){ + used.add(spawn.type); + } + max = Math.max(max, values[index][spawn.type.id]); + } + } + + ObjectSet usedCopy = new ObjectSet<>(used); + + colors.clear(); + colors.left(); + for(UnitType type : used){ + colors.button(b -> { + Color tcolor = color(type).cpy(); + b.image().size(32f).update(i -> i.setColor(b.isChecked() ? Tmp.c1.set(tcolor).mul(0.5f) : tcolor)).get().act(1); + b.image(type.icon(Cicon.medium)).padRight(20).update(i -> i.setColor(b.isChecked() ? Color.gray : Color.white)).get().act(1); + b.margin(0f); + }, Styles.fullTogglet, () -> { + if(!hidden.add(type)){ + hidden.remove(type); + } + + used.clear(); + used.addAll(usedCopy); + for(UnitType o : hidden) used.remove(o); + }).update(b -> b.setChecked(hidden.contains(type))); + } + + for(UnitType type : hidden){ + used.remove(type); + } + + } + + Color color(UnitType type){ + return Tmp.c1.fromHsv(type.id / (float)Vars.content.units().size * 360f, 0.7f, 1f); + } +} diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java index d3c8cbc693..028494fb2a 100644 --- a/core/src/mindustry/editor/WaveInfoDialog.java +++ b/core/src/mindustry/editor/WaveInfoDialog.java @@ -1,37 +1,35 @@ package mindustry.editor; import arc.*; -import arc.struct.*; -import arc.graphics.*; import arc.input.*; import arc.math.*; import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.TextField.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; -import mindustry.*; import mindustry.content.*; -import mindustry.ctype.ContentType; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.io.*; import mindustry.type.*; -import mindustry.ui.Cicon; +import mindustry.ui.*; import mindustry.ui.dialogs.*; import static mindustry.Vars.*; -import static mindustry.game.SpawnGroup.never; +import static mindustry.game.SpawnGroup.*; public class WaveInfoDialog extends BaseDialog{ private static final int displayed = 20; private Seq groups = new Seq<>(); - private Table table, preview; + private Table table; private int start = 0; private UnitType lastType = UnitTypes.dagger; private float updateTimer, updatePeriod = 1f; + private WaveGraph graph = new WaveGraph(); public WaveInfoDialog(MapEditor editor){ super("$waves.title"); @@ -47,7 +45,31 @@ public class WaveInfoDialog extends BaseDialog{ } }); + onResize(this::setup); addCloseButton(); + buttons.button("<<", () -> { + }).update(t -> { + if(t.getClickListener().isPressed()){ + updateTimer += Time.delta; + if(updateTimer >= updatePeriod){ + start = Math.max(start - 1, 0); + updateTimer = 0f; + updateWaves(); + } + } + }); + buttons.button(">>", () -> { + }).update(t -> { + if(t.getClickListener().isPressed()){ + updateTimer += Time.delta; + if(updateTimer >= updatePeriod){ + start++; + updateTimer = 0f; + updateWaves(); + } + } + }); + buttons.button("$waves.edit", () -> { BaseDialog dialog = new BaseDialog("$waves.edit"); dialog.addCloseButton(); @@ -98,35 +120,7 @@ public class WaveInfoDialog extends BaseDialog{ setAlignment(Align.center, Align.center); }}).width(390f).growY(); - cont.table(Tex.clear, m -> { - m.add("$waves.preview").color(Color.lightGray).wrap().growX().center().get().setAlignment(Align.center, Align.center); - m.row(); - m.button("-", () -> { - }).update(t -> { - if(t.getClickListener().isPressed()){ - updateTimer += Time.delta; - if(updateTimer >= updatePeriod){ - start = Math.max(start - 1, 0); - updateTimer = 0f; - updateWaves(); - } - } - }).growX().height(70f); - m.row(); - m.pane(t -> preview = t).grow().get().setScrollingDisabled(true, true); - m.row(); - m.button("+", () -> { - }).update(t -> { - if(t.getClickListener().isPressed()){ - updateTimer += Time.delta; - if(updateTimer >= updatePeriod){ - start++; - updateTimer = 0f; - updateWaves(); - } - } - }).growX().height(70f); - }).growY().width(180f).growY(); + cont.add(graph).grow(); buildGroups(); } @@ -137,6 +131,7 @@ public class WaveInfoDialog extends BaseDialog{ table.margin(10f); if(groups != null){ + for(SpawnGroup group : groups){ table.table(Tex.button, t -> { t.margin(0).defaults().pad(3).padLeft(5f).growX().left(); @@ -225,6 +220,7 @@ public class WaveInfoDialog extends BaseDialog{ updateWaves(); }).growX().pad(-6f).padTop(5); }).width(340f).pad(16); + table.row(); } }else{ @@ -243,7 +239,7 @@ public class WaveInfoDialog extends BaseDialog{ if(type.isHidden()) continue; p.button(t -> { t.left(); - t.image(type.icon(mindustry.ui.Cicon.medium)).size(40f).padRight(2f); + t.image(type.icon(Cicon.medium)).size(40f).padRight(2f); t.add(type.localizedName); }, () -> { lastType = type; @@ -258,36 +254,9 @@ public class WaveInfoDialog extends BaseDialog{ } void updateWaves(){ - preview.clear(); - preview.top(); - - for(int i = start; i < displayed + start; i++){ - int wave = i; - preview.table(Tex.underline, table -> { - table.add((wave + 1) + "").color(Pal.accent).center().colspan(2).get().setAlignment(Align.center, Align.center); - table.row(); - - int[] spawned = new int[Vars.content.getBy(ContentType.unit).size]; - - for(SpawnGroup spawn : groups){ - spawned[spawn.type.id] += spawn.getUnitsSpawned(wave); - } - - for(int j = 0; j < spawned.length; j++){ - if(spawned[j] > 0){ - UnitType type = content.getByID(ContentType.unit, j); - table.image(type.icon(Cicon.medium)).size(8f * 4f).padRight(4); - table.add(spawned[j] + "x").color(Color.lightGray).padRight(6); - table.row(); - } - } - - if(table.getChildren().size == 1){ - table.add("$none").color(Pal.remove); - } - }).width(110f).pad(2f); - - preview.row(); - } + graph.groups = groups; + graph.from = start; + graph.to = start + displayed; + graph.rebuild(); } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 9afc12d0c6..b5984742cb 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -195,13 +195,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted))); tile.getStackOffset(item, stackTrns); + tile.handleStack(item, accepted, player.unit()); createItemTransfer( item, amount, player.x + Angles.trnsx(player.unit().rotation + 180f, backTrns), player.y + Angles.trnsy(player.unit().rotation + 180f, backTrns), new Vec2(tile.x + stackTrns.x, tile.y + stackTrns.y), - () -> tile.handleStack(item, accepted, player.unit()) + () -> {} ); } diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index b57345f18a..40143c2a3d 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -81,11 +81,11 @@ public class Scripts implements Disposable{ } public String readString(String path){ - return Vars.tree.get(path).readString(); + return Vars.tree.get(path, true).readString(); } public byte[] readBytes(String path){ - return Vars.tree.get(path).readBytes(); + return Vars.tree.get(path, true).readBytes(); } public void run(LoadedMod mod, Fi file){ @@ -126,7 +126,7 @@ public class Scripts implements Disposable{ } @Override - public ModuleSource loadSource(String moduleId, Scriptable paths, Object validator) throws IOException, URISyntaxException{ + public ModuleSource loadSource(String moduleId, Scriptable paths, Object validator) throws URISyntaxException{ if(currentMod == null) return null; return loadSource(moduleId, currentMod.root.child("scripts"), validator); } diff --git a/core/src/mindustry/ui/Styles.java b/core/src/mindustry/ui/Styles.java index 88fde61aab..d31cec388b 100644 --- a/core/src/mindustry/ui/Styles.java +++ b/core/src/mindustry/ui/Styles.java @@ -25,7 +25,7 @@ import static mindustry.gen.Tex.*; public class Styles{ public static Drawable black, black9, black8, black6, black3, black5, none, flatDown, flatOver; public static ButtonStyle defaultb, waveb; - public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt; + public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt, fullTogglet; public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; public static ScrollPaneStyle defaultPane, horizontalPane, smallPane; public static KeybindDialogStyle defaultKeybindDialog; @@ -149,7 +149,16 @@ public class Styles{ disabled = buttonDisabled; disabledFontColor = Color.gray; }}; - + fullTogglet = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + checked = flatOver; + down = flatOver; + up = black; + over = flatOver; + disabled = black; + disabledFontColor = Color.gray; + }}; defaulti = new ImageButtonStyle(){{ down = buttonDown; up = button;