Mushano Posted June 8 Posted June 8 (edited) On 6/8/2026 at 7:59 AM, hextun said: Before going to "save is borked" instead of "hextun made a booboo", given that I *did* elect to move *away* from actual API calls because in *my* testbed the API calls were not working, I'd like to collect a little info if you don't mind. Hmm.. is this a purely custom modlist, a pre-made modlist (e.g. from wabbajack), or a customized pre-made modlist (e.g. from wabbajack, but with your own tweaks)? I'm curious to match it against my own testbed for SLP+ (Masterstroke) Do you have an older save you could load, verify things are working (since you did feel confident things were working at one point), and then try 980 again? Are you willing to do unpaid testing? Side note/PSA: In the LL text editor (i.e. where I am typing right now), if you enter a smiley (like colon-right parens, i.e. ":)" ), but do not hit enter or space after the parens, your arrow keys will stop allowing navigation in the text editor until you do so? Like, start typing, then enter the ":)" but without the quotes. Then, before you hit enter or space (thus letting the editor convert it to the icon), try using your arrow keys. You can't! This surprised me. Enjoy! Purely custom modlist before wabbajack existed! Basically a migrated Skyrim to Skyrim Special modlist using Wrye Bash and not any Mod Organizers. I could try older saves, but this behaviour seems kind of familiar to an old version of SL triggers where for some reasons things would play out of order. Like start of sex scripts wouldn't run, but it would fire orgasms or end of sex scripts. Or end of sex scripts would fire at the beginning of the scene. Not sure what fixed it. I could definitely try some save files and see what happens. I hope we narrow down the problem. PS: About the smiley problem. Nope! I do not have that problem . Actually I just got that bug too. Most of the time I can, but if I enter the smiley mid sentence, like I'm editing a sentence, I ran into that bug. For reference, using Firefox. Edit: Okay. Testing done. It seems like somewhere in-between 980 and 983, that's when the logic broke. I'm not 100% certain, but 982 worked most of the time, so it might just be 983 that is broken at the moment. This was tested using an older save that I had near the beginning of my game. Testing newer save seems to confirm that 983 is currently broken with SLP+ and aggressive detection. Using a newer save, it does seem like 982 works, but 983 doesn't. Edited June 9 by Mushano
hextun Posted June 26 Author Posted June 26 16 hours ago, Fraying9981 said: whats the command to get the dick size from TNG? tng_get_actor_size?
Fraying9981 Posted June 26 Posted June 26 14 minutes ago, hextun said: tng_get_actor_size? thanks, do you have an idea of the value range?
hextun Posted June 26 Author Posted June 26 2 hours ago, Fraying9981 said: thanks, do you have an idea of the value range? Not as such, though I recall the MCM has settings for e.g. small, medium, large that appeared to range typically from, say, 0.8 to 1.3 or so maybe? Factor in race multipliers and you could perhaps end up with 0.5 to 1.5? But that's all dependent on how your modlist is set up. Technically I suppose you could normalize it all to a flat 1.0 for equality. having said that I don't know for sure that that's what you'll be getting back.
Fraying9981 Posted June 27 Posted June 27 1 hour ago, hextun said: Not as such, though I recall the MCM has settings for e.g. small, medium, large that appeared to range typically from, say, 0.8 to 1.3 or so maybe? Factor in race multipliers and you could perhaps end up with 0.5 to 1.5? But that's all dependent on how your modlist is set up. Technically I suppose you could normalize it all to a flat 1.0 for equality. having said that I don't know for sure that that's what you'll be getting back. thanks, indeed. 1
Fraying9981 Posted June 30 Posted June 30 do you know what's the unit range for enjoyment? should you only use addenjoyment + a fix number? or does it make sense to use relative change?
hextun Posted June 30 Author Posted June 30 3 minutes ago, Fraying9981 said: do you know what's the unit range for enjoyment? should you only use addenjoyment + a fix number? or does it make sense to use relative change? I *think* it functions from 0-100 but IIRC the API allows values to exceed the range softly, meaning it won't fail but applies a cap. At least for SexLab. SexLab P+ redid a lot of the enjoyment stuff but I suspect it works similarly. I have a script I have tinkered with that plays with enjoyment during a scene and seems to work for both SL and SLP+ within an expected range of 0-100. So if you adjust enjoyment 50, it should add 50 to the current level. Note that normal execution by the respective frameworks seems to apply far more subtle amounts of enjoyment per unit time by default; an adjustment of 50 would be significant to say the least.
hextun Posted June 30 Author Posted June 30 55 minutes ago, Fraying9981 said: do you know what's the unit range for enjoyment? should you only use addenjoyment + a fix number? or does it make sense to use relative change? This is a slightly altered version of the SLTScript I mentioned, CumDelay.sltscript. It's a mini-game that can ostensibly work on its own or sit on top of something like SLSO. I have tested it on both SexLab and SexLab P+. Note that the values for enjoyment increase are large and notable, even for the "Work It" scenario (i.e. the player attempting to provide service to earn the right to orgasm). The general point of this mini-game is that there is an amount of effort that must be achieved, by stimulating the partner(s), before the player's ability to orgasm is unlocked. When the player breaks through, this level is increased; each scene where the player breaks through makes the next scene harder to break through. If the player does not break through, the level is reduced a bit. Several keys can be mapped for listening, configurable as variables near the top of the script. There are options to "give up", where further self pleasure is impossible, as well as self and other service, where an extreme amount of enjoyment is tacked on to either the player or the partner(s). It is meant to be run on Sex Start, Player targeted. It should give an idea of how enjoyment can be affected. You can play with the values to see how much it impacts progress. Note that, in my very anecdotal observation, SLP+ enjoyment seems to progress more quickly under normal conditions (i.e. without this script or attempting to use the built-in manipulation) than, for example, in base SexLab. So if you are using SLP+, you'll see enjoyment ratcheting up pretty noticeably, and then, if you use this script, it's going to go much more quickly. Spoiler set $CUM_DENIAL_FLOOR 100.0 set $CUM_DENIAL_DECREMENT -25.0 set $CUM_DENIAL_DECR_FLOOR $CUM_DENIAL_FLOOR - $CUM_DENIAL_DECREMENT set $CUM_DENIAL_CEILING 2000.0 ; these values are used directly with the SexLab/SexLabP+ API / It appears that for SLP the values may need to be larger to have effect, early results are inconclusive set $SERVICE_ENJOYMENT_SELF 100 ; when providing service to self, add this much enjoyment set $SERVICE_ENJOYMENT_OTHERS 100 ; when providing service to others, add this much enjoyment set $GIVEUP_ENJOYMENT_OTHERS 20 ; after giving up, add this much enjoyment to the others each 0.5 second set $BREAKTHROUGH_ENJOYMENT_SELF 100 ; upon breaking through, add this much enjoyment to self set $WORK_ENJOYMENT_RND_OTHER_MIN 0 ; for the work-it enjoyment calc, rnd(min, max) + bonus set $WORK_ENJOYMENT_RND_OTHER_MAX 7 ; for the work-it enjoyment calc, rnd(min, max) + bonus set $WORK_ENJOYMENT_OTHER_BONUS 17 ; for the work-it enjoyment calc, rnd(min, max) + bonus ; keystrokes - https://gist.github.com/arithex/3e953d1eb096afe58ce05ba6846493e4 ; NP1/79 ; NP2/80 ; NP3/81 ; NP4/75; NP5/76; NP6/77 ; NP7/71 ; NP8/72 ; NP9/73; NP0/82 ; NP-/74; NP+/78 ; NPENTER/156 ; ArrowUp/200 ; ArrowLeft/203 ; ArrowRight/205 ; ArrowDown/208 set $KEY_BREAK "G" set $DXC_BREAK 34 set $KEY_WORK "ArrowUp" set $DXC_WORK 200 set $KEY_SELF "ArrowRight" set $DXC_SELF 205 set $KEY_OTHER "ArrowLeft" set $DXC_OTHER 203 set $KEY_GIVEUP "NP5" set $DXC_GIVEUP 76 ; are you the Public Whore? Much harder to cum set $is_PW resultfrom pw_is_whore_anywhere msg_console $"CumDelay - Public Whore - {is_PW}" if $is_PW set $CUM_DENIAL_CEILING $CUM_DENIAL_CEILING * 1.5 endif if $global.cum_denial_max < $CUM_DENIAL_FLOOR msg_console $"CumDelay - Initializing cum_denial_max to {CUM_DENIAL_FLOOR}" set $global.cum_denial_max $CUM_DENIAL_FLOOR elseif $global.cum_denial_max > $CUM_DENIAL_CEILING set $rnd_decr resultfrom rnd_float 0 $global.cum_denial_max set $global.cum_denial_max $global.cum_denial_max - $rnd_decr msg_console $"CumDelay - cum_denial_max > {CUM_DENIAL_CEILING}, reducing by random amount ({rnd_decr}); new cum_denial_max - {global.cum_denial_max}" elseif $global.cum_denial_max > $CUM_DENIAL_DECR_FLOOR msg_console $"CumDelay - Decrementing cum_denial_max by {CUM_DENIAL_DECREMENT}" inc $global.cum_denial_max $CUM_DENIAL_DECREMENT endif set $info_msg $"CumDelay - Press '{KEY_BREAK}' to Disable, {KEY_WORK}-Work It, {KEY_SELF}-Service self, {KEY_OTHER}-Service others, {KEY_GIVEUP}-Give up : .. {global.cum_denial}/{global.cum_denial_max}" msg_console $info_msg uilib_shownotification $info_msg set $broken false if $global.cum_denial < $global.cum_denial_max sl_disableorgasm $system.player true msg_console "CumDelay - Disabling orgasms for now" else set $global.cum_denial 0.0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR set $broken true msg_console "CumDelay - Orgasms starting enabled" endif [startwaiting] set $keypress resultfrom sl_waitforkbd $DXC_BREAK $DXC_WORK $DXC_SELF $DXC_OTHER $DXC_GIVEUP if $keypress == $DXC_WORK set $rndi resultfrom rnd_int $WORK_ENJOYMENT_RND_OTHER_MIN $WORK_ENJOYMENT_RND_OTHER_MAX inc $rndi $WORK_ENJOYMENT_OTHER_BONUS sl_adjustenjoyment $system.partner1 $rndi sl_adjustenjoyment $system.partner2 $rndi sl_adjustenjoyment $system.partner3 $rndi sl_adjustenjoyment $system.partner4 $rndi if $broken == false set $decr_amount $system.random.100 if $is_PW set $decr_amount $decr_amount * 0.25 endif inc $global.cum_denial $decr_amount if $global.cum_denial > $global.cum_denial_max sl_disableorgasm $system.player false msg_console $"CumDelay - Breakthrough! {global.cum_denial}/{global.cum_denial_max}" set $global.cum_denial 0.0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR set $broken true sl_adjustenjoyment $system.player $BREAKTHROUGH_ENJOYMENT_SELF endif else sl_adjustenjoyment $system.player $rndi endif goto [startwaiting] elseif $keypress == $DXC_OTHER msg_console "CumDelay - Service to Others" sl_adjustenjoyment $system.partner1 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner2 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner3 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner4 $SERVICE_ENJOYMENT_OTHERS goto [startwaiting] elseif $keypress == $DXC_SELF msg_console "CumDelay - Service to Self" if $is_PW msg_console "CumDelay - Unable to service self while the public whore" else sl_adjustenjoyment $system.player $SERVICE_ENJOYMENT_SELF sl_orgasm $system.player endif goto [startwaiting] elseif $keypress == $DXC_GIVEUP sl_disableorgasm $system.player true msg_console "CumDelay - Giving Up and disabling orgasms" [do giveup_service] sl_isin $system.player if $$ sl_adjustenjoyment $system.partner1 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner2 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner3 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner4 $GIVEUP_ENJOYMENT_OTHERS util_wait 0.5 goto [do giveup_service] else msg_console "CumDelay - Exiting after Giving Up" if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif return endif elseif $keypress == $DXC_BREAK msg_console "CumDelay - Break forced" if $broken == true sl_disableorgasm $system.player false msg_console $"CumDelay - '{KEY_BREAK}' pressed again; Disabled: {global.cum_denial}/{global.cum_denial_max}" if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif return else set $global.cum_denial $global.cum_denial_max + 1.0 msg_console $"CumDelay - '{KEY_BREAK}' pressed; Overriding cum_denial {global.cum_denial}/{global.cum_denial_max}" goto [startwaiting] endif endif if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif msg_console $"CumDelay - result: {keypress} .. {global.cum_denial}/{global.cum_denial_max}"
hextun Posted June 30 Author Posted June 30 Probably also worth mentioning that spending some time to add Papyrus optimizations may help. Here is my PapyrusTweaks.ini file for example. Spoiler # |\__/,| (`\ ZZZZZZ # |_ _ |.--.) ) ZZZZ # ( T ) / zzz #(((^_(((/(((_/ [Fixes] ;Fixes ToggleScripts command not persisting when saving/stack dumping ;Scripts will now stay turned off when toggled off, and on when toggled on. bFixToggleScriptsCommand = true ;Fix unintentionally allocating script pages when getting largest available page, but out of memory. bFixScriptPageAllocation = true ;Fix crash when passing in NONE object to script function Actor.IsHostileToActor(). bFixIsHostileToActorCrash = true ;Fix scripts that don't load right away breaking completely if they reference an invalid object type (Ex: SuperSecretScript has a function that takes InvalidScript as a parameter). bFixDelayedScriptBreakage = true [Experimental] ;(VR-ONLY) Pauses all non-playroom scripts while in the VR playroom, so mod scripts only initialize once you actually enter a save/new game. ;This is only experimental as it intentionally alters script behavior bDisableScriptsInPlayroomVR = false ;Stops the game from resetting when loading a corrupted save ;This will NOT fix a broken save, just allows you to load the save no matter what information is lost. ONLY USE AS A LAST RESORT TO RECOVER A SAVE YOU HAVE BEEN WARNED!! bBypassCorruptSaveMessage = false ;Allows the Script Engine to use as much memory as needed, with no cap. This makes `iMaxAllocatedMemoryBytes` in Skyrim.ini useless ;Note: Skyrim already ignores memory limit when stressed, this setting just keeps it ignores. bIgnoreMemoryLimit = true ;(Formerly bRunScriptsOnMainThreadOnly) ;Speeds up native calls by desyncing them from framerate and instead syncing script calls to a spinlock, greatly improving script performance while still preventing concurrent execution of native calls bSpeedUpNativeCalls = true ;(Formerly sMainThreadMethodsToExclude, requires bSpeedUpNativeCalls=true) ;List of script method prefixes to exclude from being sped up (ex: "Equip" excludes "EquipItem" and "EquipItemByID", but does NOT exclude "UnequipItem". ;It is strongly recommended to leave at defaults unless you absolutely know what you're doing ;as a lot of modifying functions like `EquipItem` do not work properly if executed more than once in a single frame. ; Defaults exclude everything except for read-only functions (ex: GetFormFromFile, HasKeyword, IsLoaded, etc.) ;ORIGINALsScriptMethodPrefixesToExclude = Activate, Add, Advance, Allow, Attach, Apply, Block, Cast, Change, Clear, Close, Complete, Create, Damage, Delete, Disable, Disallow, Dismount, Dispel, DoCombatSpellApply, Draw, Drop, Enable, End, Equip, Evaluate, Fade, Fail, Fire, Force, GetAnimation, GetQuest, Hide, Hold, Ignore, Increment, Keep, Kill, Knock, Learn, Load, Lock, Mod, Move, Mute, Open, Place, Play, Pop, Precache, Process, Push, Queue, Quit, Regenerate, Register, Release, RemoteCast, Remove, Request, Reset, Restore, Resurrect, Revert, Save, Say, Send, Serve, Set, Shake, Sheath, Show, Start, Stop, Teach, TempClone, Tether, Toggle, Translate, Trap, Trigger, Try, Unequip, Unlock, UnMute, UnPause, Update, Unregister sScriptMethodPrefixesToExclude = Offset, _Set, _Adjust, _Get, _Seed, _Reset, _Clear, _Copy, CalcEnjoyment, Activate, Add, Advance, Allow, Attach, Apply, Block, Cast, Change, Clear, Close, Complete, Create, Damage, Delete, Disable, Disallow, Dismount, Dispel, DoCombatSpellApply, Draw, Drop, Enable, End, Equip, Evaluate, Fade, Fail, Fire, Force, GetAnimation, GetQuest, Hide, Hold, Ignore, Increment, Keep, Kill, Knock, Learn, Load, Lock, Mod, Move, Mute, Open, Place, Play, Pop, Precache, Process, Push, Queue, Quit, Regenerate, Register, Release, RemoteCast, Remove, Request, Reset, Restore, Resurrect, Revert, Save, Say, Send, Serve, Set, Shake, Sheath, Show, Start, Stop, Teach, TempClone, Tether, Toggle, Translate, Trap, Trigger, Try, Unequip, Unlock, UnMute, UnPause, Update, Unregister ;(Formerly sMainThreadClassesToExclude, requires bSpeedUpNativeCalls=true) ;List of script classes to exclude from being sped up by bSpeedUpNativeCalls. ;It is strongly recommended to leave at defaults unless you absolutely know what you're doing ;ORIGINALsScriptClassExclusions = UI, ConsoleUtil, PO3_SKSEFunctions, MfgConsole, MFGConsoleFunc, Input, Debug, Utility, PapyrusTweaks, Quest, MfgConsoleFuncExt sScriptClassExclusions = UI, ConsoleUtil, PO3_SKSEFunctions, MfgConsole, MFGConsoleFunc, Input, Debug, Utility, PapyrusTweaks, Quest, MfgConsoleFuncExt, SexLabUtil, slaInternalModules, AnimSpeedHelper [VM Tweaks (Tweaks that directly alter the script engine)] ;Maximum papyrus operations per frame. Higher number means better script performance on average ;Has a very minor impact on framerate, and varies from script to script. (Default: 500, Vanilla value: 100). Recommended Range: 100-2000. Set to 0 to disable iMaxOpsPerFrame = 4000 ;Modify how long Papyrus can be "overstressed" before dumping stacks, in milliseconds (Default value: 15000, Vanilla value: 5000). ;Set to 0 to disable the stack dump check, or -1 to disable this setting. ;See https://www.nexusmods.com/skyrimspecialedition/articles/4625 for information on what a stack dump is iStackDumpTimeoutMS = 15000 ;Enables loading of doc strings from scripts into the engine. Requires `bLoadDebugInformation` to be true in this INI bEnableDocStrings = true ;Enables Skyrim to load debug information of scripts. This completely overrides bLoadDebugInformation in Skyrim.ini and is provided here for easier configuration bEnableDebugInformation = true [Logging Tweaks (Tweaks that affect script logging)] ;Disables `File " % s " does not exist or is not currently loaded.` logs from being printed when calling Game.GetFormFromFile(). ;This only disables the logging of the error, the error itself will still occur bDisableGetFormFromFileErrorLogs = false ;Improves Base Type Mismatch error to show inheritance hierarchy of scripts; Also clarifies if the script was a genuine mismatch, or if the script doesn't exist bImproveBaseTypeMismatchLogs = true ;Improves several error logs relating to incompatible arguments to better clarify what is incompatible bImproveValidateArgsLogs = true ;Disable "Property %s on script %s attached to %s cannot be initialized because the script no longer contains that property" log messages. ;This only disables the logging of the warning, the warning itself will still occur bDisableNoPropertyOnScriptErrorLogs = false ;Disable "Cannot open store for class "%s", missing file?" errors being logged. ;This only disables the logging of the error, the error itself will still occur bDisableMissingScriptError = false ;Adds a summary of events when dumping stacks to log bSummarizeStackDumps = true
Fraying9981 Posted June 30 Posted June 30 1 hour ago, hextun said: This is a slightly altered version of the SLTScript I mentioned, CumDelay.sltscript. It's a mini-game that can ostensibly work on its own or sit on top of something like SLSO. I have tested it on both SexLab and SexLab P+. Note that the values for enjoyment increase are large and notable, even for the "Work It" scenario (i.e. the player attempting to provide service to earn the right to orgasm). The general point of this mini-game is that there is an amount of effort that must be achieved, by stimulating the partner(s), before the player's ability to orgasm is unlocked. When the player breaks through, this level is increased; each scene where the player breaks through makes the next scene harder to break through. If the player does not break through, the level is reduced a bit. Several keys can be mapped for listening, configurable as variables near the top of the script. There are options to "give up", where further self pleasure is impossible, as well as self and other service, where an extreme amount of enjoyment is tacked on to either the player or the partner(s). It is meant to be run on Sex Start, Player targeted. It should give an idea of how enjoyment can be affected. You can play with the values to see how much it impacts progress. Note that, in my very anecdotal observation, SLP+ enjoyment seems to progress more quickly under normal conditions (i.e. without this script or attempting to use the built-in manipulation) than, for example, in base SexLab. So if you are using SLP+, you'll see enjoyment ratcheting up pretty noticeably, and then, if you use this script, it's going to go much more quickly. Hide contents set $CUM_DENIAL_FLOOR 100.0 set $CUM_DENIAL_DECREMENT -25.0 set $CUM_DENIAL_DECR_FLOOR $CUM_DENIAL_FLOOR - $CUM_DENIAL_DECREMENT set $CUM_DENIAL_CEILING 2000.0 ; these values are used directly with the SexLab/SexLabP+ API / It appears that for SLP the values may need to be larger to have effect, early results are inconclusive set $SERVICE_ENJOYMENT_SELF 100 ; when providing service to self, add this much enjoyment set $SERVICE_ENJOYMENT_OTHERS 100 ; when providing service to others, add this much enjoyment set $GIVEUP_ENJOYMENT_OTHERS 20 ; after giving up, add this much enjoyment to the others each 0.5 second set $BREAKTHROUGH_ENJOYMENT_SELF 100 ; upon breaking through, add this much enjoyment to self set $WORK_ENJOYMENT_RND_OTHER_MIN 0 ; for the work-it enjoyment calc, rnd(min, max) + bonus set $WORK_ENJOYMENT_RND_OTHER_MAX 7 ; for the work-it enjoyment calc, rnd(min, max) + bonus set $WORK_ENJOYMENT_OTHER_BONUS 17 ; for the work-it enjoyment calc, rnd(min, max) + bonus ; keystrokes - https://gist.github.com/arithex/3e953d1eb096afe58ce05ba6846493e4 ; NP1/79 ; NP2/80 ; NP3/81 ; NP4/75; NP5/76; NP6/77 ; NP7/71 ; NP8/72 ; NP9/73; NP0/82 ; NP-/74; NP+/78 ; NPENTER/156 ; ArrowUp/200 ; ArrowLeft/203 ; ArrowRight/205 ; ArrowDown/208 set $KEY_BREAK "G" set $DXC_BREAK 34 set $KEY_WORK "ArrowUp" set $DXC_WORK 200 set $KEY_SELF "ArrowRight" set $DXC_SELF 205 set $KEY_OTHER "ArrowLeft" set $DXC_OTHER 203 set $KEY_GIVEUP "NP5" set $DXC_GIVEUP 76 ; are you the Public Whore? Much harder to cum set $is_PW resultfrom pw_is_whore_anywhere msg_console $"CumDelay - Public Whore - {is_PW}" if $is_PW set $CUM_DENIAL_CEILING $CUM_DENIAL_CEILING * 1.5 endif if $global.cum_denial_max < $CUM_DENIAL_FLOOR msg_console $"CumDelay - Initializing cum_denial_max to {CUM_DENIAL_FLOOR}" set $global.cum_denial_max $CUM_DENIAL_FLOOR elseif $global.cum_denial_max > $CUM_DENIAL_CEILING set $rnd_decr resultfrom rnd_float 0 $global.cum_denial_max set $global.cum_denial_max $global.cum_denial_max - $rnd_decr msg_console $"CumDelay - cum_denial_max > {CUM_DENIAL_CEILING}, reducing by random amount ({rnd_decr}); new cum_denial_max - {global.cum_denial_max}" elseif $global.cum_denial_max > $CUM_DENIAL_DECR_FLOOR msg_console $"CumDelay - Decrementing cum_denial_max by {CUM_DENIAL_DECREMENT}" inc $global.cum_denial_max $CUM_DENIAL_DECREMENT endif set $info_msg $"CumDelay - Press '{KEY_BREAK}' to Disable, {KEY_WORK}-Work It, {KEY_SELF}-Service self, {KEY_OTHER}-Service others, {KEY_GIVEUP}-Give up : .. {global.cum_denial}/{global.cum_denial_max}" msg_console $info_msg uilib_shownotification $info_msg set $broken false if $global.cum_denial < $global.cum_denial_max sl_disableorgasm $system.player true msg_console "CumDelay - Disabling orgasms for now" else set $global.cum_denial 0.0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR set $broken true msg_console "CumDelay - Orgasms starting enabled" endif [startwaiting] set $keypress resultfrom sl_waitforkbd $DXC_BREAK $DXC_WORK $DXC_SELF $DXC_OTHER $DXC_GIVEUP if $keypress == $DXC_WORK set $rndi resultfrom rnd_int $WORK_ENJOYMENT_RND_OTHER_MIN $WORK_ENJOYMENT_RND_OTHER_MAX inc $rndi $WORK_ENJOYMENT_OTHER_BONUS sl_adjustenjoyment $system.partner1 $rndi sl_adjustenjoyment $system.partner2 $rndi sl_adjustenjoyment $system.partner3 $rndi sl_adjustenjoyment $system.partner4 $rndi if $broken == false set $decr_amount $system.random.100 if $is_PW set $decr_amount $decr_amount * 0.25 endif inc $global.cum_denial $decr_amount if $global.cum_denial > $global.cum_denial_max sl_disableorgasm $system.player false msg_console $"CumDelay - Breakthrough! {global.cum_denial}/{global.cum_denial_max}" set $global.cum_denial 0.0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR set $broken true sl_adjustenjoyment $system.player $BREAKTHROUGH_ENJOYMENT_SELF endif else sl_adjustenjoyment $system.player $rndi endif goto [startwaiting] elseif $keypress == $DXC_OTHER msg_console "CumDelay - Service to Others" sl_adjustenjoyment $system.partner1 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner2 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner3 $SERVICE_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner4 $SERVICE_ENJOYMENT_OTHERS goto [startwaiting] elseif $keypress == $DXC_SELF msg_console "CumDelay - Service to Self" if $is_PW msg_console "CumDelay - Unable to service self while the public whore" else sl_adjustenjoyment $system.player $SERVICE_ENJOYMENT_SELF sl_orgasm $system.player endif goto [startwaiting] elseif $keypress == $DXC_GIVEUP sl_disableorgasm $system.player true msg_console "CumDelay - Giving Up and disabling orgasms" [do giveup_service] sl_isin $system.player if $$ sl_adjustenjoyment $system.partner1 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner2 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner3 $GIVEUP_ENJOYMENT_OTHERS sl_adjustenjoyment $system.partner4 $GIVEUP_ENJOYMENT_OTHERS util_wait 0.5 goto [do giveup_service] else msg_console "CumDelay - Exiting after Giving Up" if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif return endif elseif $keypress == $DXC_BREAK msg_console "CumDelay - Break forced" if $broken == true sl_disableorgasm $system.player false msg_console $"CumDelay - '{KEY_BREAK}' pressed again; Disabled: {global.cum_denial}/{global.cum_denial_max}" if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif return else set $global.cum_denial $global.cum_denial_max + 1.0 msg_console $"CumDelay - '{KEY_BREAK}' pressed; Overriding cum_denial {global.cum_denial}/{global.cum_denial_max}" goto [startwaiting] endif endif if $is_PW set $global.cum_denial 0 inc $global.cum_denial_max $CUM_DENIAL_FLOOR endif msg_console $"CumDelay - result: {keypress} .. {global.cum_denial}/{global.cum_denial_max}" thank you! this is helpful to understand an example of how to use. so the main function is "sl_adjustenjoyment " -> does it ADD a value on top of the 0-100 scale you mentioned OR: does it set the level 0-100 of the enjoyment? If you reach or exceed 100, do you get an orgasm automatically?
hextun Posted June 30 Author Posted June 30 23 minutes ago, Fraying9981 said: thank you! this is helpful to understand an example of how to use. so the main function is "sl_adjustenjoyment " -> does it ADD a value on top of the 0-100 scale you mentioned OR: does it set the level 0-100 of the enjoyment? If you reach or exceed 100, do you get an orgasm automatically? It appears to add to the actors existing value. And if orgasms are not disabled for them I believe that yes once you reach that value it will trigger one. I say I believe because other mods or values might also impact things. 1
ShadowClaw20017 Posted July 5 Posted July 5 Quick question. Say I wanted to design a script for triggering a scene upon hunger levels dropping with certain tags, but only out of combat. How do access the hunger variable in survival mode?
hextun Posted July 6 Author Posted July 6 6 hours ago, ShadowClaw20017 said: Quick question. Say I wanted to design a script for triggering a scene upon hunger levels dropping with certain tags, but only out of combat. How do access the hunger variable in survival mode? If I am understanding you correctly, you are wanting to obtain the CC (i.e. base game, not modded like SunHelm Survival) current hunger value. If I am not mistaken, you can obtain the current value, which is normally scaled from 0 (fed) to 1000 (ravenous), by querying the Global Variable "Survival_HungerNeedValue", which you can do in SLTScript using global_getvalue "Survival_HungerNeedValue", i.e.: set $current_hunger resultfrom global_getvalue "Survival_HungerNeedValue" Similarly, I *believe* but *am not certain* you could set it via: global_setvalue "Survival_HungerNeedValue" 0.0 ; which would make you well fed again I don't currently have a list set up to use vanilla survival so can't test this. I got the global variable names by pulling up ccqdrsse001-survivalmode.esl in xEdit and taking an educated guess. There are some other interesting hunger related values there too.
hextun Posted July 7 Author Posted July 7 On 6/8/2026 at 6:11 PM, Mushano said: Purely custom modlist before wabbajack existed! Basically a migrated Skyrim to Skyrim Special modlist using Wrye Bash and not any Mod Organizers. I could try older saves, but this behaviour seems kind of familiar to an old version of SL triggers where for some reasons things would play out of order. Like start of sex scripts wouldn't run, but it would fire orgasms or end of sex scripts. Or end of sex scripts would fire at the beginning of the scene. Not sure what fixed it. I could definitely try some save files and see what happens. I hope we narrow down the problem. PS: About the smiley problem. Nope! I do not have that problem . Actually I just got that bug too. Most of the time I can, but if I enter the smiley mid sentence, like I'm editing a sentence, I ran into that bug. For reference, using Firefox. Edit: Okay. Testing done. It seems like somewhere in-between 980 and 983, that's when the logic broke. I'm not 100% certain, but 982 worked most of the time, so it might just be 983 that is broken at the moment. This was tested using an older save that I had near the beginning of my game. Testing newer save seems to confirm that 983 is currently broken with SLP+ and aggressive detection. Using a newer save, it does seem like 982 works, but 983 doesn't. Sorry for taking so long to reply; I guess I must have missed your edit. Well, v983 is when I introduced a change to how I resolve aggressiveness in SLP+ explicitly. Aaaaand I am guessing I borked it up. I'll look at reverting that change, but the original issue that caused me to make said change will also need revisiting. In the meantime, try reverting to v982, though note that that will also remove access to the introduced functions: sl_is_actor_aggressor sl_is_actor_submissive sl_is_scene_aggressive
Mushano Posted July 9 Posted July 9 On 7/7/2026 at 9:33 AM, hextun said: Sorry for taking so long to reply; I guess I must have missed your edit. Well, v983 is when I introduced a change to how I resolve aggressiveness in SLP+ explicitly. Aaaaand I am guessing I borked it up. I'll look at reverting that change, but the original issue that caused me to make said change will also need revisiting. In the meantime, try reverting to v982, though note that that will also remove access to the introduced functions: sl_is_actor_aggressor sl_is_actor_submissive sl_is_scene_aggressive Yeah, for now I'm on a mix of 982/983...? I forgot what I did, but I think I unstubbed sl_is_aggressive and restored what you put in with 982. And I'm using the 982 version of sl_triggersExtensionSexLab. That seems to have restored the aggressive or consensual check for me.
Omnishade Posted July 13 Posted July 13 I tried to make my own buff and tested it via the corescripts MCM with equipmentchange as event, making it easy to trigger it. I also had gold(10) added and that part worked, but my custom buff wasn't cast at all. Did I do something wrong? Screenshots: Spoiler Spoiler
hextun Posted July 13 Author Posted July 13 9 hours ago, Omnishade said: I tried to make my own buff and tested it via the corescripts MCM with equipmentchange as event, making it easy to trigger it. I also had gold(10) added and that part worked, but my custom buff wasn't cast at all. Did I do something wrong? Screenshots: Hide contents Hide contents For the hex notation for the FormID try prefixing with '0x': 0x13B569 1
Omnishade Posted July 13 Posted July 13 18 minutes ago, hextun said: For the hex notation for the FormID try prefixing with '0x': 0x13B569 That actually worked. Is it because it's not from Skyrim.esm? Your examples don't use that prefix.
hextun Posted July 13 Author Posted July 13 2 hours ago, Omnishade said: That actually worked. Is it because it's not from Skyrim.esm? Your examples don't use that prefix. Well, if I have any remaining examples that don't do it that way, please point them out. I do want to be consistent. That said, note that not having the leading 0x is perfectly fine *provided* that you are intending to treat that FormID like a decimal (base 10) value instead of a hexadecimal (base 16) value. https://github.com/sltriggersredux/sltriggersredux/wiki/Scripts#formid-forms-and-you So, basically the formID is being interpreted as a number. If it has a leading 0x, it knows to treat it like a hexadecimal (base 16) number. If it does not have a leading 0x, it will treat it like a decimal (base 10) number. For example, from Skyrim.esm, septims are formID 0xF or 15. Either would work. i.e. "Skyrim.esm:0xF" or "Skyrim.esm:15". Or better example, take the GLOB (Global Variable) for "GameDaysPassed". It has hex FormID 0x39. So you could do "Skyrim.esm:0x39" or "Skyrim.esm:57" (because hex 39 is dec 57). But if you tried "Skyrim.esm:39" that would fail because dec 39 is hex 27 and there is no "Skyrim.esm:0x27" FormID.
hextun Posted July 13 Author Posted July 13 v0.984 UPDATE: SexLab P+ Aggressive/Aggressor detection issues I've been aware of this as an issue for a bit. When I first introduced the functionality in v0.981, when I only added sl_is_aggressive (now sl_is_scene_aggressive), I really only tested on SexLab and not on SexLab P+, trusting what I saw in the API. I then had to post a hotfix in v0.982 a few hours later. Then in v0.983 when I decided to split out and actually make sl_is_scene_aggressive along with sl_is_actor_aggressor and sl_is_actor_submissive, I went through with SLP+ testing. Lo and behold I found that the aggressive/aggressor tests were never returning true in situations where I expected them to (tested on Masterstroke 2.2.4.1 when using the SLP+ API as intended. Sort of (more on that in a bit). So I opted to switch the SLP+ implementation to use tag detection and that seemed to work. Though I hated it because it was ignoring what appeared to be obvious API functionality. Sort of (more is coming soon). Today I cracked open the code (sorry about the delay but my get up and go got up and went at some point) and started nosing around. First, I want to point out that I had an awful bug in the detection of aggressors/victims for other which I will definitely have fixed one way or another in v0.984. That said... what did I mean by "sort of" up there? BEGIN TECHNICAL PAPYRUS STUFF Spoiler The SLP+ has deprecated a lot of things and made a lot of other things internal where you aren't supposed to poke. Checking the Submissive state of an actor is not one of these things. Given an Actor or a SexLab thread ID you can retrieve a SexLabThread which exposes "bool Function GetSubmissive(Actor)", enabling you to properly retrieve this status via known non-deprecated, non-internal API calls. Suspiciously this also works. The Aggressive state of a thread, however, is visible only one way, which is internal only and thus not intended to be used in the way I had originally intended. That is, sslThreadModel exposes "bool Property IsAggressive hidden" where sslThreadModel extends SexLabThread. SexLabThread, which is actually exposed and intended for use, does *NOT* expose this property. So the only way to get to it is to fetch a SexLabThread (fine and good) and then cast to sslThreadModel (which may technically work but is not intended to be done and likely not supported). Suspiciously fetching this property's value always returns false. The Aggressor state of an Actor, similarly, is visible only two ways, one of which is deprecated (bool Function SexLabFramework.IsAggressor(int tid, Actor ActorRef)) and one of which is internal only and thus not intended for use (bool Function sslThreadModel.IsAggressor(Actor ActorRef)). Suspiciously both of these always return false in my testing. To work around this in v0.983, I did the following: Thread Aggressive state: check for the scene having the "Aggressive" tag Actor Aggressor state: if scene is aggressive, per above, and actor is *not* victim, actor is aggressor, otherwise false This combination worked in my testing on Masterstroke 2.2.4.1 which is my go to for SLP+ testing. END TECHNICAL PAPYRUS STUFF I have posted a question on the Discord for SLP+ development about what is the correct way to query these values and hope to get a response. If I don't, I'll keep using the tag check but will still push the fix for the state check in the trigger since I think that's gumming things up for some folks playing on SLP+. 1
Fraying9981 Posted July 14 Posted July 14 2 hours ago, hextun said: (sorry about the delay but my get up and go got up and went at some point) and started nosing around. I hope one day we get more content on this piece of lore :D I hope you get it solved soon! the latest updates have added nice features. with Skyrimnet compatibility, your mod has a great future 1
hextun Posted July 15 Author Posted July 15 On 7/13/2026 at 5:27 PM, hextun said: v0.984 UPDATE: SexLab P+ Aggressive/Aggressor detection issues I've been aware of this as an issue for a bit. When I first introduced the functionality in v0.981, when I only added sl_is_aggressive (now sl_is_scene_aggressive), I really only tested on SexLab and not on SexLab P+, trusting what I saw in the API. I then had to post a hotfix in v0.982 a few hours later. Then in v0.983 when I decided to split out and actually make sl_is_scene_aggressive along with sl_is_actor_aggressor and sl_is_actor_submissive, I went through with SLP+ testing. Lo and behold I found that the aggressive/aggressor tests were never returning true in situations where I expected them to (tested on Masterstroke 2.2.4.1 when using the SLP+ API as intended. Sort of (more on that in a bit). So I opted to switch the SLP+ implementation to use tag detection and that seemed to work. Though I hated it because it was ignoring what appeared to be obvious API functionality. Sort of (more is coming soon). Today I cracked open the code (sorry about the delay but my get up and go got up and went at some point) and started nosing around. First, I want to point out that I had an awful bug in the detection of aggressors/victims for other which I will definitely have fixed one way or another in v0.984. That said... what did I mean by "sort of" up there? BEGIN TECHNICAL PAPYRUS STUFF Reveal hidden contents The SLP+ has deprecated a lot of things and made a lot of other things internal where you aren't supposed to poke. Checking the Submissive state of an actor is not one of these things. Given an Actor or a SexLab thread ID you can retrieve a SexLabThread which exposes "bool Function GetSubmissive(Actor)", enabling you to properly retrieve this status via known non-deprecated, non-internal API calls. Suspiciously this also works. The Aggressive state of a thread, however, is visible only one way, which is internal only and thus not intended to be used in the way I had originally intended. That is, sslThreadModel exposes "bool Property IsAggressive hidden" where sslThreadModel extends SexLabThread. SexLabThread, which is actually exposed and intended for use, does *NOT* expose this property. So the only way to get to it is to fetch a SexLabThread (fine and good) and then cast to sslThreadModel (which may technically work but is not intended to be done and likely not supported). Suspiciously fetching this property's value always returns false. The Aggressor state of an Actor, similarly, is visible only two ways, one of which is deprecated (bool Function SexLabFramework.IsAggressor(int tid, Actor ActorRef)) and one of which is internal only and thus not intended for use (bool Function sslThreadModel.IsAggressor(Actor ActorRef)). Suspiciously both of these always return false in my testing. To work around this in v0.983, I did the following: Thread Aggressive state: check for the scene having the "Aggressive" tag Actor Aggressor state: if scene is aggressive, per above, and actor is *not* victim, actor is aggressor, otherwise false This combination worked in my testing on Masterstroke 2.2.4.1 which is my go to for SLP+ testing. END TECHNICAL PAPYRUS STUFF I have posted a question on the Discord for SLP+ development about what is the correct way to query these values and hope to get a response. If I don't, I'll keep using the tag check but will still push the fix for the state check in the trigger since I think that's gumming things up for some folks playing on SLP+. Okay, some followup: - turns out the tag related logic *is* the appropriate method for aggression checking in SLPP - I was still doing some things wrong and will fix them up - sl_is_aggressive (which is the deprecated form of what is currently sl_is_scene_aggressive) is just going to be dropped next release - sl_is_scene_aggressive is going to be renamed sl_is_thread_aggressive because threads are not scenes and honestly I should have known better -- this change will occur for both SL and SLPP - sl_is_scene_aggressive is therefore *not* going to be deprecated or in any way kept around because it would be logically incorrect - not to say it can't be readded but I kinda want to forcibly break it before changing the functionality because otherwise you might end up getting unexpected results -- i.e. in a hypothetical 0.985 or later, if sl_is_scene_aggressive is readded and you use it, I want it to be because you really want to know about the aggressive state of the current scene as opposed to the thread Other bits and bobs about SLPP: - when I first wrote the SLPP support, SLPP was at 2.15.1; it is now at 2.17.1, is in active development, and a few things have changed - among them, enjoyment is now exposed at the SexLabThread level, including specifically the AdjustEnjoyment functionality - SLTR is still using the sslThreadController to fetch an ActorAlias and call AdjustEnjoyment directly there - I would *like* to switch to use the 2.17.1 API feature but that would lose support for 2.15.1 SLPP enjoyers - This *will* happen at some point *waves vaguely into the future* so be prepared; also I hate the two distinct usages of asterisks in this line item - scene advancement (i.e. sl_advance) still uses sslThreadController but I haven't found a better/proper way yet - sl_animname also still uses sslThreadController; I'll be looking into this as it may have a direct analog that I haven't checked yet
hextun Posted July 18 Author Posted July 18 v0.984 has been pushed out the door and is standing there, waiting for you to pick it up and gently nestle it into your modlist. Isn't that sweet? So what's been cooking? Well... *cough* *looks at the previous post* .. a few things. But to recap: - SLPP aggressive thread/aggressor/submissive detection should now be compliant with intended use by the SLPP API -- Submissive detection remains the same, using the GetSubmissive call -- Aggressive thread detection now checks for: does the thread have "Aggressive" context OR does have the "Forced" tag OR does it have the "Aggressive" tag? -- Aggressor detection is a combination of: is the thread aggressive (see above) AND is the actor a Submissive (if not, they are an aggressor) -- This is based on the SLPP documentation: https://slp-community.github.io/SexLab-Wiki/slp/tagging-reference/ as well as a conversation on their Discord - Removed the functions: sl_is_aggressive and sl_is_scene_aggressive -- sl_is_aggressive was present so briefly as to not warrant the deprecation any longer -- sl_is_scene_aggressive was poorly named; SLPP thread level is in fact where the functionality was targeting and the name should have reflected this - Added the function: sl_is_thread_aggressive -- again, we are operating at the thread level at this point - These changes are also reflected in the SexLab functions, not just SLPP, as the object model is the same or similar enough - sl_animname for SLPP now properly uses SexLabThread instead of relying on the old sslThreadController logic - SLPP Actor positions in a thread are also now using SexLabThread functionality for API adherence - Note: The only remaining SLPP deprecated API usage currently is the SLPP specific version of sl_adjustenjoyment function -- Reason: When SLTR first implemented SLPP API usage, it was targeting the 2.15.1 API; as of the 2.17.1 API (latest at this time), there is a current method of adjusting enjoyment; In order to prevent problems for folks still using 2.15.1, I am currently avoiding the API update; THIS WILL CAUSE A PROBLEM IF, IN FUTURE, SLPP RELEASES AN UPDATE THAT COMPLETELY BREAKS THE CURRENT DEPRECATED CALLCHAIN - and, minor note, I updated the language files -- this not only added the sl_is_thread_aggressive/sl_is_actor_aggressor/sl_is_actor_submissive calls, it also added the pw_is_whore_anywhere call -- were you aware of the Public Whore tie-in? Get it while it's hot! PS - So hextun, what's on the agenda now? Well, I've been looking over the internals again. *shiver* I don't like the current approach that I settled on to call the function libraries. Baaaasically, when you call things like sl_is_thread_aggressive or util_wait, what *really* happens is: - the ActiveMagicEffect runs in a loop, processing each command of a script - the .dll is invoked to call the implementing function - the ActiveMagicEffect sits in a loop waiting for a flag to be set - the function called by the .dll does it's thing then sets the flag and finishes - the ActiveMagicEffect continues where it left off This isn't great and I'm pretty sure I settled for this instead of doing it better. What might better look like? - the ActiveMagicEffect runs in a loop, processing each command of a script - the .dll is invoked to call the implementing function - the ActiveMagicEffect just stops processing but remains in effect (not taking up resources for the most part) - the function called by the .dll does it's thing then tells the ActiveMagicEffect to continue processing The big change is not having a wait loop. I'm not entirely sure how much this would really impact things, but I have disliked this implementation since day 1. Which is a long time to dislike something you wrote and shipped on purpose. As you can imagine though, it's a bit like tearing out chunks of your car's ICE and replacing them with electric engine parts. In the end, for the most part, you might see something of an improvement, but it's touching a LOT of internals. Wish me luck.
Fraying9981 Posted July 18 Posted July 18 (edited) 34 minutes ago, hextun said: v0.984 has been pushed out the door and is standing there, waiting for you to pick it up and gently nestle it into your modlist. Isn't that sweet? So what's been cooking? Well... *cough* *looks at the previous post* .. a few things. But to recap: - SLPP aggressive thread/aggressor/submissive detection should now be compliant with intended use by the SLPP API -- Submissive detection remains the same, using the GetSubmissive call -- Aggressive thread detection now checks for: does the thread have "Aggressive" context OR does have the "Forced" tag OR does it have the "Aggressive" tag? -- Aggressor detection is a combination of: is the thread aggressive (see above) AND is the actor a Submissive (if not, they are an aggressor) -- This is based on the SLPP documentation: https://slp-community.github.io/SexLab-Wiki/slp/tagging-reference/ as well as a conversation on their Discord - Removed the functions: sl_is_aggressive and sl_is_scene_aggressive -- sl_is_aggressive was present so briefly as to not warrant the deprecation any longer -- sl_is_scene_aggressive was poorly named; SLPP thread level is in fact where the functionality was targeting and the name should have reflected this - Added the function: sl_is_thread_aggressive -- again, we are operating at the thread level at this point - These changes are also reflected in the SexLab functions, not just SLPP, as the object model is the same or similar enough - sl_animname for SLPP now properly uses SexLabThread instead of relying on the old sslThreadController logic - SLPP Actor positions in a thread are also now using SexLabThread functionality for API adherence - Note: The only remaining SLPP deprecated API usage currently is the SLPP specific version of sl_adjustenjoyment function -- Reason: When SLTR first implemented SLPP API usage, it was targeting the 2.15.1 API; as of the 2.17.1 API (latest at this time), there is a current method of adjusting enjoyment; In order to prevent problems for folks still using 2.15.1, I am currently avoiding the API update; THIS WILL CAUSE A PROBLEM IF, IN FUTURE, SLPP RELEASES AN UPDATE THAT COMPLETELY BREAKS THE CURRENT DEPRECATED CALLCHAIN - and, minor note, I updated the language files -- this not only added the sl_is_thread_aggressive/sl_is_actor_aggressor/sl_is_actor_submissive calls, it also added the pw_is_whore_anywhere call -- were you aware of the Public Whore tie-in? Get it while it's hot! PS - So hextun, what's on the agenda now? Well, I've been looking over the internals again. *shiver* I don't like the current approach that I settled on to call the function libraries. Baaaasically, when you call things like sl_is_thread_aggressive or util_wait, what *really* happens is: - the ActiveMagicEffect runs in a loop, processing each command of a script - the .dll is invoked to call the implementing function - the ActiveMagicEffect sits in a loop waiting for a flag to be set - the function called by the .dll does it's thing then sets the flag and finishes - the ActiveMagicEffect continues where it left off This isn't great and I'm pretty sure I settled for this instead of doing it better. What might better look like? - the ActiveMagicEffect runs in a loop, processing each command of a script - the .dll is invoked to call the implementing function - the ActiveMagicEffect just stops processing but remains in effect (not taking up resources for the most part) - the function called by the .dll does it's thing then tells the ActiveMagicEffect to continue processing The big change is not having a wait loop. I'm not entirely sure how much this would really impact things, but I have disliked this implementation since day 1. Which is a long time to dislike something you wrote and shipped on purpose. As you can imagine though, it's a bit like tearing out chunks of your car's ICE and replacing them with electric engine parts. In the end, for the most part, you might see something of an improvement, but it's touching a LOT of internals. Wish me luck. nice! amazing! if I may suggest on the roadmap: what's missing in your mod in terms of key infrastructure at this point, imo, is an actor tracking system. A simple array with individual variables, matched with a top of the hour (or more update), so that the user can define and track variables, and the actor doesn't have to be loaded to update these values every hour. Then these values are used during SL scenes. For example: how long has character X been wearing DD gloves? Correct me if I'm wrong, but this array is just char and int, so it should be very lightweight. That's a piece of infra that would bring SLT to the next level, enabling users to have lightweight, easy to read tracking system for values they define and care about for NPCs. Here is a skeleton that worked for me so far. I implemented wear I started to look into DD, these requires their own triggers when the NPC equips the DD In the long run, I'm hoping to integrate past partners names, crushes (based on # of orgasms) Spoiler Initialization script - to run once per game Spoiler ; ============================================================================= ; Tracking System Init v3g ; ============================================================================= ; PURPOSE: Initialize parallel global lists for actor tracking with wear values ; ; VERSION HISTORY: ; v1 - Used single global list + target-scoped variables (NEW approach) ; ISSUE: $target<var> syntax doesn't persist data between executions ; v2 - Reverted to parallel global lists (OLD approach) ; - $global.trk_actor_list (Form[]) - actor references ; - $global.trk_last_updated (float[]) - timestamps ; v3 - Added wear tracking lists ; - $global.trk_vaginal_wear (float[]) - vaginal wear 0-100 ; - $global.trk_anal_wear (float[]) - anal wear 0-100 ; - $global.trk_oral_wear (float[]) - oral wear 0-100 ; v3f - Added two new stats: ; - $global.trk_anal_dilation (float[]) - anal looseness 0-100 (0=tight) ; - $global.trk_gag_reflex (float[]) - gag reflex 0-100 (100=strong) ; v3g - Added DD equipment tracking: ; - $global.trk_wearing_anal_plug (int[]) - 0=not wearing, 1=wearing ; ; TRIGGER: Key Press ([) - user preference ; ============================================================================= deb_msg "[TRK-INIT] Starting initialization check" ; Check if lists already exist typeid $global.trk_actor_list if $$ == 0 msg_notify "[TRK-INIT] Creating tracking lists..." deb_msg "[TRK-INIT] typeid check returned 0 - lists do not exist" deb_msg "[TRK-INIT] Creating Form[] $global.trk_actor_list" Form[] $global.trk_actor_list deb_msg "[TRK-INIT] Creating float[] $global.trk_last_updated" float[] $global.trk_last_updated deb_msg "[TRK-INIT] Creating float[] $global.trk_vaginal_wear" float[] $global.trk_vaginal_wear deb_msg "[TRK-INIT] Creating float[] $global.trk_anal_wear" float[] $global.trk_anal_wear deb_msg "[TRK-INIT] Creating float[] $global.trk_oral_wear" float[] $global.trk_oral_wear deb_msg "[TRK-INIT] Creating float[] $global.trk_anal_dilation" float[] $global.trk_anal_dilation deb_msg "[TRK-INIT] Creating float[] $global.trk_gag_reflex" float[] $global.trk_gag_reflex deb_msg "[TRK-INIT] Creating int[] $global.trk_wearing_anal_plug" int[] $global.trk_wearing_anal_plug deb_msg "[TRK-INIT] All 8 global lists created successfully" msg_notify "[TRK-INIT] Tracking system initialized" else deb_msg "[TRK-INIT] typeid check returned non-zero - lists already exist" deb_msg "[TRK-INIT] Preserving existing data in all tracking lists" msg_notify "[TRK-INIT] Lists exist - data preserved" endif deb_msg "[TRK-INIT] Initialization complete" return Add an actor to the system. I used keystroke trigger, but cell scan would work too. Spoiler ; ============================================================================= ; Tracking System Register Keystroke v3f ; ============================================================================= ; PURPOSE: Register actors via crosshair + N key, display values if already registered ; ; VERSION HISTORY: ; v1a-v1e - Used target-scoped variables $target<targetActor>.varname ; ISSUE: Data doesn't persist between script executions ; v1f - Full debug version, confirmed the persistence bug ; v2 - Reverted to parallel global lists (OLD approach) ; - Uses list index to access parallel arrays ; - Data persists correctly across executions ; v3 - Added wear value display and initialization ; - Shows Vaginal/Anal/Oral wear on registered actors ; - Initializes wear to 0 for new registrations ; v3f - Added two new stats: ; - trk_anal_dilation: initialized to 0 (tight) ; - trk_gag_reflex: initialized to 100 (strong reflex) ; v3g - Added DD equipment tracking: ; - trk_wearing_anal_plug: detected at registration time ; ; TRIGGER: Key Press (N key) ; SYNTAX: $global.trk_xxx_wear[$index] for parallel list access ; ============================================================================= deb_msg "[TRK-REG] Starting registration check" ; Get the actor in crosshair set $targetActor resultfrom game_dogetter GetCurrentCrosshairRef deb_msg "[TRK-REG] Crosshair target acquired" ; Validate it's an actor set $isValid resultfrom actor_isvalid $targetActor deb_msg "[TRK-REG] actor_isvalid result: " $isValid if $isValid == false deb_msg "[TRK-REG] No valid actor in crosshair - aborting" msg_notify "[TRK-REG] No valid actor in crosshair" return endif ; Skip the player set $isPlayer resultfrom actor_isplayer $targetActor deb_msg "[TRK-REG] actor_isplayer result: " $isPlayer if $isPlayer == true deb_msg "[TRK-REG] Target is player - skipping" msg_notify "[TRK-REG] Skipped (player)" return endif ; Get actor name for logging actor_name $targetActor set $actorName $$ deb_msg "[TRK-REG] Target actor name: " $actorName ; Check if already registered by iterating the actor list set $count resultfrom listcount $global.trk_actor_list deb_msg "[TRK-REG] Current actor list count: " $count set $index 0 set $foundIndex -1 deb_msg "[TRK-REG] Starting search for existing registration..." while $index < $count set $listActor $global.trk_actor_list[$index] if $listActor == $targetActor set $foundIndex $index deb_msg "[TRK-REG] MATCH found at index: " $index endif inc $index 1 endwhile deb_msg "[TRK-REG] Search complete - foundIndex: " $foundIndex if $foundIndex >= 0 ; Already registered - display values from parallel lists deb_msg "[TRK-REG] Actor already registered - displaying values" msg_notify "=== " $actorName " (Index: " $foundIndex ") ===" ; Read from parallel lists using index set $lastUpd $global.trk_last_updated[$foundIndex] deb_msg "[TRK-REG] last_updated: " $lastUpd msg_notify "Last Updated: |" $lastUpd "|" ; Read wear values from parallel lists set $vagWear $global.trk_vaginal_wear[$foundIndex] set $anaWear $global.trk_anal_wear[$foundIndex] set $oraWear $global.trk_oral_wear[$foundIndex] set $anaDilation $global.trk_anal_dilation[$foundIndex] set $gagReflex $global.trk_gag_reflex[$foundIndex] set $wearingPlug $global.trk_wearing_anal_plug[$foundIndex] deb_msg "[TRK-REG] vaginal_wear: " $vagWear deb_msg "[TRK-REG] anal_wear: " $anaWear deb_msg "[TRK-REG] oral_wear: " $oraWear deb_msg "[TRK-REG] anal_dilation: " $anaDilation deb_msg "[TRK-REG] gag_reflex: " $gagReflex deb_msg "[TRK-REG] wearing_anal_plug: " $wearingPlug ; Display wear values msg_notify "Vaginal: " $vagWear " | Anal: " $anaWear " | Oral: " $oraWear msg_notify "Dilation: " $anaDilation " | Gag Reflex: " $gagReflex " | Anal Plug: " $wearingPlug return endif ; Guard rail: unique NPCs only set $isUnique resultfrom actorbase_dogetter $targetActor IsUnique deb_msg "[TRK-REG] IsUnique check result: " $isUnique if $isUnique == false deb_msg "[TRK-REG] Actor is not unique - skipping" msg_notify "[TRK-REG] Skipped (non-unique): " $actorName return endif ; Register the actor deb_msg "[TRK-REG] Proceeding with new registration for: " $actorName msg_notify "[TRK-REG] Registering: " $actorName ; Get current gametime set $currentTime $system.gametime deb_msg "[TRK-REG] Current gametime: " $currentTime ; Check if actor is wearing an anal plug at registration time actor_wornhaskeyword $targetActor "zad_DeviousPlugAnal" set $wearingPlug $$ deb_msg "[TRK-REG] Anal plug keyword check result: " $$ if $$ == true set $wearingPlug 1 deb_msg "[TRK-REG] Actor wearing anal plug - setting flag to 1" else set $wearingPlug 0 deb_msg "[TRK-REG] Actor NOT wearing anal plug - setting flag to 0" endif ; Add to ALL parallel lists (must stay in sync!) deb_msg "[TRK-REG] Adding to parallel lists..." listadd $global.trk_actor_list $targetActor deb_msg "[TRK-REG] Added to trk_actor_list" listadd $global.trk_last_updated $currentTime deb_msg "[TRK-REG] Added to trk_last_updated: " $currentTime listadd $global.trk_vaginal_wear 0.0 deb_msg "[TRK-REG] Added to trk_vaginal_wear: 0.0" listadd $global.trk_anal_wear 0.0 deb_msg "[TRK-REG] Added to trk_anal_wear: 0.0" listadd $global.trk_oral_wear 0.0 deb_msg "[TRK-REG] Added to trk_oral_wear: 0.0" listadd $global.trk_anal_dilation 0.0 deb_msg "[TRK-REG] Added to trk_anal_dilation: 0.0" listadd $global.trk_gag_reflex 100.0 deb_msg "[TRK-REG] Added to trk_gag_reflex: 100.0" listadd $global.trk_wearing_anal_plug $wearingPlug deb_msg "[TRK-REG] Added to trk_wearing_anal_plug: " $wearingPlug ; Get the new index set $aValue resultfrom listcount $global.trk_actor_list inc $aValue -1 deb_msg "[TRK-REG] New actor index: " $aValue msg_notify "[TRK-REG] Registered! Index: " $aValue msg_notify "[TRK-REG] Wear values initialized to 0, Gag Reflex: 100" deb_msg "[TRK-REG] Registration complete for: " $actorName return Example of using this array at the end of a scene for narration & to update array values Spoiler ; ============================================================================= ; Tracking System SexLab End Handler v3g ; ============================================================================= ; PURPOSE: Increment wear values when registered actors finish SexLab scenes ; ; TRIGGER: SexLab - End (runs for each actor in scene) ; ACTOR: $system.self = the actor this script is running for ; ; VERSION HISTORY: ; v3b - Read stored tags from $target. variables (sl_hastag fails at End) ; v3c - Fix: use "set $list[index] = value" instead of non-existent listset ; v3d - Fix: use intermediate variable + assignment without "=" sign ; v3e - Fix: remove invalid second parameter from SkyrimNetDirectNarration calls ; v3f - Changes: ; - Increased wear values (2x): Vaginal 20±4, Anal 50±10, Oral 15±3 ; - Added gag_reflex: -10 per oral act (100=strong, 0=broken) ; - Added gag reflex narration tiers ; - Standardized debug message format ; v3g - Added DOM training mitigation: ; - DOMTrainAnal/Vaginal/Oral factions reduce wear damage ; - Training 0 = 1.0 multiplier (100% damage) ; - Training 100 = 0.5 multiplier (50% damage) ; - Formula: multiplier = 1.0 - (training * 0.005) ; - Minimum 1 damage regardless of training ; - Added race buff: 0.8x damage for specific resilient races ; ; BASE DAMAGE VALUES (before mitigation): ; Vaginal: 20 +/- 4 (20% variance) ; Anal: 25 +/- 5 (20% variance) ; Oral: 10 +/- 2 (20% variance) - ONLY for blowjob/facefuck tags ; ; GAG REFLEX: ; -10 per oral act (desensitizes throat) ; ; MAX WEAR: 100 (clamped) ; ============================================================================= deb_msg "[TRK-END] === SexLab End Handler v3g triggered ===" ; ===== STEP 1: GET CURRENT ACTOR ===== set $selfActor $system.self deb_msg "[TRK-END] selfActor acquired" ; Validate actor set $isValid resultfrom actor_isvalid $selfActor deb_msg "[TRK-END] actor_isvalid result: " $isValid if $isValid == false deb_msg "[TRK-END] Invalid actor - aborting" return endif ; Skip the player set $isPlayer resultfrom actor_isplayer $selfActor deb_msg "[TRK-END] actor_isplayer result: " $isPlayer if $isPlayer == true deb_msg "[TRK-END] Player detected - skipping" return endif ; ===== STEP 2: CHECK IF REGISTERED ===== set $count resultfrom listcount $global.trk_actor_list deb_msg "[TRK-END] Actor list count: " $count set $index 0 set $foundIndex -1 deb_msg "[TRK-END] Searching for actor in tracking list..." while $index < $count set $listActor $global.trk_actor_list[$index] if $listActor == $selfActor set $foundIndex $index deb_msg "[TRK-END] MATCH found at index: " $index endif inc $index 1 endwhile deb_msg "[TRK-END] Search complete - foundIndex: " $foundIndex if $foundIndex < 0 ; Actor not registered - skip (only track registered actors) actor_name $selfActor deb_msg "[TRK-END] Actor not registered: " $$ " - skipping" return endif ; ===== STEP 3: GET ACTOR INFO ===== actor_name $selfActor set $actorName $$ set $actorIndex $foundIndex deb_msg "[TRK-END] === Processing: " $actorName " (Index: " $actorIndex ") ===" ; Get current gametime for last_updated set $currentTime $system.gametime deb_msg "[TRK-END] Current gametime: " $currentTime ; ===== STEP 3.5: CHECK RACE FOR BUFF ===== ; Get actor's race FormID and check against resilient race list deb_msg "[TRK-END] === Race Check ===" set $isResilientRace false actor_getrace $selfActor set $actorRaceForm $$ deb_msg "[TRK-END] Race form acquired" form_getformid $actorRaceForm set $actorRaceId $$ deb_msg "[TRK-END] Race FormID: " $actorRaceId ; Check against each resilient race (0.8x damage multiplier) if $actorRaceId == "0xwhateverrace" set $isResilientRace true endif if $isResilientRace == true deb_msg "[TRK-END] RACE BUFF ACTIVE: " $actorRaceId " (0.8x damage)" else deb_msg "[TRK-END] No race buff (normal damage)" endif ; ===== STEP 4: READ STORED TAGS (from Start script) ===== ; CRITICAL: sl_hastag does NOT work at End - scene already ended. ; Read the tags that were stored in $target. variables at Start. deb_msg "[TRK-END] === Reading stored tags ===" set $hasAnal $target.trk_scene_hasAnal set $hasVaginal $target.trk_scene_hasVaginal set $hasOral $target.trk_scene_hasOral deb_msg "[TRK-END] hasAnal: " $hasAnal deb_msg "[TRK-END] hasVaginal: " $hasVaginal deb_msg "[TRK-END] hasOral: " $hasOral ; Track if any wear was applied set $wearApplied 0 ; --- ANAL WEAR (priority 1) --- if $hasAnal == true deb_msg "[TRK-END] === ANAL WEAR CALCULATION ===" ; --- GET DOM TRAINING LEVEL --- actor_getfactionrank $selfActor "DOMTrainAnal" set $analTraining $$ deb_msg "[TRK-END] DOMTrainAnal rank: " $analTraining ; --- CALCULATE BASE DAMAGE --- ; Base: 25 +/- 5 set $baseAnaDamage 25.0 deb_msg "[TRK-END] Base damage: " $baseAnaDamage rnd_int -5 5 set $anaVariance $$ deb_msg "[TRK-END] Variance roll: " $anaVariance set $anaDamage $baseAnaDamage + $anaVariance deb_msg "[TRK-END] Pre-multiplier damage: " $anaDamage ; --- APPLY DAMAGE MULTIPLIER SYSTEM --- ; Start with base multiplier of 1.0 set $damageMultiplier 1.0 deb_msg "[TRK-END] Initial multiplier: " $damageMultiplier ; Apply DOM training mitigation: 0.005 per training point ; Training 0 = 1.0 multiplier (100% damage) ; Training 100 = 0.5 multiplier (50% damage) set $trainingReduction $analTraining * 0.005 deb_msg "[TRK-END] Training reduction: " $trainingReduction set $damageMultiplier $damageMultiplier - $trainingReduction deb_msg "[TRK-END] Multiplier after training: " $damageMultiplier ; Apply race buff: 0.8x damage for resilient races if $isResilientRace == true set $damageMultiplier $damageMultiplier * 0.8 deb_msg "[TRK-END] Multiplier after race buff (0.8x): " $damageMultiplier endif ; Apply multiplier to base damage set $finalDamage $anaDamage * $damageMultiplier deb_msg "[TRK-END] Final damage before min: " $finalDamage ; Minimum 1 damage if $finalDamage < 1 set $finalDamage 1 deb_msg "[TRK-END] Applied minimum damage: 1" endif deb_msg "[TRK-END] FINAL ANAL DAMAGE: " $finalDamage ; --- APPLY TO WEAR --- set $currentVal $global.trk_anal_wear[$actorIndex] deb_msg "[TRK-END] Current anal wear: " $currentVal set $newVal $currentVal + $finalDamage deb_msg "[TRK-END] New wear before clamp: " $newVal ; Clamp to max 100 if $newVal > 100 set $newVal 100 deb_msg "[TRK-END] Clamped to max: 100" endif set $global.trk_anal_wear[$actorIndex] $newVal deb_msg "[TRK-END] ANAL WEAR: " $currentVal " -> " $newVal " (+" $finalDamage ")" msg_notify "[TRK-END] Anal wear: " $currentVal " -> " $newVal " (+" $finalDamage ")" set $wearApplied 1 endif ; --- VAGINAL WEAR (priority 2) --- if $hasVaginal == true deb_msg "[TRK-END] === VAGINAL WEAR CALCULATION ===" ; --- GET DOM TRAINING LEVEL --- actor_getfactionrank $selfActor "DOMTrainVaginal" set $vaginalTraining $$ deb_msg "[TRK-END] DOMTrainVaginal rank: " $vaginalTraining ; --- CALCULATE BASE DAMAGE --- ; Base: 20 +/- 4 set $baseVagDamage 20.0 deb_msg "[TRK-END] Base damage: " $baseVagDamage rnd_int -4 4 set $vagVariance $$ deb_msg "[TRK-END] Variance roll: " $vagVariance set $vagDamage $baseVagDamage + $vagVariance deb_msg "[TRK-END] Pre-multiplier damage: " $vagDamage ; --- APPLY DAMAGE MULTIPLIER SYSTEM --- ; Start with base multiplier of 1.0 set $damageMultiplier 1.0 deb_msg "[TRK-END] Initial multiplier: " $damageMultiplier ; Apply DOM training mitigation: 0.005 per training point set $trainingReduction $vaginalTraining * 0.005 deb_msg "[TRK-END] Training reduction: " $trainingReduction set $damageMultiplier $damageMultiplier - $trainingReduction deb_msg "[TRK-END] Multiplier after training: " $damageMultiplier ; Apply race buff: 0.8x damage for resilient races if $isResilientRace == true set $damageMultiplier $damageMultiplier * 0.8 deb_msg "[TRK-END] Multiplier after race buff (0.8x): " $damageMultiplier endif ; Apply multiplier to base damage set $finalDamage $vagDamage * $damageMultiplier deb_msg "[TRK-END] Final damage before min: " $finalDamage ; Minimum 1 damage if $finalDamage < 1 set $finalDamage 1 deb_msg "[TRK-END] Applied minimum damage: 1" endif deb_msg "[TRK-END] FINAL VAGINAL DAMAGE: " $finalDamage ; --- APPLY TO WEAR --- set $currentVal $global.trk_vaginal_wear[$actorIndex] deb_msg "[TRK-END] Current vaginal wear: " $currentVal set $newVal $currentVal + $finalDamage deb_msg "[TRK-END] New wear before clamp: " $newVal ; Clamp to max 100 if $newVal > 100 set $newVal 100 deb_msg "[TRK-END] Clamped to max: 100" endif set $global.trk_vaginal_wear[$actorIndex] $newVal deb_msg "[TRK-END] VAGINAL WEAR: " $currentVal " -> " $newVal " (+" $finalDamage ")" msg_notify "[TRK-END] Vaginal wear: " $currentVal " -> " $newVal " (+" $finalDamage ")" set $wearApplied 1 endif ; --- ORAL WEAR (priority 3) --- if $hasOral == true deb_msg "[TRK-END] === ORAL WEAR CALCULATION ===" ; --- GET DOM TRAINING LEVEL --- actor_getfactionrank $selfActor "DOMTrainOral" set $oralTraining $$ deb_msg "[TRK-END] DOMTrainOral rank: " $oralTraining ; --- CALCULATE BASE DAMAGE --- ; Base: 10 +/- 2 set $baseOraDamage 10.0 deb_msg "[TRK-END] Base damage: " $baseOraDamage rnd_int -2 2 set $oraVariance $$ deb_msg "[TRK-END] Variance roll: " $oraVariance set $oraDamage $baseOraDamage + $oraVariance deb_msg "[TRK-END] Pre-multiplier damage: " $oraDamage ; --- APPLY DAMAGE MULTIPLIER SYSTEM --- ; Start with base multiplier of 1.0 set $damageMultiplier 1.0 deb_msg "[TRK-END] Initial multiplier: " $damageMultiplier ; Apply DOM training mitigation: 0.005 per training point set $trainingReduction $oralTraining * 0.005 deb_msg "[TRK-END] Training reduction: " $trainingReduction set $damageMultiplier $damageMultiplier - $trainingReduction deb_msg "[TRK-END] Multiplier after training: " $damageMultiplier ; Apply race buff: 0.8x damage for resilient races if $isResilientRace == true set $damageMultiplier $damageMultiplier * 0.8 deb_msg "[TRK-END] Multiplier after race buff (0.8x): " $damageMultiplier endif ; Apply multiplier to base damage set $finalDamage $oraDamage * $damageMultiplier deb_msg "[TRK-END] Final damage before min: " $finalDamage ; Minimum 1 damage if $finalDamage < 1 set $finalDamage 1 deb_msg "[TRK-END] Applied minimum damage: 1" endif deb_msg "[TRK-END] FINAL ORAL DAMAGE: " $finalDamage ; --- APPLY TO WEAR --- set $currentVal $global.trk_oral_wear[$actorIndex] deb_msg "[TRK-END] Current oral wear: " $currentVal set $newVal $currentVal + $finalDamage deb_msg "[TRK-END] New wear before clamp: " $newVal ; Clamp to max 100 if $newVal > 100 set $newVal 100 deb_msg "[TRK-END] Clamped to max: 100" endif set $global.trk_oral_wear[$actorIndex] $newVal deb_msg "[TRK-END] ORAL WEAR: " $currentVal " -> " $newVal " (+" $finalDamage ")" msg_notify "[TRK-END] Oral wear: " $currentVal " -> " $newVal " (+" $finalDamage ")" set $wearApplied 1 endif ; --- GAG REFLEX (priority 4) --- if $hasOral == true deb_msg "[TRK-END] === GAG REFLEX REDUCTION ===" set $currentGag $global.trk_gag_reflex[$actorIndex] deb_msg "[TRK-END] Current gag reflex: " $currentGag set $newGag $currentGag - 10.0 deb_msg "[TRK-END] After reduction (-10): " $newGag ; Clamp to min 0 if $newGag < 0 set $newGag 0 deb_msg "[TRK-END] Clamped to min: 0" endif set $global.trk_gag_reflex[$actorIndex] $newGag deb_msg "[TRK-END] GAG REFLEX: " $currentGag " -> " $newGag msg_notify "[TRK-END] Gag reflex: " $currentGag " -> " $newGag " (-10)" endif ; --- DEBUG: No wear tags detected --- if $wearApplied == 0 deb_msg "[TRK-END] No wear tags detected (e.g., handjob, groping, etc.)" endif ; ===== STEP 5: NARRATION BASED ON WEAR STATE ===== deb_msg "[TRK-END] === NARRATION CHECK ===" ; Tier mapping (0-100 scale). Narration only from 50+: ; 0-49: No narration ; 50-74: Worn - uncomfortable, needs rest ; 75-89: Heavy wear - painful, struggling ; 90-100: Broken - can't take anymore ; Get actor name for narration (use $actorName already set earlier) set $1 $actorName ; --- ANAL NARRATION --- set $anaWear $global.trk_anal_wear[$actorIndex] deb_msg "[TRK-END] Anal wear for narration check: " $anaWear ; Tier 5: Broken (90-100) if $anaWear >= 90 if $hasAnal == true deb_msg "[TRK-END] Triggering ANAL narration tier 5 (Broken)" SkyrimNetDirectNarration $"{$1} feels her ruined anus gaping wide, unable to clench, semen and blood mingling as it leaks. She feels her body broken beyond any quick recovery." endif ; Tier 4: Heavy wear (75-89) elseif $anaWear >= 75 if $hasAnal == true deb_msg "[TRK-END] Triggering ANAL narration tier 4 (Heavy wear)" SkyrimNetDirectNarration $"{$1} feels her abused anus throbbing with each movement, a raw burning sensation that tells her she needs a long rest." endif ; Tier 3: Worn (50-74) elseif $anaWear >= 50 if $hasAnal == true deb_msg "[TRK-END] Triggering ANAL narration tier 3 (Worn)" SkyrimNetDirectNarration $"{$1} feels her anus sore and tender, and senses she has reached her limit for this kind of use today." endif else deb_msg "[TRK-END] Anal wear below narration threshold (50)" endif ; --- VAGINAL NARRATION --- set $vagWear $global.trk_vaginal_wear[$actorIndex] deb_msg "[TRK-END] Vaginal wear for narration check: " $vagWear ; Tier 5: Broken (90-100) if $vagWear >= 90 if $hasVaginal == true deb_msg "[TRK-END] Triggering VAGINAL narration tier 5 (Broken)" SkyrimNetDirectNarration $"{$1} feels her pussy hanging open, unable to close, seed and fluids dripping down her thighs. She feels her body pushed far past its limits." endif ; Tier 4: Heavy wear (75-89) elseif $vagWear >= 75 if $hasVaginal == true deb_msg "[TRK-END] Triggering VAGINAL narration tier 4 (Heavy wear)" SkyrimNetDirectNarration $"{$1} feels her swollen pussy pulsing with an aching heat. Every step reminds her of the use she just endured." endif ; Tier 3: Worn (50-74) elseif $vagWear >= 50 if $hasVaginal == true deb_msg "[TRK-END] Triggering VAGINAL narration tier 3 (Worn)" SkyrimNetDirectNarration $"{$1} feels tender and overused between her legs, a deep soreness that tells her to avoid further penetration for a while." endif else deb_msg "[TRK-END] Vaginal wear below narration threshold (50)" endif ; --- ORAL NARRATION --- set $oraWear $global.trk_oral_wear[$actorIndex] deb_msg "[TRK-END] Oral wear for narration check: " $oraWear ; Tier 5: Broken (90-100) if $oraWear >= 90 if $hasOral == true deb_msg "[TRK-END] Triggering ORAL narration tier 5 (Broken)" SkyrimNetDirectNarration $"{$1} feels her jaw hanging slack, unable to fully close, drool and cum dripping from her numb lips. Her throat feels so raw she can barely swallow." endif ; Tier 4: Heavy wear (75-89) elseif $oraWear >= 75 if $hasOral == true deb_msg "[TRK-END] Triggering ORAL narration tier 4 (Heavy wear)" SkyrimNetDirectNarration $"{$1} feels her jaw aching and her throat burning with each swallow, stretched to its limit." endif ; Tier 3: Worn (50-74) elseif $oraWear >= 50 if $hasOral == true deb_msg "[TRK-END] Triggering ORAL narration tier 3 (Worn)" SkyrimNetDirectNarration $"{$1} feels her jaw tired and her throat slightly sore. She has had enough oral for now." endif else deb_msg "[TRK-END] Oral wear below narration threshold (50)" endif ; --- GAG REFLEX NARRATION --- ; Reverse tiers: 100 = strong reflex (good), 0 = no reflex (broken) set $gagReflex $global.trk_gag_reflex[$actorIndex] deb_msg "[TRK-END] Gag reflex for narration check: " $gagReflex ; Tier 3: Weakened (50-74) - some resistance lost if $gagReflex >= 50 if $gagReflex < 75 if $hasOral == true deb_msg "[TRK-END] Triggering GAG REFLEX narration tier 3 (Weakened)" SkyrimNetDirectNarration $"{$1} feels her throat has become more accommodating, her gag reflex weakening with each use." endif endif ; Tier 4: Heavy suppression (25-49) elseif $gagReflex >= 25 if $hasOral == true deb_msg "[TRK-END] Triggering GAG REFLEX narration tier 4 (Heavy suppression)" SkyrimNetDirectNarration $"{$1} feels her jaw hanging slack, able to take things deeply without choking. Her throat has been trained well." endif ; Tier 5: Broken (0-24) elseif $gagReflex < 25 if $hasOral == true deb_msg "[TRK-END] Triggering GAG REFLEX narration tier 5 (Broken)" SkyrimNetDirectNarration $"{$1} feels almost nothing in her throat anymore. She could take the largest member without a single gag." endif else deb_msg "[TRK-END] Gag reflex above narration threshold (75)" endif ; ===== STEP 6: UPDATE TIMESTAMP ===== set $global.trk_last_updated[$actorIndex] $currentTime deb_msg "[TRK-END] Updated timestamp to: " $currentTime ; ===== STEP 7: CLEANUP STORED TAGS ===== ; Clear the stored tag variables to prevent stale data deb_msg "[TRK-END] Clearing stored tag variables..." set $target.trk_scene_hasAnal false set $target.trk_scene_hasVaginal false set $target.trk_scene_hasOral false deb_msg "[TRK-END] Tags cleared" deb_msg "[TRK-END] === Complete for " $actorName " ===" return Example integration top of the hour with Skyrimnet narration (the NPC will think this and consider what to do Spoiler ; ============================================================================= ; Tracking System Top of the Hour Impact v1 ; ============================================================================= ; PURPOSE: Apply wear-based health/stamina damage and narration hourly ; ; TRIGGER: Top of the Hour ; ACTORS: All registered actors in $global.trk_actor_list ; ; WEAR LEVELS (0-100 -> 0-9): ; 0 (0-10): fresh/virgin ; 1 (11-20): tight ; 2 (21-30): sore ; 3 (31-40): puckered/abused ; 4 (41-50): worn ; 5 (51-60): swollen ; 6 (61-70): ravished ; 7 (71-80): loose ; 8 (81-90): battered/gaping ; 9 (91-100): ruined/destroyed ; ; DAMAGE PER WEAR TYPE: ; Level 0-1: 0% health, 0% stamina ; Level 2: 1% health, 2% stamina ; Level 3: 2% health, 4% stamina ; Level 4: 4% health, 6% stamina ; Level 5: 6% health, 10% stamina ; Level 6: 10% health, 15% stamina ; Level 7: 15% health, 20% stamina ; Level 8: 20% health, 30% stamina ; Level 9: 30% health, 40% stamina ; ============================================================================= deb_msg "[TRK-HOURLY] === Top of the Hour Impact v1 started ===" ; ===== STEP 1: GET ACTOR COUNT ===== set $count resultfrom listcount $global.trk_actor_list deb_msg "[TRK-HOURLY] Actor count: " $count if $count == 0 deb_msg "[TRK-HOURLY] No actors registered - nothing to do" msg_notify "[TRK-HOURLY] No actors registered" return endif ; ===== STEP 2: ITERATE ALL ACTORS ===== set $index 0 while $index < $count deb_msg "[TRK-HOURLY] === Processing index " $index " ===" ; Get actor set $currentActor $global.trk_actor_list[$index] ; Validate actor set $isValid resultfrom actor_isvalid $currentActor deb_msg "[TRK-HOURLY] actor_isvalid result: " $isValid if $isValid == false deb_msg "[TRK-HOURLY] Invalid actor at index " $index " - skipping" inc $index 1 continue endif ; Get actor name actor_name $currentActor set $actorName $$ deb_msg "[TRK-HOURLY] Actor: " $actorName ; ===== GET WEAR VALUES ===== set $analWear $global.trk_anal_wear[$index] set $vaginalWear $global.trk_vaginal_wear[$index] set $oralWear $global.trk_oral_wear[$index] deb_msg "[TRK-HOURLY] Anal wear: " $analWear deb_msg "[TRK-HOURLY] Vaginal wear: " $vaginalWear deb_msg "[TRK-HOURLY] Oral wear: " $oralWear ; ===== GET MAX VALUES FOR PERCENTAGE CALCULATION ===== av_getmax $currentActor "Health" set $maxHealth $$ deb_msg "[TRK-HOURLY] Max Health: " $maxHealth av_getmax $currentActor "Stamina" set $maxStamina $$ deb_msg "[TRK-HOURLY] Max Stamina: " $maxStamina ; ===== INITIALIZE TOTAL DAMAGE ===== set $totalHealthDamage 0 set $totalStaminaDamage 0 deb_msg "[TRK-HOURLY] Initializing total damage to 0" ; ===== CALCULATE ANAL WEAR DAMAGE ===== deb_msg "[TRK-HOURLY] --- ANAL DAMAGE CALCULATION ---" set $analLevel $analWear / 10 deb_msg "[TRK-HOURLY] Anal wear: " $analWear " -> Level: " $analLevel if $analLevel > 9 set $analLevel 9 deb_msg "[TRK-HOURLY] Clamped level to max: 9" endif if $analLevel == 2 set $healthPct 1 set $staminaPct 2 elseif $analLevel == 3 set $healthPct 2 set $staminaPct 4 elseif $analLevel == 4 set $healthPct 4 set $staminaPct 6 elseif $analLevel == 5 set $healthPct 6 set $staminaPct 10 elseif $analLevel == 6 set $healthPct 10 set $staminaPct 15 elseif $analLevel == 7 set $healthPct 15 set $staminaPct 20 elseif $analLevel == 8 set $healthPct 20 set $staminaPct 30 elseif $analLevel == 9 set $healthPct 30 set $staminaPct 40 else set $healthPct 0 set $staminaPct 0 endif deb_msg "[TRK-HOURLY] Anal damage percentages: HP=" $healthPct "% Stam=" $staminaPct "%" set $analHealthDamage $maxHealth * $healthPct / 100 set $analStaminaDamage $maxStamina * $staminaPct / 100 deb_msg "[TRK-HOURLY] Anal damage values: HP=" $analHealthDamage " Stam=" $analStaminaDamage set $totalHealthDamage $totalHealthDamage + $analHealthDamage set $totalStaminaDamage $totalStaminaDamage + $analStaminaDamage deb_msg "[TRK-HOURLY] Running totals: HP=" $totalHealthDamage " Stam=" $totalStaminaDamage ; ===== CALCULATE VAGINAL WEAR DAMAGE ===== deb_msg "[TRK-HOURLY] --- VAGINAL DAMAGE CALCULATION ---" set $vaginalLevel $vaginalWear / 10 deb_msg "[TRK-HOURLY] Vaginal wear: " $vaginalWear " -> Level: " $vaginalLevel if $vaginalLevel > 9 set $vaginalLevel 9 deb_msg "[TRK-HOURLY] Clamped level to max: 9" endif if $vaginalLevel == 2 set $healthPct 1 set $staminaPct 2 elseif $vaginalLevel == 3 set $healthPct 2 set $staminaPct 4 elseif $vaginalLevel == 4 set $healthPct 4 set $staminaPct 6 elseif $vaginalLevel == 5 set $healthPct 6 set $staminaPct 10 elseif $vaginalLevel == 6 set $healthPct 10 set $staminaPct 15 elseif $vaginalLevel == 7 set $healthPct 15 set $staminaPct 20 elseif $vaginalLevel == 8 set $healthPct 20 set $staminaPct 30 elseif $vaginalLevel == 9 set $healthPct 30 set $staminaPct 40 else set $healthPct 0 set $staminaPct 0 endif deb_msg "[TRK-HOURLY] Vaginal damage percentages: HP=" $healthPct "% Stam=" $staminaPct "%" set $vaginalHealthDamage $maxHealth * $healthPct / 100 set $vaginalStaminaDamage $maxStamina * $staminaPct / 100 deb_msg "[TRK-HOURLY] Vaginal damage values: HP=" $vaginalHealthDamage " Stam=" $vaginalStaminaDamage set $totalHealthDamage $totalHealthDamage + $vaginalHealthDamage set $totalStaminaDamage $totalStaminaDamage + $vaginalStaminaDamage deb_msg "[TRK-HOURLY] Running totals: HP=" $totalHealthDamage " Stam=" $totalStaminaDamage ; ===== CALCULATE ORAL WEAR DAMAGE ===== deb_msg "[TRK-HOURLY] --- ORAL DAMAGE CALCULATION ---" set $oralLevel $oralWear / 10 deb_msg "[TRK-HOURLY] Oral wear: " $oralWear " -> Level: " $oralLevel if $oralLevel > 9 set $oralLevel 9 deb_msg "[TRK-HOURLY] Clamped level to max: 9" endif if $oralLevel == 2 set $healthPct 1 set $staminaPct 2 elseif $oralLevel == 3 set $healthPct 2 set $staminaPct 4 elseif $oralLevel == 4 set $healthPct 4 set $staminaPct 6 elseif $oralLevel == 5 set $healthPct 6 set $staminaPct 10 elseif $oralLevel == 6 set $healthPct 10 set $staminaPct 15 elseif $oralLevel == 7 set $healthPct 15 set $staminaPct 20 elseif $oralLevel == 8 set $healthPct 20 set $staminaPct 30 elseif $oralLevel == 9 set $healthPct 30 set $staminaPct 40 else set $healthPct 0 set $staminaPct 0 endif deb_msg "[TRK-HOURLY] Oral damage percentages: HP=" $healthPct "% Stam=" $staminaPct "%" set $oralHealthDamage $maxHealth * $healthPct / 100 set $oralStaminaDamage $maxStamina * $staminaPct / 100 deb_msg "[TRK-HOURLY] Oral damage values: HP=" $oralHealthDamage " Stam=" $oralStaminaDamage set $totalHealthDamage $totalHealthDamage + $oralHealthDamage set $totalStaminaDamage $totalStaminaDamage + $oralStaminaDamage deb_msg "[TRK-HOURLY] FINAL TOTALS: HP=" $totalHealthDamage " Stam=" $totalStaminaDamage ; ===== APPLY TOTAL DAMAGE (never below 1) ===== deb_msg "[TRK-HOURLY] --- APPLYING DAMAGE ---" if $totalHealthDamage > 0 deb_msg "[TRK-HOURLY] Checking health safety limits..." ; Get current health and ensure we don't go below 1 av_get $currentActor "Health" set $currentHealth $$ deb_msg "[TRK-HOURLY] Current health: " $currentHealth set $maxHealthDamage $currentHealth - 1 deb_msg "[TRK-HOURLY] Max safe damage: " $maxHealthDamage if $totalHealthDamage > $maxHealthDamage if $maxHealthDamage > 0 set $totalHealthDamage $maxHealthDamage deb_msg "[TRK-HOURLY] Clamped health damage to: " $totalHealthDamage else set $totalHealthDamage 0 deb_msg "[TRK-HOURLY] Health damage set to 0 (would kill actor)" endif endif if $totalHealthDamage > 0 deb_msg "[TRK-HOURLY] Applying health damage: " $totalHealthDamage av_damage $currentActor "Health" $totalHealthDamage endif else deb_msg "[TRK-HOURLY] No health damage to apply" endif if $totalStaminaDamage > 0 deb_msg "[TRK-HOURLY] Checking stamina safety limits..." ; Get current stamina and ensure we don't go below 1 av_get $currentActor "Stamina" set $currentStamina $$ deb_msg "[TRK-HOURLY] Current stamina: " $currentStamina set $maxStaminaDamage $currentStamina - 1 deb_msg "[TRK-HOURLY] Max safe damage: " $maxStaminaDamage if $totalStaminaDamage > $maxStaminaDamage if $maxStaminaDamage > 0 set $totalStaminaDamage $maxStaminaDamage deb_msg "[TRK-HOURLY] Clamped stamina damage to: " $totalStaminaDamage else set $totalStaminaDamage 0 deb_msg "[TRK-HOURLY] Stamina damage set to 0 (would deplete)" endif endif if $totalStaminaDamage > 0 deb_msg "[TRK-HOURLY] Applying stamina damage: " $totalStaminaDamage av_damage $currentActor "Stamina" $totalStaminaDamage endif else deb_msg "[TRK-HOURLY] No stamina damage to apply" endif ; ===== NARRATION BY WEAR TYPE (level 2+ only) ===== set $1 $actorName ; ===== ANAL NARRATION ===== deb_msg "[TRK-HOURLY] --- ANAL NARRATION CHECK (Level " $analLevel ") ---" if $analLevel == 2 deb_msg "[TRK-HOURLY] Triggering anal narration level 2" SkyrimNetDirectNarration $"{$1} feels a dull ache in her anus." elseif $analLevel == 3 deb_msg "[TRK-HOURLY] Triggering anal narration level 3" SkyrimNetDirectNarration $"{$1} feels her anus stinging and tender." elseif $analLevel == 4 deb_msg "[TRK-HOURLY] Triggering anal narration level 4" SkyrimNetDirectNarration $"{$1} feels a burning sensation in her anus." elseif $analLevel == 5 deb_msg "[TRK-HOURLY] Triggering anal narration level 5" SkyrimNetDirectNarration $"{$1} feels her anus swollen and throbbing with pain." elseif $analLevel == 6 deb_msg "[TRK-HOURLY] Triggering anal narration level 6" SkyrimNetDirectNarration $"{$1} feels her anus raw and bleeding slightly." elseif $analLevel == 7 deb_msg "[TRK-HOURLY] Triggering anal narration level 7" SkyrimNetDirectNarration $"{$1} feels her anus stretched open and stinging continuously." elseif $analLevel == 8 deb_msg "[TRK-HOURLY] Triggering anal narration level 8" SkyrimNetDirectNarration $"{$1} feels her anus gaping and bleeding with each movement." elseif $analLevel == 9 deb_msg "[TRK-HOURLY] Triggering anal narration level 9" SkyrimNetDirectNarration $"{$1} feels severe tearing pain in her anus and blood running down her thighs." else deb_msg "[TRK-HOURLY] No anal narration (level 0-1)" endif ; ===== VAGINAL NARRATION ===== deb_msg "[TRK-HOURLY] --- VAGINAL NARRATION CHECK (Level " $vaginalLevel ") ---" if $vaginalLevel == 2 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 2" SkyrimNetDirectNarration $"{$1} feels a dull ache in her vagina." elseif $vaginalLevel == 3 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 3" SkyrimNetDirectNarration $"{$1} feels her vagina stinging and tender." elseif $vaginalLevel == 4 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 4" SkyrimNetDirectNarration $"{$1} feels a burning sensation in her vagina." elseif $vaginalLevel == 5 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 5" SkyrimNetDirectNarration $"{$1} feels her vaginal lips swollen and throbbing with pain." elseif $vaginalLevel == 6 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 6" SkyrimNetDirectNarration $"{$1} feels her vagina raw and bleeding slightly." elseif $vaginalLevel == 7 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 7" SkyrimNetDirectNarration $"{$1} feels her vagina stretched open and stinging continuously." elseif $vaginalLevel == 8 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 8" SkyrimNetDirectNarration $"{$1} feels her vagina gaping and bleeding with each step." elseif $vaginalLevel == 9 deb_msg "[TRK-HOURLY] Triggering vaginal narration level 9" SkyrimNetDirectNarration $"{$1} feels severe tearing pain in her vagina and blood running down her thighs." else deb_msg "[TRK-HOURLY] No vaginal narration (level 0-1)" endif ; ===== ORAL NARRATION ===== deb_msg "[TRK-HOURLY] --- ORAL NARRATION CHECK (Level " $oralLevel ") ---" if $oralLevel == 2 deb_msg "[TRK-HOURLY] Triggering oral narration level 2" SkyrimNetDirectNarration $"{$1} feels her jaw aching and throat sore." elseif $oralLevel == 3 deb_msg "[TRK-HOURLY] Triggering oral narration level 3" SkyrimNetDirectNarration $"{$1} feels her throat raw and her jaw tender." elseif $oralLevel == 4 deb_msg "[TRK-HOURLY] Triggering oral narration level 4" SkyrimNetDirectNarration $"{$1} feels her throat burning when she swallows." elseif $oralLevel == 5 deb_msg "[TRK-HOURLY] Triggering oral narration level 5" SkyrimNetDirectNarration $"{$1} feels her throat swollen and her jaw throbbing with pain." elseif $oralLevel == 6 deb_msg "[TRK-HOURLY] Triggering oral narration level 6" SkyrimNetDirectNarration $"{$1} feels her gums bleeding and her throat raw." elseif $oralLevel == 7 deb_msg "[TRK-HOURLY] Triggering oral narration level 7" SkyrimNetDirectNarration $"{$1} feels her jaw stiff and her throat stinging continuously." elseif $oralLevel == 8 deb_msg "[TRK-HOURLY] Triggering oral narration level 8" SkyrimNetDirectNarration $"{$1} feels her throat bleeding and difficulty speaking." elseif $oralLevel == 9 deb_msg "[TRK-HOURLY] Triggering oral narration level 9" SkyrimNetDirectNarration $"{$1} feels severe throat pain and blood in her mouth." else deb_msg "[TRK-HOURLY] No oral narration (level 0-1)" endif ; Summary output if $totalHealthDamage > 0 deb_msg "[TRK-HOURLY] " $actorName ": Applied HP-" $totalHealthDamage " Stam-" $totalStaminaDamage msg_notify "[TRK-HOURLY] " $actorName ": HP-" $totalHealthDamage " Stam-" $totalStaminaDamage endif inc $index 1 endwhile deb_msg "[TRK-HOURLY] === Processed " $count " actors ===" msg_notify "[TRK-HOURLY] Processed " $count " actors" return Edited July 18 by Fraying9981
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now