Jump to content

Recommended Posts

Posted (edited)
1 hour ago, Fraying9981 said:

 

Thank you for following up and clarifying. I didnt know about actor specific variables but that is exactly what im looking for. No need to have persistent storage.

 

Do you think its possible to do the following?

- use actor specific variables e.g. hextun's height, weight

- use one variable to store the last skyrim udpated time for these variables. For example tirdas 2 at 4pm or whatever skyrim game time format is easy and standard here

- when we have a sl event, update the value e.g. weight + 200kg

- in parallel we have a top of the hour that reduces hextun weight by 1 kg every hour. Question for that is: how does it go through each values?

1. Can we perhaps name these variables so that slt can loop through all of them every hour?

2. Or, simply if we have a top of the hour trigger on every actor, it calls their weight and does -1

 

Is this doable this way?

 

For each statistic tracked, instead of using a target scoped variable, use a global list variable.

 

Each time you encounter an actor, you will check for one single target scoped variable, an index.

 

If a new actor is encountered, for each statistic list, append a new entry, the default value for that statistic. Get the max index for the statistic and set a target scoped variable with that value.

 

Then when you need to access (read/write) a statistic value you will:
- Fetch the target scoped variable value containing the actor's index.
- Access the global scoped list for the given statistic of interest, using the fetched index.

 

Initialization (I suggest you run something like this via the New Session trigger):

; check to see if the global lists are setup
; all of these lists will have the same number of elements because we are tracking the same stats for each actor
; so an actor's index is the same index into each list
typeid $global.stat_height
if $$ == 0
    ; missing, init all global lists
    Form[] $global.stat_actor_list ; for later reference if needed ; truly you can skip this if you want, just adding for possible convenience use later
    string[] $global.stat_actor_name ; as a shortcut ; truly you can skip this if you want, just adding for possible convenience use later
    float[] $global.stat_height
    float[] $global.stat_weight
    int[] $global.stat_whatever
endif

 

New Actor Encountered:

set $index_typeid resultfrom typeid $target.stat_index
if $index_typeid == 0
    listadd $global.stat_actor_list $system.self
    set $aValue resultfrom actor_name $system.self
    listadd $global.stat_actor_name $aValue
    set $aValue resultfrom actorbase_dogetter $system.self GetHeight
    listadd $global.stat_height $aValue
    set $aValue resultfrom actorbase_dogetter $system.self GetWeight
    listadd $global.stat_weight $aValue
    listadd $global.stat_whatever 42 ; or whatever
    
    set $aValue resultfrom listcount $global.stat_height
    inc $aValue -1 ; 0-based index, decrement for actual last index
    set $target.stat_index $aValue
endif


Access Statistic Value:

set $weight $global.stat_weight[$target.stat_index]
inc $weight 200
set $global.stat_weight[$target.stat_index] $weight
; ALTERNATIVELY, YOU COULD PROBABLY JUST DO THIS
inc $global.stat_weight[$target.stat_index] 200

Iterate and Update All Known Actor Statistics:
set $count resultfrom listcount $global.stat_height
set $index 0
while $index < $count
    set $aValue $global.stat_height[$index]
    ; do something?
    inc $aValue -1
    set $global.stat_weight[$index] $aValue
    
    ; ALTERNATIVELY, YOU COULD PROBABLY JUST DO THIS
    inc $global.stat_weight[$index] -1

    ; need this
    inc $index 1
endwhile

 

Note that I'm taking the count of $global.stat_height even though I'm actually using $global.stat_weight values. That's perfectly fine since all the lists should be the same length anyway.

Edited by hextun
Posted
2 hours ago, hextun said:

 

For each statistic tracked, instead of using a target scoped variable, use a global list variable.

 

Each time you encounter an actor, you will check for one single target scoped variable, an index.

 

If a new actor is encountered, for each statistic list, append a new entry, the default value for that statistic. Get the max index for the statistic and set a target scoped variable with that value.

 

Then when you need to access (read/write) a statistic value you will:
- Fetch the target scoped variable value containing the actor's index.
- Access the global scoped list for the given statistic of interest, using the fetched index.

 

Initialization (I suggest you run something like this via the New Session trigger):

; check to see if the global lists are setup
; all of these lists will have the same number of elements because we are tracking the same stats for each actor
; so an actor's index is the same index into each list
typeid $global.stat_height
if $$ == 0
    ; missing, init all global lists
    Form[] $global.stat_actor_list ; for later reference if needed ; truly you can skip this if you want, just adding for possible convenience use later
    string[] $global.stat_actor_name ; as a shortcut ; truly you can skip this if you want, just adding for possible convenience use later
    float[] $global.stat_height
    float[] $global.stat_weight
    int[] $global.stat_whatever
endif

 

New Actor Encountered:

set $index_typeid resultfrom typeid $target.stat_index
if $index_typeid == 0
    listadd $global.stat_actor_list $system.self
    set $aValue resultfrom actor_name $system.self
    listadd $global.stat_actor_name $aValue
    set $aValue resultfrom actorbase_dogetter $system.self GetHeight
    listadd $global.stat_height $aValue
    set $aValue resultfrom actorbase_dogetter $system.self GetWeight
    listadd $global.stat_weight $aValue
    listadd $global.stat_whatever 42 ; or whatever
    
    set $aValue resultfrom listcount $global.stat_height
    inc $aValue -1 ; 0-based index, decrement for actual last index
    set $target.stat_index $aValue
endif


Access Statistic Value:

set $weight $global.stat_weight[$target.stat_index]
inc $weight 200
set $global.stat_weight[$target.stat_index] $weight
; ALTERNATIVELY, YOU COULD PROBABLY JUST DO THIS
inc $global.stat_weight[$target.stat_index] 200

Iterate and Update All Known Actor Statistics:
set $count resultfrom listcount $global.stat_height
set $index 0
while $index < $count
    set $aValue $global.stat_height[$index]
    ; do something?
    inc $aValue -1
    set $global.stat_weight[$index] $aValue
    
    ; ALTERNATIVELY, YOU COULD PROBABLY JUST DO THIS
    inc $global.stat_weight[$index] -1

    ; need this
    inc $index 1
endwhile

 

Note that I'm taking the count of $global.stat_height even though I'm actually using $global.stat_weight values. That's perfectly fine since all the lists should be the same length anyway.

 

Ah thanks so effectively are you creating one giant list per variable? And each element of the list is an actor? = a list of weights made of actors

 

Is this an approach that excludes what you may have alluded to earlier = the variable weight is stored on each actor?

Posted
5 hours ago, Fraying9981 said:

 

Ah thanks so effectively are you creating one giant list per variable? And each element of the list is an actor? = a list of weights made of actors

 

Is this an approach that excludes what you may have alluded to earlier = the variable weight is stored on each actor?

 

So, yes, you understand what I was suggesting. However, upon further consideration, I think there is a still better way.

 

The approach below uses a single global list containing your tracked actors ($global.stat_actor_list), a special target scoped variable that contains an actors index position in that list and also serves to indicate whether that actor is being tracked ($target.stat_index), and then uses target scoped variables on the actor for each stat tracked.

 

