diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-heat.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-heat.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-heat.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-heat.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-l.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-l.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-l.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-l.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-r.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-r.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-blade-r.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-blade-r.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-heat.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-heat.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-heat.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-heat.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-l.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-l.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-l.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-l.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-r.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-r.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-inner-r.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-inner-r.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-mid-heat.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-mid-heat.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-mid-heat.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-mid-heat.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-mid.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-mid.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-mid.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-mid.png diff --git a/core/assets-raw/sprites/blocks/turrets/fracture/fracture-preview.png b/core/assets-raw/sprites/blocks/turrets/lustre/lustre-preview.png similarity index 100% rename from core/assets-raw/sprites/blocks/turrets/fracture/fracture-preview.png rename to core/assets-raw/sprites/blocks/turrets/lustre/lustre-preview.png diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index bff8316195..f552417edd 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -380,9 +380,10 @@ editor.mapinfo = Map Info editor.author = Author: editor.description = Description: editor.nodescription = A map must have a description of at least 4 characters before being published. -editor.waves = Waves: -editor.rules = Rules: -editor.generation = Generation: +editor.waves = Waves +editor.rules = Rules +editor.generation = Generation +editor.objectives = Objectives editor.ingame = Edit In-Game editor.playtest = Playtest editor.publish.workshop = Publish On Workshop @@ -395,6 +396,8 @@ editor.filters.type = Map Type: editor.filters.search = Search In: editor.filters.author = Author editor.filters.description = Description +editor.shiftx = Shift X +editor.shifty = Shift Y workshop = Workshop waves.title = Waves waves.remove = Remove @@ -2067,7 +2070,3 @@ unit.merui.name = Merui unit.anthicus.name = Anthicus unit.elude.name = Elude unit.obviate.name = Obviate -sector.two.name = Two -sector.three.name = Three -sector.four.name = Four -sector.five.name = Five diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 745fad30aa..6d99f85b59 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -568,3 +568,4 @@ 63116=shielded-wall|block-shielded-wall-ui 63115=fracture|block-fracture-ui 63114=renale|unit-renale-ui +63113=lustre|block-lustre-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index dd6916cabb..32295ee5d6 100644 Binary files a/core/assets/logicids.dat and b/core/assets/logicids.dat differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index a77eb08848..a4703ef93f 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -8,6 +8,7 @@ import mindustry.entities.*; import mindustry.entities.bullet.*; import mindustry.entities.effect.*; import mindustry.entities.part.*; +import mindustry.entities.part.DrawPart.*; import mindustry.entities.pattern.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -23,8 +24,6 @@ import mindustry.world.blocks.heat.*; import mindustry.world.blocks.legacy.*; import mindustry.world.blocks.liquid.*; import mindustry.world.blocks.logic.*; -import mindustry.world.blocks.payloads.PayloadConveyor; -import mindustry.world.blocks.payloads.PayloadRouter; import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.power.*; import mindustry.world.blocks.production.*; @@ -135,7 +134,7 @@ public class Blocks{ duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax, tsunami, //turrets - erekir - breach, diffuse, sublimate, titan, disperse, afflict, fracture, + breach, diffuse, sublimate, titan, disperse, afflict, lustre, //units groundFactory, airFactory, navalFactory, @@ -4081,7 +4080,6 @@ public class Blocks{ limitRange(-5f); }}; - //TODO WIP afflict = new PowerTurret("afflict"){{ requirements(Category.turret, with(Items.surgeAlloy, 100, Items.silicon, 200, Items.graphite, 250, Items.oxide, 40)); @@ -4197,61 +4195,33 @@ public class Blocks{ limitRange(9f); }}; - if(false) - fracture = new ItemTurret("fracture"){{ + lustre = new ContinuousTurret("lustre"){{ requirements(Category.turret, with(Items.beryllium, 150, Items.silicon, 200, Items.graphite, 200, Items.carbide, 50)); - ammo( - Items.tungsten, new BasicBulletType(8f, 41){{ - knockback = 4f; - width = 25f; - hitSize = 7f; - height = 20f; - shootEffect = Fx.shootBigColor; - smokeEffect = Fx.shootSmokeSquareSparse; - ammoMultiplier = 1; - hitColor = backColor = trailColor = Color.valueOf("ea8878"); - frontColor = Color.valueOf("feb380"); - trailWidth = 6f; - trailLength = 3; - hitEffect = despawnEffect = Fx.hitSquaresColor; - buildingDamageMultiplier = 0.2f; + range = 100f; - if(false) - spawnBullets.add(new BulletType(){{ - instantDisappear = true; - lightning = 6; - lightningLength = 10; - lightningLengthRand = 10; - lightningColor = Color.valueOf("ff6214"); - lightningCone = 20f; - damage = 30; - despawnEffect = hitEffect = Fx.none; - }}); - }} - ); - - coolantMultiplier = 6f; - shake = 1f; - - //shoot = new ShootAlternate(){{ - // shots = 3; - // barrels = 3; - //}}; + shootType = new PointLaserBulletType(){{ + damage = 150f; + buildingDamageMultiplier = 0.3f; + hitColor = Color.valueOf("fd9e81"); + }}; drawer = new DrawTurret("reinforced-"){{ + var heatp = PartProgress.warmup.blend(p -> Mathf.absin(2f, 1f) * p.warmup, 0.2f); + parts.add(new RegionPart("-blade"){{ progress = PartProgress.warmup; - heatProgress = PartProgress.warmup.blend(PartProgress.recoil, 0.2f); + heatProgress = PartProgress.warmup; heatColor = Color.valueOf("ff6214"); mirror = true; under = true; moveX = 2f; moveRot = -7f; - moves.add(new PartMove(PartProgress.recoil, 0f, -2f, 3f)); + moves.add(new PartMove(PartProgress.warmup, 0f, -2f, 3f)); }}, new RegionPart("-inner"){{ - progress = PartProgress.recoil; + heatProgress = heatp; + progress = PartProgress.warmup; heatColor = Color.valueOf("ff6214"); mirror = true; under = false; @@ -4259,26 +4229,32 @@ public class Blocks{ moveY = -8f; }}, new RegionPart("-mid"){{ - heatProgress = PartProgress.warmup.blend(PartProgress.recoil, 0.2f); + heatProgress = heatp; + progress = PartProgress.warmup; heatColor = Color.valueOf("ff6214"); moveY = -8f; - progress = PartProgress.recoil; mirror = false; under = true; }}); }}; - shootY = 11f; + shootWarmupSpeed = 0.08f; + shootCone = 360f; + + aimChangeSpeed = 0.9f; + rotateSpeed = 0.9f; + + shootY = 0.5f; outlineColor = Pal.darkOutline; size = 4; envEnabled |= Env.space; - reload = 30f; - recoil = 2f; - range = 125; + range = 250f; scaledHealth = 210; - rotateSpeed = 3f; - coolant = consume(new ConsumeLiquid(Liquids.water, 15f / 60f)); + //TODO is this a good idea to begin with? + unitSort = UnitSorts.strongest; + + consumeLiquid(Liquids.nitrogen, 5f / 60f); }}; //TODO 3 more turrets. diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index 2604a70827..ef48d53fcd 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -1003,6 +1003,11 @@ public class Fx{ Fill.circle(e.x, e.y, e.rotation * e.fout()); }).layer(Layer.bullet - 0.001f), + colorTrail = new Effect(50, e -> { + color(e.color); + Fill.circle(e.x, e.y, e.rotation * e.fout()); + }), + absorb = new Effect(12, e -> { color(Pal.accent); stroke(2f * e.fout()); diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 5cf7ea0475..0a7b2a83f6 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -298,6 +298,39 @@ public class Damage{ units.each(cons); } + /** + * Damages entities on a point. + * Only enemies of the specified team are damaged. + */ + public static void collidePoint(Bullet hitter, Team team, Effect effect, float x, float y){ + + if(hitter.type.collidesGround){ + Building build = world.build(World.toTile(x), World.toTile(y)); + + if(build != null && hitter.damage > 0){ + float health = build.health; + + if(build.team != team && build.collide(hitter)){ + build.collision(hitter); + hitter.type.hit(hitter, x, y); + } + + //try to heal the tile + if(hitter.type.testCollision(hitter, build)){ + hitter.type.hitTile(hitter, build, x, y, health, false); + } + } + } + + Units.nearbyEnemies(team, rect.setCentered(x, y, 1f), u -> { + if(u.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround) && u.hittable()){ + effect.at(x, y); + u.collision(hitter, x, y); + hitter.collision(u, x, y); + } + }); + } + /** * Casts forward in a line. * @return the first encountered object. diff --git a/core/src/mindustry/entities/bullet/ContinuousBulletType.java b/core/src/mindustry/entities/bullet/ContinuousBulletType.java index 9e01bf93e4..df7b63c68d 100644 --- a/core/src/mindustry/entities/bullet/ContinuousBulletType.java +++ b/core/src/mindustry/entities/bullet/ContinuousBulletType.java @@ -4,7 +4,7 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.gen.*; -/** Basic continuous bullet type that does not draw itself. Essentially abstract. */ +/** Basic continuous (line) bullet type that does not draw itself. Essentially abstract. */ public class ContinuousBulletType extends BulletType{ public float length = 220f; public float shake = 0f; diff --git a/core/src/mindustry/entities/bullet/PointLaserBulletType.java b/core/src/mindustry/entities/bullet/PointLaserBulletType.java new file mode 100644 index 0000000000..a007f113df --- /dev/null +++ b/core/src/mindustry/entities/bullet/PointLaserBulletType.java @@ -0,0 +1,85 @@ +package mindustry.entities.bullet; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; + +/** A continuous bullet type that only damages in a point. */ +public class PointLaserBulletType extends BulletType{ + public String sprite = "drill-laser"; + public TextureRegion laser, laserEnd; + + public Color color = Color.white; + + public Effect beamEffect = Fx.colorTrail; + public float beamEffectInterval = 3f, beamEffectSize = 3.5f; + + public float oscScl = 2f, oscMag = 0.3f; + public float damageInterval = 5f; + + public float shake = 0f; + + public PointLaserBulletType(){ + removeAfterPierce = false; + speed = 0f; + despawnEffect = Fx.none; + shootEffect = Fx.none; + lifetime = 20f; + impact = true; + keepVelocity = false; + collides = false; + pierce = true; + hittable = false; + absorbable = false; + optimalLifeFract = 0.5f; + + //just make it massive, users of this bullet can adjust as necessary + drawSize = 1000f; + } + + @Override + public float estimateDPS(){ + return damage * 100f / damageInterval * 3f; + } + + @Override + public void load(){ + super.load(); + + laser = Core.atlas.find(sprite); + laserEnd = Core.atlas.find(sprite + "-end"); + } + + @Override + public void draw(Bullet b){ + super.draw(b); + + Draw.color(color); + Drawf.laser(laser, laserEnd, b.x, b.y, b.aimX, b.aimY, b.fslope() * (1f - oscMag + Mathf.absin(Time.time, oscScl, oscMag))); + + Draw.reset(); + } + + @Override + public void update(Bullet b){ + super.update(b); + + if(b.timer.get(0, damageInterval)){ + Damage.collidePoint(b, b.team, hitEffect, b.aimX, b.aimY); + } + + if(b.timer.get(1, beamEffectInterval)){ + beamEffect.at(b.aimX, b.aimY, beamEffectSize * b.fslope(), hitColor); + } + + if(shake > 0){ + Effect.shake(shake, shake, b); + } + } +} diff --git a/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java index b6a51f76dd..c68c45121e 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java @@ -3,6 +3,7 @@ package mindustry.world.blocks.defense.turrets; import arc.math.*; import arc.struct.*; import arc.util.*; +import arc.util.io.*; import mindustry.content.*; import mindustry.entities.bullet.*; import mindustry.gen.*; @@ -12,6 +13,8 @@ import mindustry.world.meta.*; /** A turret that fires a continuous beam bullet with no reload or coolant necessary. The bullet only disappears when the turret stops shooting. */ public class ContinuousTurret extends Turret{ public BulletType shootType = Bullets.placeholder; + /** Speed at which the turret can change its bullet "aim" distance. This is only used for point laser bullets. */ + public float aimChangeSpeed = Float.POSITIVE_INFINITY; public ContinuousTurret(String name){ super(name); @@ -33,6 +36,7 @@ public class ContinuousTurret extends Turret{ //TODO LaserTurret shared code public class ContinuousTurretBuild extends TurretBuild{ public Seq bullets = new Seq<>(); + public float lastLength = size * 4f; @Override protected void updateCooling(){ @@ -85,6 +89,18 @@ public class ContinuousTurret extends Turret{ entry.bullet.rotation(angle); entry.bullet.set(bulletX, bulletY); + //target length of laser + float shootLength = Math.min(dst(targetPos), range); + //current length of laser + float curLength = dst(entry.bullet.aimX, entry.bullet.aimY); + //resulting length of the bullet (smoothed) + float resultLength = Mathf.approachDelta(curLength, shootLength, aimChangeSpeed); + //actual aim end point based on length + Tmp.v1.trns(rotation, lastLength = resultLength).add(x, y); + + entry.bullet.aimX = Tmp.v1.x; + entry.bullet.aimY = Tmp.v1.y; + if(isShooting() && hasAmmo()){ entry.bullet.time = entry.bullet.lifetime * entry.bullet.type.optimalLifeFract * shootWarmup; entry.bullet.keepAlive = true; @@ -122,6 +138,11 @@ public class ContinuousTurret extends Turret{ protected void handleBullet(@Nullable Bullet bullet, float offsetX, float offsetY, float angleOffset){ if(bullet != null){ bullets.add(new BulletEntry(bullet, offsetX, offsetY, angleOffset, 0f)); + + //make sure the length updates to the last set value + Tmp.v1.trns(rotation, shootY + lastLength).add(x, y); + bullet.aimX = Tmp.v1.x; + bullet.aimY = Tmp.v1.y; } } @@ -129,5 +150,26 @@ public class ContinuousTurret extends Turret{ public boolean shouldActiveSound(){ return bullets.any(); } + + @Override + public byte version(){ + return 3; + } + + @Override + public void write(Writes write){ + super.write(write); + + write.f(lastLength); + } + + @Override + public void read(Reads read, byte revision){ + super.read(read, revision); + + if(revision >= 3){ + lastLength = read.f(); + } + } } }