Killed()
Moderator: Moderators
Killed()
Sorry to bug y'all, I know you're trying to get things wrapped up for what looks like the most awesome release ever... however, I've found something rather odd (imagine that!).
Very simply, Killed() runs multiple times, all during the same frame. This is probably a result of various checks against the state of Killed, but it's a big problem- among other things, it results in certain scripts getting borked.
I discovered this whilst doing some optimization on PURE today- I have scripts that are firing weapons during death events, and I kept seeing them fire far more often than I specified.
After testing and re-testing several times, with different weapons and attempts at a workaround, I have come to the reluctant conclusion that the only possible cause must be that Killed() is running several times- it appears to be 4, even if all portions of the script return (0). This is, obviously, rather wasteful, and will almost certainly bork death animations that require strict timing.
After further testing, I have determined that the cause is a start-script or call-script command.
I'm using such things as includes, to send the COB to a set of logic trees to generate certain behavior. Now that I know what's causing this, I think I can fix it, for PURE. However, it's still not correct behavior- if Killed() calls another function, then it should wait until the function returns before doing anything else, not run that function multiple times...
Very simply, Killed() runs multiple times, all during the same frame. This is probably a result of various checks against the state of Killed, but it's a big problem- among other things, it results in certain scripts getting borked.
I discovered this whilst doing some optimization on PURE today- I have scripts that are firing weapons during death events, and I kept seeing them fire far more often than I specified.
After testing and re-testing several times, with different weapons and attempts at a workaround, I have come to the reluctant conclusion that the only possible cause must be that Killed() is running several times- it appears to be 4, even if all portions of the script return (0). This is, obviously, rather wasteful, and will almost certainly bork death animations that require strict timing.
After further testing, I have determined that the cause is a start-script or call-script command.
I'm using such things as includes, to send the COB to a set of logic trees to generate certain behavior. Now that I know what's causing this, I think I can fix it, for PURE. However, it's still not correct behavior- if Killed() calls another function, then it should wait until the function returns before doing anything else, not run that function multiple times...
I've done a couple more tests, and Killed() definitely can run the same command over multiple frames. The problem seems to be that long stacks of commands go over 1 frame (ye old stack-size problem, yay) and that this causes Spring to re-run the entire set of commands over again...
The lowest I've been able to push this is to 4 repeat commands
This means that if I call twice, I can expect 8, and so forth and so on...
The lowest I've been able to push this is to 4 repeat commands

