diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 4d846805b5..f13750c813 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -23,6 +23,7 @@ text.level.mode=Gamemode: text.savegame=Save Game text.loadgame=Load Game text.joingame=Join Game +text.addplayers=Add/Remove Players text.newgame=New Game text.quit=Quit text.about.button=About diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index d500ed7de9..a4a3b57193 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -166,9 +166,11 @@ public class Control extends Module{ InputHandler[] oldi = inputs; inputs = new InputHandler[index + 1]; - System.arraycopy(old, 0, inputs, 0, oldi.length); + System.arraycopy(oldi, 0, inputs, 0, oldi.length); } + Player setTo = (index == 0 ? null : players[0]); + Player player = new Player(); player.name = Settings.getString("name"); player.mech = mobile ? Mechs.standardShip : Mechs.standard; @@ -177,6 +179,14 @@ public class Control extends Module{ player.playerIndex = index; players[index] = player; + if(setTo != null){ + player.set(setTo.x, setTo.y); + } + + if(!state.is(State.menu)){ + player.add(); + } + InputHandler input; if(mobile){ @@ -189,6 +199,19 @@ public class Control extends Module{ Inputs.addProcessor(input); } + public void removePlayer(){ + players[players.length-1].remove(); + inputs[inputs.length-1].remove(); + + Player[] old = players; + players = new Player[players.length - 1]; + System.arraycopy(old, 0, players, 0, players.length); + + InputHandler[] oldi = inputs; + inputs = new InputHandler[inputs.length - 1]; + System.arraycopy(oldi, 0, inputs, 0, inputs.length); + } + public Input gdxInput(){ return gdxInput; } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 0eda3d685d..af9fb5a66d 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -11,7 +11,6 @@ import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.BulletType; import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.SyncEntity; -import io.anuke.mindustry.gen.CallEvent; import io.anuke.mindustry.io.Platform; import io.anuke.mindustry.io.Version; import io.anuke.mindustry.net.*; diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 4462c7ccb9..10ffd9c644 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -52,6 +52,7 @@ public class UI extends SceneModule{ public AdminsDialog admins; public TraceDialog traces; public ChangelogDialog changelog; + public LocalPlayerDialog localplayers; public final MenuFragment menufrag = new MenuFragment(); public final HudFragment hudfrag = new HudFragment(); @@ -171,6 +172,7 @@ public class UI extends SceneModule{ bans = new BansDialog(); admins = new AdminsDialog(); traces = new TraceDialog(); + localplayers = new LocalPlayerDialog(); build.begin(scene); diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index d516332dea..609913b792 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -279,8 +279,10 @@ public class Player extends Unit{ movement.set(0, 0); - float xa = Inputs.getAxis("move_x"); - float ya = Inputs.getAxis("move_y"); + String section = "player_"+(playerIndex + 1); + + float xa = Inputs.getAxis(section, "move_x"); + float ya = Inputs.getAxis(section, "move_y"); if(Math.abs(xa) < 0.3) xa = 0; if(Math.abs(ya) < 0.3) ya = 0; @@ -310,7 +312,7 @@ public class Player extends Unit{ rotation = Mathf.slerpDelta(rotation, movement.angle(), 0.13f); } }else{ - float angle = Angles.mouseAngle(x, y); + float angle = control.input(playerIndex).mouseAngle(x, y); this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f); } } diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index a3d5046842..23250f1a2b 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -74,7 +74,8 @@ public class OverlayRenderer { //draw selected block bars and info if (input.recipe == null && !ui.hasMouse() && !input.frag.config.isShown()) { - Tile tile = world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y); + Vector2 vec = Graphics.world(input.getMouseX(), input.getMouseY()); + Tile tile = world.tileWorld(vec.x, vec.y); if (tile != null && tile.block() != Blocks.air) { Tile target = tile; @@ -134,7 +135,7 @@ public class OverlayRenderer { } if (input.isDroppingItem()) { - Vector2 v = Graphics.mouseWorld(); + Vector2 v = Graphics.world(input.getMouseX(), input.getMouseY()); float size = 8; Draw.rect(player.inventory.getItem().item.region, v.x, v.y, size, size); Draw.color("accent"); diff --git a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java index a8961f8138..478811cd6b 100644 --- a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java +++ b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java @@ -16,7 +16,7 @@ public class DefaultKeybinds { for(String section : sections) { KeyBinds.defaultSection(section, DeviceType.keyboard, - new Category("General"), + new Category("General"), "move_x", new Axis(Input.A, Input.D), "move_y", new Axis(Input.S, Input.W), "select", Input.MOUSE_LEFT, @@ -44,6 +44,7 @@ public class DefaultKeybinds { ); KeyBinds.defaultSection(section, DeviceType.controller, + new Category("General"), "move_x", new Axis(Input.CONTROLLER_L_STICK_HORIZONTAL_AXIS), "move_y", new Axis(Input.CONTROLLER_L_STICK_VERTICAL_AXIS), "cursor_x", new Axis(Input.CONTROLLER_R_STICK_HORIZONTAL_AXIS), @@ -51,13 +52,15 @@ public class DefaultKeybinds { "select", Input.CONTROLLER_R_BUMPER, "break", Input.CONTROLLER_L_BUMPER, "shoot", Input.CONTROLLER_R_TRIGGER, + "dash", Input.CONTROLLER_Y, + "rotate_alt", new Axis(Input.CONTROLLER_DPAD_RIGHT, Input.CONTROLLER_DPAD_LEFT), + "rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B), + new Category("View"), "zoom_hold", Input.ANY_KEY, "zoom", new Axis(Input.CONTROLLER_DPAD_DOWN, Input.CONTROLLER_DPAD_UP), "menu", Input.CONTROLLER_X, "pause", Input.CONTROLLER_L_TRIGGER, - "dash", Input.CONTROLLER_Y, - "rotate_alt", new Axis(Input.CONTROLLER_DPAD_RIGHT, Input.CONTROLLER_DPAD_LEFT), - "rotate", new Axis(Input.CONTROLLER_A, Input.CONTROLLER_B), + new Category("Multiplayer"), "player_list", Input.CONTROLLER_START ); diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index b321d2799f..579c0006f8 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -62,25 +62,26 @@ public class DesktopInput extends InputHandler{ if(Inputs.keyTap(section, "select") && recipe == null && player.inventory.hasItem()){ Vector2 vec = Graphics.screen(player.x, player.y); - if(vec.dst(Gdx.input.getX(), Gdx.graphics.getHeight() - Gdx.input.getY()) <= playerSelectRange){ + if(vec.dst(getMouseX(), Gdx.graphics.getHeight() - getMouseY()) <= playerSelectRange){ canBeginShoot = false; droppingItem = true; } } if((Inputs.keyTap(section, "select") && recipe != null) || Inputs.keyTap(section, "break")){ - Vector2 vec = Graphics.world(Gdx.input.getX(), Gdx.input.getY()); + Vector2 vec = Graphics.world(getMouseX(), getMouseY()); mousex = vec.x; mousey = vec.y; } if(!Inputs.keyDown(section, "select") && !Inputs.keyDown(section, "break")){ - mousex = Graphics.mouseWorld().x; - mousey = Graphics.mouseWorld().y; + Vector2 vec = Graphics.world(getMouseX(), getMouseY()); + mousex = vec.x; + mousey = vec.y; } - endx = Gdx.input.getX(); - endy = Gdx.input.getY(); + endx = getMouseX(); + endy = getMouseY(); boolean controller = KeyBinds.getSection(section).device.type == DeviceType.controller; @@ -229,11 +230,11 @@ public class DesktopInput extends InputHandler{ } if(Inputs.keyTap(section,"select")){ - Inputs.getProcessor().touchDown(Gdx.input.getX(), Gdx.input.getY(), player.playerIndex, Buttons.LEFT); + Inputs.getProcessor().touchDown((int)getMouseX(), (int)getMouseY(), player.playerIndex, Buttons.LEFT); } if(Inputs.keyRelease(section,"select")){ - Inputs.getProcessor().touchUp(Gdx.input.getX(), Gdx.input.getY(), player.playerIndex, Buttons.LEFT); + Inputs.getProcessor().touchUp((int)getMouseX(), (int)getMouseY(), player.playerIndex, Buttons.LEFT); } float xa = Inputs.getAxis(section, "cursor_x"); @@ -245,9 +246,11 @@ public class DesktopInput extends InputHandler{ controly -= ya*baseControllerSpeed*scl; controlling = true; - Gdx.input.setCursorCatched(true); + if(index == 0){ + Gdx.input.setCursorCatched(true); + } - Inputs.getProcessor().touchDragged(Gdx.input.getX(), Gdx.input.getY(), player.playerIndex); + Inputs.getProcessor().touchDragged((int)getMouseX(), (int)getMouseY(), player.playerIndex); } controlx = Mathf.clamp(controlx, 0, Gdx.graphics.getWidth()); @@ -266,17 +269,12 @@ public class DesktopInput extends InputHandler{ public int tilex(){ return (recipe != null && recipe.result.isMultiblock() && recipe.result.size % 2 == 0) ? - Mathf.scl(Graphics.mouseWorld().x, tilesize) : Mathf.scl2(Graphics.mouseWorld().x, tilesize); + Mathf.scl(Graphics.world(getMouseX(), getMouseY()).x, tilesize) : Mathf.scl2(Graphics.world(getMouseX(), getMouseY()).x, tilesize); } public int tiley(){ return (recipe != null && recipe.result.isMultiblock() && recipe.result.size % 2 == 0) ? - Mathf.scl(Graphics.mouseWorld().y, tilesize) : Mathf.scl2(Graphics.mouseWorld().y, tilesize); - } - - @Override - public boolean keyDown(int keycode) { - return super.keyDown(keycode); + Mathf.scl(Graphics.world(getMouseX(), getMouseY()).y, tilesize) : Mathf.scl2(Graphics.world(getMouseX(), getMouseY()).y, tilesize); } } diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index b8ae045cd2..b156ef948d 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -60,6 +60,10 @@ public abstract class InputHandler extends InputAdapter{ public void resetCursor(){} public boolean isCursorVisible(){ return false; } + public float mouseAngle(float x, float y){ + return Graphics.world(getMouseX(), getMouseY()).sub(x, y).angle(); + } + public void remove(){ Inputs.removeProcessor(this); frag.remove(); diff --git a/core/src/io/anuke/mindustry/resource/Weapon.java b/core/src/io/anuke/mindustry/resource/Weapon.java index 1148b5b1eb..1aa355b053 100644 --- a/core/src/io/anuke/mindustry/resource/Weapon.java +++ b/core/src/io/anuke/mindustry/resource/Weapon.java @@ -52,7 +52,8 @@ public class Weapon extends Upgrade{ p.timer.reset(t2, reload/2f); } - tr.set(Graphics.mouseWorld()).sub(p.x, p.y); + tr.set(Graphics.world(Vars.control.input(p.playerIndex).getMouseX(), + Vars.control.input(p.playerIndex).getMouseY())).sub(p.x, p.y); if(tr.len() < minPlayerDist) tr.setLength(minPlayerDist); float cx = tr.x + p.x, cy = tr.y + p.y; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java new file mode 100644 index 0000000000..29927af5b4 --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/dialogs/LocalPlayerDialog.java @@ -0,0 +1,59 @@ +package io.anuke.mindustry.ui.dialogs; + +import com.badlogic.gdx.utils.Scaling; +import static io.anuke.mindustry.Vars.*; +import io.anuke.mindustry.entities.Player; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.scene.ui.Image; +import io.anuke.ucore.scene.ui.layout.Stack; +import io.anuke.ucore.scene.ui.layout.Table; + +public class LocalPlayerDialog extends FloatingDialog{ + + public LocalPlayerDialog() { + super("$text.addplayers"); + + addCloseButton(); + shown(this::rebuild); + } + + private void rebuild(){ + float size = 140f; + + content().clear(); + + if(players.length > 1) { + content().addImageButton("icon-cancel", 14 * 2, () -> { + control.removePlayer(); + rebuild(); + }).size(50f, size).pad(5).bottom(); + }else{ + content().add().size(50f, size); + } + + for(Player player : players){ + Table table = new Table(); + Stack stack = new Stack(); + + stack.add(new Image("button")); + + Image img = new Image(Draw.region("icon-chat")); + img.setScaling(Scaling.fill); + + stack.add(img); + + table.add("Player " + (player.playerIndex + 1)).update(label -> label.setColor(player.color)); + table.row(); + table.add(stack).size(size); + + content().add(table).pad(5); + } + + if(players.length < 4) { + content().addImageButton("icon-add", 14 * 2, () -> { + control.addPlayer(players.length); + rebuild(); + }).size(50f, size).pad(5).bottom(); + } + } +} diff --git a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java index 72b8d99eb8..e82e1cc01a 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java @@ -54,6 +54,11 @@ public class PausedDialog extends FloatingDialog{ load.show(); }).disabled(b -> Net.active()); + content().row(); + content().addButton("$text.addplayers", () -> { + ui.localplayers.show(); + }).disabled(b -> Net.active()); + content().row(); if(!gwt) { diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java index 299a5a6eee..f881d319ab 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java @@ -14,12 +14,11 @@ import io.anuke.ucore.scene.actions.Actions; import io.anuke.ucore.scene.ui.layout.Table; public class BlockConfigFragment implements Fragment { - private Table table; + private Table table = new Table(); private Tile configTile; @Override public void build(Group parent) { - table = new Table(); parent.addChild(table); } diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java index 8e287ae794..65e609cfb6 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlocksFragment.java @@ -8,6 +8,7 @@ import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.IntSet; import io.anuke.mindustry.content.Recipes; import io.anuke.mindustry.core.GameState.State; +import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.input.InputHandler; import io.anuke.mindustry.resource.Item; import io.anuke.mindustry.resource.ItemStack; @@ -161,30 +162,44 @@ public class BlocksFragment implements Fragment{ } }); - image.clicked(() -> { - // note: input.recipe only gets set here during a click. - // during a hover only the visual description will be updated. - boolean nothingSelectedYet = input.recipe == null; - boolean selectedSomethingElse = !nothingSelectedYet && input.recipe != r; - boolean shouldMakeSelection = nothingSelectedYet || selectedSomethingElse; - if (shouldMakeSelection) { - input.recipe = r; - hoveredDescriptionRecipe = r; - updateRecipe(r); - } else { - input.recipe = null; - hoveredDescriptionRecipe = null; - updateRecipe(null); - } - }); + image.addListener(new ClickListener(){ + @Override + public void clicked(InputEvent event, float x, float y){ + // note: input.recipe only gets set here during a click. + // during a hover only the visual description will be updated. + InputHandler handler = mobile ? input : control.input(event.getPointer()); + + boolean nothingSelectedYet = handler.recipe == null; + boolean selectedSomethingElse = !nothingSelectedYet && handler.recipe != r; + boolean shouldMakeSelection = nothingSelectedYet || selectedSomethingElse; + if (shouldMakeSelection) { + handler.recipe = r; + hoveredDescriptionRecipe = r; + updateRecipe(r); + } else { + handler.recipe = null; + hoveredDescriptionRecipe = null; + updateRecipe(null); + } + } + }); table.add(image).size(size + 8); image.update(() -> { boolean has = (state.inventory.hasItems(r.requirements)); - image.setChecked(input.recipe == r); image.setTouchable(Touchable.enabled); - for(Element e : istack.getChildren()) e.setColor(has ? Color.WHITE : Hue.lightness(0.33f)); + for(Element e : istack.getChildren()){ + e.setColor(has ? Color.WHITE : Hue.lightness(0.33f)); + } + + for(Player player : players){ + if(control.input(player.playerIndex).recipe == r){ + image.setChecked(true); + return; + } + } + image.setChecked(false); }); if (i % rows == rows - 1)