new beep program on enter
@ -0,0 +1,61 @@
|
|||||||
|
[org 0x2000]
|
||||||
|
|
||||||
|
start:
|
||||||
|
mov [bootdev], dl
|
||||||
|
mov ah, 06h ; Scroll up function
|
||||||
|
xor al, al ; Clear entire screen
|
||||||
|
xor cx, cx ; Upper left corner CH=row, CL=column
|
||||||
|
mov dx, 184FH ; lower right corner DH=row, DL=column
|
||||||
|
mov bh, 4Fh ; YellowOnBlue
|
||||||
|
int 10H ; execute interrupt
|
||||||
|
|
||||||
|
mov al, 182 ; meaning that we're about to load
|
||||||
|
out 43h, al ; prepare speaker for output
|
||||||
|
|
||||||
|
mov ax, 2153 ; frequency countdown value is stored in ax. It is calculated by
|
||||||
|
out 42h, al ; Output low byte.
|
||||||
|
mov al, ah ; Output high byte.
|
||||||
|
out 42h, al
|
||||||
|
|
||||||
|
in al, 61h
|
||||||
|
or al, 00000011b
|
||||||
|
out 61h, al ; Send the new value
|
||||||
|
; mov bx, 200 ; Pause for duration of note.
|
||||||
|
|
||||||
|
mov al, 0
|
||||||
|
mov ah, 86h
|
||||||
|
mov cx, 1
|
||||||
|
mov dx, 200
|
||||||
|
int 15h
|
||||||
|
|
||||||
|
;.pause1:
|
||||||
|
; mov cx, 65535
|
||||||
|
;.pause2:
|
||||||
|
; dec cx
|
||||||
|
; jne .pause2
|
||||||
|
; dec bx
|
||||||
|
; jne .pause1
|
||||||
|
; in al, 61h ; Turn off note (get value from
|
||||||
|
; ; port 61h).
|
||||||
|
; and al, 11111100b ; Reset bits 1 and 0.
|
||||||
|
; out 61h, al ; Send new value.
|
||||||
|
jmp exit
|
||||||
|
|
||||||
|
|
||||||
|
waitforkey:
|
||||||
|
mov ah, 0x00
|
||||||
|
int 0x16
|
||||||
|
cmp ah, 01h
|
||||||
|
je exit
|
||||||
|
jmp waitforkey
|
||||||
|
|
||||||
|
exit:
|
||||||
|
in al, 61h ; Turn off note (get value from
|
||||||
|
; port 61h).
|
||||||
|
and al, 11111100b ; Reset bits 1 and 0.
|
||||||
|
out 61h, al ; Send new value.
|
||||||
|
mov dl, [bootdev]
|
||||||
|
jmp 0x1000
|
||||||
|
|
||||||
|
bootdev db 0x80 ; Boot device number
|
||||||
|
|
@ -0,0 +1,64 @@
|
|||||||
|
org 0x7C00
|
||||||
|
%define SECTOR_AMOUNT 0x10 ;Precompiler defined value for easy changing
|
||||||
|
jmp short start
|
||||||
|
nop
|
||||||
|
|
||||||
|
; BPB
|
||||||
|
OEMLabel db "Example " ; Disk label
|
||||||
|
BytesPerSector dw 512 ; Bytes per sector
|
||||||
|
SectorsPerCluster db 1 ; Sectors per cluster
|
||||||
|
ReservedForBoot dw 1 ; Reserved sectors for boot record
|
||||||
|
NumberOfFats db 2 ; Number of copies of the FAT
|
||||||
|
RootDirEntries dw 224 ; Number of entries in root dir
|
||||||
|
LogicalSectors dw 2880 ; Number of logical sectors
|
||||||
|
MediumByte db 0F0h ; Medium descriptor byte
|
||||||
|
SectorsPerFat dw 9 ; Sectors per FAT
|
||||||
|
SectorsPerTrack dw 18 ; Sectors per track (36/cylinder)
|
||||||
|
Sides dw 2 ; Number of sides/heads
|
||||||
|
HiddenSectors dd 0 ; Number of hidden sectors
|
||||||
|
LargeSectors dd 0 ; Number of LBA sectors
|
||||||
|
DriveNo dw 0 ; Drive No: 0
|
||||||
|
Signature db 41 ; Drive signature: 41 for floppy
|
||||||
|
VolumeID dd 00000000h ; Volume ID: any number
|
||||||
|
VolumeLabel db "Example "; Volume Label: any 11 chars
|
||||||
|
FileSystem db "FAT12 " ; File system type: don't change!
|
||||||
|
start:
|
||||||
|
; ------------------------------------------------------------------
|
||||||
|
|
||||||
|
;Reset disk system
|
||||||
|
mov ah, 0
|
||||||
|
int 0x13 ; 0x13 ah=0 dl = drive number
|
||||||
|
jc errorpart
|
||||||
|
;Read from harddrive and write to RAM
|
||||||
|
mov bx, 0x8000 ; bx = address to write the kernel to
|
||||||
|
mov al, SECTOR_AMOUNT ; al = amount of sectors to read
|
||||||
|
mov ch, 0 ; cylinder/track = 0
|
||||||
|
mov dh, 0 ; head = 0
|
||||||
|
mov cl, 2 ; sector = 2
|
||||||
|
mov ah, 2 ; ah = 2: read from drive
|
||||||
|
int 0x13 ; => ah = status, al = amount read
|
||||||
|
jc errorpart
|
||||||
|
jmp 0x8000
|
||||||
|
|
||||||
|
|
||||||
|
errorpart: ;if stuff went wrong you end here so let's display a message
|
||||||
|
mov si, errormsg
|
||||||
|
mov bh, 0x00 ;page 0
|
||||||
|
mov bl, 0x07 ;text attribute
|
||||||
|
mov ah, 0x0E ;tells BIOS to print char
|
||||||
|
.part:
|
||||||
|
lodsb
|
||||||
|
sub al, 0
|
||||||
|
jz end
|
||||||
|
int 0x10 ;interrupt
|
||||||
|
jmp .part
|
||||||
|
end:
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
errormsg db "Failed to load...",0
|
||||||
|
times 510-($-$$) db 0
|
||||||
|
;Begin MBR Signature
|
||||||
|
db 0x55 ;byte 511 = 0x55
|
||||||
|
db 0xAA ;byte 512 = 0xAA
|
||||||
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
|||||||
|
%ifndef CODE_BUFFER
|
||||||
|
%define CODE_BUFFER
|
||||||
|
|
||||||
|
;set's graphic mode
|
||||||
|
initGraphics:
|
||||||
|
mov ah, 0 ;set display mode
|
||||||
|
mov al, 13h ;13h = 320x200
|
||||||
|
int 0x10
|
||||||
|
ret
|
||||||
|
|
||||||
|
;resets screen to full black
|
||||||
|
resetBuffer:
|
||||||
|
pusha
|
||||||
|
mov cx, 80*60/2
|
||||||
|
;xor ax, ax ;this will make the background black
|
||||||
|
mov ax, 0xC3C3 ;this paints the background green
|
||||||
|
mov di, [screenPos]
|
||||||
|
rep stosw
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
;screen has size 320x200 but buffer only 80x60
|
||||||
|
copyBufferOver:
|
||||||
|
pusha
|
||||||
|
push es
|
||||||
|
mov es, word [graphicMemory]
|
||||||
|
xor di, di
|
||||||
|
mov cx, 200
|
||||||
|
.loop:
|
||||||
|
mov dx, cx
|
||||||
|
mov cx, 320/4
|
||||||
|
.innerloop:
|
||||||
|
mov si, 320
|
||||||
|
sub si, cx ;invert x-axis
|
||||||
|
mov bx, 200
|
||||||
|
sub bx, dx ;invert y-axis
|
||||||
|
shr bx, 2
|
||||||
|
imul bx, 80
|
||||||
|
add si, bx
|
||||||
|
add si, [screenPos]
|
||||||
|
lodsb ;read from buffer (ds:si)
|
||||||
|
mov ah, al
|
||||||
|
stosw ;write 4 pixel row to graphic memory (es:di)
|
||||||
|
stosw
|
||||||
|
loop .innerloop
|
||||||
|
mov cx, dx
|
||||||
|
loop .loop
|
||||||
|
pop es
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
;si = position of image, ax = xpos, bx = ypos
|
||||||
|
;a bit messy because of all the error checks to not draw out of screen
|
||||||
|
drawImage:
|
||||||
|
pusha
|
||||||
|
xor di, di
|
||||||
|
imul di, bx, 80 ;add offset y-position
|
||||||
|
add di, [screenPos] ;make it a pixel in buffer
|
||||||
|
;add di, ax ;add offset x-position
|
||||||
|
mov bp, ax ;backup x-position offset
|
||||||
|
xor ax, ax
|
||||||
|
lodsb
|
||||||
|
mov cx, ax ;x-size
|
||||||
|
lodsb
|
||||||
|
mov dx, ax ;y-size
|
||||||
|
.for_y:
|
||||||
|
mov bx, di
|
||||||
|
add bx, cx ;bx = offsetOnScreen + xsize
|
||||||
|
sub bx, word [screenPos] ;skip if line is out of top border screen
|
||||||
|
jl .skip_x
|
||||||
|
sub bx, cx
|
||||||
|
sub bx, 80*60
|
||||||
|
jge .skip_x ;skip if line is out of bottom border screen
|
||||||
|
xor bx, bx
|
||||||
|
.for_x:
|
||||||
|
mov al, byte [si+bx]
|
||||||
|
add bx, bp
|
||||||
|
test al, al ;skip 0bytes as transparent
|
||||||
|
jz .skip
|
||||||
|
cmp bx, 80 ;if pixel is right out of screen, skip it
|
||||||
|
jge .skip
|
||||||
|
cmp bx, 0 ;if pixel is left out of screen, skip it
|
||||||
|
jl .skip
|
||||||
|
mov byte [di+bx], al ;write byte to buffer
|
||||||
|
.skip:
|
||||||
|
sub bx, bp
|
||||||
|
inc bx
|
||||||
|
cmp bx, cx
|
||||||
|
jl .for_x
|
||||||
|
.skip_x:
|
||||||
|
add di, 80 ;next row within buffer
|
||||||
|
add si, cx ;next row within image
|
||||||
|
dec dx
|
||||||
|
jnz .for_y ;repeat for y-length
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
graphicMemory dw 0xA000
|
||||||
|
screenPos dw 0x0500 ;double buffer will be at this address
|
||||||
|
|
||||||
|
%endif
|
After Width: | Height: | Size: 982 B |
After Width: | Height: | Size: 868 B |
After Width: | Height: | Size: 874 B |
After Width: | Height: | Size: 868 B |
After Width: | Height: | Size: 563 B |
@ -0,0 +1,47 @@
|
|||||||
|
from PIL import Image #Import Image from Pillow
|
||||||
|
import sys
|
||||||
|
|
||||||
|
palleteFile = "colors.png" #pallete the BIOS uses
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
convertFile = "fox.png" #image to turn into a binary
|
||||||
|
outputFile = "fox.bin" #name of output file
|
||||||
|
elif len(sys.argv) < 3:
|
||||||
|
convertFile = sys.argv[1]
|
||||||
|
outputFile = sys.argv[1]+".bin"
|
||||||
|
elif len(sys.argv) >= 3:
|
||||||
|
convertFile = sys.argv[1]
|
||||||
|
outputFile = sys.argv[2]
|
||||||
|
|
||||||
|
pal = Image.open(palleteFile).convert('RGB')
|
||||||
|
pallete = pal.load() #load pixels of the pallete
|
||||||
|
image = Image.open(convertFile).convert('RGB')
|
||||||
|
pixels = image.load() #load pixels of the image
|
||||||
|
|
||||||
|
binary = open(outputFile, "wb") #open/create binary file
|
||||||
|
|
||||||
|
list = [] #create a list for the pallete
|
||||||
|
for y in range(pal.height):
|
||||||
|
for x in range(pal.width):
|
||||||
|
list.append(pallete[x,y]) #save the pallete into an array
|
||||||
|
|
||||||
|
binary.write(bytearray([image.width&0xFF,image.height&0xFF])) #write width and height as the first two bytes
|
||||||
|
data = []
|
||||||
|
print(image.height)
|
||||||
|
print(image.width)
|
||||||
|
for y in range(image.height):
|
||||||
|
for x in range(image.width):
|
||||||
|
difference = 0xFFFFFFF #init difference with a high value
|
||||||
|
choice = 0 #the index of the color nearest to the original pixel color
|
||||||
|
index = 0 #current index within the pallete array
|
||||||
|
#print sum([(pixels[x,y][i])**2 for i in range(3)])
|
||||||
|
for c in list:
|
||||||
|
dif = sum([(pixels[x,y][i] - c[i])**2 for i in range(3)]) #calculate difference for RGB values
|
||||||
|
if dif < difference:
|
||||||
|
difference = dif
|
||||||
|
choice = index
|
||||||
|
index += 1
|
||||||
|
data = bytearray([choice&0xFF])
|
||||||
|
print("[%d,%d] %d = %d (%d)" % (x,y,choice, difference, len(data)))
|
||||||
|
binary.write(data) #write nearest pallete index into binary file
|
||||||
|
binary.close() # close file handle
|
||||||
|
print("Done.")
|
@ -0,0 +1 @@
|
|||||||
|
00000000000000000000000000000000000000000000000000000000000000000 00000000000 X 000000000000000000000 000000000000 0000000000000000 000000000000000000000 000000000000 0000000000000000 000000000000000000000 000000000000 0000000000000000 000000000000000000 00000000 0000000000000000 000000000000000000 00000000 0000000000000000 000000000 X 00000000 0000000000000000 000000000 00000000 00000 0000000000000000 00000000 00000 0000000000000000 0000000000000000000000 X 00000000000000 0000000000000000 0000000000000000000000 00000000000000 0000000000000000 0000000000000000000000 00000000000000 00000 00000 00000000000000 00000 P X 00000 00000 000000000 X 00000 0000000000000000 0000000000000000 0000000000000000000000 0000000000000000 0000000000000000 000000 0000000000000000 000000000 000000 X 0000000000000000 X 000000 00000 000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 906 B |
After Width: | Height: | Size: 912 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 904 B |
After Width: | Height: | Size: 907 B |
After Width: | Height: | Size: 907 B |
After Width: | Height: | Size: 904 B |
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 908 B |
After Width: | Height: | Size: 861 B |
@ -0,0 +1,531 @@
|
|||||||
|
org 0x8000
|
||||||
|
bits 16
|
||||||
|
|
||||||
|
;precompiler constant
|
||||||
|
%define entityArraySize 16
|
||||||
|
;Let's begin by going into graphic mode
|
||||||
|
call initGraphics
|
||||||
|
|
||||||
|
;Now let's register some custom interrupt handlers
|
||||||
|
call registerInterruptHandlers
|
||||||
|
|
||||||
|
;init map
|
||||||
|
call initMap
|
||||||
|
|
||||||
|
;Main game loop
|
||||||
|
gameLoop:
|
||||||
|
call resetBuffer ;reset screen to draw on empty canvas
|
||||||
|
|
||||||
|
;MODULAR DRAWING CODE
|
||||||
|
mov di, entityArray
|
||||||
|
add di, 2 ;skip drawing player
|
||||||
|
.nextEntity:
|
||||||
|
cmp [di], word 0
|
||||||
|
je .skip
|
||||||
|
pusha
|
||||||
|
mov cx, [player+2] ;player x to draw relative
|
||||||
|
mov dx, [player+4] ;player z to draw relative
|
||||||
|
mov di, [di]
|
||||||
|
call drawEntity
|
||||||
|
popa
|
||||||
|
.skip:
|
||||||
|
add di, 2
|
||||||
|
cmp di, entityArray+((entityArraySize-1)*2) ;confirm that di is still pointing into the entityArray
|
||||||
|
jl .nextEntity
|
||||||
|
|
||||||
|
call drawMap
|
||||||
|
|
||||||
|
; PLAYER DRAWING CODE
|
||||||
|
mov si, [player] ;get animation
|
||||||
|
mov ax, [player+6] ;get index within animation
|
||||||
|
xor dx,dx
|
||||||
|
div word [si+2] ; animation time % time of full animation
|
||||||
|
mov ax, dx
|
||||||
|
xor dx, dx
|
||||||
|
div word [si] ; (animation time % time of full animation) / time of one frame
|
||||||
|
add ax, ax ; index*2 because image address is a word
|
||||||
|
|
||||||
|
add si, 4 ;skip first two words of structure
|
||||||
|
add si, ax ;add the offset to the frame
|
||||||
|
mov si, [si] ;set the image parameter to the image referenced in the frame
|
||||||
|
|
||||||
|
mov ax, 80/2 - 9/2 - 1 ;center player image
|
||||||
|
mov bx, 50/2 - 12/2 - 1 ;center player image
|
||||||
|
call drawImage
|
||||||
|
; END OF PLAYER DRAWING CODE
|
||||||
|
|
||||||
|
call copyBufferOver ;draw frame to screen
|
||||||
|
|
||||||
|
call gameControls ;handle control logic
|
||||||
|
|
||||||
|
call synchronize ;synchronize emulator and real application through delaying
|
||||||
|
|
||||||
|
jmp gameLoop
|
||||||
|
|
||||||
|
|
||||||
|
jmp $
|
||||||
|
|
||||||
|
;di = entity cx,dx = xpos,zpos
|
||||||
|
drawEntity:
|
||||||
|
push dx
|
||||||
|
inc word [di+6]
|
||||||
|
mov ax, [di+6] ;get index within animation
|
||||||
|
mov si, [di]
|
||||||
|
xor dx,dx
|
||||||
|
div word [si+2] ; animation time % time of full animation
|
||||||
|
mov ax, dx
|
||||||
|
xor dx, dx
|
||||||
|
div word [si] ; (animation time % time of full animation) / time of one frame
|
||||||
|
add ax, ax ; index*2 because image address is a word
|
||||||
|
|
||||||
|
add si, 4 ;skip first two words of structure
|
||||||
|
add si, ax ;add the offset to the frame
|
||||||
|
mov si, [si] ;set the image parameter to the image referenced in the frame
|
||||||
|
pop dx
|
||||||
|
|
||||||
|
;mov si, word [di] ;get animation
|
||||||
|
;mov si, word [si+4] ;get first frame of animation
|
||||||
|
|
||||||
|
mov ax, word [di+2] ;get entity x
|
||||||
|
sub ax, cx ;subtract the position of the player from the x position
|
||||||
|
add ax, 80/2 - 9/2 - 1 ;relative to screen image drawing code for x position
|
||||||
|
mov bx, word [di+4] ;get entity y
|
||||||
|
sub bx, dx ;subtract the position of the player from the z position
|
||||||
|
add bx, 50/2 - 12/2 - 1 ;relative to screen image drawing code for z position
|
||||||
|
call drawImage ;draw image to buffer
|
||||||
|
ret
|
||||||
|
|
||||||
|
;di = entity, cx = new_xpos, dx = new_zpos, bp = new animation
|
||||||
|
;fixed for modular entity system
|
||||||
|
checkForCollision:
|
||||||
|
pusha ;save current state
|
||||||
|
mov si, entityArray ;set si to entityArray
|
||||||
|
.whileLoop:
|
||||||
|
mov bx, word [si] ;read entityArray entry
|
||||||
|
test bx, bx ;if entry is zero => end of array
|
||||||
|
jz .whileSkip
|
||||||
|
cmp bx, di ;if entity is equal to di => next entity to not collide with it self
|
||||||
|
jz .whileSkip
|
||||||
|
|
||||||
|
mov ax, word [bx+2] ;ax = entity x
|
||||||
|
sub ax, 8 ;subtract 8 because of hitbox
|
||||||
|
cmp ax, cx ; (entityX-8 <= playerX)
|
||||||
|
jg .whileSkip
|
||||||
|
|
||||||
|
mov ax, word [bx+2] ;ax = entity x
|
||||||
|
add ax, 8 ;add 8 because of hitbox
|
||||||
|
cmp ax, cx ; (entityX+8 > playerX)
|
||||||
|
jle .whileSkip
|
||||||
|
|
||||||
|
mov ax, word [bx+4] ;ax = entity z
|
||||||
|
sub ax, 10 ;subtract 10 because of hitbox
|
||||||
|
cmp ax, dx ; (entityZ-10 <= playerZ)
|
||||||
|
jg .whileSkip
|
||||||
|
|
||||||
|
mov ax, word [bx+4] ;ax = entity z
|
||||||
|
add ax, 9 ;subtract 9 because of hitbox
|
||||||
|
cmp ax, dx ; (entityZ+9 > playerZ)
|
||||||
|
jle .whileSkip
|
||||||
|
|
||||||
|
;if we reach this point => actual collision
|
||||||
|
;mov cx, [di+2] ;set new x pos to current x pos => no movement
|
||||||
|
;mov dx, [di+4] ;set new z pos to current z pos => no movement
|
||||||
|
|
||||||
|
mov word [si], 0
|
||||||
|
inc word [coinFound]
|
||||||
|
|
||||||
|
;ding ding count found
|
||||||
|
|
||||||
|
jmp .noMapCollision
|
||||||
|
.whileSkip:
|
||||||
|
add si, 2 ;set si to the next entry in the entityArray
|
||||||
|
cmp si, entityArray+((entityArraySize-1)*2)
|
||||||
|
jl .whileLoop
|
||||||
|
.whileEnd
|
||||||
|
|
||||||
|
pusha
|
||||||
|
mov si, cx
|
||||||
|
mov bx, dx
|
||||||
|
call collideMap
|
||||||
|
popa
|
||||||
|
jnc .noMapCollision
|
||||||
|
;if we reach this point => actual collision
|
||||||
|
mov cx, [di+2] ;set new x pos to current x pos => no movement
|
||||||
|
mov dx, [di+4] ;set new z pos to current z pos => no movement
|
||||||
|
.noMapCollision:
|
||||||
|
mov byte [canWalk], 1
|
||||||
|
mov word [di] ,bp ;update the animation in use
|
||||||
|
mov word [di+2] ,cx ;update x pos
|
||||||
|
mov word [di+4] ,dx ;update y pos
|
||||||
|
popa ;reload old register state
|
||||||
|
ret
|
||||||
|
|
||||||
|
canWalk db 0
|
||||||
|
gameControls:
|
||||||
|
mov byte [canWalk], 0
|
||||||
|
mov di, player ;select the player as the main entity for "checkForCollision"
|
||||||
|
mov al, byte [pressA]
|
||||||
|
add al, byte [pressD]
|
||||||
|
cmp al, 0
|
||||||
|
jz .nokeyad
|
||||||
|
mov cx, word [player_PosX] ;set cx to player x
|
||||||
|
mov dx, word [player_PosZ] ;set dx to player z
|
||||||
|
mov bp, [player] ;set bp to current animation
|
||||||
|
cmp byte [pressD], 1 ;try to move x+1 if 'd' is pressed and set animation accordingly, test other cases otherwise
|
||||||
|
jne .nd
|
||||||
|
inc cx
|
||||||
|
mov bp, playerImg_right
|
||||||
|
.nd:
|
||||||
|
cmp byte [pressA], 1 ;try to move x-1 if 'a' is pressed and set animation accordingly, test other cases otherwise
|
||||||
|
jne .na
|
||||||
|
dec cx
|
||||||
|
mov bp, playerImg_left
|
||||||
|
.na:
|
||||||
|
call checkForCollision ;check if player would collide on new position, if not change position to new position
|
||||||
|
.nokeyad:
|
||||||
|
mov al, byte [pressW]
|
||||||
|
add al, byte [pressS]
|
||||||
|
cmp al, 0
|
||||||
|
jz .nokeyws
|
||||||
|
mov cx, word [player_PosX] ;set cx to player x
|
||||||
|
mov dx, word [player_PosZ] ;set dx to player z
|
||||||
|
mov bp, [player] ;set bp to current animation
|
||||||
|
cmp byte [pressW], 1 ;try to move z-1 if 'w' is pressed and set animation accordingly, test other cases otherwise
|
||||||
|
jne .nw
|
||||||
|
dec dx
|
||||||
|
mov bp, playerImg_back
|
||||||
|
.nw:
|
||||||
|
cmp byte [pressS], 1 ;try to move z+1 if 's' is pressed and set animation accordingly, test other cases otherwise
|
||||||
|
jne .ns
|
||||||
|
inc dx
|
||||||
|
mov bp, playerImg_front
|
||||||
|
.ns:
|
||||||
|
call checkForCollision ;check if player would collide on new position, if not change position to new position
|
||||||
|
.nokeyws:
|
||||||
|
cmp byte [canWalk], 0
|
||||||
|
jnz .noCollision
|
||||||
|
mov word [player+6], 0 ;reset animation counter
|
||||||
|
ret
|
||||||
|
.noCollision:
|
||||||
|
inc word [player+6] ;update animation if moving
|
||||||
|
ret
|
||||||
|
|
||||||
|
;======================================== NEW STUFF ==========================================
|
||||||
|
registerInterruptHandlers:
|
||||||
|
mov [0x0024], dword keyboardINTListener ;implements keyboardListener
|
||||||
|
ret
|
||||||
|
|
||||||
|
;; NEW KEYBOARD EVENT BASED CODE
|
||||||
|
pressA db 0
|
||||||
|
pressD db 0
|
||||||
|
pressW db 0
|
||||||
|
pressS db 0
|
||||||
|
keyboardINTListener: ;interrupt handler for keyboard events
|
||||||
|
pusha
|
||||||
|
xor bx,bx ; bx = 0: signify key down event
|
||||||
|
inc bx
|
||||||
|
in al,0x60 ;get input to AX, 0x60 = ps/2 first port for keyboard
|
||||||
|
btr ax, 7 ;al now contains the key code without key pressed flag, also carry flag set if key up event
|
||||||
|
jnc .keyDown
|
||||||
|
dec bx ; bx = 1: key up event
|
||||||
|
.keyDown:
|
||||||
|
cmp al,0x1e ;a
|
||||||
|
jne .check1
|
||||||
|
mov byte [cs:pressA], bl ;use cs overwrite because we don't know where the data segment might point to
|
||||||
|
.check1:
|
||||||
|
cmp al,0x20 ;d
|
||||||
|
jne .check2
|
||||||
|
mov byte [cs:pressD], bl
|
||||||
|
.check2:
|
||||||
|
cmp al,0x11 ;w
|
||||||
|
jne .check3
|
||||||
|
mov byte [cs:pressW], bl
|
||||||
|
.check3:
|
||||||
|
cmp al,0x1f ;s
|
||||||
|
jne .check4
|
||||||
|
mov byte [cs:pressS], bl
|
||||||
|
.check4:
|
||||||
|
mov al, 20h ;20h
|
||||||
|
out 20h, al ;acknowledge the interrupt so further interrupts can be handled again
|
||||||
|
popa ;resume state to not modify something by accident
|
||||||
|
iret ;return from an interrupt routine
|
||||||
|
|
||||||
|
;using interrupts instread of the BIOS is SUUPER fast which is why we need to delay execution for at least a few ms per gametick to not be too fast
|
||||||
|
synchronize:
|
||||||
|
pusha
|
||||||
|
mov si, 20 ; si = time in ms
|
||||||
|
mov dx, si
|
||||||
|
mov cx, si
|
||||||
|
shr cx, 6
|
||||||
|
shl dx, 10
|
||||||
|
mov ah, 86h
|
||||||
|
int 15h ;cx,dx sleep time in microseconds - cx = high word, dx = low word
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
;cx, dx = xpos, zpos, si = animation
|
||||||
|
;eax == 0 => success, else failed
|
||||||
|
addEntity:
|
||||||
|
pusha
|
||||||
|
mov bx, cx
|
||||||
|
mov di, entityArray
|
||||||
|
xor ax, ax
|
||||||
|
mov cx, (entityArraySize-1)
|
||||||
|
repne scasw ; iterate through entity array until empty stop is found
|
||||||
|
sub di, 2
|
||||||
|
test ecx, ecx ; abort here if at the end of the the entity array
|
||||||
|
je .failed
|
||||||
|
sub cx, (entityArraySize-1) ; calculate index within the array by using the amount of iterated entires
|
||||||
|
neg cx
|
||||||
|
shl cx, 3
|
||||||
|
add cx, entityArrayMem
|
||||||
|
mov [di], cx
|
||||||
|
mov di, cx
|
||||||
|
mov [di], si
|
||||||
|
mov [di+2], bx ; set x position of the entity
|
||||||
|
mov [di+4], dx ; set y position of the entity
|
||||||
|
xor bx, dx ; "randomise" initial animation position
|
||||||
|
mov [di+6], bx ; set animation state
|
||||||
|
popa
|
||||||
|
xor eax, eax ; return 0 if successfully added
|
||||||
|
ret
|
||||||
|
.failed:
|
||||||
|
popa
|
||||||
|
xor eax, eax
|
||||||
|
inc eax ; return 1 if failed to find a place for the entity
|
||||||
|
ret
|
||||||
|
|
||||||
|
;di = entity cx,dx = xpos,zpos
|
||||||
|
drawBlock:
|
||||||
|
mov ax, word [player+2]
|
||||||
|
sub ax, cx
|
||||||
|
imul ax, ax
|
||||||
|
mov bx, word [player+4]
|
||||||
|
sub bx, dx
|
||||||
|
imul bx, bx
|
||||||
|
add ax, bx
|
||||||
|
cmp ax, 3000 ;calculate distance
|
||||||
|
jge .skip
|
||||||
|
|
||||||
|
mov ax, cx
|
||||||
|
mov bx, dx
|
||||||
|
sub ax, word [player+2] ;subtract the position of the player from the x position
|
||||||
|
add ax, 80/2 - 9/2 - 1 ;relative to screen image drawing code for x position
|
||||||
|
sub bx, word [player+4] ;subtract the position of the player from the z position
|
||||||
|
add bx, 50/2 - 12/2 - 1 ;relative to screen image drawing code for z position
|
||||||
|
call drawImage ;draw image to buffer
|
||||||
|
.skip:
|
||||||
|
clc
|
||||||
|
ret
|
||||||
|
|
||||||
|
;set the position of the player to x=cx, z=dx
|
||||||
|
setSpawn:
|
||||||
|
mov word [player+2], cx ; set player x
|
||||||
|
mov word [player+4], dx ; set player z
|
||||||
|
add word [player+4], 3 ; offset player z
|
||||||
|
clc
|
||||||
|
ret
|
||||||
|
|
||||||
|
;spawn the coins add set the spawn position of the player
|
||||||
|
initMap:
|
||||||
|
mov si, coinImg
|
||||||
|
mov bp, addEntity
|
||||||
|
mov ah, 'X'
|
||||||
|
call iterateMap ; iterate the map and add a coin at every 'X' on the map
|
||||||
|
call spawnPlayer ; set spawn for player
|
||||||
|
ret
|
||||||
|
|
||||||
|
;draw the map
|
||||||
|
drawMap:
|
||||||
|
mov si, boxImg_0
|
||||||
|
mov bp, drawBlock
|
||||||
|
mov ah, '0'
|
||||||
|
call iterateMap ; iterate the map and add a box at every '0' on the map
|
||||||
|
;this second iteration is pretty unefficient but only optional for some ground texture
|
||||||
|
mov si, tileImg_0
|
||||||
|
mov bp, drawBlock
|
||||||
|
mov ah, ' '
|
||||||
|
call iterateMap ; iterate the map and add a tile at every ' ' on the map
|
||||||
|
ret
|
||||||
|
|
||||||
|
; si = player X, bx = player Y
|
||||||
|
collideMap:
|
||||||
|
mov bp, blockCollison
|
||||||
|
mov ah, '0'
|
||||||
|
call iterateMap ; iterate the map and check for a collision with a '0'
|
||||||
|
ret
|
||||||
|
|
||||||
|
;set the spawn of the player to the field 'P'
|
||||||
|
spawnPlayer:
|
||||||
|
mov bp, setSpawn
|
||||||
|
mov ah, 'P'
|
||||||
|
call iterateMap ; iterate the map and set the player position to the last 'P' found on the map
|
||||||
|
ret
|
||||||
|
|
||||||
|
%define tileWidth 8
|
||||||
|
%define ASCIImapWidth 64
|
||||||
|
%define ASCIImapHeight 64
|
||||||
|
;bp = function to call, ah = search for, si = parameter for bp function
|
||||||
|
iterateMap:
|
||||||
|
mov di, ASCIImap
|
||||||
|
mov cx, 0x0 ; map start x
|
||||||
|
mov dx, 0x0 ; map start y
|
||||||
|
.next:
|
||||||
|
mov al, [di]
|
||||||
|
test al, al
|
||||||
|
je .stop ; stop when null terminator found
|
||||||
|
cmp al, ah
|
||||||
|
jne .skip ; skip if the character is not the one this iteration is searching for
|
||||||
|
push ax ; save the content of ax
|
||||||
|
call bp ; call the specified function of this iteration
|
||||||
|
pop ax
|
||||||
|
jc .term ; the carry flag determines if the specified function has found what it was searching for (and thus exits)
|
||||||
|
.skip:
|
||||||
|
inc di ; point to the next character
|
||||||
|
add cx, tileWidth ; increase x pixel position
|
||||||
|
cmp cx, ASCIImapWidth*tileWidth ; check if x position is at the end of the line
|
||||||
|
jl .next
|
||||||
|
sub dx, tileWidth ; decrease y pixel position
|
||||||
|
xor cx, cx ; reset x position
|
||||||
|
jmp .next
|
||||||
|
.stop:
|
||||||
|
clc
|
||||||
|
.term:
|
||||||
|
ret
|
||||||
|
|
||||||
|
;si = player x, bx = player z, cx = block x, dx = block z
|
||||||
|
blockCollison:
|
||||||
|
push cx
|
||||||
|
push dx
|
||||||
|
sub cx, 8 ;subtract 8 because of hitbox
|
||||||
|
cmp cx, si ; (blockX-8 <= playerX)
|
||||||
|
jg .skip
|
||||||
|
add cx, 8+8 ;add 8 because of hitbox
|
||||||
|
cmp cx, si ; (blockX+8 > playerX)
|
||||||
|
jle .skip
|
||||||
|
sub dx, 10 ;subtract 10 because of hitbox
|
||||||
|
cmp dx, bx ; (blockZ-10 <= playerZ)
|
||||||
|
jg .skip
|
||||||
|
add dx, 9+10 ;subtract 9 because of hitbox
|
||||||
|
cmp dx, bx ; (blockZ+9 > playerZ)
|
||||||
|
jle .skip
|
||||||
|
stc
|
||||||
|
jmp .end
|
||||||
|
.skip:
|
||||||
|
clc
|
||||||
|
.end:
|
||||||
|
pop dx
|
||||||
|
pop cx
|
||||||
|
ret
|
||||||
|
|
||||||
|
%include "buffer.asm"
|
||||||
|
|
||||||
|
|
||||||
|
;game value
|
||||||
|
|
||||||
|
coinFound dw 0
|
||||||
|
|
||||||
|
;entity array
|
||||||
|
|
||||||
|
entityArray:
|
||||||
|
dw player
|
||||||
|
resw entityArraySize
|
||||||
|
|
||||||
|
;player structure
|
||||||
|
player:
|
||||||
|
player_Anim dw playerImg_front ;pointer to animation
|
||||||
|
player_PosX dw 0x32 ;position of player (x)
|
||||||
|
player_PosZ dw 0x32 ;position of player (z)
|
||||||
|
player_AnimC dw 0 ;animation counter
|
||||||
|
|
||||||
|
;entity structure
|
||||||
|
box:
|
||||||
|
box_Anim dw boxImg ;pointer to animation
|
||||||
|
box_PosX dw 0x10 ;position of box (x)
|
||||||
|
box_PosZ dw 0x10 ;position of box (z)
|
||||||
|
box_AnimC dw 0 ;animation counter
|
||||||
|
|
||||||
|
;other entity structures:
|
||||||
|
entityArrayMem:
|
||||||
|
resw entityArraySize*4
|
||||||
|
|
||||||
|
;animation structure
|
||||||
|
playerImg_front:
|
||||||
|
dw 5
|
||||||
|
dw 20
|
||||||
|
dw playerImg_front_0
|
||||||
|
dw playerImg_front_1
|
||||||
|
dw playerImg_front_0
|
||||||
|
dw playerImg_front_2
|
||||||
|
dw 0
|
||||||
|
|
||||||
|
playerImg_back:
|
||||||
|
dw 5
|
||||||
|
dw 20
|
||||||
|
dw playerImg_back_0
|
||||||
|
dw playerImg_back_1
|
||||||
|
dw playerImg_back_0
|
||||||
|
dw playerImg_back_2
|
||||||
|
dw 0
|
||||||
|
|
||||||
|
playerImg_right:
|
||||||
|
dw 5
|
||||||
|
dw 20
|
||||||
|
dw playerImg_right_0
|
||||||
|
dw playerImg_right_1
|
||||||
|
dw playerImg_right_0
|
||||||
|
dw playerImg_right_2
|
||||||
|
dw 0
|
||||||
|
|
||||||
|
playerImg_left:
|
||||||
|
dw 5
|
||||||
|
dw 20
|
||||||
|
dw playerImg_left_0
|
||||||
|
dw playerImg_left_1
|
||||||
|
dw playerImg_left_0
|
||||||
|
dw playerImg_left_2
|
||||||
|
dw 0
|
||||||
|
|
||||||
|
boxImg:
|
||||||
|
dw 1 ;time per frames
|
||||||
|
dw 1 ;time of animation
|
||||||
|
dw boxImg_0 ;frames
|
||||||
|
dw 0 ;zero end frame
|
||||||
|
|
||||||
|
coinImg:
|
||||||
|
dw 5 ;time per frames
|
||||||
|
dw 20 ;time of animation
|
||||||
|
dw coin_0 ;frames
|
||||||
|
dw coin_1 ;frames
|
||||||
|
dw coin_2 ;frames
|
||||||
|
dw coin_1 ;frames
|
||||||
|
dw 0 ;zero end frame
|
||||||
|
|
||||||
|
playerImg_front_0 incbin "img/player_front_0.bin"
|
||||||
|
playerImg_front_1 incbin "img/player_front_1.bin"
|
||||||
|
playerImg_front_2 incbin "img/player_front_2.bin"
|
||||||
|
playerImg_back_0 incbin "img/player_back_0.bin"
|
||||||
|
playerImg_back_1 incbin "img/player_back_1.bin"
|
||||||
|
playerImg_back_2 incbin "img/player_back_2.bin"
|
||||||
|
playerImg_right_0 incbin "img/player_right_0.bin"
|
||||||
|
playerImg_right_1 incbin "img/player_right_1.bin"
|
||||||
|
playerImg_right_2 incbin "img/player_right_2.bin"
|
||||||
|
playerImg_left_0 incbin "img/player_left_0.bin"
|
||||||
|
playerImg_left_1 incbin "img/player_left_1.bin"
|
||||||
|
playerImg_left_2 incbin "img/player_left_2.bin"
|
||||||
|
|
||||||
|
coin_0 incbin "img/coin_0.bin"
|
||||||
|
coin_1 incbin "img/coin_1.bin"
|
||||||
|
coin_2 incbin "img/coin_2.bin"
|
||||||
|
|
||||||
|
boxImg_0 incbin "img/box.bin"
|
||||||
|
tileImg_0 incbin "img/tile.bin"
|
||||||
|
|
||||||
|
ASCIImap incbin "img/map.bin"
|
||||||
|
db 0
|
||||||
|
|
||||||
|
%assign usedMemory ($-$$)
|
||||||
|
%assign usableMemory (512*16)
|
||||||
|
%warning [usedMemory/usableMemory] Bytes used
|
||||||
|
times (512*16)-($-$$) db 0 ;kernel must have size multiple of 512 so let's pad it to the correct size
|
||||||
|
;times (512*1000)-($-$$) db 0 ;toggle this to use in bochs
|