Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

This Week in MetaScript Development (10 April 2024)

1712755780
timmaugh
Pro
API Scripter
Features New and Really New Some of the new features in this batch of script updates are based around things I've wanted to make available for some time -- things like expanding Fetch's ability to return properties from tables or table items, ZeroFrame's ability to add tokens to the Turn Order, or Plugger getting a text replace function. Other updates stem from  an announcement  Roll20 previously made, detailing new updates that will soon be made available to scripts -- new properties and new functions to let script developers do even more things. All of these updates are discussed in the first messages of this thread... New Features in This Update New Text Replace Available (Plugger) New {&tracker} Tag to Add/Update Token Entry in Turn Tracker (ZeroFrame) Filter Selected Tokens by Character Tag (SelectManager) Minor Syntax Update for Status Criteria (SelectManager) New Properties Available to Retrieve (Fetch) Identify and Use Unique Token by Name Across Pages (Fetch) ...read more about each of these, below...
1712755785

Edited 1712755824
timmaugh
Pro
API Scripter
New Text Replace Available (Plugger) Plugger gives the capability to run other scripts (or small code snippets) at meta-speed by embedding the call in EVAL tags. If such code is written in a way that would return a text value, the original command line (where the EVAL tags are embedded) can be updated with the returned value. Plugger ships with a few of these "plugins", and it is getting a new text replace function with the 1.0.8 update. Syntax An example usage of this function might look like this: {&eval}replace(--source|@{selected|BattleCry} --find|search for this text|replace with this text --find|more text|more replacement){&/eval} That would be embedded in a larger command line intended for a mod script. The replace function can take two kinds of arguments: --source --find While it will accept any number of source arguments, only the last will be acted upon. It will also accept any number of find arguments, and will operate on those from left to right. Every argument, whether a find or source argument, will take further parts. These parts can be separated using either a pipe ("|") or a hash  ("#") character. A source argument takes a single additional part, which is the text that will be searched for the find/replace operation. Since the message that reaches the script moderator has already passed through Roll20 parsers, the text can be drawn from a token property or character attribute. Similarly, in a standard setup, the Fetch metascript processes before Plugger, which opens the potential options for the origin of the text in the source argument. See below for questions of when the text must be enclosed with some form of quotation marks. --source|This is the source text to search --source#This is the source text to search --source|@{selected|BattleCry} A find argument takes either 2 or 3 additional parts. First will be the text you want to search for, and second will be the text you want to replace with in the event that the text is found. --find|search|replace --find#red#purple The search operations default to being case-sensitive. That is, if you search for "red" you will only find "red," and not find "Red," "RED," or "ReD." To change to a case-insensitive search, include an "i" as the third argument part. --find#red#purple#i Note that no matter what case sensitivity you use for the search portion of the operation, the replacement will be made using the exact case of the replacement text you provide to the argument. When to Enclose Text in Quotation Marks In order to get the component parts and understand what you are wanting to do, the Plugger parser will break down the arguments you provide to the replace function using particular rules about how it will expect you to construct those arguments. This means that sometimes you will need to enclose the source, find, or replacement text components of your arguments in some form of quotation marks. This will make sure the parser recognizes the full length of the text to be all of a piece. You have 3 enclosure options: "standard quotation marks" 'single quotation marks' `tick marks` There are three occasions when you would need to use one of these enclosure options. First, when the text you supply would, itself, also include a pipe or hash character: --source|`This source text|material has a pipe character` Second, if the text you supply would start with one of the enclosure characters: --source|'"Spoon!" he cried.' And, finally, the last occasion is when your supplied text would begin and/or end with one or more spaces that you need to have included in the processing of the argument. Otherwise, spaces in the supplied text do not matter to the parsing and detection of the borders of the argument parts: --source#" starting with a space" Although all of the above examples are shown with source arguments, the same rules hold for find arguments. There are three options to make sure you have enough options to choose a enclosure option that will work with your source text situation.
1712755789

