From 6b59c1cd83043a0e56ac31c860abdb42ea47b613 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 14 Oct 2021 20:58:03 -0400 Subject: [PATCH] More branch merging --- .../blocks/liquid/liquid-container-bottom.png | Bin 0 -> 626 bytes .../blocks/liquid/liquid-container-top.png | Bin 0 -> 298 bytes .../sprites/blocks/liquid/rotary-pump.png | Bin 712 -> 1193 bytes core/assets/bundles/bundle.properties | 2 + core/assets/icons/icons.properties | 7 + core/assets/logicids.dat | Bin 2663 -> 2719 bytes core/assets/shaders/clouds.vert | 20 +++ core/src/mindustry/Vars.java | 2 +- core/src/mindustry/ai/Pathfinder.java | 1 + core/src/mindustry/ai/WaveSpawner.java | 1 + core/src/mindustry/content/Blocks.java | 25 +-- core/src/mindustry/content/Planets.java | 8 +- core/src/mindustry/content/UnitTypes.java | 35 ++--- core/src/mindustry/core/ContentLoader.java | 5 - core/src/mindustry/core/Renderer.java | 92 ++++++++++- core/src/mindustry/core/UI.java | 2 +- core/src/mindustry/core/World.java | 19 ++- core/src/mindustry/ctype/Content.java | 7 +- core/src/mindustry/entities/Units.java | 2 +- .../mindustry/entities/abilities/Ability.java | 1 + .../mindustry/entities/comp/EntityComp.java | 1 - .../mindustry/entities/comp/FlyingComp.java | 28 +++- .../entities/comp/LaunchCoreComp.java | 1 - .../src/mindustry/entities/comp/LegsComp.java | 40 ++++- .../src/mindustry/entities/comp/MechComp.java | 16 ++ .../mindustry/entities/comp/PayloadComp.java | 2 +- .../src/mindustry/entities/comp/UnitComp.java | 12 ++ core/src/mindustry/game/Rules.java | 19 +++ core/src/mindustry/game/Universe.java | 5 +- .../mindustry/graphics/IndexedRenderer.java | 42 ++--- .../src/mindustry/graphics/LightRenderer.java | 4 + core/src/mindustry/graphics/Shaders.java | 29 +++- core/src/mindustry/graphics/Voronoi.java | 2 +- .../mindustry/graphics/g3d/GenericMesh.java | 7 + core/src/mindustry/graphics/g3d/HexMesh.java | 6 +- .../mindustry/graphics/g3d/HexSkyMesh.java | 60 +++++++ core/src/mindustry/graphics/g3d/MatMesh.java | 22 +++ .../src/mindustry/graphics/g3d/MultiMesh.java | 18 +++ .../src/mindustry/graphics/g3d/NoiseMesh.java | 43 ++++++ .../mindustry/graphics/g3d/PlanetGrid.java | 2 + .../mindustry/graphics/g3d/PlanetMesh.java | 28 ++-- .../mindustry/graphics/g3d/PlanetParams.java | 40 +++++ .../graphics/g3d/PlanetRenderer.java | 126 ++++++++------- .../graphics/g3d/ShaderSphereMesh.java | 5 - core/src/mindustry/graphics/g3d/SunMesh.java | 5 - core/src/mindustry/io/JsonIO.java | 13 ++ core/src/mindustry/io/SaveFileReader.java | 5 +- .../maps/generators/PlanetGenerator.java | 5 + core/src/mindustry/mod/ClassMap.java | 6 - core/src/mindustry/type/ItemSeq.java | 21 +++ core/src/mindustry/type/Planet.java | 87 ++++++----- core/src/mindustry/type/Sector.java | 11 +- core/src/mindustry/type/UnitType.java | 146 ++++++++++++++---- core/src/mindustry/type/Weapon.java | 2 +- core/src/mindustry/type/Weather.java | 2 + core/src/mindustry/ui/Menus.java | 9 +- core/src/mindustry/ui/dialogs/JoinDialog.java | 2 +- .../mindustry/ui/dialogs/MapPlayDialog.java | 2 +- .../mindustry/ui/dialogs/PlanetDialog.java | 137 +++++++++------- core/src/mindustry/world/Block.java | 9 ++ core/src/mindustry/world/Build.java | 2 +- .../world/blocks/ConstructBlock.java | 1 + .../world/blocks/defense/ForceProjector.java | 1 + .../world/blocks/defense/MendProjector.java | 1 + .../blocks/defense/OverdriveProjector.java | 1 + .../mindustry/world/blocks/defense/Wall.java | 3 + .../blocks/defense/turrets/PowerTurret.java | 1 + .../world/blocks/distribution/ItemBridge.java | 2 +- .../world/blocks/distribution/MassDriver.java | 1 + .../blocks/distribution/PayloadConveyor.java | 1 + .../world/blocks/environment/AirBlock.java | 1 + .../world/blocks/environment/EmptyFloor.java | 24 +++ .../world/blocks/environment/Floor.java | 9 +- .../world/blocks/experimental/BlockForge.java | 7 +- .../blocks/experimental/BlockLoader.java | 6 +- .../blocks/experimental/BlockUnloader.java | 6 +- .../world/blocks/liquid/ArmoredConduit.java | 2 +- .../world/blocks/liquid/Conduit.java | 2 +- .../world/blocks/liquid/LiquidBlock.java | 1 + .../world/blocks/liquid/LiquidBridge.java | 1 + .../world/blocks/logic/LogicBlock.java | 3 + .../world/blocks/logic/LogicDisplay.java | 1 + .../world/blocks/logic/MemoryBlock.java | 1 + .../world/blocks/logic/MessageBlock.java | 1 + .../world/blocks/logic/SwitchBlock.java | 1 + .../world/blocks/payloads/PayloadBlock.java | 10 +- .../mindustry/world/blocks/power/Battery.java | 2 + .../world/blocks/power/DecayGenerator.java | 2 + .../world/blocks/power/ImpactReactor.java | 1 + .../world/blocks/power/LightBlock.java | 2 + .../world/blocks/power/NuclearReactor.java | 1 + .../world/blocks/power/PowerDiode.java | 1 + .../world/blocks/power/PowerNode.java | 1 + .../world/blocks/power/SolarGenerator.java | 1 + .../world/blocks/power/ThermalGenerator.java | 2 +- .../world/blocks/production/Drill.java | 8 +- .../world/blocks/production/Incinerator.java | 6 +- .../world/blocks/production/Pump.java | 3 +- .../world/blocks/production/SolidPump.java | 4 +- .../world/blocks/sandbox/LiquidSource.java | 1 + .../world/blocks/sandbox/LiquidVoid.java | 1 + .../world/blocks/storage/CoreBlock.java | 4 +- .../world/blocks/storage/StorageBlock.java | 1 + .../world/blocks/storage/Unloader.java | 1 + .../world/blocks/units/CommandCenter.java | 1 + .../world/blocks/units/RepairPoint.java | 2 + core/src/mindustry/world/meta/StatValues.java | 12 +- core/src/mindustry/world/meta/Stats.java | 2 +- 108 files changed, 1018 insertions(+), 380 deletions(-) create mode 100644 core/assets-raw/sprites/blocks/liquid/liquid-container-bottom.png create mode 100644 core/assets-raw/sprites/blocks/liquid/liquid-container-top.png create mode 100755 core/assets/shaders/clouds.vert create mode 100644 core/src/mindustry/graphics/g3d/GenericMesh.java create mode 100644 core/src/mindustry/graphics/g3d/HexSkyMesh.java create mode 100644 core/src/mindustry/graphics/g3d/MatMesh.java create mode 100644 core/src/mindustry/graphics/g3d/MultiMesh.java create mode 100644 core/src/mindustry/graphics/g3d/NoiseMesh.java create mode 100644 core/src/mindustry/graphics/g3d/PlanetParams.java create mode 100644 core/src/mindustry/world/blocks/environment/EmptyFloor.java diff --git a/core/assets-raw/sprites/blocks/liquid/liquid-container-bottom.png b/core/assets-raw/sprites/blocks/liquid/liquid-container-bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..a256cae0b7079406bbecc2780aeb1ce522b9a6b2 GIT binary patch literal 626 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hE+`>V{rlK> zP29WHtCgy?x7yg2D$3XP?mpM0e`7QnL>zCY zs5G!Qvb<1?km_OEptONOrfKU=9tLhF;RS9VOs26eaDBm)!_nb8aXAAQBU1y<{9c7$ z!YBCVcV4LFkQ24zURcSa^zYcFxVANaH#G;WRyllW+q(KL3{aF8=MT7J=#>WWQ7jgF!ff z$)|xc;MJAIA6CY<`Te!3`Nci4Qq@e~b>sC%fgHcJzbCFcx>?{=z@!f=8P>L~xa<@h zvmvfRqk)}~SK%*Pf#n&7Fcy`DFOnBdJz(0Puz+F7@xt~0^%$fW85L|hw>*qw5OLDX z%DFnFMBe*{8UvRi^8u-S+yy31B^81P0y!if9%Z=6(NXt+;gWCk)UWS9{jOWc5ZA)P zuqs}ofn8B*!Bu^c16=}~3NOXE5*$02E_~r;y&zWgYxBQLe2g7Zje9vX87{tOlxrzy gSTkKw`w;&xqucvEg>qvU7#J8lUHx3vIVCg!07E|ntpET3 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/liquid/liquid-container-top.png b/core/assets-raw/sprites/blocks/liquid/liquid-container-top.png new file mode 100644 index 0000000000000000000000000000000000000000..2c68c6dd5e6926aefa237c193c71ae21f1df30b5 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&!0^P= z#WAE}&f6Q_e9ZJkuW~K;$raM|z>Im7OT<5?Cnp!~yRPxw t&0|w{z_0rYTv_a2k;A-Z0aE5uX?mcCYfTydU%Q~loCIHJMafAQ> literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/liquid/rotary-pump.png b/core/assets-raw/sprites/blocks/liquid/rotary-pump.png index 29a234b331c6fb7bf012c94a7ee57e344e1775aa..ad88b067530fc5db069a004de3efe2b8b5130757 100644 GIT binary patch delta 1174 zcmX@Xx{`B(ayoTTlB@kxz{O=!n3Jee%;ANz9(?VyO|H&4 zXq~%f_v6a^<8kNLTxMjFx2uZ_e%rBnw)6c=b-prvm+MbA)mPOQUDyRk1ha{J3HyV2HfAALIli_1c4P~l ztM7U5$jg&~%abR$PZ3cRTlqvVcGbpp%LB43jyP=A4`OJj4`+F6x2;C~brlzbf*jxJ zn=<>ZufM$a(*kiro7w`mdIl#c&eJz*lq39(xGdve!!XIud*bw8!b}qx_W5~Fe*TBE zwVZE(73&Xc^@1m>v!*M1>RGtg-Qi-`MbC16O^N%Zw){Tr?_A z+Af^!7!qaTNe~EQ@W4iaWW3R`D)K&LdFJu|&Io-SZY;)rSrAF_|N3|WL zXFb_jtf^GcA=IF3|MLrv*yYgGv6D_s6RTH@VBoA|Xn6Xx)S0DAVx30r6cNQLjsS;G z93lr@=UKTO=@Q^FWz6~1@%8R*F~{(*%*8DnT1-1mJZ?HwqhDOgD!tS7h1a$Jb_Gua z6{o67?{u-av3Ey*LxkXxCya;GRtPCA*n3vMqnBm=+!;45U0MQWlt~pktm24zB53Kd z;eCF+Z&TDnh6TYA7uPTZKU%qt`Jek1mJ2%lnIYY#_DvhUHiUe-@>f&IqgzUG!~6Rj z3%)+t>T<$y-loYRqH^-}%D01EITX)}`ouU?AH2_+lhG{@bgoM^|5j)vcSdK!b05K? ziS8@*vIVVzQvGV9|v2s|07;TJ7hV z8JYO%x?=dl7H6%>%jwr&Pw8p6P!yJ@6WpLC;$v3VsVaWwFmr;ZWGaGfj%q@WQsvi60*P z`1!%+*nzii`76E@aBr)&e)99}J-$D?eoMYz$f$SgRn@6q&JSNsUZ41zCAUC&a*<0D zXZ7m1Gy4ucN%5$DzfNRbZP&toD^i-5x;`+=Z2Pfz8sBsw$6e-;ul(yT$vBis?S3phM8HdCz*?cK%Y^rT?wC1=O0@K!&w?DU|CuoeHGNTk!7Jam;r(mQ2ON%8yo(MQ3wr$( zVf@B1Nz2NH`QeIw=LX3}(fYV*{ziutis6h!-5lp#CiEE@Gg#ShH!>;ks^uS_A-YZB z0Hevn=W4C9ua<(7hbFe5d3kr7b?`bDxz(bYC!QzTCWo+H8d-jt$2m6cG1WVpa42uL!p6FKFO3@o{c P$*Bw+X`AP8oMr?7gQPM> delta 67 zcmbO)`doyGVdh4rU=Abhq@4WZY~8f{qV!Y-9tbBVKQSe>h=C8nE6s!QIZ85$N{dT2 J@8@{H2mtK27fApB diff --git a/core/assets/shaders/clouds.vert b/core/assets/shaders/clouds.vert new file mode 100755 index 0000000000..869b40b964 --- /dev/null +++ b/core/assets/shaders/clouds.vert @@ -0,0 +1,20 @@ +attribute vec4 a_position; +attribute vec3 a_normal; +attribute vec4 a_color; + +uniform mat4 u_proj; +uniform mat4 u_trans; +uniform vec3 u_lightdir; +uniform vec3 u_ambientColor; +uniform float u_alpha; + +varying vec4 v_col; + +const vec3 diffuse = vec3(0.01); + +void main(){ + vec3 norc = u_ambientColor * (diffuse + vec3(clamp((dot(a_normal, u_lightdir) + 1.0) / 2.0, 0.0, 1.0))); + + v_col = a_color * vec4(norc, u_alpha); + gl_Position = u_proj * u_trans * a_position; +} diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index e890156fc6..3034d4e228 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -380,7 +380,7 @@ public class Vars implements Loadable{ log.log(level, text); try{ - writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeColors(text) + "\n"); + writer.write("[" + Character.toUpperCase(level.name().charAt(0)) + "] " + Log.removeColors(text) + "\n"); writer.flush(); }catch(IOException e){ e.printStackTrace(); diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index beae777c76..de447c3a59 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -50,6 +50,7 @@ public class Pathfinder implements Runnable{ //legs (team, tile) -> PathTile.legSolid(tile) ? impassable : 1 + + (PathTile.deep(tile) ? 6000 : 0) + //leg units can now drown (PathTile.solid(tile) ? 5 : 0), //water diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index 6800c6f618..d2d780618b 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -203,6 +203,7 @@ public class WaveSpawner{ unit.apply(StatusEffects.unmoving, 30f); unit.apply(StatusEffects.invincible, 60f); unit.add(); + unit.unloaded(); Events.fire(new UnitSpawnEvent(unit)); Call.spawnEffect(unit.x, unit.y, unit.rotation, unit.type); diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index e4ec21e238..b9204490a9 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -35,7 +35,7 @@ public class Blocks implements ContentList{ public static Block //environment - air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, + air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty, dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, grass, salt, @@ -435,18 +435,6 @@ public class Blocks implements ContentList{ basalt.asFloor().decoration = hotrock.asFloor().decoration = darksand.asFloor().decoration = magmarock.asFloor().decoration = this; }}; - moss = new Floor("moss"){{ - variants = 3; - attributes.set(Attribute.spores, 0.15f); - wall = sporePine; - }}; - - sporeMoss = new Floor("spore-moss"){{ - variants = 3; - attributes.set(Attribute.spores, 0.3f); - wall = sporeWall; - }}; - metalFloor = new Floor("metal-floor", 0); metalFloorDamaged = new Floor("metal-floor-damaged", 3); @@ -2105,14 +2093,15 @@ public class Blocks implements ContentList{ }}; constructor = new Constructor("constructor"){{ - requirements(Category.units, with(Items.thorium, 100)); + requirements(Category.units, with(Items.silicon, 50, Items.thorium, 70, Items.graphite, 50)); hasPower = true; consumes.power(2f); size = 3; }}; + //yes this block is pretty much useless largeConstructor = new Constructor("large-constructor"){{ - requirements(Category.units, with(Items.thorium, 100)); + requirements(Category.units, with(Items.silicon, 100, Items.thorium, 150, Items.graphite, 50, Items.phaseFabric, 40)); hasPower = true; consumes.power(2f); maxBlockSize = 4; @@ -2121,20 +2110,20 @@ public class Blocks implements ContentList{ }}; payloadLoader = new PayloadLoader("payload-loader"){{ - requirements(Category.units, with(Items.thorium, 100)); + requirements(Category.units, with(Items.graphite, 50, Items.silicon, 50, Items.copper, 100)); hasPower = true; consumes.power(2f); size = 3; }}; payloadUnloader = new PayloadUnloader("payload-unloader"){{ - requirements(Category.units, with(Items.thorium, 100)); + requirements(Category.units, with(Items.graphite, 50, Items.silicon, 50, Items.copper, 100)); hasPower = true; consumes.power(2f); size = 3; }}; - //TODO deprecated + //deprecated, will be removed. blockForge = constructor; blockLoader = payloadLoader; blockUnloader = payloadUnloader; diff --git a/core/src/mindustry/content/Planets.java b/core/src/mindustry/content/Planets.java index 6e81501d15..e7778e4f61 100644 --- a/core/src/mindustry/content/Planets.java +++ b/core/src/mindustry/content/Planets.java @@ -14,7 +14,7 @@ public class Planets implements ContentList{ @Override public void load(){ - sun = new Planet("sun", null, 0, 2){{ + sun = new Planet("sun", null, 4){{ bloom = true; accessible = false; @@ -31,9 +31,13 @@ public class Planets implements ContentList{ ); }}; - serpulo = new Planet("serpulo", sun, 3, 1){{ + serpulo = new Planet("serpulo", sun, 1, 3){{ generator = new SerpuloPlanetGenerator(); meshLoader = () -> new HexMesh(this, 6); + cloudMeshLoader = () -> new MultiMesh( + new HexSkyMesh(this, 11, 0.15f, 0.13f, 5, new Color().set(Pal.spore).mul(0.9f).a(0.75f), 2, 0.45f, 0.9f, 0.38f), + new HexSkyMesh(this, 1, 0.6f, 0.16f, 5, Color.white.cpy().lerp(Pal.spore, 0.55f).a(0.75f), 2, 0.45f, 1f, 0.41f) + ); atmosphereColor = Color.valueOf("3c1b8f"); atmosphereRadIn = 0.02f; atmosphereRadOut = 0.3f; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 9874f66516..d9afc9eb0d 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -157,13 +157,13 @@ public class UnitTypes implements ContentList{ rotateSpeed = 2.1f; health = 9000; armor = 10f; - canDrown = false; mechFrontSway = 1f; ammoType = new ItemAmmoType(Items.thorium); mechStepParticles = true; mechStepShake = 0.15f; singleTarget = true; + drownTimeMultiplier = 4f; weapons.add( new Weapon("scepter-weapon"){{ @@ -221,7 +221,7 @@ public class UnitTypes implements ContentList{ armor = 14f; mechStepParticles = true; mechStepShake = 0.75f; - canDrown = false; + drownTimeMultiplier = 6f; mechFrontSway = 1.9f; mechSideSway = 0.6f; ammoType = new ItemAmmoType(Items.thorium); @@ -414,13 +414,13 @@ public class UnitTypes implements ContentList{ hitSize = 24f; rotateSpeed = 1.8f; - canDrown = false; mechFrontSway = 1f; buildSpeed = 3f; mechStepParticles = true; mechStepShake = 0.15f; ammoType = new PowerAmmoType(2500); + drownTimeMultiplier = 4f; speed = 0.44f; boostMultiplier = 2.4f; @@ -501,6 +501,7 @@ public class UnitTypes implements ContentList{ armor = 9f; landShake = 1.5f; rotateSpeed = 1.5f; + drownTimeMultiplier = 6f; commandLimit = 8; @@ -511,7 +512,6 @@ public class UnitTypes implements ContentList{ legTrns = 0.58f; hovering = true; visualElevation = 0.2f; - allowLegStep = true; ammoType = new PowerAmmoType(4000); groundLayer = Layer.legUnit; @@ -602,7 +602,7 @@ public class UnitTypes implements ContentList{ }}; atrax = new UnitType("atrax"){{ - speed = 0.54f; + speed = 0.57f; drag = 0.4f; hitSize = 13f; rotateSpeed = 3f; @@ -618,7 +618,6 @@ public class UnitTypes implements ContentList{ armor = 3f; ammoType = new ItemAmmoType(Items.coal); - allowLegStep = true; visualElevation = 0.2f; groundLayer = Layer.legUnit - 1f; @@ -632,8 +631,8 @@ public class UnitTypes implements ContentList{ shootSound = Sounds.flame; bullet = new LiquidBulletType(Liquids.slag){{ - damage = 11; - speed = 2.4f; + damage = 13; + speed = 2.5f; drag = 0.009f; shootEffect = Fx.shootSmall; lifetime = 57f; @@ -643,11 +642,11 @@ public class UnitTypes implements ContentList{ }}; spiroct = new UnitType("spiroct"){{ - speed = 0.48f; + speed = 0.52f; drag = 0.4f; hitSize = 15f; rotateSpeed = 3f; - health = 910; + health = 940; immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); legCount = 6; legLength = 13f; @@ -660,7 +659,6 @@ public class UnitTypes implements ContentList{ buildSpeed = 0.75f; - allowLegStep = true; visualElevation = 0.3f; groundLayer = Layer.legUnit; @@ -678,7 +676,7 @@ public class UnitTypes implements ContentList{ bullet = new SapBulletType(){{ sapStrength = 0.5f; length = 75f; - damage = 20; + damage = 23; shootEffect = Fx.shootSmall; hitColor = color = Color.valueOf("bf92f9"); despawnEffect = Fx.none; @@ -698,7 +696,7 @@ public class UnitTypes implements ContentList{ bullet = new SapBulletType(){{ sapStrength = 0.8f; length = 40f; - damage = 16; + damage = 18; shootEffect = Fx.shootSmall; hitColor = color = Color.valueOf("bf92f9"); despawnEffect = Fx.none; @@ -711,7 +709,7 @@ public class UnitTypes implements ContentList{ arkyid = new UnitType("arkyid"){{ drag = 0.1f; - speed = 0.6f; + speed = 0.62f; hitSize = 23f; health = 8000; armor = 6f; @@ -733,16 +731,16 @@ public class UnitTypes implements ContentList{ legSplashDamage = 32; legSplashRange = 30; + drownTimeMultiplier = 2f; hovering = true; - allowLegStep = true; visualElevation = 0.65f; groundLayer = Layer.legUnit; BulletType sapper = new SapBulletType(){{ sapStrength = 0.85f; length = 55f; - damage = 37; + damage = 40; shootEffect = Fx.shootSmall; hitColor = color = Color.valueOf("bf92f9"); despawnEffect = Fx.none; @@ -820,6 +818,7 @@ public class UnitTypes implements ContentList{ lightRadius = 140f; rotateSpeed = 1.9f; + drownTimeMultiplier = 3f; legCount = 8; legMoveSpace = 0.8f; @@ -828,7 +827,6 @@ public class UnitTypes implements ContentList{ legExtension = -20; legBaseOffset = 8f; landShake = 1f; - legSpeed = 0.1f; legLengthScl = 0.93f; rippleScale = 3f; legSpeed = 0.19f; @@ -839,7 +837,6 @@ public class UnitTypes implements ContentList{ legSplashRange = 60; hovering = true; - allowLegStep = true; visualElevation = 0.95f; groundLayer = Layer.legUnit; @@ -2287,6 +2284,7 @@ public class UnitTypes implements ContentList{ defaultController = BuilderAI::new; isCounted = false; + lowAltitude = true; flying = true; mineSpeed = 6.5f; mineTier = 1; @@ -2366,6 +2364,7 @@ public class UnitTypes implements ContentList{ defaultController = BuilderAI::new; isCounted = false; + lowAltitude = true; flying = true; mineSpeed = 8f; mineTier = 2; diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index 6a836dceb5..715c22a89b 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -151,11 +151,6 @@ public class ContentLoader{ ColorMapper.load(); } - public void dispose(){ - initialize(Content::dispose); - clear(); - } - /** Get last piece of content created for error-handling purposes. */ public @Nullable Content getLastAdded(){ return lastAdded; diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 61e44b011e..79f5ddfc4a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -1,6 +1,7 @@ package mindustry.core; import arc.*; +import arc.assets.loaders.TextureLoader.*; import arc.files.*; import arc.graphics.*; import arc.graphics.Texture.*; @@ -42,12 +43,14 @@ public class Renderer implements ApplicationListener{ public PlanetRenderer planets; public @Nullable Bloom bloom; + public @Nullable FrameBuffer backgroundBuffer; public FrameBuffer effectBuffer = new FrameBuffer(); public boolean animateShields, drawWeather = true, drawStatus; public float weatherAlpha; /** minZoom = zooming out, maxZoom = zooming in */ public float minZoom = 1.5f, maxZoom = 6f; public Seq envRenderers = new Seq<>(); + public ObjectMap customBackgrounds = new ObjectMap<>(); public TextureRegion[] bubbles = new TextureRegion[16], splashes = new TextureRegion[12]; private @Nullable CoreBuild landCore; @@ -88,6 +91,10 @@ public class Renderer implements ApplicationListener{ envRenderers.add(new EnvRenderer(mask, render)); } + public void addCustomBackground(String name, Runnable render){ + customBackgrounds.put(name, render); + } + @Override public void init(){ planets = new PlanetRenderer(); @@ -108,6 +115,14 @@ public class Renderer implements ApplicationListener{ t.setWrap(TextureWrap.repeat); t.setFilter(TextureFilter.linear); }; + + Events.on(WorldLoadEvent.class, e -> { + //reset background buffer on every world load, so it can be re-cached first render + if(backgroundBuffer != null){ + backgroundBuffer.dispose(); + backgroundBuffer = null; + } + }); } @Override @@ -311,8 +326,81 @@ public class Renderer implements ApplicationListener{ Events.fire(Trigger.postDraw); } - private void drawBackground(){ - //nothing to draw currently + protected void drawBackground(){ + //draw background only if there is no planet background with a skybox + if(state.rules.backgroundTexture != null && (state.rules.planetBackground == null || !state.rules.planetBackground.drawSkybox)){ + if(!assets.isLoaded(state.rules.backgroundTexture, Texture.class)){ + var file = assets.getFileHandleResolver().resolve(state.rules.backgroundTexture); + + //don't draw invalid/non-existent backgrounds. + if(!file.exists() || !file.extEquals("png")){ + return; + } + + var desc = assets.load(state.rules.backgroundTexture, Texture.class, new TextureParameter(){{ + wrapU = wrapV = TextureWrap.mirroredRepeat; + magFilter = minFilter = TextureFilter.linear; + }}); + + assets.finishLoadingAsset(desc); + } + + Texture tex = assets.get(state.rules.backgroundTexture, Texture.class); + Tmp.tr1.set(tex); + Tmp.tr1.u = 0f; + Tmp.tr1.v = 0f; + + float ratio = camera.width / camera.height; + float size = state.rules.backgroundScl; + + Tmp.tr1.u2 = size; + Tmp.tr1.v2 = size / ratio; + + float sx = 0f, sy = 0f; + + if(!Mathf.zero(state.rules.backgroundSpeed)){ + sx = (camera.position.x) / state.rules.backgroundSpeed; + sy = (camera.position.y) / state.rules.backgroundSpeed; + } + + Tmp.tr1.scroll(sx + state.rules.backgroundOffsetX, -sy + state.rules.backgroundOffsetY); + + Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height); + } + + if(state.rules.planetBackground != null){ + int size = Math.max(graphics.getWidth(), graphics.getHeight()); + + boolean resized = false; + if(backgroundBuffer == null){ + resized = true; + backgroundBuffer = new FrameBuffer(size, size); + } + + if(resized || backgroundBuffer.resizeCheck(size, size)){ + backgroundBuffer.begin(Color.clear); + + var params = state.rules.planetBackground; + + //override some values + params.viewW = size; + params.viewH = size; + params.alwaysDrawAtmosphere = true; + params.drawUi = false; + + planets.render(params); + + backgroundBuffer.end(); + } + + float drawSize = Math.max(camera.width, camera.height); + Draw.rect(Draw.wrap(backgroundBuffer.getTexture()), camera.position.x, camera.position.y, drawSize, -drawSize); + } + + if(state.rules.customBackgroundCallback != null && customBackgrounds.containsKey(state.rules.customBackgroundCallback)){ + customBackgrounds.get(state.rules.customBackgroundCallback).run(); + } + } void updateLandParticles(){ diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index b0180958a1..49b5afcdda 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -588,7 +588,7 @@ public class UI implements ApplicationListener, Loadable{ if(mag >= 1_000_000_000){ return sign + Strings.fixed(mag / 1_000_000_000f, 1) + "[gray]" + billions+ "[]"; }else if(mag >= 1_000_000){ - return sign + Strings.fixed(mag / 1_000_000f, 1) + "[gray]" +millions + "[]"; + return sign + Strings.fixed(mag / 1_000_000f, 1) + "[gray]" + millions + "[]"; }else if(mag >= 10_000){ return number / 1000 + "[gray]" + thousands + "[]"; }else if(mag >= 1000){ diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 839b453867..47d4c05475 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -8,6 +8,7 @@ import arc.math.geom.Geometry.*; import arc.struct.*; import arc.util.*; import arc.util.noise.*; +import mindustry.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.ctype.*; @@ -246,15 +247,17 @@ public class World{ if(sector.preset != null){ sector.preset.generator.generate(tiles); sector.preset.rules.get(state.rules); //apply extra rules - }else{ + }else if(sector.planet.generator != null){ sector.planet.generator.generate(tiles, sector); + }else{ + throw new RuntimeException("Sector " + sector.id + " on planet " + sector.planet.name + " has no generator or preset defined. Provide a planet generator or preset map."); } //just in case state.rules.sector = sector; }); //postgenerate for bases - if(sector.preset == null){ + if(sector.preset == null && sector.planet.generator != null){ sector.planet.generator.postGenerate(tiles); } @@ -477,12 +480,14 @@ public class World{ //TODO optimize; this is very slow and called too often! public float getDarkness(int x, int y){ - int edgeBlend = 2; - float dark = 0; - int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1))))); - if(edgeDst <= edgeBlend){ - dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark); + + if(Vars.state.rules.borderDarkness){ + int edgeBlend = 2; + int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1))))); + if(edgeDst <= edgeBlend){ + dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark); + } } if(state.hasSector() && state.getSector().preset == null){ diff --git a/core/src/mindustry/ctype/Content.java b/core/src/mindustry/ctype/Content.java index 4103f4899e..fb0679bf9b 100644 --- a/core/src/mindustry/ctype/Content.java +++ b/core/src/mindustry/ctype/Content.java @@ -6,7 +6,7 @@ import mindustry.*; import mindustry.mod.Mods.*; /** Base class for a content type that is loaded in {@link mindustry.core.ContentLoader}. */ -public abstract class Content implements Comparable, Disposable{ +public abstract class Content implements Comparable{ public short id; /** Info on which mod this content was loaded from. */ public ModContentInfo minfo = new ModContentInfo(); @@ -39,11 +39,6 @@ public abstract class Content implements Comparable, Disposable{ return minfo.error != null; } - @Override - public void dispose(){ - //does nothing by default - } - @Override public int compareTo(Content c){ return Integer.compare(id, c.id); diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index ae4f8e00eb..532c74fbbf 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -129,7 +129,7 @@ public class Units{ nearby(x, y, width, height, unit -> { if(boolResult) return; - if((unit.isGrounded() && !unit.type.hovering) == ground){ + if((unit.isGrounded() && !unit.hovering) == ground){ unit.hitboxTile(hitrect); if(hitrect.overlaps(x, y, width, height)){ diff --git a/core/src/mindustry/entities/abilities/Ability.java b/core/src/mindustry/entities/abilities/Ability.java index c11c393602..433563d70b 100644 --- a/core/src/mindustry/entities/abilities/Ability.java +++ b/core/src/mindustry/entities/abilities/Ability.java @@ -7,6 +7,7 @@ import mindustry.gen.*; public abstract class Ability implements Cloneable{ public void update(Unit unit){} public void draw(Unit unit){} + public void death(Unit unit){} public Ability copy(){ try{ diff --git a/core/src/mindustry/entities/comp/EntityComp.java b/core/src/mindustry/entities/comp/EntityComp.java index d44e5481b4..aaacdc521b 100644 --- a/core/src/mindustry/entities/comp/EntityComp.java +++ b/core/src/mindustry/entities/comp/EntityComp.java @@ -1,6 +1,5 @@ package mindustry.entities.comp; -import arc.func.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.entities.*; diff --git a/core/src/mindustry/entities/comp/FlyingComp.java b/core/src/mindustry/entities/comp/FlyingComp.java index 1242593c49..c2d6dacea4 100644 --- a/core/src/mindustry/entities/comp/FlyingComp.java +++ b/core/src/mindustry/entities/comp/FlyingComp.java @@ -8,6 +8,7 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.game.EventType.*; import mindustry.gen.*; +import mindustry.type.*; import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; @@ -16,14 +17,16 @@ import static mindustry.Vars.*; abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2(); - @Import float x, y, speedMultiplier; + @Import float x, y, speedMultiplier, hitSize; @Import Vec2 vel; + @Import UnitType type; @SyncLocal float elevation; private transient boolean wasFlying; transient boolean hovering; transient float drownTime; transient float splashTimer; + transient @Nullable Floor lastDrownFloor; boolean checkTarget(boolean targetAir, boolean targetGround){ return (isGrounded() && targetGround) || (isFlying() && targetAir); @@ -41,6 +44,10 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ return isGrounded() && !hovering; } + @Nullable Floor drownFloor(){ + return canDrown() ? floorOn() : null; + } + boolean emitWalkSound(){ return true; } @@ -90,20 +97,27 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ } } - if(canDrown() && floor.isLiquid && floor.drownTime > 0){ - drownTime += Time.delta / floor.drownTime; - drownTime = Mathf.clamp(drownTime); + updateDrowning(); + } + + public void updateDrowning(){ + Floor floor = drownFloor(); + + if(floor != null && floor.isLiquid && floor.drownTime > 0){ + lastDrownFloor = floor; + drownTime += Time.delta / floor.drownTime / type.drownTimeMultiplier; if(Mathf.chanceDelta(0.05f)){ - floor.drownUpdateEffect.at(x, y, 1f, floor.mapColor); + floor.drownUpdateEffect.at(x, y, hitSize, floor.mapColor); } - //TODO is the netClient check necessary? if(drownTime >= 0.999f && !net.client()){ kill(); Events.fire(new UnitDrownEvent(self())); } }else{ - drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f); + drownTime -= Time.delta / 50f; } + + drownTime = Mathf.clamp(drownTime); } } diff --git a/core/src/mindustry/entities/comp/LaunchCoreComp.java b/core/src/mindustry/entities/comp/LaunchCoreComp.java index e91e3749fc..b28e3657b8 100644 --- a/core/src/mindustry/entities/comp/LaunchCoreComp.java +++ b/core/src/mindustry/entities/comp/LaunchCoreComp.java @@ -7,7 +7,6 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.ui.*; import mindustry.world.*; @EntityDef(value = LaunchCorec.class, serialize = false) diff --git a/core/src/mindustry/entities/comp/LegsComp.java b/core/src/mindustry/entities/comp/LegsComp.java index 8ddb4793e4..81073abc1f 100644 --- a/core/src/mindustry/entities/comp/LegsComp.java +++ b/core/src/mindustry/entities/comp/LegsComp.java @@ -9,6 +9,7 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.EntityCollisions.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -18,22 +19,30 @@ import mindustry.world.blocks.environment.*; abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ @Import float x, y; @Import UnitType type; + @Import Team team; transient Leg[] legs = {}; transient float totalLength; transient float moveSpace; transient float baseRotation; + transient Floor lastDeepFloor; @Replace @Override public SolidPred solidity(){ - return !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid; + return type.allowLegStep ? EntityCollisions::legsSolid : EntityCollisions::solid; } @Override @Replace public int pathType(){ - return Pathfinder.costLegs; + return type.allowLegStep ? Pathfinder.costGround : Pathfinder.costLegs; + } + + @Override + @Replace + public Floor drownFloor(){ + return lastDeepFloor; } @Override @@ -41,10 +50,18 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ resetLegs(); } + @Override + public void unloaded(){ + resetLegs(1f); + } + public void resetLegs(){ + resetLegs(type.legLength); + } + + public void resetLegs(float legLength){ float rot = baseRotation; int count = type.legCount; - float legLength = type.legLength; this.legs = new Leg[count]; @@ -85,6 +102,9 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ Vec2 moveOffset = Tmp.v4.trns(rot, trns); boolean moving = moving(); + lastDeepFloor = null; + int deeps = 0; + for(int i = 0; i < legs.length; i++){ float dstRot = legAngle(rot, i); Vec2 baseOffset = Tmp.v5.trns(dstRot, type.legBaseOffset).add(x, y); @@ -105,11 +125,16 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ l.moving = move; l.stage = moving ? stageF % 1f : Mathf.lerpDelta(l.stage, 0f, 0.1f); + Floor floor = Vars.world.floorWorld(l.base.x, l.base.y); + if(floor.isDeep()){ + deeps ++; + lastDeepFloor = floor; + } + if(l.group != group){ //create effect when transitioning to a group it can't move in if(!move && i % div == l.group){ - Floor floor = Vars.world.floorWorld(l.base.x, l.base.y); if(floor.isLiquid){ floor.walkEffect.at(l.base.x, l.base.y, type.rippleScale, floor.mapColor); floor.walkSound.at(x, y, 1f, floor.walkSoundVolume); @@ -123,7 +148,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ } if(type.legSplashDamage > 0){ - Damage.damage(team(), l.base.x, l.base.y, type.legSplashRange, type.legSplashDamage, false, true); + Damage.damage(team, l.base.x, l.base.y, type.legSplashRange, type.legSplashDamage, false, true); } } @@ -148,6 +173,11 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{ l.joint.lerpDelta(jointDest, moveSpeed / 4f); } + + //when at least 1 leg is touching land, it can't drown + if(deeps != legs.length){ + lastDeepFloor = null; + } } /** @return outwards facing angle of leg at the specified index. */ diff --git a/core/src/mindustry/entities/comp/MechComp.java b/core/src/mindustry/entities/comp/MechComp.java index bd822d523b..18ffc784a7 100644 --- a/core/src/mindustry/entities/comp/MechComp.java +++ b/core/src/mindustry/entities/comp/MechComp.java @@ -10,6 +10,7 @@ import mindustry.entities.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; +import mindustry.world.blocks.environment.*; import static mindustry.Vars.*; @@ -62,6 +63,21 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati walkExtension = extendScl; } + @Replace + @Override + public @Nullable Floor drownFloor(){ + //large mechs can only drown when all the nearby floors are deep + if(hitSize >= 12 && canDrown()){ + for(Point2 p : Geometry.d8){ + Floor f = world.floorWorld(x + p.x * tilesize, y + p.y * tilesize); + if(!f.isDeep()){ + return null; + } + } + } + return canDrown() ? floorOn() : null; + } + public float walkExtend(boolean scaled){ //now ranges from -maxExtension to maxExtension*3 diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java index 0f02434a92..3cc63c835d 100644 --- a/core/src/mindustry/entities/comp/PayloadComp.java +++ b/core/src/mindustry/entities/comp/PayloadComp.java @@ -13,7 +13,6 @@ import mindustry.entities.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.type.*; -import mindustry.ui.*; import mindustry.world.*; import mindustry.world.blocks.payloads.*; @@ -123,6 +122,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{ //decrement count to prevent double increment if(!u.isAdded()) u.team.data().updateCount(u.type, -1); u.add(); + u.unloaded(); return true; } diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index ab36682972..7236f5618b 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -45,12 +45,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I boolean spawnedByCore; double flag; + transient float shadowAlpha = -1f; transient Seq abilities = new Seq<>(0); transient float healTime; private transient float resupplyTime = Mathf.random(10f); private transient boolean wasPlayer; private transient boolean wasHealed; + /** Called when this unit was unloaded from a factory or spawn point. */ + public void unloaded(){ + + } + /** Move based on preferred unit movement type. */ public void movePref(Vec2 movement){ if(type.omniMovement){ @@ -520,6 +526,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I } } + if(abilities.size > 0){ + for(Ability a : abilities){ + a.death(self()); + } + } + remove(); } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index 3354f223f4..bed0a54cab 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -6,6 +6,7 @@ import arc.util.*; import arc.util.serialization.*; import arc.util.serialization.Json.*; import mindustry.content.*; +import mindustry.graphics.g3d.*; import mindustry.io.*; import mindustry.type.*; import mindustry.type.Weather.*; @@ -117,8 +118,22 @@ public class Rules{ public @Nullable String modeName; /** Whether cores incinerate items when full, just like in the campaign. */ public boolean coreIncinerates = false; + /** If false, borders fade out into darkness. Only use with custom backgrounds!*/ + public boolean borderDarkness = true; /** special tags for additional info. */ public StringMap tags = new StringMap(); + /** Name of callback to call for background rendering in mods; see Renderer#addCustomBackground. Runs last. */ + public @Nullable String customBackgroundCallback; + /** path to background texture with extension (e.g. "sprites/space.png")*/ + public @Nullable String backgroundTexture; + /** background texture move speed scaling - bigger numbers mean slower movement. 0 to disable. */ + public float backgroundSpeed = 27000f; + /** background texture scaling factor */ + public float backgroundScl = 1f; + /** background UV offsets */ + public float backgroundOffsetX = 0.1f, backgroundOffsetY = 0.1f; + /** Parameters for planet rendered in the background. Cannot be changed once a map is loaded. */ + public @Nullable PlanetParams planetBackground; /** Copies this ruleset exactly. Not efficient at all, do not use often. */ public Rules copy(){ @@ -140,6 +155,10 @@ public class Rules{ } } + public boolean hasEnv(int env){ + return (environment & env) != 0; + } + public float unitBuildSpeed(Team team){ return unitBuildSpeedMultiplier * teams.get(team).unitBuildSpeedMultiplier; } diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java index 8d563f9957..f12250980c 100644 --- a/core/src/mindustry/game/Universe.java +++ b/core/src/mindustry/game/Universe.java @@ -82,10 +82,11 @@ public class Universe{ } } - if(state.hasSector()){ + if(state.hasSector() && state.getSector().planet.updateLighting){ + var planet = state.getSector().planet; //update sector light float light = state.getSector().getLight(); - float alpha = Mathf.clamp(Mathf.map(light, 0f, 0.8f, 0.3f, 1f)); + float alpha = Mathf.clamp(Mathf.map(light, planet.lightSrcFrom, planet.lightSrcTo, planet.lightDstFrom, planet.lightDstTo)); //assign and map so darkness is not 100% dark state.rules.ambientLight.a = 1f - alpha; diff --git a/core/src/mindustry/graphics/IndexedRenderer.java b/core/src/mindustry/graphics/IndexedRenderer.java index 9c02615fbd..4353279355 100644 --- a/core/src/mindustry/graphics/IndexedRenderer.java +++ b/core/src/mindustry/graphics/IndexedRenderer.java @@ -10,27 +10,29 @@ public class IndexedRenderer implements Disposable{ private static final int vsize = 5; private final Shader program = new Shader( - "attribute vec4 a_position;\n" + - "attribute vec4 a_color;\n" + - "attribute vec2 a_texCoord0;\n" + - "uniform mat4 u_projTrans;\n" + - "varying vec4 v_color;\n" + - "varying vec2 v_texCoords;\n" + + """ + attribute vec4 a_position; + attribute vec4 a_color; + attribute vec2 a_texCoord0; + uniform mat4 u_projTrans; + varying vec4 v_color; + varying vec2 v_texCoords; + void main(){ + v_color = a_color; + v_color.a = v_color.a * (255.0/254.0); + v_texCoords = a_texCoord0; + gl_Position = u_projTrans * a_position; + } + """, - "void main(){\n" + - " v_color = a_color;\n" + - " v_color.a = v_color.a * (255.0/254.0);\n" + - " v_texCoords = a_texCoord0;\n" + - " gl_Position = u_projTrans * a_position;\n" + - "}", - - "varying lowp vec4 v_color;\n" + - "varying vec2 v_texCoords;\n" + - "uniform sampler2D u_texture;\n" + - - "void main(){\n" + - " gl_FragColor = v_color * texture2D(u_texture, v_texCoords);\n" + - "}" + """ + varying lowp vec4 v_color; + varying vec2 v_texCoords; + uniform sampler2D u_texture; + void main(){ + gl_FragColor = v_color * texture2D(u_texture, v_texCoords); + } + """ ); private Mesh mesh; private float[] tmpVerts = new float[vsize * 6]; diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java index acf0583e02..b117b984bc 100644 --- a/core/src/mindustry/graphics/LightRenderer.java +++ b/core/src/mindustry/graphics/LightRenderer.java @@ -191,7 +191,10 @@ public class LightRenderer{ Draw.color(); buffer.begin(Color.clear); + Draw.sort(false); Gl.blendEquationSeparate(Gl.funcAdd, Gl.max); + //apparently necessary + Blending.normal.apply(); for(Runnable run : lights){ run.run(); @@ -202,6 +205,7 @@ public class LightRenderer{ Draw.rect(circleRegion, cir.x, cir.y, cir.radius * 2, cir.radius * 2); } Draw.reset(); + Draw.sort(true); buffer.end(); Gl.blendEquationSeparate(Gl.funcAdd, Gl.funcAdd); diff --git a/core/src/mindustry/graphics/Shaders.java b/core/src/mindustry/graphics/Shaders.java index 33026d6fe1..f0054e95d5 100644 --- a/core/src/mindustry/graphics/Shaders.java +++ b/core/src/mindustry/graphics/Shaders.java @@ -23,6 +23,7 @@ public class Shaders{ public static LightShader light; public static SurfaceShader water, mud, tar, slag, cryofluid, space, caustics; public static PlanetShader planet; + public static CloudShader clouds; public static PlanetGridShader planetGrid; public static AtmosphereShader atmosphere; public static MeshShader mesh; @@ -56,6 +57,7 @@ public class Shaders{ // } //}; planet = new PlanetShader(); + clouds = new CloudShader(); planetGrid = new PlanetGridShader(); atmosphere = new AtmosphereShader(); unlit = new LoadShader("planet", "unlit"); @@ -94,6 +96,7 @@ public class Shaders{ public Vec3 lightDir = new Vec3(1, 1, 1).nor(); public Color ambientColor = Color.white.cpy(); public Vec3 camDir = new Vec3(); + public Planet planet; public PlanetShader(){ super("planet", "planet"); @@ -101,7 +104,7 @@ public class Shaders{ @Override public void apply(){ - camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, renderer.planets.planet.getRotation()); + camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, planet.getRotation()); setUniformf("u_lightdir", lightDir); setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b); @@ -109,6 +112,27 @@ public class Shaders{ } } + public static class CloudShader extends LoadShader{ + public Vec3 lightDir = new Vec3(1, 1, 1).nor(); + public Color ambientColor = Color.white.cpy(); + public Vec3 camDir = new Vec3(); + public float alpha = 1f; + public Planet planet; + + public CloudShader(){ + super("planet", "clouds"); + } + + @Override + public void apply(){ + camDir.set(renderer.planets.cam.direction).rotate(Vec3.Y, planet.getRotation()); + + setUniformf("u_alpha", alpha); + setUniformf("u_lightdir", lightDir); + setUniformf("u_ambientColor", ambientColor.r, ambientColor.g, ambientColor.b); + } + } + public static class MeshShader extends LoadShader{ public MeshShader(){ @@ -176,6 +200,7 @@ public class Shaders{ public static class BlockBuildShader extends LoadShader{ public float progress; public TextureRegion region = new TextureRegion(); + public float time; public BlockBuildShader(){ super("blockbuild", "default"); @@ -186,7 +211,7 @@ public class Shaders{ setUniformf("u_progress", progress); setUniformf("u_uv", region.u, region.v); setUniformf("u_uv2", region.u2, region.v2); - setUniformf("u_time", Time.time); + setUniformf("u_time", time); setUniformf("u_texsize", region.texture.width, region.texture.height); } } diff --git a/core/src/mindustry/graphics/Voronoi.java b/core/src/mindustry/graphics/Voronoi.java index 7b10e497e2..84065f53b2 100755 --- a/core/src/mindustry/graphics/Voronoi.java +++ b/core/src/mindustry/graphics/Voronoi.java @@ -396,7 +396,7 @@ public class Voronoi{ private void clipLine(Edge e){ float pxmin, pxmax, pymin, pymax; Site s1, s2; - float x1 = 0, x2 = 0, y1 = 0, y2 = 0; + float x1, x2, y1, y2; x1 = e.reg[0].coord.x; x2 = e.reg[1].coord.x; diff --git a/core/src/mindustry/graphics/g3d/GenericMesh.java b/core/src/mindustry/graphics/g3d/GenericMesh.java new file mode 100644 index 0000000000..d4198f5d9a --- /dev/null +++ b/core/src/mindustry/graphics/g3d/GenericMesh.java @@ -0,0 +1,7 @@ +package mindustry.graphics.g3d; + +import arc.math.geom.*; + +public interface GenericMesh{ + void render(PlanetParams params, Mat3D projection, Mat3D transform); +} diff --git a/core/src/mindustry/graphics/g3d/HexMesh.java b/core/src/mindustry/graphics/g3d/HexMesh.java index e3ba7b9f27..bf5af1366e 100644 --- a/core/src/mindustry/graphics/g3d/HexMesh.java +++ b/core/src/mindustry/graphics/g3d/HexMesh.java @@ -15,8 +15,12 @@ public class HexMesh extends PlanetMesh{ super(planet, MeshBuilder.buildHex(mesher, divisions, false, planet.radius, 0.2f), shader); } + public HexMesh(){ + } + @Override - public void preRender(){ + public void preRender(PlanetParams params){ + Shaders.planet.planet = planet; Shaders.planet.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation()).nor(); Shaders.planet.ambientColor.set(planet.solarSystem.lightColor); } diff --git a/core/src/mindustry/graphics/g3d/HexSkyMesh.java b/core/src/mindustry/graphics/g3d/HexSkyMesh.java new file mode 100644 index 0000000000..9cb08db46e --- /dev/null +++ b/core/src/mindustry/graphics/g3d/HexSkyMesh.java @@ -0,0 +1,60 @@ +package mindustry.graphics.g3d; + +import arc.graphics.*; +import arc.math.geom.*; +import arc.util.*; +import arc.util.noise.*; +import mindustry.graphics.*; +import mindustry.type.*; + +public class HexSkyMesh extends PlanetMesh{ + static Mat3D mat = new Mat3D(); + + public float speed = 0f; + + public HexSkyMesh(Planet planet, int seed, float speed, float radius, int divisions, Color color, int octaves, float persistence, float scl, float thresh){ + super(planet, MeshBuilder.buildHex(new HexMesher(){ + @Override + public float getHeight(Vec3 position){ + return 1f; + } + + @Override + public Color getColor(Vec3 position){ + return color; + } + + @Override + public boolean skip(Vec3 position){ + return Simplex.noise3d(planet.id + seed, octaves, persistence, scl, position.x, position.y * 3f, position.z) >= thresh; + } + }, divisions, false, planet.radius, radius), Shaders.clouds); + + this.speed = speed; + } + + public HexSkyMesh(){ + } + + public float relRot(){ + return Time.globalTime * speed / 40f; + } + + @Override + public void render(PlanetParams params, Mat3D projection, Mat3D transform){ + preRender(params); + shader.bind(); + shader.setUniformMatrix4("u_proj", projection.val); + shader.setUniformMatrix4("u_trans", mat.setToTranslation(planet.position).rotate(Vec3.Y, planet.getRotation() + relRot()).val); + shader.apply(); + mesh.render(shader, Gl.triangles); + } + + @Override + public void preRender(PlanetParams params){ + Shaders.clouds.planet = planet; + Shaders.clouds.lightDir.set(planet.solarSystem.position).sub(planet.position).rotate(Vec3.Y, planet.getRotation() + relRot()).nor(); + Shaders.clouds.ambientColor.set(planet.solarSystem.lightColor); + Shaders.clouds.alpha = 1f - params.uiAlpha; + } +} diff --git a/core/src/mindustry/graphics/g3d/MatMesh.java b/core/src/mindustry/graphics/g3d/MatMesh.java new file mode 100644 index 0000000000..5fd064dfda --- /dev/null +++ b/core/src/mindustry/graphics/g3d/MatMesh.java @@ -0,0 +1,22 @@ +package mindustry.graphics.g3d; + +import arc.math.geom.*; + +//TODO maybe this is a bad idea +/** A GenericMesh that wraps and applies an additional transform to a generic mesh. */ +public class MatMesh implements GenericMesh{ + private static final Mat3D tmp = new Mat3D(); + + GenericMesh mesh; + Mat3D mat; + + public MatMesh(GenericMesh mesh, Mat3D mat){ + this.mesh = mesh; + this.mat = mat; + } + + @Override + public void render(PlanetParams params, Mat3D projection, Mat3D transform){ + mesh.render(params, projection, tmp.set(transform).mul(mat)); + } +} diff --git a/core/src/mindustry/graphics/g3d/MultiMesh.java b/core/src/mindustry/graphics/g3d/MultiMesh.java new file mode 100644 index 0000000000..2512a5f172 --- /dev/null +++ b/core/src/mindustry/graphics/g3d/MultiMesh.java @@ -0,0 +1,18 @@ +package mindustry.graphics.g3d; + +import arc.math.geom.*; + +public class MultiMesh implements GenericMesh{ + GenericMesh[] meshes; + + public MultiMesh(GenericMesh... meshes){ + this.meshes = meshes; + } + + @Override + public void render(PlanetParams params, Mat3D projection, Mat3D transform){ + for(var v : meshes){ + v.render(params, projection, transform); + } + } +} diff --git a/core/src/mindustry/graphics/g3d/NoiseMesh.java b/core/src/mindustry/graphics/g3d/NoiseMesh.java new file mode 100644 index 0000000000..f6b8b7328e --- /dev/null +++ b/core/src/mindustry/graphics/g3d/NoiseMesh.java @@ -0,0 +1,43 @@ +package mindustry.graphics.g3d; + +import arc.graphics.*; +import arc.math.geom.*; +import arc.util.noise.*; +import mindustry.graphics.*; +import mindustry.type.*; + +public class NoiseMesh extends HexMesh{ + + public NoiseMesh(Planet planet, int seed, int divisions, Color color, float radius, int octaves, float persistence, float scale, float mag){ + this.planet = planet; + this.shader = Shaders.planet; + this.mesh = MeshBuilder.buildHex(new HexMesher(){ + @Override + public float getHeight(Vec3 position){ + return Simplex.noise3d(planet.id + seed, octaves, persistence, scale, 5f + position.x, 5f + position.y, 5f + position.z) * mag; + } + + @Override + public Color getColor(Vec3 position){ + return color; + } + }, divisions, false, radius, 0.2f); + } + + /** Two-color variant. */ + public NoiseMesh(Planet planet, int seed, int divisions, float radius, int octaves, float persistence, float scale, float mag, Color color1, Color color2, int coct, float cper, float cscl, float cthresh){ + this.planet = planet; + this.shader = Shaders.planet; + this.mesh = MeshBuilder.buildHex(new HexMesher(){ + @Override + public float getHeight(Vec3 position){ + return Simplex.noise3d(planet.id + seed, octaves, persistence, scale, 5f + position.x, 5f + position.y, 5f + position.z) * mag; + } + + @Override + public Color getColor(Vec3 position){ + return Simplex.noise3d(planet.id + seed + 1, coct, cper, cscl, 5f + position.x, 5f + position.y, 5f + position.z) > cthresh ? color2 : color1; + } + }, divisions, false, radius, 0.2f); + } +} diff --git a/core/src/mindustry/graphics/g3d/PlanetGrid.java b/core/src/mindustry/graphics/g3d/PlanetGrid.java index 9b72970087..993ca34c25 100644 --- a/core/src/mindustry/graphics/g3d/PlanetGrid.java +++ b/core/src/mindustry/graphics/g3d/PlanetGrid.java @@ -221,6 +221,8 @@ public class PlanetGrid{ } public static class Ptile{ + public static final Ptile empty = new Ptile(0, 0); + public int id; public int edgeCount; diff --git a/core/src/mindustry/graphics/g3d/PlanetMesh.java b/core/src/mindustry/graphics/g3d/PlanetMesh.java index 23e7966d33..0eaa18adbb 100644 --- a/core/src/mindustry/graphics/g3d/PlanetMesh.java +++ b/core/src/mindustry/graphics/g3d/PlanetMesh.java @@ -3,14 +3,13 @@ package mindustry.graphics.g3d; import arc.graphics.*; import arc.graphics.gl.*; import arc.math.geom.*; -import arc.util.*; import mindustry.type.*; /** Defines a mesh that is rendered for a planet. Subclasses provide a mesh and a shader. */ -public abstract class PlanetMesh implements Disposable{ - protected final Mesh mesh; - protected final Planet planet; - protected final Shader shader; +public abstract class PlanetMesh implements GenericMesh{ + protected Mesh mesh; + protected Planet planet; + protected Shader shader; public PlanetMesh(Planet planet, Mesh mesh, Shader shader){ this.planet = planet; @@ -18,20 +17,21 @@ public abstract class PlanetMesh implements Disposable{ this.shader = shader; } - /** Should be overridden to set up any shader parameters such as planet position, normals, etc. */ - public abstract void preRender(); + public PlanetMesh(){} - public void render(Mat3D projection, Mat3D transform){ - preRender(); + /** Should be overridden to set up any shader parameters such as planet position, normals, etc. + * @param params*/ + public void preRender(PlanetParams params){ + + } + + @Override + public void render(PlanetParams params, Mat3D projection, Mat3D transform){ + preRender(params); shader.bind(); shader.setUniformMatrix4("u_proj", projection.val); shader.setUniformMatrix4("u_trans", transform.val); shader.apply(); mesh.render(shader, Gl.triangles); } - - @Override - public void dispose(){ - mesh.dispose(); - } } diff --git a/core/src/mindustry/graphics/g3d/PlanetParams.java b/core/src/mindustry/graphics/g3d/PlanetParams.java new file mode 100644 index 0000000000..9116592fae --- /dev/null +++ b/core/src/mindustry/graphics/g3d/PlanetParams.java @@ -0,0 +1,40 @@ +package mindustry.graphics.g3d; + +import arc.math.geom.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.graphics.g3d.PlanetRenderer.*; +import mindustry.type.*; + +/** Parameters for rendering a solar system. */ +public class PlanetParams{ + /** Camera direction relative to the planet. Length is determined by zoom. */ + public Vec3 camPos = new Vec3(0f, 0f, 4f); + /** Camera up vector. */ + public Vec3 camUp = new Vec3(0f, 1f, 0f); + /** the unit length direction vector of the camera **/ + public Vec3 camDir = new Vec3(0, 0, -1); + /** The sun/main planet of the solar system from which everything is rendered. */ + public Planet solarSystem = Planets.sun; + /** Planet being looked at. */ + public Planet planet = Planets.serpulo; + /** Zoom relative to planet. */ + public float zoom = 1f; + /** Alpha of orbit rings and other UI elements. */ + public float uiAlpha = 1f; + /** If false, orbit and sector grid are not drawn. */ + public boolean drawUi = false; + /** If true, a space skybox is drawn. */ + public boolean drawSkybox = true; + + /** Handles drawing details. */ + public @Nullable transient PlanetInterfaceRenderer renderer; + /** Viewport size. <=0 to use screen size. Do not change in rules. */ + public transient int viewW = -1, viewH = -1; + /** If true, atmosphere will be drawn regardless of player options. */ + public transient boolean alwaysDrawAtmosphere = false; + + //TODO: + //- blur + //- darken +} diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index 2aef57b29a..dbdac3100b 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -9,7 +9,6 @@ import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; -import mindustry.content.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.graphics.g3d.PlanetGrid.*; @@ -25,25 +24,15 @@ public class PlanetRenderer implements Disposable{ private static final Seq points = new Seq<>(); - /** Camera direction relative to the planet. Length is determined by zoom. */ - public final Vec3 camPos = new Vec3(); - /** The sun/main planet of the solar system from which everything is rendered. */ - public final Planet solarSystem = Planets.sun; - /** Planet being looked at. */ - public Planet planet = Planets.serpulo; /** Camera used for rendering. */ - public Camera3D cam = new Camera3D(); + public final Camera3D cam = new Camera3D(); /** Raw vertex batch. */ public final VertexBatch3D batch = new VertexBatch3D(20000, false, true, 0); - public float zoom = 1f; - public float orbitAlpha = 1f; - private final Mesh[] outlines = new Mesh[10]; public final PlaneBatch3D projector = new PlaneBatch3D(); public final Mat3D mat = new Mat3D(); public final FrameBuffer buffer = new FrameBuffer(2, 2, true); - public PlanetInterfaceRenderer irenderer; public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{ setThreshold(0.8f); @@ -55,16 +44,13 @@ public class PlanetRenderer implements Disposable{ public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/")); public PlanetRenderer(){ - camPos.set(0, 0f, camLength); projector.setScaling(1f / 150f); cam.fov = 60f; cam.far = 150f; } /** Render the entire planet scene to the screen. */ - public void render(PlanetInterfaceRenderer irenderer){ - this.irenderer = irenderer; - + public void render(PlanetParams params){ Draw.flush(); Gl.clear(Gl.depthBufferBit); Gl.enable(Gl.depthTest); @@ -73,49 +59,63 @@ public class PlanetRenderer implements Disposable{ Gl.enable(Gl.cullFace); Gl.cullFace(Gl.back); + int w = params.viewW <= 0 ? Core.graphics.getWidth() : params.viewW; + int h = params.viewH <= 0 ? Core.graphics.getHeight() : params.viewH; + + bloom.blending = !params.drawSkybox; + //lock to up vector so it doesn't get confusing cam.up.set(Vec3.Y); - cam.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); - camPos.setLength(planet.radius * camLength + (zoom-1f) * planet.radius * 2); - cam.position.set(planet.position).add(camPos); - cam.lookAt(planet.position); + cam.resize(w, h); + params.camPos.setLength((params.planet.radius + params.planet.camRadius) * camLength + (params.zoom-1f) * (params.planet.radius + params.planet.camRadius) * 2); + cam.position.set(params.planet.position).add(params.camPos); + //cam.up.set(params.camUp); //TODO broken + cam.lookAt(params.planet.position); cam.update(); + //write back once it changes. + params.camUp.set(cam.up); + params.camDir.set(cam.direction); projector.proj(cam.combined); batch.proj(cam.combined); Events.fire(Trigger.universeDrawBegin); - beginBloom(); + //begin bloom + bloom.resize(w, h); + bloom.capture(); - //render skybox at 0,0,0 - Vec3 lastPos = Tmp.v31.set(cam.position); - cam.position.setZero(); - cam.update(); + if(params.drawSkybox){ + //render skybox at 0,0,0 + Vec3 lastPos = Tmp.v31.set(cam.position); + cam.position.setZero(); + cam.update(); - Gl.depthMask(false); + Gl.depthMask(false); - skybox.render(cam.combined); + skybox.render(cam.combined); - Gl.depthMask(true); + Gl.depthMask(true); - cam.position.set(lastPos); - cam.update(); + cam.position.set(lastPos); + cam.update(); + } Events.fire(Trigger.universeDraw); - renderPlanet(solarSystem); + renderPlanet(params.solarSystem, params); + renderTransparent(params.solarSystem, params); - renderTransparent(solarSystem); - - endBloom(); + bloom.render(); Events.fire(Trigger.universeDrawEnd); Gl.enable(Gl.blend); - irenderer.renderProjections(planet); + if(params.renderer != null){ + params.renderer.renderProjections(params.planet); + } Gl.disable(Gl.cullFace); Gl.disable(Gl.depthTest); @@ -123,68 +123,64 @@ public class PlanetRenderer implements Disposable{ cam.update(); } - public void beginBloom(){ - bloom.resize(Core.graphics.getWidth(), Core.graphics.getHeight()); - bloom.capture(); - } - - public void endBloom(){ - bloom.render(); - } - - - public void renderPlanet(Planet planet){ + public void renderPlanet(Planet planet, PlanetParams params){ if(!planet.visible()) return; cam.update(); if(cam.frustum.containsSphere(planet.position, planet.clipRadius)){ //render planet at offsetted position in the world - planet.draw(cam.combined, planet.getTransform(mat)); + planet.draw(params, cam.combined, planet.getTransform(mat)); } - renderOrbit(planet); - for(Planet child : planet.children){ - renderPlanet(child); + renderPlanet(child, params); } } - public void renderTransparent(Planet planet){ + public void renderTransparent(Planet planet, PlanetParams params){ if(!planet.visible()) return; - if(planet.hasGrid() && planet == this.planet){ - renderSectors(planet); + planet.drawClouds(params, cam.combined, planet.getTransform(mat)); + + if(planet.hasGrid() && planet == params.planet && params.drawUi){ + renderSectors(planet, params); } - if(cam.frustum.containsSphere(planet.position, planet.clipRadius) && planet.parent != null && planet.hasAtmosphere && Core.settings.getBool("atmosphere")){ + if(cam.frustum.containsSphere(planet.position, planet.clipRadius) && planet.parent != null && planet.hasAtmosphere && (params.alwaysDrawAtmosphere || Core.settings.getBool("atmosphere"))){ planet.drawAtmosphere(atmosphere, cam); } - planet.drawClouds(cam.combined, planet.getTransform(mat)); - for(Planet child : planet.children){ - renderTransparent(child); + renderTransparent(child, params); + } + + batch.proj(cam.combined); + + if(params.drawUi){ + renderOrbit(planet, params); } } - public void renderOrbit(Planet planet){ - if(planet.parent == null || !planet.visible() || orbitAlpha <= 0.02f) return; + public void renderOrbit(Planet planet, PlanetParams params){ + if(planet.parent == null || !planet.visible() || params.uiAlpha <= 0.02f || !planet.drawOrbit) return; Vec3 center = planet.parent.position; float radius = planet.orbitRadius; int points = (int)(radius * 10); - Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray.write(Tmp.c1).a(orbitAlpha))); + Angles.circleVectors(points, radius, (cx, cy) -> batch.vertex(Tmp.v32.set(center).add(cx, 0, cy), Pal.gray.write(Tmp.c1).a(params.uiAlpha))); batch.flush(Gl.lineLoop); } - public void renderSectors(Planet planet){ - if(orbitAlpha <= 0.02f) return; + public void renderSectors(Planet planet, PlanetParams params){ + if(params.uiAlpha <= 0.02f) return; //apply transformed position batch.proj().mul(planet.getTransform(mat)); - irenderer.renderSectors(planet); + if(params.renderer != null){ + params.renderer.renderSectors(planet); + } //render sector grid Mesh mesh = outline(planet.grid.size); @@ -262,12 +258,12 @@ public class PlanetRenderer implements Disposable{ } public void setPlane(Sector sector){ - float rotation = -planet.getRotation(); + float rotation = -sector.planet.getRotation(); float length = 0.01f; projector.setPlane( //origin on sector position - Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(planet.position), + Tmp.v33.set(sector.tile.v).setLength(outlineRad + length).rotate(Vec3.Y, rotation).add(sector.planet.position), //face up sector.plane.project(Tmp.v32.set(sector.tile.v).add(Vec3.Y)).sub(sector.tile.v).rotate(Vec3.Y, rotation).nor(), //right vector diff --git a/core/src/mindustry/graphics/g3d/ShaderSphereMesh.java b/core/src/mindustry/graphics/g3d/ShaderSphereMesh.java index e70dd07c29..b7529229f6 100644 --- a/core/src/mindustry/graphics/g3d/ShaderSphereMesh.java +++ b/core/src/mindustry/graphics/g3d/ShaderSphereMesh.java @@ -8,9 +8,4 @@ public class ShaderSphereMesh extends PlanetMesh{ public ShaderSphereMesh(Planet planet, Shader shader, int divisions){ super(planet, MeshBuilder.buildIcosphere(divisions, planet.radius), shader); } - - @Override - public void preRender(){ - - } } diff --git a/core/src/mindustry/graphics/g3d/SunMesh.java b/core/src/mindustry/graphics/g3d/SunMesh.java index 6b00aa3885..b858303e39 100644 --- a/core/src/mindustry/graphics/g3d/SunMesh.java +++ b/core/src/mindustry/graphics/g3d/SunMesh.java @@ -25,9 +25,4 @@ public class SunMesh extends HexMesh{ } }, divisions, Shaders.unlit); } - - @Override - public void preRender(){ - //do absolutely nothing - } } diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java index 3e6beb26e8..e92f59bdb1 100644 --- a/core/src/mindustry/io/JsonIO.java +++ b/core/src/mindustry/io/JsonIO.java @@ -163,6 +163,19 @@ public class JsonIO{ } }); + json.setSerializer(Planet.class, new Serializer<>(){ + @Override + public void write(Json json, Planet object, Class knownType){ + json.writeValue(object.name); + } + + @Override + public Planet read(Json json, JsonValue jsonData, Class type){ + Planet block = Vars.content.getByName(ContentType.planet, jsonData.asString()); + return block == null ? Planets.serpulo : block; + } + }); + json.setSerializer(Weather.class, new Serializer<>(){ @Override public void write(Json json, Weather object, Class knownType){ diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index 0ea4f3af9d..37f07b3e86 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -56,7 +56,10 @@ public abstract class SaveFileReader{ "water", "shallow-water", "slag", "molten-slag", - "cryofluidmixer", "cryofluid-mixer" + "cryofluidmixer", "cryofluid-mixer", + "block-forge", "constructor", + "block-unloader", "payload-unloader", + "block-loader", "payload-loader" ); public static final ObjectMap modContentNameMap = ObjectMap.of( diff --git a/core/src/mindustry/maps/generators/PlanetGenerator.java b/core/src/mindustry/maps/generators/PlanetGenerator.java index 3533943b19..806c04d70c 100644 --- a/core/src/mindustry/maps/generators/PlanetGenerator.java +++ b/core/src/mindustry/maps/generators/PlanetGenerator.java @@ -123,6 +123,11 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe return 3200; } + public int getSectorSize(Sector sector){ + int res = (int)(sector.rect.radius * getSizeScl()); + return res % 2 == 0 ? res : res + 1; + } + public void generate(Tiles tiles, Sector sec){ this.tiles = tiles; this.sector = sec; diff --git a/core/src/mindustry/mod/ClassMap.java b/core/src/mindustry/mod/ClassMap.java index 7599ca0713..54b5891ab1 100644 --- a/core/src/mindustry/mod/ClassMap.java +++ b/core/src/mindustry/mod/ClassMap.java @@ -218,14 +218,8 @@ public class ClassMap{ classes.put("SwitchBuild", mindustry.world.blocks.logic.SwitchBlock.SwitchBuild.class); classes.put("BallisticSilo", mindustry.world.blocks.payloads.BallisticSilo.class); classes.put("BallisticSiloBuild", mindustry.world.blocks.payloads.BallisticSilo.BallisticSiloBuild.class); - classes.put("BlockForge", mindustry.world.blocks.payloads.BlockForge.class); - classes.put("BlockForgeBuild", mindustry.world.blocks.payloads.BlockForge.BlockForgeBuild.class); - classes.put("BlockLoader", mindustry.world.blocks.payloads.BlockLoader.class); - classes.put("BlockLoaderBuild", mindustry.world.blocks.payloads.BlockLoader.BlockLoaderBuild.class); classes.put("BlockProducer", mindustry.world.blocks.payloads.BlockProducer.class); classes.put("BlockProducerBuild", mindustry.world.blocks.payloads.BlockProducer.BlockProducerBuild.class); - classes.put("BlockUnloader", mindustry.world.blocks.payloads.BlockUnloader.class); - classes.put("BlockUnloaderBuild", mindustry.world.blocks.payloads.BlockUnloader.BlockUnloaderBuild.class); classes.put("BuildPayload", mindustry.world.blocks.payloads.BuildPayload.class); classes.put("NuclearWarhead", mindustry.world.blocks.payloads.NuclearWarhead.class); classes.put("NuclearWarheadBuild", mindustry.world.blocks.payloads.NuclearWarhead.NuclearWarheadBuild.class); diff --git a/core/src/mindustry/type/ItemSeq.java b/core/src/mindustry/type/ItemSeq.java index a02f29bdb6..61bcc37e3a 100644 --- a/core/src/mindustry/type/ItemSeq.java +++ b/core/src/mindustry/type/ItemSeq.java @@ -55,6 +55,21 @@ public class ItemSeq implements Iterable, JsonSerializable{ return out; } + public ItemStack[] toArray(){ + int count = 0; + for(int value : values){ + if(value != 0) count++; + } + ItemStack[] result = new ItemStack[count]; + int index = 0; + for(int i = 0; i < values.length; i++){ + if(values[i] != 0){ + result[index ++] = new ItemStack(Vars.content.item(i), values[i]); + } + } + return result; + } + public void min(int number){ for(Item item : Vars.content.items()){ set(item, Math.min(get(item), number)); @@ -90,6 +105,12 @@ public class ItemSeq implements Iterable, JsonSerializable{ itemModule.each(this::add); } + public void add(ItemStack[] stacks){ + for(var s : stacks){ + add(s); + } + } + public void add(ItemSeq seq){ seq.each(this::add); } diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java index ac7c2761de..adfc406768 100644 --- a/core/src/mindustry/type/Planet.java +++ b/core/src/mindustry/type/Planet.java @@ -18,14 +18,12 @@ import mindustry.maps.generators.*; import static mindustry.Vars.*; public class Planet extends UnlockableContent{ - /** Default spacing between planet orbits in world units. */ - private static final float orbitSpacing = 11f; /** intersect() temp var. */ private static final Vec3 intersectResult = new Vec3(); /** Mesh used for rendering. Created on load() - will be null on the server! */ - public @Nullable PlanetMesh mesh; + public @Nullable GenericMesh mesh; /** Mesh used for rendering planet clouds. Null if no clouds are present. */ - public @Nullable PlanetMesh cloudMesh; + public @Nullable GenericMesh cloudMesh; /** Position in global coordinates. Will be 0,0,0 until the Universe updates it. */ public Vec3 position = new Vec3(); /** Grid used for the sectors on the planet. Null if this planet can't be landed on. */ @@ -33,9 +31,17 @@ public class Planet extends UnlockableContent{ /** Generator that will make the planet. Can be null for planets that don't need to be landed on. */ public @Nullable PlanetGenerator generator; /** Array of sectors; directly maps to tiles in the grid. */ - public Seq sectors; + public Seq sectors = new Seq<>(); + /** Default spacing between planet orbits in world units. This is defined per-parent! */ + public float orbitSpacing = 12f; /** Radius of this planet's sphere. Does not take into account satellites. */ public float radius; + /** Camera radius offset. */ + public float camRadius; + /** Minimum camera zoom value. */ + public float minZoom = 0.5f; + /** Whether to draw the orbital circle. */ + public boolean drawOrbit = true; /** Atmosphere radius adjustment parameters. */ public float atmosphereRadIn = 0, atmosphereRadOut = 0.3f; /** Frustrum sphere clip radius. */ @@ -48,12 +54,18 @@ public class Planet extends UnlockableContent{ public float orbitTime; /** Time for the planet to perform a full revolution, in seconds. One day. */ public float rotateTime = 24f * 60f; + /** Random orbit angle offset to prevent planets from starting out in a line. */ + public float orbitOffset; /** Approx. radius of one sector. */ public float sectorApproxRadius; /** Whether this planet is tidally locked relative to its parent - see https://en.wikipedia.org/wiki/Tidal_locking */ public boolean tidalLock = false; /** Whether this planet is listed in the planet access UI. **/ public boolean accessible = true; + /** If true, a day/night cycle is simulated. */ + public boolean updateLighting = true; + /** Day/night cycle parameters. */ + public float lightSrcFrom = 0f, lightSrcTo = 0.8f, lightDstFrom = 0.2f, lightDstTo = 1f; /** The default starting sector displayed to the map dialog. */ public int startSector = 0; /** Whether the bloom render effect is enabled. */ @@ -77,32 +89,20 @@ public class Planet extends UnlockableContent{ /** Satellites orbiting this planet. */ public Seq satellites = new Seq<>(); /** Loads the mesh. Clientside only. Defaults to a boring sphere mesh. */ - protected Prov meshLoader = () -> new ShaderSphereMesh(this, Shaders.unlit, 2), cloudMeshLoader = () -> null; + protected Prov meshLoader = () -> new ShaderSphereMesh(this, Shaders.unlit, 2), cloudMeshLoader = () -> null; - public Planet(String name, Planet parent, int sectorSize, float radius){ + public Planet(String name, Planet parent, float radius){ super(name); this.radius = radius; this.parent = parent; - - if(sectorSize > 0){ - grid = PlanetGrid.create(sectorSize); - - sectors = new Seq<>(grid.tiles.length); - for(int i = 0; i < grid.tiles.length; i++){ - sectors.add(new Sector(this, grid.tiles[i])); - } - - sectorApproxRadius = sectors.first().tile.v.dst(sectors.first().tile.corners[0].v); - }else{ - sectors = new Seq<>(); - } + this.orbitOffset = Mathf.randomSeed(id, 360); //total radius is initially just the radius - totalRadius += radius; + totalRadius = radius; //get orbit radius by extending past the parent's total radius - orbitRadius = parent == null ? 0f : (parent.totalRadius + orbitSpacing + totalRadius); + orbitRadius = parent == null ? 0f : (parent.totalRadius + parent.orbitSpacing + totalRadius); //orbit time is based on radius [kepler's third law] orbitTime = Mathf.pow(orbitRadius, 1.5f) * 1000; @@ -117,6 +117,21 @@ public class Planet extends UnlockableContent{ for(solarSystem = this; solarSystem.parent != null; solarSystem = solarSystem.parent); } + public Planet(String name, Planet parent, float radius, int sectorSize){ + this(name, parent, radius); + + if(sectorSize > 0){ + grid = PlanetGrid.create(sectorSize); + + sectors.ensureCapacity(grid.tiles.length); + for(int i = 0; i < grid.tiles.length; i++){ + sectors.add(new Sector(this, grid.tiles[i])); + } + + sectorApproxRadius = sectors.first().tile.v.dst(sectors.first().tile.corners[0].v); + } + } + public @Nullable Sector getLastSector(){ if(sectors.isEmpty()){ return null; @@ -137,6 +152,11 @@ public class Planet extends UnlockableContent{ return grid != null && generator != null && sectors.size > 0; } + /** @return whether this planet has any sectors to land on. */ + public boolean isLandable(){ + return sectors.size > 0; + } + public void updateTotalRadius(){ totalRadius = radius; for(Planet planet : children){ @@ -151,9 +171,7 @@ public class Planet extends UnlockableContent{ /** Calculates orbital rotation based on universe time.*/ public float getOrbitAngle(){ - //applies random offset to prevent planets from starting out in a line - float offset = Mathf.randomSeed(id, 360); - return (offset + universe.secondsf() / (orbitTime / 360f)) % 360f; + return (orbitOffset + universe.secondsf() / (orbitTime / 360f)) % 360f; } /** Calulates rotation on own axis based on universe time.*/ @@ -212,9 +230,6 @@ public class Planet extends UnlockableContent{ /** Regenerates the planet mesh. For debugging only. */ public void reloadMesh(){ - if(mesh != null){ - mesh.dispose(); - } mesh = meshLoader.get(); } @@ -246,14 +261,6 @@ public class Planet extends UnlockableContent{ clipRadius = Math.max(clipRadius, radius + atmosphereRadOut + 0.5f); } - @Override - public void dispose(){ - if(mesh != null){ - mesh.dispose(); - mesh = null; - } - } - /** Gets a sector a tile position. */ public Sector getSector(Ptile tile){ return sectors.get(tile.id); @@ -294,8 +301,8 @@ public class Planet extends UnlockableContent{ return visible; } - public void draw(Mat3D projection, Mat3D transform){ - mesh.render(projection, transform); + public void draw(PlanetParams params, Mat3D projection, Mat3D transform){ + mesh.render(params, projection, transform); } public void drawAtmosphere(Mesh atmosphere, Camera3D cam){ @@ -316,9 +323,9 @@ public class Planet extends UnlockableContent{ Gl.depthMask(true); } - public void drawClouds(Mat3D projection, Mat3D transform){ + public void drawClouds(PlanetParams params, Mat3D projection, Mat3D transform){ if(cloudMesh != null){ - cloudMesh.render(projection, transform); + cloudMesh.render(params, projection, transform); } } } diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index 39f31e75ae..0637ed8c2b 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -40,7 +40,12 @@ public class Sector{ this.planet = planet; this.tile = tile; this.plane = new Plane(); - this.rect = makeRect(); + //empty sector tile needs a special rect + if(tile.corners.length == 0){ + rect = new SectorRect(1f, Vec3.Zero.cpy(), Vec3.Y.cpy(), Vec3.X.cpy(), 0f); + }else{ + this.rect = makeRect(); + } this.id = tile.id; } @@ -156,9 +161,7 @@ public class Sector{ /** @return the sector size, in tiles */ public int getSize(){ - if(planet.generator == null) return 1; - int res = (int)(rect.radius * planet.generator.getSizeScl()); - return res % 2 == 0 ? res : res + 1; + return planet.generator == null ? 1 : planet.generator.getSectorSize(this); } public void removeItems(ItemSeq items){ diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 895fcc1f15..d934824d3b 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -71,9 +71,13 @@ public class UnitType extends UnlockableContent{ public int commandLimit = 8; public float commandRadius = 150f; public float visualElevation = -1f; + /** If true and this is a legged unit, this unit can walk over blocks. */ public boolean allowLegStep = false; + /** If true, this unit cannot drown, and will not be affected by the floor under it. */ public boolean hovering = false; public boolean omniMovement = true; + public boolean showHeal = true; + public Color healColor = Pal.heal; public Effect fallEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke; public Effect deathExplosionEffect = Fx.dynamicExplosion; @@ -112,13 +116,14 @@ public class UnitType extends UnlockableContent{ public float dpsEstimate = -1; public float clipSize = -1; public boolean canDrown = true, naval = false; + public float drownTimeMultiplier = 1f; public float engineOffset = 5f, engineSize = 2.5f; public float strafePenalty = 0.5f; public float hitSize = 6f; public float itemOffsetY = 3f; public float lightRadius = -1f, lightOpacity = 0.6f; public Color lightColor = Pal.powerLight; - public boolean drawCell = true, drawItems = true, drawShields = true; + public boolean drawCell = true, drawItems = true, drawShields = true, drawBody = true; public int trailLength = 3; public float trailX = 4f, trailY = -3f, trailScl = 1f; /** Whether the unit can heal blocks. Initialized in init() */ @@ -135,7 +140,9 @@ public class UnitType extends UnlockableContent{ softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion; public TextureRegion[] wreckRegions; + protected float buildTime = -1f; protected @Nullable ItemStack[] cachedRequirements; + protected @Nullable ItemStack[] totalRequirements; public UnitType(String name){ super(name); @@ -312,6 +319,8 @@ public class UnitType extends UnlockableContent{ Unit example = constructor.get(); + allowLegStep = example instanceof Legsc; + //water preset if(example instanceof WaterMovec){ naval = true; @@ -323,6 +332,10 @@ public class UnitType extends UnlockableContent{ } } + if(flying){ + envEnabled |= Env.space; + } + if(lightRadius == -1){ lightRadius = Math.max(60f, hitSize * 2.3f); } @@ -475,25 +488,72 @@ public class UnitType extends UnlockableContent{ } } + /** @return the time required to build this unit, as a value that takes into account reconstructors */ + public float getBuildTime(){ + getTotalRequirements(); + return buildTime; + } + + /** @return all items needed to build this unit, including reconstructor steps. */ + public ItemStack[] getTotalRequirements(){ + if(totalRequirements == null){ + UnitType[] ret = {null}; + float[] timeret = {0f}; + ItemStack[] result = getRequirements(ret, timeret); + + //prevents stack overflow if requirements are circular and result != null + totalRequirements = ItemStack.empty; + + if(result != null){ + ItemSeq total = new ItemSeq(); + + total.add(result); + if(ret[0] != null){ + total.add(ret[0].getTotalRequirements()); + } + totalRequirements = total.toArray(); + } + + for(var stack : totalRequirements){ + buildTime += stack.item.cost * stack.amount; + } + } + return totalRequirements; + } + + /** @return item requirements based on reconstructors or factories found; returns previous unit in array if provided */ + public @Nullable ItemStack[] getRequirements(@Nullable UnitType[] prevReturn, @Nullable float[] timeReturn){ + var rec = (Reconstructor)content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this)); + + if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){ + if(prevReturn != null){ + prevReturn[0] = rec.upgrades.find(u -> u[1] == this)[0]; + } + if(timeReturn != null){ + timeReturn[0] = rec.constructTime; + } + return ci.items; + }else{ + var factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this)); + if(factory != null){ + + var plan = factory.plans.find(p -> p.unit == this); + if(timeReturn != null){ + timeReturn[0] = plan.time; + } + return plan.requirements; + } + } + return null; + } + @Override public ItemStack[] researchRequirements(){ if(cachedRequirements != null){ return cachedRequirements; } - ItemStack[] stacks = null; - - //calculate costs based on reconstructors or factories found - Block rec = content.blocks().find(b -> b instanceof Reconstructor re && re.upgrades.contains(u -> u[1] == this)); - - if(rec != null && rec.consumes.has(ConsumeType.item) && rec.consumes.get(ConsumeType.item) instanceof ConsumeItems ci){ - stacks = ci.items; - }else{ - UnitFactory factory = (UnitFactory)content.blocks().find(u -> u instanceof UnitFactory uf && uf.plans.contains(p -> p.unit == this)); - if(factory != null){ - stacks = factory.plans.find(p -> p.unit == this).requirements; - } - } + ItemStack[] stacks = getRequirements(null, null); if(stacks != null){ ItemStack[] out = new ItemStack[stacks.length]; @@ -557,10 +617,10 @@ public class UnitType extends UnlockableContent{ Draw.z(z); - drawOutline(unit); + if(drawBody) drawOutline(unit); drawWeaponOutlines(unit); if(engineSize > 0) drawEngine(unit); - drawBody(unit); + if(drawBody) drawBody(unit); if(drawCell) drawCell(unit); drawWeapons(unit); if(drawItems) drawItems(unit); @@ -623,14 +683,25 @@ public class UnitType extends UnlockableContent{ } public void drawShadow(Unit unit){ - Draw.color(Pal.shadow); - float e = Math.max(unit.elevation, visualElevation); + float e = Math.max(unit.elevation, visualElevation) * (1f - unit.drownTime); + float x = unit.x + shadowTX * e, y = unit.y + shadowTY * e; + Floor floor = world.floorWorld(x, y); + + float dest = floor.canShadow ? 1f : 0f; + //yes, this updates state in draw()... which isn't a problem, because I don't want it to be obvious anyway + unit.shadowAlpha = unit.shadowAlpha < 0 ? dest : Mathf.approachDelta(unit.shadowAlpha, dest, 0.11f); + Draw.color(Pal.shadow, Pal.shadow.a * unit.shadowAlpha); + Draw.rect(shadowRegion, unit.x + shadowTX * e, unit.y + shadowTY * e, unit.rotation - 90); Draw.color(); } public void drawSoftShadow(Unit unit){ - Draw.color(0, 0, 0, 0.4f); + drawSoftShadow(unit, 1f); + } + + public void drawSoftShadow(Unit unit, float alpha){ + Draw.color(0, 0, 0, 0.4f * alpha); float rad = 1.6f; float size = Math.max(region.width, region.height) * Draw.scl; Draw.rect(softShadowRegion, unit, size * rad * Draw.xscl, size * rad * Draw.yscl, unit.rotation - 90); @@ -719,16 +790,11 @@ public class UnitType extends UnlockableContent{ Draw.reset(); } - public void applyOutlineColor(Unit unit){ - if(unit.isBoss()){ - Draw.mixcol(unit.team.color, Mathf.absin(7f, 1f)); - } - } - public void drawOutline(Unit unit){ Draw.reset(); if(Core.atlas.isFound(outlineRegion)){ + applyColor(unit); applyOutlineColor(unit); Draw.rect(outlineRegion, unit.x, unit.y, unit.rotation - 90); Draw.reset(); @@ -764,14 +830,16 @@ public class UnitType extends UnlockableContent{ public void drawLegs(T unit){ applyColor(unit); + Tmp.c3.set(Draw.getMixColor()); Leg[] legs = unit.legs(); float ssize = footRegion.width * Draw.scl * 1.5f; float rotation = unit.baseRotation(); + float invDrown = 1f - unit.drownTime; for(Leg leg : legs){ - Drawf.shadow(leg.base.x, leg.base.y, ssize); + Drawf.shadow(leg.base.x, leg.base.y, ssize, invDrown); } //legs are drawn front first @@ -787,13 +855,15 @@ public class UnitType extends UnlockableContent{ Tmp.v1.set(leg.base).sub(leg.joint).inv().setLength(legExtension); if(leg.moving && visualElevation > 0){ - float scl = visualElevation; + float scl = visualElevation * invDrown; float elev = Mathf.slope(1f - leg.stage) * scl; Draw.color(Pal.shadow); Draw.rect(footRegion, leg.base.x + shadowTX * elev, leg.base.y + shadowTY * elev, position.angleTo(leg.base)); Draw.color(); } + Draw.mixcol(Tmp.c3, Tmp.c3.a); + Draw.rect(footRegion, leg.base.x, leg.base.y, position.angleTo(leg.base)); Lines.stroke(legRegion.height * Draw.scl * flips); @@ -848,8 +918,8 @@ public class UnitType extends UnlockableContent{ Draw.mixcol(Color.white, unit.hitTime); - if(floor.isLiquid){ - Draw.color(Color.white, floor.mapColor, unit.drownTime() * 0.4f); + if(unit.lastDrownFloor != null){ + Draw.color(Color.white, Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.83f), unit.drownTime * 0.9f); }else{ Draw.color(Color.white); } @@ -859,13 +929,25 @@ public class UnitType extends UnlockableContent{ Draw.mixcol(); } + public void applyOutlineColor(Unit unit){ + if(unit.isBoss()){ + Draw.mixcol(unit.team.color, Mathf.absin(7f, 1f)); + } + + if(unit.drownTime > 0 && unit.lastDrownFloor != null){ + Draw.color(Color.white, Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.8f), unit.drownTime * 0.9f); + } + } + public void applyColor(Unit unit){ Draw.color(); - Tmp.c1.set(Color.white).lerp(Pal.heal, Mathf.clamp(unit.healTime - unit.hitTime)); + if(showHeal){ + Tmp.c1.set(Color.white).lerp(healColor, Mathf.clamp(unit.healTime - unit.hitTime)); + } Draw.mixcol(Tmp.c1, Math.max(unit.hitTime, Mathf.clamp(unit.healTime))); - if(unit.drownTime > 0 && unit.floorOn().isDeep()){ - Draw.mixcol(unit.floorOn().mapColor, unit.drownTime * 0.8f); + if(unit.drownTime > 0 && unit.lastDrownFloor != null){ + Draw.mixcol(Tmp.c1.set(unit.lastDrownFloor.mapColor).mul(0.83f), unit.drownTime * 0.9f); } } diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index db3c924825..dc83c9282f 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -26,7 +26,7 @@ public class Weapon implements Cloneable{ static int sequenceNum = 0; /** displayed weapon region */ - public String name = ""; + public String name; /** bullet shot */ public BulletType bullet = Bullets.standardCopper; /** shell ejection effect */ diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java index 0f62e423a4..93790fbeee 100644 --- a/core/src/mindustry/type/Weather.java +++ b/core/src/mindustry/type/Weather.java @@ -148,6 +148,8 @@ public class Weather extends UnlockableContent{ Draw.rect(region, x, y, size, size, rotation); } } + + Draw.reset(); } public static void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){ diff --git a/core/src/mindustry/ui/Menus.java b/core/src/mindustry/ui/Menus.java index 511bd7b55b..016b3416c0 100644 --- a/core/src/mindustry/ui/Menus.java +++ b/core/src/mindustry/ui/Menus.java @@ -11,11 +11,12 @@ import static mindustry.Vars.*; /** Class for handling menus and notifications across the network. Unstable API! */ public class Menus{ - private static IntMap menuListeners = new IntMap<>(); + private static final Seq menuListeners = new Seq<>(); /** Register a *global* menu listener. If no option is chosen, the option is returned as -1. */ - public static void registerMenu(int id, MenuListener listener){ - menuListeners.put(id, listener); + public static int registerMenu(MenuListener listener){ + menuListeners.add(listener); + return menuListeners.size - 1; } //do not invoke any of the methods below directly, use Call @@ -30,7 +31,7 @@ public class Menus{ @Remote(targets = Loc.both, called = Loc.both) public static void menuChoose(@Nullable Player player, int menuId, int option){ - if(player != null && menuListeners.containsKey(menuId)){ + if(player != null && menuId >= 0 && menuId < menuListeners.size){ Events.fire(new MenuOptionChooseEvent(player, menuId, option)); menuListeners.get(menuId).get(player, option); } diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index a859620f61..501804f32e 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -512,7 +512,7 @@ public class JoinDialog extends BaseDialog{ void safeConnect(String ip, int port, int version){ if(version != Version.build && Version.build != -1 && version != -1){ - ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" + + ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated) + "\n[]" + Core.bundle.format("server.versions", Version.build, version)); }else{ connect(ip, port); diff --git a/core/src/mindustry/ui/dialogs/MapPlayDialog.java b/core/src/mindustry/ui/dialogs/MapPlayDialog.java index 004c990f00..730762932c 100644 --- a/core/src/mindustry/ui/dialogs/MapPlayDialog.java +++ b/core/src/mindustry/ui/dialogs/MapPlayDialog.java @@ -97,7 +97,7 @@ public class MapPlayDialog extends BaseDialog{ table.row(); for(Gamemode mode : Gamemode.values()){ if(mode.hidden) continue; - table.labelWrap("[accent]" + mode.toString() + ":[] [lightgray]" + mode.description()).width(400f); + table.labelWrap("[accent]" + mode + ":[] [lightgray]" + mode.description()).width(400f); table.row(); } diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 0ddd26830d..eeab52ae59 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -15,6 +15,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; +import mindustry.*; import mindustry.content.*; import mindustry.content.TechTree.*; import mindustry.core.*; @@ -24,6 +25,7 @@ import mindustry.game.SectorInfo.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; +import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.graphics.g3d.*; import mindustry.input.*; import mindustry.maps.*; @@ -49,10 +51,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ public static float sectorShowDuration = 60f * 2.4f; public final FrameBuffer buffer = new FrameBuffer(2, 2, true); - public final PlanetRenderer planets = renderer.planets; public final LaunchLoadoutDialog loadouts = new LaunchLoadoutDialog(); + public final PlanetRenderer planets = renderer.planets; - public float zoom = 1f, selectAlpha = 1f; + public PlanetParams state = new PlanetParams(); + public float zoom = 1f; public @Nullable Sector selected, hovered, launchSector; public Mode mode = look; public boolean launching; @@ -68,10 +71,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ public PlanetDialog(){ super("", Styles.fullDialog); + + state.renderer = this; + state.drawUi = true; shouldPause = true; - planets.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo")); - if(planets.planet == null) planets.planet = Planets.serpulo; + state.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo")); + if(state.planet == null) state.planet = Planets.serpulo; addListener(new InputListener(){ @Override @@ -107,7 +113,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ newPresets.clear(); } - Vec3 pos = planets.camPos; + Vec3 pos = state.camPos; float upV = pos.angle(Vec3.Y); float xscale = 9f, yscale = 10f; @@ -116,20 +122,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //scale X speed depending on polar coordinate float speed = 1f - Math.abs(upV - 90) / 90f; - pos.rotate(planets.cam.up, cx / xscale * speed); + pos.rotate(state.camUp, cx / xscale * speed); //prevent user from scrolling all the way up and glitching it out float amount = cy / yscale; amount = Mathf.clamp(upV + amount, margin, 180f - margin) - upV; - pos.rotate(Tmp.v31.set(planets.cam.up).rotate(planets.cam.direction, 90), amount); + pos.rotate(Tmp.v31.set(state.camUp).rotate(state.camDir, 90), amount); }); addListener(new InputListener(){ @Override public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){ if(event.targetActor == PlanetDialog.this){ - zoom = Mathf.clamp(zoom + amountY / 10f, 0.5f, 2f); + zoom = Mathf.clamp(zoom + amountY / 10f, state.planet.minZoom, 2f); } return true; } @@ -144,7 +150,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ lastZoom = zoom; } - zoom = (Mathf.clamp(initialDistance / distance * lastZoom, 0.5f, 2f)); + zoom = (Mathf.clamp(initialDistance / distance * lastZoom, state.planet.minZoom, 2f)); } @Override @@ -170,9 +176,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ launching = false; zoom = 1f; - planets.zoom = 1f; - selectAlpha = 0f; - launchSector = state.getSector(); + state.zoom = 1f; + state.uiAlpha = 0f; + launchSector = Vars.state.getSector(); presetShow = 0f; showed = false; listener = s -> {}; @@ -181,7 +187,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //announce new presets for(SectorPreset preset : content.sectors()){ - if(preset.unlocked() && !preset.alwaysUnlocked && !preset.sector.info.shown && !preset.sector.hasBase() && preset.planet == planets.planet){ + if(preset.unlocked() && !preset.alwaysUnlocked && !preset.sector.info.shown && !preset.sector.hasBase() && preset.planet == state.planet){ newPresets.add(preset.sector); preset.sector.info.shown = true; preset.sector.saveInfo(); @@ -189,14 +195,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } if(newPresets.any()){ - newPresets.add(planets.planet.getLastSector()); + newPresets.add(state.planet.getLastSector()); } newPresets.reverse(); updateSelected(); - if(planets.planet.getLastSector() != null){ - lookAt(planets.planet.getLastSector()); + if(state.planet.getLastSector() != null){ + lookAt(state.planet.getLastSector()); } return super.show(); @@ -252,8 +258,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //update view to sector zoom = 1f; - planets.zoom = 1f; - selectAlpha = 0f; + state.zoom = 1f; + state.uiAlpha = 0f; mode = planetLaunch; @@ -269,8 +275,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //update view to sector lookAt(sector); zoom = 1f; - planets.zoom = 1f; - selectAlpha = 0f; + state.zoom = 1f; + state.uiAlpha = 0f; launchSector = sector; mode = select; @@ -279,7 +285,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } void lookAt(Sector sector){ - planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation())); + if(sector.tile == Ptile.empty) return; + + state.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation())); } boolean canSelect(Sector sector){ @@ -307,7 +315,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ launchFrom = to.near().find(Sector::hasBase); if(launchFrom == null && to.preset != null){ if(launchSector != null) return launchSector; - launchFrom = planets.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v)); + launchFrom = state.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v)); if(!launchFrom.hasBase()) launchFrom = null; } } @@ -323,7 +331,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ public void renderSectors(Planet planet){ //draw all sector stuff - if(selectAlpha > 0.01f){ + if(state.uiAlpha > 0.01f){ for(Sector sec : planet.sectors){ if(canSelect(sec) || sec.unlocked() || debugSelect){ @@ -336,15 +344,15 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ null; if(color != null){ - planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(selectAlpha), 0.026f, -0.001f); + planets.drawSelection(sec, Tmp.c1.set(color).mul(0.8f).a(state.uiAlpha), 0.026f, -0.001f); } }else{ - planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, selectAlpha), -0.001f); + planets.fill(sec, Tmp.c1.set(shadowColor).mul(1, 1, 1, state.uiAlpha), -0.001f); } } } - Sector current = state.getSector() != null && state.getSector().isBeingPlayed() && state.getSector().planet == planets.planet ? state.getSector() : null; + Sector current = Vars.state.getSector() != null && Vars.state.getSector().isBeingPlayed() && Vars.state.getSector().planet == state.planet ? Vars.state.getSector() : null; if(current != null){ planets.fill(current, hoverColor, -0.001f); @@ -371,12 +379,12 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } } - if(selectAlpha > 0.001f){ + if(state.uiAlpha > 0.001f){ for(Sector sec : planet.sectors){ if(sec.hasBase()){ for(Sector enemy : sec.near()){ if(enemy.hasEnemyBase()){ - planets.drawArc(planet, enemy.tile.v, sec.tile.v, Team.crux.color.write(Tmp.c2).a(selectAlpha), Color.clear, 0.24f, 110f, 25); + planets.drawArc(planet, enemy.tile.v, sec.tile.v, Team.crux.color.write(Tmp.c2).a(state.uiAlpha), Color.clear, 0.24f, 110f, 25); } } @@ -384,11 +392,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ if(selected != null && selected != sec && selected.hasBase()){ //imports if(sec.info.getRealDestination() == selected && sec.info.anyExports()){ - planets.drawArc(planet, sec.tile.v, selected.tile.v, Color.gray.write(Tmp.c2).a(selectAlpha), Pal.accent.write(Tmp.c3).a(selectAlpha), 0.4f, 90f, 25); + planets.drawArc(planet, sec.tile.v, selected.tile.v, Color.gray.write(Tmp.c2).a(state.uiAlpha), Pal.accent.write(Tmp.c3).a(state.uiAlpha), 0.4f, 90f, 25); } //exports if(selected.info.getRealDestination() == sec && selected.info.anyExports()){ - planets.drawArc(planet, selected.tile.v, sec.tile.v, Pal.place.write(Tmp.c2).a(selectAlpha), Pal.accent.write(Tmp.c3).a(selectAlpha), 0.4f, 90f, 25); + planets.drawArc(planet, selected.tile.v, sec.tile.v, Pal.place.write(Tmp.c2).a(state.uiAlpha), Pal.accent.write(Tmp.c3).a(state.uiAlpha), 0.4f, 90f, 25); } } } @@ -415,7 +423,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ if(icon != null){ planets.drawPlane(sec, () -> { //use white for content icons - Draw.color(preficon == icon && sec.info.contentIcon != null ? Color.white : color, selectAlpha); + Draw.color(preficon == icon && sec.info.contentIcon != null ? Color.white : color, state.uiAlpha); Draw.rect(icon, 0, 0, iw, iw * icon.height / icon.width); }); } @@ -444,13 +452,13 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ boolean selectable(Planet planet){ //TODO what if any sector is selectable? if(mode == planetLaunch) return launchSector != null && planet != launchSector.planet; - return planet == planets.planet || planet.alwaysUnlocked || planet.sectors.contains(Sector::hasBase); + return planet == state.planet || (planet.alwaysUnlocked && planet.isLandable()) || planet.sectors.contains(Sector::hasBase); } void setup(){ searchText = ""; - zoom = planets.zoom = 1f; - selectAlpha = 1f; + zoom = state.zoom = 1f; + state.uiAlpha = 1f; ui.minimapfrag.hide(); clearChildren(); @@ -492,8 +500,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ @Override public void draw(){ - planets.orbitAlpha = selectAlpha; - planets.render(PlanetDialog.this); + planets.render(state); } }, //info text @@ -518,12 +525,12 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ pt.button(planet.localizedName, Styles.clearTogglet, () -> { selected = null; launchSector = null; - if(renderer.planets.planet != planet){ - renderer.planets.planet = planet; + if(state.planet != planet){ + state.planet = planet; rebuildList(); } settings.put("lastplanet", planet.name); - }).width(200).height(40).growX().update(bb -> bb.setChecked(renderer.planets.planet == planet)); + }).width(200).height(40).growX().update(bb -> bb.setChecked(state.planet == planet)); pt.row(); } } @@ -533,8 +540,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ new Table(c -> { c.visible(() -> !(graphics.isPortrait() && mobile)); - if(planets.planet.sectors.contains(Sector::hasBase)){ - int attacked = planets.planet.sectors.count(Sector::isAttacked); + if(state.planet.sectors.contains(Sector::hasBase)){ + int attacked = state.planet.sectors.count(Sector::isAttacked); //sector notifications & search c.top().right(); @@ -564,7 +571,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ notifs.clear(); - var all = planets.planet.sectors.select(Sector::hasBase); + var all = state.planet.sectors.select(Sector::hasBase); all.sort(Structs.comps(Structs.comparingBool(s -> !s.isAttacked()), Structs.comparingInt(s -> s.save == null ? 0 : -(int)s.save.meta.timePlayed))); notifs.pane(p -> { @@ -646,20 +653,20 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } public void lookAt(Sector sector, float alpha){ - float len = planets.camPos.len(); - planets.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha); + float len = state.camPos.len(); + state.camPos.slerp(Tmp.v31.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()).setLength(len), alpha); } @Override public void act(float delta){ super.act(delta); - if(hovered != null && !mobile){ + if(hovered != null && !mobile && state.planet.hasGrid()){ addChild(hoverLabel); hoverLabel.toFront(); hoverLabel.touchable = Touchable.disabled; - Vec3 pos = planets.cam.project(Tmp.v31.set(hovered.tile.v).setLength(PlanetRenderer.outlineRad).rotate(Vec3.Y, -planets.planet.getRotation()).add(planets.planet.position)); + Vec3 pos = planets.cam.project(Tmp.v31.set(hovered.tile.v).setLength(PlanetRenderer.outlineRad).rotate(Vec3.Y, -state.planet.getRotation()).add(state.planet.position)); hoverLabel.setPosition(pos.x - Core.scene.marginLeft, pos.y - Core.scene.marginBottom, Align.center); hoverLabel.getText().setLength(0); @@ -704,14 +711,24 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } } - if(planets.planet.hasGrid()){ - hovered = planets.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad); + if(state.planet.hasGrid()){ + hovered = state.planet.getSector(planets.cam.getMouseRay(), PlanetRenderer.outlineRad); + }else if(state.planet.isLandable()){ + boolean wasNull = selected == null; + //always have the first sector selected. + //TODO better support for multiple sectors in gridless planets? + hovered = selected = state.planet.sectors.first(); + + //autoshow + if(wasNull){ + updateSelected(); + } }else{ hovered = selected = null; } - planets.zoom = Mathf.lerpDelta(planets.zoom, zoom, 0.4f); - selectAlpha = Mathf.lerpDelta(selectAlpha, Mathf.num(planets.zoom < 1.9f), 0.1f); + state.zoom = Mathf.lerpDelta(state.zoom, zoom, 0.4f); + state.uiAlpha = Mathf.lerpDelta(state.uiAlpha, Mathf.num(state.zoom < 1.9f), 0.1f); } void displayItems(Table c, float scl, ObjectMap stats, String name){ @@ -996,13 +1013,17 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ if(launching){ stable.color.sub(0, 0, 0, 0.05f * Time.delta); }else{ - //fade out UI when not facing selected sector - Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor(); - float dot = planets.cam.direction.dot(Tmp.v31); - stable.color.a = Math.max(dot, 0f)*2f; - if(dot*2f <= -0.1f){ - selected = null; - updateSelected(); + if(!state.planet.hasGrid()){ + stable.color.a = 1f; + }else{ + //fade out UI when not facing selected sector + Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -state.planet.getRotation()).scl(-1f).nor(); + float dot = planets.cam.direction.dot(Tmp.v31); + stable.color.a = Math.max(dot, 0f)*2f; + if(dot*2f <= -0.1f){ + selected = null; + updateSelected(); + } } } } @@ -1029,7 +1050,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ boolean shouldHide = true; //save before launch. - if(control.saves.getCurrent() != null && state.isGame() && mode != select){ + if(control.saves.getCurrent() != null && Vars.state.isGame() && mode != select){ try{ control.saves.getCurrent().save(); }catch(Throwable e){ diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index d0e900e479..feaf234ae9 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -25,6 +25,7 @@ import mindustry.graphics.*; import mindustry.graphics.MultiPacker.*; import mindustry.type.*; import mindustry.ui.*; +import mindustry.world.blocks.*; import mindustry.world.blocks.environment.*; import mindustry.world.blocks.power.*; import mindustry.world.consumers.*; @@ -122,6 +123,8 @@ public class Block extends UnlockableContent{ public boolean useColor = true; /** item that drops from this block, used for drills */ public @Nullable Item itemDrop = null; + /** Array of affinities to certain things. */ + public Attributes attributes = new Attributes(); /** tile entity health */ public int health = -1; /** base block explosiveness */ @@ -384,10 +387,16 @@ public class Block extends UnlockableContent{ } /** Returns whether or not this block can be place on the specified */ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ + return canPlaceOn(tile, team); + } + + /** Legacy canPlaceOn implementation, override {@link #canPlaceOn(Tile, Team, int)} instead.*/ public boolean canPlaceOn(Tile tile, Team team){ return true; } + public boolean canBreak(Tile tile){ return true; } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 0f6c13d9be..c4317a542b 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -169,7 +169,7 @@ public class Build{ return false; } - if(!type.canPlaceOn(tile, team)){ + if(!type.canPlaceOn(tile, team, rotation)){ return false; } diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index ee42782485..294a3a5964 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -227,6 +227,7 @@ public class ConstructBlock extends Block{ for(TextureRegion region : current.getGeneratedIcons()){ Shaders.blockbuild.region = region; + Shaders.blockbuild.time = Time.time; Shaders.blockbuild.progress = progress; Draw.rect(region, x, y, current.rotate ? rotdeg() : 0); diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 1c712abf89..c4cf8812db 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -58,6 +58,7 @@ public class ForceProjector extends Block{ ambientSound = Sounds.shield; ambientSoundVolume = 0.08f; consumes.add(new ConsumeCoolant(0.1f)).boost().update(false); + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java index f61f3c0355..90d3e30c95 100644 --- a/core/src/mindustry/world/blocks/defense/MendProjector.java +++ b/core/src/mindustry/world/blocks/defense/MendProjector.java @@ -36,6 +36,7 @@ public class MendProjector extends Block{ hasItems = true; emitLight = true; lightRadius = 50f; + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index b2c43ab490..95daea2e29 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -41,6 +41,7 @@ public class OverdriveProjector extends Block{ canOverdrive = false; emitLight = true; lightRadius = 50f; + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/blocks/defense/Wall.java b/core/src/mindustry/world/blocks/defense/Wall.java index 12ae157afd..9a22520775 100644 --- a/core/src/mindustry/world/blocks/defense/Wall.java +++ b/core/src/mindustry/world/blocks/defense/Wall.java @@ -36,6 +36,9 @@ public class Wall extends Block{ buildCostMultiplier = 6f; canOverdrive = false; drawDisabled = false; + + //it's a wall of course it's supported everywhere + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java index be1d3c25b8..7dc4eed3f6 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -12,6 +12,7 @@ public class PowerTurret extends Turret{ public PowerTurret(String name){ super(name); hasPower = true; + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index 59d90b1817..746ee0cfc7 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -410,7 +410,7 @@ public class ItemBridge extends Block{ } protected boolean checkAccept(Building source, Tile other){ - if(linked(source)) return true; + if(tile == null || linked(source)) return true; if(linkValid(tile, other)){ int rel = relativeTo(other); diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index 4b0f40d87b..c0bd7d73b2 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -48,6 +48,7 @@ public class MassDriver extends Block{ hasPower = true; outlineIcon = true; sync = true; + envEnabled |= Env.space; //point2 is relative config(Point2.class, (MassDriverBuild tile, Point2 point) -> tile.link = Point2.pack(point.x + tile.tileX(), point.y + tile.tileY())); diff --git a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java index a2d470c528..2681376e35 100644 --- a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java @@ -30,6 +30,7 @@ public class PayloadConveyor extends Block{ update = true; outputsPayload = true; noUpdateDisabled = true; + envEnabled |= Env.space; sync = true; } diff --git a/core/src/mindustry/world/blocks/environment/AirBlock.java b/core/src/mindustry/world/blocks/environment/AirBlock.java index b100bbc4ef..e0eef67635 100644 --- a/core/src/mindustry/world/blocks/environment/AirBlock.java +++ b/core/src/mindustry/world/blocks/environment/AirBlock.java @@ -14,6 +14,7 @@ public class AirBlock extends Floor{ useColor = false; wall = this; needsSurface = false; + canShadow = false; } @Override diff --git a/core/src/mindustry/world/blocks/environment/EmptyFloor.java b/core/src/mindustry/world/blocks/environment/EmptyFloor.java new file mode 100644 index 0000000000..3b1aba9e82 --- /dev/null +++ b/core/src/mindustry/world/blocks/environment/EmptyFloor.java @@ -0,0 +1,24 @@ +package mindustry.world.blocks.environment; + +import mindustry.content.*; +import mindustry.world.*; + +public class EmptyFloor extends Floor{ + + public EmptyFloor(String name){ + super(name); + variants = 0; + canShadow = false; + } + + @Override + public void drawBase(Tile tile){ + //draws only edges, never itself + drawEdges(tile); + + Floor floor = tile.overlay(); + if(floor != Blocks.air && floor != this){ + floor.drawBase(tile); + } + } +} diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java index ddad7804b3..91d677825b 100644 --- a/core/src/mindustry/world/blocks/environment/Floor.java +++ b/core/src/mindustry/world/blocks/environment/Floor.java @@ -15,7 +15,6 @@ import mindustry.graphics.*; import mindustry.graphics.MultiPacker.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -54,8 +53,6 @@ public class Floor extends Block{ public boolean playerUnmineable = false; /** Group of blocks that this block does not draw edges on. */ public Block blendGroup = this; - /** Array of affinities to certain things. */ - public Attributes attributes = new Attributes(); /** Whether this ore generates in maps by default. */ public boolean oreDefault = false; /** Ore generation params. */ @@ -64,6 +61,8 @@ public class Floor extends Block{ public Block wall = Blocks.air; /** Decoration block. Usually a rock. May be air. */ public Block decoration = Blocks.air; + /** Whether units can draw shadows over this. */ + public boolean canShadow = true; /** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */ public boolean needsSurface = true; @@ -116,10 +115,6 @@ public class Floor extends Block{ //keep default value if not found... if(wall == null) wall = Blocks.air; - if(decoration == Blocks.air){ - decoration = content.blocks().min(b -> b instanceof Prop && b.minfo.mod == null && b.breakable ? mapColor.diff(b.mapColor) : Float.POSITIVE_INFINITY); - } - if(isLiquid && walkEffect == Fx.none){ walkEffect = Fx.ripple; } diff --git a/core/src/mindustry/world/blocks/experimental/BlockForge.java b/core/src/mindustry/world/blocks/experimental/BlockForge.java index 29adc64d00..6f9987f8dc 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockForge.java +++ b/core/src/mindustry/world/blocks/experimental/BlockForge.java @@ -1,14 +1,17 @@ package mindustry.world.blocks.experimental; +import mindustry.world.blocks.payloads.*; + +/** @deprecated use Constructor instead. */ @Deprecated -public class BlockForge extends mindustry.world.blocks.payloads.BlockForge{ +public class BlockForge extends Constructor{ public BlockForge(String name){ super(name); } @Deprecated - public class BlockForgeBuild extends mindustry.world.blocks.payloads.BlockForge.BlockForgeBuild{ + public class BlockForgeBuild extends Constructor.ConstructorBuild{ } } diff --git a/core/src/mindustry/world/blocks/experimental/BlockLoader.java b/core/src/mindustry/world/blocks/experimental/BlockLoader.java index 91a044d4f8..6c0202a883 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockLoader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockLoader.java @@ -1,14 +1,16 @@ package mindustry.world.blocks.experimental; +import mindustry.world.blocks.payloads.*; + @Deprecated -public class BlockLoader extends mindustry.world.blocks.payloads.BlockLoader{ +public class BlockLoader extends PayloadLoader{ public BlockLoader(String name){ super(name); } @Deprecated - public class BlockLoaderBuild extends mindustry.world.blocks.payloads.BlockLoader.BlockLoaderBuild{ + public class BlockLoaderBuild extends PayloadLoaderBuild{ } } diff --git a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java index 1c655318e3..45403c0f1a 100644 --- a/core/src/mindustry/world/blocks/experimental/BlockUnloader.java +++ b/core/src/mindustry/world/blocks/experimental/BlockUnloader.java @@ -1,14 +1,16 @@ package mindustry.world.blocks.experimental; +import mindustry.world.blocks.payloads.*; + @Deprecated -public class BlockUnloader extends mindustry.world.blocks.payloads.BlockUnloader{ +public class BlockUnloader extends PayloadUnloader{ public BlockUnloader(String name){ super(name); } @Deprecated - public class BlockUnloaderBuild extends mindustry.world.blocks.payloads.BlockUnloader.BlockUnloaderBuild{ + public class BlockUnloaderBuild extends PayloadUnloaderBuild{ } } diff --git a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java index d8f480836c..c53e05ee21 100644 --- a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java +++ b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java @@ -20,7 +20,7 @@ public class ArmoredConduit extends Conduit{ public class ArmoredConduitBuild extends ConduitBuild{ @Override public boolean acceptLiquid(Building source, Liquid liquid){ - return super.acceptLiquid(source, liquid) && (source.block instanceof Conduit || + return super.acceptLiquid(source, liquid) && (tile == null || source.block instanceof Conduit || source.tile.absoluteRelativeTo(tile.x, tile.y) == rotation); } } diff --git a/core/src/mindustry/world/blocks/liquid/Conduit.java b/core/src/mindustry/world/blocks/liquid/Conduit.java index 0b4295f7dd..11ba66255b 100644 --- a/core/src/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/mindustry/world/blocks/liquid/Conduit.java @@ -151,7 +151,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ public boolean acceptLiquid(Building source, Liquid liquid){ noSleep(); return (liquids.current() == liquid || liquids.currentAmount() < 0.2f) - && ((source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); + && (tile == null || (source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); } @Override diff --git a/core/src/mindustry/world/blocks/liquid/LiquidBlock.java b/core/src/mindustry/world/blocks/liquid/LiquidBlock.java index eb9a3f16d3..ec5d40f571 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidBlock.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidBlock.java @@ -19,6 +19,7 @@ public class LiquidBlock extends Block{ hasLiquids = true; group = BlockGroup.liquids; outputsLiquid = true; + envEnabled |= Env.space | Env.underwater; } @Override diff --git a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java index c58a60c36c..984688a468 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java @@ -13,6 +13,7 @@ public class LiquidBridge extends ItemBridge{ outputsLiquid = true; canOverdrive = false; group = BlockGroup.liquids; + envEnabled = Env.any; } public class LiquidBridgeBuild extends ItemBridgeBuild{ diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index 80385a14ac..e8cf14ef16 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -42,6 +42,9 @@ public class LogicBlock extends Block{ group = BlockGroup.logic; schematicPriority = 5; + //universal, no real requirements + envEnabled = Env.any; + config(byte[].class, (LogicBuild build, byte[] data) -> build.readCompressed(data, true)); config(Integer.class, (LogicBuild entity, Integer pos) -> { diff --git a/core/src/mindustry/world/blocks/logic/LogicDisplay.java b/core/src/mindustry/world/blocks/logic/LogicDisplay.java index 772e17fdba..7e6bb10e29 100644 --- a/core/src/mindustry/world/blocks/logic/LogicDisplay.java +++ b/core/src/mindustry/world/blocks/logic/LogicDisplay.java @@ -36,6 +36,7 @@ public class LogicDisplay extends Block{ solid = true; group = BlockGroup.logic; drawDisabled = false; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/logic/MemoryBlock.java b/core/src/mindustry/world/blocks/logic/MemoryBlock.java index cff63b98a3..3868b80935 100644 --- a/core/src/mindustry/world/blocks/logic/MemoryBlock.java +++ b/core/src/mindustry/world/blocks/logic/MemoryBlock.java @@ -14,6 +14,7 @@ public class MemoryBlock extends Block{ solid = true; group = BlockGroup.logic; drawDisabled = false; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/logic/MessageBlock.java b/core/src/mindustry/world/blocks/logic/MessageBlock.java index d6bffd83f2..3a982c37cb 100644 --- a/core/src/mindustry/world/blocks/logic/MessageBlock.java +++ b/core/src/mindustry/world/blocks/logic/MessageBlock.java @@ -30,6 +30,7 @@ public class MessageBlock extends Block{ destructible = true; group = BlockGroup.logic; drawDisabled = false; + envEnabled = Env.any; config(String.class, (MessageBuild tile, String text) -> { if(text.length() > maxTextLength){ diff --git a/core/src/mindustry/world/blocks/logic/SwitchBlock.java b/core/src/mindustry/world/blocks/logic/SwitchBlock.java index 60e5db6dc7..ac9780a16b 100644 --- a/core/src/mindustry/world/blocks/logic/SwitchBlock.java +++ b/core/src/mindustry/world/blocks/logic/SwitchBlock.java @@ -17,6 +17,7 @@ public class SwitchBlock extends Block{ drawDisabled = false; autoResetEnabled = false; group = BlockGroup.logic; + envEnabled = Env.any; config(Boolean.class, (SwitchBuild entity, Boolean b) -> entity.enabled = b); } diff --git a/core/src/mindustry/world/blocks/payloads/PayloadBlock.java b/core/src/mindustry/world/blocks/payloads/PayloadBlock.java index a7885e76c7..17f74ac4ad 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadBlock.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadBlock.java @@ -80,16 +80,16 @@ public class PayloadBlock extends Block{ } @Override - public boolean canControlSelect(Player player){ - return !player.unit().spawnedByCore && this.payload == null && acceptUnitPayload(player.unit()) && player.tileOn() != null && player.tileOn().build == this; + public boolean canControlSelect(Unit player){ + return !player.spawnedByCore && this.payload == null && acceptUnitPayload(player) && player.tileOn() != null && player.tileOn().build == this; } @Override - public void onControlSelect(Player player){ + public void onControlSelect(Unit player){ float x = player.x, y = player.y; - acceptPlayerPayload(player, p -> payload = (T)p); + handleUnitPayload(player, p -> payload = (T)p); this.payVector.set(x, y).sub(this).clamp(-size * tilesize / 2f, -size * tilesize / 2f, size * tilesize / 2f, size * tilesize / 2f); - this.payRotation = player.unit().rotation; + this.payRotation = player.rotation; } @Override diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java index f0cff96156..b3d36969fc 100644 --- a/core/src/mindustry/world/blocks/power/Battery.java +++ b/core/src/mindustry/world/blocks/power/Battery.java @@ -21,6 +21,8 @@ public class Battery extends PowerDistributor{ outputsPower = true; consumesPower = true; flags = EnumSet.of(BlockFlag.battery); + //TODO could be supported everywhere... + envEnabled |= Env.space; } public class BatteryBuild extends Building{ diff --git a/core/src/mindustry/world/blocks/power/DecayGenerator.java b/core/src/mindustry/world/blocks/power/DecayGenerator.java index becce39642..0bb9e2eac9 100644 --- a/core/src/mindustry/world/blocks/power/DecayGenerator.java +++ b/core/src/mindustry/world/blocks/power/DecayGenerator.java @@ -1,6 +1,7 @@ package mindustry.world.blocks.power; import mindustry.type.*; +import mindustry.world.meta.*; public class DecayGenerator extends ItemLiquidGenerator{ @@ -8,6 +9,7 @@ public class DecayGenerator extends ItemLiquidGenerator{ super(true, false, name); hasItems = true; hasLiquids = false; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index 64e94d8c14..3679b2be80 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -43,6 +43,7 @@ public class ImpactReactor extends PowerGenerator{ flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator); lightRadius = 115f; emitLight = true; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/power/LightBlock.java b/core/src/mindustry/world/blocks/power/LightBlock.java index 2f1f05d606..36fc8c0f5f 100644 --- a/core/src/mindustry/world/blocks/power/LightBlock.java +++ b/core/src/mindustry/world/blocks/power/LightBlock.java @@ -14,6 +14,7 @@ import mindustry.graphics.*; import mindustry.input.*; import mindustry.logic.*; import mindustry.world.*; +import mindustry.world.meta.*; import static mindustry.Vars.*; @@ -28,6 +29,7 @@ public class LightBlock extends Block{ update = true; configurable = true; saveConfig = true; + envEnabled |= Env.space; swapDiagonalPlacement = true; config(Integer.class, (LightBuild tile, Integer value) -> tile.color = value); diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java index 6ed9f11189..a26a99d5cd 100644 --- a/core/src/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java @@ -56,6 +56,7 @@ public class NuclearReactor extends PowerGenerator{ rebuildable = false; flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator); schematicPriority = -5; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/power/PowerDiode.java b/core/src/mindustry/world/blocks/power/PowerDiode.java index 422c978aef..f31cf71cf6 100644 --- a/core/src/mindustry/world/blocks/power/PowerDiode.java +++ b/core/src/mindustry/world/blocks/power/PowerDiode.java @@ -23,6 +23,7 @@ public class PowerDiode extends Block{ group = BlockGroup.power; noUpdateDisabled = true; schematicPriority = 10; + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 7d8c609b77..8ee013f6fe 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -43,6 +43,7 @@ public class PowerNode extends PowerBlock{ swapDiagonalPlacement = true; schematicPriority = -10; drawDisabled = false; + envEnabled |= Env.space; config(Integer.class, (entity, value) -> { PowerModule power = entity.power; diff --git a/core/src/mindustry/world/blocks/power/SolarGenerator.java b/core/src/mindustry/world/blocks/power/SolarGenerator.java index 84e0b0ba81..bac6345115 100644 --- a/core/src/mindustry/world/blocks/power/SolarGenerator.java +++ b/core/src/mindustry/world/blocks/power/SolarGenerator.java @@ -12,6 +12,7 @@ public class SolarGenerator extends PowerGenerator{ super(name); //remove the BlockFlag.generator flag to make this a lower priority target than other generators. flags = EnumSet.of(); + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/power/ThermalGenerator.java b/core/src/mindustry/world/blocks/power/ThermalGenerator.java index 8c97beca13..d0b979a29d 100644 --- a/core/src/mindustry/world/blocks/power/ThermalGenerator.java +++ b/core/src/mindustry/world/blocks/power/ThermalGenerator.java @@ -41,7 +41,7 @@ public class ThermalGenerator extends PowerGenerator{ } @Override - public boolean canPlaceOn(Tile tile, Team team){ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ //make sure there's heat at this location return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(attribute)) > 0.01f; } diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index 9ee6eb8e6d..fa3a274301 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -36,7 +36,7 @@ public class Drill extends Block{ /** How many times faster the drill will progress when boosted by liquid. */ public float liquidBoostIntensity = 1.6f; /** Speed at which the drill speeds up. */ - public float warmupSpeed = 0.02f; + public float warmupSpeed = 0.015f; //return variables for countOre protected @Nullable Item returnItem; @@ -108,7 +108,7 @@ public class Drill extends Block{ } @Override - public boolean canPlaceOn(Tile tile, Team team){ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ if(isMultiblock()){ for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ if(canMine(other)){ @@ -275,14 +275,14 @@ public class Drill extends Block{ speed *= efficiency(); // Drill slower when not at full power lastDrillSpeed = (speed * dominantItems * warmup) / (drillTime + hardnessDrillMultiplier * dominantItem.hardness); - warmup = Mathf.lerpDelta(warmup, speed, warmupSpeed); + warmup = Mathf.approachDelta(warmup, speed, warmupSpeed); progress += delta() * dominantItems * speed * warmup; if(Mathf.chanceDelta(updateEffectChance * warmup)) updateEffect.at(x + Mathf.range(size * 2f), y + Mathf.range(size * 2f)); }else{ lastDrillSpeed = 0f; - warmup = Mathf.lerpDelta(warmup, 0f, warmupSpeed); + warmup = Mathf.approachDelta(warmup, 0f, warmupSpeed); return; } diff --git a/core/src/mindustry/world/blocks/production/Incinerator.java b/core/src/mindustry/world/blocks/production/Incinerator.java index 906763d7e6..b5ceff931b 100644 --- a/core/src/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/mindustry/world/blocks/production/Incinerator.java @@ -28,11 +28,7 @@ public class Incinerator extends Block{ @Override public void updateTile(){ - if(consValid() && efficiency() > 0.9f){ - heat = Mathf.lerpDelta(heat, 1f, 0.04f); - }else{ - heat = Mathf.lerpDelta(heat, 0f, 0.02f); - } + heat = Mathf.approachDelta(heat, consValid() && efficiency() > 0.9f ? 1f : 0f, 0.04f); } @Override diff --git a/core/src/mindustry/world/blocks/production/Pump.java b/core/src/mindustry/world/blocks/production/Pump.java index de524f72f6..9a9aca65c3 100644 --- a/core/src/mindustry/world/blocks/production/Pump.java +++ b/core/src/mindustry/world/blocks/production/Pump.java @@ -20,6 +20,7 @@ public class Pump extends LiquidBlock{ super(name); group = BlockGroup.liquids; floating = true; + envEnabled = Env.terrestrial; } @Override @@ -61,7 +62,7 @@ public class Pump extends LiquidBlock{ } @Override - public boolean canPlaceOn(Tile tile, Team team){ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ if(isMultiblock()){ Liquid last = null; for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){ diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index 8098bebd59..912af46b18 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -31,6 +31,8 @@ public class SolidPump extends Pump{ public SolidPump(String name){ super(name); hasPower = true; + //only supports ground by default + envEnabled = Env.terrestrial; } @Override @@ -63,7 +65,7 @@ public class SolidPump extends Pump{ } @Override - public boolean canPlaceOn(Tile tile, Team team){ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ float sum = tile.getLinkedTilesAs(this, tempTiles).sumf(t -> canPump(t) ? baseEfficiency + (attribute != null ? t.floor().attributes.get(attribute) : 0f) : 0f); return sum > 0.00001f; } diff --git a/core/src/mindustry/world/blocks/sandbox/LiquidSource.java b/core/src/mindustry/world/blocks/sandbox/LiquidSource.java index 7f029299c3..621c2252df 100644 --- a/core/src/mindustry/world/blocks/sandbox/LiquidSource.java +++ b/core/src/mindustry/world/blocks/sandbox/LiquidSource.java @@ -27,6 +27,7 @@ public class LiquidSource extends Block{ noUpdateDisabled = true; displayFlow = false; group = BlockGroup.liquids; + envEnabled = Env.any; config(Liquid.class, (LiquidSourceBuild tile, Liquid l) -> tile.source = l); configClear((LiquidSourceBuild tile) -> tile.source = null); diff --git a/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java b/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java index bde9742467..713dace08f 100644 --- a/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java +++ b/core/src/mindustry/world/blocks/sandbox/LiquidVoid.java @@ -13,6 +13,7 @@ public class LiquidVoid extends Block{ solid = true; update = true; group = BlockGroup.liquids; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 013937eb48..7d76842a86 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -121,7 +121,7 @@ public class CoreBlock extends StorageBlock{ } @Override - public boolean canPlaceOn(Tile tile, Team team){ + public boolean canPlaceOn(Tile tile, Team team, int rotation){ if(tile == null) return false; CoreBuild core = team.core(); //must have all requirements @@ -166,7 +166,7 @@ public class CoreBlock extends StorageBlock{ public void drawPlace(int x, int y, int rotation, boolean valid){ if(world.tile(x, y) == null) return; - if(!canPlaceOn(world.tile(x, y), player.team())){ + if(!canPlaceOn(world.tile(x, y), player.team(), rotation)){ drawPlaceText(Core.bundle.get( (player.team().core() != null && player.team().core().items.has(requirements, state.rules.buildCostMultiplier)) || state.rules.infiniteResources ? diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 260e3487bd..6135288c3c 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -23,6 +23,7 @@ public class StorageBlock extends Block{ group = BlockGroup.transportation; flags = EnumSet.of(BlockFlag.storage); allowResupply = true; + envEnabled = Env.any; } @Override diff --git a/core/src/mindustry/world/blocks/storage/Unloader.java b/core/src/mindustry/world/blocks/storage/Unloader.java index d43015b7cf..d535952e70 100644 --- a/core/src/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/mindustry/world/blocks/storage/Unloader.java @@ -28,6 +28,7 @@ public class Unloader extends Block{ itemCapacity = 0; noUpdateDisabled = true; unloadable = false; + envEnabled = Env.any; config(Item.class, (UnloaderBuild tile, Item item) -> tile.sortItem = item); configClear((UnloaderBuild tile) -> tile.sortItem = null); diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index ad2b3e075a..3d8f9c024f 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -37,6 +37,7 @@ public class CommandCenter extends Block{ configurable = true; drawDisabled = false; logicConfigurable = true; + envEnabled = Env.any; config(UnitCommand.class, (CommandBuild build, UnitCommand command) -> { if(build.team.data().command != command){ diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java index 1e8e9c9ddf..3ca61ec0d7 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -59,6 +59,8 @@ public class RepairPoint extends Block{ outlineIcon = true; //yeah, this isn't the same thing, but it's close enough group = BlockGroup.projectors; + + envEnabled |= Env.space; } @Override diff --git a/core/src/mindustry/world/meta/StatValues.java b/core/src/mindustry/world/meta/StatValues.java index b556e7809c..ba07d8e19d 100644 --- a/core/src/mindustry/world/meta/StatValues.java +++ b/core/src/mindustry/world/meta/StatValues.java @@ -108,14 +108,18 @@ public class StatValues{ }; } - public static StatValue floorEfficiency(Floor floor, float multiplier, boolean startZero){ + public static StatValue blockEfficiency(Block floor, float multiplier, boolean startZero){ return table -> table.stack( new Image(floor.uiIcon).setScaling(Scaling.fit), new Table(t -> t.top().right().add((multiplier < 0 ? "[scarlet]" : startZero ? "[accent]" : "[accent]+") + (int)((multiplier) * 100) + "%").style(Styles.outlineLabel)) ); } - public static StatValue floors(Attribute attr, boolean floating, float scale, boolean startZero){ + public static StatValue blocks(Attribute attr, boolean floating, float scale, boolean startZero){ + return blocks(attr, floating, scale, startZero, true); + } + + public static StatValue blocks(Attribute attr, boolean floating, float scale, boolean startZero, boolean checkFloors){ return table -> table.table(c -> { Runnable[] rebuild = {null}; Map[] lastMap = {null}; @@ -126,14 +130,14 @@ public class StatValues{ if(state.isGame()){ var blocks = Vars.content.blocks() - .select(block -> block instanceof Floor f && indexer.isBlockPresent(block) && f.attributes.get(attr) != 0 && !(f.isDeep() && !floating)) + .select(block -> (!checkFloors || block instanceof Floor) && indexer.isBlockPresent(block) && block.attributes.get(attr) != 0 && !((block instanceof Floor f && f.isDeep()) && !floating)) .as().with(s -> s.sort(f -> f.attributes.get(attr))); if(blocks.any()){ int i = 0; for(var block : blocks){ - floorEfficiency(block, block.attributes.get(attr) * scale, startZero).display(c); + blockEfficiency(block, block.attributes.get(attr) * scale, startZero).display(c); if(++i % 5 == 0){ c.row(); } diff --git a/core/src/mindustry/world/meta/Stats.java b/core/src/mindustry/world/meta/Stats.java index d11b56f395..742400989f 100644 --- a/core/src/mindustry/world/meta/Stats.java +++ b/core/src/mindustry/world/meta/Stats.java @@ -66,7 +66,7 @@ public class Stats{ } public void add(Stat stat, Attribute attr, boolean floating, float scale, boolean startZero){ - add(stat, StatValues.floors(attr, floating, scale, startZero)); + add(stat, StatValues.blocks(attr, floating, scale, startZero)); } /** Adds a single string value with this stat. */