Jump to content

[LE] Need help with a script on werewolves


LyreaTheFox

Recommended Posts

Hi there, I'm currently trying to add a script to werewolves that adds a slight health restore whenever the 'feeding' kill move is executed.

I think I've got a pretty good idea on how to do it, but whatever I do, it seems like the script fails somewhere. Considering that the logs don't even show anything about it I'm not even sure if it's running at all.
Any ideas on how to do this kind of thing or why it's seemingly not working?

Here's the current code:

Scriptname PlayerWerewolfFeedingKillScript extends Quest

Spell Property FeedingKillBoost auto
Idle Property FeedingKillFinisher auto ;Obsolete at the moment, replaced by inserted animation name
Quest Property PlayerWerewolfQuest auto


Event OnInit()
	RegisterForSingleUpdate(1.0)
EndEvent

Event OnUpdate()
	Bool bKeepUpdating = true
	if PlayerWerewolfQuest.getStage() == 10
		RegisterForAnimationEvent(Game.GetPlayer(), "pa_KillWerewolfPairedFeedingWithHuman")
	endif
	if bKeepUpdating == true
		RegisterForSingleUpdate(1.0)
	endif
EndEvent

Event OnAnimationEvent(ObjectReference akSource, string asEventName)
	if (akSource == Game.GetPlayer() && asEventName == "pa_KillWerewolfPairedFeedingWithHuman")
		Utility.Wait(1.0)
		FeedingKillBoost.Cast(Game.GetPlayer())
		Debug.Notification("Success")
	endif
EndEvent

Any help would be appreciated.

Link to comment
Share on other sites

Idles are not the things that trigger animation events. You passed an idle to the function as a string, when it's just an idle(and not a string).

 

You are on the right track, script looks good, the only issue being that you need to know the animation event that occurs when a werewolf begins to feed.

 

You can totally just make your own feed function, without worrying about clunky OnAnimationEvent.

 

This is bethesda's from the PlayerWerewolfChangeScript:

 

 

; called from stage 11
Function Feed(Actor victim)
    float newShiftTime = PlayerWerewolfShiftBackTime.GetValue() + __feedExtensionTime
    Game.GetPlayer().PlayIdle(SpecialFeeding)
    
    ;This is for adding a spell that simulates bleeding
    BleedingFXSpell.Cast(victim,victim)
    
    if (!C03Rampage.IsRunning())
        PlayerWerewolfShiftBackTime.SetValue(newShiftTime)
        PlayerWerewolfFeedMessage.Show()
        FeedBoost.Cast(Game.GetPlayer())
        ; victim.SetActorValue("Variable08", 100)
;         Debug.Trace("WEREWOLF: Player feeding -- new regress day is " + newShiftTime)
    endif
    SetStage(10)
EndFunction
Link to comment
Share on other sites

I know how bethesda did things, I had to look around for a long while until I realized that that Feed function is actually tied to the activation of the dead body though, which is why I couldn't use something like it because I needed to have the effect be applied while the kill move is playing.

The goal of my script was initially to first of all check that the player is a werewolf and the quest is at stage 10, because that's the 'idle' stage.
The next point was checking for the kill move animation, which is why I have the OnAnimationEvent there.

It's supposed to detect when the kill move happens and after a short delay so the animation is already running heal the player.

 

And on the way everything is set up: I looked up syntax and things like that on the creationkit 'wiki', and they did checking for animations that way as far as I could tell.

I'm just a little stuck because I'm out of ideas on how to do it.

Edit: The main problem is that I can't add a manual trigger, like pressing 'E' to activate, otherwise I wouldn't have these problems.

 

Edit2: Slight update: seems like I derped a little, after some more research it seems like it can't actually register all animations, so it won't ever find that killmove I was looking for. Looks like I will have to try and trigger it some other way, though I am not sure as to how to do that without manual activation of the target or using a power.

Edited by LyreaTheFox
Link to comment
Share on other sites

OK all I'm going to say about that is, you are being mislead by the information you see in the Idle Manager. If you really want to deal with that travesty of an event, you can use this mod: https://www.nexusmods.com/skyrim/mods/38382

 

If you are interested in animations and how they work in game, nobody knows more about it than Fore: https://www.nexusmods.com/skyrim/mods/11811

 

One other way to detect if an actor is in a kill move: https://www.creationkit.com/index.php?title=IsInKillMove_-_Actor

Link to comment
Share on other sites

I'll see what I can do with that mod once I can get enough free time again to, probably will have to wait until wednesday.

