Space Opera CSO

57
;----------------------------------------------------------------------------- ---------------------- ;SPACE OPERA ;A game by Samuel Horwitz ;With thanks to Robert Dewar for some code. ; ;Copyright (c) 2008, 2011 Samuel Horwitz ; ;Permission is hereby granted, free of charge, to any person obtaining a copy ;of this software and associated documentation files (the "Software"), to deal ;in the Software without restriction, including without limitation the rights ;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ;copies of the Software, and to permit persons to whom the Software is ;furnished to do so, subject to the following conditions: ; ;The above copyright notice and this permission notice shall be included in ;all copies or substantial portions of the Software. ; ;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ;THE SOFTWARE. ; ;Find more at <http://www.logicalore.net/> ;----------------------------------------------------------------------------- ---------------------- jmp start ;Jump to code ;----------------------------------------------------------------------------- ---------------------- ;CONSTANTS ;Constant values to be used at assemble time. ;----------------------------------------------------------------------------- ---------------------- ;Video information VIDEO_MODE equ 0Dh ;EGA 16 Color mode TEXT_MODE equ 3 ;CGA Color text mode VIDEO_SEGMENT equ 0A000h ;The location of VGA video memory BIOS_SEGMENT equ 40h ;The location of the ROM-BIOS variables

description

CMD file game

Transcript of Space Opera CSO

Page 1: Space Opera CSO

;---------------------------------------------------------------------------------------------------;SPACE OPERA;A game by Samuel Horwitz;With thanks to Robert Dewar for some code.;;Copyright (c) 2008, 2011 Samuel Horwitz;;Permission is hereby granted, free of charge, to any person obtaining a copy;of this software and associated documentation files (the "Software"), to deal;in the Software without restriction, including without limitation the rights;to use, copy, modify, merge, publish, distribute, sublicense, and/or sell;copies of the Software, and to permit persons to whom the Software is;furnished to do so, subject to the following conditions:;;The above copyright notice and this permission notice shall be included in;all copies or substantial portions of the Software.;;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR;IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,;FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE;AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER;LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,;OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN;THE SOFTWARE.;;Find more at <http://www.logicalore.net/>;---------------------------------------------------------------------------------------------------

jmp start;Jump to code

;---------------------------------------------------------------------------------------------------;CONSTANTS;Constant values to be used at assemble time.;---------------------------------------------------------------------------------------------------;Video informationVIDEO_MODE equ 0Dh

;EGA 16 Color modeTEXT_MODE equ 3

;CGA Color text modeVIDEO_SEGMENT equ 0A000h

;The location of VGA video memoryBIOS_SEGMENT equ 40h

;The location of the ROM-BIOS variablesPAGE_OFFSET_ADR equ 4Eh

;The offset in BIOS_SEGMENT for page dataVIDEO_MAX_PIX equ 8000

;The max number of bytes on an EGA planeVIDEO_HEIGHT equ 25

;The number of bytes high the video isVIDEO_HEIGHT_PIX equ VIDEO_HEIGHT*8

;The number of pixels high the video isVIDEO_WIDTH equ 40

;The number of bytes wide the video is

Page 2: Space Opera CSO

VIDEO_WIDTH_PIX equ VIDEO_WIDTH*8;The number of pixels wide the video is

;Bitplane masksNO_COLORS equ 00000000b

;Mask off all planesBLACK_MASK equ 00000000b

;Mask off all planesBLUE_MASK equ 00000001b

;Mask off all planes except blueGREEN_MASK equ 00000010b

;Mask off all planes except greenCYAN_MASK equ 00000011b

;Mask off all planes except blue and greenRED_MASK equ 00000100b

;Mask off all planes except redPURPLE_MASK equ 00000101b

;Mask off all planes except red and blueBROWN_MASK equ 00000110b

;Mask off all planes except red and greenLIGHT_GRAY_MASK equ 00000111b

;Mask off intensity plane onlyDARK_GRAY_MASK equ 00001000b

;Mask off all planes except intensityLIGHT_BLUE_MASK equ 00001001b

;Mask off all planes except i and blueLIGHT_GREEN_MASK equ 00001010b

;Mask off all planes except i and greenLIGHT_CYAN_MASK equ 00001011b

;Mask off all planes except i green and blueLIGHT_RED_MASK equ 00001100b

;Mask off all planes except i and redMAGENTA_MASK equ 00001101b

;Mask off all planes except i red and blueYELLOW_MASK equ 00001110b

;Mask off all planes except i red and greenWHITE_MASK equ 00001111b

;Mask off no planesALL_COLORS equ 00001111b

;Mask off no planesXOR_MODE equ 18h

;XOR graphics mode

;PortsSC_PORT equ 3C4h

;SC Index portGC_PORT equ 3CEh

;GC Index portTIMER_GATE_PORT equ 61h

;Timer gate control portTIMER_CTRL_PORT equ 43h

;Timer control portTIMER_CNTR_PORT equ 42h

;Timer counter port

;Port registers

Page 3: Space Opera CSO

SC_MAP_MASK_REG equ 2;Register for map masking

GC_DATA_ROT_REG equ 3;Register for data rotation

GC_MODE_REG equ 5;Register for graphics modes

;Object sizes and dataPLAYER_HT equ 3

;Number of bytes tall player isPLAYER_HT_PIX equ PLAYER_HT*8

;Number of pixels tall player isPLAYER_WD equ 3

;Number of bytes wide player isPLAYER_WD_PIX equ PLAYER_WD*8

;Number of pixels wide player isENEMY1_HT equ 3

;Number of bytes tall enemy 1 isENEMY1_HT_PIX equ ENEMY1_HT*8

;Number of pixels tall enemey 1 isENEMY1_WD equ 3

;Number of bytes wide enemy 1 isENEMY1_WD_PIX equ ENEMY1_WD*8

;Number of pixels wide enemy 1 isENEMY1_PT_VAL equ 10

;Point value of enemy 1EXP_WD equ 3

;Number of bytes wide explosions areEXP_WD_PIX equ EXP_WD*8

;Number of pixels wide explosions areEXP_HT equ 3

;Number of bytes tall explosions areEXP_HT_PIX equ EXP_HT*8

;Number of pixels tall explosions areLETTER_HT equ 1

;The height of each letter/numberLETTER_HT_PIX equ LETTER_HT*8

;The height of each letter/number in pixelsLETTER_WD equ 1

;The width of each letter/numberLETTER_WD_PIX equ LETTER_WD*8

;The width of each letter/number in pixelsLASER_WD equ 1

;Number of bytes wide laser isLASER_WD_PIX equ LASER_WD*8

;Number of pixels wide laser isLASER_DUR equ 1

;Duration of laser soundLASER_FREQ equ 500

;Frequency of laser soundEXP_DUR equ 2

;Duration of explosion soundEXP_FREQ equ 200

;Frequency of explosion soundCHAR_ALIVE equ 1

;Character is alive

Page 4: Space Opera CSO

CHAR_EXP equ 0;Character exploded

ENEMY_LIMIT equ 12;The maximum number of possible enemies

NO_ENEMY equ 10000;Used to specify blank array object enemy

NO_PLAYER equ 10000;Used to specify blank array object player

NO_BULLET equ 10000;Same as NO_ENEMY but named for bullets

PLAYER_COL equ 1;Signifies player on collision table

ENEMY1_COL equ 2;Signifies enemy 1 on collision table

PLASER_COL equ 3;Signifies good laser on collision table

ELASER_COL equ 4;Signifies bad laser on collision table

MENU_NEW equ 0;New game in menu

MENU_HELP equ 1;Help in menu

MENU_QUIT equ 2;Quit in menu

MENU2_EASY equ 0;Easy in difficulty menu

MENU2_MEDIUM equ 1;Medium in difficulty menu

MENU2_HARD equ 2;Hard in difficulty menu

MENU2_NIGHTMARE equ 3;Nightmare in difficulty menu

KBD_UP equ 48h;Scancode for up arrow

KBD_DOWN equ 50h;Scancode for down arrow

KBD_ESC equ 1;Scancode for escape

KBD_ENTER equ 1Ch;Scancode for enter

TRUE equ 1;True

FALSE equ 0;False

;Peripheral dataMOUSE_LBOUND equ 0

;The left bound of the mouse's movementMOUSE_RBOUND equ VIDEO_WIDTH_PIX-PLAYER_WD_PIX;The right bound of the mouse's movementMOUSE_UBOUND equ 48

