Jump to content

[LE] Help with creating a toxicity script


Ryyz

Recommended Posts

Beat to the punch... Tho I'll post what I came up with. I suggest changing your magic effect (the one your script is attached) to have a duration of 90 seconds. Thus you can use the OnEffectFinish event to drop the global value by 25. Other changes are that I kept it as float, I didn't see where it needed to be used as an integer. Also, I used Mod. In theory, Mod is more thread safe but mileage may vary...

 

 

 

ScriptName WA_ToxicityScript Extends ActiveMagicEffect

;GlobalVariable that disallows potion. 0 is disallow. 1 is allow. disallow once toxicity is at 100. allow when below
GlobalVariable Property DisallowPotion Auto

;Toxicity level integer. default 0. max 100.
GlobalVariable Property ToxicityLevel Auto

Event OnEffectStart (Actor akTarget, Actor akCaster)
;Check if toxicity level is less than 100. If it is add 25 to toxicityamount.
	If (ToxicityLevel.GetValue() < 100.0)
		DisallowPotion.SetValue(1)
		ToxicityLevel.Mod(25.0)
		Debug.Notification("You drink the potion. Toxicity is now "+ToxicityLevel.GetValue())
	EndIf

;Check is toxicitylevel is 100. if it is set globalvariable to 0.
	If (ToxicityLevel.GetValue() == 100.0)
		DisallowPotion.SetValue(0)
		Debug.Notification("Your toxicity amount is too high. Drinking another potion would kill you.")
	EndIf
EndEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)
	If ToxicityLevel.GetValue() != 0
		ToxicityLevel.Mod(-25.0)
		Debug.Notification("Your toxicity amount is now "+ToxicityLevel.GetValue())
	EndIf
EndEvent
 

 

 

Hmm. Good idea on the effect duration, but there's a problem with that.

 

If you were to drink another potion before the effect ends, it would take it back down instantly.

 

I feel I'd need a script that checks every 90 seconds or so if the toxicity is above 0, if it is then run the decrease system. Any ideas?

 

Also, upon testing I realized something. The original script, the decrease thing would only do it once after every potion consumption which won't work.

Edited by Ryyz
Link to comment
Share on other sites

I'm pretty sure you can make stackable effects. I'm not sure of the specifics.

I'm sure I could.... but then you run into the problem of it being really OP... for example, one of the potions increases damage output. so if you stack those types of effects it would make the player ridiculously OP.

Link to comment
Share on other sites

Maybe i'm missing something thatbhas been said previously but couldnt you separate both things? so you have potions that simply add toxicity and then a script running on the player via a an ability or alias that removes X toxicity every Y seconds (registerforupdate or registerforupdategametime).
Link to comment
Share on other sites

Maybe i'm missing something thatbhas been said previously but couldnt you separate both things? so you have potions that simply add toxicity and then a script running on the player via a an ability or alias that removes X toxicity every Y seconds (registerforupdate or registerforupdategametime).

 

That might work in the short term. But will fail when waiting/sleeping for periods longer than the designated duration. The update event would only run once after the sleep/wait menus close. Thus storing the current time when the update is registered and comparing that to the new current time when the update fires and doing a bit of math to determine if multiple stages of toxicity need to be removed would be a necessary step.

Link to comment
Share on other sites

 

Maybe i'm missing something thatbhas been said previously but couldnt you separate both things? so you have potions that simply add toxicity and then a script running on the player via a an ability or alias that removes X toxicity every Y seconds (registerforupdate or registerforupdategametime).

 

That might work in the short term. But will fail when waiting/sleeping for periods longer than the designated duration. The update event would only run once after the sleep/wait menus close. Thus storing the current time when the update is registered and comparing that to the new current time when the update fires and doing a bit of math to determine if multiple stages of toxicity need to be removed would be a necessary step.

 

That's the reason I used Utility.Wait

Idk how else to do it without that happening.

 

So I made a little oninit script. I attached it to a blank quest and had the quest run on startup, the script runs but it doesn't actually work. Basically the debug message box I made telling me its running shows up, but when I drink the potion the debug box telling me that its working doesn't appear and the toxicity doesn't go down.

 

ScriptName WA_ToxicityRemovalScript Extends Quest

GlobalVariable Property ToxicityLevel Auto

Event OnInit ()
Debug.MessageBox("Script running.")
;Checks if toxicity level is greater than zero. If it is, remove 25 toxicity every 60 seconds.
If (ToxicityLevel.GetValue() > 0)
Debug.MessageBox("Script working.")
Utility.Wait(60)
ToxicityLevel.Mod(-25)
Debug.Notification("Toxicity level is now "+ToxicityLevel)
EndIf

;Checks if toxicity level is 0. If it is do nothing.
If (ToxicityLevel.GetValue() == 0)
EndIf

;Checks if toxicity level is less than 0. If it is set the value to 0
If (ToxicityLevel.GetValue() < 0)
ToxicityLevel.SetValue(0)
EndIf
EndEvent


