Vibe coding a GDD

Created by using Claude, Gemini, and ChatGPT to put together something using my collection of documents over the years.

Ballhalla: Crossover Tactics - Consolidated Technical Implementation Guide

BALLHALLA: CROSSOVER TACTICS - CONSOLIDATED TECHNICAL IMPLEMENTATION GUIDE

(Final Expanded Version - March 30, 2025)


Table of Contents


1. Game Overview & Core Concepts

  • Genre: Tactical Turn-Based RPG meets Basketball.
  • Platform: PC/Mobile.
  • Target Age: 13+.
  • Logline: After a crushing defeat, a ragtag basketball team is transported to Ballhalla, a magical realm where basketball is life and death. They must master card-based abilities, recruit defeated foes, and explore themed realms to challenge the usurper Mizio, restore order, and find the missing G.O.A.T.
  • Core Gameplay: Command 5 ballers on a 9x12 grid (half-court). Use actions (Move, Fake, Talk, Pass, Screen, Shoot) within a 24-second shot clock (3s/action). Chain actions to execute Plays. Manage Stamina and build Hype to unlock powerful abilities. Customize team using a card-based system for ballers, plays, and equipment. Explore an overworld with 8 unique themed Sub-Realms. Features roguelike progression with autosaving and run-based resets.

2. Game Manager (AGameManager)

  • Purpose: Central controller managing overall game state, transitions between states (Overworld, Match, Menu, etc.), and holding references to other core managers. Orchestrates the main game flow and handles Save/Load operations.
  • Code: GameManager.h / GameManager.cpp
// GameManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
// #include "BattleManager.h" // Forward declare or include needed headers
// #include "GridManager.h"
// #include "TurnManager.h"
// #include "OverworldManager.h"
// #include "TeamManager.h"
// #include "MatchManager.h"
// #include "EssenceManager.h"
// #include "ProgressionManager.h"
// #include "DeckManager.h"
// #include "CardCollectionManager.h" // Placeholder
#include "GameManager.generated.h"

UENUM(BlueprintType)
enum class EGameState : uint8
{
    MainMenu UMETA(DisplayName = "Main Menu"),
    Overworld UMETA(DisplayName = "Overworld"),
    // CourtSelection UMETA(DisplayName = "Court Selection"), // May be part of TeamSetup
    TeamSetup UMETA(DisplayName = "Team Setup"),         // Deck/Roster adjustment pre-match
    Match UMETA(DisplayName = "Match"),                   // Active gameplay
    Results UMETA(DisplayName = "Results"),                 // Post-match screen
    GameOver UMETA(DisplayName = "Game Over")               // Run ended
};

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGameStateChangedSignature, EGameState, NewState);

/**
 * Main game manager that controls overall game flow and manager access.
 */
UCLASS()
class BALLHALLA_API AGameManager : public AActor
{
    GENERATED_BODY()

public:
    AGameManager();
    virtual void BeginPlay() override;

    // Current game state
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Game State")
    EGameState CurrentGameState;

    // Core Manager References (Ensure these are set up, e.g., via spawning or finding)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class ABattleManager* BattleManager;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class AGridManager* GridManager;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class ATurnManager* TurnManager;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class AOverworldManager* OverworldManager;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class AMatchManager* MatchManager;

    // Component Managers (May be components on GameManager or PlayerState/GameState)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class UEssenceManager* EssenceManager;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class UProgressionManager* ProgressionManager;

    // Card Management Components (Potentially on Player State)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class UDeckManager* PlayerDeckManager; // Manages in-match deck

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Managers")
    class UCardCollectionManager* PlayerCardCollectionManager; // Manages persistent run collection

    // State transitions
    UFUNCTION(BlueprintCallable, Category = "Game State")
    void TransitionToState(EGameState NewState);

    // State entry/exit handlers (Called by TransitionToState)
protected:
    virtual void HandleMainMenuState();
    virtual void HandleOverworldState();
    // virtual void HandleCourtSelectionState();
    virtual void HandleTeamSetupState();
    virtual void HandleMatchState();
    virtual void HandleResultsState();
    virtual void HandleGameOverState();

public:
    // Game flow
    UFUNCTION(BlueprintCallable, Category = "Game Flow")
    void StartNewGame(); // Initializes a fresh run (resets facilities, run progress)

    UFUNCTION(BlueprintCallable, Category = "Game Flow")
    void SaveGame(); // Triggers autosave logic for current run (See Section 21)

    UFUNCTION(BlueprintCallable, Category = "Game Flow")
    void LoadGame(); // Loads game from autosave for current run (See Section 21)

    // Meta Progression Save/Load potentially handled separately or via Profile system

    // Events
    UPROPERTY(BlueprintAssignable, Category = "Game State|Events")
    FOnGameStateChangedSignature OnGameStateChanged;
};

3. Grid System (AGridManager, UGridCell)

  • Purpose: Manages the 9x12 court grid, cell data, spatial queries (range, AoE), and coordinate conversions.
  • Code: GridManager.h/.cpp, GridCell.h/.cpp
// GridCell.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "GridCell.generated.h"

UENUM(BlueprintType)
enum class ECourtArea : uint8
{
    Paint UMETA(DisplayName = "Paint"),         // 1-3 squares from rim
    Midrange UMETA(DisplayName = "Midrange"),   // 4-7 squares from rim
    ThreePoint UMETA(DisplayName = "ThreePoint"), // 7-9 squares from rim
    Deep UMETA(DisplayName = "Deep")            // 9-12 squares from rim
};

/** Represents a single cell in the basketball court grid */
UCLASS(BlueprintType)
class BALLHALLA_API UGridCell : public UObject
{
    GENERATED_BODY()
public:
    UGridCell();

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Grid")
    FIntPoint Coordinates; // X, Y on the grid

    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Grid") // ReadWrite to allow setting/clearing
    TWeakObjectPtr<AActor> OccupyingActor; // Use TWeakObjectPtr to avoid circular refs

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Grid")
    ECourtArea AreaType; // Pre-calculated area type

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Grid")
    float DistanceFromRim; // Pre-calculated distance

    // World location equivalent of the cell center
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Grid")
    FVector WorldLocation;

    UFUNCTION(BlueprintCallable, Category = "Grid")
    bool IsOccupied() const;

    UFUNCTION(BlueprintCallable, Category = "Grid")
    bool CanBeOccupied() const; // Add logic (e.g., not occupied, not obstacle)

    UFUNCTION(BlueprintCallable, Category = "Grid")
    void SetOccupant(AActor* NewOccupant);

    UFUNCTION(BlueprintCallable, Category = "Grid")
    void ClearOccupant();
};

// GridManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GridCell.h" // Include GridCell header
#include "GridManager.generated.h"

/** Manages the 9x12 basketball court grid */
UCLASS()
class BALLHALLA_API AGridManager : public AActor
{
    GENERATED_BODY()
public:
    AGridManager();
    virtual void BeginPlay() override;

    // Grid dimensions
    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Grid Config")
    int32 Width = 9;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Grid Config")
    int32 Height = 12;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Grid Config")
    float CellSize = 100.0f; // World units per cell

    // Rim location in grid coordinates (configurable)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Grid Config")
    FIntPoint RimCoordinates = FIntPoint(4, 0); // Example: Center of back row

protected:
    // Grid data storage (Use flat array for cache efficiency)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Grid")
    TArray<UGridCell*> GridCells;

private:
    // Initialize grid cells, calculate distances, areas, world locations
    void InitializeGrid();
    void SetupCourtAreas(); // Assign AreaType based on DistanceFromRim
    void CalculateDistancesFromRim(); // Calculate DistanceFromRim for each cell

public:
    // Get cell object at coordinates
    UFUNCTION(BlueprintCallable, Category = "Grid Query")
    UGridCell* GetCellAt(int32 X, int32 Y) const;

    UFUNCTION(BlueprintCallable, Category = "Grid Query")
    UGridCell* GetCellAtCoord(const FIntPoint& Coords) const;

    // Get cells within Manhattan distance range
    UFUNCTION(BlueprintCallable, Category = "Grid Query")
    TArray<UGridCell*> GetCellsInRange(const UGridCell* Origin, int32 Range) const;

    // Get cells affected by an Area of Effect pattern relative to a target cell
    UFUNCTION(BlueprintCallable, Category = "Grid Query")
    TArray<UGridCell*> GetAreaOfEffect(const UGridCell* Target, const TArray<FIntPoint>& Pattern) const;

    // Convert grid coordinates to world location (center of cell)
    UFUNCTION(BlueprintCallable, Category = "Grid Conversion")
    FVector GridToWorldLocation(const FIntPoint& GridCoords) const;

    // Convert world location to grid coordinates
    UFUNCTION(BlueprintCallable, Category = "Grid Conversion")
    FIntPoint WorldToGridLocation(const FVector& WorldLocation) const;

    // Calculate shooting modifier based on cell properties (e.g., distance, area type)
    UFUNCTION(BlueprintCallable, Category = "Grid Gameplay")
    float CalculateShootingModifier(const UGridCell* FromCell) const;

    // Helper to check if coordinates are valid
    UFUNCTION(BlueprintPure, Category = "Grid Query")
    bool IsValidCoordinate(const FIntPoint& Coords) const;

    // Pathfinding (Simple BFS suitable for this grid size)
    UFUNCTION(BlueprintCallable, Category = "Grid Pathfinding")
    TArray<UGridCell*> FindPath(const UGridCell* StartCell, const UGridCell* EndCell) const;
};

(Implementation Notes for Grid System: Pre-calculate DistanceFromRim, AreaType, and WorldLocation during InitializeGrid for efficiency. Use Manhattan distance for range calculations unless diagonal movement is explicitly allowed.)

4. Turn Manager (ATurnManager)

  • Purpose: Manages the current game phase (Offense/Defense), shot clock, quarter progression, and phase transitions.
  • Code: TurnManager.h/.cpp
// TurnManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "TurnManager.generated.h"

UENUM(BlueprintType)
enum class EGamePhase : uint8
{
    PreMatch UMETA(DisplayName = "Pre-Match"), // Setup phase
    Offense UMETA(DisplayName = "Offense"),
    Defense UMETA(DisplayName = "Defense"),   // AI simulates offense here
    Timeout UMETA(DisplayName = "Timeout"),
    Halftime UMETA(DisplayName = "Halftime"),
    PostMatch UMETA(DisplayName = "Post-Match"), // Results/Rewards
    GameOver UMETA(DisplayName = "Game Over")     // End of run
};

// Add delegates for events if needed by UI or other systems
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPhaseChangedSignature, EGamePhase, NewPhase);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnShotClockUpdatedSignature, int32, TimeRemaining);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnQuarterChangedSignature, int32, NewQuarter);


/** Manages turns, shot clock, and game phases within a match */
UCLASS()
class BALLHALLA_API ATurnManager : public AActor
{
    GENERATED_BODY()
public:
    ATurnManager();
    virtual void BeginPlay() override;
    // Removed Tick if updates are event-driven

    // --- Configuration ---
    UPROPERTY(EditDefaultsOnly, Category = "Turn Config")
    int32 MaxShotClockTime = 24;

    UPROPERTY(EditDefaultsOnly, Category = "Turn Config")
    int32 TimePerAction = 3;

    // --- State ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Turn State")
    EGamePhase CurrentPhase;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Turn State")
    int32 CurrentShotClockTime;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Turn State")
    int32 CurrentQuarter = 1;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Turn State")
    bool bIsPlayerTeamOffense = true; // Tracks which team has offensive possession

    // --- Phase Management ---
    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartMatch(bool bPlayerStartsOnDefense = false); // Initialize for match start

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartNextPhase(); // Core logic to transition (e.g., Offense -> Defense -> Offense...)

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartOffensePhase();

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartDefensePhase();

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartTimeoutPhase();
    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void EndTimeoutPhase();

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartHalftimePhase();
    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void EndHalftimePhase();

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void StartPostMatchPhase();

    UFUNCTION(BlueprintCallable, Category = "Turn Flow")
    void EndMatch(); // Sets state to GameOver or triggers results

    // --- Shot Clock ---
    UFUNCTION(BlueprintCallable, Category = "Turn Actions")
    void ConsumeActionTime(); // Decreases shot clock by TimePerAction

    UFUNCTION(BlueprintCallable, Category = "Turn State")
    bool IsShotClockExpired() const;

    UFUNCTION(BlueprintCallable, Category = "Turn Actions")
    void ResetShotClock();

    // --- Event Handling (Called by BattleManager/MatchManager) ---
    UFUNCTION(BlueprintCallable, Category = "Turn Events")
    void HandlePossessionChange(); // Switches bIsPlayerTeamOffense, resets clock, starts next phase

    UFUNCTION(BlueprintCallable, Category = "Turn Events")
    void HandleShotAttemptOutcome(bool bMadeShot, bool bIsBlocked); // Determines next step based on shot result

    UFUNCTION(BlueprintCallable, Category = "Turn Events")
    void HandleTurnoverOccurred(bool bIsShotClockViolation); // Ends offense phase due to turnover

    UFUNCTION(BlueprintCallable, Category = "Turn Events")
    void HandleEndOfQuarter(); // Logic before incrementing quarter

    UFUNCTION(BlueprintCallable, Category = "Turn Events")
    void HandleEndOfHalf(); // Triggers halftime

    // --- Event Dispatchers ---
    UPROPERTY(BlueprintAssignable, Category = "Turn|Events")
    FOnPhaseChangedSignature OnPhaseChanged;

    UPROPERTY(BlueprintAssignable, Category = "Turn|Events")
    FOnShotClockUpdatedSignature OnShotClockUpdated;

    UPROPERTY(BlueprintAssignable, Category = "Turn|Events")
    FOnQuarterChangedSignature OnQuarterChanged;

private:
    // Helper to change phase and broadcast event
    void SetPhase(EGamePhase NewPhase);
    void UpdateShotClock(int32 NewTime);
    void AdvanceQuarter();
};

(Implementation Notes for Turn Manager: Ensure phase transitions correctly handle quarter/halftime logic and interact with MatchManager.)

5. Baller Character (ABallerCharacter)

  • Purpose: Base class for all player-controlled and AI ballers. Contains stats, resources, state, abilities, and action implementations.
  • Code: BallerCharacter.h/.cpp
// BallerCharacter.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "GameplayTagContainer.h" // Include for Synergy/Status Tags
#include "GridCell.h" // Include GridCell
// Include headers for Ability, EquipmentCard if needed
#include "BallerCharacter.generated.h"

// Forward Declarations
class UGridCell;
class UAbility;
class UEquipmentCard;
class ATeamManager; // For team reference
class UStatusManagerComponent; // For Status Effects

// Define Enums (ensure globally accessible or within appropriate scope)
UENUM(BlueprintType) enum class EPosition : uint8 { PointGuard, ShootingGuard, SmallForward, PowerForward, Center };
UENUM(BlueprintType) enum class ERank : uint8 { Rookie, Starter, Veteran, AllStar, MVP, HallOfFamer };
UENUM(BlueprintType) enum class EEssenceType : uint8 { None, Werewolf, Voodoo, Witch, Beast, Ocean, Police, TreePeople, Vampire };
UENUM(BlueprintType) enum class EActionType : uint8 { Move, Fake, Talk, Shoot, Pass, Screen, HypeAbility }; // Basic Types
UENUM(BlueprintType) enum class EMoveType : uint8 { Cut, Drive, Juke, Pick };
UENUM(BlueprintType) enum class EFakeType : uint8 { Crossover, BallFake, TripleThreat, PostUp };
UENUM(BlueprintType) enum class ETalkType : uint8 { Playcall, TrashTalk, Leadership, ISO };
UENUM(BlueprintType) enum class EHypeLevel : uint8 { None, Low, Medium, High, Max };


USTRUCT(BlueprintType)
struct FBallerStats // Structure to hold baller stats for easier management
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
    float MaxStamina = 100.0f;
    UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Stats")
    float CurrentStamina = 100.0f;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
    float MaxHype = 100.0f;
    UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "Stats")
    float CurrentHype = 0.0f;

    // --- Core Basketball Stats ---
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Offense")
    float TwoPointPercentage = 50.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Offense")
    float ThreePointPercentage = 35.0f;
     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Offense")
    float PassRating = 50.0f;
     UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Offense")
    float OffensiveRating = 50.0f; // General offensive capability

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Physical")
    float DribbleRating = 50.0f; // Handle
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Physical")
    float SpeedRating = 50.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Physical")
    float Movement = 4.0f; // Grid cells per move action base

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Defense")
    float ReboundRating = 50.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Defense")
    float BlockRating = 50.0f;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Defense")
    float DefensiveRating = 50.0f; // General defensive capability

    // Gravity - Influences AI behavior (See Section 5.1)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats|Special")
    float NaturalGravity = 3.0f;

    // Gameplay Tags inherent to this baller's role/archetype (for Synergy System)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Stats|Tags")
    FGameplayTagContainer InherentTags;
};


/** Base class for all basketball players (ballers) */
UCLASS()
class BALLHALLA_API ABallerCharacter : public ACharacter
{
    GENERATED_BODY()
public:
    ABallerCharacter();
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;

    // --- Identity & Role ---
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Identity")
    FString BallerName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Identity", meta=(ToolTip="Unique ID for save games and tracking"))
    FString UniqueID; // Needed for XP tracking / SaveGame persistence

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Identity")
    EPosition Position;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Identity", SaveGame) // Rank persists
    ERank Rank = ERank::Rookie;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Identity", SaveGame) // Essence empowerment persists
    EEssenceType CurrentEssenceType = EEssenceType::None;

    // --- Stats ---
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Baller|Stats", meta = (ShowOnlyInnerProperties))
    FBallerStats BaseStats; // Holds the core, unmodified stats

    // --- Status Effects ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Baller|Status", meta=(ToolTip="Manages temporary conditions affecting this baller"))
    UStatusManagerComponent* StatusManager; // Component manages active conditions (See Section 5.2)

    // --- State ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Baller|State")
    UGridCell* CurrentCell; // Cell the baller occupies

    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Baller|State") // ReadWrite for BattleManager to set
    bool bHasBall;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Baller|State")
    bool bIsExhausted; // True if CurrentStamina reaches zero

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Baller|State")
    TWeakObjectPtr<ATeamManager> OwningTeam; // Reference to the team manager

    // --- Gameplay Actions (Called by BattleManager) ---
    // These functions contain the core logic for executing an action
    virtual bool PerformMove(UGridCell* TargetCell, EMoveType MoveType);
    virtual bool PerformFake(ABallerCharacter* Target, EFakeType FakeType);
    virtual bool PerformTalk(ETalkType TalkType);
    virtual bool PerformShoot(UGridCell* TargetCell); // TargetCell is usually basket cell based on current position
    virtual bool PerformPass(ABallerCharacter* TargetReceiver);
    virtual bool PerformScreen(UGridCell* TargetCell);
    virtual bool PerformHypeAbility(int32 AbilityIndex /* or Ability Ptr */, const struct FAbilityTargetData& TargetData); // Define FAbilityTargetData

    // --- Resource Management ---
    UFUNCTION(BlueprintCallable, Category = "Baller|Resources")
    bool ConsumeStamina(float Amount); // Returns false if not enough stamina (unless forced)
    UFUNCTION(BlueprintCallable, Category = "Baller|Resources")
    void GainStamina(float Amount);
    UFUNCTION(BlueprintCallable, Category = "Baller|Resources")
    void GainHype(float Amount);
    UFUNCTION(BlueprintCallable, Category = "Baller|Resources")
    bool ConsumeHype(float Amount); // Returns false if not enough hype

