# retail_diff.py findings checked against the retail asm and accepted as model differences.
# One per line: fn_<mod>_<off> <kind> <regex over the finding text>  # reason (required)
# A whole-port run lists stale lines (matching nothing); --no-allow shows the accepted findings.

# Dead results: retail computes a value it never reads (no side effects)
fn_3_3104 call ^(Magnitude|AsNormalized)__9CVector3f  # A9-101: 0x32FC/0x3318, the normalized aim delta at 0x38(r1) is never read; RayCollideWorld takes start/end
fn_16_601C call ^GetCurrentCameraTransform  # A9-101: 0x6324, the camera transform copied to 0x1F0(r1) is never read
fn_83_1098 call ^FromMatrix__11CQuaternion  # A9-101: 0x1130/0x1160, both quaternions (0x34/0x24(r1)) are never read
fn_55_3434 call ^GetLctrTransform  # A9-101: the locator transform copied to 0xBC(r1) is never read
fn_55_37F4 call ^GetLctrTransform  # A9-101: the locator transform copied to 0x94(r1) is never read
fn_61_2630 call ^IsMultiplayer  # A9-101: 0x2660, r3 is overwritten by the next lbz; the result is dropped

# Same behaviour, written another way
fn_79_A13C call ^Dot__9CVector2f  # A9-102: the 2D dot is written out (x*x + y*y)
fn_79_66DC call ^fn_79_6754  # A9-102: CollisionActor's manager lookup is inlined (the ids it holds are all collision actors)
fn_78_48A8 call ^fn_78_9A1C  # A9-102: JointMatches(type, 2) is `mType == 2`: no kJoints entry is kAllJoints (3)
fn_79_6B78 call ^(GetDamageVulnerability|LdrToDamageVulnerability)  # A9-102: the light vulnerability is built once (mLightVulnerability), not per joint
fn_29_2414 call ^AddObject  # A9-102: the caller (PortCIng.cpp AcceptScriptMsg) adds the explosion SpawnHitEffect returns
fn_30_CD10 call ^GetBoundingBox__13CPhysicsActor  # A9-102: CD10 is the REL's copy of CPatterned::GetTouchBounds, which the port calls
fn_12_1154 call ^fn_12_11E0  # A9-402: the REL's copy of CPatterned::GetTouchBounds (bl GetBoundingBox__13CPhysicsActorCFv, 11E0 at 0x11F8), which the port calls
fn_29_B970 call ^fn_29_BA4C  # A9-402: the REL's copy of CPatterned::GetTouchBounds (bl GetBoundingBox__13CPhysicsActorCFv, 11E0 at 0x11F8), which the port calls
fn_52_120C call ^fn_52_13CC  # A9-402: the REL's copy of CPatterned::GetTouchBounds (bl GetBoundingBox__13CPhysicsActorCFv, 11E0 at 0x11F8), which the port calls
fn_74_3CA8 call ^fn_74_3E58  # A9-402: the REL's copy of CPatterned::GetTouchBounds (bl GetBoundingBox__13CPhysicsActorCFv, 11E0 at 0x11F8), which the port calls
fn_15_1A48 call ^fn_15_1A84  # A9-403: the shock-wave info built from its loader data per use (bl LdrToDamageInfo at 0x1AB0); the port converts it once in the data ctor
fn_34_1904 call ^fn_34_1B30  # A9-403: as fn_15_1A84 (bl LdrToDamageInfo at 0x1B5C); the port builds CShockWaveInfo(mData.shockWaveInfo)
fn_27_3C1C call ^fn_27_3E18  # A9-404: 3E18 is the CLineSeg ctor (AsNormalized 0x3E74, CUnitVector3f ctor 0x3E80): the port's `const CLineSeg line(start, end)`
fn_56_6AA8 call ^Normalize__9CVector3f  # A9-406: 0x6B3C/0x6B44 normalize both vectors before GetAngleDiff, which divides by both magnitudes itself (rounding only)
fn_56_D690 call ^fn_56_D83C  # A9-102: D83C is the CRayCastResult copy; the host's `res =` assignment
fn_56_E764 call ^fn_56_C704  # A9-102: C704 is the inlined CCharLayoutInfo::GetFromParentUnrotated the port calls
fn_55_D208 call ^(Render__10CPatterned|fn_55_8A8C)  # A9-102: the host draws the body and armour from the sorted Render pass (see PortCSandBoss.cpp Render)