I also tried attaching it to a quest alias but the script didn't load at all. I set the reference to player. I don't really understand how quest aliases work anyway.

I put the last one as a precaution in case the value ever goes below 0.

 

In case you were wondering, yes I put the correct global property in CK.

Also I was already planning on separating them before frank said that. I realized it wouldn't function properly as a magic effect.

Edited by Ryyz
Link to comment
Share on other sites

 

 

Maybe i'm missing something thatbhas been said previously but couldnt you separate both things? so you have potions that simply add toxicity and then a script running on the player via a an ability or alias that removes X toxicity every Y seconds (registerforupdate or registerforupdategametime).

 

That might work in the short term. But will fail when waiting/sleeping for periods longer than the designated duration. The update event would only run once after the sleep/wait menus close. Thus storing the current time when the update is registered and comparing that to the new current time when the update fires and doing a bit of math to determine if multiple stages of toxicity need to be removed would be a necessary step.

 

That's the reason I used Utility.Wait

Idk how else to do it without that happening.

 

So I made a little oninit script. I attached it to a blank quest and had the quest run on startup, the script runs but it doesn't actually work. Basically the debug message box I made telling me its running shows up, but when I drink the potion the debug box telling me that its working doesn't appear and the toxicity doesn't go down.

 

ScriptName WA_ToxicityRemovalScript Extends Quest

GlobalVariable Property ToxicityLevel Auto

Event OnInit ()
Debug.MessageBox("Script running.")
;Checks if toxicity level is greater than zero. If it is, remove 25 toxicity every 60 seconds.
If (ToxicityLevel.GetValue() > 0)
Debug.MessageBox("Script working.")
Utility.Wait(60)
ToxicityLevel.Mod(-25)
Debug.Notification("Toxicity level is now "+ToxicityLevel)
EndIf

;Checks if toxicity level is 0. If it is do nothing.
If (ToxicityLevel.GetValue() == 0)
EndIf

;Checks if toxicity level is less than 0. If it is set the value to 0
If (ToxicityLevel.GetValue() < 0)
ToxicityLevel.SetValue(0)
EndIf
EndEvent


I also tried attaching it to a quest alias but the script didn't load at all. I set the reference to player. I don't really understand how quest aliases work anyway.

I put the last one as a precaution in case the value ever goes below 0.

 

In case you were wondering, yes I put the correct global property in CK.

Also I was already planning on separating them before frank said that. I realized it wouldn't function properly as a magic effect.

 

 

To identify the first part of the problem I would suspect the reason you get the startup msg but nothing else is because at the time the OnInit() runs the value of ToxicityLevel is probably actually 0. So nothing happens. The times when OnInit is run is "For Quests and Aliases: On game startup, and again whenever the quest starts, due to the quest being reset." as per the wiki https://www.creationkit.com/index.php?title=OnInit. Though the way you describe the events is confusing. You shouldn't get any message from the quest when you drink your potion. Because the quest is already running. Any potential message from the quest should happen immediately upon start of the game. Also semi-relevant, did you make a .SEQ file for your plugin to properly identify the start enabled quest?

 

The OnInit() MUST run very fast. It is also latent(?) or maybe blocking is the right term. Never put a Wait() in there, EVER. In fact almost always you should set an update timer that will trigger a call back to the script to do any work. Something like

Event OnInit()
    RegisterForSingleUpdate(0.01)
EndEvent
 
Event OnUpdate()
    ; do your long running code here
EndEvent

Another relevant timer choice may be RegisterForSingleUpdateGameTime https://www.creationkit.com/index.php?title=RegisterForSingleUpdateGameTime_-_Form

 

You would probably need to change your code for incrementing toxicity on your magic effect. Perhaps have it call a function on the quest script to do the incrementing via a global.mod() call. That way the whole thing is threadsafe in case you pop multiple drinks at once. Otherwise there's issues where the counter will not increment properly.

Edited by BigAndFlabby
Link to comment
Share on other sites

The OnInit event runs only when the quest starts up. If you're wanting to catch something after the quest has already started, you don't want to use the OnInit event.

 

You will need to register for an update and track the current time.

 

Here is my suggestion:

 

Quest script:

GlobalVariable Property ToxicityLevel Auto
Float StartTime
Float EndTime
 
Function IncreaseToxicity()
  ToxicityLevel.Mod(25)
  RegisterForSingleUpdate(60) ;real time
  StartTime = Game.GetCurrentRealTime()
EndFunction
 
Event OnUpdate()
  EndTime = Game.GetCurrentRealTime()
  Float Mult = (EndTime - StartTime) / 60
  While (Mult as Int) > 0
    ToxicityLevel.Mod(-25)
    Mult -= 1.0
  EndWhile
EndEvent

Potion script:

Manually add a property by writing it directly on the script. It must follow this pattern: NameOfQuestScript Property VariableNameToUse Auto

Then when you assign data to the property, the CK will list all objects with the 'NameOfQuestScript' script attached. In your case it should just be your quest. So assign your quest to the property.

Then inside your OnEffectStart event add using the following pattern: VariableNameToUse.IncreaseToxicity()

 

