Jump to content

[LE] Identifying Quest Items on an NPC Inventory via Script


Myst42

Recommended Posts

I'm about to release mod, which does many things, but among them, is the ability to "cristallize" an enemy with ice spells and destroy them with a visual explosion.

 

The problem is that upon explosion, there is a series of functions, including SetCriticalStage and SetAlpha to 0, which makes it impossible to loot the killed enemy after the explosion happened.

 

For now, One can be careful and aware not to destroy corpses before looting them, as well as save and reload if something goes wrong.

Worst case scenario where someone doesnt want to reload and still needs th quest item, the enemy can still be brought back via resurrect code, knowing the proper ID.

 

But Ideally, I'd like a safer approach where one doesnt have to fear this feature and can safely destroy anyone who is allowed by my script.

 

The idea was to create a function that scans the inventory for quest items and drops them if needed.

Stuff like dragon claws etc...

But Apparently there is no way to determine if an item is important via script.

I could try make a comprehensive formlist to compare the scanned items to, but that would probably be tedious and ineffective if some other mod decides to make such an item.

 

Any one has any idea?

Edited by Myst42
Link to comment
Share on other sites

Drop a visual remains, like, say, Ice Wraiths do, and transfer everything the NPC has to that.

That's accomplished by attaching an ash pile (although technically from script you can attach any object you want which is how ice wraiths and ghosts have their custom remains). You could leave behind an ice shard or a small puddle. And the best part is that the game will clear out the "ash pile" in the same way it cleans up dead bodies.

Link to comment
Share on other sites

Alright... Fire and shock effects already had an ash pile function on the same mod. i guess it's only fair that Ice effect also turns to "ash" so I used the Ice Pile...

 

Another question though, if anyone knows and hopefully I dont need a new thread to ask.

 

This function. Does it even exist?

Why the heck can't I compile it?

I wrote it like this:

Actor Subject

Event OnEffectStart(Actor akSubject, Actor akCaster)
    Subject = akSubject
EndEvent

;;;Other Stuff;;;

Function DoSomething()
    If Subject.WaitFor3DLoad()
        ;Do Stuff
    EndIf
EndFunction

And then also tried like this

Actor Subject
ObjectReference ActorRef

Event OnEffectStart(Actor akSubject, Actor akCaster)
    Subject = akSubject
    ActorRef = Subject as ObjectReference
EndEvent

;;;Other Stuff;;;

Function DoSomething()
    If ActorRef.WaitFor3DLoad()
        ;Do Stuff
    EndIf
EndFunction

But the damn thing just refuses to compile

Edited by Myst42
Link to comment
Share on other sites

WaitFor3DLoad() is a Fallout4 function and doesn't exist in Skyrim. You'll have to make a custom function to replicate it if you want the same effects.

Any reasonable way to do that?

I have no idea what that function even does or how to replicate it

Is it an update loop with timers, a "while" function, something else? What?

How is it even supposed to work between loading screens

Should I even try?

Link to comment
Share on other sites

 

WaitFor3DLoad() is a Fallout4 function and doesn't exist in Skyrim. You'll have to make a custom function to replicate it if you want the same effects.

Any reasonable way to do that?

I have no idea what that function even does or how to replicate it

Is it an update loop with timers, a "while" function, something else? What?

How is it even supposed to work between loading screens

Should I even try?

 

 

Depends how important it is that your object is loaded before you do stuff to it, how your control flow is structured, and what you want to do if it isn't loaded. Skyrim's biggest tool for checking loaded state is Is3DLoaded, but you also have the OnLoad and OnUnload events. I've usually found them sufficient.

Edited by foamyesque
Link to comment
Share on other sites

Depends how important it is that your object is loaded before you do stuff to it, how your control flow is structured, and what you want to do if it isn't loaded. Skyrim's biggest tool for checking loaded state is Is3DLoaded, but you also have the OnLoad and OnUnload events. I've usually found them sufficient.

It's basically a shader removal system.

 

Say there is a "magic critical hit" type spell, that paralizes the target for a few seconds, while applying a "crystallized" effect

It applies shaders during the entire event, it was designed that way to make sure the shaders would prevail over other things that can affect the actor with shaders.

But when it's over, shaders need to be removed.