Edited 1712755842
timmaugh
Pro
API Scripter
New {&tracker} Tag to Add/Update Token Entry in Turn Tracker (ZeroFrame) Roll20 provides a &{tracker} syntax structure that you can use in an inline roll to use the result of the roll as the initiative value for the currently selected token in the Turn Order. In other words, you can select a token and enter: [[ 1d20 &{tracker} ]] ...into the chat and you will either add that token to the Turn Order or you will update the entry for the token in the Turn Order (if it is already there). In either case, that token's entry in the Turn Order would now bear the result of this roll. This functionality does not require a mod script. That simple functionality does not help in situations where you don't immediately have a selected token. That could be when one script calls another script (for instance, if you use a script like ScriptCards and have it dispatch a call to some other script, or if you use the metascript loop of ZeroFrame), or it could be where you don't immediately know which token should be selected, or it could be where you have too many tokens to select and don't want to go through the process manually. For all of these cases, ZeroFrame now offers a metascript variation: {&tracker} While the tag can take further syntax to customize its behavior, it's easiest to see the difference between the Roll20 and metascript versions if I present it in this simplest form. There are a few requirements for using this tag and obtaining the result you'd expect. Requirement 1: Must Use Deferred Roll This is critical to using this new tag without crashing your sandbox. In any message that gets sent to Roll20 chat, inline rolls are detected by Roll20 before the message comes to the script stack. That means the roll is parsed before ZeroFrame can detect and take action on the {&tracker} tag. Because of this, in a normal roll the {&tracker} tag will, at best,, do nothing... but when using the more complex syntax (discussed, below), it might crash your sandbox with a roll syntax violation. For a fuller discussion of deferred rolls, see the  ZeroFrame wiki entry . For now, just understand that deferred rolls are rolls that are hidden from Roll20 parsers until a certain number of metascript loops pass. In order to use the new {&tracker} tag, we'll require at least 1 loop cycle. Here is a simple example of what this might look like: [\][\] 1d20 {&tracker} \]\] How this works is that ZeroFrame, at the end of any metascript loop where meta-work has been done, un-defers rolls by one slash (one deferral), and then checks the command line for the presence of the {&tracker} tag  within an inline roll . If it finds that combination, it consumes the {&tracker} tag, rendering the inline roll safe to pass through the Roll20 parsers. You'll notice that I said, "at the end of any metascript loop where meta-work has been done." That is, in fact, our second requirement... Requirement 2: Something Must Trigger the Loop ZeroFrame will only un-defer rolls (and detect the {&tracker} tag) if some meta-work was done in the previous loop. This can be a metascript operation necessary to the message (for instance, using {&select} to select tokens, or using Fetch to return some data from a token or character), or it can be something designed simply to trigger the loop without impacting the message (for instance a {&global} declaration that will not change the text of the message, or a Fetch retrieval of data in a place that won't affect the function of the message -- like between template parts in a template message). Basic Example !Adding @(selected.token_name) to Turn Order with value of [\][\] 1d20 {&tracker} \]\]. {&simple} {&select ?{Enter start of a token name}*} In that example, we wait for the user to enter the start of a token name before we know which token we should enter. Since the result of the query feeds a {&select} statement (a part of SelectManager), and SelectManager runs before Fetch, we could then utilize Fetch constructions to construct the roll, as necessary: !Adding @(selected.token_name) to Turn Order with value of [\][\] 1d20 +  @(selected.initiative)  {&tracker} \]\]. {&simple} {&select ?{Enter start of a token name}*} Extended Basic Example Using this syntax in conjunction with a forselected construction (SelectManager), you can iterate over tokens and give them individual Turn Order entries, each rolled separately. This example selects all tokens that begin "BobHorde" then iterates over them, rolling a 1d20 as a tracker value: !forselected(^) Adding @^(selected.token_name) at [^\\][^\\] 1d20 {^&tracker} ^\\]^\\] {^&simple} {&select BobHorde*} You can do the same thing without announcing each result in chat, but I added that just as a demonstration that the roll will still process and function. Why does the roll in this case require 2 backslashes (being deferred twice)? Because the initial message goes through the metascript loop before it is caught (at normal script speed) by the forselected handle of SelectManager. During this initial loop, SelectManager selects all tokens beginning "BobHorde". This prompts ZeroFrame to send the initial message through another cycle -- which means one deferral is stripped off. That is the end of the metascript processing for the main message, so then the iterated messages are dispatched, one for each token. For each of these messages, the act of restoring the iterated token to the message as a selected token constitutes the "triggering work" that causes a loop, so the second deferral is removed, and the tracker tag is discovered in a roll. Advanced Syntax The {&tracker} syntax structure can also take a comma separated list of token references. If you supply such a list, the tag will operate on the tokens you reference (if they are found) rather than the selected tokens. {&tracker Bob, Joe, Calamity Mike} Since the {&tracker} syntax is found at the end of the metascript loop, you not only can use Roll20 constructions (such as @{selected|token_id} or @{target|Select Target|token_id} ), you could also use metascript constructions (provided they were present in the command line for the utilized script to have detected and taken action on them). For instance, you could use a Fetch reference to the next token up in the tracker: {&tracker Bob, Joe, @(tracker+1.token_id)} But there is a better way to reference a given entry in the Turn Order. For each of the tokens referenced in the {&tracker} list, you can follow them with information to instruct ZeroFrame which entry to update or how to behave. Counting the option to have no trailing text, there are four options: Bob => default, adds an entry for Bob (if not found in the Turn Order) or updates first existing entry (if found) Bob+ => adds a new turn in the Turn Order for Bob, regardless of how many are there already Bob@13 => will update the first* Turn Order entry for Bob that currently has a value of 13, or create a new one (if one isn't found) Bob#2 => will update the second* Turn Order entry for Bob, or create a new one if Bob doesn't already have 2 * - the order for these constructions is the Turn Order as it stands when the {&tracker} tag is utilized {&tracker Bob+, Joe@16, Cornelius Whitaker#1} That would use the value of the roll where this construction was found to set a new entry for Bob, to update the entry for Joe that is currently at 16 (or create a new entry if that one isn't found), and do the same for the first Cornelius Whitaker entry.
1712755793

