Talk:Simulating new functions
I've tried creating a custom "function" that can be called by other scripts. The basic approach I took was to make the function a quest script, and have the calling script call the function via |StartQuest function_quest|. Ex:
I have a quest called testfunc that is initially disabled and contains the following script:
scn testfuncscript float param1 float param2 float result begin GameMode Message "start func", 1 set result to param1 + param2 Message "end func: %.0f", result, 1 StopQuest testfunc end
In another script, I call this "function":
scn testscript float r begin OnActivate Message "before call", 1 set testfunc.param1 to 10 set testfunc.param2 to 20 StartQuest testfunc set r to testfunc.result Message "after call: %.0f", r, 1 end
However, the above code doesn't work. The order of the output illustrates why:
before call after call: 0 start func end func: 30
This is what it should be:
before call start func end func: 30 after call: 30
The problem is that the calling script doesn't wait for the function script to execute, and instead the function script is delayed until after the calling script finishes executing.
So is there any way that can bypass this problem without resorting to nasty "wait for the other script to finish" hacks? (I could make the calling script have a GameMode block that would repeatly check when the function finishes executing, but that would be a serious PITA.) I suspect this same problem would've arisen if I had tried creating a function script by attaching it to a persistent object instead of a quest (and calling it via the Activate function).
--Maian 03:59, 18 April 2006 (EDT)
I'm just kind of brainstorming here, but you might try making a quest, marked "Allow repeated stages" so you can call the stages repeatedly, and make (say) stage 10 be your "function". Quest stage results are executed immediately, while the current script is processing, so you wouldn't have to wait for the results.
Keep your variables in your quest script. In stage 10 results, you'd have:
Message "start func", 1 set testfunc.result to testfunc.param1 + testfunc.param2 Message "end func: %.0f", testfunc.result, 1
To call this function, you'd do the following:
scn testscript float r begin OnActivate Message "before call", 1 set testfunc.param1 to 10 set testfunc.param2 to 20 setstage testfunc 10 ; call the "function" set r to testfunc.result Message "after call: %.0f", r, 1 end
I think this should work (I haven't tried it).
--Kkuhlmann 14:02, 18 April 2006 (EDT)
I've been doing this for awhile now with OnActivate functions placed on activators. The reference you use to activate it acts as a parameter to tell it how to act. Then when that function is done it activates the calling object to let it know that it is finished and it is time to process the results.
So for instance
scn ActivateFunction ref incoming begin OnActivate set incoming to GetActionRef if (incoming == CallingScriptRef.Me) set CallingScriptRef.Value to CallingScriptRef.Value + 3 CallingScriptRef.Activate CallingScriptRef.ActivateFunctionRef 1 return endif end
scn CallingScript ref Me ref ActivateFunctionRef long Value ref incoming begin OnLoad set Me to GetSelf set Value to 0 Message "I am storing a value of %.0f", Value, 1 end begin OnActivate set incoming to GetActionRef if (incoming == ActivateFunctionRef) Message "Now I am storing a value of %.0f", Value, 1 return endif ActivateFunctionRef.Activate Me 1 end
This removes the need for a game mode block and allows function passing (or setting in a persistent reference). I've used this quite successfully for some cool stuff I'm finishing the testing on. --Tegid 14:44, 18 April 2006 (EDT)
After some experimentation, I've verified that making the function script an object script and attaching it to a dummy object (in activator called testfunc in my case), it works. That is, it satisfies the following conditions:
- It can be called (via |testfunc.Activate player, 1|).
- The function is executed immediately rather than after the script that called it.
- It can be called even in places where the dummy object isn't at, e.g. I placed the dummy object inside an interior cell and called it in an exterior cell. This was what I was most worried about with this approach - that the function would only work if the dummy object is in the same area. I haven't tested this extensively, so it may be the case that it works only because the dummy object is still in memory, but I hope that's not the case.
Tegid, in your example, the called function apparently needs a reference to the script calling it, which defeats the purpose of making the function generic (after all, the main reason for creating a new function is to share code between 2+ functions). Maybe if your script just checked if incoming.Me was set and just used incoming rather than CallingScriptRef, it could work generically.
Kkuhlmann, I haven't tried your method yet, but I'm post an update once I do so.
Thanks for all the help! --Maian 21:49, 18 April 2006 (EDT)
Kkuhlmann's solution also worked.
For reference, here's my dummy object + activate script solution:
On a dummy object:
scn testfuncobjscript float param1 float param2 float result begin OnActivate if IsActionRef Player != 1 Message "start func", 1 set result to param1 + param2 Message "end func: %.0f", result, 1 else Activate endif end
Calling script:
scn testobjscript float r ref self begin Onload set self to GetSelf end begin OnActivate Message "before call", 1 set testfuncref.param1 to 10 set testfuncref.param2 to 20 testfuncref.Activate self, 1 set r to testfuncref.result Message "after call: %.0f", r, 1 end
--Maian 01:47, 19 April 2006 (EDT)
The CallingScriptRef is just your single point of entry into the set of scripted functions. It is a persistent reference Activator like your testfuncref. Also, it has not been my experience that Activate calls interrupt the flow of script parsing. I was under the impression that the Activate call really just sets a bit so that when that script is reached, the OnActivate block is executed. --Tegid 11:07, 19 April 2006 (EDT)
I love the solution kkuhlmann has written! This is by far the best idea for immediately executing function calls! I've advanced his idea to a working solution! See the article for more info. --JustTim 11:26, 7 May 2006 (EDT)
The math for getAngle is definitely not correct. You mixed up cos and sin (cos = x/h; sin = y/h). I'm not sure why you're multiplying cos or sin with 180/PI since that's not the angle. In fact, you shouldn't even be using cos or sin when trying to get the arctangent. --Maian 00:56, 8 May 2006 (EDT)
Oops, now i see why i've recieved some strange results. But the results aren't too far from what they should be. ^^ But i'd appreciate a corrected version very much. As said before my math skills are VERY limited and those functions are nothing but patchwork of stuff i found on the net, put together by trial and error instead of reasonable mathematics. :) --JustTim 11:34, 8 May 2006 (EDT)
BTW: If there is something you'd like to change or contribute to the article or if you know of a good way to write a simplier example don't hesitate to modify the article directly. I know the article lacks a professional writing style (presumably due to me not being a native english-speaker) and it would be cool if someone could help me to bring this into a professional, more wiki-like (and error-free) form. --JustTim 15:16, 8 May 2006 (EDT)
This is a script I made but ended up never using once I discovered the getHeadingAngle function (so it's rather untested and probably has bugs). It's basically a lookup table, one row for a degree (so the script is large), except since there are no arrays, I made the look up act as a binary search. It also doesn't use the quest result script thing - I'm using the method I described above.
scn ArcTanScript ; by Maian float x float y float result float ratio begin GameMode if x == 0 if y >= 0 set result to 90 else set result to 270 endif return endif set ratio to y / x if ratio < 0 set ratio to -ratio endif if ratio < 1.018 if ratio < 0.414 if ratio < 0.203 if ratio < 0.096 if ratio < 0.044 if ratio < 0.009 set result to 0 elseif ratio < 0.026 set result to 1 else set result to 2 endif else ; 0.044 if ratio < 0.061 set result to 3 elseif ratio < 0.079 set result to 4 else set result to 5 endif endif else ; 0.096 if ratio < 0.149 if ratio < 0.114 set result to 6 elseif ratio < 0.132 set result to 7 else set result to 8 endif else ; 0.149 if ratio < 0.167 set result to 9 elseif ratio < 0.185 set result to 10 else set result to 11 endif endif endif else ; 0.203 if ratio < 0.296 if ratio < 0.24 if ratio < 0.222 set result to 12 else set result to 13 endif else ; 0.24 if ratio < 0.259 set result to 14 elseif ratio < 0.277 set result to 15 else set result to 16 endif endif else ; 0.296 if ratio < 0.354 if ratio < 0.315 set result to 17 elseif ratio < 0.335 set result to 18 else set result to 19 endif else ; 0.354 if ratio < 0.374 set result to 20 elseif ratio < 0.394 set result to 21 else set result to 22 endif endif endif endif else ; 0.414 if ratio < 0.662 if ratio < 0.521 if ratio < 0.456 if ratio < 0.435 set result to 23 else set result to 24 endif else ; 0.456 if ratio < 0.477 set result to 25 elseif ratio < 0.499 set result to 26 else set result to 27 endif endif else ; 0.521 if ratio < 0.589 if ratio < 0.543 set result to 28 elseif ratio < 0.566 set result to 29 else set result to 30 endif else ; 0.589 if ratio < 0.613 set result to 31 elseif ratio < 0.637 set result to 32 else set result to 33 endif endif endif else ; 0.662 if ratio < 0.824 if ratio < 0.74 if ratio < 0.687 set result to 34 elseif ratio < 0.713 set result to 35 else set result to 36 endif else ; 0.74 if ratio < 0.767 set result to 37 elseif ratio < 0.795 set result to 38 else set result to 39 endif endif else ; 0.824 if ratio < 0.916 if ratio < 0.854 set result to 40 elseif ratio < 0.885 set result to 41 else set result to 42 endif else ; 0.916 if ratio < 0.949 set result to 43 elseif ratio < 0.983 set result to 44 else set result to 45 endif endif endif endif endif else ; 1.018 if ratio < 2.414 if ratio < 1.511 if ratio < 1.213 if ratio < 1.091 if ratio < 1.054 set result to 46 else set result to 47 endif else ; 1.091 if ratio < 1.13 set result to 48 elseif ratio < 1.171 set result to 49 else set result to 50 endif endif else ; 1.213 if ratio < 1.351 if ratio < 1.257 set result to 51 elseif ratio < 1.303 set result to 52 else set result to 53 endif else ; 1.351 if ratio < 1.402 set result to 54 elseif ratio < 1.455 set result to 55 else set result to 56 endif endif endif else ; 1.511 if ratio < 1.842 if ratio < 1.632 if ratio < 1.57 set result to 57 else set result to 58 endif else ; 1.632 if ratio < 1.698 set result to 59 elseif ratio < 1.767 set result to 60 else set result to 61 endif endif else ; 1.842 if ratio < 2.097 if ratio < 1.921 set result to 62 elseif ratio < 2.006 set result to 63 else set result to 64 endif else ; 2.097 if ratio < 2.194 set result to 65 elseif ratio < 2.3 set result to 66 else set result to 67 endif endif endif endif else ; 2.414 if ratio < 4.915 if ratio < 3.172 if ratio < 2.675 if ratio < 2.539 set result to 68 elseif ratio < 2.006 set result to 69 endif else ; 2.675 if ratio < 2.824 set result to 70 elseif ratio < 2.989 set result to 71 else set result to 72 endif endif else ; 3.172 if ratio < 3.867 if ratio < 3.376 set result to 73 elseif ratio < 3.606 set result to 74 else set result to 75 endif else ; 3.867 if ratio < 4.165 set result to 76 elseif ratio < 4.511 set result to 77 else set result to 78 endif endif endif else ; 4.915 if ratio < 10.385 if ratio < 6.691 if ratio < 5.396 set result to 79 elseif ratio < 5.976 set result to 80 else set result to 81 endif else ; 6.691 if ratio < 7.596 set result to 82 elseif ratio < 8.777 set result to 83 else set result to 84 endif endif else ; 10.385 if ratio < 22.904 if ratio < 10.385 set result to 85 elseif ratio < 12.706 set result to 86 else set result to 87 endif else ; 22.904 if ratio < 38.188 set result to 88 elseif ratio < 114.589 set result to 89 else set result to 90 endif endif endif endif endif endif if x < 0 && y < 0 set result to result + 180 elseif x < 0 set result to -result + 180 elseif y < 0 set result to -result + 360 endif end
--Maian 16:50, 8 May 2006 (EDT)