Advertisement
Ham62

TronV1.ASM

Apr 20th, 2024
972
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
ASM (NASM) 9.77 KB | Source Code | 0 0
  1. ; -----------------------------------------------------
  2. ; MS-DOS Tron
  3. ;
  4. ; A WIP recreation of the game Tron for MS-DOS.
  5. ;
  6. ; Runs in CGA screen mode 4 using only 808x compatible
  7. ; instructions.
  8. ;
  9. ; Written by Graham Downey (2024)
  10.  
  11. CPU 8086
  12. ORG 100h
  13.  
  14. %define _UP    0
  15. %define _DOWN  1
  16. %define _LEFT  2
  17. %define _RIGHT 3
  18.  
  19. %define _P1CLR 1
  20. %define _P2CLR 2
  21.  
  22. %define _P1MASK 55h
  23. %define _P2MASK 0AAh
  24.  
  25.  
  26. section .text
  27.  
  28. ; Startup code
  29. start:
  30.     MOV AX, 0F00h  ; Get and save current video mode
  31.     INT 10h
  32.     MOV [CS:oldVideoState], AL
  33.  
  34.     MOV AX, 0004h  ; Set video mode to CGA 320x200x4
  35.     INT 10h
  36.  
  37.     MOV AX, 0B800h ; CGA graphics seg
  38.     MOV ES, AX
  39.  
  40.     MOV DX, CS     ; Set data segment to code segment
  41.     MOV DS, DX
  42.  
  43.     ; Test drawing 8 pixels top left corner
  44.     MOV [ES:0000h], BYTE 0E4h
  45.     MOV [ES:0001h], BYTE 1Bh
  46.  
  47.  
  48. drawBorder:
  49.  
  50.     ; Draw top and bottom borders
  51.  horizontalBorder:
  52.     MOV CX, 80     ; 80*4 pixels across
  53.     MOV AL, 0E7h   ; Cool border pattern
  54.  
  55.     XOR DI, DI     ; Top border starts at 0000h
  56.     MOV SI, 3EF0h-80  ; Bottom border starts here
  57.  
  58.    ; Render a cool arrow pattern
  59.  .nextColumn:
  60.     MOV [ES:DI], AL ; First row
  61.     MOV [ES:SI], AL
  62.  
  63.     ROL AL, 1
  64.     ROL AL, 1
  65.  
  66.     ADD DI, 80
  67.     ADD SI, 80
  68.     MOV [ES:DI], AL ; Third row
  69.     MOV [ES:SI], AL
  70.  
  71.     XOR DI, 2000h
  72.     XOR SI, 2000h
  73.  
  74.     ROL AL, 1
  75.     ROL AL, 1
  76.  
  77.     MOV [ES:DI], AL ; 4th row
  78.     MOV [ES:SI], AL
  79.  
  80.     SUB DI, 80
  81.     SUB SI, 80
  82.  
  83.     ROL AL, 1
  84.     ROL AL, 1
  85.  
  86.     MOV [ES:DI], AL ; Second row
  87.     MOV [ES:SI], AL
  88.  
  89.     XOR DI, 2000h
  90.     XOR SI, 2000h
  91.  
  92.     ROL AL, 1      ; Rotate 4px pattern
  93.     ROL AL, 1
  94.  
  95.     INC DI
  96.     INC SI
  97.  
  98.     LOOP .nextColumn
  99.  
  100.     ; Draw left and right borders
  101.  verticalBorder:
  102.     MOV CX, 99    ; 100*2 scanlines
  103.  
  104.     MOV AL, 0DBh
  105.  
  106.     MOV DI, 2000h
  107.  
  108.  .nextRow:
  109.     MOV [ES:DI], AL ; left odd scanline
  110.  
  111.     ADD DI, 79
  112.     MOV [ES:DI], AL ; right odd scanline
  113.  
  114.     ADD DI, 80
  115.     XOR DI, 2000h
  116.     MOV [ES:DI], AL ; right even scanline
  117.  
  118.     SUB DI, 79
  119.     MOV [ES:DI], AL ; left even scanline
  120.  
  121.     OR DI, 2000h
  122.  
  123.     ; Creates a cool barber shop pole pattern
  124.     ROL AL, 1
  125.     ROL AL, 1
  126.  
  127.     LOOP .nextRow
  128.  
  129. ; -------------------------------
  130. ;    Main program loop start
  131. ;
  132. mainLoop:
  133.  
  134.     CALL movePlayers      ; Do player movement logic
  135.  
  136.     CALL drawPlayers      ; Render new player locations
  137.  
  138.     CALL checkKeyPress    ; Get user input
  139.  
  140.     MOV CX, 2             ; Wait 2 VBlanks between frames (~15 fps)
  141.     CALL waitVBlank       ; So we don't get runaway speed on fast CPUs
  142.  
  143.     JMP mainLoop
  144.  
  145. ; End Main Loop
  146.  
  147.  
  148. ; CGA Mode 4 reference
  149. ; https://www.chibialiens.com/8086/platform.php#LessonP1
  150.  
  151. ; -----------------------------------
  152. ;     Draw players on the screen
  153. ;  Also checks for player collisions
  154.  
  155. drawPlayers:
  156.  
  157.     ; Draw Player 1
  158.     MOV DI, [p1Location]
  159.     MOV CL, [p1Offset]
  160.     SHL CL, 1        ; CL *= 2 because 2 bits per pixel
  161.  
  162.     MOV DL, 03h      ; 1 pixel CGA bitmask (0000 0011b)
  163.     SHL DL, CL       ; Shift to correct pixel offset
  164.  
  165.     TEST [ES:DI], DL ; Check if something already passed here
  166.     JNZ .P1Collision
  167.  
  168.     AND DL, _P1MASK  ; Use mask to set DL to P1 color
  169.     OR [ES:DI], DL   ; Draw to screen
  170.  
  171.  
  172.     ; Draw Player 2
  173.     MOV DI, [p2Location]
  174.     MOV CL, [p2Offset]
  175.     SHL CL, 1        ; CL *= 2 because 2 bits per pixel
  176.  
  177.     MOV DL, 03h      ; 1 pixel bitmask
  178.     SHL DL, CL
  179.  
  180.  
  181.     TEST [ES:DI], DL ; Check if something already passed here
  182.     JNZ .P2Collision
  183.  
  184.     AND DL, _P2MASK  ; Use mask to set DL to P1 color
  185.     OR [ES:DI], DL  ; Draw to screen
  186.  
  187.     RET
  188.  
  189.  .P1Collision:
  190.     JMP end
  191.  
  192.  .P2Collision:
  193.     JMP end
  194.  
  195.  
  196.  
  197. ; -------------------
  198. ;  Move the players
  199.  
  200. movePlayers:
  201.  
  202.  ; Move player 1
  203.  moveP1:
  204.     MOV BL, [p1Direction]
  205.  
  206.  .left:
  207.     CMP BL, _LEFT
  208.     JNE .right
  209.  
  210.     INC BYTE [p1Offset]
  211.     AND BYTE [p1Offset], 03h ; Only using 2 bits for offset (4px per byte)
  212.     JNZ .done
  213.  
  214.     DEC WORD [p1Location]
  215.     JMP .done
  216.  
  217.  .right:
  218.     CMP BL, _RIGHT
  219.     JNE .down
  220.  
  221.     DEC BYTE [p1Offset]
  222.     TEST BYTE [p1Offset], 0FCh
  223.     JZ .done
  224.  
  225.     MOV [p1Offset], BYTE 03h  ; 4 pixels per byte (offset 0-3)
  226.     INC WORD [p1Location]
  227.     JMP .done
  228.  
  229.  .down:
  230.     CMP BL, _DOWN
  231.     JNE .up
  232.  
  233.     MOV BX, [p1Location]
  234.  
  235.     TEST BX, 2000h ; Check if we're odd or even scanline
  236.     JZ .skipAdd
  237.     ADD BX, 80
  238.  
  239.   .skipAdd:
  240.     XOR BX, 2000h  ; Toggle odd/even scanline bit
  241.     MOV [p1Location], BX
  242.     JMP .done
  243.  
  244.  .up:
  245.     ;CMP BL, _UP  ; Up direction assumed as last-case
  246.     ;JNE .done
  247.  
  248.     MOV BX, [p1Location]
  249.  
  250.     TEST BX, 2000h
  251.     JNZ .skipSub
  252.     SUB BX, 80
  253.  
  254.   .skipSub:
  255.     XOR BX, 2000h
  256.     MOV [p1Location], BX
  257.  
  258.  .done:
  259.  
  260.  ; Move player 2
  261.  moveP2:
  262.     MOV BL, [p2Direction]
  263.  
  264.  .left:
  265.     CMP BL, _LEFT
  266.     JNE .right
  267.  
  268.     INC BYTE [p2Offset]
  269.     AND BYTE [p2Offset], 03h ; Only using 2 bits for offset (4px per byte)
  270.     JNZ .done
  271.  
  272.     DEC WORD [p2Location]
  273.     JMP .done
  274.  
  275.  .right:
  276.     CMP BL, _RIGHT
  277.     JNE .down
  278.  
  279.     DEC BYTE [p2Offset]
  280.     TEST BYTE [p2Offset], 0FCh
  281.     JZ .done
  282.  
  283.     MOV [p2Offset], BYTE 03h  ; 4 pixels per byte (offset 0-3)
  284.     INC WORD [p2Location]
  285.     JMP .done
  286.  
  287.  .down:
  288.     CMP BL, _DOWN
  289.     JNE .up
  290.  
  291.     MOV BX, [p2Location]
  292.  
  293.     TEST BX, 2000h ; Check if we're odd or even scanline
  294.     JZ .skipAdd
  295.     ADD BX, 80
  296.  
  297.   .skipAdd:
  298.     XOR BX, 2000h  ; Toggle odd/even scanline bit
  299.     MOV [p2Location], BX
  300.     JMP .done
  301.  
  302.  .up:
  303.     ;CMP BL, _UP  ; Up direction assumed as last-case
  304.     ;JNE .done
  305.  
  306.     MOV BX, [p2Location]
  307.  
  308.     TEST BX, 2000h
  309.     JNZ .skipSub
  310.     SUB BX, 80
  311.  
  312.   .skipSub:
  313.     XOR BX, 2000h
  314.     MOV [p2Location], BX
  315.  
  316.  .done:
  317.     RET
  318.  
  319.  
  320. ; ---------------------------------------
  321. ; Read and parse keyboard input
  322.  
  323. checkKeyPress:
  324.     MOV AX, 0100h ; Keyboard check for keystroke
  325.     INT 16h
  326.  
  327.     JNZ checkKeyCode ; ZF not set if key is available
  328.     RET
  329.  
  330. checkKeyCode:
  331.     XOR AX, AX    ; Get keystroke and remove from buffer
  332.     INT 16h       ; AH = Scancode, AL = ASCII char
  333.  
  334.  ; --------------------------------------
  335.  ;            Global Keys
  336.  .checkEsc:
  337.     CMP AH, 1  ; Esc key
  338.     JE end
  339.  
  340.  .checkPause:
  341.     CMP AH, 25 ; P key
  342.     JNE .isPaused
  343.  
  344.     NOT BYTE [paused] ; flip pause flag
  345.  
  346.   .isPaused:
  347.     TEST [paused], BYTE 1
  348.     JNE checkKeyCode   ; Keep looping until pause key hit again
  349.  
  350.  ; --------------------------------------
  351.  ;            P1 controls
  352.  .checkUp:
  353.     CMP AH, 72 ; up arrow
  354.     JNE .checkDown
  355.  
  356.     CMP [p1Direction], BYTE _DOWN   ; Do not allow to backtrack
  357.     JE .doneKeys
  358.  
  359.     MOV [p1Direction], BYTE _UP    
  360.  
  361.  .checkDown:
  362.     CMP AH, 80 ; down arrow
  363.     JNE .checkLeft
  364.  
  365.     CMP [p1Direction], BYTE _UP     ; Do not allow to backtrack
  366.     JE .doneKeys
  367.  
  368.     MOV [p1Direction], BYTE _DOWN    
  369.  
  370.  .checkLeft:
  371.     CMP AH, 75 ; left arrow
  372.     JNE .checkRight
  373.  
  374.     CMP [p1Direction], BYTE _RIGHT  ; Do not allow to backtrack
  375.     JE .doneKeys
  376.  
  377.     MOV [p1Direction], BYTE _LEFT
  378.  
  379.  .checkRight:
  380.     CMP AH, 77 ; right arrow
  381.     JNE .checkW
  382.  
  383.     CMP [p1Direction], BYTE _LEFT   ; Do not allow to backtrack
  384.     JE .doneKeys
  385.  
  386.     MOV [p1Direction], BYTE _RIGHT
  387.  
  388.  ; --------------------------------------
  389.  ;            P2 controls
  390.  .checkW:
  391.     CMP AH, 17 ; W key
  392.     JNE .checkA
  393.  
  394.     CMP [p2Direction], BYTE _DOWN   ; Do not allow to backtrack
  395.     JE .doneKeys
  396.  
  397.     MOV [p2Direction], BYTE _UP    
  398.  
  399.  .checkA:
  400.     CMP AH, 30 ; A key
  401.     JNE .checkS
  402.  
  403.     CMP [p2Direction], BYTE _RIGHT  ; Do not allow to backtrack
  404.     JE .doneKeys
  405.  
  406.     MOV [p2Direction], BYTE _LEFT    
  407.  
  408.  .checkS:
  409.     CMP AH, 31 ; S key
  410.     JNE .checkD
  411.  
  412.     CMP [p2Direction], BYTE _UP     ; Do not allow to backtrack
  413.     JE .doneKeys
  414.  
  415.     MOV [p2Direction], BYTE _DOWN
  416.  
  417.  .checkD:
  418.     CMP AH, 32 ; D key
  419.     JNE .doneKeys
  420.  
  421.     CMP [p2Direction], BYTE _LEFT   ; Do not allow to backtrack
  422.     JE .doneKeys
  423.  
  424.     MOV [p2Direction], BYTE _RIGHT
  425.  
  426.  .doneKeys:
  427.  
  428.     JMP checkKeyPress ; Keep looping until kb buffer clear
  429.  
  430.  
  431. ; -----------------------------------------------
  432. ; Clears the keyboard buffer so we don't dump
  433. ; random key presses into the console when we
  434. ; quit the program
  435. clearKBBuff:
  436.     MOV AX, 0040h ; Buffer is at seg 0040h
  437.     MOV DS, AX
  438.  
  439.                   ; To clear the buffer, set
  440.                   ; [0040:001A] = [0040:001C]
  441.     MOV AL, BYTE [001Ch]
  442.     MOV [001Ah], AL
  443.  
  444.     MOV AX, CS    ; Restore DS to CS
  445.     MOV DS, AX
  446.     RET
  447.  
  448.  
  449. ; ----------------------------------------------
  450. ; Pauses the program while it waits for 'n' vBlanks
  451. ; to pass.
  452. ;
  453. ; CX = 'n' vsyncs to wait for
  454. ; trashes: DX, AX, CX
  455. waitVBlank:  
  456.     MOV DX, 03DAh  ; port vsync pulse is sent to
  457.  
  458.   .waitVSync:
  459.     IN AL, DX      ; read vsync status
  460.     TEST AL, 8     ; when we read !8 from the port
  461.     JNE .waitVSync ; vsync in progress
  462.  
  463.   .waitVBlank:
  464.     IN AL, DX
  465.     TEST AL, 8     ; when we read 8 from the port
  466.     JE .waitVBlank ; vsync is done
  467.  
  468.     DEC CX         ; next vsync?
  469.     JNZ waitVBlank
  470.     RET    
  471.  
  472.  
  473. ; -----------------------------------------------
  474. ; Restore video state and terminate program
  475. end:
  476.     CALL clearKBBuff
  477.  
  478.     XOR AH, AH     ; Restore to initial video mode
  479.     MOV AL, [CS:oldVideoState]
  480.     INT 10h
  481.  
  482.     XOR AX, AX     ; Quit to DOS
  483.     INT 21h
  484.  
  485.  
  486.  
  487. section .data
  488.  
  489. ; Store DOS' video state at program's start
  490. oldVideoState: db 03h
  491.  
  492. paused: DB 00h ; Variable to hold paused/unpaused state
  493.  
  494. ; Player 1 direction & location
  495. p1Direction: db _LEFT
  496. p1Location:  dw 0FA0h-1 ; ptr to screen mem location
  497. p1Offset:    db 03h   ; offset of which pixel in byte
  498.  
  499. ; Player 2 direction & location
  500. p2Direction: db _RIGHT
  501. p2Location:  dw 0F50h+1 ; ptr to screen mem location
  502. p2Offset:    db 04h   ; offset of which pixel in byte
  503.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement