Repository navigation
Mini Boss 1: Cerberus
Cerberus is a three-headed mini boss with independent head health, tethered movement and phase-based attacks.
The middle head also acts as the main body. The left and right heads are separate entities attached to it. Each head owns a different attack, which becomes unavailable when that head dies.
When the combined health of all three heads reaches 50% or below, Cerberus enters Phase 2. Living heads display a pulsing red aura, and attacks can run concurrently while retaining their individual cooldowns.
| Head | Health | Ability | Behaviour |
|---|---|---|---|
| Left | 125 | Dark Mist | Creates a temporary mist area at the player’s position when cast. |
| Middle / Body | 250 | Lunge and Bite | Winds up, lunges towards a locked destination and can damage the player once per attack. |
| Right | 125 | Homing Projectile | Fires projectiles that continuously adjust their direction towards the player. |
The default combined health is 500.
The middle head’s health and base attack are read from the cerberus configuration in NPCs.json. Each side head receives half the configured middle-head health.
The default middle-head attack damage is 20. The right head supplies 10 as projectile damage.
The left head’s mist applies a movement-speed multiplier of 0.5 and doubles incoming damage while the player remains inside the area. CerberusMistComponent handles mist placement, duration, visuals, and entry/exit events. PlayerCerberusMistDebuffComponent connects those events to the player’s status effects.
The effects are removed when the player leaves the mist or when the mist is cleared. Re-entering the same mist does not stack its effects.
| Class | Responsibility |
|---|---|
| CerberusFactory | Creates the three heads and connects their components to a shared attack coordinator. |
| CerberusDeathComponent | Preserves the main body until all heads have died. |
| CerberusMovementComponent | Controls normal pursuit within the tethered area and gives bite movement priority. |
| ChainRestrictionComponent | Restricts the main body to a fixed radius around its anchor. |
| HeadAttachmentComponent | Positions each side head relative to the main body. |
| CerberusBiteComponent | Controls windup, lunge, damage and cooldown. |
| CerberusMistComponent | Controls mist duration, area detection, rendering and entry/exit events. |
| CerberusProjectileComponent | Controls projectile cooldown, deferred creation and cancellation. |
| HomingProjectileMovementComponent | Moves projectiles towards the target with a travel-distance limit. |
| CerberusPhaseComponent | Detects the combined-health threshold and starts Phase 2. |
| CerberusAttackCoordinator | Controls sequential attacks in Phase 1 and concurrent attacks in Phase 2. |
| CerberusEnrageVisualComponent | Renders a red aura around each living, enraged head. |
| CerberusMistSlowEffect | Applies a 0.5 multiplier to effective movement speed while the mist remains active. |
| PlayerCerberusMistDebuffComponent | Listens for mist entry/exit events and adds or removes the player's mist effects. |
| CerberusLayeredRenderComponent | Renders the body and three head layers, controls their animations and hides dead heads independently. |
| CerberusProjectileFactory | Creates animated homing fireballs with the existing movement, lifetime and contact-damage behaviour. |
| CerberusChainComponent | Stores the fixed wall anchor and calculates the attachment point on the moving body. |
| CerberusChainRenderComponent | Draws repeated chain links along a sagging path between the wall and body. Unregisters when the main entity is disposed. |
Cerberus-specific components are grouped in the com.csse3200.game.components.miniboss.cerberus package.
Each head has its own CombatStatsComponent.
- Left-head death: clears the active mist and prevents further mist casts.
- Middle-head death: disables bite attacks and stops body movement. The main body remains available as the attachment parent for surviving side heads.
- Right-head death: prevents further firing and cancels queued projectile creation.
- All three heads dead: CerberusDeathComponent schedules disposal of the main body.
Side heads use EnemyDeathComponent(false) for their own disposal. A dying head also releases its attack opportunity so it does not block the remaining heads.
The main body follows the player within a circular area centred on a fixed movement anchor. The current movement radius is 3 world units.
CerberusMovementComponent limits the pursuit destination, while ChainRestrictionComponent corrects positions outside the boundary and removes outward velocity.
The visible chain uses a separate wall anchor. This anchor controls where the chain is drawn; it does not replace the existing movement anchor or change the movement boundary.
The main body uses a 2×2 world-unit scale. Side-head entities retain independent health and hitboxes, while their images are drawn by the main body's layered renderer.
Current side-head position offsets relative to the main entity's bottom-left position are:
| Head | Offset |
|---|---|
| Left | (0.2825f, 0.95f) |
| right | (1.1575f, 0.95f) |
| -- | -- |
The chain attaches to the body at 50% of its width and 40% of its height. Its wall endpoint remains fixed while its body endpoint follows movement.
The chain remains after the middle head dies if either side head is still alive. It disappears when all three heads have died and the main entity is disposed.
The mist is created at the player’s centre position when cast. Its position remains fixed for that cast.
| Parameter | Value |
|---|---|
| Cooldown | 5 seconds |
| Duration | 3 seconds |
| Cast range | 7 world units |
| Area radius | 2 world units |
The component checks whether the player’s centre is inside the mist. Entering and leaving trigger events on the player, with the left-head entity supplied as the source.
The cooldown restarts when the mist expires. Head death, player death or component disposal clears an active mist and releases any current occupancy.
While the player remains inside the mist, PlayerCerberusMistDebuffComponent applies two shared status effects:
- Movement speed is multiplied by
0.5. - Incoming damage is doubled.
The effects are removed immediately when the player leaves the mist, the mist expires, the left head dies, the player dies, or the player debuff component is disposed. Re-entering the same mist does not stack the effects.
The attack follows these states:
READY → WINDUP → LUNGE → COOLDOWN → READY
| Parameter | Value |
|---|---|
| Trigger range | 2 world units |
| Hit range | 1.2 world units |
| Windup | 0.5 seconds |
| Lunge duration | 0.35 seconds |
| Cooldown | 2 seconds |
| Lunge movement speed setting | 6 |
| Default damage | 20 |
The destination is locked when windup begins and is constrained to the tethered area. During the lunge, damage can be applied once if the player is within hit range.
The attack is cancelled if the middle head or target dies.
| Parameter | Value |
|---|---|
| Cooldown | 2.5 seconds |
| Attack range | 7 world units |
| Projectile speed | 5 world units per second |
| Maximum travel distance | 7 world units |
| Projectile lifetime | 1.8 seconds |
| Default projectile damage | 10 |
Keep the existing projectile statistics and deferred-creation explanation. Replace the old factory reference with:
The right head creates fireballs through CerberusProjectileFactory.createHomingProjectile(). The factory uses images/cerberus/cerberus-fireball.atlas and retains HomingProjectileMovementComponent for tracking.
The projectile animation loops during flight. Reaching the travel-distance limit triggers projectileHit; this event is not a collision callback.
Fireballs retain the existing hitbox contact-damage behaviour. They do not automatically disappear on their first successful hit.
The coordinator prioritises heads in this order:
Left → Middle → Right → Left
Heads that are dead, cooling down or outside their attack range are skipped. Consequently, the visible attack order can vary, and the opening attack is not guaranteed to come from the left head.
An attack occupies its turn until:
- The mist expires or is cancelled.
- The bite finishes its lunge or is cancelled.
- The projectile creation task finishes or is cancelled.
An already-fired projectile can remain in flight during the next attack. Normal pursuit movement is not blocked solely because another head owns the attack turn.
The threshold uses all three heads:
Combined current health / Combined maximum health ≤ 0.5
Dead heads still contribute their maximum health to the denominator. With the default values, Phase 2 begins at 250 combined HP or below, provided some health remains.
The transition occurs only once. Healing does not return Cerberus to Phase 1.
During Phase 2:
- Different heads may attack concurrently.
- Individual cooldowns and range checks still apply.
- An attack already in progress is not restarted by the coordinator.
- Living heads display a pulsing red aura.
Cerberus uses images/cerberus/cerberus-modular.atlas and cerberus-modular.png.
CerberusLayeredRenderComponent draws four layers: body, left head, middle head and right head. Each layer has its own animation state. The factory connects the body's attackStart and default events to the body and middle-head lunge and idle animations.
Each head layer is connected to its corresponding CombatStatsComponent. A dead head becomes invisible independently, while the body remains visible until the complete boss is disposed.
Fireballs use a dedicated atlas containing flight and impact animations. The wall chain uses images/cerberus/cerberus-chain.atlas and repeated textured links.
The mist remains a purple area, and living enraged heads display pulsing red auras. Mist and aura textures are generated procedurally. The visual changes do not require modifications to the shared AnimationRenderComponent.
Entity cerberus = CerberusFactory.createCerberus( target, anchorPoint, wallAnchor, sideHeadSpawner, "images/cerberus/cerberus-modular.atlas");
anchorPoint is the centre of the existing movement restriction. wallAnchor is the fixed attachment point used by the visible chain.
The factory returns the main body and passes both side heads to sideHeadSpawner. The caller must spawn and track all three entities.
The overload without wallAnchor creates Cerberus without a visible chain. The overload without a target creates the three-head structure without target-dependent movement and attack components.
The room must load the modular, fireball and chain atlases before spawning the boss.
CerberusAttackCoordinator is a plain Java class shared by all three skills.
| Method | Purpose |
|---|---|
| register(Entity, BooleanSupplier) | Registers a head’s attack-readiness check. |
| tryStart(Entity) | Requests permission to begin an attack. |
| finish(Entity) | Releases an attack when it completes or is cancelled. |
Each skill connects to the coordinator through setAttackCoordinator(...), after it has been attached to its entity.
| Method | Purpose |
|---|---|
| CerberusPhaseComponent.getCurrentPhase() | Returns the current phase. |
| CerberusMistComponent.isMistActive() | Reports whether mist is active. |
| CerberusMistComponent.getMistCentre() | Returns a copy of the mist centre. |
| CerberusEnrageVisualComponent.isAuraActive() | Reports whether the head’s aura is active. |
| Event | Source | Purpose |
|---|---|---|
| updateHealth / updateMaxHealth | Each head’s combat stats | Re-evaluates the combined-health phase threshold. |
| entityDied | Each head | Cancels abilities and handles head lifecycle. |
| enragePhaseStarted | Phase component, on living heads | Announces entry into Phase 2. |
| biteWindup | Middle head | Announces bite windup. |
| attackStart | Middle head | Starts the bite attack animation. |
| default | Middle head | Returns to the default animation after lunge. |
| cerberusMistEntered / cerberusMistExited | Player event handler | Reports mist occupancy, with the left head as the source argument. |
| cerberusProjectileSpawned | Main body | Requests projectile spawning through the room manager. |
| projectileRangeReached | Projectile | Signals that its travel-distance limit has been reached. |
Cerberus currently spawns in Dungeon 1's end room. The visible chain attaches to the lower edge of wall tile (27, 32), centred horizontally within that tile.
This coordinate belongs to the current room layout. If the room layout changes, the wall attachment should be reviewed alongside the spawn position.
The chain is a render component on the main body, not a separate enemy, and does not affect the room's enemy count.
EnemyManagerComponent tracks all three heads as enemies. Each head is removed from enemy tracking when it dies.
Projectiles are spawned through a separate event callback and are not added to the active-enemy count. They therefore do not need to be defeated to clear the room.
The room clears only when all tracked enemies have died, including any surviving Cerberus heads.
| Test class | Main coverage |
|---|---|
| CerberusPhaseComponentTest | Combined-health threshold and one-way phase transition. |
| CerberusAttackCoordinatorTest | Turn order, readiness, death and concurrent attacks. |
| CerberusAttackCoordinationTest | Interaction between the three real skills and phase changes. |
| CerberusBiteComponentTest | Windup, damage, cooldown, cancellation and turn release. |
| CerberusMistComponentTest | Duration, occupancy, cleanup and attack coordination. |
| CerberusProjectileComponentTest | Deferred firing, cooldown, cancellation and coordination. |
| HomingProjectileMovementComponentTest | Homing movement and travel limits. |
| CerberusEnrageVisualComponentTest | Aura activation, independent death and disposal. |
| CerberusLayeredRenderComponentTest | Layered animation state and independent head visibility. |
| CerberusProjectileFactoryTest | Dedicated fireball construction and component setup. |
| CerberusChainComponentTest | Fixed wall anchor, defensive copying, body attachment and endpoint distance. |
| CerberusChainRenderComponentTest | Chain endpoints, approximate length, straight-path fallback and renderer disposal. |
| CerberusStatusEffectsTest | Shared enemy status-effect support on Cerberus parts. |
| ChainRestrictionComponentTest | Tether boundary behaviour. |
| HeadAttachmentComponentTest | Relative head positioning. |
| CerberusMistSlowEffectTest | Verifies that mist slows only movement speed. |
| PlayerCerberusMistDebuffComponentTest | Verifies slow, doubled incoming damage, immediate cleanup, no stacking and independent mist sources. |
| CerberusTest | Factory setup, animation events, head positioning and optional chain attachment. |
From the source directory on Windows PowerShell:
.\gradlew.bat :core:test --tests "com.csse3200.game.components.miniboss.cerberus.*" --tests "com.csse3200.game.entities.enemy.CerberusTest" --tests "com.csse3200.game.entities.factories.CerberusProjectileFactoryTest" --tests "com.csse3200.game.entities.factories.CerberusStatusEffectsTest" --tests "com.csse3200.game.components.ChainRestrictionComponentTest" --tests "com.csse3200.game.components.HeadAttachmentComponentTest" --tests "com.csse3200.game.components.player.PlayerCerberusMistDebuffComponentTest"
Run the complete core test suite with:
.\gradlew.bat :core:test
Launch Desktop and enter a room configured to spawn Cerberus.
- Confirm that three heads appear close together and use the default idle animation.
- Move away and verify that the body remains within its anchor radius.
- During Phase 1, verify that active mist prevents new bite and projectile attacks.
- Verify that other attacks resume after the mist expires.
- Reduce combined health to 50% or below and verify that living heads display red auras.
- Confirm that attacks can overlap in Phase 2 while still respecting cooldowns and range.
- Kill individual heads and verify that their abilities stop while surviving heads continue.
- Confirm that the room does not clear while tracked enemies remain alive.
<img width="4543" alt="mermaid-diagram-2026-10-07-233042" src="https://github.com/u
ser-attachments/assets/52cb62af-a96f-46a1-9166-8332cf4af936" />
The previous separate wolf sprites were replaced with a layered Cerberus appearance while retaining the independent three-head combat system. Side heads remain separate gameplay entities, and the main renderer combines their visuals into one boss.
A dedicated projectile factory separates Cerberus's fireball appearance from the ordinary ranged-enemy projectile factory.
The visible wall chain communicates the existing movement restriction. Its wall attachment and the movement-boundary centre remain separate so that adding the visual does not alter the established combat movement.