annotate src/ljpc.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 /* PC frontend for LOCKJAW, an implementation of the Soviet Mind Game
paulo@0 2
paulo@0 3 Copyright (C) 2006-2008 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 "ljpc.h"
paulo@0 26 #include "ljreplay.h"
paulo@0 27 #include <jpgalleg.h>
paulo@0 28 #include <time.h>
paulo@0 29 #include "scenario.h"
paulo@0 30 #include "ljpath.h"
paulo@0 31
paulo@0 32 #if 1
paulo@0 33 #define LJ_VERSION "0.46a ("__DATE__")"
paulo@0 34 #else
paulo@0 35 #define LJ_VERSION "WIP ("__DATE__")"
paulo@0 36 #endif
paulo@0 37
paulo@0 38 #define USE_PICS_FOLDER 0
paulo@0 39 #define MAX_PLAYERS 2
paulo@0 40 #define LJ_TICK_RATE 3600 // frames per minute
paulo@0 41
paulo@0 42 int bgColor, fgColor = 0, hiliteColor, pfBgColor = 0, pfFgColor;
paulo@0 43 static volatile int curTime = 0;
paulo@0 44 volatile char redrawWholeScreen = 1;
paulo@0 45 static volatile int wantPause = 0;
paulo@0 46 const DATAFILE *dat = NULL, *sound_dat = NULL;
paulo@0 47 const FONT *aver32 = NULL, *aver16 = NULL;
paulo@0 48 char withSound = 0;
paulo@0 49 char autoPause;
paulo@0 50 int refreshRate = 0;
paulo@0 51 char demoFilename[512];
paulo@0 52
paulo@0 53 int withPics = -1;
paulo@0 54
paulo@0 55 char skinName[PATH_MAX] = "default.skin";
paulo@0 56 char ljblocksSRSName[PATH_MAX];
paulo@0 57 char ljblocksSegaName[PATH_MAX];
paulo@0 58 char ljconnSRSName[PATH_MAX];
paulo@0 59 char ljconnSegaName[PATH_MAX];
paulo@0 60 char ljbgName[PATH_MAX];
paulo@0 61 char menubgName[PATH_MAX];
paulo@0 62 char bgmName[PATH_MAX];
paulo@0 63 char bgmRhythmName[PATH_MAX];
paulo@0 64 unsigned long int bgmLoopPoint = 0;
paulo@0 65 int bgmReadyGo = 0;
paulo@0 66 int bgmVolume = 128;
paulo@0 67 int skinW = 800;
paulo@0 68 int skinH = 600;
paulo@0 69
paulo@0 70
paulo@0 71
paulo@0 72
paulo@0 73 static void incCurTime(void) {
paulo@0 74 ++curTime;
paulo@0 75 } END_OF_FUNCTION(incCurTime);
paulo@0 76
paulo@0 77 static void amnesia(void) {
paulo@0 78 redrawWholeScreen = 1;
paulo@0 79 } END_OF_FUNCTION(amnesia);
paulo@0 80
paulo@0 81 static void requestPause(void) {
paulo@0 82 wantPause |= autoPause;
paulo@0 83 }
paulo@0 84
paulo@0 85
paulo@0 86 int getTime(void) {
paulo@0 87 return curTime;
paulo@0 88 }
paulo@0 89
paulo@0 90 void yieldCPU(void) {
paulo@0 91 rest(5);
paulo@0 92 }
paulo@0 93
paulo@0 94 void ljBeginDraw(LJView *v, int sync) {
paulo@0 95 vsync();
paulo@0 96 if (redrawWholeScreen) {
paulo@0 97 redrawWholeScreen = 0;
paulo@0 98 playRedrawScreen(v);
paulo@0 99 }
paulo@0 100
paulo@0 101 BITMAP *sc = v->plat->skin->fullback;
paulo@0 102
paulo@0 103 // Draw shape
paulo@0 104 blit(v->plat->skin->bg, sc, 0, 0, 0, 0, 48, 16);
paulo@0 105 if (v->control->replayDst) {
paulo@0 106
paulo@0 107 // circle: record
paulo@0 108 circlefill(sc, 8, 8, 7, fgColor);
paulo@0 109 textout_ex(sc, aver16, "Rec", 18, 2, fgColor, -1);
paulo@0 110 } else if (v->control->replaySrc) {
paulo@0 111
paulo@0 112 // triangle: play
paulo@0 113 for (int wid = 0; wid < 7; ++wid) {
paulo@0 114 hline(sc, 2, 2 + wid, wid * 2 + 3, fgColor);
paulo@0 115 hline(sc, 2, 14 - wid, wid * 2 + 3, fgColor);
paulo@0 116 }
paulo@0 117 textout_ex(sc, aver16, "Play", 18, 2, fgColor, -1);
paulo@0 118 } else {
paulo@0 119
paulo@0 120 // square: stop
paulo@0 121 rectfill(sc, 2, 2, 14, 14, fgColor);
paulo@0 122 }
paulo@0 123 blit(sc, screen, 0, 0, 0, 0, 48, 16);
paulo@0 124 }
paulo@0 125
paulo@0 126 void ljEndDraw(LJView *v) {
paulo@0 127
paulo@0 128 }
paulo@0 129
paulo@0 130 static void startRecording(LJView *v) {
paulo@0 131 withPics = -1;
paulo@0 132
paulo@0 133 // close existing playback
paulo@0 134 if (v->control->replaySrc) {
paulo@0 135 replayClose(v->control->replaySrc);
paulo@0 136 v->control->replaySrc = NULL;
paulo@0 137 }
paulo@0 138
paulo@0 139 // toggle recording
paulo@0 140 if (v->control->replayDst) {
paulo@0 141 replayClose(v->control->replayDst);
paulo@0 142 v->control->replayDst = NULL;
paulo@0 143 } else {
paulo@0 144 char path[PATH_MAX];
paulo@0 145
paulo@0 146 ljpathFind_w(path, "demo.ljm");
paulo@0 147 v->control->replayDst = newReplay(path, v->field);
paulo@0 148 #if USE_PICS_FOLDER
paulo@0 149 withPics = 0;
paulo@0 150 #endif
paulo@0 151 }
paulo@0 152 }
paulo@0 153
paulo@0 154 static void startPlaying(LJView *v) {
paulo@0 155 withPics = -1;
paulo@0 156
paulo@0 157 // close existing recording
paulo@0 158 if (v->control->replayDst) {
paulo@0 159 replayClose(v->control->replayDst);
paulo@0 160 v->control->replayDst = NULL;
paulo@0 161 }
paulo@0 162
paulo@0 163 // toggle playback
paulo@0 164 if (v->control->replaySrc) {
paulo@0 165 replayClose(v->control->replaySrc);
paulo@0 166 v->control->replaySrc = NULL;
paulo@0 167 } else {
paulo@0 168 char path[PATH_MAX];
paulo@0 169
paulo@0 170 if (ljpathFind_r(path, "demo.ljm")) {
paulo@0 171 v->control->replaySrc = openReplay(path, v->field);
paulo@0 172 }
paulo@0 173 v->nLockTimes = 0;
paulo@0 174 #if USE_PICS_FOLDER
paulo@0 175 withPics = 0;
paulo@0 176 #endif
paulo@0 177 }
paulo@0 178 v->backDirty = ~0;
paulo@0 179 v->field->reloaded = 1;
paulo@0 180 }
paulo@0 181
paulo@0 182 int ljHandleConsoleButtons(LJView *v) {
paulo@0 183 int canceled = 0;
paulo@0 184
paulo@0 185 while (keypressed()) {
paulo@0 186 int scancode;
paulo@0 187 int codepoint = ureadkey(&scancode);
paulo@0 188
paulo@0 189 if (scancode == KEY_ESC) {
paulo@0 190 wantPause = 1;
paulo@0 191 } else if (scancode == KEY_PRTSCR) {
paulo@0 192 saveScreen(-1);
paulo@0 193 save_bitmap("ljbackbuf.bmp", v->plat->skin->fullback, NULL);
paulo@0 194 } else if (codepoint == '[') {
paulo@0 195 v->plat->wantRecord = 1;
paulo@0 196 } else if (codepoint == ']') {
paulo@0 197 v->plat->wantRecord = 0;
paulo@0 198 startPlaying(v);
paulo@0 199 }
paulo@0 200 }
paulo@0 201 if (v->plat->wantRecord) {
paulo@0 202 v->plat->wantRecord = 0;
paulo@0 203 startRecording(v);
paulo@0 204 }
paulo@0 205 if (wantPause) {
paulo@0 206 canceled = pauseGame(v->plat);
paulo@0 207 wantPause = 0;
paulo@0 208 }
paulo@0 209
paulo@0 210 if (wantsClose) {
paulo@0 211 canceled = 1;
paulo@0 212 }
paulo@0 213
paulo@0 214 return canceled;
paulo@0 215 }
paulo@0 216
paulo@0 217
paulo@0 218 static void drawBlock(const LJPCView *const v, int x, int y, int blk) {
paulo@0 219
paulo@0 220 if (x >= 0 && x < LJ_PF_WID && y >= 0 && y < LJ_PF_VIS_HT) {
paulo@0 221 const int w = v->skin->blkW;
paulo@0 222 const int h = v->skin->blkH;
paulo@0 223 const int dstX = w * x;
paulo@0 224 const int dstY = h * (LJ_PF_VIS_HT - 1 - y);
paulo@0 225
paulo@0 226 if (v->skin->transparentPF && (blk == 0 || blk == 0x100)) {
paulo@0 227
paulo@0 228 // Copy background
paulo@0 229 const unsigned int srcX = dstX + v->baseX;
paulo@0 230 const unsigned int srcY = dstY + v->skin->baseY
paulo@0 231 - LJ_PF_VIS_HT * h - v->skin->pfElev;
paulo@0 232 blit(v->skin->bg, v->back, srcX, srcY, dstX, dstY, w, h);
paulo@0 233 } else if (blk && v->skin->connBlocks) {
paulo@0 234
paulo@0 235 // Copy connected block
paulo@0 236 const unsigned int srcX = ((blk >> 0) & 15) * w;
paulo@0 237 const unsigned int srcY = ((blk >> 4) & 15) * h;
paulo@0 238 blit(v->skin->connBlocks, v->back, srcX, srcY, dstX, dstY, w, h);
paulo@0 239 } else {
paulo@0 240
paulo@0 241 // Copy lone block
paulo@0 242 const unsigned int srcX = ((blk >> 4) & 7) * w;
paulo@0 243 const unsigned int srcY = ((blk >> 7) & 1) * h;
paulo@0 244 blit(v->skin->blocks, v->back, srcX, srcY, dstX, dstY, w, h);
paulo@0 245 }
paulo@0 246
paulo@0 247 // 0x100: hotline
paulo@0 248 if (blk & 0x100) {
paulo@0 249 hline(v->back, dstX, dstY + h / 2 - 1, dstX + w - 1, pfFgColor);
paulo@0 250 hline(v->back, dstX, dstY + h / 2 , dstX + w - 1, pfFgColor);
paulo@0 251 hline(v->back, dstX, dstY + h / 2 + 1, dstX + w - 1, pfBgColor);
paulo@0 252 }
paulo@0 253 }
paulo@0 254 }
paulo@0 255
paulo@0 256 /**
paulo@0 257 * Draws multiple rows of the playfield
paulo@0 258 * @param p the playfield
paulo@0 259 * @param rows the rows to be updated (0x00001 on bottom, 0x80000 on top)
paulo@0 260 */
paulo@0 261 void updField(const LJView *const v, LJBits rows) {
paulo@0 262 const LJField *const p = v->field;
paulo@0 263
paulo@0 264 acquire_bitmap(v->plat->back);
paulo@0 265 for (int y = 0;
paulo@0 266 y < LJ_PF_VIS_HT && rows != 0;
paulo@0 267 ++y, rows >>= 1) {
paulo@0 268 int blankTile = 0;
paulo@0 269
paulo@0 270 // hotline: draw 0x100 as the background
paulo@0 271 if (hotlineRows[y] && v->field->scoreStyle == LJSCORE_HOTLINE) {
paulo@0 272 blankTile = 0x100;
paulo@0 273 }
paulo@0 274 // during line clear delay, draw bars to show which lines were cleared
paulo@0 275 if (p->state == LJS_LINES_FALLING && p->stateTime > 0
paulo@0 276 && ((1 << y) & p->tempRows)) {
paulo@0 277 blankTile = 0x100;
paulo@0 278 }
paulo@0 279 if (rows & 1) {
paulo@0 280 for (int x = p->leftWall; x < p->rightWall; x++) {
paulo@0 281 int b = v->hidePF ? 0 : p->b[y][x];
paulo@0 282 drawBlock(v->plat, x, y, b ? b : blankTile);
paulo@0 283 }
paulo@0 284 }
paulo@0 285 }
paulo@0 286 release_bitmap(v->plat->back);
paulo@0 287 }
paulo@0 288
paulo@0 289
paulo@0 290 #define SHADOW_BLOCK 0x00
paulo@0 291
paulo@0 292 /**
paulo@0 293 * Draws a tetromino whose lower left corner of the bounding box is at (x, y)
paulo@0 294 * @param b the bitmap to draw to
paulo@0 295 * @param piece the piece to be drawn
paulo@0 296 * @param x distance from to left side of 4x4 box
paulo@0 297 * @param y distance from top of bitmap to bottom of 4x4 box
paulo@0 298 * @param the rotation state (0: U; 1: R; 2: D; 3: L; 4: Initial position)
paulo@0 299 * @param w width of each block
paulo@0 300 * @param h height of each block
paulo@0 301 * @param color Drawing style
paulo@0 302 * color == 0: draw shadow
paulo@0 303 * color == 0x10 through 0x70: draw in that color
paulo@0 304 * color == 0x80: draw as garbage
paulo@0 305 * color == -255 through -1: draw with 255 through 1 percent lighting
paulo@0 306 */
paulo@0 307 LJBits drawPiece(LJView *const v, BITMAP *const b,
paulo@0 308 int piece, int x, int y, int theta,
paulo@0 309 int color, int w, int h) {
paulo@0 310 // Don't try to draw the -1 that's the sentinel for no hold piece
paulo@0 311 if (piece < 0)
paulo@0 312 return 0;
paulo@0 313
paulo@0 314 LJBits rows = 0;
paulo@0 315 LJBlkSpec blocks[4];
paulo@0 316 const int srcW = v->plat->skin->blkW;
paulo@0 317 const int srcH = v->plat->skin->blkH;
paulo@0 318 BITMAP *singleBlocks = v->plat->skin->blocks;
paulo@0 319 int singleSeries = (color == 0
paulo@0 320 && singleBlocks->h >= 6 * srcH)
paulo@0 321 ? 4 : 2;
paulo@0 322
paulo@0 323 // color: 0 for shadow, >0 for piece
paulo@0 324 BITMAP *connBlocks = (color != SHADOW_BLOCK)
paulo@0 325 ? v->plat->skin->connBlocks : NULL;
paulo@0 326
paulo@0 327 BITMAP *transTemp = color < 0
paulo@0 328 || (color == SHADOW_BLOCK && v->hideShadow < LJSHADOW_COLORED)
paulo@0 329 ? create_bitmap(w, h) : 0;
paulo@0 330
paulo@0 331 if (transTemp) {
paulo@0 332 set_trans_blender(0, 0, 0, v->hideShadow ? 128 : 64);
paulo@0 333 }
paulo@0 334
paulo@0 335 expandPieceToBlocks(blocks, v->field, piece, 0, 0, theta);
paulo@0 336 acquire_bitmap(b);
paulo@0 337 for (int blk = 0; blk < 4; ++blk) {
paulo@0 338 int blkValue = blocks[blk].conn;
paulo@0 339
paulo@0 340 // If blkValue == 0 then the block is not part of the piece,
paulo@0 341 // such as if it's a domino or tromino or (once pentominoes
paulo@0 342 // are added) a tetromino.
paulo@0 343 if (blkValue) {
paulo@0 344 int blkX = blocks[blk].x;
paulo@0 345 int blkY = blocks[blk].y;
paulo@0 346 const int dstX = x + w * blkX;
paulo@0 347 const int dstY = y + h * (-1 - blkY);
paulo@0 348
paulo@0 349 if (color > 0) {
paulo@0 350 blkValue = color | (blkValue & CONNECT_MASK);
paulo@0 351 } else if (color == 0 && v->hideShadow == LJSHADOW_COLORLESS) {
paulo@0 352 blkValue = 0;
paulo@0 353 }
paulo@0 354
paulo@0 355 if (connBlocks) {
paulo@0 356 const unsigned int srcX = ((blkValue >> 0) & 15) * srcW;
paulo@0 357 const unsigned int srcY = ((blkValue >> 4) & 15) * srcH;
paulo@0 358
paulo@0 359 if (transTemp) {
paulo@0 360 stretch_blit(connBlocks, transTemp,
paulo@0 361 srcX, srcY, srcW, srcH,
paulo@0 362 0, 0, w, h);
paulo@0 363 if (color < 0) {
paulo@0 364 draw_lit_sprite(b, transTemp, dstX, dstY, color + 256);
paulo@0 365 } else {
paulo@0 366 draw_trans_sprite(b, transTemp, dstX, dstY);
paulo@0 367 }
paulo@0 368 } else if (srcW != w || srcH != h) {
paulo@0 369 stretch_blit(connBlocks, b,
paulo@0 370 srcX, srcY, srcW, srcH,
paulo@0 371 dstX, dstY, w, h);
paulo@0 372 if (dstY > 600) {
paulo@0 373 allegro_message("dstY = %d\n", dstY);
paulo@0 374 }
paulo@0 375 } else {
paulo@0 376 blit(connBlocks, b,
paulo@0 377 srcX, srcY,
paulo@0 378 dstX, dstY, w, h);
paulo@0 379 }
paulo@0 380 } else {
paulo@0 381 const unsigned int srcX = ((blkValue >> 4) & 7) * srcW;
paulo@0 382 const unsigned int srcY = (((blkValue >> 7) & 1) + singleSeries) * srcH;
paulo@0 383
paulo@0 384 if (transTemp) {
paulo@0 385 stretch_blit(singleBlocks, transTemp,
paulo@0 386 srcX, srcY, srcW, srcH,
paulo@0 387 0, 0, w, h);
paulo@0 388 if (color < 0) {
paulo@0 389 draw_lit_sprite(b, transTemp, dstX, dstY, color + 256);
paulo@0 390 } else {
paulo@0 391 draw_trans_sprite(b, transTemp, dstX, dstY);
paulo@0 392 }
paulo@0 393 } else {
paulo@0 394 stretch_blit(singleBlocks, b,
paulo@0 395 srcX, srcY, srcW, srcH,
paulo@0 396 dstX, dstY, w, h);
paulo@0 397 }
paulo@0 398 }
paulo@0 399 rows |= 1 << blkY;
paulo@0 400 }
paulo@0 401 }
paulo@0 402 release_bitmap(b);
paulo@0 403 if (transTemp) {
paulo@0 404 solid_mode();
paulo@0 405 destroy_bitmap(transTemp);
paulo@0 406 }
paulo@0 407
paulo@0 408 return rows;
paulo@0 409 }
paulo@0 410
paulo@0 411 void drawPieceInPF(LJView *v, int dstX, LJFixed dstY, int theta, int color) {
paulo@0 412 LJBits bits = 0;
paulo@0 413 BITMAP *b = v->plat->back;
paulo@0 414 const LJField *const p = v->field;
paulo@0 415 int y = ljfixfloor(dstY);
paulo@0 416 const int w = v->plat->skin->blkW;
paulo@0 417 const int h = v->plat->skin->blkH;
paulo@0 418 int drawnY = fixmul(h, dstY);
paulo@0 419
paulo@0 420 bits = drawPiece(v, b, p->curPiece[0],
paulo@0 421 w * dstX, h * LJ_PF_VIS_HT - drawnY,
paulo@0 422 theta,
paulo@0 423 color, w, h);
paulo@0 424 bits = (y >= 0) ? bits << y : bits >> -y;
paulo@0 425 bits &= (1 << LJ_PF_VIS_HT) - 1;
paulo@0 426 if (dstY & 0xFFFF) {
paulo@0 427 bits |= bits << 1;
paulo@0 428 }
paulo@0 429
paulo@0 430 v->backDirty |= bits;
paulo@0 431 v->frontDirty |= bits;
paulo@0 432 }
paulo@0 433
paulo@0 434
paulo@0 435 void drawFallingPiece(LJView *v) {
paulo@0 436 const LJField *const p = v->field;
paulo@0 437 int piece = p->curPiece[0];
paulo@0 438 int y = v->smoothGravity
paulo@0 439 ? p->y
paulo@0 440 : ljitofix(ljfixfloor(p->y));
paulo@0 441 const int color = (p->state == LJS_LANDED)
paulo@0 442 ? -128 - ((p->stateTime + 1) * 128 / (p->speed.lockDelay + 1))
paulo@0 443 : pieceColors[piece];
paulo@0 444
paulo@0 445 // Draw trails
paulo@0 446 if (v->showTrails) {
paulo@0 447
paulo@0 448 // trail going up
paulo@0 449 while (v->trailY - y < ljitofix(-1)) {
paulo@0 450 v->trailY += ljitofix(1);
paulo@0 451 drawPieceInPF(v, p->x, v->trailY, p->theta, color);
paulo@0 452 }
paulo@0 453
paulo@0 454 // trail going down
paulo@0 455 while (v->trailY - y > ljitofix(1)) {
paulo@0 456 v->trailY -= ljitofix(1);
paulo@0 457 drawPieceInPF(v, p->x, v->trailY, p->theta, color);
paulo@0 458 }
paulo@0 459 }
paulo@0 460 drawPieceInPF(v, p->x, y, p->theta, color);
paulo@0 461 v->trailY = y;
paulo@0 462 }
paulo@0 463
paulo@0 464 void drawShadow(LJView *v) {
paulo@0 465 const LJField *const p = v->field;
paulo@0 466 int y = ljitofix(p->hardDropY);
paulo@0 467 const int color = SHADOW_BLOCK;
paulo@0 468 drawPieceInPF(v, p->x, y, p->theta, color);
paulo@0 469 }
paulo@0 470
paulo@0 471 void drawNextPieces(LJView *v) {
paulo@0 472 int baseX = v->plat->baseX;
paulo@0 473 int baseY = v->plat->skin->baseY - v->plat->skin->pfElev;
paulo@0 474 int blkW = v->plat->skin->blkW;
paulo@0 475 int blkH = v->plat->skin->blkH;
paulo@0 476 int holdPieceColor = v->field->alreadyHeld
paulo@0 477 ? 0x80
paulo@0 478 : pieceColors[v->field->holdPiece];
paulo@0 479 int ceil = v->field->ceiling;
paulo@0 480
paulo@0 481 BITMAP *sc = v->plat->skin->fullback;
paulo@0 482
paulo@0 483 if (v->frontDirty & LJ_DIRTY_NEXT) {
paulo@0 484 int holdW = blkW * 2 / 3;
paulo@0 485 int holdH = blkH * 2 / 3;
paulo@0 486 int holdX = baseX + blkW;
paulo@0 487 int holdY = baseY - (ceil - 1) * blkH - 4 * holdH;
paulo@0 488
paulo@0 489 // Move the hold piece within the screen
paulo@0 490 if (holdY < 0) {
paulo@0 491 holdY = 0;
paulo@0 492 }
paulo@0 493
paulo@0 494 // Draw hold piece
paulo@0 495 blit(v->plat->skin->bg, sc,
paulo@0 496 holdX, holdY,
paulo@0 497 holdX, holdY,
paulo@0 498 holdW * 4, holdH * 2);
paulo@0 499 drawPiece(v, sc,
paulo@0 500 v->field->holdPiece, holdX, holdY + 4 * holdH, 4,
paulo@0 501 holdPieceColor, holdW, holdH);
paulo@0 502 blit(sc, screen,
paulo@0 503 holdX, holdY,
paulo@0 504 holdX, holdY,
paulo@0 505 holdW * 4, holdH * 2);
paulo@0 506 }
paulo@0 507 // Draw next pieces
paulo@0 508
paulo@0 509 switch (v->plat->skin->nextPos) {
paulo@0 510 case LJNEXT_RIGHT:
paulo@0 511 case LJNEXT_RIGHT_TAPER:
paulo@0 512 if (v->frontDirty & LJ_DIRTY_NEXT) {
paulo@0 513 int y = baseY - ceil * blkH;
paulo@0 514 int x = baseX + LJ_PF_WID * blkW;
paulo@0 515 int w = blkW;
paulo@0 516 int h = blkH;
paulo@0 517 for (int i = 1; i <= v->nextPieces; ++i) {
paulo@0 518 int piece = v->field->curPiece[i];
paulo@0 519
paulo@0 520 blit(v->plat->skin->bg, sc, x, y, x, y, w * 4, h * 2);
paulo@0 521 if (!v->hideNext) {
paulo@0 522 drawPiece(v, sc,
paulo@0 523 piece, x, y + 4 * h, 4,
paulo@0 524 pieceColors[piece], w, h);
paulo@0 525 }
paulo@0 526 blit(sc, screen, x, y, x, y, w * 4, h * 2);
paulo@0 527 y += 8 + h * 2;
paulo@0 528 if (v->plat->skin->nextPos == LJNEXT_RIGHT_TAPER) {
paulo@0 529 --h;
paulo@0 530 --w;
paulo@0 531 }
paulo@0 532 }
paulo@0 533 }
paulo@0 534 break;
paulo@0 535
paulo@0 536 case LJNEXT_TOP:
paulo@0 537 if (v->frontDirty & LJ_DIRTY_NEXT) {
paulo@0 538 int y = baseY - (ceil + 2) * blkH - 8;
paulo@0 539 int x = baseX + 4 * blkW;
paulo@0 540 int blitX = x, blitY = y;
paulo@0 541
paulo@0 542 blit(v->plat->skin->bg, sc, x, y, x, y, blkW * 8, blkH * 2);
paulo@0 543 if (!v->hideNext) {
paulo@0 544 if (v->nextPieces >= 1) {
paulo@0 545 int piece = v->field->curPiece[1];
paulo@0 546 drawPiece(v, sc,
paulo@0 547 piece, x, y + 4 * blkH, 4,
paulo@0 548 pieceColors[piece], blkW, blkH);
paulo@0 549 }
paulo@0 550 if (v->nextPieces >= 2) {
paulo@0 551 int piece = v->field->curPiece[2];
paulo@0 552 x += 4 * blkW;
paulo@0 553 drawPiece(v, sc,
paulo@0 554 piece, x, y + 3 * blkH, 4,
paulo@0 555 pieceColors[piece], blkW/ 2, blkH / 2);
paulo@0 556 }
paulo@0 557 if (v->nextPieces >= 3) {
paulo@0 558 int piece = v->field->curPiece[3];
paulo@0 559 x += 2 * blkW;
paulo@0 560 drawPiece(v, sc,
paulo@0 561 piece, x, y + 3 * blkH, 4,
paulo@0 562 pieceColors[piece], blkW / 2, blkH / 2);
paulo@0 563 }
paulo@0 564 }
paulo@0 565 blit(sc, screen, blitX, blitY, blitX, blitY, blkW * 8, blkH * 2);
paulo@0 566 }
paulo@0 567 break;
paulo@0 568 }
paulo@0 569
paulo@0 570 if (v->plat->nextAbove && !v->hideNext) {
paulo@0 571 int row = (v->field->hardDropY + 4);
paulo@0 572 int x = (1 + v->field->x) * blkW;
paulo@0 573 for (int i = 1;
paulo@0 574 i <= v->plat->nextAbove
paulo@0 575 && row <= v->field->ceiling - 2;
paulo@0 576 ++i) {
paulo@0 577 int y = (LJ_PF_VIS_HT - row) * blkH;
paulo@0 578 int piece = v->field->curPiece[i];
paulo@0 579
paulo@0 580 drawPiece(v, v->plat->back,
paulo@0 581 piece, x, y, 4,
paulo@0 582 pieceColors[piece], blkW / 2, blkH / 2);
paulo@0 583 v->backDirty |= 3 << row;
paulo@0 584 row += 2;
paulo@0 585 }
paulo@0 586 }
paulo@0 587 v->frontDirty &= ~LJ_DIRTY_NEXT;
paulo@0 588 }
paulo@0 589
paulo@0 590 void drawScore(LJView *v) {
paulo@0 591 int gameTime = v->field->gameTime;
paulo@0 592 int seconds = gameTime / 60;
paulo@0 593 int minutes = seconds / 60;
paulo@0 594 int baseX = v->plat->baseX;
paulo@0 595 int tpm = -1;
paulo@0 596 int spawnLeft = v->plat->skin->blkW * LJ_SPAWN_X + baseX;
paulo@0 597 int pfRight = v->plat->skin->blkW * LJ_PF_WID + baseX;
paulo@0 598 BITMAP *sc = v->plat->skin->fullback;
paulo@0 599
paulo@0 600 if (withPics >= 0) {
paulo@0 601 if (v->field->nPieces != withPics) {
paulo@0 602 saveScreen(v->field->nPieces);
paulo@0 603 }
paulo@0 604 withPics = v->field->nPieces;
paulo@0 605 }
paulo@0 606
paulo@0 607 if (v->nLockTimes >= 2 ) {
paulo@0 608 int time = v->lockTime[0] - v->lockTime[v->nLockTimes - 1];
paulo@0 609 if (time > 0) {
paulo@0 610 tpm = 3600 * (v->nLockTimes - 1) / time;
paulo@0 611 }
paulo@0 612 }
paulo@0 613
paulo@0 614 if (v->frontDirty & LJ_DIRTY_SCORE) {
paulo@0 615 switch (v->plat->skin->nextPos) {
paulo@0 616 case LJNEXT_TOP:
paulo@0 617 blit(v->plat->skin->bg, sc,
paulo@0 618 pfRight, 72,
paulo@0 619 pfRight, 72,
paulo@0 620 112, 136);
paulo@0 621
paulo@0 622 textout_ex(sc, aver32, "Lines:", pfRight, 72, fgColor, -1);
paulo@0 623 textprintf_right_ex(sc, aver32, pfRight + 104, 102, fgColor, -1,
paulo@0 624 "%d", v->field->lines);
paulo@0 625 textout_ex(sc, aver32, "Score:", pfRight, 142, fgColor, -1);
paulo@0 626 textprintf_right_ex(sc, aver32, pfRight + 104, 172, fgColor, -1,
paulo@0 627 "%d", v->field->score);
paulo@0 628 textout_ex(sc, aver32, "Level:", pfRight, 212, fgColor, -1);
paulo@0 629 textprintf_right_ex(sc, aver32, pfRight + 104, 242, fgColor, -1,
paulo@0 630 "%d", v->field->speedState.level);
paulo@0 631 blit(sc, screen,
paulo@0 632 pfRight, 72,
paulo@0 633 pfRight, 72,
paulo@0 634 112, 136);
paulo@0 635 break;
paulo@0 636
paulo@0 637 default:
paulo@0 638 blit(v->plat->skin->bg, sc, spawnLeft, 12, spawnLeft, 12, 288, 30);
paulo@0 639 blit(v->plat->skin->bg, sc,
paulo@0 640 spawnLeft, 42, spawnLeft, 42,
paulo@0 641 pfRight - spawnLeft, 30);
paulo@0 642 textprintf_right_ex(sc, aver32, spawnLeft + 288, 12, fgColor, -1,
paulo@0 643 "Lv. %d", v->field->speedState.level);
paulo@0 644 textprintf_ex(sc, aver32, spawnLeft, 12, fgColor, -1,
paulo@0 645 "Lines: %d", v->field->lines);
paulo@0 646 textprintf_ex(sc, aver32, spawnLeft, 42, fgColor, -1,
paulo@0 647 "Score: %d", v->field->score);
paulo@0 648 blit(sc, screen, spawnLeft, 12, spawnLeft, 12, 288, 60);
paulo@0 649 break;
paulo@0 650 }
paulo@0 651 }
paulo@0 652
paulo@0 653 /* If speed is defined, and there is room to draw it, draw it. */
paulo@0 654 if (tpm > 0 && v->nextPieces <= 3) {
paulo@0 655 blit(v->plat->skin->bg, sc,
paulo@0 656 pfRight, 282,
paulo@0 657 pfRight, 282,
paulo@0 658 104, 60);
paulo@0 659 textout_ex(sc, aver32, "Speed:", pfRight, 282, fgColor, -1);
paulo@0 660 textprintf_right_ex(sc, aver32, pfRight + 104, 312, fgColor, -1,
paulo@0 661 "%d", tpm);
paulo@0 662 blit(sc, screen,
paulo@0 663 pfRight, 282,
paulo@0 664 pfRight, 282,
paulo@0 665 104, 60);
paulo@0 666 }
paulo@0 667
paulo@0 668 if (v->frontDirty & LJ_DIRTY_NEXT) {
paulo@0 669
paulo@0 670 // Erase gimmick
paulo@0 671 blit(v->plat->skin->bg, sc,
paulo@0 672 baseX, v->plat->skin->baseY + 8,
paulo@0 673 baseX, v->plat->skin->baseY + 8,
paulo@0 674 v->plat->skin->blkW * LJ_PF_WID, 30);
paulo@0 675 // Draw gimmick
paulo@0 676 if (v->field->gimmick >= 0 && v->field->gimmick < LJGM_N_GIMMICKS) {
paulo@0 677 const char *gimmickName = ljGetFourCCName(gimmickNames[v->field->gimmick]);
paulo@0 678 textout_centre_ex(sc, aver32,
paulo@0 679 gimmickName ? gimmickName : "Bad gimmick ID",
paulo@0 680 baseX + (LJ_PF_WID / 2) * v->plat->skin->blkW,
paulo@0 681 v->plat->skin->baseY + 8,
paulo@0 682 fgColor, -1);
paulo@0 683 blit(sc, screen,
paulo@0 684 baseX, v->plat->skin->baseY + 8,
paulo@0 685 baseX, v->plat->skin->baseY + 8,
paulo@0 686 v->plat->skin->blkW * LJ_PF_WID, 30);
paulo@0 687 }
paulo@0 688 }
paulo@0 689 drawNextPieces(v);
paulo@0 690
paulo@0 691 blit(v->plat->skin->bg, sc, pfRight, 42, pfRight, 42, 96, 30);
paulo@0 692 #if 0
paulo@0 693 // Use this for DEBUG inspection into a variable
paulo@0 694 textprintf_right_ex(sc, aver16, pfRight + 96, 8, fgColor, -1,
paulo@0 695 "%d", v->field->bpmCounter);
paulo@0 696 #endif
paulo@0 697 textprintf_right_ex(sc, aver32, pfRight + 96, 42, fgColor, -1,
paulo@0 698 "%d:%02d", minutes, seconds - 60 * minutes);
paulo@0 699 blit(sc, screen, pfRight, 42, pfRight, 42, 96, 30);
paulo@0 700
paulo@0 701 }
paulo@0 702
paulo@0 703 void blitField(LJView *v) {
paulo@0 704 int blkH = v->plat->skin->blkH;
paulo@0 705 int rowY = v->plat->skin->baseY
paulo@0 706 - v->plat->skin->pfElev
paulo@0 707 - blkH * v->field->ceiling;
paulo@0 708 int x = v->plat->skin->blkW * v->field->leftWall;
paulo@0 709 int w = v->plat->skin->blkW * (v->field->rightWall - v->field->leftWall);
paulo@0 710
paulo@0 711 // Copy each dirty row
paulo@0 712 for (int y = v->field->ceiling - 1; y >= 0; --y) {
paulo@0 713 if (v->frontDirty & (1 << y)) {
paulo@0 714 int top = (LJ_PF_VIS_HT - y - 1) * blkH;
paulo@0 715 int ht = 0;
paulo@0 716
paulo@0 717 // Find the height of the contiguous rows to blit
paulo@0 718 do {
paulo@0 719 ht += blkH;
paulo@0 720 --y;
paulo@0 721 } while ((y >= 0)
paulo@0 722 && (v->frontDirty & (1 << y)));
paulo@0 723 blit(v->plat->back, screen,
paulo@0 724 x, top,
paulo@0 725 x + v->plat->baseX, rowY,
paulo@0 726 w, ht);
paulo@0 727 rowY += ht;
paulo@0 728 }
paulo@0 729 rowY += blkH;
paulo@0 730 }
paulo@0 731
paulo@0 732 v->frontDirty &= (~0) << LJ_PF_HT;
paulo@0 733 }
paulo@0 734
paulo@0 735 void saveScreen(int n) {
paulo@0 736 BITMAP *b = create_bitmap(SCREEN_W, SCREEN_H);
paulo@0 737 if (b) {
paulo@0 738 PALETTE pal;
paulo@0 739
paulo@0 740 get_palette(pal);
paulo@0 741 blit(screen, b, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
paulo@0 742 if (n < 0) {
paulo@0 743 save_bitmap("ljsnap.bmp", b, pal);
paulo@0 744 } else {
paulo@0 745 char filename[64];
paulo@0 746 sprintf(filename, "pics/lj%05d.bmp", n);
paulo@0 747 save_bitmap(filename, b, pal);
paulo@0 748 }
paulo@0 749 destroy_bitmap(b);
paulo@0 750 }
paulo@0 751 }
paulo@0 752
paulo@0 753 #define PRESETS_PER_COL 6
paulo@0 754 #define N_NONPRESETS 2
paulo@0 755 #define PRESETS_TOP 140
paulo@0 756 #define PRESET_COL_WIDTH 250
paulo@0 757 #define PRESET_ROW_HT 40
paulo@0 758
paulo@0 759 static const char *const nonPresetNames[N_NONPRESETS] = {
paulo@0 760 "Full Custom", "Back"
paulo@0 761 };
paulo@0 762
paulo@0 763 static void getPresetDrawRow(unsigned int preset, int hilite) {
paulo@0 764 unsigned int ht = text_height(aver32);
paulo@0 765 const char *txt = preset < nLoadedPresets
paulo@0 766 ? loadedPresets[preset].name
paulo@0 767 : nonPresetNames[preset - nLoadedPresets];
paulo@0 768 if (!txt) {
paulo@0 769 txt = "Bad";
paulo@0 770 }
paulo@0 771 unsigned int wid = text_length(aver32, txt);
paulo@0 772
paulo@0 773 int buttonCol = preset / PRESETS_PER_COL;
paulo@0 774 int buttonX = 20 + buttonCol * PRESET_COL_WIDTH;
paulo@0 775 int buttonY = PRESETS_TOP
paulo@0 776 + PRESET_ROW_HT * (preset - buttonCol * PRESETS_PER_COL);
paulo@0 777 unsigned int buttonWidth = wid + 16;
paulo@0 778
paulo@0 779 rectfill(screen,
paulo@0 780 buttonX, buttonY,
paulo@0 781 buttonX + buttonWidth - 1, buttonY + PRESET_ROW_HT - 1,
paulo@0 782 hilite ? hiliteColor : bgColor);
paulo@0 783 if (hilite) {
paulo@0 784 rect(screen,
paulo@0 785 buttonX, buttonY,
paulo@0 786 buttonX + buttonWidth - 1, buttonY + PRESET_ROW_HT - 1,
paulo@0 787 fgColor);
paulo@0 788 }
paulo@0 789 textout_ex(screen, aver32, txt,
paulo@0 790 8 + buttonX,
paulo@0 791 20 + buttonY - ht / 2,
paulo@0 792 fgColor, -1);
paulo@0 793 }
paulo@0 794
paulo@0 795 int getPreset(int lastPreset) {
paulo@0 796 LJBits lastKeys = ~0;
paulo@0 797 redrawWholeScreen = 1;
paulo@0 798
paulo@0 799 clear_keybuf();
paulo@0 800 if (lastPreset < 0) {
paulo@0 801 lastPreset += nLoadedPresets + N_NONPRESETS;
paulo@0 802 }
paulo@0 803
paulo@0 804 for(int done = 0; done == 0; ) {
paulo@0 805 if (redrawWholeScreen) {
paulo@0 806 redrawWholeScreen = 0;
paulo@0 807 clear_to_color(screen, bgColor);
paulo@0 808 textout_ex(screen, aver32, "LOCKJAW > Play", 16, 32, fgColor, -1);
paulo@0 809 textout_ex(screen, aver32, "Select a scenario:", 16, 90, fgColor, -1);
paulo@0 810
paulo@0 811 for (int preset = 0;
paulo@0 812 preset < nLoadedPresets + N_NONPRESETS;
paulo@0 813 ++preset) {
paulo@0 814 getPresetDrawRow(preset, preset == lastPreset);
paulo@0 815 }
paulo@0 816 textout_ex(screen, aver16, "Arrows: move; Rotate Right: start",
paulo@0 817 16, PRESETS_TOP + 40 * (PRESETS_PER_COL + 1), fgColor, -1);
paulo@0 818 textout_ex(screen, aver16, "Coming soon: an editor for these!",
paulo@0 819 16, PRESETS_TOP + 40 * (PRESETS_PER_COL + 1) + 20, fgColor, -1);
paulo@0 820 }
paulo@0 821 while (keypressed()) {
paulo@0 822 int scancode;
paulo@0 823 ureadkey(&scancode);
paulo@0 824 if (scancode == KEY_PRTSCR) {
paulo@0 825 saveScreen(-1);
paulo@0 826 }
paulo@0 827 }
paulo@0 828
paulo@0 829 int preset = lastPreset;
paulo@0 830 LJBits keys = menuReadPad();
paulo@0 831 LJBits newKeys = keys & ~lastKeys;
paulo@0 832
paulo@0 833 if ((newKeys & VKEY_ROTL) || wantsClose) {
paulo@0 834 preset = nLoadedPresets + N_NONPRESETS - 1;
paulo@0 835 ezPlaySample("rotate_wav", 128);
paulo@0 836 }
paulo@0 837 if ((newKeys & VKEY_ROTR) || wantsClose) {
paulo@0 838 done = 1;
paulo@0 839 ezPlaySample("line_wav", 128);
paulo@0 840 }
paulo@0 841
paulo@0 842 if (newKeys & VKEY_UP) {
paulo@0 843 if (preset <= 0) {
paulo@0 844 preset = nLoadedPresets + N_NONPRESETS - 1;
paulo@0 845 } else {
paulo@0 846 --preset;
paulo@0 847 }
paulo@0 848 ezPlaySample("shift_wav", 128);
paulo@0 849 }
paulo@0 850 if (newKeys & VKEY_DOWN) {
paulo@0 851 ++preset;
paulo@0 852 if (preset >= nLoadedPresets + N_NONPRESETS) {
paulo@0 853 preset = 0;
paulo@0 854 }
paulo@0 855 ezPlaySample("shift_wav", 128);
paulo@0 856 }
paulo@0 857
paulo@0 858 if (newKeys & VKEY_LEFT) {
paulo@0 859 if (preset < PRESETS_PER_COL) {
paulo@0 860 preset += (((nLoadedPresets + N_NONPRESETS)
paulo@0 861 / PRESETS_PER_COL)
paulo@0 862 )
paulo@0 863 * PRESETS_PER_COL;
paulo@0 864 if (preset >= nLoadedPresets + N_NONPRESETS) {
paulo@0 865 preset -= PRESETS_PER_COL;
paulo@0 866 }
paulo@0 867 } else {
paulo@0 868 preset -= PRESETS_PER_COL;
paulo@0 869 }
paulo@0 870 ezPlaySample("shift_wav", 128);
paulo@0 871 }
paulo@0 872 if (newKeys & VKEY_RIGHT) {
paulo@0 873 preset += PRESETS_PER_COL;
paulo@0 874 if (preset >= nLoadedPresets + N_NONPRESETS) {
paulo@0 875 preset %= PRESETS_PER_COL;
paulo@0 876 }
paulo@0 877 ezPlaySample("shift_wav", 128);
paulo@0 878 }
paulo@0 879
paulo@0 880 if (preset != lastPreset) {
paulo@0 881 vsync();
paulo@0 882 getPresetDrawRow(lastPreset, 0);
paulo@0 883 getPresetDrawRow(preset, 1);
paulo@0 884 lastPreset = preset;
paulo@0 885 } else {
paulo@0 886 rest(30);
paulo@0 887 }
paulo@0 888 lastKeys = keys;
paulo@0 889 }
paulo@0 890
paulo@0 891 // Wrap the nonpresets into the negative numbers.
paulo@0 892 if (lastPreset >= nLoadedPresets) {
paulo@0 893 lastPreset -= (nLoadedPresets + N_NONPRESETS);
paulo@0 894 }
paulo@0 895
paulo@0 896 return lastPreset;
paulo@0 897 }
paulo@0 898
paulo@0 899 /**
paulo@0 900 * Pauses the game, returning nonzero if the player wants to quit.
paulo@0 901 */
paulo@0 902 int pauseGame(LJPCView *v) {
paulo@0 903 int escCount = 0;
paulo@0 904 int quit = 0;
paulo@0 905 int escHold = curTime;
paulo@0 906 redrawWholeScreen = 1;
paulo@0 907
paulo@0 908 LJMusic_pause(v->skin->bgm, 1);
paulo@0 909 while (escCount < 2 && !quit) {
paulo@0 910 LJMusic_poll(v->skin->bgm);
paulo@0 911 if (redrawWholeScreen) {
paulo@0 912 redrawWholeScreen = 0;
paulo@0 913 clear_to_color(screen, pfBgColor);
paulo@0 914 textout_centre_ex(screen, aver32, "LOCKJAW: GAME PAUSED",
paulo@0 915 SCREEN_W / 2, 200, pfFgColor, -1);
paulo@0 916 textout_centre_ex(screen, aver32, "Press Esc to continue",
paulo@0 917 SCREEN_W / 2, 250, pfFgColor, -1);
paulo@0 918 textout_centre_ex(screen, aver32, "or hold Esc to quit",
paulo@0 919 SCREEN_W / 2, 300, pfFgColor, -1);
paulo@0 920 }
paulo@0 921
paulo@0 922 if (key[KEY_ESC]) {
paulo@0 923 if (escHold == 0) {
paulo@0 924 escHold = curTime;
paulo@0 925 }
paulo@0 926 if (curTime - escHold >= 60) {
paulo@0 927 quit = 1;
paulo@0 928 }
paulo@0 929 } else {
paulo@0 930 if (escHold) {
paulo@0 931 ++escCount;
paulo@0 932 }
paulo@0 933 escHold = 0;
paulo@0 934 }
paulo@0 935 rest(30);
paulo@0 936 if (wantsClose) {
paulo@0 937 quit = 1;
paulo@0 938 }
paulo@0 939
paulo@0 940 }
paulo@0 941 LJMusic_pause(v->skin->bgm, 0);
paulo@0 942 redrawWholeScreen = 1;
paulo@0 943 clear_keybuf();
paulo@0 944 return quit;
paulo@0 945 }
paulo@0 946
paulo@0 947
paulo@0 948 void pcInit(LJView *v, struct LJPrefs *prefs) {
paulo@0 949 v->plat->b2bcd1 = 0;
paulo@0 950 v->plat->b2bcd2 = 0;
paulo@0 951 v->plat->baseX = v->plat->skin->baseX;
paulo@0 952
paulo@0 953 // If the player has chosen to use more next pieces than the
paulo@0 954 // next piece position can handle, set the number of
paulo@0 955 // next pieces for correctness of debrief().
paulo@0 956 if (v->nextPieces > 3 && v->plat->skin->nextPos == LJNEXT_TOP) {
paulo@0 957 v->nextPieces = 3;
paulo@0 958 }
paulo@0 959 }
paulo@0 960
paulo@0 961 /**
paulo@0 962 * Redraws everything on the screen.
paulo@0 963 * Called when needs redraw.
paulo@0 964 */
paulo@0 965 void playRedrawScreen(LJView *v) {
paulo@0 966 blit(v->plat->skin->bg, screen,
paulo@0 967 0, 0,
paulo@0 968 0, 0,
paulo@0 969 SCREEN_W, SCREEN_H);
paulo@0 970 v->frontDirty = ~0;
paulo@0 971 }
paulo@0 972
paulo@0 973 #if 0
paulo@0 974 void startingAniWantsSkip(LJView *v) {
paulo@0 975 LJInput unusedIn;
paulo@0 976 addKeysToInput(&unusedIn, readPad(), v->field, v->control);
paulo@0 977 }
paulo@0 978 #endif
paulo@0 979
paulo@0 980 void playSampleForTetromino(int piece);
paulo@0 981
paulo@0 982 void restPollingMusic(int nFrames, LJMusic *bgm) {
paulo@0 983 nFrames += curTime;
paulo@0 984 while (curTime - nFrames < 0) {
paulo@0 985 if (bgm) {
paulo@0 986 LJMusic_poll(bgm);
paulo@0 987 }
paulo@0 988 }
paulo@0 989 }
paulo@0 990
paulo@0 991 extern int bgmReadyGo;
paulo@0 992 void startingAnimation(LJView *v) {
paulo@0 993 int readyGoX = v->plat->baseX + v->plat->skin->blkW * LJ_PF_WID / 2;
paulo@0 994 int readyGoY = v->plat->skin->baseY
paulo@0 995 - v->plat->skin->pfElev
paulo@0 996 - v->plat->skin->blkH
paulo@0 997 * v->field->ceiling * 3 / 5;
paulo@0 998
paulo@0 999 clear_keybuf();
paulo@0 1000 v->backDirty = 0;
paulo@0 1001
paulo@0 1002 playRedrawScreen(v);
paulo@0 1003 blitField(v);
paulo@0 1004 textout_centre_ex(screen, aver32, "Ready",
paulo@0 1005 readyGoX, readyGoY, pfFgColor, -1);
paulo@0 1006
paulo@0 1007 ezPlaySample("ready_wav", 128);
paulo@0 1008 restPollingMusic(36, bgmReadyGo ? v->plat->skin->bgm : NULL);
paulo@0 1009 v->frontDirty = ~0;
paulo@0 1010
paulo@0 1011 if (!wantsClose) {
paulo@0 1012 blitField(v);
paulo@0 1013 textout_centre_ex(screen, aver32, "GO!",
paulo@0 1014 readyGoX, readyGoY, pfFgColor, -1);
paulo@0 1015 drawScore(v);
paulo@0 1016
paulo@0 1017 ezPlaySample("go_wav", 128);
paulo@0 1018 v->frontDirty = ~0;
paulo@0 1019 restPollingMusic(12, bgmReadyGo ? v->plat->skin->bgm : NULL);
paulo@0 1020 }
paulo@0 1021 if (!wantsClose) {
paulo@0 1022 playSampleForTetromino(v->field->curPiece[1]);
paulo@0 1023 restPollingMusic(24, bgmReadyGo ? v->plat->skin->bgm : NULL);
paulo@0 1024 }
paulo@0 1025 }
paulo@0 1026
paulo@0 1027
paulo@0 1028 static void gameOverAnimation(const LJPCView *const v, const LJField *p, int won) {
paulo@0 1029 int ceiling = p->ceiling;
paulo@0 1030 int left = v->baseX + p->leftWall * v->skin->blkW;
paulo@0 1031 int right = v->baseX + p->rightWall * v->skin->blkW - 1;
paulo@0 1032
paulo@0 1033 ezPlaySample("sectionup_wav", 0);
paulo@0 1034 if (!won) {
paulo@0 1035 ezPlaySample("gameover_wav", 256);
paulo@0 1036 } else {
paulo@0 1037 ezPlaySample("win_wav", 256);
paulo@0 1038 }
paulo@0 1039
paulo@0 1040 for (int t = ceiling + v->skin->blkH - 2; t >= 0; --t) {
paulo@0 1041
paulo@0 1042 // FIXME: vsync doesn't work on Vista
paulo@0 1043 vsync();
paulo@0 1044 for (int row = ceiling - 1; row >= 0; --row) {
paulo@0 1045 int ysub = t - row;
paulo@0 1046
paulo@0 1047 if (ysub >= 0 && ysub < v->skin->blkH) {
paulo@0 1048 int y = v->skin->baseY - v->skin->pfElev
paulo@0 1049 - row * v->skin->blkH - ysub - 1;
paulo@0 1050 hline(screen, left, y, right, pfBgColor);
paulo@0 1051 }
paulo@0 1052 }
paulo@0 1053 if (wantsClose) {
paulo@0 1054 t = 0;
paulo@0 1055 }
paulo@0 1056 }
paulo@0 1057 }
paulo@0 1058
paulo@0 1059 #define MENU_COPR_NOTICE_LINES 4
paulo@0 1060 const char *const menuCoprNotice[MENU_COPR_NOTICE_LINES] = {
paulo@0 1061 "Copr. 2006-2008 Damian Yerrick",
paulo@0 1062 "Not sponsored or endorsed by The Tetris Company.",
paulo@0 1063 "LOCKJAW comes with ABSOLUTELY NO WARRANTY. This is free software, and you are",
paulo@0 1064 "welcome to redistribute it under certain conditions as described in GPL.txt."
paulo@0 1065 };
paulo@0 1066
paulo@0 1067 static BITMAP *buildTitleScreen(void) {
paulo@0 1068 BITMAP *back = create_system_bitmap(SCREEN_W, SCREEN_H);
paulo@0 1069 if (!back) {
paulo@0 1070 return NULL;
paulo@0 1071 }
paulo@0 1072
paulo@0 1073 // Gradient from (0, 0, 0) to (0, 0, 153)
paulo@0 1074 for (int y = 0; y < 192; ++y) {
paulo@0 1075 for (int x = -((y * 13) & 0x1F);
paulo@0 1076 x < SCREEN_W;
paulo@0 1077 x += 32) {
paulo@0 1078 int colValue = y + ((rand() & 0x7000) >> 12);
paulo@0 1079 int c = makecol(0, 0, 153 * colValue / 192);
paulo@0 1080 hline(back, x, y, x + 31, c);
paulo@0 1081 }
paulo@0 1082 }
paulo@0 1083
paulo@0 1084 // Gradient from (102, 51, 0) to (204, 102, 0)
paulo@0 1085 for (int y = 192; y < 384; ++y) {
paulo@0 1086 for (int x = -((y * 13) & 0x1F);
paulo@0 1087 x < SCREEN_W;
paulo@0 1088 x += 32) {
paulo@0 1089 int colValue = y + ((rand() & 0x7800) >> 11);
paulo@0 1090 int c = makecol(102 * colValue / 192, 51 * colValue / 192, 0);
paulo@0 1091 hline(back, x, y, x + 31, c);
paulo@0 1092 }
paulo@0 1093 }
paulo@0 1094
paulo@0 1095 // Gradient from (204, 102, 0) to (255, 128, 0)
paulo@0 1096 for (int y = 384; y < SCREEN_H; ++y) {
paulo@0 1097 for (int x = -((y * 13) & 0x1F);
paulo@0 1098 x < SCREEN_W;
paulo@0 1099 x += 32) {
paulo@0 1100 int colValue = y - 400 + ((rand() & 0x7C00) >> 10);
paulo@0 1101 if (colValue > 600 - 384) {
paulo@0 1102 colValue = 600 - 384;
paulo@0 1103 }
paulo@0 1104 int c = makecol(204 + 50 * colValue / (600 - 384),
paulo@0 1105 102 + 25 * colValue / (600 - 384),
paulo@0 1106 0);
paulo@0 1107 hline(back, x, y, x + 31, c);
paulo@0 1108 }
paulo@0 1109 }
paulo@0 1110
paulo@0 1111 DATAFILE *obj = find_datafile_object(dat, "arttitle_bmp");
paulo@0 1112 BITMAP *logo = obj ? obj->dat : NULL;
paulo@0 1113 obj = find_datafile_object(dat, "arttitle_pal");
paulo@0 1114 const RGB *pal = obj ? obj->dat : NULL;
paulo@0 1115
paulo@0 1116 if (logo && pal) {
paulo@0 1117 set_palette(pal);
paulo@0 1118 draw_sprite(back, logo,
paulo@0 1119 (SCREEN_W - logo->w) / 2, (384 - logo->h) / 2);
paulo@0 1120 //unselect_palette();
paulo@0 1121 }
paulo@0 1122
paulo@0 1123 textout_centre_ex(back, aver32, "Arrows: change; Enter: choose",
paulo@0 1124 SCREEN_W / 2, 440,
paulo@0 1125 0, -1);
paulo@0 1126
paulo@0 1127 textout_centre_ex(back, aver32, "LOCKJAW: The Reference "LJ_VERSION,
paulo@0 1128 SCREEN_W / 2, SCREEN_H - 40,
paulo@0 1129 0, -1);
paulo@0 1130
paulo@0 1131 return back;
paulo@0 1132 }
paulo@0 1133
paulo@0 1134 enum {
paulo@0 1135 TITLE_EXIT = 0,
paulo@0 1136 TITLE_PLAY,
paulo@0 1137 TITLE_REPLAY,
paulo@0 1138 TITLE_OPTIONS,
paulo@0 1139 TITLE_SKIN,
paulo@0 1140 TITLE_KEYS,
paulo@0 1141 N_TITLE_ACTIONS
paulo@0 1142 };
paulo@0 1143
paulo@0 1144 static const char *titleActions[N_TITLE_ACTIONS] = {
paulo@0 1145 [TITLE_EXIT] = "Exit",
paulo@0 1146 [TITLE_PLAY] = "Play",
paulo@0 1147 [TITLE_REPLAY] = "Replay",
paulo@0 1148 [TITLE_SKIN] = "Skin...",
paulo@0 1149 [TITLE_OPTIONS] = "Options...",
paulo@0 1150 [TITLE_KEYS] = "Game Keys..."
paulo@0 1151 };
paulo@0 1152 /*
paulo@0 1153 0: Exit
paulo@0 1154 1: Play
paulo@0 1155 2
paulo@0 1156 */
paulo@0 1157 int title(void) {
paulo@0 1158
paulo@0 1159 // don't even draw if the player is trying to close the window
paulo@0 1160 if (wantsClose) {
paulo@0 1161 return 0;
paulo@0 1162 }
paulo@0 1163
paulo@0 1164 BITMAP *back = buildTitleScreen();
paulo@0 1165 LJBits lastKeys = ~0;
paulo@0 1166 int redraw = 1;
paulo@0 1167 int choice = 1;
paulo@0 1168
paulo@0 1169 if (!back) {
paulo@0 1170 alert("Not enough memory to display the title screen.",
paulo@0 1171 "(If you don't even have RAM for a title screen,",
paulo@0 1172 "then what do you have RAM for?)",
paulo@0 1173 "Exit", 0, 13, 0);
paulo@0 1174 return 0;
paulo@0 1175 }
paulo@0 1176
paulo@0 1177 redrawWholeScreen = 1;
paulo@0 1178
paulo@0 1179 for(int done = 0; done == 0; ) {
paulo@0 1180 if (redrawWholeScreen) {
paulo@0 1181 redrawWholeScreen = 0;
paulo@0 1182 blit(back, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
paulo@0 1183 redraw = 1;
paulo@0 1184 }
paulo@0 1185 if (redraw) {
paulo@0 1186 int dehilite = makecol(221, 153, 85);
paulo@0 1187 int white = makecol(255, 255, 255);
paulo@0 1188 redraw = 0;
paulo@0 1189 vsync();
paulo@0 1190 blit(back, screen, 0, 400, 0, 400, SCREEN_W, 30);
paulo@0 1191 textout_centre_ex(screen, aver32,
paulo@0 1192 titleActions[choice],
paulo@0 1193 SCREEN_W / 2, 400, white, -1);
paulo@0 1194 textout_centre_ex(screen, aver32,
paulo@0 1195 titleActions[choice == 0 ? N_TITLE_ACTIONS - 1 : choice - 1],
paulo@0 1196 SCREEN_W / 2 - 160, 400, dehilite, -1);
paulo@0 1197 textout_centre_ex(screen, aver32,
paulo@0 1198 titleActions[choice == N_TITLE_ACTIONS - 1 ? 0 : choice + 1],
paulo@0 1199 SCREEN_W / 2 + 160, 400, dehilite, -1);
paulo@0 1200 }
paulo@0 1201
paulo@0 1202 while (keypressed()) {
paulo@0 1203 int scancode;
paulo@0 1204 ureadkey(&scancode);
paulo@0 1205 if (scancode == KEY_PRTSCR) {
paulo@0 1206 saveScreen(-1);
paulo@0 1207 }
paulo@0 1208 }
paulo@0 1209
paulo@0 1210 LJBits keys = menuReadPad();
paulo@0 1211 LJBits newKeys = keys & ~lastKeys;
paulo@0 1212
paulo@0 1213 if (newKeys & VKEY_LEFT) {
paulo@0 1214 --choice;
paulo@0 1215 redraw = 1;
paulo@0 1216 ezPlaySample("shift_wav", 128);
paulo@0 1217 }
paulo@0 1218 if (newKeys & VKEY_RIGHT) {
paulo@0 1219 ++choice;
paulo@0 1220 redraw = 1;
paulo@0 1221 ezPlaySample("shift_wav", 128);
paulo@0 1222 }
paulo@0 1223 if (newKeys & VKEY_ROTL) {
paulo@0 1224 choice = 0;
paulo@0 1225 redraw = 1;
paulo@0 1226 ezPlaySample("rotate_wav", 128);
paulo@0 1227 }
paulo@0 1228 if (newKeys & VKEY_ROTR) {
paulo@0 1229 done = 1;
paulo@0 1230 ezPlaySample("line_wav", 128);
paulo@0 1231 }
paulo@0 1232 if (choice < 0) {
paulo@0 1233 choice += N_TITLE_ACTIONS;
paulo@0 1234 }
paulo@0 1235 if (choice >= N_TITLE_ACTIONS) {
paulo@0 1236 choice -= N_TITLE_ACTIONS;
paulo@0 1237 }
paulo@0 1238
paulo@0 1239 lastKeys = keys;
paulo@0 1240
paulo@0 1241 if (!redraw) {
paulo@0 1242 rest(30);
paulo@0 1243 }
paulo@0 1244 if (wantsClose) {
paulo@0 1245 done = 1;
paulo@0 1246 choice = 0;
paulo@0 1247 }
paulo@0 1248 }
paulo@0 1249 destroy_bitmap(back);
paulo@0 1250 return choice;
paulo@0 1251 }
paulo@0 1252
paulo@0 1253
paulo@0 1254 void setupWindow(void) {
paulo@0 1255 set_window_title("LOCKJAW");
paulo@0 1256 bgColor = makecol(255, 255, 255);
paulo@0 1257 pfFgColor = bgColor;
paulo@0 1258 hiliteColor = makecol(255, 255, 204);
paulo@0 1259 refreshRate = get_refresh_rate();
paulo@0 1260 }
paulo@0 1261
paulo@0 1262 void drawCoprNotice(void) {
paulo@0 1263 clear_to_color(screen, pfBgColor);
paulo@0 1264 for (int i = 0; i < MENU_COPR_NOTICE_LINES; ++i) {
paulo@0 1265 textout_ex(screen, font, menuCoprNotice[i],
paulo@0 1266 16, 580 + 12 * (i - MENU_COPR_NOTICE_LINES),
paulo@0 1267 pfFgColor, -1);
paulo@0 1268 }
paulo@0 1269 }
paulo@0 1270
paulo@0 1271
paulo@0 1272 /**
paulo@0 1273 * Destroys the back buffers for both playfields.
paulo@0 1274 */
paulo@0 1275 static void destroyBackBuf(LJPCView *plat) {
paulo@0 1276 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 1277 if (plat->back) {
paulo@0 1278 destroy_bitmap(plat->back);
paulo@0 1279 plat->back = NULL;
paulo@0 1280 }
paulo@0 1281 }
paulo@0 1282 if (plat->skin->fullback) {
paulo@0 1283 destroy_bitmap(plat->skin->fullback);
paulo@0 1284 plat->skin->fullback = NULL;
paulo@0 1285 }
paulo@0 1286 }
paulo@0 1287
paulo@0 1288 /**
paulo@0 1289 * Creates the back buffers for both playfields.
paulo@0 1290 */
paulo@0 1291 static int createBackBuf(LJView *v) {
paulo@0 1292 v->plat->skin->fullback = create_system_bitmap(SCREEN_W, SCREEN_H);
paulo@0 1293 if(!v->plat->skin->fullback) {
paulo@0 1294 allegro_message("Could not create back buffer.\n");
paulo@0 1295 return 0;
paulo@0 1296 }
paulo@0 1297
paulo@0 1298 int blkW = v->plat->skin->blkW;
paulo@0 1299 int blkH = v->plat->skin->blkH;
paulo@0 1300 int y = v->plat->skin->baseY
paulo@0 1301 - v->plat->skin->pfElev
paulo@0 1302 - blkH * v->field->ceiling;
paulo@0 1303
paulo@0 1304 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 1305 int x = v->plat->skin->baseX
paulo@0 1306 + blkW * v[i].field->leftWall;
paulo@0 1307
paulo@0 1308 v[i].plat->back = create_sub_bitmap(v->plat->skin->fullback,
paulo@0 1309 x + SCREEN_W / 2 * i,
paulo@0 1310 y,
paulo@0 1311 v->plat->skin->blkW * LJ_PF_WID,
paulo@0 1312 v->plat->skin->blkH * LJ_PF_VIS_HT);
paulo@0 1313 if (!v[i].plat->back) {
paulo@0 1314 destroyBackBuf(v->plat);
paulo@0 1315 return 0;
paulo@0 1316 }
paulo@0 1317 }
paulo@0 1318 return 1;
paulo@0 1319 }
paulo@0 1320
paulo@0 1321 /**
paulo@0 1322 * Destroys all system bitmaps that a given view owns.
paulo@0 1323 * Useful before changing screen mode.
paulo@0 1324 */
paulo@0 1325 void destroySystemBitmaps(LJPCView *plat) {
paulo@0 1326 destroyBackBuf(plat);
paulo@0 1327 if (plat->skin->connBlocks) {
paulo@0 1328 destroy_bitmap(plat->skin->connBlocks);
paulo@0 1329 plat->skin->connBlocks = NULL;
paulo@0 1330 }
paulo@0 1331 }
paulo@0 1332
paulo@0 1333 int openWindow(int windowed)
paulo@0 1334 {
paulo@0 1335 int depth = desktop_color_depth();
paulo@0 1336 int card = windowed ? GFX_AUTODETECT_WINDOWED : GFX_AUTODETECT_FULLSCREEN;
paulo@0 1337
paulo@0 1338 /* Reference implementation for Allegro is not compatible with
paulo@0 1339 indexed color. */
paulo@0 1340 if (depth < 15) {
paulo@0 1341 depth = 16;
paulo@0 1342 }
paulo@0 1343
paulo@0 1344 // Full screen procedure
paulo@0 1345 set_color_depth(depth);
paulo@0 1346 if (set_gfx_mode(card, skinW, skinH, 0, 0) == 0) {
paulo@0 1347 setupWindow();
paulo@0 1348 return 0;
paulo@0 1349 }
paulo@0 1350
paulo@0 1351 // Windows can't tell 16 bit from 15 bit. If desktop color depth is reported as 16, try 15 too.
paulo@0 1352 if (depth == 16) {
paulo@0 1353 set_color_depth(15);
paulo@0 1354 if (set_gfx_mode(card, skinW, skinH, 0, 0) == 0) {
paulo@0 1355 setupWindow();
paulo@0 1356 return 0;
paulo@0 1357 }
paulo@0 1358 }
paulo@0 1359
paulo@0 1360 return -1;
paulo@0 1361 }
paulo@0 1362
paulo@0 1363 BITMAP *loadConnections(const char *filename, int blkW, int blkH) {
paulo@0 1364 BITMAP *src = load_bitmap(filename, NULL);
paulo@0 1365
paulo@0 1366 if (!src) {
paulo@0 1367 return NULL;
paulo@0 1368 }
paulo@0 1369 BITMAP *dst = create_system_bitmap(blkW*16, blkH*16);
paulo@0 1370 if (!dst) {
paulo@0 1371 destroy_bitmap(src);
paulo@0 1372 return NULL;
paulo@0 1373 }
paulo@0 1374 acquire_bitmap(dst);
paulo@0 1375 for (unsigned int col = 0; col < 16; ++col) {
paulo@0 1376 unsigned int srcXBase = (col & 0x03) * blkW * 2;
paulo@0 1377 unsigned int srcYBase = (col >> 2) * blkH * 2;
paulo@0 1378 unsigned int dstYBase = col * blkH;
paulo@0 1379 for (unsigned int conn = 0; conn < 16; ++conn) {
paulo@0 1380 unsigned int dstXBase = conn * blkW;
paulo@0 1381 unsigned int topSegY = (conn & CONNECT_U) ? blkH : 0;
paulo@0 1382 unsigned int botSegY = (conn & CONNECT_D) ? blkH/2 : 3*blkH/2;
paulo@0 1383 unsigned int leftSegX = (conn & CONNECT_L) ? blkW : 0;
paulo@0 1384 unsigned int rightSegX = (conn & CONNECT_R) ? blkW/2 : 3*blkW/2;
paulo@0 1385 blit(src, dst,
paulo@0 1386 srcXBase + leftSegX, srcYBase + topSegY,
paulo@0 1387 dstXBase + 0, dstYBase + 0,
paulo@0 1388 blkW/2, blkH/2);
paulo@0 1389 blit(src, dst,
paulo@0 1390 srcXBase + rightSegX, srcYBase + topSegY,
paulo@0 1391 dstXBase + blkW/2, dstYBase + 0,
paulo@0 1392 blkW/2, blkH/2);
paulo@0 1393 blit(src, dst,
paulo@0 1394 srcXBase + leftSegX, srcYBase + botSegY,
paulo@0 1395 dstXBase + 0, dstYBase + blkH/2,
paulo@0 1396 blkW/2, blkH/2);
paulo@0 1397 blit(src, dst,
paulo@0 1398 srcXBase + rightSegX, srcYBase + botSegY,
paulo@0 1399 dstXBase + blkW/2, dstYBase + blkH/2,
paulo@0 1400 blkW/2, blkH/2);
paulo@0 1401 }
paulo@0 1402 }
paulo@0 1403 release_bitmap(dst);
paulo@0 1404 destroy_bitmap(src);
paulo@0 1405 return dst;
paulo@0 1406 }
paulo@0 1407
paulo@0 1408 void closeWindow(void) {
paulo@0 1409 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
paulo@0 1410 }
paulo@0 1411
paulo@0 1412 static void mainCleanup(LJPCView *v) {
paulo@0 1413 destroyBackBuf(v);
paulo@0 1414 if (v->skin->blocks) {
paulo@0 1415 destroy_bitmap(v->skin->blocks);
paulo@0 1416 }
paulo@0 1417 if (v->skin->connBlocks) {
paulo@0 1418 destroy_bitmap(v->skin->connBlocks);
paulo@0 1419 }
paulo@0 1420 LJMusic_delete(v->skin->bgm);
paulo@0 1421 if (withSound) {
paulo@0 1422 remove_sound();
paulo@0 1423 }
paulo@0 1424 closeWindow();
paulo@0 1425 }
paulo@0 1426
paulo@0 1427 /**
paulo@0 1428 * Resets all skin settings to their initial values
paulo@0 1429 * so that skins can override them.
paulo@0 1430 */
paulo@0 1431 void loadSkinDefaults(LJPCSkin *s) {
paulo@0 1432 ustrzcpy(ljblocksSRSName, sizeof(ljblocksSRSName) - 1,
paulo@0 1433 "ljblocks.bmp");
paulo@0 1434 ustrzcpy(ljblocksSegaName, sizeof(ljblocksSegaName) - 1,
paulo@0 1435 "ljblocks-sega.bmp");
paulo@0 1436 ustrzcpy(ljconnSRSName, sizeof(ljconnSRSName) - 1,
paulo@0 1437 "ljconn.bmp");
paulo@0 1438 ustrzcpy(ljconnSegaName, sizeof(ljconnSegaName) - 1,
paulo@0 1439 "ljconn-sega.bmp");
paulo@0 1440 ustrzcpy(ljbgName, sizeof(ljbgName) - 1,
paulo@0 1441 "ljbg.jpg");
paulo@0 1442 ustrzcpy(menubgName, sizeof(ljbgName) - 1,
paulo@0 1443 "menubg.jpg");
paulo@0 1444 ustrzcpy(bgmName, sizeof(bgmName) - 1,
paulo@0 1445 "bgm.s3m");
paulo@0 1446 ustrzcpy(bgmRhythmName, sizeof(bgmRhythmName) - 1,
paulo@0 1447 "bgm-rhythm.s3m");
paulo@0 1448 bgmLoopPoint = 0;
paulo@0 1449 bgmReadyGo = 0;
paulo@0 1450 bgmVolume = 128;
paulo@0 1451 bgColor = makecol(255, 255, 255);
paulo@0 1452 fgColor = makecol(0, 0, 0);
paulo@0 1453 hiliteColor = makecol(255, 255, 204);
paulo@0 1454 pfBgColor = makecol(0, 0, 0);
paulo@0 1455 pfFgColor = makecol(255, 255, 255);
paulo@0 1456 s->blkW = 24;
paulo@0 1457 s->blkH = 24;
paulo@0 1458 s->transparentPF = 0;
paulo@0 1459 s->shiftScale = 0;
paulo@0 1460 s->baseX = 0;
paulo@0 1461 s->nextPos = 0;
paulo@0 1462 }
paulo@0 1463
paulo@0 1464 /**
paulo@0 1465 * Converts a single hexadecimal digit to its value.
paulo@0 1466 * @param in USASCII/Unicode value of hex digit character
paulo@0 1467 * @return value
paulo@0 1468 */
paulo@0 1469 int hexDigitValue(int in) {
paulo@0 1470 if (in >= '0' && in <= '9') {
paulo@0 1471 return in - '0';
paulo@0 1472 } else if (in >= 'A' && in <= 'F') {
paulo@0 1473 return in - 'A' + 10;
paulo@0 1474 } else if (in >= 'a' && in <= 'f') {
paulo@0 1475 return in - 'a' + 10;
paulo@0 1476 } else {
paulo@0 1477 return -1;
paulo@0 1478 }
paulo@0 1479 }
paulo@0 1480
paulo@0 1481 int translateComponent(const char **in, size_t nDigits) {
paulo@0 1482 const char *here = *in;
paulo@0 1483 int hi = hexDigitValue(*here++);
paulo@0 1484 int lo = nDigits > 3 ? hexDigitValue(*here++) : hi;
paulo@0 1485 *in = here;
paulo@0 1486 if (hi >= 0 && lo >= 0) {
paulo@0 1487 return hi * 16 + lo;
paulo@0 1488 } else {
paulo@0 1489 return -1;
paulo@0 1490 }
paulo@0 1491 }
paulo@0 1492
paulo@0 1493 /**
paulo@0 1494 * Interprets a hexadecimal color specifier.
paulo@0 1495 * @param in hexadecimal color specifier, in #ABC or #AABBCC format
paulo@0 1496 * @return Allegro device-dependent color, in makecol() format
paulo@0 1497 */
paulo@0 1498 int translateColor(const char *in) {
paulo@0 1499 size_t nDigits = 0;
paulo@0 1500
paulo@0 1501 // Verify and skip #
paulo@0 1502 if (*in != '#') {
paulo@0 1503 return -1;
paulo@0 1504 }
paulo@0 1505 ++in;
paulo@0 1506
paulo@0 1507 // Determine whether we have a 3-digit color or a 6-digit color
paulo@0 1508 for (const char *here = in;
paulo@0 1509 hexDigitValue(*here) >= 0;
paulo@0 1510 ++here) {
paulo@0 1511 ++nDigits;
paulo@0 1512 }
paulo@0 1513 if (nDigits != 3 && nDigits != 6) {
paulo@0 1514 return -1;
paulo@0 1515 }
paulo@0 1516
paulo@0 1517 int red = translateComponent(&in, nDigits);
paulo@0 1518 int green = translateComponent(&in, nDigits);
paulo@0 1519 int blue = translateComponent(&in, nDigits);
paulo@0 1520 if (red >= 0 && green >= 0 && blue >= 0) {
paulo@0 1521 return makecol(red, green, blue);
paulo@0 1522 } else {
paulo@0 1523 return -1;
paulo@0 1524 }
paulo@0 1525 };
paulo@0 1526
paulo@0 1527 /**
paulo@0 1528 * Loads skin parameters from the file.
paulo@0 1529 * @param skinName Name of skin ini file
paulo@0 1530 */
paulo@0 1531 int loadSkinFile(LJPCSkin *s, const char *skinName) {
paulo@0 1532
paulo@0 1533 // Don't use ljfopen here because lj.ini specifies the absolute skin file
paulo@0 1534 FILE *fp = fopen(skinName, "rt");
paulo@0 1535 char key[1024], var[1024], val[1024], input_buf[1024];
paulo@0 1536
paulo@0 1537 key[0] = 0;
paulo@0 1538 var[0] = 0;
paulo@0 1539 val[0] = 0;
paulo@0 1540 loadSkinDefaults(s);
paulo@0 1541
paulo@0 1542 if (!fp) return 0;
paulo@0 1543 while(1) {
paulo@0 1544 int rval;
paulo@0 1545
paulo@0 1546 if(!fgets (input_buf, sizeof(input_buf), fp))
paulo@0 1547 break;
paulo@0 1548 rval = parse_ini_line(input_buf, key, var, val);
paulo@0 1549
paulo@0 1550 if(!ustrcmp ("ljblocksSRS", var)) {
paulo@0 1551 ustrzcpy(ljblocksSRSName, sizeof(ljblocksSRSName) - 1, val);
paulo@0 1552 }
paulo@0 1553 else if(!ustrcmp ("ljblocksSega", var)) {
paulo@0 1554 ustrzcpy(ljblocksSegaName, sizeof(ljblocksSegaName) - 1, val);
paulo@0 1555 }
paulo@0 1556 else if(!ustrcmp ("ljconnSRS", var)) {
paulo@0 1557 ustrzcpy(ljconnSRSName, sizeof(ljconnSRSName) - 1, val);
paulo@0 1558 }
paulo@0 1559 else if(!ustrcmp ("ljconnSega", var)) {
paulo@0 1560 ustrzcpy(ljconnSegaName, sizeof(ljconnSegaName) - 1, val);
paulo@0 1561 }
paulo@0 1562 else if(!ustrcmp ("bgm", var)) {
paulo@0 1563 ustrzcpy(bgmName, sizeof(bgmName) - 1, val);
paulo@0 1564 }
paulo@0 1565 else if(!ustrcmp ("bgmRhythm", var)) {
paulo@0 1566 ustrzcpy(bgmRhythmName, sizeof(bgmRhythmName) - 1, val);
paulo@0 1567 }
paulo@0 1568 else if(!ustrcmp ("ljbg", var)) {
paulo@0 1569 ustrzcpy(ljbgName, sizeof(ljbgName) - 1, val);
paulo@0 1570 }
paulo@0 1571 else if(!ustrcmp ("bgmLoopPoint", var)) {
paulo@0 1572 unsigned long int c = strtoul(val, NULL, 0);
paulo@0 1573 if (c >= 0) {
paulo@0 1574 bgmLoopPoint = c;
paulo@0 1575 }
paulo@0 1576 }
paulo@0 1577 else if(!ustrcmp ("bgmVolume", var)) {
paulo@0 1578 unsigned long int c = strtol(val, NULL, 0);
paulo@0 1579 if (c >= 0) {
paulo@0 1580 bgmVolume = c;
paulo@0 1581 }
paulo@0 1582 }
paulo@0 1583 else if(!ustrcmp ("bgmReadyGo", var)) {
paulo@0 1584 unsigned long int c = strtoul(val, NULL, 0);
paulo@0 1585 if (c >= 0) {
paulo@0 1586 bgmReadyGo = c;
paulo@0 1587 }
paulo@0 1588 }
paulo@0 1589 else if(!ustrcmp ("pfbgcolor", var)) {
paulo@0 1590 int c = translateColor(val);
paulo@0 1591 if (c >= 0) {
paulo@0 1592 pfBgColor = c;
paulo@0 1593 }
paulo@0 1594 }
paulo@0 1595 else if(!ustrcmp ("pfcolor", var)) {
paulo@0 1596 int c = translateColor(val);
paulo@0 1597 if (c >= 0) {
paulo@0 1598 pfFgColor = c;
paulo@0 1599 }
paulo@0 1600 }
paulo@0 1601 else if(!ustrcmp ("bgcolor", var)) {
paulo@0 1602 int c = translateColor(val);
paulo@0 1603 if (c >= 0) {
paulo@0 1604 bgColor = c;
paulo@0 1605 }
paulo@0 1606 }
paulo@0 1607 else if(!ustrcmp ("color", var)) {
paulo@0 1608 int c = translateColor(val);
paulo@0 1609 if (c >= 0) {
paulo@0 1610 fgColor = c;
paulo@0 1611 }
paulo@0 1612 }
paulo@0 1613 else if(!ustrcmp ("hilitecolor", var)) {
paulo@0 1614 int c = translateColor(val);
paulo@0 1615 if (c >= 0) {
paulo@0 1616 hiliteColor = c;
paulo@0 1617 }
paulo@0 1618 }
paulo@0 1619 else if(!ustrcmp ("blkW", var)) {
paulo@0 1620 int c = strtol(val, NULL, 0);
paulo@0 1621 if (c >= 0) {
paulo@0 1622 s->blkW = c;
paulo@0 1623 }
paulo@0 1624 }
paulo@0 1625 else if(!ustrcmp ("blkH", var)) {
paulo@0 1626 int c = strtol(val, NULL, 0);
paulo@0 1627 if (c >= 0) {
paulo@0 1628 s->blkH = c;
paulo@0 1629 }
paulo@0 1630 }
paulo@0 1631 else if(!ustrcmp ("transparentPF", var)) {
paulo@0 1632 int c = atoi(val);
paulo@0 1633 if (c >= 0) {
paulo@0 1634 s->transparentPF = c;
paulo@0 1635 }
paulo@0 1636 }
paulo@0 1637 else if(!ustrcmp ("shiftScale", var)) {
paulo@0 1638 int c = atoi(val);
paulo@0 1639 if (c >= 0) {
paulo@0 1640 s->shiftScale = c;
paulo@0 1641 }
paulo@0 1642 }
paulo@0 1643 else if(!ustrcmp ("baseX", var)) {
paulo@0 1644 int c = atoi(val);
paulo@0 1645 if (c >= 0) {
paulo@0 1646 s->baseX = c;
paulo@0 1647 }
paulo@0 1648 }
paulo@0 1649 else if(!ustrcmp ("nextPos", var)) {
paulo@0 1650 int c = atoi(val);
paulo@0 1651 if (c >= 0) {
paulo@0 1652 s->nextPos = c;
paulo@0 1653 }
paulo@0 1654 }
paulo@0 1655 else if(!ustrcmp ("wndW", var)) {
paulo@0 1656 unsigned long int c = strtol(val, NULL, 0);
paulo@0 1657 if (c >= 0) {
paulo@0 1658 skinW = c;
paulo@0 1659 }
paulo@0 1660 }
paulo@0 1661 else if(!ustrcmp ("wndH", var)) {
paulo@0 1662 unsigned long int c = strtoul(val, NULL, 0);
paulo@0 1663 if (c >= 0) {
paulo@0 1664 skinH = c;
paulo@0 1665 }
paulo@0 1666 }
paulo@0 1667
paulo@0 1668 }
paulo@0 1669 fclose(fp);
paulo@0 1670 ljpathSetSkinFolder(skinName);
paulo@0 1671 return 0;
paulo@0 1672 }
paulo@0 1673
paulo@0 1674 static void drawProgressSegment(int min, int max) {
paulo@0 1675 min = min * SCREEN_W / 100;
paulo@0 1676 max = max * SCREEN_W / 100;
paulo@0 1677 int blue = makecol(0, 0, 255);
paulo@0 1678 rectfill(screen, min, SCREEN_H - 8, max - 1, SCREEN_H - 5, blue);
paulo@0 1679 int orange = makecol(255, 128, 0);
paulo@0 1680 rectfill(screen, min, SCREEN_H - 4, max - 1, SCREEN_H - 1, orange);
paulo@0 1681 }
paulo@0 1682
paulo@0 1683 static int loadSkin(LJView *v, const char *skinName) {
paulo@0 1684 BITMAP *bmp;
paulo@0 1685 const LJRotSystem *rs = rotSystems[v->field->rotationSystem];
paulo@0 1686 int colorScheme = rs->colorScheme;
paulo@0 1687
paulo@0 1688 rectfill(screen, 0, 592, 799, 599, 0);
paulo@0 1689 loadSkinFile(v->plat->skin, skinName);
paulo@0 1690
paulo@0 1691 destroyBackBuf(v->plat);
paulo@0 1692 if (!createBackBuf(v)) {
paulo@0 1693 allegro_message("Could not create back buffer.\n");
paulo@0 1694 return 1;
paulo@0 1695 }
paulo@0 1696
paulo@0 1697 drawProgressSegment(0, 20);
paulo@0 1698
paulo@0 1699 // Load background image
paulo@0 1700 char path[PATH_MAX];
paulo@0 1701 bmp = ljpathFind_r(path, ljbgName)
paulo@0 1702 ? load_bitmap(path, NULL) : NULL;
paulo@0 1703 if (v->plat->skin->bg) {
paulo@0 1704 destroy_bitmap(v->plat->skin->bg);
paulo@0 1705 }
paulo@0 1706 if (bmp) {
paulo@0 1707
paulo@0 1708 // If the image size doesn't match the window size, resize it
paulo@0 1709 if (bmp->w != SCREEN_W || bmp->h != SCREEN_H) {
paulo@0 1710 BITMAP *resized = create_bitmap(SCREEN_W, SCREEN_H);
paulo@0 1711
paulo@0 1712 if (resized) {
paulo@0 1713 stretch_blit(bmp, resized, 0, 0, bmp->w, bmp->h,
paulo@0 1714 0, 0, SCREEN_W, SCREEN_H);
paulo@0 1715 destroy_bitmap(bmp);
paulo@0 1716 }
paulo@0 1717 if (bmp) {
paulo@0 1718 bmp = resized;
paulo@0 1719 } else {
paulo@0 1720 allegro_message("Background image \"%s\" resize failed.\n",
paulo@0 1721 ljbgName);
paulo@0 1722 }
paulo@0 1723 }
paulo@0 1724 }
paulo@0 1725 if(!bmp) {
paulo@0 1726 bmp = create_bitmap(SCREEN_W, SCREEN_H);
paulo@0 1727 if (bmp) {
paulo@0 1728 allegro_message("Background image \"%s\" not found.\n"
paulo@0 1729 "Using plain background instead.\n",
paulo@0 1730 ljbgName);
paulo@0 1731 clear_to_color(bmp, bgColor);
paulo@0 1732 } else {
paulo@0 1733 allegro_message("Background image \"%s\" not found.\n",
paulo@0 1734 ljbgName);
paulo@0 1735 return 0;
paulo@0 1736 }
paulo@0 1737 }
paulo@0 1738 v->plat->skin->bg = bmp;
paulo@0 1739 drawProgressSegment(20, 40);
paulo@0 1740
paulo@0 1741 // load block images
paulo@0 1742 if (v->plat->skin->blocks) {
paulo@0 1743 destroy_bitmap(v->plat->skin->blocks);
paulo@0 1744 }
paulo@0 1745 bmp = ljpathFind_r(path, colorScheme
paulo@0 1746 ? ljblocksSegaName
paulo@0 1747 : ljblocksSRSName)
paulo@0 1748 ? load_bitmap(path, NULL) : NULL;
paulo@0 1749 v->plat->skin->blocks = bmp;
paulo@0 1750 if(!v->plat->skin->blocks) {
paulo@0 1751 allegro_message("Background image \"%s\" not found.\n",
paulo@0 1752 ljbgName);
paulo@0 1753 return 0;
paulo@0 1754 }
paulo@0 1755 drawProgressSegment(40, 60);
paulo@0 1756
paulo@0 1757 // load connected block images
paulo@0 1758 if (v->plat->skin->connBlocks) {
paulo@0 1759 destroy_bitmap(v->plat->skin->connBlocks);
paulo@0 1760 }
paulo@0 1761 bmp = ljpathFind_r(path, colorScheme
paulo@0 1762 ? ljconnSegaName
paulo@0 1763 : ljconnSRSName)
paulo@0 1764 ? loadConnections(path,
paulo@0 1765 v->plat->skin->blkW,
paulo@0 1766 v->plat->skin->blkH)
paulo@0 1767 : NULL;
paulo@0 1768 v->plat->skin->connBlocks = bmp;
paulo@0 1769 drawProgressSegment(60, 80);
paulo@0 1770
paulo@0 1771 // load music
paulo@0 1772 int isRhythm = (v->field->speedState.curve == LJSPD_RHYTHM);
paulo@0 1773 if (ljpathFind_r(path, isRhythm ? bgmRhythmName : bgmName)) {
paulo@0 1774 LJMusic_load(v->plat->skin->bgm, path);
paulo@0 1775 }
paulo@0 1776 if (!isRhythm) {
paulo@0 1777 LJMusic_setLoop(v->plat->skin->bgm, bgmLoopPoint);
paulo@0 1778 }
paulo@0 1779 drawProgressSegment(80, 100);
paulo@0 1780 return 1;
paulo@0 1781 }
paulo@0 1782
paulo@0 1783 void drop_mouse(void) {
paulo@0 1784 while (mouse_y < SCREEN_H - 25) {
paulo@0 1785 position_mouse(mouse_x, mouse_y + 20);
paulo@0 1786 rest(10);
paulo@0 1787 }
paulo@0 1788 ezPlaySample("land_wav", 192);
paulo@0 1789 position_mouse(mouse_x, SCREEN_H - 5);
paulo@0 1790 ezPlaySample("lock_wav", 192);
paulo@0 1791 }
paulo@0 1792
paulo@0 1793 int pickReplay(void) {
paulo@0 1794 FONT *oldFont = font;
paulo@0 1795 font = (FONT *)aver16;
paulo@0 1796 install_mouse();
paulo@0 1797 int got = file_select_ex("Choose a demo:", demoFilename, "ljm", sizeof(demoFilename), 600, 400);
paulo@0 1798 drop_mouse();
paulo@0 1799 remove_mouse();
paulo@0 1800 font = oldFont;
paulo@0 1801 return got ? 0 : -1;
paulo@0 1802 }
paulo@0 1803
paulo@0 1804 void badReplay(void) {
paulo@0 1805 acquire_screen();
paulo@0 1806 clear_to_color(screen, bgColor);
paulo@0 1807 textout_ex(screen, aver32, "The demo", 100, 100, fgColor, -1);
paulo@0 1808 textout_ex(screen, aver16, demoFilename, 100, 130, fgColor, -1);
paulo@0 1809 textout_ex(screen, aver32, "could not be played because it was", 100, 150, fgColor, -1);
paulo@0 1810 textout_ex(screen, aver32, "recorded with a different version", 100, 180, fgColor, -1);
paulo@0 1811 textout_ex(screen, aver32, "of LOCKJAW software.", 100, 210, fgColor, -1);
paulo@0 1812 release_screen();
paulo@0 1813
paulo@0 1814 LJBits lastKeys = ~0;
paulo@0 1815 LJBits keys, newKeys = 0;
paulo@0 1816
paulo@0 1817 do {
paulo@0 1818 keys = menuReadPad();
paulo@0 1819 newKeys = keys & ~lastKeys;
paulo@0 1820 lastKeys = keys;
paulo@0 1821 rest(30);
paulo@0 1822 } while (!(newKeys & (VKEY_ROTL | VKEY_ROTR)));
paulo@0 1823 }
paulo@0 1824
paulo@0 1825 int pickSkin(void) {
paulo@0 1826 FONT *oldFont = font;
paulo@0 1827 font = (FONT *)aver16;
paulo@0 1828 install_mouse();
paulo@0 1829 int got = file_select_ex("Choose a skin:", skinName, "skin", sizeof(skinName), 600, 400);
paulo@0 1830 drop_mouse();
paulo@0 1831 remove_mouse();
paulo@0 1832 font = oldFont;
paulo@0 1833 return got ? 0 : -1;
paulo@0 1834 }
paulo@0 1835
paulo@0 1836 void calcElev(LJView *v) {
paulo@0 1837 int blkH = v->plat->skin->blkH;
paulo@0 1838 int ceiling = v->field->ceiling;
paulo@0 1839 int elev = (LJ_PF_VIS_HT - ceiling) * blkH;
paulo@0 1840
paulo@0 1841 if (elev > 480 - ceiling * blkH) {
paulo@0 1842 elev = 480 - ceiling * blkH;
paulo@0 1843 }
paulo@0 1844 if (elev < 0) {
paulo@0 1845 elev = 0;
paulo@0 1846 }
paulo@0 1847 v->plat->skin->pfElev = elev;
paulo@0 1848 }
paulo@0 1849
paulo@0 1850 int main(const int argc, const char *const *argv) {
paulo@0 1851 const char *cmdLineDemo = NULL;
paulo@0 1852 int lastPreset = -2; // start out with full custom
paulo@0 1853 LJPCSkin skin = {
paulo@0 1854 .baseY = 552,
paulo@0 1855 .blkW = 24,
paulo@0 1856 .blkH = 24
paulo@0 1857 };
paulo@0 1858 LJField p[MAX_PLAYERS];
paulo@0 1859 LJControl control[2] = {
paulo@0 1860 {
paulo@0 1861 .replaySrc = 0,
paulo@0 1862 .replayDst = 0
paulo@0 1863 }
paulo@0 1864 };
paulo@0 1865 LJPCView platView[MAX_PLAYERS] = {
paulo@0 1866 {
paulo@0 1867 .skin = &skin
paulo@0 1868 },
paulo@0 1869 {
paulo@0 1870 .skin = &skin
paulo@0 1871 }
paulo@0 1872 };
paulo@0 1873 LJView mainView[MAX_PLAYERS] = {
paulo@0 1874 {
paulo@0 1875 .field = &p[0],
paulo@0 1876 .control = &control[0],
paulo@0 1877 .plat = &platView[0],
paulo@0 1878 .backDirty = ~0
paulo@0 1879 },
paulo@0 1880 {
paulo@0 1881 .field = &p[1],
paulo@0 1882 .control = &control[1],
paulo@0 1883 .plat = &platView[1],
paulo@0 1884 .backDirty = ~0,
paulo@0 1885 }
paulo@0 1886 };
paulo@0 1887
paulo@0 1888 struct LJPrefs prefs = {
paulo@0 1889 .number = {
paulo@0 1890 [OPTIONS_TRAILS] = 1,
paulo@0 1891 [OPTIONS_AUTO_PAUSE] = 1,
paulo@0 1892 [OPTIONS_AUTO_RECORD] = 0,
paulo@0 1893 [OPTIONS_WINDOWED] = 1
paulo@0 1894 }
paulo@0 1895 };
paulo@0 1896
paulo@0 1897 // as of 0.46, we're starting to make it a bit more 2-player-clean
paulo@0 1898 int nPlayers = 1;
paulo@0 1899
paulo@0 1900 allegro_init();
paulo@0 1901 ljpathInit(argc > 0 ? argv[0] : ".");
paulo@0 1902 install_timer();
paulo@0 1903 initOptions(prefs.number);
paulo@0 1904 loadOptions(&prefs);
paulo@0 1905 loadSkinFile(&skin, skinName);
paulo@0 1906
paulo@0 1907 if (argc > 1) {
paulo@0 1908 if (argv[1][0] == '-') {
paulo@0 1909 if (!ustrcmp("--help", argv[1])
paulo@0 1910 || !ustrcmp("-h", argv[1])) {
paulo@0 1911 allegro_message("Usage: lj [DEMOFILE]\n");
paulo@0 1912 return 0;
paulo@0 1913 }
paulo@0 1914 } else {
paulo@0 1915 cmdLineDemo = argv[1];
paulo@0 1916 }
paulo@0 1917 }
paulo@0 1918
paulo@0 1919 if (openWindow(prefs.number[OPTIONS_WINDOWED]) != 0) {
paulo@0 1920 allegro_message("LOCKJAW fatal error: Could not open an %dx%d pixel %s.\n"
paulo@0 1921 "Trying %s next time.\n",
paulo@0 1922 skinW, skinH,
paulo@0 1923 prefs.number[OPTIONS_WINDOWED] ? "window": "screen mode",
paulo@0 1924 prefs.number[OPTIONS_WINDOWED] ? "the full screen": "a window");
paulo@0 1925 prefs.number[OPTIONS_WINDOWED] = !prefs.number[OPTIONS_WINDOWED];
paulo@0 1926 saveOptions(&prefs);
paulo@0 1927 return EXIT_FAILURE;
paulo@0 1928 }
paulo@0 1929 drawCoprNotice();
paulo@0 1930 LOCK_FUNCTION(incCurTime);
paulo@0 1931 LOCK_VARIABLE(curTime);
paulo@0 1932 install_int_ex(incCurTime, BPM_TO_TIMER(LJ_TICK_RATE));
paulo@0 1933
paulo@0 1934 jpgalleg_init();
paulo@0 1935 set_color_conversion(COLORCONV_NONE);
paulo@0 1936 {
paulo@0 1937 char path[PATH_MAX];
paulo@0 1938 if (ljpathFind_r(path, "lj.dat")) {
paulo@0 1939 dat = load_datafile(path);
paulo@0 1940 }
paulo@0 1941 }
paulo@0 1942 set_color_conversion(COLORCONV_TOTAL);
paulo@0 1943 if(!dat) {
paulo@0 1944 closeWindow();
paulo@0 1945 allegro_message("LOCKJAW fatal error: Could not load datafile lj.dat\n");
paulo@0 1946 return 1;
paulo@0 1947 }
paulo@0 1948
paulo@0 1949 {
paulo@0 1950 const DATAFILE *aver16dat = find_datafile_object(dat, "Aver16_bmp");
paulo@0 1951 aver16 = aver16dat ? aver16dat->dat : font;
paulo@0 1952 const DATAFILE *aver32dat = find_datafile_object(dat, "Aver32_bmp");
paulo@0 1953 aver32 = aver32dat ? aver32dat->dat : aver16;
paulo@0 1954 }
paulo@0 1955
paulo@0 1956 LOCK_FUNCTION(amnesia);
paulo@0 1957 LOCK_VARIABLE(redrawWholeScreen);
paulo@0 1958
paulo@0 1959 // If we can be notified on switching out, take this notification.
paulo@0 1960 if (set_display_switch_mode(SWITCH_BACKGROUND) >= 0
paulo@0 1961 || set_display_switch_mode(SWITCH_BACKAMNESIA) >= 0) {
paulo@0 1962 set_display_switch_callback(SWITCH_OUT, requestPause);
paulo@0 1963 }
paulo@0 1964 set_display_switch_callback(SWITCH_IN, amnesia);
paulo@0 1965
paulo@0 1966 install_keyboard();
paulo@0 1967 initKeys();
paulo@0 1968
paulo@0 1969 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 1970 p[i].seed = time(NULL) + 123456789*i;
paulo@0 1971 }
paulo@0 1972
paulo@0 1973 reserve_voices(8, 0);
paulo@0 1974 set_volume_per_voice(0);
paulo@0 1975 #ifdef ALLEGRO_WINDOWS
paulo@0 1976 // Under Windows, use the Allegro mixer because on my machine
paulo@0 1977 // and probably others, the built-in mixer will replace the very
paulo@0 1978 // beginning of one sound with the end of the last sound played
paulo@0 1979 // on that voice.
paulo@0 1980 withSound = !install_sound(DIGI_DIRECTAMX(0), MIDI_NONE, NULL);
paulo@0 1981 #else
paulo@0 1982 withSound = !install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL);
paulo@0 1983 #endif
paulo@0 1984 skin.bgm = LJMusic_new();
paulo@0 1985 {
paulo@0 1986 char path[PATH_MAX];
paulo@0 1987 if (ljpathFind_r(path, "sound.dat")) {
paulo@0 1988 sound_dat = load_datafile(path);
paulo@0 1989 }
paulo@0 1990 }
paulo@0 1991
paulo@0 1992 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 1993 unpackOptions(&mainView[i], &prefs);
paulo@0 1994 }
paulo@0 1995 if (loadSkin(&mainView[0], skinName) < 0) {
paulo@0 1996 mainCleanup(platView);
paulo@0 1997 return EXIT_FAILURE;
paulo@0 1998 } else {
paulo@0 1999
paulo@0 2000 }
paulo@0 2001
paulo@0 2002 if(!skin.blocks) {
paulo@0 2003 mainCleanup(platView);
paulo@0 2004 allegro_message("Blocks image \"%s\" not found.\n",
paulo@0 2005 p[0].rotationSystem
paulo@0 2006 ? ljblocksSegaName
paulo@0 2007 : ljblocksSRSName);
paulo@0 2008 return 1;
paulo@0 2009 }
paulo@0 2010
paulo@0 2011 srand(time(NULL));
paulo@0 2012
paulo@0 2013 // Wait for copyright notice to be displayed "conspicuously"
paulo@0 2014 if (curTime < 180) {
paulo@0 2015 rest(3100 - curTime * 16);
paulo@0 2016 }
paulo@0 2017
paulo@0 2018 for (int action = cmdLineDemo ? TITLE_REPLAY : title();
paulo@0 2019 action > TITLE_EXIT && !wantsClose;
paulo@0 2020 action = title()) {
paulo@0 2021 switch (action) {
paulo@0 2022 case TITLE_PLAY:
paulo@0 2023 for (int preset = getPreset(lastPreset);
paulo@0 2024 preset != -1 && !wantsClose;
paulo@0 2025 preset = getPreset(lastPreset))
paulo@0 2026 {
paulo@0 2027 lastPreset = preset;
paulo@0 2028 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 2029 unpackOptions(&mainView[i], &prefs);
paulo@0 2030 }
paulo@0 2031 if (preset >= 0) {
paulo@0 2032 presetStart();
paulo@0 2033 presetAdd(preset);
paulo@0 2034 for (int i = 0; i < MAX_PLAYERS; ++i) {
paulo@0 2035 unpackOptions(&mainView[i], &prefs);
paulo@0 2036 presetFinish(&mainView[i]);
paulo@0 2037 }
paulo@0 2038 }
paulo@0 2039 // reload the skin
paulo@0 2040 if (loadSkin(&mainView[0], skinName) < 0) {
paulo@0 2041 mainCleanup(platView);
paulo@0 2042 return EXIT_FAILURE;
paulo@0 2043 };
paulo@0 2044 for (int i = 0; i < nPlayers; ++i) {
paulo@0 2045 calcElev(&mainView[0]);
paulo@0 2046 pcInit(&mainView[0], &prefs);
paulo@0 2047 }
paulo@0 2048 wantPause = 0;
paulo@0 2049 platView[0].wantRecord = prefs.number[OPTIONS_AUTO_RECORD];
paulo@0 2050 LJMusic_start(skin.bgm,
paulo@0 2051 4096, // mix buffer size
paulo@0 2052 bgmVolume); // volume scale
paulo@0 2053
paulo@0 2054 LJView *const players[MAX_PLAYERS] = {&mainView[0], &mainView[1]};
paulo@0 2055 play(players, nPlayers);
paulo@0 2056 LJMusic_stop(skin.bgm);
paulo@0 2057 if (!wantsClose) {
paulo@0 2058 gameOverAnimation(&platView[0], &p[0],
paulo@0 2059 control[0].countdown <= 0);
paulo@0 2060 debrief(&mainView[0]);
paulo@0 2061 }
paulo@0 2062 }
paulo@0 2063 break;
paulo@0 2064
paulo@0 2065 case TITLE_REPLAY:
paulo@0 2066 {
paulo@0 2067 if (cmdLineDemo) {
paulo@0 2068 ustrzcpy(demoFilename, sizeof(demoFilename) - 1,
paulo@0 2069 cmdLineDemo);
paulo@0 2070 cmdLineDemo = NULL;
paulo@0 2071 } else if (pickReplay() < 0) {
paulo@0 2072 break;
paulo@0 2073 }
paulo@0 2074
paulo@0 2075 unpackOptions(&mainView[0], &prefs);
paulo@0 2076 calcElev(&mainView[0]);
paulo@0 2077 pcInit(&mainView[0], &prefs);
paulo@0 2078 wantPause = 0;
paulo@0 2079 platView[0].wantRecord = 0;
paulo@0 2080 LJMusic_start(skin.bgm,
paulo@0 2081 4096, // mix buffer size
paulo@0 2082 bgmVolume); // volume scale
paulo@0 2083
paulo@0 2084 LJView *const players[2] = {&mainView[0], &mainView[1]};
paulo@0 2085
paulo@0 2086 p->gimmick = -1; // gimmick must be < 0 to activate replay
paulo@0 2087 play(players, 1);
paulo@0 2088 LJMusic_stop(skin.bgm);
paulo@0 2089 if (p[0].gimmick < 0) {
paulo@0 2090 badReplay();
paulo@0 2091 } else {
paulo@0 2092 if (!wantsClose) {
paulo@0 2093 gameOverAnimation(&platView[0], &p[0],
paulo@0 2094 control[0].countdown <= 0);
paulo@0 2095 debrief(&mainView[0]);
paulo@0 2096 }
paulo@0 2097 }
paulo@0 2098 }
paulo@0 2099 break;
paulo@0 2100
paulo@0 2101 case TITLE_SKIN:
paulo@0 2102 pickSkin();
paulo@0 2103
paulo@0 2104 // if resolution changed, reopen the window
paulo@0 2105 {
paulo@0 2106 int oldW = skinW;
paulo@0 2107 int oldH = skinH;
paulo@0 2108 loadSkinFile(&skin, skinName);
paulo@0 2109 if (skinH != oldH || skinW != oldW) {
paulo@0 2110 destroySystemBitmaps(&platView[0]);
paulo@0 2111 openWindow(prefs.number[OPTIONS_WINDOWED]);
paulo@0 2112 }
paulo@0 2113 }
paulo@0 2114
paulo@0 2115 // reload the skin
paulo@0 2116 if (loadSkin(&mainView[0], skinName) < 0) {
paulo@0 2117 mainCleanup(platView);
paulo@0 2118 return EXIT_FAILURE;
paulo@0 2119 };
paulo@0 2120
paulo@0 2121 // save options
paulo@0 2122 saveOptions(&prefs);
paulo@0 2123 break;
paulo@0 2124
paulo@0 2125 case TITLE_OPTIONS:
paulo@0 2126 {
paulo@0 2127 int oldWindowed = prefs.number[OPTIONS_WINDOWED];
paulo@0 2128 options(&mainView[0], prefs.number);
paulo@0 2129 if (oldWindowed != prefs.number[OPTIONS_WINDOWED]) {
paulo@0 2130 destroySystemBitmaps(&platView[0]);
paulo@0 2131 openWindow(prefs.number[OPTIONS_WINDOWED]);
paulo@0 2132 }
paulo@0 2133 }
paulo@0 2134 saveOptions(&prefs);
paulo@0 2135
paulo@0 2136 // reload the skin if the player changed the rotation system
paulo@0 2137 unpackOptions(&mainView[0], &prefs);
paulo@0 2138 if (wantsClose) {
paulo@0 2139 break;
paulo@0 2140 }
paulo@0 2141 if (loadSkin(&mainView[0], skinName) < 0) {
paulo@0 2142 mainCleanup(platView);
paulo@0 2143 return EXIT_FAILURE;
paulo@0 2144 };
paulo@0 2145 break;
paulo@0 2146
paulo@0 2147 case TITLE_KEYS:
paulo@0 2148 configureKeys();
paulo@0 2149 break;
paulo@0 2150
paulo@0 2151 }
paulo@0 2152 }
paulo@0 2153
paulo@0 2154 mainCleanup(platView);
paulo@0 2155 return 0;
paulo@0 2156 } END_OF_MAIN();