I have never heard of this before. Link and/or explain in detail please. I would like to try to fix this.Argh wrote:I've done a couple more tests, and Killed() definitely can run the same command over multiple frames. The problem seems to be that long stacks of commands go over 1 frame (ye old stack-size problem, yay) and that this causes Spring to re-run the entire set of commands over again...
The lowest I've been able to push this is to 4 repeat commandsThis means that if I call twice, I can expect 8, and so forth and so on...
Well I could give some form of proof if I could make a video, but I can't, my comp is phail. My standard debris explosion emits 2~6 flamey debris and 3 smokey debris. One time, it emitted about 9 smokey ones and 12 flamey ones -_-
Reproduce? Call something that is VERY specific. As in, you would be able to see it twice in a row in an instant. Add it to the Killed() script and watch as it repeats multiple times.
Reproduce? Call something that is VERY specific. As in, you would be able to see it twice in a row in an instant. Add it to the Killed() script and watch as it repeats multiple times.
Ok, to reproduce... hmm, this will pretty much require that you're using the latest build of PURE. You can see it there. See my release thread, download the game. I hate to make you do that, but it's in the midst of a lot of complex code.
If you review the BOS include, "ExplosionIncludes_PURE.h", it lists how many times a given "weapon" is supposed to fire, when a Unit runs Killed(). I use a call-script that passes to a function that runs the projectiles, then should return to the main script body of Killed() and remove the Unit.
I found this bug last night after playing a big game on Comet Catcher with AAI, where the low gravity made it abundantly clear that more than 12 projectiles were being spawned at once, which is what the previous version of PURE specifies.
Being somewhat horrified (each projectile calls CEGs and is CPU-heavy, so it dragged PURE down quite a bit when combat got heavy), I started building new code that would call it less frequently.
I discovered that there were several oddities, not all related:
1. Sometimes, Spring would just skip the process entirely. I'm not sure if the value of "severity" is being returned correctly, or if it's getting wiped out before the script finishes or whatever. But something odd's happening there. Return (0) seems to be the main issue- it's like when it hits that, even in a script called by Killed(), it ends Killed(). Probably the way that the death-animation code was done...
2. If I call just one "weapon" via call-script, then I get 4 projectiles. If I call just one weapon, within the main body of Killed(), then I get one. I thought Killed() was supposed to run once, and only stop when it returns 0, period. I've tested that, and it does not seem to work that way.
I tried PRINT, and it's not generating the results I'm expecting. It's something within Killed()'s loop in COBHandler, I think, not a BOS problem per se- trust me, I've been up, down and through all of that code, trying many variants.
Lastly, DGun doesn't use the MyGravity parameter... this proved to be a problem on low-grav maps, since it's the only weaponprojectile type that can currently be used to make animated rubble with. I really, really wish that Cannons firing from a script could just get fixed, and obey dir if force-fired instead of failing, even if that requires a parameter- they already have all of the things that would be ideal, such as MyGravity, good bounce behaviors, etc.
If you review the BOS include, "ExplosionIncludes_PURE.h", it lists how many times a given "weapon" is supposed to fire, when a Unit runs Killed(). I use a call-script that passes to a function that runs the projectiles, then should return to the main script body of Killed() and remove the Unit.
I found this bug last night after playing a big game on Comet Catcher with AAI, where the low gravity made it abundantly clear that more than 12 projectiles were being spawned at once, which is what the previous version of PURE specifies.
Being somewhat horrified (each projectile calls CEGs and is CPU-heavy, so it dragged PURE down quite a bit when combat got heavy), I started building new code that would call it less frequently.
I discovered that there were several oddities, not all related:
1. Sometimes, Spring would just skip the process entirely. I'm not sure if the value of "severity" is being returned correctly, or if it's getting wiped out before the script finishes or whatever. But something odd's happening there. Return (0) seems to be the main issue- it's like when it hits that, even in a script called by Killed(), it ends Killed(). Probably the way that the death-animation code was done...
2. If I call just one "weapon" via call-script, then I get 4 projectiles. If I call just one weapon, within the main body of Killed(), then I get one. I thought Killed() was supposed to run once, and only stop when it returns 0, period. I've tested that, and it does not seem to work that way.
I tried PRINT, and it's not generating the results I'm expecting. It's something within Killed()'s loop in COBHandler, I think, not a BOS problem per se- trust me, I've been up, down and through all of that code, trying many variants.
Lastly, DGun doesn't use the MyGravity parameter... this proved to be a problem on low-grav maps, since it's the only weaponprojectile type that can currently be used to make animated rubble with. I really, really wish that Cannons firing from a script could just get fixed, and obey dir if force-fired instead of failing, even if that requires a parameter- they already have all of the things that would be ideal, such as MyGravity, good bounce behaviors, etc.
Found another issue. After doing some tests...
1. The value of severity is being returned correctly. Test after test, PRINT shows it returning correctly at the start and end of Killed().
2. corpsetype defaults to 0.
3. When corpsetype <> 0, usually you're supposed to see a different corpse. However, in my tests, I have not seen Spring call the lower-level corpses. It always calls corpsetype 1.
Why is this occuring? I would assume that the corpsetype is determined by the Feature's chain to other Features as it "degrades", but it looks like this chain is broken, at least with my unit I'm testing... and it's only broken in BOS- it works otherwise.
Here is the feature:
So far as I know, it should call "misc_wreckage_3x3a", if the value of Severity > whatever I've set up, however, it does not do so. "misc_wreckage_3x3a" is in another file- is that borking things? It works if I just blow the corpse up... it just doesn't work when Killed() returns a corpsetype of 2...
Here's the function:
And I've definately seen the value of both severity and corpsetype match the results expected- it's simply that Spring isn't fetching the second corpse on the "chain"...
1. The value of severity is being returned correctly. Test after test, PRINT shows it returning correctly at the start and end of Killed().
2. corpsetype defaults to 0.
3. When corpsetype <> 0, usually you're supposed to see a different corpse. However, in my tests, I have not seen Spring call the lower-level corpses. It always calls corpsetype 1.
Why is this occuring? I would assume that the corpsetype is determined by the Feature's chain to other Features as it "degrades", but it looks like this chain is broken, at least with my unit I'm testing... and it's only broken in BOS- it works otherwise.
Here is the feature:
Code: Select all
[RadarTank_Dead]
{
description=Dead RadarTank;
object=DEAD_UNITS/RadarTank_Dead.s3o;
featuredead=misc_wreckage_3x3a;
footprintx=3;
footprintz=3;
height=4;
blocking=1;
hitdensity=100;
metal=250;
damage=40000;
reclaimable=1;
}
Here's the function:
Code: Select all
Killed(severity, corpsetype)
{
GET PRINT (severity, corpsetype);
if (severity <= 50)
{
corpsetype = 1;
call-script TinyExplosion();
} else
{
corpsetype = 2;
call-script SmallExplosion();
}
GET PRINT (severity, corpsetype);
return(0);
}
<tests> It doesn't work.
Oh, wait... you're basically saying that unless I terminate with a return (0) within the script body immediately, it won't work, period?
That's borked! That means that any time we have enough instructions that COBhandler needs to wait another frame to finish the stack, it won't produce the correct Corpse!
Killed really should run like this:
1. "I'm dead. Stop everything else. Run Killed()".
2. "I'm running Killed(), just like any other script. If I don't have a value I want yet, I'll wait until I get it, and I'll keep running I reach a return (0), terminating the script, or 10000 frames, which ever happens first."
If it doesn't work that way, all sorts of things get borked. It's better to have Spring halt if it doesn't reach a return (0), and return an error message. Given that having it "know" when it's looping endlessly is impossible... give it a static limit of frames- 10000, 100000- something really long, to allow for lengthy animation sequences. Then if it reaches that point without returning (0), post an error message to chat / infolog, and remove the Unit.
Oh, wait... you're basically saying that unless I terminate with a return (0) within the script body immediately, it won't work, period?
That's borked! That means that any time we have enough instructions that COBhandler needs to wait another frame to finish the stack, it won't produce the correct Corpse!
Killed really should run like this:
1. "I'm dead. Stop everything else. Run Killed()".
2. "I'm running Killed(), just like any other script. If I don't have a value I want yet, I'll wait until I get it, and I'll keep running I reach a return (0), terminating the script, or 10000 frames, which ever happens first."
If it doesn't work that way, all sorts of things get borked. It's better to have Spring halt if it doesn't reach a return (0), and return an error message. Given that having it "know" when it's looping endlessly is impossible... give it a static limit of frames- 10000, 100000- something really long, to allow for lengthy animation sequences. Then if it reaches that point without returning (0), post an error message to chat / infolog, and remove the Unit.
Last edited by Argh on 18 Dec 2007, 18:41, edited 1 time in total.
Tested KDR_11's statement.
It's true- if a script returns 0 immediately, then the right Corpse is generated. For example, this results in the "correct" behavior, but does NOT run my explosion script, because after the return (0) it quits (like it should):
So, I'm right- the problem there is Spring's handling of "immediately".
It's true- if a script returns 0 immediately, then the right Corpse is generated. For example, this results in the "correct" behavior, but does NOT run my explosion script, because after the return (0) it quits (like it should):
Code: Select all
Killed(severity, corpsetype)
{
GET PRINT (severity, corpsetype);
if (severity <= 50)
{
corpsetype = 1;
return (0);
} else
{
corpsetype = 2;
return (0);
}
if (corpsetype == 1)
{
call-script TinyExplosion();
}
if (corpsetype == 2)
{
call-script SmallExplosion();
}
GET PRINT (severity, corpsetype);
return(0);
}
So, I'm right- the problem there is Spring's handling of "immediately".
If you delay it the return value is used, haven't you read my post? Return 0 means corpsetype = 0 if you had any sleeps in there. If you want another corpse type return 1 or something.
Why bother checking for nonterminating Killed() functions? That should be obvious to the mod maker.
WTF is that with stacks causing frame changes? I've never had that, I've had scripts that locked up completely with a sleepless loop and the whole game halted, no "after x commands go to the next frame". Also I'm seeing traces of evidence that you don't really understand what a stack does in an interpreter. It doesn't grow with the number of commands, it only grows with function calls and after those functions return it shrinks again. The stack just stores which address to return to and a bunch of local vars. If you want my guess, call-script probably causes a sleep.
Why bother checking for nonterminating Killed() functions? That should be obvious to the mod maker.
WTF is that with stacks causing frame changes? I've never had that, I've had scripts that locked up completely with a sleepless loop and the whole game halted, no "after x commands go to the next frame". Also I'm seeing traces of evidence that you don't really understand what a stack does in an interpreter. It doesn't grow with the number of commands, it only grows with function calls and after those functions return it shrinks again. The stack just stores which address to return to and a bunch of local vars. If you want my guess, call-script probably causes a sleep.
KDR, write a script that tries to execute 20+ instructions without a sleep. Watch what it does.
Come back to arguing with me after trying that. Spring doesn't always execute COB instructions on the frame they're called, period. We've known about this problem for ages. It's just a part of how things work.
It's not the same as an endless loop, which short of being halted by Killed() will run until Spring locks. Which is how it should be, frankly.
I'll try the return 1. I definitely don't know why that's supposed to work, but meh, if it fixes it, great. I don't think that's going to address the fundamental problem here, which is that the call-script occurs multiple times in the frame...
Come back to arguing with me after trying that. Spring doesn't always execute COB instructions on the frame they're called, period. We've known about this problem for ages. It's just a part of how things work.
It's not the same as an endless loop, which short of being halted by Killed() will run until Spring locks. Which is how it should be, frankly.
I'll try the return 1. I definitely don't know why that's supposed to work, but meh, if it fixes it, great. I don't think that's going to address the fundamental problem here, which is that the call-script occurs multiple times in the frame...
There isn't any "obvious" way to see that, right now. Nor does the code work like I've described. Using a static upper limit would cut out a lot of crap in that whole code- end with a return (0) like everything else, instead of having to use special cases or whatnot. Go look at the way the code's handling these events- it appears that it starts a ticker if it encounters any significant delay at all... why not just start a ticker every time, then halt the ticker if the script returns (0), or X number of frames has passed? The way it's written right now is backwards, imo.Why bother checking for nonterminating Killed() functions? That should be obvious to the mod maker.
This did not result in the behavior you stated it would. I get corpsetype 1 regardless that severity >50 (i.e., I self-destructed the Unit).
So, is that just mis-written BOS, or does it just not work? I'm not trying to pick a fight with you, KDR- there are a number of fundamental problems here, and it could be I'm just stupid, and haven't written my code correctly. The multiple-projectiles thing is definitely real, and this part isn't working right, either.
In case anybody cares what TinyExplosion, et al look like, here's a sample of the function being called:
Note that, yes, it calls another function, and won't terminate until it returns. RandomDeathSound() is a very similar function that uses a random number to pick sounds and play them. No rocket-science stuff.
This shouldn't matter, either. But it does.
Code: Select all
Killed(severity, corpsetype)
{
GET PRINT (severity, corpsetype);
if (severity <= 50)
{
corpsetype = 1;
call-script TinyExplosion();
return (0);
} else
{
corpsetype = 2;
call-script SmallExplosion();
return (1);
}
GET PRINT (severity, corpsetype);
return(1);
}
In case anybody cares what TinyExplosion, et al look like, here's a sample of the function being called:
Code: Select all
TinyExplosion()
{
var Random;
Random = RAND(1,4);
if (Random == 1);
{
emit-sfx Rubble_Gun from EXPLODEPIECE;
//emit-sfx Rubble_Gun2 from EXPLODEPIECE;
}
if (Random == 2);
{
emit-sfx Rubble_Gun from EXPLODEPIECE;
//emit-sfx Rubble_Gun2 from EXPLODEPIECE;
//emit-sfx Rubble_Gun3 from EXPLODEPIECE;
}
if (Random == 3);
{
emit-sfx Rubble_Gun2 from EXPLODEPIECE;
//emit-sfx Rubble_Gun3 from EXPLODEPIECE;
//emit-sfx Rubble_Gun2 from EXPLODEPIECE;
//emit-sfx Rubble_Gun from EXPLODEPIECE;
}
if (Random == 4);
{
emit-sfx Rubble_Gun from EXPLODEPIECE;
//emit-sfx Rubble_Gun from EXPLODEPIECE;
//emit-sfx Rubble_Gun2 from EXPLODEPIECE;
//emit-sfx Rubble_Gun3 from EXPLODEPIECE;
//emit-sfx Rubble_Gun3 from EXPLODEPIECE;
}
call-script RandomDeathSound();
}
This shouldn't matter, either. But it does.
Ok, that works! Good, then that solves that problem. It's not how it should work, imo- the value of corpsetype should always be determined the way it was in OTA. But meh, it works. The more fundamental problem of why I am seeing, for example, 4 projectiles when TinyExplosion calls for 1... still happening.
Ok, for future reference, for anybody who needs to know how this works in the future, if you're going to have a Killed() that is delayed even one frame, then the following functions properly:
Modify values for severity, etc. to set up the whole range of corpsetypes. The return value in the IF / THEN actually controls what Spring is going to use.
Ok, for future reference, for anybody who needs to know how this works in the future, if you're going to have a Killed() that is delayed even one frame, then the following functions properly:
Code: Select all
Killed(severity, corpsetype)
{
if (severity <= 50)
{
corpsetype = 1;
call-script TinyExplosion();
return (corpsetype);
} else
{
corpsetype = 2;
call-script SmallExplosion();
return (corpsetype);
}
return(0);
}
Last edited by Argh on 18 Dec 2007, 19:22, edited 1 time in total.
It can't always work like in OTA because the reference is lost after one frame, only return works after that. We could change it to always use return but that'd break backwards compatibility.
My experiment:
output:

(output is twice as many lines as the code says because that's in a commander unit which gets spawned twice)
My experiment:
Code: Select all
static-var time;
#include "exptype.h"
CLK() {
while(1) {
++time;
sleep 1;
}
}
Create() {
start-script CLK();
sleep 200;
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
get PRINT(time);
}
Code: Select all
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0
Value 1: 6, 2: 0, 3: 0, 4: 0

(output is twice as many lines as the code says because that's in a commander unit which gets spawned twice)