Merge branch 'master' of https://github.com/Anuken/Mindustry into lights

# Conflicts:
#	core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java
This commit is contained in:
Anuken
2019-11-10 14:12:43 -05:00
332 changed files with 18151 additions and 10448 deletions

View File

@@ -1,27 +1,22 @@
package io.anuke.mindustry.entities;
import io.anuke.annotations.Annotations.Struct;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.GridBits;
import io.anuke.arc.collection.IntQueue;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.collection.*;
import io.anuke.arc.func.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.content.Bullets;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Effects.Effect;
import io.anuke.mindustry.entities.type.Bullet;
import io.anuke.mindustry.entities.effect.Fire;
import io.anuke.mindustry.entities.effect.Lightning;
import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.Effects.*;
import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.gen.PropCell;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.*;
import static io.anuke.mindustry.Vars.*;
@@ -32,6 +27,7 @@ public class Damage{
private static Vector2 tr = new Vector2();
private static GridBits bits = new GridBits(30, 30);
private static IntQueue propagation = new IntQueue();
private static IntSet collidedBlocks = new IntSet();
/** Creates a dynamic explosion based on specified parameters. */
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
@@ -88,20 +84,22 @@ public class Damage{
* Only enemies of the specified team are damaged.
*/
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){
collidedBlocks.clear();
tr.trns(angle, length);
IntPositionConsumer collider = (cx, cy) -> {
Intc2 collider = (cx, cy) -> {
Tile tile = world.ltile(cx, cy);
if(tile != null && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
tile.entity.collision(hitter);
collidedBlocks.add(tile.pos());
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
}
};
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
collider.accept(cx, cy);
collider.get(cx, cy);
if(large){
for(Point2 p : Geometry.d4){
collider.accept(cx + p.x, cy + p.y);
collider.get(cx + p.x, cy + p.y);
}
}
return false;
@@ -127,7 +125,7 @@ public class Damage{
rect.width += expand * 2;
rect.height += expand * 2;
Consumer<Unit> cons = e -> {
Cons<Unit> cons = e -> {
e.hitbox(hitrect);
Rectangle other = hitrect;
other.y -= expand;
@@ -148,16 +146,16 @@ public class Damage{
}
/** Damages all entities and blocks in a radius that are enemies of the team. */
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor){
Consumer<Unit> cons = entity -> {
if(!predicate.test(entity)) return;
public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf<Unit> predicate, Cons<Unit> acceptor){
Cons<Unit> cons = entity -> {
if(!predicate.get(entity)) return;
entity.hitbox(hitrect);
if(!hitrect.overlaps(rect)){
return;
}
entity.damage(damage);
acceptor.accept(entity);
acceptor.get(entity);
};
rect.setSize(size * 2).setCenter(x, y);
@@ -180,7 +178,7 @@ public class Damage{
/** Damages all entities and blocks in a radius that are enemies of the team. */
public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){
Consumer<Unit> cons = entity -> {
Cons<Unit> cons = entity -> {
if(entity.getTeam() == team || entity.dst(x, y) > radius){
return;
}

View File

@@ -2,7 +2,7 @@ package io.anuke.mindustry.entities;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.func.Cons;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Position;
@@ -142,11 +142,11 @@ public class Effects{
this.data = data;
}
public void scaled(float lifetime, Consumer<EffectContainer> cons){
public void scaled(float lifetime, Cons<EffectContainer> cons){
if(innerContainer == null) innerContainer = new EffectContainer();
if(time <= lifetime){
innerContainer.set(id, color, time, lifetime, rotation, x, y, data);
cons.accept(innerContainer);
cons.get(innerContainer);
}
}

View File

@@ -2,7 +2,7 @@ package io.anuke.mindustry.entities;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import io.anuke.arc.func.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.entities.traits.*;
@@ -22,8 +22,8 @@ public class EntityGroup<T extends Entity>{
private final Rectangle intersectRect = new Rectangle();
private IntMap<T> map;
private QuadTree tree;
private Consumer<T> removeListener;
private Consumer<T> addListener;
private Cons<T> removeListener;
private Cons<T> addListener;
private final Rectangle viewport = new Rectangle();
private int count = 0;
@@ -60,20 +60,20 @@ public class EntityGroup<T extends Entity>{
draw(e -> true);
}
public void draw(Predicate<T> toDraw){
public void draw(Boolf<T> toDraw){
draw(toDraw, t -> ((DrawTrait)t).draw());
}
public void draw(Predicate<T> toDraw, Consumer<T> cons){
public void draw(Boolf<T> toDraw, Cons<T> cons){
Camera cam = Core.camera;
viewport.set(cam.position.x - cam.width / 2, cam.position.y - cam.height / 2, cam.width, cam.height);
for(Entity e : all()){
if(!(e instanceof DrawTrait) || !toDraw.test((T)e) || !e.isAdded()) continue;
if(!(e instanceof DrawTrait) || !toDraw.get((T)e) || !e.isAdded()) continue;
DrawTrait draw = (DrawTrait)e;
if(viewport.overlaps(draw.getX() - draw.drawSize()/2f, draw.getY() - draw.drawSize()/2f, draw.drawSize(), draw.drawSize())){
cons.accept((T)e);
cons.get((T)e);
}
}
}
@@ -82,11 +82,11 @@ public class EntityGroup<T extends Entity>{
return useTree;
}
public void setRemoveListener(Consumer<T> removeListener){
public void setRemoveListener(Cons<T> removeListener){
this.removeListener = removeListener;
}
public void setAddListener(Consumer<T> addListener){
public void setAddListener(Cons<T> addListener){
this.addListener = addListener;
}
@@ -148,7 +148,7 @@ public class EntityGroup<T extends Entity>{
if(check.getID() == id){ //if it is indeed queued, remove it
entitiesToAdd.removeValue(check, true);
if(removeListener != null){
removeListener.accept(check);
removeListener.get(check);
}
break;
}
@@ -157,7 +157,7 @@ public class EntityGroup<T extends Entity>{
}
@SuppressWarnings("unchecked")
public void intersect(float x, float y, float width, float height, Consumer<? super T> out){
public void intersect(float x, float y, float width, float height, Cons<? super T> out){
//don't waste time for empty groups
if(isEmpty()) return;
tree().getIntersect(out, x, y, width, height);
@@ -192,10 +192,10 @@ public class EntityGroup<T extends Entity>{
return entityArray.size;
}
public int count(Predicate<T> pred){
public int count(Boolf<T> pred){
int count = 0;
for(int i = 0; i < entityArray.size; i++){
if(pred.test(entityArray.get(i))) count++;
if(pred.get(entityArray.get(i))) count++;
}
return count;
}
@@ -211,7 +211,7 @@ public class EntityGroup<T extends Entity>{
}
if(addListener != null){
addListener.accept(type);
addListener.get(type);
}
}
@@ -221,7 +221,7 @@ public class EntityGroup<T extends Entity>{
entitiesToRemove.add(type);
if(removeListener != null){
removeListener.accept(type);
removeListener.get(type);
}
}
@@ -244,10 +244,10 @@ public class EntityGroup<T extends Entity>{
map.clear();
}
public T find(Predicate<T> pred){
public T find(Boolf<T> pred){
for(int i = 0; i < entityArray.size; i++){
if(pred.test(entityArray.get(i))) return entityArray.get(i);
if(pred.get(entityArray.get(i))) return entityArray.get(i);
}
return null;

View File

@@ -0,0 +1,6 @@
package io.anuke.mindustry.entities;
public enum TargetPriority{
base,
turret
}

View File

@@ -1,8 +1,8 @@
package io.anuke.mindustry.entities;
import io.anuke.arc.collection.EnumSet;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.func.Cons;
import io.anuke.arc.func.Boolf;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Geometry;
import io.anuke.arc.math.geom.Rectangle;
@@ -78,16 +78,16 @@ public class Units{
}
/** Returns the neareset ally tile in a range. */
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
public static TileEntity findAllyTile(Team team, float x, float y, float range, Boolf<Tile> pred){
return indexer.findTile(team, x, y, range, pred);
}
/** Returns the neareset enemy tile in a range. */
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf<Tile> pred){
if(team == Team.derelict) return null;
for(Team enemy : state.teams.enemiesOf(team)){
TileEntity entity = indexer.findTile(enemy, x, y, range, pred);
TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true);
if(entity != null){
return entity;
}
@@ -101,12 +101,12 @@ public class Units{
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred){
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred){
return closestTarget(team, x, y, range, unitPred, t -> true);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred, Predicate<Tile> tilePred){
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unit> unitPred, Boolf<Tile> tilePred){
if(team == Team.derelict) return null;
Unit unit = closestEnemy(team, x, y, range, unitPred);
@@ -118,14 +118,14 @@ public class Units{
}
/** Returns the closest enemy of this team. Filter by predicate. */
public static Unit closestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
public static Unit closestEnemy(Team team, float x, float y, float range, Boolf<Unit> predicate){
if(team == Team.derelict) return null;
result = null;
cdist = 0f;
nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> {
if(e.isDead() || !predicate.test(e)) return;
if(e.isDead() || !predicate.get(e)) return;
float dst2 = Mathf.dst2(e.x, e.y, x, y);
if(dst2 < range*range && (result == null || dst2 < cdist)){
@@ -138,12 +138,12 @@ public class Units{
}
/** Returns the closest ally of this team. Filter by predicate. */
public static Unit closest(Team team, float x, float y, float range, Predicate<Unit> predicate){
public static Unit closest(Team team, float x, float y, float range, Boolf<Unit> predicate){
result = null;
cdist = 0f;
nearby(team, x, y, range, e -> {
if(!predicate.test(e)) return;
if(!predicate.get(e)) return;
float dist = Mathf.dst2(e.x, e.y, x, y);
if(result == null || dist < cdist){
@@ -156,32 +156,32 @@ public class Units{
}
/** Iterates over all units in a rectangle. */
public static void nearby(Team team, float x, float y, float width, float height, Consumer<Unit> cons){
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unit> cons){
unitGroups[team.ordinal()].intersect(x, y, width, height, cons);
playerGroup.intersect(x, y, width, height, player -> {
if(player.getTeam() == team){
cons.accept(player);
cons.get(player);
}
});
}
/** Iterates over all units in a circle around this position. */
public static void nearby(Team team, float x, float y, float radius, Consumer<Unit> cons){
public static void nearby(Team team, float x, float y, float radius, Cons<Unit> cons){
unitGroups[team.ordinal()].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.withinDst(x, y, radius)){
cons.accept(unit);
cons.get(unit);
}
});
playerGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.getTeam() == team && unit.withinDst(x, y, radius)){
cons.accept(unit);
cons.get(unit);
}
});
}
/** Iterates over all units in a rectangle. */
public static void nearby(float x, float y, float width, float height, Consumer<Unit> cons){
public static void nearby(float x, float y, float width, float height, Cons<Unit> cons){
for(Team team : Team.all){
unitGroups[team.ordinal()].intersect(x, y, width, height, cons);
}
@@ -190,12 +190,12 @@ public class Units{
}
/** Iterates over all units in a rectangle. */
public static void nearby(Rectangle rect, Consumer<Unit> cons){
public static void nearby(Rectangle rect, Cons<Unit> cons){
nearby(rect.x, rect.y, rect.width, rect.height, cons);
}
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Consumer<Unit> cons){
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons<Unit> cons){
EnumSet<Team> targets = state.teams.enemiesOf(team);
for(Team other : targets){
@@ -204,18 +204,18 @@ public class Units{
playerGroup.intersect(x, y, width, height, player -> {
if(targets.contains(player.getTeam())){
cons.accept(player);
cons.get(player);
}
});
}
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){
public static void nearbyEnemies(Team team, Rectangle rect, Cons<Unit> cons){
nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons);
}
/** Iterates over all units. */
public static void all(Consumer<Unit> cons){
public static void all(Cons<Unit> cons){
for(Team team : Team.all){
unitGroups[team.ordinal()].all().each(cons);
}

View File

@@ -20,6 +20,10 @@ public class ArtilleryBulletType extends BasicBulletType{
hitSound = Sounds.explosion;
}
public ArtilleryBulletType(){
this(1f, 1f, "shell");
}
@Override
public void update(io.anuke.mindustry.entities.type.Bullet b){
super.update(b);

View File

@@ -22,6 +22,11 @@ public class BasicBulletType extends BulletType{
this.bulletSprite = bulletSprite;
}
/** For mods. */
public BasicBulletType(){
this(1f, 1f, "bullet");
}
@Override
public void load(){
backRegion = Core.atlas.find(bulletSprite + "-back");

View File

@@ -17,4 +17,8 @@ public class BombBulletType extends BasicBulletType{
collidesAir = false;
hitSound = Sounds.explosion;
}
public BombBulletType(){
this(1f, 1f, "shell");
}
}

View File

@@ -3,12 +3,12 @@ package io.anuke.mindustry.entities.bullet;
import io.anuke.arc.audio.*;
import io.anuke.arc.math.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.ctype.Content;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.Effects.*;
import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.type.*;
@@ -47,7 +47,7 @@ public abstract class BulletType extends Content{
/** Status effect applied on hit. */
public StatusEffect status = StatusEffects.none;
/** Intensity of applied status effect in terms of duration. */
public float statusDuration = 60 * 1f;
public float statusDuration = 60 * 10f;
/** Whether this bullet type collides with tiles. */
public boolean collidesTiles = true;
/** Whether this bullet type collides with tiles that are of the same team. */

View File

@@ -6,7 +6,7 @@ import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.entities.type.Bullet;
public abstract class FlakBulletType extends BasicBulletType{
public class FlakBulletType extends BasicBulletType{
protected static Rectangle rect = new Rectangle();
protected float explodeRange = 30f;
@@ -19,6 +19,10 @@ public abstract class FlakBulletType extends BasicBulletType{
bulletHeight = 10f;
}
public FlakBulletType(){
this(1f, 1f);
}
@Override
public void update(Bullet b){
super.update(b);

View File

@@ -22,6 +22,10 @@ public class HealBulletType extends BulletType{
collidesTeam = true;
}
public HealBulletType(){
this(1f, 1f);
}
@Override
public boolean collides(Bullet b, Tile tile){
return tile.getTeam() != b.getTeam() || tile.entity.healthf() < 1f;

View File

@@ -3,6 +3,7 @@ package io.anuke.mindustry.entities.bullet;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.*;
@@ -13,14 +14,17 @@ import io.anuke.mindustry.world.*;
import static io.anuke.mindustry.Vars.*;
public class LiquidBulletType extends BulletType{
Liquid liquid;
@NonNull Liquid liquid;
public LiquidBulletType(Liquid liquid){
public LiquidBulletType(@Nullable Liquid liquid){
super(3.5f, 0);
this.liquid = liquid;
if(liquid != null){
this.liquid = liquid;
this.status = liquid.effect;
}
lifetime = 74f;
status = liquid.effect;
statusDuration = 90f;
despawnEffect = Fx.none;
hitEffect = Fx.hitLiquid;
@@ -30,13 +34,17 @@ public class LiquidBulletType extends BulletType{
knockback = 0.55f;
}
public LiquidBulletType(){
this(null);
}
@Override
public float range(){
return speed * lifetime / 2f;
}
@Override
public void update(io.anuke.mindustry.entities.type.Bullet b){
public void update(Bullet b){
super.update(b);
if(liquid.canExtinguish()){
@@ -50,7 +58,7 @@ public class LiquidBulletType extends BulletType{
}
@Override
public void draw(io.anuke.mindustry.entities.type.Bullet b){
public void draw(Bullet b){
Draw.color(liquid.color, Color.white, b.fout() / 100f);
Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f);

View File

@@ -23,6 +23,10 @@ public class MissileBulletType extends BasicBulletType{
hitSound = Sounds.explosion;
}
public MissileBulletType(){
this(1f, 1f, "missile");
}
@Override
public void update(Bullet b){
super.update(b);
@@ -32,7 +36,7 @@ public class MissileBulletType extends BasicBulletType{
}
if(weaveMag > 0){
b.velocity().rotate(Mathf.sin(Time.time() + b.id * 4422, weaveScale, weaveMag));
b.velocity().rotate(Mathf.sin(Time.time() + b.id * 4422, weaveScale, weaveMag) * Time.delta());
}
}
}

View File

@@ -12,8 +12,8 @@ import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.entities.type.TimedEntity;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.type.TypeID;
import io.anuke.mindustry.world.*;
import java.io.*;

View File

@@ -20,8 +20,9 @@ import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.bulletGroup;
import static io.anuke.mindustry.Vars.*;
public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
public static final float lifetime = 10f;
@@ -34,7 +35,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
private static final float hitRange = 30f;
private static int lastSeed = 0;
private Array<Position> lines = new Array<>();
private Array<Vector2> lines = new Array<>();
private Color color = Pal.lancerLaser;
/** For pooling use only. Do not call directly! */
@@ -61,10 +62,30 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
random.setSeed(seed);
hit.clear();
boolean[] bhit = {false};
for(int i = 0; i < length / 2; i++){
Bullet.create(Bullets.damageLightning, l, team, x, y, 0f, 1f, 1f, dmg);
l.lines.add(new Vector2(x + Mathf.range(3f), y + Mathf.range(3f)));
if(l.lines.size > 1){
bhit[0] = false;
Position from = l.lines.get(l.lines.size - 2);
Position to = l.lines.get(l.lines.size - 1);
world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> {
Tile tile = world.ltile(wx, wy);
if(tile != null && tile.block().insulated){
bhit[0] = true;
//snap it instead of removing
l.lines.get(l.lines.size -1).set(wx * tilesize, wy * tilesize);
return true;
}
return false;
});
if(bhit[0]) break;
}
rect.setSize(hitRange).setCenter(x, y);
entities.clear();
if(hit.size < maxChain){
@@ -83,6 +104,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
y = furthest.y;
}else{
rotation += random.range(20f);
x += Angles.trnsx(rotation, hitRange / 2f);
y += Angles.trnsy(rotation, hitRange / 2f);
}

View File

@@ -16,7 +16,7 @@ import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.type.SolidEntity;
import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.TypeID;
import io.anuke.mindustry.type.TypeID;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;

View File

@@ -6,8 +6,8 @@ import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*;
@@ -104,7 +104,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(current.breaking){
entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier)){
if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){
if(current.hasConfig){
Call.onTileConfig(null, tile, current.config);
}
@@ -188,16 +188,30 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Add another build requests to the tail of the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place){
addBuildRequest(place, true);
}
/** Add another build requests to the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place, boolean tail){
BuildRequest replace = null;
for(BuildRequest request : buildQueue()){
if(request.x == place.x && request.y == place.y){
return;
replace = request;
break;
}
}
if(replace != null){
buildQueue().remove(replace);
}
Tile tile = world.tile(place.x, place.y);
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress;
}
buildQueue().addLast(place);
if(tail){
buildQueue().addLast(place);
}else{
buildQueue().addFirst(place);
}
}
/**
@@ -258,14 +272,26 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Class for storing build requests. Can be either a place or remove request. */
class BuildRequest{
public final int x, y, rotation;
public final Block block;
public final boolean breaking;
/** Position and rotation of this request. */
public int x, y, rotation;
/** Block being placed. If null, this is a breaking request.*/
public @Nullable Block block;
/** Whether this is a break request.*/
public boolean breaking;
/** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/
public boolean hasConfig;
/** Config int. Not used unless hasConfig is true.*/
public int config;
/** Original position, only used in schematics.*/
public int originalX, originalY, originalWidth, originalHeight;
/** Last progress.*/
public float progress;
public boolean initialized;
/** Whether construction has started for this request.*/
public boolean initialized, worldContext = true;
/** Visual scale. Used only for rendering.*/
public float animScale = 0f;
/** This creates a build request. */
public BuildRequest(int x, int y, int rotation, Block block){
@@ -285,13 +311,67 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true;
}
public BuildRequest(){
}
public BuildRequest copy(){
BuildRequest copy = new BuildRequest();
copy.x = x;
copy.y = y;
copy.rotation = rotation;
copy.block = block;
copy.breaking = breaking;
copy.hasConfig = hasConfig;
copy.config = config;
copy.originalX = originalX;
copy.originalY = originalY;
copy.progress = progress;
copy.initialized = initialized;
copy.animScale = animScale;
return copy;
}
public BuildRequest original(int x, int y, int originalWidth, int originalHeight){
originalX = x;
originalY = y;
this.originalWidth = originalWidth;
this.originalHeight = originalHeight;
return this;
}
public Rectangle bounds(Rectangle rect){
if(breaking){
return rect.set(-100f, -100f, 0f, 0f);
}else{
return block.bounds(x, y, rect);
}
}
public BuildRequest set(int x, int y, int rotation, Block block){
this.x = x;
this.y = y;
this.rotation = rotation;
this.block = block;
this.breaking = false;
return this;
}
public float drawx(){
return x*tilesize + block.offset();
}
public float drawy(){
return y*tilesize + block.offset();
}
public BuildRequest configure(int config){
this.config = config;
this.hasConfig = true;
return this;
}
public Tile tile(){
public @Nullable Tile tile(){
return world.tile(x, y);
}

View File

@@ -1,6 +1,6 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.game.TypeID;
import io.anuke.mindustry.type.TypeID;
public interface TypeTrait{

View File

@@ -1,5 +1,6 @@
package io.anuke.mindustry.entities.type;
import io.anuke.mindustry.*;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.Entity;
@@ -14,6 +15,14 @@ public abstract class BaseEntity implements Entity{
id = lastid++;
}
public int tileX(){
return Vars.world.toTile(x);
}
public int tileY(){
return Vars.world.toTile(y);
}
@Override
public int getID(){
return id;

View File

@@ -16,6 +16,8 @@ import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.TypeID;
import io.anuke.mindustry.ui.Cicon;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.defense.DeflectorWall.*;

View File

@@ -21,7 +21,6 @@ import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.io.*;
import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.*;
@@ -51,7 +50,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public String name = "noname";
public @Nullable
String uuid, usid;
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping;
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping, isBuilding = true;
public boolean buildWasAutoPaused = false;
public float boostHeat, shootHeat, destructTime;
public boolean achievedFlight;
public Color color = new Color();
@@ -359,7 +359,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void drawOver(){
if(dead) return;
drawMechanics();
if(isBuilding() && isBuilding){
if(!state.isPaused()){
drawBuilding();
}
}else{
drawMining();
}
}
@Override
@@ -426,57 +432,17 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
public void drawBuildRequests(){
BuildRequest last = null;
if(!isLocal) return;
for(BuildRequest request : buildQueue()){
if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue;
request.animScale = 1f;
if(request.breaking){
Block block = world.ltile(request.x, request.y).block();
//draw removal request
Lines.stroke(2f, Pal.removeBack);
float rad = Mathf.absin(Time.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset() - 1,
rad);
Draw.color(Pal.remove);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset(), rad);
control.input.drawBreaking(request);
}else{
Draw.color();
PlaceDraw draw = PlaceDraw.instance;
draw.scalex = 1;
draw.scaley = 1;
draw.rotation = request.rotation;
if(last == null){
request.block.getPlaceDraw(draw, request.rotation, request.x, request.y, request.rotation);
}else{
request.block.getPlaceDraw(draw, request.rotation, last.x - request.x, last.y - request.y, last.rotation);
}
TextureRegion region = draw.region;
Draw.rect(region,
request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(),
region.getWidth() * 1f * Draw.scl * draw.scalex,
region.getHeight() * 1f * Draw.scl * draw.scaley, request.block.rotate ? draw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(request.block.size - 1, 0) / 2f * tilesize;
Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90);
}
Draw.color();
last = request;
request.block.drawRequest(request, control.input.allRequests(),
Build.validPlace(getTeam(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request));
}
}
@@ -487,6 +453,18 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
//region update methods
@Override
public void updateMechanics(){
if(isBuilding){
updateBuilding();
}
//mine only when not building
if(buildRequest() == null || !isBuilding){
updateMining();
}
}
@Override
public void update(){
hitTime -= Time.delta();
@@ -519,7 +497,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
BuildRequest request = buildRequest();
if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
if(isBuilding() && isBuilding && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f);
}
@@ -611,7 +589,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
float xa = Core.input.axis(Binding.move_x);
float ya = Core.input.axis(Binding.move_y);
if(!Core.input.keyDown(Binding.gridMode) && !(Core.scene.getKeyboardFocus() instanceof TextField)){
if(!(Core.scene.getKeyboardFocus() instanceof TextField)){
movement.y += ya * speed;
movement.x += xa * speed;
}
@@ -819,9 +797,11 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
placeQueue.clear();
dead = true;
lastText = null;
isBuilding = true;
textFadeTime = 0f;
target = null;
moveTarget = null;
isShooting = isBoosting = isTransferring = isTyping = false;
spawner = lastSpawner = null;
health = maxHealth();
mining = null;
@@ -912,7 +892,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void write(DataOutput buffer) throws IOException{
super.writeSave(buffer, !isLocal);
TypeIO.writeStringData(buffer, name);
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3));
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3)| (Pack.byteValue(isBuilding) << 4));
buffer.writeInt(Color.rgba8888(color));
buffer.writeByte(mech.id);
buffer.writeInt(mining == null ? noSpawner : mining.pos());
@@ -934,6 +914,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
dead = (bools & 2) != 0;
boolean boosting = (bools & 4) != 0;
isTyping = (bools & 8) != 0;
boolean building = (bools & 16) != 0;
color.set(buffer.readInt());
mech = content.getByID(ContentType.mech, buffer.readByte());
int mine = buffer.readInt();
@@ -952,6 +933,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
velocity.y = lastvy;
}else{
mining = world.tile(mine);
isBuilding = building;
isBoosting = boosting;
}

View File

@@ -22,6 +22,7 @@ import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.ui.Cicon;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;

View File

@@ -151,7 +151,13 @@ public class FlyingUnit extends BaseUnit{
}
public void drawWeapons(){
for(int i : Mathf.signs){
float tra = rotation - 90, trY = -type.weapon.getRecoil(this, i > 0) + type.weaponOffsetY;
float w = -i * type.weapon.region.getWidth() * Draw.scl;
Draw.rect(type.weapon.region,
x + Angles.trnsx(tra, getWeapon().width * i, trY),
y + Angles.trnsy(tra, getWeapon().width * i, trY), w, type.weapon.region.getHeight() * Draw.scl, rotation - 90);
}
}
public void drawEngine(){