Skip to content

Commit

Permalink
Detect head node in focus collection
Browse files Browse the repository at this point in the history
  • Loading branch information
szapp committed Sep 29, 2017
1 parent e955974 commit 82e9bdb
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 32 deletions.
58 changes: 58 additions & 0 deletions _work/data/Scripts/Content/GFA/_intern/aimRay.d
Expand Up @@ -55,6 +55,55 @@ func void GFA_AllowSoftSkinTraceRay(var int on) {
};


/*
* Cast a specific ray to detect intersection with the head node of NPCs. This is necessary, because for NPCs with
* dedicated head visuals (like all humans and some orcs), the model trace ray used in GFA_AimRay() does not include the
* head node. This function is thus supplementary to GFA_AimRay() but also called from
* GFA_RefinedProjectileCollisionCheck().
*/
func int GFA_AimRayHead(var int npcPtr, var int fromPosPtr, var int dirPosPtr, var int vecPtr) {
var int hit; hit = FALSE;
var oCNpc npc; npc = _^(npcPtr);
if (!Hlp_StrCmp(npc.head_visualName, "") && (npc.anictrl)) {
// Perform a lot of safety checks, to prevent crashes
var zCAIPlayer playerAI; playerAI = _^(npc.anictrl);
if (playerAI.modelHeadNode) {
// Check if head has indeed a dedicated visual
var int headNode; headNode = playerAI.modelHeadNode;
if (MEM_ReadInt(headNode+zCModelNodeInst_visual_offset))
&& (objCheckInheritance(npc._zCVob_visual, zCModel__classDef)) {
// Calculate bounding boxes of model nodes
var int model; model = npc._zCVob_visual;
const int call = 0;
if (CALL_Begin(call)) {
CALL__thiscall(_@(model), zCModel__CalcNodeListBBoxWorld);
call = CALL_End();
};
var int headBBoxPtr; headBBoxPtr = headNode+zCModelNodeInst_bbox3D_offset;

// If information about the intersection is not requeted, create disposable vector
if (!vecPtr) {
var int vec[3];
vecPtr = _@(vec);
};

// Detect intersection with head bounding box
const int call2 = 0;
if (CALL_Begin(call2)) {
CALL_PtrParam(_@(vecPtr)); // Intersection vector (not needed)
CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction
CALL_PtrParam(_@(fromPosPtr)); // Start vector
CALL_PutRetValTo(_@(hit)); // Did the trace ray hit
CALL__thiscall(_@(headBBoxPtr), zTBBox3D__TraceRay); // This is a bounding box specific trace ray
call2 = CALL_End();
};
};
};
};
return +hit;
};


/*
* Shoot a trace ray to retrieve the point of intersection with the nearest object in the world and the distance, and to
* overwrite the focus collection with a desired focus type. This function is customized for aiming and it is not
Expand Down Expand Up @@ -200,6 +249,15 @@ func int GFA_AimRay(var int distance, var int focusType, var int vobPtr, var int
} else if (her.fmode == FMODE_MAGIC) {
// Aiming is not the priority for spells, a rougher focus collection is desired
secondRay = TRUE;
} else {
// Ranged combat: Additionally detect head node (not included in model trace ray)
var int headRay[3];
if (GFA_AimRayHead(her.focus_vob, fromPosPtr, dirPosPtr, _@(headRay))) {
foundVob = her.focus_vob;
MEM_CopyBytes(_@(headRay), _@(intersection), sizeof_zVEC3);
foundFocus = her.focus_vob;
};
secondRay = FALSE;
};
};
} else if (focusType <= TARGET_TYPE_ITEMS) && (Hlp_Is_oCItem(her.focus_vob)) {
Expand Down
34 changes: 2 additions & 32 deletions _work/data/Scripts/Content/GFA/_intern/rangedShooting.d
Expand Up @@ -670,38 +670,8 @@ func int GFA_RefinedProjectileCollisionCheck(var int vobPtr, var int arrowAI) {
GFA_AllowSoftSkinTraceRay(0);

// Also check dedicated head visual if present (not detected by model trace ray)
var oCNpc npc; npc = _^(vobPtr);
if (!hit) && (!Hlp_StrCmp(npc.head_visualName, "") && (npc.anictrl)) {
// Perform a lot of safety checks, to prevent crashes
var zCAIPlayer playerAI; playerAI = _^(npc.anictrl);
if (playerAI.modelHeadNode) {
// Check if head has indeed a dedicated visual
var int headNode; headNode = playerAI.modelHeadNode;
if (MEM_ReadInt(headNode+zCModelNodeInst_visual_offset))
&& (objCheckInheritance(npc._zCVob_visual, zCModel__classDef)) {
// Calculate bounding boxes of model nodes
var int model; model = npc._zCVob_visual;
const int call3 = 0;
if (CALL_Begin(call3)) {
CALL__thiscall(_@(model), zCModel__CalcNodeListBBoxWorld);
call3 = CALL_End();
};
var int headBBoxPtr; headBBoxPtr = headNode+zCModelNodeInst_bbox3D_offset;

// Detect intersection with head bounding box
var int vecPtr; vecPtr = MEM_Alloc(sizeof_zVEC3);
const int call4 = 0;
if (CALL_Begin(call4)) {
CALL_PtrParam(_@(vecPtr)); // Intersection vector (not needed)
CALL_PtrParam(_@(dirPosPtr)); // Trace ray direction
CALL_PtrParam(_@(fromPosPtr)); // Start vector
CALL_PutRetValTo(_@(hit)); // Did the trace ray hit
CALL__thiscall(_@(headBBoxPtr), zTBBox3D__TraceRay); // This is a bounding box specific trace ray
call4 = CALL_End();
};
MEM_Free(vecPtr);
};
};
if (!hit) {
hit = GFA_AimRayHead(vobPtr, fromPosPtr, dirPosPtr, 0);
};

// Add direction vector to position vector to form a line (for debug visualization)
Expand Down

0 comments on commit 82e9bdb

Please sign in to comment.