# The callee runs somewhere the tool does not look
fn_10_1FA14 call ^fn_10_21104  # A9-103: PhazonVisorToken builds mGuestF6C in its default member initializer (CDarkSamus.hpp)
fn_18_94C8 call ^fn_18_D794  # A9-103: D794 is the stage data's destructor; the host's implicit member destructors run it
fn_40_3B18 call ^fn_72_E0AC  # A9-103: DetachActorFromPirate, the SSpacePirate_FuncPtrs proxy to PortDetachActor
fn_59_18DC call ^fn_59_3380  # A9-401: 3380 is the port's CloseNode (PRSB msgs, SetIntAt1C(-1), ENTR, bl 155C), unmarked until every arm runs
fn_59_5D40 call ^fn_59_3380  # A9-401: 3380 is the port's CloseNode (PRSB msgs, SetIntAt1C(-1), ENTR, bl 155C), unmarked until every arm runs
fn_59_34BC call ^fn_59_155C  # A9-401: 155C is the port's SetSelection (prev/cur index, 0x194/0x198, bl 4088 UpdateTransition), unmarked until every arm runs
fn_70_4D0 call ^fn_70_330  # A9-401: 330 is the port's RenderSkyActor (TCastToPtr<CActor> 0x370, CModelData::Render 0x4B8), unmarked until every arm runs
fn_76_59BC call ^fn_76_(6F70|481C)  # A9-103: unreachable in retail (r4 = 0 at 0x5C2C); the TARGET_PC block drops the dead prediction

# Sweep A9 const/nan/shape (A9-5xx): the asm read, the difference is the port's model, not a bug
fn_3_3104 const 15  # A9-501: the 15 (lfs at 0x3304) feeds a dead AsNormalized whose 0x38(r1) result is never read
fn_9_E30 const .  # A9-502: 150/360/90/0.8/30/80 are SLdrCommandoPirate.hpp's inline ctor defaults, stored at 0xED0..
fn_10_50B8 const 1\.3  # A9-503: lfs 1.3f at 0x5128 * scale.z (0x513C) stored at 0x5164..0x516C, overwritten at 0x5360..0x5368 unread: a dead store
fn_14_B100 const .  # A9-504: the +-pi/4, +-3pi/4 .data words 0x45C..0x468 fill the 0xFF8 vector, which nothing reads (PortCDigitalGuardian.cpp:269)
fn_40_D70 const 150  # A9-505: re-stores SLdrIngPossessionData's ctor default health 150 (SLdrIngPossessionData.cpp:12)
fn_74_C3C const 150  # A9-505: re-stores SLdrIngPossessionData's ctor default health 150 (SLdrIngPossessionData.cpp:12)
fn_72_38E4 nan 39D8  # A8-7: the portal-plane check is unreachable in the port (the plane is never set)
fn_78_6458 nan 6498  # A9-506: retail duplicates the xd10 > x824/x820 compare into each ternary arm (mfcr/extrwi GT at 0x6498, 0x64B0); one port compare, same NaN arm
fn_79_7BE0 nan 7C50  # A9-507: retail splits (phase==0 && xd88>x914) || (phase==2 && xd88>x918) per phase (0x7C50 bgt, 0x7C68 ble); the port's one selected compare is equivalent
fn_79_A438 nan A444  # A9-508: retail tests the four fixed slots xc10..xc1c (ble at 0xA444..0xA480); the port loops size(), and InitGrowths always pushes 4
fn_63_2D68 nan 2EA8  # A9-509: retail re-tests x20c > 0 in the unrendered arm (0x2F0C); the clamp's NaN arm cannot happen (x20c/0.33 with x20c > 0 is finite or inf)
fn_10_45F8 shape .  # A9-510: the token/optional build lives in PhazonBeamHitToken's member initializer (PortCDarkSamusHelpers.cpp:454-472)
fn_82_8C shape .  # A9-511: retail Frees each tweak global (bl Free, single_ptr assign, delete[] loop at REL_FreeTweaks); the port keeps them inside CTweakContents, whose delete frees them
