Merge branches 'master' and 'new-planning-system' of https://github.com/Anuken/Mindustry

This commit is contained in:
Anuken
2019-10-08 19:03:18 -04:00
25 changed files with 759 additions and 532 deletions

View File

@@ -177,7 +177,7 @@ public class Control implements ApplicationListener, Loadable{
});
Events.on(UnitDestroyEvent.class, e -> {
if(e.unit instanceof BaseUnit){
if(e.unit instanceof BaseUnit && world.isZone()){
data.unlockContent(((BaseUnit)e.unit).getType());
}
});
@@ -416,6 +416,7 @@ public class Control implements ApplicationListener, Loadable{
music.update();
loops.update();
Time.updateGlobal();
if(Core.input.keyTap(Binding.fullscreen)){
boolean full = settings.getBool("fullscreen");

View File

@@ -6,8 +6,8 @@ import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*;
@@ -188,6 +188,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Add another build requests to the tail of the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place){
addBuildRequest(place, true);
}
/** Add another build requests to the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place, boolean tail){
for(BuildRequest request : buildQueue()){
if(request.x == place.x && request.y == place.y){
return;
@@ -197,7 +202,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress;
}
buildQueue().addLast(place);
if(tail){
buildQueue().addLast(place);
}else{
buildQueue().addFirst(place);
}
}
/**
@@ -258,15 +267,19 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Class for storing build requests. Can be either a place or remove request. */
class BuildRequest{
public final int x, y, rotation;
public final Block block;
public final boolean breaking;
public int x, y, rotation;
public @Nullable Block block;
public boolean breaking;
public boolean hasConfig;
public int config;
public float progress;
public boolean initialized;
//animation variables
public float animScale;
public float animInvalid;
/** This creates a build request. */
public BuildRequest(int x, int y, int rotation, Block block){
this.x = x;
@@ -285,13 +298,42 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true;
}
public BuildRequest(){
}
public Rectangle bounds(Rectangle rect){
if(breaking){
return rect.set(-100f, -100f, 0f, 0f);
}else{
return block.bounds(x, y, rect);
}
}
public BuildRequest set(int x, int y, int rotation, Block block){
this.x = x;
this.y = y;
this.rotation = rotation;
this.block = block;
this.breaking = false;
return this;
}
public float drawx(){
return x*tilesize + block.offset();
}
public float drawy(){
return y*tilesize + block.offset();
}
public BuildRequest configure(int config){
this.config = config;
this.hasConfig = true;
return this;
}
public Tile tile(){
public @Nullable Tile tile(){
return world.tile(x, y);
}

View File

@@ -19,9 +19,7 @@ import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.*;
@@ -51,7 +49,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public String name = "noname";
public @Nullable
String uuid, usid;
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping;
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping, isBuilding = true;
public float boostHeat, shootHeat, destructTime;
public boolean achievedFlight;
public Color color = new Color();
@@ -357,7 +355,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void drawOver(){
if(dead) return;
drawMechanics();
if(isBuilding()){
if(!state.isPaused() && isBuilding){
drawBuilding();
}
}else{
drawMining();
}
}
@Override
@@ -424,57 +428,16 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
public void drawBuildRequests(){
BuildRequest last = null;
if(!isLocal) return;
for(BuildRequest request : buildQueue()){
if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue;
if(request.breaking){
Block block = world.ltile(request.x, request.y).block();
//draw removal request
Lines.stroke(2f, Pal.removeBack);
float rad = Mathf.absin(Time.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset() - 1,
rad);
Draw.color(Pal.remove);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset(), rad);
control.input.drawBreaking(request);
}else{
Draw.color();
PlaceDraw draw = PlaceDraw.instance;
draw.scalex = 1;
draw.scaley = 1;
draw.rotation = request.rotation;
if(last == null){
request.block.getPlaceDraw(draw, request.rotation, request.x, request.y, request.rotation);
}else{
request.block.getPlaceDraw(draw, request.rotation, last.x - request.x, last.y - request.y, last.rotation);
}
TextureRegion region = draw.region;
Draw.rect(region,
request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(),
region.getWidth() * 1f * Draw.scl * draw.scalex,
region.getHeight() * 1f * Draw.scl * draw.scaley, request.block.rotate ? draw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(request.block.size - 1, 0) / 2f * tilesize;
Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90);
}
Draw.color();
last = request;
request.block.drawRequest(request, control.input.allRequests(),
Build.validPlace(getTeam(), request.x, request.y, request.block, request.rotation));
}
}
@@ -485,6 +448,18 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
//region update methods
@Override
public void updateMechanics(){
if(isBuilding){
updateBuilding();
}
//mine only when not building
if(buildRequest() == null){
updateMining();
}
}
@Override
public void update(){
hitTime -= Time.delta();
@@ -517,7 +492,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
BuildRequest request = buildRequest();
if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
if(isBuilding() && isBuilding && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f);
}
@@ -817,6 +792,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
placeQueue.clear();
dead = true;
lastText = null;
isBuilding = true;
textFadeTime = 0f;
target = null;
moveTarget = null;
@@ -910,7 +886,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void write(DataOutput buffer) throws IOException{
super.writeSave(buffer, !isLocal);
TypeIO.writeStringData(buffer, name);
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3));
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3)| (Pack.byteValue(isBuilding) << 4));
buffer.writeInt(Color.rgba8888(color));
buffer.writeByte(mech.id);
buffer.writeInt(mining == null ? noSpawner : mining.pos());
@@ -932,6 +908,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
dead = (bools & 2) != 0;
boolean boosting = (bools & 4) != 0;
isTyping = (bools & 8) != 0;
boolean building = (bools & 16) != 0;
color.set(buffer.readInt());
mech = content.getByID(ContentType.mech, buffer.readByte());
int mine = buffer.readInt();
@@ -950,6 +927,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
velocity.y = lastvy;
}else{
mining = world.tile(mine);
isBuilding = building;
isBoosting = boosting;
}

View File

@@ -10,11 +10,10 @@ 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.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Block.*;
import static io.anuke.arc.Core.camera;
import static io.anuke.mindustry.Vars.*;
@@ -131,7 +130,7 @@ public class BlockRenderer implements Disposable{
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.mixcol(Pal.accent, 0.2f + Mathf.absin(5f, 0.2f));
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);
}
Draw.reset();

View File

@@ -25,9 +25,9 @@ public class OverlayRenderer{
public void drawBottom(){
InputHandler input = control.input;
if(!input.isDrawing() || player.isDead()) return;
if(player.isDead()) return;
input.drawOutlined();
input.drawBottom();
}
public void drawTop(){

View File

@@ -12,6 +12,8 @@ public enum Binding implements KeyBind{
select(KeyCode.MOUSE_LEFT),
deselect(KeyCode.MOUSE_RIGHT),
break_block(KeyCode.MOUSE_RIGHT),
clear_building(KeyCode.Q),
pause_building(KeyCode.E),
rotate(new Axis(KeyCode.SCROLL)),
rotateplaced(KeyCode.R),
diagonal_placement(KeyCode.CONTROL_LEFT),

View File

@@ -5,15 +5,15 @@ import io.anuke.arc.Graphics.*;
import io.anuke.arc.Graphics.Cursor.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*;
import static io.anuke.arc.Core.scene;
@@ -23,44 +23,18 @@ import static io.anuke.mindustry.input.PlaceMode.*;
public class DesktopInput extends InputHandler{
/** Current cursor type. */
private Cursor cursorType = SystemCursor.arrow;
/** Position where the player started dragging a line. */
private int selectX, selectY;
/** Last known line positions.*/
private int lastLineX, lastLineY;
/** Whether selecting mode is active. */
private PlaceMode mode;
/** Animation scale for line. */
private float selectScale;
private int prevX, prevY, prevRotation;
/** Draws a placement icon for a specific block. */
void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){
if(validPlace(x, y, block, rotation)){
block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation);
Draw.color();
Draw.mixcol(Pal.accent, 0.12f + Mathf.absin(Time.time(), 8f, 0.35f));
Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(),
placeDraw.region.getWidth() * selectScale * Draw.scl * placeDraw.scalex,
placeDraw.region.getHeight() * selectScale * Draw.scl * placeDraw.scaley,
block.rotate ? placeDraw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
if(i % 2 == 0)
Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.color();
Draw.mixcol();
}else{
Draw.color(Pal.removeBack);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1);
}
}
/** Selected build request for movement. */
private @Nullable BuildRequest sreq;
/** Whether player is currently deleting removal requests. */
private boolean deleting = false;
@Override
public boolean isDrawing(){
@@ -68,56 +42,63 @@ public class DesktopInput extends InputHandler{
}
@Override
public void drawOutlined(){
public void buildUI(Group group){
group.fill(t -> {
t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.15f));
t.visible(() -> Core.settings.getBool("hints"));
t.table(Styles.black6, b -> {
b.defaults().left();
b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.name())).style(Styles.outlineLabel);
b.row();
b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.name())).style(Styles.outlineLabel);
}).margin(10f);
});
}
@Override
public void drawTop(){
Lines.stroke(1f);
int cursorX = tileX(Core.input.mouseX());
int cursorY = tileY(Core.input.mouseY());
//draw selection(s)
if(mode == placing && block != null){
prevX = selectX;
prevY = selectY;
prevRotation = rotation;
iterateLine(selectX, selectY, cursorX, cursorY, l -> {
if(l.last && block.rotate){
drawArrow(block, l.x, l.y, l.rotation);
}
drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation);
prevX = l.x;
prevY = l.y;
prevRotation = l.rotation;
});
}else if(mode == breaking){
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, selectX, selectY, cursorX, cursorY, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.ltile(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
Draw.color(Pal.removeBack);
Lines.square(tile.drawx(), tile.drawy() - 1, tile.block().size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f - 1);
for(int i = 0; i < lineRequests.size; i++){
BuildRequest req = lineRequests.get(i);
if(i == lineRequests.size - 1 && req.block.rotate){
drawArrow(block, req.x, req.y, req.rotation);
}
drawRequest(lineRequests.get(i));
}
Draw.color(Pal.removeBack);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}else if(mode == breaking){
drawSelection(selectX, selectY, cursorX, cursorY);
}else if(isPlacing()){
if(block.rotate){
drawArrow(block, cursorX, cursorY, rotation);
}
drawPlace(cursorX, cursorY, block, rotation, cursorX, cursorY, rotation);
Draw.color();
drawRequest(cursorX, cursorY, block, rotation);
block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation));
}
if(mode == none && !isPlacing()){
BuildRequest req = getRequest(cursorX, cursorY);
if(req != null){
drawSelected(req.x, req.y, req.breaking ? req.tile().block() : req.block, Pal.accent);
}
}
if(sreq != null){
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
if(sreq.block.rotate){
drawArrow(sreq.block, sreq.x, sreq.y, sreq.rotation, valid);
}
sreq.block.drawRequest(sreq, allRequests(), valid);
drawSelected(sreq.x, sreq.y, sreq.block, getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent);
}
Draw.reset();
}
@@ -171,6 +152,14 @@ public class DesktopInput extends InputHandler{
rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4);
if(sreq != null){
sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4);
}
if(Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0 && isPlacing() && mode == placing){
updateLine(selectX, selectY);
}
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
if(cursor != null){
@@ -186,6 +175,10 @@ public class DesktopInput extends InputHandler{
cursorType = ui.drillCursor;
}
if(getRequest(cursor.x, cursor.y) != null && mode == none){
cursorType = SystemCursor.hand;
}
if(canTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y)){
cursorType = ui.unloadCursor;
}
@@ -211,11 +204,46 @@ public class DesktopInput extends InputHandler{
player.setMineTile(null);
}
if(Core.input.keyTap(Binding.clear_building)){
player.clearBuilding();
}
if(sreq != null){
float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f;
float x = Core.input.mouseWorld().x + offset;
float y = Core.input.mouseWorld().y + offset;
sreq.x = (int)(x / tilesize);
sreq.y = (int)(y / tilesize);
}
if(block == null || mode != placing){
lineRequests.clear();
}
if(Core.input.keyTap(Binding.pause_building)){
player.isBuilding = !player.isBuilding;
}
if((cursorX != lastLineX || cursorY != lastLineY) && isPlacing() && mode == placing){
updateLine(selectX, selectY);
lastLineX = cursorX;
lastLineY = cursorY;
}
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
BuildRequest req = getRequest(cursorX, cursorY);
if(isPlacing()){
selectX = cursorX;
selectY = cursorY;
lastLineX = cursorX;
lastLineY = cursorY;
mode = placing;
updateLine(selectX, selectY);
}else if(req != null && !req.breaking && mode == none){
sreq = req;
}else if(req != null && req.breaking){
deleting = true;
}else if(selected != null){
//only begin shooting if there's no cursor event
if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.buildQueue().size == 0 && !droppingItem &&
@@ -225,23 +253,28 @@ public class DesktopInput extends InputHandler{
}else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine
player.isShooting = true;
}
}else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) &&
!(player.buildRequest() != null && player.buildRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){
if(block == null){
player.clearBuilding();
}
}else if(Core.input.keyTap(Binding.deselect) && block != null){
block = null;
mode = none;
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset
deleting = false;
mode = breaking;
selectX = tileX(Core.input.mouseX());
selectY = tileY(Core.input.mouseY());
}
if (mode == placing && block != null){
if (!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){
if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){
BuildRequest req = getRequest(cursorX, cursorY);
if(req != null && req.breaking){
player.buildQueue().remove(req);
}
}else{
deleting = false;
}
if(mode == placing && block != null){
if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){
rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4;
overrideLineRotation = true;
}
@@ -252,27 +285,24 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){
if(mode == placing && block != null){ //touch up while placing, place everything in selection
iterateLine(selectX, selectY, cursorX, cursorY, l -> {
rotation = l.rotation;
tryPlaceBlock(l.x, l.y);
});
flushRequests(lineRequests);
lineRequests.clear();
Events.fire(new LineConfirmEvent());
}else if(mode == breaking){ //touch up while breaking, break everything in selection
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength);
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = selectX + x * Mathf.sign(cursorX - selectX);
int wy = selectY + y * Mathf.sign(cursorY - selectY);
tryBreakBlock(wx, wy);
}
}
removeSelection(selectX, selectY, cursorX, cursorY);
}
if(selected != null){
tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
}
if(sreq != null){
if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){
player.buildQueue().remove(sreq, true);
}
sreq = null;
}
mode = none;
}
}
@@ -298,6 +328,7 @@ public class DesktopInput extends InputHandler{
droppingItem = false;
mode = none;
block = null;
sreq = null;
}
}
}

