splash damage team programmers - a quick question


(damocles) #1

Is there a limit to the number of script threads that can execute at any one time?

The scripts that call functions in other entites seem to work in unison to each other, so I’m guessing each function outside of the current function gets a new script thread created and execution continues alongside the original function. That’s not a problem. The problem is that my script requires multiple functions to be fired at once and this is causing some functions not to fire at all. And it seems to be on a first called, first executed basis, so it’s almost random which functions will get ignored, making the script completely unreliable.

So are there limits to the number of function calls?

I know I can add waits in places, but most of the functions in question work on a timing basis as it is, so I can’t alter much. :frowning:

Would there be another way around thus problem?


(kat) #2

64 - That’s the limit on the number of calls you can make per script section and the number of event you can trigger from each call (for default RtCW MP & SP - the guys may have changed the limit for ET). You also have to be carefull what you’re trying to call and from where (esp for SP) as sometimes the game refuses to follow a script and instead ‘diverts it’s attention’ to the new section you ask it to execute.

The best thing is usually to create ‘base functions’ which are the events you want to happen and then trigger those from a main script… don’t try and call another script which then runs further events as that’s where it tends to get side tracked and doesn’t run the original fully.


(damocles) #3

I’m pretty positive that I’m nowhere near the 64 call limit per script section.

I have a large section in my game manager that has maybe 15 functions in it. A large quanitity of which get called once per second.

Yet still my script fails. Some calls get ignored and the whole thing comes crashing down :frowning:


(kat) #4

what it might be is something similar to the ‘think time’ error which usually happens when you try to tigger something before it’s spawned… In you particular case you may be trying to trigger call something inadvertantly before it’s done what’s it supposed to do (like trigger a whole bunch of other stuff?)… hmmm did that make any sense…!?


(damocles) #5

Yeah I know the problem you mean but it’s not that either :frowning: All the functions can operate happilly independantly of each other. It’s just that every so often, one function may decide not to be called, and it often is the main repeating timer function, causing everything to collapse.


(damocles) #6

Well this is fan-bloody-tastic. </sarcasm>

I’ve just spent the last 2 months working my nuts off making (imo) my best level so far. It has a (also imo) great unique objective and could be great to play, but now I’m going to have to abandon it or mutilate it simply because the wolfenstein scripting engine does NOT do excatly what it says on the tin.

There is no way my script is exceeding 64 actions per section. I even spaced out all the various function calls with waits and it still didn’t work. I stripped out half of the function calls, and still it falls down dead.

kicks Nerve square in the nuts[/i]


(kat) #7

what is it you’re actually trying to get the script to do?? post an outline of the events as they’re supposed to happen as that should help give a better idea of the problem (don’t write the script out just comment on what’s supposed to be going on when the script activates)


(damocles) #8

Ok…

The objective is for the allies to overload a power facility by turning off two coolant systems. The systems are turned off via a simple handle.

The script starts with a small pause in the game manger spawn, then fires a function called coolant loop.

The coolantloop repeats once every second and fires two functions, one called cooling and one called overload.

Cooling will check if the right accums are set and then increase another accum for timing. It also fires four other functions that will check if the timing accum is at a certain value and if it is display a message.

Overload pretty much does the opposite to cooling. It decreases the timer accum and fires five functions - the extra function is one that starts a ten second count down function.

The cooling and overloading work fine. If I set the values so that the generator starts overloading from the get go, then it runs down the timer, gives appropriate warning messages and then destroys the generator. Same if I start the timer at 1 and let the cooling system increase the timer to full - works fine and all messages appear.

The problem occurs when I use a handle to alter the accums that set the values for the two cooling systems. for some reason, the looping function stops when I activate one of the handles. The handles fire off two functions - one to see if the cooling system is being turned back on and one to see if it is being turned off (necessary to get the appropriate messages up) The handle function and it’s called functions do not directly affect the looping function, it just seems as if the script engine can’t be bothered to repeat the coolingloop function anymore because it has other things to do. Obviously I can’t control when the handles are used so there’s no way of making sure the handle functions can’t interefere with the timer function.

I’ve tried having the various functions either operating on the game_manager or in an entity by themselves and neither work reliably.

Any insight you can give would be greatly appreciated as I’m about to go on a small killing spree…


(kat) #9

hmmm that’s quite a complex series of events… are you trying to run all this from the same script block or do you have each ‘event’ on it’s own??

I can’t give a solution persay (stuff like this is map dependant) but what I can say is that what you want to do is possible but what you seem to be doing is trying to get it all happening at once (in a manner os speaking - there seem to be a load of things happening and firing off other things at the same time)…

try thinking about the script in blocks of events or sections and going thru it a step at a time… right now the way you have your scipt running it looks like it can’t check what’s happening when the handle is pressed becasue it’s trying to look at too many separate events… what you may need to do in this case is set the handle up as the ‘controlling’ event (the event that the script is basically running around) and everything else set up around that… basically the script starts becasue the handle is ‘off’…

