Jump to content

SL Triggers(v12) [2022-06-05]


Recommended Posts

Posted
20 hours ago, hextun said:

New drop. I think you'll like this one. :)

 

105
    bugfix: possible resolution issue with global variables in some cases
    enhancement: new feature, subroutines
        beginsub <subroutinename>/endsub to demarcate the subroutine
        gosub <subroutinename> to execute and return
    enhancement: new feature, "call"
        call <command file name> <optional $1 argument> <optional $2 argument> ...
            stops execution of current command file, runs the requested file, then resumes current command file
            if an extension is not specified .ini is tried first, then .json
            variable scopes are NOT shared (global variables are, of course, still global)
                so if you set $1, then call a function, it will not see your $1 value
                but if you use $g1, it will
            arguments are passed by value
        callarg <index> <variable name>
            Example: callarg 0 $2
            this will place the first (index 0) argument passed into $2

 

That's right, you can now create subroutines (i.e. functions) within your commands, and you can also call one command from another command *as* a command. You can even pass arguments to those commands.

 

I said GO NUTS!!!!

sl_triggers105.zip 426.49 kB · 6 downloads

 

Got around to test v104-105 and quickly ran into an issue; the chance part of the trigger is completely borked.
The MCM doesn't save it to the trigger#.ini if the section doesn't already exist (so triggers created through MCM are inert) and even if it does read and display the chance value from an existing .ini, nothing ever triggers.

Also I think the MCM is misaligned on every second trigger entry? Like offset by 1 because of the new/delete buttons. Just an aesthetic thing from what I can tell, nothing is breaking.

Posted
1 hour ago, MannySauce said:

 

Got around to test v104-105 and quickly ran into an issue; the chance part of the trigger is completely borked.
The MCM doesn't save it to the trigger#.ini if the section doesn't already exist (so triggers created through MCM are inert) and even if it does read and display the chance value from an existing .ini, nothing ever triggers.

Also I think the MCM is misaligned on every second trigger entry? Like offset by 1 because of the new/delete buttons. Just an aesthetic thing from what I can tell, nothing is breaking.

 

Well, you beat me by a few minutes.

 

I'm release v106 which includes the following:

- now ESL flagged

- df_setdebt and df_resetall were added as well as scripts that use them (Devious Followers Redux compat checked)

- bugfix workaround for a Papyrus VM string case destruction issue

 

I suspect the bugfix will address your problem, but if it doesn't immediately fix it, try a new save.

 

So what do I mean by "Papyrus VM string case destruction"? If you do this in Papyrus:

 

Function Foo(string aString)

  string prefix = "myprefix_"

  string mixed = prefix + aString

  JsonUtil.SetStringValue("somefile", "somekey", mixed)

  string check = JsonUtil.GetStringValue("somefile", "somekey")

EndFunction

The strings 'mixed' and 'check' are not guaranteed to be case identical. Meaning if what went in was "cat" you might get back "Cat", "CAt", etc. Mostly when the string crosses function or script boundaries. In most cases it won't matter because simple Papyrus string comparison is case-insensitive. It's when you are mashing strings together that things get wonky.

 

In my case I was combining "triggerattributes_" with an attribute name like "event" except it was coming back as "Event". Then when I asked JsonUtil to find all paths matching my string it didn't find it because JsonUtil isn't running inside the Papyrus VM; it's a DLL so it adheres to case sensitivity rules for JSON and misses the match. Technically the original format would have worked, but I added a couple of extra fields so that this sort of lookup isn't required. There is still a little string concatenation happening but it's only adding the [x] index for the path lookup and I'm hopeful that won't be an issue.

 

I suspect that the VM does this string freezing as a way to improve performance. Rather than carrying five different copies of the string "Event", just have the one in memory and have everyone reference it. And I suspect, therefore, that "the first one in wins". So the first case-insensitive cache miss for a specific string I think populates the cache. All future equality checks ignore case, so no big deal.

 

Anyway, as I said, I'm hoping it's fixed and behind us.

 

