├── readme.txt ├── readme.md ├── includes └── tetrice.inc ├── test.asm ├── graphic.asm ├── tetrice_dat.asm └── tetrice.asm /readme.txt: -------------------------------------------------------------------------------- 1 | It's Tetris, for the ti84ce. Programmed in ez80. 2 | 3 | Current features: 4 | Both old and new rotation systems 5 | Hold piece, next queue, and ghost piece 6 | Remappable controls and button repeat timing 7 | Several block themes 8 | Several modes, including Marathon, Sprint, Dig, Cascade, Ultra, and more. 9 | Very customizable data format (better documentation pending) 10 | 11 | Menu controls: 12 | 2nd: Confirm 13 | Alpha: Back 14 | Left/Right: Select number (must select with 2nd/Confirm first) 15 | Up/Down: Change item selected 16 | Del: quit (works anywhere) 17 | 18 | Default Controls: 19 | 2nd/Alpha - rotate left/right 20 | Left/Right - move 21 | Down - soft drop 22 | Up - hard drop (instant drop) 23 | XT0N - hold piece 24 | Mode - pause 25 | Del - quit 26 | 27 | Known Issues: 28 | Lock delay setting on start menu is currently useless 29 | 30 | Special thanks/Credits to... 31 | Michael - helped troubleshoot at the hackathon this was started at 32 | The various people who put together ti84pce.inc 33 | wikiti.brandonw.net, for being an amazing resource 34 | tetris.wiki, for being the most useful tetris resource I found 35 | Whoever made NullPoMino, for being an inspiration of what a tetris game can be 36 | KermMartian for making Tetric A, a source of inspiration on a calculator already 37 | Various individuals in the cemetech discord who helped with strange bugs or advice 38 | Cemetech in general, for also being a pretty great resource 39 | My friends and family who listen to me talk about the latest and greatest bug/feature/both 40 | 41 | Tools used: 42 | Notepad++ (highlighting from https://www.cemetech.net/forum/viewtopic.php?p=243171#243171) 43 | spasm-ng (https://github.com/alberthdev/spasm-ng) 44 | convbin (https://github.com/mateoconlechuga/convbin) 45 | CEmu (https://github.com/CE-Programming/CEmu) 46 | 47 | Also check out: 48 | Cemetech - https://cemetech.net 49 | NullPoMino - https://github.com/nullpomino/nullpomino 50 | Tetric A - https://www.cemetech.net/downloads/files/1347/x1347 51 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # CETris 2 | 3 | It's Tetris, for the TI-84 Plus CE. Created entirely in ez80 assembly. 4 | 5 | # Features for v0.8 6 | * Both old rotations and SRS system 7 | * Hold piece, next queue, and ghost piece 8 | * Modifiable controls, button repeat, and game timings like lock delay/DAS 9 | * Several options for block and background themes 10 | * Several modes, including Marathon, Sprint, Dig, Cascade, Ultra, and more. 11 | * Very customizable data format (better documentation pending) 12 | 13 | # Future plans 14 | Priority is listed in brackets. 15 | * [HIGH] Remaining scoring mechanics (Combo, All-Clear detection) 16 | * [MED] Ability to view all high scores at once 17 | * [MED] Display mode in score box of game 18 | * [LOW] Dig challenge speed-up with time 19 | * [LOW] Better documentation of data file and code 20 | 21 | # Controls 22 | These can be changed from within the Options/Controls menu. 23 | ## Menu controls 24 | * 2nd: Confirm 25 | * Alpha: Back 26 | * Left/Right: Select number (must select with 2nd/Confirm first) 27 | * Up/Down: Change item selected 28 | * Del: quit (works anywhere) 29 | 30 | ## Game controls 31 | * 2nd/Alpha - rotate left/right 32 | * Left/Right - move 33 | * Down - soft drop 34 | * Up - hard drop (instant drop + lock) 35 | * XT0N - hold piece 36 | * Mode - pause 37 | 38 | # Known Issues 39 | * Pausing on a frame around when the next piece spawns can cause the preview to get stuck between two frames for the duration of the pause 40 | 41 | # Building 42 | You will need convbin and spasm-ng (see Tools section) placed in the tools/ directory. If you are on Windows and want to build, try using MinGW, the build script only works on Linux or similar. 43 | 44 | Run `./build.sh` to build everything. Both the data file and the program file, as well as the graphics testing file are built here. 45 | 46 | The default build setup uses the current time as the version indicator. To build with a specific version number, specify the first arugment: `./build.sh v0.8` 47 | 48 | Just add any second argument, for example `./build.sh v0.8 1` to build with the Cesium header (this is the version with an icon, which adds about 300 bytes but looks nicer in shells). Note that the verison number in the header is currently separate from the in-program displayed version; make sure to modify tetrice.asm if building this way and you want matching versions. 49 | 50 | # Useful Resources 51 | ## Tools 52 | * ez80 Notepad++ highlighting from https://www.cemetech.net/forum/viewtopic.php?p=243171#243171) 53 | * spasm-ng (https://github.com/alberthdev/spasm-ng) 54 | * convbin (https://github.com/mateoconlechuga/convbin) 55 | * CEmu (https://github.com/CE-Programming/CEmu) 56 | * CEtris Data Converter (https://github.com/Minxrod/CETris-Data-Converter) 57 | ## References 58 | * Cemetech - https://cemetech.net 59 | * NullPoMino - https://github.com/nullpomino/nullpomino 60 | * Tetric A - https://www.cemetech.net/downloads/files/1347/x1347 61 | * tetris.wiki 62 | * wikiti.brandonw.net 63 | -------------------------------------------------------------------------------- /includes/tetrice.inc: -------------------------------------------------------------------------------- 1 | #include "includes\ti84pce.inc" 2 | 3 | ;program specfic constants: 4 | LOCK_DISABLE equ -1 5 | NULL_BLOCK equ 0 6 | NO_KEY_PRESSED equ -1 7 | vRamSplitSize equ (vRamEnd - vRam) / 2 8 | vRamSplit equ vRam + vRamSplitSize 9 | 10 | shadowOfs equ 36 11 | 12 | ;variables and memory regions 13 | PSS equ plotSScreen 14 | field equ PSS 15 | fieldHeight equ 25 16 | fieldDrawHeight equ 20 17 | fieldDrawWidth equ 10 18 | 19 | blockDataSize equ 8 20 | blockGraphicSize equ 2 21 | 22 | ;current status bits 23 | csLockedBit equ 0 ;locked block bit 24 | csNewBlockBit equ 1 ;prev. frame requests new block 25 | csClearLineBit equ 2 ;if block cleared a line 26 | csGarbageBit equ 3 ;apply garbage stored 27 | csRotateTBit equ 4 ;T-block last move was rotate 28 | csWallKicked equ 5 ;if last rotate was kicked 29 | csUsedHold equ 6 ;hold was used once already 30 | 31 | ;mino type data (held piece, next pieces, etc.) 32 | minoTypes equ PSS + 600 33 | holdTOfs equ 0 34 | bag1Ofs equ 1 35 | bag2Ofs equ 8 36 | demoTOfs equ 15 37 | 38 | holdT equ minoTypes + holdTOfs 39 | nextBag1 equ minoTypes + bag1Ofs 40 | nextBag2 equ minoTypes + bag2Ofs 41 | demoT equ minoTypes + demoTOfs 42 | 43 | ;current mino data 44 | curData equ PSS + 256 45 | curX equ curData + 0 46 | curY equ curData + 1 47 | curR equ curData + 2 48 | curT equ curData + 3 49 | curStatus equ curData + 4 50 | curBlock equ curData + 5 ;size: 10 51 | curDataSize equ curBlock + blockDataSize + blockGraphicSize - curX 52 | 53 | curXOfs equ 0 54 | curYOfs equ 1 55 | curStatusOfs equ 4 56 | curBlockOfs equ 5 57 | 58 | ;inbetween cur and old is a middle data chunk 59 | ;used to handle intermediate frames due to 60 | ;double-buffer 61 | midOfs equ curDataSize 62 | midData equ midOfs + curData 63 | 64 | ;saves data from previous frame here 65 | oldOfs equ 2 * midOfs ;alt. 2 * curDataSize 66 | oldData equ oldOfs + curData 67 | 68 | ;temp data to calculate ghost piece 69 | tempOfs equ 3 * curDataSize 70 | tempData equ tempOfs + curData 71 | 72 | midTempOfs equ 4 * curDataSize 73 | midTempData equ curData + midTempOfs 74 | 75 | ;2-previous frame's ghost 76 | oldTempOfs equ 5 * curDataSize 77 | oldTempData equ curData + oldTempOfs 78 | 79 | oldX equ oldOfs + curX 80 | oldY equ oldOfs + curY 81 | oldR equ oldOfs + curR 82 | oldT equ oldOfs + curT 83 | oldBlock equ oldOfs + curBlock 84 | 85 | gameVars equ PSS + 360 86 | score equ gameVars 87 | level equ gameVars + 4 88 | lines equ gameVars + 8 89 | linesToNextLevel equ gameVars + 12 90 | timerT equ gameVars + 16 91 | lockTimer equ gameVars + 20 ;lock delay 92 | globalTimer equ gameVars + 24 93 | spawnTimer equ gameVars + 28 ;ARE 94 | clearTimer equ gameVars + 32 ;line clear timer 95 | highscore equ gameVars + 40 96 | garbageTimer equ gameVars + 44 97 | queuedGarbage equ gameVars + 48 98 | linesClear equ gameVars + 52 ;only needs one byte 99 | lineClearInfo equ gameVars + 56 ;only needs one byte 100 | lcBackToBack equ 0 101 | lcPreviousB2B equ 1 102 | lcTSpin equ 2 ;set even if no lines clear 103 | queuedAction equ gameVars + 60 ;IHS, IRS 104 | qaHold equ 0 105 | qaRotateLeft equ 1 106 | qaRotateRight equ 2 107 | lockResets equ gameVars + 64 ; move reset related 108 | lowestY equ gameVars + 68 ; lowest Y level reached for this block 109 | rotationTemp equ gameVars + 71 ; 9 bytes 110 | rotationTempHL equ rotationTemp + 0 111 | rotationTempBC equ rotationTemp + 3 112 | rX equ rotationTemp + 6 113 | rY equ rotationTemp + 7 114 | rAttempt equ rotationTemp + 8 115 | randSeed equ gameVars + 80 ; random seed 116 | randInput equ gameVars + 83 117 | randBagPtr equ gameVars + 84 118 | randCountFail equ gameVars + 87 119 | 120 | miscVars equ gameVars + 100 121 | 122 | ;not the best location 123 | ;but I don't really know where to put this stuff 124 | saveDataPTR equ miscVars 125 | menuSelection equ miscVars + 4 126 | numberSelection equ miscVars + 8 127 | 128 | ruleVars = miscVars + 100 + 4 ;because rules uses -4 offset for some reason ;520ish 129 | 130 | ;data for various rules, stored as offset from rules 131 | ;garbage set 132 | rMode equ -4 ;why did I forget this 133 | rRGT equ -1 ;rising garbage timer 134 | rRGD equ -2;rising garbage density 135 | ;generated set 136 | rGGA equ -1;generated garbage amt 137 | rGGD equ -2 ;generated garbage density 138 | ;line clear data 139 | rLCW equ -3;lines needed to clear to win 140 | 141 | rules equ ruleVars 142 | 143 | rfBasic equ 0 ;basic mechanics 144 | rfExtra equ 1 ;extra mechanics 145 | rfWin equ 2 ;win condition currently set 146 | rfScore equ 3 ;high score method 147 | 148 | rbitGameCont equ 0 149 | rbitGameWon equ 1 150 | rbitSRSEnabled equ 2 151 | rbitPreviewEnabled equ 3 152 | rbitHoldEnabled equ 4 153 | rbitHardDropEnabled equ 5 154 | rbitBagEnabled equ 6 155 | rbitGhostEnabled equ 7 156 | 157 | ;rbitUnusedExtra equ 0 158 | rbitClearAnimation equ 0 159 | rbitGarbageRising equ 1 160 | rbitGarbageInitial equ 2 161 | rbitCascadeGravity equ 3 162 | rbitCascadeAnimation equ 4 163 | rbitLockAnimation equ 5 164 | rbitInstantHold equ 6 165 | rbitInstantRotate equ 7 166 | 167 | 168 | rbitLinesClear equ 0 169 | rbitRow0Clear equ 1 ;for garbage/generated games 170 | rbitCountdown equ 2 ;timed survival games 171 | rbitGarbageClear equ 3 172 | 173 | rbitHighScore equ 0 174 | rbitLowTime equ 1 175 | rbitHighLine equ 2 176 | 177 | rNull equ 0 178 | rGame equ 1 << rbitGameCont 179 | rGameWon equ 1 << rbitGameWon ;if game was won or lost 180 | rSRS equ 1 << rbitSRSEnabled 181 | rPreview equ 1 << rbitPreviewEnabled 182 | rHold equ 1 << rbitHoldEnabled 183 | rHardDrop equ 1 << rbitHardDropEnabled 184 | rBag equ 1 << rbitBagEnabled 185 | rGhost equ 1 << rbitGhostEnabled 186 | 187 | ;rUnused equ 1 << rbitunusedextra 188 | rClearAnim equ 1 << rbitClearAnimation 189 | rRising equ 1 << rbitGarbageRising 190 | rGenerated equ 1 << rbitGarbageInitial 191 | rCascade equ 1 << rbitCascadeGravity 192 | rCascadeAnim equ 1 << rbitCascadeAnimation 193 | rLockAnim equ 1 << rbitLockAnimation 194 | rIHS equ 1 << rbitInstantHold 195 | rIRS equ 1 << rbitInstantRotate 196 | 197 | rLines equ 1 << rbitLinesClear 198 | rRow0 equ 1 << rbitRow0Clear 199 | rCountdown equ 1 << rbitCountdown 200 | rGarbage equ 1 << rbitGarbageClear 201 | 202 | rScore equ 1 << rbitHighScore 203 | rTime equ 1 << rbitLowTime 204 | rLine equ 1 << rbitHighLine 205 | 206 | rMarathon equ rGame | rSRS | rPreview | rHold | rHardDrop | rBag | rGhost 207 | rRetro equ rGame 208 | 209 | rCascadeExtra equ rCascade | rCascadeAnim 210 | 211 | lockDelay equ PSS + 760 212 | ;themeBlock equ PSS + 764 ;precedes blockData 213 | ;themeColor equ PSS + 765 214 | ;themeBack equ PSS + 766 215 | spawnDelay equ PSS + 768 216 | clearDelay equ PSS + 772 217 | blockData equ PSS + 776 218 | buttonData equ PSS + 1024 219 | saveData equ PSS + 1024 220 | blockGraphic equ PSS + 1280 221 | empty300 equ PSS + 1536 222 | ;next must be past 1836 223 | 224 | menuJumpTable equ PSS + 2048 225 | jptMainMenu equ menuJumpTable + 0 226 | jptInitGame equ menuJumpTable + 4 227 | jptExit equ menuJumpTable + 8 228 | jptActiveMenu equ menuJumpTable + 12 229 | jptGetStringInList equ menuJumpTable + 16 230 | jptGetStringPTRSelection equ menuJumpTable + 20 231 | jptSetNumber equ menuJumpTable + 24 232 | jptDrawObject equ menuJumpTable + 28 ;for custom draws 233 | jptCheckKey equ menuJumpTable + 32 ;yes 234 | jptSwapVRamPTR equ menuJumpTable + 36 ;okay 235 | jptDrawMino equ menuJumpTable + 40 ;eh, maybe these should be split up somehow? 236 | 237 | userVars equ PSS + 3072 238 | 239 | ;key ids for important operations 240 | ;button repeat info etc. 241 | keyIDs: 242 | buttonID equ 0 243 | buttonTimeStart equ 1 244 | buttonTimeRepeat equ 2 245 | buttonTimer equ 3 246 | buttonDataSize equ 4 247 | 248 | buttonLeft equ 0 * buttonDataSize + buttonData 249 | buttonRight equ 1 * buttonDataSize + buttonData 250 | buttonSoft equ 2 * buttonDataSize + buttonData 251 | buttonHard equ 3 * buttonDataSize + buttonData 252 | buttonRotateLeft equ 4 * buttonDataSize + buttonData 253 | buttonRotateRight equ 5 * buttonDataSize + buttonData 254 | buttonHold equ 6 * buttonDataSize + buttonData 255 | buttonPause equ 7 * buttonDataSize + buttonData 256 | 257 | menuButtonData equ 8 * buttonDataSize + buttonData 258 | mbuttonUp equ 8 * buttonDataSize + buttonData 259 | mbuttonDown equ 9 * buttonDataSize + buttonData 260 | mbuttonLeft equ 10 * buttonDataSize + buttonData 261 | mbuttonRight equ 11 * buttonDataSize + buttonData 262 | 263 | mbuttonConfirm equ 12 * buttonDataSize + buttonData 264 | mbuttonBack equ 13 * buttonDataSize + buttonData 265 | mbuttonQuit equ 14 * buttonDataSize + buttonData 266 | 267 | noRepeat equ -1 268 | 269 | ;graphical and data resources 270 | ;note: info must be RELOCATED to this location. 271 | dataLocation equ saveSScreen 272 | 273 | ;save file consts 274 | savKeys equ 0 275 | savMisc equ 60 ;base for various small pieces of info 276 | savLockStart equ savMisc + 0 277 | savSpawnStart equ savMisc + 1 278 | savDASStart equ savMisc + 2 279 | savThemeBlock equ savMisc + 4 280 | savThemeColor equ savMisc + 5 281 | savThemeBack equ savMisc + 6 282 | savThemeBGCol equ savMisc + 7 283 | savUnknown equ savMisc + 8 ;to 13 284 | savFixedSize equ 74 ; size of button + misc 285 | savHighscore equ 74 286 | savHighSize equ 8 287 | savSize equ 512 ;save should not pass this size, kinda large. 288 | savScoreSize equ savSize - savHighScore ; 289 | 290 | userLockDelay equ saveData + savLockStart ; user-defined starting lock delay 291 | userSpawnDelay equ saveData + savSpawnStart ; user starting spawn delay 292 | userDASDelay equ saveData + savDASStart ; user DAS start 293 | themeBlock equ saveData + savThemeBlock 294 | themeColor equ saveData + savThemeColor 295 | themeBack equ saveData + savThemeBack 296 | themeBGColor equ saveData + savThemeBGCol 297 | 298 | ;drawing stuff 299 | drawMinoErase equ 0 300 | drawMinoHalf equ 1 301 | drawMinoDark equ 2 302 | ;drawMinoFromPTR equ 3 ;no longer useful 303 | 304 | ;bit set/reset when an object must be updated 305 | redrawObjBit equ 7 306 | 307 | ;variou equates for itemsInfo 308 | iDataType equ 0 ;type of data (use type~ to check) 309 | iDataX equ 1 ;x (16 bit) 310 | iDataXL equ 1 ;x low byte 311 | iDataXH equ 2 ;x high byte 312 | iDataY equ 3 ;y 313 | iDataA equ 4 ;a (used as color/palette for most) 314 | iDataPTR equ 5 ;ptr offset 315 | iDataPTRL equ 5 ;low byte 316 | iDataPTRH equ 6 ;high byte 317 | iDataPTRU equ 7 ;upper byte? 318 | iDataW equ 8 ;extra data (width, # digits) 319 | iDataH equ 9 ;extra data 2 (height) 320 | iDataSize equ 10 ;size of data struct 321 | 322 | iExtType equ 10 ; 323 | iExtTile equ 11 ;ptr to tile sprite data 324 | iExtTileset equ 14 ;ptr to sprite/palette pairs 325 | iExtMap equ 17 ;ptr to map data 326 | iExtSize equ 20 ;size of extended data 327 | 328 | 329 | ;object types, almost entirely used in tetrice_dat 330 | typeSprite1bpp equ 0 331 | typeSprite2bpp equ 1 332 | typeSprite4bpp equ 2 333 | typeSprite8bpp equ 3 334 | typeSprite1Half equ 4 335 | typeSprite2Half equ 5 336 | typeSprite4Half equ 6 337 | typeSprite8Half equ 7 338 | typeString equ 8 339 | typeNumber equ 9 340 | typeMenu equ 10 341 | typeNumber8 equ 11 342 | typeMap equ 12 343 | typeBox equ 13 344 | typeCustom equ 14 ;jumps to PTR provided, enables custom draw code 345 | typeCompound equ 15 ;uses pointer to another set of objects 346 | typeExtended equ 16 ;ignore 347 | typeIgnore equ 16 ;same as extended, use for clarity of purpose (ex. disable an object for some reason) 348 | 349 | ;data references used in main program 350 | ;all defined relative to SSS, so doesn't need actual data. 351 | drefSize equ 3 352 | refSize equ drefSize 353 | 354 | drefSprite equ drefSize * 0 + dataLocation 355 | drefFont equ drefSize * 1 + dataLocation 356 | drefBlocks equ drefSize * 2 + dataLocation 357 | drefBackground equ drefSize * 3 + dataLocation 358 | drefPalette equ drefSize * 4 + dataLocation 359 | drefMenu equ drefSize * 5 + dataLocation 360 | drefPause equ drefSize * 6 + dataLocation 361 | drefIInfo equ drefSize * 7 + dataLocation 362 | drefGameOver equ drefSize * 8 + dataLocation 363 | refField equ refSize * 9 + dataLocation 364 | refHold equ refSize * 10 + dataLocation 365 | refLevel equ refSize * 11 + dataLocation 366 | refScore equ refSize * 12 + dataLocation 367 | refLines equ refSize * 13 + dataLocation 368 | refPreview equ refSize * 14 + dataLocation 369 | refTimer equ refSize * 15 + dataLocation 370 | ;this is where the appvar/graphical data can set itself up, if necessary 371 | ;example: loading themes 372 | initDataStart equ refSize * 16 + dataLocation 373 | 374 | sp1bpp equ 0 375 | sp2bpp equ 1 376 | sp4bpp equ 2 377 | sp8bpp equ 3 378 | spHalf equ 4 ;OR with previous ~ default is 1bpp 379 | -------------------------------------------------------------------------------- /test.asm: -------------------------------------------------------------------------------- 1 | #include "includes/ti84pce.inc" 2 | #include "includes/tetrice.inc" 3 | 4 | .assume ADL=1 5 | .org userMem-2 6 | .db tExtTok,tAsm84CeCmp 7 | 8 | ;main program 9 | main: 10 | ld (preserveSP),sp 11 | 12 | ld de,fontData 13 | ld (smcFontDataPtr),de 14 | ld de,paletteData 15 | ld (smcPaletteDataPtr),de 16 | 17 | call initLCD ;screen init (requires data for palette) 18 | 19 | ld hl,12345678 20 | call badDivHLBy10 21 | ld (testNum),hl 22 | 23 | ld ix,testMenu 24 | call drawObject 25 | call swapVRamPTR 26 | test_select: 27 | call _GetCSC 28 | ld ix,0 29 | cp $21 30 | jr z, test_loop 31 | ld ix,testText 32 | cp $22 33 | jr z, test_loop 34 | ld ix,testNumber 35 | cp $1a 36 | jr z, test_loop 37 | ld ix,testSprite1 38 | cp $13 39 | jr z, test_loop 40 | ld ix,testSprite2 41 | cp $1b 42 | jr z, test_loop 43 | ld ix,testNumber8 44 | cp $1c 45 | jr z, test_loop 46 | ld ix,testBox 47 | cp $24 48 | jr z, test_loop 49 | ld ix,testSprite4 50 | cp $23 51 | jr z, test_loop 52 | ld ix, testMap 53 | cp $14 54 | jr z, test_loop 55 | ld ix, testSprite8 56 | cp $12 57 | jr z, test_loop 58 | 59 | jr test_select 60 | 61 | test_loop: 62 | call initLCD 63 | test_loop_actual: 64 | inc ix 65 | dec ix 66 | 67 | jr z, noTestObject 68 | call drawObjectNoReset 69 | noTestObject: 70 | push ix ;keep pointer to test object 71 | ld ix, testSpd 72 | call drawObjectNoReset 73 | call swapVRamPTR 74 | 75 | call _GetCSC 76 | pop ix 77 | 78 | cp skUp 79 | jr z,incTestQuantity 80 | cp skDown 81 | jr z,decTestQuantity 82 | cp skRight 83 | jr z,incTestQuantity2 84 | cp skLeft 85 | jr z,decTestQuantity2 86 | cp skAdd 87 | jr z,incTestQuantityPtr 88 | cp skSub 89 | jr z,decTestQuantityPtr 90 | 91 | cp skDel 92 | jr nz,test_loop_actual 93 | 94 | exit: 95 | ;restore state for ti-os 96 | call resetLCD 97 | ;call restoreKeyboard 98 | 99 | ld sp,(preserveSP) 100 | ret 101 | 102 | incTestQuantity2: 103 | inc (ix+iDataH) 104 | jr waitForNoKey 105 | 106 | decTestQuantity2: 107 | dec (ix+iDataH) 108 | jr waitForNoKey 109 | 110 | decTestQuantity: 111 | dec (ix+iDataW) 112 | jr waitForNoKey 113 | 114 | incTestQuantity: 115 | inc (ix+iDataW) 116 | jr waitForNoKey 117 | 118 | incTestQuantityPtr: 119 | inc (ix+iDataPTRL) 120 | jr waitForNoKey 121 | 122 | decTestQuantityPtr: 123 | dec (ix+iDataPTRL) 124 | jr waitForNoKey 125 | 126 | waitForNoKey: 127 | call _GetCSC 128 | or a,a 129 | jr nz,waitForNoKey 130 | jr test_loop_actual 131 | 132 | testString: 133 | .db "0123456789 Test str Hello world!",0 134 | 135 | testNum: 136 | .dl $123456 137 | 138 | preserveSP: 139 | .dl 0 140 | 141 | testCompound: 142 | .db typeCompound 143 | .dw 0 144 | .db 0 145 | .db 0 146 | .dl testAll 147 | .db 9, 0 148 | 149 | testAll: 150 | testSpd: 151 | .db typeNumber 152 | .dw 0 153 | .db 0 154 | .db 1 155 | .dl testNum; waitCounter 156 | .db 8, 4 157 | 158 | testText: 159 | .db typeString 160 | .dw 0 ; x 161 | .db 8 ; y 162 | .db 1 ; fg col 163 | .dl testString+20 ;ptr to text 164 | .db 0, 0 ; unused, bg col 165 | 166 | testNumber: 167 | .db typeNumber 168 | .dw 0 ; x 169 | .db 8 ; y 170 | .db 1 ; fg col 171 | .dl testNum ;ptr to number 172 | .db 8, 4 ; unused, bg col 173 | 174 | testSprite2: 175 | .db typeSprite2bpp 176 | .dw 0 ; x 177 | .db 8 ; y 178 | .db 12 ; palette offset 179 | .dl testSprite2bpp ;ptr to sprite data 180 | .db 3, 12 ; width (bytes), height (pixels) 181 | 182 | testSprite1: 183 | .db typeSprite1bpp 184 | .dw 0 ; x 185 | .db 8 ; y 186 | .db 1 ; palette offset 187 | .dl fontData + 1 + 264 ;ptr to sprite data 188 | .db 1, 8 ; width (bytes), height (pixels) 189 | 190 | testNumber8: 191 | .db typeNumber8 192 | .dw 0 ; x 193 | .db 8 ; y 194 | .db 1 ; fg col 195 | .dl testNum ;ptr to number 196 | .db 4, 4 ; unused, bg col 197 | 198 | testSprite4: 199 | .db typeSprite4bpp 200 | .dw 0 ; x 201 | .db 8 ; y 202 | .db 8 ; palette offset 203 | .dl testSprite4bpp ;ptr to sprite data 204 | .db 8, 16 ; width (bytes), height (pixels) 205 | 206 | testBox: 207 | .db typeBox 208 | .dw 0 ;x 209 | .db 8 ;y 210 | .db 5 ;color 211 | .dl 72 ;width 212 | .db 6, 40 ;bordercolor, height 213 | 214 | testMenu: 215 | .db typeMenu 216 | .dw 0 ; x 217 | .db 8 ; y 218 | .db 1 ; Text color 219 | .dl testMenuText ;ptr to menu items 220 | .db 10, 0 ;number of items, index of cursor object 221 | 222 | testMap: 223 | .db typeMap 224 | .dw 0 ; x 225 | .db 0 ; y 226 | .db 8 ; size of tile 227 | .db 0, 0, 0 ; flags (1 = use background block, 0 = don't), unused x2 228 | .db 26, 30 ;width (tiles), height (tiles) 229 | testMapExtended: 230 | .db typeExtended ;do not draw 231 | .dl smbTile 232 | .dl smbTileset 233 | .dl smbMap 234 | 235 | testSprite8: 236 | .db typeSprite8bpp 237 | .dw 0 ; x 238 | .db 8 ; y 239 | .db 0 ; palette offset 240 | .dl testSprite8bpp ;ptr to sprite data 241 | .db 16, 4 ; width (bytes), height (pixels) 242 | 243 | testMenuText: 244 | .db "0 - Baseline",0 245 | .db "1 - Text",0 246 | .db "2 - Number24",0 247 | .db "3 - Sprite8",0 248 | .db "4 - Sprite4",0 249 | .db "5 - Sprite2",0 250 | .db "6 - Sprite1",0 251 | .db "7 - Box",0 252 | .db "8 - Number8",0 253 | .db "9 - Map",0 254 | 255 | paletteData: 256 | .db $ff, $7f, $ef, $3d, $18, $63, $ff, $7f 257 | .db $ff, $7f, $3f, $33, $9d, $02, $b3, $01 258 | .db $ff, $7f, $9e, $25, $39, $1d, $53, $00 259 | .db $ff, $7f, $8d, $7e, $e4, $7d, $40, $69 260 | .db $ff, $7f, $ef, $7f, $c0, $7f, $e0, $62 261 | .db $ff, $7f, $8c, $17, $08, $0b, $45, $02 262 | .db $ff, $7f, $fb, $6d, $34, $51, $10, $40 263 | .db $ff, $7f, $8d, $7d, $64, $74, $00, $60 264 | .db $00, $00, $08, $21, $8c, $31, $31, $46 265 | .db $31, $46, $b1, $19, $50, $01, $ca, $00 266 | .db $31, $46, $d0, $10, $8d, $0c, $0a, $00 267 | .db $31, $46, $46, $45, $e1, $44, $a0, $38 268 | .db $31, $46, $08, $46, $00, $46, $80, $35 269 | .db $31, $46, $e6, $09, $a4, $01, $22, $01 270 | .db $31, $46, $ee, $38, $8a, $28, $08, $20 271 | .db $31, $46, $c6, $44, $21, $40, $00, $30 272 | ; 273 | ;.dw $00ff, $0ff0, $ff00, $f00f 274 | .dw $7fff, $1CE7, $3def, $0000 275 | .dw $7fff, $4f7d, $029d, $1d39 276 | .dw $7fff, $3a57, $1d39, $0000 277 | .dw $7fff, $7f21, $7de4, $4402 ;4 278 | .dw $7fff, $7fff, $7fc0, $7f21 279 | .dw $7fff, $5b83, $12c9, $3def 280 | .dw $7fff, $66fc, $5134, $0000 281 | .dw $7fff, $7eb9, $7464, $4402 ;8 282 | .dw $3def, $0c63, $1ce7, $0000 283 | .dw $3def, $25ae, $014e, $0c8c 284 | .dw $3def, $1d2b, $0c8c, $0000 285 | .dw $3def, $3d80, $3ce2, $2001 ;12 286 | .dw $3def, $3def, $3de0, $3d80 287 | .dw $3def, $2dc1, $0964, $1ce7 288 | .dw $3def, $316e, $288a, $0000 289 | .dw $3def, $3d4c, $3822, $2001 ;16 290 | .db $5f, $2e, $f6, $7e, $21, $65, $00, $00 291 | .db $5f, $2e, $ff, $7f, $ff, $1e, $00, $00 292 | .db $5f, $2e, $67, $7e, $21, $65, $00, $00 293 | .db $5f, $2e, $42, $43, $a0, $02, $00, $00 294 | .db $5f, $2e, $c4, $58, $64, $76, $a0, $35 295 | paletteDataEnd: 296 | 297 | testSprite2bpp: 298 | ;12x12 299 | .db $55, $55, $55, $6a, $6a, $54, $65, $59 300 | .db $54, $65, $59, $50, $6a, $59, $50, $55 301 | .db $55, $40, $55, $55, $00, $55, $54, $00 302 | .db $55, $50, $00, $55, $40, $3c, $50, $00 303 | .db $3c, $00, $00, $00 304 | 305 | testSprite4bpp: 306 | ;16x16 307 | .db $00, $00, $11, $11, $22, $22, $33, $33 308 | .db $00, $00, $11, $11, $22, $22, $33, $33 309 | .db $00, $00, $11, $11, $22, $22, $33, $33 310 | .db $00, $00, $11, $11, $22, $22, $33, $33 311 | .db $44, $44, $55, $55, $66, $66, $77, $77 312 | .db $44, $44, $55, $55, $66, $66, $77, $77 313 | .db $44, $44, $55, $55, $66, $66, $77, $77 314 | .db $44, $44, $55, $55, $66, $66, $77, $77 315 | .db $88, $88, $99, $99, $aa, $aa, $bb, $bb 316 | .db $88, $88, $99, $99, $aa, $aa, $bb, $bb 317 | .db $88, $88, $99, $99, $aa, $aa, $bb, $bb 318 | .db $88, $88, $99, $99, $aa, $aa, $bb, $bb 319 | .db $cc, $cc, $dd, $dd, $ee, $ee, $ff, $ff 320 | .db $cc, $cc, $dd, $dd, $ee, $ee, $ff, $ff 321 | .db $cc, $cc, $dd, $dd, $ee, $ee, $ff, $ff 322 | .db $cc, $cc, $dd, $dd, $ee, $ee, $ff, $ff 323 | 324 | testSprite8bpp: 325 | ;16x16 326 | .db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 327 | .db 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 328 | .db 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47 329 | .db 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63 330 | ;.db 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 331 | 332 | smbTile: 333 | .db sp2bpp 334 | .db $00, $00, $00, $00, $00, $00, $00, $00 335 | .db $00, $00, $00, $00, $00, $00, $00, $00 336 | .db $00, $0f, $00, $35, $03, $d5, $0d, $55 337 | .db $0d, $55, $0d, $55, $35, $69, $d5, $95 338 | .db $f0, $00, $5c, $00, $57, $00, $57, $30 339 | .db $55, $dc, $65, $57, $59, $57, $55, $57 340 | .db $00, $3f, $00, $d5, $03, $55, $01, $55 341 | .db $3d, $55, $d5, $55, $d5, $55, $35, $55 342 | .db $c3, $00, $cd, $c0, $75, $c0, $55, $cc 343 | .db $55, $77, $55, $57, $55, $57, $55, $5c 344 | .db $55, $55, $aa, $ab, $aa, $ab, $ff, $ff 345 | .db $ab, $aa, $ab, $aa, $ab, $aa, $ff, $ff 346 | .db $2a, $aa, $95, $55, $9d, $55, $95, $6a 347 | .db $95, $af, $95, $ad, $95, $ad, $95, $7d 348 | .db $aa, $a8, $55, $57, $55, $77, $a5, $57 349 | .db $e9, $57, $6b, $57, $6b, $57, $ab, $57 350 | .db $ff, $ff, $d5, $55, $ea, $a5, $d5, $a5 351 | .db $d5, $a5, $d5, $a5, $d5, $a5, $d5, $a5 352 | .db $ff, $ff, $55, $55, $55, $aa, $55, $96 353 | .db $55, $96, $55, $96, $55, $96, $55, $96 354 | .db $0d, $5a, $0d, $5a, $0d, $5a, $0d, $5a 355 | .db $0d, $5a, $0d, $5a, $0d, $5a, $0d, $5a 356 | .db $aa, $aa, $aa, $aa, $aa, $aa, $aa, $aa 357 | .db $aa, $aa, $aa, $aa, $aa, $aa, $aa, $aa 358 | .db $00, $00, $00, $00, $00, $00, $00, $00 359 | .db $00, $00, $00, $3f, $0f, $ea, $fa, $aa 360 | .db $00, $00, $00, $00, $00, $00, $00, $00 361 | .db $00, $00, $fc, $00, $ab, $f0, $aa, $af 362 | .db $00, $15, $00, $55, $00, $fe, $03, $ba 363 | .db $03, $be, $03, $ea, $00, $2a, $00, $f7 364 | .db $50, $00, $55, $40, $b8, $00, $ba, $80 365 | .db $ae, $a0, $bf, $c0, $aa, $00, $f0, $00 366 | .db $55, $55, $55, $55, $55, $55, $55, $55 367 | .db $55, $55, $55, $55, $55, $55, $55, $55 368 | .db $0d, $65, $03, $59, $00, $d6, $00, $d5 369 | .db $00, $3f, $00, $00, $00, $00, $00, $00 370 | .db $55, $55, $65, $55, $a9, $5a, $5a, $aa 371 | .db $55, $a5, $d5, $57, $3d, $5c, $03, $f0 372 | .db $65, $55, $95, $55, $a5, $59, $6a, $a5 373 | .db $5a, $95, $55, $55, $f5, $5f, $0f, $f0 374 | .db $55, $70, $55, $5c, $55, $57, $55, $54 375 | .db $55, $7c, $d7, $c0, $3c, $00, $00, $00 376 | .db $aa, $ab, $aa, $ab, $aa, $ab, $ff, $ff 377 | .db $ab, $aa, $ab, $aa, $ab, $aa, $ff, $ff 378 | .db $95, $56, $95, $56, $95, $55, $95, $56 379 | .db $95, $56, $9d, $55, $95, $55, $ff, $ff 380 | .db $bf, $57, $b5, $57, $f5, $57, $95, $57 381 | .db $b5, $57, $f5, $77, $55, $57, $ff, $ff 382 | .db $d5, $a5, $d5, $a5, $d5, $a5, $d5, $a5 383 | .db $d5, $a5, $d5, $a5, $ff, $ff, $0f, $ff 384 | .db $55, $96, $55, $96, $55, $96, $55, $96 385 | .db $55, $96, $55, $96, $ff, $ff, $ff, $ff 386 | .db $55, $65, $55, $65, $55, $65, $55, $65 387 | .db $55, $65, $55, $65, $55, $65, $55, $65 388 | .db $00, $03, $00, $0e, $00, $3a, $00, $ea 389 | .db $03, $aa, $0e, $aa, $3a, $aa, $ea, $aa 390 | .db $aa, $ba, $aa, $fe, $aa, $fe, $aa, $fe 391 | .db $be, $fe, $be, $ba, $be, $aa, $be, $aa 392 | .db $c0, $00, $b0, $00, $ac, $00, $ab, $00 393 | .db $aa, $c0, $aa, $b0, $aa, $ac, $aa, $ab 394 | .db $03, $f7, $0f, $f5, $0a, $d9, $0a, $95 395 | .db $0a, $55, $00, $54, $03, $f0, $0f, $f0 396 | .db $df, $c0, $5f, $f0, $67, $a0, $56, $a0 397 | .db $55, $a0, $15, $00, $0f, $c0, $0f, $f0 398 | .db $95, $55, $6a, $aa, $6a, $aa, $6a, $aa 399 | .db $6a, $aa, $6a, $aa, $6a, $aa, $6a, $aa 400 | .db $79, $56, $b6, $ab, $b6, $ab, $b6, $ab 401 | .db $b7, $ab, $bb, $fe, $b5, $57, $b6, $ab 402 | .db $6a, $aa, $6a, $aa, $fa, $aa, $5f, $aa 403 | .db $65, $ff, $6a, $57, $6a, $ab, $bf, $fe 404 | .db $b6, $ab, $b6, $ab, $da, $ab, $da, $ab 405 | .db $6a, $ab, $6a, $ab, $6a, $af, $7f, $fe 406 | 407 | smbTileset: 408 | .db $00, $50 409 | .db $01, $44 410 | .db $02, $44 411 | .db $03, $44 412 | .db $04, $44 413 | .db $05, $40 414 | .db $06, $48 415 | .db $07, $48 416 | .db $08, $4c 417 | .db $09, $4c 418 | .db $0a, $4c 419 | .db $0b, $4c 420 | .db $0c, $4c 421 | .db $0d, $4c 422 | .db $0e, $50 423 | .db $0f, $50 424 | .db $10, $44 425 | .db $11, $44 426 | .db $12, $44 427 | .db $13, $44 428 | .db $14, $44 429 | .db $15, $48 430 | .db $16, $48 431 | .db $17, $48 432 | .db $18, $4c 433 | .db $19, $4c 434 | .db $1a, $4c 435 | .db $1b, $4c 436 | .db $1c, $4c 437 | .db $1d, $4c 438 | .db $1e, $50 439 | .db $1f, $50 440 | .db $03, $4c 441 | .db $01, $4c 442 | .db $02, $4c 443 | .db $04, $4c 444 | .db $10, $4c 445 | .db $20, $40 446 | .db $21, $40 447 | .db $22, $40 448 | .db $23, $40 449 | 450 | smbMap: 451 | .db $00, $00, $00, $00, $00, $00, $00, $00 452 | .db $00, $00, $00, $00, $00, $00, $00, $00 453 | .db $00, $00, $00, $00, $00, $00, $00, $00 454 | .db $00, $00 455 | .db $00, $00, $00, $00, $00, $00, $00, $00 456 | .db $00, $00, $00, $00, $00, $00, $00, $00 457 | .db $00, $00, $00, $00, $00, $00, $00, $00 458 | .db $00, $00 459 | .db $00, $00, $00, $00, $00, $00, $00, $00 460 | .db $00, $00, $00, $00, $00, $00, $00, $00 461 | .db $00, $00, $00, $00, $00, $00, $00, $00 462 | .db $00, $00 463 | .db $00, $00, $00, $00, $00, $00, $00, $00 464 | .db $00, $00, $00, $00, $00, $00, $00, $00 465 | .db $00, $00, $00, $00, $00, $00, $00, $00 466 | .db $00, $00 467 | .db $00, $00, $00, $00, $00, $00, $00, $00 468 | .db $01, $02, $00, $00, $00, $00, $00, $00 469 | .db $00, $00, $00, $00, $00, $00, $00, $00 470 | .db $00, $00 471 | .db $00, $00, $00, $00, $00, $00, $00, $03 472 | .db $10, $10, $04, $00, $00, $00, $00, $00 473 | .db $00, $00, $00, $00, $00, $00, $00, $00 474 | .db $00, $00 475 | .db $00, $00, $00, $00, $00, $00, $00, $11 476 | .db $12, $13, $14, $00, $00, $00, $00, $00 477 | .db $00, $00, $00, $00, $00, $00, $00, $00 478 | .db $01, $02 479 | .db $00, $00, $00, $00, $00, $00, $00, $00 480 | .db $00, $00, $00, $00, $00, $00, $00, $00 481 | .db $00, $00, $00, $00, $00, $00, $00, $03 482 | .db $10, $10 483 | .db $00, $00, $00, $00, $00, $00, $00, $00 484 | .db $00, $00, $00, $00, $00, $00, $00, $00 485 | .db $00, $00, $00, $00, $00, $00, $00, $11 486 | .db $12, $13 487 | .db $00, $00, $00, $00, $00, $00, $00, $00 488 | .db $00, $00, $00, $00, $00, $00, $00, $00 489 | .db $00, $00, $00, $00, $00, $00, $00, $00 490 | .db $00, $00 491 | .db $00, $00, $00, $00, $00, $00, $00, $00 492 | .db $00, $00, $00, $00, $06, $07, $00, $00 493 | .db $00, $00, $00, $00, $00, $00, $00, $00 494 | .db $00, $00 495 | .db $00, $00, $00, $00, $00, $00, $00, $00 496 | .db $00, $00, $00, $00, $16, $17, $00, $00 497 | .db $00, $00, $00, $00, $00, $00, $00, $00 498 | .db $00, $00 499 | .db $00, $00, $00, $00, $00, $00, $00, $00 500 | .db $00, $00, $00, $00, $00, $00, $00, $00 501 | .db $00, $00, $00, $00, $00, $00, $00, $00 502 | .db $00, $00 503 | .db $00, $00, $00, $00, $00, $00, $00, $00 504 | .db $00, $00, $00, $00, $00, $00, $00, $00 505 | .db $00, $00, $00, $00, $00, $00, $00, $00 506 | .db $00, $00 507 | .db $00, $00, $00, $00, $00, $00, $00, $00 508 | .db $00, $00, $00, $00, $00, $00, $00, $00 509 | .db $00, $00, $00, $00, $00, $00, $00, $00 510 | .db $00, $00 511 | .db $00, $00, $00, $00, $00, $00, $00, $00 512 | .db $00, $00, $00, $00, $00, $00, $00, $00 513 | .db $00, $00, $00, $00, $00, $00, $00, $00 514 | .db $00, $00 515 | .db $00, $00, $00, $00, $00, $00, $00, $00 516 | .db $00, $00, $00, $00, $00, $00, $00, $00 517 | .db $00, $00, $00, $00, $00, $00, $00, $00 518 | .db $00, $00 519 | .db $00, $00, $00, $00, $00, $00, $00, $00 520 | .db $00, $00, $00, $00, $00, $00, $00, $00 521 | .db $00, $00, $00, $00, $00, $00, $00, $00 522 | .db $00, $00 523 | .db $06, $07, $00, $00, $00, $00, $00, $00 524 | .db $05, $05, $06, $07, $05, $05, $06, $07 525 | .db $05, $05, $00, $00, $00, $00, $00, $00 526 | .db $00, $00 527 | .db $16, $17, $00, $00, $00, $00, $00, $00 528 | .db $15, $15, $16, $17, $15, $15, $16, $17 529 | .db $15, $15, $00, $00, $00, $00, $00, $00 530 | .db $00, $00 531 | .db $00, $00, $00, $00, $00, $00, $00, $00 532 | .db $00, $00, $00, $00, $00, $00, $00, $00 533 | .db $00, $00, $00, $00, $00, $00, $00, $00 534 | .db $00, $00 535 | .db $00, $00, $00, $00, $00, $00, $00, $00 536 | .db $00, $00, $00, $00, $00, $00, $00, $00 537 | .db $00, $00, $00, $00, $00, $00, $00, $00 538 | .db $00, $00 539 | .db $00, $00, $00, $00, $00, $00, $00, $00 540 | .db $00, $00, $00, $00, $00, $00, $00, $00 541 | .db $00, $00, $00, $00, $00, $00, $00, $00 542 | .db $08, $09 543 | .db $00, $00, $0c, $0d, $00, $00, $00, $00 544 | .db $00, $00, $00, $00, $00, $00, $00, $00 545 | .db $00, $00, $00, $00, $00, $00, $00, $00 546 | .db $18, $19 547 | .db $00, $1b, $0b, $1c, $1d, $00, $00, $00 548 | .db $0e, $0f, $00, $00, $00, $00, $00, $00 549 | .db $21, $22, $00, $00, $00, $00, $00, $00 550 | .db $0a, $1a 551 | .db $1b, $0b, $0b, $0b, $0b, $1d, $00, $00 552 | .db $1e, $1f, $00, $00, $00, $00, $00, $20 553 | .db $24, $24, $23, $00, $00, $00, $00, $00 554 | .db $0a, $1a 555 | .db $25, $26, $25, $26, $25, $26, $25, $26 556 | .db $25, $26, $25, $26, $25, $26, $25, $26 557 | .db $25, $26, $25, $26, $25, $26, $25, $26 558 | .db $25, $26 559 | .db $27, $28, $27, $28, $27, $28, $27, $28 560 | .db $27, $28, $27, $28, $27, $28, $27, $28 561 | .db $27, $28, $27, $28, $27, $28, $27, $28 562 | .db $27, $28 563 | .db $25, $26, $25, $26, $25, $26, $25, $26 564 | .db $25, $26, $25, $26, $25, $26, $25, $26 565 | .db $25, $26, $25, $26, $25, $26, $25, $26 566 | .db $25, $26 567 | .db $27, $28, $27, $28, $27, $28, $27, $28 568 | .db $27, $28, $27, $28, $27, $28, $27, $28 569 | .db $27, $28, $27, $28, $27, $28, $27, $28 570 | .db $27, $28 571 | 572 | fontData: 573 | ;bits per pixel 574 | .db sp1bpp 575 | ;actual font data 576 | .db $00 577 | .db $00 578 | .db $00 579 | .db $00 580 | .db $00 581 | .db $00 582 | .db $00 583 | .db $00 584 | .db $00 585 | .db $18 586 | .db $18 587 | .db $18 588 | .db $18 589 | .db $00 590 | .db $18 591 | .db $00 592 | .db $00 593 | .db $6c 594 | .db $6c 595 | .db $24 596 | .db $00 597 | .db $00 598 | .db $00 599 | .db $00 600 | .db $00 601 | .db $6c 602 | .db $7e 603 | .db $6c 604 | .db $6c 605 | .db $7e 606 | .db $6c 607 | .db $00 608 | .db $18 609 | .db $3c 610 | .db $5a 611 | .db $38 612 | .db $1c 613 | .db $5a 614 | .db $3c 615 | .db $18 616 | .db $00 617 | .db $66 618 | .db $6c 619 | .db $18 620 | .db $18 621 | .db $36 622 | .db $66 623 | .db $00 624 | .db $00 625 | .db $38 626 | .db $6c 627 | .db $38 628 | .db $6a 629 | .db $6c 630 | .db $3a 631 | .db $00 632 | .db $00 633 | .db $18 634 | .db $18 635 | .db $08 636 | .db $00 637 | .db $00 638 | .db $00 639 | .db $00 640 | .db $00 641 | .db $18 642 | .db $30 643 | .db $30 644 | .db $30 645 | .db $30 646 | .db $18 647 | .db $00 648 | .db $00 649 | .db $18 650 | .db $0c 651 | .db $0c 652 | .db $0c 653 | .db $0c 654 | .db $18 655 | .db $00 656 | .db $00 657 | .db $66 658 | .db $3c 659 | .db $7e 660 | .db $7e 661 | .db $3c 662 | .db $66 663 | .db $00 664 | .db $00 665 | .db $18 666 | .db $18 667 | .db $7e 668 | .db $7e 669 | .db $18 670 | .db $18 671 | .db $00 672 | .db $00 673 | .db $00 674 | .db $00 675 | .db $00 676 | .db $18 677 | .db $18 678 | .db $10 679 | .db $00 680 | .db $00 681 | .db $00 682 | .db $00 683 | .db $7e 684 | .db $7e 685 | .db $00 686 | .db $00 687 | .db $00 688 | .db $00 689 | .db $00 690 | .db $00 691 | .db $00 692 | .db $00 693 | .db $18 694 | .db $18 695 | .db $00 696 | .db $00 697 | .db $06 698 | .db $0c 699 | .db $18 700 | .db $18 701 | .db $30 702 | .db $60 703 | .db $00 704 | numbers: 705 | .db $00 706 | .db $3c 707 | .db $66 708 | .db $66 709 | .db $66 710 | .db $66 711 | .db $3c 712 | .db $00 713 | .db $00 714 | .db $18 715 | .db $78 716 | .db $18 717 | .db $18 718 | .db $18 719 | .db $7e 720 | .db $00 721 | .db $00 722 | .db $3c 723 | .db $66 724 | .db $0c 725 | .db $18 726 | .db $30 727 | .db $7e 728 | .db $00 729 | .db $00 730 | .db $3c 731 | .db $66 732 | .db $1c 733 | .db $06 734 | .db $66 735 | .db $3c 736 | .db $00 737 | .db $00 738 | .db $66 739 | .db $66 740 | .db $7e 741 | .db $06 742 | .db $06 743 | .db $06 744 | .db $00 745 | .db $00 746 | .db $7e 747 | .db $60 748 | .db $7c 749 | .db $06 750 | .db $06 751 | .db $7c 752 | .db $00 753 | .db $00 754 | .db $3c 755 | .db $60 756 | .db $7c 757 | .db $66 758 | .db $66 759 | .db $3c 760 | .db $00 761 | .db $00 762 | .db $7e 763 | .db $06 764 | .db $06 765 | .db $0c 766 | .db $0c 767 | .db $0c 768 | .db $00 769 | .db $00 770 | .db $3c 771 | .db $66 772 | .db $3c 773 | .db $7e 774 | .db $66 775 | .db $3c 776 | .db $00 777 | .db $00 778 | .db $3c 779 | .db $66 780 | .db $66 781 | .db $3e 782 | .db $06 783 | .db $3c 784 | .db $00 785 | .db $00 786 | .db $18 787 | .db $18 788 | .db $00 789 | .db $00 790 | .db $18 791 | .db $18 792 | .db $00 793 | .db $00 794 | .db $18 795 | .db $18 796 | .db $00 797 | .db $18 798 | .db $18 799 | .db $10 800 | .db $00 801 | .db $00 802 | .db $06 803 | .db $1e 804 | .db $78 805 | .db $78 806 | .db $1e 807 | .db $06 808 | .db $00 809 | .db $00 810 | .db $7e 811 | .db $7e 812 | .db $00 813 | .db $00 814 | .db $7e 815 | .db $7e 816 | .db $00 817 | .db $00 818 | .db $60 819 | .db $78 820 | .db $1e 821 | .db $1e 822 | .db $78 823 | .db $60 824 | .db $00 825 | .db $00 826 | .db $3c 827 | .db $66 828 | .db $06 829 | .db $1c 830 | .db $00 831 | .db $18 832 | .db $00 833 | .db $00 834 | .db $3c 835 | .db $66 836 | .db $6e 837 | .db $6a 838 | .db $64 839 | .db $30 840 | .db $00 841 | .db $00 842 | .db $3c 843 | .db $66 844 | .db $7e 845 | .db $66 846 | .db $66 847 | .db $66 848 | .db $00 849 | .db $00 850 | .db $7c 851 | .db $66 852 | .db $7c 853 | .db $66 854 | .db $66 855 | .db $7c 856 | .db $00 857 | .db $00 858 | .db $3c 859 | .db $66 860 | .db $60 861 | .db $60 862 | .db $66 863 | .db $3c 864 | .db $00 865 | .db $00 866 | .db $7c 867 | .db $66 868 | .db $66 869 | .db $66 870 | .db $66 871 | .db $7c 872 | .db $00 873 | .db $00 874 | .db $7e 875 | .db $60 876 | .db $78 877 | .db $60 878 | .db $60 879 | .db $7e 880 | .db $00 881 | .db $00 882 | .db $7e 883 | .db $60 884 | .db $78 885 | .db $60 886 | .db $60 887 | .db $60 888 | .db $00 889 | .db $00 890 | .db $3c 891 | .db $66 892 | .db $60 893 | .db $6e 894 | .db $66 895 | .db $3c 896 | .db $00 897 | .db $00 898 | .db $66 899 | .db $66 900 | .db $7e 901 | .db $66 902 | .db $66 903 | .db $66 904 | .db $00 905 | .db $00 906 | .db $7e 907 | .db $18 908 | .db $18 909 | .db $18 910 | .db $18 911 | .db $7e 912 | .db $00 913 | .db $00 914 | .db $1e 915 | .db $06 916 | .db $06 917 | .db $06 918 | .db $66 919 | .db $3c 920 | .db $00 921 | .db $00 922 | .db $66 923 | .db $6c 924 | .db $78 925 | .db $6c 926 | .db $66 927 | .db $66 928 | .db $00 929 | .db $00 930 | .db $60 931 | .db $60 932 | .db $60 933 | .db $60 934 | .db $60 935 | .db $7e 936 | .db $00 937 | .db $00 938 | .db $66 939 | .db $7e 940 | .db $7e 941 | .db $7e 942 | .db $66 943 | .db $66 944 | .db $00 945 | .db $00 946 | .db $66 947 | .db $76 948 | .db $7e 949 | .db $6e 950 | .db $66 951 | .db $66 952 | .db $00 953 | .db $00 954 | .db $3c 955 | .db $66 956 | .db $66 957 | .db $66 958 | .db $66 959 | .db $3c 960 | .db $00 961 | .db $00 962 | .db $7c 963 | .db $66 964 | .db $7c 965 | .db $60 966 | .db $60 967 | .db $60 968 | .db $00 969 | .db $00 970 | .db $3c 971 | .db $66 972 | .db $66 973 | .db $66 974 | .db $7c 975 | .db $3e 976 | .db $00 977 | .db $00 978 | .db $7c 979 | .db $66 980 | .db $7c 981 | .db $66 982 | .db $66 983 | .db $66 984 | .db $00 985 | .db $00 986 | .db $3c 987 | .db $60 988 | .db $3c 989 | .db $06 990 | .db $66 991 | .db $3c 992 | .db $00 993 | .db $00 994 | .db $7e 995 | .db $18 996 | .db $18 997 | .db $18 998 | .db $18 999 | .db $18 1000 | .db $00 1001 | .db $00 1002 | .db $66 1003 | .db $66 1004 | .db $66 1005 | .db $66 1006 | .db $66 1007 | .db $3c 1008 | .db $00 1009 | .db $00 1010 | .db $66 1011 | .db $66 1012 | .db $3c 1013 | .db $3c 1014 | .db $18 1015 | .db $18 1016 | .db $00 1017 | .db $00 1018 | .db $66 1019 | .db $66 1020 | .db $66 1021 | .db $7e 1022 | .db $7e 1023 | .db $66 1024 | .db $00 1025 | .db $00 1026 | .db $66 1027 | .db $3c 1028 | .db $18 1029 | .db $18 1030 | .db $3c 1031 | .db $66 1032 | .db $00 1033 | .db $00 1034 | .db $66 1035 | .db $66 1036 | .db $3c 1037 | .db $18 1038 | .db $18 1039 | .db $18 1040 | .db $00 1041 | .db $00 1042 | .db $7e 1043 | .db $06 1044 | .db $1c 1045 | .db $38 1046 | .db $60 1047 | .db $7e 1048 | .db $00 1049 | .db $00 1050 | .db $1c 1051 | .db $18 1052 | .db $18 1053 | .db $18 1054 | .db $18 1055 | .db $1c 1056 | .db $00 1057 | .db $00 1058 | .db $60 1059 | .db $30 1060 | .db $18 1061 | .db $18 1062 | .db $0c 1063 | .db $06 1064 | .db $00 1065 | .db $00 1066 | .db $38 1067 | .db $18 1068 | .db $18 1069 | .db $18 1070 | .db $18 1071 | .db $38 1072 | .db $00 1073 | .db $00 1074 | .db $18 1075 | .db $18 1076 | .db $3c 1077 | .db $3c 1078 | .db $66 1079 | .db $66 1080 | .db $00 1081 | .db $00 1082 | .db $00 1083 | .db $00 1084 | .db $00 1085 | .db $00 1086 | .db $00 1087 | .db $7e 1088 | .db $00 1089 | .db $00 1090 | .db $30 1091 | .db $18 1092 | .db $0c 1093 | .db $00 1094 | .db $00 1095 | .db $00 1096 | .db $00 1097 | .db $00 1098 | .db $00 1099 | .db $3c 1100 | .db $06 1101 | .db $3e 1102 | .db $66 1103 | .db $3e 1104 | .db $00 1105 | .db $00 1106 | .db $60 1107 | .db $60 1108 | .db $7c 1109 | .db $66 1110 | .db $66 1111 | .db $7c 1112 | .db $00 1113 | .db $00 1114 | .db $00 1115 | .db $3c 1116 | .db $66 1117 | .db $60 1118 | .db $66 1119 | .db $3c 1120 | .db $00 1121 | .db $00 1122 | .db $06 1123 | .db $06 1124 | .db $3e 1125 | .db $66 1126 | .db $66 1127 | .db $3e 1128 | .db $00 1129 | .db $00 1130 | .db $00 1131 | .db $3c 1132 | .db $66 1133 | .db $7e 1134 | .db $60 1135 | .db $3c 1136 | .db $00 1137 | .db $00 1138 | .db $0e 1139 | .db $18 1140 | .db $7e 1141 | .db $18 1142 | .db $18 1143 | .db $18 1144 | .db $00 1145 | .db $00 1146 | .db $3e 1147 | .db $66 1148 | .db $66 1149 | .db $3e 1150 | .db $06 1151 | .db $3c 1152 | .db $00 1153 | .db $00 1154 | .db $60 1155 | .db $60 1156 | .db $7c 1157 | .db $66 1158 | .db $66 1159 | .db $66 1160 | .db $00 1161 | .db $00 1162 | .db $18 1163 | .db $00 1164 | .db $18 1165 | .db $18 1166 | .db $18 1167 | .db $18 1168 | .db $00 1169 | .db $00 1170 | .db $18 1171 | .db $00 1172 | .db $18 1173 | .db $18 1174 | .db $18 1175 | .db $70 1176 | .db $00 1177 | .db $00 1178 | .db $60 1179 | .db $66 1180 | .db $6c 1181 | .db $78 1182 | .db $6c 1183 | .db $66 1184 | .db $00 1185 | .db $00 1186 | .db $18 1187 | .db $18 1188 | .db $18 1189 | .db $18 1190 | .db $18 1191 | .db $18 1192 | .db $00 1193 | .db $00 1194 | .db $00 1195 | .db $7c 1196 | .db $7e 1197 | .db $7e 1198 | .db $7e 1199 | .db $66 1200 | .db $00 1201 | .db $00 1202 | .db $00 1203 | .db $7c 1204 | .db $66 1205 | .db $66 1206 | .db $66 1207 | .db $66 1208 | .db $00 1209 | .db $00 1210 | .db $00 1211 | .db $3c 1212 | .db $66 1213 | .db $66 1214 | .db $66 1215 | .db $3c 1216 | .db $00 1217 | .db $00 1218 | .db $7c 1219 | .db $66 1220 | .db $66 1221 | .db $7c 1222 | .db $60 1223 | .db $60 1224 | .db $00 1225 | .db $00 1226 | .db $3e 1227 | .db $66 1228 | .db $66 1229 | .db $3e 1230 | .db $06 1231 | .db $06 1232 | .db $00 1233 | .db $00 1234 | .db $00 1235 | .db $7c 1236 | .db $66 1237 | .db $60 1238 | .db $60 1239 | .db $60 1240 | .db $00 1241 | .db $00 1242 | .db $00 1243 | .db $3c 1244 | .db $60 1245 | .db $3c 1246 | .db $06 1247 | .db $7c 1248 | .db $00 1249 | .db $00 1250 | .db $18 1251 | .db $18 1252 | .db $7e 1253 | .db $18 1254 | .db $18 1255 | .db $18 1256 | .db $00 1257 | .db $00 1258 | .db $00 1259 | .db $66 1260 | .db $66 1261 | .db $66 1262 | .db $66 1263 | .db $3e 1264 | .db $00 1265 | .db $00 1266 | .db $00 1267 | .db $66 1268 | .db $66 1269 | .db $66 1270 | .db $3c 1271 | .db $18 1272 | .db $00 1273 | .db $00 1274 | .db $00 1275 | .db $66 1276 | .db $7e 1277 | .db $7e 1278 | .db $7e 1279 | .db $3e 1280 | .db $00 1281 | .db $00 1282 | .db $00 1283 | .db $66 1284 | .db $3c 1285 | .db $18 1286 | .db $3c 1287 | .db $66 1288 | .db $00 1289 | .db $00 1290 | .db $00 1291 | .db $66 1292 | .db $66 1293 | .db $3e 1294 | .db $06 1295 | .db $3c 1296 | .db $00 1297 | .db $00 1298 | .db $00 1299 | .db $7e 1300 | .db $0c 1301 | .db $18 1302 | .db $30 1303 | .db $7e 1304 | .db $00 1305 | .db $00 1306 | .db $0e 1307 | .db $18 1308 | .db $70 1309 | .db $70 1310 | .db $18 1311 | .db $0e 1312 | .db $00 1313 | .db $00 1314 | .db $18 1315 | .db $18 1316 | .db $18 1317 | .db $18 1318 | .db $18 1319 | .db $18 1320 | .db $00 1321 | .db $00 1322 | .db $70 1323 | .db $18 1324 | .db $0e 1325 | .db $0e 1326 | .db $18 1327 | .db $70 1328 | .db $00 1329 | .db $00 1330 | .db $00 1331 | .db $30 1332 | .db $5a 1333 | .db $0c 1334 | .db $00 1335 | .db $00 1336 | .db $00 1337 | .db $00 1338 | .db $10 1339 | .db $20 1340 | .db $7e 1341 | .db $20 1342 | .db $10 1343 | .db $00 1344 | .db $00 1345 | fontDataEnd: 1346 | 1347 | 1348 | -------------------------------------------------------------------------------- /graphic.asm: -------------------------------------------------------------------------------- 1 | 2 | ;initialize 8bpp mode and palette 3 | initLCD: 4 | call _RunIndicOff 5 | 6 | ;intialize palette from data 7 | smcPaletteDataPtr=$+1 8 | ld hl, $000000 9 | ld de, $e30200 10 | ld bc, 512 ;undefined colors likely never used 11 | ldir 12 | 13 | ld hl, lcdBpp8 | lcdPwr | lcdBgr | lcdIntFront 14 | ld (mpLcdCtrl),hl 15 | ;following change based on ;https://www.cemetech.net/forum/viewtopic.php?t=13695&start=0 16 | ld a,4 17 | ld (mpLcdIcr),a 18 | 19 | clearLCD: 20 | ld hl, vRam 21 | ld de, vRam+1 22 | ld bc, vRamEnd - vRam 23 | ld (hl),0 24 | ldir 25 | ret 26 | 27 | ;return lcd to normal state (bpp16) 28 | resetLCD: 29 | ;set default vram ptr 30 | ld hl,vRam 31 | ld (mpLcdUpbase),hl 32 | 33 | ld hl, lcdNormalMode 34 | ld (mpLcdCtrl), hl 35 | call _ClrLCDFull 36 | call _DrawStatusBar 37 | ret 38 | 39 | ;swaps ptrs between two vram buffers. 40 | ;this is for double-buffering and preventing 41 | ;flicker/tears/etc. 42 | vramOnPtr: 43 | .dl vRam 44 | vramOffPtr: 45 | .dl vRamSplit 46 | 47 | swapVRamPTR: 48 | ld de,(vramOffPtr) 49 | ld (mpLcdUpbase),de 50 | 51 | swapVRamPTRNoDisp: 52 | ld hl,(vramOnPtr) 53 | ld de,(vramOffPtr) 54 | ld (vramOnPtr),de 55 | ld (vramOffPtr),hl 56 | 57 | ;also modified based on 58 | ;https://www.cemetech.net/forum/viewtopic.php?t=13695&start=0 59 | waitLCDRIS: 60 | ld hl, mpLcdIcr 61 | set bLcdIntLNBU, (hl) 62 | ld l, mpLcdRis & $FF 63 | ; ld de,0 64 | ; ld (waitCounter),de 65 | wr: 66 | ; ld de,(waitCounter) 67 | ; inc de 68 | ; ld (waitCounter),de 69 | bit bLcdIntLNBU, (hl) 70 | jr z, wr 71 | ret 72 | 73 | ;waitCounter: 74 | ; .dl 0 75 | 76 | ;input: 77 | ;a = color 78 | ;de = x 79 | ;l = y 80 | ;b = sizey 81 | ;c = sizex 82 | ;clears a square area with the color in a 83 | ;note: preserves coords, sizexy 84 | ;this is so it can be used with sprites 85 | clearSprite: 86 | push hl 87 | push de 88 | push bc 89 | push de 90 | ld h,0 91 | ld d,h ;save HL = Y 92 | ld e,l 93 | add hl,hl ;2y 94 | add hl,hl ;4y 95 | add hl,de ;5y 96 | add hl,hl ;10y 97 | add hl,hl ;20y 98 | add hl,hl ;40y 99 | add hl,hl ;80y 100 | add hl,hl ;160y 101 | add hl,hl ;320y 102 | pop de 103 | add hl,de ;320Y+X 104 | ld de, (vramOffPTR) ;to second half of vRam, for double-buffering 105 | add hl,de ;320Y+x+vRam 106 | 107 | ld de,320 108 | putClearYLoop: 109 | push bc 110 | ld b,c 111 | push hl ;save ptr to graph 112 | putClearXLoop: 113 | ld (hl),a 114 | inc hl 115 | djnz putClearXLoop 116 | pop hl 117 | add hl,de ;move down 1 y unit 118 | pop bc 119 | djnz putClearYLoop 120 | pop bc 121 | pop de 122 | pop hl 123 | ret 124 | 125 | ;h=bpp id 126 | drawSpriteCustomBPP: 127 | push hl 128 | push de 129 | ld de,0 130 | ld e,h 131 | ld hl,ppbpp+1 ;past jp 132 | add hl,de 133 | add hl,de 134 | add hl,de 135 | add hl,de ;hl = ppbpp+1 + 4*bppid 136 | ld de,(hl) ;get ppbpp data 137 | ld hl,smcPutPixel+1 138 | ld (hl),de ;put ppbpp data to call 139 | pop de 140 | pop hl 141 | jr drawSpriteSetBPP 142 | ;inputs: 143 | ;ix = spritedataptr 144 | ;de = x 145 | ;h = bpp id/setting 146 | ;l = y 147 | ;b = sizey 148 | ;c = sizex (note: BYTES not PIXELS) 149 | ;a = spritePalette 150 | drawSprite: 151 | push de 152 | ld de, putPixel8bpp 153 | ld (smcPutPixel+1),de 154 | pop de 155 | drawSpriteSetBPP: 156 | bit 2, h 157 | jr z, noScale 158 | srl b ;half sizey 159 | noScale: 160 | push de 161 | ld de,0 162 | ld d,l 163 | push de 164 | pop hl ;256L 165 | srl d 166 | rr e 167 | srl d 168 | rr e 169 | add hl,de ;add 64L: 320L total 170 | pop de 171 | add hl,de ;320Y+X 172 | ld de, (vramOffPtr) ;to second half of vRam, for double-buffering 173 | add hl,de ;320Y+x+vRam 174 | ;hl=vramptr ix=data b=sizeY c=sizeX a=pal 175 | ;NEW: hl=data de=vramptr 176 | ex de,hl 177 | push ix 178 | pop hl 179 | putSpriteYLoop: 180 | push bc 181 | ld b,c ;size x still 182 | push de ;save ptr to vram 183 | putSpriteXLoop: 184 | push bc 185 | smcPutPixel: ;add 1 for CALL address 186 | jp 0 ;ppbpp + something 187 | putPixelReturn: 188 | pop bc 189 | djnz putSpriteXLoop 190 | ;hl=data de=vram 191 | ex de,hl ;de=data hl=vram 192 | pop hl 193 | ld bc,320 194 | add hl,bc ;move down 1 y unit 195 | ex de,hl 196 | pop bc 197 | djnz putSpriteYLoop 198 | ret 199 | 200 | ppbpp: 201 | jp putPixel1bpp 202 | jp putPixel2bpp 203 | jp putPixel4bpp 204 | jp putPixel8bpp 205 | jp put1bppHalfScale 206 | jp put2bppHalfScale 207 | jp put4bppHalfScale 208 | jp put8bppHalfScale 209 | 210 | ;a=pal 211 | ;hl=data ptr 212 | ;de=vram ptr 213 | ;speed: 16cc/px 214 | putPixel8bpp: 215 | ld b,a ;b=palette ;1 216 | ld a,(hl) ;pixel color ;2 217 | or a,a ;check if no color/transparent color ;1 218 | jr z,transPixel8 ;3 219 | add a,b ;add color to palette ofs ;1 220 | ld (de),a ;2 221 | transPixel8: 222 | ld a,b ;1 223 | inc de ;sprite data index ;1 224 | inc hl ;coords ;1 225 | jp putPixelReturn ;5 226 | 227 | ;a=pal 228 | ;hl=data ptr 229 | ;de=vram ptr 230 | put8bppHalfScale: 231 | push bc 232 | ld b,a ;b=palette 233 | ld a,(hl) ;pixel color 234 | cp 0 ;check if no color/transparent color 235 | jp z,transPixel8h 236 | add a,b ;add color to palette ofs 237 | ld (de),a 238 | transPixel8h: 239 | inc hl ;sprite data index 240 | inc hl 241 | inc de ;vram ptr 242 | ld a,b 243 | pop bc ;b=row c=width 244 | 245 | dec b 246 | jp nz,putPixelReturn ;return if not last x loc 247 | ;c is still the width of X 248 | ld b,c 249 | skipRow8h: 250 | inc hl ;add byte width to hl to skip next row 251 | djnz skipRow8h 252 | ;not very efficient but it's replacing actually drawing the entire row 253 | jp putPixelReturn 254 | 255 | ;a=pal 256 | ;hl=data ptr 257 | ;de=vram ptr 258 | ;speed: 17cc/px (34cc/2px) 259 | putPixel4bpp: 260 | ld c,a ;save palette ofs ;1 261 | ld a,(hl) ;get data ;2 262 | and $F0 ;2 263 | rrca ;1 264 | rrca ;1 265 | rrca ;1 266 | rrca ;1 267 | jr z, noPut1stPixel ;3 268 | add a,c ;add palette ofs to color ;1 269 | ld (de),a ;load first nibble + palette ofs ;2 270 | noPut1stPixel: ; 271 | inc de ;next coord ;1 272 | ; 273 | ld a,(hl) ;data again ;2 274 | and $0F ;can set z flag ;2 275 | jr z,noPut2ndPixel ;3 276 | add a,c ;add palette and color ;1 277 | ld (de),a ;2 278 | noPut2ndPixel: ; 279 | inc hl ;next data chunk ;1 280 | inc de ;next vram index ;1 281 | ld a,c ;1 282 | jp putPixelReturn ;5 283 | 284 | ;a=pal 285 | ;hl=data ptr 286 | ;de=vram ptr 287 | ;speed: ??cc/px 288 | put4bppHalfScale: 289 | push bc 290 | ld c,a ;save palette ofs 291 | ld a,(hl) 292 | srl a 293 | srl a 294 | srl a 295 | srl a 296 | jr z, noPutPixelh 297 | add a,c ;add palette ofs to color 298 | ld (de),a ;load nibble + palette ofs 299 | noPutPixelh: 300 | inc de ;next vram index 301 | inc hl ;next data chunk 302 | ld a,c 303 | pop bc 304 | 305 | dec b 306 | jp nz, putPixelReturn ;return if not last x loc 307 | ;c is still the width of X 308 | ld b,c 309 | skipRow4h: 310 | inc hl 311 | djnz skipRow4h 312 | jp putPixelReturn 313 | 314 | ;a=pal 315 | ;hl=data ptr 316 | ;de=vram ptr 317 | ;speed: ~21cc/px (86cc/4px) 318 | ;unrolled: ~15cc/px (61/4px) 319 | putPixel2bpp: 320 | ; ld ixl,a ;2 321 | ; ld a,(hl) ;2 322 | ; ld b,4 ;2 323 | ;putPixel2bit: ; 324 | ; rlca ;1*4 325 | ; rlca ;1*4 326 | ; ld c,a ;1*4 327 | ; and $03 ;2*4 328 | ; jr z, trans2bit ;3*4 329 | ; add a,ixl ;add pal and ofs ;2*4 330 | ; ld (de),a ;2*4 331 | ;trans2bit: ; 332 | ; ld a,c ;restore unmasked value ;1*4 333 | ; inc de ;1*4 334 | ; djnz putPixel2bit ;4*4 335 | ; ld a,ixl ;2 336 | ; inc hl ;1 337 | ; jp putPixelReturn ;5 338 | 339 | ld b,a ;1 340 | ld a,(hl) ;2 341 | rlca ;1*4 342 | rlca ;1*4 343 | ld c,a ;1*4 344 | and $03 ;2*4 345 | jr z,pp21 ;3*4 346 | add a,b ;1*4 347 | ld (de),a ;2*4 348 | pp21: 349 | ld a,c ;1*4 350 | inc de ;1*4 351 | rlca 352 | rlca 353 | ld c,a 354 | and $03 355 | jr z,pp22 356 | add a,b 357 | ld (de),a 358 | pp22: 359 | ld a,c 360 | inc de 361 | rlca 362 | rlca 363 | ld c,a 364 | and $03 365 | jr z,pp23 366 | add a,b 367 | ld (de),a 368 | pp23: 369 | ld a,c 370 | inc de 371 | rlca 372 | rlca 373 | ld c,a 374 | and $03 375 | jr z,pp24 376 | add a,b 377 | ld (de),a 378 | pp24: 379 | ld a,b 380 | inc de 381 | inc hl ;1 382 | jp putPixelReturn ;5 383 | 384 | 385 | ;a=pal 386 | ;hl=data ptr 387 | ;de=vram ptr 388 | ;speed: ??cc/px 389 | put2bppHalfScale: 390 | push bc 391 | ld c,(hl) 392 | push hl 393 | ld h,a ;save palette ofs 394 | ld b,2 395 | putPixel2h: 396 | xor a ;a=0 397 | rlc c 398 | rla 399 | rlc c 400 | rla ;get 2 bits from c into a 401 | rlc c 402 | rlc c ;skip next 2 bits 403 | or a 404 | jr z, trans2h 405 | add a,h ;add pal and ofs 406 | ld (de),a 407 | trans2h: 408 | inc de 409 | djnz putPixel2h 410 | ld a,h 411 | pop hl 412 | inc hl 413 | pop bc 414 | 415 | dec b 416 | jp nz, putPixelReturn ;return if b!=1 417 | ld b,c 418 | skipRow2h: 419 | inc hl 420 | djnz skipRow2h 421 | jp putPixelReturn 422 | 423 | ;a=palette ofs 424 | ;hl=data ptr 425 | ;de=vram ptr 426 | ;speed: ~13cc/px (102cc/8px) 427 | putPixel1bpp: 428 | ld c,a ;1 429 | ld a,(hl) ;2 430 | ex de,hl ;1 431 | ld b,8 ;2 432 | ;new: 433 | ;a=bit data 434 | ;b=pixel count 435 | ;c=palette 436 | putPixelBit: 437 | rlca ;get bit from a ;1*8 438 | ;if bit is zero, pixel is transparent. ; 439 | jr nc, noPutPixelBit ;skip to inc location ;3*8 440 | ld (hl),c ;save to location ;2*8 441 | noPutPixelBit: 442 | inc hl ;next ;1*8 443 | djnz putPixelBit ;4*8 444 | inc de ;done with this byte of data ;1 445 | ex de,hl ;1 446 | ld a,c ;1 447 | jp putPixelReturn ;5 448 | 449 | put1bppHalfScale: 450 | push bc 451 | ld c,(hl) 452 | ld b,4 453 | ;new: 454 | ;c=bit data 455 | ;b=pixel count 456 | putPixelBith: 457 | rlc c ;get bit from c 458 | ;if bit is zero, pixel is transparent. 459 | jr nc, noPutPixelBith ;skip to inc location 460 | ld (de),a ;save to location 461 | noPutPixelBith: 462 | inc de ;next 463 | rlc c 464 | djnz putPixelBith 465 | inc hl ;done with this byte of data 466 | pop bc 467 | 468 | dec b 469 | jp nz,putPixelReturn ;return if b!=1 470 | ld b,c 471 | skipRow1h: 472 | inc hl 473 | djnz skipRow1h 474 | jp putPixelReturn 475 | 476 | ;input: ix = info ptr, 1st elem. is # struct elems 477 | drawObjects: 478 | ld a,$00 ;nop 479 | jr drawObjs 480 | drawObjectsNoReset: 481 | ld a,$C9 ;ret 482 | ;jr drawObjs 483 | 484 | drawObjs: 485 | ld (smcRedrawReset),a 486 | ld b,(ix) 487 | inc ix 488 | drawAllObjects: 489 | push bc 490 | ;ix = info ptr 491 | call drawObject 492 | 493 | ld de,iDataSize 494 | add ix,de 495 | pop bc 496 | djnz drawAllObjects 497 | ret 498 | 499 | ;ix = info ptr, 500 | resetAllDrawCheck: 501 | ld b,(ix) 502 | inc ix 503 | ld de,iDataSize 504 | resAllObjects: 505 | res redrawObjBit,(ix+iDataType) 506 | add ix,de 507 | djnz resAllObjects 508 | ret 509 | 510 | ;draws all objects in subobject 511 | ;(lets only one redraw flag cover multiple items) 512 | drawCompound: 513 | ld a,(smcRedrawReset) 514 | ld b,(ix+iDataW) ; number of elements in compound 515 | ld ix,(ix+iDataPTR) ;now points to new set of objects (does not include number start) 516 | push af 517 | drawAllSubobjects: 518 | push bc 519 | call drawObjectNoReset 520 | ld de,iDataSize 521 | add ix,de 522 | pop bc 523 | djnz drawAllSubobjects 524 | pop af 525 | ld (smcRedrawReset),a 526 | ret 527 | 528 | drawObjectNoReset: 529 | ld a,$c9 ;ret = $c9 530 | ld (smcRedrawReset),a 531 | ;input: ix = data ptr to object 532 | ;note: only sets 7st bit 533 | drawObject: 534 | push ix 535 | call drawObjectJump 536 | pop ix 537 | ;cleanup from drawing object 538 | smcRedrawReset: 539 | ret ;either ret (no set) or nop (set) 540 | 541 | set redrawObjBit,(ix+iDataType) 542 | ret 543 | 544 | drawObjectJump: 545 | ld de,0 546 | ld e, (ix+iDataType) ;e is data type 547 | sla e 548 | ret c ;return if already drawn 549 | ; ret z ;also return if it should be ignored always 550 | sla e 551 | 552 | ld hl,drawJumps 553 | add hl,de ;jumps + 4e (since e is already *4 from 2x sla e) 554 | 555 | jp (hl) 556 | ret ;implied return from any of the jump methods 557 | 558 | ;jump table for various object types 559 | ;all should accept ix as a pointer to data 560 | drawJumps: 561 | ;various sprite types 562 | ld h,sp1bpp 563 | jr sharedDSO 564 | ld h,sp2bpp 565 | jr sharedDSO 566 | ld h,sp4bpp 567 | jr sharedDSO 568 | ld h,sp8bpp 569 | jr sharedDSO 570 | ld h,sp1bpp | spHalf 571 | jr sharedDSO 572 | ld h,sp2bpp | spHalf 573 | jr sharedDSO 574 | ld h,sp4bpp | spHalf 575 | jr sharedDSO 576 | ld h,sp8bpp | spHalf 577 | jr sharedDSO 578 | ; built on sprites 579 | jp drawText 580 | jp draw24BitNumber 581 | jp drawMenu 582 | jp draw8BitNumber 583 | jp drawMap 584 | ; other 585 | jp drawBox 586 | jp drawCustom 587 | jp drawCompound 588 | ret ; ignore this type (used for adding extra data within a second slot) 589 | nop 590 | nop 591 | nop 592 | 593 | 594 | sharedDSO: 595 | jp drawSpriteObj 596 | 597 | drawCustom: 598 | ld hl,(ix+iDataPTR) 599 | 600 | jp (hl) ;the rest is up to special drawing code 601 | 602 | blockDataPTR: 603 | .dl 0 604 | 605 | drawTextColor: 606 | .db 0 607 | drawTextBG: 608 | .db 0 609 | 610 | ;inputs: ix = data ptr 611 | drawText: 612 | or a,a 613 | sbc hl,hl 614 | ex de,hl 615 | sbc hl,hl ;de,hl=0 616 | 617 | ld e,(ix+iDataXL) 618 | ld d,(ix+iDataXH) 619 | ld l,(ix+iDataY) ;xy set 620 | ld a,(ix+iDataA) ;color 621 | ld c,(ix+iDataH) ;bg color 0=transparent 622 | ld ix,(ix+iDataPTR) ;this is now the string data ptr 623 | 624 | ;must be provided: 625 | ;ix - string data ptr 626 | ;hl - y 627 | ;de - x 628 | ;a - color 629 | ;c - bg color 630 | drawTextManual: 631 | ld (drawTextColor),a 632 | ld a,c 633 | ld (drawTextBG),a 634 | drawTextLoop: 635 | ld a,(ix) 636 | or a,a ;check null-terminated string 637 | jr z,textLoopEnd ;end string before stuff on stack 638 | push ix ;string data ptr 639 | push hl 640 | push de 641 | 642 | ;a = ofs 643 | sub 32 ;ascii adjust 644 | smcFontDataPtr=$+2 645 | ld ix,0 646 | ld h,(ix) ;bpp 647 | inc ix ;ix points to fontdata 648 | ld bc,0 649 | ld b,h 650 | inc b 651 | ld c,$08 652 | shiftCTXT: 653 | rlc c 654 | djnz shiftCTXT 655 | rrc c 656 | ;c=2^bpp*8 657 | ld b,a 658 | mlt bc ;bc = spdatasize * ofs 659 | 660 | add ix,bc ;fontData + 64a (character) 661 | 662 | ld b,8 663 | ld c,b ;size in PIXELS of char BACKGROUND width 664 | 665 | ld a,(drawTextBG) 666 | or a,a 667 | jr z,textTransBG 668 | push hl 669 | call clearSprite 670 | pop hl 671 | textTransBG: 672 | ld a,(drawTextColor) 673 | ld b,h 674 | inc b 675 | ld c,$80 676 | shiftLoopC: 677 | rlc c 678 | djnz shiftLoopC ;c is sprite width in BYTES 679 | ld b,8 ;sprite height 680 | ;h is bpp, l=y, de=x, ix=spdata 681 | call drawSpriteCustomBPP 682 | pop hl ;de, x coords 683 | ld de,8 684 | add hl,de ;add 8 685 | push hl 686 | pop de ;de = x+8 687 | pop hl ;y value (shouldn't change) 688 | pop ix ;string data ptr 689 | inc ix 690 | jr drawTextLoop 691 | textLoopEnd: 692 | ;de is the ending X location 693 | ;hl is unchanged 694 | ;ix points to 0 at end of string 695 | ;a is 0 696 | ret 697 | 698 | ;in: hl 699 | ;out: a,hl 700 | badDivHLby10: 701 | push ix 702 | push de 703 | 704 | ; hl->hlix 705 | push hl 706 | pop ix 707 | xor a,a 708 | sbc hl,hl ;hl=0 ix=lower24 709 | push ix ; will need later as "A" 710 | push hl \ push ix 711 | add ix,ix \ adc hl,hl 712 | add ix,ix \ adc hl,hl 713 | push hl \ push ix 714 | pop de \ pop bc 715 | add ix,ix \ adc hl,hl 716 | add ix,de \ adc hl,bc 717 | push hl \ push ix 718 | pop de \ pop bc 719 | ;1100 * hl -> ixhl, bcde 720 | ;TODO: use less precision for numbers that are smaller? 721 | ;Makes end result need to be shifted out of hlix for smaller values... 722 | ;constant binary constant or n precision loss past 723 | ;25 11001 0 430 724 | ;409 110011001 1 6830 725 | ;6553 1100110011001 2 109230 726 | ;104857 11001100110011001 3 1747630 727 | ;1677721 110011001100110011001 4 27962030 (i.e. never for 24bit numbers) 728 | ;smcDivShiftSize=$+1 729 | or 4 730 | ; jr z, noShift4Add12 731 | repeatShift4Add12: 732 | add ix,ix \ adc hl,hl 733 | add ix,ix \ adc hl,hl 734 | add ix,ix \ adc hl,hl 735 | add ix,ix \ adc hl,hl 736 | add ix,de \ adc hl,bc 737 | dec a 738 | jr nz, repeatShift4Add12 739 | noShift4Add12 740 | pop de \ pop bc 741 | add ix,ix \ adc hl,hl 742 | add ix,de \ adc hl,bc ;never carry because product < 2^48 743 | ;hlix = 1677721*A 744 | ;smcDivSmall=$ 745 | ; jr nc, noIxAdjust ;smc to jr c (never branch) 746 | ; ld a,ixh ;if 25*A, ix < ~11000, so 25*A/256 -> ixh 747 | ; ld l,a ;hl is 0 because small numbers only 748 | ;noIxAdjust: 749 | ex de,hl 750 | pop hl 751 | ;"B" de = 1677721*A//16777216 752 | ;"A" hl = A 753 | againSub: 754 | ld a,2 755 | againSubLoop: 756 | sbc hl,de ;A-1B 757 | sbc hl,de ;never carry because hl >= 10de 758 | sbc hl,de 759 | sbc hl,de ;A-4B 760 | sbc hl,de ;A-5B 761 | dec a ;never carry because catches z first 762 | jr nz, againSubLoop 763 | ; hl = A - 10B 764 | ld a,l 765 | cp 10 766 | jr c, noAdjust 767 | ; need to do A-10B-10 768 | sub 10 ;nc because a>=10 769 | inc de ;B=B+1 770 | noAdjust: 771 | ex de,hl 772 | ;hl = B 773 | ;a = A-10B or A-10B-10 774 | ; in other words: 775 | ;a = A % 10 776 | ;hl = A // 10 777 | pop de 778 | pop ix 779 | ret 780 | 781 | ;inputs: ix = data struct 782 | drawNumString: 783 | .db 0,0,0,0,0,0 784 | .db 0,0,0,0,0,0 ;12 bytes max 785 | .db 0 786 | draw8BitNumber: 787 | ld hl,(ix+iDataPTR) 788 | ld c,(hl) 789 | xor a,a 790 | sbc hl,hl 791 | ld l,c ;hl = number 792 | ; ld (smcDivShiftSize),a ;8bit numbers are within range for smallest precision 793 | ; ld a,$38 ; jr c (for small numbers) 794 | 795 | ;jump to shared code 796 | jr drawNumShared 797 | 798 | draw24BitNumber: 799 | ld hl,(ix+iDataPTR) 800 | 801 | ld hl,(hl) ;hl is number 802 | ; ld a,4 803 | ; ld (smcDivShiftSize),a 804 | ; ld a,$30 805 | 806 | drawNumShared: 807 | ; ld (smcDivSmall),a 808 | ld de,drawNumString+11 809 | ld b,(ix+iDataW) ;don't do extra divisions if we don't need more digits 810 | convToString: 811 | push bc 812 | call badDivHLBy10 813 | add a,48 814 | ld (de),a 815 | dec de 816 | pop bc 817 | djnz convToString ;a=0 is end of loop 818 | 819 | ld bc,0 820 | ld c,(ix+iDataW) 821 | ld hl,drawNumString+12 822 | or a,a 823 | sbc hl,bc 824 | push hl 825 | 826 | ld de,0 827 | ld e,(ix+iDataXL) 828 | ld d,(ix+iDataXH) 829 | ld hl,0 830 | ld l,(ix+iDataY) ;xy set 831 | ld a,(ix+iDataA) ;color 832 | ld c,(ix+iDataH) ;bg color 0=transparent 833 | pop ix ;string data ptr 834 | 835 | call drawTextManual 836 | ret 837 | 838 | ;ix = input 839 | drawSpriteObject: 840 | ld h,sp8bpp ;default 8bpp 841 | drawSpriteObj: 842 | ld a,h ;save bpp 843 | push ix 844 | ld hl,(ix+iDataPTR) 845 | push hl ;ptr to sprite data 846 | 847 | or a,a 848 | sbc hl,hl 849 | ex de,hl 850 | sbc hl,hl 851 | 852 | ld h,a ;get bpp 853 | ld l,(ix+iDataY) 854 | 855 | ld d,(ix+iDataXH) 856 | ld e,(ix+iDataXL) 857 | 858 | ld bc,0 859 | ld b,(ix+iDataH) 860 | ld c,(ix+iDataW) 861 | ld a,(ix+iDataA) 862 | 863 | pop ix 864 | call drawSpriteCustomBPP 865 | pop ix 866 | ret 867 | 868 | ;ix is ptr to input data 869 | drawBox: 870 | xor a,a ;a=0 used later 871 | sbc hl,hl 872 | ex de,hl 873 | sbc hl,hl 874 | 875 | ld h,(ix+iDataXH) 876 | ld l,(ix+iDataXL) 877 | ld d,(ix+iDataY) 878 | 879 | add hl,de ; x + 256y 880 | srl d 881 | rr e 882 | srl d 883 | rr e 884 | add hl,de ; x + 320y 885 | ld de, (vramOffPtr) 886 | add hl,de ;320Y+x+vRam 887 | 888 | ld b,(ix+iDataH) 889 | drawBoxYLoop: 890 | push bc 891 | ;check if y is max or 0 892 | ld a,b 893 | cp (ix+iDataH) 894 | jr z,isBorder 895 | cp 1 896 | jr z,isBorder 897 | ld a,(ix+iDataA) 898 | drawBorderReturn: 899 | ld bc,(ix+iDataPTR) 900 | push hl ;save ptr to graph 901 | drawBoxX: 902 | push hl 903 | pop de ;de = ptr to graph 904 | inc de ;hl=gptr, de=gptr+1 905 | ;bc is width of box 906 | ld (hl),a 907 | ldir 908 | ;end of drawBoxX 909 | ld a,(ix+iDataW) ;border color 910 | ld (hl),a 911 | pop hl ;restore old gptr 912 | ld (hl),a 913 | 914 | ld de,320 915 | add hl,de ;move down 1 y unit 916 | pop bc 917 | djnz drawBoxYLoop 918 | ret 919 | isBorder: 920 | ld a,(ix+iDataW) 921 | jr drawBorderReturn 922 | 923 | ;ix = data ptr input 924 | ;intended to perform initial draw of menu data 925 | ;output: ix = beginning of jumps/end of menu text 926 | drawMenu: 927 | ld hl,(ix+iDataPTR) 928 | push hl 929 | 930 | ld b,(ix+iDataW) ; # items 931 | or a,a 932 | sbc hl,hl 933 | ex de,hl 934 | sbc hl,hl 935 | ld l,(ix+iDataY) 936 | ld d,(ix+iDataXH) 937 | ld e,(ix+iDataXL) ;de, hl is (X,Y) coords 938 | 939 | ld a,(ix+iDataA) 940 | pop ix ;points to text data 941 | drawMenuItems: 942 | push bc 943 | push de ;x value 944 | push af ;color value 945 | ld c,0 ; no bg color 946 | call drawTextManual 947 | inc ix 948 | ld a,8 949 | add a,l 950 | ld l,a ;add 8 to y value 951 | pop af ;restore color value 952 | pop de ;restore old x value 953 | 954 | pop bc 955 | djnz drawMenuItems 956 | ;ix should point to just past end of text data 957 | ret 958 | 959 | menuDataPTR: 960 | .dl 0 961 | menuPTR: 962 | .dl 0 963 | cursorPTR: 964 | .dl 0 965 | 966 | ;input: 967 | ;ix is ptr to active display menudata 968 | activeMenu: 969 | call clearLCD 970 | xor a 971 | ld (menuSelection),a 972 | 973 | ld (menuDataPTR),ix 974 | inc ix ;go past # elements 975 | 976 | ;scan for typeMenu and read for data 977 | ld de,iDataSize 978 | menuScanMenu: 979 | ld a,(ix+iDataType) 980 | add ix,de 981 | cp typeMenu 982 | jr nz,menuScanMenu 983 | ld de,-iDataSize 984 | add ix,de ;ix - iDataSize ;z set => c reset 985 | ;ix points to first typeMenu object 986 | ld (menuPTR),ix 987 | 988 | ld b,(ix+iDataW) ;# text items 989 | ld hl,(ix+iDataPTR) 990 | scanToMenuJumps: 991 | ld a,(hl) 992 | inc hl 993 | or a,a 994 | jr nz,scanToMenuJumps ;jump no dec if not end of string 995 | djnz scanToMenuJumps 996 | ;hl points to jump table 997 | ld (smcLoadJumpTable+1),hl 998 | 999 | ld d,(ix+iDataH) 1000 | ld e,iDataSize 1001 | mlt de ;de=size*cursorelemid 1002 | ld hl,(menuDataPTR) 1003 | inc hl 1004 | add hl,de ;hl=ix+size*cursorID or, offset to cursor data 1005 | ld (cursorPTR),hl 1006 | 1007 | ;wait for no button forward or back through menu 1008 | ld ix,mbuttonConfirm 1009 | call waitNoButton 1010 | ld ix,mbuttonBack 1011 | call waitNoButton 1012 | jr menuDraw 1013 | 1014 | menuLoop: 1015 | call scanKeys 1016 | 1017 | ld ix,mbuttonConfirm 1018 | call checkKeyDown 1019 | jp c,menuSelect 1020 | 1021 | ld ix,mbuttonBack 1022 | call checkKeyDown 1023 | jp c,amenuEnd 1024 | 1025 | ld ix,mbuttonUp 1026 | call checkKeyDown 1027 | jr c,menuUp 1028 | 1029 | ld ix,mbuttonDown 1030 | call checkKeyDown 1031 | jr c,menuDown 1032 | 1033 | ld ix,mbuttonQuit 1034 | call checkKeyDown 1035 | jp c,exit ;early exit option (will end program) 1036 | jr menuLoop ;only redraw if something happens 1037 | 1038 | menuDraw: 1039 | ;draw active items 1040 | ld a,(menuSelection) 1041 | add a,a 1042 | add a,a 1043 | add a,a ;8*selection 1044 | ld ix,(menuPTR) ;ix points to cursor struct 1045 | add a,(ix+iDataY) ;menuY + selection ofs 1046 | ld ix,(cursorPTR) 1047 | ld (ix+iDataY),a ;save y value to cursor 1048 | 1049 | ld ix,(menuDataPTR) 1050 | call drawObjectsNoReset ;never stop drawing menu objects. 1051 | call swapVRamPTR 1052 | ld ix,(menuDataPTR) 1053 | call drawObjectsNoReset 1054 | 1055 | jr menuLoop 1056 | 1057 | menuUp: 1058 | ld hl,menuSelection 1059 | ld a,(hl) 1060 | or a,a ;cp 0 1061 | jr z, menuDraw ;don't go past zero 1062 | dec (hl) 1063 | call getStringPTRSelection 1064 | ld a,(hl) 1065 | or a,a 1066 | jr z,menuUp 1067 | jr menuDraw 1068 | 1069 | menuDown: 1070 | ld hl,menuSelection 1071 | ld a,(hl) 1072 | inc a 1073 | ld ix,(menuPTR) 1074 | cp (ix+iDataW) ;# items 1075 | jr nc, menuDraw ;don't go past end of list 1076 | ld (hl),a 1077 | call getStringPTRSelection 1078 | ld a,(hl) 1079 | or a,a 1080 | jr z, menuDown ;skip empty lines 1081 | jr menuDraw 1082 | 1083 | amenuEnd: 1084 | ;use first option 1085 | ld a,-1 1086 | ld (menuSelection),a 1087 | 1088 | menuSelect: 1089 | ld de,0 1090 | ld a,(menuSelection) 1091 | inc a 1092 | add a,a 1093 | add a,a ;4a 1094 | ld e,a ;max selection is 64 1095 | ;this is fine because menus can't render that large anyway 1096 | 1097 | smcLoadJumpTable: 1098 | ld hl,$000000 ;this will be replaced 1099 | add hl,de ; menuJumps + 4 * selection 1100 | 1101 | jp (hl) 1102 | 1103 | ;uses (menuSelection) and (menuPTR) to get string ptr 1104 | getStringPTRSelection: 1105 | ld ix,(menuPTR) 1106 | 1107 | ld hl,(ix+iDataPTR) 1108 | 1109 | ld a,(menuSelection) 1110 | ;hl: pointer to string list 1111 | ;a: selection in list 1112 | getStringInList: 1113 | or a,a 1114 | jr z, ptrOK ;selection is found 1115 | 1116 | ld b,a 1117 | scanMenuText: 1118 | ld a,(hl) 1119 | inc hl 1120 | or a,a ;cp 0 1121 | jr nz, scanMenuText 1122 | ;gets here after a 0 is found 1123 | djnz scanMenuText 1124 | 1125 | ptrOK: 1126 | ;pointer is found to string 1127 | ;hl = pointer 1128 | ret 1129 | 1130 | numberMax: 1131 | .db 0 1132 | setNumberPTR: 1133 | .dl 0 1134 | setVarPTR: 1135 | .dl 0 1136 | ;setVarPTR is the pointer to the variable being 1137 | ;modified by setNumber. 1138 | ;or, what is being "selected." 1139 | 1140 | setPtrFromObj: 1141 | ld hl,(ix+iDataPTR) 1142 | ld (setVarPTR),hl 1143 | jr setNumberReturn 1144 | 1145 | ;input: 1146 | ;ix = redraw obj ptr 1147 | ;hl = pointer to variable (for objects not typeNumber(8)) 1148 | ;a = max number + 1 1149 | setNumber: 1150 | ;ix points to data 1151 | ld (numberMax),a 1152 | ld (setNumberPTR),ix 1153 | 1154 | ld a,(ix+iDataType) 1155 | cp typeNumber8 1156 | jr z, setPtrFromObj ; set modified number from object's PTR attribute 1157 | cp typeNumber 1158 | jr z, setPtrFromObj 1159 | ; if not of number type, set ptr manually 1160 | ld (setVarPTR),hl ;points to variable to set 1161 | setNumberReturn: 1162 | 1163 | ld a,(hl) ;get default/previous from memory 1164 | ld (numberSelection),a 1165 | 1166 | ld ix, mbuttonConfirm 1167 | call waitNoButton ;wait for no confirmation press 1168 | ld ix, mbuttonBack 1169 | call waitNoButton ;wait for no back press 1170 | 1171 | setNumberLoop: 1172 | call scanKeys 1173 | 1174 | ld ix,mbuttonBack 1175 | call checkKeyDown 1176 | jr c, setNumberFinal ;return from setNumber 1177 | 1178 | ld ix,mbuttonConfirm 1179 | call checkKeyDown 1180 | jr c, setNumberFinal ;return from setNumber 1181 | 1182 | ld ix,mbuttonLeft 1183 | call checkKeyDown 1184 | jr c, setNumDown 1185 | 1186 | ld ix,mbuttonRight 1187 | call checkKeyDown 1188 | jr c, setNumUp 1189 | 1190 | ld ix,mbuttonQuit 1191 | call checkKeyDown 1192 | jp c,exit ;early exit option (will end program) 1193 | jr setNumberLoop ;only redraw if something happens 1194 | 1195 | setNumDown: 1196 | ld hl,numberSelection 1197 | ld a,(hl) 1198 | or a,a 1199 | jr z, setNumDraw ;don't dec past 0 1200 | dec (hl) 1201 | jr setNumDraw 1202 | 1203 | setNumUp: 1204 | ld hl,numberSelection 1205 | ld a,(numberMax) 1206 | ld b,a 1207 | ld a,(hl) 1208 | inc a 1209 | cp b 1210 | jr nc, setNumDraw 1211 | ld (hl),a 1212 | ;jr setNumDraw 1213 | 1214 | setNumDraw: 1215 | ;update number in memory 1216 | ld hl,(setVarPTR) 1217 | ld a,(numberSelection) 1218 | ld (hl),a 1219 | 1220 | ld ix,(setNumberPTR) 1221 | call drawObjectNoReset 1222 | call swapVRamPTR 1223 | ld ix,(setNumberPTR) 1224 | call drawObjectNoReset 1225 | jr setNumberLoop 1226 | 1227 | setNumberFinal: ;just wait for confirm/back to be released, then end 1228 | ld ix, mbuttonBack 1229 | call waitNoButton 1230 | ld ix, mbuttonConfirm 1231 | call waitNoButton 1232 | ret ;return from setNumber call 1233 | 1234 | ;input: 1235 | ;a = block size (in pixels) [0,127] 1236 | ;b = bits/pixel [0,3] 1237 | ;returns: 1238 | ;c = block size (in pixels) 1239 | ;a = block size (in bytes) 1240 | getBlockSizeBytes: 1241 | ld c,a 1242 | ld a,b 1243 | xor a,$03 1244 | ld b,a 1245 | inc b 1246 | ld a,c 1247 | sla a 1248 | getBlockSizeBytesLoop: 1249 | srl a 1250 | djnz getBlockSizeBytesLoop 1251 | ;TODO: adjust for uneven division? 1252 | ret 1253 | 1254 | ;input: 1255 | ;ix = obj data ptr 1256 | drawMap: 1257 | ld a,(ix+iDataA) 1258 | ld (smcDrawMapB),a 1259 | 1260 | ld hl,(ix+iExtTile) 1261 | ld b,(hl) 1262 | call getBlockSizeBytes 1263 | ld (smcDrawMapC),a 1264 | ld c,a ; save for later 1265 | 1266 | ld de,0 1267 | ld d,(ix+iDataXH) 1268 | ld e,(ix+iDataXL) 1269 | ld (smcDM_x),de 1270 | ld (smcDMy_x),de 1271 | 1272 | ld d,0 1273 | ld e,(ix+iDataY) 1274 | ld (smcDM_y),de 1275 | 1276 | ld a,(hl) 1277 | ld (smcDrawMapH),a 1278 | 1279 | ld hl,(ix+iExtMap) 1280 | ;at this point: 1281 | ;hl = ptr to map data 1282 | ;ix = obj data ptr 1283 | ;smcDM b,c,h are set 1284 | ;ix,a depend on tile 1285 | ;stack: y,x (coords) 1286 | ld b,(ix+iDataH) 1287 | drawMapLoopY: 1288 | ld c,b 1289 | ld b,(ix+iDataW) 1290 | smcDMy_x = $ + 1 1291 | ld de,0 1292 | ld (smcDM_x),de 1293 | drawMapLoopX: 1294 | push bc 1295 | 1296 | ld de,0 1297 | ld e,(hl) ;tile id 1298 | push hl 1299 | ld hl,(ix+iExtTileset) 1300 | add hl,de 1301 | add hl,de ;points to sprite/palette pair 1302 | ld b,(hl) ;block/sprite id 1303 | inc hl 1304 | ld a,(hl) ;palette 1305 | ld (smcDrawMapTileA),a 1306 | 1307 | ld hl,(ix+iExtTile) 1308 | inc hl ;points to sprite data 1309 | ld a,(smcDrawMapC) 1310 | ld e,a ; width of block in bytes 1311 | ld d,(ix+iDataA) 1312 | mlt de ;de = block size in bytes. assume size <256 1313 | ld d,b ;sprite data id 1314 | mlt de ;should be offset from drefSprite 1315 | add hl,de ;points to sprite data 1316 | ld (smcDrawMapTileIX),hl ;this is all set up now 1317 | 1318 | smcDM_x = $ + 1 1319 | ld de,0 1320 | smcDM_y = $ + 1 1321 | smcDrawMapH=$+2 1322 | ld hl,0 ;21 LL HH UU 1323 | smcDrawMapB=$+1 1324 | ld b,0 1325 | smcDrawMapC=$+1 1326 | ld c,0 1327 | push ix 1328 | bit 0,(ix+iDataPTRL) ;check if background block is needed 1329 | jr z,noBackgroundTile 1330 | push hl 1331 | push de 1332 | push bc 1333 | 1334 | ld a,(ix+iDataPTRH) ; null block pallete, ig 1335 | ld ix,(ix+iExtTile) 1336 | inc ix 1337 | call drawSpriteCustomBPP 1338 | ;call drawNullMinoBlock 1339 | pop bc 1340 | pop de 1341 | pop hl 1342 | noBackgroundTile: 1343 | smcDrawMapTileIX=$+2 1344 | ld ix,0 1345 | smcDrawMapTileA=$+1 1346 | ld a,0 1347 | call drawSpriteCustomBPP 1348 | ;call drawMinoBlock 1349 | pop ix 1350 | 1351 | ld hl,(smcDM_x) 1352 | ld de,0 1353 | ld e,(ix+iDataA) ;tile size 1354 | add hl,de 1355 | ld (smcDM_x),hl 1356 | 1357 | pop hl 1358 | inc hl 1359 | pop bc 1360 | djnz drawMapLoopX 1361 | ld b,c 1362 | 1363 | push hl 1364 | ld hl,(smcDM_y) 1365 | ld de,0 1366 | ld e,(ix+iDataA) ;tile size 1367 | add hl,de 1368 | ld (smcDM_y),hl 1369 | pop hl 1370 | 1371 | dec b 1372 | jp nz, drawMapLoopY 1373 | ;djnz drawMapLoopY 1374 | ret 1375 | 1376 | ;key registers read to here 1377 | keys: 1378 | .db 0,0,0,0 1379 | .db 0,0,0 1380 | 1381 | defaultButtonData: 1382 | ;buttonleft: 1383 | .db 49, 7, 2, 0 1384 | ;buttonright: 1385 | .db 50, 7, 2, 0 1386 | ;buttonsoft: 1387 | .db 48, 0, 3, 0 1388 | ;buttonhard: 1389 | .db 51, noRepeat, noRepeat, 0 1390 | ;buttonrotateleft: 1391 | .db 5, noRepeat, noRepeat, 0 1392 | ;buttonrotateright: 1393 | .db 15, noRepeat, noRepeat, 0 1394 | ;buttonhold: 1395 | .db 23, noRepeat, noRepeat, 0 1396 | ;buttonpause: 1397 | .db 6, noRepeat, noRepeat, 0 1398 | 1399 | ;buttonup: 1400 | .db 51, 60, 15, 0 1401 | ;buttondown: 1402 | .db 48, 60, 15, 0 1403 | ;buttonleft: 1404 | .db 49, 60, 15, 0 1405 | ;buttonright: 1406 | .db 50, 60, 15, 0 1407 | 1408 | ;buttonconfirm: 1409 | .db 5, noRepeat, noRepeat, 0 1410 | ;buttonback: 1411 | .db 15, noRepeat, noRepeat, 0 1412 | ;buttonquit: 1413 | .db 7, noRepeat, noRepeat, 0 1414 | defaultButtonDataEnd: 1415 | defaultButtonDataSize = defaultButtonDataEnd - defaultButtonData 1416 | 1417 | ;ix = ptr to key data to check 1418 | checkKeyDown: 1419 | ld a,(ix+buttonID) 1420 | call checkKeyA 1421 | ;so carry is set or not 1422 | push af ;save carry state 1423 | ld a,(ix+buttonTimer) 1424 | or a,a ;cp 0 1425 | jr z, buttonOK 1426 | ld b,(ix+buttonTimeStart) 1427 | cp b 1428 | jr c, buttonNotOK ;less than start time 1429 | sub b ;remove start time 1430 | cp (ix+buttonTimeRepeat) ;compare to repeater time 1431 | jr c, buttonNotOK ;less than repeat: don't repeat 1432 | ;hit repeat timer: reset it, continue, key is good 1433 | ld a,b 1434 | ld (ix+buttonTimer),a 1435 | 1436 | buttonOK: 1437 | pop af ;use whatever state button had 1438 | 1439 | jr nc, resetTimer 1440 | inc (ix+buttonTimer) 1441 | ret 1442 | 1443 | buttonNotOK: 1444 | pop af 1445 | jr nc, resetTimer ;button isn't pressed anyways 1446 | inc (ix+buttonTimer) ;inc for eventual repeat 1447 | 1448 | or a,a ;clear carry 1449 | ret 1450 | 1451 | resetTimer: 1452 | ld (ix+buttonTimer),0 1453 | ret 1454 | 1455 | checkKeyHeld: 1456 | ld a,(ix+buttonID) 1457 | checkKeyA: 1458 | or a,a 1459 | sbc hl,hl 1460 | ld l,a 1461 | and $07 ; a = bit 1462 | srl l 1463 | srl l 1464 | srl l ; l = byte 1465 | ld de, keys 1466 | add hl,de ;add byte ofs 1467 | ld b,a 1468 | ld a,(hl) 1469 | inc b 1470 | ;b is shift count 1471 | ;a is data to shift 1472 | shiftKeyBit: 1473 | rrca 1474 | djnz shiftKeyBit 1475 | rlca ;result: carry if pressed 1476 | ret 1477 | 1478 | ;ix points to button info 1479 | ;wait for no press of selected button 1480 | ;note: ix will still point to button data after 1481 | ;being called 1482 | waitNoButton: 1483 | call scanKeys 1484 | 1485 | call checkKeyDown 1486 | jr c, waitNoButton ;wait for no selection 1487 | ret 1488 | 1489 | ;waits for button press 1490 | ;ix points to button info 1491 | ;note: ix will still point to button data after 1492 | ;function ends 1493 | waitButton: 1494 | call scanKeys 1495 | 1496 | call checkKeyDown 1497 | jr nc, waitButton ;wait for selection 1498 | ret 1499 | 1500 | checkKey: 1501 | call scanKeys 1502 | ld a,NO_KEY_PRESSED 1503 | ld (smcLastPress),a ;if no press, default -1 1504 | ld b,56 1505 | rkeys: 1506 | push bc 1507 | ld a,b 1508 | dec a 1509 | call checkKeyA 1510 | pop bc 1511 | jr nc,noSetLastPress 1512 | ld a,b 1513 | dec a 1514 | ld (smcLastPress),a 1515 | noSetLastPress: 1516 | djnz rkeys 1517 | smcLastPress = $+1 1518 | ld a,-1 ;a is key id pressed 1519 | ret 1520 | 1521 | ;source: http://wikiti.brandonw.net/index.php?title=84PCE:Ports:A000 1522 | ;copied from above source 1523 | scanKeys: 1524 | di ; Disable OS interrupts 1525 | ld hl,0F50000h 1526 | ld (hl),2 ; Set Single Scan mode 1527 | 1528 | xor a,a 1529 | scan_wait: 1530 | cp a,(hl) ; Wait for Idle mode 1531 | jr nz,scan_wait 1532 | 1533 | ;just take all of the keys 1534 | ;probably can loop but eh 1535 | ld l,kbdG1 & $ff ; ld hl, kbdG1 1536 | ld de,keys 1537 | ld b,7 1538 | ld c,b 1539 | scanKey: 1540 | ldi 1541 | inc hl 1542 | ;copy from hl to de 1543 | ;key dest is 8bit unit 1544 | ;key src is 16bit unit, so inc hl 1545 | djnz scanKey ;copy 7 keys 1546 | 1547 | ei ; Enable OS interrupts 1548 | ret 1549 | 1550 | ;source: http://wikiti.brandonw.net/index.php?title=84PCE:Ports:A000 1551 | ;this is modified from the same source as above 1552 | ;might not be completely necessary, most of this doesn't get changed 1553 | RestoreKeyboard: 1554 | ld hl,DI_Mode 1555 | xor a ; Mode 0 1556 | ld b, 15 1557 | ld (hl),a 1558 | inc l ; 0F50001h 1559 | ld (hl),b ; Wait 15*256 APB cycles before scanning each row 1560 | inc l ; 0F50002h 1561 | ld (hl),a 1562 | inc l ; 0F50003h 1563 | ld (hl),b ; Wait 15 APB cycles before each scan 1564 | inc l ; 0F50004h 1565 | ld a,8 ; Number of rows to scan 1566 | ld (hl),a 1567 | inc l ; 0F50005h 1568 | ld (hl),a ; Number of columns to scan 1569 | ret 1570 | 1571 | -------------------------------------------------------------------------------- /tetrice_dat.asm: -------------------------------------------------------------------------------- 1 | #include "includes\ti84pce.inc" 2 | #include "includes\tetrice.inc" 3 | 4 | .assume ADL=1 5 | .org saveSScreen 6 | 7 | dataReferences: 8 | .dl spriteData ;std sprites like blocks, field, etc 9 | .dl fontData ;font data. 10 | .dl 0 ;previously block sprite+palette pairs 11 | .dl 0 ;what will this be? 12 | .dl paletteData ;palette data 13 | .dl menuObjData ;menu data 14 | .dl pauseData 15 | .dl SSSInfo ;ptr to item info for display in game 16 | .dl gameOverData ;game over notif 17 | 18 | ;these references behave the same as data references 19 | ;but are for specific graphical elements, 20 | ;instead of being for data pointers. 21 | ;examples: references to... 22 | ;tetris field data 23 | ;hold data 24 | ;score/lines/level 25 | ;pretty much anything that requires the 26 | ;occasional redraw as part of it's update code. 27 | ;make sure it points to SSS data, 28 | ;not the original data, because program reads from SSSInfo. 29 | references: 30 | .dl fieldInfo 31 | .dl holdInfo 32 | .dl levelInfo 33 | .dl scoreInfo 34 | .dl linesInfo 35 | .dl previewInfo 36 | .dl timerInfo 37 | 38 | 39 | ;note: address expected in tetrice.inc to be refSize * 16 + SSS. be sure to modify if refs are added. 40 | initDat: 41 | call applyTheme 42 | ret 43 | 44 | boxColor = 2 45 | boxColor2= 3 46 | lightBoxColor = 14 47 | lightBoxColor2 = 15 48 | textColor= 3 49 | infoBoxX = 168 50 | infoBoxY = 16 51 | 52 | uiCompound: 53 | ;backgroundInfo: 54 | .db typeMap 55 | .dw 0 56 | .db 0 57 | .db 16 58 | .dl 1 59 | .db 20, 15 ;size of entire screen 60 | ;backgroundInfoExtended: 61 | .db typeExtended 62 | .dl bgSprite 63 | .dl bgTiles 64 | .dl empty300 65 | ;bg box for logo 66 | titleCompound: 67 | .db typeBox 68 | .dw 240 69 | .db 192 70 | .db lightBoxColor 71 | .dl 72 72 | .db lightBoxColor2, 40 73 | ;logo shadow 74 | .db typeSprite1bpp 75 | .dw 248 76 | .db 200 77 | .db 1 78 | .dl logoSprite 79 | .db 7, 14 80 | ;logo 81 | .db typeSprite1bpp 82 | .dw 247 83 | .db 199 84 | .db 4 85 | .dl logoSprite 86 | .db 7, 14 87 | ;version string 88 | .db typeString 89 | .dw -versionStringSize * 8 + 312 90 | .db 216 91 | .db textColor 92 | .dl versionString 93 | .db 0, 0 94 | 95 | ;Game items info 96 | itemsInfo: 97 | .db 12 ;number of items 98 | ;uiCompoundObj 99 | .db typeCompound 100 | .dw 0, 0 101 | .dl uiCompound 102 | .db 6, 0 103 | fieldInfo: 104 | .db typeMap 105 | .dw 0 ;x 106 | .db 0 ;y 107 | .db 12 ;a/size of tile 108 | .dl 1 ;flags 109 | .db fieldDrawWidth, fieldDrawHeight ;10, 20 default 110 | ;fieldExtended 111 | .db typeExtended ;part of previous object 112 | .dl spriteData 113 | .dl blockGraphicData ;tileset pointer here 114 | .dl (fieldHeight - fieldDrawHeight) * fieldDrawWidth + field 115 | holdInfo: 116 | .db typeCompound ;typeHold 117 | .dw 0 ;unused 118 | .db 0 ;unused 119 | .db 0 ;unused 120 | .dl holdCompound ;ptr to compound object data (does not include item count) 121 | .db 3, 0 ; number of items, unused 122 | previewInfo: 123 | .db typeCompound 124 | .dw 0 ;unused 125 | .db 0 ;unused 126 | .db 0 ;unused 127 | .dl previewCompound 128 | .db 8, 0 ; number of items, unused 129 | ;BACKGROUND BOX INFO 130 | .db typeBox 131 | .dw infoBoxX ;x 132 | .db infoBoxY ;y 133 | .db boxColor ;color of main 134 | .dl 128 ;width 135 | .db boxColor2, 80 ;bordercolor, height 136 | ;SCORE TEXT ETC. 137 | .db typeMenu 138 | .dw infoBoxX + 8 139 | .db infoBoxY + 8 140 | .db textColor 141 | .dl gameText 142 | .db 7, 0 ;cursorid doesn't matter cause not a active menu 143 | scoreInfo: 144 | .db typeNumber 145 | .dw infoBoxX + 8 + 48 146 | .db infoBoxY + 8 + 0 147 | .db textColor 148 | .dl score ;variables are saved in PSS 149 | .db 8, boxColor ; size of number, bgcolor 150 | levelInfo: 151 | .db typeNumber 152 | .dw infoBoxX + 8 + 48 153 | .db infoBoxY + 8 + 24 154 | .db textColor 155 | .dl level 156 | .db 3, boxColor ;size number, bg color 157 | linesInfo: 158 | .db typeNumber 159 | .dw infoBoxX + 8 + 48 160 | .db infoBoxY + 8 + 32 161 | .db textColor 162 | .dl lines 163 | .db 4, boxcolor ;number of digits, bgcolor 164 | timerInfo: 165 | .db typeNumber 166 | .dw infoBoxX + 8 + 48 167 | .db infoBoxY + 8 + 8 168 | .db textColor 169 | .dl globalTimer 170 | .db 8, boxcolor 171 | highscoreInfo: 172 | .db typeNumber 173 | .dw infoBoxX + 8 + 48 174 | .db infoBoxY + 8 + 48 175 | .db textColor 176 | .dl highScore 177 | .db 8, boxcolor 178 | 179 | holdCompound: 180 | holdBox: 181 | .db typeBox 182 | .dw 126 183 | .db 160 184 | .db 2 185 | .dl 36 186 | .db 3, 36 187 | holdTitle: 188 | .db typeString 189 | .dw 128 190 | .db 162 191 | .db textColor 192 | .dl holdText 193 | .db 0, 0 194 | holdMino: 195 | .db typeCustom 196 | .dw 138 ;x 197 | .db 184 ;y 198 | .db holdTOfs ;minoTypes offset 199 | .dl drawMinoFromTypeWrapper 200 | .db 1< 768 bytes 1487 | fontData: 1488 | ;bits per pixel 1489 | .db sp1bpp 1490 | ;actual font data 1491 | .db $00, $00, $00, $00, $00, $00, $00, $00 1492 | .db $00, $18, $18, $18, $18, $00, $18, $00 1493 | .db $00, $6c, $6c, $24, $00, $00, $00, $00 1494 | .db $00, $6c, $7e, $6c, $6c, $7e, $6c, $00 1495 | .db $18, $3c, $5a, $38, $1c, $5a, $3c, $18 1496 | .db $00, $66, $6c, $18, $18, $36, $66, $00 1497 | .db $00, $38, $6c, $38, $6a, $6c, $3a, $00 1498 | .db $00, $18, $18, $08, $00, $00, $00, $00 1499 | .db $00, $18, $30, $30, $30, $30, $18, $00 1500 | .db $00, $18, $0c, $0c, $0c, $0c, $18, $00 1501 | .db $00, $66, $3c, $7e, $7e, $3c, $66, $00 1502 | .db $00, $18, $18, $7e, $7e, $18, $18, $00 1503 | .db $00, $00, $00, $00, $18, $18, $10, $00 1504 | .db $00, $00, $00, $7e, $7e, $00, $00, $00 1505 | .db $00, $00, $00, $00, $00, $18, $18, $00 1506 | .db $00, $06, $0c, $18, $18, $30, $60, $00 1507 | numbers: 1508 | .db $00, $3c, $66, $66, $66, $66, $3c, $00 1509 | .db $00, $18, $78, $18, $18, $18, $7e, $00 1510 | .db $00, $3c, $66, $0c, $18, $30, $7e, $00 1511 | .db $00, $3c, $66, $1c, $06, $66, $3c, $00 1512 | .db $00, $66, $66, $7e, $06, $06, $06, $00 1513 | .db $00, $7e, $60, $7c, $06, $06, $7c, $00 1514 | .db $00, $3c, $60, $7c, $66, $66, $3c, $00 1515 | .db $00, $7e, $06, $06, $0c, $0c, $0c, $00 1516 | .db $00, $3c, $66, $3c, $7e, $66, $3c, $00 1517 | .db $00, $3c, $66, $66, $3e, $06, $3c, $00 1518 | .db $00, $18, $18, $00, $00, $18, $18, $00 1519 | .db $00, $18, $18, $00, $18, $18, $10, $00 1520 | .db $00, $06, $1e, $78, $78, $1e, $06, $00 1521 | .db $00, $7e, $7e, $00, $00, $7e, $7e, $00 1522 | .db $00, $60, $78, $1e, $1e, $78, $60, $00 1523 | .db $00, $3c, $66, $06, $1c, $00, $18, $00 1524 | .db $00, $3c, $66, $6e, $6a, $64, $30, $00 1525 | .db $00, $3c, $66, $7e, $66, $66, $66, $00 1526 | .db $00, $7c, $66, $7c, $66, $66, $7c, $00 1527 | .db $00, $3c, $66, $60, $60, $66, $3c, $00 1528 | .db $00, $7c, $66, $66, $66, $66, $7c, $00 1529 | .db $00, $7e, $60, $78, $60, $60, $7e, $00 1530 | .db $00, $7e, $60, $78, $60, $60, $60, $00 1531 | .db $00, $3c, $66, $60, $6e, $66, $3c, $00 1532 | .db $00, $66, $66, $7e, $66, $66, $66, $00 1533 | .db $00, $7e, $18, $18, $18, $18, $7e, $00 1534 | .db $00, $1e, $06, $06, $06, $66, $3c, $00 1535 | .db $00, $66, $6c, $78, $6c, $66, $66, $00 1536 | .db $00, $60, $60, $60, $60, $60, $7e, $00 1537 | .db $00, $66, $7e, $7e, $7e, $66, $66, $00 1538 | .db $00, $66, $76, $7e, $6e, $66, $66, $00 1539 | .db $00, $3c, $66, $66, $66, $66, $3c, $00 1540 | .db $00, $7c, $66, $7c, $60, $60, $60, $00 1541 | .db $00, $3c, $66, $66, $66, $7c, $3e, $00 1542 | .db $00, $7c, $66, $7c, $66, $66, $66, $00 1543 | .db $00, $3c, $60, $3c, $06, $66, $3c, $00 1544 | .db $00, $7e, $18, $18, $18, $18, $18, $00 1545 | .db $00, $66, $66, $66, $66, $66, $3c, $00 1546 | .db $00, $66, $66, $3c, $3c, $18, $18, $00 1547 | .db $00, $66, $66, $66, $7e, $7e, $66, $00 1548 | .db $00, $66, $3c, $18, $18, $3c, $66, $00 1549 | .db $00, $66, $66, $3c, $18, $18, $18, $00 1550 | .db $00, $7e, $06, $1c, $38, $60, $7e, $00 1551 | .db $00, $1c, $18, $18, $18, $18, $1c, $00 1552 | .db $00, $60, $30, $18, $18, $0c, $06, $00 1553 | .db $00, $38, $18, $18, $18, $18, $38, $00 1554 | .db $00, $18, $18, $3c, $3c, $66, $66, $00 1555 | .db $00, $00, $00, $00, $00, $00, $7e, $00 1556 | ; `abcdefghijklmnopqrstuvwxyz{|}~ 1557 | .db $00, $30, $18, $0c, $00, $00, $00, $00 1558 | .db $00, $00, $3c, $06, $3e, $66, $3e, $00 1559 | .db $00, $60, $60, $7c, $66, $66, $7c, $00 1560 | .db $00, $00, $3c, $66, $60, $66, $3c, $00 1561 | .db $00, $06, $06, $3e, $66, $66, $3e, $00 1562 | .db $00, $00, $3c, $66, $7e, $60, $3c, $00 1563 | .db $00, $0e, $18, $7e, $18, $18, $18, $00 1564 | .db $00, $3e, $66, $66, $3e, $06, $3c, $00 1565 | .db $00, $60, $60, $7c, $66, $66, $66, $00 1566 | .db $00, $18, $00, $18, $18, $18, $18, $00 1567 | .db $00, $18, $00, $18, $18, $18, $70, $00 1568 | .db $00, $60, $66, $6c, $78, $6c, $66, $00 1569 | .db $00, $18, $18, $18, $18, $18, $18, $00 1570 | .db $00, $00, $7c, $7e, $7e, $7e, $66, $00 1571 | .db $00, $00, $7c, $66, $66, $66, $66, $00 1572 | .db $00, $00, $3c, $66, $66, $66, $3c, $00 1573 | .db $00, $7c, $66, $66, $7c, $60, $60, $00 1574 | .db $00, $3e, $66, $66, $3e, $06, $06, $00 1575 | .db $00, $00, $7c, $66, $60, $60, $60, $00 1576 | .db $00, $00, $3c, $60, $3c, $06, $7c, $00 1577 | .db $00, $18, $18, $7e, $18, $18, $18, $00 1578 | .db $00, $00, $66, $66, $66, $66, $3e, $00 1579 | .db $00, $00, $66, $66, $66, $3c, $18, $00 1580 | .db $00, $00, $66, $7e, $7e, $7e, $3e, $00 1581 | .db $00, $00, $66, $3c, $18, $3c, $66, $00 1582 | .db $00, $00, $66, $66, $3e, $06, $3c, $00 1583 | .db $00, $00, $7e, $0c, $18, $30, $7e, $00 1584 | .db $00, $0e, $18, $70, $70, $18, $0e, $00 1585 | .db $00, $18, $18, $18, $18, $18, $18, $00 1586 | .db $00, $70, $18, $0e, $0e, $18, $70, $00 1587 | .db $00, $00, $30, $5a, $0c, $00, $00, $00 1588 | .db $00, $10, $20, $7e, $20, $10, $00, $00 1589 | fontDataEnd: 1590 | 1591 | paletteData: 1592 | ; If you swap which of the two below lines is commented, you get a "dark mode" of sorts 1593 | ; (background color becomes black; grid is slightly lighter) 1594 | .dw $7fff, $1CE7, $3def, $0000 ;null block 1595 | ;.db $ff, $7f, $ef, $3d, $18, $63, $ff, $7f 1596 | .db $ff, $7f, $3f, $33, $9d, $02, $b3, $01 1597 | .db $ff, $7f, $9e, $25, $39, $1d, $53, $00 1598 | .db $ff, $7f, $8d, $7e, $e4, $7d, $40, $69 1599 | .db $ff, $7f, $ef, $7f, $c0, $7f, $e0, $62 1600 | .db $ff, $7f, $8c, $17, $08, $0b, $45, $02 1601 | .db $ff, $7f, $fb, $6d, $34, $51, $10, $40 1602 | .db $ff, $7f, $8d, $7d, $64, $74, $00, $60 1603 | .db $00, $00, $18, $63, $ef, $3d, $08, $21 ;monochrome 1604 | 1605 | .db $00, $00, $08, $21, $8c, $31, $31, $46 ;darker null block (unused) 1606 | .db $31, $46, $b1, $19, $50, $01, $ca, $00 1607 | .db $31, $46, $d0, $10, $8d, $0c, $0a, $00 1608 | .db $31, $46, $46, $45, $e1, $44, $a0, $38 1609 | .db $31, $46, $08, $46, $00, $46, $80, $35 1610 | .db $31, $46, $e6, $09, $a4, $01, $22, $01 1611 | .db $31, $46, $ee, $38, $8a, $28, $08, $20 1612 | .db $31, $46, $c6, $44, $21, $40, $00, $30 1613 | .db $00, $00, $ef, $3d, $08, $21, $00, $00 ;dark mono 1614 | ;.dw $00ff, $0ff0, $ff00, $f00f 1615 | ;.dw $7fff, $1CE7, $3def, $0000 1616 | ;.dw $7fff, $4f7d, $029d, $1d39 1617 | ;.dw $7fff, $3a57, $1d39, $0000 1618 | ;.dw $7fff, $7f21, $7de4, $4402 ;4 1619 | ;.dw $7fff, $7fff, $7fc0, $7f21 1620 | ;.dw $7fff, $5b83, $12c9, $3def 1621 | ;.dw $7fff, $66fc, $5134, $0000 1622 | ;.dw $7fff, $7eb9, $7464, $4402 ;8 1623 | ;.dw $3def, $0c63, $1ce7, $0000 1624 | ;.dw $3def, $25ae, $014e, $0c8c 1625 | ;.dw $3def, $1d2b, $0c8c, $0000 1626 | ;.dw $3def, $3d80, $3ce2, $2001 ;12 1627 | ;.dw $3def, $3def, $3de0, $3d80 1628 | ;.dw $3def, $2dc1, $0964, $1ce7 1629 | ;.dw $3def, $316e, $288a, $0000 1630 | ;.dw $3def, $3d4c, $3822, $2001 ;16 1631 | 1632 | -------------------------------------------------------------------------------- /tetrice.asm: -------------------------------------------------------------------------------- 1 | #include "includes\ti84pce.inc" 2 | #include "includes\tetrice.inc" 3 | 4 | .assume ADL=1 5 | .org userMem-2 6 | .db tExtTok,tAsm84CeCmp 7 | 8 | ; def is both indication to include icon and sets version string 9 | #ifdef META 10 | icon: 11 | jp main 12 | .db 1 13 | .db 16, 16 14 | .db $e3, $e3, $e3, $e3, $e3, $e3, $54, $54 15 | .db $e7, $e7, $e7, $e7, $54, $54, $54, $54 16 | .db $e3, $c3, $e3, $c3, $e3, $c3, $54, $54 17 | .db $e7, $e6, $e7, $e6, $54, $54, $54, $54 18 | .db $e3, $e3, $54, $54, $54, $54, $54, $54 19 | .db $e7, $e7, $e7, $e7, $54, $54, $54, $54 20 | .db $e3, $c3, $54, $54, $54, $54, $54, $54 21 | .db $e7, $e6, $e7, $e6, $54, $54, $54, $54 22 | .db $18, $18, $54, $54, $54, $54, $54, $54 23 | .db $18, $18, $54, $54, $54, $54, $54, $54 24 | .db $18, $10, $54, $54, $54, $54, $54, $54 25 | .db $18, $10, $54, $54, $54, $54, $54, $54 26 | .db $18, $18, $18, $18, $18, $18, $54, $54 27 | .db $18, $18, $18, $18, $18, $18, $54, $54 28 | .db $18, $10, $18, $10, $18, $10, $54, $54 29 | .db $18, $10, $18, $10, $18, $10, $54, $54 30 | .db $98, $98, $98, $98, $98, $98, $54, $54 31 | .db $3f, $3f, $54, $54, $54, $54, $54, $54 32 | .db $98, $70, $98, $70, $98, $70, $54, $54 33 | .db $3f, $1e, $54, $54, $54, $54, $54, $54 34 | .db $54, $54, $98, $98, $18, $18, $18, $18 35 | .db $3f, $3f, $54, $54, $54, $54, $54, $54 36 | .db $54, $54, $98, $70, $18, $10, $18, $10 37 | .db $3f, $1e, $54, $54, $54, $54, $54, $54 38 | .db $54, $54, $54, $54, $18, $18, $54, $54 39 | .db $3f, $3f, $54, $54, $47, $47, $47, $47 40 | .db $54, $54, $54, $54, $18, $10, $54, $54 41 | .db $3f, $1e, $54, $54, $47, $26, $47, $26 42 | .db $54, $54, $54, $54, $18, $18, $54, $54 43 | .db $3f, $3f, $47, $47, $47, $47, $54, $54 44 | .db $54, $54, $54, $54, $18, $10, $54, $54 45 | .db $3f, $1e, $47, $26, $47, $26, $54, $54 46 | 47 | ;todo convert this 48 | .db "CETris v0.8",0 49 | #endif 50 | 51 | ;main program 52 | ;this is where the program starts + lotsa setup stuff 53 | main: 54 | ld (preserveSP),sp 55 | ld hl, PSS 56 | ld de, PSS + 1 57 | ld bc, 4096 58 | ld (hl),0 59 | ldir 60 | 61 | ;save loading 62 | call loadSaveVar ;get ptr to save data from appvar 63 | inc de 64 | inc de ;past size of appvar 65 | ld (saveDataPTR),de 66 | call loadSave ;actually read save data 67 | 68 | ;initialize various data 69 | call initData ;important info + appvar load 70 | 71 | ld hl,(drefFont) 72 | ld (smcFontDataPtr),hl 73 | ld hl,(drefPalette) 74 | ld (smcPaletteDataPtr),hl 75 | 76 | call initLCD ;screen init (requires data for palette) 77 | 78 | call defaultInfo ;default game rules/information 79 | call initDataCustom ;appvar custom setup 80 | 81 | jp mainMenu 82 | 83 | exit: 84 | ;save appvar to archive 85 | call saveSave 86 | 87 | ;restore state for ti-os 88 | call resetLCD 89 | call restoreKeyboard 90 | 91 | ld sp,(preserveSP) 92 | ret 93 | 94 | error: 95 | call saveSave 96 | 97 | call resetLCD 98 | call restoreKeyboard 99 | 100 | ld sp,(preserveSP) 101 | 102 | ld hl,errorString 103 | ld de,appErr1 104 | ld bc,errorStringEnd - errorString 105 | ldir 106 | 107 | call _ErrCustom1 108 | ret 109 | 110 | errorString: 111 | .db "NO CETrisDT",0 112 | errorStringEnd: 113 | 114 | initDataCustom: 115 | jp initDataStart 116 | 117 | preserveSP: 118 | .dl 0 119 | 120 | defaultInfo: 121 | ld ix,rules 122 | ld (ix+rfBasic), rMarathon ;game/component rules 123 | ld (ix+rfExtra), rNull ;no extra rules 124 | ld (ix+rfWin), rLines ;win method 125 | ld (ix+rfScore),rScore ;scoring method 126 | 127 | xor a 128 | ld (ix+rMode),a 129 | ld (ix+rRGT),a 130 | ld (ix+rRGD),a 131 | ld (ix+rLCW),150 132 | 133 | inc a ;a=1 134 | ld (level),a ;starting level is by default one 135 | ret 136 | 137 | ;must have rules+rMode already set 138 | setHighScore: 139 | ld a,(rules+rMode) 140 | ld ix,(saveDataPTR) 141 | ld de,0 142 | add a,a 143 | add a,a 144 | ld e,a 145 | add ix,de ;add 4 146 | add ix,de ;add 8 147 | ld hl,(ix+savHighScore) ;hl=score from save 148 | ld (highscore),hl 149 | ret 150 | 151 | mainMenu: 152 | ld ix,(drefMenu) 153 | jp activeMenu 154 | 155 | initGame: 156 | ld ix,rules 157 | set rbitGameCont, (ix+rfBasic) ;game is going 158 | res rbitGameWon, (ix+rfBasic) ;game not won 159 | 160 | xor a 161 | sbc hl,hl 162 | ld (linesToNextLevel),a 163 | ld (clearTimer),a 164 | ld (spawnTimer),a 165 | 166 | ld a,(userLockDelay) 167 | ld (lockDelay),a 168 | ld a,(userSpawnDelay) 169 | ld (spawnDelay),a 170 | ld a,(userDASDelay) 171 | ld (buttonLeft+buttonTimeStart),a 172 | ld (buttonRight+buttonTimeStart),a 173 | 174 | ld (score),hl ;don't keep old score/time! 175 | ld (lines),hl 176 | bit rbitCountdown, (ix+rfWin) 177 | jr nz, noResetTimer 178 | ld (globaltimer),hl 179 | noResetTimer: 180 | call setHighScore 181 | call setDelay 182 | 183 | ld a,NULL_BLOCK 184 | ld (holdT),a 185 | 186 | call initBag ;also initializes random I guess? 187 | call initField ;depends on RNG being seeded by initbag, which init's rng system 188 | 189 | ld hl,curData 190 | ld de,curData+1 191 | ld bc,6*curDataSize 192 | ld (hl),0 193 | ldir ;zero out old blockdata (prevents ghosts) 194 | call newBlock 195 | 196 | ;first draw to set up screen 197 | call clearLCD 198 | ld ix,(drefIInfo) 199 | call resetAllNeeded 200 | ld ix,(drefIInfo) 201 | call drawObjectsNoReset 202 | call swapVRamPTR 203 | ld ix,(drefIInfo) 204 | call drawObjects 205 | call swapVRamPTR 206 | 207 | game: 208 | call scanKeys 209 | ld ix,mbuttonQuit 210 | call checkKeyDown 211 | jp c, exit ;exit if pressed 212 | 213 | call shiftOldData 214 | ;part of update code, essentially 215 | ;might move to update sometime 216 | 217 | jp handleDelays 218 | noDelays: 219 | 220 | call update 221 | call userUpdate 222 | ; call queuedUpdate 223 | 224 | skipGameUpdate: 225 | ld hl, (refTimer) ;time updates every frame 226 | res redrawObjBit, (hl) 227 | ld hl,(refScore) 228 | res redrawObjBit, (hl) 229 | 230 | call drawGame 231 | 232 | ld hl,rules + rfWin 233 | bit rbitCountdown, (hl) 234 | call nz, timerDown ;timer decreases 235 | call z, timerUp ;timer increases 236 | 237 | ld ix,rules 238 | bit rBitGameCont, (ix+rfBasic) 239 | jr nz, game ;jump if nz: bit is 1, game is going 240 | jp gameEndInit 241 | 242 | handleDelays: 243 | ld a,(clearTimer) 244 | or a,a 245 | jr z, noClearTimer 246 | dec a 247 | ld (clearTimer),a 248 | jr waitForClear 249 | noClearTimer: 250 | 251 | ld a,(spawnTimer) 252 | or a,a 253 | jr z, noSpawnTimer 254 | dec a 255 | ld (spawnTimer),a 256 | jr waitForSpawn 257 | noSpawnTimer: 258 | jr noDelays 259 | 260 | waitForClear: 261 | waitForSpawn: 262 | ;waiting for something or other 263 | ;check for instant actions and DAS update in ARE 264 | call userInstantUpdate 265 | jr skipGameUpdate 266 | 267 | timerDown: 268 | ld hl,(globalTimer) 269 | dec hl 270 | ld (globalTimer),hl 271 | xor a 272 | or h 273 | or l 274 | ret nz ;if hl nonzero, return (also prevents timerUp from being called) 275 | ld hl, rules + rfBasic 276 | res rbitGameCont, (hl) ;game ends when reaching zero 277 | set rbitGameWon, (hl) ;game is won if you survived to here 278 | or 1 ;resets zero so timerUp isn't called 279 | ret 280 | 281 | timerUp: 282 | ld hl,(globalTimer) 283 | inc hl 284 | ld (globalTimer),hl 285 | ret 286 | 287 | initField: 288 | ld hl,field 289 | ld de,field+1 290 | ld bc,255 291 | ld (hl),NULL_BLOCK 292 | ldir 293 | 294 | ld hl, rules+rfExtra 295 | bit rbitGarbageInitial, (hl) 296 | jr nz, generateGarbage 297 | ret 298 | 299 | generateGarbage: 300 | ld ix, rules 301 | ld a,fieldHeight 302 | sub (ix+rGGA) ;garbage rows to generate 303 | ld d,a 304 | add a,a 305 | add a,a 306 | add a,d 307 | add a,a ;10a = ofs from field 308 | ld de,0 309 | ld e,a 310 | ld hl,field 311 | add hl,de 312 | 313 | ld b,(ix+rGGA) 314 | genGarbageLoop: 315 | push bc 316 | push hl ;save field position 317 | 318 | ld b,(ix+rGGD) 319 | ld ix, rules 320 | call generateGarbageRow 321 | pop hl 322 | ld de,10 323 | add hl,de 324 | pop bc 325 | djnz genGarbageLoop 326 | ret 327 | 328 | ;hl=ptr to field row 329 | ;b=density to generate 330 | generateGarbageRow: 331 | push hl 332 | push bc 333 | push hl 334 | call rand 335 | push de 336 | pop hl 337 | ;hl = random 338 | ld a,10 339 | call _DivHLByA 340 | ;a = [0,9] random 341 | pop hl ;get fieldptr 342 | ld de,0 343 | ld e,a 344 | ;hl = fieldptr de = ofs 345 | backAgainGenerate: ;try again with new ofs here 346 | add hl,de ;fieldptr+ofs 347 | ld a,(hl) 348 | or a,a ;clear carry 349 | sbc hl,de ;fieldptr +ofs -ofs 350 | cp NULL_BLOCK ;block is empty 351 | jr nz, tryAgainGenerate ;isn't an empty block, try again 352 | ld a,8 ;garbage block? 353 | add hl,de 354 | ld (hl),a ;counting loop 355 | pop bc 356 | pop hl ;orig. fieldptr 357 | djnz generateGarbageRow 358 | ret 359 | 360 | tryAgainGenerate: 361 | ;hl = fieldptr 362 | ;de = ofs 363 | ld a,e 364 | inc a 365 | cp 10 366 | jr nz, skipResetA0 367 | xor a,a 368 | skipResetA0: 369 | ld e,a 370 | jr backAgainGenerate 371 | 372 | incGarbage: 373 | ld ix,rules 374 | bit rbitGarbageRising,(ix+rfExtra) 375 | ret z ;garbage isn't rising so don't do stuff 376 | 377 | ;increment garbage timer 378 | ld hl,rules+rRGT 379 | ld a,(garbageTimer) 380 | inc a 381 | ld (garbageTimer),a 382 | cp (hl) ;check if timer needs to inc queue garbage 383 | ret c 384 | xor a 385 | ld (garbageTimer),a 386 | 387 | ld a,(queuedGarbage) 388 | inc a 389 | ld (queuedGarbage),a 390 | ret 391 | 392 | ;input: ix=rules 393 | raiseGarbage: 394 | ld a,(queuedGarbage) 395 | cp 0 396 | ret z ;don't raise garbage if there's none to raise! 397 | ld b,a 398 | xor a 399 | ld (queuedGarbage),a 400 | 401 | ;raise field and generate garbage as many times as needed 402 | raiseOneRow: 403 | push bc 404 | ld de,field 405 | ld hl,field+10 406 | ld bc,245 407 | ldir ;copy fielddata up/shift field up 408 | 409 | ;zero last row 410 | ld hl,fieldHeight - 1 * 10 + field 411 | ld de,fieldHeight - 1 * 10 + field + 1 412 | ld bc,9 413 | ld (hl),NULL_BLOCK 414 | ldir 415 | 416 | ld b, (ix+rRGD) ;rising garbage density 417 | ld hl,fieldHeight - 1 * 10 + field ;last row of field 418 | call generateGarbageRow 419 | pop bc 420 | djnz raiseOneRow 421 | 422 | ld hl,(refField) 423 | res redrawObjBit, (hl) ;ix+0 ix+objtype 424 | ld hl,curStatus 425 | set csGarbageBit, (hl) ;garbage rose on this frame = field redraw this frame 426 | ld hl,DrawObjectsNoReset 427 | ld (smcDrawObjectsType),hl 428 | ret 429 | 430 | shiftOldData: 431 | ;copy old mino data 432 | ;to use for clearing old draws 433 | ld hl, midData 434 | ld de, oldData 435 | ld bc, curDataSize 436 | ldir 437 | ;note: can probably combine these into one copy 438 | ld hl, curData 439 | ld de, midData 440 | ld bc, curDataSize 441 | ldir 442 | 443 | ld hl, midTempData 444 | ld de, oldTempData 445 | ld bc, curDataSize 446 | ldir 447 | 448 | ld hl, tempData 449 | ld de, midTempData 450 | ld bc, curDataSize 451 | ldir 452 | ret 453 | 454 | userInstantUpdate: 455 | ld ix,buttonLeft 456 | call checkKeyDown 457 | ld ix,buttonRight 458 | call checkKeyDown 459 | ;results discarded, used to update button timers for DAS 460 | 461 | xor a 462 | ld (queuedAction),a ;clear any possibly queued moves 463 | ld ix,buttonHold 464 | call checkKeyHeld 465 | jr nc, skipQueueHold 466 | ld hl,queuedAction 467 | set qaHold,(hl) 468 | skipQueueHold: 469 | ;this happened naturall because of button timings 470 | ; ld ix,buttonRotateLeft 471 | ; call checkKeyHeld 472 | ; jr nc, skipQueueRL 473 | ; ld hl,queuedAction 474 | ; set qaRotateLeft,(hl) 475 | ;skipQueueRL: 476 | ; 477 | ; ld ix,buttonRotateRight 478 | ; call checkKeyHeld 479 | ; jr nc, skipQueueRR 480 | ; ld hl,queuedAction 481 | ; set qaRotateRight,(hl) 482 | ;skipQueueRR: 483 | ret 484 | 485 | userUpdate: 486 | ld hl, curStatus 487 | bit csLockedBit, (hl) 488 | ret nz ;if this frame locked, no other input matters 489 | 490 | ld ix,buttonLeft 491 | call checkKeyDown 492 | call c, checkMoveLeft 493 | 494 | ld ix,buttonRight 495 | call checkKeyDown 496 | call c, checkMoveRight 497 | 498 | ld ix,buttonRotateLeft 499 | call checkKeyDown 500 | call c, checkRotationLeft 501 | ;turns out unneeded due to button timing system 502 | ;ld a,(queuedAction) 503 | ;bit qaRotateLeft, a 504 | ;call nz, checkRotationLeft 505 | 506 | ld ix,buttonRotateRight 507 | call checkKeyDown 508 | call c, checkRotationRight 509 | ;ld a,(queuedAction) 510 | ;bit qaRotateRight, a 511 | ;call nz, checkRotationRight 512 | 513 | ld ix,buttonHold 514 | call checkKeyDown 515 | call c, hold 516 | 517 | ld ix,buttonPause 518 | call checkKeyDown 519 | call c, pause 520 | ret 521 | 522 | ;queuedUpdate: 523 | ; ld a,(queuedAction) 524 | ; bit qaHold, a 525 | ; call nz, hold 526 | 527 | ; xor a 528 | ; ld (queuedAction),a 529 | ; ret 530 | 531 | pause: 532 | ld ix,buttonPause 533 | call waitNoButton 534 | 535 | pauseLoop: 536 | call scanKeys 537 | 538 | ld ix,buttonPause 539 | call checkKeyDown 540 | jr c, pauseEnd 541 | ld ix,mbuttonQuit 542 | call checkKeyDown 543 | jr c, pauseEnd 544 | 545 | ld ix, (drefPause) 546 | call drawObjectsNoReset 547 | call swapVRamPTR 548 | jr pauseLoop 549 | 550 | pauseEnd: 551 | call scanKeys 552 | 553 | ld ix,buttonPause 554 | call checkKeyDown 555 | jr c, pauseEnd ;wait until release of mode 556 | 557 | ld ix, (drefIInfo) 558 | call resetAllNeeded 559 | ld ix, (drefIInfo) 560 | call drawObjectsNoReset 561 | call swapVRamPTR 562 | ld ix, (drefIInfo) 563 | call drawObjects 564 | call swapVRamPTR 565 | ret 566 | 567 | hold: 568 | ld ix,rules 569 | bit rbitHoldEnabled,(ix+0) 570 | ret z ;hold is disabled 571 | ; ld hl, curStatus 572 | ; bit csLockedBit,(hl) 573 | ; ret nz ;don't hold on locking frame 574 | 575 | ld hl, curStatus 576 | bit csUsedHold,(hl) 577 | ret nz ;hold already used once 578 | 579 | ;tell draw system to redraw HOLD 580 | ld ix,(refHold) 581 | res redrawObjBit, (ix+iDataType) 582 | ld hl, drawObjectsNoReset 583 | ld (smcDrawObjectsType),hl 584 | 585 | ld a,(holdT) 586 | cp NULL_BLOCK 587 | jr z, firstHold 588 | 589 | ;need to swap held block and current block using transfer memory 590 | ld hl, holdT 591 | ld b,(hl) 592 | ld a,(curT) 593 | ld (hl), a 594 | ld a,b 595 | ld (curT),a 596 | 597 | ld a,(curT) 598 | call determinedBlock 599 | jr holdShared 600 | firstHold: 601 | ld a,(curT) 602 | ld (holdT),a 603 | 604 | call newBlock ;geneate a new block: nothing to load 605 | holdShared: 606 | ld hl,curStatus 607 | set csUsedHold,(hl) 608 | ret 609 | 610 | update: 611 | ld hl, curStatus + midOfs ;last frame status 612 | bit csNewBlockBit, (hl) ;request new block 613 | jr z,noNewBlock 614 | call newBlock ;if set, create block 615 | ;also requires update hold, if held needs to change 616 | ld ix,rules 617 | bit rbitHoldEnabled, (ix+rfBasic) 618 | jr z, noDrawHold 619 | ld hl,(refHold) 620 | res redrawObjBit, (hl) 621 | noDrawHold: 622 | noNewBlock: 623 | 624 | bit rbitLinesClear, (ix+rfWin) 625 | jr z, skipEndCheck 626 | ;check if lines cleared is less than lines needed 627 | ld a,(lines) 628 | ; ld hl, rules+rLCW 629 | cp (ix+rLCW) ;nc (hl)<=a ;c (hl)>a 630 | jr c, skipEndCheck 631 | ;game has ended, player won 632 | ;ld hl, rules 633 | res rbitGameCont, (ix+rfBasic) 634 | set rbitGameWon, (ix+rfBasic) ;win by lines clear 635 | 636 | skipEndCheck: 637 | 638 | xor a 639 | ; ld (PSS+444),a 640 | checkGravity: 641 | ld a,(level) 642 | dec a 643 | cp 20 644 | jr c,noLevelOverflow 645 | ld a,19 ;max level speed [0-19] 646 | noLevelOverflow: 647 | ld c,a 648 | add a,a 649 | add a,c ;3a: ofs from speedcurve 650 | ld de,0 651 | ld e,a 652 | ld hl,speedCurve 653 | add hl,de 654 | ld hl,(hl) ;hl is the speed in 8.16 fp rows/frame 655 | ex de,hl ;de is speed 656 | ld hl,(timerT) 657 | add hl,de 658 | ld (timerT),hl 659 | checkGravityLoop: 660 | ld hl,(timerT) 661 | ld de,65536 ;threshold for one row drop 662 | or a,a 663 | sbc hl,de 664 | jr c, noDropGravity 665 | ;if carry, hl was less than 65536, so timer's not done 666 | ; ld a,(PSS+444) 667 | ; inc a 668 | ; ld (PSS+444),a 669 | ld (timerT),hl 670 | ld ix,curData 671 | call checkBlockDown 672 | jr checkGravityLoop ;must check for more than 1 row/frame if not locking 673 | noDropGravity: 674 | ;drops are done/unneeded 675 | 676 | ld ix,buttonSoft 677 | call checkKeyDown 678 | jr c, userdrop 679 | ld ix,buttonHard 680 | call checkKeyDown 681 | jr c, harddrop 682 | dropReturn: 683 | 684 | call incGarbage 685 | 686 | ;check if lock 687 | ld hl,lockTimer 688 | ld a,LOCK_DISABLE 689 | cp (hl) 690 | jr z, skipLockCheck 691 | dec (hl) 692 | jr z, lock 693 | skipLockCheck: 694 | ret 695 | 696 | hardDrop: 697 | ld hl,rules 698 | bit rbitHardDropEnabled,(hl) 699 | ret z ;hard drop is disabled 700 | 701 | hardDropLoop: 702 | ld a,(lockTimer) 703 | cp LOCK_DISABLE 704 | jr nz, hdrop ;lock not disabled 705 | ld hl,(score) 706 | inc hl 707 | inc hl 708 | ld (score),hl 709 | ; ld hl,0 710 | ld ix,curData 711 | call checkBlockDown 712 | jr hardDropLoop 713 | hdrop: 714 | ld a,1 715 | ld (lockTimer),a 716 | jr dropReturn 717 | 718 | userDrop: 719 | ld a,(lockTimer) 720 | cp LOCK_DISABLE 721 | jr nz, drop 722 | ld hl,(score) 723 | inc hl 724 | ld (score),hl 725 | 726 | drop: 727 | ; ld hl,0 728 | ; ld (timerT),hl 729 | ld ix,curData 730 | call checkBlockDown 731 | jp dropReturn 732 | 733 | lock: 734 | ld a,LOCK_DISABLE 735 | ld (lockTimer),a 736 | ld hl, curBlock 737 | ld b,4 738 | lockAllBlocks: 739 | push bc 740 | push hl ;save the block data ptr 741 | ld c,(hl) 742 | inc hl 743 | ld b,(hl) ;(c,b) = (ofsx, ofsy) 744 | ld a,(curX) 745 | add a,c 746 | ld h,a 747 | ld a,(curY) 748 | add a,b 749 | ld l,a 750 | call checkBlock ;get offset from coords 751 | ld a,(curT) 752 | ld (hl),a ;save block type 753 | pop hl 754 | inc hl 755 | inc hl 756 | pop bc 757 | djnz lockAllBlocks 758 | 759 | ld hl, curStatus 760 | set csLockedBit,(hl) ;this is the lock frame. 761 | ;since it locks here, do not clear block when drawn. 762 | call lockAnim 763 | 764 | call checkLines 765 | ;only check line clears after a lock 766 | ;note that checkLines runs cascadeAnim, so must happen after lockAnim 767 | 768 | ;call newBlock 769 | ld hl, curStatus 770 | set csNewBlockBit,(hl) ;new block should be created 771 | ;delay spawn by some frames 772 | ld a,(spawnDelay) 773 | ld (spawnTimer),a 774 | ret 775 | 776 | lockAnim: 777 | ; ld ix,(refField) 778 | ; set redrawObjBit, (ix+iDataType) 779 | 780 | ; ld ix,(drefIInfo) 781 | ; call drawObjectsNoReset 782 | ; call swapVRAMPtr 783 | ld ix,(drefIInfo) 784 | call drawObjectsNoReset 785 | ; call swapVRAMPtr 786 | 787 | ld b,8 788 | lockAnimLoop: 789 | push bc 790 | push bc 791 | ; probably erases a lot it doesn't need to 792 | ld ix, midOfs + curData 793 | bit 0,b 794 | jr nz, notOldOfs 795 | ld ix, oldOfs + curData 796 | notOldOfs: 797 | bit csLockedBit,(ix+curStatusOfs) 798 | jr nz, noEraseLocked 799 | push ix 800 | pop de 801 | ld ix,(refField) 802 | call NullPTRMino 803 | noEraseLocked: 804 | call eraseGhostMino 805 | pop bc 806 | 807 | ld ix,(refField) 808 | ld de, curData 809 | ld h,0 810 | bit 1,b 811 | jr z, skipDark 812 | ld h,1<= (hl), so apply the delay 992 | dec hl 993 | dec hl 994 | dec hl 995 | dec hl 996 | jr untilFindLevelOrNone 997 | 998 | ;in: 999 | ;hl: ptr to new potential delay 1000 | ;de: ptr to current delay 1001 | applyDelayIfNeeded: 1002 | ld a,(de) 1003 | cp (hl) 1004 | ret c ;don't apply if a < hl already (keep faster play if already set) 1005 | ld a,(hl) 1006 | ld (de),a 1007 | ret 1008 | 1009 | applyNewDelay: 1010 | inc hl 1011 | ld de,spawnDelay 1012 | call applyDelayIfNeeded 1013 | 1014 | inc hl 1015 | ld de,lockDelay 1016 | call applyDelayIfNeeded 1017 | 1018 | inc hl 1019 | ld de,buttonLeft+buttonTimeStart 1020 | call applyDelayIfNeeded 1021 | ld de,buttonRight+buttonTimeStart 1022 | call applyDelayIfNeeded 1023 | ret 1024 | 1025 | updateB2B: 1026 | ld hl,lineClearInfo 1027 | 1028 | ;keep set until explicitly reset 1029 | bit lcBackToBack,(hl) 1030 | jr z,noPrevB2B 1031 | set lcPreviousB2B,(hl) 1032 | res lcBackToBack,(hl) ;make sure this frame is checked 1033 | noPrevB2B: 1034 | 1035 | ld a,(linesClear) 1036 | or a,a 1037 | jr z,B2BDone ;unaffected by no lines cleared 1038 | 1039 | ;check for potential back-to-back status on this line clear 1040 | bit lcTSpin,(hl) 1041 | jr z,checkTetrisB2B ;no t spin = check lines amt 1042 | 1043 | set lcBackToBack,(hl) 1044 | jr B2BDone ;set from T spin and line clear 1045 | 1046 | checkTetrisB2B: 1047 | set lcBackToBack,(hl) ;set if tetris or better 1048 | ld a,(linesClear) 1049 | cp 4 1050 | jr nc,B2BDone ;reset combo if not tetris 1051 | res lcBackToBack,(hl) ;default unset 1052 | res lcPreviousB2B,(hl) ;needs 2 1053 | B2BDone: 1054 | res lcTSpin,(hl) ;don't keep next for next block 1055 | ;b2b set if tetris or tspin, reset otherwise 1056 | ret 1057 | 1058 | 1059 | tSpinCheckLocation: 1060 | .db -1,-1 1061 | .db 1,-1 1062 | .db 1, 1 1063 | .db -1, 1 1064 | .db -1,-1 1065 | 1066 | tSpinCLCount: 1067 | .db 0 1068 | 1069 | ;sources: 1070 | ;https://tetris.fandom.com/wiki/T-Spin 1071 | ;https://tetris.wiki/Tetris_Guideline 1072 | ;https://harddrop.com/wiki/T-Spin 1073 | ;https://harddrop.com/wiki/Talk:Tetris_Guideline 1074 | ;there are many variations to t-spin checks. 1075 | ;CETris is attempting to conform to the guideline 1076 | ;check. 1077 | 1078 | checkTSpin: 1079 | ld hl,lineClearInfo 1080 | res lcTSpin,(hl) 1081 | 1082 | xor a 1083 | ld (tSpinCLCount),a 1084 | ld b,4 1085 | ld de,tSpinCheckLocation 1086 | checkTSpinLoop: 1087 | push bc 1088 | call hlFromBlockAndPTR 1089 | 1090 | push de 1091 | call checkBlock 1092 | cp NULL_BLOCK 1093 | jr z,emptyCheck 1094 | ld hl,tSpinCLCount ;found block 1095 | inc (hl) 1096 | emptyCheck: 1097 | pop de 1098 | pop bc 1099 | djnz checkTSpinLoop 1100 | 1101 | ld a,(tSpinCLCount) 1102 | cp 3 1103 | ret c 1104 | ;less than 3 corner blocks: invalid T spin 1105 | ;note: set carry -> no t-spin 1106 | ld hl,lineClearInfo 1107 | set lcTSpin,(hl) 1108 | 1109 | ;using the 5th rotation state (triple spin kick) 1110 | ;is always a regular T spin, never a mini 1111 | ld hl,curStatus 1112 | bit csWallKicked,(hl) 1113 | jr nz, regularTSpin 1114 | 1115 | ;if one cell next to pointing side filled: mini 1116 | ld a,(curR) 1117 | add a,a 1118 | ld hl,tSpinCheckLocation 1119 | ld de,0 1120 | ld e,a 1121 | add hl,de ;points to pointing side's info 1122 | ex de,hl ;de points to info 1123 | call hlFromBlockAndPTR 1124 | push de 1125 | call checkBlock 1126 | pop de 1127 | cp NULL_BLOCK 1128 | jr z,isTMini ;implies one block unoccupied = mini 1129 | call hlFromBlockAndPTR 1130 | push de 1131 | call checkBlock 1132 | pop de 1133 | cp NULL_BLOCK 1134 | jr z,isTMini ;implies one block unoccupied = mini 1135 | 1136 | ;if TST kick: standard 1137 | regularTSpin: 1138 | ld hl,pointsPerTLine 1139 | ld (smcPointsPerLine),hl 1140 | or a,a ;clear carry 1141 | ret 1142 | 1143 | ;t-spin mini lol 1144 | isTMini: 1145 | ld hl,pointsPerTMini 1146 | ld (smcPointsPerLine),hl 1147 | or a,a ;clear carry 1148 | ret 1149 | 1150 | ;input: 1151 | ;de=ptr to ofs 1152 | ;output: 1153 | ;h=x+ofs 1154 | ;l=y+ofs 1155 | hlFromBlockAndPTR: 1156 | ex de,hl ;hl is ptr, de is output 1157 | ld a,(curX) ;x location 1158 | add a,(hl) ;add check ofs 1159 | ld d,a 1160 | inc hl 1161 | 1162 | ld a,(curY) ;x location 1163 | add a,(hl) ;add check ofs 1164 | ld e,a 1165 | inc hl 1166 | ex de,hl 1167 | ret 1168 | 1169 | clearLine: 1170 | ld a,b 1171 | cp 1 ;last row is being check and is clear 1172 | jr nz, skipGameEndR0 ;not last row 1173 | ld ix,rules 1174 | bit rbitRow0Clear, (ix+rfWin) 1175 | jr z, skipGameEndR0 ;if row 0 is not the win condition, don't end game 1176 | res rbitGameCont, (ix+rfBasic) 1177 | set rbitGameWon, (ix+rfBasic) ;you've won! 1178 | 1179 | skipGameEndR0: 1180 | push hl 1181 | ld bc,field 1182 | ld de,11 1183 | or a ;clear carry 1184 | sbc hl,bc ;field + displacement - field 1185 | or a 1186 | sbc hl,de ;displacement - 10 1187 | push hl 1188 | pop bc 1189 | ld hl, field 1190 | add hl,bc 1191 | ex de,hl 1192 | ld hl, field + 10 1193 | add hl,bc 1194 | ex de,hl 1195 | lddr ;copy rows down 10 1196 | 1197 | ld hl, field 1198 | ld de, field+1 1199 | ld bc,9 1200 | ld (hl),NULL_BLOCK 1201 | ldir ;clear top row 1202 | 1203 | ld a,(linesClear) 1204 | inc a 1205 | ld (linesClear),a 1206 | pop hl 1207 | ret 1208 | 1209 | cascadeBlocks: 1210 | ld hl,(refField) 1211 | res redrawObjBit, (hl) ;only applies to 1212 | 1213 | ld b,fieldHeight-1 1214 | applyGravity: 1215 | push bc 1216 | 1217 | ;apply from bottom of field up, 1218 | ;fieldHeight number of times 1219 | ld hl,fieldHeight-1 * 10 + field - 1 1220 | ld de,fieldHeight * 10 + field - 1 1221 | ld b,240 1222 | ld c,0 1223 | applyGravityOnce: 1224 | ld a,NULL_BLOCK 1225 | cp (hl) 1226 | jr z,noCopyNoSwap 1227 | ;copy block down 1228 | ex de,hl 1229 | cp (hl) 1230 | jr nz,noCopy ;not a null: no copy down possible 1231 | ;block can be copied 1232 | inc c ;copy counter 1233 | ld a,(de) 1234 | ld (hl),a 1235 | ld a,NULL_BLOCK 1236 | ld (de),a 1237 | 1238 | noCopy: 1239 | ex de,hl ;swap back ptrs to field 1240 | noCopyNoSwap: 1241 | dec de ;advance ptrs up field 1242 | dec hl ;so, reading field backwards: dec ptrs 1243 | djnz applyGravityOnce 1244 | 1245 | ld ix,rules 1246 | bit rbitCascadeAnimation,(ix+rfExtra) 1247 | jr z,noCascadeAnim 1248 | push bc 1249 | push hl 1250 | push de 1251 | ld ix,(drefIInfo) 1252 | call drawObjectsNoReset 1253 | call swapVRamPTR 1254 | pop de 1255 | pop hl 1256 | pop bc 1257 | noCascadeAnim: 1258 | xor a 1259 | cp c 1260 | pop bc ;for djnz 1261 | jr z,noCopiesLeft 1262 | djnz applyGravity 1263 | noCopiesLeft: 1264 | 1265 | call checkLineClears 1266 | ret 1267 | 1268 | newBlock: 1269 | ld hl, rules 1270 | bit rbitPreviewEnabled, (hl) 1271 | jr z, noRedrawPreview 1272 | ld hl,(refPreview) 1273 | res redrawObjBit, (hl) 1274 | ld hl, DrawObjectsNoReset 1275 | ld (smcDrawObjectsType), hl 1276 | noRedrawPreview: 1277 | 1278 | ld hl,rules 1279 | bit rbitBagEnabled,(hl) 1280 | jr nz, bagEnabled 1281 | 1282 | newBlockAgain: 1283 | call rand 1284 | ld a,e 1285 | and $07 1286 | cp RANDOM_NULL 1287 | jr z, newBlockAgain 1288 | jr noBag 1289 | bagEnabled: 1290 | call getNextBagItem 1291 | noBag: 1292 | ld (curT),a 1293 | 1294 | createBlockShared: 1295 | ld a,4 1296 | ld (curX),a 1297 | ld (curY),a 1298 | ld (lowestY),a 1299 | xor a 1300 | ld (curR),a 1301 | ld (curStatus),a ;important: reset all status bits 1302 | ld (timerT),a 1303 | ld (lockResets),a 1304 | 1305 | ld a,LOCK_DISABLE 1306 | ld (lockTimer),a 1307 | 1308 | ld ix,blockData 1309 | ld d,a 1310 | add a,a 1311 | add a,a 1312 | add a,a 1313 | ld de,0 1314 | ld e,a 1315 | add ix, de 1316 | ld a,(curT) ;ensure copied blockdata is CORRECT? 1317 | call copyBlockData 1318 | 1319 | ld ix,curData 1320 | call checkBlockDownOK 1321 | or a,a 1322 | call z,gameEnd 1323 | ;if block check fails immediately, it's a top out 1324 | ret 1325 | 1326 | ;a=block type 1327 | determinedBlock: 1328 | ld (curT),a 1329 | jr createBlockShared 1330 | 1331 | ;inputs: 1332 | ;a = $44 -> neg x 1333 | ;b = $44 -> neg y 1334 | ;e = $3c or $3d: inc a or dec a 1335 | ;hl = 10 or -10? (direction to travel kick table) 1336 | ModifyRotate: 1337 | ;ld a,$44 ;neg 1338 | ld (smcCheckRotateNegX),a 1339 | ld (smcRotateNegX),a 1340 | ld a,b 1341 | ;ld a,$3c ;tst a (used as a 2-byte no-op) 1342 | ld (smcCheckRotateNegY),a 1343 | ld (smcRotateNegY),a 1344 | ;ld hl,-10 1345 | ld a,e 1346 | ld (smcDecInc),a 1347 | ld (smcCheckCalcRXY),hl 1348 | ld (smcNoRotateRXY),hl 1349 | ret 1350 | 1351 | checkRotationLeft: 1352 | ld a,(curR) 1353 | or a,a 1354 | jr nz,skipAdjust4 1355 | ld a,4 1356 | skipAdjust4: 1357 | ld (curR),a 1358 | ; modify a bunch of different points that are similar but not identical 1359 | ld a,$44 1360 | ld b,$3c 1361 | ld e,$3d 1362 | ld hl,-10 1363 | call ModifyRotate 1364 | jr checkRotation 1365 | 1366 | checkRotationRight: 1367 | ; modify a bunch of different points that are similar but not identical 1368 | ld a,$3c ;tst a (essentially a two-byte NOP here) 1369 | ld b,$44 1370 | ld e,$3c ;inc a 1371 | ld hl,10 1372 | call ModifyRotate 1373 | jr checkRotation 1374 | 1375 | checkRotation: 1376 | ld a,(curT) 1377 | ld hl, kicksNormal 1378 | cp 1 ; check I piece 1379 | jr nz, notIKicks 1380 | ld hl, kicksI 1381 | notIKicks: 1382 | cp 4 ; check O piece 1383 | jp z, rotateOSuccess 1384 | push hl ;save table address 1385 | 1386 | call getTableOffset ;de=offset 1387 | pop hl ;restore table address 1388 | add hl,de ;offset + table = starting rotation kick 1389 | 1390 | smcCheckCalcRXY=$+1 1391 | ld de,-10 1392 | call calculateRXY ;hl is up two now, rxy stored 1393 | push hl ;at next offset already 1394 | 1395 | xor a 1396 | ld (rAttempt),a ;there are currently 0 rotation attempts. 1397 | 1398 | ld hl, curBlock 1399 | ld b,4 ;TODO make variable 1400 | checkBlocksRotate: 1401 | ld (rotationTempBC),bc 1402 | ;will be to <-y,x> LEFT or RIGHT 1403 | ;get new y 1404 | ld a,(hl) 1405 | smcCheckRotateNegX=$+1 1406 | neg 1407 | ld e,a 1408 | ld a,(rY) 1409 | add a,e 1410 | cp fieldHeight ;TODO: make variable 1411 | jp nc, noRotation 1412 | ld e,a 1413 | 1414 | ;get new x 1415 | inc hl 1416 | ld a,(hl) 1417 | smcCheckRotateNegY=$+1 1418 | neg 1419 | ld d,a 1420 | ld a,(rX) 1421 | add a,d 1422 | cp 10 ;TODO: make variable 1423 | jr nc, noRotation 1424 | ld d,a 1425 | 1426 | ld (rotationTempHL),hl 1427 | push de 1428 | pop hl ;d,e -> h,l are new rotated coordinates 1429 | call checkBlock 1430 | cp NULL_BLOCK 1431 | jp nz,noRotation ; if a block is found, can't rotate this way 1432 | ld hl,(rotationTempHL) 1433 | inc hl ;hl now points to next x offset 1434 | ld bc,(rotationTempBC) 1435 | djnz checkBlocksRotate 1436 | ;rotation is a go 1437 | ld b,4 1438 | ld hl, curBlock 1439 | rotateBlocks: 1440 | push bc 1441 | ld a,(hl) 1442 | smcRotateNegX=$+1 1443 | neg 1444 | ld e,a 1445 | inc hl 1446 | ld a,(hl) 1447 | smcRotateNegY=$+1 1448 | neg 1449 | ld d,a 1450 | dec hl ;back to X location 1451 | ld (hl),d 1452 | inc hl 1453 | ld (hl),e ;blocks have rotated: now do the next one 1454 | inc hl 1455 | pop bc 1456 | djnz rotateBlocks 1457 | pop hl ;next kick offset (unneeded here) 1458 | 1459 | ld a,(curR) 1460 | smcDecInc: 1461 | inc a ;right 1462 | and $03 1463 | ld (curR),a 1464 | 1465 | ld a,(rX) 1466 | ld (curX),a 1467 | ld a,(rY) ;save the location of the successful turn. 1468 | ld (curY),a 1469 | 1470 | ;check t-spin 1471 | ld hl,curStatus 1472 | ld a,(curT) 1473 | cp 6 ; T block 1474 | jr nz, noTRotate 1475 | set csRotateTBit,(hl) 1476 | noTRotate: 1477 | res csWallKicked,(hl) 1478 | ld a,(rAttempt) 1479 | cp 4 1480 | jr z,notWallKicked 1481 | set csWallKicked,(hl) 1482 | notWallKicked: 1483 | 1484 | rotateOSuccess: 1485 | ld ix,curData 1486 | ;there was a rotate: set lock timer if needed 1487 | call resetLockTimer ;setLockTimerIfGrounded 1488 | ret 1489 | 1490 | noRotation: 1491 | pop hl ;get offset 1492 | 1493 | smcNoRotateRXY=$+1 1494 | ld de,-10 1495 | call calculateRXY ;rxy stored - hl is already at next ofs 1496 | 1497 | ld ix,rules 1498 | bit rbitSRSEnabled,(ix+0) 1499 | ret z ;SRS is disabled - do not try again 1500 | 1501 | push hl ;at next offset already 1502 | ld hl, curBlock 1503 | ld b,4 1504 | 1505 | ld a,(rAttempt) 1506 | inc a 1507 | ld (rAttempt),a 1508 | cp 5 1509 | jp nz, checkBlocksRotate 1510 | 1511 | pop hl ;unneeded. 1512 | ;call setLockTimerIfGrounded 1513 | ret 1514 | 1515 | ;multiplys curR by 10 and stores to de 1516 | getTableOffset: 1517 | ld a,(curR) 1518 | ld e,a 1519 | add a,a 1520 | add a,a 1521 | add a,e 1522 | add a,a ;this is fine because curR in [0,4] -> [0,40] will never carry 1523 | ;has nc 1524 | sbc hl,hl 1525 | ex de,hl 1526 | ld e,a 1527 | ret 1528 | 1529 | ;HL=table ptr 1530 | ;de=+10 or -10 (direction) 1531 | ;updates HL by two 1532 | calculateRXY: 1533 | ld bc,rX 1534 | ld a, (curX) 1535 | add a,(hl) ;add x offset 1536 | add hl,de 1537 | sub (hl) ;subtract next offset 1538 | or a 1539 | sbc hl,de ;undo the addition to next offset (back to start) 1540 | ld (bc), a ;save to special location 1541 | inc bc ;points to rY 1542 | inc hl ;now on Y value 1543 | ld a, (curY) 1544 | add a,(hl) ;add y offset 1545 | add hl,de ;get next offset 1546 | sub (hl) 1547 | or a 1548 | sbc hl,de ;undo again 1549 | ld (bc), a 1550 | inc hl ;hl is 2 past previous offset -> 1551 | ret 1552 | 1553 | checkMoveLeft: 1554 | ld e,0 1555 | ld d,-1 1556 | jr checkMove 1557 | 1558 | checkMoveRight: 1559 | ld e,9 1560 | ld d,1 1561 | 1562 | checkMove: 1563 | ; ld a,(curX) 1564 | ld hl, curBlock 1565 | ld b,4 1566 | checkBlocksToSide: 1567 | ld c, (hl) ; c=xOfs 1568 | ld a,(curX) 1569 | add a,c ;a=x+xOfs 1570 | cp e 1571 | jr z,blockTooFar 1572 | push bc 1573 | push de ;contains d=direction e=edge coordinate 1574 | ;check if block will collide 1575 | ld c,(hl) 1576 | inc hl 1577 | ld b,(hl) ;(c,b) = (ofsx, ofsy) 1578 | inc hl 1579 | push hl ;blockdata at next coord already 1580 | ld a,(curX) 1581 | add a,c 1582 | add a,d 1583 | ld h,a 1584 | ld a,(curY) 1585 | add a,b 1586 | ld l,a 1587 | call checkBlock 1588 | cp NULL_BLOCK 1589 | pop hl ;restore and inc 2 block data ptr 1590 | pop de 1591 | pop bc 1592 | jp nz, blockTooFar ;collision with block 1593 | djnz checkBlocksToSide 1594 | 1595 | ;here: no blocks too far... 1596 | ld hl,curX 1597 | ld a,(hl) 1598 | add a,d 1599 | ld (hl),a 1600 | 1601 | ld hl,curStatus ;last move wasn't rotate 1602 | res csRotateTBit,(hl) 1603 | 1604 | call resetLockTimer 1605 | ret 1606 | ;check if block needs lock 1607 | blockTooFar: 1608 | call notResetHasReset 1609 | ret 1610 | 1611 | ;checks if the block CAN move down AND moves the block if it can. 1612 | ;note: affects lock timer 1613 | ;ix = curData 1614 | checkBlockDown: 1615 | push ix 1616 | call checkBlockDownOK 1617 | pop ix 1618 | or a,a 1619 | jr z, noBlockDown ;check block down failed: no decrement 1620 | inc (ix+curYOfs) 1621 | res csRotateTBit,(ix+curStatusOfs) 1622 | 1623 | noBlockDown: 1624 | ld hl,lowestY 1625 | ld b,(ix+curYOfs) 1626 | ld a,(hl) 1627 | cp b 1628 | jr nc, notLowestY 1629 | ; curY > lowY 1630 | ld (hl),b 1631 | xor a 1632 | ld (lockResets),a ;if block successfully moves down, you get resets back 1633 | 1634 | notLowestY: 1635 | call notResetHasReset 1636 | ret 1637 | 1638 | ;checks if the block CAN move down without actually moving it 1639 | ;input: ix = curdata struct 1640 | checkBlockDownOK: 1641 | lea hl, ix+curBlockOfs+1 ;ptr to y coord of curdata 1642 | ld b,4 ;TODO: make flexible 1643 | checkBlocksInDown: 1644 | ld a, (ix+curYOfs) 1645 | add a,(hl) 1646 | cp fieldHeight-1 1647 | jr z, blockTooFarDown 1648 | push bc 1649 | push hl 1650 | ld c,(hl) 1651 | dec hl 1652 | ; ld b,(hl) ;(b,c) = (ofsx, ofsy) 1653 | ld a,(ix+curXOfs) 1654 | add a,(hl) 1655 | ld h,a 1656 | ld a,(ix+curYOfs) 1657 | add a,c 1658 | ld l,a 1659 | inc l ; +1 to y coord 1660 | call checkBlock 1661 | cp NULL_BLOCK 1662 | pop hl 1663 | pop bc 1664 | jr nz,blockTooFarDown ;block is hit 1665 | inc hl 1666 | inc hl ;to next coord pair 1667 | djnz checkBlocksInDown 1668 | ld a,1 ;success 1669 | ret 1670 | 1671 | blockTooFarDown: 1672 | xor a 1673 | ret 1674 | 1675 | notReset: 1676 | ld ix,curData 1677 | call checkBlockDownOK 1678 | or a,a 1679 | ld a, 1 1680 | jr z, notSafe ; block down not ok 1681 | ld a, LOCK_DISABLE 1682 | notSafe: 1683 | ld (lockTimer), a 1684 | ret 1685 | 1686 | ;resets the lock timer (if reset are left) 1687 | resetLockTimer: 1688 | ld a,(lockTimer) 1689 | cp LOCK_DISABLE 1690 | jr z, notResetHasReset ; lock disabled, no reset needed 1691 | ;reset wanted, lock timer active 1692 | ld hl,lockResets 1693 | ld a, 14 ; check if too many resets 1694 | inc (hl) 1695 | cp (hl) 1696 | jr c, notReset ; too many previous resets 1697 | ;fallthrough to setLockTimerIfGrounded 1698 | 1699 | ;sets the lock timer if block is grounded 1700 | setLockTimerIfGrounded: 1701 | ld a,LOCK_DISABLE 1702 | ld (lockTimer),a 1703 | notResetHasReset: 1704 | ld ix, curData 1705 | call checkBlockDownOK 1706 | or a,a 1707 | ret nz ;success -> no lock timer 1708 | ;fail: fallthrough and set lock timer 1709 | 1710 | ;sets the lock timer if lock was previously disabled 1711 | setLockTimer: 1712 | ld a,(lockTimer) 1713 | cp LOCK_DISABLE 1714 | ret nz 1715 | ;sets the lock timer to the lock delay 1716 | forceLockTimer: 1717 | ld a,(lockDelay) 1718 | cp 2 1719 | jr nc,nonzeroDelay 1720 | ld a,2 ;lock delay 0 and 1 are infinite, cool 1721 | nonzeroDelay: 1722 | ld (lockTimer),a 1723 | ret 1724 | 1725 | ;inputs: 1726 | ;h = x 1727 | ;l = y 1728 | ;returns: a=block hl=location 1729 | ;destroy: de=field 1730 | ;TODO: variable field width? 1731 | checkBlock: 1732 | ld a,l ;y 1733 | add a,a ;x2 1734 | add a,a ;x4 1735 | add a,l ;4y + 1y 1736 | add a,a ;10y 1737 | add a,h ;10y + x (note: only works because field size < 256) 1738 | or a,a 1739 | sbc hl,hl 1740 | ld l,a 1741 | ld de,field 1742 | add hl,de ;10Y + x + field 1743 | ld a,(hl) ;a = block at (10Y+X) 1744 | ret 1745 | 1746 | ;inputs: 1747 | ;a = block type 1748 | copyBlockData: 1749 | dec a 1750 | add a,a ;x2 1751 | add a,a ;x4 1752 | add a,a ;x8 1753 | ;has nc for a<16 (always true) 1754 | sbc hl,hl 1755 | ld l,a 1756 | ld de,blockData 1757 | add hl,de 1758 | ;hl = pointer to blockdata 1759 | ld de, curBlock 1760 | ld bc, blockDataSize 1761 | ldir ;copied to current block mem 1762 | ret 1763 | 1764 | randbag = minoTypes + bag1Ofs 1765 | randbag2 = minoTypes + bag2Ofs 1766 | RANDOM_NULL = 0 ;empty slot 1767 | 1768 | getNextBagItem: 1769 | ld a,(randbag) ;get first item 1770 | push af 1771 | ld hl,randbag+1 1772 | ld de,randbag 1773 | ld bc,13 1774 | ldir ;slide all previous items up in queue 1775 | dec hl 1776 | ;ld hl,randbag2 + 6 1777 | ld (hl),RANDOM_NULL 1778 | ld hl,randBag2 1779 | ld a,(hl) 1780 | or a,a 1781 | ; cp RANDOM_NULL ;check that randbag2 is not empty 1782 | call z,randFillBag ;if the bag is empty, fill it. 1783 | pop af 1784 | ret 1785 | 1786 | initBag: 1787 | call randInit 1788 | 1789 | ld hl, randbag 1790 | call randFillBag 1791 | ;randFillBag ends up pointing to randBag2 at the end anyways 1792 | ; ld hl, randbag2 1793 | call randFillBag 1794 | ret 1795 | 1796 | ;input: 1797 | ;hl= ptr to bag to fill 1798 | randFillBag: 1799 | ld b,7 1800 | ld (randBagPtr),hl 1801 | randFillLoop: 1802 | push bc 1803 | push hl 1804 | randTryAgain: 1805 | call rand 1806 | ld a,e 1807 | and $07 1808 | ; cp RANDOM_NULL 1809 | ;above not needed because RANDOM_NULL=0 1810 | jr z, randTryAgain 1811 | ld b, 7 1812 | ld hl, (randBagPtr) 1813 | randCheckLoop: 1814 | cp (hl) 1815 | jr z, randTryAgain 1816 | inc hl 1817 | djnz randCheckLoop 1818 | pop hl 1819 | ld (hl),a ;value is good; save 1820 | inc hl ;next item 1821 | pop bc 1822 | djnz randFillLoop 1823 | ret 1824 | 1825 | ;initialize random stuff 1826 | randInit: 1827 | ;init randseed 1828 | ld hl,randSeed 1829 | ld a,r 1830 | ld (hl),a 1831 | inc hl 1832 | add a,42 1833 | ld (hl),a 1834 | 1835 | ;init bags with RANDOM_NULL 1836 | ld hl, randbag 1837 | ld de, randbag+1 1838 | ld bc, 13 1839 | ld (hl), RANDOM_NULL 1840 | ldir 1841 | ret 1842 | 1843 | ;generates a random 16-bit nubmer 1844 | ;galosis LFSR, based on wikipedia page 1845 | ;en.wikipedia.org/wiki/Linear-feedback_shift_register 1846 | ;Just read the wikipedia page. 1847 | ;This version is a slightly modified version of a bugged z80 version I created a few years ago. 1848 | rand: 1849 | ld de,(randseed) 1850 | ld a,(randinput) 1851 | bit 0,a 1852 | call nz,randXOR 1853 | ld a,(randinput) 1854 | ld l,a 1855 | push hl 1856 | pop af 1857 | rr d 1858 | rr e 1859 | push af 1860 | pop hl 1861 | ld a,l 1862 | ld (randinput),a 1863 | ld (randseed),de 1864 | ret 1865 | randXOR: 1866 | ld a,%10110100 ;this is the ideal set of bits to invert for a maximal cycle, apparently. (for 16 bits anyway) 1867 | xor d 1868 | ld d,a 1869 | ret 1870 | 1871 | 1872 | drawGame: 1873 | ld ix,(drefIInfo) 1874 | smcDrawObjectsType=$+1 1875 | call drawObjects ; NoReset 1876 | call updateMino 1877 | ; ld hl, curStatus 1878 | ; bit csLockedBit, (hl) 1879 | 1880 | call swapVRamPTR 1881 | 1882 | ld hl,drawObjects 1883 | ld (smcDrawObjectsType),hl 1884 | 1885 | ; ld ix,(drefIInfo) 1886 | ; call drawObjects 1887 | ; call updateMino 1888 | ret 1889 | 1890 | ; resets all except things that should be disabled for this mode 1891 | resetAllNeeded: 1892 | ld ix,(drefIInfo) 1893 | call resetAllDrawCheck 1894 | 1895 | ld hl, rules 1896 | bit rbitHoldEnabled, (hl) 1897 | jr nz,holdDraw 1898 | ld ix, (refHold) 1899 | set redrawObjBit, (ix) 1900 | holdDraw: 1901 | bit rbitPreviewEnabled, (hl) 1902 | jr nz,previewDraw 1903 | ld ix, (refPreview) 1904 | set redrawObjBit, (ix) 1905 | previewDraw: 1906 | ret 1907 | 1908 | ;checks if mino update is needed 1909 | ;if yes, draws mino 1910 | updateMino: 1911 | ;must be done before drawGhostMino to not keep old data in temp 1912 | ld hl, curdata 1913 | ld de, tempData 1914 | ld bc, curDataSize 1915 | ldir 1916 | 1917 | ld a, (curStatus) 1918 | and $0c ; csClearLineBit | csGarbageBit 1919 | ret nz 1920 | 1921 | ld a, (curStatus + midOfs) 1922 | and $0c 1923 | ret nz 1924 | 1925 | call eraseOldMino 1926 | call drawGhostMino ;also erases old ghost 1927 | call drawNewMino 1928 | ret 1929 | 1930 | gameEndInit: 1931 | call checkBest 1932 | 1933 | ld ix,(drefIInfo) 1934 | call resetAllNeeded 1935 | ld ix,(drefIInfo) 1936 | call drawObjectsNoReset 1937 | ld ix,(drefGameOver) 1938 | call drawObjectsNoReset 1939 | call swapVRamPTR 1940 | ;draw to 2nd buffer 1941 | ld ix,(drefIInfo) 1942 | call drawObjectsNoReset 1943 | ld ix,(drefGameOver) 1944 | call drawObjectsNoReset 1945 | call swapVRamPTR 1946 | 1947 | gameEndWait: 1948 | call scanKeys 1949 | 1950 | ld ix,mbuttonConfirm 1951 | call checkKeyDown 1952 | jp c,mainmenu ;go back to main menu 1953 | 1954 | ld ix,mbuttonQuit 1955 | call checkKeyDown 1956 | jp c,exit ;end game 1957 | jr gameEndWait 1958 | 1959 | checkBest: 1960 | ld ix,rules 1961 | bit rbitLowTime,(ix+rfScore) 1962 | jr nz, checkLowTime 1963 | bit rbitHighLine,(ix+rfScore) 1964 | jr nz, checkHighLine 1965 | ;unneeded due to order: 1966 | ;bit rScore,(ix+rfScore) 1967 | ;jr checkHighScore 1968 | 1969 | checkHighScore: 1970 | ;note: top outs for score are A-OK. Only timed games need to worry about "cheesing" for low scores. 1971 | ld hl,(highscore) 1972 | ld de,(score) 1973 | or a,a 1974 | sbc hl,de 1975 | ;carry implies highscore < score 1976 | ret nc ;return if no high score 1977 | ;set high score 1978 | ld hl,(score) 1979 | jr setBestScore 1980 | 1981 | checkHighLine: 1982 | ld hl,(highscore) 1983 | ld de,(lines) 1984 | or a,a 1985 | sbc hl,de 1986 | ;carry implies highscore < score 1987 | ret nc ;return if no high score 1988 | ;set high score 1989 | ld hl,(lines) 1990 | jr setBestScore 1991 | 1992 | checkLowTime: 1993 | bit rbitGameWon,(ix+rfBasic) 1994 | ret z ;return if not set = not a win 1995 | ;since low times can be earned by topping out rapidly, do not count these 1996 | 1997 | ld hl,(highscore) 1998 | ld de,0 1999 | scf 2000 | sbc hl,de 2001 | jr c, setFirstTime;if subtracting 1 results in carry, highscore must be 0 and therefore invalid, so just set the current score. 2002 | 2003 | ld hl,(highscore) 2004 | ld de,(globalTimer) 2005 | or a,a 2006 | sbc hl,de 2007 | ret c ;c implies best time < current time: no record 2008 | ;set low time 2009 | setFirstTime: 2010 | ld hl,(globalTimer) 2011 | jr setBestScore 2012 | 2013 | setBestScore: 2014 | ld a,(ix+rMode) 2015 | ld ix,(saveDataPTR) 2016 | ld de,0 2017 | add a,a 2018 | add a,a 2019 | ld e,a 2020 | add ix,de ;add 4 2021 | add ix,de ;add 8 2022 | ld de,savHighscore 2023 | add ix,de ;ix = savedata + hscoreofs + modeofs 2024 | ld (highscore),hl ;store score 2025 | ld (ix),hl 2026 | ret 2027 | 2028 | eraseOldMino: 2029 | ld hl, curStatus + oldOfs 2030 | bit csLockedBit, (hl) 2031 | ret nz ;don't clear a locked mino 2032 | ;bit csClearLineBit, (hl) 2033 | ;ret nz ;don't erase a mino that cleared lines 2034 | 2035 | ld ix,(refField) 2036 | ld de, oldData 2037 | call NullPTRMino 2038 | ret 2039 | 2040 | drawNewMino: 2041 | ld ix,(refField) 2042 | ld hl,curStatus + midOfs 2043 | bit csLockedBit, (hl) 2044 | ld de, midData 2045 | ld h,0 2046 | call nz, drawMinoObject 2047 | 2048 | ld ix,(refField) 2049 | ld de, curData 2050 | ld h,0 2051 | call drawMinoObject ;likely not actually visible anyways 2052 | ret 2053 | 2054 | eraseGhostMino: 2055 | ld hl, rules + rfBasic 2056 | bit rbitGhostEnabled, (hl) 2057 | ret z ;ghost is disabled 2058 | 2059 | ld hl, curStatus + oldOfs ;can't use oldTempData due to missing changes 2060 | bit csLockedBit, (hl) 2061 | ret nz ;,skipEraseGhost ;only erase not locked blocks 2062 | ;bit csClearLineBit, (hl) 2063 | ;jr nz,skipEraseGhost ;don't erase a mino that cleared lines 2064 | 2065 | ld ix, (refField) 2066 | ld de, oldTempData 2067 | call nullPTRMino 2068 | skipEraseGhost: 2069 | or 1 ;reset z 2070 | ret 2071 | 2072 | 2073 | drawGhostMino: 2074 | call eraseGhostMino 2075 | ret z ;ghost disabled 2076 | 2077 | ld ix, tempData 2078 | 2079 | lowerGhost: 2080 | push ix 2081 | call checkBlockDownOK 2082 | pop ix 2083 | or a,a 2084 | jr z,doneLowering ;check block down failed: no decrement 2085 | inc (ix+curYOfs) ;lower block 2086 | jr lowerGhost 2087 | doneLowering: 2088 | 2089 | ld ix, (refField) 2090 | ld de, tempData 2091 | ld h, 1< null block 2241 | notErase: 2242 | ld hl,(ix+iExtTileset) 2243 | ld bc,0 2244 | ld c,a 2245 | add hl,bc 2246 | add hl,bc ;pointer to sprite/palette pair 2247 | ld e,(hl) ;sprite index 2248 | inc hl 2249 | ld a,(hl) ;palette 2250 | ld (minoBlockObj+iDataA),a 2251 | ld c,(ix+iDataA) ;height (px) 2252 | ld a,(minoBlockObj+iDataW) ;width (bytes) 2253 | ld b,a 2254 | mlt bc ;single sprite size (bytes, assume <256) 2255 | ld b,e 2256 | mlt bc ;multiply by index 2257 | ld hl,(ix+iExtTile) 2258 | inc hl 2259 | add hl,bc ;ptr to sprite data 2260 | ld (minoBlockObj+iDataPTR),hl 2261 | pop hl 2262 | 2263 | bit drawMinoDark, d 2264 | jr z,notDark 2265 | ld a,(minoBlockObj+iDataA) ;TODO: make flexible? use bc? 2266 | ;Alternate TODO: set darkBit, (ix+iDataA) ;? 2267 | add a,shadowOfs 2268 | ld (minoBlockObj+iDataA),a 2269 | notDark: 2270 | ld b,4 ;number of blocks (TODO make flexible) 2271 | ld c,(ix+iDataA) 2272 | bit drawMinoHalf, d 2273 | jr z,notHalfMino 2274 | srl c 2275 | notHalfMino: 2276 | 2277 | ;ix = map data ptr 2278 | ;hl = blockdata ptr 2279 | ;d = settings 2280 | ;b = number of blocks in blockdata 2281 | ;c = size of block (pixels) 2282 | ;at this point, we have set the constants of minoBlockObj and BaseX, BaseY 2283 | drawMinoBlocks: 2284 | push bc 2285 | ld b,(hl) ;blockXOffset (tiles) 2286 | inc hl 2287 | ld d,(hl) ;blockYOffset (tiles) 2288 | inc hl 2289 | push hl 2290 | ; ld a,(ix+iDataW) 2291 | ; cp b ; a - b < 0 --> c set, b > a (out of bounds in x) 2292 | ; jr c,dMBOutOfBounds 2293 | ld e,c 2294 | call multiplyBCSigned 2295 | ld hl,(minoBlockBaseX) 2296 | add hl,bc ;fieldX + minoX + blockX 2297 | ld (minoBlockObj+iDataXL),hl ;overwrites y but it doesn't matter as we set it next 2298 | 2299 | ; ld a,(ix+iDataH) 2300 | ; cp d ; a - d < 0 --> c set, d > a (out of bounds in y) 2301 | ; jr c,dmbOutOfBounds 2302 | ld c,e 2303 | ld b,d 2304 | call multiplyBCSigned 2305 | ld hl,(minoBlockBaseY) ;TODO: make minoBlockBaseY inline 2306 | add hl,bc 2307 | ld a,l ;only valid y <256 2308 | ld (minoBlockObj+iDataY),a 2309 | 2310 | bit 7,h ;check sign 2311 | jp nz, dMBOutOfBounds ;no negative coordinates 2312 | 2313 | push ix 2314 | ld ix,minoBlockObj 2315 | call drawObjectNoReset 2316 | pop ix 2317 | 2318 | dMBOutOfBounds: 2319 | pop hl 2320 | pop bc 2321 | djnz drawMinoBlocks 2322 | ret 2323 | 2324 | ;input: 2325 | ;b,c = multiply, b is signed 2326 | ;destroy: 2327 | ;a,hl if negative 2328 | multiplyBCSigned: 2329 | bit 7,b 2330 | jr z,positiveBC 2331 | negativeBC: 2332 | ld a,b 2333 | neg 2334 | ld b,a 2335 | mlt bc ;positive b*c 2336 | or a,a 2337 | sbc hl,hl 2338 | sbc hl,bc ; -bc 2339 | push hl 2340 | pop bc 2341 | ret 2342 | positiveBC: 2343 | mlt bc 2344 | ret 2345 | 2346 | ;requires ix as obj data ptr 2347 | ;de as setDataFromPTR ptr to curdata etc 2348 | ;this function remains solely for the name joke 2349 | nullPTRMino: 2350 | ld h,1<