;The upper bound of the mouse's movementMOUSE_BBOUND equ VIDEO_HEIGHT_PIX-PLAYER_HT_PIX;The bottom bound of the mouse's movementSCREEN_DELAY equ 3

;The amount of time for the delay function

Page 5: Space Opera CSO

MOUSE_HORDEF equ 160;Default horizontal position for mouse

MOUSE_VERDEF equ MOUSE_BBOUND;Default vertical position for mouse

;---------------------------------------------------------------------------------------------------;DATA;Named locations of memory within the program itself.;---------------------------------------------------------------------------------------------------PlayerX dw MOUSE_HORDEF

;The X location of the player in pixelsPlayerY dw MOUSE_VERDEF

;The Y location of the player in pixelsPlayerShotX dw NO_BULLET

;Player's laser location x,yPlayerShotY dw NO_BULLETPlayerStat db CHAR_ALIVE

;Player's health statusPlayerDead db 0

;Is player dead?EnemiesX dw ENEMY_LIMIT dup(NO_ENEMY)

;Array of enemy X locationsEnemiesY dw ENEMY_LIMIT dup(NO_ENEMY)

;Array of enemy Y locationsEnemiesStat dw ENEMY_LIMIT dup(NO_ENEMY)

;The health status of all the enemiesEnemyShotX dw ENEMY_LIMIT dup(NO_BULLET)

;Enemies' laser locations x,yEnemyShotY dw ENEMY_LIMIT dup(NO_BULLET)MaxEnemies db 3

;The maximum number of enemies onscreenNumEnemies db 0

;The current number of enemies in any stateEnemyChance db 20

;There is a 1/this number chance of enemyPLaserSpeed db 8

;Speed of player's laserELaserSpeed db 4

;Speed of enemy's laserELaserChn db 50

;There is a 1/num chance of enemy shootingEnemySpdChn db 25

;There is a 1/num chance enemy moves/direcEnemySpeed db 1

;How many bytes traversed per movementMouseX dw MOUSE_HORDEF

;The X location of the cursorMouseY dw MOUSE_VERDEF

;The Y location of the cursorLeftButton db 0

;Boolean on whether left button is pressedScore dw 0

;The scoreNumKills dw 0

;The number of kills

Page 6: Space Opera CSO

NumKillsCnt db 0;Counts every 10 kill

Lives db 3;The number of lives the player has left

GameOver db 0;1 if game is over (lives are lost)

MenuSelect db 0;Menu selection

MenuSelect2 db 0;Difficulty menu selection

NumberPtrs dw offset zero;This array contains the offsets to the

dw offset one;number graphics. NumberPtrs[0] points todw offset two;the zero graphic for example, making itdw offset three

;useful for drawing numbers from data.dw offset fourdw offset fivedw offset sixdw offset sevendw offset eightdw offset nine

;---------------------------------------------------------------------------------------------------;Strings;ASCII Strings for menu;---------------------------------------------------------------------------------------------------newgamestr db 'New Game', 0helpstr db 'Help', 0quitstr db 'Quit', 0copystr db '(c) Samuel Horwitz 2008', 0diffstr db 'Choose your difficulty', 0gameoverstr db 'Game Over. Press any key '

db 'to continue.', 0diff1 db 'Easy', 0diff2 db 'Medium', 0diff3 db 'Hard', 0diff4 db 'Nightmare', 0thanksstr db 'Thanks to Robert Dewar and', 0Dh, 8, 8, 8

db 'Nathan Hull for portions of code', 0help db 'SPACE OPERA is a very simple game. '

db 'The goal is to destroy as many ' db 'enemies as you can before 'db 'dying.', 0Dh, 0Dhdb 'You control a small, blue ' db 'spaceship that can move around 'db 'the screen and fire ', 0Dhdb 'lasers. 'db 'Your enemies are magenta spaceships, 'db 'and they, too, can fire 'db 'lasers.', 0Dh, 0Dhdb 'Move around the screen with your 'db 'mouse, and fire your lasers with '

Page 7: Space Opera CSO

db 'the left mouse button.', 0Dh, 0Dhdb 'Watch out though, you only 'db 'have 3 lives.', 0Dh, 0Dhdb 'Have fun! (To leave this 'db 'screen, press ESC)', 0Dh, 0Dhdb 'Also, you can pause your game 'db 'with the "p" button. 'db 'Make sure you do not have ', 0Dhdb 'caps lock on!', 0

;Thanks to http://www.network-science.de/ascii/ for ASCII art generatorspoperastr db ' _______________ __'

db '_ ______ _______ ', 0Dhdb ' / _ \ / 'db ' \ / || ____| ', 0Dhdb ' | (-----| |_) | / ^'db ' \ | ,---- | |__ ', 0Dhdb ' \ \ | ___/ / /_'db '\ \ | | | __| ', 0Dhdb '.----) | | | / ___'db '__ \ | `----.| |____ ', 0Dhdb '|_______/ | _| /__/ 'db ' \__\ \______||_______| ', 0Dhdb ' ______ .______ ______'db '_ .______ ___ ', 0Dhdb ' / __ \ | _ \ | ___'db '_|| _ \ / \ ', 0Dhdb '| | | | | |_) | | |__ 'db ' | |_) | / ^ \ ', 0Dhdb '| | | | | ___/ | __|'db ' | / / /_\ \ ', 0Dhdb '| `-- | | | | |___'db '_ | |\ \----./ _____ \ ', 0Dhdb ' \______/ | _| |______'db '_|| _| `.________/ \__\ ', 0

;---------------------------------------------------------------------------------------------------;SPRITES;The bitmap data used to construct the characters and objects that appear on the screen.;---------------------------------------------------------------------------------------------------;The player custom bitmap.player db 00000000b, 00000000b, 00000000b

db 00000000b, 00000000b, 00000000bdb 00000000b, 01000010b, 00000000bdb 00000000b, 01011010b, 00000000bdb 00000000b, 00111100b, 00000000bdb 00000000b, 00111100b, 00000000bdb 00000000b, 01111110b, 00000000bdb 00000100b, 01111110b, 00100000bdb 00000100b, 01111110b, 00100000bdb 00001110b, 01111110b, 01110000bdb 00001110b, 01111110b, 01110000bdb 00001110b, 01111110b, 01110000bdb 00001110b, 01111110b, 01110000b

Page 8: Space Opera CSO

db 00001110b, 01111110b, 01110000bdb 00001110b, 01111110b, 01110000bdb 00001110b, 01111110b, 01110000bdb 00001111b, 11111111b, 11110000bdb 00001111b, 11111111b, 11110000bdb 01111111b, 11111111b, 11111110bdb 11111111b, 11111111b, 11111111bdb 11111111b, 11111111b, 11111111bdb 11111111b, 11111111b, 11111111bdb 11110001b, 10000001b, 10001111bdb 01110001b, 10000001b, 10001110b

;The graphic used for number of livesplayerlife db 00000000b

db 00011000bdb 00011000bdb 01011010bdb 01011010bdb 01111110bdb 01111110bdb 10100101b

;The enemy number 1 custom characters.enemy1 db 01100000b, 00000000b, 00000110b

db 01100000b, 00000000b, 00000110bdb 01110000b, 00011000b, 00001110bdb 01110000b, 00011000b, 00001110bdb 01111000b, 00011000b, 00011110bdb 01111000b, 00011000b, 00011110bdb 00111111b, 11111111b, 11111100bdb 00011111b, 11111111b, 11111000bdb 00011111b, 11111111b, 11111000bdb 00011111b, 11111111b, 11111000bdb 00011111b, 11111111b, 11111000bdb 00011101b, 11111111b, 10111000bdb 00001000b, 11111111b, 00010000bdb 00001000b, 01111110b, 00010000bdb 00001000b, 01111110b, 00010000bdb 00001000b, 01111110b, 00010000bdb 00001000b, 01111110b, 00010000bdb 00000000b, 01111110b, 00000000bdb 00000000b, 00111100b, 00000000bdb 00000000b, 00111100b, 00000000bdb 00000000b, 00111100b, 00000000bdb 00000000b, 00011000b, 00000000bdb 00000000b, 00000000b, 00000000bdb 00000000b, 00000000b, 00000000b

;Explosionexplosion db 00000000b, 00000000b, 00000000b

db 01000000b, 00000000b, 00000000bdb 00111100b, 01100000b, 00000000bdb 00111110b, 01110000b, 00111000bdb 00111111b, 01111000b, 11111000bdb 00111111b, 11111001b, 11111000bdb 00111111b, 11111111b, 11111000b