    // --- State Checks ---
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Baller|State")
    bool CanPerformAction(FGameplayTag ActionTag) const; // Checks if exhausted, affected by status effects (using tags) etc.
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Baller|State")
    EHypeLevel GetCurrentHypeLevel() const; // Translates CurrentHype value to Enum

    // --- Grid Interaction ---
    UFUNCTION(BlueprintCallable, Category = "Baller|Grid")
    void SetCurrentCell(UGridCell* NewCell);

    // --- Ability & Equipment Management ---
    // TODO: Define how abilities/equipment are stored and accessed (Potentially via Components)
    // UPROPERTY(SaveGame) TArray<UEquipmentCard*> EquippedItems; // Needs reference to Card Data Assets

    // --- Natural Gravity ---
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Baller|Stats")
    float GetEffectiveGravity() const; // Calculates current gravity based on state (See Section 5.1)

    // --- Stat Calculation ---
    // Function to get the final value of a stat considering base, modifiers, status effects etc.
    // UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Baller|Stats")
    // float GetCurrentStatValue(EStatType StatToGet) const;

    // --- Gameplay Tags ---
    // UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Baller|Tags")
    // FGameplayTagContainer GetCurrentGameplayTags() const; // Combine inherent + status effect tags

protected:
    // Called on initialization or when Rank/Position/Essence changes
    virtual void ApplyPositionModifiers(); // Adjust stats based on Position enum
    virtual void ApplyEssenceModifiers(); // Adjust stats/grant abilities based on CurrentEssenceType
    virtual void ApplyRankModifiers();    // Adjust stats/grant abilities based on Rank enum

    // Update exhaustion state based on stamina
    virtual void UpdateExhaustionState();

    // Recalculate derived stats whenever base stats or modifiers change
    virtual void RecalculateDerivedStats();
};

5.1. Natural Gravity Mechanic

  • Purpose: Represents the defensive attention an offensive baller commands, influencing AI behavior.
  • Core Effects:
    1. AI Targeting: Higher EffectiveGravity increases AI priority for guarding assignments/switches.
    2. AI Help Positioning: Nearby AI defenders guarding lower-gravity players may "cheat" slightly towards high-gravity players (subtle effect).
    3. AI Behavior Trigger: High EffectiveGravity on ball-handler is the main trigger for AI considering DoubleTeam.
  • Calculation: EffectiveGravity = (BaseNaturalGravity + LocationBonus) * BallPossessionModifier * HypeModifier.
    • BaseNaturalGravity: From FBallerStats.
    • LocationBonus: (Placeholder) Bonus in optimal scoring areas.
    • BallPossessionModifier: (Placeholder) Increases the longer baller holds the ball.
    • HypeModifier: (Placeholder) Increases with baller's CurrentHype.
  • Interactions: Closer defenders increase shot contest difficulty. Screens can impede defenders pulled by gravity and temporarily increase screener's perceived gravity to that defender.

5.2. Status Effect / Condition System

  • Purpose: To manage temporary or persistent effects applied to a baller that alter their stats, available actions, or passive behavior. Conditions add strategic depth, enabling combos, counterplay, and tactical team-building by modifying baller capabilities dynamically.
  • Core Structure (FConditionEffect): Conditions should be defined using a struct, likely managed via Data Assets (UConditionDataAsset inheriting from UDataAsset containing an FConditionEffect struct) for easy creation and referencing.
    USTRUCT(BlueprintType)
    struct FConditionEffect
    {
        GENERATED_BODY()
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        FName ConditionName; // Unique identifier (e.g., "Slowed", "Hexed", "Exhausted")
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        FString Description; // Tooltip explanation
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition", meta=(ToolTip="Turns remaining. Decremented per full turn cycle (Off+Def). -1 for persistent/conditional removal."))
        int32 DurationTurns;
    
        // Modifiers applied while condition is active
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        TArray<FStatModifier> StatModifiers; // Reference the unified FStatModifier struct
    
        // Restrictions imposed by the condition using Gameplay Tags
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition", meta=(ToolTip="Gameplay Tags identifying actions blocked by this condition."))
        FGameplayTagContainer BlockedActionTags; // e.g., Blocks tags like "Action.Ability", "Action.Move"
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        bool bIsBuff; // True for positive effects, False for negative (UI/visual distinction)
    
        UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        TSoftObjectPtr<UTexture2D> Icon; // For display on HUD/UI elements
    
        // Optional: Add particle system references for visual effects
        // UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Condition")
        // TSoftObjectPtr<UParticleSystem> ConditionVFX;
    };
    
  • Management Component (UStatusManagerComponent): Recommended approach is an Actor Component attached to ABallerCharacter. Responsibilities:
    • ApplyCondition(UConditionDataAsset* ConditionData): Adds a condition. Handles stacking rules (e.g., refresh duration, block application if immune, stack intensity).
    • RemoveCondition(FName ConditionName): Removes a specific condition instance.
    • TickConditions(EGamePhase CurrentPhase): Called by the Turn Manager or Battle Manager at appropriate intervals (e.g., end of a full turn cycle) to decrement DurationTurns and remove expired conditions.
    • GetCurrentStatModifiers() const: Aggregates all StatModifiers from active conditions.
    • IsActionBlocked(FGameplayTag ActionTag) const: Checks if any active condition's BlockedActionTags match the tag of the action being attempted.
    • Event dispatchers for UI updates when conditions are applied/removed/tick.
  • Example Conditions (Illustrative):
    • Exhausted: (Debuff, Applied at 0 Stamina) DurationTurns = -1 (until Stamina > 0). StatModifiers: Significant negative Shooting%, Move Range. BlockedActionTags: Action.Ability, Action.Hype.
    • Slowed: (Debuff) DurationTurns = 2 (e.g., 1 full Quarter). StatModifiers: -2 Movement. Source: Crossovers, Ice Abilities.
    • Hexed: (Debuff) DurationTurns = 3. StatModifiers: Applies random stat reduction modifier dynamically each turn (requires custom logic). Source: Witch Abilities.
    • Hydrated: (Buff) DurationTurns = 2. StatModifiers: -50% StaminaCostMultiplier (requires custom stat mod handling). Source: Water Bottle Card.
    • Shooter's Touch: (Buff) DurationTurns = -1 (Match duration). StatModifiers: +10% ShootingPercentage. Source: Equipment Card.
    • Icy Veins: (Buff) DurationTurns = -1. Conditional Stat Modifier (requires custom logic checking shot clock). Source: Card/Ability.
  • Application Sources: Actions (specific outcomes), Abilities, Card effects, Equipment (passive or active), Overworld events.
  • Integration: Requires modification of stat calculation logic in ABallerCharacter to account for modifiers from the UStatusManagerComponent. Action validation logic needs to check BlockedActionTags. UI needs to display active conditions clearly.
  • MVP Status: Post-MVP. The core loop functions without complex status effects, though the existing bIsExhausted state serves as a basic condition.

6. Team Manager (ATeamManager)

  • Purpose: Manages a single team (player or AI), including their roster of active and benched ballers, team-wide effects, and who currently possesses the ball within the team.
  • Code: TeamManager.h/.cpp
// TeamManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BallerCharacter.h" // Include BallerCharacter header
// Include headers for FStatModifier if needed
#include "TeamManager.generated.h"

// Forward declarations
struct FStatModifier; // Use the unified name

/** Manages a team of ballers (Player or Enemy) */
UCLASS()
class BALLHALLA_API ATeamManager : public AActor
{
    GENERATED_BODY()
public:
    ATeamManager();
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override; // For updating temporary effects

    // --- Team Identity ---
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team Config")
    FString TeamName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team Config")
    UTexture2D* TeamLogo;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team Config")
    bool bIsPlayerTeam = true;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Team Config")
    EEssenceType TeamEssence = EEssenceType::None; // Primary essence type for AI teams

    // --- Roster ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Team Roster")
    TArray<ABallerCharacter*> ActiveBallers; // Max 5 on court
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Team Roster")
    TArray<ABallerCharacter*> BenchedBallers; // Available substitutes

    // --- State ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Team State")
    TWeakObjectPtr<ABallerCharacter> BallerWithBall; // Current baller holding the ball

    // --- Roster Management ---
    UFUNCTION(BlueprintCallable, Category = "Team Management")
    bool AddBallerToRoster(ABallerCharacter* Baller, bool bStartActive = false);
    UFUNCTION(BlueprintCallable, Category = "Team Management")
    bool RemoveBallerFromRoster(ABallerCharacter* Baller);
    UFUNCTION(BlueprintCallable, Category = "Team Management")
    bool SubstituteBaller(ABallerCharacter* BallerToRemove, ABallerCharacter* BallerToAdd); // Swaps between Active/Bench

    // --- Gameplay ---
    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    ABallerCharacter* GetBallerWithBall() const;
    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    void SetBallerWithBall(ABallerCharacter* Baller); // Nullptr if no one has ball
    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    void ClearBallPossession();

    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    float GetTeamHype() const; // Calculates combined hype from ActiveBallers

    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    void ApplyTeamStatModifier(const FStatModifier& Modifier); // Apply temporary buff/debuff to all active ballers

    UFUNCTION(BlueprintCallable, Category = "Team Gameplay")
    void UpdateTemporaryEffects(float DeltaTime); // Decrement duration of modifiers

private:
    // Store active temporary modifiers affecting the whole team
    UPROPERTY()
    TArray<FStatModifier> ActiveTeamModifiers;
};

7. Battle Manager (ABattleManager)

  • Purpose: Orchestrates the actions within a single offensive or defensive turn. Handles player input validation, calls actions on ABallerCharacter, resolves action outcomes (like shooting percentages, turnovers), and interacts with ATurnManager to update game state. Owns the Action History.
  • Code: BattleManager.h/.cpp
// BattleManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "GameplayTagContainer.h" // For Turnover Reasons
// #include "TurnManager.h" // Forward declare needed managers
// #include "GridManager.h"
// #include "TeamManager.h"
// #include "BallerCharacter.h"
#include "BattleManager.generated.h"

// Enums EActionType, EFakeType, ETalkType, EMoveType defined previously

// Structure to hold parameters for various actions
USTRUCT(BlueprintType)
struct FActionParams // Define needed parameters for all action types
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadWrite) TWeakObjectPtr<UGridCell> TargetCell;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) TWeakObjectPtr<ABallerCharacter> TargetBaller;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) EFakeType FakeType = EFakeType::Crossover;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) ETalkType TalkType = ETalkType::Playcall;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) EMoveType MoveType = EMoveType::Cut;
    // Add params for Ability Index/Data if abilities are handled here
    // FAbilityTargetData TargetData; // If needed
};

// Structure to record action history
USTRUCT(BlueprintType)
struct FActionRecord
{
    GENERATED_BODY()
    UPROPERTY(EditAnywhere, BlueprintReadWrite) TWeakObjectPtr<ABallerCharacter> ActingBaller;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) EActionType ActionType;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) FActionParams Params;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) float Timestamp; // Game time action occurred
    UPROPERTY(EditAnywhere, BlueprintReadWrite) bool bWasSuccessful; // Did the action succeed
};

/** Manages the core basketball battle gameplay logic and action resolution */
UCLASS()
class BALLHALLA_API ABattleManager : public AActor
{
    GENERATED_BODY()
public:
    ABattleManager();
    virtual void BeginPlay() override;

    // --- Manager References ---
    UPROPERTY() TWeakObjectPtr<ATurnManager> TurnManager;
    UPROPERTY() TWeakObjectPtr<AGridManager> GridManager;
    UPROPERTY() TWeakObjectPtr<AMatchManager> MatchManager; // For reporting score changes etc.
    UPROPERTY() TWeakObjectPtr<ATeamManager> PlayerTeam;
    UPROPERTY() TWeakObjectPtr<ATeamManager> EnemyTeam;
    // Potentially references to PlaySystemManager, HypeActionManager etc.

    // --- Action Handling (Player Input Driven) ---
    // Called by PlayerController or UI based on player input
    UFUNCTION(BlueprintCallable, Category = "Battle Actions")
    bool RequestBallerAction(ABallerCharacter* Baller, EActionType ActionType, FActionParams Params);

private:
    // --- Action Resolution (Internal Logic) ---
    // These functions are called internally by RequestBallerAction after validation
    bool ExecuteMoveAction(ABallerCharacter* Mover, UGridCell* TargetCell, EMoveType MoveType);
    bool ExecuteShootAction(ABallerCharacter* Shooter); // Calculates chance, resolves hit/miss
    bool ExecutePassAction(ABallerCharacter* Passer, ABallerCharacter* Receiver); // Calculates chance, resolves completion/turnover
    bool ExecuteFakeAction(ABallerCharacter* Faker, ABallerCharacter* Target, EFakeType FakeType); // Target is defender being faked
    bool ExecuteTalkAction(ABallerCharacter* Talker, ETalkType TalkType);
    bool ExecuteScreenAction(ABallerCharacter* Screener, UGridCell* TargetCell); // TargetCell is where screen is set
    // bool ExecuteHypeAbilityAction(...);

    // --- Gameplay Logic ---
    UFUNCTION(BlueprintCallable, Category = "Battle Logic")
    float CalculateShootingPercentage(ABallerCharacter* Shooter, const UGridCell* FromCell);
    UFUNCTION(BlueprintCallable, Category = "Battle Logic")
    void ResolveShot(ABallerCharacter* Shooter, bool bWasBlocked); // Determines Make/Miss based on percentage

    UFUNCTION(BlueprintCallable, Category = "Battle Logic")
    void HandleRebound(); // Initiates the rebound contest (See Section 7.1)

    // Use Gameplay Tags for Turnover Reasons for flexibility
    UFUNCTION(BlueprintCallable, Category = "Battle Logic")
    void TriggerTurnover(ABallerCharacter* LosingBaller, FGameplayTag TurnoverReason); // Notifies TurnManager (See Section 7.2)

    UFUNCTION(BlueprintCallable, Category = "Battle Logic")
    void AddPointsToScore(bool bToPlayerTeam, int32 Points); // Notifies MatchManager

    // --- Action History ---
    // BattleManager owns the definitive history for replay/analysis/play checking
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Battle History")
    TArray<FActionRecord> ActionHistory;

    UFUNCTION(BlueprintCallable, Category = "Battle History")
    void RecordAction(ABallerCharacter* Baller, EActionType ActionType, const FActionParams& Params, bool bSuccess);

    UFUNCTION(BlueprintCallable, Category = "Battle History")
    TArray<FActionRecord> GetRecentActions(int32 Count = 5) const;

    // Helper function to get the correct team manager based on baller affiliation
    ATeamManager* GetTeamForBaller(ABallerCharacter* Baller) const;
};

7.1. Rebounding Logic

  • Purpose: Determines possession after a missed shot.
  • Core Mechanic: Probabilistic contest based on ReboundScore calculated for participants within 2-3 cells of the basket.
  • Score Factors: ReboundRating, Proximity Bonus, Box Out Modifier (Penalty if opponent between baller & basket), Role Bonus (C/PF), Stamina Penalty, Hype/Ability/Equipment Mods.
  • Participants: Includes nearby players and the original shooter.
  • Resolution: Weighted random roll based on scores. Tie-breaker: Higher Hype wins; if tied, Defender wins.
  • Outcomes:
    • Offensive Rebound: Offense continues, shot clock doesn't reset, Hype gain (extra if shooter rebounds).
    • Defensive Rebound: Offense ends, defense gains minimal Points, potential Fast Break bonus. Phase transition occurs.

7.2. Turnover Causes

  • Purpose: Lists conditions that end the offensive phase prematurely.
  • Causes:
    1. Shot Clock Violation: Clock reaches 0.
    2. Defensive Rebound: Defense secures rebound after missed shot.
    3. Pass Interception (Steal): Defender successfully intercepts pass. Chance based on Passer/Receiver/Defender ratings, distance, Hype difference, Passer Stamina.
    4. On-Ball Steal (Swipe): Defender successfully swipes ball from dribbler. Costs defender Stamina. Chance based on Dribbler/Defender ratings, Stamina, Hype. Risky for defense.
    5. Failed Offensive Actions: Fakes/Drives can fail and lose ball if user has low Stamina/Rating vs high-rated Defender.
    6. Defensive Pressure (Traps): Being Double Teamed increases turnover chance on subsequent actions (Pass/Fake).
  • Exclusions (for now): Offensive Fouls, Out of Bounds.

8. Card System (UCardBase, UBallerCard, UPlayCard, UEquipmentCard)

  • Purpose: Defines the structure for different card types. Use Data Assets (UDataAsset or UPrimaryDataAsset) for defining specific cards.
  • Code Structure:
    • FStatModifier: Define struct centrally (see Section 11).
    • UCardBase (Base Data Asset): Contains common properties: Name, Description, Rarity (Enum: Common, Uncommon, Rare, Epic, Legendary), CardType (Enum: Baller, Play, Equipment), CardImage, EssenceType (Enum), FGameplayTagContainer GameplayTags. Maybe virtual GetDescriptionText() for dynamic text.
    • UBallerCardData (Derived Data Asset): Contains FBallerStats template, TSubclassOf<ABallerCharacter> for base class, list of inherent starting TSoftObjectPtr<UAbility> or Ability Tags. Functionality: Defines baller data template.
    • UPlayCardData (Derived Data Asset): Contains sequence of FPlayAction structs (defining ActionType, Position requirement, etc.), TArray<FStatModifier> success bonuses, DifficultyRating, TArray<EPosition> requirements. Functionality: Defines play data template.
    • UEquipmentCardData (Derived Data Asset): Contains bIsPassive, TArray<FStatModifier> passive bonuses, TSoftObjectPtr<UAbility> granted active ability (if any). Functionality: Defines equipment data template.

(Implementation Notes: UBallerCardData defines templates; actual ABallerCharacter instances are managed by ATeamManager. Play/Equipment effects applied via BattleManager or components.)

8.1. Card Synergy / Tag System (Placeholder)

  • Purpose: Facilitates deeper strategy via tags on cards/abilities/ballers defining relationships and enabling synergistic effects.
  • Scope & Implementation: Use Unreal Engine's Gameplay Tag system (FGameplayTag, FGameplayTagContainer). Define a hierarchy in Project Settings (e.g., Essence.Werewolf, Action.Shoot, Role.PG, Effect.Buff, Condition.Slowed, Combo.Starter). Add FGameplayTagContainer properties to relevant data assets (UCardBase, UAbility definitions) and potentially to FBallerStats or ABallerCharacter. Implement game logic checks for tags within abilities/effects based on querying tags (HasMatchingGameplayTag, etc.).
  • Example Synergies: Play Card bonus if handler has Role.PG tag; Ability deals extra damage if target has Condition.Slowed tag; Equipment bonus if deck has 3+ Essence.Police cards.
  • Integration: Requires adding Tag properties to data structures. Logic implementation within specific abilities/effects. UI for Deckbuilding/Collection could allow filtering/sorting by tags.
  • MVP Status: Post-MVP.

9. Deck Manager (UDeckManager)

  • Purpose: Manages the active deck state during a single match (Draw, Hand, Discard). Initializes from the player's collection based on pre-match selection. Likely an Actor Component on Player State.
  • Code: DeckManager.h/.cpp
// DeckManager.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CardBase.h" // Use Data Asset Ptrs or similar ref type
#include "DeckManager.generated.h"

