Quest graph editor and runtime system (replaces the FTUE tutorial flow) - #571
Open
Shombith03 wants to merge 70 commits into
Open
Quest graph editor and runtime system (replaces the FTUE tutorial flow)#571Shombith03 wants to merge 70 commits into
Shombith03 wants to merge 70 commits into
Conversation
…e breadcrumb Recreate the XP/Quest progression system per the Quest Track + Breadcrumb design. Quest completion is now the only progression currency and the progression spine is the single driver of the Call-to-Action breadcrumb. C1 — Remove XP entirely: - Delete ParticipationXpAwarder, XPTrackView, SO_XPTrackData, SO_XPTrackReward (+ assets) and the ParticipationXpAwarder component in Bootstrap.unity. - Strip GetXP/AddXP/OnXPChanged from PlayerDataService; drop participationXpPerGame from SO_ProgressionConfig. The cloud PlayerProfileData.xp field is left dormant. Retire the old quest stack: - Delete Quest, QuestSystem, UserJourneySystem, SO_QuestChain (+ assets) and remove the SO_QuestChain field from SO_TrainingGame. Generalize the unlock model: - Rename SO_GameModeQuestData -> SO_UnlockData and SO_GameModeQuestList -> SO_UnlockList (script GUIDs + field names preserved so authored assets keep their data). Add a FeatureKind enum (GameMode/Vessel/IntensityTier/Screen/Captain/Episode/UIElement), FeatureRef, UnlockKey, and the breadcrumb fields CallToActionTargetID / CompletionUserAction / DependencyTargetIDs + BuildCallToAction(). KEY WIRE — progression drives the breadcrumb (C2): - GameModeProgressionService funnels every change through RaiseProgressionChanged, which recomputes the active frontier and lights its authored CallToAction, retracting the previous one (single guidance channel). - CallToActionSystem gains RemoveCallToAction, guards double-activation, and keeps dismissed callbacks so a target can re-light. C3 — continuity law: - CallToActionTarget blooms (scale + fade in) on activate and withers on dismiss via DOTween instead of instant SetActive. Author breadcrumb data on the 6 unlock assets (the 4 game modes point at their PlayGame* card via ArcadeMenu; the Vessel Hangar Screen node points at HangarMenu). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
…breadcrumb design Review follow-up. - Fix IsVesselHangarUnlocked: test the persistent done signal (IsUnlockObjectiveDone — a completed quest stays at max intensity) instead of the transient CompletedQuests set, which ClaimQuestAndUnlockNext empties on claim. The old conjunction was unsatisfiable, so the hangar (and its new breadcrumb, and the hangar feature gate) never unlocked. - Document the intentional CompletionUserAction=None on game-mode frontier breadcrumbs: multi-play quests stay lit until the objective is met (progression-owned), not dismissed after a single play via fragile event ordering. - Add Docs/QUEST_TRACK_AND_BREADCRUMB.md (architecture, content chain, in-editor wiring checklist, v1 boundaries); update MENU_PROGRESSION_AND_IAP.md and Analytics/DATA_INVENTORY.md to drop the removed XP track and rename SO_GameModeQuestData/List -> SO_UnlockData/List. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Drop GameModeQuest_WildlifeBlitz from SO_UnlockList and delete the asset; the chain is now CrystalCapture -> HexRace -> Joust -> PartyGame(placeholder) -> VesselHangar. Update the doc chain tables to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Set defaultMaxIntensity 2 -> 3 (config asset + SO default). Intensities 1, 2 and 3 are now playable the moment a mode unlocks; completing the intensity-3 goal unlocks intensity 4 and finishes the quest. The intensity-2->3 branch in RecordIntensityPlay is now inert (never fires while the floor is 3). Docs updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Add Assets/_Graphics/UI/CTA_Glow_Outline_Cyan.png (the breadcrumb ActiveIndicator — 9-slice neon border, spriteBorder 88) and Card_Frame_Cyan.png (sci-fi frame for the game-mode card, spriteBorder 74). Both import as Sprite (Single) with 9-slice borders preset via their .meta, so they stretch to any element size. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
- Replace the cyan CTA highlight with CTA_Glow_Outline_Green.png (neon green, 9-slice rectangular outline glow, spriteBorder 66). - CallToActionTarget now runs a continuous glow pulse while active (alpha yoyo, or a subtle scale yoyo when the ActiveIndicator has no CanvasGroup), tunable + toggleable, on top of the existing bloom-in / wither-out. Resumes on menu re-entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Card_Frame_Cyan.png now fills its interior with an opaque dark-navy vertical gradient (was a transparent-center outline) and uses a much subtler glow. Same file/GUID/9-slice meta, so existing wiring is unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FpNEL7iHc7bCKFTFvV3Byc
Adds a ScriptableObject node-graph system for authoring the First-Time-User- Experience as a branching flowchart, an IMGUI editor to build it, a runtime runner that executes it against existing systems, cloud-synced completion persistence, and a generator for the canonical onboarding flow. Extends the existing Assets/FTUE scaffold (reuses TutorialUIView / FTUEIntroAnimator / FTUEEventManager) and replaces the flat, non-branching TutorialSequenceSet with a graph. - Graph model: FTUEGraphSO + polymorphic FTUENodeSO (+ FTUEEdge/FTUEPorts/FTUERuntimeContext) with 15 node types: PlayIntro/Outro, ShowInstruction, Dialogue, EnterFreestyle, ExitFreestyle, WaitForInput, HighlightCTA, LockModes, Navigate, WaitForGameLaunch, WaitForGamePlayed, Wait, SetPhase, End — each mapped to a real runtime system. - FTUEGraphRunner: first-run gated on GameData.OnClientReady + cloud completion, edge-based advancement, per-node SOAP subscription cleanup (no leaked delegates). - Editor: FTUE Graph window (node canvas, port wiring, per-node inspector, live validation), Create Default FTUE Graph generator (authors the described flow end-to-end), and a Setup Runner In Scene helper that auto-resolves references. - Cloud persistence: FTUECloudData + FTUEProgressRepository wired into UGSDataService (key FTUE_PROGRESS) with a PlayerPrefs mirror via FTUECompletionStore. - DialogueManager.OnDialogueFinished event so dialogue nodes advance without polling. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…h tool Renames the FTUE graph system to Quest Graph (GUID-preserving) and rebuilds it around the design plan: a QuestSO holds ordered phase graphs; the graph is the source of truth driving CTA breadcrumbs, GameModeProgressionService, dialogue, and per-node UGS persistence. - Phase model: QuestSO (ordered QuestPhaseGraphSO phases with designer notes); QuestPhaseEndNode advances phases, QuestEndNode completes the quest. - New nodes: WaitForIntensity (tier gate), WaitForModeUnlocked (claim gate), UnlockMode (direct progression write), WaitForUserAction (generic gate); WaitForGamePlayed gains mode + min-intensity filters. Node categories, tooltips, and live field summaries on every node. - Runner v2: runs a quest across phases with exact mid-phase resume from UGS, records every completed node (QuestProgressCloudData, key QUEST_GRAPH_PROGRESS), and owns guidance while running via GameModeProgressionService.BreadcrumbSuppressed. - Progression service: public UnlockMode(mode) + breadcrumb suppression window. - Enums/hooks: CallToActionTargetType ProfileMenu/EpisodeMenu/PlayGameMaelstrom; UserActionType ViewProfileMenu/ViewEpisodeMenu/UnlockVessel; ScreenSwitcher fires ViewProfileMenu on Profile navigation. - Quest Graph Editor (FrogletTools ▸ Quest Graph Editor): cached asset lists + validation (no per-frame AssetDatabase hits), cursor-anchored wheel zoom, middle/alt-drag pan, content-sized node cards, category colors + legend, hover tooltips, drag-to-connect with spawn-and-connect, quest/phase panel with reorder, default asset locations (no file dialogs), F-frame/Delete keys. - Generator: FrogletTools ▸ Quest Graph ▸ Create Main Quest builds the full 6-phase FTUE plan (onboarding/CC → HexRace → Joust → Maelstrom → vessel tour → episodes finale) with notes baked in. - Docs: QUEST_GRAPH_TOOL.md; shareable/editable progression map at Docs/QuestMap/QUEST_MAP.html (data embedded via Save-as-HTML). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
- Enable/disable switches at every level (test harness): QuestSO.questEnabled (runner never starts a disabled quest), QuestPhaseGraphSO.phaseEnabled (runner skips disabled phases), QuestNodeSO.nodeEnabled (runner passes straight through disabled nodes via their next edge). Toggles in the left panel rows, node card headers, right-panel inspectors, and node context menu, with dimmed/OFF visuals and an entry-node-disabled validation warning. - Quest inspector gains Rename Asset and Reset Local Progress (PlayerPrefs mirror) controls. - Removed the Standalone Graphs section and the standalone graph creation button — phase graphs now exist only as quest phases. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
Code contracts for the five designer-built UIs, wired into the graph: - QuestInstructionView — lightweight control-teaching overlay (plain text + NiceVibrations haptic pulse, CanvasGroup fade). ShowInstruction nodes now drive it (new fields: haptic preset, minDisplaySeconds, hideOnAdvance; next-press removed) with the legacy TutorialUIView as fallback; runner hides it at phase/quest boundaries. - QuestDialoguePanelView — IDialogueView with captain portrait, typewriter body, Next (complete-then-advance) and Skip (fast-forward set); slots into DialogueViewResolver's MainMenu channel for Dialogue nodes. - QuestRewardRevealView — IDialogueView for the Reward channel: profile-screen panel populated from the set's RewardData, Continue steps lines and closes. - QuestToastNotifier — achievement toasts through ToastNotificationAPI: mode unlocked, intensity tier, quest-track objective met, quest-graph phase and quest completion (templates + toggles serialized). - FTUEEventManager gains OnQuestPhaseCompleted / OnQuestCompleted, raised by the runner at phase/quest boundaries. - UserActionTrigger gains optional triggerOnEnable so panels (e.g. the episode panel inside profile) fire their UserActionType on open. - Runner/setup expose + auto-resolve the instruction view; default-content generator updated for the new ShowInstruction fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…nels, control icons
Redesigns the Phase 0 in-flight tutorial to the new control curriculum:
sticks-outward speed up, sticks-inward slow down, movement-stick look-around,
LT+RT drift, skim 10 prisms (live counter), and press-B exit — the player is
never forced out of freestyle except by their own B press.
- QuestInstructionView: keyed CanvasGroup panels (designer-built instruction
sets with icons, cross-toggled by ShowInstruction's new panelKey) + a
progress counter ("3 / 10") for counting gates.
- New gates: QuestWaitForDriftNode (IVesselStatus.IsDrifting sustained) and
QuestWaitForSkimNode (rides the shared skim-boost SOAP channel, filtered to
the local vessel and to boost INCREASES so per-frame decay raises don't
count; drives the live counter).
- Success haptics: WaitForInput/WaitForDrift/WaitForSkim pulse a configurable
HapticType when the player performs the correct action (per-skim pulse
separate, default off — the skimmer's own haptics effect covers it).
- QuestExitFreestyleNode gains forceExit (+retry/timeout): pairs with a
WaitForInput(Button3/B) gate so the exit fires exactly on B.
- Runner/context/setup expose the skim-boost event asset.
- Control icon sprite set (white, tintable, animatable parts) at
Assets/_Graphics/UI/ControlIcons: thumbstick base/cap, chevron arrow,
composed outward/inward pulls, look-around stick, LT/RT triggers, B button.
- Generator Phase 0 rewritten to the new sequence (panel keys authored);
design map (Docs/QuestMap/QUEST_MAP.html) updated with the flight school
and embedded as the file's data revision.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
- QuestPhase0UIWirer (FrogletTools ▸ Quest Graph ▸ Wire Phase 0 UI): wires the hand-built Menu_Main UI in place — InGameInstructionSet/Container children become keyed instruction panels (flight-school order, mapping logged), a starter skim ProgressText is created if missing, DialogueSetUI gets QuestDialoguePanelView with captain/body/next resolved by heuristics and is plugged into the dialogue resolver, QuestToastNotifier lands on the runner, then the standard runner setup re-resolves references. - DialogueViewResolver: optional per-channel override slots (any IDialogueView MonoBehaviour) so the new panels take over MainMenu/Reward channels without replacing the existing concrete views; validated in OnValidate. - QuestExitFreestyleNode hides the instruction overlay when the flight ends (all completion paths) so the exit prompt can't linger over the menu. - QuestInstructionView only auto-grabs a fallback TMP in plain-text mode — with keyed panels the first child TMP belongs to a panel. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
… dialogue system retired from the quest path Per design: the Main Quest no longer uses DialogueManager/DialogueSet assets. QuestDialogueNode now carries its own lines (speaker + optional portrait override + [TextArea] lines) and drives the DialogueSetUI panel directly. - QuestDialoguePanelView: new PlayLines(speaker, portrait, lines, onComplete) self-driving sequence (typewriter, Next steps, Skip fast-forwards, hides and calls back after the last line), CancelIfPlaying for clean teardown, default captain portrait preserved across per-beat overrides. IDialogueView impl kept for optional legacy use. - QuestRuntimeContext: DialoguePanel scene ref + prefab/parent fallback with lazy instantiation (GetOrCreateDialoguePanel); DialogueManager removed. - Runner/setup wire the panel (auto-resolved); Phase 0 UI wirer no longer touches the dialogue resolver. - Generator: every dialogue beat now ships with authored placeholder lines (maps tour, profile explainer, per-mode reward reveals, hangar tour, finale) — the MainQuest runs end-to-end with zero DialogueSet assets. - Docs + design map updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
The FTUE's first beat is now the EnterFreestyle node itself: as soon as the menu initializes (OnClientReady + start delay), the camera blends from the menu orbit to the player vessel — the same transition as entering freestyle manually — and the first instruction only appears after the blend completes. The intro-cinematic node is removed from the default graph's front (the PlayIntro node type remains available for authoring). Generator, docs, and the design map updated to match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…skim counter - QuestToastNotifier: logInsteadOfToast (default on) routes all achievement messages through CSDebug.Log with a [Quest][TOAST] prefix — untick once the toast UI exists in the scene. - Phase 0 UI wirer no longer auto-creates a ProgressText: the skim counter is opt-in (assign any TMP to the instruction view's Progress Text to enable the live readout; the skim gate works without it). - Runner setup stops warning about the legacy TutorialUIView / FTUEIntroAnimator fallbacks — they're optional now that instructions use QuestInstructionView and the default graph has no intro cinematic. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…ter appends to the active set's text Legacy FTUE tutorial system deleted — the Quest Graph replaced it entirely: - Scripts: TutorialFlowController, TutorialSequenceSet/Step/StepType/Payload/ Section/Phase, FTUEProgress, FTUEIntroAnimator, TutorialUIView, InGameTutorialFlowView, all adapters/handlers/interfaces. - Assets: legacy step/sequence/progress SOs and the Captain_VO_FTUE prefab. - Quest nodes PlayIntro/PlayOutro removed (drove the deleted animator). - Runner/context/setup drop the TutorialUI + IntroAnimator legacy slots; ShowInstruction no longer has a legacy fallback. - FTUEEventManager trimmed to what is actually raised: OnCTAClicked (GameCard), InitializeFTUE, and the quest phase/completion events. Skim counter: no separate ProgressText — the "n / target" count is appended to the ACTIVE instruction set's own TMP text (base text cached on activation and restored when the gate completes). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…, training HUD hide - QuestEdge gains per-edge delaySeconds; runner waits (realtime) before running the next node. Editable in the tool: a "Delay (s)" field under each connection in the side panel plus a live label on the canvas edge. - Editor gets "Reset Player Progress (Local + Cloud)" — clears the local PlayerPrefs mirror always, and in Play mode also removes the quest's cloud record (QuestProgressStore.ResetCloud) and resets GameModeProgressionService progression. - QuestWaitForDriftNode now requires drifting BOTH directions (LT-led and RT-led, trigger-dominance detection with hold time) before advancing; shows a 0/2 progress counter and pulses haptics per completed direction. - Flight training hides gameplay HUD: runner's hideDuringFlightTraining CanvasGroups are zeroed when EnterFreestyle completes; the Phase 0 wirer auto-assigns the "Game UI" group. - Instruction panels: the node's authored text now OVERWRITES the panel's scene TMP text (scene text is a placeholder only) — also fixes the doubled skim counter, since the counter appends to the node text base. - Default MainQuest generator authors sensible delays (1.5s menu->vessel camera entry, 0.8-1s between training beats) and the two-direction drift prompt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…k, arcade funnel, full reset - Flight training now hides the vessel HUD through its own controller (VesselHUDController.HideHUD — same channel MenuMiniGameHUD uses) instead of zeroing the Game UI group, which raced the freestyle fade AND hid the volume button. Extra authored hide-groups are enforced every LateUpdate while training is active so a late fade can't re-show them. - R_VesselActionHandler gains SetInputSuppressed/ClearSuppressedInputs (no timer, caller-owned). During flight school the quest gates A/X/B/flip at press and release — only the taught sticks and triggers do anything. - Exit is now the volume/pause button (it already calls ToggleTransition): the last instruction says to tap it and a passive ExitFreestyle node waits for the menu blend. Never forced; B is suppressed like the other buttons. - New QuestLockNavigationNode + runner nav wiring: after exit the footer nav locks to the Arcade button and a captain dialogue points at it; nav is unlocked after the first Crystal Capture run and always on quest teardown. - New QuestArcadeConstraints (static, survives Menu->game->Menu reloads) + QuestSetArcadeConstraintsNode: locks every game card except the tutorial mode, disables every intensity except the forced one, defaults player count to max and domain count to 3. Consumed by ArcadeExploreView and ArcadeGameConfigureModal. P0 authors intensity-2 funnel, then intensity-3, then clears it. - WaitForGamePlayed now consults GameModeProgressionService play counts on resume — the OnMiniGameEnd raise happens in the game scene while the runner lives in Menu_Main, so a fresh menu load advances the gate from the recorded play instead of hanging. - Reset button is now a FULL gameplay wipe (QuestProgressStore. ResetAllGameplayProgress): quest local+cloud, mode/intensity progression, all vessel unlocks (hangar cloud record flushed), and arcade constraints. The Froglet Toolbox reads this state live and can still re-unlock manually. - Phase 0 wirer: removes the legacy 'Game UI' hide entry and auto-wires the nav buttons from ScreenSwitcher's OnClick*Nav persistent handlers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…l UX, constraint refresh Backend (local-only testing mode): - New ProgressionBackendGate (CloudEnabled=false, TEMP): with the gate closed, quest progress lives only in the PlayerPrefs mirror, game-mode progression neither loads from nor saves to GAME_MODE_PROGRESSION (fresh every session), and vessel unlocks are not persisted NOR resurrected from the stale hangar cloud record (SyncHangarToVessels gated symmetrically with the write paths). Reset button works instantly, edit or play mode, and the quest inspector shows a LOCAL-ONLY banner. Dialogue (the FTUE hang after flight school): - QuestDialoguePanelView now lazy-initializes and activates its own GameObject before playing — the hand-built DialogueSetUI is saved inactive, so Awake had never run: PlayLines threw on the null CanvasGroup / inactive-object StartCoroutine and the quest silently hung, which is why nothing after the dialogue (constraints, card locks, intensity locks, max players) ever applied. If a parent is still inactive it now fails OPEN (logs + completes) so the quest can never stall on a dialogue beat. - QuestRunnerSetup clears the Dialogue Panel Prefab slot when it holds the scene panel (the hand-wired duplicate reference). Arcade constraints: - QuestArcadeConstraints.OnChanged event; ArcadeExploreView repopulates on it (and retries its progression subscription in Start), so card locks apply even if the constraints node fires while the arcade is open. Editor tool: - Left/right sidebars are resizable (drag the inner edge) and hideable (toolbar toggles), widths/visibility persisted in EditorPrefs; canvas shrinks panels proportionally on small windows and drag clamps guard against inversion (review findings). - Designer-notes fields use a real scroll view with a draggable scrollbar (raw IMGUI TextAreas only caret-scroll); scrollbar drags no longer trip the change check and dirty the asset. Node [TextArea] fields grew to 8 lines. - "Legend" is now a persisted "Node Colors" show/hide toggle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…st-game 1/2/2, place progression service - Editor checkpoint view: the canvas now overlays the player's LOCAL progress — ✓ on every completed node, an amber "▶ NEXT" banner on the node the quest resumes at, a ▶ marker on the current phase row, and a PLAYER PROGRESS readout in the quest inspector. Polls the local mirror and repaints live during Play mode, so you can always see the last checkpoint you completed while testing. - QuestProgressStore records every completed node id locally (DoneNodes CSV) alongside the cursor; ResetLocal clears it and also clears the arcade constraints so a cursor wipe can't strand a locked arcade. - QuestArcadeConstraints now PERSIST in PlayerPrefs with the quest cursor: the resume point lands past the SetArcadeConstraints node, so statics alone meant any play-session restart silently unlocked the whole arcade (the "gamemodes are unlocked again" inconsistency). - First-game funnel is now authored as intensity 1, player count 2, domain count 2 (ForcedPlayerCount replaces force-max-players; the played gate accepts intensity >= 1). Second CC run stays intensity 3 with 2/2. - Phase 0 wirer creates + wires GameModeProgressionService in Menu_Main if missing — the only prefab carrying it sits unplaced in MIgration_Prefabs (DELETE LATER), so Instance was NULL in every run: no progression card locks, no play-count tracking, and played-game gates could never resume after the Menu->game->Menu round-trip. - QuestGraphRunner auto-heals the dialogue prefab slot (OnValidate + at context build): a scene object wired into the prefab slot is cleared — it must be a prefab asset, the scene panel drives dialogue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…silent stuck-at-end Adversarial trace of the solo game-over path found the whole pipeline runs synchronously inside ONE latched SOAP raise with zero exception isolation: TurnMonitorController latches _isRunning=false, raises OnMiniGameTurnEnd, and that single raise nests winner calc → score sync → reveal → scoreboard. Any subscriber exception anywhere kills everything downstream permanently — no winner, no scoreboard, no menu button: exactly "game over then stuck". - TurnMonitorController: catch + LogException around the raise with a loud pointer at the culprit subscriber (the latch means it never retries). - EndGameSequencer.RunReveal: flourish wrapped fail-open (and AudioSystem null-guarded) so InvokeShowGameEndScreen is ALWAYS reached; the reveal hold is now unscaled so a zero timescale can't freeze it forever. - Scoreboard.ShowScoreboard: population wrapped fail-open so the panel (with its Main Menu / Play Again buttons) appears even if a stats step throws — the player always has a way home. - SceneLoader: ClearPlayerVesselReferences wrapped fail-open (the fade is already black at that point), and the ignored Netcode LoadScene status now falls back to a local load when the scene event is refused. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…ttern (Joust, Maelstrom)
Mirrors the hand-authored HexRace phase in the generator's unlock-phase
template so every unlock phase (HexRace, Joust, Maelstrom) gets it:
profile CTA + explainer, then a WaitForUserAction(ViewProfileMenu) hold so
the claim-hint dialogue ("Tap the <previous mode> card on your quest track
to collect your reward!") only plays once the player is actually ON the
profile, then claim → reward → play CTA → played. Dialogue lines use
player-facing mode names (Crystal Capture / Hex Race / Joust / Maelstrom)
instead of enum names.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…ton shows unsaved state Flipping a quest/phase/node enable toggle only marked the asset dirty in memory — the .asset file (what git sees) changed only on an explicit save, so a disabled phase pushed with no diff. The five toggle sites (left-panel quest + phase, node card checkbox, right-panel node toggle, node context menu) now call AssetDatabase.SaveAssets() on the spot: the tool's harness state always lands in version control the moment it's flipped. Other edits (text, node positions, wiring) still batch behind the Save button, which now reads "Save*" with a tooltip while in-memory edits are pending. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
… Maelstrom phase ASSETS
Hand-edited MainQuest_Phase2/Phase3 directly (the live graphs the runner
uses — no regeneration): after the Profile Explainer, a new
WaitForUserAction(ViewProfileMenu) node holds until the player actually
opens the profile, then a new claim-hint dialogue points at the previous
mode's card ("Tap the HEX RACE / JOUST card on your quest track to collect
your reward!") before the claim gate — mirroring the hand-authored
HexRace phase. Fresh sub-asset ids, explainer edge retargeted, nodes
registered on each graph; edge/reference integrity verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
… state panel for testing The stale phase-0 funnel (Allowed Mode=CC, Forced Intensity=1) was leaking into phase 1: the newly claimed mode's card sat LOCKED under a glowing CTA, its button was unpressable, and the configure modal blocked intensities 2-4 even after force-advance had genuinely unlocked tier 4 in progression. Three-layer fix: - Phase scope: QuestPhaseEndNode now CLEARS the arcade funnel at every phase boundary — the funnel is a within-phase tool; a phase that wants one re-applies it. No authored graph can strand a stale funnel anymore. - Reward exemption: IsModeBlocked never blocks a mode the progression chain has explicitly unlocked — the funnel focuses onboarding, it can't lock the quest's own reward. - Correct scope: forced intensity / player count / domain count apply only to the tutorial (allowed) mode itself, never to other games' modals (IsIntensityBlocked now takes the mode; all modal call sites updated). Testing affordance: the quest inspector gains a play-mode LIVE STATE box showing the current funnel constraints and every unlocked mode with its max tier, plus a "Clear Arcade Funnel Now" escape hatch — so "why is this locked?" is answered at a glance instead of by replaying. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…r gate + toast NRE - New QuestSetButtonInteractableNode: flips a runner-registered scene Button's interactable state by key. Phase 5 now ENTERS through 'Enable Episodes Button' (key 'episodes') so the authored non-interactable Episodes button becomes clickable right before its CTA — the ViewEpisodeMenu gate is satisfiable. - QuestGraphRunner gains a Quest Buttons list (key + Button); context exposes SetQuestButtonInteractable. Phase 0 wirer auto-registers the first Button whose name contains 'episode' under key 'episodes'. - MainQuest_Phase5.asset patched in place (new entry node -> CTA: Episodes); generator emits the same chain on future regens. - GameModeProgressionService.IsUnlockObjectiveDone: full-intensity modes (Maelstrom/Tournament) have no intensity ladder, so the raw persisted-intensity check could never pass and the Vessel Hangar gate was permanently locked. They now count as done once the chain unlocks them. - ToastNotificationItem.Show: lazy-resolve CanvasGroup/RectTransform — Show can arrive before Awake on an inactive item (NRE on vessel unlock tap). - HangarVesselDetailView: hangar-locked feedback via CSDebug.Log for now. - Quest editor inspector: backend hint removed; Force-Advance / Reset / Clear Funnel buttons are centered and fitted instead of stretched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…inale dialogue Match the authored MainQuest_Phase5 order (dialogue names the Episodes screen, THEN the button becomes interactable, then its CTA) so a regenerated quest keeps the CTA gate satisfiable the moment it lights up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
QUEST_GRAPH_EDITOR_TOOL.md — hands-on guide for the FrogletTools Quest Graph Editor: window tour + canvas controls, graph editing (edges, delays, entry node, enable toggles, saving), full node reference, the play-mode testing workflow (checkpoint view, Force-Advance, LIVE STATE, reset), persistence notes, common recipes, and troubleshooting. Cross-linked from the architecture reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…editor-tool-69acq5 # Conflicts: # Assets/_Prefabs/UI Elements/Main Menu Screens/QuestItemPrefab.prefab # Assets/_SO_Assets/GameModeQuest/ProgressionConfig.asset # Assets/_Scenes/Menu_Main.unity # Assets/_Scripts/Controller/Arcade/TurnMonitorController.cs # Assets/_Scripts/ScriptableObjects/SO_GameModeQuestData.cs # Assets/_Scripts/ScriptableObjects/SO_ProgressionConfig.cs # Assets/_Scripts/System/Progression/GameModeProgressionService.cs # Assets/_Scripts/UI/Scoreboard.cs # Assets/_Scripts/Utility/DataContainers/EndGameSequencer.cs
…editor-tool-69acq5 # Conflicts: # Assets/_Scenes/Bootstrap.unity
…editor-tool-69acq5 # Conflicts: # Assets/_Scenes/Bootstrap.unity
… targets, gate readout - ExtractStatForIntensityGoal / ExtractStatForQuest: CrystalsCollected goals now read the dedicated RoundStats.CrystalsCollected counter instead of Score (mode-defined: golf finish time in races, points elsewhere) — crystal goals silently never counted. - GameModeQuest_CrystalCapture: intensity 3/4 stat targets 30/25 -> 10. The match ends when a domain totals 20 crystals, so a personal 25 was structurally impossible — the SCURRY tier-4 gate could never advance no matter how well the player played. - RecordIntensityPlay logs the shortfall when a deciding-intensity game misses its goal (stat seen vs needed, or plays so far), so "played I3, nothing advanced" is diagnosable from the console. - Quest Graph tool: when the resume node is a tier gate, PLAYER PROGRESS now spells out the unlock requirement — stat threshold or play count, the mode's current tier, plays recorded, and the race caveat (finish time counts only on the winning domain). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…2ncto' into claude/ftue-editor-tool-69acq5
…est cards open the arcade
- All three chain modes now unlock tier 4 (and complete their quest) by WINNING an
intensity-3 game: Scurry/Crystal Capture, Hex Race, and Joust all switch to the
WinMatch stat with target 1 ("Rank first ..." goal text on each quest asset).
- WinMatch extraction rewired to the authoritative winner state (WinnerDomain vs the
local player's domain, with the per-domain stats fallback) — the old check read
RoundStatsList[0], which is roster order, not rank, so wins were misdetected.
- Quest Graph tool: gate readout words the WinMatch goal plainly ("WIN the match").
- Quest track (profile): tapping a card now acts by state — an unlocked or claimed
mode jumps straight to the arcade (ScreenSwitcher.OnClickArcadeNav, which also
satisfies arcade CTA gates), a ready-to-claim card claims with the whole card as
the hit target, locked cards ignore the tap. QuestItemCard grows a BindCardAction
root-Button binding; the child claim button still consumes its own clicks first.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QkxbbeGixf58FkVYRk4Moz
…editor-tool-69acq5 # Conflicts: # Assets/_Scripts/System/VesselUnlock/VesselUnlockSystem.cs # Assets/_Scripts/UI/Views/PlayerDataService.cs # Assets/_Scripts/UI/Views/XPTrackView.cs
The Quest Graph Editor laid every phase out in columns of 5 (a snaking cursor), which said nothing about the track. Graphs now read left→right along a ROW, with a new row wherever the beat moves the player between the app shell (menus, arcade, profile) and gameplay (freestyle flight, a launched match) — so each row is one place the player is standing and each break is a real context switch. - QuestNodeSO: new QuestVenue (Inherit/AppShell/Gameplay) + Venue / VenueAfter virtuals. Only the transition nodes override them — EnterFreestyle, ExitFreestyle, WaitForGameLaunch, and the away trips WaitForGamePlayed / WaitForIntensity (gameplay while they run, app shell after) — everything else inherits, so rows never break on a beat that didn't move the player. - QuestGraphLayout (editor): DFS flow order from the entry node, one row per venue; unreachable nodes appended rather than left stacked at the origin. Geometry constants live here. - Editor window: "Layout Rows" toolbar button (undoable, frames after). - FrogletTools ▸ Quest Graph ▸ Layout All Phases (Rows) for the whole quest. - QuestDefaultContentBuilder: drops the column cursor and runs the shared layout, so generated graphs open already arranged. - All six MainQuest phase assets re-laid out (positions only). - Docs: QUEST_GRAPH_TOOL.md gains a "Canvas layout — venue rows" section; QUEST_GRAPH_EDITOR_TOOL.md gains the toolbar/menu entries and a designer walkthrough of the row paradigm. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G9U9w56EkngSuv4ix1vzmX
Long rows never wrap (Phase 0's flight-school row can't fit a framed canvas), and CLAUDE.md's FTUE section still predates the Quest Graph system entirely. Both logged in QUEST_GRAPH_TOOL.md so they have a doc home rather than living in a PR comment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G9U9w56EkngSuv4ix1vzmX
…rows-or6y6j feat(ftue): arrange quest graphs in venue rows instead of columns
…editor-tool-69acq5 # Conflicts: # Assets/FTUE/DataContainer/FTUEGraph_Default.asset.meta # Assets/FTUE/DataContainer/Phases/MainQuest_Phase0.asset.meta # Assets/FTUE/DataContainer/Phases/MainQuest_Phase1.asset.meta # Assets/FTUE/DataContainer/Phases/MainQuest_Phase2.asset.meta # Assets/Resources/PrismOcclusionConfig.asset.meta # Assets/_SO_Assets/Cell Configs/Blob Cell/Blob Cell Spawn Profile.asset # Assets/_SO_Assets/Cell Configs/Blob Cell/Blob Fauna Config Data.asset # Assets/_SO_Assets/Cell Configs/Geode Cell/Geode Cell Config.asset.meta # Assets/_SO_Assets/Cell Configs/Orrery Cell/Orrery Cell Config.asset.meta # Assets/_SO_Assets/Cell Configs/Scurry Cell/Scurry Cell Config.asset.meta # Assets/_SO_Assets/Songs/Charles 3.asset # Assets/_SO_Assets/Songs/Charles 4.asset # Assets/_SO_Assets/VesselActions/Rhino/RhinoSwordSwingKinematicsConfig.asset # Assets/_SO_Assets/XP/XPTrackData.asset.meta # Assets/_SO_Assets/XP/XPTrackReward_1.asset.meta # Assets/_SO_Assets/XP/XPTrackReward_2.asset.meta # Assets/_SO_Assets/XP/XPTrackReward_3.asset.meta # Assets/_Scenes/Menu_Main.unity # Assets/_Scripts/ScriptableObjects/SO_ProgressionConfig.cs # Assets/_Scripts/UI/Scoreboard.cs # Assets/_Scripts/UI/Views/PlayerDataService.cs # Docs/Analytics/DATA_INVENTORY.md # Docs/MENU_PROGRESSION_AND_IAP.md
…editor-tool-69acq5 # Conflicts: # Assets/_Scenes/Menu_Main.unity # Assets/_Scripts/Controller/Arcade/TurnMonitorController.cs
…pstream Merges origin/bleeding-edge (df80aab, PRs #762-#811) into the Quest Graph branch, which last synced at #761 on Aug 20. Upstream and this branch overlap on only three files; every other conflict (77 of 81) was criss-cross collateral from this branch's repeated upstream merges, on paths this branch never modified. Those are resolved to upstream exactly -- verified file-by-file that each is byte-identical between the old merge base and this branch's HEAD, so no branch change is discarded. Resolutions: - 73 paths taken from upstream verbatim (ecology level-retirement assets, prism-clock shader/HLSL, docs, CLAUDE.md, skills, CI workflow). - 4 paths removed: present in neither side, left behind by the recursive merge's virtual base (tests upstream moved to Tests/Editor/). - 4 .cs.meta kept at this branch's GUIDs. Git's rename detection paired the branch's new Quest metas with unrelated new upstream metas -- default MonoImporter boilerplate differing only in GUID. Both files now exist with their own GUIDs; all nine involved GUIDs verified distinct. The two genuine content overlaps auto-merged correctly and were checked by hand rather than assumed: - Blob Fauna Config Data: keeps this branch's PopulationSize 9 / MaxLivePopulation 15 AND upstream's retirement of FeedsPerLevel, InitialLevel, BodyScalePerLevel and LevelGrowSeconds (#810, "retire lifeform levels"). No retired field survives. - ProgressionConfig: keeps this branch's removal of mode 36 from alwaysUnlockedModes and defaultMaxIntensity 3, plus upstream's mode 44. R_VesselActionHandler.cs carried both sides: this branch's SetInputSuppressed gate and upstream's InputDeviceType.MouseKeyboard override row. The Quest/FTUE work is not superseded -- upstream touched no FTUE or Quest file. All 268 PR files, 22 quest nodes and 5 editor tools are intact. Tools/Build/check_conditional_compilation.py: OK (1804 files). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEapXRwbzTHRHeFukGugdt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the flat
TutorialSequenceSetFTUE flow with a quest system: a quest is an ordered list of phase graphs, and each phase is a node graph of ScriptableObject nodes connected by named ports. Adds a three-panel graph editor, 22 node types across 7 categories, cloud-persisted progress, and retires both the tutorial-era code and the previous quest/user-journey systems.Scope: 268 files — 134 added, 77 deleted, 38 modified, 19 renamed (+15,798 / −2,585). 174 are under
Assets/FTUE/.Editor tooling —
Assets/FTUE/Editor/QuestGraphEditorWindowQuestGraphLayoutQuestNodeSO.Venue, which is whatQuestVenueexists forQuestDefaultContentBuilderQuestRunnerSetupQuestGraphRunnerfrom the open scene and project assetsQuestPhase0UIWirerMenu_Main:InGameInstructionSet→QuestInstructionViewas keyed panels in flight-school order;DialogueSetUI→QuestDialoguePanelView, plugged intoDialogueViewResolver's MainMenu override slotAll five are
#if !LINUX_BUILD; runtime code is platform-agnostic.Core graph —
Assets/FTUE/Scripts/Graph/QuestSO— the quest:questId(stable persistence/analytics key),questEnabledmaster switch,designerNotes, and an orderedList<QuestPhaseGraphSO> phases. Index 0 runs first; a Phase End node advances.QuestPhaseGraphSO— one phase:graphId,phaseName,phaseEnabled,entryNode, andnodesstored as sub-assets, plus editor-only canvas scroll/zoom.QuestNodeSO— polymorphic base; carriesQuestNodeCategoryandQuestVenue, typed fields, anExecute()coroutine, andValidate().QuestEdge— directed connection from a named output port to a target node by stable ID, not index.QuestPorts— canonical port names. There are exactly two:nextandonTimeout.QuestRuntimeContext(+QuestButtonEntry) — live scene systems and SOAP assets handed to every node.Node types (22)
WaitForInput,WaitForSkim,WaitForDrift,WaitForIntensity,WaitForGameLaunch,WaitForGamePlayed,WaitForUserAction,WaitForModeUnlocked,ExitFreestyleNavigate,LockModes,LockNavigation,EnterFreestyle,SetArcadeConstraints,SetButtonInteractableShowInstruction,DialoguePhaseEnd,EndWaitHighlightCTAUnlockMode(All are
Quest…Node; the prefix is dropped above for width.)Runtime —
Assets/FTUE/Scripts/Graph/Runtime/QuestGraphRunner— waits for the menu autopilot vessel viaGameData.OnClientReady(so force-enter-freestyle and input steps have a live vessel), gates onQuestProgressStore.IsCompleted, resumes at the saved phase + node (every completed node is persisted to UGS), then executes from the entry node and follows the edge for the port each node advances on. HonoursquestEnabled/phaseEnabledmaster switches and carriesdebugForceRun/debugPhaseOverridetest hooks. Alongside it:QuestProgressStore,QuestArcadeConstraints,QuestPlayRecorder.UI —
QuestInstructionView(+InstructionPanel),QuestDialoguePanelView,QuestRewardRevealView,QuestToastNotifier.Cloud persistence
QuestProgressCloudData+QuestProgressRepository, keyed onUGSKeys.QuestGraph="QUEST_GRAPH_PROGRESS", exposed asUGSDataService.QuestGraph(reader) andQuestGraphRepo.Cloud is the source of truth, synced across devices, with a
PlayerPrefsmirror so first-run gating works offline; node completions are debounce-saved to UGS.ProgressionBackendGate.CloudEnabledturns the cloud half off — the store then runs PlayerPrefs-only and every cloud write is a no-op, which is the local-only testing path.Authored content
MainQuest.assetplusMainQuest_Phase0…MainQuest_Phase5.Progression & unlocks
New
SO_UnlockData,SO_UnlockList, andProgressionBackendGate(the switch that decides whether progression talks to the backend at all); modifiedGameModeProgressionService,SO_ProgressionConfig,VesselUnlockSystem,CallToActionSystem/CallToActionTarget,UserActionTrigger.ProgressionConfig.assetdrops mode 36 fromalwaysUnlockedModesand raisesdefaultMaxIntensityto 3.What this retires
25 tutorial-era files (
TutorialSequenceSet,TutorialStep/Section/Phase/Payload/StepType,TutorialFlowController,FTUEIntroAnimator+ adapters, the four step handlers, sevenITutorial*/IFlowController/IAnimator/IOutroHandlerinterfaces,TutorialUIView,InGameTutorialFlowView) and the previous quest stack:SO_GameModeQuestData,SO_GameModeQuestList,SO_QuestChain,Quest.cs,QuestSystem.cs,UserJourneySystem.cs.Documentation
Adds
Assets/FTUE/QUEST_GRAPH_TOOL.mdandQUEST_GRAPH_EDITOR_TOOL.md,Docs/QUEST_TRACK_AND_BREADCRUMB.md,Docs/QuestMap/QUEST_MAP.html; updatesDocs/Analytics/DATA_INVENTORY.mdandDocs/MENU_PROGRESSION_AND_IAP.md.Also touched
R_VesselActionHandlergainsSetInputSuppressed/ClearSuppressedInputs— an untimed on/off gate (distinct from the timedMuteInput) so the flight school can disable action buttons while only sticks and triggers are being taught. PlusScreenSwitcher,GameCanvas,Scoreboard,ArcadeGameConfigureModal,QuestTrackView,QuestItemCard,ArcadeExploreView,HangarVesselDetailView,DialogueManager,DialogueViewResolver,SceneLoader,EndGameSequencer,TurnMonitorController,Menu_Main.unity, and additive enum members inCallToActionTargetType/UserActionType.Verification status
unityjob is skipped; onlyresolveandconditional-compilationrun (both pass). Do not read a green check as a successful build.MainQuestphases 0–5. The runner gates on stored progress, so a profile that has already completed the quest silently skips everything and the run looks like a pass — use a fresh profile, or tickdebugForceRunonQuestGraphRunner(anddebugPhaseOverrideto jump to one phase).QUEST_GRAPH_PROGRESS— write, sign out, sign back in, confirm resume lands on the right phase. Offline first-run relies on thePlayerPrefsmirror; if mirror and cloud disagree the symptom is a quest that restarts or skips rather than an error. NoteIsCompletedshort-circuits on the local mirror before consulting cloud, so a stale local flag wins.QuestSystem,UserJourneySystem,SO_QuestChain) against a built player, not just the editor. These were referenced from prefabs andMenu_Main; a missed reference surfaces as a null script on a scene object, which the editor tolerates more quietly than a player does.SetInputSuppressedrelease: suppression has no timer and the caller owns the release, so a phase that exits early while a button is suppressed leaves that ability dead for the session.Base is synced to
bleeding-edgeas ofdf80aab1(PRs #762–#811).🤖 Generated with Claude Code
https://claude.ai/code/session_01MEapXRwbzTHRHeFukGugdt