Story, Revival , Defense and Loot Generation Sprint 3 - UQcsse3200/2026-studio-1 GitHub Wiki

Story, Revival , Defense and Loot Generation Sprint 3

Overview

Sprint 3's main feature is Weapon Scaling and Upgrades. On the loot side, this meant three things:

  1. Weapon rarity comes from the tier system. The loot table now reads each tier's weight from WeaponTier, so new weapon types and tiers appear in loot automatically.
  2. Upgrade Stones. A new loot item that triggers the weapon upgrade, so the upgrade progression can actually be used in game.
  3. Death loot for Hero Revival. When the hero dies, everything they carried is dropped where they died, so the next hero can go back for it.

For how loot is placed in a level (ground tiles, seeds, the starter row), see Loot Generation Sprint 2. That part is unchanged.

Weapon Rarity From the Tier System

In Sprint 2, LootTable kept its own copy of the tier weights ({60, 30, 10}). Changing the weights in WeaponTier had no effect on loot.

Now LootTable.createDefault() builds the weapon entries straight from the tier system:

  • It loops over every WeaponType and every WeaponTier.
  • Each entry's weight is WeaponTier.getLootWeight() (currently 60, 30 and 10), so a tier 3 weapon is about one in ten weapon drops.
  • A new weapon type added to WeaponType, or a new tier added to WeaponTier, shows up in the loot table with no change to LootTable.

Potions keep their own tier weights (POTION_TIER_WEIGHTS, also 60/30/10). Their strength is scaled by ConsumableGenerator, not by weapon tiers, so adding a weapon tier should not also create a new potion tier.

The standard table now holds:

Entry Tiers Weight
Each potion (5 types) 1, 2, 3 60 / 30 / 10
Each weapon (sword, bow, dagger) every WeaponTier WeaponTier.getLootWeight()
Upgrade Stone 1 only 40
Shield none 10

Rolls are still seeded, so the same seed gives the same loot.

Upgrade Stones