If a new actor is encountered, append a new entry to the actor list. Get the max index for the statistic and set $target.stat_index with that value. You can preset default values for your statistics at this point if you would like.

 

Then when you need to access (read/write) a statistic value you can just use the target scoped variables directly, no need for the index lookup. Iterating will, however, involve iterating the actor list and then accessing the variables.

 

Initialization (I suggest you run something like this via the New Session trigger):

; check to see if the global actor list is setup
typeid $global.stat_actor_list
if $$ == 0
    ; missing, init the global actor list
    Form[] $global.stat_actor_list
endif

 

New Actor Encountered:

set $index_typeid resultfrom typeid $target.stat_index
if $index_typeid == 0
    listadd $global.stat_actor_list $system.self
    
    set $aValue resultfrom listcount $global.stat_actor_list
    inc $aValue -1 ; 0-based index, decrement for actual last index
    set $target.stat_index $aValue
    
    set $target.stat_height resultfrom actorbase_dogetter $system.self GetHeight
    set $target.stat_weight resultfrom actorbase_dogetter $system.self GetWeight
endif

 

Access Statistic Value:

inc $target.stat_weight 200


Iterate and Update All Known Actor Statistics:

set $count resultfrom listcount $global.stat_actor_list
set $index 0
while $index < $count
    set $anActor $global.stat_actor_list[$index]
    inc $target<$anActor>.stat_weight -1

    ; need this
    inc $index 1
endwhile

 

This lets you work with the stats more naturally, tied to the actors in a more intuitive way as originally intended.

 

The global actor list then becomes the main method you use to know what actors you are aware of. The $target.stat_index value is primarily used to know whether the actor is being tracked and thus whether to be added to the list and initialized.

 

Something to keep in mind though... the list will just get bigger as you add more actors. The size isn't a problem in terms of memory or anything, but the iteration will just take longer as time goes by. 

 

Also, the top of the hour trigger is just an in-game 1 hour timer, which IIRC translates to roughly 3 minutes real time. It shouldn't ever be longer and may be shorter (i.e. if you travel or sleep). Depending on your need you may prefer a regular timer trigger.

Posted
46 minutes ago, Fraying9981 said:

 

Thanks, is this an actual trigger?

