diff --git a/source/core/src/main/com/csse3200/game/components/maingame/CheckWinLoseComponent.java b/source/core/src/main/com/csse3200/game/components/maingame/CheckWinLoseComponent.java index 413b9547..157e2d35 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/CheckWinLoseComponent.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/CheckWinLoseComponent.java @@ -55,7 +55,7 @@ public String checkGameState() { if (hasLost(adjustedLossThreshold)) { return "LOSE"; - } else if (currentDay == DayNightService.MAXDAYS && hasWon(adjustedWinAmount)) { + } else if (currentDay == DayNightService.MAX_DAYS && hasWon(adjustedWinAmount)) { return "WIN"; } else { return "GAME_IN_PROGRESS"; diff --git a/source/core/src/main/com/csse3200/game/components/player/PlayerStatsDisplay.java b/source/core/src/main/com/csse3200/game/components/player/PlayerStatsDisplay.java index dd71e0a0..bc27b55f 100644 --- a/source/core/src/main/com/csse3200/game/components/player/PlayerStatsDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/player/PlayerStatsDisplay.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.scenes.scene2d.utils.BaseDrawable; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.csse3200.game.components.CombatStatsComponent; import com.csse3200.game.services.ServiceLocator; @@ -34,11 +35,12 @@ public class PlayerStatsDisplay extends UIComponent { private Label goldLabel; private static Label dayLabel; - private static int currentDay = 1; private static Label timerLabel; private static long timer; private static long startTime; private static PlayerStatsDisplay instance; + private ProgressBar timeBar; + private static final float MAX_TIME = 300f; @@ -50,7 +52,7 @@ public void create() { super.create(); setPlayerStatsDisplay(this); addActors(); - setTimer(ServiceLocator.getDayNightService().FIVEMINUTES); + setTimer(ServiceLocator.getDayNightService().FIVE_MINUTES); entity.getEvents().addListener("updateGold", this::updatePlayerGoldUI); @@ -106,8 +108,10 @@ public void create() { */ private void addActors() { table = new Table(); - table.top().left(); // Position table to the top-left of the screen + table.top().left(); table.setFillParent(true); + table.padTop(80f).padLeft(20f); + goldTable = new Table(); timerTable = new Table(); dayTable = new Table(); @@ -137,7 +141,7 @@ private void addActors() { // --- Update: Day Label with Container --- // Label for the Current Day - CharSequence dayText = String.format("Day: %d", currentDay); // Start with Day 1 + CharSequence dayText = String.format("Day: %d", ServiceLocator.getDayNightService().getDay()); // Start with Day 1 dayLabel = new Label(dayText, skin, SMALL_LABEL); dayLabel.setColor(Color.GOLD); // Set text color to white for contrast @@ -232,7 +236,7 @@ public void updatePlayerGoldUI(int gold) { * Updates the displayed current day on the UI. */ public static void updateDay() { - currentDay++; + int currentDay = ServiceLocator.getDayNightService().getDay(); CharSequence dayText = String.format("Day: %d", currentDay); getDayLabel().setText(dayText); } @@ -260,11 +264,10 @@ private static void updateTimeColor() { public static void updateTime(long time) { timer = time; -// // Calculate progress as a percentage of the time remaining -// float progressPercentage = (float) timer / startTime * 100f; -// -// // Update the progress bar value to reflect the remaining time -// getInstance().timeBar.setValue(progressPercentage); + // Calculate progress as a percentage of the time remaining + float progressPercentage = (float) time / ServiceLocator.getDayNightService().FIVE_MINUTES * 100f; + + //float progressPercentage = (float) timer / startTime * 100f; // Update the timer color based on remaining time updateTimeColor(); @@ -339,10 +342,10 @@ public static String convertDigital(long x) { long minutes = TimeUnit.MILLISECONDS.toMinutes(x); long seconds = TimeUnit.MILLISECONDS.toSeconds(x) - TimeUnit.MINUTES.toSeconds(minutes); return String.format("%02d:%02d", minutes, seconds); - + } public static void reset() { - currentDay = 1; + ServiceLocator.getDayNightService().setDay(1); } diff --git a/source/core/src/main/com/csse3200/game/screens/MoralDecisionDisplay.java b/source/core/src/main/com/csse3200/game/screens/MoralDecisionDisplay.java index d835d21b..328fbb68 100644 --- a/source/core/src/main/com/csse3200/game/screens/MoralDecisionDisplay.java +++ b/source/core/src/main/com/csse3200/game/screens/MoralDecisionDisplay.java @@ -188,6 +188,7 @@ private void hide() { isVisible = false; layout.setVisible(isVisible); game.resume(); // Resume the game when the display is hidden + logger.info("decisionDone about to be triggered"); ServiceLocator.getDayNightService().getEvents().trigger("decisionDone"); } diff --git a/source/core/src/main/com/csse3200/game/services/DayNightService.java b/source/core/src/main/com/csse3200/game/services/DayNightService.java index f0f629cf..b94f77e4 100644 --- a/source/core/src/main/com/csse3200/game/services/DayNightService.java +++ b/source/core/src/main/com/csse3200/game/services/DayNightService.java @@ -15,13 +15,13 @@ */ public class DayNightService { private static final Logger logger = LoggerFactory.getLogger(DayNightService.class); - public static final long FIVEMINUTES = 5L* 60 * 1000; // 5 minutes in milliseconds - public static final int MAXDAYS = 5; // Maximum number of days - public long SEVENTYFIVEPERCENT = (long) (FIVEMINUTES * 0.75); - private long lastSecondCheck; - private long lastUpgradeCheck; - private long lastEndOfDayCheck; - private long timeRemaining; + public long FIVE_MINUTES = 5L * 60 * 1000; // 5 minutes in milliseconds + public static final int MAX_DAYS = 5; // Maximum number of days + public long SEVENTY_FIVE_PERCENT = (long) (FIVE_MINUTES * 0.75); + public long lastSecondCheck; + public long lastUpgradeCheck; + public long lastEndOfDayCheck; + public long timeRemaining; private final GameTime gameTime; private boolean endOfDayTriggered = false; private boolean pastSecond = false; @@ -30,7 +30,7 @@ public class DayNightService { private final EventHandler docketServiceEventHandler; private Random random; private int randomChoice; - private int day; + private static int day = 0; private int highQualityMeals = 0; @@ -40,7 +40,6 @@ public class DayNightService { */ public DayNightService() { this(new EventHandler()); - day = 0; } /** @@ -51,7 +50,6 @@ public DayNightService() { */ public DayNightService(EventHandler enddayEventHandler) { this(enddayEventHandler, ServiceLocator.getDocketService().getEvents()); - day = 0; } public DayNightService(EventHandler enddayEventHandler, EventHandler docketServiceEventHandler) { @@ -61,10 +59,15 @@ public DayNightService(EventHandler enddayEventHandler, EventHandler docketServi this.lastSecondCheck = gameTime.getTime(); this.lastUpgradeCheck = gameTime.getTime(); this.lastEndOfDayCheck = gameTime.getTime(); - this.timeRemaining = FIVEMINUTES; + this.timeRemaining = FIVE_MINUTES; this.random = new Random(); - randomChoice = random.nextInt((int) SEVENTYFIVEPERCENT); - day = 1; + randomChoice = random.nextInt((int) SEVENTY_FIVE_PERCENT); + + // **Only set 'day' to 1 if it hasn't been initialized yet** + if (this.day == 0) { + this.day = 1; + } + randomChoice = random.nextInt(10) * 1000; create(); @@ -137,10 +140,10 @@ public void update() { randomChoice = random.nextInt(10) * 1000; } - if (this.timeRemaining == 0 && !endOfDayTriggered) { + if (this.timeRemaining <= 0 && !endOfDayTriggered) { endOfDayTriggered = true; gameTime.setTimeScale(0); - this.timeRemaining = FIVEMINUTES; + this.timeRemaining = FIVE_MINUTES; docketServiceEventHandler.trigger("Dispose"); enddayEventHandler.trigger("endOfDay"); // Trigger the end of the day event } @@ -151,12 +154,14 @@ public void update() { * This method is triggered after the end-of-day events are processed. */ private void startNewDay() { + logger.info("new day starting!"); + logger.info("current day is " + day); applyEndOfDayBonus(); // Apply the bonus before checking win/loss condition // Checking if the game should end (i.e. it's the 5th day) - if (day > MAXDAYS) { - logger.info("Game is ending after days!"); + if (day >= MAX_DAYS) { //had this as day > MAX_DAYS + logger.info("Game is ending after max number of days!"); ServiceLocator.getDayNightService().getEvents().trigger("endGame"); return; @@ -182,19 +187,23 @@ private void startNewDay() { } } - resetHighQualityMealCount(); // Reset count for next day + // transition to new day + day += 1; + logger.info("Next/new day is: " + day); - logger.info("It's a new Day!"); + resetHighQualityMealCount(); // Reset count for next day enddayEventHandler.trigger("newday"); + + // Reset the time for the new day + this.timeRemaining = FIVE_MINUTES; + endOfDayTriggered = false; + pastUpgrade = false; + // // Resume the game time and reset the last check time lastSecondCheck = gameTime.getTime(); // Reset lastCheckTime to the current time lastEndOfDayCheck = gameTime.getTime(); - endOfDayTriggered = false; - pastUpgrade = false; - day += 1; gameTime.setTimeScale(1); // Resume game time - } /** @@ -244,10 +253,6 @@ public void updatepastSecond() { public int getHighQualityMeals() { return highQualityMeals; } - - public long getTimeRemaining() { - return timeRemaining; - } } diff --git a/source/core/src/test/com/csse3200/game/components/CheckWinLoseComponentTest.java b/source/core/src/test/com/csse3200/game/components/CheckWinLoseComponentTest.java index fab191d3..e62f5fa9 100644 --- a/source/core/src/test/com/csse3200/game/components/CheckWinLoseComponentTest.java +++ b/source/core/src/test/com/csse3200/game/components/CheckWinLoseComponentTest.java @@ -47,9 +47,9 @@ public void tearDown() { @Test public void testCheckGameStateReturnsWinOnlyOnFinalDay() { - when(dayNightService.getDay()).thenReturn(DayNightService.MAXDAYS); + when(dayNightService.getDay()).thenReturn(DayNightService.MAX_DAYS); - int adjustedWinAmount = 55 + (DayNightService.MAXDAYS * 10); + int adjustedWinAmount = 55 + (DayNightService.MAX_DAYS * 10); int playerGold = adjustedWinAmount + 5; when(combatStatsComponent.getGold()).thenReturn(playerGold); @@ -93,9 +93,9 @@ public void testCheckGameStateReturnsLoseWhenGoldBelowThreshold() { @Test public void testCheckGameStateReturnsGameInProgressWhenGoldAboveWinAmountBeforeFinalDay() { - when(dayNightService.getDay()).thenReturn(DayNightService.MAXDAYS - 1); + when(dayNightService.getDay()).thenReturn(DayNightService.MAX_DAYS - 1); - int adjustedWinAmount = 55 + ((DayNightService.MAXDAYS - 1) * 10); + int adjustedWinAmount = 55 + ((DayNightService.MAX_DAYS - 1) * 10); int playerGold = adjustedWinAmount + 10; when(combatStatsComponent.getGold()).thenReturn(playerGold); @@ -155,9 +155,9 @@ public void testAdjustedWinAndLossThresholdCalculations() { @Test public void testCheckGameStateWhenGoldEqualsWinAmountOnFinalDay() { - when(dayNightService.getDay()).thenReturn(DayNightService.MAXDAYS); + when(dayNightService.getDay()).thenReturn(DayNightService.MAX_DAYS); - int adjustedWinAmount = 55 + (DayNightService.MAXDAYS * 10); + int adjustedWinAmount = 55 + (DayNightService.MAX_DAYS * 10); when(combatStatsComponent.getGold()).thenReturn(adjustedWinAmount); playerService.getEvents().trigger("playerCreated", playerEntity); diff --git a/source/core/src/test/com/csse3200/game/services/DayNightServiceTest.java b/source/core/src/test/com/csse3200/game/services/DayNightServiceTest.java index f94acd7c..262443e2 100644 --- a/source/core/src/test/com/csse3200/game/services/DayNightServiceTest.java +++ b/source/core/src/test/com/csse3200/game/services/DayNightServiceTest.java @@ -14,7 +14,7 @@ import static org.mockito.Mockito.*; @ExtendWith(GameExtension.class) -class DayNightServiceTest { +public class DayNightServiceTest { private GameTime gameTime; private EventHandler enddayEventHandler; @@ -50,15 +50,18 @@ public void setUp() { dayNightService = new DayNightService(enddayEventHandler, docketServiceEventHandler); ServiceLocator.registerDayNightService(dayNightService); + + // Reset static day variable before each test + dayNightService.setDay(1); } @AfterEach - void tearDown() { + public void tearDown() { ServiceLocator.clear(); } @Test - void testUpdateTriggersEndOfDay() { + public void testUpdateTriggersEndOfDay() { when(gameTime.getTime()).thenReturn(0L); AtomicBoolean disposeTriggered = new AtomicBoolean(false); @@ -69,7 +72,7 @@ void testUpdateTriggersEndOfDay() { long currentTime = 0L; long timeStep = 1000L; // 1 second - while (dayNightService.getTimeRemaining() > 0) { + while (dayNightService.timeRemaining > 0) { when(gameTime.getTime()).thenReturn(currentTime); dayNightService.update(); @@ -87,7 +90,8 @@ void testUpdateTriggersEndOfDay() { } @Test - void testDecisionDone() { + public void testDecisionDone() { + dayNightService.setDay(1); // Ensure the day starts at 1 AtomicBoolean isNewDay = new AtomicBoolean(false); enddayEventHandler.addListener("newday", () -> isNewDay.set(true)); when(checkWinLoseComponent.checkGameState()).thenReturn("GAME_IN_PROGRESS"); @@ -101,7 +105,7 @@ void testDecisionDone() { } @Test - void testApplyEndOfDayBonus() { + public void testApplyEndOfDayBonus() { dayNightService.incrementHighQualityMealCount(); dayNightService.incrementHighQualityMealCount(); when(checkWinLoseComponent.checkGameState()).thenReturn("GAME_IN_PROGRESS"); @@ -112,7 +116,7 @@ void testApplyEndOfDayBonus() { } @Test - void testResetHighQualityMealCount() { + public void testResetHighQualityMealCount() { dayNightService.incrementHighQualityMealCount(); dayNightService.incrementHighQualityMealCount(); when(checkWinLoseComponent.checkGameState()).thenReturn("GAME_IN_PROGRESS"); @@ -123,7 +127,7 @@ void testResetHighQualityMealCount() { } @Test - void testGameEndsAfterMaxDays() { + public void testGameEndsAfterMaxDays() { dayNightService.setDay(6); AtomicBoolean endGameTriggered = new AtomicBoolean(false); dayNightService.getEvents().addListener("endGame", () -> endGameTriggered.set(true)); @@ -134,7 +138,7 @@ void testGameEndsAfterMaxDays() { } @Test - void testStartNewDayWithLoseCondition() { + public void testStartNewDayWithLoseCondition() { when(checkWinLoseComponent.checkGameState()).thenReturn("LOSE"); AtomicBoolean endGameTriggered = new AtomicBoolean(false); dayNightService.getEvents().addListener("endGame", () -> endGameTriggered.set(true)); @@ -145,7 +149,7 @@ void testStartNewDayWithLoseCondition() { } @Test - void testGetAndSetDay() { + public void testGetAndSetDay() { Assertions.assertEquals(1, dayNightService.getDay(), "Initial day incorrect"); dayNightService.setDay(3); @@ -154,7 +158,7 @@ void testGetAndSetDay() { } @Test - void testIncrementHighQualityMealCount() { + public void testIncrementHighQualityMealCount() { Assertions.assertEquals(0, dayNightService.getHighQualityMeals(), "Initial highQualityMeals count incorrect"); // Testing that highQualityMeals is incremented once @@ -167,7 +171,8 @@ void testIncrementHighQualityMealCount() { } @Test - void testDaysIterateAndGameEndsAfterMaxDays() { + public void testDaysIterateAndGameEndsAfterMaxDays() { + dayNightService.setDay(1); // Reset day before iterating through the days AtomicBoolean endGameTriggered = new AtomicBoolean(false); dayNightService.getEvents().addListener("endGame", () -> endGameTriggered.set(true)); when(checkWinLoseComponent.checkGameState()).thenReturn("GAME_IN_PROGRESS"); @@ -175,9 +180,8 @@ void testDaysIterateAndGameEndsAfterMaxDays() { long currentTime = 0L; long timeStep = 1000L; // 1 second - for (int expectedDay = 1; expectedDay <= 5; expectedDay++) { - while (dayNightService.getTimeRemaining() > 0) { - + for (int expectedDay = 1; expectedDay <= DayNightService.MAX_DAYS; expectedDay++) { + while (dayNightService.timeRemaining > 0) { when(gameTime.getTime()).thenReturn(currentTime); dayNightService.update(); currentTime += timeStep; @@ -190,24 +194,18 @@ void testDaysIterateAndGameEndsAfterMaxDays() { enddayEventHandler.trigger("decisionDone"); // Verify that the day has incremented correctly and trigger is reset - Assertions.assertEquals(expectedDay + 1, dayNightService.getDay(), "Day didnt increment correctly after day " + expectedDay); - Assertions.assertFalse(dayNightService.getEndOfDayTriggered(), "endOfDayTriggered was not reset for day " + (expectedDay + 1)); - } - - while (dayNightService.getTimeRemaining() > 0) { - when(gameTime.getTime()).thenReturn(currentTime); - dayNightService.update(); - - currentTime += timeStep; - enddayEventHandler.trigger("callpastsecond"); + if (expectedDay < DayNightService.MAX_DAYS) { + // For days before the last day, day should increment + Assertions.assertEquals(expectedDay + 1, dayNightService.getDay(), "Day didn't increment correctly after day " + expectedDay); + } else { + // On the last day, day should remain at MAX_DAYS + Assertions.assertEquals(DayNightService.MAX_DAYS, dayNightService.getDay(), "Day didn't increment correctly after day " + expectedDay); + } } - when(gameTime.getTime()).thenReturn(currentTime); - dayNightService.update(); - enddayEventHandler.trigger("decisionDone"); - - // Verify that "endGame" event was triggered after day 5 is done + // Verify that "endGame" event was triggered after max days Assertions.assertTrue(endGameTriggered.get(), "endGame event was not triggered after max days"); } + }