And the DF functions I added in response to people always mentioning the deals and debt go haywire, so this seemed a thing people would want. You could hook it up to a hotkey and use it as needed.

sl_triggers106.zip

Posted
2 hours ago, hextun said:

 

Well, you beat me by a few minutes.

 

I'm release v106 which includes the following:

- now ESL flagged

- df_setdebt and df_resetall were added as well as scripts that use them (Devious Followers Redux compat checked)

- bugfix workaround for a Papyrus VM string case destruction issue

 

I suspect the bugfix will address your problem, but if it doesn't immediately fix it, try a new save.

 

So what do I mean by "Papyrus VM string case destruction"? If you do this in Papyrus:

 

Function Foo(string aString)

  string prefix = "myprefix_"

  string mixed = prefix + aString

  JsonUtil.SetStringValue("somefile", "somekey", mixed)

  string check = JsonUtil.GetStringValue("somefile", "somekey")

EndFunction

The strings 'mixed' and 'check' are not guaranteed to be case identical. Meaning if what went in was "cat" you might get back "Cat", "CAt", etc. Mostly when the string crosses function or script boundaries. In most cases it won't matter because simple Papyrus string comparison is case-insensitive. It's when you are mashing strings together that things get wonky.

 

In my case I was combining "triggerattributes_" with an attribute name like "event" except it was coming back as "Event". Then when I asked JsonUtil to find all paths matching my string it didn't find it because JsonUtil isn't running inside the Papyrus VM; it's a DLL so it adheres to case sensitivity rules for JSON and misses the match. Technically the original format would have worked, but I added a couple of extra fields so that this sort of lookup isn't required. There is still a little string concatenation happening but it's only adding the [x] index for the path lookup and I'm hopeful that won't be an issue.

 

I suspect that the VM does this string freezing as a way to improve performance. Rather than carrying five different copies of the string "Event", just have the one in memory and have everyone reference it. And I suspect, therefore, that "the first one in wins". So the first case-insensitive cache miss for a specific string I think populates the cache. All future equality checks ignore case, so no big deal.

 

Anyway, as I said, I'm hoping it's fixed and behind us.

 

And the DF functions I added in response to people always mentioning the deals and debt go haywire, so this seemed a thing people would want. You could hook it up to a hotkey and use it as needed.

sl_triggers106.zip 426.41 kB · 4 downloads

 

👍

I'll give it a go when I've got time.

Posted

Next release will add:

 

  dd_unlockslot  <slot#>  ["force"]  ; slot# i.e. 32 for body; "force" - optional, if specified will unlock quest/blocked items too, be careful

  dd_unlockall  ["force"]  ; same as dd_unlockslot but for all slots

 

and:

 

  DD Unlock All.ini

 

 

Posted

Ok so I've been working on scripts for testing most operators and a few examples for sharing as well, and I've run into a self inflicted issue of using waaay too long file names trying to explain exactly what it does and why, so I've got a feature request if it isn't already a thing; would it be feasible to have comment support inside the script .ini files?

Posted
35 minutes ago, MannySauce said:

Ok so I've been working on scripts for testing most operators and a few examples for sharing as well, and I've run into a self inflicted issue of using waaay too long file names trying to explain exactly what it does and why, so I've got a feature request if it isn't already a thing; would it be feasible to have comment support inside the script .ini files?

 

Well, I *had* coded it to support comment to end of line with semi-colons. But apparently my faith in my tokenizer was such that I apparently never tested it. It didn't work, so I'm glad you didn't try it.

 

That said...

 

 

 

New beta drop, 107.

 

107
    enhancement: new commands for your scripts:
            dd_unlockslot <slot#> <"force" (optional)> ; slot# i.e. 32 is body ; if "force" is added as a second parameter, it will also unlock quest items
            dd_unlockall <"force" (optional)> ; works like dd_unlockslot but for all slots
        Note that after unlocking items may still appear to be equipped in inventory but you should be able to safely select and remove them
        And a script to demonstrate
            DD Unlock All.ini
    enhancement: .ini scripts now support comment to end of line
        sl_isin $self ; this is a valid comment
        ; as would be this (all by itself)

 