View File

@@ -7,8 +7,11 @@ 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.input.GestureDetector.*;
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.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*;
@@ -17,21 +20,26 @@ import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.fragments.*;
import io.anuke.mindustry.world.*;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
public abstract class InputHandler implements InputProcessor{
public abstract class InputHandler implements InputProcessor, GestureListener{
/** Used for dropping items. */
final static float playerSelectRange = mobile ? 17f : 11f;
/** Maximum line length. */
final static int maxLength = 100;
final static Vector2 stackTrns = new Vector2();
final static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
/** Distance on the back from where items originate. */
final static float backTrns = 3f;
@@ -41,9 +49,14 @@ public abstract class InputHandler implements InputProcessor{
public boolean overrideLineRotation;
public int rotation;
public boolean droppingItem;
public Group uiGroup;
protected PlaceDraw placeDraw = new PlaceDraw();
private PlaceLine line = new PlaceLine();
protected GestureDetector detector;
protected PlaceLine line = new PlaceLine();
protected BuildRequest resultreq;
protected BuildRequest brequest = new BuildRequest();
protected Array<BuildRequest> lineRequests = new Array<>();
protected Array<BuildRequest> selectRequests = new Array<>();
//methods to override
@@ -134,6 +147,14 @@ public abstract class InputHandler implements InputProcessor{
tile.block().configured(tile, player, value);
}
public Eachable<BuildRequest> allRequests(){
return cons -> {
for(BuildRequest request : player.buildQueue()) cons.accept(request);
for(BuildRequest request : selectRequests) cons.accept(request);
for(BuildRequest request : lineRequests) cons.accept(request);
};
}
public OverlayFragment getFrag(){
return frag;
}
@@ -150,7 +171,11 @@ public abstract class InputHandler implements InputProcessor{
return Core.input.mouseY();
}
public void buildUI(Table table){
public void buildPlacementUI(Table table){
}
public void buildUI(Group group){
}
@@ -158,7 +183,7 @@ public abstract class InputHandler implements InputProcessor{
}
public void drawOutlined(){
public void drawBottom(){
}
@@ -170,6 +195,194 @@ public abstract class InputHandler implements InputProcessor{
return false;
}
public void drawSelected(int x, int y, Block block, Color color){
Draw.color(color);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
Draw.rect("block-select",
x*tilesize + block.offset() + offset * p.x,
y*tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.reset();
}
public void drawBreaking(BuildRequest request){
if(request.breaking){
drawBreaking(request.x, request.y);
}else{
drawSelected(request.x, request.y, request.block, Pal.remove);
}
}
public void drawBreaking(int x, int y){
Tile tile = world.ltile(x, y);
if(tile == null) return;
Block block = tile.block();
drawSelected(x, y, block, Pal.remove);
}
/** Returns the selection request that overlaps this position, or null. */
protected BuildRequest getRequest(int x, int y){
return getRequest(x, y, 1, null);
}
/** Returns the selection request that overlaps this position, or null. */
protected BuildRequest getRequest(int x, int y, int size, BuildRequest skip){
float offset = ((size + 1) % 2) * tilesize / 2f;
r2.setSize(tilesize * size);
r2.setCenter(x * tilesize + offset, y * tilesize + offset);
resultreq = null;
Predicate<BuildRequest> test = req -> {
if(req == skip) return false;
Tile other = req.tile();
if(other == null) return false;
if(!req.breaking){
r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
}else{
r1.setSize(other.block().size * tilesize);
r1.setCenter(other.worldx() + other.block().offset(), other.worldy() + other.block().offset());
}
return r2.overlaps(r1);
};
for(BuildRequest req : player.buildQueue()){
if(test.test(req)) return req;
}
for(BuildRequest req : selectRequests){
if(test.test(req)) return req;
}
return null;
}
protected void drawSelection(int x1, int y1, int x2, int y2){
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.ltile(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
drawBreaking(tile.x, tile.y);
}
}
Tmp.r1.set(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.stroke(1f);
for(BuildRequest req : player.buildQueue()){
if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req);
}
}
for(BrokenBlock req : state.teams.get(player.getTeam()).brokenBlocks){
Block block = content.block(req.block);
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
drawSelected(req.x, req.y, content.block(req.block), Pal.remove);
}
}
Lines.stroke(2f);
Draw.color(Pal.removeBack);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}
protected void flushSelectRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
selectRequests.add(req);
}
}
}
protected void flushRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
player.addBuildRequest(req);
}
}
}
protected void drawRequest(BuildRequest request){
drawRequest(request.x, request.y, request.block, request.rotation);
}
/** Draws a placement icon for a specific block. */
protected void drawRequest(int x, int y, Block block, int rotation){
brequest.set(x, y, rotation, block);
block.drawRequest(brequest, allRequests(), validPlace(x, y, block, rotation));
}
/** Remove everything from the queue in a selection. */
protected void removeSelection(int x1, int y1, int x2, int y2){
removeSelection(x1, y1, x2, y2, false);
}
/** Remove everything from the queue in a selection. */
protected void removeSelection(int x1, int y1, int x2, int y2, boolean flush){
NormalizeResult result = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = x1 + x * Mathf.sign(x2 - x1);
int wy = y1 + y * Mathf.sign(y2 - y1);
if(!flush){
tryBreakBlock(wx, wy);
}else{
selectRequests.add(new BuildRequest(wx, wy));
}
}
}
//remove build requests
Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize);
Iterator<BuildRequest> it = player.buildQueue().iterator();
while(it.hasNext()){
BuildRequest req = it.next();
if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){
it.remove();
}
}
//remove blocks to rebuild
Iterator<BrokenBlock> broken = state.teams.get(player.getTeam()).brokenBlocks.iterator();
while(broken.hasNext()){
BrokenBlock req = broken.next();
Block block = content.block(req.block);
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
broken.remove();
}
}
}
protected void updateLine(int x1, int y1, int x2, int y2){
lineRequests.clear();
iterateLine(x1, y1, x2, y2, l -> {
rotation = l.rotation;
lineRequests.add(new BuildRequest(l.x, l.y, l.rotation, block));
});
}
protected void updateLine(int x1, int y1){
updateLine(x1, y1, tileX(getMouseX()), tileY(getMouseY()));
}
/** Handles tile tap events that are not platform specific. */
boolean tileTapped(Tile tile){
tile = tile.link();
@@ -216,7 +429,7 @@ public abstract class InputHandler implements InputProcessor{
//clear when the player taps on something else
if(!consumed && !mobile && player.isBuilding() && block == null){
player.clearBuilding();
//player.clearBuilding();
block = null;
return true;
}
@@ -301,16 +514,34 @@ public abstract class InputHandler implements InputProcessor{
table.clear();
}
}
if(detector != null){
Core.input.removeProcessor(detector);
}
if(uiGroup != null){
uiGroup.remove();
uiGroup = null;
}
}
public void add(){
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
Core.input.addProcessor(this);
if(Core.scene != null){
Table table = (Table)Core.scene.find("inputTable");
if(table != null){
table.clear();
buildUI(table);
buildPlacementUI(table);
}
uiGroup = new WidgetGroup();
uiGroup.touchable(Touchable.childrenOnly);
uiGroup.setFillParent(true);
ui.hudGroup.addChild(uiGroup);
buildUI(uiGroup);
}
if(player != null){
player.isBuilding = true;
}
}
@@ -356,6 +587,15 @@ public abstract class InputHandler implements InputProcessor{
}
public boolean validPlace(int x, int y, Block type, int rotation){
return validPlace(x, y, type, rotation, null);
}
public boolean validPlace(int x, int y, Block type, int rotation, BuildRequest ignore){
for(BuildRequest req : player.buildQueue()){
if(req != ignore && !req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2))){
return false;
}
}
return Build.validPlace(player.getTeam(), x, y, type, rotation);
}
@@ -407,8 +647,8 @@ public abstract class InputHandler implements InputProcessor{
float angle = Angles.angle(startX, startY, endX, endY);
int baseRotation = rotation;
if (!overrideLineRotation || diagonal){
baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4;
if(!overrideLineRotation || diagonal){
baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4;
}
Tmp.r3.set(-1, -1, 0, 0);
@@ -423,7 +663,7 @@ public abstract class InputHandler implements InputProcessor{
Point2 next = i == points.size - 1 ? null : points.get(i + 1);
line.x = point.x;
line.y = point.y;
if (!overrideLineRotation || diagonal){
if(!overrideLineRotation || diagonal){
line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation;
}else{
line.rotation = rotation;
@@ -435,13 +675,6 @@ public abstract class InputHandler implements InputProcessor{
}
}
public static class PlaceDraw{
public int rotation, scalex, scaley;
public TextureRegion region;
public static final PlaceDraw instance = new PlaceDraw();
}
class PlaceLine{
public int x, y, rotation;
public boolean last;

View File

@@ -2,12 +2,12 @@ package io.anuke.mindustry.input;
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.input.GestureDetector.*;
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.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*;
@@ -19,7 +19,6 @@ import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*;
@@ -29,17 +28,15 @@ import static io.anuke.mindustry.input.PlaceMode.*;
public class MobileInput extends InputHandler implements GestureListener{
/** Maximum speed the player can pan. */
private static final float maxPanSpeed = 1.3f;
private static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
/** Distance to edge of screen to start panning. */
private final float edgePan = Scl.scl(60f);
//gesture data
private Vector2 vector = new Vector2();
private float lastZoom = -1;
private GestureDetector detector;
/** Position where the player started dragging a line. */
private int lineStartX, lineStartY;
private int lineStartX, lineStartY, lastLineX, lastLineY;
/** Animation scale for line. */
private float lineScale;
@@ -49,10 +46,8 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Used for shifting build requests. */
private float shiftDeltaX, shiftDeltaY;
/** List of currently selected tiles to place. */
private Array<PlaceRequest> selection = new Array<>();
/** Place requests to be removed. */
private Array<PlaceRequest> removals = new Array<>();
private Array<BuildRequest> removals = new Array<>();
/** Whether or not the player is currently shifting all placed tiles. */
private boolean selecting;
/** Whether the player is currently in line-place mode. */
@@ -62,9 +57,9 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Whether no recipe was available when switching to break mode. */
private Block lastBlock;
/** Last placed request. Used for drawing block overlay. */
private PlaceRequest lastPlaced;
private int prevX, prevY, prevRotation;
private BuildRequest lastPlaced;
/** Down tracking for panning.*/
private boolean down = false;
//region utility methods
@@ -99,10 +94,10 @@ public class MobileInput extends InputHandler implements GestureListener{
r2.setSize(block.size * tilesize);
r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset());
for(PlaceRequest req : selection){
for(BuildRequest req : selectRequests){
Tile other = req.tile();
if(other == null || req.remove) continue;
if(other == null || req.breaking) continue;
r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
@@ -128,16 +123,16 @@ public class MobileInput extends InputHandler implements GestureListener{
}
/** Returns the selection request that overlaps this tile, or null. */
PlaceRequest getRequest(Tile tile){
BuildRequest getRequest(Tile tile){
r2.setSize(tilesize);
r2.setCenter(tile.worldx(), tile.worldy());
for(PlaceRequest req : selection){
for(BuildRequest req : selectRequests){
Tile other = req.tile();
if(other == null) continue;
if(!req.remove){
if(!req.breaking){
r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
@@ -156,8 +151,8 @@ public class MobileInput extends InputHandler implements GestureListener{
return null;
}
void removeRequest(PlaceRequest request){
selection.removeValue(request, true);
void removeRequest(BuildRequest request){
selectRequests.removeValue(request, true);
removals.add(request);
}
@@ -172,80 +167,8 @@ public class MobileInput extends InputHandler implements GestureListener{
//endregion
//region UI and drawing
void drawRequest(PlaceRequest request, PlaceRequest prev){
Tile tile = request.tile();
if(!request.remove){
if(prev != null){
request.block.getPlaceDraw(placeDraw, request.rotation, prev.x - request.x, prev.y - request.y, prev.rotation);
}else{
request.block.getPlaceDraw(placeDraw, request.rotation, 0, 0, request.rotation);
}
//draw placing request
float offset = request.block.offset();
TextureRegion region = placeDraw.region;
Draw.mixcol(Pal.accent, Mathf.clamp((1f - request.scale) / 0.5f + 0.12f + Mathf.absin(Time.time(), 8f, 0.35f)));
Draw.tint(Color.white, Pal.breakInvalid, request.redness);
Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset,
region.getWidth() * request.scale * Draw.scl * placeDraw.scalex,
region.getHeight() * request.scale * Draw.scl * placeDraw.scaley,
request.block.rotate ? placeDraw.rotation * 90 : 0);
Draw.mixcol(Pal.accent, 1f);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float poffset = -Math.max(request.block.size - 1, 0) / 2f * tilesize;
TextureRegion find = Core.atlas.find("block-select");
if(i % 2 == 0)
Draw.rect("block-select", request.tile().x * tilesize + request.block.offset() + poffset * p.x, request.tile().y * tilesize + request.block.offset() + poffset * p.y,
find.getWidth() * Draw.scl * request.scale, find.getHeight() * Draw.scl * request.scale, i * 90);
}
Draw.color();
}else{
float rad = Math.max((tile.block().size * tilesize / 2f - 1) * request.scale, 1f);
if(rad <= 1.01f) return;
Draw.mixcol();
//draw removing request
Draw.tint(Pal.removeBack);
Lines.square(tile.drawx(), tile.drawy() - 1, rad);
Draw.tint(Pal.remove);
Lines.square(tile.drawx(), tile.drawy(), rad);
}
}
/** Draws a placement icon for a specific block. */
void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){
if(validPlace(x, y, block, rotation) && !checkOverlapPlacement(x, y, block)){
block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation);
Draw.color();
Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(),
placeDraw.region.getWidth() * Draw.scl * placeDraw.scalex,
placeDraw.region.getHeight() * Draw.scl * placeDraw.scaley,
block.rotate ? placeDraw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
if(i % 2 == 0)
Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.color();
}else{
Draw.color(Pal.removeBack);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1);
}
}
@Override
public void buildUI(Table table){
public void buildPlacementUI(Table table){
table.addImage().color(Pal.gray).height(4f).colspan(4).growX();
table.row();
table.left().margin(0f).defaults().size(48f);
@@ -267,12 +190,12 @@ public class MobileInput extends InputHandler implements GestureListener{
//confirm button
table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> {
for(PlaceRequest request : selection){
for(BuildRequest request : selectRequests){
Tile tile = request.tile();
//actually place/break all selected blocks
if(tile != null){
if(!request.remove){
if(!request.breaking){
rotation = request.rotation;
Block before = block;
block = request.block;
@@ -285,25 +208,22 @@ public class MobileInput extends InputHandler implements GestureListener{
}
//move all current requests to removal array so they fade out
removals.addAll(selection);
selection.clear();
removals.addAll(selectRequests);
selectRequests.clear();
selecting = false;
}).visible(() -> !selection.isEmpty()).name("confirmplace");
Core.scene.table(t -> {
t.setName("cancelMobile");
t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu));
t.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
player.clearBuilding();
mode = none;
block = null;
}).width(155f);
});
}).visible(() -> !selectRequests.isEmpty()).name("confirmplace");
}
@Override
public boolean isDrawing(){
return selection.size > 0 || removals.size > 0 || lineMode || player.target != null || mode != PlaceMode.none;
public void buildUI(Group group){
group.fill(t -> {
t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu));
t.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
player.clearBuilding();
mode = none;
block = null;
}).width(155f);
});
}
@Override
@@ -312,55 +232,52 @@ public class MobileInput extends InputHandler implements GestureListener{
}
@Override
public void drawOutlined(){
public void drawBottom(){
Lines.stroke(1f);
//draw removals
for(PlaceRequest request : removals){
for(BuildRequest request : removals){
Tile tile = request.tile();
if(tile == null) continue;
request.scale = Mathf.lerpDelta(request.scale, 0f, 0.2f);
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f);
request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
drawRequest(request, null);
//TODO
//drawRequest(request);
}
PlaceRequest last = null;
//draw list of requests
for(PlaceRequest request : selection){
for(BuildRequest request : selectRequests){
Tile tile = request.tile();
if(tile == null) continue;
if((!request.remove && validPlace(tile.x, tile.y, request.block, request.rotation))
|| (request.remove && validBreak(tile.x, tile.y))){
request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f);
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f);
if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation))
|| (request.breaking && validBreak(tile.x, tile.y))){
request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
}else{
request.scale = Mathf.lerpDelta(request.scale, 0.6f, 0.1f);
request.redness = Mathf.lerpDelta(request.redness, 0.9f, 0.2f);
request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f);
request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f);
}
Tmp.c1.set(Draw.getMixColor());
if(!request.remove && request == lastPlaced && request.block != null){
if(!request.breaking && request == lastPlaced && request.block != null){
Draw.mixcol();
if(request.block.rotate) drawArrow(request.block, tile.x, tile.y, request.rotation);
}
Draw.mixcol(Tmp.c1, 1f);
drawRequest(request, last);
drawRequest(request);
//draw last placed request
if(!request.remove && request == lastPlaced && request.block != null){
if(!request.breaking && request == lastPlaced && request.block != null){
Draw.mixcol();
request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation));
}
last = request;
}
Draw.mixcol();
@@ -373,46 +290,16 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == placing && block != null){
//draw placing
prevX = lineStartX;
prevY = lineStartY;
prevRotation = rotation;
iterateLine(lineStartX, lineStartY, tileX, tileY, l -> {
if(l.last && block.rotate){
drawArrow(block, l.x, l.y, l.rotation);
}
drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation);
rotation = l.rotation;
prevX = l.x;
prevY = l.y;
prevRotation = l.rotation;
});
}else if(mode == breaking){
//draw breaking
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, lineStartX, lineStartY, tileX, tileY, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile other = world.ltile(x, y);
if(other == null || !validBreak(other.x, other.y)) continue;
Draw.color(Pal.removeBack);
Lines.square(other.drawx(), other.drawy() - 1, other.block().size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f - 1);
for(int i = 0; i < lineRequests.size; i++){
BuildRequest req = lineRequests.get(i);
if(i == lineRequests.size - 1 && req.block.rotate){
drawArrow(block, req.x, req.y, req.rotation);
}
drawRequest(lineRequests.get(i));
}
Draw.color(Pal.removeBack);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}else if(mode == breaking){
drawSelection(lineStartX, lineStartY, tileX, tileY);
}
}
TargetTrait target = player.target;
@@ -438,31 +325,23 @@ public class MobileInput extends InputHandler implements GestureListener{
Draw.reset();
}
@Override
protected void drawRequest(BuildRequest request){
drawRequest(request.x, request.y, request.block, request.rotation);
if(!request.breaking){
drawSelected(request.x, request.y, request.block, Pal.accent);
}
}
//endregion
//region input events
@Override
public void add(){
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
super.add();
}
@Override
public void remove(){
super.remove();
if(detector != null){
Core.input.removeProcessor(detector);
}
if(Core.scene != null && Core.scene.find("cancelMobile") != null){
Core.scene.find("cancelMobile").remove();
}
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){
if(state.is(State.menu) || player.isDead()) return false;
down = true;
//get tile on cursor
Tile cursor = tileAt(screenX, screenY);
@@ -489,44 +368,20 @@ public class MobileInput extends InputHandler implements GestureListener{
public boolean touchUp(int screenX, int screenY, int pointer, KeyCode button){
lastZoom = renderer.getScale();
if(!Core.input.isTouched()){
down = false;
}
//place down a line if in line mode
if(lineMode){
int tileX = tileX(screenX);
int tileY = tileY(screenY);
if(mode == placing && isPlacing()){
iterateLine(lineStartX, lineStartY, tileX, tileY, l -> {
Tile tile = world.tile(l.x, l.y);
if(tile != null && checkOverlapPlacement(tile.x, tile.y, block)){
return;
}
PlaceRequest request = new PlaceRequest(l.x, l.y, block, l.rotation);
request.scale = 1f;
selection.add(request);
});
flushSelectRequests(lineRequests);
Events.fire(new LineConfirmEvent());
}else if(mode == breaking){
//normalize area
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength);
//break everything in area
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = lineStartX + x * Mathf.sign(tileX - lineStartX);
int wy = lineStartY + y * Mathf.sign(tileY - lineStartY);
Tile tar = world.ltile(wx, wy);
if(tar == null) continue;
if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){
PlaceRequest request = new PlaceRequest(tar.x, tar.y);
request.scale = 1f;
selection.add(request);
}
}
}
removeSelection(lineStartX, lineStartY, tileX, tileY, true);
}
lineMode = false;
@@ -554,11 +409,14 @@ public class MobileInput extends InputHandler implements GestureListener{
//long pressing enables line mode otherwise
lineStartX = cursor.x;
lineStartY = cursor.y;
lastLineX = cursor.x;
lastLineY = cursor.y;
lineMode = true;
if(mode == breaking){
Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f);
}else if(block != null){
updateLine(lineStartX, lineStartY, cursor.x, cursor.y);
Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size);
}
@@ -584,11 +442,11 @@ public class MobileInput extends InputHandler implements GestureListener{
removeRequest(getRequest(cursor));
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
//add to selection queue if it's a valid place position
selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation));
selectRequests.add(lastPlaced = new BuildRequest(cursor.x, cursor.y, rotation, block));
}else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){
//add to selection queue if it's a valid BREAK position
cursor = cursor.link();
selection.add(new PlaceRequest(cursor.x, cursor.y));
selectRequests.add(new BuildRequest(cursor.x, cursor.y));
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){
tryBeginMine(cursor);
}
@@ -599,7 +457,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override
public void update(){
if(state.is(State.menu) || player.isDead()){
selection.clear();
selectRequests.clear();
removals.clear();
mode = none;
}
@@ -629,8 +487,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == none){
selecting = false;
lineMode = false;
removals.addAll(selection);
selection.clear();
removals.addAll(selectRequests);
selectRequests.clear();
}
if(lineMode && mode == placing && block == null){
@@ -656,7 +514,7 @@ public class MobileInput extends InputHandler implements GestureListener{
lineScale = Mathf.lerpDelta(lineScale, 1f, 0.1f);
//When in line mode, pan when near screen edges automatically
if(Core.input.isTouched(0) && lineMode){
if(Core.input.isTouched(0)){
float screenX = Core.input.mouseX(), screenY = Core.input.mouseY();
float panX = 0, panY = 0;
@@ -684,15 +542,24 @@ public class MobileInput extends InputHandler implements GestureListener{
Core.camera.position.x += vector.x;
Core.camera.position.y += vector.y;
}
int lx = tileX(Core.input.mouseX()), ly = tileY(Core.input.mouseY());
if((lastLineX != lx || lastLineY != ly) && isPlacing()){
lastLineX = lx;
lastLineY = ly;
updateLine(lineStartX, lineStartY, lx, ly);
}
}else{
lineRequests.clear();
lineScale = 0f;
}
//remove place requests that have disappeared
for(int i = removals.size - 1; i >= 0; i--){
PlaceRequest request = removals.get(i);
BuildRequest request = removals.get(i);
if(request.scale <= 0.0001f){
if(request.animScale <= 0.0001f){
removals.remove(i);
i--;
}
@@ -712,6 +579,8 @@ public class MobileInput extends InputHandler implements GestureListener{
return false;
}
if(!down) return false;
if(selecting){ //pan all requests
shiftDeltaX += deltaX;
shiftDeltaY += deltaY;
@@ -720,8 +589,8 @@ public class MobileInput extends InputHandler implements GestureListener{
int shiftedY = (int)(shiftDeltaY / tilesize);
if(Math.abs(shiftedX) > 0 || Math.abs(shiftedY) > 0){
for(PlaceRequest req : selection){
if(req.remove) continue; //don't shift removal requests
for(BuildRequest req : selectRequests){
if(req.breaking) continue; //don't shift removal requests
req.x += shiftedX;
req.y += shiftedY;
}
@@ -756,33 +625,4 @@ public class MobileInput extends InputHandler implements GestureListener{
}
//endregion
private class PlaceRequest{
int x, y;
Block block;
int rotation;
boolean remove;
//animation variables
float scale;
float redness;
PlaceRequest(int x, int y, Block block, int rotation){
this.x = x;
this.y = y;
this.block = block;
this.rotation = rotation;
this.remove = false;
}
PlaceRequest(int x, int y){
this.x = x;
this.y = y;
this.remove = true;
}
Tile tile(){
return world.tile(x, y);
}
}
}

View File

@@ -257,7 +257,7 @@ public abstract class SaveVersion extends SaveFileReader{
TeamData data = state.teams.get(team);
int blocks = stream.readInt();
for(int j = 0; j < blocks; j++){
data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), stream.readShort(), stream.readInt()));
data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt()));
}
}

View File

@@ -125,7 +125,7 @@ public class Mods implements Loadable{
//get textures packed
if(totalSprites > 0){
TextureFilter filter = TextureFilter.Nearest;
TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest;
packer.updateTextureAtlas(Core.atlas, filter, filter, false);
//generate new icons

View File

@@ -225,6 +225,8 @@ public class SettingsMenuDialog extends SettingsDialog{
game.checkPref("savecreate", true);
game.checkPref("hints", true);
if(steam){
game.checkPref("publichost", false, i -> {
platform.updateLobby();

View File

@@ -10,6 +10,8 @@ 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.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
@@ -17,7 +19,7 @@ import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.Styles;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*;
import static io.anuke.mindustry.Vars.*;
@@ -74,17 +76,21 @@ public class PlacementFragment extends Fragment{
boolean gridUpdate(InputHandler input){
if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
Tile tile = world.ltileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
Block tryRecipe = tile == null ? null : tile.block();
if(tile != null){
tile = tile.link();
Block tryRecipe = tile.block();
if(tryRecipe.isVisible() && unlocked(tryRecipe)){
input.block = tryRecipe;
currentCategory = input.block.category;
return true;
for(BuildRequest req : player.buildQueue()){
if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){
tryRecipe = req.block;
break;
}
}
if(tryRecipe != null && tryRecipe.isVisible() && unlocked(tryRecipe)){
input.block = tryRecipe;
currentCategory = input.block.category;
return true;
}
}
if(!Core.input.keyDown(Binding.gridMode) || ui.chatfrag.chatOpen()) return false;
@@ -263,7 +269,7 @@ public class PlacementFragment extends Fragment{
blocksSelect.margin(4).marginTop(0);
blocksSelect.table(blocks -> blockTable = blocks).grow();
blocksSelect.row();
blocksSelect.table(control.input::buildUI).name("inputTable").growX();
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
}).fillY().bottom().touchable(Touchable.enabled);
frame.table(categories -> {
categories.defaults().size(50f);

View File

@@ -19,11 +19,11 @@ import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.blocks.*;
@@ -667,10 +667,16 @@ public class Block extends BlockStorage{
}
}
public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){
draw.region = icon(Cicon.full);
draw.scalex = draw.scaley = 1;
draw.rotation = rotation;
public void drawRequest(BuildRequest req, Eachable<BuildRequest> list, boolean valid){
Draw.reset();
Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f));
Draw.alpha(1f);
drawRequestRegion(req, list);
Draw.reset();
}
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(), !rotate ? 0 : req.rotation * 90);
}
@Override
@@ -785,6 +791,10 @@ public class Block extends BlockStorage{
return ((size + 1) % 2) * tilesize / 2f;
}
public Rectangle bounds(int x, int y, Rectangle rect){
return rect.setSize(size * tilesize).setCenter(x * tilesize + offset(), y * tilesize + offset());
}
public boolean isMultiblock(){
return size > 1;
}

View File

@@ -50,10 +50,14 @@ public class Edges{
}
public static Tile getFacingEdge(Tile tile, Tile other){
if(!tile.block().isMultiblock()) return tile;
int size = tile.block().size;
return world.tile(tile.x + Mathf.clamp(other.x - tile.x, -(size - 1) / 2, (size / 2)),
tile.y + Mathf.clamp(other.y - tile.y, -(size - 1) / 2, (size / 2)));
return getFacingEdge(tile.block, tile.x, tile.y, other);
}
public static Tile getFacingEdge(Block block, int tilex, int tiley, Tile other){
if(!block.isMultiblock()) return world.tile(tilex, tiley);
int size = block.size;
return world.tile(tilex + Mathf.clamp(other.x - tilex, -(size - 1) / 2, (size / 2)),
tiley + Mathf.clamp(other.y - tiley, -(size - 1) / 2, (size / 2)));
}
public static Vector2[] getPixelPolygon(float radius){

View File

@@ -0,0 +1,96 @@
package io.anuke.mindustry.world.blocks;
import io.anuke.arc.function.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.world.*;
import java.util.*;
public interface Autotiler{
class AutotilerHolder{
static final int[] blendresult = new int[3];
static final BuildRequest[] directionals = new BuildRequest[4];
}
default @Nullable int[] getTiling(BuildRequest req, Eachable<BuildRequest> list){
if(req.tile() == null) return null;
BuildRequest[] directionals = AutotilerHolder.directionals;
Arrays.fill(directionals, null);
list.each(other -> {
if(other.breaking || other == req) return;
int i = 0;
for(Point2 point : Geometry.d4){
int x = req.x + point.x, y = req.y + point.y;
if(x >= other.x -(other.block.size - 1) / 2 && x <= other.x + (other.block.size / 2) && y >= other.y -(other.block.size - 1) / 2 && y <= other.y + (other.block.size / 2)){
directionals[i] = other;
}
i++;
}
});
return buildBlending(req.tile(), req.rotation, directionals);
}
default int[] buildBlending(Tile tile, int rotation, BuildRequest[] directional){
int[] blendresult = AutotilerHolder.blendresult;
blendresult[0] = 0;
blendresult[1] = blendresult[2] = 1;
int num =
(blends(tile, rotation, directional, 2) && blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)) ? 0 :
(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)) ? 1 :
(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 2)) ? 2 :
(blends(tile, rotation, directional, 3) && blends(tile, rotation, directional, 2)) ? 3 :
blends(tile, rotation, directional, 1) ? 4 :
blends(tile, rotation, directional, 3) ? 5 :
-1;
transformCase(num, blendresult);
return blendresult;
}
default void transformCase(int num, int[] bits){
if(num == 0){
bits[0] = 3;
}else if(num == 1){
bits[0] = 4;
}else if(num == 2){
bits[0] = 2;
}else if(num == 3){
bits[0] = 2;
bits[2] = -1;
}else if(num == 4){
bits[0] = 1;
bits[2] = -1;
}else if(num == 5){
bits[0] = 1;
}
}
default boolean blends(Tile tile, int rotation, @Nullable BuildRequest[] directional, int direction){
int realDir = Mathf.mod(rotation - direction, 4);
if(directional != null && directional[realDir] != null){
BuildRequest req = directional[realDir];
if(blends(tile, rotation, req.x, req.y, req.rotation, req.block)){
return true;
}
}
return blends(tile, rotation, direction);
}
default boolean blends(Tile tile, int rotation, int direction){
Tile other = tile.getNearby(Mathf.mod(rotation - direction, 4));
if(other != null) other = other.link();
return other != null && blends(tile, rotation, other.x, other.y, other.rotation(), other.block());
}
default boolean lookingAt(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|| (!otherblock.rotate || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
}
boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock);
}

View File

@@ -110,8 +110,8 @@ public class BuildBlock extends Block{
//if the target is constructible, begin constructing
if(entity.cblock != null){
player.clearBuilding();
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock));
//player.clearBuilding();
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock), false);
}
}

View File

@@ -1,6 +1,6 @@
package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
@@ -16,11 +16,8 @@ public class ArmoredConveyor extends Conveyor{
}
@Override
protected boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
return other != null && other.block().outputsItems()
&& ((tile.getNearby(tile.rotation()) == other) || ((!other.block().rotate && Edges.getFacingEdge(other, tile).relativeTo(tile) == tile.rotation()) || (other.block().rotate && other.getNearby(other.rotation()) == tile)));
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|| ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == tile.rotation()) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
}
}