Edited 1712755869
timmaugh
Pro
API Scripter
Filter Selected Tokens by Character Tag (SelectManager)   As a part of the new updates coming to the script sandbox and to scripts, in general, characters will be getting assignable "tags." You can think of them as invisible status markers, for now. They will give GMs (or players, as GMs allow) the ability to quickly group tokens based around shared (but not immediately publicly-visible) descriptors. More information will be coming about these tags with the upcoming Roll20 release of new script functionality. With v1.1.8, SelectManager is ready to utilize these tags as filtering criteria to more finely control what tokens are selected. If you are unfamiliar with using criteria in {&select} statements, I suggest starting with  this post  where the feature is initially discussed. Syntax Here is an example of how a tag (in this case "noble") can be used as criteria: +#noble In a {&select} statement, that might look like: {&select *, +#noble} Reading that, you would say, "select all tokens on this page where the associated character is tagged 'noble'." As with all criteria, you must begin with a "+" (for 'must have') or a "-" (for 'must not have'). Follow this with a "#" (think: 'hash tag '), and then the tag you wish to test. As discussed on the other page, all criteria in a {&select} statement must pass, so a tag-criteria can be paired with other criteria: {&select BobHorde*, +#archer, +bar1 > 0} That would select all tokens on the current page whose name begins "BobHorde," and which have an "archer" tag, and which have a bar1 value greater than 0. See Also See the new properties Fetch is getting for a way to test a single token for the presence of any tag or marker. Roll20 Contingency This syntax is contingent on Roll20 rolling out the new updates to make the underlying information available.
1712755796

Edited 1712757314
timmaugh
Pro
API Scripter
Minor Syntax Update for Status Criteria (SelectManager) To prevent potential collisions (situations where a status marker might bear the name of one of the criteria SelectManager is looking for, i.e., "bar1", "aura", "npc", etc.), the syntax for checking status markers as a part of a {&select} statement criteria evaluation will be changing. The new syntax is in place in parallel with the old syntax, so for now both will continue to work; however the legacy syntax will be removed at some point, so I'd recommend updating your abilities and macros to use the new syntax, if you make use of the ability to check status markers on selected tokens. (Incidentally, as a part of this update, SelectManager will prompt you with a message in the chat every time the sandbox updates -- reminding you of this syntax change and alerting you to potential command lines where the old syntax has been detected. The message has the ability to "opt-out" by clicking a "Don't Show Anymore" button, but in the meantime that will hopefully be a help in identifying places where you might need to update your syntax.) The new syntax simply amounts to using an "*" immediately following the "+" or "-", and before the marker name. In other words, for a marker named "noble," the old syntax for checking to see if a token bears that status marker would have been: +noble The new syntax would be:  +*noble
1712755801

