Added reconstructor blocks

This commit is contained in:
Anuken 2018-06-16 19:41:54 -04:00
parent 6c620182ea
commit 1a8cd2e24c
15 changed files with 833 additions and 450 deletions

View File

@ -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 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

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

View File

@ -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));

View File

@ -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;
}};
}
}

View File

@ -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;

View File

@ -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));

View File

@ -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...

View File

@ -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));
}
}

View File

@ -15,7 +15,7 @@ public class OverlayFragment implements Fragment{
this.input = input;
inv = new BlockInventoryFragment(input);
config = new BlockConfigFragment();
config = new BlockConfigFragment(input);
}
@Override

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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();
}
}
}