It is (to my knowledge; I haven't tested it though) a functional SLTScript that, if run against an actor, should do the appropriate setup to start tracking them. 
 

I don't know at what point you would want to start tracking an actor though, so I don't know which trigger you want to run this script. 

Posted
18 minutes ago, hextun said:

It is (to my knowledge; I haven't tested it though) a functional SLTScript that, if run against an actor, should do the appropriate setup to start tracking them. 
 

I don't know at what point you would want to start tracking an actor though, so I don't know which trigger you want to run this script. 

 

thanks its okay im using a keystroke to register actors 1 by 1.

testing right now

Posted

@hextun see below my functions and report on my implementation try. gametime doesnt seem to be stored correctly is the current issue i'm facing.

 

btw interestingly, the init script to initialize the list doesn't seem to be necessary. 

 

## Result
- Actor registered successfully (Index: 0)
- Gametime value stored: `15.054491`
- On re-check: `typeid = 0`, value empty

## Issue
`set $target<$targetActor>.trk_last_updated $currentTime` silently fails. The `set` command does NOT support dynamic target syntax `$target<$var>.name`. Value appears to write but is never stored.


 

 

Spoiler

init script

Spoiler
; Tracking System Init v1b - Initialize global list (NEW approach)
msg_notify "tracking_init: Starting initialization"
 
; Debug: show gametime format
msg_notify "tracking_init: gametime format = " $system.gametime
deb_msg "TRACKING_DEBUG gametime=" $system.gametime
 
; Check if global list is already setup
typeid $global.trk_actor_list
if $$ == 0
    ; First time - initialize ONLY the actor list
    msg_notify "tracking_init: Creating global tracking list"
    Form[] $global.trk_actor_list
    msg_notify "tracking_init: Global list created successfully"
    deb_msg "TRACKING_DEBUG list_created: trk_actor_list"
else
    msg_notify "tracking_init: Global list already exists"
endif
 
msg_notify "tracking_init: Initialization complete"
return

 

register script

Spoiler
; Tracking System Register Keystroke v1d - Register crosshair target via 'N' key
msg_notify "tracking_register_key: Checking crosshair target"
 
; Get the actor in crosshair
set $targetActor resultfrom game_dogetter GetCurrentCrosshairRef
 
; Validate it's an actor
set $isValid resultfrom actor_isvalid $targetActor
if $isValid == false
    msg_notify "tracking_register_key: No valid actor in crosshair"
    return
endif
 
; Skip the player
set $isPlayer resultfrom actor_isplayer $targetActor
if $isPlayer == true
    msg_notify "tracking_register_key: SKIPPED (player)"
    return
endif
 
; Check if already registered by iterating the list
set $count resultfrom listcount $global.trk_actor_list
set $index 0
while $index < $count
    set $listActor $global.trk_actor_list[$index]
    if $listActor == $targetActor
        ; Found - already registered, display values
        actor_name $targetActor
        set $actorName $$
        msg_notify "=== " $actorName " (Index: " $index ") ==="
 
        ; DEBUG: Check if trk_last_updated exists
        set $hasLastUpdated resultfrom typeid $target<$targetActor>.trk_last_updated
        msg_notify "DEBUG: typeid of trk_last_updated = " $hasLastUpdated
 
        ; DEBUG: Try to read the value
        set $lastUpd $target<$targetActor>.trk_last_updated
        msg_notify "DEBUG: raw value = |" $lastUpd "|"
 
        msg_notify "Last Updated: |" $target<$targetActor>.trk_last_updated "|"
 
        ; Check for wear values (Phase 2 - may not exist yet)
        set $analWear resultfrom typeid $target<$targetActor>.trk_anal_wear
        if $analWear != 0
            msg_notify "Anal Wear: |" $target<$targetActor>.trk_anal_wear "|"
        endif
        set $vaginalWear resultfrom typeid $target<$targetActor>.trk_vaginal_wear
        if $vaginalWear != 0
            msg_notify "Vaginal Wear: |" $target<$targetActor>.trk_vaginal_wear "|"
        endif
        set $oralWear resultfrom typeid $target<$targetActor>.trk_oral_wear
        if $oralWear != 0
            msg_notify "Oral Wear: |" $target<$targetActor>.trk_oral_wear "|"
        endif
        return
    endif
    inc $index 1
endwhile
 
; Guard rail: unique NPCs only
set $isUnique resultfrom actorbase_dogetter $targetActor IsUnique
if $isUnique == false
    actor_name $targetActor
    msg_notify "tracking_register_key: SKIPPED (non-unique): " $$
    return
endif
 
; Register the actor
actor_name $targetActor
set $actorName $$
msg_notify "tracking_register_key: Registering: " $actorName
 
; Add to global list
listadd $global.trk_actor_list $targetActor
 
; Store index on actor
set $aValue resultfrom listcount $global.trk_actor_list
inc $aValue -1
set $target<$targetActor>.trk_index $aValue
 
; Store gametime
set $currentTime $system.gametime
set $target<$targetActor>.trk_last_updated $currentTime
 
; Debug output
msg_notify "tracking_register_key: Stored gametime = |" $currentTime "|"
msg_notify "tracking_register_key: Registered! Index: " $aValue
 
return

 

log excerpt

Spoiler

[2026-03-04 00:05:12.409] SLTR:(_tracking_register_keystrokev1d.sltscript)[2]: tracking_register_key: Checking crosshair target
[2026-03-04 00:05:13.752] [error] SLTR:(_tracking_register_keystrokev1d.sltscript)[22]: invalid target for listcount: varscope((SCOPE[Global] / NAME[trk_actor_list])); type(<invalid RT type: 0>)
[2026-03-04 00:05:15.069] SLTR:(_tracking_register_keystrokev1d.sltscript)[71]: tracking_register_key: Registering: Tekla
[2026-03-04 00:05:15.653] SLTR:(_tracking_register_keystrokev1d.sltscript)[86]: tracking_register_key: Stored gametime = |15.054491|
[2026-03-04 00:05:15.869] SLTR:(_tracking_register_keystrokev1d.sltscript)[87]: tracking_register_key: Registered! Index: 0
[2026-03-04 00:05:43.185] SLTR:(_tracking_register_keystrokev1d.sltscript)[30]: === Tekla (Index: 0) ===
[2026-03-04 00:05:43.404] SLTR:(_tracking_register_keystrokev1d.sltscript)[34]: DEBUG: typeid of trk_last_updated = 0
[2026-03-04 00:05:43.574] SLTR:(_tracking_register_keystrokev1d.sltscript)[38]: DEBUG: raw value = ||
[2026-03-04 00:05:43.696] SLTR:(_tracking_register_keystrokev1d.sltscript)[40]: Last Updated: ||
 

 

 

Posted
8 hours ago, Fraying9981 said:

@hextun see below my functions and report on my implementation try. gametime doesnt seem to be stored correctly is the current issue i'm facing.

 

btw interestingly, the init script to initialize the list doesn't seem to be necessary. 

 

## Result
- Actor registered successfully (Index: 0)
- Gametime value stored: `15.054491`
- On re-check: `typeid = 0`, value empty

## Issue
`set $target<$targetActor>.trk_last_updated $currentTime` silently fails. The `set` command does NOT support dynamic target syntax `$target<$var>.name`. Value appears to write but is never stored.


 

 

  Reveal hidden contents

init script

  Reveal hidden contents
; Tracking System Init v1b - Initialize global list (NEW approach)
msg_notify "tracking_init: Starting initialization"
 
; Debug: show gametime format
msg_notify "tracking_init: gametime format = " $system.gametime
deb_msg "TRACKING_DEBUG gametime=" $system.gametime
 
; Check if global list is already setup
typeid $global.trk_actor_list
if $$ == 0
    ; First time - initialize ONLY the actor list
    msg_notify "tracking_init: Creating global tracking list"
    Form[] $global.trk_actor_list
    msg_notify "tracking_init: Global list created successfully"
    deb_msg "TRACKING_DEBUG list_created: trk_actor_list"
else
    msg_notify "tracking_init: Global list already exists"
endif
 
msg_notify "tracking_init: Initialization complete"
return

 

register script

  Reveal hidden contents
; Tracking System Register Keystroke v1d - Register crosshair target via 'N' key
msg_notify "tracking_register_key: Checking crosshair target"
 
; Get the actor in crosshair
set $targetActor resultfrom game_dogetter GetCurrentCrosshairRef
 
; Validate it's an actor
set $isValid resultfrom actor_isvalid $targetActor
if $isValid == false
    msg_notify "tracking_register_key: No valid actor in crosshair"
    return
endif
 
; Skip the player
set $isPlayer resultfrom actor_isplayer $targetActor
if $isPlayer == true
    msg_notify "tracking_register_key: SKIPPED (player)"
    return
endif
 
; Check if already registered by iterating the list
set $count resultfrom listcount $global.trk_actor_list
set $index 0
while $index < $count
    set $listActor $global.trk_actor_list[$index]
    if $listActor == $targetActor
        ; Found - already registered, display values
        actor_name $targetActor
        set $actorName $$
        msg_notify "=== " $actorName " (Index: " $index ") ==="
 
        ; DEBUG: Check if trk_last_updated exists
        set $hasLastUpdated resultfrom typeid $target<$targetActor>.trk_last_updated
        msg_notify "DEBUG: typeid of trk_last_updated = " $hasLastUpdated
 
        ; DEBUG: Try to read the value
        set $lastUpd $target<$targetActor>.trk_last_updated
        msg_notify "DEBUG: raw value = |" $lastUpd "|"
 
        msg_notify "Last Updated: |" $target<$targetActor>.trk_last_updated "|"
 
        ; Check for wear values (Phase 2 - may not exist yet)
        set $analWear resultfrom typeid $target<$targetActor>.trk_anal_wear
        if $analWear != 0
            msg_notify "Anal Wear: |" $target<$targetActor>.trk_anal_wear "|"
        endif
        set $vaginalWear resultfrom typeid $target<$targetActor>.trk_vaginal_wear
        if $vaginalWear != 0
            msg_notify "Vaginal Wear: |" $target<$targetActor>.trk_vaginal_wear "|"
        endif
        set $oralWear resultfrom typeid $target<$targetActor>.trk_oral_wear
        if $oralWear != 0
            msg_notify "Oral Wear: |" $target<$targetActor>.trk_oral_wear "|"
        endif
        return
    endif
    inc $index 1
endwhile
 
; Guard rail: unique NPCs only
set $isUnique resultfrom actorbase_dogetter $targetActor IsUnique
if $isUnique == false
    actor_name $targetActor
    msg_notify "tracking_register_key: SKIPPED (non-unique): " $$
    return
endif
 
; Register the actor
actor_name $targetActor
set $actorName $$
msg_notify "tracking_register_key: Registering: " $actorName
 
; Add to global list
listadd $global.trk_actor_list $targetActor
 
; Store index on actor
set $aValue resultfrom listcount $global.trk_actor_list
inc $aValue -1
set $target<$targetActor>.trk_index $aValue
 
; Store gametime
set $currentTime $system.gametime
set $target<$targetActor>.trk_last_updated $currentTime
 
; Debug output
msg_notify "tracking_register_key: Stored gametime = |" $currentTime "|"
msg_notify "tracking_register_key: Registered! Index: " $aValue
 
return

 

log excerpt

  Reveal hidden contents

[2026-03-04 00:05:12.409] SLTR:(_tracking_register_keystrokev1d.sltscript)[2]: tracking_register_key: Checking crosshair target
[2026-03-04 00:05:13.752] [error] SLTR:(_tracking_register_keystrokev1d.sltscript)[22]: invalid target for listcount: varscope((SCOPE[Global] / NAME[trk_actor_list])); type(<invalid RT type: 0>)
[2026-03-04 00:05:15.069] SLTR:(_tracking_register_keystrokev1d.sltscript)[71]: tracking_register_key: Registering: Tekla
[2026-03-04 00:05:15.653] SLTR:(_tracking_register_keystrokev1d.sltscript)[86]: tracking_register_key: Stored gametime = |15.054491|
[2026-03-04 00:05:15.869] SLTR:(_tracking_register_keystrokev1d.sltscript)[87]: tracking_register_key: Registered! Index: 0
[2026-03-04 00:05:43.185] SLTR:(_tracking_register_keystrokev1d.sltscript)[30]: === Tekla (Index: 0) ===
[2026-03-04 00:05:43.404] SLTR:(_tracking_register_keystrokev1d.sltscript)[34]: DEBUG: typeid of trk_last_updated = 0
[2026-03-04 00:05:43.574] SLTR:(_tracking_register_keystrokev1d.sltscript)[38]: DEBUG: raw value = ||
[2026-03-04 00:05:43.696] SLTR:(_tracking_register_keystrokev1d.sltscript)[40]: Last Updated: ||
 

 

 

 

I think I got my own syntax wrong. Can you try this syntax for the target scoping:

 

set $target<targetActor>.trk_last_updated $currentTime

 

Basically, remove the '$' variable prefix from within the <> for actor selection. I tried a simple test script which seems to confirm the syntax issue. Sorry about that. :)

 

Posted (edited)
6 hours ago, hextun said:

 

I think I got my own syntax wrong. Can you try this syntax for the target scoping:

 

set $target<targetActor>.trk_last_updated $currentTime

 

Basically, remove the '$' variable prefix from within the <> for actor selection. I tried a simple test script which seems to confirm the syntax issue. Sorry about that. :)

 

 

