How to find an actor's name via script, determine crippled l

Post » Fri Nov 05, 2010 12:59 am

I'm trying to find the name of any NPC / creature that the PC is currently doing damage to, to add some feedback messages similar to those in Fallout 1/2. romeck gave me the idea with his message mod, and it looks like he ran into the same issue (currently enemies are either "Creature" or "NPC")

Looking at the functions available, it seems like http://geck.gamesas.com/index.php/GetCombatTarget might work, but the GECK page doesn't say what kind of block to use it in, and also it only works if autoaim could work. That seems like a limitation. The GECK also has http://geck.gamesas.com/index.php/GetOwnerLastTarget but apparently that only works in a OnHit block, which itself can only be attached to a script running on a weapon? I'm confused. I also saw the FOSE function GetCrosshairRef but I'm not sure that would get the name of the NPC actually taking damage / dying. Depending on how erratically the PC is moving, he could do damage to one NPC, then move the crosshair when the script fires so the wrong name would be returned.

Separately, I'm looking for how to determine what body parts of an NPC / creature are hit by a given bullet, if they're crippled or not, and how to check if the PC's different body parts have been hit/crippled. Using a combination of http://geck.gamesas.com/index.php/GetHitLocation and http://geck.gamesas.com/index.php/GetLastHitCritical seemed natural, but I read on the GetHitLocation page that

GetHitLocation will only return the correct value in a GameMode block in the frame that the reference is killed.

To me, that says I can only find out if the PC is hit on the, say, arm if the PC is killed by that hit (useless), and I can't determine where any other creature / NPC is hit unless it's the killing blow. But the biggest problem with using these two functions in tandem is that GetHitLocation wants to run in the GameMode block but GetLastHitCritical's page says it only works in the OnHit block. If I'm working in the OnHit block, it seems like using http://geck.gamesas.com/index.php/GetOwnerLastTarget would make more sense, except there is no information on the page for that function!

Sorry for the wall of text, it highlights how confused I am by trying to solve these problems.
User avatar
Ludivine Dupuy
 
Posts: 3418
Joined: Tue Mar 27, 2007 6:51 pm

Post » Fri Nov 05, 2010 7:21 am

Both issues need the refid of the actor, and that can be addressed by ref-walking the current cell for actors. To guarantee that you will catch GetHitLocation data in a GameMode block, it must run every frame so you catch it when the actor dies. So a script on an object in the player's inventory (a non-playable armor item with no biped slots) might do it.

Refwalking: http://www.cipscis.com/fallout/tutorials/loops.aspx

GetCombatTarget would be unreliable for this on the player, even when autoaim has not been disabled.

Not sure how you will track an actor actually taking damage specifically from the player (the On Hit stuff) with this, though. You can determine if an actor is an enemy, is dead, and if the player killed it, or any other stat.
User avatar
Paula Ramos
 
Posts: 3384
Joined: Sun Jul 16, 2006 5:43 am

Post » Fri Nov 05, 2010 5:23 am

Thanks RickerHK. I have another question now though.

I have this code snippet that forces a specific NPCs HP to be XXX for a given range of player levels.

	if CompHealthTweak		if (player.getlevel < 10) * (GetBaseActorValue Health != 255)			SetAV Health 255		elseif (player.getlevel > 9 && player.getlevel < 16 ) * (GetBaseActorValue Health != 273)			SetAV Health 273		elseif (player.getlevel > 15 && player.getlevel < 22 ) * (GetBaseActorValue Health != 298)			SetAV Health 298		elseif (player.getlevel > 21 && player.getlevel < 28 ) * (GetBaseActorValue Health != 311)			SetAV Health 311		elseif (player.getlevel > 27 && player.getlevel < 35 ) * (GetBaseActorValue Health != 327)			SetAV Health 327		elseif (player.getlevel >= 35) * (GetBaseActorValue Health != 342)			SetAV Health 342		endif	endif

Where CompHealthTweak is a short global. When I set CompHealthTweak to 0, disabling this set of conditionals, I would like the NPC to revert back his original auto-leveled HP. Essentially, I need the NPC to re-evaluate its auto-leveled stats to correct its health. If the NPC was a companion and the player leveled, I think it would go back to normal but that's not an ideal solution. Any ideas?

edit: resetai didn't work.
User avatar
Catherine N
 
Posts: 3407
Joined: Sat Jan 27, 2007 9:58 pm

Post » Fri Nov 05, 2010 2:52 am

Just playing around at the console (on a companion) shows that SetAV makes it become the new BaseActorValue, which is going to make it harder to revert back.

GetBaseAV at the console returns the current full level-computed health (not what is in the Geck), which is what you want.
What I would suggest is using ModAV on the BaseHealth this way

