├── .gitattributes ├── .gitignore ├── README ├── fallingblocks.asm ├── fallingblocks.tap ├── fallingblocks.zxk └── license.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Falling Blocks // 3 | // Copyright (c)2015-2016 Peter McQuillan // 4 | // All Rights Reserved. // 5 | // Distributed under the BSD Software License (see license.txt) // 6 | //////////////////////////////////////////////////////////////////////////// 7 | 8 | This package contains the source code for the game 'Falling Blocks'. 9 | This game is written in z80 assembly for the ZX Spectrum. 10 | 11 | The code has been successfully assembled and tested on both ZX Spin and Pasmo. 12 | Using Pasmo allows you to produce a TAP file which can be read by most Spectrum 13 | emulators or can even be used to produce a WAV file or tape copy of the game. 14 | 15 | There is a TAP file included in the package that can be used on an emulator, 16 | including online Javascript emulators like http://jsspeccy.zxdemo.org/ 17 | 18 | The game itself is based on the classic Tetris, but with a few twists on the 19 | game and some extra features that are not commonly available like ghost (where 20 | you can see where your piece would go if you dropped it) and save (where you 21 | can swap a piece in play for later usage). 22 | 23 | It is possible to define your own keys for use in the game, but the default 24 | keys are as follows: 25 | 26 | O - move left 27 | P - move right 28 | Space - rotate piece 29 | D - Drop piece 30 | G - enable/disable ghost mode 31 | S - Swap/Save a piece for later usage 32 | 33 | You are able to modify the behaviour of the 'Drop piece' key in the settings menu 34 | off the main menu. The three possible options are 35 | 36 | Full - Pressing the drop key will cause the piece to fall down the screen as far as 37 | possible 38 | While Held - This will cause the piece to drop as long as the drop key is pressed 39 | (effectively works like a down key) 40 | Mixture - If you quickly press/tap the drop key, the piece will fall down the screen 41 | as far as possible, however holding the drop key will drop the piece as long as the 42 | drop key is pressed - therefore a mixture of 'Full' and 'While Held' 43 | 44 | A ZXK file is available which provides keyboard mapping for the ZX Spectrum Vega. 45 | If using this Vega keyboard mapping please do not enable kempston joystick in the game 46 | menu as this will interfere with the keyboard mappings. 47 | 48 | Please direct any questions or comments to beatofthedrum@gmail.com -------------------------------------------------------------------------------- /fallingblocks.asm: -------------------------------------------------------------------------------- 1 | ; 2 | ; FallingBlocks.asm 3 | ; 4 | ; Copyright (c) 2015-2016 Peter McQuillan 5 | ; 6 | ; All Rights Reserved. 7 | ; 8 | ; Distributed under the BSD Software License (see license.txt) 9 | ; 10 | ; 11 | 12 | org 24576 13 | ; set up our own routines. Two elements, a table that points to where the interrupt code is 14 | ; held and the actual interrupt code itself. Due to the strange way interrupts work on spectrum 15 | ; our table is a series of the value 200. The idea is that an interrupt call would randomly jump 16 | ; to somewhere in this table and read the values 200 (2 reads) 0 this gives a memory location of 17 | ; (200*256) + 200 = 51400, which is where we will put our actual interrupt routine 18 | ; We put our table out of the way, starting at 65024 (which is 256 * 254) 19 | 20 | di ; we are setting up out own interrupt routine, disable while doing this 21 | ld a,254 ; high byte of pointer table location (256 * 254 gives 65024). 22 | ld i,a ; set high byte. 23 | im 2 ; select interrupt mode 2. 24 | ei ; enable interrupts. 25 | jp START 26 | 27 | graphics 28 | defb 254, 126, 190, 94, 174, 86, 170, 0 ; basic block 29 | defb 126, 129, 189, 165, 165, 189, 129, 126 ; old side wall graphic 30 | defb 231, 231, 231, 231, 231, 231, 231, 231 ;vertical pipe 31 | defb 60, 126, 126, 231, 231, 231, 231, 231 ;pipe end (top) 32 | defb 231, 231, 231, 231, 231, 126, 126, 60 ; pipe end (bottom) 33 | defb 255, 255, 255, 0, 0, 255, 255, 255 ;horizontal pipe 34 | defb 231, 231, 227, 224, 240, 255, 127, 63 ; pipe corner bottom left 35 | defb 63, 127, 255, 240, 224, 227, 231, 231 ; pipe corner top left 36 | defb 231, 231, 199, 7, 15, 255, 254, 252 ; pipe corner bottom right 37 | defb 252, 254, 255, 15, 7, 199, 231, 231 ; pipe corner top right 38 | defb 8, 4, 2, 255, 2, 4, 8, 0, 56 ; arrow pointing right 39 | 40 | ;Port array used for the redefine keys routine 41 | port_array: defb $7f ; B-SPACE 42 | defb $bf ; H-ENTER 43 | defb $df ; Y-P 44 | defb $ef ; 6-0 45 | defb $f7 ; 1-5 46 | defb $fb ; Q-T 47 | defb $fd ; A-G 48 | defb $fe ; CAPS-V 49 | 50 | key_music_port: defb $7f 51 | key_music_pattern: defb 4 52 | key_left_port: defb $df 53 | key_left_pattern: defb 2 54 | key_right_port: defb $df 55 | key_right_pattern: defb 1 56 | key_anticlockwise_port: defb $7f 57 | key_anticlockwise_pattern: defb 1 58 | key_clockwise_port: defb $bf 59 | key_clockwise_pattern: defb 16 60 | key_drop_port: defb $fd 61 | key_drop_pattern: defb 4 62 | key_ghost_port: defb $fd 63 | key_ghost_pattern: defb 16 64 | key_swap_port: defb $fd 65 | key_swap_pattern: defb 2 66 | 67 | 68 | ROM_CLS: EQU 3435 69 | CHAN_OPEN: EQU 5633 70 | CC_INK: EQU 16 71 | CC_PAPER: EQU 17 72 | CC_AT: EQU 22 73 | 74 | msg_left: defm CC_INK,4,CC_AT,7,8,"Left ?",255 75 | msg_right: defm CC_INK,4,CC_AT,8,8,"Right ?",255 76 | msg_anticlockwise: defm CC_INK,4,CC_AT,9,8,"Anti Clockwise ?",255 77 | msg_clockwise: defm CC_INK,4,CC_AT,10,8,"Clockwise ?",255 78 | msg_drop: defm CC_INK,4,CC_AT,11,8,"Drop ?",255 79 | msg_ghost: defm CC_INK,4,CC_AT,12,8,"Ghost ?",255 80 | msg_swap: defm CC_INK,4,CC_AT,13,8,"Swap/Save ?",255 81 | msg_music: defm CC_INK,4,CC_AT,14,8,"Music On/Off ?",255 82 | msg_define: defm CC_INK,4,CC_AT,1,7,"Press key for ...",255 83 | 84 | msg_gameover_score: defm CC_INK,7,CC_AT,17,10,"Your score",255 85 | 86 | msg_gameover_newhighscore defm CC_INK,4,CC_AT,21,0,"Congratulations! New high score",255 87 | 88 | msg_newscreen_level defm CC_INK,7,CC_AT,12,12,"Level ",255 89 | 90 | startx defb 0 ; all blocks start at this position 91 | starty defb 15 ; all blocks start at this position 92 | 93 | upsidedownstartx defb 20 ; starting x position if upside down 94 | 95 | nextblockx defb 11 ;x position of the next block space 96 | nextblocky defb 25 ;y position of the next block space 97 | scorex defb 4 ;x position where we write the score 98 | scorey defb 25 ; y position where we write the score 99 | highscorex defb 4 ; x position where we write the high score 100 | highscorey defb 3 ; y position where we write the high score 101 | savedblockx defb 11 ;x position of the saved block space 102 | savedblocky defb 4 ;y position of the saved block space 103 | ghostx defb 0 ;x position of the ghost shape 104 | ghosty defb 15 ;y position of the ghost shape 105 | linesx defb 18 ; x position of where we write the lines completed 106 | linesy defb 25 ; y position of where we write the lines completed 107 | 108 | shootingstarx defb 0 ; x position of the star 109 | shootingstary defb 0 ; y position of the star 110 | 111 | ; holds the row that will be shifted one column left or right 112 | slidingrow defb 0 113 | 114 | ; sliding attempt counter. We try 20 times to find a row to slide, but if not we exit 115 | ; this is to prevent the (unlikely) case of no pieces currently being on the playarea 116 | slidingcounter defb 0 117 | 118 | ; when we slide a row we wrap around the blocks, this holds the value of the wrapped around block 119 | slidingwraparoundcolour defb 0 120 | 121 | ; this is the temp holder for colours used in the sliding floors routine 122 | slidingtempcolour defb 0 123 | 124 | ; This holds the colour of the ghost shape (bright white) 125 | ghostcolour defb 71 126 | 127 | ; this is used for determining whether the ghost is actually showing, for example may not be 128 | ; due to shape being too near the top of the piled blocks 129 | 130 | ghostshowing defb 0 131 | 132 | ; This defines the top line starting position, this is used when erasing the line 133 | ; after a winning line is detected 134 | playareatoplinex defb 0 135 | playareatopliney defb 12 136 | 137 | upsidedownplayareatoplinex defb 21 ; top line when upside down 138 | 139 | plx defb 4 ; player's x coordinate. 140 | ply defb 4 ; player's y coordinate. 141 | 142 | tmpx defb 16 143 | tmpy defb 16 144 | 145 | wallpos defb 3 146 | 147 | 148 | shapedata 149 | defb 15,0 ; shape 1 150 | defb 68,68 151 | defb 15,0 152 | defb 68,68 153 | defb 142,0 ; shape 2 154 | defb 68,192 155 | defb 14,32 156 | defb 200,128 157 | defb 46,0 ;shape 3 158 | defb 196,64 159 | defb 232,0 160 | defb 136,192 161 | defb 204,0 ;shape 4 162 | defb 204,0 163 | defb 204,0 164 | defb 204,0 165 | defb 108,0 ; shape 5 166 | defb 140,64 167 | defb 108,0 168 | defb 140,64 169 | defb 78,0 ; shape 6 170 | defb 76,64 171 | defb 14,64 172 | defb 140,128 173 | defb 198,0 ; shape 7 174 | defb 76,128 175 | defb 198,0 176 | defb 76,128 ; this is the end of the standard blocks 177 | defb 72,0 ;shape 8 178 | defb 132,0 179 | defb 72,0 180 | defb 132,0 181 | defb 200,192 ;shape 9 182 | defb 174,0 183 | defb 196,192 184 | defb 14,160 185 | defb 12,0 ; shape 10 186 | defb 68,0 187 | defb 12,0 188 | defb 68,0 189 | defb 164,0 ; shape 11 190 | defb 132,128 191 | defb 74,0 192 | defb 72,64 193 | defb 78,64 ; shape 12 194 | defb 78,64 195 | defb 78,64 196 | defb 78,64 197 | 198 | 199 | ; this holds the offset for ghost. Basically it is the number of increments you would 200 | ; need to take for a shape to be no longer blocking itself 201 | 202 | ghostoffset 203 | defb 1,4,1,4 204 | defb 2,3,2,3 205 | defb 2,3,2,3 206 | defb 2,2,2,2 207 | defb 2,2,2,2 208 | defb 2,3,2,3 209 | defb 2,2,2,2 210 | defb 1,1,1,1 211 | defb 3,2,3,2 212 | defb 1,2,1,2 213 | defb 1,3,1,3 214 | defb 3,3,3,3 215 | 216 | ; this table helps find the correct ghost offset 217 | 218 | ghostlookuptable defb 0,4,8,12,16,20,24,28,32,36,40,44 219 | 220 | ; ghost offset value pointer 221 | 222 | ghostpointer defb 0 223 | 224 | ; this gives the colour of each of the shapes 225 | colourlookuptable defb 5,1,67,6,4,3,2,66,68,69,70,65 226 | 227 | blockshapes defb 142,0 228 | 229 | ; this holds the current shape being shown 230 | currentshape defb 3 231 | 232 | ; this holds the next shape that will be played 233 | nextshape defb 2 234 | 235 | ; this holds the saved shape 236 | savedshape defb 0 237 | 238 | currentorientation defb 0 239 | 240 | blockpointer defb 0 241 | 242 | blocklookuptable defb 0,8,16,24,32,40,48,56,64,72,80,88 243 | 244 | ; this is the number of complete lines required to win each level 245 | linesneededperlevel defb 10,6,6,5,4,8,5,5,4,25 246 | ;linesneededperlevel defb 1,3,4,1,1,1,1,1,1,1 247 | 248 | ; this holds what level the player is currently on 249 | currentlevel defb 1 250 | 251 | ; this holds the total number of lines completed so far this level 252 | totalrowscompleted defb '00' 253 | 254 | ; this holds the total number of lines completed so far this level (as a number) 255 | totalrowscompletednum defb 0 256 | 257 | ; this holds the lines target for this level (as a string) 258 | targetlinesforthislevel defb '00' 259 | 260 | ; this holds the lines target for this level (as a number) 261 | targetlinesforthislevelnum defb 0 262 | 263 | ; this is the colour of the shape currently being played 264 | blockcolour defb 5 265 | 266 | ; this is the colour used by showshape when showing a shape onscreen 267 | drawcolour defb 0 268 | 269 | ; this holds the current number of complete lines we have made this level 270 | completedlines defb 0 271 | 272 | ; this is set to 1 when a winning/complete line is detected 273 | winningline defb 0 274 | 275 | ; when flashing a winning line, or then erasing it, this sets the colour 276 | winninglinecolour defb 130 ; flashing red 277 | 278 | ; holds the score 279 | score defb '000000' 280 | 281 | ; holds the high score 282 | highscore defb '001250' 283 | 284 | ; shows whether a new high score has been set 285 | newhighscore defb 0 286 | 287 | ; this holds whether the level is upside down (i.e. falls up rather than usual down) 288 | upsidedown defb 0 289 | 290 | ; a value of 1 means allowed move 291 | allowedmove defb 1 292 | 293 | ; a player is only allowed swap once (till the next shape is automatically picked) 294 | ; a value of 1 means they are allowed swap, otherwise they are not 295 | allowedswap defb 1 296 | 297 | ; rows completed holds the number of rows filled, bonus points for 4 298 | rowscompleted defb 0 299 | 300 | ; this holds the number of pieces played this level 301 | piecesthislevel defb 0 302 | 303 | ; ghost active. 0 is off, 1 is on. This determines whether the ghost shape is shown 304 | ; The ghost shape shows where the shape would go if the player pressed drop 305 | ghostactive defb 0 306 | 307 | ; this holds whether Kempston joystick support is enabled or not. Can cause 308 | ; issues if activated when, say, emulator is not set to support it. 309 | ; 0 - disabled, 1 - enabled, 2 - not available 310 | 311 | kemsptonactivated defb 0 312 | 313 | ; this holds the difficulty level, 0 is normal, 1 is hard 314 | 315 | difficulty defb 0 316 | 317 | ; this holds the mainmenu option pointer. If joystick is available then this is the option 318 | ; the arrow is pointing at 319 | mainmenuoptionpointer defb 0 320 | 321 | ; this holds the current settings option pointer. If joystick is available then this is the option 322 | ; the arrow is pointing at 323 | settingsmenuoptionpointer defb 0 324 | 325 | ; this holds the mainmenu option chosen. 326 | mainmenuoptionchosen defb 0 327 | 328 | ; this holds the current settings option chosen. 329 | settingsmenuoptionchosen defb 0 330 | 331 | ; this holds the colour of the arrow that points at the menu options 332 | arrowcolour defb 2 333 | 334 | ; this holds the current x position of the arrow 335 | arrowxpos defb 18 336 | 337 | ; timer used when deciding to auto drop the block 338 | pretim defb 0 339 | 340 | ; this holds whether in game music is wanted/enabled (by the player) 341 | gamemusicenabled defb 1 342 | 343 | ; drop method. When set to 0 if the player presses drop then the piece drops in one go as 344 | ; far as it can. If set to 1 then the piece only goes down while the player holds the key 345 | ; when set to 1 acts like a 'down' key rather than a drop 346 | ; when set to 2, it acts like a mixture. A quick tap causes the piece to drop down fully, 347 | ; while holding it down causes it to act like a 'down' key. 348 | dropmethod defb 0 349 | 350 | ; this is used when the dropmethod is set to 2, used in the case when we want to say drop full 351 | fulldropactive defb 0 352 | 353 | ; as we support key repeat, this is used to show when it is the first call of the key within a 354 | ; possible repeat series. Holds the number of repeated key presses 355 | keypresscount defb 0 356 | 357 | ; this holds the number of repeated joystick fire button presses 358 | firebuttoncount defb 0 359 | 360 | ; this holds the key press sensitivity, essentially this is the delay between keypress repeat 361 | ; 0 is fast, 1 is normal, 2 is slow 362 | sensitivity defb 1 363 | 364 | randomtable: 365 | db 82,97,120,111,102,116,20,12 366 | 367 | ; holds a value for last action/key pressed. 368 | ; a bit is set corresponding to the action done 369 | lastkeypressed defb 0 370 | 371 | ; holds a value for last joystick action done 372 | ; a bit is set corresponding to the action done 373 | lastjoystick defb 0 374 | 375 | 376 | ;; this mask determines if simultaneous key presses are allowed. Set to 255 to allow 377 | keypressmask defb 0 378 | 379 | msg_menu_copyright: defm CC_INK,7,CC_AT,13,4,"(c)2015 Peter McQuillan",255 380 | msg_menu_startgame: defm CC_INK,7,CC_AT,18,4,"1 Start Game",255 381 | msg_menu_definekeys: defm CC_INK,7,CC_AT,19,4,"2 Define Keys",255 382 | msg_menu_kempston: defm CC_INK,7,CC_AT,20,4,"3 Kempston Joystick",255 383 | msg_menu_settings: defm CC_INK,7,CC_AT,21,4,"4 Settings",255 384 | msg_menu_kempston_on: defm CC_INK,4,CC_AT,20,23,"(On) ",255 385 | msg_menu_kempston_off: defm CC_INK,2,CC_AT,20,23,"(Off)",255 386 | msg_menu_kempston_na: defm CC_INK,2,CC_AT,20,23,"(n/a)",255 ; we detect if a kempston joystick is present, if not show this 387 | 388 | ;settings menu text 389 | msg_menu_difficulty: defm CC_INK,7,CC_AT,10,4,"1 Difficulty",255 390 | msg_menu_difficulty_normal: defm CC_INK,4,CC_AT,10,16,"(Normal) ",255 391 | msg_menu_difficulty_hard: defm CC_INK,2,CC_AT,10,16,"(Hard) ",255 392 | msg_menu_dropmethod: defm CC_INK,7,CC_AT,11,4,"2 Drop Method",255 393 | msg_menu_dropmethod_normal: defm CC_INK,4,CC_AT,11,17,"(Full) ",255 394 | msg_menu_dropmethod_likedown: defm CC_INK,2,CC_AT,11,17,"(While Held)",255 395 | msg_menu_dropmethod_mixture: defm CC_INK,6,CC_AT,11,17,"(Mixture) ",255 396 | msg_menu_sensitivity: defm CC_INK,7,CC_AT,12,4,"3 Control Response",255 397 | msg_menu_sensitivity_fast: defm CC_INK,4,CC_AT,12,22,"(Fast) ",255 398 | msg_menu_sensitivity_normal: defm CC_INK,6,CC_AT,12,22,"(Normal)",255 399 | msg_menu_sensitivity_slow: defm CC_INK,2,CC_AT,12,22,"(Slow) ",255 400 | msg_menu_simultaneous: defm CC_INK,7,CC_AT,13,4,"4 Simultaneous Keys",255 401 | msg_menu_simultaneous_off: defm CC_INK,4,CC_AT,13,23,"(Off) ",255 402 | msg_menu_simultaneous_on: defm CC_INK,2,CC_AT,13,23,"(On) ",255 403 | msg_menu_back_to_main_menu: defm CC_INK,7,CC_AT,14,4,"5 Back To Main Menu",255 404 | 405 | msg_game_score: defm CC_INK,7,CC_AT,2,25,"Score",255 406 | msg_game_highscore: defm CC_INK,7,CC_AT,2,3,"High",255 407 | msg_game_nextpiece: defm CC_INK,7,CC_AT,9,25,"Next",255 408 | msg_game_savedpiece: defm CC_INK,7,CC_AT,9,3,"Saved",255 409 | msg_game_line: defm CC_INK,7,CC_AT,16,25,"Lines",255 410 | msg_game_ghost: defm CC_INK,7,CC_AT,16,3,"Ghost",255 411 | 412 | msg_game_ghost_active: defm CC_INK,4,CC_AT,18,2," Active ",255 413 | msg_game_ghost_inactive: defm CC_INK,2,CC_AT,18,2,"Inactive",255 414 | 415 | msg_game_level1: defm CC_INK,7,CC_AT,1,8,"1 - Nice and Easy",255 416 | msg_game_level2: defm CC_INK,7,CC_AT,1,9,"2 - Spice it up ",255 417 | msg_game_level3: defm CC_INK,7,CC_AT,1,10,"3 - G'day Mate",255 418 | msg_game_level4: defm CC_INK,7,CC_AT,1,8,"4 - Shooting Star",255 419 | msg_game_level5: defm CC_INK,7,CC_AT,1,10,"5 - More Stars",255 420 | msg_game_level6: defm CC_INK,7,CC_AT,1,11,"6 - Letter F",255 421 | msg_game_level7: defm CC_INK,7,CC_AT,1,12,"7 - Mirror",255 422 | msg_game_level8: defm CC_INK,7,CC_AT,1,8,"8 - Sliding Floor",255 423 | msg_game_level9: defm CC_INK,7,CC_AT,1,10,"9 - Mix it up",255 424 | msg_game_level10: defm CC_INK,7,CC_AT,1,9,"10 - Rising Fall",255 425 | 426 | ; date for the main falling blocks logo on the main menu page. 254 means end of line, 255 means end of data 427 | 428 | fallingblockslogo 429 | defb 0,0,67,67,67,0,254 430 | defb 0,0,67,0,0,0,0,7,0,0,7,0,0,0,7,0,0,0,7,7,7,0,7,7,0,0,0,7,7,254 431 | defb 0,0,0 ,0,0,0,7,0,3,0,5,0,0,0,7,0,0,0,0,7,0,0,7,0,5,0,7,0,0,254 432 | defb 0,0,7 ,7,0,0,7,3,3,0,5,0,0,0,7,0,0,0,0,7,0,0,7,0,5,0,7,0,2,254 433 | defb 0,0,7 ,0,0,0,7,0,3,0,5,0,0,0,7,0,0,0,0,7,0,0,7,0,5,0,7,0,2,254 434 | defb 0,0,7 ,0,0,0,7,0,7,0,5,7,7,0,7,7,7,0,7,7,7,0,7,0,5,0,0,2,2,254 435 | defb 254 436 | defb 0,0,0,0,7,7,0,0,7,0,0,0,0,7,0,0,0,7,7,0,7,0,7,0,0,7,7,254 437 | defb 0,0,0,0,7,0,7,0,7,0,0,0,7,0,7,0,7,0,0,0,3,0,7,0,7,0,0,254 438 | defb 0,0,0,0,67,7,0,0,7,0,0,0,7,0,7,0,7,0,0,0,3,3,0,0,0,7,0,254 439 | defb 0,0,0,0,67,0,7,0,2,0,0,0,7,0,7,0,7,0,0,0,3,0,7,0,0,0,7,254 440 | defb 0,0,0,0,67,67,0,0,2,2,2,0,0,7,0,0,0,7,7,0,7,0,7,0,7,7,0,254 441 | defb 255 442 | 443 | gameoverlogo 444 | defb 254,254,254 ;skip a few lines 445 | defb 0,0,0,0,0,0,0,0,7,7,0,0,7,0,0,7,0,0,0,7,0,7,7,7,254 446 | defb 0,0,0,0,0,0,0,7,0,0,0,7,0,7,0,7,7,0,7,7,0,7,0,0,254 447 | defb 0,0,0,0,0,0,0,7,0,7,0,7,7,7,0,7,0,7,0,7,0,7,7,0,254 448 | defb 0,0,0,0,0,0,0,7,0,7,0,7,0,7,0,7,0,0,0,7,0,7,0,0,254 449 | defb 0,0,0,0,0,0,0,0,7,7,0,7,0,7,0,7,0,0,0,7,0,7,7,7,254 450 | defb 254 451 | defb 0,0,0,0,0,0,0,0,0,7,0,0,7,0,7,0,7,7,7,0,7,7,0,254 452 | defb 0,0,0,0,0,0,0,0,7,0,7,0,7,0,7,0,7,0,0,0,7,0,7,254 453 | defb 0,0,0,0,0,0,0,0,7,0,7,0,7,0,7,0,7,7,0,0,7,7,0,254 454 | defb 0,0,0,0,0,0,0,0,7,0,7,0,0,7,0,0,7,0,0,0,7,0,7,254 455 | defb 0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,7,7,7,0,7,0,7,254 456 | defb 255 457 | 458 | youwinlogo 459 | defb 254,254,254 460 | defb 0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,7,0,0,7,0,7,254 461 | defb 0,0,0,0,0,0,0,0,0,0,7,0,7,0,7,0,7,0,7,0,7,254 462 | defb 0,0,0,0,0,0,0,0,0,0,0,7,0,0,7,0,7,0,7,0,7,254 463 | defb 0,0,0,0,0,0,0,0,0,0,0,7,0,0,7,0,7,0,7,0,7,254 464 | defb 0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,7,0,254 465 | defb 254 466 | defb 0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,7,0,7,7,0,254 467 | defb 0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,7,0,0,7,0,7,254 468 | defb 0,0,0,0,0,0,0,0,0,7,0,7,0,7,0,0,7,0,0,7,0,7,254 469 | defb 0,0,0,0,0,0,0,0,0,7,7,0,7,7,0,0,7,0,0,7,0,7,254 470 | defb 0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,7,7,7,0,7,0,7,254 471 | defb 255 472 | 473 | START 474 | ; Set up the graphics. 475 | 476 | ld de,(23675) ; address of user-defined graphics data. 477 | ld hl, graphics 478 | ld bc,88 479 | ldir 480 | 481 | BEGIN 482 | xor a ; black ink (0) on black paper (0*8). 483 | ld (23693),a ; set our screen colours. 484 | call 3503 ; clear the screen. 485 | ; We also want to change the border colour 486 | xor a ; 0 is the code for black. 487 | call 8859 ; set border colour. 488 | 489 | ;open the upper screen for printing (channel 2) 490 | ld a,2 491 | call 5633 492 | 493 | ; set the main menu music to be 'If I Were A Rich Man' 494 | ld bc,ifiwerearichman 495 | ld (gamemusic),bc 496 | ld a, 8 497 | ld (musicspeed),a 498 | xor a 499 | ld (noteindex),a ; so music plays at start of song 500 | ld (keypresscount),a ; so we show no keys have been pressed before 501 | ld (firebuttoncount),a ; we reset the counter for the joystick fire button presses 502 | ld (mainmenuoptionpointer),a ; we reset where the arrow points to on main menu 503 | 504 | ld a,18 505 | ld (arrowxpos),a ; start position on screen for the arrow (if kemptson available) 506 | 507 | 508 | ; before we start the main menu we need to see if a kempston joystick is 509 | ; actually there. Otherwise you can have a situation where the user enables 510 | ; kempston support but they don't actually have one and strange things happen 511 | ; during the game :) This is due to floating bus values 512 | halt 513 | in a,(31) ;read kempston joystick port directly after HALT 514 | and 31 515 | 516 | ld b,a ; backup value of a in register b for later usage 517 | and 3 518 | cp 3 ; this is equal to both left and right being active at same time, obviously should not happen with real joystick 519 | jr z, nojoy 520 | ld a,b ; get back that value we saved earlier 521 | and 12 522 | cp 12 ; 12 (8+4) is both up and down, again should not be possible 523 | jr z, nojoy 524 | ; a joystick is available, show arrow 525 | call drawarrow 526 | jr mainmenu ; all good, go to main menu 527 | nojoy 528 | ld a,2 529 | ld (kemsptonactivated),a ; set value to not available 530 | 531 | 532 | mainmenu 533 | 534 | ld hl,fallingblockslogo 535 | call printwordswithblocks 536 | 537 | ld hl,msg_menu_copyright 538 | call print_message 539 | 540 | ld hl,msg_menu_startgame 541 | call print_message 542 | ld hl,msg_menu_definekeys 543 | call print_message 544 | ld hl, msg_menu_kempston 545 | call print_message 546 | 547 | ld hl,msg_menu_settings 548 | call print_message 549 | 550 | mm11 551 | ld a,(kemsptonactivated) 552 | cp 0 553 | jr z,mm6 554 | cp 2 555 | jr z, mm9 556 | ld hl, msg_menu_kempston_on 557 | call print_message 558 | jp mm1 559 | mm6 560 | ld hl, msg_menu_kempston_off 561 | call print_message 562 | jr mm1 563 | mm9 564 | ; kempston is not available 565 | ld hl, msg_menu_kempston_na 566 | call print_message 567 | 568 | mm1 569 | ; if kempston is active, we check for up, down and fire 570 | ld a,(kemsptonactivated) 571 | cp 2 572 | jp z, mmkey1 573 | mmjoy1 574 | ; kempston is available 575 | ld bc,31 576 | in a,(c) 577 | and 31 ; bitmask 5 bits 578 | or 0 579 | jr nz, mmjoy2 580 | jp mmkey1 ; no joystick action 581 | mmjoy2 582 | ld bc,31 583 | in a,(c) ; read input. 584 | and 8 ; check "up" bit. 585 | jr nz,mmjoy3 ; move up. 586 | jr mmjoy4 587 | mmjoy3 588 | ; move arrow up if possible 589 | ; if mainmenuoptionpointer is 0 then cannot move up 590 | ld a,(mainmenuoptionpointer) 591 | or 0 592 | jp z, mmkey1 ; at top option already, jump to key read section as nothing more to do in joystick section 593 | ; possible to move up, so decrement mainmenuoptionpointer and arrowxpos 594 | xor a 595 | ld (arrowcolour),a 596 | call drawarrow ; erase old arrow 597 | 598 | ld hl,mainmenuoptionpointer 599 | dec (hl) 600 | ld hl,arrowxpos 601 | dec (hl) 602 | ld a,2 603 | ld (arrowcolour),a 604 | call drawarrow 605 | call smalldelay 606 | jr mmkey1 ; finished in joystick read section 607 | 608 | mmjoy4 609 | ld bc,31 610 | in a,(c) ; read input. 611 | and 4 ; check "down" bit. 612 | jr nz,mmjoy5 613 | jr mmjoy6 614 | mmjoy5 615 | ; move arrow down if possible 616 | ; if mainmenuoptionpointer is 3 then cannot move down 617 | ld a,(mainmenuoptionpointer) 618 | cp 3 619 | jr z, mmkey1 ; at bottom option already, jump to key read section as nothing more to do in joystick section 620 | ; possible to move down, so increment mainmenuoptionpointer and arrowxpos 621 | xor a 622 | ld (arrowcolour),a 623 | call drawarrow ; erase old arrow 624 | ld hl,mainmenuoptionpointer 625 | inc (hl) 626 | ld hl,arrowxpos 627 | inc (hl) 628 | ld a,2 629 | ld (arrowcolour),a 630 | call drawarrow 631 | call smalldelay 632 | jr mmkey1 ; finished in joystick read section 633 | 634 | mmjoy6 635 | ld bc,31 636 | in a,(c) ; read input. 637 | and 16 ; try the fire bit. 638 | jr nz,mmjoy7 ; fire pressed. 639 | jr mmkey1 640 | mmjoy7 641 | ; fire button pressed 642 | ld a,(mainmenuoptionpointer) 643 | cp 1 644 | jr nz, mmjoy8 645 | ; the key read routine actually sets all the bits to 1 except the key corresponding to key pressed 646 | ld a,29 ; 11101 647 | ld (mainmenuoptionchosen),a 648 | jr mm20 649 | mmjoy8 650 | cp 2 651 | jr nz, mmjoy9 652 | ld a,27 ; 11011 653 | ld (mainmenuoptionchosen),a 654 | jr mm20 655 | mmjoy9 656 | cp 3 657 | jr nz, mmjoy10 658 | ld a,23 ;10111 659 | ld (mainmenuoptionchosen),a 660 | jr mm20 661 | mmjoy10 662 | ; assume it is start game 663 | ld a,30 ;11110 664 | ld (mainmenuoptionchosen),a 665 | jr mm20 666 | mmkey1 667 | ;IN 63486 reads the half row 1 to 5 668 | ld bc,63486 669 | in a,(c) 670 | ld (mainmenuoptionchosen),a 671 | mm20 672 | ld a,(mainmenuoptionchosen) 673 | bit 0,a 674 | jr nz,mm2 675 | 676 | jr mm5 ;1 key pressed, start game 677 | mm2 678 | ld a, (mainmenuoptionchosen) 679 | bit 1,a 680 | jr nz,mm3 681 | call do_the_redefine 682 | jp BEGIN 683 | mm3 684 | ld a, (mainmenuoptionchosen) 685 | bit 2,a 686 | jr nz,mm7 687 | ld a,(kemsptonactivated) 688 | cp 0 689 | jr z,mm8 690 | cp 2 691 | jr z,mm10 692 | ; if here then currently support enabled, so disable 693 | xor a 694 | ld (kemsptonactivated),a 695 | ld hl, msg_menu_kempston_off 696 | call print_message 697 | call mediumdelay 698 | jp mm13 699 | mm8 700 | ; if here then currently support disabled, so enable 701 | ld a,1 702 | ld (kemsptonactivated),a 703 | ld hl, msg_menu_kempston_on 704 | call print_message 705 | call mediumdelay 706 | jr mm13 707 | mm10 708 | ; if we are set to n/a for kempston we ignore '3' keypresses 709 | jr mm13 710 | 711 | mm7 712 | ld a, (mainmenuoptionchosen) 713 | bit 3,a ; check for keypress of number 4 714 | jr nz,mm13 715 | 716 | call settingsmenu 717 | jp BEGIN ; need to reset everything after accessing settings menu 718 | 719 | mm13 720 | jp mm1 721 | mm5 722 | call 3503 723 | jp maingame 724 | 725 | settingsmenu 726 | ; settings menu is where difficulty level can be chosen and where the behaviour of the pieces can be altered 727 | 728 | call ROM_CLS 729 | 730 | xor a 731 | ld (settingsmenuoptionpointer),a ; we reset where the arrow points to on settings menu 732 | 733 | ld a,10 734 | ld (arrowxpos),a ; start position on screen for the arrow on settings menu (if kemptson available) 735 | 736 | ld hl,msg_menu_difficulty 737 | call print_message 738 | 739 | ld a,(difficulty) 740 | cp 0 741 | jr nz,setm1 ; 0 is normal difficulty 742 | 743 | ld hl,msg_menu_difficulty_normal 744 | call print_message 745 | jr setm5 746 | 747 | setm1 748 | ld hl,msg_menu_difficulty_hard 749 | call print_message 750 | 751 | setm5 752 | ld hl,msg_menu_dropmethod 753 | call print_message 754 | 755 | ld a,(dropmethod) 756 | cp 0 757 | jr z,setm20 ; 0 is normal drop method 758 | 759 | cp 1 760 | jr z,setm6; 1 is when acts like a down key 761 | 762 | ; otherwise we assume acting like a mixture 763 | jr setm21 764 | 765 | setm20 766 | ; normal drop method 767 | ld hl,msg_menu_dropmethod_normal 768 | call print_message 769 | jr setm2 770 | 771 | setm6 772 | ; when drop acts like a down key 773 | ld hl,msg_menu_dropmethod_likedown 774 | call print_message 775 | jr setm2 776 | 777 | setm21 778 | ; when drop acts like a mixture, quick tap will drop, otherwise 779 | ; holding the key down will act like a 'down' key 780 | ld hl,msg_menu_dropmethod_mixture 781 | call print_message 782 | 783 | setm2 784 | ld hl,msg_menu_sensitivity 785 | call print_message 786 | 787 | ld a,(sensitivity) 788 | cp 0 789 | jr z,setm10 790 | cp 1 791 | jr z,setm11 792 | cp 2 793 | jr z,setm12 794 | 795 | jr setm13 ; this line should not be called, here just in case! 796 | 797 | setm10 798 | ; sensitivity is 0, fast 799 | ld hl, msg_menu_sensitivity_fast 800 | call print_message 801 | jr setm13 802 | 803 | setm11 804 | ; sensitivity is 1, normal 805 | ld hl, msg_menu_sensitivity_normal 806 | call print_message 807 | jr setm13 808 | 809 | setm12 810 | ; sensitivity is 2, slow 811 | ld hl, msg_menu_sensitivity_slow 812 | call print_message 813 | 814 | setm13 815 | ; print the simultaneous keys message 816 | ld hl, msg_menu_simultaneous 817 | call print_message 818 | 819 | ld a,(keypressmask) 820 | cp 0 821 | jr z,setm30 822 | cp 255 823 | jr z,setm31 824 | 825 | jr setm32 ; this line should not be called, here just in case! 826 | 827 | setm30 828 | ld hl, msg_menu_simultaneous_off 829 | call print_message 830 | jr setm32 831 | 832 | setm31 833 | ld hl, msg_menu_simultaneous_on 834 | call print_message 835 | 836 | setm32 837 | ; print the back to main menu message 838 | ld hl, msg_menu_back_to_main_menu 839 | call print_message 840 | 841 | call mediumdelay 842 | 843 | setm9 844 | ; if kempston is active, we check for up, down and fire 845 | ld a,(kemsptonactivated) 846 | cp 2 847 | jp z, smkey1 848 | call drawarrow 849 | smjoy1 850 | ; kempston is available 851 | ld bc,31 852 | in a,(c) 853 | and 31 ; bitmask 5 bits 854 | or 0 855 | jr nz, smjoy2 856 | jp smkey1 ; no joystick action 857 | smjoy2 858 | ld bc,31 859 | in a,(c) ; read input. 860 | and 8 ; check "up" bit. 861 | jr nz,smjoy3 ; move up. 862 | jr smjoy4 863 | smjoy3 864 | ; move arrow up if possible 865 | ; if settingsmenuoptionpointer is 0 then cannot move up 866 | ld a,(settingsmenuoptionpointer) 867 | or 0 868 | jp z, smkey1 ; at top option already, jump to key read section as nothing more to do in joystick section 869 | ; possible to move up, so decrement settingsmenuoptionpointer and arrowxpos 870 | xor a 871 | ld (arrowcolour),a 872 | call drawarrow ; erase old arrow 873 | 874 | ld hl,settingsmenuoptionpointer 875 | dec (hl) 876 | ld hl, arrowxpos 877 | dec (hl) 878 | ld a,2 879 | ld (arrowcolour),a 880 | call drawarrow 881 | call smalldelay 882 | jr smkey1 ; finished in joystick read section 883 | 884 | smjoy4 885 | ld bc,31 886 | in a,(c) ; read input. 887 | and 4 ; check "down" bit. 888 | jr nz,smjoy5 889 | jr smjoy6 890 | smjoy5 891 | ; move arrow down if possible 892 | ; if settingsmenuoptionpointer is 4 then cannot move down 893 | ld a,(settingsmenuoptionpointer) 894 | cp 4 895 | jr z, smkey1 ; at bottom option already, jump to key read section as nothing more to do in joystick section 896 | ; possible to move down, so increment settingsmenuoptionpointer and arrowxpos 897 | xor a 898 | ld (arrowcolour),a 899 | call drawarrow ; erase old arrow 900 | 901 | ld hl,settingsmenuoptionpointer 902 | inc (hl) 903 | ld hl, arrowxpos 904 | inc (hl) 905 | 906 | ld a,2 907 | ld (arrowcolour),a 908 | call drawarrow 909 | call smalldelay 910 | jr smkey1 ; finished in joystick read section 911 | 912 | smjoy6 913 | ld bc,31 914 | in a,(c) ; read input. 915 | and 16 ; try the fire bit. 916 | jr nz,smjoy7 ; fire pressed. 917 | jr smkey1 918 | smjoy7 919 | ; fire button pressed 920 | ld a,(settingsmenuoptionpointer) 921 | cp 1 922 | jr nz, smjoy8 923 | ; the key read routine actually sets all the bits to 1 except the key corresponding to key pressed 924 | ld a,29 ; 11101 925 | ld (settingsmenuoptionchosen),a 926 | jr setm24 927 | smjoy8 928 | cp 2 929 | jr nz, smjoy9 930 | ld a,27 ; 11011 931 | ld (settingsmenuoptionchosen),a 932 | jr setm24 933 | smjoy9 934 | cp 3 935 | jr nz, smjoy10 936 | ld a,23 ;10111 937 | ld (settingsmenuoptionchosen),a 938 | jr setm24 939 | smjoy10 940 | cp 4 941 | jr nz, smjoy11 942 | ld a,15 ;01111 943 | ld (settingsmenuoptionchosen),a 944 | jr setm24 945 | smjoy11 946 | ; assume it is difficulty 947 | ld a,30 ;11110 948 | ld (settingsmenuoptionchosen),a 949 | jr setm24 950 | smkey1 951 | 952 | ;IN 63486 reads the half row 1 to 5 953 | ld bc,63486 954 | in a,(c) 955 | ld (settingsmenuoptionchosen), a 956 | 957 | setm24 958 | ld a, (settingsmenuoptionchosen) 959 | bit 0,a ; check for keypress of number 1 - difficulty 960 | jr nz,setm4 961 | 962 | ld a,(difficulty) 963 | cp 0 964 | jr nz,setm3 965 | 966 | ; difficulty is currently 0 (normal), set to 1 967 | ld a,1 968 | ld (difficulty),a 969 | ld hl,msg_menu_difficulty_hard 970 | call print_message 971 | call mediumdelay 972 | jp setm19 973 | setm3 974 | ; difficulty is currently 1 (hard), set to 0 975 | xor a 976 | ld (difficulty),a 977 | ld hl,msg_menu_difficulty_normal 978 | call print_message 979 | call mediumdelay 980 | jp setm19 981 | 982 | setm4 983 | ld a, (settingsmenuoptionchosen) 984 | bit 1,a ; check for keypress of number 2 - drop method 985 | jr nz,setm7 986 | 987 | ld a,(dropmethod) 988 | cp 1 989 | jr z,setm8 ; currently acts like down key 990 | 991 | cp 2 992 | jr z,setm23 993 | 994 | setm22 995 | ; drop method is currently 0 (normal), set to 1 996 | ld a,1 997 | ld (dropmethod),a 998 | ld hl,msg_menu_dropmethod_likedown 999 | call print_message 1000 | call mediumdelay 1001 | jp setm19 1002 | setm8 1003 | ; drop method is currently 1 (like down key), set to 2 1004 | ld a,2 1005 | ld (dropmethod),a 1006 | ld hl,msg_menu_dropmethod_mixture 1007 | call print_message 1008 | call mediumdelay 1009 | jp setm19 1010 | setm23 1011 | ; drop method is currently 2 (mixture), set to 0 1012 | xor a 1013 | ld (dropmethod),a 1014 | ld hl,msg_menu_dropmethod_normal 1015 | call print_message 1016 | call mediumdelay 1017 | jp setm19 1018 | 1019 | setm7 1020 | ld a, (settingsmenuoptionchosen) 1021 | bit 2,a ; check for keypress of number 3 - key sensitivity 1022 | jr nz,setm18 1023 | 1024 | ld a,(sensitivity) 1025 | cp 0 1026 | jr z, setm14 1027 | cp 1 1028 | jr z, setm15 1029 | cp 2 1030 | jr z, setm16 1031 | 1032 | jr setm19 ; this line should not be called 1033 | 1034 | setm14 1035 | ; sensitivity is 0, set to 1 1036 | ld a,1 1037 | ld (sensitivity),a 1038 | ld hl, msg_menu_sensitivity_normal 1039 | call print_message 1040 | call mediumdelay 1041 | jr setm19 1042 | 1043 | setm15 1044 | ; sensitivity is 1, set to 2 1045 | ld a,2 1046 | ld (sensitivity),a 1047 | ld hl, msg_menu_sensitivity_slow 1048 | call print_message 1049 | call mediumdelay 1050 | jr setm19 1051 | 1052 | setm16 1053 | ; sensitivity is 2, set to 0 1054 | xor a 1055 | ld (sensitivity),a 1056 | ld hl, msg_menu_sensitivity_fast 1057 | call print_message 1058 | call mediumdelay 1059 | jr setm19 1060 | 1061 | setm18 1062 | ld a, (settingsmenuoptionchosen) 1063 | bit 4,a ; check for keypress of number 5 - back to main menu 1064 | jr nz,setm33 1065 | 1066 | ret ; back to main menu 1067 | 1068 | setm33 1069 | ld a, (settingsmenuoptionchosen) 1070 | bit 3,a ; check for keypress of number 4 - simultaneous keypress 1071 | jr nz,setm19 1072 | 1073 | ld a,(keypressmask) 1074 | cp 0 1075 | jr z, setm34 1076 | cp 255 1077 | jr z, setm35 1078 | 1079 | jr setm19 ; this line should not be called 1080 | 1081 | setm34 1082 | ; keypressmask is 0, set to 255 1083 | ld a,255 1084 | ld (keypressmask),a 1085 | ld hl, msg_menu_simultaneous_on 1086 | call print_message 1087 | call mediumdelay 1088 | jr setm19 1089 | 1090 | setm35 1091 | ; keypressmask is 255, set to 0 1092 | xor a 1093 | ld (keypressmask),a 1094 | ld hl, msg_menu_simultaneous_off 1095 | call print_message 1096 | call mediumdelay 1097 | jr setm19 1098 | 1099 | setm19 1100 | jp setm2 1101 | 1102 | maingame 1103 | 1104 | ;seed our random number generator 1105 | 1106 | ld a,(23672) 1107 | and 63 1108 | ld b,a 1109 | seedgen 1110 | push bc ; have to push bc to stack as rnd changes value 1111 | call rnd 1112 | pop bc 1113 | djnz seedgen 1114 | 1115 | ; Need to reset the score 1116 | ld hl,score 1117 | ld (hl),'0' 1118 | inc hl 1119 | ld (hl),'0' 1120 | inc hl 1121 | ld (hl),'0' 1122 | inc hl 1123 | ld (hl),'0' 1124 | inc hl 1125 | ld (hl),'0' 1126 | inc hl 1127 | ld (hl),'0' 1128 | 1129 | ; ghost is set to off 1130 | xor a 1131 | ld (ghostactive),a 1132 | 1133 | ; set the current level to 1 (starting) 1134 | ld a,1 1135 | ld (currentlevel),a 1136 | 1137 | ; reset the saved shape to 0 (long bar) 1138 | xor a 1139 | ld (savedshape),a 1140 | 1141 | ; lets draw the screen 1142 | call newlevel 1143 | 1144 | 1145 | ; main game loop 1146 | L7 1147 | 1148 | ;check key pressed 1149 | call get_keys 1150 | ;The bits in A after checking keys are as follows: A = mlracdgs 1151 | 1152 | main1 1153 | cp 0 1154 | jr z,nokeypressed 1155 | jr main2 1156 | nokeypressed 1157 | call droppieceiftappedkeyboard 1158 | xor a 1159 | ld (keypresscount),a 1160 | ld (lastkeypressed),a 1161 | jp joycon ;no key has been pressed so jump to joystick check part 1162 | main2 1163 | ;check key for right pressed 1164 | bit 5,a 1165 | jr z,re1 1166 | ; move right if valid move 1167 | push af 1168 | ld a,(lastkeypressed) 1169 | bit 5,a 1170 | jr nz,main5 1171 | call moveright 1172 | ld a,(lastkeypressed) 1173 | set 5,a ; set the 5 bit of lastkeypressed 1174 | ld (lastkeypressed),a 1175 | call smalldelay 1176 | pop af 1177 | ld b,a 1178 | ld a,(keypressmask) 1179 | and b 1180 | jp l1 1181 | main5 1182 | ; if last key was right, we do not move right, but we change last key to 8 1183 | ; effectively this means that right move can be made on next call, so we have 1184 | ; key repeat but at a slower rate 1185 | ld a,(lastkeypressed) 1186 | res 5,a ; reset the 5 bit of lastkeypressed 1187 | ld (lastkeypressed),a 1188 | call smalldelay 1189 | pop af 1190 | ld b,a 1191 | ld a,(keypressmask) 1192 | and b 1193 | jp l1 1194 | re1 1195 | push af ; a is holding the key pressed so save to the stack 1196 | ld a,(lastkeypressed) 1197 | res 5,a ; reset the 5 bit of lastkeypressed 1198 | ld (lastkeypressed),a 1199 | pop af 1200 | l1 1201 | bit 6,a 1202 | jr z,re2 1203 | ; move left if valid move 1204 | push af 1205 | ld a,(lastkeypressed) 1206 | bit 6,a 1207 | jr nz,main6 1208 | call moveleft 1209 | ld a,(lastkeypressed) 1210 | set 6,a ; set the 6 bit of lastkeypressed 1211 | ld (lastkeypressed),a 1212 | call smalldelay 1213 | pop af 1214 | ld b,a 1215 | ld a,(keypressmask) 1216 | and b 1217 | jr l2 1218 | main6 1219 | ld a,(lastkeypressed) 1220 | res 6,a ; reset the 6 bit of lastkeypressed 1221 | ld (lastkeypressed),a 1222 | call smalldelay 1223 | pop af 1224 | ld b,a 1225 | ld a,(keypressmask) 1226 | and b 1227 | jr l2 1228 | re2 1229 | push af ; a is holding the key pressed so save to the stack 1230 | ld a,(lastkeypressed) 1231 | res 6,a ; reset the 6 bit of lastkeypressed 1232 | ld (lastkeypressed),a 1233 | pop af 1234 | l2 1235 | bit 0,a 1236 | jr z,l3 1237 | ; swap shape if valid move 1238 | push af 1239 | call swapshape 1240 | call smalldelay 1241 | pop af 1242 | ld b,a 1243 | ld a,(keypressmask) 1244 | and b 1245 | l3 1246 | bit 1,a 1247 | jr z,re3 1248 | push af 1249 | ld a,(lastkeypressed) 1250 | bit 1,a 1251 | jr nz,main7 1252 | call changeghostsetting 1253 | ld a,(lastkeypressed) 1254 | set 1,a ; set the 1 bit of lastkeypressed 1255 | ld (lastkeypressed),a 1256 | call smalldelay 1257 | pop af 1258 | ld b,a 1259 | ld a,(keypressmask) 1260 | and b 1261 | jr l4 1262 | main7 1263 | pop af 1264 | ld b,a 1265 | ld a,(keypressmask) 1266 | and b 1267 | jr l4 1268 | re3 1269 | push af ; a is holding the key pressed so save to the stack 1270 | ld a,(lastkeypressed) 1271 | res 1,a ; reset the 1 bit of lastkeypressed 1272 | ld (lastkeypressed),a 1273 | pop af 1274 | l4 1275 | bit 3,a 1276 | jr z,l5 1277 | push af 1278 | ld a,(lastkeypressed) 1279 | bit 3,a 1280 | jr nz, main4 ; if the last key pressed was moving clockwise then we don't turn clockwise again 1281 | call moveclockwise 1282 | ld a,(lastkeypressed) 1283 | set 3,a ; set the 3 bit of lastkeypressed 1284 | ld (lastkeypressed),a 1285 | call smalldelay 1286 | pop af 1287 | ld b,a 1288 | ld a,(keypressmask) 1289 | and b 1290 | jr l5 1291 | main4 1292 | ld a,(lastkeypressed) 1293 | res 3,a ; reset the 3 bit of lastkeypressed 1294 | ld (lastkeypressed),a 1295 | call smalldelay 1296 | pop af 1297 | ld b,a 1298 | ld a,(keypressmask) 1299 | and b 1300 | jr l5 1301 | re4 1302 | push af ; a is holding the key pressed so save to the stack 1303 | ld a,(lastkeypressed) 1304 | res 3,a ; reset the 3 bit of lastkeypressed 1305 | ld (lastkeypressed),a 1306 | pop af 1307 | l5 1308 | bit 4,a 1309 | jr z,re5 1310 | push af 1311 | ld a,(lastkeypressed) 1312 | bit 4,a 1313 | jr nz,main3 1314 | call moveanticlockwise 1315 | ld a,(lastkeypressed) 1316 | set 4,a ; set the 4 bit of lastkeypressed 1317 | ld (lastkeypressed),a 1318 | call smalldelay 1319 | pop af 1320 | ld b,a 1321 | ld a,(keypressmask) 1322 | and b 1323 | jr l6 1324 | main3 1325 | ld a,(lastkeypressed) 1326 | res 4,a ; reset the 4 bit of lastkeypressed 1327 | ld (lastkeypressed),a 1328 | call smalldelay 1329 | pop af 1330 | ld b,a 1331 | ld a,(keypressmask) 1332 | and b 1333 | jr l6 1334 | re5 1335 | push af ; a is holding the key pressed so save to the stack 1336 | ld a,(lastkeypressed) 1337 | res 4,a ; reset the 4 bit of lastkeypressed 1338 | ld (lastkeypressed),a 1339 | pop af 1340 | l6 1341 | bit 2,a 1342 | jr z,re6 1343 | push af 1344 | ld a,(keypresscount) 1345 | inc a 1346 | ld (keypresscount),a 1347 | 1348 | ld a,(lastkeypressed) 1349 | bit 2,a 1350 | jr nz,main8 1351 | 1352 | call droppiece 1353 | ld a,(lastkeypressed) 1354 | set 2,a ; set the 2 bit of lastkeypressed 1355 | ld (lastkeypressed),a 1356 | call mediumdelay ; drop unusual in that we do not vary delay 1357 | pop af 1358 | ld b,a 1359 | ld a,(keypressmask) 1360 | and b 1361 | jr main10 ; we skip to the end of the check keyboard key section as the drop key was pressed 1362 | main8 1363 | ; if last key was drop, and our drop method is one square/down we do not drop down on square, 1364 | ; but we reset bit 2 of lastkeypressed 1365 | ; effectively this means that down move can be made on next call, so we have 1366 | ; key repeat but at a slower rate 1367 | 1368 | ld a,(dropmethod) 1369 | cp 0 1370 | jr z,main12 1371 | 1372 | ld a,(lastkeypressed) 1373 | res 2,a ; reset the 2 bit of lastkeypressed 1374 | ld (lastkeypressed),a 1375 | call mediumdelay ; drop unusual in that we do not vary delay 1376 | main12 1377 | pop af 1378 | ld b,a 1379 | ld a,(keypressmask) 1380 | and b 1381 | jr main10 1382 | re6 1383 | push af ; a is holding the key pressed so save to the stack 1384 | ld a,(lastkeypressed) 1385 | res 2,a ; reset the 2 bit of lastkeypressed 1386 | ld (lastkeypressed),a 1387 | pop af 1388 | main10 1389 | bit 7,a 1390 | jr z,joycon 1391 | push af 1392 | ld a,(lastkeypressed) 1393 | bit 7,a 1394 | jr nz,main11 1395 | call switchmusiconoff 1396 | ld a,(lastkeypressed) 1397 | set 7,a ; set the 7 bit of lastkeypressed 1398 | ld (lastkeypressed),a 1399 | call smalldelay 1400 | pop af 1401 | ld b,a 1402 | ld a,(keypressmask) 1403 | and b 1404 | jr joycon 1405 | main11 1406 | pop af 1407 | ld b,a 1408 | ld a,(keypressmask) 1409 | and b 1410 | jr joycon 1411 | re7 1412 | push af ; a is holding the key pressed so save to the stack 1413 | ld a,(lastkeypressed) 1414 | res 7,a ; reset the 7 bit of lastkeypressed 1415 | ld (lastkeypressed),a 1416 | pop af 1417 | 1418 | ; in addition to key support, we also support Kempston joystick. On zxspin the emulator uses 1419 | ; the cursor keys with CTRL (for fire) 1420 | joycon 1421 | ld a,(kemsptonactivated) 1422 | cp 2 ; if 2 (n/a) or 0 (deactivated) then skip 1423 | jp z,l9 ; if user has not activated kempston support then we skip this section 1424 | or 0 1425 | jp z,l9 1426 | 1427 | ld bc,31 1428 | in a,(c) 1429 | and 31 ; bitmask 5 bits 1430 | or 0 1431 | jr nz, jc10 1432 | 1433 | call droppieceiftappedjoystick 1434 | xor a 1435 | ld (lastjoystick),a 1436 | ld (firebuttoncount),a 1437 | jp l9 ; no joystick action, so skip ahead 1438 | 1439 | jc10 1440 | ld bc,31 ; Kempston joystick port. 1441 | in a,(c) ; read input. 1442 | and 2 ; check "left" bit. 1443 | jr nz,jc1 ; move left. 1444 | jr jc2 1445 | jc1 1446 | ld a,(lastjoystick) 1447 | bit 2,a 1448 | jr nz,jc11 1449 | call moveleft 1450 | ld a,(lastjoystick) 1451 | set 2,a 1452 | ld (lastjoystick),a 1453 | call smalldelay 1454 | jr jc2 1455 | jc11 1456 | res 2,a 1457 | ld (lastjoystick),a 1458 | call smalldelay 1459 | jc2 1460 | ld bc,31 1461 | in a,(c) ; read input. 1462 | and 1 ; test "right" bit. 1463 | jr nz,jc3 ; move right. 1464 | jr jc4 1465 | jc3 1466 | ld a,(lastjoystick) 1467 | bit 1,a 1468 | jr nz,jc12 1469 | call moveright 1470 | ld a,(lastjoystick) 1471 | set 1,a 1472 | ld (lastjoystick),a 1473 | call smalldelay 1474 | jr jc4 1475 | jc12 1476 | res 1,a 1477 | ld (lastjoystick),a 1478 | call smalldelay 1479 | jc4 1480 | ld bc,31 1481 | in a,(c) ; read input. 1482 | and 8 ; check "up" bit. 1483 | jr nz,jc5 ; move up. 1484 | jr jc6 1485 | jc5 1486 | ld a,(lastjoystick) 1487 | bit 4,a 1488 | jr nz,jc14 1489 | call moveclockwise 1490 | ld a,(lastjoystick) 1491 | set 4,a 1492 | ld (lastjoystick),a 1493 | call smalldelay 1494 | jr jc6 1495 | jc14 1496 | res 4,a 1497 | ld (lastjoystick),a 1498 | call smalldelay 1499 | jc6 1500 | ld bc,31 1501 | in a,(c) ; read input. 1502 | and 4 ; check "down" bit. 1503 | jr nz,jc7 1504 | jr jc8 1505 | jc7 1506 | ld a,(lastjoystick) 1507 | bit 3,a 1508 | jr nz,jc15 1509 | call moveanticlockwise 1510 | ld a,(lastjoystick) 1511 | set 3,a 1512 | ld (lastjoystick),a 1513 | call smalldelay 1514 | jr jc8 1515 | jc15 1516 | res 3,a 1517 | ld (lastjoystick),a 1518 | call smalldelay 1519 | jc8 1520 | ld bc,31 1521 | in a,(c) ; read input. 1522 | and 16 ; try the fire bit. 1523 | jr nz,jc9 ; fire pressed. 1524 | jr l9 1525 | jc9 1526 | ld a,(firebuttoncount) 1527 | inc a 1528 | ld (firebuttoncount),a 1529 | ld a,(lastjoystick) 1530 | bit 5,a 1531 | jr nz,jc13 1532 | call droppiece 1533 | ld a,(lastjoystick) 1534 | set 5,a 1535 | ld (lastjoystick),a 1536 | call mediumdelay ; different (fixed) delay for drop 1537 | jr l9 1538 | jc13 1539 | ld a,(dropmethod) 1540 | cp 0 1541 | jr z,l9 ; we do not repeat keypresses when drop method is full 1542 | ld a,(lastjoystick) 1543 | res 5,a 1544 | ld (lastjoystick),a 1545 | call mediumdelay ; different (fixed) delay for drop 1546 | 1547 | l9 1548 | ld a,(difficulty) 1549 | cp 0 1550 | jr nz,l14 1551 | 1552 | ld hl,pretim ; previous time setting 1553 | ld a,(23672) ; current timer setting. 1554 | sub (hl) ; difference between the two. 1555 | cp 45 ; have 45 frames elapsed yet? 1556 | jr nc,l13 1557 | jr l15 1558 | l14 1559 | ; difficulty hard 1560 | ld hl,pretim ; previous time setting 1561 | ld a,(23672) ; current timer setting. 1562 | sub (hl) ; difference between the two. 1563 | cp 15 ; have 15 frames elapsed yet? 1564 | jr nc,l13 1565 | jr l15 1566 | 1567 | l15 1568 | jp L7 ;not time to drop piece yet, continue main loop 1569 | 1570 | l13 1571 | ld hl,pretim 1572 | ld a,(23672) 1573 | ld (hl),a 1574 | 1575 | call autodroppiece 1576 | 1577 | call checklevelcomplete 1578 | 1579 | jp L7 1580 | 1581 | ; random number generator 1582 | rnd: 1583 | ld hl,randomtable 1584 | rndidx: 1585 | ld bc,0 ; i 1586 | add hl,bc 1587 | ld a,c 1588 | inc a 1589 | and 7 1590 | ld (rndidx+1),a ; i = ( i + 1 ) & 7 1591 | ld c,(hl) ; y = q[i] 1592 | ex de,hl 1593 | ld h,c ; t = 256 * y 1594 | ld l,b 1595 | sbc hl,bc ; t = 255 * y 1596 | sbc hl,bc ; t = 254 * y 1597 | sbc hl,bc ; t = 253 * y 1598 | car: 1599 | ld c,0 ; c 1600 | add hl,bc ; t = 253 * y + c 1601 | ld a,h ; c = t / 256 1602 | ld (car+1),a 1603 | ld a,l ; x = t % 256 1604 | cpl ; x = (b-1) - x = -x - 1 = ~x + 1 - 1 = ~x 1605 | ld (de),a 1606 | ret 1607 | 1608 | 1609 | drawblock 1610 | ld a,22 1611 | rst 16 1612 | ld a,(tmpx) 1613 | rst 16 1614 | ld a,(tmpy) 1615 | rst 16 1616 | ld a,(blockcolour) 1617 | ld (23695),a ; set our temporary screen colours. 1618 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 1619 | rst 16 ; draw player. 1620 | ret 1621 | 1622 | drawarrow 1623 | ld a,22 1624 | rst 16 1625 | ld a,(arrowxpos) 1626 | rst 16 1627 | ld a,3 ; arrow y pos always 3 1628 | rst 16 1629 | ld a,(arrowcolour) ; arrow colour 1630 | ld (23695),a ; set our temporary screen colours. 1631 | ld a,154 ; ASCII code for User Defined Graphic 'K'. 1632 | rst 16 ; draw arrow. 1633 | ret 1634 | 1635 | ;erases the current shape. Same as showcurrentshape except 1636 | ;colour is hardcoded to 0 (black). So, this redraws over the current 1637 | ; shape in black, erasing it 1638 | erasecurrentshape 1639 | ld a,(plx) 1640 | ld (tmpx),a 1641 | ld a,(ply) 1642 | ld (tmpy),a 1643 | xor a 1644 | ld (drawcolour),a 1645 | 1646 | jp showshape 1647 | 1648 | 1649 | ; shows the current shape 1650 | showcurrentshape 1651 | ld a,(plx) 1652 | ld (tmpx),a 1653 | ld a,(ply) 1654 | ld (tmpy),a 1655 | ld a,(blockcolour) 1656 | ld (drawcolour),a 1657 | 1658 | jp showshape 1659 | 1660 | ; this draws the ghost shape. It only draws if ghost is active 1661 | ; and if calculateghostposition determines it is possible/safe to draw 1662 | showghostshape 1663 | ld a,(ghostactive) 1664 | or a 1665 | ret z ; if equal to 0 (ghost not active) then return 1666 | 1667 | sgs1 1668 | call calculateghostposition 1669 | ; now determine if possible to show ghost 1670 | ld a,(ghostshowing) 1671 | or a 1672 | ret z ; return if not possible to show ghost 1673 | ld a,(ghostx) 1674 | ld (tmpx),a 1675 | ld a,(ghosty) 1676 | ld (tmpy),a 1677 | ld a,(ghostcolour) 1678 | ld (drawcolour),a 1679 | 1680 | jp showshape 1681 | 1682 | ; this erases the ghost shape. It checks ghostshowing and if set to 1 1683 | ; it erases it. Does not bother checking ghostactive as that is only relevant 1684 | ; when drawing the ghost 1685 | 1686 | eraseghostshape 1687 | ld a,(ghostshowing) 1688 | or a 1689 | ret z ; return ias ghost not currently showing 1690 | 1691 | ld a,(ghostx) 1692 | ld (tmpx),a 1693 | ld a,(ghosty) 1694 | ld (tmpy),a 1695 | xor a 1696 | ld (drawcolour),a 1697 | 1698 | xor a 1699 | ld (ghostshowing),a ; we set to not showing as should only be set by calculateghostposition 1700 | 1701 | jp showshape 1702 | 1703 | 1704 | ; showshape draws a shape on screen, it is passed a tmpx and tmpy 1705 | ; The colour used is passed in as drawcolour 1706 | ; It draws the shape pointed to in blockshapes 1707 | 1708 | showshape 1709 | 1710 | ld a,(tmpx) ; instead of referring to tmpx and tmpy through this routine, we copy the values to d and e registers and use those 1711 | ld d,a 1712 | ld a,(tmpy) 1713 | ld e,a 1714 | 1715 | ld a,(blockshapes) 1716 | 1717 | bit 7,a 1718 | jp z, ss1 1719 | ld b,d 1720 | ld a,(tmpy) 1721 | ld c,a 1722 | call atadd 1723 | ld a,(drawcolour) 1724 | ld (hl),a 1725 | ss1 1726 | inc e 1727 | ld a,(blockshapes) 1728 | bit 6,a 1729 | jp z, ss2 1730 | ld b,d 1731 | ld c,e 1732 | call atadd 1733 | ld a,(drawcolour) 1734 | ld (hl),a 1735 | ss2 1736 | inc e 1737 | ld a,(blockshapes) 1738 | bit 5,a 1739 | jp z, ss3 1740 | ld b,d 1741 | ld c,e 1742 | call atadd 1743 | ld a,(drawcolour) 1744 | ld (hl),a 1745 | ss3 1746 | inc e 1747 | ld a,(blockshapes) 1748 | bit 4,a 1749 | jp z, ss4 1750 | ld b,d 1751 | ld c,e 1752 | call atadd 1753 | ld a,(drawcolour) 1754 | ld (hl),a 1755 | ss4 1756 | inc d 1757 | ld a,(blockshapes) 1758 | bit 0,a 1759 | jp z, ss5 1760 | ld b,d 1761 | ld c,e 1762 | call atadd 1763 | ld a,(drawcolour) 1764 | ld (hl),a 1765 | ss5 1766 | dec e 1767 | ld a,(blockshapes) 1768 | bit 1,a 1769 | jp z, ss6 1770 | ld b,d 1771 | ld c,e 1772 | call atadd 1773 | ld a,(drawcolour) 1774 | ld (hl),a 1775 | ss6 1776 | dec e 1777 | ld a,(blockshapes) 1778 | bit 2,a 1779 | jp z, ss7 1780 | ld b,d 1781 | ld c,e 1782 | call atadd 1783 | ld a,(drawcolour) 1784 | ld (hl),a 1785 | ss7 1786 | dec e 1787 | ld a,(blockshapes) 1788 | bit 3,a 1789 | jp z, ss8 1790 | ld b,d 1791 | ld c,e 1792 | call atadd 1793 | ld a,(drawcolour) 1794 | ld (hl),a 1795 | ss8 1796 | inc d 1797 | ld a,(blockshapes+1) 1798 | bit 7,a 1799 | jp z, ss9 1800 | ld b,d 1801 | ld c,e 1802 | call atadd 1803 | ld a,(drawcolour) 1804 | ld (hl),a 1805 | ss9 1806 | inc e 1807 | ld a,(blockshapes+1) 1808 | bit 6,a 1809 | jp z, ss10 1810 | ld b,d 1811 | ld c,e 1812 | call atadd 1813 | ld a,(drawcolour) 1814 | ld (hl),a 1815 | ss10 1816 | inc e 1817 | ld a,(blockshapes+1) 1818 | bit 5,a 1819 | jp z, ss11 1820 | ld b,d 1821 | ld c,e 1822 | call atadd 1823 | ld a,(drawcolour) 1824 | ld (hl),a 1825 | ss11 1826 | inc e 1827 | ld a,(blockshapes+1) 1828 | bit 4,a 1829 | jp z, ss12 1830 | ld b,d 1831 | ld c,e 1832 | call atadd 1833 | ld a,(drawcolour) 1834 | ld (hl),a 1835 | ss12 1836 | inc d 1837 | ld a,(blockshapes+1) 1838 | bit 0,a 1839 | jp z, ss13 1840 | ld b,d 1841 | ld c,e 1842 | call atadd 1843 | ld a,(drawcolour) 1844 | ld (hl),a 1845 | ss13 1846 | dec e 1847 | ld a,(blockshapes+1) 1848 | bit 1,a 1849 | jp z, ss14 1850 | ld b,d 1851 | ld c,e 1852 | call atadd 1853 | ld a,(drawcolour) 1854 | ld (hl),a 1855 | ss14 1856 | dec e 1857 | ld a,(blockshapes+1) 1858 | bit 2,a 1859 | 1860 | jp z, ss15 1861 | ld b,d 1862 | ld c,e 1863 | call atadd 1864 | ld a,(drawcolour) 1865 | ld (hl),a 1866 | ss15 1867 | dec e 1868 | ld a,(blockshapes+1) 1869 | bit 3,a 1870 | jp z, ss16 1871 | ld b,d 1872 | ld c,e 1873 | call atadd 1874 | ld a,(drawcolour) 1875 | ld (hl),a 1876 | ss16 1877 | ret 1878 | 1879 | ; moves the block right if allowed. First deletes the shape and 1880 | ; then checks the new location 1881 | moveright 1882 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 1883 | call erasecurrentshape 1884 | 1885 | ld a,(plx) 1886 | ld (tmpx),a 1887 | ld a,(ply) 1888 | inc a ; we are trying to move right 1889 | ld (tmpy),a 1890 | 1891 | call checkmove 1892 | ld a,(allowedmove) 1893 | or 0 1894 | jr z,mr1 1895 | ld a,(ply) ; move is valid so increment y 1896 | inc a 1897 | ld (ply),a 1898 | 1899 | 1900 | mr1 1901 | ld hl, colourlookuptable 1902 | ld de,(currentshape) 1903 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 1904 | add hl,de 1905 | ld a,(hl) 1906 | ld (blockcolour),a ; now draw block in new position 1907 | 1908 | call showcurrentshape 1909 | call showghostshape 1910 | 1911 | ret 1912 | 1913 | ; moves the block left if allowed. First deletes the shape and 1914 | ; then checks the new location 1915 | moveleft 1916 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 1917 | call erasecurrentshape 1918 | 1919 | ld a,(plx) 1920 | ld (tmpx),a 1921 | ld a,(ply) 1922 | dec a ; we are trying to move left 1923 | ld (tmpy),a 1924 | 1925 | call checkmove 1926 | ld a,(allowedmove) 1927 | or 0 1928 | jr z,ml1 1929 | ld a,(ply) ; move is valid so decrement y 1930 | dec a 1931 | ld (ply),a 1932 | 1933 | 1934 | ml1 1935 | ld hl, colourlookuptable 1936 | ld de,(currentshape) 1937 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 1938 | add hl,de 1939 | ld a,(hl) 1940 | ld (blockcolour),a ; now draw block in new position 1941 | 1942 | call showcurrentshape 1943 | call showghostshape 1944 | 1945 | ret 1946 | 1947 | ; this drops the piece when in mixture drop mode and drop key has been tapped 1948 | 1949 | droppieceiftappedkeyboard 1950 | ; check dropmethod and lastkeypressed and keypresscount 1951 | ld a,(dropmethod) 1952 | cp 2 1953 | ret nz 1954 | ld a,(lastkeypressed) 1955 | bit 2,a ; drop 1956 | jr dpitk1 1957 | ret 1958 | dpitk1 1959 | ld a,(keypresscount) 1960 | cp 1 1961 | jr z,dpitk2 1962 | ret 1963 | dpitk2 1964 | ld a,1 1965 | ld (fulldropactive),a 1966 | call droppiece 1967 | call smalldelay 1968 | 1969 | ret 1970 | 1971 | droppieceiftappedjoystick 1972 | ; check dropmethod and lastjoystick and firebuttoncount 1973 | ld a,(dropmethod) 1974 | cp 2 1975 | ret nz 1976 | ld a,(lastjoystick) 1977 | bit 5,a ; drop 1978 | jr dpitj1 1979 | ret 1980 | dpitj1 1981 | ld a,(firebuttoncount) 1982 | cp 1 1983 | jr z,dpitj2 1984 | ret 1985 | dpitj2 1986 | ld a,1 1987 | ld (fulldropactive),a 1988 | call droppiece 1989 | call smalldelay 1990 | 1991 | ret 1992 | 1993 | 1994 | ;this drops the piece, either by 1 square or till it cannot go any further 1995 | droppiece 1996 | ld a,(dropmethod) 1997 | cp 0 1998 | jr z,droppiecefull 1999 | cp 1 2000 | jr z,droppieceonequare 2001 | ; we are not 0 or 1 so using a mixture - check for fulldropactive 2002 | ld a,(fulldropactive) 2003 | cp 0 2004 | jr z,droppieceonequare 2005 | 2006 | ; if here then using mixture dropmethod and full drop has been requested 2007 | xor a 2008 | ld (fulldropactive),a 2009 | 2010 | jr droppiecefull 2011 | 2012 | 2013 | 2014 | ; moves the block down one square if allowed. First deletes the shape and 2015 | ; then checks the new location 2016 | droppieceonequare 2017 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2018 | call erasecurrentshape 2019 | 2020 | ld a,(upsidedown) 2021 | cp 1 2022 | jr z,dpo2 2023 | 2024 | ld a,(plx) 2025 | inc a ; going down one square 2026 | ld (tmpx),a 2027 | jr dpo3 2028 | dpo2 2029 | ld a,(plx) 2030 | dec a ; going up one square (we are upside down) 2031 | ld (tmpx),a 2032 | 2033 | dpo3 2034 | ld a,(ply) 2035 | ld (tmpy),a 2036 | 2037 | call checkmove 2038 | ld a,(allowedmove) 2039 | or 0 2040 | jr z,dpo1 2041 | 2042 | ld a,(upsidedown) 2043 | cp 1 2044 | jr z,dpo4 2045 | 2046 | ld a,(plx) ; move is valid so increment x 2047 | inc a 2048 | ld (plx),a 2049 | jr dpo1 2050 | 2051 | dpo4 2052 | ld a,(plx) ; move is valid so decrement x (as upside down) 2053 | dec a 2054 | ld (plx),a 2055 | 2056 | dpo1 2057 | ld hl, colourlookuptable 2058 | ld de,(currentshape) 2059 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2060 | add hl,de 2061 | ld a,(hl) 2062 | ld (blockcolour),a ; now draw block in new position 2063 | 2064 | call showcurrentshape 2065 | call showghostshape 2066 | 2067 | ; reset the automatic drop timing - we do this as otherwise we would get occasional piece dropping 2068 | ; down 2 spaces 2069 | ld hl,pretim 2070 | ld a,(23672) 2071 | ld (hl),a 2072 | 2073 | ret 2074 | 2075 | 2076 | ; drop the piece till it cannot go any further 2077 | ; this is a loop, the exit being when no more moves are available, when dp1 is 2078 | ; called which exits 2079 | droppiecefull 2080 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2081 | call erasecurrentshape 2082 | 2083 | ld a,(upsidedown) 2084 | cp 1 2085 | jr z,dp4 2086 | 2087 | ld a,(plx) 2088 | inc a ; we are trying to move down 2089 | ld (tmpx),a 2090 | jr dp5 2091 | 2092 | dp4 2093 | ld a,(plx) 2094 | dec a ; we are trying to move up (as upside down) 2095 | ld (tmpx),a 2096 | dp5 2097 | ld a,(ply) 2098 | ld (tmpy),a 2099 | 2100 | call checkmove 2101 | ld a,(allowedmove) 2102 | or 0 2103 | jr z,dp1 2104 | 2105 | ld a,(upsidedown) 2106 | cp 1 2107 | jr z,dp6 2108 | 2109 | ld a,(plx) ; move is valid so increment x 2110 | inc a 2111 | ld (plx),a 2112 | jr dp7 2113 | dp6 2114 | ld a,(plx) ; move is valid so decrement x (as upside down) 2115 | dec a 2116 | ld (plx),a 2117 | 2118 | dp7 2119 | call dp2 2120 | ;delay loop to make the drop seem less sudden, but still a very fast drop 2121 | ld hl, 500 2122 | dp3 2123 | dec hl 2124 | ld a,h 2125 | or l 2126 | jr nz,dp3 2127 | 2128 | ; we get bonus points for dropping, 5 points per square dropped 2129 | ld hl,score+5 ; point to ones column. 2130 | ld b,5 ; 5 ones = 5. 2131 | call uscor ; up the score. 2132 | call printscore ;print this new score 2133 | 2134 | jp droppiecefull 2135 | 2136 | dp1 2137 | call dp2 2138 | ret ; so, if can't make any more moves then we call dp2 and then return 2139 | 2140 | 2141 | dp2 2142 | ld hl, colourlookuptable 2143 | ld de,(currentshape) 2144 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2145 | add hl,de 2146 | ld a,(hl) 2147 | ld (blockcolour),a ; now draw block in new position 2148 | 2149 | call showcurrentshape 2150 | 2151 | ret 2152 | 2153 | ; this is where we calculate the ghost x and y position 2154 | ; we do this by first offsetting till no collision (against the actual current shape) 2155 | ; then dropping down till we hit the top of the already placed pieces 2156 | calculateghostposition 2157 | 2158 | ; copy the player x and y to the tmp x and y 2159 | ld a,(plx) 2160 | ld (tmpx),a 2161 | ld a,(ply) 2162 | ld (tmpy),a 2163 | 2164 | 2165 | ld hl, ghostlookuptable 2166 | ld de,(currentshape) 2167 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2168 | add hl,de 2169 | ld a,(hl) ; this now gives us the offset in the ghost offset table 2170 | ld (ghostpointer),a 2171 | 2172 | ld hl,ghostoffset 2173 | ld de,(ghostpointer) 2174 | ld d,0 2175 | add hl,de 2176 | 2177 | ld de,(currentorientation) 2178 | ld d,0 2179 | add hl,de 2180 | 2181 | ld a,(hl) ; a now holds the number of blocks to skip 2182 | ld d,a ; save value to d 2183 | 2184 | ld a,(upsidedown) 2185 | cp 1 2186 | jr z,cgp5 2187 | 2188 | ld a,(tmpx) 2189 | add a,d 2190 | ld (tmpx),a 2191 | cp 22 2192 | jp nc,cgp2 ; if a greater or equal to 22 we exit 2193 | jr cgp1 2194 | 2195 | cgp5 2196 | ld a,(tmpx) 2197 | sub d 2198 | ld (tmpx),a 2199 | cp 0 2200 | jp c,cgp2 2201 | 2202 | 2203 | cgp1 2204 | ; we have gone the minimum distance required by the ghost offset 2205 | ; we check if there is an immediate collision, if there is, we exit 2206 | 2207 | call checkmove 2208 | ld a,(allowedmove) 2209 | or 0 2210 | jp nz,cgp3 ; if no collision then determine ghost location 2211 | 2212 | 2213 | cgp2 2214 | ; if in here this not possible to determine ghost x and y, set the ghostshowing to 0 2215 | xor a 2216 | ld (ghostshowing),a 2217 | ret 2218 | 2219 | cgp3 2220 | ; if here then found empty space, now keep dropping, this will be where the ghost shape will be shown 2221 | ld a,(upsidedown) 2222 | cp 1 2223 | jr z,cgp6 2224 | 2225 | ld a,(tmpx) 2226 | inc a 2227 | ld (tmpx),a 2228 | jr cgp7 2229 | cgp6 2230 | ld a,(tmpx) 2231 | dec a ; as we are upside down 2232 | ld (tmpx),a 2233 | 2234 | cgp7 2235 | call checkmove 2236 | ld a,(allowedmove) 2237 | or 0 2238 | jp nz,cgp3 2239 | 2240 | cgp4 2241 | ; if we are here then have found the top of the place pieces, allocate ghost x and y 2242 | ld a,(upsidedown) 2243 | cp 1 2244 | jr z,cgp8 2245 | 2246 | ld a,(tmpx) 2247 | dec a ; we decrement one as we had gone one too far with previous loop 2248 | ld (ghostx),a 2249 | jr cgp9 2250 | cgp8 2251 | ld a,(tmpx) 2252 | inc a ; we increment one as we had gone one too far with previous loop 2253 | ld (ghostx),a 2254 | 2255 | cgp9 2256 | ld a,(tmpy) 2257 | ld (ghosty),a 2258 | 2259 | ld a,1 2260 | ld (ghostshowing),a 2261 | 2262 | ret 2263 | 2264 | ; this swaps the ghost setting from active to inactive (and vice versa) 2265 | 2266 | changeghostsetting 2267 | ld a,(ghostactive) 2268 | or 0 2269 | jr nz, cgs1 2270 | 2271 | ; ghost is currently off, switch it on 2272 | ld a,1 2273 | ld (ghostactive),a 2274 | 2275 | ld hl,msg_game_ghost_active 2276 | call print_message 2277 | 2278 | ret 2279 | 2280 | cgs1 2281 | ; ghost is currently on, switch it off 2282 | xor a 2283 | ld (ghostactive),a 2284 | 2285 | ld hl,msg_game_ghost_inactive 2286 | call print_message 2287 | 2288 | ret 2289 | 2290 | 2291 | ; This handles the swap piece functionality. A player is allowed swap once till a new shape is selected automatically 2292 | ; by the drop process. We swap the current piece with the saved shape 2293 | 2294 | swapshape 2295 | ld a,(allowedswap) 2296 | or 0 2297 | jr nz, ssh1 2298 | ret ;not allowed swap 2299 | 2300 | ssh1 2301 | xor a 2302 | ld (allowedswap),a ; stop any more swapping of this shape 2303 | 2304 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2305 | ; erase our current shape 2306 | call erasecurrentshape 2307 | 2308 | ld a,(savedshape) 2309 | push af ; save the shape to the stack 2310 | 2311 | ld a,(currentshape) 2312 | ld (savedshape),a 2313 | 2314 | call drawsavedshape 2315 | 2316 | pop af ; get the saved shape from the stack 2317 | ld (currentshape),a ; now we have swapped shapes 2318 | 2319 | ld a,(startx) ; swapped piece starts from the top of the screen 2320 | ld (plx),a 2321 | ld a,(starty) 2322 | ld (ply),a 2323 | 2324 | ; if we are upside down we need to update the x position 2325 | ld a,(upsidedown) 2326 | cp 1 2327 | jr z,ssh3 2328 | jr ssh4 2329 | ssh3 2330 | ld a,(upsidedownstartx) 2331 | ld (plx),a 2332 | 2333 | ssh4 2334 | ; now we work out the colour for this shape 2335 | 2336 | ld hl, colourlookuptable 2337 | ld de,(currentshape) 2338 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2339 | add hl,de 2340 | ld a,(hl) 2341 | ld (blockcolour),a ; now draw block in new position 2342 | 2343 | ; need to transfer new shape position to tmpx and tmpy for checkmove to correctly work 2344 | ld a,(plx) 2345 | ld (tmpx),a 2346 | ld a,(ply) 2347 | ld (tmpy),a 2348 | 2349 | ; player has swapped, but maybe the piece will not fit at the top of the screen (and thus game over) 2350 | call checkmove 2351 | ld a,(allowedmove) 2352 | or 0 2353 | jr nz,ssh2 2354 | ; move is not valid so its end game 2355 | pop af ; this is popping to ensure stack is back to correct status. This pop is to match the push that is done in the main loop 2356 | jp gameover 2357 | 2358 | ssh2 2359 | ; ok, so we can draw the shape ok 2360 | call setblockshapes 2361 | call showcurrentshape 2362 | call showghostshape 2363 | 2364 | ret 2365 | 2366 | ; This drops the piece down by one square if possible, if not possible then it starts a new piece 2367 | autodroppiece 2368 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2369 | call erasecurrentshape 2370 | 2371 | ld a,(upsidedown) 2372 | cp 1 2373 | jr z, adp3 2374 | ld a,(plx) 2375 | inc a ; we are trying to move down 2376 | ld (tmpx),a 2377 | jr adp4 2378 | 2379 | adp3 2380 | ; this is the section called if upside down 2381 | ld a,(plx) 2382 | dec a ; we are trying to move up (as we are upside down) 2383 | ld (tmpx),a 2384 | adp4 2385 | ld a,(ply) 2386 | ld (tmpy),a 2387 | 2388 | call checkmove 2389 | ld a,(allowedmove) 2390 | or 0 2391 | jr z,adp1 2392 | 2393 | ld a,(upsidedown) 2394 | cp 1 2395 | jr z,adp5 2396 | 2397 | ld a,(plx) ; move is valid so increment x 2398 | inc a 2399 | ld (plx),a 2400 | jr adp2 2401 | 2402 | adp5 2403 | ld a,(plx) ; move is valid so decrement x (as upside down) 2404 | dec a 2405 | ld (plx),a 2406 | jr adp2 2407 | 2408 | 2409 | adp1 2410 | ; if we are here then it was not possible to drop the block, choose a new block 2411 | ; first we redraw back the piece then choose our new one 2412 | ; we also add to the score 2413 | ; Add 50 to the score. 2414 | 2415 | ld hl,score+4 ; point to tens column. 2416 | ld b,5 ; 5 tens = 50. 2417 | call uscor ; up the score. 2418 | call printscore ;print this new score 2419 | 2420 | ld hl, colourlookuptable 2421 | ld de,(currentshape) 2422 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2423 | add hl,de 2424 | ld a,(hl) 2425 | ld (blockcolour),a ; now draw block in new position 2426 | 2427 | call showcurrentshape 2428 | 2429 | call checkplayarea ; now see if a winning line (or lines) exists 2430 | 2431 | call selectnewpiece 2432 | 2433 | adp2 2434 | ld hl, colourlookuptable 2435 | ld de,(currentshape) 2436 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2437 | add hl,de 2438 | ld a,(hl) 2439 | 2440 | ld (blockcolour),a ; now draw block in new position 2441 | 2442 | call showcurrentshape 2443 | call showghostshape 2444 | ;call autodropnoise 2445 | 2446 | ret 2447 | 2448 | 2449 | 2450 | ; Routine to pick a new block. Holds this in next shape and makes currentshape the old value of nextshape 2451 | ; levels 2,5,7 amd 9 have extra shapes added 2452 | selectnewpiece 2453 | ld a,(nextshape) 2454 | push af ; save the nextshape to the stack, this will become currentshape 2455 | 2456 | ld a,(currentlevel) 2457 | cp 2 2458 | jr z,snp2 2459 | cp 5 2460 | jr z,snp2 2461 | cp 7 2462 | jr z,snp2 2463 | cp 9 2464 | jr z,snp2 2465 | ; if get to here then using the standard set 2466 | 2467 | ;this picks the random numbers when just using standard set 2468 | snp1 2469 | call rnd 2470 | and 7 ;bitmask bits 0, 1 and 2 2471 | cp 7 2472 | jp nc, snp1 2473 | jr snp3 2474 | ; this picks the random numbers when using the extended set 2475 | snp2 2476 | call rnd 2477 | and 15 ;bitmask bits 0, 1, 2 and 3 (7 for standard set) 2478 | cp 12 ; change to 7 for standard set 2479 | jp nc, snp2 2480 | 2481 | snp3 2482 | 2483 | ld (nextshape),a 2484 | 2485 | call drawnextshape 2486 | 2487 | pop af 2488 | ld (currentshape),a ; now retrieve from the stack 2489 | 2490 | ld a,(startx) 2491 | ld (plx),a 2492 | ld a,(starty) 2493 | ld (ply),a 2494 | 2495 | ; if upside down we need to update the starting x position 2496 | ld a,(upsidedown) 2497 | cp 1 2498 | jr z,snp5 2499 | jr snp6 2500 | snp5 2501 | ld a,(upsidedownstartx) 2502 | ld (plx),a 2503 | 2504 | snp6 2505 | ; reset allowed swap 2506 | ld a,1 2507 | ld (allowedswap),a 2508 | 2509 | ; reset last key pressed (if the last key pressed was not 'drop') 2510 | ld a,(lastkeypressed) 2511 | cp 7 ;7 is drop 2512 | jr z,snp7 2513 | xor a 2514 | ld (lastkeypressed),a 2515 | 2516 | snp7 2517 | ; now check if end game 2518 | 2519 | ld a,(plx) 2520 | ld (tmpx),a 2521 | ld a,(ply) 2522 | ld (tmpy),a 2523 | call checkmove 2524 | ld a,(allowedmove) 2525 | or 0 2526 | jr nz,snp4 2527 | ; move is not valid so its end game 2528 | jp gameover 2529 | 2530 | snp4 2531 | xor a 2532 | ld (currentorientation),a 2533 | call setblockshapes 2534 | 2535 | ld hl,piecesthislevel 2536 | inc (hl) 2537 | 2538 | jp levelspecialaction; this does the special action required per level (may not do anything) 2539 | 2540 | ; Moves the block anti clockwise if allowed 2541 | 2542 | moveanticlockwise 2543 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2544 | call erasecurrentshape 2545 | 2546 | ld a,(currentorientation) 2547 | inc a 2548 | cp 4 ;if 4 then need to set to 0 2549 | jr nz, mac1 2550 | xor a 2551 | mac1 2552 | ld (currentorientation),a 2553 | 2554 | call setblockshapes 2555 | 2556 | ld a,(plx) 2557 | ld (tmpx),a 2558 | ld a,(ply) 2559 | ld (tmpy),a 2560 | 2561 | 2562 | call checkmove 2563 | ld a,(allowedmove) 2564 | or 0 2565 | jr nz,mac6 2566 | ; move is not valid so need to reset blockpointer and blockshapes 2567 | ld a,(currentorientation) 2568 | or 0 2569 | jr nz, mac5 2570 | ld a,4 ; we set to be 4 as we will decrememt by 1 giving us correct value 3 2571 | mac5 2572 | dec a 2573 | ld (currentorientation),a ;currentorientation not reset to previous value 2574 | 2575 | call setblockshapes 2576 | 2577 | 2578 | mac6 2579 | ld hl, colourlookuptable 2580 | ld de,(currentshape) 2581 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2582 | add hl,de 2583 | ld a,(hl) 2584 | ld (blockcolour),a ; now draw block in new position 2585 | 2586 | call showcurrentshape 2587 | call showghostshape 2588 | 2589 | ret 2590 | 2591 | ; Moves the block clockwise if allowed 2592 | 2593 | moveclockwise 2594 | call eraseghostshape ; always try to erase ghost, if not showing this call will not do anything 2595 | call erasecurrentshape 2596 | 2597 | ld a,(currentorientation) 2598 | or 0 2599 | jr nz,mcw1 2600 | ld a,4 ; we set to be 4 as we will decrememt by 1 giving us correct value 3 2601 | 2602 | mcw1 2603 | dec a 2604 | ld (currentorientation),a 2605 | 2606 | call setblockshapes 2607 | 2608 | ld a,(plx) 2609 | ld (tmpx),a 2610 | ld a,(ply) 2611 | ld (tmpy),a 2612 | 2613 | 2614 | call checkmove 2615 | ld a,(allowedmove) 2616 | or 0 2617 | jr nz,mcw3 ; move is valid 2618 | ; move is not valid so need to reset blockpointer and blockshapes 2619 | ld a,(currentorientation) 2620 | inc a 2621 | cp 4 2622 | jr nz, mcw2 2623 | xor a ; we set to be 4 as we will decrememt by 1 giving us correct value 3 2624 | mcw2 2625 | ld (currentorientation),a ;currentorientation not reset to previous value 2626 | 2627 | call setblockshapes 2628 | 2629 | 2630 | mcw3 2631 | ld hl, colourlookuptable 2632 | ld de,(currentshape) 2633 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2634 | add hl,de 2635 | ld a,(hl) 2636 | ld (blockcolour),a ; now draw block in new position 2637 | 2638 | call showcurrentshape 2639 | call showghostshape 2640 | 2641 | ret 2642 | 2643 | 2644 | ;setblockshapes uses the currentorientation and currentshape to set the 2645 | ; value of blockshapes i.e. the exact block to draw 2646 | setblockshapes 2647 | xor a ;reset a to 0 2648 | ld (blockpointer),a 2649 | 2650 | ld a,(currentshape) 2651 | or 0 2652 | jr z, sbs1 2653 | 2654 | ; each shape is 8 bytes so have to increase by eight for each shape 2655 | ld hl, blocklookuptable 2656 | ld de,(currentshape) 2657 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2658 | add hl,de 2659 | ld a,(hl) 2660 | ld (blockpointer),a 2661 | 2662 | sbs1 2663 | ld a,(currentorientation) 2664 | or 0 2665 | jr z, sbs2 2666 | ld b,a 2667 | sbsloop1 2668 | ld a,(blockpointer) 2669 | inc a 2670 | inc a 2671 | ld (blockpointer),a 2672 | djnz sbsloop1 2673 | 2674 | sbs2 2675 | ld hl, shapedata 2676 | ld de,(blockpointer) 2677 | ld d,0 ;blockpointer is always a 8 bit value 2678 | add hl,de 2679 | ld a,(hl) 2680 | ld (blockshapes),a 2681 | inc hl 2682 | ld a,(hl) 2683 | ld (blockshapes+1),a 2684 | 2685 | ret 2686 | 2687 | ;this draws the next piece that will be played in the right hand side 2688 | ; we temporarily set the current piece to be this 2689 | drawnextshape 2690 | call erasenextshape 2691 | 2692 | ld a,(nextblockx) 2693 | ld (tmpx),a 2694 | ld a,(nextblocky) 2695 | ld (tmpy),a 2696 | xor a 2697 | ld (currentorientation),a 2698 | ld a,(nextshape) 2699 | ld (currentshape),a 2700 | 2701 | ld hl, colourlookuptable 2702 | ld de,(currentshape) 2703 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2704 | add hl,de 2705 | ld a,(hl) 2706 | ld (drawcolour),a 2707 | 2708 | call setblockshapes 2709 | call showshape 2710 | ret 2711 | 2712 | ; This erases the next shape area. There are three lines here to cope with all shapes 2713 | ; in orientation 0 2714 | 2715 | erasenextshape 2716 | ld a,(nextblockx) 2717 | ld (tmpx),a 2718 | ld a,(nextblocky) 2719 | ld (tmpy),a 2720 | 2721 | ld b,4 2722 | ens1 2723 | push bc 2724 | ld a,(tmpx) 2725 | ld b,a 2726 | ld a,(tmpy) 2727 | ld c,a 2728 | call atadd 2729 | ld (hl),0 2730 | ld a,(tmpy) 2731 | inc a 2732 | ld (tmpy),a 2733 | pop bc 2734 | djnz ens1 2735 | 2736 | ld a,(tmpx) 2737 | inc a 2738 | ld (tmpx),a 2739 | ld a,(nextblocky) 2740 | ld (tmpy),a 2741 | 2742 | ld b,4 2743 | ens2 2744 | push bc 2745 | ld a,(tmpx) 2746 | ld b,a 2747 | ld a,(tmpy) 2748 | ld c,a 2749 | call atadd 2750 | ld (hl),0 2751 | ld a,(tmpy) 2752 | inc a 2753 | ld (tmpy),a 2754 | pop bc 2755 | djnz ens2 2756 | 2757 | ld a,(tmpx) 2758 | inc a 2759 | ld (tmpx),a 2760 | ld a,(nextblocky) 2761 | ld (tmpy),a 2762 | 2763 | ld b,4 2764 | ens3 2765 | push bc 2766 | ld a,(tmpx) 2767 | ld b,a 2768 | ld a,(tmpy) 2769 | ld c,a 2770 | call atadd 2771 | ld (hl),0 2772 | ld a,(tmpy) 2773 | inc a 2774 | ld (tmpy),a 2775 | pop bc 2776 | djnz ens3 2777 | 2778 | ret 2779 | 2780 | ; This is the initial setup of the next shape area. 3 lines to handle 2781 | ; all shapes in orientation 0 2782 | 2783 | setupnextshape 2784 | xor a 2785 | ld (blockcolour),a 2786 | ld a,(nextblockx) 2787 | ld (tmpx),a 2788 | ld a,(nextblocky) 2789 | ld (tmpy),a 2790 | 2791 | ld b,4 2792 | sns1 2793 | push bc 2794 | call drawblock 2795 | ld a,(tmpy) 2796 | inc a 2797 | ld (tmpy),a 2798 | pop bc 2799 | djnz sns1 2800 | 2801 | ld a,(tmpx) 2802 | inc a 2803 | ld (tmpx),a 2804 | ld a,(nextblocky) 2805 | ld (tmpy),a 2806 | 2807 | ld b,4 2808 | sns2 2809 | push bc 2810 | call drawblock 2811 | ld a,(tmpy) 2812 | inc a 2813 | ld (tmpy),a 2814 | pop bc 2815 | djnz sns2 2816 | 2817 | ld a,(tmpx) 2818 | inc a 2819 | ld (tmpx),a 2820 | ld a,(nextblocky) 2821 | ld (tmpy),a 2822 | 2823 | ld b,4 2824 | sns3 2825 | push bc 2826 | call drawblock 2827 | ld a,(tmpy) 2828 | inc a 2829 | ld (tmpy),a 2830 | pop bc 2831 | djnz sns3 2832 | 2833 | ret 2834 | 2835 | 2836 | ; This erases the saved shape area 2837 | 2838 | erasesavedshape 2839 | ld a,(savedblockx) 2840 | ld (tmpx),a 2841 | ld a,(savedblocky) 2842 | ld (tmpy),a 2843 | 2844 | ld b,4 2845 | ess1 2846 | push bc 2847 | ld a,(tmpx) 2848 | ld b,a 2849 | ld a,(tmpy) 2850 | ld c,a 2851 | call atadd 2852 | ld (hl),0 2853 | ld a,(tmpy) 2854 | inc a 2855 | ld (tmpy),a 2856 | pop bc 2857 | djnz ess1 2858 | 2859 | ld a,(tmpx) 2860 | inc a 2861 | ld (tmpx),a 2862 | ld a,(savedblocky) 2863 | ld (tmpy),a 2864 | 2865 | ld b,4 2866 | ess2 2867 | push bc 2868 | ld a,(tmpx) 2869 | ld b,a 2870 | ld a,(tmpy) 2871 | ld c,a 2872 | call atadd 2873 | ld (hl),0 2874 | ld a,(tmpy) 2875 | inc a 2876 | ld (tmpy),a 2877 | pop bc 2878 | djnz ess2 2879 | 2880 | ld a,(tmpx) 2881 | inc a 2882 | ld (tmpx),a 2883 | ld a,(savedblocky) 2884 | ld (tmpy),a 2885 | 2886 | ld b,4 2887 | ess3 2888 | push bc 2889 | ld a,(tmpx) 2890 | ld b,a 2891 | ld a,(tmpy) 2892 | ld c,a 2893 | call atadd 2894 | ld (hl),0 2895 | ld a,(tmpy) 2896 | inc a 2897 | ld (tmpy),a 2898 | pop bc 2899 | djnz ess3 2900 | 2901 | ret 2902 | 2903 | ; This is the initial setup of the saved shape area 2904 | 2905 | setupsavedshape 2906 | xor a 2907 | ld (blockcolour),a 2908 | ld a,(savedblockx) 2909 | ld (tmpx),a 2910 | ld a,(savedblocky) 2911 | ld (tmpy),a 2912 | 2913 | ld b,4 2914 | sss1 2915 | push bc 2916 | call drawblock 2917 | ld a,(tmpy) 2918 | inc a 2919 | ld (tmpy),a 2920 | pop bc 2921 | djnz sss1 2922 | 2923 | ld a,(tmpx) 2924 | inc a 2925 | ld (tmpx),a 2926 | ld a,(savedblocky) 2927 | ld (tmpy),a 2928 | 2929 | ld b,4 2930 | sss2 2931 | push bc 2932 | call drawblock 2933 | ld a,(tmpy) 2934 | inc a 2935 | ld (tmpy),a 2936 | pop bc 2937 | djnz sss2 2938 | 2939 | ld a,(tmpx) 2940 | inc a 2941 | ld (tmpx),a 2942 | ld a,(savedblocky) 2943 | ld (tmpy),a 2944 | 2945 | ld b,4 2946 | sss3 2947 | push bc 2948 | call drawblock 2949 | ld a,(tmpy) 2950 | inc a 2951 | ld (tmpy),a 2952 | pop bc 2953 | djnz sss3 2954 | 2955 | ret 2956 | 2957 | ;this draws the saved piece that on the left hand side 2958 | ; we temporarily set the current piece to be this 2959 | drawsavedshape 2960 | call erasesavedshape 2961 | 2962 | ld a,(savedblockx) 2963 | ld (tmpx),a 2964 | ld a,(savedblocky) 2965 | ld (tmpy),a 2966 | xor a 2967 | ld (currentorientation),a 2968 | ld a,(savedshape) 2969 | ld (currentshape),a 2970 | 2971 | ld hl, colourlookuptable 2972 | ld de,(currentshape) 2973 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 2974 | add hl,de 2975 | ld a,(hl) 2976 | ld (drawcolour),a 2977 | 2978 | call setblockshapes 2979 | call showshape 2980 | ret 2981 | 2982 | 2983 | ; this routine is used to erase the top line of the play area. We need this code 2984 | ; as when we move everything down a line after a winning line, we need to clear the top line 2985 | 2986 | erasetopline 2987 | ld a,(upsidedown) 2988 | cp 1 2989 | jp z,etl2 2990 | ld a,(playareatoplinex) 2991 | ld (tmpx),a 2992 | jp eraseline 2993 | etl2 2994 | ld a,(upsidedownplayareatoplinex) ; different x if upside down 2995 | ld (tmpx),a 2996 | jp eraseline 2997 | 2998 | ; eraseline is used for clearing the playarea at the start of every level and is used 2999 | ; during process for handling winning lines. tmpx is passed in (line to erase) 3000 | 3001 | eraseline 3002 | ld a,(playareatopliney) 3003 | ld (tmpy),a 3004 | 3005 | ld b,10 ;10 squares in width of play area 3006 | etl1 3007 | push bc 3008 | ld a,(tmpx) 3009 | ld b,a 3010 | ld a,(tmpy) 3011 | ld c,a 3012 | call atadd 3013 | ld (hl),0 ; set the attribute at this square to be 0, black 3014 | ld a,(tmpy) 3015 | inc a 3016 | ld (tmpy),a 3017 | pop bc 3018 | djnz etl1 3019 | 3020 | ret 3021 | 3022 | ; this routine detects a winning line in the playarea. It checks the line defined in tmpx 3023 | ; winningline will be set to 1 in the case of a winning line, otherwise 0 3024 | 3025 | checkwinningline 3026 | xor a 3027 | ld (winningline),a ; winningline reset to 0 3028 | 3029 | ; tmpx is already set, but set initial y value 3030 | ld a,(playareatopliney) 3031 | ld (tmpy),a 3032 | 3033 | ld b,10 ;10 squares in width of play area 3034 | cwl1 3035 | push bc 3036 | ld a,(tmpx) 3037 | ld b,a 3038 | ld a,(tmpy) 3039 | ld c,a 3040 | call atadd 3041 | or 0 ; check if it black/black i.e. empty square 3042 | jp z, cwl2 ;square is empty, can return with winningline set to 0, not winning line 3043 | 3044 | ld a,(tmpy) 3045 | inc a 3046 | ld (tmpy),a 3047 | pop bc 3048 | djnz cwl1 3049 | 3050 | ; if get this far then winning line 3051 | ld a,1 3052 | ld (winningline),a 3053 | ret 3054 | 3055 | cwl2 3056 | ; not a winning line, but need to tidy the stack, then exit 3057 | pop bc 3058 | ret 3059 | 3060 | 3061 | ; when a winning line is detected, this is the routine that flashes the line, by setting 3062 | ; the attribute of each of the squares with a flash attribute 3063 | ; The line to flash will be passed in using tmpx 3064 | flashwinningline 3065 | ; tmpx is already set, but set initial y value 3066 | ld a,(playareatopliney) 3067 | ld (tmpy),a 3068 | 3069 | ld b,10 ;10 squares in width of play area 3070 | fwl1 3071 | push bc 3072 | ld a,(tmpx) 3073 | ld b,a 3074 | ld a,(tmpy) 3075 | ld c,a 3076 | call atadd 3077 | ld a,(winninglinecolour) 3078 | ld (hl),a ; set the attribute at this square to be winninglinecolour 3079 | 3080 | ld a,(tmpy) 3081 | inc a 3082 | ld (tmpy),a 3083 | pop bc 3084 | djnz fwl1 3085 | 3086 | ret 3087 | 3088 | ; this is the routine that checks the playarea for all winning lines, adding to 3089 | ; the players score, flash the lines temporarily and then deleting them and moving 3090 | ; the playarea down 3091 | checkplayarea 3092 | 3093 | xor a 3094 | ld (rowscompleted),a 3095 | 3096 | ld b,20 3097 | cpa1 3098 | push bc ; b will be modified by later calls 3099 | ld a,b 3100 | ld (tmpx),a 3101 | call checkwinningline 3102 | ld a,(winningline) 3103 | or 0 3104 | jr z,cpa2 ; if not a winning line then skip flashwinningline call 3105 | call flashwinningline 3106 | ld hl,score+4 ; point to tens column. 3107 | ld b,5 ; 5 tens = 50. 3108 | call uscor ; up the score. 3109 | ld hl,score+3 ; point to hundreds column. 3110 | ld b,2 ; 2 hundreds = 200. 3111 | call uscor ; up the score. - so score increased by 250 3112 | call printscore ;print this new score 3113 | ld a,(rowscompleted) 3114 | inc a 3115 | ld (rowscompleted),a 3116 | cp 4 ; bonus points for 4 rows together (+1000 score) 3117 | jr nz, cpa2 3118 | ld hl,score+2 ; point to thousands column. 3119 | ld b,1 ; 1 thousands = 1000. 3120 | call uscor ; up the score. 3121 | call printscore ;print this new score 3122 | 3123 | cpa2 3124 | pop bc 3125 | djnz cpa1 3126 | 3127 | ; now update the lines completed 3128 | 3129 | ld hl,totalrowscompleted+1 ; point to ones column. 3130 | ld a,(rowscompleted) 3131 | ld b,a 3132 | call uscor ; up the lines count 3133 | call printlines ;print this new lines tally 3134 | 3135 | ld a,(rowscompleted) 3136 | ld b,a 3137 | ld a,(totalrowscompletednum) 3138 | add a,b 3139 | ld (totalrowscompletednum),a 3140 | 3141 | ; at this stage we have any winning lines flashing and extra score has been added 3142 | ; if any winning lines need to now remove 3143 | ld a,(rowscompleted) 3144 | or 0 3145 | ret z ; if no rows completed we can exit this routine 3146 | 3147 | ; if there are rows we add a short delay so the player can see the flashing lines i.e. 3148 | ; they can see their winning lines 3149 | ld hl, 50000 3150 | cpa3 3151 | dec hl 3152 | ld a,h 3153 | or l 3154 | jr nz,cpa3 3155 | 3156 | ld a,(upsidedown) 3157 | cp 1 3158 | jr z,cpa6 3159 | 3160 | 3161 | ld b,20 3162 | cpa4 3163 | push bc ; b will be modified by later calls 3164 | ld a,b 3165 | ld (tmpx),a 3166 | call checkwinningline 3167 | ld a,(winningline) 3168 | or 0 3169 | jr z,cpa5 ; if not a winning line then skip eraseline 3170 | call eraseline 3171 | call dropplayarea 3172 | ; we now need to add 1 to b to ensure we delete all winning lines 3173 | pop bc 3174 | inc b 3175 | push bc 3176 | 3177 | cpa5 3178 | pop bc 3179 | djnz cpa4 3180 | call clearedlinenoise 3181 | ret 3182 | 3183 | 3184 | cpa6 3185 | ld b,1 3186 | cpa7 3187 | push bc ; b will be modified by later calls 3188 | ld a,b 3189 | ld (tmpx),a 3190 | call checkwinningline 3191 | ld a,(winningline) 3192 | or 0 3193 | jr z,cpa8 3194 | call eraseline 3195 | call upsidedowndropplayarea 3196 | ; we now need to decrement 1 from b to ensure we delete all winning lines 3197 | pop bc 3198 | dec b 3199 | push bc 3200 | cpa8 3201 | pop bc 3202 | inc b 3203 | ld a,b 3204 | cp 22 3205 | jr z,cpa9 3206 | jp cpa7 3207 | cpa9 3208 | call clearedlinenoise 3209 | ret 3210 | 3211 | 3212 | ; move playarea down. When we get a winning line, we remove the winning line and this routine 3213 | ; drops the playarea above that line down 3214 | ; we pass in tmpx which is the winning line (drop everything above this) 3215 | dropplayarea 3216 | ld a,(playareatopliney) 3217 | ld (tmpy),a 3218 | 3219 | ld a,(tmpx) 3220 | ld b,a 3221 | dpa1 3222 | push bc 3223 | ld b,10 ; inner loop 3224 | dpa2 3225 | push bc 3226 | 3227 | ld a,(tmpx) 3228 | dec a ; we drop by 1 as we are copying the line above 3229 | ld b,a 3230 | 3231 | ld a,(tmpy) 3232 | ld c,a 3233 | call atadd 3234 | ld (blockcolour),a ; this now contains the colour of the square directly above 3235 | ld a,(tmpx) 3236 | ld b,a 3237 | call atadd 3238 | ld a,(blockcolour) 3239 | ld (hl),a 3240 | ld a,(tmpy) ; next square in the row 3241 | inc a 3242 | ld (tmpy),a 3243 | pop bc 3244 | djnz dpa2 3245 | ; finished inner loop, i.e. that row, drop x by 1 and reset y 3246 | 3247 | ld a,(tmpx) 3248 | dec a 3249 | ld (tmpx),a 3250 | ld a,(playareatopliney) 3251 | ld (tmpy),a 3252 | 3253 | pop bc 3254 | djnz dpa1 3255 | 3256 | ; at this stage we have dropped everything, now just need to erase the top line 3257 | 3258 | jp erasetopline 3259 | 3260 | ; move playarea up. When we get a winning line, we remove the winning line and this routine 3261 | ; drops the playarea above that line up (as this is the routine called when upside down) 3262 | ; we pass in tmpx which is the winning line (drop everything below this) 3263 | upsidedowndropplayarea 3264 | ld a,(playareatopliney) 3265 | ld (tmpy),a 3266 | 3267 | ld a,(tmpx) 3268 | uddpa1 3269 | ld b,10 ; inner loop 3270 | uddpa2 3271 | push bc 3272 | 3273 | ld a,(tmpx) 3274 | inc a ; we increase by 1 as we are copying the line below 3275 | ld b,a 3276 | 3277 | ld a,(tmpy) 3278 | ld c,a 3279 | call atadd 3280 | ld (blockcolour),a ; this now contains the colour of the square directly above 3281 | ld a,(tmpx) 3282 | ld b,a 3283 | call atadd 3284 | ld a,(blockcolour) 3285 | ld (hl),a 3286 | ld a,(tmpy) ; next square in the row 3287 | inc a 3288 | ld (tmpy),a 3289 | pop bc 3290 | djnz uddpa2 3291 | ; finished inner loop, i.e. that row, increase x by 1 and reset y 3292 | 3293 | ld a,(tmpx) 3294 | inc a 3295 | ld (tmpx),a 3296 | ld a,(playareatopliney) 3297 | ld (tmpy),a 3298 | 3299 | ld a,(tmpx) 3300 | cp 22 3301 | jr nz, uddpa1 3302 | 3303 | ; at this stage we have dropped everything, now just need to erase the top line 3304 | 3305 | jp erasetopline 3306 | 3307 | ; setupplayarea is used to draw a block (in black so not shown) in each square of the 3308 | ; playarea 3309 | setupplayarea 3310 | 3311 | xor a 3312 | ld (blockcolour),a 3313 | 3314 | ld b,21 3315 | spa1 3316 | push bc ; b will be modified by later calls 3317 | ld a,b 3318 | ld (tmpx),a 3319 | call drawlineofblocks 3320 | pop bc 3321 | djnz spa1 3322 | 3323 | xor a ; now clear the very top line 3324 | ld (tmpx),a 3325 | call drawlineofblocks 3326 | 3327 | ret 3328 | 3329 | ;drawlineofblocks draws a line of blocks 3330 | ; passed in tmpx, line at which to draw 3331 | drawlineofblocks 3332 | ld a,(playareatopliney) 3333 | ld (tmpy),a 3334 | 3335 | ld b,10 ;10 squares in width of play area 3336 | dlb1 3337 | push bc 3338 | call drawblock 3339 | 3340 | ld a,(tmpy) 3341 | inc a 3342 | ld (tmpy),a 3343 | pop bc 3344 | djnz dlb1 3345 | 3346 | ret 3347 | 3348 | ;checkmove. tmpx and tmpy will be set to the desired location 3349 | ;and the current shape will be removed. This checks if there are 3350 | ;any existing blocks at the new location 3351 | 3352 | checkmove 3353 | ld a,1 3354 | ld (allowedmove),a ; default is move allowed 3355 | ld a,(tmpx) ; instead of referring to tmpx and tmpy through this routine, we copy the values to d and e registers and use those 3356 | ld d,a 3357 | ld a,(tmpy) 3358 | ld e,a 3359 | 3360 | ld a,(blockshapes) 3361 | bit 7,a 3362 | jp z, cm1 3363 | ld b,d 3364 | ld c,e 3365 | call atadd 3366 | or 0 ; check if it black/black i.e. empty square 3367 | jp z, cm1 ;square is empty, can move 3368 | xor a 3369 | ld (allowedmove),a ; cannot move 3370 | ret ; exit as cannot move 3371 | cm1 3372 | ld a,(blockshapes) 3373 | bit 6,a 3374 | jp z, cm2 3375 | ld b,d 3376 | ld a,e 3377 | inc a 3378 | ld c,a 3379 | call atadd 3380 | or 0 3381 | jp z, cm2 3382 | xor a 3383 | ld (allowedmove),a ; cannot move 3384 | ret ; exit as cannot move 3385 | cm2 3386 | ld a,(blockshapes) 3387 | bit 5,a 3388 | jp z, cm3 3389 | ld b,d 3390 | ld a,e 3391 | inc a 3392 | inc a 3393 | ld c,a 3394 | call atadd 3395 | or 0 3396 | jp z, cm3 3397 | xor a 3398 | ld (allowedmove),a ; cannot move 3399 | ret ; exit as cannot move 3400 | cm3 3401 | ld a,(blockshapes) 3402 | bit 4,a 3403 | jp z, cm4 3404 | ld b,d 3405 | ld a,e 3406 | inc a 3407 | inc a 3408 | inc a 3409 | ld c,a 3410 | call atadd 3411 | or 0 3412 | jp z, cm4 3413 | xor a 3414 | ld (allowedmove),a ; cannot move 3415 | ret ; exit as cannot move 3416 | cm4 3417 | ld a,(blockshapes) 3418 | bit 3,a 3419 | jp z, cm5 3420 | ld a,d 3421 | inc a 3422 | ld b,a 3423 | ld c,e 3424 | call atadd 3425 | or 0 ; check if it black/black i.e. empty square 3426 | jp z, cm5 3427 | xor a 3428 | ld (allowedmove),a ; cannot move 3429 | ret ; exit as cannot move 3430 | cm5 3431 | ld a,(blockshapes) 3432 | bit 2,a 3433 | jp z, cm6 3434 | ld a,d 3435 | inc a 3436 | ld b,a 3437 | ld a,e 3438 | inc a 3439 | ld c,a 3440 | call atadd 3441 | or 0 3442 | jp z, cm6 3443 | xor a 3444 | ld (allowedmove),a ; cannot move 3445 | ret ; exit as cannot move 3446 | cm6 3447 | ld a,(blockshapes) 3448 | bit 1,a 3449 | jp z, cm7 3450 | ld a,d 3451 | inc a 3452 | ld b,a 3453 | ld a,e 3454 | inc a 3455 | inc a 3456 | ld c,a 3457 | call atadd 3458 | or 0 3459 | jp z, cm7 3460 | xor a 3461 | ld (allowedmove),a ; cannot move 3462 | ret ; exit as cannot move 3463 | cm7 3464 | ld a,(blockshapes) 3465 | bit 0,a 3466 | jp z, cm8 3467 | ld a,d 3468 | inc a 3469 | ld b,a 3470 | ld a,e 3471 | inc a 3472 | inc a 3473 | inc a 3474 | ld c,a 3475 | call atadd 3476 | or 0 3477 | jp z, cm8 3478 | xor a 3479 | ld (allowedmove),a ; cannot move 3480 | ret ; exit as cannot move 3481 | cm8 3482 | ld a,(blockshapes+1) 3483 | bit 7,a 3484 | jp z, cm9 3485 | ld a,d 3486 | inc a 3487 | inc a 3488 | ld b,a 3489 | ld c,e 3490 | call atadd 3491 | or 0 ; check if it black/black i.e. empty square 3492 | jp z, cm9 3493 | xor a 3494 | ld (allowedmove),a ; cannot move 3495 | ret ; exit as cannot move 3496 | cm9 3497 | ld a,(blockshapes+1) 3498 | bit 6,a 3499 | jp z, cm10 3500 | ld a,d 3501 | inc a 3502 | inc a 3503 | ld b,a 3504 | ld a,e 3505 | inc a 3506 | ld c,a 3507 | call atadd 3508 | or 0 3509 | jp z, cm10 3510 | xor a 3511 | ld (allowedmove),a ; cannot move 3512 | ret ; exit as cannot move 3513 | cm10 3514 | ld a,(blockshapes+1) 3515 | bit 5,a 3516 | jp z, cm11 3517 | ld a,d 3518 | inc a 3519 | inc a 3520 | ld b,a 3521 | ld a,e 3522 | inc a 3523 | inc a 3524 | ld c,a 3525 | call atadd 3526 | or 0 3527 | jp z, cm11 3528 | xor a 3529 | ld (allowedmove),a ; cannot move 3530 | ret ; exit as cannot move 3531 | cm11 3532 | ld a,(blockshapes+1) 3533 | bit 4,a 3534 | jp z, cm12 3535 | ld a,d 3536 | inc a 3537 | inc a 3538 | ld b,a 3539 | ld a,e 3540 | inc a 3541 | inc a 3542 | inc a 3543 | ld c,a 3544 | call atadd 3545 | or 0 3546 | jp z, cm12 3547 | xor a 3548 | ld (allowedmove),a ; cannot move 3549 | ret ; exit as cannot move 3550 | cm12 3551 | ld a,(blockshapes+1) 3552 | bit 3,a 3553 | jp z, cm13 3554 | ld a,d 3555 | inc a 3556 | inc a 3557 | inc a 3558 | ld b,a 3559 | ld c,e 3560 | call atadd 3561 | or 0 ; check if it black/black i.e. empty square 3562 | jp z, cm13 3563 | xor a 3564 | ld (allowedmove),a ; cannot move 3565 | ret ; exit as cannot move 3566 | cm13 3567 | ld a,(blockshapes+1) 3568 | bit 2,a 3569 | jp z, cm14 3570 | ld a,d 3571 | inc a 3572 | inc a 3573 | inc a 3574 | ld b,a 3575 | ld a,e 3576 | inc a 3577 | ld c,a 3578 | call atadd 3579 | or 0 3580 | jp z, cm14 3581 | xor a 3582 | ld (allowedmove),a ; cannot move 3583 | ret ; exit as cannot move 3584 | cm14 3585 | ld a,(blockshapes+1) 3586 | bit 1,a 3587 | jp z, cm15 3588 | ld a,d 3589 | inc a 3590 | inc a 3591 | inc a 3592 | ld b,a 3593 | ld a,e 3594 | inc a 3595 | inc a 3596 | ld c,a 3597 | call atadd 3598 | or 0 3599 | jp z, cm15 3600 | xor a 3601 | ld (allowedmove),a ; cannot move 3602 | ret ; exit as cannot move 3603 | cm15 3604 | ld a,(blockshapes+1) 3605 | bit 0,a 3606 | jp z, cmend 3607 | ld a,d 3608 | inc a 3609 | inc a 3610 | inc a 3611 | ld b,a 3612 | ld a,e 3613 | inc a 3614 | inc a 3615 | inc a 3616 | ld c,a 3617 | call atadd 3618 | or 0 3619 | jp z, cmend 3620 | xor a 3621 | ld (allowedmove),a ; cannot move 3622 | ret ; exit as cannot move 3623 | cmend 3624 | ret 3625 | 3626 | 3627 | ; Calculate address of attribute for character at (b, c). 3628 | 3629 | atadd 3630 | ld a,b ; x position. 3631 | rrca ; multiply by 32. 3632 | rrca 3633 | rrca 3634 | ld l,a ; store away in l. 3635 | and 3 ; mask bits for high byte. 3636 | add a,88 ; 88*256=22528, start of attributes. 3637 | ld h,a ; high byte done. 3638 | ld a,l ; get x*32 again. 3639 | and 224 ; mask low byte. 3640 | ld l,a ; put in l. 3641 | ld a,c ; get y displacement. 3642 | add a,l ; add to low byte. 3643 | ld l,a ; hl=address of attributes. 3644 | ld a,(hl) ; return attribute in a. 3645 | ret 3646 | 3647 | ; redefine keys routine written by John Young 3648 | get_keys: 3649 | ld de,0 ; DE will hold the bits for the keys pressed 3650 | ld hl,key_music_port ; address of the ports/patterns 3651 | ld b,8 ; 8 keys to check 3652 | res 0,d 3653 | dec hl 3654 | gk_loop: 3655 | inc hl 3656 | rl d 3657 | ld a,(hl) ; get the port row 3658 | in a,(254) ; check that row 3659 | cpl 3660 | and 31 3661 | inc hl ; point to the key bit pattern 3662 | cp (hl) ; check if that key is pressed 3663 | jr z,gk_key_is_pressed 3664 | ;key is not pressed 3665 | res 0,d ; indicate key not pressed 3666 | djnz gk_loop ; go check next key 3667 | jr gk_exit 3668 | gk_key_is_pressed: 3669 | set 0,d ; indicate key is pressed 3670 | djnz gk_loop ; go check next key 3671 | ; ok, all done, maybe, I hope, ahh pffffffffffffffffft 3672 | gk_exit: 3673 | ld a,d ; return the bit thingy 3674 | ret 3675 | 3676 | 3677 | ; This is where we redefine the keys 3678 | do_the_redefine: 3679 | call ROM_CLS ; do the clear screen 3680 | xor a 3681 | ld hl,msg_define 3682 | call print_message 3683 | 3684 | call mediumdelay 3685 | 3686 | ld hl,msg_left 3687 | call print_message 3688 | ld hl,key_left_port 3689 | call get_defined_key 3690 | 3691 | ld hl,msg_right 3692 | call print_message 3693 | ld hl,key_right_port 3694 | call get_defined_key 3695 | 3696 | ld hl,msg_anticlockwise 3697 | call print_message 3698 | ld hl,key_anticlockwise_port 3699 | call get_defined_key 3700 | 3701 | ld hl,msg_clockwise 3702 | call print_message 3703 | ld hl,key_clockwise_port 3704 | call get_defined_key 3705 | 3706 | ld hl,msg_drop 3707 | call print_message 3708 | ld hl,key_drop_port 3709 | call get_defined_key 3710 | 3711 | ld hl,msg_ghost 3712 | call print_message 3713 | ld hl,key_ghost_port 3714 | call get_defined_key 3715 | 3716 | ld hl,msg_swap 3717 | call print_message 3718 | ld hl,key_swap_port 3719 | call get_defined_key 3720 | 3721 | ld hl,msg_music 3722 | call print_message 3723 | ld hl,key_music_port 3724 | call get_defined_key 3725 | 3726 | ; ok, keys should have been saved, (/me hopes) 3727 | ld bc,key_music_port ; return the keys data to calling program 3728 | ret 3729 | 3730 | ; ---------------------------------------------- 3731 | ; ROUTINE: print_message 3732 | ; 3733 | ; prints a string which is terminated with $ff 3734 | ; On entry, HL = address of message 3735 | print_message: 3736 | push hl ; save the message address 3737 | ld a,2 ; upper screen 3738 | call CHAN_OPEN ; get the channel sorted 3739 | pop hl ; get the message address back 3740 | 3741 | pm_do_it: 3742 | ld a,(hl) ; get the character to print 3743 | inc hl ; point to next character 3744 | cp 255 ; end of the string 3745 | ret z ; so exit 3746 | rst 16 ; print the character 3747 | jr pm_do_it ; and do it all over again 3748 | ret 3749 | 3750 | ; ---------------------------------------------- 3751 | ; ROUTINE: get_defined_key 3752 | ; 3753 | ; check for key being pressed 3754 | ; On entry, HL = key_xxx_port where xxx is the direction, eg up/down/left/right/fire/pause/quit 3755 | ; On exit, the key_xxx_port and key_xxx_pattern will hold the values for the key pressed 3756 | ; 3757 | get_defined_key: 3758 | ld de,port_array ; the array of rows 3759 | ld b,8 ; number of rows to check 3760 | gdk_loop: 3761 | ld a,(de) ; get row 3762 | in a,(254) ; check for keys on that row 3763 | cpl 3764 | and 31 ; mask off the 5 bits I want 3765 | jr z,gdk_none ; nothing pressed? ok, go to next row 3766 | inc hl ; point to the key_xxx_pattern byte 3767 | ld (hl),a ; save the pattern byte 3768 | dec hl ; go back to the key_xxx_port byte 3769 | ld a,(de) ; get the port that the key was found on 3770 | ld (hl),a ; save it 3771 | ; ok, details for the pressed key are saved, lets gtfo here 3772 | call delay 3773 | ret 3774 | gdk_none: 3775 | inc de ; next row in array 3776 | djnz gdk_loop ; go check next row 3777 | ; hmm, no key pressed on keyboard, sooooo do it all again 3778 | jr get_defined_key 3779 | ret ; not executed, but it stops me from getting confused, :) 3780 | 3781 | ; ----------------------------------------------- 3782 | delay: 3783 | ld bc,32768 3784 | xor a 3785 | d_loop: 3786 | dec a 3787 | out (254),a 3788 | dec bc 3789 | ld a,b 3790 | or c 3791 | jr nz,d_loop 3792 | ret 3793 | 3794 | ; Update score routine by Jonathan Cauldwell 3795 | 3796 | uscor 3797 | ld a,(hl) ; current value of digit. 3798 | add a,b ; add points to this digit. 3799 | ld (hl),a ; place new digit back in string. 3800 | cp 58 ; more than ASCII value '9'? 3801 | ret c ; no - relax. 3802 | sub 10 ; subtract 10. 3803 | ld (hl),a ; put new character back in string. 3804 | uscor0 3805 | dec hl ; previous character in string. 3806 | inc (hl) ; up this by one. 3807 | ld a,(hl) ; what's the new value? 3808 | cp 58 ; gone past ASCII nine? 3809 | ret c ; no, scoring done. 3810 | sub 10 ; down by ten. 3811 | ld (hl),a ; put it back 3812 | jr uscor0 ; go round again. 3813 | 3814 | ; Print the score 3815 | printscore 3816 | ld a,CC_INK 3817 | rst 16 3818 | ld a,7 3819 | rst 16 3820 | ld a,CC_AT 3821 | rst 16 3822 | ld a,(scorex) 3823 | rst 16 3824 | ld a,(scorey) 3825 | rst 16 3826 | 3827 | ld hl, score 3828 | ld b,6 3829 | ps1 3830 | ld a,(hl) ; get the character to print 3831 | inc hl ; point to next character 3832 | rst 16 ; print the character 3833 | djnz ps1 ; and do it all over again 3834 | ret 3835 | 3836 | ; Print the high score 3837 | printhighscore 3838 | ld a,CC_INK 3839 | rst 16 3840 | ld a,7 3841 | rst 16 3842 | ld a,CC_AT 3843 | rst 16 3844 | ld a,(highscorex) 3845 | rst 16 3846 | ld a,(highscorey) 3847 | rst 16 3848 | 3849 | ld hl, highscore 3850 | ld b,6 3851 | phs1 3852 | ld a,(hl) ; get the character to print 3853 | inc hl ; point to next character 3854 | rst 16 ; print the character 3855 | djnz phs1 ; and do it all over again 3856 | ret 3857 | 3858 | gameover 3859 | 3860 | ; switch the music to heart and soul 3861 | ld bc,heartandsoul 3862 | ld (gamemusic),bc 3863 | ld a, 11 3864 | ld (musicspeed),a 3865 | xor a 3866 | ld (noteindex),a ; so music plays at start of song 3867 | 3868 | call ROM_CLS ; do the clear screen 3869 | 3870 | ;open the upper screen for printing (channel 2) 3871 | ld a,2 3872 | call 5633 3873 | 3874 | ld hl,gameoverlogo 3875 | call printwordswithblocks 3876 | 3877 | ld hl, msg_gameover_score 3878 | call print_message 3879 | 3880 | ld a,CC_INK 3881 | rst 16 3882 | ld a,7 3883 | rst 16 3884 | ld a,CC_AT 3885 | rst 16 3886 | ld a,19 3887 | rst 16 3888 | ld a,12 3889 | rst 16 3890 | 3891 | ld hl, score 3892 | ld b,6 3893 | go1 3894 | ld a,(hl) ; get the character to print 3895 | inc hl ; point to next character 3896 | rst 16 ; print the character 3897 | djnz go1 ; and do it all over again 3898 | 3899 | call checkhighscore 3900 | 3901 | ld a,(newhighscore) 3902 | cp 0 3903 | jr z,go3 ; if equal to 0, no new high score 3904 | 3905 | ld hl, msg_gameover_newhighscore 3906 | call print_message 3907 | 3908 | go3 3909 | ld b,250 ; time to pause (50 frames a sec, 5 secs wait) 3910 | go2 3911 | halt ; wait for an interrupt. 3912 | djnz go2 ; repeat. 3913 | 3914 | jp BEGIN 3915 | 3916 | ; screen that gets called when you win 3917 | youwin 3918 | ; change music to you win music 3919 | ld bc,youwinmusic 3920 | ld (gamemusic),bc 3921 | ld a, 10 3922 | ld (musicspeed),a 3923 | xor a 3924 | ld (noteindex),a ; so music plays at start of song 3925 | 3926 | call ROM_CLS ; do the clear screen 3927 | 3928 | ;open the upper screen for printing (channel 2) 3929 | ld a,2 3930 | call 5633 3931 | 3932 | ld hl,youwinlogo 3933 | call printwordswithblocks 3934 | 3935 | ld hl, msg_gameover_score 3936 | call print_message 3937 | 3938 | ld a,CC_INK 3939 | rst 16 3940 | ld a,7 3941 | rst 16 3942 | ld a,CC_AT 3943 | rst 16 3944 | ld a,19 3945 | rst 16 3946 | ld a,12 3947 | rst 16 3948 | 3949 | ld hl, score 3950 | ld b,6 3951 | yw1 3952 | ld a,(hl) ; get the character to print 3953 | inc hl ; point to next character 3954 | rst 16 ; print the character 3955 | djnz yw1 ; and do it all over again 3956 | 3957 | call checkhighscore 3958 | 3959 | ld a,(newhighscore) 3960 | cp 0 3961 | jr z,yw3 ; if equal to 0, no new high score 3962 | 3963 | ld hl, msg_gameover_newhighscore 3964 | call print_message 3965 | 3966 | yw3 3967 | ld b,250 ; time to pause (50 frames a sec, 5 secs wait) 3968 | yw2 3969 | halt ; wait for an interrupt. 3970 | djnz yw2 ; repeat. 3971 | 3972 | jp BEGIN 3973 | 3974 | 3975 | ; small delay loop used by main loop 3976 | smalldelay 3977 | ld a,(sensitivity) 3978 | cp 0 3979 | jr z,sd2 3980 | cp 1 3981 | jr z,sd3 3982 | ; else its slow 3983 | ld hl, 17500 3984 | jr sd1 3985 | sd2 3986 | ; fast 3987 | ld hl,5000 3988 | jr sd1 3989 | sd3 3990 | ; normal 3991 | ld hl,12500 3992 | sd1 3993 | jr actualdelay 3994 | 3995 | longdelay 3996 | ld hl, 17500 3997 | jr actualdelay 3998 | 3999 | ; medium delay loop used by main menu loop 4000 | mediumdelay 4001 | ld hl, 12500 4002 | jr actualdelay 4003 | 4004 | ; very small delay loop used by main menu loop 4005 | verysmalldelay 4006 | ld hl, 5000 4007 | jr actualdelay 4008 | 4009 | actualdelay 4010 | dec hl 4011 | ld a,h 4012 | or l 4013 | jr nz,actualdelay 4014 | ret 4015 | 4016 | ; This draws words onscreen using blocks to make up the parts of the letters 4017 | ; Each byte represents a colour for the block to draw 4018 | ; 254 means end of line and 255 means end of data (stop drawing) 4019 | ; hl is passed in, this is the address of the start of the data to print 4020 | printwordswithblocks 4021 | xor a 4022 | ld (tmpx),a 4023 | ld (tmpy),a 4024 | 4025 | pbl1 4026 | ld a,(hl) 4027 | cp 254 4028 | jr z,pbl2 4029 | cp 255 4030 | ret z ; we return from here if a 255 found 4031 | ld (blockcolour),a 4032 | call drawblock 4033 | ld a,(tmpy) 4034 | inc a 4035 | ld (tmpy),a 4036 | inc hl 4037 | jp pbl1 4038 | pbl2 4039 | ; end of line reached, reset y and increment x 4040 | ld a,(tmpx) 4041 | inc a 4042 | ld (tmpx),a 4043 | xor a 4044 | ld (tmpy),a 4045 | inc hl 4046 | jp pbl1 4047 | 4048 | ; this updates the lines completed area 4049 | printlines 4050 | 4051 | ld a,CC_INK 4052 | rst 16 4053 | ld a,7 4054 | rst 16 4055 | ld a,CC_AT 4056 | rst 16 4057 | ld a,(linesx) 4058 | rst 16 4059 | ld a,(linesy) 4060 | rst 16 4061 | 4062 | ld hl, totalrowscompleted 4063 | ld b,2 4064 | pl1 4065 | ld a,(hl) ; get the character to print 4066 | inc hl ; point to next character 4067 | rst 16 ; print the character 4068 | djnz pl1 ; and do it all over again 4069 | 4070 | ; now print slash divider 4071 | 4072 | ld a,'/' 4073 | rst 16 4074 | 4075 | ld hl, targetlinesforthislevel 4076 | ld b,2 4077 | pl2 4078 | ld a,(hl) ; get the character to print 4079 | inc hl ; point to next character 4080 | rst 16 ; print the character 4081 | djnz pl2 ; and do it all over again 4082 | 4083 | ret 4084 | 4085 | ; this determines the target number of lines for this level 4086 | calculatelinesforthislevel 4087 | 4088 | ld hl, linesneededperlevel 4089 | ld de,(currentlevel) 4090 | dec de 4091 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 4092 | add hl,de 4093 | ld a,(hl) 4094 | 4095 | cp 10 4096 | jr z,cll1 4097 | cp 25 4098 | jr z,cll2 4099 | 4100 | ld hl,targetlinesforthislevel+1 ; point to ones column. 4101 | ld b,a 4102 | call uscor ; up the lines count 4103 | ret 4104 | cll1 4105 | ld hl,targetlinesforthislevel ; point to tens column. 4106 | ld b,1 4107 | call uscor ; up the lines count 4108 | ret 4109 | cll2 4110 | ld hl,targetlinesforthislevel ; point to tens column. 4111 | ld b,2 4112 | call uscor ; up the lines count 4113 | ld hl,targetlinesforthislevel+1 ; point to ones column. 4114 | ld b,5 4115 | call uscor ; up the lines count 4116 | ret 4117 | 4118 | ; routine for printing the name of the level at the bottom of the screen 4119 | printlevelname 4120 | 4121 | ld a,1 ; open channel 1 4122 | call 5633 4123 | 4124 | ld a,(currentlevel) 4125 | cp 1 4126 | jr z,pln1 4127 | cp 2 4128 | jr z,pln2 4129 | cp 3 4130 | jr z,pln3 4131 | cp 4 4132 | jr z,pln4 4133 | cp 5 4134 | jr z,pln5 4135 | cp 6 4136 | jr z,pln6 4137 | cp 7 4138 | jr z,pln7 4139 | cp 8 4140 | jr z,pln8 4141 | cp 9 4142 | jr z,pln9 4143 | cp 10 4144 | jr z,pln10 4145 | jr pln12 ; no matches found, exit 4146 | pln1 4147 | ld hl, msg_game_level1 4148 | jr pln11 4149 | pln2 4150 | ld hl, msg_game_level2 4151 | jr pln11 4152 | pln3 4153 | ld hl, msg_game_level3 4154 | jr pln11 4155 | pln4 4156 | ld hl, msg_game_level4 4157 | jr pln11 4158 | pln5 4159 | ld hl, msg_game_level5 4160 | jr pln11 4161 | pln6 4162 | ld hl, msg_game_level6 4163 | jr pln11 4164 | pln7 4165 | ld hl, msg_game_level7 4166 | jr pln11 4167 | pln8 4168 | ld hl, msg_game_level8 4169 | jr pln11 4170 | pln9 4171 | ld hl, msg_game_level9 4172 | jr pln11 4173 | pln10 4174 | ld hl, msg_game_level10 4175 | 4176 | pln11 4177 | call pm_do_it ; part of print_message 4178 | pln12 4179 | ld a,2 ; re-open channel 2 4180 | call 5633 4181 | 4182 | 4183 | ret 4184 | 4185 | 4186 | ; sound effect when clearing lines 4187 | clearedlinenoise 4188 | ld e,200 ; repeat 200 times. 4189 | ld hl,0 ; start pointer in ROM. 4190 | noise2 4191 | push de 4192 | ld b,32 ; length of step. 4193 | noise0 4194 | push bc 4195 | ld a,(hl) ; next "random" number. 4196 | inc hl ; pointer. 4197 | and 248 ; we want a black border. 4198 | out (254),a ; write to speaker. 4199 | ld a,e ; as e gets smaller... 4200 | cpl ; ...we increase the delay. 4201 | noise1 4202 | dec a ; decrement loop counter. 4203 | jr nz,noise1 ; delay loop. 4204 | pop bc 4205 | djnz noise0 ; next step. 4206 | pop de 4207 | ld a,e 4208 | sub 24 ; size of step. 4209 | cp 30 ; end of range. 4210 | ret z 4211 | ret c 4212 | ld e,a 4213 | cpl 4214 | noise3 4215 | ld b,40 ; silent period. 4216 | noise4 4217 | djnz noise4 4218 | dec a 4219 | jr nz,noise3 4220 | jr noise2 4221 | 4222 | ret 4223 | 4224 | ; this is the noise used when the piece drops one square 4225 | 4226 | autodropnoise 4227 | ld hl,300 ; starting pitch. 4228 | ld b, 2 ; length of pitch bend. 4229 | adn1 4230 | push bc 4231 | push hl ; store pitch. 4232 | ld de,1 ; very short duration. 4233 | call 949 ; ROM beeper routine. 4234 | pop hl ; restore pitch. 4235 | inc hl ; pitch going up. 4236 | pop bc 4237 | djnz adn1 ; repeat. 4238 | ret 4239 | 4240 | ; this is the routine that draws the screen 4241 | 4242 | drawscreen 4243 | call 3503 ; clear the screen 4244 | 4245 | ld hl, msg_newscreen_level 4246 | call print_message 4247 | 4248 | ; now print the level 4249 | 4250 | ld a,CC_AT 4251 | rst 16 4252 | ld a,12 ;x position 4253 | rst 16 4254 | ld a,18 ;y position 4255 | rst 16 4256 | ld a,7 ;colour white 4257 | 4258 | ld a,(currentlevel) 4259 | cp 10 4260 | jr z,ds20 4261 | 4262 | add a,48 ; add ASCII to get correct character 4263 | ld c,a 4264 | rst 16 4265 | jr ds21 4266 | 4267 | ds20 4268 | ;code for handling level 10 4269 | ld a,49 ; ASCII char for '1' 4270 | rst 16 4271 | ld a,48; ASCII char for '0' 4272 | rst 16 4273 | 4274 | ds21 4275 | ld b,75 ; time to pause (50 frames a sec, 1.5 secs wait) 4276 | ds19 4277 | halt ; wait for an interrupt. 4278 | djnz ds19 ; repeat. 4279 | 4280 | ; to improve performance, we initially draw blocks whereever one of the shapes will be drawn 4281 | ; we then simply change their attribute colour to show or hide them 4282 | 4283 | call setupnextshape 4284 | call setupsavedshape 4285 | call setupplayarea 4286 | 4287 | ; draw the saved shape 4288 | call drawsavedshape 4289 | 4290 | ; we call selectnewpiece twice so we have a value for current and next shape 4291 | call selectnewpiece 4292 | call selectnewpiece 4293 | 4294 | ; reset the number of pieces played this level (to skip over the 2 select new piece calls above) 4295 | xor a 4296 | ld (piecesthislevel),a 4297 | 4298 | 4299 | ld b,21 4300 | 4301 | dsloop1 4302 | ld a,CC_AT 4303 | rst 16 4304 | ld a,b 4305 | rst 16 4306 | ld a,11 4307 | rst 16 4308 | ld a,2 ;wall colour 4309 | 4310 | ld (23695),a ; set our temporary screen colours. 4311 | ld a,146 ; ASCII code for User Defined Graphic 'C'. 4312 | rst 16 4313 | djnz dsloop1 4314 | 4315 | ld b,21 4316 | dsloop2 4317 | ld a,CC_AT 4318 | rst 16 4319 | ld a,b 4320 | rst 16 4321 | ld a,22 ; y co-ordinate 4322 | rst 16 4323 | ld a,2 ;wall colour 4324 | 4325 | ld (23695),a ; set our temporary screen colours. 4326 | ld a,146 ; ASCII code for User Defined Graphic 'C'. 4327 | rst 16 4328 | djnz dsloop2 4329 | 4330 | ld a,12 4331 | ld (wallpos),a 4332 | 4333 | ld d,21 ; default position 4334 | ld a,(upsidedown) 4335 | cp 1 4336 | jr z, ds1 4337 | jr ds2 4338 | ds1 4339 | ld d,0 4340 | 4341 | ds2 4342 | 4343 | ld b,10 4344 | dsloop3 4345 | ld a,CC_AT 4346 | rst 16 4347 | ld a,d 4348 | rst 16 4349 | ld a,(wallpos) ; y co-ordinate 4350 | rst 16 4351 | 4352 | ld a,(wallpos) 4353 | inc a 4354 | ld (wallpos),a 4355 | ld a,2 ;wall colour 4356 | 4357 | ld (23695),a ; set our temporary screen colours. 4358 | ld a,149 ; ASCII code for User Defined Graphic 'F'. 4359 | rst 16 4360 | djnz dsloop3 4361 | 4362 | ; now we draw the end of the pipes 4363 | 4364 | ld a,(upsidedown) 4365 | cp 1 4366 | jr z,ds12 4367 | ds11 4368 | ld b,0 ;end of pipes at top 4369 | ld c,147 ; ASCII code for User Defined Graphic 'D' 4370 | jr ds13 4371 | ds12 4372 | ld b,21 ;upside down so end of pipes at bottom 4373 | ld c,148 ; ASCII code for User Defined Graphic 'E' 4374 | ds13 4375 | ld a,CC_AT 4376 | rst 16 4377 | ld a,b ;x position 4378 | rst 16 4379 | ld a,11 ;y position 4380 | rst 16 4381 | ld a,2 ;colour red 4382 | 4383 | ld (23695),a ; set our temporary screen colours. 4384 | ld a,c ; graphic 4385 | rst 16 4386 | 4387 | ld a,CC_AT 4388 | rst 16 4389 | ld a,b 4390 | rst 16 4391 | ld a,22 ;y position 4392 | rst 16 4393 | ld a,2 ;colour red 4394 | 4395 | ld (23695),a ; set our temporary screen colours. 4396 | ld a,c ;graphic 4397 | rst 16 4398 | 4399 | ds14 4400 | ; now we draw the corner pieces 4401 | ld a,(upsidedown) 4402 | cp 1 4403 | jr z,ds16 4404 | ds15 4405 | ld b,21 ;corner of pipes at bottom 4406 | ld c,150 ; ASCII code for User Defined Graphic 'G' 4407 | ld d,152 ; ASCII code for User Defined Graphic 'I' 4408 | jr ds17 4409 | ds16 4410 | ld b,0 ;corner of pipes at top 4411 | ld c,151 ; ASCII code for User Defined Graphic 'H' 4412 | ld d,153 ; ASCII code for User Defined Graphic 'J' 4413 | ds17 4414 | ld a,CC_AT 4415 | rst 16 4416 | ld a,b ;x position 4417 | rst 16 4418 | ld a,11 ;y position 4419 | rst 16 4420 | ld a,2 ;colour red 4421 | 4422 | ld (23695),a ; set our temporary screen colours. 4423 | ld a,c ; graphic 4424 | rst 16 4425 | 4426 | ld a,CC_AT 4427 | rst 16 4428 | ld a,b ;x position 4429 | rst 16 4430 | ld a,22 ;y position 4431 | rst 16 4432 | ld a,2 ;colour red 4433 | 4434 | ld (23695),a ; set our temporary screen colours. 4435 | ld a,d ; graphic 4436 | rst 16 4437 | 4438 | 4439 | ds18 4440 | ; now we check for any special cases 4441 | 4442 | ld a,(currentlevel) 4443 | cp 4 ; shooting stars 4444 | jr z,ds3 4445 | cp 5 ; more stars 4446 | jr z,ds4 4447 | cp 6 ; level letter F 4448 | jr z,ds5 4449 | cp 7 ; mirror level 4450 | jr z,ds6 4451 | cp 9 4452 | jr z,ds7 4453 | jr ds8 ; no matches to special cases 4454 | ds3 4455 | ; draw 2 stars on screen 4456 | call shootingstar 4457 | call shootingstar 4458 | jr ds8 4459 | ds4 4460 | ; draw 2 stars on screen 4461 | call shootingstar 4462 | call shootingstar 4463 | jr ds8 4464 | ds5 4465 | call drawletterf 4466 | jr ds8 4467 | ds6 4468 | call drawmirror 4469 | jr ds8 4470 | ds7 4471 | ; draw 2 stars on screen 4472 | call shootingstar 4473 | call shootingstar 4474 | ds8 4475 | ; print the score section 4476 | ld hl,msg_game_score 4477 | call print_message 4478 | 4479 | call printscore 4480 | 4481 | ; print the high score section 4482 | ld hl,msg_game_highscore 4483 | call print_message 4484 | 4485 | call printhighscore 4486 | 4487 | ; print ghost section 4488 | ld hl, msg_game_ghost 4489 | call print_message 4490 | 4491 | ld a,(ghostactive) 4492 | cp 1 4493 | jr z,ds9 4494 | 4495 | ld hl, msg_game_ghost_inactive 4496 | jr ds10 4497 | ds9 4498 | ld hl, msg_game_ghost_active 4499 | ds10 4500 | call print_message 4501 | 4502 | ; print next shape wording 4503 | ld hl, msg_game_nextpiece 4504 | call print_message 4505 | 4506 | ; print saved shape section 4507 | ld hl, msg_game_savedpiece 4508 | call print_message 4509 | 4510 | ; print lines completed section 4511 | ld hl,msg_game_line 4512 | call print_message 4513 | 4514 | call printlines 4515 | 4516 | ; print the name of the level 4517 | call printlevelname 4518 | 4519 | ;align shape to correct orientation 4520 | call setblockshapes 4521 | 4522 | ; now we draw our shape 4523 | ld hl, colourlookuptable 4524 | ld de,(currentshape) 4525 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 4526 | add hl,de 4527 | ld a,(hl) 4528 | ld (blockcolour),a ; now draw block in new position 4529 | 4530 | call showcurrentshape 4531 | 4532 | ; final action of setup, set music to 'Hall of the Mountain King' 4533 | 4534 | ld bc,hallofthemountainking 4535 | ld (gamemusic),bc 4536 | ld a, 6 4537 | ld (musicspeed),a 4538 | xor a 4539 | ld (noteindex),a ; so music plays at start of song 4540 | 4541 | 4542 | ret 4543 | 4544 | ; level 6 is called the letter F. We draw a letter F on-screen 4545 | drawletterf 4546 | 4547 | ld c,20 ; starting x position 4548 | ld b,5 4549 | 4550 | dlf1 4551 | ld a,CC_AT 4552 | rst 16 4553 | ld a,c 4554 | rst 16 4555 | ld a,16 ;y position 4556 | rst 16 4557 | ld a,4 ;colour green 4558 | 4559 | ld (23695),a ; set our temporary screen colours. 4560 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4561 | rst 16 4562 | 4563 | dec c ; drop c one square (up the screen) 4564 | 4565 | djnz dlf1 4566 | 4567 | ld a,CC_AT 4568 | rst 16 4569 | ld a,18 4570 | rst 16 4571 | ld a,17 ;y position 4572 | rst 16 4573 | ld a,4 ;colour green 4574 | 4575 | ld (23695),a ; set our temporary screen colours. 4576 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4577 | rst 16 4578 | 4579 | ld a,CC_AT 4580 | rst 16 4581 | ld a,16 4582 | rst 16 4583 | ld a,17 ;y position 4584 | rst 16 4585 | ld a,4 ;colour green 4586 | 4587 | ld (23695),a ; set our temporary screen colours. 4588 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4589 | rst 16 4590 | 4591 | ld a,CC_AT 4592 | rst 16 4593 | ld a,16 4594 | rst 16 4595 | ld a,18 ;y position 4596 | rst 16 4597 | ld a,4 ;colour green 4598 | 4599 | ld (23695),a ; set our temporary screen colours. 4600 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4601 | rst 16 4602 | 4603 | 4604 | 4605 | 4606 | ret 4607 | 4608 | ; level 7 is called Mirror, this draws a mirrored F on screen 4609 | drawmirror 4610 | ld c,20 ; starting x position 4611 | ld b,5 4612 | 4613 | dm1 4614 | ld a,CC_AT 4615 | rst 16 4616 | ld a,c 4617 | rst 16 4618 | ld a,16 ;y position 4619 | rst 16 4620 | ld a,4 ;colour green 4621 | 4622 | ld (23695),a ; set our temporary screen colours. 4623 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4624 | rst 16 4625 | 4626 | dec c ; drop c one square (up the screen) 4627 | 4628 | djnz dm1 4629 | 4630 | ld c,14 4631 | ld b,5 4632 | dm2 4633 | ld a,CC_AT 4634 | rst 16 4635 | ld a, 16 4636 | rst 16 4637 | ld a,c 4638 | rst 16 4639 | ld a,4 ;colour green 4640 | 4641 | ld (23695),a ; set our temporary screen colours. 4642 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4643 | rst 16 4644 | 4645 | inc c 4646 | 4647 | djnz dm2 4648 | 4649 | ld c,15 4650 | ld b,3 4651 | dm3 4652 | ld a,CC_AT 4653 | rst 16 4654 | ld a, 18 4655 | rst 16 4656 | ld a,c 4657 | rst 16 4658 | ld a,4 ;colour green 4659 | 4660 | ld (23695),a ; set our temporary screen colours. 4661 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4662 | rst 16 4663 | 4664 | inc c 4665 | 4666 | djnz dm3 4667 | 4668 | 4669 | 4670 | ret 4671 | 4672 | ; this sets up the variables for a new level 4673 | setuplevel 4674 | xor a 4675 | ld (upsidedown),a 4676 | ld a,(currentlevel) 4677 | cp 3 4678 | jr z,sul1 4679 | jr sul2 4680 | sul1 4681 | ld a,1 4682 | ld (upsidedown),a 4683 | sul2 4684 | ; reset allowed swap 4685 | ld a,1 4686 | ld (allowedswap),a 4687 | 4688 | ;reset the lines completed 4689 | ld hl,totalrowscompleted 4690 | ld (hl),'0' 4691 | inc hl 4692 | ld (hl),'0' 4693 | 4694 | xor a 4695 | ld (totalrowscompletednum),a 4696 | 4697 | ; reset the number of pieces played this level 4698 | xor a 4699 | ld (piecesthislevel),a 4700 | 4701 | ; calculate the lines required for this level 4702 | ld hl,targetlinesforthislevel 4703 | ld (hl),'0' 4704 | inc hl 4705 | ld (hl),'0' 4706 | 4707 | call calculatelinesforthislevel 4708 | 4709 | ld hl, linesneededperlevel 4710 | ld de,(currentlevel) 4711 | dec de 4712 | ld d,0 ;de is 16 bit, but we are actually trying to add an 8 bit to a 16bit so remove any possible extras 4713 | add hl,de 4714 | ld a,(hl) 4715 | ld (targetlinesforthislevelnum),a 4716 | 4717 | ; ensure block starts in start position 4718 | ld a,(startx) 4719 | ld (plx),a 4720 | ld a,(starty) 4721 | ld (ply),a 4722 | 4723 | ; if upside down we need to modify the x position 4724 | ld a,(upsidedown) 4725 | cp 1 4726 | jr z,sul3 4727 | jr sul4 4728 | sul3 4729 | ld a,(upsidedownstartx) 4730 | ld (plx),a 4731 | sul4 4732 | ret 4733 | 4734 | ; this setups the variables for a new level and draws the screen 4735 | newlevel 4736 | ; switch off in-game music, music set to silent (will be re-activated later after new screen drawn) 4737 | ld bc,silentmusic 4738 | ld (gamemusic),bc 4739 | xor a 4740 | ld (noteindex),a ; so (silent) music plays at start of song 4741 | 4742 | call setuplevel 4743 | call drawscreen 4744 | 4745 | ld hl,pretim 4746 | ld a,(23672) 4747 | ld (hl),a 4748 | 4749 | ret 4750 | 4751 | ; this does the level special action 4752 | ; for example put a random square on the screen or slide a floor level or 4753 | ; rise the entire board. There are special actions for levels 4,5,8,9 and 10 4754 | levelspecialaction 4755 | 4756 | ld a,(currentlevel) 4757 | cp 4 4758 | jp z,lsa1 4759 | cp 5 4760 | jp z,lsa2 4761 | cp 8 4762 | jp z,lsa3 4763 | cp 9 4764 | jp z,lsa4 4765 | cp 10 4766 | jp z,lsa5 4767 | 4768 | ret 4769 | 4770 | lsa1 4771 | ; level 4, needs shooting stars every 5 pieces 4772 | ld a,(piecesthislevel) 4773 | ld d,a 4774 | ld e,5 4775 | call getmodulo 4776 | ; a will be 0 if evenly divisible by 5 4777 | cp 0 4778 | ret nz 4779 | 4780 | call shootingstar 4781 | 4782 | ret 4783 | lsa2 4784 | ; level 5, needs shooting stars every 5 pieces 4785 | ld a,(piecesthislevel) 4786 | ld d,a 4787 | ld e,5 4788 | call getmodulo 4789 | ; a will be 0 if evenly divisible by 5 4790 | cp 0 4791 | ret nz 4792 | 4793 | call shootingstar 4794 | ret 4795 | lsa3 4796 | ; level 8, sliding floor 4797 | ; a random level is moved either left or right every 4 pieces 4798 | 4799 | ld a,(piecesthislevel) 4800 | ld d,a 4801 | ld e,4 4802 | call getmodulo 4803 | ; a will be 0 if evenly divisible by 4 4804 | cp 0 4805 | ret nz 4806 | 4807 | call slidingfloor 4808 | 4809 | ret 4810 | lsa4 4811 | ; level 9, needs shooting stars every 5 pieces and sliding floor 4812 | ld a,(piecesthislevel) 4813 | ld d,a 4814 | ld e,5 4815 | call getmodulo 4816 | ; a will be 0 if evenly divisible by 5 4817 | cp 0 4818 | jp nz,lsa6 4819 | 4820 | call shootingstar 4821 | 4822 | lsa6 4823 | ld a,(piecesthislevel) 4824 | ld d,a 4825 | ld e,4 4826 | call getmodulo 4827 | ; a will be 0 if evenly divisible by 4 4828 | cp 0 4829 | ret nz 4830 | 4831 | call slidingfloor 4832 | 4833 | ret 4834 | lsa5 4835 | ld a,(piecesthislevel) 4836 | ld d,a 4837 | ld e,10 4838 | call getmodulo 4839 | ; a will be 0 if evenly divisible by 10 4840 | cp 0 4841 | ret nz 4842 | 4843 | call risingfloor 4844 | ret 4845 | 4846 | 4847 | 4848 | ; routine for calculating modulo 4849 | ; Integer divides D by E 4850 | ; Result in D, remainder in A 4851 | ; Clobbers F, B 4852 | getmodulo 4853 | xor a 4854 | ld b,8 4855 | gm1 4856 | sla d 4857 | rla 4858 | cp e 4859 | jr c,gm2 4860 | sub e 4861 | inc d 4862 | gm2 4863 | djnz gm1 4864 | ret 4865 | 4866 | ; shooting star. This puts a random square somewhere on the playarea. It puts it at least 4 4867 | ; squares down from the top of the screen to give the player a chance 4868 | shootingstar 4869 | call rnd 4870 | and 15 ;bitmask bits 0, 1, 2 and 3 4871 | 4872 | add a,5 ; to ensure we do not put a block directly in starting position 4873 | ld (shootingstarx),a 4874 | 4875 | ; now that we have picked the row, need to pick the column 4876 | ; column must be between 12 and 21 (inclusive) 4877 | 4878 | sst1 4879 | call rnd 4880 | and 15; bitmask 4 bits 4881 | cp 10 4882 | jp nc,sst1 4883 | sst3 4884 | ; we now have a value between 0 and 9 4885 | add a,12 4886 | ld c,a 4887 | ld (shootingstary),a 4888 | 4889 | ; now see if there is already a block at this position 4890 | ld a,(shootingstarx) 4891 | ld b,a 4892 | 4893 | call atadd 4894 | or 0 ; check if it black/black i.e. empty square 4895 | jp nz,sst1 4896 | 4897 | ; at this stage we have picked a square and it is blank 4898 | ; lets draw it on-screen 4899 | 4900 | ld a,CC_AT 4901 | rst 16 4902 | ld a,(shootingstarx) 4903 | rst 16 4904 | ld a,(shootingstary) 4905 | rst 16 4906 | ld a,2 ;colour red 4907 | 4908 | ld (23695),a ; set our temporary screen colours. 4909 | ld a,144 ; ASCII code for User Defined Graphic 'A'. 4910 | rst 16 4911 | 4912 | ret 4913 | 4914 | ; finds a row (that has a square already on that row) and slides it one square left or right 4915 | slidingfloor 4916 | xor a 4917 | ld (slidingcounter),a 4918 | 4919 | sf1 4920 | call rnd 4921 | and 15 ;bitmask bits 0, 1, 2 and 3 4922 | 4923 | add a,5 ; so picking a level safely below start point 4924 | 4925 | ld (slidingrow),a 4926 | 4927 | ; now that we have picked a row, need to ensure there is at least one square already on that 4928 | ; row, otherwise we will need to pick a new row 4929 | 4930 | ; set tmpx to the row to check 4931 | ld (tmpx),a 4932 | 4933 | ld a,(playareatopliney) 4934 | ld (tmpy),a 4935 | 4936 | ld b,10 ;10 squares in width of play area 4937 | sf2 4938 | push bc 4939 | ld a,(tmpx) 4940 | ld b,a 4941 | ld a,(tmpy) 4942 | ld c,a 4943 | call atadd 4944 | or 0 ; check if it black/black i.e. empty square 4945 | jp nz, sf3 ; found a non black square 4946 | 4947 | ld a,(tmpy) 4948 | inc a 4949 | ld (tmpy),a 4950 | pop bc 4951 | djnz sf2 4952 | ; if got here then no squares on the line, pick a new row 4953 | ld a,(slidingcounter) 4954 | inc a 4955 | cp 20 4956 | ret z ; if 20 attempts to find a row, give up 4957 | ld (slidingcounter),a 4958 | jr sf1 4959 | sf3 4960 | ; so we have found a row with at least one block on it, now lets shift it 4961 | ;pick whether to go left (0) or right (1) 4962 | pop bc ; to handle first push within sf2 4963 | 4964 | call rnd 4965 | and 15; bitmask 4 bits 4966 | 4967 | ld d,a 4968 | ld e,2 4969 | call getmodulo 4970 | cp 1 4971 | jp z,sf4 ; going right 4972 | 4973 | ;we are going left so get value at column 12 4974 | ld c,12 4975 | ld a,(slidingrow) 4976 | ld b,a 4977 | call atadd 4978 | ld (slidingwraparoundcolour),a 4979 | 4980 | ld a,12 ; starting point is column 12 4981 | ld (tmpy),a 4982 | ld b,9 ; one less than normal 4983 | sf5 4984 | push bc 4985 | 4986 | ld a,(slidingrow) 4987 | ld b,a 4988 | 4989 | ld a,(tmpy) 4990 | inc a 4991 | ld c,a 4992 | call atadd 4993 | ld (slidingtempcolour),a ; this now contains the colour of the square directly to the right 4994 | ld a,(tmpy) 4995 | ld c,a 4996 | call atadd 4997 | ld a,(slidingtempcolour) 4998 | ld (hl),a 4999 | ld a,(tmpy) ; next square in the row 5000 | inc a 5001 | ld (tmpy),a 5002 | pop bc 5003 | djnz sf5 5004 | sf6 5005 | ; now place the wrap around colour, place at column 21 5006 | ld a,(slidingrow) 5007 | ld b,a 5008 | ld c,21 5009 | call atadd 5010 | ld a,(slidingwraparoundcolour) 5011 | ld (hl),a 5012 | 5013 | ret ;finished 5014 | 5015 | 5016 | 5017 | sf4 5018 | ;get the value at column 21 5019 | ld c,21 5020 | ld a,(slidingrow) 5021 | ld b,a 5022 | call atadd 5023 | ld (slidingwraparoundcolour),a 5024 | 5025 | ld a,21 ; starting point is column 21 5026 | ld (tmpy),a 5027 | ld b,9 ; one less than normal 5028 | sf7 5029 | push bc 5030 | 5031 | ld a,(slidingrow) 5032 | ld b,a 5033 | 5034 | ld a,(tmpy) 5035 | dec a 5036 | ld c,a 5037 | call atadd 5038 | ld (slidingtempcolour),a ; this now contains the colour of the square directly to the left 5039 | ld a,(tmpy) 5040 | ld c,a 5041 | call atadd 5042 | ld a,(slidingtempcolour) 5043 | ld (hl),a 5044 | ld a,(tmpy) ; next square in the row 5045 | dec a 5046 | ld (tmpy),a 5047 | pop bc 5048 | djnz sf7 5049 | sf8 5050 | ; now place the wrap around colour, place at column 12 5051 | ld a,(slidingrow) 5052 | ld b,a 5053 | ld c,12 5054 | call atadd 5055 | ld a,(slidingwraparoundcolour) 5056 | ld (hl),a 5057 | 5058 | ret 5059 | 5060 | ; this is the special action for level 10. Every 10 pieces the playarea raises one level 5061 | ; and random squares are added to that level 5062 | risingfloor 5063 | ld a,(playareatopliney) 5064 | ld (tmpy),a 5065 | 5066 | xor a 5067 | ld (tmpx),a 5068 | 5069 | rf1 5070 | ld b,10 ; inner loop 5071 | rf2 5072 | push bc 5073 | 5074 | ld a,(tmpx) 5075 | inc a ; we increase by 1 as we are copying the line below 5076 | ld b,a 5077 | 5078 | ld a,(tmpy) 5079 | ld c,a 5080 | call atadd 5081 | ld (blockcolour),a ; this now contains the colour of the square directly above 5082 | ld a,(tmpx) 5083 | ld b,a 5084 | call atadd 5085 | ld a,(blockcolour) 5086 | ld (hl),a 5087 | ld a,(tmpy) ; next square in the row 5088 | inc a 5089 | ld (tmpy),a 5090 | pop bc 5091 | djnz rf2 5092 | ; finished inner loop, i.e. that row, increase x by 1 and reset y 5093 | 5094 | ld a,(tmpx) 5095 | inc a 5096 | ld (tmpx),a 5097 | ld a,(playareatopliney) 5098 | ld (tmpy),a 5099 | 5100 | ld a,(tmpx) 5101 | cp 20 ; at 21 we are at the bottom of the screen, 20 would try to read from the bricks (+1) 5102 | jr nz, rf1 5103 | 5104 | ; at this stage we have dropped everything, now now erase the bottom line 5105 | ld a,20 5106 | ld (tmpx),a 5107 | call eraseline 5108 | 5109 | ; now fill this line with random squares 5110 | ld a,(playareatopliney) 5111 | ld (tmpy),a 5112 | 5113 | ld b,10 ;10 squares in width of play area 5114 | rf3 5115 | push bc 5116 | 5117 | call rnd 5118 | and 15; bitmask 4 bits 5119 | 5120 | ld d,a 5121 | ld e,2 5122 | call getmodulo 5123 | cp 1 5124 | jp z,rf5 5125 | 5126 | rf4 5127 | ld a,(tmpx) 5128 | ld b,a 5129 | ld a,(tmpy) 5130 | ld c,a 5131 | call atadd 5132 | ld (hl),5 ; set the attribute at this square to be 5, cyan 5133 | rf5 5134 | ld a,(tmpy) 5135 | inc a 5136 | ld (tmpy),a 5137 | pop bc 5138 | djnz rf3 5139 | 5140 | ret 5141 | 5142 | 5143 | ; this checks if we have completed the level or won the game 5144 | checklevelcomplete 5145 | ld a,(targetlinesforthislevelnum) 5146 | ld b,a 5147 | ld a,(totalrowscompletednum) 5148 | cp b 5149 | jr nc,clc1 5150 | ret ; target for level nor reached, can exit routine 5151 | 5152 | clc1 5153 | ld a,(currentlevel) 5154 | inc a 5155 | ld (currentlevel),a 5156 | 5157 | cp 11 5158 | jp nc,youwin 5159 | 5160 | ; add delay 5161 | ld hl, 50000 5162 | clc2 5163 | dec hl 5164 | ld a,h 5165 | or l 5166 | jr nz,clc2 5167 | 5168 | jp newlevel 5169 | 5170 | ;checks the score against the high score and sets the score to be the high score if larger 5171 | checkhighscore 5172 | xor a 5173 | ld (newhighscore),a 5174 | 5175 | ld hl,highscore 5176 | ld c,(hl) 5177 | ld hl,score 5178 | ld a,(hl) 5179 | cp c 5180 | jr z,chs2 ;if equal we check next digit 5181 | jr nc,chs1 ; accumulator (score) is greater than high score 5182 | ret ; otherwise high score is still bettter 5183 | chs2 5184 | inc hl ; advance score pointer 5185 | ld a,(hl) 5186 | ld hl,highscore+1 5187 | ld c,(hl) 5188 | cp c 5189 | jr z,chs3 5190 | jr nc,chs1 5191 | ret 5192 | chs3 5193 | inc hl ;advance high score pointer 5194 | ld c,(hl) 5195 | ld hl,score+2 5196 | ld a,(hl) 5197 | cp c 5198 | jr z,chs4 5199 | jr nc,chs1 5200 | ret 5201 | chs4 5202 | inc hl ; advance score pointer 5203 | ld a,(hl) 5204 | ld hl,highscore+3 5205 | ld c,(hl) 5206 | cp c 5207 | jr z,chs5 5208 | jr nc,chs1 5209 | ret 5210 | chs5 5211 | inc hl ;advance high score pointer 5212 | ld c,(hl) 5213 | ld hl,score+4 5214 | ld a,(hl) 5215 | cp c 5216 | jr z,chs6 5217 | jr nc,chs1 5218 | ret 5219 | chs6 5220 | inc hl ; advance score pointer 5221 | ld a,(hl) 5222 | ld hl,highscore+5 5223 | ld c,(hl) 5224 | cp c 5225 | jr nc,chs1 5226 | ret ;if reach here score is less than high score 5227 | 5228 | chs1 5229 | ld a,1 5230 | ld (newhighscore),a ;new high score 5231 | 5232 | ld de,highscore 5233 | ld hl,score 5234 | ld bc,6 5235 | ldir 5236 | 5237 | ret 5238 | 5239 | ; this allows the player to switch the music on off 5240 | switchmusiconoff 5241 | ld a,(gamemusicenabled) 5242 | cp 0 5243 | jr nz,smo1 5244 | ; if here then music is currently on, switch off 5245 | ld a,1 5246 | ld (gamemusicenabled),a 5247 | ret 5248 | smo1 5249 | ; if here then music is currently on, we switch off 5250 | xor a 5251 | ld (gamemusicenabled),a 5252 | ret 5253 | 5254 | 5255 | ; the in-game music section 5256 | org 40000 5257 | 5258 | gamemusic defb 0,0 5259 | musicspeed defb 6 5260 | 5261 | ;alternative version 'In the Hall of the Mountain King' 5262 | ;set musicspeed value to 6 to use 5263 | hallofthemountainking 5264 | defb 48,48,43,43,40,40,36,36,32,32,40,40,32,32 5265 | defb 32,32 5266 | defb 34,34,43,43,34,34,34,34,36,36,45,45,36,36,36,36 5267 | defb 48,48,43,43,40,40,36,36,32,32,40,40,32,32 5268 | defb 24,24,27,27,32,32,40,40,32,32,27,27,27,27,27,27 5269 | defb 27,27 5270 | defb 128,128,114,114,102,102,96,96,86,86,102,102,86,86 5271 | defb 86,86,81,81,102,102,81,81,81,81,86,86,102,102,86,86 5272 | defb 86,86 5273 | defb 128,128,114,114,102,102,96,96,86,86,102,102,86,86 5274 | defb 86,86,81,81,102,102,81,81,81,81,86,86,86,86 5275 | defb 86,86,86,86,255 5276 | 5277 | 5278 | ; music played when you win 5279 | ;set cp value to 10 in playmusic to use 5280 | youwinmusic 5281 | defb 18,24,23,20,23,24,27,27 5282 | defb 23,18,20,23,24,23,20,18 5283 | defb 23,27,27,27,24,23,20,17 5284 | defb 13,15,17,18,23,18,20,23 5285 | defb 24,24,23,20,18,23,27,27 5286 | defb 1,18,23,20,24,23,27,28 5287 | defb 24,1,18,23,20,24,23,18 5288 | defb 13,14,255 5289 | 5290 | ; 'If I were a rich man' from Jet Set Willy 5291 | ifiwerearichman 5292 | defb 86,96,86,96,102,102,128,128,128,128,102,96,86,96,86,96 5293 | defb 102,96,86,76,72,76,72,76,86,86,86,86,86,86,86,86 5294 | defb 64,64,64,64,68,68,76,76,86,96,102,96,86,86,102,102 5295 | defb 81,86,96,86,81,81,96,96,64,64,64,64,64,64,64,64,255 5296 | 5297 | ; heart and soul, speed 11 5298 | heartandsoul 5299 | defb 91,91,91,0,91,96,108,96 5300 | defb 91,81,0,72,72,72,0,72 5301 | defb 81,91,81,72,68,0,61,0 5302 | defb 91,0,54,61,68,72,81,72 5303 | defb 81,91,0,0,255 5304 | 5305 | ; silent music 5306 | silentmusic 5307 | defb 0,0,0,255 5308 | 5309 | noteindex defb 0 5310 | musicpauseindex defb 0 5311 | 5312 | 5313 | playmusic 5314 | 5315 | ; now see if player wants music 5316 | ld a,(gamemusicenabled) 5317 | cp 0 5318 | ret z 5319 | 5320 | ; we do not play a not every interrupt call. This piece of code allows us 5321 | ; to play a note every X (musicspeed) interrupts 5322 | 5323 | ld a,(musicspeed) 5324 | ld d,a 5325 | 5326 | ld a,(musicpauseindex) 5327 | inc a 5328 | ld (musicpauseindex),a 5329 | cp d 5330 | jr nc,pm1 5331 | ret 5332 | pm1 5333 | xor a 5334 | ld (musicpauseindex),a 5335 | jp playnote 5336 | 5337 | 5338 | ; this music routine adapted from manic miner code 5339 | ; 255 means end of music data, back to beginning of music data 5340 | ; 0 is a pause, don't play anything 5341 | playnote 5342 | ld a,(noteindex) 5343 | ld e,a 5344 | ld d,0 5345 | ld hl,(gamemusic) 5346 | add hl,de 5347 | ld a,(hl) 5348 | cp 255 ; end of song 5349 | jr z,pn3 5350 | cp 0 ; pause/silence 5351 | jr z,pn6 5352 | ; not end of song, increase index 5353 | ld a,(noteindex) 5354 | inc a 5355 | ld (noteindex),a 5356 | jr pn4 5357 | pn3 5358 | xor a 5359 | ld (noteindex),a 5360 | jr playnote 5361 | pn4 5362 | xor a ; set border colour to 0 5363 | ld e,(hl) 5364 | ld bc,3 5365 | pn1 5366 | out (254),a 5367 | dec e 5368 | jr nz,pn2 5369 | ld e,(hl) 5370 | xor 24 5371 | pn2 5372 | djnz pn1 5373 | dec c 5374 | jr nz,pn1 5375 | ret 5376 | 5377 | ; pause routine (0 in music data), increases index, but does not play sound 5378 | pn6 5379 | ld a,(noteindex) 5380 | inc a 5381 | ld (noteindex),a 5382 | ret 5383 | 5384 | 5385 | 5386 | org 51400 ; location of our interrupt routine 5387 | 5388 | Interrupt 5389 | di ; disable interrupts 5390 | push af ; preserve registers. 5391 | push bc 5392 | push hl 5393 | push de 5394 | push ix 5395 | 5396 | ; here is where we put the calls to the routines we want to execute during interrupts 5397 | ; e.g. play music etc. 5398 | ; we increment the frames counter as this is used to determine the rate of drop of the 5399 | ; main game piece 5400 | 5401 | ld hl,23672 ; frames counter. 5402 | inc (hl) ; move it along. 5403 | 5404 | call playmusic 5405 | 5406 | ; end of our routines 5407 | 5408 | pop ix ; restore registers. 5409 | pop de 5410 | pop hl 5411 | pop bc 5412 | pop af 5413 | ei ; always re-enable interrupts before returning. 5414 | reti ; done (return from interrupt) 5415 | 5416 | org 65024 5417 | 5418 | ; pointers to interrupt routine. 5419 | ; 257 instances of '200' 5420 | defb 200,200,200,200,200,200,200,200 5421 | defb 200,200,200,200,200,200,200,200 5422 | defb 200,200,200,200,200,200,200,200 5423 | defb 200,200,200,200,200,200,200,200 5424 | defb 200,200,200,200,200,200,200,200 5425 | defb 200,200,200,200,200,200,200,200 5426 | defb 200,200,200,200,200,200,200,200 5427 | defb 200,200,200,200,200,200,200,200 5428 | defb 200,200,200,200,200,200,200,200 5429 | defb 200,200,200,200,200,200,200,200 5430 | defb 200,200,200,200,200,200,200,200 5431 | defb 200,200,200,200,200,200,200,200 5432 | defb 200,200,200,200,200,200,200,200 5433 | defb 200,200,200,200,200,200,200,200 5434 | defb 200,200,200,200,200,200,200,200 5435 | defb 200,200,200,200,200,200,200,200 5436 | defb 200,200,200,200,200,200,200,200 5437 | defb 200,200,200,200,200,200,200,200 5438 | defb 200,200,200,200,200,200,200,200 5439 | defb 200,200,200,200,200,200,200,200 5440 | defb 200,200,200,200,200,200,200,200 5441 | defb 200,200,200,200,200,200,200,200 5442 | defb 200,200,200,200,200,200,200,200 5443 | defb 200,200,200,200,200,200,200,200 5444 | defb 200,200,200,200,200,200,200,200 5445 | defb 200,200,200,200,200,200,200,200 5446 | defb 200,200,200,200,200,200,200,200 5447 | defb 200,200,200,200,200,200,200,200 5448 | defb 200,200,200,200,200,200,200,200 5449 | defb 200,200,200,200,200,200,200,200 5450 | defb 200,200,200,200,200,200,200,200 5451 | defb 200,200,200,200,200,200,200,200 5452 | defb 200 5453 | 5454 | end 24576 ; assembler directive, says this is the end of the code and where the entry point is 5455 | 5456 | 5457 | 5458 | 5459 | 5460 | -------------------------------------------------------------------------------- /fallingblocks.tap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soiaf/FallingBlocks/b03087bb829c193811c8858df10eb2f0720b5cb3/fallingblocks.tap -------------------------------------------------------------------------------- /fallingblocks.zxk: -------------------------------------------------------------------------------- 1 | T: Falling Blocks 2 | F: fallingblocks.tap 3 | M: 48 4 | # key mapping has following order 5 | #start sequence; up; down; left; right; fire; select; 1; 2; A; B ; C; 6 | K:1;H;SP;O;P;G;1;S;D;2;3;4; 7 | D:;Clockwise Rotate;Anticlockwise Rotate;Left;Right;Ghost Mode;Start Game (1);Swap;Drop;2;3;4; -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2016 Peter McQuillan 2 | 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, 9 | this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * The name of the author may not be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------