%include ../include/gigatron.i ; 0x30 -> 0x38 Vars ; 0x3A -> 0x45 Midi ; 0x4A -> 0x96 CallTable *DO NOT* pull CallTable above 0xBE, future ROMS will *NOT* work as the CallTable is preloaded and will conflict with future loading mechanisms ; 0x98 -> 0xE5 Vars ; 0xE6 -> 0xFF Stack The amount of stack space you will require depends on how many nested CALLS you make, 28 bytes allows for upto 14 nested calls kk EQU 0x30 ll EQU kk + 0x01 mm EQU kk + 0x02 nn EQU kk + 0x03 tt EQU kk + 0x04 buttonStatePrev EQU kk + 0x05 refresh EQU kk + 0x06 blocked EQU kk + 0x07 tetrominoNext EQU kk + 0x08 midiStreamPtr EQU 0x3A midiCommand EQU midiStreamPtr + 0x02 midiChannel EQU midiStreamPtr + 0x04 midiDelay EQU midiStreamPtr + 0x06 midiNote EQU midiStreamPtr + 0x08 midiScratch EQU midiStreamPtr + 0x0A xx EQU 0x98 yy EQU xx + 0x01 ii EQU xx + 0x02 jj EQU xx + 0x03 index EQU xx + 0x04 rotation EQU xx + 0x06 indexNext EQU xx + 0x08 rotationNext EQU xx + 0x0A tx EQU xx + 0x0C ty EQU xx + 0x0E tw EQU xx + 0x10 th EQU xx + 0x12 tu EQU xx + 0x14 tv EQU xx + 0x16 ox EQU xx + 0x18 oy EQU xx + 0x1A ov EQU xx + 0x1C oindex EQU xx + 0x1E orotation EQU xx + 0x20 tetrominoLut EQU xx + 0x22 tetrominoBase EQU xx + 0x24 colour EQU xx + 0x26 result EQU xx + 0x28 frameCounter EQU xx + 0x2A frameCountPrev EQU xx + 0x2C frameTicks EQU xx + 0x2E frameTicksLevel EQU xx + 0x30 rand EQU xx + 0x32 scratch EQU xx + 0x34 vbase EQU xx + 0x36 xScroll EQU xx + 0x38 tbase EQU xx + 0x3A dbase EQU xx + 0x3C textStr EQU xx + 0x3E textPos EQU xx + 0x40 textChr EQU xx + 0x42 numLines EQU xx + 0x44 scoreDelta EQU xx + 0x46 scoreLevel EQU xx + 0x48 scoreUpdate EQU xx + 0x4A scoreScratch EQU xx + 0x4C xTetris EQU 10 yTetris EQU 20 xPixels EQU xTetris*4 yPixels EQU yTetris*4 xOffset EQU (giga_xres - xPixels) / 2 yOffset EQU (giga_yres - yPixels) / 2 maxLines EQU 4 maxLevel EQU 8 maxTicks EQU 50 deltaTicks EQU 5 scorePos EQU 0x6D44 levelPos EQU 0x6D5F highPos EQU 0x1644 multPos EQU 0x6D3A fgColourB EQU 0xFF bgColourB EQU 0x15 bgColourW EQU 0x1515 _startAddress_ EQU 0x0200 ; entry point for the code, if this is missing defaults to 0x0200 _callTable_ EQU 0x0096 ; call addresses are automatically stored here by the assembler, it grows downwards ; *NOTE* gt1 spec only allows for one zero page segment, .vasm files use this for the call table ; do *NOT* make this address higher than 0x00BE, it will conflict with future ROM loading mechanisms ; do *NOT* define constants, (DB or DW), between 0x30 -> 0x44 and 0xc0 -> 0xFF, these addresses are ; used by the loader and the vCPU stack, you can create variables in these areas as long as you don't ; corrupt your nested CALL return addresses on the stack _singleStepWatch_ EQU frameCounter ; the single step debugger watches this variable location to decide when to step, ; choose a variable that is updated often _cpuUsageAddressA_ EQU 0x0600 ; these two addresses are used to build an exclusion zone around vCPU code that will not be counted _cpuUsageAddressB_ EQU 0x0620 ; in the vCPU usage meter, (almost always used to exclude your VBlank polling loop) %include midi_scores.i %include tetromino.i scoringLut EQU tetromino_I + 0x0700 levellingLut EQU tetromino_I + 0x0705 scoringLut DB 10 25 50 100 levellingLut DW 250 750 1000 2000 4000 8000 16000 32000 64000 score_string EQU 0x7FA1 high_string EQU 0x7FA8 level_string EQU 0x7FAF mult_string EQU 0x7FB2 score_string DB 6 '000000' high_string DB 6 '000000' ;level_string DB 7 'LEVEL 0' ; TODO: build a complete font set, right now ':' = 'L' and ';' = 'x' level_string DB 2 ':0' mult_string DB 2 ';1' ; tetromino_I gets an extra slot to make rand easier to implement, this also means tetromino_I will appear statistically more often, ; replace with which ever tetromino you want to favour tetromino_lut EQU 0x08E0 tetromino_lut DW tetromino_I tetromino_J tetromino_L tetromino_O tetromino_S tetromino_T tetromino_Z tetromino_I entry_point EQU 0x0200 handleInput EQU entry_point + 0x0100 updateScore EQU entry_point + 0x0200 ; too big to store in unused area of video memory incrementScore EQU entry_point + 0x0300 ; too big to store in unused area of video memory waitVBlank EQU entry_point + 0x0400 ; storing subroutines in unused areas of video memory clearBoard EQU 0x15A1 clearScreen EQU clearBoard + 0x0100 clearScreen_0 EQU clearBoard + 0x0200 setTetrisBlock EQU clearBoard + 0x0300 drawTetromino EQU clearBoard + 0x0400 drawNextTet EQU clearBoard + 0x0500 drawTetrisField EQU clearBoard + 0x0600 drawTFtopH EQU clearBoard + 0x0700 drawTFbotH EQU clearBoard + 0x0800 eraseTetromino EQU clearBoard + 0x0900 eraseTrCorner EQU clearBoard + 0x0A00 getTetrisBlock EQU clearBoard + 0x0B00 checkTetromino EQU clearBoard + 0x0C00 spawnTetromino EQU clearBoard + 0x0D00 updateTetromino EQU clearBoard + 0x0E00 checkLines EQU clearBoard + 0x0F00 moveLines EQU clearBoard + 0x1000 shakeScreen EQU clearBoard + 0x1100 printText EQU clearBoard + 0x1200 printDigits EQU clearBoard + 0x1300 updateHighScore EQU clearBoard + 0x1400 resetLevel EQU clearBoard + 0x1500 resetScore EQU clearBoard + 0x1600 incrementLevel EQU clearBoard + 0x1700 loadTetromino EQU clearBoard + 0x1800 resetAudio EQU clearBoard + 0x1900 playMidi EQU clearBoard + 0x1A00 midiStartNote EQU clearBoard + 0x1B00 midiSegment EQU clearBoard + 0x1C00 %include macros.i %include clear_board.i %include draw_tetromino.i %include erase_tetromino.i %include check_tetromino.i %include spawn_tetromino.i %include check_lines.i %include print_text.i %include update_score.i %include digit_font.i %include audio.i entry_point LDWI giga_vram STW vbase ; vram base address LDWI giga_text32 STW tbase ; text font base address, (ROM) LDWI digit_font0 STW dbase ; tiny digit font base address, (RAM) LDWI giga_videoTable + 1 STW xScroll CALL resetAudio CALL clearScreen CALL drawTetrisField restart CALL resetLevel CALL resetScore CALL clearBoard LDWI 0x0000 STW scoreDelta STW scoreLevel STW frameCounter LDWI maxTicks STW frameTicksLevel STW frameTicks LD giga_rand0 ST tetrominoNext LDI 0x00 ST blocked LD giga_frameCount STW frameCountPrev LDWI tetromino_lut STW tetrominoLut CALL spawnTetromino LD giga_frameCount ; Start checking midi stream immediately ST midiDelay ; main update loop update ST scratch CALL saveTetromino ; wait for VBlank vBlank CALL waitVBlank CALL playMidi ; input CALL handleInput ST refresh XORI 0xFB ; down BEQ frame_count1 LD refresh ; all other input BNE erase ; reset frameTicks LDW frameTicksLevel STW frameTicks ; frameTicks defines speed of tetrominoes frame_count1 LDW frameCounter ADDI 0x01 STW frameCounter SUBW frameTicks BLT vBlank ; don't allow input to override timing LDI 0x00 ST refresh ; erase old tetromino erase LD blocked BNE check_txl CALL eraseTetromino ; if(tx < 0 - tu) tx = 0 - tu; check_txl LDW tx ADDW tu BGE check_txr LDWI 0x00 SUBW tu STW tx BRA frame_count0 ; if(tx > TETRIS_XEXT - tw - tu) tx = TETRIS_XEXT - tw - tu; check_txr LDW tx ADDW tw ADDW tu SUBI xTetris BLE frame_count0 LDWI xTetris SUBW tw SUBW tu STW tx ; if(frameCount >= frameTick) frame_count0 LDW frameCounter SUBW frameTicks BLT check_blocks LDWI 0x0000 STW frameCounter LDI 0x00 ; reset flicker control ST blocked ; gravity INC ty ; if(y > TETRIS_YEXT - h) LDW ty ADDW th SUBI yTetris BLE check_blocks ; draw floor tetromino LD ty SUBI 0x01 ST ty CALL drawTetromino ; spawn new tetromino CALL spawnTetromino LDI 0xFF ; control flicker ST blocked BRA update ; check new tetromino position check_blocks CALL checkTetromino ; checks tetromino for occupied blocks, returns result, 0 = empty, 1 = game over, >1 = blocked LDW result BEQ draw_new ; check for game over SUBI 0x01 BNE check_blocked CALL resetAudio LDWI game_overMidi00 ; game over music STW midiStreamPtr BRA restart ; check for fall blocked whilst input active, (but not drop) check_blocked LD refresh BEQ fall_blocked ; load old tetromino CALL loadTetromino BRA draw_new ; draw falling blocked tetromino at previous y position fall_blocked LD ty SUBI 0x01 ST ty CALL drawTetromino ; spawn new tetromino CALL spawnTetromino BRA update draw_new CALL drawTetromino BRA update ; load tetromino state loadTetromino LDW ox STW tx LDW oy STW ty LDW ov ; vertical offset in tetris block units STW tv LDW oindex STW index LDW orotation STW rotation RET ; save tetromino state saveTetromino LDW tx STW ox LDW ty STW oy LDW tv ; vertical offset in tetris block units STW ov LDW index STW oindex LDW rotation STW orotation RET ; handle input, returns 0x00 if nothing was handled, otherwise returns input handleInput LD giga_buttonState ; 0xFF is no input XORI 0xFF BNE handleI_down ST buttonStatePrev ; return 0x00 RET ; level triggered buttons handleI_down LD giga_buttonState XORI 0xFB ; down BNE handleI_event LDWI 2 STW frameTicks LD giga_buttonState RET ; edge triggering handleI_event LD buttonStatePrev ; only handle new events BEQ handleI_left LD 0x00 RET ; edge triggered buttons handleI_left LD giga_buttonState ST buttonStatePrev XORI 0xFD ; left BNE handleI_right LDW tx ; tx-- SUBI 0x01 STW tx LD giga_buttonState RET handleI_right LD giga_buttonState XORI 0xFE ; right BNE handleI_up LDW tx ; tx++ ADDI 0x01 STW tx LD giga_buttonState RET handleI_up LD giga_buttonState XORI 0xF7 ; up BNE handleI_exit LDW rotation STW scratch ADDI 0x10 ; rotation table's are separated by 16 bytes ANDI 0x30 ; 4 rotation patterns STW rotation PUSH CALL updateTetromino POP ; check rotation LDW ty ; if(ty > TETRIS_YEXT - th - tv) ADDW th ADDW tv SUBI yTetris BLE handleI_exit ; restore rotation LDW scratch STW rotation PUSH CALL updateTetromino POP LD 0x00 RET handleI_exit LD giga_buttonState RET waitVBlank LD giga_frameCount SUBW frameCountPrev BEQ waitVBlank LD giga_frameCount STW frameCountPrev RET