Port retail's radius-aware placement ring so a relogging player is seated beside creatures occupying the saved location, and register the local body in the shared resolved-shadow pipeline. Route new forward movement and jump through AbortAutomaticAttack so repeat combat cancels immediately on movement. Co-Authored-By: Codex <codex@openai.com>
119 lines
3.9 KiB
Markdown
119 lines
3.9 KiB
Markdown
# Login placement and repeat-attack cancellation — retail pseudocode
|
|
|
|
## Sources
|
|
|
|
- `CTransition::find_placement_pos` @ `0x0050BA50`
|
|
- `CTransition::find_placement_position` @ `0x0050C170`
|
|
- `CObjCell::find_obj_collisions` @ `0x0052B750`
|
|
- `CPhysicsObj::add_shadows_to_cells` @ `0x00514AE0`
|
|
- `CPhysicsObj::enter_world` @ `0x00516170`
|
|
- `ClientCombatSystem::AbortAutomaticAttack` @ `0x0056AE90`
|
|
- `ClientCombatSystem::CommenceJump` @ `0x0056AF90`
|
|
- `ACCmdInterp::HandleNewForwardMovement` @ `0x0058B1F0`
|
|
- Named pseudo-C: `docs/research/named-retail/acclient_2013_pseudo_c.txt`
|
|
- Interpretation cross-check: ACE `Transition.cs`, `CommandInterpreter.cs`, and
|
|
`ACCmdInterp.cs` on the `ACEmulator/ACE` `master` branch.
|
|
|
|
## Enter-world placement
|
|
|
|
Retail `enter_world(position)` stores the server position and calls
|
|
`enter_world(true)`. That constructs `SetPosition` flags `0x11`, so placement
|
|
may slide away from an obstruction.
|
|
|
|
```text
|
|
find_placement_position():
|
|
check = current
|
|
insert_type = INITIAL_PLACEMENT
|
|
test environment/cells at check
|
|
(CObjCell skips shadow-object collisions for INITIAL_PLACEMENT)
|
|
validate initial placement
|
|
|
|
insert_type = PLACEMENT
|
|
if !find_placement_pos(): fail
|
|
|
|
optionally step down to a walkable surface
|
|
validate final placement
|
|
```
|
|
|
|
`find_placement_pos` is the object-aware nearest-clear-point search:
|
|
|
|
```text
|
|
find_placement_pos():
|
|
check = current
|
|
clear sliding/contact state
|
|
if placement_test(check) succeeds:
|
|
accept check and return true
|
|
|
|
if placement sliding is disabled:
|
|
return false
|
|
|
|
search_distance = 4 metres
|
|
search_radius = 4 metres
|
|
radius = mover foot-sphere radius
|
|
|
|
if radius < 0.125 metres:
|
|
fake_sphere = true
|
|
search_radius = 2 metres
|
|
else if radius < 0.48 metres:
|
|
radius = 0.48 metres
|
|
|
|
exact_step_count = 4 / radius
|
|
if fake_sphere: exact_step_count *= 0.5
|
|
if exact_step_count <= 1: return false
|
|
|
|
step_count = ceil(exact_step_count)
|
|
distance_step = search_radius / step_count
|
|
radians_step = PI * distance_step / radius
|
|
total_distance = 0
|
|
total_radians = 0
|
|
|
|
for each radial step:
|
|
total_distance += distance_step
|
|
total_radians += radians_step
|
|
compass_samples = ceil(total_radians) * 2
|
|
heading_step_degrees = 360 / compass_samples
|
|
|
|
for sample = 0 .. compass_samples-1:
|
|
check = current
|
|
heading = heading_step_degrees * sample
|
|
offset = forward_vector(heading) * total_distance
|
|
offset = adjust_offset(offset)
|
|
if length(offset) < epsilon: continue
|
|
|
|
check += offset
|
|
clear sliding/contact state
|
|
if placement_test(check) succeeds:
|
|
accept check and return true
|
|
|
|
return false
|
|
```
|
|
|
|
The local player must also own a normal shadow entry. Retail registers every
|
|
placed `CPhysicsObj`; collision queries exclude only the moving object's own
|
|
pointer. Therefore remote monsters can collide/de-overlap against the local
|
|
player, while the player's placement search skips its own shadow by entity id.
|
|
|
|
## Movement cancels repeat attack
|
|
|
|
```text
|
|
ACCmdInterp.HandleNewForwardMovement():
|
|
if combat_system exists:
|
|
combat_system.AbortAutomaticAttack()
|
|
base.HandleNewForwardMovement() // also stops auto-run
|
|
|
|
ClientCombatSystem.AbortAutomaticAttack():
|
|
if server_response_pending
|
|
or attack_request_in_progress
|
|
or attack_in_progress
|
|
or repeat_attacking:
|
|
send Event_CancelAttack
|
|
repeat_attacking = false
|
|
if combat power build is active:
|
|
HidePowerBar()
|
|
```
|
|
|
|
`CommandInterpreter::AddCommand` calls `HandleNewForwardMovement` for the
|
|
forward-substate command list, which includes forward/backward/autorun rather
|
|
than the independent turn and sidestep lists. Jump has the same cancellation
|
|
at `ClientCombatSystem::CommenceJump` before its jump power bar begins.
|
|
|