diff --git a/core/assets-raw/sprites/units/locus-weapon-cell.png b/core/assets-raw/sprites/units/weapons/locus-weapon-cell.png similarity index 100% rename from core/assets-raw/sprites/units/locus-weapon-cell.png rename to core/assets-raw/sprites/units/weapons/locus-weapon-cell.png diff --git a/core/assets-raw/sprites/units/locus-weapon.png b/core/assets-raw/sprites/units/weapons/locus-weapon.png similarity index 100% rename from core/assets-raw/sprites/units/locus-weapon.png rename to core/assets-raw/sprites/units/weapons/locus-weapon.png diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index a9aa5eee2c..7db7815f1e 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -331,13 +331,6 @@ public class Fx{ Lines.poly(e.x, e.y, 4, 5f + e.fin() * 60f); }), - vtolHover = new Effect(40f, e -> { - float len = e.finpow() * 10f; - float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f); - color(Pal.lightFlame, Pal.lightOrange, e.fin()); - Fill.circle(e.x + trnsx(ang, len), e.y + trnsy(ang, len), 2f * e.fout()); - }), - breakProp = new Effect(23, e -> { float scl = Math.max(e.rotation, 1); color(Tmp.c1.set(e.color).mul(1.1f)); diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 2092e3dae1..62401867fd 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1789,9 +1789,9 @@ public class UnitTypes{ bullet = new RailBulletType(){{ shootEffect = Fx.railShoot; length = 500; - updateEffectSeg = 60f; + pointEffectSpace = 60f; pierceEffect = Fx.railHit; - updateEffect = Fx.railTrail; + pointEffect = Fx.railTrail; hitEffect = Fx.massiveExplosion; smokeEffect = Fx.shootBig2; damage = 1250; @@ -2484,8 +2484,8 @@ public class UnitTypes{ weapons.add(new Weapon("locus-weapon"){{ layerOffset = 0.0001f; - reload = 30f; - shootY = 9.3f; + reload = 12f; + shootY = 10f; recoil = 1f; rotate = true; rotateSpeed = 1.4f; @@ -2499,19 +2499,29 @@ public class UnitTypes{ spread = 3.5f; }}; - bullet = new BasicBulletType(5f, 50){{ - sprite = "missile-large"; + bullet = new RailBulletType(){{ + length = 140f; + damage = 40f; + hitColor = Color.valueOf("feb380"); + hitEffect = endEffect = Fx.hitBulletColor; + shootEffect = Fx.shootBig; smokeEffect = Fx.shootBigSmoke; - shootEffect = Fx.shootBigColor; - width = 5f; - height = 7f; - lifetime = 40f; - hitSize = 4f; - hitColor = backColor = trailColor = Color.valueOf("feb380"); - frontColor = Color.white; - trailWidth = 1.7f; - trailLength = 5; - despawnEffect = hitEffect = Fx.hitBulletColor; + pierceDamageFactor = 0.8f; + + lineEffect = new Effect(14f, e -> { + if(!(e.data instanceof Vec2 v)) return; + + stroke(e.fout() * 1.5f); + color(e.color); + Lines.line(e.x, e.y, v.x, v.y); + }); + + pointEffectSpace = 8f; + if(false) + pointEffect = new Effect(20, e -> { + color(e.color); + Fill.poly(e.x, e.y, 3, 4f * e.fout(), e.rotation); + }).layer(Layer.bullet - 0.001f); }}; }}); }}; @@ -2926,12 +2936,14 @@ public class UnitTypes{ layerOffset = -0.001f; heatColor = Pal.techBlue; heatProgress = PartProgress.heat.add(0.2f).min(PartProgress.warmup); - progress = PartProgress.warmup.blend(PartProgress.reload, 0.2f); - x = 11 / 4f; - y = 10f / 4f; - moveY = 1f - fi * 3f; - moveX = fi * 0.5f; - moveRot = -30f - fi * 15f; + progress = PartProgress.warmup.blend(PartProgress.reload, 0.1f); + x = 13.5f / 4f; + y = 10f / 4f - fi * 2f; + moveY = 1f - fi * 1f; + moveX = fi * 0.3f; + moveRot = -45f - fi * 17f; + + moves.add(new PartMove(PartProgress.reload.inv().mul(1.8f).inv().curve(fi / 5f, 0.2f), 0f, 0f, 40f)); }}); } diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 5a8a5ca0d7..d6c1c609f1 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -214,7 +214,7 @@ public class Damage{ //try to heal the tile if(collide && hitter.type.testCollision(hitter, tile)){ - hitter.type.hitTile(hitter, tile, health, false); + hitter.type.hitTile(hitter, tile, cx * tilesize, cy * tilesize, health, false); } } }; diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index fd9ac7d9db..efce92afb4 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -255,12 +255,12 @@ public class BulletType extends Content implements Cloneable{ /** If direct is false, this is an indirect hit and the tile was already damaged. * TODO this is a mess. */ - public void hitTile(Bullet b, Building build, float initialHealth, boolean direct){ + public void hitTile(Bullet b, Building build, float x, float y, float initialHealth, boolean direct){ if(makeFire && build.team != b.team){ Fires.create(build.tile); } - if(heals()&& build.team == b.team && !(build.block instanceof ConstructBlock)){ + if(heals() && build.team == b.team && !(build.block instanceof ConstructBlock)){ healEffect.at(build.x, build.y, build.block.size, healColor); build.heal(healPercent / 100f * build.maxHealth + healAmount); }else if(build.team != b.team && direct){ diff --git a/core/src/mindustry/entities/bullet/RailBulletType.java b/core/src/mindustry/entities/bullet/RailBulletType.java index 13d024e531..4d0fd7ad31 100644 --- a/core/src/mindustry/entities/bullet/RailBulletType.java +++ b/core/src/mindustry/entities/bullet/RailBulletType.java @@ -9,14 +9,16 @@ import mindustry.gen.*; public class RailBulletType extends BulletType{ //for calculating the furthest point static float furthest = 0; + static boolean any = false; - public Effect pierceEffect = Fx.hitBulletSmall, updateEffect = Fx.none; + public Effect pierceEffect = Fx.hitBulletSmall, pointEffect = Fx.none, lineEffect = Fx.none; + public Effect endEffect; /** Multiplier of damage decreased per health pierced. */ public float pierceDamageFactor = 1f; public float length = 100f; - public float updateEffectSeg = 20f; + public float pointEffectSpace = 20f; public RailBulletType(){ speed = 0f; @@ -34,18 +36,18 @@ public class RailBulletType extends BulletType{ return length; } - void handle(Bullet b, Posc pos, float initialHealth){ + void handle(Bullet b, float initialHealth, float x, float y){ float sub = Math.max(initialHealth*pierceDamageFactor, 0); if(b.damage <= 0){ - b.fdata = Math.min(b.fdata, b.dst(pos)); + b.fdata = Math.min(b.fdata, b.dst(x, y)); return; } if(b.damage > 0){ - pierceEffect.at(pos.getX(), pos.getY(), b.rotation()); + pierceEffect.at(x, y, b.rotation()); - hitEffect.at(pos.getX(), pos.getY()); + hitEffect.at(x, y); } //subtract health from each consecutive pierce @@ -53,8 +55,10 @@ public class RailBulletType extends BulletType{ //bullet was stopped, decrease furthest distance if(b.damage <= 0f){ - furthest = Math.min(furthest, b.dst(pos)); + furthest = Math.min(furthest, b.dst(x, y)); } + + any = true; } @Override @@ -63,12 +67,23 @@ public class RailBulletType extends BulletType{ b.fdata = length; furthest = length; + any = false; Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), length, false, false); float resultLen = furthest; Vec2 nor = Tmp.v1.trns(b.rotation(), 1f).nor(); - for(float i = 0; i <= resultLen; i += updateEffectSeg){ - updateEffect.at(b.x + nor.x * i, b.y + nor.y * i, b.rotation()); + if(pointEffect != Fx.none){ + for(float i = 0; i <= resultLen; i += pointEffectSpace){ + pointEffect.at(b.x + nor.x * i, b.y + nor.y * i, b.rotation(), trailColor); + } + } + + if(!any){ + endEffect.at(b.x + nor.x * resultLen, b.y + nor.y * resultLen, b.rotation(), hitColor); + } + + if(lineEffect != Fx.none){ + lineEffect.at(b.x, b.y, b.rotation(), hitColor, new Vec2(b.x, b.y).mulAdd(nor, resultLen)); } } @@ -80,11 +95,11 @@ public class RailBulletType extends BulletType{ @Override public void hitEntity(Bullet b, Hitboxc entity, float health){ super.hitEntity(b, entity, health); - handle(b, entity, health); + handle(b, health, entity.getX(), entity.getY()); } @Override - public void hitTile(Bullet b, Building build, float initialHealth, boolean direct){ - handle(b, build, initialHealth); + public void hitTile(Bullet b, Building build, float x, float y, float initialHealth, boolean direct){ + handle(b, initialHealth, x, y); } } diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index 4193a823b6..2bdc7301af 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -132,9 +132,9 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw //copy-paste of World#raycastEach, inlined for lambda capture performance. @Override - public void tileRaycast(int x0f, int y0f, int x1, int y1){ - int x = x0f, dx = Math.abs(x1 - x), sx = x < x1 ? 1 : -1; - int y = y0f, dy = Math.abs(y1 - y), sy = y < y1 ? 1 : -1; + public void tileRaycast(int x1, int y1, int x2, int y2){ + int x = x1, dx = Math.abs(x2 - x), sx = x < x2 ? 1 : -1; + int y = y1, dy = Math.abs(y2 - y), sy = y < y2 ? 1 : -1; int e2, err = dx - dy; int ww = world.width(), wh = world.height(); @@ -173,13 +173,13 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw } } - type.hitTile(self(), build, health, true); + type.hitTile(self(), build, x * tilesize, y * tilesize, health, true); //stop raycasting when building is hit if(type.pierceBuilding) return; } - if(x == x1 && y == y1) break; + if(x == x2 && y == y2) break; e2 = 2 * err; if(e2 > -dy){ diff --git a/core/src/mindustry/entities/part/DrawPart.java b/core/src/mindustry/entities/part/DrawPart.java index d6e6e13041..a8ed826082 100644 --- a/core/src/mindustry/entities/part/DrawPart.java +++ b/core/src/mindustry/entities/part/DrawPart.java @@ -92,6 +92,10 @@ public abstract class DrawPart{ return p -> (get(p) - amount) / (1f - amount); } + default PartProgress curve(float offset, float duration){ + return p -> (get(p) - offset) / duration; + } + default PartProgress shorten(float amount){ return p -> get(p) / (1f - amount); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index c70559c088..5b777ef3d1 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -503,8 +503,6 @@ public class Turret extends ReloadTurret{ handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, 1f + Mathf.range(velocityInaccuracy), lifeScl), xOffset, yOffset, angleOffset); - //TODO "shoot" and "smoke" should just be MultiEffects there's no reason to have them separate - (shootEffect == Fx.none ? type.shootEffect : shootEffect).at(bulletX, bulletY, rotation, type.hitColor); (smokeEffect == Fx.none ? type.smokeEffect : smokeEffect).at(bulletX, bulletY, rotation, type.hitColor); shootSound.at(bulletX, bulletY, Mathf.random(soundPitchMin, soundPitchMax)); @@ -512,7 +510,7 @@ public class Turret extends ReloadTurret{ ammoUseEffect.at( x - Angles.trnsx(rotation, ammoEjectBack), y - Angles.trnsy(rotation, ammoEjectBack), - rotation * (shoot.shots == 1 && shoot instanceof ShootAlternate && totalShots % 2 == 1 ? -1f : 1f) + rotation * Mathf.sign(xOffset) ); if(shootShake > 0){