Block 9 — Progression Hooks (1 day)
Goal: Milestones formalize unlock triggers, replace hardcoded gating from Block 7, and give players directed short-term goals via quest log.
Depends on: Block 7 (target unlocks, Distractor, recruitment), Block 4 (raid completion events).
Deliverables
Milestone DataTable (DT_Milestones)
UDataTable using row struct FMilestoneTableRow:
UENUM(BlueprintType)
enum class EProgressionEvent : uint8 { RaidCompleted, RaccoonRecruited, StationUpgraded, GearCrafted };
UENUM(BlueprintType)
enum class EMilestoneReward : uint8 { UnlockUnit, UnlockTarget, AddRaccoon, AddResource };
USTRUCT(BlueprintType)
struct FMilestoneTableRow : public FTableRowBase {
UPROPERTY(EditAnywhere) FString DisplayName;
UPROPERTY(EditAnywhere) FString Description; // "Complete 5 raids"
UPROPERTY(EditAnywhere) EProgressionEvent TriggerEvent;
UPROPERTY(EditAnywhere) int32 Threshold; // how many events to trigger
UPROPERTY(EditAnywhere) EMilestoneReward RewardType;
UPROPERTY(EditAnywhere) FString RewardPayload; // flexible: unit type name, target asset path, etc.
UPROPERTY(EditAnywhere) FString RewardDescription; // "Hauler unit unlocked!"
};MVP Milestones:
| Row Name | Display | Trigger | Threshold | Reward | Payload |
|---|---|---|---|---|---|
FirstScore | ”First Score” | RaidCompleted | 1 | AddRaccoon | ”Hauler” — new Hauler auto-joins |
GrowingOperation | ”Growing Operation” | RaidCompleted | 5 | UnlockTarget | ”RichNeighbor,GroceryStore” |
StreetCred | ”Street Cred” | RaccoonRecruited | 4 | UnlockUnit | ”Distractor” |
DataTable at Content/TrashNTreasure/Data/Tables/DT_Milestones.uasset.
FMilestoneProgress Struct
USTRUCT(BlueprintType)
struct FMilestoneProgress {
UPROPERTY(BlueprintReadOnly) int32 CurrentCount = 0;
UPROPERTY(BlueprintReadOnly) bool bCompleted = false;
};UProgressionSubsystem — Full Implementation (C++)
| Function | Signature | Purpose |
|---|---|---|
Initialize | void () | Called in ATNTGameMode::BeginPlay. Load DT_Milestones rows into memory. Init TMap<FName, FMilestoneProgress> for each row. Bind to subsystem delegates: URaidSubsystem::OnRaidCompleted, URaccoonSubsystem::OnRosterChanged. |
HandleEvent | void (EProgressionEvent, int32 Count=1) | C++ — iterates milestone table. For each milestone matching the event type and not yet completed: increment CurrentCount by Count. If CurrentCount >= Threshold: mark completed, call ApplyReward, broadcast OnMilestoneCompleted. |
ApplyReward | void (FMilestoneTableRow&) | Switch on RewardType: • UnlockUnit → add type to recruitment pool (flag on URaccoonSubsystem) • UnlockTarget → unlock buildings on city map (flag on UCityMapSubsystem) • AddRaccoon → URaccoonSubsystem::AddRaccoon(type from payload) • AddResource → UResourceSubsystem::AddResource |
IsMilestoneComplete | bool (FName RowName) | For UI checkmarks and gating queries |
IsTargetUnlocked | bool (URaidTargetDataAsset*) | Checks target’s unlock milestone. If no milestone → always unlocked. If milestone → IsMilestoneComplete. Used by UCityMapSubsystem::GetUnlockedBuildings and ATNTBuilding for locked/unlocked visuals. |
GetAllMilestones | TArray<FMilestoneDisplayData> () | For quest log UI. Returns name, description, progress fraction, completed flag, reward description. |
Internal state (extends Block 1 stub — MilestoneProgress map declared there):
| Member | Type | Purpose |
|---|---|---|
MilestoneTable | UDataTable* | Reference to DT_Milestones. Loaded in Initialize, rows cached for HandleEvent iteration |
OnMilestoneCompleted | FOnMilestoneCompleted (DYNAMIC_MULTICAST_DELEGATE_OneParam) | BlueprintAssignable. Param: FName MilestoneRowName. Quest log and HUD bind to this |
Event Binding
UProgressionSubsystem::Initialize binds to:
| Source Delegate | Maps To |
|---|---|
URaidSubsystem::OnRaidCompleted | HandleEvent(RaidCompleted, 1) |
URaccoonSubsystem::OnRosterChanged | Check if raccoon was added → HandleEvent(RaccoonRecruited, 1) |
Need a way to distinguish roster additions from removals. Options:
- Add
OnRaccoonAdded/OnRaccoonRemoveddelegates alongsideOnRosterChanged - Or check roster count delta in the handler
Recommend: add DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRaccoonAdded, FGuid, RaccoonId) to URaccoonSubsystem. Fire from AddRaccoon only.
Replace Hardcoded Triggers
Block 7 hardcoded unlock triggers. Replace with milestone queries:
UCityMapSubsystem::GetUnlockedBuildings→ callsUProgressionSubsystem::IsTargetUnlockedper buildingATNTBuildinglocked/unlocked visual state → queriesIsTargetUnlockedon BeginPlay + listens toOnMilestoneCompleted- Distractor recruitment availability →
URaccoonSubsystem::GetAvailableRecruitTypeschecksIsMilestoneComplete("StreetCred")
Quest Log UI (UTNTQuestLogUI)
UMG widget toggled by hotkey (J):
- Active milestones: Each shows name, description, progress bar (e.g., “Complete 5 raids: 3/5”)
- Completed milestones: Checked off with reward description
- Binds to
OnMilestoneCompletedfor live updates - Plain text, no styling
Widget: Content/TrashNTreasure/UI/WBP_QuestLog.uasset.
Milestone Completion Notification
When OnMilestoneCompleted fires:
- HUD popup/toast: “Milestone Complete: [Name]! Reward: [RewardDescription]”
- Blueprint handles the visual notification (bind to delegate on HUD widget)
Milestone Chain Verification
End-to-end test:
- New game → 2 raccoons (Scout + Hauler)
- Complete 1 raid → “First Score” fires → Hauler joins → roster now 3
- Complete 4 more raids → “Growing Operation” fires → Rich Neighbor + Grocery Store unlock on city map
- Recruit from raids until 4 total recruited → “Street Cred” fires → Distractor available in pool
- All milestone progress tracks correctly, rewards apply, quest log reflects
Done When
- Milestones track progress and fire on correct triggers
- “First Score” (1 raid) → new Hauler auto-joins
- “Growing Operation” (5 raids) → Rich Neighbor + Grocery Store unlock on city map
- “Street Cred” (4 recruits) → Distractor type available in recruitment pool
- Quest log (J) shows active progress and completed milestones
- Hardcoded unlock triggers from Block 7 replaced with milestone queries
- New player can follow milestone chain from first raid to Distractor unlock
-
OnMilestoneCompletedfires and HUD shows notification toast