Edited 1712758215
timmaugh
Pro
API Scripter
New Properties Available to Retrieve (Fetch)   There are a batch of new objects and properties that Roll20 will soon be releasing for scripts, as well as some that were always available but only now are being added to Fetch. There is a lot of information in this post, most of it to document the properties. The parts that I think are the most helpful and therefore the most important to pay attention to are the discussion (at the bottom of this post) of the "is" pseudo-property for tokens, characters, and handouts, and the new rollable table properties, including the ability to get the total weight of the table, as well as to obtain a random result from the table with a "1dW" property, or to get properties from a specific item from a table. Character Properties These properties are in addition to what Fetch can already retrieve. See the  wiki entry  for a full list. A ccess these properties by using a valid character reference in a Fetch construction. Character references can come from tokens provided the referenced token represents a character: @(Bob.tags) @(selected.tags) CHARACTER PROPERTY      FETCH SYNTAX TO REFERENCE tags tags (is the character "tagged" with a given tag?) is  (see below) TokenProperties Tokens get the same "is" property that characters get in that the "is" test will check both markers on a token as well as tags on a character. The full application of the "is" property is discussed, below.  @(Bob.is.Party) @(selected.is.noble) TOKEN PROPERTY      FETCH SYNTAX TO REFERENCE (is the token marked or the character tagged?) is  (see below) Handout Properties Handouts are new to Fetch v2.1.0. To access these properties, use a pattern such as: @(handout.identifier.property) ...where the identifier is a name or ID of a handout, and the property comes from the table, below. HANDOUT PROPERTY      FETCH SYNTAX TO REFERENCE id id type type name name archived archived avatar avatar, imgsrc (image source in <img> tag) img (image source without arguments) imgsrc_short controlledby controlledby (controlledby list as names) controlledby_name, controlledby_names (ID of first non-"all" player in controlledby) player (name of first non-"all" player in controlledby) player_name inplayerjournals inplayerjournals (inplayerjournals list as names) inplayerjournals_name, inplayerjournals_names tags tags (is a handout "tagged" with a given tag?) is  (see below) Campaign Properties These properties are in addition to what Fetch can already retrieve. See the  wiki entry  for a full list.  Access these properties by referencing the campaign in a Fetch construction: @(campaign.sheetname) @(campaign.nodeversion) CAMPAIGN PROPERTY      FETCH SYNTAX TO REFERENCE nodeversion nodeversion sheetname sheetname Page Properties These properties are in addition to what Fetch can already retrieve. See the  wiki entry  for a full list. Access these properties by using "page" in a Fetch construction, followed by a page reference (name or ID): @(page.Fortress.wrapper) @(page.Dungeon of Bara'dur.wrapper_color) PAGE PROPERTY      FETCH SYNTAX TO REFERENCE path path placement placement use_auto_wrapper use_auto_wrapper wrapper_auto_color wrapper_auto_color wrapperColor wrapper, wrapper_color Card Properties Fetch could always get information for objects that were graphics with a subtype of "image," referring to the cards that had been played to the tabletop. With this update, Fetch can now access the  source  card from which those graphics are created. For instance, in a standard deck, there is only one Ace of Spades, no matter how many graphics of the card are on the board. Access these properties by using "card" in a Fetch construction, followed by a card reference (name or ID): @(card.Red Joker.card_back) @(card.Ace of Spades.img) CARD PROPERTY      FETCH SYNTAX TO REFERENCE id id type type _deckid deckid name name avatar avatar, imgsrc (image source in <img> tag) img (image source without arguments) img_short card_back card_back is_removed is_removed tooltip tooltip Table Properties Access these properties by using "table" in a Fetch construction, followed by a table reference (name or ID): @(table.FemaleNames.totalweight) @(table.MaleNames.id) If the requested "property" isn't a property of a rollable table, Fetch will immediately convert to seeing if the requested information could come from an item in the table, checking the ID of the table item and/or the name (the text value of the item). By behaving this way, you can directly reference items in the rollable table in order to get other information about that item (like the avatar image, the ID, or the weight): @(table.MaleNames.Clarence.img) Using this construction, you can return an item based on a number. The number would be compared to the weight of individual items to return the correct item. That is, if the first item in a table had a weight of 5, then every number up to 5 would return that item. If the second item had a weight of 4, then every number between 6 (where it would begin, following the first item) and 9 would return this item. @(table.FemaleNames.6) Because of this, you can use an inline roll to return the value, provided you unpack the value with a ZeroFrame .value tag: @(table.FemaleNames.[[1d20]].value) You can also retrieve a random result from a table based on the overall weight of all items in the table. For instance, in a table of 6 items where three items have a weight of 1, two items have a weight of 2, and one item has a weight of 3, you would have a total weight of 10. Each item in the table would have a certain chance in 10 of being the item returned. You can get this random return by using the property "1dW" @(table.MaleNames.1dW) Because this returns a table item, you can request further specificity in the property. By default the above would give you the text result of the table item, but you could get the avatar just by appending an ".img" to the end: @(table.MaleNames.1dW.img) TABLE PROPERTY      FETCH SYNTAX TO REFERENCE id id type type name name showplayers showplayers (the total weight of all items in table) totalweight  TABLE ITEM PROPERTY      FETCH SYNTAX TO REFERENCE id id type type name name avatar avatar, imgsrc (image source in <img> tag) img (image source without arguments) imgsrc_short The "is" Pseudo-Property Tokens, characters, and handouts now have an "is" pseudo-property that tests the presence of markers (in the case of tokens) or tags (in the case of characters and handouts). As characters can be located by token references in Fetch constructions (like "selected"), this can get a bit confusing. It is therefore advisable to use tags that have names different from any markers in your games. The "is" pseudo-property returns a "yes" or a "no" depending on if the specified tag or marker is found attached to the referenced object. You can use this yes/no return in other tests (APILogic tests, or other scripts that run logic comparisons, like ScriptCards). @(selected.is.noble) The above would test if the selected token has a status marker named "noble", or if the associated character has a tag of "noble". @(handout.Pidgin Elvish Incantations.is.spellbook) The above would test if the handout named "Pidgin Elvish Incantations" has been tagged as "spellbook". Token marker checks can take the "which" switch (a "?"), to indicate a multinary instance of the marker. For instance, to test if a token is  twice  marked with a blue dot, you can use: @(selected.is.blue?2) If you need to know the value of a given status marker, use the existing "status" pseudo-property of a token, as  described here . Roll20 Contingency This syntax is contingent on Roll20 rolling out the new updates to make the underlying information available.
1712755804

Edited 1712755935
timmaugh
Pro
API Scripter
Identify and Use Unique Token by Name Across Pages (Fetch) While Fetch can retrieve information from tokens, prior versions of Fetch required that non-ID references to tokens had to result in a token on the same page as the person making the request. For instance,  @(Bob the Hirsute.ArmorFlair)  would look for the first token  on the current page  that was either named "Bob the Hirsute" or which represented a character named "Bob the Hirsute." If there was no such token on this page, the Fetch construction would fail even if there was such a token on a different page. (ID-based references to a token, like @(-M1234567890abcdef.ArmorFlair) would work, since those are specifically referring to a unique token.) With v2.1.0, Fetch can now reach across pages for a token by name provided that token is the only token of that name in your game. This can be helpful in situations where you have a central "party loot" token, or a "spellbook" token with information in its gmnotes, etc. In these cases, you don't want to have multiple places to track certain information (i.e., copying the token to multiple pages) since the data is stored on the token, itself.
Definitely watching with bated breath. I’d love to have advantage set on appropriate initiative rolls when I try to roll a group.
1712766047
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
These are amazing! The find/replace is particularly intriguing. And thank you for the Unique Token Fetch. This will make my "character's library" idea workable.
1712774401
timmaugh
Pro
API Scripter
Thanks, Keith! For anyone looking for some of this functionality in use, check out this post , where I use some of this new functionality: the new Plugger replace function, and Fetch's ability to get images from a rollable table. I also use Plugger's getDiceByVal function and its filter function, as well as conditionals from APILogic. The end result is a custom "match" operation/output using images from a table.
Hi Tim, I've been using the meta scripts for a while now, over a year, and my macros just broke this week.  I posted some details about it in a new post in the Mods forum. I was assuming it is something in the new versions, but I don't know how to track it down.  It may be in Plugger.  I've tried installing the prior version of Plugger and it still isn't working, so now I'm not sure what is going on.   What is the easiest way to test if the {&eval} function is working?  I tried creating a new game with only Plugger and  SpawnDefaultToken as APIs.   This command works:  ! Spawn --name|d10 This command causes the error:   !{&eval}Spawn --name|d10 {&/eval}  The error is: TypeError: Cannot read properties of undefined (reading 'who') TypeError: Cannot read properties of undefined (reading 'who')     at handleInput (apiscript.js:1819:43)     at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:168:1), <anonymous>:65:16)     at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:168:1), <anonymous>:70:8)     at /home/node/d20-api-server/api.js:1762:12     at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560     at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147)     at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546)     at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489)     at Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425)     at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:461 Any ideas what I can do to test further?  What's an easy way to check if Plugger is working? Thank you!
1713610471
timmaugh
Pro
API Scripter
That particular error owes to the fact that you have a script (Plugger) launching another script (Spawn). When you do that, the "who" property of the message doesn't point to a player; it points to "API". I think there is something that I can fix in Plugger so that it at least doesn't throw this error -- it will just quietly use the "API" value, leaving the potential that the downstream message doesn't work. In this case, I know that Spawn *does* require a proper "who" value to make sure it knows where to find certain information, so we need to make sure we supply that. That's where SelectManager comes in. I know you set up your test game to just have the 2 scripts (Plugger and Spawn), but for that to work properly, you'd at least need SelectManager, too, AND you need it to either be installed before Plugger or you need ZeroFrame to impose the correct order (SM, then Plugger). Finally, you'd need to configure SelectManager to give back the "who" property by running this command one time: !smconfig +who *whew* Or, just install the full Metascript Toolbox and run the above command line. Ultimately, though, we want to get this working in your original game, so in your regular game, run this command: !smconfig And see how SelectManager is configured. If the "who" property is not enabled, run the: !smconfig +who ...command, then try your macros again. If that fixes it, it will give me a place to start tracking the issue down. Finally, if you want to test Plugger in a game where the Metascript Toolbox is installed, you can run this command: !{&eval}This worked.{&simple}{&/eval}So did this.{&simple} You should get two outputs from that. First, you should see the eval message of: This worked. Then you should see the message that remains: So did this. Let me know how all of that turns out, and we can figure out the next steps, if necessary.
Thank you!  That was the problem.  When I did the first smconfig, the result was: SelectManager is currently configured as follows: playerscanids: disabled selected: enabled who: disabled playerid: disabled I did the  !smconfig +who command, but it was still broken.  I tried that a couple times, including after a reload, just to be sure. Then I did  !smconfig +who +playerid +playerscanids, and after that it started working. Back in my notes from what I did to get this working originally I did have a note about running that command with all three turned on.  I didn't think to check there earlier today though.   Is it expected that those commands might be reset to defaults when the scripts get updated to a new version?  Or does something seem to have gone wrong in my game? Either way, thank you again!  (this week's game starts in 2 hours!  whew!)
1713627013
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Whenever I need a particular metascript in a new game these days, I just install the whole suite via the metascript toolbox.
That is a lot easier, yes.  I didn't know there was a single suite option until just now.   I've been considering trying to test out the new Jumpgate beta, so maybe I'll do that and try it with the suite instead of individual scripts.
1713640413
timmaugh
Pro
API Scripter
Jim said: Is it expected that those commands might be reset to defaults when the scripts get updated to a new version?  Or does something seem to have gone wrong in my game? It shouldn't, but that's what I'm afraid might have happened... So this gives me something to start with in terms of digging into the error. Glad it's working for you!