More cleanup

This commit is contained in:
Anuken
2020-02-03 20:24:49 -05:00
parent 88d2ec5be8
commit a942ed2cad
141 changed files with 2213 additions and 1819 deletions
+2 -2
View File
@@ -181,10 +181,10 @@ public class Damage{
if(entity.getTeam() == team || entity.dst(x, y) > radius){
return;
}
float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage);
float amount = calculateDamage(x, y, entity.getX(), entity.getY(), radius, damage);
entity.damage(amount);
//TODO better velocity displacement
float dst = tr.set(entity.x - x, entity.y - y).len();
float dst = tr.set(entity.getX() - x, entity.getY() - y).len();
entity.velocity().add(tr.setLength((1f - dst / radius) * 2f / entity.mass()));
if(complete && damage >= 9999999f && entity == player){
+4
View File
@@ -47,6 +47,10 @@ public class Effect{
Effects.createEffect(this, x, y, rotation, color, null);
}
public void at(float x, float y, Color color){
Effects.createEffect(this, x, y, 0, color, null);
}
public void at(float x, float y, float rotation, Color color, Object data){
Effects.createEffect(this, x, y, rotation, color, data);
}
-33
View File
@@ -1,33 +0,0 @@
package mindustry.entities;
import arc.struct.*;
import mindustry.entities.traits.*;
/** Simple container for managing entity groups.*/
public class Entities{
private final Array<EntityGroup<?>> groupArray = new Array<>();
public void clear(){
for(EntityGroup group : groupArray){
group.clear();
}
}
public EntityGroup<?> get(int id){
return groupArray.get(id);
}
public Array<EntityGroup<?>> all(){
return groupArray;
}
public <T extends Entity> EntityGroup<T> add(Class<T> type){
return add(type, true);
}
public <T extends Entity> EntityGroup<T> add(Class<T> type, boolean useTree){
EntityGroup<T> group = new EntityGroup<>(groupArray.size, type, useTree);
groupArray.add(group);
return group;
}
}
@@ -3,6 +3,7 @@ package mindustry.entities;
import arc.struct.Array;
import arc.math.Mathf;
import arc.math.geom.*;
import mindustry.gen.*;
import mindustry.world.Tile;
import static mindustry.Vars.tilesize;
@@ -22,9 +23,9 @@ public class EntityCollisions{
private Rect r2 = new Rect();
//entity collisions
private Array<SolidTrait> arrOut = new Array<>();
private Array<Hitboxc> arrOut = new Array<>();
public void move(SolidTrait entity, float deltax, float deltay){
public void move(Hitboxc entity, float deltax, float deltay){
boolean movedx = false;
@@ -53,8 +54,7 @@ public class EntityCollisions{
}
}
public void moveDelta(SolidTrait entity, float deltax, float deltay, boolean x){
public void moveDelta(Hitboxc entity, float deltax, float deltay, boolean x){
Rect rect = r1;
entity.hitboxTile(rect);
entity.hitboxTile(r2);
@@ -66,7 +66,7 @@ public class EntityCollisions{
for(int dx = -r; dx <= r; dx++){
for(int dy = -r; dy <= r; dy++){
int wx = dx + tilex, wy = dy + tiley;
if(solid(wx, wy) && entity.collidesGrid(wx, wy)){
if(solid(wx, wy)){
tmp.setSize(tilesize).setCenter(wx * tilesize, wy * tilesize);
if(tmp.overlaps(rect)){
@@ -106,18 +106,16 @@ public class EntityCollisions{
}
@SuppressWarnings("unchecked")
public <T extends Entity> void updatePhysics(EntityGroup<T> group){
public <T extends Hitboxc> void updatePhysics(EntityGroup<T> group){
QuadTree tree = group.tree();
tree.clear();
for(Entity entity : group.all()){
if(entity instanceof SolidTrait){
SolidTrait s = (SolidTrait)entity;
s.lastPosition().set(s.getX(), s.getY());
tree.insert(s);
}
}
group.each(s -> {
s.setLastX(s.getX());
s.setLastY(s.getY());
tree.insert(s);
});
}
private static boolean solid(int x, int y){
@@ -125,25 +123,22 @@ public class EntityCollisions{
return tile != null && tile.solid();
}
private void checkCollide(Entity entity, Entity other){
SolidTrait a = (SolidTrait)entity;
SolidTrait b = (SolidTrait)other;
private void checkCollide(Hitboxc a, Hitboxc b){
a.hitbox(this.r1);
b.hitbox(this.r2);
r1.x += (a.lastPosition().x - a.getX());
r1.y += (a.lastPosition().y - a.getY());
r2.x += (b.lastPosition().x - b.getX());
r2.y += (b.lastPosition().y - b.getY());
r1.x += (a.getLastX() - a.getX());
r1.y += (a.getLastY() - a.getY());
r2.x += (b.getLastX() - b.getX());
r2.y += (b.getLastY() - b.getY());
float vax = a.getX() - a.lastPosition().x;
float vay = a.getY() - a.lastPosition().y;
float vbx = b.getX() - b.lastPosition().x;
float vby = b.getY() - b.lastPosition().y;
float vax = a.getX() - a.getLastX();
float vay = a.getY() - a.getLastY();
float vbx = b.getX() - b.getLastX();
float vby = b.getY() - b.getLastY();
if(a != b && a.collides(b) && b.collides(a)){
if(a != b && a.collides(b)){
l1.set(a.getX(), a.getY());
boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay,
r2.x, r2.y, r2.width, r2.height, vbx, vby, l1);
@@ -205,17 +200,12 @@ public class EntityCollisions{
}
@SuppressWarnings("unchecked")
public void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){
for(Entity entity : groupa.all()){
if(!(entity instanceof SolidTrait))
continue;
SolidTrait solid = (SolidTrait)entity;
public void collideGroups(EntityGroup<? extends Hitboxc> groupa, EntityGroup<? extends Hitboxc> groupb){
groupa.each(solid -> {
solid.hitbox(r1);
r1.x += (solid.lastPosition().x - solid.getX());
r1.y += (solid.lastPosition().y - solid.getY());
r1.x += (solid.getLastX() - solid.getX());
r1.y += (solid.getLastY() - solid.getY());
solid.hitbox(r2);
r2.merge(r1);
@@ -223,12 +213,12 @@ public class EntityCollisions{
arrOut.clear();
groupb.tree().getIntersect(arrOut, r2);
for(SolidTrait sc : arrOut){
for(Hitboxc sc : arrOut){
sc.hitbox(r1);
if(r2.overlaps(r1)){
checkCollide(entity, sc);
checkCollide(solid, sc);
}
}
}
});
}
}
+27 -151
View File
@@ -1,39 +1,26 @@
package mindustry.entities;
import arc.*;
import arc.struct.*;
import arc.func.*;
import arc.graphics.*;
import arc.math.geom.*;
import mindustry.entities.traits.*;
import arc.struct.*;
import mindustry.gen.*;
import java.util.*;
import static mindustry.Vars.collisions;
import static mindustry.Vars.*;
/** Represents a group of a certain type of entity.*/
@SuppressWarnings("unchecked")
public class EntityGroup<T extends Entity> implements Iterable<T>{
public class EntityGroup<T extends Entityc>{
private final boolean useTree;
private final int id;
private final Class<T> type;
private final Array<T> entityArray = new Array<>(false, 32);
private final Array<T> entitiesToRemove = new Array<>(false, 32);
private final Array<T> entitiesToAdd = new Array<>(false, 32);
private final Array<T> array = new Array<>(false, 32);
private final Array<T> intersectArray = new Array<>();
private final Rect intersectRect = new Rect();
private IntMap<T> map;
private QuadTree tree;
private Cons<T> removeListener;
private Cons<T> addListener;
private final Rect viewport = new Rect();
private int count = 0;
private int index;
public EntityGroup(int id, Class<T> type, boolean useTree){
public EntityGroup(boolean useTree){
this.useTree = useTree;
this.id = id;
this.type = type;
if(useTree){
tree = new QuadTree<>(new Rect(0, 0, 0, 0));
@@ -41,42 +28,18 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
}
public void update(){
updateEvents();
if(useTree()){
collisions.updatePhysics(this);
collisions.updatePhysics((EntityGroup<? extends Hitboxc>)this);
}
for(Entity e : all()){
e.update();
}
each(Entityc::update);
}
public int countInBounds(){
count = 0;
draw(e -> true, e -> count++);
return count;
}
public void draw(){
draw(e -> true);
}
public void draw(Boolf<T> toDraw){
draw(toDraw, t -> ((DrawTrait)t).draw());
}
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.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.get((T)e);
}
public void each(Cons<T> cons){
T[] items = array.items;
for(index = 0; index < array.size; index++){
cons.get(items[index]);
}
}
@@ -84,14 +47,6 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
return useTree;
}
public void setRemoveListener(Cons<T> removeListener){
this.removeListener = removeListener;
}
public void setAddListener(Cons<T> addListener){
this.addListener = addListener;
}
public EntityGroup<T> enableMapping(){
map = new IntMap<>();
return this;
@@ -101,40 +56,6 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
return map != null;
}
public Class<T> getType(){
return type;
}
public int getID(){
return id;
}
public void updateEvents(){
for(T e : entitiesToAdd){
if(e == null)
continue;
entityArray.add(e);
e.added();
if(map != null){
map.put(e.getID(), e);
}
}
entitiesToAdd.clear();
for(T e : entitiesToRemove){
entityArray.removeValue(e, true);
if(map != null){
map.remove(e.getID());
}
e.removed();
}
entitiesToRemove.clear();
}
public T getByID(int id){
if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!");
return map.get(id);
@@ -145,16 +66,6 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
T t = map.get(id);
if(t != null){ //remove if present in map already
remove(t);
}else{ //maybe it's being queued?
for(T check : entitiesToAdd){
if(check.getID() == id){ //if it is indeed queued, remove it
entitiesToAdd.removeValue(check, true);
if(removeListener != null){
removeListener.get(check);
}
break;
}
}
}
}
@@ -187,81 +98,46 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
}
public boolean isEmpty(){
return entityArray.size == 0;
return array.size == 0;
}
public int size(){
return entityArray.size;
return array.size;
}
public int count(Boolf<T> pred){
int count = 0;
for(int i = 0; i < entityArray.size; i++){
if(pred.get(entityArray.get(i))) count++;
}
return count;
return array.count(pred);
}
public void add(T type){
if(type == null) throw new RuntimeException("Cannot add a null entity!");
if(type.getGroup() != null) return;
type.setGroup(this);
entitiesToAdd.add(type);
array.add(type);
if(mappingEnabled()){
map.put(type.getID(), type);
}
if(addListener != null){
addListener.get(type);
map.put(type.getId(), type);
}
}
public void remove(T type){
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
type.setGroup(null);
entitiesToRemove.add(type);
int idx = array.indexOf(type, true);
if(idx != -1){
array.remove(idx);
if(removeListener != null){
removeListener.get(type);
//fix iteration index when removing
if(index >= idx){
index --;
}
}
}
public void clear(){
for(T entity : entityArray){
entity.removed();
entity.setGroup(null);
}
for(T entity : entitiesToAdd)
entity.setGroup(null);
for(T entity : entitiesToRemove)
entity.setGroup(null);
entitiesToAdd.clear();
entitiesToRemove.clear();
entityArray.clear();
array.clear();
if(map != null)
map.clear();
}
public T find(Boolf<T> pred){
for(int i = 0; i < entityArray.size; i++){
if(pred.get(entityArray.get(i))) return entityArray.get(i);
}
return null;
}
/** Returns the array for iteration. */
public Array<T> all(){
return entityArray;
}
@Override
public Iterator<T> iterator(){
return entityArray.iterator();
return array.find(pred);
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ public class Predict{
/**
* See {@link #intercept(float, float, float, float, float, float, float)}.
*/
public static Vec2 intercept(TargetTrait src, TargetTrait dst, float v){
public static Vec2 intercept(Teamc src, Teamc dst, float v){
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/(2f*Time.delta()), dst.getTargetVelocityY() - src.getTargetVelocityY()/(2f*Time.delta()), v);
}
+12 -30
View File
@@ -5,6 +5,7 @@ import arc.math.*;
import arc.math.geom.*;
import mindustry.entities.type.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.world.*;
import static mindustry.Vars.*;
@@ -30,17 +31,17 @@ public class Units{
* @param range The maximum distance from the target X/Y the targeter can be for it to be valid
* @return whether the target is invalid
*/
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){
public static boolean invalidateTarget(Teamc target, Team team, float x, float y, float range){
return target == null || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || target.getTeam() == team || !target.isValid();
}
/** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
/** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */
public static boolean invalidateTarget(Teamc target, Team team, float x, float y){
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
}
/** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */
public static boolean invalidateTarget(TargetTrait target, Unitc targeter){
/** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */
public static boolean invalidateTarget(Teamc target, Unitc targeter){
return invalidateTarget(target, targeter.getTeam(), targeter.x, targeter.y, targeter.getWeapon().bullet.range());
}
@@ -68,35 +69,35 @@ public class Units{
}
/** Returns the neareset damaged tile. */
public static TileEntity findDamagedTile(Team team, float x, float y){
public static Tilec findDamagedTile(Team team, float x, float y){
Tile tile = Geometry.findClosest(x, y, indexer.getDamaged(team));
return tile == null ? null : tile.entity;
}
/** Returns the neareset ally tile in a range. */
public static TileEntity findAllyTile(Team team, float x, float y, float range, Boolf<Tile> pred){
public static Tilec 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, Boolf<Tile> pred){
public static Tilec findEnemyTile(Team team, float x, float y, float range, Boolf<Tile> pred){
if(team == Team.derelict) return null;
return indexer.findEnemyTile(team, x, y, range, pred);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range){
public static Teamc closestTarget(Team team, float x, float y, float range){
return closestTarget(team, x, y, range, Unitc::isValid);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf<Unitc> unitPred){
public static Teamc closestTarget(Team team, float x, float y, float range, Boolf<Unitc> 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, Boolf<Unitc> unitPred, Boolf<Tile> tilePred){
public static Teamc closestTarget(Team team, float x, float y, float range, Boolf<Unitc> unitPred, Boolf<Tile> tilePred){
if(team == Team.derelict) return null;
Unitc unit = closestEnemy(team, x, y, range, unitPred);
@@ -152,11 +153,6 @@ public class Units{
cons.get(u);
}
});
playerGroup.intersect(x, y, width, height, player -> {
if(player.getTeam() == team){
cons.get(player);
}
});
}
/** Iterates over all units in a circle around this position. */
@@ -166,18 +162,11 @@ public class Units{
cons.get(unit);
}
});
playerGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.getTeam() == team && unit.withinDst(x, y, radius)){
cons.get(unit);
}
});
}
/** Iterates over all units in a rectangle. */
public static void nearby(float x, float y, float width, float height, Cons<Unitc> cons){
unitGroup.intersect(x, y, width, height, cons);
playerGroup.intersect(x, y, width, height, cons);
}
/** Iterates over all units in a rectangle. */
@@ -192,12 +181,6 @@ public class Units{
cons.get(u);
}
});
playerGroup.intersect(x, y, width, height, player -> {
if(team.isEnemy(player.getTeam())){
cons.get(player);
}
});
}
/** Iterates over all units that are enemies of this team. */
@@ -208,7 +191,6 @@ public class Units{
/** Iterates over all units. */
public static void all(Cons<Unitc> cons){
unitGroup.all().each(cons);
playerGroup.all().each(cons);
}
public static void each(Team team, Cons<BaseUnit> cons){
@@ -3,7 +3,6 @@ package mindustry.entities.bullet;
import arc.graphics.g2d.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
//TODO scale velocity depending on fslope()
@@ -24,7 +23,7 @@ public class ArtilleryBulletType extends BasicBulletType{
}
@Override
public void update(Bullet b){
public void update(Bulletc b){
super.update(b);
if(b.timer.get(0, 3 + b.fslope() * 2f)){
@@ -33,7 +32,7 @@ public class ArtilleryBulletType extends BasicBulletType{
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
float baseScale = 0.7f;
float scale = (baseScale + b.fslope() * (1f - baseScale));
@@ -4,7 +4,7 @@ import arc.Core;
import arc.graphics.Color;
import arc.graphics.g2d.Draw;
import arc.graphics.g2d.TextureRegion;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
import mindustry.graphics.Pal;
/** An extended BulletType for most ammo-based bullets shot from turrets and units. */
@@ -34,7 +34,7 @@ public class BasicBulletType extends BulletType{
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout());
Draw.color(backColor);
@@ -2,13 +2,16 @@ package mindustry.entities.bullet;
import arc.audio.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.Effects.*;
import mindustry.entities.effect.*;
import mindustry.entities.traits.*;
import mindustry.entities.type.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
@@ -97,20 +100,20 @@ public abstract class BulletType extends Content{
return speed * lifetime * (1f - drag);
}
public boolean collides(Bullet bullet, Tile tile){
public boolean collides(Bulletc bullet, Tile tile){
return true;
}
public void hitTile(Bullet b, Tile tile){
public void hitTile(Bulletc b, Tile tile){
hit(b);
}
public void hit(Bullet b){
hit(b, b.x, b.y);
public void hit(Bulletc b){
hit(b, b.getX(), b.getY());
}
public void hit(Bullet b, float x, float y){
hitEffect.at(x, y, b.rot());
public void hit(Bulletc b, float x, float y){
hitEffect.at(x, y, b.getRotation());
hitSound.at(b);
Effects.shake(hitShake, hitShake, b);
@@ -119,7 +122,7 @@ public abstract class BulletType extends Content{
for(int i = 0; i < fragBullets; i++){
float len = Mathf.random(1f, 7f);
float a = Mathf.random(360f);
Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax));
fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax));
}
}
@@ -132,8 +135,8 @@ public abstract class BulletType extends Content{
}
}
public void despawned(Bullet b){
despawnEffect.at(b.x, b.y, b.rot());
public void despawned(Bulletc b){
despawnEffect.at(b.getX(), b.getY(), b.getRotation());
hitSound.at(b);
if(fragBullet != null || splashDamageRadius > 0){
@@ -145,23 +148,23 @@ public abstract class BulletType extends Content{
}
}
public void draw(Bullet b){
public void draw(Bulletc b){
}
public void init(Bullet b){
if(killShooter && b.getOwner() instanceof HealthTrait){
((HealthTrait)b.getOwner()).kill();
public void init(Bulletc b){
if(killShooter && b.getOwner() instanceof Healthc){
((Healthc)b.getOwner()).kill();
}
if(instantDisappear){
b.time(lifetime);
b.setTime(lifetime);
}
}
public void update(Bullet b){
public void update(Bulletc b){
if(homingPower > 0.0001f){
TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir);
Teamc target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir);
if(target != null){
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
}
@@ -172,4 +175,61 @@ public abstract class BulletType extends Content{
public ContentType getContentType(){
return ContentType.bullet;
}
//TODO change 'create' to 'at'
public Bulletc create(Teamc owner, float x, float y, float angle){
return create(owner, owner.getTeam(), x, y, angle);
}
public Bulletc create(Entityc owner, Team team, float x, float y, float angle){
return create(owner, team, x, y, angle, 1f);
}
public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl){
return create(owner, team, x, y, angle, velocityScl, 1f, null);
}
public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
return create(owner, team, x, y, angle, velocityScl, lifetimeScl, null);
}
public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl, Object data){
//TODO implement
return null;
/*
Bullet bullet = Pools.obtain(Bullet.class, Bullet::new);
bullet.type = type;
bullet.owner = owner;
bullet.data = data;
bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl);
if(type.keepVelocity){
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).velocity() : Vec2.ZERO);
}
bullet.team = team;
bullet.type = type;
bullet.lifeScl = lifetimeScl;
bullet.set(x - bullet.velocity.x * Time.delta(), y - bullet.velocity.y * Time.delta());
bullet.add();
return bullet;*/
}
public Bulletc create(Bulletc parent, float x, float y, float angle){
return create(parent.getOwner(), parent.getTeam(), x, y, angle);
}
public Bulletc create(Bulletc parent, float x, float y, float angle, float velocityScl){
return create(parent.getOwner(), parent.getTeam(), x, y, angle, velocityScl);
}
@Remote(called = Loc.server, unreliable = true)
public static void createBullet(BulletType type, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
type.create(null, team, x, y, angle, velocityScl, lifetimeScl, null);
}
}
@@ -4,7 +4,7 @@ import arc.math.geom.Rect;
import arc.util.Time;
import mindustry.content.Fx;
import mindustry.entities.Units;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
public class FlakBulletType extends BasicBulletType{
protected static Rect rect = new Rect();
@@ -24,7 +24,7 @@ public class FlakBulletType extends BasicBulletType{
}
@Override
public void update(Bullet b){
public void update(Bulletc b){
super.update(b);
if(b.getData() instanceof Integer) return;
@@ -3,7 +3,7 @@ package mindustry.entities.bullet;
import arc.graphics.*;
import arc.graphics.g2d.*;
import mindustry.content.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
@@ -28,12 +28,12 @@ public class HealBulletType extends BulletType{
}
@Override
public boolean collides(Bullet b, Tile tile){
public boolean collides(Bulletc b, Tile tile){
return tile.getTeam() != b.getTeam() || tile.entity.healthf() < 1f;
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
Draw.color(backColor);
Lines.stroke(bulletWidth);
Lines.lineAngleCenter(b.x, b.y, b.rot(), bulletHeight);
@@ -43,7 +43,7 @@ public class HealBulletType extends BulletType{
}
@Override
public void hitTile(Bullet b, Tile tile){
public void hitTile(Bulletc b, Tile tile){
super.hit(b);
tile = tile.link();
@@ -6,7 +6,7 @@ import arc.math.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class LaserBulletType extends BulletType{
@@ -40,12 +40,12 @@ public class LaserBulletType extends BulletType{
}
@Override
public void init(Bullet b){
public void init(Bulletc b){
Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length);
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
float f = Mathf.curve(b.fin(), 0f, 0.2f);
float baseLen = length * f;
float cwidth = width;
@@ -3,7 +3,7 @@ package mindustry.entities.bullet;
import arc.graphics.*;
import mindustry.content.*;
import mindustry.entities.effect.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class LightningBulletType extends BulletType{
@@ -20,11 +20,11 @@ public class LightningBulletType extends BulletType{
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
}
@Override
public void init(Bullet b){
public void init(Bulletc b){
Lightning.create(b.getTeam(), lightningColor, damage, b.x, b.y, b.rot(), lightningLength);
}
}
@@ -5,9 +5,8 @@ import arc.graphics.g2d.*;
import arc.math.geom.*;
import arc.util.ArcAnnotate.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.effect.*;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
@@ -45,7 +44,7 @@ public class LiquidBulletType extends BulletType{
}
@Override
public void update(Bullet b){
public void update(Bulletc b){
super.update(b);
if(liquid.canExtinguish()){
@@ -59,14 +58,14 @@ public class LiquidBulletType extends BulletType{
}
@Override
public void draw(Bullet b){
public void draw(Bulletc b){
Draw.color(liquid.color, Color.white, b.fout() / 100f);
Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f);
}
@Override
public void hit(Bullet b, float hitx, float hity){
public void hit(Bulletc b, float hitx, float hity){
hitEffect.at(liquid.color, hitx, hity);
Puddle.deposit(world.tileWorld(hitx, hity), liquid, puddleSize);
@@ -5,7 +5,7 @@ import arc.graphics.g2d.Draw;
import arc.math.Angles;
import arc.math.Mathf;
import mindustry.content.Fx;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
import mindustry.graphics.Pal;
import mindustry.world.blocks.distribution.MassDriver.DriverBulletData;
@@ -23,7 +23,7 @@ public class MassDriverBolt extends BulletType{
}
@Override
public void draw(mindustry.entities.type.Bullet b){
public void draw(Bulletc b){
float w = 11f, h = 13f;
Draw.color(Pal.bulletYellowBack);
@@ -36,7 +36,7 @@ public class MassDriverBolt extends BulletType{
}
@Override
public void update(mindustry.entities.type.Bullet b){
public void update(Bulletc b){
//data MUST be an instance of DriverBulletData
if(!(b.getData() instanceof DriverBulletData)){
hit(b);
@@ -82,7 +82,7 @@ public class MassDriverBolt extends BulletType{
}
@Override
public void despawned(mindustry.entities.type.Bullet b){
public void despawned(Bulletc b){
super.despawned(b);
if(!(b.getData() instanceof DriverBulletData)) return;
@@ -99,7 +99,7 @@ public class MassDriverBolt extends BulletType{
}
@Override
public void hit(Bullet b, float hitx, float hity){
public void hit(Bulletc b, float hitx, float hity){
super.hit(b, hitx, hity);
despawned(b);
}
@@ -4,7 +4,6 @@ import arc.graphics.Color;
import arc.math.Mathf;
import arc.util.Time;
import mindustry.content.Fx;
import mindustry.entities.type.Bullet;
import mindustry.gen.*;
import mindustry.graphics.Pal;
@@ -27,7 +26,7 @@ public class MissileBulletType extends BasicBulletType{
}
@Override
public void update(Bullet b){
public void update(Bulletc b){
super.update(b);
if(Mathf.chance(Time.delta() * 0.2)){
+262 -155
View File
@@ -5,6 +5,7 @@ import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.math.geom.QuadTree.*;
import arc.scene.ui.layout.*;
import arc.struct.Bits;
import arc.struct.Queue;
@@ -19,7 +20,6 @@ import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.effect.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
@@ -31,18 +31,19 @@ import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.BuildBlock.*;
import mindustry.world.consumers.*;
import mindustry.world.modules.*;
import java.io.*;
import java.util.*;
import static mindustry.Vars.*;
import static mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
@SuppressWarnings("unused")
public class EntityComps{
@Component
abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitboxc, Rotc{
abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitboxc, Rotc, Massc{
UnitDef type;
UnitController controller;
@@ -138,8 +139,8 @@ public class EntityComps{
}
@Component
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc{
private boolean supressCollision, supressOnce, deflected;
abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc{
private float lifeScl;
Object data;
BulletType type;
@@ -148,196 +149,91 @@ public class EntityComps{
return type.damage;
}
public void init(){
//TODO
type.init((Bulletc)this);
public void add(){
type.init(this);
setDrag(type.drag);
setHitSize(type.hitSize);
setLifetime(lifeScl * type.lifetime);
}
public void remove(){
//TODO
type.despawned((Bulletc)this);
type.despawned(this);
}
public float getLifetime(){
return type.lifetime;
}
void deflect(){
supressCollision = true;
supressOnce = true;
deflected = true;
}
public boolean isDeflected(){
return deflected;
}
public float damageMultiplier(){
if(owner instanceof Unitc){
return ((Unitc)owner).getDamageMultipler();
if(getOwner() instanceof Unitc){
return ((Unitc)getOwner()).getDamageMultiplier();
}
return 1f;
}
@Override
public void killed(Entity other){
if(owner instanceof KillerTrait){
((KillerTrait)owner).killed(other);
}
}
@Override
public void absorb(){
supressCollision = true;
//TODO
remove();
}
@Override
public float drawSize(){
public float clipSize(){
return type.drawSize;
}
@Override
public float damage(){
if(owner instanceof Lightning && data instanceof Float){
return (Float)data;
}
return type.damage * damageMultiplier();
}
@Override
public Team getTeam(){
return team;
}
@Override
public float getShieldDamage(){
return Math.max(damage(), type.splashDamage);
}
@Override
public boolean collides(SolidTrait other){
return type.collides && (other != owner && !(other instanceof DamageTrait)) && !supressCollision && !(other instanceof Unitc && ((Unitc)other).isFlying() && !type.collidesAir);
}
@Override
public void collision(SolidTrait other, float x, float y){
public void collision(Hitboxc other, float x, float y){
if(!type.pierce) remove();
type.hit(this, x, y);
if(other instanceof Unitc){
Unitc unit = (Unitc)other;
unit.velocity().add(Tmp.v3.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.mass()));
unit.applyEffect(type.status, type.statusDuration);
unit.getVel().add(Tmp.v3.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass()));
unit.apply(type.status, type.statusDuration);
}
}
@Override
public void update(){
type.update(this);
x += velocity.x * Time.delta();
y += velocity.y * Time.delta();
velocity.scl(Mathf.clamp(1f - type.drag * Time.delta()));
time += Time.delta() * 1f / (lifeScl);
time = Mathf.clamp(time, 0, type.lifetime);
if(time >= type.lifetime){
if(!supressCollision) type.despawned(this);
remove();
}
if(type.hitTiles && collidesTiles() && !supressCollision && initialized){
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
if(type.hitTiles){
world.raycastEach(world.toTile(getLastX()), world.toTile(getLastY()), tileX(), tileY(), (x, y) -> {
Tile tile = world.ltile(x, y);
if(tile == null) return false;
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
if(tile.getTeam() != team){
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != getTeam())){
if(tile.getTeam() != getTeam()){
tile.entity.collision(this);
}
if(!supressCollision){
type.hitTile(this, tile);
remove();
}
type.hitTile(this, tile);
remove();
return true;
}
return false;
});
}
if(supressOnce){
supressCollision = false;
supressOnce = false;
}
initialized = true;
}
@Override
public void reset(){
type = null;
owner = null;
velocity.setZero();
time = 0f;
timer.clear();
lifeScl = 1f;
team = null;
data = null;
supressCollision = false;
supressOnce = false;
deflected = false;
initialized = false;
}
@Override
public void hitbox(Rect rect){
rect.setSize(type.hitSize).setCenter(x, y);
}
@Override
public void hitboxTile(Rect rect){
rect.setSize(type.hitSize).setCenter(x, y);
}
@Override
public void draw(){
type.draw(this);
renderer.lights.add(x, y, 16f, Pal.powerLight, 0.3f);
}
@Override
public float fin(){
return time / type.lifetime;
}
@Override
public Vec2 velocity(){
return velocity;
}
public void velocity(float speed, float angle){
velocity.set(0, speed).setAngle(angle);
}
public void limit(float f){
velocity.limit(f);
//TODO refactor
renderer.lights.add(getX(), getY(), 16f, Pal.powerLight, 0.3f);
}
/** Sets the bullet's rotation in degrees. */
public void rot(float angle){
velocity.setAngle(angle);
public void setRotation(float angle){
getVel().setAngle(angle);
}
/** @return the bullet's rotation. */
public float rot(){
float angle = Mathf.atan2(velocity.x, velocity.y) * Mathf.radiansToDegrees;
public float getRotation(){
float angle = Mathf.atan2(getVel().x, getVel().y) * Mathf.radiansToDegrees;
if(angle < 0) angle += 360;
return angle;
}
@@ -491,17 +387,218 @@ public class EntityComps{
}
@Component
abstract class TileComp implements Posc, Teamc{
static abstract class TileComp implements Posc, Teamc, Healthc, Tilec{
static final float timeToSleep = 60f * 1;
static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
static int sleepingEntities = 0;
Tile tile;
Block block;
Array<Tile> proximity = new Array<>(8);
PowerModule power;
ItemModule items;
LiquidModule liquids;
ConsumeModule cons;
private Interval timer;
private float timeScale = 1f, timeScaleDuration;
private @Nullable SoundLoop sound;
private boolean sleeping;
private float sleepTime;
/** Sets this tile entity data to this tile, and adds it if necessary. */
public Tilec init(Tile tile, boolean shouldAdd){
this.tile = tile;
this.block = tile.block();
set(tile.drawx(), tile.drawy());
if(block.activeSound != Sounds.none){
sound = new SoundLoop(block.activeSound, block.activeSoundVolume);
}
setHealth(block.health);
setMaxHealth(block.health);
timer = new Interval(block.timers);
if(shouldAdd){
add();
}
return this;
}
public float getTimeScale(){
return timeScale;
}
public boolean consValid(){
return cons.valid();
}
public void consume(){
cons.trigger();
}
public boolean timer(int id, float time){
return timer.get(id, time);
}
/** Scaled delta. */
public float delta(){
return Time.delta() * timeScale;
}
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
public float efficiency(){
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
}
/** Call when nothing is happening to the entity. This increments the internal sleep timer. */
public void sleep(){
sleepTime += Time.delta();
if(!sleeping && sleepTime >= timeToSleep){
remove();
sleeping = true;
sleepingEntities++;
}
}
/** Call when this entity is updating. This wakes it up. */
public void noSleep(){
sleepTime = 0f;
if(sleeping){
add();
sleeping = false;
sleepingEntities--;
}
}
/** Returns the version of this TileEntity IO code.*/
public byte version(){
return 0;
}
public boolean collide(Bulletc other){
return true;
}
public void collision(Bulletc other){
block.handleBulletHit(this, other);
}
//TODO Implement damage!
public void removeFromProximity(){
block.onProximityRemoved(tile);
Point2[] nearby = Edges.getEdges(block.size);
for(Point2 point : nearby){
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
//remove this tile from all nearby tile's proximities
if(other != null){
other.block().onProximityUpdate(other);
if(other.entity != null){
other.entity.getProximity().remove(tile, true);
}
}
}
}
public void updateProximity(){
tmpTiles.clear();
proximity.clear();
Point2[] nearby = Edges.getEdges(block.size);
for(Point2 point : nearby){
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
if(other == null) continue;
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
//add this tile to proximity of nearby tiles
if(!other.entity.getProximity().contains(tile, true)){
other.entity.getProximity().add(tile);
}
tmpTiles.add(other);
}
//using a set to prevent duplicates
for(Tile tile : tmpTiles){
proximity.add(tile);
}
block.onProximityAdded(tile);
block.onProximityUpdate(tile);
for(Tile other : tmpTiles){
other.block().onProximityUpdate(other);
}
}
public Array<Tile> proximity(){
return proximity;
}
/** Tile configuration. Defaults to 0. Used for block rebuilding. */
public int config(){
return 0;
}
public void remove(){
if(sound != null){
sound.stop();
}
}
public void killed(){
Events.fire(new BlockDestroyEvent(tile));
block.breakSound.at(tile);
block.onDestroyed(tile);
tile.remove();
}
public void update(){
timeScaleDuration -= Time.delta();
if(timeScaleDuration <= 0f || !block.canOverdrive){
timeScale = 1f;
}
if(sound != null){
sound.update(getX(), getY(), block.shouldActiveSound(tile));
}
if(block.idleSound != Sounds.none && block.shouldIdleSound(tile)){
loops.play(block.idleSound, this, block.idleSoundVolume);
}
block.update(tile);
if(liquids != null){
liquids.update();
}
if(cons != null){
cons.update();
}
if(power != null){
power.graph.update();
}
}
}
@Component
abstract class TeamComp implements Posc{
abstract class TeamComp implements Posc, Healthc{
transient float x, y;
Team team = Team.sharded;
public @Nullable TileEntity getClosestCore(){
public @Nullable Tilec getClosestCore(){
return state.teams.closestCore(x, y, team);
}
}
@@ -838,14 +935,14 @@ public class EntityComps{
}
void updateMining(){
TileEntity core = getClosestCore();
Tilec core = getClosestCore();
if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && dst(core) < mineTransferRange){
int accepted = core.tile.block().acceptStack(item(), getStack().amount, core.tile, this);
int accepted = core.getTile().block().acceptStack(item(), getStack().amount, core.getTile(), this);
if(accepted > 0){
Call.transferItemTo(item(), accepted,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile);
mineTile.worldy() + Mathf.range(tilesize / 2f), core.getTile());
clearItem();
}
}
@@ -859,10 +956,10 @@ public class EntityComps{
if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMiningSpeed())){
if(dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, this) == 1 && offloadImmediately()){
if(dst(core) < mineTransferRange && core.getTile().block().acceptStack(item, 1, core.getTile(), this) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile);
mineTile.worldy() + Mathf.range(tilesize / 2f), core.getTile());
}else if(acceptsItem(item)){
//this is clientside, since items are synced anyway
ItemTransfer.transferItemToUnit(item,
@@ -927,7 +1024,7 @@ public class EntityComps{
}
}
TileEntity core = getClosestCore();
Tilec core = getClosestCore();
//nothing to build.
if(buildRequest() == null) return;
@@ -996,10 +1093,10 @@ public class EntityComps{
}
/** @return whether this request should be skipped, in favor of the next one. */
boolean shouldSkip(BuildRequest request, @Nullable TileEntity core){
boolean shouldSkip(BuildRequest request, @Nullable Tilec core){
//requests that you have at least *started* are considered
if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false;
return request.stuck && !core.items.has(request.block.requirements);
return request.stuck && !core.getItems().has(request.block.requirements);
}
void removeBuild(int x, int y, boolean breaking){
@@ -1163,7 +1260,7 @@ public class EntityComps{
}
@Component
abstract class HitboxComp implements Posc{
abstract class HitboxComp implements Posc, QuadTreeObject{
transient float x, y;
float hitSize;
@@ -1178,7 +1275,7 @@ public class EntityComps{
lastY = y;
}
void collision(Hitboxc other){
void collision(Hitboxc other, float x, float y){
}
@@ -1194,6 +1291,15 @@ public class EntityComps{
return Intersector.overlapsRect(x - hitSize/2f, y - hitSize/2f, hitSize, hitSize,
other.getX() - other.getHitSize()/2f, other.getY() - other.getHitSize()/2f, other.getHitSize(), other.getHitSize());
}
public void hitbox(Rect rect){
rect.setCentered(x, y, hitSize, hitSize);
}
public void hitboxTile(Rect rect){
float scale = 0.6f;
rect.setCentered(x, y, hitSize * scale, hitSize * scale);
}
}
@Component
@@ -1201,9 +1307,9 @@ public class EntityComps{
private Array<StatusEntry> statuses = new Array<>();
private Bits applied = new Bits(content.getBy(ContentType.status).size);
private float speedMultiplier;
private float damageMultiplier;
private float armorMultiplier;
float speedMultiplier;
float damageMultiplier;
float armorMultiplier;
/** @return damage taken based on status armor multipliers */
float getDamage(float amount){
@@ -1329,10 +1435,11 @@ public class EntityComps{
@Component
@BaseComponent
class EntityComp{
private boolean added;
int id;
boolean isAdded(){
return true;
return added;
}
void init(){}
@@ -1340,11 +1447,11 @@ public class EntityComps{
void update(){}
void remove(){
added = false;
}
void add(){
added = true;
}
boolean isLocal(){
@@ -7,4 +7,7 @@ class EntityDefs{
@EntityDef({BulletComp.class, VelComp.class, TimedComp.class})
class BulletDef{}
@EntityDef({TileComp.class})
class TileDef{}
}
@@ -0,0 +1,4 @@
package mindustry.entities.def;
public class EntityGroupDefs{
}
+2 -2
View File
@@ -8,7 +8,7 @@ import arc.math.geom.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -119,7 +119,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{
return;
}
TileEntity entity = tile.link().entity;
Tilec entity = tile.link().entity;
boolean damage = entity != null;
float flammability = baseFlammability + puddleFlammability;
@@ -4,7 +4,7 @@ import arc.math.Mathf;
import arc.util.Time;
import mindustry.Vars;
import mindustry.entities.Effects;
import mindustry.entities.Effects.Effect;
import mindustry.entities.*;
import mindustry.entities.Effects.EffectRenderer;
import mindustry.world.Tile;
@@ -42,11 +42,11 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
@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;
if(tile == null || tile.entity == null || tile.entity.getItems() == null) return;
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
Time.run(i * 3, () -> create(item, x, y, tile, () -> {}));
}
tile.entity.items.add(item, amount);
tile.entity.getItems().add(item, amount);
}
public static void create(Item item, float fromx, float fromy, Position to, Runnable done){
@@ -12,7 +12,6 @@ import arc.util.pooling.Pools;
import mindustry.content.Bullets;
import mindustry.entities.EntityGroup;
import mindustry.entities.Units;
import mindustry.entities.type.Bullet;
import mindustry.game.Team;
import mindustry.gen.Call;
import mindustry.graphics.Pal;
@@ -1,350 +0,0 @@
package mindustry.entities.type;
import arc.*;
import mindustry.annotations.Annotations.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.ctype.ContentType;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.type.TypeID;
import mindustry.ui.Cicon;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.defense.DeflectorWall.*;
import mindustry.world.blocks.units.CommandCenter.*;
import mindustry.world.blocks.units.UnitFactory.*;
import mindustry.world.meta.*;
import java.io.*;
import static mindustry.Vars.*;
/** Base class for AI units. */
public abstract class BaseUnit extends Unitc implements ShooterTrait{
protected static int timerIndex = 0;
protected static final int timerTarget = timerIndex++;
protected static final int timerTarget2 = timerIndex++;
protected boolean loaded;
protected UnitDef type;
protected Interval timer = new Interval(5);
protected StateMachine state = new StateMachine();
protected TargetTrait target;
protected int spawner = noSpawner;
/** internal constructor used for deserialization, DO NOT USE */
public BaseUnit(){
}
@Remote(called = Loc.server)
public static void onUnitDeath(BaseUnit unit){
if(unit == null) return;
if(net.server() || !net.active()){
UnitDrops.dropItems(unit);
}
unit.onSuperDeath();
unit.type.deathSound.at(unit);
//visual only.
if(net.client()){
Tile tile = world.tile(unit.spawner);
if(tile != null){
tile.block().unitRemoved(tile, unit);
}
unit.spawner = noSpawner;
}
//must run afterwards so the unit's group is not null when sending the removal packet
Core.app.post(unit::remove);
}
@Override
public TypeID getTypeID(){
return type.typeID;
}
@Override
public void onHit(SolidTrait entity){
if(entity instanceof Bullet && ((Bullet)entity).getOwner() instanceof DeflectorEntity && player != null && getTeam() != player.getTeam()){
Core.app.post(() -> {
if(isDead()){
Events.fire(Trigger.phaseDeflectHit);
}
});
}
}
public @Nullable
Tile getSpawner(){
return world.tile(spawner);
}
public boolean isCommanded(){
return indexer.getAllied(team, BlockFlag.comandCenter).size != 0 && indexer.getAllied(team, BlockFlag.comandCenter).first().entity instanceof CommandCenterEntity;
}
public @Nullable UnitCommand getCommand(){
if(isCommanded()){
return indexer.getAllied(team, BlockFlag.comandCenter).first().<CommandCenterEntity>ent().command;
}
return null;
}
/**Called when a command is recieved from the command center.*/
public void onCommand(UnitCommand command){
}
/** Initialize the type and team of this unit. Only call once! */
public void init(UnitDef type, Team team){
if(this.type != null) throw new RuntimeException("This unit is already initialized!");
this.type = type;
this.team = team;
}
/** @return whether this unit counts toward the enemy amount in the wave UI. */
public boolean countsAsEnemy(){
return true;
}
public void setSpawner(Tile tile){
this.spawner = tile.pos();
}
public void rotate(float angle){
rotation = Mathf.slerpDelta(rotation, angle, type.rotateSpeed);
}
public boolean targetHasFlag(BlockFlag flag){
return (target instanceof TileEntity && ((TileEntity)target).tile.block().flags.contains(flag)) ||
(target instanceof Tile && ((Tile)target).block().flags.contains(flag));
}
public void setState(UnitState state){
this.state.set(state);
}
public boolean retarget(){
return timer.get(timerTarget, 20);
}
/** Only runs when the unit has a target. */
public void behavior(){
}
public void updateTargeting(){
if(target == null || (target instanceof Unitc && (target.isDead() || target.getTeam() == team))
|| (target instanceof TileEntity && ((TileEntity)target).tile.entity == null)){
target = null;
}
}
public void targetClosestAllyFlag(BlockFlag flag){
Tile target = Geometry.findClosest(x, y, indexer.getAllied(team, flag));
if(target != null) this.target = target.entity;
}
public void targetClosestEnemyFlag(BlockFlag flag){
Tile target = Geometry.findClosest(x, y, indexer.getEnemy(team, flag));
if(target != null) this.target = target.entity;
}
public void targetClosest(){
TargetTrait newTarget = Units.closestTarget(team, x, y, type.range, u -> type.targetAir || !u.isFlying());
if(newTarget != null){
target = newTarget;
}
}
public @Nullable Tile getClosest(BlockFlag flag){
return Geometry.findClosest(x, y, indexer.getAllied(team, flag));
}
public @Nullable Tile getClosestSpawner(){
return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns());
}
public @Nullable TileEntity getClosestEnemyCore(){
return Vars.state.teams.closestEnemyCore(x, y, team);
}
public UnitState getStartState(){
return null;
}
public boolean isBoss(){
return hasEffect(StatusEffects.boss);
}
@Override
public float getDamageMultipler(){
return status.getDamageMultiplier() * Vars.state.rules.unitDamageMultiplier;
}
@Override
public TextureRegion getIconRegion(){
return type.icon(Cicon.full);
}
@Override
public void interpolate(){
super.interpolate();
if(interpolator.values.length > 0){
rotation = interpolator.values[0];
}
}
@Override
public float maxHealth(){
return type.health * Vars.state.rules.unitHealthMultiplier;
}
@Override
public void update(){
if(isDead()){
//dead enemies should get immediately removed
remove();
return;
}
hitTime -= Time.delta();
if(net.client()){
interpolate();
status.update(this);
return;
}
if(!isFlying() && (world.tileWorld(x, y) != null && !(world.tileWorld(x, y).block() instanceof BuildBlock) && world.tileWorld(x, y).solid())){
kill();
}
avoidOthers();
if(spawner != noSpawner && (world.tile(spawner) == null || !(world.tile(spawner).entity instanceof UnitFactoryEntity))){
kill();
}
updateTargeting();
state.update();
updateVelocityStatus();
if(target != null) behavior();
if(!isFlying()){
clampPosition();
}
}
@Override
public void draw(){
}
@Override
public void removed(){
super.removed();
Tile tile = world.tile(spawner);
if(tile != null && !net.client()){
tile.block().unitRemoved(tile, this);
}
spawner = noSpawner;
}
@Override
public float drawSize(){
return type.hitsize * 10;
}
@Override
public void onDeath(){
Call.onUnitDeath(this);
}
@Override
public void added(){
state.set(getStartState());
if(!loaded){
health(maxHealth());
}
if(isCommanded()){
onCommand(getCommand());
}
}
@Override
public EntityGroup targetGroup(){
return unitGroup;
}
@Override
public byte version(){
return 0;
}
@Override
public void writeSave(DataOutput stream) throws IOException{
super.writeSave(stream);
stream.writeByte(type.id);
stream.writeInt(spawner);
}
@Override
public void readSave(DataInput stream, byte version) throws IOException{
super.readSave(stream, version);
loaded = true;
byte type = stream.readByte();
this.spawner = stream.readInt();
this.type = content.getByID(ContentType.unit, type);
add();
}
@Override
public void write(DataOutput data) throws IOException{
super.writeSave(data);
data.writeByte(type.id);
data.writeInt(spawner);
}
@Override
public void read(DataInput data) throws IOException{
float lastx = x, lasty = y, lastrot = rotation;
super.readSave(data, version());
this.type = content.getByID(ContentType.unit, data.readByte());
this.spawner = data.readInt();
interpolator.read(lastx, lasty, x, y, rotation);
rotation = lastrot;
x = lastx;
y = lasty;
}
public void onSuperDeath(){
super.onDeath();
}
}
@@ -1,322 +0,0 @@
package mindustry.entities.type;
import mindustry.annotations.Annotations.*;
import arc.math.*;
import arc.math.geom.*;
import arc.util.*;
import arc.util.pooling.Pool.*;
import arc.util.pooling.*;
import mindustry.entities.*;
import mindustry.entities.bullet.*;
import mindustry.entities.effect.*;
import mindustry.game.*;
import mindustry.graphics.*;
import mindustry.world.*;
import static mindustry.Vars.*;
public class Bullet extends SolidEntity implements DamageTrait, Scaled, Poolable, DrawTrait, VelocityTrait, TimeTrait, TeamTrait, AbsorbTrait{
public Interval timer = new Interval(3);
private float lifeScl;
private Team team;
private Object data;
private boolean supressCollision, supressOnce, initialized, deflected;
protected BulletType type;
protected Entity owner;
protected float time;
/** Internal use only! */
public Bullet(){
}
public static Bullet create(BulletType type, TeamTrait owner, float x, float y, float angle){
return create(type, owner, owner.getTeam(), x, y, angle);
}
public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle){
return create(type, owner, team, x, y, angle, 1f);
}
public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){
return create(type, owner, team, x, y, angle, velocityScl, 1f, null);
}
public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
return create(type, owner, team, x, y, angle, velocityScl, lifetimeScl, null);
}
public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl, Object data){
Bullet bullet = Pools.obtain(Bullet.class, Bullet::new);
bullet.type = type;
bullet.owner = owner;
bullet.data = data;
bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl);
if(type.keepVelocity){
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).velocity() : Vec2.ZERO);
}
bullet.team = team;
bullet.type = type;
bullet.lifeScl = lifetimeScl;
bullet.set(x - bullet.velocity.x * Time.delta(), y - bullet.velocity.y * Time.delta());
bullet.add();
return bullet;
}
public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle){
return create(type, parent.owner, parent.team, x, y, angle);
}
public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){
return create(type, parent.owner, parent.team, x, y, angle, velocityScl);
}
@Remote(called = Loc.server, unreliable = true)
public static void createBullet(BulletType type, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){
create(type, null, team, x, y, angle, velocityScl, lifetimeScl, null);
}
public Entity getOwner(){
return owner;
}
public boolean collidesTiles(){
return type.collidesTiles;
}
public void deflect(){
supressCollision = true;
supressOnce = true;
deflected = true;
}
public boolean isDeflected(){
return deflected;
}
public BulletType getBulletType(){
return type;
}
public void resetOwner(Entity entity, Team team){
this.owner = entity;
this.team = team;
}
public void scaleTime(float add){
time += add;
}
public Object getData(){
return data;
}
public void setData(Object data){
this.data = data;
}
public float damageMultiplier(){
if(owner instanceof Unitc){
return ((Unitc)owner).getDamageMultipler();
}
return 1f;
}
@Override
public void killed(Entity other){
if(owner instanceof KillerTrait){
((KillerTrait)owner).killed(other);
}
}
@Override
public void absorb(){
supressCollision = true;
remove();
}
@Override
public float drawSize(){
return type.drawSize;
}
@Override
public float damage(){
if(owner instanceof Lightning && data instanceof Float){
return (Float)data;
}
return type.damage * damageMultiplier();
}
@Override
public Team getTeam(){
return team;
}
@Override
public float getShieldDamage(){
return Math.max(damage(), type.splashDamage);
}
@Override
public boolean collides(SolidTrait other){
return type.collides && (other != owner && !(other instanceof DamageTrait)) && !supressCollision && !(other instanceof Unitc && ((Unitc)other).isFlying() && !type.collidesAir);
}
@Override
public void collision(SolidTrait other, float x, float y){
if(!type.pierce) remove();
type.hit(this, x, y);
if(other instanceof Unitc){
Unitc unit = (Unitc)other;
unit.velocity().add(Tmp.v3.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.mass()));
unit.applyEffect(type.status, type.statusDuration);
}
}
@Override
public void update(){
type.update(this);
x += velocity.x * Time.delta();
y += velocity.y * Time.delta();
velocity.scl(Mathf.clamp(1f - type.drag * Time.delta()));
time += Time.delta() * 1f / (lifeScl);
time = Mathf.clamp(time, 0, type.lifetime);
if(time >= type.lifetime){
if(!supressCollision) type.despawned(this);
remove();
}
if(type.hitTiles && collidesTiles() && !supressCollision && initialized){
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
Tile tile = world.ltile(x, y);
if(tile == null) return false;
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
if(tile.getTeam() != team){
tile.entity.collision(this);
}
if(!supressCollision){
type.hitTile(this, tile);
remove();
}
return true;
}
return false;
});
}
if(supressOnce){
supressCollision = false;
supressOnce = false;
}
initialized = true;
}
@Override
public void reset(){
type = null;
owner = null;
velocity.setZero();
time = 0f;
timer.clear();
lifeScl = 1f;
team = null;
data = null;
supressCollision = false;
supressOnce = false;
deflected = false;
initialized = false;
}
@Override
public void hitbox(Rect rect){
rect.setSize(type.hitSize).setCenter(x, y);
}
@Override
public void hitboxTile(Rect rect){
rect.setSize(type.hitSize).setCenter(x, y);
}
@Override
public float lifetime(){
return type.lifetime;
}
@Override
public void time(float time){
this.time = time;
}
@Override
public float time(){
return time;
}
@Override
public void removed(){
Pools.free(this);
}
@Override
public EntityGroup targetGroup(){
return bulletGroup;
}
@Override
public void added(){
type.init(this);
}
@Override
public void draw(){
type.draw(this);
renderer.lights.add(x, y, 16f, Pal.powerLight, 0.3f);
}
@Override
public float fin(){
return time / type.lifetime;
}
@Override
public Vec2 velocity(){
return velocity;
}
public void velocity(float speed, float angle){
velocity.set(0, speed).setAngle(angle);
}
public void limit(float f){
velocity.limit(f);
}
/** Sets the bullet's rotation in degrees. */
public void rot(float angle){
velocity.setAngle(angle);
}
/** @return the bullet's rotation. */
public float rot(){
float angle = Mathf.atan2(velocity.x, velocity.y) * Mathf.radiansToDegrees;
if(angle < 0) angle += 360;
return angle;
}
}
+6 -6
View File
@@ -59,8 +59,8 @@ public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
public @Nullable NetConnection con;
public boolean isLocal = false;
public Interval timer = new Interval(6);
public TargetTrait target;
public TargetTrait moveTarget;
public Teamc target;
public Teamc moveTarget;
public @Nullable String lastText;
public float textFadeTime;
@@ -604,7 +604,7 @@ public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
protected void updateTouch(){
if(Units.invalidateTarget(target, this) &&
!(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range && !(((TileEntity)target).block instanceof BuildBlock))){
!(target instanceof Tilec && ((Tilec)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range && !(((Tilec)target).block instanceof BuildBlock))){
target = null;
}
@@ -619,7 +619,7 @@ public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
if(moveTarget != null && !moveTarget.isDead()){
targetX = moveTarget.getX();
targetY = moveTarget.getY();
boolean tapping = moveTarget instanceof TileEntity && moveTarget.getTeam() == team;
boolean tapping = moveTarget instanceof Tilec && moveTarget.getTeam() == team;
attractDst = 0f;
if(tapping){
@@ -628,7 +628,7 @@ public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
if(dst(moveTarget) <= 2f * Time.delta()){
if(tapping && !isDead()){
Tile tile = ((TileEntity)moveTarget).tile;
Tile tile = ((Tilec)moveTarget).tile;
tile.block().tapped(tile, this);
}
@@ -695,7 +695,7 @@ public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
setMineTile(null);
}
}
}else if(target.isValid() || (target instanceof TileEntity && ((TileEntity)target).damaged() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range)){
}else if(target.isValid() || (target instanceof Tilec && ((Tilec)target).damaged() && target.getTeam() == team && mech.canHeal && dst(target) < mech.range)){
//rotate toward and shoot the target
if(mech.faceTarget){
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);
@@ -6,10 +6,8 @@ import arc.Events;
import arc.struct.Array;
import arc.struct.ObjectSet;
import arc.math.geom.Point2;
import arc.math.geom.Vec2;
import arc.util.*;
import arc.util.ArcAnnotate.*;
import mindustry.entities.EntityGroup;
import mindustry.game.*;
import mindustry.game.EventType.BlockDestroyEvent;
import mindustry.gen.*;
@@ -21,7 +19,7 @@ import java.io.*;
import static mindustry.Vars.*;
public class TileEntity{
public class Tilec__{
public static final float timeToSleep = 60f * 1; //1 second to fall asleep
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
/** This value is only used for debugging. */
@@ -63,7 +61,7 @@ public class TileEntity{
}
/** Sets this tile entity data to this tile, and adds it if necessary. */
public TileEntity init(Tile tile, boolean shouldAdd){
public Tilec init(Tile tile, boolean shouldAdd){
this.tile = tile;
x = tile.drawx();
y = tile.drawy();
@@ -148,11 +146,11 @@ public class TileEntity{
return 0;
}
public boolean collide(Bullet other){
public boolean collide(Bulletc other){
return true;
}
public void collision(Bullet other){
public void collision(Bulletc other){
block.handleBulletHit(this, other);
}
@@ -39,7 +39,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
public void update(){
BuildEntity entity = (BuildEntity)target;
TileEntity core = getClosestCore();
Tilec core = getClosestCore();
if(isBuilding() && entity == null && canRebuild()){
target = world.tile(buildRequest().x, buildRequest().y);
@@ -97,7 +97,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{
}
}else{
incDrones(playerTarget);
TargetTrait prev = target;
Teamc prev = target;
target = playerTarget;
float dst = 90f + (id % 10)*3;
float tdst = dst(target);
@@ -12,7 +12,6 @@ import mindustry.entities.bullet.*;
import mindustry.entities.type.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.meta.*;
@@ -34,7 +33,7 @@ public class GroundUnit extends BaseUnit{
}
public void update(){
TileEntity core = getClosestEnemyCore();
Tilec core = getClosestEnemyCore();
if(core == null){
Tile closestSpawn = getClosestSpawner();
@@ -251,7 +250,7 @@ public class GroundUnit extends BaseUnit{
Tile tile = world.tileWorld(x, y);
if(tile == null) return;
Tile targetTile = pathfinder.getTargetTile(tile, enemy, PathTarget.enemyCores);
TileEntity core = getClosestCore();
Tilec core = getClosestCore();
if(tile == targetTile || core == null || dst(core) < 120f) return;
@@ -3,7 +3,7 @@ package mindustry.entities.type.base;
import arc.math.Mathf;
import arc.util.Structs;
import mindustry.content.Blocks;
import mindustry.entities.type.TileEntity;
import mindustry.gen.*;
import mindustry.entities.units.UnitState;
import mindustry.gen.Call;
import mindustry.type.Item;
@@ -28,7 +28,7 @@ public class MinerDrone extends BaseDrone implements MinerTrait{
}
public void update(){
TileEntity entity = getClosestCore();
Tilec entity = getClosestCore();
if(entity == null) return;
@@ -90,7 +90,7 @@ public class MinerDrone extends BaseDrone implements MinerTrait{
if(target == null) return;
TileEntity tile = (TileEntity)target;
Tilec tile = (Tilec)target;
if(dst(target) < type.range){
if(tile.tile.block().acceptStack(item.item, item.amount, tile.tile, MinerDrone.this) > 0){
@@ -169,10 +169,10 @@ public class MinerDrone extends BaseDrone implements MinerTrait{
}
protected void findItem(){
TileEntity entity = getClosestCore();
Tilec entity = getClosestCore();
if(entity == null){
return;
}
targetItem = Structs.findMin(type.toMine, indexer::hasOre, (a, b) -> -Integer.compare(entity.items.get(a), entity.items.get(b)));
targetItem = Structs.findMin(type.toMine, indexer::hasOre, (a, b) -> -Integer.compare(entity.getItems().get(a), entity.getItems().get(b)));
}
}
@@ -1,7 +1,7 @@
package mindustry.entities.type.base;
import mindustry.entities.Units;
import mindustry.entities.type.TileEntity;
import mindustry.gen.*;
import mindustry.entities.units.UnitState;
import mindustry.world.Pos;
import mindustry.world.Tile;
@@ -24,7 +24,7 @@ public class RepairDrone extends BaseDrone{
target = Units.findDamagedTile(team, x, y);
}
if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){
if(target instanceof Tilec && ((Tilec)target).block instanceof BuildBlock){
target = null;
}
@@ -58,7 +58,7 @@ public class RepairDrone extends BaseDrone{
@Override
public void write(DataOutput data) throws IOException{
super.write(data);
data.writeInt(state.is(repair) && target instanceof TileEntity ? ((TileEntity)target).tile.pos() : Pos.invalid);
data.writeInt(state.is(repair) && target instanceof Tilec ? ((Tilec)target).tile.pos() : Pos.invalid);
}
@Override
@@ -3,8 +3,7 @@ package mindustry.entities.units;
import arc.math.Mathf;
import mindustry.Vars;
import mindustry.content.Items;
import mindustry.entities.type.BaseUnit;
import mindustry.entities.type.TileEntity;
import mindustry.gen.*;
import mindustry.gen.Call;
import mindustry.type.Item;
import static mindustry.Vars.*;
@@ -18,7 +17,7 @@ public class UnitDrops{
return;
}
TileEntity core = unit.getClosestEnemyCore();
Tilec core = unit.getClosestEnemyCore();
if(core == null || core.dst(unit) > Vars.mineTransferRange){
return;