#Bug: Variable Value Changing when it Shouldn't Be

1 messages · Page 1 of 1 (latest)

keen oriole
#

No idea how to better title this, but I think I've run into something of an absurd bug. The full code is too long to post, but the gist is I'm trying to apply conditions to multiple tokens. To do so, I loop through each token, checking to see if each passes a save. If they pass, conditions are removed, if they fail, they remain. Conditions are applied, then the loop restarts and moves on to the next token.

This is done by creating a variable, effConditionInfo, before the loop is started. Within the loop, thisTokenConditionInfo is set to equal effConditionInfo. thisTokenConditionInfo is then the only variable modified (for sure). effConditionInfo is never modified once it has been set. The intent is that when moving on to the next target, thisTokenConditionInfo is set equal to the unchanged effConditionInfo to restart the whole process.

Except, for some reason, effConditionInfo is changing. effDamageInfo (which you can probably infer the purpose of) is changing. I have no clue why.

Using broadcast() functions, I narrowed down where exactly it changes - in the following section of code:```[h:broadcast(effConditionInfo+" HERE")]
[h,foreach(condition,conditionsResistedFinal): thisTokenConditionInfo = json.path.delete(thisTokenConditionInfo,"[]['Conditions'][][?(@.Name=='"+json.get(condition,"Name")+"' && @.Class=='"+json.get(condition,"Class")+"' && @.Subclass=='"+json.get(condition,"Subclass")+"')]")]

[h:broadcast(effConditionInfo)]```It should not be changing here. And yet, the "Conditions" key is empty in effConditionInfo AND thisTokenConditionInfo if that's what's supposed to be happening to thisTokenConditionInfo alone. I don't know why. Pls help.

teal grail
#

You posted all of that as one entity, so I can't reply to just a portion of it. The portion I want to reply to is the "Except" part. You're right — this code doesn't change either of those. Something else is going on. I don't see how in this code, especially since your debugging shows that you're printing effConditionInfo pre- and post-operations. So there must be something weird in the data.

#

I presume that conditionResistedFinal is a JSON variable? If an array, it sequences through each element. If an object, it sequences through the properties. Can you provide a sample for that variable that creates this issue?

keen oriole
#

Sure - conditionsResistedFinal is an array of objects like below:

[{"Name":"Paralyzed","Class":"Condition","Subclass":""}]

Name, Class, and Subclass are the identifiers I use for specific features, so the loop is essentially looking for specific conditions based on those identifiers and removing them from the list of conditions to be added to the target.

#

Additional bits of information of possibly varying levels of usefulness/suspicion:

  • This loop takes place in a UDF that keeps the same scope. (I'll likely change this, which should fix it, but if there's a bug I'd like to get to the bottom of it for future releases.)
  • The effects stack with each target. For example, damage is also tracked, and can be halved on save. If three targets succeed when damage is halved, then damage is halved, then quartered, then eighthed (is that a word?)
  • I attempted to test setting variables that were simply set to 0, simulating the same behavior but just setting it to 1. No loop, no json.path functions. This functioned normally, so I suspect either json.path functions or loops are involved. Damage and conditions use both functions and loops, so can't rule stuff out that way.
teal grail
#

I know there are "hidden" variables for some loops, like count, for example, but you're not using any of those. I know there are bugs in the parser that cause variables with names starting with tru and fal to give errors (the parser treats true and false in a weird way that's not easy to fix). I can't see any way for your code to change those variables, though. I need to fire up MT anyway, so I'll try this myself on a new/fresh campaign.

#

@keen oriole Is there an initial value for thisTokenCondition that I can use for testing?

keen oriole
#

Sure:

[{"Conditions":[{"Name":"Paralyzed","DisplayName":"Paralyzed","Type":"Condition","ConditionType":"","Level":1,"GainOnLevel":0,"Optional":0,"MultiAbility":0,"AssociatedConditions":[{"Name":"Incapacitated","Class":"Condition","Subclass":""}],"Library":"SRD","Class":"Condition","Subclass":"","CallSpeed":1,"CallSaveSuccess":1,"CallAttackAdvTargeted":1,"CallAttackCritTargeted":1}],"EndInfo":{"Duration":1,"DurationUnits":"minute","AdvancePoint":"EndofTurn","AuraRange":0,"AuraUnits":"","EndTriggers":{"EndTurn":{"SaveType":"Constitution","DC":13}}}}]

#

(Pairs with the above conditionsResistedFinal)

teal grail
#

@keen oriole "Except, for some reason, effConditionInfo is changing. effDamageInfo (which you can probably infer the purpose of) is changing. I have no clue why."

I'm not seeing that behavior on my fresh campaign. The first variable is NOT changing and the second one, when I try to print it, gives me the normal popup for an undefined variable.

keen oriole
#

Hm, is this using a UDF with no scope change?

teal grail
#

No, just typing in that code literally into a new macro. I'm just proving that this code isn't the direct problem.

keen oriole
#

Ah, I see.

teal grail
#

I ended up with this:

[h: effConditionInfo = "Bob"]
[h: thisTokenConditionInfo = '[{"Conditions":[{"Name":"Paralyzed","DisplayName":"Paralyzed","Type":"Condition","ConditionType":"","Level":1,"GainOnLevel":0,"Optional":0,"MultiAbility":0,"AssociatedConditions":[{"Name":"Incapacitated","Class":"Condition","Subclass":""}],"Library":"SRD","Class":"Condition","Subclass":"","CallSpeed":1,"CallSaveSuccess":1,"CallAttackAdvTargeted":1,"CallAttackCritTargeted":1}],"EndInfo":{"Duration":1,"DurationUnits":"minute","AdvancePoint":"EndofTurn","AuraRange":0,"AuraUnits":"","EndTriggers":{"EndTurn":{"SaveType":"Constitution","DC":13}}}}]']
[h: conditionsResistedFinal = '[{"Name":"Paralyzed","Class":"Condition","Subclass":""}]']
[h:broadcast(effConditionInfo+" HERE")]
[h,foreach(condition,conditionsResistedFinal): thisTokenConditionInfo = json.path.delete(thisTokenConditionInfo,"[*]['Conditions'][*][?(@.Name=='"+json.get(condition,"Name")+"' && @.Class=='"+json.get(condition,"Class")+"' && @.Subclass=='"+json.get(condition,"Subclass")+"')]")]
[h:broadcast(effConditionInfo)]
#

(Man that looks ugly on my screen. Window is not wide enough...)

keen oriole
#

(Yep, my discord is scrunched up in a vertical monitor...)

#

So presumably "Bob" is broadcast at the end?

teal grail
#

Yep.

#

I also tried it without the broadcast() and just [r: ] to see if maybe the function call was doing something, but no change.

humble smelt
#

I find it's easier to sort things out if I don't mix code and strings. limits the possibility of errant braces's and quotes being misinterpreted. Also, class is a reserved word and some MT uses of it will silent quit on you.js [h:broadcast(effConditionInfo+" HERE")] [h,foreach(condition,conditionsResistedFinal), code: { [H: json.toVars(condition,"sub_")] [H: thisTokenConditionInfo = json.path.delete( thisTokenConditionInfo, strformat("[*]['Conditions'][*][?(@.Name=='%{sub_Name}' && @.Class=='%{sub_Class}' && @.Subclass=='%{sub_Subclass}')]") ) ] [h:broadcast(effConditionInfo)]

I just added the extra spacing and lines just for clarity.

#

Using sub_ as a prefix will prevent overwriting other propertie of the base name. It's especially good to do this in UDFs with shared scopes. I personally would do it on all variables in sub function.

teal grail
keen oriole
#

Thanks for the tip on prefixes! For whatever reason concatenating things just clicks better for me, I know it's not really the preferred method. 🤷‍♂️

That being said, I'm fairly certain this is not an instance of missing something in the code. Searching the entirety of my addon in VSCode for effConditionInfo shows only two results - when it was set and when it is used to set the value of thisTokenConditionInfo.

keen oriole
# teal grail I ended up with this: ``` [h: effConditionInfo = "Bob"] [h: thisTokenConditionIn...

I changed this to the following to try and more closely simulate what's going on:

[h,count(2),CODE:{
    [h: thisTokenConditionInfo = effConditionInfo]
    [h: conditionsResistedFinal = '[{"Name":"Paralyzed","Class":"Condition","Subclass":""}]']
    [h:broadcast(effConditionInfo+" HERE")]
    [h,foreach(condition,conditionsResistedFinal): thisTokenConditionInfo = json.path.delete(thisTokenConditionInfo,"[*]['Conditions'][*][?(@.Name=='"+json.get(condition,"Name")+"' && @.Class=='"+json.get(condition,"Class")+"' && @.Subclass=='"+json.get(condition,"Subclass")+"')]")]
[h:broadcast(thisTokenConditionInfo)]
[h:broadcast(effConditionInfo)]
}]

[h:broadcast(effConditionInfo)]```It worked as expected, not with this strange error I'm getting.
teal grail
#

Well, so there's something else going on then. What you really need -- and what MT doesn't have -- is the ability to set a breakpoint/watchpoint on a given variable so any changes are immediately flagged. But Craig has (had?) plans to replace MTscript anyway, so time spent on it would be kind of wasted... (Although such a feature might not be too tough to do, since there's a single API call for looking up variable names and it automatically handles the scope issues, so... If anyone with Java experience wants to take a crack at it, I'd be happy to help as much as I can.)

humble smelt
# keen oriole Thanks for the tip on prefixes! For whatever reason concatenating things just cl...

Yeah, everyone has their own style. You could also just pull out the concat part in to a separate statement to make things more clear. js [H: filter = "[*]['Conditions'][*][?(@.Name=='"+json.get(condition,"Name")+ "' && @.Class=='"+json.get(condition,"Class")+ "' && @.Subclass=='"+json.get(condition,"Subclass")+"')]"] [h,foreach(condition,conditionsResistedFinal): thisTokenConditionInfo = json.path.delete(thisTokenConditionInfo,filter)]

keen oriole
keen oriole
humble smelt
#

I usually slap-chop my code together and once it's working go back through it to clean it up, add comments and optimize. It really helps to future proof that bit of code.

#

I just recently did that with json.add (UDF) and found a bug and added some extra error checking in case some unexpected data is used.