Thanks, still doesnt work. I'm going to try parallelized lists.

See report below

 

Spoiler
# Dynamic Target Scope Issue - Data Not Persisting Between Script Executions
 
## Problem
Using `$target<variableName>` syntax to store data on actors dynamically. Data writes successfully and is readable **within the same script execution**, but **does not persist** to subsequent script executions.
 
## Test Code
 
```sltscript
; Key parts of the test script _tracking_register_keystrokev1f.sltscript
 
; Get actor from crosshair
set $targetActor resultfrom game_dogetter GetCurrentCrosshairRef
 
; Write to target-scoped variables (no $ inside <>)
set $target<targetActor>.trk_index $aValue
set $target<targetActor>.trk_last_updated $currentTime
set $target<targetActor>.trk_x $currentTime
 
; IMMEDIATE typeid check
set $typeid_after1 resultfrom typeid $target<targetActor>.trk_last_updated
set $typeid_after2 resultfrom typeid $target<targetActor>.trk_x
deb_msg "IMMEDIATE typeid after write: last_updated=" $typeid_after1 " trk_x=" $typeid_after2
 
; IMMEDIATE read
set $imm1 $target<targetActor>.trk_last_updated
set $imm2 $target<targetActor>.trk_x
deb_msg "IMMEDIATE read: last_updated=" $imm1 " trk_x=" $imm2
```
 
## Log Evidence
 
**First execution (registration):**
```
[15:24:39] DebMsg> DEBUG_V1F currentTime=15.057133
[15:24:39] DebMsg> DEBUG_V1F Wrote trk_last_updated via set
[15:24:39] DebMsg> DEBUG_V1F Wrote trk_x via set
[15:24:40] DebMsg> DEBUG_V1F IMMEDIATE typeid after write: last_updated=4 trk_x=4 trk_index=3 trk_test=3
[15:24:40] DebMsg> DEBUG_V1F IMMEDIATE read: last_updated=15.057133 trk_x=15.057133 trk_index=0 trk_test=1
```
✓ typeid returns non-zero (4=float, 3=int)
✓ Values are readable immediately after write
 
**Second execution (same actor, 30 seconds later):**
```
[15:25:09] DebMsg> DEBUG_V1F BEFORE WRITE typeid: last_updated=0 trk_x=0 trk_index=0
[15:25:11] DebMsg> DEBUG_V1F READ typeid: last_updated=0 trk_x=0 trk_index=0
[15:25:11] DebMsg> DEBUG_V1F READ via set: last_updated= trk_x= trk_index=
```
✗ typeid returns 0 for all variables
✗ Values are empty
 
## What We Tried
 
| Attempt | Result |
|---------|--------|
| `$target<$targetActor>.var` (with $) | Error/doesn't work |
| `$target<targetActor>.var` (no $) | Writes but doesn't persist |
| Short variable name `trk_x` | Same issue |
| Using `inc` instead of `set` | Same issue |
 
## Conclusion
 
The `$target<varname>` syntax appears to write to a **temporary scope** that exists only within the current script execution. When the script ends, that scope is destroyed and the data is lost.
 
This prevents using the "NEW approach" from the guidelines (target-scoped variables with dynamic actor selection) for any data that needs to persist.
 
## Expected Behavior
 
Data written via `$target<actorVar>.propertyName` should persist on that actor's target scope and be readable in subsequent script executions when accessing the same actor.
 
## Workaround
 
Currently falling back to OLD approach using parallel global arrays instead of target-scoped variables.

 

Edit:  parallelized lists (your first idea) works on 1 NPC. I will continue working on that

 

Edited by Fraying9981
Posted
19 hours ago, Fraying9981 said:

 

Thanks, still doesnt work. I'm going to try parallelized lists.

See report below

 

  Hide contents
# Dynamic Target Scope Issue - Data Not Persisting Between Script Executions
 
## Problem
Using `$target<variableName>` syntax to store data on actors dynamically. Data writes successfully and is readable **within the same script execution**, but **does not persist** to subsequent script executions.
 
## Test Code
 
```sltscript
; Key parts of the test script _tracking_register_keystrokev1f.sltscript
 
; Get actor from crosshair
set $targetActor resultfrom game_dogetter GetCurrentCrosshairRef
 
; Write to target-scoped variables (no $ inside <>)
set $target<targetActor>.trk_index $aValue
set $target<targetActor>.trk_last_updated $currentTime
set $target<targetActor>.trk_x $currentTime
 
; IMMEDIATE typeid check
set $typeid_after1 resultfrom typeid $target<targetActor>.trk_last_updated
set $typeid_after2 resultfrom typeid $target<targetActor>.trk_x
deb_msg "IMMEDIATE typeid after write: last_updated=" $typeid_after1 " trk_x=" $typeid_after2
 
; IMMEDIATE read
set $imm1 $target<targetActor>.trk_last_updated
set $imm2 $target<targetActor>.trk_x
deb_msg "IMMEDIATE read: last_updated=" $imm1 " trk_x=" $imm2
```
 
## Log Evidence
 
**First execution (registration):**
```
[15:24:39] DebMsg> DEBUG_V1F currentTime=15.057133
[15:24:39] DebMsg> DEBUG_V1F Wrote trk_last_updated via set
[15:24:39] DebMsg> DEBUG_V1F Wrote trk_x via set
[15:24:40] DebMsg> DEBUG_V1F IMMEDIATE typeid after write: last_updated=4 trk_x=4 trk_index=3 trk_test=3
[15:24:40] DebMsg> DEBUG_V1F IMMEDIATE read: last_updated=15.057133 trk_x=15.057133 trk_index=0 trk_test=1
```
✓ typeid returns non-zero (4=float, 3=int)
✓ Values are readable immediately after write
 
