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

1156 lines
40 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 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.struct.*;
2019-12-25 01:39:38 -05:00
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
2019-12-25 01:39:38 -05:00
import mindustry.content.*;
import mindustry.entities.*;
2020-02-02 23:38:16 -05:00
import mindustry.entities.units.*;
2019-12-25 01:39:38 -05:00
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.input.Placement.*;
import mindustry.net.Administration.*;
2020-02-05 22:08:57 -05:00
import mindustry.net.*;
2019-12-25 01:39:38 -05:00
import mindustry.type.*;
import mindustry.ui.fragments.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import mindustry.world.blocks.power.*;
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();
2020-05-02 21:34:37 -04:00
final static Array<Unitc> units = new Array<>();
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
2020-05-10 09:14:13 -04:00
public @Nullable Block block;
public boolean overrideLineRotation;
2018-07-12 20:37:14 -04:00
public int rotation;
public boolean droppingItem;
public Group uiGroup;
2020-05-20 18:48:04 -04:00
public boolean isShooting, isBuilding = true, buildWasAutoPaused = false, isBoosting = false;
2020-05-10 09:14:13 -04:00
public @Nullable UnitType controlledType;
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
2020-02-05 13:03:22 -05:00
@Remote(called = Loc.server, unreliable = true)
2020-02-05 18:28:19 -05:00
public static void transferItemEffect(Item item, float x, float y, Itemsc to){
2020-02-05 13:03:22 -05:00
if(to == null) return;
2020-03-22 09:28:55 -04:00
createItemTransfer(item, 1, x, y, to, null);
2020-02-05 13:03:22 -05:00
}
@Remote(called = Loc.server, unreliable = true)
2020-02-05 18:28:19 -05:00
public static void transferItemToUnit(Item item, float x, float y, Itemsc to){
2020-02-05 13:03:22 -05:00
if(to == null) return;
2020-03-22 09:28:55 -04:00
createItemTransfer(item, 1, x, y, to, () -> to.addItem(item));
2020-02-05 13:03:22 -05:00
}
@Remote(called = Loc.server, unreliable = true)
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
if(tile == null || tile.entity == null || tile.entity.items() == null) return;
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
2020-03-22 09:28:55 -04:00
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, tile, () -> {}));
2020-02-05 13:03:22 -05:00
}
tile.entity.items().add(item, amount);
}
2020-03-22 09:28:55 -04:00
public static void createItemTransfer(Item item, int amount, float x, float y, Position to, Runnable done){
Fx.itemTransfer.at(x, y, amount, item.color, to);
2020-02-05 13:03:22 -05:00
if(done != null){
Time.run(Fx.itemTransfer.lifetime, done);
}
}
@Remote(variants = Variant.one)
public static void removeQueueBlock(int x, int y, boolean breaking){
2020-02-05 20:11:49 -05:00
player.builder().removeBuild(x, y, breaking);
}
2018-07-26 15:24:48 -04:00
@Remote(targets = Loc.client, called = Loc.server)
2020-02-04 18:00:32 -05:00
public static void dropItem(Playerc player, float angle){
2020-02-05 20:11:49 -05:00
if(net.server() && player.unit().stack().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
2020-02-05 20:11:49 -05:00
Fx.dropItem.at(player.x(), player.y(), angle, Color.white, player.unit().item());
player.unit().clearItem();
2018-05-11 07:59:10 -07:00
}
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
2020-03-05 18:05:59 -05:00
public static void rotateBlock(Playerc player, Tilec tile, boolean direction){
if(net.server() && (!Units.canInteract(player, tile) ||
2020-03-06 15:22:13 -05:00
!netServer.admins.allowAction(player, ActionType.rotate, tile.tile(), action -> action.rotation = Mathf.mod(tile.rotation() + Mathf.sign(direction), 4)))){
throw new ValidateException(player, "Player cannot rotate a block.");
}
tile.rotation(Mathf.mod(tile.rotation() + Mathf.sign(direction), 4));
2020-03-05 18:05:59 -05:00
tile.updateProximity();
tile.noSleep();
}
2018-07-26 15:24:48 -04:00
@Remote(targets = Loc.both, forward = true, called = Loc.server)
2020-03-05 18:05:59 -05:00
public static void transferInventory(Playerc player, Tilec tile){
2020-03-06 15:22:13 -05:00
if(player == null || tile == null) return;
2020-02-05 20:11:49 -05:00
if(net.server() && (player.unit().stack().amount <= 0 || !Units.canInteract(player, tile) ||
2020-03-06 15:22:13 -05:00
!netServer.admins.allowAction(player, ActionType.depositItem, tile.tile(), action -> {
2020-02-05 20:11:49 -05:00
action.itemAmount = player.unit().stack().amount;
action.item = player.unit().item();
}))){
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
2020-02-05 20:11:49 -05:00
Item item = player.unit().item();
int amount = player.unit().stack().amount;
2020-03-06 14:55:06 -05:00
int accepted = tile.acceptStack(item, amount, player.unit());
2020-02-05 20:11:49 -05:00
player.unit().stack().amount -= accepted;
2018-05-29 00:15:24 -04:00
Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted)));
2019-08-08 21:26:50 -04:00
2020-03-22 09:28:55 -04:00
tile.getStackOffset(item, stackTrns);
2018-07-12 20:37:14 -04:00
2020-03-22 09:28:55 -04:00
createItemTransfer(
item,
amount,
player.x() + Angles.trnsx(player.unit().rotation() + 180f, backTrns), player.y() + Angles.trnsy(player.unit().rotation() + 180f, backTrns),
new Vec2(tile.x() + stackTrns.x, tile.y() + stackTrns.y),
() -> tile.handleStack(item, accepted, player.unit())
);
2018-05-29 00:15:24 -04:00
}
2020-03-04 19:58:48 -05:00
@Remote(targets = Loc.both, called = Loc.server, forward = true)
2020-03-05 18:05:59 -05:00
public static void onTileTapped(Playerc player, Tilec tile){
2020-03-04 19:58:48 -05:00
if(tile == null || player == null) return;
if(net.server() && (!Units.canInteract(player, tile) ||
2020-03-06 15:22:13 -05:00
!netServer.admins.allowAction(player, ActionType.tapTile, tile.tile(), action -> {}))) throw new ValidateException(player, "Player cannot tap a tile.");
2020-03-06 14:55:06 -05:00
tile.tapped(player);
2020-03-04 19:58:48 -05:00
Core.app.post(() -> Events.fire(new TapEvent(tile, player)));
}
2019-09-30 19:40:08 -04:00
@Remote(targets = Loc.both, called = Loc.both, forward = true)
2020-03-05 18:05:59 -05:00
public static void onTileConfig(Playerc player, Tilec tile, @Nullable Object value){
if(tile == null) return;
if(net.server() && (!Units.canInteract(player, tile) ||
2020-03-06 15:22:13 -05:00
!netServer.admins.allowAction(player, ActionType.configure, tile.tile(), action -> action.config = value))) throw new ValidateException(player, "Player cannot configure a tile.");
2020-03-06 14:55:06 -05:00
tile.configured(player, value);
Core.app.post(() -> Events.fire(new TapConfigEvent(tile, player, value)));
2019-09-30 10:57:48 -04:00
}
@Remote(targets = Loc.both, called = Loc.server, forward = true)
public static void onUnitControl(Playerc player, @Nullable Unitc unit){
if(unit == null){
player.clearUnit();
//make sure it's AI controlled, so players can't overwrite each other
}else if(unit.isAI() && unit.team() == player.team()){
2020-04-27 01:31:41 -04:00
player.unit(unit);
2020-04-11 11:34:51 -04:00
Time.run(Fx.unitSpirit.lifetime, () -> Fx.unitControl.at(unit.x(), unit.y(), 0f, unit));
if(!player.dead()){
Fx.unitSpirit.at(player.x(), player.y(), 0f, unit);
}
}
}
public Eachable<BuildRequest> allRequests(){
return cons -> {
2020-02-05 20:11:49 -05:00
for(BuildRequest request : player.builder().requests()) cons.get(request);
2019-10-29 15:57:25 -04:00
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(){
2020-02-04 18:00:32 -05:00
player.typing(ui.chatfrag.shown());
2020-04-27 01:31:41 -04:00
if(player.isBuilder()){
player.builder().building(isBuilding);
}
2020-04-27 01:31:41 -04:00
if(!player.dead()){
controlledType = player.unit().type();
}
if(controlledType != null && player.dead()){
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
if(unit != null){
Call.onUnitControl(player, unit);
}
}
}
public void checkUnit(){
if(controlledType != null){
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
if(unit != null){
if(net.client()){
Call.onUnitControl(player, unit);
}else{
unit.controller(player);
}
}
}
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){
2020-04-16 09:55:57 -04:00
Drawf.selected(x, y, block, color);
2019-10-07 17:17:01 -04:00
}
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){
2020-03-05 18:05:59 -05:00
Tile tile = world.tile(x, y);
2019-10-06 23:03:02 -04:00
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){
2020-02-05 20:11:49 -05:00
selectRequests.addAll(schematics.toRequests(schem, player.tileX(), player.tileY()));
2019-10-18 00:41:30 -04:00
}
protected void showSchematicSave(){
if(lastSchematic == null) return;
ui.showTextInput("$schematic.add", "$name", "", text -> {
2020-03-09 09:41:39 -04:00
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 -> {
2020-03-04 13:32:31 -05:00
req.pointConfig(p -> {
2020-03-04 19:21:40 -05:00
int cx = p.x, cy = p.y;
2019-10-18 14:38:43 -04:00
int lx = cx;
if(direction >= 0){
cx = -cy;
cy = lx;
}else{
cx = cy;
cy = -lx;
}
2020-03-04 19:21:40 -05:00
p.set(cx, cy);
2020-03-04 13:32:31 -05:00
});
2019-10-18 14:38:43 -04:00
//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
}
2020-03-04 13:32:31 -05:00
req.pointConfig(p -> {
2019-10-18 14:38:43 -04:00
int corigin = x ? req.originalWidth/2 : req.originalHeight/2;
2020-03-04 19:21:40 -05:00
int nvalue = -(x ? p.x : p.y);
2019-10-18 14:38:43 -04:00
if(x){
req.originalX = -(req.originalX - corigin) + corigin;
2020-03-04 13:32:31 -05:00
p.x = nvalue;
2019-10-18 14:38:43 -04:00
}else{
req.originalY = -(req.originalY - corigin) + corigin;
2020-03-04 13:32:31 -05:00
p.y = nvalue;
2019-10-18 14:38:43 -04:00
}
2020-03-04 13:32:31 -05:00
});
2019-10-18 14:38:43 -04:00
//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);
};
2020-02-05 20:11:49 -05:00
for(BuildRequest req : player.builder().requests()){
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++){
2020-03-05 18:05:59 -05:00
Tile tile = world.tilec(x, y);
2019-10-07 17:17:01 -04:00
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);
2020-02-05 20:11:49 -05:00
for(BuildRequest req : player.builder().requests()){
2019-10-07 17:17:01 -04:00
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
for(BrokenBlock req : player.team().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();
2020-02-05 20:11:49 -05:00
player.builder().addBuild(copy);
}
}
}
2020-03-04 19:21:40 -05:00
protected void drawOverRequest(BuildRequest request){
boolean valid = validPlace(request.x, request.y, request.block, request.rotation);
Draw.reset();
Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f));
Draw.alpha(1f);
request.block.drawRequestConfigTop(request, selectRequests);
Draw.reset();
}
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));
2020-05-03 12:08:11 -04:00
if(request.block.saveConfig && request.block.lastConfig != null && !request.hasConfig){
2020-05-03 12:08:11 -04:00
Object conf = request.config;
2020-05-10 09:14:13 -04:00
request.config = request.block.lastConfig;
2020-05-03 12:08:11 -04:00
request.block.drawRequestConfig(request, allRequests());
request.config = conf;
}
}
/** 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);
2020-03-05 18:05:59 -05:00
Tile tile = world.tilec(wx, wy);
2019-10-10 22:13:45 -04:00
if(tile == null) continue;
2019-10-08 19:01:04 -04:00
if(!flush){
tryBreakBlock(wx, wy);
2020-03-05 18:05:59 -05:00
}else if(validBreak(tile.x, tile.y) && !selectRequests.contains(r -> r.tile() != null && r.tile() == tile)){
2019-10-10 22:13:45 -04:00
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
2020-02-05 20:11:49 -05:00
Iterator<BuildRequest> it = player.builder().requests().iterator();
2019-10-07 17:17:01 -04:00
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.team()).brokenBlocks.iterator();
2019-10-07 17:17:01 -04:00
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. */
2020-03-05 18:05:59 -05:00
boolean tileTapped(@Nullable Tilec tile){
2020-03-06 16:07:07 -05:00
if(tile == null){
frag.inv.hide();
frag.config.hideConfig();
2020-03-06 16:07:07 -05:00
return false;
}
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
if(tile.block().configurable && tile.interactable(player.team())){
2018-07-12 20:37:14 -04:00
consumed = true;
2020-03-06 14:55:06 -05:00
if(((!frag.config.isShown() && tile.shouldShowConfigure(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
2020-03-06 15:22:13 -05:00
|| (frag.config.isShown() && frag.config.getSelectedTile().onConfigureTileTapped(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.
2020-03-06 15:22:13 -05:00
if(frag.config.isShown() && frag.config.getSelectedTile().onConfigureTileTapped(tile)){
2018-07-12 20:37:14 -04:00
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
if(!consumed && tile.interactable(player.team())){
2020-03-04 19:58:48 -05: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
if(tile.interactable(player.team()) && tile.block().consumesTap){
2018-07-12 20:37:14 -04:00
consumed = true;
}else if(tile.interactable(player.team()) && tile.block().synthetic() && !consumed){
2020-03-05 18:05:59 -05:00
if(tile.block().hasItems && tile.items().total() > 0){
2018-07-12 20:37:14 -04:00
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){
2020-02-05 22:08:57 -05:00
return player.within(x, y, playerSelectRange) && player.unit().stack().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
2020-02-05 22:08:57 -05:00
player.miner().mineTile(player.miner().mineTile() == tile ? null : tile);
2018-07-12 20:37:14 -04:00
return true;
}
return false;
}
boolean canMine(Tile tile){
2018-12-22 22:17:28 -05:00
return !Core.scene.hasMouse()
2020-02-05 22:08:57 -05:00
&& tile.drop() != null && player.miner().canMine(tile.drop())
2019-04-12 23:03:34 -04:00
&& !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null)
2020-02-05 20:11:49 -05:00
&& player.unit().acceptsItem(tile.drop())
2020-02-05 22:08:57 -05:00
&& tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= miningRange;
2018-07-12 20:37:14 -04:00
}
2020-03-05 18:05:59 -05:00
Tilec entAt(float x, float y){
return world.ent(tileX(x), tileY(y));
}
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
}
2020-04-11 11:34:51 -04:00
public @Nullable Unitc selectedUnit(){
Unitc unit = Units.closest(player.team(), Core.input.mouseWorld().x, Core.input.mouseWorld().y, 40f, Unitc::isAI);
if(unit != null){
unit.hitbox(Tmp.r1);
Tmp.r1.grow(6f);
if(Tmp.r1.contains(Core.input.mouseWorld())){
return unit;
}
}
return null;
}
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(){
2020-01-23 14:40:07 -05:00
Core.input.getInputProcessors().remove(i -> i instanceof InputHandler || (i instanceof GestureDetector && ((GestureDetector)i).getListener() instanceof InputHandler));
2020-01-20 14:13:20 -05:00
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.3f, 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-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;
}
2020-03-05 18:05:59 -05:00
public void tryDropItems(Tilec tile, float x, float y){
2020-02-05 20:11:49 -05:00
if(!droppingItem || player.unit().stack().amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){
2018-07-12 20:37:14 -04:00
droppingItem = false;
return;
}
droppingItem = false;
2020-02-05 20:11:49 -05:00
ItemStack stack = player.unit().stack();
2018-07-12 20:37:14 -04:00
2020-03-06 14:55:06 -05:00
if(tile.acceptStack(stack.item, stack.amount, player.unit()) > 0 && tile.interactable(player.team()) && tile.block().hasItems && player.unit().stack().amount > 0 && tile.interactable(player.team())){
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){
2020-02-05 20:11:49 -05:00
for(BuildRequest req : player.builder().requests()){
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;
}
}
return Build.validPlace(player.team(), x, y, type, rotation);
2018-07-12 20:37:14 -04:00
}
public boolean validBreak(int x, int y){
return Build.validBreak(player.team(), 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){
2020-02-05 20:11:49 -05:00
player.builder().requests().remove(req);
}
2020-02-05 20:11:49 -05:00
player.builder().addBuild(new BuildRequest(x, y, rotation, block));
2018-07-12 20:37:14 -04:00
}
public void breakBlock(int x, int y){
2020-03-05 18:05:59 -05:00
Tile tile = world.tile(x, y);
//TODO hacky
2020-03-31 15:01:22 -04:00
if(tile != null && tile.entity != null) tile = tile.entity.tile();
2020-02-05 20:11:49 -05:00
player.builder().addBuild(new BuildRequest(tile.x, tile.y));
2018-07-12 20:37:14 -04:00
}
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){
2020-04-15 12:44:53 -04:00
float trns = (block.size / 2) * tilesize;
int dx = Geometry.d4(rotation).x, dy = Geometry.d4(rotation).y;
Draw.color(!valid ? Pal.removeBack : Pal.accentBack);
2019-03-19 15:26:30 -04:00
Draw.rect(Core.atlas.find("place-arrow"),
2020-04-15 12:44:53 -04:00
x * tilesize + block.offset() + dx*trns,
y * tilesize + block.offset() - 1 + dy*trns,
2019-03-19 15:26:30 -04:00
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"),
2020-04-15 12:44:53 -04:00
x * tilesize + block.offset() + dx*trns,
y * tilesize + block.offset() + dy*trns,
2019-03-19 15:26:30 -04:00
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++){
2020-03-05 18:05:59 -05:00
if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.tile(point.x, point.y), world.tile(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
}
2020-02-04 18:00:32 -05:00
//TODO implement all of this!
/*
protected void updateKeyboard(){
Tile tile = world.tileWorld(x, y);
boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown();
isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying;
//if player is in solid block
if(tile != null && tile.solid()){
isBoosting = true;
}
float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed;
if(mech.flying){
//prevent strafing backwards, have a penalty for doing so
float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x
speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f);
}
movement.setZero();
float xa = Core.input.axis(Binding.move_x);
float ya = Core.input.axis(Binding.move_y);
if(!(Core.scene.getKeyboardFocus() instanceof TextField)){
movement.y += ya * speed;
movement.x += xa * speed;
}
if(Core.input.keyDown(Binding.mouse_move)){
movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed;
movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed;
}
Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY());
pointerX = vec.x;
pointerY = vec.y;
updateShooting();
movement.limit(speed).scl(Time.delta());
if(canMove){
velocity.add(movement.x, movement.y);
}else{
isShooting = false;
}
float prex = x, prey = y;
updateVelocityStatus();
moved = dst(prex, prey) > 0.001f;
if(canMove){
float baseLerp = mech.getRotationAlpha(this);
if(!isShooting() || !mech.faceTarget){
if(!movement.isZero()){
rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp);
}
}else{
float angle = control.input.mouseAngle(x, y);
this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp);
}
}
}
protected void updateShooting(){
if(!state.isEditor() && isShooting() && mech.canShoot(this)){
weapons.update(this);
//if(!mech.turnCursor){
//shoot forward ignoring cursor
//mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance));
//}else{
//mech.weapon.update(this, pointerX, pointerY);
//}
}
}
protected void updateTouch(){
if(Units.invalidateTarget(target, this) &&
!(target instanceof Tilec && ((Tilec)target).damaged() && target.isValid() && target.team() == team && mech.canHeal && dst(target) < mech.range && !(((Tilec)target).block instanceof BuildBlock))){
target = null;
}
if(state.isEditor()){
target = null;
}
float targetX = Core.camera.position.x, targetY = Core.camera.position.y;
float attractDst = 15f;
float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed;
if(moveTarget != null && !moveTarget.dead()){
targetX = moveTarget.getX();
targetY = moveTarget.getY();
boolean tapping = moveTarget instanceof Tilec && moveTarget.team() == team;
attractDst = 0f;
if(tapping){
velocity.setAngle(angleTo(moveTarget));
}
if(dst(moveTarget) <= 2f * Time.delta()){
if(tapping && !dead()){
Tile tile = ((Tilec)moveTarget).tile;
2020-03-06 14:55:06 -05:00
tile.tapped(this);
2020-02-04 18:00:32 -05:00
}
moveTarget = null;
}
}else{
moveTarget = null;
}
movement.set((targetX - x) / Time.delta(), (targetY - y) / Time.delta()).limit(speed);
movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f));
if(dst(targetX, targetY) < attractDst){
movement.setZero();
}
float expansion = 3f;
hitbox(rect);
rect.x -= expansion;
rect.y -= expansion;
rect.width += expansion * 2f;
rect.height += expansion * 2f;
isBoosting = collisions.overlapsTile(rect) || dst(targetX, targetY) > 85f;
velocity.add(movement.scl(Time.delta()));
if(velocity.len() <= 0.2f && mech.flying){
rotation += Mathf.sin(Time.time() + id * 99, 10f, 1f);
}else if(target == null){
rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len() / 10f);
}
float lx = x, ly = y;
updateVelocityStatus();
moved = dst(lx, ly) > 0.001f;
if(mech.flying){
//hovering effect
x += Mathf.sin(Time.time() + id * 999, 25f, 0.08f);
y += Mathf.cos(Time.time() + id * 999, 25f, 0.08f);
}
//update shooting if not building, not mining and there's ammo left
2020-02-05 22:08:57 -05:00
if(!isBuilding() && mineTile() == null){
2020-02-04 18:00:32 -05:00
//autofire
if(target == null){
isShooting = false;
if(Core.settings.getBool("autotarget")){
2020-02-05 13:03:22 -05:00
target = Units.closestTarget(team, x, y, mech.range, u -> u.team() != Team.derelict, u -> u.team() != Team.derelict);
2020-02-04 18:00:32 -05:00
if(mech.canHeal && target == null){
target = Geometry.findClosest(x, y, indexer.getDamaged(Team.sharded));
if(target != null && dst(target) > mech.range){
target = null;
}else if(target != null){
target = ((Tile)target).entity;
}
}
if(target != null){
2020-02-05 22:08:57 -05:00
mineTile(null);
2020-02-04 18:00:32 -05:00
}
}
}else if(target.isValid() || (target instanceof Tilec && ((Tilec)target).damaged() && target.team() == team && mech.canHeal && dst(target) < mech.range)){
//rotate toward and shoot the target
if(mech.faceTarget){
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);
}
Vec2 intercept = Predict.intercept(this, target, getWeapon().bullet.speed);
pointerX = intercept.x;
pointerY = intercept.y;
updateShooting();
isShooting = true;
}
}
}
*/
}