Decoded: Sopwith (1984) by David L. Clark Source file: SWGRPH.ASM Beginner friendly, line-by-line code walkthrough by MaiZure SWGRPH.ASM is assembly to drive the CGA display in Sopwith. Original code: http://davidlclark.com/page/sopwith-source-code Original code with line numbers http://www.maizure.org/projects/decoded-sopwith/SWGRPH_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 COMMENT 7 COMMENT 8 COMMENT 9 COMMENT 10 COMMENT 11 COMMENT 12 COMMENT 13 COMMENT 14 COMMENT 15 COMMENT 16 COMMENT 17 COMMENT 18 COMMENT 19 COMMENT 20 COMMENT 21 COMMENT 22 COMMENT 23 COMMENT 24 COMMENT 25 BLANK 26 BLANK 27 Sets the assembler to use small memory model using C calling conventions. These are passed as arguments to the assembler in the makefile (SW.MAK). Small memory model implies data and stack are in the same 64kb segment. 28 Includes macros provided with MASM 29 BLANK 30 Creates a local code segment, linker will combine upcoming code with other code 31 BLANK 32 Imports @AB variable. @AB == 4 33 Imports game header definitions in assembly (see SW.HA) 34 BLANK 35 Function swdisp - Removes and displays all objects 36 Function swground - Displays the ground at the title screen 37 Function swputsym - Draws a graphic at input coordinates 38 Function swputcol - Tests a graphic for collision at a point 39 Function swclrcol - Removes a graphic from the screen 40 Function swpntsym - Draws a pixel color at a specific point 41 Function swpntcol - Tests a specific point for collision 42 Function get_type - Returns the video mode 43 Function set_type - Sets the video mode 44 Function setvdisp - Sets the video RAM as the display source 45 Function setadisp - Sets the aux buffer as the display source 46 BLANK 47 Imports dispoxsplat from SWDISP.C to display the splattered ox 48 BLANK 49 BLANK 50 BLANK 51 COMMENT 52 BLANK 53 BLANK MAIN GAME RENDERING FUNCTION 54 Define swdisp to display the world objects 55 Store the previous frame 56 Store the DI register 57 Store the SI register 58 Store the ES register 59 BLANK 60 COMMENT 61 COMMENT 62 COMMENT 63 Set video RAM as the active display segment 64 BLANK 65 COMMENT 66 COMMENT 67 COMMENT 68 COMMENT 69 BLANK 70 Move the top object pointer to BX 71 BLANK 72 Label disploop: Loop through objects to display 73 Update flags on BX value (NULL or not) 74 If BX has a value then jump to line 77 75 BX has no value, so all objects have been processed. Return 76 BLANK 77 Label disp00, object processing start. Move obj delete flag to AX 78 Compare AX (delete flag) with the object's draw flag 79 If either flag is zero, nothing to delete/redraw so jump to line 94 80 Check if the object is only 1 pixel in size 81 If only 1 pixel, jump to line 94 82 Move the old symbol pointer in to AX 83 Compare the new graphiv with the old graphic 84 If the symbols do not match then jump to line 94 85 They match, so check if the object is moving. Move Y value to AX 86 Compare Y with the old Y to see if there is vertical movement 87 If the y values are different, it is moving vertically - jump to line 94 88 Move the object's old x in to AX 89 Add the screen movement factor to AX 90 Check if the new x and the adjusted old x match. 91 If they don't match, then it's moving with x so jump to line 94. 92 If we've made it here, it may be ready to display, test draw on line 121 93 BLANK 94 Label disp0: Time to XOR delete the old object 95 Check for the delete flag by comparing 0 with the flag 96 If it IS zero, then we don't have to delete. Jump to line 103 97 Otherwise, we let's set up for delete. Move the old y in to DI 98 Move the old x in to SI 99 Move the old symbol reference in to DP 100 Move the object's color (it's team) in to AX 101 Call drawsym (line 508) 102 BLANK 103 Checks if the draw flag is asserted or not 104 If it is zero, there's nothing to draw so jump to line 129 105 We have to draw so load the x coordinate in to SI (obj pointer in BX) 106 Compare the object's x coordinate with the left display coordinate 107 If object x is less than screen, its not on screen, jump to line 128 108 Compare the object's x coordinate with the right display coordination 109 Greater than right side? Then still not on screen so jump to line 128 110 It must be on screen, so get it's offset on the screen in to SI 111 Call testox (line 176) to see if it's been hit, which skips drawing. 112 Ox was hit? Skip drawing by jumping to line 128 113 BLANK 114 Push the old object x coordinate (on screen) in to oldx 115 Save the object's y in to DI 116 Move the DI in to old y to store its on screen y 117 Move the object's graphic pointer in to BP 118 Move the object's color (team) in to AX 119 Call drawsym to execute drawing on line 508 120 BLANK 121 Check for a display object pointer in the object 122 No display? Then Nothing to do so jump to line 129 123 There is a display so save the object's pointer 124 Call the display function (uses stored BX) 125 Restore BX stored on line 123 126 We're done, so jump to line 129 127 BLANK 128 Object was not drawn so save 0 in to draw flag for future comparison 129 Move the next object pointer in to the current object pointer 130 Redo everything above for the next object on line 72 131 BLANK 132 COMMENT 133 COMMENT 134 COMMENT 135 COMMENT 136 BLANK 137 Procedure dispdel removes deleted objects from the screen 138 BLANK 139 Move the top deleted object pointer in to BX 140 BLANK 141 dispdlop table, 142 Check of there is actually an object to delete 143 If no object, then go to line 156 144 BLANK 145 Check if the object is to be deleted (delete flag is 1) 146 If it is zero (no delete), then jump to line 154 147 If it needs to be removed, then move the old y coordinate in to DI 148 Move the old x coordinate in to SI 149 Move the graphic pointer in to BP 150 Move the object color/team in to AX 151 Call xor remove procedure on line 508 152 BLANK 153 No need to remove so load the next candidate object in to BX 154 Jump back to line 141 to test for removal again 155 BLANK 156 dispret label, return from deleting objects 157 Done removing objects, check if the ox is splattered 158 If it's splattered, then skip ground display and jump to line 164 159 Otherwise, we need to update the ground display, 160 Check if the ox is still ok 161 If so, jump to finish on line 164 162 The ox was splattered so call the procedure to draw splat in SWDISP.C 163 BLANK 164 Procedure dispdone wraps up the call to swdisp 165 Unset display init 166 Unset forced draw 167 Restore ES that was stored on line 58 168 Restore SI that was stored on line 57 169 Restore DI that was stored on line 56 170 Restore the previous stack frame 171 Return to caller 172 BLANK 173 BLANK 174 COMMENT 175 BLANK 176 Procedure testox, which checks if splattered ox interferes with draws 177 Check for splattered ox 178 No, then nothing to do here, skip to line 189 179 BLANK 180 Store AX 181 Store DX 182 Object x current in SI, move to AX 183 Moves 1/3rd of the screen size in to DL 184 Divides AX by 109, result is in AX 185 Updates flags (sign, zero, and parity) 186 Restore DX stored on line 181 187 Restore AX stored on line 180 188 BLANK 189 Return to caller (line 112) 190 BLANK 191 COMMENT 192 BLANK 193 Procedure dispgrnd displays the ground 194 Clear DF in flags to ensure increments of SI/DI 195 Check if this is the first time we're displaying ground 196 If so, we don't need to erase old ground, jump to line 206 197 We're erasing old ground, but first check if screen is moving 198 It's moving so we need to erase, jump to line 203 199 We're not moving, but check if display is set to forced redraw 200 It is forced so jump to dg0 to erase ground 201 Return to caller, ground doesn't need to update 202 BLANK 203 We need to erase old ground. Load old ground point in to SI 204 Call ground redraw with XOR on line 219 205 BLANK 206 Prepare to draw ground by storing DS to AX 207 Then move AX to ES (can't move segments directly) 208 Load the ground address in to SI 209 Offset the display in to the ground array, 1 byte/pixel per ground point 210 Save the location in the ground array to BX 211 Load the ground destination area in to DI 212 Set the counter register to half the screen width 213 Move from SI to DI a word (2 bytes) at a time. Hence half screen in CX 214 BLANK 215 Move the ground address in to SI 216 Display the ground using dispg starting on line 219 217 Return 218 BLANK 219 Move the odd raster line offset in to DX 220 Then move it in to BX 221 Move up one line from position in MX 222 BLANK 223 SI is pointing to the beginning of the line, move to AL (i.e. 89) 224 Then to CL 225 Since line 0 is at the bottom of the screen, invert height (89-200=-111) 226 Twos complement -111 becomes 111. Thus a height of 89 is at screen y 111 227 Shift it right, effectively halving it due to interlacing. 228 Move the line width (80) int o CH 229 Multiplies the screen width by the height to find the first pixel 230 BLANK 231 Checks if the first pixel is on the even (base) or odd (roff) line 232 If we're on the correct line, jump to line 238 to prep memory address 233 Otherwise, we're off by 1 line, so add DX (raster offset) to AX 234 The odd offset lines need to flip the offsets, twos complement invert BX 235 Same with DX 236 Swap the values in BX (screen width) and DX (odd raster offset) 237 BLANK 238 We're ready to set up memory. Add the display offset to AX 239 AX becomes the target in the display segment 240 BLANK 241 Move the memory location of the ground start in to BP 242 Move BP to the end of the screen display 243 Assert bits 7 and 8 in CH, base pixel is white and even though CGA packs 4 pixels per byte, we're only going to do each pixel individually and rotate as needed 244 Move the first ground height in to AH (for comparing heights each sweep) 245 Set ES to video out segment 246 BLANK 247 Start the draw loop 248 Load the next ground height in to AL 249 Compare this height with the previous height 250 If new height is higher, then jump to line 256 251 If new height is lower, then jump to line 266 252 BLANK 253 If they are the same, then XOR the dot at the address for the height 254 Get the next pixel starting on line 275 255 BLANK 256 We need to move up a line, changing raster segments. Add our neg offset 257 Invert current segment offset 258 Invert other segment offset 259 Exchange them since moving lines moves segments 260 Draw the dot (may not be the endpoint, but we plot anyway for a line) 261 Increment the last height 262 Check if the heights now match 263 If we need to keep moving up, jump back to line 256 and do this again 264 Otherwise, go to the next pixel on line 275 265 BLANK 266 The next ground pixel is below the current, lets change raster segments 267 We've changed basis, like the above case, so negate BX 268 Then DX 269 Then swap again 270 XOR the mask (0xC0 - single dot in CGA) 271 Drop the height comparison 272 Check if we're at the correct height 273 IF not, jump back to line 266 and do this again 274 BLANK 275 Move to the next pixel, we shift the mask two bits. First shift... 276 And second shift...(why not just shift 2 bits outright? Clobber risk?) 277 See if we've shifted our pixel out of the byte (happens every 4 pixels) 278 If not, then we're ready for the next pixel. Jump back to line 247 279 Move to the next byte in video memory 280 Restart the XOR mask (0xC0 = 11000000) 281 Check if we've reached the end of the ground array on screen 282 Not done? Get back to work on line 247 283 We are done, so return to caller 284 BLANK 285 BLANK 286 BLANK DRAW GROUND FOR TITLE SCREEN 287 COMMENT 288 BLANK 289 Define swground to draw the ground at the title screen 290 Store the previous frame 291 Store the DI register 292 Store the SI register 293 Store the ES register 294 Call dispgrnd, general ground drawing function 295 Restore ES register stored on line 293 296 Restore SI register stored on line 292 297 Restore DI register stored on line 291 298 Restore the previous stack frame 299 Return 300 BLANK 301 BLANK 302 BLANK 303 BLANK 304 COMMENT 305 BLANK CLEAR COLLISION MASK TEST 306 Defines swclrcol to remove collision test drawings 307 Store the DI register 308 Store the SI register 309 Store the ES register 310 BLANK 311 Clear DF in flags so we move forward in memory 312 Move the display segment in to ES 313 Move the display offset in to SI (Now reading from ES:SI) 314 Move SI to the last line 315 Clear the base rastor lines on line 325 316 Change to start of other raster line, 0x1000 bytes ahead 317 Clear the remaining raster lines on line 325 318 BLANK 319 Restore the ES register stored on line 309 320 Restore the SI register stored on line 308 321 Restore the DI register stored on line 307 322 Return 323 BLANK 324 BLANK 325 Define clearhalf procedure to XOR half of the screen (even or odd lines) 326 Start at the beginning 327 Start the counter at 8 328 Clear the AX register 329 BLANK 330 Start a loop by storing 8 pixels (word == 2 bytes == 8 pixels in CGA) 331 Store another 8 bytes for a total of 16 pixels 332 Store another 8 bytes for a total of 24 pixels 333 Store another 8 bytes for a total of 32 pixels 334 Store another 8 bytes for a total of 40 pixels 335 Store another 8 bytes for a total of 48 pixels 336 Remember we started at the bottom (line 314), so go up one raster line. This technically moves us up 2 rows because we're only working in one half of the interlace right now 337 Loop 8 time, automatically decrementing CX 338 Return to caller 339 End procedure for clearhalf 340 BLANK 341 BLANK 342 COMMENT 343 BLANK DRAW A GRAPHIC 344 Procedure swputsym draws a symbol to a location 345 Create a new frame in BX 346 Store the previous frame 347 Store the SI register 348 Store the DI register 349 Store the ES register 350 BLANK 351 Load argument 1 in to SI, the x coordinate 352 Load arugment 2 in to DI, the y coordinate 353 Load argument 3 in to BX, the object pointer 354 Load the object's graphic pointer in to BP 355 Load the object's color in to AX 356 Call drawsym on line 508 to XOR draw it 357 BLANK 358 Restore the ES register stored on line 349 359 Restore the DI register stored on line 348 360 Restore the SI register stored on line 347 361 Restore the previous stack frame 362 Return 363 BLANK 364 BLANK 365 COMMENT 366 BLANK DRAW A POINT 367 Procedure swputpntsym to draw a colored point 368 Store the previous frame 369 Create a new frame 370 Store the SI register 371 Store the DI register 372 Store the ES register 373 BLANK 374 Load argument 1 in to SI, the x coordinate 375 Load argument 2 in to DI, the y coordinate 376 Load argument 3 in to BP, the color/team 377 Call draw point on line 601 378 BLANK 379 Restore the ES register from line 372 380 Restore the DI register from line 371 381 Restore the SI register from line 370 382 Restore the BP register from line 369 383 Return to caller 384 BLANK 385 BLANK 386 COMMENT 387 BLANK TEST GRAPHIC COLLISIONS 388 Procedure swputcol draws and tests a graphic for collision 389 Create a new stack frame (but using BX, not BP) 390 Store the previous frame 391 Store the SI register 392 Store the DI register 393 Store the ES register 394 BLANK 395 Load argument 1 in to SI, the x coordinate 396 Load argument 2 in to DI, the y coordinate 397 Load argument 3 in to BX, the pointer to the object 398 Pointer to the object's graphic in BP 399 BLANK 400 Call setup (line 748) to configure display, sets flags for next check 401 If we're testing an entire image, jump to line 415 402 Otherwise, we're testing a point, jump to line 668 403 Jump to line 450 to clear up collision test 404 BLANK 405 COMMENT 406 COMMENT 407 COMMENT 408 COMMENT 409 COMMENT 410 COMMENT 411 COMMENT 412 COMMENT 413 COMMENT 414 BLANK 415 Start collision test 416 Set the return code to zero for now 417 Step 1 - set up the call 418 Store AX 419 Store DI 420 Clear CH 421 Store BX 422 Load the XOR translation table (Starts on line 877 and provides the XOR lookup) 423 Call dispputc (line 468) to test the entire segment for collisions 424 BLANK 425 Check if we've moved beyond the 255 width trackable in AL 426 If no wrap occurrend, continue on lin 432 427 Otherwise we need to wrap, by moving AH to AL 428 Clear AH 429 Offset SI by the segment length 430 Jump to end of loop for anther pass (line 438), if needed 431 BLANK 432 Process line for collision: 433 Check if we have a meaningful value in CH 434 If not, then continue without testing on line 438 435 If there is a value, move it in to DH 436 Call collide (line 849) to perform a check 437 Move value to video 438 Wrap up this iteration 439 Restore BX from line 421 440 Return DI from line 419 441 Change destination lines 442 Covert to offset (Line 864) 443 Return AX from line 418 444 Finished a line, decrement from BP 445 Jump back to line 417 if BP is still positive 446 BLANK 447 Return code may have changed in collide, so store it in AL 448 Clear AH 449 BLANK 450 Return from collision test 451 Restore the ES register from on line 393 452 Restore the DI register from on line 392 453 Restore the SI register from on line 391 454 Restore the previous stack frame 455 Return to caller 456 BLANK 457 COMMENT 458 COMMENT 459 COMMENT 460 COMMENT 461 COMMENT 462 COMMENT 463 COMMENT 464 COMMENT 465 COMMENT 466 COMMENT 467 BLANK 468 Plot the raster line to video ram 469 Clear DL 470 Put the first byte in DH 471 We may be in the middle of the byte (pixels 2-4) 472 Add possible carries from last iteration 473 Call the collision check on like 849 474 XOR the properly shifited and carried byte in to video ram 475 Save the carry 476 Increment the place in the graphic segment 477 Increment the place in video ram 478 Count down the bytes remaining 479 If bytes remain, jump back to like 468 480 BLANK 481 We're done, return to caller 482 BLANK 483 BLANK 484 BLANK 485 COMMENT 486 BLANK TEST COLLISION POINT 487 Procedure swpntcol draws and tests a point for a collision 488 Store the previous frame 489 Create a new stack frame 490 Store the SI register 491 Store the DI register 492 Store the ES register 493 BLANK 494 Load argument 1 in to SI, the x coordinate 495 Load argument 2 in to SI, the y coordinate 496 Load argument 3 in to SI, the color/team 497 Call drawpntc to do the actual drawing 498 BLANK 499 Restore the ES register from line 492 500 Restore the DI register from line 491 501 Restore the SI register from line 490 502 Restore the previous stack frame 503 Return to caller 504 BLANK 505 BLANK 506 COMMENT 507 BLANK DRAW A SYMBOL 508 Procedure drawsym. SI, DI, BP, and AX hold the object properties 509 Store the object pointer in BX 510 BLANK 511 Extraneous push? Object pointer now on stack twice 512 Move object color (old color) in to BX 513 Mask the first 2 bits in BX (color) 514 Move the mask byte in to AL (defined in 898, byte 0 = 0, byte 1 = 0xFF) 515 Move that mask value in to variable colmask 516 Restore object pointer 517 BLANK 518 Call setup on line 748 to prepare symbol. Flags represent symbol size 519 If the symbol is larger than a point, jump to line 533 520 Otherwise, it's a point so call drawpnt on line 601 521 We've finished the work so clean up on line 563 522 BLANK 523 COMMENT 524 COMMENT 525 COMMENT 526 COMMENT 527 COMMENT 528 COMMENT 529 COMMENT 530 COMMENT 531 COMMENT 532 BLANK 533 Procedure to draw a large symbol 534 Store AX, which is the length 535 Store DI, which is where we write to video 536 Clear CH, which holds our packed pixel rotation amount within a byte 537 Store the line wrap distance 538 Load the translation table address in to BX (fast XOR lookup) 539 Calls display segment on line 580 to use the above prepped registers 540 BLANK 541 Check if we've wrapped the size of our byte 542 If we're still processing normally (no wrap) then jump to line 548 543 We've wrapped, so AH is now a negative number. Store the wrap in AL 544 Clear AH 545 Add the wrap amount to SI for the new symbol address 546 Jump to line 554 to continue to the next line 547 BLANK 548 No wrap, we're still processing the line 549 Check if we've had a carry (CX was repurposed during dispds) 550 No carry, jump to line 554 to start a new line 551 There's a carry amount, store it in DH 552 Symbol has a different color from base, so jump to line 864 to adjust 553 XOR the adjusted color in DH to video 554 Start a new symbol line 555 Restore the line offset stored on line 537 556 Restore the old video location stored on line 536 557 Offset DI to the new line using BX 558 We've changed to the other raster line so swap adjrast and BX 559 Restore the old segment length stored on line 534 560 We're down one more line, so decrement the line counter 561 If the line counter is positive, we have more work. Back to line 533 562 BLANK 563 All done! 564 Restore BX double stored on line 511 and 509 (bug??) 565 Return to caller, usually from swdisp 566 BLANK 567 BLANK 568 BLANK 569 COMMENT 570 COMMENT 571 COMMENT 572 COMMENT 573 COMMENT 574 COMMENT 575 COMMENT 576 COMMENT 577 COMMENT 578 COMMENT 579 BLANK 580 Time to display the segment we've constructed 581 Clear out the carry space 582 Move the bytes to display in to DH (4 pixels in a byte) 583 Shift DX to the proper pixel 584 Clear everything but the target pixel 585 BLANK 586 Call adjcolor to detect and swap colors between the two teams 587 BLANK 588 Pixel is correct, write it to video 589 We've adjusted the carry, save it in CH for next pixel 590 Move to next source byte 591 Move to the next video ram byte 592 Decrement the length remaining 593 If AL is still positive, repeat from line 580 594 BLANK 595 Segment done, return 596 BLANK 597 BLANK 598 BLANK 599 COMMENT 600 BLANK DRAW A PIXEL 601 Procedure to draw a point (no symbol or masks) 602 BLANK 603 COMMENT 604 BLANK 605 Adjust our target line to swap from game basis to screen basis 606 Twos complement the now negative screen basis 607 BLANK 608 COMMENT 609 COMMENT 610 BLANK 611 Get the pixel column in to CX 612 Mask the first 2 bytes (are we at base byte offset or sub-byte?) 613 Invert the value, which becomes the shift amount after... 614 Twos-complement the inversion (a bit value of 2 became -1 and now 1) 615 Shift left (2 bits per pixel). Our column requires 2 double bit shifts 616 BLANK 617 COMMENT 618 BLANK 619 Move the start address in to AX 620 Halve row value since we only care about half the screen (one scanline) 621 Move the screen width in to DX 622 Screen width * row == end of row 623 End of row + Column number in SI = pixel offset, but we need byte offset. Remember that each byte is 4 packed pixels, so we aren't interested in the lowest two bits, just the byte we can use to address the upcoming change. Rather, we'll rotate the target byte to the pixels we're interested in 624 Increment DX with CF flag based on previous operation for carry 625 Shift DX right -- the least significant bit drops off in to the CF 626 Rotate AX right, this picks up the CF from DX from the last shift in to MSB. The LSB moves to CF, but that doesn't matter. 627 Do the shifting again for DX -- clobbers the LSB in CF from AX rotation 628 Rotate AX one last time and we should have the byte we're interested in 629 Store the byte we'll modify in SI. 630 BLANK 631 COMMENT 632 BLANK 633 Checks the first bit of the row number to see if we're on an odd line 634 If we're on an even line, then skip the next instruction (to line 636) 635 Odd line, so we need to move the source forward to the other raster segment 636 Jump label skipping raster 637 Move the video ram base address in to AX (Temp) 638 Move video ram base address in to extra segment, ES 639 Move SI back to base 640 BLANK 641 COMMENT 642 COMMENT 643 BLANK 644 Store the color in to AX 645 Save only bits 7, 0, and 1 of current AX value 646 Test AL bit 7 for XOR flag 647 If we're doing an XOR color write, jump to line 659 648 BLANK 649 Otherwise this is an overlay so we compare src/dest, Set CH to 0x03 650 Shift the 0x03 in to position to mask the pixel of interest 651 Copy the current video value in to DH 652 Mask out the bits of interest 653 Do XOR of the current color (cyan becomes magenta and vice versa) 654 Rotate modified pixels back to original position 655 Set the remainder of the old byte around the new pixels 656 Move that byte back to its home in video memory 657 Return to caller 658 BLANK 659 Time for a full XOR, set every bit except 7 660 Shift AL left to the pixel of interest 661 XOR the byte 662 Return to caller 663 BLANK 664 BLANK 665 BLANK 666 COMMENT 667 BLANK DRAW PIXEL FOR COLLISION TEST 668 Draw point with collision detection 669 BLANK 670 COMMENT 671 BLANK 672 Covert our pixel number from game basis in to screen basis (top/bottom) 673 Twos complement for the actual number (currently negative) 674 BLANK 675 COMMENT 676 COMMENT 677 BLANK 678 Store the column in to CX 679 Saves only the first 2 bits in CL (The packed pixel position) 680 We need to find the rotation value, subtract 3... 681 And invert to find the sub-byte pixel rotation value 682 Shift bits in to mask position 683 BLANK 684 COMMENT 685 BLANK 686 Save the target row in DX 687 Halve row value since we only care about half the screen (one scanline) 688 Size of row in DX 689 Multiply the row size by the row number to find row offset 690 Add the pixel offset to the row offset 691 Then add the carry flag from add in to DX 692 Shift DX right -- the least significant bit drops off in to the CF 693 Rotate AX right, this picks up the CF from DX from the last shift in to MSB. The LSB moves to CF, but that doesn't matter. 694 Do the shifting again for DX -- clobbers the LSB in CF from AX rotation 695 Rotate AX one last time and we should have the byte we're interested in 696 Store the target byte in to SI 697 BLANK 698 COMMENT 699 BLANK 700 Check the first bit to determine row value (hence memory segment) 701 If the even row, jump to line 703 and skip odd raster offset 702 It's odd, so add the raster offset to the source 703 Skip label 704 Move the base video display segment in to AX (temp) 705 Move the video memroy segment in to ES 706 Add the offset to the source 707 BLANK 708 COMMENT 709 BLANK 710 Set the initial mask in to CH (00000011) 711 Shift the bit mask in to proper position depending on pixel within byte 712 Mask the byte in memory with the mask to save the pixel in CH 713 BLANK 714 COMMENT 715 COMMENT 716 BLANK 717 Move the color bit in to AX 718 Mask bits 0, 1, and 7 719 Check bit 7 for operation, color or XOR 720 It's XOR so jump to 727 721 BLANK 722 Otherwise, we're doing a pixel color copy 723 Rotate the pixels in AL by the shift amount 724 Set the target pixels 725 Jump to return on 735 726 BLANK 727 XOR write - set AL to all 1s, except bit 7 728 Rotate AL based on target pixel position 729 XOR the colors 730 BLANK 731 COMMENT 732 COMMENT 733 COMMENT 734 BLANK 735 Cleanup label 736 Move the XOR'd colors back to base byte position 737 Move the result in to AL 738 Clear AH 739 Return (color result in AL) 740 BLANK 741 BLANK 742 COMMENT 743 BLANK 744 COMMENT 745 COMMENT 746 COMMENT 747 BLANK SET UP VARIABLES AND REGISTERS FOR DRAWING 748 Prepare for draw by setting the call environment 749 Check if the symbol is only 1 pixel tall 750 If it's more than 1 pixel, jump down to line 757 751 Check if the symbol width is more than 1 pixel 752 If it is more than 1, jump down to 757 753 If symbol is just a single pixel, then there's no prep work 754 BLANK 755 COMMENT 756 BLANK 757 Label for setup for pre-draw 758 Change position from game basis to screen basis (0 is top, not bottom) 759 Twos-complement the subtractions 760 BLANK 761 COMMENT 762 COMMENT 763 BLANK 764 Move the memory offset (pixel position) in to CX 765 Mask the sub-byte pixel position (first two bytes) 766 Shift CL left once to count the rotation required, used after return 767 BLANK 768 COMMENT 769 COMMENT 770 BLANK 771 Move the symbol width from object memory in to AX (pixels) 772 Convert from pixels to bytes...left shift once 773 ...and again since 1 byte = 4 pixels in CGA 774 BLANK 775 Move the pixel column in to DX 776 Convert from column to bytes with one shift... 777 and another shift...just like before 778 Subtract the entire screen width, now we're at negative byte difference 779 Twos-completement for the positive value of screen bytes remaining 780 BLANK 781 Preserve symbol width in AL 782 Subtract the screen bytes remaining (DL) from bytes required (AH) 783 If there is no concern about symbol space, jump to line 785 784 Otherwise, we need to track the remaining screen space as we draw 785 Time to consider vertical boundaries... 786 BLANK 787 COMMENT 788 COMMENT 789 BLANK 790 Store symbol dimensions on the stack 791 Pull the symbol height in to AX 792 Pull the screen ehight in DX 793 Subtract screen height from symbol position to get available space 794 Compare symbol height with availble space 795 If there is no space crunch, jump to line 797 796 Store the availble lines in DX 797 Label for next step -- vram location 798 Push height available on to the stack 799 BLANK 800 COMMENT 801 BLANK 802 Store the row start in AX 803 Halve row value since we only care about half the screen (one scanline) 804 Move the screen width in to DX (320) 805 Multiply DX by the row value to find the memory offset 806 Offset the pixel value in to the row 807 Add back the carry flag 808 We need the byte index, right shift DX, LSB to CF 809 Rotate AX to being CF from DX in to MSB 810 Shift DX right once more, again using CF to hold LSB 811 Final rotate of AX, brings in the CF from DX. AX is the byte index 812 BLANK 813 COMMENT 814 COMMENT 815 BLANK 816 Total line width in to DX 817 Odd line memory offset in to BX 818 Save DX in to adjrast 819 Subtract the offset from the screen width (now a negative value to change scanlines) 820 BLANK 821 COMMENT 822 COMMENT 823 BLANK 824 Checks if the symbol is on an off row 825 Not an odd row? no need to offset, so jump to line 828 826 Otherwise, add the offset to the first start byte 827 Swap the offset values for the eventual return 828 Label for final step 829 BLANK 830 COMMENT 831 BLANK 832 Saves the video ram segment in to SI... 833 Then moves it to the extra segment 834 Saves the symbol pointer in in to the source address 835 Saves the video ram in to destination address 836 Adds the offset in to video ram 837 Restore the previous stack frame 838 Restores the line count stored on line 798 in to 837 839 BLANK 840 Restores the segment size as stored on line 790 in to AX 841 Return to caller 842 BLANK 843 BLANK 844 COMMENT 845 COMMENT 846 COMMENT 847 COMMENT 848 BLANK COLLISION TEST 849 Detect collisions label 850 Store AX 851 Move the desired byte value in to AL 852 Looks up the index in AL in to the translation table. Result back in AL 853 Compare the look up result with the actual memory value 854 Sets the comparison to the return value (0 = no collision) 855 Restore AX from line 850 856 Return to caller 857 BLANK 858 BLANK 859 COMMENT 860 COMMENT 861 COMMENT 862 COMMENT 863 BLANK ADJUST COLOR FOR OTHER PLAYER/TEAM 864 Adjusts the color depending on object's team color (base is player) 865 Store AX 866 Store the inital byte in AL 867 Look up the byte in the translation table (result in AL) 868 Mask result with color mask (set from cmsktab on line 898) 869 Either nothing to mask here or it's wrong and all is masked (blue->red) 870 Restore AX from line 865 871 Return to caller 872 BLANK 873 COMMENT 874 COMMENT 875 COMMENT 876 COMMENT TRANSLATION TABLE FOR BYTE VALUE TO PIXEL COLOR (COLLISION CHECK) 877 Defines translation table for collisions - bytes 0-15 878 Defines translation table for collisions - bytes 16-31 879 Defines translation table for collisions - bytes 32-47 880 Defines translation table for collisions - bytes 48-63 881 Defines translation table for collisions - bytes 64-79 882 Defines translation table for collisions - bytes 80-95 883 Defines translation table for collisions - bytes 96-111 884 Defines translation table for collisions - bytes 112-127 885 Defines translation table for collisions - bytes 128-143 886 Defines translation table for collisions - bytes 144-159 887 Defines translation table for collisions - bytes 160-175 888 Defines translation table for collisions - bytes 176-191 889 Defines translation table for collisions - bytes 192-207 890 Defines translation table for collisions - bytes 208-223 891 Defines translation table for collisions - bytes 224-239 892 Defines translation table for collisions - bytes 240-255 893 BLANK 894 COMMENT 895 COMMENT 896 COMMENT 897 BLANK COLOR XOR MASK 898 The color mask table for each player color, only color 2 is different 899 BLANK 900 BLANK 901 BLANK 902 COMMENT 903 COMMENT 904 COMMENT 905 COMMENT 906 COMMENT 907 COMMENT 908 COMMENT 909 BLANK 910 BLANK 911 Defines get_type procedure to retrieve screen modes 912 Sets AH to 15, which prepares interrupt 10 to retrieve the screen mode 913 Invoke interrupt 10, which saves the screen mode in to AL 914 Clears AH so that only the screen mode remains in AX 915 Return from procedure 916 BLANK 917 BLANK 918 Defines set_type procedure to set screen modes 919 Store the previous frame 920 Create the new frame 921 Get argument 1 in to AL - the desired screen mode 922 Clear AH, which prepares the processor for interrupt 10 to set screen 923 Invokes interrupt 10, setting the screen mode to the value in AL 924 Restore the previous stack frame 925 Return from procedure 926 BLANK 927 BLANK 928 BLANK 929 COMMENT 930 COMMENT 931 COMMENT 932 COMMENT 933 COMMENT 934 COMMENT 935 COMMENT 936 BLANK 937 BLANK 938 Define setvdisp to set the active display to video RAM 939 Store the screen segment (0xB800) in dispseg 940 Start at the beginning of the segment 941 Set the odd raster lines to the odd raster offset 942 Return to caller 943 BLANK 944 BLANK 945 Define setadisp to set the active display to the aux buffer 946 Set the current data segment in to dispset (this needs prior setup) 947 Set the offset 0x1000 bytes before the auxdisp buffer (offset to base) 948 Set the odd raster offset halfway in to the aux buffer 949 Return to caller 950 BLANK 951 BLANK 952 BLANK 953 BLANK 954 Begin the data area for this assembly unit 955 BLANK 956 Allocate an uninitialized word (2 bytes) for the restor line offset 957 Allocate an unitialized byte for the collision mask 958 Allocate an unitialized byte for the return come 959 Allocate a byte SCR_WDTH times (so 320 or 640 if high res) ground data 960 Allocate a word for the display segment 961 Allocate a word for the offset in the segment 962 Allocate a word for the odd line offset 963 BLANK 964 Import the left side of the screen position 965 Import the right side of the screen position 966 Import the shifting amount 967 Import the aux buffer 968 Import the ground height map 969 Import the display init flag 970 Import the forced redraw flag 971 Import the top of the object list 972 Import the top of the deleted list 973 Import the splattered ox draw flag 974 Import the splattered ox state flag 975 BLANK 976 End of assmbly 977 EOF