feat(chargen): Campaign CC slice CC5 — Summary page, Finish flow, RandomizeCharacter port
Fills TS-82's Summary placeholder with a faithful port of gmCGSummaryPage (name field with NameInputFilter + the retail commit-on-focus-lost/submit dispatch + the >32-char ID_CharGen_NameTooLong reject-and-revert path, the REAL three-row-template listbox confirmed against the installed EoR dat before writing any page code, and Summary's own independent gmCG3DView preview instance wired through a second ChargenPreviewController pair mirroring the Appearance page's exact composition shape). Ports CharGenState::RandomizeCharacter and its six sub-primitives into RuntimeCharacterCreationState — not approximated: the RandInt/RollDice semantics are independently confirmed from both the decompiled RNG bodies and the CharGenStateVtbl union struct in acclient.h. Three consumers: the chargen screen's open-roll (retiring AP-214's honest-blank deviation and reproducing the Appearance page's gender-flip-on-init quirk), the Summary page's Random button (behind the retail randomize-warning confirm), and the Appearance page's Random button (narrowing AP-212 to just Heritage/Profession/Town's still-approximated rolls and Skills' still-unported RandomizeSkills). Wires the Finish button (previously ghosted) with retail's NoName/ CreditWarning dialog pair, adds the F12 amendment's HeritageOrGenderUnset local refusal to TryBeginFinish (register AP-223) as a defensive backstop now that the screen-open roll normally makes it unreachable, and wires the four ID_Character_Err_* rejection dialogs for the 0xF643 response codes CC3 already parsed but nothing displayed. Register: TS-82 retired, AP-214 retired, AP-212 narrowed, AP-223/224/225 filed (heritage/gender Finish refusal, Summary's two-bucket skill-list narrowing, the 32-vs-33 name-length threshold reconciliation). Runtime 1722/0 (was 1713), App 5240/3 skips (was 5223/3), Headless 166/0 unchanged, full solution Release build green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
6114b2dda2
commit
34e3a534be
22 changed files with 2217 additions and 79 deletions
|
|
@ -540,7 +540,8 @@ internal sealed class FrameRootCompositionPhase
|
|||
new PrivateEntityViewportFrameGroup(
|
||||
live.PaperdollPresenter,
|
||||
live.CreatureAppraisalPresenter,
|
||||
live.ChargenPreviewController),
|
||||
live.ChargenPreviewController,
|
||||
live.SummaryPreviewController),
|
||||
retainedGameplayUi,
|
||||
// The ImGui developer-tools frontend was removed at Campaign V
|
||||
// slice V11; this optional hook is unbound until a follow-up
|
||||
|
|
|
|||
|
|
@ -1007,6 +1007,11 @@ internal sealed class RetailInteractionRetainedUiCompositionFactory
|
|||
DatStringResolver.ComputeHash(key));
|
||||
}
|
||||
},
|
||||
SetName: late.GameRuntime.CharacterCreationSetName,
|
||||
AcknowledgeRejection: late.GameRuntime.CharacterCreationAcknowledgeRejection,
|
||||
RandomizeCharacter: late.GameRuntime.CharacterCreationRandomizeCharacter,
|
||||
RandomizeAppearance: late.GameRuntime.CharacterCreationRandomizeAppearance,
|
||||
RandomizeClothing: late.GameRuntime.CharacterCreationRandomizeClothing,
|
||||
OpenOnStart: d.Options.OpenCharacterCreationOnStart)
|
||||
: null);
|
||||
RetailUiRuntime runtime = lease.Mount(
|
||||
|
|
|
|||
|
|
@ -241,6 +241,28 @@ internal sealed class DeferredGameRuntimeStateCommands
|
|||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.SetShade(generation, slot, value));
|
||||
|
||||
// ── Campaign CC slice CC5: Summary page + RandomizeCharacter commands ──
|
||||
|
||||
public RuntimeCommandResult CharacterCreationSetName(string name) =>
|
||||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.SetName(generation, name));
|
||||
|
||||
public RuntimeCommandResult CharacterCreationAcknowledgeRejection() =>
|
||||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.AcknowledgeRejection(generation));
|
||||
|
||||
public RuntimeCommandResult CharacterCreationRandomizeCharacter() =>
|
||||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.RandomizeCharacter(generation));
|
||||
|
||||
public RuntimeCommandResult CharacterCreationRandomizeAppearance() =>
|
||||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.RandomizeAppearance(generation));
|
||||
|
||||
public RuntimeCommandResult CharacterCreationRandomizeClothing() =>
|
||||
Invoke((commands, generation) =>
|
||||
commands.CharacterCreation.RandomizeClothing(generation));
|
||||
|
||||
// ── Campaign FA slice FA4: fellowship page commands ─────────────────
|
||||
// Same "capture view+commands under one generation" shape as every
|
||||
// method above — a displaced session (reconnect mid-click) can never
|
||||
|
|
|
|||
|
|
@ -132,6 +132,11 @@ internal sealed record LivePresentationResult(
|
|||
// a leased composition resource, mirroring PaperdollViewportRenderer).
|
||||
ChargenPreviewRenderer? ChargenPreviewRenderer,
|
||||
ChargenPreviewController? ChargenPreviewController,
|
||||
// Campaign CC slice CC5: the Summary page's own gmCG3DView instance —
|
||||
// a SEPARATE leased renderer/controller pair, same split reasoning as
|
||||
// the Appearance preview fields immediately above.
|
||||
ChargenPreviewRenderer? SummaryPreviewRenderer,
|
||||
ChargenPreviewController? SummaryPreviewController,
|
||||
WbFrustum EnvCellFrustum,
|
||||
EnvCellRenderer? EnvCellRenderer,
|
||||
LandblockPresentationPipeline LandblockPipeline,
|
||||
|
|
@ -1102,6 +1107,82 @@ internal sealed class LivePresentationCompositionPhase
|
|||
+ "time — the Appearance page's zoom/rotate controls and "
|
||||
+ "3D preview will not function this session.");
|
||||
}
|
||||
|
||||
// Campaign CC slice CC5: the Summary page's OWN gmCG3DView instance
|
||||
// (gmCGSummaryPage::InitializePage @0x0047bbf0, confirmed a SEPARATE
|
||||
// instance from the Appearance page's own during the CC6b-MOUNT
|
||||
// review) — same one-shot binding shape as the Appearance preview
|
||||
// immediately above (AP-221's own disposition applies here too: a
|
||||
// DAT/resource read not ready on this exact composition frame means
|
||||
// the Summary preview stays permanently unbound for the session,
|
||||
// same tracked follow-up as the Appearance preview). No zoom/rotate
|
||||
// control surface is wired — retail's Summary page has no such
|
||||
// buttons (only <c>StartAnimation</c>'s idle loop and a fixed 180°
|
||||
// heading), so this controller's ZoomIn/RotateClockwise etc. simply
|
||||
// never get called.
|
||||
CompositionAcquisitionScope.CompositionAcquisitionLease<
|
||||
ChargenPreviewRenderer>? summaryPreviewLease = null;
|
||||
ChargenPreviewController? summaryPreviewController = null;
|
||||
if (dispatcherLease.Resource is { } summaryDispatcher
|
||||
&& interaction.RetainedUi?.Runtime.SummaryPreviewViewportWidget is { } summaryViewport)
|
||||
{
|
||||
var summaryCamera = new ChargenPreviewCamera();
|
||||
summaryPreviewLease = scope.Acquire(
|
||||
"summary preview viewport",
|
||||
() => new ChargenPreviewRenderer(
|
||||
worldPassScope
|
||||
?? throw new InvalidOperationException(
|
||||
"The graphics backend must publish a world pass scope."),
|
||||
host.GpuDevice,
|
||||
host.GpuFrameLifetime,
|
||||
summaryDispatcher,
|
||||
foundation.SceneLighting!,
|
||||
foundation.TextureCache,
|
||||
foundation.MeshAdapter!,
|
||||
camera: summaryCamera),
|
||||
static value => value.Dispose());
|
||||
IUiViewportRenderer? previousSummaryRenderer = summaryViewport.Renderer;
|
||||
summaryViewport.Renderer = summaryPreviewLease.Resource;
|
||||
bindings.AdoptRelease(
|
||||
"summary preview viewport target",
|
||||
() =>
|
||||
{
|
||||
if (ReferenceEquals(summaryViewport.Renderer, summaryPreviewLease.Resource))
|
||||
summaryViewport.Renderer = previousSummaryRenderer;
|
||||
});
|
||||
|
||||
var summaryCatalog = new AcDream.Content.CharGen.ChargenAppearanceCatalog(content.Dats);
|
||||
summaryPreviewController = new ChargenPreviewController(
|
||||
summaryPreviewLease.Resource,
|
||||
summaryCamera,
|
||||
new RetailChargenPreviewFrameView(
|
||||
summaryViewport,
|
||||
new RetailSummaryPreviewPageVisibility(interaction.RetainedUi.Runtime)),
|
||||
content.Dats,
|
||||
content.AnimationLoader,
|
||||
summaryCatalog,
|
||||
summaryCatalog,
|
||||
d.DatLock);
|
||||
interaction.RetainedUi.Runtime.SummaryPreviewControl = summaryPreviewController;
|
||||
bindings.AdoptRelease(
|
||||
"summary preview control",
|
||||
() =>
|
||||
{
|
||||
if (ReferenceEquals(
|
||||
interaction.RetainedUi.Runtime.SummaryPreviewControl,
|
||||
summaryPreviewController))
|
||||
{
|
||||
interaction.RetainedUi.Runtime.SummaryPreviewControl = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (dispatcherLease.Resource is not null && interaction.RetainedUi is not null)
|
||||
{
|
||||
Console.WriteLine(
|
||||
"[UI] summary preview viewport unavailable at composition "
|
||||
+ "time — the Summary page's 3D preview will not function "
|
||||
+ "this session.");
|
||||
}
|
||||
Fault(LivePresentationCompositionPoint.PrivateCreatureViewportsCreated);
|
||||
|
||||
var envCellFrustum = new WbFrustum();
|
||||
|
|
@ -1410,6 +1491,8 @@ internal sealed class LivePresentationCompositionPhase
|
|||
creatureAppraisalPresenter,
|
||||
chargenPreviewLease?.Resource,
|
||||
chargenPreviewController,
|
||||
summaryPreviewLease?.Resource,
|
||||
summaryPreviewController,
|
||||
envCellFrustum,
|
||||
envCellLease.Resource,
|
||||
landblockPipeline,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue