diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties index 922fe9f5e4..555d72975c 100644 --- a/annotations/src/main/resources/classids.properties +++ b/annotations/src/main/resources/classids.properties @@ -40,4 +40,5 @@ spiroct=21 timed=38 timedDef=37 toxopid=33 +vanquish=40 vela=25 \ No newline at end of file diff --git a/annotations/src/main/resources/revisions/vanquish/0.json b/annotations/src/main/resources/revisions/vanquish/0.json new file mode 100644 index 0000000000..7f2885cdcf --- /dev/null +++ b/annotations/src/main/resources/revisions/vanquish/0.json @@ -0,0 +1 @@ +{fields:[{name:ammo,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq},{name:team,type:mindustry.game.Team},{name:type,type:mindustry.type.UnitType},{name:updateBuilding,type:boolean},{name:vel,type:arc.math.geom.Vec2},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/assets-raw/sprites/units/vanquish-cell.png b/core/assets-raw/sprites/units/vanquish-cell.png new file mode 100644 index 0000000000..46c91ead15 Binary files /dev/null and b/core/assets-raw/sprites/units/vanquish-cell.png differ diff --git a/core/assets-raw/sprites/units/vanquish-treads.png b/core/assets-raw/sprites/units/vanquish-treads.png new file mode 100644 index 0000000000..dea46d155e Binary files /dev/null and b/core/assets-raw/sprites/units/vanquish-treads.png differ diff --git a/core/assets-raw/sprites/units/vanquish.png b/core/assets-raw/sprites/units/vanquish.png index d8ec8ea8a9..118b862018 100644 Binary files a/core/assets-raw/sprites/units/vanquish.png and b/core/assets-raw/sprites/units/vanquish.png differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 8e10964f1d..a00581b2f6 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -483,3 +483,4 @@ 63223=phase-heater|block-phase-heater-ui 63222=arkyic-wall|block-arkyic-wall-ui 63221=heat-redirector|block-heat-redirector-ui +63220=vanquish|unit-vanquish-ui diff --git a/core/assets/logicids.dat b/core/assets/logicids.dat index 7125675ef5..0e15c2ddf1 100644 Binary files a/core/assets/logicids.dat and b/core/assets/logicids.dat differ diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index df994eac68..ebdd90c805 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -15,6 +15,7 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.type.ammo.*; +import mindustry.type.unit.*; import mindustry.type.weapons.*; import mindustry.world.meta.*; @@ -70,6 +71,10 @@ public class UnitTypes{ //transport public static @EntityDef({Unitc.class, BuildingTetherc.class}) UnitType manifold; + //tank + //TODO tank comp + public static @EntityDef({Unitc.class, Tankc.class}) UnitType vanquish; + //endregion //missile definition, needed for codegen @@ -1372,8 +1377,8 @@ public class UnitTypes{ lowAltitude = false; flying = true; circleTarget = true; - engineOffset = 12f; - engineSize = 6f; + engineOffset = 13f; + engineSize = 7f; rotateShooting = false; hitSize = 36f; payloadCapacity = (3 * 3) * tilePayload; @@ -2419,6 +2424,13 @@ public class UnitTypes{ }}); }}; + //endregion + //region erekir - tank + + vanquish = new TankUnitType("vanquish"){{ + hitSize = 28f; + }}; + //endregion //region erekir - core diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index a503241116..1a94f29fd6 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -11,9 +11,7 @@ import mindustry.world.*; import static mindustry.Vars.*; public class EntityCollisions{ - //range for tile collision scanning - private static final int r = 1; - //move in 1-unit chunks + //move in 1-unit chunks (can this be made more efficient?) private static final float seg = 1f; //tile collisions @@ -42,10 +40,12 @@ public class EntityCollisions{ if(Math.abs(deltax) < 0.0001f & Math.abs(deltay) < 0.0001f) return; boolean movedx = false; + entity.hitboxTile(r1); + int r = Math.max(Math.round(r1.width / tilesize), 1); while(Math.abs(deltax) > 0 || !movedx){ movedx = true; - moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true, solidCheck); + moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, r, true, solidCheck); if(Math.abs(deltax) >= seg){ deltax -= seg * Mathf.sign(deltax); @@ -58,7 +58,7 @@ public class EntityCollisions{ while(Math.abs(deltay) > 0 || !movedy){ movedy = true; - moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false, solidCheck); + moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), r, false, solidCheck); if(Math.abs(deltay) >= seg){ deltay -= seg * Mathf.sign(deltay); @@ -68,7 +68,7 @@ public class EntityCollisions{ } } - public void moveDelta(Hitboxc entity, float deltax, float deltay, boolean x, SolidPred solidCheck){ + public void moveDelta(Hitboxc entity, float deltax, float deltay, int r, boolean x, SolidPred solidCheck){ entity.hitboxTile(r1); entity.hitboxTile(r2); r1.x += deltax; diff --git a/core/src/mindustry/entities/comp/HitboxComp.java b/core/src/mindustry/entities/comp/HitboxComp.java index 6fdab58a3e..a444f350ab 100644 --- a/core/src/mindustry/entities/comp/HitboxComp.java +++ b/core/src/mindustry/entities/comp/HitboxComp.java @@ -69,6 +69,9 @@ abstract class HitboxComp implements Posc, Sized, QuadTreeObject{ public void hitboxTile(Rect rect){ //tile hitboxes are never bigger than a tile, otherwise units get stuck float size = Math.min(hitSize * 0.66f, 7.9f); + //TODO: better / more accurate version is + //float size = hitSize * 0.85f; + //- for tanks? rect.setCentered(x, y, size, size); } } diff --git a/core/src/mindustry/entities/comp/TankComp.java b/core/src/mindustry/entities/comp/TankComp.java new file mode 100644 index 0000000000..f721b13bb3 --- /dev/null +++ b/core/src/mindustry/entities/comp/TankComp.java @@ -0,0 +1,63 @@ +package mindustry.entities.comp; + +import arc.math.geom.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; +import mindustry.type.*; +import mindustry.world.blocks.environment.*; + +import static mindustry.Vars.*; + +@Component +abstract class TankComp implements Posc, Flyingc, Hitboxc, Unitc, ElevationMovec{ + @Import float x, y, hitSize; + @Import UnitType type; + + transient float treadTime; + transient boolean walked; + + @Override + public void update(){ + //trigger animation only when walking manually + if(walked || net.client()){ + float len = deltaLen(); + treadTime += len; + walked = false; + } + + //TODO treads should create dust, see MechComp + } + + @Replace + @Override + public @Nullable Floor drownFloor(){ + //tanks can only drown when all the nearby floors are deep + //TODO implement properly + 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; + } + + @Override + public void moveAt(Vec2 vector, float acceleration){ + //mark walking state when moving in a controlled manner + if(!vector.isZero()){ + walked = true; + } + } + + @Override + public void approach(Vec2 vector){ + //mark walking state when moving in a controlled manner + if(!vector.isZero(0.001f)){ + walked = true; + } + } +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index f8a9e780a7..b0dc05cc95 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -71,7 +71,10 @@ public class UnitType extends UnlockableContent{ public boolean createWreck = true; public boolean useUnitCap = true; public boolean destructibleWreck = true; - public boolean squareShadow = false; + /** If true, this modded unit always has a -outline region generated for its base. Normally, outlines are ignored if there are no top = false weapons. */ + public boolean alwaysCreateOutline = false; + /** If true, this unit has a square shadow. TODO physics? */ + public boolean squareShape = false; public float groundLayer = Layer.groundUnit; public float payloadCapacity = 8; public float aimDst = -1f; @@ -162,7 +165,7 @@ public class UnitType extends UnlockableContent{ public Seq weapons = new Seq<>(); public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, - softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion; + softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion, treadRegion; public TextureRegion[] wreckRegions; public TextureRegion[] segmentRegions, segmentOutlineRegions; @@ -494,12 +497,13 @@ public class UnitType extends UnlockableContent{ jointRegion = Core.atlas.find(name + "-joint"); baseJointRegion = Core.atlas.find(name + "-joint-base"); footRegion = Core.atlas.find(name + "-foot"); + treadRegion = Core.atlas.find(name + "-treads"); legBaseRegion = Core.atlas.find(name + "-leg-base", name + "-leg"); baseRegion = Core.atlas.find(name + "-base"); cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell")); //when linear filtering is on, it's acceptable to use the relatively low-res 'particle' region softShadowRegion = - squareShadow ? Core.atlas.find("square-shadow") : + squareShape ? Core.atlas.find("square-shadow") : hitSize <= 10f || (Core.settings != null && Core.settings.getBool("linear", true)) ? Core.atlas.find("particle") : Core.atlas.find("circle-shadow"); @@ -522,16 +526,16 @@ public class UnitType extends UnlockableContent{ clipSize = Math.max(region.width * 2f, clipSize); } - private void makeOutline(MultiPacker packer, TextureRegion region){ + private void makeOutline(MultiPacker packer, TextureRegion region, boolean makeNew){ if(region instanceof AtlasRegion at && region.found()){ String name = at.name; - if(!packer.has(name + "-outline")){ + if(!makeNew || !packer.has(name + "-outline")){ PixmapRegion base = Core.atlas.getPixmap(region); var result = Pixmaps.outline(base, outlineColor, outlineRadius); if(Core.settings.getBool("linear", true)){ Pixmaps.bleed(result); } - packer.add(PageType.main, name + "-outline", result); + packer.add(PageType.main, name + (makeNew ? "-outline" : ""), result); } } } @@ -542,10 +546,13 @@ public class UnitType extends UnlockableContent{ //currently does not create outlines for legs or base regions due to older mods having them outlined by default if(outlines){ - makeOutline(packer, region); + + //outlines only created when weapons are drawn under w/ merged outlines + makeOutline(packer, region, alwaysCreateOutline || weapons.contains(w -> !w.top)); + for(Weapon weapon : weapons){ if(!weapon.name.isEmpty()){ - makeOutline(packer, weapon.region); + makeOutline(packer, weapon.region, true); } } } @@ -686,6 +693,10 @@ public class UnitType extends UnlockableContent{ unit.trns(legOffset.x, legOffset.y); } + if(unit instanceof Tankc){ + drawTank((Unit & Tankc)unit); + } + if(unit instanceof Legsc){ drawLegs((Unit & Legsc)unit); } @@ -950,6 +961,10 @@ public class UnitType extends UnlockableContent{ } } + public void drawTank(T unit){ + Draw.rect(treadRegion, unit.x, unit.y, unit.rotation - 90); + } + public void drawLegs(T unit){ applyColor(unit); Tmp.c3.set(Draw.getMixColor()); diff --git a/core/src/mindustry/type/MissileUnitType.java b/core/src/mindustry/type/unit/MissileUnitType.java similarity index 93% rename from core/src/mindustry/type/MissileUnitType.java rename to core/src/mindustry/type/unit/MissileUnitType.java index 9052090f57..2ff78936ef 100644 --- a/core/src/mindustry/type/MissileUnitType.java +++ b/core/src/mindustry/type/unit/MissileUnitType.java @@ -1,7 +1,8 @@ -package mindustry.type; +package mindustry.type.unit; import mindustry.ai.types.*; import mindustry.gen.*; +import mindustry.type.*; import mindustry.world.meta.*; /** Field template for unit types. No new functionality. */ diff --git a/core/src/mindustry/type/NeoplasmUnitType.java b/core/src/mindustry/type/unit/NeoplasmUnitType.java similarity index 94% rename from core/src/mindustry/type/NeoplasmUnitType.java rename to core/src/mindustry/type/unit/NeoplasmUnitType.java index 5bc673193e..fe331ce3b3 100644 --- a/core/src/mindustry/type/NeoplasmUnitType.java +++ b/core/src/mindustry/type/unit/NeoplasmUnitType.java @@ -1,8 +1,9 @@ -package mindustry.type; +package mindustry.type.unit; import mindustry.content.*; import mindustry.entities.abilities.*; import mindustry.graphics.*; +import mindustry.type.*; /** This is just a preset. Contains no new behavior. */ public class NeoplasmUnitType extends UnitType{ diff --git a/core/src/mindustry/type/unit/TankUnitType.java b/core/src/mindustry/type/unit/TankUnitType.java new file mode 100644 index 0000000000..ca5597f19d --- /dev/null +++ b/core/src/mindustry/type/unit/TankUnitType.java @@ -0,0 +1,21 @@ +package mindustry.type.unit; + +import mindustry.graphics.*; +import mindustry.type.*; +import mindustry.world.meta.*; + +public class TankUnitType extends UnitType{ + + public TankUnitType(String name){ + super(name); + + squareShape = true; + omniMovement = false; + rotateSpeed = 1.3f; + envDisabled = Env.none; + speed = 0.8f; + outlineColor = Pal.darkOutline; + } + + +} diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index 88e055c3d0..b31e5bed42 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -72,7 +72,7 @@ public class ImpactReactor extends PowerGenerator{ } public class ImpactReactorBuild extends GeneratorBuild{ - public float warmup; + public float warmup, totalProgress; @Override public void updateTile(){ @@ -95,9 +95,16 @@ public class ImpactReactor extends PowerGenerator{ warmup = Mathf.lerpDelta(warmup, 0f, 0.01f); } + totalProgress += warmup * Time.delta; + productionEfficiency = Mathf.pow(warmup, 5f); } + @Override + public float totalProgress(){ + return totalProgress; + } + @Override public float ambientVolume(){ return warmup; @@ -113,7 +120,7 @@ public class ImpactReactor extends PowerGenerator{ Draw.color(plasma1, plasma2, (float)i / plasmaRegions.length); Draw.alpha((0.3f + Mathf.absin(Time.time, 2f + i * 2f, 0.3f + i * 0.05f)) * warmup); - Draw.rect(plasmaRegions[i], x, y, r, r, Time.time * (12 + i * 6f) * warmup); + Draw.rect(plasmaRegions[i], x, y, r, r, totalProgress * (12 + i * 6f)); } Draw.blend(); diff --git a/gradle.properties b/gradle.properties index 074ee130ec..bf6d009b07 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,4 +24,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 -archash=f8264ffafe +archash=de5a78a868 diff --git a/tools/build.gradle b/tools/build.gradle index a6b527ae39..56758d2ed0 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -25,6 +25,7 @@ import java.util.concurrent.Executors def genFolder = "../core/assets-raw/sprites_out/generated/" def doAntialias = !project.hasProperty("disableAntialias") def colorMap = new IntMap>(), colorIndexMap = new IntIntMap() +def enableAA = true //on my machine, I have a native Nim AA implementation that is ~10x faster //it's not compiled for other platforms so they don't get it def useFastAA = project.hasProperty("fastAA") || System.getProperty("user.name") == "anuke" @@ -222,22 +223,24 @@ task pack(dependsOn: [classes, configurations.runtimeClasspath]){ delete "../core/assets-raw/sprites_out/ui/icons" } - ExecutorService executor = Executors.newFixedThreadPool(16) - long ms = System.currentTimeMillis() + if(enableAA){ + ExecutorService executor = Executors.newFixedThreadPool(16) + long ms = System.currentTimeMillis() - //antialias everything except UI elements - fileTree(dir: new File(rootDir, 'core/assets-raw/sprites_out/').absolutePath, include: "**/*.png").visit{ file -> - if(file.isDirectory() || (file.toString().replace("\\", "/").contains("/ui/") && file.toString().startsWith("icon-")) || file.toString().contains(".9.png")) return + //antialias everything except UI elements + fileTree(dir: new File(rootDir, 'core/assets-raw/sprites_out/').absolutePath, include: "**/*.png").visit{ file -> + if(file.isDirectory() || (file.toString().replace("\\", "/").contains("/ui/") && file.toString().startsWith("icon-")) || file.toString().contains(".9.png")) return - executor.submit{ - antialias(file.file) + executor.submit{ + antialias(file.file) + } } + + Threads.await(executor) + + println "Time taken for AA: ${(System.currentTimeMillis() - ms) / 1000f}" } - Threads.await(executor) - - println "Time taken for AA: ${(System.currentTimeMillis() - ms) / 1000f}" - println("\n\nPacking normal 4096 sprites...\n\n") //pack normal sprites diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index c8bebc23d4..4ffc842f12 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -514,6 +514,7 @@ public class Generators{ outliner.get(type.legBaseRegion); outliner.get(type.baseJointRegion); if(sample instanceof Legsc) outliner.get(type.legRegion); + if(sample instanceof Tankc) outliner.get(type.treadRegion); Pixmap image = type.segments > 0 ? get(type.segmentRegions[0]) : outline.get(get(type.region)); @@ -529,7 +530,12 @@ public class Generators{ save(image, type.name); } - save(image, type.name + "-outline"); + //outline only needs to be different if there's a weapon that draws under; most units don't have this, and it saves significant space. + if(type.weapons.contains(w -> !w.top)){ + save(image, type.name + "-outline"); + }else{ + replace(type.name, image); + } //draw mech parts if(sample instanceof Mechc){