short iBaseHealth short iTargetHealth short iModHealthDiff   ;will be a +/- value if CompHealthTweak						set iBaseHealth to GetBaseActorValue Health				                if (player.getlevel < 10)                        Set iTargetHealth to 255                elseif (player.getlevel > 9 && player.getlevel < 16 )                        Set iTargetHealth to 273                elseif (player.getlevel > 15 && player.getlevel < 22 )                        Set iTargetHealth to 298                elseif (player.getlevel > 21 && player.getlevel < 28 )                        Set iTargetHealth to 311                elseif (player.getlevel > 27 && player.getlevel < 35 )                        Set iTargetHealth to 327                elseif (player.getlevel >= 35)                        Set iTargetHealth to 342                endif								if (iBaseHealth != iTargetHealth)					set iModHealthDiff to iTargetHealth - iBaseHealth					ModAV Health iModHealthDiff				endif				endif


At the console, GetActorValueInfo will show that modav doesn't affect the base value, but affects the perm value. So you will always be able to go back to what the game computes the NPC should be by figuring the iModHealthDiff and applying it.
User avatar
Sarah Edmunds
 
Posts: 3461
Joined: Sat Jul 08, 2006 8:03 pm

Post » Thu Nov 04, 2010 11:18 pm

This looks good, and you've also eliminated a lot logic checks from the original script, thank you. One thing that isn't clear though: won't this script constantly be running? If iBaseHealth is polling the BaseActorValue Health and ModAV doesn't affect the base value, but the permanent value, then iBaseHealth != iTargetHealth will always be true even after the NPCs health has been changed. Also, won't ModAV just hurt / heal the companion, without changing their HP pool?

Just tested this, it keeps running and kills the companion. I don't think there is any way to actually change the health pool without using SetAV which changes the BaseActorValue. So far, it looks like my best option is to manually store the original companion HP and return it when the HP tweak is turned off. Like this:

short iBaseHealthshort iTargetHealthshort iModHealthDiff   ;will be a +/- valueshort sDoOnceBEGIN gamemode	if CompHealthTweak           		if sDoOnce < 1     			set iBaseHealth to CraigBooneREF.GetBaseActorValue Health			set sDoOnce to 1		endif                                		if (player.getlevel < 7)					set iTargetHealth to 192		elseif (player.getlevel > 6) * (player.getlevel < 14 )			set iTargetHealth to 214		elseif (player.getlevel > 13) * (player.getlevel < 20 )			set iTargetHealth to 230		elseif (player.getlevel > 19) * (player.getlevel < 28 )			set iTargetHealth to 248		elseif (player.getlevel > 27) * (player.getlevel < 35 )			set iTargetHealth to 263		elseif (player.getlevel > 34)			set iTargetHealth to 277		endif                                		if (CraigBooneREF.GetBaseActorValue Health != iTargetHealth)			CraigBooneREF.SetAV Health iTargetHealth		endif	elseif (CompHealthTweak < 1) * (iBaseHealth > 0)		CraigBooneREF.SetAV Health iBaseHealth		set sDoOnce to 0	endif                                end

User avatar
Flutterby
 
Posts: 3379
Joined: Mon Sep 25, 2006 11:28 am

Post » Fri Nov 05, 2010 2:27 am

Yeah, I goofed on that one. The ModAv will be applied every frame.

if (iBaseHealth != iTargetHealth)		<-- oops. this will always be true. 


If you are going to do this with more than one NPC, you might consider storing all of your variables in and actually running the code as a quest script.

I still prefer ModAv, (like Buffout does it), because of this scenario:
Say you apply the tweak using SetAv at a low player level, and store their health - say it's 200.
Then later on, maybe at level 15, you turn the tweak off, and SetAV 200 to restore what you saved. But their health was supposed to be leveling with the player - maybe it should have been 270. The SetAV overrides this.
User avatar
Mark
 
Posts: 3341
Joined: Wed May 23, 2007 11:59 am

Post » Thu Nov 04, 2010 7:08 pm

Yea, that's the biggest problem with how I've done it. I understand what you're saying about ModAV but that also means that when a player uses the companion wheel, the HPs shown will be 230/380 and never higher: that could confuse people.

Do you know of NPC autoleveled stats are calculated after the player has gone through the level up / distribute points prompt? Or is it immediate when the player's XP threshold has been reached? If I could detect a stage just prior to the NPCs autoleveled stats being calculated, I could restore their base HP, let the HP autolevel, store that new value, and apply my changes. Using (GetXPForNextLevel < 1) I could "race" the autoleveling process with my script. I may try that.
User avatar
megan gleeson
 
Posts: 3493
Joined: Wed Feb 07, 2007 2:01 pm

