diff --git a/core/assets-raw/sprites/effects/point-laser-center.png b/core/assets-raw/sprites/effects/point-laser-center.png new file mode 100644 index 0000000000..31aa55c040 Binary files /dev/null and b/core/assets-raw/sprites/effects/point-laser-center.png differ diff --git a/core/assets-raw/sprites/effects/point-laser-end.png b/core/assets-raw/sprites/effects/point-laser-end.png new file mode 100644 index 0000000000..2369095417 Binary files /dev/null and b/core/assets-raw/sprites/effects/point-laser-end.png differ diff --git a/core/assets-raw/sprites/effects/point-laser.png b/core/assets-raw/sprites/effects/point-laser.png new file mode 100644 index 0000000000..1ac2ffc640 Binary files /dev/null and b/core/assets-raw/sprites/effects/point-laser.png differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index a4703ef93f..b1ebc86f88 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -4196,14 +4196,14 @@ public class Blocks{ }}; lustre = new ContinuousTurret("lustre"){{ - requirements(Category.turret, with(Items.beryllium, 150, Items.silicon, 200, Items.graphite, 200, Items.carbide, 50)); + requirements(Category.turret, with(Items.silicon, 250, Items.graphite, 200, Items.oxide, 50, Items.carbide, 90)); range = 100f; shootType = new PointLaserBulletType(){{ damage = 150f; buildingDamageMultiplier = 0.3f; - hitColor = Color.valueOf("fd9e81"); + hitColor = Color.valueOf("fda981"); }}; drawer = new DrawTurret("reinforced-"){{ diff --git a/core/src/mindustry/editor/MapObjectivesDialog.java b/core/src/mindustry/editor/MapObjectivesDialog.java index 52554a5fae..6d27ed5a3d 100644 --- a/core/src/mindustry/editor/MapObjectivesDialog.java +++ b/core/src/mindustry/editor/MapObjectivesDialog.java @@ -1,22 +1,36 @@ package mindustry.editor; import arc.*; +import arc.func.*; +import arc.scene.event.*; +import arc.scene.ui.layout.*; import arc.struct.*; +import arc.util.*; +import mindustry.*; +import mindustry.content.*; +import mindustry.ctype.*; +import mindustry.game.*; import mindustry.game.MapObjectives.*; import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.io.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; +import mindustry.world.*; + +import java.lang.reflect.*; import static mindustry.Vars.*; public class MapObjectivesDialog extends BaseDialog{ private Seq objectives = new Seq<>(); + private @Nullable MapObjective selectedObjective; + private Table list = new Table(); public MapObjectivesDialog(){ super("@editor.objectives"); - buttons.defaults().size(180f, 64f).pad(2f); + buttons.defaults().size(170f, 64f).pad(2f); buttons.button("@back", Icon.left, this::hide); buttons.button("@edit", Icon.edit, () -> { @@ -54,17 +68,247 @@ public class MapObjectivesDialog extends BaseDialog{ dialog.addCloseButton(); dialog.show(); }); + + buttons.button("@add", Icon.add, () -> { + var selection = new BaseDialog("@add"); + selection.cont.pane(p -> { + p.background(Tex.button); + p.marginRight(14); + p.defaults().size(195f, 56f); + int i = 0; + for(var gen : MapObjectives.allObjectiveTypes){ + var objective = gen.get(); + + p.button(objective.typeName(), Styles.flatt, () -> { + objectives.add(objective); + setup(); + selection.hide(); + }).with(Table::left).get().getLabelCell().growX().left().padLeft(5).labelAlign(Align.left); + + if(++i % 3 == 0) p.row(); + } + }).scrollX(false); + + selection.addCloseButton(); + selection.show(); + }); + + cont.clear(); + cont.pane(t -> { + list = t; + list.top(); + }).grow(); } public void show(Seq objectives){ super.show(); + selectedObjective = null; this.objectives = objectives; setup(); } void setup(){ - cont.clear(); - cont.add("This editor doesn't work yet. Come back later."); + list.clear(); + + for(var objective : objectives){ + list.table(Tex.button, t -> { + t.margin(0); + + t.button(b -> { + b.left(); + b.add(objective.typeName()).color(Pal.accent); + + b.add().growX(); + + b.button(Icon.upOpen, Styles.emptyi, () -> { + int index = objectives.indexOf(objective); + if(index > 0){ + objectives.swap(index, index - 1); + setup(); + } + }).pad(-6).size(46f); + + b.button(Icon.downOpen, Styles.emptyi, () -> { + int index = objectives.indexOf(objective); + if(index < objectives.size - 1){ + objectives.swap(index, index + 1); + setup(); + } + }).pad(-6).size(46f); + + b.button(Icon.cancel, Styles.emptyi, () -> { + objectives.remove(objective); + list.getCell(t).pad(0f); + + t.remove(); + setup(); + }).pad(-6).size(46f).padRight(-12f); + }, () -> { + if(selectedObjective != objective){ + selectedObjective = objective; + setup(); + } + }).growX().height(46f).pad(-6f).padBottom(0f).row(); + + if(selectedObjective == objective){ + t.table(f -> { + f.left(); + f.margin(10f); + + f.defaults().minHeight(40f).left(); + + var fields = objective.getClass().getFields(); + + for(var field : fields){ + if((field.getModifiers() & Modifier.PUBLIC) == 0) continue; + + f.add(field.getName() + ": "); + + var type = field.getType(); + + if(type == String.class){ + f.field(Reflect.get(objective, field), text -> { + Reflect.set(objective, field, text); + }); + }else if(type == int.class){ + f.field(Reflect.get(objective, field) + "", text -> { + if(Strings.canParseInt(text)){ + Reflect.set(objective, field, Strings.parseInt(text)); + } + }).valid(Strings::canParseInt); + }else if(type == float.class){ + f.field(Reflect.get(objective, field) + "", text -> { + if(Strings.canParsePositiveFloat(text)){ + Reflect.set(objective, field, Strings.parseFloat(text)); + } + }).valid(Strings::canParseFloat); + }else if(type == UnlockableContent.class){ + + f.button(b -> b.image(Reflect.get(objective, field).uiIcon).size(iconSmall), () -> { + showContentSelect(null, result -> { + Reflect.set(objective, field, result); + setup(); + }, b -> b.techNode != null); + }).pad(4); + + }else if(type == Block.class){ + f.button(b -> b.image(Reflect.get(objective, field).uiIcon).size(iconSmall), () -> { + showContentSelect(ContentType.block, result -> { + Reflect.set(objective, field, result); + setup(); + }, b -> ((Block)b).synthetic()); + }).pad(4); + }else if(type == Team.class){ //TODO list of flags + f.button(b -> b.image(Tex.whiteui).color(Reflect.get(objective, field).color).size(iconSmall), () -> { + showTeamSelect(result -> { + Reflect.set(objective, field, result); + setup(); + }); + }).pad(4); + }else if(type == String[].class){ //TODO list of flags + + Table strings = new Table(); + strings.marginLeft(20f); + Runnable[] rebuild = {null}; + + strings.left(); + + float h = 40f; + + rebuild[0] = () -> { + strings.clear(); + strings.left().defaults().padBottom(3f).padTop(3f); + String[] array = Reflect.get(objective, field); + + for(int i = 0; i < array.length; i ++){ + int fi = i; + var str = array[i]; + strings.field(str, result -> { + array[fi] = result; + }).maxTextLength(20).height(h); + + strings.button(Icon.cancel, Styles.squarei, () -> { + + String[] next = new String[array.length - 1]; + System.arraycopy(array, 0, next, 0, fi); + if(fi < array.length - 1){ + System.arraycopy(array, fi + 1, next, fi, array.length - 1 - fi); + } + Reflect.set(objective, field, next); + + rebuild[0].run(); + }).padLeft(4).size(h); + + strings.row(); + } + + strings.button("+ Add", () -> { + String[] next = new String[array.length + 1]; + next[array.length] = ""; + System.arraycopy(array, 0, next, 0, array.length); + Reflect.set(objective, field, next); + + rebuild[0].run(); + }).height(h).width(140f).padLeft(-20f).left().row(); + }; + + rebuild[0].run(); + + f.row(); + f.add(strings).colspan(2).fill(); + + }else{ + f.add("[red]UNFINISHED"); + } + + f.row(); + } + + }).grow(); + } + + }).width(340f).pad(8f).row(); + } + } + + void showContentSelect(@Nullable ContentType type, Cons cons, Boolf check){ + BaseDialog dialog = new BaseDialog(""); + dialog.cont.pane(p -> { + int i = 0; + for(var block : (type == null ? Vars.content.blocks().copy().as() + .add(Vars.content.items()) + .add(Vars.content.liquids()) + .add(Vars.content.units()) : + Vars.content.getBy(type).as())){ + + if(!check.get(block)) continue; + + p.image(block == Blocks.air ? Icon.none.getRegion() : block.uiIcon).size(iconMed).pad(3).with(b -> b.addListener(new HandCursorListener())) + .tooltip(block.localizedName).get().clicked(() -> { + cons.get(block); + dialog.hide(); + }); + if(++i % 10 == 0) p.row(); + } + }); + + dialog.closeOnBack(); + dialog.show(); + } + + void showTeamSelect(Cons cons){ + BaseDialog dialog = new BaseDialog(""); + for(var team : Team.baseTeams){ + + dialog.cont.image(Tex.whiteui).size(iconMed).color(team.color).pad(4).with(i -> i.addListener(new HandCursorListener())) + .tooltip(team.localized()).get().clicked(() -> { + cons.get(team); + dialog.hide(); + }); + } + + dialog.closeOnBack(); + dialog.show(); } } diff --git a/core/src/mindustry/entities/bullet/PointLaserBulletType.java b/core/src/mindustry/entities/bullet/PointLaserBulletType.java index a007f113df..c794f97f14 100644 --- a/core/src/mindustry/entities/bullet/PointLaserBulletType.java +++ b/core/src/mindustry/entities/bullet/PointLaserBulletType.java @@ -12,7 +12,7 @@ import mindustry.graphics.*; /** A continuous bullet type that only damages in a point. */ public class PointLaserBulletType extends BulletType{ - public String sprite = "drill-laser"; + public String sprite = "point-laser"; public TextureRegion laser, laserEnd; public Color color = Color.white; diff --git a/core/src/mindustry/game/MapObjectives.java b/core/src/mindustry/game/MapObjectives.java index b1f3c926b3..07ed022020 100644 --- a/core/src/mindustry/game/MapObjectives.java +++ b/core/src/mindustry/game/MapObjectives.java @@ -365,10 +365,15 @@ public class MapObjectives{ /** Base abstract class for any in-map objective. */ public static abstract class MapObjective{ + public @Nullable String details; public String[] flagsAdded = {}; public String[] flagsRemoved = {}; public ObjectiveMarker[] markers = {}; - public @Nullable String details; + + //TODO localize + public String typeName(){ + return getClass().getSimpleName().replace("Objective", ""); + } public MapObjective withFlags(String... flags){ this.flagsAdded = flags;