diff --git a/.boot2.asm.swp b/.boot2.asm.swp new file mode 100644 index 0000000..d31a798 Binary files /dev/null and b/.boot2.asm.swp differ diff --git a/.program.asm.swp b/.program.asm.swp new file mode 100644 index 0000000..bcace04 Binary files /dev/null and b/.program.asm.swp differ diff --git a/Makefile b/Makefile index 47a1203..1def271 100755 --- a/Makefile +++ b/Makefile @@ -3,24 +3,27 @@ all : image compile : nasm -f bin -o boot.bin boot.asm nasm -f bin -o program.bin program.asm - nasm -f bin -o program2.bin program2.asm + nasm -f bin -o beep.bin beep.asm +# nasm -f bin -o program2.bin program2.asm image : compile sudo dd if=/dev/zero of=disk.img bs=1024 count=720 + #cat boot.bin program.bin > exe.bin sudo dd if=boot.bin of=disk.img bs=512 count=1 conv=notrunc - sudo dd if=program.bin of=disk.img bs=512 seek=1 count=1 conv=notrunc - sudo dd if=program2.bin of=disk.img bs=512 seek=2 count=1 conv=notrunc - + sudo dd if=program.bin of=disk.img bs=512 seek=1 count=2 conv=notrunc + sudo dd if=beep.bin of=disk.img bs=512 seek=3 count=1 conv=notrunc flashusb : image sudo dd if=boot.bin of=/dev/sdb bs=512 count=1 - sudo dd if=program.bin of=/dev/sdb bs=512 seek=1 count=1 - sudo dd if=program2.bin of=/dev/sdb bs=512 seek=2 count=1 + sudo dd if=program.bin of=/dev/sdb bs=512 seek=1 count=2 + sudo dd if=beep.bin of=/dev/sdb bs=512 seek=3 count=1 +# sudo dd if=exe.bin of=/dev/sdb bs=512 count=4 + run : image - qemu-system-x86_64 disk.img + qemu-system-x86_64 disk.img -soundhw pcspk clean : rm *.img diff --git a/beep.asm b/beep.asm new file mode 100644 index 0000000..6ecf832 --- /dev/null +++ b/beep.asm @@ -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 + diff --git a/beep.bin b/beep.bin new file mode 100644 index 0000000..ba63910 Binary files /dev/null and b/beep.bin differ diff --git a/boot.asm b/boot.asm index 4335b0c..52f32b7 100755 --- a/boot.asm +++ b/boot.asm @@ -1,5 +1,4 @@ [org 0x7c00] - [bits 16] pre: @@ -12,14 +11,12 @@ welcome: xor ax,ax ; We want a segment of 0 for DS for this question mov ds,ax ; Set AX to appropriate segment value for your situation mov es,ax ; In this case we'll default to ES=DS - mov bx,0x8000 ; Stack segment can be any usable memory + mov bx,0x1000 ; Stack segment can be any usable memory mov ss,bx ; This places it with the top of the stack @ 0x80000. mov sp,ax ; Set SP=0 so the bottom of stack will be @ 0x8FFFF cld ; Set the direction flag to be positive direction - - - mov ah, 01h ;make cursor invisible + mov ah, 01h ;make cursor invisible mov cx, 2607h int 10h @@ -82,17 +79,17 @@ load_it_all_1: mov bx, 0x1000 ; BX = 0x1000. ES:BX=0x0:0x1000 ; ES:BX = starting address to read sector(s) into mov ah, 02 ; Int 13h/AH=2 = Read Sectors From Drive - mov al, 01 ; Sectors to read = 1 - mov ch, 00 ; CH=Cylinder. Second sector of disk + mov al, 0x10 ; Sectors to read = 1 + mov ch, 00 ; CH=Cylinder. Second sector of disk ; is at Cylinder 0 not 1 - mov cl, 02 ; Sector to read = 2 + mov cl, 02 ; Sector to read = 2 mov dh, 00 ; Head to read = 0 - ; DL hasn't been destroyed by our bootloader code and still - ; contains boot drive # passed to our bootloader by the BIOS + mov dl, [bootdev] int 13h - jc wolf_error + + jc wolf_error popf jmp 0x0:0x1000 cli diff --git a/boot.bin b/boot.bin index 0e9d01b..e8c7266 100644 Binary files a/boot.bin and b/boot.bin differ diff --git a/boot2.asm b/boot2.asm new file mode 100644 index 0000000..cfa8a95 --- /dev/null +++ b/boot2.asm @@ -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 + + diff --git a/buffer.asm b/buffer.asm new file mode 100644 index 0000000..a8220e8 --- /dev/null +++ b/buffer.asm @@ -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 \ No newline at end of file diff --git a/disk.img b/disk.img index 0fb2cc8..b709635 100755 Binary files a/disk.img and b/disk.img differ diff --git a/exe.bin b/exe.bin new file mode 100644 index 0000000..437c7e6 Binary files /dev/null and b/exe.bin differ diff --git a/img/box.bin b/img/box.bin new file mode 100644 index 0000000..a5c15ae Binary files /dev/null and b/img/box.bin differ diff --git a/img/box.png b/img/box.png new file mode 100644 index 0000000..ae23d25 Binary files /dev/null and b/img/box.png differ diff --git a/img/coin_0.bin b/img/coin_0.bin new file mode 100644 index 0000000..d1cea24 Binary files /dev/null and b/img/coin_0.bin differ diff --git a/img/coin_0.png b/img/coin_0.png new file mode 100644 index 0000000..87d1077 Binary files /dev/null and b/img/coin_0.png differ diff --git a/img/coin_1.bin b/img/coin_1.bin new file mode 100644 index 0000000..42173aa Binary files /dev/null and b/img/coin_1.bin differ diff --git a/img/coin_1.png b/img/coin_1.png new file mode 100644 index 0000000..71bb349 Binary files /dev/null and b/img/coin_1.png differ diff --git a/img/coin_2.bin b/img/coin_2.bin new file mode 100644 index 0000000..6a16372 Binary files /dev/null and b/img/coin_2.bin differ diff --git a/img/coin_2.png b/img/coin_2.png new file mode 100644 index 0000000..4159c5d Binary files /dev/null and b/img/coin_2.png differ diff --git a/img/colors.png b/img/colors.png new file mode 100644 index 0000000..e4eda1d Binary files /dev/null and b/img/colors.png differ diff --git a/img/image2binary.py b/img/image2binary.py new file mode 100644 index 0000000..6416072 --- /dev/null +++ b/img/image2binary.py @@ -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.") \ No newline at end of file diff --git a/img/map.bin b/img/map.bin new file mode 100644 index 0000000..3cad53d --- /dev/null +++ b/img/map.bin @@ -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 \ No newline at end of file diff --git a/img/player_back_0.bin b/img/player_back_0.bin new file mode 100644 index 0000000..d549c07 Binary files /dev/null and b/img/player_back_0.bin differ diff --git a/img/player_back_0.png b/img/player_back_0.png new file mode 100644 index 0000000..0cc7609 Binary files /dev/null and b/img/player_back_0.png differ diff --git a/img/player_back_1.bin b/img/player_back_1.bin new file mode 100644 index 0000000..ba7afab Binary files /dev/null and b/img/player_back_1.bin differ diff --git a/img/player_back_1.png b/img/player_back_1.png new file mode 100644 index 0000000..0ad676c Binary files /dev/null and b/img/player_back_1.png differ diff --git a/img/player_back_2.bin b/img/player_back_2.bin new file mode 100644 index 0000000..9e34896 Binary files /dev/null and b/img/player_back_2.bin differ diff --git a/img/player_back_2.png b/img/player_back_2.png new file mode 100644 index 0000000..8efb707 Binary files /dev/null and b/img/player_back_2.png differ diff --git a/img/player_front_0.bin b/img/player_front_0.bin new file mode 100644 index 0000000..550b5f2 Binary files /dev/null and b/img/player_front_0.bin differ diff --git a/img/player_front_0.png b/img/player_front_0.png new file mode 100644 index 0000000..32a0f49 Binary files /dev/null and b/img/player_front_0.png differ diff --git a/img/player_front_1.bin b/img/player_front_1.bin new file mode 100644 index 0000000..bbbc732 Binary files /dev/null and b/img/player_front_1.bin differ diff --git a/img/player_front_1.png b/img/player_front_1.png new file mode 100644 index 0000000..1fa37cc Binary files /dev/null and b/img/player_front_1.png differ diff --git a/img/player_front_2.bin b/img/player_front_2.bin new file mode 100644 index 0000000..97930f7 Binary files /dev/null and b/img/player_front_2.bin differ diff --git a/img/player_front_2.png b/img/player_front_2.png new file mode 100644 index 0000000..e14ebc5 Binary files /dev/null and b/img/player_front_2.png differ diff --git a/img/player_left_0.bin b/img/player_left_0.bin new file mode 100644 index 0000000..4599e26 Binary files /dev/null and b/img/player_left_0.bin differ diff --git a/img/player_left_0.png b/img/player_left_0.png new file mode 100644 index 0000000..2baca03 Binary files /dev/null and b/img/player_left_0.png differ diff --git a/img/player_left_1.bin b/img/player_left_1.bin new file mode 100644 index 0000000..dd647fc Binary files /dev/null and b/img/player_left_1.bin differ diff --git a/img/player_left_1.png b/img/player_left_1.png new file mode 100644 index 0000000..3cf3f9f Binary files /dev/null and b/img/player_left_1.png differ diff --git a/img/player_left_2.bin b/img/player_left_2.bin new file mode 100644 index 0000000..dd647fc Binary files /dev/null and b/img/player_left_2.bin differ diff --git a/img/player_left_2.png b/img/player_left_2.png new file mode 100644 index 0000000..3cf3f9f Binary files /dev/null and b/img/player_left_2.png differ diff --git a/img/player_right_0.bin b/img/player_right_0.bin new file mode 100644 index 0000000..4e1060e Binary files /dev/null and b/img/player_right_0.bin differ diff --git a/img/player_right_0.png b/img/player_right_0.png new file mode 100644 index 0000000..bb19c69 Binary files /dev/null and b/img/player_right_0.png differ diff --git a/img/player_right_1.bin b/img/player_right_1.bin new file mode 100644 index 0000000..5910571 Binary files /dev/null and b/img/player_right_1.bin differ diff --git a/img/player_right_1.png b/img/player_right_1.png new file mode 100644 index 0000000..022673c Binary files /dev/null and b/img/player_right_1.png differ diff --git a/img/player_right_2.bin b/img/player_right_2.bin new file mode 100644 index 0000000..5910571 Binary files /dev/null and b/img/player_right_2.bin differ diff --git a/img/player_right_2.png b/img/player_right_2.png new file mode 100644 index 0000000..022673c Binary files /dev/null and b/img/player_right_2.png differ diff --git a/img/tile.bin b/img/tile.bin new file mode 100644 index 0000000..47e274f Binary files /dev/null and b/img/tile.bin differ diff --git a/img/tile.png b/img/tile.png new file mode 100644 index 0000000..6d6c46f Binary files /dev/null and b/img/tile.png differ diff --git a/program.asm b/program.asm index 63b5f49..87e37a5 100755 --- a/program.asm +++ b/program.asm @@ -1,6 +1,7 @@ [org 0x1000] start: + mov [bootdev], dl mov ah, 01h ;make cursor invisible mov cx, 2607h int 10h @@ -14,36 +15,45 @@ start: mov ah, 06h ;draw rect on background mov cx, 0101h - mov dx, 164Dh + mov dx, 124Dh mov bh, 3Eh int 10h mov ah, 06h ;draw shadow - mov cx, 1702h - mov dx, 174Eh + mov cx, 1302h + mov dx, 134Eh mov bh, 0Eh int 10h mov ah, 06h ;draw shadow mov cx, 024Eh - mov dx, 174Eh + mov dx, 134Eh mov bh, 0Eh int 10h + ; menu bottom + mov ah, 06h ;draw rect on background + mov cx, 1700h + mov dx, 184Fh + mov bh, 3Fh + int 10h + mov ah, 02h ;sets cursor to top to write mov bh, 0h - mov dh, 1h - mov dl, 1h + mov dh, 17h + mov dl, 2h int 10h + mov si, menuhelp + call print - mov al, 0xC9 ;draw border - mov bl, 0x03 - mov ah,0x0e - int 10h - mov al, 0xCD - mov bl, 0x03 - mov ah,0x0e - int 10h + mov si, menuselect + call print + + mov si, menuexit + call print + + mov si, menuenter + call print mov ah, 02h ;sets cursor to top to write mov bh, 0h @@ -111,6 +121,8 @@ waitforkey: je .up cmp ah, 11h je .down + cmp ah, 1Ch + je loadproject jmp waitforkey .up @@ -141,29 +153,90 @@ waitforkey: jmp print_projects + + +loadproject: + + +mov bx, [currentselection] + + pushf + stc + + mov ah,00 + int 13h + +.read_sector: + mov ax, 0x0 + mov es, ax ; ES = 0 + mov bx, 0x2000 ; BX = 0x1000. ES:BX=0x0:0x1000 + ; ES:BX = starting address to read sector(s) in$ + mov ah, 02 ; Int 13h/AH=2 = Read Sectors From Drive; + mov al, 0x10 ; Sectors to read = 1 + mov ch, 00 ; CH=Cylinder. Second sector of disk + ; is at Cylinder 0 not 1 + mov cl, 04 ; Sector to read = 2 + mov dh, 00 ; Head to read = 0 + + mov dl, [bootdev] + int 13h + + + jc wolf_error + popf + jmp 0x0:0x2000 + cli + hlt + + +wolf_error: + mov si, wolf_error_msg + call print + mov si, wolf_error_msg1 + call print + mov ah,00 + int 16h + xor ax,ax + int 19h + + + print: lodsb or al,al jz exit - ;mov bl, 0x03 mov ah,0x0e int 10h jmp print exit: ret +msg1 db "ARTIST / TITLE",0 -msg1 db " X P U B",0x0A,0 -msg2 db " NOT MY DEFAULT",0x0D,0x0A,0 - -project1 db "Alex / Poetic Software", 0x0A,0 -project2 db "Tash / Silence Making", 0x0A,0 -project3 db "Alice / F00d", 0x0A,0 -project4 db "Joca / The ghost in the speaker", 0x0A,0 -project5 db "Angeliki / Voices", 0x0A,0 -project6 db "Zalan / Phantasmagoria", 0x0A,0 +project1 db "Name / Exampletitle of this",0 +project2 db "Name2 / Silence and more",0 +project3 db "Name3 / C00l, new title and more", 0 +project4 db "Name4 / Everyon", 0 +project5 db "Name5 / Voices and more", 0 +project6 db "Name6 / Examples of titles", 0 projects dq project1, project2, project3, project4, project5, project6 +menuhelp db "F1 Help", 0 +menuselect db " W/S Select Item",0 +menuexit db 0x0D,0x0A," ESC Exit", 0 +menuenter db " Enter publication",0 + +wolf_error_msg db 'Program not found!',0x0D,0x0A,0 +wolf_error_msg1 db 'Press any key to restart..',0 + currentselection dw 0 storebx dw 0 + +bootdev db 0x80 ; Boot device number + +%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 + diff --git a/program.bin b/program.bin index fc414f4..601ab62 100644 Binary files a/program.bin and b/program.bin differ diff --git a/program3.asm b/program3.asm new file mode 100644 index 0000000..a0477cc --- /dev/null +++ b/program3.asm @@ -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