I've fixed a number of annoying, mysterious bugs when I came to a realization a few days ago. It started when I was working on testing a level and noticed at first some sprites stopped behaving as intended, a few tests later, they straight up disappeared before my eyes, one after another. Well, three total. I got to looking into it and thinking about it and I'll try and explain what was happening.
When a level is entered or started, some sprites are already initialized. Universal sprites that are used throughout the game. A few are level and scenery sprites (0-3) and some are player based and UI, special effects, etc. (228-255) This means that sprites 4-227 are set aside for level use. their counters are set at the beginning of every level by a robot and cleared upon leaving so they can be recycled and used again. so upon entering a level, in the very first two cycles, nearly every robot controlling a sprite runs a routine similar to this;
set "local" to "robot_id"
if "local" >= "lowsprite" then "next"
set "local" to "('robot_id'+('player'-'lowsprite'))"
: "next"
set "local2" to "thisx"
set "local3" to "thisy"
. "@sprite&local&"
gotoxy 0 "robot_id"
set "spr&local&_ccheck" to 2
set "spr&local&_refx" to "local30"
set "spr&local&_refy" to "local31"
set "spr&local&_width" to 2
set "spr&local&_height" to 1
set "spr&local&_cx" to 0
set "spr&local&_cy" to 0
set "spr&local&_cwidth" to 2
set "spr&local&_cheight" to 1
set "spr&local&_x" to "local2"
set "spr&local&_y" to "local3"
put c?? Sprite "local" at "spr&local&_x" "spr&local&_y"
I say in the first two cycles because 'gotoxy' is a cycle ending command. And I say nearly every robot because their is a caveat to that rule, every robot that is there at the start of the level. So not disposable sprites and robots like bullets or water splashing, those come and go though the course of the level, so they are not initialized at the beginning, that happens on the fly and uses a different format for initialization. it looks like this;
restore "#reorder" 1
restore "unpause" 1
restore "#pause" 1
loop start
if "spr('loopcount'+'lowsprite')_width" = 0 then "next"
loop for 222
* "too many sprites"
goto "done"
: "next"
set "local" to "('loopcount'+'lowsprite')"
. "@sprite&local&"
set "local2" to "bulletx"
set "local3" to "bullety"
set "local8" to "bulletdir"
set "spr&local&_ccheck" to 2
set "spr&local&_vlayer" to 1
set "spr&local&_refx" to 0
set "spr&local&_refy" to 7
set "spr&local&_width" to 1
set "spr&local&_height" to 1
set "spr&local&_cy" to 0
set "spr&local&_cx" to 0
set "spr&local&_cheight" to 0
set "spr&local&_cwidth" to 0
set "spr&local&_x" to "local2"
set "spr&local&_y" to "local3"
gotoxy 1 "('robot_id'+4)"
sfx 27
put c0f Sprite "local" at "spr&local&_x" "spr&local&_y"
I do it this way because when certain events in the game happen like saving or loading, MegaZeux assigns new numbers to the robots. You can't count on the robot_id counter to yield you a sprite that is not being used. So the program looks for an unused sprite by checking if that sprites width is greater than 0. This system has worked great, sprites that are there from that start of the level are protected, the robots go to a basically protected spot on the board and the ones that are temporary search for an vacant sprite and those robots go to a different spot on the board. on other thing I should mention is that these temporary robots need to be rearranged when save/loading in order to not be overwritten by new incoming temporary sprites. I do that like so;
| "#reorder"
gotoxy "('robot_id'+2)" 31
gotoxy 1 "('robot_id'+4)"
goto "#return"
when a temporary robot is initializing a sprite, it restores the zapped label '#reorder', so that if a save or load event happens this label can be called and that robot will move to a temporary spot on the board and then move to a spot corresponding to it's robot ID. because it's ID # will be different after the event it needs to find a new spot to be protected from being overwritten.
Whew, so now to the bug I was having, well it's very simple actually. See, I forgot that I had set everything up this way. I wasn't following the rules I had put in place. I was using a wait command at the very beginning of some programs, before the sprite was initialized or the robot moved, in order to time some puzzles. I have a save at the beginning of a level so you can restart from there if you need to. so by the time these robots began executing code, their ID # had already changed and they would overwrite another robot and re configure the sprite.
So the fix was to have the waiting happen after the sprite has initialized and the robot has moved, but before it starts actually executing code for whatever its doing on the board. this fix was simple, under standing the problem was a little more of a challenge.
Now back to the game!