Post » Fri Nov 05, 2010 1:54 am

You can detect a levelup with a Menumode 1027 in a quest script. But SetAv disables autolevel on the stat. So even if you restored the value that you saved, the level up doesn't do anything.

The problem is, when you use SetAV just once, you are stuck with it because it overrides the Base value on the base object. (ModAv affects just the reference).
So using SetAV overrides the level-with-player setting in the Geck. The 'Derived value' below goes from 70 to 75 after level up, but it is ignored after the setav, and GetBaseActorValue returns the value set by the override.

SetConsoleOutputFilename >> 'statstest.txt'

getactorvalueinfo health
GetActorValueInfo: Health on Wendy
...Current Value: 270.00 Computed Base: 270.00
...Base Value components:
......Reference Base Value: 200.00 (auto-calculated)
......Derived Value: 70.00
...Modifiers: Temp: 0.00 Perm: 0.00 Damage: -0.00

SetAV health 220

getactorvalueinfo health

GetActorValueInfo: Health on Wendy
...Current Value: 220.00 Computed Base: 220.00
...Base Value components:
......Reference Base Value: 200.00 (auto-calculated)
......Derived Value: 70.00
......SetAV override: 220.00
...Modifiers: Temp: 0.00 Perm: 0.00 Damage: -0.00


getbaseAV health
GetBaseActorValue: Health >> 220.00

rewardxp 1300 - level up (leave console mode and level up)

getav health
GetActorValue: Health >> 220.00

getactorvalueinfo health
GetActorValueInfo: Health on Wendy
...Current Value: 220.00 Computed Base: 220.00
...Base Value components:
......Reference Base Value: 200.00 (auto-calculated)
......Derived Value: 75.00
......SetAV override: 220.00
...Modifiers: Temp: 0.00 Perm: 0.00 Damage: -0.00

I saw what you mean by the wheel - it would be confusing, especially if you nerfed the health. That looks like a show stopper for ModAV. Then SetAV would be the way to go but to revert health to what the game thinks it should have been, you could probably compute the derived value using the player's level and some game settings (don't know which), and add it to the BaseActorValue that you saved before applying the very first SetAV.
User avatar
Sylvia Luciani
 
Posts: 3380
Joined: Sun Feb 11, 2007 2:31 am

Post » Fri Nov 05, 2010 5:32 am

Thanks RickerHK, I ended up kludging it together but at least people can toggle between the different HP amounts to see what suits them.

I'm trying to implement psuedo-essential right now and I keep losing player's limbs. Do you know if it's possible to reinstate a dismembered / exploded limb or completely disable the destruction of limbs? I'm not using resurrect, but an OnHit that enables essential as soon as the NPC's health drops below 1. The script damages the NPC to 1 HP (thanks to part of your code above, actually) and then switches off essential.
User avatar
Justin Hankins
 
Posts: 3348
Joined: Fri Oct 26, 2007 12:36 pm

Post » Thu Nov 04, 2010 9:10 pm

Thanks RickerHK, I ended up kludging it together but at least people can toggle between the different HP amounts to see what suits them.

I'm trying to implement psuedo-essential right now and I keep losing player's limbs. Do you know if it's possible to reinstate a dismembered / exploded limb or completely disable the destruction of limbs? I'm not using resurrect, but an OnHit that enables essential as soon as the NPC's health drops below 1. The script damages the NPC to 1 HP (thanks to part of your code above, actually) and then switches off essential.


Under 'Body Part Data' in the Geck, the DefaultBodyPartData is what determines if a limb can be dismembered or exploded. Unfortunately it is hard-wired to all NPCs, including the player. So any changes here apply to all NPC actors in the game.

So is setting essential in the On Hit block actually reviving them? Or is it hit and miss as far as catching the health < 1? where it may be negative and they are dead with missing limbs?

I don't have a solution for the dismemberment, so I've left it up to a player choice in my mod - leave her dead or resurrect. Though if you are dealing with the vanilla followers, you have to be careful because a resurrect resets their object script variables.
These snippets might help in what you are doing. If you use SetUnconscious in the Death block, it actually revives them. I didn't discover these techniques but have used them in my FO3 mod and my WIP FNV mod.

