diff --git a/core/assets-raw/sprites/blocks/environment/arkyic-vent1.png b/core/assets-raw/sprites/blocks/environment/arkyic-vent1.png new file mode 100644 index 0000000000..cb2a687612 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/arkyic-vent1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/arkyic-vent2.png b/core/assets-raw/sprites/blocks/environment/arkyic-vent2.png new file mode 100644 index 0000000000..7c689388ac Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/arkyic-vent2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/carbon-vent1.png b/core/assets-raw/sprites/blocks/environment/carbon-vent1.png new file mode 100644 index 0000000000..4429e8168d Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/carbon-vent1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/carbon-vent2.png b/core/assets-raw/sprites/blocks/environment/carbon-vent2.png new file mode 100644 index 0000000000..755e7d608e Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/carbon-vent2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/red-stone-vent1.png b/core/assets-raw/sprites/blocks/environment/red-stone-vent1.png new file mode 100644 index 0000000000..be730b3c3f Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/red-stone-vent1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/red-stone-vent2.png b/core/assets-raw/sprites/blocks/environment/red-stone-vent2.png new file mode 100644 index 0000000000..09e1ca9994 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/red-stone-vent2.png differ diff --git a/core/assets-raw/sprites/blocks/environment/steam-vent1.png b/core/assets-raw/sprites/blocks/environment/rhyolite-vent1.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/steam-vent1.png rename to core/assets-raw/sprites/blocks/environment/rhyolite-vent1.png diff --git a/core/assets-raw/sprites/blocks/environment/steam-vent2.png b/core/assets-raw/sprites/blocks/environment/rhyolite-vent2.png similarity index 100% rename from core/assets-raw/sprites/blocks/environment/steam-vent2.png rename to core/assets-raw/sprites/blocks/environment/rhyolite-vent2.png diff --git a/core/assets-raw/sprites/blocks/environment/yellow-stone-vent1.png b/core/assets-raw/sprites/blocks/environment/yellow-stone-vent1.png new file mode 100644 index 0000000000..a4821a5770 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/yellow-stone-vent1.png differ diff --git a/core/assets-raw/sprites/blocks/environment/yellow-stone-vent2.png b/core/assets-raw/sprites/blocks/environment/yellow-stone-vent2.png new file mode 100644 index 0000000000..dc62a2b238 Binary files /dev/null and b/core/assets-raw/sprites/blocks/environment/yellow-stone-vent2.png differ diff --git a/core/assets-raw/sprites/units/weapons/disrupt-weapon-preview.png b/core/assets-raw/sprites/units/weapons/disrupt-weapon-preview.png new file mode 100644 index 0000000000..39bd8016e1 Binary files /dev/null and b/core/assets-raw/sprites/units/weapons/disrupt-weapon-preview.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 7856baa92b..428c2d0282 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -521,3 +521,8 @@ 63182=disrupt|unit-disrupt-ui 63181=krepost|unit-krepost-ui 63180=disrupt-missile|unit-disrupt-missile-ui +63179=rhyolite-vent|block-rhyolite-vent-ui +63178=arkyic-vent|block-arkyic-vent-ui +63177=yellow-stone-vent|block-yellow-stone-vent-ui +63176=red-stone-vent|block-red-stone-vent-ui +63175=carbon-vent|block-carbon-vent-ui diff --git a/core/assets/maps/aware.msav b/core/assets/maps/aware.msav index 608107a562..4284763b82 100644 Binary files a/core/assets/maps/aware.msav and b/core/assets/maps/aware.msav differ diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index deb22b3f9b..97ffdc7a07 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -46,7 +46,9 @@ public class Blocks{ redmat, bluemat, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, redweed, purbush, yellowCoral, - regolithWall, yellowStoneWall, rhyoliteWall, steamVent, carbonWall, redIceWall, ferricStoneWall, beryllicStoneWall, arkyicWall, crystallineStoneWall, redStoneWall, redDiamondWall, + //TODO rename steamvent to rhyolite vent, maybe add red vent or crystal vent + rhyoliteVent, carbonVent, arkyicVent, yellowStoneVent, redStoneVent, + regolithWall, yellowStoneWall, rhyoliteWall, carbonWall, redIceWall, ferricStoneWall, beryllicStoneWall, arkyicWall, crystallineStoneWall, redStoneWall, redDiamondWall, ferricStone, ferricCraters, carbonStone, beryllicStone, crystallineStone, crystalFloor, yellowStonePlates, iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, grass, salt, //boulders @@ -382,11 +384,6 @@ public class Blocks{ variants = 3; }}; - steamVent = new SteamVent("steam-vent"){{ - parent = blendGroup = rhyolite; - attributes.set(Attribute.vent, 1f); - }}; - regolith = new Floor("regolith"){{ attributes.set(Attribute.water, -1f); }}; @@ -457,10 +454,38 @@ public class Blocks{ albedo = 0.9f; }}; - arkyicStone = new Floor("arkyic-stone"){{ + arkyicStone = new Floor("arkyic-stone"){{ variants = 3; }}; + //TODO different vent colors + rhyoliteVent = new SteamVent("rhyolite-vent"){{ + parent = blendGroup = rhyolite; + attributes.set(Attribute.steam, 1f); + }}; + + carbonVent = new SteamVent("carbon-vent"){{ + parent = blendGroup = carbonStone; + attributes.set(Attribute.steam, 1f); + }}; + + arkyicVent = new SteamVent("arkyic-vent"){{ + parent = blendGroup = arkyicStone; + attributes.set(Attribute.steam, 1f); + }}; + + yellowStoneVent = new SteamVent("yellow-stone-vent"){{ + //TODO ...or regolith + parent = blendGroup = yellowStone; + attributes.set(Attribute.steam, 1f); + }}; + + redStoneVent = new SteamVent("red-stone-vent"){{ + //TODO ...or regolith + parent = blendGroup = denseRedStone; + attributes.set(Attribute.steam, 1f); + }}; + redmat = new Floor("redmat"); bluemat = new Floor("bluemat"); @@ -879,10 +904,10 @@ public class Blocks{ }}; siliconArcFurnace = new GenericCrafter("silicon-arc-furnace"){{ - requirements(Category.crafting, with(Items.beryllium, 60, Items.graphite, 80)); + requirements(Category.crafting, with(Items.beryllium, 70, Items.graphite, 80)); craftEffect = Fx.none; - outputItem = new ItemStack(Items.silicon, 5); - craftTime = 40f; + outputItem = new ItemStack(Items.silicon, 4); + craftTime = 50f; size = 3; hasPower = true; hasLiquids = false; @@ -1138,6 +1163,7 @@ public class Blocks{ ); drawer.iconOverride = new String[]{"-bottom", ""}; + regionRotated1 = 3; continuousLiquidOutput = true; outputLiquids = LiquidStack.with(Liquids.ozone, 4f / 60, Liquids.hydrogen, 6f / 60); liquidOutputDirections = new int[]{1, 3}; @@ -1184,6 +1210,7 @@ public class Blocks{ drawer = new DrawMulti(new DrawRegion("-bottom"), new DrawLiquidRegion(), new DrawBlock(), new DrawHeatOutput()); drawer.iconOverride = new String[]{"-bottom", "", "-top1"}; + regionRotated1 = 2; craftTime = 60f * 3f; liquidCapacity = 30f; heatOutput = 5f; @@ -2185,7 +2212,7 @@ public class Blocks{ turbineCondenser = new ThermalGenerator("turbine-condenser"){{ requirements(Category.power, with(Items.graphite, 40, Items.beryllium, 40)); - attribute = Attribute.vent; + attribute = Attribute.steam; displayEfficiencyScale = 1f / 9f; minEfficiency = 9f - 0.0001f; powerProduction = 3f / 9f; @@ -2369,7 +2396,7 @@ public class Blocks{ //TODO output heat? ventCondenser = new AttributeCrafter("vent-condenser"){{ requirements(Category.production, with(Items.graphite, 20, Items.beryllium, 60)); - attribute = Attribute.vent; + attribute = Attribute.steam; minEfficiency = 9f - 0.0001f; baseEfficiency = 0f; displayEfficiency = false; diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java index fc63290739..359af7de91 100644 --- a/core/src/mindustry/content/SectorPresets.java +++ b/core/src/mindustry/content/SectorPresets.java @@ -119,7 +119,7 @@ public class SectorPresets{ }}; aware = new SectorPreset("aware", erekir, 88){{ - captureWave = 6; + captureWave = 5; difficulty = 3; }}; diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 0788ccdfd0..899a2b87c6 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -328,6 +328,7 @@ public class Renderer implements ApplicationListener{ Draw.draw(Layer.plans, overlays::drawBottom); if(animateShields && Shaders.shield != null){ + //TODO would be nice if there were a way to detect if any shields or build beams actually *exist* before beginning/ending buffers, otherwise you're just blitting and swapping shaders for nothing Draw.drawRange(Layer.shields, 1f, () -> effectBuffer.begin(Color.clear), () -> { effectBuffer.end(); effectBuffer.blit(Shaders.shield); diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 544649f292..6253750460 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1036,6 +1036,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, int id = pos(); TextureRegion region = renderer.blocks.cracks[block.size - 1][Mathf.clamp((int)((1f - healthf()) * BlockRenderer.crackRegions), 0, BlockRenderer.crackRegions-1)]; Draw.colorl(0.2f, 0.1f + (1f - healthf())* 0.6f); + //TODO could be random, flipped, pseudorandom, etc Draw.rect(region, x, y, (id%4)*90); Draw.color(); } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index ec33b51bf8..6ff55ef14f 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -36,7 +36,7 @@ public class Rules{ /** Whether this is the editor gamemode. */ public boolean editor = false; /** Whether a gameover can happen at all. Set this to false to implement custom gameover conditions. */ - public boolean canGameOver = true; + public boolean canGameOver = false; /** Whether cores change teams when they are destroyed. */ public boolean coreCapture = false; /** Whether reactors can explode and damage other blocks. */ diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 138b92679b..6291770cbe 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -359,7 +359,7 @@ public class BlockRenderer{ for(int i = 0; i < tileview.size; i++){ Tile tile = tileview.items[i]; Block block = tile.block(); - Building entity = tile.build; + Building build = tile.build; Draw.z(Layer.block); @@ -374,20 +374,21 @@ public class BlockRenderer{ Draw.z(Layer.block); } - if(entity != null){ + if(build != null){ - if(entity.damaged()){ - entity.drawCracks(); + if(build.damaged()){ + Draw.z(Layer.blockCracks); + build.drawCracks(); Draw.z(Layer.block); } - if(entity.team != player.team()){ - entity.drawTeam(); + if(build.team != player.team()){ + build.drawTeam(); Draw.z(Layer.block); } - if(entity.team == player.team() && renderer.drawStatus && block.consumes.any()){ - entity.drawStatus(); + if(build.team == player.team() && renderer.drawStatus && block.consumes.any()){ + build.drawStatus(); } } Draw.reset(); diff --git a/core/src/mindustry/graphics/Layer.java b/core/src/mindustry/graphics/Layer.java index cb8dd93618..109bc2799d 100644 --- a/core/src/mindustry/graphics/Layer.java +++ b/core/src/mindustry/graphics/Layer.java @@ -26,6 +26,12 @@ public class Layer{ //base block layer - most blocks go here block = 30, + //layer for cracks over blocks, batched to prevent excessive texture swaps + blockCracks = 30f + 0.1f, + + //some blocks need to draw stuff after cracks + blockAfterCracks = 30f + 0.2f, + //informal layer used for additive blending overlay, grouped together to reduce draw calls blockAdditive = 31, diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index b991b64f85..a39142caca 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -61,7 +61,8 @@ public abstract class SaveFileReader{ "block-unloader", "payload-unloader", "block-loader", "payload-loader", "thermal-pump", "impulse-pump", - "alloy-smelter", "surge-smelter" + "alloy-smelter", "surge-smelter", + "steam-vent", "rhyolite-vent" ); public static final ObjectMap modContentNameMap = ObjectMap.of( diff --git a/core/src/mindustry/maps/planet/ErekirPlanetGenerator.java b/core/src/mindustry/maps/planet/ErekirPlanetGenerator.java index 5080d4f549..336bc4662d 100644 --- a/core/src/mindustry/maps/planet/ErekirPlanetGenerator.java +++ b/core/src/mindustry/maps/planet/ErekirPlanetGenerator.java @@ -324,10 +324,9 @@ public class ErekirPlanetGenerator extends PlanetGenerator{ trimDark(); - int minVents = rand.random(5, 8); + int minVents = rand.random(6, 8); int ventCount = 0; - //TODO vents everywhere! rhyolite patches //vents outer: for(Tile tile : tiles){ @@ -346,7 +345,7 @@ public class ErekirPlanetGenerator extends PlanetGenerator{ ventCount ++; for(var pos : SteamVent.offsets){ Tile other = tiles.get(pos.x + tile.x + 1, pos.y + tile.y + 1); - other.setFloor(Blocks.steamVent.asFloor()); + other.setFloor(Blocks.rhyoliteVent.asFloor()); } } } @@ -358,22 +357,52 @@ public class ErekirPlanetGenerator extends PlanetGenerator{ while(ventCount < minVents && iterations++ < maxIterations){ outer: for(Tile tile : tiles){ - if(rand.chance(0.00018)){ + if(rand.chance(0.00018 * (1 + iterations))){ + //skip crystals, but only when directly on them + if(tile.floor() == Blocks.crystallineStone || tile.floor() == Blocks.crystalFloor){ + continue; + } + int radius = 1; for(int x = -radius; x <= radius; x++){ for(int y = -radius; y <= radius; y++){ Tile other = tiles.get(x + tile.x, y + tile.y); //skip solids / other vents / arkycite / slag - if(other == null || other.block().solid || other.floor() == Blocks.steamVent || other.floor() == Blocks.slag || other.floor() == Blocks.arkyciteFloor){ + if(other == null || other.block().solid || other.floor().attributes.get(Attribute.steam) != 0 || other.floor() == Blocks.slag || other.floor() == Blocks.arkyciteFloor){ continue outer; } } } + Block + floor = Blocks.rhyolite, + secondFloor = Blocks.rhyoliteCrater, + vent = Blocks.rhyoliteVent; + + int xDir = 1; + //set target material depending on what's encountered + if(tile.floor() == Blocks.beryllicStone || tile.floor() == Blocks.arkyicStone){ + floor = secondFloor = Blocks.arkyicStone; + vent = Blocks.arkyicVent; + }else if(tile.floor() == Blocks.yellowStone || tile.floor() == Blocks.yellowStonePlates || tile.floor() == Blocks.regolith){ + floor = Blocks.yellowStone; + secondFloor = Blocks.yellowStonePlates; + vent = Blocks.yellowStoneVent; + }else if(tile.floor() == Blocks.redStone || tile.floor() == Blocks.denseRedStone){ + floor = Blocks.denseRedStone; + secondFloor = Blocks.redStone; + vent = Blocks.redStoneVent; + xDir = -1; + }else if(tile.floor() == Blocks.carbonStone){ + floor = secondFloor = Blocks.carbonStone; + vent = Blocks.carbonVent; + } + + ventCount ++; for(var pos : SteamVent.offsets){ Tile other = tiles.get(pos.x + tile.x + 1, pos.y + tile.y + 1); - other.setFloor(Blocks.steamVent.asFloor()); + other.setFloor(vent.asFloor()); } //"circle" for blending @@ -384,12 +413,14 @@ public class ErekirPlanetGenerator extends PlanetGenerator{ int rx = cx + tile.x, ry = cy + tile.y; //skew circle Y float rcy = cy + cx*0.9f; - if(cx*cx + rcy*rcy <= crad2 - noise(rx, ry + rx*2f, 2, 0.7f, 8f, crad2 * 1.1f)){ + if(cx*cx + rcy*rcy <= crad2 - noise(rx, ry + rx * 2f * xDir, 2, 0.7f, 8f, crad2 * 1.1f)){ Tile dest = tiles.get(rx, ry); - if(dest != null && dest.floor() != Blocks.steamVent && dest.floor() != Blocks.roughRhyolite && dest.floor() != Blocks.arkyciteFloor && dest.floor() != Blocks.slag){ - dest.setFloor(rand.chance(0.08) ? Blocks.rhyoliteCrater.asFloor() : Blocks.rhyolite.asFloor()); + if(dest != null && dest.floor().attributes.get(Attribute.steam) == 0 && dest.floor() != Blocks.roughRhyolite && dest.floor() != Blocks.arkyciteFloor && dest.floor() != Blocks.slag){ + + dest.setFloor(rand.chance(0.08) ? secondFloor.asFloor() : floor.asFloor()); + if(dest.block().isStatic()){ - dest.setBlock(Blocks.rhyoliteWall); + dest.setBlock(floor.asFloor().wall); } } } diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index 19b4553eb7..6ac25140f6 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -149,13 +149,17 @@ public class ContentParser{ PartProgress base = (PartProgress)field(PartProgress.class, data.getString("type")); + JsonValue opval = + data.has("operation") ? data.get("operation") : + data.has("op") ? data.get("op") : null; + //no operations I guess (why would you do this?) - if(!data.has("operation")){ + if(opval == null){ return base; } //this is the name of the method to call - String op = data.getString("operation"); + String op = opval.asString(); //I have to hard-code this, no easy way of getting parameter names, unfortunately return switch(op){ diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 0293d4b3e9..f3256d5839 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -171,6 +171,8 @@ public class UnitType extends UnlockableContent{ public boolean forceMultiTarget = false; public boolean hidden = false; public boolean internal = false; + /** A sample of the unit that this type creates. Do not modify! */ + public Unit sample; //for crawlers public int segments = 0; @@ -522,6 +524,9 @@ public class UnitType extends UnlockableContent{ dpsEstimate /= 25f; } } + + //only do this after everything else was initialized + sample = constructor.get(); } @CallSuper diff --git a/core/src/mindustry/world/blocks/defense/BaseShield.java b/core/src/mindustry/world/blocks/defense/BaseShield.java new file mode 100644 index 0000000000..3cb7a9e10b --- /dev/null +++ b/core/src/mindustry/world/blocks/defense/BaseShield.java @@ -0,0 +1,107 @@ +package mindustry.world.blocks.defense; + +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class BaseShield extends Block{ + //TODO game rule? or field? should vary by base. + //public float radius = 400f; + + protected static BaseShieldBuild paramBuild; + //protected static Effect paramEffect; + protected static final Cons bulletConsumer = bullet -> { + if(bullet.team != paramBuild.team && bullet.type.absorbable && bullet.within(paramBuild, paramBuild.radius())){ + bullet.absorb(); + //paramEffect.at(bullet); + + //TODO effect, shield health go down? + //paramBuild.hit = 1f; + //paramBuild.buildup += bullet.damage; + } + }; + + protected static final Cons unitConsumer = unit -> { + //if this is positive, repel the unit; if it exceeds the unit radius * 2, it's inside the forcefield and must be killed + float overlapDst = (unit.hitSize/2f + paramBuild.radius()) - unit.dst(paramBuild); + + if(overlapDst > 0){ + if(overlapDst > unit.hitSize){ + //instakill units that are stuck inside the shield (TODO or maybe damage them instead?) + unit.kill(); + }else{ + unit.move(Tmp.v1.set(unit).sub(paramBuild).setLength(overlapDst)); + } + } + }; + + + public BaseShield(String name){ + super(name); + + hasPower = true; + } + + public class BaseShieldBuild extends Building{ + public boolean broken = false; //TODO + public float hit = 0f; + + @Override + public void updateTile(){ + //TODO smooth radius + float radius = radius(); + + if(radius > 0 && !broken){ + paramBuild = this; + //paramEffect = absorbEffect; + Groups.bullet.intersect(x - radius, y - radius, radius * 2f, radius * 2f, bulletConsumer); + Units.nearbyEnemies(team,x ,y, radius, unitConsumer); + } + } + + public float radius(){ + //TODO bad rule? + return Vars.state.rules.enemyCoreBuildRadius; + } + + @Override + public void draw(){ + super.draw(); + + drawShield(); + } + + public void drawShield(){ + if(!broken){ + float radius = radius(); + + Draw.z(Layer.shields); + + Draw.color(team.color, Color.white, Mathf.clamp(hit)); + + if(renderer.animateShields){ + Fill.circle(x, y, radius); + }else{ + Lines.stroke(1.5f); + Draw.alpha(0.09f + Mathf.clamp(0.08f * hit)); + Fill.circle(x, y, radius); + Draw.alpha(1f); + //TODO + Lines.poly(x, y, 60, radius); + Draw.reset(); + } + } + + Draw.reset(); + } + } +} diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 1356619b19..98653a318c 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -39,12 +39,12 @@ public class ForceProjector extends Block{ protected static ForceBuild paramEntity; protected static Effect paramEffect; - protected static final Cons shieldConsumer = trait -> { - if(trait.team != paramEntity.team && trait.type.absorbable && Intersector.isInsideHexagon(paramEntity.x, paramEntity.y, paramEntity.realRadius() * 2f, trait.x(), trait.y())){ - trait.absorb(); - paramEffect.at(trait); + protected static final Cons shieldConsumer = bullet -> { + if(bullet.team != paramEntity.team && bullet.type.absorbable && Intersector.isInsideHexagon(paramEntity.x, paramEntity.y, paramEntity.realRadius() * 2f, bullet.x, bullet.y)){ + bullet.absorb(); + paramEffect.at(bullet); paramEntity.hit = 1f; - paramEntity.buildup += trait.damage(); + paramEntity.buildup += bullet.damage; } }; diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index ea2f1152da..bf350a6807 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -325,8 +325,10 @@ public class Drill extends Block{ float ts = 0.6f; Draw.rect(region, x, y); + Draw.z(Layer.blockCracks); drawDefaultCracks(); + Draw.z(Layer.blockAfterCracks); if(drawRim){ Draw.color(heatColor); Draw.alpha(warmup * ts * (1f - s + Mathf.absin(Time.time, 3f, s))); diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index 7bd7cb9bed..3f5ecd5ab1 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -103,7 +103,9 @@ public class SolidPump extends Pump{ @Override public void draw(){ Draw.rect(region, x, y); + Draw.z(Layer.blockCracks); super.drawCracks(); + Draw.z(Layer.blockAfterCracks); Drawf.liquid(liquidRegion, x, y, liquids.get(result) / liquidCapacity, result.color); Drawf.spinSprite(rotatorRegion, x, y, pumpTime * rotateSpeed); diff --git a/core/src/mindustry/world/meta/Attribute.java b/core/src/mindustry/world/meta/Attribute.java index 5d573ed2e7..a0be6d1cd2 100644 --- a/core/src/mindustry/world/meta/Attribute.java +++ b/core/src/mindustry/world/meta/Attribute.java @@ -21,7 +21,7 @@ public class Attribute{ /** Used for sand extraction. */ sand = add("sand"), /** Used for erekir vents only. */ - vent = add("vent"); + steam = add("steam"); public final int id; public final String name; diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 2cb796e7d3..9788eaef66 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -765,7 +765,7 @@ public class ApplicationTests{ @Test void allBlockTest(){ - Tiles tiles = world.resize(256 * 4 + 20, 10); + Tiles tiles = world.resize(80, 80); world.beginMapLoad(); for(int x = 0; x < tiles.width; x++){ @@ -773,14 +773,24 @@ public class ApplicationTests{ tiles.set(x, y, new Tile(x, y, Blocks.stone, Blocks.air, Blocks.air)); } } - int i = 0; + int maxHeight = 0; + state.rules.canGameOver = false; + state.rules.borderDarkness = false; - for(int x = 5; x < tiles.width && i < content.blocks().size; ){ - Block block = content.block(i++); + for(int x = 0, y = 0, i = 0; i < content.blocks().size; i ++){ + Block block = content.block(i); if(block.canBeBuilt()){ + int offset = Math.max(block.size % 2 == 0 ? block.size/2 - 1 : block.size/2, 0); + + if(x + block.size + 1 >= world.width()){ + y += maxHeight; + maxHeight = 0; + x = 0; + } + + tiles.get(x + offset, y + offset).setBlock(block); x += block.size; - tiles.get(x, 5).setBlock(block); - x += block.size; + maxHeight = Math.max(maxHeight, block.size); } } world.endMapLoad(); @@ -903,14 +913,16 @@ public class ApplicationTests{ if(state.rules.attackMode){ bossWave = 100; }else{ - assertNotEquals(0, bossWave, "Sector doesn't have a boss wave."); + assertNotEquals(0, bossWave, "Sector doesn't have a boss/end wave."); } + if(state.rules.winWave > 0) bossWave = state.rules.winWave - 1; + //TODO check for difficulty? for(int i = 1; i <= bossWave; i++){ int total = 0; for(SpawnGroup spawn : spawns){ - total += spawn.getSpawned(i); + total += spawn.getSpawned(i - 1); } assertNotEquals(0, total, "Sector " + zone + " has no spawned enemies at wave " + i); diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index 457421a85c..5c50a70d1c 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -95,13 +95,7 @@ public class PowerTestFixture{ // Simulate the "changed" method. Calling it through reflections would require half the game to be initialized. tile.build = block.newBuilding().init(tile, Team.sharded, false, 0); if(block.hasPower){ - new PowerGraph(){ - //assume there's always something consuming power - @Override - public float getUsageFraction(){ - return 1f; - } - }.add(tile.build); + new PowerGraph().add(tile.build); } // Assign incredibly high health so the block does not get destroyed on e.g. burning Blast Compound diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 1e358fb140..6a76e1ce8b 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -275,7 +275,7 @@ public class Generators{ } } - Fi.get("cracks-" + size + "-" + i + ".png").writePng(output); + Fi.get("../rubble/cracks-" + size + "-" + i + ".png").writePng(output); } } }); @@ -560,6 +560,16 @@ public class Generators{ Pixmap image = type.segments > 0 ? get(type.segmentRegions[0]) : outline.get(get(type.region)); + Func weaponRegion = weapon -> Core.atlas.has(weapon.name + "-preview") ? get(weapon.name + "-preview") : get(weapon.region); + Cons2 drawWeapon = (weapon, pixmap) -> + image.draw(weapon.flipSprite ? pixmap.flipX() : pixmap, + (int)(weapon.x / Draw.scl + image.width / 2f - weapon.region.width / 2f), + (int)(-weapon.y / Draw.scl + image.height / 2f - weapon.region.height / 2f), + true + ); + + boolean anyUnder = false; + //draw each extra segment on top before it is saved as outline if(sample instanceof Crawlc){ for(int i = 0; i < type.segments; i++){ @@ -579,6 +589,17 @@ public class Generators{ replace(type.name, image); } + //draw weapons that are under the base + for(Weapon weapon : weapons.select(w -> w.layerOffset < 0)){ + drawWeapon.get(weapon, outline.get(weaponRegion.get(weapon))); + anyUnder = true; + } + + //draw over the weapons under the image + if(anyUnder){ + image.draw(outline.get(get(type.region)), true); + } + //draw treads if(sample instanceof Tankc){ image.draw(outline.get(get(type.treadRegion)), true); @@ -593,14 +614,12 @@ public class Generators{ image.draw(get(type.region), true); } - //TODO draw under for layerOffset < 0 //draw weapon outlines on base for(Weapon weapon : weapons){ - image.draw(weapon.flipSprite ? outline.get(get(weapon.region)).flipX() : outline.get(get(weapon.region)), - (int)(weapon.x / Draw.scl + image.width / 2f - weapon.region.width / 2f), - (int)(-weapon.y / Draw.scl + image.height / 2f - weapon.region.height / 2f), - true - ); + //skip weapons under unit + if(weapon.layerOffset < 0) continue; + + drawWeapon.get(weapon, outline.get(weaponRegion.get(weapon))); } //draw base region on top to mask weapons @@ -610,24 +629,23 @@ public class Generators{ Pixmap baseCell = get(type.cellRegion); Pixmap cell = baseCell.copy(); - //replace with 0xffd37fff : 0xdca463ff for sharded colors? - cell.replace(in -> in == 0xffffffff ? 0xffa664ff : in == 0xdcc6c6ff || in == 0xdcc5c5ff ? 0xd06b53ff : 0); + //replace with 0xffd37fff : 0xdca463ff for sharded colors? + cell.replace(in -> in == 0xffffffff ? 0xffa664ff : in == 0xdcc6c6ff || in == 0xdcc5c5ff ? 0xd06b53ff : 0); image.draw(cell, image.width / 2 - cell.width / 2, image.height / 2 - cell.height / 2, true); } for(Weapon weapon : weapons){ - Pixmap wepReg = weapon.top ? outline.get(get(weapon.region)) : get(weapon.region); - if(weapon.flipSprite){ - wepReg = wepReg.flipX(); - } + //skip weapons under unit + if(weapon.layerOffset < 0) continue; - image.draw(wepReg, - (int)(weapon.x / Draw.scl + image.width / 2f - weapon.region.width / 2f), - (int)(-weapon.y / Draw.scl + image.height / 2f - weapon.region.height / 2f), - true); + Pixmap reg = weaponRegion.get(weapon); + Pixmap wepReg = weapon.top ? outline.get(reg) : reg; + + drawWeapon.get(weapon, wepReg); } + //TODO I can save a LOT of space by not creating a full icon. save(image, "unit-" + type.name + "-full"); Rand rand = new Rand();