/** Manages card deck, hand, and discard for a match. */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UDeckManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UDeckManager();
    virtual void BeginPlay() override;

    // --- Deck Configuration ---
    UPROPERTY(EditDefaultsOnly, Category = "Deck Rules")
    int32 MaxDeckSize = 10;
    // UPROPERTY(EditDefaultsOnly, Category = "Deck Rules")
    // int32 MaxBallerCardsInDeck = 3; // CONFIRM: This rule likely applies to Collection, not Match Deck
    UPROPERTY(EditDefaultsOnly, Category = "Deck Rules")
    int32 StartingHandSize = 5;
    UPROPERTY(EditDefaultsOnly, Category = "Deck Rules")
    int32 HalftimeDrawAmount = 5;

    // --- Card Piles (Match State) ---
    // Store references to the Data Assets representing the cards
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Deck State")
    TArray<UCardBase*> DrawPile; // Should be TArray> or similar
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Deck State")
    TArray<UCardBase*> HandCards;
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Deck State")
    TArray<UCardBase*> DiscardPile;

    // --- Deck Management ---
    // Initialize with specific list of Card Data Assets from CollectionManager
    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void InitializeDeck(const TArray<UCardBase*>& PlayerSelectedDeck); // Pass Data Asset refs

    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void ShuffleDrawPile();

    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    TArray<UCardBase*> DrawCards(int32 Amount); // Returns drawn cards (Data Asset refs)

    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void DiscardCardFromHand(UCardBase* Card); // Pass Data Asset ref
    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void DiscardHand();

    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void AddCardToDiscard(UCardBase* Card); // Pass Data Asset ref

    // Called when draw pile is empty
    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void ReshuffleDiscardIntoDrawPile();

    // Reset state for a new match
    UFUNCTION(BlueprintCallable, Category = "Deck Management")
    void ResetDeck();
};

(Self-Correction: Clarified MaxBallerCardsInDeck rule needs review, as Ballers are usually roster elements, not playable cards in the deck. Updated card pile types to reflect storing Data Asset references.)

10. Card Collection Manager

  • Purpose: Manages the player's persistent collection of all acquired Play and Equipment card types across a single roguelike run. This is the source pool for constructing the 10-card match deck via the UDeckManager. Baller acquisition/roster is managed separately by ATeamManager.
  • Scope & Structure: Actor Component (UCardCollectionManager) on PlayerState. Stores collection data using TMap<TSoftObjectPtr<UCardBase>, int32> (Card Data Asset -> Count). Provides functions: AddCard, RemoveCard, DestroyCard, GetCardCount, GetUniqueOwnedCardTypes.
  • Card Destruction: Triggered via UI. Removes card instance permanently for the current run. Grants Neutral Essence based on rarity via UEssenceManager.
  • Integration: Saved/loaded via run's SaveGame. Provides data to Deckbuilding UI & UDeckManager. Interacts with UEssenceManager. Populated by MatchManager::DistributeRewards.
  • MVP Status: Required if deck customization is MVP.
  • Code: CardCollectionManager.h/.cpp (Likely UActorComponent on PlayerState or similar persistent object).
// CardCollectionManager.h (Conceptual)
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
// #include "CardBase.h" // Reference Data Assets
#include "CardCollectionManager.generated.h"

// Forward declarations
class UCardBase;
class UEssenceManager;

USTRUCT(BlueprintType)
struct FCardCollectionEntry
{
    GENERATED_BODY()
    // Reference to the card's Data Asset
    UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame) // Mark relevant fields for SaveGame
    TSoftObjectPtr<UCardBase> CardDataAsset;
    // Count if multiple copies can be owned
    UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame)
    int32 Count = 0;
};

/** Manages the player's persistent card collection for the current run */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UCardCollectionManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UCardCollectionManager();
    virtual void BeginPlay() override;

    // The collection, saved/loaded per run
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Collection", SaveGame)
    TArray<FCardCollectionEntry> CardCollection;

    // Reference needed for destruction logic
    UPROPERTY() TWeakObjectPtr<UEssenceManager> EssenceManager;

    UFUNCTION(BlueprintCallable, Category = "Collection")
    void AddCardToCollection(UCardBase* CardData); // Adds one instance

    // Destroys a card instance permanently for the run, grants essence
    UFUNCTION(BlueprintCallable, Category = "Collection")
    bool DestroyCardInCollection(UCardBase* CardData);

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Collection")
    int32 GetCardCount(UCardBase* CardData) const;

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Collection")
    TArray<UCardBase*> GetAvailableCardsForDeckbuilding() const; // Returns list of unique card types owned

    // Function to load/save collection data via SaveGame system
    void LoadCollection(/* From SaveGame data */);
    void PopulateSaveData(/* To SaveGame data */);

private:
    int32 GetEssenceFromCardDestruction(UCardBase* CardData); // Define value based on rarity etc.
};

11. Ability System (UAbility, UActionAbility, UHypeAbility)

  • Purpose: Defines structure and logic for special actions. Use Data Assets (UAbilityData) or a component-based approach.
  • Code Structure:
    • FStatModifier (Central Struct): StatName (FName/Enum), ModifierAmount, Duration (Turns), bIsPercentage, bStacks.
    • UAbilityBase (Base Data Asset/Object): Name, Description, Icon, Costs (Stamina, Hype), Cooldown (Turns), TargetingType (Enum), AreaPattern (TArray<FIntPoint>), FGameplayTagContainer AbilityTags. Virtual CanActivate(Actor), Activate(Actor, TargetData).
    • UActionAbilityData (Derived): EActionType, Subtype (e.g., EMoveType), TArray<FStatModifier> applied on use. Activate calls BattleManager action.
    • UHypeAbilityData (Derived): EEssenceType requirement, HypeThreshold. CanActivate checks Hype. Activate implements special effect.
    • UEssenceAbilityData (Derived): Tied to specific Essence type. Can be passive (applied constantly if baller has essence) or active.
// FStatModifier.h (Define where appropriate)
#pragma once
#include "CoreMinimal.h"
#include "FStatModifier.generated.h"

USTRUCT(BlueprintType)
struct FStatModifier
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite) FName StatName; // Target stat (use Enum or FName for safety)
    UPROPERTY(EditAnywhere, BlueprintReadWrite) float ModifierAmount;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 Duration = 1; // In turns or seconds? Define unit.
    UPROPERTY(EditAnywhere, BlueprintReadWrite) bool bIsPercentage = false;
    UPROPERTY(EditAnywhere, BlueprintReadWrite) bool bStacks = false; // Can multiple instances stack?

    FStatModifier() : StatName(NAME_None), ModifierAmount(0.0f), Duration(1), bIsPercentage(false), bStacks(false) 
;

12. Essence System (UEssenceManager)

  • Purpose: Manages Colored (thematic) and Neutral (upgrade currency) Essence. Handles acquisition, spending, and potentially Baller Empowerment. Component on GameState or similar.
  • Code: EssenceManager.h/.cpp
// EssenceManager.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "BallerCharacter.h" // Include EEssenceType
#include "EssenceManager.generated.h"

// Forward declarations
class UBallerCard;
class UEquipmentCard;
class UAbility;

/** Manages essence collection, storage, and usage */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UEssenceManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UEssenceManager();
    virtual void BeginPlay() override;

    // Player's current Essence inventory (Persisted via SaveGame)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Essence", SaveGame)
    TMap<EEssenceType, int32> ColoredEssenceInventory;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Essence", SaveGame)
    int32 NeutralEssenceAmount = 0;

    // --- Essence Management ---
    UFUNCTION(BlueprintCallable, Category = "Essence")
    void AddColoredEssence(EEssenceType Type, int32 Amount);
    UFUNCTION(BlueprintCallable, Category = "Essence")
    bool ConsumeColoredEssence(EEssenceType Type, int32 Amount);
    UFUNCTION(BlueprintCallable, Category = "Essence")
    int32 GetColoredEssenceAmount(EEssenceType Type) const;

    UFUNCTION(BlueprintCallable, Category = "Essence")
    void AddNeutralEssence(int32 Amount);
    UFUNCTION(BlueprintCallable, Category = "Essence")
    bool ConsumeNeutralEssence(int32 Amount); // Returns true if successful
    UFUNCTION(BlueprintCallable, Category = "Essence")
    int32 GetNeutralEssenceAmount() const;

    // --- Gameplay Integration ---
    // Empower baller - Applies temporary (e.g., one match) essence effects. Cost/Source TBD.
    UFUNCTION(BlueprintCallable, Category = "Essence")
    bool EmpowerBaller(ABallerCharacter* Baller, EEssenceType Type, bool bIsTemporary = true);

    // Ability Upgrades - Uses Neutral Essence
    // UFUNCTION(BlueprintCallable, Category = "Essence")
    // bool CanAffordUpgrade(UAbility* AbilityToUpgrade) const; // Needs cost definition on Ability
    // UFUNCTION(BlueprintCallable, Category = "Essence")
    // bool PurchaseAbilityUpgrade(UAbility* AbilityToUpgrade); // Consumes Neutral Essence

    // Function to load/save essence data via SaveGame system
    void LoadEssence(/* From SaveGame data */);
    void PopulateSaveData(/* To SaveGame data */);
};

(Implementation Notes: Define the 8 Essence Types: Werewolf, Voodoo, Witch, Beast, Ocean, Police, Tree People, Vampire and their general thematic effects/associated abilities. Clarify mechanics/cost/persistence of `EmpowerBaller`.)

13. Overworld System (AOverworldManager, ASubRealm, AOverworldObject)

  • Purpose: Manages player navigation between Sub-Realms (potentially on a node-based map), interactions with objects (Courts, Items, NPCs), and discovering content outside of matches.
  • Code: OverworldManager.h/.cpp, SubRealm.h/.cpp, OverworldObject.h/.cpp
// OverworldManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "OverworldManager.generated.h"

// Forward Declarations
class ASubRealm;
class AOverworldObject;

/** Manages the overworld navigation and interactions */
UCLASS()
class BALLHALLA_API AOverworldManager : public AActor
{
    GENERATED_BODY()
public:
    AOverworldManager();
    virtual void BeginPlay() override;

    // List of all potential SubRealms in the game
    UPROPERTY(EditDefaultsOnly, Category = "Overworld Config")
    TArray<TSubclassOf<ASubRealm>> AllSubRealmClasses; // Or load from data asset

    // Current state (Run specific - Saved/Loaded)
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Overworld State", SaveGame)
    TArray<FName> UnlockedSubRealmKeys; // Identifiers for unlocked realms

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Overworld State", SaveGame)
    FName CurrentSubRealmKey; // Identifier for player's current location

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Overworld State")
    ASubRealm* CurrentSubRealmActor; // Spawned actor instance for current realm

    // Functions for managing state and travel
    UFUNCTION(BlueprintCallable, Category = "Overworld")
    void TravelToSubRealm(FName TargetRealmKey);

    UFUNCTION(BlueprintCallable, Category = "Overworld")
    void InteractWithObject(AOverworldObject* Object); // Called by player controller

    UFUNCTION(BlueprintCallable, Category = "Overworld")
    void UnlockSubRealm(FName RealmKey);

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Overworld")
    bool IsSubRealmUnlocked(FName RealmKey) const;

    // Function to load/save Overworld state via SaveGame system
    void LoadOverworldState(/* From SaveGame data */);
    void PopulateSaveData(/* To SaveGame data */);

private:
    void LoadSubRealmLevel(FName RealmKey); // Handles level streaming / loading
};

// SubRealm.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BallerCharacter.h" // For EEssenceType
#include "SubRealm.generated.h"

/** Represents a themed area in the overworld */
UCLASS()
class BALLHALLA_API ASubRealm : public AActor
{
    GENERATED_BODY()
public:
    ASubRealm();

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Realm")
    FName RealmKey; // Unique identifier used by OverworldManager
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Realm")
    FString RealmName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Realm")
    FString Description;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Realm")
    EEssenceType RealmEssence;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sub-Realm")
    int32 DifficultyLevel = 1; // Base difficulty

    // Define potential contents (spawn points, encounter triggers, etc.)
    // UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sub-Realm")
    // TArray Courts;
    // UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sub-Realm")
    // TArray FreeAgents;
    // UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Sub-Realm")
    // TArray Items;
};

// OverworldObject.h (Abstract Base)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "OverworldObject.generated.h"

/** Base class for all interactable objects in the overworld */
UCLASS(Abstract)
class BALLHALLA_API AOverworldObject : public AActor
{
    GENERATED_BODY()
public:
    AOverworldObject();

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Overworld Object")
    FString ObjectName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Overworld Object")
    FString Description;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Overworld Object")
    UTexture2D* Icon;

    // Called when player interacts
    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Overworld Object")
    void OnInteract(APlayerController* InteractingController);
    virtual void OnInteract_Implementation(APlayerController* InteractingController);

    // Check if interaction is possible
    UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Overworld Object")
    bool CanInteract(APlayerController* InteractingController);
    virtual bool CanInteract_Implementation(APlayerController* InteractingController);
};
// Derived classes: ACourtEntrance, AFreeAgentCharacter, AItemPickup, ADraftScout, AGameTapePickup, etc.

13.1. Random Overworld Events (Placeholder)

  • Purpose: Enhance roguelike variance during Overworld exploration via random encounters/choices.
  • Scope & Implementation: Define trigger conditions (% chance, node types). Use Data Assets (UOverworldEventDataAsset) for event structure (Text, Choices[FEventChoice], Outcomes[FEventOutcome]). Use Data Tables for encounter lists per Sub-Realm. AOverworldManager handles triggering, UI display, choice resolution, and outcome execution via other managers.
  • MVP Status: Post-MVP.

14. Progression System (UProgressionManager)

  • Purpose: Manages persistent *run-based* progression: Baller Rank/XP and Facility Upgrades. Component on GameState or similar. Resets at start of new run.
  • Code: ProgressionManager.h/.cpp
// ProgressionManager.h
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "BallerCharacter.h" // Include ERank
#include "ProgressionManager.generated.h"

// Forward declarations
class UEssenceManager;

UENUM(BlueprintType)
enum class EFacilityType : uint8 {
    Concession UMETA(DisplayName = "Concession Stand"),
    Merchandise UMETA(DisplayName = "Merchandise Mart"),
    Coaching UMETA(DisplayName = "Coaching Staff"),
    FrontOffice UMETA(DisplayName = "Front Office"),
    LockerRoom UMETA(DisplayName = "Locker Room")
};

/** Manages run-based progression: Baller XP/Rank and Facility Upgrades */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UProgressionManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UProgressionManager();
    virtual void BeginPlay() override;

    // --- Dependencies ---
    UPROPERTY() TWeakObjectPtr<UEssenceManager> EssenceManager; // Needed for upgrade costs

    // --- Facility Levels (Run Specific - Saved/Loaded via SaveGame) ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Progression|Facilities", SaveGame)
    TMap<EFacilityType, int32> FacilityLevels;

    // Map to store current XP for each baller (Run Specific - Saved/Loaded)
    // Key: Baller UniqueID (FString or FName)
    UPROPERTY(VisibleAnywhere, Category = "Progression|Baller", SaveGame)
    TMap<FString, int32> BallerExperience;

    // --- Configuration ---
    UPROPERTY(EditDefaultsOnly, Category = "Progression|Config")
    int32 MaxFacilityLevel = 5;
    // Define XP requirements per rank (e.g., Rookie->Starter = 100XP, Starter->Veteran=250XP)
    UPROPERTY(EditDefaultsOnly, Category = "Progression|Config")
    TMap<ERank, int32> RankExperienceRequirements;
    // Define Facility Upgrade Costs (Neutral Essence) - Array index corresponds to level upgrading TO (Index 0 = cost to level 1->2)
    // UPROPERTY(EditDefaultsOnly, Category = "Progression|Config")
    // TMap<EFacilityType, TArray<int32>> FacilityUpgradeCosts;

    // --- Run Initialization ---
    UFUNCTION(BlueprintCallable, Category = "Progression")
    void InitializeForNewRun(); // Resets Levels and XP maps to default (Level 1, 0 XP)

    // --- Baller Progression ---
    UFUNCTION(BlueprintCallable, Category = "Progression|Baller")
    void AddExperienceToBaller(const FString& BallerUniqueID, ABallerCharacter* BallerInstance, int32 Amount); // Handles XP gain and checks for Rank Up

private:
    UFUNCTION() // Internal helper
    bool CheckAndPromoteBallerRank(const FString& BallerUniqueID, ABallerCharacter* BallerInstance);

public:
    // --- Facility Management ---
    UFUNCTION(BlueprintCallable, Category = "Progression|Facilities")
    bool UpgradeFacility(EFacilityType Type); // Checks cost, consumes Neutral essence, increments level

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Progression|Facilities")
    int32 GetFacilityLevel(EFacilityType Type) const;

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Progression|Facilities")
    int32 GetFacilityUpgradeCost(EFacilityType Type) const; // Cost for *next* level

    // --- Facility Bonuses (Calculated based on levels) ---
    // These functions return the current bonus provided by facility levels
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Progression|Bonuses")
    float GetHypeGenerationBonus() const; // From Concession Stand
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Progression|Bonuses")
    float GetStaminaRegenBonus() const; // From Coaching
    // ... other facility bonus getters ...

    // Functions to load/save progression data via SaveGame system
    void LoadProgression(/* From SaveGame data */);
    void PopulateSaveData(/* To SaveGame data */);
};

(Implementation Notes: Define specific XP curves and Facility upgrade costs/effects.)

14.1. Post-Match Reward System

  • Purpose: Distributes rewards after winning a match. Triggered by MatchManager.
  • Rewards:
    • XP: Awarded to participating ballers (full share for active, reduced for bench/exhausted). Scales with opponent difficulty. Handled via UProgressionManager.
    • Colored Essence: 1 unit matching defeated team's type. Unlocks potential. Handled via UEssenceManager.
    • Neutral Essence: Variable amount based on opponent difficulty. Used for upgrades. Handled via UEssenceManager.
    • Card Rewards: Player chooses 1 from several offered cards (Play/Equipment). Pool influenced by context. Added via UCardCollectionManager. Requires UI.
  • Logic Flow (Summary in MatchManager::DistributeRewards): Verify win -> Determine opponent details -> Calculate & Distribute XP -> Add Colored Essence -> Calculate & Add Neutral Essence -> Trigger Card Reward UI & process choice.

15. Play System (UPlaySystemManager, UPlayData)

  • Purpose: Manages the calling and execution tracking of basketball plays initiated via Play Cards. Provides bonuses upon successful execution.
  • Code: PlaySystemManager.h/.cpp (Likely Actor Component), PlayData.h/.cpp (Data Asset)
// PlayData.h (Use Data Asset)
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h" // For tags if used
#include "BallerCharacter.h" // For Enums
#include "AbilitySystem/FStatModifier.h" // Assuming path
#include "PlayData.generated.h"

USTRUCT(BlueprintType)
struct FPlayActionStep // Defines one step in a play's sequence
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    EActionType ActionType;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(EditCondition="bRequirePosition"))
    EPosition RequiredPosition = EPosition::PointGuard; // Optional: Specific position must perform

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    bool bRequirePosition = false;

    // Optional: Define target requirements (e.g., pass to Center, screen near basket)
    // UPROPERTY(EditAnywhere, BlueprintReadWrite) FGameplayTagContainer TargetRequirementTags;
};