Page 9: Space Opera CSO

db 00011111b, 11111111b, 11110000bdb 00001111b, 11111111b, 11110000bdb 00011111b, 11111111b, 11000000bdb 00111111b, 11111111b, 11000000bdb 00011111b, 11111111b, 11100000bdb 00000111b, 11111111b, 11100000bdb 00111111b, 11111111b, 11110000bdb 00011111b, 11111111b, 11111100bdb 00011111b, 11111111b, 11111100bdb 00011111b, 11111111b, 11111100bdb 00011100b, 11111111b, 11111100bdb 00010000b, 11110001b, 11111100bdb 00000000b, 11110001b, 11111000bdb 00000000b, 11100000b, 11001000bdb 00000000b, 11000000b, 00001110bdb 00000000b, 10000000b, 00000010bdb 00000000b, 00000000b, 00000001b

;Laserlaser db 01000010b

;Oneone db 00111100b

db 01001000bdb 00001000bdb 00001000bdb 00001000bdb 00001000bdb 00001000bdb 01111110b

;Twotwo db 00111000b

db 01000100bdb 00000100bdb 00001000bdb 00010000bdb 00100000bdb 01000000bdb 01111100b

;Threethree db 00111000b

db 01000100bdb 01000010bdb 00011100bdb 00000010bdb 01000010bdb 00100100bdb 00011000b

;Fourfour db 10000100b

db 10000100bdb 10000100bdb 11111110b

Page 10: Space Opera CSO

db 00000100bdb 00000100bdb 00000100bdb 00000100b

;Fivefive db 01111110b

db 01000000bdb 10000000bdb 01111110bdb 00000010bdb 10000010bdb 01000010bdb 00111100b

;Sixsix db 00011100b

db 00100010bdb 01000000bdb 11111100bdb 10000010bdb 10000010bdb 01000010bdb 00111100b

;Sevenseven db 01111110b

db 10000010bdb 00000010bdb 00000100bdb 00000100bdb 00001000bdb 00001000bdb 00001000b

;Eighteight db 00111100b

db 01000010bdb 01100110bdb 00011000bdb 00100100bdb 01000010bdb 01000010bdb 00111100b

;Ninenine db 00111100b

db 01000010bdb 01000010bdb 00111110bdb 00000010bdb 01000010bdb 01000010bdb 00111100b

Page 11: Space Opera CSO

;Zerozero db 00111100b

db 01000010bdb 01000010bdb 01000010bdb 01000010bdb 01000010bdb 01000010bdb 00111100b

;---------------------------------------------------------------------------------------------------;PROCEDURES;Callable segments of code that make programming easier.;---------------------------------------------------------------------------------------------------;Add enemiesaddenemies proc

push ax;Save registers

push bxpush cxpush dxpush simov al, NumEnemies

;Copy number of enemies to registercmp al, MaxEnemies

;Compare number of current enemies to maxje addendn

;Number of enemies is equal to max, donemov ah, 0

;Prepare ah for axmov al, EnemyChance

;Prepare for random interruptint 62h

;Get random numbercmp ax, 0

;See if random number is 0jne addendn

;Not 0 so donemov si, 0

;Otherwise, prepare array pointeraddenlp1: cmp EnemiesX[si], NO_ENEMY ;Check if this location in array is free

jne addenlp2;Location isn't free

mov EnemiesY[si], 0;Spawn on top row

addenlp3: mov ax, VIDEO_WIDTH-ENEMY1_WD-1 ;Upper bound for random number

int 62h;Get random number

inc ax;Between 1 and 39

mov cl, 3;Prepare for shift

Page 12: Space Opera CSO

shl ax, cl;Multiply random number by 8

mov bx, 0;Prepare registers for collision check proc

mov ch, ENEMY1_WD_PIXmov cl, ENEMY1_HT_PIXcall chkcolenemy

;Check for collisions with other enemiescmp dx, NO_ENEMY

;Check if no enemy constant is returnedjne addendn

;If not, forget about new enemy for nowmov EnemiesX[si], ax

;Otherwise, move random number into X locationmov EnemiesStat[si], CHAR_ALIVE ;Enemy is

aliveinc NumEnemies

;Increment the number of enemiesjmp addendn

;Finishedaddenlp2: add si, 2

;Increment array pointercmp si, ENEMY_LIMIT*2

;Check if out of boundsjne addenlp1

;Not out of array bounds so loopaddendn: pop si

;Restore registerspop dxpop cxpop bxpop axret

;Returnaddenemies endp

;Calculates the byte offset;REGISTERS AX X Offset; BX Y Offset;RETURNS AX Byte Offset; BX Bit Offsetbyteoffset proc

push di;Save registers

push dxpush simov di, ax

;Backup X offsetmov si, bx

;Backup Y offsetmov ax, VIDEO_WIDTH

;Get the video width in bytes for multiplicationmul bx

;Multiply width by Y offsetmov si, ax

;Backup product

Page 13: Space Opera CSO

mov ax, di;Get X offset for division use

mov bx, 8;The number of bits in byte, for division use

div bx;Divide the X offset by 8

add ax, si;Add the quotient and product

mov bx, dx;Copy the remainder to bx

pop si;Restore registers

pop dxpop diret

;Returnbyteoffset endp

;This procedure directly accesses EGA video memory and clears the screen by writing 0s in a loop.clearscn proc

push ax;Save registers

push cxpush dipush dxmov dx, SC_PORT

;Copy SC port location to dx for out usemov al, SC_MAP_MASK_REG

;Use map masking capability of SC portmov ah, ALL_COLORS

;Mask off no planesout dx, ax

;Write to all bitplanesmov di, 0

;Reset video memory pointermov cx, VIDEO_MAX_PIX/2

;Set repeat loop register to max number of pixels/2mov ax, 0

;AX is 0 which will clear video memory by wordrep stosw

;Write 0 to video memory until end of video memorypop dx

;Restore registerspop dipop cxpop axret

;Returnclearscn endp

;Checks for an enemy collision given an X and Y coordinates;REGISTERS AX X Offset; BX Y Offset; CH Width in pixels; CL Height in pixels

Page 14: Space Opera CSO

;RETURNS DX NO_ENEMY if no collision or the array pointer to the enemy collided withchkcolenemy proc

push ax;Save registers

push bppush bxpush cxpush dipush simov si, 0

;Prepare array pointermov bp, NO_ENEMY

;Default return value to be put in dx at end of procchkcolelp1: cmp EnemiesX[si], NO_ENEMY ;Check if enemy is present in this offset

je chkcolelp2;No enemy present so next in array

mov di, bx;Copy Y offset to new register

mov dh, 0;Prepare dx

mov dl, cladd di, dx

;Add the height to the temp Y offsetcmp di, EnemiesY[si]

;Compare enemy top to inputted bottomjb chkcolelp2

;Inputted object above enemy, so next in arraymov di, EnemiesY[si]

;Copy enemy's Y offset to new registeradd di, ENEMY1_HT_PIX

;Add height of enemy to temp enemy Y offsetcmp bx, di

;Compare inputted top to enemy bottomja chkcolelp2

;Inputted object below enemy, so nextmov di, ax

;Copy X offset to new registermov dh, 0

;Prepare dxmov dl, chadd di, dx

;Add the width to the new temp X offsetcmp di, EnemiesX[si]

;Compare enemy left to inputted rightjb chkcolelp2

;Inputted object is left of enemy, so nextmov di, EnemiesX[si]

;Copy enemy's X offset to new registeradd di, ENEMY1_WD_PIX

;Add width of enemy to temp enemy X offsetcmp ax, di

;Compare inputted left to enemy rightja chkcolelp2

;Inputted object is right of enemy, so next

Page 15: Space Opera CSO

mov bp, si;Collision has occured, indicate with whom

jmp chkcoledn;Finished

chkcolelp2: add si, 2;Increment array pointer

cmp si, ENEMY_LIMIT*2;Check if array is out of bounds

jne chkcolelp1;Not out of bounds so loop

chkcoledn: mov dx, bp;Set return register to "no enemy" or collided enemy

pop si;Restore registers

pop dipop cxpop bxpop bppop axret

;Returnchkcolenemy endp

;Checks for an enemy collision given an X and Y coordinates;REGISTERS AX X Offset; BX Y Offset; CH Width in pixels; CL Height in pixels;RETURNS DX NO_PLAYER if no collision or the array pointer to the enemy collided withchkcolplay proc

