diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 549a31769f..8036dca51b 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1770,6 +1770,7 @@ public class UnitTypes implements ContentList{ health = 1; rotateSpeed = 360f; itemCapacity = 0; + commandLimit = 0; } @Override diff --git a/core/src/mindustry/entities/comp/StatusComp.java b/core/src/mindustry/entities/comp/StatusComp.java index fcce0d0a02..c4ea7be07a 100644 --- a/core/src/mindustry/entities/comp/StatusComp.java +++ b/core/src/mindustry/entities/comp/StatusComp.java @@ -114,13 +114,14 @@ abstract class StatusComp implements Posc, Flyingc{ StatusEntry entry = statuses.get(index++); entry.time = Math.max(entry.time - Time.delta, 0); - applied.set(entry.effect.id); - if(entry.time <= 0 && !entry.effect.permanent){ + if(entry.effect == null || (entry.time <= 0 && !entry.effect.permanent)){ Pools.free(entry); index --; statuses.remove(index); }else{ + applied.set(entry.effect.id); + speedMultiplier *= entry.effect.speedMultiplier; healthMultiplier *= entry.effect.healthMultiplier; damageMultiplier *= entry.effect.damageMultiplier; diff --git a/core/src/mindustry/game/Objectives.java b/core/src/mindustry/game/Objectives.java index 7fc844a180..7faa162624 100644 --- a/core/src/mindustry/game/Objectives.java +++ b/core/src/mindustry/game/Objectives.java @@ -38,7 +38,7 @@ public class Objectives{ @Override public boolean complete(){ - return preset.sector.save != null && preset.sector.save.meta.wave >= preset.captureWave; + return preset.sector.save != null && !preset.sector.isAttacked() && preset.sector.hasBase(); } @Override diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 049853c864..ac43a96cfb 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -279,7 +279,7 @@ public class DesktopInput extends InputHandler{ if(isPlacing() && mode == placing){ updateLine(selectX, selectY); - }else if(!selectRequests.isEmpty()){ + }else if(!selectRequests.isEmpty() && !ui.chatfrag.shown()){ rotateRequests(selectRequests, Mathf.sign(Core.input.axisTap(Binding.rotate))); } } @@ -660,7 +660,7 @@ public class DesktopInput extends InputHandler{ } //update commander unit - if(Core.input.keyTap(Binding.command)){ + if(Core.input.keyTap(Binding.command) && unit.type.commandLimit > 0){ Call.unitCommand(player); } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index adeb6d3c2b..8d2c376e94 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -336,6 +336,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public static void unitControl(Player player, @Nullable Unit unit){ if(player == null) return; + //make sure player is allowed to control the unit + if(net.server() && !netServer.admins.allowAction(player, ActionType.control, action -> action.unit = unit)){ + throw new ValidateException(player, "Player cannot control a unit."); + } + //clear player unit when they possess a core if((unit instanceof BlockUnitc && ((BlockUnitc)unit).tile() instanceof CoreBuild)){ Fx.spawn.at(player); @@ -376,6 +381,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public static void unitCommand(Player player){ if(player == null || player.dead() || !(player.unit() instanceof Commanderc commander)) return; + //make sure player is allowed to make the command + if(net.server() && !netServer.admins.allowAction(player, ActionType.command, action -> {})){ + throw new ValidateException(player, "Player cannot command a unit."); + } + if(commander.isCommanding()){ commander.clearCommand(); }else if(player.unit().type.commandLimit > 0){ diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 63df6c151b..690b267548 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -613,7 +613,7 @@ public class MobileInput extends InputHandler implements GestureListener{ //reset payload target payloadTarget = null; //apply command on double tap when own unit is tapped - if(Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f)){ + if(!player.dead() && Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f) && player.unit().type.commandLimit > 0){ Call.unitCommand(player); }else{ //control a unit/block diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index ccf5f76755..32356ff838 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -142,11 +142,18 @@ public class Administration{ /** @return whether this action is allowed by the action filters. */ public boolean allowAction(Player player, ActionType type, Tile tile, Cons setter){ + return allowAction(player, type, action -> setter.get(action.set(player, type, tile))); + } + + /** @return whether this action is allowed by the action filters. */ + public boolean allowAction(Player player, ActionType type, Cons setter){ //some actions are done by the server (null player) and thus are always allowed if(player == null) return true; PlayerAction act = Pools.obtain(PlayerAction.class, PlayerAction::new); - setter.get(act.set(player, type, tile)); + act.player = player; + act.type = type; + setter.get(act); for(ActionFilter filter : actionFilters){ if(!filter.allow(act)){ Pools.free(act); @@ -699,7 +706,7 @@ public class Administration{ public static class PlayerAction implements Poolable{ public Player player; public ActionType type; - public Tile tile; + public @Nullable Tile tile; /** valid for block placement events only */ public @Nullable Block block; @@ -712,6 +719,9 @@ public class Administration{ public @Nullable Item item; public int itemAmount; + /** valid for unit-type events only, and even in that case may be null. */ + public @Nullable Unit unit; + public PlayerAction set(Player player, ActionType type, Tile tile){ this.player = player; this.type = type; @@ -719,6 +729,13 @@ public class Administration{ return this; } + public PlayerAction set(Player player, ActionType type, Unit unit){ + this.player = player; + this.type = type; + this.unit = unit; + return this; + } + @Override public void reset(){ item = null; @@ -728,11 +745,12 @@ public class Administration{ type = null; tile = null; block = null; + unit = null; } } public enum ActionType{ - breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem + breakBlock, placeBlock, rotate, configure, withdrawItem, depositItem, control, command } }