Merge remote-tracking branch 'origin/mech-rework' into mech-rework
# Conflicts: # gradle.properties
This commit is contained in:
@@ -164,6 +164,10 @@ public class BlockIndexer{
|
||||
}
|
||||
|
||||
public TileEntity findTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
return findTile(team, x, y, range, pred, false);
|
||||
}
|
||||
|
||||
public TileEntity findTile(Team team, float x, float y, float range, Predicate<Tile> pred, boolean usePriority){
|
||||
TileEntity closest = null;
|
||||
float dst = 0;
|
||||
|
||||
@@ -184,7 +188,7 @@ public class BlockIndexer{
|
||||
TileEntity e = other.entity;
|
||||
|
||||
float ndst = Mathf.dst(x, y, e.x, e.y);
|
||||
if(ndst < range && (closest == null || ndst < dst)){
|
||||
if(ndst < range && (closest == null || ndst < dst || (usePriority && closest.block.priority.ordinal() < e.block.priority.ordinal()))){
|
||||
dst = ndst;
|
||||
closest = e;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.type.Bullet;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
@@ -29,8 +29,6 @@ import io.anuke.mindustry.world.consumers.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
import io.anuke.mindustry.world.modules.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Blocks implements ContentList{
|
||||
public static Block
|
||||
|
||||
@@ -58,7 +56,7 @@ public class Blocks implements ContentList{
|
||||
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
|
||||
|
||||
//transport
|
||||
conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, router, overflowGate, massDriver,
|
||||
conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, overflowGate, massDriver,
|
||||
|
||||
//liquids
|
||||
mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit,
|
||||
@@ -716,23 +714,23 @@ public class Blocks implements ContentList{
|
||||
//region sandbox
|
||||
|
||||
powerVoid = new PowerVoid("power-void"){{
|
||||
requirements(Category.power, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
powerSource = new PowerSource("power-source"){{
|
||||
requirements(Category.power, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemSource = new ItemSource("item-source"){{
|
||||
requirements(Category.distribution, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemVoid = new ItemVoid("item-void"){{
|
||||
requirements(Category.distribution, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
liquidSource = new LiquidSource("liquid-source"){{
|
||||
requirements(Category.liquid, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.liquid, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
message = new MessageBlock("message"){{
|
||||
@@ -745,27 +743,27 @@ public class Blocks implements ContentList{
|
||||
int wallHealthMultiplier = 4;
|
||||
|
||||
scrapWall = new Wall("scrap-wall"){{
|
||||
requirements(Category.defense, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * wallHealthMultiplier;
|
||||
variants = 5;
|
||||
}};
|
||||
|
||||
scrapWallLarge = new Wall("scrap-wall-large"){{
|
||||
requirements(Category.defense, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
variants = 4;
|
||||
}};
|
||||
|
||||
scrapWallHuge = new Wall("scrap-wall-huge"){{
|
||||
requirements(Category.defense, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 9 * wallHealthMultiplier;
|
||||
size = 3;
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
scrapWallGigantic = new Wall("scrap-wall-gigantic"){{
|
||||
requirements(Category.defense, () -> state.rules.infiniteResources, ItemStack.with());
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
@@ -935,7 +933,11 @@ public class Blocks implements ContentList{
|
||||
|
||||
sorter = new Sorter("sorter"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2));
|
||||
}};
|
||||
|
||||
invertedSorter = new Sorter("inverted-sorter"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2));
|
||||
invert = true;
|
||||
}};
|
||||
|
||||
router = new Router("router"){{
|
||||
@@ -1083,11 +1085,12 @@ public class Blocks implements ContentList{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
differentialGenerator = new SingleTypeGenerator(true, false, "differential-generator"){{
|
||||
differentialGenerator = new SingleTypeGenerator("differential-generator"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 70, Items.titanium, 50, Items.lead, 100, Items.silicon, 65, Items.metaglass, 50));
|
||||
powerProduction = 16f;
|
||||
itemDuration = 120f;
|
||||
hasLiquids = true;
|
||||
hasItems = true;
|
||||
size = 3;
|
||||
|
||||
consumes.item(Items.pyratite).optional(true, false);
|
||||
@@ -1230,7 +1233,7 @@ public class Blocks implements ContentList{
|
||||
//region storage
|
||||
|
||||
coreShard = new CoreBlock("core-shard"){{
|
||||
requirements(Category.effect, () -> false, ItemStack.with(Items.titanium, 1000));
|
||||
requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000));
|
||||
alwaysUnlocked = true;
|
||||
|
||||
health = 1100;
|
||||
@@ -1239,7 +1242,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
coreFoundation = new CoreBlock("core-foundation"){{
|
||||
requirements(Category.effect, () -> false, ItemStack.with(Items.titanium, 1500, Items.silicon, 1000));
|
||||
requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 400, Items.silicon, 3000));
|
||||
|
||||
health = 2000;
|
||||
itemCapacity = 9000;
|
||||
@@ -1247,7 +1250,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
coreNucleus = new CoreBlock("core-nucleus"){{
|
||||
requirements(Category.effect, () -> false, ItemStack.with(Items.titanium, 4000, Items.silicon, 2000, Items.surgealloy, 1000));
|
||||
requirements(Category.effect, BuildVisibility.debugOnly, ItemStack.with(Items.titanium, 4000, Items.silicon, 2000, Items.surgealloy, 3000));
|
||||
|
||||
health = 4000;
|
||||
itemCapacity = 13000;
|
||||
@@ -1272,7 +1275,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
launchPad = new LaunchPad("launch-pad"){{
|
||||
requirements(Category.effect, () -> world.isZone(), ItemStack.with(Items.copper, 250, Items.silicon, 75, Items.lead, 100));
|
||||
requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 250, Items.silicon, 75, Items.lead, 100));
|
||||
size = 3;
|
||||
itemCapacity = 100;
|
||||
launchTime = 60f * 16;
|
||||
@@ -1281,7 +1284,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
launchPadLarge = new LaunchPad("launch-pad-large"){{
|
||||
requirements(Category.effect, () -> world.isZone(), ItemStack.with(Items.titanium, 200, Items.silicon, 150, Items.lead, 250, Items.plastanium, 75));
|
||||
requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.titanium, 200, Items.silicon, 150, Items.lead, 250, Items.plastanium, 75));
|
||||
size = 4;
|
||||
itemCapacity = 250;
|
||||
launchTime = 60f * 14;
|
||||
|
||||
@@ -31,6 +31,7 @@ public class TechTree implements ContentList{
|
||||
|
||||
node(distributor);
|
||||
node(sorter, () -> {
|
||||
node(invertedSorter);
|
||||
node(message);
|
||||
node(overflowGate);
|
||||
});
|
||||
|
||||
@@ -338,6 +338,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
}
|
||||
|
||||
public void showException(String text, Throwable exc){
|
||||
loadfrag.hide();
|
||||
new Dialog(""){{
|
||||
String message = Strings.getFinalMesage(exc);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class MapResizeDialog extends FloatingDialog{
|
||||
|
||||
buttons.defaults().size(200f, 50f);
|
||||
buttons.addButton("$cancel", this::hide);
|
||||
buttons.addButton("$editor.resize", () -> {
|
||||
buttons.addButton("$ok", () -> {
|
||||
cons.accept(width, height);
|
||||
hide();
|
||||
});
|
||||
|
||||
6
core/src/io/anuke/mindustry/entities/TargetPriority.java
Normal file
6
core/src/io/anuke/mindustry/entities/TargetPriority.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
public enum TargetPriority{
|
||||
base,
|
||||
turret
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class Units{
|
||||
if(team == Team.derelict) return null;
|
||||
|
||||
for(Team enemy : state.teams.enemiesOf(team)){
|
||||
TileEntity entity = indexer.findTile(enemy, x, y, range, pred);
|
||||
TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true);
|
||||
if(entity != null){
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.anuke.arc.graphics.glutils.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.type.base.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Teams.*;
|
||||
@@ -29,6 +28,7 @@ public class BlockRenderer implements Disposable{
|
||||
private int lastCamX, lastCamY, lastRangeX, lastRangeY;
|
||||
private int requestidx = 0;
|
||||
private int iterateidx = 0;
|
||||
private float brokenFade = 0f;
|
||||
private FrameBuffer shadows = new FrameBuffer(2, 2);
|
||||
private FrameBuffer fog = new FrameBuffer(2, 2);
|
||||
private Array<Tile> outArray = new Array<>();
|
||||
@@ -124,12 +124,18 @@ public class BlockRenderer implements Disposable{
|
||||
}
|
||||
|
||||
public void drawBroken(){
|
||||
if(unitGroups[player.getTeam().ordinal()].all().contains(p -> p instanceof BuilderDrone)){
|
||||
if(control.input.isPlacing() || control.input.isBreaking()){
|
||||
brokenFade = Mathf.lerpDelta(brokenFade, 1f, 0.1f);
|
||||
}else{
|
||||
brokenFade = Mathf.lerpDelta(brokenFade, 0f, 0.1f);
|
||||
}
|
||||
|
||||
if(brokenFade > 0.001f){
|
||||
for(BrokenBlock block : state.teams.get(player.getTeam()).brokenBlocks){
|
||||
Block b = content.block(block.block);
|
||||
if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue;
|
||||
|
||||
Draw.alpha(0.5f);
|
||||
Draw.alpha(0.53f * brokenFade);
|
||||
Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f));
|
||||
Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f);
|
||||
}
|
||||
|
||||
@@ -190,6 +190,11 @@ public class DesktopInput extends InputHandler{
|
||||
cursorType = SystemCursor.arrow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBreaking(){
|
||||
return mode == breaking;
|
||||
}
|
||||
|
||||
void pollInput(){
|
||||
Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
||||
int cursorX = tileX(Core.input.mouseX());
|
||||
|
||||
@@ -523,6 +523,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
return block != null;
|
||||
}
|
||||
|
||||
public boolean isBreaking(){
|
||||
return false;
|
||||
}
|
||||
|
||||
public float mouseAngle(float x, float y){
|
||||
return Core.input.mouseWorld(getMouseX(), getMouseY()).sub(x, y).angle();
|
||||
}
|
||||
|
||||
@@ -348,6 +348,11 @@ public class MobileInput extends InputHandler implements GestureListener{
|
||||
//endregion
|
||||
//region input events
|
||||
|
||||
@Override
|
||||
public boolean isBreaking(){
|
||||
return mode == breaking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){
|
||||
if(state.is(State.menu) || player.isDead()) return false;
|
||||
|
||||
@@ -8,12 +8,27 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class JsonIO{
|
||||
private static CustomJson jsonBase = new CustomJson();
|
||||
private static Json json = new Json(){{
|
||||
apply(this);
|
||||
}};
|
||||
private static Json json = new Json(){
|
||||
{ apply(this); }
|
||||
|
||||
@Override
|
||||
public void writeValue(Object value, Class knownType, Class elementType){
|
||||
if(value instanceof MappableContent){
|
||||
try{
|
||||
getWriter().value(((MappableContent)value).name);
|
||||
}catch(IOException e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}else{
|
||||
super.writeValue(value, knownType, elementType);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static String write(Object object){
|
||||
return json.toJson(object, object.getClass());
|
||||
@@ -66,24 +81,6 @@ public class JsonIO{
|
||||
}
|
||||
});
|
||||
|
||||
//TODO extremely hacky and disgusting
|
||||
for(Block block : Vars.content.blocks()){
|
||||
Class type = block.getClass();
|
||||
if(type.isAnonymousClass()) type = type.getSuperclass();
|
||||
|
||||
json.setSerializer(type, new Serializer<Block>(){
|
||||
@Override
|
||||
public void write(Json json, Block object, Class knownType){
|
||||
json.writeValue(object.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block read(Json json, JsonValue jsonData, Class type){
|
||||
return Vars.content.getByName(ContentType.block, jsonData.asString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
json.setSerializer(Block.class, new Serializer<Block>(){
|
||||
@Override
|
||||
public void write(Json json, Block object, Class knownType){
|
||||
@@ -96,26 +93,6 @@ public class JsonIO{
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
json.setSerializer(TeamData.class, new Serializer<TeamData>(){
|
||||
@Override
|
||||
public void write(Json json, TeamData object, Class knownType){
|
||||
json.writeObjectStart();
|
||||
json.writeValue("brokenBlocks", object.brokenBlocks.toArray());
|
||||
json.writeValue("team", object.team.ordinal());
|
||||
json.writeObjectEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TeamData read(Json json, JsonValue jsonData, Class type){
|
||||
long[] blocks = jsonData.get("brokenBlocks").asLongArray();
|
||||
Team team = Team.all[jsonData.getInt("team", 0)];
|
||||
TeamData out = new TeamData(team, EnumSet.of(new Team[]{}));
|
||||
out.brokenBlocks = new LongQueue(blocks);
|
||||
return out;
|
||||
}
|
||||
});*/
|
||||
|
||||
json.setSerializer(ItemStack.class, new Serializer<ItemStack>(){
|
||||
@Override
|
||||
public void write(Json json, ItemStack object, Class knownType){
|
||||
|
||||
@@ -25,6 +25,7 @@ import io.anuke.mindustry.mod.Mods.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
@@ -79,6 +80,12 @@ public class ContentParser{
|
||||
private Json parser = new Json(){
|
||||
@Override
|
||||
public <T> T readValue(Class<T> type, Class elementType, JsonValue jsonData, Class keyType){
|
||||
T t = internalRead(type, elementType, jsonData, keyType);
|
||||
if(t != null) checkNullFields(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
private <T> T internalRead(Class<T> type, Class elementType, JsonValue jsonData, Class keyType){
|
||||
if(type != null){
|
||||
if(classParsers.containsKey(type)){
|
||||
try{
|
||||
@@ -167,9 +174,9 @@ public class ContentParser{
|
||||
TechTree.create(find(ContentType.block, value.get("research").asString()), block);
|
||||
}
|
||||
|
||||
//make block visible
|
||||
if(value.has("requirements")){
|
||||
block.buildVisibility = () -> true;
|
||||
//make block visible by default if there are requirements and no visibility set
|
||||
if(value.has("requirements") && block.buildVisibility == BuildVisibility.hidden){
|
||||
block.buildVisibility = BuildVisibility.shown;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -289,10 +296,12 @@ public class ContentParser{
|
||||
}
|
||||
|
||||
currentMod = mod;
|
||||
boolean exists = Vars.content.getByName(type, name) != null;
|
||||
Content c = parsers.get(type).parse(mod.name, name, value);
|
||||
c.sourceFile = file;
|
||||
c.mod = mod;
|
||||
checkNulls(c);
|
||||
if(!exists){
|
||||
c.sourceFile = file;
|
||||
c.mod = mod;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -348,35 +357,21 @@ public class ContentParser{
|
||||
|
||||
private Object fieldOpt(Class<?> type, JsonValue value){
|
||||
try{
|
||||
Object b = type.getField(value.asString()).get(null);
|
||||
if(b == null) return null;
|
||||
return b;
|
||||
return type.getField(value.asString()).get(null);
|
||||
}catch(Exception e){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks all @NonNull fields in this object, recursively.
|
||||
* Throws an exception if any are null.*/
|
||||
private void checkNulls(Object object){
|
||||
checkNulls(object, new ObjectSet<>());
|
||||
}
|
||||
|
||||
private void checkNulls(Object object, ObjectSet<Object> checked){
|
||||
checked.add(object);
|
||||
private void checkNullFields(Object object){
|
||||
if(object instanceof Number || object instanceof String) return;
|
||||
|
||||
parser.getFields(object.getClass()).values().toArray().each(field -> {
|
||||
try{
|
||||
if(field.field.getType().isPrimitive()) return;
|
||||
|
||||
Object obj = field.field.get(object);
|
||||
if(field.field.isAnnotationPresent(NonNull.class) && field.field.get(object) == null){
|
||||
throw new RuntimeException("Field '" + field.field.getName() + "' in " + object.getClass().getSimpleName() + " is missing!");
|
||||
}
|
||||
|
||||
if(obj != null && !checked.contains(obj)){
|
||||
checkNulls(obj, checked);
|
||||
checked.add(obj);
|
||||
throw new RuntimeException("'" + field.field.getName() + "' in " + object.getClass().getSimpleName() + " is missing!");
|
||||
}
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException(e);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
@@ -29,7 +30,7 @@ public class Links{
|
||||
}
|
||||
|
||||
public static class LinkEntry{
|
||||
public final String name, description, link;
|
||||
public final String name, title, description, link;
|
||||
public final Color color;
|
||||
|
||||
public LinkEntry(String name, String link, Color color){
|
||||
@@ -37,6 +38,9 @@ public class Links{
|
||||
this.color = color;
|
||||
this.description = Core.bundle.getNotNull("link." + name + ".description");
|
||||
this.link = link;
|
||||
|
||||
String title = Core.bundle.getOrNull("link." + name + ".title");
|
||||
this.title = title != null ? title : Strings.capitalize(name.replace("-", " "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public class AboutDialog extends FloatingDialog{
|
||||
}).size(h - 5, h);
|
||||
|
||||
table.table(inset -> {
|
||||
inset.add("[accent]" + Strings.capitalize(link.name.replace("-", " "))).growX().left();
|
||||
inset.add("[accent]" + link.title).growX().left();
|
||||
inset.row();
|
||||
inset.labelWrap(link.description).width(w - 100f).color(Color.lightGray).growX();
|
||||
}).padLeft(8);
|
||||
|
||||
@@ -157,14 +157,14 @@ public class CustomRulesDialog extends FloatingDialog{
|
||||
main.row();
|
||||
|
||||
title("$rules.title.player");
|
||||
number("$rules.playerdamagemultiplier", f -> rules.playerDamageMultiplier = f, () -> rules.playerDamageMultiplier);
|
||||
number("$rules.playerhealthmultiplier", f -> rules.playerHealthMultiplier = f, () -> rules.playerHealthMultiplier);
|
||||
number("$rules.playerdamagemultiplier", f -> rules.playerDamageMultiplier = f, () -> rules.playerDamageMultiplier);
|
||||
|
||||
title("$rules.title.unit");
|
||||
check("$rules.unitdrops", b -> rules.unitDrops = b, () -> rules.unitDrops, () -> true);
|
||||
number("$rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
|
||||
number("$rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier);
|
||||
number("$rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
|
||||
number("$rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
|
||||
|
||||
title("$rules.title.enemy");
|
||||
check("$rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
|
||||
|
||||
@@ -5,9 +5,11 @@ import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.input.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.scene.*;
|
||||
import io.anuke.arc.scene.event.*;
|
||||
import io.anuke.arc.scene.style.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
@@ -21,7 +23,8 @@ import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.io.SaveIO.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.TreeLayout.*;
|
||||
import io.anuke.mindustry.ui.layout.*;
|
||||
import io.anuke.mindustry.ui.layout.TreeLayout.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -30,13 +33,14 @@ public class DeployDialog extends FloatingDialog{
|
||||
private ObjectSet<ZoneNode> nodes = new ObjectSet<>();
|
||||
private ZoneInfoDialog info = new ZoneInfoDialog();
|
||||
private Rectangle bounds = new Rectangle();
|
||||
private View view = new View();
|
||||
|
||||
public DeployDialog(){
|
||||
super("", Styles.fullDialog);
|
||||
|
||||
ZoneNode root = new ZoneNode(Zones.groundZero, null);
|
||||
|
||||
TreeLayout layout = new TreeLayout();
|
||||
BranchTreeLayout layout = new BranchTreeLayout();
|
||||
layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f);
|
||||
layout.gapBetweenNodes = Scl.scl(120f);
|
||||
layout.layout(root);
|
||||
@@ -47,6 +51,51 @@ public class DeployDialog extends FloatingDialog{
|
||||
buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f);
|
||||
|
||||
shown(this::setup);
|
||||
|
||||
//view input.
|
||||
|
||||
addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
|
||||
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(InputEvent event, float x, float y){
|
||||
view.requestScroll();
|
||||
return super.mouseMoved(event, x, y);
|
||||
}
|
||||
});
|
||||
|
||||
addListener(new ElementGestureListener(){
|
||||
@Override
|
||||
public void zoom(InputEvent event, float initialDistance, float distance){
|
||||
if(view.lastZoom < 0){
|
||||
view.lastZoom = view.getScaleX();
|
||||
}
|
||||
|
||||
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
view.lastZoom = view.getScaleX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
|
||||
view.panX += deltaX / view.getScaleX();
|
||||
view.panY += deltaY / view.getScaleY();
|
||||
view.moved = true;
|
||||
view.clamp();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void setup(){
|
||||
@@ -71,7 +120,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
update(() -> {
|
||||
setOrigin(Align.center);
|
||||
time[0] += Core.graphics.getDeltaTime() * 10f;
|
||||
setTranslation(Mathf.sin(time[0], 60f, 70f) + panX / 30f, Mathf.cos(time[0], 140f, 80f) + (panY + 200) / 30f);
|
||||
setTranslation(Mathf.sin(time[0], 60f, 70f) + view.panX / 30f, Mathf.cos(time[0], 140f, 80f) + (view.panY + 200) / 30f);
|
||||
});
|
||||
}}.setScaling(Scaling.fit));
|
||||
|
||||
@@ -141,7 +190,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
}).width(size).height(50f).padTop(3);
|
||||
}));
|
||||
}else{
|
||||
stack.add(new View());
|
||||
stack.add(view = new View());
|
||||
}
|
||||
|
||||
stack.add(new ItemsDisplay());
|
||||
@@ -158,6 +207,9 @@ public class DeployDialog extends FloatingDialog{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
}
|
||||
|
||||
boolean hidden(Zone zone){
|
||||
@@ -166,7 +218,11 @@ public class DeployDialog extends FloatingDialog{
|
||||
|
||||
void buildButton(Zone zone, Button button){
|
||||
button.setDisabled(() -> hidden(zone));
|
||||
button.clicked(() -> info.show(zone));
|
||||
button.clicked(() -> {
|
||||
if(!view.moved){
|
||||
info.show(zone);
|
||||
}
|
||||
});
|
||||
|
||||
if(zone.unlocked() && !hidden(zone)){
|
||||
button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
|
||||
@@ -178,10 +234,9 @@ public class DeployDialog extends FloatingDialog{
|
||||
}
|
||||
}
|
||||
|
||||
//should be static variables of View, but that's impossible
|
||||
static float panX = 0, panY = -200;
|
||||
|
||||
class View extends Group{
|
||||
float panX = 0, panY = -200, lastZoom = -1;
|
||||
boolean moved = false;
|
||||
|
||||
{
|
||||
for(ZoneNode node : nodes){
|
||||
@@ -201,11 +256,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
addChild(stack);
|
||||
}
|
||||
|
||||
dragged((x, y) -> {
|
||||
panX += x;
|
||||
panY += y;
|
||||
clamp();
|
||||
});
|
||||
released(() -> moved = false);
|
||||
}
|
||||
|
||||
void clamp(){
|
||||
@@ -221,9 +272,9 @@ public class DeployDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
public void drawChildren(){
|
||||
clamp();
|
||||
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y;
|
||||
float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
|
||||
|
||||
for(ZoneNode node : nodes){
|
||||
for(ZoneNode child : node.allChildren){
|
||||
@@ -234,7 +285,7 @@ public class DeployDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
super.draw();
|
||||
super.drawChildren();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.mod.Mods.*;
|
||||
@@ -24,9 +23,35 @@ public class ModsDialog extends FloatingDialog{
|
||||
() -> Core.net.openURI(reportIssueURL))
|
||||
.size(250f, 64f);
|
||||
|
||||
buttons.row();
|
||||
|
||||
buttons.addImageTextButton("$mods.guide", Icon.wiki,
|
||||
() -> Core.net.openURI(modGuideURL))
|
||||
.size(280f, 64f);
|
||||
.size(210f, 64f);
|
||||
|
||||
buttons.addImageTextButton("$mod.import.github", Icon.github, () -> {
|
||||
ui.showTextInput("$mod.import.github", "", 64, "Anuken/ExampleMod", text -> {
|
||||
ui.loadfrag.show();
|
||||
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
|
||||
Core.net.httpGet(loc.getHeader("Location"), result -> {
|
||||
try{
|
||||
Streams.copyStream(result.getResultAsStream(), modDirectory.child(text.replace("/", "") + ".zip").write(false));
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
mods.reloadContent();
|
||||
setup();
|
||||
ui.loadfrag.hide();
|
||||
}catch(Exception e){
|
||||
ui.showException(e);
|
||||
}
|
||||
});
|
||||
}catch(Exception e){
|
||||
ui.showException(e);
|
||||
}
|
||||
}, t -> Core.app.post(() -> ui.showException(t)));
|
||||
}, t -> Core.app.post(() -> ui.showException(t)));
|
||||
});
|
||||
}).size(250f, 64f);
|
||||
|
||||
shown(this::setup);
|
||||
|
||||
@@ -120,27 +145,5 @@ public class ModsDialog extends FloatingDialog{
|
||||
}
|
||||
});
|
||||
}).margin(12f).width(500f);
|
||||
|
||||
//not well tested currently
|
||||
if(Version.build == -1){
|
||||
cont.row();
|
||||
|
||||
cont.addImageTextButton("$mod.import.github", Icon.github, () -> {
|
||||
ui.showTextInput("$mod.import.github", "", "Anuken/ExampleMod", text -> {
|
||||
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
|
||||
Core.net.httpGet(loc.getHeader("Location"), result -> {
|
||||
try{
|
||||
Streams.copyStream(result.getResultAsStream(), modDirectory.child(text.replace("/", "") + ".zip").write(false));
|
||||
ui.loadAnd(() -> {
|
||||
mods.reloadContent();
|
||||
});
|
||||
}catch(Exception e){
|
||||
ui.showException(e);
|
||||
}
|
||||
}, ui::showException);
|
||||
}, ui::showException);
|
||||
});
|
||||
}).margin(12f).width(500f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +294,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
graphics.checkPref("effects", true);
|
||||
graphics.checkPref("playerchat", true);
|
||||
graphics.checkPref("minimap", !mobile);
|
||||
graphics.checkPref("position", false);
|
||||
graphics.checkPref("fps", false);
|
||||
graphics.checkPref("indicators", true);
|
||||
graphics.checkPref("animatedwater", false);
|
||||
|
||||
@@ -4,6 +4,7 @@ import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.input.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.scene.*;
|
||||
@@ -21,7 +22,8 @@ import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.TreeLayout.*;
|
||||
import io.anuke.mindustry.ui.layout.*;
|
||||
import io.anuke.mindustry.ui.layout.TreeLayout.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -31,13 +33,14 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
|
||||
private Rectangle bounds = new Rectangle();
|
||||
private ItemsDisplay items;
|
||||
private View view;
|
||||
|
||||
public TechTreeDialog(){
|
||||
super("");
|
||||
|
||||
titleTable.remove();
|
||||
margin(0f).marginBottom(8);
|
||||
cont.stack(new View(), items = new ItemsDisplay()).grow();
|
||||
cont.stack(view = new View(), items = new ItemsDisplay()).grow();
|
||||
|
||||
shown(() -> {
|
||||
checkNodes(root);
|
||||
@@ -52,16 +55,57 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
hide();
|
||||
ui.database.show();
|
||||
}).size(210f, 64f);
|
||||
|
||||
//scaling/drag input
|
||||
|
||||
addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
|
||||
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(InputEvent event, float x, float y){
|
||||
view.requestScroll();
|
||||
return super.mouseMoved(event, x, y);
|
||||
}
|
||||
});
|
||||
|
||||
addListener(new ElementGestureListener(){
|
||||
@Override
|
||||
public void zoom(InputEvent event, float initialDistance, float distance){
|
||||
if(view.lastZoom < 0){
|
||||
view.lastZoom = view.getScaleX();
|
||||
}
|
||||
|
||||
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
view.lastZoom = view.getScaleX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
|
||||
view.panX += deltaX / view.getScaleX();
|
||||
view.panY += deltaY / view.getScaleY();
|
||||
view.moved = true;
|
||||
view.clamp();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void treeLayout(){
|
||||
TreeLayout layout = new TreeLayout();
|
||||
layout.gapBetweenLevels = Scl.scl(60f);
|
||||
layout.gapBetweenNodes = Scl.scl(40f);
|
||||
RadialTreeLayout layout = new RadialTreeLayout();
|
||||
LayoutNode node = new LayoutNode(root, null);
|
||||
layout.layout(node);
|
||||
bounds.set(layout.getBounds());
|
||||
bounds.y += nodeSize*1.5f;
|
||||
//bounds.y += nodeSize*1.5f;
|
||||
copyInfo(node);
|
||||
}
|
||||
|
||||
@@ -110,7 +154,7 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
this.parent = parent;
|
||||
this.width = this.height = nodeSize;
|
||||
if(node.children != null){
|
||||
children = Array.with(node.children).select(n -> n.visible).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
|
||||
children = Array.with(node.children).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +178,7 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
class View extends Group{
|
||||
float panX = 0, panY = -200;
|
||||
float panX = 0, panY = -200, lastZoom = -1;
|
||||
boolean moved = false;
|
||||
ImageButton hoverNode;
|
||||
Table infoTable = new Table();
|
||||
@@ -146,6 +190,8 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
ImageButton button = new ImageButton(node.node.block.icon(Cicon.medium), Styles.nodei);
|
||||
button.visible(() -> node.visible);
|
||||
button.clicked(() -> {
|
||||
if(moved) return;
|
||||
|
||||
if(mobile){
|
||||
hoverNode = button;
|
||||
rebuild();
|
||||
@@ -182,7 +228,6 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
});
|
||||
button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled);
|
||||
button.setUserObject(node.node);
|
||||
button.tapped(() -> moved = false);
|
||||
button.setSize(nodeSize);
|
||||
button.update(() -> {
|
||||
float offset = (Core.graphics.getHeight() % 2) / 2f;
|
||||
@@ -205,12 +250,9 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
});
|
||||
}
|
||||
|
||||
dragged((x, y) -> {
|
||||
moved = true;
|
||||
panX += x;
|
||||
panY += y;
|
||||
clamp();
|
||||
});
|
||||
setOrigin(Align.center);
|
||||
setTransform(true);
|
||||
released(() -> moved = false);
|
||||
}
|
||||
|
||||
void clamp(){
|
||||
@@ -308,9 +350,9 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
public void drawChildren(){
|
||||
clamp();
|
||||
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y;
|
||||
float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
|
||||
|
||||
for(TechTreeNode node : nodes){
|
||||
if(!node.visible) continue;
|
||||
@@ -324,7 +366,7 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
super.draw();
|
||||
super.drawChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ public class ZoneInfoDialog extends FloatingDialog{
|
||||
hide();
|
||||
control.playZone(zone);
|
||||
}
|
||||
}).minWidth(150f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !zone.canUnlock() : !data.hasItems(zone.getLaunchCost())).uniformY().get();
|
||||
}).minWidth(200f).margin(13f).padTop(5).disabled(b -> zone.locked() ? !zone.canUnlock() : !data.hasItems(zone.getLaunchCost())).uniformY().get();
|
||||
|
||||
button.row();
|
||||
button.add(iteminfo);
|
||||
|
||||
@@ -19,15 +19,14 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.Styles;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -249,9 +248,16 @@ public class HudFragment extends Fragment{
|
||||
info.label(() -> ping.get(netClient.getPing())).visible(net::client).left().style(Styles.outlineLabel);
|
||||
}).top().left();
|
||||
});
|
||||
|
||||
//minimap
|
||||
parent.fill(t -> t.top().right().add(new Minimap()).visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial));
|
||||
|
||||
parent.fill(t -> {
|
||||
//minimap
|
||||
t.add(new Minimap().visible(() -> Core.settings.getBool("minimap") && !state.rules.tutorial));
|
||||
t.row();
|
||||
//position
|
||||
t.label(() -> world.toTile(player.x) + "," + world.toTile(player.y))
|
||||
.visible(() -> Core.settings.getBool("position") && !state.rules.tutorial);
|
||||
t.top().right();
|
||||
});
|
||||
|
||||
//spawner warning
|
||||
parent.fill(t -> {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.ui;
|
||||
package io.anuke.mindustry.ui.layout;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
@@ -6,7 +6,7 @@ import io.anuke.arc.math.geom.*;
|
||||
/**
|
||||
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
|
||||
*/
|
||||
public class TreeLayout{
|
||||
public class BranchTreeLayout implements TreeLayout{
|
||||
public TreeLocation rootLocation = TreeLocation.top;
|
||||
public TreeAlignment alignment = TreeAlignment.awayFromRoot;
|
||||
public float gapBetweenLevels = 10;
|
||||
@@ -18,6 +18,7 @@ public class TreeLayout{
|
||||
private float boundsTop = Float.MAX_VALUE;
|
||||
private float boundsBottom = Float.MIN_VALUE;
|
||||
|
||||
@Override
|
||||
public void layout(TreeNode root){
|
||||
firstWalk(root, null);
|
||||
calcSizeOfLevels(root, 0);
|
||||
@@ -288,20 +289,4 @@ public class TreeLayout{
|
||||
public enum TreeAlignment{
|
||||
center, towardsRoot, awayFromRoot
|
||||
}
|
||||
|
||||
public static class TreeNode<T extends TreeNode>{
|
||||
public float width, height, x, y;
|
||||
|
||||
//should be initialized by user
|
||||
public T[] children;
|
||||
public T parent;
|
||||
|
||||
private float mode, prelim, change, shift;
|
||||
private int number = -1;
|
||||
private TreeNode thread, ancestor;
|
||||
|
||||
boolean isLeaf(){
|
||||
return children == null || children.length == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
core/src/io/anuke/mindustry/ui/layout/RadialTreeLayout.java
Normal file
66
core/src/io/anuke/mindustry/ui/layout/RadialTreeLayout.java
Normal file
@@ -0,0 +1,66 @@
|
||||
package io.anuke.mindustry.ui.layout;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.math.*;
|
||||
|
||||
public class RadialTreeLayout implements TreeLayout{
|
||||
private static ObjectSet<TreeNode> visited = new ObjectSet<>();
|
||||
private static Queue<TreeNode> queue = new Queue<>();
|
||||
|
||||
public float startRadius, delta;
|
||||
|
||||
@Override
|
||||
public void layout(TreeNode root){
|
||||
startRadius = root.height * 2.4f;
|
||||
delta = root.height * 2.4f;
|
||||
|
||||
bfs(root, true);
|
||||
radialize(root, 0, 360);
|
||||
}
|
||||
|
||||
void radialize(TreeNode root, float from, float to){
|
||||
int depthOfVertex = root.number;
|
||||
float theta = from;
|
||||
float radius = startRadius + (delta * depthOfVertex);
|
||||
|
||||
int leavesNumber = bfs(root, false);
|
||||
for(TreeNode child : root.children){
|
||||
int lambda = bfs(child, false);
|
||||
float mi = theta + ((float)lambda / leavesNumber * (to - from));
|
||||
|
||||
float x = radius * Mathf.cos((theta + mi) / 2f * Mathf.degRad);
|
||||
float y = radius * Mathf.sin((theta + mi) / 2f * Mathf.degRad);
|
||||
|
||||
child.x = x;
|
||||
child.y = y;
|
||||
|
||||
if(child.children.length > 0) radialize(child, theta, mi);
|
||||
theta = mi;
|
||||
}
|
||||
}
|
||||
|
||||
int bfs(TreeNode node, boolean assign){
|
||||
visited.clear();
|
||||
queue.clear();
|
||||
if(assign) node.number = 0;
|
||||
int leaves = 0;
|
||||
|
||||
visited.add(node);
|
||||
queue.addFirst(node);
|
||||
|
||||
while(!queue.isEmpty()){
|
||||
TreeNode current = queue.removeFirst();
|
||||
if(current.children.length == 0) leaves++;
|
||||
|
||||
for(TreeNode child : current.children){
|
||||
if(assign) child.number = current.number + 1;
|
||||
if(!visited.contains(child)){
|
||||
visited.add(child);
|
||||
queue.addLast(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return leaves;
|
||||
}
|
||||
}
|
||||
22
core/src/io/anuke/mindustry/ui/layout/TreeLayout.java
Normal file
22
core/src/io/anuke/mindustry/ui/layout/TreeLayout.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package io.anuke.mindustry.ui.layout;
|
||||
|
||||
public interface TreeLayout{
|
||||
void layout(TreeNode root);
|
||||
|
||||
class TreeNode<T extends TreeNode>{
|
||||
public float width, height, x, y;
|
||||
|
||||
//should be initialized by user
|
||||
public T[] children;
|
||||
public T parent;
|
||||
|
||||
//internal stuff
|
||||
public float mode, prelim, change, shift;
|
||||
public int number = -1;
|
||||
public TreeNode thread, ancestor;
|
||||
|
||||
public boolean isLeaf(){
|
||||
return children == null || children.length == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,8 +39,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class Block extends BlockStorage{
|
||||
public static final int crackRegions = 8, maxCrackSize = 5;
|
||||
|
||||
private static final BooleanProvider invisible = () -> false;
|
||||
|
||||
/** whether this block has a tile entity that updates */
|
||||
public boolean update;
|
||||
/** whether this block has health and can be destroyed */
|
||||
@@ -83,6 +81,8 @@ public class Block extends BlockStorage{
|
||||
public BlockGroup group = BlockGroup.none;
|
||||
/** List of block flags. Used for AI indexing. */
|
||||
public EnumSet<BlockFlag> flags = EnumSet.of();
|
||||
/** Targeting priority of this block, as seen by enemies.*/
|
||||
public TargetPriority priority = TargetPriority.base;
|
||||
/** Whether the block can be tapped and selected to configure. */
|
||||
public boolean configurable;
|
||||
/** Whether this block consumes touchDown events when tapped. */
|
||||
@@ -122,7 +122,9 @@ public class Block extends BlockStorage{
|
||||
/** Cost of building this block; do not modify directly! */
|
||||
public float buildCost;
|
||||
/** Whether this block is visible and can currently be built. */
|
||||
public BooleanProvider buildVisibility = invisible;
|
||||
public BuildVisibility buildVisibility = BuildVisibility.hidden;
|
||||
/** Multiplier for speed of building this block. */
|
||||
public float buildCostMultiplier = 1f;
|
||||
/** Whether this block has instant transfer.*/
|
||||
public boolean instantTransfer = false;
|
||||
public boolean alwaysUnlocked = false;
|
||||
@@ -153,7 +155,7 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
public boolean isBuildable(){
|
||||
return buildVisibility != invisible;
|
||||
return buildVisibility != BuildVisibility.hidden && buildVisibility != BuildVisibility.debugOnly;
|
||||
}
|
||||
|
||||
public boolean isStatic(){
|
||||
@@ -386,6 +388,7 @@ public class Block extends BlockStorage{
|
||||
for(ItemStack stack : requirements){
|
||||
buildCost += stack.amount * stack.item.cost;
|
||||
}
|
||||
buildCost *= buildCostMultiplier;
|
||||
|
||||
if(consumes.has(ConsumeType.power)) hasPower = true;
|
||||
if(consumes.has(ConsumeType.item)) hasItems = true;
|
||||
@@ -803,7 +806,7 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
public boolean isVisible(){
|
||||
return buildVisibility.get() && !isHidden();
|
||||
return buildVisibility.visible() && !isHidden();
|
||||
}
|
||||
|
||||
public boolean isFloor(){
|
||||
@@ -820,7 +823,7 @@ public class Block extends BlockStorage{
|
||||
|
||||
@Override
|
||||
public boolean isHidden(){
|
||||
return !buildVisibility.get();
|
||||
return !buildVisibility.visible();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -829,21 +832,21 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
protected void requirements(Category cat, ItemStack[] stacks, boolean unlocked){
|
||||
requirements(cat, () -> true, stacks);
|
||||
requirements(cat, BuildVisibility.shown, stacks);
|
||||
this.alwaysUnlocked = unlocked;
|
||||
}
|
||||
|
||||
protected void requirements(Category cat, ItemStack[] stacks){
|
||||
requirements(cat, () -> true, stacks);
|
||||
requirements(cat, BuildVisibility.shown, stacks);
|
||||
}
|
||||
|
||||
/** Sets up requirements. Use only this method to set up requirements. */
|
||||
protected void requirements(Category cat, BooleanProvider visible, ItemStack[] stacks){
|
||||
protected void requirements(Category cat, BuildVisibility visible, ItemStack[] stacks){
|
||||
this.category = cat;
|
||||
this.requirements = stacks;
|
||||
this.buildVisibility = visible;
|
||||
|
||||
Arrays.sort(requirements, (a, b) -> Integer.compare(a.item.id, b.item.id));
|
||||
Arrays.sort(requirements, Structs.comparingInt(i -> i.item.id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,10 +95,9 @@ public class Floor extends Block{
|
||||
}
|
||||
|
||||
if(variants > 0){
|
||||
variantRegions();
|
||||
|
||||
for(int i = 0; i < variantRegions.length; i++){
|
||||
editor.pack("editor-" + ((AtlasRegion)variantRegions[i]).name, Core.atlas.getPixmap((AtlasRegion)variantRegions[i]).crop());
|
||||
for(int i = 0; i < variants; i++){
|
||||
String rname = name + (i + 1);
|
||||
editor.pack("editor-" + rname, Core.atlas.getPixmap(rname).crop());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,10 +211,6 @@ public class Floor extends Block{
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean eq(int i){
|
||||
return (eq & (1 << Mathf.mod(i, 8))) != 0;
|
||||
}
|
||||
|
||||
TextureRegion edge(Floor block, int x, int y){
|
||||
return block.edges()[x][2 - y];
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class Wall extends Block{
|
||||
solid = true;
|
||||
destructible = true;
|
||||
group = BlockGroup.walls;
|
||||
buildCostMultiplier = 5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -72,6 +72,7 @@ public abstract class Turret extends Block{
|
||||
|
||||
public Turret(String name){
|
||||
super(name);
|
||||
priority = TargetPriority.turret;
|
||||
update = true;
|
||||
solid = true;
|
||||
layer = Layer.turret;
|
||||
|
||||
@@ -232,8 +232,8 @@ public class MassDriver extends Block{
|
||||
int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed);
|
||||
data.items[i] = maxTransfer;
|
||||
totalUsed += maxTransfer;
|
||||
entity.items.remove(content.item(i), maxTransfer);
|
||||
}
|
||||
entity.items.clear();
|
||||
|
||||
float angle = tile.angleTo(target);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class Sorter extends Block{
|
||||
private static Item lastItem;
|
||||
protected boolean invert;
|
||||
|
||||
public Sorter(String name){
|
||||
super(name);
|
||||
@@ -40,16 +41,6 @@ public class Sorter extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
public static void setSorterItem(Player player, Tile tile, Item item){
|
||||
if(!Units.canInteract(player, tile)) return;
|
||||
SorterEntity entity = tile.entity();
|
||||
if(entity != null){
|
||||
entity.sortItem = item;
|
||||
}
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void configured(Tile tile, Player player, int value){
|
||||
tile.<SorterEntity>entity().sortItem = content.item(value);
|
||||
@@ -92,7 +83,7 @@ public class Sorter extends Block{
|
||||
if(dir == -1) return null;
|
||||
Tile to;
|
||||
|
||||
if(item == entity.sortItem){
|
||||
if((item == entity.sortItem) != invert){
|
||||
//prevent 3-chains
|
||||
if(isSame(dest, source) && isSame(dest, dest.getNearby(dir))){
|
||||
return null;
|
||||
@@ -115,12 +106,10 @@ public class Sorter extends Block{
|
||||
}else{
|
||||
if(dest.rotation() == 0){
|
||||
to = a;
|
||||
if(flip)
|
||||
dest.rotation((byte)1);
|
||||
if(flip) dest.rotation((byte)1);
|
||||
}else{
|
||||
to = b;
|
||||
if(flip)
|
||||
dest.rotation((byte)0);
|
||||
if(flip) dest.rotation((byte)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
@@ -28,8 +29,8 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
/** Maximum liquid used per frame. */
|
||||
protected float maxLiquidGenerate = 0.4f;
|
||||
|
||||
protected Effects.Effect generateEffect = Fx.generatespark;
|
||||
protected Effects.Effect explodeEffect = Fx.generatespark;
|
||||
protected Effect generateEffect = Fx.generatespark;
|
||||
protected Effect explodeEffect = Fx.generatespark;
|
||||
protected Color heatColor = Color.valueOf("ff9b59");
|
||||
protected TextureRegion topRegion, liquidRegion;
|
||||
protected boolean randomlyExplode = true;
|
||||
|
||||
@@ -5,12 +5,9 @@ import io.anuke.mindustry.type.Liquid;
|
||||
|
||||
public class SingleTypeGenerator extends ItemLiquidGenerator{
|
||||
|
||||
public SingleTypeGenerator(boolean hasItems, boolean hasLiquids, String name){
|
||||
super(hasItems, hasLiquids, name);
|
||||
}
|
||||
|
||||
public SingleTypeGenerator(String name){
|
||||
super(name);
|
||||
defaults = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.world.consumers;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
@@ -14,7 +15,7 @@ import io.anuke.mindustry.world.meta.values.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ConsumeItemFilter extends Consume{
|
||||
public final Predicate<Item> filter;
|
||||
public final @NonNull Predicate<Item> filter;
|
||||
|
||||
public ConsumeItemFilter(Predicate<Item> item){
|
||||
this.filter = item;
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.world.consumers;
|
||||
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
@@ -10,7 +11,7 @@ import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
public class ConsumeLiquid extends ConsumeLiquidBase{
|
||||
public final Liquid liquid;
|
||||
public final @NonNull Liquid liquid;
|
||||
|
||||
public ConsumeLiquid(Liquid liquid, float amount){
|
||||
super(amount);
|
||||
|
||||
22
core/src/io/anuke/mindustry/world/meta/BuildVisibility.java
Normal file
22
core/src/io/anuke/mindustry/world/meta/BuildVisibility.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package io.anuke.mindustry.world.meta;
|
||||
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.mindustry.*;
|
||||
|
||||
public enum BuildVisibility{
|
||||
hidden(() -> false),
|
||||
shown(() -> true),
|
||||
debugOnly(() -> false),
|
||||
sandboxOnly(() -> Vars.state.rules.infiniteResources),
|
||||
campaignOnly(() -> Vars.world.isZone());
|
||||
|
||||
private final BooleanProvider visible;
|
||||
|
||||
public boolean visible(){
|
||||
return visible.get();
|
||||
}
|
||||
|
||||
BuildVisibility(BooleanProvider visible){
|
||||
this.visible = visible;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user