diff --git a/core/assets-raw/sprites/blocks/turrets/bases/reinforced-block-3.png b/core/assets-raw/sprites/blocks/turrets/bases/reinforced-block-3.png new file mode 100644 index 0000000000..29f2caeabd Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/bases/reinforced-block-3.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/sublimate-back1.png b/core/assets-raw/sprites/blocks/turrets/sublimate-back1.png new file mode 100644 index 0000000000..ddb85632b8 Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/sublimate-back1.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/sublimate-back2.png b/core/assets-raw/sprites/blocks/turrets/sublimate-back2.png new file mode 100644 index 0000000000..cc3a2757e2 Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/sublimate-back2.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/sublimate-preview.png b/core/assets-raw/sprites/blocks/turrets/sublimate-preview.png new file mode 100644 index 0000000000..f0974e30b4 Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/sublimate-preview.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/sublimate.png b/core/assets-raw/sprites/blocks/turrets/sublimate.png index 295ff20515..3688fd76a7 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/sublimate.png and b/core/assets-raw/sprites/blocks/turrets/sublimate.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index b69beefcda..56bdb1495a 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -457,3 +457,4 @@ 63249=slag-heater|block-slag-heater-ui 63248=slag-incinerator|block-slag-incinerator-ui 63247=phase-synthesizer|block-phase-synthesizer-ui +63246=sublimate|block-sublimate-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index d218107478..1cc8dad67a 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 7b73588bd1..8f7232450d 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -99,7 +99,7 @@ public class Blocks implements ContentList{ //storage coreShard, coreFoundation, coreNucleus, vault, container, unloader, //storage - erekir - coreBastion, coreCitadel, coreAcropolis, + coreBastion, coreCitadel, coreAcropolis, reinforcedContainer, reinforcedVault, //turrets duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax, tsunami, @@ -1143,14 +1143,13 @@ public class Blocks implements ContentList{ size = 3; + liquidCapacity = 40f; outputLiquid = new LiquidStack(Liquids.cyanogen, 3f); craftTime = 60f * 1f; consumes.liquid(Liquids.hydrogen, 3f / 60f); consumes.item(Items.graphite); - consumes.power(2f); - liquidCapacity = 40f; }}; //TODO bad name @@ -1181,7 +1180,7 @@ public class Blocks implements ContentList{ }}, new DrawBlock(), new DrawHeatInput(), new DrawHeatRegion("-vents"){{ heatColor = new Color(1f, 0.4f, 0.3f, 1f); }}); - iconOverride = new String[]{"-bottom", ""}; + iconOverride = new String[]{"-bottom", "-weave", ""}; consumes.items(with(Items.thorium, 2, Items.sand, 6)); consumes.liquid(Liquids.ozone, 2f / 60f); @@ -2126,13 +2125,6 @@ public class Blocks implements ContentList{ researchCostMultiplier = 0.11f; }}; - vault = new StorageBlock("vault"){{ - requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); - size = 3; - itemCapacity = 1000; - health = size * size * 55; - }}; - container = new StorageBlock("container"){{ requirements(Category.effect, with(Items.titanium, 100)); size = 2; @@ -2140,12 +2132,27 @@ public class Blocks implements ContentList{ health = size * size * 55; }}; + vault = new StorageBlock("vault"){{ + requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); + size = 3; + itemCapacity = 1000; + health = size * size * 55; + }}; + + //TODO move tabs? unloader = new Unloader("unloader"){{ requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30)); speed = 60f / 11f; group = BlockGroup.transportation; }}; + reinforcedContainer = new StorageBlock("reinforced-container"){{ + requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); + size = 3; + itemCapacity = 1000; + health = size * size * 120; + }}; + //endregion //region turrets @@ -2681,10 +2688,31 @@ public class Blocks implements ContentList{ }}; //TODO bad name - if(false) sublimate = new ContinuousTurret("sublimate"){{ //TODO requirements requirements(Category.turret, with(Items.tungsten, 35, Items.silicon, 35), true); + + draw = new DrawTurret("reinforced-"){{ + parts.addAll(new RegionPart("-back"){{ + outline = true; + rotMove = 30f; + offsetX = 29 / 4f; + offsetY = -10f / 4f; + originX = -8f / 4f; + originY = 8f / 4f; + }}); + }}; + outlineColor = Pal.darkOutline; + + consumes.liquids(LiquidStack.with(Liquids.cyanogen, 3f / 60f, Liquids.ozone, 2f / 60f)); + + range = 170f; + + shootType = new ContinuousFlameBulletType(){{ + length = range; + }}; + shootLength = 9f; + size = 3; }}; //endregion diff --git a/core/src/mindustry/entities/bullet/ContinuousBulletType.java b/core/src/mindustry/entities/bullet/ContinuousBulletType.java new file mode 100644 index 0000000000..7d203f05b0 --- /dev/null +++ b/core/src/mindustry/entities/bullet/ContinuousBulletType.java @@ -0,0 +1,63 @@ +package mindustry.entities.bullet; + +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; + +/** Basic continuous bullet type that does not draw itself. Essentially abstract. */ +public class ContinuousBulletType extends BulletType{ + public float length = 220f; + public float shake = 0f; + public float damageInterval = 5f; + public boolean largeHit = false; + + { + speed = 0f; + despawnEffect = Fx.none; + lifetime = 16f; + impact = true; + keepVelocity = false; + collides = false; + pierce = true; + hittable = false; + absorbable = false; + } + + @Override + public float continuousDamage(){ + return damage / damageInterval * 60f; + } + + @Override + public float estimateDPS(){ + //assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method + //assume it pierces 3 blocks/units + return damage * 100f / damageInterval * 3f; + } + + @Override + public float range(){ + return Math.max(length, maxRange); + } + + @Override + public void init(){ + super.init(); + + drawSize = Math.max(drawSize, length*2f); + } + + @Override + public void update(Bullet b){ + + //damage every 5 ticks + if(b.timer(1, damageInterval)){ + Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit); + } + + if(shake > 0){ + Effect.shake(shake, shake, b); + } + } + +} diff --git a/core/src/mindustry/entities/bullet/ContinuousFlameBulletType.java b/core/src/mindustry/entities/bullet/ContinuousFlameBulletType.java new file mode 100644 index 0000000000..545feb51fd --- /dev/null +++ b/core/src/mindustry/entities/bullet/ContinuousFlameBulletType.java @@ -0,0 +1,74 @@ +package mindustry.entities.bullet; + +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.*; + +//TODO implement +public class ContinuousFlameBulletType extends ContinuousBulletType{ + public float fadeTime = 16f; + public float lightStroke = 40f; + public float width = 3.7f, oscScl = 1.2f, oscMag = 0.02f; + public int divisions = 25; + + /** Lengths, widths, ellipse panning, and offsets, all as fractions of the base width and length. Stored as an 'interleaved' array of values: LWPO1 LWPO2 LWPO3... */ + public float[] lengthWidthPanOffsets = { + 1.12f, 1.3f, 0.32f, 0f, + 1f, 1f, 0.3f, 0f, + 0.8f, 0.9f, 0.2f, 0.01f, + 0.5f, 0.8f, 0.15f, 0.02f, + 0.25f, 0.7f, 0.1f, 0.03f + }; + + public Color[] colors = {Color.valueOf("eb7abe").a(0.55f), Color.valueOf("e189f5").a(0.7f), Color.valueOf("907ef7").a(0.8f), Color.valueOf("91a4ff"), Color.white}; + + public ContinuousFlameBulletType(float damage){ + this.damage = damage; + } + + public ContinuousFlameBulletType(){ + } + + { + length = 120f; + hitEffect = Fx.hitBeam; + hitSize = 4; + drawSize = 420f; + lifetime = 16f; + hitColor = colors[3]; + lightColor = colors[3]; + } + + @Override + public void draw(Bullet b){ + float realLength = Damage.findLaserLength(b, length); + float fout = Mathf.clamp(b.time > b.lifetime - fadeTime ? 1f - (b.time - (lifetime - fadeTime)) / fadeTime : 1f); + float baseLen = realLength * fout; + + float sin = Mathf.sin(Time.time, oscScl, oscMag); + + for(int i = 0; i < colors.length; i++){ + Draw.color(colors[i].write(Tmp.c1).mul(0.9f).mul(1f + Mathf.absin(Time.time, 1f, 0.1f))); + Drawf.flame(b.x, b.y, divisions, b.rotation(), + baseLen * lengthWidthPanOffsets[i * 4] * (1f - sin), + width * lengthWidthPanOffsets[i * 4 + 1] * fout * (1f + sin), + lengthWidthPanOffsets[i * 4 + 2], + baseLen * lengthWidthPanOffsets[i * 4 + 3] + ); + } + + Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, lightStroke, lightColor, 0.7f); + Draw.reset(); + } + + @Override + public void drawLight(Bullet b){ + //no light drawn here + } + +} diff --git a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java index 27d5043ba5..a2a654058e 100644 --- a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java +++ b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java @@ -9,9 +9,7 @@ import mindustry.entities.*; import mindustry.gen.*; import mindustry.graphics.*; -public class ContinuousLaserBulletType extends BulletType{ - public float length = 220f; - public float shake = 1f; +public class ContinuousLaserBulletType extends ContinuousBulletType{ public float fadeTime = 16f; public float lightStroke = 40f; public float spaceMag = 35f; @@ -20,14 +18,18 @@ public class ContinuousLaserBulletType extends BulletType{ public float[] strokes = {2f, 1.5f, 1f, 0.3f}; public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f}; public float width = 9f, oscScl = 0.8f, oscMag = 1.5f; - public boolean largeHit = true; public ContinuousLaserBulletType(float damage){ this.damage = damage; - this.speed = 0f; + } + public ContinuousLaserBulletType(){ + } + + { + shake = 1f; + largeHit = true; hitEffect = Fx.hitBeam; - despawnEffect = Fx.none; hitSize = 4; drawSize = 420f; lifetime = 16f; @@ -36,53 +38,6 @@ public class ContinuousLaserBulletType extends BulletType{ incendSpread = 5; incendChance = 0.4f; lightColor = Color.orange; - impact = true; - keepVelocity = false; - collides = false; - pierce = true; - hittable = false; - absorbable = false; - } - - protected ContinuousLaserBulletType(){ - this(0); - } - - @Override - public float continuousDamage(){ - return damage / 5f * 60f; - } - - @Override - public float estimateDPS(){ - //assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method - //assume it pierces 3 blocks/units - return damage * 100f / 5f * 3f; - } - - @Override - public float range(){ - return Math.max(length, maxRange); - } - - @Override - public void init(){ - super.init(); - - drawSize = Math.max(drawSize, length*2f); - } - - @Override - public void update(Bullet b){ - - //damage every 5 ticks - if(b.timer(1, 5f)){ - Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit); - } - - if(shake > 0){ - Effect.shake(shake, shake, b); - } } @Override diff --git a/core/src/mindustry/graphics/Drawf.java b/core/src/mindustry/graphics/Drawf.java index efa7eb10fc..500f8c8b69 100644 --- a/core/src/mindustry/graphics/Drawf.java +++ b/core/src/mindustry/graphics/Drawf.java @@ -5,6 +5,7 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.ctype.*; @@ -15,6 +16,51 @@ import mindustry.world.*; import static mindustry.Vars.*; public class Drawf{ + private static FloatSeq points = new FloatSeq(); + + public static void flame(float x, float y, int divisions, float rotation, float length, float width, float pan){ + flame(x, y, divisions, rotation, length, width, pan, 0f); + } + + public static void flame(float x, float y, int divisions, float rotation, float length, float width, float pan, float offset){ + float len1 = length * pan, len2 = length * (1f - pan); + + points.clear(); + + //left side; half arc beginning at 90 degrees and ending at 270 + for(int i = 0; i < divisions; i++){ + float rot = 90f + 180f * i / (float)divisions; + Tmp.v1.trnsExact(rot, width); + + point( + (Tmp.v1.x + width) / width * len1, //convert to 0..1, then multiply by desired length + Tmp.v1.y, //Y axis remains unchanged + x, y, + rotation + ); + } + + //right side; half arc beginning at -90 (270) and ending at 90 + for(int i = 0; i < divisions; i++){ + float rot = -90f + 180f * i / (float)divisions; + Tmp.v1.trnsExact(rot, width); + + point( + len1 + (Tmp.v1.x) / width * len2, //convert to 0..1, then multiply by desired length and offset relative to previous segment + Tmp.v1.y, //Y axis remains unchanged + x, y, + rotation + ); + } + + Fill.poly(points); + } + + private static void point(float x, float y, float baseX, float baseY, float rotation){ + //TODO test exact and non-exact + Tmp.v1.set(x, y).rotateRadExact(rotation * Mathf.degRad); + points.add(Tmp.v1.x + baseX, Tmp.v1.y + baseY); + } public static void dashLine(Color color, float x, float y, float x2, float y2){ int segments = (int)(Math.max(Math.abs(x - x2), Math.abs(y - y2)) / tilesize * 2); diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 72766cd983..31a56f0623 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -240,7 +240,7 @@ public class Weapon implements Cloneable{ mountY = unit.y + Angles.trnsy(unit.rotation - 90, x, y), bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX, this.shootY), bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX, this.shootY), - shootAngle = rotate ? weaponRotation + 90 : Angles.angle(bulletX, bulletY, mount.aimX, mount.aimY) + (unit.rotation - unit.angleTo(mount.aimX, mount.aimY)); + shootAngle = rotate ? unit.rotation + mount.rotation : Angles.angle(bulletX, bulletY, mount.aimX, mount.aimY) + (unit.rotation - unit.angleTo(mount.aimX, mount.aimY)); //find a new target if(!controllable && autoTarget){ @@ -333,8 +333,16 @@ public class Weapon implements Cloneable{ return Units.invalidateTarget(target, unit.team, x, y, range + Math.abs(shootY)); } + protected Vec2 getShootPos(Unit unit, WeaponMount mount, Vec2 out){ + float weaponRot = unit.rotation - 90 + (rotate ? mount.rotation : 0); + return out.set(unit.x, unit.y) + .add(Angles.trnsx(unit.rotation - 90, x, y), Angles.trnsy(unit.rotation - 90, x, y)) + .add(Angles.trnsx(weaponRot, this.shootX, this.shootY), Angles.trnsx(weaponRot, this.shootX, this.shootY)); + } + protected void shoot(Unit unit, WeaponMount mount, float shootX, float shootY, float aimX, float aimY, float mountX, float mountY, float rotation, int side){ - float baseX = unit.x, baseY = unit.y; + Vec2 offset = getShootPos(unit, mount, Tmp.v1); + float baseX = offset.x, baseY = offset.y, baseRot = unit.rotation + mount.rotation; boolean delay = firstShotDelay + shotDelay > 0f; (delay ? chargeSound : continuous ? Sounds.none : shootSound).at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); @@ -347,7 +355,11 @@ public class Weapon implements Cloneable{ Angles.shotgun(shots, spacing, rotation, f -> { Time.run(sequenceNum * shotDelay + firstShotDelay, () -> { if(!unit.isAdded()) return; - mount.bullet = bullet(unit, shootX + unit.x - baseX, shootY + unit.y - baseY, f + Mathf.range(inaccuracy), lifeScl); + + getShootPos(unit, mount, offset).sub(baseX, baseY); + + float rotOffset = unit.rotation + mount.rotation - baseRot; + mount.bullet = bullet(unit, shootX + offset.x, shootY + offset.y, f + Mathf.range(inaccuracy) + rotOffset, lifeScl); if(!continuous){ shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); } @@ -371,7 +383,10 @@ public class Weapon implements Cloneable{ if(!continuous){ shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); } - ammo.chargeShootEffect.at(shootX + unit.x - baseX, shootY + unit.y - baseY, rotation, parentize ? unit : null); + + getShootPos(unit, mount, offset).sub(baseX, baseY); + + ammo.chargeShootEffect.at(shootX + offset.x, shootY + offset.y, rotation, parentize ? unit : null); }); }else{ unit.vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil)); diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 89d5731bdd..7547a17abf 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -710,6 +710,10 @@ public class Block extends UnlockableContent{ return teamRegion.found() && minfo.mod == null ? new TextureRegion[]{r, teamRegions[Team.sharded.id]} : new TextureRegion[]{r}; } + public void getRegionsToOutline(Seq out){ + + } + public TextureRegion[] getGeneratedIcons(){ return generatedIcons == null ? (generatedIcons = icons()) : generatedIcons; } diff --git a/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java index 2f98a84448..6f0611a133 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ContinuousTurret.java @@ -42,7 +42,7 @@ public class ContinuousTurret extends Turret{ @Override public boolean hasAmmo(){ - return consValid(); + return cons.canConsume(); } @Override diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 10bf0ef956..30de73a628 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -48,6 +48,7 @@ public class Turret extends ReloadTurret{ public float ammoEjectBack = 1f; public float inaccuracy = 0f; public float velocityInaccuracy = 0f; + public float shootWarmupSpeed = 3f / 60f; public int shots = 1; public float spread = 4f; public float recoilAmount = 1f; @@ -149,6 +150,11 @@ public class Turret extends ReloadTurret{ return draw.icons(this); } + @Override + public void getRegionsToOutline(Seq out){ + draw.getRegionsToOutline(out); + } + public static abstract class AmmoEntry{ public int amount; @@ -165,6 +171,7 @@ public class Turret extends ReloadTurret{ public Seq ammo = new Seq<>(); public int totalAmmo; public float recoil, heat, logicControlTime = -1; + public float shootWarmup; public int shotCounter; public boolean logicShooting = false; public @Nullable Posc target; @@ -172,6 +179,11 @@ public class Turret extends ReloadTurret{ public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team); public boolean wasShooting, charging; + @Override + public float warmup(){ + return shootWarmup; + } + @Override public float drawrot(){ return rotation - 90; @@ -273,6 +285,9 @@ public class Turret extends ReloadTurret{ public void updateTile(){ if(!validateTarget()) target = null; + //TODO can be lerp instead, that's smoother + shootWarmup = Mathf.approachDelta(shootWarmup, isActive() ? 1f : 0f, shootWarmupSpeed); + wasShooting = false; recoil = Mathf.lerpDelta(recoil, 0f, restitution); diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 4ebbf3a217..1a127ec3c4 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -138,6 +138,11 @@ public class GenericCrafter extends Block{ return outputItems != null; } + @Override + public void getRegionsToOutline(Seq out){ + drawer.getRegionsToOutline(out); + } + public class GenericCrafterBuild extends Building{ public float progress; public float totalProgress; diff --git a/core/src/mindustry/world/draw/DrawBlock.java b/core/src/mindustry/world/draw/DrawBlock.java index e47ad4c9ae..9b6e16c3e1 100644 --- a/core/src/mindustry/world/draw/DrawBlock.java +++ b/core/src/mindustry/world/draw/DrawBlock.java @@ -2,6 +2,7 @@ package mindustry.world.draw; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.*; import mindustry.entities.units.*; import mindustry.gen.*; @@ -22,6 +23,10 @@ public class DrawBlock{ @Deprecated public void drawLight(GenericCrafterBuild build){} + public void getRegionsToOutline(Seq out){ + + } + /** Draws the block itself. */ public void drawBase(Building build){ Draw.rect(build.block.region, build.x, build.y, build.drawrot()); diff --git a/core/src/mindustry/world/draw/DrawMulti.java b/core/src/mindustry/world/draw/DrawMulti.java index 2aa69d1eb3..2d35189fd8 100644 --- a/core/src/mindustry/world/draw/DrawMulti.java +++ b/core/src/mindustry/world/draw/DrawMulti.java @@ -24,6 +24,13 @@ public class DrawMulti extends DrawBlock{ this.drawers = drawers.toArray(DrawBlock.class); } + @Override + public void getRegionsToOutline(Seq out){ + for(var draw : drawers){ + draw.getRegionsToOutline(out); + } + } + @Override public void drawBase(Building build){ for(var draw : drawers){ diff --git a/core/src/mindustry/world/draw/DrawTurret.java b/core/src/mindustry/world/draw/DrawTurret.java index 078649fe25..6784ab9bf2 100644 --- a/core/src/mindustry/world/draw/DrawTurret.java +++ b/core/src/mindustry/world/draw/DrawTurret.java @@ -4,6 +4,8 @@ import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; +import arc.util.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; @@ -14,8 +16,9 @@ import mindustry.world.blocks.defense.turrets.Turret.*; public class DrawTurret extends DrawBlock{ protected static final Rand rand = new Rand(); + public Seq parts = new Seq<>(); public String basePrefix = ""; - public TextureRegion base, liquid, top, heat; + public TextureRegion base, liquid, top, heat, preview; public DrawTurret(String basePrefix){ this.basePrefix = basePrefix; @@ -24,6 +27,13 @@ public class DrawTurret extends DrawBlock{ public DrawTurret(){ } + @Override + public void getRegionsToOutline(Seq out){ + for(var part : parts){ + part.getOutlines(out); + } + } + @Override public void drawBase(Building build){ Turret turret = (Turret)build.block; @@ -38,6 +48,12 @@ public class DrawTurret extends DrawBlock{ drawTurret(turret, tb); drawHeat(turret, tb); + + if(parts.size > 0){ + for(var part : parts){ + part.draw(tb); + } + } } public void drawTurret(Turret block, TurretBuild build){ @@ -67,11 +83,16 @@ public class DrawTurret extends DrawBlock{ public void load(Block block){ if(!(block instanceof Turret)) throw new ClassCastException("This drawer can only be used on turrets."); + preview = Core.atlas.find(block.name + "-preview", block.region); liquid = Core.atlas.find(block.name + "-liquid"); top = Core.atlas.find(block.name + "-top"); heat = Core.atlas.find(block.name + "-heat"); base = Core.atlas.find(block.name + "-base"); + for(var part : parts){ + part.load(block); + } + //TODO test this for mods, e.g. exotic if(!base.found() && block.minfo.mod != null) base = Core.atlas.find(block.minfo.mod.name + "-block-" + block.size); if(!base.found()) base = Core.atlas.find(basePrefix + "block-" + block.size); @@ -80,6 +101,98 @@ public class DrawTurret extends DrawBlock{ /** @return the generated icons to be used for this block. */ @Override public TextureRegion[] icons(Block block){ - return top.found() ? new TextureRegion[]{base, block.region, top} : new TextureRegion[]{base, block.region}; + TextureRegion showTop = preview.found() ? preview : block.region; + return top.found() ? new TextureRegion[]{base, showTop, top} : new TextureRegion[]{base, showTop}; + } + + public static class RegionPart extends TurretPart{ + public String suffix = ""; + public boolean mirror = true; + public TextureRegion[] regions; + public TextureRegion[] outlines; + + public boolean outline = false; + public float layer = -1; + public float outlineLayerOffset = -0.01f; + public float rotation, rotMove; + public float originX, originY; + public float offsetX, offsetY, offsetMoveX, offsetMoveY; + + public RegionPart(String region){ + this.suffix = region; + } + + public RegionPart(){ + } + + @Override + public void draw(TurretBuild build){ + float z = Draw.z(); + if(layer > 0){ + Draw.z(layer); + } + float prevZ = layer > 0 ? layer : z; + + float progress = build.warmup(); + + for(int i = 0; i < regions.length; i++){ + var region = regions[i]; + float sign = i == 1 ? -1 : 1; + Tmp.v1.set((offsetX + offsetMoveX * progress) * sign, offsetY + offsetMoveY*progress).rotate(build.rotation - 90); + + float + x = build.x + Tmp.v1.x, + y = build.y + Tmp.v1.y, + rot = (i == 0 ? rotation : 180f - rotation) + rotMove * progress * sign + build.rotation, + ox = originX + region.width * Draw.scl/2f, oy = originY + region.height * Draw.scl/2f; + + if(outline){ + Draw.z(prevZ + outlineLayerOffset); + + Draw.rect(outlines[i], + x, y, region.width * Draw.scl, region.height * Draw.scl, + ox, oy, rot); + + Draw.z(prevZ); + } + + Draw.rect(region, + x, y, region.width * Draw.scl, region.height * Draw.scl, + ox, oy, rot); + } + + Draw.z(z); + } + + @Override + public void load(Block block){ + if(mirror){ + regions = new TextureRegion[]{ + Core.atlas.find(block.name + suffix + "1"), + Core.atlas.find(block.name + suffix + "2") + }; + + outlines = new TextureRegion[]{ + Core.atlas.find(block.name + suffix + "1-outline"), + Core.atlas.find(block.name + suffix + "2-outline") + }; + }else{ + regions = new TextureRegion[]{Core.atlas.find(block.name + suffix)}; + outlines = new TextureRegion[]{Core.atlas.find(block.name + suffix + "-outline")}; + } + } + + @Override + public void getOutlines(Seq out){ + if(outline){ + out.addAll(regions); + } + } + } + + public static abstract class TurretPart{ + public abstract void draw(TurretBuild build); + public abstract void load(Block block); + public void getOutlines(Seq out){} } } diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 8365903ee3..6468b8aaed 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -220,6 +220,9 @@ public class Generators{ block.load(); block.loadIcon(); + Seq toOutline = new Seq<>(); + block.getRegionsToOutline(toOutline); + TextureRegion[] regions = block.getGeneratedIcons(); if(block.variants > 0 || block instanceof Floor){ @@ -257,6 +260,13 @@ public class Generators{ } } + if(toOutline != null){ + for(TextureRegion region : toOutline){ + Pixmap pix = get(region).outline(block.outlineColor, block.outlineRadius); + save(pix, ((GenRegion)region).name + "-outline"); + } + } + if(regions.length == 0){ continue; }