mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-03 13:30:25 +07:00
Added reconstructor blocks
This commit is contained in:
parent
6c620182ea
commit
1a8cd2e24c
@ -11,7 +11,7 @@ import java.lang.annotation.Target;
|
||||
*/
|
||||
public class Annotations {
|
||||
|
||||
/**Marks a method as invokable remotely from a server on a client.*/
|
||||
/**Marks a method as invokable remotely across a server/client connection.*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface Remote {
|
||||
|
BIN
core/assets-raw/sprites/blocks/units/reconstructor-open.png
Normal file
BIN
core/assets-raw/sprites/blocks/units/reconstructor-open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 276 B |
BIN
core/assets-raw/sprites/blocks/units/reconstructor.png
Normal file
BIN
core/assets-raw/sprites/blocks/units/reconstructor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 266 B |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 118 KiB |
@ -122,6 +122,7 @@ public class Recipes implements ContentList{
|
||||
new Recipe(units, UnitBlocks.resupplyPoint, new ItemStack(Items.steel, 10));
|
||||
|
||||
new Recipe(units, UnitBlocks.droneFactory, new ItemStack(Items.iron, 50));
|
||||
new Recipe(units, UnitBlocks.reconstructor, new ItemStack(Items.iron, 1));
|
||||
|
||||
|
||||
//new Recipe(units, UnitBlocks.vtolFactory, new ItemStack(Items.steel, 10));
|
||||
|
@ -5,13 +5,10 @@ import io.anuke.mindustry.content.UnitTypes;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.units.DropPoint;
|
||||
import io.anuke.mindustry.world.blocks.units.RepairPoint;
|
||||
import io.anuke.mindustry.world.blocks.units.ResupplyPoint;
|
||||
import io.anuke.mindustry.world.blocks.units.UnitFactory;
|
||||
import io.anuke.mindustry.world.blocks.units.*;
|
||||
|
||||
public class UnitBlocks extends BlockList implements ContentList {
|
||||
public static Block resupplyPoint, repairPoint, droneFactory, dropPoint;
|
||||
public static Block resupplyPoint, repairPoint, droneFactory, dropPoint, reconstructor;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
@ -38,5 +35,9 @@ public class UnitBlocks extends BlockList implements ContentList {
|
||||
shadow = "shadow-round-1";
|
||||
repairSpeed = 0.1f;
|
||||
}};
|
||||
|
||||
reconstructor = new Reconstructor("reconstructor") {{
|
||||
size = 2;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
@ -597,6 +597,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait {
|
||||
respawning = true;
|
||||
}
|
||||
|
||||
public void setRespawning(boolean respawning){
|
||||
this.respawning = respawning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<BuildRequest> getPlaceQueue(){
|
||||
return placeQueue;
|
||||
|
@ -67,6 +67,28 @@ public class Units {
|
||||
return value[0];
|
||||
}
|
||||
|
||||
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
||||
public static boolean anyEntities(Tile tile, float expansion, Predicate<Unit> pred){
|
||||
Block type = tile.block();
|
||||
rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion);
|
||||
rect.setCenter(tile.drawx(), tile.drawy());
|
||||
|
||||
boolean[] value = new boolean[1];
|
||||
|
||||
Units.getNearby(rect, unit -> {
|
||||
if(value[0] || !pred.test(unit)) return;
|
||||
if(!unit.isFlying()){
|
||||
unit.getHitbox(hitrect);
|
||||
|
||||
if(hitrect.overlaps(rect)) {
|
||||
value[0] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return value[0];
|
||||
}
|
||||
|
||||
/**Returns the neareset ally tile in a range.*/
|
||||
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
return findTile(x, y, range, tile -> !state.teams.areEnemies(team, tile.getTeam()) && pred.test(tile));
|
||||
|
@ -104,9 +104,9 @@ public abstract class InputHandler extends InputAdapter{
|
||||
//check if tapped block is configurable
|
||||
if(tile.block().configurable && tile.getTeam() == player.getTeam()){
|
||||
consumed = true;
|
||||
if((!frag.config.isShown() //if the config fragment is hidden, show
|
||||
if(((!frag.config.isShown() && tile.block().shouldShowConfigure(tile, player)) //if the config fragment is hidden, show
|
||||
//alternatively, the current selected block can 'agree' to switch config tiles
|
||||
|| frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile))) {
|
||||
|| (frag.config.isShown() && frag.config.getSelectedTile().block().onConfigureTileTapped(frag.config.getSelectedTile(), tile)))) {
|
||||
frag.config.showConfig(tile);
|
||||
}
|
||||
//otherwise...
|
||||
|
@ -4,8 +4,10 @@ import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.scene.Element;
|
||||
@ -13,12 +15,18 @@ import io.anuke.ucore.scene.Group;
|
||||
import io.anuke.ucore.scene.actions.Actions;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class BlockConfigFragment implements Fragment {
|
||||
public class BlockConfigFragment implements Fragment {
|
||||
private Table table = new Table();
|
||||
private InputHandler input;
|
||||
private Tile configTile;
|
||||
|
||||
public BlockConfigFragment(InputHandler input){
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(Group parent) {
|
||||
parent.addChild(table);
|
||||
@ -44,6 +52,16 @@ public class BlockConfigFragment implements Fragment {
|
||||
Actions.scaleTo(1f, 1f, 0.07f, Interpolation.pow3Out));
|
||||
|
||||
table.update(() -> {
|
||||
if(state.is(State.menu)){
|
||||
hideConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
if(configTile != null && configTile.block().shouldHideConfigure(configTile, input.player)){
|
||||
hideConfig();
|
||||
return;
|
||||
}
|
||||
|
||||
table.setOrigin(Align.center);
|
||||
Vector2 pos = Graphics.screen(tile.drawx(), tile.drawy() - tile.block().size * tilesize/2f - 1);
|
||||
table.setPosition(pos.x, pos.y, Align.top);
|
||||
@ -59,6 +77,7 @@ public class BlockConfigFragment implements Fragment {
|
||||
}
|
||||
|
||||
public void hideConfig(){
|
||||
configTile = null;
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.visible(false));
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public class OverlayFragment implements Fragment{
|
||||
this.input = input;
|
||||
|
||||
inv = new BlockInventoryFragment(input);
|
||||
config = new BlockConfigFragment();
|
||||
config = new BlockConfigFragment(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -195,6 +195,16 @@ public class Block extends BaseBlock implements UnlockableContent{
|
||||
return tile != other;
|
||||
}
|
||||
|
||||
/**Returns whether this config menu should show when the specified player taps it.*/
|
||||
public boolean shouldShowConfigure(Tile tile, Player player){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**Whether this configuration should be hidden now. Called every frame the config is open.*/
|
||||
public boolean shouldHideConfigure(Tile tile, Player player){
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean synthetic(){
|
||||
return update || destructible || solid;
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ public class MassDriver extends Block {
|
||||
protected float range;
|
||||
protected float rotateSpeed = 0.04f;
|
||||
protected float translation = 7f;
|
||||
//minimum amount of items needed to begin firing
|
||||
protected int minDistribute = 10;
|
||||
protected float knockback = 4f;
|
||||
protected float reloadTime = 80f;
|
||||
@ -134,6 +133,8 @@ public class MassDriver extends Block {
|
||||
|
||||
@Override
|
||||
public boolean onConfigureTileTapped(Tile tile, Tile other){
|
||||
if(tile == other) return false;
|
||||
|
||||
MassDriverEntity entity = tile.entity();
|
||||
|
||||
if(entity.link == other.packedPosition()) {
|
||||
|
@ -0,0 +1,304 @@
|
||||
package io.anuke.mindustry.world.blocks.units;
|
||||
|
||||
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.fx.Fx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.gen.CallBlocks;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.core.Graphics;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Reconstructor extends Block{
|
||||
protected float departTime = 20f;
|
||||
protected float arriveTime = 30f;
|
||||
protected float powerPerTeleport = 5f;
|
||||
protected Effect arriveEffect = Fx.spawn;
|
||||
|
||||
public Reconstructor(String name) {
|
||||
super(name);
|
||||
update = true;
|
||||
solidifes = true;
|
||||
hasPower = true;
|
||||
configurable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolidFor(Tile tile) {
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
return entity.solid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawConfigure(Tile tile) {
|
||||
super.drawConfigure(tile);
|
||||
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
if(validLink(tile, entity.link)){
|
||||
Tile target = world.tile(entity.link);
|
||||
|
||||
Draw.color(Palette.place);
|
||||
Lines.square(target.drawx(), target.drawy(),
|
||||
target.block().size * tilesize / 2f + 1f);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConfigureTileTapped(Tile tile, Tile other){
|
||||
if(tile == other) return false;
|
||||
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
if(entity.link == other.packedPosition()) {
|
||||
CallBlocks.unlinkReconstructor(null, tile, other);
|
||||
return false;
|
||||
}else if(other.block() instanceof Reconstructor){
|
||||
CallBlocks.linkReconstructor(null, tile, other);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldShowConfigure(Tile tile, Player player) {
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
return !checkValidTap(tile, entity, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldHideConfigure(Tile tile, Player player){
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
return checkValidTap(tile, entity, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile) {
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
if(entity.solid){
|
||||
Draw.rect(name, tile.drawx(), tile.drawy());
|
||||
}else{
|
||||
Draw.rect(name + "-open", tile.drawx(), tile.drawy());
|
||||
}
|
||||
|
||||
if(entity.current != null){
|
||||
float progress = entity.departing ? entity.updateTime : (1f - entity.updateTime);
|
||||
|
||||
Player player = entity.current;
|
||||
|
||||
TextureRegion region = Draw.region(player.mech.name);
|
||||
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = progress;
|
||||
Shaders.build.color.set(Palette.accent);
|
||||
Shaders.build.time = -entity.time / 10f;
|
||||
|
||||
Graphics.shader(Shaders.build, false);
|
||||
Shaders.build.apply();
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Graphics.shader();
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
|
||||
Lines.lineAngleCenter(
|
||||
tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size),
|
||||
tile.drawy(),
|
||||
90,
|
||||
size * Vars.tilesize /2f);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile) {
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
boolean stayOpen = false;
|
||||
|
||||
if(entity.current != null){
|
||||
entity.time += Timers.delta();
|
||||
|
||||
entity.solid = true;
|
||||
|
||||
if(entity.departing){
|
||||
//force respawn if there's suddenly nothing to link to
|
||||
if(!validLink(tile, entity.link)){
|
||||
entity.current.setRespawning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
ReconstructorEntity other = world.tile(entity.link).entity();
|
||||
|
||||
entity.updateTime -= Timers.delta()/departTime;
|
||||
if(entity.updateTime <= 0f){
|
||||
//TODO veryify power per teleport!
|
||||
other.power.amount -= powerPerTeleport;
|
||||
other.current = entity.current;
|
||||
other.departing = false;
|
||||
other.current.set(other.x, other.y);
|
||||
other.updateTime = 1f;
|
||||
entity.current = null;
|
||||
}
|
||||
}else{ //else, arriving
|
||||
entity.updateTime -= Timers.delta()/arriveTime;
|
||||
|
||||
if(entity.updateTime <= 0f){
|
||||
entity.solid = false;
|
||||
entity.current.setDead(false);
|
||||
|
||||
Effects.effect(arriveEffect, entity.current);
|
||||
|
||||
entity.current = null;
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
if (validLink(tile, entity.link)) {
|
||||
Tile other = world.tile(entity.link);
|
||||
if (other.entity.power.amount >= powerPerTeleport && Units.anyEntities(tile, 4f, unit -> unit.getTeam() == entity.getTeam() && unit instanceof Player) &&
|
||||
entity.power.amount >= powerPerTeleport) {
|
||||
entity.solid = false;
|
||||
stayOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stayOpen && !entity.solid && !Units.anyEntities(tile)) {
|
||||
entity.solid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tapped(Tile tile, Player player) {
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
if(!checkValidTap(tile, entity, player)) return;
|
||||
|
||||
CallBlocks.reconstructPlayer(player, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity() {
|
||||
return new ReconstructorEntity();
|
||||
}
|
||||
|
||||
protected static boolean checkValidTap(Tile tile, ReconstructorEntity entity, Player player){
|
||||
return validLink(tile, entity.link) &&
|
||||
Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize / 2f &&
|
||||
Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize / 2f &&
|
||||
entity.current == null && entity.power.amount >= ((Reconstructor)tile.block()).powerPerTeleport;
|
||||
}
|
||||
|
||||
protected static boolean validLink(Tile tile, int position){
|
||||
Tile other = world.tile(position);
|
||||
return other != tile && other != null && other.block() instanceof Reconstructor;
|
||||
}
|
||||
|
||||
protected static void unlink(ReconstructorEntity entity){
|
||||
Tile other = world.tile(entity.link);
|
||||
|
||||
if(other != null && other.block() instanceof Reconstructor){
|
||||
ReconstructorEntity oe = other.entity();
|
||||
if(oe.link == entity.tile.packedPosition()){
|
||||
oe.link = -1;
|
||||
}
|
||||
}
|
||||
|
||||
entity.link = -1;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true)
|
||||
public static void reconstructPlayer(Player player, Tile tile){
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
|
||||
if(!checkValidTap(tile, entity, player)) return;
|
||||
|
||||
entity.departing = true;
|
||||
entity.current = player;
|
||||
entity.solid = false;
|
||||
entity.set(tile.drawx(), tile.drawy());
|
||||
entity.updateTime = 1f;
|
||||
player.setDead(true);
|
||||
player.setRespawning(true);
|
||||
player.setRespawning();
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true)
|
||||
public static void linkReconstructor(Player player, Tile tile, Tile other){
|
||||
//just in case the client has invalid data
|
||||
if(!(tile.entity instanceof ReconstructorEntity) || !(other.entity instanceof ReconstructorEntity)) return;
|
||||
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
ReconstructorEntity oe = other.entity();
|
||||
|
||||
//called in main thread to prevent issues
|
||||
threads.run(() -> {
|
||||
unlink(entity);
|
||||
unlink(oe);
|
||||
|
||||
entity.link = other.packedPosition();
|
||||
oe.link = tile.packedPosition();
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true)
|
||||
public static void unlinkReconstructor(Player player, Tile tile, Tile other){
|
||||
//just in case the client has invalid data
|
||||
if(!(tile.entity instanceof ReconstructorEntity) || !(other.entity instanceof ReconstructorEntity)) return;
|
||||
|
||||
ReconstructorEntity entity = tile.entity();
|
||||
ReconstructorEntity oe = other.entity();
|
||||
|
||||
//called in main thread to prevent issues
|
||||
threads.run(() -> {
|
||||
unlink(entity);
|
||||
unlink(oe);
|
||||
});
|
||||
}
|
||||
|
||||
public class ReconstructorEntity extends TileEntity{
|
||||
public Player current;
|
||||
public float updateTime;
|
||||
public float time;
|
||||
public int link;
|
||||
public boolean solid = true, departing;
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream stream) throws IOException {
|
||||
stream.writeInt(link);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream stream) throws IOException {
|
||||
link = stream.readInt();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user