Files
Mindustry/core/src/mindustry/input/InputHandler.java

885 lines
30 KiB
Java
Raw Normal View History

2019-12-25 01:39:38 -05:00
package mindustry.input;
2019-12-25 01:39:38 -05:00
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.input.GestureDetector.*;
import arc.math.*;
import arc.math.geom.*;
import arc.scene.*;
import arc.scene.event.*;
import arc.scene.ui.layout.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.effect.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.Placement.*;
import mindustry.net.*;
import mindustry.type.*;
import mindustry.ui.fragments.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import mindustry.world.blocks.power.PowerNode;
2019-10-07 17:17:01 -04:00
import java.util.*;
2019-12-25 01:39:38 -05:00
import static mindustry.Vars.*;
public abstract class InputHandler implements InputProcessor, GestureListener{
2019-04-08 09:03:18 -04:00
/** Used for dropping items. */
final static float playerSelectRange = mobile ? 17f : 11f;
2019-04-08 09:03:18 -04:00
/** Maximum line length. */
2018-07-12 20:37:14 -04:00
final static int maxLength = 100;
2019-12-25 11:16:54 -05:00
final static Vec2 stackTrns = new Vec2();
final static Rect r1 = new Rect(), r2 = new Rect();
2019-04-08 09:03:18 -04:00
/** Distance on the back from where items originate. */
2018-07-12 20:37:14 -04:00
final static float backTrns = 3f;
2019-07-02 18:40:39 -04:00
public final OverlayFragment frag = new OverlayFragment();
2018-07-12 20:37:14 -04:00
2019-01-20 13:49:53 -05:00
public Block block;
public boolean overrideLineRotation;
2018-07-12 20:37:14 -04:00
public int rotation;
public boolean droppingItem;
public Group uiGroup;
2018-07-12 20:37:14 -04:00
2019-10-18 11:38:00 -04:00
protected @Nullable Schematic lastSchematic;
protected GestureDetector detector;
protected PlaceLine line = new PlaceLine();
2019-10-07 19:51:52 -04:00
protected BuildRequest resultreq;
protected BuildRequest brequest = new BuildRequest();
protected Array<BuildRequest> lineRequests = new Array<>();
protected Array<BuildRequest> selectRequests = new Array<>();
2019-03-19 10:30:13 -04:00
2018-07-12 20:37:14 -04:00
//methods to override
2018-05-29 00:15:24 -04:00
2018-07-26 15:24:48 -04:00
@Remote(targets = Loc.client, called = Loc.server)
2018-07-12 20:37:14 -04:00
public static void dropItem(Player player, float angle){
2019-09-07 14:11:50 -04:00
if(net.server() && player.item().amount <= 0){
2018-07-12 20:37:14 -04:00
throw new ValidateException(player, "Player cannot drop an item.");
}
2018-04-15 13:05:18 -04:00
Effects.effect(Fx.dropItem, Color.white, player.x, player.y, angle, player.item().item);
player.clearItem();
2018-05-11 07:59:10 -07:00
}
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
public static void rotateBlock(Player player, Tile tile, boolean direction){
if(net.server() && !Units.canInteract(player, tile)){
throw new ValidateException(player, "Player cannot drop an item.");
}
tile.rotation(Mathf.mod(tile.rotation() + Mathf.sign(direction), 4));
if(tile.entity != null){
tile.entity.updateProximity();
tile.entity.noSleep();
}
}
2018-07-26 15:24:48 -04:00
@Remote(targets = Loc.both, forward = true, called = Loc.server)
2018-07-12 20:37:14 -04:00
public static void transferInventory(Player player, Tile tile){
2019-09-18 15:18:59 -04:00
if(player == null || player.timer == null || !player.timer.get(Player.timerTransfer, 40)) return;
2019-09-26 19:51:41 -04:00
if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile))){
2018-07-12 20:37:14 -04:00
throw new ValidateException(player, "Player cannot transfer an item.");
}
2018-05-29 00:15:24 -04:00
2019-09-08 15:08:55 -04:00
if(tile.entity == null) return;
2018-05-29 00:15:24 -04:00
2018-12-21 21:33:05 -05:00
player.isTransferring = true;
2018-05-29 00:15:24 -04:00
Item item = player.item().item;
int amount = player.item().amount;
2018-12-21 21:33:05 -05:00
int accepted = tile.block().acceptStack(item, amount, tile, player);
player.item().amount -= accepted;
2018-05-29 00:15:24 -04:00
2018-12-21 21:33:05 -05:00
int sent = Mathf.clamp(accepted / 4, 1, 8);
int removed = accepted / sent;
int[] remaining = {accepted, accepted};
Block block = tile.block();
2018-07-12 20:37:14 -04:00
Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted)));
2019-08-08 21:26:50 -04:00
2018-12-21 21:33:05 -05:00
for(int i = 0; i < sent; i++){
boolean end = i == sent - 1;
Time.run(i * 3, () -> {
tile.block().getStackOffset(item, tile, stackTrns);
2018-07-12 20:37:14 -04:00
2018-12-21 21:33:05 -05:00
ItemTransfer.create(item,
2019-04-08 09:03:18 -04:00
player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns),
2019-12-25 11:16:54 -05:00
new Vec2(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> {
2019-04-08 09:03:18 -04:00
if(tile.block() != block || tile.entity == null || tile.entity.items == null) return;
2018-07-12 20:37:14 -04:00
2019-04-08 09:03:18 -04:00
tile.block().handleStack(item, removed, tile, player);
remaining[1] -= removed;
2018-07-12 20:37:14 -04:00
2019-04-08 09:03:18 -04:00
if(end && remaining[1] > 0){
tile.block().handleStack(item, remaining[1], tile, player);
}
});
2018-07-12 20:37:14 -04:00
2018-12-21 21:33:05 -05:00
remaining[0] -= removed;
2018-07-12 20:37:14 -04:00
2018-12-21 21:33:05 -05:00
if(end){
player.isTransferring = false;
}
});
}
2018-05-29 00:15:24 -04:00
}
2018-07-26 15:24:48 -04:00
@Remote(targets = Loc.both, called = Loc.server, forward = true)
2018-07-12 20:37:14 -04:00
public static void onTileTapped(Player player, Tile tile){
if(tile == null || player == null) return;
2019-09-26 19:51:41 -04:00
if(!Units.canInteract(player, tile)) return;
2018-07-12 20:37:14 -04:00
tile.block().tapped(tile, player);
Core.app.post(() -> Events.fire(new TapEvent(tile, player)));
2018-07-12 20:37:14 -04:00
}
2018-05-29 00:15:24 -04:00
2019-09-30 19:40:08 -04:00
@Remote(targets = Loc.both, called = Loc.both, forward = true)
2019-09-30 10:57:48 -04:00
public static void onTileConfig(Player player, Tile tile, int value){
if(tile == null || !Units.canInteract(player, tile)) return;
2019-09-30 19:40:08 -04:00
tile.block().configured(tile, player, value);
Core.app.post(() -> Events.fire(new TapConfigEvent(tile, player, value)));
2019-09-30 10:57:48 -04:00
}
public Eachable<BuildRequest> allRequests(){
return cons -> {
2019-10-29 15:57:25 -04:00
for(BuildRequest request : player.buildQueue()) cons.get(request);
for(BuildRequest request : selectRequests) cons.get(request);
for(BuildRequest request : lineRequests) cons.get(request);
};
}
public OverlayFragment getFrag(){
return frag;
}
2018-07-12 20:37:14 -04:00
public void update(){
2018-05-29 00:15:24 -04:00
2018-07-12 20:37:14 -04:00
}
2018-05-29 00:15:24 -04:00
2018-07-12 20:37:14 -04:00
public float getMouseX(){
2018-12-22 22:17:28 -05:00
return Core.input.mouseX();
2018-07-12 20:37:14 -04:00
}
2018-07-12 20:37:14 -04:00
public float getMouseY(){
2018-12-22 22:17:28 -05:00
return Core.input.mouseY();
2018-07-12 20:37:14 -04:00
}
public void buildPlacementUI(Table table){
}
public void buildUI(Group group){
2018-05-29 00:15:24 -04:00
2018-07-12 20:37:14 -04:00
}
2018-05-29 00:15:24 -04:00
2019-09-21 15:35:59 -04:00
public void updateState(){
2018-05-29 00:15:24 -04:00
2018-07-12 20:37:14 -04:00
}
2019-10-06 23:03:02 -04:00
public void drawBottom(){
2018-07-12 20:37:14 -04:00
}
public void drawTop(){
}
2019-10-07 17:17:01 -04:00
public void drawSelected(int x, int y, Block block, Color color){
2019-10-07 19:51:52 -04:00
Draw.color(color);
2019-10-07 17:17:01 -04:00
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();
}
2019-10-06 23:03:02 -04:00
public void drawBreaking(BuildRequest request){
if(request.breaking){
drawBreaking(request.x, request.y);
}else{
2019-10-18 17:18:29 -04:00
drawSelected(request.x, request.y, request.block, Pal.remove);
2019-10-06 23:03:02 -04:00
}
}
2019-10-22 20:17:43 -04:00
public boolean requestMatches(BuildRequest request){
Tile tile = world.tile(request.x, request.y);
2019-12-08 18:34:23 -05:00
return tile != null && tile.block() instanceof BuildBlock && tile.<BuildEntity>ent().cblock == request.block;
2019-10-22 20:17:43 -04:00
}
2019-10-06 23:03:02 -04:00
public void drawBreaking(int x, int y){
Tile tile = world.ltile(x, y);
if(tile == null) return;
Block block = tile.block();
2019-10-07 17:17:01 -04:00
drawSelected(x, y, block, Pal.remove);
}
2019-10-18 00:41:30 -04:00
public void useSchematic(Schematic schem){
selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y)));
}
protected void showSchematicSave(){
if(lastSchematic == null) return;
ui.showTextInput("$schematic.add", "$name", "", text -> {
Schematic replacement = schematics.all().find(s -> s.name().equals(text));
if(replacement != null){
ui.showConfirm("$confirm", "$schematic.replace", () -> {
schematics.overwrite(replacement, lastSchematic);
ui.showInfoFade("$schematic.saved");
ui.schematics.showInfo(replacement);
});
}else{
lastSchematic.tags.put("name", text);
schematics.add(lastSchematic);
ui.showInfoFade("$schematic.saved");
ui.schematics.showInfo(lastSchematic);
}
});
}
2019-10-18 11:38:00 -04:00
public void rotateRequests(Array<BuildRequest> requests, int direction){
int ox = schemOriginX(), oy = schemOriginY();
2019-10-18 11:38:00 -04:00
requests.each(req -> {
2019-10-18 14:38:43 -04:00
//rotate config position
if(req.block.posConfig){
int cx = Pos.x(req.config) - req.originalX, cy = Pos.y(req.config) - req.originalY;
int lx = cx;
if(direction >= 0){
cx = -cy;
cy = lx;
}else{
cx = cy;
cy = -lx;
}
req.config = Pos.get(cx + req.originalX, cy + req.originalY);
}
//rotate actual request, centered on its multiblock position
2019-10-18 11:38:00 -04:00
float wx = (req.x - ox) * tilesize + req.block.offset(), wy = (req.y - oy) * tilesize + req.block.offset();
float x = wx;
if(direction >= 0){
wx = -wy;
wy = x;
}else{
wx = wy;
wy = -x;
}
req.x = world.toTile(wx - req.block.offset()) + ox;
req.y = world.toTile(wy - req.block.offset()) + oy;
2019-10-18 14:38:43 -04:00
req.rotation = Mathf.mod(req.rotation + direction, 4);
});
}
public void flipRequests(Array<BuildRequest> requests, boolean x){
int origin = (x ? schemOriginX() : schemOriginY()) * tilesize;
2019-10-18 14:38:43 -04:00
requests.each(req -> {
float value = -((x ? req.x : req.y) * tilesize - origin + req.block.offset()) + origin;
2019-10-18 14:38:43 -04:00
if(x){
req.x = (int)((value - req.block.offset()) / tilesize);
2019-10-18 14:38:43 -04:00
}else{
req.y = (int)((value - req.block.offset()) / tilesize);
2019-10-18 14:38:43 -04:00
}
if(req.block.posConfig){
int corigin = x ? req.originalWidth/2 : req.originalHeight/2;
int nvalue = -((x ? Pos.x(req.config) : Pos.y(req.config)) - corigin) + corigin;
if(x){
req.originalX = -(req.originalX - corigin) + corigin;
req.config = Pos.get(nvalue, Pos.y(req.config));
}else{
req.originalY = -(req.originalY - corigin) + corigin;
req.config = Pos.get(Pos.x(req.config), nvalue);
}
}
//flip rotation
if(x == (req.rotation % 2 == 0)){
req.rotation = Mathf.mod(req.rotation + 2, 4);
}
2019-10-18 11:38:00 -04:00
});
}
protected int schemOriginX(){
return rawTileX();
}
protected int schemOriginY(){
return rawTileY();
}
2019-10-07 19:51:52 -04:00
/** 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;
2019-10-29 15:57:25 -04:00
Boolf<BuildRequest> test = req -> {
2019-10-07 19:51:52 -04:00
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()){
2019-10-29 15:57:25 -04:00
if(test.get(req)) return req;
2019-10-07 19:51:52 -04:00
}
for(BuildRequest req : selectRequests){
2019-10-29 15:57:25 -04:00
if(test.get(req)) return req;
2019-10-07 19:51:52 -04:00
}
return null;
}
2019-10-18 14:38:43 -04:00
protected void drawBreakSelection(int x1, int y1, int x2, int y2){
2019-11-02 14:09:16 -04:00
NormalizeDrawResult result = Placement.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
NormalizeResult dresult = Placement.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
2019-10-07 17:17:01 -04:00
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);
2019-10-06 23:03:02 -04:00
Draw.color(Pal.remove);
2019-10-07 17:17:01 -04:00
Lines.stroke(1f);
for(BuildRequest req : player.buildQueue()){
if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req);
}
2019-10-06 23:03:02 -04:00
}
2019-10-07 17:17:01 -04:00
2019-10-10 22:13:45 -04:00
for(BuildRequest req : selectRequests){
if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req);
}
2019-11-02 10:45:23 -04:00
}
2019-10-10 22:13:45 -04:00
2019-12-26 20:08:53 -05:00
for(BrokenBlock req : player.getTeam().data().brokenBlocks){
2019-10-07 17:17:01 -04:00
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);
2019-10-06 23:03:02 -04:00
}
2019-10-18 14:38:43 -04:00
protected void drawSelection(int x1, int y1, int x2, int y2, int maxLength){
2019-11-02 14:09:16 -04:00
NormalizeDrawResult result = Placement.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
2019-10-18 14:38:43 -04:00
Lines.stroke(2f);
Draw.color(Pal.accentBack);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.accent);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}
2019-10-07 20:52:50 -04:00
protected void flushSelectRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
2019-11-02 10:45:23 -04:00
BuildRequest other = getRequest(req.x, req.y, req.block.size, null);
if(other == null){
selectRequests.add(req.copy());
}else if(!other.breaking && other.x == req.x && other.y == req.y && other.block.size == req.block.size){
2019-10-25 12:58:07 -04:00
selectRequests.remove(other);
2019-11-02 10:45:23 -04:00
selectRequests.add(req.copy());
2019-10-25 12:58:07 -04:00
}
2019-10-07 20:52:50 -04:00
}
}
}
protected void flushRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
2019-10-18 00:41:30 -04:00
BuildRequest copy = req.copy();
if(copy.hasConfig && copy.block.posConfig){
copy.config = Pos.get(Pos.x(copy.config) + copy.x - copy.originalX, Pos.y(copy.config) + copy.y - copy.originalY);
}
player.addBuildRequest(copy);
}
}
}
protected void drawRequest(BuildRequest request){
2019-11-17 11:20:36 -05:00
request.block.drawRequest(request, allRequests(), validPlace(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);
2019-10-12 12:52:50 -04:00
brequest.animScale = 1f;
block.drawRequest(brequest, allRequests(), validPlace(x, y, block, rotation));
}
2019-10-07 17:17:01 -04:00
/** Remove everything from the queue in a selection. */
protected void removeSelection(int x1, int y1, int x2, int y2){
2019-10-08 19:01:04 -04:00
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){
2019-11-02 14:09:16 -04:00
NormalizeResult result = Placement.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
2019-10-07 17:17:01 -04:00
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);
2019-10-10 22:13:45 -04:00
Tile tile = world.ltile(wx, wy);
if(tile == null) continue;
2019-10-08 19:01:04 -04:00
if(!flush){
tryBreakBlock(wx, wy);
2019-10-10 22:13:45 -04:00
}else if(validBreak(tile.x, tile.y) && !selectRequests.contains(r -> r.tile() != null && r.tile().link() == tile)){
selectRequests.add(new BuildRequest(tile.x, tile.y));
2019-10-08 19:01:04 -04:00
}
2019-10-07 17:17:01 -04:00
}
}
//remove build requests
Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize);
2019-10-10 22:13:45 -04:00
2019-10-07 17:17:01 -04:00
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();
}
}
2019-10-10 22:13:45 -04:00
it = selectRequests.iterator();
while(it.hasNext()){
BuildRequest req = it.next();
if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){
it.remove();
}
2019-11-02 10:45:23 -04:00
}
2019-10-10 22:13:45 -04:00
2019-10-07 17:17:01 -04:00
//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();
}
}
}
2019-10-07 20:52:50 -04:00
protected void updateLine(int x1, int y1, int x2, int y2){
lineRequests.clear();
2019-10-07 20:52:50 -04:00
iterateLine(x1, y1, x2, y2, l -> {
rotation = l.rotation;
2019-10-12 12:52:50 -04:00
BuildRequest req = new BuildRequest(l.x, l.y, l.rotation, block);
req.animScale = 1f;
lineRequests.add(req);
});
2019-11-01 17:30:09 -04:00
2019-11-02 14:09:16 -04:00
if(Core.settings.getBool("blockreplace")){
lineRequests.each(req -> {
Block replace = req.block.getReplacement(req, lineRequests);
if(replace.unlockedCur()){
req.block = replace;
}
});
}
}
2019-10-07 20:52:50 -04:00
protected void updateLine(int x1, int y1){
updateLine(x1, y1, tileX(getMouseX()), tileY(getMouseY()));
}
2019-04-08 09:03:18 -04:00
/** Handles tile tap events that are not platform specific. */
2018-07-12 20:37:14 -04:00
boolean tileTapped(Tile tile){
2019-05-05 19:05:46 -04:00
tile = tile.link();
2018-07-12 20:37:14 -04:00
2019-01-18 15:41:49 -05:00
boolean consumed = false, showedInventory = false;
2018-07-12 20:37:14 -04:00
//check if tapped block is configurable
2019-02-15 12:32:01 -05:00
if(tile.block().configurable && tile.interactable(player.getTeam())){
2018-07-12 20:37:14 -04:00
consumed = true;
if(((!frag.config.isShown() && tile.block().shouldShowConfigure(tile, player)) //if the config fragment is hidden, show
2019-04-08 09:03:18 -04:00
//alternatively, the current selected block can 'agree' to switch config tiles
|| (frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)))){
2019-08-12 23:29:24 -04:00
Sounds.click.at(tile);
2018-07-12 20:37:14 -04:00
frag.config.showConfig(tile);
}
//otherwise...
}else if(!frag.config.hasConfigMouse()){ //make sure a configuration fragment isn't on the cursor
//then, if it's shown and the current block 'agrees' to hide, hide it.
if(frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)){
consumed = true;
frag.config.hideConfig();
}
2018-10-15 02:05:25 -03:00
if(frag.config.isShown()){
consumed = true;
}
2018-07-12 20:37:14 -04:00
}
//call tapped event
2019-02-15 12:32:01 -05:00
if(!consumed && tile.interactable(player.getTeam())){
2018-07-26 15:24:48 -04:00
Call.onTileTapped(player, tile);
2018-07-12 20:37:14 -04:00
}
2018-07-12 20:37:14 -04:00
//consume tap event if necessary
2019-02-15 12:32:01 -05:00
if(tile.interactable(player.getTeam()) && tile.block().consumesTap){
2018-07-12 20:37:14 -04:00
consumed = true;
2019-02-15 12:32:01 -05:00
}else if(tile.interactable(player.getTeam()) && tile.block().synthetic() && !consumed){
2018-07-12 20:37:14 -04:00
if(tile.block().hasItems && tile.entity.items.total() > 0){
frag.inv.showFor(tile);
consumed = true;
showedInventory = true;
}
}
2018-06-02 21:45:07 -04:00
2018-07-12 20:37:14 -04:00
if(!showedInventory){
frag.inv.hide();
}
2018-07-12 20:37:14 -04:00
return consumed;
}
2019-04-08 09:03:18 -04:00
/** Tries to select the player to drop off items, returns true if successful. */
2018-07-12 20:37:14 -04:00
boolean tryTapPlayer(float x, float y){
if(canTapPlayer(x, y)){
droppingItem = true;
return true;
}
return false;
}
boolean canTapPlayer(float x, float y){
return Mathf.dst(x, y, player.x, player.y) <= playerSelectRange && player.item().amount > 0;
2018-07-12 20:37:14 -04:00
}
2019-04-08 09:03:18 -04:00
/** Tries to begin mining a tile, returns true if successful. */
2018-07-12 20:37:14 -04:00
boolean tryBeginMine(Tile tile){
if(canMine(tile)){
//if a block is clicked twice, reset it
player.setMineTile(player.getMineTile() == tile ? null : tile);
return true;
}
return false;
}
boolean canMine(Tile tile){
2018-12-22 22:17:28 -05:00
return !Core.scene.hasMouse()
2019-04-08 09:03:18 -04:00
&& tile.drop() != null && tile.drop().hardness <= player.mech.drillPower
2019-04-12 23:03:34 -04:00
&& !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null)
2019-04-08 09:03:18 -04:00
&& player.acceptsItem(tile.drop())
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= Player.mineDistance;
2018-07-12 20:37:14 -04:00
}
2019-04-08 09:03:18 -04:00
/** Returns the tile at the specified MOUSE coordinates. */
2018-07-12 20:37:14 -04:00
Tile tileAt(float x, float y){
return world.tile(tileX(x), tileY(y));
}
2019-10-18 14:38:43 -04:00
int rawTileX(){
return world.toTile(Core.input.mouseWorld().x);
}
int rawTileY(){
return world.toTile(Core.input.mouseWorld().y);
}
int tileX(float cursorX){
2019-12-25 11:16:54 -05:00
Vec2 vec = Core.input.mouseWorld(cursorX, 0);
if(selectedBlock()){
2019-01-20 13:49:53 -05:00
vec.sub(block.offset(), block.offset());
}
return world.toTile(vec.x);
}
int tileY(float cursorY){
2019-12-25 11:16:54 -05:00
Vec2 vec = Core.input.mouseWorld(0, cursorY);
if(selectedBlock()){
2019-01-20 13:49:53 -05:00
vec.sub(block.offset(), block.offset());
2018-07-12 20:37:14 -04:00
}
return world.toTile(vec.y);
2018-07-12 20:37:14 -04:00
}
public boolean selectedBlock(){
return isPlacing();
}
2018-07-12 20:37:14 -04:00
public boolean isPlacing(){
2019-01-20 13:49:53 -05:00
return block != null;
2018-07-12 20:37:14 -04:00
}
public boolean isBreaking(){
return false;
}
2018-07-12 20:37:14 -04:00
public float mouseAngle(float x, float y){
2018-12-22 22:17:28 -05:00
return Core.input.mouseWorld(getMouseX(), getMouseY()).sub(x, y).angle();
2018-05-13 20:48:44 -07:00
}
2018-07-12 20:37:14 -04:00
public void remove(){
2018-12-21 21:33:05 -05:00
Core.input.removeProcessor(this);
2018-07-12 20:37:14 -04:00
frag.remove();
2019-09-21 15:54:34 -04:00
if(Core.scene != null){
Table table = (Table)Core.scene.find("inputTable");
if(table != null){
table.clear();
}
}
if(detector != null){
Core.input.removeProcessor(detector);
}
if(uiGroup != null){
uiGroup.remove();
uiGroup = null;
}
2018-07-12 20:37:14 -04:00
}
2019-09-21 15:35:59 -04:00
public void add(){
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
2019-09-21 15:35:59 -04:00
Core.input.addProcessor(this);
2019-09-21 15:54:34 -04:00
if(Core.scene != null){
Table table = (Table)Core.scene.find("inputTable");
if(table != null){
table.clear();
buildPlacementUI(table);
2019-09-21 15:54:34 -04:00
}
uiGroup = new WidgetGroup();
uiGroup.touchable(Touchable.childrenOnly);
uiGroup.setFillParent(true);
ui.hudGroup.addChild(uiGroup);
buildUI(uiGroup);
frag.add();
2019-09-21 15:54:34 -04:00
}
2019-10-07 20:26:08 -04:00
if(player != null){
player.isBuilding = true;
}
2019-09-21 15:35:59 -04:00
}
2018-07-12 20:37:14 -04:00
public boolean canShoot(){
2019-01-20 13:49:53 -05:00
return block == null && !Core.scene.hasMouse() && !onConfigurable() && !isDroppingItem();
2018-07-12 20:37:14 -04:00
}
public boolean onConfigurable(){
return false;
}
public boolean isDroppingItem(){
return droppingItem;
}
public void tryDropItems(Tile tile, float x, float y){
2019-09-01 15:52:07 -04:00
if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() || !player.timer.check(Player.timerTransfer, 40)){
2018-07-12 20:37:14 -04:00
droppingItem = false;
return;
}
droppingItem = false;
ItemStack stack = player.item();
2018-07-12 20:37:14 -04:00
2019-09-10 20:53:31 -04:00
if(tile.block().acceptStack(stack.item, stack.amount, tile, player) > 0 && tile.interactable(player.getTeam()) && tile.block().hasItems && player.item().amount > 0 && !player.isTransferring && tile.interactable(player.getTeam())){
2018-07-26 15:24:48 -04:00
Call.transferInventory(player, tile);
2018-07-12 20:37:14 -04:00
}else{
2018-07-26 15:24:48 -04:00
Call.dropItem(player.angleTo(x, y));
2018-07-12 20:37:14 -04:00
}
}
public void tryPlaceBlock(int x, int y){
2019-03-24 19:58:51 -04:00
if(block != null && validPlace(x, y, block, rotation)){
2019-01-20 13:49:53 -05:00
placeBlock(x, y, block, rotation);
2018-07-12 20:37:14 -04:00
}
}
public void tryBreakBlock(int x, int y){
2019-03-24 19:58:51 -04:00
if(validBreak(x, y)){
2018-07-12 20:37:14 -04:00
breakBlock(x, y);
}
}
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))
2019-11-02 09:40:41 -04:00
&& !(type.canReplace(req.block) && Tmp.r1.equals(Tmp.r2))){
return false;
}
}
2019-03-24 19:58:51 -04:00
return Build.validPlace(player.getTeam(), x, y, type, rotation);
2018-07-12 20:37:14 -04:00
}
public boolean validBreak(int x, int y){
2019-07-14 12:54:24 -04:00
return Build.validBreak(player.getTeam(), x, y);
2018-07-12 20:37:14 -04:00
}
2019-01-20 13:49:53 -05:00
public void placeBlock(int x, int y, Block block, int rotation){
BuildRequest req = getRequest(x, y);
if(req != null){
player.buildQueue().remove(req);
}
2019-01-20 13:49:53 -05:00
player.addBuildRequest(new BuildRequest(x, y, rotation, block));
2018-07-12 20:37:14 -04:00
}
public void breakBlock(int x, int y){
2019-05-05 19:05:46 -04:00
Tile tile = world.ltile(x, y);
2018-07-12 20:37:14 -04:00
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
}
public void drawArrow(Block block, int x, int y, int rotation){
drawArrow(block, x, y, rotation, validPlace(x, y, block, rotation));
}
public void drawArrow(Block block, int x, int y, int rotation, boolean valid){
Draw.color(!valid ? Pal.removeBack : Pal.accentBack);
2019-03-19 15:26:30 -04:00
Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + block.offset(),
y * tilesize + block.offset() - 1,
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
Draw.color(!valid ? Pal.remove : Pal.accent);
2019-03-19 15:26:30 -04:00
Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + block.offset(),
y * tilesize + block.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
}
2019-10-29 15:57:25 -04:00
void iterateLine(int startX, int startY, int endX, int endY, Cons<PlaceLine> cons){
2019-03-19 15:26:30 -04:00
Array<Point2> points;
boolean diagonal = Core.input.keyDown(Binding.diagonal_placement);
2019-11-02 10:49:21 -04:00
if(Core.settings.getBool("swapdiagonal") && mobile){
2019-03-19 15:26:30 -04:00
diagonal = !diagonal;
}
if(block instanceof PowerNode){
diagonal = !diagonal;
}
2019-03-19 15:26:30 -04:00
if(diagonal){
2019-11-02 14:09:16 -04:00
points = Placement.pathfindLine(block != null && block.conveyorPlacement, startX, startY, endX, endY);
2019-03-19 15:26:30 -04:00
}else{
2019-11-02 14:09:16 -04:00
points = Placement.normalizeLine(startX, startY, endX, endY);
2019-03-19 15:26:30 -04:00
}
if(block instanceof PowerNode){
Array<Point2> skip = new Array<>();
for(int i = 1; i < points.size; i++){
int overlaps = 0;
2019-11-08 13:04:24 -05:00
Point2 point = points.get(i);
2019-11-08 13:04:24 -05:00
//check with how many powernodes the *next* tile will overlap
for(int j = 0; j < i; j++){
if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.ltile(point.x, point.y), world.ltile(points.get(j).x, points.get(j).y))){
overlaps++;
}
}
2019-11-08 13:04:24 -05:00
//if it's more than one, it can bridge the gap
if(overlaps > 1){
skip.add(points.get(i-1));
}
}
2019-11-08 13:04:24 -05:00
//remove skipped points
points.removeAll(skip);
}
2019-03-19 15:26:30 -04:00
float angle = Angles.angle(startX, startY, endX, endY);
int baseRotation = rotation;
2019-10-06 17:30:11 -04:00
if(!overrideLineRotation || diagonal){
2019-10-06 23:03:02 -04:00
baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4;
}
2019-03-19 15:26:30 -04:00
Tmp.r3.set(-1, -1, 0, 0);
2019-03-19 15:26:30 -04:00
for(int i = 0; i < points.size; i++){
Point2 point = points.get(i);
2019-04-08 09:03:18 -04:00
if(block != null && Tmp.r2.setSize(block.size * tilesize).setCenter(point.x * tilesize + block.offset(), point.y * tilesize + block.offset()).overlaps(Tmp.r3)){
continue;
}
2019-03-19 15:26:30 -04:00
Point2 next = i == points.size - 1 ? null : points.get(i + 1);
line.x = point.x;
line.y = point.y;
2019-10-06 17:30:11 -04:00
if(!overrideLineRotation || diagonal){
line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation;
}else{
line.rotation = rotation;
}
2019-03-19 15:26:30 -04:00
line.last = next == null;
2019-10-29 15:57:25 -04:00
cons.get(line);
2019-04-08 09:03:18 -04:00
Tmp.r3.setSize(block.size * tilesize).setCenter(point.x * tilesize + block.offset(), point.y * tilesize + block.offset());
2019-03-19 15:26:30 -04:00
}
}
class PlaceLine{
public int x, y, rotation;
public boolean last;
2019-03-19 11:46:00 -04:00
}
}