View File

@@ -1,16 +1,17 @@
package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.math.Mathf;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.LiquidBlock;
import io.anuke.mindustry.world.modules.LiquidModule;
import io.anuke.arc.*;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.modules.*;
public class Conduit extends LiquidBlock{
public class Conduit extends LiquidBlock implements Autotiler{
protected final int timerFlow = timers++;
protected TextureRegion[] topRegions = new TextureRegion[7];
@@ -39,29 +40,33 @@ public class Conduit extends LiquidBlock{
super.onProximityUpdate(tile);
ConduitEntity entity = tile.entity();
entity.blendbits = 0;
entity.blendrot = 0;
if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 3;
}else if(blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 6;
}else if(blends(tile, 1) && blends(tile, 2)){
entity.blendbits = 2;
}else if(blends(tile, 3) && blends(tile, 2)){
entity.blendbits = 4;
}else if(blends(tile, 1)){
entity.blendbits = 5;
}else if(blends(tile, 3)){
entity.blendbits = 1;
}
int[] bits = buildBlending(tile, tile.rotation(), null);
entity.blendbits = bits[0];
}
private boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
@Override
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
int[] bits = getTiling(req, list);
return other != null && other.block().hasLiquids && other.block().outputsLiquid && ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile));
if(bits == null) return;
Draw.colorl(0.34f);
Draw.alpha(0.5f);
Draw.rect(botRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
Draw.color();
Draw.rect(topRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
}
@Override
public void transformCase(int num, int[] bits){
bits[0] = num == 0 ? 3 : num == 1 ? 6 : num == 2 ? 2 : num == 3 ? 4 : num == 4 ? 5 : num == 5 ? 1 : 0;
}
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.hasLiquids && otherblock.outputsLiquid && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
}
@Override
@@ -113,7 +118,6 @@ public class Conduit extends LiquidBlock{
public static class ConduitEntity extends TileEntity{
public float smoothLiquid;
byte blendbits;
int blendrot;
int blendbits;
}
}

