From 4b98d04e273a9463b13b9e48132cd08d6a2f7b6a Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 29 Aug 2026 19:05:25 -0400 Subject: [PATCH 1/2] split RPBowScene --- config/RSPE01_01/splits.txt | 266 ++++++++++++++++++++++++++++++++++-- configure.py | 57 +++++++- 2 files changed, 314 insertions(+), 9 deletions(-) diff --git a/config/RSPE01_01/splits.txt b/config/RSPE01_01/splits.txt index 9d551c0d..b2a66af5 100644 --- a/config/RSPE01_01/splits.txt +++ b/config/RSPE01_01/splits.txt @@ -3491,12 +3491,262 @@ Pack/RPSports/RPBoxScene/RPBoxScene_unsplit.o: .sbss start:0x804BF958 end:0x804BF998 .sdata2 start:0x804C4CB8 end:0x804C5AC0 -Pack/RPSports/RPBowScene/RPBowScene_unsplit.o: - .text start:0x80313028 end:0x8035507C - .ctors start:0x8035524C end:0x8035525C - .rodata start:0x80392190 end:0x80393A70 - .data start:0x803CA1B8 end:0x803CAF00 - .bss start:0x804A9DE8 end:0x804BD36C - .sdata start:0x804BE968 end:0x804BE9D0 +Pack/RPSports/RPBowScene/RPBow_80313028.cpp: + .text start:0x80313028 end:0x80315998 + .rodata start:0x80392190 end:0x803924A0 + .data start:0x803CA1B8 end:0x803CA940 .sbss start:0x804BF998 end:0x804BFA10 - .sdata2 start:0x804C5AC0 end:0x804C69D0 + .sdata2 start:0x804C5AC0 end:0x804C5B00 + +Pack/RPSports/RPBowScene/RPBow_80315998.cpp: + .text start:0x80315998 end:0x8031641C + .sdata2 start:0x804C5B00 end:0x804C5B48 + +Pack/RPSports/RPBowScene/RPBow_8031641C.cpp: + .text start:0x8031641C end:0x80319C98 + .rodata start:0x803924A0 end:0x803929C8 + .data start:0x803CA940 end:0x803CAF00 + .sdata2 start:0x804C5B48 end:0x804C5B80 + +Pack/RPSports/RPBowScene/RPBow_80319C98.cpp: + .text start:0x80319C98 end:0x8031C388 + .sdata2 start:0x804C5B80 end:0x804C5CB8 + +Pack/RPSports/RPBowScene/RPBowSwing.cpp: + .text start:0x8031C388 end:0x8031ECB4 + .sdata2 start:0x804C5CB8 end:0x804C5D28 + +Pack/RPSports/RPBowScene/RPBow_8031C388.cpp: + .text start:0x8031ECB4 end:0x8031EFE4 + .rodata start:0x803929C8 end:0x803929E0 + .sdata2 start:0x804C5D28 end:0x804C5D30 + +Pack/RPSports/RPBowScene/RPBow_8031EFE4.cpp: + .text start:0x8031EFE4 end:0x80320EFC + .sdata2 start:0x804C5D30 end:0x804C5DC8 + +Pack/RPSports/RPBowScene/RPBow_80320EFC.cpp: + .text start:0x80320EFC end:0x80323790 + .rodata start:0x803929E0 end:0x80392A80 + .sdata2 start:0x804C5DC8 end:0x804C5EF8 + +Pack/RPSports/RPBowScene/RPBow_80323790.cpp: + .text start:0x80323790 end:0x80327F0C + .ctors start:0x8035524C end:0x80355250 + .rodata start:0x80392A80 end:0x80392B20 + .bss start:0x804A9DE8 end:0x804BC218 + .sdata2 start:0x804C5EF8 end:0x804C6078 + +Pack/RPSports/RPBowScene/RPBow_80327F0C.cpp: + .text start:0x80327F0C end:0x80329350 + .sdata2 start:0x804C6078 end:0x804C6098 + +Pack/RPSports/RPBowScene/RPBow_80329350.cpp: + .text start:0x80329350 end:0x80329658 + +Pack/RPSports/RPBowScene/RPBow_80329658.cpp: + .text start:0x80329658 end:0x8032A9E8 + .rodata start:0x80392B20 end:0x80392B30 + .sdata2 start:0x804C6098 end:0x804C60E0 + +Pack/RPSports/RPBowScene/RPBowActiveBall.cpp: + .text start:0x8032A9E8 end:0x8032ADD8 + .sdata2 start:0x804C60E0 end:0x804C6100 + +Pack/RPSports/RPBowScene/RPBow_8032ADD8.cpp: + .text start:0x8032ADD8 end:0x8032EA58 + .rodata start:0x80392B30 end:0x80392B58 + .sdata2 start:0x804C6100 end:0x804C6158 + +Pack/RPSports/RPBowScene/RPBow_8032EA58.cpp: + .text start:0x8032EA58 end:0x80330830 + .rodata start:0x80392B58 end:0x80392C08 + .bss start:0x804BC218 end:0x804BD2E8 + .sdata2 start:0x804C6158 end:0x804C6178 + +Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp: + .text start:0x80330830 end:0x80330EBC + .sdata2 start:0x804C6178 end:0x804C6180 + +Pack/RPSports/RPBowScene/RPBow_80330EBC.cpp: + .text start:0x80330EBC end:0x80330FE8 + .sdata2 start:0x804C6180 end:0x804C6188 + +Pack/RPSports/RPBowScene/RPBow_80330FE8.cpp: + .text start:0x80330FE8 end:0x80331654 + .sdata2 start:0x804C6188 end:0x804C61B8 + +Pack/RPSports/RPBowScene/RPBowNpcManager.cpp: + .text start:0x80331654 end:0x803327FC + .sdata2 start:0x804C61B8 end:0x804C61C8 + +Pack/RPSports/RPBowScene/RPBowManagerContext.cpp: + .text start:0x803327FC end:0x80332C24 + .rodata start:0x80392C08 end:0x80392CC0 + .bss start:0x804BD2E8 end:0x804BD328 + .sdata2 start:0x804C61C8 end:0x804C61D8 + +Pack/RPSports/RPBowScene/RPBow_80332C24.cpp: + .text start:0x80332C24 end:0x80332D14 + +Pack/RPSports/RPBowScene/RPBow_80332D14.cpp: + .text start:0x80332D14 end:0x803345F0 + .sdata2 start:0x804C61D8 end:0x804C6260 + +Pack/RPSports/RPBowScene/RPBowPinSetter.cpp: + .text start:0x803345F0 end:0x803349E0 + .sdata2 start:0x804C6260 end:0x804C6288 + +Pack/RPSports/RPBowScene/RPBow_803349E0.cpp: + .text start:0x803349E0 end:0x803363D0 + .rodata start:0x80392CC0 end:0x80392D28 + .sdata2 start:0x804C6288 end:0x804C62A0 + +Pack/RPSports/RPBowScene/RPBow_803363D0.cpp: + .text start:0x803363D0 end:0x803381DC + .sdata2 start:0x804C62A0 end:0x804C62B8 + +Pack/RPSports/RPBowScene/RPBow_803381DC.cpp: + .text start:0x803381DC end:0x8033A558 + .sdata2 start:0x804C62B8 end:0x804C6320 + +Pack/RPSports/RPBowScene/RPBow_8033A558.cpp: + .text start:0x8033A558 end:0x8033B690 + .rodata start:0x80392D28 end:0x80392EE8 + .sdata2 start:0x804C6320 end:0x804C6390 + +Pack/RPSports/RPBowScene/RPBow_8033B690.cpp: + .text start:0x8033B690 end:0x8033FD0C + .rodata start:0x80392EE8 end:0x80392EF8 + .sdata2 start:0x804C6390 end:0x804C6440 + +Pack/RPSports/RPBowScene/RPBow_8033FD0C.cpp: + .text start:0x8033FD0C end:0x80340308 + .sdata2 start:0x804C6440 end:0x804C6450 + +Pack/RPSports/RPBowScene/RPBowObstacleManager.cpp: + .text start:0x80340308 end:0x80340C34 + .rodata start:0x80392EF8 end:0x803930D0 + .sdata2 start:0x804C6450 end:0x804C6478 + +Pack/RPSports/RPBowScene/RPBow_80340C34.cpp: + .text start:0x80340C34 end:0x803433E4 + .rodata start:0x803930D0 end:0x803930E8 + .sdata2 start:0x804C6478 end:0x804C64D8 + +Pack/RPSports/RPBowScene/RPBow_803433E4.cpp: + .text start:0x803433E4 end:0x8034656C + .rodata start:0x803930E8 end:0x80393168 + .sdata2 start:0x804C64D8 end:0x804C6518 + +Pack/RPSports/RPBowScene/RPBow_8034656C.cpp: + .text start:0x8034656C end:0x80346E60 + .ctors start:0x80355250 end:0x80355254 + .rodata start:0x80393168 end:0x80393180 + .sdata2 start:0x804C6518 end:0x804C65C0 + +Pack/RPSports/RPBowScene/RPBowPlayerLaneNpc.cpp: + .text start:0x80346E60 end:0x80347574 + .sdata2 start:0x804C65C0 end:0x804C65EC + +Pack/RPSports/RPBowScene/RPBow_80347574.cpp: + .text start:0x80347574 end:0x80347D0C + .ctors start:0x80355254 end:0x80355258 + .rodata start:0x80393180 end:0x803931A0 + .sdata2 start:0x804C65EC end:0x804C6610 + +Pack/RPSports/RPBowScene/RPBow_80347D0C.cpp: + .text start:0x80347D0C end:0x80348158 + .rodata start:0x803931A0 end:0x803931C0 + .sdata2 start:0x804C6610 end:0x804C6628 + +Pack/RPSports/RPBowScene/RPBow_80348158.cpp: + .text start:0x80348158 end:0x80348858 + .rodata start:0x803931C0 end:0x80393350 + .sdata2 start:0x804C6628 end:0x804C6660 + +Pack/RPSports/RPBowScene/RPBow_80348858.cpp: + .text start:0x80348858 end:0x8034C1AC + .sdata2 start:0x804C6660 end:0x804C67C8 + +Pack/RPSports/RPBowScene/RPBow_8034C1AC.cpp: + .text start:0x8034C1AC end:0x8034C95C + .sdata2 start:0x804C67C8 end:0x804C67E0 + +Pack/RPSports/RPBowScene/RPBow_8034C95C.cpp: + .text start:0x8034C95C end:0x8034D128 + .sdata2 start:0x804C67E0 end:0x804C6838 + +Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp: + .text start:0x8034D128 end:0x8034D4F4 + .sdata2 start:0x804C6838 end:0x804C6848 + +Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp: + .text start:0x8034D4F4 end:0x8034DD08 + .sdata2 start:0x804C6848 end:0x804C6898 + +Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp: + .text start:0x8034DD08 end:0x8034E974 + .ctors start:0x80355258 end:0x8035525C + .bss start:0x804BD328 end:0x804BD36C + .sdata2 start:0x804C6898 end:0x804C68F8 + +Pack/RPSports/RPBowScene/RPBow_8034E974.cpp: + .text start:0x8034E974 end:0x8034F710 + .rodata start:0x80393350 end:0x80393360 + .sdata2 start:0x804C68F8 end:0x804C6930 + +Pack/RPSports/RPBowScene/RPBow_8034F710.cpp: + .text start:0x8034F710 end:0x803501D8 + .rodata start:0x80393360 end:0x80393398 + .sdata2 start:0x804C6930 end:0x804C6948 + +Pack/RPSports/RPBowScene/RPBow_803501D8.cpp: + .text start:0x803501D8 end:0x80350F78 + .sdata2 start:0x804C6948 end:0x804C6950 + +Pack/RPSports/RPBowScene/RPBow_80350F78.cpp: + .text start:0x80350F78 end:0x80351D58 + .rodata start:0x80393398 end:0x80393578 + .sdata start:0x804BE968 end:0x804BE9D0 + .sdata2 start:0x804C6950 end:0x804C6968 + +Pack/RPSports/RPBowScene/RPBow_80351D58.cpp: + .text start:0x80351D58 end:0x803520F0 + .sdata2 start:0x804C6968 end:0x804C6970 + +Pack/RPSports/RPBowScene/RPBow_803520F0.cpp: + .text start:0x803520F0 end:0x80353214 + .rodata start:0x80393578 end:0x803937C0 + .sdata2 start:0x804C6970 end:0x804C6978 + +Pack/RPSports/RPBowScene/RPBow_80353214.cpp: + .text start:0x80353214 end:0x803536C4 + .rodata start:0x803937C0 end:0x80393848 + .sdata2 start:0x804C6978 end:0x804C6980 + +Pack/RPSports/RPBowScene/RPBow_803536C4.cpp: + .text start:0x803536C4 end:0x80353C8C + .rodata start:0x80393848 end:0x803938C8 + .sdata2 start:0x804C6980 end:0x804C6988 + +Pack/RPSports/RPBowScene/RPBow_80353C8C.cpp: + .text start:0x80353C8C end:0x803543A8 + .rodata start:0x803938C8 end:0x803939F0 + .sdata2 start:0x804C6988 end:0x804C6998 + +Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp: + .text start:0x803543A8 end:0x803547A4 + .sdata2 start:0x804C6998 end:0x804C69C0 + +Pack/RPSports/RPBowScene/RPBow_803547A4.cpp: + .text start:0x803547A4 end:0x80354C78 + +Pack/RPSports/RPBowScene/RPBow_80354C78.cpp: + .text start:0x80354C78 end:0x80354CAC + .sdata2 start:0x804C69C0 end:0x804C69C8 + +Pack/RPSports/RPBowScene/RPBow_80354CAC.cpp: + .text start:0x80354CAC end:0x8035507C + .rodata start:0x803939F0 end:0x80393A70 + .sdata2 start:0x804C69C8 end:0x804C69D0 diff --git a/configure.py b/configure.py index 11afe8bc..67a2f00f 100755 --- a/configure.py +++ b/configure.py @@ -1341,7 +1341,62 @@ def MatchingFor(*versions): "cflags": cflags_rp, "progress_category": "bowling", # str | List[str] "objects": [ - Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowScene_unsplit.o"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80313028.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80315998.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8031641C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80319C98.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowSwing.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8031C388.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8031EFE4.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80320EFC.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80323790.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80327F0C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80329350.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80329658.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowActiveBall.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8032ADD8.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8032EA58.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80330EBC.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80330FE8.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowNpcManager.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowManagerContext.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80332C24.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80332D14.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowPinSetter.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803349E0.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803363D0.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803381DC.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8033A558.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8033B690.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8033FD0C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowObstacleManager.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80340C34.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803433E4.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8034656C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowPlayerLaneNpc.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80347574.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80347D0C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80348158.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80348858.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8034C1AC.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8034C95C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8034E974.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_8034F710.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803501D8.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80350F78.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80351D58.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803520F0.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80353214.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803536C4.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80353C8C.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_803547A4.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80354C78.cpp"), + Object(NonMatching, "Pack/RPSports/RPBowScene/RPBow_80354CAC.cpp") ], }, ] From 238c3f01475a2d8165f34422cf146465ccaa628c Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Aug 2026 02:44:54 -0400 Subject: [PATCH 2/2] import TUs --- config/RSPE01_01/symbols.txt | 170 ++-- include/Pack/RPSports/RPBowScene/bowling.h | 859 ++++++++++++++++++ .../RPSports/RPBowScene/RPBowActiveBall.cpp | 110 +++ .../RPBowScene/RPBowBackgroundNpcManager.cpp | 382 ++++++++ .../RPBowScene/RPBowBallReturnRack.cpp | 276 ++++++ .../RPBowScene/RPBowGlobalLaneManager.cpp | 227 +++++ .../RPBowScene/RPBowManagerContext.cpp | 107 +++ .../RPSports/RPBowScene/RPBowMotionBlur.cpp | 110 +++ .../RPSports/RPBowScene/RPBowNpcManager.cpp | 115 +++ .../RPSports/RPBowScene/RPBowPinSetter.cpp | 166 ++++ .../RPBowScene/RPBowTrajectoryGuide.cpp | 134 +++ 11 files changed, 2571 insertions(+), 85 deletions(-) create mode 100644 include/Pack/RPSports/RPBowScene/bowling.h create mode 100644 src/Pack/RPSports/RPBowScene/RPBowActiveBall.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowManagerContext.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowNpcManager.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowPinSetter.cpp create mode 100644 src/Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 46acac44..c3a965de 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -14093,7 +14093,7 @@ fn_803165D8 = .text:0x803165D8; // type:function size:0x60 fn_80316638 = .text:0x80316638; // type:function size:0x4 fn_8031663C = .text:0x8031663C; // type:function size:0x408 fn_80316A44 = .text:0x80316A44; // type:function size:0x4 -fn_80316A48 = .text:0x80316A48; // type:function size:0x34 +fn_80316A48__7BowlingFPQ27Bowling15SomeUnkManager0Pvi = .text:0x80316A48; // type:function size:0x34 fn_80316A7C = .text:0x80316A7C; // type:function size:0x88 fn_80316B04 = .text:0x80316B04; // type:function size:0x4 fn_80316B08 = .text:0x80316B08; // type:function size:0xFC @@ -14180,17 +14180,17 @@ fn_803248E8 = .text:0x803248E8; // type:function size:0x8 fn_803248F0 = .text:0x803248F0; // type:function size:0x8 fn_803248F8 = .text:0x803248F8; // type:function size:0x94 fn_8032498C = .text:0x8032498C; // type:function size:0x8 -fn_80324994 = .text:0x80324994; // type:function size:0xC0 +fn_80324994__7BowlingFPQ27Bowling9PinStatusPQ27Bowling11LaneContext = .text:0x80324994; // type:function size:0xC0 fn_80324A54 = .text:0x80324A54; // type:function size:0x4C fn_80324AA0 = .text:0x80324AA0; // type:function size:0x8 fn_80324AA8 = .text:0x80324AA8; // type:function size:0x18 fn_80324AC0 = .text:0x80324AC0; // type:function size:0x34 fn_80324AF4 = .text:0x80324AF4; // type:function size:0x1C -fn_80324B10 = .text:0x80324B10; // type:function size:0x8 +fn_80324B10__7BowlingFPQ27Bowling11LaneContext = .text:0x80324B10; // type:function size:0x8 fn_80324B18 = .text:0x80324B18; // type:function size:0x38 fn_80324B50 = .text:0x80324B50; // type:function size:0x50 fn_80324BA0 = .text:0x80324BA0; // type:function size:0x230 -fn_80324DD0 = .text:0x80324DD0; // type:function size:0x2C8 +fn_80324DD0__7BowlingFPQ27Bowling11LaneContextPQ34nw4r4math4VEC3 = .text:0x80324DD0; // type:function size:0x2C8 fn_80325098 = .text:0x80325098; // type:function size:0x1C fn_803250B4 = .text:0x803250B4; // type:function size:0x8 fn_803250BC = .text:0x803250BC; // type:function size:0x1C @@ -14199,7 +14199,7 @@ fn_803250E8 = .text:0x803250E8; // type:function size:0x10 fn_803250F8 = .text:0x803250F8; // type:function size:0x10 fn_80325108 = .text:0x80325108; // type:function size:0x3C fn_80325144 = .text:0x80325144; // type:function size:0x10 -fn_80325154 = .text:0x80325154; // type:function size:0x1A8 +fn_80325154__7BowlingFPQ27Bowling11LaneContext = .text:0x80325154; // type:function size:0x1A8 fn_803252FC = .text:0x803252FC; // type:function size:0x2E8 fn_803255E4 = .text:0x803255E4; // type:function size:0x24 fn_80325608 = .text:0x80325608; // type:function size:0x30 @@ -14241,15 +14241,15 @@ fn_803271E4 = .text:0x803271E4; // type:function size:0x1C fn_80327200 = .text:0x80327200; // type:function size:0x8 fn_80327208 = .text:0x80327208; // type:function size:0x8 fn_80327210 = .text:0x80327210; // type:function size:0x8 -fn_80327218 = .text:0x80327218; // type:function size:0x44 +fn_80327218__7BowlingFPQ27Bowling11LaneContext = .text:0x80327218; // type:function size:0x44 fn_8032725C = .text:0x8032725C; // type:function size:0xD4 -fn_80327330 = .text:0x80327330; // type:function size:0x174 +fn_80327330__7BowlingFPQ27Bowling11LaneContextPQ27Bowling9PinStatus = .text:0x80327330; // type:function size:0x174 fn_803274A4 = .text:0x803274A4; // type:function size:0x2C fn_803274D0 = .text:0x803274D0; // type:function size:0x34 fn_80327504 = .text:0x80327504; // type:function size:0x54 fn_80327558 = .text:0x80327558; // type:function size:0x240 fn_80327798 = .text:0x80327798; // type:function size:0x1C -fn_803277B4 = .text:0x803277B4; // type:function size:0x68 +fn_803277B4__7BowlingFPQ27Bowling11LaneContext = .text:0x803277B4; // type:function size:0x68 fn_8032781C = .text:0x8032781C; // type:function size:0x3C fn_80327858 = .text:0x80327858; // type:function size:0x298 fn_80327AF0 = .text:0x80327AF0; // type:function size:0xA0 @@ -14281,7 +14281,7 @@ fn_80329184 = .text:0x80329184; // type:function size:0x1CC fn_80329350 = .text:0x80329350; // type:function size:0x4 fn_80329354 = .text:0x80329354; // type:function size:0x12C fn_80329480 = .text:0x80329480; // type:function size:0x150 -fn_803295D0 = .text:0x803295D0; // type:function size:0x88 +fn_803295D0__7BowlingFPQ27Bowling11LaneBvhDataPvPv = .text:0x803295D0; // type:function size:0x88 fn_80329658 = .text:0x80329658; // type:function size:0x7AC fn_80329E04 = .text:0x80329E04; // type:function size:0x114 fn_80329F18 = .text:0x80329F18; // type:function size:0x188 @@ -14293,8 +14293,8 @@ fn_8032A7E4 = .text:0x8032A7E4; // type:function size:0x38 fn_8032A81C = .text:0x8032A81C; // type:function size:0x1AC fn_8032A9C8 = .text:0x8032A9C8; // type:function size:0x1C fn_8032A9E4 = .text:0x8032A9E4; // type:function size:0x4 -fn_8032A9E8 = .text:0x8032A9E8; // type:function size:0x3A0 -fn_8032AD88 = .text:0x8032AD88; // type:function size:0x50 +RenderModelSet__Q27Bowling15RPBowActiveBallFv = .text:0x8032A9E8; // type:function size:0x3A0 +ResetRenderState__Q27Bowling15RPBowActiveBallFv = .text:0x8032AD88; // type:function size:0x50 fn_8032ADD8 = .text:0x8032ADD8; // type:function size:0x1C fn_8032ADF4 = .text:0x8032ADF4; // type:function size:0x4 fn_8032ADF8 = .text:0x8032ADF8; // type:function size:0x5C @@ -14326,48 +14326,48 @@ fn_8032F6F8 = .text:0x8032F6F8; // type:function size:0xEE0 fn_803305D8 = .text:0x803305D8; // type:function size:0x24C fn_80330824 = .text:0x80330824; // type:function size:0x8 fn_8033082C = .text:0x8033082C; // type:function size:0x4 -fn_80330830 = .text:0x80330830; // type:function size:0x130 -fn_80330960 = .text:0x80330960; // type:function size:0x1F8 -fn_80330B58 = .text:0x80330B58; // type:function size:0x4C -fn_80330BA4 = .text:0x80330BA4; // type:function size:0x8C -fn_80330C30 = .text:0x80330C30; // type:function size:0x3C -fn_80330C6C = .text:0x80330C6C; // type:function size:0x7C -fn_80330CE8 = .text:0x80330CE8; // type:function size:0x64 -fn_80330D4C = .text:0x80330D4C; // type:function size:0x4C -fn_80330D98 = .text:0x80330D98; // type:function size:0x124 +UpdateBallsMdl__Q27Bowling22RPBowGlobalLaneManagerFPQ27Bowling18SceneObjectManager = .text:0x80330830; // type:function size:0x130 +UpdateLaneItems__Q27Bowling22RPBowGlobalLaneManagerFiPvPQ27Bowling15SomeUnkManager0b = .text:0x80330960; // type:function size:0x1F8 +TickNpcLanes__Q27Bowling22RPBowGlobalLaneManagerFv = .text:0x80330B58; // type:function size:0x4C +UpdateBallsPhysics__Q27Bowling22RPBowGlobalLaneManagerFv = .text:0x80330BA4; // type:function size:0x8C +SetLaneUnknownState__Q27Bowling22RPBowGlobalLaneManagerFi = .text:0x80330C30; // type:function size:0x3C +ResetLanePinsAndAnimations__Q27Bowling22RPBowGlobalLaneManagerFv = .text:0x80330C6C; // type:function size:0x7C +SetupBallManagerLaneObjects__Q27Bowling22RPBowGlobalLaneManagerFPvPv = .text:0x80330CE8; // type:function size:0x64 +InitializeBallManagerLanes__Q27Bowling22RPBowGlobalLaneManagerFv = .text:0x80330D4C; // type:function size:0x4C +CheckBallLaneIntersection__7BowlingFPff = .text:0x80330D98; // type:function size:0x124 fn_80330EBC = .text:0x80330EBC; // type:function size:0x12C -fn_80330FE8 = .text:0x80330FE8; // type:function size:0x66C -fn_80331654 = .text:0x80331654; // type:function size:0xFC -fn_80331750 = .text:0x80331750; // type:function size:0xDF0 -fn_80332540 = .text:0x80332540; // type:function size:0x7C -fn_803325BC = .text:0x803325BC; // type:function size:0x8 -fn_803325C4 = .text:0x803325C4; // type:function size:0x10 -fn_803325D4 = .text:0x803325D4; // type:function size:0xA4 -fn_80332678 = .text:0x80332678; // type:function size:0x184 -fn_803327FC = .text:0x803327FC; // type:function size:0x58 -fn_80332854 = .text:0x80332854; // type:function size:0x1B8 -fn_80332A0C = .text:0x80332A0C; // type:function size:0x5C -fn_80332A68 = .text:0x80332A68; // type:function size:0xCC -fn_80332B34 = .text:0x80332B34; // type:function size:0x98 -fn_80332BCC = .text:0x80332BCC; // type:function size:0x58 +CalculateNpcThrowVelocity__7BowlingFPQ34nw4r4math4VEC3PCQ27Bowling15RPBowNpcManagerPCQ34nw4r4math4VEC3PCQ27Bowling9PinStatus = .text:0x80330FE8; // type:function size:0x66C +DebugPrintNpcState__Q27Bowling15RPBowNpcManagerFv = .text:0x80331654; // type:function size:0xFC +Update__Q27Bowling15RPBowNpcManagerFv = .text:0x80331750; // type:function size:0xDF0 +ActivateNpcTurn__Q27Bowling15RPBowNpcManagerFv = .text:0x80332540; // type:function size:0x7C +SetStateFlag__Q27Bowling15RPBowNpcManagerFUc = .text:0x803325BC; // type:function size:0x8 +IsLaneIdle__Q27Bowling15RPBowNpcManagerFv = .text:0x803325C4; // type:function size:0x10 +Setup__Q27Bowling15RPBowNpcManagerFPQ27Bowling11LaneContextPQ27Bowling10NpcContextPQ27Bowling10NpcContextPQ27Bowling10NpcContextiPQ27Bowling19RPBowBallReturnRackPv = .text:0x803325D4; // type:function size:0xA4 +InitAudioActors__Q27Bowling15RPBowNpcManagerFi = .text:0x80332678; // type:function size:0x184 +DebugPrintStates__Q27Bowling19RPBowManagerContextFv = .text:0x803327FC; // type:function size:0x58 +UpdateNpcs__Q27Bowling19RPBowManagerContextFv = .text:0x80332854; // type:function size:0x1B8 +SetNpcStateFlags__Q27Bowling19RPBowManagerContextFUc = .text:0x80332A0C; // type:function size:0x5C +LinkNpcLanes__Q27Bowling19RPBowManagerContextFPQ27Bowling22RPBowGlobalLaneManagerPQ27Bowling18SceneObjectManager = .text:0x80332A68; // type:function size:0xCC +Initialize__Q27Bowling19RPBowManagerContextFv = .text:0x80332B34; // type:function size:0x98 +__dt__Q27Bowling15RPBowNpcManagerFv = .text:0x80332BCC; // type:function size:0x58 fn_80332C24 = .text:0x80332C24; // type:function size:0x8 fn_80332C2C = .text:0x80332C2C; // type:function size:0x34 fn_80332C60 = .text:0x80332C60; // type:function size:0xB4 fn_80332D14 = .text:0x80332D14; // type:function size:0x1390 -fn_803340A4 = .text:0x803340A4; // type:function size:0x1CC -fn_80334270 = .text:0x80334270; // type:function size:0xEC +CalculateNpcBallTransform__7BowlingFPQ34nw4r4math5MTX34PCQ27Bowling10NpcContext = .text:0x803340A4; // type:function size:0x1CC +fn_80334270__7BowlingFPQ27Bowling10NpcContext = .text:0x80334270; // type:function size:0xEC fn_8033435C = .text:0x8033435C; // type:function size:0x48 fn_803343A4 = .text:0x803343A4; // type:function size:0xA0 -fn_80334444 = .text:0x80334444; // type:function size:0x8 -fn_8033444C = .text:0x8033444C; // type:function size:0x70 +UpdateNpcLane__7BowlingFPUcPCQ27Bowling10NpcContext = .text:0x80334444; // type:function size:0x8 +InitNpcContext__7BowlingFPQ27Bowling10NpcContextii = .text:0x8033444C; // type:function size:0x70 fn_803344BC = .text:0x803344BC; // type:function size:0x68 fn_80334524 = .text:0x80334524; // type:function size:0x58 fn_8033457C = .text:0x8033457C; // type:function size:0x74 -fn_803345F0 = .text:0x803345F0; // type:function size:0x4 -fn_803345F4 = .text:0x803345F4; // type:function size:0x24 -fn_80334618 = .text:0x80334618; // type:function size:0x344 -fn_8033495C = .text:0x8033495C; // type:function size:0x24 -fn_80334980 = .text:0x80334980; // type:function size:0x60 +fn_803345F0__7BowlingFPQ27Bowling11LaneContext = .text:0x803345F0; // type:function size:0x4 +IsPinSetterActive__7BowlingFPQ27Bowling11LaneContext = .text:0x803345F4; // type:function size:0x24 +UpdatePinSetter__7BowlingFPQ27Bowling11LaneContext = .text:0x80334618; // type:function size:0x344 +TriggerPinSetter__7BowlingFPQ27Bowling11LaneContexti = .text:0x8033495C; // type:function size:0x24 +ResetPinSetterState__7BowlingFPQ27Bowling11LaneContextUc = .text:0x80334980; // type:function size:0x60 fn_803349E0 = .text:0x803349E0; // type:function size:0x51C fn_80334EFC = .text:0x80334EFC; // type:function size:0x650 fn_8033554C = .text:0x8033554C; // type:function size:0x368 @@ -14508,40 +14508,40 @@ fn_8034C6B0 = .text:0x8034C6B0; // type:function size:0x224 fn_8034C8D4 = .text:0x8034C8D4; // type:function size:0x24 fn_8034C8F8 = .text:0x8034C8F8; // type:function size:0x5C fn_8034C954 = .text:0x8034C954; // type:function size:0x8 -fn_8034C95C = .text:0x8034C95C; // type:function size:0x668 -fn_8034CFC4 = .text:0x8034CFC4; // type:function size:0xD0 +fn_8034C95C__7BowlingFPQ27Bowling12NpcIdleState = .text:0x8034C95C; // type:function size:0x668 +fn_8034CFC4__7BowlingFPQ27Bowling12NpcIdleStateii = .text:0x8034CFC4; // type:function size:0xD0 fn_8034D094 = .text:0x8034D094; // type:function size:0x90 fn_8034D124 = .text:0x8034D124; // type:function size:0x4 -fn_8034D128 = .text:0x8034D128; // type:function size:0x1B0 -fn_8034D2D8 = .text:0x8034D2D8; // type:function size:0x194 -fn_8034D46C = .text:0x8034D46C; // type:function size:0xC -fn_8034D478 = .text:0x8034D478; // type:function size:0x1C -fn_8034D494 = .text:0x8034D494; // type:function size:0x5C +DrawBlur__Q27Bowling15RPBowMotionBlurFPv = .text:0x8034D128; // type:function size:0x1B0 +UpdateBlurTransform__Q27Bowling15RPBowMotionBlurFPCQ34nw4r4math5MTX34f = .text:0x8034D2D8; // type:function size:0x194 +DeactivateBlur__Q27Bowling15RPBowMotionBlurFv = .text:0x8034D46C; // type:function size:0xC +SetBlurModels__Q27Bowling15RPBowMotionBlurFP10RPGrpModelP10RPGrpModelP10RPGrpModelP10RPGrpModelP10RPGrpModelP10RPGrpModel = .text:0x8034D478; // type:function size:0x1C +__dt__Q27Bowling15RPBowMotionBlurFv = .text:0x8034D494; // type:function size:0x5C fn_8034D4F0 = .text:0x8034D4F0; // type:function size:0x4 -fn_8034D4F4 = .text:0x8034D4F4; // type:function size:0x3E8 -fn_8034D8DC = .text:0x8034D8DC; // type:function size:0x10 -fn_8034D8EC = .text:0x8034D8EC; // type:function size:0x14 -fn_8034D900 = .text:0x8034D900; // type:function size:0x28 -fn_8034D928 = .text:0x8034D928; // type:function size:0x10 -fn_8034D938 = .text:0x8034D938; // type:function size:0x14 -fn_8034D94C = .text:0x8034D94C; // type:function size:0x1C8 -fn_8034DB14 = .text:0x8034DB14; // type:function size:0xBC -fn_8034DBD0 = .text:0x8034DBD0; // type:function size:0x20 -fn_8034DBF0 = .text:0x8034DBF0; // type:function size:0xA8 +UpdateBallReturnRack__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D4F4; // type:function size:0x3E8 +GetBallSlotIndex__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D8DC; // type:function size:0x10 +ReleaseBallFromNPC__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D8EC; // type:function size:0x14 +SpawnBallOnRack__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D900; // type:function size:0x28 +IsBallOnRack__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D928; // type:function size:0x10 +RemoveBallFromRack__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034D938; // type:function size:0x14 +SelectBallForNPC__Q27Bowling19RPBowBallReturnRackFv = .text:0x8034D94C; // type:function size:0x1C8 +ResetRackBallStates__Q27Bowling19RPBowBallReturnRackFv = .text:0x8034DB14; // type:function size:0xBC +InitBallSlotResources__Q27Bowling19RPBowBallReturnRackFlP10RPGrpModelP10RPGrpModell = .text:0x8034DBD0; // type:function size:0x20 +InitBallReturnRack__Q27Bowling19RPBowBallReturnRackFl = .text:0x8034DBF0; // type:function size:0xA8 fn_8034DC98 = .text:0x8034DC98; // type:function size:0x70 -fn_8034DD08 = .text:0x8034DD08; // type:function size:0x4 -fn_8034DD0C = .text:0x8034DD0C; // type:function size:0x8 -fn_8034DD14 = .text:0x8034DD14; // type:function size:0x4 -fn_8034DD18 = .text:0x8034DD18; // type:function size:0x3F0 -fn_8034E108 = .text:0x8034E108; // type:function size:0x638 -fn_8034E740 = .text:0x8034E740; // type:function size:0xFC -fn_8034E83C = .text:0x8034E83C; // type:function size:0x4 -fn_8034E840 = .text:0x8034E840; // type:function size:0x14 -fn_8034E854 = .text:0x8034E854; // type:function size:0x98 -fn_8034E8EC = .text:0x8034E8EC; // type:function size:0x80 -fn_8034E96C = .text:0x8034E96C; // type:function size:0x8 -fn_8034E974 = .text:0x8034E974; // type:function size:0x168 -fn_8034EADC = .text:0x8034EADC; // type:function size:0x594 +fn_8034DD08__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034DD08; // type:function size:0x4 +fn_8034DD0C__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034DD0C; // type:function size:0x8 +fn_8034DD14__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034DD14; // type:function size:0x4 +Render__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034DD18; // type:function size:0x3F0 +UpdateMovement__Q27Bowling25RPBowBackgroundNpcManagerFPQ34nw4r4math4VEC3Pb = .text:0x8034E108; // type:function size:0x638 +Reset__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034E740; // type:function size:0xFC +fn_8034E83C__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034E83C; // type:function size:0x4 +SetModelGroups__Q27Bowling25RPBowBackgroundNpcManagerFiPQ27Bowling13NpcModelGroupPQ27Bowling13NpcModelGroup = .text:0x8034E840; // type:function size:0x14 +InitializeConfig__Q27Bowling25RPBowBackgroundNpcManagerFi = .text:0x8034E854; // type:function size:0x98 +__dt__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034E8EC; // type:function size:0x80 +fn_8034E96C__Q27Bowling25RPBowBackgroundNpcManagerFv = .text:0x8034E96C; // type:function size:0x8 +fn_8034E974__7BowlingFPvi = .text:0x8034E974; // type:function size:0x168 +fn_8034EADC__7BowlingFPviPQ34nw4r4math5MTX34PQ34nw4r4math5MTX34b = .text:0x8034EADC; // type:function size:0x594 fn_8034F070 = .text:0x8034F070; // type:function size:0xF4 fn_8034F164 = .text:0x8034F164; // type:function size:0x4 fn_8034F168 = .text:0x8034F168; // type:function size:0x2D8 @@ -14640,13 +14640,13 @@ fn_80354138 = .text:0x80354138; // type:function size:0x208 fn_80354340 = .text:0x80354340; // type:function size:0x5C fn_8035439C = .text:0x8035439C; // type:function size:0x8 fn_803543A4 = .text:0x803543A4; // type:function size:0x4 -fn_803543A8 = .text:0x803543A8; // type:function size:0x2F8 -fn_803546A0 = .text:0x803546A0; // type:function size:0x28 -fn_803546C8 = .text:0x803546C8; // type:function size:0x28 -fn_803546F0 = .text:0x803546F0; // type:function size:0x10 -fn_80354700 = .text:0x80354700; // type:function size:0xC -fn_8035470C = .text:0x8035470C; // type:function size:0x5C -fn_80354768 = .text:0x80354768; // type:function size:0x3C +Draw__Q27Bowling20RPBowTrajectoryGuideFv = .text:0x803543A8; // type:function size:0x2F8 +Reset__Q27Bowling20RPBowTrajectoryGuideFv = .text:0x803546A0; // type:function size:0x28 +Initialize__Q27Bowling20RPBowTrajectoryGuideFv = .text:0x803546C8; // type:function size:0x28 +SetDotModel__Q27Bowling20RPBowTrajectoryGuideFUlP10RPGrpModel = .text:0x803546F0; // type:function size:0x10 +SetMainModels__Q27Bowling20RPBowTrajectoryGuideFP10RPGrpModelP10RPGrpModel = .text:0x80354700; // type:function size:0xC +__dt__Q27Bowling20RPBowTrajectoryGuideFv = .text:0x8035470C; // type:function size:0x5C +UpdateControllerState__7BowlingFPUl = .text:0x80354768; // type:function size:0x3C fn_803547A4 = .text:0x803547A4; // type:function size:0x6C fn_80354810 = .text:0x80354810; // type:function size:0x98 fn_803548A8 = .text:0x803548A8; // type:function size:0x6C @@ -16984,7 +16984,7 @@ lbl_80392C67 = .rodata:0x80392C67; // type:object size:0x4 data:string lbl_80392C6B = .rodata:0x80392C6B; // type:object size:0x4 data:string lbl_80392C6F = .rodata:0x80392C6F; // type:object size:0x29 lbl_80392C98 = .rodata:0x80392C98; // type:object size:0x18 data:4byte -lbl_80392CB0 = .rodata:0x80392CB0; // type:object size:0x10 data:byte +sTargetLaneWeights__7Bowling = .rodata:0x80392CB0; // type:object size:0x10 data:byte lbl_80392CC0 = .rodata:0x80392CC0; // type:object size:0x68 lbl_80392D28 = .rodata:0x80392D28; // type:object size:0x1B0 data:4byte lbl_80392ED8 = .rodata:0x80392ED8; // type:object size:0xF data:string @@ -19490,8 +19490,8 @@ lbl_803CA640 = .data:0x803CA640; // type:object size:0x10 lbl_803CA650 = .data:0x803CA650; // type:object size:0x38 jumptable_803CA688 = .data:0x803CA688; // type:object size:0x28 scope:local lbl_803CA6B0 = .data:0x803CA6B0; // type:object size:0x18 -lbl_803CA6C8 = .data:0x803CA6C8; // type:object size:0x20 align:4 data:float -lbl_803CA6E8 = .data:0x803CA6E8; // type:object size:0x18 +gLaneXOffsets__7Bowling = .data:0x803CA6C8; // type:object size:0x20 align:4 data:float +__vt__Q27Bowling15RPBowNpcManager = .data:0x803CA6E8; // type:object size:0x18 lbl_803CA700 = .data:0x803CA700; // type:object size:0x14 lbl_803CA714 = .data:0x803CA714; // type:object size:0x24 jumptable_803CA738 = .data:0x803CA738; // type:object size:0x20 scope:local @@ -20081,7 +20081,7 @@ lbl_804A9D98 = .bss:0x804A9D98; // type:object size:0xC lbl_804A9DA4 = .bss:0x804A9DA4; // type:object size:0x1C align:4 data:float lbl_804A9DC0 = .bss:0x804A9DC0; // type:object size:0xC lbl_804A9DCC = .bss:0x804A9DCC; // type:object size:0x1C align:4 data:float -lbl_804A9DE8 = .bss:0x804A9DE8; // type:object size:0x2D0 data:byte +gBowlingPhysicsData__7Bowling = .bss:0x804A9DE8; // type:object size:0x2D0 data:byte lbl_804AA0B8 = .bss:0x804AA0B8; // type:object size:0x160 lbl_804AA218 = .bss:0x804AA218; // type:object size:0x12000 lbl_804BC218 = .bss:0x804BC218; // type:object size:0xC68 data:4byte @@ -20090,7 +20090,7 @@ lbl_804BD150 = .bss:0x804BD150; // type:object size:0xD8 align:4 data:float lbl_804BD228 = .bss:0x804BD228; // type:object size:0x48 align:4 data:float lbl_804BD270 = .bss:0x804BD270; // type:object size:0x30 align:4 data:float lbl_804BD2A0 = .bss:0x804BD2A0; // type:object size:0x48 data:4byte -lbl_804BD2E8 = .bss:0x804BD2E8; // type:object size:0x40 align:4 data:float +gBallReturnRackConstants__7Bowling = .bss:0x804BD2E8; // type:object size:0x40 align:4 data:float lbl_804BD328 = .bss:0x804BD328; // type:object size:0x44 align:4 data:float mFontEncode__Q34nw4r2ut7RomFont = .sdata:0x804BD380; // type:object size:0x2 scope:global align:2 data:2byte mFormatBufferSize__Q34nw4r2ut17TextWriterBase = .sdata:0x804BD388; // type:object size:0x4 scope:weak align:4 data:4byte diff --git a/include/Pack/RPSports/RPBowScene/bowling.h b/include/Pack/RPSports/RPBowScene/bowling.h new file mode 100644 index 00000000..79cd4d57 --- /dev/null +++ b/include/Pack/RPSports/RPBowScene/bowling.h @@ -0,0 +1,859 @@ +#include +#include + +namespace Bowling { + +struct RPGrpModelPair { + // total size: 0x8 + RPGrpModel* pRealModel; // offset 0x0, size 0x4 + RPGrpModel* pReflectionModel; // offset 0x4, size 0x4 +}; + +class RPBowActiveBall { +public: + // total size: 0x88 + virtual ~RPBowActiveBall(); // offset 0x0, size 0x4 + + RPGrpModelPair models[8]; // offset 0x4, size 0x40 + nw4r::math::MTX34 mtx; // offset 0x44, size 0x30 + f32 field_0x74; // offset 0x74, size 0x4 + u32 index; // offset 0x78, size 0x4 + f32 alpha; // offset 0x7C, size 0x4 + RPGrpShadowTexture* pShadowTexture; // offset 0x80, size 0x4 + BOOL disableShadow; // offset 0x84, size 0x4 + + void ResetRenderState(); + void RenderModelSet(); +}; + +struct PhysicsBody { + // total size: 0xFC + + virtual void VF_0x00(); // vtable index 0 (offset 0x0) + virtual void VF_0x04(); // vtable index 1 (offset 0x4) + virtual void VF_0x08(); // vtable index 2 (offset 0x8) + virtual void VF_0x0C(); // vtable index 3 (offset 0xC) + + nw4r::math::VEC3 position; // offset 0x04, size 0x4 + nw4r::math::VEC3 linearVelocity; // offset 0x10, size 0x4 + nw4r::math::VEC3 previousPosition; // offset 0x1C, size 0x4 + + nw4r::math::VEC3 minPositionDelta; // offset 0x28, size 0x4 + nw4r::math::VEC3 maxPositionDelta; // offset 0x34, size 0x4 + + nw4r::math::VEC3 minVelocityDelta; // offset 0x40, size 0x4 + nw4r::math::VEC3 maxVelocityDelta; // offset 0x4C, size 0x4 + + f32 linearDamping; // offset 0x58, size 0x4 + + nw4r::math::VEC3 basisX; // offset 0x5C, size 0x4 + nw4r::math::VEC3 basisY; // offset 0x68, size 0x4 + nw4r::math::VEC3 basisZ; // offset 0x74, size 0x4 + + nw4r::math::VEC3 angularVelXY; // offset 0x80, size 0x4 + nw4r::math::VEC3 angularVelYZ; // offset 0x8C, size 0x4 + nw4r::math::VEC3 angularVelZX; // offset 0x98, size 0x4 + + nw4r::math::VEC3 minAngularDeltaXY; // offset 0xA4, size 0x4 + nw4r::math::VEC3 maxAngularDeltaXY; // offset 0xB0, size 0x4 + + nw4r::math::VEC3 minAngularDeltaYZ; // offset 0xBC, size 0x4 + nw4r::math::VEC3 maxAngularDeltaYZ; // offset 0xC8, size 0x4 + + nw4r::math::VEC3 minAngularDeltaZX; // offset 0xD4, size 0x4 + nw4r::math::VEC3 maxAngularDeltaZX; // offset 0xE0, size 0x4 + + f32 angularDamping; // offset 0xEC, size 0x4 + f32 angularResponseScale; // offset 0xF0, size 0x4 + f32 interactionRadius; // offset 0xF4, size 0x4 + + u8 flags; // offset 0xF8, size 0x1 + u8 pad_F9[0x3]; // offset 0xF9, size 0x3 +}; + +struct PinSubVecs { + // total size: 0x1C + nw4r::math::VEC3 vec1; // offset 0x0, size 0xC + nw4r::math::VEC3 vec2; // offset 0xC, size 0xC + float field_0x18; // offset 0x18, size 0x4 +}; + +struct PinPhysicsBody : public PhysicsBody { + // total size: 0x2C0 + // PhysicsBody // offset 0x0, size 0xFC + nw4r::math::VEC3 field_0xFC; // offset 0xFC, size 0xC + nw4r::math::VEC3 unkVec_0x108; // offset 0x108, size 0xC + nw4r::math::VEC3 unkVec_0x114; // offset 0x114, size 0xC + nw4r::math::VEC3 unkVec_0x120; // offset 0x120, size 0xC + nw4r::math::VEC3 unkVec_0x12C; // offset 0x12C, size 0xC + nw4r::math::VEC3 unkVec_0x138; // offset 0x138, size 0xC + nw4r::math::VEC3 unkVec_0x144; // offset 0x144, size 0xC + nw4r::math::VEC3 unkVec_0x150; // offset 0x150, size 0xC + nw4r::math::VEC3 unkVec_0x15C; // offset 0x15C, size 0xC + float field_0x168; // offset 0x168, size 0x4 + float field_0x16C; // offset 0x16C, size 0x4 + PinSubVecs pinVecs[8]; // offset 0x170, size 0xE0 + u8 unkFlag_0x250; // offset 0x250, size 0x1 + u8 isActive; // offset 0x251, size 0x1 + u8 pad_0x252[0x2]; // offset 0x252, size 0x2 + void* unkPtr_0x254; // offset 0x254, size 0x4 + void* unkPtr_0x258; // offset 0x258, size 0x4 + void* unkPtr_0x25C; // offset 0x25C, size 0x4 + void* unkPtr_0x260; // offset 0x260, size 0x4 + f32 field_0x264; // offset 0x264, size 0x4 + f32 field_0x268; // offset 0x268, size 0x4 + f32 field_0x26C; // offset 0x26C, size 0x4 + f32 field_0x270; // offset 0x270, size 0x4 + f32 field_0x274; // offset 0x274, size 0x4 + f32 field_0x278; // offset 0x278, size 0x4 + f32 field_0x27C; // offset 0x27C, size 0x4 + f32 field_0x280; // offset 0x280, size 0x4 + f32 field_0x284; // offset 0x284, size 0x4 + f32 field_0x288; // offset 0x288, size 0x4 + int mode_0x28C; // offset 0x28C, size 0x4 + u8 flag_0x290; // offset 0x290, size 0x1 + u8 pad_0x291[0x3]; // offset 0x291, size 0x3 + f32 field_0x294; // offset 0x294, size 0x4 + void* unkPtr_0x298; // offset 0x298, size 0x4 + u8 flag_0x29C; // offset 0x29C, size 0x1 + u8 pad_0x29D[0x3]; // offset 0x29D, size 0x3 + void* unkPtr_0x2A0; // offset 0x2A0, size 0x4 + int unkCounter_0x2A4; // offset 0x2A4, size 0x4 + void* field_0x2A8; // offset 0x2A8, size 0x4 + int unkCounter_0x2AC; // offset 0x2AC, size 0x4 + f32 field_0x2B0; // offset 0x2B0, size 0x4 + f32 field_0x2B4; // offset 0x2B4, size 0x4 + f32 field_0x2B8; // offset 0x2B8, size 0x4 + f32 field_0x2BC; // offset 0x2BC, size 0x4 +}; + +// Rack index order for PinManager's pPinBodies +// [6] [7] [8] [9] +// [3] [4] [5] +// [1] [2] +// [0] + +struct PinManager { + PinPhysicsBody* pPinBodies[10]; // offset 0x0, size 0x28 +}; + +struct BvhEntryHeader { + // total size: 0x40 + u32 pEntry; // offset 0x0, size 0x4 + u32 child[4]; // offset 0x4, size 0x10 + f32 field_14; // offset 0x14, size 0x4 + u32 field_18; // offset 0x18, size 0x4 + u32 field_1C; // offset 0x1C, size 0x4 + u32 field_20; // offset 0x20, size 0x4 + u32 field_24; // offset 0x24, size 0x4 + u32 field_28; // offset 0x28, size 0x4 + u32 field_2C; // offset 0x2C, size 0x4 + u32 field_30; // offset 0x30, size 0x4 + u32 field_34; // offset 0x34, size 0x4 + u32 field_38; // offset 0x38, size 0x4 + f32 field_3C; // offset 0x3C, size 0x4 + + BvhEntryHeader() { + pEntry = 0; + } +}; + +struct LaneBvhData { + // total size: 0x18 + float field_0x0; // offset 0x0, size 0x4 + float field_0x4; // offset 0x4, size 0x4 + float field_0x8; // offset 0x8, size 0x4 + float field_0xC; // offset 0xC, size 0x4 + float field_0x10; // offset 0x10, size 0x4 + float field_0x14; // offset 0x14, size 0x4 + BvhEntryHeader* pObj1; // offset 0x18, size 0x4 + BvhEntryHeader* pObj2; // offset 0x1C, size 0x4 +}; + +struct PinSetter { + // total size: 0x4C + void* vtable; // offset 0x0, size 0x4 + void* field_04; // offset 0x4, size 0x4 + void* field_08; // offset 0x8, size 0x4 + float field_0C; // offset 0xC, size 0x4 + u8 pad_10[0x8]; // offset 0x10, size 0x8 + float positionX; // offset 0x18, size 0x4 + u8 pad_1c[0x4]; // offset 0x1C, size 0x4 + float field_20; // offset 0x20, size 0x4 + u8 pad_24[0x10]; // offset 0x24, size 0x10 + float field_34; // offset 0x34, size 0x4 + float positionZ; // offset 0x38, size 0x4 + int primaryState; // offset 0x3C, size 0x4 + int sequencePhase; // offset 0x40, size 0x4 + float field_44; // offset 0x44, size 0x4 + float frameTimer; // offset 0x48, size 0x4 +}; + +struct ThrowContext { + // total size: 0x108 + int throwState; // offset 0x0, size 0x4 + nw4r::math::MTX34 ballMtx; // offset 0x4, size 0x30 + u8 pad_0x34[0x2C]; // offset 0x34, size 0x2C + float field_0x60; // offset 0x60, size 0x4 + u8 pad_0x64[0x18]; // offset 0x64, size 0x18 + float field_0x7C; // offset 0x7C, size 0x4 + void* unkPtr_0x80; // offset 0x80, size 0x4 + float field_0x84; // offset 0x84, size 0x4 + float field_0x88; // offset 0x88, size 0x4 + float field_0x8C; // offset 0x8C, size 0x4 + u8 pad_0x90[0x4]; // offset 0x90, size 0x4 + float field_0x94; // offset 0x94, size 0x4 + float field_0x98; // offset 0x98, size 0x4 + u8 pad_0x9C[0x4]; // offset 0x9C, size 0x4 + u8 flag_0xA0; // offset 0xA0, size 0x1 + u8 pad_0xA1[0x3]; // offset 0xA1, size 0x3 + float field_0xA4; // offset 0xA4, size 0x4 + u8 flag_0xA8; // offset 0xA8, size 0x1 + u8 flag_0xA9; // offset 0xA9, size 0x1 + u8 isGutterBall; // offset 0xAA, size 0x1 + u8 flag_0xAB; // offset 0xAB, size 0x1 + u8 pad_0xAC[0x14]; // offset 0xAC, size 0x14 + int animationMode; // offset 0xC0, size 0x4 + u8 pad_0xC4[0x40]; // offset 0xC4, size 0x40 + int field_0x104; // offset 0x104, size 0x4 +}; + +struct PinStatus { + // total size: 0x14 + u32 pinBits[4]; // 0x0, Bitmask where each bit represents a pin (0=down, 1=standing) + s32 pinCount; // 0x10 + + int GetStandingPinCount() const { + int count = 0; + for (int i = 0; i < pinCount; ++i) { + if (pinBits[i / 30] & (1 << (i % 30))) { + count++; + } + } + return count; + } +}; + +struct PinSetterAnimation { + // total size: 0x10 + int sequenceFrameCount; // offset 0x0, size 0x4 + float animOffsetZ; // offset 0x4, size 0x4 + float animRotationY; // offset 0x8, size 0x4 + u8 isNewRack; // offset 0xC, size 0x1 + u8 pad_2025; // offset 0xD, size 0x1 + u8 pad_2026; // offset 0xE, size 0x1 + u8 pad_2027; // offset 0xF, size 0x1 +}; + + +struct LaneContext { + // total size: 0x2080 + // void* vtable; // offset 0x0, size 0x4 + + virtual void VF_0x00(); // at 0x0 + virtual void VF_0x04(); // at 0x4 + virtual void VF_0x08(); // at 0x8 + virtual void VF_0x0C(); // at 0xC + virtual void VF_0x10(); // at 0x10 + virtual void VF_0x14(); // at 0x14 + + PinManager* pPinManager; // offset 0x4, size 0x4 + LaneBvhData* pLaneBvhData; // offset 0x8, size 0x4 + PinSetter* pPinSetter; // offset 0xC, size 0x4 + void* unkPtr_0x10; // offset 0x10, size 0x4 + int pinCount; // offset 0x14, size 0x4 + void* unkPtr_0x18; // offset 0x18, size 0x4 + void* unkPtr_0x1C; // offset 0x1C, size 0x4 + u8 pad_0x20[0x1EA0]; // offset 0x20, size 0x1EA0 + int field_1EC0; // offset 0x1EC0, size 0x4 + int field_1EC4; // offset 0x1EC4, size 0x4 + u8 pad_0x1EC8[0x18]; // offset 0x1EC8, size 0x18 + int field_1EE0; // offset 0x1EE0, size 0x4 + int field_1EE4; // offset 0x1EE4, size 0x4 + float field_0x1EE8; // offset 0x1EE8, size 0x4 + float field_0x1EEC; // offset 0x1EEC, size 0x4 + float field_0x1EF0; // offset 0x1EF0, size 0x4 + int field_1EF4; // offset 0x1EF4, size 0x4 + ThrowContext throwContext; // offset 0x1EF8, size 0x108 + PinStatus pinStatus; // offset 0x2000, size 0x4 + float laneXOffset; // offset 0x2014, size 0x4 + PinSetterAnimation setterAnm; // offset 0x2018, size 0x10 + u32 field_0x2028; // offset 0x2028, size 0x4 + void* unkPtr_0x202C; // offset 0x202C, size 0x4 + void* unkPtr_0x2030; // offset 0x2030, size 0x4 + void* unkPtr_0x2034; // offset 0x2034, size 0x4 + void* unkPtr_0x2038; // offset 0x2038, size 0x4 + void* unkPtr_0x203C; // offset 0x203C, size 0x4 + void* unkPtr_0x2040; // offset 0x2040, size 0x4 + void* unkPtr_0x2044; // offset 0x2044, size 0x4 + void* unkPtr_0x2048; // offset 0x2048, size 0x4 + void* unkPtr_0x204C; // offset 0x204C, size 0x4 + void* unkPtr_0x2050; // offset 0x2050, size 0x4 + void* unkPtr_0x2054; // offset 0x2054, size 0x4 + void* unkPtr_0x2058; // offset 0x2058, size 0x4 + void* unkPtr_0x205C; // offset 0x205C, size 0x4 + void* unkPtr_0x2060; // offset 0x2060, size 0x4 + void* unkPtr_0x2064; // offset 0x2064, size 0x4 + void* unkPtr_0x2068; // offset 0x2068, size 0x4 + void* unkPtr_0x206C; // offset 0x206C, size 0x4 + bool flag_0x2070; // offset 0x2070, size 0x1 + u8 pad_0x2071[0x3]; // offset 0x2071, size 0x3 + float field_0x2074; // offset 0x2074, size 0x4 + bool flag_0x2078; // offset 0x2078, size 0x1 + u8 pad_0x2079[0x3]; // offset 0x2079, size 0x3 + int laneStateTarget; // offset 0x207C, size 0x4 +}; + +struct SomeUnkManager0 { + // total size: 0x30 + void* vtable; // offset 0x0, size 0x4 + void* unkPtr_0x4; // offset 0x4, size 0x4 + void* unkPtr_0x8; // offset 0x8, size 0x4 + void* unkPtr_0xC; // offset 0xC, size 0x4 + void* unkPtr_0x10; // offset 0x10, size 0x4 + void* arr[7]; // offset 0x14, size 0x1C +}; + +struct SubNpcLaneData { + // total size: 0x5C + u32 field_0x0; // offset 0x0, size 0x4 + int counter_0x4; // offset 0x4, size 0x4 + float field_0x8; // offset 0x8, size 0x4 + u8 pad_0xC[0x4]; // offset 0xC, size 0x4 + float field_0x10; // offset 0x10, size 0x4 + float field_0x14; // offset 0x14, size 0x4 + float field_0x18; // offset 0x18, size 0x4 + float field_0x1C; // offset 0x1C, size 0x4 + float field_0x20; // offset 0x20, size 0x4 + float field_0x24; // offset 0x24, size 0x4 + float field_0x28; // offset 0x28, size 0x4 + u8 pad_0x2C[0x4]; // offset 0x2C, size 0x4 + u8 pad_0x30[0x4]; // offset 0x30, size 0x4 + float field_0x34; // offset 0x34, size 0x4 + u8 pad_0x38[0x4]; // offset 0x38, size 0x4 + u8 pad_0x3C[0x4]; // offset 0x3C, size 0x4 + float field_0x40; // offset 0x40, size 0x4 + u8 pad_0x44[0x4]; // offset 0x44, size 0x4 + float field_0x48; // offset 0x48, size 0x4 + u8 pad_0x4C[0x4]; // offset 0x4C, size 0x4 + u8 pad_0x50[0x4]; // offset 0x50, size 0x4 + u8 flag_0x54; // offset 0x54, size 0x1 + u8 flag_0x55; // offset 0x55, size 0x1 + u8 flag_0x56; // offset 0x56, size 0x1 + u8 flag_0x57; // offset 0x57, size 0x1 + int field_0x58; // offset 0x58, size 0x4 +}; + +struct NpcModelGroup { + // total size: 0xB4 + void* vtable; // offset 0x0, size 0x4 + u8 pad_00[0xA0]; // offset 0x4, size 0xA0 + RPGrpModel* mModelA4; // offset 0xA4, size 0x4 + RPGrpModel* mModelA8; // offset 0xA8, size 0x4 + RPGrpModel* mModelAC; // offset 0xAC, size 0x4 + RPGrpModel* mModelB0; // offset 0xB0, size 0x4 +}; + +struct ModelGroupPair { + // total size: 0x8 + NpcModelGroup* groupA; // offset 0x0, size 0x4 + NpcModelGroup* groupB; // offset 0x4, size 0x4 +}; + +struct NpcLaneDataHolder { + // total size: 0x130 + void* vtable; // offset 0x0, size 0x4 + void* unkPtr_0x04; // offset 0x4, size 0x4 + u32 field_0x08; // offset 0x8, size 0x4 + float field_0x0C; // offset 0xC, size 0x4 + float field_0x10; // offset 0x10, size 0x4 + float field_0x14; // offset 0x14, size 0x4 + float field_0x18; // offset 0x18, size 0x4 + float field_0x1C; // offset 0x1C, size 0x4 + float field_0x20; // offset 0x20, size 0x4 + float field_0x24; // offset 0x24, size 0x4 + float field_0x28; // offset 0x28, size 0x4 + float field_0x2C; // offset 0x2C, size 0x4 + SubNpcLaneData subData; // offset 0x30, size 0x5C + ModelGroupPair groups[4]; // offset 0x8C, size 0x20 + u16 field_0xAC; // offset 0xAC, size 0x2 + u16 field_0xAE; // offset 0xAE, size 0x2 + float field_0xB0; // offset 0xB0, size 0x4 + float field_0xB4; // offset 0xB4, size 0x4 + u16 field_0xB8; // offset 0xB8, size 0x2 + u16 field_0xBA; // offset 0xBA, size 0x2 + float field_0xBC; // offset 0xBC, size 0x4 + float field_0xC0; // offset 0xC0, size 0x4 + float field_0xC4; // offset 0xC4, size 0x4 + float field_0xC8; // offset 0xC8, size 0x4 + float field_0xCC; // offset 0xCC, size 0x4 + float field_0xD0; // offset 0xD0, size 0x4 + u16 field_0xD4; // offset 0xD4, size 0x2 + u16 field_0xD6; // offset 0xD6, size 0x2 + u16 field_0xD8; // offset 0xD8, size 0x2 + u8 pad_0xDA[0x2]; // offset 0xDA, size 0x2 + nw4r::math::VEC3 vec_0xDC; // offset 0xDC, size 0xC + float field_0xE8; // offset 0xE8, size 0x4 + float field_0xEC; // offset 0xEC, size 0x4 + u8 flags[0x4]; // offset 0xF0, size 0x4 + void* unkPtr_0xF4; // offset 0xF4, size 0x4 + float field_0xF8; // offset 0xF8, size 0x4 + float field_0xFC; // offset 0xFC, size 0x4 + float field_0x100; // offset 0x100, size 0x4 + float field_0x104; // offset 0x104, size 0x4 + float field_0x108; // offset 0x108, size 0x4 + float field_0x10C; // offset 0x10C, size 0x4 + float field_0x110; // offset 0x110, size 0x4 + float field_0x114; // offset 0x114, size 0x4 + RPGrpModel* unkModel_0x118; // offset 0x118, size 0x4 + float field_0x11C; // offset 0x11C, size 0x4 + void* field_0x120[0x4]; // offset 0x120, size 0x10 +}; + +class RPBowTrajectoryGuide : public RP_DEBUG_STUB_1 { +public: + // total size: 0x6C + virtual ~RPBowTrajectoryGuide(); // offset 0x0, size 0x4 + RPGrpModel* mpMainModel; // offset 0x4, size 0x4 + RPGrpModel* mpUnkModel; // offset 0x8, size 0x4 + RPGrpModel* mpDotModels[16]; // offset 0xC, size 0x40 + u32 mActiveModelIndex; // offset 0x4C, size 0x4 + u8 mIsVisible; // offset 0x50, size 0x1 + u8 pad51[3]; // offset 0x51, size 0x3 + f32 mStartX; // offset 0x54, size 0x4 + f32 mAngle; // offset 0x58, size 0x4 + f32 unk_0x5C; // offset 0x5C, size 0x4 + u32 unk_0x60; // offset 0x60, size 0x4 + f32 mLimitCenter; // offset 0x64, size 0x4 + f32 mLimitWidth; // offset 0x68, size 0x4 + + void SetMainModels(RPGrpModel* pMainModel, RPGrpModel* pUnkModel); + void SetDotModel(u32 index, RPGrpModel* pDotModel); + void Initialize(); + void Reset(); + void Draw(); +}; + +struct NpcIdleStateSub { + // total size: 0x3C + int idleState; // offset 0x0, size 0x4 + int frameCounter; // offset 0x4, size 0x4 + int unk_0x8; // offset 0x8, size 0x4 + float targetRotation; // offset 0xC, size 0x4 + float rotationSpeed; // offset 0x10, size 0x4 + nw4r::math::VEC3 pos; // offset 0x14, size 0xC + s32 bouncesRemaining; // offset 0x20, size 0x4 + float bounceVelocity; // offset 0x24, size 0x4 + s32 unk_countdown_0x28; // offset 0x28, size 0x4 + u8 field_0x2C; // offset 0x2C, size 0x1 + u8 pad_0x2D[3]; // offset 0x2D, size 0x3 + float field_0x30; // offset 0x30, size 0x4 + float field_0x34; // offset 0x34, size 0x4 + u8 field_0x38; // offset 0x38, size 0x1 + u8 pad_0x39[3]; // offset 0x39, size 0x3 +}; + +struct NpcIdleState { + // total size: 0x48 + void* vtable; // offset 0x0, size 0x4 + int unk_0x04; // offset 0x4, size 0x4 + int unk_0x08; // offset 0x8, size 0x4 + NpcIdleStateSub sub; // offset 0xC, size 0x3C +}; + +enum NpcStates { + NPC_STATE_IDLE = 0, // Idle state + NPC_STATE_WALK_TO_APPROACH_AREA = 1, // Walking to approach area + NPC_STATE_UNUSED_2 = 2, // Unused + NPC_STATE_BOWL = 3, // Bowling action + NPC_STATE_WALK_TO_BALL_RETURN = 4, // Walking to ball return + NPC_STATE_WALK_BACK_TO_SEAT = 5, // Walking back to seat +}; + +struct NpcMovementState { + // total size: 0x1C + void* vtable; // offset 0x0, size 0x4 + s32 laneIdx; // offset 0x4, size 0x4 + s32 npcIdx; // offset 0x8, size 0x4 + u8 isMovementComplete; // offset 0xC, size 0x1 + u8 pad0D[3]; // offset 0xD, size 0x3 + nw4r::math::VEC3 returnStartPos; // offset 0x10, size 0xC +}; + +struct NpcContext { + // total size: 0xA8 + void* vtable; // offset 0x0, size 0x4 + RPSysKokeshi* mpKokeshi; // offset 0x4, size 0x4 + void* field_0x8; // offset 0x8, size 0x4 + void* field_0xC; // offset 0xC, size 0x4 + nw4r::math::VEC3 pos_0x10; // offset 0x10, size 0xC + nw4r::math::VEC3 rot_0x1C; // offset 0x1C, size 0xC + float field_0x28; // offset 0x28, size 0x4 + u8 pad_0x2C[0x4]; // offset 0x2C, size 0x4 + NpcStates npcState; // offset 0x30, size 0x4 + int stateFrameCounter; // offset 0x34, size 0x4 + u8 triggerThrow; // offset 0x38, size 0x1 + u8 triggerTransition; // offset 0x39, size 0x1 + u8 pad_0x3A[0x2]; // offset 0x3A, size 0x2 + s32 field_0x3A; // offset 0x3C, size 0x4 + float targetZPos; // offset 0x40, size 0x4 + u8 field_0x44; // offset 0x44, size 0x1 + u8 pad_0x45[3]; // offset 0x45, size 0x3 + NpcMovementState* movementState; // offset 0x48, size 0x4 + int field_0x4C; // offset 0x4C, size 0x4, 0 = Walk to approach area, 1 = Idle at approach area, 2 = Bowl, 3 = Watch ball, 4 = Turn around, 5 = Walk to ball return or seat from approach area, 6 = Idle, 7 = Walk to ball return from seat + u8 isHoldingBall; // offset 0x50, size 0x1 + u8 flag_51; // offset 0x51, size 0x1 + u8 flag_52; // offset 0x52, size 0x1 + u8 flag_53; // offset 0x53, size 0x1 + int laneIdx; // offset 0x54, size 0x4 + int npcIdx; // offset 0x58, size 0x4 + NpcIdleState subStruct; // offset 0x5C, size 0x48 + u8 pad_0xA4[0x1]; // offset 0xA4, size 0x1 + u8 flag_A5; // offset 0xA5, size 0x1 + u8 pad_0xA6[0x2]; // offset 0xA6, size 0x2 +}; + +class RPBowPlayerLaneNpc : public RP_DEBUG_STUB_1 { +public: + // total size: 0x78 + virtual ~RPBowPlayerLaneNpc(); // offset 0x0, size 0x4 + void* unkPtr_0x4; // offset 0x4, size 0x4 + RPSysKokeshi* mKokeshis[2]; // offset 0x8, size 0x8 + u32 index; // offset 0x10, size 0x4 + nw4r::math::VEC3 pos; // offset 0x14, size 0xC + nw4r::math::VEC3 rot; // offset 0x20, size 0xC + u8 isVisible; // offset 0x2C, size 0x1 + u8 pad_0x2D[0x3]; // offset 0x2D, size 0x3 + NpcIdleState npcIdleState; // offset 0x30, size 0x48 + + void Init(RPSysKokeshi* kokeshi1, RPSysKokeshi* kokeshi2, int index); + void SetSeatPosition(); + void HideActiveBowler(); + void UpdateModels(); +}; + +struct BallReturnBall { + // total size: 0x28 + nw4r::math::VEC3 mPos; // offset 0x0, size 0xC + nw4r::math::VEC3 unkVec_0xC; // offset 0xC, size 0xC + float mSpeed; // offset 0x18, size 0x4 + float mAngle; // offset 0x1C, size 0x4 + float mRepulsionForce; // offset 0x20, size 0x4 + bool mClaimedByNPC; // offset 0x24, size 0x1 + bool mIsOnRack; // offset 0x25, size 0x1 + char pad_0x26[0x2]; // offset 0x26, size 0x2 +}; + +class RPBowBallReturnRack { +public: + // total size: 0xDC + RPGrpModelPair mModels[4]; // offset 0x0, size 0x20 + void* unkPtr_0x20; // offset 0x20, size 0x4 + void* unkPtr_0x24; // offset 0x24, size 0x4 + s32 mSlotIndices[4]; // offset 0x28, size 0x10 + int mRackIndex; // offset 0x38, size 0x4 + BallReturnBall mBalls[4]; // offset 0x3C, size 0xA0 (Order: Blue, Red, Green, Yellow) + + void InitBallReturnRack(s32 index); + void InitBallSlotResources(s32 index, RPGrpModel* realModel, RPGrpModel* reflectionModel, s32 slotIndex); + void ResetRackBallStates(); + int SelectBallForNPC(); + void RemoveBallFromRack(s32 index); + u8 IsBallOnRack(s32 index); + void SpawnBallOnRack(s32 index); + void ReleaseBallFromNPC(s32 index); + s32 GetBallSlotIndex(s32 index); + void UpdateBallReturnRack(s32 index); +}; + +struct BackgroundNpcMovement { + // total size: 0x30 + nw4r::math::VEC3 position; // offset 0x0, size 0xC + nw4r::math::VEC3 rotation; // offset 0xC, size 0xC + nw4r::math::VEC3 velocity; // offset 0x18, size 0xC + int behaviorState; // offset 0x24, size 0x4 + int stateTimer; // offset 0x28, size 0x4 + int animationState; // offset 0x2C, size 0x4 +}; + +class RPBowBackgroundNpcManager : public RP_DEBUG_STUB_1 { +public: + // total size: 0x9C + virtual ~RPBowBackgroundNpcManager(); // offset 0x0, size 0x4 + void* unkPtr_0x04; // offset 0x4, size 0x4 + BackgroundNpcMovement mMovement; // offset 0x8, size 0x30 + NpcModelGroup* mModelGroups[2][2]; // offset 0x38, size 0x10 + int mConfigIndex; // offset 0x48, size 0x4 + NpcIdleState mIdleState; // offset 0x4C, size 0x48 + bool unk_0x94; // offset 0x94, size 0x1 + u8 pad_0x95[3]; // offset 0x95, size 0x3 + s32 mModelGroupSet; // offset 0x98, size 0x4 + + void fn_8034E96C(); + void InitializeConfig(int index); + void SetModelGroups(int managerIndex, NpcModelGroup* modelGroup0, NpcModelGroup* modelGroup1); + void fn_8034E83C(); + void Reset(); + void UpdateMovement(nw4r::math::VEC3* outPosition, bool* outStateFlag); + void Render(); + void fn_8034DD14(); + void fn_8034DD0C(); + void fn_8034DD08(); +}; + +struct SceneEntities { + // total size: 0x1E0 + void* unkPtr_0x04; // offset 0x0, size 0x4 + NpcLaneDataHolder* npcLaneData; // offset 0x4, size 0x4 + RPBowTrajectoryGuide* trajectoryGuide; // offset 0x8, size 0x4 + void* unkPtr_0x10; // offset 0xC, size 0x4 + void* unkPtr_0x14; // offset 0x10, size 0x4 + void* unkPtr_0x18; // offset 0x14, size 0x4 + void* unkPtr_0x1C; // offset 0x18, size 0x4 + void* unkPtr_0x20; // offset 0x1C, size 0x4 + void* unkPtr_0x24; // offset 0x20, size 0x4 + void* unkPtr_0x28; // offset 0x24, size 0x4 + void* unkPtr_0x2C; // offset 0x28, size 0x4 + RPBowActiveBall* balls[7]; // offset 0x2C, size 0x1C + NpcContext* npcs[18]; // offset 0x48, size 0x48 + RPBowPlayerLaneNpc* playerLaneNpcs[4]; // offset 0x90, size 0x10 + PinSetter* setters[7]; // offset 0xA0, size 0x1C + void* unkPtrs2[64]; // offset 0xBC, size 0x100 + RPBowBallReturnRack* ballReturns[4]; // offset 0x1BC, size 0x10 + RPBowBackgroundNpcManager* BackgroundNpcs[4]; // offset 0x1CC, size 0x10 + void* unkPtr_0x1E0; // offset 0x1DC, size 0x4 +}; + +struct SceneObjectManager { + // total size: 0x218 + void* vtable; // offset 0x0, size 0x4 + SceneEntities entities; // offset 0x4, size 0x1E0 + u8 field_0x1E4; // offset 0x1E4, size 0x1 + u8 pad_0x1E5; // offset 0x1E5, size 0x1 + u8 field_0x1E6; // offset 0x1E6, size 0x1 + u8 field_0x1E7; // offset 0x1E7, size 0x1 + u8 field_0x1E8; // offset 0x1E8, size 0x1 + u8 field_0x1E9; // offset 0x1E9, size 0x1 + u8 field_0x1EA; // offset 0x1EA, size 0x1 + u8 field_0x1EB; // offset 0x1EB, size 0x1 + void* unkPtr_0x1EC; // offset 0x1EC, size 0x4 + u8 isComplete; // offset 0x1F0, size 0x1 + u8 field_0x1F1; // offset 0x1F1, size 0x1 + u8 field_0x1F2; // offset 0x1F2, size 0x1 + u8 field_0x1F3; // offset 0x1F3, size 0x1 + u8 field_0x1F4; // offset 0x1F4, size 0x1 + u8 pad_0x1F5[0x3]; // offset 0x1F5, size 0x3 + void* unkPtr_0x1F8; // offset 0x1F8, size 0x4 + void* unkPtr_0x1FC; // offset 0x1FC, size 0x4 + void* unkPtr_0x200; // offset 0x200, size 0x4 + u8 pad_0x204[0x4]; // offset 0x204, size 0x4 + void* obj208Data; // offset 0x208, size 0x4 + void* field_0x20C; // offset 0x20C, size 0x4 + float field_0x210; // offset 0x210, size 0x4 + float field_0x214; // offset 0x214, size 0x4 +}; + +class RPBowGlobalLaneManager { +public: + // total size: 0x24 + u8 pad_00[0x04]; // offset 0x0, size 0x4 + LaneContext* pLanes[7]; // offset 0x4, size 0x1C + u8 isInitialized; // offset 0x20, size 0x1 + u8 field_0x21; // offset 0x21, size 0x1 + u8 pad_22[0x2]; // offset 0x22, size 0x2 + + void InitializeBallManagerLanes(); + void SetupBallManagerLaneObjects(void* arg1, void* arg2); + void ResetLanePinsAndAnimations(); + void SetLaneUnknownState(int value); + void UpdateBallsPhysics(); + void TickNpcLanes(); + void UpdateLaneItems(int val, void* obj, SomeUnkManager0* someMgr, bool isPlayerTurn); + void UpdateBallsMdl(SceneObjectManager* vballmgr); +}; + +class RPBowNpcManager: public IRPSysHostIOSocket { +public: + // Total Size 0x58. See fn_80332B34 + // vtable // offset 0x0, size 0x4 + u32 pad_0x04; // offset 0x4, size 0x4 + int mStateId; // offset 0x8, size 0x4, 0 = Idle, 1 = Walk to approach area, 2 = Idle at approach area, 3 = Bowl, 4 = Watch ball, 5 = Walk to ball return or seat. + int mStateTimer; // offset 0xC, size 0x4 + bool mHasReleasedBall; // offset 0x10, size 0x1, Set to 1 the moment the first ball is thrown during a turn. + bool mIsSecondThrow; // offset 0x11, size 0x1, Set to 1 the moment the NPC walks up to the approach area on the second turn. + bool mShouldReturnToSeat; // offset 0x12, size 0x1, Set to 1 after the pins are knocked down and the NPC turns to walk back to their seat. + u8 field_0x13; // offset 0x13, size 0x1 + LaneContext* mpLaneContext; // offset 0x14, size 0x4 + NpcContext* mpNpcs[3]; // offset 0x18, size 0xC + NpcContext* mpCurrentNpc; // offset 0x24, size 0x4 + int mLaneIdx; // offset 0x28, size 0x4 + int mCurrentNpcIdx; // offset 0x2C, size 0x4 + PinStatus mPinStatus; // offset 0x30, size 0x14 + void* mpSoundAudioMgr; // offset 0x44, size 0x4 + bool mHasPlayedGutterSfx; // offset 0x48, size 0x1 + u8 mDisableResultSfx; // offset 0x49, size 0x1 + u8 field_0x4A; // offset 0x4A, size 0x1 + u8 field_0x4B; // offset 0x4B, size 0x1 + RPBowBallReturnRack* mpReturnRack; // offset 0x4C, size 0x4 + s32 mActiveSubObjIdx; // offset 0x50, size 0x4 + void* mpSomeAudioStruct; // offset 0x54, size 0x4 + + void InitAudioActors(int laneIdx); + void Setup(LaneContext* pLaneContext, NpcContext* pNpc0, NpcContext* pNpc1, NpcContext* pNpc2, int laneIdx, RPBowBallReturnRack* pReturnRack, void* pAudioStruct); + int IsLaneIdle(); + void SetStateFlag(u8 flag); + void ActivateNpcTurn(); + void Update(); + void DebugPrintNpcState(); + + inline RPBowNpcManager() { + mPinStatus.pinBits[3] = -1; + mPinStatus.pinBits[2] = -1; + mPinStatus.pinBits[1] = -1; + mPinStatus.pinBits[0] = -1; + mPinStatus.pinCount = 10; + } + + nw4r::math::MTX34 GetPinWorldMatrix(int pinIndex) const { + if (pinIndex >= mpLaneContext->pinCount) { + nw4r::math::MTX34 matrix; + nw4r::math::MTX34Identity(&matrix); + return matrix; + } else { + PinPhysicsBody* pinData = mpLaneContext->pPinManager->pPinBodies[pinIndex]; + return nw4r::math::MTX34( + pinData->basisX.x, pinData->basisY.x, pinData->basisZ.x, pinData->position.x, + pinData->basisX.y, pinData->basisY.y, pinData->basisZ.y, pinData->position.y, + pinData->basisX.z, pinData->basisY.z, pinData->basisZ.z, pinData->position.z + ); + } + } +}; + +class RPBowManagerContext { +public: + // total size: 0x34 + void* vtable; // offset 0x0, size 0x4 + RPBowNpcManager* mpManagers[6]; // offset 0x4, size 0x18 + int field_0x1C; // offset 0x1C, size 0x4 + u8 mIsEnabled; // offset 0x20, size 0x1 + u8 pad_0x24[7]; // offset 0x21, size 0x7 + int field_0x28; // offset 0x28, size 0x4 + void* field_0x2C; // offset 0x2C, size 0x4 + void* field_0x30; // offset 0x30, size 0x4 + + void Initialize(); + void LinkNpcLanes(RPBowGlobalLaneManager* laneManager, SceneObjectManager* sceneObjectManager); + void SetNpcStateFlags(u8 flag); + void UpdateNpcs(); + void DebugPrintStates(); +}; + +class RPBowMotionBlur : public RP_DEBUG_STUB_1 { +public: + // total size: 0xB4 + virtual ~RPBowMotionBlur(); // offset 0x0, size 0x4 + RPGrpModelPair models[3]; // offset 0x4, size 0x18 + nw4r::math::MTX34 blurMtxs[3]; // offset 0x1C, size 0x90 + bool isActive; // offset 0xAC, size 0x1 + u8 pad1[3]; // offset 0xAD, size 0x3 + f32 speed; // offset 0xB0, size 0x4 + + void SetBlurModels(RPGrpModel* pReal1, RPGrpModel* pReal2, RPGrpModel* pReal3, RPGrpModel* pRefl1, RPGrpModel* pRefl2, RPGrpModel* pRefl3); + void DeactivateBlur(); + void UpdateBlurTransform(const nw4r::math::MTX34* pBaseMtx, f32 speed); + void DrawBlur(void* pCullingCtx); +}; + +// Global Data: + +struct BallReturnRackConstants { + // total size: 0x3C + nw4r::math::VEC3 mPositionOffsets[4]; // offset 0x0, size 0x30 + float mHeightLimit; // offset 0x30, size 0x4 + float mRepulsionThreshold; // offset 0x34, size 0x4 + float mGravity; // offset 0x38, size 0x4 +}; + +struct BowlingPhysicsData { + // total size: 0x2D0 + u8 flag_00; // offset 0x0, size 0x1 + u8 flag_01; // offset 0x1, size 0x1 + u8 flag_02; // offset 0x2, size 0x1 + u8 flag_03; // offset 0x3, size 0x1 + u8 flag_04; // offset 0x4, size 0x1 + u8 flag_05; // offset 0x5, size 0x1 + u8 flag_06; // offset 0x6, size 0x1 + u8 flag_07; // offset 0x7, size 0x1 + f32 field_08; // offset 0x8, size 0x4 + f32 field_0C; // offset 0xC, size 0x4 + f32 field_10; // offset 0x10, size 0x4 + f32 field_14; // offset 0x14, size 0x4 + f32 field_18; // offset 0x18, size 0x4 + f32 field_1C; // offset 0x1C, size 0x4 + f32 field_20; // offset 0x20, size 0x4 + f32 field_24; // offset 0x24, size 0x4 + f32 field_28; // offset 0x28, size 0x4 + f32 field_2C; // offset 0x2C, size 0x4 + f32 field_30; // offset 0x30, size 0x4 + f32 field_34; // offset 0x34, size 0x4 + u8 pad_0x38[0x3C]; // offset 0x38, size 0x3C + f32 field_74; // offset 0x74, size 0x4 + f32 field_78; // offset 0x78, size 0x4 + f32 field_7C; // offset 0x7C, size 0x4 + f32 field_80; // offset 0x80, size 0x4 + u8 pad_0x84[0x8]; // offset 0x84, size 0x8 + f32 field_8C; // offset 0x8C, size 0x4 + f32 field_90; // offset 0x90, size 0x4 + f32 field_94; // offset 0x94, size 0x4 + u8 pad_0x98[0x70]; // offset 0x98, size 0x70 + f32 field_108; // offset 0x108, size 0x4 + f32 field_10C; // offset 0x10C, size 0x4 + f32 field_110; // offset 0x110, size 0x4 + f32 field_114; // offset 0x114, size 0x4 + f32 field_118; // offset 0x118, size 0x4 + f32 field_11C; // offset 0x11C, size 0x4 + u8 pad_0x120[0x8]; // offset 0x120, size 0x8 + f32 field_128; // offset 0x128, size 0x4 + u8 pad_0x12C[0x2C]; // offset 0x12C, size 0x2C + f32 field_158; // offset 0x158, size 0x4 + u8 pad_0x15C[0x28]; // offset 0x15C, size 0x28 + f32 field_184; // offset 0x184, size 0x4 + u8 pad_0x188[0x1C]; // offset 0x188, size 0x1C + f32 field_1A4; // offset 0x1A4, size 0x4 + u8 pad_0x1A8[0x1C]; // offset 0x1A8, size 0x1C + f32 field_1C4; // offset 0x1C4, size 0x4 + u8 pad_0x1C8[0x3C]; // offset 0x1C8, size 0x3C + f32 field_204; // offset 0x204, size 0x4 + f32 field_208; // offset 0x208, size 0x4 + u8 pad_0x20C[0x60]; // offset 0x20C, size 0x60 + f32 floats[20]; // offset 0x26C, size 0x50 + f32 field_2BC; // offset 0x2BC, size 0x4 + f32 field_2C0; // offset 0x2C0, size 0x4 + f32 field_2C4; // offset 0x2C4, size 0x4 + f32 field_2C8; // offset 0x2C8, size 0x4 + f32 field_2CC; // offset 0x2CC, size 0x4 +}; + +struct BackgroundNpcConfig { + // total size: 0x44 + float laneZPositions[4]; // offset 0x0, size 0x10 + float basePosY; // offset 0x10, size 0x4 + float seatedPosY; // offset 0x14, size 0x4 + float mirroredModelZOffset; // offset 0x18, size 0x4 + float patrolMinX; // offset 0x1C, size 0x4 + float patrolMaxX; // offset 0x20, size 0x4 + float minWalkSpeed; // offset 0x24, size 0x4 + float maxWalkSpeed; // offset 0x28, size 0x4 + u32 dormantToPatrolChanceDenom; // offset 0x2C, size 0x4 + u32 patrolToIdleChanceDenom; // offset 0x30, size 0x4 + u32 idleToPatrolChanceDenom; // offset 0x34, size 0x4 + float turnLerpRate; // offset 0x38, size 0x4 + float idleCenterZoneX; // offset 0x3C, size 0x4 + u32 minStateDuration; // offset 0x40, size 0x4 +}; + +extern BallReturnRackConstants gBallReturnRackConstants; +extern BowlingPhysicsData gBowlingPhysicsData; + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowActiveBall.cpp b/src/Pack/RPSports/RPBowScene/RPBowActiveBall.cpp new file mode 100644 index 00000000..6fb3f4c2 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowActiveBall.cpp @@ -0,0 +1,110 @@ +#include + +// Returns a packed 32-bit color (RGBA) from the model +u32 fn_801C389C(RPGrpModel* pModel, int unk1, int unk2); + +// Applies the given color to the model +void fn_801C37EC(RPGrpModel* pModel, int unk1, int unk2, GXColor* pColor); + +namespace Bowling { + +/** + * @brief Initializes the render object to its default state + */ +void RPBowActiveBall::ResetRenderState() { + MTX34Identity(&mtx); + + field_0x74 = 0.0f; + index = 0; + + mtx._23 = 9999.0f; + alpha = 1.0f; +} + +/** + * @brief Renders the currently selected model set + * + * Updates the main model's transform and color, renders a mirrored version used + * for reflections, and optionally submits the model to the shadow texture renderer. + */ +void RPBowActiveBall::RenderModelSet() { + if (mtx._23 > 49.0f) { + return; + } + + nw4r::math::MTX34 worldMtx = mtx; + + f32 scale = 1.0f; + worldMtx._00 *= scale; + worldMtx._01 *= scale; + worldMtx._02 *= scale; + + worldMtx._10 *= scale; + worldMtx._11 *= scale; + worldMtx._12 *= scale; + + worldMtx._20 *= scale; + worldMtx._21 *= scale; + worldMtx._22 *= scale; + + u32 packedColor = fn_801C389C(models[index].pRealModel, 0, 0); + + GXColor color; + color.a = (s8) (255.0f * alpha); + color.r = GX_BITGET(packedColor, 16, 8); + color.g = GX_BITGET(packedColor, 8, 8); + color.b = GX_BITGET(packedColor, 0, 8); + + GXColor modelColor = color; + + fn_801C37EC(models[index].pRealModel, 0, 0, &modelColor); + + if (models[index].pRealModel->GetScnObj() != NULL) { + models[index].pRealModel->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &worldMtx); + } + + models[index].pRealModel->UpdateFrame(); + models[index].pRealModel->Calc(); + models[index].pRealModel->Entry(); + + nw4r::math::MTX34 reflectionMtx = worldMtx; + + reflectionMtx._10 *= -1.0f; + reflectionMtx._11 *= -1.0f; + reflectionMtx._12 *= -1.0f; + reflectionMtx._13 *= -1.0f; + + nw4r::math::VEC3 src(0.0f, 0.0f, 0.0f); + nw4r::math::VEC3 dst; + + f32 limit = 1.075f; + f32 thresholdZ = -192.0f + limit; + f32 thresholdY = -limit; + f32 offset = 0.0f; + + VEC3Transform(&dst, &reflectionMtx, &src); + + if (dst.y > thresholdY && dst.z > thresholdZ) { + f32 diff = thresholdY - dst.y; + + if (offset > diff) { + offset = diff; + } + } + + reflectionMtx._13 += offset; + + if (models[index].pReflectionModel->GetScnObj() != NULL) { + models[index].pReflectionModel->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &reflectionMtx); + } + + models[index].pReflectionModel->UpdateFrame(); + models[index].pReflectionModel->Calc(); + models[index].pReflectionModel->Entry(); + + if (!disableShadow) { + pShadowTexture->AddModel(models[index].pRealModel, 1.0f); + } +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp b/src/Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp new file mode 100644 index 00000000..80eabbf1 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowBackgroundNpcManager.cpp @@ -0,0 +1,382 @@ +#include +#include + +#define nullptr 0 + +namespace Bowling { + +// Forward declarations +extern u8 lbl_804BF9F8; +extern u32 lbl_804BF9F4; + +void fn_8034CFC4(NpcIdleState* pIdleState, int param_2, int param_3); +NpcIdleStateSub* fn_8034C95C(NpcIdleState* pIdleState); + +BackgroundNpcConfig gBackgroundNpcParams; + +class RPGrpModelAccessor : public RPGrpModel { +public: + static RPGrpModelAnm* GetModelAnm(RPGrpModel* pModel) { + return pModel->*(&RPGrpModelAccessor::mpModelAnm); + } + + static void SetScale(RPGrpModel* pModel, const nw4r::math::VEC3& rScale) { + pModel->*(&RPGrpModelAccessor::mBaseScale) = rScale; + } +}; + +/** + * @brief Unknown stub + */ +void RPBowBackgroundNpcManager::fn_8034E96C() { + ; +} + +/** + * @brief Destructor + */ +RPBowBackgroundNpcManager::~RPBowBackgroundNpcManager() {} + +/** + * @brief Initializes the background NPC configuration + * + * @param index Lane index + */ +void RPBowBackgroundNpcManager::InitializeConfig(int index) { + mConfigIndex = index; + + gBackgroundNpcParams.laneZPositions[0] = 92.0f; + gBackgroundNpcParams.laneZPositions[1] = 99.0f; + gBackgroundNpcParams.laneZPositions[2] = 106.0f; + gBackgroundNpcParams.laneZPositions[3] = 113.0f; + + gBackgroundNpcParams.basePosY = 3.85f; + gBackgroundNpcParams.seatedPosY = 2.0f; + gBackgroundNpcParams.mirroredModelZOffset = 6.5f; + gBackgroundNpcParams.patrolMinX = -120.0f; + gBackgroundNpcParams.patrolMaxX = 120.0f; + gBackgroundNpcParams.minWalkSpeed = 0.07f; + gBackgroundNpcParams.maxWalkSpeed = 0.25f; + + gBackgroundNpcParams.dormantToPatrolChanceDenom = 200; + gBackgroundNpcParams.patrolToIdleChanceDenom = 400; + gBackgroundNpcParams.idleToPatrolChanceDenom = 300; + + gBackgroundNpcParams.turnLerpRate = 0.05f; + gBackgroundNpcParams.idleCenterZoneX = 70.0f; + + gBackgroundNpcParams.minStateDuration = 120; +} + +/** + * @brief Sets the model groups for the manager + * + * @param managerIndex Manager index + * @param pModelGroup0 First model group + * @param pModelGroup1 Second model group + */ +void RPBowBackgroundNpcManager::SetModelGroups(int managerIndex, NpcModelGroup* pModelGroup0, NpcModelGroup* pModelGroup1) { + mModelGroups[managerIndex][0] = pModelGroup0; + mModelGroups[managerIndex][1] = pModelGroup1; +} + +/** + * @brief Unknown stub + */ +void RPBowBackgroundNpcManager::fn_8034E83C() { + ; +} + +/** + * @brief Resets the manager state + */ +void RPBowBackgroundNpcManager::Reset() { + mModelGroupSet = 0; + *(volatile int*)&mMovement.animationState = -1; + *(volatile int*)&mMovement.animationState = 0; + + for (int i = 0; i < 2; i++) { + NpcModelGroup* pGroup = mModelGroups[mModelGroupSet][i]; + RPGrpModelAnm* pAnimation = RPGrpModelAccessor::GetModelAnm(pGroup->mModelA8); + pAnimation->StartBlend(RPGrpModelAnm::Anm_Chr, 0, 60.0f, 0.0f); + } + + memset(&mMovement, 0, 0x30); + + mMovement.behaviorState = 0; + mMovement.stateTimer = -1; + + fn_8034CFC4(&mIdleState, 999, 0); + unk_0x94 = 0; + + for (int j = 0; j < 600; j++) { + UpdateMovement(nullptr, nullptr); + } + + lbl_804BF9F8 = 0; +} + +/** + * @brief Updates the movement state and calculates position + * + * @param pOutPosition[out] Output position + * @param pOutStateFlag[out] Output state flag + */ +void RPBowBackgroundNpcManager::UpdateMovement(nw4r::math::VEC3* pOutPosition, bool* pOutStateFlag) { + bool stateFlag = true; + BackgroundNpcConfig* pConfig = &gBackgroundNpcParams; + + if (mMovement.stateTimer < 0) { + mMovement.stateTimer = 0; + } + + nw4r::math::VEC3 localVec(0.0f, 0.0f, 0.0f); + + switch (mMovement.behaviorState) { + case 0: + { + if (RPUtlRandom::getU32(pConfig->dormantToPatrolChanceDenom) == 0) { + mModelGroupSet = RPUtlRandom::getU32(2); + if (mModelGroupSet >= 2) { + mModelGroupSet = 1; + } + mMovement.animationState = -1; + mMovement.behaviorState = 1; + mMovement.stateTimer = -1; + } + stateFlag = false; + break; + } + + case 1: + { + if (mMovement.stateTimer == 0) { + f32 walkSpeed = pConfig->minWalkSpeed + RPUtlRandom::getF32() * (pConfig->maxWalkSpeed - pConfig->minWalkSpeed); + if (RPUtlRandom::getU32(2) == 0) { + walkSpeed *= -1.0f; + } + + mMovement.velocity.x = walkSpeed; + mMovement.velocity.y = 0.0f; + mMovement.velocity.z = 0.0f; + + if (walkSpeed < 0.0f) { + mMovement.position.x = pConfig->patrolMaxX; + } else { + mMovement.position.x = pConfig->patrolMinX; + } + + mMovement.position.y = pConfig->basePosY; + mMovement.position.z = pConfig->laneZPositions[mConfigIndex]; + } + + if (mMovement.animationState != 1) { + mMovement.animationState = 1; + for (int i = 0; i < 2; i++) { + NpcModelGroup* pGroup = mModelGroups[mModelGroupSet][i]; + RPGrpModelAnm* pAnimation = RPGrpModelAccessor::GetModelAnm(pGroup->mModelA8); + + pAnimation->StartBlend(RPGrpModelAnm::Anm_Chr, 1, 60.0f, 0.0f); + } + } + + if (std::fabs(mMovement.position.x) < pConfig->idleCenterZoneX && (int)pConfig->minStateDuration < mMovement.stateTimer) { + if (RPUtlRandom::getU32(pConfig->patrolToIdleChanceDenom) == 0) { + mMovement.behaviorState = 2; + mMovement.stateTimer = -1; + } + } + + f32 targetAngle; + if (mMovement.velocity.x < 0.0f) { + targetAngle = 270.0f; + } else { + targetAngle = 90.0f; + } + + mMovement.rotation.y += pConfig->turnLerpRate * (targetAngle - mMovement.rotation.y); + mMovement.position += mMovement.velocity; + + if (mMovement.position.x < pConfig->patrolMinX || mMovement.position.x > pConfig->patrolMaxX) { + mMovement.behaviorState = 0; + mMovement.stateTimer = -1; + } + break; + } + + case 2: + { + if (mMovement.stateTimer == 0) { + mIdleState.sub.field_0x2C = true; + mIdleState.sub.unk_0x8 = lbl_804BF9F4; + } + + if (mMovement.animationState != 0) { + mMovement.animationState = 0; + for (int i = 0; i < 2; i++) { + NpcModelGroup* pGroup = mModelGroups[mModelGroupSet][i]; + RPGrpModelAnm* pAnimation = RPGrpModelAccessor::GetModelAnm(pGroup->mModelA8); + + pAnimation->StartBlend(RPGrpModelAnm::Anm_Chr, 0, 60.0f, 0.0f); + } + } + + NpcIdleStateSub* pRet = fn_8034C95C(&mIdleState); + localVec = pRet->pos; + mMovement.rotation.y += pRet->rotationSpeed * (pRet->targetRotation - mMovement.rotation.y); + + if ((int)pConfig->minStateDuration < mMovement.stateTimer) { + if (RPUtlRandom::getU32(pConfig->idleToPatrolChanceDenom) == 0) { + mMovement.behaviorState = 1; + mMovement.stateTimer = 0; + + f32 walkSpeed = pConfig->minWalkSpeed + RPUtlRandom::getF32() * (pConfig->maxWalkSpeed - pConfig->minWalkSpeed); + if (RPUtlRandom::getU32(2) == 0) { + walkSpeed *= -1.0f; + } + mMovement.velocity.x = walkSpeed; + } + } + break; + } + } + + mMovement.stateTimer++; + + if (pOutPosition != nullptr) { + *pOutPosition = localVec; + } + if (pOutStateFlag != nullptr) { + *pOutStateFlag = stateFlag; + } +} + +//! Gets the face model +#define GET_FACE(pKokeshi) ((pKokeshi)->mModelA4) +//! Gets the body model +#define GET_BODY(pKokeshi) ((pKokeshi)->mModelA8) +//! Gets the left hand model +#define GET_LHAND(pKokeshi) ((pKokeshi)->mModelAC) +//! Gets the right hand model +#define GET_RHAND(pKokeshi) ((pKokeshi)->mModelB0) + +/** + * @brief Renders the background NPC + */ +void RPBowBackgroundNpcManager::Render() { + bool stateFlag = true; + nw4r::math::VEC3 position(0.0f, 0.0f, 0.0f); + BackgroundNpcConfig* pConfig = &gBackgroundNpcParams; + + UpdateMovement(&position, &stateFlag); + + if (!stateFlag || !unk_0x94) { + return; + } + + nw4r::math::MTX34 mtx; + nw4r::math::MTX34Identity(&mtx); + + position += mMovement.position; + if (lbl_804BF9F8 != 0) { + position.y += pConfig->seatedPosY - pConfig->basePosY; + } + + nw4r::math::MTX34Trans(&mtx, &position, &mtx); + + nw4r::math::MTX34 mtx2; + nw4r::math::MTX34RotXYZDeg(&mtx2, mMovement.rotation.x, mMovement.rotation.y, mMovement.rotation.z); + + nw4r::math::MTX34Mult(&mtx, &mtx, &mtx2); + + nw4r::math::VEC3 scale(0.7f, 0.7f, 0.7f); + nw4r::math::MTX34 mtx3 = mtx; + + mtx3._10 *= -1.0f; + mtx3._11 *= -1.0f; + mtx3._12 *= -1.0f; + mtx3._13 *= -1.0f; + mtx3._13 += pConfig->mirroredModelZOffset; + + for (int i = 0; i < 2; i++) { + NpcModelGroup* pGroup = mModelGroups[mModelGroupSet][i]; + + nw4r::math::MTX34 leftHandMtx; + nw4r::math::MTX34 rightHandMtx; + nw4r::math::MTX34 headMtx; + + if (GET_BODY(pGroup)->GetScnObj() != nullptr) { + GET_BODY(pGroup)->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, i == 0 ? &mtx : &mtx3); + } + RPGrpModelAccessor::SetScale(GET_BODY(pGroup), scale); + GET_BODY(pGroup)->UpdateFrame(); + GET_BODY(pGroup)->Calc(); + + RPSysKokeshi* pKokeshi = reinterpret_cast(pGroup); + pKokeshi->GetHeadJointMtx(reinterpret_cast(&headMtx)); + pKokeshi->GetLeftHandJointMtx(reinterpret_cast(&leftHandMtx)); + pKokeshi->GetRightHandJointMtx(reinterpret_cast(&rightHandMtx)); + + if (i != 0) { + nw4r::math::MTX34 flipMtx( + -1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f + ); + nw4r::math::MTX34Mult(&headMtx, &headMtx, &flipMtx); + } + + if (GET_FACE(pGroup)->GetScnObj() != nullptr) { + GET_FACE(pGroup)->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &headMtx); + } + RPGrpModelAccessor::SetScale(GET_FACE(pGroup), scale); + GET_FACE(pGroup)->UpdateFrame(); + GET_FACE(pGroup)->Calc(); + + if (GET_LHAND(pGroup)->GetScnObj() != nullptr) { + GET_LHAND(pGroup)->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &leftHandMtx); + } + RPGrpModelAccessor::SetScale(GET_LHAND(pGroup), scale); + GET_LHAND(pGroup)->UpdateFrame(); + GET_LHAND(pGroup)->Calc(); + + if (GET_RHAND(pGroup)->GetScnObj() != nullptr) { + GET_RHAND(pGroup)->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &rightHandMtx); + } + RPGrpModelAccessor::SetScale(GET_RHAND(pGroup), scale); + GET_RHAND(pGroup)->UpdateFrame(); + GET_RHAND(pGroup)->Calc(); + + if (i == 1 && !lbl_804BF9F8) { + break; + } + + GET_BODY(pGroup)->Entry(); + GET_FACE(pGroup)->Entry(); + GET_LHAND(pGroup)->Entry(); + GET_RHAND(pGroup)->Entry(); + } +} + +/** + * @brief Unknown stub + */ +void RPBowBackgroundNpcManager::fn_8034DD14() { + ; +} + +/** + * @brief Unknown stub + */ +void RPBowBackgroundNpcManager::fn_8034DD0C() { + ; +} + +/** + * @brief Unknown stub + */ +void RPBowBackgroundNpcManager::fn_8034DD08() { + ; +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp b/src/Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp new file mode 100644 index 00000000..2cb12a4a --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowBallReturnRack.cpp @@ -0,0 +1,276 @@ +#include +#include + +namespace Bowling { + +// Extern Functions +int fn_801C3490(int arg0, float arg1, void* pArg2); +u32 fn_801C389C(RPGrpModel* pModel, int arg1, int arg2); +void fn_801C37EC(RPGrpModel* pModel, int arg1, int arg2, void* pColor); + +/** + * @brief Initializes physics constants + * + * @param index Rack index + */ +void RPBowBallReturnRack::InitBallReturnRack(s32 index) { + mRackIndex = index; + + gBallReturnRackConstants.mPositionOffsets[0] = nw4r::math::VEC3( -25.0f, 3.5f, 33.3f ); + gBallReturnRackConstants.mPositionOffsets[1] = nw4r::math::VEC3( 8.8f, 3.5f, 33.3f ); + gBallReturnRackConstants.mPositionOffsets[2] = nw4r::math::VEC3( -58.5f, 3.5f, 33.3f ); + gBallReturnRackConstants.mPositionOffsets[3] = nw4r::math::VEC3( 42.4f, 3.5f, 33.3f ); + + gBallReturnRackConstants.mHeightLimit = 11.700001f; + gBallReturnRackConstants.mRepulsionThreshold = 1.075f; + gBallReturnRackConstants.mGravity = 0.0012f; +} + +/** + * @brief Initializes the resources associated with a ball slot + * + * @param index Rack index + * @param pRealModel Graphical model of the ball + * @param pReflectionModel Reflection model of the ball + * @param slotIndex Ball slot index mapping + */ +void RPBowBallReturnRack::InitBallSlotResources(s32 index, RPGrpModel* pRealModel, RPGrpModel* pReflectionModel, s32 slotIndex) { + mModels[index + 1].pRealModel = pRealModel; + mModels[index + 1].pReflectionModel = pReflectionModel; + + mSlotIndices[index] = slotIndex; +} + +/** + * @brief Sets up the graphical models for all of the NPC balls + */ +void RPBowBallReturnRack::ResetRackBallStates() { + BallReturnBall* pBall; + BallReturnRackConstants* pConstants = &gBallReturnRackConstants; + + pBall = mBalls; + for (int i = 0; i < 4; i++, pBall++) { + memset(pBall, 0, sizeof(BallReturnBall)); + + pBall->mIsOnRack = true; + + pBall->mPos.z = pConstants->mHeightLimit - (2.0f * ((float)(i + 1) * pConstants->mRepulsionThreshold)); + } +} + +/** + * @brief Selects an available ball from the rack for an NPC to use on their turn + * + * @return The index of the selected ball, or -1 if no balls are available + */ +int RPBowBallReturnRack::SelectBallForNPC() { + int indices[4]; + indices[0] = 0; + indices[1] = 1; + indices[2] = 2; + indices[3] = 3; + + for (int i = 0; i < 3; i++) { + for (int j = i + 1; j < 4; j++) { + if (mBalls[indices[i]].mPos.z < mBalls[indices[j]].mPos.z) { + int temp = indices[i]; + indices[i] = indices[j]; + indices[j] = temp; + } + } + } + + u32 randVal = (u32)(RPUtlRandom::getF32() * 3.0f); + int result = indices[randVal]; + + if (mBalls[result].mClaimedByNPC != 0 || mBalls[result].mIsOnRack == 0) { + result = -1; + } + + int* pIndex = indices; + int i = 0; + + while (i < 4 && result == -1) { + if (mBalls[*pIndex].mClaimedByNPC == 0 && mBalls[*pIndex].mIsOnRack != 0) { + result = indices[i]; + break; + } + pIndex++; + i++; + } + + if (result != -1) { + mBalls[result].mClaimedByNPC = 1; + return result; + } + return -1; +} + +/** + * @brief Removes the ball from rack physics calculations and rendering + * + * @param index Ball index + */ +void RPBowBallReturnRack::RemoveBallFromRack(s32 index) { + mBalls[index].mIsOnRack = 0; +} + +/** + * @brief Tests whether a specific ball slot currently has a ball resting on the rack + * + * @param index Ball index + * @return Non-zero if the ball is resting on the rack, 0 otherwise + */ +u8 RPBowBallReturnRack::IsBallOnRack(s32 index) { + return mBalls[index].mIsOnRack; +} + +/** + * @brief Spawns or resets a ball at the beginning of the return rack track + * + * @param index Ball index + */ +void RPBowBallReturnRack::SpawnBallOnRack(s32 index) { + mBalls[index].mPos.z = 0.0f; + mBalls[index].mClaimedByNPC = 0; + mBalls[index].mIsOnRack = 1; + mBalls[index].mAngle = 0.0f; +} + +/** + * @brief Removes an NPC's reservation of a ball + * + * @param index Ball index + */ +void RPBowBallReturnRack::ReleaseBallFromNPC(s32 index) { + mBalls[index].mClaimedByNPC = 0; +} + +/** + * @brief Retrieves the default slot index mapping for the rack + * + * @param index Ball index + * @return Default slot index mapping + */ +s32 RPBowBallReturnRack::GetBallSlotIndex(s32 index) { + return mSlotIndices[index]; +} + +/** + * @brief Main update function for the bowling scene entities + * + * @param index Rack index + */ +void RPBowBallReturnRack::UpdateBallReturnRack(s32 index) { + BallReturnBall* pBall; + RPGrpModelPair* pModelPair; + BallReturnRackConstants* pConstants = &gBallReturnRackConstants; + + // Part 1: Calculate repulsive forces between entities + for (int i = 0; i < 4; i++) { + mBalls[i].mRepulsionForce = 0.0f; + } + + for (int i = 0; i < 3; i++) { + if (!mBalls[i].mIsOnRack) continue; + + for (int j = i + 1; j < 4; j++) { + if (!mBalls[j].mIsOnRack) continue; + + f32 distI = mBalls[i].mPos.z; + f32 distJ = mBalls[j].mPos.z; + f32 distDiff = __fabs(distI - distJ); + + if (distDiff < pConstants->mRepulsionThreshold * 2.0f) { + f32 force = (pConstants->mRepulsionThreshold * 2.0f) - distDiff; + if (distI < distJ) { + mBalls[i].mRepulsionForce += -force; + mBalls[i].mSpeed = 0.0f; + } else { + mBalls[j].mRepulsionForce += -force; + mBalls[j].mSpeed = 0.0f; + } + } + } + } + + // Part 2: Update physics and models for each entity + pModelPair = &mModels[0]; + pBall = mBalls; + + for (int i = 0; i < 4; i++, pModelPair++, pBall++) { + if (!pBall->mIsOnRack) continue; + + f32 oldZ = pBall->mPos.z; + pBall->mSpeed += pConstants->mGravity; + pBall->mPos.z += pBall->mSpeed + pBall->mRepulsionForce; + + if (pBall->mPos.z > pConstants->mHeightLimit) { + pBall->mPos.z = pConstants->mHeightLimit; + pBall->mSpeed = 0.0f; + } + + f32 limit = 6.28318f * pConstants->mRepulsionThreshold; + f32 diff = pBall->mPos.z - oldZ; + f32 delta = diff / limit; + + pBall->mAngle += 6.28318f * delta; + + nw4r::math::VEC3 worldPos = pBall->mPos + pConstants->mPositionOffsets[mRackIndex]; + + nw4r::math::MTX34 ballMtx, rotMtx; + MTX34Identity(&ballMtx); + MTX34Trans(&ballMtx, &worldPos, &ballMtx); + + nw4r::math::MTX34RotXYZFIdx(&rotMtx, 40.743664f * pBall->mAngle, 0.0f, 0.0f); + PSMTXConcat(ballMtx, rotMtx, ballMtx); + + nw4r::g3d::ScnObj* pRealScnObj = pModelPair[1].pRealModel->GetScnObj(); + if (pRealScnObj != NULL) { + pRealScnObj->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &ballMtx); + } + + pModelPair[1].pRealModel->UpdateFrame(); + pModelPair[1].pRealModel->Calc(); + + if (fn_801C3490(index, pConstants->mRepulsionThreshold, &worldPos) != 0) { + u32 colorVal = fn_801C389C(pModelPair[1].pRealModel, 0, 0); + + GXColor color; + GXColor temp; + temp.r = colorVal >> 24; + temp.g = colorVal >> 16; + temp.b = colorVal >> 8; + temp.a = 255; + color = temp; + + fn_801C37EC(pModelPair[1].pRealModel, 0, 0, &color); + pModelPair[1].pRealModel->Entry(); + } + + nw4r::math::MTX34 reflectionMtx = ballMtx; + reflectionMtx.m[1][0] *= -1.0f; + reflectionMtx.m[1][1] *= -1.0f; + reflectionMtx.m[1][2] *= -1.0f; + reflectionMtx.m[1][3] *= -1.0f; + + nw4r::g3d::ScnObj* pReflScnObj = pModelPair[1].pReflectionModel->GetScnObj(); + if (pReflScnObj != NULL) { + pReflScnObj->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &reflectionMtx); + } + + pModelPair[1].pReflectionModel->UpdateFrame(); + pModelPair[1].pReflectionModel->Calc(); + + nw4r::math::VEC3 reflPosFinal; + reflPosFinal.x = reflectionMtx.m[0][3]; + reflPosFinal.y = reflectionMtx.m[1][3]; + reflPosFinal.z = reflectionMtx.m[2][3]; + + if (fn_801C3490(index, pConstants->mRepulsionThreshold, &reflPosFinal) != 0) { + pModelPair[1].pReflectionModel->Entry(); + } + } +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp b/src/Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp new file mode 100644 index 00000000..c54a92b1 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowGlobalLaneManager.cpp @@ -0,0 +1,227 @@ +#include + +namespace Bowling { + +/** + * @brief Pin target offsets + * @details Controls where the triangle of pins is set up. + */ +float gLaneXOffsets[8] = { + 0, + -16.1, + 17.6, + -33.75, + 33.6, + -49.85, + 51.15, + 0 +}; + +// Extern Functions +void ResetPinSetterState(LaneContext* pLane, u8 arg); +void fn_80327330(LaneContext* pLane, PinStatus* pStatus); +nw4r::math::MTX34* fn_80316A48(SomeUnkManager0* pSomeMgr, void* pObj, int val); +void fn_8034EADC(void* pArrEntry, int validCount, nw4r::math::MTX34* pResultMtx, nw4r::math::MTX34* pMtx, bool flag); +void fn_8034E974(void* pArrEntry, int validCount); +void fn_80327218(LaneContext* pLane); +void fn_803277B4(LaneContext* pLane); +void fn_803295D0(LaneBvhData* pBvhData, void* pArg1, void* pArg2); +void fn_80325154(LaneContext* pLane); + +/** + * @brief Tests whether the ball's X position falls inside the hit-box radius of any lane boundary + * + * @param pBallXPos Ball's X position + * @param radius Hit-box radius + * @return True if the ball intersects with a lane boundary, false otherwise + */ +bool CheckBallLaneIntersection(float* pBallXPos, float radius) { + for (int i = 0; i < 7; i++) { + if (*pBallXPos > gLaneXOffsets[i] - radius && *pBallXPos < radius + gLaneXOffsets[i]) { + return true; + } + } + return false; +} + +/** + * @brief Initializes the context state and logic for all 7 lanes + */ +void RPBowGlobalLaneManager::InitializeBallManagerLanes() { + for (int i = 0; i < 7; i++) { + fn_803277B4(pLanes[i]); + } +} + +/** + * @brief Submits parameters to setup secondary components attached to each lane and flags the manager as initialized + * + * @param pArg1 First setup parameter + * @param pArg2 Second setup parameter + */ +void RPBowGlobalLaneManager::SetupBallManagerLaneObjects(void* pArg1, void* pArg2) { + for (int i = 0; i < 7; i++) { + fn_803295D0(pLanes[i]->pLaneBvhData, pArg1, pArg2); + } + isInitialized = 1; +} + +/** + * @brief Resets the pin layout mask to a fresh set of 10 standing pins for all 7 lanes + */ +void RPBowGlobalLaneManager::ResetLanePinsAndAnimations() { + for (int i = 0; i < 7; i++) { + LaneContext* pLane = pLanes[i]; + PinStatus status; + status.pinBits[3] = -1; + status.pinBits[2] = -1; + status.pinBits[1] = -1; + status.pinBits[0] = -1; + status.pinCount = 10; + + fn_80327330(pLane, &status); + ResetPinSetterState(pLanes[i], 0); + } + field_0x21 = 0; +} + +/** + * @brief Pushes target state updates to all lanes + * + * @param value Target state value + */ +void RPBowGlobalLaneManager::SetLaneUnknownState(int value) { + for (int i = 0; i < 7; i++) { + pLanes[i]->laneStateTarget = value; + } +} + +/** + * @brief Ensures lane position offsets are correctly pushed to memory + * @details Computes ball physics on NPC lanes, and skips computing it on the player lane unless conditions dictate otherwise. + */ +void RPBowGlobalLaneManager::UpdateBallsPhysics() { + for (int i = 0; i < 7; i++) { + pLanes[i]->laneXOffset = gLaneXOffsets[i]; + if (i != 0 || field_0x21 == 0) { + fn_80327218(pLanes[i]); + } + } +} + +/** + * @brief Executes a sub-tick physics/state update on the player lane and all 6 NPC lanes + */ +void RPBowGlobalLaneManager::TickNpcLanes() { + for (int i = 0; i < 7; i++) { + fn_80325154(pLanes[i]); + } +} + +/** + * @brief Iterates the 7 lane item arrays to synthesize their 3D world space transforms and registers them back into the game engine's scene + * + * @param val Unknown integer value + * @param pObj Pointer to an object + * @param pSomeMgr Manager object + * @param isPlayerTurn Indicates if it is currently the player's turn + */ +void RPBowGlobalLaneManager::UpdateLaneItems(int val, void* pObj, SomeUnkManager0* pSomeMgr, bool isPlayerTurn) { + if (isInitialized == 0) return; + + nw4r::math::MTX34* pResultMtx = fn_80316A48(pSomeMgr, pObj, val); + + for (int i = 0; i < 7; i++) { + void* pArrEntry = pSomeMgr->arr[i]; + int validCount = 0; + + for (int j = 0; j < 10; j++) { + LaneContext* pLane = pLanes[i]; + int limit = pLane->pinCount; + u8 isValid; + + if (j >= limit) { + isValid = 0; + } else { + PinPhysicsBody* pBody = pLane->pPinManager->pPinBodies[j]; + isValid = pBody->isActive; + } + + if (isValid != 0) { + nw4r::math::MTX34 mtx; + nw4r::math::MTX34* pMtx; + + if (j >= limit) { + nw4r::math::MTX34 mtxTemp; + MTX34Identity(&mtxTemp); + mtx = mtxTemp; + pMtx = &mtx; + } else { + PinPhysicsBody* pBody = pLane->pPinManager->pPinBodies[j]; + pMtx = &mtx; + + f32 t23 = pBody->position.z; + f32 t22 = pBody->basisZ.z; + f32 t21 = pBody->basisZ.y; + f32 t20 = pBody->basisZ.x; + f32 t13 = pBody->position.y; + f32 t12 = pBody->basisY.z; + f32 t11 = pBody->basisY.y; + f32 t10 = pBody->basisY.x; + f32 t03 = pBody->position.x; + f32 t02 = pBody->basisX.z; + f32 t01 = pBody->basisX.y; + // f32 t00 = pBody->basisX.x; + + mtx._00 = pBody->basisX.x; + mtx._01 = t01; + mtx._02 = t02; + mtx._03 = t03; + mtx._10 = t10; + mtx._11 = t11; + mtx._12 = t12; + mtx._13 = t13; + mtx._20 = t20; + mtx._21 = t21; + mtx._22 = t22; + mtx._23 = t23; + } + + bool flag = false; + if (i == 0 && isPlayerTurn != 0) { + flag = true; + } + + pLanes[i]->VF_0x14(); + + fn_8034EADC(pArrEntry, validCount, pResultMtx, pMtx, flag); + validCount++; + } + } + fn_8034E974(pArrEntry, validCount); + } +} + +/** + * @brief Applies physics matrix translations onto the game's ball models + * @details Also artificially moves the ball out of view bounds (y = 9999.0f) if it falls completely below the floor bounds. + * + * @param pBallMgr Scene object manager for balls + */ +void RPBowGlobalLaneManager::UpdateBallsMdl(SceneObjectManager* pBallMgr) { + for (int i = 0; i < 7; i++) { + LaneContext* pLane = pLanes[i]; + RPBowActiveBall* pBall = pBallMgr->entities.balls[i]; + + nw4r::math::MTX34 mtx = pLane->throwContext.ballMtx; + if (mtx._23 < -210.0f) { + mtx._23 = 9999.0f; + } + + float field_110 = gBowlingPhysicsData.field_110; + pBall->mtx = mtx; + pBall->field_0x74 = field_110; + } +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowManagerContext.cpp b/src/Pack/RPSports/RPBowScene/RPBowManagerContext.cpp new file mode 100644 index 00000000..02bd481d --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowManagerContext.cpp @@ -0,0 +1,107 @@ +#include +#include + +namespace Bowling { + +struct WeightedLanes { + u8 data[15]; +}; + +static const WeightedLanes sTargetLaneWeights = {{ + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x02, + 0x02, 0x03, 0x03, 0x04, 0x05 +}}; + +/** + * @brief Initializes the manager context and its sub-managers + */ +void RPBowManagerContext::Initialize() { + for (int i = 0; i < 6; i++) { + mpManagers[i] = new RPBowNpcManager(); + mpManagers[i]->InitAudioActors(i); + } + mIsEnabled = 0; +} + +/** + * @brief Links NPC lanes to ball returns and balls + * + * @param pLaneManager Global lane manager instance + * @param pSceneObjectManager Scene object manager instance + */ +void RPBowManagerContext::LinkNpcLanes(RPBowGlobalLaneManager* pLaneManager, SceneObjectManager* pSceneObjectManager) { + for (int i = 0; i < 6; i++) { + const int sBallReturnMapping[] = { 0, 1, 0, 3, 2, 3 }; + + mpManagers[i]->Setup( + pLaneManager->pLanes[i + 1], + pSceneObjectManager->entities.npcs[i * 3 + 0], + pSceneObjectManager->entities.npcs[i * 3 + 1], + pSceneObjectManager->entities.npcs[i * 3 + 2], + i, + pSceneObjectManager->entities.ballReturns[sBallReturnMapping[i]], + pSceneObjectManager->entities.balls[i + 1] + ); + } +} + +/** + * @brief Sets the state flag for all NPC managers + * + * @param flag Status value applied to each NPC manager + */ +void RPBowManagerContext::SetNpcStateFlags(u8 flag) { + for (int i = 0; i < 6; i++) { + mpManagers[i]->SetStateFlag(flag); + } +} + +/** + * @brief Updates the six NPC bowling lanes and starts a new NPC turn if permitted + * + * @details Lanes closer to the player are heavily preferred when a new NPC is activated. + * A maximum of 2 NPCs are allowed to be active at once. New NPCs have a 1-in-180 chance to start per frame. + */ +void RPBowManagerContext::UpdateNpcs() { + int activeCount = 0; + + for (int i = 0; i < 6; i++) { + mpManagers[i]->Update(); + + if (mpManagers[i]->IsLaneIdle() == 0) { + activeCount++; + } + } + + if (activeCount >= 2) { + return; + } + + int targetLane = -1; + + if ((RPUtlRandom::getU32() % 180) == 0) { + WeightedLanes weightedLanes = sTargetLaneWeights; + u32 idx = (u32)(RPUtlRandom::getF32() * 15.0f); + targetLane = weightedLanes.data[idx]; + } + + if (targetLane != -1) { + if (mpManagers[targetLane]->IsLaneIdle() != 0) { + mpManagers[targetLane]->ActivateNpcTurn(); + } + } +} + +/** + * @brief Prints debug information for all NPC managers + */ +void RPBowManagerContext::DebugPrintStates() { + if (mIsEnabled != 0) { + for (int i = 0; i < 6; i++) { + mpManagers[i]->DebugPrintNpcState(); + } + } +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp b/src/Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp new file mode 100644 index 00000000..5337a8c9 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowMotionBlur.cpp @@ -0,0 +1,110 @@ +#include + +namespace Bowling { + +// Appears to check frustum culling +extern bool fn_801C3490(void* pCullingCtx, const nw4r::math::VEC3* pos, f32 radius); + +/** + * @brief Destructor + */ +RPBowMotionBlur::~RPBowMotionBlur() {} + +/** + * @brief Sets the models used for the motion blur effect + * + * @param pReal1 Real model 1 + * @param pReal2 Real model 2 + * @param pReal3 Real model 3 + * @param pRefl1 Reflection model 1 + * @param pRefl2 Reflection model 2 + * @param pRefl3 Reflection model 3 + */ +void RPBowMotionBlur::SetBlurModels(RPGrpModel* pReal1, RPGrpModel* pReal2, RPGrpModel* pReal3, RPGrpModel* pRefl1, RPGrpModel* pRefl2, RPGrpModel* pRefl3) { + models[0].pRealModel = pReal1; + models[0].pReflectionModel = pRefl1; + models[1].pRealModel = pReal2; + models[1].pReflectionModel = pRefl2; + models[2].pRealModel = pReal3; + models[2].pReflectionModel = pRefl3; +} + +/** + * @brief Deactivates the motion blur effect + */ +void RPBowMotionBlur::DeactivateBlur() { + isActive = false; +} + +/** + * @brief Updates the transform matrices for the motion blur + * + * @param pBaseMtx Base transform matrix + * @param blurSpeed Speed of the blur effect + */ +void RPBowMotionBlur::UpdateBlurTransform(const nw4r::math::MTX34* pBaseMtx, f32 blurSpeed) { + if (blurSpeed > 0.001f) { + isActive = true; + } else { + isActive = false; + return; + } + + f32 stretchFactor = (blurSpeed * 2.0f) / 5.267f; + + blurMtxs[2] = *pBaseMtx; + blurMtxs[1] = *pBaseMtx; + blurMtxs[0] = *pBaseMtx; + + blurMtxs[0]._03 -= pBaseMtx->_00 * blurSpeed; + blurMtxs[0]._13 -= pBaseMtx->_10 * blurSpeed; + blurMtxs[0]._23 -= pBaseMtx->_20 * blurSpeed; + + blurMtxs[2]._03 += pBaseMtx->_00 * blurSpeed; + blurMtxs[2]._13 += pBaseMtx->_10 * blurSpeed; + blurMtxs[2]._23 += pBaseMtx->_20 * blurSpeed; + + blurMtxs[1]._00 *= stretchFactor; + blurMtxs[1]._10 *= stretchFactor; + blurMtxs[1]._20 *= stretchFactor; + + speed = blurSpeed; +} + +/** + * @brief Renders the motion blur models + * + * @param pCullingCtx Frustum culling context + */ +void RPBowMotionBlur::DrawBlur(void* pCullingCtx) { + if (!isActive) { + return; + } + + nw4r::math::VEC3 pos(blurMtxs[1]._03, blurMtxs[1]._13, blurMtxs[1]._23); + if (!fn_801C3490(pCullingCtx, &pos, speed * 2.0f)) { + return; + } + + for (int i = 0; i < 3; i++) { + if (models[i].pRealModel->GetScnObj() != NULL) { + models[i].pRealModel->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &blurMtxs[i]); + } + models[i].pRealModel->Calc(); + models[i].pRealModel->Entry(); + + nw4r::math::MTX34 reflectionMtx = blurMtxs[i]; + reflectionMtx._10 *= -1.0f; + reflectionMtx._11 *= -1.0f; + reflectionMtx._12 *= -1.0f; + reflectionMtx._13 *= -1.0f; + + if (models[i].pReflectionModel->GetScnObj() != NULL) { + models[i].pReflectionModel->GetScnObj()->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &reflectionMtx); + } + models[i].pReflectionModel->Calc(); + models[i].pReflectionModel->Entry(); + } +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowNpcManager.cpp b/src/Pack/RPSports/RPBowScene/RPBowNpcManager.cpp new file mode 100644 index 00000000..417dbcb3 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowNpcManager.cpp @@ -0,0 +1,115 @@ +#include + +extern "C" int rand(); + +namespace Bowling { + +// Extern functions: +void fn_80334270(NpcContext* pContext); +void InitNpcContext(NpcContext* pContext, int laneIdx, int npcIdx); + +/** + * @brief Initializes audio-related structures for the manager + * @details Allocates memory for sound actors and configures 3D audio settings. + * + * @param laneIdx Index of the lane + */ +// void RPBowNpcManager::InitAudioActors(int laneIdx) { +// ; +// } + +/** + * @brief Configures internal pointers and prepares initial contexts + * + * @param pLaneContext Pointer to the lane physics and gameplay context + * @param pNpc0 Pointer to the first NPC object + * @param pNpc1 Pointer to the second NPC object + * @param pNpc2 Pointer to the third NPC object + * @param laneIdx Lane index + * @param pReturnRack Rack containing usable balls + * @param pAudioStruct Pointer to the audio structure + */ +void RPBowNpcManager::Setup(LaneContext* pLaneContext, NpcContext* pNpc0, NpcContext* pNpc1, NpcContext* pNpc2, int laneIdx, RPBowBallReturnRack* pReturnRack, void* pAudioStruct) { + mpNpcs[0] = pNpc0; + mpNpcs[1] = pNpc1; + mpNpcs[2] = pNpc2; + + mpLaneContext = pLaneContext; + mLaneIdx = laneIdx; + mpReturnRack = pReturnRack; + mpSomeAudioStruct = pAudioStruct; + + memset(&mStateId, 0, 12); + + for (int i = 0; i < 3; i++) { + fn_80334270(mpNpcs[i]); + InitNpcContext(mpNpcs[i], mLaneIdx, i); + } + + mpCurrentNpc = mpNpcs[0]; + mCurrentNpcIdx = 0; +} + +/** + * @brief Tests whether the lane is idle + * + * @return 1 if idle, 0 otherwise + */ +int RPBowNpcManager::IsLaneIdle() { + return mStateId == 0; +} + +/** + * @brief Sets the NPC state flag + * + * @param flag Status value applied + */ +void RPBowNpcManager::SetStateFlag(u8 flag) { + mDisableResultSfx = flag; +} + +/** + * @brief Activates a new NPC turn for the lane + * @details Cycles to the next NPC in the lane (0->1->2->0). + */ +void RPBowNpcManager::ActivateNpcTurn() { + memset(&mStateId, 0, 12); + mStateId = 1; + mStateTimer = -1; + mpLaneContext->throwContext.throwState = 0; + + mpCurrentNpc = mpNpcs[mCurrentNpcIdx]; + + int nextIdx = mCurrentNpcIdx; // TODO: remove? + mCurrentNpcIdx = mCurrentNpcIdx + 1; + if (mCurrentNpcIdx == 3) { + mCurrentNpcIdx = 0; + } +} + +// States for RPBowNpcManager::Update() +enum NpcBowlingStates { + NPC_BOWLING_STATE_IDLE = 0, // Inactive, ball hidden off-screen + NPC_BOWLING_STATE_WAIT_PREPARE_LINE = 1, // Walk to approach area, pick up ball + NPC_BOWLING_STATE_PREPARE = 2, // Idle at line, RNG delay before bowling + NPC_BOWLING_STATE_RUN = 3, // Swing and release ball + NPC_BOWLING_STATE_SEE = 4, // Watch ball roll, handle result SFX + NPC_BOWLING_STATE_BACK = 5, // Walk to ball return or back to seat +}; + +/** + * @brief Updates the manager's state machine + */ +// void RPBowNpcManager::Update() { +// ; +// } + +/** + * @brief Prints debug information for this NPC manager + * @details Example string formats: 'NPC[0(1st)] PREPARE phy:0' + */ +// void RPBowNpcManager::DebugPrintNpcState() { +// ; +// } + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowPinSetter.cpp b/src/Pack/RPSports/RPBowScene/RPBowPinSetter.cpp new file mode 100644 index 00000000..ed9fca21 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowPinSetter.cpp @@ -0,0 +1,166 @@ +#include + +namespace Bowling { + +#define SWEEPER_BALL_Z_TRIGGER -192.0f +#define SWEEPER_FRAME_LIFT_PINS 0x73 +#define SWEEPER_FRAME_START_SWEEP 0xAF +#define SWEEPER_FRAME_PLACE_PINS 0xF5 +#define SWEEPER_FRAME_END 0x1B8 + +/** + * @brief Resets the pin setter state + * + * @param pContext Lane context + * @param isNewRack Flag indicating if this is a new rack + */ +void ResetPinSetterState(LaneContext* pContext, u8 isNewRack) { + memset(&pContext->setterAnm, 0, 0x10); + pContext->setterAnm.isNewRack = isNewRack; + + PinSetter* pSetter = pContext->pPinSetter; + pSetter->sequencePhase = 0; + pSetter->primaryState = 0; + pSetter->frameTimer = 0.0f; +} + +/** + * @brief Triggers the pin setter animation sequence + * + * @param pContext Lane context + * @param spawnNewRack Flag indicating if a new rack should be spawned + */ +void TriggerPinSetter(LaneContext* pContext, int spawnNewRack) { + if (pContext->setterAnm.sequenceFrameCount == 0) { + pContext->setterAnm.sequenceFrameCount = 1; + if (spawnNewRack != 0) { + pContext->setterAnm.isNewRack = 1; + } + } +} + +/** + * @brief Updates the pin setter state and animations + * + * @param pContext Lane context + * @return 1 on success, otherwise 0 + */ +int UpdatePinSetter(LaneContext* pContext) { + int currentAnimMode = pContext->throwContext.animationMode; + pContext->setterAnm.animOffsetZ = 0.0f; + pContext->setterAnm.animRotationY = -180.5f; + + if (currentAnimMode == 2) { + return 1; + } + + int sequenceFrame = pContext->setterAnm.sequenceFrameCount; + if (sequenceFrame == 0) { + for (int i = 0; i < pContext->pinCount; i++) { + pContext->pPinManager->pPinBodies[i]->mode_0x28C = 0; + } + + float z = pContext->throwContext.ballMtx._23; + float y = pContext->throwContext.ballMtx._13; + float x = pContext->throwContext.ballMtx._03; + nw4r::math::VEC3 ballPos(x, y, z); + + if (ballPos.z < SWEEPER_BALL_Z_TRIGGER) { + pContext->pPinSetter->sequencePhase = 1; + } + return 1; + } + + if (currentAnimMode != 0) { + return 1; + } + + if (sequenceFrame == 1 && pContext->setterAnm.isNewRack == 0) { + pContext->pPinSetter->sequencePhase = 2; + } + + if (pContext->setterAnm.sequenceFrameCount == SWEEPER_FRAME_LIFT_PINS && pContext->setterAnm.isNewRack == 0) { + for (int i = 0; i < pContext->pinCount; i++) { + if (pContext->pPinManager->pPinBodies[i]->unkFlag_0x250 == 0) { + pContext->pPinManager->pPinBodies[i]->mode_0x28C = 1; + } + } + } + + if (pContext->setterAnm.sequenceFrameCount == SWEEPER_FRAME_START_SWEEP) { + pContext->pPinSetter->sequencePhase = 3; + } + + if (pContext->setterAnm.sequenceFrameCount > SWEEPER_FRAME_START_SWEEP) { + pContext->setterAnm.animOffsetZ = 0.28f * ((float)pContext->setterAnm.sequenceFrameCount - (float)SWEEPER_FRAME_START_SWEEP); + } + + if (pContext->setterAnm.sequenceFrameCount == SWEEPER_FRAME_PLACE_PINS && pContext->setterAnm.isNewRack == 0) { + for (int i = 0; i < pContext->pinCount; i++) { + if (pContext->pPinManager->pPinBodies[i]->unkFlag_0x250 == 0) { + pContext->pPinManager->pPinBodies[i]->mode_0x28C = 3; + } + } + } + + if (pContext->setterAnm.sequenceFrameCount == SWEEPER_FRAME_PLACE_PINS && pContext->setterAnm.isNewRack != 0) { + for (int i = 0; i < pContext->pinCount; i++) { + pContext->pPinManager->pPinBodies[i]->VF_0x0C(); + + nw4r::math::VEC3 basisZ; + nw4r::math::VEC3 basisY; + nw4r::math::VEC3 basisX; + + pContext->pPinManager->pPinBodies[i]->isActive = 1; + + PinPhysicsBody* pBody = pContext->pPinManager->pPinBodies[i]; + nw4r::math::VEC3 pos = pBody->field_0xFC; + pos.y = 8.0f; + + pBody->position = pos; + + basisX.x = 1.0f; + basisX.y = 0.0f; + basisX.z = 0.0f; + pBody->basisX = basisX; + + basisY.x = 0.0f; + basisY.y = 1.0f; + basisY.z = 0.0f; + pBody->basisY = basisY; + + basisZ.x = 0.0f; + basisZ.y = 0.0f; + basisZ.z = 1.0f; + pBody->basisZ = basisZ; + + pContext->pPinManager->pPinBodies[i]->mode_0x28C = 3; + } + } + + pContext->setterAnm.sequenceFrameCount++; + return 1; +} + +/** + * @brief Tests whether the pin setter is currently active + * + * @param pContext Lane context + * @return 1 if active, 0 otherwise + */ +int IsPinSetterActive(LaneContext* pContext) { + int frame = pContext->setterAnm.sequenceFrameCount; + if (frame != 0 && frame < SWEEPER_FRAME_END) { + return 1; + } + return 0; +} + +/** + * @brief Unknown function (stubbed) + */ +void fn_803345F0(LaneContext* /* unused */) { + ; +} + +} // namespace Bowling diff --git a/src/Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp b/src/Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp new file mode 100644 index 00000000..2c59b085 --- /dev/null +++ b/src/Pack/RPSports/RPBowScene/RPBowTrajectoryGuide.cpp @@ -0,0 +1,134 @@ +#include + +namespace Bowling { + +/** + * @brief Updates the controller state bitmask + * + * @param pObj Unknown object data array + */ +void UpdateControllerState(u32* pObj) { + if (pObj[3] != 0) { + EGG::CoreController* pCtrl = EGG::CoreControllerMgr::instance()->getNthController(0); + + pObj[3] &= 0x100; + } +} + +/** + * @brief Destructor + */ +RPBowTrajectoryGuide::~RPBowTrajectoryGuide() {} + +/** + * @brief Sets the main directional indicator models for the trajectory guide + * + * @param pMainModel Primary guide model + * @param pUnkModel Secondary guide model + */ +void RPBowTrajectoryGuide::SetMainModels(RPGrpModel* pMainModel, RPGrpModel* pUnkModel) { + mpMainModel = pMainModel; + mpUnkModel = pUnkModel; +} + +/** + * @brief Assigns a dot model to a specific index in the guide path + * + * @param index Index of the dot model + * @param pDotModel Point model along the trajectory + */ +void RPBowTrajectoryGuide::SetDotModel(u32 index, RPGrpModel* pDotModel) { + mpDotModels[index] = pDotModel; +} + +/** + * @brief Initializes the trajectory guide state upon scene startup + */ +void RPBowTrajectoryGuide::Initialize() { + mActiveModelIndex = 0; + mIsVisible = 0; + mStartX = 0.0f; + mAngle = 0.0f; + unk_0x60 = 0; + mLimitWidth = 0.0f; + mLimitCenter = 0.0f; +} + +/** + * @brief Resets the trajectory guide state for a new shot + */ +void RPBowTrajectoryGuide::Reset() { + mActiveModelIndex = 0; + mIsVisible = 0; + mStartX = 0.0f; + mAngle = 0.0f; + unk_0x60 = 0; + mLimitWidth = 0.0f; + mLimitCenter = 0.0f; +} + +/** + * @brief Renders the trajectory guide + * @details Computes transforms and pushes both the main indicator (arrow) and + * the individual path dots to the renderer to visually represent the player's aim. + */ +void RPBowTrajectoryGuide::Draw() { + if (mIsVisible == 0) return; + + f32 cosAngle = std::cos(mAngle); + f32 nCosAngle = -cosAngle; + f32 sinAngle = std::sin(mAngle); + + nw4r::math::VEC3 vecB(sinAngle, 0.0f, nCosAngle); + nw4r::math::VEC3 vecA(0.0f, -1.0f, 0.0f); + nw4r::math::VEC3 vecCross; + nw4r::math::VEC3Cross(&vecCross, &vecB, &vecA); + + nw4r::math::MTX34 mtx( + 1.0f, 0.0f, 0.0f, mStartX, + 0.0f, 1.0f, 0.0f, vecB.y + 0.03f, + 0.0f, 0.0f, 1.0f, 20.0f + ); + + nw4r::math::VEC3 vecBase(mStartX, 0.0f, 20.0f); + + if (nw4r::g3d::ScnObj* pScnObj1 = (&mpMainModel)[mActiveModelIndex]->GetScnObj()) { + pScnObj1->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &mtx); + } + + (&mpMainModel)[mActiveModelIndex]->UpdateFrame(); + (&mpMainModel)[mActiveModelIndex]->Calc(); + (&mpMainModel)[mActiveModelIndex]->Entry(); + + nw4r::math::MTX34 mtx2( + vecCross.x, vecA.x, vecB.x, 0.0f, + vecCross.y, vecA.y, vecB.y, 0.0f, + vecCross.z, vecA.z, vecB.z, 0.0f + ); + + for (int i = 0; i < 16; i++) { + nw4r::math::VEC3 vecFinal = vecBase + ((vecB * 6.0f) * static_cast(i)); + + f32 diffX = vecFinal.x - mLimitCenter; + + if (diffX < -mLimitWidth || diffX > mLimitWidth) { + if (vecFinal.z < -6.0f) { + continue; + } + } + + mtx2._03 = vecFinal.x; + mtx2._13 = vecFinal.y + 0.03f; + mtx2._23 = vecFinal.z; + + if (nw4r::g3d::ScnObj* pScnObj2 = mpDotModels[i]->GetScnObj()) { + pScnObj2->SetMtx(nw4r::g3d::ScnObj::MTX_LOCAL, &mtx2); + } + + mpDotModels[i]->UpdateFrame(); + mpDotModels[i]->Calc(); + mpDotModels[i]->Entry(); + } +} + +} // namespace Bowling