From ba14151a01087bbc887452e32888c43284848468 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 23 Nov 2021 22:41:25 -0500 Subject: [PATCH] A significant waste of time and effort --- .../turrets/bases/reinforced-block-3.png | Bin 0 -> 1027 bytes .../blocks/turrets/sublimate-back1.png | Bin 0 -> 356 bytes .../blocks/turrets/sublimate-back2.png | Bin 0 -> 344 bytes .../blocks/turrets/sublimate-preview.png | Bin 0 -> 1704 bytes .../sprites/blocks/turrets/sublimate.png | Bin 794 -> 1503 bytes core/assets/icons/icons.properties | 1 + core/assets/logicids.dat | Bin 3490 -> 3501 bytes core/src/mindustry/content/Blocks.java | 52 ++++++-- .../entities/bullet/ContinuousBulletType.java | 63 ++++++++++ .../bullet/ContinuousFlameBulletType.java | 74 +++++++++++ .../bullet/ContinuousLaserBulletType.java | 61 ++------- core/src/mindustry/graphics/Drawf.java | 46 +++++++ core/src/mindustry/type/Weapon.java | 23 +++- core/src/mindustry/world/Block.java | 4 + .../defense/turrets/ContinuousTurret.java | 2 +- .../world/blocks/defense/turrets/Turret.java | 15 +++ .../blocks/production/GenericCrafter.java | 5 + core/src/mindustry/world/draw/DrawBlock.java | 5 + core/src/mindustry/world/draw/DrawMulti.java | 7 ++ core/src/mindustry/world/draw/DrawTurret.java | 117 +++++++++++++++++- tools/src/mindustry/tools/Generators.java | 10 ++ 21 files changed, 413 insertions(+), 72 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/turrets/bases/reinforced-block-3.png create mode 100644 core/assets-raw/sprites/blocks/turrets/sublimate-back1.png create mode 100644 core/assets-raw/sprites/blocks/turrets/sublimate-back2.png create mode 100644 core/assets-raw/sprites/blocks/turrets/sublimate-preview.png create mode 100644 core/src/mindustry/entities/bullet/ContinuousBulletType.java create mode 100644 core/src/mindustry/entities/bullet/ContinuousFlameBulletType.java 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 0000000000000000000000000000000000000000..29f2caeabd1abf11477e2b5697ac38810de37c8e GIT binary patch literal 1027 zcmeAS@N?(olHy`uVBq!ia0y~yU`POA4mJh`hDS5XEf^S>PkFjHhE&XXJKH<&j)8zn z?Y@ea)hw1x{emfPt8W!FaH=&=yb>DwcXGx8aW=P*uhmMahvrNdfAswO{QmPVl8WZ) z7Dp<-YEw(o%XhhY;mDa>sgGtRhQ+(xZnUlXd`cz6+;FehA2!#6|3Civ_Ve@g>dGIR zMR@*)g>l}W|2f2LLf0OHn$;}%#y5quJ|Ftfuj12uU(uYW-uqC<57|$LKgg^4wBL7Q zV)`FuxOjA9^??N_;yAHY^sCxfUEJ5&yNp|H+ z#iM=lx|Sggsq;Uqi8QTw|3jHI;v47WtSJnq?GlsbIvq&iOlFxA=(JjuagN|^@eFeVfjOM&lgPct)Wcvv0Widn;s}%xMHm3(!hEzlGWq- zKh*@z2&QQb2uecbz@;~ltP6ymFs(Ve>iFq~e9?xUa3*=d35txBNy^8j>e>n#C#+&P zxtpPNeI2_`Y*WAwf7J~i);_R0=zhTU;D7%n@qJECW;NUgGJgD5S;4YFXw`%Fjc1zf zI~}-Kx<=!4=~e&zkq6{#u2vr?;^nG;zw5=<`&z4xK8$%1*LAbrq& zgyibOy&clMUW%JoO$lP!95S`mb!D)o%7*t{lk{JfuF>H1ZU{Ie!I(b9Ad53e)#dc& zzW*HO4lf8{U^1>^Tlo0?gUa9h;t4-vwmezUewb-nNW=5ZS3lV9obcUwMngv8R3V84 zE15(#FO#yG+V3hN8 zaSVxQeLKUK>yUwfoBiI-b$fbZxgUvUeOD4WvbT!$Bh$QNQ{|SfYg(%I(&rgB$1`1T zquQB&e1aDQXo%Fc@5;0;JHx5$5&xzrOVg0CX^wufj$`nI8zDw4lbJoP%?LGExjF4) zG|Tc^e2N=CS1r!ccQn=Nyz#B<>o?z%3wAWCCF?i_Cch0~k~w&>O*4sabwY`Ag!iP< z$tvl3-##g>lr&jusjz-Q<#wi@EJxc5a$2q?s&^^Mwm63>)-6m!I)yH5aYS2E+5cxOF-0t%v;~NvC<}xraFnGH9 KxvXU=;Fn zaSVxQeS6)OugO7x^}+I~=^HMeI_+>)*2kvV-9Y8u!KkeDk4-le3bT~W*v~8W`Bv-G z({B#xIH(A9{)u0;>*d~Ow<>&D{v6u%{IJb->AZDGVGFqXqP(~-^gMoJsC%Jha!ws@ zf%aZSRrcL)&M$hsa)s9M#;xyvzu7y9tE+HQS7f8ooDxk&=?T4;4+L#-xW=8>nEA{% za?KpkX{)6+#8?&;_)0iDxYovasNX>R+S|CFh6l_2?kaBL|9^<@_~jCx8;4vhvQ{=^ z9&K~*%`dH1T(LAK|GLp~A-)YPJPBnSToGJs7F*Wu?B&0a*bw|!p4m2`;qgRG#=Qv* zpA#=XE-#Synv%T0{LGwHc~$4_|9Gf4Jz+Mk?Bq_I@y?rpfq}u()z4*}Q$iB}#DtS; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f0974e30b46eb5e2175cc698066d323c59dc1fd2 GIT binary patch literal 1704 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 delta 758 zcmcc5J&SFEK|RwIPZ!6KiaBrRI+h();BoPcUw?gF^^rA`nYU^0eZE9OdV-12y#0NS zXB2V_)Rqc3aVWNci0Yc!|9`Uns0o>uFr-(AfBm^5{IT8d-5xaym@QsyG`799DMvTK z_Q{Iv+m2YyX0&~}coS>T%ZUN*w#7#pj8m0;3f2Z_KXvDwQLlTy$-m!Asb{OL#~wMi z8TVT@ckVx`T=paQ!qtV02^kC$#mq)$+`dOVQuDcWfx)1LCwIa>LzB%vno6b5@I*M) z9NeV)%3DyIbN|t-N~g08p{@1qw>vbM*C|!?=H5;}BVqL5)S>G$PIl=rYt+mZRQ8i} zc=-E;;i622*7=Wn1VihYHTLM~D*y96qOnibG19OBM2P7uvtkhp9+?a9*KW5!?LQfXnWZ0F1!cdj z3#{H-Ci;Rvito0%GU-b2iQ`2dgPg1wHSA0>mQnDL}HgfUOJKfyJFxrC$Z1EaiE zn8h_a@m1JRK_gCj8nlYo7bAFz3B$`VG zeC|d$PkXh)yf{Tds#p24Tft6Fck%lDB6lQicn|Sgilsiu40!2hKd=zV?>0 zJWFZPQ-5C_)pb9bwsUIsuibL&GRyX^O&$6bGZW%G%^u$0Xm)7Jhc}P7r>V^l-P84> zX)32$>pHc46O!aMtoqTkjWe&iP2{SGdlz z;ZDDN;`;v_iT}=g)(K;8TcFmyLHYEB-A@;tIp)j~nEYgiOm8-)VvB(OKZX~2>pt#f T`Ygr3z`)??>gTe~DWM4fdk0)7 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 d2181074789ee3d2d21f44fc3491bc3f425be517..1cc8dad67afe888d291d811ccdc44c4ad44227d6 100644 GIT binary patch delta 27 icmZ1^y;hou;owFl18y$P;?ks?%-qD1)Xj$6g-if-+X!+1 delta 16 XcmZ20y-1pg;lM^F1MbbX+yzVkE13kN 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; }