**Second execution (same actor, 30 seconds later):**
```
[15:25:09] DebMsg> DEBUG_V1F BEFORE WRITE typeid: last_updated=0 trk_x=0 trk_index=0
[15:25:11] DebMsg> DEBUG_V1F READ typeid: last_updated=0 trk_x=0 trk_index=0
[15:25:11] DebMsg> DEBUG_V1F READ via set: last_updated= trk_x= trk_index=
```
✗ typeid returns 0 for all variables
✗ Values are empty
 
## What We Tried
 
| Attempt | Result |
|---------|--------|
| `$target<$targetActor>.var` (with $) | Error/doesn't work |
| `$target<targetActor>.var` (no $) | Writes but doesn't persist |
| Short variable name `trk_x` | Same issue |
| Using `inc` instead of `set` | Same issue |
 
## Conclusion
 
The `$target<varname>` syntax appears to write to a **temporary scope** that exists only within the current script execution. When the script ends, that scope is destroyed and the data is lost.
 
This prevents using the "NEW approach" from the guidelines (target-scoped variables with dynamic actor selection) for any data that needs to persist.
 
## Expected Behavior
 
Data written via `$target<actorVar>.propertyName` should persist on that actor's target scope and be readable in subsequent script executions when accessing the same actor.
 
## Workaround
 
Currently falling back to OLD approach using parallel global arrays instead of target-scoped variables.

 

Edit:  parallelized lists (your first idea) works on 1 NPC. I will continue working on that

 

 

So welcome to this edition of "Hextun is a Massive Idiot".

 

*ahem*

 

The syntax is:

 

$target.<some_actor_var>.your_target_var (note the bolded periods, both before and after the <> brackets) ((yes, I bolded them because I am a massive idiot)).

 

You can also use a global var in there:

 

$target.<global.some_global_actor_var>.your_target_var (note I did not bold the periods that time, even though I am still a massive idiot)

 

Note further that the online documentation and that contained in the mod is WRONG, but the test scripts are CORRECT. Yay for being a massive idiot.

 

I will update the online docs but they obviously won't be corrected in the mod itself until the next release.

 

Oh... and because I was leading you so very far astray, it was not seeing a scope of "target" but instead an attempted scope of "target<the_var_or_whatever_you_named_your_actor_var>", which is not valid, and thus, indeed, makes it local scoped.

 

So very sorry.

Posted
3 minutes ago, hextun said:

 

So welcome to this edition of "Hextun is a Massive Idiot".

 

*ahem*

 

The syntax is:

 

$target.<some_actor_var>.your_target_var (note the bolded periods, both before and after the <> brackets) ((yes, I bolded them because I am a massive idiot)).

 

You can also use a global var in there:

 

$target.<global.some_global_actor_var>.your_target_var (note I did not bold the periods that time, even though I am still a massive idiot)

 

Note further that the online documentation and that contained in the mod is WRONG, but the test scripts are CORRECT. Yay for being a massive idiot.

 

I will update the online docs but they obviously won't be corrected in the mod itself until the next release.

 

Oh... and because I was leading you so very far astray, it was not seeing a scope of "target" but instead an attempted scope of "target<the_var_or_whatever_you_named_your_actor_var>", which is not valid, and thus, indeed, makes it local scoped.

 

So very sorry.

 