sl_triggers107.zip

Posted (edited)
16 hours ago, MannySauce said:

Thanks, time to make my files 99% overexplaining comments.

 

I don't know if I made it clear, btw, but you can rename your trigger files to something more meaningful.

 

 

 

Capture.PNG

Edited by hextun
Posted

New version drop, 108. Does not require a new save.

 

108
    enhancement: added sl_triggersAPI for other mod authors to access SLT features
        sl_triggersAPI exposes the following endpoints:
            GetVersion()
            GetScriptsList()
            RunScript(string _scriptname, Actor _actor = none) ; defaults to Player
                if RunScript() is called without an Actor provided
                    it will first try the Actor currently in your crosshairs if there is one
                    it will fall back to the Player

    enhancement: added console commands (slt/sl_triggers)
        slt console command has the following usage:
			Usage: slt version          ; displays sl_triggers mod version
			Usage: slt list             ; lists the scripts available to run from SLT
			Usage: slt run <scriptname> ; where <scriptname> is a valid script for SLT
                when slt run is called
                    it will first check if there is an Actor currently selected in the console
                    it will then check for an Actor in the crosshairs
                    it will fall back to the Player

 

sl_triggers108.zip

Posted

For those just tuning in, the following version upgrades require new saves:

 

12 -> anything higher

24 -> anything higher

106-108 new save not needed

Posted

Also, for those who have used sl_triggers before and after the beta started, what is your impression of the changes I've made so far? Specifically with regard to the new breakout of extensions and types of triggers and such? Also having separate files per trigger instead of a single monolithic file?

 

The .ini change and additional functions aren't a distinguishing factor; those could be retrofitted to the pre-beta chassis.

Posted (edited)

Btw, I heard from fotogen. I'm cleared to continue working on SLT but they wanted me to create a new support thread. I'll be setting that up soon.

 

image.png.b2bcd043ece7915076a6e58b8f01230c.png

Edited by hextun
Posted

v108 still has the SexLab trigger chance issue where it doesn't save the chance section to new trigger#.inis, and if it already exists, it only reads the value for MCM display purposes as nothing triggers even at 100%.

Core key mapping triggers work just fine however.

I've tested this on both my cleaned ongoing saves, a brand new save and an almost-vanilla new save with only the SexLab and SL Triggers requirements installed. Same result with all.

Posted

At Fotogen's request I have created a new download link and support forum. In order to differentiate at this point I am going to be using the name "SL Triggers Redux" as seems to be the fashion these days.

 

The upload is for v109 which includes fixes for the SexLab issues you mentioned @MannySauce.

 

I will be active over in the thread going forward.

  • 3 weeks later...
Posted (edited)
On 4/20/2025 at 1:19 PM, hextun said:

Depending on your script environment, you have access to the $g# variables e.g. what I call globals. I added it... back ... before The Versions... the dark times. You're used to accessing variables as "$1", "$2" and so on. Those values persist only during the execution of that command script. There are now two changes. One, you can use any positive integer, so you have a lot more variables should you like. Two, if you use variable names as follows: "$g1", "$g2", and so on, those variables persist across command scripts. All command scripts. Across all sessions. 

 

Hey @hextun,

do global variables persist across saves? or are they reset every time I load any save?

I'm still working on my mini-mod (for the old version)

 

also, is it possible to do the following?
detect whether:
- an actor has a certain exact name
- an actor name contains a certain string
- an actor ID is a certain exact ID

then based on this:

- define actor groups for example: ulfric and jarls in 1, legion legates in 2, etc.

- and then build triggers based on whether the partner belongs to that group

 

thanks in advance for your inputs! 🙏

Edited by Fraying9981
Posted
20 hours ago, Fraying9981 said:

 

Hey @hextun,