Weapon upgrades are worked out by WeaponUpgrader (see the weapon tiers work in #214), but nothing in the game called it. The Upgrade Stone is the in-game trigger.

How the player uses it

  1. Upgrade Stones drop from the loot table. They are rarer than any single potion (weight 40, compared with 100 for each potion type across its tiers). One also appears in the starter loot row, which spawns one of every consumable.
  2. The player holds the weapon they want to upgrade, then presses the stone's number key.
  3. The weapon goes up one tier, and the player is holding the upgraded weapon straight away. The weapon HUD and in-hand sprite update automatically.

Examples:

  • Bow: tier 1 fires 1 arrow, tier 2 fires 5, tier 3 fires 10.
  • Sword: each tier has more damage, reach and knockback.
  • Dagger: a dagger turns into a sword on its first upgrade (tier 1 dagger, then tier 2 sword, then tier 3 sword).

A stone used on the tier 1 bow: the HUD shows a tier 2 bow, and one shot fires 5 arrows in a spread.

Tier 2 bow firing five arrows

A stone used on 20 tier 1 daggers: they become 20 tier 2 swords, split into two stacks of 10 because a sword stack holds 10.

Daggers upgraded into two stacks of tier 2 swords

Rules

  • One stone upgrades the whole stack. 20 tier 1 daggers become 20 tier 2 swords, not one sword.
  • The stone is never wasted. Like a health potion at full health, the stone stays in the inventory if:
    • the weapon is already at its highest tier,
    • no weapon has been held yet, or the held weapon has since been dropped or thrown,
    • there is not enough room for the upgraded stack. For example, 20 daggers fit in one slot, but 20 swords need two because a sword stack holds 10.

How it works

The stone is a consumable, so pickup, stacking, dropping on death and saving all work the same way as potions.

flowchart TD
    A[Player holds a weapon] --> B[ConsumableUseComponent remembers that slot]
    B --> C[Player presses the stone's number key]
    C --> D[The stone's slot is selected, then useItem fires]
    D --> E[WeaponUpgradeEffect looks up the remembered weapon slot]
    E --> F{Weapon there, not max tier, enough room?}
    F -- no --> G[Stone is kept]
    F -- yes --> H[WeaponUpgrader upgrades each weapon in the stack]
    H --> I[Upgraded weapons go back into the inventory and are selected]
    I --> J[Stone is used up, weaponUpgraded event fires]
Loading

Why the stone needs to remember the weapon: pressing a number key both selects that slot and uses the item in it. By the time the stone is used, the stone's own slot is selected. ConsumableUseComponent listens for activeSlotChanged and remembers the last slot that held a weapon, and that is the weapon the stone upgrades.

Why weapons are added one at a time: when the inventory splits a large quantity across several slots, it builds the extra stacks as plain items rather than weapons. Upgrading and adding each weapon separately keeps every stack a real WeaponItem.

Class Responsibility
WeaponUpgradeEffect The stone's effect: upgrades the held weapon stack with WeaponUpgrader and puts it back in the inventory
ConsumableUseComponent Uses consumables, and now remembers the last weapon slot the player selected
ConsumableType.UPGRADE_STONE The stone's type and sprite. isPotion() separates it from the potions
LootTable Adds the stone once at tier 1 with weight 40

Death Loot (Hero Revival)

Hero Revival is a core loop in Sprint 3: the hero dies, their loot drops at the death spot, a new hero spawns, and the player can travel back to collect the old hero's loot.

The death drop is done by DeathLootDropComponent on the player (merged in #263):

  • On the death event, every inventory slot, all gold and any held shield are dropped as loot at the death spot, and the inventory is emptied so nothing is duplicated.
  • The drop happens only once, even though death can fire several times for one death (CombatStatsComponent fires it on every hit at zero health, and DeathStateComponent fires it again).
  • The drop waits until after the current physics step. Death can be triggered from inside a Box2D collision callback, such as an enemy's touch attack, and the physics world is locked during that callback, so creating loot bodies there would fail.
  • On Try Again, the dead hero is removed and a brand-new hero is created in the same room, so it starts with a fresh inventory, not the old one. Because the room is kept, the dropped loot stays where the hero died. Dropped loot never despawns.

The new hero walking back to the previous hero's loot, still lying where they died:

Dropped loot at the death spot

The loot-side design for this was worked out in #258, which was closed once #263 delivered the same behaviour.

Testing

  • LootTableTest: weapon drops follow the WeaponTier weights (within 5%), every weapon type can be found at every tier, every rolled weapon has the damage, attack speed, knockback and range its tier defines, higher tiers are rarer, the same seed rolls the same loot, and the Upgrade Stone drops only at tier 1 and less often than a tier 1 health potion.
  • WeaponUpgradeEffectTest (13 tests), using the same select-then-use flow as the keyboard:
    • the held weapon goes up one tier, the stone is used up, and the weapon is selected again
    • the bow gets more arrows
    • the weapon selected before the stone is the one upgraded
    • every weapon in a stack is upgraded, and daggers turning into swords split into two real weapon stacks
    • the stone is kept at max tier, when no weapon was held, when the held weapon is gone, and when there is no room
    • the weaponUpgraded event fires
  • ConsumableEffectIntegrationTest: every potion still affects the player. The stone is skipped there because it acts on a weapon.
  • DeathLootDropComponentTest: inventory and gold drop on death, repeated death events drop only once, and missing components do not throw.
  • In-game playtest on main after the Upgrade Stone merged: the tier 2 bow fires 5 arrows, 20 daggers become 20 tier 2 swords, dying drops every stack and all gold at the death spot, and the revived hero (with a fresh starter kit) walks back and collects them.

Known Limitations

  • Gold over 99 is cut down on death. ItemDropComponent.dropGold() builds the gold pile with a maximum stack of 99, so a hero who dies with more than 99 gold loses the rest. The player starts with 50 gold, so this is reachable. Fix: use the gold amount as the pile's maximum stack size.
  • Death loot piles share one spot. Each stack is dropped at the same position beside the hero, so the piles overlap.
  • Death loot is not tied to its room. Dropped loot is registered directly with the entity service rather than with the room. If the player leaves the room before collecting it, it is not cleaned up with the room, so it can appear at the same coordinates in the next room.
  • The Upgrade Stone sprite is a placeholder (a 32x32 purple gem with a gold arrow).

Weapon Tiers, Scaling and Upgrades

Sprint 3 expanded the existing weapon tier system so that higher tiers provide meaningful changes to weapon statistics and behaviour. The work focused on Tier 1–3 progression, tier-based stat scaling, projectile-count scaling, weapon upgrades, weapon transformations and balancing.

Tier-Based Weapon Scaling

Weapon tier information is centralised through WeaponTier, WeaponStats and WeaponItem. The tier system supports weapon properties including damage, attack speed, range, knockback, projectile count and weapon form.

Keeping these values within the tier/stat system allows the other weapon systems to retrieve the appropriate statistics for the weapon's current tier.

Bow Projectile Scaling

Projectile count was added as a tier-dependent weapon statistic.

Bow Tier Projectile Count
Tier 1 1
Tier 2 5
Tier 3 10

getProjectileCount() exposes the projectile count through the weapon tier/item system so that the combat implementation can retrieve the appropriate value for the current bow tier.

This allows bow upgrades to change attack behaviour rather than only increasing numerical statistics.

Weapon Upgrade Progression

WeaponUpgrader implements progression between weapon tiers:

Tier 1 → Tier 2 → Tier 3

When a weapon is upgraded, the next tier determines the statistics and behaviour used by the other weapon systems.

The upgrade system also supports the agreed dagger-to-sword transformation:

Tier 1 Dagger → Tier 2 Sword → Tier 3 Sword

The Upgrade Stone described earlier on this page provides the in-game trigger for the upgrade, while WeaponUpgrader contains the underlying tier-progression logic.

Bug Fixes and Balancing

Dagger Tier Scaling

Fixed dagger statistics that were incorrectly hardcoded to Tier 1. Damage, attack speed, knockback and range now use the dagger's actual tier statistics.

The dagger upgrade path was also corrected so that the first upgrade transforms a Tier 1 Dagger → Tier 2 Sword, followed by a Tier 3 Sword, matching the agreed Sprint 3 design.

Weapon HUD Update

Fixed the weapon HUD so that it refreshes correctly when switching between sword, bow and dagger. The HUD label colour was also changed from unreadable dark text to white to improve visibility.

Bow Damage Balancing

Playtesting identified that higher-tier bows produced excessive total damage when combined with multi-projectile scaling.

Bow damage-per-arrow was rebalanced from 70/140/210 to 10/20/30 across Tier 1–3 so that the increased projectile count did not make higher-tier bows disproportionately powerful.

System Integration

The tier and upgrade system integrates with the other Sprint 3 weapon features:

  • Combat: reads tier-dependent weapon statistics and projectile counts.
  • Loot: uses weapon tier information for weapon generation and rarity.
  • Upgrade Stones: trigger progression through WeaponUpgrader.
  • Inventory/HUD: reflects the currently equipped/upgraded weapon and its tier.
  • Rendering: uses weapon tier information to provide visual feedback for upgraded weapons.

Simplified UML - Weapon Tier and Upgrade System

classDiagram
    class WeaponStats {
        <<interface>>
        +getProjectileCount()
    }

    class WeaponTier {
        <<enumeration>>
        TIER_1
        TIER_2
        TIER_3
    }

    class WeaponItem {
        -WeaponStats weaponStats
        +getProjectileCount()
    }

    class WeaponUpgrader {
        +upgradeWeapon()
    }

    WeaponTier ..|> WeaponStats : provides tier stats
    WeaponItem --> WeaponStats : uses
    WeaponUpgrader --> WeaponItem : upgrades
Loading

Upgrade Flow

flowchart LR
    A[Weapon Item] --> B[Current Tier]
    B --> C{Maximum Tier?}
    C -->|No| D[WeaponUpgrader]
    D --> E[Next Tier]
    E --> F[Updated Weapon Stats]
    F --> G[Combat]
    F --> H[Inventory / HUD]
    F --> I[Rendering]
    C -->|Yes| J[Keep Current Tier]
Loading

Testing

Testing covered:

  • Dagger damage, attack speed, knockback and range scaling across tiers.
  • Tier 1, Tier 2 and Tier 3 weapon progression.
  • Bow projectile-count scaling of 1 → 5 → 10.
  • Sword, bow and dagger upgrade paths.
  • Maximum-tier upgrade rejection.
  • Null-input handling for weapon upgrades.
  • Dagger-to-sword transformation.
  • Bow damage balancing through in-game playtesting.
  • Weapon HUD updates when switching between sword, bow and dagger.
  • Compatibility and integration testing with combat, loot, inventory and rendering.
  • Regression testing after Sprint 3 integration.

Relevant automated testing included:

  • WeaponTierTest for tier statistics and projectile-count scaling.
  • WeaponItemTest for weapon item behaviour.
  • WeaponUpgraderTest for weapon upgrade progression, upgrade paths, maximum-tier rejection and null-input handling.

Manual gameplay testing was also performed to verify weapon switching/HUD updates, bow damage balancing, projectile progression and dagger-to-sword upgrade behaviour.

The resulting system provides Tier 1–3 weapon progression where upgrades can affect statistics, projectile count and weapon form while keeping tier and upgrade information centralised for use across the game's weapon systems.

Story, Revival & Weapon Visual Systems – Sprint 3

Overview

For Sprint 3, my main contributions focused on two areas:

  1. Story and Cutscene System
  2. Weapon Rendering, Visuals and Animations

The Story/Cutscene system provides a reusable framework for presenting narrative sequences and integrating them with the existing gameplay and revival flow.

The Weapon Rendering system displays the player's currently equipped weapon with correct positioning, animations, weapon types and tier-based visual scaling.


1. Story / Cutscene System

1.1 Purpose

The Story/Cutscene system provides a reusable framework for creating and displaying narrative sequences within the game.

The system supports:

  • Multiple scenes within a cutscene
  • Sequential scene progression
  • Scene text and background images
  • Player input for progressing through scenes
  • Opening story sequences
  • After-death story sequences
  • Integration with the existing gameplay and revival flow

The core framework was designed so that additional story sequences can be added without changing the overall cutscene architecture.

Core Story/Cutscene Framework

View Commit


1.2 Story Flow

Opening Story

The opening story is presented before the player enters gameplay.

Main Menu
    |
    v
Opening Story Cutscene
    |
    v
Gameplay

The opening sequence introduces the game's narrative before the player begins the main gameplay experience.

Opening Story Commit

View Commit


After-Death Story

The after-death cutscene was integrated into the existing death, loot and revival flow.

Hero Dies
    |
    v
Loot Drops
    |
    v
After-Death Cutscene
    |
    v
Death Screen
    |
    v
Try Again / Revival
    |
    v
New Hero
    |
    v
Gameplay

The after-death cutscene is presented after the player's death and loot-drop process, before the existing revival flow continues.

After-Death Story Commit

View Commit

Death and Revival Integration Commit

View Commit


1.3 Story Components

Component Responsibility
StoryCutscene Manages a sequence of story scenes and controls scene progression
StoryScene Represents an individual scene within a cutscene
StoryCutsceneScreen Displays the cutscene as a game screen
StoryCutsceneInputComponent Handles input used to progress through the cutscene
Story display components Present the scene text and visual content

The framework separates the story content, scene sequencing, screen presentation and input handling. This allows individual scenes to be changed or additional cutscenes to be created without redesigning the entire system.


1.4 Opening Cutscene

The opening cutscene consists of multiple narrative scenes that introduce the game's story and transition the player into gameplay.

The opening sequence was implemented using the reusable StoryCutscene and StoryScene framework.

Relevant Commits

Story/Cutscene Framework

View Commit

Opening Story Cutscene

View Commit


1.5 After-Death Cutscene

The after-death cutscene provides additional narrative progression after the player's character dies.

The sequence contains four narrative stages:

THE FALL
    |
    v
THE LEGEND
    |
    v
THE NEXT HERO
    |
    v
THE JOURNEY CONTINUES

The after-death sequence was implemented as part of the existing death and revival flow rather than replacing the existing death screen or revival functionality.

After-Death Cutscene

View Commit

Revival Flow Integration

View Commit


2. Weapon Rendering, Visuals & Animations

2.1 Purpose

The weapon rendering system is responsible for displaying the player's currently equipped weapon separately from the main player sprite.

The system supports:

  • Sword rendering
  • Bow rendering
  • Dagger rendering
  • Weapon switching
  • Correct in-hand positioning
  • Player-facing direction
  • Weapon attack animations
  • Tier-based weapon visuals
  • Tier-based visual scaling
  • Tier 2 and Tier 3 sword textures

The rendering system focuses on the visual representation of weapons, while gameplay behaviour such as damage, projectile spawning and attack effects remains handled by the combat systems.


2.2 Weapon Rendering Flow

Inventory / Equipped Weapon
            |
            v
   WeaponRenderComponent
            |
            v
     Identify Weapon Type
            |
            v
         Identify Tier
            |
            v
     Select Visual Config
            |
            v
       Select Texture
            |
            v
   Position / Scale / Rotation
            |
            v
      Render Weapon

This separates the visual representation of weapons from the underlying combat logic.


2.3 Supported Weapon Types

Weapon Visual Behaviour
Sword Rendered beside the player and visually swings during attacks
Bow Rendered beside the player with a draw and release animation
Dagger Rendered beside the player with a throwing animation

The renderer updates the displayed weapon according to the currently equipped weapon.


2.4 Weapon Positioning

Weapon positioning was adjusted so that equipped weapons appear correctly in the player's hands.

The rendering system accounts for:

  • Player-facing direction
  • Hand position
  • Weapon dimensions
  • Weapon-specific offsets
  • Weapon rotation during attacks
  • Weapon scale

The hand position was refined through manual gameplay testing to ensure that the weapons visually align with the player.

Weapon Positioning

View Commit


3. Tier-Based Weapon Visuals

3.1 Tier Scaling

The weapon rendering system supports different visual sizes for different weapon tiers.

For the sword:

Tier Texture Visual Scale
Tier 1 sword.png 1.00x
Tier 2 sword_t2.png 1.20x
Tier 3 sword_t3.png 1.45x

This allows upgraded weapons to have a visually stronger presence in addition to their gameplay upgrades.


3.2 Tier 2 and Tier 3 Sword Assets

Separate sword textures were added for Tier 2 and Tier 3 weapons.

Tier 1
sword.png

Tier 2
sword_t2.png

Tier 3
sword_t3.png

The additional textures were also included in the game's resource loading so that they can be displayed during gameplay.

Tier 2 and Tier 3 Sword Visuals

View Commit


3.3 Tier Visual Selection

The renderer determines the appropriate sword texture based on the equipped weapon's tier.

Equipped Sword
      |
      v
 Check Weapon Tier
      |
   +--+--+
   |  |  |
   v  v  v
  T1 T2 T3
   |  |  |
   v  v  v
sword.png  sword_t2.png  sword_t3.png
   |  |  |
   +--+--+
      |
      v
 Apply Tier Scale
      |
      v
  Render Weapon

The tier-based visual scaling is covered by automated tests.

Tier Visual Scaling Tests

View Commit


4. Weapon Animations

The weapon renderer provides visual animations for the different weapon types.

4.1 Sword Animation

Sword Idle
    |
    v
Sword Attack
    |
    v
Swing Animation
    |
    v
Sword Idle

The sword visually swings when an attack is performed.


4.2 Bow Animation

Bow Idle
    |
    v
Bow Draw
    |
    v
Bow Release
    |
    v
Bow Idle

The bow visually draws and releases during the attack.


4.3 Dagger Animation

Dagger Idle
    |
    v
Dagger Throw
    |
    v
Dagger Idle

The dagger uses a throwing animation to visually represent its attack.

The animations represent the visual side of the attacks. The actual gameplay behaviour, including damage, projectile spawning and attack effects, is handled by the combat systems.


5. Integration With Existing Systems

5.1 Story System Integration

The Story/Cutscene system integrates with the existing game flow.

Main Menu
    |
    v
Opening Story Cutscene
    |
    v
Gameplay
    |
    v
Death Detection
    |
    v
Loot Drop
    |
    v
After-Death Story Cutscene
    |
    v
Death Screen
    |
    v
Revival
    |
    v
Gameplay

The after-death cutscene was added without removing the existing death screen or revival functionality.

Death and Revival Integration

View Commit


5.2 Weapon System Integration

The weapon renderer integrates with the player's inventory and equipped weapon state.

Player Inventory
       |
       v
Equipped Weapon
       |
       v
WeaponRenderComponent
       |
   +---+---+
   |   |   |
   v   v   v
 Sword Bow Dagger
   |   |   |
   +---+---+
       |
       v
Visual Rendering
       |
       v
     Player

The renderer updates when the equipped weapon changes, allowing the correct weapon to be displayed during gameplay.


6. Testing

6.1 Story / Cutscene Testing

The Story/Cutscene system was tested for:

  • Correct scene ordering
  • Scene progression
  • Scene resetting
  • Final-scene behaviour
  • Empty cutscene handling
  • Correct number and ordering of after-death scenes
  • Opening cutscene transition into gameplay
  • After-death cutscene integration with the death and revival flow

Story Framework Tests

View Commit

After-Death Cutscene Tests

View Commit


6.2 Weapon Rendering Testing

The weapon rendering system was tested for:

  • Rendering the equipped weapon
  • Stopping rendering after the selected weapon is dropped
  • Tier 1 sword texture selection
  • Tier 2 sword texture selection
  • Tier 3 sword texture selection
  • Correct tier-based visual scaling
  • Weapon switching
  • Weapon positioning
  • Attack animations
  • Resource loading for Tier 2 and Tier 3 sword textures

Weapon Visual Scaling Tests

View Commit

Tier 2/3 Sword Assets and Resource Loading

View Commit


6.3 Manual Testing

Manual gameplay testing was performed to verify:

  • Opening cutscene presentation
  • Transition from the opening cutscene into gameplay
  • Player death behaviour
  • Loot dropping before the after-death cutscene
  • After-death cutscene presentation
  • Revival after the cutscene
  • Sword, bow and dagger rendering
  • Weapon switching
  • Weapon positioning relative to the player
  • Tier 2 and Tier 3 sword visuals
  • Weapon attack animations
  • Integration with the Sprint 3 combat systems

7. System Overview

7.1 Story / Cutscene Architecture

MainGameScreen
      |
      v
StoryCutsceneScreen
      |
      v
StoryCutscene
      |
      v
StoryScene

StoryCutsceneInputComponent
      |
      v
Advances StoryCutscene

The StoryCutscene manages the sequence of scenes, while StoryScene represents the individual narrative elements. The screen and input components provide the presentation and interaction layer.


7.2 Weapon Rendering Architecture

Player Inventory
      |
      v
Equipped Weapon
      |
      v
WeaponRenderComponent
      |
   +--+--+--+
   |  |  |
   v  v  v
Sword Bow Dagger
   |  |  |
   v  v  v
T1/T2/T3  Draw/Release  Throw
   |  |  |
   +--+--+
      |
      v
Visual Rendering
      |
      v
    Player

8. Key Contributions

The Sprint 3 implementation resulted in the following additions:

  • Reusable Story/Cutscene framework
  • Opening story cutscene
  • After-death story cutscene
  • Integration of the after-death cutscene with the death and revival flow
  • Equipped weapon rendering
  • Sword, bow and dagger visual support
  • Weapon switching visuals
  • Correct in-hand weapon positioning
  • Sword attack animation
  • Bow draw animation
  • Dagger throw animation
  • Tier-based weapon visual scaling
  • Tier 2 and Tier 3 sword textures
  • Automated tests for story and weapon rendering functionality
  • Manual integration testing across the Sprint 3 systems

Overall, the implementation separates narrative presentation, weapon visualisation and gameplay mechanics, allowing these systems to integrate with the existing game architecture without duplicating the underlying gameplay logic.

Defense Mechanism

Overview

This feature introduces two new defensive/gameplay mechanics to the player:

Ballistic Shield — a stronger defensive shield that is available as a rare loot and can be activated with B when the player has obtained one. Enemy Bribe — allows the player to bribe an enemy that attacked them, temporarily preventing that enemy from continuing its attack.

Both mechanics were implemented as part of the player's combat and defensive systems and integrated with the game's configurable keybind system.

Ballistic Shield

Purpose

The Ballistic Shield provides the player with an additional defensive option during combat. Unlike the standard shield, the Ballistic Shield can not only block the incoming damage but also retaliate 25% of the damage back to the enemy.

The mechanic was designed to give the player a strategic defensive option when facing stronger or multiple enemies.

Gameplay Behaviour

When the player presses the B key:

The game checks whether the player currently has a Shield. If a Ballistic Shield is available, it is activated. If no Ballistic Shield is available, the normal shield is checked instead. The Ballistic Shield activation is handled by the dedicated BallisticShieldComponent.

This allows the same player control to work with both the normal shield and the upgraded Ballistic Shield.

Implementation

The Ballistic Shield functionality is implemented using a dedicated BallisticShieldComponent.

The Ballistic Shield component provides functionality for determining whether the player has a shield available and activating it when requested.

The implementation also uses the game's event system to trigger shield-related behaviour, keeping the input handling separate from the actual shield mechanics.

Visual Asset

A dedicated Ballistic Shield visual asset was created and integrated into the game so that the item can be visually represented during gameplay.

The asset was added alongside the gameplay implementation in:

https://github.com/UQcsse3200/2026-studio-1/commit/fea54660

Enemy Bribe

Purpose

The Enemy Bribe mechanic provides an alternative to directly fighting an enemy. After an enemy attacks the player, the player can use the bribe action to temporarily stop that enemy from attacking.

This introduces another strategic option into combat, allowing the player to avoid or delay an encounter rather than relying entirely on attacking or shielding.

Gameplay Behaviour

When the player presses the bribe key:

The input system detects the configured bribe key. The player's PlayerActions component attempts to bribe the attacker. The relevant enemy's melee attack component is identified. The enemy enters a bribed state. Its current attack/wind-up is cancelled. The enemy remains bribed for a fixed duration. After the duration expires, the enemy can return to its normal behaviour.

The bribe duration is currently 20 seconds.

Implementation

The bribe functionality is connected through the player action system.

The input flow is:

Bribe Key → PlayerActions.bribeLastAttacker() → Enemy Bribe → MeleeAttackComponent.bribe()

The MeleeAttackComponent maintains the bribed state and the time at which the bribe expires.

When an enemy is bribed:

bribed is set to true. A 20-second expiration time is calculated. Any pending attack target is cleared. The current attack wind-up is cancelled. An enemyBribed event is triggered.

This keeps the temporary state within the enemy's melee attack component rather than placing enemy-specific combat logic inside the keyboard input component.

Keybind Integration

Both mechanics were integrated with the game's configurable keybind system.

image

The implementation uses KeybindSettings rather than hard-coding the controls directly into the gameplay logic. This allows the controls to remain compatible with the game's keybind configuration system.

The shield keybind was also added to the settings display so that the player can see the assigned control.

Keybind display commit: https://github.com/UQcsse3200/2026-studio-1/commit/63167f79

Design Decisions

Reusing the Shield Key

The Ballistic Shield was integrated into the existing shield control rather than introducing another key specifically for the Ballistic Shield.

This makes the control scheme simpler for the player:

B = Shield

The game determines which shield behaviour should be used based on whether a Ballistic Shield is available.

Temporary Bribe State

The bribe effect is intentionally temporary rather than permanently changing an enemy's behaviour.

A fixed duration of 20 seconds was selected so that the mechanic provides meaningful breathing room without permanently removing an enemy from combat.

Separation of Responsibilities

The implementation separates input, player actions, and enemy behaviour:

Keyboard Input → detects the player's key press

PlayerActions → performs the requested player action

MeleeAttackComponent → manages the enemy's bribed state and attack behaviour

This prevents the keyboard input component from containing enemy-specific gameplay logic.

Event Flow

Ballistic Shield

Player presses B ↓ KeyboardPlayerInputComponent ↓ Check for Ballistic Shield ↓ BallisticShieldComponent ↓ Activate Ballistic Shield

If no Ballistic Shield is available:

Player presses B ↓ Check for Ballistic Shield ↓ No Ballistic Shield ↓ Activate normal Shield

Enemy Bribe

Player presses R ↓ KeyboardPlayerInputComponent ↓ PlayerActions.bribeLastAttacker() ↓ Identify last attacking enemy ↓ MeleeAttackComponent.bribe() ↓ Enemy enters bribed state ↓ 20-second duration ↓ Enemy can return to normal behaviour

Implementation Commit

The main implementation of both mechanics is contained in the following commit:

https://github.com/UQcsse3200/2026-studio-1/commit/fea54660

Commit: fea54660 — Add ballistic shield and enemy bribe mechanics

The commit includes the implementation of the Ballistic Shield and Enemy Bribe gameplay functionality as well as the associated Ballistic Shield asset.

Testing

The mechanics were tested during gameplay to verify that:

Ballistic Shield

The shield key correctly activates the Ballistic Shield when one is available. The normal shield remains available when the player does not have a Ballistic Shield. The Ballistic Shield can be activated through the player input system. The shield behaviour integrates correctly with the existing combat system. The Ballistic Shield visual asset appears correctly in-game.

Enemy Bribe

The bribe key correctly triggers the bribe action. The correct attacking enemy is identified. The enemy enters the bribed state. The enemy's current attack is interrupted. The bribe lasts for the intended 20-second duration. The enemy can resume normal behaviour after the bribe expires.

image
⚠️ **GitHub.com Fallback** ⚠️