View File

@@ -2,24 +2,26 @@ package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.meta.*;
import java.io.*;
import static io.anuke.mindustry.Vars.*;
public class Conveyor extends Block{
public class Conveyor extends Block implements Autotiler{
private static final float itemSpace = 0.4f;
private static final float minmove = 1f / (Short.MAX_VALUE - 2);
private static ItemPos drawpos = new ItemPos();
@@ -27,6 +29,8 @@ public class Conveyor extends Block{
private static ItemPos pos2 = new ItemPos();
private final Vector2 tr1 = new Vector2();
private final Vector2 tr2 = new Vector2();
private final int[] blendresult = new int[3];
private final BuildRequest[] directionals = new BuildRequest[4];
private TextureRegion[][] regions = new TextureRegion[7][4];
@@ -90,55 +94,25 @@ public class Conveyor extends Block{
super.onProximityUpdate(tile);
ConveyorEntity entity = tile.entity();
entity.blendbits = 0;
entity.blendsclx = entity.blendscly = 1;
if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 3;
}else if(blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 4;
}else if(blends(tile, 1) && blends(tile, 2)){
entity.blendbits = 2;
}else if(blends(tile, 3) && blends(tile, 2)){
entity.blendbits = 2;
entity.blendscly = -1;
}else if(blends(tile, 1)){
entity.blendbits = 1;
entity.blendscly = -1;
}else if(blends(tile, 3)){
entity.blendbits = 1;
}
int[] bits = buildBlending(tile, tile.rotation(), null);
entity.blendbits = bits[0];
entity.blendsclx = bits[1];
entity.blendscly = bits[2];
}
@Override
public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){
draw.rotation = rotation;
draw.scalex = draw.scaley = 1;
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
int[] bits = getTiling(req, list);
int blendbits = 0;
if(bits == null) return;
if(blends(rotation, 1, prevX, prevY, prevRotation)){
blendbits = 1;
draw.scaley = -1;
}else if(blends(rotation, 3, prevX, prevY, prevRotation)){
blendbits = 1;
}
draw.rotation = rotation;
draw.region = regions[blendbits][0];
TextureRegion region = regions[bits[0]][0];
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl, region.getHeight() * bits[2] * Draw.scl, req.rotation * 90);
}
protected boolean blends(int rotation, int offset, int prevX, int prevY, int prevRotation){
Point2 left = Geometry.d4(rotation - offset);
return left.equals(prevX, prevY) && prevRotation == Mathf.mod(rotation + offset, 4);
}
protected boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
return other != null && other.block().outputsItems()
&& ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile));
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
}
@Override