Spawn cubes miss east and west targets

The spawn cubes spawned by the monster spawner will miss the monster spawn spot if the spot is directly east or west of the spawner.

Details
Missed spawn cubes flying directly due east or west will carry on until the game or level ends, even sailing through the walls of the level and eventually wrapping around to the other side of the map. Given enough time, this will result in an endless string of spawn cubes crossing the level (or multiple such streams in case there are multiple monster spawners and/or spawn spots arranged in this fashion).

None of the original commercial Doom games exhibit this bug in their levels.

Cause
This is caused by the id developers finding that trigonometry is too complicated and should be avoided whenever possible.

The A_SpawnFly codepointer counts down the spawn cube mobj's reactiontime variable every time it is called, and spawns the monster if it reaches zero after being decreased.

void A_SpawnFly (mobj_t* mo) {     if (--mo->reactiontime) return;	// still flying  }

Therefore, to obtain the effect of the spawn cube flying to its spawn point, it is important that the initial reactiontime value corresponds to how many times A_SpawnFly will be called until reaching the destination point. The idea is very simple: take the distance to run, divide it by the cube's flying speed, and by the number of tics it takes for A_SpawnFly to be called. (By the way, given how the computation is made, if the spawn cube's states are not homogeneous in length, this will break too, because A_BrainSpit assumes the length of the cube's spawn state is the length of all its flying states.)

This computation is made in A_BrainSpit:

void A_BrainSpit (mobj_t*	mo) {     // spawn brain missile newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT); newmobj->target = targ; newmobj->reactiontime = ((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics; S_StartSound(NULL, sfx_bospit); } Here, P_SpawnMissile will take care of the hard part of separating the spawn cube's speed into both a North-South component (momx) and an East-West component (momz). So we can just take one of these components, and the corresponding distance, and it'll be a lot simpler than having to bother with Pythagoreanizing both axes.

Of course, if the target is directly east or west, then the distance is 0. We're lucky we do not crash because momy will also be zero, logically enough, and we're dividing by it. Oops!

Demos

 * [[Media:WORSTAIM.WAD|A level set up to demonstrate this bug]] (file info). The level contains a monster spawner which will dispense spawn cubes in each cardinal direction, with each spawn spot evenly spaced from it; wait until it shoots east and west to see this bug.