From 3965dda89335f653aa06c0180204759e836010cc Mon Sep 17 00:00:00 2001 From: szapp Date: Sat, 25 Feb 2017 01:51:24 +0100 Subject: [PATCH] Fix #105 trace ray performance The cause for the performance drops was an awkwardly hooked function (see #105) which caused the trace ray machinery to be run ten times per freame during aiming in ranged combat. This is now resolved (tenfold speed-up). Performance can be further boosted by a new entry in the ini file which introduces an adjustable recalculation frequency in milliseconds. By default the trace ray/focus collection is recalculated at each frame. When increasing the interval (to up to 500 ms) the focus collection becomes less precise, but might boost the performance slightly on weak machines (powerful machines will not benefit from this setting and should keep the value close to zero). Caution: Increasing this value beyond 45 ms will introduce a stutter in spells like blink that continually visualize the aim vob. --- .../Scripts/Content/freeAim/_intern/aimRay.d | 293 +++++++++--------- .../Content/freeAim/_intern/ccommands.d | 3 +- .../Scripts/Content/freeAim/_intern/const.d | 3 +- .../Scripts/Content/freeAim/_intern/init.d | 7 +- .../Scripts/Content/freeAim/_intern/ranged.d | 15 +- 5 files changed, 166 insertions(+), 155 deletions(-) diff --git a/_work/data/Scripts/Content/freeAim/_intern/aimRay.d b/_work/data/Scripts/Content/freeAim/_intern/aimRay.d index 8c5c3cb..81775be 100644 --- a/_work/data/Scripts/Content/freeAim/_intern/aimRay.d +++ b/_work/data/Scripts/Content/freeAim/_intern/aimRay.d @@ -24,121 +24,7 @@ /* Shoot aim-tailored trace ray. Do no use for other purposes. This function is customized for aiming. */ func int freeAimRay(var int distance, var int focusType, var int vobPtr, var int posPtr, var int distPtr, var int trueDistPtr) { - // Flags: VOB_IGNORE_NO_CD_DYN | POLY_IGNORE_TRANSP | POLY_TEST_WATER | VOB_IGNORE_PROJECTILES - var int flags; flags = (1<<0) | (1<<8) | (1<<9) | (1<<14); // Do not change (will make trace ray unstable) - var zMAT4 camPos; camPos = _^(MEM_ReadInt(MEM_ReadInt(MEMINT_oGame_Pointer_Address)+20)+60); //0=right, 2=out, 3=pos var int herPtr; herPtr = _@(hero); - // Shift the start point for the trace ray beyond the player model. Necessary, because if zooming out, - // (1) there might be something between camera and hero and (2) the maximum aiming distance is off. - var int dist; dist = sqrtf(addf(addf( // Distance between camera and player model (does not care about cam offset) - sqrf(subf(MEM_ReadInt(herPtr+72), camPos.v0[3])), - sqrf(subf(MEM_ReadInt(herPtr+88), camPos.v1[3]))), - sqrf(subf(MEM_ReadInt(herPtr+104), camPos.v2[3])))); - if (FREEAIM_CAMERA_X_SHIFT) { // Shifting the camera (shoulderview) is not recommended. Aiming is harder + less fps? - // This makes the distance mentioned above more complex and requires the calculation of a point-line distance - // For illustration: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html - var int line[6]; // Line with two points along the camera right vector at the level of the player model - line[0] = subf(MEM_ReadInt(herPtr+72), mulf(camPos.v0[0], FLOAT1K)); // Left of player model - line[1] = subf(MEM_ReadInt(herPtr+88), mulf(camPos.v1[0], FLOAT1K)); - line[2] = subf(MEM_ReadInt(herPtr+104), mulf(camPos.v2[0], FLOAT1K)); - line[3] = addf(MEM_ReadInt(herPtr+72), mulf(camPos.v0[0], FLOAT1K)); // Right of player model - line[4] = addf(MEM_ReadInt(herPtr+88), mulf(camPos.v1[0], FLOAT1K)); - line[5] = addf(MEM_ReadInt(herPtr+104), mulf(camPos.v2[0], FLOAT1K)); - var int u[3]; var int v[3]; // Subtract both points of the line from the camera position - u[0] = subf(camPos.v0[3], line[0]); v[0] = subf(camPos.v0[3], line[3]); - u[1] = subf(camPos.v1[3], line[1]); v[1] = subf(camPos.v1[3], line[4]); - u[2] = subf(camPos.v2[3], line[2]); v[2] = subf(camPos.v2[3], line[5]); - var int crossProd[3]; // Cross-product - crossProd[0] = subf(mulf(u[1], v[2]), mulf(u[2], v[1])); - crossProd[1] = subf(mulf(u[2], v[0]), mulf(u[0], v[2])); - crossProd[2] = subf(mulf(u[0], v[1]), mulf(u[1], v[0])); - dist = sqrtf(addf(addf(sqrf(crossProd[0]), sqrf(crossProd[1])), sqrf(crossProd[2]))); - dist = divf(dist, mkf(2000)); // Divide area of triangle by length between the points on the line - }; - var int traceRayVec[6]; - traceRayVec[0] = addf(camPos.v0[3], mulf(camPos.v0[2], dist)); // Start ray from here - traceRayVec[1] = addf(camPos.v1[3], mulf(camPos.v1[2], dist)); - traceRayVec[2] = addf(camPos.v2[3], mulf(camPos.v2[2], dist)); - traceRayVec[3] = mulf(camPos.v0[2], mkf(distance)); // Direction-/to-vector of ray - traceRayVec[4] = mulf(camPos.v1[2], mkf(distance)); - traceRayVec[5] = mulf(camPos.v2[2], mkf(distance)); - var int fromPosPtr; fromPosPtr = _@(traceRayVec); - var int dirPosPtr; dirPosPtr = _@(traceRayVec)+12; - var int worldPtr; worldPtr = _@(MEM_World); - const int call = 0; - if (CALL_Begin(call)) { - CALL_IntParam(_@(flags)); // Trace ray flags - CALL_PtrParam(_@(herPtr)); // Ignore player model - CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction - CALL__fastcall(_@(worldPtr), _@(fromPosPtr), zCWorld__TraceRayNearestHit_Vob); - call = CALL_End(); - }; - var int found; found = CALL_RetValAsInt(); // Did the trace ray hit - if (!found) && (!MEM_World.foundVob) { // Fix the intersection if there was no hit (trace ray is inconsistent) - MEM_World.foundIntersection[0] = addf(traceRayVec[0], traceRayVec[3]); - MEM_World.foundIntersection[1] = addf(traceRayVec[1], traceRayVec[4]); - MEM_World.foundIntersection[2] = addf(traceRayVec[2], traceRayVec[5]); - }; - var int foundFocus; foundFocus = 0; // Is the focus vob in the trace ray vob list - var int potentialVob; potentialVob = MEM_ReadInt(herPtr+2476); // oCNpc.focus_vob // Focus vob by focus collection - if (potentialVob) { // Check if collected focus matches the desired focus type - var int runDetailedTraceRay; runDetailedTraceRay = 0; // Second trace ray only if focus vob is reasonable - if (!focusType) { // No focus vob (still a trace ray though) - foundFocus = 0; - } else if (focusType != TARGET_TYPE_ITEMS) && (Hlp_Is_oCNpc(potentialVob)) { // Validate focus vob, if it is npc - var C_Npc target; target = _^(potentialVob); - MEM_PushInstParam(target); // Function is not defined yet at time of parsing: - MEM_Call(C_NpcIsUndead); // C_NpcIsUndead(target); - var int npcIsUndead; npcIsUndead = MEM_PopIntResult(); - if ((focusType == TARGET_TYPE_NPCS) // Any npc - || ((focusType == TARGET_TYPE_ORCS) && target.guild > GIL_SEPERATOR_ORC) // Only focus orcs - || ((focusType == TARGET_TYPE_HUMANS) && target.guild < GIL_SEPERATOR_HUM) // Only focus humans - || ((focusType == TARGET_TYPE_UNDEAD) && npcIsUndead)) // Only focus undead npcs - && (!Npc_IsInState(target, ZS_Unconscious)) // Do not allow focusing npcs that are down - && (!Npc_IsInState(target, ZS_MagicSleep)) - && (!Npc_IsDead(target)) { - var int potVobPtr; potVobPtr = _@(potentialVob); - var int voblist; voblist = _@(MEM_World.traceRayVobList_array); - const int call2 = 0; - if (CALL_Begin(call2)) { // More complicated for npcs: Check if npc is in trace ray vob list - CALL_PtrParam(_@(potVobPtr)); // Explanation: Npcs are never HIT by a trace ray (only collected) - CALL__thiscall(_@(voblist), zCArray_zCVob__IsInList); - call2 = CALL_End(); - }; - runDetailedTraceRay = CALL_RetValAsInt(); // Will perform detailed trace ray if npc was in vob list - }; - } else if (focusType <= TARGET_TYPE_ITEMS) && (Hlp_Is_oCItem(potentialVob)) { - runDetailedTraceRay = 1; // Will perform detailed trace ray - }; - if (runDetailedTraceRay) { // If focus collection is reasonable, run a more detailed examination - // zCWorld::TraceRayNearestHit (0x621D82 in g2) - flags = (1<<0) | (1<<2); // (zTRACERAY_VOB_IGNORE_NO_CD_DYN | zTRACERAY_VOB_BBOX) // Important! - var int trRep; trRep = MEM_Alloc(40); // sizeof_zTTraceRayReport - const int call3 = 0; - if (CALL_Begin(call3)) { - CALL_PtrParam(_@(trRep)); // zTTraceRayReport - CALL_IntParam(_@(flags)); // Trace ray flags - CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction - CALL_PtrParam(_@(fromPosPtr)); // Start vector - CALL__thiscall(_@(potentialVob), zCVob__TraceRay); // This is a vob specific trace ray - call3 = CALL_End(); - }; - if (CALL_RetValAsInt()) { // Got a hit: Update trace ray report - MEM_World.foundVob = potentialVob; - MEM_CopyWords(trRep+12, _@(MEM_World.foundIntersection), 3); // 0x0C zVEC3 - foundFocus = potentialVob; // Confirmed focus vob - }; - MEM_Free(trRep); // Free the report - }; - }; - if (foundFocus != potentialVob) { // If focus vob changed by the validation above - const int call4 = 0; // Set the focus vob properly: reference counter - if (CALL_Begin(call4)) { - CALL_PtrParam(_@(foundFocus)); // If no valid focus was found, this will remove the focus (foundFocus == 0) - CALL__thiscall(_@(herPtr), oCNpc__SetFocusVob); - call4 = CALL_End(); - }; - }; if (MEM_ReadInt(herPtr+1176)) { //0x0498 oCNpc.enemy const int call5 = 0; var int null; // Remove the enemy properly: reference counter if (CALL_Begin(call5)) { @@ -147,36 +33,155 @@ func int freeAimRay(var int distance, var int focusType, var int vobPtr, var int call5 = CALL_End(); }; }; - // Debug visualization - if (FREEAIM_DEBUG_TRACERAY) { - freeAimDebugTRBBox[0] = subf(MEM_World.foundIntersection[0], mkf(5)); - freeAimDebugTRBBox[1] = subf(MEM_World.foundIntersection[1], mkf(5)); - freeAimDebugTRBBox[2] = subf(MEM_World.foundIntersection[2], mkf(5)); - freeAimDebugTRBBox[3] = addf(freeAimDebugTRBBox[0], mkf(10)); - freeAimDebugTRBBox[4] = addf(freeAimDebugTRBBox[1], mkf(10)); - freeAimDebugTRBBox[5] = addf(freeAimDebugTRBBox[2], mkf(10)); - MEM_CopyWords(_@(traceRayVec), _@(freeAimDebugTRTrj), 3); - freeAimDebugTRTrj[3] = addf(traceRayVec[0], traceRayVec[3]); - freeAimDebugTRTrj[4] = addf(traceRayVec[1], traceRayVec[4]); - freeAimDebugTRTrj[5] = addf(traceRayVec[2], traceRayVec[5]); - if (MEM_World.foundVob) { freeAimDebugTRPrevVob = MEM_World.foundVob+124; } else { freeAimDebugTRPrevVob = 0; }; + // Only run full trace ray machinery every so often (see freeAimTraceRayFreq) + var int curTime; curTime = MEM_Timer.totalTime; + if (curTime-prevCalculationTime >= freeAimTraceRayFreq) || (foundFocus != MEM_ReadInt(herPtr+2476)) { + var int prevCalculationTime; prevCalculationTime = curTime; + // Flags: VOB_IGNORE_NO_CD_DYN | POLY_IGNORE_TRANSP | POLY_TEST_WATER | VOB_IGNORE_PROJECTILES + var int flags; flags = (1<<0) | (1<<8) | (1<<9) | (1<<14); // Do not change (will make trace ray unstable) + var zMAT4 camPos; camPos = _^(MEM_ReadInt(MEM_ReadInt(MEMINT_oGame_Pointer_Address)+20)+60); + // Shift the start point for the trace ray beyond the player model. Necessary, because if zooming out, + // (1) there might be something between camera and hero and (2) the maximum aiming distance is off. + var int distCamToPlayer; distCamToPlayer = sqrtf(addf(addf( // Does not care about camera offset (camera shift) + sqrf(subf(MEM_ReadInt(herPtr+72), camPos.v0[3])), + sqrf(subf(MEM_ReadInt(herPtr+88), camPos.v1[3]))), + sqrf(subf(MEM_ReadInt(herPtr+104), camPos.v2[3])))); + if (FREEAIM_CAMERA_X_SHIFT) { // Shifting camera (shoulderview) is not recommended. Aiming is harder + less fps? + // This makes the distance mentioned above more complex and requires calculation of a point-line distance + // For illustration: http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + var int line[6]; // Line with two points along the camera right vector at the level of the player model + line[0] = subf(MEM_ReadInt(herPtr+72), mulf(camPos.v0[0], FLOAT1K)); // Left of player model + line[1] = subf(MEM_ReadInt(herPtr+88), mulf(camPos.v1[0], FLOAT1K)); + line[2] = subf(MEM_ReadInt(herPtr+104), mulf(camPos.v2[0], FLOAT1K)); + line[3] = addf(MEM_ReadInt(herPtr+72), mulf(camPos.v0[0], FLOAT1K)); // Right of player model + line[4] = addf(MEM_ReadInt(herPtr+88), mulf(camPos.v1[0], FLOAT1K)); + line[5] = addf(MEM_ReadInt(herPtr+104), mulf(camPos.v2[0], FLOAT1K)); + var int u[3]; var int v[3]; // Subtract both points of the line from the camera position + u[0] = subf(camPos.v0[3], line[0]); v[0] = subf(camPos.v0[3], line[3]); + u[1] = subf(camPos.v1[3], line[1]); v[1] = subf(camPos.v1[3], line[4]); + u[2] = subf(camPos.v2[3], line[2]); v[2] = subf(camPos.v2[3], line[5]); + var int crossProd[3]; // Cross-product + crossProd[0] = subf(mulf(u[1], v[2]), mulf(u[2], v[1])); + crossProd[1] = subf(mulf(u[2], v[0]), mulf(u[0], v[2])); + crossProd[2] = subf(mulf(u[0], v[1]), mulf(u[1], v[0])); + distCamToPlayer = sqrtf(addf(addf(sqrf(crossProd[0]), sqrf(crossProd[1])), sqrf(crossProd[2]))); + distCamToPlayer = divf(distCamToPlayer, mkf(2000)); // Divide area of triangle by length between points + }; + distance = mkf(distance); + var int traceRayVec[6]; + traceRayVec[0] = addf(camPos.v0[3], mulf(camPos.v0[2], distCamToPlayer)); // Start ray from here + traceRayVec[1] = addf(camPos.v1[3], mulf(camPos.v1[2], distCamToPlayer)); + traceRayVec[2] = addf(camPos.v2[3], mulf(camPos.v2[2], distCamToPlayer)); + traceRayVec[3] = mulf(camPos.v0[2], distance); // Direction-/to-vector of ray + traceRayVec[4] = mulf(camPos.v1[2], distance); + traceRayVec[5] = mulf(camPos.v2[2], distance); + var int fromPosPtr; fromPosPtr = _@(traceRayVec); + var int dirPosPtr; dirPosPtr = _@(traceRayVec)+12; + var int worldPtr; worldPtr = _@(MEM_World); + const int call = 0; + if (CALL_Begin(call)) { + CALL_IntParam(_@(flags)); // Trace ray flags + CALL_PtrParam(_@(herPtr)); // Ignore player model + CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction + CALL__fastcall(_@(worldPtr), _@(fromPosPtr), zCWorld__TraceRayNearestHit_Vob); + call = CALL_End(); + }; + var int hit; hit = CALL_RetValAsInt(); // Did the trace ray hit + var int foundVob; foundVob = MEM_World.foundVob; + var int intersection[3]; MEM_CopyWords(_@(MEM_World.foundIntersection), _@(intersection), 3); + var int distHitToPlayer; + if (!hit) && (!foundVob) { // Fix the intersection if there was no hit (trace ray is inconsistent) + intersection[0] = addf(traceRayVec[0], traceRayVec[3]); + intersection[1] = addf(traceRayVec[1], traceRayVec[4]); + intersection[2] = addf(traceRayVec[2], traceRayVec[5]); + distHitToPlayer = distance; // Maximum distance of trace ray + } else { + distHitToPlayer = sqrtf(addf(addf( + sqrf(subf(intersection[0], traceRayVec[0])), + sqrf(subf(intersection[1], traceRayVec[1]))), + sqrf(subf(intersection[2], traceRayVec[2])))); + }; + var int distHitToCam; distHitToCam = addf(distHitToPlayer, distCamToPlayer); + var int foundFocus; foundFocus = 0; // Is the focus vob in the trace ray vob list + var int potentialVob; potentialVob = MEM_ReadInt(herPtr+2476); // oCNpc.focus_vob // Focus vob by f-collection + if (potentialVob) { // Check if collected focus matches the desired focus type + var int runDetailedTraceRay; runDetailedTraceRay = 0; // Second trace ray only if focus vob is reasonable + if (!focusType) { // No focus vob (still a trace ray though) + foundFocus = 0; + } else if (focusType != TARGET_TYPE_ITEMS) && (Hlp_Is_oCNpc(potentialVob)) { // Validate focus vob, if npc + var C_Npc target; target = _^(potentialVob); + MEM_PushInstParam(target); // Function is not defined yet at time of parsing: + MEM_Call(C_NpcIsUndead); // C_NpcIsUndead(target); + var int npcIsUndead; npcIsUndead = MEM_PopIntResult(); + MEM_PushInstParam(target); // Function is not defined yet at time of parsing: + MEM_Call(C_NpcIsDown); // C_NpcIsDown(target); + var int npcIsDown; npcIsUndead = MEM_PopIntResult(); + if ((focusType == TARGET_TYPE_NPCS) // Any npc + || ((focusType == TARGET_TYPE_ORCS) && target.guild > GIL_SEPERATOR_ORC) // Only focus orcs + || ((focusType == TARGET_TYPE_HUMANS) && target.guild < GIL_SEPERATOR_HUM) // Only focus humans + || ((focusType == TARGET_TYPE_UNDEAD) && npcIsUndead)) // Only focus undead npcs + && (!npcIsDown) { + var int potVobPtr; potVobPtr = _@(potentialVob); + var int voblist; voblist = _@(MEM_World.traceRayVobList_array); + const int call2 = 0; + if (CALL_Begin(call2)) { // More complicated for npcs: Check if npc is in trace ray vob list + CALL_PtrParam(_@(potVobPtr)); // Explanation: Npcs are never HIT by a trace ray (only collected) + CALL__thiscall(_@(voblist), zCArray_zCVob__IsInList); + call2 = CALL_End(); + }; + runDetailedTraceRay = CALL_RetValAsInt(); // Will perform detailed trace ray if npc was in vob list + }; + } else if (focusType <= TARGET_TYPE_ITEMS) && (Hlp_Is_oCItem(potentialVob)) { + runDetailedTraceRay = 1; // Will perform detailed trace ray + }; + if (runDetailedTraceRay) { // If focus collection is reasonable, run a more detailed examination + // zCWorld::TraceRayNearestHit (0x621D82 in g2) + flags = (1<<0) | (1<<2); // (zTRACERAY_VOB_IGNORE_NO_CD_DYN | zTRACERAY_VOB_BBOX) // Important! + var int trRep; trRep = MEM_Alloc(40); // sizeof_zTTraceRayReport + const int call3 = 0; + if (CALL_Begin(call3)) { + CALL_PtrParam(_@(trRep)); // zTTraceRayReport + CALL_IntParam(_@(flags)); // Trace ray flags + CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction + CALL_PtrParam(_@(fromPosPtr)); // Start vector + CALL__thiscall(_@(potentialVob), zCVob__TraceRay); // This is a vob specific trace ray + call3 = CALL_End(); + }; + if (CALL_RetValAsInt()) { // Got a hit: Update trace ray report + foundVob = potentialVob; + MEM_CopyWords(trRep+12, _@(intersection), 3); // 0x0C zVEC3 + foundFocus = potentialVob; // Confirmed focus vob + }; + MEM_Free(trRep); // Free the report + }; + }; + if (foundFocus != potentialVob) { // If focus vob changed by the validation above + const int call4 = 0; // Set the focus vob properly: reference counter + if (CALL_Begin(call4)) { + CALL_PtrParam(_@(foundFocus)); // If no valid focus found, this will remove the focus (foundFocus == 0) + CALL__thiscall(_@(herPtr), oCNpc__SetFocusVob); + call4 = CALL_End(); + }; + }; + // Debug visualization + if (FREEAIM_DEBUG_TRACERAY) { + freeAimDebugTRBBox[0] = subf(intersection[0], mkf(5)); + freeAimDebugTRBBox[1] = subf(intersection[1], mkf(5)); + freeAimDebugTRBBox[2] = subf(intersection[2], mkf(5)); + freeAimDebugTRBBox[3] = addf(freeAimDebugTRBBox[0], mkf(10)); + freeAimDebugTRBBox[4] = addf(freeAimDebugTRBBox[1], mkf(10)); + freeAimDebugTRBBox[5] = addf(freeAimDebugTRBBox[2], mkf(10)); + MEM_CopyWords(_@(traceRayVec), _@(freeAimDebugTRTrj), 3); + freeAimDebugTRTrj[3] = addf(traceRayVec[0], traceRayVec[3]); + freeAimDebugTRTrj[4] = addf(traceRayVec[1], traceRayVec[4]); + freeAimDebugTRTrj[5] = addf(traceRayVec[2], traceRayVec[5]); + if (foundVob) { freeAimDebugTRPrevVob = foundVob+124; } else { freeAimDebugTRPrevVob = 0; }; + }; }; // Write call-by-reference variables - if (vobPtr) { MEM_WriteInt(vobPtr, MEM_World.foundVob); }; - if (posPtr) { MEM_CopyWords(_@(MEM_World.foundIntersection), posPtr, 3); }; - if (distPtr) { // Distance between intersection and player model - distance = sqrtf(addf(addf( - sqrf(subf(MEM_World.foundIntersection[0], traceRayVec[0])), - sqrf(subf(MEM_World.foundIntersection[1], traceRayVec[1]))), - sqrf(subf(MEM_World.foundIntersection[2], traceRayVec[2])))); - MEM_WriteInt(distPtr, distance); - }; - if (trueDistPtr) { // Distance between intersection and camera - distance = sqrtf(addf(addf( - sqrf(subf(MEM_World.foundIntersection[0], camPos.v0[3])), - sqrf(subf(MEM_World.foundIntersection[1], camPos.v1[3]))), - sqrf(subf(MEM_World.foundIntersection[2], camPos.v2[3])))); - MEM_WriteInt(trueDistPtr, distance); - }; - return found; + if (vobPtr) { MEM_WriteInt(vobPtr, foundVob); }; + if (posPtr) { MEM_CopyWords(_@(intersection), posPtr, 3); }; + if (distPtr) { MEM_WriteInt(distPtr, distHitToPlayer); }; + if (trueDistPtr) { MEM_WriteInt(trueDistPtr, distHitToCam); }; + return hit; }; diff --git a/_work/data/Scripts/Content/freeAim/_intern/ccommands.d b/_work/data/Scripts/Content/freeAim/_intern/ccommands.d index 7be1b8d..df37584 100644 --- a/_work/data/Scripts/Content/freeAim/_intern/ccommands.d +++ b/_work/data/Scripts/Content/freeAim/_intern/ccommands.d @@ -55,7 +55,8 @@ func string freeAimInfo(var string command) { var int s; s = SB_New(); SB(FREEAIM_VERSION); SBc(13); SBc(10); SB("Enabled: "); SB(MEM_ReadStatStringArr(onOff, STR_ToInt(MEM_GetGothOpt("FREEAIM", "enabled")))); SBc(13);SBc(10); - SB("Focus: "); SB(MEM_ReadStatStringArr(onOff, FREEAIM_FOCUS_COLLECTION)); SBc(13); SBc(10); + SB("Focus: "); SB(MEM_ReadStatStringArr(onOff, FREEAIM_FOCUS_COLLECTION)); + SB(" ("); SBi(freeAimTraceRayFreq); SB(" ms collection frequency)"); SBc(13); SBc(10); SB("Reuse projectiles: "); SB(MEM_ReadStatStringArr(onOff, FREEAIM_REUSE_PROJECTILES)); SBc(13); SBc(10); SB("Free aim for spells: "); SB(MEM_ReadStatStringArr(onOff, !FREEAIM_DISABLE_SPELLS)); SBc(13); SBc(10); var string ret; ret = SB_ToString(); SB_Destroy(); diff --git a/_work/data/Scripts/Content/freeAim/_intern/const.d b/_work/data/Scripts/Content/freeAim/_intern/const.d index df1a6b9..f5a7cdd 100644 --- a/_work/data/Scripts/Content/freeAim/_intern/const.d +++ b/_work/data/Scripts/Content/freeAim/_intern/const.d @@ -37,6 +37,7 @@ const int FREEAIM_ARROWAI_REDIRECT = 0; // Used to redir const int FLOAT1C = 1120403456; // 100 as float const int FLOAT3C = 1133903872; // 300 as float const int FLOAT1K = 1148846080; // 1000 as float +var int freeAimTraceRayFreq; // Trace ray frequency (change in ini-file) var int freeAimDebugWSBBox[6]; // Weaksopt boundingbox for debug visualization var int freeAimDebugWSTrj[6]; // Projectile trajectory for debug visualization var int freeAimDebugTRBBox[6]; // Trace ray intersection for debug visualization @@ -80,7 +81,7 @@ const int mouseSensX = 9019720; //0x89A148 const int mouseDeltaX = 9246300; //0x8D165C const int projectileDeflectOffNpcAddr = 6949734; //0x6A0B66 const int zCWorld__AdvanceClock = 6447328; //0x6260E0 // Hook length 10 -const int oCAniCtrl_Human__InterpolateCombineAni = 7037296; //0x6B6170 // Hook length 5 +const int oCAIHuman__BowMode_696296 = 6906518; //0x696296 // Hook length 5 const int oCAIArrow__SetupAIVob = 6951136; //0x6A10E0 // Hook length 6 const int oCAIArrow__CanThisCollideWith = 6952080; //0x6A1490 // Hook length 7 const int oCAIHuman__BowMode = 6905600; //0x695F00 // Hook length 6 diff --git a/_work/data/Scripts/Content/freeAim/_intern/init.d b/_work/data/Scripts/Content/freeAim/_intern/init.d index 8603ceb..824ffc3 100644 --- a/_work/data/Scripts/Content/freeAim/_intern/init.d +++ b/_work/data/Scripts/Content/freeAim/_intern/init.d @@ -36,7 +36,7 @@ func void freeAim_Init() { CC_Register(freeAimVersion, "freeaim version", "print freeaim version info"); CC_Register(freeAimLicense, "freeaim license", "print freeaim license info"); CC_Register(freeAimInfo, "freeaim info", "print freeaim info"); - HookEngineF(oCAniCtrl_Human__InterpolateCombineAni, 5, freeAimAnimation); // Update aiming animation + HookEngineF(oCAIHuman__BowMode_696296, 5, freeAimAnimation); // Update aiming animation HookEngineF(oCAIArrow__SetupAIVob, 6, freeAimSetupProjectile); // Set projectile direction and trajectory HookEngineF(oCAIHuman__BowMode, 6, freeAimManageReticle); // Manage the reticle (on/off) HookEngineF(oCNpcFocus__SetFocusMode, 7, freeAimSwitchMode); // Manage the reticle (on/off) and draw force @@ -72,7 +72,10 @@ func void freeAim_Init() { if (!MEM_GothOptExists("FREEAIM", "enabled")) { MEM_SetGothOpt("FREEAIM", "enabled", "1"); }; // If not set if (!MEM_GothOptExists("FREEAIM", "focusEnabled")) { MEM_SetGothOpt("FREEAIM", "focusEnabled", "1"); } else if (!STR_ToInt(MEM_GetGothOpt("FREEAIM", "focusEnabled"))) { - FREEAIM_FOCUS_COLLECTION = 0; }; // No focuscollection (performance) not recommended + FREEAIM_FOCUS_COLLECTION = 0; }; // No focus collection (performance) not recommended + if (!MEM_GothOptExists("FREEAIM", "focusCollFreqMS")) { MEM_SetGothOpt("FREEAIM", "focusCollFreqMS", "10"); }; + freeAimTraceRayFreq = STR_ToInt(MEM_GetGothOpt("FREEAIM", "focusCollFreqMS")); + if (freeAimTraceRayFreq > 500) { freeAimTraceRayFreq = 500; }; // Recalculate trace ray intersection every x ms r_DefaultInit(); // Start rng for aiming accuracy hookFreeAim = 1; }; diff --git a/_work/data/Scripts/Content/freeAim/_intern/ranged.d b/_work/data/Scripts/Content/freeAim/_intern/ranged.d index 92fedf2..add0459 100644 --- a/_work/data/Scripts/Content/freeAim/_intern/ranged.d +++ b/_work/data/Scripts/Content/freeAim/_intern/ranged.d @@ -53,9 +53,10 @@ func void freeAimAnimation() { freeAimInsertReticle(_@(reticle)); // Draw/update reticle var zMAT4 camPos; camPos = _^(MEM_ReadInt(MEM_ReadInt(MEMINT_oGame_Pointer_Address)+20)+60); //0=right, 2=out, 3=pos var int pos[3]; // The position is calculated from the camera, not the player model - pos[0] = addf(camPos.v0[3], mulf(camPos.v0[2], mkf(FREEAIM_MAX_DIST))); - pos[1] = addf(camPos.v1[3], mulf(camPos.v1[2], mkf(FREEAIM_MAX_DIST))); - pos[2] = addf(camPos.v2[3], mulf(camPos.v2[2], mkf(FREEAIM_MAX_DIST))); + distance = mkf(FREEAIM_MAX_DIST); // Take the max distance, otherwise it looks strange on close range targets + pos[0] = addf(camPos.v0[3], mulf(camPos.v0[2], distance)); + pos[1] = addf(camPos.v1[3], mulf(camPos.v1[2], distance)); + pos[2] = addf(camPos.v2[3], mulf(camPos.v2[2], distance)); // Get aiming angles var int angleX; var int angXptr; angXptr = _@(angleX); var int angleY; var int angYptr; angYptr = _@(angleY); @@ -72,13 +73,13 @@ func void freeAimAnimation() { if (lf(angleY, FLOATNULL)) { angleY = -1098907648; } // -0.25 else { angleY = 1048576000; }; // 0.25 }; - // This following paragraph is essentially "copied" from oCAIHuman::BowMode (0x695F00 in g2) + // This following paragraph is inspired by oCAIHuman::BowMode (0x695F00 in g2) angleY = negf(subf(mulf(angleY, 1001786197), FLOATHALF)); // Scale and flip Y [-90° +90°] to [+1 0] if (lef(angleY, FLOATNULL)) { angleY = FLOATNULL; } // Maximum aim height (straight up) else if (gef(angleY, 1065353216)) { angleY = 1065353216; }; // Minimum aim height (down) - // New aiming coordinates. Overwrite the arguments passed to oCAniCtrl_Human::InterpolateCombineAni - MEM_WriteInt(ESP+4, FLOATHALF); // Always aim at center (x angle) - MEM_WriteInt(ESP+8, angleY); + // New aiming coordinates. Overwrite the arguments one and two passed to oCAniCtrl_Human::InterpolateCombineAni + MEM_WriteInt(ESP+20, FLOATHALF); // First argument: Always aim at center (azimuth) (esp+44h+30h) + ECX = angleY; // Second argument: New elevation }; /* Internal helper function for freeAimGetDrawForce() */