A port of Zachtronics' match-4 game HACK*MATCH to the TI-84 Plus CE

added exa movement and file operations

ariajd27 ecccd109 97c4fc37

+218 -26
+6 -1
makefile
··· 3 3 # ---------------------------- 4 4 5 5 NAME = HACKMTCH 6 - DESCRIPTION = "A Tetris-like game of block-moving and -swapping designed by Zachtronics" 6 + DESCRIPTION = "A fast-paced match-4 designed by Zachtronics" 7 7 COMPRESSED = YES 8 8 ARCHIVED = NO 9 + 10 + DEPS = src/gfx/gfx.h 9 11 10 12 CFLAGS = -Wall -Wextra -Oz 11 13 CXXFLAGS = -Wall -Wextra -Oz ··· 13 15 # ---------------------------- 14 16 15 17 include $(shell cedev-config --makefile) 18 + 19 + src/gfx/gfx.h: 20 + make gfx
src/gfx/background.png

This is a binary file and will not be displayed.

+42 -3
src/gfx/convimg.yaml
··· 4 4 - color: {index: 0, r: 0, g: 0, b: 0} 5 5 - color: {index: 1, r: 255, g: 255, b: 255} 6 6 - color: {index: 2, r: 181, g: 49, b: 33} 7 + - color: {index: 3, r: 179, g: 243, b: 204} 7 8 images: automatic 8 9 9 10 converts: 10 - - name: sprites 11 + - name: misc 12 + palette: global_palette 13 + style: rlet 14 + transparent-color-index: 4 15 + images: 16 + - background.png 17 + - exa_empty.png 18 + - exa_full.png 19 + - title.png 20 + - name: grid_icons 21 + palette: global_palette 22 + style: palette 23 + images: 24 + - file_blue.png 25 + - file_cyan.png 26 + - file_locked.png 27 + - file_purple.png 28 + - file_red.png 29 + - file_yellow.png 30 + - star_blue.png 31 + - star_cyan.png 32 + - star_purple.png 33 + - star_red.png 34 + - star_yellow.png 35 + - name: digits 11 36 palette: global_palette 12 - images: automatic 37 + style: palette 38 + images: 39 + - digit_0.png 40 + - digit_1.png 41 + - digit_2.png 42 + - digit_3.png 43 + - digit_4.png 44 + - digit_5.png 45 + - digit_6.png 46 + - digit_7.png 47 + - digit_8.png 48 + - digit_9.png 49 + - digit_0_grey.png 13 50 14 51 outputs: 15 52 - type: c ··· 17 54 palettes: 18 55 - global_palette 19 56 converts: 20 - - sprites 57 + - misc 58 + - grid_icons 59 + - digits 21 60
src/gfx/exa_empty.png

This is a binary file and will not be displayed.

src/gfx/exa_full.png

This is a binary file and will not be displayed.

src/gfx/file_blue.png

This is a binary file and will not be displayed.

src/gfx/file_cyan.png

This is a binary file and will not be displayed.

src/gfx/file_locked.png

This is a binary file and will not be displayed.

src/gfx/title.png

This is a binary file and will not be displayed.

