Jump to content

[Help] Scripting - How to call functions from another script


Recommended Posts

Posted

I'm trying to write a script that allows a mod's potions and drinks to proc SL Pheromones effects. I don't understand how typecasting and calling functions from other scripts work. Here's the script that I working on, but it won't compile. Any help would be appreciated.

 

Script:

Spoiler

Form Food

Bool Property SLPheromonesIsLoaded = False Auto Hidden

Quest Property SPPheromones Auto

FormList Property ca_Drink_Food Auto
FormList Property ca_Potion_Food Auto

;================================

Event OnInit()
    RegisterForModEvent("CA_Int_PlayerLoadsGame", "OnCA_Int_PlayerLoadsGame")
EndEvent

 

Event OnCA_Int_PlayerLoadsGame(string eventName, string strArg, float numArg, Form sender)
    PlayerLoadsGame()
EndEvent

 

Function PlayerLoadsGame()
    If Game.GetModByName("SexLab Pheromones.esp") != 255
        If GetState() != "Installed"
            GoToState("Installed")
        EndIf
    
    Else
        If GetState() != ""
            GoToState("")
        EndIf
    EndIf
EndFunction

 

Event OnEndState()
    Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
    SPPheromones = Game.GetFormFromFile(0x000D62, "SL Pheromones.esp") as Quest
EndEvent

 

Function CheckInstalledMod()

    If (Game.GetModByName("SL Pheromones.esp") != 255)
        If (SLPheromonesIsLoaded == False)
            SLPheromonesIsLoaded = True
            SLPheromonesCompatibility()  
        Endif
    Else
        SLPheromonesIsLoaded = False
    EndIf
EndFunction

 

Function SLPheromonesCompatibility()

    If ca_Drink_Food.HasForm(Food) || ca_Potion_Food.HasForm(Food)
        Quest CA_Compatibility = SPPheromones
        (CA_Compatibility as SLPheromonesControlScript).IngestPheromones()
        Debug.Notification("It tastes weird.")
    EndIf        

EndFunction

 

Posted
44 minutes ago, Visio Diaboli said:

What's the compile error? Something about SLPheromonesControlScript isn't a type?

 

Yeah pretty much.

 

cannot convert to unknown type slpheromonescontrolscript

 

cannot cast a quest to a slpheromonescontrolscript, types are incompatible
 

slpheromonescontrolscript is not a known user-defined type

 

Posted (edited)
13 minutes ago, RangerEdas said:

 

Yeah pretty much.

 

cannot convert to unknown type slpheromonescontrolscript

 

cannot cast a quest to a slpheromonescontrolscript, types are incompatible
 

slpheromonescontrolscript is not a known user-defined type

 

So it doesn't know where SLPheromonesControlScript.psc is, it's just a matter of why. Just checking off the boxes here, is SLPheromonesControlScript.psc in your scripts/source folder? And if so can that compile?

 

Also sometimes if you launch CK through MO2, the compiler will have difficulty finding source files, I've had to move everything I need to compile into the physical data/ folder

Edited by Visio Diaboli
Posted (edited)

I have SL Pheromones enabled and SLPheromonesControlScript.psc was in the scripts/source folder, which wouldn't allow me to edit the source. I tried source/scripts and it gave me a bunch of unknown type errors like "unknown type sexlabframework".

 

Then I disabled SL Pheromones and put SLPheromonesControlScript.psc into the physical data/ folder, which gave me the same unknown type errors. 

 

Would I need to turn SexLab and SexLab Aroused folders into source/scripts?

 

Edit: Making both SexLab and SexLab Aroused folders into source/scripts gives variable undefined errors from the sslBaseExpression.psc and SPMCMConfig.psc

Edited by RangerEdas
Posted

Not sure what the compiler's deal is with source/scripts vs scripts/source, I think there's a way to change which one it looks at but not sure what it is. Sounds like you're getting closer, though, because now it gives different errors than before. Typically you'd need to move the entire dependency tree's scripts into the same compiler-visible location - I think sslBaseExpression.psc should be from SexLab too though.

Posted (edited)
12 hours ago, Visio Diaboli said:

Not sure what the compiler's deal is with source/scripts vs scripts/source, I think there's a way to change which one it looks at but not sure what it is. Sounds like you're getting closer, though, because now it gives different errors than before. Typically you'd need to move the entire dependency tree's scripts into the same compiler-visible location - I think sslBaseExpression.psc should be from SexLab too though.

 

After a bit of poking around, I finally got it to compile by using the same compiler visible location (source/scripts) for SKSE, FNIS, FNIS Creature Pack, XPMSSE, and RaceMenu, and installing SkyUI SDK (for SkyUi- and MCM-based scripts) and Mfg Console. However, it doesn't actually work once tested ingame. I attached the script to a quest with a forced player alias reference. Is there something wrong with my code?


Edit: I added "state Installed" and defined both functions (CheckInstalledMod() and SLPheromonesCompatibility()) in the empty state and it still didnt work.

Edited by RangerEdas
Posted

I don't know anything about SL Pheromones so I couldn't say if you're using its scripts right, but do you get the debug notifications? It isn't elegant but the best way to debug Papyrus is to just pepper it with debug.notification calls and see what happens when the code should run

Posted

The sources (.psc files) ALL need to be in the same place for mods and their dependencies. And that place has to be wherever your creation kit ini file is telling it to look. Some people change that to data/scripts/sources, but by default it looks for source files in data/source/scripts. I left mine at the default and I copy any mod's source files to data/source/scripts if they're not already there. Some mods have them in both locations. But you need to first find out where creation kit is expecting to find the source files and then be consistent about making sure they're there.

 

Posted
23 hours ago, Visio Diaboli said:

I don't know anything about SL Pheromones so I couldn't say if you're using its scripts right, but do you get the debug notifications? It isn't elegant but the best way to debug Papyrus is to just pepper it with debug.notification calls and see what happens when the code should run

 

I don't think the code even runs since I'm not getting any of the debug notifications I put in. I set up my quest and script like one of SL Survival's interface quests since that's the closest example of what I'm trying to do (Start game enabled and uncheck "run once"). 

 

Script:

Spoiler

Scriptname CA_Compatibility_SLPheromones extends Quest

{Compatibility script that allows consumables to proc SL Pheromones effects}

;================================

Form Food

Bool Property SLPheromonesIsLoaded = False Auto Hidden

ReferenceAlias SLP_PlayerAlias

Quest Property SPPheromones Auto

FormList Property ca_List_Drinks Auto
FormList Property ca_List_Potions Auto

;================================

Event OnInit()
    RegisterForModEvent("CA_Int_PlayerLoadsGame", "OnCA_Int_PlayerLoadsGame")
    debug.notification("Mod event registered.") 
EndEvent

Event OnCA_Int_PlayerLoadsGame(string eventName, string strArg, float numArg, Form sender)
    PlayerLoadsGame()
    debug.notification("Player has loaded game.")
EndEvent

Function PlayerLoadsGame()
    If Game.GetModByName("SexLab Pheromones.esp") != 255
        If GetState() != "Installed"
            debug.notification("SL Pheromones is present.")
            GoToState("Installed")
        EndIf
    
    Else
        If GetState() != ""
            debug.notification("SL Pheromones is not present.")
            GoToState("")
        EndIf
    EndIf
EndFunction

Event OnEndState()
    Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
   SLP_PlayerAlias = (Game.GetFormFromFile(0x000D62, "SL Pheromones.esp") as Quest).GetNthAlias(0) as ReferenceAlias
    debug.notification("SL Pheromones Quest has been called.")
EndEvent

State Installed

    Function SLPheromonesCompatibility()

        If ca_List_Drinks.HasForm(Food) || ca_List_Potions.HasForm(Food)
            Quest CA_Compatibility = SPPheromones
            (CA_Compatibility as SLPheromonesControlScript).IngestPheromones()
            Debug.Notification("It tastes weird.")
        EndIf        

    EndFunction
EndState

;================================

Function SLPheromonesCompatibility()
EndFunction

 

Posted
1 minute ago, RangerEdas said:

CA_Int_PlayerLoadsGame

Is this something you yourself are sending? I would guess from a 'Scriptname <> extends ReferenceAlias' script attached to the player alias?

Posted
8 minutes ago, Visio Diaboli said:

Is this something you yourself are sending? I would guess from a 'Scriptname <> extends ReferenceAlias' script attached to the player alias?

 

Yeah but not from a 'Scriptname <> extends ReferenceAlias' script attached to the player alias. Do I need a secondary script to send it since I thought I could do that with just one.

Posted

Depends how you're sending it I guess, but I would assume you would want to send that from the OnPlayerLoadGame event. The OnPlayerLoadGame event will only get sent to a script attached to a ReferenceAlias that's assigned to the player. So if you had something like:

Event OnPlayerLoadGame()
  SendModEvent("CA_Int_PlayerLoadsGame")
endEvent

I'd think that would result in you atleast getting "Player has loaded game." in the corner. Although are you even getting "Mod event registered."? If not, have you generated an SEQ file yet?

Posted
3 hours ago, Visio Diaboli said:

Depends how you're sending it I guess, but I would assume you would want to send that from the OnPlayerLoadGame event. The OnPlayerLoadGame event will only get sent to a script attached to a ReferenceAlias that's assigned to the player. So if you had something like:

Event OnPlayerLoadGame()
  SendModEvent("CA_Int_PlayerLoadsGame")
endEvent

I'd think that would result in you atleast getting "Player has loaded game." in the corner. Although are you even getting "Mod event registered."? If not, have you generated an SEQ file yet?

 

Okay so I did everything you said and it kinda worked. Testing the script on a new game only gets me "Mod event registered". But, after saving and reloading that save, I get all of the notifications up to "SL Pheromones Quest has been called.". I don't the "It tastes weird." notification after drinking a potion from my mod. It doesn't seem to work at all on a current save.

Posted (edited)

Insert more debugging. 

 

Scriptname CA_Compatibility_SLPheromones extends Quest

{Compatibility script that allows consumables to proc SL Pheromones effects}

;================================

Form Food

Bool Property SLPheromonesIsLoaded = False Auto Hidden

ReferenceAlias SLP_PlayerAlias

Quest Property SPPheromones Auto

FormList Property ca_List_Drinks Auto
FormList Property ca_List_Potions Auto

;================================

Event OnInit()
    RegisterForModEvent("CA_Int_PlayerLoadsGame", "OnCA_Int_PlayerLoadsGame")
    debug.notification("Mod event registered.") 
EndEvent

Event OnCA_Int_PlayerLoadsGame(string eventName, string strArg, float numArg, Form sender)
    PlayerLoadsGame()
    debug.notification("Player has loaded game.")
EndEvent

Function PlayerLoadsGame()
	Debug.Messagebox("PlayerLoadsGame()") 
	If Game.GetModByName("SexLab Pheromones.esp") != 255
		If GetState() != "Installed"
			debug.notification("SL Pheromones is present.")
			GoToState("Installed")
		EndIf

	Else
		If GetState() != ""
			debug.notification("SL Pheromones is not present.")
			GoToState("")
		EndIf
	EndIf
EndFunction

Event OnEndState()
	Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
	SLP_PlayerAlias = (Game.GetFormFromFile(0x000D62, "SL Pheromones.esp") as Quest).GetNthAlias(0) as ReferenceAlias
	debug.notification("SL Pheromones Quest has been called.")
EndEvent

State Installed
	Function SLPheromonesCompatibility()
		If ca_List_Drinks.HasForm(Food) || ca_List_Potions.HasForm(Food)
			Debug.Messagebox("SLPheromonesCompatibility()")
			Quest CA_Compatibility = SPPheromones
			(CA_Compatibility as SLPheromonesControlScript).IngestPheromones()
			Debug.Notification("It tastes weird.")
		Else
			Debug.Messagebox("SLPheromonesCompatibility() ELSE")
		EndIf        
	EndFunction
EndState

;================================

Function SLPheromonesCompatibility()
	Debug.Messagebox("SLPheromonesCompatibility() STATE OFF!")
EndFunction

 

Use 'sqv  YourQuestName' in the console to check what state the script is in. 

 

7 hours ago, RangerEdas said:

It doesn't seem to work at all on a current save.

The order of events is important. Not just for the script but for your save too. If you created the alias but forgot to fill it with the player and then went into the game and saved it then your saves alias is empty and likely won't receive OnGameLoad events. Even if you go back to the CK and fill it now the saves version is still empty. You can: 

- Load an earlier save

- Restart the quest (easy)

- Force the ref via a script version update (not as easy)

 

Use sqv to check what's filling quest aliases. 

 

 

This code:

Quest CA_Compatibility = SPPheromones
(CA_Compatibility as SLPheromonesControlScript).IngestPheromones()

1. I don't know why you're creating another quest variable here when you have the same thing. SPPheromones and CA_Compatibility are the same thing. This is the same thing:

(SPPheromones as SLPheromonesControlScript).IngestPheromones()

 

2. SPPheromones - What is this? If this is a quest on another mod (that isn't a hard dependency) then it is empty (pointing at nothing). 

 

3. Reference alias SLP_PlayerAlias is not used anywhere in the script? Is the script you're trying to access attached to a quest OR a reference alias on a quest?

 

4. (CA_Compatibility as SLPheromonesControlScript).IngestPheromones()

This defeats the entire purpose of an interface script - you are casting to an external type on a script attached to an object. This has been known to potentially cause massive problems depending on a users installation. It's fine for testing purposes but this isn't something you should release. 

 

Review this:

https://www.loverslab.com/topic/106848-multiple-mods-with-soft-dependency-to-the-same-resource/?do=findComment&comment=2933753

 

Casting to a type that may or may not be installed should be done in an isolated script not attached to any form (not attached to anything in the CK)

 

5. Also a good idea to double check properties are filled (I always forget to fill properties and I've been doing this a long time) and of course check the papyrus log. 

Edited by Monoman1
Posted
6 hours ago, Monoman1 said:

3. Reference alias SLP_PlayerAlias is not used anywhere in the script? Is the script you're trying to access attached to a quest OR a reference alias on a quest?

 

I'm trying to access a function "IngestPheromones()" from the script "SLPheromonesControlScript", which is attached to a quest "SPPheromones".

 

So I've looked at that link and my scripts work for the most part.

 

Script A - The main script thats attached to a quest. 

Spoiler

Scriptname CA_Compatibility_SLPheromones extends Quest

{Compatibility script that allows consumables to proc SL Pheromones effects}

;================================

Form Food

Quest SPPheromones

FormList Property ca_List_Drinks Auto
FormList Property ca_List_Potions Auto

;================================

Event OnInit()
    RegisterForModEvent("CA_Int_PlayerLoadsGame", "OnCA_Int_PlayerLoadsGame")
    debug.notification("Mod event registered.") 
EndEvent

Event OnCA_Int_PlayerLoadsGame(string eventName, string strArg, float numArg, Form sender)
    debug.notification("Player has loaded game.")
    PlayerLoadsGame()
EndEvent

Function PlayerLoadsGame()
    If Game.GetModByName("SexLab Pheromones.esp") != 255
        If GetState() != "Installed"
        debug.notification("SL Pheromones is present.")
        GoToState("Installed")
        EndIf
    
    Else
        If GetState() != ""
        debug.notification("SL Pheromones is not present.")
                GoToState("")
        EndIf
    EndIf
EndFunction

Event OnEndState()
    Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
     SPPheromones = Game.GetFormFromFile(0x000D62, "SexLab Pheromones.esp") as Quest
    debug.notification("SL Pheromones Quest has been called.")
EndEvent

State Installed

    Function SLPheromonesCompatibility()
        If ca_List_Drinks.HasForm(Food) || ca_List_Potions.HasForm(Food)
            Debug.Messagebox("SLPheromonesCompatibility()")
            CA_IntSLP.SLPheromonesCompatibility(SPPheromones)
            Debug.Notification("It tastes weird.")
        Else
            Debug.Messagebox("SLPheromonesCompatibility() ELSE")
        EndIf        
    EndFunction

EndState

;================================

Function SLPheromonesCompatibility()
EndFunction

 

Script B - The interface script that's not attached to anything.

Spoiler

Scriptname CA_IntSLP  Hidden 

;================================

Function SLPheromonesCompatibility(Quest SPPheromones) Global
        (SPPheromones as SLPheromonesControlScript).IngestPheromones()
        Debug.Notification("It tastes weird.")      
EndFunction

 

Script C - A reference alias script that attached to a reference alias (forced player ref) in my quest.

Spoiler

Scriptname CA_SLP_PlayerAlias extends ReferenceAlias  

;================================

Event OnPlayerLoadGame()
    SendModEvent("CA_Int_PlayerLoadsGame")
    debug.notification("Reference Alias.")
endEvent

 

I used sqv to check out the quest aliases and it said that my quest was enabled and running. SPPheromones was pointing to the correct thing (0x000D62) but Food was pointing to nothing (Food = None). How do I get it to point to the formlists where I stored my potions and drinks?

Posted
22 minutes ago, RangerEdas said:

How do I get it to point to the formlists where I stored my potions and drinks?

Use the properties menu and fill them in (point them to your lists)

I usually set the property names to be the same in the script as in the CK. That way you can use autofill. 

 

PS: properties are the same with saves as I said earlier. Once you save a game with an empty property, it stays empty until 1 of the 3 things I mentioned before. 

Posted
10 minutes ago, Monoman1 said:

Use the properties menu and fill them in (point them to your lists)

I usually set the property names to be the same in the script as in the CK. That way you can use autofill. 

 

PS: properties are the same with saves as I said earlier. Once you save a game with an empty property, it stays empty until 1 of the 3 things I mentioned before. 

 

"Form Food" doesnt have a property listed on the menu. It's only the two formlists I already defined and filled in with "FormList Property<> Auto". "Form Property Food Auto" doesn't work either since there's only two options if manually filled: "CommandingActorpersistenceForm" and "PapyrusPersistenceForm".

Posted (edited)
20 minutes ago, RangerEdas said:

"Form Food" doesnt have a property listed on the menu.

You expect this to be whatever the player equipped? But that's not automatic. Add event OnObjectEquipped to the player alias script. Might as well replace the player load game element as well. I only use a mod event in SLS because there are a lot of interfaces to trigger. 

 

Event OnPlayerLoadGame()
	Phers.PlayerLoadsGame() ; Call directly instead of using a mod event
EndEvent

Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
	If akBaseObject as Potion ; Filter out anything thats not a potion
    	Phers.SLPheromonesCompatibility(akBaseObject)
	EndIf
EndEvent

CA_Compatibility_SLPheromones Property Phers Auto

 

Change the interface function SLPheromonesCompatibility() to:

SLPheromonesCompatibility(Form akBaseObject)

So that you can pass in whatever was equipped from the alias to the quest script

 

Eg:

State Installed
	Function SLPheromonesCompatibility(Form akBaseObject)
		If ca_List_Drinks.HasForm(akBaseObject) || ca_List_Potions.HasForm(akBaseObject)
			Debug.Messagebox("SLPheromonesCompatibility()")
			Quest CA_Compatibility = SPPheromones
			(CA_Compatibility as SLPheromonesControlScript).IngestPheromones()
			Debug.Notification("It tastes weird.")
		Else
			Debug.Messagebox("SLPheromonesCompatibility() ELSE")
		EndIf        
	EndFunction
EndState

 

Add the parameter to the function for both states (parameters must match in all states)

 

You can remove 'Form Food' from the quest script.

 

You can also remove the entire blocks:

Event OnInit()
    RegisterForModEvent("CA_Int_PlayerLoadsGame", "OnCA_Int_PlayerLoadsGame")
    debug.notification("Mod event registered.") 
EndEvent

Event OnCA_Int_PlayerLoadsGame(string eventName, string strArg, float numArg, Form sender)
    PlayerLoadsGame()
    debug.notification("Player has loaded game.")
EndEvent

As you're calling the load game function directly from the alias - there's no need for the mod event stuff now. 

Edited by Monoman1
Posted (edited)
6 hours ago, Monoman1 said:

Add event OnObjectEquipped to the player alias script. Might as well replace the player load game element as well. I only use a mod event in SLS because there are a lot of interfaces to trigger. 

 

Why am I using the OnObjectEquipped event instead of the OnItemRemoved Event when I'm tracking when a potion is consumed?

 

So the player alias script should look like this?

 

Script C

Spoiler

Scriptname CA_SLS_PlayerAlias extends ReferenceAlias   

;================================

CA_Compatibility_SLPheromones Property Phers Auto

;=============================

Event OnPlayerLoadGame()
    debug.notification("Player has loaded game")
    Phers.PlayerLoadsGame() ; Call directly instead of using a mod event
EndEvent

Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
    If akBaseObject as Potion ; Filter out anything thats not a potion
        debug.notification("Phers.SLPheromonesCompatibility(akBaseObject)")
        Phers.SLPheromonesCompatibility(akBaseObject)
    EndIf
EndEvent

 

The sqv command kept saying "SPPheromones = None" even though there was no change on that part of the script. So I got rid of the OnEndState event and moved them down to Function SLPheromonesCompatibility(Form akBaseObject) but it didn't do anything.  The interface script (Script B) remains unchanged.

 

Script A

Spoiler

Scriptname CA_Compatibility_SLPheromones extends Quest

{Compatibility script that allows consumables to proc SL Pheromones effects}

;================================
Quest SPPheromones

FormList Property ca_List_Drinks Auto
FormList Property ca_List_Potions Auto

;================================

Function PlayerLoadsGame()
    If Game.GetModByName("SexLab Pheromones.esp") != 255
        If GetState() != "Installed"
        debug.notification("SL Pheromones is present.")
        GoToState("Installed")
        EndIf
    
    Else
        If GetState() != ""
        debug.notification("SL Pheromones is not present.")
                GoToState("")
        EndIf
    EndIf
EndFunction

State Installed

    Function SLPheromonesCompatibility(Form akBaseObject)

        Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
         SPPheromones = Game.GetFormFromFile(0x000D62, "SexLab Pheromones.esp") as Quest
        debug.notification("SL Pheromones Quest has been called.")

        If ca_List_Drinks.HasForm(akBaseObject) || ca_List_Potions.HasForm(akBaseObject)
            Debug.Messagebox("SLPheromonesCompatibility(Form akBaseObject)")
            CA_IntSLP.SLPheromonesCompatibility(SPPheromones)
            Debug.Notification("It tastes weird.")
        Else
            Debug.Messagebox("SLPheromonesCompatibility() ELSE")
        EndIf        
    EndFunction

EndState

;================================

Function SLPheromonesCompatibility(Form akBaseObject)
EndFunction

 

At what number of interfaces do you start thinking about using a mod event?

 

This is actually more complicated than I thought... 

 

Edit: I've added this to the beginning of Script A and  sqv shows that SPPheromones is now filled.

Event OnInit()
    PlayerLoadsGame()
EndEvent

 

Edited by RangerEdas
Posted (edited)
10 hours ago, RangerEdas said:

Why am I using the OnObjectEquipped event instead of the OnItemRemoved Event when I'm tracking when a potion is consumed?

Because the player may put the item into a cupboard/sell it/have it stolen/give it to a follower. Which would all fire OnItemRemoved(). 

I assume you wish to fire on consumption. 

10 hours ago, RangerEdas said:

So the player alias script should look like this?

Looks ok. 

Don't forget to fill the 'Phers' property on the alias. There will only be one possible fill for 'phers' anyway (assuming you haven't attached the script to another object)

10 hours ago, RangerEdas said:

At what number of interfaces do you start thinking about using a mod event?

Up to you really. Since we were creating a direct link between the alias and the quest script there wasn't much point. Both work. Direct looks a little neater. 

 

10 hours ago, RangerEdas said:

The sqv command kept saying "SPPheromones = None" even though there was no change on that part of the script.

Yea. Adding the OnInit block like you have is probably fine in this case. It would have been empty until you loaded the game. I'd add a wait though:

Event OnInit()
    Utility.Wait(5.0)
    PlayerLoadsGame()
EndEvent
10 hours ago, RangerEdas said:

So I got rid of the OnEndState event and moved them down to Function SLPheromonesCompatibility(Form akBaseObject) but it didn't do anything.

Don't do that. You've added a 5 second wait every time this item is consumed. It will delay reaction and seem weird to the player (unless you actually want a delay). Add back in OnEndState() and move the wait back in there. It'll add a delay before allowing your scripts to access these external scripts, potentially before they're ready to receive calls. But it'll only add this delay once - while starting up the interface. 

 

Event OnEndState()
	Utility.Wait(5.0) ; Wait before entering active state to help avoid making function calls to scripts that may not have initialized yet.
	SPPheromones = Game.GetFormFromFile(0x000D62, "SexLab Pheromones.esp") as Quest
    Debug.Notification("SPPheromones has been filled")
EndEvent

 

To be a little more efficient I might move the formlist checks to the alias instead. Which would mean clearing the properties on the quest & removing the properties from the script as they wouldn't be used in that script any more. And move them to the alias. 

Scriptname CA_SLS_PlayerAlias extends ReferenceAlias   

;================================

CA_Compatibility_SLPheromones Property Phers Auto

;=============================

Event OnPlayerLoadGame()
    debug.notification("Player has loaded game")
    Phers.PlayerLoadsGame() ; Call directly instead of using a mod event
EndEvent

Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference)
    If akBaseObject as Potion && (ca_List_Drinks.HasForm(akBaseObject) || ca_List_Potions.HasForm(akBaseObject)) ; Filter out anything thats not a potion
        debug.notification("Phers.SLPheromonesCompatibility(akBaseObject)")
        Phers.SLPheromonesCompatibility(akBaseObject)
    EndIf
EndEvent

Formlist Property ca_List_Drinks Auto
Formlist Property ca_List_Potions Auto

 

My understanding is that calls to other scripts are somewhat slower so filtering items as early as possible (and so making calls to 'phers' only when you consume the exact potions you want) would be preferred. 

Edited by Monoman1
Posted
3 hours ago, Monoman1 said:

Because the player may put the item into a cupboard/sell it/have it stolen/give it to a follower. Which would all fire OnItemRemoved(). 

I assume you wish to fire on consumption. 

 

Ahh I see. Thanks for the clarification. It was a little confusing since OnObjectEquipped implies that its used for armor/weapons but I guess you would equip a potion to consume it.

 

3 hours ago, Monoman1 said:

Don't forget to fill the 'Phers' property on the alias. There will only be one possible fill for 'phers' anyway (assuming you haven't attached the script to another object)

 

I had already moved the formlists to the player alias script and clicked autofill, completely forgetting to manually fill the Phers property. It finally worked on both a new game and a current save after I did that and the other suggestions you made!! Thank you so much for your help and @Visio Diaboli for your help too!! I really appreciate it! This was more complicated than I thought but I'm glad it's working perfectly. Scripting has fried my brain. 

 

3 hours ago, Monoman1 said:

clearing the properties on the quest & removing the properties from the script as they wouldn't be used in that script any more. And move them to the alias. 

 