not much direct info but I hope it helps you out a bit… :???:


(damocles) #10

I can try moving some of functions into seperate entity blocks if that’s what you mean, but the majority of functions need to remain in the one block because they need to check against the accums to see if they should fire or not.

What this language REALLY needs is an if statement, then I wouldn’t have to fire so many functions.

EDIT:

just had a look at my script and there is only one function that can be moved outside of the script block. All others must have the same block or they can’t check against the same accums.

In theory I could set up another 10-15 functions in other script blocks that set another set of accums for checking, but that seems a lot of work for something that should work anyway.


(kat) #11

‘IF’… my buddy assisting me with some SP scripting said exactly the same thing… we found out the only way to get things to work properly was to break scripts up into thier own component sections… you may be stuck though with MP as you’ve only got a single script file to run from (??) rather than SP which has 2 - the *.ai and the *.script, sorry I can’t be of more help to you dude…


(demoneye) #12

All I can suggest you do is split the code…

I often do that and pass accums backwards and forwards. This code deals with 3 script_movers. The last two, set the accum 2 in the first when they have finsihed what they are doing.


southdoorswitch
{
	spawn
	{
		accum 1 set 0 // Set to 0 means closed, 1 means open
		accum 2 set 0 // Set to 0 means not moving, 1 means moving
	}
	trigger open
	{
		accum 1 abort_if_equal 1 // Abort if already open	
		accum 2 abort_if_equal 1 // Abort if already moving
		accum 2 set 1 // Set to moving		
		trigger southdoor1 open
		trigger southdoor2 open
		accum 1 set 1
	}
	trigger close
	{
		accum 1 abort_if_equal 0 // Abort if already closed	
		accum 2 abort_if_equal 1 // Abort if already moving
		accum 2 set 1 // Set to moving		
		trigger southdoor1 close
		trigger southdoor2 close
		accum 1 set 0	
	}	
	trigger setaccum_2_to_0
	{
		accum 2 set 0
	}
}

southdoor1
{
	trigger open
	{
		playsound sound/delivery/foundrydoors.wav 
		gotomarker southdoor1open 5 wait
		trigger southdoorswitch setaccum_2_to_0
		stopsound
	}
	trigger close
	{
		playsound sound/delivery/foundrydoors.wav 
		gotomarker southdoorclosepath 5 wait
		trigger southdoorswitch setaccum_2_to_0
		stopsound
	}
}

southdoor2
{
	trigger open
	{
		playsound sound/delivery/foundrydoors.wav 
		gotomarker southdoor2open 5 wait
		trigger southdoorswitch setaccum_2_to_0
		stopsound
	}
	trigger close
	{
		playsound sound/delivery/foundrydoors.wav 
		gotomarker southdoorclosepath 5 wait
		trigger southdoorswitch setaccum_2_to_0
		stopsound
	}
}

Can you post the code so I can have a look and see if I can see anything in it…

DeMoNeye


(damocles) #13

Well, I have it working again. Although I don’t really beleive what the problem was…

…It seems that you are only allowed one wait per script block/entity block. The problem I noticed (using the g_scriptdebug 1 command) was that while the timer function was waiting for one second repeatedly, another function would get called in the same block that would attempt to wait also. This caused the looping wait timer to be overridden and thus fail to loop as needed.

Quite what madness drove them to only allow one wait per block is beyond me (probably some memory shaving idea) but that seems to be the problem. I now have EVERY function bar one in the generator script running immediately without a single wait in them. The bar one had to be moved to another block because I couldn’t remove the waits involved.

I wish I had found this before I turned my original script into spaghetti though :frowning:

As far as I can tell however, this problem only applies directly to wait statements. Scripts that wait for animations or movements don’t seem to be affected.


(digibob) #14

The problem is that wolf’s scripting system is not “multi-threaded”.

An entity can only have one active function at a time, aside from the special case of during the server running the entity, i.e.

There are three classes of commands in wolf scripting, those which return instantly, those which wait, and those which might do either. Commands falling into the first category are: accum and any of the wm_ commands (i think). The second category is stuff like gotomarker and wait. The third contains only trigger afaik, as it can contain commands that wait, and commands that dont, so it’s not certain to do either.

Whilst running a script for an entity, a couple of things can happen. If the script is already running a thread, and pops into another function ON THE SAME ENTITY, which does NOT return instantly, then the function it was in previously will not continue execution. If it calls a function on another entity, or a command which returns instantly, execution will continue until either the function ends, or hits a command which waits.

If the entity was already running a function when anotehr entity calls a function inside it, and this function does not terminate, (i.e. it waits), then the function it as already running is lost.

If the entity was not running a function already, then it really doesn’t matter what happens, it’ll either wait if it waits, or terminate if there are no waits.


(damocles) #15

Yeah that’s pretty much what I’d figured out. You just have to be really careful when placing waits in a complicated script block