Block 4 — Raid Resolution (2 days)

Goal: Dispatched raids play out in three phases on the city map: group travel, looting with probabilistic encounter + backup window, and group return. Encounters can kill or capture raccoons.

Depends on: Block 3 (dispatch system, city map, raid targets, crew assignment).


Deliverables

New Enums

UENUM(BlueprintType)
enum class ERaidPhase : uint8
{
    Traveling,
    Looting,
    EncounterPending,
    Returning,
    Complete
};

New Structs

USTRUCT(BlueprintType)
struct FActiveRaid
{
    UPROPERTY() FGuid RaidId;
    UPROPERTY() TSoftObjectPtr<URaidTargetDataAsset> Target;
    UPROPERTY() TArray<FGuid> CrewRaccoonIds;
    UPROPERTY() TArray<FGuid> BackupRaccoonIds;       // encounter-only reinforcements
    UPROPERTY() ERaidPhase Phase;
    UPROPERTY() float TravelTime;                      // seconds, group travel to target
    UPROPERTY() float TravelElapsed;                   // seconds into travel
    UPROPERTY() float LootProgress;                    // 0.0–1.0
    UPROPERTY() float TotalWork;                       // fixed per target
    UPROPERTY() float CompletionSpeed;                 // from weighted formula
    UPROPERTY() bool bEncounterScheduled;              // rolled at dispatch
    UPROPERTY() float BackupWindowRemaining;           // countdown when EncounterPending
    UPROPERTY() float BackupTravelTime;                // backup group travel time
    UPROPERTY() float BackupTravelElapsed;             // backup group progress
    UPROPERTY() UEncounterDataAsset* PendingEncounter; // which encounter, if scheduled
    UPROPERTY() FLootPayload PendingLoot;
    UPROPERTY() TArray<TWeakObjectPtr<ATNTRaccoonAIPawn>> SpawnedPawns;     // transient
    UPROPERTY() TArray<TWeakObjectPtr<ATNTRaccoonAIPawn>> BackupPawns;      // transient
    UPROPERTY() bool bIsDaytimeRaid;                   // snapshot at dispatch for 2x encounter chance
};

URaidSubsystem — Full Resolution (C++)

FunctionSignaturePurpose
DispatchRaidFGuid (URaidTargetDataAsset*, TArray<FGuid>)(Update from Block 3) Calculate CrewAvgSpeed = sum(Speed) / CrewSize. TravelTime = NavMeshDistance(HideoutExit, Target) / (CrewAvgSpeed * SpeedScale). Generate loot. Roll encounter chance (see formula below). Spawn crew AI pawns as a group at HideoutExit. Set Phase = Traveling. Snapshot bIsDaytimeRaid from current clock.
TickRaidsvoid (float DeltaTime)Called from subsystem Tick. Phase state machine per active raid — see “Tick State Machine” below.
ResolveEncounterFEncounterResult (FActiveRaid&)Sum relevant stat from all on-site crew + arrived backup. Compare vs threshold. Apply tiered casualties. Broadcast OnEncounterResolved.
DispatchBackupvoid (FGuid RaidId, TArray<FGuid> BackupIds)Validate all backup raccoons are Idle. Set status to Raiding. Calculate backup group travel time (NavMeshDistance / BackupAvgSpeed * SpeedScale). Add to FActiveRaid::BackupRaccoonIds. Spawn backup AI pawns at HideoutExit.
GenerateLootFLootPayload (URaidTargetDataAsset*, TArray<FGuid>)C++ — weighted random rolls. Same as Block 3 spec. Hauler Strength scales loot volume.
CompleteRaidvoid (FGuid)Set original crew raccoons to Idle (or leave dead/captured ones removed). Despawn crew AI pawns. Despawn any remaining backup pawns. Deposit FLootPayload to Loot Sorting Station. Broadcast OnRaidCompleted.
GetActiveRaidsTArray<FActiveRaid> ()For HUD and city map display.

Internal state (extends Block 1 stub — ActiveRaids declared there; OnEncounterPending and OnRaidDispatched declared in Block 3):

