From 8736983c465f97c2c448ee860e02ba688eaf7071 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Wed, 22 Dec 2021 16:25:58 +0100 Subject: [PATCH 1/5] Refactor elevators --- src/Components/Modules/Elevators.cpp | 135 +++++++++++++++++++++------ src/Components/Modules/Elevators.hpp | 7 +- src/Game/Functions.cpp | 6 ++ src/Game/Functions.hpp | 14 ++- src/Game/Structs.hpp | 113 ++++++++++++++++++++-- 5 files changed, 233 insertions(+), 42 deletions(-) diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index f297f48a..1d7aa12d 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -2,38 +2,107 @@ namespace Components { - Game::dvar_t* Elevators::SV_DisableElevators; + Dvar::Var Elevators::SV_Elevators; - __declspec(naked) void Elevators::PM_GroundTraceStub() + int Elevators::PM_CorrectAllSolid(Game::pmove_s* pm, Game::pml_t* pml, Game::trace_t* trace) + { + assert(pm != nullptr); + assert(pm->ps != nullptr); + + Game::vec3_t point; + auto* ps = pm->ps; + + auto i = 0; + const auto EleSettings = Elevators::SV_Elevators.get(); + while (TRUE) + { + point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0]; + point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1]; + point[2] = ps->origin[2] + Game::CorrectSolidDeltas[i][2]; + + Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask); + + // If the player wishes to glitch without effort they can do so + if (!trace->startsolid || EleSettings == Elevators::EASY) + { + ps->origin[0] = point[0]; + ps->origin[1] = point[1]; + ps->origin[2] = point[2]; + point[2] = (ps->origin[2] - 1.0f) - 0.25f; + + Game::PM_playerTrace(pm, trace, ps->origin, point, &pm->bounds, ps->clientNum, pm->tracemask); + + // If elevators are disabled we need to check that startsolid is false before proceeding + // like later versions of the game do + if (!trace->startsolid || EleSettings >= Elevators::ENABLED) + { + + pml->groundTrace.fraction = trace->fraction; + pml->groundTrace.normal[0] = trace->normal[0]; + pml->groundTrace.normal[1] = trace->normal[1]; + pml->groundTrace.normal[2] = trace->normal[2]; + + pml->groundTrace.surfaceFlags = trace->surfaceFlags; + pml->groundTrace.contents = trace->contents; + pml->groundTrace.hitType = trace->hitType; + pml->groundTrace.hitId = trace->hitId; + + pml->groundTrace.partName = trace->partName; + pml->groundTrace.partGroup = trace->partGroup; + pml->groundTrace.walkable = trace->walkable; + + const auto fraction = trace->fraction; + ps->origin[0] += fraction * (point[0] - ps->origin[0]); + ps->origin[1] += fraction * (point[1] - ps->origin[1]); + ps->origin[2] += fraction * (point[2] - ps->origin[2]); + break; + } + } + + i += 1; + if (i >= 26) + { + ps->groundEntityNum = Game::ENTITYNUM_NONE; + pml->groundPlane = 0; + pml->almostGroundPlane = 0; + pml->walking = 0; + Game::Jump_ClearState(ps); + return 0; + } + } + + return 1; + } + + void Elevators::PM_TraceStub(Game::pmove_s* pm, Game::trace_t* trace, const float* f3, + const float* f4, const Game::Bounds* bounds, int a6, int a7) + { + Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7); + + if (Elevators::SV_Elevators.get() == Elevators::EASY) + { + trace->allsolid = false; + } + } + + __declspec(naked) void Elevators::PM_CorrectAllSolidStub() { __asm { push eax - mov eax, Elevators::SV_DisableElevators - cmp byte ptr [eax + 16], 1 + pushad + + push [esp + 0x8 + 0x24] + push [esp + 0x8 + 0x24] + push eax + call Elevators::PM_CorrectAllSolid + add esp, 0xC + + mov [esp + 0x20], eax + popad pop eax - // Always skip PM_CorrectAllSolid if SV_DisableElevators is set to 1 - je noElevators - - // Original code - cmp byte ptr [esp + 0x50], 0 - rep movsd - mov esi, [esp + 0x58] - - // Original code flow - push 0x573694 - retn - - noElevators: - - // Original code - rep movsd - mov esi, [esp + 0x58] - - // Jump over call to PM_CorrectAllSolid - push 0x5736AE - retn + ret } } @@ -41,12 +110,20 @@ namespace Components { Dvar::OnInit([] { - Elevators::SV_DisableElevators = Game::Dvar_RegisterBool("sv_disableElevators", - false, Game::DVAR_FLAG_REPLICATED, "Disable elevators"); + static const char* values[] = + { + "Disable elevators", + "Enable elevators", + "Enable easy elevators", + nullptr + }; + + Elevators::SV_Elevators = Game::Dvar_RegisterEnum("sv_Elevators", values, + Elevators::ENABLED, Game::DVAR_FLAG_REPLICATED, "Elevators glitch settings"); }); - // Hook PM_GroundTrace so me way skip PM_CorrectAllSolid (disable elevators) - Utils::Hook(0x573689, Elevators::PM_GroundTraceStub, HOOK_JUMP).install()->quick(); + Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x570EC5, Elevators::PM_TraceStub, HOOK_CALL).install()->quick(); } Elevators::~Elevators() diff --git a/src/Components/Modules/Elevators.hpp b/src/Components/Modules/Elevators.hpp index 73af502a..ff490a31 100644 --- a/src/Components/Modules/Elevators.hpp +++ b/src/Components/Modules/Elevators.hpp @@ -9,8 +9,11 @@ namespace Components ~Elevators(); private: - static Game::dvar_t* SV_DisableElevators; + enum ElevatorSettings { DISABLED, ENABLED, EASY }; + static Dvar::Var SV_Elevators; - static void PM_GroundTraceStub(); + static int PM_CorrectAllSolid(Game::pmove_s* move, Game::pml_t* pml, Game::trace_t* trace); + static void PM_CorrectAllSolidStub(); + static void PM_TraceStub(Game::pmove_s*, Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 86d8b5c5..b09916fe 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -377,6 +377,10 @@ namespace Game Field_AdjustScroll_t Field_AdjustScroll = Field_AdjustScroll_t(0x488C10); AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee = AimAssist_ApplyAutoMelee_t(0x56A360); + Jump_ClearState_t Jump_ClearState = Jump_ClearState_t(0x04B3890); + PM_playerTrace_t PM_playerTrace = PM_playerTrace_t(0x458980); + PM_Trace_t PM_Trace = PM_Trace_t(0x441F60); + XAssetHeader* DB_XAssetPool = reinterpret_cast(0x7998A8); unsigned int* g_poolSize = reinterpret_cast(0x7995E8); @@ -493,6 +497,8 @@ namespace Game GraphFloat* aaInputGraph = reinterpret_cast(0x7A2FC0); + vec3_t* CorrectSolidDeltas = reinterpret_cast(0x739BB8); // Count 26 + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 7da47215..9e7b7132 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -759,7 +759,7 @@ namespace Game typedef void(__cdecl * SV_Cmd_EndTokenizedString_t)(); extern SV_Cmd_EndTokenizedString_t SV_Cmd_EndTokenizedString; - typedef void(__cdecl* SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); + typedef void(__cdecl * SV_Cmd_ArgvBuffer_t)(int arg, char* buf, int size); extern SV_Cmd_ArgvBuffer_t SV_Cmd_ArgvBuffer; typedef void(__cdecl * SV_SetConfigstring_t)(int index, const char* string); @@ -894,6 +894,15 @@ namespace Game typedef void(__cdecl * AimAssist_ApplyAutoMelee_t)(const AimInput* input, AimOutput* output); extern AimAssist_ApplyAutoMelee_t AimAssist_ApplyAutoMelee; + typedef void(__cdecl * Jump_ClearState_t)(playerState_s* ps); + extern Jump_ClearState_t Jump_ClearState; + + typedef void(__cdecl * PM_playerTrace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + extern PM_playerTrace_t PM_playerTrace; + + typedef void(__cdecl * PM_Trace_t)(pmove_s*, trace_t*, const float*, const float*, const Bounds*, int, int); + extern PM_Trace_t PM_Trace; + extern XAssetHeader* DB_XAssetPool; extern unsigned int* g_poolSize; @@ -944,6 +953,7 @@ namespace Game extern int* serverMessageSequence; constexpr auto MAX_GENTITIES = 2048u; + constexpr auto ENTITYNUM_NONE = MAX_GENTITIES - 1; extern gentity_t* g_entities; extern netadr_t* connectedHost; @@ -1013,6 +1023,8 @@ namespace Game constexpr auto AIM_ASSIST_GRAPH_COUNT = 4u; extern GraphFloat* aaInputGraph; + extern vec3_t* CorrectSolidDeltas; + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_s* item); void Menu_SetNextCursorItem(Game::UiContext* ctx, Game::menuDef_t* currentMenu, int unk = 1); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 8a74e54d..63acd2a4 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -211,6 +211,31 @@ namespace Game FL_MOVER_SLIDE = 0x8000000 }; + typedef enum + { + HITLOC_NONE, + HITLOC_HELMET, + HITLOC_HEAD, + HITLOC_NECK, + HITLOC_TORSO_UPR, + HITLOC_TORSO_LWR, + HITLOC_R_ARM_UPR, + HITLOC_L_ARM_UPR, + HITLOC_R_ARM_LWR, + HITLOC_L_ARM_LWR, + HITLOC_R_HAND, + HITLOC_L_HAND, + HITLOC_R_LEG_UPR, + HITLOC_L_LEG_UPR, + HITLOC_R_LEG_LWR, + HITLOC_L_LEG_LWR, + HITLOC_R_FOOT, + HITLOC_L_FOOT, + HITLOC_GUN, + HITLOC_SHIELD, + HITLOC_NUM + } hitLocation_t; + struct FxEffectDef; struct pathnode_t; struct pathnode_tree_t; @@ -1132,7 +1157,7 @@ namespace Game int unpredictableEventSequenceOld; int unpredictableEvents[4]; unsigned int unpredictableEventParms[4]; - int clientNum; + int clientNum; // 260 int viewmodelIndex; float viewangles[3]; int viewHeightTarget; @@ -5348,21 +5373,42 @@ namespace Game PLAYER_FLAG_FROZEN = 1 << 2, }; + typedef enum + { + SESS_STATE_PLAYING = 0x0, + SESS_STATE_DEAD = 0x1, + SESS_STATE_SPECTATOR = 0x2, + SESS_STATE_INTERMISSION = 0x3 + } sessionState_t; + + typedef enum + { + CON_DISCONNECTED = 0x0, + CON_CONNECTING = 0x1, + CON_CONNECTED = 0x2 + } clientConnected_t; + typedef struct gclient_s { - unsigned char pad[12764]; - unsigned int team; + playerState_s ps; + sessionState_t sessionState; // 12572 + char pad0[40]; + clientConnected_t connected; // 12616 + char pad1[144]; + unsigned int team; // 12764 char pad2[436]; - int flags; + int flags; // 13204 int spectatorClient; int lastCmdTime; int buttons; - int oldbuttons; - int latched_buttons; - int buttonsSinceLastFrame; - char pad3[700]; + int oldbuttons; // 13220 + int latched_buttons; // 13224 + int buttonsSinceLastFrame; // 13228 + char pad3[700]; // 13232 } gclient_t; + static_assert(sizeof(gclient_t) == 13932); + struct EntHandle { unsigned __int16 number; @@ -6930,15 +6976,43 @@ namespace Game const char* args[9]; }; + enum TraceHitType + { + TRACE_HITTYPE_NONE = 0, + TRACE_HITTYPE_ENTITY = 1, + TRACE_HITTYPE_DYNENT_MODEL = 2, + TRACE_HITTYPE_DYNENT_BRUSH = 3, + TRACE_HITTYPE_GLASS = 4 + }; + +#pragma pack(push, 1) + struct trace_t + { + float fraction; + float normal[3]; + int surfaceFlags; + int contents; + TraceHitType hitType; + unsigned __int16 hitId; + float fractionForHitType; + unsigned __int16 modelIndex; + unsigned __int16 partName; + unsigned __int16 partGroup; + bool allsolid; + bool startsolid; + bool walkable; + }; +#pragma pack(pop) + struct pmove_s { playerState_s* ps; usercmd_s cmd; usercmd_s oldcmd; - int tracemask; + int tracemask; // 84 int numtouch; int touchents[32]; - char __pad0[24]; + Bounds bounds; // 220 float xyspeed; int proneChange; float maxSprintTimeMultiplier; @@ -6952,6 +7026,25 @@ namespace Game unsigned char handler; }; + static_assert(sizeof(pmove_s) == 296); + + struct pml_t + { + float forward[3]; + float right[3]; + float up[3]; + float frametime; + int msec; + int walking; + int groundPlane; + int almostGroundPlane; + trace_t groundTrace; + float impactSpeed; + float previous_origin[3]; + float previous_velocity[3]; + int holdrand; + }; + enum EffectiveStance { PM_EFF_STANCE_DEFAULT = 0, From 8cf5208c29bc46f80322bad4e54ee718b26c015d Mon Sep 17 00:00:00 2001 From: Diavolo Date: Wed, 22 Dec 2021 16:40:30 +0100 Subject: [PATCH 2/5] comments --- src/Components/Modules/Elevators.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index 1d7aa12d..8195a273 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -36,7 +36,6 @@ namespace Components // like later versions of the game do if (!trace->startsolid || EleSettings >= Elevators::ENABLED) { - pml->groundTrace.fraction = trace->fraction; pml->groundTrace.normal[0] = trace->normal[0]; pml->groundTrace.normal[1] = trace->normal[1]; @@ -79,6 +78,7 @@ namespace Components { Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7); + // Allow the player to stand even when there is no headroom if (Elevators::SV_Elevators.get() == Elevators::EASY) { trace->allsolid = false; @@ -122,7 +122,10 @@ namespace Components Elevators::ENABLED, Game::DVAR_FLAG_REPLICATED, "Elevators glitch settings"); }); + //Replace PM_CorrectAllSolid Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); + + // Place hook in PM_CheckDuck Utils::Hook(0x570EC5, Elevators::PM_TraceStub, HOOK_CALL).install()->quick(); } From ec3cbb4d7c063f7d17376ea967095370b8441cda Mon Sep 17 00:00:00 2001 From: Edo Date: Sun, 26 Dec 2021 17:22:42 +0100 Subject: [PATCH 3/5] Commit suggestion Bad copy paste on my end Co-authored-by: Jan --- src/Components/Modules/Elevators.cpp | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index 8195a273..bba565cc 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -36,19 +36,7 @@ namespace Components // like later versions of the game do if (!trace->startsolid || EleSettings >= Elevators::ENABLED) { - pml->groundTrace.fraction = trace->fraction; - pml->groundTrace.normal[0] = trace->normal[0]; - pml->groundTrace.normal[1] = trace->normal[1]; - pml->groundTrace.normal[2] = trace->normal[2]; - - pml->groundTrace.surfaceFlags = trace->surfaceFlags; - pml->groundTrace.contents = trace->contents; - pml->groundTrace.hitType = trace->hitType; - pml->groundTrace.hitId = trace->hitId; - - pml->groundTrace.partName = trace->partName; - pml->groundTrace.partGroup = trace->partGroup; - pml->groundTrace.walkable = trace->walkable; + pml->groundTrace = *trace; const auto fraction = trace->fraction; ps->origin[0] += fraction * (point[0] - ps->origin[0]); From ec43adda5989eb90f41d1c2bf5e90ba0574d4839 Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 26 Dec 2021 17:25:13 +0100 Subject: [PATCH 4/5] Address parts of review --- src/Components/Modules/Elevators.cpp | 24 ++++++++++++------------ src/Components/Modules/Elevators.hpp | 4 ++-- src/Game/Structs.hpp | 8 +++++--- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index 8195a273..fa1df9fd 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -2,7 +2,7 @@ namespace Components { - Dvar::Var Elevators::SV_Elevators; + Dvar::Var Elevators::BG_Elevators; int Elevators::PM_CorrectAllSolid(Game::pmove_s* pm, Game::pml_t* pml, Game::trace_t* trace) { @@ -13,8 +13,8 @@ namespace Components auto* ps = pm->ps; auto i = 0; - const auto EleSettings = Elevators::SV_Elevators.get(); - while (TRUE) + const auto elevatorSetting = Elevators::BG_Elevators.get(); + while (true) { point[0] = ps->origin[0] + Game::CorrectSolidDeltas[i][0]; point[1] = ps->origin[1] + Game::CorrectSolidDeltas[i][1]; @@ -23,7 +23,7 @@ namespace Components Game::PM_playerTrace(pm, trace, point, point, &pm->bounds, ps->clientNum, pm->tracemask); // If the player wishes to glitch without effort they can do so - if (!trace->startsolid || EleSettings == Elevators::EASY) + if (!trace->startsolid || elevatorSetting == Elevators::EASY) { ps->origin[0] = point[0]; ps->origin[1] = point[1]; @@ -34,7 +34,7 @@ namespace Components // If elevators are disabled we need to check that startsolid is false before proceeding // like later versions of the game do - if (!trace->startsolid || EleSettings >= Elevators::ENABLED) + if (!trace->startsolid || elevatorSetting >= Elevators::ENABLED) { pml->groundTrace.fraction = trace->fraction; pml->groundTrace.normal[0] = trace->normal[0]; @@ -73,13 +73,13 @@ namespace Components return 1; } - void Elevators::PM_TraceStub(Game::pmove_s* pm, Game::trace_t* trace, const float* f3, + void Elevators::PM_Trace_Hk(Game::pmove_s* pm, Game::trace_t* trace, const float* f3, const float* f4, const Game::Bounds* bounds, int a6, int a7) { Game::PM_Trace(pm, trace, f3, f4, bounds, a6, a7); // Allow the player to stand even when there is no headroom - if (Elevators::SV_Elevators.get() == Elevators::EASY) + if (Elevators::BG_Elevators.get() == Elevators::EASY) { trace->allsolid = false; } @@ -112,13 +112,13 @@ namespace Components { static const char* values[] = { - "Disable elevators", - "Enable elevators", - "Enable easy elevators", + "off", + "normal", + "easy", nullptr }; - Elevators::SV_Elevators = Game::Dvar_RegisterEnum("sv_Elevators", values, + Elevators::BG_Elevators = Game::Dvar_RegisterEnum("bg_elevators", values, Elevators::ENABLED, Game::DVAR_FLAG_REPLICATED, "Elevators glitch settings"); }); @@ -126,7 +126,7 @@ namespace Components Utils::Hook(0x57369E, Elevators::PM_CorrectAllSolidStub, HOOK_CALL).install()->quick(); // Place hook in PM_CheckDuck - Utils::Hook(0x570EC5, Elevators::PM_TraceStub, HOOK_CALL).install()->quick(); + Utils::Hook(0x570EC5, Elevators::PM_Trace_Hk, HOOK_CALL).install()->quick(); } Elevators::~Elevators() diff --git a/src/Components/Modules/Elevators.hpp b/src/Components/Modules/Elevators.hpp index ff490a31..02b0b64e 100644 --- a/src/Components/Modules/Elevators.hpp +++ b/src/Components/Modules/Elevators.hpp @@ -10,10 +10,10 @@ namespace Components private: enum ElevatorSettings { DISABLED, ENABLED, EASY }; - static Dvar::Var SV_Elevators; + static Dvar::Var BG_Elevators; static int PM_CorrectAllSolid(Game::pmove_s* move, Game::pml_t* pml, Game::trace_t* trace); static void PM_CorrectAllSolidStub(); - static void PM_TraceStub(Game::pmove_s*, Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int); + static void PM_Trace_Hk(Game::pmove_s*, Game::trace_t*, const float*, const float*, const Game::Bounds*, int, int); }; } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 63acd2a4..bad13871 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -6985,16 +6985,15 @@ namespace Game TRACE_HITTYPE_GLASS = 4 }; -#pragma pack(push, 1) struct trace_t { float fraction; float normal[3]; int surfaceFlags; int contents; + const char* material; TraceHitType hitType; unsigned __int16 hitId; - float fractionForHitType; unsigned __int16 modelIndex; unsigned __int16 partName; unsigned __int16 partGroup; @@ -7002,7 +7001,8 @@ namespace Game bool startsolid; bool walkable; }; -#pragma pack(pop) + + static_assert(sizeof(trace_t) == 0x2C); struct pmove_s { @@ -7045,6 +7045,8 @@ namespace Game int holdrand; }; + static_assert(sizeof(pml_t) == 0x84); + enum EffectiveStance { PM_EFF_STANCE_DEFAULT = 0, From 41874769aa3a57337a0d58ac779592302c207d0a Mon Sep 17 00:00:00 2001 From: Diavolo Date: Sun, 26 Dec 2021 17:33:48 +0100 Subject: [PATCH 5/5] Address review --- src/Components/Modules/Elevators.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Components/Modules/Elevators.cpp b/src/Components/Modules/Elevators.cpp index 224aba21..f9f42354 100644 --- a/src/Components/Modules/Elevators.cpp +++ b/src/Components/Modules/Elevators.cpp @@ -36,12 +36,6 @@ namespace Components // like later versions of the game do if (!trace->startsolid || elevatorSetting >= Elevators::ENABLED) { - pml->groundTrace = *trace; - - const auto fraction = trace->fraction; - ps->origin[0] += fraction * (point[0] - ps->origin[0]); - ps->origin[1] += fraction * (point[1] - ps->origin[1]); - ps->origin[2] += fraction * (point[2] - ps->origin[2]); break; } } @@ -58,6 +52,13 @@ namespace Components } } + pml->groundTrace = *trace; + + const auto fraction = trace->fraction; + ps->origin[0] += fraction * (point[0] - ps->origin[0]); + ps->origin[1] += fraction * (point[1] - ps->origin[1]); + ps->origin[2] += fraction * (point[2] - ps->origin[2]); + return 1; }