Cleanup continues
This commit is contained in:
@@ -73,7 +73,7 @@ public class Damage{
|
||||
}
|
||||
}
|
||||
|
||||
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||
public static void collideLine(Bulletc hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||
collideLine(hitter, team, effect, x, y, angle, length, false);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ public class Damage{
|
||||
* Damages entities in a line.
|
||||
* 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){
|
||||
public static void collideLine(Bulletc hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){
|
||||
collidedBlocks.clear();
|
||||
tr.trns(angle, length);
|
||||
Intc2 collider = (cx, cy) -> {
|
||||
@@ -89,7 +89,7 @@ public class Damage{
|
||||
if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.id && tile.entity.collide(hitter)){
|
||||
tile.entity.collision(hitter);
|
||||
collidedBlocks.add(tile.pos());
|
||||
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
|
||||
hitter.type().hit(hitter, tile.worldx(), tile.worldy());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -184,7 +184,7 @@ public class Damage{
|
||||
entity.damage(amount);
|
||||
//TODO better velocity displacement
|
||||
float dst = tr.set(entity.getX() - x, entity.getY() - y).len();
|
||||
entity.velocity().add(tr.setLength((1f - dst / radius) * 2f / entity.mass()));
|
||||
entity.vel().add(tr.setLength((1f - dst / radius) * 2f / entity.mass()));
|
||||
|
||||
if(complete && damage >= 9999999f && entity == player){
|
||||
Events.fire(Trigger.exclusionDeath);
|
||||
@@ -235,8 +235,8 @@ public class Damage{
|
||||
|
||||
//apply damage to entity if needed
|
||||
if(tile.entity != null && tile.getTeam() != team){
|
||||
int health = (int)tile.entity.health;
|
||||
if(tile.entity.health > 0){
|
||||
int health = (int)tile.entity.health();
|
||||
if(tile.entity.health() > 0){
|
||||
tile.entity.damage(scaledDamage);
|
||||
scaledDamage -= health;
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ public class Effect{
|
||||
/** Clip size. */
|
||||
public float size;
|
||||
|
||||
public boolean ground;
|
||||
public float groundDuration;
|
||||
|
||||
public Effect(float life, float clipsize, Cons<EffectContainer> renderer){
|
||||
this.id = lastid++;
|
||||
this.lifetime = life;
|
||||
@@ -27,6 +30,17 @@ public class Effect{
|
||||
this(life, 28f, renderer);
|
||||
}
|
||||
|
||||
public Effect ground(){
|
||||
ground = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effect ground(float duration){
|
||||
ground = true;
|
||||
this.groundDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void at(Position pos){
|
||||
Effects.createEffect(this, pos.getX(), pos.getY(), 0, Color.white, null);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,7 @@ import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.type.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -40,13 +38,14 @@ public class Effects{
|
||||
Rect pos = Tmp.r2.setSize(effect.size).setCenter(x, y);
|
||||
|
||||
if(view.overlaps(pos)){
|
||||
EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new);
|
||||
entity.effect = effect;
|
||||
entity.color.set(color);
|
||||
entity.rotation = rotation;
|
||||
entity.data = data;
|
||||
entity.id++;
|
||||
entity.set(x, y);
|
||||
//TODO implement create() method here.
|
||||
//EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new);
|
||||
//entity.effect = effect;
|
||||
//entity.color.set(color);
|
||||
//entity.rotation = rotation;
|
||||
//entity.data = data;
|
||||
//entity.id++;
|
||||
//entity.set(x, y);
|
||||
//if(data instanceof Entity){
|
||||
// entity.setParent((Entity)data);
|
||||
//}
|
||||
|
||||
@@ -3,7 +3,7 @@ package mindustry.entities;
|
||||
import arc.func.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.*;
|
||||
@@ -18,7 +18,7 @@ public class Units{
|
||||
private static boolean boolResult;
|
||||
|
||||
/** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/
|
||||
public static boolean canInteract(Player player, Tile tile){
|
||||
public static boolean canInteract(Playerc player, Tile tile){
|
||||
return player == null || tile == null || tile.interactable(player.team());
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public class Units{
|
||||
|
||||
/** Iterates over all units in a rectangle. */
|
||||
public static void nearby(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
|
||||
unitGroup.intersect(x, y, width, height, u -> {
|
||||
Groups.unit.intersect(x, y, width, height, u -> {
|
||||
if(u.getTeam() == team){
|
||||
cons.get(u);
|
||||
}
|
||||
@@ -157,7 +157,7 @@ public class Units{
|
||||
|
||||
/** Iterates over all units in a circle around this position. */
|
||||
public static void nearby(Team team, float x, float y, float radius, Cons<Unitc> cons){
|
||||
unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
|
||||
Groups.unit.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
|
||||
if(unit.getTeam() == team && unit.withinDst(x, y, radius)){
|
||||
cons.get(unit);
|
||||
}
|
||||
@@ -166,7 +166,7 @@ public class Units{
|
||||
|
||||
/** 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);
|
||||
Groups.unit.intersect(x, y, width, height, cons);
|
||||
}
|
||||
|
||||
/** Iterates over all units in a rectangle. */
|
||||
@@ -176,7 +176,7 @@ public class Units{
|
||||
|
||||
/** Iterates over all units that are enemies of this team. */
|
||||
public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons<Unitc> cons){
|
||||
unitGroup.intersect(x, y, width, height, u -> {
|
||||
Groups.unit.intersect(x, y, width, height, u -> {
|
||||
if(team.isEnemy(u.getTeam())){
|
||||
cons.get(u);
|
||||
}
|
||||
@@ -190,11 +190,11 @@ public class Units{
|
||||
|
||||
/** Iterates over all units. */
|
||||
public static void all(Cons<Unitc> cons){
|
||||
unitGroup.all().each(cons);
|
||||
Groups.unit.all().each(cons);
|
||||
}
|
||||
|
||||
public static void each(Team team, Cons<BaseUnit> cons){
|
||||
unitGroup.all().each(t -> t.getTeam() == team, cons);
|
||||
public static void each(Team team, Cons<Unitc> cons){
|
||||
Groups.unit.all().each(t -> t.getTeam() == team, cons);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ArtilleryBulletType extends BasicBulletType{
|
||||
super.update(b);
|
||||
|
||||
if(b.timer.get(0, 3 + b.fslope() * 2f)){
|
||||
trailEffect.at(b.x, b.y, b.fslope() * 4f, backColor);
|
||||
trailEffect.at(b.x(), b.y(), b.fslope() * 4f, backColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ public class ArtilleryBulletType extends BasicBulletType{
|
||||
float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout());
|
||||
|
||||
Draw.color(backColor);
|
||||
Draw.rect(backRegion, b.x, b.y, bulletWidth * scale, height * scale, b.rot() - 90);
|
||||
Draw.rect(backRegion, b.x(), b.y(), bulletWidth * scale, height * scale, b.rotation() - 90);
|
||||
Draw.color(frontColor);
|
||||
Draw.rect(frontRegion, b.x, b.y, bulletWidth * scale, height * scale, b.rot() - 90);
|
||||
Draw.rect(frontRegion, b.x(), b.y(), bulletWidth * scale, height * scale, b.rotation() - 90);
|
||||
Draw.color();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ public class BasicBulletType extends BulletType{
|
||||
float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout());
|
||||
|
||||
Draw.color(backColor);
|
||||
Draw.rect(backRegion, b.x, b.y, bulletWidth, height, b.rot() - 90);
|
||||
Draw.rect(backRegion, b.x(), b.y(), bulletWidth, height, b.rotation() - 90);
|
||||
Draw.color(frontColor);
|
||||
Draw.rect(frontRegion, b.x, b.y, bulletWidth, height, b.rot() - 90);
|
||||
Draw.rect(frontRegion, b.x(), b.y(), bulletWidth, height, b.rotation() - 90);
|
||||
Draw.color();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ public abstract class BulletType extends Content{
|
||||
|
||||
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.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).vel() : Vec2.ZERO);
|
||||
}
|
||||
|
||||
bullet.team = team;
|
||||
|
||||
@@ -29,7 +29,7 @@ public class FlakBulletType extends BasicBulletType{
|
||||
if(b.getData() instanceof Integer) return;
|
||||
|
||||
if(b.timer.get(2, 6)){
|
||||
Units.nearbyEnemies(b.team(), rect.setSize(explodeRange * 2f).setCenter(b.x, b.y), unit -> {
|
||||
Units.nearbyEnemies(b.team(), rect.setSize(explodeRange * 2f).setCenter(b.x(), b.y()), unit -> {
|
||||
if(b.getData() instanceof Float) return;
|
||||
|
||||
if(unit.dst(b) < explodeRange){
|
||||
|
||||
@@ -36,9 +36,9 @@ public class HealBulletType extends BulletType{
|
||||
public void draw(Bulletc b){
|
||||
Draw.color(backColor);
|
||||
Lines.stroke(bulletWidth);
|
||||
Lines.lineAngleCenter(b.x, b.y, b.rot(), bulletHeight);
|
||||
Lines.lineAngleCenter(b.x(), b.y(), b.rotation(), bulletHeight);
|
||||
Draw.color(frontColor);
|
||||
Lines.lineAngleCenter(b.x, b.y, b.rot(), bulletHeight / 2f);
|
||||
Lines.lineAngleCenter(b.x(), b.y(), b.rotation(), bulletHeight / 2f);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public class LaserBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void init(Bulletc b){
|
||||
Damage.collideLine(b, b.team(), hitEffect, b.x, b.y, b.rot(), length);
|
||||
Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,18 +51,18 @@ public class LaserBulletType extends BulletType{
|
||||
float cwidth = width;
|
||||
float compound = 1f;
|
||||
|
||||
Lines.lineAngle(b.x, b.y, b.rot(), baseLen);
|
||||
Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen);
|
||||
Lines.precise(true);
|
||||
for(Color color : colors){
|
||||
Draw.color(color);
|
||||
Lines.stroke((cwidth *= lengthFalloff) * b.fout());
|
||||
Lines.lineAngle(b.x, b.y, b.rot(), baseLen, CapStyle.none);
|
||||
Tmp.v1.trns(b.rot(), baseLen);
|
||||
Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, Lines.getStroke() * 1.22f, cwidth * 2f + width / 2f, b.rot());
|
||||
Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen, CapStyle.none);
|
||||
Tmp.v1.trns(b.rotation(), baseLen);
|
||||
Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, Lines.getStroke() * 1.22f, cwidth * 2f + width / 2f, b.rotation());
|
||||
|
||||
Fill.circle(b.x, b.y, 1f * cwidth * b.fout());
|
||||
Fill.circle(b.x(), b.y(), 1f * cwidth * b.fout());
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(b.x, b.y, sideWidth * b.fout() * cwidth, sideLength * compound, b.rot() + sideAngle * i);
|
||||
Drawf.tri(b.x(), b.y(), sideWidth * b.fout() * cwidth, sideLength * compound, b.rotation() + sideAngle * i);
|
||||
}
|
||||
|
||||
compound *= lengthFalloff;
|
||||
|
||||
@@ -25,6 +25,6 @@ public class LightningBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void init(Bulletc b){
|
||||
Lightning.create(b.team(), lightningColor, damage, b.x, b.y, b.rot(), lightningLength);
|
||||
Lightning.create(b.team(), lightningColor, damage, b.x(), b.y(), b.rotation(), lightningLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class LiquidBulletType extends BulletType{
|
||||
super.update(b);
|
||||
|
||||
if(liquid.canExtinguish()){
|
||||
Tile tile = world.tileWorld(b.x, b.y);
|
||||
Tile tile = world.tileWorld(b.x(), b.y());
|
||||
if(tile != null && Fire.has(tile.x, tile.y)){
|
||||
Fire.extinguish(tile, 100f);
|
||||
b.remove();
|
||||
@@ -61,7 +61,7 @@ public class LiquidBulletType extends BulletType{
|
||||
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);
|
||||
Fill.circle(b.x(), b.y(), 0.5f + b.fout() * 2.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,10 +27,10 @@ public class MassDriverBolt extends BulletType{
|
||||
float w = 11f, h = 13f;
|
||||
|
||||
Draw.color(Pal.bulletYellowBack);
|
||||
Draw.rect("shell-back", b.x, b.y, w, h, b.rot() + 90);
|
||||
Draw.rect("shell-back", b.x(), b.y(), w, h, b.rotation() + 90);
|
||||
|
||||
Draw.color(Pal.bulletYellow);
|
||||
Draw.rect("shell", b.x, b.y, w, h, b.rot() + 90);
|
||||
Draw.rect("shell", b.x(), b.y(), w, h, b.rotation() + 90);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
@@ -92,8 +92,8 @@ public class MassDriverBolt extends BulletType{
|
||||
for(int i = 0; i < data.items.length; i++){
|
||||
int amountDropped = Mathf.random(0, data.items[i]);
|
||||
if(amountDropped > 0){
|
||||
float angle = b.rot() + Mathf.range(100f);
|
||||
Fx.dropItem.at(b.x, b.y, angle, Color.white, content.item(i));
|
||||
float angle = b.rotation() + Mathf.range(100f);
|
||||
Fx.dropItem.at(b.x(), b.y(), angle, Color.white, content.item(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,11 @@ public class MissileBulletType extends BasicBulletType{
|
||||
super.update(b);
|
||||
|
||||
if(Mathf.chance(Time.delta() * 0.2)){
|
||||
Fx.missileTrail.at(b.x, b.y, 2f, trailColor);
|
||||
Fx.missileTrail.at(b.x(), b.y(), 2f, trailColor);
|
||||
}
|
||||
|
||||
if(weaveMag > 0){
|
||||
b.velocity().rotate(Mathf.sin(Time.time() + b.id * 4422, weaveScale, weaveMag) * Time.delta());
|
||||
b.vel().rotate(Mathf.sin(Time.time() + b.id * 4422, weaveScale, weaveMag) * Time.delta());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import arc.util.pooling.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
@@ -25,7 +26,9 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.net.Packets.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
@@ -179,6 +182,11 @@ public class EntityComps{
|
||||
|
||||
Object data;
|
||||
BulletType type;
|
||||
Interval timer = new Interval(6);
|
||||
|
||||
public boolean timer(int index, float time){
|
||||
return timer.get(index, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamage(){
|
||||
@@ -662,6 +670,136 @@ public class EntityComps{
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
abstract class PlayerComp implements UnitController, Entityc, Syncc{
|
||||
@Nullable Unitc unit;
|
||||
|
||||
@ReadOnly Team team = Team.sharded;
|
||||
String name = "noname";
|
||||
@Nullable NetConnection con;
|
||||
boolean admin, typing;
|
||||
Color color = new Color();
|
||||
float mouseX, mouseY;
|
||||
|
||||
@Nullable String lastText;
|
||||
float textFadeTime;
|
||||
|
||||
public void update(){
|
||||
if(unit != null){
|
||||
x(unit.x());
|
||||
y(unit.y());
|
||||
unit.team(team);
|
||||
}
|
||||
textFadeTime -= Time.delta() / (60 * 5);
|
||||
}
|
||||
|
||||
public void team(Team team){
|
||||
if(unit != null){
|
||||
unit.team(team);
|
||||
}
|
||||
}
|
||||
|
||||
public void unit(Unitc unit){
|
||||
this.unit = unit;
|
||||
unit.team(team);
|
||||
}
|
||||
|
||||
String uuid(){
|
||||
return con == null ? "AAAAAAAA" : con.uuid;
|
||||
}
|
||||
|
||||
String usid(){
|
||||
return con == null ? "AAAAAAAA" : con.usid;
|
||||
}
|
||||
|
||||
void kick(KickReason reason){
|
||||
con.kick(reason);
|
||||
}
|
||||
|
||||
void kick(String reason){
|
||||
con.kick(reason);
|
||||
}
|
||||
|
||||
void drawName(){
|
||||
BitmapFont font = Fonts.def;
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
final float nameHeight = 11;
|
||||
final float textHeight = 15;
|
||||
|
||||
boolean ints = font.usesIntegerPositions();
|
||||
font.setUseIntegerPositions(false);
|
||||
font.getData().setScale(0.25f / Scl.scl(1f));
|
||||
layout.setText(font, name);
|
||||
|
||||
if(!isLocal()){
|
||||
Draw.color(0f, 0f, 0f, 0.3f);
|
||||
Fill.rect(unit.x(), unit.y() + nameHeight - layout.height / 2, layout.width + 2, layout.height + 3);
|
||||
Draw.color();
|
||||
font.setColor(color);
|
||||
font.draw(name, unit.x(), unit.y() + nameHeight, 0, Align.center, false);
|
||||
|
||||
if(admin){
|
||||
float s = 3f;
|
||||
Draw.color(color.r * 0.5f, color.g * 0.5f, color.b * 0.5f, 1f);
|
||||
Draw.rect(Icon.adminSmall.getRegion(), unit.x() + layout.width / 2f + 2 + 1, unit.y() + nameHeight - 1.5f, s, s);
|
||||
Draw.color(color);
|
||||
Draw.rect(Icon.adminSmall.getRegion(), unit.x() + layout.width / 2f + 2 + 1, unit.y() + nameHeight - 1f, s, s);
|
||||
}
|
||||
}
|
||||
|
||||
if(Core.settings.getBool("playerchat") && ((textFadeTime > 0 && lastText != null) || typing)){
|
||||
String text = textFadeTime <= 0 || lastText == null ? "[LIGHT_GRAY]" + Strings.animated(Time.time(), 4, 15f, ".") : lastText;
|
||||
float width = 100f;
|
||||
float visualFadeTime = 1f - Mathf.curve(1f - textFadeTime, 0.9f);
|
||||
font.setColor(1f, 1f, 1f, textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime);
|
||||
|
||||
layout.setText(font, text, Color.white, width, Align.bottom, true);
|
||||
|
||||
Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime));
|
||||
Fill.rect(unit.x(), unit.y() + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3);
|
||||
font.draw(text, unit.x() - width/2f, unit.y() + textHeight + layout.height, width, Align.center, true);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
Pools.free(layout);
|
||||
font.getData().setScale(1f);
|
||||
font.setColor(Color.white);
|
||||
font.setUseIntegerPositions(ints);
|
||||
}
|
||||
|
||||
void sendMessage(String text){
|
||||
if(isLocal()){
|
||||
if(ui != null){
|
||||
ui.chatfrag.addMessage(text, null);
|
||||
}
|
||||
}else{
|
||||
Call.sendMessage(con, text, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
void sendMessage(String text, Playerc from){
|
||||
sendMessage(text, from, NetClient.colorizeName(from.id(), from.name()));
|
||||
}
|
||||
|
||||
void sendMessage(String text, Playerc from, String fromName){
|
||||
if(isLocal()){
|
||||
if(ui != null){
|
||||
ui.chatfrag.addMessage(text, fromName);
|
||||
}
|
||||
}else{
|
||||
Call.sendMessage(con, text, fromName, from);
|
||||
}
|
||||
}
|
||||
|
||||
PlayerInfo getInfo(){
|
||||
if(isLocal()){
|
||||
throw new IllegalArgumentException("Local players cannot be traced and do not have info.");
|
||||
}else{
|
||||
return netServer.admins.getInfo(uuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
abstract class TeamComp implements Posc, Healthc{
|
||||
transient float x, y;
|
||||
@@ -1194,6 +1332,25 @@ public class EntityComps{
|
||||
current.progress = entity.progress;
|
||||
}
|
||||
|
||||
|
||||
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
|
||||
void drawBuildRequests(){
|
||||
|
||||
for(BuildRequest request : requests){
|
||||
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){
|
||||
control.input.drawBreaking(request);
|
||||
}else{
|
||||
request.block.drawRequest(request, control.input.allRequests(),
|
||||
Build.validPlace(team(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request));
|
||||
}
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
/** @return whether this request should be skipped, in favor of the next one. */
|
||||
boolean shouldSkip(BuildRequest request, @Nullable Tilec core){
|
||||
//requests that you have at least *started* are considered
|
||||
@@ -1557,7 +1714,7 @@ public class EntityComps{
|
||||
}
|
||||
|
||||
boolean isLocal(){
|
||||
return this == Vars.player;
|
||||
return this instanceof Unitc && ((Unitc)this).controller() == player || this == player;
|
||||
}
|
||||
|
||||
<T> T as(Class<T> type){
|
||||
@@ -1566,5 +1723,13 @@ public class EntityComps{
|
||||
|
||||
@InternalImpl
|
||||
abstract int classId();
|
||||
|
||||
void read(DataInput input) throws IOException{
|
||||
//TODO dynamic io
|
||||
}
|
||||
|
||||
void write(DataOutput output) throws IOException{
|
||||
//TODO dynamic io
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,7 @@ class EntityDefs{
|
||||
|
||||
@EntityDef({DecalComp.class})
|
||||
class DecalDef{}
|
||||
|
||||
@EntityDef({PlayerComp.class})
|
||||
class PlayerDef{}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,11 @@ import mindustry.entities.def.EntityComps.*;
|
||||
|
||||
public class EntityGroupDefs{
|
||||
|
||||
@GroupDef(PlayerComp.class)
|
||||
void player(){
|
||||
|
||||
}
|
||||
|
||||
@GroupDef(UnitComp.class)
|
||||
void unit(){
|
||||
|
||||
@@ -16,7 +21,12 @@ public class EntityGroupDefs{
|
||||
}
|
||||
|
||||
@GroupDef(DrawComp.class)
|
||||
void drawers(){
|
||||
void drawer(){
|
||||
|
||||
}
|
||||
|
||||
@GroupDef(SyncComp.class)
|
||||
void sync(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
package mindustry.entities.effect;
|
||||
|
||||
import arc.math.Mathf;
|
||||
import arc.util.Time;
|
||||
import mindustry.Vars;
|
||||
import mindustry.entities.Effects;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.Effects.EffectRenderer;
|
||||
import mindustry.world.Tile;
|
||||
|
||||
/**
|
||||
* A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.
|
||||
*/
|
||||
public class GroundEffectEntity extends EffectEntity{
|
||||
private boolean once;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
GroundEffect effect = (GroundEffect)this.effect;
|
||||
|
||||
if(effect.isStatic){
|
||||
time += Time.delta();
|
||||
|
||||
time = Mathf.clamp(time, 0, effect.staticLife);
|
||||
|
||||
if(!once && time >= lifetime()){
|
||||
once = true;
|
||||
time = 0f;
|
||||
Tile tile = Vars.world.tileWorld(x, y);
|
||||
if(tile != null && tile.floor().isLiquid){
|
||||
remove();
|
||||
}
|
||||
}else if(once && time >= effect.staticLife){
|
||||
remove();
|
||||
}
|
||||
}else{
|
||||
super.update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
GroundEffect effect = (GroundEffect)this.effect;
|
||||
|
||||
if(once && effect.isStatic)
|
||||
Effects.renderEffect(id, effect, color, lifetime(), rotation, x, y, data);
|
||||
else
|
||||
Effects.renderEffect(id, effect, color, time, rotation, x, y, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
super.reset();
|
||||
once = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* An effect that is rendered on the ground layer as opposed to the top layer.
|
||||
*/
|
||||
public static class GroundEffect extends Effect{
|
||||
/**
|
||||
* How long this effect stays on the ground when static.
|
||||
*/
|
||||
public final float staticLife;
|
||||
/**
|
||||
* If true, this effect will stop and lie on the ground for a specific duration,
|
||||
* after its initial lifetime is over.
|
||||
*/
|
||||
public final boolean isStatic;
|
||||
|
||||
public GroundEffect(float life, float staticLife, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = staticLife;
|
||||
this.isStatic = true;
|
||||
}
|
||||
|
||||
public GroundEffect(boolean isStatic, float life, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = 0f;
|
||||
this.isStatic = isStatic;
|
||||
}
|
||||
|
||||
public GroundEffect(float life, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = 0f;
|
||||
this.isStatic = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import arc.util.pooling.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
@@ -201,7 +201,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
|
||||
unit.applyEffect(liquid.effect, 60 * 2);
|
||||
|
||||
if(unit.velocity().len() > 0.1){
|
||||
if(unit.vel().len() > 0.1){
|
||||
Fx.ripple.at(liquid.color, unit.x, unit.y);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,914 +0,0 @@
|
||||
package mindustry.entities.type;
|
||||
|
||||
import arc.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import arc.struct.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.ContentType;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.io.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Player extends Unitc implements BuilderMinerTrait, ShooterTrait{
|
||||
public static final int timerSync = 2;
|
||||
public static final int timerAbility = 3;
|
||||
private static final float liftoffBoost = 0.2f;
|
||||
|
||||
private static final Rect rect = new Rect();
|
||||
|
||||
//region instance variables
|
||||
|
||||
public float baseRotation;
|
||||
public float pointerX, pointerY;
|
||||
public String name = "noname";
|
||||
public @Nullable String uuid, usid;
|
||||
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();
|
||||
public UnitDef mech = Mechs.starter;
|
||||
public SpawnerTrait spawner, lastSpawner;
|
||||
public int respawns;
|
||||
|
||||
public @Nullable NetConnection con;
|
||||
public boolean isLocal = false;
|
||||
public Interval timer = new Interval(6);
|
||||
public Teamc target;
|
||||
public Teamc moveTarget;
|
||||
|
||||
public @Nullable String lastText;
|
||||
public float textFadeTime;
|
||||
|
||||
private float walktime, itemtime;
|
||||
private Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
private Tile mining;
|
||||
private Vec2 movement = new Vec2();
|
||||
private boolean moved;
|
||||
|
||||
//endregion
|
||||
|
||||
//region unit and event overrides, utility methods
|
||||
|
||||
@Remote(targets = Loc.server, called = Loc.server)
|
||||
public static void onPlayerDeath(Player player){
|
||||
if(player == null) return;
|
||||
|
||||
player.dead = true;
|
||||
player.placeQueue.clear();
|
||||
player.onDeath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamageMultipler(){
|
||||
return status.getDamageMultiplier() * state.rules.playerDamageMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRespawn(Tile tile){
|
||||
velocity.setZero();
|
||||
boostHeat = 1f;
|
||||
achievedFlight = true;
|
||||
rotation = 90f;
|
||||
baseRotation = 90f;
|
||||
dead = false;
|
||||
spawner = null;
|
||||
respawns --;
|
||||
Sounds.respawn.at(tile);
|
||||
|
||||
setNet(tile.drawx(), tile.drawy());
|
||||
clearItem();
|
||||
heal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offloadImmediately(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeID getTypeID(){
|
||||
return TypeIDs.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitDef type(){
|
||||
return mech;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Weapons getWeapons(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(float x, float y){
|
||||
if(!mech.flying){
|
||||
collisions.move(this, x, y);
|
||||
}else{
|
||||
moveBy(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinePower(){
|
||||
return mech.minePower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion getIconRegion(){
|
||||
return mech.icon(Cicon.full);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpolate(){
|
||||
super.interpolate();
|
||||
|
||||
if(interpolator.values.length > 1){
|
||||
baseRotation = interpolator.values[1];
|
||||
}
|
||||
|
||||
if(interpolator.target.dst(interpolator.last) > 1f){
|
||||
walktime += Time.delta();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBuildPower(Tile tile){
|
||||
return mech.buildPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float maxHealth(){
|
||||
return mech.health * state.rules.playerHealthMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile getMineTile(){
|
||||
return mining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMineTile(Tile tile){
|
||||
this.mining = tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMine(Item item){
|
||||
return item.hardness <= mech.drillTier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float calculateDamage(float amount){
|
||||
return amount * Mathf.clamp(1f - (status.getArmorMultiplier() + mech.getExtraArmor(this)) / 100f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added(){
|
||||
baseRotation = 90f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float mass(){
|
||||
return mech.mass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlying(){
|
||||
return mech.flying || boostHeat > liftoffBoost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(float amount){
|
||||
hitTime = hitDuration;
|
||||
if(!net.client()){
|
||||
health -= calculateDamage(amount);
|
||||
}
|
||||
|
||||
if(health <= 0 && !dead){
|
||||
Call.onPlayerDeath(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(float x, float y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<BuildRequest> buildQueue(){
|
||||
return placeQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "Player{" + name + ", mech=" + mech.name + ", id=" + id + ", local=" + isLocal + ", " + x + ", " + y + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup(){
|
||||
return playerGroup;
|
||||
}
|
||||
|
||||
public void team(Team team){
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region draw methods
|
||||
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return isLocal ? Float.MAX_VALUE : 40 + placeDistance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawShadow(float offsetX, float offsetY){
|
||||
float scl = mech.flying ? 1f : boostHeat / 2f;
|
||||
|
||||
Draw.rect(getIconRegion(), x + offsetX * scl, y + offsetY * scl, rotation - 90);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
if(dead) return;
|
||||
|
||||
if(!movement.isZero() && moved && !state.isPaused()){
|
||||
walktime += movement.len() * getFloorOn().speedMultiplier * 2f;
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
|
||||
}
|
||||
|
||||
float ft = Mathf.sin(walktime, 6f, 2f) * (1f - boostHeat);
|
||||
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
Draw.color();
|
||||
Draw.mixcol(Color.white, hitTime / hitDuration);
|
||||
|
||||
if(!mech.flying){
|
||||
if(floor.isLiquid){
|
||||
Draw.color(Color.white, floor.color, 0.5f);
|
||||
}
|
||||
|
||||
float boostTrnsY = -boostHeat * 3f;
|
||||
float boostTrnsX = boostHeat * 3f;
|
||||
float boostAng = boostHeat * 40f;
|
||||
|
||||
float light = 0.2f;
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Draw.colorl(1f-light + Mathf.clamp(ft * i, 0, 1) *light);
|
||||
Draw.rect(mech.legRegion,
|
||||
x + Angles.trnsx(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i),
|
||||
y + Angles.trnsy(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i),
|
||||
mech.legRegion.getWidth() * i * Draw.scl,
|
||||
(mech.legRegion.getHeight() - Mathf.clamp(ft * i, 0, 2)) * Draw.scl,
|
||||
baseRotation - 90 + boostAng * i);
|
||||
}
|
||||
Draw.color();
|
||||
|
||||
Draw.rect(mech.baseRegion, x, y, baseRotation - 90);
|
||||
}
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.color(Color.white, floor.color, drownTime);
|
||||
}else{
|
||||
Draw.color(Color.white);
|
||||
}
|
||||
|
||||
Draw.rect(mech.region, x, y, rotation - 90);
|
||||
|
||||
mech.draw(this);
|
||||
weapons.draw(this);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public void drawBackItems(){
|
||||
drawBackItems(itemtime, isLocal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawStats(){
|
||||
mech.drawStats(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(){
|
||||
if(dead) return;
|
||||
|
||||
if(isBuilding() && isBuilding){
|
||||
if(!state.isPaused()){
|
||||
drawBuilding();
|
||||
}
|
||||
}else{
|
||||
drawMining();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(){
|
||||
if(dead) return;
|
||||
|
||||
float size = mech.engineSize * (mech.flying ? 1f : boostHeat);
|
||||
Draw.color(mech.engineColor);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset), y + Angles.trnsy(rotation + 180, mech.engineOffset),
|
||||
size + Mathf.absin(Time.time(), 2f, size / 4f));
|
||||
|
||||
Draw.color(Color.white);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset - 1f), y + Angles.trnsy(rotation + 180, mech.engineOffset - 1f),
|
||||
(size + Mathf.absin(Time.time(), 2f, size / 4f)) / 2f);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public void drawName(){
|
||||
BitmapFont font = Fonts.def;
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
final float nameHeight = 11;
|
||||
final float textHeight = 15;
|
||||
|
||||
boolean ints = font.usesIntegerPositions();
|
||||
font.setUseIntegerPositions(false);
|
||||
font.getData().setScale(0.25f / Scl.scl(1f));
|
||||
layout.setText(font, name);
|
||||
|
||||
if(!isLocal){
|
||||
Draw.color(0f, 0f, 0f, 0.3f);
|
||||
Fill.rect(x, y + nameHeight - layout.height / 2, layout.width + 2, layout.height + 3);
|
||||
Draw.color();
|
||||
font.setColor(color);
|
||||
font.draw(name, x, y + nameHeight, 0, Align.center, false);
|
||||
|
||||
if(isAdmin){
|
||||
float s = 3f;
|
||||
Draw.color(color.r * 0.5f, color.g * 0.5f, color.b * 0.5f, 1f);
|
||||
Draw.rect(Icon.adminSmall.getRegion(), x + layout.width / 2f + 2 + 1, y + nameHeight - 1.5f, s, s);
|
||||
Draw.color(color);
|
||||
Draw.rect(Icon.adminSmall.getRegion(), x + layout.width / 2f + 2 + 1, y + nameHeight - 1f, s, s);
|
||||
}
|
||||
}
|
||||
|
||||
if(Core.settings.getBool("playerchat") && ((textFadeTime > 0 && lastText != null) || isTyping)){
|
||||
String text = textFadeTime <= 0 || lastText == null ? "[LIGHT_GRAY]" + Strings.animated(Time.time(), 4, 15f, ".") : lastText;
|
||||
float width = 100f;
|
||||
float visualFadeTime = 1f - Mathf.curve(1f - textFadeTime, 0.9f);
|
||||
font.setColor(1f, 1f, 1f, textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime);
|
||||
|
||||
layout.setText(font, text, Color.white, width, Align.bottom, true);
|
||||
|
||||
Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime));
|
||||
Fill.rect(x, y + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3);
|
||||
font.draw(text, x - width/2f, y + textHeight + layout.height, width, Align.center, true);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
Pools.free(layout);
|
||||
font.getData().setScale(1f);
|
||||
font.setColor(Color.white);
|
||||
font.setUseIntegerPositions(ints);
|
||||
}
|
||||
|
||||
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
|
||||
public void drawBuildRequests(){
|
||||
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){
|
||||
control.input.drawBreaking(request);
|
||||
}else{
|
||||
request.block.drawRequest(request, control.input.allRequests(),
|
||||
Build.validPlace(team(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request));
|
||||
}
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//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();
|
||||
textFadeTime -= Time.delta() / (60 * 5);
|
||||
itemtime = Mathf.lerpDelta(itemtime, Mathf.num(item.amount > 0), 0.1f);
|
||||
|
||||
if(Float.isNaN(x) || Float.isNaN(y)){
|
||||
velocity.set(0f, 0f);
|
||||
x = 0;
|
||||
y = 0;
|
||||
dead(true);
|
||||
}
|
||||
|
||||
if(netServer.isWaitingForPlayers()){
|
||||
dead(true);
|
||||
}
|
||||
|
||||
if(!dead() && isOutOfBounds()){
|
||||
destructTime += Time.delta();
|
||||
|
||||
if(destructTime >= boundsCountdown){
|
||||
kill();
|
||||
}
|
||||
}else{
|
||||
destructTime = 0f;
|
||||
}
|
||||
|
||||
if(!dead() && isFlying()){
|
||||
loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.3f);
|
||||
}
|
||||
|
||||
BuildRequest request = buildRequest();
|
||||
if(isBuilding() && isBuilding && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
|
||||
loops.play(Sounds.build, request.tile(), 0.75f);
|
||||
}
|
||||
|
||||
if(dead()){
|
||||
isBoosting = false;
|
||||
boostHeat = 0f;
|
||||
if(respawns > 0 || !state.rules.limitedRespawns){
|
||||
updateRespawning();
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
spawner = null;
|
||||
}
|
||||
|
||||
if(isLocal || net.server()){
|
||||
avoidOthers();
|
||||
}
|
||||
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
boostHeat = Mathf.lerpDelta(boostHeat, (tile != null && tile.solid()) || (isBoosting && ((!movement.isZero() && moved) || !isLocal)) ? 1f : 0f, 0.08f);
|
||||
shootHeat = Mathf.lerpDelta(shootHeat, isShooting() ? 1f : 0f, 0.06f);
|
||||
mech.update(this); //updated regardless
|
||||
|
||||
if(boostHeat > liftoffBoost + 0.1f){
|
||||
achievedFlight = true;
|
||||
}
|
||||
|
||||
if(boostHeat <= liftoffBoost + 0.05f && achievedFlight && !mech.flying){
|
||||
if(tile != null){
|
||||
Fx.unitLand.at(x, y, tile.floor().isLiquid ? 1f : 0.5f, tile.floor().color);
|
||||
}
|
||||
mech.onLand(this);
|
||||
achievedFlight = false;
|
||||
}
|
||||
|
||||
if(!isLocal){
|
||||
interpolate();
|
||||
updateMechanics(); //building happens even with non-locals
|
||||
status.update(this); //status effect updating also happens with non locals for effect purposes
|
||||
updateVelocityStatus(); //velocity too, for visual purposes
|
||||
|
||||
if(net.server()){
|
||||
updateShooting(); //server simulates player shooting
|
||||
}
|
||||
return;
|
||||
}else if(world.isZone()){
|
||||
//unlock mech when used
|
||||
data.unlockContent(mech);
|
||||
}
|
||||
|
||||
if(control.input instanceof MobileInput){
|
||||
updateTouch();
|
||||
}else{
|
||||
updateKeyboard();
|
||||
}
|
||||
|
||||
isTyping = ui.chatfrag.shown();
|
||||
|
||||
updateMechanics();
|
||||
|
||||
if(!mech.flying){
|
||||
clampPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateKeyboard(){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown();
|
||||
|
||||
isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying;
|
||||
|
||||
//if player is in solid block
|
||||
if(tile != null && tile.solid()){
|
||||
isBoosting = true;
|
||||
}
|
||||
|
||||
float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed;
|
||||
|
||||
if(mech.flying){
|
||||
//prevent strafing backwards, have a penalty for doing so
|
||||
float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x
|
||||
speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f);
|
||||
}
|
||||
|
||||
movement.setZero();
|
||||
|
||||
float xa = Core.input.axis(Binding.move_x);
|
||||
float ya = Core.input.axis(Binding.move_y);
|
||||
if(!(Core.scene.getKeyboardFocus() instanceof TextField)){
|
||||
movement.y += ya * speed;
|
||||
movement.x += xa * speed;
|
||||
}
|
||||
|
||||
if(Core.input.keyDown(Binding.mouse_move)){
|
||||
movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed;
|
||||
movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed;
|
||||
}
|
||||
|
||||
Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY());
|
||||
pointerX = vec.x;
|
||||
pointerY = vec.y;
|
||||
updateShooting();
|
||||
|
||||
movement.limit(speed).scl(Time.delta());
|
||||
|
||||
if(canMove){
|
||||
velocity.add(movement.x, movement.y);
|
||||
}else{
|
||||
isShooting = false;
|
||||
}
|
||||
float prex = x, prey = y;
|
||||
updateVelocityStatus();
|
||||
moved = dst(prex, prey) > 0.001f;
|
||||
|
||||
if(canMove){
|
||||
float baseLerp = mech.getRotationAlpha(this);
|
||||
if(!isShooting() || !mech.faceTarget){
|
||||
if(!movement.isZero()){
|
||||
rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp);
|
||||
}
|
||||
}else{
|
||||
float angle = control.input.mouseAngle(x, y);
|
||||
this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateShooting(){
|
||||
if(!state.isEditor() && isShooting() && mech.canShoot(this)){
|
||||
weapons.update(this);
|
||||
//if(!mech.turnCursor){
|
||||
//shoot forward ignoring cursor
|
||||
//mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance));
|
||||
//}else{
|
||||
//mech.weapon.update(this, pointerX, pointerY);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateTouch(){
|
||||
if(Units.invalidateTarget(target, this) &&
|
||||
!(target instanceof Tilec && ((Tilec)target).damaged() && target.isValid() && target.team() == team && mech.canHeal && dst(target) < mech.range && !(((Tilec)target).block instanceof BuildBlock))){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(state.isEditor()){
|
||||
target = null;
|
||||
}
|
||||
|
||||
float targetX = Core.camera.position.x, targetY = Core.camera.position.y;
|
||||
float attractDst = 15f;
|
||||
float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed;
|
||||
|
||||
if(moveTarget != null && !moveTarget.dead()){
|
||||
targetX = moveTarget.getX();
|
||||
targetY = moveTarget.getY();
|
||||
boolean tapping = moveTarget instanceof Tilec && moveTarget.team() == team;
|
||||
attractDst = 0f;
|
||||
|
||||
if(tapping){
|
||||
velocity.setAngle(angleTo(moveTarget));
|
||||
}
|
||||
|
||||
if(dst(moveTarget) <= 2f * Time.delta()){
|
||||
if(tapping && !dead()){
|
||||
Tile tile = ((Tilec)moveTarget).tile;
|
||||
tile.block().tapped(tile, this);
|
||||
}
|
||||
|
||||
moveTarget = null;
|
||||
}
|
||||
}else{
|
||||
moveTarget = null;
|
||||
}
|
||||
|
||||
movement.set((targetX - x) / Time.delta(), (targetY - y) / Time.delta()).limit(speed);
|
||||
movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f));
|
||||
|
||||
if(dst(targetX, targetY) < attractDst){
|
||||
movement.setZero();
|
||||
}
|
||||
|
||||
float expansion = 3f;
|
||||
|
||||
hitbox(rect);
|
||||
rect.x -= expansion;
|
||||
rect.y -= expansion;
|
||||
rect.width += expansion * 2f;
|
||||
rect.height += expansion * 2f;
|
||||
|
||||
isBoosting = collisions.overlapsTile(rect) || dst(targetX, targetY) > 85f;
|
||||
|
||||
velocity.add(movement.scl(Time.delta()));
|
||||
|
||||
if(velocity.len() <= 0.2f && mech.flying){
|
||||
rotation += Mathf.sin(Time.time() + id * 99, 10f, 1f);
|
||||
}else if(target == null){
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len() / 10f);
|
||||
}
|
||||
|
||||
float lx = x, ly = y;
|
||||
updateVelocityStatus();
|
||||
moved = dst(lx, ly) > 0.001f;
|
||||
|
||||
if(mech.flying){
|
||||
//hovering effect
|
||||
x += Mathf.sin(Time.time() + id * 999, 25f, 0.08f);
|
||||
y += Mathf.cos(Time.time() + id * 999, 25f, 0.08f);
|
||||
}
|
||||
|
||||
//update shooting if not building, not mining and there's ammo left
|
||||
if(!isBuilding() && getMineTile() == null){
|
||||
|
||||
//autofire
|
||||
if(target == null){
|
||||
isShooting = false;
|
||||
if(Core.settings.getBool("autotarget")){
|
||||
target = Units.closestTarget(team, x, y, mech.range, u -> u.team() != Team.derelict, u -> u.getTeam() != Team.derelict);
|
||||
|
||||
if(mech.canHeal && target == null){
|
||||
target = Geometry.findClosest(x, y, indexer.getDamaged(Team.sharded));
|
||||
if(target != null && dst(target) > mech.range){
|
||||
target = null;
|
||||
}else if(target != null){
|
||||
target = ((Tile)target).entity;
|
||||
}
|
||||
}
|
||||
|
||||
if(target != null){
|
||||
setMineTile(null);
|
||||
}
|
||||
}
|
||||
}else if(target.isValid() || (target instanceof Tilec && ((Tilec)target).damaged() && target.team() == team && mech.canHeal && dst(target) < mech.range)){
|
||||
//rotate toward and shoot the target
|
||||
if(mech.faceTarget){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);
|
||||
}
|
||||
|
||||
Vec2 intercept = Predict.intercept(this, target, getWeapon().bullet.speed);
|
||||
|
||||
pointerX = intercept.x;
|
||||
pointerY = intercept.y;
|
||||
|
||||
updateShooting();
|
||||
isShooting = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region utility methods
|
||||
|
||||
public void sendMessage(String text){
|
||||
if(isLocal){
|
||||
if(Vars.ui != null){
|
||||
Vars.ui.chatfrag.addMessage(text, null);
|
||||
}
|
||||
}else{
|
||||
Call.sendMessage(con, text, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String text, Player from){
|
||||
sendMessage(text, from, NetClient.colorizeName(from.id, from.name));
|
||||
}
|
||||
|
||||
public void sendMessage(String text, Player from, String fromName){
|
||||
if(isLocal){
|
||||
if(Vars.ui != null){
|
||||
Vars.ui.chatfrag.addMessage(text, fromName);
|
||||
}
|
||||
}else{
|
||||
Call.sendMessage(con, text, fromName, from);
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerInfo getInfo(){
|
||||
if(uuid == null){
|
||||
throw new IllegalArgumentException("Local players cannot be traced and do not have info.");
|
||||
}else{
|
||||
return netServer.admins.getInfo(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets all values of the player. */
|
||||
public void reset(){
|
||||
resetNoAdd();
|
||||
|
||||
add();
|
||||
}
|
||||
|
||||
public void resetNoAdd(){
|
||||
status.clear();
|
||||
team = Team.sharded;
|
||||
item.amount = 0;
|
||||
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;
|
||||
boostHeat = drownTime = hitTime = 0f;
|
||||
mech = Mechs.starter;
|
||||
placeQueue.clear();
|
||||
respawns = state.rules.respawns;
|
||||
}
|
||||
|
||||
public boolean isShooting(){
|
||||
return isShooting && (boostHeat < 0.1f || mech.flying) && mining == null;
|
||||
}
|
||||
|
||||
public void updateRespawning(){
|
||||
|
||||
if(state.isEditor()){
|
||||
//instant respawn at center of map.
|
||||
set(world.width() * tilesize/2f, world.height() * tilesize/2f);
|
||||
dead(false);
|
||||
}else if(spawner != null && spawner.isValid()){
|
||||
spawner.updateSpawning(this);
|
||||
}else if(!netServer.isWaitingForPlayers()){
|
||||
if(!net.client()){
|
||||
if(lastSpawner != null && lastSpawner.isValid()){
|
||||
this.spawner = lastSpawner;
|
||||
}else if(closestCore() != null){
|
||||
this.spawner = (SpawnerTrait)closestCore();
|
||||
}
|
||||
}
|
||||
}else if(closestCore() != null){
|
||||
set(closestCore().getX(), closestCore().getY());
|
||||
}
|
||||
}
|
||||
|
||||
public void beginRespawning(SpawnerTrait spawner){
|
||||
this.spawner = spawner;
|
||||
this.lastSpawner = spawner;
|
||||
this.dead = true;
|
||||
setNet(spawner.getX(), spawner.getY());
|
||||
spawner.updateSpawning(this);
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
//region read and write methods
|
||||
|
||||
@Override
|
||||
public byte version(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeBoolean(isLocal);
|
||||
|
||||
if(isLocal){
|
||||
stream.writeByte(mech.id);
|
||||
stream.writeInt(lastSpawner == null ? noSpawner : lastSpawner.getTile().pos());
|
||||
super.writeSave(stream, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream, byte version) throws IOException{
|
||||
boolean local = stream.readBoolean();
|
||||
|
||||
if(local){
|
||||
byte mechid = stream.readByte();
|
||||
int spawner = stream.readInt();
|
||||
Tile stile = world.tile(spawner);
|
||||
Player player = headless ? this : Vars.player;
|
||||
player.readSaveSuper(stream, version);
|
||||
player.mech = content.getByID(ContentType.mech, mechid);
|
||||
player.dead = false;
|
||||
if(stile != null && stile.entity instanceof SpawnerTrait){
|
||||
player.lastSpawner = (SpawnerTrait)stile.entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readSaveSuper(DataInput stream, byte version) throws IOException{
|
||||
super.readSave(stream, version);
|
||||
|
||||
add();
|
||||
}
|
||||
|
||||
@Override
|
||||
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)| (Pack.byteValue(isBuilding) << 4));
|
||||
buffer.writeInt(Color.rgba8888(color));
|
||||
buffer.writeByte(mech.id);
|
||||
buffer.writeInt(mining == null ? noSpawner : mining.pos());
|
||||
buffer.writeInt(spawner == null || !spawner.hasUnit(this) ? noSpawner : spawner.getTile().pos());
|
||||
buffer.writeShort((short)(baseRotation * 2));
|
||||
|
||||
writeBuilding(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput buffer) throws IOException{
|
||||
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
||||
|
||||
super.readSave(buffer, version());
|
||||
|
||||
name = TypeIO.readStringData(buffer);
|
||||
byte bools = buffer.readByte();
|
||||
isAdmin = (bools & 1) != 0;
|
||||
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();
|
||||
int spawner = buffer.readInt();
|
||||
float baseRotation = buffer.readShort() / 2f;
|
||||
|
||||
readBuilding(buffer, !isLocal);
|
||||
|
||||
interpolator.read(lastx, lasty, x, y, rotation, baseRotation);
|
||||
rotation = lastrot;
|
||||
x = lastx;
|
||||
y = lasty;
|
||||
|
||||
if(isLocal){
|
||||
velocity.x = lastvx;
|
||||
velocity.y = lastvy;
|
||||
}else{
|
||||
mining = world.tile(mine);
|
||||
isBuilding = building;
|
||||
isBoosting = boosting;
|
||||
}
|
||||
|
||||
Tile tile = world.tile(spawner);
|
||||
if(tile != null && tile.entity instanceof SpawnerTrait){
|
||||
this.spawner = (SpawnerTrait)tile.entity;
|
||||
}else{
|
||||
this.spawner = null;
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.math.Mathf;
|
||||
import arc.math.geom.Geometry;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.world.Tile;
|
||||
import mindustry.world.meta.BlockFlag;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public abstract class BaseDrone extends FlyingUnit{
|
||||
public final StateMachine.UnitState retreat = new StateMachine.UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(health >= maxHealth()){
|
||||
state.set(getStartState());
|
||||
}else if(!targetHasFlag(BlockFlag.repair)){
|
||||
if(retarget()){
|
||||
Tile repairPoint = Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair));
|
||||
if(repairPoint != null){
|
||||
target = repairPoint;
|
||||
}else{
|
||||
setState(getStartState());
|
||||
}
|
||||
}
|
||||
}else{
|
||||
circle(40f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean countsAsEnemy(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
//do nothing, normal commands are not applicable here
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation(){
|
||||
if(target != null && shouldRotate() && target.dst(this) < type.range){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f);
|
||||
}else{
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(){
|
||||
if(health <= maxHealth() * type.retreatPercent && !state.is(retreat) && Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair)) != null){
|
||||
setState(retreat);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldRotate(){
|
||||
return state.is(getStartState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract StateMachine.UnitState getStartState();
|
||||
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.type.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.BuildBlock.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BuilderDrone extends BaseDrone implements BuilderTrait{
|
||||
private static final StaticReset reset = new StaticReset();
|
||||
private static final IntIntMap totals = new IntIntMap();
|
||||
|
||||
protected Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
protected BuildRequest lastFound;
|
||||
protected boolean isBreaking;
|
||||
protected Player playerTarget;
|
||||
|
||||
public final StateMachine.UnitState
|
||||
|
||||
build = new StateMachine.UnitState(){
|
||||
|
||||
public void entered(){
|
||||
if(!(target instanceof BuildEntity)){
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void update(){
|
||||
BuildEntity entity = (BuildEntity)target;
|
||||
Tilec core = getClosestCore();
|
||||
|
||||
if(isBuilding() && entity == null && canRebuild()){
|
||||
target = world.tile(buildRequest().x, buildRequest().y);
|
||||
circle(placeDistance * 0.7f);
|
||||
target = null;
|
||||
|
||||
BuildRequest request = buildRequest();
|
||||
|
||||
if(world.tile(request.x, request.y).entity instanceof BuildEntity){
|
||||
target = world.tile(request.x, request.y).entity;
|
||||
}
|
||||
}else if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid
|
||||
if(!isBuilding() && dst(target) < placeDistance * 0.9f){ //within distance, begin placing
|
||||
if(isBreaking){
|
||||
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
|
||||
}else{
|
||||
buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
|
||||
if(lastFound != null && lastFound.hasConfig){
|
||||
buildQueue().last().configure(lastFound.config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
circle(placeDistance * 0.7f);
|
||||
velocity.scl(0.74f);
|
||||
}else{ //else, building isn't valid, follow a player
|
||||
target = null;
|
||||
|
||||
if(playerTarget == null || playerTarget.team() != team || !playerTarget.isValid()){
|
||||
playerTarget = null;
|
||||
|
||||
if(retarget()){
|
||||
float minDst = Float.POSITIVE_INFINITY;
|
||||
int minDrones = Integer.MAX_VALUE;
|
||||
|
||||
//find player with min amount of drones
|
||||
for(Player player : playerGroup.all()){
|
||||
if(player.team() == team){
|
||||
int drones = getDrones(player);
|
||||
float dst = dst2(player);
|
||||
|
||||
if(playerTarget == null || drones < minDrones || (drones == minDrones && dst < minDst)){
|
||||
minDrones = drones;
|
||||
minDst = dst;
|
||||
playerTarget = player;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(getSpawner() != null){
|
||||
target = getSpawner();
|
||||
circle(40f);
|
||||
target = null;
|
||||
}
|
||||
}else{
|
||||
incDrones(playerTarget);
|
||||
Teamc prev = target;
|
||||
target = playerTarget;
|
||||
float dst = 90f + (id % 10)*3;
|
||||
float tdst = dst(target);
|
||||
float scale = (Mathf.lerp(1f, 0.2f, 1f - Mathf.clamp((tdst - dst) / dst)));
|
||||
circle(dst);
|
||||
velocity.scl(scale);
|
||||
target = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public BuilderDrone(){
|
||||
if(reset.check()){
|
||||
Events.on(BuildSelectEvent.class, event -> {
|
||||
if(!(event.tile.entity instanceof BuildEntity)) return;
|
||||
|
||||
for(BaseUnit unit : unitGroup.all()){
|
||||
if(unit instanceof BuilderDrone && unit.getTeam() == getTeam()){
|
||||
BuilderDrone drone = (BuilderDrone)unit;
|
||||
if(drone.isBuilding()){
|
||||
//stop building if opposite building begins.
|
||||
BuildRequest req = drone.buildRequest();
|
||||
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
|
||||
drone.clearBuilding();
|
||||
drone.target = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int getDrones(Player player){
|
||||
return Pack.leftShort(totals.get(player.id, 0));
|
||||
}
|
||||
|
||||
void incDrones(Player player){
|
||||
int num = totals.get(player.id, 0);
|
||||
int amount = Pack.leftShort(num), frame = Pack.rightShort(num);
|
||||
short curFrame = (short)(Core.graphics.getFrameId() % Short.MAX_VALUE);
|
||||
|
||||
if(frame != curFrame){
|
||||
totals.put(player.id, Pack.shortInt((short)1, curFrame));
|
||||
}else{
|
||||
totals.put(player.id, Pack.shortInt((short)(amount + 1), curFrame));
|
||||
}
|
||||
}
|
||||
|
||||
boolean canRebuild(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBuildPower(Tile tile){
|
||||
return type.buildPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Queue<BuildRequest> buildQueue(){
|
||||
return placeQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
if(!isBuilding() && timer.get(timerTarget2, 15)){
|
||||
for(Player player : playerGroup.all()){
|
||||
if(player.team() == team && player.buildRequest() != null){
|
||||
BuildRequest req = player.buildRequest();
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile != null && tile.entity instanceof BuildEntity){
|
||||
BuildEntity b = tile.ent();
|
||||
float dist = Math.min(b.dst(x, y) - placeDistance, 0);
|
||||
if(dist / type.maxVelocity < b.buildCost * 0.9f){
|
||||
lastFound = req;
|
||||
target = b;
|
||||
this.isBreaking = req.breaking;
|
||||
setState(build);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(timer.get(timerTarget, 80) && Units.closestEnemy(getTeam(), x, y, 100f, u -> !(u instanceof BaseDrone)) == null && !isBuilding()){
|
||||
TeamData data = team.data();
|
||||
if(!data.brokenBlocks.isEmpty()){
|
||||
BrokenBlock block = data.brokenBlocks.removeLast();
|
||||
if(Build.validPlace(getTeam(), block.x, block.y, content.block(block.block), block.rotation)){
|
||||
placeQueue.addFirst(new BuildRequest(block.x, block.y, block.rotation, content.block(block.block)).configure(block.config));
|
||||
setState(build);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRotate(){
|
||||
return isBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine.UnitState getStartState(){
|
||||
return build;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(){
|
||||
drawBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return isBuilding() ? placeDistance * 2f : 30f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCreateBlocks(){
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException{
|
||||
super.write(data);
|
||||
writeBuilding(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data) throws IOException{
|
||||
super.read(data);
|
||||
readBuilding(data);
|
||||
}
|
||||
}
|
||||
@@ -1,255 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class FlyingUnit extends BaseUnit{
|
||||
protected float[] weaponAngles = {0,0};
|
||||
|
||||
protected final StateMachine.UnitState
|
||||
|
||||
attack = new StateMachine.UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
|
||||
if(Units.invalidateTarget(target, team, x, y)){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(retarget()){
|
||||
targetClosest();
|
||||
|
||||
if(target == null) targetClosestEnemyFlag(BlockFlag.producer);
|
||||
if(target == null) targetClosestEnemyFlag(BlockFlag.turret);
|
||||
|
||||
if(target == null && isCommanded() && getCommand() != UnitCommand.attack){
|
||||
onCommand(getCommand());
|
||||
}
|
||||
}
|
||||
|
||||
if(getClosestSpawner() == null && getSpawner() != null && target == null){
|
||||
target = getSpawner();
|
||||
circle(80f + Mathf.randomSeed(id) * 120);
|
||||
}else if(target != null){
|
||||
attack(type.attackLength);
|
||||
|
||||
if((Angles.near(angleTo(target), rotation, type.shootCone) || getWeapon().ignoreRotation) //bombers and such don't care about rotation
|
||||
&& dst(target) < getWeapon().bullet.range()){
|
||||
BulletType ammo = getWeapon().bullet;
|
||||
|
||||
if(type.rotateWeapon){
|
||||
for(boolean left : Mathf.booleans){
|
||||
int wi = Mathf.num(left);
|
||||
float wx = x + Angles.trnsx(rotation - 90, getWeapon().width * Mathf.sign(left));
|
||||
float wy = y + Angles.trnsy(rotation - 90, getWeapon().width * Mathf.sign(left));
|
||||
|
||||
weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi], Angles.angle(wx, wy, target.getX(), target.getY()), 0.1f);
|
||||
|
||||
Tmp.v2.trns(weaponAngles[wi], getWeapon().length);
|
||||
getWeapon().update(FlyingUnit.this, wx + Tmp.v2.x, wy + Tmp.v2.y, weaponAngles[wi], left);
|
||||
}
|
||||
}else{
|
||||
Vec2 to = Predict.intercept(FlyingUnit.this, target, ammo.speed);
|
||||
getWeapon().update(FlyingUnit.this, to.x, to.y);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
target = getClosestSpawner();
|
||||
moveTo(Vars.state.rules.dropZoneRadius + 120f);
|
||||
}
|
||||
}
|
||||
},
|
||||
rally = new StateMachine.UnitState(){
|
||||
public void update(){
|
||||
if(retarget()){
|
||||
targetClosestAllyFlag(BlockFlag.rally);
|
||||
targetClosest();
|
||||
|
||||
if(target != null && !Units.invalidateTarget(target, team, x, y)){
|
||||
setState(attack);
|
||||
return;
|
||||
}
|
||||
|
||||
if(target == null) target = getSpawner();
|
||||
}
|
||||
|
||||
if(target != null){
|
||||
circle(65f + Mathf.randomSeed(id) * 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new StateMachine.UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(retarget()){
|
||||
target = getSpawner();
|
||||
|
||||
Tile repair = Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair));
|
||||
if(repair != null && damaged()) FlyingUnit.this.target = repair.entity;
|
||||
if(target == null) target = getClosestCore();
|
||||
}
|
||||
|
||||
circle(targetHasFlag(BlockFlag.repair) ? 20f : 60f + Mathf.randomSeed(id) * 50, 0.65f * type.speed);
|
||||
}
|
||||
};;
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.rally ? rally :
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(float x, float y){
|
||||
moveBy(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
if(!net.client()){
|
||||
updateRotation();
|
||||
}
|
||||
wobble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(){
|
||||
drawEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.mixcol(Color.white, hitTime / hitDuration);
|
||||
Draw.rect(type.region, x, y, rotation - 90);
|
||||
|
||||
drawWeapons();
|
||||
|
||||
Draw.mixcol();
|
||||
}
|
||||
|
||||
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(){
|
||||
Draw.color(Pal.engine);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset), y + Angles.trnsy(rotation + 180, type.engineOffset),
|
||||
type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize / 4f));
|
||||
|
||||
Draw.color(Color.white);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset - 1f), y + Angles.trnsy(rotation + 180, type.engineOffset - 1f),
|
||||
(type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize / 4f)) / 2f);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(){
|
||||
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
for(boolean left : Mathf.booleans){
|
||||
int wi = Mathf.num(left);
|
||||
weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi], rotation, 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine.UnitState getStartState(){
|
||||
return attack;
|
||||
}
|
||||
|
||||
protected void wobble(){
|
||||
if(net.client()) return;
|
||||
|
||||
x += Mathf.sin(Time.time() + id * 999, 25f, 0.05f) * Time.delta();
|
||||
y += Mathf.cos(Time.time() + id * 999, 25f, 0.05f) * Time.delta();
|
||||
|
||||
if(velocity.len() <= 0.05f){
|
||||
//rotation += Mathf.sin(Time.time() + id * 99, 10f, 2f * type.speed)*Time.delta();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateRotation(){
|
||||
rotation = velocity.angle();
|
||||
}
|
||||
|
||||
protected void circle(float circleLength){
|
||||
circle(circleLength, type.speed);
|
||||
}
|
||||
|
||||
protected void circle(float circleLength, float speed){
|
||||
if(target == null) return;
|
||||
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
if(Tmp.v1.len() < circleLength){
|
||||
Tmp.v1.rotate((circleLength - Tmp.v1.len()) / circleLength * 180f);
|
||||
}
|
||||
|
||||
Tmp.v1.setLength(speed * Time.delta());
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
|
||||
protected void moveTo(float circleLength){
|
||||
if(target == null) return;
|
||||
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((dst(target) - circleLength) / 100f, -1f, 1f);
|
||||
|
||||
Tmp.v1.setLength(type.speed * Time.delta() * length);
|
||||
if(length < -0.5f){
|
||||
Tmp.v1.rotate(180f);
|
||||
}else if(length < 0){
|
||||
Tmp.v1.setZero();
|
||||
}
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
|
||||
protected void attack(float circleLength){
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
float ang = angleTo(target);
|
||||
float diff = Angles.angleDist(ang, rotation);
|
||||
|
||||
if(diff > 100f && Tmp.v1.len() < circleLength){
|
||||
Tmp.v1.setAngle(velocity.angle());
|
||||
}else{
|
||||
Tmp.v1.setAngle(Mathf.slerpDelta(velocity.angle(), Tmp.v1.angle(), 0.44f));
|
||||
}
|
||||
|
||||
Tmp.v1.setLength(type.speed * Time.delta());
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
}
|
||||
@@ -1,259 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ai.Pathfinder.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class GroundUnit extends BaseUnit{
|
||||
protected static Vec2 vec = new Vec2();
|
||||
|
||||
protected float walkTime;
|
||||
protected float stuckTime;
|
||||
protected float baseRotation;
|
||||
|
||||
public final StateMachine.UnitState
|
||||
|
||||
attack = new StateMachine.UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
Tilec core = getClosestEnemyCore();
|
||||
|
||||
if(core == null){
|
||||
Tile closestSpawn = getClosestSpawner();
|
||||
if(closestSpawn == null || !withinDst(closestSpawn, Vars.state.rules.dropZoneRadius + 85f)){
|
||||
moveToCore(PathTarget.enemyCores);
|
||||
}
|
||||
}else{
|
||||
float dst = dst(core);
|
||||
|
||||
if(dst < getWeapon().bullet.range() / 1.1f){
|
||||
target = core;
|
||||
}
|
||||
|
||||
if(dst > getWeapon().bullet.range() * 0.5f){
|
||||
moveToCore(PathTarget.enemyCores);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
rally = new StateMachine.UnitState(){
|
||||
public void update(){
|
||||
Tile target = getClosest(BlockFlag.rally);
|
||||
|
||||
if(target != null && dst(target) > 80f){
|
||||
moveToCore(PathTarget.rallyPoints);
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new StateMachine.UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
moveAwayFromCore();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCommand(UnitCommand command){
|
||||
state.set(command == UnitCommand.retreat ? retreat :
|
||||
command == UnitCommand.attack ? attack :
|
||||
command == UnitCommand.rally ? rally :
|
||||
null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpolate(){
|
||||
super.interpolate();
|
||||
|
||||
if(interpolator.values.length > 1){
|
||||
baseRotation = interpolator.values[1];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(float x, float y){
|
||||
float dst = Mathf.dst(x, y);
|
||||
if(dst > 0.01f){
|
||||
baseRotation = Mathf.slerp(baseRotation, Mathf.angle(x, y), type.baseRotateSpeed * (dst / type.speed));
|
||||
}
|
||||
super.move(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StateMachine.UnitState getStartState(){
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
stuckTime = !vec.set(x, y).sub(lastPosition()).isZero(0.0001f) ? 0f : stuckTime + Time.delta();
|
||||
|
||||
if(!velocity.isZero()){
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, velocity.angle(), 0.05f);
|
||||
}
|
||||
|
||||
if(stuckTime < 1f){
|
||||
walkTime += Time.delta();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.mixcol(Color.white, hitTime / hitDuration);
|
||||
|
||||
float ft = Mathf.sin(walkTime * type.speed * 5f, 6f, 2f + type.hitsize / 15f);
|
||||
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.color(Color.white, floor.color, 0.5f);
|
||||
}
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Draw.rect(type.legRegion,
|
||||
x + Angles.trnsx(baseRotation, ft * i),
|
||||
y + Angles.trnsy(baseRotation, ft * i),
|
||||
type.legRegion.getWidth() * i * Draw.scl, type.legRegion.getHeight() * Draw.scl - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
|
||||
}
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.color(Color.white, floor.color, drownTime * 0.4f);
|
||||
}else{
|
||||
Draw.color(Color.white);
|
||||
}
|
||||
|
||||
Draw.rect(type.baseRegion, x, y, baseRotation - 90);
|
||||
|
||||
Draw.rect(type.region, x, y, rotation - 90);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Draw.mixcol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(){
|
||||
|
||||
if(!Units.invalidateTarget(target, this)){
|
||||
if(dst(target) < getWeapon().bullet.range()){
|
||||
|
||||
rotate(angleTo(target));
|
||||
|
||||
if(Angles.near(angleTo(target), rotation, 13f)){
|
||||
BulletType ammo = getWeapon().bullet;
|
||||
|
||||
Vec2 to = Predict.intercept(GroundUnit.this, target, ammo.speed);
|
||||
|
||||
getWeapon().update(GroundUnit.this, to.x, to.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTargeting(){
|
||||
super.updateTargeting();
|
||||
|
||||
if(Units.invalidateTarget(target, team, x, y, Float.MAX_VALUE)){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(retarget()){
|
||||
targetClosest();
|
||||
}
|
||||
}
|
||||
|
||||
protected void patrol(){
|
||||
vec.trns(baseRotation, type.speed * Time.delta());
|
||||
velocity.add(vec.x, vec.y);
|
||||
vec.trns(baseRotation, type.hitsizeTile * 5);
|
||||
Tile tile = world.tileWorld(x + vec.x, y + vec.y);
|
||||
if((tile == null || tile.solid() || tile.floor().drownTime > 0 || tile.floor().isLiquid) || stuckTime > 10f){
|
||||
baseRotation += Mathf.sign(id % 2 - 0.5f) * Time.delta() * 3f;
|
||||
}
|
||||
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), type.rotatespeed);
|
||||
}
|
||||
|
||||
protected void circle(float circleLength){
|
||||
if(target == null) return;
|
||||
|
||||
vec.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
if(vec.len() < circleLength){
|
||||
vec.rotate((circleLength - vec.len()) / circleLength * 180f);
|
||||
}
|
||||
|
||||
vec.setLength(type.speed * Time.delta());
|
||||
|
||||
velocity.add(vec);
|
||||
}
|
||||
|
||||
protected void moveToCore(PathTarget path){
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
if(tile == null) return;
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, team, path);
|
||||
|
||||
if(tile == targetTile) return;
|
||||
|
||||
velocity.add(vec.trns(angleTo(targetTile), type.speed * Time.delta()));
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
rotation = Mathf.slerpDelta(rotation, baseRotation, type.rotatespeed);
|
||||
}
|
||||
}
|
||||
|
||||
protected void moveAwayFromCore(){
|
||||
Team enemy = null;
|
||||
for(Team team : team.enemies()){
|
||||
if(team.active()){
|
||||
enemy = team;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(enemy == null){
|
||||
for(Team team : team.enemies()){
|
||||
enemy = team;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(enemy == null) return;
|
||||
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
if(tile == null) return;
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, enemy, PathTarget.enemyCores);
|
||||
Tilec core = getClosestCore();
|
||||
|
||||
if(tile == targetTile || core == null || dst(core) < 120f) return;
|
||||
|
||||
velocity.add(vec.trns(angleTo(targetTile), type.speed * Time.delta()));
|
||||
rotation = Mathf.slerpDelta(rotation, baseRotation, type.rotatespeed);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.graphics.g2d.Draw;
|
||||
import arc.math.Angles;
|
||||
import arc.math.Mathf;
|
||||
import mindustry.entities.Units;
|
||||
|
||||
public class HoverUnit extends FlyingUnit{
|
||||
|
||||
@Override
|
||||
public void drawWeapons(){
|
||||
for(int i : Mathf.signs){
|
||||
float tra = rotation - 90, trY = -getWeapon().getRecoil(this, i > 0) + type.weaponOffsetY;
|
||||
float w = i > 0 ? -12 : 12;
|
||||
float wx = x + Angles.trnsx(tra, getWeapon().width * i, trY), wy = y + Angles.trnsy(tra, getWeapon().width * i, trY);
|
||||
int wi = (i + 1) / 2;
|
||||
Draw.rect(getWeapon().region, wx, wy, w, 12, weaponAngles[wi] - 90);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attack(float circleLength){
|
||||
moveTo(circleLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation(){
|
||||
if(!Units.invalidateTarget(target, this)){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), type.rotatespeed);
|
||||
}else{
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), type.baseRotateSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import arc.math.Mathf;
|
||||
import arc.util.Structs;
|
||||
import mindustry.content.Blocks;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.entities.units.StateMachine.UnitState;
|
||||
import mindustry.gen.Call;
|
||||
import mindustry.type.Item;
|
||||
import mindustry.type.ItemType;
|
||||
import mindustry.world.Pos;
|
||||
import mindustry.world.Tile;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
/** A drone that only mines.*/
|
||||
public class MinerDrone extends BaseDrone implements MinerTrait{
|
||||
protected Item targetItem;
|
||||
protected Tile mineTile;
|
||||
|
||||
public final UnitState
|
||||
|
||||
mine = new UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
Tilec entity = getClosestCore();
|
||||
|
||||
if(entity == null) return;
|
||||
|
||||
findItem();
|
||||
|
||||
//core full of the target item, do nothing
|
||||
if(targetItem != null && entity.block.acceptStack(targetItem, 1, entity.tile, MinerDrone.this) == 0){
|
||||
MinerDrone.this.clearItem();
|
||||
return;
|
||||
}
|
||||
|
||||
//if inventory is full, drop it off.
|
||||
if(item.amount >= getItemCapacity() || (targetItem != null && !acceptsItem(targetItem))){
|
||||
setState(drop);
|
||||
}else{
|
||||
if(retarget() && targetItem != null){
|
||||
target = indexer.findClosestOre(x, y, targetItem);
|
||||
}
|
||||
|
||||
if(target instanceof Tile){
|
||||
moveTo(type.range / 1.5f);
|
||||
|
||||
if(dst(target) < type.range && mineTile != target){
|
||||
setMineTile((Tile)target);
|
||||
}
|
||||
|
||||
if(((Tile)target).block() != Blocks.air){
|
||||
setState(drop);
|
||||
}
|
||||
}else{
|
||||
//nothing to mine anymore, core full: circle spawnpoint
|
||||
if(getSpawner() != null){
|
||||
target = getSpawner();
|
||||
|
||||
circle(40f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void exited(){
|
||||
setMineTile(null);
|
||||
}
|
||||
},
|
||||
|
||||
drop = new UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(item.amount == 0 || item.item.type != ItemType.material){
|
||||
clearItem();
|
||||
setState(mine);
|
||||
return;
|
||||
}
|
||||
|
||||
target = getClosestCore();
|
||||
|
||||
if(target == null) return;
|
||||
|
||||
Tilec tile = (Tilec)target;
|
||||
|
||||
if(dst(target) < type.range){
|
||||
if(tile.tile.block().acceptStack(item.item, item.amount, tile.tile, MinerDrone.this) > 0){
|
||||
Call.transferItemTo(item.item, item.amount, x, y, tile.tile);
|
||||
}
|
||||
|
||||
clearItem();
|
||||
setState(mine);
|
||||
}
|
||||
|
||||
circle(type.range / 1.8f);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return mine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
updateMining();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation(){
|
||||
if(mineTile != null && shouldRotate() && mineTile.dst(this) < type.range){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(mineTile), 0.3f);
|
||||
}else{
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRotate(){
|
||||
return isMining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(){
|
||||
drawMining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canMine(Item item){
|
||||
return type.toMine.contains(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMinePower(){
|
||||
return type.minePower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile getMineTile(){
|
||||
return mineTile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMineTile(Tile tile){
|
||||
mineTile = tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException{
|
||||
super.write(data);
|
||||
data.writeInt(mineTile == null || !state.is(mine) ? Pos.invalid : mineTile.pos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data) throws IOException{
|
||||
super.read(data);
|
||||
mineTile = world.tile(data.readInt());
|
||||
}
|
||||
|
||||
protected void findItem(){
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package mindustry.entities.type.base;
|
||||
|
||||
import mindustry.entities.Units;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.entities.units.StateMachine.UnitState;
|
||||
import mindustry.world.Pos;
|
||||
import mindustry.world.Tile;
|
||||
import mindustry.world.blocks.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static mindustry.Vars.world;
|
||||
|
||||
public class RepairDrone extends BaseDrone{
|
||||
public final UnitState repair = new UnitState(){
|
||||
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
|
||||
if(retarget()){
|
||||
target = Units.findDamagedTile(team, x, y);
|
||||
}
|
||||
|
||||
if(target instanceof Tilec && ((Tilec)target).block instanceof BuildBlock){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(target != null){
|
||||
if(target.dst(RepairDrone.this) > type.range){
|
||||
circle(type.range * 0.9f);
|
||||
}else{
|
||||
getWeapon().update(RepairDrone.this, target.getX(), target.getY());
|
||||
}
|
||||
}else{
|
||||
//circle spawner if there's nothing to repair
|
||||
if(getSpawner() != null){
|
||||
target = getSpawner();
|
||||
circle(type.range * 1.5f, type.speed/2f);
|
||||
target = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean shouldRotate(){
|
||||
return target != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return repair;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException{
|
||||
super.write(data);
|
||||
data.writeInt(state.is(repair) && target instanceof Tilec ? ((Tilec)target).tile.pos() : Pos.invalid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data) throws IOException{
|
||||
super.read(data);
|
||||
Tile repairing = world.tile(data.readInt());
|
||||
|
||||
if(repairing != null){
|
||||
target = repairing.entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user