MemberTypePurpose
OnRaidCompletedFOnRaidCompleted (DYNAMIC_MULTICAST_DELEGATE_TwoParams)BlueprintAssignable. Params: FGuid RaidId, FLootPayload Loot
OnEncounterResolvedFOnEncounterResolved (DYNAMIC_MULTICAST_DELEGATE_TwoParams)BlueprintAssignable. Params: FGuid RaidId, FEncounterResult Result
HideoutExitActorATNTHideoutExit*Cached spawn/despawn point for AI pawns in L_City. Resolved in Initialize()
BackupWindowDurationfloatTunable backup window length (120–180s). UPROPERTY(EditDefaultsOnly)
StealthScalefloatTunable divisor for encounter chance formula (default 200). UPROPERTY(EditDefaultsOnly)
SpeedScalefloatTunable multiplier for travel speed calculation. UPROPERTY(EditDefaultsOnly)

Encounter Chance Formula

Rolled once at dispatch time. Result stored in bEncounterScheduled.

EncounterChance = TargetBaseChance * (1 - CrewStealthSum / StealthScale)
if bIsDaytimeRaid: EncounterChance *= 2.0
if any crew raccoon is Scout: EncounterChance *= 0.5
EncounterChance = clamp(EncounterChance, 0, 0.95)

bEncounterScheduled = (FMath::FRand() < EncounterChance)

If scheduled, select encounter type from target’s weighted encounter pool (random by pool weights). Store in PendingEncounter.

StealthScale is a global tunable constant (e.g., 200). TargetBaseChance comes from the URaidTargetDataAsset.

Tick State Machine

Per active raid, each tick:

Traveling:

TravelElapsed += DeltaTime
if TravelElapsed >= TravelTime:
    Phase = Looting
    // crew pawns arrive at building, begin looting animation

Looting:

LootProgress += CompletionSpeed * DeltaTime / TotalWork
if LootProgress >= 0.5 AND bEncounterScheduled AND Phase == Looting:
    Phase = EncounterPending
    BackupWindowRemaining = BackupWindowDuration  // tunable, 120–180 seconds
    Broadcast OnEncounterPending(RaidId, PendingEncounter)
if LootProgress >= 1.0:
    Phase = Returning
    TravelElapsed = 0  // reset for return trip

EncounterPending:

BackupWindowRemaining -= DeltaTime
// Also tick backup travel if backup dispatched:
if BackupRaccoonIds.Num() > 0:
    BackupTravelElapsed += DeltaTime
if BackupWindowRemaining <= 0 OR player confirms resolve:
    // Determine which backup arrived:
    //   backup counts if BackupTravelElapsed >= BackupTravelTime
    ResolveEncounter(Raid)
    // Remove dead/captured raccoons from crew
    bEncounterScheduled = false  // consumed
    Phase = Looting  // resume from 50%
    // If entire crew wiped: Phase = Returning (abort, partial/no loot)

Returning:

TravelElapsed += DeltaTime
if TravelElapsed >= TravelTime:
    CompleteRaid(RaidId)
    Phase = Complete

Encounter Resolution — Stat Check

// Dual-check: use whichever stat sum is higher
int32 StatSumA = GetCrewStatSum(OnSiteIds, EncounterCheckStatA);
int32 StatSumB = GetCrewStatSum(OnSiteIds, EncounterCheckStatB);
int32 BestSum = FMath::Max(StatSumA, StatSumB);
 
if (BestSum >= Threshold) → Pass
else → Fail, apply casualties

OnSiteIds = original crew (alive) + backup that arrived before window closed.

Encounter DataAssets (authored)

AssetCheck ACheck BThreshold (Easy)Threshold (Medium)Threshold (Hard)
DA_AggressiveDogSpeedStrength152540
DA_AnimalControlStealthCunning122235

Casualty Tiers

float Deficit = (Threshold - BestSum) / (float)Threshold;
 
