fix(chat): Campaign CH user-gate round 1 — jump-in-air edge, portal cue cadence, wrap/prefix/color fixes
The user tested Campaign CH's CODE-COMPLETE build live and reported ten defects (docs/plans/2026-08-09-chat-parity-campaign.md, "User gate — round 1"). Items A-G are fixed here; the remaining three (extra chat windows on 1/2/3/4, resize working in only one corner, transparency/ artifacts) are out of scope for a fix and filed as slice CH6. A. Jump-in-air refusal never fired live: the jump block only ever evaluated input.Jump inside the grounded-charge or already-charging branches. PlayerMovementController now detects the press RISING EDGE while airborne and reports WeenieError.NotGrounded once per press, leaving the grounded charge/fire path untouched. B. ChatVM's invented "[System] " prefix is dropped — retail prints system text bare. [Popup] is unchanged (AP-175). C. SpewBoxController's color is now the user-pinned exact value (1, 1, 0.247, 1), the same bright yellow as an incoming Tell. Register row AP-178 updated: color CLOSES, size/position/font stay open per the user's live report that they still differ. D. Closes #329: PortalTunnelPresentation now emits the portal wait cue unconditionally on every rotation-segment boundary, matching gmSmartBoxUI::UseTime's decompiled else-arm exactly instead of gating on a 5-second hold local transits never reached. PortalWaitNotice Controller now renders it in the same pinned yellow as item C. Register row AP-150 retired. E. Closes #362: new ClientCommandResponses.cs parses and renders the four previously-unhandled inbound GameEvents (ChannelIndex, ChannelList, AvailableHouses, AllegianceInfoResponse), each ported line-for-line from the named-retail decomp's inbound handlers. Register row TS-70 retired. F. ChatWindowController.WrapText now splits on embedded '\n'/'\r\n' first, then word-wraps each segment independently — server text like /help's reply no longer collapses onto one line. G. The chat input field's right edge no longer holds a fixed absolute pixel position across a window resize; Bind now upgrades it to retail edge-mode 1 (UiLayoutPolicy) or the AnchorEdges.Right stretch fallback so it tracks the window's client width instead of overflowing past a narrower resize. Full Release suite: 12,247 passed / 4 skipped / 0 failed (baseline 12,221/4/0 + 26 new tests across items A, E, F, G). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d1c1368a5e
commit
47e40900f3
17 changed files with 1428 additions and 81 deletions
|
|
@ -940,6 +940,51 @@ public class PlayerMovementControllerTests
|
|||
Assert.Null(exception);
|
||||
}
|
||||
|
||||
// ── Campaign CH user-gate round 1 (item A): airborne jump refusal ──────
|
||||
|
||||
[Fact]
|
||||
public void JumpPress_RisingEdgeWhileAirborne_ReportsCantJumpInAir_HeldOnlyOnce_NoneAfterLanding()
|
||||
{
|
||||
var engine = MakeFlatEngine();
|
||||
var controller = new PlayerMovementController(engine);
|
||||
controller.SeedPlacementForTest(new Vector3(96f, 96f, 50f), 0x0001, new Vector3(96f, 96f, 50f));
|
||||
|
||||
// Launch into the air with an ordinary charged jump — the fix must
|
||||
// not touch this grounded charge/fire path at all.
|
||||
controller.Update(1.0f, new MovementInput(Jump: true)); // full charge
|
||||
controller.Update(0.016f, new MovementInput(Jump: false)); // release -> jump fires
|
||||
Assert.True(controller.IsAirborne);
|
||||
controller.Update(0.05f, new MovementInput()); // clear the ground before pressing again
|
||||
|
||||
var reported = new List<string>();
|
||||
controller.OnInterfaceText = (text, _) => reported.Add(text);
|
||||
|
||||
// Rising edge while airborne: exactly one "You can't jump while in
|
||||
// the air" report.
|
||||
controller.Update(0.016f, new MovementInput(Jump: true));
|
||||
var report = Assert.Single(reported);
|
||||
Assert.Equal(ClientTextRefusals.CantJumpInAir, report);
|
||||
|
||||
// Holding the key across multiple further updates raises no
|
||||
// additional reports.
|
||||
controller.Update(0.016f, new MovementInput(Jump: true));
|
||||
controller.Update(0.016f, new MovementInput(Jump: true));
|
||||
controller.Update(0.016f, new MovementInput(Jump: true));
|
||||
Assert.Single(reported);
|
||||
|
||||
// Release, then land.
|
||||
controller.Update(0.016f, new MovementInput(Jump: false));
|
||||
for (int i = 0; i < 60 && controller.IsAirborne; i++)
|
||||
controller.Update(0.05f, new MovementInput());
|
||||
Assert.False(controller.IsAirborne, "should have landed");
|
||||
|
||||
// Landing then pressing again while grounded raises none (the
|
||||
// grounded charge succeeds normally for an unburdened character).
|
||||
reported.Clear();
|
||||
controller.Update(0.016f, new MovementInput(Jump: true));
|
||||
Assert.Empty(reported);
|
||||
}
|
||||
|
||||
// ── Campaign P Slice P5 (2026-07-30): ConstraintManager leash arming (#167) ──
|
||||
//
|
||||
// docs/research/2026-07-30-constraint-leash-constants.md. The player's
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue