randomtguy Posted August 19, 2015 Posted August 19, 2015 I'm trying to create a mod that bypasses the need to use Death Alternative with Simple Slavery as I can never get the former to damn well work. It's supposed to check when the player has been defeated through any Defeat type mod (by checking a player's health at the moment an aggressive SexLab animation starts) and give a configurable chance of teleporting you to the Simple Slavery market. But I'm clearly missing something key as the only debug message I've inserted that I've managed to trigger is the one to check whether the mod's active. It may be because I'm iffy on how to use StorageUtil - do I need to declare it in the scripts like you do with SexLab or something? It may be any number of other things as I'm still so new at scripting. Here's the MCM menu script: ScriptName SimplerSlaveryMCMScript Extends SKI_ConfigBase ; OIDs int aOID int MinhealththresholdOID_S int ChanceofenslavementOID_S ; Toggle states bool aVal = true float Minhealththreshold = 25.0 float Chanceofenslavement = 25.0 event OnLoad() StorageUtil.SetIntValue(none, "SRSModOn", aOID) StorageUtil.SetIntValue(none, "SRSMinHealth", MinhealththresholdOID_S) StorageUtil.SetIntValue(none, "SRSChanceofEnslave", ChanceofenslavementOID_S) endEvent event OnPageReset(string page) {Called when a new page is selected, including the initial empty page} SetCursorFillMode(LEFT_TO_RIGHT) AddToggleOption("Simpler Slavery active", aVal) MinhealththresholdOID_S = AddSliderOption("Minimum health threshold", Minhealththreshold, "{0}%") ChanceofenslavementOID_S = AddSliderOption("Chance of enslavement", Chanceofenslavement, "{1}%") endEvent event OnOptionSelect(int option) {Called when a non-interactive option has been selected} if (option == aOID) aVal = !aVal SetToggleOptionValue(aOID, aVal) StorageUtil.SetIntValue(none, "SRSModOn", aOID) endIf endEvent event OnOptionDefault(int option) if (option == aOID) aVal = true ; default value SetToggleOptionValue(aOID, aVal) StorageUtil.SetIntValue(none, "SRSModOn", aOID) elseif (option == MinhealththresholdOID_S) SetSliderOptionValue(MinhealththresholdOID_S, Minhealththreshold, "{0}%") StorageUtil.SetIntValue(none, "SRSMinHealth", MinhealththresholdOID_S) elseif (option == ChanceofenslavementOID_S) SetSliderOptionValue(ChanceofenslavementOID_S, Chanceofenslavement, "{0}%") StorageUtil.SetIntValue(none, "SRSChanceofEnslave", ChanceofenslavementOID_S) endIf endEvent Event OnOptionHighlight(int option) if (option == aOID) SetInfoText("Select to activate or deactivate this mod") elseif (option == MinhealththresholdOID_S) SetInfoText("Minimum health threshold required to trigger slavery") elseif (option == ChanceofenslavementOID_S) SetInfoText("Chance of being enslaved. Set to just above your defeat threshold") endIf endEvent event OnOptionSliderOpen(int option) if (option == MinhealththresholdOID_S) SetSliderDialogStartValue(Minhealththreshold) SetSliderDialogDefaultValue(25) SetSliderDialogRange(1.0, 100.0) SetSliderDialogInterval(1.0) elseIf (option == ChanceofenslavementOID_S) SetSliderDialogStartValue(Chanceofenslavement) SetSliderDialogDefaultValue(25) SetSliderDialogRange(1.0, 100.0) SetSliderDialogInterval(1.0) endif endevent event OnOptionSliderAccept(int option, float value) if (option == MinhealththresholdOID_S) Minhealththreshold = value SetSliderOptionValue(MinhealththresholdOID_S, Minhealththreshold, "{0}%") StorageUtil.SetIntValue(none, "SRSMinHealth", MinhealththresholdOID_S) elseif (option == ChanceofenslavementOID_S) Chanceofenslavement = value SetSliderOptionValue(ChanceofenslavementOID_S, Chanceofenslavement, "{0}%") StorageUtil.SetIntValue(none, "SRSChanceofEnslave", ChanceofenslavementOID_S) endIf endEvent And here's the trigger script: ScriptName SimplerSlaveryTriggerScript Extends Quest SexLabFramework Property SexLab Auto SimplerSlaveryMCMScript Property Config Auto ObjectReference Property sslv_cagemark2 Auto Actor Player Event OnInit() RegisterForModEvent("AnimationStart", "CheckDefeated") Debug.Notification("Simpler Slavery Detected") EndEvent event CheckDefeated(string eventName, string argString, float argNum, form sender) int SRSModOnInt = StorageUtil.GetIntValue(none, "SRSModOn") if SRSModOnInt == 0 Debug.Notification("Mod active check failed") return endif Debug.Notification("Mod active check passed") int SRSMinHealthInt = StorageUtil.GetIntValue(none, "SRSMinHealth") If Player.getav("Health") > SRSMinHealthInt Debug.Notification("Health threshold check failed") return endif Debug.Notification("Health threshold check passed") sslThreadController controller = SexLab.HookController(argString) if !controller.HasPlayer Debug.Notification("Player involvement check failed") return endif Debug.Notification("Player involvement check passed") actor victim = SexLab.HookVictim(argString) if victim != player Debug.Notification("Player is victim check failed") return endif RegisterForModEvent("AnimationEnd", "EnslavePlayerEvent") Debug.Notification("Player is victim check passed") EndEvent event EnslavePlayerEvent(string eventName, string argString, float argNum, form sender) UnregisterForModEvent("AnimationEnd") int SRSEnslaveInt = StorageUtil.GetIntValue(none, "SRSChanceofEnslave") int random = Utility.RandomInt(0, 99) if random > SRSEnslaveInt Debug.Notification("Random roll failed") return endif Debug.Notification("Random roll passed") Game.GetPlayer().MoveTo(sslv_cagemark2) EndEvent
Sailing Rebel Posted August 19, 2015 Posted August 19, 2015 One issue, the script appears to be using StorageUtil to store the OID of the MCM elements rather than the value those elements are returning. StorageUtil.SetIntValue(none, "SRSMinHealth", MinhealththresholdOID_S) Should be StorageUtil.SetFloatValue(none, "SRSMinHealth", Minhealththreshold) or StorageUtil.SetIntValue(none, "SRSMinHealth", Minhealththreshold as Int)
randomtguy Posted August 19, 2015 Author Posted August 19, 2015 One issue, the script appears to be using StorageUtil to store the OID of the MCM elements rather than the value those elements are returning. StorageUtil.SetIntValue(none, "SRSMinHealth", MinhealththresholdOID_S) Should be StorageUtil.SetFloatValue(none, "SRSMinHealth", Minhealththreshold) or StorageUtil.SetIntValue(none, "SRSMinHealth", Minhealththreshold as Int) Thanks for that, that was definitely part of the problem, though clearly not all of it as the other debug messages still aren't showing.
Guest Posted August 19, 2015 Posted August 19, 2015 In your code you are never initializing the "Player" variable. Change it with: Actor Property PlayerRef Auto Second point: It is good and wise to specify the actual storage area for Storage Utils. Saving it globally can lead to reading the value in not the correct way. You can switch (if this values are written and read just by you) on a JSON file, like: JSONUtil.setFloatValue("RandomTGuyMod", "SRSMinHealth", Minhealththreshold)
randomtguy Posted August 19, 2015 Author Posted August 19, 2015 In your code you are never initializing the "Player" variable. Change it with: Actor Property PlayerRef Auto Second point: It is good and wise to specify the actual storage area for Storage Utils. Saving it globally can lead to reading the value in not the correct way. You can switch (if this values are written and read just by you) on a JSON file, like: JSONUtil.setFloatValue("RandomTGuyMod", "SRSMinHealth", Minhealththreshold) Ah, that makes a lot of sense. If I did that, then can and should I attach the script to PlayerRef in the CK (rather than in the quest window)? It wasn't working when I tried before. As for JSONUtil, why would I want to use a float instead of an int? If I do can I still call it in the trigger script the same way? Thanks a lot for your help once again.
Guest Posted August 19, 2015 Posted August 19, 2015 Ah, that makes a lot of sense. If I did that, then can and should I attach the script to PlayerRef in the CK (rather than in the quest window)? It wasn't working when I tried before. As for JSONUtil, why would I want to use a float instead of an int? If I do can I still call it in the trigger script the same way? Thanks a lot for your help once again. Your script extends a Quest, so it should be attached to a quest. I just added a property PlayerRef, because you are using the Player actor, and this property is the fastest possible way to get it. I used for JSON a SetFloatValue because your variable has a Float type. You should use the appropriate function to avoid casting: if your variable is a float but you store it as an Int, then you have to cast it. I don't know what is the best type for you, but for sure you can use the most appropriate value, and use the set/get functions specific for the type of the variable: int function SetIntValue(string FileName, string KeyName, int value) float function SetFloatValue(string FileName, string KeyName, float value) string function SetStringValue(string FileName, string KeyName, string value) form function SetFormValue(string FileName, string KeyName, form value)
randomtguy Posted August 20, 2015 Author Posted August 20, 2015 Ah, that makes a lot of sense. If I did that, then can and should I attach the script to PlayerRef in the CK (rather than in the quest window)? It wasn't working when I tried before. As for JSONUtil, why would I want to use a float instead of an int? If I do can I still call it in the trigger script the same way? Thanks a lot for your help once again. Your script extends a Quest, so it should be attached to a quest. I just added a property PlayerRef, because you are using the Player actor, and this property is the fastest possible way to get it. I used for JSON a SetFloatValue because your variable has a Float type. You should use the appropriate function to avoid casting: if your variable is a float but you store it as an Int, then you have to cast it. I don't know what is the best type for you, but for sure you can use the most appropriate value, and use the set/get functions specific for the type of the variable: int function SetIntValue(string FileName, string KeyName, int value) float function SetFloatValue(string FileName, string KeyName, float value) string function SetStringValue(string FileName, string KeyName, string value) form function SetFormValue(string FileName, string KeyName, form value) Thanks for that, I rewrote it to use JSON floats, and to mostly avoid casting except I don't know how to use JSON to store boolean values. But I'm clearly still missing something key as none of the debug messages are showing up except the first still, showing it's still not working. The JSON file is generating and storing the values but apparently to no avail. Here's the rewritten MCM script: ScriptName SimplerSlaveryMCMScript Extends SKI_ConfigBase ; OIDs int aOID int MinhealththresholdOID_S int ChanceofenslavementOID_S ; Toggle states bool aVal = true float Minhealththreshold = 25.0 float Chanceofenslavement = 25.0 event OnInit() parent.OnInit() JSONUtil.setFloatValue("SimplerSlavery", "SRSModOn", aVal as float) JSONUtil.setFloatValue("SimplerSlavery", "SRSMinHealth", Minhealththreshold) JSONUtil.setFloatValue("SimplerSlavery", "SRSChanceofEnslave", Chanceofenslavement) endEvent event OnPageReset(string page) {Called when a new page is selected, including the initial empty page} SetCursorFillMode(LEFT_TO_RIGHT) AddToggleOption("Simpler Slavery active", aVal) MinhealththresholdOID_S = AddSliderOption("Minimum health threshold", Minhealththreshold, "{0}%") ChanceofenslavementOID_S = AddSliderOption("Chance of enslavement", Chanceofenslavement, "{1}%") endEvent event OnOptionSelect(int option) {Called when a non-interactive option has been selected} if (option == aOID) aVal = !aVal SetToggleOptionValue(aOID, aVal) JSONUtil.setFloatValue("SimplerSlavery", "SRSModOn", aVal as float) endIf endEvent event OnOptionDefault(int option) if (option == aOID) aVal = true ; default value SetToggleOptionValue(aOID, aVal) JSONUtil.setFloatValue("SimplerSlavery", "SRSModOn", aVal as float) elseif (option == MinhealththresholdOID_S) SetSliderOptionValue(MinhealththresholdOID_S, Minhealththreshold, "{0}%") JSONUtil.setFloatValue("SimplerSlavery", "SRSMinHealth", Minhealththreshold) elseif (option == ChanceofenslavementOID_S) SetSliderOptionValue(ChanceofenslavementOID_S, Chanceofenslavement, "{0}%") JSONUtil.setFloatValue("SimplerSlavery", "SRSChanceofEnslave", Chanceofenslavement) endIf endEvent Event OnOptionHighlight(int option) if (option == aOID) SetInfoText("Select to activate or deactivate this mod") elseif (option == MinhealththresholdOID_S) SetInfoText("Minimum health threshold required to trigger slavery") elseif (option == ChanceofenslavementOID_S) SetInfoText("Chance of being enslaved. Set to just above your defeat threshold") endIf endEvent event OnOptionSliderOpen(int option) if (option == MinhealththresholdOID_S) SetSliderDialogStartValue(Minhealththreshold) SetSliderDialogDefaultValue(25) SetSliderDialogRange(1.0, 100.0) SetSliderDialogInterval(1.0) elseIf (option == ChanceofenslavementOID_S) SetSliderDialogStartValue(Chanceofenslavement) SetSliderDialogDefaultValue(25) SetSliderDialogRange(1.0, 100.0) SetSliderDialogInterval(1.0) endif endevent event OnOptionSliderAccept(int option, float value) if (option == MinhealththresholdOID_S) Minhealththreshold = value SetSliderOptionValue(MinhealththresholdOID_S, Minhealththreshold, "{0}%") JSONUtil.setFloatValue("SimplerSlavery", "SRSMinHealth", Minhealththreshold) elseif (option == ChanceofenslavementOID_S) Chanceofenslavement = value SetSliderOptionValue(ChanceofenslavementOID_S, Chanceofenslavement, "{0}%") JSONUtil.setFloatValue("SimplerSlavery", "SRSChanceofEnslave", Chanceofenslavement) endIf endEvent And the rewritten trigger script: ScriptName SimplerSlaveryTriggerScript Extends Quest SexLabFramework Property SexLab Auto SimplerSlaveryMCMScript Property Config Auto ObjectReference Property sslv_cagemark2 Auto Actor Property PlayerRef Auto Actor Player Event OnInit() RegisterForModEvent("AnimationStart", "CheckDefeated") Debug.Notification("Simpler Slavery Detected") EndEvent event CheckDefeated(string eventName, string argString, float argNum, form sender) if JSONUtil.GetFloatValue("SimplerSlavery", "SRSModOn") == 0 Debug.Notification("Mod active check failed") return endif Debug.Notification("Mod active check passed") If Player.getav("Health") > JSONUtil.GetFloatValue("SimplerSlavery", "SRSMinHealth") Debug.Notification("Health threshold check failed") return endif Debug.Notification("Health threshold check passed") sslThreadController controller = SexLab.HookController(argString) if !controller.HasPlayer Debug.Notification("Player involvement check failed") return endif Debug.Notification("Player involvement check passed") actor victim = SexLab.HookVictim(argString) if victim != player Debug.Notification("Player is victim check failed") return endif RegisterForModEvent("AnimationEnd", "EnslavePlayerEvent") Debug.Notification("Player is victim check passed") EndEvent event EnslavePlayerEvent(string eventName, string argString, float argNum, form sender) UnregisterForModEvent("AnimationEnd") Int random = Utility.RandomInt(0, 99) if random > JSONUtil.GetFloatValue("SimplerSlavery", "SRSChanceofEnslave") Debug.Notification("Random roll failed") return endif Debug.Notification("Random roll passed") Game.GetPlayer().MoveTo(sslv_cagemark2) EndEvent Edit: Seems the problem may be with the Player.GetAV section, as my Papyrus logs say this: ERROR: Cannot call GetAV() on a None object, aborting function call stack: [simplerSlaveryQuest (64001826)].SimplerSlaveryTriggerScript.CheckDefeated() - "SimplerSlaveryTriggerScript.psc" Line 20[08/20/2015 - 06:03:11PM] warning: Assigning None to a non-object variable named "::temp1" stack: [simplerSlaveryQuest(64001826)].SimplerSlaveryTriggerScript.CheckDefeated() - "SimplerSlaveryTriggerScript.psc" Line 20 Double edit: Nope, I changed it to Game.GetPlayer().GetAV("health"), which removed the error, but still no messages.
Guest Posted August 20, 2015 Posted August 20, 2015 My friend. Just do a simple search/replace of "Player." with "PlayerRef.". And get rid of the source of your problems that is "Actor Player". Just to explain: A variable has not a value just because of its name. A variable like "Actor Player" has nothing inside until you set a value in. Not just because it is called "Player" it will get the player inside. Normal variable have no "Auto-Fill". Properties are slightly different but just in a few cases. PlayerRef is a magical one that can be auto-filled. But you still have to auto-fill it.
randomtguy Posted August 20, 2015 Author Posted August 20, 2015 My friend. Just do a simple search/replace of "Player." with "PlayerRef.". And get rid of the source of your problems that is "Actor Player". Just to explain: A variable has not a value just because of its name. A variable like "Actor Player" has nothing inside until you set a value in. Not just because it is called "Player" it will get the player inside. Normal variable have no "Auto-Fill". Properties are slightly different but just in a few cases. PlayerRef is a magical one that can be auto-filled. But you still have to auto-fill it. That was very educational and it's not like it wasn't necessary, but it still doesn't do anything. I just don't understand, at the bare minimum it should be giving me the debug message about checking whether the mod's enabled in the MCM. I'm feeling very discouraged now, but thanks a lot for trying to help anyway.
Guest Posted August 20, 2015 Posted August 20, 2015 This evening I will check in detail all your code and logs. And I will write something to explain what is going on. Now it is real work time, for me.
randomtguy Posted August 20, 2015 Author Posted August 20, 2015 This evening I will check in detail all your code and logs. And I will write something to explain what is going on. Now it is real work time, for me. Thanks my friend, you're a star. Take all the time you need. Sigh, but I was really hoping (before starting this thread) that this script would work and you'd be proud of me for figuring out how to write one on my own.
Guest Posted August 20, 2015 Posted August 20, 2015 I am proud of you. 1) You try 2) You are not afraid to ask for help 3) You do great progresses 4) You already released a mod that is appreciated 5) You are not afraid to try new things 6) You are not afraid to learn If you were my son/daughter, I had already put a sticker on my car saying: "Proud of my best new Papyrus learner."
randomtguy Posted August 20, 2015 Author Posted August 20, 2015 I am proud of you. 1) You try 2) You are not afraid to ask for help 3) You do great progresses 4) You already released a mod that is appreciated 5) You are not afraid to try new things 6) You are not afraid to learn If you were my son/daughter, I had already put a sticker on my car saying: "Proud of my best new Papyrus learner." Aw shucks, I'm genuinely touched, thanks. Helped me be less discouraged.
Sailing Rebel Posted August 20, 2015 Posted August 20, 2015 The key is to track down the disconnect. I would recommend putting unconditional debug notifications at the top of each function and event to make sure they are being called. Are you even getting the "Simpler Slavery Detected" notifiction from the SimplerSlaveryTriggerScript.psc OnInit()? Is the owning quest set to Start Game Enabled? Looking at SimplerSlaveryTriggerScript.psc again I think I (or we) may have misunderstood what the intention here is. Right now the MCM is pushing values to JSON and then your trigger script is trying to pull them back again. I've not used the JSON functions myself but I'm sure this is not the way to do it. JSON is really for long term storage and communication between different saves. Rather than send the value to JSON we can just read it straight from the MCM script. In fact you're halfway there since you have the Config property declared in your trigger script (assuming this property is pointed to the SimplerSlaveryMCMScript in CK). So what we have now is: If Player.getav("Health") > JSONUtil.GetFloatValue("SimplerSlavery", "SRSMinHealth") [...] EndIf What we should be doing is: If Player.getav("Health") > Config.Minhealththreshold [...] EndIf In order for that to work Minhealththreshold must be made a property of SimplerSlaveryTriggerScript rather than just a variable so we edit the declaration in SimplerSlaveryMCMScript from: Float Minhealththreshold = 25.0 to: Float Property Minhealththreshold Auto Then pull up the script in CK and edit that new property value to your default value. Now Your trigger script should have direct access to the value rather than sending it through a different process. Not sure if that will help with the immediate problem but it can't hurt.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.