Jump to content

Need some help making a simple headshot script


trashgarbage666

Recommended Posts

Like the title says, I'm working on a headshot script, and need some help working out a very persistent bug. I have no coding knowledge whatsoever, so the code you're seeing now is based purely on examples and lots and lots of testing.

 

What the script does:

 

The script is attached to Ammo as an "Impact Script". When the ammo hits a target, it checks if the target's human, checks if the target's been hit in either the head or neck, checks if the target isn't wearing a helmet, and checks if the target isn't dead already. If all four conditions are good, it sets the target's health to 0.

 

(I omitted the part that checks for helmets from the example script below, because I actually use three different versions of this script that I apply to ammo of varying caliber. The only difference between the three versions being which helmets prevent headshots from insta-killing the target. It's just a GetEquipped Form List check. It isn't causing the error.)

ScriptName HeadshotAmmoSCRIPT

BEGIN GameMode

    Ref rTarget
    Set rTarget to GetOwnerLastTarget

    If (GetHitLocation == 1 || GetHitLocation == 2) && (rTarget.GetDead != 1) && (rTarget.GetIsCreature != 1)
        ForceActorValue Health 0
    Else
    EndIf

END

Here's my problem:

 

Currently, the code says headshots are only lethal if the target IS NOT a creature. However, if I load up the game with the code looking like this, headshots are lethal to everything. Creatures and NPCs. If I reverse the condition so headshots are ONLY lethal to creatures, then headshots behave like a bodyshot on all creatures and NPCs. The GetIsCreature command is behaving like it can't tell the difference between humans and animals.

 

It's really important that I get this script to ignore creatures, because I'd much rather handle headshot lethality on a creature to creature basis through Body Part Data damage mults. The player shouldn't be able to 1-shot deathclaws with a 9mm.

 

Hopefully all my script needs is a fresh set of eyes on it. Thanks for hearing me out!

Edited by punchbattle
Link to comment
Share on other sites

  • Replies 59
  • Created
  • Last Reply

Top Posters In This Topic

Here's a programming tip for when a compound conditional (multiple tests on the same line) is not working as expected: split it up into nested conditions. An "ElseIf" is equivalent to an "OR (||)" compound, and each nested "IF" statement is equivalent to an "AND (&&)" compound.

 

So, change: "If (GetHitLocation == 1 || GetHitLocation == 2) && (rTarget.GetDead != 1) && (rTarget.GetIsCreature != 1)" into:

If (GetHitLocation == 1 || GetHitLocation == 2)
    ; NVSE required: PrintD (string:expression), DBPrint (formatted string)
    DBPrintC "Script [HeadshotAmmoSCRIPT], GetHitLocation = [%g].", GetHitLocation


   If (rTarget.GetDead != 1)
      ; NVSE required: PrintD (string:expression), DBPrint (formatted string)
      PrintD "Script [HeadshotAmmoSCRIPT], rTarget.GetDead = [" + $(rTarget.GetDead) + "]."

      If (rTarget.GetIsCreature != 1)
         ; NVSE required: PrintD (string:expression), DBPrint (formatted string)
         PrintD "Script [HeadshotAmmoSCRIPT], rTarget.GetIsCreature = [" + $(rTarget.GetIsCreature) + "]."

         ForceActorValue Health 0
      Else ; (Can be dropped if you just want it to totally fail.)
      Endif
   Else; (Can be dropped if you just want it to totally fail.)
   Endif
Else
EndIf 

Insert "debug messages" (examples given) as required to pin down what values your conditions are actually testing. That should quickly isolate what is not as expected. (I just repeat the '; NVSE required' comment line to remind myself of the required syntax differences with each line. Not required otherwise.)

 

Use the game console "bat <filename.bat>" command to run a "batch file" similar to this to trigger the debug print statements when testing. Without that they won't actually do anything normally:

con_SCOF "_MyDebug.log" ; Output console messages to file
DBMode 1 65  ; "Enable Debug mode" command
; NVSE required: PrintD (string:expression), DBPrint (formatted string)
DBPrintC "Starting log for mod index 65(0x41) (<ModPluginName>) ..."  ; descriptive initialization message (e.g. "<ModPluginName>" = "New Vegas Bounties III")

Place your "batch file" in the game root folder (where the "FalloutNV.exe" file is found). The filename begins with an "underscore" (_) so it will be sorted to the top of the file list.