push ax;Save registers

push bppush bxpush cxpush dipush simov bp, NO_PLAYER

;Default return value to be put in dx at end of procmov di, bx

;Copy Y offset to new registermov dh, 0

;Prepare dxmov dl, cladd di, dx

;Add the height to the temp Y offsetcmp di, PlayerY

;Compare player top to inputted bottomjb chkcolpdn

;Inputted object above player, so next in arraymov di, PlayerY

;Copy player's Y offset to new registeradd di, PLAYER_HT_PIX

;Add height of player to temp player Y offsetcmp bx, di

;Compare inputted top to player bottom

Page 16: Space Opera CSO

ja chkcolpdn;Inputted object below enemy, so next

mov di, ax;Copy X offset to new register

mov dh, 0;Prepare dx

mov dl, chadd di, dx

;Add the width to the new temp X offsetcmp di, PlayerX

;Compare player left to inputted rightjb chkcolpdn

;Inputted object is left of player, so nextmov di, PlayerX

;Copy player's X offset to new registeradd di, PLAYER_WD_PIX

;Add width of player to temp player X offsetcmp ax, di

;Compare inputted left to player rightja chkcolpdn

;Inputted object is right of player, so nextmov bp, 1

;Collision has occuredjmp chkcolpdn

;Finishedchkcolpdn: mov dx, bp

;Set return registerpop si

;Restore registerspop dipop cxpop bxpop bppop axret

;Returnchkcolplay endp

;Decrement livesdeclives proc

sub Lives, 1;Decrement lives

jnz declivesdn;Check if 0

mov GameOver, 1;Yes so game over

declivesdn: ret;Return

declives endp

;Decrement score by specified amount;REGISTERS AX Amount to decrementdecscore proc

cmp ax, Score;Compare amount to current score

ja decscore1;If amount to decrement is greater, make 0

Page 17: Space Opera CSO

sub Score, ax;Otherwise, subtract score

jmp decscoredn;And finish

decscore1: mov Score, 0;Score is 0

decscoredn: ret;Return

decscore endp

;Delay routine. This code borrows heavily from the Dewar Game Program. Some wording and constant;names have been changed.delay proc

push ax;Save registers

push dxsub ax, ax

;Set ax to 0 for procedure callmov dx, SCREEN_DELAY

;Delay lengthcall note

;Play blank note for specified timepop dx

;Restore registerspop axret

;Returndelay endp

;Difficulty menudiffmenu proc

push ax;Save registers

push bxpush dxmov MenuSelect2, 0

;Start at top of menumov ah, 5

;Change video pagemov al, 2int 10h

diffmenulp: mov ax, offset diffstrmov bh, 2mov bl, LIGHT_CYAN_MASKmov dh, 8mov dl, 30call writeasciizmov ax, offset diff1mov bh, 2cmp MenuSelect2, MENU2_EASY

;Check if menu selection is 0jne diffmen1_1

;It's not so nextmov bl, YELLOW_MASKjmp diffmen1_2

;Next

Page 18: Space Opera CSO

diffmen1_1: mov bl, WHITE_MASKdiffmen1_2: mov dh, 9

mov dl, 30call writeasciizmov ax, offset diff2mov bh, 2cmp MenuSelect2, MENU2_MEDIUM ;Check if

menu selection is 1jne diffmen2_1

;It's not so nextmov bl, YELLOW_MASKjmp diffmen2_2

;Nextdiffmen2_1: mov bl, WHITE_MASKdiffmen2_2: mov dh, 10

mov dl, 30call writeasciizmov ax, offset diff3mov bh, 2cmp MenuSelect2, MENU2_HARD

;Check if menu selection is 2jne diffmen3_1

;It's not so nextmov bl, YELLOW_MASKjmp diffmen3_2

;Nextdiffmen3_1: mov bl, WHITE_MASKdiffmen3_2: mov dh, 11

mov dl, 30call writeasciizmov ax, offset diff4mov bh, 2cmp MenuSelect2, MENU2_NIGHTMARE;Check if

menu selection is 3jne diffmen4_1

;It's not so nextmov bl, YELLOW_MASKjmp diffmen4_2

;Nextdiffmen4_1: mov bl, WHITE_MASKdiffmen4_2: mov dh, 12

mov dl, 30call writeasciiz

;The following gets keyboard input and acts accordinglymov ax, 0int 16hcmp ah, KBD_DOWNjne diffmenu1cmp MenuSelect2, 3jne diffmenu2mov MenuSelect2, 0jmp diffmenu1

diffmenu2: inc MenuSelect2diffmenu1: cmp ah, KBD_UP

jne diffmenu3cmp MenuSelect2, 0jne diffmenu4

Page 19: Space Opera CSO

mov MenuSelect2, 3jmp diffmenu3

diffmenu4: dec MenuSelect2diffmenu3: cmp ah, KBD_ESC

jne diffmenu5call menuinit

diffmenu5: cmp ah, KBD_ENTERjne diffmenu9cmp MenuSelect2, 0jne diffmenu6call start_easy

diffmenu6: cmp MenuSelect2, 1jne diffmenu7call start_med

diffmenu7: cmp MenuSelect2, 2jne diffmenu8call start_hard

diffmenu8: cmp MenuSelect2, 3jne diffmenu9call start_nm

diffmenu9: jmp diffmenulppop dx

;Restore registerspop bxpop axret

;Returndiffmenu endp

;Display the help screendisphelp proc

push ax;Save registers

push bxpush dxmov ah, 5mov al, 1int 10hmov ax, offset helpmov bh, 1mov bl, WHITE_MASKmov dh, 0mov dl, 0call writeasciiz

;Write help data to screendisphelp1: mov ax, 0

int 16h;Get input

cmp ah, KBD_ESC;Check if Escape key pressed

jne disphelp;If not, get input

mov ah, 5mov al, 0int 10h

;Go back to menu video page

Page 20: Space Opera CSO

pop dx;Restore registers

pop bxpop axret

;Returndisphelp endp

;Display the number of lives the player hasdisplives proc

push ax;Save registers

push bxpush cxpush dipush dxpush simov ch, Lives

;Move number of lives to a registercmp ch, 0

;Check if lives are 0je displidn

;Zero so donemov dx, SC_PORT

;Prepare for out statement mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, LIGHT_CYAN_MASK ;Lives color is light cyan out dx, ax ;Set lives color by masking off correct planes

mov dx, VIDEO_WIDTH_PIX;Prepare registers for proc

displilp1: sub dx, 10mov ax, dxmov bx, 8call byteoffset

;Get byte offsetmov di, ax

;Set video offsetmov si, 0

;Reset array pointermov cl, 8

;Reset counterdisplilp2: mov al, playerlife[si] ;The bmp data for the graphic

stosb;Send bmp data to video memory

add di, VIDEO_WIDTH-1;Point to next row

inc si;Next row in bmp data

sub cl, 1;Decrement count

jnz displilp2;Next row

Page 21: Space Opera CSO

sub ch, 1;Decrement life count

jnz displilp1;Not zero so loop

displidn: pop si;Restore registers

pop dxpop dipop cxpop bxpop axret

;Returndisplives endp

;Display a number;REGISTERS AX Number to display (between 0-9 inclusive); BX X Offset; CX Y Offsetdispnumber proc

push ax;Save registers

push bppush bxpush cxpush dipush sicmp ax, 9ja dispnmdncmp ax, 0jb dispnmdnmov si, ax

;Backup numbermov ax, bx

;Prepare registers for procmov bx, cxcall byteoffset

;Get byte offsetmov di, ax

;Set video offsetshl si, 1

;Multiply pointer by 2 because word arraymov bp, NumberPtrs[si]

;Get number offsetmov cl, 8

;Number of times to repeatdispnmlp1: mov al, [bp]

;Draw number by looping through bmp datastosbinc bpadd di, VIDEO_WIDTH-1sub cl, 1jnz dispnmlp1

dispnmdn: pop si;Restore registers

pop dipop cx

Page 22: Space Opera CSO

pop bxpop bppop axret

;Returndispnumber endp

;Displays the scoredispscore proc

push ax;Save registers

push bppush bxpush cxpush dipush dxpush simov dx, SC_PORT

;Prepare for out statement mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, WHITE_MASK ;Score color is white out dx, ax ;Set score color by masking off correct planes

mov ax, Score;Prepare for divison

