annotate src/ljgbads.inc @ 2:80a2761bd3a4

change DS keys (add alt. rotate)
author paulo@localhost
date Mon, 23 Mar 2009 01:19:12 -0700
parents
children
rev   line source
paulo@0 1 /* DS/GBA frontend for LOCKJAW, an implementation of the Soviet Mind Game
paulo@0 2
paulo@0 3 Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net>
paulo@0 4
paulo@0 5 This work is free software; you can redistribute it and/or modify
paulo@0 6 it under the terms of the GNU General Public License as published by
paulo@0 7 the Free Software Foundation; either version 2 of the License, or
paulo@0 8 (at your option) any later version.
paulo@0 9
paulo@0 10 This program is distributed in the hope that it will be useful,
paulo@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
paulo@0 13 GNU General Public License for more details.
paulo@0 14
paulo@0 15 You should have received a copy of the GNU General Public License
paulo@0 16 along with this program; if not, write to the Free Software
paulo@0 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
paulo@0 18
paulo@0 19 Original game concept and design by Alexey Pajitnov.
paulo@0 20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
paulo@0 21 or The Tetris Company LLC.
paulo@0 22
paulo@0 23 */
paulo@0 24
paulo@0 25 #include "fontdraw.h"
paulo@0 26
paulo@0 27 unsigned char wantPause;
paulo@0 28 volatile char redrawWholeScreen = 0;
paulo@0 29
paulo@0 30 void finishSprites();
paulo@0 31
paulo@0 32 void cls(void) {
paulo@0 33 for (int y = 0; y < SCREEN_H; ++y) {
paulo@0 34 for (int x = 0; x < SCREEN_W; ++x) {
paulo@0 35 MAP[31][y][x] = ' ';
paulo@0 36 }
paulo@0 37 }
paulo@0 38 }
paulo@0 39
paulo@0 40 void drawFrame(LJView *v) {
paulo@0 41 int left = v->field->leftWall;
paulo@0 42 int right = v->field->rightWall;
paulo@0 43 cls();
paulo@0 44 if (DS_PFTOP > 0) {
paulo@0 45 for (int x = left - 1; x < right + 1; ++x) {
paulo@0 46 MAP[31][DS_PFTOP - 1][DS_PFLEFT + x] = 0x8005;
paulo@0 47 }
paulo@0 48 }
paulo@0 49 if (DS_PFTOP + LJ_PF_VIS_HT < SCREEN_H) {
paulo@0 50 for (int x = left - 1; x < right + 1; ++x) {
paulo@0 51 MAP[31][DS_PFTOP + LJ_PF_VIS_HT][DS_PFLEFT + x] = 0x8004;
paulo@0 52 }
paulo@0 53 }
paulo@0 54 for (int i = 0; i < LJ_PF_VIS_HT; ++i) {
paulo@0 55 MAP[31][i + DS_PFTOP][DS_PFLEFT + left - 1] = 0x8003;
paulo@0 56 MAP[31][i + DS_PFTOP][DS_PFLEFT + right] = 0x8003;
paulo@0 57 }
paulo@0 58 textout("Score", 1, 6 + DS_PFTOP, 0);
paulo@0 59 textout("Lines", 1, 8 + DS_PFTOP, 0);
paulo@0 60 textout("Speed", 1, 10 + DS_PFTOP, 0);
paulo@0 61 }
paulo@0 62
paulo@0 63 static void drawBlock(struct LJPCView *unused, int x, int y, int b) {
paulo@0 64 if (x >= 0 && x < LJ_PF_WID && y >= 0 && y < LJ_PF_VIS_HT) {
paulo@0 65 int c;
paulo@0 66
paulo@0 67 if (b == 0x100) {
paulo@0 68 c = '-';
paulo@0 69 } else if (b == 0x110) {
paulo@0 70 c = 0x8005; // ceiling tile
paulo@0 71 } else if (b >= 0xA0 && b < 0xC0) {
paulo@0 72 c = (b & 0xF0) << 8 | (b & 0x0F) | 0x100;
paulo@0 73 } else if (b >= 0x10) {
paulo@0 74 c = (b & 0xF0) << 8 | (b & 0x0F) | 0x10;
paulo@0 75 } else {
paulo@0 76 c = ' ';
paulo@0 77 }
paulo@0 78 MAP[31][DS_PFTOP + LJ_PF_VIS_HT - 1 - y][DS_PFLEFT + x] = c;
paulo@0 79 }
paulo@0 80 }
paulo@0 81
paulo@0 82 void updField(const LJView *const v, LJBits rows) {
paulo@0 83 const LJField *const p = v->field;
paulo@0 84
paulo@0 85 for (int y = 0;
paulo@0 86 y < LJ_PF_VIS_HT && rows != 0;
paulo@0 87 ++y, rows >>= 1) {
paulo@0 88 int blankTile = 0;
paulo@0 89
paulo@0 90 if (y == p->ceiling) {
paulo@0 91 blankTile = 0x110;
paulo@0 92 } else if (hotlineRows[y] && v->field->scoreStyle == LJSCORE_HOTLINE) {
paulo@0 93 blankTile = 0x100;
paulo@0 94 }
paulo@0 95 if (p->state == LJS_LINES_FALLING && p->stateTime > 0
paulo@0 96 && ((1 << y) & p->tempRows)) {
paulo@0 97 blankTile = 0x100;
paulo@0 98 }
paulo@0 99 if (rows & 1) {
paulo@0 100 for (int x = p->leftWall; x < p->rightWall; x++) {
paulo@0 101 int b = v->hidePF ? 0 : p->b[y][x];
paulo@0 102 drawBlock(v->plat, x, y, b ? b : blankTile);
paulo@0 103 }
paulo@0 104 }
paulo@0 105 }
paulo@0 106 }
paulo@0 107
paulo@0 108 void blitField(LJView *v) {
paulo@0 109
paulo@0 110 }
paulo@0 111
paulo@0 112 int getTime() {
paulo@0 113 return curTime;
paulo@0 114 }
paulo@0 115
paulo@0 116 #if !defined(DISP_VBLANK_IRQ)
paulo@0 117 #define DISP_VBLANK_IRQ LCDC_VBL
paulo@0 118 #endif
paulo@0 119 #if !defined(IRQ_HANDLER)
paulo@0 120 #define IRQ_HANDLER INT_VECTOR
paulo@0 121 #endif
paulo@0 122
paulo@0 123 void install_timer(void)
paulo@0 124 {
paulo@0 125
paulo@0 126 // Turn off interrupts before doing anything
paulo@0 127 REG_IME = 0;
paulo@0 128
paulo@0 129 // Overwrite the ISR
paulo@0 130 IRQ_HANDLER = isr;
paulo@0 131
paulo@0 132 // Hook up the interrupt destination
paulo@0 133 REG_IE = IRQ_VBLANK;
paulo@0 134
paulo@0 135 // Acknowledge all pending interrupts
paulo@0 136 REG_IF = ~0;
paulo@0 137
paulo@0 138 // Set up an interrupt source
paulo@0 139 REG_DISPSTAT = DISP_VBLANK_IRQ;
paulo@0 140
paulo@0 141 // Turn interrupts back on
paulo@0 142 REG_IME = 1;
paulo@0 143 }
paulo@0 144
paulo@0 145 void yieldCPU(void) {
paulo@0 146 // we're not multitasking so we don't need this
paulo@0 147 // on the GBA and DS, vsync() does all the waiting we need
paulo@0 148 }
paulo@0 149
paulo@0 150 static void upcvt_4bit(void *dst, const u8 *src, size_t len)
paulo@0 151 {
paulo@0 152 u32 *out = dst;
paulo@0 153
paulo@0 154 for(; len > 0; len--)
paulo@0 155 {
paulo@0 156 u32 dst_bits = 0;
paulo@0 157 u32 src_bits = *src++;
paulo@0 158 u32 x;
paulo@0 159
paulo@0 160 for(x = 0; x < 8; x++)
paulo@0 161 {
paulo@0 162 dst_bits <<= 4;
paulo@0 163 dst_bits |= src_bits & 1;
paulo@0 164 src_bits >>= 1;
paulo@0 165 }
paulo@0 166 *out++ = dst_bits;
paulo@0 167 }
paulo@0 168 }
paulo@0 169
paulo@0 170 extern const unsigned char text_chr[];
paulo@0 171 extern const unsigned int text_chr_size;
paulo@0 172 extern const unsigned char gbablk_chr[];
paulo@0 173 extern const unsigned int gbablk_chr_size;
paulo@0 174
paulo@0 175 static void loadOneConnection(void *in_dst, const void *in_src) {
paulo@0 176 u16 *dst = in_dst;
paulo@0 177 const u16 *src = in_src;
paulo@0 178 for (unsigned int conn = 0; conn < 16; ++conn) {
paulo@0 179 unsigned int topSegY = (conn & CONNECT_U) ? 32 : 0;
paulo@0 180 unsigned int botSegY = (conn & CONNECT_D) ? 8 : 40;
paulo@0 181 unsigned int leftSegX = (conn & CONNECT_L) ? 16 : 0;
paulo@0 182 unsigned int rightSegX = (conn & CONNECT_R) ? 1 : 17;
paulo@0 183 for (unsigned int i = 0; i < 8; i += 2) {
paulo@0 184 *dst++ = src[leftSegX + topSegY + i];
paulo@0 185 *dst++ = src[rightSegX + topSegY + i];
paulo@0 186 }
paulo@0 187 for (unsigned int i = 0; i < 8; i += 2) {
paulo@0 188 *dst++ = src[leftSegX + botSegY + i];
paulo@0 189 *dst++ = src[rightSegX + botSegY + i];
paulo@0 190 }
paulo@0 191 }
paulo@0 192 }
paulo@0 193
paulo@0 194 static void loadConnections(void) {
paulo@0 195 loadOneConnection(PATRAM4(0, 16), gbablk_chr + 8*32);
paulo@0 196 loadOneConnection(PATRAM4(0, 256), gbablk_chr + 12*32);
paulo@0 197 }
paulo@0 198
paulo@0 199 static void load_font(void) {
paulo@0 200 upcvt_4bit(PATRAM4(0, 0), text_chr, text_chr_size);
paulo@0 201 memcpy(PATRAM4(0, 0), gbablk_chr, 8*32);
paulo@0 202 memcpy(SPR_VRAM(0), gbablk_chr, 8*32);
paulo@0 203 loadConnections();
paulo@0 204 }
paulo@0 205
paulo@0 206 void textout(const char *str, int x, int y, int c) {
paulo@0 207 u16 *dst = &(MAP[31][y][x]);
paulo@0 208 int spacesLeft = SCREEN_W - x;
paulo@0 209
paulo@0 210 c <<= 12;
paulo@0 211 while (*str != 0 && spacesLeft > 0) {
paulo@0 212 *dst++ = c | *(unsigned char *)str++;
paulo@0 213 --spacesLeft;
paulo@0 214 }
paulo@0 215 }
paulo@0 216
paulo@0 217 static const u16 srsColors[12] = {
paulo@0 218 RGB5(2, 2, 2),
paulo@0 219 RGB5(0, 3, 3),
paulo@0 220 RGB5(0, 0, 3),
paulo@0 221 RGB5(3, 2, 0),
paulo@0 222 RGB5(3, 3, 0),
paulo@0 223 RGB5(0, 3, 0),
paulo@0 224 RGB5(2, 0, 3),
paulo@0 225 RGB5(3, 0, 0),
paulo@0 226 RGB5(2, 2, 2),
paulo@0 227 RGB5(3, 0, 0),
paulo@0 228 RGB5(2, 2, 2),
paulo@0 229 RGB5(3, 2, 1),
paulo@0 230 };
paulo@0 231
paulo@0 232 static const u16 arsColors[12] = {
paulo@0 233 RGB5(2, 2, 2),
paulo@0 234 RGB5(3, 1, 0),
paulo@0 235 RGB5(0, 0, 3),
paulo@0 236 RGB5(3, 2, 0),
paulo@0 237 RGB5(3, 3, 0),
paulo@0 238 RGB5(2, 0, 3),
paulo@0 239 RGB5(0, 3, 3),
paulo@0 240 RGB5(0, 3, 0),
paulo@0 241 RGB5(2, 2, 2),
paulo@0 242 RGB5(3, 0, 0),
paulo@0 243 RGB5(2, 2, 2),
paulo@0 244 RGB5(3, 2, 1),
paulo@0 245 };
paulo@0 246
paulo@0 247 void setupPalette(const u16 *colors) {
paulo@0 248 for (int i = 1; i < 12; ++i) {
paulo@0 249 int c = colors[i];
paulo@0 250
paulo@0 251 BG_PALETTE[i * 16 + 1] = RGB5(22,22,22) + 3 * c;
paulo@0 252 BG_PALETTE[i * 16 + 2] = RGB5(13,13,13) + 6 * c;
paulo@0 253 BG_PALETTE[i * 16 + 3] = RGB5( 4, 4, 4) + 9 * c;
paulo@0 254 BG_PALETTE[i * 16 + 4] = RGB5( 4, 4, 4) + 7 * c;
paulo@0 255 BG_PALETTE[i * 16 + 5] = RGB5( 4, 4, 4) + 5 * c;
paulo@0 256 BG_PALETTE[i * 16 + 6] = RGB5( 4, 4, 4) + 3 * c;
paulo@0 257 }
paulo@0 258 memcpy(SPRITE_PALETTE, BG_PALETTE, 12 * 32);
paulo@0 259 }
paulo@0 260
paulo@0 261 // libnds style wrapper around libgba header
paulo@0 262 #ifndef DISPLAY_BG0_ACTIVE
paulo@0 263 #define DISPLAY_BG0_ACTIVE BG0_ON
paulo@0 264 #define DISPLAY_SPR_ACTIVE OBJ_ON
paulo@0 265 #define MODE_0_2D MODE_0
paulo@0 266 #define DISPLAY_SPR_1D_LAYOUT OBJ_1D_MAP
paulo@0 267 static inline void videoSetMode(int x) {
paulo@0 268 REG_DISPCNT = x;
paulo@0 269 }
paulo@0 270
paulo@0 271 #endif
paulo@0 272
paulo@0 273 void waitForStart(void) {
paulo@0 274 LJBits lastJ = ~0;
paulo@0 275 LJBits jnew = 0;
paulo@0 276
paulo@0 277 do {
paulo@0 278 LJBits j = ~REG_KEYINPUT;
paulo@0 279 jnew = j & ~lastJ;
paulo@0 280 lastJ = j;
paulo@0 281 vsync();
paulo@0 282 } while(!(jnew & (KEY_A | KEY_START)));
paulo@0 283 }
paulo@0 284
paulo@0 285
paulo@0 286 static const char *const coprNoticeLines[] = {
paulo@0 287 "LOCKJAW: The Reference",
paulo@0 288 "Version "LJ_VERSION,
paulo@0 289 NULL,
paulo@0 290 "© 2008 Damian Yerrick",
paulo@0 291 "Not sponsored or endorsed by Nintendo",
paulo@0 292 "or Tetris Holding.",
paulo@0 293 "Comes with ABSOLUTELY NO WARRANTY.",
paulo@0 294 "This is free software, and you are welcome",
paulo@0 295 "to share it under the conditions described",
paulo@0 296 "in GPL.txt."
paulo@0 297 };
paulo@0 298
paulo@0 299 void coprNotice(void) {
paulo@0 300 videoSetMode(MODE_0_2D);
paulo@0 301 BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31);
paulo@0 302 BG_OFFSET[0].x = 0;
paulo@0 303 BG_OFFSET[0].y = 0;
paulo@0 304
paulo@0 305 BG_PALETTE[0] = RGB5(31,31,31);
paulo@0 306 BG_PALETTE[1] = RGB5(20,20,20);
paulo@0 307 BG_PALETTE[2] = RGB5( 0, 0, 0);
paulo@0 308 vwfWinInit(&vwfTop);
paulo@0 309 for (int i = 0, y = 8;
paulo@0 310 i < sizeof(coprNoticeLines) / sizeof(coprNoticeLines[0]);
paulo@0 311 ++i) {
paulo@0 312 if (coprNoticeLines[i]) {
paulo@0 313 vwfPuts(&vwfTop, coprNoticeLines[i], 8, y);
paulo@0 314 y += 12;
paulo@0 315 } else {
paulo@0 316 y += 6;
paulo@0 317 }
paulo@0 318 }
paulo@0 319 vwfPuts(&vwfTop, "Press Start", 8, SCREEN_H * 8 - 16);
paulo@0 320 videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE);
paulo@0 321 waitForStart();
paulo@0 322 }
paulo@0 323
paulo@0 324 LJBits menuReadPad(void) {
paulo@0 325 LJBits keys = readPad(0);
paulo@0 326 if (keys & VKEY_START) {
paulo@0 327 keys |= VKEY_ROTR;
paulo@0 328 }
paulo@0 329 return keys;
paulo@0 330 }
paulo@0 331
paulo@0 332 void ljBeginDraw(LJView *v, int sync) {
paulo@0 333 vsync();
paulo@0 334 finishSprites();
paulo@0 335 }
paulo@0 336
paulo@0 337 void ljEndDraw(LJView *v) {
paulo@0 338
paulo@0 339 }
paulo@0 340
paulo@0 341 /* Replay stubs */
paulo@0 342 void replayRecord(struct LJReplay *r, LJBits keys, const LJInput *in) {
paulo@0 343
paulo@0 344 }
paulo@0 345
paulo@0 346 void replayClose(struct LJReplay *r) {
paulo@0 347
paulo@0 348 }
paulo@0 349
paulo@0 350 int getReplayFrame(struct LJReplay *r, LJInput *d) {
paulo@0 351 return 0;
paulo@0 352 }
paulo@0 353
paulo@0 354 #define READY_GO_LINE 13
paulo@0 355
paulo@0 356 void startingAnimation(LJView *v) {
paulo@0 357 vsync();
paulo@0 358 gba_poll_sound(v->plat);
paulo@0 359 setupPalette(rotSystems[v->field->rotationSystem]->colorScheme ? arsColors : srsColors);
paulo@0 360 videoSetMode(MODE_0_2D);
paulo@0 361 cls();
paulo@0 362 load_font();
paulo@0 363 BG_PALETTE[0] = RGB5(31,31,31);
paulo@0 364 BG_PALETTE[1] = RGB5( 0, 0, 0);
paulo@0 365 drawFrame(v);
paulo@0 366 finishSprites();
paulo@0 367 vsync();
paulo@0 368 gba_poll_sound(v->plat);
paulo@0 369 videoSetMode(MODE_0_2D
paulo@0 370 | DISPLAY_BG0_ACTIVE);
paulo@0 371 BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31);
paulo@0 372 BG_OFFSET[0].x = 0;
paulo@0 373 BG_OFFSET[0].y = 0;
paulo@0 374
paulo@0 375 textout("Ready",
paulo@0 376 (LJ_PF_WID - 5) / 2 + DS_PFLEFT,
paulo@0 377 DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE,
paulo@0 378 0);
paulo@0 379 for (int i = 0; i < 30; ++i) {
paulo@0 380 vsync();
paulo@0 381 gba_poll_sound(v->plat);
paulo@0 382 }
paulo@0 383 v->backDirty = ~0;
paulo@0 384 updField(v, ~0);
paulo@0 385 videoSetMode(MODE_0_2D
paulo@0 386 | DISPLAY_BG0_ACTIVE
paulo@0 387 | DISPLAY_SPR_1D_LAYOUT
paulo@0 388 | DISPLAY_SPR_ACTIVE);
paulo@0 389 drawScore(v);
paulo@0 390 finishSprites();
paulo@0 391
paulo@0 392 textout(" GO! ",
paulo@0 393 (LJ_PF_WID - 5) / 2 + DS_PFLEFT,
paulo@0 394 DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE,
paulo@0 395 0);
paulo@0 396 for (int i = 0; i < 30; ++i) {
paulo@0 397 vsync();
paulo@0 398 gba_poll_sound(v->plat);
paulo@0 399 }
paulo@0 400 drawFrame(v);
paulo@0 401 wantPause = 0;
paulo@0 402
paulo@0 403 #ifdef ARM9
paulo@0 404 tb.cmd = TALKBACK_PLAY_MUSIC;
paulo@0 405 #endif
paulo@0 406 }
paulo@0 407
paulo@0 408 int pauseGame(struct LJPCView *v) {
paulo@0 409 LJBits lastKeys = ~0;
paulo@0 410 int unpaused = 0;
paulo@0 411 int canceled = 0;
paulo@0 412
paulo@0 413 // hide playfield
paulo@0 414 for (int y = DS_PFTOP; y < DS_PFTOP + LJ_PF_VIS_HT; ++y) {
paulo@0 415 for (int x = DS_PFLEFT;
paulo@0 416 x < DS_PFLEFT + LJ_PF_WID;
paulo@0 417 ++x) {
paulo@0 418 MAP[31][y][x] = ' ';
paulo@0 419 }
paulo@0 420 }
paulo@0 421 textout("Game", 2 + DS_PFLEFT, 6 + DS_PFTOP, 0);
paulo@0 422 textout("Paused", 2 + DS_PFLEFT, 7 + DS_PFTOP, 0);
paulo@0 423 textout("Start:", 2 + DS_PFLEFT, 10 + DS_PFTOP, 0);
paulo@0 424 textout("Resume", 2 + DS_PFLEFT, 11 + DS_PFTOP, 0);
paulo@0 425 textout("Select:", 2 + DS_PFLEFT, 13 + DS_PFTOP, 0);
paulo@0 426 textout("Exit", 2 + DS_PFLEFT, 14 + DS_PFTOP, 0);
paulo@0 427
paulo@0 428 #ifdef ARM9
paulo@0 429 tb.cmd = TALKBACK_PAUSE_MUSIC;
paulo@0 430 #endif
paulo@0 431 while (!unpaused || (lastKeys & (KEY_SELECT | KEY_START))) {
paulo@0 432 int keys = ~REG_KEYINPUT;
paulo@0 433 if (keys & ~lastKeys & KEY_START) {
paulo@0 434 unpaused = 1;
paulo@0 435 }
paulo@0 436 if (keys & ~lastKeys & KEY_SELECT) {
paulo@0 437 unpaused = 1;
paulo@0 438 canceled = 1;
paulo@0 439 }
paulo@0 440 finishSprites();
paulo@0 441 vsync();
paulo@0 442 gba_poll_sound(v);
paulo@0 443 lastKeys = keys;
paulo@0 444 }
paulo@0 445 #ifdef ARM9
paulo@0 446 tb.cmd = TALKBACK_PLAY_MUSIC;
paulo@0 447 #endif
paulo@0 448 return canceled;
paulo@0 449 }
paulo@0 450
paulo@0 451 int ljHandleConsoleButtons(LJView *v) {
paulo@0 452 LJBits keys = ~REG_KEYINPUT;
paulo@0 453 int canceled = 0;
paulo@0 454
paulo@0 455 wantPause |= !!(keys & KEY_START);
paulo@0 456 if (wantPause) {
paulo@0 457 canceled = pauseGame(v->plat);
paulo@0 458 wantPause = 0;
paulo@0 459 drawFrame(v);
paulo@0 460 v->backDirty = ~0;
paulo@0 461 }
paulo@0 462 return canceled;
paulo@0 463 }
paulo@0 464
paulo@0 465 LJBits drawPiece(LJView *const v, void *const b,
paulo@0 466 int piece, int x, int y, int theta,
paulo@0 467 int color, int w, int h);
paulo@0 468
paulo@0 469 void drawFallingPiece(LJView *v) {
paulo@0 470 LJBits bits = 0;
paulo@0 471 const LJField *const p = v->field;
paulo@0 472 int piece = p->curPiece[0];
paulo@0 473 int y = ljfixfloor(p->y);
paulo@0 474 const int w = 8;
paulo@0 475 const int h = 8;
paulo@0 476 int drawnY = v->smoothGravity ? ljfixfloor(h * p->y) : h * y;
paulo@0 477 const int color = (p->state == LJS_LANDED)
paulo@0 478 ? -128 - ((p->stateTime + 1) * 128 / (p->speed.lockDelay + 1))
paulo@0 479 : pieceColors[piece];
paulo@0 480
paulo@0 481 bits = drawPiece(v, NULL, piece,
paulo@0 482 w * (p->x + DS_PFLEFT),
paulo@0 483 h * (LJ_PF_VIS_HT + DS_PFTOP) - drawnY,
paulo@0 484 p->theta,
paulo@0 485 color, w, h);
paulo@0 486 bits = (y >= 0) ? bits << y : bits >> -y;
paulo@0 487 bits &= (1 << LJ_PF_VIS_HT) - 1;
paulo@0 488
paulo@0 489 v->backDirty |= bits | (bits << 1);
paulo@0 490 v->frontDirty |= bits | (bits << 1);
paulo@0 491 }
paulo@0 492
paulo@0 493 #define SHADOW_BLOCK 0x00
paulo@0 494
paulo@0 495 void drawShadow(LJView *v) {
paulo@0 496 LJBits bits = 0;
paulo@0 497 const LJField *const p = v->field;
paulo@0 498 int piece = p->curPiece[0];
paulo@0 499 int y = p->hardDropY;
paulo@0 500 const int w = 8;
paulo@0 501 const int h = 8;
paulo@0 502
paulo@0 503 bits = drawPiece(v, NULL, piece,
paulo@0 504 w * (p->x + DS_PFLEFT),
paulo@0 505 h * (LJ_PF_VIS_HT + DS_PFTOP - y),
paulo@0 506 p->theta,
paulo@0 507 SHADOW_BLOCK, w, h);
paulo@0 508 bits = (y >= 0) ? bits << y : bits >> -y;
paulo@0 509 bits &= (1 << LJ_PF_VIS_HT) - 1;
paulo@0 510
paulo@0 511 v->backDirty |= bits;
paulo@0 512 v->frontDirty |= bits;
paulo@0 513 }
paulo@0 514
paulo@0 515 void drawNextPieces(LJView *v) {
paulo@0 516 int holdPieceColor = v->field->alreadyHeld
paulo@0 517 ? 0x80
paulo@0 518 : pieceColors[v->field->holdPiece];
paulo@0 519
paulo@0 520 // Draw hold piece
paulo@0 521 drawPiece(v, NULL,
paulo@0 522 v->field->holdPiece,
paulo@0 523 (DS_PFLEFT - 5) * 8, (DS_PFTOP + 5) * 8, 4,
paulo@0 524 holdPieceColor, 8, 8);
paulo@0 525
paulo@0 526 // Draw next pieces
paulo@0 527 int y = 32 + 8 * DS_PFTOP;
paulo@0 528 int x = (DS_PFLEFT + LJ_PF_WID) * 8;
paulo@0 529 for(int i = 1; i <= v->nextPieces; ++i) {
paulo@0 530 int piece = v->field->curPiece[i];
paulo@0 531
paulo@0 532 if (!v->hideNext) {
paulo@0 533 drawPiece(v, NULL,
paulo@0 534 piece, x, y, 4,
paulo@0 535 pieceColors[piece], 8, 8);
paulo@0 536 }
paulo@0 537 y += 20;
paulo@0 538 }
paulo@0 539 v->frontDirty &= (1 << LJ_PF_VIS_HT) - 1;
paulo@0 540 }
paulo@0 541
paulo@0 542 void drawScore(LJView *v) {
paulo@0 543 char txt[16];
paulo@0 544 int tpm = -1;
paulo@0 545 int lvl = v->field->speedState.level;
paulo@0 546
paulo@0 547 siprintf(txt, "%8u", v->field->score);
paulo@0 548 textout(txt, 0, 7 + DS_PFTOP, 0);
paulo@0 549 siprintf(txt, "%8u", v->field->lines);
paulo@0 550 textout(txt, 0, 9 + DS_PFTOP, 0);
paulo@0 551
paulo@0 552 if (lvl > 0) {
paulo@0 553 textout("Level:", 1, SCREEN_H - 3, 0);
paulo@0 554 siprintf(txt, "%9u", lvl);
paulo@0 555 textout(txt, 0, SCREEN_H - 2, 0);
paulo@0 556 }
paulo@0 557
paulo@0 558 if (v->nLockTimes >= 2) {
paulo@0 559 int time = v->lockTime[0] - v->lockTime[v->nLockTimes - 1];
paulo@0 560 if (time > 0) {
paulo@0 561 tpm = 3600 * (v->nLockTimes - 1) / time;
paulo@0 562 }
paulo@0 563 }
paulo@0 564 if (tpm > 0) {
paulo@0 565 siprintf(txt, "%8d", tpm);
paulo@0 566 textout(txt, 0, 11 + DS_PFTOP, 0);
paulo@0 567 } else {
paulo@0 568 textout(" ---", 0, 11 + DS_PFTOP, 0);
paulo@0 569 }
paulo@0 570
paulo@0 571 {
paulo@0 572 int seconds = v->field->gameTime / 60;
paulo@0 573 int minutes = seconds / 60;
paulo@0 574 seconds -= minutes * 60;
paulo@0 575 siprintf(txt, "%6d:%02d", minutes, seconds);
paulo@0 576 textout(txt, 0, SCREEN_H - 1, 0);
paulo@0 577 }
paulo@0 578 drawNextPieces(v);
paulo@0 579 }