From 2c46a69188697beb8dbdfedb1aee3fb2b3bdd143 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 17 Mar 2026 00:10:26 -0600 Subject: [PATCH] CMorphBall & link RMathUtils (#44) * Update tool versions * Initial CMorphBall * Cleanup CMorphBall, link RMathUtils * Rematch a couple symbols * Fix _01 DolphinCGraphics .sdata size regression --- config/GM8E01_00/symbols.txt | 197 +- config/GM8E01_01/symbols.txt | 14 +- config/GM8E01_48/splits.txt | 8 +- config/GM8E01_48/symbols.txt | 2 +- configure.py | 8 +- include/Collision/CCollidableSphere.hpp | 3 + include/Collision/CCollisionInfoList.hpp | 2 - include/Collision/CCollisionPrimitive.hpp | 1 + include/Collision/CMaterialList.hpp | 3 + include/Collision/CollisionUtil.hpp | 11 +- include/Kyoto/Graphics/CLight.hpp | 1 - include/Kyoto/Math/CMath.hpp | 19 +- include/Kyoto/Math/CQuaternion.hpp | 2 +- include/Kyoto/Particles/CElementGen.hpp | 3 +- include/Kyoto/Particles/CParticleElectric.hpp | 2 +- include/Kyoto/Particles/CParticleGen.hpp | 2 +- include/Kyoto/Particles/CParticleSwoosh.hpp | 2 +- include/Kyoto/TReservedAverage.hpp | 4 +- include/MetroidPrime/CActorLights.hpp | 10 +- include/MetroidPrime/CActorModelParticles.hpp | 2 +- include/MetroidPrime/CAxisAngle.hpp | 3 +- include/MetroidPrime/CModelData.hpp | 1 + include/MetroidPrime/CPhysicsActor.hpp | 1 + include/MetroidPrime/CStateManager.hpp | 10 +- include/MetroidPrime/Enemies/CMetroidBeta.hpp | 3 +- include/MetroidPrime/Player/CMorphBall.hpp | 122 +- .../MetroidPrime/Player/CMorphBallShadow.hpp | 15 +- include/MetroidPrime/Player/CPlayer.hpp | 14 +- include/rstl/construct.hpp | 14 +- include/rstl/reserved_vector.hpp | 10 +- include/rstl/vector.hpp | 2 +- src/Collision/CollisionUtil.cpp | 2 + src/Kyoto/Math/RMathUtils.cpp | 137 +- src/MetroidPrime/CAxisAngle.cpp | 22 +- src/MetroidPrime/CFluidPlaneCPU.cpp | 2 + src/MetroidPrime/CGameCollision.cpp | 4 +- src/MetroidPrime/CGameLight.cpp | 3 +- src/MetroidPrime/CStateManager.cpp | 4058 +++++++++-------- src/MetroidPrime/Player/CMorphBall.cpp | 2891 +++++++++++- src/MetroidPrime/Player/CPlayer.cpp | 9 + src/Weapons/CProjectileWeapon.cpp | 2 + src/WorldFormat/CWorldLight.cpp | 2 + 42 files changed, 5328 insertions(+), 2295 deletions(-) diff --git a/config/GM8E01_00/symbols.txt b/config/GM8E01_00/symbols.txt index 61f9a478..53e16766 100644 --- a/config/GM8E01_00/symbols.txt +++ b/config/GM8E01_00/symbols.txt @@ -706,7 +706,7 @@ SetInfraModel__9CAnimDataFRC21TLockedToken<6CModel>RC26TLockedToken<10CSkinRules SubstituteModelData__9CAnimDataFRC29TCachedToken<13CSkinnedModel> = .text:0x8002E09C; // type:function size:0xCC scope:global FreeCache__9CAnimDataFv = .text:0x8002E168; // type:function size:0x84 scope:global InitializeCache__9CAnimDataFv = .text:0x8002E1EC; // type:function size:0x154 scope:global -uninitialized_fill_n__4rstlFP13CInt32POINodeiRC13CInt32POINode = .text:0x8002E340; // type:function size:0xF0 scope:global +uninitialized_fill_n__4rstlFP13CInt32POINodeiRC13CInt32POINode = .text:0x8002E340; // type:function size:0xF0 scope:local DrawSkinnedModel__9CAnimDataCFRC13CSkinnedModelRC11CModelFlags = .text:0x8002E430; // type:function size:0x80 scope:global PoseSkinnedModel__9CAnimDataCFRC13CSkinnedModelRC17CPoseAsTransformsRCQ24rstl37optional_object<18CVertexMorphEffect>PCf = .text:0x8002E4B0; // type:function size:0x34 scope:global AdvanceParticles__9CAnimDataFRC12CTransform4ffRC9CVector3fR13CStateManager = .text:0x8002E4E4; // type:function size:0x3C scope:global @@ -724,8 +724,8 @@ __dt__14CCharacterInfoFv = .text:0x8002EEC4; // type:function size:0xE0 scope:gl __dt__Q24rstl220vector,Q24rstl17rmemory_allocator>,Q24rstl66basic_string,Q24rstl17rmemory_allocator>>>,Q24rstl17rmemory_allocator>Fv = .text:0x8002EFA4; // type:function size:0xC8 __dt__12CPASDatabaseFv = .text:0x8002F06C; // type:function size:0x54 scope:global __dt__Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>Fv = .text:0x8002F0C0; // type:function size:0x8C -destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator> = .text:0x8002F14C; // type:function size:0x50 -destroy<13CPASAnimState>__4rstlFP13CPASAnimState = .text:0x8002F19C; // type:function size:0x24 +destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator> = .text:0x8002F14C; // type:function size:0x50 scope:local +destroy<13CPASAnimState>__4rstlFP13CPASAnimState = .text:0x8002F19C; // type:function size:0x24 scope:local __rf__Q24rstl126const_pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>CFv = .text:0x8002F1C0; // type:function size:0xE8 scope:global fn_8002F2A8 = .text:0x8002F2A8; // type:function size:0xF4 __dt__Q214CCharacterInfo16CParticleResDataFv = .text:0x8002F39C; // type:function size:0x16C scope:global @@ -1023,11 +1023,11 @@ QueueMessage__13CStateManagerFiUif = .text:0x80043F2C; // type:function size:0x1 GetPlayer__13CStateManagerCFv = .text:0x80043F3C; // type:function size:0x8 scope:global SetBossParams__13CStateManagerF9TUniqueIdfUi = .text:0x80043F44; // type:function size:0x14 scope:global SetGameState__13CStateManagerFQ213CStateManager10EGameState = .text:0x80043F58; // type:function size:0xB0 scope:global -fn_80044008 = .text:0x80044008; // type:function size:0x28 +SetPendingOnScreenTex__13CStateManagerFUiRC9CVector2iRC9CVector2i = .text:0x80044008; // type:function size:0x28 SetSinglePathMaze__13CStateManagerFQ24rstl29single_ptr<15CSinglePathMaze> = .text:0x80044030; // type:function size:0x58 scope:global SinglePathMaze__13CStateManagerFv = .text:0x80044088; // type:function size:0x8 scope:global GetSinglePathMaze__13CStateManagerCFv = .text:0x80044090; // type:function size:0x8 scope:global -fn_80044098 = .text:0x80044098; // type:function size:0x3D8 +DoCollisionResponse__13CStateManagerFRC22CCollisionResponseDataRC14CRayCastResult9TUniqueIdRC11CWeaponModebb = .text:0x80044098; // type:function size:0x3D8 GetCharacterRenderMaskAndTarget__13CStateManagerFbRiRi = .text:0x80044470; // type:function size:0xF8 scope:global UpdateThermalVisor__13CStateManagerFv = .text:0x80044568; // type:function size:0x284 scope:global CanShowMapScreen__13CStateManagerFv = .text:0x800447EC; // type:function size:0x48 scope:global @@ -1058,14 +1058,14 @@ ReflectionDrawer__13CStateManagerFPvRC9CVector3f = .text:0x80045710; // type:fun CanCreateProjectile__13CStateManagerCF9TUniqueId11EWeaponTypei = .text:0x80045730; // type:function size:0x50 scope:global BuildDynamicLightListForWorld__13CStateManagerFv = .text:0x80045780; // type:function size:0x244 scope:global push_back__Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>FRC6CLight = .text:0x800459C4; // type:function size:0x7C scope:global -fn_80045A40 = .text:0x80045A40; // type:function size:0x28 +construct<6CLight>__4rstlFPvRC6CLight = .text:0x80045A40; // type:function size:0x28 scope:local __as__Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>FRCQ24rstl42vector<6CLight,Q24rstl17rmemory_allocator> = .text:0x80045A68; // type:function size:0xD4 scope:global -uninitialized_copy__4rstlFPC6CLightPC6CLightP6CLight = .text:0x80045B3C; // type:function size:0x64 scope:global +uninitialized_copy__4rstlFP6CLightP6CLightP6CLight = .text:0x80045B3C; // type:function size:0x64 scope:local DrawDebugStuff__13CStateManagerCFv = .text:0x80045BA0; // type:function size:0x4 scope:global RenderCamerasAndAreaLights__13CStateManagerCFv = .text:0x80045BA4; // type:function size:0x5C scope:global DrawE3DeathEffect__13CStateManagerCFv = .text:0x80045C00; // type:function size:0x164 scope:global DrawAdditionalFilters__13CStateManagerCFv = .text:0x80045D64; // type:function size:0xB8 scope:global -ResetViewAfterDraw__13CStateManagerCFRCQ29CGraphics9CViewportRC12CTransform4f = .text:0x80045E1C; // type:function size:0x160 scope:global +ResetViewAfterDraw__13CStateManagerCFRC9CViewportRC12CTransform4f = .text:0x80045E1C; // type:function size:0x160 scope:global DrawWorld__13CStateManagerCFv = .text:0x80045F7C; // type:function size:0xD90 scope:global GetAliveAreasEnd__6CWorldFv = .text:0x80046D0C; // type:function size:0xC scope:global SetupFogForArea3XRange__13CStateManagerCF7TAreaId = .text:0x80046D18; // type:function size:0x68 @@ -1123,13 +1123,13 @@ FrameBegin__13CStateManagerFUi = .text:0x8004B55C; // type:function size:0x3C sc InitializeState__13CStateManagerFUi7TAreaIdUi = .text:0x8004B598; // type:function size:0x490 scope:global CreateStandardGameObjects__13CStateManagerFv = .text:0x8004BA28; // type:function size:0x2B8 scope:global RemoveObject__13CStateManagerF9TUniqueId = .text:0x8004BCE0; // type:function size:0x1D0 scope:global -fn_8004BEB0 = .text:0x8004BEB0; // type:function size:0x94 +equal_range__Q24rstl175red_black_tree<9TEditorId,Q24rstl27pair<9TEditorId,9TUniqueId>,1,Q24rstl47select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>FRC9TEditorId = .text:0x8004BEB0; // type:function size:0x94 UpdateRoomAcoustics__13CStateManagerF7TAreaId = .text:0x8004BF44; // type:function size:0x188 scope:global SetCurrentAreaId__13CStateManagerF7TAreaId = .text:0x8004C0CC; // type:function size:0xC8 scope:global ClearGraveyard__13CStateManagerFv = .text:0x8004C194; // type:function size:0xD8 scope:global DeleteObjectRequest__13CStateManagerF9TUniqueId = .text:0x8004C26C; // type:function size:0x200 scope:global -fn_8004C46C = .text:0x8004C46C; // type:function size:0x28 -fn_8004C494 = .text:0x8004C494; // type:function size:0xE0 +push_back__Q24rstl72list,Q24rstl17rmemory_allocator>FRCQ24rstl30reserved_vector<9TUniqueId,32> = .text:0x8004C46C; // type:function size:0x28 +do_insert_before__Q24rstl72list,Q24rstl17rmemory_allocator>FPQ34rstl72list,Q24rstl17rmemory_allocator>4nodeRCQ24rstl30reserved_vector<9TUniqueId,32> = .text:0x8004C494; // type:function size:0xE0 ObjectById__13CStateManagerF9TUniqueId = .text:0x8004C574; // type:function size:0x30 scope:global GetObjectById__13CStateManagerCF9TUniqueId = .text:0x8004C5A4; // type:function size:0x30 scope:global AreaUnloaded__13CStateManagerF7TAreaId = .text:0x8004C5D4; // type:function size:0x4 scope:global @@ -1144,7 +1144,7 @@ CalculateObjectBounds__13CStateManagerFRC6CActor = .text:0x8004C920; // type:fun AddObject__13CStateManagerFR7CEntity = .text:0x8004CB14; // type:function size:0x1E0 scope:global AddObject__13CStateManagerFP7CEntity = .text:0x8004CCF4; // type:function size:0x28 scope:global HasWorld__13CStateManagerCFv = .text:0x8004CD1C; // type:function size:0x14 -RayCollideWorldInternal__13CStateManagerRC9CVector3fRC9CVector3fRC15CMaterialFilterRCQ24rstl49reserved_vector<9TUniqueId,1024>RC6CActor = .text:0x8004CD30; // type:function size:0x10C scope:global +RayCollideWorldInternal__13CStateManagerCFRC9CVector3fRC9CVector3fRC15CMaterialFilterRCQ24rstl32reserved_vector<9TUniqueId,1024>PC6CActor = .text:0x8004CD30; // type:function size:0x10C scope:global RayCollideWorld__13CStateManagerFRC9CVector3fRC9CVector3fRC15CMaterialFilterPC6CActor = .text:0x8004CE3C; // type:function size:0x130 scope:global RayCollideWorld__13CStateManagerCFRC9CVector3fRC9CVector3fRCQ24rstl32reserved_vector<9TUniqueId,1024>RC15CMaterialFilterPC6CActor = .text:0x8004CF6C; // type:function size:0x2C scope:global RayStaticIntersection__13CStateManagerCFRC9CVector3fRC9CVector3ffRC15CMaterialFilter = .text:0x8004CF98; // type:function size:0x2C scope:global @@ -1157,8 +1157,8 @@ __dt__22CStateManagerContainerFv = .text:0x8004D704; // type:function size:0x20C __dt__14CCameraManagerFv = .text:0x8004D910; // type:function size:0x1B4 scope:global __dt__18CFluidPlaneManagerFv = .text:0x8004DAC4; // type:function size:0xF8 scope:global __dt__13CEnvFxManagerFv = .text:0x8004DBBC; // type:function size:0x184 scope:global -fn_8004DD40 = .text:0x8004DD40; // type:function size:0x50 -fn_8004DD90 = .text:0x8004DD90; // type:function size:0x68 +__dt__Q24rstl39reserved_vector<17CEnvFxManagerGrid,64>Fv = .text:0x8004DD40; // type:function size:0x50 +clear__Q24rstl39reserved_vector<17CEnvFxManagerGrid,64>Fv = .text:0x8004DD90; // type:function size:0x68 fn_8004DDF8 = .text:0x8004DDF8; // type:function size:0x6C __dt__20CActorModelParticlesFv = .text:0x8004DE64; // type:function size:0xE8 scope:global __dt__Q24rstl55reserved_vectorFv = .text:0x8004DF4C; // type:function size:0x50 scope:global @@ -1167,10 +1167,10 @@ __dt__Q24rstl36reserved_vector<15CCameraBlurPass,9>Fv = .text:0x8004E044; // typ clear__Q24rstl36reserved_vector<15CCameraBlurPass,9>Fv = .text:0x8004E094; // type:function size:0xA0 scope:global __ct__13CStateManagerFRCQ24rstl26ncrc_ptr<14CScriptMailbox>RCQ24rstl25ncrc_ptr<13CMapWorldInfo>RCQ24rstl24ncrc_ptr<12CPlayerState>RCQ24rstl30ncrc_ptr<18CWorldTransManager>RCQ24rstl28ncrc_ptr<16CWorldLayerState> = .text:0x8004E134; // type:function size:0x11AC scope:global __ct__Q24rstl36reserved_vector<15CCameraBlurPass,9>FiRC15CCameraBlurPass = .text:0x8004F2E0; // type:function size:0x38 scope:global -uninitialized_fill_n__4rstlFP15CCameraBlurPassiRC15CCameraBlurPass = .text:0x8004F318; // type:function size:0xE8 scope:global +uninitialized_fill_n__4rstlFP15CCameraBlurPassiRC15CCameraBlurPass = .text:0x8004F318; // type:function size:0xE8 scope:local __cl__Q227@unnamed@CStateManager_cpp@11area_sorterCFPC9CGameAreaPC9CGameArea = .text:0x8004F400; // type:function size:0xEC scope:global -fn_8004F4EC = .text:0x8004F4EC; // type:function size:0x68 -fn_8004F554 = .text:0x8004F554; // type:function size:0x68 +free_node_and_sub_nodes__Q24rstl197red_black_tree<9TEditorId,Q24rstl38pair<9TEditorId,19SScriptObjectStream>,0,Q24rstl58select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>FPQ34rstl197red_black_tree<9TEditorId,Q24rstl38pair<9TEditorId,19SScriptObjectStream>,0,Q24rstl58select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>4node = .text:0x8004F4EC; // type:function size:0x68 +free_node_and_sub_nodes__Q24rstl175red_black_tree<9TEditorId,Q24rstl27pair<9TEditorId,9TUniqueId>,1,Q24rstl47select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>FPQ34rstl175red_black_tree<9TEditorId,Q24rstl27pair<9TEditorId,9TUniqueId>,1,Q24rstl47select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>4node = .text:0x8004F554; // type:function size:0x68 free_node_and_sub_nodes__Q24rstl382red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl66basic_string,Q24rstl17rmemory_allocator>,0,Q24rstl85identity,Q24rstl17rmemory_allocator>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>FPQ34rstl382red_black_tree,Q24rstl17rmemory_allocator>,Q24rstl66basic_string,Q24rstl17rmemory_allocator>,0,Q24rstl85identity,Q24rstl17rmemory_allocator>>,Q24rstl81less,Q24rstl17rmemory_allocator>>,Q24rstl17rmemory_allocator>4node = .text:0x8004F5BC; // type:function size:0x80 __nw__36TOneStatic<22CStateManagerContainer>FUlPCcPCc = .text:0x8004F63C; // type:function size:0x30 scope:global __dl__36TOneStatic<22CStateManagerContainer>FPv = .text:0x8004F66C; // type:function size:0x2C scope:global @@ -1182,18 +1182,18 @@ GetAllocSpace__20TOneStatic<7CPlayer>Fv = .text:0x8004F724; // type:function siz Max__5CMathFRCfRCf = .text:0x8004F730; // type:function size:0x18 scope:global sort__4rstlFPPC9CGameAreaPPC9CGameAreaQ227@unnamed@CStateManager_cpp@11area_sorter = .text:0x8004F748; // type:function size:0x190 scope:global sort,Q24rstl17rmemory_allocator>,15CLightPredicate>__4rstlFQ24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>15CLightPredicate = .text:0x8004F8D8; // type:function size:0x258 scope:global -fn_8004FB30 = .text:0x8004FB30; // type:function size:0x18C +iter_swap,Q24rstl17rmemory_allocator>,Q24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator> = .text:0x8004FB30; // type:function size:0x18C insert_into__Q24rstl175red_black_tree<9TEditorId,Q24rstl27pair<9TEditorId,9TUniqueId>,1,Q24rstl47select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>FPQ34rstl175red_black_tree<9TEditorId,Q24rstl27pair<9TEditorId,9TUniqueId>,1,Q24rstl47select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>4nodeRCQ24rstl27pair<9TEditorId,9TUniqueId> = .text:0x8004FCBC; // type:function size:0x208 scope:global insert_into__Q24rstl197red_black_tree<9TEditorId,Q24rstl38pair<9TEditorId,19SScriptObjectStream>,0,Q24rstl58select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>FPQ34rstl197red_black_tree<9TEditorId,Q24rstl38pair<9TEditorId,19SScriptObjectStream>,0,Q24rstl58select1st>,Q24rstl16less<9TEditorId>,Q24rstl17rmemory_allocator>4nodeRCQ24rstl38pair<9TEditorId,19SScriptObjectStream> = .text:0x8004FEC4; // type:function size:0x26C scope:global __dt__10CWeaponMgrFv = .text:0x80050130; // type:function size:0xD4 scope:global reserve__Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>Fi = .text:0x80050204; // type:function size:0xDC scope:global -fn_800502E0 = .text:0x800502E0; // type:function size:0x68 +uninitialized_copy,Q24rstl17rmemory_allocator>,6CLight>__4rstlFQ24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl104pointer_iterator<6CLight,Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P6CLight = .text:0x800502E0; // type:function size:0x68 scope:local reserve__Q24rstl45vector<9TEditorId,Q24rstl17rmemory_allocator>Fi = .text:0x80050348; // type:function size:0xEC scope:global reserve__Q24rstl48vector<11SConnection,Q24rstl17rmemory_allocator>Fi = .text:0x80050434; // type:function size:0x100 scope:global __dt__Q24rstl43list<9TUniqueId,Q24rstl17rmemory_allocator>Fv = .text:0x80050534; // type:function size:0x78 scope:global do_erase__Q24rstl72list,Q24rstl17rmemory_allocator>FPQ34rstl72list,Q24rstl17rmemory_allocator>4node = .text:0x800505AC; // type:function size:0xD8 __dt__Q24rstl72list,Q24rstl17rmemory_allocator>Fv = .text:0x80050684; // type:function size:0xDC scope:global -fn_80050760 = .text:0x80050760; // type:function size:0x94 +__dt__Q24rstl63listFv = .text:0x80050760; // type:function size:0x94 __insertion_sort__4rstlFPPC9CGameAreaPPC9CGameAreaQ227@unnamed@CStateManager_cpp@11area_sorter = .text:0x800507F4; // type:function size:0x88 scope:global __sort3<6CLight,15CLightPredicate>__4rstlFR6CLightR6CLightR6CLight15CLightPredicate = .text:0x8005087C; // type:function size:0x3CC scope:global swap<6CLight>__4rstlFR6CLightR6CLight = .text:0x80050C48; // type:function size:0x180 scope:global @@ -1523,7 +1523,7 @@ StartStreamingMainArea__9CGameAreaFv = .text:0x8005FBF4; // type:function size:0 Set__Q24rstl42single_ptrFPQ29CGameArea16CPostConstructed = .text:0x800600D0; // type:function size:0x48 scope:global __dt__Q29CGameArea16CPostConstructedFv = .text:0x80060118; // type:function size:0x3A4 scope:global fn_800604BC = .text:0x800604BC; // type:function size:0x8C -destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl136pointer_iterator<21CMetroidModelInstance,Q24rstl58vector<21CMetroidModelInstance,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl136pointer_iterator<21CMetroidModelInstance,Q24rstl58vector<21CMetroidModelInstance,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator> = .text:0x80060548; // type:function size:0x50 scope:global +destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl136pointer_iterator<21CMetroidModelInstance,Q24rstl58vector<21CMetroidModelInstance,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl136pointer_iterator<21CMetroidModelInstance,Q24rstl58vector<21CMetroidModelInstance,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator> = .text:0x80060548; // type:function size:0x50 scope:local __dt__21CMetroidModelInstanceFv = .text:0x80060598; // type:function size:0x6C scope:global UnloadAllloadedTextures__9CGameAreaFv = .text:0x80060604; // type:function size:0xC8 scope:global ReloadAllUnloadedTextures__9CGameAreaFv = .text:0x800606CC; // type:function size:0xC0 scope:global @@ -1802,10 +1802,10 @@ LaunchProjectile__10CPatternedFRC12CTransform4fR13CStateManageriQ27CWeapon17EPro RenderIceModelWithFlags__10CPatternedCFRC11CModelFlags = .text:0x80077BE4; // type:function size:0xA8 scope:global __dt__Q24rstl37optional_object<18CVertexMorphEffect>Fv = .text:0x80077C8C; // type:function size:0x50 scope:global clear__Q24rstl37optional_object<18CVertexMorphEffect>Fv = .text:0x80077CDC; // type:function size:0x40 -destroy<18CVertexMorphEffect>__4rstlFP18CVertexMorphEffect = .text:0x80077D1C; // type:function size:0x24 +destroy<18CVertexMorphEffect>__4rstlFP18CVertexMorphEffect = .text:0x80077D1C; // type:function size:0x24 scope:local __dt__18CVertexMorphEffectFv = .text:0x80077D40; // type:function size:0xDC scope:global __ct__Q24rstl37optional_object<18CVertexMorphEffect>FRC18CVertexMorphEffect = .text:0x80077E1C; // type:function size:0x38 -construct<18CVertexMorphEffect>__4rstlFPvRC18CVertexMorphEffect = .text:0x80077E54; // type:function size:0x28 +construct<18CVertexMorphEffect>__4rstlFPvRC18CVertexMorphEffect = .text:0x80077E54; // type:function size:0x28 scope:local __ct__18CVertexMorphEffectFRC18CVertexMorphEffect = .text:0x80077E7C; // type:function size:0x1B0 Render__10CPatternedCFRC13CStateManager = .text:0x8007802C; // type:function size:0x274 scope:global CanRenderUnsorted__10CPatternedCFRC13CStateManager = .text:0x800782A0; // type:function size:0x3C scope:global @@ -1974,7 +1974,7 @@ Reset__11CBallCameraFRC12CTransform4fR13CStateManager = .text:0x8008C08C; // typ Render__11CBallCameraCFRC13CStateManager = .text:0x8008C40C; // type:function size:0x4 scope:global SetupColliders__11CBallCameraFRQ24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>fffifff = .text:0x8008C410; // type:function size:0x218 scope:global push_back__Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>FRC15CCameraCollider = .text:0x8008C628; // type:function size:0x7C scope:global -construct<15CCameraCollider>__4rstlFPvRC15CCameraCollider = .text:0x8008C6A4; // type:function size:0x28 scope:global +construct<15CCameraCollider>__4rstlFPvRC15CCameraCollider = .text:0x8008C6A4; // type:function size:0x28 scope:local __ct__15CCameraColliderFRC15CCameraCollider = .text:0x8008C6CC; // type:function size:0xB0 scope:global __dt__15CCameraColliderFv = .text:0x8008C77C; // type:function size:0x48 scope:global ResetToTweaks__11CBallCameraFR13CStateManager = .text:0x8008C7C4; // type:function size:0x234 scope:global @@ -1987,7 +1987,7 @@ __dt__Q24rstl43single_ptrFv = .text:0x8008CEAC; __ct__11CBallCameraF9TUniqueId9TUniqueIdRC12CTransform4fffff = .text:0x8008CF5C; // type:function size:0x848 scope:global __ct__15CCameraColliderFf9CVector3fRC13CCameraSpringf = .text:0x8008D7A4; // type:function size:0xA8 scope:global reserve__Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>Fi = .text:0x8008D84C; // type:function size:0xE4 scope:global -uninitialized_copy,Q24rstl17rmemory_allocator>,P15CCameraCollider>__4rstlFQ24rstl124pointer_iterator<15CCameraCollider,Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl124pointer_iterator<15CCameraCollider,Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P15CCameraCollider = .text:0x8008D930; // type:function size:0x68 scope:global +uninitialized_copy,Q24rstl17rmemory_allocator>,P15CCameraCollider>__4rstlFQ24rstl124pointer_iterator<15CCameraCollider,Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl124pointer_iterator<15CCameraCollider,Q24rstl52vector<15CCameraCollider,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P15CCameraCollider = .text:0x8008D930; // type:function size:0x68 scope:local __sinit_CBallCamera_cpp = .text:0x8008D998; // type:function size:0xD8 scope:local __dt__13CScriptEffectFv = .text:0x8008DA70; // type:function size:0x100 scope:global SetActive__13CScriptEffectFb = .text:0x8008DB70; // type:function size:0x3C scope:global @@ -5784,7 +5784,7 @@ LoadRepulsor__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = . LoadStreamedMusic__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = .text:0x800CB03C; // type:function size:0x148 scope:global LoadMidi__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = .text:0x800CB184; // type:function size:0x108 scope:global LoadThardusRockProjectile__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = .text:0x800CB28C; // type:function size:0x2A8 scope:global -construct<10CModelData>__4rstlFPvRC10CModelData = .text:0x800CB534; // type:function size:0x7C scope:global +construct<10CModelData>__4rstlFPvRC10CModelData = .text:0x800CB534; // type:function size:0x7C scope:local fn_800CB5B0 = .text:0x800CB5B0; // type:function size:0x28 LoadFlaahgraTentacle__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = .text:0x800CB5D8; // type:function size:0x1CC scope:global LoadWallCrawlerSwarm__12ScriptLoaderFR13CStateManagerR12CInputStreamiRC11CEntityInfo = .text:0x800CB7A4; // type:function size:0x480 scope:global @@ -6181,13 +6181,13 @@ CalculateSurfaceFriction__10CMorphBallCFv = .text:0x800F0010; // type:function s ComputeLiftForces__10CMorphBallFRC9CVector3fRC9CVector3fRC13CStateManager = .text:0x800F0094; // type:function size:0x4D8 scope:global GetAverage__22TReservedAverageCFv = .text:0x800F056C; // type:function size:0x60 scope:global GetAverage__31TReservedAverage<9CVector3f,15>CFv = .text:0x800F05CC; // type:function size:0x74 scope:global -fn_800F0640 = .text:0x800F0640; // type:function size:0x15C +AddValue__31TReservedAverage<9CVector3f,15>FRC9CVector3f = .text:0x800F0640; // type:function size:0x15C IsInFrustum__10CMorphBallCFRC14CFrustumPlanes = .text:0x800F079C; // type:function size:0x170 scope:global CollidedWith__10CMorphBallFRC9TUniqueIdRC18CCollisionInfoListR13CStateManager = .text:0x800F090C; // type:function size:0xA1C scope:global __as__18CCollisionInfoListFRC18CCollisionInfoList = .text:0x800F1328; // type:function size:0x30 scope:global -fn_800F1358 = .text:0x800F1358; // type:function size:0xBC -fn_800F1414 = .text:0x800F1414; // type:function size:0x64 -fn_800F1478 = .text:0x800F1478; // type:function size:0x28 +__as__Q24rstl36reserved_vector<14CCollisionInfo,32>FRCQ24rstl36reserved_vector<14CCollisionInfo,32> = .text:0x800F1358; // type:function size:0xBC +uninitialized_copy__4rstlFPC14CCollisionInfoPC14CCollisionInfoP14CCollisionInfo = .text:0x800F1414; // type:function size:0x64 scope:local +construct<14CCollisionInfo>__4rstlFPvRC14CCollisionInfo = .text:0x800F1478; // type:function size:0x28 scope:local __ct__14CCollisionInfoFRC14CCollisionInfo = .text:0x800F14A0; // type:function size:0xC4 scope:global BallCloseToCollision__10CMorphBallCFRC13CStateManagerfRC15CMaterialFilter = .text:0x800F1564; // type:function size:0x390 scope:global DisableHalfPipeStatus__10CMorphBallFv = .text:0x800F18F4; // type:function size:0x94 scope:global @@ -6206,14 +6206,14 @@ IsMorphBallTransitionFlashValid__10CMorphBallCFv = .text:0x800F1FAC; // type:fun RenderMorphBallTransitionFlash__10CMorphBallCFRC13CStateManager = .text:0x800F1FC0; // type:function size:0x90 scope:global UpdateMorphBallTransitionFlash__10CMorphBallFf = .text:0x800F2050; // type:function size:0x1D0 scope:global ResetMorphBallTransitionFlash__10CMorphBallFv = .text:0x800F2220; // type:function size:0x58 scope:global -Render__10CMorphBallCFRC13CStateManagerPC12CActorLights_0 = .text:0x800F2278; // type:function size:0xB70 scope:global +Render__10CMorphBallCFRC13CStateManagerPC12CActorLights = .text:0x800F2278; // type:function size:0xB70 scope:global GetEntry__33TReservedAverage<11CQuaternion,5>CFi = .text:0x800F2DE8; // type:function size:0x54 scope:global GetEntry__30TReservedAverage<9CVector3f,5>CFi = .text:0x800F2E3C; // type:function size:0x4C scope:global PreRender__10CMorphBallFR13CStateManagerRC14CFrustumPlanes = .text:0x800F2E88; // type:function size:0x3A4 scope:global -fn_800F322C = .text:0x800F322C; // type:function size:0x108 -fn_800F3334 = .text:0x800F3334; // type:function size:0xBC -fn_800F33F0 = .text:0x800F33F0; // type:function size:0x64 -fn_800F3454 = .text:0x800F3454; // type:function size:0x28 +__as__12CActorLightsFRC12CActorLights = .text:0x800F322C; // type:function size:0x108 +__as__Q24rstl26reserved_vector<6CLight,4>FRCQ24rstl26reserved_vector<6CLight,4> = .text:0x800F3334; // type:function size:0xBC +uninitialized_copy__4rstlFPC6CLightPC6CLightP6CLight = .text:0x800F33F0; // type:function size:0x64 scope:local +construct<6CLight>__4rstlFPvRC6CLight = .text:0x800F3454; // type:function size:0x28 scope:local GetMinimumAlignmentSpeed__10CMorphBallCFv = .text:0x800F347C; // type:function size:0x20 scope:global DampLinearAndAngularVelocities__10CMorphBallFff = .text:0x800F349C; // type:function size:0xC0 scope:global ApplyFriction__10CMorphBallFf = .text:0x800F355C; // type:function size:0xD0 scope:global @@ -6224,8 +6224,8 @@ LeaveBoosting__10CMorphBallFv = .text:0x800F3EC4; // type:function size:0x34 sco EnterBoosting__10CMorphBallFR13CStateManager = .text:0x800F3EF8; // type:function size:0x4B4 scope:global ComputeBoostBallMovement__10CMorphBallFRC11CFinalInputRC13CStateManagerf = .text:0x800F43AC; // type:function size:0x4BC scope:global UpdateEffects__10CMorphBallFfR13CStateManager = .text:0x800F4868; // type:function size:0xC30 scope:global -fn_800F5498 = .text:0x800F5498; // type:function size:0x30 -fn_800F54C8 = .text:0x800F54C8; // type:function size:0xE4 +__as__Q24rstl24optional_object<6CLight>FRC6CLight = .text:0x800F5498; // type:function size:0x30 +assign__Q24rstl24optional_object<6CLight>FRC6CLight = .text:0x800F54C8; // type:function size:0xE4 StopParticleWakes__10CMorphBallFv = .text:0x800F55AC; // type:function size:0x90 scope:global LeaveMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F563C; // type:function size:0x4C scope:global EnterMorphBallState__10CMorphBallFR13CStateManager = .text:0x800F5688; // type:function size:0xB8 scope:global @@ -6236,8 +6236,8 @@ Update__10CMorphBallFfR13CStateManager = .text:0x800F5974; // type:function size SwitchToTire__10CMorphBallFv = .text:0x800F5B18; // type:function size:0x20 scope:global SwitchToMarble__10CMorphBallFv = .text:0x800F5B38; // type:function size:0x114 scope:global UpdateBallDynamics__10CMorphBallFR13CStateManagerf = .text:0x800F5C4C; // type:function size:0x578 scope:global -fn_800F61C4 = .text:0x800F61C4; // type:function size:0x15C -fn_800F6320 = .text:0x800F6320; // type:function size:0x194 +AddValue__30TReservedAverage<9CVector3f,5>FRC9CVector3f = .text:0x800F61C4; // type:function size:0x15C +AddValue__33TReservedAverage<11CQuaternion,5>FRC11CQuaternion = .text:0x800F6320; // type:function size:0x194 BallTurnInput__10CMorphBallCFRC11CFinalInput = .text:0x800F64B4; // type:function size:0x6C scope:global CalculateBallContactInfo__10CMorphBallCFR9CVector3fR9CVector3f = .text:0x800F6520; // type:function size:0x4C scope:global CalculateSurfaceToWorld__10CMorphBallCFRC9CVector3fRC9CVector3fRC9CVector3f = .text:0x800F656C; // type:function size:0x188 scope:global @@ -6268,10 +6268,10 @@ GetBallRadius__10CMorphBallCFv = .text:0x800F8E04; // type:function size:0xC sco __dt__10CMorphBallFv = .text:0x800F8E10; // type:function size:0x764 __ct__10CMorphBallFR7CPlayerf = .text:0x800F9574; // type:function size:0xE98 scope:global __dl__24TOneStatic<10CMorphBall>FPv = .text:0x800FA40C; // type:function size:0x2C -fn_800FA438 = .text:0x800FA438; // type:function size:0x7C -fn_800FA4B4 = .text:0x800FA4B4; // type:function size:0x78 +do_erase__Q24rstl78listFPQ34rstl78list4node = .text:0x800FA438; // type:function size:0x7C +__dt__Q24rstl78listFv = .text:0x800FA4B4; // type:function size:0x78 __sinit_CMorphBall_cpp = .text:0x800FA52C; // type:function size:0x64 scope:local -fn_800FA590 = .text:0x800FA590; // type:function size:0x94 +__dt__Q24rstl21reserved_vectorFv = .text:0x800FA590; // type:function size:0x94 Accept__24CScriptDamageableTriggerFR8IVisitor = .text:0x800FA624; // type:function size:0x38 scope:global GetCollisionResponseType__24CScriptDamageableTriggerCFRC9CVector3fRC9CVector3fRC11CWeaponModei = .text:0x800FA65C; // type:function size:0x3C scope:global Render__24CScriptDamageableTriggerCFRC13CStateManager = .text:0x800FA698; // type:function size:0x1A4 scope:global @@ -6372,7 +6372,7 @@ BuildConstantAmbientLighting__12CActorLightsFv = .text:0x80103084; // type:funct BuildConstantAmbientLighting__12CActorLightsFRC6CColor = .text:0x801030B0; // type:function size:0x7C scope:global BuildFakeLightList__12CActorLightsFRCQ24rstl42vector<6CLight,Q24rstl17rmemory_allocator>RC6CColor = .text:0x8010312C; // type:function size:0x120 scope:global push_back__Q24rstl26reserved_vector<6CLight,4>FRC6CLight = .text:0x8010324C; // type:function size:0x48 scope:global -construct<6CLight>__4rstlFPvRC6CLight = .text:0x80103294; // type:function size:0x28 scope:global +construct<6CLight>__4rstlFPvRC6CLight = .text:0x80103294; // type:function size:0x28 scope:local BuildFaceLightList__12CActorLightsFRC13CStateManagerRC9CGameAreaRC6CAABox = .text:0x801032BC; // type:function size:0x454 scope:global BuildDynamicLightList__12CActorLightsFRC13CStateManagerRC6CAABox = .text:0x80103710; // type:function size:0x330 scope:global MoveAmbienceToLights__12CActorLightsFRC9CVector3f = .text:0x80103A40; // type:function size:0x178 scope:global @@ -6569,7 +6569,7 @@ Touch__10CModelDataCFQ210CModelData11EWhichModeli = .text:0x80115CAC; // type:fu Touch__10CModelDataCFRC13CStateManageri = .text:0x80115D10; // type:function size:0x4C scope:global MultipassDraw__10CModelDataF11EWhichModelRC12CTransform4fPC12CActorLightsPC11CModelFlagsi = .text:0x80115D5C; // type:function size:0x14C scope:global MultiLightingDraw__10CModelDataF11EWhichModelRC12CTransform4fPC12CActorLightsRC6CColorRC6CColor = .text:0x80115EA8; // type:function size:0x11C scope:global -FlatDraw__10CModelDataCF11EWhichModelRC12CTransform4fbRC11CModelFlags = .text:0x80115FC4; // type:function size:0x11C scope:global +FlatDraw__10CModelDataCFQ210CModelData11EWhichModelRC12CTransform4fbRC11CModelFlags = .text:0x80115FC4; // type:function size:0x11C scope:global DisintegrateDraw__10CModelDataFRC13CStateManagerRC12CTransform4fRC8CTextureRC6CColorf = .text:0x801160E0; // type:function size:0x7C scope:global DisintegrateDraw__10CModelDataF11EWhichModelRC12CTransform4fRC8CTextureRC6CColor = .text:0x8011615C; // type:function size:0x144 scope:global RenderThermal__10CModelDataCFRC12CTransform4fRC6CColorRC6CColorRC11CModelFlags = .text:0x801162A0; // type:function size:0x114 scope:global @@ -6600,10 +6600,10 @@ __ct__Q213CDecalManager6SDecalFRCQ24rstl24optional_object<6CDecal>7TAreaIdcc = . __ct__Q24rstl24optional_object<6CDecal>FRCQ24rstl24optional_object<6CDecal> = .text:0x80117718; // type:function size:0xEC ShutDown__13CDecalManagerFv = .text:0x80117804; // type:function size:0x8C scope:global clear__Q24rstl44reserved_vectorFv = .text:0x80117890; // type:function size:0x68 scope:global -destroy__4rstlFPQ213CDecalManager6SDecal = .text:0x801178F8; // type:function size:0x5C +destroy__4rstlFPQ213CDecalManager6SDecal = .text:0x801178F8; // type:function size:0x5C scope:local Initialize__13CDecalManagerFv = .text:0x80117954; // type:function size:0x118 scope:global push_back__Q24rstl44reserved_vectorFRCQ213CDecalManager6SDecal = .text:0x80117A6C; // type:function size:0x48 -construct__4rstlFPvRCQ213CDecalManager6SDecal = .text:0x80117AB4; // type:function size:0x28 +construct__4rstlFPvRCQ213CDecalManager6SDecal = .text:0x80117AB4; // type:function size:0x28 scope:local __ct__Q213CDecalManager6SDecalFRCQ213CDecalManager6SDecal = .text:0x80117ADC; // type:function size:0x54 __sinit_CDecalManager_cpp = .text:0x80117B30; // type:function size:0x5C scope:local __dt__Q24rstl21reserved_vectorFv = .text:0x80117B8C; // type:function size:0x94 scope:global @@ -6721,7 +6721,7 @@ Init__14CRippleManagerFi = .text:0x8011D114; // type:function size:0x90 scope:gl resize__Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>FiRC7CRipple = .text:0x8011D1A4; // type:function size:0x140 scope:global __ct__14CRippleManagerFif = .text:0x8011D2E4; // type:function size:0x4C scope:global reserve__Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>Fi = .text:0x8011D330; // type:function size:0xD8 scope:global -uninitialized_copy,Q24rstl17rmemory_allocator>,7CRipple>__4rstlFQ24rstl106pointer_iterator<7CRipple,Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl106pointer_iterator<7CRipple,Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P7CRipple = .text:0x8011D408; // type:function size:0xAC scope:global +uninitialized_copy,Q24rstl17rmemory_allocator>,7CRipple>__4rstlFQ24rstl106pointer_iterator<7CRipple,Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl106pointer_iterator<7CRipple,Q24rstl43vector<7CRipple,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P7CRipple = .text:0x8011D408; // type:function size:0xAC scope:local DisconnectGrappleBeam__11CGrappleArmFv = .text:0x8011D4B4; // type:function size:0x58 scope:global PointGenerator__11CGrappleArmFPvPC9CVector3fPC9CVector3fi = .text:0x8011D50C; // type:function size:0x28 scope:global RenderXRayModel__11CGrappleArmFRC13CStateManagerRC12CTransform4fRC11CModelFlags = .text:0x8011D534; // type:function size:0x110 scope:global @@ -7357,7 +7357,7 @@ PreThink__12CPuddleSporeFfR13CStateManager = .text:0x80148280; // type:function Accept__12CPuddleSporeFR8IVisitor = .text:0x80148358; // type:function size:0x38 scope:global __ct__12CPuddleSporeF9TUniqueIdRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>Q210CPatterned11EFlavorTypeRC11CEntityInfoRC12CTransform4fRC10CModelDataRC14CPatternedInfoQ210CPatterned13EColliderTypeUifffffRC16CActorParametersUiRC11CDamageInfo = .text:0x80148390; // type:function size:0x2D4 scope:global push_back__Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>FRC11CElementGen = .text:0x80148664; // type:function size:0x7C -construct<11CElementGen>__4rstlFPvRC11CElementGen = .text:0x801486E0; // type:function size:0x28 +construct<11CElementGen>__4rstlFPvRC11CElementGen = .text:0x801486E0; // type:function size:0x28 scope:local __ct__11CElementGenFRC11CElementGen = .text:0x80148708; // type:function size:0x678 fn_80148D80 = .text:0x80148D80; // type:function size:0xB0 fn_80148E30 = .text:0x80148E30; // type:function size:0x98 @@ -7366,7 +7366,7 @@ fn_80148F0C = .text:0x80148F0C; // type:function size:0x98 fn_80148FA4 = .text:0x80148FA4; // type:function size:0xB4 fn_80149058 = .text:0x80149058; // type:function size:0x8C reserve__Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>Fi = .text:0x801490E4; // type:function size:0xE8 -uninitialized_copy,Q24rstl17rmemory_allocator>,11CElementGen>__4rstlFQ24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P11CElementGen = .text:0x801491CC; // type:function size:0x68 +uninitialized_copy,Q24rstl17rmemory_allocator>,P11CElementGen>__4rstlFQ24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P11CElementGen = .text:0x801491CC; // type:function size:0x68 scope:local fn_80149234 = .text:0x80149234; // type:function size:0x7C __dt__8CBSTauntFv = .text:0x801492B0; // type:function size:0x5C scope:global GetBodyStateTransition__8CBSTauntFfR15CBodyController = .text:0x8014930C; // type:function size:0xD4 scope:global @@ -8044,8 +8044,8 @@ SendScriptMessages__14CGameCollisionFR13CStateManagerR6CActorP6CActorRC18CCollis MakeCollisionCallbacks__14CGameCollisionFR13CStateManagerR13CPhysicsActorRC9TUniqueIdRC18CCollisionInfoList = .text:0x80182BB8; // type:function size:0x13C scope:global __ct__18CCollisionInfoListFRC18CCollisionInfoList = .text:0x80182CF4; // type:function size:0x30 scope:global __ct__Q24rstl36reserved_vector<14CCollisionInfo,32>FRCQ24rstl36reserved_vector<14CCollisionInfo,32> = .text:0x80182D24; // type:function size:0x44 -uninitialized_copy_n__4rstlFPC14CCollisionInfoiP14CCollisionInfo = .text:0x80182D68; // type:function size:0x74 -construct<14CCollisionInfo>__4rstlFPvRC14CCollisionInfo = .text:0x80182DDC; // type:function size:0x28 +uninitialized_copy_n__4rstlFPC14CCollisionInfoiP14CCollisionInfo = .text:0x80182D68; // type:function size:0x74 scope:local +construct<14CCollisionInfo>__4rstlFPvRC14CCollisionInfo = .text:0x80182DDC; // type:function size:0x28 scope:local DetectStaticCollision_Cached_Moving__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheRC19CCollisionPrimitiveRC12CTransform4fRC15CMaterialFilter9CVector3fR14CCollisionInfoRd = .text:0x80182E04; // type:function size:0x59C scope:global DetectStaticCollisionBoolean__14CGameCollisionFRC13CStateManagerRC19CCollisionPrimitiveRC12CTransform4fRC15CMaterialFilter = .text:0x801833A0; // type:function size:0x258 scope:global DetectStaticCollisionBoolean_Cached__14CGameCollisionFRC13CStateManagerR19CAreaCollisionCacheRC19CCollisionPrimitiveRC12CTransform4fRC15CMaterialFilter = .text:0x801835F8; // type:function size:0x2E8 scope:global @@ -10941,7 +10941,7 @@ fn_80267E6C = .text:0x80267E6C; // type:function size:0x14 fn_80267E80 = .text:0x80267E80; // type:function size:0x18 __ct__13CGameHintInfoFR12CInputStreamUi = .text:0x80267E98; // type:function size:0xB0 scope:global push_back__Q24rstl62vectorFRCQ213CGameHintInfo9CGameHint = .text:0x80267F48; // type:function size:0x7C scope:global -construct__4rstlFRCQ213CGameHintInfo9CGameHint = .text:0x80267FC4; // type:function size:0x28 scope:global +construct__4rstlFRCQ213CGameHintInfo9CGameHint = .text:0x80267FC4; // type:function size:0x28 scope:local __ct__Q213CGameHintInfo9CGameHintFRCQ213CGameHintInfo9CGameHint = .text:0x80267FEC; // type:function size:0x108 scope:global __ct__Q213CGameHintInfo9CGameHintFR12CInputStreamUi = .text:0x802680F4; // type:function size:0x168 scope:global __ct__Q213CGameHintInfo13SHintLocationFR12CInputStream = .text:0x8026825C; // type:function size:0x68 scope:global @@ -10991,7 +10991,7 @@ __ct__Q220CRainSplashGenerator11SRainSplashFvFRCQ220CRainSplashGenerator11SRainS __as__Q220CRainSplashGenerator11SRainSplashFRCQ220CRainSplashGenerator11SRainSplash = .text:0x8026A98C; // type:function size:0x98 scope:global GetNextBestPt__20CRainSplashGeneratorFiPC9CVector3fPC9CVector3fiR9CRandom16f = .text:0x8026AA24; // type:function size:0x194 scope:global reserve__Q24rstl72vectorFi = .text:0x8026ABB8; // type:function size:0x140 scope:global -uninitialized_copy,Q24rstl17rmemory_allocator>,Q220CRainSplashGenerator11SRainSplash>__4rstlFQ24rstl164pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl164pointer_iterator,Q24rstl17rmemory_allocator>PQ220CRainSplashGenerator11SRainSplash = .text:0x8026ACF8; // type:function size:0x68 scope:global +uninitialized_copy,Q24rstl17rmemory_allocator>,Q220CRainSplashGenerator11SRainSplash>__4rstlFQ24rstl164pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl164pointer_iterator,Q24rstl17rmemory_allocator>PQ220CRainSplashGenerator11SRainSplash = .text:0x8026ACF8; // type:function size:0x68 scope:local FSaveWorldFactory__FRC10SObjectTagR12CInputStreamRC15CVParamTransfer = .text:0x8026AD60; // type:function size:0x64 scope:global fn_8026ADC4 = .text:0x8026ADC4; // type:function size:0xA4 fn_8026AE68 = .text:0x8026AE68; // type:function size:0x90 @@ -11979,7 +11979,7 @@ Clear__7BucketsFv = .text:0x802BF3AC; // type:function size:0x1F8 scope:global Sort__7BucketsFv = .text:0x802BF5A4; // type:function size:0x578 scope:global InsertPlaneObject__7BucketsFffRC6CAABoxbRC6CPlaneb13EDrawableTypePCv = .text:0x802BFB1C; // type:function size:0x78 scope:global push_back__Q24rstl41reserved_vector<20CDrawablePlaneObject,8>FRC20CDrawablePlaneObject = .text:0x802BFB94; // type:function size:0x48 scope:global -construct<20CDrawablePlaneObject>__4rstlFPvRC20CDrawablePlaneObject = .text:0x802BFBDC; // type:function size:0x28 scope:global +construct<20CDrawablePlaneObject>__4rstlFPvRC20CDrawablePlaneObject = .text:0x802BFBDC; // type:function size:0x28 scope:local __ct__20CDrawablePlaneObjectFRC20CDrawablePlaneObject = .text:0x802BFC04; // type:function size:0x8C scope:global __ct__20CDrawablePlaneObjectF13EDrawableTypeffRC6CAABoxbRC6CPlanebPCv = .text:0x802BFC90; // type:function size:0x88 scope:global Insert__7BucketsFRC9CVector3fRC6CAABox13EDrawableTypePCvRC6CPlaneUs = .text:0x802BFD18; // type:function size:0x144 scope:global @@ -12699,7 +12699,7 @@ __ct__12CPASDatabaseFR12CInputStream = .text:0x802E5280; // type:function size:0 lower_bound,Q24rstl17rmemory_allocator>,13CPASAnimState>__4rstlFQ24rstl126const_pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl126const_pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>RC13CPASAnimState = .text:0x802E5340; // type:function size:0xC0 scope:global lower_bound,Q24rstl17rmemory_allocator>,13CPASAnimState>__4rstlFQ24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>RC13CPASAnimState = .text:0x802E5400; // type:function size:0xC0 scope:global reserve__Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>Fi = .text:0x802E54C0; // type:function size:0xD0 scope:global -construct<13CPASAnimState>__4rstlFPvRC13CPASAnimState = .text:0x802E5590; // type:function size:0x68 scope:global +construct<13CPASAnimState>__4rstlFPvRC13CPASAnimState = .text:0x802E5590; // type:function size:0x68 scope:local advance,Q24rstl17rmemory_allocator>,i>__4rstlFRQ24rstl126const_pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>i = .text:0x802E55F8; // type:function size:0x2C scope:global advance,Q24rstl17rmemory_allocator>,i>__4rstlFRQ24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>i = .text:0x802E5624; // type:function size:0x2C scope:global __advance,Q24rstl17rmemory_allocator>,i>__4rstlFRQ24rstl120pointer_iterator<13CPASAnimState,Q24rstl50vector<13CPASAnimState,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>iQ24rstl26random_access_iterator_tag = .text:0x802E5650; // type:function size:0x14 scope:global @@ -14056,11 +14056,11 @@ IsLargeEnough__15CParticleSwooshCFv = .text:0x8032EBB4; // type:function size:0x __dt__15CParticleSwooshFv = .text:0x8032EBDC; // type:function size:0x208 scope:global __ct__15CParticleSwooshF28TToken<18CSwooshDescription>i = .text:0x8032EDE4; // type:function size:0x7DC scope:global push_back__Q24rstl67vectorFRCQ215CParticleSwoosh11SSwooshData = .text:0x8032F5C0; // type:function size:0x7C -construct__4rstlFPvRCQ215CParticleSwoosh11SSwooshData = .text:0x8032F63C; // type:function size:0x28 +construct__4rstlFPvRCQ215CParticleSwoosh11SSwooshData = .text:0x8032F63C; // type:function size:0x28 scope:local __ct__Q215CParticleSwoosh11SSwooshDataFRCQ215CParticleSwoosh11SSwooshData = .text:0x8032F664; // type:function size:0xE4 __ct__Q215CParticleSwoosh11SSwooshDataFRC9CVector3fRC9CVector3fffibRC12CTransform4fRC9CVector3fffRC6CColor = .text:0x8032F748; // type:function size:0xDC scope:global reserve__Q24rstl67vectorFi = .text:0x8032F824; // type:function size:0xD8 -uninitialized_copy,Q24rstl17rmemory_allocator>,Q215CParticleSwoosh11SSwooshData>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator>PQ215CParticleSwoosh11SSwooshData = .text:0x8032F8FC; // type:function size:0x68 +uninitialized_copy,Q24rstl17rmemory_allocator>,PQ215CParticleSwoosh11SSwooshData>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator>PQ215CParticleSwoosh11SSwooshData = .text:0x8032F8FC; // type:function size:0x68 scope:local CreateWPSM__26CParticleSwooshDataFactoryFP18CSwooshDescriptionR12CInputStreamP11CSimplePool = .text:0x8032F964; // type:function size:0x4DC scope:global CreateGeneratorDescription__26CParticleSwooshDataFactoryFR12CInputStreamP11CSimplePool = .text:0x8032FE40; // type:function size:0x8C scope:global GetGeneratorDesc__26CParticleSwooshDataFactoryFR12CInputStreamP11CSimplePool = .text:0x8032FECC; // type:function size:0x84 scope:global @@ -15008,7 +15008,7 @@ VerifyBuffer__17CTextRenderBufferFv = .text:0x8035A3FC; // type:function size:0x Render__17CTextRenderBufferCFRC6CColorf = .text:0x8035A4BC; // type:function size:0x70C scope:global AddImage__17CTextRenderBufferFRC9CVector2iRC13CFontImageDef = .text:0x8035ABC8; // type:function size:0x214 scope:global push_back__Q24rstl50vector<13CFontImageDef,Q24rstl17rmemory_allocator>FRC13CFontImageDef = .text:0x8035ADDC; // type:function size:0x7C -construct<13CFontImageDef>__4rstlFPvRC13CFontImageDef = .text:0x8035AE58; // type:function size:0x28 +construct<13CFontImageDef>__4rstlFPvRC13CFontImageDef = .text:0x8035AE58; // type:function size:0x28 scope:local AddCharacter__17CTextRenderBufferFRC9CVector2isUi = .text:0x8035AE80; // type:function size:0x1B0 scope:global AddPaletteChange__17CTextRenderBufferFRC16CGraphicsPalette = .text:0x8035B030; // type:function size:0x180 scope:global AddFontChange__17CTextRenderBufferFRC21TToken<11CRasterFont> = .text:0x8035B1B0; // type:function size:0x258 scope:global @@ -15025,7 +15025,7 @@ MixAudio__12CMoviePlayerFPsPCsUl = .text:0x8035B670; // type:function size:0x214 StaticMyAudioCallback__12CMoviePlayerFv = .text:0x8035B884; // type:function size:0xC0 scope:global Rewind__12CMoviePlayerFv = .text:0x8035B944; // type:function size:0x120 scope:global clear__Q24rstl67vectorFv = .text:0x8035BA64; // type:function size:0x60 scope:global -destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator> = .text:0x8035BAC4; // type:function size:0xC0 scope:global +destroy,Q24rstl17rmemory_allocator>>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator> = .text:0x8035BAC4; // type:function size:0xC0 scope:local GetIsMovieFinishedPlaying__12CMoviePlayerCFv = .text:0x8035BB84; // type:function size:0x2C scope:global GetIsFullyCached__12CMoviePlayerCFv = .text:0x8035BBB0; // type:function size:0x1C scope:global GetPlayedSeconds__12CMoviePlayerCFv = .text:0x8035BBCC; // type:function size:0x10 scope:global @@ -15046,7 +15046,7 @@ MyTHPYuv2RgbTextureSetup__FPvPvPvUsUs = .text:0x8035D120; // type:function size: MyTHPGXYuv2RgbSetup__Fbb = .text:0x8035D294; // type:function size:0x51C scope:global MyTHPGXRestore__Fv = .text:0x8035D7B0; // type:function size:0x84 scope:global reserve__Q24rstl67vectorFi = .text:0x8035D834; // type:function size:0x144 scope:global -construct__4rstlFPvRCQ212CMoviePlayer14CTHPTextureSet = .text:0x8035D978; // type:function size:0x90 scope:global +construct__4rstlFPvRCQ212CMoviePlayer14CTHPTextureSet = .text:0x8035D978; // type:function size:0x90 scope:local reserve__Q24rstl56vector,Q24rstl17rmemory_allocator>Fi = .text:0x8035DA08; // type:function size:0x108 scope:global AddToSegStatementSet__21CAdditiveAnimPlaybackCFRC10CSegIdListRC15CCharLayoutInfoR16CSegStatementSet = .text:0x8035DB10; // type:function size:0xE8 scope:global Update__21CAdditiveAnimPlaybackFf = .text:0x8035DBF8; // type:function size:0x118 scope:global @@ -15100,7 +15100,7 @@ CalculatePoints__17CParticleElectricFv = .text:0x80361094; // type:function size __dt__17CParticleElectricFv = .text:0x80361C70; // type:function size:0x2A4 scope:global __dt__Q24rstl74reserved_vector,32>Fv = .text:0x80361F14; // type:function size:0x50 scope:global clear__Q24rstl74reserved_vector,32>Fv = .text:0x80361F64; // type:function size:0x68 scope:global -destroy>__4rstlFPQ24rstl45auto_ptr = .text:0x80361FCC; // type:function size:0x24 scope:global +destroy>__4rstlFPQ24rstl45auto_ptr = .text:0x80361FCC; // type:function size:0x24 scope:local __dt__Q24rstl45auto_ptrFv = .text:0x80361FF0; // type:function size:0xB0 scope:global __dt__Q24rstl45vector<9CVector3f,Q24rstl17aligned_allocator>Fv = .text:0x803620A0; // type:function size:0xD0 scope:global __ct__17CParticleElectricF30TToken<20CElectricDescription> = .text:0x80362170; // type:function size:0xBCC scope:global @@ -17032,16 +17032,7 @@ lbl_803CEB08 = .rodata:0x803CEB08; // type:object size:0x70 lbl_803CEB78 = .rodata:0x803CEB78; // type:object size:0x1C lbl_803CEB94 = .rodata:0x803CEB94; // type:object size:0x30 lbl_803CEBC4 = .rodata:0x803CEBC4; // type:object size:0x30 -lbl_803CEBF4 = .rodata:0x803CEBF4; // type:object size:0xE data:string -lbl_803CEC02 = .rodata:0x803CEC02; // type:object size:0x14 data:string -lbl_803CEC16 = .rodata:0x803CEC16; // type:object size:0x15 data:string -lbl_803CEC2B = .rodata:0x803CEC2B; // type:object size:0x1B data:string -lbl_803CEC46 = .rodata:0x803CEC46; // type:object size:0x1B data:string -lbl_803CEC61 = .rodata:0x803CEC61; // type:object size:0x14 data:string -lbl_803CEC75 = .rodata:0x803CEC75; // type:object size:0x14 data:string -lbl_803CEC89 = .rodata:0x803CEC89; // type:object size:0x19 data:string -lbl_803CECA2 = .rodata:0x803CECA2; // type:object size:0x19 data:string -lbl_803CECBB = .rodata:0x803CECBB; // type:object size:0x13D +@stringBase0 = .rodata:0x803CEBF4; // type:object size:0x202 scope:local data:string_table lbl_803CEDF8 = .rodata:0x803CEDF8; // type:object size:0x7 data:string @stringBase0 = .rodata:0x803CEE00; // type:object size:0x1C scope:local data:string_table kSplashScales = .rodata:0x803CEE20; // type:object size:0x18 scope:local @@ -19566,7 +19557,7 @@ sInt32TransientCache = .bss:0x8056CF40; // type:object size:0x4C4 scope:global d kScaleVector__10CPlayerGun = .bss:0x8056D404; // type:object size:0xC scope:global align:4 data:float NullConnectionList__7CEntity = .bss:0x8056D410; // type:object size:0x10 scope:global CameraShaker = .bss:0x8056D420; // type:object size:0xD4 scope:global -lbl_8056D4F4 = .bss:0x8056D4F4; // type:object size:0x84 data:4byte +skWakeEffectMap = .bss:0x8056D4F4; // type:object size:0x84 scope:local data:4byte sNormalVulnerability__20CDamageVulnerability = .bss:0x8056D578; // type:object size:0x68 scope:global data:4byte sImmuneVulnerability__20CDamageVulnerability = .bss:0x8056D718; // type:object size:0x68 scope:global data:4byte sReflectVulnerability__20CDamageVulnerability = .bss:0x8056D780; // type:object size:0x68 scope:global data:4byte @@ -20204,11 +20195,11 @@ lbl_805A73E0 = .sdata:0x805A73E0; // type:object size:0x8 align:4 data:float lbl_805A73E8 = .sdata:0x805A73E8; // type:object size:0x4 lbl_805A73EC = .sdata:0x805A73EC; // type:object size:0x4 lbl_805A73F0 = .sdata:0x805A73F0; // type:object size:0x4 data:4byte -lbl_805A73F4 = .sdata:0x805A73F4; // type:object size:0x4 data:4byte -lbl_805A73F8 = .sdata:0x805A73F8; // type:object size:0x4 data:4byte -lbl_805A73FC = .sdata:0x805A73FC; // type:object size:0x4 data:4byte +@464 = .sdata:0x805A73F4; // type:object size:0x4 scope:local data:4byte +@465 = .sdata:0x805A73F8; // type:object size:0x4 scope:local data:4byte +@466 = .sdata:0x805A73FC; // type:object size:0x4 scope:local data:4byte lbl_805A7400 = .sdata:0x805A7400; // type:object size:0x4 align:4 data:float -lbl_805A7404 = .sdata:0x805A7404; // type:object size:0x1 data:byte +@489 = .sdata:0x805A7404; // type:object size:0x1 scope:local data:byte lbl_805A7408 = .sdata:0x805A7408; // type:object size:0x4 lbl_805A740C = .sdata:0x805A740C; // type:object size:0x4 lbl_805A7410 = .sdata:0x805A7410; // type:object size:0x4 align:4 data:float @@ -20249,7 +20240,7 @@ lbl_805A7498 = .sdata:0x805A7498; // type:object size:0x4 data:4byte lbl_805A749C = .sdata:0x805A749C; // type:object size:0x4 align:4 data:float lbl_805A74A0 = .sdata:0x805A74A0; // type:object size:0x4 lbl_805A74A4 = .sdata:0x805A74A4; // type:object size:0x4 -lbl_805A74A8 = .sdata:0x805A74A8; // type:object size:0x8 data:4byte +@2755 = .sdata:0x805A74A8; // type:object size:0x8 scope:local data:4byte lbl_805A74B0 = .sdata:0x805A74B0; // type:object size:0x4 data:4byte lbl_805A74B4 = .sdata:0x805A74B4; // type:object size:0x4 data:4byte lbl_805A74B8 = .sdata:0x805A74B8; // type:object size:0x4 data:4byte @@ -21793,10 +21784,10 @@ kLandingBobDamping2__16CPlayerCameraBob = .sbss:0x805A8ED4; // type:object size: kCameraDamping__16CPlayerCameraBob = .sbss:0x805A8ED8; // type:object size:0x8 scope:global align:4 data:float lbl_805A8EE0 = .sbss:0x805A8EE0; // type:object size:0x8 data:4byte lbl_805A8EE8 = .sbss:0x805A8EE8; // type:object size:0x4 align:4 data:float -lbl_805A8EEC = .sbss:0x805A8EEC; // type:object size:0x4 data:4byte -lbl_805A8EF0 = .sbss:0x805A8EF0; // type:object size:0x4 data:4byte -lbl_805A8EF4 = .sbss:0x805A8EF4; // type:object size:0x4 data:4byte -lbl_805A8EF8 = .sbss:0x805A8EF8; // type:object size:0x4 data:4byte +skSamusBall = .sbss:0x805A8EEC; // type:object size:0x4 scope:local data:4byte +skSamusBallLowPoly = .sbss:0x805A8EF0; // type:object size:0x4 scope:local data:4byte +skSamusSpiderBallGlass = .sbss:0x805A8EF4; // type:object size:0x4 scope:local data:4byte +skSamusBallFrozen = .sbss:0x805A8EF8; // type:object size:0x4 scope:local data:4byte lbl_805A8EFC = .sbss:0x805A8EFC; // type:object size:0x1 data:byte mInstance__20CConsoleOutputWindow = .sbss:0x805A8F00; // type:object size:0x4 scope:global data:4byte lbl_805A8F08 = .sbss:0x805A8F08; // type:object size:0x8 data:byte @@ -22606,14 +22597,14 @@ lbl_805A9DF0 = .sdata2:0x805A9DF0; // type:object size:0x4 align:4 data:float lbl_805A9DF4 = .sdata2:0x805A9DF4; // type:object size:0x4 align:4 data:float lbl_805A9DF8 = .sdata2:0x805A9DF8; // type:object size:0x4 align:4 data:float lbl_805A9DFC = .sdata2:0x805A9DFC; // type:object size:0x4 align:4 data:float -lbl_805A9E00 = .sdata2:0x805A9E00; // type:object size:0x1 data:byte -lbl_805A9E01 = .sdata2:0x805A9E01; // type:object size:0x1 data:byte -lbl_805A9E02 = .sdata2:0x805A9E02; // type:object size:0x1 data:byte -lbl_805A9E04 = .sdata2:0x805A9E04; // type:object size:0x4 align:4 data:float -lbl_805A9E08 = .sdata2:0x805A9E08; // type:object size:0x1 data:byte -lbl_805A9E09 = .sdata2:0x805A9E09; // type:object size:0x1 data:byte -lbl_805A9E0C = .sdata2:0x805A9E0C; // type:object size:0x4 align:4 data:float -lbl_805A9E10 = .sdata2:0x805A9E10; // type:object size:0x4 align:4 data:float +gkAutoAim = .sdata2:0x805A9E00; // type:object size:0x1 data:byte +gkAutoAimAtOrbitedObject = .sdata2:0x805A9E01; // type:object size:0x1 data:byte +gkFreeLookPreventsOrbitMovement = .sdata2:0x805A9E02; // type:object size:0x1 data:byte +gkSpiderBallControllerActivationPercentage = .sdata2:0x805A9E04; // type:object size:0x4 align:4 data:float +gkWorldOnlyReflection = .sdata2:0x805A9E08; // type:object size:0x1 data:byte +gkUseNewPlayerMovement = .sdata2:0x805A9E09; // type:object size:0x1 data:byte +gkFirstPersonDeathTime = .sdata2:0x805A9E0C; // type:object size:0x4 align:4 data:float +gkBallDeathTime = .sdata2:0x805A9E10; // type:object size:0x4 align:4 data:float kGunLocator = .sdata2:0x805A9E14; // type:object size:0x4 data:4byte skDefaultHudFadeOutSpeed__7CPlayer = .sdata2:0x805A9E18; // type:object size:0x4 scope:global align:4 data:float skDefaultHudFadeInSpeed__7CPlayer = .sdata2:0x805A9E1C; // type:object size:0x4 scope:global align:4 data:float @@ -23535,10 +23526,10 @@ lbl_805AAE60 = .sdata2:0x805AAE60; // type:object size:0x4 align:4 data:float lbl_805AAE64 = .sdata2:0x805AAE64; // type:object size:0x4 align:4 data:float lbl_805AAE68 = .sdata2:0x805AAE68; // type:object size:0x4 align:4 data:float lbl_805AAE6C = .sdata2:0x805AAE6C; // type:object size:0x4 align:4 data:float -lbl_805AAE70 = .sdata2:0x805AAE70; // type:object size:0x4 align:4 data:float +@802 = .sdata2:0x805AAE70; // type:object size:0x4 scope:local align:4 data:float lbl_805AAE74 = .sdata2:0x805AAE74; // type:object size:0x4 align:4 data:float lbl_805AAE78 = .sdata2:0x805AAE78; // type:object size:0x4 align:4 data:float -lbl_805AAE7C = .sdata2:0x805AAE7C; // type:object size:0x4 align:4 data:float +@1619 = .sdata2:0x805AAE7C; // type:object size:0x4 scope:local align:4 data:float lbl_805AAE80 = .sdata2:0x805AAE80; // type:object size:0x4 lbl_805AAE84 = .sdata2:0x805AAE84; // type:object size:0x4 lbl_805AAE88 = .sdata2:0x805AAE88; // type:object size:0x4 align:4 data:float @@ -23570,7 +23561,7 @@ lbl_805AAEF8 = .sdata2:0x805AAEF8; // type:object size:0x4 align:4 data:float lbl_805AAEFC = .sdata2:0x805AAEFC; // type:object size:0x4 align:4 data:float lbl_805AAF00 = .sdata2:0x805AAF00; // type:object size:0x4 align:4 data:float lbl_805AAF04 = .sdata2:0x805AAF04; // type:object size:0x4 align:4 data:float -lbl_805AAF08 = .sdata2:0x805AAF08; // type:object size:0x4 align:4 data:float +@1623 = .sdata2:0x805AAF08; // type:object size:0x4 scope:local align:4 data:float lbl_805AAF0C = .sdata2:0x805AAF0C; // type:object size:0x4 align:4 data:float lbl_805AAF10 = .sdata2:0x805AAF10; // type:object size:0x4 align:4 data:float lbl_805AAF14 = .sdata2:0x805AAF14; // type:object size:0x4 align:4 data:float @@ -23644,7 +23635,7 @@ lbl_805AB03C = .sdata2:0x805AB03C; // type:object size:0x4 align:4 data:float lbl_805AB040 = .sdata2:0x805AB040; // type:object size:0x4 align:4 data:float lbl_805AB044 = .sdata2:0x805AB044; // type:object size:0x4 align:4 data:float lbl_805AB048 = .sdata2:0x805AB048; // type:object size:0x4 align:4 data:float -lbl_805AB050 = .sdata2:0x805AB050; // type:object size:0x8 align:8 data:double +@1622 = .sdata2:0x805AB050; // type:object size:0x8 scope:local align:8 data:double lbl_805AB058 = .sdata2:0x805AB058; // type:object size:0x4 align:4 data:float lbl_805AB05C = .sdata2:0x805AB05C; // type:object size:0x4 align:4 data:float lbl_805AB060 = .sdata2:0x805AB060; // type:object size:0x4 align:4 data:float @@ -23691,7 +23682,7 @@ lbl_805AB100 = .sdata2:0x805AB100; // type:object size:0x8 align:4 data:float @465 = .sdata2:0x805AB114; // type:object size:0x4 scope:local align:4 data:float @466 = .sdata2:0x805AB118; // type:object size:0x4 scope:local align:4 data:float @467 = .sdata2:0x805AB11C; // type:object size:0x4 scope:local align:4 data:float -lbl_805AB120 = .sdata2:0x805AB120; // type:object size:0x4 data:4byte +kInvalidShadowLightIndex__12CActorLights = .sdata2:0x805AB120; // type:object size:0x4 data:4byte kDefaultPositionUpdateThreshold__12CActorLights = .sdata2:0x805AB124; // type:object size:0x4 scope:global align:4 data:float lbl_805AB128 = .sdata2:0x805AB128; // type:object size:0x4 align:4 data:float lbl_805AB12C = .sdata2:0x805AB12C; // type:object size:0x4 align:4 data:float @@ -26659,11 +26650,11 @@ lbl_805AE608 = .sdata2:0x805AE608; // type:object size:0x8 align:4 data:float @269 = .sdata2:0x805AE638; // type:object size:0x4 scope:local align:4 data:float @270 = .sdata2:0x805AE63C; // type:object size:0x4 scope:local align:4 data:float @308 = .sdata2:0x805AE640; // type:object size:0x4 scope:local align:4 data:float -lbl_805AE648 = .sdata2:0x805AE648; // type:object size:0x4 align:4 data:float -lbl_805AE64C = .sdata2:0x805AE64C; // type:object size:0x4 align:4 data:float -lbl_805AE650 = .sdata2:0x805AE650; // type:object size:0x4 align:4 data:float -lbl_805AE654 = .sdata2:0x805AE654; // type:object size:0x4 align:4 data:float -lbl_805AE658 = .sdata2:0x805AE658; // type:object size:0x4 align:4 data:float +skArcCosX1 = .sdata2:0x805AE648; // type:object size:0x4 align:4 data:float +skArcCosX2 = .sdata2:0x805AE64C; // type:object size:0x4 align:4 data:float +skArcCosX3 = .sdata2:0x805AE650; // type:object size:0x4 align:4 data:float +skArcCosX4 = .sdata2:0x805AE654; // type:object size:0x4 align:4 data:float +skArcCosX5 = .sdata2:0x805AE658; // type:object size:0x4 align:4 data:float lbl_805AE660 = .sdata2:0x805AE660; // type:object size:0x8 align:8 data:double skCosX1 = .sdata2:0x805AE668; // type:object size:0x4 align:4 data:float skCosX2 = .sdata2:0x805AE66C; // type:object size:0x4 align:4 data:float @@ -26676,10 +26667,10 @@ lbl_805AE68C = .sdata2:0x805AE68C; // type:object size:0x4 align:4 data:float lbl_805AE690 = .sdata2:0x805AE690; // type:object size:0x4 align:4 data:float lbl_805AE694 = .sdata2:0x805AE694; // type:object size:0x4 align:4 data:float lbl_805AE698 = .sdata2:0x805AE698; // type:object size:0x8 align:8 data:double -lbl_805AE6A0 = .sdata2:0x805AE6A0; // type:object size:0x4 align:4 data:float -lbl_805AE6A4 = .sdata2:0x805AE6A4; // type:object size:0x4 align:4 data:float -lbl_805AE6A8 = .sdata2:0x805AE6A8; // type:object size:0x4 align:4 data:float -lbl_805AE6AC = .sdata2:0x805AE6AC; // type:object size:0x4 align:4 data:float +skSinX1 = .sdata2:0x805AE6A0; // type:object size:0x4 align:4 data:float +skSinX2 = .sdata2:0x805AE6A4; // type:object size:0x4 align:4 data:float +skSinX3 = .sdata2:0x805AE6A8; // type:object size:0x4 align:4 data:float +skSinX4 = .sdata2:0x805AE6AC; // type:object size:0x4 align:4 data:float lbl_805AE6B0 = .sdata2:0x805AE6B0; // type:object size:0x4 align:4 data:float lbl_805AE6B4 = .sdata2:0x805AE6B4; // type:object size:0x4 align:4 data:float lbl_805AE6B8 = .sdata2:0x805AE6B8; // type:object size:0x4 align:4 data:float diff --git a/config/GM8E01_01/symbols.txt b/config/GM8E01_01/symbols.txt index fb20c5b2..2c2e5f84 100644 --- a/config/GM8E01_01/symbols.txt +++ b/config/GM8E01_01/symbols.txt @@ -1060,7 +1060,7 @@ BuildDynamicLightListForWorld__13CStateManagerFv = .text:0x800457FC; // type:fun push_back__Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>FRC6CLight = .text:0x80045A40; // type:function size:0x7C scope:global fn_80045A40 = .text:0x80045ABC; // type:function size:0x28 scope:global __as__Q24rstl42vector<6CLight,Q24rstl17rmemory_allocator>FRCQ24rstl42vector<6CLight,Q24rstl17rmemory_allocator> = .text:0x80045AE4; // type:function size:0xD4 scope:global -uninitialized_copy__4rstlFPC6CLightPC6CLightP6CLight = .text:0x80045BB8; // type:function size:0x64 scope:global +uninitialized_copy__4rstlFP6CLightP6CLightP6CLight = .text:0x80045BB8; // type:function size:0x64 scope:global DrawDebugStuff__13CStateManagerCFv = .text:0x80045C1C; // type:function size:0x4 scope:global RenderCamerasAndAreaLights__13CStateManagerCFv = .text:0x80045C20; // type:function size:0x5C scope:global DrawE3DeathEffect__13CStateManagerCFv = .text:0x80045C7C; // type:function size:0x164 scope:global @@ -1144,7 +1144,7 @@ CalculateObjectBounds__13CStateManagerFRC6CActor = .text:0x8004C99C; // type:fun AddObject__13CStateManagerFR7CEntity = .text:0x8004CB90; // type:function size:0x1E0 scope:global AddObject__13CStateManagerFP7CEntity = .text:0x8004CD70; // type:function size:0x28 scope:global fn_8004CD1C = .text:0x8004CD98; // type:function size:0x14 scope:global -RayCollideWorldInternal__13CStateManagerRC9CVector3fRC9CVector3fRC15CMaterialFilterRCQ24rstl49reserved_vector<9TUniqueId,1024>RC6CActor = .text:0x8004CDAC; // type:function size:0x10C scope:global +RayCollideWorldInternal__13CStateManagerCFRC9CVector3fRC9CVector3fRC15CMaterialFilterRCQ24rstl32reserved_vector<9TUniqueId,1024>PC6CActor = .text:0x8004CDAC; // type:function size:0x10C scope:global RayCollideWorld__13CStateManagerFRC9CVector3fRC9CVector3fRC15CMaterialFilterPC6CActor = .text:0x8004CEB8; // type:function size:0x130 scope:global RayCollideWorld__13CStateManagerCFRC9CVector3fRC9CVector3fRCQ24rstl32reserved_vector<9TUniqueId,1024>RC15CMaterialFilterPC6CActor = .text:0x8004CFE8; // type:function size:0x2C scope:global RayStaticIntersection__13CStateManagerCFRC9CVector3fRC9CVector3ffRC15CMaterialFilter = .text:0x8004D014; // type:function size:0x2C scope:global @@ -1157,8 +1157,8 @@ __dt__22CStateManagerContainerFv = .text:0x8004D780; // type:function size:0x20C __dt__14CCameraManagerFv = .text:0x8004D98C; // type:function size:0x1B4 scope:global __dt__18CFluidPlaneManagerFv = .text:0x8004DB40; // type:function size:0xF8 scope:global __dt__13CEnvFxManagerFv = .text:0x8004DC38; // type:function size:0x184 scope:global -fn_8004DD40 = .text:0x8004DDBC; // type:function size:0x50 scope:global -fn_8004DD90 = .text:0x8004DE0C; // type:function size:0x68 scope:global +__dt__Q24rstl39reserved_vector<17CEnvFxManagerGrid,64>Fv = .text:0x8004DDBC; // type:function size:0x50 scope:global +clear__Q24rstl39reserved_vector<17CEnvFxManagerGrid,64>Fv = .text:0x8004DE0C; // type:function size:0x68 scope:global fn_8004DDF8 = .text:0x8004DE74; // type:function size:0x6C scope:global __dt__20CActorModelParticlesFv = .text:0x8004DEE0; // type:function size:0xE8 scope:global fn_8004DF4C = .text:0x8004DFC8; // type:function size:0x50 scope:global @@ -7366,7 +7366,7 @@ fn_80148F0C = .text:0x80148F88; // type:function size:0x98 scope:global fn_80148FA4 = .text:0x80149020; // type:function size:0xB4 scope:global fn_80149058 = .text:0x801490D4; // type:function size:0x8C scope:global reserve__Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>Fi = .text:0x80149160; // type:function size:0xE8 scope:global -uninitialized_copy,Q24rstl17rmemory_allocator>,11CElementGen>__4rstlFQ24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P11CElementGen = .text:0x80149248; // type:function size:0x68 scope:global +uninitialized_copy,Q24rstl17rmemory_allocator>,P11CElementGen>__4rstlFQ24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl116pointer_iterator<11CElementGen,Q24rstl48vector<11CElementGen,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>P11CElementGen = .text:0x80149248; // type:function size:0x68 scope:global fn_80149234 = .text:0x801492B0; // type:function size:0x7C scope:global __dt__8CBSTauntFv = .text:0x8014932C; // type:function size:0x5C scope:global GetBodyStateTransition__8CBSTauntFfR15CBodyController = .text:0x80149388; // type:function size:0xD4 scope:global @@ -21324,7 +21324,7 @@ lbl_805A8A21 = .sdata:0x805A8A21; // type:object size:0x1 data:byte lbl_805A8A22 = .sdata:0x805A8A22; // type:object size:0x1 data:byte lbl_805A8A24 = .sdata:0x805A8A24; // type:object size:0x4 align:4 data:float lbl_805A8A28 = .sdata:0x805A8A28; // type:object size:0x4 -lbl_805A8A2C = .sdata:0x805A8A2C; // type:object size:0x2 data:string +lbl_805A8A2C = .sdata:0x805A8A2C; // type:object size:0x4 data:4byte lbl_805A8A30 = .sdata:0x805A8A30; // type:object size:0x4 lbl_805A8A34 = .sdata:0x805A8A34; // type:object size:0x4 lbl_805A8A38 = .sdata:0x805A8A38; // type:object size:0x4 align:4 data:float @@ -23595,7 +23595,7 @@ lbl_805AB2E0 = .sdata2:0x805AB2E0; // type:object size:0x8 align:4 data:float @414 = .sdata2:0x805AB2F4; // type:object size:0x4 scope:local align:4 data:float @415 = .sdata2:0x805AB2F8; // type:object size:0x4 scope:local align:4 data:float @416 = .sdata2:0x805AB2FC; // type:object size:0x4 scope:local align:4 data:float -lbl_805AB300 = .sdata2:0x805AB300; // type:object size:0x4 data:4byte +kInvalidShadowLightIndex__12CActorLights = .sdata2:0x805AB300; // type:object size:0x4 data:4byte kDefaultPositionUpdateThreshold__12CActorLights = .sdata2:0x805AB304; // type:object size:0x4 align:4 data:float lbl_805AB308 = .sdata2:0x805AB308; // type:object size:0x4 align:4 data:float lbl_805AB30C = .sdata2:0x805AB30C; // type:object size:0x4 align:4 data:float diff --git a/config/GM8E01_48/splits.txt b/config/GM8E01_48/splits.txt index 334ddac1..7bee7a83 100644 --- a/config/GM8E01_48/splits.txt +++ b/config/GM8E01_48/splits.txt @@ -1100,7 +1100,7 @@ musyx/runtime/hardware.c: musyx/runtime/dsp_import.c: .data start:0x803F4760 end:0x803F6140 - .sdata start:0x805A88C0 end:0x805A88C4 + .sdata start:0x805A88C0 end:0x805A88C8 musyx/runtime/hw_aramdma.c: .text start:0x803B4074 end:0x803B4D40 @@ -1162,7 +1162,7 @@ Dolphin/card/CARDBios.c: Dolphin/card/CARDUnlock.c: .text start:0x803B9190 end:0x803BA3F0 .data start:0x803F69E0 end:0x803F6B40 - .sdata start:0x805A88D0 end:0x805A88D4 + .sdata start:0x805A88D0 end:0x805A88D8 Dolphin/card/CARDRdwr.c: .text start:0x803BA3F0 end:0x803BA670 @@ -1206,7 +1206,7 @@ Dolphin/card/CARDRename.c: Dolphin/card/CARDNet.c: .text start:0x803BE6EC end:0x803BE7B0 - .sdata start:0x805A88D8 end:0x805A88DC + .sdata start:0x805A88D8 end:0x805A88E0 Dolphin/si/SIBios.c: .text start:0x803BE7B0 end:0x803C0010 @@ -1222,7 +1222,7 @@ Dolphin/si/SISamplingRate.c: Dolphin/exi/EXIBios.c: .text start:0x803C0118 end:0x803C19F4 - .data start:0x803F6D30 end:0x803F6DFC + .data start:0x803F6D30 end:0x803F6E00 .bss start:0x80569B78 end:0x80569C38 .sdata start:0x805A88E8 end:0x805A88EC diff --git a/config/GM8E01_48/symbols.txt b/config/GM8E01_48/symbols.txt index 5dcba6e9..0c3dc5c5 100644 --- a/config/GM8E01_48/symbols.txt +++ b/config/GM8E01_48/symbols.txt @@ -14060,7 +14060,7 @@ construct__4rstlFPvRCQ215CParticleSwoosh11SSwo __ct__Q215CParticleSwoosh11SSwooshDataFRCQ215CParticleSwoosh11SSwooshData = .text:0x8032F7D4; // type:function size:0xE4 __ct__Q215CParticleSwoosh11SSwooshDataFRC9CVector3fRC9CVector3fffibRC12CTransform4fRC9CVector3fffRC6CColor = .text:0x8032F8B8; // type:function size:0xDC reserve__Q24rstl67vectorFi = .text:0x8032F994; // type:function size:0xD8 -uninitialized_copy,Q24rstl17rmemory_allocator>,Q215CParticleSwoosh11SSwooshData>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator>PQ215CParticleSwoosh11SSwooshData = .text:0x8032FA6C; // type:function size:0x68 +uninitialized_copy,Q24rstl17rmemory_allocator>,PQ215CParticleSwoosh11SSwooshData>__4rstlFQ24rstl154pointer_iterator,Q24rstl17rmemory_allocator>Q24rstl154pointer_iterator,Q24rstl17rmemory_allocator>PQ215CParticleSwoosh11SSwooshData = .text:0x8032FA6C; // type:function size:0x68 CreateWPSM__26CParticleSwooshDataFactoryFP18CSwooshDescriptionR12CInputStreamP11CSimplePool = .text:0x8032FAD4; // type:function size:0x4DC CreateGeneratorDescription__26CParticleSwooshDataFactoryFR12CInputStreamP11CSimplePool = .text:0x8032FFB0; // type:function size:0x8C GetGeneratorDesc__26CParticleSwooshDataFactoryFR12CInputStreamP11CSimplePool = .text:0x8033003C; // type:function size:0x84 diff --git a/configure.py b/configure.py index 34f2321a..fa8606a3 100755 --- a/configure.py +++ b/configure.py @@ -182,10 +182,10 @@ if not config.non_matching: # Tool versions config.binutils_tag = "2.42-1" config.compilers_tag = "20251118" -config.dtk_tag = "v1.8.0" -config.objdiff_tag = "v3.0.1" +config.dtk_tag = "v1.8.3" +config.objdiff_tag = "v3.7.0" config.sjiswrap_tag = "v1.2.2" -config.wibo_tag = "1.0.0" +config.wibo_tag = "1.0.3" # Project config.config_path = Path("config") / config.version / "config.yml" @@ -1491,7 +1491,7 @@ config.libs = [ Object(MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/Math/CVector3d.cpp"), Object(MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/Math/CVector3f.cpp"), Object(MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/Math/CVector3i.cpp"), - Object(NonMatching, "Kyoto/Math/RMathUtils.cpp"), + Object(MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/Math/RMathUtils.cpp"), Object(MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/CCrc32.cpp"), Object( MatchingFor("GM8E01_00", "GM8E01_01"), "Kyoto/Alloc/CCircularBuffer.cpp" diff --git a/include/Collision/CCollidableSphere.hpp b/include/Collision/CCollidableSphere.hpp index 7ea1f59a..c71dfdfb 100644 --- a/include/Collision/CCollidableSphere.hpp +++ b/include/Collision/CCollidableSphere.hpp @@ -11,6 +11,8 @@ class CCollidableSphere : public CCollisionPrimitive { public: CCollidableSphere(const CSphere& sphere, const CMaterialList& material) : CCollisionPrimitive(material), x10_sphere(sphere) {} + CCollidableSphere(const CCollidableSphere& other) + : CCollisionPrimitive(other), x10_sphere(other.x10_sphere) {} static bool CollideMovingAABox(const CInternalCollisionStructure& collision, const CVector3f& dir, double& dOut, CCollisionInfo& infoOut); @@ -23,6 +25,7 @@ public: FourCC GetPrimType() const override; CSphere Transform(const CTransform4f& xf) const; const CSphere& GetSphere() const { return x10_sphere; } + void SetSphereCenter(const CVector3f& center) { x10_sphere = CSphere(center, x10_sphere.GetRadius()); } ~CCollidableSphere() override {} CRayCastResult CastRayInternal(const CInternalRayCastStructure& internalRayCast) const override; diff --git a/include/Collision/CCollisionInfoList.hpp b/include/Collision/CCollisionInfoList.hpp index 7aa4d7ea..55232fef 100644 --- a/include/Collision/CCollisionInfoList.hpp +++ b/include/Collision/CCollisionInfoList.hpp @@ -38,8 +38,6 @@ public: const_iterator End() const { return x0_list.end(); } iterator Begin() { return x0_list.begin(); } const_iterator Begin() const { return x0_list.begin(); } - - CCollisionInfoList& operator=(const CCollisionInfoList& other); }; #endif // _CCOLLISIONINFOLIST diff --git a/include/Collision/CCollisionPrimitive.hpp b/include/Collision/CCollisionPrimitive.hpp index 17473250..e6caa4f6 100644 --- a/include/Collision/CCollisionPrimitive.hpp +++ b/include/Collision/CCollisionPrimitive.hpp @@ -88,6 +88,7 @@ public: }; CCollisionPrimitive(const CMaterialList& list); + CCollisionPrimitive(const CCollisionPrimitive& other) : x8_material(other.x8_material) {} virtual uint GetTableIndex() const = 0; virtual void SetMaterial(const CMaterialList& other) { x8_material = other; } diff --git a/include/Collision/CMaterialList.hpp b/include/Collision/CMaterialList.hpp index fdcc2d93..384c46ad 100644 --- a/include/Collision/CMaterialList.hpp +++ b/include/Collision/CMaterialList.hpp @@ -121,6 +121,9 @@ public: return (other.value & value) ? true : false; } + // TODO: fake? + u64 GetValue() const { return value; } + private: u64 value; diff --git a/include/Collision/CollisionUtil.hpp b/include/Collision/CollisionUtil.hpp index 9623a10e..c480435d 100644 --- a/include/Collision/CollisionUtil.hpp +++ b/include/Collision/CollisionUtil.hpp @@ -7,6 +7,7 @@ class CCollisionInfoList; class CVector3f; class CSphere; class CMRay; +class CPlane; namespace CollisionUtil { @@ -23,7 +24,7 @@ bool TriSphereOverlap(const CSphere&, const CVector3f&, const CVector3f&, const bool TriSphereIntersection(const CSphere&, const CVector3f&, const CVector3f&, const CVector3f&, CVector3f&, CVector3f&); double TriPointSqrDist(const CVector3f&, const CVector3f&, const CVector3f&, const CVector3f&, - float*, float*); + float*, float*); bool AABoxAABoxIntersection(const CAABox& left, const CAABox& right); bool AABoxAABoxIntersection(const CAABox& left, const CMaterialList& leftFilter, @@ -32,10 +33,10 @@ bool AABoxAABoxIntersection(const CAABox& left, const CMaterialList& leftFilter, bool AABoxSphereIntersection(const CAABox&, const CSphere&); float AABoxSphereIntersectionRadius(const CAABox&, const CSphere&); bool RayTriangleIntersection(const CVector3f&, const CVector3f&, const CVector3f*, float&); -bool RayTriangleIntersection_Double(const CVector3f&, const CVector3f&, const CVector3f*, - double&); +bool RayTriangleIntersection_Double(const CVector3f&, const CVector3f&, const CVector3f*, double&); int RayAABoxIntersection(const CMRay& ray, const CAABox& box, float& tMin, float& tMax); -int RayAABoxIntersection_Double(const CMRay& ray, const CAABox& box, CVector3f& dir, double& penetration); +int RayAABoxIntersection_Double(const CMRay& ray, const CAABox& box, CVector3f& dir, + double& penetration); int RayAABoxIntersection(const CMRay& ray, const CAABox& box, CVector3f& dir, float& penetration); bool AABox_AABox_Moving(const CAABox& left, const CAABox& right, const CVector3f& dir, double& d, CVector3f& point, CVector3f& normal); @@ -47,6 +48,8 @@ bool RaySphereIntersection_Double(const CSphere& sphere, const CVector3f& pos, c double& T); bool RaySphereIntersection(const CSphere& sphere, const CVector3f& pos, const CVector3f& dir, float mag, float& T, CVector3f& point); +bool RayPlaneIntersection(const CVector3f& from, const CVector3f& to, const CPlane& plane, + CVector3f& point); // Global function defined in either CBallFilter or an unknown TU, name unknown. // Called by CNewFlameThrower. diff --git a/include/Kyoto/Graphics/CLight.hpp b/include/Kyoto/Graphics/CLight.hpp index 33fe0c29..b9379421 100644 --- a/include/Kyoto/Graphics/CLight.hpp +++ b/include/Kyoto/Graphics/CLight.hpp @@ -25,7 +25,6 @@ public: const CColor& color, float cutoff); CLight(const CVector3f& pos, const CVector3f& direction, const CColor& color, float distC, float distL, float distQ, float angleC, float angleL, float angleQ); - CLight(const CLight&); void SetPosition(const CVector3f& pos); const CVector3f& GetPosition() const { return x0_pos; } diff --git a/include/Kyoto/Math/CMath.hpp b/include/Kyoto/Math/CMath.hpp index ed988026..12de6c3e 100644 --- a/include/Kyoto/Math/CMath.hpp +++ b/include/Kyoto/Math/CMath.hpp @@ -3,8 +3,8 @@ #include "types.h" -#include "math.h" #include "float.h" +#include "math.h" #include @@ -21,7 +21,11 @@ public: template < typename T > static const T& Clamp(const T& min, const T& val, const T& max); static float SqrtF(float v); - static inline float Limit(float v, float h) { if (fabs(v) > h) return h * Sign(v); return v; } + static inline float Limit(float v, float h) { + if (fabs(v) > h) + return h * Sign(v); + return v; + } static inline float Sign(float v) { return FastFSel(v, 1.f, -1.f); } #ifdef __MWERKS__ static inline float FastFSel(register float v, register float h, register float l) { @@ -37,7 +41,16 @@ public: static inline float AbsF(float v) { return fabs(v); } static inline double AbsD(double v) { return fabs(v); } static inline int AbsI(int v) { return abs(v); } - // WrapPi__5CMathFf weak + static inline float WrapPi(float rad) { + float value = FastFmod(rad, M_2PIF); + if (value > M_PIF) { + return value - M_2PIF; + } else if (value < -M_PIF) { + return value + M_2PIF; + } else { + return value; + } + } // WrapTwoPi__5CMathFf weak template < typename T > static const T& Min(const T& a, const T& b); diff --git a/include/Kyoto/Math/CQuaternion.hpp b/include/Kyoto/Math/CQuaternion.hpp index f262d32c..59443fbb 100644 --- a/include/Kyoto/Math/CQuaternion.hpp +++ b/include/Kyoto/Math/CQuaternion.hpp @@ -32,7 +32,7 @@ public: // __amu__11CQuaternionFRC11CQuaternion // ScalarVector__11CQuaternionFfRC9CVector3f // Slerp__11CQuaternionFRC11CQuaternionRC11CQuaternionf - // ShortestRotationArc__11CQuaternionFRC9CVector3fRC9CVector3f + static CQuaternion ShortestRotationArc(const CVector3f&, const CVector3f&); // TODO: map says const CUnitVector3f&, but this matches better in CBSCover/CSamusFaceReflection static CQuaternion LookAt(CUnitVector3f, CUnitVector3f, const CRelAngle&); diff --git a/include/Kyoto/Particles/CElementGen.hpp b/include/Kyoto/Particles/CElementGen.hpp index c3457001..00d52e76 100644 --- a/include/Kyoto/Particles/CElementGen.hpp +++ b/include/Kyoto/Particles/CElementGen.hpp @@ -66,7 +66,7 @@ public: virtual CVector3f GetGlobalTranslation() const override; virtual CVector3f GetGlobalScale() const override; virtual bool GetParticleEmission() const override; - virtual CColor GetModulationColor() const override; + virtual const CColor& GetModulationColor() const override; virtual bool IsSystemDeletable() const override; virtual rstl::optional_object< CAABox > GetBounds() const override; virtual int GetParticleCount() const override; @@ -79,6 +79,7 @@ public: int GetEmitterTime() const; int GetSystemCount(); void EndLifetime(); + void ForceParticleCreation(int amount); int GetNumActiveChildParticles() const; CParticleGen* GetActiveChildParticle(int index) const; diff --git a/include/Kyoto/Particles/CParticleElectric.hpp b/include/Kyoto/Particles/CParticleElectric.hpp index f8d1b243..64caa8d4 100644 --- a/include/Kyoto/Particles/CParticleElectric.hpp +++ b/include/Kyoto/Particles/CParticleElectric.hpp @@ -30,7 +30,7 @@ public: CVector3f GetGlobalTranslation() const override; CVector3f GetGlobalScale() const override; bool GetParticleEmission() const override; - CColor GetModulationColor() const override; + const CColor& GetModulationColor() const override; bool IsSystemDeletable() const override; rstl::optional_object< CAABox > GetBounds() const override; int GetParticleCount() const override; diff --git a/include/Kyoto/Particles/CParticleGen.hpp b/include/Kyoto/Particles/CParticleGen.hpp index fdc72842..1adaba16 100644 --- a/include/Kyoto/Particles/CParticleGen.hpp +++ b/include/Kyoto/Particles/CParticleGen.hpp @@ -32,7 +32,7 @@ public: virtual CVector3f GetGlobalTranslation() const = 0; virtual CVector3f GetGlobalScale() const = 0; virtual bool GetParticleEmission() const = 0; - virtual CColor GetModulationColor() const = 0; + virtual const CColor& GetModulationColor() const = 0; virtual float GetGeneratorRate() const { return 1.f; } virtual bool IsSystemDeletable() const = 0; virtual rstl::optional_object< CAABox > GetBounds() const = 0; diff --git a/include/Kyoto/Particles/CParticleSwoosh.hpp b/include/Kyoto/Particles/CParticleSwoosh.hpp index d0ac0172..6d512ba6 100644 --- a/include/Kyoto/Particles/CParticleSwoosh.hpp +++ b/include/Kyoto/Particles/CParticleSwoosh.hpp @@ -66,7 +66,7 @@ public: CVector3f GetGlobalTranslation() const; CVector3f GetGlobalScale() const; bool GetParticleEmission() const; - CColor GetModulationColor() const; + const CColor& GetModulationColor() const; bool IsSystemDeletable() const; rstl::optional_object< CAABox > GetBounds() const; int GetParticleCount() const; diff --git a/include/Kyoto/TReservedAverage.hpp b/include/Kyoto/TReservedAverage.hpp index 56dfb22a..707bae24 100644 --- a/include/Kyoto/TReservedAverage.hpp +++ b/include/Kyoto/TReservedAverage.hpp @@ -12,9 +12,7 @@ template < typename T, int N > class TReservedAverage : public rstl::reserved_vector< T, N > { public: TReservedAverage() {} - TReservedAverage(const T& value) { - // resize(value, N); TODO - } + TReservedAverage(const T& value) { this->resize(N, value); } void AddValue(const T& value); rstl::optional_object< T > GetAverage() const; rstl::optional_object< T > GetEntry(int idx) const; diff --git a/include/MetroidPrime/CActorLights.hpp b/include/MetroidPrime/CActorLights.hpp index bf6a36be..b6ebb155 100644 --- a/include/MetroidPrime/CActorLights.hpp +++ b/include/MetroidPrime/CActorLights.hpp @@ -38,10 +38,14 @@ public: uint GetActiveLightCount() const; bool GetNeedsRelight() const { return x298_24_dirty == TRUE; } - bool HasShadowLight() const { return x29c_shadowLightArrIdx != -1; } + bool HasShadowLight() const { return x29c_shadowLightArrIdx != kInvalidShadowLightIndex; } + const TAreaId GetAreaLightIndexForShadowLight() const { return x29c_shadowLightArrIdx; } + uint GetShadowLightArrIndex() const { return x29c_shadowLightArrIdx; } int GetShadowLightIndex() const { return x2a0_shadowLightIdx; } + const CVector3f& GetAmbientColor() const { return x288_ambientColor; } void SetAmbientColor(const CColor& color); + void SetNeedsRelight(bool v) { x298_24_dirty = v; } void SetCastShadows(bool v) { x298_25_castShadows = v; } void SetFindShadowLight(bool v) { x298_27_findShadowLight = v; } void SetShadowDynamicRangeThreshold(float t) { x2d0_shadowDynamicRangeThreshold = t; } @@ -74,7 +78,7 @@ private: bool x299_25_useBrightLightLag : 1; bool x299_26_ambientOnly : 1; bool x29a_findNearestDynamicLights; - int x29c_shadowLightArrIdx; + uint x29c_shadowLightArrIdx; int x2a0_shadowLightIdx; uint x2a4_lastUpdateFrame; uint x2a8_areaUpdateFramePeriod; @@ -87,6 +91,8 @@ private: float x2d4_worldLightingLevel; int x2d8_brightLightIdx; uint x2dc_brightLightLag; + + static int kInvalidShadowLightIndex; }; CHECK_SIZEOF(CActorLights, 0x2e0) diff --git a/include/MetroidPrime/CActorModelParticles.hpp b/include/MetroidPrime/CActorModelParticles.hpp index 27a65c01..42919e8d 100644 --- a/include/MetroidPrime/CActorModelParticles.hpp +++ b/include/MetroidPrime/CActorModelParticles.hpp @@ -132,7 +132,7 @@ private: TToken< CGenDescription > x30_firePop; TToken< CGenDescription > x38_icePop; TToken< CElectricDescription > x40_electric; - TToken< CTexture > x48_ashy; + CToken x48_ashy; rstl::reserved_vector< Dependency, 6 > x50_dgrps; bool xe4_loadingDeps; bool xe5_justLoadedDeps; diff --git a/include/MetroidPrime/CAxisAngle.hpp b/include/MetroidPrime/CAxisAngle.hpp index e8078ce7..8d2401f6 100644 --- a/include/MetroidPrime/CAxisAngle.hpp +++ b/include/MetroidPrime/CAxisAngle.hpp @@ -19,7 +19,6 @@ public: explicit CAxisAngle(const CVector3f& vec); explicit CAxisAngle(const CUnitVector3f& vec, float); CAxisAngle(float x, float y, float z) : mVector(x, y, z) {} - void FromVector(const CVector3f& angle); static const CAxisAngle& Identity(); float GetAngle() const; @@ -28,6 +27,8 @@ public: const CAxisAngle& operator*=(const float& rhs); const CAxisAngle& operator+=(const CAxisAngle& rhs); + static CAxisAngle FromVector(const CVector3f& angle); + private: CVector3f mVector; }; diff --git a/include/MetroidPrime/CModelData.hpp b/include/MetroidPrime/CModelData.hpp index 3a718177..c10e433c 100644 --- a/include/MetroidPrime/CModelData.hpp +++ b/include/MetroidPrime/CModelData.hpp @@ -97,6 +97,7 @@ public: } CAABox GetBounds(const CTransform4f& xf) const; CAABox GetBounds() const; + bool IsInFrustum(const CTransform4f& xf, const CFrustumPlanes& planes) const; bool IsLoaded(int shaderIdx) const; bool IsDefinitelyOpaque(EWhichModel which) const; diff --git a/include/MetroidPrime/CPhysicsActor.hpp b/include/MetroidPrime/CPhysicsActor.hpp index 87f698fc..f2068b9d 100644 --- a/include/MetroidPrime/CPhysicsActor.hpp +++ b/include/MetroidPrime/CPhysicsActor.hpp @@ -131,6 +131,7 @@ public: void SetAngularMomentumWR(const CAxisAngle& angularMomentum) { x108_angularMomentum = angularMomentum; } + const CAxisAngle& GetAngularVelocityWR() const { return x144_angularVelocity; } const CVector3f& GetVelocityWR() const { return x138_velocity; } const CVector3f& GetMomentumWR() const { return x150_momentum; } void SetMomentumWR(const CVector3f& momentum) { x150_momentum = momentum; } diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index 3cbc787f..be4b3419 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -39,6 +39,7 @@ class CPlane; class CGameArea; class CPVSVisSet; class CActorModelParticles; +class CCollisionResponseData; class CCameraManager; class CEnvFxManager; class CFluidPlaneManager; @@ -303,6 +304,9 @@ public: void DrawE3DeathEffect() const; void DrawAdditionalFilters() const; void GetCharacterRenderMaskAndTarget(bool, int&, int&); + void DoCollisionResponse(const CCollisionResponseData& colRespData, + const CRayCastResult& rayCast, TUniqueId uid, + const CWeaponMode& weaponMode, bool w1, bool b1); void DrawDebugStuff() const; // State transitions @@ -334,11 +338,7 @@ public: void SetEnergyBarActorInfo(TUniqueId bossId, float maxEnergy, uint stringIdx) { SetBossParams(bossId, maxEnergy, stringIdx); } - void SetPendingOnScreenTex(CAssetId texId, const CVector2i& origin, const CVector2i& extent); /* { - xef4_pendingScreenTex.x0_id = texId; - xef4_pendingScreenTex.x4_origin = origin; - xef4_pendingScreenTex.xc_extent = extent; - }*/ + void SetPendingOnScreenTex(CAssetId texId, const CVector2i& origin, const CVector2i& extent); const SOnScreenTex& GetPendingScreenTex() const { return xef4_pendingScreenTex; } float IntegrateVisorFog(float f) const; diff --git a/include/MetroidPrime/Enemies/CMetroidBeta.hpp b/include/MetroidPrime/Enemies/CMetroidBeta.hpp index fcd310ad..1b351224 100644 --- a/include/MetroidPrime/Enemies/CMetroidBeta.hpp +++ b/include/MetroidPrime/Enemies/CMetroidBeta.hpp @@ -4,7 +4,8 @@ #include "MetroidPrime/Enemies/CPatterned.hpp" class CMetroidBeta : public CPatterned { - +public: + void RenderHitBallEffect() const; }; #endif // _CMETROIDBETA diff --git a/include/MetroidPrime/Player/CMorphBall.hpp b/include/MetroidPrime/Player/CMorphBall.hpp index bea5fa53..2d9ad5f1 100644 --- a/include/MetroidPrime/Player/CMorphBall.hpp +++ b/include/MetroidPrime/Player/CMorphBall.hpp @@ -57,25 +57,25 @@ public: float GetBallRadius() const; void TakeDamage(float damage); bool IsProjectile() const { return x1954_isProjectile; } - // LeaveMorphBallState__10CMorphBallFR13CStateManager global - // LeaveBoosting__10CMorphBallFv global - // CancelBoosting__10CMorphBallFv global + void LeaveMorphBallState(CStateManager& mgr); + void LeaveBoosting(); + void CancelBoosting(); // InSpiderMode__10CMorphBallCFv weak - // SetAsProjectile__10CMorphBallFRC11CDamageInfoRC11CDamageInfo global - // CollidedWith__10CMorphBallFRC9TUniqueIdRC18CCollisionInfoListR13CStateManager global - // SwitchToMarble__10CMorphBallFv global + void SetAsProjectile(); + void CollidedWith(const TUniqueId&, const CCollisionInfoList&, CStateManager&); + void SwitchToMarble(); bool GetIsInHalfPipeMode() const; - // DampLinearAndAngularVelocities__10CMorphBallFff global - // IsClimbable__10CMorphBallCFRC14CCollisionInfo global + void DampLinearAndAngularVelocities(float linDamp, float angDamp); + bool IsClimbable(const CCollisionInfo&) const; void FluidFXThink(CActor::EFluidState state, CScriptWater& water, CStateManager& mgr); // GetCollidableSphere__10CMorphBallCFv weak // DrawCollisionPrimitive__10CMorphBallCFv global // GetPrimitiveTransform__10CMorphBallCFv global void TouchModel(const CStateManager&) const; void Render(const CStateManager&, const CActorLights*) const; - // RenderDamageEffects__10CMorphBallCFRC13CStateManagerRC12CTransform4f global - // RenderSpiderBallElectricalEffects__10CMorphBallCFv global - // RenderEnergyDrainEffects__10CMorphBallCFRC13CStateManager global + void RenderDamageEffects(const CStateManager&, const CTransform4f&) const; + void RenderSpiderBallElectricalEffects() const; + void RenderEnergyDrainEffects(const CStateManager&) const; void RenderMorphBallTransitionFlash(const CStateManager&) const; const CModelData& GetModel() const { return *x58_ballModel.get(); } // GetBallContactSurfaceNormal__10CMorphBallCFv weak @@ -84,67 +84,81 @@ public: float GetBallTouchRadius() const; void Touch(CActor& actor, CStateManager& mgr); void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); - // DeleteLight__10CMorphBallFR13CStateManager global - // EnterMorphBallState__10CMorphBallFR13CStateManager - // GetSwooshToWorld__10CMorphBallCFv global - // IsMorphBallTransitionFlashValid__10CMorphBallCFv global - // AddSpiderBallElectricalEffect__10CMorphBallFv global - // UpdateSpiderBallElectricalEffects__10CMorphBallFv global - // UpdateMorphBallTransitionFlash__10CMorphBallFf global - // DisableHalfPipeStatus__10CMorphBallFv global - // SetIsInHalfPipeMode__10CMorphBallFb global - // SetIsInHalfPipeModeInAir__10CMorphBallFb global - // SetTouchedHalfPipeRecently__10CMorphBallFb global - // ResetMorphBallTransitionFlash__10CMorphBallFv global - // CreateSpiderBallParticles__10CMorphBallFRC9CVector3fRC9CVector3f global + void DeleteLight(CStateManager& mgr); + void EnterMorphBallState(CStateManager& mgr); + CTransform4f GetSwooshToWorld() const; + bool IsMorphBallTransitionFlashValid() const; + void AddSpiderBallElectricalEffect(); + void UpdateSpiderBallElectricalEffects(); + void UpdateMorphBallTransitionFlash(float); + void DisableHalfPipeStatus(); + void SetIsInHalfPipeMode(bool); + void SetIsInHalfPipeModeInAir(bool); + void SetTouchedHalfPipeRecently(bool); + void ResetMorphBallTransitionFlash(); + void CreateSpiderBallParticles(const CVector3f& ballPos, const CVector3f& trackPoint); ESpiderBallState GetSpiderBallState() const { return x187c_spiderBallState; } - static CModelData* GetMorphballModel(const rstl::string& name, const float radius); + static CModelData* GetMorphBallModel(const rstl::string& name, const float radius); // GetMorphBallModel__10CMorphBallFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator>f // global - // LoadAnimationTokens__10CMorphBallFRCQ24rstl66basic_string,Q24rstl17rmemory_allocator> // global IsBoosting__10CMorphBallCFv weak GetBoostChargeTimer__10CMorphBallCFv weak // GetWallBumpCounter__10CMorphBallCFv weak // GetBallContactMaterials__10CMorphBallCFv weak void ComputeBallMovement(const CFinalInput&, CStateManager&, float); void ComputeBoostBallMovement(const CFinalInput& input, const CStateManager& mgr, float dt); bool IsMovementAllowed() const; - // EnterBoosting__10CMorphBallFv global - // SwitchToTire__10CMorphBallFv global + void EnterBoosting(CStateManager& mgr); + void SwitchToTire(); void ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt); // SetSpiderBallState__10CMorphBallFQ210CMorphBall16ESpiderBallState weak void UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, float dt); bool CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const; - // FindClosestSpiderBallWaypoint__10CMorphBallCFR13CStateManagerRC9CVector3fR9CVector3fR9CVector3fR9CVector3fRfR9CVector3fRbR12CTransform4f + bool FindClosestSpiderBallWaypoint(CStateManager& mgr, const CVector3f& ballCenter, + CVector3f& trackPoint, CVector3f& spiderInterpBetweenPoints, + CVector3f& spiderBetweenPoints, float& distance, + CVector3f& playerToSpiderNormal, bool& isSpiderSurface, + CTransform4f& spiderSurfaceTransform) const; void SetSpiderBallSwingingState(const bool state); bool IsSpiderBallSwinging() const { return x18be_spiderBallSwinging; } - // ResetSpiderBallSwingControllerMovementTimer__10CMorphBallFv global + void ResetSpiderBallSwingControllerMovementTimer(); void ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, float dt); - // GetSpiderBallControllerMovement__10CMorphBallCFRC11CFinalInputbb global - // UpdateSpiderBallSwingControllerMovementTimer__10CMorphBallFff global - // GetSpiderBallSwingControllerMovementScalar__10CMorphBallCFv global + float GetSpiderBallControllerMovement(const CFinalInput& input) const; + void UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt); + float GetSpiderBallSwingControllerMovementScalar() const; void ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt); - // CalculateSpiderBallAttractionSurfaceForces__10CMorphBallCFRC11CFinalInputR13CStateManagerRC12CTransform4f + void ResetSpiderBallForces(); + static CVector3f TransformSpiderBallForcesXZ(CVector2f& forces, CStateManager& mgr); + static CVector3f TransformSpiderBallForcesXY(CVector2f& forces, CStateManager& mgr); + CVector2f CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const; float ForwardInput(const CFinalInput& input) const; - // BallTurnInput__10CMorphBallCFRC11CFinalInput global - // ComputeMaxSpeed__10CMorphBallCFv global + float BallTurnInput(const CFinalInput& input) const; + float ComputeMaxSpeed() const; bool GetIsInHalfPipeModeInAir() const; - // GetTouchedHalfPipeRecently__10CMorphBallCFv global - // ComputeLiftForces__10CMorphBallFRC9CVector3fRC9CVector3fRC13CStateManager global + bool GetTouchedHalfPipeRecently() const; + void ComputeLiftForces(const CVector3f&, const CVector3f&, const CStateManager&); void UpdateBallDynamics(CStateManager&, float); bool BallCloseToCollision(const CStateManager& mgr, float dist, const CMaterialFilter& filter) const; - // UpdateHalfPipeStatus__10CMorphBallFR13CStateManagerf global - // CalculateSurfaceToWorld__10CMorphBallCFRC9CVector3fRC9CVector3fRC9CVector3f global - // UpdateMarbleDynamics__10CMorphBallFR13CStateManagerfRC9CVector3f global - // SpinToSpeed__10CMorphBallFfRC9CVector3ff global - // GetMinimumAlignmentSpeed__10CMorphBallCFv global - // CalculateBallContactInfo__10CMorphBallCFR9CVector3fR9CVector3f global - // CalculateSurfaceFriction__10CMorphBallCFv global - // ApplyFriction__10CMorphBallFf global - // ApplyGravity__10CMorphBallFR13CStateManager global + void UpdateHalfPipeStatus(CStateManager&, float); + CTransform4f CalculateSurfaceToWorld(const CVector3f& trackNormal, const CVector3f& trackPoint, + const CVector3f& ballDir) const; + bool UpdateMarbleDynamics(CStateManager&, float, const CVector3f&); + void SpinToSpeed(float, const CVector3f&, float); + float GetMinimumAlignmentSpeed() const; + bool CalculateBallContactInfo(CVector3f& normal, CVector3f& point) const; + float CalculateSurfaceFriction() const; + void ApplyFriction(float); + void ApplyGravity(CStateManager&); void Land(); void ResetMorphBallIceBreak(); + void UpdateIceBreakEffect(float); + void RenderIceBreakEffect(const CStateManager&) const; void StopParticleWakes(); + void StartLandingSfx(); + void DrawBallShadow(CStateManager&); + void RenderToShadowTex(CStateManager&); + void CreateBallShadow(); + void DeleteBallShadow(); void EnableBallShadow(); void DisableBallShadow(); void PreRenderBallShadow(CStateManager&); @@ -160,9 +174,15 @@ private: uint x4_lifetime; uint x8_curFrame; CSpiderBallElectricityManager(uint effectIdx, uint lifetime) - : x0_effectIdx(effectIdx), x4_lifetime(lifetime) {} + : x0_effectIdx(effectIdx), x4_lifetime(lifetime), x8_curFrame(0) {} }; + void InitializeWakeEffects(); + void LoadAnimationTokens(const rstl::string& name); + void SelectMorphBallSounds(const CMaterialList&); + void UpdateMorphBallSound(float dt); + static void PointGenerator(void*, const CVector3f*, const CVector3f*, int); + CPlayer& x0_player; int x4_loadedModelId; uint x8_ballGlowColorIdx; @@ -181,7 +201,7 @@ private: uint x6c_lowPolyBallModelShader; rstl::single_ptr< CModelData > x70_frozenBallModel; CCollisionInfoList x74_collisionInfos; - char xc78_[0x187c - 0xc78]; + CCollisionInfoList xc78_collisionInfos; ESpiderBallState x187c_spiderBallState; CVector3f x1880_playerToSpiderNormal; float x188c_spiderPullMovement; @@ -231,7 +251,7 @@ private: rstl::single_ptr< CElementGen > x19d8_boostBallGlowGen; rstl::single_ptr< CElementGen > x19dc_morphBallTransitionFlashGen; rstl::single_ptr< CElementGen > x19e0_effect_morphBallIceBreakGen; - rstl::reserved_vector< rstl::pair< rstl::single_ptr< CParticleSwoosh >, bool >, 48 > + rstl::reserved_vector< rstl::pair< rstl::auto_ptr< CParticleSwoosh >, bool >, 32 > x19e4_spiderElectricGens; rstl::list< CSpiderBallElectricityManager > x1b68_activeSpiderElectricList; CRandom16 x1b80_rand; @@ -271,7 +291,7 @@ private: float x1e04_touchHalfPipeRecentCooldown; CVector3f x1e08_prevHalfPipeNormal; CVector3f x1e14_halfPipeNormal; - uint x1e20_ballAnimIdx; + int x1e20_ballAnimIdx; CSfxHandle x1e24_boostSfxHandle; CSfxHandle x1e28_wallHitSfxHandle; CSfxHandle x1e2c_rollSfxHandle; diff --git a/include/MetroidPrime/Player/CMorphBallShadow.hpp b/include/MetroidPrime/Player/CMorphBallShadow.hpp index 185fcccd..a71b5ebd 100644 --- a/include/MetroidPrime/Player/CMorphBallShadow.hpp +++ b/include/MetroidPrime/Player/CMorphBallShadow.hpp @@ -1,9 +1,22 @@ #ifndef _CMORPHBALLSHADOW #define _CMORPHBALLSHADOW +class CAABox; +class CPlayer; +class CStateManager; +class CTexture; +template < typename T > +class TToken; + class CMorphBallShadow { + char x0_pad[0xd4]; + public: - CMorphBallShadow(); + CMorphBallShadow(int, int, const TToken< CTexture >&); ~CMorphBallShadow(); + + void Render(CStateManager&, float); + void RenderIdBuffer(const CAABox&, CStateManager&, CPlayer&); }; + #endif // _CMORPHBALLSHADOW diff --git a/include/MetroidPrime/Player/CPlayer.hpp b/include/MetroidPrime/Player/CPlayer.hpp index ca34cbe7..ecfcaa70 100644 --- a/include/MetroidPrime/Player/CPlayer.hpp +++ b/include/MetroidPrime/Player/CPlayer.hpp @@ -29,6 +29,8 @@ enum EPlayerMovementState { }; class CPlayer : public CPhysicsActor, public TOneStatic< CPlayer > { + friend class CMorphBall; + struct CVisorSteam { float x0_curTargetAlpha; float x4_curAlphaInDur; @@ -203,6 +205,7 @@ public: virtual bool IsTransparent(); CVector3f GetBallPosition() const; + float GetBallMaxVelocity() const; CVector3f GetEyePosition() const; float GetEyeHeight() const; CTransform4f CreateTransformFromMovementDirection() const; @@ -280,7 +283,7 @@ public: void UpdateFreeLookState(const CFinalInput& input, float dt, CStateManager& mgr); void UpdateCameraTimers(float dt, const CFinalInput& input); void UpdateSubmerged(const CStateManager& mgr); - bool CheckSubmerged(); + bool CheckSubmerged() const; void SetMoveState(NPlayer::EPlayerMovementState state, CStateManager& mgr); void StartLandingControlFreeze(); // name? void EndLandingControlFreeze(); // name? @@ -603,4 +606,13 @@ private: }; CHECK_SIZEOF(CPlayer, 0xa38) +extern const bool gkAutoAim; +extern const bool gkAutoAimAtOrbitedObject; +extern const bool gkFreeLookPreventsOrbitMovement; +extern const float gkSpiderBallControllerActivationPercentage; +extern const bool gkWorldOnlyReflection; +extern const bool gkUseNewPlayerMovement; +extern const float gkFirstPersonDeathTime; +extern const float gkBallDeathTime; + #endif // _CPLAYER diff --git a/include/rstl/construct.hpp b/include/rstl/construct.hpp index 22ebef2c..05b8925a 100644 --- a/include/rstl/construct.hpp +++ b/include/rstl/construct.hpp @@ -7,17 +7,17 @@ namespace rstl { template < typename T > -inline void construct(void* dest, const T& src) { +static inline void construct(void* dest, const T& src) { new (dest) T(src); } template < typename T > -inline void destroy(T* in) { +static inline void destroy(T* in) { in->~T(); } template < typename It > -inline void destroy(It begin, It end) { +static inline void destroy(It begin, It end) { It cur = begin; for (; cur != end; ++cur) { destroy(&*cur); @@ -25,8 +25,8 @@ inline void destroy(It begin, It end) { } template < typename It, typename T > -inline T* uninitialized_copy(It begin, It end, T* out) { - T* tmp = out; +static inline T uninitialized_copy(It begin, It end, T out) { + T tmp = out; It cur = begin; for (; cur != end; ++tmp, ++cur) { construct(tmp, *cur); @@ -36,7 +36,7 @@ inline T* uninitialized_copy(It begin, It end, T* out) { } template < typename S, typename D > -inline void uninitialized_copy_n(S src, int n, D dest) { +static inline void uninitialized_copy_n(S src, int n, D dest) { D cur = dest; for (int i = 0; i < n; ++cur, ++i, ++src) { construct(&*cur, *src); @@ -44,7 +44,7 @@ inline void uninitialized_copy_n(S src, int n, D dest) { } template < typename D, typename S > -inline void uninitialized_fill_n(D dest, int n, const S& value) { +static inline void uninitialized_fill_n(D dest, int n, const S& value) { D cur = dest; for (int i = 0; i < n; ++i, ++cur) { construct(&*cur, value); diff --git a/include/rstl/reserved_vector.hpp b/include/rstl/reserved_vector.hpp index bbe0bcdb..df2e4651 100644 --- a/include/rstl/reserved_vector.hpp +++ b/include/rstl/reserved_vector.hpp @@ -36,13 +36,15 @@ public: reserved_vector(CInputStream& in); reserved_vector& operator=(const reserved_vector& other) { - if (this != &other) { - clear(); - uninitialized_copy(other.data(), other.data() + other.size(), data()); - x0_count = other.x0_count; + if (this == &other) { + return *this; } + clear(); + uninitialized_copy(other.data(), other.data() + other.size(), data()); + x0_count = other.x0_count; return *this; } + void clear() { T* ptr = data(); for (int i = 0; i < x0_count; ++i) { diff --git a/include/rstl/vector.hpp b/include/rstl/vector.hpp index 45452bf4..109b1f87 100644 --- a/include/rstl/vector.hpp +++ b/include/rstl/vector.hpp @@ -227,7 +227,7 @@ vector< T, Alloc >& vector< T, Alloc >::operator=(const vector< T, Alloc >& othe xc_items = nullptr; } else { reserve(other.size()); - uninitialized_copy(other.data(), other.data() + other.size(), data()); + uninitialized_copy(other.xc_items, other.xc_items + other.x4_count, data()); x4_count = other.x4_count; } return *this; diff --git a/src/Collision/CollisionUtil.cpp b/src/Collision/CollisionUtil.cpp index e3cebad6..d39fa1f9 100644 --- a/src/Collision/CollisionUtil.cpp +++ b/src/Collision/CollisionUtil.cpp @@ -15,6 +15,8 @@ #include "Kyoto/Math/CloseEnough.hpp" #include "rstl/math.hpp" +#pragma inline_max_size(250) + namespace CollisionUtil { /*======================== X-tests ========================*/ diff --git a/src/Kyoto/Math/RMathUtils.cpp b/src/Kyoto/Math/RMathUtils.cpp index f76ab6de..351f434b 100644 --- a/src/Kyoto/Math/RMathUtils.cpp +++ b/src/Kyoto/Math/RMathUtils.cpp @@ -1,5 +1,7 @@ #include "Kyoto/Math/CMath.hpp" +#include "Kyoto/Math/CVector3f.hpp" + float CMath::SqrtF(const float x) { return sqrt(x); } double CMath::SqrtD(const double x) { return sqrt(x); } @@ -29,6 +31,7 @@ float CMath::CeilingF(float x) { } return tmp + 1.f; } + CVector3f CMath::GetCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, const CVector3f& d, float t) { if (t <= 0.0f) @@ -36,11 +39,10 @@ CVector3f CMath::GetCatmullRomSplinePoint(const CVector3f& a, const CVector3f& b if (t >= 1.0f) return c; - const float t2 = t * t; - const float t3 = t2 * t; - - return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) + - c * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) + d * (0.5f * t3 - 0.5f * t2)); + return (a * (-0.5f * t * t * t + t * t - 0.5f * t) + + b * (1.5f * t * t * t + -2.5f * t * t + 1.0f) + + c * (-1.5f * t * t * t + 2.0f * t * t + 0.5f * t) + + d * (0.5f * t * t * t - 0.5f * t * t)); } float CMath::GetCatmullRomSplinePoint(float a, float b, float c, float d, float t) { @@ -49,11 +51,10 @@ float CMath::GetCatmullRomSplinePoint(float a, float b, float c, float d, float if (t >= 1.0f) return c; - const float t2 = t * t; - const float t3 = t2 * t; - - return (a * (-0.5f * t3 + t2 - 0.5f * t) + b * (1.5f * t3 + -2.5f * t2 + 1.0f) + - c * (-1.5f * t3 + 2.0f * t2 + 0.5f * t) + d * (0.5f * t3 - 0.5f * t2)); + return (a * (-0.5f * t * t * t + t * t - 0.5f * t) + + b * (1.5f * t * t * t + -2.5f * t * t + 1.0f) + + c * (-1.5f * t * t * t + 2.0f * t * t + 0.5f * t) + + d * (0.5f * t * t * t - 0.5f * t * t)); } CVector3f CMath::GetBezierPoint(const CVector3f& a, const CVector3f& b, const CVector3f& c, @@ -70,78 +71,72 @@ CVector3f CMath::BaryToWorld(const CVector3f& p0, const CVector3f& p1, const CVe return bary.GetX() * p0 + bary.GetY() * p1 + bary.GetZ() * p2; } +static const uint skSinX1 = 0x3f7ff347; // 0.99980587f +static const uint skSinX2 = 0xbe2a34ae; // -0.16621658f +static const uint skSinX3 = 0x3c047fca; // 0.008087108f +static const uint skSinX4 = 0xb9206873; // -0.000152977f + float CMath::FastSinR(float x) { - if (fabs(x) > M_PI) { - f32 temp = x; - temp *= (1 / M_2PIF); - temp = (int)temp; - x -= temp * M_2PIF; - if (x > M_PIF) { - x = x - M_2PIF; - } else if (x < -M_PIF) { - x = M_2PIF + x; - } + if (fabs(x) > M_PIF) { + x = WrapPi(x); } - float f4 = x; - f4 *= x; - float f5 = x; - f5 *= 0.99980587f; - x *= f4; - f5 += x * -0.16621658f; - x *= f4; - f5 += x * 0.008087108f; - x *= f4; - f5 += x * -0.000152977f; - return f5; + float x2 = x * x; + float acc = x; + acc *= reinterpret_cast< const float& >(skSinX1); + x *= x2; + acc += x * reinterpret_cast< const float& >(skSinX2); + x *= x2; + acc += x * reinterpret_cast< const float& >(skSinX3); + x *= x2; + acc += x * reinterpret_cast< const float& >(skSinX4); + return acc; } +static const uint skCosX1 = 0x3f800000; // 1.0f +static const uint skCosX2 = 0xbefffd62; // -0.49998003f +static const uint skCosX3 = 0x3d2a7a18; // 0.041620344f +static const uint skCosX4 = 0xbab2bb2b; // -0.0013636103f +static const uint skCosX5 = 0x37a93188; // 0.000020169435f + float CMath::FastCosR(float x) { - if (fabs(x) > M_PI) { - x -= M_2PIF * static_cast< int >(x * (1 / M_PIF)); - if (x > M_PIF) { - x -= M_2PIF; - } else if (x < -M_PIF) { - x = M_2PIF + x; - } + if (fabs(x) > M_PIF) { + x = WrapPi(x); } - float f4 = x * x; - float f1 = 1.f; - float f0 = -0.49998003; - float f3 = 0.041620344; - f1 += f4 * f0; - float f2 = -0.0013636103; - float f5 = (f4 * f4); - f0 = 0.000020169435; - f1 += f5 * f3; - f5 *= f4; - f1 += f5 * f2; - f5 *= f4; - f1 += f5 * f0; - return f1; + float x2 = x * x; + float acc = reinterpret_cast< const float& >(skCosX1); + acc += x2 * reinterpret_cast< const float& >(skCosX2); + float xn = x2 * x2; + acc += xn * reinterpret_cast< const float& >(skCosX3); + xn *= x2; + acc += xn * reinterpret_cast< const float& >(skCosX4); + xn *= x2; + acc += xn * reinterpret_cast< const float& >(skCosX5); + return acc; } -float CMath::FastArcCosR(float f1) { - if (fabs(f1) > 0.925000011920929) { - return acosf(f1); - } - // TODO: can mess be simplified? - float f4 = f1 * f1; - float f5 = 1.5707964f; - float f0 = -0.9982272f; - float f3 = -0.20586604f; - f5 = (f1 * f0) + f5; - float f2 = 0.114254236f; - f1 = (f1 * f4); - f0 = -0.29697824f; - f5 = (f1 * f3) + f5; - f1 = (f1 * f4); - f5 = (f1 * f2) + f5; - f1 = (f1 * f4); - f5 = (f1 * f0) + f5; +static const uint skArcCosX1 = 0x3fc90fdb; // 1.5707964f (pi/2) +static const uint skArcCosX2 = 0xbf7f8bd1; // -0.9982272f +static const uint skArcCosX3 = 0xbe52ce8c; // -0.20586604f +static const uint skArcCosX4 = 0x3de9fe20; // 0.114254236f +static const uint skArcCosX5 = 0xbe980d88; // -0.29697824f - return f5; +float CMath::FastArcCosR(float x) { + if (fabs(x) > 0.925f) { + return acosf(x); + } + + float x2 = x * x; + float acc = reinterpret_cast< const float& >(skArcCosX1); + acc += x * reinterpret_cast< const float& >(skArcCosX2); + float xn = x * x2; + acc += xn * reinterpret_cast< const float& >(skArcCosX3); + xn *= x2; + acc += xn * reinterpret_cast< const float& >(skArcCosX4); + xn *= x2; + acc += xn * reinterpret_cast< const float& >(skArcCosX5); + return acc; } int CMath::FloorPowerOfTwo(int v) { diff --git a/src/MetroidPrime/CAxisAngle.cpp b/src/MetroidPrime/CAxisAngle.cpp index f7689e48..50ab3433 100644 --- a/src/MetroidPrime/CAxisAngle.cpp +++ b/src/MetroidPrime/CAxisAngle.cpp @@ -1,11 +1,18 @@ #include "MetroidPrime/CAxisAngle.hpp" +#ifdef __MWERKS__ +// This helps with CAxisAngle::FromVector. Marking the constructor inline causes +// it to not be emitted in the object file, but auto-inlining works. +#pragma auto_inline on +#endif + const CAxisAngle CAxisAngle::sIdentity; CAxisAngle::CAxisAngle(const CVector3f& vec) : mVector(vec) {} + CAxisAngle::CAxisAngle(const CUnitVector3f& vec, float angle) : mVector(vec * angle) {} -void CAxisAngle::FromVector(const CVector3f& axis) { mVector = axis; } +CAxisAngle CAxisAngle::FromVector(const CVector3f& axis) { return CAxisAngle(axis); } const CAxisAngle& CAxisAngle::Identity() { return sIdentity; } @@ -24,18 +31,13 @@ const CAxisAngle& CAxisAngle::operator+=(const CAxisAngle& rhs) { } CAxisAngle operator*(const CAxisAngle& lhs, const float& rhs) { - CAxisAngle angle; - angle.mVector = lhs.mVector * rhs; - return angle; + return CAxisAngle(lhs.mVector * rhs); } + CAxisAngle operator*(const float& lhs, const CAxisAngle& rhs) { - CAxisAngle angle; - angle.mVector = lhs * rhs.mVector; - return angle; + return CAxisAngle(lhs * rhs.mVector); } CAxisAngle operator+(const CAxisAngle& lhs, const CAxisAngle& rhs) { - CAxisAngle angle = lhs; - angle.mVector = lhs.mVector + rhs.mVector; - return angle; + return CAxisAngle(lhs.mVector + rhs.mVector); } diff --git a/src/MetroidPrime/CFluidPlaneCPU.cpp b/src/MetroidPrime/CFluidPlaneCPU.cpp index e6605e1a..6f6e980d 100644 --- a/src/MetroidPrime/CFluidPlaneCPU.cpp +++ b/src/MetroidPrime/CFluidPlaneCPU.cpp @@ -38,6 +38,8 @@ #include +#pragma inline_max_size(250) + extern "C" float* InitializeSineWave(); extern const bool sRenderBumpMaps; extern const int sFluidEnvMapType; diff --git a/src/MetroidPrime/CGameCollision.cpp b/src/MetroidPrime/CGameCollision.cpp index 360d3262..94368c66 100644 --- a/src/MetroidPrime/CGameCollision.cpp +++ b/src/MetroidPrime/CGameCollision.cpp @@ -13,6 +13,7 @@ #include "MetroidPrime/CGroundMovement.hpp" #include "MetroidPrime/CPhysicsActor.hpp" #include "MetroidPrime/CWorld.hpp" +#include "MetroidPrime/Player/CPlayer.hpp" #include "MetroidPrime/ScriptObjects/CScriptPlatform.hpp" #include "MetroidPrime/TCastTo.hpp" #include "MetroidPrime/UserNames.hpp" @@ -29,7 +30,6 @@ #pragma inline_max_size(250) extern CGameArea::CConstChainIterator sAliveAreasEnd; -extern const uchar lbl_805A9E09; static int gDebugPrintCount; void CGameCollision::InitCollision() { @@ -812,7 +812,7 @@ void CGameCollision::MovePlayer(CStateManager& mgr, CPhysicsActor& actor, float CBallFilter filter(actor); MoveAndCollide(mgr, actor, dt, filter, colliderList); } else if (actor.GetMaterialList().HasMaterial(kMT_GroundCollider)) { - if (lbl_805A9E09) { + if (gkUseNewPlayerMovement) { CGroundMovement::MoveGroundCollider_New(mgr, actor, dt, colliderList); } else { CGroundMovement::MoveGroundCollider(mgr, actor, dt, colliderList); diff --git a/src/MetroidPrime/CGameLight.cpp b/src/MetroidPrime/CGameLight.cpp index eb92e55f..bf7f71c1 100644 --- a/src/MetroidPrime/CGameLight.cpp +++ b/src/MetroidPrime/CGameLight.cpp @@ -2,6 +2,8 @@ #include "MetroidPrime/CActorParameters.hpp" +#pragma inline_max_size(250) + CGameLight::CGameLight(TUniqueId uid, TAreaId aid, const bool active, const rstl::string& name, const CTransform4f& xf, TUniqueId parentId, const CLight& light, uint sourceId, uint priority, float lifeTime) @@ -13,7 +15,6 @@ CGameLight::CGameLight(TUniqueId uid, TAreaId aid, const bool active, const rstl , x13c_lightId(sourceId) , x140_priority(priority) , x144_lifeTime(lifeTime) { - // Needs to not inline CLight copy constructor xec_light.GetRadius(); xec_light.GetIntensity(); SetLightPriorityAndId(); diff --git a/src/MetroidPrime/CStateManager.cpp b/src/MetroidPrime/CStateManager.cpp index 46afc976..bbdda7bf 100644 --- a/src/MetroidPrime/CStateManager.cpp +++ b/src/MetroidPrime/CStateManager.cpp @@ -4,36 +4,36 @@ #include "MetroidPrime/CStateManager.hpp" #undef CSTATEMANAGER_OUT_OF_LINE_GETPLAYER -#include "MetroidPrime/CControlMapper.hpp" #include "MetroidPrime/CActor.hpp" -#include "MetroidPrime/CPhysicsActor.hpp" +#include "MetroidPrime/CControlMapper.hpp" +#include "MetroidPrime/CDamageVulnerability.hpp" #include "MetroidPrime/CDecalManager.hpp" #include "MetroidPrime/CEnvFxManager.hpp" +#include "MetroidPrime/CExplosion.hpp" #include "MetroidPrime/CFluidPlaneCPU.hpp" #include "MetroidPrime/CGameCollision.hpp" -#include "MetroidPrime/Cameras/CBallCamera.hpp" -#include "MetroidPrime/Cameras/CCinematicCamera.hpp" +#include "MetroidPrime/CGameHintInfo.hpp" #include "MetroidPrime/CGameLight.hpp" #include "MetroidPrime/CMapWorld.hpp" #include "MetroidPrime/CMapWorldInfo.hpp" -#include "MetroidPrime/CGameHintInfo.hpp" -#include "MetroidPrime/CDamageVulnerability.hpp" -#include "MetroidPrime/Enemies/CPatterned.hpp" -#include "MetroidPrime/Enemies/CWallCrawlerSwarm.hpp" #include "MetroidPrime/CMemoryCard.hpp" +#include "MetroidPrime/CPhysicsActor.hpp" #include "MetroidPrime/CRipple.hpp" #include "MetroidPrime/CRumbleManager.hpp" #include "MetroidPrime/CScriptMailbox.hpp" #include "MetroidPrime/CStateManagerContainer.hpp" #include "MetroidPrime/CWorld.hpp" +#include "MetroidPrime/Cameras/CBallCamera.hpp" +#include "MetroidPrime/Cameras/CCinematicCamera.hpp" +#include "MetroidPrime/Enemies/CPatterned.hpp" +#include "MetroidPrime/Enemies/CWallCrawlerSwarm.hpp" #include "MetroidPrime/GameObjectLists.hpp" #include "MetroidPrime/HUD/CSamusHud.hpp" +#include "MetroidPrime/Player/CGameState.hpp" #include "MetroidPrime/Player/CPlayer.hpp" #include "MetroidPrime/Player/CPlayerState.hpp" -#include "MetroidPrime/Player/CGameState.hpp" #include "MetroidPrime/Player/CWorldLayerState.hpp" #include "MetroidPrime/Player/CWorldTransManager.hpp" -#include "MetroidPrime/Tweaks/CTweakGui.hpp" #include "MetroidPrime/ScriptObjects/CScriptDock.hpp" #include "MetroidPrime/ScriptObjects/CScriptDoor.hpp" #include "MetroidPrime/ScriptObjects/CScriptEffect.hpp" @@ -43,10 +43,12 @@ #include "MetroidPrime/ScriptObjects/CScriptSpecialFunction.hpp" #include "MetroidPrime/ScriptObjects/CScriptWater.hpp" #include "MetroidPrime/TCastTo.hpp" +#include "MetroidPrime/Tweaks/CTweakGui.hpp" #include "MetroidPrime/Tweaks/CTweakPlayer.hpp" #include "MetroidPrime/Tweaks/CTweakPlayerRes.hpp" -#include "MetroidPrime/Weapons/CWeapon.hpp" #include "MetroidPrime/Weapons/CProjectileWeapon.hpp" +#include "MetroidPrime/Weapons/CWeapon.hpp" +#include "Weapons/CCollisionResponseData.hpp" #include "Collision/CCollidableSphere.hpp" #include "Collision/CCollisionPrimitive.hpp" @@ -58,7 +60,6 @@ #include "Kyoto/CARAMToken.hpp" #include "Kyoto/CSimplePool.hpp" #include "Kyoto/CTimeProvider.hpp" -#include "Kyoto/Streams/CMemoryInStream.hpp" #include "Kyoto/Graphics/CGraphicsPalette.hpp" #include "Kyoto/Graphics/CLight.hpp" #include "Kyoto/Graphics/CModel.hpp" @@ -67,6 +68,7 @@ #include "Kyoto/Math/CQuaternion.hpp" #include "Kyoto/Math/CRelAngle.hpp" #include "Kyoto/Math/CUnitVector3f.hpp" +#include "Kyoto/Streams/CMemoryInStream.hpp" #include "MetaRender/CCubeRenderer.hpp" #include "Weapons/CDecal.hpp" #include "WorldFormat/CPVSAreaSet.hpp" @@ -121,10 +123,11 @@ static char init = 0; extern "C" void TouchModels__18CScriptPlayerActorFRC13CStateManager(void*, const CStateManager&); extern "C" void ConvertToScreenSpace__11CGameCameraCFRC9CVector3f(CVector3f*, const CGameCamera*, - const CVector3f*); + const CVector3f*); extern "C" void DrawReflection__13CStateManagerFRC9CVector3f(CStateManager*, const CVector3f&); -extern "C" void SetNewPlayerPositionAndTime__10CCubeModelFRC9CVector3fRC10CStopwatch( - const CVector3f&, const CStopwatch&); +extern "C" void +SetNewPlayerPositionAndTime__10CCubeModelFRC9CVector3fRC10CStopwatch(const CVector3f&, + const CStopwatch&); extern "C" CGameArea::CChainIterator AliveAreasEnd__6CWorldFv(); extern "C" void ResetParticleCounts__13CScriptEffectFv(); extern "C" void Update__15CCameraBlurPassFf(CCameraBlurPass*, float); @@ -132,10 +135,12 @@ extern "C" void Update__13CDecalManagerFfR13CStateManager(float, CStateManager*) extern "C" void Update__6CWorldFf(CWorld*, float); extern "C" void PreRender__6CWorldFv(CWorld*); extern "C" void Update__13CEnvFxManagerFfR13CStateManager(float, CEnvFxManager*, CStateManager*); -extern "C" void AsyncLoadResources__13CEnvFXManagerFR13CStateManager(CEnvFxManager*, CStateManager*); +extern "C" void AsyncLoadResources__13CEnvFXManagerFR13CStateManager(CEnvFxManager*, + CStateManager*); extern "C" void DismissDisplayedHint__12CHintOptionsFv(CHintOptions*); extern "C" void CrossTouchActors__13CStateManagerFf(CStateManager*); -extern "C" void TravelToArea__6CWorldFRC7TAreaIdR13CStateManagerb(CWorld*, const TAreaId&, CStateManager*, bool); +extern "C" void TravelToArea__6CWorldFRC7TAreaIdR13CStateManagerb(CWorld*, const TAreaId&, + CStateManager*, bool); extern "C" void SetTotalPlayTime__10CGameStateFd(CGameState*, double); extern "C" void SetDeferPowerupInit__10CGameStateFb(CGameState*, bool); extern "C" void SetAreaId__11CWorldStateF7TAreaId(CWorldState*, TAreaId); @@ -145,21 +150,22 @@ extern "C" ushort lbl_805A8A10; extern "C" s64 lbl_805A8D98; extern "C" uint lbl_805A8D9C; extern "C" CGameArea* lbl_805A8DDC; -extern "C" uchar lbl_805A9E08; -extern "C" float lbl_805A9E10; extern "C" float lbl_805AA2D4; extern "C" void fn_80046DE8(const CStateManager*, const CGameArea*); extern "C" void fn_8004B504(CStateManager*); extern "C" float GetHardModeDamageMultiplier__10CGameStateCFv(const CGameState*); extern "C" void IncrementFrozenBallCount__12CSystemStateFv(CSystemState*); extern "C" float BombJump__7CPlayerFRC9CVector3fR13CStateManager(CPlayer*, const CVector3f*, - CStateManager*); + CStateManager*); extern "C" void ApplyRadiusDamage__17CWallCrawlerSwarmF9CVector3ffR13CStateManager( CWallCrawlerSwarm*, const CVector3f*, const CDamageInfo*, CStateManager*); -extern "C" void ApplyRadiusDamage__15CSnakeWeedSwarmF9CVector3ffR13CStateManager( - CSnakeWeedSwarm*, const CVector3f*, const CDamageInfo*, CStateManager*); +extern "C" void ApplyRadiusDamage__15CSnakeWeedSwarmF9CVector3ffR13CStateManager(CSnakeWeedSwarm*, + const CVector3f*, + const CDamageInfo*, + CStateManager*); -extern bool TestRayDamage(const CStateManager&, const CVector3f&, const CActor&, const TEntityList&); +extern bool TestRayDamage(const CStateManager&, const CVector3f&, const CActor&, + const TEntityList&); struct SScriptLayerBuffer { const void* x0_buf; @@ -181,93 +187,6 @@ public: } }; -void CStateManager::BuildNearList(TEntityList& nearList, const CAABox& aabb, - const CMaterialFilter& filter, const CActor* actor) const { - x874_sortedListManager->BuildNearList(nearList, aabb, filter, actor); -} - -void CStateManager::BuildColliderList(TEntityList& out, const CActor& actor, - const CAABox& aabb) const { - x874_sortedListManager->BuildNearList(out, actor, aabb); -} - -void CStateManager::BuildNearList(TEntityList& nearList, const CVector3f& pos, - const CVector3f& dir, float mag, - const CMaterialFilter& filter, const CActor* actor) const { - x874_sortedListManager->BuildNearList(nearList, pos, dir, mag, filter, actor); -} - -void CStateManager::UpdateActorInSortedLists(CActor& actor) { - x874_sortedListManager->Insert(&actor, actor.GetSortingBounds(*this)); -} - -void CStateManager::UpdateSortedLists() { - if (x850_world.get() == nullptr) { - return; - } - - CObjectList* actorList = x808_objectLists[kOL_Actor].get(); - for (int i = actorList->GetFirstObjectIndex(); i != -1; i = actorList->GetNextObjectIndex(i)) { - CActor* actor = static_cast< CActor* >((*actorList)[i]); - if (actor != nullptr) { - UpdateActorInSortedLists(*actor); - } - } -} - -rstl::optional_object< CAABox > CStateManager::CalculateObjectBounds(const CActor& actor) { - const CPhysicsActor* physAct = TCastToConstPtr< CPhysicsActor >(actor); - rstl::optional_object< CAABox > touchBounds = actor.GetTouchBounds(); - - if (touchBounds) { - CAABox aabb = CAABox::MakeMaxInvertedBox(); - aabb.AccumulateBounds(touchBounds->GetMinPoint()); - aabb.AccumulateBounds(touchBounds->GetMaxPoint()); - - if (physAct != nullptr) { - CAABox physAabb = physAct->GetBoundingBox(); - aabb.AccumulateBounds(physAabb.GetMinPoint()); - aabb.AccumulateBounds(physAabb.GetMaxPoint()); - } - - return aabb; - } - - if (physAct != nullptr) { - return physAct->GetBoundingBox(); - } - - return rstl::optional_object_null(); -} - -void CStateManager::AreaLoaded(TAreaId aid) { - x8bc_mailbox->SendMsgs(aid, *this); - x880_envFxManager->AreaLoaded(); -} - -void CStateManager::PrepareAreaUnload(TAreaId aid) { - CObjectList* allList = x808_objectLists[0].get(); - for (int i = allList->GetFirstObjectIndex(); i != -1; i = allList->GetNextObjectIndex(i)) { - if (CScriptDoor* door = TCastToPtr< CScriptDoor >((*allList)[i])) { - if (door->IsConnectedToArea(*this, aid)) { - door->ForceClosed(*this); - } - } - } - - FreeScriptObjects(aid); -} - -void CStateManager::AreaUnloaded(TAreaId) {} - -const CEntity* CStateManager::GetObjectById(TUniqueId uid) const { - return GetObjectListById(kOL_All).GetObjectById(uid); -} - -CEntity* CStateManager::ObjectById(TUniqueId uid) { - return x808_objectLists[0]->GetObjectById(uid); -} - CStateManager::CStateManager(const rstl::ncrc_ptr< CScriptMailbox >& mailbox, const rstl::ncrc_ptr< CMapWorldInfo >& mwInfo, const rstl::ncrc_ptr< CPlayerState >& playerState, @@ -559,6 +478,30 @@ TUniqueId CStateManager::AllocateUniqueId() { return TUniqueId(x4_objectIndexArray[ourIndex], ourIndex); } +void CStateManager::UpdateObjectInLists(CEntity& ent) { + rstl::auto_ptr< CObjectList >* listBegin = x808_objectLists.data(); + for (rstl::auto_ptr< CObjectList >* listIt = listBegin; + listIt != listBegin + x808_objectLists.size(); ++listIt) { + if (static_cast< const CObjectList* >(listIt->get())->GetValidObjectById(ent.GetUniqueId()) != + nullptr && + !listIt->get()->IsQualified(ent)) { + listIt->get()->RemoveObject(ent.GetUniqueId()); + } + + if (static_cast< const CObjectList* >(listIt->get())->GetValidObjectById(ent.GetUniqueId()) == + nullptr) { + listIt->get()->AddObject(ent); + } + } +} + +CRayCastResult CStateManager::RayWorldIntersection(TUniqueId& idOut, const CVector3f& pos, + const CVector3f& dir, float length, + const CMaterialFilter& filter, + const TEntityList& list) const { + return CGameCollision::RayWorldIntersection(*this, idOut, pos, dir, length, filter, list); +} + CRayCastResult CStateManager::RayStaticIntersection(const CVector3f& pos, const CVector3f& dir, float length, const CMaterialFilter& filter) const { @@ -587,7 +530,8 @@ void CStateManager::AddObject(CEntity* obj) { void CStateManager::AddObject(CEntity& obj) { if (obj.GetEditorId() != kInvalidEditorId) { - x890_scriptIdMap.insert(rstl::pair< TEditorId, TUniqueId >(obj.GetEditorId(), obj.GetUniqueId())); + x890_scriptIdMap.insert( + rstl::pair< TEditorId, TUniqueId >(obj.GetEditorId(), obj.GetUniqueId())); } rstl::reserved_vector< rstl::auto_ptr< CObjectList >, 8 >::iterator listIt = @@ -626,6 +570,194 @@ void CStateManager::AddObject(CEntity& obj) { } } +rstl::optional_object< CAABox > CStateManager::CalculateObjectBounds(const CActor& actor) { + const CPhysicsActor* physAct = TCastToConstPtr< CPhysicsActor >(actor); + rstl::optional_object< CAABox > touchBounds = actor.GetTouchBounds(); + + if (touchBounds) { + CAABox aabb = CAABox::MakeMaxInvertedBox(); + aabb.AccumulateBounds(touchBounds->GetMinPoint()); + aabb.AccumulateBounds(touchBounds->GetMaxPoint()); + + if (physAct != nullptr) { + CAABox physAabb = physAct->GetBoundingBox(); + aabb.AccumulateBounds(physAabb.GetMinPoint()); + aabb.AccumulateBounds(physAabb.GetMaxPoint()); + } + + return aabb; + } + + if (physAct != nullptr) { + return physAct->GetBoundingBox(); + } + + return rstl::optional_object_null(); +} + +void CStateManager::UpdateSortedLists() { + if (x850_world.get() == nullptr) { + return; + } + + CObjectList* actorList = x808_objectLists[kOL_Actor].get(); + for (int i = actorList->GetFirstObjectIndex(); i != -1; i = actorList->GetNextObjectIndex(i)) { + CActor* actor = static_cast< CActor* >((*actorList)[i]); + if (actor != nullptr) { + UpdateActorInSortedLists(*actor); + } + } +} + +void CStateManager::UpdateActorInSortedLists(CActor& actor) { + x874_sortedListManager->Insert(&actor, actor.GetSortingBounds(*this)); +} + +void CStateManager::BuildNearList(TEntityList& nearList, const CAABox& aabb, + const CMaterialFilter& filter, const CActor* actor) const { + x874_sortedListManager->BuildNearList(nearList, aabb, filter, actor); +} + +void CStateManager::BuildColliderList(TEntityList& out, const CActor& actor, + const CAABox& aabb) const { + x874_sortedListManager->BuildNearList(out, actor, aabb); +} + +void CStateManager::BuildNearList(TEntityList& nearList, const CVector3f& pos, const CVector3f& dir, + float mag, const CMaterialFilter& filter, + const CActor* actor) const { + x874_sortedListManager->BuildNearList(nearList, pos, dir, mag, filter, actor); +} + +void CStateManager::AreaLoaded(TAreaId aid) { + x8bc_mailbox->SendMsgs(aid, *this); + x880_envFxManager->AreaLoaded(); +} + +void CStateManager::PrepareAreaUnload(TAreaId aid) { + CObjectList* allList = x808_objectLists[0].get(); + for (int i = allList->GetFirstObjectIndex(); i != -1; i = allList->GetNextObjectIndex(i)) { + if (CScriptDoor* door = TCastToPtr< CScriptDoor >((*allList)[i])) { + if (door->IsConnectedToArea(*this, aid)) { + door->ForceClosed(*this); + } + } + } + + FreeScriptObjects(aid); +} + +void CStateManager::AreaUnloaded(TAreaId) {} + +const CEntity* CStateManager::GetObjectById(TUniqueId uid) const { + return GetObjectListById(kOL_All).GetObjectById(uid); +} + +CEntity* CStateManager::ObjectById(TUniqueId uid) { + return x808_objectLists[0]->GetObjectById(uid); +} + +void CStateManager::DeleteObjectRequest(TUniqueId uid) { + CEntity* ent = ObjectById(uid); + if (ent == nullptr) { + return; + } + if ((*reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(ent) + 0x30) >> 6) & 1) { + return; + } + + ent->x30_25_inGraveyard = true; + + if (x854_graveyard.size() == 0) { + rstl::reserved_vector< TUniqueId, 32 > newVec; + x854_graveyard.push_back(newVec); + } else { + rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator backIt = x854_graveyard.end(); + --backIt; + if (backIt->size() == backIt->capacity()) { + rstl::reserved_vector< TUniqueId, 32 > newVec; + x854_graveyard.push_back(newVec); + } + } + + rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator backIt = x854_graveyard.end(); + --backIt; + backIt->push_back(uid); + + ent->AcceptScriptMsg(kSM_Deleted, kInvalidUniqueId, *this); + ent->x30_26_scriptingBlocked = true; + + if (CActor* actor = TCastToPtr< CActor >(ent)) { + x874_sortedListManager->Remove(actor); + actor->SetUseInSortedLists(false); + } +} + +void CStateManager::ClearGraveyard() { + rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator gyIt = x854_graveyard.begin(); + for (; gyIt != x854_graveyard.end(); ++gyIt) { + rstl::reserved_vector< TUniqueId, 32 >& vec = *gyIt; + rstl::reserved_vector< TUniqueId, 32 >::iterator idIt = vec.begin(); + for (; idIt != vec.end(); ++idIt) { + TUniqueId id = *idIt; + CEntity* ent = x808_objectLists[0]->GetValidObjectById(id); + RemoveObject(id); + if (ent != nullptr) { + delete ent; + } + } + } + + { + rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator clearIt = x854_graveyard.begin(); + while (clearIt != x854_graveyard.end()) { + clearIt = x854_graveyard.erase(clearIt); + } + } +} + +void CStateManager::SetCurrentAreaId(TAreaId aid) { + if (x8cc_nextAreaId != aid) { + x8d0_prevAreaId = x8cc_nextAreaId; + UpdateRoomAcoustics(aid); + x8cc_nextAreaId = aid; + } + + const TAreaId& currentArea = aid; + if (currentArea != kInvalidAreaId) { + if (!x8c0_mapWorldInfo->IsAreaVisited(currentArea)) { + x8c0_mapWorldInfo->SetAreaVisited(currentArea, true); + CMapWorldInfo* mapWorldInfo = x8c0_mapWorldInfo.GetPtr(); + CWorld* world = x850_world.get(); + CMapWorld* mapWorld = world->GetMapWorld(); + mapWorld->RecalculateWorldSphere(*mapWorldInfo, *world); + } + } +} + +void CStateManager::UpdateRoomAcoustics(TAreaId aid) { + rstl::reserved_vector< CScriptRoomAcoustics*, 10 > areaAcoustics; + CObjectList* allList = x808_objectLists[kOL_All].get(); + + for (int i = allList->GetFirstObjectIndex(); i != -1 && areaAcoustics.size() < 10; + i = allList->GetNextObjectIndex(i)) { + CEntity* ent = (*allList)[i]; + if (CScriptRoomAcoustics* acoustics = TCastToPtr< CScriptRoomAcoustics >(ent)) { + if (acoustics->GetCurrentAreaId() == aid && acoustics->GetActive()) { + areaAcoustics.push_back(acoustics); + } + } + } + + if (areaAcoustics.size() > 0) { + const int acousticsIdx = static_cast< int >( + 0.99f * (x900_random->Float() * static_cast< float >(areaAcoustics.size()))); + areaAcoustics[acousticsIdx]->EnableAuxCallbacks(); + } else { + CScriptRoomAcoustics::DisableAuxCallbacks(); + } +} + void CStateManager::RemoveObject(TUniqueId id) { CEntity* ent = x808_objectLists[0]->GetValidObjectById(id); if (ent != nullptr) { @@ -662,702 +794,6 @@ void CStateManager::RemoveObject(TUniqueId id) { } } -void CStateManager::ClearGraveyard() { - rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator gyIt = x854_graveyard.begin(); - for (; gyIt != x854_graveyard.end(); ++gyIt) { - rstl::reserved_vector< TUniqueId, 32 >& vec = *gyIt; - rstl::reserved_vector< TUniqueId, 32 >::iterator idIt = vec.begin(); - for (; idIt != vec.end(); ++idIt) { - TUniqueId id = *idIt; - CEntity* ent = x808_objectLists[0]->GetValidObjectById(id); - RemoveObject(id); - if (ent != nullptr) { - delete ent; - } - } - } - - { - rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator clearIt = - x854_graveyard.begin(); - while (clearIt != x854_graveyard.end()) { - clearIt = x854_graveyard.erase(clearIt); - } - } -} - -void CStateManager::DeleteObjectRequest(TUniqueId uid) { - CEntity* ent = ObjectById(uid); - if (ent == nullptr) { - return; - } - if ((*reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(ent) + 0x30) >> 6) & 1) { - return; - } - - ent->x30_25_inGraveyard = true; - - if (x854_graveyard.size() == 0) { - rstl::reserved_vector< TUniqueId, 32 > newVec; - x854_graveyard.push_back(newVec); - } else { - rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator backIt = x854_graveyard.end(); - --backIt; - if (backIt->size() == backIt->capacity()) { - rstl::reserved_vector< TUniqueId, 32 > newVec; - x854_graveyard.push_back(newVec); - } - } - - rstl::list< rstl::reserved_vector< TUniqueId, 32 > >::iterator backIt = x854_graveyard.end(); - --backIt; - backIt->push_back(uid); - - ent->AcceptScriptMsg(kSM_Deleted, kInvalidUniqueId, *this); - ent->x30_26_scriptingBlocked = true; - - if (CActor* actor = TCastToPtr< CActor >(ent)) { - x874_sortedListManager->Remove(actor); - actor->SetUseInSortedLists(false); - } -} - -void CStateManager::KnockBackPlayer(CPlayer& player, const CVector3f& dir, float power, - float resistance) { - if (player.GetMaterialList().HasMaterial(kMT_Immovable)) { - return; - } - - float usePower; - if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) { - usePower = power * 500.f; - } else { - usePower = power * 1000.f; - if (player.GetSurfaceRestraint() != CPlayer::kSR_Normal && - player.GetOrbitState() == CPlayer::kOS_NoOrbit) { - usePower /= 7.f; - } - } - - float minVel = 70.f; - if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) { - minVel = 35.f; - } - - const float playerVel = player.GetVelocityWR().Magnitude(); - const float maxVel = minVel < playerVel ? playerVel : minVel; - const CVector3f invVel = -player.GetVelocityWR(); - - usePower *= (1.f - (0.5f * CVector3f::GetAngleDiff(dir, invVel)) / M_PIF); - - player.ApplyImpulseWR(dir * usePower, CAxisAngle::Identity()); - player.UseCollisionImpulses(); - *reinterpret_cast< float* >(reinterpret_cast< uchar* >(&player) + 0x2d4) = 0.25f; - - const CVector3f velocity = player.GetVelocityWR(); - const float velocityMag = velocity.Magnitude(); - if (maxVel < velocityMag) { - const float invMag = 1.f / velocityMag; - const CVector3f norm(invMag * velocity.GetX(), invMag * velocity.GetY(), invMag * velocity.GetZ()); - player.SetVelocityWR(CVector3f(maxVel * norm.GetX(), maxVel * norm.GetY(), maxVel * norm.GetZ())); - } -} - -void CStateManager::ApplyKnockBack(CActor& actor, const CDamageInfo& info, - const CDamageVulnerability& vuln, const CVector3f& dir, - float dampen) { - if (vuln.GetVulnerability(info.GetWeaponMode(), 0) == kVN_Deflect) { - return; - } - - CHealthInfo* hInfo = actor.HealthInfo(*this); - if (hInfo == nullptr) { - return; - } - - const float resistance = - *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(hInfo) + 0x4); - const float dampedPower = (1.f - dampen) * info.GetKnockBackPower(); - - CPlayer* player = TCastToPtr< CPlayer >(actor); - CPatterned* patterned = TCastToPtr< CPatterned >(actor); - - if (player != nullptr) { - KnockBackPlayer(*player, dir, dampedPower, resistance); - return; - } - - if (patterned == nullptr && hInfo->GetHP() <= 0.f) { - if (dampedPower > resistance) { - CPhysicsActor* physActor = TCastToPtr< CPhysicsActor >(actor); - if (physActor != nullptr) { - const CVector3f impulse = - dir * (1.5f * ((dampedPower - resistance) * physActor->GetMass())); - if (!physActor->GetMaterialList().HasMaterial(kMT_Immovable) && - physActor->GetMaterialList().HasMaterial(kMT_Solid)) { - physActor->ApplyImpulseWR(impulse, CAxisAngle::Identity()); - } - } - } - } - - if (patterned != nullptr) { - patterned->KnockBack(dir, *this, info, dampen == 0.f ? kKBT_Direct : kKBT_Radius, false, - dampedPower); - } -} - -void CStateManager::ApplyDamageToWorld(TUniqueId damagerId, const CActor& actor, - const CVector3f& pos, const CDamageInfo& info, - const CMaterialFilter& filter) { - const CVector3f extent(info.GetRadius(), info.GetRadius(), info.GetRadius()); - const CAABox aabb(pos - extent, pos + extent); - - bool bomb = false; - const CWeapon* weapon = TCastToConstPtr< CWeapon >(actor); - if (weapon != nullptr) { - bomb = (weapon->GetAttribField() & (CWeapon::kPA_Bombs | CWeapon::kPA_PowerBombs)) != 0; - } - - TEntityList nearList; - BuildNearList(nearList, aabb, filter, &actor); - - for (TEntityList::iterator it = nearList.begin(); it != nearList.end(); ++it) { - CEntity* ent = ObjectById(*it); - CActor* act = TCastToPtr< CActor >(ent); - CPlayer* player = TCastToPtr< CPlayer >(ent); - CWallCrawlerSwarm* wallSwarm = TCastToPtr< CWallCrawlerSwarm >(ent); - CSnakeWeedSwarm* snakeSwarm = TCastToPtr< CSnakeWeedSwarm >(ent); - - if (bomb && player != nullptr) { - if (player->GetFrozenState()) { - IncrementFrozenBallCount__12CSystemStateFv(&gpGameState->SystemState()); - CSamusHud::DisplayHudMemo(rstl::wstring_l(L""), CHUDMemoParms(0.f, true, true, true)); - player->BreakFrozenState(*this); - } else if (weapon != nullptr && (weapon->GetAttribField() & CWeapon::kPA_Bombs) != 0) { - BombJump__7CPlayerFRC9CVector3fR13CStateManager(player, &pos, this); - } - } else if (act != nullptr && act->GetUniqueId() != damagerId) { - TestBombHittingWater(actor, pos, *act); - if (TestRayDamage(*this, pos, *act, nearList)) { - ApplyRadiusDamage(actor, pos, *act, info); - } - } - - if (wallSwarm != nullptr) { - ApplyRadiusDamage__17CWallCrawlerSwarmF9CVector3ffR13CStateManager(wallSwarm, &pos, &info, - this); - } - - if (snakeSwarm != nullptr) { - ApplyRadiusDamage__15CSnakeWeedSwarmF9CVector3ffR13CStateManager(snakeSwarm, &pos, &info, - this); - } - } -} - -void CStateManager::ProcessRadiusDamage(const CActor& damager, CActor& damagee, - TUniqueId radiusSender, const CDamageInfo& info, - const CMaterialFilter& filter) { - const float radius = info.GetRadius(); - const CVector3f pos = damager.GetTranslation(); - const CVector3f maxPos(pos.GetX() + radius, pos.GetY() + radius, pos.GetZ() + radius); - const CVector3f minPos(pos.GetX() - radius, pos.GetY() - radius, pos.GetZ() - radius); - const CAABox aabb(minPos, maxPos); - CMaterialFilter localFilter = filter; - - TEntityList nearList; - BuildNearList(nearList, aabb, localFilter, nullptr); - - const TUniqueId damagerId = damager.GetUniqueId(); - const TUniqueId damageeId = damagee.GetUniqueId(); - - for (TEntityList::iterator it = nearList.begin(); it != nearList.end(); ++it) { - CActor* actor = static_cast< CActor* >(ObjectById(*it)); - if (actor != nullptr) { - const TUniqueId actorId = actor->GetUniqueId(); - if (damagerId != actorId && radiusSender != actorId && damageeId != actorId) { - TestBombHittingWater(damager, pos, *actor); - if (TestRayDamage(*this, pos, *actor, nearList)) { - ApplyRadiusDamage(damager, pos, *actor, info); - } - } - } - } -} - -void CStateManager::ApplyRadiusDamage(const CActor& damager, const CVector3f& pos, CActor& damagee, - const CDamageInfo& info) { - CVector3f delta = damagee.GetTranslation() - pos; - if (info.GetRadius() * info.GetRadius() <= delta.MagSquared()) { - if (!damagee.GetTouchBounds()) { - return; - } - - if (!CCollidableSphere::Sphere_AABox_Bool(CSphere(pos, info.GetRadius()), - *damagee.GetTouchBounds())) { - return; - } - } - - float rad = info.GetRadius(); - if (rad > gkEpsilon) { - rad = delta.Magnitude() / rad; - } else { - rad = 0.f; - } - - if (rad > 0.f) { - delta.Normalize(); - } - - bool alive = false; - CHealthInfo* hInfo = damagee.HealthInfo(*this); - if (hInfo != nullptr && hInfo->GetHP() > 0.f) { - alive = true; - } - - const CDamageVulnerability* vuln = - rad > 0.f ? damagee.GetDamageVulnerability(pos, delta, info) : damagee.GetDamageVulnerability(); - - if (vuln->WeaponHurts(info.GetWeaponMode(), 1)) { - const float localDamage = info.GetRadiusDamage(*vuln); - if (localDamage > 0.f) { - ApplyLocalDamage(pos, delta, damagee, localDamage, info.GetWeaponMode()); - } - - damagee.SendScriptMsgs(kSS_Damage, *this, kSM_None); - DeliverScriptMsg(&damagee, damager.GetUniqueId(), kSM_Damage); - } else { - damagee.SendScriptMsgs(kSS_InvulnDamage, *this, kSM_None); - DeliverScriptMsg(&damagee, damager.GetUniqueId(), kSM_InvulnDamage); - } - - if (alive && info.GetKnockBackPower() > 0.f) { - CVector3f knockbackDir(damagee.GetTranslation().GetX() - damager.GetTranslation().GetX(), - damagee.GetTranslation().GetY() - damager.GetTranslation().GetY(), - 0.0001f); - ApplyKnockBack(damagee, info, *vuln, knockbackDir.AsNormalized(), rad); - } -} - -bool CStateManager::MultiRayCollideWorld(const CMRay& ray, const CMaterialFilter& filter) { - const CVector3f& start = *reinterpret_cast< const CVector3f* >( - reinterpret_cast< const uchar* >(&ray) + 0x0); - const CVector3f& dir = - *reinterpret_cast< const CVector3f* >(reinterpret_cast< const uchar* >(&ray) + 0x2c); - const float length = - *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&ray) + 0x24); - - CVector3f crossed(-dir.GetZ() * dir.GetZ() - dir.GetY() * dir.GetX(), - dir.GetX() * dir.GetX() - dir.GetZ() * dir.GetY(), - dir.GetY() * dir.GetY() - dir.GetX() * -dir.GetZ()); - CVector3f crossedNorm = crossed.AsNormalized(); - - const CVector3f crossed2( - (dir.GetY() * crossedNorm.GetZ() - crossedNorm.GetY() * dir.GetZ()) * 0.35355338f, - (dir.GetZ() * crossedNorm.GetX() - crossedNorm.GetZ() * dir.GetX()) * 0.35355338f, - (dir.GetX() * crossedNorm.GetY() - crossedNorm.GetX() * dir.GetY()) * 0.35355338f); - const CVector3f rms = crossedNorm * 0.35355338f; - - for (uint i = 0; i < 4; ++i) { - const CVector3f useCrossed = (i & 2) != 0 ? -crossed2 : crossed2; - const CVector3f useRms = (i & 1) != 0 ? rms : -rms; - const CVector3f useStart = start + useRms + useCrossed; - if (CGameCollision::RayStaticIntersectionBool(*this, useStart, dir, length, filter)) { - return true; - } - } - - return false; -} - -void CStateManager::TestBombHittingWater(const CActor& damager, const CVector3f& pos, - CActor& damagee) { - CWeapon* weapon = TCastToPtr< CWeapon >(const_cast< CActor& >(damager)); - if (weapon == nullptr) { - return; - } - - const int attribField = weapon->GetAttribField(); - if ((attribField & (CWeapon::kPA_Bombs | CWeapon::kPA_PowerBombs)) == 0) { - return; - } - - const bool powerBomb = (attribField & CWeapon::kPA_PowerBombs) != 0; - CScriptWater* water = TCastToPtr< CScriptWater >(damagee); - if (water == nullptr) { - return; - } - - CAABox triggerBounds = water->GetTriggerBoundsWR(); - CVector3f hitPos(pos.GetX(), pos.GetY(), triggerBounds.GetMaxPoint().GetZ()); - - CVector3f up(0.f, 0.f, 1.f); - up.Normalize(); - - CAABox triggerBounds2 = water->GetTriggerBoundsWR(); - const int idx = powerBomb; - const float depth = -(CVector3f::Dot(up, pos) - triggerBounds2.GetMaxPoint().GetZ()); - - if (depth <= skBombUnderwaterRanges[idx] && depth > 0.f) { - const float rippleFactor = 1.f - depth / skBombUnderwaterRanges[idx]; - if (x87c_fluidPlaneManager->GetLastRippleDeltaTime(damager.GetUniqueId()) >= 0.15f) { - const float bombMag = skBombUnderwaterMags[idx]; - const float sinVal = CMath::FastSinR(2.f * M_PIF * rippleFactor * 0.25f); - water->FluidPlane().AddRipple(0.6f * bombMag + 0.4f * bombMag * sinVal, - damager.GetUniqueId(), hitPos, *water, *this); - } - - if (!powerBomb) { - x87c_fluidPlaneManager->CreateSplash(damager.GetUniqueId(), *this, *water, hitPos, - rippleFactor, true); - } - } else if (depth > -skBombAboveWaterRanges[idx] && depth < 0.f) { - const float depthAbove = -depth; - CVector3f down(0.f, 0.f, -1.f); - const CRayCastResult result = - RayStaticIntersection(pos, down, depthAbove, CMaterialFilter::GetPassEverything()); - - if (!result.GetValid() && x87c_fluidPlaneManager->GetLastRippleDeltaTime(damager.GetUniqueId()) >= 0.15f) { - const float bombMag = skBombAboveWaterMags[idx]; - const float sinVal = - CMath::FastSinR(2.f * M_PIF * (depthAbove / skBombAboveWaterRanges[idx]) * 0.25f); - water->FluidPlane().AddRipple(0.6f * bombMag + 0.4f * bombMag * sinVal, - damager.GetUniqueId(), hitPos, *water, *this); - } - } -} - -bool CStateManager::ApplyLocalDamage(const CVector3f& pos, const CVector3f& dir, CActor& damagee, - float damage, const CWeaponMode& weaponMode) { - CHealthInfo* hInfo = damagee.HealthInfo(*this); - if (hInfo == nullptr || damage < 0.f) { - return false; - } - - const float oldHp = hInfo->GetHP(); - if (oldHp <= 0.f) { - return true; - } - - float useDamage = damage; - CPlayer* player = TCastToPtr< CPlayer >(damagee); - CAi* ai = TCastToPtr< CAi >(damagee); - - if (player != nullptr) { - if (x870_cameraManager->IsInCinematicCamera() || - (weaponMode.GetType() == kWT_Phazon && x8b8_playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit))) { - return false; - } - - if (gpGameState->GetHardMode()) { - useDamage *= GetHardModeDamageMultiplier__10CGameStateCFv(gpGameState); - } - - float damageReduction = 0.f; - if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_VariaSuit)) { - damageReduction = gpTweakPlayer->GetVariaDamageReduction(); - } - - if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_GravitySuit)) { - const float gravityReduction = gpTweakPlayer->GetGravityDamageReduction(); - damageReduction = CMath::Max(damageReduction, gravityReduction); - } - - if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit)) { - const float phazonReduction = gpTweakPlayer->GetPhazonDamageReduction(); - damageReduction = CMath::Max(damageReduction, phazonReduction); - } - - useDamage = -(damageReduction * useDamage - useDamage); - } - - const float newHp = oldHp - useDamage; - const bool significant = fabs(newHp - oldHp) >= 0.00001f; - hInfo->SetHP(newHp); - - if (player != nullptr) { - player->TakeDamage(significant, pos, useDamage, weaponMode.GetType(), *this); - if (newHp <= 0.f) { - struct SPlayerStateFlags { - bool x0_24_alive : 1; - }; - reinterpret_cast< SPlayerStateFlags* >(x8b8_playerState.GetPtr())->x0_24_alive = false; - } - } else if (ai != nullptr) { - if (significant) { - ai->TakeDamage(dir, useDamage); - } - - if (newHp <= 0.f) { - ai->Death(*this, dir, kSS_DeathRattle); - } - } - - return significant; -} - -void CStateManager::ApplyDamage(const TUniqueId damagerId, const TUniqueId damageeId, - const TUniqueId radiusSender, const CDamageInfo& info, - const CMaterialFilter& filter, const CVector3f& knockbackVec) { - CEntity* damagerEnt = const_cast< CEntity* >(GetObjectById(damagerId)); - CEntity* damageeEnt = ObjectById(damageeId); - CActor* damager = TCastToPtr< CActor >(damagerEnt); - CActor* damagee = TCastToPtr< CActor >(damageeEnt); - CPlayer* player = TCastToPtr< CPlayer >(damageeEnt); - - if (damagee != nullptr) { - CHealthInfo* hInfo = damagee->HealthInfo(*this); - if (hInfo != nullptr) { - CVector3f position = CVector3f::Zero(); - CVector3f direction = CVector3f::Right(); - const bool alive = hInfo->GetHP() > 0.f; - - if (damager != nullptr) { - position = damager->GetTranslation(); - direction = damager->GetTransform().GetForward(); - } - - const bool useWeaponDir = damager != nullptr || player != nullptr; - const CDamageVulnerability* dVuln = - useWeaponDir ? damagee->GetDamageVulnerability(position, direction, info) - : damagee->GetDamageVulnerability(); - - if (info.GetWeaponMode().GetType() == kWT_None || dVuln->WeaponHurts(info.GetWeaponMode(), 0)) { - const float localDamage = info.GetDamage(*dVuln); - if (localDamage > 0.f) { - ApplyLocalDamage(position, direction, *damagee, localDamage, info.GetWeaponMode()); - } - - damagee->SendScriptMsgs(kSS_Damage, *this, kSM_None); - DeliverScriptMsg(damagee, damagerId, kSM_Damage); - } else { - damagee->SendScriptMsgs(kSS_InvulnDamage, *this, kSM_None); - DeliverScriptMsg(damagee, damagerId, kSM_InvulnDamage); - } - - if (alive && damager != nullptr && info.GetKnockBackPower() > 0.f) { - CVector3f defaultDir = damagee->GetTranslation() - damager->GetTranslation(); - const CVector3f& useDir = knockbackVec.IsNonZero() ? knockbackVec : defaultDir; - CVector3f knockDir(useDir.GetX(), useDir.GetY(), 0.0001f); - ApplyKnockBack(*damagee, info, *dVuln, knockDir.AsNormalized(), 0.f); - } - } - - if (damager != nullptr && info.GetRadius() > 0.f) { - ProcessRadiusDamage(*damager, *damagee, radiusSender, info, filter); - } - - CWallCrawlerSwarm* swarm = TCastToPtr< CWallCrawlerSwarm >(damageeEnt); - if (swarm != nullptr && damager != nullptr) { - const CVector3f damagerPos = damager->GetTranslation(); - ApplyRadiusDamage__17CWallCrawlerSwarmF9CVector3ffR13CStateManager( - swarm, &damagerPos, &info, this); - } - } -} - -void CStateManager::UpdateAreaSounds() { - rstl::reserved_vector< int, 10 > areaIds; - areaIds.clear(); - for (CGameArea::CConstChainIterator areaIt = x850_world->GetChainHead(CWorld::kC_Alive); - areaIt != CWorld::GetAliveAreasEnd(); ++areaIt) { - CGameArea::EOcclusionState occState; - if (areaIt->IsPostConstructed()) { - occState = areaIt->GetPostConstructed()->x10dc_occlusionState; - } else { - occState = CGameArea::kOS_Occluded; - } - - if (occState == CGameArea::kOS_Visible) { - areaIds.push_back(areaIt->GetId().Value()); - } - } - - CSfxManager::SetActiveAreas(areaIds); -} - -void CStateManager::FrameEnd() { - CModel::FrameDone(); - gpSimplePool->Flush(); -} - -void CStateManager::ProcessPlayerInput() { - if (x84c_player != nullptr) { - x84c_player->ProcessInput(xb54_finalInput, *this); - } -} - -void CStateManager::ProcessInput(const CFinalInput& input) { - static CFinalInput skDefaultInput; - - if (input.ControllerNumber() == 0) { - const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); - bool disableInput = cam.DisablesInput(); - - const uchar playerFlags = - *reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(x84c_player) + 0x9c6); - if ((playerFlags >> 2) & 1) { - disableInput = true; - } - - if (disableInput) { - xb54_finalInput = skDefaultInput; - xb54_finalInput.SetTime(input.Time()); - } else { - xb54_finalInput = input; - } - } - - x870_cameraManager->ProcessInput(input, *this); -} - -void CStateManager::Update(float dt) { - lbl_805A88B8 = static_cast< ushort >(x8d8_updateFrameIdx); - lbl_805A8A10 = static_cast< ushort >(x8d8_updateFrameIdx); - CDecal::SetGlobalSeed(static_cast< ushort >(x8d8_updateFrameIdx)); - CProjectileWeapon::SetGlobalSeed(x8d8_updateFrameIdx); - - xf14_curTimeMod900 += dt; - if (xf14_curTimeMod900 > 900.f) { - xf14_curTimeMod900 -= 900.f; - } - - xf08_pauseHudMessage = kInvalidAssetId; - - ResetParticleCounts__13CScriptEffectFv(); - UpdateThermalVisor(); - fn_8004B504(this); - UpdateGameState(); - - const float deathTime = - *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(x84c_player) + 0x9f4); - const bool isDead = deathTime > 0.f; - - if (x904_gameState == kGS_Running) { - if (TCastToPtr< CCinematicCamera >( - const_cast< CGameCamera& >(x870_cameraManager->GetCurrentCamera(*this))) == nullptr) { - SetTotalPlayTime__10CGameStateFd( - gpGameState, - dt + *reinterpret_cast< const double* >(reinterpret_cast< const uchar* >(gpGameState) + 0xa0)); - UpdateHintState(dt); - } - - CCameraFilterPass* filt = xb84_camFilterPasses.data(); - CCameraBlurPass* blur = xd14_camBlurPasses.data(); - for (int i = 0; i < kCFS_Max; ++i) { - filt->Update(dt); - Update__15CCameraBlurPassFf(blur, dt); - ++filt; - ++blur; - } - } - - if (x904_gameState != kGS_Paused) { - PreThinkObjects(dt); - x87c_fluidPlaneManager->Update(dt); - } - - if (x904_gameState == kGS_Running) { - if (!isDead) { - Update__13CDecalManagerFfR13CStateManager(dt, this); - } - - UpdateSortedLists(); - - if (!isDead) { - MovePlatforms(dt); - MoveDoors(dt); - } - - ProcessPlayerInput(); - - if (x904_gameState != kGS_SoftPaused) { - CGameCollision::Move(*this, *x84c_player, dt, nullptr); - } - - UpdateSortedLists(); - - if (!isDead) { - CrossTouchActors__13CStateManagerFf(this); - } - } else { - ProcessPlayerInput(); - } - - if (!isDead && x904_gameState == kGS_Running) { - x884_actorModelParticles->Update(dt, *this); - } - - if (x904_gameState == kGS_Running || x904_gameState == kGS_SoftPaused) { - Think(dt); - } - - if (x904_gameState != kGS_SoftPaused) { - x870_cameraManager->Update(dt, *this); - } - - while (xf76_lastRelay != kInvalidUniqueId) { - CEntity* ent = ObjectById(xf76_lastRelay); - if (ent == nullptr) { - xf76_lastRelay = kInvalidUniqueId; - break; - } - - ent->Think(dt, *this); - } - - if (x904_gameState != kGS_Paused) { - PostUpdatePlayer(dt); - } - - if (xf84_ == xf80_hudMessageFrameCount) { - ShowPausedHUDMemo(xf88_, xf8c_); - --xf84_; - xf88_ = kInvalidAssetId; - } - - if (!isDead && x904_gameState == kGS_Running && !x870_cameraManager->IsInCinematicCamera()) { - UpdateEscapeSequenceTimer(dt); - } - - Update__6CWorldFf(x850_world.get(), dt); - x88c_rumbleManager->Update(dt); - - if (!isDead) { - Update__13CEnvFxManagerFfR13CStateManager(dt, x880_envFxManager, this); - } - - UpdateAreaSounds(); - - xf94_24_readyToRender = true; - - if (xf94_27_inMapScreen) { - CHintOptions& hintOptions = gpGameState->HintOptions(); - CHintOptions::SHintState* hint = - const_cast< CHintOptions::SHintState* >(hintOptions.GetCurrentDisplayedHint()); - if (hint != nullptr && hint->CanContinue()) { - DismissDisplayedHint__12CHintOptionsFv(&hintOptions); - } - xf94_27_inMapScreen = false; - } - - SetAreaId__11CWorldStateF7TAreaId(&gpGameState->CurrentWorldState(), x8cc_nextAreaId); - - TravelToArea__6CWorldFRC7TAreaIdR13CStateManagerb(x850_world.get(), x8cc_nextAreaId, this, - false); - - ClearGraveyard(); - ++x8d8_updateFrameIdx; -} - -void CStateManager::PostUpdatePlayer(float dt) { x84c_player->DoPostCameraStuff(dt, *this); } - -void CStateManager::UpdateGameState() {} - -void CStateManager::SwapOutTexturesToARAM(int, unsigned int) {} - void CStateManager::CreateStandardGameObjects() { const float xyHalfExtent = gpTweakPlayer->GetPlayerXYHalfExtent(); const float stepUp = gpTweakPlayer->GetStepUpHeight(); @@ -1378,10 +814,9 @@ void CStateManager::CreateStandardGameObjects() { CMatrix3f mtx = quat.BuildTransform(); CTransform4f xf = CTransform4f(mtx.GetColumn(kDX), mtx.GetColumn(kDY), mtx.GetColumn(kDZ), pos); - x84c_player = - rs_new CPlayer(uid, xf, playerBounds, gpTweakPlayerRes->xc4_ballTransitionsANCS, - CVector3f(1.65f, 1.65f, 1.65f), 200.f, stepUp, stepDown, ballRadius, - CMaterialList(kMT_Player, kMT_Solid, kMT_GroundCollider)); + x84c_player = rs_new CPlayer(uid, xf, playerBounds, gpTweakPlayerRes->xc4_ballTransitionsANCS, + CVector3f(1.65f, 1.65f, 1.65f), 200.f, stepUp, stepDown, ballRadius, + CMaterialList(kMT_Player, kMT_Solid, kMT_GroundCollider)); AddObject(*x84c_player); x870_cameraManager->CreateCameras(*this); } @@ -1487,6 +922,8 @@ void CStateManager::FrameBegin(unsigned int frame) { SwapOutTexturesToARAM(2, 0x180000); } +void CStateManager::SwapOutTexturesToARAM(int, unsigned int) {} + const bool CStateManager::MemoryAllocatorAllocationFailedCallback(const void* obj, unsigned int) { return static_cast< CStateManager* >(const_cast< void* >(obj))->SwapOutAllPossibleMemory(); } @@ -1498,1189 +935,7 @@ bool CStateManager::SwapOutAllPossibleMemory() { return true; } -void CStateManager::RendererDrawCallback(const void*, const void*, int) {} - -void CStateManager::InformListeners(const CVector3f& pos, EListenNoiseType type) { - CObjectList* list = x808_objectLists[kOL_ListeningAi].get(); - for (int i = list->GetFirstObjectIndex(); i != -1; i = list->GetNextObjectIndex(i)) { - CPatterned* patterned = TCastToPtr< CPatterned >((*list)[i]); - if (patterned != nullptr) { - if (patterned->GetActive()) { - const TAreaId areaId2 = patterned->x4_areaId; - const TAreaId areaId = areaId2; - CGameArea* area = x850_world->Area(areaId); - CGameArea::EOcclusionState occState; - if (area->IsPostConstructed()) { - occState = area->GetPostConstructed()->x10dc_occlusionState; - } else { - occState = CGameArea::kOS_Occluded; - } - - if (occState != CGameArea::kOS_Occluded) { - patterned->Listen(pos, type); - } - } - } - } -} - -rstl::pair< TEditorId, TUniqueId > CStateManager::GenerateObject(const TEditorId& eid) { - const rstl::pair< const SScriptObjectStream*, TEditorId > build = GetBuildForScript(eid); - TAreaId aid = TAreaId(build.second.AreaNum()); - if (build.first != nullptr) { - CGameArea* area = x850_world->Area(aid); - if (area->IsPostConstructed()) { - int layer = static_cast< int >(build.second.value >> 26); - SScriptLayerBuffer layerBuf; - GetLayerScriptBuffer__9CGameAreaFi(&layerBuf, area, &layer); - - CMemoryInStream stream(static_cast< const uchar* >(layerBuf.x0_buf) + build.first->x4_position, - build.first->x8_length); - return LoadScriptObject(aid, build.first->x0_type, build.first->x8_length, stream); - } - } - - return rstl::pair< TEditorId, TUniqueId >(kInvalidEditorId, kInvalidUniqueId); -} - -void CStateManager::InitScriptObjects(const rstl::vector< TEditorId >& ids) { - for (int i = 0; i < static_cast< int >(ids.size()); ++i) { - if (ids[i] != kInvalidEditorId) { - TEditorId id = ids[i]; - TUniqueId uid = GetIdForScript(id); - SendScriptMsgAlways(uid, kInvalidUniqueId, kSM_InitializedInArea); - } - } - - MurderScriptInstanceNames(); -} - -CStateManager::TIdListResult CStateManager::GetIdListForScript(TEditorId eid) const { - rstl::multimap< TEditorId, TUniqueId >::const_iterator firstIt = x890_scriptIdMap.find(eid); - rstl::multimap< TEditorId, TUniqueId >::const_iterator lastIt = firstIt; - - if (firstIt != x890_scriptIdMap.end()) { - for (; lastIt != x890_scriptIdMap.end() && lastIt->first == eid; ++lastIt) { - } - } - - const TIdList::const_iterator first = - *reinterpret_cast< const TIdList::const_iterator* >(&firstIt); - const TIdList::const_iterator last = *reinterpret_cast< const TIdList::const_iterator* >(&lastIt); - return TIdListResult(first, last); -} - -TUniqueId CStateManager::GetIdForScript(TEditorId eid) const { - rstl::multimap< TEditorId, TUniqueId >::const_iterator it = x890_scriptIdMap.find(eid); - if (it != x890_scriptIdMap.end()) { - return it->second; - } - return kInvalidUniqueId; -} - -TEditorId CStateManager::GetEditorIdForUniqueId(TUniqueId uid) const { - const CEntity* ent = GetObjectById(uid); - if (ent != nullptr) { - return ent->GetEditorId(); - } - return kInvalidEditorId; -} - -rstl::pair< const SScriptObjectStream*, TEditorId > -CStateManager::GetBuildForScript(TEditorId eid) const { - rstl::map< TEditorId, SScriptObjectStream >::const_iterator it = - x8a4_loadedScriptObjects.find(eid); - if (it != x8a4_loadedScriptObjects.end()) { - return rstl::pair< const SScriptObjectStream*, TEditorId >(&it->second, it->first); - } - - return rstl::pair< const SScriptObjectStream*, TEditorId >(0, kInvalidEditorId); -} - -void CStateManager::LoadScriptObjects(TAreaId aid, CInputStream& in, EScriptPersistence persist) { - in.ReadChar(); - - int count = in.ReadLong(); - persist.reserve(count + persist.size()); - while (count != 0) { - const char type = in.ReadChar(); - const uint length = in.ReadLong(); - const uint readPos = in.GetReadPosition(); - - const rstl::pair< TEditorId, TUniqueId > loaded = - LoadScriptObject(aid, static_cast< EScriptObjectType >(type), length, in); - const TEditorId eid = loaded.first; - if (eid != kInvalidEditorId) { - const rstl::pair< const SScriptObjectStream*, TEditorId > build = GetBuildForScript(eid); - if (build.first == NULL) { - SScriptObjectStream stream; - stream.x0_type = static_cast< EScriptObjectType >(type); - stream.x4_position = readPos; - stream.x8_length = length; - x8a4_loadedScriptObjects.insert(rstl::pair< TEditorId, SScriptObjectStream >(eid, stream)); - persist.push_back(eid); - } - } - - --count; - } -} - -rstl::pair< TEditorId, TUniqueId > -CStateManager::LoadScriptObject(TAreaId aid, EScriptObjectType type, unsigned int length, - CInputStream& in) { - bool failed = false; - const TEditorId eid = in.ReadLong(); - - rstl::vector< SConnection > conns; - const uint connCount = in.ReadLong(); - conns.reserve(connCount); - - uint bytesLeft = length - 8; - for (uint i = 0; i < connCount; ++i) { - const EScriptObjectState state = static_cast< EScriptObjectState >(in.ReadLong()); - const EScriptObjectMessage msg = static_cast< EScriptObjectMessage >(in.ReadLong()); - const TEditorId target = in.ReadLong(); - bytesLeft -= 12; - conns.push_back(SConnection(state, msg, target)); - } - - const uint propCount = in.ReadLong(); - bytesLeft -= 4; - const uint readPos = in.GetReadPosition(); - - CEntity* ent = NULL; - FScriptLoader loader = NULL; - if (type <= kST_EnergyBall && type >= kST_Actor) { - loader = x90c_loaderFuncs[type]; - } - - if (loader == NULL) { - failed = true; - } else { - CEntityInfo info(aid, conns, eid); - ent = loader(*this, in, propCount, info); - } - - if (ent == NULL) { - failed = true; - } else { - AddObject(*ent); - } - - uint leftOver = bytesLeft - (in.GetReadPosition() - readPos); - while (leftOver != 0) { - in.ReadChar(); - --leftOver; - } - - if (failed || ent == NULL) { - return rstl::pair< TEditorId, TUniqueId >(kInvalidEditorId, kInvalidUniqueId); - } - return rstl::pair< TEditorId, TUniqueId >(eid, ent->GetUniqueId()); -} - -void CStateManager::FreeScriptObjects(TAreaId aid) { - rstl::multimap< TEditorId, TUniqueId >::iterator scriptIt = x890_scriptIdMap.get_inner().begin(); - while (scriptIt != x890_scriptIdMap.get_inner().end()) { - rstl::multimap< TEditorId, TUniqueId >::iterator cur = scriptIt; - ++scriptIt; - - if (cur->first.AreaNum() == aid.Value()) { - DeleteObjectRequest(cur->second); - } - } - - typedef rstl::red_black_tree< - TEditorId, rstl::pair< TEditorId, SScriptObjectStream >, 0, - rstl::select1st< rstl::pair< TEditorId, SScriptObjectStream > >, rstl::less< TEditorId >, - rstl::rmemory_allocator > TLoadedScriptObjMapInner; - - TLoadedScriptObjMapInner& loadedScriptObjects = - *reinterpret_cast< TLoadedScriptObjMapInner* >(&x8a4_loadedScriptObjects); - - TLoadedScriptObjMapInner::iterator loadedIt = loadedScriptObjects.begin(); - while (loadedIt != loadedScriptObjects.end()) { - TLoadedScriptObjMapInner::iterator cur = loadedIt; - ++loadedIt; - - if (cur->first.AreaNum() == aid.Value()) { - loadedScriptObjects.erase(cur); - } - } - - CGameArea* area = x850_world->Area(aid); - if (area->IsPostConstructed()) { - CObjectList* areaObjList = - static_cast< CObjectList* >(area->GetPostConstructed()->x10c0_areaObjectList); - - for (int i = areaObjList->GetFirstObjectIndex(); i != -1; i = areaObjList->GetNextObjectIndex(i)) { - CEntity* ent = (*areaObjList)[i]; - if (ent != nullptr && !ent->x30_27_notInArea) { - DeleteObjectRequest(ent->GetUniqueId()); - } - } - } -} - -void CStateManager::SendScriptMsg(TUniqueId uid, TEditorId target, EScriptObjectMessage msg, - EScriptObjectState) { - GetObjectById(uid); - - TIdListResult search = GetIdListForScript(target); - if (search.first == search.second) { - return; - } - - TIdList::const_iterator it = search.first; - for (; it != search.second; ++it) { - DeliverScriptMsg(x808_objectLists[0]->GetObjectById(it->second), uid, msg); - } -} - -void CStateManager::RecursiveDrawTree(TUniqueId uid) const { - CActor* actor = TCastToPtr< CActor >(const_cast< CEntity* >(GetObjectById(uid))); - if (actor != NULL && - x8dc_objectDrawToken != - *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xc8)) { - const TUniqueId nextNode = - *reinterpret_cast< TUniqueId* >(reinterpret_cast< uchar* >(actor) + 0xc6); - if (nextNode != kInvalidUniqueId) { - RecursiveDrawTree(nextNode); - } - if (x8dc_objectDrawToken == - *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xcc)) { - actor->Render(*this); - } - *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xc8) = x8dc_objectDrawToken; - } -} - -bool CStateManager::GetVisSetForArea(TAreaId areaA, TAreaId areaB, CPVSVisSet& setOut) const { - if (areaB == kInvalidAreaId) { - return false; - } - - const CTransform4f& viewXf = CGraphics::GetViewMatrix(); - const CVector3f viewPoint(viewXf.Get03(), viewXf.Get13(), viewXf.Get23()); - CVector3f closestDockPoint = viewPoint; - - bool hasClosestDock = false; - if (areaA == areaB) { - hasClosestDock = true; - } else { - const CGameArea* area = x850_world->GetArea(areaB); - if (area->IsPostConstructed()) { - for (int i = 0; i < area->GetDockCount(); ++i) { - const IGameArea::Dock& dock = area->GetDock(i); - const int connCount = dock.GetDockRefs().size(); - for (int conn = 0; conn < connCount; ++conn) { - if (dock.GetConnectedAreaId(conn) != areaA) { - continue; - } - - const rstl::reserved_vector< CVector3f, 4 >& verts = dock.GetPlaneVertices(); - const CVector3f dockCenter( - 0.25f * (verts[0].GetX() + verts[1].GetX() + verts[2].GetX() + verts[3].GetX()), - 0.25f * (verts[0].GetY() + verts[1].GetY() + verts[2].GetY() + verts[3].GetY()), - 0.25f * (verts[0].GetZ() + verts[1].GetZ() + verts[2].GetZ() + verts[3].GetZ())); - - if (hasClosestDock) { - const CVector3f oldDelta = closestDockPoint - viewPoint; - const CVector3f newDelta = dockCenter - viewPoint; - if (newDelta.MagSquared() >= oldDelta.MagSquared()) { - continue; - } - } - - closestDockPoint = dockCenter; - hasClosestDock = true; - } - } - } - } - - int setState = 0; - if (hasClosestDock) { - setState = 1; - - const CGameArea* area = x850_world->GetArea(areaA); - const CPVSAreaSet* areaSet = area->GetPostConstructed()->xa0_pvs; - if (areaSet != nullptr) { - setState = 2; - - const uint worldAreaArg = - *reinterpret_cast< const uint* >(reinterpret_cast< const uchar* >(x850_world.get()) + 0x20); - CPVSVisOctree& visOctree = - *const_cast< CPVSVisOctree* >(&areaSet->GetVisOctree(worldAreaArg)); - - const CTransform4f& invAreaXf = *reinterpret_cast< const CTransform4f* >( - reinterpret_cast< const uchar* >(area) + 0x3c); - const CVector3f localPoint = invAreaXf * closestDockPoint; - - CPVSVisSet visSet = visOctree.GetVisSet(localPoint); - if (*reinterpret_cast< const int* >(reinterpret_cast< const uchar* >(&visSet)) == - kVSS_NodeFound) { - setOut = visSet; - setState = 3; - } - } - } - - return setState == 3; -} - -extern "C" CGameArea::CChainIterator AliveAreasEnd__6CWorldFv() { - return CGameArea::CChainIterator(lbl_805A8DDC); -} - -void CStateManager::PreRender() { - CStateManager* mgr = this; - if (!mgr->xf94_24_readyToRender) { - return; - } - - CStopwatch timer; - - mgr->x86c_stateManagerContainer->xf370_.clear(); - mgr->x86c_stateManagerContainer->xf39c_renderLast.clear(); - mgr->xf7c_projectedShadow = nullptr; - - PreRender__6CWorldFv(mgr->x850_world.get()); - mgr->BuildDynamicLightListForWorld(); - - const CGameCamera& curCam = mgr->x870_cameraManager->GetCurrentCamera(*mgr); - const CTransform4f curCamXf = mgr->x870_cameraManager->GetCurrentCameraTransform(*mgr); - CFrustumPlanes frustum(curCamXf, 0.017453292f * curCam.GetFov(), curCam.GetAspectRatio(), - curCam.GetNearClipDistance(), false, 100.f); - - for (CGameArea::CChainIterator areaIt = mgr->x850_world->ChainHead(CWorld::kC_Alive); - areaIt != AliveAreasEnd__6CWorldFv(); ++areaIt) { - CGameArea::EOcclusionState occState; - if (areaIt->IsPostConstructed()) { - occState = areaIt->GetPostConstructed()->x10dc_occlusionState; - } else { - occState = CGameArea::kOS_Occluded; - } - - if (occState == CGameArea::kOS_Visible) { - CObjectList* areaObjList = - static_cast< CObjectList* >(areaIt->GetPostConstructed()->x10c0_areaObjectList); - for (int i = areaObjList->GetFirstObjectIndex(); i != -1; - i = areaObjList->GetNextObjectIndex(i)) { - CActor* actor = TCastToPtr< CActor >((*areaObjList)[i]); - if (actor != nullptr && - ((*reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(actor) + 0xe7) >> - 2) & - 1) != 0) { - actor->CalculateRenderBounds(); - actor->PreRender(*mgr, frustum); - } - } - } - } - - if (lbl_805A9E08 == 0) { - mgr->CacheReflection(); - } - - gpRender->PrepareDynamicLights(mgr->x8e0_dynamicLights); - lbl_805A8D98 = timer.GetElapsedMicros(); -} - -CFrustumPlanes CStateManager::SetupViewForDraw(const CViewport& viewport) const { - const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); - const CTransform4f camXf = x870_cameraManager->GetCurrentCameraTransform(*this); - gpRender->SetWorldViewpoint(camXf); - - const CVector3f playerPos = x84c_player->GetTranslation(); - SetNewPlayerPositionAndTime__10CCubeModelFRC9CVector3fRC10CStopwatch( - playerPos, CStopwatch::GetGlobalTimerObj()); - - const float scaledWidth = xf2c_viewportScaleX * static_cast< float >(viewport.mWidth); - const float scaledHeight = xf30_viewportScaleY * static_cast< float >(viewport.mHeight); - const int width = static_cast< int >(scaledWidth); - const int halfHeight = static_cast< int >(scaledHeight) / 2; - - const int left = viewport.mLeft + (viewport.mWidth - width) / 2; - const int top = viewport.mTop + (viewport.mHeight - halfHeight * 2) / 2; - - const float fov = - 2.f * CMath::ArcTangentR(CMath::SlowTangentR(0.5f * ((1.f / 360.f) * (2.f * M_PIF) * - cam.GetFov())) * - xf30_viewportScaleY); - - gpRender->SetViewport(left, top, width, halfHeight * 2); - CGraphics::SetDepthRange(0.125f, 1.f); - - const float zFar = *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&cam) + 0x164); - gpRender->SetPerspective(360.f * ((1.f / (2.f * M_PIF)) * fov), scaledWidth, scaledHeight, - cam.GetNearClipDistance(), zFar); - - CFrustumPlanes frustum(camXf, fov, (xf2c_viewportScaleX * cam.GetAspectRatio()) / xf30_viewportScaleY, - cam.GetNearClipDistance(), false, 100.f); - gpRender->SetClippingPlanes(frustum); - gpRender->PrimColor(CColor::White()); - gpRender->SetModelMatrix(CTransform4f::Identity()); - - x87c_fluidPlaneManager->StartFrame(false); - gpRender->SetDebugOption(IRenderer::kDO_PVSState, 1); - - return frustum; -} - -bool CStateManager::SetupFogForDraw() const { - switch (x8b8_playerState->GetActiveVisor(*this)) { - case CPlayerState::kPV_Thermal: - gpRender->SetWorldFog(kRFM_None, 0.f, 1.f, CColor::Black()); - return true; - case CPlayerState::kPV_XRay: - default: - return false; - case CPlayerState::kPV_Combat: - case CPlayerState::kPV_Scan: { - const CGameArea::CAreaFog* fog = reinterpret_cast< const CGameArea::CAreaFog* >( - reinterpret_cast< const uchar* >(x870_cameraManager) + 0x3c); - if (fog->IsFogDisabled()) { - return false; - } - fog->SetCurrent(); - return true; - } - } -} - -void CStateManager::SetupFogForArea(const CGameArea& area) const { - if (SetupFogForDraw()) { - return; - } - - if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_XRay) { - const float fogDist = GetXRayFogDistance__9CGameAreaFv(const_cast< CGameArea* >(&area)); - const CTweakGui* tweak = gpTweakGui; - const float fogFarZ = tweak->GetXRayFogFarZ(); - const float nearZ = tweak->GetXRayFogNearZ(); - const float farZ = nearZ * (1.f - fogDist) + fogFarZ * fogDist; - gpRender->SetWorldFog(static_cast< ERglFogMode >(tweak->GetXRayFogMode()), nearZ, farZ, - tweak->GetXRayFogColor()); - } else { - area.GetPostConstructed()->x10c4_areaFog->SetCurrent(); - } -} - -void CStateManager::SetupFogForArea(TAreaId area) const { - TAreaId areaValue; - const TAreaId* areaId = &area; - int nextArea; - if (area == kInvalidAreaId) { - nextArea = x8cc_nextAreaId.Value(); - areaId = reinterpret_cast< const TAreaId* >(&nextArea); - } - - areaValue = *areaId; - const CGameArea* areaObj = x850_world->GetArea(areaValue); - if (areaObj->IsPostConstructed()) { - SetupFogForArea(*areaObj); - } -} - -void CStateManager::SetupFogForArea3XRange(TAreaId area) const { - TAreaId areaValue; - const TAreaId* areaId = &area; - int nextArea; - if (area == kInvalidAreaId) { - nextArea = x8cc_nextAreaId.Value(); - areaId = reinterpret_cast< const TAreaId* >(&nextArea); - } - - areaValue = *areaId; - const CGameArea* areaObj = x850_world->GetArea(areaValue); - if (areaObj->IsPostConstructed()) { - fn_80046DE8(this, areaObj); - } -} - -void CStateManager::DrawWorld() const { - - const CTimeProvider timeProvider(xf14_curTimeMod900); - const CViewport backupViewport = CGraphics::GetViewport(); - - /* Area camera is in (not necessarily player) */ - const TAreaId visAreaId = GetVisAreaId(); - - x850_world->TouchSky(); - - const CFrustumPlanes frustum = SetupViewForDraw(CGraphics::GetViewport()); - const CTransform4f backupViewMatrix = CGraphics::GetViewMatrix(); - - int areaCount = 0; - const CGameArea* areaArr[10]; - - CGameArea::CConstChainIterator it = x850_world->GetChainHead(CWorld::kC_Alive); - CGameArea::CConstChainIterator end = x850_world->GetAliveAreasEnd(); - for (; it != end; ++it) { - if (areaCount == 10) { - break; - } - CGameArea::EOcclusionState occState = CGameArea::kOS_Occluded; - if (it->IsLoaded()) { - occState = it->GetOcclusionState(); - } - if (occState == CGameArea::kOS_Visible) { - areaArr[areaCount++] = &*it; - } - } - - // rstl::sort(&areaArr[0], &areaArr[areaCount], area_sorter(CGraphics::GetViewPoint(), - // visAreaId)); -} - -void CStateManager::ResetViewAfterDraw(const CViewport& backupViewport, - const CTransform4f& backupViewMatrix) const { - gpRender->SetViewport(backupViewport.mLeft, backupViewport.mTop, backupViewport.mWidth, - backupViewport.mHeight); - - const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); - CFrustumPlanes frustum(backupViewMatrix, 0.017453292f * cam.GetFov(), cam.GetAspectRatio(), - cam.GetNearClipDistance(), false, 100.f); - gpRender->SetClippingPlanes(frustum); - - const CViewport& viewport = CGraphics::GetViewport(); - const float zFar = *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&cam) + 0x164); - gpRender->SetPerspective(cam.GetFov(), static_cast< float >(viewport.mWidth), - static_cast< float >(viewport.mHeight), cam.GetNearClipDistance(), zFar); -} - -void CStateManager::DrawAdditionalFilters() const { - if (xf0c_escapeTimer < 1.f && xf0c_escapeTimer > 0.f && !x870_cameraManager->IsInCinematicCamera()) { - const float alpha = 1.f - xf0c_escapeTimer; - const CColor color = CColor::White().WithAlphaOf(alpha); - CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Add, CCameraFilterPass::kFS_Fullscreen, - color, 0, 1.f); - } -} - -void CStateManager::DrawE3DeathEffect() const { - const CPlayer* player = x84c_player; - const float deathTime = - *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(player) + 0x9f4); - float blurFactor; - float whiteFactor; - - if (deathTime > 0.f) { - if (player->GetMorphballTransitionState() != CPlayer::kMS_Unmorphed) { - blurFactor = (deathTime - 1.f) / (lbl_805A9E10 - 1.f); - const float blurAmt = CMath::Clamp(0.f, blurFactor, 1.f); - if (blurAmt > 0.f) { - CCameraBlurPass blur; - blur.SetBlur(CCameraBlurPass::kBT_HiBlur, 7.f * blurAmt, 0.f, false); - blur.Draw(); - } - } - - whiteFactor = 1.f - deathTime / (lbl_805AA2D4 * lbl_805A9E10); - const float whiteAmt = CMath::Clamp(0.f, whiteFactor, 1.f); - const CColor color = CColor::White().WithAlphaOf(whiteAmt); - CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Add, CCameraFilterPass::kFS_Fullscreen, - color, 0, 1.f); - } -} - -void CStateManager::RenderCamerasAndAreaLights() const { - x870_cameraManager->Render(*this); - for (int i = 0; i < kCFS_Max; ++i) { - xb84_camFilterPasses[i].Draw(); - } -} - -void CStateManager::DrawDebugStuff() const {} - -void CStateManager::BuildDynamicLightListForWorld() { - if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Thermal) { - x8e0_dynamicLights = rstl::vector< CLight >(); - return; - } - - const CObjectList& list = GetObjectListById(kOL_GameLight); - int listSize = list.size(); - if (listSize == 0) { - return; - } - - if (x8e0_dynamicLights.capacity() != listSize) { - x8e0_dynamicLights = rstl::vector< CLight >(); - x8e0_dynamicLights.reserve(listSize); - } else { - x8e0_dynamicLights.clear(); - } - - for (int idx = list.GetFirstObjectIndex(); idx != -1; idx = list.GetNextObjectIndex(idx)) { - const CGameLight* light = static_cast< const CGameLight* >(list[idx]); - if (light && light->GetActive()) { - const CLight& l = light->GetLight(); - if (l.GetIntensity() > FLT_EPSILON && l.GetRadius() > FLT_EPSILON) { - // TODO: This shouldn't be inlined, but currently is. - x8e0_dynamicLights.push_back(l); - } - } - } - rstl::sort(x8e0_dynamicLights.begin(), x8e0_dynamicLights.end(), CLightPredicate()); -} - -bool CStateManager::CanCreateProjectile(TUniqueId uid, EWeaponType type, int maxAllowed) const { - return x878_weaponMgr->GetNumActive(uid, type) < maxAllowed; -} - -void CStateManager::ReflectionDrawer(void* ctx, const CVector3f& point) { - DrawReflection__13CStateManagerFRC9CVector3f(static_cast< CStateManager* >(ctx), point); -} - -void CStateManager::CacheReflection() { - typedef void (*TCacheReflectionFn)(IRenderer*, void (*)(void*, const CVector3f&), void*, bool); - TCacheReflectionFn cacheReflection = *reinterpret_cast< TCacheReflectionFn* >( - reinterpret_cast< uchar* >(*reinterpret_cast< void** >(gpRender)) + 0xc8); - cacheReflection(gpRender, ReflectionDrawer, this, !lbl_805A9E08); -} - -void CStateManager::DrawReflection(const CVector3f& point) { - CPlayer* player = x84c_player; - CAABox playerBounds = player->GetBoundingBox(); - CVector3f playerPos = playerBounds.GetCenterPoint(); - - const CVector3f viewPos = - playerPos - - 3.5f * CVector3f(playerPos.GetX() - point.GetX(), playerPos.GetY() - point.GetY(), - playerPos.GetZ() - playerPos.GetZ()) - .AsNormalized(); - - CTransform4f reflectionXf = CTransform4f::LookAt(viewPos, playerPos, CVector3f(0.f, 0.f, -1.f)); - const CTransform4f backupView = CGraphics::GetViewMatrix(); - CGraphics::SetViewPointMatrix(reflectionXf); - - const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); - const CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState(); - - const CViewport& viewport = CGraphics::GetViewport(); - const float zFar = - *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&curCam) + 0x164); - gpRender->SetPerspective(curCam.GetFov(), static_cast< float >(viewport.mWidth), - static_cast< float >(viewport.mHeight), curCam.GetNearClipDistance(), zFar); - - player->RenderReflectedPlayer(*this); - - CGraphics::SetViewPointMatrix(backupView); - CGraphics::SetProjectionState(backupProj); -} - -void CStateManager::DrawSpaceWarp(const CVector3f& point, float strength) const { - switch (x8b8_playerState->GetActiveVisor(*this)) { - case CPlayerState::kPV_XRay: - case CPlayerState::kPV_Thermal: - return; - default: - break; - } - - const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); - CVector3f screenPoint; - ConvertToScreenSpace__11CGameCameraCFRC9CVector3f(&screenPoint, &curCam, &point); - gpRender->DrawSpaceWarp(screenPoint, strength); -} - -void CStateManager::TouchSky() const { x850_world->TouchSky(); } - -void CStateManager::TouchPlayerActor() const { - if (xf6c_playerActorHead != kInvalidUniqueId) { - const CEntity* ent = GetObjectById(xf6c_playerActorHead); - if (ent != nullptr) { - TouchModels__18CScriptPlayerActorFRC13CStateManager(const_cast< CEntity* >(ent), *this); - } - } -} - -void CStateManager::SetActorAreaId(CActor& actor, TAreaId aid) { - const int oldArea = actor.x4_areaId.value; - if (oldArea != aid.value) { - CWorld* world = x850_world.get(); - - if (oldArea != kInvalidAreaId.value) { - TAreaId oldAid = actor.x4_areaId; - TAreaId oldAid2 = actor.x4_areaId; - CGameArea* oldAreaObj = world->Area(oldAid); - if (oldAreaObj->IsPostConstructed()) { - static_cast< CObjectList* >(oldAreaObj->GetPostConstructed()->x10c0_areaObjectList) - ->RemoveObject(actor.GetUniqueId()); - } - } - - actor.x4_areaId = aid; - - if (aid != kInvalidAreaId) { - TAreaId newAid = aid; - CGameArea* newAreaObj = world->Area(newAid); - if (newAreaObj->IsPostConstructed()) { - TUniqueId uid = actor.GetUniqueId(); - CObjectList* areaObjList = - static_cast< CObjectList* >(newAreaObj->GetPostConstructed()->x10c0_areaObjectList); - if (static_cast< const CObjectList* >(areaObjList)->GetValidObjectById(uid) == nullptr) { - areaObjList->AddObject(actor); - } - } - } - } -} - -void CStateManager::AddWeaponId(TUniqueId uid, EWeaponType type) { - x878_weaponMgr->IncrCount(uid, type); -} - -void CStateManager::RemoveWeaponId(TUniqueId uid, EWeaponType type) { - x878_weaponMgr->DecrCount(uid, type); -} - -int CStateManager::GetWeaponIdCount(TUniqueId uid, EWeaponType type) { - return x878_weaponMgr->GetNumActive(uid, type); -} - -TAreaId CStateManager::GetVisAreaId() const { - const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); - const CBallCamera* ballCam = x870_cameraManager->GetBallCamera(); - const TAreaId curArea = x850_world->GetCurrentAreaId(); - if (&curCam != ballCam) { - return curArea; - } - - const CVector3f camTranslation = ballCam->GetTranslation(); - const CVector3f playerTranslation = x84c_player->GetTranslation(); - CAABox camAABB(camTranslation, camTranslation); - camAABB.AccumulateBounds(playerTranslation); - - TEntityList nearList; - const CMaterialFilter filter = CMaterialFilter::MakeInclude(CMaterialList(kMT_AIBlock)); - BuildNearList(nearList, camAABB, filter, nullptr); - for (const TUniqueId* uid = nearList.begin(); uid != nearList.end(); ++uid) { - const CScriptDock* dock = TCastToConstPtr< CScriptDock >(GetObjectById(*uid)); - if (dock != nullptr && dock->GetAreaId() == curArea && dock->HasPointCrossedDock(*this, camTranslation)) { - return dock->GetCurrentConnectedAreaId(*this); - } - } - - return curArea; -} - -const rstl::string& CStateManager::HashInstanceName(CInputStream& in) { - rstl::string instanceName(in); - rstl::set< rstl::string >::iterator it = xb40_uniqueInstanceNames.find(instanceName); - if (it == xb40_uniqueInstanceNames.end()) { - it = xb40_uniqueInstanceNames.insert(instanceName); - } - - return **it; -} - -void CStateManager::MurderScriptInstanceNames() { - bool done = false; - - while (!done) { - done = true; - - rstl::set< rstl::string >::iterator it = xb40_uniqueInstanceNames.begin(); - rstl::set< rstl::string >::iterator end = xb40_uniqueInstanceNames.end(); - for (; it != end; ++it) { - const rstl::string* str = *it; - const void* cow = - *reinterpret_cast< const void* const* >(reinterpret_cast< const uchar* >(str) + 0x4); - int refCount = -1; - if (cow != nullptr) { - refCount = *reinterpret_cast< const int* >(reinterpret_cast< const uchar* >(cow) + 0x4); - } - - if (refCount == 1) { - xb40_uniqueInstanceNames.erase(it); - done = false; - break; - } - } - } -} - -void CStateManager::SetupParticleHook(const CActor& actor) const { - x884_actorModelParticles->SetupHook(actor.GetUniqueId()); -} - -void CStateManager::ResetEscapeSequenceTimer(float time) { - xf0c_escapeTimer = time; - xf10_escapeTotalTime = time; -} - -float CStateManager::GetEscapeSequenceTimer() const { return xf0c_escapeTimer; } - -void CStateManager::UpdateEscapeSequenceTimer(float dt) { - const float totalTime = xf10_escapeTotalTime; - if (xf0c_escapeTimer > 0.f) { - xf0c_escapeTimer = rstl::max_val(gkEpsilon, xf0c_escapeTimer - dt); - if (xf0c_escapeTimer <= FLT_EPSILON) { - struct SPlayerStateFlags { - bool x0_24_alive : 1; - }; - reinterpret_cast< SPlayerStateFlags* >(x8b8_playerState.GetPtr())->x0_24_alive = false; - } - - if (!init) { - init = true; - nextShake = 0.f; - } - - nextShake -= dt; - if (nextShake < 0.f) { - const float factor = 1.f - xf0c_escapeTimer / totalTime; - const float factorSq = factor * factor; - { - const CCameraShakeData shakeData(1.f, 0.2f * factorSq * x900_random->Range(0.5f, 1.f)); - x870_cameraManager->AddCameraShaker(shakeData, true); - } - x88c_rumbleManager->Rumble(*this, static_cast< ERumbleFxId >(0xb), 0.75f, kRP_One); - nextShake = -12.f * factorSq + 15.f; - } - } -} - -void CStateManager::UpdateHintState(float dt) { - CHintOptions& hintOpts = gpGameState->HintOptions(); - hintOpts.Update(dt, *this); - - int nextHintIdx = -1; - int hintPeriods = -1; - const SHintState* curHint = hintOpts.GetCurrentDisplayedHint(); - if (curHint != NULL) { - const CGameHintInfo::CGameHint& nextHint = GetGameHints()[hintOpts.GetNextHintIdx()]; - const rstl::vector< CGameHintInfo::SHintLocation >& locations = nextHint.GetLocations(); - for (int i = 0; i < static_cast< int >(locations.size()); ++i) { - const CGameHintInfo::SHintLocation& location = locations[i]; - const TAreaId areaId = location.x8_areaId; - const CAssetId mlvlId = location.x0_mlvlId; - CWorldState& worldState = gpGameState->StateForWorld(mlvlId); - rstl::rc_ptr< CMapWorldInfo > mapWorldInfo = worldState.MapWorldInfo(); - mapWorldInfo->SetIsMapped(areaId, true); - } - - if (curHint->x4_time < nextHint.GetTextTime()) { - nextHintIdx = hintOpts.GetNextHintIdx(); - hintPeriods = static_cast< int >(curHint->x4_time / 3.f); - } - } - - if (nextHintIdx != xeec_hintIdx || hintPeriods != static_cast< int >(xef0_hintPeriods)) { - if (nextHintIdx == -1) { - const rstl::wstring& empty = rstl::wstring_l(L""); - CHUDMemoParms memoInfo(0.f, true, true, true); - CSamusHud::DisplayHudMemo(empty, memoInfo); - } else { - const CGameHintInfo::CGameHint* hint = &GetGameHints()[nextHintIdx]; - SHudMemoInfo memoInfo(0.f, true, false, true); - CSamusHud::DeferHintMemo(hint->GetStringId(), hintPeriods, memoInfo); - } - - xeec_hintIdx = nextHintIdx; - xef0_hintPeriods = hintPeriods; - } -} - -bool CStateManager::SpecialSkipCinematic() { - bool hadRandom = false; - TUniqueId id = xf38_skipCineSpecialFunc; - if (id == kInvalidUniqueId) { - return false; - } - - TUniqueId copyId(id); - CScriptSpecialFunction* special = static_cast< CScriptSpecialFunction* >(ObjectById(copyId)); - if (special == nullptr || !special->ShouldSkipCinematic(*this)) { - return false; - } - - hadRandom = x900_random != nullptr; - x900_random = &x8fc_random; - x870_cameraManager->StopCinematics(*this); - special->SkipCinematic(*this); - x900_random = hadRandom ? &x8fc_random : nullptr; - return true; -} - -bool CStateManager::AddDrawableActor(const CActor& actor, const CVector3f& pos, - const CAABox& bounds) const { - const_cast< CActor& >(actor).SetAddedToken(x8dc_objectDrawToken + 1); - gpRender->AddDrawable(&actor, pos, bounds, 0, IRenderer::kDS_SortedCallback); -} - -void CStateManager::AddDrawableActorPlane(const CActor& actor, const CPlane& plane, - const CAABox& bounds) const { - const_cast< CActor& >(actor).SetAddedToken(x8dc_objectDrawToken + 1); - gpRender->AddPlaneObject(&actor, bounds, plane, 0); -} - -bool CStateManager::RenderLast(const TUniqueId& uid) { - CStateManagerContainer* container = x86c_stateManagerContainer.get(); - CStateManagerContainer* bucket = container; - int count = *reinterpret_cast< int* >(reinterpret_cast< uchar* >(bucket) + 0xf39c); - if (count == 20) { - return false; - } - - TUniqueId* id = reinterpret_cast< TUniqueId* >(reinterpret_cast< uchar* >(bucket) + 0xf3a0) + count; - if (id != nullptr) { - *id = uid; - } - - int* curCount = reinterpret_cast< int* >(reinterpret_cast< uchar* >(container) + 0xf39c); - *curCount = *curCount + 1; - return true; -} - -void CStateManager::DeferStateTransition(EStateManagerTransition t) { - if (t == kSMT_InGame) { - if (xf90_deferredTransition != kSMT_InGame) { - x850_world->SetLoadPauseState(false); - xf90_deferredTransition = kSMT_InGame; - } - } else if (xf90_deferredTransition == kSMT_InGame) { - x850_world->SetLoadPauseState(true); - xf90_deferredTransition = t; - } -} - -void CStateManager::ShowPausedHUDMemo(CAssetId strg, float time) { - xf78_hudMessageTime = time; - xf08_pauseHudMessage = strg; - DeferStateTransition(kSMT_MessageScreen); -} - -bool CStateManager::CanShowMapScreen() { - const SHintState* curHint = gpGameState->HintOptions().GetCurrentDisplayedHint(); - if (curHint != nullptr && !const_cast< SHintState* >(curHint)->CanContinue()) { - return false; - } - return true; -} - -void CStateManager::UpdateThermalVisor() { - xf28_thermColdScale2 = 0.f; - xf24_thermColdScale1 = 0.f; - - if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Thermal && - x8cc_nextAreaId != kInvalidAreaId) { - CGameArea* curArea = x850_world->Area(x8cc_nextAreaId); - CGameArea* bestArea = nullptr; - float bestDistSq = FLT_MAX; - - const float playerX = x84c_player->GetTransform().Get03(); - const float playerY = x84c_player->GetTransform().Get13(); - - for (int i = 0; i < curArea->GetDockCount(); ++i) { - const IGameArea::Dock& dock = curArea->GetDock(i); - const rstl::reserved_vector< CVector3f, 4 >& verts = dock.GetPlaneVertices(); - - const float dockCenterY = - 0.25f * (verts[0].GetY() + verts[1].GetY() + verts[2].GetY() + verts[3].GetY()); - const float dockCenterX = - 0.25f * (verts[0].GetX() + verts[1].GetX() + verts[2].GetX() + verts[3].GetX()); - - const float deltaY = playerY - dockCenterY; - const float deltaX = playerX - dockCenterX; - const float distSq = deltaX * deltaX + deltaY * deltaY; - - if (distSq < bestDistSq) { - const TAreaId connectedAreaId = dock.GetConnectedAreaId(0); - if (connectedAreaId != kInvalidAreaId) { - CGameArea* connectedArea = x850_world->Area(connectedAreaId); - if (connectedArea->IsPostConstructed() && - connectedArea->GetPostConstructed()->x10dc_occlusionState == CGameArea::kOS_Visible) { - bestArea = connectedArea; - bestDistSq = distSq; - } - } - } - } - - const float areaThermal = curArea->GetPostConstructed()->x111c_thermalCurrent; - if (bestArea == nullptr) { - xf24_thermColdScale1 = areaThermal; - } else { - const float dist = CMath::FastSqrtF(bestDistSq); - const float blendDist = dist - 2.f; - if (blendDist >= 8.f) { - xf24_thermColdScale1 = areaThermal; - } else { - float blend = 0.5f; - if (blendDist > 0.f) { - blend = 0.5f * 0.125f * blendDist + 0.5f; - } - xf24_thermColdScale1 = - blend * areaThermal + (1.f - blend) * bestArea->GetPostConstructed()->x111c_thermalCurrent; - } - } - } -} - -void CStateManager::GetCharacterRenderMaskAndTarget(bool thawed, int& mask, int& target) { - mask = 0; - target = 0; - - switch (x8b8_playerState->GetActiveVisor(*this)) { - case CPlayerState::kPV_Combat: - case CPlayerState::kPV_Scan: - mask = 0x1000; - break; - case CPlayerState::kPV_XRay: - mask = 0x800; - break; - case CPlayerState::kPV_Thermal: - if (thawed) { - mask = 0x600; - target = xf34_thermalFlag == kTD_Hot ? 0 : 0x200; - } else { - mask = 0x500; - target = xf34_thermalFlag == kTD_Cold ? 0 : 0x100; - } - break; - default: - break; - } -} - -const CSinglePathMaze* CStateManager::GetSinglePathMaze() const { return xf70_currentMaze.get(); } - -CSinglePathMaze* CStateManager::SinglePathMaze() { return xf70_currentMaze.get(); } - -void CStateManager::SetSinglePathMaze(rstl::single_ptr< CSinglePathMaze > maze) { - xf70_currentMaze = maze; -} - -void CStateManager::SetGameState(EGameState state) { - if (x904_gameState != state) { - if (x904_gameState == kGS_SoftPaused) { - x850_world->SetLoadPauseState(false); - } - - if (state != kGS_SoftPaused) { - if (state < kGS_SoftPaused) { - if (state < kGS_Running) { - } else { - CRumbleGenerator* rumbleGen = reinterpret_cast< CRumbleGenerator* >(x88c_rumbleManager); - if (rumbleGen->GetDisabled()) { - rumbleGen->SetDisabled(false); - } - } - } - } else { - CRumbleGenerator* rumbleGen = reinterpret_cast< CRumbleGenerator* >(x88c_rumbleManager); - if (!rumbleGen->GetDisabled()) { - rumbleGen->SetDisabled(true); - } - x850_world->SetLoadPauseState(true); - } - - x904_gameState = state; - } -} - -void CStateManager::SendScriptMsgAlways(TUniqueId uid, TUniqueId src, EScriptObjectMessage msg) { - CEntity* ent = ObjectById(uid); - if (ent != nullptr) { - ent->AcceptScriptMsg(msg, src, *this); - } -} - -void CStateManager::DeliverScriptMsg(CEntity* ent, TUniqueId target, EScriptObjectMessage msg) { - if (ent != nullptr && !ent->IsScriptingBlocked()) { - ent->AcceptScriptMsg(msg, target, *this); - } -} - -void CStateManager::QueueMessage(int frameCount, CAssetId msg, float f1) { - xf84_ = frameCount; - xf88_ = msg; - xf8c_ = f1; -} - -const CPlayer* CStateManager::GetPlayer() const { return x84c_player; } - -void CStateManager::SetBossParams(TUniqueId bossId, float maxEnergy, uint stringIdx) { - xf18_bossId = bossId; - xf1c_totalBossEnergy = maxEnergy; - xf20_bossStringIdx = stringIdx; -} - -float CStateManager::IntegrateVisorFog(float f) const { - if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Scan) { - return f * (1.f - x8b8_playerState->GetVisorTransitionFactor()); - } - return f; -} - -CRayCastResult CStateManager::RayWorldIntersection(TUniqueId& idOut, const CVector3f& pos, - const CVector3f& dir, float length, - const CMaterialFilter& filter, - const TEntityList& list) const { - return CGameCollision::RayWorldIntersection(*this, idOut, pos, dir, length, filter, list); -} - -void CStateManager::UpdateObjectInLists(CEntity& ent) { - rstl::auto_ptr< CObjectList >* listBegin = x808_objectLists.data(); - for (rstl::auto_ptr< CObjectList >* listIt = listBegin; - listIt != listBegin + x808_objectLists.size(); ++listIt) { - if (static_cast< const CObjectList* >(listIt->get())->GetValidObjectById(ent.GetUniqueId()) != nullptr && - !listIt->get()->IsQualified(ent)) { - listIt->get()->RemoveObject(ent.GetUniqueId()); - } - - if (static_cast< const CObjectList* >(listIt->get())->GetValidObjectById(ent.GetUniqueId()) == nullptr) { - listIt->get()->AddObject(ent); - } - } -} - -void CStateManager::SetCurrentAreaId(TAreaId aid) { - if (x8cc_nextAreaId != aid) { - x8d0_prevAreaId = x8cc_nextAreaId; - UpdateRoomAcoustics(aid); - x8cc_nextAreaId = aid; - } - - const TAreaId& currentArea = aid; - if (currentArea != kInvalidAreaId) { - if (!x8c0_mapWorldInfo->IsAreaVisited(currentArea)) { - x8c0_mapWorldInfo->SetAreaVisited(currentArea, true); - CMapWorldInfo* mapWorldInfo = x8c0_mapWorldInfo.GetPtr(); - CWorld* world = x850_world.get(); - CMapWorld* mapWorld = world->GetMapWorld(); - mapWorld->RecalculateWorldSphere(*mapWorldInfo, *world); - } - } -} - -void CStateManager::UpdateRoomAcoustics(TAreaId aid) { - rstl::reserved_vector< CScriptRoomAcoustics*, 10 > areaAcoustics; - CObjectList* allList = x808_objectLists[kOL_All].get(); - - for (int i = allList->GetFirstObjectIndex(); i != -1 && areaAcoustics.size() < 10; - i = allList->GetNextObjectIndex(i)) { - CEntity* ent = (*allList)[i]; - if (CScriptRoomAcoustics* acoustics = TCastToPtr< CScriptRoomAcoustics >(ent)) { - if (acoustics->GetCurrentAreaId() == aid && acoustics->GetActive()) { - areaAcoustics.push_back(acoustics); - } - } - } - - if (areaAcoustics.size() > 0) { - const int acousticsIdx = - static_cast< int >(0.99f * (x900_random->Float() * static_cast< float >(areaAcoustics.size()))); - areaAcoustics[acousticsIdx]->EnableAuxCallbacks(); - } else { - CScriptRoomAcoustics::DisableAuxCallbacks(); - } -} +void CStateManager::UpdateGameState() {} void CStateManager::MovePlatforms(float dt) { CObjectList* platformAndDoorList = x808_objectLists[kOL_PlatformAndDoor].get(); @@ -2857,3 +1112,1818 @@ void CStateManager::PreThinkObjects(float dt) { } } } + +void CStateManager::PostUpdatePlayer(float dt) { x84c_player->DoPostCameraStuff(dt, *this); } + +void CStateManager::Update(float dt) { + lbl_805A88B8 = static_cast< ushort >(x8d8_updateFrameIdx); + lbl_805A8A10 = static_cast< ushort >(x8d8_updateFrameIdx); + CDecal::SetGlobalSeed(static_cast< ushort >(x8d8_updateFrameIdx)); + CProjectileWeapon::SetGlobalSeed(x8d8_updateFrameIdx); + + xf14_curTimeMod900 += dt; + if (xf14_curTimeMod900 > 900.f) { + xf14_curTimeMod900 -= 900.f; + } + + xf08_pauseHudMessage = kInvalidAssetId; + + ResetParticleCounts__13CScriptEffectFv(); + UpdateThermalVisor(); + fn_8004B504(this); + UpdateGameState(); + + const float deathTime = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(x84c_player) + 0x9f4); + const bool isDead = deathTime > 0.f; + + if (x904_gameState == kGS_Running) { + if (TCastToPtr< CCinematicCamera >( + const_cast< CGameCamera& >(x870_cameraManager->GetCurrentCamera(*this))) == nullptr) { + SetTotalPlayTime__10CGameStateFd( + gpGameState, dt + *reinterpret_cast< const double* >( + reinterpret_cast< const uchar* >(gpGameState) + 0xa0)); + UpdateHintState(dt); + } + + CCameraFilterPass* filt = xb84_camFilterPasses.data(); + CCameraBlurPass* blur = xd14_camBlurPasses.data(); + for (int i = 0; i < kCFS_Max; ++i) { + filt->Update(dt); + Update__15CCameraBlurPassFf(blur, dt); + ++filt; + ++blur; + } + } + + if (x904_gameState != kGS_Paused) { + PreThinkObjects(dt); + x87c_fluidPlaneManager->Update(dt); + } + + if (x904_gameState == kGS_Running) { + if (!isDead) { + Update__13CDecalManagerFfR13CStateManager(dt, this); + } + + UpdateSortedLists(); + + if (!isDead) { + MovePlatforms(dt); + MoveDoors(dt); + } + + ProcessPlayerInput(); + + if (x904_gameState != kGS_SoftPaused) { + CGameCollision::Move(*this, *x84c_player, dt, nullptr); + } + + UpdateSortedLists(); + + if (!isDead) { + CrossTouchActors__13CStateManagerFf(this); + } + } else { + ProcessPlayerInput(); + } + + if (!isDead && x904_gameState == kGS_Running) { + x884_actorModelParticles->Update(dt, *this); + } + + if (x904_gameState == kGS_Running || x904_gameState == kGS_SoftPaused) { + Think(dt); + } + + if (x904_gameState != kGS_SoftPaused) { + x870_cameraManager->Update(dt, *this); + } + + while (xf76_lastRelay != kInvalidUniqueId) { + CEntity* ent = ObjectById(xf76_lastRelay); + if (ent == nullptr) { + xf76_lastRelay = kInvalidUniqueId; + break; + } + + ent->Think(dt, *this); + } + + if (x904_gameState != kGS_Paused) { + PostUpdatePlayer(dt); + } + + if (xf84_ == xf80_hudMessageFrameCount) { + ShowPausedHUDMemo(xf88_, xf8c_); + --xf84_; + xf88_ = kInvalidAssetId; + } + + if (!isDead && x904_gameState == kGS_Running && !x870_cameraManager->IsInCinematicCamera()) { + UpdateEscapeSequenceTimer(dt); + } + + Update__6CWorldFf(x850_world.get(), dt); + x88c_rumbleManager->Update(dt); + + if (!isDead) { + Update__13CEnvFxManagerFfR13CStateManager(dt, x880_envFxManager, this); + } + + UpdateAreaSounds(); + + xf94_24_readyToRender = true; + + if (xf94_27_inMapScreen) { + CHintOptions& hintOptions = gpGameState->HintOptions(); + CHintOptions::SHintState* hint = + const_cast< CHintOptions::SHintState* >(hintOptions.GetCurrentDisplayedHint()); + if (hint != nullptr && hint->CanContinue()) { + DismissDisplayedHint__12CHintOptionsFv(&hintOptions); + } + xf94_27_inMapScreen = false; + } + + SetAreaId__11CWorldStateF7TAreaId(&gpGameState->CurrentWorldState(), x8cc_nextAreaId); + + TravelToArea__6CWorldFRC7TAreaIdR13CStateManagerb(x850_world.get(), x8cc_nextAreaId, this, false); + + ClearGraveyard(); + ++x8d8_updateFrameIdx; +} + +void CStateManager::ProcessInput(const CFinalInput& input) { + static CFinalInput skDefaultInput; + + if (input.ControllerNumber() == 0) { + const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); + bool disableInput = cam.DisablesInput(); + + const uchar playerFlags = + *reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(x84c_player) + 0x9c6); + if ((playerFlags >> 2) & 1) { + disableInput = true; + } + + if (disableInput) { + xb54_finalInput = skDefaultInput; + xb54_finalInput.SetTime(input.Time()); + } else { + xb54_finalInput = input; + } + } + + x870_cameraManager->ProcessInput(input, *this); +} + +void CStateManager::ProcessPlayerInput() { + if (x84c_player != nullptr) { + x84c_player->ProcessInput(xb54_finalInput, *this); + } +} + +void CStateManager::FrameEnd() { + CModel::FrameDone(); + gpSimplePool->Flush(); +} + +void CStateManager::UpdateAreaSounds() { + rstl::reserved_vector< int, 10 > areaIds; + areaIds.clear(); + for (CGameArea::CConstChainIterator areaIt = x850_world->GetChainHead(CWorld::kC_Alive); + areaIt != CWorld::GetAliveAreasEnd(); ++areaIt) { + CGameArea::EOcclusionState occState; + if (areaIt->IsPostConstructed()) { + occState = areaIt->GetPostConstructed()->x10dc_occlusionState; + } else { + occState = CGameArea::kOS_Occluded; + } + + if (occState == CGameArea::kOS_Visible) { + areaIds.push_back(areaIt->GetId().Value()); + } + } + + CSfxManager::SetActiveAreas(areaIds); +} + +void CStateManager::ApplyDamage(const TUniqueId damagerId, const TUniqueId damageeId, + const TUniqueId radiusSender, const CDamageInfo& info, + const CMaterialFilter& filter, const CVector3f& knockbackVec) { + CEntity* damagerEnt = const_cast< CEntity* >(GetObjectById(damagerId)); + CEntity* damageeEnt = ObjectById(damageeId); + CActor* damager = TCastToPtr< CActor >(damagerEnt); + CActor* damagee = TCastToPtr< CActor >(damageeEnt); + CPlayer* player = TCastToPtr< CPlayer >(damageeEnt); + + if (damagee != nullptr) { + CHealthInfo* hInfo = damagee->HealthInfo(*this); + if (hInfo != nullptr) { + CVector3f position = CVector3f::Zero(); + CVector3f direction = CVector3f::Right(); + const bool alive = hInfo->GetHP() > 0.f; + + if (damager != nullptr) { + position = damager->GetTranslation(); + direction = damager->GetTransform().GetForward(); + } + + const bool useWeaponDir = damager != nullptr || player != nullptr; + const CDamageVulnerability* dVuln = + useWeaponDir ? damagee->GetDamageVulnerability(position, direction, info) + : damagee->GetDamageVulnerability(); + + if (info.GetWeaponMode().GetType() == kWT_None || + dVuln->WeaponHurts(info.GetWeaponMode(), 0)) { + const float localDamage = info.GetDamage(*dVuln); + if (localDamage > 0.f) { + ApplyLocalDamage(position, direction, *damagee, localDamage, info.GetWeaponMode()); + } + + damagee->SendScriptMsgs(kSS_Damage, *this, kSM_None); + DeliverScriptMsg(damagee, damagerId, kSM_Damage); + } else { + damagee->SendScriptMsgs(kSS_InvulnDamage, *this, kSM_None); + DeliverScriptMsg(damagee, damagerId, kSM_InvulnDamage); + } + + if (alive && damager != nullptr && info.GetKnockBackPower() > 0.f) { + CVector3f defaultDir = damagee->GetTranslation() - damager->GetTranslation(); + const CVector3f& useDir = knockbackVec.IsNonZero() ? knockbackVec : defaultDir; + CVector3f knockDir(useDir.GetX(), useDir.GetY(), 0.0001f); + ApplyKnockBack(*damagee, info, *dVuln, knockDir.AsNormalized(), 0.f); + } + } + + if (damager != nullptr && info.GetRadius() > 0.f) { + ProcessRadiusDamage(*damager, *damagee, radiusSender, info, filter); + } + + CWallCrawlerSwarm* swarm = TCastToPtr< CWallCrawlerSwarm >(damageeEnt); + if (swarm != nullptr && damager != nullptr) { + const CVector3f damagerPos = damager->GetTranslation(); + ApplyRadiusDamage__17CWallCrawlerSwarmF9CVector3ffR13CStateManager(swarm, &damagerPos, &info, + this); + } + } +} + +bool CStateManager::ApplyLocalDamage(const CVector3f& pos, const CVector3f& dir, CActor& damagee, + float damage, const CWeaponMode& weaponMode) { + CHealthInfo* hInfo = damagee.HealthInfo(*this); + if (hInfo == nullptr || damage < 0.f) { + return false; + } + + const float oldHp = hInfo->GetHP(); + if (oldHp <= 0.f) { + return true; + } + + float useDamage = damage; + CPlayer* player = TCastToPtr< CPlayer >(damagee); + CAi* ai = TCastToPtr< CAi >(damagee); + + if (player != nullptr) { + if (x870_cameraManager->IsInCinematicCamera() || + (weaponMode.GetType() == kWT_Phazon && + x8b8_playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit))) { + return false; + } + + if (gpGameState->GetHardMode()) { + useDamage *= GetHardModeDamageMultiplier__10CGameStateCFv(gpGameState); + } + + float damageReduction = 0.f; + if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_VariaSuit)) { + damageReduction = gpTweakPlayer->GetVariaDamageReduction(); + } + + if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_GravitySuit)) { + const float gravityReduction = gpTweakPlayer->GetGravityDamageReduction(); + damageReduction = CMath::Max< float >(damageReduction, gravityReduction); + } + + if (x8b8_playerState->HasPowerUp(CPlayerState::kIT_PhazonSuit)) { + const float phazonReduction = gpTweakPlayer->GetPhazonDamageReduction(); + damageReduction = CMath::Max< float >(damageReduction, phazonReduction); + } + + useDamage = -(damageReduction * useDamage - useDamage); + } + + const float newHp = oldHp - useDamage; + const bool significant = fabs(newHp - oldHp) >= 0.00001f; + hInfo->SetHP(newHp); + + if (player != nullptr) { + player->TakeDamage(significant, pos, useDamage, weaponMode.GetType(), *this); + if (newHp <= 0.f) { + struct SPlayerStateFlags { + bool x0_24_alive : 1; + }; + reinterpret_cast< SPlayerStateFlags* >(x8b8_playerState.GetPtr())->x0_24_alive = false; + } + } else if (ai != nullptr) { + if (significant) { + ai->TakeDamage(dir, useDamage); + } + + if (newHp <= 0.f) { + ai->Death(*this, dir, kSS_DeathRattle); + } + } + + return significant; +} + +void CStateManager::TestBombHittingWater(const CActor& damager, const CVector3f& pos, + CActor& damagee) { + CWeapon* weapon = TCastToPtr< CWeapon >(const_cast< CActor& >(damager)); + if (weapon == nullptr) { + return; + } + + const int attribField = weapon->GetAttribField(); + if ((attribField & (CWeapon::kPA_Bombs | CWeapon::kPA_PowerBombs)) == 0) { + return; + } + + const bool powerBomb = (attribField & CWeapon::kPA_PowerBombs) != 0; + CScriptWater* water = TCastToPtr< CScriptWater >(damagee); + if (water == nullptr) { + return; + } + + CAABox triggerBounds = water->GetTriggerBoundsWR(); + CVector3f hitPos(pos.GetX(), pos.GetY(), triggerBounds.GetMaxPoint().GetZ()); + + CVector3f up(0.f, 0.f, 1.f); + up.Normalize(); + + CAABox triggerBounds2 = water->GetTriggerBoundsWR(); + const int idx = powerBomb; + const float depth = -(CVector3f::Dot(up, pos) - triggerBounds2.GetMaxPoint().GetZ()); + + if (depth <= skBombUnderwaterRanges[idx] && depth > 0.f) { + const float rippleFactor = 1.f - depth / skBombUnderwaterRanges[idx]; + if (x87c_fluidPlaneManager->GetLastRippleDeltaTime(damager.GetUniqueId()) >= 0.15f) { + const float bombMag = skBombUnderwaterMags[idx]; + const float sinVal = CMath::FastSinR(2.f * M_PIF * rippleFactor * 0.25f); + water->FluidPlane().AddRipple(0.6f * bombMag + 0.4f * bombMag * sinVal, damager.GetUniqueId(), + hitPos, *water, *this); + } + + if (!powerBomb) { + x87c_fluidPlaneManager->CreateSplash(damager.GetUniqueId(), *this, *water, hitPos, + rippleFactor, true); + } + } else if (depth > -skBombAboveWaterRanges[idx] && depth < 0.f) { + const float depthAbove = -depth; + CVector3f down(0.f, 0.f, -1.f); + const CRayCastResult result = + RayStaticIntersection(pos, down, depthAbove, CMaterialFilter::GetPassEverything()); + + if (!result.GetValid() && + x87c_fluidPlaneManager->GetLastRippleDeltaTime(damager.GetUniqueId()) >= 0.15f) { + const float bombMag = skBombAboveWaterMags[idx]; + const float sinVal = + CMath::FastSinR(2.f * M_PIF * (depthAbove / skBombAboveWaterRanges[idx]) * 0.25f); + water->FluidPlane().AddRipple(0.6f * bombMag + 0.4f * bombMag * sinVal, damager.GetUniqueId(), + hitPos, *water, *this); + } + } +} + +bool CStateManager::MultiRayCollideWorld(const CMRay& ray, const CMaterialFilter& filter) { + const CVector3f& start = + *reinterpret_cast< const CVector3f* >(reinterpret_cast< const uchar* >(&ray) + 0x0); + const CVector3f& dir = + *reinterpret_cast< const CVector3f* >(reinterpret_cast< const uchar* >(&ray) + 0x2c); + const float length = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&ray) + 0x24); + + CVector3f crossed(-dir.GetZ() * dir.GetZ() - dir.GetY() * dir.GetX(), + dir.GetX() * dir.GetX() - dir.GetZ() * dir.GetY(), + dir.GetY() * dir.GetY() - dir.GetX() * -dir.GetZ()); + CVector3f crossedNorm = crossed.AsNormalized(); + + const CVector3f crossed2( + (dir.GetY() * crossedNorm.GetZ() - crossedNorm.GetY() * dir.GetZ()) * 0.35355338f, + (dir.GetZ() * crossedNorm.GetX() - crossedNorm.GetZ() * dir.GetX()) * 0.35355338f, + (dir.GetX() * crossedNorm.GetY() - crossedNorm.GetX() * dir.GetY()) * 0.35355338f); + const CVector3f rms = crossedNorm * 0.35355338f; + + for (uint i = 0; i < 4; ++i) { + const CVector3f useCrossed = (i & 2) != 0 ? -crossed2 : crossed2; + const CVector3f useRms = (i & 1) != 0 ? rms : -rms; + const CVector3f useStart = start + useRms + useCrossed; + if (CGameCollision::RayStaticIntersectionBool(*this, useStart, dir, length, filter)) { + return true; + } + } + + return false; +} + +void CStateManager::ApplyRadiusDamage(const CActor& damager, const CVector3f& pos, CActor& damagee, + const CDamageInfo& info) { + CVector3f delta = damagee.GetTranslation() - pos; + if (info.GetRadius() * info.GetRadius() <= delta.MagSquared()) { + if (!damagee.GetTouchBounds()) { + return; + } + + if (!CCollidableSphere::Sphere_AABox_Bool(CSphere(pos, info.GetRadius()), + *damagee.GetTouchBounds())) { + return; + } + } + + float rad = info.GetRadius(); + if (rad > gkEpsilon) { + rad = delta.Magnitude() / rad; + } else { + rad = 0.f; + } + + if (rad > 0.f) { + delta.Normalize(); + } + + bool alive = false; + CHealthInfo* hInfo = damagee.HealthInfo(*this); + if (hInfo != nullptr && hInfo->GetHP() > 0.f) { + alive = true; + } + + const CDamageVulnerability* vuln = rad > 0.f ? damagee.GetDamageVulnerability(pos, delta, info) + : damagee.GetDamageVulnerability(); + + if (vuln->WeaponHurts(info.GetWeaponMode(), 1)) { + const float localDamage = info.GetRadiusDamage(*vuln); + if (localDamage > 0.f) { + ApplyLocalDamage(pos, delta, damagee, localDamage, info.GetWeaponMode()); + } + + damagee.SendScriptMsgs(kSS_Damage, *this, kSM_None); + DeliverScriptMsg(&damagee, damager.GetUniqueId(), kSM_Damage); + } else { + damagee.SendScriptMsgs(kSS_InvulnDamage, *this, kSM_None); + DeliverScriptMsg(&damagee, damager.GetUniqueId(), kSM_InvulnDamage); + } + + if (alive && info.GetKnockBackPower() > 0.f) { + CVector3f knockbackDir(damagee.GetTranslation().GetX() - damager.GetTranslation().GetX(), + damagee.GetTranslation().GetY() - damager.GetTranslation().GetY(), + 0.0001f); + ApplyKnockBack(damagee, info, *vuln, knockbackDir.AsNormalized(), rad); + } +} + +void CStateManager::ProcessRadiusDamage(const CActor& damager, CActor& damagee, + TUniqueId radiusSender, const CDamageInfo& info, + const CMaterialFilter& filter) { + const float radius = info.GetRadius(); + const CVector3f pos = damager.GetTranslation(); + const CVector3f maxPos(pos.GetX() + radius, pos.GetY() + radius, pos.GetZ() + radius); + const CVector3f minPos(pos.GetX() - radius, pos.GetY() - radius, pos.GetZ() - radius); + const CAABox aabb(minPos, maxPos); + CMaterialFilter localFilter = filter; + + TEntityList nearList; + BuildNearList(nearList, aabb, localFilter, nullptr); + + const TUniqueId damagerId = damager.GetUniqueId(); + const TUniqueId damageeId = damagee.GetUniqueId(); + + for (TEntityList::iterator it = nearList.begin(); it != nearList.end(); ++it) { + CActor* actor = static_cast< CActor* >(ObjectById(*it)); + if (actor != nullptr) { + const TUniqueId actorId = actor->GetUniqueId(); + if (damagerId != actorId && radiusSender != actorId && damageeId != actorId) { + TestBombHittingWater(damager, pos, *actor); + if (TestRayDamage(*this, pos, *actor, nearList)) { + ApplyRadiusDamage(damager, pos, *actor, info); + } + } + } + } +} + +void CStateManager::ApplyDamageToWorld(TUniqueId damagerId, const CActor& actor, + const CVector3f& pos, const CDamageInfo& info, + const CMaterialFilter& filter) { + const CVector3f extent(info.GetRadius(), info.GetRadius(), info.GetRadius()); + const CAABox aabb(pos - extent, pos + extent); + + bool bomb = false; + const CWeapon* weapon = TCastToConstPtr< CWeapon >(actor); + if (weapon != nullptr) { + bomb = (weapon->GetAttribField() & (CWeapon::kPA_Bombs | CWeapon::kPA_PowerBombs)) != 0; + } + + TEntityList nearList; + BuildNearList(nearList, aabb, filter, &actor); + + for (TEntityList::iterator it = nearList.begin(); it != nearList.end(); ++it) { + CEntity* ent = ObjectById(*it); + CActor* act = TCastToPtr< CActor >(ent); + CPlayer* player = TCastToPtr< CPlayer >(ent); + CWallCrawlerSwarm* wallSwarm = TCastToPtr< CWallCrawlerSwarm >(ent); + CSnakeWeedSwarm* snakeSwarm = TCastToPtr< CSnakeWeedSwarm >(ent); + + if (bomb && player != nullptr) { + if (player->GetFrozenState()) { + IncrementFrozenBallCount__12CSystemStateFv(&gpGameState->SystemState()); + CSamusHud::DisplayHudMemo(rstl::wstring_l(L""), CHUDMemoParms(0.f, true, true, true)); + player->BreakFrozenState(*this); + } else if (weapon != nullptr && (weapon->GetAttribField() & CWeapon::kPA_Bombs) != 0) { + BombJump__7CPlayerFRC9CVector3fR13CStateManager(player, &pos, this); + } + } else if (act != nullptr && act->GetUniqueId() != damagerId) { + TestBombHittingWater(actor, pos, *act); + if (TestRayDamage(*this, pos, *act, nearList)) { + ApplyRadiusDamage(actor, pos, *act, info); + } + } + + if (wallSwarm != nullptr) { + ApplyRadiusDamage__17CWallCrawlerSwarmF9CVector3ffR13CStateManager(wallSwarm, &pos, &info, + this); + } + + if (snakeSwarm != nullptr) { + ApplyRadiusDamage__15CSnakeWeedSwarmF9CVector3ffR13CStateManager(snakeSwarm, &pos, &info, + this); + } + } +} + +void CStateManager::ApplyKnockBack(CActor& actor, const CDamageInfo& info, + const CDamageVulnerability& vuln, const CVector3f& dir, + float dampen) { + if (vuln.GetVulnerability(info.GetWeaponMode(), 0) == kVN_Deflect) { + return; + } + + CHealthInfo* hInfo = actor.HealthInfo(*this); + if (hInfo == nullptr) { + return; + } + + const float resistance = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(hInfo) + 0x4); + const float dampedPower = (1.f - dampen) * info.GetKnockBackPower(); + + CPlayer* player = TCastToPtr< CPlayer >(actor); + CPatterned* patterned = TCastToPtr< CPatterned >(actor); + + if (player != nullptr) { + KnockBackPlayer(*player, dir, dampedPower, resistance); + return; + } + + if (patterned == nullptr && hInfo->GetHP() <= 0.f) { + if (dampedPower > resistance) { + CPhysicsActor* physActor = TCastToPtr< CPhysicsActor >(actor); + if (physActor != nullptr) { + const CVector3f impulse = + dir * (1.5f * ((dampedPower - resistance) * physActor->GetMass())); + if (!physActor->GetMaterialList().HasMaterial(kMT_Immovable) && + physActor->GetMaterialList().HasMaterial(kMT_Solid)) { + physActor->ApplyImpulseWR(impulse, CAxisAngle::Identity()); + } + } + } + } + + if (patterned != nullptr) { + patterned->KnockBack(dir, *this, info, dampen == 0.f ? kKBT_Direct : kKBT_Radius, false, + dampedPower); + } +} + +void CStateManager::KnockBackPlayer(CPlayer& player, const CVector3f& dir, float power, + float resistance) { + if (player.GetMaterialList().HasMaterial(kMT_Immovable)) { + return; + } + + float usePower; + if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) { + usePower = power * 500.f; + } else { + usePower = power * 1000.f; + if (player.GetSurfaceRestraint() != CPlayer::kSR_Normal && + player.GetOrbitState() == CPlayer::kOS_NoOrbit) { + usePower /= 7.f; + } + } + + float minVel = 70.f; + if (player.GetMorphballTransitionState() == CPlayer::kMS_Morphed) { + minVel = 35.f; + } + + const float playerVel = player.GetVelocityWR().Magnitude(); + const float maxVel = minVel < playerVel ? playerVel : minVel; + const CVector3f invVel = -player.GetVelocityWR(); + + usePower *= (1.f - (0.5f * CVector3f::GetAngleDiff(dir, invVel)) / M_PIF); + + player.ApplyImpulseWR(dir * usePower, CAxisAngle::Identity()); + player.UseCollisionImpulses(); + *reinterpret_cast< float* >(reinterpret_cast< uchar* >(&player) + 0x2d4) = 0.25f; + + const CVector3f velocity = player.GetVelocityWR(); + const float velocityMag = velocity.Magnitude(); + if (maxVel < velocityMag) { + const float invMag = 1.f / velocityMag; + const CVector3f norm(invMag * velocity.GetX(), invMag * velocity.GetY(), + invMag * velocity.GetZ()); + player.SetVelocityWR( + CVector3f(maxVel * norm.GetX(), maxVel * norm.GetY(), maxVel * norm.GetZ())); + } +} + +void CStateManager::InformListeners(const CVector3f& pos, EListenNoiseType type) { + CObjectList* list = x808_objectLists[kOL_ListeningAi].get(); + for (int i = list->GetFirstObjectIndex(); i != -1; i = list->GetNextObjectIndex(i)) { + CPatterned* patterned = TCastToPtr< CPatterned >((*list)[i]); + if (patterned != nullptr) { + if (patterned->GetActive()) { + const TAreaId areaId2 = patterned->x4_areaId; + const TAreaId areaId = areaId2; + CGameArea* area = x850_world->Area(areaId); + CGameArea::EOcclusionState occState; + if (area->IsPostConstructed()) { + occState = area->GetPostConstructed()->x10dc_occlusionState; + } else { + occState = CGameArea::kOS_Occluded; + } + + if (occState != CGameArea::kOS_Occluded) { + patterned->Listen(pos, type); + } + } + } + } +} + +rstl::pair< TEditorId, TUniqueId > CStateManager::LoadScriptObject(TAreaId aid, + EScriptObjectType type, + unsigned int length, + CInputStream& in) { + bool failed = false; + const TEditorId eid = in.ReadLong(); + + rstl::vector< SConnection > conns; + const uint connCount = in.ReadLong(); + conns.reserve(connCount); + + uint bytesLeft = length - 8; + for (uint i = 0; i < connCount; ++i) { + const EScriptObjectState state = static_cast< EScriptObjectState >(in.ReadLong()); + const EScriptObjectMessage msg = static_cast< EScriptObjectMessage >(in.ReadLong()); + const TEditorId target = in.ReadLong(); + bytesLeft -= 12; + conns.push_back(SConnection(state, msg, target)); + } + + const uint propCount = in.ReadLong(); + bytesLeft -= 4; + const uint readPos = in.GetReadPosition(); + + CEntity* ent = NULL; + FScriptLoader loader = NULL; + if (type <= kST_EnergyBall && type >= kST_Actor) { + loader = x90c_loaderFuncs[type]; + } + + if (loader == NULL) { + failed = true; + } else { + CEntityInfo info(aid, conns, eid); + ent = loader(*this, in, propCount, info); + } + + if (ent == NULL) { + failed = true; + } else { + AddObject(*ent); + } + + uint leftOver = bytesLeft - (in.GetReadPosition() - readPos); + while (leftOver != 0) { + in.ReadChar(); + --leftOver; + } + + if (failed || ent == NULL) { + return rstl::pair< TEditorId, TUniqueId >(kInvalidEditorId, kInvalidUniqueId); + } + return rstl::pair< TEditorId, TUniqueId >(eid, ent->GetUniqueId()); +} + +rstl::pair< TEditorId, TUniqueId > CStateManager::GenerateObject(const TEditorId& eid) { + const rstl::pair< const SScriptObjectStream*, TEditorId > build = GetBuildForScript(eid); + TAreaId aid = TAreaId(build.second.AreaNum()); + if (build.first != nullptr) { + CGameArea* area = x850_world->Area(aid); + if (area->IsPostConstructed()) { + int layer = static_cast< int >(build.second.value >> 26); + SScriptLayerBuffer layerBuf; + GetLayerScriptBuffer__9CGameAreaFi(&layerBuf, area, &layer); + + CMemoryInStream stream(static_cast< const uchar* >(layerBuf.x0_buf) + + build.first->x4_position, + build.first->x8_length); + return LoadScriptObject(aid, build.first->x0_type, build.first->x8_length, stream); + } + } + + return rstl::pair< TEditorId, TUniqueId >(kInvalidEditorId, kInvalidUniqueId); +} + +void CStateManager::LoadScriptObjects(TAreaId aid, CInputStream& in, EScriptPersistence persist) { + in.ReadChar(); + + int count = in.ReadLong(); + persist.reserve(count + persist.size()); + while (count != 0) { + const char type = in.ReadChar(); + const uint length = in.ReadLong(); + const uint readPos = in.GetReadPosition(); + + const rstl::pair< TEditorId, TUniqueId > loaded = + LoadScriptObject(aid, static_cast< EScriptObjectType >(type), length, in); + const TEditorId eid = loaded.first; + if (eid != kInvalidEditorId) { + const rstl::pair< const SScriptObjectStream*, TEditorId > build = GetBuildForScript(eid); + if (build.first == NULL) { + SScriptObjectStream stream; + stream.x0_type = static_cast< EScriptObjectType >(type); + stream.x4_position = readPos; + stream.x8_length = length; + x8a4_loadedScriptObjects.insert(rstl::pair< TEditorId, SScriptObjectStream >(eid, stream)); + persist.push_back(eid); + } + } + + --count; + } +} + +void CStateManager::InitScriptObjects(const rstl::vector< TEditorId >& ids) { + for (int i = 0; i < static_cast< int >(ids.size()); ++i) { + if (ids[i] != kInvalidEditorId) { + TEditorId id = ids[i]; + TUniqueId uid = GetIdForScript(id); + SendScriptMsgAlways(uid, kInvalidUniqueId, kSM_InitializedInArea); + } + } + + MurderScriptInstanceNames(); +} + +CStateManager::TIdListResult CStateManager::GetIdListForScript(TEditorId eid) const { + rstl::multimap< TEditorId, TUniqueId >::const_iterator firstIt = x890_scriptIdMap.find(eid); + rstl::multimap< TEditorId, TUniqueId >::const_iterator lastIt = firstIt; + + if (firstIt != x890_scriptIdMap.end()) { + for (; lastIt != x890_scriptIdMap.end() && lastIt->first == eid; ++lastIt) { + } + } + + const TIdList::const_iterator first = + *reinterpret_cast< const TIdList::const_iterator* >(&firstIt); + const TIdList::const_iterator last = *reinterpret_cast< const TIdList::const_iterator* >(&lastIt); + return TIdListResult(first, last); +} + +TUniqueId CStateManager::GetIdForScript(TEditorId eid) const { + rstl::multimap< TEditorId, TUniqueId >::const_iterator it = x890_scriptIdMap.find(eid); + if (it != x890_scriptIdMap.end()) { + return it->second; + } + return kInvalidUniqueId; +} + +TEditorId CStateManager::GetEditorIdForUniqueId(TUniqueId uid) const { + const CEntity* ent = GetObjectById(uid); + if (ent != nullptr) { + return ent->GetEditorId(); + } + return kInvalidEditorId; +} + +rstl::pair< const SScriptObjectStream*, TEditorId > +CStateManager::GetBuildForScript(TEditorId eid) const { + rstl::map< TEditorId, SScriptObjectStream >::const_iterator it = + x8a4_loadedScriptObjects.find(eid); + if (it != x8a4_loadedScriptObjects.end()) { + return rstl::pair< const SScriptObjectStream*, TEditorId >(&it->second, it->first); + } + + return rstl::pair< const SScriptObjectStream*, TEditorId >(0, kInvalidEditorId); +} + +void CStateManager::FreeScriptObjects(TAreaId aid) { + rstl::multimap< TEditorId, TUniqueId >::iterator scriptIt = x890_scriptIdMap.get_inner().begin(); + while (scriptIt != x890_scriptIdMap.get_inner().end()) { + rstl::multimap< TEditorId, TUniqueId >::iterator cur = scriptIt; + ++scriptIt; + + if (cur->first.AreaNum() == aid.Value()) { + DeleteObjectRequest(cur->second); + } + } + + typedef rstl::red_black_tree< TEditorId, rstl::pair< TEditorId, SScriptObjectStream >, 0, + rstl::select1st< rstl::pair< TEditorId, SScriptObjectStream > >, + rstl::less< TEditorId >, rstl::rmemory_allocator > + TLoadedScriptObjMapInner; + + TLoadedScriptObjMapInner& loadedScriptObjects = + *reinterpret_cast< TLoadedScriptObjMapInner* >(&x8a4_loadedScriptObjects); + + TLoadedScriptObjMapInner::iterator loadedIt = loadedScriptObjects.begin(); + while (loadedIt != loadedScriptObjects.end()) { + TLoadedScriptObjMapInner::iterator cur = loadedIt; + ++loadedIt; + + if (cur->first.AreaNum() == aid.Value()) { + loadedScriptObjects.erase(cur); + } + } + + CGameArea* area = x850_world->Area(aid); + if (area->IsPostConstructed()) { + CObjectList* areaObjList = + static_cast< CObjectList* >(area->GetPostConstructed()->x10c0_areaObjectList); + + for (int i = areaObjList->GetFirstObjectIndex(); i != -1; + i = areaObjList->GetNextObjectIndex(i)) { + CEntity* ent = (*areaObjList)[i]; + if (ent != nullptr && !ent->x30_27_notInArea) { + DeleteObjectRequest(ent->GetUniqueId()); + } + } + } +} + +void CStateManager::SendScriptMsg(TUniqueId uid, TEditorId target, EScriptObjectMessage msg, + EScriptObjectState) { + GetObjectById(uid); + + TIdListResult search = GetIdListForScript(target); + if (search.first == search.second) { + return; + } + + TIdList::const_iterator it = search.first; + for (; it != search.second; ++it) { + DeliverScriptMsg(x808_objectLists[0]->GetObjectById(it->second), uid, msg); + } +} + +void CStateManager::RecursiveDrawTree(TUniqueId uid) const { + CActor* actor = TCastToPtr< CActor >(const_cast< CEntity* >(GetObjectById(uid))); + if (actor != NULL && + x8dc_objectDrawToken != *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xc8)) { + const TUniqueId nextNode = + *reinterpret_cast< TUniqueId* >(reinterpret_cast< uchar* >(actor) + 0xc6); + if (nextNode != kInvalidUniqueId) { + RecursiveDrawTree(nextNode); + } + if (x8dc_objectDrawToken == + *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xcc)) { + actor->Render(*this); + } + *reinterpret_cast< int* >(reinterpret_cast< uchar* >(actor) + 0xc8) = x8dc_objectDrawToken; + } +} + +void CStateManager::RendererDrawCallback(const void*, const void*, int) {} + +bool CStateManager::GetVisSetForArea(TAreaId areaA, TAreaId areaB, CPVSVisSet& setOut) const { + if (areaB == kInvalidAreaId) { + return false; + } + + const CTransform4f& viewXf = CGraphics::GetViewMatrix(); + const CVector3f viewPoint(viewXf.Get03(), viewXf.Get13(), viewXf.Get23()); + CVector3f closestDockPoint = viewPoint; + + bool hasClosestDock = false; + if (areaA == areaB) { + hasClosestDock = true; + } else { + const CGameArea* area = x850_world->GetArea(areaB); + if (area->IsPostConstructed()) { + for (int i = 0; i < area->GetDockCount(); ++i) { + const IGameArea::Dock& dock = area->GetDock(i); + const int connCount = dock.GetDockRefs().size(); + for (int conn = 0; conn < connCount; ++conn) { + if (dock.GetConnectedAreaId(conn) != areaA) { + continue; + } + + const rstl::reserved_vector< CVector3f, 4 >& verts = dock.GetPlaneVertices(); + const CVector3f dockCenter( + 0.25f * (verts[0].GetX() + verts[1].GetX() + verts[2].GetX() + verts[3].GetX()), + 0.25f * (verts[0].GetY() + verts[1].GetY() + verts[2].GetY() + verts[3].GetY()), + 0.25f * (verts[0].GetZ() + verts[1].GetZ() + verts[2].GetZ() + verts[3].GetZ())); + + if (hasClosestDock) { + const CVector3f oldDelta = closestDockPoint - viewPoint; + const CVector3f newDelta = dockCenter - viewPoint; + if (newDelta.MagSquared() >= oldDelta.MagSquared()) { + continue; + } + } + + closestDockPoint = dockCenter; + hasClosestDock = true; + } + } + } + } + + int setState = 0; + if (hasClosestDock) { + setState = 1; + + const CGameArea* area = x850_world->GetArea(areaA); + const CPVSAreaSet* areaSet = area->GetPostConstructed()->xa0_pvs; + if (areaSet != nullptr) { + setState = 2; + + const uint worldAreaArg = *reinterpret_cast< const uint* >( + reinterpret_cast< const uchar* >(x850_world.get()) + 0x20); + CPVSVisOctree& visOctree = + *const_cast< CPVSVisOctree* >(&areaSet->GetVisOctree(worldAreaArg)); + + const CTransform4f& invAreaXf = + *reinterpret_cast< const CTransform4f* >(reinterpret_cast< const uchar* >(area) + 0x3c); + const CVector3f localPoint = invAreaXf * closestDockPoint; + + CPVSVisSet visSet = visOctree.GetVisSet(localPoint); + if (*reinterpret_cast< const int* >(reinterpret_cast< const uchar* >(&visSet)) == + kVSS_NodeFound) { + setOut = visSet; + setState = 3; + } + } + } + + return setState == 3; +} + +extern "C" CGameArea::CChainIterator AliveAreasEnd__6CWorldFv() { + return CGameArea::CChainIterator(lbl_805A8DDC); +} + +void CStateManager::PreRender() { + CStateManager* mgr = this; + if (!mgr->xf94_24_readyToRender) { + return; + } + + CStopwatch timer; + + mgr->x86c_stateManagerContainer->xf370_.clear(); + mgr->x86c_stateManagerContainer->xf39c_renderLast.clear(); + mgr->xf7c_projectedShadow = nullptr; + + PreRender__6CWorldFv(mgr->x850_world.get()); + mgr->BuildDynamicLightListForWorld(); + + const CGameCamera& curCam = mgr->x870_cameraManager->GetCurrentCamera(*mgr); + const CTransform4f curCamXf = mgr->x870_cameraManager->GetCurrentCameraTransform(*mgr); + CFrustumPlanes frustum(curCamXf, 0.017453292f * curCam.GetFov(), curCam.GetAspectRatio(), + curCam.GetNearClipDistance(), false, 100.f); + + for (CGameArea::CChainIterator areaIt = mgr->x850_world->ChainHead(CWorld::kC_Alive); + areaIt != AliveAreasEnd__6CWorldFv(); ++areaIt) { + CGameArea::EOcclusionState occState; + if (areaIt->IsPostConstructed()) { + occState = areaIt->GetPostConstructed()->x10dc_occlusionState; + } else { + occState = CGameArea::kOS_Occluded; + } + + if (occState == CGameArea::kOS_Visible) { + CObjectList* areaObjList = + static_cast< CObjectList* >(areaIt->GetPostConstructed()->x10c0_areaObjectList); + for (int i = areaObjList->GetFirstObjectIndex(); i != -1; + i = areaObjList->GetNextObjectIndex(i)) { + CActor* actor = TCastToPtr< CActor >((*areaObjList)[i]); + if (actor != nullptr && + ((*reinterpret_cast< const uchar* >(reinterpret_cast< const uchar* >(actor) + 0xe7) >> + 2) & + 1) != 0) { + actor->CalculateRenderBounds(); + actor->PreRender(*mgr, frustum); + } + } + } + } + + if (!gkWorldOnlyReflection) { + mgr->CacheReflection(); + } + + gpRender->PrepareDynamicLights(mgr->x8e0_dynamicLights); + lbl_805A8D98 = timer.GetElapsedMicros(); +} + +CFrustumPlanes CStateManager::SetupViewForDraw(const CViewport& viewport) const { + const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); + const CTransform4f camXf = x870_cameraManager->GetCurrentCameraTransform(*this); + gpRender->SetWorldViewpoint(camXf); + + const CVector3f playerPos = x84c_player->GetTranslation(); + SetNewPlayerPositionAndTime__10CCubeModelFRC9CVector3fRC10CStopwatch( + playerPos, CStopwatch::GetGlobalTimerObj()); + + const float scaledWidth = xf2c_viewportScaleX * static_cast< float >(viewport.mWidth); + const float scaledHeight = xf30_viewportScaleY * static_cast< float >(viewport.mHeight); + const int width = static_cast< int >(scaledWidth); + const int halfHeight = static_cast< int >(scaledHeight) / 2; + + const int left = viewport.mLeft + (viewport.mWidth - width) / 2; + const int top = viewport.mTop + (viewport.mHeight - halfHeight * 2) / 2; + + const float fov = + 2.f * CMath::ArcTangentR( + CMath::SlowTangentR(0.5f * ((1.f / 360.f) * (2.f * M_PIF) * cam.GetFov())) * + xf30_viewportScaleY); + + gpRender->SetViewport(left, top, width, halfHeight * 2); + CGraphics::SetDepthRange(0.125f, 1.f); + + const float zFar = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&cam) + 0x164); + gpRender->SetPerspective(360.f * ((1.f / (2.f * M_PIF)) * fov), scaledWidth, scaledHeight, + cam.GetNearClipDistance(), zFar); + + CFrustumPlanes frustum(camXf, fov, + (xf2c_viewportScaleX * cam.GetAspectRatio()) / xf30_viewportScaleY, + cam.GetNearClipDistance(), false, 100.f); + gpRender->SetClippingPlanes(frustum); + gpRender->PrimColor(CColor::White()); + gpRender->SetModelMatrix(CTransform4f::Identity()); + + x87c_fluidPlaneManager->StartFrame(false); + gpRender->SetDebugOption(IRenderer::kDO_PVSState, 1); + + return frustum; +} + +bool CStateManager::SetupFogForDraw() const { + switch (x8b8_playerState->GetActiveVisor(*this)) { + case CPlayerState::kPV_Thermal: + gpRender->SetWorldFog(kRFM_None, 0.f, 1.f, CColor::Black()); + return true; + case CPlayerState::kPV_XRay: + default: + return false; + case CPlayerState::kPV_Combat: + case CPlayerState::kPV_Scan: { + const CGameArea::CAreaFog* fog = reinterpret_cast< const CGameArea::CAreaFog* >( + reinterpret_cast< const uchar* >(x870_cameraManager) + 0x3c); + if (fog->IsFogDisabled()) { + return false; + } + fog->SetCurrent(); + return true; + } + } +} + +void CStateManager::SetupFogForArea(const CGameArea& area) const { + if (SetupFogForDraw()) { + return; + } + + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_XRay) { + const float fogDist = GetXRayFogDistance__9CGameAreaFv(const_cast< CGameArea* >(&area)); + const CTweakGui* tweak = gpTweakGui; + const float fogFarZ = tweak->GetXRayFogFarZ(); + const float nearZ = tweak->GetXRayFogNearZ(); + const float farZ = nearZ * (1.f - fogDist) + fogFarZ * fogDist; + gpRender->SetWorldFog(static_cast< ERglFogMode >(tweak->GetXRayFogMode()), nearZ, farZ, + tweak->GetXRayFogColor()); + } else { + area.GetPostConstructed()->x10c4_areaFog->SetCurrent(); + } +} + +void CStateManager::SetupFogForArea(TAreaId area) const { + TAreaId areaValue; + const TAreaId* areaId = &area; + int nextArea; + if (area == kInvalidAreaId) { + nextArea = x8cc_nextAreaId.Value(); + areaId = reinterpret_cast< const TAreaId* >(&nextArea); + } + + areaValue = *areaId; + const CGameArea* areaObj = x850_world->GetArea(areaValue); + if (areaObj->IsPostConstructed()) { + SetupFogForArea(*areaObj); + } +} + +void CStateManager::SetupFogForArea3XRange(TAreaId area) const { + TAreaId areaValue; + const TAreaId* areaId = &area; + int nextArea; + if (area == kInvalidAreaId) { + nextArea = x8cc_nextAreaId.Value(); + areaId = reinterpret_cast< const TAreaId* >(&nextArea); + } + + areaValue = *areaId; + const CGameArea* areaObj = x850_world->GetArea(areaValue); + if (areaObj->IsPostConstructed()) { + fn_80046DE8(this, areaObj); + } +} + +void CStateManager::DrawWorld() const { + + const CTimeProvider timeProvider(xf14_curTimeMod900); + const CViewport backupViewport = CGraphics::GetViewport(); + + /* Area camera is in (not necessarily player) */ + const TAreaId visAreaId = GetVisAreaId(); + + x850_world->TouchSky(); + + const CFrustumPlanes frustum = SetupViewForDraw(CGraphics::GetViewport()); + const CTransform4f backupViewMatrix = CGraphics::GetViewMatrix(); + + int areaCount = 0; + const CGameArea* areaArr[10]; + + CGameArea::CConstChainIterator it = x850_world->GetChainHead(CWorld::kC_Alive); + CGameArea::CConstChainIterator end = x850_world->GetAliveAreasEnd(); + for (; it != end; ++it) { + if (areaCount == 10) { + break; + } + CGameArea::EOcclusionState occState = CGameArea::kOS_Occluded; + if (it->IsLoaded()) { + occState = it->GetOcclusionState(); + } + if (occState == CGameArea::kOS_Visible) { + areaArr[areaCount++] = &*it; + } + } + + // rstl::sort(&areaArr[0], &areaArr[areaCount], area_sorter(CGraphics::GetViewPoint(), + // visAreaId)); +} + +void CStateManager::ResetViewAfterDraw(const CViewport& backupViewport, + const CTransform4f& backupViewMatrix) const { + gpRender->SetViewport(backupViewport.mLeft, backupViewport.mTop, backupViewport.mWidth, + backupViewport.mHeight); + + const CGameCamera& cam = x870_cameraManager->GetCurrentCamera(*this); + CFrustumPlanes frustum(backupViewMatrix, 0.017453292f * cam.GetFov(), cam.GetAspectRatio(), + cam.GetNearClipDistance(), false, 100.f); + gpRender->SetClippingPlanes(frustum); + + const CViewport& viewport = CGraphics::GetViewport(); + const float zFar = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&cam) + 0x164); + gpRender->SetPerspective(cam.GetFov(), static_cast< float >(viewport.mWidth), + static_cast< float >(viewport.mHeight), cam.GetNearClipDistance(), zFar); +} + +void CStateManager::DrawAdditionalFilters() const { + if (xf0c_escapeTimer < 1.f && xf0c_escapeTimer > 0.f && + !x870_cameraManager->IsInCinematicCamera()) { + const float alpha = 1.f - xf0c_escapeTimer; + const CColor color = CColor::White().WithAlphaOf(alpha); + CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Add, CCameraFilterPass::kFS_Fullscreen, + color, 0, 1.f); + } +} + +void CStateManager::DrawE3DeathEffect() const { + const CPlayer* player = x84c_player; + const float deathTime = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(player) + 0x9f4); + float blurFactor; + float whiteFactor; + + if (deathTime > 0.f) { + if (player->GetMorphballTransitionState() != CPlayer::kMS_Unmorphed) { + blurFactor = (deathTime - 1.f) / (gkBallDeathTime - 1.f); + const float blurAmt = CMath::Clamp(0.f, blurFactor, 1.f); + if (blurAmt > 0.f) { + CCameraBlurPass blur; + blur.SetBlur(CCameraBlurPass::kBT_HiBlur, 7.f * blurAmt, 0.f, false); + blur.Draw(); + } + } + + whiteFactor = 1.f - deathTime / (lbl_805AA2D4 * gkBallDeathTime); + const float whiteAmt = CMath::Clamp(0.f, whiteFactor, 1.f); + const CColor color = CColor::White().WithAlphaOf(whiteAmt); + CCameraFilterPass::DrawFilter(CCameraFilterPass::kFT_Add, CCameraFilterPass::kFS_Fullscreen, + color, 0, 1.f); + } +} + +void CStateManager::RenderCamerasAndAreaLights() const { + x870_cameraManager->Render(*this); + for (int i = 0; i < kCFS_Max; ++i) { + xb84_camFilterPasses[i].Draw(); + } +} + +void CStateManager::DrawDebugStuff() const {} + +void CStateManager::BuildDynamicLightListForWorld() { + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Thermal) { + x8e0_dynamicLights = rstl::vector< CLight >(); + return; + } + + const CObjectList& list = GetObjectListById(kOL_GameLight); + int listSize = list.size(); + if (listSize == 0) { + return; + } + + if (x8e0_dynamicLights.capacity() != listSize) { + x8e0_dynamicLights = rstl::vector< CLight >(); + x8e0_dynamicLights.reserve(listSize); + } else { + x8e0_dynamicLights.clear(); + } + + for (int idx = list.GetFirstObjectIndex(); idx != -1; idx = list.GetNextObjectIndex(idx)) { + const CGameLight* light = static_cast< const CGameLight* >(list[idx]); + if (light && light->GetActive()) { + const CLight& l = light->GetLight(); + if (l.GetIntensity() > FLT_EPSILON && l.GetRadius() > FLT_EPSILON) { + // TODO: This shouldn't be inlined, but currently is. + x8e0_dynamicLights.push_back(l); + } + } + } + rstl::sort(x8e0_dynamicLights.begin(), x8e0_dynamicLights.end(), CLightPredicate()); +} + +bool CStateManager::CanCreateProjectile(TUniqueId uid, EWeaponType type, int maxAllowed) const { + return x878_weaponMgr->GetNumActive(uid, type) < maxAllowed; +} + +void CStateManager::ReflectionDrawer(void* ctx, const CVector3f& point) { + CStateManager* mgr = reinterpret_cast< CStateManager* >(ctx); + mgr->DrawReflection(point); +} + +void CStateManager::CacheReflection() { + gpRender->CacheReflection(ReflectionDrawer, this, !gkWorldOnlyReflection); +} + +void CStateManager::DrawReflection(const CVector3f& point) { + CPlayer* player = x84c_player; + CAABox playerBounds = player->GetBoundingBox(); + CVector3f playerPos = playerBounds.GetCenterPoint(); + + const CVector3f viewPos = + playerPos - 3.5f * CVector3f(playerPos.GetX() - point.GetX(), playerPos.GetY() - point.GetY(), + playerPos.GetZ() - playerPos.GetZ()) + .AsNormalized(); + + CTransform4f reflectionXf = CTransform4f::LookAt(viewPos, playerPos, CVector3f(0.f, 0.f, -1.f)); + const CTransform4f backupView = CGraphics::GetViewMatrix(); + CGraphics::SetViewPointMatrix(reflectionXf); + + const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); + const CGraphics::CProjectionState backupProj = CGraphics::GetProjectionState(); + + const CViewport& viewport = CGraphics::GetViewport(); + const float zFar = + *reinterpret_cast< const float* >(reinterpret_cast< const uchar* >(&curCam) + 0x164); + gpRender->SetPerspective(curCam.GetFov(), static_cast< float >(viewport.mWidth), + static_cast< float >(viewport.mHeight), curCam.GetNearClipDistance(), + zFar); + + player->RenderReflectedPlayer(*this); + + CGraphics::SetViewPointMatrix(backupView); + CGraphics::SetProjectionState(backupProj); +} + +void CStateManager::DrawSpaceWarp(const CVector3f& point, float strength) const { + switch (x8b8_playerState->GetActiveVisor(*this)) { + case CPlayerState::kPV_XRay: + case CPlayerState::kPV_Thermal: + return; + default: + break; + } + + const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); + CVector3f screenPoint; + ConvertToScreenSpace__11CGameCameraCFRC9CVector3f(&screenPoint, &curCam, &point); + gpRender->DrawSpaceWarp(screenPoint, strength); +} + +void CStateManager::TouchSky() const { x850_world->TouchSky(); } + +void CStateManager::TouchPlayerActor() const { + if (xf6c_playerActorHead != kInvalidUniqueId) { + const CEntity* ent = GetObjectById(xf6c_playerActorHead); + if (ent != nullptr) { + TouchModels__18CScriptPlayerActorFRC13CStateManager(const_cast< CEntity* >(ent), *this); + } + } +} + +void CStateManager::SetActorAreaId(CActor& actor, TAreaId aid) { + const int oldArea = actor.x4_areaId.value; + if (oldArea != aid.value) { + CWorld* world = x850_world.get(); + + if (oldArea != kInvalidAreaId.value) { + TAreaId oldAid = actor.x4_areaId; + TAreaId oldAid2 = actor.x4_areaId; + CGameArea* oldAreaObj = world->Area(oldAid); + if (oldAreaObj->IsPostConstructed()) { + static_cast< CObjectList* >(oldAreaObj->GetPostConstructed()->x10c0_areaObjectList) + ->RemoveObject(actor.GetUniqueId()); + } + } + + actor.x4_areaId = aid; + + if (aid != kInvalidAreaId) { + TAreaId newAid = aid; + CGameArea* newAreaObj = world->Area(newAid); + if (newAreaObj->IsPostConstructed()) { + TUniqueId uid = actor.GetUniqueId(); + CObjectList* areaObjList = + static_cast< CObjectList* >(newAreaObj->GetPostConstructed()->x10c0_areaObjectList); + if (static_cast< const CObjectList* >(areaObjList)->GetValidObjectById(uid) == nullptr) { + areaObjList->AddObject(actor); + } + } + } + } +} + +const rstl::string& CStateManager::HashInstanceName(CInputStream& in) { + static rstl::string empty = rstl::string_l(""); + uchar n = 0; + do { + n = in.ReadChar(); + } while (n != '\0'); + return empty; +} + +void CStateManager::MurderScriptInstanceNames() { + bool done = false; + + while (!done) { + done = true; + + rstl::set< rstl::string >::iterator it = xb40_uniqueInstanceNames.begin(); + rstl::set< rstl::string >::iterator end = xb40_uniqueInstanceNames.end(); + for (; it != end; ++it) { + const rstl::string* str = *it; + const void* cow = + *reinterpret_cast< const void* const* >(reinterpret_cast< const uchar* >(str) + 0x4); + int refCount = -1; + if (cow != nullptr) { + refCount = *reinterpret_cast< const int* >(reinterpret_cast< const uchar* >(cow) + 0x4); + } + + if (refCount == 1) { + xb40_uniqueInstanceNames.erase(it); + done = false; + break; + } + } + } +} + +void CStateManager::SetupParticleHook(const CActor& actor) const { + x884_actorModelParticles->SetupHook(actor.GetUniqueId()); +} + +void CStateManager::ResetEscapeSequenceTimer(float time) { + xf0c_escapeTimer = time; + xf10_escapeTotalTime = time; +} + +float CStateManager::GetEscapeSequenceTimer() const { return xf0c_escapeTimer; } + +void CStateManager::UpdateEscapeSequenceTimer(float dt) { + const float totalTime = xf10_escapeTotalTime; + if (xf0c_escapeTimer > 0.f) { + xf0c_escapeTimer = rstl::max_val(gkEpsilon, xf0c_escapeTimer - dt); + if (xf0c_escapeTimer <= FLT_EPSILON) { + struct SPlayerStateFlags { + bool x0_24_alive : 1; + }; + reinterpret_cast< SPlayerStateFlags* >(x8b8_playerState.GetPtr())->x0_24_alive = false; + } + + if (!init) { + init = true; + nextShake = 0.f; + } + + nextShake -= dt; + if (nextShake < 0.f) { + const float factor = 1.f - xf0c_escapeTimer / totalTime; + const float factorSq = factor * factor; + { + const CCameraShakeData shakeData(1.f, 0.2f * factorSq * x900_random->Range(0.5f, 1.f)); + x870_cameraManager->AddCameraShaker(shakeData, true); + } + x88c_rumbleManager->Rumble(*this, static_cast< ERumbleFxId >(0xb), 0.75f, kRP_One); + nextShake = -12.f * factorSq + 15.f; + } + } +} + +void CStateManager::UpdateHintState(float dt) { + CHintOptions& hintOpts = gpGameState->HintOptions(); + hintOpts.Update(dt, *this); + + int nextHintIdx = -1; + int hintPeriods = -1; + const SHintState* curHint = hintOpts.GetCurrentDisplayedHint(); + if (curHint != NULL) { + const CGameHintInfo::CGameHint& nextHint = GetGameHints()[hintOpts.GetNextHintIdx()]; + const rstl::vector< CGameHintInfo::SHintLocation >& locations = nextHint.GetLocations(); + for (int i = 0; i < static_cast< int >(locations.size()); ++i) { + const CGameHintInfo::SHintLocation& location = locations[i]; + const TAreaId areaId = location.x8_areaId; + const CAssetId mlvlId = location.x0_mlvlId; + CWorldState& worldState = gpGameState->StateForWorld(mlvlId); + rstl::rc_ptr< CMapWorldInfo > mapWorldInfo = worldState.MapWorldInfo(); + mapWorldInfo->SetIsMapped(areaId, true); + } + + if (curHint->x4_time < nextHint.GetTextTime()) { + nextHintIdx = hintOpts.GetNextHintIdx(); + hintPeriods = static_cast< int >(curHint->x4_time / 3.f); + } + } + + if (nextHintIdx != xeec_hintIdx || hintPeriods != static_cast< int >(xef0_hintPeriods)) { + if (nextHintIdx == -1) { + const rstl::wstring& empty = rstl::wstring_l(L""); + CHUDMemoParms memoInfo(0.f, true, true, true); + CSamusHud::DisplayHudMemo(empty, memoInfo); + } else { + const CGameHintInfo::CGameHint* hint = &GetGameHints()[nextHintIdx]; + SHudMemoInfo memoInfo(0.f, true, false, true); + CSamusHud::DeferHintMemo(hint->GetStringId(), hintPeriods, memoInfo); + } + + xeec_hintIdx = nextHintIdx; + xef0_hintPeriods = hintPeriods; + } +} + +void CStateManager::AddWeaponId(TUniqueId uid, EWeaponType type) { + x878_weaponMgr->IncrCount(uid, type); +} + +void CStateManager::RemoveWeaponId(TUniqueId uid, EWeaponType type) { + x878_weaponMgr->DecrCount(uid, type); +} + +int CStateManager::GetWeaponIdCount(TUniqueId uid, EWeaponType type) { + return x878_weaponMgr->GetNumActive(uid, type); +} + +TAreaId CStateManager::GetVisAreaId() const { + const CGameCamera& curCam = x870_cameraManager->GetCurrentCamera(*this); + const CBallCamera* ballCam = x870_cameraManager->GetBallCamera(); + const TAreaId curArea = x850_world->GetCurrentAreaId(); + if (&curCam != ballCam) { + return curArea; + } + + const CVector3f camTranslation = ballCam->GetTranslation(); + const CVector3f playerTranslation = x84c_player->GetTranslation(); + CAABox camAABB(camTranslation, camTranslation); + camAABB.AccumulateBounds(playerTranslation); + + TEntityList nearList; + const CMaterialFilter filter = CMaterialFilter::MakeInclude(CMaterialList(kMT_AIBlock)); + BuildNearList(nearList, camAABB, filter, nullptr); + for (const TUniqueId* uid = nearList.begin(); uid != nearList.end(); ++uid) { + const CScriptDock* dock = TCastToConstPtr< CScriptDock >(GetObjectById(*uid)); + if (dock != nullptr && dock->GetAreaId() == curArea && + dock->HasPointCrossedDock(*this, camTranslation)) { + return dock->GetCurrentConnectedAreaId(*this); + } + } + + return curArea; +} + +bool CStateManager::SpecialSkipCinematic() { + bool hadRandom = false; + TUniqueId id = xf38_skipCineSpecialFunc; + if (id == kInvalidUniqueId) { + return false; + } + + TUniqueId copyId(id); + CScriptSpecialFunction* special = static_cast< CScriptSpecialFunction* >(ObjectById(copyId)); + if (special == nullptr || !special->ShouldSkipCinematic(*this)) { + return false; + } + + hadRandom = x900_random != nullptr; + x900_random = &x8fc_random; + x870_cameraManager->StopCinematics(*this); + special->SkipCinematic(*this); + x900_random = hadRandom ? &x8fc_random : nullptr; + return true; +} + +bool CStateManager::AddDrawableActor(const CActor& actor, const CVector3f& pos, + const CAABox& bounds) const { + const_cast< CActor& >(actor).SetAddedToken(x8dc_objectDrawToken + 1); + gpRender->AddDrawable(&actor, pos, bounds, 0, IRenderer::kDS_SortedCallback); +} + +void CStateManager::AddDrawableActorPlane(const CActor& actor, const CPlane& plane, + const CAABox& bounds) const { + const_cast< CActor& >(actor).SetAddedToken(x8dc_objectDrawToken + 1); + gpRender->AddPlaneObject(&actor, bounds, plane, 0); +} + +bool CStateManager::RenderLast(const TUniqueId& uid) { + CStateManagerContainer* container = x86c_stateManagerContainer.get(); + CStateManagerContainer* bucket = container; + int count = *reinterpret_cast< int* >(reinterpret_cast< uchar* >(bucket) + 0xf39c); + if (count == 20) { + return false; + } + + TUniqueId* id = + reinterpret_cast< TUniqueId* >(reinterpret_cast< uchar* >(bucket) + 0xf3a0) + count; + if (id != nullptr) { + *id = uid; + } + + int* curCount = reinterpret_cast< int* >(reinterpret_cast< uchar* >(container) + 0xf39c); + *curCount = *curCount + 1; + return true; +} + +void CStateManager::DeferStateTransition(EStateManagerTransition t) { + if (t == kSMT_InGame) { + if (xf90_deferredTransition != kSMT_InGame) { + x850_world->SetLoadPauseState(false); + xf90_deferredTransition = kSMT_InGame; + } + } else if (xf90_deferredTransition == kSMT_InGame) { + x850_world->SetLoadPauseState(true); + xf90_deferredTransition = t; + } +} + +void CStateManager::ShowPausedHUDMemo(CAssetId strg, float time) { + xf78_hudMessageTime = time; + xf08_pauseHudMessage = strg; + DeferStateTransition(kSMT_MessageScreen); +} + +bool CStateManager::CanShowMapScreen() { + const SHintState* curHint = gpGameState->HintOptions().GetCurrentDisplayedHint(); + if (curHint != nullptr && !const_cast< SHintState* >(curHint)->CanContinue()) { + return false; + } + return true; +} + +void CStateManager::UpdateThermalVisor() { + xf28_thermColdScale2 = 0.f; + xf24_thermColdScale1 = 0.f; + + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Thermal && + x8cc_nextAreaId != kInvalidAreaId) { + CGameArea* curArea = x850_world->Area(x8cc_nextAreaId); + CGameArea* bestArea = nullptr; + float bestDistSq = FLT_MAX; + + const float playerX = x84c_player->GetTransform().Get03(); + const float playerY = x84c_player->GetTransform().Get13(); + + for (int i = 0; i < curArea->GetDockCount(); ++i) { + const IGameArea::Dock& dock = curArea->GetDock(i); + const rstl::reserved_vector< CVector3f, 4 >& verts = dock.GetPlaneVertices(); + + const float dockCenterY = + 0.25f * (verts[0].GetY() + verts[1].GetY() + verts[2].GetY() + verts[3].GetY()); + const float dockCenterX = + 0.25f * (verts[0].GetX() + verts[1].GetX() + verts[2].GetX() + verts[3].GetX()); + + const float deltaY = playerY - dockCenterY; + const float deltaX = playerX - dockCenterX; + const float distSq = deltaX * deltaX + deltaY * deltaY; + + if (distSq < bestDistSq) { + const TAreaId connectedAreaId = dock.GetConnectedAreaId(0); + if (connectedAreaId != kInvalidAreaId) { + CGameArea* connectedArea = x850_world->Area(connectedAreaId); + if (connectedArea->IsPostConstructed() && + connectedArea->GetPostConstructed()->x10dc_occlusionState == CGameArea::kOS_Visible) { + bestArea = connectedArea; + bestDistSq = distSq; + } + } + } + } + + const float areaThermal = curArea->GetPostConstructed()->x111c_thermalCurrent; + if (bestArea == nullptr) { + xf24_thermColdScale1 = areaThermal; + } else { + const float dist = CMath::FastSqrtF(bestDistSq); + const float blendDist = dist - 2.f; + if (blendDist >= 8.f) { + xf24_thermColdScale1 = areaThermal; + } else { + float blend = 0.5f; + if (blendDist > 0.f) { + blend = 0.5f * 0.125f * blendDist + 0.5f; + } + xf24_thermColdScale1 = blend * areaThermal + + (1.f - blend) * bestArea->GetPostConstructed()->x111c_thermalCurrent; + } + } + } +} + +void CStateManager::GetCharacterRenderMaskAndTarget(bool thawed, int& mask, int& target) { + mask = 0; + target = 0; + + switch (x8b8_playerState->GetActiveVisor(*this)) { + case CPlayerState::kPV_Combat: + case CPlayerState::kPV_Scan: + mask = 0x1000; + break; + case CPlayerState::kPV_XRay: + mask = 0x800; + break; + case CPlayerState::kPV_Thermal: + if (thawed) { + mask = 0x600; + target = xf34_thermalFlag == kTD_Hot ? 0 : 0x200; + } else { + mask = 0x500; + target = xf34_thermalFlag == kTD_Cold ? 0 : 0x100; + } + break; + default: + break; + } +} + +void CStateManager::DoCollisionResponse(const CCollisionResponseData& colRespData, + const CRayCastResult& rayCast, TUniqueId uid, + const CWeaponMode& weaponMode, bool w1, bool b1) { + if (!rayCast.IsValid()) { + return; + } + + CTransform4f xf = CTransform4f::LookAt(CVector3f::Zero(), rayCast.GetPlane().GetNormal()); + xf.SetTranslation(rayCast.GetPoint()); + + EWeaponCollisionResponseTypes type = kWCR_Default; + if (uid == kInvalidUniqueId) { + type = CCollisionResponseData::GetWorldCollisionResponseType( + CMaterialList::BitPosition(rayCast.GetMaterial().GetValue() & 0x00e3fffe)); + } else if (const CActor* actor = TCastToConstPtr< CActor >(GetObjectById(uid))) { + type = actor->GetCollisionResponseType(rayCast.GetPoint(), rayCast.GetPlane().GetNormal(), + weaponMode, 0); + } + + rstl::optional_object< TLockedToken< CGenDescription > > particleDesc = + colRespData.GetParticleDescription(type); + + if (particleDesc.valid()) { + CExplosion* explosion = rs_new CExplosion( + *particleDesc, AllocateUniqueId(), true, + CEntityInfo(kInvalidAreaId, CEntity::NullConnectionList, kInvalidEditorId), + rstl::string_l("Proj col resp"), xf, (b1 ? 0u : 1u) | (w1 ? 2u : 0u), + CVector3f(1.f, 1.f, 1.f), CColor::White()); + AddObject(explosion); + } + + int soundId = colRespData.GetSoundEffectId(type); + if (soundId >= 0) { + float range = colRespData.GetAudibleRange(); + float fallOff = colRespData.GetAudibleFallOff(); + CAudioSys::C3DEmitterParmData parmData(range, fallOff, 1, CAudioSys::kMaxVolume, 0x14); + parmData.x0_pos = rayCast.GetPoint(); + parmData.x24_sfxId = CSfxManager::TranslateSFXID(static_cast< ushort >(soundId)); + CSfxManager::AddEmitter(parmData, true, CSfxManager::kMedPriority, false, + CSfxManager::kAllAreas); + } +} + +const CSinglePathMaze* CStateManager::GetSinglePathMaze() const { return xf70_currentMaze.get(); } + +CSinglePathMaze* CStateManager::SinglePathMaze() { return xf70_currentMaze.get(); } + +void CStateManager::SetSinglePathMaze(rstl::single_ptr< CSinglePathMaze > maze) { + xf70_currentMaze = maze; +} + +void CStateManager::SetPendingOnScreenTex(CAssetId texId, const CVector2i& origin, + const CVector2i& extent) { + xef4_pendingScreenTex.x0_id = texId; + xef4_pendingScreenTex.x4_origin = origin; + xef4_pendingScreenTex.xc_extent = extent; +} + +void CStateManager::SetGameState(EGameState state) { + if (x904_gameState == state) { + return; + } + + if (x904_gameState == kGS_SoftPaused) { + x850_world->SetLoadPauseState(false); + } + + switch (state) { + case kGS_Running: { + CRumbleGenerator* rumbleGen = reinterpret_cast< CRumbleGenerator* >(x88c_rumbleManager); + if (rumbleGen->GetDisabled()) { + rumbleGen->SetDisabled(false); + } + break; + } + case kGS_SoftPaused: { + CRumbleGenerator* rumbleGen = reinterpret_cast< CRumbleGenerator* >(x88c_rumbleManager); + if (!rumbleGen->GetDisabled()) { + rumbleGen->SetDisabled(true); + } + x850_world->SetLoadPauseState(true); + break; + } + default: + break; + } + + x904_gameState = state; +} + +void CStateManager::SetBossParams(TUniqueId bossId, float maxEnergy, uint stringIdx) { + xf18_bossId = bossId; + xf1c_totalBossEnergy = maxEnergy; + xf20_bossStringIdx = stringIdx; +} + +const CPlayer* CStateManager::GetPlayer() const { return x84c_player; } + +void CStateManager::QueueMessage(int frameCount, CAssetId msg, float f1) { + xf84_ = frameCount; + xf88_ = msg; + xf8c_ = f1; +} + +void CStateManager::DeliverScriptMsg(CEntity* ent, TUniqueId target, EScriptObjectMessage msg) { + if (ent != nullptr && !ent->IsScriptingBlocked()) { + ent->AcceptScriptMsg(msg, target, *this); + } +} + +void CStateManager::SendScriptMsgAlways(TUniqueId uid, TUniqueId src, EScriptObjectMessage msg) { + CEntity* ent = ObjectById(uid); + if (ent != nullptr) { + ent->AcceptScriptMsg(msg, src, *this); + } +} + +float CStateManager::IntegrateVisorFog(float f) const { + if (x8b8_playerState->GetActiveVisor(*this) == CPlayerState::kPV_Scan) { + return f * (1.f - x8b8_playerState->GetVisorTransitionFactor()); + } + return f; +} diff --git a/src/MetroidPrime/Player/CMorphBall.cpp b/src/MetroidPrime/Player/CMorphBall.cpp index fb4a8851..da2e69d2 100644 --- a/src/MetroidPrime/Player/CMorphBall.cpp +++ b/src/MetroidPrime/Player/CMorphBall.cpp @@ -1,21 +1,240 @@ #include "MetroidPrime/Player/CMorphBall.hpp" #include "Collision/CMaterialList.hpp" +#include "Collision/CollisionUtil.hpp" +#include "Kyoto/Audio/CSfxManager.hpp" +#include "Kyoto/Basics/CCast.hpp" +#include "Kyoto/CDependencyGroup.hpp" +#include "Kyoto/CResFactory.hpp" +#include "Kyoto/CSimplePool.hpp" #include "Kyoto/Input/CFinalInput.hpp" +#include "Kyoto/Math/CVector3f.hpp" #include "MetroidPrime/CActorLights.hpp" +#include "MetroidPrime/CAnimRes.hpp" +#include "MetroidPrime/CAxisAngle.hpp" #include "MetroidPrime/CControlMapper.hpp" +#include "MetroidPrime/CDamageInfo.hpp" +#include "MetroidPrime/CFluidPlaneCPU.hpp" +#include "MetroidPrime/CGameCollision.hpp" +#include "MetroidPrime/CGameLight.hpp" +#include "MetroidPrime/CPhysicsActor.hpp" +#include "MetroidPrime/CRainSplashGenerator.hpp" +#include "MetroidPrime/CWorld.hpp" #include "MetroidPrime/CWorldShadow.hpp" +#include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CGameCamera.hpp" +#include "MetroidPrime/Enemies/CMetroidBeta.hpp" #include "MetroidPrime/Player/CMorphBallShadow.hpp" #include "MetroidPrime/Player/CPlayer.hpp" +#include "MetroidPrime/SFX/IceWorld.h" +#include "MetroidPrime/SFX/LavaWorld.h" +#include "MetroidPrime/SFX/MiscSamus.h" +#include "MetroidPrime/ScriptObjects/CScriptAreaAttributes.hpp" +#include "MetroidPrime/ScriptObjects/CScriptSpiderBallAttractionSurface.hpp" +#include "MetroidPrime/ScriptObjects/CScriptSpiderBallWaypoint.hpp" +#include "MetroidPrime/ScriptObjects/CScriptWater.hpp" +#include "MetroidPrime/TCastTo.hpp" #include "MetroidPrime/TGameTypes.hpp" +#include "Kyoto/Math/CMath.hpp" +#include "Kyoto/Math/CPlane.hpp" +#include "Kyoto/Math/CRelAngle.hpp" #include "Kyoto/Math/CTransform4f.hpp" +#include "Kyoto/Math/CloseEnough.hpp" #include "Kyoto/Particles/CElementGen.hpp" +#include "Kyoto/Particles/CGenDescription.hpp" #include "Kyoto/Particles/CParticleSwoosh.hpp" #include "MetroidPrime/Tweaks/CTweakBall.hpp" #include "MetroidPrime/Tweaks/CTweakPlayer.hpp" +#include "rstl/math.hpp" + +#pragma inline_max_size(250) + +float kSpiderBallCollisionRadius; + +struct SMorphBallModelInfo { + const char* x0_name; + uint x4_shader; +}; + +struct SMorphBallModelTables { + SMorphBallModelInfo x0_ballCharacter[8]; + SMorphBallModelInfo x40_ballLowPoly[8]; + SMorphBallModelInfo x80_spiderBallLowPoly[8]; + SMorphBallModelInfo xc0_spiderBallCharacter[8]; + SMorphBallModelInfo x100_spiderBallGlass[8]; + SMorphBallModelInfo x140_frozenBall[8]; + uint x180_spiderBallGlowColorIdx[8]; + uint x1a0_ballGlowColorIdx[8]; +}; + +static const SMorphBallModelTables skMorphBallModelTables = { + { + {"SamusBallANCS", 0}, + {"SamusBallANCS", 0}, + {"SamusBallANCS", 1}, + {"SamusBallANCS", 0}, + {"SamusFusionBallANCS", 0}, + {"SamusFusionBallANCS", 2}, + {"SamusFusionBallANCS", 1}, + {"SamusFusionBallANCS", 3}, + }, + { + {"SamusBallLowPolyCMDL", 0}, + {"SamusBallLowPolyCMDL", 0}, + {"SamusBallLowPolyCMDL", 1}, + {"SamusBallLowPolyCMDL", 0}, + {"SamusBallFusionLowPolyCMDL", 0}, + {"SamusBallFusionLowPolyCMDL", 2}, + {"SamusBallFusionLowPolyCMDL", 1}, + {"SamusBallFusionLowPolyCMDL", 3}, + }, + { + {"SamusSpiderBallLowPolyCMDL", 0}, + {"SamusSpiderBallLowPolyCMDL", 0}, + {"SamusSpiderBallLowPolyCMDL", 1}, + {"SamusSpiderBallLowPolyCMDL", 2}, + {"SamusBallFusionLowPolyCMDL", 0}, + {"SamusBallFusionLowPolyCMDL", 2}, + {"SamusBallFusionLowPolyCMDL", 1}, + {"SamusBallFusionLowPolyCMDL", 3}, + }, + { + {"SamusSpiderBallANCS", 0}, + {"SamusSpiderBallANCS", 0}, + {"SamusSpiderBallANCS", 1}, + {"SamusPhazonBallANCS", 0}, + {"SamusFusionBallANCS", 0}, + {"SamusFusionBallANCS", 2}, + {"SamusFusionBallANCS", 1}, + {"SamusFusionBallANCS", 3}, + }, + { + {"SamusSpiderBallGlassCMDL", 0}, + {"SamusSpiderBallGlassCMDL", 0}, + {"SamusSpiderBallGlassCMDL", 1}, + {"SamusPhazonBallGlassCMDL", 0}, + {"SamusSpiderBallGlassCMDL", 0}, + {"SamusSpiderBallGlassCMDL", 0}, + {"SamusSpiderBallGlassCMDL", 1}, + {"SamusPhazonBallGlassCMDL", 0}, + }, + { + // TODO hack: where is the \0 coming from? + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + {"SamusBallFrozenCMDL\0", 0}, + }, + {3, 3, 2, 4, 5, 7, 6, 8}, + {0, 0, 1, 0, 5, 7, 6, 8}, +}; + +static const char* const skSamusBall = skMorphBallModelTables.x0_ballCharacter[0].x0_name; +static const char* const skSamusBallLowPoly = skMorphBallModelTables.x40_ballLowPoly[0].x0_name; +static const char* const skSamusSpiderBallGlass = + skMorphBallModelTables.x100_spiderBallGlass[0].x0_name; +static const char* const skSamusBallFrozen = skMorphBallModelTables.x140_frozenBall[0].x0_name; + +namespace { +const uchar lbl_803CEAD0[0x1c] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, + 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +}; + +const uchar lbl_803CEAEC[0x1c] = { + 0xc2, 0x7e, 0x10, 0x66, 0xc4, 0xff, 0x60, 0xff, 0x90, 0x33, 0x33, 0xff, 0xff, 0x20, + 0x20, 0x00, 0x9d, 0xb6, 0xd3, 0xf1, 0x00, 0xa6, 0x86, 0xd8, 0xfb, 0x98, 0x21, 0x00, +}; + +const uchar lbl_803CEB08[0x1c] = { + 0xc2, 0x7e, 0x10, 0x66, 0xc4, 0xff, 0x6c, 0xff, 0x61, 0x33, 0x33, 0xff, 0xff, 0x20, + 0x20, 0x00, 0x9d, 0xb6, 0xd3, 0xf1, 0x00, 0xa6, 0x86, 0xd8, 0xfb, 0x98, 0x21, 0x00, +}; + +const uchar lbl_803CEB24[0x1c] = { + 0xc2, 0x8f, 0x17, 0x70, 0xd4, 0xff, 0x6a, 0xff, 0x8a, 0x3d, 0x4d, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0xbe, 0xdc, 0xdf, 0xff, 0x00, 0xc4, 0x9e, 0xff, 0xff, 0x9a, 0x22, 0x00, +}; + +const uchar lbl_803CEB40[0x1c] = { + 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0xff, 0x80, + 0x20, 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0xff, 0xe6, 0x00, 0x00, +}; + +const uchar lbl_803CEB5C[0x1c] = { + 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0xff, 0xd5, + 0x19, 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0xff, 0xcc, 0x00, 0x00, +}; + +const uchar lbl_803CEB78[0x1c] = { + 0xc2, 0x7e, 0x10, 0x66, 0xc4, 0xff, 0x60, 0xff, 0x90, 0x33, 0x33, 0xff, 0xff, 0x80, + 0x80, 0x00, 0x9d, 0xb6, 0xd3, 0xf1, 0x00, 0x60, 0x33, 0xff, 0xfb, 0x98, 0x21, 0x00, +}; +} // namespace + +static rstl::reserved_vector< int, 32 > skWakeEffectMap; + +static const ushort skBallRollSfx[24] = { + 0xFFFF, + SFXsam_b_rolllston_lp, + SFXsam_b_rollmetl_lp_00, + SFXsam_b_rollgras_lp_00, + SFXsam_b_rolllice_lp_00, + 0xFFFF, + SFXsam_b_rollgrat_lp_00, + SFXsam_b_rollphaz_lp_00, + SFXsam_b_rollgravel_lp_00, + SFXsam_b_rollllava_lp_00, + SFXsam_b_rolllcrus_lp_00, + SFXsam_b_rolllsnow_lp_00, + SFXsam_b_rollmud_lp_00, + 0xFFFF, + SFXsam_b_rollorg_lp_00, + SFXsam_b_rollmetl_lp_00, + SFXsam_b_rollmetl_lp_00, + SFXsam_b_rollgravel_lp_00, + 0xFFFF, + 0xFFFF, + 0xFFFF, + 0xFFFF, + SFXsam_b_rollwood_lp_00, + SFXsam_b_rollorg_lp_00, +}; + +static const ushort skBallLandSfx[24] = { + 0xFFFF, + SFXsam_b_mlandstn_00, + SFXsam_b_mlandmtl_00, + SFXsam_b_mlandgrs_00, + SFXsam_b_mlandice_00, + 0xFFFF, + SFXsam_b_mlandgrt_00, + SFXsam_b_mlandphz_00, + SFXsam_b_landsand_00, + SFXsam_b_mlandcrs_00, + SFXsam_b_mlandcrs_00, + SFXsam_b_mlandsnw_00, + SFXsam_b_mlandmud_00, + 0xFFFF, + SFXsam_b_mlandorg_00, + SFXsam_b_mlandmtl_00, + SFXsam_b_mlandmtl_00, + SFXsam_b_landsand_00, + 0xFFFF, + 0xFFFF, + 0xFFFF, + 0xFFFF, + SFXsam_b_mlandwoo_00, + SFXsam_b_mlandorg_00, +}; + CMorphBall::CMorphBall(CPlayer& player, float radius) : x0_player(player) , x4_loadedModelId(-1) @@ -28,15 +247,16 @@ CMorphBall::CMorphBall(CPlayer& player, float radius) , x30_ballTiltAngle(0.f) , x38_collisionSphere(CSphere(CVector3f(0.f, 0.f, radius), radius), CMaterialList(kMT_Player, kMT_Solid, kMT_GroundCollider)) -, x58_ballModel(GetMorphballModel(rstl::string_l("SamusBallAncs"), radius)) +, x58_ballModel(GetMorphBallModel(rstl::string_l(skSamusBall), xc_radius)) , x5c_ballModelShader(0) -, x60_spiderBallGlassModel(GetMorphballModel(rstl::string_l("SamusSpiderBallGalssCMDL"), radius)) +, x60_spiderBallGlassModel(GetMorphBallModel(rstl::string_l(skSamusSpiderBallGlass), xc_radius)) , x64_spiderBallGlassModelShader(0) -, x68_lowPolyBallModel(GetMorphballModel(rstl::string_l("SamusBallLowPolyCMDL"), radius)) +, x68_lowPolyBallModel(GetMorphBallModel(rstl::string_l(skSamusBallLowPoly), xc_radius)) , x6c_lowPolyBallModelShader(0) +, x70_frozenBallModel(GetMorphBallModel(rstl::string_l(skSamusBallFrozen), xc_radius)) , x187c_spiderBallState(kSBS_Inactive) , x1880_playerToSpiderNormal(CVector3f::Zero()) -, x188c_spiderPullMovement(0.f) +, x188c_spiderPullMovement(1.f) , x1890_spiderTrackPoint(CVector3f::Zero()) , x189c_spiderInterpBetweenPoints(CVector3f::Zero()) , x18a8_spiderBetweenPoints(CVector3f::Zero()) @@ -60,8 +280,94 @@ CMorphBall::CMorphBall(CPlayer& player, float radius) , x191c_damageTimer(0.f) , x1920_spiderForcesReset(false) , x1924_surfaceToWorld(CTransform4f::Identity()) +, x1954_isProjectile(false) +, x1958_animationTokens() +, x1968_slowBlueTailSwoosh(gpSimplePool->GetObj("SlowBlueTailSwoosh")) +, x1970_slowBlueTailSwoosh2(gpSimplePool->GetObj("SlowBlueTailSwoosh2")) +, x1978_jaggyTrail(gpSimplePool->GetObj("JaggyTrail")) +, x1980_wallSpark(gpSimplePool->GetObj("WallSpark")) +, x1988_ballInnerGlow(gpSimplePool->GetObj("BallInnerGlow")) +, x1990_spiderBallMagnetEffect(gpSimplePool->GetObj("SpiderBallMagnetEffect")) +, x1998_boostBallGlow(gpSimplePool->GetObj("BoostBallGlow")) +, x19a0_spiderElectric(gpSimplePool->GetObj("SpiderElectric")) +, x19a8_morphBallTransitionFlash(gpSimplePool->GetObj("MorphBallTransitionFlash")) +, x19b0_effect_morphBallIceBreak(gpSimplePool->GetObj("Effect_MorphBallIceBreak")) +, x19b8_slowBlueTailSwooshGen(rs_new CParticleSwoosh(x1968_slowBlueTailSwoosh, 0)) +, x19bc_slowBlueTailSwooshGen2(rs_new CParticleSwoosh(x1968_slowBlueTailSwoosh, 0)) +, x19c0_slowBlueTailSwoosh2Gen(rs_new CParticleSwoosh(x1970_slowBlueTailSwoosh2, 0)) +, x19c4_slowBlueTailSwoosh2Gen2(rs_new CParticleSwoosh(x1970_slowBlueTailSwoosh2, 0)) +, x19c8_jaggyTrailGen(rs_new CParticleSwoosh(x1978_jaggyTrail, 0)) +, x19cc_wallSparkGen( + rs_new CElementGen(x1980_wallSpark, CElementGen::kMOT_Normal, CElementGen::kOSF_One)) +, x19d0_ballInnerGlowGen( + rs_new CElementGen(x1988_ballInnerGlow, CElementGen::kMOT_Normal, CElementGen::kOSF_One)) +, x19d4_spiderBallMagnetEffectGen(rs_new CElementGen( + x1990_spiderBallMagnetEffect, CElementGen::kMOT_Normal, CElementGen::kOSF_One)) +, x19d8_boostBallGlowGen( + rs_new CElementGen(x1998_boostBallGlow, CElementGen::kMOT_Normal, CElementGen::kOSF_One)) +, x1b80_rand(99) , x1c0c_wakeEffectIdx(-1) -, x1c10_ballInnerGlowLight(kInvalidUniqueId) {} +, x1c10_ballInnerGlowLight(kInvalidUniqueId) +, x1c14_worldShadow(rs_new CWorldShadow(16, 16, false)) +, x1c18_actorLights(rs_new CActorLights(8, CVector3f::Zero(), 4, 4)) +, x1c1c_rainSplashGen( + rs_new CRainSplashGenerator(CVector3f(x58_ballModel->GetScale()), 40, 2, 0.15f, 0.5f)) +, x1c20_tireFactor(0.f) +, x1c24_maxTireFactor(0.5f) +, x1c28_tireInterpSpeed(1.f) +, x1c2c_tireInterpolating(false) +, x1c30_boostOverLightFactor(0.f) +, x1c34_boostLightFactor(0.f) +, x1c38_spiderLightFactor(0.f) +, x1c3c_ballOrientAvg(CQuaternion::NoRotation()) +, x1c90_ballPosAvg(CVector3f::Zero()) +, x1cd0_liftSpeedAvg(0.f) +, x1d10_liftControlForceAvg(CVector3f::Zero()) +, x1dc8_failsafeCounter(0) +, x1dcc_(CVector3f::Zero()) +, x1dd8_(CVector3f::Zero()) +, x1de4_24_inBoost(false) +, x1de4_25_boostEnabled(true) +, x1de8_boostChargeTime(0.f) +, x1dec_timeNotInBoost(0.f) +, x1df0_(0.f) +, x1df4_boostDrainTime(0.f) +, x1df8_24_inHalfPipeMode(false) +, x1df8_25_inHalfPipeModeInAir(false) +, x1df8_26_touchedHalfPipeRecently(false) +, x1df8_27_ballCloseToCollision(false) +, x1dfc_touchHalfPipeCooldown(0.f) +, x1e00_disableControlCooldown(0.f) +, x1e04_touchHalfPipeRecentCooldown(0.f) +, x1e08_prevHalfPipeNormal(CVector3f::Zero()) +, x1e14_halfPipeNormal(CVector3f::Zero()) +, x1e20_ballAnimIdx(0) +, x1e24_boostSfxHandle() +, x1e28_wallHitSfxHandle() +, x1e2c_rollSfxHandle() +, x1e30_spiderSfxHandle() +, x1e34_rollSfx(0xffff) +, x1e36_landSfx(0xffff) +, x1e38_wallSparkFrameCountdown(0) +, x1e3c_boostState(kBBS_BoostAvailable) +, x1e40_bombJumpState(kBJS_BombJumpAvailable) +, x1e44_damageEffect(0.f) +, x1e48_damageEffectDecaySpeed(0.f) +, x1e4c_damageTime(0.f) +, x1e50_shadow() { + x19d4_spiderBallMagnetEffectGen->SetParticleEmission(false); + x19d4_spiderBallMagnetEffectGen->Update(1.f / 60.f); + + kSpiderBallCollisionRadius = 0.2f + GetBallRadius(); + + for (int i = 0; i < x19e4_spiderElectricGens.capacity(); ++i) { + x19e4_spiderElectricGens.push_back(rstl::pair< rstl::auto_ptr< CParticleSwoosh >, bool >( + rstl::auto_ptr< CParticleSwoosh >(rs_new CParticleSwoosh(x19a0_spiderElectric, 0)), false)); + } + + LoadAnimationTokens(rstl::string_l(skSamusBall)); + InitializeWakeEffects(); +} CMorphBall::~CMorphBall() {} @@ -108,3 +414,2578 @@ void CMorphBall::UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, ApplySpiderBallRollForces(input, mgr, dt); } } + +void CMorphBall::ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, + float dt) { + x18b4_linVelDamp = 0.04f; + x18b8_angVelDamp = 0.99f; + x1880_playerToSpiderNormal = x1890_spiderTrackPoint - x0_player.GetTranslation(); + + const float playerToSpiderDist = x1880_playerToSpiderNormal.Magnitude(); + x1880_playerToSpiderNormal *= 1.f / (-1.f * playerToSpiderDist); + + const float movement = GetSpiderBallControllerMovement(input); + UpdateSpiderBallSwingControllerMovementTimer(movement, dt); + + const float swingMovement = movement * GetSpiderBallSwingControllerMovementScalar(); + const float swingForce = 110000.f * playerToSpiderDist / 3.7f; + const CVector3f swing = CVector3f::Cross(x1880_playerToSpiderNormal, x18a8_spiderBetweenPoints); + x0_player.ApplyForceWR(CVector3f::Cross(swing, x1880_playerToSpiderNormal).AsNormalized() * + swingForce * swingMovement * 0.06f, + CAxisAngle::Identity()); + x0_player.SetMomentumWR(CVector3f(0.f, 0.f, x0_player.GetMass() * gpTweakBall->GetBallGravity())); + x18fc_refPullVel = (1.f - x188c_spiderPullMovement) * 3.7f + 1.4f; + x1900_playerToSpiderTrackDist = playerToSpiderDist; + + CVector3f playerVel = x0_player.GetVelocityWR(); + const float playerSpeed = playerVel.Magnitude(); + playerVel -= x1880_playerToSpiderNormal * playerSpeed * + CVector3f::Dot(x1880_playerToSpiderNormal, playerVel.AsNormalized()); + + float maxPullVel = 0.04f; + if (1.f == x188c_spiderPullMovement && CMath::AbsF(x1880_playerToSpiderNormal.GetZ()) > 0.8f) { + maxPullVel = 0.3f; + } + + const float pullDelta = x18fc_refPullVel - playerToSpiderDist; + const float signedMaxPull = maxPullVel * CMath::Sign(pullDelta); + const float clampedPull = rstl::min_val(CMath::AbsF(signedMaxPull), CMath::AbsF(pullDelta)); + playerVel += x1880_playerToSpiderNormal * (clampedPull * CMath::Sign(signedMaxPull) / dt); + x0_player.SetVelocityWR(playerVel); +} + +void CMorphBall::ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt) { + CVector2f surfaceForces = CalculateSpiderBallAttractionSurfaceForces(input); + CVector3f viewSurfaceForces = TransformSpiderBallForcesXZ(surfaceForces, mgr); + const CTransform4f camXf = mgr.GetCameraManager()->GetCurrentCamera(mgr).GetTransform(); + const CVector3f spiderDirNorm = x189c_spiderInterpBetweenPoints.AsNormalized(); + + const float spiderUpDot = CMath::AbsF(CVector3f::Dot(spiderDirNorm, camXf.GetColumn(kDZ))); + const float spiderForwardDot = CMath::AbsF(CVector3f::Dot(spiderDirNorm, camXf.GetColumn(kDY))); + if (x0_player.x9c4_29_spiderBallControlXY) { + if (spiderUpDot < 0.25f) { + if (spiderForwardDot > 0.25f) { + viewSurfaceForces = TransformSpiderBallForcesXY(surfaceForces, mgr); + } + } + } + + const float forceMag = surfaceForces.Magnitude(); + CVector2f normSurfaceForces(0.f, 0.f); + float spiderTrackForceMag = + x18c0_isSpiderSurface ? forceMag : CVector3f::Dot(viewSurfaceForces, spiderDirNorm); + + bool forceApplied = true; + bool moving; + bool continueTrackForce = false; + if (CMath::AbsF(forceMag) > 0.05f) { + normSurfaceForces = surfaceForces.AsNormalized(); + if (!x18c0_isSpiderSurface && + CVector2f::Dot(normSurfaceForces, x190c_normSpiderSurfaceForces) > 0.9f) { + continueTrackForce = true; + spiderTrackForceMag = forceMag * CMath::Sign(x1914_spiderTrackForceMag); + } else if (CMath::AbsF(spiderTrackForceMag) > 0.05f) { + spiderTrackForceMag = forceMag * CMath::Sign(spiderTrackForceMag); + } else { + forceApplied = false; + } + } else { + forceApplied = false; + } + + if (!continueTrackForce) { + x190c_normSpiderSurfaceForces = normSurfaceForces; + x1914_spiderTrackForceMag = spiderTrackForceMag; + x1920_spiderForcesReset = true; + } + + if (!forceApplied) { + spiderTrackForceMag = 0.f; + ResetSpiderBallForces(); + } + + moving = true; + if (!forceApplied) { + if (!(x0_player.GetVelocityWR().Magnitude() > 6.5f)) { + moving = false; + } + } + + CVector3f moveDelta = CVector3f::Zero(); + if (x18bd_touchingSpider && forceApplied) { + if (x18c0_isSpiderSurface) { + moveDelta = 0.1f * viewSurfaceForces; + } else { + const float spiderTrackSign = CMath::Sign(spiderTrackForceMag); + moveDelta = x18a8_spiderBetweenPoints.AsNormalized() * 0.1f * spiderTrackSign; + } + } + + CVector3f ballPos = GetBallToWorld().GetTranslation() + moveDelta; + bool lockToCurrentTrack = false; + float distance = 0.f; + if (!moving && x18bd_touchingSpider && 1.f == x188c_spiderPullMovement && + !x18bf_spiderSwingInAir) { + lockToCurrentTrack = true; + } + + if (!lockToCurrentTrack) { + x18bc_spiderNearby = false; + if (FindClosestSpiderBallWaypoint(mgr, ballPos, x1890_spiderTrackPoint, + x189c_spiderInterpBetweenPoints, x18a8_spiderBetweenPoints, + distance, x1880_playerToSpiderNormal, x18c0_isSpiderSurface, + x18c4_spiderSurfaceTransform)) { + x18bc_spiderNearby = true; + x18bf_spiderSwingInAir = false; + } + } else { + x1880_playerToSpiderNormal = x1890_spiderTrackPoint - ballPos; + distance = x1880_playerToSpiderNormal.Magnitude(); + x1880_playerToSpiderNormal *= 1.f / (-1.f * distance); + x18bc_spiderNearby = true; + } + + if (x18bc_spiderNearby) { + if (distance < kSpiderBallCollisionRadius) { + x18bd_touchingSpider = true; + } + + const float angVelDamp = 0.2f; + if (x18bd_touchingSpider == true) { + if (moving) { + if (!x18c0_isSpiderSurface) { + x18b4_linVelDamp = 0.4f; + x18b8_angVelDamp = angVelDamp; + + const CVector3f spiderInterpNorm = x189c_spiderInterpBetweenPoints.AsNormalized(); + float viewControlMag = CVector3f::Dot(viewSurfaceForces, spiderInterpNorm); + if (continueTrackForce && !x1920_spiderForcesReset) { + viewControlMag = x1918_spiderViewControlMag; + } else { + x1918_spiderViewControlMag = viewControlMag; + x1920_spiderForcesReset = false; + } + + float spiderForceMag; + if (CMath::AbsF(viewControlMag) > 0.1f) { + const float spiderTrackSign = CMath::Sign(viewControlMag); + spiderForceMag = spiderTrackSign * CMath::Clamp(-1.f, forceMag, 1.f); + } else { + spiderForceMag = 0.f; + ResetSpiderBallForces(); + } + + if (distance > 1.05f) { + spiderForceMag *= (1.05f - (distance - 1.05f)) / 1.05f; + } + + x0_player.ApplyForceWR(spiderForceMag * + (x18a8_spiderBetweenPoints.AsNormalized() * 90000.f), + CAxisAngle::Identity()); + } else { + x18b4_linVelDamp = 0.3f; + x18b8_angVelDamp = angVelDamp; + + const float surfaceXForce = + CVector3f::Dot(x18c4_spiderSurfaceTransform.GetColumn(kDX), viewSurfaceForces); + const float surfaceZForce = + CVector3f::Dot(x18c4_spiderSurfaceTransform.GetColumn(kDZ), viewSurfaceForces); + const CVector3f forceVec = (x18c4_spiderSurfaceTransform.GetColumn(kDX) * surfaceXForce + + x18c4_spiderSurfaceTransform.GetColumn(kDZ) * surfaceZForce) * + 45000.f; + x0_player.ApplyForceWR(forceVec, CAxisAngle::Identity()); + + const float pivotSurfaceX = surfaceXForce * 45000.f; + const float pivotSurfaceZ = surfaceZForce * 45000.f; + float angle = x18f8_spiderSurfacePivotTargetAngle; + if (forceVec.MagSquared() > 0.f) { + angle = atan2f(pivotSurfaceX, pivotSurfaceZ); + if (angle - x18f4_spiderSurfacePivotAngle > M_PIF / 2.f) { + angle -= M_PIF; + } else if (x18f4_spiderSurfacePivotAngle - angle > M_PIF / 2.f) { + angle += M_PIF; + } + x18f8_spiderSurfacePivotTargetAngle = angle; + } + + const float pivotDelta = angle - x18f4_spiderSurfacePivotAngle; + const float absPivotDelta = CMath::AbsF(pivotDelta); + const float pivotStep = rstl::min_val(0.2f, absPivotDelta); + x18f4_spiderSurfacePivotAngle = + pivotStep * CMath::Sign(pivotDelta) + x18f4_spiderSurfacePivotAngle; + + const CRelAngle pivotAngle(x18f4_spiderSurfacePivotAngle); + const CTransform4f& rotateY = CTransform4f::RotateY(pivotAngle); + x189c_spiderInterpBetweenPoints = + x18c4_spiderSurfaceTransform.Rotate(rotateY.GetColumn(kDZ)); + } + } + + const float spiderPullForce = 8.f * (x0_player.GetMass() * gpTweakBall->GetBallGravity()); + x0_player.ApplyForceWR( + CVector3f(0.f, 0.f, (1.f - x188c_spiderPullMovement) * spiderPullForce), + CAxisAngle::Identity()); + } else { + x18b4_linVelDamp = 0.2f; + x18b8_angVelDamp = angVelDamp; + } + + x0_player.SetMomentumWR( + 4.f * ((x0_player.GetMass() * gpTweakBall->GetBallGravity()) * x1880_playerToSpiderNormal)); + } +} + +CVector3f CMorphBall::TransformSpiderBallForcesXZ(CVector2f& forces, CStateManager& mgr) { + CTransform4f camXf = mgr.GetCameraManager()->GetCurrentCamera(mgr).GetTransform(); + CVector3f ret = camXf.GetColumn(kDX) * forces.GetX() + camXf.GetColumn(kDZ) * forces.GetY(); + return ret; +} + +CVector3f CMorphBall::TransformSpiderBallForcesXY(CVector2f& forces, CStateManager& mgr) { + CTransform4f camXf = mgr.GetCameraManager()->GetCurrentCamera(mgr).GetTransform(); + CVector3f ret = camXf.GetColumn(kDX) * forces.GetX() + camXf.GetColumn(kDY) * forces.GetY(); + return ret; +} + +void CMorphBall::ResetSpiderBallForces() { + x190c_normSpiderSurfaceForces = CVector2f(0.f, 0.f); + x1914_spiderTrackForceMag = 0.f; + x1918_spiderViewControlMag = 0.f; + x1920_spiderForcesReset = true; +} + +CVector2f CMorphBall::CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const { + if (!IsMovementAllowed()) { + return CVector2f::Zero(); + } + + const float forwardBack = ControlMapper::GetAnalogInput(ControlMapper::kC_Forward, input) - + ControlMapper::GetAnalogInput(ControlMapper::kC_Backward, input); + const float rightLeft = ControlMapper::GetAnalogInput(ControlMapper::kC_TurnRight, input) - + ControlMapper::GetAnalogInput(ControlMapper::kC_TurnLeft, input); + return CVector2f(rightLeft, forwardBack); +} + +bool CMorphBall::CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const { + if (!x18bd_touchingSpider) { + return false; + } + + if (1.f == x188c_spiderPullMovement) { + if (x18be_spiderBallSwinging) { + CVector3f closestPoint = CVector3f::Zero(); + CVector3f interpDeltaBetweenPoints = CVector3f::Zero(); + CVector3f deltaBetweenPoints = CVector3f::Zero(); + float distance = 0.f; + CVector3f normal = CVector3f::Zero(); + CTransform4f surfaceTransform(CTransform4f::Identity()); + bool isSurface; + if (FindClosestSpiderBallWaypoint(mgr, GetBallToWorld().GetTranslation(), closestPoint, + interpDeltaBetweenPoints, deltaBetweenPoints, distance, + normal, isSurface, surfaceTransform)) { + if (distance < 2.1f) { + return false; + } + } + + return true; + } + + return false; + } + + if (x18be_spiderBallSwinging) { + return true; + } + + return CMath::AbsF(x1880_playerToSpiderNormal.GetZ()) > 0.9f; +} + +bool CMorphBall::FindClosestSpiderBallWaypoint(CStateManager& mgr, const CVector3f& ballCenter, + CVector3f& closestPoint, + CVector3f& interpDeltaBetweenPoints, + CVector3f& deltaBetweenPoints, float& distance, + CVector3f& normal, bool& isSurface, + CTransform4f& surfaceTransform) const { + float minDist = 2.1f; + TEntityList nearList; + bool ret = false; + const CAABox aabb(ballCenter - CVector3f(minDist, minDist, minDist), + ballCenter + CVector3f(minDist, minDist, minDist)); + mgr.BuildNearList(nearList, aabb, CMaterialFilter::skPassEverything, nullptr); + + for (AUTO(surfaceIt, nearList.begin()); surfaceIt != nearList.end(); ++surfaceIt) { + if (const CScriptSpiderBallAttractionSurface* surface = + TCastToConstPtr< CScriptSpiderBallAttractionSurface >(mgr.GetObjectById(*surfaceIt))) { + const CVector3f surfaceNormal = surface->GetTransform().GetColumn(kDY).AsNormalized(); + CPlane plane(surface->GetTransform().GetTranslation(), CUnitVector3f(1.f * surfaceNormal)); + CVector3f point = CVector3f::Zero(); + + if (CollisionUtil::RayPlaneIntersection(ballCenter + 2.1f * surfaceNormal, + ballCenter - 2.1f * surfaceNormal, plane, point)) { + const float halfX = 0.5f * surface->GetScale().GetX(); + const float halfY = 0.5f * surface->GetScale().GetY(); + const float halfZ = 0.5f * surface->GetScale().GetZ(); + CTransform4f invScaleXf = CTransform4f::Scale(1.f / halfX, 1.f / halfY, 1.f / halfZ); + CVector3f clampedPoint = (invScaleXf * surface->GetTransform().GetQuickInverse()) * point; + clampedPoint[kDX] = CMath::Clamp(-1.f, clampedPoint[kDX], 1.f); + clampedPoint[kDZ] = CMath::Clamp(-1.f, clampedPoint[kDZ], 1.f); + CTransform4f scaleXf = CTransform4f::Scale(halfX, halfY, halfZ); + CVector3f worldPoint = (surface->GetTransform() * scaleXf) * clampedPoint; + const CVector3f finalDelta = worldPoint - ballCenter; + const float finalMag = finalDelta.Magnitude(); + + if (finalMag < minDist) { + minDist = finalMag; + closestPoint = worldPoint; + distance = finalMag; + normal = (-1.f / minDist) * finalDelta; + isSurface = true; + surfaceTransform = surface->GetTransform(); + ret = true; + } + } + } + } + + for (AUTO(waypointIt, nearList.begin()); waypointIt != nearList.end(); ++waypointIt) { + if (const CScriptSpiderBallWaypoint* waypoint = + TCastToConstPtr< CScriptSpiderBallWaypoint >(mgr.GetObjectById(*waypointIt))) { + const CScriptSpiderBallWaypoint* closestWp = nullptr; + CVector3f worldPoint = CVector3f::Zero(); + CVector3f useInterpDeltaBetweenPoints = interpDeltaBetweenPoints; + CVector3f useDeltaBetweenPoints = deltaBetweenPoints; + waypoint->GetClosestPointAlongWaypoints(mgr, ballCenter, 2.1f, &closestWp, worldPoint, + useDeltaBetweenPoints, 0.8f, + useInterpDeltaBetweenPoints); + + if (closestWp != nullptr) { + const CVector3f ballToPoint = worldPoint - ballCenter; + const float ballToPointMag = ballToPoint.Magnitude(); + + if (ballToPointMag < minDist) { + minDist = ballToPointMag; + closestPoint = worldPoint; + interpDeltaBetweenPoints = useInterpDeltaBetweenPoints; + deltaBetweenPoints = useDeltaBetweenPoints; + distance = ballToPointMag; + normal = (-1.f / minDist) * ballToPoint; + isSurface = false; + ret = true; + } + } + } + } + + return ret; +} + +void CMorphBall::SetSpiderBallSwingingState(const bool state) { + if (x18be_spiderBallSwinging != state) { + ResetSpiderBallSwingControllerMovementTimer(); + x18bf_spiderSwingInAir = true; + } + + x18be_spiderBallSwinging = state; +} + +float CMorphBall::GetSpiderBallControllerMovement(const CFinalInput& input) const { + if (!IsMovementAllowed()) { + return 0.f; + } + + const float forward = ControlMapper::GetAnalogInput(ControlMapper::kC_Forward, input) - + ControlMapper::GetAnalogInput(ControlMapper::kC_Backward, input); + const float turn = ControlMapper::GetAnalogInput(ControlMapper::kC_TurnRight, input) - + ControlMapper::GetAnalogInput(ControlMapper::kC_TurnLeft, input); + const double angleTemp = atan2(forward, turn); + const float angle = (180.f / M_PIF) * static_cast< float >(angleTemp); + const float hyp = CMath::SqrtF(forward * forward + turn * turn); + + if (angle > -35.f && angle < 125.f) { + return hyp; + } + + if (angle < -55.f || angle > 145.f) { + return -hyp; + } + + return 0.f; +} + +void CMorphBall::ResetSpiderBallSwingControllerMovementTimer() { + x1904_swingControlDir = 0.f; + x1908_swingControlTime = 0.f; +} + +void CMorphBall::UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt) { + if (CMath::AbsF(movement) < 0.05f) { + ResetSpiderBallSwingControllerMovementTimer(); + } else { + if (x1904_swingControlDir != CMath::Sign(movement)) { + ResetSpiderBallSwingControllerMovementTimer(); + x1904_swingControlDir = CMath::Sign(movement); + } else { + x1908_swingControlTime += dt; + } + } +} + +float CMorphBall::GetSpiderBallSwingControllerMovementScalar() const { + if (x1908_swingControlTime < 1.2f) { + return 1.f; + } + + return rstl::max_val(0.f, (2.4f - x1908_swingControlTime) / 1.2f); +} + +void CMorphBall::CreateSpiderBallParticles(const CVector3f& ballPos, const CVector3f& trackPoint) { + x19d4_spiderBallMagnetEffectGen->SetParticleEmission(true); + + CVector3f ballToTrack = trackPoint - ballPos; + const float ballToTrackMag = ballToTrack.Magnitude(); + const int subCount = static_cast< int >(ballToTrackMag / 0.2f + 1.f); + const float scale = 1.f / static_cast< float >(subCount); + ballToTrack *= scale; + int count = static_cast< int >(8.f * (ballToTrackMag / 2.1f)); + + while (count >= 0) { + CVector3f translation = ballPos; + for (int i = 0; i < subCount; ++i) { + x19d4_spiderBallMagnetEffectGen->SetTranslation(translation); + x19d4_spiderBallMagnetEffectGen->ForceParticleCreation(1); + translation += ballToTrack; + } + --count; + } + + x19d4_spiderBallMagnetEffectGen->SetParticleEmission(false); +} + +void CMorphBall::ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt) { + x1c_controlForce = CVector3f::Zero(); + x10_boostControlForce = CVector3f::Zero(); + + if (!IsMovementAllowed()) { + return; + } + + float spiderPullThreshold = gkSpiderBallControllerActivationPercentage / 100.f; + const float spiderPull = ControlMapper::GetAnalogInput(ControlMapper::kC_SpiderBall, input); + x188c_spiderPullMovement = spiderPull >= spiderPullThreshold ? 1.f : 0.f; + + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_SpiderBall) && + x188c_spiderPullMovement != 0.f && !x191c_damageTimer) { + if (x187c_spiderBallState != kSBS_Active) { + x18bd_touchingSpider = false; + x187c_spiderBallState = kSBS_Active; + x189c_spiderInterpBetweenPoints = x0_player.GetTransform().GetColumn(kDZ); + x18a8_spiderBetweenPoints = x189c_spiderInterpBetweenPoints; + } + + UpdateSpiderBall(input, mgr, dt); + + if (!x18bc_spiderNearby) { + x187c_spiderBallState = kSBS_Inactive; + ResetSpiderBallForces(); + } + } else { + x187c_spiderBallState = kSBS_Inactive; + ResetSpiderBallForces(); + } + + if (x187c_spiderBallState == kSBS_Active) { + return; + } + + const float forward = ForwardInput(input); + const float turn = -BallTurnInput(input); + const float maxSpeed = ComputeMaxSpeed(); + const float currentSpeed = x0_player.GetVelocityWR().Magnitude(); + float forwardScale = 0.f; + float turnScale = 0.f; + float speedScale; + float forwardAcc = 0.f; + float turnAcc = 0.f; + const CTransform4f controlXf = + CTransform4f::LookAt(CVector3f::Zero(), x0_player.x54c_controlDirFlat, CVector3f::Up()); + const CVector3f controlFrameVel = controlXf.TransposeRotate(x0_player.GetVelocityWR()); + + if (CMath::AbsF(turn) > 0.1f) { + const float controlTurn = turn * maxSpeed; + const float controlTurnDelta = controlTurn - controlFrameVel.GetX(); + turnScale = CMath::Clamp(0.f, CMath::AbsF(controlTurnDelta) / maxSpeed, 1.f); + float maxAccel; + + if (CMath::Sign(controlFrameVel.GetX()) != CMath::Sign(controlTurn) && + currentSpeed > 0.8f * maxSpeed) { + maxAccel = gpTweakBall->GetBallForwardBrakingAcceleration(x0_player.GetSurfaceRestraint()); + } else { + maxAccel = gpTweakBall->GetMaxBallTranslationAcceleration(x0_player.GetSurfaceRestraint()); + } + + if (controlTurnDelta < 0.f) { + turnAcc = -maxAccel * turnScale; + } else { + turnAcc = maxAccel * turnScale; + } + } + + if (CMath::AbsF(forward) > 0.1f) { + const float controlForward = forward * maxSpeed; + const float controlForwardDelta = controlForward - controlFrameVel.GetY(); + forwardScale = CMath::Clamp(0.f, CMath::AbsF(controlForwardDelta) / maxSpeed, 1.f); + float maxAccel; + + if (CMath::Sign(controlFrameVel.GetY()) != CMath::Sign(controlForward) && + currentSpeed > 0.8f * maxSpeed) { + maxAccel = gpTweakBall->GetBallForwardBrakingAcceleration(x0_player.GetSurfaceRestraint()); + } else { + maxAccel = gpTweakBall->GetMaxBallTranslationAcceleration(x0_player.GetSurfaceRestraint()); + } + + if (controlForwardDelta < 0.f) { + forwardAcc = -maxAccel * forwardScale; + } else { + forwardAcc = maxAccel * forwardScale; + } + } + + if (0.f != forwardAcc || 0.f != turnAcc || x1de4_24_inBoost || GetIsInHalfPipeMode()) { + const CVector3f forwardForce = controlXf.Rotate(CVector3f(0.f, forwardAcc, 0.f)); + const CVector3f turnForce = controlXf.Rotate(CVector3f(turnAcc, 0.f, 0.f)); + CVector3f controlForce = turnForce + forwardForce; + x1c_controlForce = controlForce; + + if (x1de4_24_inBoost && !GetIsInHalfPipeMode()) { + const CVector3f controlLocalForce = x1924_surfaceToWorld.TransposeRotate(controlForce); + CVector3f boostControlForce; + boostControlForce = controlLocalForce; + boostControlForce.SetY(0.f); + boostControlForce.SetZ(0.f); + controlForce = x1924_surfaceToWorld.Rotate(boostControlForce); + } + + if (GetIsInHalfPipeMode()) { + if (controlForce.Magnitude() > FLT_EPSILON) { + if (GetIsInHalfPipeModeInAir() && currentSpeed <= 15.f) { + const CVector3f halfPipeCol = x1924_surfaceToWorld.GetColumn(kDZ); + const float halfPipeDot = CVector3f::Dot(controlForce, halfPipeCol); + if (halfPipeDot / controlForce.Magnitude() < -0.85f) { + DisableHalfPipeStatus(); + x1e00_disableControlCooldown = 0.2f; + + const float impulseMag = -7.5f * x0_player.GetMass(); + x0_player.ApplyImpulseWR(impulseMag * halfPipeCol, CAxisAngle::Identity()); + } + } + + if (GetIsInHalfPipeMode()) { + const CVector3f halfPipeCol = x1924_surfaceToWorld.GetColumn(kDZ); + const float halfPipeDot = CVector3f::Dot(controlForce, halfPipeCol); + controlForce -= halfPipeDot * halfPipeCol; + + CVector3f controlLocalForce = x1924_surfaceToWorld.TransposeRotate(controlForce); + CVector3f halfPipeForce = controlLocalForce; + const float halfPipeXScale = 0.6f; + const float halfPipeYScale = 1.4f * (x1de4_24_inBoost ? 0.f : 0.35f); + halfPipeForce[kDX] *= halfPipeXScale; + halfPipeForce[kDY] *= halfPipeYScale; + controlForce = x1924_surfaceToWorld.Rotate(halfPipeForce); + + if (maxSpeed > 95.f) { + x0_player.SetVelocityWR(0.99f * x0_player.GetVelocityWR()); + } + } + } + } + + if (GetTouchedHalfPipeRecently()) { + const float halfPipeDot = CVector3f::Dot(x1e08_prevHalfPipeNormal, x1e14_halfPipeNormal); + if (halfPipeDot < 0.99f && halfPipeDot > 0.5f) { + const CVector3f halfPipeRampAxis = + CVector3f::Cross(x1e08_prevHalfPipeNormal, x1e14_halfPipeNormal).AsNormalized(); + CVector3f newVel = x0_player.GetVelocityWR(); + const float rampVelDot = CVector3f::Dot(halfPipeRampAxis, newVel); + newVel -= 0.15f * (rampVelDot * halfPipeRampAxis); + x0_player.SetVelocityWR(newVel); + } + } + + const float speedThreshold = 0.75f * maxSpeed; + if (currentSpeed >= speedThreshold) { + CVector3f currentVel = x0_player.GetVelocityWR(); + const float velDot = CVector3f::Dot(controlForce, currentVel.AsNormalized()); + if (velDot > 0.f) { + speedScale = (currentSpeed - speedThreshold) / (maxSpeed - speedThreshold); + speedScale = CMath::Clamp(0.f, speedScale, 1.f); + const CVector3f currentVelNorm = currentVel.AsNormalized(); + const float scaledVelDot = speedScale * velDot; + controlForce -= scaledVelDot * currentVelNorm; + } + } + + x10_boostControlForce = controlForce; + x0_player.ApplyForceWR(controlForce, CAxisAngle::Identity()); + } + + ComputeLiftForces(x1c_controlForce, x0_player.GetVelocityWR(), mgr); +} + +CTransform4f CMorphBall::GetSwooshToWorld() const { + const CRelAngle tiltAngle(x30_ballTiltAngle); + const CVector3f ballTranslation(0.f, 0.f, GetBallRadius()); + const CVector3f& translation = x0_player.GetTranslation(); + const CVector3f ballPos = translation + ballTranslation; + + return CTransform4f(CTransform4f::Translate(ballPos) * x1924_surfaceToWorld.GetRotation() * + CTransform4f::RotateY(tiltAngle)); +} + +CTransform4f CMorphBall::GetBallToWorld() const { + const CTransform4f& playerXf = x0_player.GetTransform(); + const CVector3f ballTranslation(0.f, 0.f, GetBallRadius()); + const CVector3f& translation = x0_player.GetTranslation(); + const CVector3f ballPos = translation + ballTranslation; + + return CTransform4f(CTransform4f::Translate(ballPos) * playerXf.GetRotation()); +} + +CTransform4f CMorphBall::CalculateSurfaceToWorld(const CVector3f& trackNormal, + const CVector3f& trackPoint, + const CVector3f& ballDir) const { + if (ballDir.CanBeNormalized()) { + const CVector3f forward = ballDir.AsNormalized(); + CVector3f right = CVector3f::Cross(ballDir, trackNormal); + if (right.CanBeNormalized()) { + right.Normalize(); + const float rightY = right.GetY(); + const float forwardX = forward.GetX(); + const float rightZ = right.GetZ(); + const float forwardY = forward.GetY(); + const float rightX = right.GetX(); + const float forwardZ = forward.GetZ(); + const float upZ = rightX * forwardY - forwardX * rightY; + const float upX = rightY * forwardZ - forwardY * rightZ; + const float upY = rightZ * forwardX - forwardZ * rightX; + const CVector3f upNorm = CVector3f(upX, upY, upZ).AsNormalized(); + + return CTransform4f(right, forward, upNorm, trackPoint + CVector3f(0.f, 0.f, 0.f)); + } + } + + return CTransform4f::Identity(); +} + +bool CMorphBall::CalculateBallContactInfo(CVector3f& normal, CVector3f& point) const { + if (0 < x74_collisionInfos.GetCount()) { + normal = x74_collisionInfos[0].GetNormalLeft(); + point = x74_collisionInfos[0].GetPoint(); + return true; + } + + return false; +} + +float CMorphBall::BallTurnInput(const CFinalInput& input) const { + if (!IsMovementAllowed()) { + return 0.f; + } + + const float turnLeftInput = ControlMapper::GetAnalogInput(ControlMapper::kC_TurnLeft, input); + const float turnRightInput = ControlMapper::GetAnalogInput(ControlMapper::kC_TurnRight, input); + + return turnLeftInput - turnRightInput; +} + +void CMorphBall::UpdateBallDynamics(CStateManager& mgr, float dt) { + CVector3f ballContactNormal(0.f, 0.f, 0.f); + CVector3f ballContactPoint(0.f, 0.f, 0.f); + CTransform4f ballToWorldXf(CTransform4f::Identity()); + + x0_player.SetAngularVelocityWR(CAxisAngle(x0_player.GetAngularVelocityWR().GetVector() * 0.95f)); + + const CMaterialFilter ballCloseFilter = CMaterialFilter::MakeInclude(CMaterialList(kMT_Solid)); + x1df8_27_ballCloseToCollision = + BallCloseToCollision(mgr, kSpiderBallCollisionRadius, ballCloseFilter); + + UpdateHalfPipeStatus(mgr, dt); + + x1e00_disableControlCooldown -= dt; + x1e00_disableControlCooldown = rstl::max_val(x1e00_disableControlCooldown, 0.f); + x191c_damageTimer -= dt; + x191c_damageTimer = rstl::max_val(x191c_damageTimer, 0.f); + + if (x187c_spiderBallState == kSBS_Active) { + x1924_surfaceToWorld = CalculateSurfaceToWorld( + x1880_playerToSpiderNormal, x1890_spiderTrackPoint, x189c_spiderInterpBetweenPoints); + x2c_tireLeanAngle = 0.f; + if (!x28_tireMode) { + SwitchToTire(); + } + x1c2c_tireInterpolating = true; + x1c28_tireInterpSpeed = -1.f; + UpdateMarbleDynamics(mgr, dt, x1890_spiderTrackPoint); + } else { + if (x0_player.GetSurfaceRestraint() != CPlayer::kSR_Air) { + if (CalculateBallContactInfo(ballContactNormal, ballContactPoint)) { + x1924_surfaceToWorld = + CalculateSurfaceToWorld(ballContactNormal, ballContactPoint, x0_player.x500_lookDir); + + const float ballSpeed = x0_player.GetVelocityWR().Magnitude(); + if (ballSpeed < gpTweakBall->GetTireToMarbleThresholdSpeed() && x28_tireMode) { + SwitchToMarble(); + } + + if (UpdateMarbleDynamics(mgr, dt, ballContactPoint) && + ballSpeed >= gpTweakBall->GetMarbleToTireThresholdSpeed() && !x28_tireMode) { + SwitchToTire(); + } + + if (x28_tireMode) { + float maxAccel = + gpTweakBall->GetMaxBallTranslationAcceleration(x0_player.GetSurfaceRestraint()); + float accel = x0_player.GetTransform().TransposeRotate(x0_player.GetForceWR()).GetX(); + x2c_tireLeanAngle = (accel / maxAccel) * gpTweakBall->GetMaxLeanAngle() * + gpTweakBall->GetForceToLeanGain(); + x2c_tireLeanAngle = CMath::Limit(x2c_tireLeanAngle, gpTweakBall->GetMaxLeanAngle()); + + if ((x0_player.GetTransform().Get00() * x1924_surfaceToWorld.Get00() + + x0_player.GetTransform().Get10() * x1924_surfaceToWorld.Get10() + + x0_player.GetTransform().Get20() * x1924_surfaceToWorld.Get20()) < 0.f) { + x2c_tireLeanAngle = -x2c_tireLeanAngle; + } + } + } + } else { + x2c_tireLeanAngle = 0.f; + } + } + + float tiltAngleDelta = CMath::WrapPi(x2c_tireLeanAngle - x30_ballTiltAngle); + const float leanGain = gpTweakBall->GetLeanTrackingGain(); + const float leanTracking = + gpTweakBall->GetMaxLeanAngle() * CMath::AbsF(tiltAngleDelta) * leanGain; + if (tiltAngleDelta > 0.05f) { + x30_ballTiltAngle += leanTracking * dt; + } else if (tiltAngleDelta < -0.05f) { + x30_ballTiltAngle -= leanTracking * dt; + } else { + x30_ballTiltAngle = x2c_tireLeanAngle; + } + + if (x187c_spiderBallState != kSBS_Active) { + ApplyFriction(CalculateSurfaceFriction()); + } else { + DampLinearAndAngularVelocities(x18b4_linVelDamp, x18b8_angVelDamp); + } + + if (x187c_spiderBallState != kSBS_Active) { + ApplyGravity(mgr); + } + + x74_collisionInfos.Clear(); + x1c3c_ballOrientAvg.AddValue(CQuaternion::FromMatrix(GetBallToWorld())); + x1c90_ballPosAvg.AddValue(GetBallToWorld().GetTranslation()); +} + +void CMorphBall::SwitchToMarble() { + CVector3f lookDir = x0_player.x500_lookDir; + CQuaternion tiltQ = CQuaternion::AxisAngle( + CUnitVector3f(x0_player.GetTransform().TransposeRotate(lookDir)), x30_ballTiltAngle); + x0_player.SetTransform(x0_player.GetTransform() * tiltQ.BuildTransform4f()); + x28_tireMode = false; + x1c2c_tireInterpolating = true; + x1c28_tireInterpSpeed = -1.f; +} + +void CMorphBall::SwitchToTire() { + x28_tireMode = true; + x1c2c_tireInterpolating = true; + x30_ballTiltAngle = 0.f; + x1c28_tireInterpSpeed = 1.f; +} + +void CMorphBall::Update(float dt, CStateManager& mgr) { + if (x187c_spiderBallState == kSBS_Active) { + CVector3f ballPos = GetBallToWorld().GetTranslation(); + CreateSpiderBallParticles(ballPos, x1890_spiderTrackPoint); + } + + if (x0_player.x9f4_deathTime <= 0.f) { + UpdateEffects(dt, mgr); + } + + if (x1e44_damageEffect > 0.f) { + x1e44_damageEffect -= x1e48_damageEffectDecaySpeed * dt; + if (x1e44_damageEffect <= 0.f) { + x1e44_damageEffect = 0.f; + x1e48_damageEffectDecaySpeed = 0.f; + x1e4c_damageTime = 0.f; + } else { + x1e4c_damageTime += dt; + } + } + + if (x58_ballModel.get() != nullptr) { + x58_ballModel->AdvanceAnimation(dt, mgr, kInvalidAreaId, true); + } + + if (x1c2c_tireInterpolating) { + x1c20_tireFactor += x1c28_tireInterpSpeed * dt; + if (x1c20_tireFactor < 0.f) { + x1c2c_tireInterpolating = false; + x1c20_tireFactor = 0.f; + } else if (x1c20_tireFactor > x1c24_maxTireFactor) { + x1c2c_tireInterpolating = false; + x1c20_tireFactor = x1c24_maxTireFactor; + } + } + + if (x1c1c_rainSplashGen.get() != nullptr) { + x1c1c_rainSplashGen->Update(dt, mgr); + } + + UpdateMorphBallSound(dt); +} + +void CMorphBall::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + switch (msg) { + case kSM_Registered: + if (x19d0_ballInnerGlowGen.get() != nullptr && x19d0_ballInnerGlowGen->SystemHasLight()) { + x1c10_ballInnerGlowLight = mgr.AllocateUniqueId(); + const int sourceId = x1988_ballInnerGlow.GetTag().GetId(); + mgr.AddObject(rs_new CGameLight(x1c10_ballInnerGlowLight, kInvalidAreaId, false, + rstl::string_l("BallLight"), GetBallToWorld(), + x0_player.GetUniqueId(), x19d0_ballInnerGlowGen->GetLight(), + sourceId, 0, 0.f)); + } + break; + case kSM_Deleted: + DeleteLight(mgr); + break; + default: + break; + } +} + +void CMorphBall::DeleteLight(CStateManager& mgr) { + if (x1c10_ballInnerGlowLight == kInvalidUniqueId) { + return; + } + + mgr.DeleteObjectRequest(x1c10_ballInnerGlowLight); + x1c10_ballInnerGlowLight = kInvalidUniqueId; +} + +void CMorphBall::SetBallLightActive(CStateManager& mgr, bool active) { + if (x1c10_ballInnerGlowLight == kInvalidUniqueId) { + return; + } + + if (CGameLight* light = TCastToPtr< CGameLight >(mgr.ObjectById(x1c10_ballInnerGlowLight))) { + light->SetActive(active); + } +} + +void CMorphBall::EnterMorphBallState(CStateManager& mgr) { + x1c20_tireFactor = 0.f; + UpdateEffects(0.f, mgr); + x187c_spiderBallState = kSBS_Inactive; + x58_ballModel->AnimationData()->SetAnimation(CAnimPlaybackParms(0, -1, 1.f, true), false); + x1e20_ballAnimIdx = 0; + StopParticleWakes(); + x1c30_boostOverLightFactor = 0.f; + x1c34_boostLightFactor = 0.f; + x1c38_spiderLightFactor = 0.f; + DisableHalfPipeStatus(); + x30_ballTiltAngle = 0.f; + x2c_tireLeanAngle = 0.f; +} + +void CMorphBall::LeaveMorphBallState(CStateManager&) { + LeaveBoosting(); + CancelBoosting(); + CSfxManager::SfxStop(x1e24_boostSfxHandle); + StopParticleWakes(); +} + +void CMorphBall::StopParticleWakes() { + x19cc_wallSparkGen->SetParticleEmission(false); + x1bc8_wakeEffectGens[7]->SetParticleEmission(false); + + if (x1c0c_wakeEffectIdx != -1) { + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->SetParticleEmission(false); + } +} + +void CMorphBall::UpdateEffects(float dt, CStateManager& mgr) { + const CTransform4f swooshToWorld = GetSwooshToWorld(); + + const CVector3f slowBlueOffset1 = swooshToWorld.Rotate(CVector3f(0.1f, 0.f, 0.f)); + x19b8_slowBlueTailSwooshGen->SetTranslation(swooshToWorld.GetTranslation() + slowBlueOffset1); + x19b8_slowBlueTailSwooshGen->SetOrientation(swooshToWorld.GetRotation()); + x19b8_slowBlueTailSwooshGen->SetWarmUp(); + x19b8_slowBlueTailSwooshGen->Update(1.0 / 60.0); + + const CVector3f slowBlueOffset2 = swooshToWorld.Rotate(CVector3f(-0.1f, 0.f, 0.f)); + x19bc_slowBlueTailSwooshGen2->SetTranslation(swooshToWorld.GetTranslation() + slowBlueOffset2); + x19bc_slowBlueTailSwooshGen2->SetOrientation(swooshToWorld.GetRotation()); + x19bc_slowBlueTailSwooshGen2->SetWarmUp(); + x19bc_slowBlueTailSwooshGen2->Update(1.0 / 60.0); + + const CVector3f slowBlueOffset3 = swooshToWorld.Rotate(CVector3f(0.f, 0.f, 0.65f)); + x19c0_slowBlueTailSwoosh2Gen->SetTranslation(swooshToWorld.GetTranslation() + slowBlueOffset3); + x19c0_slowBlueTailSwoosh2Gen->SetOrientation(swooshToWorld.GetRotation()); + x19c0_slowBlueTailSwoosh2Gen->SetWarmUp(); + x19c0_slowBlueTailSwoosh2Gen->Update(1.0 / 60.0); + + const CVector3f slowBlueOffset4 = swooshToWorld.Rotate(CVector3f(0.f, 0.f, -0.65f)); + x19c4_slowBlueTailSwoosh2Gen2->SetTranslation(swooshToWorld.GetTranslation() + slowBlueOffset4); + x19c4_slowBlueTailSwoosh2Gen2->SetOrientation(swooshToWorld.GetRotation()); + x19c4_slowBlueTailSwoosh2Gen2->SetWarmUp(); + x19c4_slowBlueTailSwoosh2Gen2->Update(1.0 / 60.0); + + x19c8_jaggyTrailGen->SetTranslation(swooshToWorld.GetTranslation()); + x19c8_jaggyTrailGen->SetOrientation(swooshToWorld.GetRotation()); + x19c8_jaggyTrailGen->SetWarmUp(); + x19c8_jaggyTrailGen->Update(1.0 / 60.0); + + x19cc_wallSparkGen->Update(dt); + x1bc8_wakeEffectGens[7]->Update(dt); + + bool emitRainWake = false; + bool hasRain = false; + bool useRainWake = false; + if (x0_player.GetPlayerMovementState() == NPlayer::kMS_OnGround && + mgr.GetWorld()->GetNeededEnvFx() == kEFX_Rain) { + useRainWake = true; + } + if (useRainWake && mgr.GetEnvFxManager()->GetRainMagnitude() > 0.f) { + hasRain = true; + } + if (hasRain && mgr.GetEnvFxManager()->IsSplashActive()) { + emitRainWake = true; + } + + static_cast< CParticleGen* >(x1bc8_wakeEffectGens[7].get())->SetParticleEmission(emitRainWake); + + const float flatMoveSpeed = x0_player.x4fc_flatMoveSpeed; + const float ballMaxVelocity = x0_player.GetBallMaxVelocity(); + const float rainDensity = 2.f * mgr.GetEnvFxManager()->GetRainMagnitude(); + const float rainGenRate = rainDensity * flatMoveSpeed / ballMaxVelocity; + x1bc8_wakeEffectGens[7]->SetGeneratorRate(rstl::min_val(rainGenRate, 1.f)); + + x1bc8_wakeEffectGens[7]->SetTranslation(x0_player.GetTranslation()); + if (emitRainWake) { + const CTransform4f rainWakeXf = + CTransform4f::LookAt(x0_player.GetTranslation() + x0_player.GetMovementDirection(), + x0_player.GetTranslation(), CVector3f::Up()); + x1bc8_wakeEffectGens[7]->SetOrientation(rainWakeXf); + } + + if (x1c0c_wakeEffectIdx != -1) { + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->Update(dt); + } + + if (static_cast< int >(x1e38_wallSparkFrameCountdown) > 0) { + x1e38_wallSparkFrameCountdown -= 1; + if (static_cast< int >(x1e38_wallSparkFrameCountdown) <= 0) { + x19cc_wallSparkGen->SetParticleEmission(false); + } + } + + x19d0_ballInnerGlowGen->SetGlobalTranslation(swooshToWorld.GetTranslation()); + x19d0_ballInnerGlowGen->Update(dt); + + if (x1de8_boostChargeTime == 0.f && x1df4_boostDrainTime == 0.f) { + const CColor clear(0); + x19d8_boostBallGlowGen->SetModulationColor(clear); + } else { + x19d8_boostBallGlowGen->SetGlobalTranslation(swooshToWorld.GetTranslation()); + + float t; + if (x1df4_boostDrainTime == 0.f) { + t = x1de8_boostChargeTime / gpTweakBall->GetBoostBallMaxChargeTime(); + } else { + t = 1.f - x1df4_boostDrainTime / gpTweakBall->GetBoostBallDrainTime(); + } + + CElementGen* boostBallGlowGen = x19d8_boostBallGlowGen.get(); + boostBallGlowGen->SetModulationColor( + CColor::Lerp(CColor(0.f, 0.f, 0.f, 1.f), CColor(1.f, 1.f, 0.4f, 1.f), t)); + x19d8_boostBallGlowGen->Update(dt); + } + + x19d4_spiderBallMagnetEffectGen->Update(dt); + + x1c30_boostOverLightFactor -= 0.03f; + x1c30_boostOverLightFactor = rstl::max_val(0.f, x1c30_boostOverLightFactor); + if (x1c30_boostOverLightFactor == 0.f) { + x1c34_boostLightFactor -= 0.04f; + x1c34_boostLightFactor = rstl::max_val(0.f, x1c34_boostLightFactor); + } + + if (x1de4_24_inBoost) { + x1c30_boostOverLightFactor = 1.f; + x1c34_boostLightFactor = 1.f; + } else { + x1c34_boostLightFactor = rstl::max_val( + x1c34_boostLightFactor, x1de8_boostChargeTime / gpTweakBall->GetBoostBallMaxChargeTime()); + x1c34_boostLightFactor = rstl::min_val(1.f, x1c34_boostLightFactor); + } + + UpdateMorphBallTransitionFlash(dt); + UpdateIceBreakEffect(dt); + + if (x1c10_ballInnerGlowLight != kInvalidUniqueId) { + if (CGameLight* ballLight = + TCastToPtr< CGameLight >(mgr.ObjectById(x1c10_ballInnerGlowLight))) { + const float ballRadius = GetBallRadius(); + ballLight->SetTranslation(swooshToWorld.GetTranslation() + CVector3f(0.f, 0.f, ballRadius)); + + rstl::optional_object< CLight > light; + if (IsMorphBallTransitionFlashValid() && + x19dc_morphBallTransitionFlashGen->SystemHasLight()) { + light = x19dc_morphBallTransitionFlashGen->GetLight(); + } else if (x19d0_ballInnerGlowGen.get() != nullptr && + x19d0_ballInnerGlowGen->SystemHasLight()) { + light = x19d0_ballInnerGlowGen->GetLight(); + } + + if (light.valid()) { + CLight lightCopy(*light); + const CColor& lightColor = lightCopy.GetColor(); + const uchar* color = lbl_803CEB78 + 3 * x8_ballGlowColorIdx; + const CColor modColor(color[0], color[1], color[2], 0xff); + lightCopy.SetColor(CColor::Modulate(lightColor, modColor)); + + if (x0_player.GetMorphballTransitionState() == CPlayer::kMS_Unmorphing) { + float t = + x0_player.x578_morphDuration == 0.f + ? 0.f + : CMath::Clamp(0.f, x0_player.x574_morphTime / x0_player.x578_morphDuration, 1.f); + lightCopy.SetColor(CColor::Lerp(lightColor, CColor::Black(), t)); + } else if (x0_player.GetMorphballTransitionState() == CPlayer::kMS_Morphing) { + float t = + x0_player.x578_morphDuration == 0.f + ? 0.f + : CMath::Clamp(0.f, x0_player.x574_morphTime / x0_player.x578_morphDuration, 1.f); + + if (t < 0.5f) { + float fadeFactor = rstl::min_val(2.f * t, 1.f); + lightCopy.SetColor(CColor::Lerp(CColor::Black(), lightColor, fadeFactor)); + } + } else { + lightCopy.SetColor(CColor::Lerp(lightColor, CColor::White(), x1c34_boostLightFactor)); + } + + ballLight->SetLight(lightCopy); + } + } + } + + if (x187c_spiderBallState == kSBS_Active) { + AddSpiderBallElectricalEffect(); + AddSpiderBallElectricalEffect(); + AddSpiderBallElectricalEffect(); + AddSpiderBallElectricalEffect(); + AddSpiderBallElectricalEffect(); + + x1c38_spiderLightFactor = rstl::min_val(1.f, x1c38_spiderLightFactor + 0.25f); + } else { + x1c38_spiderLightFactor = rstl::max_val(0.f, x1c38_spiderLightFactor - 0.15f); + } + + UpdateSpiderBallElectricalEffects(); +} + +void CMorphBall::ComputeBoostBallMovement(const CFinalInput& input, const CStateManager& mgr, + float dt) { + if (!IsMovementAllowed()) { + return; + } + if (!mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_BoostBall)) { + return; + } + + if (!x1de4_25_boostEnabled) { + CancelBoosting(); + LeaveBoosting(); + return; + } + + if (!x1de4_24_inBoost) { + x1dec_timeNotInBoost += dt; + + if (ControlMapper::GetDigitalInput(ControlMapper::kC_JumpOrBoost, input) && + x187c_spiderBallState != kSBS_Active) { + if (x1e20_ballAnimIdx == 0) { + CAnimPlaybackParms parms(1, -1, 1.f, true); + x58_ballModel->AnimationData()->SetAnimation(parms, false); + x1e20_ballAnimIdx = 1; + x1e24_boostSfxHandle = CSfxManager::SfxStart( + 0x5c5, 0x7f, 0x40, true, CSfxManager::kMedPriority, true, CSfxManager::kAllAreas); + } + + x1de8_boostChargeTime += dt; + if (x1de8_boostChargeTime > gpTweakBall->GetBoostBallMaxChargeTime()) { + x1de8_boostChargeTime = gpTweakBall->GetBoostBallMaxChargeTime(); + } + } else { + CVector3f translation; + + if (x1e20_ballAnimIdx == 1) { + CAnimPlaybackParms parms(0, -1, 1.f, true); + x58_ballModel->AnimationData()->SetAnimation(parms, false); + x1e20_ballAnimIdx = 0; + CSfxManager::RemoveEmitter(x1e24_boostSfxHandle); + + if (x1de8_boostChargeTime >= gpTweakBall->GetBoostBallMinChargeTime()) { + translation = x0_player.GetTranslation(); + CSfxManager::AddEmitter(0x5c4, translation, CVector3f::Zero(), true, false, 0xb4, + CSfxManager::kAllAreas); + } + } + + if (x1de8_boostChargeTime >= gpTweakBall->GetBoostBallMinChargeTime()) { + if (GetBallBoostState() == kBBS_BoostAvailable) { + if (GetIsInHalfPipeMode() || x1df8_27_ballCloseToCollision) { + EnterBoosting(const_cast< CStateManager& >(mgr)); + } else { + CVector3f boostVec = 10000.f * -x1924_surfaceToWorld.GetColumn(kDY); + x0_player.ApplyImpulseWR(CVector3f::Zero(), CAxisAngle::FromVector(boostVec)); + CancelBoosting(); + } + } else if (GetBallBoostState() == kBBS_BoostDisabled) { + x0_player.SetTransform(CTransform4f::LookAt( + x0_player.GetTranslation(), + x0_player.GetTranslation() + GetBallToWorld().GetColumn(kDY), CVector3f::Up())); + + CVector3f boostVec = 10000.f * -x0_player.GetTransform().GetColumn(kDX); + x0_player.ApplyImpulseWR(CVector3f::Zero(), CAxisAngle::FromVector(boostVec)); + CancelBoosting(); + } + } else if (x1de8_boostChargeTime > 0.f) { + CancelBoosting(); + } + } + } else { + x1df4_boostDrainTime += dt; + if (x1df4_boostDrainTime > gpTweakBall->GetBoostBallDrainTime()) { + LeaveBoosting(); + } + + if (!GetIsInHalfPipeMode() && !x1df8_27_ballCloseToCollision) { + if (x1df4_boostDrainTime / gpTweakBall->GetBoostBallDrainTime() < 0.3f) { + DampLinearAndAngularVelocities(0.5f, 0.01f); + } + + LeaveBoosting(); + } + } +} + +void CMorphBall::EnterBoosting(CStateManager& mgr) { + x1de4_24_inBoost = true; + + const float boostChargeTime = x1de8_boostChargeTime; + float incSpeed = 0.f; + if (boostChargeTime <= gpTweakBall->GetBoostBallChargeTimeTable(0)) { + incSpeed = gpTweakBall->GetBoostBallIncrementalSpeedTable(0); + } else if (boostChargeTime <= gpTweakBall->GetBoostBallChargeTimeTable(1)) { + incSpeed = gpTweakBall->GetBoostBallIncrementalSpeedTable(1); + } else if (boostChargeTime <= gpTweakBall->GetBoostBallChargeTimeTable(2)) { + incSpeed = gpTweakBall->GetBoostBallIncrementalSpeedTable(2); + } + + if (GetIsInHalfPipeMode()) { + const float speedMul = x0_player.GetVelocityWR().Magnitude() / 95.f; + if (speedMul > 0.3f) { + incSpeed = incSpeed - incSpeed * (speedMul - 0.3f); + } + incSpeed = rstl::max_val(0.f, incSpeed); + } + + CVector3f lookDir; + lookDir.SetX(x0_player.x500_lookDir.GetX()); + lookDir.SetY(x0_player.x500_lookDir.GetY()); + lookDir.SetZ(x0_player.x500_lookDir.GetZ()); + float lookMag2d = sqrt(lookDir.GetX() * lookDir.GetX() + lookDir.GetY() * lookDir.GetY()); + double lookAngle = atan2(lookDir.GetZ(), lookMag2d); + float vertLookAngle = CMath::Rad2Rev(lookAngle) * 360.f; + float lookMag2dZero = 0.f; + if (fabs(lookMag2d - lookMag2dZero) < 0.001f && + x0_player.GetPlayerMovementState() == NPlayer::kMS_OnGround) { + const CVector3f& velocity = x0_player.GetVelocityWR(); + const float velZ = velocity.GetZ(); + float velMag2d = sqrt(velocity.GetX() * velocity.GetX() + velocity.GetY() * velocity.GetY()); + float velMag2dZero = 0.f; + if (fabs(velMag2d - velMag2dZero) < 0.01f && CMath::AbsF(velZ) < 2.f) { + const CGameCamera& camera = mgr.GetCameraManager()->GetCurrentCamera(mgr); + lookDir.SetX(camera.GetTransform().Get01()); + lookDir.SetY(camera.GetTransform().Get11()); + lookDir.SetZ(camera.GetTransform().Get21()); + lookMag2d = sqrt(lookDir.GetX() * lookDir.GetX() + lookDir.GetY() * lookDir.GetY()); + lookAngle = atan2(lookDir.GetZ(), lookMag2d); + vertLookAngle = CMath::Rad2Rev(lookAngle) * 360.f; + } + } + + float speedMul = 1.f; + if (vertLookAngle > 40.f) { + const float speedDamp = (vertLookAngle - 40.f) / 50.f; + speedMul = 0.35f * speedDamp + (1.f - speedDamp); + } + + x0_player.ApplyImpulseWR(lookDir * (speedMul * incSpeed * x0_player.GetMass()), + CAxisAngle::Identity()); + x1df4_boostDrainTime = 0.f; + x1de8_boostChargeTime = 0.f; + + x0_player.SetTransform( + CTransform4f(x1924_surfaceToWorld.BuildMatrix3f(), x0_player.GetTranslation())); + SwitchToTire(); +} + +void CMorphBall::LeaveBoosting() { + if (x1de4_24_inBoost) { + x1dec_timeNotInBoost = 0.f; + x1de8_boostChargeTime = 0.f; + } + + x1de4_24_inBoost = false; + x1df4_boostDrainTime = 0.f; +} + +void CMorphBall::CancelBoosting() { + x1de8_boostChargeTime = 0.f; + x1df4_boostDrainTime = 0.f; + + if (x1e20_ballAnimIdx == 1) { + CAnimPlaybackParms parms(0, -1, 1.f, true); + x58_ballModel->AnimationData()->SetAnimation(parms, false); + x1e20_ballAnimIdx = 0; + CSfxManager::SfxStop(x1e24_boostSfxHandle); + } +} + +bool CMorphBall::UpdateMarbleDynamics(CStateManager&, float dt, const CVector3f& point) { + bool aligned = false; + bool continueForce = false; + const float maxAcceleration = + gpTweakBall->GetMaxBallTranslationAcceleration(x0_player.GetSurfaceRestraint()); + + if (x0_player.GetVelocityWR().Magnitude() < 3.f && + x10_boostControlForce.Magnitude() > 0.95f * maxAcceleration) { + CVector3f momentum = x0_player.GetMomentumWR(); + CVector3f localMomentum = x1924_surfaceToWorld.TransposeRotate(momentum); + CVector3f localControlForce = x1924_surfaceToWorld.TransposeRotate(x10_boostControlForce); + localMomentum.SetZ(0.f); + localControlForce.SetZ(0.f); + if (localMomentum.CanBeNormalized() && localControlForce.CanBeNormalized()) { + if (CVector3f::Dot(localMomentum.AsNormalized(), localControlForce.AsNormalized()) < -0.9f) { + continueForce = true; + } + } + } + + if (!continueForce) { + const CVector3f velocity = x0_player.GetVelocityWR(); + CVector3f ballToPoint = + point - (x0_player.GetTranslation() + CVector3f(0.f, 0.f, GetBallRadius())); + + const CVector3f addVelocity = + CVector3f::Cross(x0_player.GetAngularVelocityWR().GetVector(), ballToPoint); + CVector3f slipVelocity = velocity - addVelocity; + + const float minLiftSpeed = x187c_spiderBallState == kSBS_Active ? -1.f : 0.4f; + + float liftSpeed = 0.f; + if (x1cd0_liftSpeedAvg.size() > 3) { + liftSpeed = *x1cd0_liftSpeedAvg.GetEntry(0); + liftSpeed = rstl::min_val(*x1cd0_liftSpeedAvg.GetEntry(1), liftSpeed); + liftSpeed = rstl::min_val(*x1cd0_liftSpeedAvg.GetEntry(2), liftSpeed); + } + + if (slipVelocity.MagSquared() > 1.f && liftSpeed > minLiftSpeed) { + if (slipVelocity.Magnitude() > M_PIF * 8.f) { + slipVelocity = slipVelocity.AsNormalized() * M_PIF * 8.f; + } + + CVector3f newVelocity = velocity + addVelocity; + if (newVelocity.CanBeNormalized()) { + bool useTireFactor = false; + if (x28_tireMode && x187c_spiderBallState != kSBS_Active) { + useTireFactor = true; + } + + const float tireFactor = useTireFactor ? 0.25f : 1.f; + + const CVector3f& newVelocityDir = newVelocity.AsNormalized(); + const float slipFactor = gpTweakBall->GetBallSlipFactor(x0_player.GetSurfaceRestraint()); + const float ballRadius = GetBallRadius(); + const float slipMag = slipVelocity.Magnitude(); + const float torqueScale = slipMag * -slipFactor * tireFactor * 0.5f / ballRadius; + const CVector3f torque = newVelocityDir * torqueScale; + const CVector3f ballToPointDir = ballToPoint.AsNormalized(); + x0_player.ApplyTorqueWR(CVector3f::Cross(ballToPointDir, torque)); + } + } + } else { + const float spinSpeed = 25.f / GetBallRadius(); + CVector3f rotateAxis = + CVector3f::Cross(x1924_surfaceToWorld.GetColumn(kDZ), x10_boostControlForce); + if (rotateAxis.CanBeNormalized()) { + SpinToSpeed(spinSpeed, rotateAxis.AsNormalized(), 800.f); + } + } + + const float velocityMag = x0_player.GetVelocityWR().Magnitude(); + if (velocityMag >= GetMinimumAlignmentSpeed()) { + const CVector3f playerRight = x0_player.GetTransform().GetColumn(kDX); + CVector3f surfaceRight = x1924_surfaceToWorld.GetColumn(kDX); + if (CVector3f::Dot(playerRight, surfaceRight) < 0.f) { + surfaceRight = -surfaceRight; + } + + CVector3f upVec = CVector3f::Cross(playerRight, surfaceRight); + if (upVec.CanBeNormalized()) { + if (!x28_tireMode) { + const CVector3f angularImpulseVec = x0_player.GetAngularImpulseWR().GetVector() + + gpTweakBall->GetTireness() * upVec.AsNormalized(); + x0_player.SetAngularImpulseWR(CAxisAngle::FromVector(angularImpulseVec)); + } else { + CVector3f right(1.f, 0.f, 0.f); + CVector3f localRight = GetBallToWorld().TransposeRotate(surfaceRight); + CQuaternion rotation = CQuaternion::ShortestRotationArc(right, localRight); + x0_player.RotateInOneFrameOR(rotation, dt); + } + + const float alignmentMagnitude = GetIsInHalfPipeMode() ? 0.2f : 0.05f; + if (upVec.Magnitude() < alignmentMagnitude) { + aligned = true; + } + } + } + + return aligned; +} + +void CMorphBall::ApplyFriction(float friction) { + CVector3f vel = x0_player.GetVelocityWR(); + if (friction < vel.Magnitude()) { + vel = vel.AsNormalized() * (vel.Magnitude() - friction); + } else { + vel = CVector3f::Zero(); + } + x0_player.SetVelocityWR(vel); +} + +void CMorphBall::DampLinearAndAngularVelocities(float linDamp, float angDamp) { + CVector3f vel = x0_player.GetVelocityWR(); + vel *= 1.f - linDamp; + x0_player.SetVelocityWR(vel); + + CAxisAngle angVel = x0_player.GetAngularVelocityWR(); + float damp = 1.f - angDamp; + angVel *= damp; + x0_player.SetAngularVelocityWR(angVel); +} + +float CMorphBall::GetMinimumAlignmentSpeed() const { + if (x187c_spiderBallState == kSBS_Active) { + return 0.f; + } + + return gpTweakBall->GetMinimumAlignmentSpeed(); +} + +void CMorphBall::PreRender(CStateManager& mgr, const CFrustumPlanes&) { + if (1.f == x1c34_boostLightFactor) { + return; + } + + CActorLights* lights = x0_player.ActorLights(); + lights->SetFindShadowLight(x1e44_damageEffect < 0.25f); + lights->SetShadowDynamicRangeThreshold(0.05f); + lights->SetNeedsRelight(true); + + CCollidableSphere sphere = x38_collisionSphere; + sphere.SetSphereCenter(CVector3f::Zero()); + CAABox ballAABB = sphere.CalculateAABox(GetBallToWorld()); + int areaId; + int shadowAreaId; + + areaId = x0_player.GetCurrentAreaId().Value(); + if (areaId != kInvalidAreaId.Value()) { + const CWorld* world = mgr.GetWorld(); + if (world->GetAreaAlways(TAreaId(areaId)).IsPostConstructed()) { + lights->BuildAreaLightList(mgr, world->GetAreaAlways(TAreaId(areaId)), ballAABB); + } + } + + lights->BuildDynamicLightList(mgr, ballAABB); + + if (x0_player.ActorLights()->HasShadowLight()) { + CCollidableSphere shadowSphere = x38_collisionSphere; + shadowSphere.SetSphereCenter(CVector3f::Zero()); + + shadowAreaId = x0_player.GetCurrentAreaId().Value(); + const uint lightIndex = x0_player.ActorLights()->GetShadowLightIndex(); + x1c14_worldShadow->BuildLightShadowTexture(mgr, TAreaId(shadowAreaId), lightIndex, + shadowSphere.CalculateAABox(GetBallToWorld()), false, + false); + } else { + x1c14_worldShadow->ResetBlur(); + } + + { + CColor ambientColor(lights->GetAmbientColor().GetX(), lights->GetAmbientColor().GetY(), + lights->GetAmbientColor().GetZ(), 1.f); + lights->SetAmbientColor(CColor::Lerp(ambientColor, CColor::White(), x1c34_boostLightFactor)); + *x1c18_actorLights = *lights; + + const float& lightFactor = rstl::max_val(x1c38_spiderLightFactor, x1c34_boostLightFactor); + CColor spiderAmbient(lights->GetAmbientColor().GetX(), lights->GetAmbientColor().GetY(), + lights->GetAmbientColor().GetZ(), 1.f); + x1c18_actorLights->SetAmbientColor(CColor::Lerp(spiderAmbient, CColor::White(), lightFactor)); + } + + if (x58_ballModel->AnimationData() != nullptr) { + x58_ballModel->AnimationData()->PreRender(); + } +} + +void CMorphBall::Render(const CStateManager& mgr, const CActorLights* lights) const { + CTransform4f ballToWorld = GetBallToWorld(); + if (x28_tireMode) { + const CVector3f lookDir = x0_player.x500_lookDir; + const CQuaternion tilt = + CQuaternion::AxisAngle(ballToWorld.TransposeRotate(lookDir), x30_ballTiltAngle); + ballToWorld = ballToWorld * tilt.BuildTransform4f(); + } + + const bool dying = x0_player.x9f4_deathTime > 0.f; + if (x0_player.x9f4_deathTime > 0.f) { + float deathFade = 1.f - x0_player.x9f4_deathTime / (0.2f * gkBallDeathTime); + const float alpha = CMath::Clamp(0.f, deathFade, 1.f); + const CModelData& ballModel = *x58_ballModel; + const int ballModelShader = x5c_ballModelShader; + const CModelFlags& addFlags = CModelFlags::Additive(CColor::White().WithAlphaOf(alpha)); + const CModelFlags& deathFlags = + addFlags.DepthCompareUpdate(true, false).UseShaderSet(ballModelShader); + ballModel.Render(mgr, ballToWorld, 0, deathFlags); + } + + CModelFlags ballFlags = CModelFlags::Normal(); + if (x1e44_damageEffect > 0.f) { + const float fade = 1.f - x1e44_damageEffect; + ballFlags = CModelFlags(CModelFlags::kT_One, CColor(1.f, fade, fade, 1.f)); + } + + if (x1c1c_rainSplashGen.get() != nullptr && x1c1c_rainSplashGen->IsRaining()) { + CSkinnedModel::SetPointGeneratorFunc(x1c1c_rainSplashGen.get(), &CMorphBall::PointGenerator); + } + + ballFlags = ballFlags.UseShaderSet(x5c_ballModelShader); + if (1.f != x1c34_boostLightFactor) { + if (lights->HasShadowLight()) { + x1c14_worldShadow->EnableModelProjectedShadow(ballToWorld, lights->GetShadowLightArrIndex(), + 1.f); + } + x58_ballModel->Render(mgr, ballToWorld, lights, ballFlags); + x1c14_worldShadow->DisableModelProjectedShadow(); + } else { + x58_ballModel->Render(mgr, ballToWorld, 0, ballFlags); + } + + if (x1c1c_rainSplashGen.get() != nullptr && x1c1c_rainSplashGen->IsRaining()) { + CSkinnedModel::ClearPointGeneratorFunc(); + CRainSplashGenerator* const rainSplashGen = x1c1c_rainSplashGen.get(); + rainSplashGen->Draw(CTransform4f::Translate(ballToWorld.GetTranslation())); + } + + const float speed = x0_player.GetVelocityWR().Magnitude(); + if (x1e44_damageEffect > 0.25f) { + RenderDamageEffects(mgr, ballToWorld); + } else if (x1c30_boostOverLightFactor > 0.f && !dying) { + const int count = rstl::min_val(5, static_cast< int >(speed / 2.f)); + for (int i = 0; i < count; ++i) { + const float t = static_cast< float >(i) / 5.f; + const CTransform4f xf = CTransform4f::Translate(*x1c90_ballPosAvg.GetEntry(i)) * + x1c3c_ballOrientAvg.GetEntry(i)->BuildTransform4f(); + const float alpha = (1.f - t) * x1c30_boostOverLightFactor * 0.2f; + if (x68_lowPolyBallModel.get() != nullptr) { + const CModelFlags& lowPolyFlags = CModelFlags::Additive(alpha) + .DepthCompareUpdate(true, false) + .UseShaderSet(x6c_lowPolyBallModelShader); + x68_lowPolyBallModel->Render(mgr, xf, 0, lowPolyFlags); + } + } + } + + { + const float swooshAlpha = x1c20_tireFactor / x1c24_maxTireFactor; + const uchar* swooshColor0 = lbl_803CEB24 + 3 * x8_ballGlowColorIdx; + CColor color0 = CColor(swooshColor0[0], swooshColor0[1], swooshColor0[2], 0xff); + color0.SetAlpha(swooshAlpha); + const uchar* swooshColor1 = lbl_803CEB40 + 3 * x8_ballGlowColorIdx; + CColor color1 = CColor(swooshColor1[0], swooshColor1[1], swooshColor1[2], 0xff); + color1.SetAlpha(swooshAlpha); + + float t = 0.f; + if (x1df4_boostDrainTime > 0.f) { + t = CMath::Clamp(0.f, (speed - 25.f) / 15.f, 1.f); + } + + const CColor tailColor = CColor::Lerp(color0, color1, t); + x19b8_slowBlueTailSwooshGen->SetModulationColor(tailColor); + x19b8_slowBlueTailSwooshGen->Render(); + x19bc_slowBlueTailSwooshGen2->SetModulationColor(tailColor); + x19bc_slowBlueTailSwooshGen2->Render(); + x19c0_slowBlueTailSwoosh2Gen->SetModulationColor(tailColor); + x19c0_slowBlueTailSwoosh2Gen->Render(); + x19c4_slowBlueTailSwoosh2Gen2->SetModulationColor(tailColor); + x19c4_slowBlueTailSwoosh2Gen2->Render(); + + if (x1df4_boostDrainTime > 0.f && speed > 23.f && static_cast< double >(swooshAlpha) > 0.5) { + const float jaggyAlpha = CMath::Clamp(0.f, (speed - 23.f) / 17.f, t); + const uchar* jaggyColorData = lbl_803CEB5C + 3 * x8_ballGlowColorIdx; + CColor jaggyColor = CColor(jaggyColorData[0], jaggyColorData[1], jaggyColorData[2], 0xff); + jaggyColor.SetAlpha(jaggyAlpha); + x19c8_jaggyTrailGen->SetModulationColor(jaggyColor); + x19c8_jaggyTrailGen->Render(); + } + } + + RenderSpiderBallElectricalEffects(); + + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_SpiderBall) && + x60_spiderBallGlassModel.get() != nullptr) { + const float lightFactor = rstl::max_val(x1c38_spiderLightFactor, x1c34_boostLightFactor); + const CModelFlags spiderFlags = + CModelFlags::Normal().UseShaderSet(x64_spiderBallGlassModelShader); + if (1.f != lightFactor) { + if (lights->HasShadowLight()) { + x1c14_worldShadow->EnableModelProjectedShadow(ballToWorld, lights->GetShadowLightArrIndex(), + 1.f); + } + x60_spiderBallGlassModel->Render(mgr, ballToWorld, x1c18_actorLights.get(), spiderFlags); + x1c14_worldShadow->DisableModelProjectedShadow(); + } else { + x60_spiderBallGlassModel->Render(mgr, ballToWorld, 0, spiderFlags); + } + } + + x19cc_wallSparkGen->Render(); + x1bc8_wakeEffectGens[7]->Render(); + if (x1c0c_wakeEffectIdx != -1) { + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->Render(); + } + + const uchar* glowColorData = lbl_803CEAD0 + 3 * x8_ballGlowColorIdx; + const uchar glowBlue = glowColorData[2]; + const uchar glowGreen = glowColorData[1]; + x19d0_ballInnerGlowGen->SetModulationColor(CColor(glowColorData[0], glowGreen, glowBlue, 0xff)); + if (x19d0_ballInnerGlowGen->GetNumActiveChildParticles() > 0) { + CParticleGen* particle = x19d0_ballInnerGlowGen->GetActiveChildParticle(0); + const uchar* transFlashColorData = lbl_803CEAEC + 3 * x8_ballGlowColorIdx; + const uchar transFlashBlue = transFlashColorData[2]; + const uchar transFlashGreen = transFlashColorData[1]; + particle->SetModulationColor( + CColor(transFlashColorData[0], transFlashGreen, transFlashBlue, 0xff)); + if (x19d0_ballInnerGlowGen->GetNumActiveChildParticles() > 1) { + particle = x19d0_ballInnerGlowGen->GetActiveChildParticle(1); + const uchar* auxGlowColorData = lbl_803CEB08 + 3 * x8_ballGlowColorIdx; + const uchar auxGlowBlue = auxGlowColorData[2]; + const uchar auxGlowGreen = auxGlowColorData[1]; + particle->SetModulationColor(CColor(auxGlowColorData[0], auxGlowGreen, auxGlowBlue, 0xff)); + } + } + + x19d0_ballInnerGlowGen->Render(); + x19d4_spiderBallMagnetEffectGen->Render(); + RenderEnergyDrainEffects(mgr); + if (x19d8_boostBallGlowGen->GetModulationColor().GetColor_u32() != 0) { + x19d8_boostBallGlowGen->Render(); + } + + RenderMorphBallTransitionFlash(mgr); + + if (x0_player.GetFrozenState()) { + const CModelFlags frozenFlags = CModelFlags::Normal(); + x70_frozenBallModel->Render(mgr, + CTransform4f(CMatrix3f::Identity(), ballToWorld.GetTranslation()), + lights, frozenFlags); + } + + RenderIceBreakEffect(mgr); +} + +void CMorphBall::ResetMorphBallTransitionFlash() { + x19a8_morphBallTransitionFlash.Lock(); + x19dc_morphBallTransitionFlashGen = nullptr; +} + +void CMorphBall::UpdateMorphBallTransitionFlash(float dt) { + if (x19dc_morphBallTransitionFlashGen.get() == nullptr && + x19a8_morphBallTransitionFlash.IsLocked() && x19a8_morphBallTransitionFlash.IsLoaded()) { + x19dc_morphBallTransitionFlashGen = rs_new CElementGen( + x19a8_morphBallTransitionFlash, CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x19dc_morphBallTransitionFlashGen->SetOrientation(x0_player.GetTransform().GetRotation()); + } + + if (x19dc_morphBallTransitionFlashGen.get() != nullptr) { + if (x19dc_morphBallTransitionFlashGen->IsSystemDeletable()) { + x19dc_morphBallTransitionFlashGen = nullptr; + x19a8_morphBallTransitionFlash.Unlock(); + } else { + x19dc_morphBallTransitionFlashGen->SetGlobalTranslation(GetBallToWorld().GetTranslation()); + x19dc_morphBallTransitionFlashGen->Update(dt); + } + } +} + +void CMorphBall::RenderMorphBallTransitionFlash(const CStateManager&) const { + if (x19dc_morphBallTransitionFlashGen.get() != nullptr) { + const uchar* color = lbl_803CEAEC + 3 * x8_ballGlowColorIdx; + const CColor modColor(color[0], color[1], color[2], 0xff); + x19dc_morphBallTransitionFlashGen->SetModulationColor(modColor); + x19dc_morphBallTransitionFlashGen->Render(); + } +} + +bool CMorphBall::IsMorphBallTransitionFlashValid() const { + return x19dc_morphBallTransitionFlashGen.get() != nullptr; +} + +void CMorphBall::ResetMorphBallIceBreak() { + x19b0_effect_morphBallIceBreak.Lock(); + x19e0_effect_morphBallIceBreakGen = nullptr; +} + +void CMorphBall::UpdateIceBreakEffect(float dt) { + if (x19e0_effect_morphBallIceBreakGen.get() == nullptr && + x19b0_effect_morphBallIceBreak.IsLocked() && x19b0_effect_morphBallIceBreak.IsLoaded()) { + x19e0_effect_morphBallIceBreakGen = rs_new CElementGen( + x19b0_effect_morphBallIceBreak, CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x19e0_effect_morphBallIceBreakGen->SetOrientation(x0_player.GetTransform().GetRotation()); + } + + if (x19e0_effect_morphBallIceBreakGen.get() != nullptr) { + if (x19e0_effect_morphBallIceBreakGen->IsSystemDeletable()) { + x19e0_effect_morphBallIceBreakGen = nullptr; + x19b0_effect_morphBallIceBreak.Unlock(); + } else { + x19e0_effect_morphBallIceBreakGen->SetGlobalTranslation(GetBallToWorld().GetTranslation()); + x19e0_effect_morphBallIceBreakGen->Update(dt); + } + } +} + +void CMorphBall::RenderIceBreakEffect(const CStateManager&) const { + if (x19e0_effect_morphBallIceBreakGen.get() != nullptr) { + x19e0_effect_morphBallIceBreakGen->Render(); + } +} + +void CMorphBall::RenderDamageEffects(const CStateManager&, const CTransform4f& xf) const { + CRandom16 rand(99); + const float colorComponent = 0.1f * x1e44_damageEffect; + const CColor color(0.25f * x1e44_damageEffect, colorComponent, colorComponent, 1.f); + const CModelFlags flags = CModelFlags::Additive(color).DepthCompareUpdate(true, false); + + for (int i = 0; i < 5; ++i) { + const float randX = rand.Float(); + const float randY = rand.Float(); + const float randZ = rand.Float(); + const float translateMag = x1e44_damageEffect * + CMath::FastSinR(30.f * x1e4c_damageTime + M_PIF * rand.Float()) * + 0.15f; + CTransform4f modelXf = + xf * CTransform4f::Translate( + CVector3f(randX * translateMag, randY * translateMag, randZ * translateMag)); + x68_lowPolyBallModel->FlatDraw(CModelData::kWM_Normal, modelXf, false, flags); + } +} + +void CMorphBall::UpdateHalfPipeStatus(CStateManager&, float dt) { + x1dfc_touchHalfPipeCooldown -= dt; + x1dfc_touchHalfPipeCooldown = rstl::max_val(0.f, x1dfc_touchHalfPipeCooldown); + x1e04_touchHalfPipeRecentCooldown -= dt; + x1e04_touchHalfPipeRecentCooldown = rstl::max_val(0.f, x1e04_touchHalfPipeRecentCooldown); + + if (x1dfc_touchHalfPipeCooldown > 0.f) { + const float avg = *x1cd0_liftSpeedAvg.GetAverage(); + if (avg > 25.f || (GetIsInHalfPipeMode() && avg > 4.5f)) { + SetIsInHalfPipeMode(true); + SetIsInHalfPipeModeInAir(!x1df8_27_ballCloseToCollision); + SetTouchedHalfPipeRecently(x1e04_touchHalfPipeRecentCooldown > 0.f); + if (GetIsInHalfPipeModeInAir()) { + x1e08_prevHalfPipeNormal = CVector3f::Zero(); + x1e14_halfPipeNormal = CVector3f::Zero(); + } + } else { + DisableHalfPipeStatus(); + } + } else { + DisableHalfPipeStatus(); + } + + if (GetIsInHalfPipeMode()) { + x0_player.SetCollisionAccuracyModifier(10.f); + } else { + x0_player.SetCollisionAccuracyModifier(1.f); + } +} + +bool CMorphBall::GetIsInHalfPipeMode() const { return x1df8_24_inHalfPipeMode; } + +void CMorphBall::SetIsInHalfPipeMode(bool state) { x1df8_24_inHalfPipeMode = state; } + +bool CMorphBall::GetIsInHalfPipeModeInAir() const { return x1df8_25_inHalfPipeModeInAir; } + +void CMorphBall::SetIsInHalfPipeModeInAir(bool state) { x1df8_25_inHalfPipeModeInAir = state; } + +bool CMorphBall::GetTouchedHalfPipeRecently() const { return x1df8_26_touchedHalfPipeRecently; } + +void CMorphBall::SetTouchedHalfPipeRecently(bool state) { + x1df8_26_touchedHalfPipeRecently = state; +} + +void CMorphBall::DisableHalfPipeStatus() { + SetIsInHalfPipeMode(false); + SetIsInHalfPipeModeInAir(false); + SetTouchedHalfPipeRecently(false); + x1dfc_touchHalfPipeCooldown = 0.f; + x1e00_disableControlCooldown = 0.f; + x0_player.SetCollisionAccuracyModifier(1.f); + x1e08_prevHalfPipeNormal = CVector3f::Zero(); + x1e14_halfPipeNormal = CVector3f::Zero(); +} + +bool CMorphBall::BallCloseToCollision(const CStateManager& mgr, float dist, + const CMaterialFilter& filter) const { + const CCollidableSphere prim( + CSphere(x0_player.GetTranslation() + CVector3f(0.f, 0.f, GetBallRadius()), dist), + CMaterialList(kMT_Player, kMT_Solid)); + TEntityList nearList; + mgr.BuildColliderList(nearList, x0_player, prim.CalculateLocalAABox()); + + if (CGameCollision::DetectStaticCollisionBoolean(mgr, prim, CTransform4f::Identity(), filter)) { + return true; + } + + for (TEntityList::const_iterator id = nearList.begin(); id != nearList.end(); ++id) { + if (const CPhysicsActor* actor = TCastToConstPtr< CPhysicsActor >(mgr.GetObjectById(*id))) { + if (CCollisionPrimitive::CollideBoolean( + CInternalCollisionStructure::CPrimDesc(prim, filter, CTransform4f::Identity()), + CInternalCollisionStructure::CPrimDesc(*actor->GetCollisionPrimitive(), + CMaterialFilter::GetPassEverything(), + actor->GetPrimitiveTransform()))) { + return true; + } + } + } + + return false; +} + +void CMorphBall::CollidedWith(const TUniqueId& id, const CCollisionInfoList& list, + CStateManager& mgr) { + x74_collisionInfos = list; + + CMaterialList allMats; + int wakeMaterial; + for (const CCollisionInfo* info = list.Begin(); info != list.End(); ++info) { + allMats.Add(info->GetMaterialLeft()); + } + + const CVector3f vel = x0_player.GetVelocityWR(); + const float velMag = vel.Magnitude(); + wakeMaterial = kMT_NoStepLogic; + CVector3f cvel; + CVector3f cforce; + CVector3f newVel; + if (velMag > 7.f && !x0_player.IsInFluid()) { + bool hitWall = false; + for (const CCollisionInfo* info = list.Begin(); info != list.End(); ++info) { + if (!hitWall) { + if (info->GetMaterialLeft().HasMaterial(kMT_Wall)) { + hitWall = true; + if (info->GetMaterialLeft().HasMaterial(kMT_Stone) || + info->GetMaterialLeft().HasMaterial(kMT_Metal)) { + x19cc_wallSparkGen->SetTranslation(info->GetPoint()); + x19cc_wallSparkGen->SetParticleEmission(true); + x1e38_wallSparkFrameCountdown = 7; + } + } + } + + if (wakeMaterial == kMT_NoStepLogic) { + if (info->GetMaterialLeft().HasMaterial(kMT_Floor)) { + int tmpMaterial = info->GetMaterialLeft().HasMaterial(kMT_Dirt) ? kMT_Dirt : wakeMaterial; + if (info->GetMaterialLeft().HasMaterial(kMT_Sand)) { + tmpMaterial = kMT_Sand; + } + if (info->GetMaterialLeft().HasMaterial(kMT_Lava)) { + tmpMaterial = kMT_Lava; + } + if (info->GetMaterialLeft().HasMaterial(kMT_MudSlow)) { + tmpMaterial = kMT_MudSlow; + } + if (info->GetMaterialLeft().HasMaterial(kMT_Snow)) { + tmpMaterial = kMT_Snow; + } + if (info->GetMaterialLeft().HasMaterial(kMT_Phazon)) { + tmpMaterial = kMT_Phazon; + } + + wakeMaterial = tmpMaterial; + if (tmpMaterial != kMT_NoStepLogic) { + int mappedIdx = skWakeEffectMap[tmpMaterial]; + if (mappedIdx == 0) { + const TAreaId areaId = mgr.GetNextAreaId(); + const CScriptAreaAttributes* areaAttrs = + mgr.GetWorld()->GetArea(areaId)->GetPostConstructed()->x10d8_areaAttributes; + if (areaAttrs != nullptr && areaAttrs->GetPhazonType() == kPT_Orange) { + mappedIdx = 1; + } + } + + if (x1c0c_wakeEffectIdx != mappedIdx) { + if (x1c0c_wakeEffectIdx != -1) { + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->SetParticleEmission(false); + } + x1c0c_wakeEffectIdx = mappedIdx; + } + + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->SetParticleEmission(true); + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->SetTranslation(info->GetPoint()); + } + } + } + } + + if (hitWall && !CSfxManager::IsPlaying(x1e28_wallHitSfxHandle)) { + CVector3f translation; + const CVector3f zero(0.f, 0.f, 0.f); + translation = x0_player.GetTranslation(); + x1e28_wallHitSfxHandle = + CSfxManager::AddEmitter(SFXsam_r_mhitwall_00, translation, zero, true, false); + x0_player.DoSfxEffects(x1e28_wallHitSfxHandle); + } + } + + if (wakeMaterial == kMT_NoStepLogic && x1c0c_wakeEffectIdx != -1) { + x1bc8_wakeEffectGens[x1c0c_wakeEffectIdx]->SetParticleEmission(false); + } + + if (x1954_isProjectile) { + x1954_isProjectile = false; + } + + if (allMats.HasMaterial(kMT_HalfPipe)) { + x1dfc_touchHalfPipeCooldown = 4.f; + x1e04_touchHalfPipeRecentCooldown = 0.05f; + int i = 0; + const CCollisionInfo* info = list.Begin(); + for (; i < list.GetCount(); ++info, ++i) { + if (info->GetMaterialLeft().HasMaterial(kMT_HalfPipe)) { + const CVector3f normal = info->GetNormalLeft(); + const float dot = CVector3f::Dot(normal, x1e14_halfPipeNormal); + if (dot < 0.99f) { + x1e08_prevHalfPipeNormal = x1e14_halfPipeNormal; + x1e14_halfPipeNormal = normal; + if (close_enough(x1e08_prevHalfPipeNormal, CVector3f::Zero(), 0.000011920929f)) { + x1e08_prevHalfPipeNormal = x1e14_halfPipeNormal; + } + } + } + } + } + + if (x28_tireMode && allMats.HasMaterial(kMT_Floor) && allMats.HasMaterial(kMT_Wall)) { + SwitchToMarble(); + } + + if (!GetIsInHalfPipeMode() && x1de4_24_inBoost && velMag > 3.f) { + const CVector3f velNorm = vel.AsNormalized(); + for (int i = 0; i < list.GetCount(); ++i) { + const CCollisionInfo& info = list[i]; + if (!info.GetMaterialLeft().HasMaterial(kMT_HalfPipe) && + CVector3f::Dot(info.GetNormalLeft(), velNorm) < -0.4f) { + LeaveBoosting(); + DampLinearAndAngularVelocities(0.4f, 0.01f); + break; + } + } + } + + if (id == kInvalidUniqueId) { + cvel = x0_player.GetVelocityWR(); + cforce = x1c_controlForce; + const float cvelMag = cvel.Magnitude(); + if (cforce.Magnitude() > 1000.f && cvelMag > 8.f) { + const CVector3f cforceNorm = cforce.AsNormalized(); + const CVector3f cvelNorm = cvel.AsNormalized(); + for (const CCollisionInfo* info = list.Begin(); info != list.End(); ++info) { + if (IsClimbable(*info)) { + const CVector3f normal = info->GetNormalLeft(); + const float cforceDot = CVector3f::Dot(cforceNorm, normal); + const float cvelDot = CVector3f::Dot(cvelNorm, normal); + if (cforceDot < -0.4f && cvelDot < -0.6f) { + const float boostZ = 0.75f * cvelMag; + const float minZ = + 0.15f * gpTweakBall->GetBallTranslationMaxSpeed(x0_player.GetSurfaceRestraint()); + const float clampedZ = CMath::FastFSel(boostZ - minZ, boostZ, minZ); + const float maxZ = + 0.25f * gpTweakBall->GetBallTranslationMaxSpeed(x0_player.GetSurfaceRestraint()); + const float zVel = CMath::FastFSel(clampedZ - maxZ, maxZ, clampedZ); + x1dcc_ = cvel; + newVel = cvel + CVector3f(0.f, 0.f, zVel); + x1dd8_ = newVel; + x0_player.SetVelocityWR(newVel); + ++x1dc8_failsafeCounter; + break; + } + } + } + } + } + + if (list.GetCount() > 2 && list[0].GetNormalLeft().GetZ() > 0.2f && + CMath::AbsF(CVector3f::Dot(list[0].GetNormalLeft(), x0_player.GetVelocityWR())) > 2.f) { + float accum = 0.f; + uint dotCount = 0; + for (int i = 1; i < list.GetCount(); ++i) { + const CCollisionInfo& infoA = list[i]; + for (int j = 1; j < list.GetCount(); ++j) { + if (i != j) { + accum += CVector3f::Dot(infoA.GetNormalLeft(), list[j].GetNormalLeft()); + ++dotCount; + } + } + } + + accum /= static_cast< float >(dotCount); + if (accum < 0.5f) { + ++x1dc8_failsafeCounter; + } + } + + const CCollisionInfo* info = list.Begin(); + if (info != list.End()) { + SelectMorphBallSounds(info->GetMaterialLeft()); + } +} + +bool CMorphBall::IsInFrustum(const CFrustumPlanes& frustum) const { + if (!x58_ballModel->IsNull()) { + rstl::optional_object< CAABox > swooshBounds = x19b8_slowBlueTailSwooshGen->GetBounds(); + if (x58_ballModel->IsInFrustum(GetBallToWorld(), frustum)) { + return true; + } + + if (x19b8_slowBlueTailSwooshGen->GetModulationColor().GetAlpha() != 0.f && swooshBounds) { + if (frustum.BoxFrustumPlanesCheck(*swooshBounds) != 0) { + return true; + } + } + } + + return false; +} + +void CMorphBall::ComputeLiftForces(const CVector3f& controlForce, const CVector3f& velocity, + const CStateManager& mgr) { + const float liftSpeed = velocity.Magnitude(); + if (x1cd0_liftSpeedAvg.size() < x1cd0_liftSpeedAvg.capacity()) { + x1cd0_liftSpeedAvg.push_back(liftSpeed); + } + for (int i = x1cd0_liftSpeedAvg.size() - 1; i > 0; --i) { + x1cd0_liftSpeedAvg[i] = x1cd0_liftSpeedAvg[i - 1]; + } + x1cd0_liftSpeedAvg[0] = liftSpeed; + + x1d10_liftControlForceAvg.AddValue(controlForce); + + const CVector3f avgControlForce = x1d10_liftControlForceAvg.GetAverage().data(); + const float avgControlForceMag = avgControlForce.Magnitude(); + if (avgControlForceMag > 12000.f) { + const float avgLiftSpeed = x1cd0_liftSpeedAvg.GetAverage().data(); + if (avgLiftSpeed < 4.f) { + const CTransform4f primitiveXf = x0_player.GetPrimitiveTransform(); + const CAABox primitiveBounds = x0_player.GetCollisionPrimitive()->CalculateAABox(primitiveXf); + const CVector3f liftBoundsOffset(0.1f, 0.1f, -0.05f); + const CAABox liftBounds(primitiveBounds.GetMinPoint() - liftBoundsOffset, + primitiveBounds.GetMaxPoint() + liftBoundsOffset); + if (CGameCollision::DetectStaticCollisionBoolean( + mgr, CCollidableAABox(liftBounds, CMaterialList(SolidMaterial)), + CTransform4f::Identity(), CMaterialFilter::skPassEverything)) { + const float ballRadius = GetBallRadius(); + const float zLift = 1.75f * ballRadius; + const CVector3f liftPos = primitiveXf.GetTranslation() + CVector3f(0.f, 0.f, zLift); + const CVector3f liftDir = avgControlForce / avgControlForceMag; + const CMaterialFilter rayFilter = + CMaterialFilter::MakeInclude(CMaterialList(SolidMaterial)); + const CRayCastResult result = mgr.RayStaticIntersection(liftPos, liftDir, 1.4f, rayFilter); + if (!result.IsValid()) { + const float liftScale = 1.f - rstl::max_val(0.f, avgLiftSpeed - 3.f); + x0_player.ApplyForceWR(CVector3f(0.f, 0.f, liftScale * 40000.f), CAxisAngle::Identity()); + + const CVector3f& liftImpulseVec = + CVector3f(-x1924_surfaceToWorld.Get00(), -x1924_surfaceToWorld.Get10(), + -x1924_surfaceToWorld.Get20()) * + 1000.f; + x0_player.ApplyImpulseWR(CVector3f::Zero(), + CAxisAngle::FromVector(liftImpulseVec * liftScale)); + } + } + } + } +} + +float CMorphBall::CalculateSurfaceFriction() const { + float friction = gpTweakBall->GetBallTranslationFriction(x0_player.GetSurfaceRestraint()); + if (x0_player.x26c_attachedActor != kInvalidUniqueId) { + friction *= 2.f; + } + + const int drainSourceCount = x0_player.x274_energyDrain.GetEnergyDrainSources().size(); + if (drainSourceCount > 0) { + friction *= drainSourceCount * 1.5f; + } + + return friction; +} + +void CMorphBall::ApplyGravity(CStateManager& mgr) { + if (x0_player.CheckSubmerged()) { + if (!mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_GravitySuit)) { + x0_player.SetMomentumWR( + CVector3f(0.f, 0.f, x0_player.GetMass() * gpTweakBall->GetBallWaterGravity())); + return; + } + } + + x0_player.SetMomentumWR(CVector3f(0.f, 0.f, x0_player.GetMass() * gpTweakBall->GetBallGravity())); +} + +void CMorphBall::SpinToSpeed(float holdMag, const CVector3f& torque, float mag) { + const CVector3f angVel = x0_player.GetAngularVelocityWR().GetVector(); + x0_player.ApplyTorqueWR(torque * (mag * (holdMag - angVel.Magnitude()))); +} + +static const float kHalfPipeMaxSpeed = 95.f; + +float CMorphBall::ComputeMaxSpeed() const { + float maxSpeed = 0.f; + if (GetIsInHalfPipeMode()) { + maxSpeed = x0_player.GetVelocityWR().Magnitude() * 1.5f; + maxSpeed = rstl::min_val(kHalfPipeMaxSpeed, maxSpeed); + } else { + maxSpeed = gpTweakBall->GetBallTranslationMaxSpeed(x0_player.GetSurfaceRestraint()); + } + return maxSpeed; +} + +void CMorphBall::Touch(CActor& actor, CStateManager& mgr) { + if (CPhysicsActor* act = TCastToPtr< CPhysicsActor >(actor)) { + if (x1de4_24_inBoost) { + const float relSpeed = (act->GetVelocityWR() - x0_player.GetVelocityWR()).Magnitude(); + if (relSpeed > gpTweakBall->GetBoostBallMinRelativeSpeedForDamage()) { + static CDamageInfo kBallDamage(CWeaponMode::BoostBall(), 50000.f, 0.f, 0.f); + const TUniqueId playerId = x0_player.GetUniqueId(); + mgr.ApplyDamage( + playerId, actor.GetUniqueId(), playerId, kBallDamage, + CMaterialFilter::MakeIncludeExclude(CMaterialList(SolidMaterial), CMaterialList()), + CVector3f::Zero()); + } + } + } +} + +bool CMorphBall::IsClimbable(const CCollisionInfo& cinfo) const { + if (CMath::AbsF(cinfo.GetNormalLeft().GetZ()) < 0.7f) { + const float pointToBall = GetBallToWorld().Get23() - cinfo.GetPoint().GetZ(); + if (pointToBall > 0.1f && pointToBall < GetBallRadius() - 0.05f) { + return true; + } + } + + return false; +} + +void CMorphBall::FluidFXThink(CActor::EFluidState state, CScriptWater& water, CStateManager& mgr) { + CActor::EFluidState fluidState = state; + const float flatMoveSpeed = x0_player.x4fc_flatMoveSpeed; + const CVector3f splashPos(x0_player.GetTranslation().GetX(), x0_player.GetTranslation().GetY(), + water.GetTriggerBoundsWR().GetMaxPoint().GetZ()); + + if (flatMoveSpeed >= 8.f) { + const float maxVel = x0_player.GetBallMaxVelocity(); + if (mgr.GetFluidPlaneManager()->GetLastSplashDeltaTime(x0_player.GetUniqueId()) >= + 0.1f * ((maxVel - flatMoveSpeed) / (maxVel - 8.f))) { + mgr.FluidPlaneManager()->CreateSplash(x0_player.GetUniqueId(), mgr, water, splashPos, 0.f, + fluidState == CActor::kFS_EnteredFluid); + } + } + + if (flatMoveSpeed >= 0.2f) { + const float rippleDt = + mgr.GetFluidPlaneManager()->GetLastRippleDeltaTime(x0_player.GetUniqueId()); + float minRippleDt; + if (flatMoveSpeed <= 15.f) { + minRippleDt = 0.13f; + } else { + const float min = 0.1f; + minRippleDt = + rstl::max_val(min, 0.13f - (0.029999994f * (flatMoveSpeed - 15.f)) / + (x0_player.GetBallMaxVelocity() - flatMoveSpeed)); + } + + if (rippleDt >= minRippleDt) { + const float rippleMag = 0.65f * flatMoveSpeed / x0_player.GetBallMaxVelocity(); + water.FluidPlane().AddRipple(rippleMag, x0_player.GetUniqueId(), splashPos, water, mgr); + } + } +} + +void CMorphBall::LoadMorphBallModel(CStateManager& mgr) { + const SMorphBallModelTables& tables = skMorphBallModelTables; + int modelIdx; + int loadModelId; + CPlayerState* playerState; + bool spiderBall; + + playerState = mgr.PlayerState(); + spiderBall = playerState->HasPowerUp(CPlayerState::kIT_SpiderBall); + modelIdx = playerState->GetCurrentSuitRaw(); + if (playerState->GetIsFusionEnabled()) { + modelIdx += 4; + } + + loadModelId = modelIdx; + if (spiderBall) { + loadModelId = modelIdx + 4; + } + if (playerState->GetIsFusionEnabled()) { + loadModelId += 100; + } + + if (x4_loadedModelId != loadModelId) { + x4_loadedModelId = loadModelId; + if (spiderBall) { + const SMorphBallModelInfo* character = tables.xc0_spiderBallCharacter; + const SMorphBallModelInfo* lowPoly = tables.x80_spiderBallLowPoly; + const SMorphBallModelInfo* glass = tables.x100_spiderBallGlass; + + x58_ballModel = GetMorphBallModel(rstl::string_l(character[modelIdx].x0_name), xc_radius); + x5c_ballModelShader = character[modelIdx].x4_shader; + x68_lowPolyBallModel = + GetMorphBallModel(rstl::string_l(lowPoly[modelIdx].x0_name), xc_radius); + x6c_lowPolyBallModelShader = lowPoly[modelIdx].x4_shader; + if (glass[modelIdx].x0_name != nullptr) { + x60_spiderBallGlassModel = + GetMorphBallModel(rstl::string_l(glass[modelIdx].x0_name), xc_radius); + x64_spiderBallGlassModelShader = glass[modelIdx].x4_shader; + } else { + x60_spiderBallGlassModel = nullptr; + x64_spiderBallGlassModelShader = 0; + } + x8_ballGlowColorIdx = tables.x180_spiderBallGlowColorIdx[modelIdx]; + } else { + const SMorphBallModelInfo* character = tables.x0_ballCharacter; + const SMorphBallModelInfo* lowPoly = tables.x40_ballLowPoly; + + x58_ballModel = GetMorphBallModel(rstl::string_l(character[modelIdx].x0_name), xc_radius); + x5c_ballModelShader = character[modelIdx].x4_shader; + x68_lowPolyBallModel = + GetMorphBallModel(rstl::string_l(lowPoly[modelIdx].x0_name), xc_radius); + x6c_lowPolyBallModelShader = lowPoly[modelIdx].x4_shader; + x8_ballGlowColorIdx = tables.x1a0_ballGlowColorIdx[modelIdx]; + } + + const float scale = 2.f * gpTweakPlayer->GetPlayerBallHalfExtent(); + x58_ballModel->SetScale(CVector3f(scale, scale, scale)); + } +} + +CModelData* CMorphBall::GetMorphBallModel(const rstl::string& name, float radius) { + const SObjectTag* tag = gpResourceFactory->GetResourceIdByName(name.data()); + + // what is going on here? + const CAssetId& id = tag->GetId(); + const FourCC& type = tag->GetType(); + const FourCC* const typePtr = &type; + + CModelData* ret = nullptr; + if (*typePtr == 'CMDL') { + ret = rs_new CModelData(CStaticRes(id, CVector3f(2.f * radius, 2.f * radius, 2.f * radius))); + } else { + ret = + rs_new CModelData(CAnimRes(id, CAnimRes::kDefaultCharIdx, + CVector3f(2.f * radius, 2.f * radius, 2.f * radius), 0, false)); + } + return ret; +} + +void CMorphBall::AddSpiderBallElectricalEffect() { + for (int i = 0; i < x19e4_spiderElectricGens.size(); ++i) { + if (x19e4_spiderElectricGens[i].second) { + continue; + } + + x19e4_spiderElectricGens[i].second = true; + x1b68_activeSpiderElectricList.push_back( + CSpiderBallElectricityManager(i, x1b80_rand.Range(4, 8))); + + CParticleSwoosh* swoosh = x19e4_spiderElectricGens[i].first.get(); + const float sign = (x1b80_rand.Next() & 0x100) < 0x80 ? -1.f : 1.f; + const float randDir = sign * (0.9f * GetBallRadius()); + float ang0; + float cosAng0CosAng1; + float ang1; + ang0 = 40.f - 80.f * x1b80_rand.Float(); + ang0 *= 0.017453292f; + ang1 = 90.f + (40.f - 80.f * x1b80_rand.Float()); + ang1 *= 0.017453292f; + const float cosAng1 = CMath::FastCosR(ang1); + cosAng0CosAng1 = CMath::FastCosR(ang0); + cosAng0CosAng1 *= cosAng1; + const float translationX = 1.32f * randDir; + const float sinAng0 = CMath::FastSinR(ang0); + const float cosAng0 = CMath::FastCosR(ang0); + const float sinAng1 = CMath::FastSinR(ang1); + CVector3f transInc; + CVector3f translation = + 0.6f * CVector3f(sign * ((-sinAng1) * cosAng0), sign * sinAng0, sign * cosAng0CosAng1) + + CVector3f(translationX, 0.f, 0.f); + transInc = (1.f / 6.f) * (CVector3f(randDir, 0.f, 0.f) - translation); + + swoosh->SetOrientation(CTransform4f::LookAt(CVector3f::Zero(), transInc, CVector3f::Up())); + + for (uint j = 0; j < 6; ++j) { + swoosh->SetTranslation(translation); + swoosh->SetWarmUp(); + swoosh->Update(1.0 / 60.0); + translation += transInc; + } + return; + } +} + +void CMorphBall::UpdateSpiderBallElectricalEffects() { + rstl::list< CSpiderBallElectricityManager >::iterator it = x1b68_activeSpiderElectricList.begin(); + CTransform4f orientation = GetBallToWorld(); + const CVector3f translation = orientation.GetTranslation(); + orientation.SetTranslation(CVector3f::Zero()); + + while (it != x1b68_activeSpiderElectricList.end()) { + CSpiderBallElectricityManager& effect = *it; + if (effect.x8_curFrame >= effect.x4_lifetime) { + x19e4_spiderElectricGens[effect.x0_effectIdx].second = false; + it = x1b68_activeSpiderElectricList.erase(it); + continue; + } + + CParticleSwoosh* swoosh = x19e4_spiderElectricGens[effect.x0_effectIdx].first.get(); + swoosh->SetModulationColor( + CColor(1.f, 1.f, 1.f, 1.f - float(effect.x8_curFrame) / float(effect.x4_lifetime))); + x19e4_spiderElectricGens[effect.x0_effectIdx].first->SetGlobalTranslation(translation); + x19e4_spiderElectricGens[effect.x0_effectIdx].first->SetGlobalOrientation(orientation); + ++effect.x8_curFrame; + ++it; + } +} + +void CMorphBall::RenderSpiderBallElectricalEffects() const { + for (rstl::list< CSpiderBallElectricityManager >::const_iterator it = + x1b68_activeSpiderElectricList.begin(); + it != x1b68_activeSpiderElectricList.end(); ++it) { + const CSpiderBallElectricityManager& effect = *it; + x19e4_spiderElectricGens[effect.x0_effectIdx].first->Render(); + } +} + +void CMorphBall::RenderEnergyDrainEffects(const CStateManager& mgr) const { + const rstl::vector< CEnergyDrainSource >& sources = + x0_player.x274_energyDrain.GetEnergyDrainSources(); + for (const CEnergyDrainSource* it = sources.data(); it != sources.data() + sources.size(); ++it) { + const CMetroidBeta* metroid = CPatterned::CastTo(TPatternedCast< CMetroidBeta >( + const_cast< CEntity* >(mgr.GetObjectById(it->GetEnergyDrainSourceId())))); + if (metroid != nullptr) { + metroid->RenderHitBallEffect(); + break; + } + } +} + +void CMorphBall::TouchModel(const CStateManager& mgr) const { + x58_ballModel->Touch(mgr, x5c_ballModelShader); + if (mgr.GetPlayerState()->HasPowerUp(CPlayerState::kIT_SpiderBall) && + x60_spiderBallGlassModel.get() != nullptr) { + x60_spiderBallGlassModel->Touch(mgr, x64_spiderBallGlassModelShader); + } + x68_lowPolyBallModel->Touch(mgr, x6c_lowPolyBallModelShader); +} + +void CMorphBall::SetAsProjectile() { x1954_isProjectile = true; } + +CMorphBall::EBallBoostState CMorphBall::GetBallBoostState() const { return x1e3c_boostState; } + +void CMorphBall::SetBallBoostState(EBallBoostState state) { x1e3c_boostState = state; } + +CMorphBall::EBombJumpState CMorphBall::GetBombJumpState() const { return x1e40_bombJumpState; } + +void CMorphBall::SetBombJumpState(EBombJumpState state) { x1e40_bombJumpState = state; } + +void CMorphBall::LoadAnimationTokens(const rstl::string& name) { + const rstl::string dgrpName = name + rstl::string_l("_DGRP"); + TLockedToken< CDependencyGroup > dgrpToken = gpSimplePool->GetObj(dgrpName.data()); + const rstl::vector< SObjectTag >& tags = dgrpToken->GetObjectTagVector(); + + x1958_animationTokens = rstl::vector< CToken >(); + x1958_animationTokens.reserve(tags.size()); + for (AUTO(tag, tags.begin()); tag != tags.end(); ++tag) { + if (tag->GetType() == 'CMDL' || tag->GetType() == 'CSKR' || tag->GetType() == 'TXTR') { + continue; + } + + CToken token = gpSimplePool->GetObj(*tag); + token.Lock(); + x1958_animationTokens.push_back(token); + } +} + +void CMorphBall::TakeDamage(float damage) { + if (damage <= 0.f) { + x1e44_damageEffect = 0.f; + x1e48_damageEffectDecaySpeed = 0.f; + return; + } + + if (damage >= 20.f) { + x1e48_damageEffectDecaySpeed = 0.25f; + } else if (damage > 5.f) { + x1e48_damageEffectDecaySpeed = 1.f - 0.75f * ((damage - 5.f) / 15.f); + } else { + x1e48_damageEffectDecaySpeed = 1.f; + } + x1e44_damageEffect = 1.f; +} + +void CMorphBall::SelectMorphBallSounds(const CMaterialList& materials) { + short rollSfx; + if (x0_player.x9c5_30_selectFluidBallSound) { + if (x0_player.x82c_inLava) { + rollSfx = SFXsam_b_rollllava_lp_00; + } else { + rollSfx = SFXsam_b_rollwatr_lp_00; + } + } else { + rollSfx = + CPlayer::SfxIdFromMaterial(materials, skBallRollSfx, ARRAY_SIZE(skBallRollSfx), 0xffff); + } + x0_player.x9c5_30_selectFluidBallSound = false; + + if (rollSfx != 0xffff) { + if (x1e34_rollSfx != rollSfx && x1e2c_rollSfxHandle) { + CSfxManager::SfxStop(x1e2c_rollSfxHandle); + x1e2c_rollSfxHandle.Clear(); + } + x1e34_rollSfx = rollSfx; + } + + x1e36_landSfx = + CPlayer::SfxIdFromMaterial(materials, skBallLandSfx, ARRAY_SIZE(skBallLandSfx), 0xffff); +} + +void CMorphBall::UpdateMorphBallSound(float dt) { + CVector3f velocity = x0_player.GetVelocityWR(); + if (x187c_spiderBallState != kSBS_Active) { + velocity[kDZ] = 0.f; + } + + switch (x0_player.GetPlayerMovementState()) { + case NPlayer::kMS_OnGround: + case NPlayer::kMS_FallingMorphed: { + float speed = velocity.Magnitude(); + if (x187c_spiderBallState == kSBS_Active) { + speed += 4.f * (dt * gpTweakBall->GetBallGravity()); + } + + if (speed > 0.8f) { + if (!x1e2c_rollSfxHandle) { + if (x1e34_rollSfx != 0xffff) { + x1e2c_rollSfxHandle = CSfxManager::AddEmitter(x1e34_rollSfx, x0_player.GetTranslation(), + CVector3f::Zero(), true, true); + } + x0_player.DoSfxEffects(x1e2c_rollSfxHandle); + } + + CSfxManager::PitchBend(x1e2c_rollSfxHandle, + CMath::Clamp(0, static_cast< int >(speed) * 500 + 0x2b4, 0x4000)); + // ? this forces them into .sdata2 + const float kRollVolumeMin = 64.f; + const float kRollVolumeMax = 127.f; + uchar vol = CCast::ToUint8(CMath::Clamp(kRollVolumeMin, 3.2f * speed + 64.f, kRollVolumeMax)); + CSfxManager::UpdateEmitter(x1e2c_rollSfxHandle, x0_player.GetTranslation(), CVector3f::Zero(), + vol); + break; + } + } + default: + if (x1e2c_rollSfxHandle) { + CSfxManager::SfxStop(x1e2c_rollSfxHandle); + x1e2c_rollSfxHandle.Clear(); + } + break; + } + + if (x187c_spiderBallState == kSBS_Active) { + if (!x1e30_spiderSfxHandle) { + x1e30_spiderSfxHandle = CSfxManager::AddEmitter( + SFXsam_b_spidlach_lp_00, x0_player.GetTranslation(), CVector3f::Zero(), true, true, 0xc8); + x0_player.DoSfxEffects(x1e30_spiderSfxHandle); + } + CSfxManager::UpdateEmitter(x1e30_spiderSfxHandle, x0_player.GetTranslation(), CVector3f::Zero(), + 0x7f); + } else if (x1e30_spiderSfxHandle) { + CSfxManager::SfxStop(x1e30_spiderSfxHandle); + x1e30_spiderSfxHandle.Clear(); + } +} + +void CMorphBall::StopSounds() { + if (x1e2c_rollSfxHandle) { + CSfxManager::SfxStop(x1e2c_rollSfxHandle); + x1e2c_rollSfxHandle.Clear(); + } + if (x1e30_spiderSfxHandle) { + CSfxManager::SfxStop(x1e30_spiderSfxHandle); + x1e30_spiderSfxHandle.Clear(); + } +} + +void CMorphBall::StartLandingSfx() { + if (x0_player.GetVelocityWR().GetZ() < -5.f && x1e36_landSfx != 0xffff) { + // ? this forces them into .sdata2 + static const float kLandingVolumeMin = 95.f; + static const float kLandingVolumeMax = 127.f; + const uchar vol = CCast::ToUint8(CMath::Clamp( + kLandingVolumeMin, x0_player.x794_lastVelocity.GetZ() * 1.6f + 95.f, kLandingVolumeMax)); + x0_player.DoSfxEffects(CSfxManager::SfxStart(x1e36_landSfx, vol, 64, true)); + } +} + +void CMorphBall::PointGenerator(void* ptr, const CVector3f* vertices, const CVector3f* normals, + int count) { + if (ptr != nullptr) { + static_cast< CRainSplashGenerator* >(ptr)->GeneratePoints(vertices, normals, count); + } +} + +void CMorphBall::InitializeWakeEffects() { + skWakeEffectMap.resize(skWakeEffectMap.capacity(), -1); + skWakeEffectMap[kMT_Phazon] = 0; + skWakeEffectMap[kMT_Dirt] = 2; + skWakeEffectMap[kMT_Lava] = 3; + skWakeEffectMap[kMT_Snow] = 4; + skWakeEffectMap[kMT_MudSlow] = 5; + skWakeEffectMap[kMT_Sand] = 6; + + { + const TToken< CGenDescription > nullParticle(rs_new CGenDescription); + x1b84_wakeEffects.resize(x1b84_wakeEffects.capacity(), nullParticle); + } + x1b84_wakeEffects[2] = gpSimplePool->GetObj("DirtWake"); + x1b84_wakeEffects[0] = gpSimplePool->GetObj("PhazonWake"); + x1b84_wakeEffects[1] = gpSimplePool->GetObj("PhazonWakeOrange"); + x1b84_wakeEffects[3] = gpSimplePool->GetObj("LavaWake"); + x1b84_wakeEffects[4] = gpSimplePool->GetObj("SnowWake"); + x1b84_wakeEffects[5] = gpSimplePool->GetObj("MudWake"); + x1b84_wakeEffects[6] = gpSimplePool->GetObj("SandWake"); + x1b84_wakeEffects[7] = gpSimplePool->GetObj("RainWake"); + + x1bc8_wakeEffectGens.resize(x1bc8_wakeEffectGens.capacity()); + x1bc8_wakeEffectGens[2] = + rs_new CElementGen(x1b84_wakeEffects[2], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[0] = + rs_new CElementGen(x1b84_wakeEffects[0], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[1] = + rs_new CElementGen(x1b84_wakeEffects[1], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[3] = + rs_new CElementGen(x1b84_wakeEffects[3], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[4] = + rs_new CElementGen(x1b84_wakeEffects[4], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[5] = + rs_new CElementGen(x1b84_wakeEffects[5], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[6] = + rs_new CElementGen(x1b84_wakeEffects[6], CElementGen::kMOT_Normal, CElementGen::kOSF_One); + x1bc8_wakeEffectGens[7] = + rs_new CElementGen(x1b84_wakeEffects[7], CElementGen::kMOT_Normal, CElementGen::kOSF_One); +} + +void CMorphBall::DrawBallShadow(CStateManager& mgr) { + if (x1e50_shadow.get() == nullptr) { + return; + } + + float alpha = 1.f; + switch (x0_player.x2f8_morphBallState) { + case CPlayer::kMS_Unmorphed: + return; + case CPlayer::kMS_Morphed: + break; + case 4: + break; + case CPlayer::kMS_Unmorphing: { + float t = 0.f; + const float duration = x0_player.x578_morphDuration; + if (t != duration) { + t = CMath::Clamp(0.f, x0_player.x574_morphTime / duration, 1.f); + } + alpha = 1.f - t; + break; + } + case CPlayer::kMS_Morphing: { + float t = 0.f; + const float duration = x0_player.x578_morphDuration; + if (t != duration) { + t = CMath::Clamp(0.f, x0_player.x574_morphTime / duration, 1.f); + } + alpha = t; + break; + } + case -1: + break; + } + + x1e50_shadow->Render(mgr, alpha); +} + +void CMorphBall::RenderToShadowTex(CStateManager& mgr) { + if (x1e50_shadow.get() == nullptr) { + return; + } + + const float ballRadius = xc_radius; + CVector3f primitiveOffset = x0_player.GetPrimitiveOffset(); + const CVector3f center = + x0_player.GetTranslation() + primitiveOffset + CVector3f(0.f, 0.f, ballRadius); + const float extent = 1.25f * xc_radius; + const CAABox aabb(CVector3f(center.GetX() - extent, center.GetY() - extent, center.GetZ() - 10.f), + CVector3f(center.GetX() + extent, center.GetY() + extent, center.GetZ())); + x1e50_shadow->RenderIdBuffer(aabb, mgr, x0_player); +} + +void CMorphBall::CreateBallShadow() { + if (x1e50_shadow.get() == nullptr) { + x1e50_shadow = rs_new CMorphBallShadow(0x40, 0x40, gpSimplePool->GetObj("TXTR_BallFade")); + } +} + +void CMorphBall::DeleteBallShadow() { x1e50_shadow = nullptr; } diff --git a/src/MetroidPrime/Player/CPlayer.cpp b/src/MetroidPrime/Player/CPlayer.cpp index 16059bb9..5a917ae1 100644 --- a/src/MetroidPrime/Player/CPlayer.cpp +++ b/src/MetroidPrime/Player/CPlayer.cpp @@ -75,6 +75,15 @@ #include "rstl/math.hpp" #include "rstl/vector.hpp" +const bool gkAutoAim = false; +const bool gkAutoAimAtOrbitedObject = false; +const bool gkFreeLookPreventsOrbitMovement = true; +const float gkSpiderBallControllerActivationPercentage = 0.5f; +const bool gkWorldOnlyReflection = false; +const bool gkUseNewPlayerMovement = true; +const float gkFirstPersonDeathTime = 2.5f; +const float gkBallDeathTime = 6.f; + static CVector3f testRayStart(0.f, 0.f, 0.f); static CVector3f testRayNormal(0.f, 0.f, 1.f); static CRayCastResult testRayResult; diff --git a/src/Weapons/CProjectileWeapon.cpp b/src/Weapons/CProjectileWeapon.cpp index 9872804b..22a6fcd3 100644 --- a/src/Weapons/CProjectileWeapon.cpp +++ b/src/Weapons/CProjectileWeapon.cpp @@ -19,6 +19,8 @@ #include #include +#pragma inline_max_size(250) + uint CProjectileWeapon::skGlobalSeed = 99; float CProjectileWeapon::GetTickPeriod() { return 1 / 60.f; } diff --git a/src/WorldFormat/CWorldLight.cpp b/src/WorldFormat/CWorldLight.cpp index ad8fc299..ad0fa7f2 100644 --- a/src/WorldFormat/CWorldLight.cpp +++ b/src/WorldFormat/CWorldLight.cpp @@ -3,6 +3,8 @@ #include "Kyoto/Streams/CInputStream.hpp" #include +#pragma inline_max_size(250) + const CVector3f CWorldLight::kDefaultPosition = CVector3f(0.f, 0.f, 0.f); const CVector3f CWorldLight::kDefaultDirection = CVector3f(0.f, 1.f, 0.f);