Sadly IsInKillMove only allows me to check if there is a kill move happening or not, but that would mean the healing would also be triggered by the 'maul' kill move, which wouldn't make all too much sense, would it?

But thanks for the help overall, will post an update once I can experiment with that mod for a bit.

Link to comment
Share on other sites

Maybe this is what you want.

 

PlayerWerewolfFeedingKillScript

 

Scriptname PlayerWerewolfFeedingKillScript extends Quest
{rewritten by ReDragon 2018}    ; not sure whether animation event will be triggered
; https://forums.nexusmods.com/index.php?/topic/6366761-need-help-with-a-script-on-werewolves/
; LyreaTheFox wrote: "Any ideas on how to do this kind of thing or why it's seemingly not working?"

  Quest PROPERTY PlayerWerewolfQuest auto    ; vanilla quest, autofill?

  Spell PROPERTY FeedingKillBoost    auto
  Idle  PROPERTY FeedingKillFinisher auto    ; Obsolete at the moment, replaced by inserted animation name


; -- EVENTs -- 3

EVENT OnInit()
    Debug.Trace("PWFK: Quest has been started.. " +self)
    RegisterForSingleUpdate(1.0)
ENDEVENT

EVENT OnUpdate()
    myF_Update()
ENDEVENT

EVENT OnAnimationEvent(ObjectReference akSource, String asEventName)
IF (asEventName == "pa_KillWerewolfPairedFeedingWithHuman")
    myF_Boost(akSource)
ELSE                                        ; unknown anim event name, should not be
    myF_UnRegister(akSource, asEventName)
ENDIF
ENDEVENT


; -- FUNCTIONs -- 3

;--------------------
FUNCTION myF_Update()
;--------------------
IF (PlayerWerewolfQuest) && PlayerWerewolfQuest.IsRunning()
    int i = PlayerWerewolfQuest.GetCurrentStageID()

    IF (i == 10)
        Debug.Trace("PWFK: Quest stage 10 has been reached.. register for special animation")
        RegisterForAnimationEvent(Game.GetPlayer() as ObjectReference, "pa_KillWerewolfPairedFeedingWithHuman")
    ELSE
        RegisterForSingleUpdate(1.5)
    ENDIF
ELSE
;;      Debug.Trace("PWFK: Quest property is " +PlayerWerewolfQuest)
        RegisterForSingleUpdate(2.0)
ENDIF
ENDFUNCTION

;----------------------------------------------------------
FUNCTION myF_UnRegister(ObjectReference akSource, String s)
;----------------------------------------------------------
    UnRegisterForAnimationEvent(akSource, s)
ENDFUNCTION

;-------------------------------------------
FUNCTION myF_Boost(ObjectReference akSource)
;-------------------------------------------
IF (akSource == Game.GetPlayer() as ObjectReference)
ELSE
    myF_UnRegister(akSource, "pa_KillWerewolfPairedFeedingWithHuman")
    RETURN    ; - STOP -    not the player for whatever reason
ENDIF
;---------------------
    Debug.Trace("PWFK: myF_Boost() has been reached..")
    Utility.Wait(1.0)
    FeedingKillBoost.Cast(akSource)    ; cast the spell after 1 sec waittime
    Debug.Notification("Success")
ENDFUNCTION

 

 

Link to comment
Share on other sites

I've gotten everything to run just fine with the one I had, but it seems like RegisterForAnimationEvent can't register this specific animation.
If this list is correct and up to date then only some basic animations will be found by that function.

If that's true it will never find the "pa_KillWerewolfPairedFeedingWithHuman" animation and thus make any attempt at scripting it that way basically impossible...
It'd be pretty weird in my opinion if that's the case, but I can't really look at the function itself and tell if that's true or not.
I'd expect it to find it regardless, but seeing as nothing seems to work and it always stops at the animation check, that seems to be the case and problem.

Link to comment
Share on other sites

FYI - you can add a manual trigger with SKSE.

 

I have a local mod that for gamepad/controller reasons uses the standard activation key. It requires careful checking of menus and crosshair targets so that it doesn't trigger at the wrong times. But it is totally possible. You can also set it up to use other keys instead of the standard activation key, if desired.

 

If this interests you, I can share a stripped down version of the script (i.e. remove what would not be needed for your purposes).

Link to comment
Share on other sites

Hm, taking a look at it won't hurt I suppose, and any help is appreciated.