no problem at all!
i got the system i wanted working (implemented with your first method):

  • a list of actors
  • i can add actors manually with a keystroke (so as not to overload the game + i don't need a sex scene to necessarily register them)
  • every hour my scripts update their stats
  • sex scenes also update their stats

The only think I'm missing now is the following:

  • I want to track dd usage for the NPC over time. For example if they wear a plug for too long: not good
  • The issue, ofc, is this needs to be updated every hour (top of the hour) and if the actor is not loaded, then we don't know if they are wearing the plug right?
  • So my initial idea was to add a DD equip/unequip detect script to register in my table for each NPC whether they are wearing device X or not (boolean)
  • The issue is that only player equip trigger is available. I don't see NPC equip trigger in the MCM

=> Would you have a suggestion as to how to do this?

 

 

I also had another question: can SL trigger realistically alter bodymorphs permanently for a character? If so, how?

for example: handjob sex => twisted wrist :D

I would want to add this to my NPC tracking: updated bodymorphs.

I'm using CBBE 3BA body.

Posted
11 hours ago, Fraying9981 said:

 

no problem at all!
i got the system i wanted working (implemented with your first method):

  • a list of actors
  • i can add actors manually with a keystroke (so as not to overload the game + i don't need a sex scene to necessarily register them)
  • every hour my scripts update their stats
  • sex scenes also update their stats

The only think I'm missing now is the following:

  • I want to track dd usage for the NPC over time. For example if they wear a plug for too long: not good
  • The issue, ofc, is this needs to be updated every hour (top of the hour) and if the actor is not loaded, then we don't know if they are wearing the plug right?
  • So my initial idea was to add a DD equip/unequip detect script to register in my table for each NPC whether they are wearing device X or not (boolean)
  • The issue is that only player equip trigger is available. I don't see NPC equip trigger in the MCM

=> Would you have a suggestion as to how to do this?

 

 

I also had another question: can SL trigger realistically alter bodymorphs permanently for a character? If so, how?

for example: handjob sex => twisted wrist :D

I would want to add this to my NPC tracking: updated bodymorphs.

I'm using CBBE 3BA body.

DD detection:

You're right, I am only handling player equip events. I am using the TESEquipEvent event sink in the SKSE plugin, which in fact runs for all actors, not just the player. I just happen to be filtering for the player exclusively.

 

I hadn't considered the need to check all NPCs. The problem with using this approach in your specific case is that there would be no good way to filter for only the actors you are interested in, or to filter only for devious device equipment; your script would end up running for all actors, for any gear, and you would need to check what was being equipped/unequipped each time. Maybe that wouldn't be a problem? I don't know; I'm not sure how frequently equip events actually occur (like do they happen when outfits are applied?). Maybe this could actually be performant, though it would require a broadening of the trigger to include non-players.

 

I don't see any indication of an event I could capture for when specifically DD are applied/removed either.

 

There are DD lib functions for checking if someone is bound, or is wearing something of a specific type e.g. collar, harness, and so on, but I have not implemented those bindings. Simple enough to do I suppose. Probably about time to revisit and expand those bindings since I only have two functions bound. Still, I'm still not sure if this would be what you want as you presumably would need to check each actor for if they are wearing any of a number of types of items, depending on what sorts of stats you are planning to collect.

 

I think there are some special keywords you can check for on your armor, something like zad_lockable I think? To see if someone is wearing anything lockable in a given armor slots. Vague recollection of that and having asked about it on the DD Discord at some point.

 

Actor Being Not Loaded:

Since I've rediscovered and recommunicated the correct dynamic target scope syntax :P if you switched to the "new" approach, with a list of actors and variables directly on an actor, you could perhaps iterate that list and check actor_haslos with $self.player; it would not monitor actors not actually in los of the player, but would definitely let you know if an actor is currently loaded.

 

I also have a function in use, InSameCell(), which returns true if the given actor is in the same cell as the player, a reasonable and reasonably fast check. It is not bound and available in SLTScript but would be an easy add.

 

Updated Bodymorphs (e.g. twisted wrist):
So, the only stuff I've done has been the NiOverride (nio_* and other functions) related bindings, and I believe that's just working with the sliders already available (i.e. make something bigger or smaller). What you're talking about, twisting a wrist, sounds .. not like that. :) I want to say something more akin to IK (inverse kinematics) or something; in any case, I have no bindings like what you are talking about and I'm not familiar with anything that exposes that functional interface.

 

Back to the DD Handling:
I can investigate how busy opening up the equip trigger to non-players gets. I'm not sure how else to do what you want reasonably. util_scan_cell_npcs isn't particularly fast, and you would end up having to scan every NPC in a cell to find anyone you want to track. That would be a terrible, horrible, no good, very bad approach. Other options might be overly constrained, especially by available bindings. :/

 

If you did that, then when an item is equipped, you could set a variable to hold the in-game time, along with perhaps a reference counter, adding 1 for each DD equip and subtracting 1 for each DD unequip, to make sure that you are accumulating any time you wear any DD equipment. So during the loop, for a given actor, only accrue time if the reference counter is greater than 0.

 

But yeah, the trick is catching those edge (equip/unequip DD) events. I'll look into that.

 

In the meantime, the short answer is "right now, I don't know of a convenient approach off the top of my head without adding global equip triggering".

Posted
8 hours ago, hextun said:

I hadn't considered the need to check all NPCs. The problem with using this approach in your specific case is that there would be no good way to filter for only the actors you are interested in, or to filter only for devious device equipment; your script would end up running for all actors, for any gear, and you would need to check what was being equipped/unequipped each time. Maybe that wouldn't be a problem? I don't know; I'm not sure how frequently equip events actually occur (like do they happen when outfits are applied?). Maybe this could actually be performant, though it would require a broadening of the trigger to include non-players.

 

 

Thanks. yeah that sounds like serious scripting, performance would probably tank.

 

8 hours ago, hextun said:

I think there are some special keywords you can check for on your armor, something like zad_lockable I think? To see if someone is wearing anything lockable in a given armor slots. Vague recollection of that and having asked about it on the DD Discord at some point.

 

 

yes, keywords are not an issue, it's the easy part.

 

8 hours ago, hextun said:

Since I've rediscovered and recommunicated the correct dynamic target scope syntax :P if you switched to the "new" approach, with a list of actors and variables directly on an actor, you could perhaps iterate that list and check actor_haslos with $self.player; it would not monitor actors not actually in los of the player, but would definitely let you know if an actor is currently loaded.

 

 

thanks I'm trying to do the opposite: process NPCs that are not loaded. because the purpose is to update NPCs stats over time, regardless if they are loaded or not. 
Which is why you list idea overall is amazing: it's just an array that lives in the SKSE cosave and manages records, no matter if the NPC is present or not. probably very lightweight.

 

8 hours ago, hextun said:

So, the only stuff I've done has been the NiOverride (nio_* and other functions) related bindings, and I believe that's just working with the sliders already available (i.e. make something bigger or smaller). What you're talking about, twisting a wrist, sounds .. not like that. :) I want to say something more akin to IK (inverse kinematics) or something; in any case, I have no bindings like what you are talking about and I'm not familiar with anything that exposes that functional interface.

 

 

haah sorry bad example, i'm not familiar with body change logic that much my example was wrong.
Let's say increase breast size: can you do this with Nioverride/SL triggers? Does this conflict with other mods such as Obody that defines body shapes? 

 

8 hours ago, hextun said:

I can investigate how busy opening up the equip trigger to non-players gets. I'm not sure how else to do what you want reasonably. util_scan_cell_npcs isn't particularly fast, and you would end up having to scan every NPC in a cell to find anyone you want to track. That would be a terrible, horrible, no good, very bad approach. Other options might be overly constrained, especially by available bindings. :/

 

 

How about the following logic:

scan only the NPCs from the list we are tracking? = the top of the hour script has a function that scans ONLY the npcs on the list, checks if they have the DD keyword and thats it.

Would you be able to provide some code that works for that?

 

This would be a lightweight, good fallback: we lose the exact moment when they equip/unequip, but it's a minor piece of information because 1 hour in skyrim is very short anyway.

  • For loaded actors in the list: the script would see they have a DD equipped so would toggle "DD is equipped" on in our list (that the rest of our scripts can use)
  • For non loaded actors: the script would detect they are not loaded (perhaps with los that you recommended), then check if DD was equipped last time they were loaded -> if yes would maintain DD equipped
Posted
On 3/6/2026 at 6:25 AM, Fraying9981 said:

haah sorry bad example, i'm not familiar with body change logic that much my example was wrong.
Let's say increase breast size: can you do this with Nioverride/SL triggers? Does this conflict with other mods such as Obody that defines body shapes? 

 

 

How about the following logic:

scan only the NPCs from the list we are tracking? = the top of the hour script has a function that scans ONLY the npcs on the list, checks if they have the DD keyword and thats it.

Would you be able to provide some code that works for that?

 

This would be a lightweight, good fallback: we lose the exact moment when they equip/unequip, but it's a minor piece of information because 1 hour in skyrim is very short anyway.

  • For loaded actors in the list: the script would see they have a DD equipped so would toggle "DD is equipped" on in our list (that the rest of our scripts can use)
  • For non loaded actors: the script would detect they are not loaded (perhaps with los that you recommended), then check if DD was equipped last time they were loaded -> if yes would maintain DD equipped

 

Yup, the nioverride_* functions (https://github.com/sltriggersredux/sltriggersredux/wiki/Function-Libraries#nioverride) are the same ones used by OBody and such. The "morphName" parameters are what you expect: "Breasts", "Butt", and so on. The "keyName" is how it keeps tracks of who is doing what. So if two mods add 1.0 to "Breasts", each specifying a distinct "keyName", that will total 2.0 added. If they (for some reason) happened to use the same "keyName", the last one in would win; in this scenario it would lead to only a single 1.0 being added.

 

I'm actually in the process of moving right now, so time is a little tight for a bit. But to gather the info: when you say "check for the DD keyword", do you mean "check to see if any DD keywords exist on any of their worn items"? i.e. "are you wearing a collar? are you wearing wrist cuffs? are you wearing...?". Is there a specific subset of DD keywords you would want to check (maybe wrist and leg cuffs don't have any impact)? And for scanning "only the NPCs from the list", that would be easy enough; the concern becomes managing that list so that not too many entries are on it at one time, no? Or I guess you would want to iterate the whole list and only work with actors in LOS?

Posted
9 hours ago, hextun said:

"check for the DD keyword", do you mean "check to see if any DD keywords exist on any of their worn items"? i.e. "are you wearing a collar? are you wearing wrist cuffs? are you wearing...?". Is there a specific subset of DD keywords you would want to check (maybe wrist and leg cuffs don't have any impact)?

 

yes, I'm starting with plugs to keep it simple.

Ultimately I would want to track corset, collar, feet, belt, harness.

 

9 hours ago, hextun said:

And for scanning "only the NPCs from the list", that would be easy enough; the concern becomes managing that list so that not too many entries are on it at one time, no? Or I guess you would want to iterate the whole list and only work with actors in LOS?

 

Good point, yes we could just restrict the LOS.

my question on this and the reason I asked for code is that with my current system I know how to add NPCs to the list, and then call the array anytime to update it/access values (because it's ultimately an independent array that sits somewhere and the NPC name is the key).

so yeah top of the hour script workflow could look like this:

  • scan all nearby actors
  • see which ones are in our array
  • based on that, do they have DD equipped
  • if yes then adjust body morphs

 

But an even cleaner version would be:

  • scan all nearby actors
  • see which ones are in our array
  • if they have DD equipped: make sure the toggle for that specific device is on in the array
  • calculate when the DD was first detected - now = get the duration of equipment
  • based on that, adjust body morphs. this way we update values more closely to real time

 

9 hours ago, hextun said:

I'm actually in the process of moving right now

 

good luck with moving!

  • 2 weeks later...
Posted

Small question, in the documentation there is this:

 

### util_getgametime

**Description**

Returns: float: the value of Utility.GetCurrentGameTime() (a float value representing the number of days in game time; mid-day day 2 is 1.5)


**Example**

    util_getgametime  



### util_getgametime

**Description**

Returns: int: the in-game hour (i.e. 2:30 AM returns 2)


**Example**

    util_getgametime  


I'm guessing this is a typo since two functions seem to have the same name but different uses?

Posted
13 hours ago, just let me download said:

Small question, in the documentation there is this:

 

### util_getgametime

**Description**

Returns: float: the value of Utility.GetCurrentGameTime() (a float value representing the number of days in game time; mid-day day 2 is 1.5)


**Example**

    util_getgametime  



### util_getgametime

**Description**

Returns: int: the in-game hour (i.e. 2:30 AM returns 2)


**Example**

    util_getgametime  


I'm guessing this is a typo since two functions seem to have the same name but different uses?

 

Yup, good catch. The second one should be 'util_gethour' to get the in-game hour. Will be fixed next release in the included docs but I have updated the github wiki in the meantime. Thanks for reporting! :)

 

Posted

Ive tried looking through all the functions but cant seem to find a better way so thought i would ask.

Im trying to create a list of follower actors without using the NFF follower command (since i intend to make this more universal even tho the getnfffollower function works great wheng using nff, which i do.)

currently this is the code i have set up:
 

Spoiler
set $FoundActors resultfrom util_scan_cell_npcs

set $loop 0
set $TotalActors resultfrom listcount $FoundActors
set $Follower[0] $system.player
while $loop < $TotalActors
	set $Actor $FoundActors[$loop]
	actor_infaction $Actor "Skyrim.esm:0x05c84e" ; Follower Faction
	if $$ = "true"
		set $ActorName resultfrom actor_name $Actor ; used for debug message
		msg_notify $"{$ActorName}" ; Debug msg just so i know it found a follower
		listadd $Follower $Actor
	endif
	inc $loop 1
endwhile

 

 

This does work but gets slower when there are a lot of npcs in the cell (obviously as its checking all npcs in the cell).

 

I read the util_scan_cell_npcs function can check a specific keyword but there doesn't seem to be an easily shared keyword between current followers unless "keyword" can check for things i am unaware of.

 

Is there a function that can act basically like util_scan_cell_npcs but can filter out via faction instead?
Side note: trying to add any arguments onto util_scan_cell_npcs results in it not seemingly running. Looking at the wiki using "set $FoundActors resultfrom util_scan_cell_npcs none 100.0 "" true" should work but doesnt seem to work for me (im probably doing something wrong).

 

Any advice would be greatly appreciated, Thanks

Posted

Good afternoon.
Is it possible to translate MSM somehow?

It's very difficult to set up triggers when you don't know the language.
Thank you.

Posted
On 3/25/2026 at 6:50 AM, thorax339 said:

Ive tried looking through all the functions but cant seem to find a better way so thought i would ask.

Im trying to create a list of follower actors without using the NFF follower command (since i intend to make this more universal even tho the getnfffollower function works great wheng using nff, which i do.)

currently this is the code i have set up:
 

  Reveal hidden contents
set $FoundActors resultfrom util_scan_cell_npcs

set $loop 0
set $TotalActors resultfrom listcount $FoundActors
set $Follower[0] $system.player
while $loop < $TotalActors
	set $Actor $FoundActors[$loop]
	actor_infaction $Actor "Skyrim.esm:0x05c84e" ; Follower Faction
	if $$ = "true"
		set $ActorName resultfrom actor_name $Actor ; used for debug message
		msg_notify $"{$ActorName}" ; Debug msg just so i know it found a follower
		listadd $Follower $Actor
	endif
	inc $loop 1
endwhile

 

 

This does work but gets slower when there are a lot of npcs in the cell (obviously as its checking all npcs in the cell).

 

I read the util_scan_cell_npcs function can check a specific keyword but there doesn't seem to be an easily shared keyword between current followers unless "keyword" can check for things i am unaware of.

 

Is there a function that can act basically like util_scan_cell_npcs but can filter out via faction instead?
Side note: trying to add any arguments onto util_scan_cell_npcs results in it not seemingly running. Looking at the wiki using "set $FoundActors resultfrom util_scan_cell_npcs none 100.0 "" true" should work but doesnt seem to work for me (im probably doing something wrong).

 

Any advice would be greatly appreciated, Thanks

 

I'll have to take a look at util_scan_cell_npcs regarding it not working properly with parameters. Can you copy/paste your sltscript here so I have the exact syntax you are using?

 

As for filtering specifically for followers, I'm not sure; it's not something I've looked into. As you say, perhaps there is a keyword or something that can be used. Google may have some answers (I know it's where I would turn).

 

I've not been poking at SLTR much lately, but there are a few things pending. I may look further into this (followering filtering) but I can't make any promises (that I will find anything useful). :(

Posted (edited)
6 hours ago, tatkaa4 said:

Good afternoon.
Is it possible to translate MSM somehow?

It's very difficult to set up triggers when you don't know the language.
Thank you.

 

I had done some localization for parts of the MCM but a) was not thorough regarding fields and b) did not attempt anything with the selection values.

 

I will have a look at this but be aware that I am, unfortunately, monolingual and would need assistance with translation (barring use of Google translate).

 

Also, what language are you looking for?

Edited by hextun
Posted
5 hours ago, hextun said:

 

I'll have to take a look at util_scan_cell_npcs regarding it not working properly with parameters. Can you copy/paste your sltscript here so I have the exact syntax you are using?

 

As for filtering specifically for followers, I'm not sure; it's not something I've looked into. As you say, perhaps there is a keyword or something that can be used. Google may have some answers (I know it's where I would turn).

 