What this will accomplish is when a potion is drank it will tell your quest script to run the IncreaseToxicity function which will in turn increase the toxicity global and register for a single update. Then when the update triggers, it should decrease the toxicity level. Calculations are in place to cover scenarios where the player might wait or sleep. So test those situations out.

 

 

FYI - Papyrus always rounds down when converting a float to an int. Thus if the Mult above turned out to be 2.75, it will be treated as a 2 and remove only 50 total in toxicity

Link to comment
Share on other sites

The OnInit event runs only when the quest starts up. If you're wanting to catch something after the quest has already started, you don't want to use the OnInit event.

 

You will need to register for an update and track the current time.

 

Here is my suggestion:

 

Quest script:

GlobalVariable Property ToxicityLevel Auto
Float StartTime
Float EndTime
 
Function IncreaseToxicity()
  ToxicityLevel.Mod(25)
  RegisterForSingleUpdate(60) ;real time
  StartTime = Game.GetCurrentRealTime()
EndFunction
 
Event OnUpdate()
  EndTime = Game.GetCurrentRealTime()
  Float Mult = (EndTime - StartTime) / 60
  While (Mult as Int) > 0
    ToxicityLevel.Mod(-25)
    Mult -= 1.0
  EndWhile
EndEvent

Potion script:

Manually add a property by writing it directly on the script. It must follow this pattern: NameOfQuestScript Property VariableNameToUse Auto

Then when you assign data to the property, the CK will list all objects with the 'NameOfQuestScript' script attached. In your case it should just be your quest. So assign your quest to the property.

Then inside your OnEffectStart event add using the following pattern: VariableNameToUse.IncreaseToxicity()

 

What this will accomplish is when a potion is drank it will tell your quest script to run the IncreaseToxicity function which will in turn increase the toxicity global and register for a single update. Then when the update triggers, it should decrease the toxicity level. Calculations are in place to cover scenarios where the player might wait or sleep. So test those situations out.

 

 

FYI - Papyrus always rounds down when converting a float to an int. Thus if the Mult above turned out to be 2.75, it will be treated as a 2 and remove only 50 total in toxicity

Yeah. The OnInit thing slipped my mind. I wrote that code at 4AM. I make mistakes at that time. I haven't actually tested anything since 5AM.

 

As for that code you put, I completely forgot about while.

 

Also, the quest was a dummy quest. Just there to run the script. Tried a bunch of different things. Probably should have clarified that. My mistake.

 

As for the "FYI" I knew that. I know ints can't have decimals. That's what floats are for.

As you can tell I'm still learning papyrus. I learn better by doing. I'm also good at analyzing code and figuring out what does what.

 

But thanks a lot for helping me out. I really appreciate it.

 

PS: All my properties are manually added. I do nothing with the script in CK til after its done and ready to be assigned. I use Notepad++ with the papyrus plugin. Compiles, catches errors, and its easier for me to code in. I'll work on it tomorrow and get back to you.

 

Edited by Ryyz
Link to comment
Share on other sites

The OnInit event runs only when the quest starts up. If you're wanting to catch something after the quest has already started, you don't want to use the OnInit event.

 

You will need to register for an update and track the current time.

 

Here is my suggestion:

 

Quest script:

GlobalVariable Property ToxicityLevel Auto
Float StartTime
Float EndTime
 
Function IncreaseToxicity()
  ToxicityLevel.Mod(25)
  RegisterForSingleUpdate(60) ;real time
  StartTime = Game.GetCurrentRealTime()
EndFunction
 
Event OnUpdate()
  EndTime = Game.GetCurrentRealTime()
  Float Mult = (EndTime - StartTime) / 60
  While (Mult as Int) > 0
    ToxicityLevel.Mod(-25)
    Mult -= 1.0
  EndWhile
EndEvent

Potion script:

Manually add a property by writing it directly on the script. It must follow this pattern: NameOfQuestScript Property VariableNameToUse Auto

Then when you assign data to the property, the CK will list all objects with the 'NameOfQuestScript' script attached. In your case it should just be your quest. So assign your quest to the property.

Then inside your OnEffectStart event add using the following pattern: VariableNameToUse.IncreaseToxicity()

 

What this will accomplish is when a potion is drank it will tell your quest script to run the IncreaseToxicity function which will in turn increase the toxicity global and register for a single update. Then when the update triggers, it should decrease the toxicity level. Calculations are in place to cover scenarios where the player might wait or sleep. So test those situations out.

 

 

FYI - Papyrus always rounds down when converting a float to an int. Thus if the Mult above turned out to be 2.75, it will be treated as a 2 and remove only 50 total in toxicity

 

Sorry I'm late getting back, been busy the last couple of days. It works beautifully. Thank you so much.

 

Also, that quest script had a mistake in it. Its Utility.GetCurrentRealTime not Game.GetCurrentRealTime. When I first compiled it shot up a bunch of errors. Looked up the function on the CK wiki and fixed it.

 

But again, thanks.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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