DoctaSax Posted February 7, 2014 Posted February 7, 2014 Don't you just hate to see your scripts packed with chunks of code that rarely ever need to run, on the off chance that some condition is met? To see most of your script's body plastered all across the editor window at 5 levels of indentation? Or to see yourself repeating chunks of code all the time for each time it applies, until you hit your max script size limit? Jesus, what a drag! Don't you just wish, sometimes, you could outsource some of that - but then, setting up new spell or quest scripts for one-time-only code is just way more trouble than it's worth, spells only really work in gamemode, and quest stage result scripts can't handle complicated code or loops. Not to mention you have to copy across any vars via a quest script, copying that shit twice, with again a lot of code lines being spent on just that!Well, no more.NVSE4+ comes with the ability to set up your own functions, in the form of scripts that you call in when you need them: call SomeFunction Who you gonna call? Some Function! Case in point: if you've got settings in your mod, eg like with an MCM menu, you need to set the default values of the various variables it refers to when the mod is first installed, and if you buildref stuff you need to do buildref that stuff every time a new gaming session starts just in case there was a load order change. So far, people've tended to stick that in their main quest script, which is supposed to run all the time anyway, depending on an iInit or bDoonce variable. Begin GameMode if iInit == 0 ; code that only has to run the first time a mod is ever loaded    set Var1 to someValue    set Var2 to someValue    set Var3 to someValue    etc etc    set iInit to 1 elseif iInit && fVersion < somefloat ; code that only runs on a mod update      if Var1 < someValue       ; do stuff       if someActor.GetAV someActorValue > someValue          ; do stuff       endif    else       ; do stuff       if somecondition || (somecondition && somecondition)          ; do stuff       endif    endif    set fVersion to someFloat elseif iInit && (GetGameLoaded || GetGameRestarted) ; code that only has to run once on each game load    if IsModLoaded "SomeMod"       set iModIndex to GetModIndex "SomeMod"       set rRef to BuildRef iModIndex someDecimalNumber    endif    if IsModLoaded "SomeOtherMod"       ; etc.    endif endif ; finally, the actual chunk of script that does need to run all the time Now, I don't know about you, but I can't stand the thought of that code being processed throughout a gaming session when it's not needed and just skipped, being dead weight. Of course, as said above, you could splice off some of that with old-school methods, but how about parking those chunks in a UDF instead?   1. BASIC UDF STRUCTURE & CALLING A UDFYou create a UDF by opening a brand new object script. Do not attach it to anything; UDFs are scripts that are called directly, you don't need to stick it to an item or NPC, in fact, you really shouldn't. They are free-floating scripts in the geck's object window, and if you right-click on them and select "use info", the only thing that should appear in that window are the scripts that call them.UDFs can only have one script block: a Function block. scn MyFirstInitFunction ; the script name will be what you "call" in the calling script ; variables ; all variables need to be declared before the block begins (in UDFs it's obligatory, in other scripts it's just stupid not to) Begin Function {} ; don't forget those accolades set Var1 to someValue set Var2 to someValue set Var3 to someValue set Var4 to someValue ; etc End scn MyUpdateInitFunction ; variables Begin Function {} if Var1 < someValue    ; do stuff    if someActor.GetAV someActorValue > someValue       ; do stuff    endif else    ; do stuff    if somecondition || (somecondition && somecondition)       ; do stuff    endif endif let MyQuestID.fVersion := someFloat End scn MyOnEveryLoadInitFunction ; variables Begin Function {}    if IsModLoaded "SomeMod"       set iModIndex to GetModIndex "SomeMod"       set rRef to BuildRef iModIndex someDecimalNumber    endif    if IsModLoaded "SomeOtherMod"       ; etc.    endif    End and then your main script would only have to spend this on your inits: scn MyMainQstScript int iInit Begin GameMode if iInit == 0    call MyFirstInitFunction elseif iInit && fVersion < someFloat    call MyUpdateInitFunction elseif iInit && (GetGameLoaded || GetGameRestarted)    call MyOnEveryLoadInitFunction endif ; your actual main script End Nice and tidy, huh? When that quest script runs and encounters a UDF it should call, it stops what it's doing, runs the UDF and then returns to the exact same spot to pick up where it left off - all in the same frame. And if the condition doesn't apply, all it has to do is skip that one line.Well, that's just the beginning. Right now we've only used these UDFs as code holders, just to have simpler, more readable scripts; let's start using them as proper functions. They're not called user-defined functions for nothing.Vanilla has quite a variety of function types. Some of them can/have to be called on a reference (reference functions, like moveto or enable), others not (like IsHardCore, IsPC1stPerson). Some of them return a float (eg the math functions, or GetEquipped) or reference (eg GetActionRef), others don't return anything (enable, disable). Some of them take or require parameters (GetAV), others not (GetCurrentAIPackage). UDFs can do any of that too, or not, depending on what you want.   2. CALLING UDFS ON A REFERENCE & NESTING UDFSIn the examples above, I didn't call my UDFs on a reference because there was no point. What happened there is similar to what would've happened if I'd called let's say a quest stage result script, a one-frame script doing something in general. But if you want your UDF to do something to a reference, or retrieve information from it, then you call it on a ref just like any other reference function. BuddyRef.call SomeFunction scn SomeFunction Begin Function {} CIOS SomeSpell ; this spell will be cast on BuddyRef End As you can see, right now the UDF works as a one-frame-only object script attached to Buddy Ref, or a spell script cast on BuddyRef: the implied reference is the reference the UDF was called on. (In fact if you want to display the reference it's called on in a debugprint readout, you'll find it with the GetSelf function.) And if the UDF includes a call to another UDF, it carries that relationship across: BuddyRef.call someFunction1 scn SomeFunction1 Begin Function {} ; do other shit call SomeFunction2 End scn SomeFunction2 Begin Function {} CIOS SomeSpell ; this spell is still cast on BuddyRef End Whether called on a reference or not, you can nest up to 30 UDFs like that, although I think that's a bit overkill and you should really reconsider your overall mod structure  Also, a UDF can call itself - if you comment out the line that does it and compile it first.3. RETURNING VALUES FROM A UDFIf you choose, you can let a UDF return a value, which can be a number, a form, a string, or an array. To do that, you use the SetFunctionValue function: SetFunctionValue fSomeFloat SetFunctionValue 3 SetFunctionValue rSomeRefVar SetFunctionValue playerref SetFunctionValue Scotch SetFunctionValue sv_SomeStringVar SetFunctionValue "An actual string" SetFunctionValue ar_SomeArrayVar and of course, set up the calling script to catch that value properly: let fSomeFloat := call MyUDF let iSomeInt := call MyUDF let fSomeFloat := 1 + (call SomeUDF) * 3 ; which will obviously only work if the UDF returns a number let rSomeRefVar := call MyUDF let sv_SomeStringVar := call MyUDF let ar_SomeArrayVar := call MyUDF so in the case of my version update UDF I could've done this: scn MyMainQstScript ... elseif iInit && fVersion < somefloat    let fVersion := call MyUpdateInitFunction elseif ... scn MyUpdateInitFunction ; variables Begin Function {} if Var1 < someValue    ; do stuff    if someActor.GetAV someActorValue > someValue       ; do stuff    endif else    ; do stuff    if somecondition || (somecondition && somecondition)       ; do stuff    endif endif SetFunctionValue someFloat End for the same effect. It makes sense for you to do that near the end of your UDF, although to be sure, that just depends on the structure. scn MyUDF Begin Function {} if somecondition    SetFunctionValue someFloat    return elseif someothercondition    SetFunctionValue someOtherFloat endif End See that return command there? As in other scripts, it breaks off the script, and because a UDF is a one-time-only script, that means we return straight to the calling script. Obviously you try to put the simpler, faster condition checks near the top of your UDF so you can "return" before you hit the more complicated code if it isn't required to run it. Same as with everything else.    4. PASSING PARAMETERS TO UDFSBy now, you must've wondered what the deal is with those accolades behind the Function block command. Well, vanilla functions are hardcoded to take parameters or not, but NVSE obviously can't know if you mean to pass parameters at all, or how many, or which ones, or in what order, until you specify that yourself. That's what those accolades are for.You specify parameters by declaring variables, and sticking them between those accolades: scn MyUDF float fFloat1 int iInt ref rForm1 ref rForm2 string_var sv_somestring1 string_var sv_somestring2 array_var ar_somearray ; your UDF's local variables go here Begin Function {fFloat iInt rForm1 rForm2 sv_somestring1 sv_somestring2 ar_somearray} ; do stuff with all of that End scn MyCallingScript Begin SomeBlock call MyUDF fSomeFloat 4 someRefVar playerref sv_somestringvar "I'm a string" ar_somearray End As you can see you can use actual values or the variables for the parameters when you call the UDF, as long as the variables on the UDF's end can "catch" them, ie a float variable can catch both an actual number and another float variable, a string var both a string var and an actual string. It was the same in the opposite direction with SetFunctionValue.Once those UDF variables are declared as parameters by sticking them between those accolades, you will be required to specify that exact same number of parameters in the function call, in exactly that order of types, ie call MyUDF fSomeFloat rSomeRef rSomeRef playerref sv_somestringvar "I'm a string" ar_somearray call MYUDF fSomeFloat 4 rSomeRef playerref sv_somestringvar "I'm a string" will both not work, the first because the second parameter is supposed to be an int and you're passing a ref, the second because the array parameter's missing.Example 1: A pretty simple one from the obse docs this time: ScriptName Multiply float arg1 float arg2 ; I like to leave a blank line between parameter vars and local vars, to keep things clear float localVar   ; a local variable Begin Function {arg1, arg2}      ; function body, with parameter list in {braces}    Let localVar := arg1 * arg2    SetFunctionValue localVar   ; this is the value that will be returned End and the calling script can be: float someVar Let someVar := Call Multiply 10 5 Example 2: Some vanilla functions take formlists as parameters, but a whole lot don't. IsSpellTarget is one of them. scn MyUDF ref rList int iCount ref rSpell Begin Function {rList} let iCount := ListGetCount rList while (iCount -= 1) >= 0    let rSpell := ListGetNthForm rList iCount    if IsSpellTarget rSpell       SetFunctionValue 1       break    endif loop End and then the calling script would be something like: if rActor.call MyUDF BoozeList    ; actor is drunk, omg, do something endif if rActor.call MyUDF DrugsList    ; actor is high, omg, do something endif Note: in this case it'd be in our best interests to stick the most commonly used drinks / drugs at the end of our formlist, right?  Example 3: Let's say we're tired of typing out the particulars to a Sexout act in every dialog result script in our mod: rActor1.NX_SetEVFl "Sexout:Start::CallVer" 1 rActor1.NX_SetEVFo "Sexout:Start::ActorA" rActor2 rActor1.NX_SetEVFo "Sexout:Start::ActorB" rActor1 rActor1.NX_SetEVFl "Sexout:Start::IsOral" 1 rActor1.NX_SetEVFl "Sexout:Start::Anim" 201 rActor1.CIOS SexoutBegin type, type, type... We could just write ourselves this UDF: scn StartSexin ref rActorA ref rActorB int isOral int isVaginal int isAnal int iAnim Begin Function {rActorA rActorB isOral isVaginal isAnal iAnim} NX_SetEVFl "Sexout:Start::CallVer" 1 NX_SetEVFo "Sexout:Start::ActorA" rActorA NX_SetEVFo "Sexout:Start::ActorB" rActorB NX_SetEVFl "Sexout:Start::IsOral" isOral NX_SetEVFl "Sexout:Start::IsVaginal" isVaginal NX_SetEVfl "Sexout:Start::IsAnal" isAnal NX_SetEVFl "Sexout:Start::Anim" iAnim CIOS SexoutBegin End and only have to do something like this in the calling script: BuddyRef.call StartSexin BuddyRef playerref 1 0 0 201 or BuddyRef.call StartSexin BuddyRef VeronicaRef 0 1 0 605 Shucks, we could expand this with the refSufarce, fSurfaceX/Y/Z/Angle, and RefMoveA/BTo variables as well. You can stipulate up to 10 parameters to a UDF (15 as of NVSE 4.5 beta 1). 5. WHAT HAPPENS TO YOUR UDF VARIABLESWhen a UDF's run its course and returned to the calling script, whatever variables in the UDF that were used to store the parameters are destroyed and don't refer to anything anymore. The vars and values they referred to in the first place aren't touched. That goes for all types of parameter variable.Local variables are destroyed/nullified too, except for one type of local variable: string vars. Strings referred to by a UDF's local string variables aren't destroyed and will continue to linger on in your .nvse file unless you destroy them yourself when you're done with them, so do that: sv_destruct mystringvar 6. OTHER SWEET STUFFBecause UDFs are standalone scripts that are still held as entries in the object window, you can refer to them with a ref variable, and pretty much do anything with them that you can do with other ref vars that refer to base forms without a world model. Ie you obviously can't moveto a UDF to you, but you can park it in a formlist or array, return its formID in a debugprint readout with %i, NX_SetEVFo it, and of course just have it be "set" depending on different conditions. if somecondition    let someRefVar := someUDF1 elseif somecondition    let someRefVar := someUDF2 endif call someRefVar And because you can park them in a ref variable, you can buildref them! set someRefVar to BuildRef someModIndex somedecimalint call SomeRefVar Which means of course that if some other mod has pretty UDFs you'd like to use, you can, just like that. No copying the entire thing, no making it a master or worrying about load order etc.
Symon Posted February 7, 2014 Posted February 7, 2014 Another good one. Although I mostly work in OBSE20+ these days, I mostly write far more functions than traditional Quest and Object scripts. (OK, I mostly work in Bash, Sed, Awk and PhP these days but that's work that pays).
zippy57 Posted February 9, 2014 Posted February 9, 2014 Example 3: Let's say we're tired of typing out the particulars to a Sexout act in every dialog result script in our mod:I'm wondering if it's a good idea to implement something like that directly into Sexout. If so, it should be done before every single mod ends up with its own custom function.
DoctaSax Posted February 10, 2014 Author Posted February 10, 2014 I think sexout could have some UDFs like that available. And then modding for sexout can really become a breeze. The only trouble I see is the passing of null ref vars as variables if they don't apply (ActorC, refsurface), someone oughta check out how to do that. Me, I'm kinda pooped right now - the string var one was murder.
nyaalich Posted March 8, 2014 Posted March 8, 2014 Confirming: Since the UDF is an object script, it's going to execute every frame, yes? Which means that you'd need to use stages to manage long scripts, yes?
DoctaSax Posted March 8, 2014 Author Posted March 8, 2014 No, it's a one-frame-only script, like a result script, it's just that you select it to be an object script in the geck, and if you call it on a ref, that ref becomes the implied ref (GetSelf).
nyaalich Posted March 9, 2014 Posted March 9, 2014 So if a long script was in a UDF, it would only process as much of the script as it was able to in one frame and then that's that?
DoctaSax Posted March 9, 2014 Author Posted March 9, 2014 Well, a lot can be done in one frame - it all kinda depends how much else is going on, how 'heavy' the functions in it are, whether there's extensive looping. But seriously, I run a lot of code in UDFs, or in tiers of UDFs and haven't really had much of an issue, except where I could've known in the first place. That said, the beauty of UDFs is that they usually don"'t have to be very long, because chunks of code that rarely come into play - like under a rare condition - can be exported to another UDF.
Guest Posted May 12, 2014 Posted May 12, 2014 Hello Doctasax,  Here I am with my wall of text...  My concerns about UDF:  A - Do variables declared inside the UDF be resetted at every execution (like if everytime you call UDF it creates a new istance of it) or do they need to be manually resetted in the main quest script? is SetFunctionValue the only way to make values go out from the UDF, or I can simply set a value to an external variable in the form quest.var?  B - You made the example of CIOS and then you were calling the UDF like ref.call UDF, so CIOS will be applied to ref. But what happens if ref is not specified, will player be the target or it will CTD because it's null?  C - if I make a UDF accepting a number of variables (with accolades), I assume I can even not write them (starting from right, not left... how can I say... think to DisablePlayerControls, I think it's the same, you can write 7 parameters but even miss some and write only 1), if I don't put them I assume their value will be 0 for numbers, is it true? and what happens when a ref is not specified, will it be "null" or zero? It helps me to place conditioned statements inside the function to prevent CTDs but I don't want to put extra code if I can prevent it. EDIT no they don't allow me to skip them, so why vanilla functions allow that?  D - Is there a way for the UDF to understand which Quest Script is calling it? it would be useful to set the quest delay automatically to a proper value  E - You said you can nest your UDF inside itself. Why that? is for example the case of a loop? something like: Begin Function {} do code if counter < 10  let counter += 1  call sameUDF endif But I think that it won't work because counter takes a different value every execution, unless I use quest.counter as variable... could you make me a simple example of where people want to nest an UDF inside itself?  F - Here the most important, sorry if it's long but it sums what I need for my UDFs.  EDIT: re-reading, I think the example with UDF is completely messed up. Erased for clarity, I keep just the last part:  I just changed it, still I'd like a confirmation if I understood well how SetFunctionValue works. I understood that inside the function it will assume a specific value (or the value of a variable used inside the script), so if it's true can I use it to check when a UDF must stop its execution on a quest GameMode script? let's write down an example: scn MyQuest short GoOn if GoOn <something>   <change stage> <or return> <not important> else   let GoOn := Call myUDF endif scn myUDF Begin Function {} ... do some code... ... do a lot of code... ... no matter if it won't finish in a frame... ... since it's staged... ... and at last stage, do this: SetFunctionValue 1 end (even without return because I'm at the end) Now my guess is that since GoOn is zero, the quest will repeat the UDF every (delay time) for (number of stages) times, then it will quit since UDF will give to GoOn the value of 1 and it will interrupt the execution. Did I get the purpose of SetFunctionValue?  ok I add G and H because I struggled on it, even if it's about arrays. G - I can't use an array var as parameter of a function (as GetEquippedObject myarray[1], whatever you want), should I use compiler override? is it one of "those cases"? H - Since I told you about the limitations of compiler override, is there a way to split the script so that I can use compiler override in a part and the common compiler in another part? like if I declare two different blocktypes, both _Gamemode AND a Gamemode blocktype inside the same script, as I could declare both a OnAdd and a Gamemode for example...
DoctaSax Posted May 12, 2014 Author Posted May 12, 2014 I'll take that in chunks: Â A. Yes, local variables are reset every time you call a UDF again. It's a one-frame only script, and when it's done, it's done. Yes, SetFunctionValue is the only way to make a UDF return something (number, form/ref, string, array) directly. But sure, you can make it affect a quest var from inside the udf by going "set somequestid.somevar to somevalue".B. Haven't tried that. At compile time, there's no way for the script compiler to know if the script will have an implied reference so it will compile fine, but at run-time I assume you'll get an error - perhaps CTD, perhaps not.C. No, you can't assume that. If a UDF is written to expect a specific ordering of parameters, eg. 1st = number, 2nd = form, 3rd = string, then if you don't call the UDF with that specific order of parameters (skipping some, or placing them in the wrong order) you won't be able to compile your calling script. None of the parameters are optional. For numbers, you can simply put a 0 there, for strings an empty string (""), for arrays an empty but initialized array.For forms/ref vars, it's a bit trickier. A UDF can return a null ref if you just SetFunctionValue 0, but you can't pass a null ref as a parameter to a UDF that way - the calling script won't compile. What I do is pass some form, any form, that isn't of the type you expect to use. For instance if the code in the UDF is meant to do something to a ref that is an actor, and I want it to not apply, I pass the form Pencil01, and write the UDF to check with a GetType check to see if the received form is an actor first. If anyone knows of an alternative, I'm all ears. (EDIT: heh, I suppose if I just pass a ref var that I set to 0 first, that might do the trick too.)D. There is the GetCallingScript function, which returns the calling script as a form. (http://cs.elderscrolls.com/constwiki/index.php/GetCallingScript) I haven't used it yet so don't know if it'd return the quest or the actual quest script - I assume it's the script, so for using setquestdelay that's probably not very useful. Still, you may search the beth forums for "GetCallingScript" and find some useful examples from Oblivion coders.E. A good example of a nested UDF is the ArrayDeepDump function posted on the CS wiki by QQuix: http://cs.elderscrolls.com/index.php?title=ArrayDeepDump. To print the contents of a regular array to the console, we have ar_dump, but that doesn't help us in the case of arrays inside arrays. The arraydeepdump function prints out the contents of an array, and if one of those is another array, it calls itself on that one too. But you can't get it to work unless you comment out that line first, so that the script is actually added to your mod first. (There's something about that one that I couldn't get to work in spunk, so I adapted it, see attachment.) SpunkFuDeepDump.7z
Guest Posted May 12, 2014 Posted May 12, 2014 sorry sometimes I find it's not understable after the third or fourth time I re-read it, so after I already posted... I modified my previous post...
DoctaSax Posted May 12, 2014 Author Posted May 12, 2014 F. First things first: you don't use accolades/brackets in the line that calls a UDF, only in the Begin Function line of the UDF itself. They are like a net that captures the parameters.- if you call a UDF on a ref (someref.call someUDF), then you can find that ref inside the UDF by using GetSelf and passing that to a local ref variable, yes.- The parameter variables that you use to capture the parameters don't have to have the same name as in the calling script. They just have to be the same type.- As said, a local int/float variable that isn't set will be 0 every time the UDF is called, and a local ref var will be NULL every time the UDF is called, until you set them to something.- I think you caught it in your example, yes. SetFunctionValue is pretty versatile - it doesn't have to be done at the end of a UDF either. You can conditionalize it. For instance as part of my init cycle in spunk I have this in my calling script:   if iInit == 0      let iInit := call SpunkFuInitFirst ; returns 5   elseif SpunkVARZ.fVersion < currentversionvalue      if iInit != 2         let iInit := call SpunkFuInitVersion iInit ; returns 4-3-2 (this is a UDF that runs on a version update)         return      endif      let SpunkVARZ.fVersion := currentversionvalue   else   ...   endifand this in the UDF   if iInit == 5      ; bunch of code      SetFunctionValue 4      return   endif   if iInit == 4      ; bunch of code      SetFunctionValue 3      return   endif   if iInit == 3      ; bunch of code      SetFunctionValue 2   endif  Which looks to be similar to your example. Of course, in this case I use the same name for the iInit variable in the calling script and the iInit parameter variable in the UDF - this isn't necessary, just easier to remember what it refers to. It's important to understand here that the variable in the calling script isn't automatically changed, no matter what I do with it in the UDF, it only is because I let it to the result of the UDF, and specify the result with SetFunctionValue. This is different for references, strings, and arrays because they're held elsewhere and ref/string/array vars just refer to them. Changes you make to them affect the original. Number vars are always local to the script (unless they're globals).G. Yes, looks like a case for the compiler override.H. Yes, you can have CO and non-CO blocks in the same script. Except inside UDFs, which can only have one block.
Guest Posted May 12, 2014 Posted May 12, 2014 nice, it seems I got it now, thank you very much. Â EDIT: nevermind, I got it. The parameters you pass think in a slight different way than what I was expecting. so if you pass a baseID it will be used as baseID and not as a reference to that baseID.
Guest Posted May 13, 2014 Posted May 13, 2014 Another question about SetFunctionVar: I understood the way you set different function vars and you let the result to link it to some main script variable, but can you set more values together? i.e. UDF code:  Begin function {}   do my operations   SetFunctionVar myref   SetFunctionVar 5   SetFunctionVar 4.65 end  can you set them all outside the UDF, inside the main script, or you must use external quest.vars? essentially my UDF must give me a ref as result, but I also need a short to check if the UDF has finished its execution (like in the example I did before). Of course I can use a quest.var but it would create more and more troubles in readability. Also, the script calling the UDF is linked to a quest, so I assume I could, inside the UDF code, simply write "let myUDFref := myquestcallingtheUDF.myquestvar", but as you can see it would make a specific UDF for a specific calling script, loosing one of the meanings of UDFs (which is being generic pieces of code for different purposes). Maybe the parameters can be used in two ways and I ignore it? Something like this (Main script): let myREF := someref call myUDF {myREF} >>> inside myUDF I use myREF (which is == someref), then I change myREF in someotherref ; and now in the main code myREF is someotherref PS two days I use them, and I really love them. My scripts can be shortened by A LOT, I mean even from 300 to 30 lines
DoctaSax Posted May 13, 2014 Author Posted May 13, 2014 Nah, only one SetFunctionValue at a time. For signification, I'd just use the fact that a value is returned at all:  let someRefVar := call MyUDF if someRefVar  ; you're good to go endif  But if you need to return a bunch of data, consider sticking them in an array and returning that.
prideslayer Posted May 16, 2014 Posted May 16, 2014 Doc, do you know if passing multiple arrays as params to a UDF is valid or not? In most pass-by-ref oriented languages it works fine, but it doesn't in the pass-by-val ones (the first array seen gobbles up all remaining params). Â Trying to decide how the 'raw' internal sexout UDFs (there will be simpler public interfaces) should look. I'm leaning towards most of them taking a single hash (stringmap) arg as their only parameter, so I can add support for more params without changing the interface signature; something I do a lot in 'real' programming languages. I didn't see a function to return a normal array of keys in the hash though, and if I end up needing that, it might be easier to pass multiple arrays instead in some cases. HasKey will work 99% of the time, but the edge cases might bite me.
DoctaSax Posted May 16, 2014 Author Posted May 16, 2014 I'm sure think I managed to pass more than one in one go, yes. Â Array of keys : ar_Keys should do you fine if you're after what I think you're after. EDIT: I think I forgot about that one in the array tut, so I added it.
Guest Posted May 18, 2014 Posted May 18, 2014 Passing a float to a UDF, which is explicit written as negative number (-90), doesn't compile, it says you miss that parameter, as if the - kills everything. Any clue on how workaround that?
Guest Posted May 18, 2014 Posted May 18, 2014 because if it is possible, I would prefer jumping that step. It could create less issues when that UDF must be used by someone else.
prideslayer Posted May 18, 2014 Posted May 18, 2014 Passing a float to a UDF, which is explicit written as negative number (-90), doesn't compile, it says you miss that parameter, as if the - kills everything. Any clue on how workaround that? - is a negation operator or something when only given one arg. Â Try passing in "0 - 90"?
Guest Posted May 18, 2014 Posted May 18, 2014 Yes I'm trying to pass a negative value, but there wasn't way to make it compile. I tried -90 and - 90 but not 0-90 because I already have seen vanilla functions don't want operations in them. But now I just tried it following your suggestion and you know what, now it compiles even with -90. Mmmh compiler confuses me.
prideslayer Posted May 24, 2014 Posted May 24, 2014 Funny story... when writing a recursive function, you have to save it once first without the recursive call, or it can't be resolved.
Loogie Posted May 24, 2014 Posted May 24, 2014 Before I start fiddling with this, because my brain isn't so good with this kind of thinking, if I have an event where a player normally has a token with a "removeme" at the end just so I can process that script when it's called, instead I could just do "call ScriptNameHere" and process the script without adding a token?
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