Jump to content

Recommended Posts

Posted (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 by Mushano
  • 3 weeks later...
Posted
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. 

Posted
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. 

 

 

image.png.efc4a608e87427d0b85bb08b05f1dbdf.pngthanks, indeed.

Posted
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. 

Posted
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}"

 

 

Posted

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

 

 

Posted
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?

Posted
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. 

Posted

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?

Posted
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.

Posted
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

Posted
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.
 

Posted

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

Screenshot2026-07-13033842.png.641556e7b5de626b0d24a9ac605bdc5e.png

Spoiler

Screenshot2026-07-13034044.png.358aa379d38a2cd84e81d7e94ca05fb6.png

 

Posted
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

Screenshot2026-07-13033842.png.641556e7b5de626b0d24a9ac605bdc5e.png

  Hide contents

Screenshot2026-07-13034044.png.358aa379d38a2cd84e81d7e94ca05fb6.png

 

For the hex notation for the FormID try prefixing with '0x':

 

0x13B569

Posted
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.

Posted
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.

Posted

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+.

Posted
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

 

Posted
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

Posted

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.

Posted (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 by Fraying9981

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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