llde / xOBSE

Oblivion Script extender source
250 stars 36 forks source link

GetTileChildren and GetTileTraits can't utilize variables #192

Closed hartcrompton closed 1 year ago

hartcrompton commented 1 year ago

Not a bug, but functions like GetTileChildren and GetTileTraits (and I'm guessing SetMenuFloatValue and SetMenuStringValue) seem to only interpret their string parameters literally so you can't use variables within those functions.

For example: GetTileChildren "name1/name2/name3" 1011

This returns an array with the children of "name3" as expected.

But: string_var TilePath ... set TilePath to sv_Construct "name1/name2/name3" GetTileChildren TilePath 1011

Doesn't work because it doesn't seem to recognize that TilePath is a variable.

Just wondering if this is tweakable or if there might be some workaround that I've missed. I've been working on some mods that affect the UI and this would be a huge help.

Thanks!

katawful commented 1 year ago

All menu functions (including for MenuQue) support format specifiers. e.g.:

SetMenuFloatValue "some\tile\%g", 1

You can also use them for functions that need a pipe character | but I don't have an example off the top of my head

hartcrompton commented 1 year ago

All menu functions (including for MenuQue) support format specifiers. e.g.:

SetMenuFloatValue "some\tile\%g", 1

You can also use them for functions that need a pipe character | but I don't have an example off the top of my head

I have tried: GetTileChildren "%z", TilePath 1011 That just gives me the compile error "Unknown variable FilePath for parameter in."

Forlini91 commented 1 year ago

Of all menu commands GetTileChildren and GetTileTraits accept "strings" but not "formatString", which means you can't build the string like that. When an argument is a "formatString", you can pass extra arguments which will replace the placeholders in the string. Instead, a "string" argument won't accept extra arguments and you must build the string in some other way.

There are 2 solutions to this problem:

  1. Extract the string from the string_var with the $ operator
    string_var TilePath
    ...
    set TilePath to sv_Construct "name1/name2/name3"
    GetTileChildren $TilePath 1011
    sv_Destruct TilePath
  2. Directly use a quoted string
    GetTileChildren "name1/name2/name3" 1011

If you enable the OBSE compiler in that script block (in OBSE Documentation search "Using OBSE expressions in scripts"), you can also build the string in place, example:

string_var middleName
...
let middleName := "name2"
GetTileChildren ("name1/" + $middleName + "/name3") 1011
sv_Destruct middleName

SHORT EXPLANATION:

These commands accept "string" arguments but not "string_var" variables, which means you must "extract" the string from the string_var. To extract a string from a string_var use the $ operator: it casts ANYTHING to string (extract the string contained in a string_var, convert a number to string, get the "name" of a reference, etc...)

LONG EXPLANATION:

Yes, it's not intuitive. String_var variables are not usable in place of strings (unless you use the $ operator). String_var and Array_var variables not native in the Oblivion script language. They have been created by the OBSE team and they works similar to a "Ref" type/variable, because they only hold the numeric "reference" or "ID" of the string or the array, not the string/array itself (under the hood, they are actually "numeric" types like the Ref variables).

As a consequence, if you pass a string_var/array_var variable as input to any command means you're passing its numeric ID to the command, which, like in the issue you encountered, means passing a number to a command expecting a pure string. Also, a command argument may either accept a pure string or a string_var, not boths at the same time (so existing Oblivion/OBSE commands can't be "patched" to accept both types). Luckily, that's not a problem, as arguments accepting a "string" can still be feed a string_var by using the $ operator to extract the contained string, while argument accepting a string_var can be feed a string if you assign that string to a string_var first.

The same problem doesn't happen with arrays, because commands may only accept "references" to array

hartcrompton commented 1 year ago

Ah, I knew it missed something. Your explanation also answers a number of (I thought) totally unrelated thoughts I had while looking at the OBSE source.

Wonderful explanation, thank you so much!