Decoded: Sopwith (1984) by David L. Clark
Source file: SWCOLLSN.C
Beginner friendly, line-by-line code walkthrough by MaiZure

SWCOLLSN.C manages collisions between game objects, player score and ground
destruction

Original code:
http://davidlclark.com/page/sopwith-source-code

Original code with line numbers
http://www.maizure.org/projects/decoded-sopwith/SWCOLLSN_linenum.txt

1     COMMENT
2     COMMENT
3     BLANK
4     COMMENT
5     COMMENT
6     COMMENT
7     COMMENT
8     COMMENT
9     COMMENT
10    COMMENT
11    COMMENT
12    COMMENT
13    COMMENT
14    BLANK
15    COMMENT
16    BLANK
17    COMMENT
18    COMMENT
19    COMMENT
20    COMMENT
21    COMMENT
22    COMMENT
23    COMMENT
24    COMMENT
25    COMMENT
26    COMMENT
27    COMMENT
28    COMMENT
29    COMMENT
30    Includes the main game header (sw.h)
31    BLANK
32    BLANK
33    Import the ends of the object list declared in SWMAIN.C
34    Import the plane objects arrays from SWMAIN.C
35    Import the list of objects from SWMAIN.C
36    Import the current (runtime) ground array from SWGROUND.C
37    Import the initial ground height array from SWGROUND.C
38    Import the playmode defined in SWINIT.C
39    Import the player object
40    Import the number of screen bullet holes
41    Import the number of splattered birds
42    Import the splatter ox flag
43    Import the number of active targets (ground targets)
44    Import the communications buffer
45    Import the game number
46    Import the object end status
47    Import ground redraw flag
48    Import the current game speed settings
49    Import the performance counters
50    BLANK
51    Create a local list of killed objects indexed like the object list
52    Create a local list of killer objects with the same index
53    Create a specific index for the killed list
54    BLANK
55    Create a local variable for collision point delta x check
56    Create a local variable for collision point delta y check
57    Create a local variable for collision object check
58    Create a local variable to index collision arrays
59    Create a local variables for collision offset checks
60    BLANK
61    BLANK
62    BLANK

MAIN COLLISION TEST ROUTINE
63    Declare and define swcollsn with no arguments
64    BLOCK START - swcollsn, collision check procedure called from game loop
65    Declare local object pointers
66    Declare local position holding variables
67    Declare local more x position holders for testing values
68    BLANK
69    Clear collision pointers for upcoming checks
70    Set default x collision adjustment to 2 pixels
71    Set default y collision adjustment to 1 pixel
72    BLOCK START - Swap collision adjustment, for every other frame...
73    Change the x adjustment to its additive inverse
74    Change the y adjustment to its additive inverse
75    BLOCK END - Swap collision adjustment
76    Set the active display to auxillery 
77    Save the top object's x position
78    START BLOCK - Loop through all objects and test positions (outer loop)
79    Set both x test variables to the object in the loop
80    BLANK
81    Set maximum x variable to the end of the object's graphic in world space.
      (For instance, a 16x16 plane located at 850, 30 would mean xmax is 865)
82    Find the world space of the y object graphic offset. Previous example
      would be at ymin = 15. Recall that Sopwith world space has a y of 0 for the
      bottom of the screen
83    BLANK
84    Loop from the testing object's next object...
85    While we still have objects, and the next isn't beyond the base object..
86    START BLOCK - Loop though all other objects (inner loop)
87    Save the new object's x to compare with the old object
88    BLANK
89    If the new object isn't below the old object...
90    And is within sprite distance...
91    Test for pixel-perfect collision between the two objects. Any deaths are
      tagged in the killer/killed array and handled below
92    BLOCK END - Loop through all other objects (inner loop)
93    BLANK
94    If the original object is a plane..
95    And the plane is still active...
96    And not parked..
97    And if the plane is at a low altitude
98    Or if it's a missle or bomb..
99    below a certain altitude...
100   Test for crash in to ground or target. Any deaths are tagged in the killer/killed
      array
101   BLOCK END - Loop through all objects
102   BLANK
103   Set killed pointer to the killed array
104   Set killer pointer to the killer array
105   Loop through all objects until we've reached the kill pointer (could be
      empty and nothing happens)
106   Perform a kill for the two objects indexed in both arrays. Possible tag
      for collision later
