Difference between revisions of "Simulating new functions"
imported>Maian |
imported>Maian |
||
Line 124: | Line 124: | ||
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. | 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. | ||
--[[User:Tegid|Tegid]] 14:44, 18 April 2006 (EDT) | --[[User:Tegid|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: | 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: | ||
Line 137: | Line 135: | ||
Thanks for all the help! --[[User:Maian|Maian]] 21:49, 18 April 2006 (EDT) | Thanks for all the help! --[[User:Maian|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: | |||
<pre>scn testfuncobjscript | |||
float param1 | |||
float param2 | |||
float result | |||
begin OnActivate | |||
Message "start func", 1 | |||
set result to param1 + param2 | |||
Message "end func: %.0f", result, 1 | |||
end</pre> | |||
Calling script: | |||
<pre>scn testobj2script | |||
float r | |||
begin OnActivate | |||
Message "before call", 1 | |||
set testfuncref.param1 to 10 | |||
set testfuncref.param2 to 20 | |||
testfuncref.Activate Player, 1 ; <-- function call | |||
set r to testfuncref.result | |||
Message "after call: %.0f", r, 1 | |||
end</pre> | |||
--[[User:Maian|Maian]] 01:47, 19 April 2006 (EDT) | |||
[[Category:Solutions]] |
Revision as of 00:47, 19 April 2006
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 suspect 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 Message "start func", 1 set result to param1 + param2 Message "end func: %.0f", result, 1 end
Calling script:
scn testobj2script float r begin OnActivate Message "before call", 1 set testfuncref.param1 to 10 set testfuncref.param2 to 20 testfuncref.Activate Player, 1 ; <-- function call set r to testfuncref.result Message "after call: %.0f", r, 1 end
--Maian 01:47, 19 April 2006 (EDT)