/** Data asset defining a single basketball play */
UCLASS()
class BALLHALLA_API UPlayData : public UDataAsset
{
    GENERATED_BODY()
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") FString PlayName;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") FText Description;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") TSoftObjectPtr<UTexture2D> DiagramImage;

    // Required sequence of actions
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") TArray<FPlayActionStep> RequiredActions;

    // Stat modifiers applied to team/actors on successful execution
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") TArray<FStatModifier> SuccessModifiers;

    // Difficulty rating (influences AI usage, maybe cost)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play", meta = (ClampMin = "1", ClampMax = "10"))
    int32 DifficultyRating = 5;

    // Positions required on the court for this play to be viable
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") TArray<EPosition> RequiredPositions;

    // Gameplay Tags associated with this play (for synergy etc.)
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Play") FGameplayTagContainer PlayTags;

    // Function to check if a sequence of recent actions matches this play
    bool CheckActionSequence(const TArray<struct FActionRecord>& Actions) const;
};

// PlaySystemManager.h (Likely Actor Component on BattleManager or TeamManager)
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
// Include PlayData, FActionRecord
#include "PlaySystemManager.generated.h"

// Forward Declarations
class UPlayData;
struct FActionRecord;
class ABallerCharacter;

/** Manages active plays and checks for successful execution */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UPlaySystemManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UPlaySystemManager();
    virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

    // Play currently called by the player/AI
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Play System")
    UPlayData* CurrentCalledPlay;

    // Reference to the action history source (likely BattleManager)
    // UPROPERTY() TWeakObjectPtr BattleManagerRef;

    // Call a play (from Play Card)
    UFUNCTION(BlueprintCallable, Category = "Play System")
    void CallPlay(UPlayData* PlayToCall);

    // Cancel the currently called play
    UFUNCTION(BlueprintCallable, Category = "Play System")
    void CancelCurrentPlay();

    // Check if the called play was successfully executed based on recent actions
    UFUNCTION(BlueprintCallable, Category = "Play System")
    void CheckPlayExecution(); // Called after each action is recorded

private:
    // Apply bonuses if execution successful
    void ApplyPlayBonuses(UPlayData* Play);

    // Handle success/failure feedback or state changes
    void HandleSuccessfulPlay(UPlayData* Play);
    void HandleFailedPlay(UPlayData* Play);

    // Internal state tracking if needed (e.g., current step index)
};

(Implementation Notes: UPlaySystemManager needs access to BattleManager::ActionHistory. CheckPlayExecution compares recent history against UPlayData::RequiredActions. ApplyPlayBonuses applies SuccessModifiers.)

16. Hype Action System (UHypeActionManager, UHypeActionData)

  • Purpose: Manages the selection and execution of enhanced "Hype Actions" when a baller's Hype level is high. Includes logic for critical hits triggering Hype Actions.
  • Code: HypeActionManager.h/.cpp (Likely Actor Component), HypeActionData.h/.cpp (Data Asset)
// HypeActionData.h (Use Data Asset)
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "BallerCharacter.h" // For Enums EActionType, EHypeLevel
// #include "AbilityBase.h" // Reference ability types
#include "HypeActionData.generated.h"

// Forward Declaration
class UAbilityBase; // Or specific Ability Data Asset type

/** Data asset defining hype variations for a base action */
UCLASS()
class BALLHALLA_API UHypeActionData : public UDataAsset
{
    GENERATED_BODY()
public:
    // The base action this data corresponds to
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hype Action")
    EActionType BaseActionType;

    // Define the ability/action variation for each hype level
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hype Action", meta=(DisplayName="Normal Action (Low Hype)"))
    TSoftObjectPtr<UAbilityBase> NormalAction; // Pointer to Ability Data Asset

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hype Action", meta=(DisplayName="Hype Action (Medium Hype)"))
    TSoftObjectPtr<UAbilityBase> HypeAction;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hype Action", meta=(DisplayName="Super Hype Action (High Hype)"))
    TSoftObjectPtr<UAbilityBase> SuperHypeAction;

    // Chance (0-100) for a 'Critical Hit' - using a higher-tier action than current hype allows
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hype Action", meta = (ClampMin = "0", ClampMax = "100"))
    float CriticalHitChance = 5.0f;

    // Get the appropriate ability data asset based on hype level
    UFUNCTION(BlueprintCallable, Category = "Hype Action")
    UAbilityBase* GetActionForHypeLevel(EHypeLevel HypeLevel) const;
};


// HypeActionManager.h (Likely Actor Component on BattleManager or accessible globally)
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "BallerCharacter.h" // For Enums
#include "HypeActionManager.generated.h"

// Forward Declarations
class UHypeActionData;
class ABallerCharacter;
class UAbilityBase;

/** Manages hype-enhanced actions and critical hits */
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class BALLHALLA_API UHypeActionManager : public UActorComponent
{
    GENERATED_BODY()
public:
    UHypeActionManager();
    virtual void BeginPlay() override;

    // Map base action types to their hype data assets (Populated from config/registry)
    UPROPERTY(EditDefaultsOnly, Category = "Hype System")
    TMap<EActionType, UHypeActionData*> HypeActionMap;

    // Get the Hype-modified Ability/Action to use based on baller's state and base action type
    UFUNCTION(BlueprintCallable, Category = "Hype System")
    UAbilityBase* GetAppropriateAction(ABallerCharacter* Baller, EActionType BaseActionType);

    // Check if a critical hit should occur for a given action
    UFUNCTION(BlueprintCallable, Category = "Hype System")
    bool ShouldTriggerCriticalHit(ABallerCharacter* Baller, EActionType BaseActionType);

    // Potentially trigger the critical hit effect (e.g., modify action outcome or use higher-tier ability)
    // UFUNCTION(BlueprintCallable, Category = "Hype System")
    // void TriggerCriticalHitEffect(ABallerCharacter* Baller, EActionType BaseActionType);

private:
    // Helper to get the specific UHypeActionData for a base action type
    UHypeActionData* GetHypeDataForAction(EActionType BaseActionType) const;
};

(Implementation Notes: UHypeActionManager::GetAppropriateAction selects Ability based on BaseActionType and current EHypeLevel. Critical Hit logic checks chance and potentially returns a higher-tier ability than expected for the current Hype level.)

17. AI Defense System (ADefensiveAIController)

  • Purpose: Controls enemy baller behavior during player's offense. Uses utility scores (CalculateDefensiveUtility) to choose actions (Guard, Switch, Swipe, DoubleTeam, TrashTalk). Influenced by Natural Gravity.
  • Code: DefensiveAIController.h/.cpp
// DefensiveAIController.h
#pragma once
#include "CoreMinimal.h"
#include "AIController.h"
// Include necessary headers: BallerCharacter, GridCell
#include "DefensiveAIController.generated.h"

UENUM(BlueprintType)
enum class EDefensiveAction : uint8
{
    Guard UMETA(DisplayName = "Guard"),
    Switch UMETA(DisplayName = "Switch"),
    Swipe UMETA(DisplayName = "Swipe"),
    DoubleTeam UMETA(DisplayName = "Double Team"),
    TrashTalk UMETA(DisplayName = "Trash Talk"),
    HelpDefense UMETA(DisplayName = "Help Defense") // Subtle repositioning
};

/** AI controller for defensive players */
UCLASS()
class BALLHALLA_API ADefensiveAIController : public AAIController
{
    GENERATED_BODY()
public:
    ADefensiveAIController();
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override; // For decision timing

    // Assign the primary offensive player this AI should focus on
    UFUNCTION(BlueprintCallable, Category = "Defensive AI")
    void AssignDefensiveTarget(ABallerCharacter* NewTarget);

    // Core decision loop, called periodically
    UFUNCTION(BlueprintCallable, Category = "Defensive AI")
    void DecideNextAction();

protected:
    // Calculates the utility score for performing a given action in the current context
    UFUNCTION(BlueprintNativeEvent, Category = "Defensive AI")
    float CalculateDefensiveUtility(EDefensiveAction Action);
    virtual float CalculateDefensiveUtility_Implementation(EDefensiveAction Action);

    // Chooses the best action based on utility scores
    UFUNCTION(BlueprintCallable, Category = "Defensive AI")
    EDefensiveAction ChooseBestDefensiveAction();

    // Executes the chosen action
    UFUNCTION(BlueprintCallable, Category = "Defensive AI")
    void PerformDefensiveAction(EDefensiveAction Action);

    // Specific action logic implementations
    virtual void ExecuteGuardAction();
    virtual void ExecuteSwitchAction(); // Needs logic to find suitable switch target/partner
    virtual void ExecuteSwipeAction(); // Calls BattleManager potentially
    virtual void ExecuteDoubleTeamAction(); // Needs coordination with another AI/TeamManager
    virtual void ExecuteTrashTalkAction(); // Calls BattleManager potentially
    virtual void ExecuteHelpDefenseAction(); // Adjusts position slightly towards high gravity threat

    // React to specific offensive moves made by the target or nearby players
    UFUNCTION(BlueprintCallable, Category = "Defensive AI")
    void ReactToOffensiveMove(ABallerCharacter* OffensivePlayer, EActionType Action);

private:
    UPROPERTY() TWeakObjectPtr<ABallerCharacter> AssignedTarget;
    UPROPERTY() TWeakObjectPtr<ABallerCharacter> ControlledDefender; // The Pawn this controller possesses

    UPROPERTY() EDefensiveAction CurrentAction;
    UPROPERTY() float DecisionCooldownTimer = 0.0f;
    UPROPERTY(EditDefaultsOnly, Category = "Defensive AI") float DecisionInterval = 1.0f; // Time between decisions

    // Target for double teaming, if active
    UPROPERTY() TWeakObjectPtr<ABallerCharacter> DoubleTeamTarget;
};

(Implementation Notes: Fix UseTrashTalk typo if present in original implementation. Integrate Natural Gravity calculations into utility scores and targeting, especially for Guard, HelpDefense, and DoubleTeam actions.)