107   BLANK
108   Set the killed pointer to the collision check array
109   BLOCK START - Loop through all objects tagged for collision death 
110   If the object's delta x matches the collision check
111   Match the collision delta y
112   BLOCK END - Loop through all objects tagged for collision death 
113   BLOCK END - swcollsn
114   BLANK
115   BLANK
116   BLANK
117   BLANK

TESTS FOR OBJECTS COLLISION
118   Declare and define colltest with 2 arguments
119   Both arguments are pointers to objects
120   BLOCK START - colltest, tests two objects for collision
121   Declares pointers for both input objects and a temporary swap pointer
122   Declares variables for object types
123   BLANK
124   Sets one local pointer to the first input object
125   Sets the other local pointer to the second input object
126   Sets local type variable to that of the first input object
127   Sets other local type variable to that of the second input object
128   If the first object is plane thats already dead or a ghost...
129   or the second object is plane thats dead or a ghost...
130   or both objects are explosion shrapel
131   then return from collision check -- no explosion occurred
132   BLANK
133   BLOCK START - Pointer swap, if object 1 is lower than object 2
134   Set temp pointer to object 1's pointer
135   Set object 1's pointer to object 2's pointer
136   Set object 2's pointer to object 1
137   BLOCK END - Pointer swap
138   BLANK
139   Draw object 1 in the lower right of the screen
140   If drawing the other object relative to the first.., 
141   results in a non-zero comparison (See SWGRAPH.ASM)...
142   ..then there was a pixel collision..
143   BLOCK START - Set collision flags for future processing
144   Flag object 1 for death
145   Flag object 2 as the killer
146   Flag object 2 for death
147   Flag object 1 as the killer
148   BLOCK END - Set collision flags
149   Clear the collision test
150   BLOCK END - colltest
151   BLANK
152   BLANK
153   BLANK

TESTS POINT FOR GROUND COLLISION
154   Declare tstcrash with 1 argument
155   Argument 1 is the object to test
156   BLOCK START - tstcrash, tests an object for collision with the ground
157   Declares a local object pointer
158   Declares local position variables
159   Declares a crash boolean
160   BLANK
161   Sets the local pointer to the input object
162   Draws the input object in the lower right of the screen
163   BLANK
164   Sets the max width to the width of the object graphic
165   BLOCK START - Loop through the width of the object
166   If the ground is higher than the sprite
167   Set hit to true -- the ground is above the entire graphic
168   End the test
169   End ground check
170   Otherwise, if the plane is below the ground...
171   Then skip check
172   Otherwise, test for collision by drawing the ground pixel and hit if color
      result was unexpected.
173   End test
174   BLOCK END - Loop through the width of the object
175   Clear the collision drawing test
176   BLANK
177   If the plane is hit and we have room in the kill array..
178   Flag the object for death
179   There is no killer
180   End collision check
181   BLOCK END - tstcrash
182   BLANK
183   BLANK
184   BLANK

