Stuart Cheshire
Sidney Sussex College
The other part of the program is called every 1/50 of a second from the 50Hz video interrupt, and deals with all the processes which must happen at a constant speed, such as the movement of flying shells and driving of the tank. It would not be acceptable if you were being chased along the road by an enemy when your tank suddenly slowed down because your screen was a little more crowded.
In the prototype program the tank movement was a foreground process, and the constant speed was achieved by measuring the how long it was since the last time the tank was moved, and multiplying this value by the velocity to find out how large to make the movement step.
Now that the tank is moved at regular intervals instead, the code is much simpler, and the way it reacts when colliding with buildings and other tanks is much more acceptable.
The keyboard is scanned for the keys which select the building mode. The available options are: Building, road/bridge, lay mine, place pillbox, and farm forest. When such a key is pressed, various things are checked, such as whether the tank is carrying the required resources, and whether the man is currently inside the tank and available to do building work. If all is well, then the man is given the required resources from the tank's inventory. If for any reason the man is unable to achieve the objective, for example he is unable to find a way past an obstacle in his way, then the resources will be replaced in the tank's inventory when (and if) he returns.
The obvious way implement them is for each machine to fire shells from its player's pillboxes towards enemy tanks, in the same way that it handles shells fired by its player's tank towards enemy tanks.
The problem with this is that a large amount of workspace must be reserved for holding many moving shells, to cope with the common situation where several players team up to attack one who is winning. If six players attack another player's fortress which is fortified by pillboxes, then that player's machine will have to handle perhaps 24 shells simultaneously, plus any the player fires manually from the tank. The problem is not so much the extra memory required, but the extra work which will be imposed upon the machine, making other processes run slower. It would be unfortunate if a player was defeated in a battle such as this because he was doing too well and had captured too many pillboxes and his machine couldn't handle the number of shells that they were trying to fire.
There is another problem. When the game starts, all pillboxes are allied to no one and are equally hostile to all players. Who has the responsibility of firing them? Is the work somehow shared equally between all the machines? If a machine is disconnected, who takes over its work?
The logical jump which had to be made to solve the problem was to move the responsibility for handling shells from the player who is firing them to the player who is being fired at. This means that if a machine can handle eight such shells, then the inability to handle more is likely to be of little significance when eight shells from different pillboxes are simultaneously converging upon a tank. It also means that, in the example above, of six players attacking one, that player's pillboxes could be firing up to 48 shells on his behalf without the undue extra load that that would otherwise impose upon his machine.
The algorithm works as follows: For each pillbox:
There are four keys which can be used to move the screen manually, overriding these automatic rules. This enables the player to look at areas of the map other than that which the program assumes he will be interested in.
All of these movements are subject to the restriction that the player's tank can never be moved off the screen. It is not possible to move the screen to look at any part of the map the player wishes, he can only see the region in the immediate vicinity of his tank.
The tank is then moved forwards a distance according to its current speed and direction.
It is then checked to see if it intersects with any buildings. If so then it is pushed away until it no longer intersects with any buildings. By careful tuning of the algorithm, the behaviour of the tank when it hits a solid object is made to appear natural. The calculation of the correct behaviour of colliding objects is often a problem in games. Often it is not solved at all well.
A similar procedure is used when the tank is on a boat, to make the river banks appear semi-solid. This means that if the boat makes a glancing collision with the bank of a river, it will be gently pushed back into the river, but if it hits a river bank hard then the tank leaves the boat and moves onto the land.
If he runs into a solid obstacle (or a river) he will run along the edge looking for a gap (or a bridge). If none can be found then the man gives up and returns to the tank. No attempt is made to plan the best route beforehand. Such planning algorithms are in the scope of A.I. research, although if time had permitted it would have been interesting to try to find some kind of simple solution. This will be easier to experiment with in the C implementation than in 6502 assembler.
When he reaches the target location, he stops moving and waits.
When the Token arrives, the man generates the instruction to perform the required building operation, unless something else has happened to that region of the map which makes the building operation impossible. The flag is then set which causes the man to head back towards the tank.
If the shell hits a solid obstacle, then a flag is set which makes it stop moving, and wait. When the Token arrives, an instruction is generated to damage the tank or building which was hit, unless someone else's shell has already destroyed the object while this shell was waiting.
The x and y components of the shell's movement are calculated using a sine wave table to quickly find sin(theta) and cos(theta), where the angle theta is the direction in which the shell is travelling.
It is not a scan-line algorithm; it is the simplest, naïve, ink-blot type flood-fill algorithm which, when it fills a square, simply checks the four adjacent squares to see if they, too, are eligible for filling.
However, in this case, it is not a recursive routine using a stack; it uses a queue -- and when it inserts coordinates into the queue a time delay of about 2/5 of a second is also attached. This means that the routine may often examine the queue and find it not empty, but nevertheless have nothing to do because the objects there are not yet ready to be removed. Only when a timer has decremented to zero can the flooding operation proceed further. This causes the flooding to progress at a leisurely rate of about 21/2 squares per second.
As you will realize, this routine is not used for flooding pixels with colour, it is used for flooding craters with water. Whenever a crater is created in the map (by a mine or tank exploding, or any other cause) the four adjacent squares are checked to see if they contain water. If they do, then the M-coordinates of the newly formed crater are inserted into the flooding queue with a small time delay attached. The crater then fills up with water a small time later, and if any of its neighbours are also craters, then their M-coordinates are similarly inserted into the flooding queue with a small time delay, so that large areas can be gradually flooded with water.
This routine performs the propagation of chain-reactions in exploding minefields too. A bit-flag in each queue item identifies whether it is a pending flood operation or a pending mine explosion.
The time delay is to produce a pleasing looking flood, which proceeds along a trench of craters at a sensible rate. Any tank which is in the water also gets pushed along in the direction of the `flooding'.
If the queue is full when the routine tries to insert flooding co-ordinates then they are lost, but the flood dæmon is woken up. This then slowly crawls across the map as a foreground process, looking for craters adjacent to water which have obviously been lost by the normal flooding routine. This means that it is possible to get an open trench next to the sea which is not flooded, but eventually it will be discovered and the appropriate changes will be made to the map.
If the queue is full when the routine tries to insert explosion co-ordinates then they are lost and cannot be recovered. This is not a major problem for three reasons:
![]()