int32 Casualties;
if (Deficit <= 0.20) Casualties = 1;                           // close fail
else if (Deficit <= 0.50) Casualties = 2;                      // medium fail
else Casualties = FMath::CeilToInt(OnSiteIds.Num() * 0.5f);   // catastrophic
 
// Select victims: sort on-site raccoons by relevant stat ascending
// Kill/capture from weakest first
Encounter TypeFail Consequence
Aggressive DogRaccoons die. RemoveRaccoon(Id). Permanent.
Animal ControlRaccoons captured. RemoveRaccoon(Id). Post-MVP: recoverable from Animal Control HQ.

Backup raccoons are in the casualty pool — they can die/be captured too.

Raccoon AI Pawns (City Map)

ATNTRaccoonAIPawn extending APawn:

  • Spawned by URaidSubsystem::DispatchRaid at ATNTHideoutExit location in L_City
  • UFloatingPawnMovement with MaxSpeed set from CrewAvgSpeed * SpeedScale
  • All crew pawns move as a group — same speed, same path
  • Controlled by BP_RaccoonAIController (AAIController subclass)
  • Visual: capsule/sphere with team-colored material during blockout

Behavior Tree (BT_RaccoonRaid):

Simple sequence:

  1. MoveToTargetBuilding (group travel)
  2. PlayAnimation → looting idle at building
  3. WaitForSignalURaidSubsystem signals looting complete (may include encounter pause)
  4. MoveToHideoutExit (return home)

Backup Pawns: Separate group, same behavior tree but target is the building where the encounter is happening. After encounter resolves, backup pawns reroute to HideoutExit and despawn on arrival.

Blackboard (BB_RaccoonRaid):

KeyTypeSet By
TargetBuildingObject (AActor*)URaidSubsystem at spawn
HideoutExitObject (AActor*)URaidSubsystem at spawn
MoveSpeedFloatCrewAvgSpeed * SpeedScale
RaidPhaseEnumUpdated by URaidSubsystem

Encounter Visual Feedback

When OnEncounterPending fires:

  • HUD alert: “[Crew] encountered [threat] at [Target]! Backup window: 2:00”
  • Encounter icon appears over building on city map
  • Crew pawns freeze in defensive pose

When OnEncounterResolved fires:

  • Death → affected pawn fades out with skull icon
  • Capture → affected pawn dragged off-screen by invisible force, net icon
  • Pass → brief relief animation, green checkmark, looting resumes
  • Backup arrival → new pawns visibly running to join the group

Raid Completion Flow

  1. TickRaids detects LootProgress >= 1.0
  2. Phase → Returning, crew pawns navigate back to HideoutExit
  3. TravelElapsed >= TravelTimeCompleteRaid(RaidId)
  4. Surviving crew raccoons → Idle via URaccoonSubsystem::SetStatus
  5. AI pawns despawned from city map
  6. FLootPayload deposited to Loot Sorting Station storage (if cap allows)
  7. OnRaidCompleted broadcast with RaidId + LootPayload
  8. HUD notification: “Crew returned from [Target]!”

Done When

  • Dispatched raids play out on city map — crew pawns visibly travel as a group to target and back
  • Travel speed scales with crew average Speed stat
  • Looting phase progresses and completes
  • Encounter chance is rolled at dispatch based on Stealth, Scout presence, and daytime modifier
  • When encounter triggers at 50% progress, raid pauses and backup window opens
  • Player can walk to Raid Board, see encounter alert, and dispatch backup raccoons
  • Backup raccoons travel as their own group; only arrived backup counts for stat check
  • Encounter resolves with tiered casualties (1 / 2 / half crew)
  • Failed dog encounter kills raccoons (permanent removal)
  • Failed animal control encounter captures raccoons (permanent removal)
  • Backup raccoons can be casualties
  • Crew returns → loot deposited → raccoons update status
  • OnRaidCompleted, OnEncounterPending, OnEncounterResolved delegates fire correctly
  • AI pawns show visual feedback for encounter results

References

Raid Encounters · Encounters MOC · Core Loop · Game Clock · Raid Resolution