Well, I am finally getting to the final stages of my mod, just testing it now.
I think the final solution I am taking will be 2 parts. Both are separate solutions that work independently of each other but have the same goal in mind. The first solution is the easiest, simplest and most lightweight solution. However it is the slowest solution and will be subject to target movement inaccuracy in reporting the head positions.
Solution 1Projectiles have a script that when an projectile impacts - spawn an object at that impact point that reports the location of the impact to a script running on the player called registerImpact(int x, int y, int z). After registering the impact position it jumps to the head node of the target by calling a getclosestactor function which definitely impacts performance, but there is no way for the spawned object to know of its intended target beforehand, and programming logic to have some other aware script give it the target will just take as much time. The spawned object moves to this target's head and reports its head position with a similar function - registerHead(int x, int y, int z, Actor target). Once these functions are called, they set a flag (impactR and headR) to true. Both function check to see if the other is true, then calls calcHeadDistance() which will determine if the impact was a headshot.
It's light, simple, runs in one script on an object that gets spawned on impact. Very compact and not resource intensive at all - but slow. Targets would need to standing still or moving on a flat plane in order for headshots to be accurate.
Solution 2Projectiles do the same thing, they simply report their location, but are not tasked with getting an Actor and getting his head location and reporting that, too. A quest that fills Aliases with Actors near the player is running, and each alias has a OnHit event that will (when struck by the player and a projectile) report their head location *used with a non-persistent marker spawned at OnInit() time). Much faster than the other solution. Solution 1 took ~240+ time from registerImpact() to calcHeadDistance(). This solution goes from 70-180 time units (100 units average). This however requires a lot more complexity with 2 quests running and aliases. However, not all NPCs will be filled by the manager into aliases. Meaning headshots won't work period making it useless in these cases.
Final Solution?Use both. It is essentially a race for whoever gets to registerHead() first which is not a bad thing. The projectile will report its impact position on impact like in both cases, and then the Actor will be hit and report his head position, meanwhile the Projectile will be in the process of getting that Actor's head position and reporting it, usually in will lose the race an the OnHit event will report it first. However, in the cases where the manager does not put the target into an Alias (making the OnHit never fire) it will still work since we have the Projectile getting and registering the head. The fact they are racing will not have a negative effect, since the sooner calcHeadDistance() gets called the better, if it gets called twice -- no big deal, one will use accurate data, one will use less accurate data, so if it was a head shot, it will still get registered. The only case would be if it was NOT a head shot, but the inaccurate laggy data said it was (you fire at a wall, miss, and the target dies). This is a shortcoming I am ok with. If the actor is standing next to a wall and your arrow hits the wall with the same z position the actors head is at, it will be a headshot -- oh well -- that's more fun than hitting them in the head and them not dying IMO.
Also, MOST people will probably use the slomo effect with archery, making both solutions become very accurate. Slowing the game down makes both methods report very good data. I honestly want to just use solution 1 and tell everyone to just do headshots in slow motion