do global variables persist across saves? or are they reset every time I load any save?

I'm still working on my mini-mod (for the old version)

 

also, is it possible to do the following?
detect whether:
- an actor has a certain exact name
- an actor name contains a certain string
- an actor ID is a certain exact ID

then based on this:

- define actor groups for example: ulfric and jarls in 1, legion legates in 2, etc.

- and then build triggers based on whether the partner belongs to that group

 

thanks in advance for your inputs! 🙏

 

Global variables are wrappers around StorageUtil, tied to the "global" space (i.e. not tied to a specific Form). They will persist across saves. :)

 

- detect whether an actor has a certain exact name

  - yes, there is actor_name, which returns the actor's name. you could use that, then compare the value to what I guess is the name you are looking for

  - although (I'm trying to anticipate your need), if you, say, fetched an actor_name and stored it into a global variable, you could then just later compare against that value

- detect whether an actor name contains a certain string

  - unfortunately, no. or at least, not directly. that is, there is no "substring" or "contains" functionality exposed for string manipulation, but I suppose if you got creative somehow... but no, right now, there isn't that I'm aware of

- detect whether an actor ID is a certain exact ID

  - by this I assume you mean the FormID of the Actor... and in sl_triggers, no, as there is no "get the id of the form" function. I added a TON of new functions, including exactly this (return the formid of the actor.. well, form), which returns an integer which you could then compare

 

- define actor groups

  - there isn't a concept of a "group" or "list" or "set" or other collections, so creating a "group" in this case is likely going to just be you keeping track of the handful of (presumably global) variables that represent the various actors, according to their groups

- build triggers based on whether the actor is in the group

  - well, again, you can certainly run a script and in that script compare the actor's values to whatever values you have on hand, and if they don't match up, exit early

  - how to do it specifically? 

 

I don't know all of the particulars but it sounds like you have the following tasks you are trying to perform:

- identify group actors and collect them, or key attributes at least, to compare against later

- compare an actor to the lists to see if they are in a group then act accordingly

 

Identification of actors:

- with current SLT (i.e. not SLTRedux) you have fewer options for collecting reasonable attributes. I'm pretty sure name might be it? You'd have to check the documentation. :/ If you are talking about unique NPCs, that shouldn't be too bad. 

- but you're talking about groups like "legion legates"... non-unique NPCs. That won't work with simple name comparison.

- perhaps instead of thinking in terms of "identify these specific npcs and note them in advance" instead think in terms of "sets of attributes an actor must meet to belong to this group or classification" which might consist of names or could be a keyword check or an equipment check (like looking for worn imperial armor). 

- then in your script, when you are trying to decide whether an actor belongs to a given group, you would use a goto to go to a block of code to check for each group. Try them in order from "most likely" to "least likely" to match if possible, to reduce cycle usage

- you could perhaps consider mixing in something like KID or SPID, whatever it is to let you distribute keywords of your choosing to NPCs based on your criteria. Then that mod handles setting up keywords and all you would need to do is do is use "actor_haskeyword" to check for group identity

Posted (edited)

Thank you! as always, super helpful.

 

I've been rereading the readme and only discovered now that SL triggers can read json files in game. so I'm trying to use that as a DB to store actors in groups, and hardcoded values that cluttered my functions before.

 

3 hours ago, hextun said:

  - yes, there is actor_name, which returns the actor's name. you could use that, then compare the value to what I guess is the name you are looking for

 

yes I'm going to use this to group specific npcs like ulfric stormcloak. The man is a high king, he should have his own script! (I'm teasing you a little for what's coming, if it works).

unique npcs i will try to fetch from jsons after building the list in a json.

 

3 hours ago, hextun said:

- but you're talking about groups like "legion legates"... non-unique NPCs. That won't work with simple name comparison.

 

 

for non unique npcs, i will try adding fallback values based on faction. this way non unique npcs should be sorted in a way, even vaguely.

 

I have a question regarding fetching these values.

say I have a $g4 = "3"

and a json file like this

{

 1 : hello

2 : world

3: apache helicopter

}

 

if i do this:


        ["set", "$2", "../sl_triggers/commandstore/time_control"],
        ["json_getvalue", "$2", "float", "$g4", "1"],

 

at run time, will $g4 be dynamically replaced by 3, and the function return "apache helicopter"? or will it look for a field named "$g4" (as string)

 

My second question is regarding global variable initialization:

 

3 hours ago, hextun said:

Global variables are wrappers around StorageUtil, tied to the "global" space (i.e. not tied to a specific Form). They will persist across saves. :)

 

 

