Block 2 — Raccoon Roster (1 day)
Goal: Raccoons exist as persistent, named entities the player can inspect. Starter crew spawns on game start. Full UTNTRaccoonSubsystem operational.
Depends on: Block 1 data model (FTNTRaccoonData, FTNTStatBlock, subsystem stubs).
Naming convention: All gameplay types carry the
TNTprefix (UTNT…,FTNT…,ETNT…). Earlier drafts of this page used un-prefixed names; the implementation standardised on the prefix during Block 1.
Deliverables
UTNTRaccoonSubsystem — Full Implementation (C++)
Class: UTNTRaccoonSubsystem : UGameInstanceSubsystem.
Header: Source/TrashNTreasure/Public/Subsystems/TNTRaccoonSubsystem.h · Impl: Source/TrashNTreasure/Private/Subsystems/TNTRaccoonSubsystem.cpp.
All functions UFUNCTION(BlueprintCallable, Category = "TNT|Raccoon"):
| Function | Signature | Purpose |
|---|---|---|
AddRaccoon | FGuid (ETNTRaccoonType, const FString& Name = TEXT("")) | Roll FTNTRaccoonData from the resolved UTNTRaccoonTypeDataAsset (random within stat ranges). Generate name if empty. Append to TArray<FTNTRaccoonData>. Broadcast OnRosterChanged and OnRaccoonAdded. |
RemoveRaccoon | void (FGuid) | Remove from array. Unassign from station if assigned. Broadcast OnRosterChanged. Used for desertion and capture. |
GetRaccoon | FTNTRaccoonData (FGuid) const | Return copy for Blueprint. Sentinel: empty Name == not found. Internal helpers Find / FindMutable return pointers. |
GetAllRaccoons | TArray<FTNTRaccoonData> () const | Full roster for UI. |
GetEffectiveStats | FTNTStatBlock (FGuid) const | Base + Training + Gear. Sums FTNTRaccoonData::BaseStats + TrainingBonus + resolved row from GearTable (FTNTGearRow::StatBonus). Clamped to 100 per stat via ClampBlock100. |
GetInheritedStats | FTNTStatBlock (FGuid) const | Base + Training (no gear). Used by breeding to determine parent contribution. |
GetCrewStatSum | FTNTStatBlock (const TArray<FGuid>& Crew) const | Sum GetEffectiveStats across crew. Used by encounter resolution (Block 4). |
SetStatus | void (FGuid, ETNTRaccoonStatus) | Validate transition via IsLegalTransition, update, broadcast OnRosterChanged. |
GetRaccoonsByStatus | TArray<FGuid> (ETNTRaccoonStatus) const | Filter roster by status. |
EquipGear | bool (FGuid, FName GearRow) | Set EquippedGearRowName. Returns false if raccoon not found or already equipped. |
UnequipGear | FName (FGuid) | Clear gear slot, return row name for inventory. |
GenerateName | FString () | Pick from NamePool (seeded via SeedNamePool). Avoid duplicates within current roster. |
Internal state (extends Block 1 stubs — Raccoons and NamePool declared there):
| Member | Type | Purpose |
|---|---|---|
OnRosterChanged | FOnRosterChanged (DYNAMIC_MULTICAST_DELEGATE) | BlueprintAssignable. Broadcast on any roster mutation. UI binds to this. |
OnRaccoonAdded | FOnRaccoonAdded (DYNAMIC_MULTICAST_DELEGATE_OneParam) | BlueprintAssignable. Param: FGuid RaccoonId. Fired from AddRaccoon only. Used by UTNTProgressionSubsystem to track recruitment milestones. |
GearTable | TObjectPtr<UDataTable> (EditDefaultsOnly) | Gear modifier table. Rows are FTNTGearRow { FName DisplayName; FTNTStatBlock StatBonus; } (Source/TrashNTreasure/Public/Data/TNTGearRow.h). GetEffectiveStats resolves EquippedGearRowName against this table. |
Type asset resolution — UTNTRaccoonSettings (Developer Settings)
Type → asset mapping is held in a UDeveloperSettings rather than scanned from the AssetRegistry.
- Class:
UTNTRaccoonSettings : UDeveloperSettings(Source/TrashNTreasure/Public/Settings/TNTRaccoonSettings.h). - Property:
TMap<ETNTRaccoonType, TSoftClassPtr<UTNTRaccoonTypeDataAsset>> TypeAssets(Config,EditAnywhere). - Edited in Project Settings → Game → Trash N Treasure - Raccoons, persisted to
Config/DefaultGame.ini. UTNTRaccoonSubsystem::ResolveTypeAsset(ETNTRaccoonType)lazy-loads only the requested type’s CDO on demand.
Why: earlier registry scan during subsystem init caused 15–20 s cold-PIE stalls. Soft-class map sidesteps it and keeps designer-facing wiring in Project Settings (commit 7ab039a).
Raccoon Type DataAssets
Author UTNTRaccoonTypeDataAsset content assets:
| Asset | Primary Stat | Secondary | Starting Ranges |
|---|---|---|---|
DA_Scout | Stealth (15–25) | Cunning (12–20) | Speed 8–15, Strength 5–10, Luck 5–15 |
DA_Hauler | Strength (15–25) | — | Speed 5–10, Stealth 5–10, Cunning 5–10, Luck 5–15 |
Values are tunable placeholders. Each DataAsset lives in Content/TrashNTreasure/Data/RaccoonTypes/ and is registered in UTNTRaccoonSettings::TypeAssets (see above).
Stat Display UI — Player’s Clipboard
Diegetic: the roster is rendered as a clipboard the player holds. No abstract HUD overlay — the fantasy is “raccoon-boss reading the crew sheet”. Blueprint-only UMG, no C++ widget class.
Content/TrashNTreasure/UI/WBP_Roster.uasset— clipboard surface, scrollable list, binds toUTNTRaccoonSubsystem::OnRosterChangedto auto-refresh.Content/TrashNTreasure/UI/WBP_Roster_Card.uasset— per-row entry showing Name, Type, all 5 stats (base / training / gear layers + total), gear slot, current assignment, status.
Toggle is bound to IA_Clipboard (Content/TrashNTreasure/Input/IA_Clipboard.uasset) on BP_PlayerController — pulling the clipboard out / putting it away is the in-fiction equivalent of opening the roster.
Starter Raccoon
ATNTGameMode::BeginPlay (Source/TrashNTreasure/Private/GameModes/TNTGameMode.cpp:34–38) calls UTNTRaccoonSubsystem::AddRaccoon(ETNTRaccoonType::Scout) if the roster is empty, producing a single auto-named Scout.
Player starts with a single Scout. First Hauler is a guaranteed reward from scouting the first house — tutorial-as-gameplay-progression rather than a freebie spawn.
Save/Load
UTNTSaveGame : USaveGame (Source/TrashNTreasure/Public/Save/TNTSaveGame.h):
UTNTSaveGame
TArray<FTNTRaccoonData> Raccoons
FTNTResourceLedger Ledger
TMap<ETNTStationType, FTNTStationRuntimeState> Stations
TArray<FTNTActiveRaid> ActiveRaids
TMap<FName, FTNTMilestoneProgress> Milestones
float GameClockTime // 0–1440 game-minutes, see Game Clock system
FTNTActiveRaid will include phase state, travel/loot progress, backup crew, and encounter pending state — expanded in Block 4. On load, UTNTRaidSubsystem::LoadFromSave will reconstruct raid state: respawn AI pawns for active raids and teleport them to interpolated positions based on saved TravelElapsed / LootProgress.
Each subsystem implements SerializeToSave(UTNTSaveGame*) and LoadFromSave(const UTNTSaveGame*). Orchestrated by a save manager (currently on GameMode). Uses UGameplayStatics::SaveGameToSlot / LoadGameFromSlot. This block only serialises raccoons — other subsystems add their data in later blocks.
Dev save/load round-trip is exercised through input bindings on BP_PlayerController (commit badf844) so the loop can be smoke-tested without UI.
Done When
- Game starts with 1 named Scout visible in the roster UI (clipboard via
IA_Clipboard) - Player can see the raccoon’s name, type, and all 5 stats
-
GetEffectiveStatsreturns correct values (base + training for now — gear tested in Block 8) -
GetInheritedStatsreturns base + training (no gear component) -
GetRaccoonsByStatus(Idle)returns the starter - Raccoons persist through save/load cycle (smoke-tested via
BP_PlayerControllerbindings) -
OnRosterChangeddelegate fires and roster UI refreshes - Roster toggle bound to
IA_ClipboardonBP_PlayerController
References
Units · Scout · Hauler · Raccoon Stats