Alright. Two script process. It will allow you to use the 'E' key or whatever the player has designated as the activation key. Do note that there will not be a UI element. i.e. it will not show 'E to Perform feeding kill move'.

 

The following shows how to set up the player's chosen activation key (E by default) as your mod's activation key. Also included is a possible means of triggering a kill move and casting your feeding spell. All scripts tested for compilation but not function. Tho the scripts I pulled the bulk of the code from do work.

 

 

First script is a quest script. This is where most of the work takes place.

Scriptname MyQuestScript extends Quest

Actor Property PlayerRef Auto

Int Property MyKeyCode Auto Hidden

Idle Property MyPairedKillmove Auto
Spell Property FeedingKillBoost auto

Event OnInit()
	MaintCode()
EndEvent

Function MaintCode()
	If MyKeyCode != Input.GetMappedKey("Activate")
		UnregisterForKey(MyKeyCode)
		MyKeyCode = Input.GetMappedKey("Activate")
		RegisterForKey(MyKeyCode)
	EndIf
	RegisterForMenu("Crafting Menu")
	RegisterForMenu("MessageBoxMenu")
EndFunction

Bool IsInCraftingMenu = false
Event OnMenuOpen(String MenuName)
	If MenuName == "Crafting Menu" || MenuName == "MessageBoxMenu"
		IsInCraftingMenu = true
	EndIf
EndEvent

Event OnMenuClose(String MenuName)
	If MenuName == "Crafting Menu" || MenuName == "MessageBoxMenu"
		Utility.Wait(2.0)
		IsInCraftingMenu = false
	EndIf
EndEvent

Event OnKeyDown(Int KeyCode)
	If 	SafeProcess() == true
		If 	KeyCode == MyKeyCode

			;ensure that we have an updated key if the player changes the activation keybind mid-game
			If KeyCode != Input.GetMappedKey("Activate")
				MaintCode()
			EndIf

			;make sure the crosshair is pointing at an actor 
			Actor Bob = (Game.GetCurrentCrosshairRef() as Actor)
			If Bob ;a valid actor
				If Bob.GetActorValuePercentage("Health") <= 0.1 ;if actor health is less than or equal to 10 percent
					PlayerRef.PlayIdleWithTarget(MyPairedKillmove,Bob)
					FeedingKillBoost.Cast(PlayerRef)

					;you may need additional things to get your FX just right.
					;if using a custom paired animation, refer to FNIS documentation on how to add it into the game and reference it.
					;the above setup as-is should work for stock paired idles
				EndIf
			EndIf

		EndIf
	EndIf
EndEvent

Bool Function SafeProcess()
	If (!Utility.IsInMenuMode()) \
	&& (!UI.IsMenuOpen("Dialogue Menu")) \
	&& (!UI.IsMenuOpen("Console")) \
	&& (!UI.IsMenuOpen("Crafting Menu")) \
	&& (!UI.IsMenuOpen("MessageBoxMenu")) \
	&& (!UI.IsMenuOpen("ContainerMenu")) \
	&& (IsInCraftingMenu == false)
		;IsInMenuMode to block when game is paused with menus open
		;Dialogue Menu to block when button is used INSIDE dialog and crosshair moved off of object via NPC movement
		;Console to block when button is used INSIDE console and crosshair not pointing at valid object
		;Crafting Menu to block when button is used INSIDE menu and crosshair moved off of object via animation sequence
		;MessageBoxMenu to block when button is used INSIDE menu and crosshair not pointing at valid object
		;ContainerMenu to block when button is used INSIDE menu and crosshair not pointing at valid object
		;IsInCraftingMenu is true when a crafting menu or message box menu is open, we want to allow false only
		Return True
	Else
		Return False
	EndIf
EndFunction

Second script goes on an alias for the player within the same quest as the first script. This second script is used to trigger the maintenance code on each game session. This is to check if the player has changed the key bind (perhaps while playing a different character that is not using the mod).

Scriptname MyPlayerAliasScript extends ReferenceAlias  

MyQuestScript MyQscript

Event OnPlayerLoadGame()
	MyQscript = GetOwningQuest() as MyQuestScript
	MyQscript.Maintcode()
EndEvent

 

You may need to reference the following:

https://www.creationkit.com/index.php?title=PlayIdleWithTarget_-_Actor

https://forums.nexusmods.com/index.php?/topic/5525007-how-to-trigger-a-killmove-using-papyrus-script/

https://forums.nexusmods.com/index.php?/topic/2602229-trying-to-run-an-animation-via-spell-or-power-but/

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...