+170 -22
src/main.c
··· 10 10 11 11 #include "gfx/gfx.h" 12 12 13 - #define NO_BUFFER 13 + // uncomment this line out to draw directly to the screen 14 + // #define NO_BUFFER 14 15 15 16 #define SAVE_VAR_NAME "HKMCHDAT" 16 17 17 - #define FRAME_TIME 1600 18 + #define FRAME_TIME 3200 18 19 19 20 #define COLOR_BLACK 0 20 21 #define COLOR_WHITE 1 21 22 #define COLOR_RED 2 23 + #define COLOR_DASH 3 22 24 23 25 #define TITLE_SPRITE_HOFFSET ((GFX_LCD_WIDTH - title_width) / 2) 24 26 #define TITLE_SPRITE_VOFFSET 36 ··· 29 31 #define MAX_ROWS 11 30 32 #define NUM_INITIAL_ROWS 3 31 33 #define NUM_BLOCK_COLORS 5 34 + #define EXA_START_COL 2 32 35 33 36 #define BG_HOFFSET ((GFX_LCD_WIDTH - background_width) / 2) 34 37 #define BG_VOFFSET ((GFX_LCD_HEIGHT - background_height) / 2) 38 + 35 39 #define GRID_HOFFSET (BG_HOFFSET + 48) 36 40 #define GRID_VOFFSET (BG_VOFFSET + 23) 37 41 #define GRID_SIZE 16 42 + 43 + #define EXA_HOFFSET (BG_HOFFSET + 44) 44 + #define EXA_VOFFSET (BG_VOFFSET + 193) 45 + #define EXA_HELD_HOFFSET 4 46 + #define EXA_HELD_VOFFSET 6 47 + #define DASH_HOFFSET 8 48 + #define DASH_VOFFSET 3 49 + #define DASH_INTERVAL 4 50 + 38 51 #define SCORE_HOFFSET (BG_HOFFSET + 160) 39 52 #define SCORE_VOFFSET (BG_VOFFSET + 41) 40 53 #define HIGH_SCORE_HOFFSET (BG_HOFFSET + 160) 41 54 #define HIGH_SCORE_VOFFSET (BG_VOFFSET + 97) 42 55 #define NUM_DISPLAY_DIGITS 6 43 56 57 + #define FILE_EMPTY 0 58 + #define FILE_RED 1 59 + #define FILE_YELLOW 2 60 + #define FILE_CYAN 3 61 + #define FILE_BLUE 4 62 + #define FILE_PURPLE 5 63 + #define FILE_LOCKED 6 64 + 44 65 bool toExit; 66 + 45 67 unsigned int score; 46 68 unsigned int highScore; 47 69 48 - enum file_t { 49 - EMPTY, 50 - RED, 51 - YELLOW, 52 - CYAN, 53 - BLUE, 54 - PURPLE, 55 - LOCKED 56 - }; 70 + unsigned char files[NUM_COLS][MAX_ROWS]; 71 + unsigned char exaCol; 72 + bool isHoldingFile; 73 + unsigned char heldFile; 57 74 58 75 const struct gfx_sprite_t *fileSprites[] = { 59 76 0, ··· 78 95 digit_9 79 96 }; 80 97 81 - unsigned char files[NUM_COLS][MAX_ROWS]; 98 + gfx_UninitedSprite(behindExa, exa_empty_width, exa_empty_height); 99 + 100 + unsigned char prev2nd, prevAlpha; 101 + 102 + void drawExa() 103 + { 104 + const unsigned char exaX = EXA_HOFFSET + GRID_SIZE * exaCol; 105 + 106 + if (isHoldingFile) 107 + { 108 + gfx_Sprite_NoClip(fileSprites[heldFile], exaX + EXA_HELD_HOFFSET, EXA_VOFFSET + EXA_HELD_VOFFSET); 109 + gfx_RLETSprite_NoClip(exa_full, exaX, EXA_VOFFSET); 110 + } 111 + else 112 + { 113 + gfx_RLETSprite_NoClip(exa_empty, exaX, EXA_VOFFSET); 114 + } 115 + } 116 + 117 + unsigned char *getTargetedFile() 118 + { 119 + for (unsigned char row = MAX_ROWS - 1; row > 0; row--) 120 + { 121 + if (files[exaCol][row] == FILE_EMPTY) continue; 122 + return &files[exaCol][row]; 123 + } 124 + return 0; 125 + } 126 + 127 + unsigned char *getTargetedSpace() 128 + { 129 + for (unsigned char row = 0; row < MAX_ROWS; row++) 130 + { 131 + if (files[exaCol][row] != FILE_EMPTY) continue; 132 + return &files[exaCol][row]; 133 + } 134 + return 0; 135 + } 136 + 137 + bool grab() // all of these return true if something changed 138 + { 139 + unsigned char *targetedFile = getTargetedFile(); 140 + if (targetedFile == 0) return false; // column is empty 141 + 142 + isHoldingFile = true; 143 + heldFile = *targetedFile; 144 + *targetedFile = FILE_EMPTY; 145 + return true; 146 + } 147 + 148 + bool drop() 149 + { 150 + unsigned char *targetedSpace = getTargetedSpace(); 151 + if (targetedSpace == 0) return false; 152 + 153 + isHoldingFile = false; 154 + *targetedSpace = heldFile; 155 + return true; 156 + } 157 + 158 + bool swap() 159 + { 160 + unsigned char *targetedFile = getTargetedFile(); 161 + if (targetedFile == 0) return false; 162 + 163 + const unsigned char swapFile = *targetedFile; 164 + *targetedFile = heldFile; 165 + heldFile = swapFile; 166 + return true; 167 + } 82 168 83 169 bool doInput() 84 170 { 85 - return os_GetCSC(); 171 + kb_Scan(); 172 + 173 + const unsigned char oldExaCol = exaCol; 174 + 175 + if (kb_IsDown(kb_KeyRight) && exaCol < NUM_COLS - 1) exaCol++; 176 + if (kb_IsDown(kb_KeyLeft) && exaCol > 0) exaCol--; 177 + 178 + bool changedExaLook = false; 179 + 180 + // the three main operations 181 + if (kb_IsDown(kb_Key2nd) && !prev2nd) 182 + { 183 + if (isHoldingFile) changedExaLook = drop(); 184 + else changedExaLook = grab(); 185 + } 186 + if (kb_IsDown(kb_KeyAlpha) && !prevAlpha) 187 + { 188 + if (isHoldingFile) changedExaLook = swap(); 189 + // else nothing happens :( 190 + } 191 + 192 + prev2nd = kb_IsDown(kb_Key2nd); 193 + prevAlpha = kb_IsDown(kb_KeyAlpha); 194 + 195 + if (exaCol != oldExaCol || changedExaLook) // redraw the exa 196 + { 197 + const unsigned char oldExaX = EXA_HOFFSET + GRID_SIZE * oldExaCol; 198 + gfx_Sprite(behindExa, oldExaX, EXA_VOFFSET); 199 + 200 + const unsigned char exaX = EXA_HOFFSET + GRID_SIZE * exaCol; 201 + gfx_GetSprite(behindExa, exaX, EXA_VOFFSET); 202 + 203 + drawExa(); 204 + } 205 + 206 + return kb_IsDown(kb_KeyClear); 86 207 } 87 208 88 209 void updateGrid() ··· 101 222 remainder -= divisor * thisDigit; 102 223 if (thisDigit > 0) significant = true; 103 224 104 - if (!significant) gfx_Sprite(digit_0_grey, digitX, y); 105 - else gfx_Sprite(digitSprites[thisDigit], digitX, y); 225 + if (!significant) gfx_Sprite_NoClip(digit_0_grey, digitX, y); 226 + else gfx_Sprite_NoClip(digitSprites[thisDigit], digitX, y); 106 227 107 228 digitX += 8; 108 229 } ··· 110 231 111 232 void drawFrame() 112 233 { 113 - // draw the grid 114 - gfx_SetColor(COLOR_BLACK); // to fill in empty cells 234 + // clear the old grid 235 + gfx_SetColor(COLOR_BLACK); 236 + gfx_FillRectangle_NoClip(GRID_HOFFSET, GRID_VOFFSET, NUM_COLS * GRID_SIZE, MAX_ROWS * GRID_SIZE); 237 + 238 + // draw the new grid 239 + gfx_SetColor(COLOR_DASH); 115 240 unsigned char y = GRID_VOFFSET; 116 241 for (unsigned char row = 0; row < MAX_ROWS; row++) 117 242 { 118 243 unsigned int x = GRID_HOFFSET; 119 244 for (unsigned char col = 0; col < NUM_COLS; col++) 120 245 { 121 - if (files[col][row] == EMPTY) gfx_FillRectangle(x, y, GRID_SIZE, GRID_SIZE); 122 - else gfx_Sprite(fileSprites[files[col][row]], x, y); 246 + if (files[col][row] != FILE_EMPTY) 247 + { 248 + // just draw a file 249 + gfx_Sprite_NoClip(fileSprites[files[col][row]], x, y); 250 + } 251 + else if (col == exaCol) 252 + { 253 + // draw the dashed line up from the exa 254 + const unsigned char xx = x + DASH_HOFFSET; 255 + for (unsigned char yy = y + DASH_VOFFSET; yy < y + GRID_SIZE; yy += DASH_INTERVAL) 256 + { 257 + gfx_SetPixel(xx, yy); 258 + } 259 + } 123 260 x += GRID_SIZE; 124 261 } 125 262 y += GRID_SIZE; 126 263 } 264 + 265 + drawExa(); // otherwise its head gets cut off by the grid update 127 266 128 267 // draw the score 129 268 drawNumber(SCORE_HOFFSET, SCORE_VOFFSET, score); ··· 137 276 { 138 277 // draw the background 139 278 gfx_FillScreen(COLOR_BLACK); 140 - gfx_Sprite(background, BG_HOFFSET, BG_VOFFSET); 279 + gfx_RLETSprite_NoClip(background, BG_HOFFSET, BG_VOFFSET); 141 280 142 281 // draw the high score 143 282 drawNumber(HIGH_SCORE_HOFFSET, HIGH_SCORE_VOFFSET, highScore); ··· 155 294 } 156 295 } 157 296 158 - // get the first screen out there 297 + // set and draw initial exa position 298 + exaCol = EXA_START_COL; 299 + gfx_GetSprite(behindExa, EXA_HOFFSET + EXA_START_COL * GRID_SIZE, EXA_VOFFSET); 300 + gfx_RLETSprite(exa_empty, EXA_HOFFSET + EXA_START_COL * GRID_SIZE, EXA_VOFFSET); 301 + 302 + // get the initial frame out there 159 303 drawFrame(); 160 304 } 161 305 ··· 190 334 ti_Read(&highScore, 3, 1, saveVar); 191 335 } 192 336 ti_Close(saveVar); 337 + 338 + // initialize sprite storage 339 + behindExa->width = exa_empty_width; 340 + behindExa->height = exa_empty_height; 193 341 } 194 342 195 343 void titleScreen() 196 344 { 197 345 gfx_FillScreen(COLOR_BLACK); 198 - gfx_Sprite(title, TITLE_SPRITE_HOFFSET, TITLE_SPRITE_VOFFSET); 346 + gfx_RLETSprite_NoClip(title, TITLE_SPRITE_HOFFSET, TITLE_SPRITE_VOFFSET); 199 347 200 348 gfx_SetTextFGColor(COLOR_RED); 201 349 gfx_SetTextXY(TITLE_TEXT_HOFFSET, TITLE_TEXT_VOFFSET);