DESTROY OBJECTS
185   Declares and defines kill with 2 arguments
186   Both arguments are object pointers
187   BLOCK START - Performs kill actions between two objects based on type
188   Declares pointers to objects
189   Declares local state, type, and iterators
190   BLANK
191   Point to object 1
192   Point to object 2
193   If object 2 has no pointer, then it must be NULL (ground)
194   If the 2nd object is a bird or flock...
195   but the 2nd type isn't a plane
196   Then exit the function -- no kill occurred
197   BLANK
198   SWITCH on object 1's type
199   BLANK
200   CASE Bomb or...
201   CASE Missile
202   Create an explosion on object
203   Mark the bomb or missile as dead
204   If there is no 2nd object, there must have been a collision with ground
205   Make crater damage
206   Stop playing the sound for the bomb or missile
207   Return to swcollsn
208   BLANK
209   CASE shots/bullets
210   Mark bullets for destruction
211   Return to swcollsn
212   BLANK
213   CASE flares
214   If the flares hit a bomb, missle or the ground..
215   Destroy the flares
216   Return to swcollsn
217   BLANK
218   CASE explosive shrapnel
219   If the shrapnel hit the ground..
220   Mark the shrapnel to disppear
221   Stop playing shrapnel sound
222   End check for ground hit
223   Return to swcollsn
224   BLANK
225   CASE target building
226   If the building has already been destroyed..
227   Return to swcollsn
228   If a flare or shrapnel hit the building....then no damage
229   Return to swcollsn
230   BLANK
231   If a bullet hit the building...
232   And the cumulative damage of the building...
233   Is less than the game number (target health == game number)
234   Then it's still alive, return to swcollsn
235   BLANK
236   Flag the building for destruction
237   Create explosion
238   BLANK
239   Set the display to primary video memory
240   Update the world minimap with the new state of object 1
241   Set the display to aux
242   BLANK
243   Apply score to destroyer based on orientation (type), and color
244   Decrement the target counter and if there are no more...
245   Trigger end game
246   Return to swcollsn
247   BLANK
248   CASE airplane
249   If the plane has already crashed...
250   ...or is a ghost that crashed..
251   Return to swcollsn
252   BLANK
253   If the plane is the player and has already won the game
254   Then return, player can't die during end sequence
255   BLANK
256   If the plane collided with a flare or...
257   ..a bird, but the plane is parked...
258   Then return - no damage
259   BLANK
260   BLOCK START - Plane crash in to ground, if plane hit the ground
261   If the plane is falling, the plane crashes so..
262   Stop playing the plane sound
263   Start an explosion
264   Damage the ground
265   End case for falling plane but..
266   If the plane is still alive, it still crashes
267   Add scores to the plane
268   Start can explosion
269   Damage the ground
270   End case for plane crashing
271   BLANK
272   In all cases, the plane crashed
273   Return to swcollsn
274   BLOCK END - Plane crash in to ground
275   BLANK
276   If the plane was already destroyed then
277   Return to swcolln -- no crash
278   BLANK
279   If the plane is falling...
280   and the plane is the player...
281   and the player hit bullets
282   Then add a shot hole to the screen
283   Otherwise, if the plaer hit a bird...
284   Or flock..
285   Add some splattered birds
286   Return to swcollsn
287   End case for falling player
288   BLANK (this block needs some serious refactor)
289   If the plane hits shots or birds...
290   or oxen, or flocks
291   and this is the player...
292   Then if it really really really was bullets..
293   Add a shot hole on the screen
294   But if it was an oxen
295   Splat that ox
296   Otherwise it must be a birdie 
297   Smash!
298   But if we're flying....and we've hit something
299   Change to wounded
300   End case for flying damage
301   Return to swcollsn
302   But if we're stalled
303   Then we stalled AND wounded
304   Return to swcollsn
305   End case for stalled
306   BUT IF WE HIT SOMETHING THAT ISN'T COVERED YET.....
307   Make a small explosion anyway
308   BLOCK START - Plane hit plane
309   Set a collision x point..
310   To the average of both object's x movement vectors 
311   Plus the turn x adjustment
312   Set a collision y point...
313   To the avearge of both ocject's y movement vectors
314   Plus the turn y adjustment
315   Record the object that collides
316   BLOCK END - Plane hit plane
317   End case for hitting something else
318   BLANK
319   Object hits a plane
320   Add score for the plane
321   Return to swcollsn
322   BLANK
323   CASE Bird
324   If the bird hits something that can hurt it, kill the birds
325   Return swcollsn
326   BLANK
327   CASE Flock
328   If the flock doesn't hit other birds...
329   But it is a flying object...
330   Then loop through 8 times...
331   And separate the block in to birds..
332   Destroy the flock
333   Twice!
334   End case for flock
335   Return to swcollsn
336   BLANK
337   CASE Oxen
338   If the oxen is already dead...
339   Return to swcollsn
340   If the oxen hit an explosion or a flare..
341   Return to swcollsn
342   Otherwise, deduct some score for whoever hit it
343   Kill the oxen
344   Return to swcollsn
345   SWITCH END - On object type
346   BLOCK END - kill
347   BLANK
348   BLANK
349   BLANK

PENALIZE PLAYER SCORE
350   Declare scorepenalty with 3 arguments
351   Argument 1 is the object type hit
352   Argument 2 is a pointer to the plane that hit the object
353   Argument 3 is the score penalty to assess
354   BLOCK START - scorepenalty, assesses a score penalty to a player
355   Declare a local pointer to an object
356   BLANK
357   Points to the input plane
358   If the plane hits a shot, bomb, missile..
359   Or another plane that..
360   Is still flying..
361   Or is wounded..
362   Or is falling...
363   ..and hasn't exploded yet
364   And the plane isn't on the ground
365   Then assess the penalty
366   Return true for the penalty
367   End case for true penalty
368   Return false for no penalty
369   BLOCK END - scorepenalty
370   BLANK
371   BLANK
372   BLANK
373   BLANK

ADD SCORE FOR TARGETS
374   Declare and define scoretarg with 2 argument
375   Argument 1 is the target destroyed
376   Argument 2 is the score amount
377   BLOCK START - scoretarg, add score for target destruction
378   Declare local object pointer
379   BLANK
380   Point to the target to destroy
381   If we're not in multiplayer mode..
382   Or there's only one player..
383   Then if the target's color matches the players color...
384   Deduct the score amount from the playe
385   Otherwise it's an enemy target so..
386   Add the score to the player
387   Update the score display
388   Otherwise it's multiplayer so figure out which player it is..
389   Add the target score to the player of the opposite color
390   Update the player's score
391   End case for multiplayer update
392   BLOCK END - scoretarg
393   BLANK
394   BLANK
395   BLANK
396   BLANK
397   BLANK

ADD SCORE FOR PLANES
398   Declare scorepln with 1 argument
399   Argument 1 is the object that scored
400   BLOCK START - scorepln, adds/subtracts score to the target object
401   BLANK
402   Adds or subtracts 50 points depending on color of target and plane
403   BLOCK END - scorepln
404   BLANK
405   BLANK
406   BLANK
407   BLANK

DISPLAY SCORE
408   Declare dispscore with 1 argument
409   Argument 1 is the pointer to the player's plane
410   BLOCK START - dispscore, update the score display
411   Declare a local pointer to the player object
412   BLANK
413   Position the cursor at (2,24) or (9,24) depending on the player
414   Match the score color to the player color
415   Display the score with 6 characters
416   BLOCK END - dispscore
417   BLANK
418   BLANK
419   BLANK
420   BLANK

DEBUG DISPLAY
421   Declare dispd with 2 arguments
422   Both arguments are integers, one for the value and the other for size
423   BLOCK START - dispd, display value (usually for debug purposes)
424   Declare an iterator intialized to zero
425   Declare more iterators
426   Declare a boolean flag initialized to true
427   BLANK
428   If the input number is negative..
429   Flip the sign
430   Print a negative sign
431   Increment our iterator
432   End case for negative numvers
433   Loop through decimal magnitudes starting with 10000 down to 10
434   If there the value place is non-zero or it's not first, then...
435   Clear the first flag
436   Print the (coerced) number
437   Increment the count iterator
438   End loop through magnitudes
439   Otherwise, print the score, (always zero here?)
440   Increment the counter
441   If we still have places remaining
442   Print spaces
443   BLOCK END - dispd
444   BLANK
445   BLANK
446   BLANK
447   BLANK
448   BLANK
449   BLANK

BOMB DAMAGE ON GROUND
450   Defines the impact strength of bombs on the ground. Bomb graphic is 8x8
      and these values are the delta y subtracted from the ground height across the
      8 pixels
451   BLANK
452   Declare and define crater with 1 argument
453   Argument 1 is an input object
454   BLOCK START - crater, makes a crater in the ground
455   Declare local variables for position
456   Declares more local variables for position
457   BLANK
458   Set variable to the middle of the sprite in world space
459   Set another variable 7 pixels in front of the middle
460   BLANK
461   BLOCK START - Damage ground
462   Start at the current ground height
463   If the ground has been damaged below a height of 20..
464   Set the base height to 20
465   Subtract the damage from the vector on line 450 and check base
466   Clamp base if necessary...no bombing through the world
467   Remove the clamped amount of damage from the ground
468   BLOCK END - Damage ground
469   Set flag to redraw ground
470   BLOCK END - crater
471   BLANK
472   BLANK
473   BLANK
474   BLANK

TEST EQUALITY BETWEEN TWO INPUT FUNCTIONS
475   Defines equal with 2 arguments
476   Argument 1 and 2 are function pointers
477   BLOCK START - equal, tests if two function pointers are the same
478   Returns true or false if function pointers are the same
479   BLOCK END - equal
480   EOF