mov dx, 0mov bx, 10000div bx

;Dividemov bx, 10

;Prepare registers for procmov cx, 8call dispnumber

;Display numbermov ax, dx

;Preparemov dx, 0mov bx, 1000div bx

;Dividemov bx, 18

;Prepare registers for procmov cx, 8call dispnumber

;Display numbermov ax, dx

;Preparemov dx, 0mov bx, 100div bx

;Dividemov bx, 26

;Prepare registers for procmov cx, 8

Page 23: Space Opera CSO

call dispnumber;Display number

mov ax, dx;Prepare

mov dx, 0mov bx, 10div bx

;Dividemov bx, 34

;Prepare registers for procmov cx, 8call dispnumber

;Display numbermov ax, dxmov bx, 42

;Prepare registers for procmov cx, 8call dispnumber

;Display numberpop si

;Restore registerspop dxpop dipop cxpop bxpop bppop axret

;Returndispscore endp

;Draw the enemiesdrawenemies proc

push ax;Save registers

push bppush bxpush dipush dxpush simov bp, 0

;Array pointerjmp drawenlp1

;Go to first loopdrawenlp1: cmp EnemiesX[bp], NO_ENEMY ;Compare current enemy to "no enemy" constant

je drawenlp2;No enemy here so draw nothing

mov ax, EnemiesX[bp];Prepare registers for procedure

mov bx, EnemiesY[bp]call byteoffset

;Get byte offsetmov di, ax

;Copy byte offset to dicmp EnemiesStat[bp], CHAR_EXP ;Check if

enemy had been shot

Page 24: Space Opera CSO

je drawenlp4;Enemy will be not drawn as explosion

mov si, 0;Bitmap pointer

mov dx, SC_PORT;Prepare for out statement

mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, MAGENTA_MASK ;Enemy color is magenta out dx, ax ;Set enemy color by masking off correct planes mov bh, ENEMY1_WD ;Store enemy width mov bl, ENEMY1_HT_PIX ;Store enemy heightdrawenlp3: mov al, enemy1[si] ;Move current bmp byte into al for drawing

stosb;Write byte to video memory

inc si;Increment bmp pointer

sub bh, 1;Decrement enemy width

jnz drawenlp3;Check if width is equal to 0. If not, next byte

mov bh, ENEMY1_WD;Width has been decremented to 0, reset

sub bl, 1;Decrement the height of the enemy

jz drawenlp2;Height of enemy is 0, next enemy

add di, VIDEO_WIDTH - ENEMY1_WD;Otherwise begin drawing next row

jmp drawenlp3;Loop

drawenlp4: mov ax, EnemiesX[bp] ;Prepare registers for proc

mov bx, EnemiesY[bp]call drawexp

;Draw an explosiondrawenlp2: add bp, 2

;Increment array pointercmp bp, ENEMY_LIMIT*2

;Check if pointer is out of boundsjne drawenlp1

;Not out of bounds so loopdrawendn: pop si

;Restore registerspop dxpop dipop bxpop bppop axret

;Returndrawenemies endp

Page 25: Space Opera CSO

;Draw an explosion;REGISTERS AX X Offset; BX Y Offsetdrawexp proc

push ax;Save registers

push bxpush dipush dxpush sicall byteoffsetmov di, axmov si, 0

;Bitmap pointermov bh, EXP_WD

;Width in regmov bl, EXP_HT_PIX

;Height in regmov dx, SC_PORT

;Prepare for out statement mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, YELLOW_MASK ;Explosion color is yellow out dx, ax ;Set explosion color by masking off correct planesdrawexplp1: mov al, explosion[si] ;Move current bmp byte into al for drawing

stosb;Write byte to video memory

inc si;Increment bmp pointer

sub bh, 1;Decrement enemy width

jnz drawexplp1;Check if width is equal to 0. If not, next byte

mov bh, EXP_WD;Width has been decremented to 0, reset

sub bl, 1;Decrement the height of the explosion

jz drawexpen;Height of enemy is 0, done

add di, VIDEO_WIDTH - EXP_WD;Otherwise begin drawing next row

jmp drawexplp1;Loop

drawexpen: mov ax, EXP_FREQ ;Prepare registers for procedure

mov dx, EXP_DURcall notepop si

;Restore registerspop dxpop dipop bxpop ax

Page 26: Space Opera CSO

ret;Return

drawexp endp

;Draw the player. This should not be called directly, instead the player should be moved around the ;screen by the appropriate functions that will call this function to redraw the player correctly.drawplayer proc

push ax;Save registers

push bxpush cxpush dipush dxpush sicmp PlayerStat, CHAR_EXP ;Check if

player is explodedje drawplayex

;Draw the player explodedmov ax, PlayerX

;Prepare registers for proceduremov bx, PlayerYcall byteoffset

;Get byte offset from X and Ymov di, ax

;The byte offset to begin drawing the player mov si, 0 ;Player bitmap data array pointer mov dx, SC_PORT ;Prepare for out statement mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, LIGHT_CYAN_MASK ;Player color is light cyan out dx, ax ;Set player color by masking off correct planes mov bh, PLAYER_WD ;Store player width in register for drawing mov bl, PLAYER_HT_PIX ;Store player height in register for drawingdrawplaylp: mov al, player[si] ;Move the current player bmp byte into draw reg stosb

;Move current bitmap byte to current vid offset inc si

;Increment the bitmap array pointer sub bh, 1

;Decrement the width of the player jnz drawplaylp ;Check if width is equal to 0. If not, next byte mov bh, PLAYER_WD ;Width has decremented to 0, reset width sub bl, 1

;Decrement the height of the player jz enddrwplay ;If the height of the player is 0, we are done

Page 27: Space Opera CSO

add di, VIDEO_WIDTH - PLAYER_WD ;Otherwise, beging drawing next row of bmp data jmp drawplaylp ;Loopdrawplayex: mov ax, PlayerX

;Prepare registers for procmov bx, PlayerYcall drawexp

;Draw an explosionenddrwplay: pop si

;Restore registerspop dxpop dipop cxpop bxpop axret

;Returndrawplayer endp

;Draw the enemies' bullets on the screendraweshot proc

push ax;Save registers

push bppush bxpush cxpush dipush dxpush simov bp, 0

;Reset array pointerdraweshlp1: cmp EnemyShotX[bp], NO_BULLET ;Check if laser has been shot

je draweshlp2;No laser shot so loop

mov ax, EnemyShotX[bp];Prepare registers for collision check proc

mov bx, EnemyShotY[bp]mov ch, LASER_WD_PIXmov cl, ELaserSpeedcall chkcolplay

;Check if collision with playercmp dx, NO_PLAYER

;See if collision occuredje draweshot1

;No collision, draw lasermov PlayerStat, CHAR_EXP ;Player

has explodedcall declives

;Decrement player's livesmov ax, ENEMY1_PT_VALcall decscore

;Decrement player's scoremov EnemyShotX[bp], NO_BULLET ;Reset

enemy's lasermov EnemyShotY[bp], NO_BULLET

Page 28: Space Opera CSO

jmp draweshlp2;Done drawing laser

draweshot1: mov dx, SC_PORT;Prepare for out statement

mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, LIGHT_RED_MASK ;Laser color out dx, ax ;Set laser color by masking off correct planes mov ax, EnemyShotX[bp] mov bx, EnemyShotY[bp] call byteoffset mov di, ax mov dl, 7

;Temporary loop count register mov al, laser ;Load bmp data for laserdraweshlp3: stosb

;Send to video memoryadd di, VIDEO_WIDTH - LASER_WD ;Next rowsub dl, 1

;Subtract 1 from countjnz draweshlp3

;Count not zero so loopdraweshlp2: add bp, 2

;Increment array pointercmp bp, ENEMY_LIMIT*2

;Check if out of boundsjne draweshlp1

;Not out of bounds so loopenddrwesht: pop si

;Restore registerspop dxpop cxpop dipop bxpop bppop axret

;Returndraweshot endp

;Draw the player's bullets on the screendrawpshot proc

push ax;Save registers

push bxpush cxpush dipush dxpush sicmp PlayerShotX, NO_BULLET ;Check if

laser has been shotje enddrwpsht

;No laser shot so finishmov ax, PlayerShotX

;Prepare registers for collision check proc

Page 29: Space Opera CSO

mov bx, PlayerShotYmov ch, LASER_WD_PIXmov cl, PLaserSpeedcall chkcolenemy

