-
Notifications
You must be signed in to change notification settings - Fork 1
Kangaroo Boss Special Move
Phurin Vanasrivilai edited this page Oct 1, 2024
·
11 revisions
The SpecialKangaMove is a special move used in combat by the Kanga Boss, extending from the SpecialMove abstract class (as described in Combat Moves).
This move applies at random one of the two status effects to the player:
- CONFUSION: The player executes a random move.
- BLEEDING: The player loses health at the end of each turn.
In addition to debuffing the player, the move also buffs Kanga’s strength and defense.
package com.csse3200.game.components.combat.move;
import com.csse3200.game.components.CombatStatsComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The SpecialKangaMove class represents Kanga's special combat move, which inflicts debuffs
* on the player and buffs Kanga's own stats. This move is unique to Kanga and impacts both
* the target and the attacker.
*/
public class SpecialKangaMove extends SpecialMove {
private static final Logger logger = LoggerFactory.getLogger(SpecialKangaMove.class);
/**
* Constructs the SpecialKangaMove with the given move name and stamina cost.
*
* @param moveName the name of the special Kanga move.
* @param staminaCost the stamina cost required to perform the special Kanga move.
*/
public SpecialKangaMove(String moveName, int staminaCost) {
super(moveName, staminaCost);
}
/**
* Applies a random status effect to the target player after the move is executed
*
* Also apply debuff which decreases Player's strength by 15 and defense by 10.
*
* @param targetStats combat stats of the target (player) that will be affected by the debuffs.
*/
@Override
protected void applyDebuffs(CombatStatsComponent targetStats) {
// Applies debuffs to target's stats
targetStats.addStrength(-15);
targetStats.addDefense(-15);
int rand = (int) (Math.random() * 2);
CombatStatsComponent.StatusEffect statusEffect = switch (rand) {
case 0 -> CombatStatsComponent.StatusEffect.CONFUSION;
case 1 -> CombatStatsComponent.StatusEffect.BLEEDING;
default -> throw new IllegalStateException("Unexpected value: " + rand);
};
targetStats.addStatusEffect(statusEffect);
logger.info("Status effect {} applied to the {}", statusEffect.name(), targetStats.isPlayer() ? "PLAYER" : "ENEMY");
}
/**
* Buffs Kanga's strength and defense stats after the special move.
*
* This method increases Kanga's strength by 15 and defense by 10.
*
* @param attackerStats combat stats of Kanga, who is performing the special move.
*/
@Override
protected void applyBuffs(CombatStatsComponent attackerStats) {
attackerStats.addStrength(15);
attackerStats.addDefense(10);
logger.info("{} increased its strength to {} and defense to {}.",
attackerStats.isPlayer() ? "PLAYER" : "ENEMY",
attackerStats.getStrength(),
attackerStats.getDefense());
}
}
.
.
.
public void onPlayerActionSelected(String playerActionStr)
{
// Map the string input to the corresponding enum value
try {
playerAction = Action.valueOf(playerActionStr.toUpperCase());
} catch (IllegalArgumentException e) {
logger.error("Invalid player action: {}", playerActionStr);
return;
}
// The effect of confusion is applied at the start of the round after the player has selected their move.
checkForConfusion(playerStats);
enemyAction = selectEnemyMove();
logger.info("Player action = {}, enemy action = {}", playerAction, enemyAction);
executeMoveCombination(playerAction, enemyAction);
// The effect of any status ailments that afflict the player/enemy are applied at the end of each round.
processStatusEffects(playerStats);
processStatusEffects(enemyStats);
}
.
.
.
- The
CombatMoveComponent
class is extensively unit tested for each method. - The base
CombatMove
class is extensively unit tested for each method. - The
SpecialMove
and it's concrete subclassSpecialKangaMove
are tested method-wise.
/**
* Unit tests for the SpecialKangaMove class.
* These tests use Mockito to mock the behaviour of dependent components (e.g., CombatStatsComponent).
*/
class SpecialKangaMoveTest {
private SpecialKangaMove specialKangaMove;
private CombatStatsComponent mockTargetStats;
private CombatStatsComponent mockAttackerStats;
/**
* Initial setup before each test. Creates an instance of SpecialKangaMove and
* mocks the necessary dependencies.
*/
@BeforeEach
void setUp() {
// Create an instance of SpecialKangaMove with a mock move name and stamina cost.
specialKangaMove = new SpecialKangaMove("Kanga Rage", 20);
// Mock the target and attacker stats (CombatStatsComponent).
mockTargetStats = mock(CombatStatsComponent.class);
mockAttackerStats = mock(CombatStatsComponent.class);
}
/**
* Test to verify that the applyDebuffs method correctly applies the debuff to the target
* by reducing strength and defense, and applies a random status effect.
*/
@Test
void testApplyDebuffs() {
// Act: Apply the debuffs to the target stats.
specialKangaMove.applyDebuffs(mockTargetStats);
// Assert: Verify that the target's strength and defense are decreased.
verify(mockTargetStats).addStrength(-15);
verify(mockTargetStats).addDefense(-15);
// Capture the added status effect (CONFUSION or BLEEDING).
ArgumentCaptor<CombatStatsComponent.StatusEffect> statusCaptor = ArgumentCaptor.forClass(CombatStatsComponent.StatusEffect.class);
verify(mockTargetStats).addStatusEffect(statusCaptor.capture());
CombatStatsComponent.StatusEffect appliedEffect = statusCaptor.getValue();
assertTrue(appliedEffect == CombatStatsComponent.StatusEffect.CONFUSION ||
appliedEffect == CombatStatsComponent.StatusEffect.BLEEDING,
"Random status effect should be CONFUSION or BLEEDING.");
}
/**
* Test to verify that the applyBuffs method correctly buffs Kanga's strength
* and defense by the expected amounts.
*/
@Test
void testApplyBuffs() {
// Act: Apply the buffs to the attacker's stats.
specialKangaMove.applyBuffs(mockAttackerStats);
// Assert: Verify that the attacker's strength and defense are increased.
verify(mockAttackerStats).addStrength(15);
verify(mockAttackerStats).addDefense(10);
}
/**
* Test to ensure that the logger outputs the correct message when applyDebuffs is called.
* We can test the side effects (logging) of the method using Mockito's verification features.
*/
@Test
void testApplyDebuffsLogsCorrectMessage() {
// Act: Apply the debuffs to trigger the logger.
specialKangaMove.applyDebuffs(mockTargetStats);
// Since logger is static and logs to output, here we focus on behaviour verification (mock calls).
verify(mockTargetStats).addStrength(-15);
verify(mockTargetStats).addDefense(-15);
verify(mockTargetStats, times(1)).addStatusEffect(any(CombatStatsComponent.StatusEffect.class));
}
/**
* Test to ensure that the logger outputs the correct message when applyBuffs is called.
* Again, this is focused on verifying behaviour and state, not direct logging output.
*/
@Test
void testApplyBuffsLogsCorrectMessage() {
// Set up mock stats to return specific values.
when(mockAttackerStats.getStrength()).thenReturn(30);
when(mockAttackerStats.getDefense()).thenReturn(20);
// Act: Apply the buffs to trigger the logger.
specialKangaMove.applyBuffs(mockAttackerStats);
// Assert: Verify that the logger logs the correct message for buffs.
verify(mockAttackerStats, times(1)).addStrength(15);
verify(mockAttackerStats, times(1)).addDefense(10);
}
}