diff --git a/core/assets-raw/sprites/blocks/defense/regen-projector.png b/core/assets-raw/sprites/blocks/defense/regen-projector.png index 7c54117503..46230dd168 100644 Binary files a/core/assets-raw/sprites/blocks/defense/regen-projector.png and b/core/assets-raw/sprites/blocks/defense/regen-projector.png differ diff --git a/core/assets/shaders/shield.frag b/core/assets/shaders/shield.frag index ae0d8fab72..098f62c7b1 100644 --- a/core/assets/shaders/shield.frag +++ b/core/assets/shaders/shield.frag @@ -21,18 +21,10 @@ void main(){ vec4 color = texture2D(u_texture, T); vec2 v = u_invsize; - vec4 maxed = max(max(max(max(max(max(max( - texture2D(u_texture, T + vec2(0, step) * v), - texture2D(u_texture, T + vec2(0, -step) * v)), - texture2D(u_texture, T + vec2(step, 0) * v)), - texture2D(u_texture, T + vec2(-step, 0) * v)), - - texture2D(u_texture, T + vec2(-step, -step) * v)), - texture2D(u_texture, T + vec2(-step, step) * v)), - texture2D(u_texture, T + vec2(step, -step) * v)), - texture2D(u_texture, T + vec2(step, step) * v)); + vec4 maxed = max(max(max(texture2D(u_texture, T + vec2(0, step) * v), texture2D(u_texture, T + vec2(0, -step) * v)), texture2D(u_texture, T + vec2(step, 0) * v)), texture2D(u_texture, T + vec2(-step, 0) * v)); if(texture2D(u_texture, T).a < 0.9 && maxed.a > 0.9){ + gl_FragColor = vec4(maxed.rgb, maxed.a * 100.0); }else{ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 409235fd28..d729f1e272 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1513,7 +1513,8 @@ public class Blocks{ //TODO requirements(Category.effect, with(Items.surgeAlloy, 100, Items.silicon, 125)); size = 3; - radius = 50f; + width = 50f; + length = 36; shieldHealth = 2000f; cooldownNormal = 3f; cooldownBrokenBase = 0.35f; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index e9dbada86d..3dc5ee97e1 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -78,6 +78,14 @@ public class Fx{ Draw.rect(Icon.warning.getRegion(), e.x, e.y, size, size); }), + unitEnvKill = new Effect(80f, e -> { + color(Color.scarlet); + alpha(e.fout(Interp.pow4Out)); + + float size = 10f + e.fout(Interp.pow10In) * 25f; + Draw.rect(Icon.cancel.getRegion(), e.x, e.y, size, size); + }), + unitControl = new Effect(30f, e -> { if(!(e.data instanceof Unit select)) return; diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index a4b94ae570..2c5797067d 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -33,6 +33,15 @@ public class Units{ } } + @Remote(called = Loc.server) + public static void unitEnvDeath(Unit unit){ + if(unit != null){ + unit.dead = true; + Fx.unitEnvKill.at(unit); + Core.app.post(() -> Call.unitDestroy(unit.id)); + } + } + @Remote(called = Loc.server) public static void unitDeath(int uid){ Unit unit = Groups.unit.getByID(uid); diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index 7df354bf40..3f8f9f7d50 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -378,7 +378,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I //check if environment is unsupported if(!type.supportsEnv(state.rules.environment) && !dead){ - Call.unitCapDeath(self()); + Call.unitEnvDeath(self()); team.data().updateCount(type, -1); } diff --git a/core/src/mindustry/logic/LParser.java b/core/src/mindustry/logic/LParser.java index d6e8b40e62..f8d3d37bfa 100644 --- a/core/src/mindustry/logic/LParser.java +++ b/core/src/mindustry/logic/LParser.java @@ -138,8 +138,7 @@ public class LParser{ try{ st = LogicIO.read(tokens, tok); }catch(Exception e){ - //log invalid statements - Log.err(e); + //replace invalid statements st = new InvalidStatement(); } diff --git a/core/src/mindustry/world/blocks/defense/DirectionalForceProjector.java b/core/src/mindustry/world/blocks/defense/DirectionalForceProjector.java index 4525c9102c..6ca4b35ab6 100644 --- a/core/src/mindustry/world/blocks/defense/DirectionalForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/DirectionalForceProjector.java @@ -6,19 +6,32 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.*; +import mindustry.world.consumers.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; -public class DirectionalForceProjector extends ForceProjector{ +//TODO use completely different layer +//TODO consume heat +public class DirectionalForceProjector extends Block{ protected static final Vec2 intersectOut = new Vec2(), p1 = new Vec2(), p2 = new Vec2(); + protected static DirectionalForceProjectorBuild paramEntity; + protected static Effect paramEffect; protected static final Cons dirShieldConsumer = b -> { if(b.team != paramEntity.team && b.type.absorbable){ //just in case float deltaAdd = 1.1f; - if(Intersector.intersectSegments(b.x, b.y, b.x + b.vel.x * (Time.delta + deltaAdd), b.y + b.vel.y * (Time.delta + deltaAdd), p1.x, p1.y, p2.x, p2.y, intersectOut)){ + if(Intersector.intersectSegments(b.x, b.y, + b.x + b.vel.x * (Time.delta + deltaAdd), + b.y + b.vel.y * (Time.delta + deltaAdd), p1.x, p1.y, p2.x, p2.y, intersectOut)){ b.set(intersectOut); b.absorb(); paramEffect.at(b); @@ -28,48 +41,141 @@ public class DirectionalForceProjector extends ForceProjector{ } }; - //TODO proper length? + public float width = 30f; + public float shieldHealth = 3000f; + public float cooldownNormal = 1.75f; + public float cooldownLiquid = 1.5f; + public float cooldownBrokenBase = 0.35f; + + public Effect absorbEffect = Fx.absorb; + public Effect shieldBreakEffect = Fx.shieldBreak; + public @Load("@-top") TextureRegion topRegion; + public float length = 40f; public float padSize = 40f; public DirectionalForceProjector(String name){ super(name); - radius = 30f; - consumeCoolant = false; rotate = true; rotateDraw = false; + + update = true; + solid = true; + group = BlockGroup.projectors; + envEnabled |= Env.space; + ambientSound = Sounds.shield; + ambientSoundVolume = 0.08f; } @Override public void init(){ + clipSize = Math.max(clipSize, (width + 3f) * 2f); + super.init(); + if(length < 0){ length = size * tilesize/2f; } } + @Override + public void setBars(){ + super.setBars(); + bars.add("shield", (DirectionalForceProjectorBuild entity) -> new Bar("stat.shieldhealth", Pal.accent, () -> entity.broken ? 0f : 1f - entity.buildup / (shieldHealth)).blink(Color.white)); + } + + @Override + public boolean outputsItems(){ + return false; + } + + @Override + public void setStats(){ + super.setStats(); + stats.add(Stat.shieldHealth, shieldHealth, StatUnit.none); + stats.add(Stat.cooldownTime, (int) (shieldHealth / cooldownBrokenBase / 60f), StatUnit.seconds); + } + @Override public void drawPlace(int x, int y, int rotation, boolean valid){ drawPotentialLinks(x, y); - //TODO + x *= tilesize; + y *= tilesize; + + Tmp.v1.set(length - size/2f, (width + size/2f)).rotate(rotation * 90).add(x, y); + Tmp.v2.set(length - size/2f, -(width + size/2f)).rotate(rotation * 90).add(x, y); + + Drawf.dashLine(Color.lightGray, x, y, Tmp.v1.x, Tmp.v1.y); + Drawf.dashLine(Color.lightGray, x, y, Tmp.v2.x, Tmp.v2.y); + Drawf.dashLine(Pal.accent, Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y); } - public class DirectionalForceProjectorBuild extends ForceBuild{ + public class DirectionalForceProjectorBuild extends Building{ + public boolean broken = true; + public float buildup, hit, warmup, shieldRadius; @Override - public void deflectBullets(){ - float realRadius = realRadius(); + public boolean shouldAmbientSound(){ + return !broken && shieldRadius > 1f; + } - if(realRadius > 0 && !broken){ + @Override + public void pickedUp(){ + super.pickedUp(); + shieldRadius = warmup = 0f; + } + + @Override + public void updateTile(){ + shieldRadius = Mathf.lerpDelta(shieldRadius, broken ? 0f : warmup * width, 0.05f); + + //TODO ????????????????? + if(Mathf.chanceDelta(buildup / shieldHealth * 0.1f)){ + Fx.reactorsmoke.at(x + Mathf.range(tilesize / 2f), y + Mathf.range(tilesize / 2f)); + } + + warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f); + + if(buildup > 0 && consumes.has(ConsumeType.liquid)){ + float scale = !broken ? cooldownNormal : cooldownBrokenBase; + Consume cons = consumes.get(ConsumeType.liquid); + if(cons.valid(this)){ + cons.update(this); + scale *= (cooldownLiquid * (1f + (liquids.current().heatCapacity - 0.4f) * 0.9f)); + } + + buildup -= delta() * scale; + } + + if(broken && buildup <= 0){ + broken = false; + } + + if(buildup >= shieldHealth && !broken){ + broken = true; + buildup = shieldHealth; + shieldBreakEffect.at(x, y, shieldRadius, team.color); + } + + if(hit > 0f){ + hit -= 1f / 5f * Time.delta; + } + + deflectBullets(); + } + + public void deflectBullets(){ + + if(shieldRadius > 0 && !broken){ paramEntity = this; paramEffect = absorbEffect; //top - p1.set(length, realRadius).rotate(rotdeg()); + p1.set(length, shieldRadius).rotate(rotdeg()); //bot - p2.set(length, -realRadius).rotate(rotdeg()); + p2.set(length, -shieldRadius).rotate(rotdeg()); //"check" radius is grown to catch bullets moving at high velocity Tmp.r1.set(p2.x, p2.y, p1.x - p2.x, p1.y - p2.y).normalize().grow(padSize); @@ -82,13 +188,30 @@ public class DirectionalForceProjector extends ForceProjector{ } @Override - public void drawShield(){ - if(!broken && realRadius() > 0){ - float realRadius = realRadius(), rot = rotdeg(); + public void draw(){ + super.draw(); - p1.set(length, realRadius).rotate(rot).add(this); - p2.set(length, -realRadius).rotate(rot).add(this); - float size = 3f; + //TODO wrong + if(buildup > 0f){ + Draw.alpha(buildup / shieldHealth * 0.75f); + Draw.z(Layer.blockAdditive); + Draw.blend(Blending.additive); + Draw.rect(topRegion, x, y); + Draw.blend(); + Draw.z(Layer.block); + Draw.reset(); + } + + drawShield(); + } + + public void drawShield(){ + if(!broken && shieldRadius > 0){ + float rot = rotdeg(); + + p1.set(length, shieldRadius).rotate(rot).add(this); + p2.set(length, -shieldRadius).rotate(rot).add(this); + float size = 4f; Tmp.r1.set(p2.x, p2.y, p1.x - p2.x, p1.y - p2.y).normalize().grow(size); Draw.z(Layer.shields); @@ -98,15 +221,20 @@ public class DirectionalForceProjector extends ForceProjector{ if(renderer.animateShields){ Fill.rect(Tmp.r1); - Tmp.v1.set(length - size/2f - size * 2, (realRadius + size/2f)).rotate(rot).add(this); - Tmp.v2.set(length - size/2f - size * 2, -(realRadius + size/2f)).rotate(rot).add(this); + Tmp.v1.set(length - size/2f, (shieldRadius + size/2f)).rotate(rot).add(this); + Tmp.v2.set(length - size/2f, -(shieldRadius + size/2f)).rotate(rot).add(this); - Fill.tri(x, y, Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y); + //Fill.tri(x, y, Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y); + Lines.stroke(3f); + Lines.line(x, y, Tmp.v1.x, Tmp.v1.y); + Lines.line(x, y, Tmp.v2.x, Tmp.v2.y); + + Draw.z(Layer.shields); for(int i : Mathf.signs){ - Tmp.v1.set(length - size/2f, (realRadius + size/2f) * i).rotate(rot).add(this); - Tmp.v3.set(length + size/2f, (realRadius + size/2f) * i).rotate(rot).add(this); - Tmp.v2.set(length, (realRadius + size) * i).rotate(rot).add(this); + Tmp.v1.set(length - size/2f, (shieldRadius + size/2f) * i).rotate(rot).add(this); + Tmp.v3.set(length + size/2f, (shieldRadius + size/2f) * i).rotate(rot).add(this); + Tmp.v2.set(length, (shieldRadius + size) * i).rotate(rot).add(this); Fill.tri(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y, Tmp.v3.x, Tmp.v3.y); } }else{ @@ -121,5 +249,25 @@ public class DirectionalForceProjector extends ForceProjector{ Draw.reset(); } } + + //TODO + /* + @Override + public void write(Writes write){ + super.write(write); + write.bool(broken); + write.f(buildup); + write.f(radscl); + write.f(warmup); + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); + broken = read.bool(); + buildup = read.f(); + radscl = read.f(); + warmup = read.f(); + }*/ } } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 488d366cc3..1356619b19 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -155,12 +155,15 @@ public class ForceProjector extends Block{ warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f); - if(buildup > 0 && consumes.has(ConsumeType.liquid)){ + if(buildup > 0){ float scale = !broken ? cooldownNormal : cooldownBrokenBase; - Consume cons = consumes.get(ConsumeType.liquid); - if(cons.valid(this)){ - cons.update(this); - scale *= (cooldownLiquid * (1f + (liquids.current().heatCapacity - 0.4f) * 0.9f)); + + if(consumes.has(ConsumeType.liquid)){ + Consume cons = consumes.get(ConsumeType.liquid); + if(cons.valid(this)){ + cons.update(this); + scale *= (cooldownLiquid * (1f + (liquids.current().heatCapacity - 0.4f) * 0.9f)); + } } buildup -= delta() * scale; diff --git a/core/src/mindustry/world/blocks/payloads/PayloadSource.java b/core/src/mindustry/world/blocks/payloads/PayloadSource.java index d2146d5a48..a02e3bd29a 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadSource.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadSource.java @@ -75,7 +75,7 @@ public class PayloadSource extends PayloadBlock{ } public boolean canProduce(UnitType t){ - return !t.isHidden() && !t.isBanned(); + return !t.isHidden() && !t.isBanned() && t.supportsEnv(state.rules.environment); } public class PayloadSourceBuild extends PayloadBlockBuild{ diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index c6e03236a8..6e4770f919 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -111,7 +111,7 @@ public class Reconstructor extends UnitBlock{ @Override public boolean acceptUnitPayload(Unit unit){ - return hasUpgrade(unit.type); + return hasUpgrade(unit.type) && !upgrade(unit.type).isBanned(); } @Override diff --git a/gradle.properties b/gradle.properties index ddb9285998..208c2f90ba 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,4 +24,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 -archash=997803e989 +archash=3dc6a7fac5