Edit: Replaced "<MainQuestName>" with "<ModPluginName>" without any file extension. Just used to coordinate mod index with plugin file for reference. Sorry about any confusion.

 

While it would require some additional lines of code, consider using "GetCreatureType" instead if you can't get "GetIsCreature" to do the job.

 

-Dubious-

Edited by dubiousintent
Link to comment
Share on other sites

I think the problem is GetIsCreature and GetIsCreatureType doesn't like playing nice with the GameMode script block. Here's what I mean:

ScriptName HeadshotAmmoSCRIPT

BEGIN GameMode

	Ref rTarget
	Set rTarget to GetOwnerLastTarget

	If rTarget.GetIsCreature != 1
		ForceActorValue Health 0
	Else
	EndIf

END
ScriptName HeadshotAmmoSCRIPT

BEGIN GameMode

	Ref rTarget
	Set rTarget to GetOwnerLastTarget

	If rTarget.GetIsCreatureType 6 != 1
		ForceActorValue Health 0
	Else
	EndIf

END

Neither of these scripts work. The first script should make my ammo 1-hit kill anything that isn't a creature, and the second script should 1-hit kill anything that isn't a robot, and yet the bullets indiscriminately kill everything they hit.

 

Check out the Boxing Glove script from the vanilla game:

scn BoxingGlovesFatigueOnHitScript

; Inflicts Fatigue damage on the target to temporarily knock it out.
; JES

Begin OnHit

	Ref BoxingGloveTarget
	Set BoxingGloveTarget to GetOwnerLastTarget

	If (BoxingGloveTarget != PlayerRef) && (BoxingGloveTarget.GetIsCreatureType 6 != 1)
		BoxingGloveTarget.damageav Fatigue 16
	Else
		BoxingGloveTarget.damageav Health 10
	EndIf

End

This code is able to successfully differentiate between creatures, NPCs, and the player, and yet it does so within the OnHit script block. I'd gladly use OnHit for my code, but I read somewhere on the GECK wiki that the GetHitLocation command doesn't work inside OnHit. Is it possible to use multiple script blocks within the same script? If so, I could probably use OnHit to determine if the target's a creature, and GameMode to determine if the target got hit in the head. That could work... right?

 

EDIT: Couldn't get it to work.

 

So I had another Idea. I tried giving a super mutant a dummy "helmet" item and told the script to not insta-kill anything that has that item in its inventory. It didn't work either, which completely blows me away because I had no problem telling the script not to insta-kill someone wearing a helmet.

 

I'm at a complete loss for what to do.

Edited by punchbattle
Link to comment
Share on other sites

I think the key is in those notes you are recalling from the wiki about "GetHitLocation":

  • This information is not available in the OnHit and OnHitWith script blocks, unlike GetLastHitCritical.
  • This information is available in a UDF event handler script for OnHit and OnHitWith
  • This information is available in a UDF script for SetOnCriticalHitEventHandler
  • GetHitLocation won't work if used in a weapon's Object Effect, but will work if used in the weapon's Crit Effect.
  • GetHitLocation will only return the correct value in a GameMode block in the frame that the reference is killed.

The "BoxingGlove" script is not in a "GameMode" Block. Without looking, my guess would be it is called by an "EventHandler" (second bullet point). So you need to create a OnHit EventHandler "User Defined Function" (UDF) to call your script.

 

-Dubious-

Link to comment
Share on other sites

Unfortunately, I think you might be right. It's unfortunate because I'm reading the UDF and Event Handling pages on the GECK wiki, and it's just ...completely out of my league. I don't even know where to begin. If you know how to set something like this up, could you walk me through it? Making this mod has been helping me de-stress, and and this point, I feel like my project has hit a wall.

Link to comment
Share on other sites

As for "walking you through it", suggest you read the series of NVSE+ tutorials by DoctaSax under the "Scripting" section of wiki "Getting started creating mods using GECK" article. Read the entire series as they build upon each other.

 

While that will be useful, you are now getting fairly deep into "programming" for a non-programmer. The GECK wiki is primarily a list of functions and their syntax with some basic tutorials that just cover how to build game "assets". Not really anything about how to "write proper code" for scripts.

 

