fix(selection): port SmartBox click lighting pulse
Port the retail high/low material-lighting cadence for successful world clicks, keep it instance-scoped in the modern renderer, and restore authored lighting after 0.8 seconds. Correct the selection oracle and pin timing plus per-frame buffer lifecycle with tests. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
146a963aeb
commit
ea4f52ec51
11 changed files with 338 additions and 16 deletions
|
|
@ -139,7 +139,64 @@ else:
|
|||
show the on-screen root and hide the off-screen root
|
||||
```
|
||||
|
||||
There is no selected-world-mesh tint or luminosity mutation in
|
||||
`CPhysicsPart::Draw`, `ACCWeenieObject::SetSelected`, or the world mesh draw
|
||||
path. The visible notification is the colorized four-corner DAT indicator. A
|
||||
mesh shader tint would therefore be a new effect, not a retail port.
|
||||
The indicator is persistent selection presentation. Retail also has a separate,
|
||||
short-lived click confirmation owned by SmartBox; it is not implemented in
|
||||
`CPhysicsPart::Draw` or `ACCWeenieObject::SetSelected`.
|
||||
|
||||
## SmartBox click lighting pulse
|
||||
|
||||
`UIElement_SmartBoxWrapper::RecvNotice_SmartBoxObjectFound @ 0x004E5AD0`
|
||||
|
||||
```text
|
||||
when FindObject succeeds for Select, Examine, Use, Drop, Drag, or TargetedUse:
|
||||
if another object is currently pulsing:
|
||||
RestoreLighting(previous object)
|
||||
SetLighting(found object, luminosity=0.99, diffuse=1.0) // HIGH
|
||||
flipCount = 1
|
||||
nextFlip = Timer::cur_time + 0.2 seconds
|
||||
|
||||
continue with the reason-specific select/examine/use/drop behavior
|
||||
```
|
||||
|
||||
`UIElement_SmartBoxWrapper::Global_Loop @ 0x004E5620`
|
||||
|
||||
```text
|
||||
if flipCount != 0 and Timer::cur_time >= nextFlip:
|
||||
flipCount += 1
|
||||
if flipCount < 5:
|
||||
lightingMode = ((flipCount & 1) != 0) + 1
|
||||
nextFlip = Timer::cur_time + 0.2 seconds
|
||||
else:
|
||||
flipCount = 0
|
||||
lightingMode = RESTORE
|
||||
ApplyLighting(pulsing object, lightingMode)
|
||||
```
|
||||
|
||||
`UIElement_SmartBoxWrapper::ApplyLighting @ 0x004E5320`
|
||||
|
||||
```text
|
||||
RESTORE: CPhysicsObj::RestoreLighting(object)
|
||||
LOW: CPhysicsObj::SetLighting(object, luminosity=0.0, diffuse=0.35)
|
||||
HIGH: CPhysicsObj::SetLighting(object, luminosity=0.99, diffuse=1.0)
|
||||
```
|
||||
|
||||
The complete cadence is therefore HIGH immediately, LOW at 0.2 seconds, HIGH
|
||||
at 0.4, LOW at 0.6, and authored material lighting restored at 0.8. A delayed
|
||||
frame advances only one step because retail schedules the next flip from the
|
||||
current `Timer::cur_time`; it does not drain missed intervals.
|
||||
|
||||
`CPhysicsObj::SetLighting @ 0x00511A80` forwards to every physics part through
|
||||
`CPartArray::SetLightingInternal @ 0x00518490`. `CPhysicsPart::SetLighting @
|
||||
0x0050E400` copies the material when needed, then calls
|
||||
`CMaterial::SetLuminositySimple` followed by `CMaterial::SetDiffuseSimple`.
|
||||
The modern renderer's equivalent is an instance-scoped material replacement:
|
||||
|
||||
```text
|
||||
lit = luminosity + diffuse * sceneLighting
|
||||
rgb = sampledTexture.rgb * clamp(lit, 0, 1)
|
||||
```
|
||||
|
||||
Normal/restored rendering uses `(luminosity=0, diffuse=1)` in the current object
|
||||
shader. The pulse is distinct from the persistent four-corner indicator and
|
||||
must restart on every successfully resolved SmartBox click, even when the click
|
||||
is consumed by targeted use instead of changing the selected object.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue