Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features

 Conflicts:
	core/assets/icons/icons.properties
	core/assets/logicids.dat
	core/src/mindustry/ui/dialogs/PlanetDialog.java
	core/src/mindustry/world/blocks/distribution/ItemBridge.java
	core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java
	core/src/mindustry/world/blocks/storage/StorageBlock.java
	gradle.properties
This commit is contained in:
Anuken
2021-08-10 15:15:07 -04:00
196 changed files with 2485 additions and 1664 deletions
+7 -10
View File
@@ -16,12 +16,12 @@ public class Puddles{
/** Deposits a Puddle between tile and source. */
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){
deposit(tile, source, liquid, amount, 0);
deposit(tile, source, liquid, amount, true);
}
/** Deposits a Puddle at a tile. */
public static void deposit(Tile tile, Liquid liquid, float amount){
deposit(tile, tile, liquid, amount, 0);
deposit(tile, tile, liquid, amount, true);
}
/** Returns the Puddle on the specified tile. May return null. */
@@ -29,7 +29,7 @@ public class Puddles{
return map.get(tile.pos());
}
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount, boolean initial){
if(tile == null) return;
if(tile.floor().isLiquid && !canStayOn(liquid, tile.floor().liquidDrop)){
@@ -38,16 +38,14 @@ public class Puddles{
Puddle p = map.get(tile.pos());
if(generation == 0 && p != null && p.lastRipple <= Time.time - 40f){
if(initial && p != null && p.lastRipple <= Time.time - 40f){
Fx.ripple.at((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f, 1f, tile.floor().liquidDrop.color);
p.lastRipple = Time.time;
}
return;
}
if(tile.floor().solid){
return;
}
if(tile.floor().solid) return;
Puddle p = map.get(tile.pos());
if(p == null){
@@ -55,14 +53,13 @@ public class Puddles{
puddle.tile = tile;
puddle.liquid = liquid;
puddle.amount = amount;
puddle.generation = generation;
puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
puddle.add();
map.put(tile.pos(), puddle);
puddle.add();
}else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting);
if(generation == 0 && p.lastRipple <= Time.time - 40f && p.amount >= maxLiquid / 2f){
if(initial && p.lastRipple <= Time.time - 40f && p.amount >= maxLiquid / 2f){
Fx.ripple.at((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f, 1f, p.liquid.color);
p.lastRipple = Time.time;
}
+22 -1
View File
@@ -22,6 +22,7 @@ public class Units{
private static float cdist;
private static boolean boolResult;
private static int intResult;
private static Building buildResult;
@Remote(called = Loc.server)
public static void unitCapDeath(Unit unit){
@@ -142,7 +143,7 @@ public class Units{
/** Returns the nearest damaged tile. */
public static Building findDamagedTile(Team team, float x, float y){
return Geometry.findClosest(x, y, indexer.getDamaged(team));
return indexer.getDamaged(team).min(b -> b.dst2(x, y));
}
/** Returns the nearest ally tile in a range. */
@@ -157,6 +158,26 @@ public class Units{
return indexer.findEnemyTile(team, x, y, range, pred);
}
/** @return the closest building of the provided team that matches the predicate. */
public static @Nullable Building closestBuilding(Team team, float wx, float wy, float range, Boolf<Building> pred){
buildResult = null;
cdist = 0f;
var buildings = team.data().buildings;
if(buildings == null) return null;
buildings.intersect(wx - range, wy - range, range*2f, range*2f, b -> {
if(pred.get(b)){
float dst = b.dst(wx, wy) - b.hitSize()/2f;
if(dst <= range && (buildResult == null || dst <= cdist)){
cdist = dst;
buildResult = b;
}
}
});
return buildResult;
}
/** Iterates through all buildings in a range. */
public static void nearbyBuildings(float x, float y, float range, Cons<Building> cons){
indexer.allBuildings(x, y, range, cons);
@@ -14,6 +14,8 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import static mindustry.Vars.*;
public class EnergyFieldAbility extends Ability{
private static final Seq<Healthc> all = new Seq<>();
@@ -31,6 +33,7 @@ public class EnergyFieldAbility extends Ability{
public float effectRadius = 5f, sectorRad = 0.14f, rotateSpeed = 0.5f;
public int sectors = 5;
public Color color = Pal.heal;
public boolean useAmmo = true;
protected float timer, curStroke;
protected boolean anyNearby = false;
@@ -88,8 +91,7 @@ public class EnergyFieldAbility extends Ability{
curStroke = Mathf.lerpDelta(curStroke, anyNearby ? 1 : 0, 0.09f);
if((timer += Time.delta) >= reload){
if((timer += Time.delta) >= reload && (!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo)){
Tmp.v1.trns(unit.rotation - 90, x, y).add(unit.x, unit.y);
float rx = Tmp.v1.x, ry = Tmp.v1.y;
anyNearby = false;
@@ -131,7 +133,11 @@ public class EnergyFieldAbility extends Ability{
}
}else{
anyNearby = true;
other.damage(damage);
if(other instanceof Building b){
b.damage(unit.team, damage);
}else{
other.damage(damage);
}
if(other instanceof Statusc s){
s.apply(status, statusDuration);
}
@@ -143,6 +149,10 @@ public class EnergyFieldAbility extends Ability{
if(anyNearby){
shootSound.at(unit);
if(useAmmo && state.rules.unitAmmo){
unit.ammo --;
}
}
timer = 0f;
@@ -24,6 +24,8 @@ public class MoveLightningAbility extends Ability{
public Color color = Color.valueOf("a9d8ff");
/** Shifts where the lightning spawns along the Y axis */
public float offset = 0f;
/** Offset along the X axis. */
public float width = 0f;
/** Jittering heat sprite like the shield on v5 Javelin */
public String heatRegion = "error";
/** Bullet type that is fired. Can be null */
@@ -33,6 +35,8 @@ public class MoveLightningAbility extends Ability{
public Effect shootEffect = Fx.sparkShoot;
public Sound shootSound = Sounds.spark;
protected float side = 1f;
MoveLightningAbility(){}
@@ -61,7 +65,7 @@ public class MoveLightningAbility extends Ability{
public void update(Unit unit){
float scl = Mathf.clamp((unit.vel().len() - minSpeed) / (maxSpeed - minSpeed));
if(Mathf.chance(Time.delta * chance * scl)){
float x = unit.x + Angles.trnsx(unit.rotation, offset, 0), y = unit.y + Angles.trnsy(unit.rotation, offset, 0);
float x = unit.x + Angles.trnsx(unit.rotation, offset, width * side), y = unit.y + Angles.trnsy(unit.rotation, offset, width * side);
shootEffect.at(x, y, unit.rotation, color);
shootSound.at(unit);
@@ -73,6 +77,8 @@ public class MoveLightningAbility extends Ability{
if(bullet != null){
bullet.create(unit, unit.team, x, y, unit.rotation + bulletAngle + Mathf.range(bulletSpread));
}
side *= -1f;
}
}
@@ -343,15 +343,6 @@ public class BulletType extends Content implements Cloneable{
if(instantDisappear){
b.time = lifetime;
}
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
despawnHit = true;
}
if(lightRadius == -1){
lightRadius = Math.max(18, hitSize * 5f);
}
drawSize = Math.max(drawSize, trailLength * speed * 2f);
}
public void update(Bullet b){
@@ -412,6 +403,15 @@ public class BulletType extends Content implements Cloneable{
if(lightningType == null){
lightningType = !collidesAir ? Bullets.damageLightningGround : Bullets.damageLightning;
}
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
despawnHit = true;
}
if(lightRadius == -1){
lightRadius = Math.max(18, hitSize * 5f);
}
drawSize = Math.max(drawSize, trailLength * speed * 2f);
}
@Override
@@ -0,0 +1,64 @@
package mindustry.entities.bullet;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class FireBulletType extends BulletType{
public Color colorFrom = Pal.lightFlame, colorMid = Pal.darkFlame, colorTo = Color.gray;
public float radius = 3f;
public float velMin = 0.6f, velMax = 2.6f;
public float fireTrailChance = 0.04f;
public Effect trailEffect2 = Fx.ballfire;
public float fireEffectChance = 0.1f, fireEffectChance2 = 0.1f;
{
pierce = true;
collidesTiles = false;
collides = false;
drag = 0.03f;
hitEffect = despawnEffect = Fx.none;
trailEffect = Fx.fireballsmoke;
}
public FireBulletType(float speed, float damage){
super(speed, damage);
}
public FireBulletType(){}
@Override
public void init(Bullet b){
super.init(b);
b.vel.setLength(Mathf.random(velMin, velMax));
}
@Override
public void draw(Bullet b){
Draw.color(colorFrom, colorMid, colorTo, b.fin());
Fill.circle(b.x, b.y, radius * b.fout());
Draw.reset();
}
@Override
public void update(Bullet b){
super.update(b);
if(Mathf.chanceDelta(fireTrailChance)){
Fires.create(b.tileOn());
}
if(Mathf.chanceDelta(fireEffectChance)){
trailEffect.at(b.x, b.y);
}
if(Mathf.chanceDelta(fireEffectChance2)){
trailEffect2.at(b.x, b.y);
}
}
}
@@ -13,7 +13,7 @@ import static mindustry.Vars.*;
public class MassDriverBolt extends BulletType{
public MassDriverBolt(){
super(1f, 50);
super(1f, 75);
collidesTiles = false;
lifetime = 1f;
despawnEffect = Fx.smeltsmoke;
@@ -1,28 +0,0 @@
package mindustry.entities.comp;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.blocks.units.*;
@Component
abstract class AmmoDistributeComp implements Unitc{
@Import float x, y;
@Import UnitType type;
@Import Team team;
@Import float ammo;
private transient float ammoCooldown;
@Override
public void update(){
if(ammoCooldown > 0f) ammoCooldown -= Time.delta;
if(ammo > 0 && ammoCooldown <= 0f && ResupplyPoint.resupply(team, x, y, type.ammoResupplyRange, Math.min(type.ammoResupplyAmount, ammo), type.ammoType.color, u -> u != self())){
ammo -= Math.min(type.ammoResupplyAmount, ammo);
ammoCooldown = 5f;
}
}
}
@@ -96,7 +96,7 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{
if(!(tile.build instanceof ConstructBuild cb)){
if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){
boolean hasAll = infinite || current.isRotation(team) || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item));
boolean hasAll = infinite || current.isRotation(team) || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item, Math.min(Mathf.round(i.amount * state.rules.buildCostMultiplier), 1)));
if(hasAll){
Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation);
@@ -176,7 +176,7 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{
/** @return whether this request should be skipped, in favor of the next one. */
boolean shouldSkip(BuildPlan request, @Nullable Building core){
//requests that you have at least *started* are considered
if(state.rules.infiniteResources || team.rules().infiniteResources || request.breaking || core == null || request.isRotation(team)) return false;
if(state.rules.infiniteResources || team.rules().infiniteResources || request.breaking || core == null || request.isRotation(team) || (isBuilding() && !within(plans.last(), buildingRange))) return false;
return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item, Math.min(i.amount, 15)) && Mathf.round(i.amount * state.rules.buildCostMultiplier) > 0) && !request.initialized);
}
@@ -49,6 +49,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
static final float timeToSleep = 60f * 1, timeToUncontrol = 60f * 6;
static final ObjectSet<Building> tmpTiles = new ObjectSet<>();
static final Seq<Building> tempBuilds = new Seq<>();
static final BuildTeamChangeEvent teamChangeEvent = new BuildTeamChangeEvent();
static int sleepingEntities = 0;
@Import float x, y, health, maxHealth;
@@ -63,6 +64,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
transient boolean enabled = true;
transient float enabledControlTime;
transient String lastAccessed;
transient boolean wasDamaged; //used only by the indexer
PowerModule power;
ItemModule items;
@@ -158,7 +160,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public final void readBase(Reads read){
health = read.f();
//cap health by block health in case of nerfs
health = Math.min(read.f(), block.health);
byte rot = read.b();
team = Team.get(read.b());
@@ -1071,7 +1074,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public String getDisplayName(){
return block.localizedName;
//derelict team icon currently doesn't display
return team == Team.derelict ?
block.localizedName + "\n" + Core.bundle.get("block.derelict") :
block.localizedName + (team == player.team() || team.emoji.isEmpty() ? "" : " " + team.emoji);
}
public TextureRegion getDisplayIcon(){
@@ -1100,7 +1106,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
table.row();
table.table(this::displayConsumption).growX();
boolean displayFlow = (block.category == Category.distribution || block.category == Category.liquid) && Core.settings.getBool("flow") && block.displayFlow;
boolean displayFlow = (block.category == Category.distribution || block.category == Category.liquid) && block.displayFlow;
if(displayFlow){
String ps = " " + StatUnit.perSecond.localized();
@@ -1254,9 +1260,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Changes this building's team in a safe manner. */
public void changeTeam(Team next){
Team last = this.team;
indexer.removeIndex(tile);
this.team = next;
indexer.addIndex(tile);
Events.fire(teamChangeEvent.set(last, self()));
}
public boolean canPickup(){
@@ -1342,6 +1350,18 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return tile.build == self() && !dead();
}
@MethodPriority(100)
@Override
public void heal(){
indexer.notifyBuildHealed(self());
}
@MethodPriority(100)
@Override
public void heal(float amount){
indexer.notifyBuildHealed(self());
}
@Override
public float hitSize(){
return tile.block().size * tilesize;
@@ -81,7 +81,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
}
public boolean hasCollided(int id){
return collided.size != 0 && !collided.contains(id);
return collided.size != 0 && collided.contains(id);
}
@Replace
@@ -1,5 +1,6 @@
package mindustry.entities.comp;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
@@ -20,16 +21,29 @@ import static mindustry.entities.Puddles.*;
@EntityDef(value = {Puddlec.class}, pooled = true)
@Component(base = true)
abstract class PuddleComp implements Posc, Puddlec, Drawc{
private static final int maxGeneration = 2;
private static final Rect rect = new Rect(), rect2 = new Rect();
private static int seeds;
private static Puddle paramPuddle;
private static Cons<Unit> unitCons = unit -> {
if(unit.isGrounded() && !unit.hovering){
unit.hitbox(rect2);
if(rect.overlaps(rect2)){
unit.apply(paramPuddle.liquid.effect, 60 * 2);
if(unit.vel.len2() > 0.1f * 0.1f){
Fx.ripple.at(unit.x, unit.y, unit.type.rippleScale, paramPuddle.liquid.color);
}
}
}
};
@Import int id;
@Import float x, y;
transient float accepting, updateTime, lastRipple;
transient private boolean mismatch = false;
transient float accepting, updateTime, lastRipple = Time.time + Mathf.random(40f);
float amount;
int generation;
Tile tile;
Liquid liquid;
@@ -39,46 +53,45 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
@Override
public void update(){
//update code
float addSpeed = accepting > 0 ? 3f : 0f;
amount -= Time.delta * (1f - liquid.viscosity) / (5f + addSpeed);
amount += accepting;
accepting = 0f;
if(amount >= maxLiquid / 1.5f && generation < maxGeneration){
if(amount >= maxLiquid / 1.5f){
float deposited = Math.min((amount - maxLiquid / 1.5f) / 4f, 0.3f) * Time.delta;
int targets = 0;
for(Point2 point : Geometry.d4){
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
if(other != null && other.block() == Blocks.air){
Puddles.deposit(other, tile, liquid, deposited, generation + 1);
amount -= deposited / 2f; //tweak to speed up/slow down Puddle propagation
targets ++;
Puddles.deposit(other, tile, liquid, deposited, false);
}
}
amount -= deposited * targets;
}
amount = Mathf.clamp(amount, 0, maxLiquid);
if(amount <= 0f){
remove();
return;
}
if(Puddles.get(tile) != self()){
mismatch = true;
remove();
return;
}
//effects-only code
if(amount >= maxLiquid / 2f && updateTime <= 0f){
Units.nearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> {
if(unit.isGrounded() && !unit.hovering){
unit.hitbox(rect2);
if(rect.overlaps(rect2)){
unit.apply(liquid.effect, 60 * 2);
paramPuddle = self();
if(unit.vel.len() > 0.1){
Fx.ripple.at(unit.x, unit.y, unit.type.rippleScale, liquid.color);
}
}
}
});
Units.nearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unitCons);
if(liquid.temperature > 0.7f && (tile.build != null) && Mathf.chance(0.5)){
if(liquid.temperature > 0.7f && tile.build != null && Mathf.chance(0.5)){
Fires.create(tile);
}
@@ -121,7 +134,9 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
@Override
public void remove(){
Puddles.remove(tile);
if(!mismatch){
Puddles.remove(tile);
}
}
@Override
@@ -154,7 +154,7 @@ abstract class StatusComp implements Posc, Flyingc{
public void draw(){
for(StatusEntry e : statuses){
e.effect.draw(self());
e.effect.draw(self(), e.time);
}
}
@@ -59,6 +59,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
vel.approachDelta(vector, type.accel * realSpeed());
}
public void rotateMove(Vec2 vec){
moveAt(Tmp.v2.trns(rotation, vec.len()));
if(!vec.isZero()){
rotation = Angles.moveToward(rotation, vec.angle(), type.rotateSpeed * Math.max(Time.delta, 1));
}
}
public void aimLook(Position pos){
aim(pos);
lookAt(pos);
@@ -126,6 +134,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
if(isBuilding()){
return state.rules.infiniteResources ? Float.MAX_VALUE : Math.max(type.clipSize, type.region.width) + buildingRange + tilesize*4f;
}
if(mining()){
return type.clipSize + type.miningRange;
}
return type.clipSize;
}
@@ -6,6 +6,7 @@ import arc.util.*;
import mindustry.*;
import mindustry.ai.*;
import mindustry.entities.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
@@ -79,7 +80,6 @@ public class AIController implements UnitController{
return Units.invalidateTarget(target, unit.team, unit.x, unit.y);
}
protected void pathfind(int pathTarget){
int costType = unit.pathType();
@@ -97,7 +97,7 @@ public class AIController implements UnitController{
boolean ret = retarget();
if(ret){
target = findTarget(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround);
target = findMainTarget(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround);
}
if(invalid(target)){
@@ -155,6 +155,7 @@ public class AIController implements UnitController{
}
protected Teamc targetFlag(float x, float y, BlockFlag flag, boolean enemy){
if(unit.team == Team.derelict) return null;
Tile target = Geometry.findClosest(x, y, enemy ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag));
return target == null ? null : target.build;
}
@@ -167,6 +168,10 @@ public class AIController implements UnitController{
return timer.get(timerTarget, target == null ? 40 : 90);
}
protected Teamc findMainTarget(float x, float y, float range, boolean air, boolean ground){
return findTarget(x, y, range, air, ground);
}
protected Teamc findTarget(float x, float y, float range, boolean air, boolean ground){
return target(x, y, range, air, ground);
}