;Check if collisioncmp dx, NO_ENEMY

;See if collision occured from return valueje drawpshot1

;No collision, draw lasermov si, dx

;Copy enemy value to new registermov EnemiesStat[si], CHAR_EXP ;Enemy is

now in exploded statedec NumEnemies

;Decrement enemy countmov PlayerShotX, NO_BULLET ;Reset

player's lasermov PlayerShotY, NO_BULLETmov ax, ENEMY1_PT_VAL

;Prepare register for proccall incscore

;Increment the scorejmp enddrwpsht

;Done drawing laserdrawpshot1: mov dx, SC_PORT

;Prepare for out statement mov al, SC_MAP_MASK_REG ;Prepare for out statement to set color mov ah, LIGHT_BLUE_MASK ;Laser color out dx, ax ;Set laser color by masking off correct planes mov ax, PlayerShotX mov bx, PlayerShotY call byteoffset mov di, ax

mov dl, 7;Temporary loop count register

mov al, laser;Load bmp data for laser

drawpshtlp: stosb;Send to video memory

add di, VIDEO_WIDTH - LASER_WD ;Next rowsub dl, 1

;Subtract 1 from countjnz drawpshtlp

;Count not zero so loopenddrwpsht: pop si

;Restore registerspop dxpop cxpop dipop bxpop axret

;Returndrawpshot endp

Page 30: Space Opera CSO

;Enemy shoots weaponenemyshoot proc

push ax;Save registers

push bxpush dxpush simov si, 0

;Reset array pointerenshootlp1: cmp EnemiesX[si], NO_ENEMY ;Check if enemy exists in this pointer

je enshootlp2;Doesn't exist so next enemy

cmp EnemyShotX[si], NO_BULLET ;Check if enemy has shot anything yet

jne enshootlp2;Yes, enemy has already fired weapon

mov ah, 0;Prepare ax

mov al, ELaserChn;Set random number upperbound

int 62h;Get random number

cmp ax, 0;Check if random number is 0

jne enshootlp2;Not 0, so next enemy

mov ax, EnemiesX[si];Prepare registers for proc

mov bx, EnemiesY[si]cmp bx, VIDEO_HEIGHT_PIX-8 ;Check if

too close to bottom of screenjae enshootlp2

;Too close, next enemyadd ax, 8add bx, 8mov EnemyShotX[si], axmov EnemyShotY[si], bxmov ax, LASER_FREQ

;Prepare registers for proceduremov dx, LASER_DURcall note

;Laser soundenshootlp2: add si, 2

;Increment array pointercmp si, ENEMY_LIMIT*2

;Check if out of boundsjne enshootlp1

;Not out of bounds so looppop si

;Restore registerspop dxpop bxpop axret

;Returnenemyshoot endp

Page 31: Space Opera CSO

;Resets video modes and exits to DOSexitgame proc

push ax;Save registers

mov ah, 0;Prepare graphics mode registers

mov al, 3int 10hint 20h

;Exit gamepop ax

;Restore registersret

;Returnexitgame endp

;Gets the input from the mousegetinput proc

push ax;Save registers

push bxpush cxpush dxmov ax, 3

;Prepare mouse interruptint 33h

;Get mouse position and buttonscmp cx, MOUSE_RBOUND

;Compare X offset to player maxjna movx

;Not greater so move Xmov cx, MOUSE_RBOUND

;Fix Xmovx: mov MouseX, cx

;Copy X position to variablecmp dx, MOUSE_BBOUND

;Compare Y offset to player maxjna movy

;Not greater so check upper boundmov dx, MOUSE_BBOUND

;Fix Ymovy: cmp dx, MOUSE_UBOUND ;Compare Y offset to player max

jnb movy2;Not less so move Y

mov dx, MOUSE_UBOUND;Fix Y

movy2: mov MouseY, dx;Copy Y position to variable

mov ax, 0000000000000001b ;Create bitmask

and bx, ax;Mask off button click register

cmp bx, 1;Compare button click register to 1

Page 32: Space Opera CSO

jne notpressed;Not 1 so left not pressed

mov LeftButton, 1;Otherwise, left is pressed

jmp movdone;Finished

notpressed: mov LeftButton, 0 ;Set left as not pressedmovdone: pop dx

;Restore registerspop cxpop bxpop axret

;Returngetinput endp

;Move enemies' laser downscreeninceshot proc

push ax;Save registers

push bxpush simov si, 0

;Reset array pointerinceshlp1: cmp EnemyShotX[si], NO_BULLET ;Check if laser in play

je inceshlp2;No laser, next enemy

mov ax, EnemyShotX[si];Set registers for proc

mov bx, EnemyShotY[si]call byteoffsetcmp ax, 0

;Check if laser is on screenje inceshlp2

;No laser, no incrementingmov ah, 0mov al, ELaserSpeedcmp EnemyShotY[si], VIDEO_WIDTH_PIX;See if

shot is at bottom of screenjne inceshlp3

;Not so next checkmov EnemyShotX[si], NO_BULLET

;Otherwise, remove laser from screen completelymov EnemyShotY[si], NO_BULLETjmp inceshlp2

;Next enemyinceshlp3: cmp EnemyShotY[si], ax ;Compare Y location and what will be subtracted

jnae inceshlp4;Not above or equal so make Y 0

add EnemyShotY[si], ax;Otherwise move Y naturally

jmp inceshlp2;Next enemy

inceshlp4: mov EnemyShotY[si], 0

Page 33: Space Opera CSO

inceshlp2: add si, 2;Increment array pointer

cmp si, ENEMY_LIMIT*2;Check if in bounds

jne inceshlp1;In bounds, so loop

pop si;Restore registers

pop bxpop axret

;Returninceshot endp

;Move player's lasers upscreenincpshot proc

push ax;Save registers

push bxcmp PlayerShotX, NO_BULLET ;Check if

laser in playje incpshotdn

;No laser, donemov ax, PlayerShotX

;Set registers for proceduremov bx, PlayerShotYcall byteoffsetcmp ax, 0

;Check if laser is on screenje incpshotdn

;No laser, no incrementingmov ah, 0mov al, PLaserSpeedcmp PlayerShotY, 0

;See if shot is at top of screenjne incpshotd3

;Not so next checkmov PlayerShotX, NO_BULLET

;Otherwise, remove laser from screen completelymov PlayerShotY, NO_BULLETjmp incpshotdn

;Finishedincpshotd3: cmp PlayerShotY, ax ;Compare Y location and what will be subtracted

jnae incpshotd2;Not above or equal so make Y 0

sub PlayerShotY, ax;Otherwise move Y naturally

jmp incpshotdn;Finished

incpshotd2: mov PlayerShotY, 0incpshotdn: pop bx

;Restore registerspop axret

;Returnincpshot endp

Page 34: Space Opera CSO

;Increment the score by specified amount;REGISTERS AX Amount to increase score byincscore proc

push ax;Save registers

push bxpush dxadd Score, ax

;Add specified amount to scoreinc NumKills

;Increment the number of killscmp MaxEnemies, ENEMY_LIMIT

;Check if max enemies reachedje incscrdn

;Max enemies reached, doneinc NumKillsCnt

;Increment the 20 count of number of killscmp NumKillsCnt, 19

;Compare number of kills 20 count to 19jne incscrdn

;Not 19 so donemov NumKillsCnt, 0

;Reset number of kills 20 countinc MaxEnemies

;Increment the maximum number of enemiesincscrdn: pop dx

;Restore registerspop bxpop axret

;Returnincscore endp

;Initialize menumenuinit proc

push ax;Save registers

push bxpush cxpush dxmov ah, 0

;Initialize text modemov al, TEXT_MODEint 10hmov MenuSelect, 0

menuinlp1: mov ax, offset spoperastrmov bh, 0mov bl, LIGHT_CYAN_MASKmov dh, 0mov dl, 12call writeasciiz

;Write SPACE OPERA stringmov ax, offset copystrmov bh, 0mov bl, CYAN_MASKmov dh, 14

Page 35: Space Opera CSO

mov dl, 26call writeasciiz

;Write copyright stringmov ax, offset thanksstrmov bh, 0mov bl, MAGENTA_MASKmov dh, 16mov dl, 26call writeasciiz

;Write thank you stringmov ax, offset newgamestrmov bh, 0cmp MenuSelect, MENU_NEW ;Check if

menu selection is 0jne menuin1_1

;It's not so nextmov bl, YELLOW_MASKjmp menuin1_2