thats great, but what does it mean for unused ones? are they automatically initialized to zero even if they are unused?

i'm trying to define a new character property that evolves over time. the thing, is if i initialize it inside a trigger, as you suspect, every time the trigger plays, it will be reset (to 0 for example).

right now im using json to store that global property, access it, and update it.

 

Last question: how do we check if we are indoor or outdoor from inside the trigger?

 

as always, thanks in advance for your precious inputs!

Edited by Fraying9981
Posted
On 4/28/2025 at 9:26 PM, hextun said:

For those just tuning in, the following version upgrades require new saves:

 

12 -> anything higher

24 -> anything higher

106-108 new save not needed

 

How does version 12 suddenly become v 108? The version format doesn't make sense.

Posted

I have tried and tried but will never figure this out, could ya'll try to explain how faction detection works?

 

I have got:

 

{
    "cmd" :
    [
        ["actor_infaction", "$partner", "**Skyrim.esm:000000"],
        ["if", "$$", "!=", "1", "end"],

        ["item_add", "$player", "**Skyrim.esm:000", "1", "0"],
        ["goto", "end"],

        [":", "end"]
    ]
}

 

My goal is to add an item to the player's inventory IF the partner is in a particular faction but not if they aren't, no matter what I try it's either all or nothing,

["if", "$$", "!=", "1", "end"] causes the item to add no matter the NPC alignment

["if", "$$", "=", "1", "end"] causes the item to add no matter the NPC alignment

["if", "$$", "&=", "1", "end"] blocks the item from adding no matter the NPC alignment

["if", "$partner", "=", "1", "end"] blocks the item from adding no matter the NPC alignment

etc.

etc...

 

...would applying a custom magic effect that causes a script to run which checks for factions and then would run a bat with a consoleutil command that could add the item work better?

 

Any help or insight would be greatly appreciated.

 

 

 

 

