2019-12-25 01:39:38 -05:00
package mindustry.input ;
2017-12-13 23:28:20 -05:00
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.* ;
2020-01-14 10:32:52 -05:00
import arc.struct.* ;
2019-12-25 01:39:38 -05:00
import arc.util.ArcAnnotate.* ;
import arc.util.* ;
2020-01-14 10:32:52 -05:00
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.* ;
2020-01-14 10:32:52 -05:00
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.* ;
2020-01-14 10:32:52 -05:00
import mindustry.world.blocks.power.* ;
2017-12-13 23:28:20 -05:00
2019-10-07 17:17:01 -04:00
import java.util.* ;
2019-12-25 01:39:38 -05:00
import static mindustry.Vars.* ;
2017-12-31 14:23:13 -05:00
2019-10-06 16:56:31 -04:00
public abstract class InputHandler implements InputProcessor , GestureListener {
2019-04-08 09:03:18 -04:00
/** Used for dropping items. */
2018-06-09 23:23:14 -04:00
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 ( ) ;
2019-12-26 22:44:15 -05:00
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 ;
2019-09-21 15:03:05 -07:00
public boolean overrideLineRotation ;
2018-07-12 20:37:14 -04:00
public int rotation ;
public boolean droppingItem ;
2019-10-06 16:56:31 -04:00
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 ;
2019-10-06 16:56:31 -04:00
protected GestureDetector detector ;
protected PlaceLine line = new PlaceLine ( ) ;
2019-10-07 19:51:52 -04:00
protected BuildRequest resultreq ;
2019-10-06 16:56:31 -04:00
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 ) ;
}
}
2020-01-14 10:32:52 -05:00
@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 ) ;
2020-01-14 10:32:52 -05:00
}
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
}
2019-09-29 19:54:52 -04: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 ) {
2020-01-14 10:32:52 -05:00
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 ) ) ) ) {
2020-01-14 10:32:52 -05:00
throw new ValidateException ( player , " Player cannot rotate a block. " ) ;
2019-09-29 19:54:52 -04:00
}
tile . rotation ( Mathf . mod ( tile . rotation ( ) + Mathf . sign ( direction ) , 4 ) ) ;
2020-03-05 18:05:59 -05:00
tile . updateProximity ( ) ;
tile . noSleep ( ) ;
2019-09-29 19:54:52 -04:00
}
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 ( ) ;
2020-01-14 10:32:52 -05:00
} ) ) ) {
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
2019-11-10 10:15:52 -05: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 ) {
2020-01-14 10:32:52 -05:00
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 ) ;
2019-11-09 04:58:24 +09:00
Core . app . post ( ( ) - > Events . fire ( new TapConfigEvent ( tile , player , value ) ) ) ;
2019-09-30 10:57:48 -04:00
}
2020-04-11 10:03:47 -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 ) ;
}
2020-04-11 10:03:47 -04:00
}
}
2019-10-06 16:56:31 -04:00
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 ) ;
2019-10-06 16:56:31 -04:00
} ;
}
2018-09-19 22:17:58 -04:00
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
2020-05-15 11:03:21 -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-05-29 22:03:43 -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
}
2018-05-29 22:03:43 -04:00
2019-10-06 16:56:31 -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
}
2018-06-01 13:01:05 -04:00
2019-10-06 23:03:02 -04:00
public void drawBottom ( ) {
2018-05-30 23:51:42 -04:00
2018-07-12 20:37:14 -04:00
}
public void drawTop ( ) {
}
2018-05-30 18:32:01 -04:00
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
}
2019-10-31 22:44:07 -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-31 22:44:07 -04:00
} ) ;
}
2019-10-18 11:38:00 -04:00
public void rotateRequests ( Array < BuildRequest > requests , int direction ) {
2019-10-31 22:44:07 -04:00
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 ) {
2019-10-31 22:44:07 -04:00
int origin = ( x ? schemOriginX ( ) : schemOriginY ( ) ) * tilesize ;
2019-10-18 14:38:43 -04:00
requests . each ( req - > {
2019-10-20 20:39:58 -04:00
float value = - ( ( x ? req . x : req . y ) * tilesize - origin + req . block . offset ( ) ) + origin ;
2019-10-18 14:38:43 -04:00
if ( x ) {
2019-10-20 20:39:58 -04:00
req . x = ( int ) ( ( value - req . block . offset ( ) ) / tilesize ) ;
2019-10-18 14:38:43 -04:00
} else {
2019-10-20 20:39:58 -04:00
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
} ) ;
}
2019-10-31 22:44:07 -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
2020-02-04 12:14:09 -05: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
}
}
}
2019-10-06 16:56:31 -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 ) ;
2019-10-06 16:56:31 -04:00
}
}
}
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 ( ) ;
}
2019-10-06 16:56:31 -04:00
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
2020-05-12 09:34:26 -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 ;
}
2019-10-06 16:56:31 -04:00
}
/** 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 ;
2019-10-06 16:56:31 -04:00
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
2020-02-04 12:14:09 -05:00
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 ) {
2019-10-06 16:56:31 -04:00
lineRequests . clear ( ) ;
2019-10-07 20:52:50 -04:00
iterateLine ( x1 , y1 , x2 , y2 , l - > {
2019-10-06 16:56:31 -04:00
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-10-06 16:56:31 -04:00
} ) ;
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-06 16:56:31 -04:00
}
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 ( ) ;
2020-03-17 11:51:33 -04:00
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
2020-02-04 12:14:09 -05:00
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
2020-02-04 12:14:09 -05:00
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-06-09 23:23:14 -04:00
2018-07-12 20:37:14 -04:00
//consume tap event if necessary
2020-02-04 12:14:09 -05:00
if ( tile . interactable ( player . team ( ) ) & & tile . block ( ) . consumesTap ) {
2018-07-12 20:37:14 -04:00
consumed = true ;
2020-02-04 12:14:09 -05:00
} 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-05-30 23:51:42 -04:00
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 ) {
2018-10-13 17:47:58 -04:00
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 ) ;
}
2018-10-13 17:47:58 -04:00
int tileX ( float cursorX ) {
2019-12-25 11:16:54 -05:00
Vec2 vec = Core . input . mouseWorld ( cursorX , 0 ) ;
2018-10-22 22:21:22 -04:00
if ( selectedBlock ( ) ) {
2019-01-20 13:49:53 -05:00
vec . sub ( block . offset ( ) , block . offset ( ) ) ;
2018-10-13 17:47:58 -04:00
}
return world . toTile ( vec . x ) ;
}
int tileY ( float cursorY ) {
2019-12-25 11:16:54 -05:00
Vec2 vec = Core . input . mouseWorld ( 0 , cursorY ) ;
2018-10-22 22:21:22 -04:00
if ( selectedBlock ( ) ) {
2019-01-20 13:49:53 -05:00
vec . sub ( block . offset ( ) , block . offset ( ) ) ;
2018-07-12 20:37:14 -04:00
}
2018-10-13 17:47:58 -04:00
return world . toTile ( vec . y ) ;
2018-07-12 20:37:14 -04:00
}
2018-10-22 22:21:22 -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
}
2019-10-14 23:43:13 -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 ( ) ;
}
}
2019-10-06 16:56:31 -04:00
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 ( ) ;
2019-10-06 16:56:31 -04:00
buildPlacementUI ( table ) ;
2019-09-21 15:54:34 -04:00
}
2019-10-06 16:56:31 -04:00
uiGroup = new WidgetGroup ( ) ;
uiGroup . touchable ( Touchable . childrenOnly ) ;
uiGroup . setFillParent ( true ) ;
ui . hudGroup . addChild ( uiGroup ) ;
buildUI ( uiGroup ) ;
2019-10-09 17:36:57 -04:00
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 ) {
2019-10-06 16:56:31 -04:00
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 ( ) ) {
2019-10-18 23:23:23 +02:00
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 ) ) ) {
2019-10-06 16:56:31 -04:00
return false ;
}
}
2020-02-04 12:14:09 -05:00
return Build . validPlace ( player . team ( ) , x , y , type , rotation ) ;
2018-07-12 20:37:14 -04:00
}
public boolean validBreak ( int x , int y ) {
2020-02-04 12:14:09 -05:00
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 ) {
2019-10-18 23:23:23 +02:00
BuildRequest req = getRequest ( x , y ) ;
if ( req ! = null ) {
2020-02-05 20:11:49 -05:00
player . builder ( ) . requests ( ) . remove ( req ) ;
2019-10-18 23:23:23 +02:00
}
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
}
2018-06-09 23:23:14 -04:00
2019-09-29 19:54:52 -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 ;
2019-09-29 19:54:52 -04:00
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 ) ;
2019-09-29 19:54:52 -04:00
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-08 18:28:49 +01:00
2019-11-02 10:49:21 -04:00
if ( Core . settings . getBool ( " swapdiagonal " ) & & mobile ) {
2019-03-19 15:26:30 -04:00
diagonal = ! diagonal ;
}
2019-11-08 18:28:49 +01:00
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
}
2019-11-08 18:28:49 +01: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 18:28:49 +01:00
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 ) ) ) {
2019-11-08 18:28:49 +01:00
overlaps + + ;
}
}
2019-11-08 13:04:24 -05:00
//if it's more than one, it can bridge the gap
2019-11-08 18:28:49 +01:00
if ( overlaps > 1 ) {
skip . add ( points . get ( i - 1 ) ) ;
}
}
2019-11-08 13:04:24 -05:00
//remove skipped points
2019-11-08 18:28:49 +01:00
points . removeAll ( skip ) ;
}
2019-03-19 15:26:30 -04:00
float angle = Angles . angle ( startX , startY , endX , endY ) ;
2019-09-21 15:03:05 -07:00
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-09-21 15:03:05 -07:00
}
2019-03-19 15:26:30 -04:00
2019-03-19 19:25:48 -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-03-19 19:25:48 -04:00
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 ) ) {
2019-03-19 19:25:48 -04:00
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 ) {
2019-09-21 15:03:05 -07:00
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-03-19 19:25:48 -04:00
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 ;
}
}
}
* /
2017-12-13 23:28:20 -05:00
}