# Retail world selection and vivid target indicator Oracle: September 2013 EoR named retail client. Cross-checks: the extracted WorldBuilder mesh path (DAT geometry and current part transforms) and ACE object identity/qualities. Neither reference implementation supplies the client picker; the named retail functions below are authoritative. ## Mouse selection `SmartBox::find_object @ 0x00451C60` ```text remember the clicked viewport pixel clear the previous per-frame selection accumulator arm mouse selection for the next world draw ``` `CPhysicsPart::Draw @ 0x0050D7A0`, `RenderDeviceD3D::DrawMesh @ 0x005A0860`, and `Render::GfxObjUnderSelectionRay @ 0x0054C740` ```text for each physics part which reaches the normal visible-mesh draw path: reject parts which do not belong to a server object transform the one world selection ray into this part's local coordinates divide by the part's GfxObj scale (do not change the ray parameter units) sphere = gfxObj.drawing_sphere if sphere does not intersect the local ray: continue if a polygon has already won globally and sphereDistance is farther: continue if sphereDistance is nearer than the current sphere fallback: remember this object's id, part index, and sphereDistance for polygons in the GfxObj's stored flat DAT order: if polygon_hits_ray(polygon, localRay, out t): remember only this FIRST polygon hit for this part if t is nearer than the current global polygon winner: remember this object's id, part index, and t break ``` `CPolygon::polygon_hits_ray @ 0x005395E0` ```text if polygon.sides_type == ST_SINGLE (raw value 0) and dot(ray.direction, polygon.plane.normal) > 0: miss // back face denominator = dot(ray.direction, polygon.plane.normal) if abs(denominator) < 0.0002: miss // parallel to the plane t = plane/ray intersection time if t < 0: miss // behind the viewer point = ray.origin + t * ray.direction normal = normalize(sum(cross(vertex[i] - vertex[0], vertex[i+1] - vertex[0]))) for each ordered edge (previous -> current): inward = cross(normal, current - previous) if dot(point - previous, inward) < 0: miss return hit ``` The broad-phase helper is retail `CSphere::sphere_intersects_ray @ 0x005377A0`: it rejects rays beginning in/on the sphere, requires squared ray direction length at least `0.0002`, solves the quadratic in double precision, and chooses the near root when non-negative or the far root otherwise. The ray origin is `Render::viewpoint` (the camera eye), not the unprojected near-plane point; `Render::pick_ray @ 0x0054B610` supplies only its direction. `Render::GetMouseSelectionObjectID @ 0x0054C950` ```text if any polygon hit exists anywhere in the visible draw: return the closest polygon winner if any drawing-sphere hit exists: return the closest sphere fallback return no object ``` Important consequences: - The broad phase is each visible **GfxObj part's drawing sphere**, not a Setup selection sphere, physics collision shape, fixed creature hit box, or expanded screen rectangle. - A polygon hit on any visible part beats every sphere-only fallback. - Retail does not ray-test world-cell walls as a second, independent occluder. Occlusion is inherited from the same portal/viewcone draw traversal that decides which parts may call `GfxObjUnderSelectionRay`. - `BSPTREE::GetSphere @ 0x005397E0` returns the drawing BSP root sphere exactly; the DAT source is `GfxObj.DrawingBSP.Root.BoundingSphere`. ## Vivid target indicator `VividTargetIndicator::SetSelected @ 0x004F5CE0` ```text if selected id is the player: clear it if object is player-owned or IN_CONTAINER: clear it publish the remaining id to SmartBox if enabled and an id remains: color = gmRadarUI::GetBlipColor(selected id) else: hide both indicator roots ``` `VividTargetIndicator::Initialized @ 0x004F6C60` ```text onscreenRoot = child 0x10000038 corners = children 0x10000039, 0x1000003A, 0x1000003B, 0x1000003C offscreenRoot = child 0x10000045 ``` The constructor resolves twelve source surfaces by calling `DBObj::GetByEnum` with RenderSurface DBO type `0x0C`, client-enum category `0x10000009`, and enum values `1..12`. Values `1..4` are the four on-screen corners. `CopyImage @ 0x004F5DD0` uses the active retail blit mode (`s_BlitMethod == 4`) to colorize the source art with the same color as the object's radar blip. `SmartBox::GetObjectBoundingBox @ 0x00452E20` ```text resolve the selected id directly through CObjectMaint::GetObjectA if the object is absent: return ObjectNotFound reset to Render::set_default_view push the object's position obtain CPhysicsObj::GetSelectionSphere if no sphere exists: use an origin-centered sphere with radius 0.1 world units if Render::viewconeCheck says the sphere intersects the full viewport cone: project Render::GetViewerBBox's two corners return ObjectOnscreen and the resulting screen rectangle target = normalized selection-sphere center in viewer-local coordinates if target is in front of the viewer: angle = (450 - degrees(atan2(target.screenRight, target.screenUp))) mod 360 else: angle = (450 - degrees(atan2(target.screenRight, 0))) mod 360 return ObjectOffscreen and angle ``` This path has no object-distance test and does not ask whether the selected object participated in the visible world draw. `set_default_view` also removes the per-portal view cone before the test. Consequently, a live selected object keeps its four corners through walls and at any distance for which it remains in the client object table. `VividTargetIndicator::OnDraw @ 0x004F62B0` ```text if disabled, display-off, or selected id is zero: hide both roots else if status is ObjectOnscreen: colorize source images 1..4 with the selected radar-blip color use the actual DAT corner width and height place the corners just outside the SmartBox screen rectangle clamp the assembled indicator to an 8-pixel viewport margin show the on-screen root and hide the off-screen root else if status is ObjectOffscreen: choose one authored source image by angle: [338,360) or [0,23) -> 6 [23,68) -> 7 [68,113) -> 9 [113,158) -> 12 [158,203) -> 11 [203,248) -> 10 [248,293) -> 8 [293,338) -> 5 colorize it with the selected radar-blip color intersect the angle ray from viewport center with the screen edge center the image on that intersection clamp its top-left to the 8-pixel viewport margin hide the on-screen root and show the off-screen image ``` Installed retail DAT verification pins images 1..4 at 12×12 pixels and images 5..12 at 24×24 pixels. The larger off-screen marker is authored art, not a procedural arrow. 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.