Just make sure, this is done when "FormList Property <> Auto" is deleted from the script and it doesn't show up on the properties menu afterwards, right?

 

3 hours ago, Monoman1 said:

Up to you really. Since we were creating a direct link between the alias and the quest script there wasn't much point. Both work. Direct looks a little neater. 

 

 

Since I'm thinking of adding RND and iNeed compatibility to my mod, can I use your interface scripts from SLS? Or is it better to add that sort of compatibility through an esp? Not really sure which method is better/preferred.

 

Also, if it's not too much trouble (not related to this topic), but I made a working script that adds an ingredient to the player's inventory after using the spell and I'd like a second opinion on it to make sure I don't accidentally ruin someone's save.

Spoiler

Scriptname CA_ME_PlayerVialSolo extends ActiveMagicEffect  

{Adds a race-dependent vial of cum upon spell cast}

;================================================

;Defines the player cum vials used in this script

Ingredient Property ca_CumAltmer Auto
Ingredient Property ca_CumArgonian Auto
Ingredient Property ca_CumBosmer Auto
Ingredient Property ca_CumBreton Auto
Ingredient Property ca_CumDunmer Auto
Ingredient Property ca_CumImperial Auto
Ingredient Property ca_CumKhajiit Auto
Ingredient Property ca_CumNord Auto
Ingredient Property ca_CumOrsimer Auto
Ingredient Property ca_CumRedguard Auto

;Defines man, mer, and beast races

Race Property HighElfRace Auto
Race Property HighElfRaceVampire Auto
Race Property ArgonianRace Auto
Race Property ArgonianRaceVampire Auto
Race Property WoodElfRace Auto
Race Property WoodElfRaceVampire Auto
Race Property BretonRace Auto
Race Property BretonRaceVampire Auto
Race Property DarkElfRace Auto
Race Property DarkElfRaceVampire Auto
Race Property ImperialRace Auto
Race Property ImperialRaceVampire Auto
Race Property KhajiitRace Auto
Race Property KhajiitRaceVampire Auto
Race Property NordRace Auto
Race Property NordRaceVampire Auto
Race Property OrcRace Auto
Race Property OrcRaceVampire Auto
Race Property RedguardRace Auto
Race Property RedguardRaceVampire Auto

;Defines global variables

GlobalVariable Property ca_CooldownTimer Auto
GlobalVariable Property GameDaysPassed Auto

;Defines the target actor

Actor Property PlayerREF Auto

;Defines failure message if spell is used within cooldown period

String Property RefractoryPeriod Auto

;Defines sound

Sound Property ca_MAGMasturbateFFFire Auto
Sound Property ca_MAGMasturbateCooldown Auto

;================================
    
Event OnEffectStart(Actor akTarget, Actor akCaster)
    
    If ca_CooldownTimer.GetValue() < GameDaysPassed.GetValue()
    
        Race PlayerRace = PlayerREF.GetRace()
        ca_MAGMasturbateFFFire.play(PlayerREF)
        
        ;Adds Altmer cum vial if player is a High Elf
        If PlayerRace == HighElfRace || PlayerRace == HighElfRaceVampire
            PlayerREF.AddItem(ca_CumAltmer,1,true)
            debug.notification("Vial of Altmer Cum Added")
            ;Spell can't be used until 6 hours have passed
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25) 
        
        ;Adds Argonian cum vial if player is an Argonian
        Elseif PlayerRace == ArgonianRace || PlayerRace == ArgonianRaceVampire
            PlayerREF.AddItem(ca_CumArgonian,1,true)
            debug.notification("Vial of Argonian Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Bosmer cum vial if player is a Wood Elf
        Elseif PlayerRace == WoodElfRace || PlayerRace == WoodElfRaceVampire
            PlayerREF.AddItem(ca_CumBosmer,1,true)
            debug.notification("Vial of Bosmer Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Breton cum vial if player is an Breton
        Elseif PlayerRace == BretonRace || PlayerRace == BretonRaceVampire
            PlayerREF.AddItem(ca_CumBreton,1,true)
            debug.notification("Vial of Breton Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Dunmer cum vial if player is an Dark Elf
        Elseif PlayerRace == DarkElfRace || PlayerRace == DarkElfRaceVampire
            PlayerREF.AddItem(ca_CumDunmer,1,true)
            debug.notification("Vial of Dunmer Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Imperial cum vial if player is an Imperial
        Elseif PlayerRace == ImperialRace || PlayerRace == ImperialRaceVampire
            PlayerREF.AddItem(ca_CumImperial,1,true)
            debug.notification("Vial of Imperial Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Khajiit cum vial if player is a Khajiit
        Elseif PlayerRace == KhajiitRace || PlayerRace == KhajiitRaceVampire
            PlayerREF.AddItem(ca_CumKhajiit,1,true)
            debug.notification("Vial of Khajiit Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Nord cum vial if player is an Nord
        Elseif PlayerRace == NordRace || PlayerRace == NordRaceVampire
            PlayerREF.AddItem(ca_CumNord,1,true)
            debug.notification("Vial of Nord Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Orsimer cum vial if player is an Orc
        Elseif PlayerRace == OrcRace || PlayerRace == OrcRaceVampire
            PlayerREF.AddItem(ca_CumOrsimer,1,true)
            debug.notification("Vial of Orsimer Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        
        ;Adds Redguard cum vial if player is a Redguard
        Elseif PlayerRace == RedguardRace || PlayerRace == RedguardRaceVampire
            PlayerREF.AddItem(ca_CumRedguard,1,true)
            debug.notification("Vial of Redguard Cum Added")
            ca_CooldownTimer.SetValue(GameDaysPassed.GetValue() + 0.25)
        Endif
    Else
        debug.notification(RefractoryPeriod)
        ca_MAGMasturbateCooldown.play(PlayerREF)
    Endif
EndEvent

 

Once again, thanks so much for all your help!!!

Posted (edited)
25 minutes ago, RangerEdas said:

Also, if it's not too much trouble (not related to this topic), but I made a working script that adds an ingredient to the player's inventory after using the spell and I'd like a second opinion on it to make sure I don't accidentally ruin someone's save

Doesn't seem like it could break too terribly to me, but the only way to tell for sure is to test it and try to break it a lot, and to check the script logs to see if it adds any errors to them.

It doesn't do anything with animations, mess with quests, mess with the player's state, or remove items, which imo are the areas that can screw things up the most noticeably

Edited by Visio Diaboli
Posted
10 minutes ago, Visio Diaboli said:

Doesn't seem like it could break too terribly to me, but the only way to tell for sure is to test it and try to break it a lot, and to check the script logs to see if it adds any errors to them.

It doesn't do anything with animations, mess with quests, mess with the player's state, or remove items, which imo are the areas that can screw things up the most noticeably

 

Yeah that makes sense. I'll make sure to test it a lot before I release it. Thanks!

Posted
19 hours ago, RangerEdas said:

Just make sure, this is done when "FormList Property <> Auto" is deleted from the script and it doesn't show up on the properties menu afterwards, right?

Yes. But I would clear the property in the properties menu first and save the file. Then remove the line from the script and compile. 

 

I think I remember it causing some (harmless?) log spam otherwise. Though I've been doing the above for so long I could be wrong. 

19 hours ago, RangerEdas said:

can I use your interface scripts from SLS?

sure. 

19 hours ago, RangerEdas said:

Or is it better to add that sort of compatibility through an esp? Not really sure which method is better/preferred.

Users will probably prefer this method - Less esps and patches to worry about. 

Also I suppose you don't need to worry about users not installing the correct patch. 

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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