From ba48373bbc1400e98e9ef5ca7dd928500e36b89c Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Aug 2021 16:39:20 -0400 Subject: [PATCH 01/13] Game stats cleanup --- core/assets/bundles/bundle.properties | 3 +- core/assets/sounds/wind3.ogg | Bin 0 -> 38775 bytes core/src/mindustry/core/Control.java | 10 ++++- .../entities/abilities/UnitSpawnAbility.java | 2 + core/src/mindustry/game/EventType.java | 12 ++++-- core/src/mindustry/game/GameStats.java | 40 +----------------- .../mindustry/ui/dialogs/GameOverDialog.java | 13 +----- .../world/blocks/power/PowerNode.java | 6 ++- gradle.properties | 2 +- 9 files changed, 28 insertions(+), 60 deletions(-) create mode 100644 core/assets/sounds/wind3.ogg diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 53e361382b..b2e221af25 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -78,13 +78,12 @@ schematic.tagexists = That tag already exists. stats = Stats stat.wave = Waves Defeated:[accent] {0} +stat.unitsCreated = Units Created:[accent] {0} stat.enemiesDestroyed = Enemies Destroyed:[accent] {0} stat.built = Buildings Built:[accent] {0} stat.destroyed = Buildings Destroyed:[accent] {0} stat.deconstructed = Buildings Deconstructed:[accent] {0} -stat.delivered = Resources Launched: stat.playtime = Time Played:[accent] {0} -stat.rank = Final Rank: [accent]{0} globalitems = [accent]Total Items map.delete = Are you sure you want to delete the map "[accent]{0}[]"? diff --git a/core/assets/sounds/wind3.ogg b/core/assets/sounds/wind3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..35e732725bfe2186ed8b883ca59ea82406dfdb6e GIT binary patch literal 38775 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 { if(e.tile.team() == player.team()){ - state.stats.buildingsDestroyed++; + state.stats.buildingsDestroyed ++; } }); Events.on(UnitDestroyEvent.class, e -> { if(e.unit.team() != player.team()){ - state.stats.enemyUnitsDestroyed++; + state.stats.enemyUnitsDestroyed ++; + } + }); + + Events.on(UnitCreateEvent.class, e -> { + if(e.unit.team == state.rules.defaultTeam){ + state.stats.unitsCreated++; } }); diff --git a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java index c3f826e5a5..04be58be39 100644 --- a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java +++ b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java @@ -7,6 +7,7 @@ import arc.util.*; import mindustry.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -40,6 +41,7 @@ public class UnitSpawnAbility extends Ability{ Unit u = this.unit.create(unit.team); u.set(x, y); u.rotation = unit.rotation; + Events.fire(new UnitCreateEvent(u, null, unit)); if(!Vars.net.client()){ u.add(); } diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 5ff6a6f264..c72ffc403c 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -411,14 +411,20 @@ public class EventType{ } } - /** Called when a unit is created in a reconstructor or factory. */ + /** Called when a unit is created in a reconstructor, factory or other unit. */ public static class UnitCreateEvent{ public final Unit unit; - public final Building spawner; + public final @Nullable Building spawner; + public final @Nullable Unit spawnerUnit; - public UnitCreateEvent(Unit unit, Building spawner){ + public UnitCreateEvent(Unit unit, Building spawner, Unit spawnerUnit){ this.unit = unit; this.spawner = spawner; + this.spawnerUnit = spawnerUnit; + } + + public UnitCreateEvent(Unit unit, Building spawner){ + this(unit, spawner, null); } } diff --git a/core/src/mindustry/game/GameStats.java b/core/src/mindustry/game/GameStats.java index 19d404c802..5b54385e32 100644 --- a/core/src/mindustry/game/GameStats.java +++ b/core/src/mindustry/game/GameStats.java @@ -1,52 +1,16 @@ package mindustry.game; -import arc.math.*; -import arc.struct.*; -import mindustry.type.*; - -//TODO more stats: -//- units constructed public class GameStats{ - /** Total items delivered to global resoure counter. Campaign only. */ - public ObjectIntMap itemsDelivered = new ObjectIntMap<>(); /** Enemy (red team) units destroyed. */ public int enemyUnitsDestroyed; /** Total waves lasted. */ public int wavesLasted; - /** Total (ms) time lasted in this save/zone. */ - public long timeLasted; /** Friendly buildings fully built. */ public int buildingsBuilt; /** Friendly buildings fully deconstructed. */ public int buildingsDeconstructed; /** Friendly buildings destroyed. */ public int buildingsDestroyed; - - //unused - public RankResult calculateRank(Sector sector){ - float score = 0; - - int rankIndex = Mathf.clamp((int)score, 0, Rank.all.length - 1); - Rank rank = Rank.all[rankIndex]; - String sign = Math.abs((rankIndex + 0.5f) - score) < 0.2f || rank.name().contains("S") ? "" : (rankIndex + 0.5f) < score ? "-" : "+"; - - return new RankResult(rank, sign); - } - - public static class RankResult{ - public final Rank rank; - /** + or - */ - public final String modifier; - - public RankResult(Rank rank, String modifier){ - this.rank = rank; - this.modifier = modifier; - } - } - - public enum Rank{ - F, D, C, B, A, S, SS; - - public static final Rank[] all = values(); - } + /** Total units created by any means. */ + public int unitsCreated; } diff --git a/core/src/mindustry/ui/dialogs/GameOverDialog.java b/core/src/mindustry/ui/dialogs/GameOverDialog.java index 32e593ea0e..8ab6054b6b 100644 --- a/core/src/mindustry/ui/dialogs/GameOverDialog.java +++ b/core/src/mindustry/ui/dialogs/GameOverDialog.java @@ -4,7 +4,6 @@ import arc.*; import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.type.*; import static mindustry.Vars.*; @@ -52,6 +51,7 @@ public class GameOverDialog extends BaseDialog{ t.margin(13f); t.left().defaults().left(); t.add(Core.bundle.format("stat.wave", state.stats.wavesLasted)).row(); + t.add(Core.bundle.format("stat.unitsCreated", state.stats.unitsCreated)).row(); t.add(Core.bundle.format("stat.enemiesDestroyed", state.stats.enemyUnitsDestroyed)).row(); t.add(Core.bundle.format("stat.built", state.stats.buildingsBuilt)).row(); t.add(Core.bundle.format("stat.destroyed", state.stats.buildingsDestroyed)).row(); @@ -59,17 +59,6 @@ public class GameOverDialog extends BaseDialog{ if(control.saves.getCurrent() != null){ t.add(Core.bundle.format("stat.playtime", control.saves.getCurrent().getPlayTime())).row(); } - if(state.isCampaign() && !state.stats.itemsDelivered.isEmpty()){ - t.add("@stat.delivered").row(); - for(Item item : content.items()){ - if(state.stats.itemsDelivered.get(item, 0) > 0){ - t.table(items -> { - items.add(" [lightgray]" + state.stats.itemsDelivered.get(item, 0)); - items.image(item.uiIcon).size(8 * 3).pad(4); - }).left().row(); - } - } - } if(state.isCampaign() && net.client()){ t.add("@gameover.waiting").padTop(20f).row(); diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 7ced9f8052..f9fb216592 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -108,13 +108,15 @@ public class PowerNode extends PowerBlock{ Core.bundle.format("bar.powerbalance", ((entity.power.graph.getPowerBalance() >= 0 ? "+" : "") + UI.formatAmount((long)(entity.power.graph.getPowerBalance() * 60)))), () -> Pal.powerBar, - () -> Mathf.clamp(entity.power.graph.getLastPowerProduced() / entity.power.graph.getLastPowerNeeded()))); + () -> Mathf.clamp(entity.power.graph.getLastPowerProduced() / entity.power.graph.getLastPowerNeeded()) + )); bars.add("batteries", entity -> new Bar(() -> Core.bundle.format("bar.powerstored", (UI.formatAmount((long)entity.power.graph.getLastPowerStored())), UI.formatAmount((long)entity.power.graph.getLastCapacity())), () -> Pal.powerBar, - () -> Mathf.clamp(entity.power.graph.getLastPowerStored() / entity.power.graph.getLastCapacity()))); + () -> Mathf.clamp(entity.power.graph.getLastPowerStored() / entity.power.graph.getLastCapacity()) + )); bars.add("connections", entity -> new Bar(() -> Core.bundle.format("bar.powerlines", entity.power.links.size, maxNodes), diff --git a/gradle.properties b/gradle.properties index fa7fb4b746..9ff216de0d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works http.socketTimeout=80000 http.connectionTimeout=80000 -archash=d9eb4aa5b85f51c87f2e5e78cea4043e65bd29f0 +archash=96dbecb52d98b54550bda3d6bb33c69d24884c08 From a94735c5a5a1f1e0765cddc1532944806e0a4436 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Aug 2021 17:52:02 -0400 Subject: [PATCH 02/13] Remote unlock tweaks --- core/src/mindustry/ctype/UnlockableContent.java | 12 ++++++++++-- core/src/mindustry/world/blocks/ConstructBlock.java | 2 +- .../mindustry/world/blocks/units/Reconstructor.java | 8 ++++---- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index b557bbaf89..c45f076061 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -149,9 +149,17 @@ public abstract class UnlockableContent extends MappableContent{ } } + public boolean unlockedNowHost(){ + if(!state.isCampaign()) return true; + return net != null && net.client() ? + alwaysUnlocked || state.rules.researched.contains(name) : + unlocked || alwaysUnlocked; + } + public boolean unlocked(){ - if(net != null && net.client()) return alwaysUnlocked || state.rules.researched.contains(name); - return unlocked || alwaysUnlocked; + return net != null && net.client() ? + alwaysUnlocked || unlocked || state.rules.researched.contains(name) : + unlocked || alwaysUnlocked; } /** Locks this content again. */ diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index 63f66a9afa..9113a840a1 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -302,7 +302,7 @@ public class ConstructBlock extends Block{ int accumulated = (int)(accumulator[i]); //get amount if(clampedAmount > 0 && accumulated > 0){ //if it's positive, add it to the core - if(core != null && requirements[i].item.unlockedNow()){ //only accept items that are unlocked + if(core != null && requirements[i].item.unlockedNowHost()){ //only accept items that are unlocked int accepting = Math.min(accumulated, core.storageCapacity - core.items.get(requirements[i].item)); //transfer items directly, as this is not production. core.items.add(requirements[i].item, accepting); diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index b8ee614f50..0d84db2fb5 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -126,7 +126,7 @@ public class Reconstructor extends UnitBlock{ var upgrade = upgrade(pay.unit.type); if(upgrade != null){ - if(!upgrade.unlockedNow()){ + if(!upgrade.unlockedNowHost()){ //flash "not researched" pay.showOverlay(Icon.tree); } @@ -137,7 +137,7 @@ public class Reconstructor extends UnitBlock{ } } - return upgrade != null && upgrade.unlockedNow() && !upgrade.isBanned(); + return upgrade != null && upgrade.unlockedNowHost() && !upgrade.isBanned(); } @Override @@ -232,7 +232,7 @@ public class Reconstructor extends UnitBlock{ if(payload == null) return null; UnitType t = upgrade(payload.unit.type); - return t != null && t.unlockedNow() ? t : null; + return t != null && t.unlockedNowHost() ? t : null; } public boolean constructing(){ @@ -241,7 +241,7 @@ public class Reconstructor extends UnitBlock{ public boolean hasUpgrade(UnitType type){ UnitType t = upgrade(type); - return t != null && t.unlockedNow() && !type.isBanned(); + return t != null && t.unlockedNowHost() && !type.isBanned(); } public UnitType upgrade(UnitType type){ From b8eaabe0deec1430643c6a65b782eed5d5d0c84d Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Aug 2021 18:55:36 -0400 Subject: [PATCH 03/13] Fixed #5802 --- core/src/mindustry/world/blocks/sandbox/PowerVoid.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java index 93427b7e02..15fb0ac574 100644 --- a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java +++ b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java @@ -9,6 +9,7 @@ public class PowerVoid extends PowerBlock{ super(name); consumes.power(Float.MAX_VALUE); envEnabled = Env.any; + enableDrawStatus = false; } @Override From 41829b86606fd1e866e9491085163ed6f4898b3f Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 18 Aug 2021 20:10:14 -0400 Subject: [PATCH 04/13] Fixed #5803 --- core/src/mindustry/world/consumers/ConsumeItemFilter.java | 1 - gradle.properties | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/mindustry/world/consumers/ConsumeItemFilter.java index b4346d0c6e..bc81cc9201 100644 --- a/core/src/mindustry/world/consumers/ConsumeItemFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeItemFilter.java @@ -43,7 +43,6 @@ public class ConsumeItemFilter extends Consume{ @Override public void update(Building entity){ - } @Override diff --git a/gradle.properties b/gradle.properties index 9ff216de0d..5bd4e7119e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works http.socketTimeout=80000 http.connectionTimeout=80000 -archash=96dbecb52d98b54550bda3d6bb33c69d24884c08 +archash=4410a18d881622cb655c9d48e4cb0ff2ec40782f From 558ee579e1d7ac7c3126c7ca7a164e4fc92f59bd Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 09:37:12 -0400 Subject: [PATCH 05/13] BlockIndexer null team fix --- core/src/mindustry/ai/BlockIndexer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index f91aa89e11..519720e4ac 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -202,15 +202,20 @@ public class BlockIndexer{ } public boolean eachBlock(@Nullable Team team, float wx, float wy, float range, Boolf pred, Cons cons){ - breturnArray.clear(); if(team == null){ + returnBool = false; + allBuildings(wx, wy, range, b -> { if(pred.get(b)){ - breturnArray.add(b); + returnBool = true; + cons.get(b); } }); + return returnBool; }else{ + breturnArray.clear(); + var buildings = team.data().buildings; if(buildings == null) return false; buildings.intersect(wx - range, wy - range, range*2f, range*2f, b -> { From a4bd160995227f19206443711cdd6021ea31accf Mon Sep 17 00:00:00 2001 From: Volas171 <60143910+Volas171@users.noreply.github.com> Date: Thu, 19 Aug 2021 09:43:58 -0500 Subject: [PATCH 06/13] omegahub ip change (last) (#5807) --- servers_v7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/servers_v7.json b/servers_v7.json index 0f33a7c392..8b26864eb3 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -13,7 +13,7 @@ }, { "name": "Omega", - "address": ["yeet.mindustry.me:2345", "yeet.mindustry.me:2076", "yeet.mindustry.me:2222","yeet.mindustry.me:6567", "yeet.mindustry.me:2054", "yeet.mindustry.me:3512"] + "address": ["yeet.mindustry.me:6567", "yeet.mindustry.me:2345", "n3.mindustry.me:4444","n2.mindustry.me:4040", "n2.mindustry.me:4002", "n2.mindustry.me:4001"] }, { "name": "MeowLand", From a8b423836eaf654511c85510130352f054dd89fa Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 14:20:18 -0400 Subject: [PATCH 07/13] Added unit decal system for mods/future units --- .../mindustry/entities/units/UnitDecal.java | 25 +++++++++++++++++++ core/src/mindustry/type/UnitType.java | 15 +++++++++++ .../mindustry/ui/dialogs/PlanetDialog.java | 3 ++- 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 core/src/mindustry/entities/units/UnitDecal.java diff --git a/core/src/mindustry/entities/units/UnitDecal.java b/core/src/mindustry/entities/units/UnitDecal.java new file mode 100644 index 0000000000..62a12e3c29 --- /dev/null +++ b/core/src/mindustry/entities/units/UnitDecal.java @@ -0,0 +1,25 @@ +package mindustry.entities.units; + +import arc.graphics.*; +import mindustry.graphics.*; + +/** A sprite drawn in addition to the base unit sprites. */ +public class UnitDecal{ + public String region = "error"; + public float x, y, rotation; + public float layer = Layer.flyingUnit + 1f; + public float xScale = 1f, yScale = 1f; + public Color color = Color.white; + + public UnitDecal(String region, float x, float y, float rotation, float layer, Color color){ + this.region = region; + this.x = x; + this.y = y; + this.rotation = rotation; + this.layer = layer; + this.color = color; + } + + public UnitDecal(){ + } +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index af06cc2087..1ee3c7a345 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -77,6 +77,8 @@ public class UnitType extends UnlockableContent{ public Effect fallEffect = Fx.fallSmoke; public Effect fallThrusterEffect = Fx.fallSmoke; public Effect deathExplosionEffect = Fx.dynamicExplosion; + /** Additional sprites that are drawn with the unit. */ + public Seq decals = new Seq<>(); public Seq abilities = new Seq<>(); /** Flags to target based on priority. Null indicates that the closest target should be found. The closest enemy core is used as a fallback. */ public BlockFlag[] targetFlags = {null}; @@ -565,6 +567,18 @@ public class UnitType extends UnlockableContent{ unit.trns(-legOffset.x, -legOffset.y); } + if(decals.size > 0){ + float base = unit.rotation - 90; + for(var d : decals){ + Draw.z(d.layer); + Draw.scl(d.xScale, d.yScale); + Draw.color(d.color); + Draw.rect(d.region, unit.x + Angles.trnsx(base, d.x, d.y), unit.y + Angles.trnsy(base, d.x, d.y), base + d.rotation); + } + Draw.reset(); + Draw.z(z); + } + if(unit.abilities.size > 0){ for(Ability a : unit.abilities){ Draw.reset(); @@ -849,4 +863,5 @@ public class UnitType extends UnlockableContent{ } //endregion + } diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 91a1dcf9da..cc105257d3 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -537,7 +537,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ //sector notifications & search c.top().right(); - c.defaults().width(280f); + c.defaults().width(290f); c.button(bundle.get("sectorlist") + (attacked == 0 ? "" : "\n[red]⚠[lightgray] " + bundle.format("sectorlist.attacked", "[red]" + attacked + "[]")), @@ -585,6 +585,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ for(Sector sec : all){ if(sec.hasBase() && (searchText.isEmpty() || sec.name().toLowerCase().contains(searchText.toLowerCase()))){ con.button(t -> { + t.marginRight(10f); t.left(); t.defaults().growX(); From e23054d6064f695f4c62959d5fb515bcc30025da Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 16:29:49 -0400 Subject: [PATCH 08/13] Better support for disabling omniMovement --- core/src/mindustry/ai/types/GroundAI.java | 10 +--------- core/src/mindustry/ai/types/HugAI.java | 13 +++---------- core/src/mindustry/ai/types/SuicideAI.java | 10 +++------- .../src/mindustry/entities/comp/MechComp.java | 11 +++++++++++ .../src/mindustry/entities/comp/UnitComp.java | 9 +++++++++ .../entities/units/AIController.java | 19 ++++++++++++++++++- core/src/mindustry/input/DesktopInput.java | 6 +----- core/src/mindustry/input/MobileInput.java | 6 +----- 8 files changed, 47 insertions(+), 37 deletions(-) diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java index 4ebdfe1595..05358ae5e8 100644 --- a/core/src/mindustry/ai/types/GroundAI.java +++ b/core/src/mindustry/ai/types/GroundAI.java @@ -2,7 +2,6 @@ package mindustry.ai.types; import arc.math.*; import mindustry.ai.*; -import mindustry.entities.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.world.*; @@ -49,13 +48,6 @@ public class GroundAI extends AIController{ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, unit.type.riseSpeed); } - if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){ - if(unit.type.hasWeapons()){ - unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - }else if(unit.moving()){ - unit.lookAt(unit.vel().angle()); - } - + faceTarget(); } } diff --git a/core/src/mindustry/ai/types/HugAI.java b/core/src/mindustry/ai/types/HugAI.java index 76acdec8c8..70d2bce36e 100644 --- a/core/src/mindustry/ai/types/HugAI.java +++ b/core/src/mindustry/ai/types/HugAI.java @@ -47,10 +47,10 @@ public class HugAI extends AIController{ })){ if(unit.within(target, (unit.hitSize + (target instanceof Sized s ? s.hitSize() : 1f)) * 0.6f)){ //circle target - unit.moveAt(vec.set(target).sub(unit).rotate(90f).setLength(unit.speed())); + unit.movePref(vec.set(target).sub(unit).rotate(90f).setLength(unit.speed())); }else{ //move toward target in a straight line - unit.moveAt(vec.set(target).sub(unit).limit(unit.speed())); + unit.movePref(vec.set(target).sub(unit).limit(unit.speed())); } }else if(move){ pathfind(Pathfinder.fieldCore); @@ -69,13 +69,6 @@ public class HugAI extends AIController{ unit.elevation = Mathf.approachDelta(unit.elevation, 0f, unit.type.riseSpeed); } - if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){ - if(unit.type.hasWeapons()){ - unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - }else if(unit.moving()){ - unit.lookAt(unit.vel().angle()); - } - + faceTarget(); } } diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java index 1db94b95b0..70e365e775 100644 --- a/core/src/mindustry/ai/types/SuicideAI.java +++ b/core/src/mindustry/ai/types/SuicideAI.java @@ -41,10 +41,6 @@ public class SuicideAI extends GroundAI{ shoot = unit.within(target, unit.type.weapons.first().bullet.range() + (target instanceof Building b ? b.block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f)); - if(unit.type.hasWeapons()){ - unit.aimLook(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); - } - //do not move toward walls or transport blocks if(!(target instanceof Building build && !(build.block instanceof CoreBlock) && ( build.block.group == BlockGroup.walls || @@ -76,7 +72,7 @@ public class SuicideAI extends GroundAI{ if(!blocked){ moveToTarget = true; //move towards target directly - unit.moveAt(vec.set(target).sub(unit).limit(unit.speed())); + unit.movePref(vec.set(target).sub(unit).limit(unit.speed())); } } } @@ -103,11 +99,11 @@ public class SuicideAI extends GroundAI{ pathfind(Pathfinder.fieldCore); } } - - if(unit.moving()) unit.lookAt(unit.vel().angle()); } unit.controlWeapons(rotate, shoot); + + faceTarget(); } @Override diff --git a/core/src/mindustry/entities/comp/MechComp.java b/core/src/mindustry/entities/comp/MechComp.java index e8ed72974d..bd822d523b 100644 --- a/core/src/mindustry/entities/comp/MechComp.java +++ b/core/src/mindustry/entities/comp/MechComp.java @@ -76,6 +76,17 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati return raw; } + @Override + @Replace + public void rotateMove(Vec2 vec){ + //mechs use baseRotation to rotate, not rotation. + moveAt(Tmp.v2.trns(baseRotation, vec.len())); + + if(!vec.isZero()){ + baseRotation = Angles.moveToward(baseRotation, vec.angle(), type.rotateSpeed * Math.max(Time.delta, 1)); + } + } + @Override public void moveAt(Vec2 vector, float acceleration){ //mark walking state when moving in a controlled manner diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index ae4001d25f..ca168362d2 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -51,6 +51,15 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I private transient boolean wasPlayer; private transient boolean wasHealed; + /** Move based on preferred unit movement type. */ + public void movePref(Vec2 movement){ + if(type.omniMovement){ + moveAt(movement); + }else{ + rotateMove(movement); + } + } + public void moveAt(Vec2 vector){ moveAt(vector, type.accel); } diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java index 583691adaa..c06fe06d88 100644 --- a/core/src/mindustry/entities/units/AIController.java +++ b/core/src/mindustry/entities/units/AIController.java @@ -76,6 +76,23 @@ public class AIController implements UnitController{ } } + /** For ground units: Looks at the target, or the movement position. Does not apply to non-omni units. */ + public void faceTarget(){ + if(unit.type.omniMovement || unit instanceof Mechc){ + if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting && unit.type.hasWeapons()){ + unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed)); + }else if(unit.moving()){ + unit.lookAt(unit.vel().angle()); + } + } + } + + public void faceMovement(){ + if((unit.type.omniMovement || unit instanceof Mechc) && unit.moving()){ + unit.lookAt(unit.vel().angle()); + } + } + public boolean invalid(Teamc target){ return Units.invalidateTarget(target, unit.team, unit.x, unit.y); } @@ -89,7 +106,7 @@ public class AIController implements UnitController{ if(tile == targetTile || (costType == Pathfinder.costNaval && !targetTile.floor().isLiquid)) return; - unit.moveAt(vec.trns(unit.angleTo(targetTile.worldx(), targetTile.worldy()), unit.speed())); + unit.movePref(vec.trns(unit.angleTo(targetTile.worldx(), targetTile.worldy()), unit.speed())); } public void updateWeapons(){ diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index acb3795aff..6c247c50cf 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -642,11 +642,7 @@ public class DesktopInput extends InputHandler{ unit.lookAt(unit.prefRotation()); } - if(omni){ - unit.moveAt(movement); - }else{ - unit.rotateMove(movement); - } + unit.movePref(movement); unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y)); unit.controlWeapons(true, player.shooting && !boosted); diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 2480cad5ab..be0de31ffa 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -919,11 +919,7 @@ public class MobileInput extends InputHandler implements GestureListener{ player.boosting = collisions.overlapsTile(rect) || !unit.within(targetPos, 85f); - if(omni){ - unit.moveAt(movement); - }else{ - unit.rotateMove(movement); - } + unit.movePref(movement); //update shooting if not building + not mining if(!player.unit().activelyBuilding() && player.unit().mineTile == null){ From 4b140080806ae9abc1794a6f05554306e836635d Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 17:50:31 -0400 Subject: [PATCH 09/13] Fixed #5812 --- core/src/mindustry/ui/dialogs/SettingsMenuDialog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index 8efa0f740e..66ec8f64d7 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -301,6 +301,8 @@ public class SettingsMenuDialog extends Dialog{ control.setInput(new DesktopInput()); input.setUseKeyboard(true); } + }else{ + Core.settings.put("keyboard", false); } } //the issue with touchscreen support on desktop is that: From 0ab5f5bb14bbaae78931bcc6504729baca814c11 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 21:29:50 -0400 Subject: [PATCH 10/13] hide hidden units in menu --- core/src/mindustry/graphics/MenuRenderer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 1cd431c7e8..57f435e945 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -29,7 +29,7 @@ public class MenuRenderer implements Disposable{ private float time = 0f; private float flyerRot = 45f; private int flyers = Mathf.chance(0.2) ? Mathf.random(35) : Mathf.random(15); - private UnitType flyerType = content.units().select(u -> u.hitSize <= 20f && u.flying && u.onTitleScreen && u.region.found()).random(); + private UnitType flyerType = content.units().select(u -> !u.isHidden() && u.hitSize <= 20f && u.flying && u.onTitleScreen && u.region.found()).random(); public MenuRenderer(){ Time.mark(); From 5d4ab9ecd7d60d98e847d0529c32816cdb73f365 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 23:26:39 -0400 Subject: [PATCH 11/13] Added max units field for wave editor --- core/assets/bundles/bundle.properties | 1 + .../src/mindustry/editor/MapResizeDialog.java | 2 ++ core/src/mindustry/editor/WaveInfoDialog.java | 29 ++++++++++++------- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index b2e221af25..750ba063be 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -384,6 +384,7 @@ waves.waves = wave(s) waves.perspawn = per spawn waves.shields = shields/wave waves.to = to +waves.max = max units waves.guardian = Guardian waves.preview = Preview waves.edit = Edit... diff --git a/core/src/mindustry/editor/MapResizeDialog.java b/core/src/mindustry/editor/MapResizeDialog.java index fe3e6eda06..b9925e14dc 100644 --- a/core/src/mindustry/editor/MapResizeDialog.java +++ b/core/src/mindustry/editor/MapResizeDialog.java @@ -15,6 +15,8 @@ public class MapResizeDialog extends BaseDialog{ public MapResizeDialog(Intc2 cons){ super("@editor.resizemap"); + + closeOnBack(); shown(() -> { cont.clear(); width = editor.width(); diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java index 3d1307b9d0..15049f7381 100644 --- a/core/src/mindustry/editor/WaveInfoDialog.java +++ b/core/src/mindustry/editor/WaveInfoDialog.java @@ -14,7 +14,6 @@ import mindustry.gen.*; import mindustry.graphics.*; import mindustry.io.*; import mindustry.type.*; -import mindustry.ui.*; import mindustry.ui.dialogs.*; import static mindustry.Vars.*; @@ -171,9 +170,8 @@ public class WaveInfoDialog extends BaseDialog{ t.remove(); updateWaves(); }).pad(-6).size(46f).padRight(-12f); - }, () -> showUpdate(group)).height(46f).pad(-6f).padBottom(0f); + }, () -> showUpdate(group)).height(46f).pad(-6f).padBottom(0f).row(); - t.row(); t.table(spawns -> { spawns.field("" + (group.begin + 1), TextFieldFilter.digitsOnly, text -> { if(Strings.canParsePositiveInt(text)){ @@ -191,8 +189,8 @@ public class WaveInfoDialog extends BaseDialog{ updateWaves(); } }).width(100f).get().setMessageText("∞"); - }); - t.row(); + }).row(); + t.table(p -> { p.add("@waves.every").padRight(4); p.field(group.spacing + "", TextFieldFilter.digitsOnly, text -> { @@ -202,9 +200,8 @@ public class WaveInfoDialog extends BaseDialog{ } }).width(100f); p.add("@waves.waves").padLeft(4); - }); + }).row(); - t.row(); t.table(a -> { a.field(group.unitAmount + "", TextFieldFilter.digitsOnly, text -> { if(Strings.canParsePositiveInt(text)){ @@ -221,8 +218,19 @@ public class WaveInfoDialog extends BaseDialog{ } }).width(80f); a.add("@waves.perspawn").padLeft(4); - }); - t.row(); + }).row(); + + t.table(a -> { + a.field(group.max + "", TextFieldFilter.digitsOnly, text -> { + if(Strings.canParsePositiveInt(text)){ + group.max = Strings.parseInt(text); + updateWaves(); + } + }).width(80f); + + a.add("@waves.max").padLeft(5); + }).row(); + t.table(a -> { a.field((int)group.shields + "", TextFieldFilter.digitsOnly, text -> { if(Strings.canParsePositiveInt(text)){ @@ -239,9 +247,8 @@ public class WaveInfoDialog extends BaseDialog{ } }).width(80f); a.add("@waves.shields").padLeft(4); - }); + }).row(); - t.row(); t.check("@waves.guardian", b -> group.effect = (b ? StatusEffects.boss : null)).padTop(4).update(b -> b.setChecked(group.effect == StatusEffects.boss)).padBottom(8f); }).width(340f).pad(8); From 38ec05807a89d3a09166b5638ae5092f9cf97f9e Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 23:32:21 -0400 Subject: [PATCH 12/13] Disallow logic-building invalid blocks --- core/src/mindustry/logic/LExecutor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index c2b3fac347..f9ac8c2f05 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -447,7 +447,7 @@ public class LExecutor{ } } case build -> { - if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block){ + if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block && block.canBeBuilt()){ int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize); int rot = exec.numi(p4); From 3a3622bb589feba27b2f15f678d805a003e8c05f Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Aug 2021 23:42:27 -0400 Subject: [PATCH 13/13] Boss status color fix --- core/src/mindustry/content/StatusEffects.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 710995d4a1..0a93c2103c 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -164,7 +164,7 @@ public class StatusEffects implements ContentList{ }}; boss = new StatusEffect("boss"){{ - color = Team.sharded.color; + color = Team.crux.color; permanent = true; damageMultiplier = 1.3f; healthMultiplier = 1.5f;