Merge branch 'master' of https://github.com/Anuken/Mindustry into markers-update
This commit is contained in:
@@ -30,6 +30,8 @@ public class CommandAI extends AIController{
|
||||
public int groupIndex = 0;
|
||||
/** All encountered unreachable buildings of this AI. Why a sequence? Because contains() is very rarely called on it. */
|
||||
public IntSeq unreachableBuildings = new IntSeq(8);
|
||||
/** ID of unit read as target. This is set up after reading. Do not access! */
|
||||
public int readAttackTarget = -1;
|
||||
|
||||
protected boolean stopAtTarget, stopWhenInRange;
|
||||
protected Vec2 lastTargetPos;
|
||||
@@ -284,7 +286,7 @@ public class CommandAI extends AIController{
|
||||
attackTarget = null;
|
||||
}
|
||||
|
||||
if(unit.isFlying() && move){
|
||||
if(unit.isFlying() && move && (attackTarget == null || !unit.within(attackTarget, unit.type.range))){
|
||||
unit.lookAt(vecMovePos);
|
||||
}else{
|
||||
faceTarget();
|
||||
@@ -349,6 +351,14 @@ public class CommandAI extends AIController{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRead(Unit unit){
|
||||
if(readAttackTarget != -1){
|
||||
attackTarget = Groups.unit.getByID(readAttackTarget);
|
||||
readAttackTarget = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float prefSpeed(){
|
||||
return group == null ? super.prefSpeed() : Math.min(group.minSpeed, unit.speed());
|
||||
|
||||
@@ -1845,6 +1845,7 @@ public class UnitTypes{
|
||||
armor = 3f;
|
||||
|
||||
buildSpeed = 1.5f;
|
||||
rotateToBuilding = false;
|
||||
|
||||
weapons.add(new RepairBeamWeapon("repair-beam-weapon-center"){{
|
||||
x = 0f;
|
||||
@@ -1935,6 +1936,7 @@ public class UnitTypes{
|
||||
abilities.add(new StatusFieldAbility(StatusEffects.overclock, 60f * 6, 60f * 6f, 60f));
|
||||
|
||||
buildSpeed = 2f;
|
||||
rotateToBuilding = false;
|
||||
|
||||
weapons.add(new Weapon("plasma-mount-weapon"){{
|
||||
|
||||
@@ -2009,6 +2011,7 @@ public class UnitTypes{
|
||||
trailScl = 2f;
|
||||
|
||||
buildSpeed = 2f;
|
||||
rotateToBuilding = false;
|
||||
|
||||
weapons.add(new RepairBeamWeapon("repair-beam-weapon-center"){{
|
||||
x = 11f;
|
||||
@@ -2150,6 +2153,7 @@ public class UnitTypes{
|
||||
trailScl = 3.2f;
|
||||
|
||||
buildSpeed = 3f;
|
||||
rotateToBuilding = false;
|
||||
|
||||
abilities.add(new EnergyFieldAbility(40f, 65f, 180f){{
|
||||
statusDuration = 60f * 6f;
|
||||
@@ -2193,6 +2197,7 @@ public class UnitTypes{
|
||||
trailScl = 3.5f;
|
||||
|
||||
buildSpeed = 3.5f;
|
||||
rotateToBuilding = false;
|
||||
|
||||
for(float mountY : new float[]{-117/4f, 50/4f}){
|
||||
for(float sign : Mathf.signs){
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package mindustry.entities;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -14,13 +12,12 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class Fires{
|
||||
private static final float baseLifetime = 1000f;
|
||||
private static final IntMap<Fire> map = new IntMap<>();
|
||||
|
||||
/** Start a fire on the tile. If there already is a fire there, refreshes its lifetime. */
|
||||
public static void create(Tile tile){
|
||||
if(net.client() || tile == null || !state.rules.fire || !state.rules.hasEnv(Env.oxygen)) return; //not clientside.
|
||||
|
||||
Fire fire = map.get(tile.pos());
|
||||
Fire fire = get(tile);
|
||||
|
||||
if(fire == null){
|
||||
fire = Fire.create();
|
||||
@@ -28,48 +25,58 @@ public class Fires{
|
||||
fire.lifetime = baseLifetime;
|
||||
fire.set(tile.worldx(), tile.worldy());
|
||||
fire.add();
|
||||
map.put(tile.pos(), fire);
|
||||
set(tile, fire);
|
||||
}else{
|
||||
fire.lifetime = baseLifetime;
|
||||
fire.time = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public static Fire get(int x, int y){
|
||||
return map.get(Point2.pack(x, y));
|
||||
public static @Nullable Fire get(Tile tile){
|
||||
return world.tiles.getFire(tile.array());
|
||||
}
|
||||
|
||||
public static @Nullable Fire get(int x, int y){
|
||||
return world.tiles.getFire(world.packArray(x, y));
|
||||
}
|
||||
|
||||
private static void set(Tile tile, Fire fire){
|
||||
world.tiles.setFire(tile.array(), fire);
|
||||
}
|
||||
|
||||
public static boolean has(int x, int y){
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height()) || !map.containsKey(Point2.pack(x, y))){
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height())){
|
||||
return false;
|
||||
}
|
||||
Fire fire = map.get(Point2.pack(x, y));
|
||||
return fire.isAdded() && fire.fin() < 1f && fire.tile() != null && fire.tile().x == x && fire.tile().y == y;
|
||||
Fire fire = get(x, y);
|
||||
return fire != null && fire.isAdded() && fire.fin() < 1f && fire.tile != null && fire.tile.x == x && fire.tile.y == y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.
|
||||
*/
|
||||
public static void extinguish(Tile tile, float intensity){
|
||||
if(tile != null && map.containsKey(tile.pos())){
|
||||
Fire fire = map.get(tile.pos());
|
||||
fire.time(fire.time + intensity * Time.delta);
|
||||
Fx.steam.at(fire);
|
||||
if(fire.time >= fire.lifetime){
|
||||
Events.fire(Trigger.fireExtinguish);
|
||||
if(tile != null){
|
||||
Fire fire = get(tile);
|
||||
if(fire != null){
|
||||
fire.time(fire.time + intensity * Time.delta);
|
||||
Fx.steam.at(fire);
|
||||
if(fire.time >= fire.lifetime){
|
||||
Events.fire(Trigger.fireExtinguish);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void remove(Tile tile){
|
||||
if(tile != null){
|
||||
map.remove(tile.pos());
|
||||
set(tile, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(Fire fire){
|
||||
if(fire.tile != null){
|
||||
map.put(fire.tile.pos(), fire);
|
||||
set(fire.tile, fire);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@ public class Puddles{
|
||||
}
|
||||
|
||||
/** Returns the Puddle on the specified tile. May return null. */
|
||||
public static Puddle get(Tile tile){
|
||||
return world.tiles.puddle(tile.array());
|
||||
public static @Nullable Puddle get(Tile tile){
|
||||
return world.tiles.getPuddle(tile.array());
|
||||
}
|
||||
|
||||
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount, boolean initial){
|
||||
|
||||
@@ -214,7 +214,10 @@ public class Units{
|
||||
}
|
||||
});
|
||||
|
||||
return buildResult;
|
||||
var result = buildResult;
|
||||
buildResult = null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Iterates through all buildings in a range. */
|
||||
|
||||
@@ -66,4 +66,9 @@ abstract class EntityComp{
|
||||
void afterRead(){
|
||||
|
||||
}
|
||||
|
||||
/** Called after *all* entities are read. */
|
||||
void afterAllRead(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +183,9 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
if(!unit.isNull()){
|
||||
clearUnit();
|
||||
}
|
||||
|
||||
lastReadUnit = Nulls.unit;
|
||||
justSwitchTo = justSwitchFrom = null;
|
||||
}
|
||||
|
||||
public void team(Team team){
|
||||
|
||||
@@ -490,6 +490,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterAllRead(){
|
||||
controller.afterRead(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(){
|
||||
team.data().updateCount(type, 1);
|
||||
|
||||
@@ -55,6 +55,11 @@ public class AIController implements UnitController{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterRead(Unit unit){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLogicControllable(){
|
||||
return true;
|
||||
|
||||
@@ -27,6 +27,10 @@ public interface UnitController{
|
||||
|
||||
}
|
||||
|
||||
default void afterRead(Unit unit){
|
||||
|
||||
}
|
||||
|
||||
default boolean isBeingControlled(Unit player){
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,13 @@ public class SaveIO{
|
||||
}
|
||||
|
||||
public static boolean isSaveValid(Fi file){
|
||||
return isSaveFileValid(file) || isSaveFileValid(backupFileFor(file));
|
||||
}
|
||||
|
||||
private static boolean isSaveFileValid(Fi file){
|
||||
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(file.read(bufferSize)))){
|
||||
return isSaveValid(stream);
|
||||
getMeta(stream);
|
||||
return true;
|
||||
}catch(Throwable e){
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -437,6 +437,8 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
//entityMapping is null in older save versions, so use the default
|
||||
var mapping = this.entityMapping == null ? EntityMapping.idMap : this.entityMapping;
|
||||
|
||||
Seq<Entityc> entities = new Seq<>();
|
||||
|
||||
int amount = stream.readInt();
|
||||
for(int j = 0; j < amount; j++){
|
||||
readChunk(stream, true, in -> {
|
||||
@@ -449,12 +451,17 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
int id = in.readInt();
|
||||
|
||||
Entityc entity = (Entityc)mapping[typeid].get();
|
||||
entities.add(entity);
|
||||
EntityGroup.checkNextId(id);
|
||||
entity.id(id);
|
||||
entity.read(Reads.get(in));
|
||||
entity.add();
|
||||
});
|
||||
}
|
||||
|
||||
for(var e : entities){
|
||||
e.afterAllRead();
|
||||
}
|
||||
}
|
||||
|
||||
public void readEntityMapping(DataInput stream) throws IOException{
|
||||
|
||||
@@ -563,13 +563,14 @@ public class TypeIO{
|
||||
ai.targetPos = null;
|
||||
}
|
||||
ai.setupLastPos();
|
||||
ai.readAttackTarget = -1;
|
||||
|
||||
if(hasAttack){
|
||||
byte entityType = read.b();
|
||||
if(entityType == 1){
|
||||
ai.attackTarget = world.build(read.i());
|
||||
}else{
|
||||
ai.attackTarget = Groups.unit.getByID(read.i());
|
||||
ai.attackTarget = Groups.unit.getByID(ai.readAttackTarget = read.i());
|
||||
}
|
||||
}else{
|
||||
ai.attackTarget = null;
|
||||
|
||||
@@ -1372,13 +1372,20 @@ public class LExecutor{
|
||||
exec.setobj(result, i < 0 || i >= builds.size ? null : builds.get(i));
|
||||
}
|
||||
}
|
||||
case unitCount -> exec.setnum(result, data.units.size);
|
||||
case unitCount -> {
|
||||
UnitType type = exec.obj(extra) instanceof UnitType u ? u : null;
|
||||
if(type == null){
|
||||
exec.setnum(result, data.units.size);
|
||||
}else{
|
||||
exec.setnum(result, data.unitsByType[type.id].size);
|
||||
}
|
||||
}
|
||||
case coreCount -> exec.setnum(result, data.cores.size);
|
||||
case playerCount -> exec.setnum(result, data.players.size);
|
||||
case buildCount -> {
|
||||
Block block = exec.obj(extra) instanceof Block b ? b : null;
|
||||
if(block == null){
|
||||
exec.setobj(result, null);
|
||||
exec.setnum(result, data.buildings.size);
|
||||
}else{
|
||||
exec.setnum(result, data.getBuildings(block).size);
|
||||
}
|
||||
|
||||
@@ -1740,7 +1740,7 @@ public class LStatements{
|
||||
fields(table, index, i -> index = i);
|
||||
}
|
||||
|
||||
if(type == FetchType.buildCount || type == FetchType.build){
|
||||
if(type == FetchType.buildCount || type == FetchType.build || type == FetchType.unitCount){
|
||||
row(table);
|
||||
|
||||
fields(table, "block", extra, i -> extra = i);
|
||||
|
||||
@@ -952,7 +952,7 @@ public class UnitType extends UnlockableContent implements Senseable{
|
||||
public void createIcons(MultiPacker packer){
|
||||
super.createIcons(packer);
|
||||
|
||||
if(constructor == null) throw new IllegalArgumentException("No constructor set up for unit '" + name + "'. Make sure you assign a valid value to `constructor`, e.g. `constructor = UnitEntity::new`");
|
||||
if(constructor == null) throw new IllegalArgumentException("No constructor set up for unit '" + name + "', add this argument to your units field: `constructor = UnitEntity::create`");
|
||||
|
||||
sample = constructor.get();
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ public class BlockConfigFragment{
|
||||
|
||||
table.visible = true;
|
||||
table.clear();
|
||||
table.background(null);
|
||||
tile.buildConfiguration(table);
|
||||
table.pack();
|
||||
table.setTransform(true);
|
||||
|
||||
@@ -14,15 +14,17 @@ public class Tiles implements Iterable<Tile>{
|
||||
|
||||
final Tile[] array;
|
||||
final Puddle[] puddles;
|
||||
final Fire[] fires;
|
||||
|
||||
public Tiles(int width, int height){
|
||||
this.array = new Tile[width * height];
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.puddles = new Puddle[width * height];
|
||||
this.fires = new Fire[width * height];
|
||||
}
|
||||
|
||||
public Puddle puddle(int pos){
|
||||
public Puddle getPuddle(int pos){
|
||||
return puddles[pos];
|
||||
}
|
||||
|
||||
@@ -30,6 +32,15 @@ public class Tiles implements Iterable<Tile>{
|
||||
puddles[pos] = p;
|
||||
}
|
||||
|
||||
public Fire getFire(int pos){
|
||||
return fires[pos];
|
||||
}
|
||||
|
||||
public void setFire(int pos, Fire f){
|
||||
fires[pos] = f;
|
||||
}
|
||||
|
||||
|
||||
public void each(Intc2 cons){
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
|
||||
Reference in New Issue
Block a user