18. AI Offensive System

  • Purpose: Controls enemy baller behavior during their own offensive phase.
  • Core Logic: Utility-based decision making (CalculateOffensiveUtility). Considers Baller Capabilities, Court Position, Defensive Pressure, Teammate Status, Game State, Resources (Stamina/Hype), Active Plays, and Team Style Bias.
  • Actions: Implements logic for choosing Move targets, Pass targets (risk/reward), when to Shoot (based on % chance, clock), when to Fake/Talk/Screen, and when/how to use Abilities/Hype.
  • Play Calling: AI has a small playbook (2-4 Play Cards per style), evaluates calling plays, prioritizes executing called plays, may abandon if disrupted.
  • Difficulty Scaling: Adjusts complexity of utility calculation, play usage, resource management.
  • Code: Requires OffensiveAIController or integration into TeamManager/BattleManager AI turn logic. Requires defining CalculateOffensiveUtility and corresponding action execution functions similar to the Defensive AI.

19. Player-Directed AI Strategy (Placeholder)

  • Purpose: (Potential Post-MVP Feature) To allow players a degree of influence over their *own team's* AI behavior during the **Defensive Phase**, enhancing strategic control.
  • Scope & Implementation: Define simple strategy options (e.g., Stance: Aggressive/Balanced/Conservative; Focus: Perimeter/Paint/Ball). Store player choice (per-run or persistent). Modify ADefensiveAIController utility calculations based on selected strategy. Requires UI for setting strategy.
  • MVP Status: Post-MVP.

20. Match Manager (AMatchManager)

  • Purpose: Manages the overall flow of a single match: teams involved, score, quarters, halftime, timeouts, overtime conditions, and triggering reward distribution.
  • Code: MatchManager.h/.cpp
// MatchManager.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
// Include/Forward Declare Managers: BattleManager, TurnManager, TeamManager
#include "MatchManager.generated.h"

UENUM(BlueprintType)
enum class ETeam : uint8 { None, Player, Enemy, Tie }; // For determining winner

// Add Delegates if needed (OnMatchStarted, OnMatchEnded, OnScoreChanged)

/** Manages the state and flow of a single basketball match */
UCLASS()
class BALLHALLA_API AMatchManager : public AActor
{
    GENERATED_BODY()
public:
    AMatchManager();
    virtual void BeginPlay() override;

    // --- Manager References ---
    UPROPERTY() TWeakObjectPtr<ABattleManager> BattleManager;
    UPROPERTY() TWeakObjectPtr<ATurnManager> TurnManager;
    UPROPERTY() TWeakObjectPtr<AGameManager> GameManager; // To report match end

    // --- Match Participants ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Match Teams")
    ATeamManager* PlayerTeam; // Assign these when match is set up
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Match Teams")
    ATeamManager* EnemyTeam;  // Assign these when match is set up

    // --- Match State ---
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Match State")
    int32 PlayerScore = 0;
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Match State")
    int32 EnemyScore = 0;
    UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Match State") // RW to allow decrementing
    int32 PlayerTimeoutsRemaining = 2; // Add logic to enforce this limit
    // UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Match State")
    // int32 EnemyTimeoutsRemaining = 2; // If AI uses timeouts

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Match State")
    bool bIsOvertime = false;

    // --- Match Flow Control ---
    UFUNCTION(BlueprintCallable, Category = "Match Flow")
    void SetupMatch(ATeamManager* InPlayerTeam, ATeamManager* InEnemyTeam); // Initialize teams

    UFUNCTION(BlueprintCallable, Category = "Match Flow")
    void StartMatch(); // Begins the first quarter via TurnManager

    UFUNCTION(BlueprintCallable, Category = "Match Flow") // Called by TurnManager usually
    void EndMatch(); // Determines winner, triggers rewards via DistributeRewards

    UFUNCTION(BlueprintCallable, Category = "Match Flow")
    bool CanCallTimeout(bool bIsPlayerTeam) const;
    UFUNCTION(BlueprintCallable, Category = "Match Flow")
    void CallTimeout(bool bIsPlayerTeam); // Decrements count, notifies TurnManager

    UFUNCTION(BlueprintCallable, Category = "Match Flow")
    void StartOvertime(); // Called if score tied after 4 quarters

    // --- Gameplay Interaction (Called by BattleManager) ---
    UFUNCTION(BlueprintCallable, Category = "Match Gameplay")
    void AddPoints(ETeam Team, int32 Points); // Updates score

    // --- Results & Rewards ---
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Match Results")
    ETeam GetWinningTeam() const;

    UFUNCTION(BlueprintCallable, Category = "Match Results")
    void DistributeRewards(); // Contains logic for XP, Essence, Cards (See Section 14.1)

private:
    // Helper to check if overtime is needed
    bool ShouldGoToOvertime() const;
    // Potentially internal helpers for reward calculation if logic is complex
};

(Implementation Notes: Needs logic for timeout limits/enforcement. DistributeRewards function details are in Section 14.1.)

21. Save/Load System

  • Purpose: Handles automatic saving/loading of the current roguelike run's progress via a single slot.
  • Triggers: Autosaves on Overworld Travel (between Sub-Realms/major locations), Post-Match (Win), potentially major progression events. No saving during match.
  • Saved Data: Team Roster (Baller ID, Rank, potentially persistent Essence/Equipment), Card Collection (Owned Play/Equipment types & counts), Essence Inventory (Colored/Neutral), Facility Levels, Baller XP Map, Current Overworld Location, Unlocked Realms/Paths, Persistent World State Flags.
  • Implementation: Use USaveGame object (UBallhallaSaveGame). Logic resides in AGameManager::SaveGame/LoadGame. Handle new game if no save exists. Single slot name (e.g., "BallhallaAutosaveSlot").

22. Player Profile / Meta Progression

  • Purpose: Tracks achievements and unlocks persisting *between* runs (meta-progression). Separate from the single-run autosave.
  • Facility Reset Policy: All Facility levels managed by UProgressionManager **reset to Level 1** at the start of each new run.
  • Scope (Post-MVP): Define permanent unlocks (New Cards, Playstyles, Events, Starting Bonuses). Store in UPlayerProfile (separate save file). Unlocks triggered by achievements. Affects content generation/options in future runs.
  • Playstyle Cards: Unique cards unlocked via meta-progression, selected pre-run to grant team-wide effects (e.g., "7 Seconds or Less," "Twin Towers").
  • MVP Status: Post-MVP for unlocks. Facility Reset policy is MVP relevant.

23. Minimum Viable Product (MVP) Definition

  • Core Loop: Grid Movement -> Turn/Shot Clock -> Basic Actions (Move, Pass, Shoot) -> Stamina/Hype Resources -> Basic Make/Miss -> Basic AI Defense Sim -> Quarter Progression -> Win/Loss.
  • Includes: Functional core systems (Grid, Turn, Baller Character, Resource, Battle, Match, Team systems at their core level). Minimal AI Defense & simulated AI Offense. Baller Cards for initial roster. Basic UI for selection and state display.
  • Excludes (Initially): Advanced AI (Offense/Defense details), Full Card System (Plays, Equipment, In-Match Draw/Play), Advanced Hype/Play/Essence/Status Effects, Overworld, Progression (XP/Facilities), Narrative, Audio, Gravity, Complex Rebounding/Turnovers, Detailed Balancing/Polish, Meta Progression.

24. Implementation Notes & Best Practices

  • Data Assets: Use for static definitions (Cards, Abilities, Conditions, Plays, etc.).
  • Grid Array: Use flat 1D TArray for GridCells.
  • Pre-calculation: Calculate static grid data (DistanceFromRim, AreaType) on init.
  • Structs: Use for grouping stats (FBallerStats), effects (FStatModifier, FConditionEffect).
  • Weak Pointers: Use TWeakObjectPtr for inter-object references to prevent cycles.
  • Components: Use UActorComponent for modular logic/state (UStatusManagerComponent, UDeckManager, UCardCollectionManager, UEssenceManager, UProgressionManager).
  • Event-Driven: Use Delegates for manager communication.
  • Clear Ownership: Define state ownership clearly (e.g., BattleManager owns ActionHistory).
  • Placeholders: Mark values needing tuning clearly.
  • Gameplay Tags: Use Unreal's Gameplay Tag system for Conditions, Synergies, Action Blocking.

25. Known Design Gaps / Areas for Future Definition

  • Stat Balancing & Economy Formulas: Precise values for XP curves, Essence costs, ability costs, AI weights, rebound factors, pass/steal rates, shot formulas, reward scaling, Card Destruction Essence return. (Status: ⚠️ Placeholder)
  • UI/UX Design Documentation: Mockups, wireframes, interaction flows, asset requirements, style guides for all interfaces. (Status: ❌ Missing)
  • Detailed Ability/Card/Condition/Playstyle Effects:** Specific implementation logic & balancing for *all* unique items. (Status: ⚠️ Placeholder)
  • Narrative Implementation:** Technical design for dialogue display, cutscenes, story progression flags. (Status: ❌ Missing)
  • Audio Design:** List of required SFX, music, VO needs. (Status: ❌ Missing)
  • Condition System Details:** Finalized list, effects, durations, stacking rules, interactions. (Status: 📝 Expanded, Needs Detail)
  • Card Synergy/Tag Details:** Finalized tag hierarchy & specific interaction logic. (Status: 📝 Expanded, Needs Detail)
  • Random Overworld Event Details:** Specific event content, tables, logic, UI. (Status: 📝 Expanded, Needs Detail)
  • Card Collection Implementation:** Final design details for UI interaction, sorting/filtering. (Status: 📝 Expanded, Needs Detail)
  • Meta Progression Details:** Specific unlockables, trigger conditions, UI. (Status: 📝 Expanded, Needs Detail)
  • Player-Directed AI Strategy Design:** Specifics (Post-MVP). (Status: 📝 Expanded, Needs Detail)
  • Deck/Timeout Limit Enforcement Logic:** Specific implementation details for UI/gameplay checks. (Status: ⚠️ Implementation Detail Needed)
  • Baller Card Deck Rule:** Clarify `MaxBallerCardsInDeck` rule - likely applies to Roster Size / Collection rules, not Match Deck. (Status: ⚠️ Needs Clarification)
```