diff --git a/source/core/src/main/com/csse3200/game/components/maingame/PauseMenuDisplay.java b/source/core/src/main/com/csse3200/game/components/maingame/PauseMenuDisplay.java index 0b80a951..71c73c1b 100644 --- a/source/core/src/main/com/csse3200/game/components/maingame/PauseMenuDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/maingame/PauseMenuDisplay.java @@ -148,6 +148,7 @@ public void clicked(InputEvent event, float x, float y) { @Override public void changed(ChangeEvent changeEvent, Actor actor) { logger.debug("Restart button clicked"); + game.resetScreen(); entity.getEvents().trigger("restart"); } }); diff --git a/source/core/src/main/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplay.java b/source/core/src/main/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplay.java index 90599d16..a7c4f38f 100644 --- a/source/core/src/main/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplay.java +++ b/source/core/src/main/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplay.java @@ -1,6 +1,7 @@ package com.csse3200.game.components.ordersystem; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.scenes.scene2d.InputEvent; @@ -144,8 +145,19 @@ public void create() { ServiceLocator.getDocketService().getEvents().addListener("removeBigTicket", this::removeBigTicket); //From Team 2, these listeners are for our dance party upgrade to pause and unpause docket times - ServiceLocator.getDocketService().getEvents().addListener("Dancing", ()->setPaused(true)); - ServiceLocator.getDocketService().getEvents().addListener("UnDancing", ()->setPaused(false)); + // ServiceLocator.getDocketService().getEvents().addListener("Dancing", ()->{ + // addTimeToDockets(600000); + // }); + ServiceLocator.getRandomComboService().getEvents().addListener("Dancing", ()->{ + addTimeToDockets(600000); + }); + + ServiceLocator.getDocketService().getEvents().addListener("paused", ()->{ + setPaused(true); + }); + ServiceLocator.getDocketService().getEvents().addListener("unpaused", ()->{ + setPaused(false); + }); //From team 2, I used your dispose method here when listening for a new day, so current dockets get removed //when the end of day occurs @@ -165,7 +177,7 @@ public boolean keyDown(InputEvent event, int keycode) { * @return true if the ESCAPE key was pressed and the event was handled, false otherwise. */ public boolean handleKeyDown(int keycode) { - if (keycode == com.badlogic.gdx.Input.Keys.ESCAPE) { + if (keycode == com.badlogic.gdx.Input.Keys.ESCAPE || keycode == Input.Keys.NUM_0) { setPaused(!isPaused); return true; } @@ -197,6 +209,14 @@ public void addActors() { table.setPosition(xVal, yVal); table.padTop(25f); Docket background = new Docket(getTimer()); + + // Check if Dancing is active, and add 60 seconds to the timer for new tickets + long ticketTimer = getTimer(); + if (ServiceLocator.getRandomComboService().dancing()) { + ticketTimer += 600000; // Add 60 seconds + } + recipeTimeArrayList.add(ticketTimer); // Add adjusted time to the list + backgroundArrayList.add(background); table.setBackground(background.getImage().getDrawable()); @@ -722,5 +742,10 @@ public long getTotalPausedDuration() { return totalPausedDuration; } + private void addTimeToDockets(long additionalTime) { + for (int i = 0; i < recipeTimeArrayList.size(); i++) { + recipeTimeArrayList.set(i, recipeTimeArrayList.get(i) + additionalTime); + } + } } diff --git a/source/core/src/main/com/csse3200/game/components/upgrades/DancePartyUpgrade.java b/source/core/src/main/com/csse3200/game/components/upgrades/DancePartyUpgrade.java index 5ba8010b..84421bb6 100644 --- a/source/core/src/main/com/csse3200/game/components/upgrades/DancePartyUpgrade.java +++ b/source/core/src/main/com/csse3200/game/components/upgrades/DancePartyUpgrade.java @@ -37,12 +37,16 @@ public class DancePartyUpgrade extends UIComponent implements Upgrade { private static final String[] greenTexture = {"images/green_fill.png"}; private static final String[] whiteBgTexture = {"images/white_background.png"}; public Table layout; - public Label text; // the "Upgrade" text above the speedMeter + public Label text; // the "Upgrade" text above the meter public ProgressBar meter; // the meter that show the remaining time private Sound bgEffect; private boolean playSound = false; + /** + * Constructor for DancePartyUpgrade that initializes the upgrade and sets up event listeners. + * It listens for "playerCreated" and "Dance party" events. + */ public DancePartyUpgrade() { ServiceLocator.getPlayerService().getEvents().addListener("playerCreated", (Entity player) -> this.combatStatsComponent = player.getComponent(CombatStatsComponent.class)); gameTime = ServiceLocator.getTimeSource(); @@ -52,6 +56,12 @@ public DancePartyUpgrade() { ServiceLocator.getRandomComboService().getEvents().addListener("Dance partyoff", this::deactivate); } + /** + * Constructor for DancePartyUpgrade with an explicit CombatStatsComponent. + * This initializes the upgrade and registers the same event listeners as the default constructor. + * + * @param combatStatsComponent the CombatStatsComponent for the player + */ public DancePartyUpgrade(CombatStatsComponent combatStatsComponent) { this.combatStatsComponent = combatStatsComponent; this.orderManager = orderManager; @@ -62,6 +72,11 @@ public DancePartyUpgrade(CombatStatsComponent combatStatsComponent) { ServiceLocator.getRandomComboService().getEvents().addListener("Dance partyoff", this::deactivate); } + /** + * Initializes the Dance Party upgrade by loading necessary assets, + * such as textures and sound effects, and setting up the UI components + * (progress meter and label). This method is called when the component is created. + */ @Override public void create() { super.create(); @@ -74,7 +89,7 @@ public void create() { layout = new Table(); layout.setFillParent(true); layout.setVisible(false); - setupMeter(); +// setupMeter(); } @@ -84,31 +99,37 @@ public void create() { * Also initializes the accompanying label. */ private void setupMeter() { - if (meter == null) { - Texture whiteBgTexture = ServiceLocator.getResourceService().getAsset("images/white_background.png", Texture.class); - Texture fillTexture = ServiceLocator.getResourceService().getAsset("images/green_fill.png", Texture.class); + Texture whiteBgTexture = ServiceLocator + .getResourceService().getAsset("images/white_background.png", Texture.class); + Texture fillTexture = ServiceLocator + .getResourceService().getAsset("images/green_fill.png", Texture.class); - ProgressBar.ProgressBarStyle style = new ProgressBar.ProgressBarStyle(); - style.background = new TextureRegionDrawable(new TextureRegion(whiteBgTexture)); - style.knobBefore = new TextureRegionDrawable(new TextureRegion(fillTexture)); + ProgressBar.ProgressBarStyle style = new ProgressBar.ProgressBarStyle(); - style.background = new TextureRegionDrawable(new TextureRegion(whiteBgTexture)); - style.background.setMinHeight(15); - style.background.setMinWidth(10); + // Setting white background + style.background = new TextureRegionDrawable(new TextureRegion(whiteBgTexture)); + style.background.setMinHeight(15); + style.background.setMinWidth(10); - // Setting green fill color - style.knobBefore = new TextureRegionDrawable(new TextureRegion(fillTexture)); - style.knobBefore.setMinHeight(15); - style.background.setMinWidth(10); + // Setting green fill color + style.knobBefore = new TextureRegionDrawable(new TextureRegion(fillTexture)); + style.knobBefore.setMinHeight(15); + style.background.setMinWidth(10); + + // Only show the speed meter if it is activated + if (isActive) { meter = new ProgressBar(0f, 1f, 0.01f, false, style); - meter.setValue(1f); - meter.setPosition(8, 500); + meter.setValue(1f); // Initially, the meter is full + meter.setPosition(30, 250); - text = new Label("Upgrade", skin); - text.setPosition(meter.getX(), meter.getY() + meter.getHeight() + 8); - layout.add(text).row(); - layout.add(meter); + // Set up text + text = new Label("Upgrade", skin); + text.setPosition(meter.getX(), meter.getY() + meter.getHeight() + 8); // Placed above meter + } + else { + meter = null; + text = null; } } @@ -123,8 +144,13 @@ public void activate() { dancePartyCost(); isActive = true; layout.setVisible(true); + setupMeter(); + System.out.println("Dance party meter value on activate: " + meter.getValue()); - ServiceLocator.getDocketService().getEvents().trigger("Dancing"); + ServiceLocator.getRandomComboService().getEvents().trigger("Dancing"); + } + else{ + ServiceLocator.getRandomComboService().getEvents().trigger("notenoughmoney"); } } @@ -142,11 +168,17 @@ public void deactivate() { ServiceLocator.getDocketService().getEvents().trigger("UnDancing"); } - + /** + * Handles the cost of the Dance Party upgrade, deducting gold from the player's CombatStatsComponent. + */ public void dancePartyCost() { combatStatsComponent.addGold(-20); } + /** + * Checks and updates the remaining time for the Dance Party upgrade, updating the progress bar meter. + * It also checks if the upgrade's time has run out and deactivates it accordingly. + */ @Override public void update() { if (isActive) { @@ -168,27 +200,79 @@ public void update() { } } - if (Gdx.input.isKeyJustPressed(Input.Keys.V)) { - if (isActive) { - deactivate(); - } else { - activate(); - } - } +// if (Gdx.input.isKeyJustPressed(Input.Keys.V)) { +// if (isActive) { +// deactivate(); +// } else { +// activate(); +// } +// } } + /** + * Disposes of assets and cleans up when the upgrade is no longer needed. + * Unloads the textures used by the upgrade. + */ @Override public void dispose() { super.dispose(); ServiceLocator.getResourceService().unloadAssets(whiteBgTexture); ServiceLocator.getResourceService().unloadAssets(greenTexture); } + + /** + * Draw method required by the UIComponent class, but not used in this upgrade. + * + * @param batch the SpriteBatch used to draw + */ @Override protected void draw(SpriteBatch batch) { } + + /** + * Sets the stage for the UI components, such as the layout, meter, and text. + * + * @param mock the Stage to which the UI components belong + */ @Override public void setStage(Stage mock) { this.stage = mock; } + + /** + * Gets the current active state of the Dance Party upgrade. + * + * @return true if the upgrade is currently active, false otherwise + */ + public boolean isActive() { + return isActive; + } + + /** + * Retrieves the remaining time for which the upgrade will stay active. + * + * @return the remaining active time in milliseconds + */ + public float getActiveTimeRemaining() { + return activeTimeRemaining; + } + + /** + * Retrieves the total upgrade duration. + * + * @return the total duration of the upgrade in milliseconds + */ + public long getUpgradeDuration() { + return UPGRADE_DURATION; + } + + /** + * Retrieves the current state of the playSound flag, which indicates whether the upgrade's sound has been played. + * + * @return true if the sound has been played, false otherwise + */ + public boolean getPlaySound() { + return playSound; + } } diff --git a/source/core/src/main/com/csse3200/game/components/upgrades/ExtortionUpgrade.java b/source/core/src/main/com/csse3200/game/components/upgrades/ExtortionUpgrade.java index d751243b..bd3543ff 100644 --- a/source/core/src/main/com/csse3200/game/components/upgrades/ExtortionUpgrade.java +++ b/source/core/src/main/com/csse3200/game/components/upgrades/ExtortionUpgrade.java @@ -29,9 +29,9 @@ public class ExtortionUpgrade extends UIComponent implements Upgrade { private static final String[] greenTexture = {"images/green_fill.png"}; private static final String[] whiteBgTexture = {"images/white_background.png"}; - private Table layout; - private Label text; // the "Upgrade" text above the speedMeter - private ProgressBar meter; // the meter that show the remaining time + public Table layout; + public Label text; // the "Upgrade" text above the meter + public ProgressBar meter; // the meter that show the remaining time private boolean isVisible; private Sound bgEffect; private boolean playSound = false; @@ -49,6 +49,14 @@ public ExtortionUpgrade() { ServiceLocator.getRandomComboService().getEvents().addListener("Extortionoff", this::deactivate); } + public ExtortionUpgrade(CombatStatsComponent combatStatsComponent) { + this.isActive = false; + this.gameTime = ServiceLocator.getTimeSource(); + this.combatStatsComponent = combatStatsComponent; + ServiceLocator.getRandomComboService().getEvents().addListener("Extortion", this::activate); + ServiceLocator.getRandomComboService().getEvents().addListener("Extortionoff", this::deactivate); + } + @Override public void create() { super.create(); @@ -61,6 +69,7 @@ public void create() { layout = new Table(); layout.setFillParent(true); layout.setVisible(isVisible); +// setupMeter(); } /** @@ -90,10 +99,10 @@ private void setupMeter() { if (isActive) { meter = new ProgressBar(0f, 1f, 0.01f, false, style); meter.setValue(1f); // Initially, the meter is full - meter.setPosition(8, 500); + meter.setPosition(30, 250); // Set up text - text = new Label("Upgrade", skin); + text = new Label("Upgrade", skin); text.setPosition(meter.getX(), meter.getY() + meter.getHeight() + 8); // Placed above meter } else { @@ -134,15 +143,9 @@ public void deactivate() { layout.setVisible(false); ServiceLocator.getRandomComboService().getEvents().trigger("extortion unactive"); - // Ensure the text and meter are removed from the stage after time finish - if (meter != null && meter.hasParent()) { - meter.remove(); - text.remove(); - } - } - public boolean isActive() { - return isActive; + meter.remove(); + text.remove(); } /** @@ -189,6 +192,26 @@ protected void draw(SpriteBatch batch) { @Override public void setStage(Stage mock) { + this.stage = mock; + } + + public boolean isActive() { + return isActive; + } + + public boolean isVisible() { + return isVisible; + } + + public long getUpgradeDuration() { + return upgradeDuration; + } + + public float getActivateTimeRemaining() { + return activateTimeRemaining; + } + public boolean getPlaySound() { + return playSound; } } \ No newline at end of file diff --git a/source/core/src/main/com/csse3200/game/components/upgrades/LoanUpgrade.java b/source/core/src/main/com/csse3200/game/components/upgrades/LoanUpgrade.java index ad28ee39..db08577c 100644 --- a/source/core/src/main/com/csse3200/game/components/upgrades/LoanUpgrade.java +++ b/source/core/src/main/com/csse3200/game/components/upgrades/LoanUpgrade.java @@ -28,16 +28,11 @@ public LoanUpgrade(){ * at least 20 gold */ public void activate() { - if(combatStatsComponent.getGold() >= 20){ - // https://pixabay.com/sound-effects/cha-ching-7053/ - Sound moneySound = Gdx.audio.newSound(Gdx.files.internal("sounds/loan.mp3")); - long moneySoundId = moneySound.play(); - moneySound.setVolume(moneySoundId, 0.2f); - combatStatsComponent.addGold(100); - } - else{ - ServiceLocator.getRandomComboService().getEvents().trigger("notenoughmoney"); - } + // https://pixabay.com/sound-effects/cha-ching-7053/ + Sound moneySound = Gdx.audio.newSound(Gdx.files.internal("sounds/loan.mp3")); + long moneySoundId = moneySound.play(); + moneySound.setVolume(moneySoundId, 0.2f); + combatStatsComponent.addGold(100); } /** @@ -47,9 +42,6 @@ public void deactivate() {} @Override public void update() { - // Check if the 'L' key is pressed in each frame - if (Gdx.input.isKeyJustPressed(Input.Keys.L)) { - activate(); // Add 100 gold when 'L' is pressed - } + } } diff --git a/source/core/src/main/com/csse3200/game/components/upgrades/SpeedBootsUpgrade.java b/source/core/src/main/com/csse3200/game/components/upgrades/SpeedBootsUpgrade.java index ba6bc6fe..74c023f7 100644 --- a/source/core/src/main/com/csse3200/game/components/upgrades/SpeedBootsUpgrade.java +++ b/source/core/src/main/com/csse3200/game/components/upgrades/SpeedBootsUpgrade.java @@ -167,7 +167,7 @@ private void setupSpeedMeter() { if (isActivate) { speedMeter = new ProgressBar(0f, 1f, 0.01f, false, style); speedMeter.setValue(1f); // Initially, the meter is full - speedMeter.setPosition(8, 500); + speedMeter.setPosition(30, 250); // Set up text text = new Label("Upgrade", skin); diff --git a/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java b/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java index ecd31e14..b15f99c9 100644 --- a/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java +++ b/source/core/src/main/com/csse3200/game/entities/factories/NPCFactory.java @@ -104,7 +104,8 @@ public static Entity createUpgradeNPC(Vector2 firstPosition, UpgradesDisplay upg // Add a click event listener for the penguin penguin.getEvents().addListener("penguinactivated", ()->{ - if (!isClicked[0] && isHoverBox[0]) { + if (!isClicked[0] && isHoverBox[0] ) { + ServiceLocator.getDocketService().getEvents().trigger("paused"); hoverBox.setEnabled(false); logger.info("Penguin clicked!"); upgradesDisplay.create(); @@ -115,7 +116,9 @@ public static Entity createUpgradeNPC(Vector2 firstPosition, UpgradesDisplay upg } }); - ServiceLocator.getRandomComboService().getEvents().addListener("response", penguin::dispose); + ServiceLocator.getRandomComboService().getEvents().addListener("response", ()->{ + ServiceLocator.getDocketService().getEvents().trigger("unpaused"); + penguin.dispose();}); return penguin; } diff --git a/source/core/src/main/com/csse3200/game/services/DocketService.java b/source/core/src/main/com/csse3200/game/services/DocketService.java index 3f2d854f..cd7fdf68 100644 --- a/source/core/src/main/com/csse3200/game/services/DocketService.java +++ b/source/core/src/main/com/csse3200/game/services/DocketService.java @@ -14,7 +14,11 @@ public class DocketService { * Initialises the EventHandler that will manage all docket-related events. */ public DocketService() { - docketEventHandler = new EventHandler(); + this(new EventHandler()); + } + + public DocketService(EventHandler docketEventHandler) { + this.docketEventHandler = docketEventHandler; } diff --git a/source/core/src/main/com/csse3200/game/services/RandomComboService.java b/source/core/src/main/com/csse3200/game/services/RandomComboService.java index 5cbcc480..9cd9497b 100644 --- a/source/core/src/main/com/csse3200/game/services/RandomComboService.java +++ b/source/core/src/main/com/csse3200/game/services/RandomComboService.java @@ -2,8 +2,15 @@ import com.csse3200.game.components.Component; +import com.csse3200.game.components.maingame.PauseMenuDisplay; import com.csse3200.game.events.EventHandler; +import com.csse3200.game.services.ServiceLocator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; import java.util.Random; +import java.util.List; /** * The RandomComboService class is responsible for managing and activating random upgrades @@ -14,11 +21,13 @@ */ public class RandomComboService extends Component { - + private static final Logger logger = LoggerFactory.getLogger(RandomComboService.class); + // private List upgrades; private Random random; int randomChoice; private EventHandler eventHandler; - private int totalUpgrades = 4; + private int total_upgrades = 4; + private boolean isDancing = false; public RandomComboService() { this(new EventHandler()); @@ -27,7 +36,14 @@ public RandomComboService(EventHandler eventHandler) { super(); this.eventHandler = eventHandler; this.random = new Random(); - randomChoice = random.nextInt(totalUpgrades); + randomChoice = random.nextInt(total_upgrades); + + eventHandler.addListener("Dancing", ()->{isDancing = true;}); + eventHandler.addListener("UnDancing", ()->{isDancing = true;}); + + // ServiceLocator.getDocketService().getEvents().addListener("UnDancing", ()->{ + // isDancing = false; + // }); } /** @@ -74,6 +90,11 @@ public void deactivateUpgrade() { public EventHandler getEvents() { return eventHandler; } + + public boolean dancing(){ + return isDancing; + + } } diff --git a/source/core/src/test/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplayTest.java b/source/core/src/test/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplayTest.java index fc602cbf..7c319fcd 100644 --- a/source/core/src/test/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplayTest.java +++ b/source/core/src/test/com/csse3200/game/components/ordersystem/MainGameOrderTicketDisplayTest.java @@ -13,10 +13,7 @@ import com.csse3200.game.events.EventHandler; import com.csse3200.game.extensions.GameExtension; import com.csse3200.game.rendering.RenderService; -import com.csse3200.game.services.DocketService; -import com.csse3200.game.services.PlayerService; -import com.csse3200.game.services.ResourceService; -import com.csse3200.game.services.ServiceLocator; +import com.csse3200.game.services.*; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -56,6 +53,7 @@ class MainGameOrderTicketDisplayTest { @Mock CombatStatsComponent combatStatsComponent; @Mock TicketDetails ticketDetails; // Mocked TicketDetails private MockedStatic serviceLocatorMock; + RandomComboService randomComboService; private static final Logger logger = LoggerFactory.getLogger(MainGameOrderTicketDisplayTest.class); /** @@ -69,6 +67,7 @@ void setUp() { resourceService = mock(ResourceService.class); ServiceLocator.registerResourceService(resourceService); textureMock = mock(Texture.class); + randomComboService = new RandomComboService(new EventHandler()); serviceLocatorMock = Mockito.mockStatic(ServiceLocator.class); @@ -77,6 +76,7 @@ void setUp() { serviceLocatorMock.when(ServiceLocator::getPlayerService).thenReturn(playerService); serviceLocatorMock.when(ServiceLocator::getResourceService).thenReturn(resourceService); serviceLocatorMock.when(ServiceLocator::getTicketDetails).thenReturn(ticketDetails); + serviceLocatorMock.when(ServiceLocator::getRandomComboService).thenReturn(randomComboService); resourceService = mock(ResourceService.class); textureMock = mock(Texture.class); diff --git a/source/core/src/test/com/csse3200/game/components/upgrades/DancePartyUpgradeTest.java b/source/core/src/test/com/csse3200/game/components/upgrades/DancePartyUpgradeTest.java index 3f494bc4..ab6a73a5 100644 --- a/source/core/src/test/com/csse3200/game/components/upgrades/DancePartyUpgradeTest.java +++ b/source/core/src/test/com/csse3200/game/components/upgrades/DancePartyUpgradeTest.java @@ -16,6 +16,8 @@ import com.csse3200.game.rendering.RenderService; import com.csse3200.game.services.*; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.*; import org.junit.jupiter.api.AfterEach; @@ -23,6 +25,8 @@ import org.junit.jupiter.api.Test; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.concurrent.atomic.AtomicBoolean; + @ExtendWith(GameExtension.class) @ExtendWith(MockitoExtension.class) public class DancePartyUpgradeTest { @@ -37,22 +41,26 @@ public class DancePartyUpgradeTest { @Mock ProgressBar meter; @Mock Label mockText; @Mock CombatStatsComponent combatStatsComponent; - @Mock KeyboardPlayerInputComponent keyboardPlayerInputComponent; - private EventHandler eventHandler; + private EventHandler randomComboEventHandler; + private EventHandler docketEventHandler; RandomComboService randomComboService; + DocketService docketService; private DancePartyUpgrade dancePartyUpgrade; @BeforeEach void setUp() { ServiceLocator.clear(); - eventHandler = new EventHandler(); - randomComboService = new RandomComboService(eventHandler); + randomComboEventHandler = new EventHandler(); + docketEventHandler = new EventHandler(); + randomComboService = new RandomComboService(randomComboEventHandler); + docketService = spy(new DocketService(randomComboEventHandler)); ServiceLocator.registerRandomComboService(randomComboService); ServiceLocator.registerRenderService(renderService); ServiceLocator.registerResourceService(resourceService); ServiceLocator.registerTimeSource(gameTime); + ServiceLocator.registerDocketService(docketService); lenient().when(resourceService.getAsset(anyString(), eq(Texture.class))).thenReturn(textureMock); lenient().when(renderService.getStage()).thenReturn(stage); @@ -68,8 +76,111 @@ void setUp() { } @Test - void testNotNull() { + void testDancePartyActivates() { assertNotNull(dancePartyUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + dancePartyUpgrade.activate(); + + AtomicBoolean isActive = new AtomicBoolean(false); + docketEventHandler.addListener("Dancing", () -> { + isActive.set(true); + }); + docketEventHandler.trigger("Dancing"); + + assertEquals(1f, dancePartyUpgrade.meter.getValue()); + assertTrue(isActive.get()); + assertTrue(dancePartyUpgrade.isActive()); + assertTrue(dancePartyUpgrade.layout.isVisible()); + assertEquals(dancePartyUpgrade.getActiveTimeRemaining(), dancePartyUpgrade.getUpgradeDuration()); + } + + @Test + void testDancePartyDeactivates() { + dancePartyUpgrade.activate(); + lenient().when(meter.hasParent()).thenReturn(true); + dancePartyUpgrade.deactivate(); + + AtomicBoolean isActive = new AtomicBoolean(false); + docketEventHandler.addListener("UnDancing", () -> { + isActive.set(true); + }); + docketEventHandler.trigger("UnDancing"); + + assertTrue(isActive.get()); + verify(dancePartyUpgrade.meter).remove(); + verify(dancePartyUpgrade.text).remove(); + + assertFalse(dancePartyUpgrade.isActive()); + assertFalse(dancePartyUpgrade.layout.isVisible()); + assertEquals(0f, dancePartyUpgrade.meter.getValue()); + } + + @Test + void testLoseGoldOnPurchase() { + when(combatStatsComponent.getGold()).thenReturn(100); + dancePartyUpgrade.activate(); + verify(combatStatsComponent).addGold(-20); + } + + @Test + void testInsufficientGold() { + when(combatStatsComponent.getGold()).thenReturn(10); + AtomicBoolean notEnoughMoney = new AtomicBoolean(false); + randomComboEventHandler.addListener("notenoughmoney", () -> { + notEnoughMoney.set(true); + }); + + dancePartyUpgrade.activate(); + + assertTrue(notEnoughMoney.get()); + assertFalse(dancePartyUpgrade.isActive()); + assertFalse(dancePartyUpgrade.layout.isVisible()); + } + + @Test + void testDancePartyFor30Seconds() { + DancePartyUpgrade spyDancePartyUpgrade = spy(dancePartyUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + spyDancePartyUpgrade.activate(); + + when(gameTime.getDeltaTime()).thenReturn(1f); + for (int i = 0; i < 15; i++) { + spyDancePartyUpgrade.update(); + } + + assertEquals(spyDancePartyUpgrade.getActiveTimeRemaining() / + (float) spyDancePartyUpgrade.getUpgradeDuration(), spyDancePartyUpgrade.meter.getValue()); + + for (int i = 0; i < 15; i++) { + spyDancePartyUpgrade.update(); + } + + assertEquals(0, spyDancePartyUpgrade.getActiveTimeRemaining()); + verify(spyDancePartyUpgrade).deactivate(); + assertFalse(spyDancePartyUpgrade.getPlaySound()); + } + + @ParameterizedTest + @ValueSource(ints = {5, 10, 15, 20, 25, 30}) + void testMeterValueAtDifferentLevelsOfDepletion(int totalDepletedTime) { + DancePartyUpgrade spyDancePartyUpgrade = spy(dancePartyUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + spyDancePartyUpgrade.activate(); + + when(gameTime.getDeltaTime()).thenReturn(1f); + for (int i = 0; i < totalDepletedTime; i++) { + spyDancePartyUpgrade.update(); + } + + assertEquals(spyDancePartyUpgrade.getActiveTimeRemaining() / + (float) spyDancePartyUpgrade.getUpgradeDuration(), spyDancePartyUpgrade.meter.getValue(), 0.01); + } + + @Test + void testDispose() { + dancePartyUpgrade.dispose(); + verify(resourceService).unloadAssets(SpeedBootsUpgrade.whiteBgTexture); + verify(resourceService).unloadAssets(SpeedBootsUpgrade.greenTexture); } @AfterEach diff --git a/source/core/src/test/com/csse3200/game/components/upgrades/ExtortionUpgradeTest.java b/source/core/src/test/com/csse3200/game/components/upgrades/ExtortionUpgradeTest.java index fe1e47e1..b4a6b954 100644 --- a/source/core/src/test/com/csse3200/game/components/upgrades/ExtortionUpgradeTest.java +++ b/source/core/src/test/com/csse3200/game/components/upgrades/ExtortionUpgradeTest.java @@ -1,38 +1,187 @@ package com.csse3200.game.components.upgrades; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.*; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.utils.viewport.Viewport; + +import com.csse3200.game.components.CombatStatsComponent; +import com.csse3200.game.components.player.KeyboardPlayerInputComponent; +import com.csse3200.game.events.EventHandler; +import com.csse3200.game.extensions.GameExtension; +import com.csse3200.game.rendering.RenderService; +import com.csse3200.game.services.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.concurrent.atomic.AtomicBoolean; + +@ExtendWith(GameExtension.class) +@ExtendWith(MockitoExtension.class) public class ExtortionUpgradeTest { - /** - private CombatStatsComponent combatStatsComponent; + @Mock RenderService renderService; + @Spy OrthographicCamera camera; + @Mock Stage stage; + @Mock Viewport viewport; + @Mock ResourceService resourceService; + @Mock GameTime gameTime; + @Mock Texture textureMock; + @Mock Table mockLayout; + @Mock ProgressBar mockSpeedMeter; + @Mock Label mockText; + @Mock CombatStatsComponent combatStatsComponent; + private EventHandler eventHandler; + RandomComboService randomComboService; private ExtortionUpgrade extortionUpgrade; - private MainGameOrderTicketDisplay mainGameOrderTicketDisplay; - @BeforeEach - void beforeEach() { - GameTime gameTime = mock(GameTime.class); - when(gameTime.getTime()).thenReturn(0L); + void setUp() { + ServiceLocator.clear(); + + eventHandler = new EventHandler(); + randomComboService = new RandomComboService(eventHandler); + + ServiceLocator.registerRandomComboService(randomComboService); + ServiceLocator.registerRenderService(renderService); + ServiceLocator.registerResourceService(resourceService); ServiceLocator.registerTimeSource(gameTime); - PlayerService playerService = new PlayerService(); - ServiceLocator.registerPlayerService(playerService); + lenient().when(resourceService.getAsset(anyString(), eq(Texture.class))).thenReturn(textureMock); + lenient().when(renderService.getStage()).thenReturn(stage); + lenient().when(renderService.getStage().getViewport()).thenReturn(viewport); + lenient().when(renderService.getStage().getViewport().getCamera()).thenReturn(camera); - //To my knowledge you can't do when() on this, which is causing a lot of problems - //when(ServiceLocator.getPlayerService()).thenReturn(new PlayerService()); + extortionUpgrade = new ExtortionUpgrade(combatStatsComponent); + extortionUpgrade.setStage(stage); + extortionUpgrade.layout = mockLayout; + extortionUpgrade.meter = mockSpeedMeter; + extortionUpgrade.text = mockText; + extortionUpgrade.create(); + } + + @Test + void testExtortionUpgradeActivates() { + assertNotNull(extortionUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + extortionUpgrade.activate(); - //extortionUpgrade = mock(new ExtortionUpgrade(10, gameTime)); - extortionUpgrade = mock(ExtortionUpgrade.class); - mainGameOrderTicketDisplay = new MainGameOrderTicketDisplay(); - when(extortionUpgrade.getTickets()).thenReturn(mainGameOrderTicketDisplay); + AtomicBoolean isActive = new AtomicBoolean(false); + eventHandler.addListener("extortion active", () -> { + isActive.set(true); + }); + eventHandler.trigger("extortion active"); - //TODO mock CombatStatsService + assertTrue(isActive.get()); + assertTrue(extortionUpgrade.isActive()); + assertTrue(extortionUpgrade.isVisible()); + assertTrue(extortionUpgrade.layout.isVisible()); + assertEquals(extortionUpgrade.getUpgradeDuration(), extortionUpgrade.getActivateTimeRemaining()); + assertEquals(1f, extortionUpgrade.meter.getValue()); + } + + @Test + void testExtortionUpgradeDeactivates() { + extortionUpgrade.activate(); + lenient().when(mockSpeedMeter.hasParent()).thenReturn(true); + extortionUpgrade.deactivate(); + + AtomicBoolean isActive = new AtomicBoolean(false); + eventHandler.addListener("UnDancing", () -> { + isActive.set(true); + }); + eventHandler.trigger("UnDancing"); + + assertTrue(isActive.get()); + verify(extortionUpgrade.meter).remove(); + verify(extortionUpgrade.text).remove(); + + assertFalse(extortionUpgrade.isActive()); + assertFalse(extortionUpgrade.isVisible()); + assertFalse(extortionUpgrade.layout.isVisible()); + assertEquals(0f, extortionUpgrade.meter.getValue()); + } + + @Test + void testLoseGoldOnPurchase() { + when(combatStatsComponent.getGold()).thenReturn(100); + extortionUpgrade.activate(); + verify(combatStatsComponent).addGold(-40); } @Test - void shouldDoubleGold() { - int goldBefore = mainGameOrderTicketDisplay.getRecipeValue(); - int goldAfter = mainGameOrderTicketDisplay.getRecipeValue(); - assertEquals(goldBefore, goldAfter); + void testInsufficientGold() { + when(combatStatsComponent.getGold()).thenReturn(10); + AtomicBoolean notEnoughMoney = new AtomicBoolean(false); + eventHandler.addListener("notenoughmoney", () -> { + notEnoughMoney.set(true); + }); + + extortionUpgrade.activate(); + + assertTrue(notEnoughMoney.get()); + assertFalse(extortionUpgrade.isActive()); + assertFalse(extortionUpgrade.isVisible()); + assertFalse(extortionUpgrade.layout.isVisible()); + } + + @Test + void testExtortionUpgradeFor30Seconds() { + ExtortionUpgrade spyExtortionUpgrade = spy(extortionUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + spyExtortionUpgrade.activate(); + + when(gameTime.getDeltaTime()).thenReturn(1f); + for (int i = 0; i < 15; i++) { + spyExtortionUpgrade.update(); + } + + assertEquals(spyExtortionUpgrade.getActivateTimeRemaining() / + (float) spyExtortionUpgrade.getUpgradeDuration(), spyExtortionUpgrade.meter.getValue()); + + for (int i = 0; i < 15; i++) { + spyExtortionUpgrade.update(); + } + + verify(spyExtortionUpgrade).deactivate(); + assertFalse(spyExtortionUpgrade.getPlaySound()); + } + + @ParameterizedTest + @ValueSource(ints = {5, 10, 15, 20, 25, 30}) + void testMeterValueAtDifferentLevelsOfDepletion(int totalDepletedTime) { + ExtortionUpgrade spyExtortionUpgrade = spy(extortionUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + spyExtortionUpgrade.activate(); + + when(gameTime.getDeltaTime()).thenReturn(1f); + for (int i = 0; i < totalDepletedTime; i++) { + spyExtortionUpgrade.update(); + } + + assertEquals(spyExtortionUpgrade.getActivateTimeRemaining() / + (float) spyExtortionUpgrade.getUpgradeDuration(), spyExtortionUpgrade.meter.getValue(), 0.01); + } + + @Test + void testDispose() { + extortionUpgrade.dispose(); + verify(resourceService).unloadAssets(SpeedBootsUpgrade.whiteBgTexture); + verify(resourceService).unloadAssets(SpeedBootsUpgrade.greenTexture); + } + + @AfterEach + void tearDown() { + ServiceLocator.clear(); } - */ } diff --git a/source/core/src/test/com/csse3200/game/components/upgrades/LoanUpgradeTest.java b/source/core/src/test/com/csse3200/game/components/upgrades/LoanUpgradeTest.java index 908c464b..7ce4e29f 100644 --- a/source/core/src/test/com/csse3200/game/components/upgrades/LoanUpgradeTest.java +++ b/source/core/src/test/com/csse3200/game/components/upgrades/LoanUpgradeTest.java @@ -57,32 +57,8 @@ public void tearDown() { @Test public void activate_shouldAddGold_WhenGoldIsSufficient() { - when(combatStatsComponent.getGold()).thenReturn(20); loanUpgrade.activate(); verify(combatStatsComponent).addGold(100); } - @Test - public void activate_shouldTriggerNotEnoughMoneyEvent_WhenGoldIsInsufficient() { - when(combatStatsComponent.getGold()).thenReturn(10); - loanUpgrade.activate(); - verify(randomComboServiceEvents).trigger("notenoughmoney"); - } - - @Test - public void update_shouldCallActivate_WhenLKeyIsPressed() throws Exception { - MockedStatic gdxMock = mockStatic(Gdx.class); - Input mockInput = mock(Input.class); - - Field inputField = Gdx.class.getDeclaredField("input"); - inputField.setAccessible(true); - inputField.set(null, mockInput); - - when(mockInput.isKeyJustPressed(Input.Keys.L)).thenReturn(true); - LoanUpgrade loanUpgradeSpy = spy(loanUpgrade); - loanUpgradeSpy.update(); - verify(loanUpgradeSpy).activate(); - gdxMock.close(); - } - } diff --git a/source/core/src/test/com/csse3200/game/components/upgrades/RageUpgradeTest.java b/source/core/src/test/com/csse3200/game/components/upgrades/RageUpgradeTest.java index dbdd5d9d..f8fab9ce 100644 --- a/source/core/src/test/com/csse3200/game/components/upgrades/RageUpgradeTest.java +++ b/source/core/src/test/com/csse3200/game/components/upgrades/RageUpgradeTest.java @@ -22,6 +22,9 @@ import org.junit.jupiter.api.Test; import org.mockito.junit.jupiter.MockitoExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + @ExtendWith(GameExtension.class) @ExtendWith(MockitoExtension.class) public class RageUpgradeTest { @@ -115,11 +118,12 @@ void testRageMeterFillsIn90Seconds() { assertFalse(spyRageUpgrade.isRageFilling()); } - @Test - void testRageDeactivationBeforeDepletion() { + @ParameterizedTest + @ValueSource(floats = {0.25f, 0.5f, 0.75f}) + void testRageDeactivationBeforeDepletion(float rageMeterValue) { // Wanted to do parameterised testing here but need to ask about how to modify build.gradle for // @ParamterizedTest annotation - rageUpgrade.rageMeter.setValue(0.5f); + rageUpgrade.rageMeter.setValue(rageMeterValue); rageUpgrade.deactivateRageMode(); // 45 seconds diff --git a/source/core/src/test/com/csse3200/game/components/upgrades/SpeedBootsUpgradeTest.java b/source/core/src/test/com/csse3200/game/components/upgrades/SpeedBootsUpgradeTest.java index 98d40595..03c761fe 100644 --- a/source/core/src/test/com/csse3200/game/components/upgrades/SpeedBootsUpgradeTest.java +++ b/source/core/src/test/com/csse3200/game/components/upgrades/SpeedBootsUpgradeTest.java @@ -16,6 +16,8 @@ import com.csse3200.game.rendering.RenderService; import com.csse3200.game.services.*; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.*; import org.junit.jupiter.api.AfterEach; @@ -152,6 +154,22 @@ void testSpeedBootsFor30Seconds() { assertFalse(spySpeedBootsUpgrade.getPlaySound()); } + @ParameterizedTest + @ValueSource(ints = {5, 10, 15, 20, 25, 30}) + void testMeterValueAtDifferentLevelsOfDepletion(int totalDepletedTime) { + SpeedBootsUpgrade spySpeedBootsUpgrade = spy(speedBootsUpgrade); + when(combatStatsComponent.getGold()).thenReturn(100); + spySpeedBootsUpgrade.activate(); + + when(gameTime.getDeltaTime()).thenReturn(1f); + for (int i = 0; i < totalDepletedTime; i++) { + spySpeedBootsUpgrade.update(); + } + + assertEquals(spySpeedBootsUpgrade.getActiveTimeRemaining() / + (float) spySpeedBootsUpgrade.getBoostDuration(), spySpeedBootsUpgrade.speedMeter.getValue(), 0.01); + } + @Test void testDispose() { speedBootsUpgrade.dispose();