paulo@0: /* DS/GBA frontend for LOCKJAW, an implementation of the Soviet Mind Game paulo@0: paulo@0: Copyright (C) 2006-2007 Damian Yerrick paulo@0: paulo@0: This work is free software; you can redistribute it and/or modify paulo@0: it under the terms of the GNU General Public License as published by paulo@0: the Free Software Foundation; either version 2 of the License, or paulo@0: (at your option) any later version. paulo@0: paulo@0: This program is distributed in the hope that it will be useful, paulo@0: but WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the paulo@0: GNU General Public License for more details. paulo@0: paulo@0: You should have received a copy of the GNU General Public License paulo@0: along with this program; if not, write to the Free Software paulo@0: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA paulo@0: paulo@0: Original game concept and design by Alexey Pajitnov. paulo@0: The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, paulo@0: or The Tetris Company LLC. paulo@0: paulo@0: */ paulo@0: paulo@0: #include "fontdraw.h" paulo@0: paulo@0: unsigned char wantPause; paulo@0: volatile char redrawWholeScreen = 0; paulo@0: paulo@0: void finishSprites(); paulo@0: paulo@0: void cls(void) { paulo@0: for (int y = 0; y < SCREEN_H; ++y) { paulo@0: for (int x = 0; x < SCREEN_W; ++x) { paulo@0: MAP[31][y][x] = ' '; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: void drawFrame(LJView *v) { paulo@0: int left = v->field->leftWall; paulo@0: int right = v->field->rightWall; paulo@0: cls(); paulo@0: if (DS_PFTOP > 0) { paulo@0: for (int x = left - 1; x < right + 1; ++x) { paulo@0: MAP[31][DS_PFTOP - 1][DS_PFLEFT + x] = 0x8005; paulo@0: } paulo@0: } paulo@0: if (DS_PFTOP + LJ_PF_VIS_HT < SCREEN_H) { paulo@0: for (int x = left - 1; x < right + 1; ++x) { paulo@0: MAP[31][DS_PFTOP + LJ_PF_VIS_HT][DS_PFLEFT + x] = 0x8004; paulo@0: } paulo@0: } paulo@0: for (int i = 0; i < LJ_PF_VIS_HT; ++i) { paulo@0: MAP[31][i + DS_PFTOP][DS_PFLEFT + left - 1] = 0x8003; paulo@0: MAP[31][i + DS_PFTOP][DS_PFLEFT + right] = 0x8003; paulo@0: } paulo@0: textout("Score", 1, 6 + DS_PFTOP, 0); paulo@0: textout("Lines", 1, 8 + DS_PFTOP, 0); paulo@0: textout("Speed", 1, 10 + DS_PFTOP, 0); paulo@0: } paulo@0: paulo@0: static void drawBlock(struct LJPCView *unused, int x, int y, int b) { paulo@0: if (x >= 0 && x < LJ_PF_WID && y >= 0 && y < LJ_PF_VIS_HT) { paulo@0: int c; paulo@0: paulo@0: if (b == 0x100) { paulo@0: c = '-'; paulo@0: } else if (b == 0x110) { paulo@0: c = 0x8005; // ceiling tile paulo@0: } else if (b >= 0xA0 && b < 0xC0) { paulo@0: c = (b & 0xF0) << 8 | (b & 0x0F) | 0x100; paulo@0: } else if (b >= 0x10) { paulo@0: c = (b & 0xF0) << 8 | (b & 0x0F) | 0x10; paulo@0: } else { paulo@0: c = ' '; paulo@0: } paulo@0: MAP[31][DS_PFTOP + LJ_PF_VIS_HT - 1 - y][DS_PFLEFT + x] = c; paulo@0: } paulo@0: } paulo@0: paulo@0: void updField(const LJView *const v, LJBits rows) { paulo@0: const LJField *const p = v->field; paulo@0: paulo@0: for (int y = 0; paulo@0: y < LJ_PF_VIS_HT && rows != 0; paulo@0: ++y, rows >>= 1) { paulo@0: int blankTile = 0; paulo@0: paulo@0: if (y == p->ceiling) { paulo@0: blankTile = 0x110; paulo@0: } else if (hotlineRows[y] && v->field->scoreStyle == LJSCORE_HOTLINE) { paulo@0: blankTile = 0x100; paulo@0: } paulo@0: if (p->state == LJS_LINES_FALLING && p->stateTime > 0 paulo@0: && ((1 << y) & p->tempRows)) { paulo@0: blankTile = 0x100; paulo@0: } paulo@0: if (rows & 1) { paulo@0: for (int x = p->leftWall; x < p->rightWall; x++) { paulo@0: int b = v->hidePF ? 0 : p->b[y][x]; paulo@0: drawBlock(v->plat, x, y, b ? b : blankTile); paulo@0: } paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: void blitField(LJView *v) { paulo@0: paulo@0: } paulo@0: paulo@0: int getTime() { paulo@0: return curTime; paulo@0: } paulo@0: paulo@0: #if !defined(DISP_VBLANK_IRQ) paulo@0: #define DISP_VBLANK_IRQ LCDC_VBL paulo@0: #endif paulo@0: #if !defined(IRQ_HANDLER) paulo@0: #define IRQ_HANDLER INT_VECTOR paulo@0: #endif paulo@0: paulo@0: void install_timer(void) paulo@0: { paulo@0: paulo@0: // Turn off interrupts before doing anything paulo@0: REG_IME = 0; paulo@0: paulo@0: // Overwrite the ISR paulo@0: IRQ_HANDLER = isr; paulo@0: paulo@0: // Hook up the interrupt destination paulo@0: REG_IE = IRQ_VBLANK; paulo@0: paulo@0: // Acknowledge all pending interrupts paulo@0: REG_IF = ~0; paulo@0: paulo@0: // Set up an interrupt source paulo@0: REG_DISPSTAT = DISP_VBLANK_IRQ; paulo@0: paulo@0: // Turn interrupts back on paulo@0: REG_IME = 1; paulo@0: } paulo@0: paulo@0: void yieldCPU(void) { paulo@0: // we're not multitasking so we don't need this paulo@0: // on the GBA and DS, vsync() does all the waiting we need paulo@0: } paulo@0: paulo@0: static void upcvt_4bit(void *dst, const u8 *src, size_t len) paulo@0: { paulo@0: u32 *out = dst; paulo@0: paulo@0: for(; len > 0; len--) paulo@0: { paulo@0: u32 dst_bits = 0; paulo@0: u32 src_bits = *src++; paulo@0: u32 x; paulo@0: paulo@0: for(x = 0; x < 8; x++) paulo@0: { paulo@0: dst_bits <<= 4; paulo@0: dst_bits |= src_bits & 1; paulo@0: src_bits >>= 1; paulo@0: } paulo@0: *out++ = dst_bits; paulo@0: } paulo@0: } paulo@0: paulo@0: extern const unsigned char text_chr[]; paulo@0: extern const unsigned int text_chr_size; paulo@0: extern const unsigned char gbablk_chr[]; paulo@0: extern const unsigned int gbablk_chr_size; paulo@0: paulo@0: static void loadOneConnection(void *in_dst, const void *in_src) { paulo@0: u16 *dst = in_dst; paulo@0: const u16 *src = in_src; paulo@0: for (unsigned int conn = 0; conn < 16; ++conn) { paulo@0: unsigned int topSegY = (conn & CONNECT_U) ? 32 : 0; paulo@0: unsigned int botSegY = (conn & CONNECT_D) ? 8 : 40; paulo@0: unsigned int leftSegX = (conn & CONNECT_L) ? 16 : 0; paulo@0: unsigned int rightSegX = (conn & CONNECT_R) ? 1 : 17; paulo@0: for (unsigned int i = 0; i < 8; i += 2) { paulo@0: *dst++ = src[leftSegX + topSegY + i]; paulo@0: *dst++ = src[rightSegX + topSegY + i]; paulo@0: } paulo@0: for (unsigned int i = 0; i < 8; i += 2) { paulo@0: *dst++ = src[leftSegX + botSegY + i]; paulo@0: *dst++ = src[rightSegX + botSegY + i]; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void loadConnections(void) { paulo@0: loadOneConnection(PATRAM4(0, 16), gbablk_chr + 8*32); paulo@0: loadOneConnection(PATRAM4(0, 256), gbablk_chr + 12*32); paulo@0: } paulo@0: paulo@0: static void load_font(void) { paulo@0: upcvt_4bit(PATRAM4(0, 0), text_chr, text_chr_size); paulo@0: memcpy(PATRAM4(0, 0), gbablk_chr, 8*32); paulo@0: memcpy(SPR_VRAM(0), gbablk_chr, 8*32); paulo@0: loadConnections(); paulo@0: } paulo@0: paulo@0: void textout(const char *str, int x, int y, int c) { paulo@0: u16 *dst = &(MAP[31][y][x]); paulo@0: int spacesLeft = SCREEN_W - x; paulo@0: paulo@0: c <<= 12; paulo@0: while (*str != 0 && spacesLeft > 0) { paulo@0: *dst++ = c | *(unsigned char *)str++; paulo@0: --spacesLeft; paulo@0: } paulo@0: } paulo@0: paulo@0: static const u16 srsColors[12] = { paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(0, 3, 3), paulo@0: RGB5(0, 0, 3), paulo@0: RGB5(3, 2, 0), paulo@0: RGB5(3, 3, 0), paulo@0: RGB5(0, 3, 0), paulo@0: RGB5(2, 0, 3), paulo@0: RGB5(3, 0, 0), paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(3, 0, 0), paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(3, 2, 1), paulo@0: }; paulo@0: paulo@0: static const u16 arsColors[12] = { paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(3, 1, 0), paulo@0: RGB5(0, 0, 3), paulo@0: RGB5(3, 2, 0), paulo@0: RGB5(3, 3, 0), paulo@0: RGB5(2, 0, 3), paulo@0: RGB5(0, 3, 3), paulo@0: RGB5(0, 3, 0), paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(3, 0, 0), paulo@0: RGB5(2, 2, 2), paulo@0: RGB5(3, 2, 1), paulo@0: }; paulo@0: paulo@0: void setupPalette(const u16 *colors) { paulo@0: for (int i = 1; i < 12; ++i) { paulo@0: int c = colors[i]; paulo@0: paulo@0: BG_PALETTE[i * 16 + 1] = RGB5(22,22,22) + 3 * c; paulo@0: BG_PALETTE[i * 16 + 2] = RGB5(13,13,13) + 6 * c; paulo@0: BG_PALETTE[i * 16 + 3] = RGB5( 4, 4, 4) + 9 * c; paulo@0: BG_PALETTE[i * 16 + 4] = RGB5( 4, 4, 4) + 7 * c; paulo@0: BG_PALETTE[i * 16 + 5] = RGB5( 4, 4, 4) + 5 * c; paulo@0: BG_PALETTE[i * 16 + 6] = RGB5( 4, 4, 4) + 3 * c; paulo@0: } paulo@0: memcpy(SPRITE_PALETTE, BG_PALETTE, 12 * 32); paulo@0: } paulo@0: paulo@0: // libnds style wrapper around libgba header paulo@0: #ifndef DISPLAY_BG0_ACTIVE paulo@0: #define DISPLAY_BG0_ACTIVE BG0_ON paulo@0: #define DISPLAY_SPR_ACTIVE OBJ_ON paulo@0: #define MODE_0_2D MODE_0 paulo@0: #define DISPLAY_SPR_1D_LAYOUT OBJ_1D_MAP paulo@0: static inline void videoSetMode(int x) { paulo@0: REG_DISPCNT = x; paulo@0: } paulo@0: paulo@0: #endif paulo@0: paulo@0: void waitForStart(void) { paulo@0: LJBits lastJ = ~0; paulo@0: LJBits jnew = 0; paulo@0: paulo@0: do { paulo@0: LJBits j = ~REG_KEYINPUT; paulo@0: jnew = j & ~lastJ; paulo@0: lastJ = j; paulo@0: vsync(); paulo@0: } while(!(jnew & (KEY_A | KEY_START))); paulo@0: } paulo@0: paulo@0: paulo@0: static const char *const coprNoticeLines[] = { paulo@0: "LOCKJAW: The Reference", paulo@0: "Version "LJ_VERSION, paulo@0: NULL, paulo@0: "© 2008 Damian Yerrick", paulo@0: "Not sponsored or endorsed by Nintendo", paulo@0: "or Tetris Holding.", paulo@0: "Comes with ABSOLUTELY NO WARRANTY.", paulo@0: "This is free software, and you are welcome", paulo@0: "to share it under the conditions described", paulo@0: "in GPL.txt." paulo@0: }; paulo@0: paulo@0: void coprNotice(void) { paulo@0: videoSetMode(MODE_0_2D); paulo@0: BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31); paulo@0: BG_OFFSET[0].x = 0; paulo@0: BG_OFFSET[0].y = 0; paulo@0: paulo@0: BG_PALETTE[0] = RGB5(31,31,31); paulo@0: BG_PALETTE[1] = RGB5(20,20,20); paulo@0: BG_PALETTE[2] = RGB5( 0, 0, 0); paulo@0: vwfWinInit(&vwfTop); paulo@0: for (int i = 0, y = 8; paulo@0: i < sizeof(coprNoticeLines) / sizeof(coprNoticeLines[0]); paulo@0: ++i) { paulo@0: if (coprNoticeLines[i]) { paulo@0: vwfPuts(&vwfTop, coprNoticeLines[i], 8, y); paulo@0: y += 12; paulo@0: } else { paulo@0: y += 6; paulo@0: } paulo@0: } paulo@0: vwfPuts(&vwfTop, "Press Start", 8, SCREEN_H * 8 - 16); paulo@0: videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE); paulo@0: waitForStart(); paulo@0: } paulo@0: paulo@0: LJBits menuReadPad(void) { paulo@0: LJBits keys = readPad(0); paulo@0: if (keys & VKEY_START) { paulo@0: keys |= VKEY_ROTR; paulo@0: } paulo@0: return keys; paulo@0: } paulo@0: paulo@0: void ljBeginDraw(LJView *v, int sync) { paulo@0: vsync(); paulo@0: finishSprites(); paulo@0: } paulo@0: paulo@0: void ljEndDraw(LJView *v) { paulo@0: paulo@0: } paulo@0: paulo@0: /* Replay stubs */ paulo@0: void replayRecord(struct LJReplay *r, LJBits keys, const LJInput *in) { paulo@0: paulo@0: } paulo@0: paulo@0: void replayClose(struct LJReplay *r) { paulo@0: paulo@0: } paulo@0: paulo@0: int getReplayFrame(struct LJReplay *r, LJInput *d) { paulo@0: return 0; paulo@0: } paulo@0: paulo@0: #define READY_GO_LINE 13 paulo@0: paulo@0: void startingAnimation(LJView *v) { paulo@0: vsync(); paulo@0: gba_poll_sound(v->plat); paulo@0: setupPalette(rotSystems[v->field->rotationSystem]->colorScheme ? arsColors : srsColors); paulo@0: videoSetMode(MODE_0_2D); paulo@0: cls(); paulo@0: load_font(); paulo@0: BG_PALETTE[0] = RGB5(31,31,31); paulo@0: BG_PALETTE[1] = RGB5( 0, 0, 0); paulo@0: drawFrame(v); paulo@0: finishSprites(); paulo@0: vsync(); paulo@0: gba_poll_sound(v->plat); paulo@0: videoSetMode(MODE_0_2D paulo@0: | DISPLAY_BG0_ACTIVE); paulo@0: BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(31); paulo@0: BG_OFFSET[0].x = 0; paulo@0: BG_OFFSET[0].y = 0; paulo@0: paulo@0: textout("Ready", paulo@0: (LJ_PF_WID - 5) / 2 + DS_PFLEFT, paulo@0: DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE, paulo@0: 0); paulo@0: for (int i = 0; i < 30; ++i) { paulo@0: vsync(); paulo@0: gba_poll_sound(v->plat); paulo@0: } paulo@0: v->backDirty = ~0; paulo@0: updField(v, ~0); paulo@0: videoSetMode(MODE_0_2D paulo@0: | DISPLAY_BG0_ACTIVE paulo@0: | DISPLAY_SPR_1D_LAYOUT paulo@0: | DISPLAY_SPR_ACTIVE); paulo@0: drawScore(v); paulo@0: finishSprites(); paulo@0: paulo@0: textout(" GO! ", paulo@0: (LJ_PF_WID - 5) / 2 + DS_PFLEFT, paulo@0: DS_PFTOP + LJ_PF_VIS_HT - 1 - READY_GO_LINE, paulo@0: 0); paulo@0: for (int i = 0; i < 30; ++i) { paulo@0: vsync(); paulo@0: gba_poll_sound(v->plat); paulo@0: } paulo@0: drawFrame(v); paulo@0: wantPause = 0; paulo@0: paulo@0: #ifdef ARM9 paulo@0: tb.cmd = TALKBACK_PLAY_MUSIC; paulo@0: #endif paulo@0: } paulo@0: paulo@0: int pauseGame(struct LJPCView *v) { paulo@0: LJBits lastKeys = ~0; paulo@0: int unpaused = 0; paulo@0: int canceled = 0; paulo@0: paulo@0: // hide playfield paulo@0: for (int y = DS_PFTOP; y < DS_PFTOP + LJ_PF_VIS_HT; ++y) { paulo@0: for (int x = DS_PFLEFT; paulo@0: x < DS_PFLEFT + LJ_PF_WID; paulo@0: ++x) { paulo@0: MAP[31][y][x] = ' '; paulo@0: } paulo@0: } paulo@0: textout("Game", 2 + DS_PFLEFT, 6 + DS_PFTOP, 0); paulo@0: textout("Paused", 2 + DS_PFLEFT, 7 + DS_PFTOP, 0); paulo@0: textout("Start:", 2 + DS_PFLEFT, 10 + DS_PFTOP, 0); paulo@0: textout("Resume", 2 + DS_PFLEFT, 11 + DS_PFTOP, 0); paulo@0: textout("Select:", 2 + DS_PFLEFT, 13 + DS_PFTOP, 0); paulo@0: textout("Exit", 2 + DS_PFLEFT, 14 + DS_PFTOP, 0); paulo@0: paulo@0: #ifdef ARM9 paulo@0: tb.cmd = TALKBACK_PAUSE_MUSIC; paulo@0: #endif paulo@0: while (!unpaused || (lastKeys & (KEY_SELECT | KEY_START))) { paulo@0: int keys = ~REG_KEYINPUT; paulo@0: if (keys & ~lastKeys & KEY_START) { paulo@0: unpaused = 1; paulo@0: } paulo@0: if (keys & ~lastKeys & KEY_SELECT) { paulo@0: unpaused = 1; paulo@0: canceled = 1; paulo@0: } paulo@0: finishSprites(); paulo@0: vsync(); paulo@0: gba_poll_sound(v); paulo@0: lastKeys = keys; paulo@0: } paulo@0: #ifdef ARM9 paulo@0: tb.cmd = TALKBACK_PLAY_MUSIC; paulo@0: #endif paulo@0: return canceled; paulo@0: } paulo@0: paulo@0: int ljHandleConsoleButtons(LJView *v) { paulo@0: LJBits keys = ~REG_KEYINPUT; paulo@0: int canceled = 0; paulo@0: paulo@0: wantPause |= !!(keys & KEY_START); paulo@0: if (wantPause) { paulo@0: canceled = pauseGame(v->plat); paulo@0: wantPause = 0; paulo@0: drawFrame(v); paulo@0: v->backDirty = ~0; paulo@0: } paulo@0: return canceled; paulo@0: } paulo@0: paulo@0: LJBits drawPiece(LJView *const v, void *const b, paulo@0: int piece, int x, int y, int theta, paulo@0: int color, int w, int h); paulo@0: paulo@0: void drawFallingPiece(LJView *v) { paulo@0: LJBits bits = 0; paulo@0: const LJField *const p = v->field; paulo@0: int piece = p->curPiece[0]; paulo@0: int y = ljfixfloor(p->y); paulo@0: const int w = 8; paulo@0: const int h = 8; paulo@0: int drawnY = v->smoothGravity ? ljfixfloor(h * p->y) : h * y; paulo@0: const int color = (p->state == LJS_LANDED) paulo@0: ? -128 - ((p->stateTime + 1) * 128 / (p->speed.lockDelay + 1)) paulo@0: : pieceColors[piece]; paulo@0: paulo@0: bits = drawPiece(v, NULL, piece, paulo@0: w * (p->x + DS_PFLEFT), paulo@0: h * (LJ_PF_VIS_HT + DS_PFTOP) - drawnY, paulo@0: p->theta, paulo@0: color, w, h); paulo@0: bits = (y >= 0) ? bits << y : bits >> -y; paulo@0: bits &= (1 << LJ_PF_VIS_HT) - 1; paulo@0: paulo@0: v->backDirty |= bits | (bits << 1); paulo@0: v->frontDirty |= bits | (bits << 1); paulo@0: } paulo@0: paulo@0: #define SHADOW_BLOCK 0x00 paulo@0: paulo@0: void drawShadow(LJView *v) { paulo@0: LJBits bits = 0; paulo@0: const LJField *const p = v->field; paulo@0: int piece = p->curPiece[0]; paulo@0: int y = p->hardDropY; paulo@0: const int w = 8; paulo@0: const int h = 8; paulo@0: paulo@0: bits = drawPiece(v, NULL, piece, paulo@0: w * (p->x + DS_PFLEFT), paulo@0: h * (LJ_PF_VIS_HT + DS_PFTOP - y), paulo@0: p->theta, paulo@0: SHADOW_BLOCK, w, h); paulo@0: bits = (y >= 0) ? bits << y : bits >> -y; paulo@0: bits &= (1 << LJ_PF_VIS_HT) - 1; paulo@0: paulo@0: v->backDirty |= bits; paulo@0: v->frontDirty |= bits; paulo@0: } paulo@0: paulo@0: void drawNextPieces(LJView *v) { paulo@0: int holdPieceColor = v->field->alreadyHeld paulo@0: ? 0x80 paulo@0: : pieceColors[v->field->holdPiece]; paulo@0: paulo@0: // Draw hold piece paulo@0: drawPiece(v, NULL, paulo@0: v->field->holdPiece, paulo@0: (DS_PFLEFT - 5) * 8, (DS_PFTOP + 5) * 8, 4, paulo@0: holdPieceColor, 8, 8); paulo@0: paulo@0: // Draw next pieces paulo@0: int y = 32 + 8 * DS_PFTOP; paulo@0: int x = (DS_PFLEFT + LJ_PF_WID) * 8; paulo@0: for(int i = 1; i <= v->nextPieces; ++i) { paulo@0: int piece = v->field->curPiece[i]; paulo@0: paulo@0: if (!v->hideNext) { paulo@0: drawPiece(v, NULL, paulo@0: piece, x, y, 4, paulo@0: pieceColors[piece], 8, 8); paulo@0: } paulo@0: y += 20; paulo@0: } paulo@0: v->frontDirty &= (1 << LJ_PF_VIS_HT) - 1; paulo@0: } paulo@0: paulo@0: void drawScore(LJView *v) { paulo@0: char txt[16]; paulo@0: int tpm = -1; paulo@0: int lvl = v->field->speedState.level; paulo@0: paulo@0: siprintf(txt, "%8u", v->field->score); paulo@0: textout(txt, 0, 7 + DS_PFTOP, 0); paulo@0: siprintf(txt, "%8u", v->field->lines); paulo@0: textout(txt, 0, 9 + DS_PFTOP, 0); paulo@0: paulo@0: if (lvl > 0) { paulo@0: textout("Level:", 1, SCREEN_H - 3, 0); paulo@0: siprintf(txt, "%9u", lvl); paulo@0: textout(txt, 0, SCREEN_H - 2, 0); paulo@0: } paulo@0: paulo@0: if (v->nLockTimes >= 2) { paulo@0: int time = v->lockTime[0] - v->lockTime[v->nLockTimes - 1]; paulo@0: if (time > 0) { paulo@0: tpm = 3600 * (v->nLockTimes - 1) / time; paulo@0: } paulo@0: } paulo@0: if (tpm > 0) { paulo@0: siprintf(txt, "%8d", tpm); paulo@0: textout(txt, 0, 11 + DS_PFTOP, 0); paulo@0: } else { paulo@0: textout(" ---", 0, 11 + DS_PFTOP, 0); paulo@0: } paulo@0: paulo@0: { paulo@0: int seconds = v->field->gameTime / 60; paulo@0: int minutes = seconds / 60; paulo@0: seconds -= minutes * 60; paulo@0: siprintf(txt, "%6d:%02d", minutes, seconds); paulo@0: textout(txt, 0, SCREEN_H - 1, 0); paulo@0: } paulo@0: drawNextPieces(v); paulo@0: }