**(yes Skyrim:000000 is invalid, it's redacted.)

Posted

Could someone please help me. I have tried to write one of the files but i cannot get it right. I want the NPC in a sex scene to not become hostile (my follower then kilsl them). Can someone please help with what the code should be. TO either make them friendly or add them to the follower faction temporarily?

Posted
On 5/29/2025 at 5:47 AM, Giren said:

I have tried and tried but will never figure this out, could ya'll try to explain how faction detection works?

 

I have got:

 

{
    "cmd" :
    [
        ["actor_infaction", "$partner", "**Skyrim.esm:000000"],
        ["if", "$$", "!=", "1", "end"],

        ["item_add", "$player", "**Skyrim.esm:000", "1", "0"],
        ["goto", "end"],

        [":", "end"]
    ]
}

 

My goal is to add an item to the player's inventory IF the partner is in a particular faction but not if they aren't, no matter what I try it's either all or nothing,

["if", "$$", "!=", "1", "end"] causes the item to add no matter the NPC alignment

["if", "$$", "=", "1", "end"] causes the item to add no matter the NPC alignment

["if", "$$", "&=", "1", "end"] blocks the item from adding no matter the NPC alignment

["if", "$partner", "=", "1", "end"] blocks the item from adding no matter the NPC alignment

etc.

etc...

 

...would applying a custom magic effect that causes a script to run which checks for factions and then would run a bat with a consoleutil command that could add the item work better?

 

Any help or insight would be greatly appreciated.

 

 

 

 

**(yes Skyrim:000000 is invalid, it's redacted.)

 

My guess would be, that faction "**Skyrim.esm:000000" is invalid. Does not exists. Even non-redacted one. Because of that, "actor_infaction" always returns 0.

 

Posted
7 hours ago, gooser said:

Thanks. Looks great.

btw, what is "Aaaaa.ini"  (and Aaaaa.json) ?

 

I had extended sl_triggers a bit before moving over to SL Triggers Redux. So anything past Fotogen's original sl_triggers v12 isn't (I don't think; @Fotogen correct me if I'm wrong) likely to be supported. This would include the features that added the ".ini" format for scripts. As for "Aaaaa" and other zonky named scripts, that's my fault for leaving oddly named test scripts in places where they get scooped up by my packing script. It was the sound I was making at one point while testing... you know... "AAAAAaaaaaaaa"... usually precipitated by other frustrated noises. Then it became "Bbbbb" because I got over my emotional issues. And so on. I added scripts like Z01 through Z10 because when I wanted to test something that I thought was a syntax issue, I could modify each script in turn before it was loaded and could have up to 10 additional tests without needing to reload anything. So please ignore those and don't fault Fotogen for any of that. :)

Posted
On 5/28/2025 at 1:37 PM, Omnishade said:

 

How does version 12 suddenly become v 108? The version format doesn't make sense.

 

As I mentioned further down, any version past 12 is on me. I had done a couple of updates first, sticking mostly to the existing mod. Then I decided to start rearchitecting and I bumped the version up to the 100's because the original versioning scheme didn't appear to be semver based, so I decided that a ludicrously higher number would presumably be a pretty clear indication that this was not a "normal" cut. I also tried to be clear that it was "beta" quality. As for why it skipped to... 108... it's because at that point I had put up and then taken down versions 100-107 (I think). Mostly because I didn't want to leave buggy versions around.

 

At this point, I've moved my effort over to SL Triggers Redux as a fork/offshoot. Following the same versioning it's up to 120 at this point. I haven't released an update in a bit because I'm in the middle of yet another overhaul. Beta.

 

This forum, of course, is for support of Fotogen's version, so my recommendation would be either stick with v12 (or whichever the latest is Fotogen releases in this thread), go ahead and use one of the other variants I added (but don't expect support) or, of course, try out SLTRedux (beta, but in progress).

Posted
On 5/21/2025 at 5:41 PM, Fraying9981 said:

Thank you! as always, super helpful.

 

I've been rereading the readme and only discovered now that SL triggers can read json files in game. so I'm trying to use that as a DB to store actors in groups, and hardcoded values that cluttered my functions before.

 

yes I'm going to use this to group specific npcs like ulfric stormcloak. The man is a high king, he should have his own script! (I'm teasing you a little for what's coming, if it works).

unique npcs i will try to fetch from jsons after building the list in a json.

 

 

for non unique npcs, i will try adding fallback values based on faction. this way non unique npcs should be sorted in a way, even vaguely.

 

I have a question regarding fetching these values.

say I have a $g4 = "3"

and a json file like this

{

 1 : hello

2 : world

3: apache helicopter

}

 

if i do this:


        ["set", "$2", "../sl_triggers/commandstore/time_control"],
        ["json_getvalue", "$2", "float", "$g4", "1"],

 

at run time, will $g4 be dynamically replaced by 3, and the function return "apache helicopter"? or will it look for a field named "$g4" (as string)

 

My second question is regarding global variable initialization:

 

 

thats great, but what does it mean for unused ones? are they automatically initialized to zero even if they are unused?

i'm trying to define a new character property that evolves over time. the thing, is if i initialize it inside a trigger, as you suspect, every time the trigger plays, it will be reset (to 0 for example).

right now im using json to store that global property, access it, and update it.

 

Last question: how do we check if we are indoor or outdoor from inside the trigger?

 

as always, thanks in advance for your precious inputs!

 

Hey @hextun

Would you have some feedback about this one? 🙏

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