diff --git a/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyUI.java b/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyUI.java index 8fb3f40..831f71b 100644 --- a/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyUI.java +++ b/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyUI.java @@ -34,4 +34,11 @@ public interface RoboRallyUI { * @return The server of the game */ RoboRallyServer getServer(); + + /** + * Sets whether the client should hurry with whatever it's doing + * + * @param shouldHurry True if the user should hurry + */ + void setShouldHurry(boolean shouldHurry); } diff --git a/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyWrapper.java b/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyWrapper.java index 5ce74de..6048f4f 100644 --- a/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyWrapper.java +++ b/src/main/java/inf112/fiasko/roborally/gamewrapper/RoboRallyWrapper.java @@ -19,6 +19,7 @@ public class RoboRallyWrapper extends Game implements RoboRallyUI { public RoboRallyGame roboRallyGame; public RoboRallyServer server; public RoboRallyClient client; + public boolean shouldHurry = false; @Override public void create() { @@ -59,6 +60,11 @@ public class RoboRallyWrapper extends Game implements RoboRallyUI { return server; } + @Override + public void setShouldHurry(boolean shouldHurry) { + this.shouldHurry = shouldHurry; + } + /** * Quits the game */ diff --git a/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/CardChoiceScreen.java b/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/CardChoiceScreen.java index badb1f3..4e052bd 100644 --- a/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/CardChoiceScreen.java +++ b/src/main/java/inf112/fiasko/roborally/gamewrapper/screens/CardChoiceScreen.java @@ -39,6 +39,7 @@ public class CardChoiceScreen extends InteractiveScreen implements Screen { private final ShapeRenderer shapeRenderer; private final List chosenCards; private final int maxCards; + private long timerStarted; /** * Instantiates a new card choice screen @@ -213,10 +214,23 @@ public class CardChoiceScreen extends InteractiveScreen implements Screen { roboRallyWrapper.batch.begin(); roboRallyWrapper.font.draw(roboRallyWrapper.batch, "Press TAB to toggle the board", 10, viewport.getWorldHeight() - 50); + int timerSize = 30; + if (timerStarted != 0) { + roboRallyWrapper.font.draw(roboRallyWrapper.batch, "Time left: " + String.valueOf(timerSize - + (System.currentTimeMillis() - timerStarted) / 1000), viewport.getWorldWidth() - 150, + viewport.getWorldHeight() - 50); + } renderCardText(); roboRallyWrapper.batch.end(); stage.draw(); stage.act(); + if (roboRallyWrapper.shouldHurry && timerStarted == 0) { + timerStarted = System.currentTimeMillis(); + } + if (System.currentTimeMillis() > timerStarted + 1000 * timerSize && timerStarted > 0) { + fillProgramWithRandomCards(); + confirmCards(false); + } } @Override @@ -251,6 +265,23 @@ public class CardChoiceScreen extends InteractiveScreen implements Screen { roboRallyWrapper.batch.end(); } + /** + * Fills the user's program with enough cards to complete the program + */ + private void fillProgramWithRandomCards() { + int missingCards = maxCards - getCards().size(); + for (int i = 0; i < missingCards; i++) { + for (CardRectangle rectangle : cardRectangles) { + if (!rectangle.selected) { + rectangle.selected = true; + rectangle.selectable = false; + chosenCards.add(rectangle); + break; + } + } + } + } + /** * Renders the text displayed on cards */ diff --git a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java index 638f20d..0ea0ea8 100644 --- a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java +++ b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyClientListener.java @@ -6,6 +6,7 @@ import inf112.fiasko.roborally.elementproperties.GameState; import inf112.fiasko.roborally.gamewrapper.RoboRallyUI; import inf112.fiasko.roborally.networking.containers.ErrorResponse; import inf112.fiasko.roborally.networking.containers.GameStartInfoResponse; +import inf112.fiasko.roborally.networking.containers.HurryResponse; import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramsContainerResponse; @@ -67,6 +68,8 @@ class RoboRallyClientListener extends Listener { new Thread(() -> wrapper.getGame().receiveStayInPowerDown((PowerDownContainerResponse) object)).start(); } else if (object instanceof OkayResponse) { this.lastRequestState = RequestState.SENT_OKAY; + } else if (object instanceof HurryResponse) { + this.wrapper.setShouldHurry(true); } } diff --git a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java index 0b989d5..eef4f49 100644 --- a/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java +++ b/src/main/java/inf112/fiasko/roborally/networking/RoboRallyServerListener.java @@ -5,6 +5,7 @@ import com.esotericsoftware.kryonet.Connection; import com.esotericsoftware.kryonet.Listener; import inf112.fiasko.roborally.elementproperties.RobotID; import inf112.fiasko.roborally.networking.containers.ErrorResponse; +import inf112.fiasko.roborally.networking.containers.HurryResponse; import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramAndPowerdownRequest; @@ -169,6 +170,13 @@ class RoboRallyServerListener extends Listener { } server.sendToAllClients(new ProgramsContainerResponse(program, powerDown)); programs = new HashMap<>(); + } else { + List notReceivedFrom = playersNotYetReceivedFrom(programs); + if (notReceivedFrom.size() != 1) { + return; + } + Connection hurryUp = notReceivedFrom.get(0); + hurryUp.sendTCP(new HurryResponse()); } } @@ -185,6 +193,20 @@ class RoboRallyServerListener extends Listener { return data.keySet().containsAll(connections); } + /** + * Gets a list containing all connections the data has not been received from + * + * @param data The data map to check + * @param The type of data contained in the map + * @return All active connections for which the map has no data + */ + private List playersNotYetReceivedFrom(Map data) { + Set connections = clients.keySet(); + connections.removeAll(deadPlayers); + connections.removeAll(data.keySet()); + return new ArrayList<>(connections); + } + @Override public void connected(Connection connection) { //Prevent players from joining after the game has started diff --git a/src/main/java/inf112/fiasko/roborally/networking/containers/HurryResponse.java b/src/main/java/inf112/fiasko/roborally/networking/containers/HurryResponse.java new file mode 100644 index 0000000..3bddafe --- /dev/null +++ b/src/main/java/inf112/fiasko/roborally/networking/containers/HurryResponse.java @@ -0,0 +1,7 @@ +package inf112.fiasko.roborally.networking.containers; + +/** + * A response telling the client to hurry up the action it's doing because other clients are waiting + */ +public class HurryResponse { +} diff --git a/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java b/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java index cca2f20..ceb09d9 100644 --- a/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java +++ b/src/main/java/inf112/fiasko/roborally/utility/NetworkUtil.java @@ -5,6 +5,7 @@ import inf112.fiasko.roborally.elementproperties.Action; import inf112.fiasko.roborally.elementproperties.RobotID; import inf112.fiasko.roborally.networking.containers.ErrorResponse; import inf112.fiasko.roborally.networking.containers.GameStartInfoResponse; +import inf112.fiasko.roborally.networking.containers.HurryResponse; import inf112.fiasko.roborally.networking.containers.OkayResponse; import inf112.fiasko.roborally.networking.containers.PowerDownContainerResponse; import inf112.fiasko.roborally.networking.containers.ProgramAndPowerdownRequest; @@ -44,5 +45,6 @@ public final class NetworkUtil { kryo.register(HashMap.class); kryo.register(UsernameRequest.class); kryo.register(OkayResponse.class); + kryo.register(HurryResponse.class); } } diff --git a/src/test/java/inf112/fiasko/roborally/objects/PhaseTest.java b/src/test/java/inf112/fiasko/roborally/objects/PhaseTest.java index 95b394a..60283e6 100644 --- a/src/test/java/inf112/fiasko/roborally/objects/PhaseTest.java +++ b/src/test/java/inf112/fiasko/roborally/objects/PhaseTest.java @@ -178,7 +178,7 @@ public class PhaseTest { robots.add(robot3); Phase testPhase = createPhaseAndLoadBoard(players, robots, "boards/another_test_map.txt"); robot3.setFacingDirection(Direction.EAST); - + assertEquals(0, robot.getDamageTaken()); testPhase.fireAllLasers(); assertEquals(2, robot.getDamageTaken());