After several patches, filtes and cleansing utilities, it's almost safe to assume the shaders will go away everytime.

Except on one reported occasion, which is changing cells.

The Stop() function cannot be called if target has no 3D, nor can the cleansing spell be casted either.

As a result, It was reported that doing things like IE leaving the cell after a follower suffered a critical hit, results in said follower appearing with the crystal shaders when they should be clean instead.

It's not a serious issue. It's usually resolved by manually applying a cleansing spell which I provide in the mod, but still, that's not how one should be playing.

Link to comment
Share on other sites

So what's happening is if you change cells while the effect is active, the shaders (I assume script-applied?) stay active even after the effect then lapses, and what you're after is a way to pause the execution of some code in the OnEffectFinish() event until the Stop() function can be successfully run?

Link to comment
Share on other sites

So what's happening is if you change cells while the effect is active, the shaders (I assume script-applied?) stay active even after the effect then lapses, and what you're after is a way to pause the execution of some code in the OnEffectFinish() event until the Stop() function can be successfully run?

Basically, yeah, I think...

 

I was after a way to succesfully stop the shaders from executing, that works no matter what.

I realize it's simpler and safer to just attach the shader to the magic effect on the CK, but when I tried it like that, the shader was at high risk of being lost mid-effect if some other effect with a shader, say "frostbite" interefered. So it had to be scripted and reapplied, it was visually important that it stayed.

 

So I called all the Stop() functions OnEffectFinish, and it works if you wait for them in the same cell.

But... My collaborator on this project, reported that if the entire cycle of OnEffectFinish (Which according to him takes about 160 ms) is still running while a cell change occurs (And as strange as it sounds, it can happen), it will be unable to execute because it wont be able to run Stop() on an actor that is not 3dLoaded. Such threat is extensible to any circumstance that briefly unloads 3D on an actor, and apparently that happens more often than I initially thought.

 

Another alternative that I could investigate is calling the shaders with a duration in the first place, to make sure they will stop themselves when they run out of time.

But that poses another potential issue I can explain...

While doing other experiments, on another smaller project, I discovered effects like Slow Time, can alter the perceived duration of spells. meaning that placing timers on them according to say, their duration (Obtained with GetNthEffectDuration()) doesnt exactly work as intended...

I mean I could try

Int Timer =  IceSpell.GetNthEffectDuration(0)
;Then
IceShader.Play(Subject, Timer)

But then I'm afraid if I use Slow Time mid-battle,it will completely scramble the duration... Can't remember exactly if it would make the shader end before the effect finishes or after it. And it's absolutely imperative for the visuals that the effects ends exactly when the effect ends.

Not to mention I wouldn't be able to run the loop function I used, which is

Function ShaderRedundancyLoop(Bool DeadLoop)
	Bool Running = False
	If DeadLoop ; DeadLoop has a counter to make sure it only works for a limited time trying to apply its shaders in case it failed the initial attempts 
		Int Counter = 0
		While Cristallized && Subject.Is3DLoaded() && Counter <= 10
			If !Running
				Running = True
				ElementalFrozenShader_Redundant.Play(Subject)
				Counter += 1
				Utility.Wait(0.1)
				Running = False
			EndIf
		EndWhile
	Else ; This loop is for the temporary effect, which sets Cristallized = False when it ends.
		While Cristallized && Subject.Is3DLoaded()
			If !Running
				Running = True
				ElementalFrozenShader_Redundant.Play(Subject)
				Utility.Wait(0.3)
				Running = False
			EndIf
		EndWhile
	EndIf	
EndFunction

If I use that, with timers, it blinks instead of reaffirming the shader's presence.

 

Ehhh...

At this point I dunno anymore.

My collaborator is a master of scripting, and he thinks there's no way to completely prevent these issues.

They're notthing serious that I haven't alteady created measures to fix mid-game anyway. If shaders get stuck, most of the times, they go away with simply applying a new shader on top of them with any other effect from the vanilla game. Or... using a cleansing spell I provided.

I guess I'm trying to make this bug-free and seamless in gameplay, but at this point I'm starting to think it's not possible.

Edited by Myst42
Link to comment
Share on other sites

  • Recently Browsing   0 members

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