;Nextmenuin1_1: mov bl, WHITE_MASKmenuin1_2: mov dh, 19

mov dl, 34call writeasciiz

;Write new game stringmov ax, offset helpstrmov bh, 0cmp MenuSelect, MENU_HELP ;Check if

menu selection is 0jne menuin2_1

;It's not so nextmov bl, YELLOW_MASKjmp menuin2_2

;Nextmenuin2_1: mov bl, WHITE_MASKmenuin2_2: mov dh, 20

mov dl, 36call writeasciiz

;Write help stringmov ax, offset quitstrmov bh, 0cmp MenuSelect, MENU_QUIT ;Check if

menu selection is 0jne menuin3_1

;It's not so nextmov bl, YELLOW_MASKjmp menuin3_2

;Nextmenuin3_1: mov bl, WHITE_MASKmenuin3_2: mov dh, 21

mov dl, 36call writeasciiz

;Write quit stringmenugetin: mov ax, 0

;Get inputint 16h

;The following controls menu selections and keyboard inputcmp ah, KBD_UP

Page 36: Space Opera CSO

jne menuin5cmp MenuSelect, 0jne menuin4mov MenuSelect, 2jmp menuin5

menuin4: sub MenuSelect, 1menuin5: cmp ah, KBD_DOWN

jne menuin7cmp MenuSelect, 2jne menuin6mov MenuSelect, 0jmp menuin7

menuin6: add MenuSelect, 1menuin7: cmp ah, KBD_ESC

jne menuin8call exitgame

menuin8: cmp ah, KBD_ENTERjne menuin11cmp MenuSelect, MENU_NEWjne menuin9call diffmenu

;Start gamemenuin9: cmp MenuSelect, MENU_HELP

jne menuin10call disphelp

;Display helpmenuin10: cmp MenuSelect, MENU_QUIT

jne menuin11call exitgame

menuin11: jmp menuinlp1;Loop

pop dx;Restore registers

pop cxpop bxpop axret

;Returnmenuinit endp

;Initialize the mousemouseinit proc

push ax;Save registers

push cxpush dxmov ax, 0

;Initialize mouse int 33h mov ax, 4 ;Set mouse position

mov cx, MOUSE_HORDEFmov dx, MOUSE_VERDEFint 33hpop dx

;Restore registerspop cx

Page 37: Space Opera CSO

pop axret

;Returnmouseinit endp

;Move the enemiesmoveenemies proc

push ax;Save registers

push cxpush simov si, 0

;Prepare array pointermov ah, 0

;Prepare al for axmov al, EnemySpeed

;Prepare register for additionmov cl, 3

;Prepare for shiftshl ax, cl

;Multiply register by 8mov bp, ax

;Copy speed offset to dxmoveenlp1: cmp EnemiesX[si], NO_ENEMY ;Check if enemy exists

je moveenlp2;No enemy so next

cmp EnemiesStat[si], CHAR_EXP ;Check if it's exploded

jne moveenlp3;Not exploded so continue

mov EnemiesX[si], NO_ENEMY ;Reset enemy in array

mov EnemiesY[si], NO_ENEMYmov EnemiesStat[si], NO_ENEMYjmp moveenlp2

;Next enemymoveenlp3: mov ah, 0

;Set random number upper boundmov al, EnemySpdChnint 62h

;Get random numbercmp ax, 0

;Compare random number to 0jne moveenlp2

;Not 0 so finishedadd EnemiesY[si], bp

;Otherwise move enemy forwardmov bx, PlayerX

;Send player X location to registercmp EnemiesX[si], bx

;Compare player X to current enemy Xjna moveenrght

;The player is to the right so move rightsub EnemiesX[si], bp

;Otherwise, player is to the left so move left

Page 38: Space Opera CSO

jmp moveenlp4;Finished

moveenrght: add EnemiesX[si], bp ;Move player rightmoveenlp4: cmp EnemiesY[si], VIDEO_HEIGHT_PIX;Check and see if player has gone offscreen

jna moveenlp2mov EnemiesX[si], NO_ENEMY ;Enemy no

longer exists; offscreenmov EnemiesY[si], NO_ENEMYmov EnemiesStat[si], NO_ENEMYdec NumEnemies

;Decrement number of enemiesmoveenlp2: add si, 2

;Increment array pointercmp si, ENEMY_LIMIT*2

;Check if array is out of boundsjne moveenlp1

;Not out of bounds so loopmoveendn: pop si

;Restore registerspop cxpop axret

;Returnmoveenemies endp

;Move player by mousemoveplayer proc

push ax;Save registers

push bxpush cxpush dxmov ax, MouseX

;Copy mouse X to temp registermov PlayerX, ax

;Copy temp register to player Xmov ax, MouseY

;Copy mouse Y to temp registermov PlayerY, ax

;Copy temp register to player Ymov ax, PlayerX

;Prepare registers for collision check procmov bx, PlayerYmov ch, PLAYER_WD_PIXmov cl, PLAYER_HT_PIXcall chkcolenemy

;Check if player has collided with enemycmp dx, NO_ENEMY

;Check if no enemyje moveplaydn

;No enemy so donemov bx, dx

;Copy enemy array pointermov PlayerStat, CHAR_EXP ;Player

has exploded

Page 39: Space Opera CSO

mov EnemiesStat[bx], CHAR_EXP ;Enemy has exploded

dec NumEnemies;Decrement the number of enemies

mov ax, ENEMY1_PT_VAL;Prepare register for proc

call decscore;Decrement score

call declives;Decrement lives

moveplaydn: pop dx;Restore registers

pop cxpop bxpop axret

;Returnmoveplayer endp

;Player shoots weaponplayershoot proc

push ax;Save registers

push bxcmp PlayerShotX, NO_BULLET ;Check if

laser existsjne endpshoot

;Is not 0, so donemov ax, PlayerX

;Prepare registers for proceduremov bx, PlayerYcmp bx, 8jbe endpshootadd ax, 8sub bx, 8mov PlayerShotX, ax

;Store the byte offset in the laser tablemov PlayerShotY, bxmov ax, LASER_FREQ

;Prepare registers for proceduremov dx, LASER_DURcall note

;Laser soundendpshoot: pop bx

;Restore registerspop axret

;Returnplayershoot endp

;Reset the game dataresetgame proc

push si;Save registers

mov PlayerShotX, NO_BULLETmov PlayerShotY, NO_BULLETmov PlayerStat, CHAR_ALIVE

Page 40: Space Opera CSO

mov PlayerDead, FALSEmov si, 0

;Array pointerresetlp1: mov EnemiesX[si], NO_ENEMY

mov EnemiesY[si], NO_ENEMYmov EnemiesStat[si], NO_ENEMYmov EnemyShotX[si], NO_BULLETmov EnemyShotY[si], NO_BULLETadd si, 2cmp si, ENEMY_LIMIT*2jne resetlp1mov MaxEnemies, 3mov NumEnemies, 0mov LeftButton, 0mov Score, 0mov NumKills, 0mov NumKillsCnt, 0mov Lives, 3mov GameOver, FALSEpop si

;Restore registersret

;Returnresetgame endp

;Reset player if deadresetplayer proc

push ax;Save registers

push cxpush dxmov PlayerStat, CHAR_ALIVE ;Player

is alive againmov ax, 4mov cx, 160mov dx, MOUSE_BBOUNDint 33hpop dx

;Restore registerspop cxpop axret

;Returnresetplayer endp

;Start easystart_easy proc

mov EnemyChance, 50mov PLaserSpeed, 16mov ELaserSpeed, 4mov ELaserChn, 100mov EnemySpdChn, 50mov EnemySpeed, 1jmp initret

;Returnstart_easy endp

Page 41: Space Opera CSO

;Start mediumstart_med proc

mov EnemyChance, 25mov PLaserSpeed, 8mov ELaserSpeed, 4mov ELaserChn, 50mov EnemySpdChn, 25mov EnemySpeed, 1jmp initret

;Returnstart_med endp

;Start hardstart_hard proc

mov EnemyChance, 20mov PLaserSpeed, 8mov ELaserSpeed, 8mov ELaserChn, 50mov EnemySpdChn, 25mov EnemySpeed, 2jmp initret

;Returnstart_hard endp

;Start nightmarestart_nm proc

mov EnemyChance, 10mov PLaserSpeed, 4mov ELaserSpeed, 8mov ELaserChn, 100mov EnemySpdChn, 10mov EnemySpeed, 2jmp initret

