Skip to content

Player Inventory

Riki edited this page Oct 20, 2026 · 2 revisions

Player Inventory

Introduction

The Player Inventory System manages items owned by the player. It uses a slot-based grid to support item storage, stacking, selection, hotbar access, and inventory expansion.

By default, the inventory contains 3 rows × 8 columns (24 slots). The first row is used as the player's hotbar.


Key Components

InventoryComponent

The main component responsible for inventory state and operations, including:

  • Adding and removing items
  • Item selection
  • Item sorting by Itemid
  • Inventory capacity
  • Slot swapping and expansion

InventorySlot

Represents one physical inventory slot containing an ItemType and its quantity. Empty slots contain no item.

InventoryBarDisplay

Displays the first row of the inventory as the player's hotbar.

BackpackDisplay

Displays the complete inventory grid and selected item information.

PlayerInteractionComponent

Handles world-item pickup, automatic gold collection, and dropping or deleting the selected item stack.

GoldPickupComponent

Stores a world coin's gold value and prevents it from being collected more than once. Gold is managed as currency rather than occupying an inventory slot.


Implementation

The inventory stores its slots using:

List<InventorySlot> slots;

Items of the same ItemType are stacked together. New item types are placed into the first available empty slot.

The first inventory row acts as the hotbar:

┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 1  │ 2  │ 3  │ 4  │ 5  │ 6  │ 7  │ 8  │  Hotbar
├────┼────┼────┼────┼────┼────┼────┼────┤
│    │    │    │    │    │    │    │    │
├────┼────┼────┼────┼────┼────┼────┼────┤
│    │    │    │    │    │    │    │    │
└────┴────┴────┴────┴────┴────┴────┴────┘

Inventory changes trigger inventoryChanged, while selection changes trigger inventorySelectionChanged. UI components listen to these events and update automatically.

UML Diagram

classDiagram
    class InventoryComponent {
        -List~InventorySlot~ slots
        -int rows
        -int columns
        -int selectedSlotIndex
        +addItem(ItemType, int) boolean
        +removeItem(ItemType, int) boolean
        +selectSlot(int)
        +selectNext()
        +selectPrevious()
        +swapSlots(int, int)
        +sortByItemId()
    }

    class InventorySlot {
        -ItemType itemType
        -int quantity
        +getItemType() ItemType
        +getQuantity() int
        +isEmpty() boolean
    }

    InventoryComponent "1" *-- "*" InventorySlot
Loading

Usage

Key Public Methods

Method Purpose
addItem(item, quantity) Add items to the inventory
removeItem(item, quantity) Remove items
getItemCount(item) Get an item's quantity
hasItem(item) Check whether an item exists
selectSlot(index) Select a specific slot
selectNext() / selectPrevious() Cycle between owned items
swapSlots(a, b) Swap two inventory slots
sortByItemId() Sort item by itemid
addRow() / addColumn() Expand the inventory

Example Usage

InventoryComponent inventory = new InventoryComponent(0);

inventory.addItem(ItemType.ARROW, 10);
inventory.addItem(ItemType.RopeArrow, 1);

inventory.selectSlot(0);

int arrows = inventory.getItemCount(ItemType.ARROW);

inventory.removeItem(ItemType.ARROW, 1);

Automatic Gold Collection

Gold coins within 0.75 world units of the player's centre are collected automatically without pressing F. A standard coin grants 10 gold, while custom coins may grant a different amount.

Collected gold increases the player's currency without occupying an inventory slot. Each coin can only be awarded once. Automatic collection stops while the game is paused or the shop is open.

Ordinary items and wheel tokens still require manual interaction.

Dropping and Deleting Items

Key Action Result
R Drop the selected stack Removes the entire stack from the inventory and creates a world item at the player's position, allowing it to be picked up again.
Delete (Forward Delete) Delete the selected stack Permanently removes the entire stack without creating a world item.

If an empty slot is selected, neither operation changes the inventory. Successful operations update the inventory display and emit itemDropped or itemDeleted.


Testing

Automated tests cover the inventory, item-use, player-interaction, and ranged-combat systems.

Inventory

InventoryComponentTest verifies:

  • Adding, stacking, and removing items
  • Inventory capacity and invalid quantities
  • Item selection, switching, and sorting
  • Slot swapping and selection preservation
  • Row and column expansion
  • Quick-slot selection
  • Invalid and no-op inventory operations
  • Inventory and selection change events

Player–Item Interaction

PlayerInteractionComponentTest verifies:

  • Detecting the nearest item within interaction range
  • Ignoring non-item and out-of-range entities
  • Picking up items and handling a full inventory
  • Dropping the complete selected item stack
  • Permanently deleting the complete selected item stack
  • Rejecting drop or delete operations when no item is selected
  • Switching between owned items
  • Emitting the appropriate success and failure events
  • Automatically collecting all gold within the pickup radius
  • Respecting the automatic pickup distance boundary
  • Preventing duplicate gold awards before deferred removal
  • Suspending automatic collection while paused or shopping
  • Leaving ordinary items and wheel tokens for manual interaction

Item Use and Attack Restrictions

ItemUseComponentTest verifies:

  • Standard arrows are consumed when fired
  • A projectile attack event is produced for a valid standard-arrow attack
  • The player cannot attack without owning and selecting an item
  • Health potions heal the player and are consumed
  • Potions cannot be used at full health
  • Rope Arrows are not consumed
  • Rope Arrow cooldown is applied and enforced

Keyboard Controls

KeyboardPlayerInputComponentTest verifies:

  • E produces only one attack per key press
  • Attacks use the current mouse aim direction
  • The player cannot bypass inventory validation when ItemUseComponent is missing
  • R drops the selected stack
  • Delete removes the selected stack
  • Movement, jumping, sprinting, and grapple input events

Grapple and Projectile Behaviour

GrappleComponentTest, BowComponentTest, and ArrowProjectileComponentTest verify:

  • Grappling is rejected when the player does not own a Rope Arrow
  • Grappling succeeds without consuming an owned Rope Arrow
  • Bow attacks create projectiles in the requested direction
  • Projectiles damage valid targets only once
  • Projectiles expire when hitting terrain or obstacles
  • Projectile range and movement behaviour

Manual Integration Testing

The following behaviours should also be checked during gameplay:

  • F picks up the nearest item within range
  • E does nothing when no owned arrow is selected
  • Standard arrows visibly spawn and damage a target
  • R creates a dropped world item containing the complete selected stack
  • Delete removes the selected stack without spawning a world item
  • Rope grappling only works while a Rope Arrow is owned
  • Inventory and hotbar displays refresh after pickup, use, drop, and deletion
  • Attack, item-use, and failure audio/visual feedback appears at the correct time

Known Testing Gaps

  • Fire Arrow and Cold Arrow attributes are unit tested, but their complete attack-effect pipelines are not yet covered by integration tests.

Running the Tests

From the source directory:

./gradlew core:test

Clone this wiki locally