MannySauce Posted April 27, 2025 Posted April 27, 2025 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.
hextun Posted April 27, 2025 Posted April 27, 2025 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
MannySauce Posted April 27, 2025 Posted April 27, 2025 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.
hextun Posted April 27, 2025 Posted April 27, 2025 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
MannySauce Posted April 27, 2025 Posted April 27, 2025 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?
hextun Posted April 27, 2025 Posted April 27, 2025 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 1
MannySauce Posted April 27, 2025 Posted April 27, 2025 Thanks, time to make my files 99% overexplaining comments.
hextun Posted April 28, 2025 Posted April 28, 2025 (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. Edited April 28, 2025 by hextun
hextun Posted April 28, 2025 Posted April 28, 2025 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 1
hextun Posted April 28, 2025 Posted April 28, 2025 For those just tuning in, the following version upgrades require new saves: 12 -> anything higher 24 -> anything higher 106-108 new save not needed
hextun Posted April 28, 2025 Posted April 28, 2025 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.
hextun Posted April 29, 2025 Posted April 29, 2025 (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. Edited April 29, 2025 by hextun
MannySauce Posted April 30, 2025 Posted April 30, 2025 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.
hextun Posted April 30, 2025 Posted April 30, 2025 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
Fraying9981 Posted May 20, 2025 Posted May 20, 2025 (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 May 21, 2025 by Fraying9981
hextun Posted May 21, 2025 Posted May 21, 2025 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
Fraying9981 Posted May 21, 2025 Posted May 21, 2025 (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 May 21, 2025 by Fraying9981
Omnishade Posted May 28, 2025 Posted May 28, 2025 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.
Giren Posted May 29, 2025 Posted May 29, 2025 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.)
Dinkelage Posted June 2, 2025 Posted June 2, 2025 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?
gooser Posted June 2, 2025 Posted June 2, 2025 Thanks. Looks great. btw, what is "Aaaaa.ini" (and Aaaaa.json) ?
Fotogen Posted June 2, 2025 Author Posted June 2, 2025 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.
hextun Posted June 3, 2025 Posted June 3, 2025 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.
hextun Posted June 3, 2025 Posted June 3, 2025 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).
Fraying9981 Posted June 3, 2025 Posted June 3, 2025 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? 🙏
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now