;Returnstart_nm endp

;Writes an ASCIIZ string in text mode at specified location;REGISTERS AX Offset to ASCIIZ string; BH Video page; BL Color; DH Row; DL Columnwriteasciiz proc

push ax;Save registers

push bxpush cxpush dipush dxmov di, ax

;Backup offsetmov si, dx

;Backup location

Page 42: Space Opera CSO

wrasciilp1: mov ah, 2;Set cursor position

int 10hmov ah, 9

;Write charactermov al, [di]

;Copy character into new registercmp al, 0

;Check if nullje wrasciidn

;If null, finishedcmp al, 0Dh

;Check if carriage returnjne wrasciilp2

;Not so skipinc dh

;Increment rowmov cx, simov dl, cl

;Reset columnjmp wrasciilp3

;Next characterwrasciilp2: cmp al, 8

;Check if backspacejne wrasciip4

;Not so skipdec dl

;Decrement columnjmp wrasciilp3

;Next characterwrasciip4: mov cx, 1

;Repeat onceint 10h

;Otherwise, write charinc dl

;Increment column offsetwrasciilp3: inc di

;Increment character offset in stringjmp wrasciilp1

;Loopwrasciidn: mov ah, 1

mov ch, 32int 10h

;Get rid of cursorpop dx

;Restore registerspop dipop cxpop bxpop axret

;Returnwriteasciiz endp

;Initialize videovideoinit proc

Page 43: Space Opera CSO

push ax;Save registers

mov ah, 0;Prepare registers for setting video mode int 10h

mov al, VIDEO_MODE;Choose video mode for int 10h

int 10h;Initialize video mode

mov ah, 5;Prepare registers for setting default page

mov al, 0;Default page is 0

int 10h;Set default page

mov ax, VIDEO_SEGMENT;Set video segment for copying into ES register

mov es, ax;ES points to video segment

pop ax;Restore registers

ret;Return

videoinit endp

;---------------------------------------------------------------------------------------------------;DEWAR CODE;Code taken from Dewar game;---------------------------------------------------------------------------------------------------;; Routine to play note on speaker;; (AX) Frequency in Hz (32 - 32000); (DX) Duration in units of 1/100 second; CALL NOTE;; Note: a frequency of zero, means rest (silence) for the indicated; time, allowing this routine to be used simply as a timing delay.;; Definitions for timer gate control;CTRL EQU 61H ; timer gate control portTIMR EQU 00000001B ; bit to turn timer onSPKR EQU 00000010B ; bit to turn speaker on;; Definitions of input/output ports to access timer chip;TCTL EQU 043H ; port for timer controlTCTR EQU 042H ; port for timer count values;; Definitions of timer control values (to send to control port);TSQW EQU 10110110B ; timer 2, 2 bytes, sq wave, binaryLATCH EQU 10000000B ; latch timer 2;; Define 32 bit value used to set timer frequency

Page 44: Space Opera CSO

;FRHI EQU 0012H ; timer frequency high (1193180 / 256)FRLO EQU 34DCH ; timer low (1193180 mod 256);NOTE PROC PUSH AX ; save registers PUSH BX PUSH CX PUSH DX PUSH SI MOV BX,AX ; save frequency in BX MOV CX,DX ; save duration in CX;; We handle the rest (silence) case by using an arbitrary frequency to; program the clock so that the normal approach for getting the right; delay functions, but we will leave the speaker off in this case.; MOV SI,BX ; copy frequency to BX OR BX,BX ; test zero frequency (rest) JNZ NOT1 ; jump if not MOV BX,256 ; else reset to arbitrary non-zero;; Initialize timer and set desired frequency;NOT1: MOV AL,TSQW ; set timer 2 in square wave mode OUT TCTL,AL MOV DX,FRHI ; set DX:AX = 1193180 decimal MOV AX,FRLO ; = clock frequency DIV BX ; divide by desired frequency OUT TCTR,AL ; output low order of divisor MOV AL,AH ; output high order of divisor OUT TCTR,AL;; Turn the timer on, and also the speaker (unless frequency 0 = rest); IN AL,CTRL ; read current contents of control port OR AL,TIMR ; turn timer on OR SI,SI ; test zero frequency JZ NOT2 ; skip if so (leave speaker off) OR AL,SPKR ; else turn speaker on as well;; Compute number of clock cycles required at this frequency;NOT2: OUT CTRL,AL ; rewrite control port XCHG AX,BX ; frequency to AX MUL CX ; frequency times secs/100 to DX:AX MOV CX,100 ; divide by 100 to get number of beats DIV CX SHL AX,1 ; times 2 because two clocks/beat XCHG AX,CX ; count of clock cycles to CX;; Loop through clock cycles;NOT3: CALL RCTR ; read initial count;; Loop to wait for clock count to get reset. The count goes from the; value we set down to 0, and then is reset back to the set value

Page 45: Space Opera CSO

;NOT4: MOV DX,AX ; save previous count in DX CALL RCTR ; read count again CMP AX,DX ; compare new count : old count JB NOT4 ; loop if new count is lower LOOP NOT3 ; else reset, count down cycles;; Wait is complete, so turn off clock and return; IN AL,CTRL ; read current contents of port AND AL,0FFH-TIMR-SPKR ; reset timer/speaker control bits OUT CTRL,AL ; rewrite control port POP SI ; restore registers POP DX POP CX POP BX POP AX RET ; return to callerNOTE ENDP;; Routine to read count, returns current timer 2 count in AX;RCTR PROC MOV AL,LATCH ; latch the counter OUT TCTL,AL ; latch counter IN AL,TCTR ; read lsb of count MOV AH,AL IN AL,TCTR ; read msb of count XCHG AH,AL ; count is in AX RET ; return to callerRCTR ENDP;---------------------------------------------------------------------------------------------------;END OF DEWAR CODE;End of code taken from Dewar game;---------------------------------------------------------------------------------------------------

start:;---------------------------------------------------------------------------------------------------;Menu code;Code for pre-game menu;---------------------------------------------------------------------------------------------------menu: call menuinit

;Initialize menu

;---------------------------------------------------------------------------------------------------;INITIALIZE CODE;Pre-game loop code.;---------------------------------------------------------------------------------------------------init: call videoinit

;Initialize video

Page 46: Space Opera CSO

call mouseinit;Initialize mouse

call resetgame ;Reset game data

call clearscn;Clear the screen

jmp game;Skip first get input call/draw enemies call

;---------------------------------------------------------------------------------------------------;GAME LOOP;The main loop that is run through, throughout the game.;---------------------------------------------------------------------------------------------------;GAME LOOP CODE HEREgame: mov ah, 1

;Check if key pressint 16hjz game3

;No key pressed so do loopmov ah, 0

;Otherwise, get pressed keyint 16hcmp ah, KBD_ESC

;If key is escape go to menujne game5call menuinit

game5: cmp al, 'p';If key is 'p', pause game

jne game3mov cx, MouseXmov dx, MouseY

game6: mov ah, 0;Get key while paused

int 16hcmp al, 'p'

;If key is 'p', unpausejne game6

;Otherwise, getkey loopmov ax, 4

;Unpaused, reset mouse to wear start of pause locint 33h

game3: call clearscn ;Clear the screen

call addenemies;Add enemies

call getinput;Get input

call moveplayer;Move the player

call moveenemies;Move the enemies

call enemyshoot;Enemies will try and shoot

cmp LeftButton, 1;See if left button is pressed

Page 47: Space Opera CSO

jne game2;It's not so do nothing

call playershoot;Otherwise, shoot

game2: call draweshot ;Draw enemies' lasers

call drawpshot;Draw player's lasers

call incpshot;Increment player's lasers

call inceshot;Increment enemies' lasers

call drawenemies;Draw the enemies

call drawplayer;Draw the player on the screen

call dispscore;Display the score

call displives;Display number of lives

call delay;Delay

cmp GameOver, 0;Check if game is over

je game4;Not game over, continue

mov ax, offset gameoverstrmov bh, 0mov bl, WHITE_MASKmov dh, 11mov dl, 2call writeasciiz

;Right game over stringmov ax, 0int 16h

;Before returning to menu, have player press keycall menuinit

;Otherwise, exit gamegame4: cmp PlayerStat, CHAR_EXP ;Check if player has exploded

jne game7;Not exploded, so loop

call resetplayer;Reset the player

game7: jmp game;Loop

end