I've not been poking at SLTR much lately, but there are a few things pending. I may look further into this (followering filtering) but I can't make any promises (that I will find anything useful). :(

My sltscript is currently just what i posted above. I intend for it to be a matchmaker like system that focuses on the followers using the player since i couldn't find a mod that worked the way id like.


Did a bit more testing on the util_scan_cell_npcs function.
it seems that once you start putting in arguments this is the part where it has issues

"Form: objCenter: (optional: default none) ObjectReference to center the search on; specifying 'none' will target the player (i.e. bareword none, not a string "none")"
if you put the word none without quotes it seems to try and use that for something instead of defaulting to the player. if i instead use the command like this:
set $FoundActors resultfrom util_scan_cell_npcs $system.player 200.0 "" true
It works fine.

As for keywords. one of the console mods i have lets me see all the keywords npcs have and the ones all my followers have seem to be generic ones that many other npcs have. nothing specifically for followers as that all seems to be controlled via factions. I probably could use SPID to apply keywords to followers but then that would add a SPID requirement which i am still trying to make it not require anything else.

 

Thanks for the reply. I think i will use the NFFfollowers method for my own use for now as it requires less code which should be faster and maybe update in the future if i end up sharing the script.

Just remembered. My first iteration using the nfffollowers method i was sorting via arousal and found that using "sl_get_statistic" function for arousal e.g. "sl_get_statistic (followerActor) 17 " would always return 0. Ended up needing to use "sla_get_arousal (followerActor)".
sl_get_statistic is listed under the Sexlab P+ section and i am using the latest version which recently updated to 2.17 so perhaps something changed.

 
Posted
On 3/26/2026 at 10:53 PM, thorax339 said:

My sltscript is currently just what i posted above. I intend for it to be a matchmaker like system that focuses on the followers using the player since i couldn't find a mod that worked the way id like.


Did a bit more testing on the util_scan_cell_npcs function.
it seems that once you start putting in arguments this is the part where it has issues

"Form: objCenter: (optional: default none) ObjectReference to center the search on; specifying 'none' will target the player (i.e. bareword none, not a string "none")"
if you put the word none without quotes it seems to try and use that for something instead of defaulting to the player. if i instead use the command like this:
set $FoundActors resultfrom util_scan_cell_npcs $system.player 200.0 "" true
It works fine.

As for keywords. one of the console mods i have lets me see all the keywords npcs have and the ones all my followers have seem to be generic ones that many other npcs have. nothing specifically for followers as that all seems to be controlled via factions. I probably could use SPID to apply keywords to followers but then that would add a SPID requirement which i am still trying to make it not require anything else.

 

Thanks for the reply. I think i will use the NFFfollowers method for my own use for now as it requires less code which should be faster and maybe update in the future if i end up sharing the script.

Just remembered. My first iteration using the nfffollowers method i was sorting via arousal and found that using "sl_get_statistic" function for arousal e.g. "sl_get_statistic (followerActor) 17 " would always return 0. Ended up needing to use "sla_get_arousal (followerActor)".
sl_get_statistic is listed under the Sexlab P+ section and i am using the latest version which recently updated to 2.17 so perhaps something changed.

 

 

Okay, I took a look at util_scan_cell_npcs and, lo and behold, therein lies a bug! Yep, a buggier bug has never bugged bugs more than this bug (with apologies to Ms. Hopper).

 

It turns out that the notion of passing none as the objCenter was something *I* decided to offer to my lovely userbase as a matter of convenience. Meaning if none is passed into the underlying PapyrusUtil call, one should expect things to break.

 

And in my state of drunken revelry (or whatever mental state I was in when I coded insect befouled code), I had thought that initializing the local variable BEFORE attempting to assign it via resolution would be satisfactory.

 

As if. You see, that means the default player reference was getting overridden with... none. *facepalm*

 

Anyhow, the bug will be swatted in the next release. Thank you for your attention. *swat*

Posted
On 3/26/2026 at 10:53 PM, thorax339 said:


Just remembered. My first iteration using the nfffollowers method i was sorting via arousal and found that using "sl_get_statistic" function for arousal e.g. "sl_get_statistic (followerActor) 17 " would always return 0. Ended up needing to use "sla_get_arousal (followerActor)".
sl_get_statistic is listed under the Sexlab P+ section and i am using the latest version which recently updated to 2.17 so perhaps something changed.

 

 

I just checked into this as well. I pulled the latest SLP from pixeldrain via the Discord link. This would be SLP+ 2.17.0, announced by Scrab on 2026-March-06. Looking at the SexLabStatistics.psc file, I see the same signature and the same ID values, including 17 for Arousal.

 

I'm not sure why you would always get 0, although I have some thoughts. While I was investigating (i.e. searching the Discord history for references to arousal), I saw indications that SexLab "arousal" is an in-scene thing, representing the level of arousal/enjoyment that would lead to an orgasm. This would be separate from the "arousal" from arousal mods like OSLA. Those "arousal" values represent the actor's general level of arousal, i.e. desire for sex. As opposed to the in-scene arousal, i.e. closeness to orgasm. This is further indicated when you look at the SexLabP+ API docs at https://slp-community.github.io/SexLab-Wiki/slp/api-reference/ (search for arousal) where the API calls actually reference "enjoyment", which I'm very sure references in-scene behavior.

 

What does this mean? If you are trying to determine how much an actor wants to have sex outside of a scene, you need to use whatever arousal mod's API can fetch you that info (as you did with sla_get_arousal). If you are trying to determine how close an actor in scene is to having an orgasm, you need to use the appropriate SexLab API.

 

I am, let's say, 87% certain of this, with the variability due to not having actually seen code or gotten a statement from a dev that corroborates my stance. Otherwise, I think there is sufficient evidence to make the statement.

Posted

Status update, for those who care...

 

Version 0.979 is targeted to include:

- various doc fixes (thank you again for those who reported in)

- a fix for util_scan_cell_npcs

- a new Core trigger, Player Level Up

- a deeper localization effort

 

What is a "deeper localization effort"? I had done *some* localization in the MCM but mostly just for static fields. Anything that was coming in from the *-attributes.json files, which are how the actual selectable items are generated dynamically, were not being localized. At the time of this writing, I have converted all widget labels and all widget help/info text to use localization keys and added them to sl_triggers_ENGLISH.txt and sl_triggers_CHINESE.txt, the only two translation files I currently have. That said, I have *not* attempted to translate the new keys to Chinese as I think my results would be laughably bad. If someone wants to offer to perform a suitable translation, I'll be happy to share the files in advance so they can be included in the release.

 

As I mentioned, at this time I only have English and Chinese. If there are other languages someone is interested in and wishes to offer translation services I'll be happy to include them. I can *try* something like Google Translate but I'm not sure if it will work well enough and am loathe to accidentally put out something that is confusing or, worse, offensive due to my ignorance.

 

Additionally, if anyone is running a Chinese localized installation and is willing to test to ensure the newly localized stuff works, send me a DM; I would appreciate being able to test this on a non-English setup before releasing.

 

Pinging @guliguliradish and @tatkaa4 due to prior input. :)

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