DoctaSax Posted February 9, 2014 Posted February 9, 2014 1. Intro: String Theory 2. String Variable basics: declaring and initializing 3. 'Let' v. 'Set' syntax 4. Destroying string vars 5. Checking string vars 6. Passing string vars as parameters: ToString ($) 7. Concatenting strings, or: adding them up 8. Measuring and searching your string vars 9. Breaking string vars down, replacing bits, and reassembling them 10. Switching between string and other representations, character functions This one's a bit longer than the previous ones. Don't panic, and take a break when it gets too much. I know I had to. 1. INTRO: STRING THEORYStrings are particular combinations of characters - letters, numbers and punctuation. They're nothing new to the vanilla game and you've seen them all over. Just about anything that you see in the game interface that is a word or sentence instead of a number is a string: the names of the buttons in your menu, the word 'Open' or 'Enter' that pops up when your crosshair hovers over a container or door, the notification "You no longer have hunger sickness", the 'name' of the key the game kindly suggests that you press to activate something, and so on, they're all stored as strings under "Game Settings". Different language versions of the game will have different values for those strings. You may remember from the syntax tutorial that in a line like 'playerref.SetAV Health', 'health' is in fact also a string that can be replaced by a numeric int referring to the same actor value - using the string 'Health' just makes it so you don't have to look up that int. What we'll be talking about here mostly are formatted strings, however, not those game setting or actor value ones. If you've ever used functions like DebugPrint, Printc, or MessageEX, (and if you're reading this, I have to assume you have because it's standard practice even on a basic level) you've used formatted strings to tell the game what to display: DebugPrint "I'm a string" Printc "I'm a string" MessageEX "I'm a string" What's in between those quotation marks is a formatted string, because you've used the double quotation marks to tell the script compiler it's a formatted string. Without that, it would complain that 'I'm' is not a valid argument to the function. (Because double quotation marks are used to mark strings, I'll use single ones to quote things in this tutorial, to avoid confusion. And I'll just use 'string' for 'formatted string' from now on.) The problem with strings, from a scripting POV, is that vanilla doesn't leave us many options to manipulate them through script. That is especially true for game setting strings and actor value strings. Formatted strings at least have the advantage that vanilla allows us to use a few format specifiers on them, to pass the value of a float variable to the string itself: if 'fSomeFloat' is 3.4, then DebugPrint "The number is %.0f" fSomeFloat --> will display 'The number is 3' DebugPrint "the number is %g" fSomeFloat --> will display 'The number is 3' DebugPrint "The number is %.2f" fSomeFloat --> will display 'The number is 3.40' DebugPrint "The number is %2.2f" fSomeFloat --> will display 'The number is 3.40' and NVSE added some more that we've been using a long time: if rRef is DocMitchellRef: DebugPrint "The object's name is %n" rRef --> will display 'The object's name is Doc Mitchell' DebugPrint "The ref's formid is %i" rRef --> will display 'The ref's formid is 00104C0C' DebugPrint "%ps is scratching %pp balls" rRef rRef --> will display 'He's scratching his balls.' MessageEX "Press %k to scratch your own" iInt --> will display 'Press M to scratch your own', if iInt is 50, because that's the directxinput scan code for the M key MessageEX "Press sUActnActivate to activate" --> will display "Press E to activate" if that's the key you use for activating stuff, because sUActnActivate displays the key name for what's used for the activate control, see the control codes So far so good, but we still couldn't store those strings anywhere or edit them through script other than by entirely retyping them. That's where string vars come in. 2. STRING VARIABLE BASICS: DECLARING AND INITIALIZING Just like a reference variable refers to a reference or form, and a float variable refers to a floating point number, string variables refer to a string. Duh, you might say, but it's important to remember that they themselves are not strings, which is why I make it a point not to use the word 'string' when I mean 'string var'. We already had strings, string vars to store and manipulate them are what's new. The actual strings that the string vars refer to are stored in the .nvse file that corresponds to your save file. You declare a string variable like this: string_var somestringvariablename (A note about naming conventions: most scripters prefix their variable names like float fSomeFloat, ref rSomeForm to remember what they really refer to. Some do the same with string vars and use the 's' prefix (sSomeStringVar) but I'd advise against that, because there are hundreds of string-based game settings that use that same convention and you're bound to have conflicts. Personally, I use the 'sv_' prefix a lot, or none at all. Of course, there is the possibility of a conflict with the string var functions, which also have that prefix, but there are only a handful of them. Anyway, your choice, just watch out.) Declaring a string var doesn't mean it actually refers to a string yet, it's the same with them as with other script variables: if you don't bother to set a ref var to something, it refers to nothing at all, and if you perform a function on nothing at all, you get squat or even crash. Making a string var refer to a string is called 'initializing' it, and you do this by either: - 'letting' it to a formatted string, - 'letting' it to a string var, or - 'letting' it to a function that is supposed to return a string (including UDFs that return a string or stringvar with SetFunctionValue). let sv_mystringvar1 := "I'm a string" ; compare with: let rRefVar := DocMitchellRef let sv_mystringvar2 := sv_mystringvar1 ; compare with: let rRefVar2 := rRefVar1 let sv_mystringvar3 := player.GetName ; compare with: let rRefVar := GetActionRef You can also still use the format specifiers when initializing, although this has you revert to an antiquated way of initializing strings by using sv_construct: let sv_mystringvar := sv_construct "I'm string number %.0f" someInt let rForm := Pencil01 let sv_mystringvar := sv_construct "Got a %n?" rForm (Note that for passing numbers and names of things into strings, it's often much easier to just use ToString, see the chapter on that.) If a string var is not initialized it returns the numeric value 0. That's the only time string vars and numbers can mix: never set a string var to a number, never set a float var to a string var or a string. In order to check if a string var is initialized or not before you use it for something, you can go: if sv_mystringvar ; do stuff with your initialized string var else ; you haven't initialized endif if eval !(sv_mystringvar) ; ! means LogicalNot ; you haven't initialized endif Of course, if you know you've initialized it, there's no point. 3. 'LET' V. 'SET' SYNTAX String vars were introduced to OBSE right before the 'let' and 'if eval' syntax was introduced, so keep in mind that most of the explanations in the obse docs about them are still based on the pre-'let' era. Before you could simply go 'let sv_mystringvar := "I'm a string"' you had to go 'set sv_mystringvar to sv_construct "I'm a string"'. With 'let', the sv_construct function is entirely unnecessary, and to keep things straightforward I will never mention "set" equivalents to ways of doing things if there is no need for them. Use "let", seriously. The main reason I'm frowning on the 'set' way is that if you 'set' a string var to another they actually refer to the same string, and changing one of them will automatically change the other one too: script console readout string_var sv_string1 string_var sv_string2 set sv_string1 to sv_construct "I'm string 1" printc "string1 says '%z'" sv_string1 --> string1 says 'I'm string 1' set sv_string2 to sv_string1 printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1' set sv_string1 to sv_construct "I'm a different string now" printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now' printc "string2 says '%z'" sv_string2 --> string2 says 'I'm a different string now' set sv_string2 to sv_construct "In that case, I'm changing too" printc "string1 says '%z'" sv_string1 --> string1 says 'In that case, I'm changing too' printc "string2 says '%z'" sv_string2 --> string2 says 'In that case, I'm changing too' and in order to make sure that didn't happen, you had to this to make sv_string2 refer to a copy of sv_string1's string, rather than the same one: set sv_string2 to sv_construct "%z" sv_string1 and that was pretty much the only way of 'cleanly' copying a string var's contents to another. When you 'let' a string var to another one, however, it will refer to a copy of the first's string rightaway, and if you later change something about either of them, the other one will remain intact: script console readout string_var sv_string1 string_var sv_string2 let sv_string1 := "I'm string 1" printc "string1 says '%z'" sv_string1 --> string1 says 'I'm string 1' let sv_string2 := sv_string1 printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1' let sv_string1 := "I'm a different string now" printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now' printc "string2 says '%z'" sv_string2 --> string2 says 'I'm string 1' let sv_string2 := "In that case, I'm changing too" printc "string1 says '%z'" sv_string1 --> string1 says 'I'm a different string now' printc "string2 says '%z'" sv_string2 --> string2 says 'In that case, I'm changing too' In my view, the 'set' way not only involves more typing, but is more dangerous, in that people may accidentally lose the contents of a string that they didn't mean to overwrite. And let's face it: why have 2 string vars around that'll always be the exact same thing? You're much more likely to want to copy one and then change one of the 2, than to want to have duplicates of the same thing all the time. The same difference applies, btw, if you 'set' or 'let' string vars to the values returned by functions like GetName, increasing the chance of accidental fuck-ups with 'set'. 4. DESTROYING STRING VARS With regular vanilla script variables (ref float int short long), you don't need to worry about them after you've used them. If you stuck them in a quest script, you meant to keep them around indefinitely until your mod's uninstalled; if they're part of an object or spell script that doesn't run anymore, they simply disappear from view - you don't need to erase them. It's different with string variables, whose strings keep lingering in the .nvse files even if the script they were in doesn't run anymore. They are forcibly removed when your mod is uninstalled, but in the meantime they cause a bit of bloat, so be sure to remove/uninitialize/destroy them yourself as soon as you don't need them anymore by going sv_destruct MyStringVar You can destroy up to 10 different ones in the same line like that: sv_destruct stringvar1 stringvar2 stringvar3 stringvar4 stringvar5 stringvar6 stringvar7 stringvar8 stringvar9 stringvar10 As you may remember from the UDF tutorial, string vars are also the only UDF local variables that you need to destruct yourself. 5. CHECKING STRING VARS With 'if eval' syntax, checking whether a string var is the same as another, or the same as a string, is as simple as if eval sv_stringvar == "some string" if eval sv_stringvar1 == sv_stringvar2 and you can use != too for inequality. Before that, you had to check the int value returned by the sv_compare function if you wanted to compare a string var to a string: if 0 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool ; they are the same elseif 1 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool ; the string var's string occurs before the string, alphabetically speaking elseif -1 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool ; the string var's string occurs after the string, alphabetically speaking elseif -2 == sv_compare "some string" FormatSpecVars sv_stringvar bCaseSensitiveComparebool ; none of the above, the compare 'fails' endif Not much point in using sv_compare, now that we have the "if eval" alternative, except if you're really interested in the alphabetical comparison. These comparisons are case-insensitive, unless you use that bool with sv_compare. 6. PASSING STRING VARS AS PARAMETERS: TOSTRING ($) If a vanilla or NVSE function takes one or more formatted strings as parameters DebugPrint "I'm a string" MessageEX "I'm a string" SetModelPathEX "Clutter\Junk\WhetStone.NIF" NX_SetEVFl "some nx key string" someFloat NX_SetEVSt "some nx key string" "some string value" you can force them to take a string variable as parameter instead with the ToString function, in short: $ DebugPrint $sv_stringvar MessageEX $sv_stringvar SetModelPathEX $sv_stringvar NX_SetEVFl $sv_keystringvar someFloat NX_SetEVSt $sv_keystringvar $sv_valuestringvar There are a few functions, especially fallout-specific ones and ones that are injected with NVSE plugins like MCM, that may not seem to work with ToString + string var that way - this is because they probably haven't been prepped for that. If you think this is the case in your script, try using the script compiler override, which should force it. The ToString function can also return a string representation of numbers and forms, ie pass them to a string: It will return the name of a form if the form has a name: let rRef := DocMitchellRef let sv_name := $rRef printc "%z" sv_name --> displays 'Doc Mitchell' Or its hex FormID if it doesn't: let rRef := BlackBoardMarker let sv_name := $rRef printc "%z" sv_name --> displays '00002FCC' Numbers: let iInt := 32 let sv_name := $iInt printc "%z" sv_name --> displays '32' 7. CONCATENATING STRING VARS, OR: ADDING THEM UP Easy : + let sv_stringvar := "String1" + "String2" printc "%z" sv_stringvar --> reads: 'String1String2' let sv_stringvar := Player.GetName + "'s chair" rChairRef.SetName $sv_stringvar --> reads 'Prudencia's chair' because that's my test char's name note: names are usually defined on the base form, and setting them will set them on the base form too When adding strings up, you may run into some limitations of passing variables into strings with format specifiers in the context of an addition: let sv_stringvar := "First Part:" + playerref.GetName + ":" + "%.0f" iSomeInt let sv_stringvar := "First Part:" + "%n" rSomeForm will make warnings pop up and not compile. Luckily ToString is there, once again saving the day a lot of times: let sv_stringvar := "First Part:" + playerref.GetName + ":" + $iSomeInt let sv_stringvar := "First Part:" + $rSomeForm will be fine. And if you can't do it in one line and can't use ToString, sometimes you just gotta do it in two or involve sv_construct again: let sv_stringvar := sv_construct " is scratching %pp balls" rSomeRef ; had to add the sv_construct there to make the %pp specifier work let sv_stringvar := $rSomeRef + $sv_stringvar And you can also get some traction out of the sv_Insert function: sv_insert "Some String" FormatSpecifierVars String_VarToInsertTheStringIn PositionToInsertAtInt let sv_stringvar := " balls must itch something fierce" sv_insert "%pp" rSomeForm sv_stringvar 0 or sv_insert "%pp" rSomeform sv_stringvar ; we want to insert it at the very first character of the stringvar's string, which is position 0 (like with formlists and arrays) ;if the position is 0 we can leave out that parameter, really 8. MEASURING AND SEARCHING YOUR STRING VARSsv_Length returns the length of a string var's string: let iSomeInt := sv_length sv_stringvar Since the start position is always indexed at 0, the end position will always be (sv_length sv_stringvar) - 1. sv_Find finds the first occurrence of a substring in a string, and returns the position as an int: let iSomeInt := sv_Find "substring" FormatSpecifierVars SourceStringVar StartPositionInt SearchLengthFromStartPosInt CaseSensitiveSearchBool ; leave out the parameters if you don't need them let sv_stringvar := "This is example 3" let iSomeInt1 := sv_Find "example %.0f" someInt2 sv_stringvar ; --> will return 8 if someInt2 is 3 sv_Count returns just how many instances of a substring a string contains: let sv_stringvar := "Ain't no sunshine when she's gone. And she's always gone too long." let iSomeInt := sv_Count "gone" sv_stringvar --> returns 2 9. BREAKING STRING VARS DOWN, REPLACING BITS, AND REASSEMBLING THEM The most straightforward way of taking chunks out of a string var's string is by using sv_Erase: sv_erase stringvar StartPositionInt NumberofCharacterstoEraseInt ; StartPositionInt: if you leave that out we'll start at position 0 ; NumberofCharacterstoEraseInt: if you leave that out we erase everything from the start position to the end scn CensorshipScpt let sv_stringvar := "I fucked up." sv_erase sv_stringvar 2 6 --> 'I up.' sv_insert "messed" sv_stringvar 2 Or you can replace a chunk of a string with another with sv_Replace: sv_replace "texttoreplace|texttoreplacewith" FormatSpecVars SourceStringVar StartPositionInt SearchLengthFromStartPosInt CaseSensitiveBool NumberofOccurrencestoReplaceInt ; don't use what you don't need sv_replace "fucked|messed" sv_stringvar bit more complicated version: scn Variety let sv_stringvar := "That motherfucking fuckhead fuckin' fucked me over. Fuck!" sv_replace "fuck|dick" sv_stringvar 19 38 1 1 The only 'fuck' that is replaced there is in 'fuckhead', and the same goes for sv_replace "fuck|dick" sv_stringvar 19 4 If elements of a string are separated by a common character, like a space or backslash, sv_Split can split them up for you and return them as string values to an array: let sv_stringvar := "This is a sentence." let somearray := sv_Split sv_stringvar " " ; the 'delimiter', what separates the string, is the 'space' that I stuck in that format string, you can have several characters be delimiters at once and then ar_dump somearray will return [ 0.000000 ] : This [ 1.000000 ] : is [ 2.000000 ] : a [ 3.000000 ] : sentence. Each of those values being strings. Example 1: Let's say you have clothing meshes for a particular body corresponding to some vanilla ones, and want to switch them out in-game through script: if vanilla's have filepaths like these: armor\LegateArmor\LegateArmor.NIF and yours have filepaths like these: armor\MyModFolderName\LegateArmor\LegateArmor.NIF then you'd go about it like this: let sv_filepath := GetBiPedModelPath 0 ArmorLegate --> 'armor\LegateArmor\LegateArmor.NIF' let ar_paths := sv_Split sv_filepath "\" --> ar_paths[0] is "armor", ar_paths[1] is "LegateArmor", ar_paths[2] is "LegateArmor.Nif" let sv_newfilepath := ar_paths[0] + "\MyModFolderName\" + ar_paths[1] + "\" + ar_paths[2] ; you'll probably need the compiler override on to add that up SetBiPedModelPathEX $sv_newfilepath 0 ArmorLegate Note that I used the 0 parameter to get the male mesh, and the 'object' calling convention rather than the reference calling convention (ArmorRef.GetBiPedModelPath 0), so that code switches out the filepaths for the base form. Maybe get in a TempCloneForm or something in between. You may notice that at no point do I really need to know the specific filepaths, just that I need to insert a foldername after the first section ('armor'), so ArmorLegate can just as easily be a ref var holding whichever armor retrieved by GetEquippedObject or some such, as long as the new filepath is otherwise the same. Example 2: spend some time in the fallout sections on LL and you're bound to run into mentioning of NX vars, which take a format string for the function key: let fSomeFloat := rSomeRef.NX_GetEVfl "Some key string" rSomeRef.NX_SetEVfl "Some key string" fSomeFloatValue Those keys being format strings, you can use the ToString symbol to force the nx functions to take a string variable as a key: let fSomeFloat := rSomeRef.NX_GetEVFl $somestringvar You'll probably build your keys like "MyModNameString:SomeKeyString:SomeOptionalSubKeyString" (and those colons would be a good delimiter for sv_split), but of course, typing is a drag, and sometimes you want to build nx keys dynamically, on the fly, without knowing how many you need. Let's say we want to keep tabs on the specific combination of clothing items we have equipped, in order to store the combo: let iNum := -1 while (iNum += 1) < 20 ; check equipment slots 0-19 let rForm := playerref.GetEquippedObject iNum if rForm let sv_keystring := "OutfitMod:OutfitSet:" + "1:" + "Slot:" + $iNum playerref.NX_SetEVFo $sv_keystring rForm endif loop and equipping that later on would be something similar: let iNum := -1 while (iNum += 1) < 20 let sv_keystring := "OutfitMod:OutfitSet:" + "1:" + "Slot:" + $iNum let rForm := playerref.NX_GetEVfo $sv_keystring if rForm if playerref.getitemcount rForm playerref.EquipItem rForm endif endif loop And I could have different sets if I replaced this: let sv_keystring := "OutfitMod:OutfitSet:" + "1:" with let sv_keystring := "OutfitMod:OutfitSet:" + $someInt + ":" Depending on what you're wearing, and how many slots each item has flagged, you can have any number of those EVFo variables set on your character. The fact that you just don't know and would otherwise have to type that out in x elseif conditions, makes this another prime example of why string vars are so useful, being editable. Here's hoping someone revises MCM to use some of that, right? 10. SWITCHING BETWEEN STRING AND OTHER REPRESENTATIONS, CHARACTER FUNCTIONS I'm not spending too much time on these, this has gotten pretty lengthy already I'm just pooling them together here because they're all over the place in obse docs. Just a few basics: you know the ToString function by now, and it's turned out to be pretty handy. It has a ToNumber counterpart (short: #), which will try to pass a number that's in a string to a float/int: let sv_somestringvar := "34.5" let fFloat := ToNumber sv_somestringvar let fFloat := #sv_somestringvar --> fFloat will be 34.5 It can also do this with hex numbers kept in a string if you add the hex bool parameter, or if the string started with "0x", which can catch a dynamically created ref. let sv_somestringvar := "00000ADE" let fFloat := ToNumber sv_somestringvar 1 NumToHex, in turn, converts an int into a hex string, with a default width of 8 characters, although you can specify that as a parameter: let iInt := 2782 let sv_somestringvar := NumToHex iInt --> "00000ADE" let sv_somestringvar := NumToHex iInt 4 --> "0ADE" To get some operations done at the level of single characters, you need to pass a character from a string to its ascii code, which you can do with sv_GetChar: let iSomeInt := "somestring" somePosInt let iSomeInt := sv_GetChar "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ.,:" 4 --> will return 53, which is the ascii code for 5, at pos 4 in our string If our string is a single character, we can just use CharToAscii let sv_somestringvar := "5" let iSomeInt := CharToAsci sv_somestringvar --> again, 53 Once passed to its ASCII code, you can check the type of the character with the boolean IsDigit, IsLetter, IsPunctuation and IsPrintable functions. You can also switch between upper and lower case with ToUpper and ToLower. And then return that ASCII code int back to a string, with ASCIIToChar: let sv_SomeStringVar := AsciiTochar 53 --> "5" let iSomeInt := ToLower 65 ; 65 is A --> iSomeINt = 141 let sv_SomeStringVar := AsciiToChar iSomeInt --> "a" If you want to perform such functions and checks on each character in a string, rather than one you retrieve from its position with sv_GetChar, you can use a foreach loop, which passes each character to a string var, the iterator, that holds it for the duration of the loop body: foreach sv_iterator <- "SomeString" ; or: foreach sv_iterator <- somestringvar ; do stuff to sv_iterator, which will contain one character for each loop run going from position 0 to end loop The "Break" and "continue" commands, which you might remember from while loops, apply here too. See the array var tutorial for more information on foreach loops. And now that we're talking int codes anyway, GetKeyName (aka GetKey) will return the string for a keyboard key if you pass the directx scan code as an int parameter: let sv_somestringvar := GetKeyName 1 --> "Escape" which I suppose can be handy for different localizations, or for situations where the %k format specifier doesn't suffice. And that's it. Trust me, you'll rarely need to use all of these functions, just be sure to be clear on the basics, and know what your options are.
zippy57 Posted February 9, 2014 Posted February 9, 2014 Is there any way to use a string variable in notes and dialogues like you can use &PCName?
DoctaSax Posted February 9, 2014 Author Posted February 9, 2014 I wish Although for Notes, Terminal text, and even Messages/MessageBoxes in the object window, that's probably a case of coming up with functions to do whatever EX does with other functions like MessageBoxEX and the like. Dialog... I don't think that can really work.
DoctaSax Posted February 10, 2014 Author Posted February 10, 2014 I just remembered, it's not quite the same but the Enhanced Economy mod for Oblivion does set up quests dynamically, and the quest giver's text is therefor also dynamically created, but that's done with a messagebox that's superimposed over the dialog window, not dialog itself.
jaam Posted February 10, 2014 Posted February 10, 2014 Is there any way to use a string variable in notes and dialogues like you can use &PCName? I thiink I found were to insert them in dialogue. Did not take the time to test the theory yet.
DoctaSax Posted February 10, 2014 Author Posted February 10, 2014 Added a little bit about foreach loops with string vars under the last section.
nyaalich Posted March 13, 2014 Posted March 13, 2014 @jaam: Did you ever test your theory about using strings in dialogue?
Odessa Posted May 30, 2014 Posted May 30, 2014 You don't need to sv_Destruct strings that are stored in arrays, right? This is enough?: let aArray := ar_List "the", "cat", "sat", "on", "the", "mat" let aArray := ar_Null
DoctaSax Posted May 30, 2014 Author Posted May 30, 2014 You don't need to sv_Destruct strings that are stored in arrays, right? This is enough?: let aArray := ar_List "the", "cat", "sat", "on", "the", "mat" let aArray := ar_Null Yeah, as far as I can tell sv_destruct is only for strings stored in string vars.
Guest tomm434 Posted June 4, 2014 Posted June 4, 2014 Is there any way to use a string variable in notes and dialogues like you can use &PCName? You can always do it manually and have fun with dialogues. String_var PlayerName Begin Function {} let PlayerName := player.GetName if eval PlayerName == "Courier" set aaalunetteref.PlayerName to 1 printC "Player name is Courier" elseif eval PlayerName == "Dumbass" set aaalunetteref.PlayerName to 2 printC "Player name is Dumbass" else PrintC "player name is not in list" endif end
Guest tomm434 Posted June 4, 2014 Posted June 4, 2014 Doctasax, Why can't I complile string? I followed your tutorial. let rForm := Pencil01 let sv_mystringvar := "Got a %n?" rForm My code is ref Cell String_var CellString Begin gamemode let Cell :=Player.GetParentCell PrintC "%n" Cell PrintC "%i" Cell let CellString := "%i" Cell PrintC "%z" CellString I want to put ID of the cell into string (for exterior cells) and GECK says that "let CellString := "%i" Cell" line has more args that needed. I can't use $Cell because every cell has a name.
DoctaSax Posted June 4, 2014 Author Posted June 4, 2014 Ah, maybe I just supposed that'll work because it did during the early days when I used sv_construct (too much) Try either: let CellString := ("%i" Cell) or let CellString := sv_construct "%i" Cell In fact, why don't you try both
Guest tomm434 Posted June 4, 2014 Posted June 4, 2014 Ah, maybe I just supposed that'll work because it did during the early days when I used sv_construct (too much) Try either: let CellString := ("%i" Cell) or let CellString := sv_construct "%i" Cell In fact, why don't you try both First one compilies but breaks the script Seconds one works flawlessly, thanks!
prideslayer Posted June 24, 2014 Posted June 24, 2014 Just an fyi for those of you looking at sv_replace. The first argument must be a string literal or a $-prefixed string var, it can't be a raw string var. string_var svLeft string_var svRight string_var svMerge string_var svTarget ; ... let svLeft := "foo" let svRight := "bar" let svMerge := svLeft + "|" + svRight ; Example 1, works let svTarget := "my foo thing" sv_replace "foo|bar" svTarget ; svTarget now == 'my bar thing' ; Example 2, works let svTarget := "my foo thing" sv_replace $svMerge svTarget ; svTarget now == 'my bar thing' ; Example 3, does NOT work let svTarget := "my foo thing" sv_replace svMerge svTarget ; svTarget unchanged Just FYI.
Xilandro Posted June 28, 2014 Posted June 28, 2014 And I was sure that I know a lot about strings, lol =D Thanks again for one more great tutorial, found a lot of extremely useful information. And a little question. Trying to add ascii codes of the each character into an array with "ForEach", and no cigar. Characters works fine, but when I try to make them an ascii - something is going bad. string_var sv_SomeChar Let Array1 := Ar_Construct Array ForEach sv_iterator <- $Targetref Let sv_SomeChar := CharToAscii sv_iterator Ar_Append Array1 sv_SomeChar Loop Ar_Dump Array1 Array have empty elements. Something like this [ 0.000000 ] : [ 1.000000 ] : [ 2.000000 ] : [ 3.000000 ] : Tried to use integer int iSomeChar Let Array1 := Ar_Construct Array ForEach sv_iterator <- $Targetref Let iSomeChar := CharToAscii sv_iterator Ar_Append Array1 iSomeChar Loop Ar_Dump Array1 returns [ 0.000000 ] : -1 [ 1.000000 ] : -1 [ 2.000000 ] : -1 [ 3.000000 ] : -1 and even "ToNumber" didn't help: string_var sv_SomeChar Let Array1 := Ar_Construct Array ForEach sv_iterator <- $Targetref Let sv_SomeChar := CharToAscii sv_iterator Ar_Append Array1 #sv_SomeChar Loop Ar_Dump Array1 [ 0.000000 ] : 0 [ 1.000000 ] : 0 [ 2.000000 ] : 0 [ 3.000000 ] : 0 What exactly I'm doing wrong? Upd this code will do the job, but still don't understand why CharToAscii didn't =\ Let Array1 := Ar_Construct Array ForEach sv_iterator <- $Targetref set iSomeInt to sv_GetChar sv_iterator 0 Ar_Append Array1 iSomeInt Loop Ar_Dump Array1
Odessa Posted June 28, 2014 Posted June 28, 2014 You can do foreach on strings? I don't think I've seen that documented anywhere, but makes sense. Awesome. I think this is why it doesn't work (note: this is kind of a logical guess): CharToAscii only works on a single char. ForEach sv_iterator <- $Targetref Let sv_SomeChar := CharToAscii sv_iterator sv_iterator is not a single char, it is a string containing both key and value. When you do this: sv_GetChar sv_iterator 0 You get a single char (the first, aka 0) from the string, so it works. -- (@DoctaSax: I got around to translating this tutorial to the GECK wiki, haven't done the others yet)
Xilandro Posted June 28, 2014 Posted June 28, 2014 sv_iterator is not a single char, it is a string containing both key and value. Yeah, it does make sense. I was tricked with single characters in array, and I thought that I can charToAscii before appending char into an array. Thank you for explanation =)
DoctaSax Posted June 28, 2014 Author Posted June 28, 2014 Actually, I don't think a foreach loop in a string or string var bothers with "key" and "value" - that's just specific to arrays. What's going on there, I feel, is that sv_getchar is rigged to accept a string var as parameter - being an sv function after all - while chartoascii isn't (obse docs have it as accepting 'strings', not string vars) and so probably needs ToString in front of the string var: Let iSomeChar := CharToAscii $sv_iterator sv_GetChar is marked as deprecated in obse docs, because we're supposed to just as easily do let char := str[pos] and then, I guess, use chartoascii on "char" if my hunch about tostring is correct. In this case, I like the depecrated function better, doing both in one line and sparing an extra string var. The use of bracket notation on string vars is something that passed me by a bit. Someone adventurous may wanna test what it can do in terms of adding to & replacing characters in strings.
Odessa Posted June 28, 2014 Posted June 28, 2014 Why do you need to put the chars into an nvse array? Couldn't you just leave them as a string? Assuming you can do str[pos] just like arr[pos]?
DoctaSax Posted June 28, 2014 Author Posted June 28, 2014 Yeah, str in str[pos] is meant to be a string var.
Xilandro Posted June 28, 2014 Posted June 28, 2014 Wow, so I can skip all the array and foreach stuff just with str[pos]? o_O This is so awesome! I need to test it right now. Soon my script will be like "begin, 2 lines of code that do all the facny stuff, end" =D Thank you good people for helping me^^
Guest tomm434 Posted July 20, 2014 Posted July 20, 2014 I got to ask - if I have string variable as function parameter -do I have to destroy it manually? String_var SexType Begin function{SexType} player.NX_SetEVFl "Sexout:Start::CallVer" 1 if eval SexType == "Oral" player.NX_SetEVFo "Sexout:Start::ActorA" Raider player.NX_SetEVFo "Sexout:Start::ActorB" playerREF player.NX_SetEVFl "Sexout:Start::isOral" 1 player.NX_SetEVFo "Sexout:Start::CBDialogA" aaaraidersOralafter end This code executes often. Do I have to destroy "SexType" every time?
DoctaSax Posted July 20, 2014 Author Posted July 20, 2014 Since it's a parameter to your UDF, you shouldn't have to. But it has to be destroyed in the calling script when you're done with it.
Guest tomm434 Posted July 20, 2014 Posted July 20, 2014 How exactly can I do that? The code from calling script is call aaraiderFunctionSex Oral And this string is only present in function.
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