From 307943c098b99bf215675df0bce96832b0cef194 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 13 May 2023 02:41:04 -0400 Subject: [PATCH 0001/1150] Update SERVERLIST.md --- SERVERLIST.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SERVERLIST.md b/SERVERLIST.md index b3dbebe0ca..2afe0b887e 100644 --- a/SERVERLIST.md +++ b/SERVERLIST.md @@ -1,7 +1,7 @@ ### Adding a server to the list Mindustry now has a public list of servers that everyone can see and connect to. -This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json) in this repository. +This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers_v7.json) in this repository. You may want to add your server to this list. The steps for getting this done are as follows: @@ -18,7 +18,7 @@ You'll need to either hire some moderators, or make use of (currently non-existe 4. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option. 5. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`). 6. Finally, **submit a pull request** to add your server's IP to the list. -This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json), then add a JSON object with a single key, indicating your server address. +This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers_v7.json), then add a JSON object with a single key, indicating your server address. For example, if your server address is `example.com:6000`, you would add a comma after the last entry and insert: ```json { From b40615d9e6dff2afe89506861780399782c457f6 Mon Sep 17 00:00:00 2001 From: buthed010203 Date: Sat, 13 May 2023 09:48:32 -0400 Subject: [PATCH 0002/1150] Fix crash (#8599) --- core/src/mindustry/input/InputHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index ba33d0cef2..8d5eab1901 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -469,7 +469,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ build.updateProximity(); build.noSleep(); Fx.rotateBlock.at(build.x, build.y, build.block.size); - Events.fire(new BuildRotateEvent(build, player.unit(), previous)); + Events.fire(new BuildRotateEvent(build, player == null ? null : player.unit(), previous)); } @Remote(targets = Loc.both, called = Loc.both, forward = true) From 5ec0e9dc9f66e6a5eb84326f7288430cbe251a87 Mon Sep 17 00:00:00 2001 From: BalaM314 <71201189+BalaM314@users.noreply.github.com> Date: Sat, 13 May 2023 19:23:47 +0530 Subject: [PATCH 0003/1150] Use shouldExplode, explosionMinWarmup in generators (#8600) --- core/src/mindustry/world/blocks/power/ImpactReactor.java | 8 +------- core/src/mindustry/world/blocks/power/NuclearReactor.java | 6 ++---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index e0336abb53..136cf66b46 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -36,6 +36,7 @@ public class ImpactReactor extends PowerGenerator{ explosionShake = 6f; explosionShakeDuration = 16f; explosionDamage = 1900 * 4; + explosionMinWarmup = 0.3f; explodeEffect = Fx.impactReactorExplosion; explodeSound = Sounds.explosionbig; } @@ -110,13 +111,6 @@ public class ImpactReactor extends PowerGenerator{ return super.sense(sensor); } - @Override - public void createExplosion(){ - if(warmup >= 0.3f){ - super.createExplosion(); - } - } - @Override public void write(Writes write){ super.write(write); diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java index 63b4c90d57..8e28d5b331 100644 --- a/core/src/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java @@ -128,10 +128,8 @@ public class NuclearReactor extends PowerGenerator{ } @Override - public void createExplosion(){ - if(items.get(fuelItem) >= 5 || heat >= 0.5f){ - super.createExplosion(); - } + public boolean shouldExplode(){ + return super.shouldExplode() && (items.get(fuelItem) >= 5 || heat >= 0.5f); } @Override From 89e942ee35640fa36dbe4fdab5a6bff5c8b5b7a5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 13 May 2023 10:51:05 -0400 Subject: [PATCH 0004/1150] Fixed #8602 --- core/src/mindustry/entities/comp/BuilderComp.java | 8 ++++++++ core/src/mindustry/world/blocks/storage/CoreBlock.java | 6 ------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 0f77f2a940..b380e82af8 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -47,6 +47,14 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{ updateBuildLogic(); } + @Override + public void afterRead(){ + //why would this happen? + if(plans == null){ + plans = new Queue<>(1); + } + } + public void validatePlans(){ if(plans.size > 0){ Iterator it = plans.iterator(); diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index d0a5bebda5..aa0ed7ba29 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -492,12 +492,6 @@ public class CoreBlock extends StorageBlock{ storageCapacity = itemCapacity + proximity().sum(e -> owns(e) ? e.block.itemCapacity : 0); proximity.each(this::owns, t -> { - //add inventory if there is something in it from a payload - if(t.items != items){ - items.add(t.items); - t.items.clear(); - } - t.items = items; ((StorageBuild)t).linkedCore = this; }); From 151743021bb06de2ab2776fd4120f20d69ef6e2f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 13 May 2023 18:22:01 -0400 Subject: [PATCH 0005/1150] Latest RoboVM --- ios/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/build.gradle b/ios/build.gradle index a440c4a8c3..d0ec38f0a9 100644 --- a/ios/build.gradle +++ b/ios/build.gradle @@ -4,7 +4,7 @@ buildscript{ } dependencies{ - classpath "com.mobidevelop.robovm:robovm-gradle-plugin:2.3.18" + classpath "com.mobidevelop.robovm:robovm-gradle-plugin:2.3.19" } } From 738b96b94b7edaa98c95cbec432a7da718e305ab Mon Sep 17 00:00:00 2001 From: HamzaGSopp <104453337+HamzaGSopp@users.noreply.github.com> Date: Sun, 14 May 2023 22:50:20 +0200 Subject: [PATCH 0006/1150] Update servers_v7.json (#8606) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 34796e9833..54324cd37c 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -1,7 +1,7 @@ [ { "name": "Tamazia", - "address": ["83.150.217.98:25566", "83.150.217.98:25568"] + "address": ["83.150.217.98:25573", "83.150.217.98:25566", "83.150.217.98:25568"] }, { "name": "RCM", From 30c773b304bf93e521a868b95a5d6062fca222e9 Mon Sep 17 00:00:00 2001 From: BeDanGames <92419640+BeDanGames@users.noreply.github.com> Date: Mon, 15 May 2023 19:53:54 +0700 Subject: [PATCH 0007/1150] Update servers_v7.json (#8611) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 54324cd37c..4a7c98d4c4 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -138,7 +138,7 @@ }, { "name": "|RussianServers|[]", - "address": ["2p2g.ml:6568", "2p2g.ml:6569", "2p2g.ml:6570", "2p2g.ml:6571", "2p2g.ml:6572", "2p2g.ml:6573"] + "address": ["2p2g.ml:6567", "2p2g.ml:6568", "2p2g.ml:6569", "2p2g.ml:6570", "2p2g.ml:6571", "2p2g.ml:6572", "2p2g.ml:6573"] }, { "name": "Hungarian", From 9b02d2685624fb5deba28b7d947304d97fbb9c9c Mon Sep 17 00:00:00 2001 From: Vojtak42 Date: Mon, 15 May 2023 14:54:07 +0200 Subject: [PATCH 0008/1150] Update bundle_cs.properties (#8610) --- core/assets/bundles/bundle_cs.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index d46ecbc12b..fb73b156a5 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -767,7 +767,7 @@ sector.fungalPass.description = Přechodová oblast mezi vysokými horami a spó sector.biomassFacility.description = Prapůvod všech spór. Toto je zařízení, be kterém byly spóry vynalezeny a zpočátku u vyráběny.\nVynalezni technologii, která se skrýbá uvnitř. Kultivuj spóry k výrobě paliva a plastů.\n\n[lightgray]Po vypnutí tohoto zařízení byly spóry vypuštěny. V okolním ekosystému však tomuto invazivnímu druhu nebylo nic schopné konkurovat. sector.windsweptIslands.description = Vzdálen od pevniny je tento řetízek ostrovů. Záznamy ukazují, že zde kdysi byly zařízení na výrobu [accent]Plastany[].\n\nPoraž nepřátelské námořní jednotky. Vybuduj základnu na ostrově. Vynalezni továrny. sector.extractionOutpost.description = Vzdálená pevnost, postavená nepřítelem za účelem vysílání zdrojů do okolních sektorů.\n\nDoprava položek napříč sektory je nezbytná pro lapení dalších sektorů. Znič základnu. Vyzkoumej jejich Vysílací plošiny. -sector.impact0078.description = Zde leží zbytky mezihvězdné lodi, která vstoupila d otohoto systému.\n\nZachraň z vraku vše, co se dá. Vyzkoumej nepoškozenou technologii. +sector.impact0078.description = Zde leží zbytky mezihvězdné lodi, která vstoupila do tohoto systému.\n\nZachraň z vraku vše, co se dá. Vyzkoumej nepoškozenou technologii. sector.planetaryTerminal.description = Konečný cíl.\n\nTato pobřežní základna obsahuje konstrukce schopné vyslat jádra na okolní planety. Je mimořádně dobře opevněna.\n\nVyrob námořní jednotky. Odstraň nepřítele tak rychle, jak umíš. Vyzkoumej vysílací konstrukci. sector.coastline.description = Remnants of naval unit technology have been detected at this location. Repel the enemy attacks, capture this sector, and acquire the technology. sector.navalFortress.description = The enemy has established a base on a remote, naturally-fortified island. Destroy this outpost. Acquire their advanced naval craft technology, and research it. From aa7ba6548cd05b1832098c7166e9b77db45313bc Mon Sep 17 00:00:00 2001 From: GlennFolker <63218676+GlennFolker@users.noreply.github.com> Date: Mon, 15 May 2023 20:59:14 +0700 Subject: [PATCH 0009/1150] Move most planet rendering out of PlanetRenderer to Planet (#8608) * Planet speaks for itself * Ok fine keep old Gradle version * Planet grid mesh builder * Inline --- .../mindustry/graphics/g3d/MeshBuilder.java | 21 ++++ .../graphics/g3d/PlanetRenderer.java | 114 +---------------- core/src/mindustry/type/Planet.java | 115 +++++++++++++++++- .../mindustry/ui/dialogs/PlanetDialog.java | 8 +- 4 files changed, 144 insertions(+), 114 deletions(-) diff --git a/core/src/mindustry/graphics/g3d/MeshBuilder.java b/core/src/mindustry/graphics/g3d/MeshBuilder.java index 64d9ef8ec6..af2a7e040f 100644 --- a/core/src/mindustry/graphics/g3d/MeshBuilder.java +++ b/core/src/mindustry/graphics/g3d/MeshBuilder.java @@ -29,6 +29,27 @@ public class MeshBuilder{ return buildIcosphere(divisions, radius, Color.white); } + public static Mesh buildPlanetGrid(PlanetGrid grid, Color color, float scale){ + int total = 0; + for(Ptile tile : grid.tiles){ + total += tile.corners.length * 2; + } + + begin(total * (3 + 3 + 1)); + for(Ptile tile : grid.tiles){ + Corner[] c = tile.corners; + for(int i = 0; i < c.length; i++){ + Vec3 a = v1.set(c[i].v).scl(scale); + Vec3 b = v2.set(c[(i + 1) % c.length].v).scl(scale); + + vert(a, Vec3.Z, color); + vert(b, Vec3.Z, color); + } + } + + return end(); + } + public static Mesh buildHex(Color color, int divisions, boolean lines, float radius){ return buildHex(new HexMesher(){ @Override diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index 1af20f68ed..80f95767c7 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -22,14 +22,11 @@ public class PlanetRenderer implements Disposable{ borderColor = Pal.accent.cpy().a(0.3f), shadowColor = new Color(0, 0, 0, 0.7f); - private static final Seq points = new Seq<>(); - /** Camera used for rendering. */ public final Camera3D cam = new Camera3D(); /** Raw vertex batch. */ public final VertexBatch3D batch = new VertexBatch3D(20000, false, true, 0); - 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); @@ -179,26 +176,7 @@ public class PlanetRenderer implements Disposable{ public void renderSectors(Planet planet, PlanetParams params){ if(params.uiAlpha <= 0.02f) return; - - //apply transformed position - batch.proj().mul(planet.getTransform(mat)); - - if(params.renderer != null){ - params.renderer.renderSectors(planet); - } - - //render sector grid - float scaledOutlineRad = outlineRad * planet.radius; - Mesh mesh = outline(planet.grid.size, planet.radius); - Shader shader = Shaders.planetGrid; - Vec3 tile = planet.intersect(cam.getMouseRay(), scaledOutlineRad); - Shaders.planetGrid.mouse.lerp(tile == null ? Vec3.Zero : tile.sub(planet.position).rotate(Vec3.Y, planet.getRotation()), 0.2f); - - shader.bind(); - shader.setUniformMatrix4("u_proj", cam.combined.val); - shader.setUniformMatrix4("u_trans", planet.getTransform(mat).val); - shader.apply(); - mesh.render(shader, Gl.lines); + planet.renderSectors(batch, cam, params); } public void drawArc(Planet planet, Vec3 a, Vec3 b){ @@ -210,48 +188,11 @@ public class PlanetRenderer implements Disposable{ } public void drawArc(Planet planet, Vec3 a, Vec3 b, Color from, Color to, float length, float timeScale, int pointCount){ - //increase curve height when on opposite side of planet, so it doesn't tunnel through - float scaledOutlineRad = outlineRad * planet.radius; - float dot = 1f - (Tmp.v32.set(a).nor().dot(Tmp.v33.set(b).nor()) + 1f)/2f; - - Vec3 avg = Tmp.v31.set(b).add(a).scl(0.5f); - avg.setLength(planet.radius*(1f+length) + dot * 1.35f); - - points.clear(); - points.addAll(Tmp.v33.set(b).setLength(scaledOutlineRad), Tmp.v31, Tmp.v34.set(a).setLength(scaledOutlineRad)); - Tmp.bz3.set(points); - - for(int i = 0; i < pointCount + 1; i++){ - float f = i / (float)pointCount; - Tmp.c1.set(from).lerp(to, (f+ Time.globalTime /timeScale)%1f); - batch.color(Tmp.c1); - batch.vertex(Tmp.bz3.valueAt(Tmp.v32, f)); - } - batch.flush(Gl.lineStrip); + planet.drawArc(batch, a, b, from, to, length, timeScale, pointCount); } public void drawBorders(Sector sector, Color base, float alpha){ - Color color = Tmp.c1.set(base).a((base.a + 0.3f + Mathf.absin(Time.globalTime, 5f, 0.3f)) * alpha); - - float r1 = 1f * sector.planet.radius; - float r2 = outlineRad * sector.planet.radius + 0.001f; - - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; - - Tmp.v31.set(c.v).setLength(r2); - Tmp.v32.set(next.v).setLength(r2); - Tmp.v33.set(c.v).setLength(r1); - - batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); - - Tmp.v31.set(next.v).setLength(r2); - Tmp.v32.set(next.v).setLength(r1); - Tmp.v33.set(c.v).setLength(r1); - - batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); - } - + sector.planet.drawBorders(batch, sector, base, alpha); if(batch.getNumVertices() >= batch.getMaxVertices() - 6 * 6){ batch.flush(Gl.triangles); } @@ -279,11 +220,7 @@ public class PlanetRenderer implements Disposable{ } public void fill(Sector sector, Color color, float offset){ - float rr = outlineRad * sector.planet.radius + offset; - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; - batch.tri(Tmp.v31.set(c.v).setLength(rr), Tmp.v32.set(next.v).setLength(rr), Tmp.v33.set(sector.tile.v).setLength(rr), color); - } + sector.planet.fill(batch, sector, color, offset); } public void drawSelection(Sector sector, float alpha){ @@ -291,43 +228,7 @@ public class PlanetRenderer implements Disposable{ } public void drawSelection(Sector sector, Color color, float stroke, float length){ - float arad = (outlineRad + length) * sector.planet.radius; - - for(int i = 0; i < sector.tile.corners.length; i++){ - Corner next = sector.tile.corners[(i + 1) % sector.tile.corners.length]; - Corner curr = sector.tile.corners[i]; - - next.v.scl(arad); - curr.v.scl(arad); - sector.tile.v.scl(arad); - - Tmp.v31.set(curr.v).sub(sector.tile.v).setLength(curr.v.dst(sector.tile.v) - stroke).add(sector.tile.v); - Tmp.v32.set(next.v).sub(sector.tile.v).setLength(next.v.dst(sector.tile.v) - stroke).add(sector.tile.v); - - batch.tri(curr.v, next.v, Tmp.v31, color); - batch.tri(Tmp.v31, next.v, Tmp.v32, color); - - sector.tile.v.scl(1f / arad); - next.v.scl(1f / arad); - curr.v.scl(1f /arad); - } - } - - public Mesh outline(int size, float radiusScale){ - if(outlines[size] == null){ - outlines[size] = MeshBuilder.buildHex(new HexMesher(){ - @Override - public float getHeight(Vec3 position){ - return 0; - } - - @Override - public Color getColor(Vec3 position){ - return outlineColor; - } - }, size, true, outlineRad * radiusScale, 0.2f); - } - return outlines[size]; + sector.planet.drawSelection(batch, sector, color, stroke, length); } @Override @@ -338,11 +239,6 @@ public class PlanetRenderer implements Disposable{ atmosphere.dispose(); buffer.dispose(); bloom.dispose(); - for(Mesh m : outlines){ - if(m != null){ - m.dispose(); - } - } } public interface PlanetInterfaceRenderer{ diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java index ee7a9bcd42..e63db3a4e8 100644 --- a/core/src/mindustry/type/Planet.java +++ b/core/src/mindustry/type/Planet.java @@ -4,6 +4,7 @@ import arc.*; import arc.func.*; import arc.graphics.*; import arc.graphics.g3d.*; +import arc.graphics.gl.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; @@ -23,14 +24,22 @@ import mindustry.world.blocks.*; import mindustry.world.meta.*; import static mindustry.Vars.*; +import static mindustry.graphics.g3d.PlanetRenderer.*; public class Planet extends UnlockableContent{ /** intersect() temp var. */ private static final Vec3 intersectResult = new Vec3(); + /** drawSectors() temp matrix. */ + private static final Mat3D mat = new Mat3D(); + /** drawArc() temp curve points. */ + private static final Seq points = new Seq<>(); + /** Mesh used for rendering. Created on load() - will be null on the server! */ public @Nullable GenericMesh mesh; /** Mesh used for rendering planet clouds. Null if no clouds are present. */ public @Nullable GenericMesh cloudMesh; + /** Mesh used for rendering planet grid outlines. Null on server or if {@link #grid} is null. */ + public @Nullable Mesh gridMesh; /** 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. */ @@ -141,6 +150,8 @@ public class Planet extends UnlockableContent{ public Seq unlockedOnLand = new Seq<>(); /** Loads the mesh. Clientside only. Defaults to a boring sphere mesh. */ public Prov meshLoader = () -> new ShaderSphereMesh(this, Shaders.unlit, 2), cloudMeshLoader = () -> null; + /** Loads the planet grid outline mesh. Clientside only. */ + public Prov gridMeshLoader = () -> MeshBuilder.buildPlanetGrid(grid, outlineColor, outlineRad * radius); public Planet(String name, Planet parent, float radius){ super(name); @@ -312,12 +323,12 @@ public class Planet extends UnlockableContent{ if(!headless){ mesh = meshLoader.get(); cloudMesh = cloudMeshLoader.get(); + if(grid != null) gridMesh = gridMeshLoader.get(); } } @Override public void init(){ - if(techTree == null){ techTree = TechTree.roots.find(n -> n.planet == this); } @@ -418,4 +429,106 @@ public class Planet extends UnlockableContent{ cloudMesh.render(params, projection, transform); } } + + /** Draws sector borders. Supply the batch with {@link Gl#triangles triangle} vertices. */ + public void drawBorders(VertexBatch3D batch, Sector sector, Color base, float alpha){ + Color color = Tmp.c1.set(base).a((base.a + 0.3f + Mathf.absin(Time.globalTime, 5f, 0.3f)) * alpha); + + float r1 = radius; + float r2 = outlineRad * radius + 0.001f; + + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; + + Tmp.v31.set(c.v).setLength(r2); + Tmp.v32.set(next.v).setLength(r2); + Tmp.v33.set(c.v).setLength(r1); + + batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); + + Tmp.v31.set(next.v).setLength(r2); + Tmp.v32.set(next.v).setLength(r1); + Tmp.v33.set(c.v).setLength(r1); + + batch.tri2(Tmp.v31, Tmp.v32, Tmp.v33, color); + } + } + + /** Draws sector plane. Supply the batch with {@link Gl#triangles triangle} vertices. */ + public void fill(VertexBatch3D batch, Sector sector, Color color, float offset){ + float rr = outlineRad * radius + offset; + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner c = sector.tile.corners[i], next = sector.tile.corners[(i+1) % sector.tile.corners.length]; + batch.tri(Tmp.v31.set(c.v).setLength(rr), Tmp.v32.set(next.v).setLength(rr), Tmp.v33.set(sector.tile.v).setLength(rr), color); + } + } + + /** Draws sector when selected. Supply the batch with {@link Gl#triangles triangle} vertices. */ + public void drawSelection(VertexBatch3D batch, Sector sector, Color color, float stroke, float length){ + float arad = (outlineRad + length) * radius; + + for(int i = 0; i < sector.tile.corners.length; i++){ + Corner next = sector.tile.corners[(i + 1) % sector.tile.corners.length]; + Corner curr = sector.tile.corners[i]; + + next.v.scl(arad); + curr.v.scl(arad); + sector.tile.v.scl(arad); + + Tmp.v31.set(curr.v).sub(sector.tile.v).setLength(curr.v.dst(sector.tile.v) - stroke).add(sector.tile.v); + Tmp.v32.set(next.v).sub(sector.tile.v).setLength(next.v.dst(sector.tile.v) - stroke).add(sector.tile.v); + + batch.tri(curr.v, next.v, Tmp.v31, color); + batch.tri(Tmp.v31, next.v, Tmp.v32, color); + + sector.tile.v.scl(1f / arad); + next.v.scl(1f / arad); + curr.v.scl(1f /arad); + } + } + + /** Renders sector outlines. */ + public void renderSectors(VertexBatch3D batch, Camera3D cam, PlanetParams params){ + //apply transformed position + batch.proj().mul(getTransform(mat)); + + if(params.renderer != null){ + params.renderer.renderSectors(this); + } + + //render sector grid + float scaledOutlineRad = outlineRad * radius; + Mesh mesh = gridMesh; + Shader shader = Shaders.planetGrid; + Vec3 tile = intersect(cam.getMouseRay(), scaledOutlineRad); + Shaders.planetGrid.mouse.lerp(tile == null ? Vec3.Zero : tile.sub(position).rotate(Vec3.Y, getRotation()), 0.2f); + + shader.bind(); + shader.setUniformMatrix4("u_proj", cam.combined.val); + shader.setUniformMatrix4("u_trans", getTransform(mat).val); + shader.apply(); + mesh.render(shader, Gl.lines); + } + + /** Draws an arc from one point to another on the planet. */ + public void drawArc(VertexBatch3D batch, Vec3 a, Vec3 b, Color from, Color to, float length, float timeScale, int pointCount){ + //increase curve height when on opposite side of planet, so it doesn't tunnel through + float scaledOutlineRad = outlineRad * radius; + float dot = 1f - (Tmp.v32.set(a).nor().dot(Tmp.v33.set(b).nor()) + 1f)/2f; + + Vec3 avg = Tmp.v31.set(b).add(a).scl(0.5f); + avg.setLength(radius * (1f + length) + dot * 1.35f); + + points.clear(); + points.addAll(Tmp.v33.set(b).setLength(scaledOutlineRad), Tmp.v31, Tmp.v34.set(a).setLength(scaledOutlineRad)); + Tmp.bz3.set(points); + + for(int i = 0; i < pointCount + 1; i++){ + float f = i / (float)pointCount; + Tmp.c1.set(from).lerp(to, (f + Time.globalTime / timeScale) % 1f); + batch.color(Tmp.c1); + batch.vertex(Tmp.bz3.valueAt(Tmp.v32, f)); + } + batch.flush(Gl.lineStrip); + } } diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 3ab79fb947..c26e3f9f2c 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -150,11 +150,11 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ @Override public void zoom(InputEvent event, float initialDistance, float distance){ - if(lastZoom < 0){ - lastZoom = zoom; - } + if(lastZoom < 0){ + lastZoom = zoom; + } - zoom = (Mathf.clamp(initialDistance / distance * lastZoom, state.planet.minZoom, 2f)); + zoom = (Mathf.clamp(initialDistance / distance * lastZoom, state.planet.minZoom, 2f)); } @Override From 0d8965410365d957073af09bd51b2b25561bf674 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 15 May 2023 10:26:35 -0400 Subject: [PATCH 0010/1150] Ignore null messages --- core/src/mindustry/core/NetClient.java | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 99608a6168..d9fa35135a 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -233,6 +233,8 @@ public class NetClient implements ApplicationListener{ return; } + if(message == null) return; + if(message.length() > maxTextLength){ throw new ValidateException(player, "Player has sent a message above the text limit."); } diff --git a/gradle.properties b/gradle.properties index 1440494de5..8d7036080a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=55585b5c6e +archash=ca4f4a41b0 From 1289e20990e5505cdf9dd359b1929f6ec42304f0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 15 May 2023 11:44:08 -0400 Subject: [PATCH 0011/1150] Native (Zenity) file dialogs for Linux --- core/src/mindustry/core/Platform.java | 64 ++++++++++++++++++- .../src/mindustry/ui/dialogs/FileChooser.java | 16 +++-- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index 60d938f084..7e3bbde613 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -14,6 +14,7 @@ import mindustry.type.*; import mindustry.ui.dialogs.*; import rhino.*; +import java.io.*; import java.net.*; import static mindustry.Vars.*; @@ -140,6 +141,61 @@ public interface Platform{ * @param title The title of the native dialog */ default void showFileChooser(boolean open, String title, String extension, Cons cons){ + if(OS.isLinux && !OS.isAndroid){ + showZenity(open, title, new String[]{extension}, cons, () -> defaultFileDialog(open, title, extension, cons)); + }else{ + defaultFileDialog(open, title, extension, cons); + } + } + + /** attempt to use the native file picker with zenity, or runs the fallback Runnable if the operation fails */ + static void showZenity(boolean open, String title, String[] extensions, Cons cons, Runnable fallback){ + Threads.daemon(() -> { + try{ + String formatted = (title.startsWith("@") ? Core.bundle.get(title.substring(1)) : title).replaceAll("\"", "'"); + + String last = FileChooser.getLastDirectory().absolutePath(); + if(!last.endsWith("/")) last += "/"; + + //zenity doesn't support filtering by extension + Seq args = Seq.with("zenity", + "--file-selection", + "--title=" + formatted, + "--filename=" + last, + "--confirm-overwrite", + "--file-filter=" + Seq.with(extensions).toString(" ", s -> "*." + s), + "--file-filter=All files | *" //allow anything if the user wants + ); + + if(!open){ + args.add("--save"); + } + + String result = OS.exec(args.toArray(String.class)); + + if(result.isEmpty() || result.equals("\n")) return; + + if(result.endsWith("\n")) result = result.substring(0, result.length() - 1); + if(result.contains("\n")) throw new IOException("invalid input"); + + Fi file = Core.files.absolute(result); + Core.app.post(() -> { + FileChooser.setLastDirectory(file.isDirectory() ? file : file.parent()); + + if(!open){ + cons.get(file.parent().child(file.nameWithoutExtension() + "." + extensions[0])); + }else{ + cons.get(file); + } + }); + }catch(Exception e){ + Log.warn("zenity not found, using non-native file dialog. Consider installing `zenity` for native file dialogs."); + Core.app.post(fallback); + } + }); + } + + static void defaultFileDialog(boolean open, String title, String extension, Cons cons){ new FileChooser(title, file -> file.extEquals(extension), open, file -> { if(!open){ cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension)); @@ -161,11 +217,17 @@ public interface Platform{ default void showMultiFileChooser(Cons cons, String... extensions){ if(mobile){ showFileChooser(true, extensions[0], cons); + }else if(OS.isLinux && !OS.isAndroid){ + showZenity(true, "@open", extensions, cons, () -> defaultMultiFileChooser(cons, extensions)); }else{ - new FileChooser("@open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show(); + defaultMultiFileChooser(cons, extensions); } } + static void defaultMultiFileChooser(Cons cons, String... extensions){ + new FileChooser("@open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show(); + } + /** Hide the app. Android only. */ default void hide(){ } diff --git a/core/src/mindustry/ui/dialogs/FileChooser.java b/core/src/mindustry/ui/dialogs/FileChooser.java index 8188d97514..6a33696fdc 100644 --- a/core/src/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/mindustry/ui/dialogs/FileChooser.java @@ -20,7 +20,7 @@ public class FileChooser extends BaseDialog{ private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath()); static Fi lastDirectory = Core.files.absolute(Core.settings.getString("lastDirectory", homeDirectory.absolutePath())); - Fi directory = lastDirectory; + Fi directory; private Table files; private ScrollPane pane; private TextField navigation, filefield; @@ -37,10 +37,7 @@ public class FileChooser extends BaseDialog{ this.filter = filter; this.selectListener = result; - if(!lastDirectory.exists()){ - lastDirectory = homeDirectory; - directory = lastDirectory; - } + directory = getLastDirectory(); onResize(() -> { cont.clear(); @@ -254,11 +251,18 @@ public class FileChooser extends BaseDialog{ if(open) filefield.clearText(); } - public static void setLastDirectory(Fi directory){ + public static synchronized void setLastDirectory(Fi directory){ lastDirectory = directory; Core.settings.put("lastDirectory", directory.absolutePath()); } + public static synchronized Fi getLastDirectory(){ + if(!lastDirectory.exists()){ + lastDirectory = homeDirectory; + } + return lastDirectory; + } + public class FileHistory{ private Seq history = new Seq<>(); private int index; From 8b35b44489a047fb8fff232c31eeb880ea6e610f Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 15 May 2023 22:54:10 -0400 Subject: [PATCH 0012/1150] Made default CacheLayer add method insert before 'normal' --- core/src/mindustry/core/Platform.java | 1 + core/src/mindustry/ctype/Content.java | 5 +++++ core/src/mindustry/graphics/CacheLayer.java | 16 ++++++++++++++-- core/src/mindustry/world/meta/Stat.java | 5 +++++ core/src/mindustry/world/meta/StatCat.java | 5 +++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index 7e3bbde613..7ee4a6c32a 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -173,6 +173,7 @@ public interface Platform{ String result = OS.exec(args.toArray(String.class)); + //cancelled selection, ignore result if(result.isEmpty() || result.equals("\n")) return; if(result.endsWith("\n")) result = result.substring(0, result.length() - 1); diff --git a/core/src/mindustry/ctype/Content.java b/core/src/mindustry/ctype/Content.java index 46767ca25a..58a75b4dc8 100644 --- a/core/src/mindustry/ctype/Content.java +++ b/core/src/mindustry/ctype/Content.java @@ -44,6 +44,11 @@ public abstract class Content implements Comparable{ return minfo.mod == null; } + /** @return whether this content is from a mod. */ + public boolean isModded(){ + return !isVanilla(); + } + @Override public int compareTo(Content c){ return Integer.compare(id, c.id); diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index ed9019cf64..9ffd468ac2 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -18,8 +18,16 @@ public class CacheLayer{ public int id; - /** Register a new CacheLayer. */ + /** Registers cache layers that will render before the 'normal' layer. */ public static void add(CacheLayer... layers){ + for(var layer : layers){ + //7 = 'normal' index + add(7, layer); + } + } + + /** Register CacheLayers at the end of the array. This will render over "normal" tiles. This is likely not the method you want to use. */ + public static void addLast(CacheLayer... layers){ int newSize = all.length + layers.length; var prev = all; //reallocate the array and copy everything over; performance matters very little here anyway @@ -43,11 +51,15 @@ public class CacheLayer{ System.arraycopy(prev, index, all, index + 1, prev.length - index); all[index] = layer; + + for(int i = 0; i < all.length; i++){ + all[i].id = i; + } } /** Loads default cache layers. */ public static void init(){ - add( + addLast( water = new ShaderLayer(Shaders.water), mud = new ShaderLayer(Shaders.mud), tar = new ShaderLayer(Shaders.tar), diff --git a/core/src/mindustry/world/meta/Stat.java b/core/src/mindustry/world/meta/Stat.java index c63db17653..5248a70c80 100644 --- a/core/src/mindustry/world/meta/Stat.java +++ b/core/src/mindustry/world/meta/Stat.java @@ -116,6 +116,11 @@ public class Stat implements Comparable{ return Core.bundle.get("stat." + name.toLowerCase(Locale.ROOT)); } + @Override + public String toString(){ + return name; + } + @Override public int compareTo(Stat o){ return id - o.id; diff --git a/core/src/mindustry/world/meta/StatCat.java b/core/src/mindustry/world/meta/StatCat.java index af825e794a..416df5a20a 100644 --- a/core/src/mindustry/world/meta/StatCat.java +++ b/core/src/mindustry/world/meta/StatCat.java @@ -30,6 +30,11 @@ public class StatCat implements Comparable{ return Core.bundle.get("category." + name); } + @Override + public String toString(){ + return name; + } + @Override public int compareTo(StatCat o){ return id - o.id; From 45baeb4933be72b97f7f93ac5c0d292b206a4fbc Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 00:16:46 -0400 Subject: [PATCH 0013/1150] Log zenity error --- core/src/mindustry/core/Platform.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index 7ee4a6c32a..b0c5073e76 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -177,7 +177,7 @@ public interface Platform{ if(result.isEmpty() || result.equals("\n")) return; if(result.endsWith("\n")) result = result.substring(0, result.length() - 1); - if(result.contains("\n")) throw new IOException("invalid input"); + if(result.contains("\n")) throw new IOException("invalid input: \"" + result + "\""); Fi file = Core.files.absolute(result); Core.app.post(() -> { @@ -190,6 +190,7 @@ public interface Platform{ } }); }catch(Exception e){ + Log.err(e); Log.warn("zenity not found, using non-native file dialog. Consider installing `zenity` for native file dialogs."); Core.app.post(fallback); } From 874cba7ad39cc186f03a7be9ae7e3c01e7d14402 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 00:33:17 -0400 Subject: [PATCH 0014/1150] arc --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 8d7036080a..efd464dddc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=ca4f4a41b0 +archash=9a41faa61b From 83d28461f03f10b6fcdfbca19530f04f59d4d647 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 00:34:12 -0400 Subject: [PATCH 0015/1150] augh --- core/src/mindustry/core/Platform.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index b0c5073e76..73e65615be 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -172,6 +172,10 @@ public interface Platform{ } String result = OS.exec(args.toArray(String.class)); + //first line. + if(result.length() > 1 && result.contains("\n")){ + result = result.split("\n")[0]; + } //cancelled selection, ignore result if(result.isEmpty() || result.equals("\n")) return; From 16358dbd6a57fdac0df7bf9a99b6a3c20f309f81 Mon Sep 17 00:00:00 2001 From: Tentyanuk <91948148+SSTentacleSS@users.noreply.github.com> Date: Tue, 16 May 2023 16:35:12 +0300 Subject: [PATCH 0016/1150] Update servers_v7.json (#8615) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Обновили комплектацию серверов --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 4a7c98d4c4..f440df2684 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -101,7 +101,7 @@ }, { "name": "OMNIDUSTRY", - "address": ["85.193.87.179", "85.193.87.179:6568", "85.193.87.179:6569", "85.193.87.179:6570", "85.193.87.179:6571", "85.193.87.179:6572", "85.193.87.179:6573", "85.193.87.179:6574"] + "address": ["80.90.179.146", "80.90.179.146:6568", "80.90.179.146:6569", "80.90.179.146:6570", "80.90.179.146:6571", "80.90.179.146:6572", "80.90.179.146:6573", "80.90.179.146:6574"] }, { From 29855243cbc0b72695d9ba314b12250e0c9a16f1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 17:24:41 -0400 Subject: [PATCH 0017/1150] Base building AI is back --- core/assets/bundles/bundle.properties | 2 + core/assets/maps/glacier.msav | Bin 7198 -> 8550 bytes core/assets/maps/passage.msav | Bin 13732 -> 15083 bytes core/assets/maps/veins.msav | Bin 22989 -> 24431 bytes core/src/mindustry/ai/BaseBuilderAI.java | 325 ++++++++++++++++++ core/src/mindustry/ai/types/BuilderAI.java | 12 +- core/src/mindustry/core/Logic.java | 6 + core/src/mindustry/game/Rules.java | 5 + core/src/mindustry/game/Teams.java | 4 +- .../ui/dialogs/CustomRulesDialog.java | 4 + 10 files changed, 355 insertions(+), 3 deletions(-) create mode 100644 core/src/mindustry/ai/BaseBuilderAI.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c7d8db925b..1b327a02cd 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1212,6 +1212,8 @@ rules.wavetimer = Wave Timer rules.wavesending = Wave Sending rules.waves = Waves rules.attack = Attack Mode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI [red](WIP) rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/maps/glacier.msav b/core/assets/maps/glacier.msav index efe240108d7b7c17a5cb8355fdb667a36487b7d3..cdb524a0d4ff848b056845eb46d3c7bca2556058 100644 GIT binary patch literal 8550 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 literal 7198 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 diff --git a/core/assets/maps/passage.msav b/core/assets/maps/passage.msav index e9b8c5b1d12ff1c546fd8da83a3fae520acefa9f..fb14ff303228a3a86d0a471bf484fccb5b13a4b2 100644 GIT binary patch literal 15083 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 diff --git a/core/assets/maps/veins.msav b/core/assets/maps/veins.msav index 037d3f0b7596a5d6f329126d0b0a3d5d899a28f1..ad6a8b5c013eae731accb12430ecf4ec10609b67 100644 GIT binary patch literal 24431 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 literal 22989 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 diff --git a/core/src/mindustry/ai/BaseBuilderAI.java b/core/src/mindustry/ai/BaseBuilderAI.java new file mode 100644 index 0000000000..807458b349 --- /dev/null +++ b/core/src/mindustry/ai/BaseBuilderAI.java @@ -0,0 +1,325 @@ +package mindustry.ai; + +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import mindustry.*; +import mindustry.ai.BaseRegistry.*; +import mindustry.content.*; +import mindustry.core.*; +import mindustry.game.*; +import mindustry.game.Schematic.*; +import mindustry.game.Teams.*; +import mindustry.gen.*; +import mindustry.maps.generators.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.defense.*; +import mindustry.world.blocks.payloads.*; +import mindustry.world.blocks.production.*; +import mindustry.world.blocks.storage.*; +import mindustry.world.blocks.storage.CoreBlock.*; + +import static mindustry.Vars.*; + +public class BaseBuilderAI{ + private static final Vec2 axis = new Vec2(), rotator = new Vec2(); + private static final int attempts = 4; + private static final float emptyChance = 0.01f; + private static final int timerStep = 0, timerSpawn = 1, timerRefreshPath = 2; + private static final float placeIntervalMin = 12f, placeIntervalMax = 2f; + private static final int pathStep = 50; + private static final Seq tmpTiles = new Seq<>(); + + private static int correct = 0, incorrect = 0; + + private int lastX, lastY, lastW, lastH; + private boolean triedWalls, foundPath; + + final TeamData data; + final Interval timer = new Interval(4); + + IntSet path = new IntSet(); + IntSet calcPath = new IntSet(); + @Nullable Tile calcTile; + boolean calculating, startedCalculating; + int calcCount = 0; + int totalCalcs = 0; + Block wallType; + + public BaseBuilderAI(TeamData data){ + this.data = data; + } + + public void update(){ + + //fill cores. + if(data.team.cores().size > 0){ + var core = data.team.cores().first(); + for(Item item : content.items()){ + core.items.set(item, core.getMaximumAccepted(item)); + } + } + + if(wallType == null){ + wallType = BaseGenerator.getDifficultyWall(1, data.team.rules().buildAiTier / 0.8f); + } + + if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 6f) && data.hasCore()){ + CoreBlock block = (CoreBlock)data.core().block; + int coreUnits = data.countType(block.unitType); + + //create AI core unit(s) + if(!state.isEditor() && coreUnits < data.cores.size){ + Unit unit = block.unitType.create(data.team); + unit.set(data.cores.random()); + unit.add(); + Fx.spawn.at(unit); + } + } + + //refresh path + if(!calculating && (timer.get(timerRefreshPath, 3f * Time.toMinutes) || !startedCalculating) && data.hasCore()){ + calculating = true; + startedCalculating = true; + calcPath.clear(); + } + + //didn't find tile in time + if(calculating && calcCount >= world.width() * world.height()){ + calculating = false; + calcCount = 0; + calcPath.clear(); + totalCalcs ++; + } + + //calculate path for units so schematics are not placed on it + if(calculating){ + if(calcTile == null){ + Vars.spawner.eachGroundSpawn((x, y) -> calcTile = world.tile(x, y)); + if(calcTile == null){ + calculating = false; + } + }else{ + var field = pathfinder.getField(data.team, Pathfinder.costGround, Pathfinder.fieldCore); + + if(field.weights != null){ + int[] weights = field.weights; + for(int i = 0; i < pathStep; i++){ + int minCost = Integer.MAX_VALUE; + int cx = calcTile.x, cy = calcTile.y; + boolean foundAny = false; + for(Point2 p : Geometry.d4){ + int nx = cx + p.x, ny = cy + p.y, packed = world.packArray(nx, ny); + + Tile other = world.tile(nx, ny); + if(other != null && weights[packed] < minCost && weights[packed] != -1){ + minCost = weights[packed]; + calcTile = other; + foundAny = true; + } + } + + //didn't find anything, break out of loop, this will trigger a clear later + if(!foundAny){ + calcCount = Integer.MAX_VALUE; + break; + } + + calcPath.add(calcTile.pos()); + for(Point2 p : Geometry.d8){ + calcPath.add(Point2.pack(p.x + calcTile.x, p.y + calcTile.y)); + } + + //found the end. + if(calcTile.build instanceof CoreBuild b && b.team != data.team){ + //clean up calculations and flush results + calculating = false; + calcCount = 0; + path.clear(); + path.addAll(calcPath); + calcPath.clear(); + calcTile = null; + totalCalcs ++; + foundPath = true; + + break; + } + + calcCount ++; + } + } + } + } + + //only schedule when there's something to build. + if(foundPath && data.plans.isEmpty() && timer.get(timerStep, Mathf.lerp(placeIntervalMin, placeIntervalMax, data.team.rules().buildAiTier))){ + //TODO walls are silly, no walls + //if(!triedWalls){ + // tryWalls(); + // triedWalls = true; + //} + + for(int i = 0; i < attempts; i++){ + int range = 150; + + Position pos = randomPosition(); + + //when there are no random positions, do nothing. + if(pos == null) return; + + Tmp.v1.rnd(Mathf.random(range)); + int wx = (int)(World.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(World.toTile(pos.getY()) + Tmp.v1.y); + Tile tile = world.tiles.getc(wx, wy); + + //try not to block the spawn point + if(spawner.getSpawns().contains(t -> t.within(tile, tilesize * 40f))){ + continue; + } + + Seq parts = null; + + //pick a completely random base part, and place it a random location + //((yes, very intelligent)) + if(tile.drop() != null && Vars.bases.forResource(tile.drop()).any()){ + parts = Vars.bases.forResource(tile.drop()); + }else if(Mathf.chance(emptyChance)){ + parts = Vars.bases.parts; + } + + if(parts != null){ + BasePart part = parts.random(); + if(tryPlace(part, tile.x, tile.y)){ + break; + } + } + } + } + } + + /** @return a random position from which to seed building. */ + private Position randomPosition(){ + if(data.hasCore()){ + return data.cores.random(); + }else if(data.team == state.rules.waveTeam){ + return spawner.getSpawns().random(); + } + return null; + } + + private boolean tryPlace(BasePart part, int x, int y){ + int rotation = Mathf.range(2); + axis.set((int)(part.schematic.width / 2f), (int)(part.schematic.height / 2f)); + Schematic result = Schematics.rotate(part.schematic, rotation); + int rotdeg = rotation*90; + rotator.set(part.centerX, part.centerY).rotateAround(axis, rotdeg); + //bottom left schematic corner + int cx = x - (int)rotator.x; + int cy = y - (int)rotator.y; + + //check valid placeability + for(Stile tile : result.tiles){ + int realX = tile.x + cx, realY = tile.y + cy; + if(!Build.validPlace(tile.block, data.team, realX, realY, tile.rotation)){ + return false; + } + Tile wtile = world.tile(realX, realY); + + if(tile.block instanceof PayloadConveyor || tile.block instanceof PayloadBlock){ + //near a building + for(Point2 point : Edges.getEdges(tile.block.size)){ + var t = world.build(tile.x + point.x, tile.y + point.y); + if(t != null){ + return false; + } + } + } + + //may intersect AI path + tmpTiles.clear(); + if(tile.block.solid && wtile != null && wtile.getLinkedTilesAs(tile.block, tmpTiles).contains(t -> path.contains(t.pos()))){ + return false; + } + } + + //make sure at least X% of resource requirements are met + correct = incorrect = 0; + boolean anyDrills = false; + + if(part.required instanceof Item){ + for(Stile tile : result.tiles){ + if(tile.block instanceof Drill){ + anyDrills = true; + + tile.block.iterateTaken(tile.x + cx, tile.y + cy, (ex, ey) -> { + Tile res = world.rawTile(ex, ey); + if(res.drop() == part.required){ + correct ++; + }else if(res.drop() != null){ + incorrect ++; + } + }); + } + } + } + + //fail if not enough fit requirements + if(anyDrills && (incorrect != 0 || correct == 0)){ + return false; + } + + //queue it + for(Stile tile : result.tiles){ + data.plans.add(new BlockPlan(cx + tile.x, cy + tile.y, tile.rotation, tile.block.id, tile.config)); + } + + lastX = cx - 1; + lastY = cy - 1; + lastW = result.width + 2; + lastH = result.height + 2; + + triedWalls = false; + + return true; + } + + private void tryWalls(){ + Block wall = wallType; + Building spawnt = state.rules.defaultTeam.core() != null ? state.rules.defaultTeam.core() : data.team.core(); + Tile spawn = spawnt == null ? null : spawnt.tile; + + if(spawn == null) return; + + for(int wx = lastX; wx <= lastX + lastW; wx++){ + outer: + for(int wy = lastY; wy <= lastY + lastH; wy++){ + Tile tile = world.tile(wx, wy); + + if(tile == null || !tile.block().alwaysReplace) continue; + + boolean any = false; + + for(Point2 p : Geometry.d8){ + if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(tile)) > 70){ + continue; + } + + Tile o = world.tile(tile.x + p.x, tile.y + p.y); + if(o != null && (o.block() instanceof PayloadBlock || o.block() instanceof PayloadConveyor || o.block() instanceof ShockMine)){ + continue outer; + } + + if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){ + any = true; + } + } + + tmpTiles.clear(); + if(any && Build.validPlace(wall, data.team, tile.x, tile.y, 0) && !tile.getLinkedTilesAs(wall, tmpTiles).contains(t -> path.contains(t.pos()))){ + data.plans.add(new BlockPlan(tile.x, tile.y, (short)0, wall.id, null)); + } + } + } + } +} \ No newline at end of file diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java index 6c71f5f934..a8ea3118cf 100644 --- a/core/src/mindustry/ai/types/BuilderAI.java +++ b/core/src/mindustry/ai/types/BuilderAI.java @@ -12,14 +12,14 @@ import mindustry.world.blocks.ConstructBlock.*; import static mindustry.Vars.*; public class BuilderAI extends AIController{ - public static float buildRadius = 1500, retreatDst = 110f, retreatDelay = Time.toSeconds * 2f; + public static float buildRadius = 1500, retreatDst = 110f, retreatDelay = Time.toSeconds * 2f, defaultRebuildPeriod = 60f * 2f; public @Nullable Unit assistFollowing; public @Nullable Unit following; public @Nullable Teamc enemy; public @Nullable BlockPlan lastPlan; - public float fleeRange = 370f, rebuildPeriod = 60f * 2f; + public float fleeRange = 370f, rebuildPeriod = defaultRebuildPeriod; public boolean alwaysFlee; public boolean onlyAssist; @@ -34,6 +34,14 @@ public class BuilderAI extends AIController{ public BuilderAI(){ } + @Override + public void init(){ + //rebuild much faster with buildAI; there are usually few builder units so this is fine + if(rebuildPeriod == defaultRebuildPeriod && unit.team.rules().buildAi){ + rebuildPeriod = 10f; + } + } + @Override public void updateMovement(){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index bde8089da8..b312e93374 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -445,6 +445,12 @@ public class Logic implements ApplicationListener{ updateWeather(); for(TeamData data : state.teams.getActive()){ + //does not work on PvP so built-in attack maps can have it on by default without issues + if(data.team.rules().buildAi && !state.rules.pvp){ + if(data.buildAi == null) data.buildAi = new BaseBuilderAI(data); + data.buildAi.update(); + } + if(data.team.rules().rtsAi){ if(data.rtsAi == null) data.rtsAi = new RtsAI(data); data.rtsAi.update(); diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index f6445db9ec..177021f1cb 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -267,6 +267,11 @@ public class Rules{ /** If true, this team has infinite unit ammo. */ public boolean infiniteAmmo; + /** AI that builds random schematics. */ + public boolean buildAi; + /** Tier of builder AI. [0, 1] */ + public float buildAiTier = 1f; + /** Enables "RTS" unit AI. */ public boolean rtsAi; /** Minimum size of attack squads. */ diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index 87eebbdbf0..e47b5bfb13 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -241,6 +241,8 @@ public class Teams{ public static class TeamData{ public final Team team; + /** Handles building ""bases"". */ + public @Nullable BaseBuilderAI buildAi; /** Handles RTS unit control. */ public @Nullable RtsAI rtsAi; @@ -409,7 +411,7 @@ public class Teams{ /** @return whether this team is controlled by the AI and builds bases. */ public boolean hasAI(){ - return team.rules().rtsAi; + return team.rules().rtsAi || team.rules().buildAi; } @Override diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 4f35ae48ac..f1f574f954 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -300,6 +300,10 @@ public class CustomRulesDialog extends BaseDialog{ numberi("@rules.rtsmaxsquadsize", f -> teams.rtsMaxSquad = f, () -> teams.rtsMaxSquad, () -> teams.rtsAi, 1, 1000); number("@rules.rtsminattackweight", f -> teams.rtsMinWeight = f, () -> teams.rtsMinWeight, () -> teams.rtsAi); + check("@rules.buildai", b -> teams.buildAi = b, () -> teams.buildAi, () -> team != rules.defaultTeam && rules.env != Planets.erekir.defaultEnv && !rules.pvp); + //disallow on Erekir (this is broken for mods I'm sure, but whatever) + number("@rules.buildaitier", false, f -> teams.buildAiTier = f, () -> teams.buildAiTier, () -> teams.buildAi && rules.env != Planets.erekir.defaultEnv && !rules.pvp, 0, 1); + check("@rules.infiniteresources", b -> teams.infiniteResources = b, () -> teams.infiniteResources); number("@rules.buildspeedmultiplier", f -> teams.buildSpeedMultiplier = f, () -> teams.buildSpeedMultiplier, 0.001f, 50f); From c6829c23d47bb161264c293c5e0ff37860f238fe Mon Sep 17 00:00:00 2001 From: Github Actions Date: Tue, 16 May 2023 21:26:10 +0000 Subject: [PATCH 0018/1150] Automatic bundle update --- core/assets/bundles/bundle_be.properties | 2 ++ core/assets/bundles/bundle_bg.properties | 2 ++ core/assets/bundles/bundle_ca.properties | 2 ++ core/assets/bundles/bundle_cs.properties | 2 ++ core/assets/bundles/bundle_da.properties | 2 ++ core/assets/bundles/bundle_de.properties | 2 ++ core/assets/bundles/bundle_es.properties | 2 ++ core/assets/bundles/bundle_et.properties | 2 ++ core/assets/bundles/bundle_eu.properties | 2 ++ core/assets/bundles/bundle_fi.properties | 2 ++ core/assets/bundles/bundle_fil.properties | 2 ++ core/assets/bundles/bundle_fr.properties | 2 ++ core/assets/bundles/bundle_hu.properties | 2 ++ core/assets/bundles/bundle_id_ID.properties | 2 ++ core/assets/bundles/bundle_it.properties | 2 ++ core/assets/bundles/bundle_ja.properties | 2 ++ core/assets/bundles/bundle_ko.properties | 2 ++ core/assets/bundles/bundle_lt.properties | 2 ++ core/assets/bundles/bundle_nl.properties | 2 ++ core/assets/bundles/bundle_nl_BE.properties | 2 ++ core/assets/bundles/bundle_pl.properties | 2 ++ core/assets/bundles/bundle_pt_BR.properties | 2 ++ core/assets/bundles/bundle_pt_PT.properties | 2 ++ core/assets/bundles/bundle_ro.properties | 2 ++ core/assets/bundles/bundle_ru.properties | 2 ++ core/assets/bundles/bundle_sr.properties | 2 ++ core/assets/bundles/bundle_sv.properties | 2 ++ core/assets/bundles/bundle_th.properties | 2 ++ core/assets/bundles/bundle_tk.properties | 2 ++ core/assets/bundles/bundle_tr.properties | 2 ++ core/assets/bundles/bundle_uk_UA.properties | 2 ++ core/assets/bundles/bundle_vi.properties | 2 ++ core/assets/bundles/bundle_zh_CN.properties | 2 ++ core/assets/bundles/bundle_zh_TW.properties | 2 ++ 34 files changed, 68 insertions(+) diff --git a/core/assets/bundles/bundle_be.properties b/core/assets/bundles/bundle_be.properties index a1ea0615d1..3002d5ec37 100644 --- a/core/assets/bundles/bundle_be.properties +++ b/core/assets/bundles/bundle_be.properties @@ -1187,6 +1187,8 @@ rules.wavetimer = Інтэрвал хваляў rules.wavesending = Адпраўка Хваль rules.waves = Хвалі rules.attack = Рэжым атакі +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Мінімальны Размер Атраду rules.rtsmaxsquadsize = Максімальны Размер Атраду diff --git a/core/assets/bundles/bundle_bg.properties b/core/assets/bundles/bundle_bg.properties index 0962beb62a..191f9af2b8 100644 --- a/core/assets/bundles/bundle_bg.properties +++ b/core/assets/bundles/bundle_bg.properties @@ -1198,6 +1198,8 @@ rules.wavetimer = Таймер за Вълни rules.wavesending = Wave Sending rules.waves = Вълни rules.attack = Режим Атака +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_ca.properties b/core/assets/bundles/bundle_ca.properties index 920fdae708..1dbfe4acda 100644 --- a/core/assets/bundles/bundle_ca.properties +++ b/core/assets/bundles/bundle_ca.properties @@ -1202,6 +1202,8 @@ rules.wavetimer = Temporitzador d’onades rules.wavesending = Enviament d’onades rules.waves = Onades rules.attack = Mode d’atac +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = IA avançada (RTS AI) rules.rtsminsquadsize = Mida mínima de l’esquadró rules.rtsmaxsquadsize = Mida màxima de l’esquadró diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index fb73b156a5..6dae5e9ad0 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = Časovač vln rules.wavesending = Wave Sending rules.waves = Vlny rules.attack = Režim útoku +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_da.properties b/core/assets/bundles/bundle_da.properties index 73462d394f..db494680a2 100644 --- a/core/assets/bundles/bundle_da.properties +++ b/core/assets/bundles/bundle_da.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Bølge-æggeur rules.wavesending = Wave Sending rules.waves = Bølger rules.attack = Angrebsmode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 8b630402bd..0a4ef5ccd8 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -1211,6 +1211,8 @@ rules.wavetimer = Wellen-Timer rules.wavesending = Manuelle Wellen möglich rules.waves = Wellen rules.attack = Angriff-Modus +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS KI [red](unfertig) rules.rtsminsquadsize = Min. Squadgröße rules.rtsmaxsquadsize = Max. Squadgröße diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index ac6d705cd9..16980db4ee 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -1208,6 +1208,8 @@ rules.wavetimer = Temporizador de oleadas rules.wavesending = Envío de oleadas rules.waves = Oleadas rules.attack = Modo de ataque +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = IA enemiga avanzada (RTS AI) rules.rtsminsquadsize = Tamaño mínimo de escuadrón rules.rtsmaxsquadsize = Tamaño máximo de escuadrón diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties index f1c467ca7e..c524efe18a 100644 --- a/core/assets/bundles/bundle_et.properties +++ b/core/assets/bundles/bundle_et.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Kasuta taimerit rules.wavesending = Wave Sending rules.waves = Kasuta lahingulaineid rules.attack = Mänguviis "Rünnak" +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_eu.properties b/core/assets/bundles/bundle_eu.properties index 81162be510..27fb059258 100644 --- a/core/assets/bundles/bundle_eu.properties +++ b/core/assets/bundles/bundle_eu.properties @@ -1190,6 +1190,8 @@ rules.wavetimer = Boladen denboragailua rules.wavesending = Wave Sending rules.waves = Boladak rules.attack = Eraso modua +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties index a32f4ad83c..2e0dd752a1 100644 --- a/core/assets/bundles/bundle_fi.properties +++ b/core/assets/bundles/bundle_fi.properties @@ -1187,6 +1187,8 @@ rules.wavetimer = Tasojen aikaraja rules.wavesending = Wave Sending rules.waves = Tasot rules.attack = Hyökkäystila +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min. hyökkäysjoukon koko rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_fil.properties b/core/assets/bundles/bundle_fil.properties index da750d5d40..53dbba2802 100644 --- a/core/assets/bundles/bundle_fil.properties +++ b/core/assets/bundles/bundle_fil.properties @@ -1187,6 +1187,8 @@ rules.wavetimer = Wave Timer rules.wavesending = Wave Sending rules.waves = Waves rules.attack = Attack Mode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index de718442a4..c1c1785c81 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -1212,6 +1212,8 @@ rules.wavetimer = Compte à rebours des vagues rules.wavesending = Déclenchement des Vagues rules.waves = Vagues rules.attack = Mode « Attaque » +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = IA de RTS [red](WIP) rules.rtsminsquadsize = Taille Minimale d'une Escouade rules.rtsmaxsquadsize = Taille Maximale d'une Escouade diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties index 234fdbcec1..94bb27ac7e 100644 --- a/core/assets/bundles/bundle_hu.properties +++ b/core/assets/bundles/bundle_hu.properties @@ -1197,6 +1197,8 @@ rules.wavetimer = Hullám időzítő rules.wavesending = Wave Sending rules.waves = Hullámok rules.attack = Támadás mód +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_id_ID.properties b/core/assets/bundles/bundle_id_ID.properties index 7f56827144..f5d6575e6b 100644 --- a/core/assets/bundles/bundle_id_ID.properties +++ b/core/assets/bundles/bundle_id_ID.properties @@ -1208,6 +1208,8 @@ rules.wavetimer = Pengaturan Waktu Gelombang rules.wavesending = Wave Sending rules.waves = Gelombang rules.attack = Mode Penyerangan +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = A.I. RTS rules.rtsminsquadsize = Ukuran Regu Minimum rules.rtsmaxsquadsize = Ukuran Regu Maksimum diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index 0d94d5ba8a..8c3bbb4ada 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -1194,6 +1194,8 @@ rules.wavetimer = Timer Ondate rules.wavesending = Wave Sending rules.waves = Ondate rules.attack = Modalità Attacco +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Dimensione minima squadra rules.rtsmaxsquadsize = Dimensione massima squadra diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties index 8979ea4a25..0614e1dbb6 100644 --- a/core/assets/bundles/bundle_ja.properties +++ b/core/assets/bundles/bundle_ja.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = ウェーブの自動進行 rules.wavesending = ウェーブスキップ rules.waves = ウェーブ rules.attack = アタックモード +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = チームの最少人数 rules.rtsmaxsquadsize = チームの最大人数 diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index a08654d6f0..21d9618c7c 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = 시간 제한이 있는 단계 rules.wavesending = 단계 넘김 rules.waves = 단계 rules.attack = 공격 모드 +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = 최소 부대 규모 rules.rtsmaxsquadsize = 최대 부대 규모 diff --git a/core/assets/bundles/bundle_lt.properties b/core/assets/bundles/bundle_lt.properties index ac8ece1fcd..2bef2f3320 100644 --- a/core/assets/bundles/bundle_lt.properties +++ b/core/assets/bundles/bundle_lt.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Bangų Laikmatis rules.wavesending = Wave Sending rules.waves = Bangos rules.attack = Puolimo Režimas +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index 47c16aef5d..f0761d9929 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = Vijandelijke Golven Timer rules.wavesending = Golven Sturen rules.waves = Golven rules.attack = Aanvalmodus +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Ploeg Grootte rules.rtsmaxsquadsize = Max Ploeg Grootte diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties index 9ac90625cf..f923408bd4 100644 --- a/core/assets/bundles/bundle_nl_BE.properties +++ b/core/assets/bundles/bundle_nl_BE.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Wave Timer rules.wavesending = Wave Sending rules.waves = Waves rules.attack = Attack Mode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index af70996027..cb00bbf9bd 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -1198,6 +1198,8 @@ rules.wavetimer = Zegar Fal rules.wavesending = Wysyłanie Fal rules.waves = Fale rules.attack = Tryb Ataku +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS SI rules.rtsminsquadsize = Minimalny Rozmiar Składu rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index c95837d0ef..995507ef52 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -1209,6 +1209,8 @@ rules.wavetimer = Tempo de horda rules.wavesending = Wave Sending rules.waves = Hordas rules.attack = Modo de ataque +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Tamanho mínimo do esquadrão rules.rtsmaxsquadsize = Tamanho máximo do esquadrão diff --git a/core/assets/bundles/bundle_pt_PT.properties b/core/assets/bundles/bundle_pt_PT.properties index 806654ccfb..43a6d4a258 100644 --- a/core/assets/bundles/bundle_pt_PT.properties +++ b/core/assets/bundles/bundle_pt_PT.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Tempo de horda rules.wavesending = Wave Sending rules.waves = Hordas rules.attack = Modo de ataque +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_ro.properties b/core/assets/bundles/bundle_ro.properties index d8e6fd4d9f..ce1d16f952 100644 --- a/core/assets/bundles/bundle_ro.properties +++ b/core/assets/bundles/bundle_ro.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = Valuri pe Timp rules.wavesending = Wave Sending rules.waves = Valuri rules.attack = Modul Atac +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 9b82515ed4..5228277366 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -1200,6 +1200,8 @@ rules.wavetimer = Интервал волн rules.wavesending = Отправка волн rules.waves = Волны rules.attack = Режим атаки +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = ИИ в реальном времени rules.rtsminsquadsize = Минимальный размер отряда rules.rtsmaxsquadsize = Максимальный размер отряда diff --git a/core/assets/bundles/bundle_sr.properties b/core/assets/bundles/bundle_sr.properties index 0d8b8f7285..2a12e58ded 100644 --- a/core/assets/bundles/bundle_sr.properties +++ b/core/assets/bundles/bundle_sr.properties @@ -1202,6 +1202,8 @@ rules.wavetimer = Talasna Štoperica rules.wavesending = Slanje Talasa rules.waves = Talasi rules.attack = Mod Napada +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI [red](Nedovršeno) rules.rtsminsquadsize = Minimalna Veličina Odreda rules.rtsmaxsquadsize = Maksimalna Veličina Odreda diff --git a/core/assets/bundles/bundle_sv.properties b/core/assets/bundles/bundle_sv.properties index 95332329f7..8d2bd17178 100644 --- a/core/assets/bundles/bundle_sv.properties +++ b/core/assets/bundles/bundle_sv.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Vågtimer rules.wavesending = Wave Sending rules.waves = Vågor rules.attack = Attack Mode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties index 68f5c818cb..969e9f0581 100644 --- a/core/assets/bundles/bundle_th.properties +++ b/core/assets/bundles/bundle_th.properties @@ -1202,6 +1202,8 @@ rules.wavetimer = นับถอยหลังการปล่อยคล rules.wavesending = การปล่อยคลื่น rules.waves = คลื่น rules.attack = โหมดการโจมตี +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI [red](ไม่เสถียร) rules.rtsminsquadsize = ขนาดกองทัพเล็กที่สุด rules.rtsmaxsquadsize = ขนาดกองทัพใหญ่ที่สุด diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index df6daf11cd..67fd4206a6 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -1188,6 +1188,8 @@ rules.wavetimer = Wave Timer rules.wavesending = Wave Sending rules.waves = Waves rules.attack = Attack Mode +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Squad Size rules.rtsmaxsquadsize = Max Squad Size diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index f8075573a5..8f4ba852ea 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -1199,6 +1199,8 @@ rules.wavetimer = Dalga Zamanlayıcısı rules.wavesending = Dalga Gönderiliyor rules.waves = Dalgalar rules.attack = Saldırı Modu +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Min Gurup Boyutu rules.rtsmaxsquadsize = Maks Gurup Boyutu diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index ae5ab371f2..8d78491378 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -1210,6 +1210,8 @@ rules.wavetimer = Таймер для хвиль rules.wavesending = Ручне надсилання хвиль rules.waves = Хвилі rules.attack = Режим атаки +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = ШІ зі стратегій реального часу rules.rtsminsquadsize = Мінімальний розмір загону rules.rtsmaxsquadsize = Максимальний розмір загону diff --git a/core/assets/bundles/bundle_vi.properties b/core/assets/bundles/bundle_vi.properties index 1cfd5262a1..b175639cc4 100644 --- a/core/assets/bundles/bundle_vi.properties +++ b/core/assets/bundles/bundle_vi.properties @@ -1203,6 +1203,8 @@ rules.wavetimer = Đếm ngược đợt rules.wavesending = Gửi đợt rules.waves = Đợt rules.attack = Chế độ tấn công +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = Kích thước đội hình tối thiểu rules.rtsmaxsquadsize = Kích thước đội hình tối đa diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index 2711eae6f2..40ea8a9666 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -1211,6 +1211,8 @@ rules.wavetimer = 波次计时器 rules.wavesending = 波次可跳波 rules.waves = 波次 rules.attack = 进攻模式 +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = 最小部队规模 rules.rtsmaxsquadsize = 最大部队规模 diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index 08bc2123c5..7bce7ac7b6 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -1207,6 +1207,8 @@ rules.wavetimer = 波次時間 rules.wavesending = Wave Sending rules.waves = 波次 rules.attack = 攻擊模式 +rules.buildai = Base Builder AI +rules.buildaitier = Builder AI Tier rules.rtsai = RTS AI rules.rtsminsquadsize = 最小隊伍規模 rules.rtsmaxsquadsize = 最大隊伍規模 From 7f6907e14fa1645242494786c4875b3594aa5b65 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 18:13:09 -0400 Subject: [PATCH 0019/1150] More core units for bases --- core/src/mindustry/ai/BaseBuilderAI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/ai/BaseBuilderAI.java b/core/src/mindustry/ai/BaseBuilderAI.java index 807458b349..d53ab68712 100644 --- a/core/src/mindustry/ai/BaseBuilderAI.java +++ b/core/src/mindustry/ai/BaseBuilderAI.java @@ -25,7 +25,7 @@ import static mindustry.Vars.*; public class BaseBuilderAI{ private static final Vec2 axis = new Vec2(), rotator = new Vec2(); - private static final int attempts = 4; + private static final int attempts = 5, coreUnitMultiplier = 2; private static final float emptyChance = 0.01f; private static final int timerStep = 0, timerSpawn = 1, timerRefreshPath = 2; private static final float placeIntervalMin = 12f, placeIntervalMax = 2f; @@ -71,7 +71,7 @@ public class BaseBuilderAI{ int coreUnits = data.countType(block.unitType); //create AI core unit(s) - if(!state.isEditor() && coreUnits < data.cores.size){ + if(!state.isEditor() && coreUnits < data.cores.size * coreUnitMultiplier){ Unit unit = block.unitType.create(data.team); unit.set(data.cores.random()); unit.add(); From 410f4f69a1a498378a725d2c05ad2e79830f164c Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 May 2023 21:15:56 -0400 Subject: [PATCH 0020/1150] near is nearer --- core/src/mindustry/graphics/g3d/PlanetRenderer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index 80f95767c7..e516f69400 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -7,11 +7,9 @@ import arc.graphics.g3d.*; import arc.graphics.gl.*; import arc.math.*; import arc.math.geom.*; -import arc.struct.*; import arc.util.*; import mindustry.game.EventType.*; import mindustry.graphics.*; -import mindustry.graphics.g3d.PlanetGrid.*; import mindustry.type.*; public class PlanetRenderer implements Disposable{ @@ -44,6 +42,7 @@ public class PlanetRenderer implements Disposable{ projector.setScaling(1f / 150f); cam.fov = 60f; cam.far = 150f; + cam.near = 0.01f; } /** Render the entire planet scene to the screen. */ From 445e147c16258d4b10a70062d604657a95e5292b Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 17 May 2023 09:38:15 -0400 Subject: [PATCH 0021/1150] near is further --- core/src/mindustry/graphics/g3d/PlanetRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index e516f69400..536af2c4be 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -42,7 +42,7 @@ public class PlanetRenderer implements Disposable{ projector.setScaling(1f / 150f); cam.fov = 60f; cam.far = 150f; - cam.near = 0.01f; + cam.near = 0.1f; } /** Render the entire planet scene to the screen. */ From 00ae28847eda71f9e383f7a498aa7ad5c222edb5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 17 May 2023 18:45:15 -0400 Subject: [PATCH 0022/1150] New salvo sprite --- .../turrets/salvo/salvo-barrel-heat.png | Bin 501 -> 552 bytes .../blocks/turrets/salvo/salvo-barrel.png | Bin 383 -> 752 bytes .../blocks/turrets/salvo/salvo-heat.png | Bin 203 -> 0 bytes .../blocks/turrets/salvo/salvo-preview.png | Bin 1070 -> 1019 bytes .../blocks/turrets/salvo/salvo-side-l.png | Bin 0 -> 429 bytes .../blocks/turrets/salvo/salvo-side-r.png | Bin 0 -> 423 bytes .../sprites/blocks/turrets/salvo/salvo.png | Bin 864 -> 0 bytes core/src/mindustry/content/Blocks.java | 17 +++++++++++------ 8 files changed, 11 insertions(+), 6 deletions(-) delete mode 100644 core/assets-raw/sprites/blocks/turrets/salvo/salvo-heat.png create mode 100644 core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-l.png create mode 100644 core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-r.png delete mode 100644 core/assets-raw/sprites/blocks/turrets/salvo/salvo.png diff --git a/core/assets-raw/sprites/blocks/turrets/salvo/salvo-barrel-heat.png b/core/assets-raw/sprites/blocks/turrets/salvo/salvo-barrel-heat.png index 3da20590373e9f7df2c98e6f761ec670faeeaeb3..274053f819c982c2d61caa2a858dd28cfaaf166f 100644 GIT binary patch delta 513 zcmey$yn%x|>_Pt^@o>wRi# z>J%`4ga5t7vQ4j2l0V6v6}X}{OY8kbF2~eKxle7S6h-DIgjd%4zZB^6lKW$yz^HNN zW6aCllP|1lh;`{Y-Tcl!L0VC?^1^$@;3HR_II1^X&#+OEc;CH$_S{APH!6LS;7Pyu z?svu=?e}x4PwiYcAxTt0iT`4>^HhV1XTrx%xlQB}m}vb#YKQNeK5a#{&~L>F59d_h zEYCH(sqNsR*Zk1t^kK#6=6k*uHwvse(fls=qd`ltS+AfO?|W|7$_w=dLTv?1F{O{oZ*j|n zR<8J*p~J_hb<%ln`{G2708hDBc5?ZL3VACJ8}MKtzV`Ut$95e|oL%d|z`(%Z>FVdQ I&MBb@0Oc3%2><{9 delta 462 zcmZ3%@|AglVf}hf7srr_Id5m~_B(7K(Q02TDIg@o%q^Upu6C~_{fY042{$B+HyS8} zYH=(~YO^{~cv)zHot(w|5Y?~$qrX}1JCb`~M!j#w)q8$ zH!G!k4EOy}3+rYsZFaE#_1pEQQTNG=!~-%GjCNh0QoB4S>ND0q=$(2Y_2bOtGelmh zNhI%K?Q2}jtGWJwQcJHE>|>Bq`{n|@R-E$@3|Sixt*m>wCaS+eGh=GC=b zpJWV{gN?oo#A7XQO{G66H+d;N^%1CO|wIlYj#y!&})3}GohRPtlAAm@t1bu zX09pQAMabUa2Dg-73cZ`^%~a&y_+8(@nOQmdKI;Vst0I!7CAOHXW diff --git a/core/assets-raw/sprites/blocks/turrets/salvo/salvo-barrel.png b/core/assets-raw/sprites/blocks/turrets/salvo/salvo-barrel.png index b21c193a113f1337b759edd87c645d1f708cf845..1ac7d8ff1fac547a239daf9c099dafd68d3fd971 100644 GIT binary patch delta 716 zcmey*^nrDPK|RwdPZ!6KiaBp*@Ar~%lsRs18PxSeu&H;cpxy-SEAA6Y8V?6`zGUHi z!pW4mP9#~mga3iD3dxaa!O0MkBAs;I(P2u*>`{cah%)!sqAT<{rul=^N$sZ zWo2c_70;`v{g9Gg!)$O%g6Tunp65ln%>DelAI|=d*1DD+q=cbhnGBq7r zS&SJ~KPXNU@?j}y46UvkA@z|NIvmh-`-aLpufWm2F7(lF)Stz zo%g8B;PyD!Ug5FA_rhfp#Jk_l_w9Jx74e2=sPVrWtZ~vyW{H!&Kl$Q+r?bgM{Z#%`Y>T#i-l#y zg!L?+10TG<_3%pZ@#p%y>z|nE9Zv9SVz-g_&d{)Qs`&S~|GV~_nAiV#LG^)@^qR?8 zB|(w$GM(!MJ2*4+YBD?`Z{-O7# zMsx1Wx1J--yG(ylTgJiW1lBz_Ypz*^eR}?W&5{TA_s;vB`(CMv+r#@p8+)tV1=mAg zAHBQsX{PyFp?RF~l`8$5uRNi5d6H#|koob*P_F=&uwHxkDsx}fjU1bv!c=_E{A5s;v zdEk2RN9V*V`yO6l<2=3G-RHlpT)30gwf=K6-t(XE{7{j1BDLAYtLeIPuqg=iTmEO9 YBWY=2=jay7z`(%Z>FVdQ&MBb@05E4pTL1t6 delta 344 zcmeys`k!fnK|Q0Tr;B4q#hka-46_b92(&(2{yg%JOl;FHUa0 z<9lDNDxJ2Wj$v~B|D-#=iWPb0Zcy`P_jwj~sfHt)n|DF>seiYgvX@?c_40M{%ibTw ziHs$_m7k9)IdgD6n0K0gkyC_i!^@}B(`v2c1QlD}Fa|#sn0Bv)@nO2xANa`JMi}x|C)S<*sVEDc`Og~4)ikI sVcj9vu$#f0sX+XJ8^b#$1_WT-$G9>i)c)(af2%=)p00i_>zopr06<`xNB{r; diff --git a/core/assets-raw/sprites/blocks/turrets/salvo/salvo-heat.png b/core/assets-raw/sprites/blocks/turrets/salvo/salvo-heat.png deleted file mode 100644 index 48482e269780d74a7e595a238699db44ec93921e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 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 CUFBy0 diff --git a/core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-l.png b/core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-l.png new file mode 100644 index 0000000000000000000000000000000000000000..4ef96282827b7b9b9c9e46db0bed23097f78a89e GIT binary patch literal 429 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z?kmo z;uumf=j}~fKc+y5)`yD=8Q(P>I~FHYmXMvC@11m5ti!ft+75o92nMw)I!zb&uS%GF zzxVT9|76SSpQmZHd_H6FiCJUmlprrn1TpW~>*CMf_GJgvpT$*xLtuq zPT~8O_f89Tu`zr+|8w1S))EHIR)K%43=iB_h&_1v^WK;8t4s`LEvpzC@>*UoHW)aW zGAzE#wD|I&-_`O?rVP1?Ea6uf845W<7qYP_eq9% bt>j)HP^!(+t23X0fq}u()z4*}Q$iB}YzDa0 literal 0 HcmV?d00001 diff --git a/core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-r.png b/core/assets-raw/sprites/blocks/turrets/salvo/salvo-side-r.png new file mode 100644 index 0000000000000000000000000000000000000000..21cda3b07b408369483945454dce2054f6bee802 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0y~yU~m9o4mJh`hEk44ofy`glX=O&z?kUi z;uumf=j|-}yh8>uZuUyY<}4~+YGhQ{x~lloL>cE8YiwUP7RIF8x0ZflaAY_jzp%|l_T0{cJNKwNwg?k44ofy`glX=O&z%1qI z;uumf=j|-pZs9 zQn+#QU(1F>>FHZ9x?Sp8dqQMokL!-ZXYN)%n^*mAZmy00No$`I+kGgK<-)}QYob>dK(ITaW-_KOlejJfb@=cIVaA#6|_4KiRNYysZ zDL>wBzP|Om|E4`kbCR6`Sk5f7WvDYWRBP$dUv4e6rS@jL;ttM&`%8|nto%{*D?s=L z+nHs1A8eCJa$57F$WBph15ZKc{{QL6v=*Fed04S=Udm6au$ubUON!)@m`*dStYA)c zlAZG7{c`nlul0m2o>uT0$j)Er_b0Wi=kw3j&v6}`Q+}lXjb*42wg?os!})KAX-VAv zGkx8UC4_4p@#+abtB zGMgH^#PX^f^yE0^bA%c#o8>Gy|A5sjF@6`f25v1a4Z|spS3b`vyXV1DpzatF(&FOO zQ_*10!gPjX!kTA0idp?;FmIBZC(JqLFT=&Ed6(@ACU&q_Oq`J7-l5dW8T2tGZ^?-x zExWDflpj?-`123b?H#kOO__XX&I=BW?O!j*?d9`}`*tPVX$s@IKD|~>#mXbI6wDqR zJ(&9`u7`8dmbBF|O(z(X|DAlG`?JTTL*;C9v#-5^=|OA1TZb3CK07_U$;@{hYtIj( z_jcjuYl|Bfa4a|!C&Ve^bd>qwM1f7}H(tGeKOt|KnWK{2jX$Z=YIFnQSnusE-drfW zGf|cE_)_a|cm9%n&mLqm?c+NiY^v`W)_m#WLHEm#8e2{$o@)8`&oBGSzvP0{ z?|kmMUMX519UlE Date: Wed, 17 May 2023 19:03:16 -0400 Subject: [PATCH 0023/1150] New base schematcs from Bluewolf --- core/assets/baseparts/000.msch | Bin 97 -> 0 bytes core/assets/baseparts/1591389341902.msch | Bin 103 -> 0 bytes core/assets/baseparts/1591389353247.msch | Bin 97 -> 0 bytes core/assets/baseparts/1591389457130.msch | 1 - core/assets/baseparts/1603214918168.msch | 2 -- core/assets/baseparts/1603214945791.msch | 2 -- core/assets/baseparts/1603219428262.msch | Bin 176 -> 0 bytes core/assets/baseparts/752919619894902997.msch | Bin 102 -> 0 bytes core/assets/baseparts/752926963076694047.msch | Bin 523 -> 0 bytes core/assets/baseparts/752961607314702336.msch | Bin 472 -> 0 bytes core/assets/baseparts/752980871690059906.msch | Bin 217 -> 0 bytes core/assets/baseparts/752982341865046126.msch | Bin 217 -> 0 bytes core/assets/baseparts/753043453876895784.msch | Bin 853 -> 0 bytes core/assets/baseparts/772860344174772254.msch | Bin 847 -> 0 bytes core/assets/baseparts/772861253630165084.msch | 3 --- core/assets/baseparts/actuallyokrtg.msch | 4 ++++ core/assets/baseparts/atrax-surprise.msch | Bin 0 -> 499 bytes core/assets/baseparts/flar.msch | 1 + core/assets/baseparts/fortress.msch | Bin 0 -> 804 bytes core/assets/baseparts/impending-doom.msch | Bin 0 -> 536 bytes core/assets/baseparts/scorch.msch | 1 + core/assets/baseparts/simplemeltdown.msch | 2 ++ core/assets/baseparts/steamgobrr.msch | 2 ++ core/assets/baseparts/strong_duos.msch | Bin 0 -> 316 bytes 24 files changed, 10 insertions(+), 8 deletions(-) delete mode 100644 core/assets/baseparts/000.msch delete mode 100644 core/assets/baseparts/1591389341902.msch delete mode 100644 core/assets/baseparts/1591389353247.msch delete mode 100644 core/assets/baseparts/1591389457130.msch delete mode 100644 core/assets/baseparts/1603214918168.msch delete mode 100644 core/assets/baseparts/1603214945791.msch delete mode 100644 core/assets/baseparts/1603219428262.msch delete mode 100644 core/assets/baseparts/752919619894902997.msch delete mode 100644 core/assets/baseparts/752926963076694047.msch delete mode 100644 core/assets/baseparts/752961607314702336.msch delete mode 100644 core/assets/baseparts/752980871690059906.msch delete mode 100644 core/assets/baseparts/752982341865046126.msch delete mode 100644 core/assets/baseparts/753043453876895784.msch delete mode 100644 core/assets/baseparts/772860344174772254.msch delete mode 100644 core/assets/baseparts/772861253630165084.msch create mode 100644 core/assets/baseparts/actuallyokrtg.msch create mode 100644 core/assets/baseparts/atrax-surprise.msch create mode 100644 core/assets/baseparts/flar.msch create mode 100644 core/assets/baseparts/fortress.msch create mode 100644 core/assets/baseparts/impending-doom.msch create mode 100644 core/assets/baseparts/scorch.msch create mode 100644 core/assets/baseparts/simplemeltdown.msch create mode 100644 core/assets/baseparts/steamgobrr.msch create mode 100644 core/assets/baseparts/strong_duos.msch diff --git a/core/assets/baseparts/000.msch b/core/assets/baseparts/000.msch deleted file mode 100644 index 35d2df8e147a1fd293bdaeeab51c70de85b364a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97 zcmc~TPR?Mgm?PWc$km`A!W#cK>$1`dxpi0GDSvZRHuVv|XO}6FW+~ywyexw$dHp-1 zs8x##F8gV{l}fD4J#{UyTIqU1*Y-ze{_WfN>yYD~m1(CLIP7cLcouAAFP?69NLS=G E0O08>RsaA1 diff --git a/core/assets/baseparts/1591389341902.msch b/core/assets/baseparts/1591389341902.msch deleted file mode 100644 index de7b07b8bf305441892215695eb8f4bf8ed76c96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 103 zcmc~TPR?Mgn4{Vi&DCJQ!?OLD$Ps@3OU_fJwp?i6QdKXls$1`dxpi0GDSvZRHuVv|XO}6FW+~ywyexw$dHp-1 zs8x##F8gV{l}fD4J#{UyTIqU1*Y-ze{_WfN>yYD~m1(CLIP7cLcouAAFP?69NLS=G E0O08>RsaA1 diff --git a/core/assets/baseparts/1591389457130.msch b/core/assets/baseparts/1591389457130.msch deleted file mode 100644 index cba53a4737..0000000000 --- a/core/assets/baseparts/1591389457130.msch +++ /dev/null @@ -1 +0,0 @@ -mschx%Q0 C]R>v>9"S(H~)X_dKaYDݹ(Sim;VI^e0s-@ uVxz?k \ No newline at end of file diff --git a/core/assets/baseparts/1603214918168.msch b/core/assets/baseparts/1603214918168.msch deleted file mode 100644 index 6d69a2c362..0000000000 --- a/core/assets/baseparts/1603214918168.msch +++ /dev/null @@ -1,2 +0,0 @@ -mschx5 -! Ey-J(qG&'.}SmtWKuXGq Yz\P?E:Y ΤԢh)(%UDK(.%#V0FN# \ No newline at end of file diff --git a/core/assets/baseparts/1603219428262.msch b/core/assets/baseparts/1603219428262.msch deleted file mode 100644 index 6d5b519036beea7b07e3cd00513ba6605fb3a28f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmc~TPR?Mgn4@|omhX^)0Lz2MOY&=veL0w1pm9k^b>Rh_Eyr%}E}d`Jb~p0N3=^NC z)yE_5&-6O`Bu+*wK8-7y*OF0o*`&qFyLUcW{Pg-xp;hs@C#}!QoH|#(?ODJ2miF7p zMU lIKmS}@(%qyQsB7#&Y#O4BTE;xx*0fWmoSOf87FIT0sy-ZRTBUJ diff --git a/core/assets/baseparts/752919619894902997.msch b/core/assets/baseparts/752919619894902997.msch deleted file mode 100644 index c8c143ca231f331f8f7ef3eecb3ad5d297c7a16e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 zcmc~TPR?Mgm?PU`&DCHaz&gM4){Tg2_WZ>44>%9~I^tlrq4WE9u diff --git a/core/assets/baseparts/752926963076694047.msch b/core/assets/baseparts/752926963076694047.msch deleted file mode 100644 index 6e2629672939712dd0206c89a855859549630003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 523 zcmc~TPR?MgnByB5op;+nAm&wKAphyIS!}Ks`{NwaU)cU~Kb`ZyNsKqD?ABy)52h8y zON5Rz?Ad+z=FF!-`#cw`NS{6F_51YfI-|qiH&<`^cRcFV;}rk9M`LUAQ_BmRKi<9B zQ}$wlZPd>vdDrCsd`#QDxqN@Fy`}zF_IWw;&ZN|)|M!{l>}8$7^p(z+4Nm0k`t`SP z%iYDYYt3!$OVt8w<(ZahT|SuaUD;*pH5Un9d9>}Bti&Oa?3MRE z&N?zpiNPzStH5Y2HMk9-~3pj!uBs#<=)Y=tC=FTR=J!=YS4Dn)r@?|7_==kXZLg) mhBIM`+E0wd4{vyMg1>Mf{~Dv8O`Eq&T)$)YivQgT`4a&s{Q{Bz diff --git a/core/assets/baseparts/752961607314702336.msch b/core/assets/baseparts/752961607314702336.msch deleted file mode 100644 index f7ea7664dbeee317cafeb691371ad0aaac99e82a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472 zcmc~TPR?MgnBy84J!!UqfQ-Pj%8Ejv=O1TtPq03zuzQM7htQ$8=N>;#f8DfO&Gyh# z)+chkQMR_pw=U`}%n8`LEGuiT)c*c=tNxnbiVwZ8@8bD`tIaI@OJC=|OG&@{^;u-K zmhwi)nB^-o?g~tioKROJ{?`9m>}+F}jQTIjtY5RWbnkOqHsi~RJxNDvV>9d z{4DdizDz!F)5j{^nuMe0W_Rbgy{~&UR%|odEzpk zK|$Uk&8WQfw`Kn;V}@t@8MG4g_+q*vpIW8odDXC{s9X>@xhLY?Y3bbuyedCbyswD2 jIP~xRCnu*5zFVRhx#oFxiU$^9r`N;|0r>~a&-nK&b~@zScOob&T70=~{Nwy9HwxEA z->q75+qL^R+o_qt4^4k?Z{*ut_)+&?%lE^_pY#1adc^0Y)J>j?#@`NGxmTMV-G5|i z|FwzpP6+0|$mE>o$-XT0;667id!ee==Z;Kt+xugW#NP*J*RU5&eEZ!>a9)4T@y;&~ z?(Vq7vB167ciM`u(CbV_vzIY2?tHBf}M9;4H^^^RD!h dZ@If=K27}^J=<&Zs^9r`N;|0r>~a&-nK&b~@zScOob&T70=~{Nwy9HwxEA z->q75+qL^R+o_qt4^4k?Z{*ut_)+&?%lE^_pY#1adc^0Y)J>j?#@`NGxmTMV-G5|i z|FwzpP6+0|$mE>o$-XT0;667id!ee==Z;Kt+xugW#NP*J*RU5&eEZ!>a9)4T@y;&~ z?(Vq7vB167ciM`u(CbV_vzIY2?tHBf}M9;4H^^^RD!h dZ@If=K27}^J=<&ZsNsC}<9O+bFpE;KS*=<#t!iDQo}6EoOe>GJoEGZO_sw*{mmJ*JXcZzB`wf z@&D+LZO1e0x1?{k=KXvB-S?Uq@2n!tYwy05DxcH#Ewip{Q{75+^EY>2-hE19zAAeY>&6 zeL2&coo-?)`QGjLzqW4T`ifNDfBDLa58WO%A6k1T><~jizU!p}9LLo}nvWVB3fDQt z6vW9n(@8IpM?*s1%*t))^un9ItOnGE&(+-GE(T4?{>&Si@|S_-RkuPkd_I zEB5%mVB(PnvoD3Xs!Vh4nRq(5lW{7`jCD?WN3HzB92^fWY)IhMII4bY1-p6D3r4Nw z>~`@-YM45{YKsAGrq2ik!B3L&qY;^9_bU$2xjg7hGDSkQQc; z#~8gX(o3sVal^qb--U@gJsR#X@*a>V3lLCDJQ>D+K&$iWrZv-2x9Y4;y;(lVx+?dn z<00$$S~`pi_OKrj5(<*BRtPtnZx!};RP&i znVnwVAyH1pCEqVqo$`(SuUN~n4T|piEcf2DmQ{P}-J8^~_rSUX=D&n&G_#cs$T^+* z6(lqJC&vj*gQ-dvzp1m@DNfkDbbjh{$#Y>sHB1{K8KgyvxefCt6g{lY4T#*wtUS-| zUPn-^e9p%E(vvkK+qORFEb9#87h4;~IK!52>r9@5+fDn= UI4_%^EyAVEdgtx@%R3~>0X3O zt)AlxEq#6OcRmp^om{DL{GW|X?-Bp2DQ%Z(nl$IC*vz}VvT}`1?W_3<-u$}dVKVR6 z!70lR_AFkKd_T;&a+THPX$#&h{C^|tamY32%iDzHf3MQ*UpBk#**l(GE7RbsrqA0y z-6-#WCVB92zjN^Y+3`)j|1;WlZ>!gOA2|6({rugF*Zxd;ab6?n(Z)>a8Pgv(XKLQK z=Y09<)4BJ;AF(ZLJ9%ZtU5Dl;A-3CVL;rg*O@H-8-0H(;wcV@MN#D6XrMdB<1#kLo zwu$vE{py=aWCS{QwD>F(C|Bg>;+)CUvTlda?|*-sW#(0iiErV)#rn4Kn?v;koka0- z`VYhob-eo{|0aGxWW=r1q7QNv{MWqIlvB7oo}Fanc+Rvz@c3lW;B^O7m0EljIuv|7 z`c>9|?+ugKL+<{+EEgD^T0Im)W0wVN5LWbFy7Mdd6_tR=4Qh-&VcH`5w(R9Dtf^|@ z$lAHJNO~DZ>S_UP6|R*{yi!IQ+D>OU*rzM7a4l?FYwnc6J=01g$@N3@;{_eO40TVG z#5TG`Dc;zU?Yldzm~-c=oc`@^3L9p{-#x?rTHED~-lE?UAO0l&%X9zBq%U*s>c%k3 z-{Qq~j3VomjwaOVL^jOYw&DVp5?2e;?G0@&}tXx5@u9-dX3BSv}YWz_0>f6 zl4WXN#BVt96#cv2rM#}JOXkOff+UANCY$!ArtYa1=Y6ib+!XTKQ?hA7cWj%v+00uh zS(9J77KuKawL2lNC@g%%x`1{k>Ft*VW3qDWVqSR93X)oP;a7fzee}w?Czh)G6H3*; z*mm^K-G3hPF{^TqXv-dbm%G*4ci-hh>jGvtI|Lg!9JGsDd2(vn&S$$8IGW#jk{ucs z{PJX6{d8&3doOzPcCfa%D2AR8DT-wI5dG09{$pL^@wmU=tzPWqt2%E#Z^KieH-aUO zdVz_nCajG2yKCM1sc)KeL+qFDS~ct6vHy+a-xbgPPFyi4LOVxf+nveHN9@hNFPO*s;ipYm;1hrfzƩp~:}bU$ %M; Ce~rT:^/6*#yA97ϧ#)%++5mꘌ5;f18ZfS4b0f52wOV$N+1(u -U -mIRuâ80GFĩ2шU;F~'b3xb`_ ݾ+U \ No newline at end of file diff --git a/core/assets/baseparts/actuallyokrtg.msch b/core/assets/baseparts/actuallyokrtg.msch new file mode 100644 index 0000000000..904f16fda5 --- /dev/null +++ b/core/assets/baseparts/actuallyokrtg.msch @@ -0,0 +1,4 @@ +mschxMan0 MK[H"9rcڏ <-4(Ma~)R{vB':Դi^'+ /4g"jPa~dwIStxoNpK >98DW&DMq|7THUJ3Ey;I(*?($*i*$9^yNfrv zZ5+IQFK{-0^-@F8YIS?vi_Fwm^{>hwD&6@95 z+Agr+`&5|s+edzP;)O=`axOOcJ0|CyzjS&$P;ASwoIXY6LAH=)f^%lu={6U>8$wT~ z6!b2PTA((OQOZok;LIf5^fd31V;3!#h6reBT6HjOP@5B!<>j&OxJ13$nwillI;jlN zjNdGSj!13)5Vm5?%_I9=rYyMHs}{3%W}Wks^*e7(v50$K#Jelf^kc3ZH}~=T4u2j$ zimp-Zy8c5bzEJ%U_tJ{u584%d>2WJ#!nAJQO^~bMYMW*6dT`TTj=>rwA`%IQ V*Ž6ˀf'06LZ^s03ey1 b$=Hz A2o6 </_& \ No newline at end of file diff --git a/core/assets/baseparts/simplemeltdown.msch b/core/assets/baseparts/simplemeltdown.msch new file mode 100644 index 0000000000..3cb3fc34df --- /dev/null +++ b/core/assets/baseparts/simplemeltdown.msch @@ -0,0 +1,2 @@ +mschx=벓0 (=8@tjɝqjqmq(|ٗ|Q㼘j5w<8U/5]kvvݢ];8c-[R߼z?;(.za5jY)m|/n2زKߩ\N]v5C;75?%#N~ˑ~A!" 6_r$F2U#>yIR. `2'ʼD=)eۓ[]D#C&4HJVxHjӎLZr>;XUD"%(Bg$QJ'X\ZS2x`Bzo:M +Up$wI%̓G2޹A# " PHLo \ No newline at end of file diff --git a/core/assets/baseparts/steamgobrr.msch b/core/assets/baseparts/steamgobrr.msch new file mode 100644 index 0000000000..99af5789df --- /dev/null +++ b/core/assets/baseparts/steamgobrr.msch @@ -0,0 +1,2 @@ +mschx%r JԘfm:@u̠d^Y.fd!6gmȿ\^6R0m_p9N1upvf¯/3)9u3IoO +\$NGD=ȡo\7l03i1H<H\(FE 5s\(FYd /Jh%Zi,:#VIX%JbUB*ݨiFu8IJZIhVi^UZhQW?J- \ No newline at end of file diff --git a/core/assets/baseparts/strong_duos.msch b/core/assets/baseparts/strong_duos.msch new file mode 100644 index 0000000000000000000000000000000000000000..32027b2c7e78527f1e44e43e71ebe9d31a7108aa GIT binary patch literal 316 zcmc~TPR?Mgm}7b=Hm})0faSr)-rPE-CF~E?_Bvi=_qrp}`QXF^m%X)ndwwiPOJ?`tCyg&CWZSAM^%G;VIx=A<+JL?o4Iqmjt|H4N} zzEYPa^?fm5eZEzaS9j{fhc$NpPkiE>WSKTElv6!)-=YxHDIvVS{nkWfoV5D(HQ;!R z#kJ%QCJSk*}8n5NVX(db4(^uF#6dGg#0HHIUi~s-t literal 0 HcmV?d00001 From f59c439f2f88d2d109579ce4f5e65e24c6af6d27 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 17 May 2023 19:32:47 -0400 Subject: [PATCH 0024/1150] Some more random schematics --- core/assets/baseparts/rtgbrick1.msch | 2 ++ core/assets/baseparts/rtgbrick2.msch | 5 +++++ core/assets/baseparts/rtgsalvo.msch | Bin 0 -> 166 bytes core/assets/baseparts/solarbrick1.msch | Bin 0 -> 110 bytes core/assets/baseparts/solarbrick2.msch | Bin 0 -> 108 bytes core/assets/baseparts/solarbrick4.msch | Bin 0 -> 121 bytes core/src/mindustry/ai/BaseBuilderAI.java | 2 +- 7 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 core/assets/baseparts/rtgbrick1.msch create mode 100644 core/assets/baseparts/rtgbrick2.msch create mode 100644 core/assets/baseparts/rtgsalvo.msch create mode 100644 core/assets/baseparts/solarbrick1.msch create mode 100644 core/assets/baseparts/solarbrick2.msch create mode 100644 core/assets/baseparts/solarbrick4.msch diff --git a/core/assets/baseparts/rtgbrick1.msch b/core/assets/baseparts/rtgbrick1.msch new file mode 100644 index 0000000000..f894bcdd1b --- /dev/null +++ b/core/assets/baseparts/rtgbrick1.msch @@ -0,0 +1,2 @@ +mschxK CͯE= +ʂB% D~ya?2 Q%|ԔlʈYܵ4 $ \ No newline at end of file diff --git a/core/assets/baseparts/rtgbrick2.msch b/core/assets/baseparts/rtgbrick2.msch new file mode 100644 index 0000000000..f6898651e9 --- /dev/null +++ b/core/assets/baseparts/rtgbrick2.msch @@ -0,0 +1,5 @@ +mschx K +0COҖEMpN0v; $! v7t>mGjMc`%DtK!a0333^iZ+|z9JzJkpC~Yuphp^1| zwMT10e@wk~=;e!*Vhm=-#h|qSnc%H~-?--&d0=j6bmP=CDrwmXE6&LD89!k;;AS7FbK&p`*F6=g<jFQ3Ul4b7BQBo-B P7Fsp)5tIBuf5{vG{Z=oR literal 0 HcmV?d00001 diff --git a/core/assets/baseparts/solarbrick4.msch b/core/assets/baseparts/solarbrick4.msch new file mode 100644 index 0000000000000000000000000000000000000000..d740903d5e5000e872b5879cc59a366eff7c30f1 GIT binary patch literal 121 zcmc~TPR?Mgm}A;~k?W8Fk8A#ArRImr-<;hqS^XkyLQ<}~)y?;}C43ds&F3g6RI~`i z_iVf>lR9;aZN9|&J7%80CuT7goGg5L$KkV+ec`R-hj$J~%h||&O?ml9^!_KSIgLDV d58vFYz7WeB#9Tk|&2`N=jXbvX3{TR;JprttIwAl7 literal 0 HcmV?d00001 diff --git a/core/src/mindustry/ai/BaseBuilderAI.java b/core/src/mindustry/ai/BaseBuilderAI.java index d53ab68712..afc2a40be8 100644 --- a/core/src/mindustry/ai/BaseBuilderAI.java +++ b/core/src/mindustry/ai/BaseBuilderAI.java @@ -25,7 +25,7 @@ import static mindustry.Vars.*; public class BaseBuilderAI{ private static final Vec2 axis = new Vec2(), rotator = new Vec2(); - private static final int attempts = 5, coreUnitMultiplier = 2; + private static final int attempts = 6, coreUnitMultiplier = 2; private static final float emptyChance = 0.01f; private static final int timerStep = 0, timerSpawn = 1, timerRefreshPath = 2; private static final float placeIntervalMin = 12f, placeIntervalMax = 2f; From b611e0f9f49be7c3f14483a0b5c97c1c951b4bac Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 18 May 2023 00:27:01 -0400 Subject: [PATCH 0025/1150] Tecta buff / Closes Anuken/Mindustry-Suggestions/issues/4427 --- core/src/mindustry/content/UnitTypes.java | 11 +++--- core/src/mindustry/game/Schematics.java | 6 +++- .../maps/generators/BaseGenerator.java | 34 ++++++++++++------- .../world/blocks/logic/LogicBlock.java | 4 +++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index ffd418a857..514bc19b21 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -3258,7 +3258,7 @@ public class UnitTypes{ drag = 0.1f; speed = 0.6f; hitSize = 23f; - health = 6700; + health = 7300; armor = 5f; lockLegBase = true; @@ -3271,13 +3271,14 @@ public class UnitTypes{ abilities.add(new ShieldArcAbility(){{ region = "tecta-shield"; - radius = 34f; + radius = 36f; angle = 82f; regen = 0.6f; cooldown = 60f * 8f; - max = 1500f; + max = 2000f; y = -20f; width = 6f; + whenShooting = false; }}); rotateSpeed = 2.1f; @@ -3319,14 +3320,14 @@ public class UnitTypes{ velocityRnd = 0.33f; heatColor = Color.red; - bullet = new MissileBulletType(4.2f, 47){{ + bullet = new MissileBulletType(4.2f, 60){{ homingPower = 0.2f; weaveMag = 4; weaveScale = 4; lifetime = 55f; shootEffect = Fx.shootBig2; smokeEffect = Fx.shootSmokeTitan; - splashDamage = 60f; + splashDamage = 70f; splashDamageRadius = 30f; frontColor = Color.white; hitSound = Sounds.none; diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 118fdaf14f..32b304f3e9 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -492,10 +492,14 @@ public class Schematics implements Loadable{ } public static void place(Schematic schem, int x, int y, Team team){ + place(schem, x, y, team, true); + } + + public static void place(Schematic schem, int x, int y, Team team, boolean overwrite){ int ox = x - schem.width/2, oy = y - schem.height/2; schem.tiles.each(st -> { Tile tile = world.tile(st.x + ox, st.y + oy); - if(tile == null) return; + if(tile == null || (!overwrite && !Build.validPlace(st.block, team, tile.x, tile.y, st.rotation))) return; tile.setBlock(st.block, team, st.rotation); diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index bab2dab6a2..5ef5199386 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -24,7 +24,8 @@ import static mindustry.Vars.*; public class BaseGenerator{ private static final Vec2 axis = new Vec2(), rotator = new Vec2(); - private static final int range = 160; + private static final int range = 180; + private static final boolean insanity = false; private Tiles tiles; private Seq cores; @@ -51,9 +52,9 @@ public class BaseGenerator{ float baseChance = Mathf.lerp(0.7f, 2.1f, difficulty); int wallAngle = 70; //180 for full coverage double resourceChance = 0.5 * baseChance; - double nonResourceChance = 0.0005 * baseChance; + double nonResourceChance = 0.002 * baseChance; BasePart coreschem = bases.cores.getFrac(difficulty); - int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 2 : 3; + int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 3 : 5; Block wall = getDifficultyWall(1, difficulty), wallLarge = getDifficultyWall(2, difficulty); @@ -80,7 +81,7 @@ public class BaseGenerator{ tryPlace(parts.getFrac(difficulty + Mathf.range(bracketRange)), tile.x, tile.y, team); } }else if(Mathf.chance(nonResourceChance)){ - tryPlace(bases.parts.getFrac(difficulty + Mathf.range(bracketRange)), tile.x, tile.y, team); + tryPlace(bases.parts.getFrac(Mathf.random(1f)), tile.x, tile.y, team); } }); } @@ -148,10 +149,13 @@ public class BaseGenerator{ }); } + + float coreDst = 10f * 8; + //clear path for ground units for(Tile tile : cores){ - Astar.pathfind(tile, spawn, t -> t.team() == state.rules.waveTeam && !t.within(tile, 25f * 8) ? 100000 : t.floor().hasSurface() ? 1 : 10, t -> !t.block().isStatic()).each(t -> { - if(!t.within(tile, 25f * 8)){ + Astar.pathfind(tile, spawn, t -> t.team() == state.rules.waveTeam && !t.within(tile, coreDst) ? 100000 : t.floor().hasSurface() ? 1 : 10, t -> !t.block().isStatic()).each(t -> { + if(!t.within(tile, coreDst)){ if(t.team() == state.rules.waveTeam){ t.setBlock(Blocks.air); } @@ -208,7 +212,7 @@ public class BaseGenerator{ for(Stile tile : result.tiles){ int realX = tile.x + cx, realY = tile.y + cy; - if(isTaken(tile.block, realX, realY)){ + if(!insanity && isTaken(tile.block, realX, realY)){ return false; } @@ -219,12 +223,16 @@ public class BaseGenerator{ if(part.required instanceof Item item){ for(Stile tile : result.tiles){ - if(tile.block instanceof Drill){ + //uncomment for extra checks if changed above + if(tile.block instanceof Drill && (!insanity || !isTaken(tile.block, tile.x + cx, tile.y + cy))){ tile.block.iterateTaken(tile.x + cx, tile.y + cy, (ex, ey) -> { + Tile placed = world.tiles.get(ex, ey); - if(world.tiles.getn(ex, ey).floor().hasSurface()){ - set(world.tiles.getn(ex, ey), item); + if(placed == null) return; + + if(placed.floor().hasSurface()){ + set(placed, item); } Tile rand = world.tiles.getc(ex + Mathf.range(1), ey + Mathf.range(1)); @@ -237,16 +245,16 @@ public class BaseGenerator{ } } - Schematics.place(result, cx + result.width/2, cy + result.height/2, team); + Schematics.place(result, cx + result.width/2, cy + result.height/2, team, false); //fill drills with items after placing if(part.required instanceof Item item){ for(Stile tile : result.tiles){ if(tile.block instanceof Drill){ - Building build = world.tile(tile.x + cx, tile.y + cy).build; + var build = world.build(tile.x + cx, tile.y + cy); - if(build != null){ + if(build != null && build.block == tile.block){ build.items.add(item, build.block.itemCapacity); } } diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java index 36fa541c6e..188b3b93f6 100644 --- a/core/src/mindustry/world/blocks/logic/LogicBlock.java +++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java @@ -73,6 +73,10 @@ public class LogicBlock extends Block{ link.name = ""; link.name = entity.findLinkName(lbuild.block); } + //disable when unlinking + if(!link.active && lbuild.block.autoResetEnabled && lbuild.lastDisabler == entity){ + lbuild.enabled = true; + } }else{ entity.links.remove(l -> world.build(l.x, l.y) == lbuild); entity.links.add(new LogicLink(x, y, entity.findLinkName(lbuild.block), true)); From f2d83f35992baaa3e0a87670eeffa180f33c1a1e Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 18 May 2023 00:45:18 -0400 Subject: [PATCH 0026/1150] Vanilla base walls only --- core/src/mindustry/maps/generators/BaseGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index 5ef5199386..3cd472c4b6 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -31,7 +31,7 @@ public class BaseGenerator{ private Seq cores; public static Block getDifficultyWall(int size, float difficulty){ - Seq wallsSmall = content.blocks().select(b -> b instanceof Wall && b.size == size + Seq wallsSmall = content.blocks().select(b -> b instanceof Wall && b.isVanilla() && b.size == size && !b.insulated && b.buildVisibility == BuildVisibility.shown && !(b instanceof Door) && !(Structs.contains(b.requirements, i -> state.rules.hiddenBuildItems.contains(i.item)))); From 72c28f70983bfa9500b085f9d227ceeb529c6cb9 Mon Sep 17 00:00:00 2001 From: Ilya246 <57039557+Ilya246@users.noreply.github.com> Date: Thu, 18 May 2023 17:29:44 +0400 Subject: [PATCH 0027/1150] insanius (#8621) --- core/src/mindustry/maps/generators/BaseGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/maps/generators/BaseGenerator.java b/core/src/mindustry/maps/generators/BaseGenerator.java index 3cd472c4b6..e38c5206fe 100644 --- a/core/src/mindustry/maps/generators/BaseGenerator.java +++ b/core/src/mindustry/maps/generators/BaseGenerator.java @@ -25,7 +25,7 @@ public class BaseGenerator{ private static final Vec2 axis = new Vec2(), rotator = new Vec2(); private static final int range = 180; - private static final boolean insanity = false; + private static boolean insanity = false; private Tiles tiles; private Seq cores; From d739269f59ba726ec4ca28955f6d9df0d4dbe5e2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 18 May 2023 11:03:58 -0400 Subject: [PATCH 0028/1150] Scatter resprite (By Daz from Discord) --- .../blocks/turrets/scatter/scatter-mid.png | Bin 499 -> 510 bytes .../blocks/turrets/scatter/scatter-preview.png | Bin 779 -> 817 bytes .../sprites/blocks/turrets/scatter/scatter.png | Bin 547 -> 603 bytes core/src/mindustry/content/Blocks.java | 4 ++-- 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/assets-raw/sprites/blocks/turrets/scatter/scatter-mid.png b/core/assets-raw/sprites/blocks/turrets/scatter/scatter-mid.png index b33adc2c1775adc58912ae666921ef9bc5451ad7..1dc01391fe9052ed8f1852b8cbc0f79e37381f93 100644 GIT binary patch delta 471 zcmey&{EvBpVf{Q$7srr_Id5kh`WR>pIK(a#2fhJ@FK)j+{p6+rPt!~emXwFgtt_h=f_^mUHmW7~ z{%FuVID0`-KzNh!4xtupM}~DQD|ZN`@W1dXU<_|6Q1x)tdQfrW@$28=maKgZZ&nA? zh_X%aN~o2+6>}iyhl6V4zIv8T9~zS^D}+P*9e86MUYhFb_OG3=hjAv0YemBc^_8ce zpBFu$eQ*WyrVoWGd9%_kTYCLw^nNJ0L)k@^cj|YR=2g266(4`Fv1R9no@B$Pyc(VX zZR~dh3cb(x2L9?;u}4>~M|H&^<|W+1OYOa;^Evi-i%cG zyF`S^t8Jov!Y`a z{|)&*S4FuKEKl}t3uNyu@p+FG(0yUNjeu?J{CUrt4v(~ZpsI5M@ z>^$S?t5qzg)DP}^A3L9W7w3j2y+OJUG!HJ-|6u%c&ZRB>nin50KHm`ZY4%&b*z2)> z)*Sbl@Rn)z+jp;bsWkSwILxcx19yO8m*RWI`1pDH`^h=gB8pH!c12fS8y_#?tk<6Z?EgUQ>*Ukt+r#HAtbTa z>6B1{M}nzW=J$qKLNj8MUioflV=3#Nvyc0ad(-j%%uNazv;B8Im=g23df7q-1_lOC LS3j3^P6Q5Di(^Q|oVT+b^Oy{IT<@-8UwK4o$*SiIUdyqFEl!L)vPfph>u+is zp6Qf`YD(oC?~`p`^?AB;+sXRJoc1Rf46?7S`M;(;PCRb^-griau+yvz3~#>w)~l_2 zQ+P4O?z%;v`Eex?J_h6YSD2kN7|zuMnY0)%2z~aPD6p%C@%xf`Nr(4*U#{^iIPPkG z`|jC|i4s;{mM}A%sR`oeSjb@U+4G{nAqI~#>aI=|o95W?n%m!xR}`L=8L-J`$trCI z@3Ko<%K!Y?VOeG&<8u9I&>~gKFvbTx(-ab(P4*J7SiDu>3WG}d%&fyR{TC^C@LY2U zV7%ayu`E~h+2mycCdal29I0n8c~z{6N6mE!&pg@=Ra$$Z)~adXG1{ zzNM?!9P>F=KV5XPJZnkcAye67=T2Hj{fb%jXU?*~2xiBub6kwsw@tXNPt!|Zb+kOp zJ<*eGe|uwKkg5#JRfQcl--XPyi#lwuB7DkGhN8z}95GiTgwpb2m>pRdjNkAcJZ)3X z6a2YX@YTkXiV4rMPwjM5Vu)zFu2aPHK(xNtD&FI>RN`m$mvfwA7MCH8;4ZB3l0zD=01MTo;}a#Nvhld zftEcA0bK_C2|i6y$+NaeIbYj0fXE{+b?lWtM67wfh(Jm7eT$`rw(nih+TF!PAw^&t;ucLK6T{SznF- delta 742 zcmdnU*3CA-u>Pp0i(^Q|oVPPJ=1DmUwAH&;PVl&*;9ALkx;J+Al}Z*3fhm@OD*X>` z1vm>oHC*s*b4*vpoUf_*`Dx{8&!^l8SFHK*?0-aBIp2&KKi2PDS$p_*yL;75rUOZK z)xqAEO+sH+hJVeg&zSjs=3_+#(Ji}J){7cQsWIMTt$3`JU^u`2VNvZzorC@k8~*O} zDi9QCQ{ST!A}+w~U*S>kmT~%P?;sD}d*1c}GO4?_FcjFyMjn6t;r29>!*9#H+n2tm zUE-d(R#d_2;L$^AYgncRFK%mi^r5A_C5Tav*{6Mxlov~nqRqru?{y7^t?HYygx)i) zl-7M_tn+OD?vl$U7xm`8s{gU_U%~$mH!hiW#$9y!F~NNc(~1s>yNjCMW_^fi5T93^ z`)Z%z4JMU`mPZTH8~6Rr@=V}7!FhgRiPV(|1{w;Yc1Pdd71~~YdjGxY^O*V0`&-!9 zKb>-5Qi2ipktXJR=}2*|`{5<)S`@Fa^0cb&+U(%r%Ne@tV2JYR%muS%aC>~MpK!IR z{cPIh-#4X%?#yFfb8Ywa>zbU`c(@*%`+nrSeEY%dLmyb&4}JP9?y0$V`9*!ZwqH7k6Z|68R!{vh#SP1Bt8 zCeK}$A3VLa|Lxjq)-}I=DBfh*Eu3&}r$Xy1{{{IXeG{#@Gy0EYF%=yajuQ%DnbM|i zqawmRq2;=p^Pw%gRpJkNe=$!qeE7{Fg=fV%CWm<~SKgdgO%IYe$}HIXp~a=?C$nH5 z%h?Ys?oII~HWMtlTZGOnfBgFQwPs<@6P&k>Z{f}Qw^?d;>$C0r5^ET|Id45=Ts*&_ zm8JVbLn8l$DG8!-26;_VLOO?;Mavq6IIlfaS5s4~V{GoVP-5zu@|%Hyfx*+&&t;uc GLK6Uq&R-<} diff --git a/core/assets-raw/sprites/blocks/turrets/scatter/scatter.png b/core/assets-raw/sprites/blocks/turrets/scatter/scatter.png index b37f3f7c535271bbe6674a8eed776c82a54f9ce9..83613f9364730f4fe789b114471fef646a38e30a 100644 GIT binary patch delta 566 zcmZ3?a+_s>K|PbGr;B4q#hkaZ42upK2)LThywf6;$7IUhcqsW)g~p`jC4PBKrs;}T z&uPfryrus(>QhR5JA34x^vF0)VavY97BKY3IL=GzJ^%6aA3vY}Uj3pb=-0mgm){%k z-29tnF4LaAMz!a#@lK&lQogO}YgBw%(~DFN@CH4sm(1l{`GH4^@z*93o5iY*Qu7>D z_IT~@Xj{*z|u?X z79cc_V+ONMdVNyv1a4;ErtAp~eO^06@*i3-cQcB>ib&J=%USO8Qm{<_vbS_SI*K83sca;v7BTU|^Q*t7` zRY8myy6xASJPtfRzWYUl?z-!%UqtYH7TAwB?YnsEE^6m5erZtu-vsGbFqZ32RO{WU4x) zO+6@z`^tm`g7Z8I4MisFFZigu_FT5x{qO$0=FZ37@E?CZEAC2>OuFnJreDXnpH8+p Sl+3`uz~JfX=d#Wzp$PzT<@^%> delta 509 zcmcc3vY2IpK|SMLPZ!6KiaBp*8s;$>3b@(_p4!Wr`+zNQmj>^Z30B(|+>2hqcjbbM zCEJxdO?AO76HjE7zukEJhRXj?4~g@C`mb9jGq(shaVWM3IQ^4Xe#@Ws+4X)nFTPZq?+MNNxQ+ zA{8*HLQ!LR^=XI8CnYYQJg*mfee28H31;yo3>)la4CnT=7X=>;<(;Oo>xI{;Q!VRu zFsrS2RKx0C%BZ$(`s6T>_?`9)y|UY2Ar zB>eoftV@4KSW~F#4{pKyll8wI->vaeXk^qp!ma7!v56^)?JWYN$e48FXu^qml~f9BKkjOB-E< Date: Thu, 18 May 2023 11:54:30 -0400 Subject: [PATCH 0029/1150] Less MeshBuilder memory usage --- core/src/mindustry/graphics/g3d/MeshBuilder.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/graphics/g3d/MeshBuilder.java b/core/src/mindustry/graphics/g3d/MeshBuilder.java index af2a7e040f..6bc0688552 100644 --- a/core/src/mindustry/graphics/g3d/MeshBuilder.java +++ b/core/src/mindustry/graphics/g3d/MeshBuilder.java @@ -11,7 +11,7 @@ public class MeshBuilder{ private static Mesh mesh; public static Mesh buildIcosphere(int divisions, float radius, Color color){ - begin(20 * (2 << (2 * divisions - 1)) * 7 * 3); + begin(20 * (2 << (2 * divisions - 1)) * 3); MeshResult result = Icosphere.create(divisions); for(int i = 0; i < result.indices.size; i+= 3){ @@ -35,7 +35,7 @@ public class MeshBuilder{ total += tile.corners.length * 2; } - begin(total * (3 + 3 + 1)); + begin(total); for(Ptile tile : grid.tiles){ Corner[] c = tile.corners; for(int i = 0; i < c.length; i++){ @@ -71,7 +71,7 @@ public class MeshBuilder{ generator.seed = generator.baseSeed; } - begin(grid.tiles.length * 12 * (3 + 3 + 1)); + begin(grid.tiles.length * 12); for(Ptile tile : grid.tiles){ if(mesher.skip(tile.v)){ @@ -124,7 +124,7 @@ public class MeshBuilder{ VertexAttribute.color ); - mesh.getVerticesBuffer().limit(mesh.getMaxVertices()); + mesh.getVerticesBuffer().limit(mesh.getVerticesBuffer().capacity()); mesh.getVerticesBuffer().position(0); } From 43d164d54bc725dd01edd3af9995dfd5eead2173 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 18 May 2023 12:21:45 -0400 Subject: [PATCH 0030/1150] Map list fixes on phones --- core/src/mindustry/ui/dialogs/MapListDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/ui/dialogs/MapListDialog.java b/core/src/mindustry/ui/dialogs/MapListDialog.java index 74f785da3c..310bb4ff48 100644 --- a/core/src/mindustry/ui/dialogs/MapListDialog.java +++ b/core/src/mindustry/ui/dialogs/MapListDialog.java @@ -88,13 +88,13 @@ public abstract class MapListDialog extends BaseDialog{ cont.add(search).growX(); cont.row(); - cont.add(pane).padLeft(36f).uniformX().growY(); + cont.add(pane).padLeft(28f).uniformX().growY(); } void rebuildMaps(){ mapTable.clear(); - mapTable.marginRight(18f); + mapTable.marginRight(12f); int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1); float mapsize = 200f; From 3dd7412ed86e40a4d2af3cd8b2ff309543a32a13 Mon Sep 17 00:00:00 2001 From: nullevoy <89076920+stacktrace-error@users.noreply.github.com> Date: Fri, 19 May 2023 01:56:39 +0200 Subject: [PATCH 0031/1150] swarmer resprite? (#8573) * plastic * swarm * I did not forget I did not forget I did not forget I did not forget I did not for * god I can never settle on anything hhhhhhhhhhhhhhhhhhhhhhhhhhhh * Revert "god I can never settle on anything hhhhhhhhhhhhhhhhhhhhhhhhhhhh" This reverts commit a59734eb04a923e2209c795ac533e61598c8b341. * eh why not * Revert "eh why not" This reverts commit c228dc5337c915faf3bf4abe09d8fb5e6909a424. --- .../sprites/blocks/turrets/swarmer.png | Bin 893 -> 873 bytes core/src/mindustry/content/Blocks.java | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/core/assets-raw/sprites/blocks/turrets/swarmer.png b/core/assets-raw/sprites/blocks/turrets/swarmer.png index 6f98a1ba7aa0ae3d46c9f453d4bc32c0d3d18ecb..508e74f8614ba77a53a180044b3e1efccbdf0321 100644 GIT binary patch delta 837 zcmey%_L6OaVZE}ai(^Q|oVT-WyKg%PwB45}%=aih+t}*sA-J<_{xhlDYj=kUdzs9wUK*sq-i3*(;V_nlT~d`V!6^{tH8tQ!4kTyLETU8F-Xm%esGj_06g0*m-z( z{+zeDm{YU!)|JmiTnsnfmIXeKT4!d;aOQO8myL!onWjFB9jjK=XWgz=?eBGUbuecT z6ly8X;d;cB!>Dp$!iSJuj`I4aTW2j0*`vH*)vBn^Qdg38-nyc=_@d^5y9ZP~J6>)N zZ8&*P)uZF>_P~ZT#nY|6hav^Pw4RSWV)1|bEkCN*I<^UjZ4 z4@3-kmvm=b;PB8)n&lyO@qto?cGAv*-WG|F^v3qtg_~=?SM*qw?UpdT{XPDF*VmQZ zQGz+`=5Kdrw41;6UZiwD%*>@pcg-}GkKPBwH~sz{>9XN%l1iOrM_)sw<y1yU z`A59xPd_@Ndq%^zEsGTs_u8A>o+RYLGUM4D0nW|0v;X}0bo=+dvI-}!rtkxY&+e$4 zxk1+=PX52e?YVd3%x~Lq&cDCM;NKm!#N866`tp8^`&RlW*(jQ1UhbT;~K zSne15Y-8tPnpgkh#hg#HN~%&Jtj{0C2&RUpom;S3{x!UorNbVb>zImn{;g+ ztYlPaEat!8_BrB?i^u+$hm8$NFII7Cx}H;2d^)+@^Fu2;Q#xa?^Bk`HNe3jqsd4U0 z@>BV*eyqPd|7QG*J=Hczael7g#;FN@ yoOeDnTnMsgXX*UV@L;dQe4!LIB>Ybi0F7NBs#|R7Nu30Z6c=6lOy0yB;bKlng|MEF->0Q}%o6k;f zkKS6nQGR~=KU3zKxvGw5qU-b7bcDVyk&UZYFB4&FzJ2$8>OlS>x;+#km*(8aiu`9$vz8wIxvzunx4Jpt8kO`T1d zcRWyOEKc+6?OB+{pd^sl%yGrU@o2-k?M6zr!V1i0*TS2X0zW?fC))cv{9@VVixZYD zR{SzoQP|J#d}8w=wi`^d`?l!L5pLi1ctfkQ+LnF1zufMs^W`r0-DY(_tlg)+cbkWq zLaO1czBbQCreg6^ojOb(dj8N9T=-VjZ3^QpR}X0q-e!K6XO4Rg&S;nsIGd^3d-J^C z{Hy){xT|lCmpzvfsP?JsbKTQlXD{AAwblR6x1)9WkM4XW=Df)f>72qj7cQjVxm~Y%Fg%6lTge51t$V&LD60MWnE!XB@SB$p zy2|4xHg0!ZqE&pf;7#2RPnZACR&9}cP?vp2z3TsKy)U*G%sQqmdGSK>qgloQml+pV zEDU5`^0nd&%lr!Fq$ZWq0>W0cVh-E9%B?p~>~Md1hQV|0ftd?@&oY!xy|Tb_;*~Z| zyWERB7WIF=gnnsTHhY<-=%VbVl5QJoyN+Y;Ob?WDnJ(QZ<=eUbqn5(EWGb0c8s4e|#T@xCbAjT$drTLD&g7Qp)Rom-@LtQ_!+AQ} zYO&tk|GXbW3S_UIV9|~FIH`2?M2_D#bWDYV`VY)nve$R9Ye2PchS#beP74EeFzURG W*=JPJ)5XBRz~JfX=d#Wzp$P!6q>)bm diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 9dc0ca3344..3f6dd01948 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3421,7 +3421,7 @@ public class Blocks{ shotDelay = 5f; }}; - shootY = 7f; + shootY = 4.5f; reload = 30f; inaccuracy = 10f; range = 240f; From 0f87942b16c4482089be0b6d92d92ddaeea4156f Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 May 2023 00:01:36 -0400 Subject: [PATCH 0032/1150] Fixed #8622 --- core/src/mindustry/mod/Mods.java | 6 ------ core/src/mindustry/type/Weapon.java | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index d3bda2a127..00b3bc79fa 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -202,12 +202,6 @@ public class Mods implements Loadable{ continue; //(horrible code below) - }else if(prefix && !mod.meta.keepOutlines && name.endsWith("-outline") && file.path().contains("units") && !file.path().contains("blocks")){ - Log.warn("Sprite '@' in mod '@' is likely to be an unnecessary unit outline. These should not be separate sprites. Ignoring.", name, mod.name); - //TODO !!! document this on the wiki !!! - //do not allow packing standard outline sprites for now, they are no longer necessary and waste space! - //TODO also full regions are bad: || name.endsWith("-full") - continue; } //read and bleed pixmaps in parallel diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index a52b423dba..fd8fd02304 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -251,6 +251,8 @@ public class Weapon implements Cloneable{ Draw.color(); } + Draw.xscl = 1f; + if(parts.size > 0){ //TODO does it need an outline? for(int i = 0; i < parts.size; i++){ From 6cd778783ea01a061add608751b48e277e894dc5 Mon Sep 17 00:00:00 2001 From: MEEPofFaith <54301439+MEEPofFaith@users.noreply.github.com> Date: Fri, 19 May 2023 07:53:06 -0700 Subject: [PATCH 0033/1150] Shift swarmer shoot barrels to match the chutes (#8624) Similar to how cyclone shoot barrels match the ends of each barrel. --- core/src/mindustry/content/Blocks.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 3f6dd01948..6ad0a5b3dd 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3413,11 +3413,14 @@ public class Blocks{ lightningLength = 10; }} ); - - shoot = new ShootAlternate(){{ + + shoot = new ShootBarrel(){{ + barrels = new float[]{ + -4, -1.25f, 0, + 0, 0, 0, + 4, -1.25f, 0 + }; shots = 4; - barrels = 3; - spread = 3.5f; shotDelay = 5f; }}; From 39227774e14aeb41761e15145b6433a776b8d410 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 May 2023 11:08:18 -0400 Subject: [PATCH 0034/1150] Ripple tint change / Minor optimization --- .../sprites/blocks/turrets/ripple.png | Bin 1498 -> 2015 bytes core/src/mindustry/core/ContentLoader.java | 2 +- .../mindustry/entities/comp/BuildingComp.java | 13 +++++++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/assets-raw/sprites/blocks/turrets/ripple.png b/core/assets-raw/sprites/blocks/turrets/ripple.png index 92bd3db328fdba385d267986c032eee5fdf9d7a8..4660117fd84fec22acd4247a7a25affcb6b9d6ba 100644 GIT binary patch delta 2002 zcmcb`eV>1Vaym&VUUON`LpNF?E9WpmM8j_pRc6cdUy5z|9gH`?bfbeuxQbuMUOTZx!inl za!AZ;nDYsrt8mTWtj7R-;3Y5_4R*?&sU7P!K$`6JOCS}`}*QdYRtTW{jgKTWg(H9xEo9F87J7lu3r^e)ku))G> zS1w+(VpwoBXTvw!j%6p@uW+oWznZn;YSyDq>3!>5Y-S&nZFZi*Vc;76K7N0luh#r1 zkUIk9b zWnsBt9XFkG(!>ih7i*t9BPgkm8K#kHCa3fM|5?F!M?**ZHs07DB5E6WIC3wqd|I#i zNIS{RiR%R0kvBfR${=;u&j@@JtyFsvIAPbZ*)DTC_U^CFEnjYbM=>{k_0E&feM6+`6*3Hva$Tqu(R;S2>pGy#A=# zdS=$%+Cr)N+v3aT-q!w@d~jw5tIT3{hUw|ojqmr~uW$SK`}{Av$!?6N88)9iFD&Pw zyiaKN5>DdfzjU7U8xB^GKfZ<(LT>n8m>9KHI-=YFx@ zr~drvzIfBp%Kn|pnXP}*@7Lb^zVGtOC)2`fn{Ms9n>YEqDt}NtD8zoccYEEK_wCm5 z6|>$8@9OZl(cKoe{PIZ&^UUs=yaNo?CHNC0pml=FCDYX??zqZJ+ zi^2b`f7EC8&ecjKRF43^5DtkYKxy=;yxU7^68i;yiCCP&)53Z;wQYX zt*Jb)j9U|8A2> z>hGNog%6yv{#4iPkkeo}@BVR#)PStNPj8m4=bYqca-Jp2BuG8Yyv0rI9!p?*?Yh-` zPH9`WJ%ty|x%KNr_WA2Kvk9zW6>TimePI$?Q+h5fc)Lm2wsgDIhgdb4VjgKbwNH1rrTReP;)-yI zXnWUQmO%LjukJW`COYMO6uoqi={CcC7xgyI)Z^DfynHmy7JW%<&22dUwAtj+#7Eg` zs;3neacr1bAaNx8hL6Dgh03;^cUumt>~k_#Oktd0QqRAmE+_khnMiEx?UMDJksEyP zhy~oa9HMa}ZR7sA|7L`gC1%~RS*RV^)2N)Xbh1;XdQy;J@I71M=1WoxM|PgueC83esyRc)d_isL zC3X(`JDnV5S&zQZRyp6)p=!5PSTEOahH=bS!QW}NT(12M4K9`sr>OBb{YkM*lqlcC zbErk6r6WGVPh#5bjvbbXvpJWZ<}~)0Cfw#+bJWq(U2D~x4b58h>OKh*EFXrLzx-*j z1xzn}=J2FtsrgIMg9}e{icjU|Sa^zadP9U|;-!eM4-dDWOLsYPqUWXku{TdX)y2f= znxB3>^{8n^haq>~_S??N%E~*Ro)rA>)_gkGNlxbGlia`Eau!-XEZZIH;}>DBnC2(( z!CuTr?TWO?619RO>@4-Q4Z1=#Eqd~DarQxdhW2_==k|ynavJ=H=mh3lG4(f zUs+gM&Wtw8P&(GzCSdV@$wHn-!JP9r`A@N2FLvgi^n>AXrK4TY><7C(E%bRbzsk=0 zmj4#+%{6LE-e@NYEpB`6nAhYqZ$@ZH%a&QaieCfX-e~FYU;CF~Ge1YAcS&T9aMamj z|NbS-RuKJv<#Xh;9}E{6KHoRvy~Pq+<{9 delta 1481 zcmcc5e~Wv9ay{!pPZ!6Kid%2z+UCg^^0a<;@SN|hQX2GAit)~pGpcuXnF%PUdpz9C zV&^P$UMcwum(WpnyP!)++-08^SKjZ@m^A6xmoHyRX5Fl-{rO zvpM&l3U}Ch|L>=%%z?80)yx~XzVZvmS}(;0LGs`QV9FswP`t&qha z(B5tFY$@Z0Bl?aJ_iH#CMC+Y2{}nNOYj;-2n6pmBj%(pl?yRtEdFvUAJMN!yFk<*} zujY&Q1es51>z}Wf*UPHp@*{&`mf%G81Ajga4-Y6F3HAFGCWKXflj*P8J(NOoj0mh4-i#lg)Y z*s$&P#jbqD1AIpW7;HIu-mTzTV0z?BSN(aW2b@O&7%mE25njZ?kTJiO@qlp0LdS@+ zoY@Q>-#r-*2-T-D1PYvCSkq*{Xb>dG!63rK%AmB5^?+d0)3e)aICVeTGOQ6uVDMm$ zZ{E21D}zVhoVi^Z?URHWuAlgxbHerxLzRFIL!ZC}yLofF0%{hDKdNS!v1@?_gEh;t zAJghXTG$Q*{!wI5Nq@t*K{B|;TWeAJ(jQ_B9=oLC6dtk$M7>o!n7H=ko=^WKRc>0F z#-Pg)$Pgv4rPgc;f7Ts)u7;gzZ&(*JKB$aX>p$^UbH{wX2GjWaOboJHGj6vsoQUY3 zuq}a!F+tKSOEH5nMVG@fcH<((1ljG`zRU{6u71DjCn@qXbsXHEn-}-Q^9|V&q~hwckj-%X}q?Tk)d|Rezh9r2|N$3vGTraaJl*=6jJzjZ zYT7H?qEVNd`b2|a%ikuodZrCCv$C5m#tIk<$z5di6!2kC%06^)=Ylh{HgGniCiA8F zR){jpnzbSAJ;(QJCOr;0A`L4Xcy1m#w$)z1nCl#yfFy7B(RM}|#gwHAZr7M~1fm`} zGnfdtJ*zi*&8Wbz^+P_xh1^pU<^~&e85xTt%gM?4>AueW!TWxisc=h}V0~TL$JpPj zXPFu|mPRi5Val*>Wv8*DMC|v}PJdPdu5%s}of+3KJp8X#y*%`2`2QpAtWCQA_!@W> zohyErhZ#F+Y@4~n>4b>AY{Rm|-ll-dQNQcowQ+5hHCAQdXW0_S!Lsbf)4z+4n*To& z%za4vKn8=YK%)J}jV7Nsnm*1}UuframsOy&Uh|Oe|M?rfv8Vem+L+z`99WkrcXvnN tqjcN*ya!$}nDqAS`}g8^_4@z(e+|xmEYk2k!@$76;OXk;vd$@?2>?b@dEo#6 diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index 0fabcc5ce8..de2fe755df 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -33,7 +33,7 @@ public class ContentLoader{ public ContentLoader(){ for(ContentType type : ContentType.all){ - contentMap[type.ordinal()] = new Seq<>(); + contentMap[type.ordinal()] = new Seq<>(type.contentClass == null ? Object.class : type.contentClass); contentNameMap[type.ordinal()] = new ObjectMap<>(); } } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index a1c5f7b766..21614e4e5b 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1006,15 +1006,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, if(proximity.size == 0) return false; + var allItems = content.items(); + int itemSize = allItems.size; + Item[] itemArray = allItems.items; + for(int i = 0; i < proximity.size; i++){ Building other = proximity.get((i + dump) % proximity.size); if(todump == null){ - for(int ii = 0; ii < content.items().size; ii++){ - Item item = content.item(ii); + for(int ii = 0; ii < itemSize; ii++){ + if(!items.has(ii)) continue; + Item item = itemArray[ii]; - if(other.team == team && items.has(item) && other.acceptItem(self(), item) && canDump(other, item)){ + if(other.acceptItem(self(), item) && canDump(other, item)){ other.handleItem(self(), item); items.remove(item, 1); incrementDump(proximity.size); @@ -1022,7 +1027,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } }else{ - if(other.team == team && other.acceptItem(self(), todump) && canDump(other, todump)){ + if(other.acceptItem(self(), todump) && canDump(other, todump)){ other.handleItem(self(), todump); items.remove(todump, 1); incrementDump(proximity.size); From 4a53a80b2118f61e19ff37818fb6e6e46bec62e2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 May 2023 11:12:32 -0400 Subject: [PATCH 0035/1150] Removed redundant team checks --- core/src/mindustry/entities/comp/BuildingComp.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 21614e4e5b..86e6e44544 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -775,7 +775,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(int i = 0; i < proximity.size; i++){ Building other = proximity.get((i + dump) % proximity.size); - if(other.team == team && other.acceptPayload(self(), todump)){ + if(other.acceptPayload(self(), todump)){ other.handlePayload(self(), todump); incrementDump(proximity.size); return true; @@ -828,7 +828,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, other = other.getLiquidDestination(self(), liquid); - if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){ + if(other != null && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){ float ofract = other.liquids.get(liquid) / other.block.liquidCapacity; float fract = liquids.get(liquid) / block.liquidCapacity; @@ -935,7 +935,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(int i = 0; i < proximity.size; i++){ incrementDump(proximity.size); Building other = proximity.get((i + dump) % proximity.size); - if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){ + if(other.acceptItem(self(), item) && canDump(other, item)){ other.handleItem(self(), item); return; } @@ -953,7 +953,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(int i = 0; i < proximity.size; i++){ incrementDump(proximity.size); Building other = proximity.get((i + dump) % proximity.size); - if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){ + if(other.acceptItem(self(), item) && canDump(other, item)){ other.handleItem(self(), item); return true; } @@ -1694,7 +1694,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(Point2 point : nearby){ Building other = world.build(tile.x + point.x, tile.y + point.y); - if(other == null || !(other.tile.interactable(team))) continue; + if(other == null || other.team != team) continue; other.proximity.addUnique(self()); From 1f85d0d24fee77321978797a0053a690583a35a2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 May 2023 12:29:53 -0400 Subject: [PATCH 0036/1150] Load logger in iOS --- core/src/mindustry/entities/comp/BuildingComp.java | 7 +------ gradle.properties | 2 +- ios/src/mindustry/ios/IOSLauncher.java | 2 ++ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 86e6e44544..ca4b0e13ce 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1000,12 +1000,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, * @param todump Item to dump. Can be null to dump anything. */ public boolean dump(Item todump){ - if(!block.hasItems || items.total() == 0 || (todump != null && !items.has(todump))) return false; + if(!block.hasItems || items.total() == 0 || proximity.size == 0 || (todump != null && !items.has(todump))) return false; int dump = this.cdump; - - if(proximity.size == 0) return false; - var allItems = content.items(); int itemSize = allItems.size; Item[] itemArray = allItems.items; @@ -1714,8 +1711,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } - //TODO probably should not have a shouldConsume() check? should you even *use* consValid? - public void consume(){ for(Consume cons : block.consumers){ cons.trigger(self()); diff --git a/gradle.properties b/gradle.properties index efd464dddc..663774945e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=9a41faa61b +archash=e20ff75344 diff --git a/ios/src/mindustry/ios/IOSLauncher.java b/ios/src/mindustry/ios/IOSLauncher.java index f6a2834b9f..45b542134a 100644 --- a/ios/src/mindustry/ios/IOSLauncher.java +++ b/ios/src/mindustry/ios/IOSLauncher.java @@ -40,6 +40,8 @@ public class IOSLauncher extends IOSApplication.Delegate{ Scl.setAddition(-0.5f); } + Vars.loadFileLogger(); + return new IOSApplication(new ClientLauncher(){ @Override From 7c52444e3c77b3d6484c644d2a6064eb8ee77266 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 19 May 2023 12:30:45 -0400 Subject: [PATCH 0037/1150] typo --- core/src/mindustry/content/Blocks.java | 2 +- .../world/blocks/defense/turrets/BaseTurret.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 6ad0a5b3dd..3bfcb95dfe 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -4663,7 +4663,7 @@ public class Blocks{ recoil = 0.5f; - fogRadiusMultiuplier = 0.4f; + fogRadiusMultiplier = 0.4f; coolantMultiplier = 6f; shootSound = Sounds.missileLaunch; diff --git a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java index 916be9f4dc..a959c00ba2 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java @@ -18,7 +18,7 @@ public class BaseTurret extends Block{ public float range = 80f; public float placeOverlapMargin = 8 * 7f; public float rotateSpeed = 5; - public float fogRadiusMultiuplier = 1f; + public float fogRadiusMultiplier = 1f; /** Effect displayed when coolant is used. */ public Effect coolEffect = Fx.fuelburn; @@ -57,7 +57,7 @@ public class BaseTurret extends Block{ } placeOverlapRange = Math.max(placeOverlapRange, range + placeOverlapMargin); - fogRadius = Math.max(Mathf.round(range / tilesize * fogRadiusMultiuplier), fogRadius); + fogRadius = Math.max(Mathf.round(range / tilesize * fogRadiusMultiplier), fogRadius); super.init(); } @@ -67,8 +67,8 @@ public class BaseTurret extends Block{ Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing); - if(fogRadiusMultiuplier < 0.99f && state.rules.fog){ - Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range * fogRadiusMultiuplier, Pal.lightishGray); + if(fogRadiusMultiplier < 0.99f && state.rules.fog){ + Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range * fogRadiusMultiplier, Pal.lightishGray); } } From b6d27c16bef1bf465392e2a5c2cf691fe56b6049 Mon Sep 17 00:00:00 2001 From: MEEPofFaith <54301439+MEEPofFaith@users.noreply.github.com> Date: Fri, 19 May 2023 18:02:54 -0700 Subject: [PATCH 0038/1150] Interval bullets for continuous bullets (#8628) --- .../entities/bullet/ContinuousBulletType.java | 2 ++ .../entities/bullet/PointLaserBulletType.java | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/entities/bullet/ContinuousBulletType.java b/core/src/mindustry/entities/bullet/ContinuousBulletType.java index df7b63c68d..0f95881285 100644 --- a/core/src/mindustry/entities/bullet/ContinuousBulletType.java +++ b/core/src/mindustry/entities/bullet/ContinuousBulletType.java @@ -74,6 +74,8 @@ public class ContinuousBulletType extends BulletType{ if(shake > 0){ Effect.shake(shake, shake, b); } + + updateBulletInterval(b); } public void applyDamage(Bullet b){ diff --git a/core/src/mindustry/entities/bullet/PointLaserBulletType.java b/core/src/mindustry/entities/bullet/PointLaserBulletType.java index e78b91d2d8..8e96579a5b 100644 --- a/core/src/mindustry/entities/bullet/PointLaserBulletType.java +++ b/core/src/mindustry/entities/bullet/PointLaserBulletType.java @@ -75,7 +75,9 @@ public class PointLaserBulletType extends BulletType{ @Override public void update(Bullet b){ - super.update(b); + updateTrail(b); + updateTrailEffects(b); + updateBulletInterval(b); if(b.timer.get(0, damageInterval)){ Damage.collidePoint(b, b.team, hitEffect, b.aimX, b.aimY); @@ -115,4 +117,13 @@ public class PointLaserBulletType extends BulletType{ b.trail.update(b.aimX, b.aimY, b.fslope() * (1f - (trailSinMag > 0 ? Mathf.absin(Time.time, trailSinScl, trailSinMag) : 0f))); } } + + public void updateBulletInterval(Bullet b){ + if(intervalBullet != null && b.time >= intervalDelay && b.timer.get(2, bulletInterval)){ + float ang = b.rotation(); + for(int i = 0; i < intervalBullets; i++){ + intervalBullet.create(b, b.aimX, b.aimY, ang + Mathf.range(intervalRandomSpread) + intervalAngle + ((i - (intervalBullets - 1f)/2f) * intervalSpread)); + } + } + } } From 047d39d129be43adfcbd9397c14639c0fb7d1761 Mon Sep 17 00:00:00 2001 From: MEEPofFaith <54301439+MEEPofFaith@users.noreply.github.com> Date: Fri, 19 May 2023 18:03:39 -0700 Subject: [PATCH 0039/1150] Chained PartProgress Operation in Json (#8627) * Op parsing method * Parse multi op * Big brain * Parse operation array * Error wording * Unnecessary code --- core/src/mindustry/mod/ContentParser.java | 60 ++++++++++++++++------- 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index d39825f455..8fd98c0c1e 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -190,32 +190,33 @@ public class ContentParser{ data.has("operation") ? data.get("operation") : data.has("op") ? data.get("op") : null; - //no operations I guess (why would you do this?) + //no singular operation, check for multi-operation if(opval == null){ + JsonValue opsVal = + data.has("operations") ? data.get("operations") : + data.has("ops") ? data.get("ops") : null; + + if(opsVal != null){ + if(!opsVal.isArray()) throw new RuntimeException("Chained PartProgress operations must be an array."); + int i = 0; + while(true){ + JsonValue val = opsVal.get(i); + if(val == null) break; + JsonValue op = val.has("operation") ? val.get("operation") : + val.has("op") ? val.get("op") : null; + + base = parseProgressOp(base, op.asString(), val); + i++; + } + } + return base; } //this is the name of the method to call String op = opval.asString(); - //I have to hard-code this, no easy way of getting parameter names, unfortunately - return switch(op){ - case "inv" -> base.inv(); - case "slope" -> base.slope(); - case "clamp" -> base.clamp(); - case "delay" -> base.delay(data.getFloat("amount")); - case "sustain" -> base.sustain(data.getFloat("offset", 0f), data.getFloat("grow", 0f), data.getFloat("sustain")); - case "shorten" -> base.shorten(data.getFloat("amount")); - case "compress" -> base.compress(data.getFloat("start"), data.getFloat("end")); - case "add" -> data.has("amount") ? base.add(data.getFloat("amount")) : base.add(parser.readValue(PartProgress.class, data.get("other"))); - case "blend" -> base.blend(parser.readValue(PartProgress.class, data.get("other")), data.getFloat("amount")); - case "mul" -> data.has("amount") ? base.mul(data.getFloat("amount")) : base.mul(parser.readValue(PartProgress.class, data.get("other"))); - case "min" -> base.min(parser.readValue(PartProgress.class, data.get("other"))); - case "sin" -> base.sin(data.has("offset") ? data.getFloat("offset") : 0f, data.getFloat("scl"), data.getFloat("mag")); - case "absin" -> base.absin(data.getFloat("scl"), data.getFloat("mag")); - case "curve" -> data.has("interp") ? base.curve(parser.readValue(Interp.class, data.get("interp"))) : base.curve(data.getFloat("offset"), data.getFloat("duration")); - default -> throw new RuntimeException("Unknown operation '" + op + "', check PartProgress class for a list of methods."); - }; + return parseProgressOp(base, op, data); }); put(PlanetGenerator.class, (type, data) -> { var result = new AsteroidGenerator(); //only one type for now @@ -875,6 +876,27 @@ public class ContentParser{ }; } + private PartProgress parseProgressOp(PartProgress base, String op, JsonValue data){ + //I have to hard-code this, no easy way of getting parameter names, unfortunately + return switch(op){ + case "inv" -> base.inv(); + case "slope" -> base.slope(); + case "clamp" -> base.clamp(); + case "delay" -> base.delay(data.getFloat("amount")); + case "sustain" -> base.sustain(data.getFloat("offset", 0f), data.getFloat("grow", 0f), data.getFloat("sustain")); + case "shorten" -> base.shorten(data.getFloat("amount")); + case "compress" -> base.compress(data.getFloat("start"), data.getFloat("end")); + case "add" -> data.has("amount") ? base.add(data.getFloat("amount")) : base.add(parser.readValue(PartProgress.class, data.get("other"))); + case "blend" -> base.blend(parser.readValue(PartProgress.class, data.get("other")), data.getFloat("amount")); + case "mul" -> data.has("amount") ? base.mul(data.getFloat("amount")) : base.mul(parser.readValue(PartProgress.class, data.get("other"))); + case "min" -> base.min(parser.readValue(PartProgress.class, data.get("other"))); + case "sin" -> base.sin(data.has("offset") ? data.getFloat("offset") : 0f, data.getFloat("scl"), data.getFloat("mag")); + case "absin" -> base.absin(data.getFloat("scl"), data.getFloat("mag")); + case "curve" -> data.has("interp") ? base.curve(parser.readValue(Interp.class, data.get("interp"))) : base.curve(data.getFloat("offset"), data.getFloat("duration")); + default -> throw new RuntimeException("Unknown operation '" + op + "', check PartProgress class for a list of methods."); + }; + } + T make(Class type){ try{ Constructor cons = type.getDeclaredConstructor(); From 94fe92d67d04ab6f41ebb922222d8d8d4f4fab38 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 20 May 2023 10:40:33 -0400 Subject: [PATCH 0040/1150] Pathfinder fixes / Hail resprite by Snake#2132 on Discord --- core/assets-raw/sprites/blocks/turrets/hail.png | Bin 349 -> 463 bytes core/src/mindustry/ai/ControlPathfinder.java | 5 ++++- core/src/mindustry/ai/Pathfinder.java | 7 +++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/assets-raw/sprites/blocks/turrets/hail.png b/core/assets-raw/sprites/blocks/turrets/hail.png index 10001df6ed56267146c29776bed5c20c99b34b3d..aa7a70ac87693fa0a58ec15fd51d2490d854c744 100644 GIT binary patch delta 437 zcmcc1be?&FN_~x|i(^Q|oVV9DW-&PmusyKdAn;C>>E&8J#e|6=FE3}W-MaCV@RB`I zxy5@|24^~ObWGjX@V;O|-s3qvZ{EH=dv1-PV}XO;_0s?T`Q;lH{@W=Pe!!LKQeF7t z&*z+fThv{bbxUWT@vy8mb>%cAmxhuJ{N|5k1A|zk4gTMG@%6TLy=33i=R5lz&uC3x zRG4F|&+?G9rNvu7?_!8w%Jo+fyHMY7ww&EdGGJ@@7BI5J%@qEevOavh6l^d1SR@H+gC7n zJ#6H#p5xSEmRS6K;l6yill7LDFFKUIyZuDQG9mw%tLBj>KQ~BD?-rGQ$S(14(j%ok z4HF7Do$hobTwL;eAFBY{dv7n6h;!jbbqnWmyXyb| delta 322 zcmX@le3xm0O1+Awi(^Pd+}kOJe1{BpT&w-d)?E%R5IAyW?nd_)H}+1@aC>H2ILXYF z=kF!?16%J43%%WCEPXj%f8XJ?-~VPZ)fCnqURtvz_gLYVs|6etotd+0X1hIbe8Ak# zp`&!c$La9<{^#O0Y6jZ*7sibw5B<%shRim^OLoctQ{)+nyf*L1rMvv*`AxtwdC2Ir+YdN+_S7)&C|I* zQB%QKT~AIokaNScBR2%CJGmN6pa1+M;NbD9TJwGA@teU8hkr;u-I=>lg|FRPr_*C+ e-Lv}7O#kkL)ve#l`-_2rfx*+&&t;ucLK6UEX_hVk diff --git a/core/src/mindustry/ai/ControlPathfinder.java b/core/src/mindustry/ai/ControlPathfinder.java index 7cbfc5eb19..c369f0d986 100644 --- a/core/src/mindustry/ai/ControlPathfinder.java +++ b/core/src/mindustry/ai/ControlPathfinder.java @@ -54,7 +54,10 @@ public class ControlPathfinder{ (PathTile.nearSolid(tile) || PathTile.solid(tile) ? 3 : 0), costNaval = (team, tile) -> - (PathTile.solid(tile) || !PathTile.liquid(tile) ? impassable : 1) + + //impassable same-team neutral block, or non-liquid + ((PathTile.solid(tile) && ((PathTile.team(tile) == team && !PathTile.teamPassable(tile)) || PathTile.team(tile) == 0)) || !PathTile.liquid(tile) ? impassable : 1) + + //impassable synthetic enemy block + ((PathTile.team(tile) != team && PathTile.team(tile) != 0) && PathTile.solid(tile) ? wallImpassableCap : 0) + (PathTile.nearGround(tile) || PathTile.nearSolid(tile) ? 6 : 0); public static boolean showDebug = false; diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index bffb9031da..ff8bb71534 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -58,7 +58,8 @@ public class Pathfinder implements Runnable{ //water (team, tile) -> - (PathTile.solid(tile) || !PathTile.liquid(tile) ? 6000 : 1) + + (!PathTile.liquid(tile) ? 6000 : 1) + + PathTile.health(tile) * 5 + (PathTile.nearGround(tile) || PathTile.nearSolid(tile) ? 14 : 0) + (PathTile.deep(tile) ? 0 : 1) + (PathTile.damages(tile) ? 35 : 0) @@ -527,7 +528,9 @@ public class Pathfinder implements Runnable{ } protected boolean passable(int pos){ - return cost.getCost(team.id, pathfinder.tiles[pos]) != impassable; + int amount = cost.getCost(team.id, pathfinder.tiles[pos]); + //edge case: naval reports costs of 6000+ for non-liquids, even though they are not technically passable + return amount != impassable && !(cost == costTypes.get(costNaval) && amount >= 6000); } /** Gets targets to pathfind towards. This must run on the main thread. */ From dc631129158178992b56ad5cd2df639b3370a5a7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 00:57:10 -0400 Subject: [PATCH 0041/1150] Always hide content when isHidden() == true --- core/src/mindustry/ui/dialogs/DatabaseDialog.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/mindustry/ui/dialogs/DatabaseDialog.java b/core/src/mindustry/ui/dialogs/DatabaseDialog.java index 0100836ce2..9ef878c280 100644 --- a/core/src/mindustry/ui/dialogs/DatabaseDialog.java +++ b/core/src/mindustry/ui/dialogs/DatabaseDialog.java @@ -52,10 +52,9 @@ public class DatabaseDialog extends BaseDialog{ for(int j = 0; j < allContent.length; j++){ ContentType type = ContentType.all[j]; - Seq array = allContent[j] - .select(c -> c instanceof UnlockableContent u && - (!u.isHidden() || u.techNode != null) && - (text.isEmpty() || u.localizedName.toLowerCase().contains(text.toLowerCase()))); + Seq array = allContent[j] + .select(c -> c instanceof UnlockableContent u && !u.isHidden() && + (text.isEmpty() || u.localizedName.toLowerCase().contains(text.toLowerCase()))).as(); if(array.size == 0) continue; all.add("@content." + type.name() + ".name").growX().left().color(Pal.accent); @@ -69,7 +68,7 @@ public class DatabaseDialog extends BaseDialog{ int count = 0; for(int i = 0; i < array.size; i++){ - UnlockableContent unlock = (UnlockableContent)array.get(i); + UnlockableContent unlock = array.get(i); Image image = unlocked(unlock) ? new Image(unlock.uiIcon).setScaling(Scaling.fit) : new Image(Icon.lock, Pal.gray); From 564e81e734c6a8d01d8a1b4b0430c18710d5fedd Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 03:59:08 -0400 Subject: [PATCH 0042/1150] Team#isEnemy is pointless --- core/assets-raw/sprites/units/dagger.png | Bin 531 -> 523 bytes core/src/mindustry/entities/Damage.java | 2 +- core/src/mindustry/game/Team.java | 2 ++ core/src/mindustry/input/MobileInput.java | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/assets-raw/sprites/units/dagger.png b/core/assets-raw/sprites/units/dagger.png index 2fa4b1464d70c76122a4425adfd7c8f86c8bfde9..784c3c49e1aaaafc781f125a730f82a14a9dd2c4 100644 GIT binary patch delta 484 zcmbQt(#Pp0i(^PewW>H*wXr)~P!NzPNWaj~_<>`p zI;VuiS>^^u1rI?RhGkrVfsI-d1b93T7My+i?#;P3_ku3}ymRl(xqtu9zR_z?;Am3d zIP}J7dHsn^K9cI5i+V1bl&bAHv%Ws&0 zoP5u2-)U(n-3HF6T+^u^UngX&Ie05`=fycss^od+zHRHeSiND60K)>d_*1hCbtXOH zE)kwnqy3dt^<61j$w!%-M=NLWuKmRp#=P<9?=u$*XFBliI5OS4XKTOyofJpz?uISjsqhc!PL}n;f%h31c2{VLd4({`G;Z{DS$|-Q;W>x>{}=UaFS9x& zvHNuCHFK#K-=8lR+!?lisocA&b3gBiE?DO{yF%;O$=*Z>3;WlT&Tr3E_F9n5=Wer% zcddh{uwqLWd%>0qTYN$U`5opk_I3VWc45MEOR03uJv-k=#(Vt@vx=!IdA94$u+JmV4B$iSC%Z!a@8*Z|l34SC!P4$8HgN`)!v0EY4rEgCAVpbP#4i(^Pe=@Fx3=JElCJ3AnI4R!f15h*2r1^Mj*1Gijdi zmv4r8`WaIg)H2rI47jzvd7&Y@_VTG!i%)#Dld?L^E4ui4f~6vZ1Mj{mmiIS!bj@Ed z`@xgw*tmdWd*3za&1?3xF->!}u4P``c;iuRQb~+j0JGl5r^?4p9T(5Do6Y%HsJLvN z(7io-9e%S{A9wtz_Gf0myLy)^^$Z8}=1Fm@u43#va6@g;`~zDI-#P66zi7+$a%(T? z>eHoWX0J2;f4NM4&M)w_F+Fy&w(gp#UEE;?u_Lh^LNB^Ff66oH zs0SQ%;g~abd*-HT7qNkP9Q{2+c?-2Vn$OSKlI z6h5~Ls%xu+%swjiyM53W&Qe-d;V8i3D9{r5Tzu7`l}E4s2s*>Sz`)??>gTe~DWM4f DRZ8L= diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 4c2106e70b..3b3571df09 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -600,7 +600,7 @@ public class Damage{ for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.build != null && (team == null ||team.isEnemy(tile.team())) && dx*dx + dy*dy <= trad*trad){ + if(tile != null && tile.build != null && (team == null || team != tile.team()) && dx*dx + dy*dy <= trad*trad){ tile.build.damage(team, damage); } } diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java index 9bd6ee89c2..d5673dfdd6 100644 --- a/core/src/mindustry/game/Team.java +++ b/core/src/mindustry/game/Team.java @@ -121,6 +121,8 @@ public class Team implements Comparable{ return isAI() && !rules().rtsAi; } + /** @deprecated There is absolutely no reason to use this. */ + @Deprecated public boolean isEnemy(Team other){ return this != other; } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index aec370fb38..126032c5e1 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -96,7 +96,7 @@ public class MobileInput extends InputHandler implements GestureListener{ }else{ Building tile = world.buildWorld(x, y); - if((tile != null && player.team().isEnemy(tile.team) && (tile.team != Team.derelict || state.rules.coreCapture)) || (tile != null && player.unit().type.canHeal && tile.team == player.team() && tile.damaged())){ + if((tile != null && player.team() != tile.team && (tile.team != Team.derelict || state.rules.coreCapture)) || (tile != null && player.unit().type.canHeal && tile.team == player.team() && tile.damaged())){ player.unit().mineTile = null; target = tile; } From dd3ce95264ec79a9179d850681894c9cf1f13b69 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 04:42:23 -0400 Subject: [PATCH 0043/1150] fixed iOS crash --- core/src/mindustry/Vars.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index a8e0d9290e..77b017755b 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -392,9 +392,11 @@ public class Vars implements Loadable{ } public static void loadFileLogger(){ - if(loadedFileLogger) return; + if(settings != null){ + settings.setAppName(appName); + } - settings.setAppName(appName); + if(loadedFileLogger) return; try{ Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false); From e714285671ca7e69ccad0f5df17d082c08e64df8 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 04:46:50 -0400 Subject: [PATCH 0044/1150] pain --- core/src/mindustry/Vars.java | 6 ++---- gradle.properties | 2 +- ios/src/mindustry/ios/IOSLauncher.java | 2 -- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 77b017755b..a8e0d9290e 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -392,12 +392,10 @@ public class Vars implements Loadable{ } public static void loadFileLogger(){ - if(settings != null){ - settings.setAppName(appName); - } - if(loadedFileLogger) return; + settings.setAppName(appName); + try{ Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false); LogHandler log = Log.logger; diff --git a/gradle.properties b/gradle.properties index 663774945e..d510ad50f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=e20ff75344 +archash=fa549dae62 diff --git a/ios/src/mindustry/ios/IOSLauncher.java b/ios/src/mindustry/ios/IOSLauncher.java index 45b542134a..f6a2834b9f 100644 --- a/ios/src/mindustry/ios/IOSLauncher.java +++ b/ios/src/mindustry/ios/IOSLauncher.java @@ -40,8 +40,6 @@ public class IOSLauncher extends IOSApplication.Delegate{ Scl.setAddition(-0.5f); } - Vars.loadFileLogger(); - return new IOSApplication(new ClientLauncher(){ @Override From 25b26be87b0c2f99b107cf7a8ef76c1d9a507d3d Mon Sep 17 00:00:00 2001 From: WayZer Date: Sun, 21 May 2023 22:59:09 +0800 Subject: [PATCH 0045/1150] fixup! Fix Turret bug when `cheat` (#8273) (#8629) --- core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index 7eb9891d8f..5e37d32a97 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -28,7 +28,7 @@ public class ItemTurret extends Turret{ /** Initializes accepted ammo map. Format: [item1, bullet1, item2, bullet2...] */ public void ammo(Object... objects){ - ammoTypes = ObjectMap.of(objects); + ammoTypes = OrderedMap.of(objects); } /** Limits bullet range to this turret's range value. */ From c335722de528b2b640b5401018755141b8a8f77a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 15:24:23 -0400 Subject: [PATCH 0046/1150] Interplanetary accelerator hidden in database --- core/src/mindustry/content/Blocks.java | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 3bfcb95dfe..c8735833b8 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -5819,7 +5819,7 @@ public class Blocks{ }}; interplanetaryAccelerator = new Accelerator("interplanetary-accelerator"){{ - requirements(Category.effect, BuildVisibility.campaignOnly, with(Items.copper, 16000, Items.silicon, 11000, Items.thorium, 13000, Items.titanium, 12000, Items.surgeAlloy, 6000, Items.phaseFabric, 5000)); + requirements(Category.effect, BuildVisibility.hidden, with(Items.copper, 16000, Items.silicon, 11000, Items.thorium, 13000, Items.titanium, 12000, Items.surgeAlloy, 6000, Items.phaseFabric, 5000)); researchCostMultiplier = 0.1f; size = 7; hasPower = true; diff --git a/gradle.properties b/gradle.properties index d510ad50f8..f144d02746 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=fa549dae62 +archash=ad3aecc4e4 From 7ab9c6fd9cc4418dd14065b3db5f0815a13e850f Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 15:47:56 -0400 Subject: [PATCH 0047/1150] Logic sprite upper limit now 64 --- tools/src/mindustry/tools/Generators.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index c15bf06a22..a48462ebbd 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -27,7 +27,7 @@ import static mindustry.Vars.*; import static mindustry.tools.ImagePacker.*; public class Generators{ - static final int logicIconSize = (int)iconMed, maxUiIcon = 128; + static final int logicIconSize = 64, maxUiIcon = 128; private static float fluid(boolean gas, double x, double y, float frame){ int keyframes = gas ? 4 : 3; @@ -44,9 +44,7 @@ public class Generators{ }else{ //liquids float min = 0.84f; double rx = (x + frame*32) % 32, ry = (y + frame*32) % 32; - //rx = x; ry = y; - //(float)liquidFrame(rx, ry, 0) - float interpolated = (float)liquidFrame(rx, ry, 2);//Mathf.lerp((float)liquidFrame(rx, ry, curFrame), (float)liquidFrame(rx, ry, nextFrame), progress); + float interpolated = (float)liquidFrame(rx, ry, 2); //only two colors here return min + (interpolated >= 0.3f ? 1f - min : 0f); } @@ -460,7 +458,7 @@ public class Generators{ base = container.outline(Pal.gray, 3); } - saveScaled(base, item.name + "-icon-logic", logicIconSize); + saveScaled(base, item.name + "-icon-logic", Math.min(logicIconSize, Math.min(base.width, base.height))); save(base, "../ui/" + item.getContentType().name() + "-" + item.name + "-ui"); } }); @@ -718,7 +716,7 @@ public class Generators{ Pixmap fit = new Pixmap(maxd, maxd); drawScaledFit(fit, image); - saveScaled(fit, type.name + "-icon-logic", logicIconSize); + saveScaled(fit, type.name + "-icon-logic", Math.min(logicIconSize, Math.min(fit.width, fit.height))); save(fit, "../ui/unit-" + type.name + "-ui"); }catch(IllegalArgumentException e){ Log.err("WARNING: Skipping unit @: @", type.name, e.getMessage()); From 520d122d8225adf9f20a58bcfdf495dc1cfc8981 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 20:42:34 -0400 Subject: [PATCH 0048/1150] arc --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f144d02746..9b6008c821 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=ad3aecc4e4 +archash=d8cd7a6003 From a78e7ca8c90691f5e7f9276fa31b272eca5339e7 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 21 May 2023 22:36:36 -0400 Subject: [PATCH 0049/1150] Possible crash fix --- .../mindustry/world/blocks/defense/OverdriveProjector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index b0aa7801c6..14b553c6b4 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -68,9 +68,9 @@ public class OverdriveProjector extends Block{ stats.add(Stat.range, range / tilesize, StatUnit.blocks); stats.add(Stat.productionTime, useTime / 60f, StatUnit.seconds); - if(hasBoost){ + if(hasBoost && findConsumer(f -> f instanceof ConsumeItems) instanceof ConsumeItems items){ stats.remove(Stat.booster); - stats.add(Stat.booster, StatValues.itemBoosters("+{0}%", stats.timePeriod, speedBoostPhase * 100f, phaseRangeBoost, ((ConsumeItems)findConsumer(f -> f instanceof ConsumeItems)).items, this::consumesItem)); + stats.add(Stat.booster, StatValues.itemBoosters("+{0}%", stats.timePeriod, speedBoostPhase * 100f, phaseRangeBoost, items.items, this::consumesItem)); } } From bf320a98b89bcb623550228edd7ae0b9e07ba752 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 22 May 2023 01:09:53 -0400 Subject: [PATCH 0050/1150] Faster connection lookup --- core/src/mindustry/input/InputHandler.java | 2 +- core/src/mindustry/net/ArcNetProvider.java | 24 +++++++--------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 8d5eab1901..91787021f1 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -168,7 +168,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ @Remote(called = Loc.server, unreliable = true) public static void transferItemTo(@Nullable Unit unit, Item item, int amount, float x, float y, Building build){ - if(build == null || build.items == null) return; + if(build == null || build.items == null || item == null) return; if(unit != null && unit.item() == item) unit.stack.amount = Math.max(unit.stack.amount - amount, 0); diff --git a/core/src/mindustry/net/ArcNetProvider.java b/core/src/mindustry/net/ArcNetProvider.java index ef0497dc0f..462415b20d 100644 --- a/core/src/mindustry/net/ArcNetProvider.java +++ b/core/src/mindustry/net/ArcNetProvider.java @@ -116,14 +116,14 @@ public class ArcNetProvider implements NetProvider{ Log.debug("&bReceived connection: @", c.addressTCP); + connection.setArbitraryData(kn); connections.add(kn); Core.app.post(() -> net.handleServerReceived(kn, c)); } @Override public void disconnected(Connection connection, DcReason reason){ - ArcConnection k = getByArcID(connection.getID()); - if(k == null) return; + if(!(connection.getArbitraryData() instanceof ArcConnection k)) return; Disconnect c = new Disconnect(); c.reason = reason.toString(); @@ -136,8 +136,8 @@ public class ArcNetProvider implements NetProvider{ @Override public void received(Connection connection, Object object){ - ArcConnection k = getByArcID(connection.getID()); - if(!(object instanceof Packet pack) || k == null) return; + if(!(connection.getArbitraryData() instanceof ArcConnection k)) return; + if(!(object instanceof Packet pack)) return; if(packetSpamLimit > 0 && !k.packetRate.allow(3000, packetSpamLimit)){ Log.warn("Blacklisting IP '@' as potential DOS attack - packet spam.", k.address); @@ -308,17 +308,6 @@ public class ArcNetProvider implements NetProvider{ mainExecutor.submit(server::stop); } - ArcConnection getByArcID(int id){ - for(int i = 0; i < connections.size(); i++){ - ArcConnection con = connections.get(i); - if(con.connection != null && con.connection.getID() == id){ - return con; - } - } - - return null; - } - class ArcConnection extends NetConnection{ public final Connection connection; @@ -370,8 +359,9 @@ public class ArcNetProvider implements NetProvider{ Log.info("Error sending packet. Disconnecting invalid client!"); connection.close(DcReason.error); - ArcConnection k = getByArcID(connection.getID()); - if(k != null) connections.remove(k); + if(connection.getArbitraryData() instanceof ArcConnection k){ + connections.remove(k); + } } } From c4b1df9526955bfb7faac3e5e19394b0e99b17ae Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 22 May 2023 14:28:10 -0400 Subject: [PATCH 0051/1150] Closes Anuken/Mindustry-Suggestions/issues/4433 --- .../sprites/blocks/turrets/hail-heat.png | Bin 226 -> 279 bytes core/assets-raw/sprites/blocks/turrets/hail.png | Bin 463 -> 383 bytes .../world/blocks/payloads/PayloadConveyor.java | 2 ++ 3 files changed, 2 insertions(+) diff --git a/core/assets-raw/sprites/blocks/turrets/hail-heat.png b/core/assets-raw/sprites/blocks/turrets/hail-heat.png index ef3805e18e123a952c383abfedf98d90e8034751..84f197b52b582f0efb167530cba4bcd8ec8f1165 100644 GIT binary patch delta 238 zcmaFFIGt&NVf{r<7srr@*0-0fy;vLt8Xm59VR7YUQ9gL!aIQuLgEGHDg$*$`#u<~P$?r2eJ1rQ7sq7WB@1%C$|~ z?y&MZ@1oqQ|4nE19OCTT5dUzxRGqNk^2JMc!`leoQiTc4Ld@JHgBnb)rUyh^_hvwZrXD|D1;{-JDDzt)Gbn`+atSEkuFwtkqS z)pbP0l+XkKf8k5V diff --git a/core/assets-raw/sprites/blocks/turrets/hail.png b/core/assets-raw/sprites/blocks/turrets/hail.png index aa7a70ac87693fa0a58ec15fd51d2490d854c744..604fb5d5de6733326a259c4569e1691abbb9d396 100644 GIT binary patch delta 357 zcmX@l{GVxpay6YGBs@F zb5g_9=O36D8JT+hrl+ruPml1vhW7_z*n@+)_uh-Y@njj>slW2<-@mtHJif2|p;Dt$ zdF8dmA0JfLN}PRIGuP@-+MP{Ds@4lKc-;|i;w{+q~Q>X|sD zhN1LTpup{;&(rtJdw-Vcg?pTy`3?a;2Kho3CNm|imHav^3y!R|a+2iZ3S^p*Z*(nU zsq>CIey&p`L&F#vS19MPIw-vA;C^T*I@>R^uDHagZFj?}p7Rm++@$kU(r;B4q#hka-HfAw73a~w}-5~Hzmg(hMKE;HIAulgyuid)wl<<;0 zQMtu?R|aP~aCA)F*YLhzLf+#!J#XH=J$r7Ap<{uA-}Tb}{`ut_7XI5Q6@I{#=~7+z z*U-Lfcm` zcs*?7u%6@8VU}3@ec`@*x%!iqmoGY$zPtTI#xf!Qn5*WICqFkxPVW|#e#kEIaMB~C zJq;5IIGyfvBwSqbd>^X-+k0;>mWXrVM|BJ5a^zS9xv(0@q)+^;5tXV`bC<9CD*KX- zXMNk Date: Mon, 22 May 2023 21:42:46 -0400 Subject: [PATCH 0052/1150] Fixed mod startup crash --- core/src/mindustry/core/ContentLoader.java | 2 +- core/src/mindustry/entities/comp/BuildingComp.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index de2fe755df..0fabcc5ce8 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -33,7 +33,7 @@ public class ContentLoader{ public ContentLoader(){ for(ContentType type : ContentType.all){ - contentMap[type.ordinal()] = new Seq<>(type.contentClass == null ? Object.class : type.contentClass); + contentMap[type.ordinal()] = new Seq<>(); contentNameMap[type.ordinal()] = new ObjectMap<>(); } } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index ca4b0e13ce..3f4157abcf 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1005,7 +1005,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, int dump = this.cdump; var allItems = content.items(); int itemSize = allItems.size; - Item[] itemArray = allItems.items; + Object[] itemArray = allItems.items; for(int i = 0; i < proximity.size; i++){ Building other = proximity.get((i + dump) % proximity.size); @@ -1014,7 +1014,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, for(int ii = 0; ii < itemSize; ii++){ if(!items.has(ii)) continue; - Item item = itemArray[ii]; + Item item = (Item)itemArray[ii]; if(other.acceptItem(self(), item) && canDump(other, item)){ other.handleItem(self(), item); From 3813d66f30f49a92d0b1781756a07128e7dffde0 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 22 May 2023 21:51:06 -0400 Subject: [PATCH 0053/1150] New scorch sprite by Fox1va_ --- .../sprites/blocks/turrets/scorch-heat.png | Bin 329 -> 439 bytes .../sprites/blocks/turrets/scorch.png | Bin 307 -> 521 bytes core/src/mindustry/content/Blocks.java | 1 + 3 files changed, 1 insertion(+) diff --git a/core/assets-raw/sprites/blocks/turrets/scorch-heat.png b/core/assets-raw/sprites/blocks/turrets/scorch-heat.png index ede4fe6657753aced3ca28552dcb14e874941a1e..82ac4b138f8c21909c6104fbb26f4b63df91bd2c 100644 GIT binary patch delta 400 zcmX@fw4Hf^VSS;ei(^Pc>)WY@L5B?lT<06bD7ellnX+;xWB3Chna+7u;SX2>mVDyr zwKmtRX<0haNIG)&G!`C_pS?>Xe*gdMRrX++eb|P)j*c0wiXyM8vS#(_9G)lD;H&tj z_N)f~8qV!|%x^YbxA?Q7bp@~gJgsC-hMof#m@W#*?RDpWV6ISqrl7%kv4*aVMsxeQ z1Y?>dok91oAO{$O({-og36 zVTwc1%iQ9_3;&2sS@ONWAbjfK*h+@@axT<@F`!*_bl5Yx;y9Inz#nZ8)*lN z`vcF5{aG=KU$LRX=Ga5Cxby~rL(!|l!`ZzYZ6BKd<*sGCx^tfPgXyXp85kHi89ZJ6 KT-G@yGywqG5wofQ delta 289 zcmdnae3EH`VLh{_i(^Pc>)R=(1rHhUxPY)RtW&__DPh(HF z{a;&z?*$8;z9k-MWbozvB%K9YzeVivW4L#6T4+zlo!yLL&n~B(Y&LkT)Zu*a&ZVV4 zbkC-S9njdl+*~j@?2$xHNG-#hIa^Oed~aLDaHcz*|A_It!z+~P8>Zf1_WWO=UCz~W z%u+g$D@k(wzk9P;p2=-sP&zwt<0)BZ{fGB9=J01Et(W3S5pQ63l3uOl{=v&Z>2rpD zLlvvZ#i>31N97#Zg3Q8}CUY>X-8y^o5`|?OJ8a4sJrv#?VJ+rrXk0Oi`Ht%sVP1w+ x>?kVe7FDr diff --git a/core/assets-raw/sprites/blocks/turrets/scorch.png b/core/assets-raw/sprites/blocks/turrets/scorch.png index abbd3b5188699756d66828db61073d7f6b40d1de..ad77c9fedaf48b558d1b4c01eb3ab6456d2f018c 100644 GIT binary patch delta 496 zcmdnY)X6eIxt?*Gr;B4q1n1kS_Wn$c0!R5DZ@+j-B1hy3Q}R;Iuz7puHcsk0C*+i_ ze=SN<_fK%v!*C~gi`h5t&P@JhbEQf1U0M0Fv%l}Q#cs-xtlz_IdiMXK%kw|n`ImUv zx1ax;i|q9eRUD>gyI!AS+anlVcKCLCIzL~hk<<&NhRR+Ar-F`pqgj#D84ld)IMSf8 zSkd<0MZOPD@_WuQ_z=;V4>wJB?cX#BmQSD zvO5Y)vizjPAQU=dF@KXnnsNRAl}tZUyJxF1=gj#UGV52S``JuR!GwZ&{)ZkPllBmB zefHk`@S9wlj(-O(7&A3k&Wu!iHZ$0s^N{uTJ9AtryyJa-9{VQ6yV!hROxM~yuWJ^| zPGE7hR=k?*Ys~-JmqB2uL&VvO*Lf0JJq-QX8Wz0rxYfAo?8W!>j3w)jy{pi9l$m{T zvb^J&#j+Yr4(oPqUgvaepOQ%fXX})1h5#MM52l<<&s^OmSzcY8f2Zfx+ZA0AOyTQG z{%)G|)ZjNultbr|O(hM*3=9l>sS%!OzP=1v3=9k$3=nWBcru9L>FVdQ&MBb@0Gt@( A9smFU delta 281 zcmeBV*~~OSxt`&dr;B4qMcmt|d;1O<2(W#g_hm|l`vcxfN?9*fu5?)WqH_KLFPA9) zH?jXiIQqYY_SqDdTS~O~9e-G1b-rr%--CC)mhm6^-L>FO_kul|O+k9$aiWfqSvx;1 z>NtP&CZmzpoWSkN*lU~R1g(xzI31KLHgb`W(uEb1H=_38=neh{G@Z#m+{vf?hEIG;zSP=D~cX? q-m;8gUZ%u>V&6cA=kF_+W7>t@UHh<6+LVETfx*+&&t;ucLK6U_+J>S4 diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index c8735833b8..761dbee4f1 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -3184,6 +3184,7 @@ public class Blocks{ reload = 6f; coolantMultiplier = 1.5f; range = 60f; + shootY = 3; shootCone = 50f; targetAir = false; ammoUseEffect = Fx.none; From c774968c2de27c57cb85bb5dca65edcea12185cd Mon Sep 17 00:00:00 2001 From: Alexander397172YT <76264974+Alexander397172YT@users.noreply.github.com> Date: Tue, 23 May 2023 17:16:53 +0400 Subject: [PATCH 0054/1150] new server CreateDustry v7 (#8631) --- servers_v7.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/servers_v7.json b/servers_v7.json index f440df2684..7fd9baa2ac 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -176,4 +176,8 @@ "name": "Realm of Serene Lime", "address": ["43.248.185.167:8517","n2.akiracloud.net:10686"] } + { + "name": "CreateDustry", + "address": ["116.202.83.83:25689"] + } ] From 18cfffd105142a1a5da576107c4b57f7fd4a8124 Mon Sep 17 00:00:00 2001 From: frieda666 <103875616+frieda666@users.noreply.github.com> Date: Tue, 23 May 2023 12:44:25 -0700 Subject: [PATCH 0055/1150] Add test case for achievement (#8633) --- tests/src/test/java/ApplicationTests.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 1885a31d94..b875d39179 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -15,6 +15,7 @@ import mindustry.ctype.*; import mindustry.entities.units.*; import mindustry.game.*; import mindustry.gen.*; +import mindustry.graphics.g3d.*; import mindustry.io.*; import mindustry.io.SaveIO.*; import mindustry.maps.*; @@ -22,6 +23,7 @@ import mindustry.mod.*; import mindustry.mod.Mods.*; import mindustry.net.*; import mindustry.net.Packets.*; +import mindustry.service.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.payloads.*; @@ -981,4 +983,16 @@ public class ApplicationTests{ tile.build.handleStack(item, 1, unit); assertEquals(capacity, tile.build.items.get(item)); } + + @Test + void achievementTest(){ + clientLoaded = true; + state.rules.sector = new Sector(null, PlanetGrid.Ptile.empty); + player = Player.create(); + service.init(); + + assertFalse(Achievement.buildT5.isAchieved()); + Events.fire(new EventType.UnitCreateEvent(UnitTypes.eclipse.create(Team.sharded), null)); + assertTrue(Achievement.buildT5.isAchieved()); + } } From ad4ce35a42281f375c0f107cbf77b283db43a4e2 Mon Sep 17 00:00:00 2001 From: The Serjio <84933638+TheSerjio@users.noreply.github.com> Date: Wed, 24 May 2023 16:22:05 +0300 Subject: [PATCH 0056/1150] Update bundle_ru.properties (#8638) --- core/assets/bundles/bundle_ru.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 5228277366..2d0ef86218 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -458,7 +458,7 @@ waves.sort.reverse = Обратная сортировка waves.sort.begin = Начало waves.sort.health = Здоровье waves.sort.type = Тип -waves.search = Search waves... +waves.search = Поиск волн... waves.filter.unit = Unit Filter waves.units.hide = Скрыть все waves.units.show = Показать все @@ -1200,8 +1200,8 @@ rules.wavetimer = Интервал волн rules.wavesending = Отправка волн rules.waves = Волны rules.attack = Режим атаки -rules.buildai = Base Builder AI -rules.buildaitier = Builder AI Tier +rules.buildai = ИИ строит базы +rules.buildaitier = Уровень баз ИИ rules.rtsai = ИИ в реальном времени rules.rtsminsquadsize = Минимальный размер отряда rules.rtsmaxsquadsize = Максимальный размер отряда @@ -1230,7 +1230,7 @@ rules.buildcostmultiplier = Множитель затрат на строите rules.buildspeedmultiplier = Множитель скорости строительства rules.deconstructrefundmultiplier = Множитель возврата ресурсов при разборке rules.waitForWaveToEnd = Волны ожидают врагов -rules.wavelimit = Map Ends After Wave +rules.wavelimit = Игра заканчивается после волны rules.dropzoneradius = Радиус зоны высадки врагов:[lightgray] (блоков) rules.unitammo = Боев. ед. требуют боеприпасы rules.enemyteam = Команда Врагов From 9869922710ebea916bd217a97e715aeefb52632b Mon Sep 17 00:00:00 2001 From: YozoZChomutova <55143954+yozozchomutova@users.noreply.github.com> Date: Wed, 24 May 2023 15:22:34 +0200 Subject: [PATCH 0057/1150] Update bundle_cs.properties (#8639) * Updated bundle_cs.properties All unstraslated words I've found were translated. Spacing between lines were synchronized with bundle.properties. +Added self to contributors file. * Updated bundle_cs.properties Replaced with shorters words, fixing issue with multilined text in buttons. * Translated several keys to Czech. --- core/assets/bundles/bundle_cs.properties | 335 +++++++++++------------ 1 file changed, 167 insertions(+), 168 deletions(-) diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index 6dae5e9ad0..af485c11a4 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -12,9 +12,9 @@ link.itch.io.description = Stránka na itch.io s odkazy na stažení hry link.google-play.description = Obchod Google Play link.f-droid.description = F-Droid link.wiki.description = Oficiální Wiki Mindustry -link.suggestions.description = Suggest new features +link.suggestions.description = Doporučit nové funkce link.bug.description = Našel jsi nějaký? Nahlaš ho zde -linkopen = This server has sent you a link. Are you sure you want to open it?\n\n[sky]{0} +linkopen = Tento server vám poslal odkaz. Jste si jist s jeho otevřením?\n\n[sky]{0} linkfail = Nepodařilo se otevřít odkaz!\nAdresa URL byla zkopírována do schránky. screenshot = Snímek obrazovky uložen {0} screenshot.invalid = Mapa je moc velká, nemusí být dost paměti pro získání snímku obrazovky. @@ -45,12 +45,12 @@ mods.browser = Prohlížeč modifikací mods.browser.selected = Vybraný mod mods.browser.add = Stáhnout mods.browser.reinstall = Reinstalovat -mods.browser.view-releases = View Releases -mods.browser.noreleases = [scarlet]No Releases Found\n[accent]Couldn't find any releases for this mod. Check if the mod's repository has any releases published. -mods.browser.latest = -mods.browser.releases = Releases +mods.browser.view-releases = Zobrazit Vydání +mods.browser.noreleases = [scarlet]Žádné Vydání Nenalezeny\n[accent]Nenalezene žádné vydání pro tento mod. Check if the mod's repository has any releases published. Zjistěte, jestli repozitář modu má již veřejně vydán. +mods.browser.latest = +mods.browser.releases = Vydání mods.github.open = Úložiště -mods.github.open-release = Release Page +mods.github.open-release = Stranka Vydání mods.browser.sortdate = Řadit podle nedavných mods.browser.sortstars = Řadit podle hvězd @@ -82,13 +82,13 @@ schematic.tagdelconfirm = Smazat tuto značku? schematic.tagexists = Tato značka již existuje. stats = Statistiky -stats.wave = Waves Defeated -stats.unitsCreated = Units Created -stats.enemiesDestroyed = Enemies Destroyed -stats.built = Buildings Built -stats.destroyed = Buildings Destroyed -stats.deconstructed = Buildings Deconstructed -stats.playtime = Time Played +stats.wave = Poraženo Vln +stats.unitsCreated = Jednotek Vytvořeno +stats.enemiesDestroyed = Nepřátel Zničeno +stats.built = Budov Postaveno +stats.destroyed = Budov Zničeno +stats.deconstructed = Budov Zdekonstruovano +stats.playtime = Doba Hraní globalitems = [accent]Celkové položky[] map.delete = Jsi si jistý, že chceš smazat mapu "[accent]{0}[]"? @@ -144,13 +144,13 @@ mod.multiplayer.compatible = [gray]Hra více hráčů komapitibilní mod.disable = Zakázat mod.content = Obsah: mod.delete.error = Nebylo možnost smazat modifikaci. Soubor může být používán. -mod.incompatiblegame = [red]Outdated Game -mod.incompatiblemod = [red]Incompatible -mod.blacklisted = [red]Unsupported -mod.unmetdependencies = [red]Unmet Dependencies +mod.incompatiblegame = [red]Zastaralá Hra +mod.incompatiblemod = [red]Nekompatibilní +mod.blacklisted = [red]Nepodporováno +mod.unmetdependencies = [red]Nesplněné Dependencies mod.erroredcontent = [scarlet]V obsahu jsou chyby[] -mod.circulardependencies = [red]Circular Dependencies -mod.incompletedependencies = [red]Incomplete Dependencies +mod.circulardependencies = [red]Kruhové Dependencies +mod.incompletedependencies = [red]Nedokončené Dependencies mod.requiresversion.details = Requires game version: [accent]{0}[]\nYour game is outdated. This mod requires a newer version of the game (possibly a beta/alpha release) to function. mod.outdatedv7.details = This mod is incompatible with the latest version of the game. The author must update it, and add [accent]minGameVersion: 136[] to its [accent]mod.json[] file. mod.blacklisted.details = This mod has been manually blacklisted for causing crashes or other issues with this version of the game. Do not use it. @@ -187,13 +187,13 @@ filename = Název souboru: unlocked = Byl odemmknut nový blok! available = Je zpřístupněn nový výzkum! unlock.incampaign = < Odemkni v kampani pro více detailů > -campaign.select = Select Starting Campaign +campaign.select = Vybrat Začínající Kampaň campaign.none = [lightgray]Select a planet to start on.\nThis can be switched at any time. campaign.erekir = Newer, more polished content. Mostly linear campaign progression.\n\nHigher quality maps and overall experience. campaign.serpulo = Older content; the classic experience. More open-ended.\n\nPotentially unbalanced maps and campaign mechanics. Less polished. completed = [accent]Dokončeno[] techtree = Technologie -techtree.select = Tech Tree Selection +techtree.select = Výběr Výzkumného Stromu techtree.serpulo = Serpulo techtree.erekir = Erekir research.load = Načíst @@ -392,15 +392,15 @@ map.publish.confirm = Jsi si jistý, že chceš publikovat tuto mapu?\n\n[lightg workshop.menu = Vyber si, co bys chtěl dělat s touto položkou. workshop.info = Informace o položce changelog = Seznam změn (volitelně): -updatedesc = Overwrite Title & Description +updatedesc = Přepsat Nadpis a Popis eula = Smluvní podmínky platformy Steam missing = Tato položka byla smazána nebo přesunuta.\n[lightgray]Položka bude automaticky odebrána ze seznamu Workshopu na Steamu. publishing = [accent]Publikuji... publish.confirm = Opravdu chceš toto publikovat?\n\n[lightgray]Ujisti se nejprve, že souhlasíš se smluvními podmínkami Workshopu na Steamu (EULA), jinak se Tvoje položky nezobrazí.[] publish.error = Chyba při publikování položky: {0} steam.error = Nepodařilo se inicializovat služby platformy Steam. Chyba: {0} -editor.planet = Planet: -editor.sector = Sector: +editor.planet = Planeta: +editor.sector = Sektor: editor.seed = Seed: editor.cliffs = Zdi Na Útesy @@ -415,7 +415,7 @@ editor.nodescription = Než může být mapa publikována, musí mít popis dlou editor.waves = Vln: editor.rules = Pravidla: editor.generation = Generace: -editor.objectives = Objectives +editor.objectives = Úkoly: editor.ingame = Upravit ve hře editor.playtest = Playtest editor.publish.workshop = Publikovat do Workshopu na Steamu @@ -435,19 +435,19 @@ waves.title = Vlny waves.remove = Odebrat waves.every = každých waves.waves = vln(y) -waves.health = health: {0}% +waves.health = životy: {0}% waves.perspawn = za zrození waves.shields = štítů/vlnu waves.to = do -waves.spawn = spawn: +waves.spawn = zrození: waves.spawn.all = -waves.spawn.select = Spawn Select -waves.spawn.none = [scarlet]no spawns found in map +waves.spawn.select = Výběr Zrození +waves.spawn.none = [scarlet]žádné zrození nebyly nalezeny na mapě waves.max = max jednotek waves.guardian = Strážce waves.preview = Náhled waves.edit = Upravit.... -waves.random = Random +waves.random = Náhodně waves.copy = Uložit do schránky waves.load = Načíst ze schránky waves.invalid = Neplatné vlny ve schránce. @@ -458,8 +458,8 @@ waves.sort.reverse = Obrátit řazení waves.sort.begin = Začít waves.sort.health = Životy waves.sort.type = Typ -waves.search = Search waves... -waves.filter.unit = Unit Filter +waves.search = Hledat vlny... +waves.filter.unit = Filtr Jednotky waves.units.hide = Schovat vše waves.units.show = Zobrazit vše @@ -485,12 +485,12 @@ editor.errorheader = Tento soubor mapy je buď neplatný nebo poškozen. editor.errorname = Mapa nemá definované jméno. Nesnažíš se náhodou nahrát soubor s uložením hry? editor.update = Aktualizovat editor.randomize = Náhodně vygenerovat -editor.moveup = Move Up -editor.movedown = Move Down -editor.copy = Copy +editor.moveup = Pohyb Nahoru +editor.movedown = Pohyb Dolu +editor.copy = Kopírovat editor.apply = Aplikovat editor.generate = Generovat -editor.sectorgenerate = Sector Generate +editor.sectorgenerate = Generovat Sektor editor.resize = Změnit velikost editor.loadmap = Načíst mapu editor.savemap = Uložit mapu @@ -498,7 +498,7 @@ editor.saved = Uloženo! editor.save.noname = Tvoje mapa nemá jméno! Jméno nastavíš v položce nabídky "Informace o mapě". editor.save.overwrite = Tvoje mapa přepisuje vestavěnou mapu! Nastav jí radši jiné jméno v položce nabídky "Informace o mapě". editor.import.exists = [scarlet]Není možno importovat:[] existuje vestavěná mapa se stejným jménem '{0}'! -editor.import = Import... +editor.import = Importovat... editor.importmap = Importovat mapu editor.importmap.description = Importovat již existující mapu editor.importfile = Importovat soubor @@ -534,11 +534,10 @@ toolmode.fillteams = Doplnit týmy toolmode.fillteams.description = Doplní týmy místo bloků. toolmode.drawteams = Kreslit týmy toolmode.drawteams.description = Kreslí týmy místo bloků. -toolmode.underliquid = Under Liquids -toolmode.underliquid.description = Draw floors under liquid tiles. +toolmode.underliquid = Pod Kapalinami +toolmode.underliquid.description = Kreslí podlahy pod kostkama kapalin. filters.empty = [lightgray]Nejsou zadány žádné filtry, přidej filtr tlačítkem níže.[] - filter.distort = Zkreslení filter.noise = Zašumění filter.enemyspawn = Výběr nepřátelské líhně @@ -564,9 +563,9 @@ filter.option.circle-scale = Poloměr kružnice filter.option.octaves = Octávy filter.option.falloff = Pokles filter.option.angle = Úhel -filter.option.tilt = Tilt +filter.option.tilt = Naklonit filter.option.rotate = Otočit -filter.option.amount = Amount +filter.option.amount = Počet filter.option.block = Blok filter.option.floor = Povrch filter.option.flooronto = Cílový povrch @@ -607,31 +606,31 @@ requirement.core = Znič nepřátelské jádro na mapě {0} requirement.research = Vynalezni {0} requirement.produce = Vyrob {0} requirement.capture = Polap {0} -requirement.onplanet = Control Sector On {0} -requirement.onsector = Land On Sector: {0} +requirement.onplanet = Kontrolovat Sektor na {0} +requirement.onsector = Přistát na Sektor: {0} launch.text = Vyslat research.multiplayer = Jen hostitel hry může vynalézat nové technologie. map.multiplayer = Jen hostitel může prohlížet sektory. uncover = Odkrýt mapu configure = Přizpůsobit vybavení -objective.research.name = Research -objective.produce.name = Obtain -objective.item.name = Obtain Item -objective.coreitem.name = Core Item -objective.buildcount.name = Build Count -objective.unitcount.name = Unit Count -objective.destroyunits.name = Destroy Units -objective.timer.name = Timer -objective.destroyblock.name = Destroy Block -objective.destroyblocks.name = Destroy Blocks -objective.destroycore.name = Destroy Core -objective.commandmode.name = Command Mode -objective.flag.name = Flag +objective.research.name = Výzkum +objective.produce.name = Získat +objective.item.name = Získat Věc +objective.coreitem.name = Jádrova Věc +objective.buildcount.name = Počet Budov +objective.unitcount.name = Počet Jednotek +objective.destroyunits.name = Znič Jednotky +objective.timer.name = Časovač +objective.destroyblock.name = Zničit Kostku +objective.destroyblocks.name = Zničit Kostky +objective.destroycore.name = Zničit Jádro +objective.commandmode.name = Příkazovy Režim +objective.flag.name = Vlajka marker.shapetext.name = Shape Text -marker.minimap.name = Minimap -marker.shape.name = Shape +marker.minimap.name = Minimapa +marker.shape.name = Tvar marker.text.name = Text -marker.background = Background +marker.background = Pozadí marker.outline = Outline objective.research = [accent]Research:\n[]{0}[lightgray]{1} objective.produce = [accent]Obtain:\n[]{0}[lightgray]{1} @@ -654,9 +653,9 @@ loadout = Načtení resources = Zdroje resources.max = Max bannedblocks = Zakázané bloky -objectives = Objectives +objectives = Úkoly bannedunits = Zakázané jednotky -rules.hidebannedblocks = Hide Banned Blocks +rules.hidebannedblocks = Schovat Zakázané Kostky bannedunits.whitelist = Banned Units As Whitelist bannedblocks.whitelist = Banned Blocks As Whitelist addall = Přidat vše @@ -708,7 +707,7 @@ sectors.underattack = [scarlet]Pod palbou! [accent]{0}% poškozeno sectors.underattack.nodamage = [scarlet]Uncaptured sectors.survives = [accent]Přežívá již {0} vln sectors.go = Jdi -sector.abandon = Abandon +sector.abandon = Opustit sector.abandon.confirm = This sector's core(s) will self-destruct.\nContinue? sector.curcapture = Sektor polapen sector.curlost = Sektor ztracen @@ -718,9 +717,9 @@ sector.lost = Sektor [accent]{0}[white] ztracen! :( #note: chybějící mezera v řádce níže je záměrná :) sector.captured = Sektor [accent]{0}[white]polapen! :) sector.changeicon = Změnit Ikonu -sector.noswitch.title = Unable to Switch Sectors +sector.noswitch.title = Nelze Vyměnit Sektor sector.noswitch = Sektory nelze přepnut, pokud je stávající sektor pod útokem.\n\nSektor: [accent]{0}[] na [accent]{1}[] -sector.view = View Sector +sector.view = Prohlédnout Sektor threat.low = Nízké threat.medium = Střední @@ -728,7 +727,7 @@ threat.high = Velké threat.extreme = Extrémní threat.eradication = Vyhlazující -planets = Planets +planets = Planety planet.serpulo.name = Serpulo planet.erekir.name = Erekir @@ -889,8 +888,8 @@ stat.repairtime = Čas do úplné opravy stat.repairspeed = Rychlost Opravy stat.weapons = Zbraně stat.bullet = Střela -stat.moduletier = Module Tier -stat.unittype = Unit Type +stat.moduletier = Úroveň Modulu +stat.unittype = Typ Jednotky stat.speedincrease = Zvýšení rychlosti stat.range = Dosah stat.drilltier = Lze těžit @@ -933,7 +932,7 @@ stat.speedmultiplier = Násobič Rychlostí stat.reloadmultiplier = Násobič Přebití stat.buildspeedmultiplier = Nasobič Rychlostí Stavby stat.reactive = Reaguje -stat.immunities = Immunities +stat.immunities = Imunity stat.healing = Léčí se ability.forcefield = Silové pole @@ -942,10 +941,10 @@ ability.statusfield = Stav pole ability.unitspawn = {0} továrna ability.shieldregenfield = Silově opravné pole ability.movelightning = Pohybující se blesk -ability.shieldarc = Shield Arc +ability.shieldarc = Štítovy Oblouk ability.suppressionfield = Regen Suppression Field ability.energyfield = Energetické pole: [accent]{0}[] poškození ~ [accent]{1}[] dlaždic / [accent]{2}[] cílu -bar.onlycoredeposit = Only Core Depositing Allowed +bar.onlycoredeposit = Pouze Ukládání do Jádra je povoleno bar.drilltierreq = Je vyžadován lepší vrt bar.noresources = Chybějí zdroje @@ -966,12 +965,12 @@ bar.capacity = Kapacita: {0} bar.unitcap = {0} {1}/{2} bar.liquid = Chlazení bar.heat = Teplo -bar.instability = Instability -bar.heatamount = Heat: {0} -bar.heatpercent = Heat: {0} ({1}%) +bar.instability = Nestabilita +bar.heatamount = Teplo: {0} +bar.heatpercent = Teplo: {0} ({1}%) bar.power = Energie bar.progress = Konstrukce v průběhu -bar.loadprogress = Progress +bar.loadprogress = Pokrok bar.launchcooldown = Launch Cooldown bar.input = Vstup bar.output = Výstup @@ -984,7 +983,7 @@ bullet.splashdamage = [stat]{0}[lightgray] plošného poškození ~[stat] {1}[li bullet.incendiary = [stat]zápalný bullet.homing = [stat]samonaváděcí bullet.armorpierce = [stat]armor piercing -bullet.suppression = [stat]{0} sec[lightgray] repair suppression ~ [stat]{1}[lightgray] tiles +bullet.suppression = [stat]{0} sec[lightgray] repair suppression ~ [stat]{1}[lightgray] kostek bullet.interval = [stat]{0}/sec[lightgray] interval bullets: bullet.frags = [stat]{0}[lightgray]x frag střel: bullet.lightning = [stat]{0}[lightgray]x jiskření ~ [stat]{1}[lightgray] poškození @@ -993,10 +992,10 @@ bullet.knockback = [stat]{0}[lightgray] odhození[] bullet.pierce = [stat]{0}[lightgray]x průrazné[] bullet.infinitepierce = [stat]průrazné[] bullet.healpercent = [stat]{0}[lightgray]% opravující -bullet.healamount = [stat]{0}[lightgray] direct repair +bullet.healamount = [stat]{0}[lightgray] přímá oprava bullet.multiplier = [stat]{0}[lightgray]x více střel[] bullet.reload = [stat]{0}[lightgray]x rychlost střelby[] -bullet.range = [stat]{0}[lightgray] tiles range +bullet.range = [stat]{0}[lightgray] kostek dosah unit.blocks = bloky unit.blockssquared = bloky² @@ -1006,7 +1005,7 @@ unit.liquidsecond = kapalin/sekundu unit.itemssecond = předmětů/sekundu unit.liquidunits = jednotek kapalin unit.powerunits = jednotek energie -unit.heatunits = heat units +unit.heatunits = jednotek tepla unit.degrees = úhly unit.seconds = sekundy unit.minutes = minuty @@ -1038,7 +1037,7 @@ setting.logichints.name = Logic Nápovědy setting.backgroundpause.name = Pozastavit v pozadí setting.buildautopause.name = Automaticky pozastavit stavění setting.doubletapmine.name = Dvojklik pro Těžbu -setting.commandmodehold.name = Hold For Command Mode +setting.commandmodehold.name = Držet pro Příkazový Režim setting.modcrashdisable.name = Vypnout Modifikace Při Pádovém Spuštění setting.animatedwater.name = Animované povrchy setting.animatedshields.name = Animované štíty @@ -1060,11 +1059,11 @@ setting.difficulty.hard = Těžká setting.difficulty.insane = Šílená setting.difficulty.name = Obtížnost: setting.screenshake.name = Chvění obrazovky -setting.bloomintensity.name = Bloom Intensity -setting.bloomblur.name = Bloom Blur +setting.bloomintensity.name = Intenzita Bloom +setting.bloomblur.name = Rozmazání Bloom setting.effects.name = Zobrazit efekty setting.destroyedblocks.name = Zobrazit zničené bloky -setting.blockstatus.name = Display Block Status +setting.blockstatus.name = Zobrazit Stav Bloku setting.conveyorpathfinding.name = Hledat cestu při umisťování pásu setting.sensitivity.name = Citlivost ovladače setting.saveinterval.name = Interval automatického ukládání @@ -1075,14 +1074,14 @@ setting.borderlesswindow.name = Bezokrajové okno [lightgray](může výt vyžad setting.borderlesswindow.name.windows = Celá obrazovka bez okrajů setting.borderlesswindow.description = Pro aplikování změn, je potřeba restart. setting.fps.name = Ukázat FPS a ping -setting.console.name = Enable Console +setting.console.name = Povolit Konzoli setting.smoothcamera.name = Plynulá kamera setting.vsync.name = Vertikální synchronizace setting.pixelate.name = Rozpixlovat setting.minimap.name = Ukázat mapičku setting.coreitems.name = Ukázat položky jádra setting.position.name = Ukázat pozici hráče -setting.mouseposition.name = Show Mouse Position +setting.mouseposition.name = Zobrazit Pozici Myši setting.musicvol.name = Hlasitost hudby setting.atmosphere.name = Ukázat atmosféru planety setting.ambientvol.name = Hlasitost prostředí @@ -1099,7 +1098,7 @@ setting.bridgeopacity.name = Průsvitnost přemostění setting.playerchat.name = Zobrazit bublinu se zprávami hráče setting.showweather.name = Zobrazit Grafiku Počasí setting.hidedisplays.name = Hide Logic Displays -steam.friendsonly = Friends Only +steam.friendsonly = Přátele Pouze steam.friendsonly.tooltip = Whether only Steam friends will be able to join your game.\nUnchecking this box will make your game public - anyone can join. public.beta = Poznámka: nevydané verze her nemůžou být veřejné. uiscale.reset = Škálování uživatelskho rozhraní se změnilo.\nZmáčkni "OK", abys potvrdil toto nastavení.\n[scarlet]Návrat k původním hodnotám proběhne za [accent]{0}[] vteřin...[] @@ -1125,8 +1124,8 @@ keybind.move_y.name = Pohyb svisle keybind.mouse_move.name = Následovat myš keybind.pan.name = Následovat kameru keybind.boost.name = Posílení -keybind.command_mode.name = Command Mode -keybind.rebuild_select.name = Rebuild Region +keybind.command_mode.name = Příkazový Režim +keybind.rebuild_select.name = Přestavět Region keybind.schematic_select.name = Vybrat oblast keybind.schematic_menu.name = Nabídka šablon keybind.schematic_flip_x.name = Překlopit šablona podle svislé osy @@ -1152,8 +1151,8 @@ keybind.select.name = Vybrat/Střílet keybind.diagonal_placement.name = Umisťovat úhlopříčně keybind.pick.name = Vybrat blok keybind.break_block.name = Rozbít blok -keybind.select_all_units.name = Select All Units -keybind.select_all_unit_factories.name = Select All Unit Factories +keybind.select_all_units.name = Vybrat Všechny Jednotky +keybind.select_all_unit_factories.name = Vybrat Všechny Továrny Jednotek keybind.deselect.name = Odznačit keybind.pickupCargo.name = Vyzvednout náklad keybind.dropCargo.name = Položit náklad @@ -1194,31 +1193,31 @@ rules.infiniteresources = Neomezeně surovin rules.onlydepositcore = Only Allow Core Depositing rules.reactorexplosions = Výbuch reaktoru rules.coreincinerates = Jádro Spaluje Nadbytečné Suroviny -rules.disableworldprocessors = Disable World Processors +rules.disableworldprocessors = Zakázat Světové Procesory rules.schematic = Šablony povoleny rules.wavetimer = Časovač vln rules.wavesending = Wave Sending rules.waves = Vlny rules.attack = Režim útoku -rules.buildai = Base Builder AI -rules.buildaitier = Builder AI Tier +rules.buildai = Umělá AI staví +rules.buildaitier = Úroveň AI stavitele rules.rtsai = RTS AI -rules.rtsminsquadsize = Min Squad Size -rules.rtsmaxsquadsize = Max Squad Size -rules.rtsminattackweight = Min Attack Weight +rules.rtsminsquadsize = Min velikost skupiny +rules.rtsmaxsquadsize = Max velikost skupiny +rules.rtsminattackweight = Min váha útoku rules.cleanupdeadteams = Vyčistit Budovy Poražených Týmů (PvP) rules.corecapture = Dobýt Jádro Po Jeho Zničení rules.polygoncoreprotection = Polygonální Ochrana Jádra -rules.placerangecheck = Placement Range Check +rules.placerangecheck = Dosah stavění rules.enemyCheat = Neomezeně surovin pro umělou inteligenci rules.blockhealthmultiplier = Násobek zdraví bloků rules.blockdamagemultiplier = Násobek poškození bloků rules.unitbuildspeedmultiplier = Násobek rychlosti výroby jednotek -rules.unitcostmultiplier = Unit Cost Multiplier +rules.unitcostmultiplier = Násobek ceny jednotek rules.unithealthmultiplier = Násobek zdraví jednotek rules.unitdamagemultiplier = Násobek poškození jednotkami -rules.unitcrashdamagemultiplier = Unit Crash Damage Multiplier -rules.solarmultiplier = Solar Power Multiplier +rules.unitcrashdamagemultiplier = Násobek poškození při nárazu jednotky +rules.solarmultiplier = Násobek Solární Energie rules.unitcapvariable = Jádra Zvýšujou Maximum Počtu Jednotek rules.unitcap = Základní Maximum Počtu Jednotek rules.limitarea = Limit Map Area @@ -1229,7 +1228,7 @@ rules.buildcostmultiplier = Násobek ceny stavění rules.buildspeedmultiplier = Násobek rychlosti stavění rules.deconstructrefundmultiplier = Násobek vratky při rozebrání rules.waitForWaveToEnd = Vlny čekají na nepřátele -rules.wavelimit = Map Ends After Wave +rules.wavelimit = Mapa končí po vlně rules.dropzoneradius = Poloměr oblasti pro vylíhnutí: [lightgray](dlaždic)[] rules.unitammo = Jednotky vyžadují munici rules.enemyteam = Nepřátelský Tým @@ -1241,11 +1240,11 @@ rules.title.unit = Jednotky rules.title.experimental = Experimentální rules.title.environment = Environmentální rules.title.teams = Týmy -rules.title.planet = Planet +rules.title.planet = Planeta rules.lighting = Osvětlení rules.fog = Fog of War rules.fire = Výstřel -rules.anyenv = +rules.anyenv = rules.explosions = Výbušné poškození bloku/jednotky rules.ambientlight = Světlo prostředí rules.weather = Počasí @@ -1278,24 +1277,24 @@ item.blast-compound.name = Výbušnina item.pyratite.name = Pyratit item.metaglass.name = Metasklo item.scrap.name = Šrot -item.fissile-matter.name = Fissile Matter -item.beryllium.name = Beryllium -item.tungsten.name = Tungsten -item.oxide.name = Oxide -item.carbide.name = Carbide +item.fissile-matter.name = Štěpná Hmota +item.beryllium.name = Berylium +item.tungsten.name = Wolfram +item.oxide.name = Oxid +item.carbide.name = Karbid item.dormant-cyst.name = Dormant Cyst liquid.water.name = Voda liquid.slag.name = Struska liquid.oil.name = Nafta liquid.cryofluid.name = Chladící kapalina -liquid.neoplasm.name = Neoplasm -liquid.arkycite.name = Arkycite -liquid.gallium.name = Gallium -liquid.ozone.name = Ozone -liquid.hydrogen.name = Hydrogen -liquid.nitrogen.name = Nitrogen -liquid.cyanogen.name = Cyanogen +liquid.neoplasm.name = Neoplasma +liquid.arkycite.name = Arkycit +liquid.gallium.name = Gálium +liquid.ozone.name = Ozón +liquid.hydrogen.name = Vodík +liquid.nitrogen.name = Dusík +liquid.cyanogen.name = Kyanogen unit.dagger.name = Dýka unit.mace.name = Palcát @@ -1339,12 +1338,12 @@ unit.stell.name = Stell unit.locus.name = Locus unit.precept.name = Precept unit.vanquish.name = Vanquish -unit.conquer.name = Conquer +unit.conquer.name = Dobyvatel unit.merui.name = Merui unit.cleroi.name = Cleroi -unit.anthicus.name = Anthicus +unit.anthicus.name = Antikus unit.tecta.name = Tecta -unit.collaris.name = Collaris +unit.collaris.name = Kolaris unit.elude.name = Elude unit.avert.name = Avert unit.obviate.name = Obviate @@ -1354,7 +1353,7 @@ unit.evoke.name = Evoke unit.incite.name = Incite unit.emanate.name = Emanate unit.manifold.name = Manifold -unit.assembly-drone.name = Assembly Drone +unit.assembly-drone.name = Montážní Dron unit.latum.name = Latum unit.renale.name = Renale @@ -1469,8 +1468,8 @@ block.distributor.name = Rozdělovač block.sorter.name = Třídička block.inverted-sorter.name = Obrácená třídička block.message.name = Zpráva -block.reinforced-message.name = Reinforced Message -block.world-message.name = World Message +block.reinforced-message.name = Posílená Zpráva +block.world-message.name = Světová Zpráva block.illuminator.name = Osvětlovač block.overflow-gate.name = Brána s přepadem block.underflow-gate.name = Brána s podtokem @@ -1567,7 +1566,7 @@ block.payload-router.name = Směřovač nákladu block.duct.name = Potrubí block.duct-router.name = Potrubní Směrovač block.duct-bridge.name = Potrubní Most -block.large-payload-mass-driver.name = Large Payload Mass Driver +block.large-payload-mass-driver.name = Velká Nákladní Transportní Věž block.payload-void.name = Černá díra na náklad block.payload-source.name = Zdroj nákladů block.disassembler.name = Rozebírač @@ -1584,23 +1583,23 @@ block.payload-loader.name = Nákladový Nakládač block.payload-loader.description = Nakládá kapaliny a věci z bloků. block.payload-unloader.name = Nákladový Vykládač block.payload-unloader.description = Vykládá kapaliny a věci z bloků. -block.heat-source.name = Heat Source -block.heat-source.description = A 1x1 block that gives virtualy infinite heat. -block.empty.name = Empty -block.rhyolite-crater.name = Rhyolite Crater -block.rough-rhyolite.name = Rough Rhyolite -block.regolith.name = Regolith -block.yellow-stone.name = Yellow Stone -block.carbon-stone.name = Carbon Stone +block.heat-source.name = Zdroj Tepla +block.heat-source.description = 1x1 blok, který dává virtuálně někonečné teplo. +block.empty.name = Prázdné +block.rhyolite-crater.name = Ryolitní Kráter +block.rough-rhyolite.name = Hrubý Ryolit +block.regolith.name = Regolit +block.yellow-stone.name = Žlutý Kámen +block.carbon-stone.name = Krabonový Kámen block.ferric-stone.name = Ferric Stone block.ferric-craters.name = Ferric Craters block.beryllic-stone.name = Beryllic Stone block.crystalline-stone.name = Crystalline Stone -block.crystal-floor.name = Crystal Floor -block.yellow-stone-plates.name = Yellow Stone Plates -block.red-stone.name = Red Stone -block.dense-red-stone.name = Dense Red Stone -block.red-ice.name = Red Ice +block.crystal-floor.name = Křišťalová Zem +block.yellow-stone-plates.name = Žluté Kamenné Pláty +block.red-stone.name = Červený Kámen +block.dense-red-stone.name = Hustý Červený Kámen +block.red-ice.name = Červený Led block.arkycite-floor.name = Arkycite Floor block.arkyic-stone.name = Arkyic Stone block.rhyolite-vent.name = Rhyolite Vent @@ -1611,21 +1610,21 @@ block.red-stone-vent.name = Red Stone Vent block.crystalline-vent.name = Crystalline Vent block.redmat.name = Redmat block.bluemat.name = Bluemat -block.core-zone.name = Core Zone +block.core-zone.name = Jádrová Zona block.regolith-wall.name = Regolith Wall block.yellow-stone-wall.name = Yellow Stone Wall block.rhyolite-wall.name = Rhyolite Wall -block.carbon-wall.name = Carbon Wall +block.carbon-wall.name = Krabonová Zeď block.ferric-stone-wall.name = Ferric Stone Wall block.beryllic-stone-wall.name = Beryllic Stone Wall block.arkyic-wall.name = Arkyic Wall block.crystalline-stone-wall.name = Crystalline Stone Wall -block.red-ice-wall.name = Red Ice Wall -block.red-stone-wall.name = Red Stone Wall -block.red-diamond-wall.name = Red Diamond Wall +block.red-ice-wall.name = Červená Ledová Zeď +block.red-stone-wall.name = Červená Kamenná Zeď +block.red-diamond-wall.name = Červená Diamantová Zeď block.redweed.name = Redweed block.pur-bush.name = Pur Bush -block.yellowcoral.name = Yellowcoral +block.yellowcoral.name = Žlutý Korál block.carbon-boulder.name = Carbon Boulder block.ferric-boulder.name = Ferric Boulder block.beryllic-boulder.name = Beryllic Boulder @@ -1633,32 +1632,32 @@ block.yellow-stone-boulder.name = Yellow Stone Boulder block.arkyic-boulder.name = Arkyic Boulder block.crystal-cluster.name = Crystal Cluster block.vibrant-crystal-cluster.name = Vibrant Crystal Cluster -block.crystal-blocks.name = Crystal Blocks -block.crystal-orbs.name = Crystal Orbs +block.crystal-blocks.name = Křišťálové Bloky +block.crystal-orbs.name = Křišťálové Orby block.crystalline-boulder.name = Crystalline Boulder block.red-ice-boulder.name = Red Ice Boulder block.rhyolite-boulder.name = Rhyolite Boulder block.red-stone-boulder.name = Red Stone Boulder block.graphitic-wall.name = Graphitic Wall block.silicon-arc-furnace.name = Silicon Arc Furnace -block.electrolyzer.name = Electrolyzer +block.electrolyzer.name = Elektrolyzer block.atmospheric-concentrator.name = Atmospheric Concentrator block.oxidation-chamber.name = Oxidation Chamber -block.electric-heater.name = Electric Heater +block.electric-heater.name = Elektrický Ohřívač block.slag-heater.name = Slag Heater block.phase-heater.name = Phase Heater block.heat-redirector.name = Heat Redirector -block.heat-router.name = Heat Router +block.heat-router.name = Tepelný Směrovač block.slag-incinerator.name = Slag Incinerator block.carbide-crucible.name = Carbide Crucible block.slag-centrifuge.name = Slag Centrifuge block.surge-crucible.name = Surge Crucible block.cyanogen-synthesizer.name = Cyanogen Synthesizer block.phase-synthesizer.name = Phase Synthesizer -block.heat-reactor.name = Heat Reactor +block.heat-reactor.name = Tepelný Reaktor block.beryllium-wall.name = Beryllium Wall block.beryllium-wall-large.name = Large Beryllium Wall -block.tungsten-wall.name = Tungsten Wall +block.tungsten-wall.name = Wolframová Zeď block.tungsten-wall-large.name = Large Tungsten Wall block.blast-door.name = Blast Door block.carbide-wall.name = Carbide Wall @@ -1670,7 +1669,7 @@ block.radar.name = Radar block.build-tower.name = Build Tower block.regen-projector.name = Regen Projector block.shockwave-tower.name = Shockwave Tower -block.shield-projector.name = Shield Projector +block.shield-projector.name = Štítový Projektor block.large-shield-projector.name = Large Shield Projector block.armored-duct.name = Armored Duct block.overflow-duct.name = Overflow Duct @@ -1711,7 +1710,7 @@ block.disperse.name = Disperse block.afflict.name = Afflict block.lustre.name = Lustre block.scathe.name = Scathe -block.fabricator.name = Fabricator +block.fabricator.name = Fabrikátor block.tank-refabricator.name = Tank Refabricator block.mech-refabricator.name = Mech Refabricator block.ship-refabricator.name = Ship Refabricator @@ -1722,20 +1721,20 @@ block.reinforced-payload-conveyor.name = Reinforced Payload Conveyor block.reinforced-payload-router.name = Reinforced Payload Router block.payload-mass-driver.name = Payload Mass Driver block.small-deconstructor.name = Small Deconstructor -block.canvas.name = Canvas -block.world-processor.name = World Processor -block.world-cell.name = World Cell -block.tank-fabricator.name = Tank Fabricator +block.canvas.name = Plátno +block.world-processor.name = Světový Procesor +block.world-cell.name = Světová Buňka +block.tank-fabricator.name = Frabrikátor tanků block.mech-fabricator.name = Mech Fabricator block.ship-fabricator.name = Ship Fabricator block.prime-refabricator.name = Prime Refabricator block.unit-repair-tower.name = Unit Repair Tower block.diffuse.name = Diffuse -block.basic-assembler-module.name = Basic Assembler Module +block.basic-assembler-module.name = Běžný Skládací Modul block.smite.name = Smite block.malign.name = Malign -block.flux-reactor.name = Flux Reactor -block.neoplasia-reactor.name = Neoplasia Reactor +block.flux-reactor.name = Fluxní Reaktor +block.neoplasia-reactor.name = Neoplasia Reaktor block.switch.name = Přepínač block.micro-processor.name = Mikroprocesor @@ -2230,20 +2229,20 @@ laccess.dead = Zda jednotka/budova je mrtvá/zničená nebo již neplatná. laccess.controlled = Vrací:\n[accent]@ctrlProcessor[] pokud kontroler jednotky je procesor\n[accent]@ctrlPlayer[] pokud kontroloer jednotky/budovy je hráč\n[accent]@ctrlFormation[] pokud jednotka je ve formaci\nJiank, 0. laccess.progress = Průběh akce, 0 do 1.\nVrací průběh výroby, přebití věže nebo stavby. laccess.speed = Top speed of a unit, in tiles/sec. -lcategory.unknown = Unknown -lcategory.unknown.description = Uncategorized instructions. -lcategory.io = Input & Output -lcategory.io.description = Modify contents of memory blocks and processor buffers. -lcategory.block = Block Control -lcategory.block.description = Interact with blocks. -lcategory.operation = Operations -lcategory.operation.description = Logical operations. +lcategory.unknown = Neznámé +lcategory.unknown.description = Nezařazené instrukce. +lcategory.io = Vstup a Výstup +lcategory.io.description = Upravuje obsah paměťních bloků a procesorových pamětí. +lcategory.block = Ovládaní Bloku +lcategory.block.description = Interaktovat s bloky. +lcategory.operation = Operace +lcategory.operation.description = Logické operace. lcategory.control = Flow Control lcategory.control.description = Manage execution order. lcategory.unit = Unit Control lcategory.unit.description = Give units commands. -lcategory.world = World -lcategory.world.description = Control how the world behaves. +lcategory.world = Svět +lcategory.world.description = Ovládá, jak se svět chová. graphicstype.clear = Vyplní zobrazovač danou barvou. graphicstype.color = Vybere barvu pro další vykreslovací operace. From 19cd6fd07cc5b8caea7a4335c6acd95cdf8f7ea8 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 24 May 2023 09:49:30 -0400 Subject: [PATCH 0058/1150] Fixed #8632 --- core/assets/bundles/bundle.properties | 4 ++-- core/src/mindustry/net/ArcNetProvider.java | 3 +-- tools/src/mindustry/tools/Generators.java | 8 +++++++- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 1b327a02cd..c7f7921ae2 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1811,8 +1811,8 @@ hint.factoryControl.mobile = To set a unit factory's [accent]output destination[ gz.mine = Move near the \uF8C4 [accent]copper ore[] on the ground and click to begin mining. gz.mine.mobile = Move near the \uF8C4 [accent]copper ore[] on the ground and tap it to begin mining. -gz.research = Open the \uE875 tech tree.\nResearch the \uF870 [accent]Mechanical Drill[], then select it from the menu in the bottom right.\nClick on a copper patch to place it. -gz.research.mobile = Open the \uE875 tech tree.\nResearch the \uF870 [accent]Mechanical Drill[], then select it from the menu in the bottom right.\nTap on a copper patch to place it.\n\nPress the \uE800 [accent]checkmark[] at the bottom right to confirm. +gz.research = Open the \uE875 tech tree.\nResearch the \uF870 [accent]Mechanical Drill[], then select it from the \ue85e menu in the bottom right.\nClick on a copper patch to place it. +gz.research.mobile = Open the \uE875 tech tree.\nResearch the \uF870 [accent]Mechanical Drill[], then select it from the \ue85e menu in the bottom right.\nTap on a copper patch to place it.\n\nPress the \uE800 [accent]checkmark[] at the bottom right to confirm. gz.conveyors = Research and place \uF896 [accent]conveyors[] to move the mined resources\nfrom drills to the core.\n\nClick and drag to place multiple conveyors.\n[accent]Scroll[] to rotate. gz.conveyors.mobile = Research and place \uF896 [accent]conveyors[] to move the mined resources\nfrom drills to the core.\n\nHold down your finger for a second and drag to place multiple conveyors. gz.drills = Expand the mining operation.\nPlace more Mechanical Drills.\nMine 100 copper. diff --git a/core/src/mindustry/net/ArcNetProvider.java b/core/src/mindustry/net/ArcNetProvider.java index 462415b20d..222a97baa0 100644 --- a/core/src/mindustry/net/ArcNetProvider.java +++ b/core/src/mindustry/net/ArcNetProvider.java @@ -136,8 +136,7 @@ public class ArcNetProvider implements NetProvider{ @Override public void received(Connection connection, Object object){ - if(!(connection.getArbitraryData() instanceof ArcConnection k)) return; - if(!(object instanceof Packet pack)) return; + if(!(connection.getArbitraryData() instanceof ArcConnection k) || !(object instanceof Packet pack)) return; if(packetSpamLimit > 0 && !k.packetRate.allow(3000, packetSpamLimit)){ Log.warn("Blacklisting IP '@' as potential DOS attack - packet spam.", k.address); diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index a48462ebbd..fa954a4197 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -349,7 +349,13 @@ public class Generators{ region.path.delete(); - save(out, region.name); + //1 pixel of padding to prevent edges with linear filtering + int padding = 1; + Pixmap padded = new Pixmap(base.width + padding*2, base.height + padding*2); + padded.draw(base, padding, padding); + padded = padded.outline(block.outlineColor, block.outlineRadius); + + save(padded, region.name); } if(!regions[0].found()){ From 5c45df1a69f575034d6f6b9fd8bb7d3ff1c33ed9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 24 May 2023 16:49:09 -0400 Subject: [PATCH 0059/1150] Fixed turrets with moveWhileCharging = true and accurateDelay = true --- .../mindustry/world/blocks/defense/turrets/Turret.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 2a3862837f..9003d6e4c6 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -85,6 +85,8 @@ public class Turret extends ReloadTurret{ public boolean targetUnderBlocks = true; /** If true, the turret will always shoot when it has ammo, regardless of targets in range or any control. */ public boolean alwaysShooting = false; + /** Whether this turret predicts unit movement. */ + public boolean predictTarget = true; /** Function for choosing which unit to target. */ public Sortf unitSort = UnitSorts.closest; /** Filter for types of units to attack. */ @@ -332,11 +334,15 @@ public class Turret extends ReloadTurret{ var offset = Tmp.v1.setZero(); //when delay is accurate, assume unit has moved by chargeTime already - if(accurateDelay && pos instanceof Hitboxc h){ + if(accurateDelay && !moveWhileCharging && pos instanceof Hitboxc h){ offset.set(h.deltaX(), h.deltaY()).scl(shoot.firstShotDelay / Time.delta); } - targetPos.set(Predict.intercept(this, pos, offset.x, offset.y, bullet.speed <= 0.01f ? 99999999f : bullet.speed)); + if(predictTarget){ + targetPos.set(Predict.intercept(this, pos, offset.x, offset.y, bullet.speed <= 0.01f ? 99999999f : bullet.speed)); + }else{ + targetPos.set(pos); + } if(targetPos.isZero()){ targetPos.set(pos); From f5a32fdb6bacdb6fa50bbf04ae0d2d83423d0714 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 25 May 2023 02:44:07 -0400 Subject: [PATCH 0060/1150] near is further again --- core/src/mindustry/graphics/g3d/PlanetRenderer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index 536af2c4be..514572d435 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -42,7 +42,6 @@ public class PlanetRenderer implements Disposable{ projector.setScaling(1f / 150f); cam.fov = 60f; cam.far = 150f; - cam.near = 0.1f; } /** Render the entire planet scene to the screen. */ From 6a8e0eb6b205397ccec5f50b91669b6069e8e797 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 25 May 2023 09:13:37 -0400 Subject: [PATCH 0061/1150] Stack router fix --- .../mindustry/world/blocks/distribution/StackRouter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/world/blocks/distribution/StackRouter.java b/core/src/mindustry/world/blocks/distribution/StackRouter.java index ea707098b4..e763b2ece1 100644 --- a/core/src/mindustry/world/blocks/distribution/StackRouter.java +++ b/core/src/mindustry/world/blocks/distribution/StackRouter.java @@ -44,7 +44,7 @@ public class StackRouter extends DuctRouter{ if(unloading && current != null){ //unload when possible var target = target(); - while(target != null && items.total() > 0){ + while(target != null && items.get(current) > 0){ target.handleItem(this, current); items.remove(current, 1); @@ -52,13 +52,13 @@ public class StackRouter extends DuctRouter{ } //if out of items, unloading is over - if(items.total() == 0){ + if(items.get(current) == 0){ current = null; unloading = false; } } - if(current == null && items.total() > 0){ + if((current == null || items.get(current) == 0) && items.total() > 0){ current = items.first(); } } From 80ad379c18e9e1022ac8902ae2f51ee51f9dfcf9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 25 May 2023 12:05:33 -0400 Subject: [PATCH 0062/1150] Buffer gone --- core/src/mindustry/graphics/g3d/PlanetRenderer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java index 514572d435..812bb2b504 100644 --- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java +++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java @@ -4,7 +4,6 @@ import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.graphics.g3d.*; -import arc.graphics.gl.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; @@ -27,7 +26,6 @@ public class PlanetRenderer implements Disposable{ public final PlaneBatch3D projector = new PlaneBatch3D(); public final Mat3D mat = new Mat3D(); - public final FrameBuffer buffer = new FrameBuffer(2, 2, true); public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{ setThreshold(0.8f); @@ -235,7 +233,6 @@ public class PlanetRenderer implements Disposable{ batch.dispose(); projector.dispose(); atmosphere.dispose(); - buffer.dispose(); bloom.dispose(); } From b21c0f4553f9a657310c0d6ed517deb223869160 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 26 May 2023 14:12:34 -0400 Subject: [PATCH 0063/1150] Fixed squished logic icons --- core/src/mindustry/world/blocks/logic/LogicDisplay.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/logic/LogicDisplay.java b/core/src/mindustry/world/blocks/logic/LogicDisplay.java index 888ebf5b62..192bd67801 100644 --- a/core/src/mindustry/world/blocks/logic/LogicDisplay.java +++ b/core/src/mindustry/world/blocks/logic/LogicDisplay.java @@ -98,7 +98,10 @@ public class LogicDisplay extends Block{ case commandTriangle -> Fill.tri(x, y, p1, p2, p3, p4); case commandColor -> Draw.color(this.color = Color.toFloatBits(x, y, p1, p2)); case commandStroke -> Lines.stroke(this.stroke = x); - case commandImage -> Draw.rect(Fonts.logicIcon(p1), x, y, p2, p2, p3); + case commandImage -> { + var icon = Fonts.logicIcon(p1); + Draw.rect(Fonts.logicIcon(p1), x, y, p2, p2 / icon.ratio(), p3); + } } } From 4f34a9235cb7e001aa27e0fc478b1d1f5e54511c Mon Sep 17 00:00:00 2001 From: buthed010203 Date: Fri, 26 May 2023 17:57:24 -0400 Subject: [PATCH 0064/1150] Don't show ghosts when typing in chat (#8644) * Don't show ghosts when typing in chat * braint --- core/src/mindustry/graphics/BlockRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 394238b8e8..29807d0132 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -266,7 +266,7 @@ public class BlockRenderer{ public void drawDestroyed(){ if(!Core.settings.getBool("destroyedblocks")) return; - if(control.input.isPlacing() || control.input.isBreaking() || control.input.isRebuildSelecting()){ + if(control.input.isPlacing() || control.input.isBreaking() || (control.input.isRebuildSelecting() && !scene.hasKeyboard())){ brokenFade = Mathf.lerpDelta(brokenFade, 1f, 0.1f); }else{ brokenFade = Mathf.lerpDelta(brokenFade, 0f, 0.1f); From c2d7e2eb725c8effc19e87e47ae87b1db1c99e2e Mon Sep 17 00:00:00 2001 From: WayZer Date: Sat, 27 May 2023 21:05:08 +0800 Subject: [PATCH 0065/1150] fix assetsJar (#8641) --- build.gradle | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 5b3103f660..84cfbefca7 100644 --- a/build.gradle +++ b/build.gradle @@ -320,11 +320,6 @@ project(":core"){ } } - artifacts{ - archives sourcesJar - archives assetsJar - } - dependencies{ compileJava.dependsOn(preGen) @@ -442,6 +437,9 @@ configure([":core", ":server"].collect{project(it)}){ publications{ maven(MavenPublication){ from components.java + if(project.name == "core"){ + artifact(tasks.named("assetsJar")) + } } } } From ca51ad601ef8533d22e9199d7cdf25c9cb61d931 Mon Sep 17 00:00:00 2001 From: thedimas <51395517+thedimas3007@users.noreply.github.com> Date: Sat, 27 May 2023 15:19:14 +0200 Subject: [PATCH 0066/1150] Add some servers (#8640) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 7fd9baa2ac..176e779a0f 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -41,7 +41,7 @@ }, { "name": "thedimas", - "address": ["91.209.226.11", "91.209.226.11:6510", "91.209.226.11:6511", "91.209.226.11:6509", "91.209.226.11:6508", "91.209.226.11:6512", "91.209.226.11:6513"] + "address": ["91.209.226.11", "91.209.226.11:6503","91.209.226.11:6505", "91.209.226.11:6506", "91.209.226.11:6507", "91.209.226.11:6508", "91.209.226.11:6509", "91.209.226.11:6510", "91.209.226.11:6511", "91.209.226.11:6512", "91.209.226.11:6513"] }, { "name": "HexPvP Network", From ab95b88c057b175ee4a7bea81782022f4a0ef09a Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 27 May 2023 09:57:53 -0400 Subject: [PATCH 0067/1150] Fixed Base AI not working sometimes --- core/src/mindustry/ai/BaseBuilderAI.java | 61 ++---------------------- core/src/mindustry/ai/Pathfinder.java | 4 ++ core/src/mindustry/core/Renderer.java | 2 +- gradle.properties | 2 +- 4 files changed, 10 insertions(+), 59 deletions(-) diff --git a/core/src/mindustry/ai/BaseBuilderAI.java b/core/src/mindustry/ai/BaseBuilderAI.java index afc2a40be8..b3093b4f17 100644 --- a/core/src/mindustry/ai/BaseBuilderAI.java +++ b/core/src/mindustry/ai/BaseBuilderAI.java @@ -12,10 +12,8 @@ import mindustry.game.*; import mindustry.game.Schematic.*; import mindustry.game.Teams.*; import mindustry.gen.*; -import mindustry.maps.generators.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.defense.*; import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.production.*; import mindustry.world.blocks.storage.*; @@ -35,7 +33,7 @@ public class BaseBuilderAI{ private static int correct = 0, incorrect = 0; private int lastX, lastY, lastW, lastH; - private boolean triedWalls, foundPath; + private boolean foundPath; final TeamData data; final Interval timer = new Interval(4); @@ -46,7 +44,6 @@ public class BaseBuilderAI{ boolean calculating, startedCalculating; int calcCount = 0; int totalCalcs = 0; - Block wallType; public BaseBuilderAI(TeamData data){ this.data = data; @@ -62,10 +59,6 @@ public class BaseBuilderAI{ } } - if(wallType == null){ - wallType = BaseGenerator.getDifficultyWall(1, data.team.rules().buildAiTier / 0.8f); - } - if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 6f) && data.hasCore()){ CoreBlock block = (CoreBlock)data.core().block; int coreUnits = data.countType(block.unitType); @@ -104,8 +97,8 @@ public class BaseBuilderAI{ }else{ var field = pathfinder.getField(data.team, Pathfinder.costGround, Pathfinder.fieldCore); - if(field.weights != null){ - int[] weights = field.weights; + if(field.hasCompleteWeights()){ + int[] weights = field.completeWeights; for(int i = 0; i < pathStep; i++){ int minCost = Integer.MAX_VALUE; int cx = calcTile.x, cy = calcTile.y; @@ -154,12 +147,7 @@ public class BaseBuilderAI{ } //only schedule when there's something to build. - if(foundPath && data.plans.isEmpty() && timer.get(timerStep, Mathf.lerp(placeIntervalMin, placeIntervalMax, data.team.rules().buildAiTier))){ - //TODO walls are silly, no walls - //if(!triedWalls){ - // tryWalls(); - // triedWalls = true; - //} + if((foundPath || (!calculating && !foundPath)) && data.plans.isEmpty() && timer.get(timerStep, Mathf.lerp(placeIntervalMin, placeIntervalMax, data.team.rules().buildAiTier))){ for(int i = 0; i < attempts; i++){ int range = 150; @@ -279,47 +267,6 @@ public class BaseBuilderAI{ lastW = result.width + 2; lastH = result.height + 2; - triedWalls = false; - return true; } - - private void tryWalls(){ - Block wall = wallType; - Building spawnt = state.rules.defaultTeam.core() != null ? state.rules.defaultTeam.core() : data.team.core(); - Tile spawn = spawnt == null ? null : spawnt.tile; - - if(spawn == null) return; - - for(int wx = lastX; wx <= lastX + lastW; wx++){ - outer: - for(int wy = lastY; wy <= lastY + lastH; wy++){ - Tile tile = world.tile(wx, wy); - - if(tile == null || !tile.block().alwaysReplace) continue; - - boolean any = false; - - for(Point2 p : Geometry.d8){ - if(Angles.angleDist(Angles.angle(p.x, p.y), spawn.angleTo(tile)) > 70){ - continue; - } - - Tile o = world.tile(tile.x + p.x, tile.y + p.y); - if(o != null && (o.block() instanceof PayloadBlock || o.block() instanceof PayloadConveyor || o.block() instanceof ShockMine)){ - continue outer; - } - - if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){ - any = true; - } - } - - tmpTiles.clear(); - if(any && Build.validPlace(wall, data.team, tile.x, tile.y, 0) && !tile.getLinkedTilesAs(wall, tmpTiles).contains(t -> path.contains(t.pos()))){ - data.plans.add(new BlockPlan(tile.x, tile.y, (short)0, wall.id, null)); - } - } - } - } } \ No newline at end of file diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index ff8bb71534..e5f862e14f 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -522,6 +522,10 @@ public class Pathfinder implements Runnable{ this.initialized = true; } + public boolean hasCompleteWeights(){ + return hasComplete && completeWeights != null; + } + public void updateTargetPositions(){ targets.clear(); getPositions(targets); diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 1eb37957f2..35c3779b33 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -342,7 +342,7 @@ public class Renderer implements ApplicationListener{ if(bloom != null){ bloom.resize(graphics.getWidth(), graphics.getHeight()); - bloom.setBloomIntesity(settings.getInt("bloomintensity", 6) / 4f + 1f); + bloom.setBloomIntensity(settings.getInt("bloomintensity", 6) / 4f + 1f); bloom.blurPasses = settings.getInt("bloomblur", 1); Draw.draw(Layer.bullet - 0.02f, bloom::capture); Draw.draw(Layer.effect + 0.02f, bloom::render); diff --git a/gradle.properties b/gradle.properties index 9b6008c821..99182f85a4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -25,4 +25,4 @@ org.gradle.caching=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=d8cd7a6003 +archash=6433d83dbd From fc0f48e13d3e5183e986754e5e91db9984bbbdad Mon Sep 17 00:00:00 2001 From: "[Error_27]" Date: Sat, 27 May 2023 16:26:24 -0400 Subject: [PATCH 0068/1150] Fix Scaling on Objective Dialogs (#8646) --- core/src/mindustry/editor/MapObjectivesDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/editor/MapObjectivesDialog.java b/core/src/mindustry/editor/MapObjectivesDialog.java index 9642ea5126..5e354a84ae 100644 --- a/core/src/mindustry/editor/MapObjectivesDialog.java +++ b/core/src/mindustry/editor/MapObjectivesDialog.java @@ -98,7 +98,7 @@ public class MapObjectivesDialog extends BaseDialog{ setInterpreter(UnlockableContent.class, (cont, name, type, field, remover, indexer, get, set) -> { name(cont, name, remover, indexer); cont.table(t -> t.left().button( - b -> b.image().size(iconSmall).update(i -> i.setDrawable(get.get().uiIcon)), + b -> b.image().size(iconSmall).scaling(Scaling.fit).update(i -> i.setDrawable(get.get().uiIcon)), () -> showContentSelect(null, set, b -> (field != null && !field.isAnnotationPresent(Researchable.class)) || b.techNode != null) ).fill().pad(4)).growX().fillY(); }); @@ -505,7 +505,7 @@ public class MapObjectivesDialog extends BaseDialog{ content.getBy(type).as() )){ if(content.isHidden() || !check.get((T)content)) continue; - t.image(content == Blocks.air ? Icon.none.getRegion() : content.uiIcon).size(iconMed).pad(3) + t.image(content == Blocks.air ? Icon.none.getRegion() : content.uiIcon).size(iconMed).pad(3).scaling(Scaling.fit) .with(b -> b.addListener(new HandCursorListener())) .tooltip(content.localizedName).get().clicked(() -> { cons.get((T)content); From 257d34170373b4729515970fbb8c6ebf1463f3c0 Mon Sep 17 00:00:00 2001 From: MEEPofFaith <54301439+MEEPofFaith@users.noreply.github.com> Date: Sat, 27 May 2023 21:06:57 -0700 Subject: [PATCH 0069/1150] Spinning FlareParts (#8637) --- core/src/mindustry/entities/part/FlarePart.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/entities/part/FlarePart.java b/core/src/mindustry/entities/part/FlarePart.java index b82fbfb92b..d07987d37e 100644 --- a/core/src/mindustry/entities/part/FlarePart.java +++ b/core/src/mindustry/entities/part/FlarePart.java @@ -9,7 +9,7 @@ import mindustry.graphics.*; public class FlarePart extends DrawPart{ public int sides = 4; public float radius = 100f, radiusTo = -1f, stroke = 6f, innerScl = 0.5f, innerRadScl = 0.33f; - public float x, y, rotation, rotMove; + public float x, y, rotation, rotMove, spinSpeed; public boolean followRotation; public Color color1 = Pal.techBlue, color2 = Color.white; public PartProgress progress = PartProgress.warmup; @@ -29,7 +29,7 @@ public class FlarePart extends DrawPart{ float rx = params.x + Tmp.v1.x, ry = params.y + Tmp.v1.y, - rot = (followRotation ? params.rotation : 0f) + rotMove * prog + rotation, + rot = (followRotation ? params.rotation : 0f) + rotMove * prog + rotation + Time.time * spinSpeed, rad = radiusTo < 0 ? radius : Mathf.lerp(radius, radiusTo, prog); Draw.color(color1); From 8db8d79eff42085ae6cacd27fcd3f9521077fcf9 Mon Sep 17 00:00:00 2001 From: GlennFolker <63218676+GlennFolker@users.noreply.github.com> Date: Sun, 28 May 2023 20:14:15 +0700 Subject: [PATCH 0070/1150] Allow Universe to update all solar systems (#8647) --- core/src/mindustry/game/Universe.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java index 01b1d714b3..a1c8951db6 100644 --- a/core/src/mindustry/game/Universe.java +++ b/core/src/mindustry/game/Universe.java @@ -38,8 +38,10 @@ public class Universe{ /** Update regardless of whether the player is in the campaign. */ public void updateGlobal(){ - //currently only updates one solar system - updatePlanet(Planets.sun); + for(Planet planet : content.planets()){ + //update all parentless planets (solar system root), regardless of which one the player is in + if(planet.parent == null) updatePlanet(planet); + } } public int turn(){ From c4cd9e8f569c7195b9876243c001db7978d431b4 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 28 May 2023 09:57:26 -0400 Subject: [PATCH 0071/1150] Misc minor bugfixes --- core/src/mindustry/ai/BaseBuilderAI.java | 2 +- core/src/mindustry/logic/LStatements.java | 2 +- core/src/mindustry/world/blocks/power/LightBlock.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/ai/BaseBuilderAI.java b/core/src/mindustry/ai/BaseBuilderAI.java index b3093b4f17..763fd15ee5 100644 --- a/core/src/mindustry/ai/BaseBuilderAI.java +++ b/core/src/mindustry/ai/BaseBuilderAI.java @@ -147,7 +147,7 @@ public class BaseBuilderAI{ } //only schedule when there's something to build. - if((foundPath || (!calculating && !foundPath)) && data.plans.isEmpty() && timer.get(timerStep, Mathf.lerp(placeIntervalMin, placeIntervalMax, data.team.rules().buildAiTier))){ + if((foundPath || !calculating) && data.plans.isEmpty() && timer.get(timerStep, Mathf.lerp(placeIntervalMin, placeIntervalMax, data.team.rules().buildAiTier))){ for(int i = 0; i < attempts; i++){ int range = 150; diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index a8c35141b0..a20f1f30d8 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -643,7 +643,7 @@ public class LStatements{ b.clicked(() -> showSelect(b, LogicOp.all, op, o -> { op = o; rebuild(parent); - })); + }, 4, c -> c.width(64f))); }, Styles.logict, () -> {}).size(64f, 40f).pad(4f).color(table.color); } diff --git a/core/src/mindustry/world/blocks/power/LightBlock.java b/core/src/mindustry/world/blocks/power/LightBlock.java index 0d033aac05..8beccc9f76 100644 --- a/core/src/mindustry/world/blocks/power/LightBlock.java +++ b/core/src/mindustry/world/blocks/power/LightBlock.java @@ -38,7 +38,8 @@ public class LightBlock extends Block{ @Override public void init(){ - lightRadius = radius*3f; + lightRadius = radius*2.5f; + clipSize = Math.max(clipSize, lightRadius * 3f); emitLight = true; super.init(); From 7911a22cc91b51f1995dda0c95b27ef06c9f8e15 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 29 May 2023 10:23:32 -0400 Subject: [PATCH 0072/1150] Fixed #8649 --- core/src/mindustry/ai/BlockIndexer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index 705d2acfd5..0cae6ca790 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -286,7 +286,7 @@ public class BlockIndexer{ //when team data is not initialized, scan through every team. this is terrible if(data.isEmpty()){ for(Team enemy : Team.all){ - if(enemy == team) continue; + if(enemy == team || (enemy == Team.derelict && !state.rules.coreCapture)) continue; var set = getFlagged(enemy)[type.ordinal()]; if(set != null){ breturnArray.addAll(set); @@ -295,7 +295,7 @@ public class BlockIndexer{ }else{ for(int i = 0; i < data.size; i++){ Team enemy = data.items[i].team; - if(enemy == team) continue; + if(enemy == team || (enemy == Team.derelict && !state.rules.coreCapture)) continue; var set = getFlagged(enemy)[type.ordinal()]; if(set != null){ breturnArray.addAll(set); From e3ccd5cc2c727df7c46fb2d5f460a36b7730f827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D1=80=D0=BA=D0=BD=D0=B5=D1=81=D1=81=233729?= <79508138+Darkness6030@users.noreply.github.com> Date: Mon, 29 May 2023 20:09:56 +0300 Subject: [PATCH 0073/1150] Load content icons on a headless server (#8650) * Update build.gradle * Update Fonts.java * Update ServerLauncher.java * Update ServerLauncher.java * s stands for shiza * Update build.gradle --- core/src/mindustry/ui/Fonts.java | 23 +++++++++++++++++-- server/build.gradle | 4 +++- .../src/mindustry/server/ServerLauncher.java | 5 ++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/core/src/mindustry/ui/Fonts.java b/core/src/mindustry/ui/Fonts.java index 5cbfce3f42..753a2e7534 100644 --- a/core/src/mindustry/ui/Fonts.java +++ b/core/src/mindustry/ui/Fonts.java @@ -156,10 +156,29 @@ public class Fonts{ }); for(Team team : Team.baseTeams){ - if(Core.atlas.has("team-" + team.name)){ - team.emoji = stringIcons.get(team.name, ""); + team.emoji = stringIcons.get(team.name, ""); + } + } + + public static void loadContentIconsHeadless(){ + try(Scanner scan = new Scanner(Core.files.internal("icons/icons.properties").read(512))){ + while(scan.hasNextLine()){ + String line = scan.nextLine(); + String[] split = line.split("="); + String[] nametex = split[1].split("\\|"); + String character = split[0]; + int ch = Integer.parseInt(character); + + unicodeIcons.put(nametex[0], ch); + stringIcons.put(nametex[0], ((char)ch) + ""); } } + + stringIcons.put("alphachan", stringIcons.get("alphaaaa")); + + for(Team team : Team.baseTeams){ + team.emoji = stringIcons.get(team.name, ""); + } } /** Called from a static context for use in the loading screen.*/ diff --git a/server/build.gradle b/server/build.gradle index a15d067065..7359fdac3c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -39,11 +39,13 @@ task dist(type: Jar, dependsOn: configurations.runtimeClasspath){ exclude("music/**") exclude("sounds/**") exclude("fonts/**") - exclude("icons/**") exclude("bundles/**") exclude("cubemaps/**") exclude("cursors/**") exclude("shaders/**") + exclude("icons/icon.icns") + exclude("icons/icon.ico") + exclude("icons/icon_64.png") manifest{ attributes 'Main-Class': project.mainClassName diff --git a/server/src/mindustry/server/ServerLauncher.java b/server/src/mindustry/server/ServerLauncher.java index 413ee39e91..1aea11b2cc 100644 --- a/server/src/mindustry/server/ServerLauncher.java +++ b/server/src/mindustry/server/ServerLauncher.java @@ -11,6 +11,7 @@ import mindustry.mod.*; import mindustry.mod.Mods.*; import mindustry.net.Net; import mindustry.net.*; +import mindustry.ui.*; import java.time.*; @@ -45,11 +46,15 @@ public class ServerLauncher implements ApplicationListener{ Vars.loadSettings(); Vars.init(); + UI.loadColors(); + Fonts.loadContentIconsHeadless(); + content.createBaseContent(); mods.loadScripts(); content.createModContent(); content.init(); + if(mods.hasContentErrors()){ err("Error occurred loading mod content:"); for(LoadedMod mod : mods.list()){ From 2e96f598fb2a53dd5ec602b2736d1214dbc2c9d6 Mon Sep 17 00:00:00 2001 From: Tentyanuk <91948148+SSTentacleSS@users.noreply.github.com> Date: Mon, 29 May 2023 21:01:55 +0300 Subject: [PATCH 0074/1150] Update servers_v7.json (#8651) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 176e779a0f..620784c07c 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -175,7 +175,7 @@ { "name": "Realm of Serene Lime", "address": ["43.248.185.167:8517","n2.akiracloud.net:10686"] - } + }, { "name": "CreateDustry", "address": ["116.202.83.83:25689"] From b6f5d424da757cac9b6287121cbdd7ea6be2703a Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 30 May 2023 20:08:48 -0400 Subject: [PATCH 0075/1150] Select command from reconstructor / Units save command when controlled --- .../mindustry/annotations/Annotations.java | 8 +++ .../annotations/entity/EntityIO.java | 3 +- .../annotations/entity/EntityProcess.java | 2 +- .../resources/revisions/PlayerComp/1.json | 1 + core/src/mindustry/ai/UnitCommand.java | 5 ++ .../mindustry/entities/comp/PlayerComp.java | 13 ++++ core/src/mindustry/io/TypeIO.java | 9 +-- .../world/blocks/units/Reconstructor.java | 71 ++++++++++++++++++- 8 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 annotations/src/main/resources/revisions/PlayerComp/1.json diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 9960f673eb..24b00c5f76 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -34,6 +34,14 @@ public class Annotations{ } + /** Indicates that a field should not be synced to clients (but may still be non-transient) */ + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.SOURCE) + public @interface NoSync{ + + } + + /** Indicates that a component field is imported from other components. This means it doesn't actually exist. */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.SOURCE) diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java b/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java index 7f817fe562..1d6e6a0aec 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityIO.java @@ -118,7 +118,7 @@ public class EntityIO{ } } - void writeSync(MethodSpec.Builder method, boolean write, Seq syncFields, Seq allFields) throws Exception{ + void writeSync(MethodSpec.Builder method, boolean write, Seq allFields) throws Exception{ this.method = method; this.write = write; @@ -138,6 +138,7 @@ public class EntityIO{ //add code for reading revision for(RevisionField field : rev.fields){ Svar var = allFields.find(s -> s.name().equals(field.name)); + if(var == null || var.has(NoSync.class)) continue; boolean sf = var.has(SyncField.class), sl = var.has(SyncLocal.class); if(sl) cont("if(!islocal)"); diff --git a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java index ba44aa5b9a..3fa62d8446 100644 --- a/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java +++ b/annotations/src/main/java/mindustry/annotations/entity/EntityProcess.java @@ -490,7 +490,7 @@ public class EntityProcess extends BaseProcessor{ //SPECIAL CASE: sync I/O code if((first.name().equals("readSync") || first.name().equals("writeSync"))){ - io.writeSync(mbuilder, first.name().equals("writeSync"), syncedFields, allFields); + io.writeSync(mbuilder, first.name().equals("writeSync"), allFields); } //SPECIAL CASE: sync I/O code for writing to/from a manual buffer diff --git a/annotations/src/main/resources/revisions/PlayerComp/1.json b/annotations/src/main/resources/revisions/PlayerComp/1.json new file mode 100644 index 0000000000..52d4a67cae --- /dev/null +++ b/annotations/src/main/resources/revisions/PlayerComp/1.json @@ -0,0 +1 @@ +{version:1,fields:[{name:admin,type:boolean},{name:boosting,type:boolean},{name:color,type:arc.graphics.Color},{name:lastCommand,type:mindustry.ai.UnitCommand},{name:mouseX,type:float},{name:mouseY,type:float},{name:name,type:java.lang.String},{name:shooting,type:boolean},{name:team,type:mindustry.game.Team},{name:typing,type:boolean},{name:unit,type:Unit},{name:x,type:float},{name:y,type:float}]} \ No newline at end of file diff --git a/core/src/mindustry/ai/UnitCommand.java b/core/src/mindustry/ai/UnitCommand.java index 79bf619a77..0cc864fd83 100644 --- a/core/src/mindustry/ai/UnitCommand.java +++ b/core/src/mindustry/ai/UnitCommand.java @@ -2,6 +2,7 @@ package mindustry.ai; import arc.*; import arc.func.*; +import arc.scene.style.*; import arc.struct.*; import mindustry.ai.types.*; import mindustry.entities.units.*; @@ -60,6 +61,10 @@ public class UnitCommand{ return Core.bundle.get("command." + name); } + public TextureRegionDrawable getIcon(){ + return Icon.icons.get(icon, Icon.cancel); + } + @Override public String toString(){ return "UnitCommand:" + name; diff --git a/core/src/mindustry/entities/comp/PlayerComp.java b/core/src/mindustry/entities/comp/PlayerComp.java index ec3c5749f3..a28a293c16 100644 --- a/core/src/mindustry/entities/comp/PlayerComp.java +++ b/core/src/mindustry/entities/comp/PlayerComp.java @@ -8,6 +8,8 @@ import arc.scene.ui.layout.*; import arc.util.*; import arc.util.pooling.*; import mindustry.*; +import mindustry.ai.*; +import mindustry.ai.types.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.units.*; @@ -36,6 +38,8 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra @ReadOnly Team team = Team.sharded; @SyncLocal boolean typing, shooting, boosting; @SyncLocal float mouseX, mouseY; + /** command the unit had before it was controlled. */ + @Nullable @NoSync UnitCommand lastCommand; boolean admin; String name = "frog"; Color color = new Color(); @@ -203,9 +207,18 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead."); if(this.unit == unit) return; + //save last command this unit had + if(unit.controller() instanceof CommandAI ai){ + lastCommand = ai.command; + } + if(this.unit != Nulls.unit){ //un-control the old unit this.unit.resetController(); + //restore last command issued before it was controlled + if(lastCommand != null && this.unit.controller() instanceof CommandAI ai){ + ai.command(lastCommand); + } } this.unit = unit; if(unit != Nulls.unit){ diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index a12c2f5f7d..8be6b0cf90 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -301,12 +301,13 @@ public class TypeIO{ return Nulls.unit; } - public static void writeCommand(Writes write, UnitCommand command){ - write.b(command.id); + public static void writeCommand(Writes write, @Nullable UnitCommand command){ + write.b(command == null ? 255 : command.id); } - public static UnitCommand readCommand(Reads read){ - return UnitCommand.all.get(read.ub()); + public static @Nullable UnitCommand readCommand(Reads read){ + int val = read.ub(); + return val == 255 ? null : UnitCommand.all.get(val); } public static void writeEntity(Writes write, Entityc entity){ diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index 52b2270b47..8ff7554706 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -1,13 +1,18 @@ package mindustry.world.blocks.units; import arc.*; +import arc.Graphics.*; +import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import arc.util.io.*; import mindustry.*; +import mindustry.ai.*; import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.units.*; @@ -35,6 +40,7 @@ public class Reconstructor extends UnitBlock{ regionRotated2 = 2; commandable = true; ambientSound = Sounds.respawning; + configurable = true; } @Override @@ -132,6 +138,7 @@ public class Reconstructor extends UnitBlock{ public class ReconstructorBuild extends UnitBuild{ public @Nullable Vec2 commandPos; + public @Nullable UnitCommand command; public float fraction(){ return progress / constructTime; @@ -157,6 +164,51 @@ public class Reconstructor extends UnitBlock{ return hasUpgrade(unit.type) && !upgrade(unit.type).isBanned(); } + public boolean canSetCommand(){ + var output = unit(); + return output != null && output.commands.length > 1; + } + + @Override + public Cursor getCursor(){ + return canSetCommand() ? super.getCursor() : SystemCursor.arrow; + } + + @Override + public boolean shouldShowConfigure(Player player){ + return canSetCommand(); + } + + @Override + public void buildConfiguration(Table table){ + var unit = unit(); + + if(unit == null){ + deselect(); + return; + } + + var group = new ButtonGroup(); + group.setMinCheckCount(0); + int i = 0, columns = 4; + + table.background(Styles.black6); + + var list = unit().commands; + for(var item : list){ + ImageButton button = table.button(item.getIcon(), Styles.clearNoneTogglei, 40f, () -> { + command = (command == item ? null : item); + deselect(); + }).tooltip(item.localized()).group(group).get(); + + button.update(() -> button.setChecked(command == item)); + + if(++i % columns == 0){ + table.row(); + } + } + } + @Override public boolean acceptPayload(Building source, Payload payload){ if(!(this.payload == null @@ -252,9 +304,17 @@ public class Reconstructor extends UnitBlock{ //upgrade the unit if(progress >= constructTime){ payload.unit = upgrade(payload.unit.type).create(payload.unit.team()); - if(commandPos != null && payload.unit.isCommandable()){ - payload.unit.command().commandPosition(commandPos); + + if(payload.unit.isCommandable()){ + if(commandPos != null){ + payload.unit.command().commandPosition(commandPos); + } + if(command != null){ + //this already checks if it is a valid command for the unit type + payload.unit.command().command(command); + } } + progress %= 1f; Effect.shake(2f, 3f, this); Fx.producesmoke.at(this); @@ -303,7 +363,7 @@ public class Reconstructor extends UnitBlock{ @Override public byte version(){ - return 2; + return 3; } @Override @@ -312,6 +372,7 @@ public class Reconstructor extends UnitBlock{ write.f(progress); TypeIO.writeVecNullable(write, commandPos); + TypeIO.writeCommand(write, command); } @Override @@ -325,6 +386,10 @@ public class Reconstructor extends UnitBlock{ if(revision >= 2){ commandPos = TypeIO.readVecNullable(read); } + + if(revision >= 3){ + command = TypeIO.readCommand(read); + } } } From 1a0edf80f11e45b0d33462b7a21f04d24b62cb51 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 30 May 2023 20:15:44 -0400 Subject: [PATCH 0076/1150] Bugfixes for reconstructor config --- .../mindustry/world/blocks/units/Reconstructor.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index 8ff7554706..0c8e13be02 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -41,6 +41,8 @@ public class Reconstructor extends UnitBlock{ commandable = true; ambientSound = Sounds.respawning; configurable = true; + config(UnitCommand.class, (ReconstructorBuild build, UnitCommand command) -> build.command = command); + configClear((ReconstructorBuild build) -> build.command = null); } @Override @@ -197,11 +199,11 @@ public class Reconstructor extends UnitBlock{ var list = unit().commands; for(var item : list){ ImageButton button = table.button(item.getIcon(), Styles.clearNoneTogglei, 40f, () -> { - command = (command == item ? null : item); + configure(item); deselect(); }).tooltip(item.localized()).group(group).get(); - button.update(() -> button.setChecked(command == item)); + button.update(() -> button.setChecked(command == item || (command == null && unit.defaultCommand == item))); if(++i % columns == 0){ table.row(); @@ -340,6 +342,11 @@ public class Reconstructor extends UnitBlock{ return constructing() && enabled; } + @Override + public Object config(){ + return command; + } + public UnitType unit(){ if(payload == null) return null; From 8e1e003ff2f1a1392c9319bc38cebb175361512e Mon Sep 17 00:00:00 2001 From: MEEPofFaith <54301439+MEEPofFaith@users.noreply.github.com> Date: Tue, 30 May 2023 19:51:07 -0700 Subject: [PATCH 0077/1150] Inversion option for payload router sorting (#8652) --- core/src/mindustry/world/blocks/payloads/PayloadRouter.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/mindustry/world/blocks/payloads/PayloadRouter.java b/core/src/mindustry/world/blocks/payloads/PayloadRouter.java index 6b10281279..20fbde8091 100644 --- a/core/src/mindustry/world/blocks/payloads/PayloadRouter.java +++ b/core/src/mindustry/world/blocks/payloads/PayloadRouter.java @@ -21,6 +21,8 @@ import mindustry.world.blocks.storage.*; import static mindustry.Vars.*; public class PayloadRouter extends PayloadConveyor{ + public boolean invert = false; + public @Load("@-over") TextureRegion overRegion; public PayloadRouter(String name){ @@ -130,6 +132,8 @@ public class PayloadRouter extends PayloadConveyor{ matches = sorted != null && (item instanceof BuildPayload build && build.block() == sorted) || (item instanceof UnitPayload unit && unit.unit.type == sorted); + + if(invert) matches = !matches; } @Override From 9d986e1e8d010e18083d26a826abe29737e2179e Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 31 May 2023 08:53:21 -0400 Subject: [PATCH 0078/1150] Fixed #8653 --- core/src/mindustry/world/blocks/liquid/Conduit.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/world/blocks/liquid/Conduit.java b/core/src/mindustry/world/blocks/liquid/Conduit.java index d73b6c9331..011662d43e 100644 --- a/core/src/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/mindustry/world/blocks/liquid/Conduit.java @@ -221,7 +221,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ public boolean acceptLiquid(Building source, Liquid liquid){ noSleep(); return (liquids.current() == liquid || liquids.currentAmount() < 0.2f) - && (tile == null || (source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); + && (tile == null || source == this || (source.relativeTo(tile.x, tile.y) + 2) % 4 != rotation); } @Override From 94caca680aad8d0b9a315cf6a1ff14da9efae6ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D1=80=D0=BA=D0=BD=D0=B5=D1=81=D1=81=233729?= <79508138+Darkness6030@users.noreply.github.com> Date: Thu, 1 Jun 2023 01:26:04 +0300 Subject: [PATCH 0079/1150] Make PlayerInfo map public (#8655) --- core/src/mindustry/net/Administration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index e5a75dd81d..a8b4a01307 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -26,8 +26,8 @@ public class Administration{ private boolean modified, loaded; - /** All player info. Maps UUIDs to info. This persists throughout restarts. Do not access directly. */ - private ObjectMap playerInfo = new ObjectMap<>(); + /** All player info. Maps UUIDs to info. This persists throughout restarts. Do not modify directly. */ + public ObjectMap playerInfo = new ObjectMap<>(); public Administration(){ load(); From bf51a01677866147ba7b31f926aa3771b9639a21 Mon Sep 17 00:00:00 2001 From: ulwepo <85295540+ulwepo@users.noreply.github.com> Date: Sat, 3 Jun 2023 00:11:54 +0900 Subject: [PATCH 0080/1150] Update servers_v7.json (#8656) thanks --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 620784c07c..042ebe60d0 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -134,7 +134,7 @@ }, { "name": "Sakura", - "address": ["160.16.207.141:22527", "160.16.207.141:23527", "160.16.207.141:24527", "160.16.207.141:25527", "160.16.207.141:26527", "160.16.207.141:27527", "160.16.207.141:28527"] + "address": ["160.16.207.141:20527", "160.16.207.141:21527", "160.16.207.141:22527", "160.16.207.141:23527", "160.16.207.141:24527", "160.16.207.141:25527", "160.16.207.141:26527", "160.16.207.141:27527", "160.16.207.141:28527", "160.16.207.141:29527"] }, { "name": "|RussianServers|[]", From c84ec75c53b6af68dd90fdceb6b185added7a68a Mon Sep 17 00:00:00 2001 From: JniTrRny <85090668+JniTrRny@users.noreply.github.com> Date: Fri, 2 Jun 2023 22:37:15 +0700 Subject: [PATCH 0081/1150] Improvements to the Schematics UI (#8605) * schematics UI improvements * better edit tags UI * visual tweaks * cleanup inline obsession cleanup again... another little bit of cleanup a little bit of cleanup minor cleanup --- core/assets/bundles/bundle.properties | 8 +- .../src/mindustry/editor/MapEditorDialog.java | 2 +- core/src/mindustry/editor/MapLoadDialog.java | 51 ++- core/src/mindustry/editor/WaveInfoDialog.java | 58 ++-- .../mindustry/maps/filters/FilterOption.java | 4 +- .../ui/dialogs/SchematicsDialog.java | 312 ++++++++++-------- .../mindustry/world/blocks/ItemSelection.java | 6 +- 7 files changed, 234 insertions(+), 207 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index c7f7921ae2..0ab09b4ec9 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -57,6 +57,7 @@ mods.browser.sortstars = Sort by stars schematic = Schematic schematic.add = Save Schematic... schematics = Schematics +schematic.search = Search schematics... schematic.replace = A schematic by that name already exists. Replace it? schematic.exists = A schematic by that name already exists. schematic.import = Import Schematic... @@ -69,7 +70,7 @@ schematic.shareworkshop = Share on Workshop schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Flip Schematic schematic.saved = Schematic saved. schematic.delete.confirm = This schematic will be utterly eradicated. -schematic.rename = Rename Schematic +schematic.edit = Edit Schematic schematic.info = {0}x{1}, {2} blocks schematic.disabled = [scarlet]Schematics disabled[]\nYou are not allowed to use schematics on this [accent]map[] or [accent]server. schematic.tags = Tags: @@ -78,6 +79,7 @@ schematic.addtag = Add Tag schematic.texttag = Text Tag schematic.icontag = Icon Tag schematic.renametag = Rename Tag +schematic.tagged = {0} tagged schematic.tagdelconfirm = Delete this tag completely? schematic.tagexists = That tag already exists. @@ -463,7 +465,7 @@ waves.sort.begin = Begin waves.sort.health = Health waves.sort.type = Type waves.search = Search waves... -waves.filter.unit = Unit Filter +waves.filter = Unit Filter waves.units.hide = Hide All waves.units.show = Show All @@ -1791,7 +1793,7 @@ hint.launch = Once enough resources are collected, you can [accent]Launch[] by s hint.launch.mobile = Once enough resources are collected, you can [accent]Launch[] by selecting nearby sectors from the \uE827 [accent]Map[] in the \uE88C [accent]Menu[]. hint.schematicSelect = Hold [accent][[F][] and drag to select blocks to copy and paste.\n\n[accent][[Middle Click][] to copy a single block type. hint.rebuildSelect = Hold [accent][[B][] and drag to select destroyed block plans.\nThis will rebuild them automatically. -hint.rebuildSelect.mobile = Select the \ue874 copy button, then tap the \ue80f rebuild button and drag to select destroyed block plans.\nThis will rebuild them automatically. +hint.rebuildSelect.mobile = Select the \uE874 copy button, then tap the \uE80F rebuild button and drag to select destroyed block plans.\nThis will rebuild them automatically. hint.conveyorPathfind = Hold [accent][[L-Ctrl][] while dragging conveyors to automatically generate a path. hint.conveyorPathfind.mobile = Enable \uE844 [accent]diagonal mode[] and drag conveyors to automatically generate a path. hint.boost = Hold [accent][[L-Shift][] to fly over obstacles with your current unit.\n\nOnly a few ground units have boosters. diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 1d30d18d82..0010346f9a 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -803,7 +803,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ } if(i == 0){ - blockSelection.add("@none.found").color(Color.lightGray).padLeft(54f).padTop(10f); + blockSelection.add("@none.found").padLeft(54f).padTop(10f); } } } diff --git a/core/src/mindustry/editor/MapLoadDialog.java b/core/src/mindustry/editor/MapLoadDialog.java index 1217c87020..46b98e037d 100644 --- a/core/src/mindustry/editor/MapLoadDialog.java +++ b/core/src/mindustry/editor/MapLoadDialog.java @@ -1,9 +1,11 @@ package mindustry.editor; +import arc.*; import arc.func.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; +import mindustry.gen.*; import mindustry.maps.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; @@ -11,65 +13,60 @@ import mindustry.ui.dialogs.*; import static mindustry.Vars.*; public class MapLoadDialog extends BaseDialog{ - private Map selected = null; + private @Nullable Map selected = null; public MapLoadDialog(Cons loader){ super("@editor.loadmap"); shown(this::rebuild); + hidden(() -> selected = null); + onResize(this::rebuild); - TextButton button = new TextButton("@load"); - button.setDisabled(() -> selected == null); - button.clicked(() -> { + buttons.defaults().size(210f, 64f); + buttons.button("@cancel", Icon.cancel, this::hide); + buttons.button("@load", Icon.ok, () -> { if(selected != null){ loader.get(selected); hide(); } - }); - - buttons.defaults().size(200f, 50f); - buttons.button("@cancel", this::hide); - buttons.add(button); + }).disabled(b -> selected == null); addCloseListener(); + makeButtonOverlay(); } public void rebuild(){ cont.clear(); - if(maps.all().size > 0){ - selected = maps.all().first(); - } - - ButtonGroup group = new ButtonGroup<>(); - - int maxcol = 3; + ButtonGroup