You can teach yourself from online resources these days, but you may need to look up some "basic programming" guides elsewhere. (The earliest "command line" forms of the "Basic" programming language (not "Visual Basic") have all you need to understand scripting. Command prompt "batch files" or "shell scripts" as well.) NVSE just adds functionality (i.e. technical features such as new functions) that are missing from the game engine. Use of them presumes knowledge of basic programming (how to have code logic flow as desired). Mostly that is through the use of "If ... Else ... EndIf" blocks, but other features like "arrays" are less obvious. You could learn all you need to know for scripting in a single semester of a formal "introductory programming" language class. These are often available as "adult continuing education classes" or as part of community center programs.

 

-Dubious-

Edited by dubiousintent
Link to comment
Share on other sites

 

So I had another Idea. I tried giving a super mutant a dummy "helmet" item and told the script to not insta-kill anything that has that item in its inventory. It didn't work either, which completely blows me away because I had no problem telling the script not to insta-kill someone wearing a helmet.

 

I'm at a complete loss for what to do.

 

I'm guessing for some reason the impact script execution / or the GetOwnerLastTarget , won't return subcategories of actor type or inventory.

But you say it works for checking equipped slots.

So since all humans will have something equipped in the upper body slot , and no creature ever will.

 

How about adding " If GetEquippedObject 2 != 0 " ?

 

But I was also thinking having another script that could use "ObjectUnderReticle" setting a variable ... in an actor or object effect.

Then in your impact script use "GetScriptVariable"

But that one might be kind of processor intensive ?

Edited by Mktavish
Link to comment
Share on other sites

 

I'm guessing for some reason the impact script execution / or the GetOwnerLastTarget , won't return subcategories of actor type or inventory.

But you say it works for checking equipped slots.

So since all humans will have something equipped in the upper body slot , and no creature ever will.

 

How about adding " If GetEquippedObject 2 != 0 " ?

 

So after reading this, I thought "oh my god, that's a great idea! I finally get to move forward with my mod! I'm so excited!" and added it to my script right away...

 

only to be stopped dead in the water immediately. The script won't save. It's acting like there's a typo or syntax error. There isn't. Honestly, I think it's not working just to spite me. I hate this. I hate it. I see no reason why your idea shouldn't work, and yet here we are.

 

EDIT: Well, I know "GetEquipped (Form List) == 0" works because I've been using it to tell the script to ignore anyone wearing a helmet! So! I put together an armor / clothing Form List and told the script to only kill things wearing clothes or armor. It didn't work at first, so I changed how the script found its target from "GetOwnerLastTarget" to "Player.GetCombatTarget" and it started working just fine.

 

So it's pretty much mission accomplished at this point? Kind of? I was sorta hoping the player could be killed by headshots as well, but Player.GetCombatTarget dictates that only NPCs shot by the player will be killed. I've been experimenting with stuff like (OwnerOfThis).GetCombatTarget, but haven't had any luck. Anyone have any ideas?

Edited by punchbattle
Link to comment
Share on other sites

Dang I thought it would at least save ... but it seems it doesn't like the ref instance of what "GetOwnerLastTarget" is returning.

 

So I dug a little deeper with what you could pass besides "GetIsCreature"

 

And "GetIsFormType" is at least saving ... although not sure it will give you the same problems as trying to exclude creatures. But here is what I was able to save.

 

~~~~~~~~~~~~~

SCN ZZZMyBulletScript
BEGIN GameMode
Ref rTarget
Set rTarget to GetOwnerLastTarget
If rTarget.GetIsFormType 42 == 1 || rTarget.GetIsFormType 44 == 1
If (GetHitLocation == 1 || GetHitLocation == 2) && (rTarget.GetDead != 1)
ForceActorValue Health 0
Else
EndIf
EndIf
END
~~~~~~~~~~~~~~
And here is the Int code list for form types http://geck.bethsoft.com/index.php?title=Form_Type_IDs
Link to comment
Share on other sites

I was actually able to get your previous suggestion to work perfectly! You might not have seen it, because I just kind of stealth edited my previous post to say so. However, I thought I'd give your new idea a try just to see if it had any notable pros or cons over the other method, and while it did manage to save, it wasn't able to differentiate between creatures and NPCs. But still! I wasn't even aware of Form Types, so it was helpful all the same!

 

I just wanted to say thanks for all your help. Like I mentioned in a previous post, making mods has sort of become how I de-stress, and now that I'm past this problem I can continue doing that!

Edited by punchbattle
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...