BEGIN GameMode; Getting disintegrated		if (gethealthpercentage < .01)			if (IsInCriticalStage GooStart)				set iGooFlag to 1			endif			if (IsInCriticalStage DisintegrateStart)				set iGooFlag to 1			endif		endifENDBEGIN OnDeath	if ((IsLimbGone 0) || (IsLimbGone 1) || (IsLimbGone 2) || (IsLimbGone 3) || (IsLimbGone 4) || (IsLimbGone 5) || (IsLimbGone 6))		set iDismembered to 1	elseif ((IsLimbGone 7) || (IsLimbGone 8) || (IsLimbGone 9) || (IsLimbGone 10) || (IsLimbGone 11) || (IsLimbGone 12) || (IsLimbGone 13))		set iDismembered to 1	else		set iDismembered to 0	endif		if (iDismembered || iGooFlag)		;Do something else		;Time to reload, or perform a resurrect (in quest script)	else		damageav fatigue 1000		;So I fall down		setunconscious 1			;This revives me		setessential MyBaseObject 1		resethealth		;set a flag to do whatever in quest script.	endifEND

User avatar
Natasha Callaghan
 
Posts: 3523
Joined: Sat Dec 09, 2006 7:44 pm

Post » Fri Nov 05, 2010 9:32 am

So is setting essential in the On Hit block actually reviving them? Or is it hit and miss as far as catching the health < 1? where it may be negative and they are dead with missing limbs?

On one hand, it works fine. The NPC never dies / OnDeath code-block never runs (no pop-up about dead companion, etc). Using:

BEGIN OnHit	IF (GetAV Health < 1) * PsuedoEssentialFlag * (IsEssential < 1)		SetEssential CompanionBaseID 1	ENDifENDBEGIN GameMode	stuff to do when companion death is intercepted	SetEssential CompanionBaseID 0END

This keeps a companion's OnDeath block from running, but if I'm the one attacking my NPC, sometimes I get the XP as if I killed them. I will also dismember their limbs depending on how much damage I do. I'm not sure from a mechanics point of view if the game considers the companion dead because like I said, I don't get any of their OnDeath block messages. I added a condition to check for head shots (as a test) and the head never explodes unless I get a critical on it.

BEGIN OnHit	IF (GetAV Health < 1) * PsuedoEssentialFlag * (IsEssential < 1) * (GetAV PerceptionCondition < 1)		CompanionRef.RestoreAV PerceptionCondition 1		SetEssential CompanionBaseID 1	ENDif	IF (GetAV Health < 1) * PsuedoEssentialFlag * (IsEssential < 1)		SetEssential CompanionBaseID 1	ENDifENDBEGIN GameMode	stuff to do when companion death is intercepted	SetEssential CompanionBaseID 0END

I see two possible solutions to limbs being dismembered on a critical: one, find out when the critical occurs and counter the damage (seems unlikely) or two, use NVSE and swap the weapon that would be otherwise killing the companion with a dummy weapon that has the no dismemberment / explode flag checked and then immediately swap it back.

EDIT What do you mean by "I don't have a solution for the dismemberment, so I've left it up to a player choice in my mod - leave her dead or resurrect."? Does the resurrect command restore the limbs, or do you mean to bring them back with the limb missing?

EDIT 2 something like
BEGIN OnHit	IF (GetAV Health < 1) * PsuedoEssentialFlag * (IsEssential < 1) * (GetAV PerceptionCondition < 1) * CompanionRef.GetLastHitCritical		AttackWeaponRef.SetWeaponCritEffect SomeNonDamagingEffect		CompanionRef.RestoreAV PerceptionCondition 1		SetEssential CompanionBaseID 1	ENDifEND

User avatar
Emma
 
Posts: 3287
Joined: Mon Aug 28, 2006 12:51 am

Post » Fri Nov 05, 2010 12:35 am


What do you mean by "I don't have a solution for the dismemberment, so I've left it up to a player choice in my mod - leave her dead or resurrect."? Does the resurrect command restore the limbs, or do you mean to bring them back with the limb missing?

A resurrect 0 will completely reset the Actor. So inventory needs to be moved temporarily and script variables saved.
In my mod, I have options the player can set for revival:
1. always revive - even if dismembered or a goo pile
2. Revive unless dismembered or goo pile
3. Never revive
4. Just make her essential

I added option 2 because I didn't have a solution for preventing dismemberment or disintegration.
Both option 1 and 2 use Resurrect 0, after 'reviving' in the 'on death' block (she appears to be unconsious).
If there is a goo pile, it is disabled/markfordelete by performing a ref-walk for it.

EDIT 2 something like
BEGIN OnHit	IF (GetAV Health < 1) * PsuedoEssentialFlag * (IsEssential < 1) * (GetAV PerceptionCondition < 1) * CompanionRef.GetLastHitCritical		AttackWeaponRef.SetWeaponCritEffect SomeNonDamagingEffect		CompanionRef.RestoreAV PerceptionCondition 1		SetEssential CompanionBaseID 1	ENDifEND


It will be interesting to see if this will work if caught in the same frame.
User avatar
Maria Garcia
 
Posts: 3358
Joined: Sat Jul 01, 2006 6:59 am


Return to Fallout: New Vegas