annotate src/ljplay.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 /* Game loop frontend for LOCKJAW, an implementation of the Soviet Mind Game
paulo@0 2
paulo@0 3 Copyright (C) 2006 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[player], Elorg,
paulo@0 21 or The Tetris Company LLC.
paulo@0 22
paulo@0 23 */
paulo@0 24
paulo@0 25 #include "ljplay.h"
paulo@0 26 #ifndef WITH_REPLAY
paulo@0 27 #define WITH_REPLAY 0
paulo@0 28 #endif
paulo@0 29
paulo@0 30 #if WITH_REPLAY
paulo@0 31 #include "ljreplay.h"
paulo@0 32 extern const char demoFilename[];
paulo@0 33
paulo@0 34 #endif
paulo@0 35
paulo@0 36
paulo@0 37 void play(LJView *const v[], size_t nPlayers) {
paulo@0 38 int canceled = 0;
paulo@0 39
paulo@0 40 for (unsigned int player = 0; player < nPlayers; ++player) {
paulo@0 41 LJField *const p = v[player]->field;
paulo@0 42 LJControl *const ctl = v[player]->control;
paulo@0 43
paulo@0 44 ctl->countdown = 6;
paulo@0 45 ctl->presses = 0;
paulo@0 46
paulo@0 47 /* Load replay if needed */
paulo@0 48 #if WITH_REPLAY
paulo@0 49 if (p->gimmick < 0) {
paulo@0 50 ctl->replaySrc = openReplay(demoFilename, p);
paulo@0 51 if (!ctl->replaySrc) {
paulo@0 52 return;
paulo@0 53 }
paulo@0 54 v[player]->backDirty = ~0;
paulo@0 55 playRedrawScreen(v[player]);
paulo@0 56 } else {
paulo@0 57 ctl->replaySrc = 0;
paulo@0 58 }
paulo@0 59 #endif
paulo@0 60 }
paulo@0 61 if (!v[0]->control->replaySrc) {
paulo@0 62 for (unsigned int player = 0; player < nPlayers; ++player) {
paulo@0 63 LJField *const p = v[player]->field;
paulo@0 64 newGame(p);
paulo@0 65 initGimmicks(p);
paulo@0 66 v[player]->nLockTimes = 0;
paulo@0 67 v[player]->hideNext = 0;
paulo@0 68 updField(v[player], ~0);
paulo@0 69 }
paulo@0 70 startingAnimation(v[0]);
paulo@0 71 for (unsigned int player = 0; player < nPlayers; ++player) {
paulo@0 72 v[player]->control->lastKeys = 0;
paulo@0 73 v[player]->control->repressKeys = 0;
paulo@0 74 blitField(v[player]);
paulo@0 75 }
paulo@0 76 }
paulo@0 77
paulo@0 78 int lastTime = getTime();
paulo@0 79
paulo@0 80 while(v[0]->field->state != LJS_GAMEOVER && !canceled) {
paulo@0 81 if (getTime() == lastTime) {
paulo@0 82 yieldCPU();
paulo@0 83 }
paulo@0 84 canceled |= ljHandleConsoleButtons(v[0]);
paulo@0 85 while (getTime() - lastTime > 0) {
paulo@0 86 for (unsigned int player = 0; player < nPlayers; ++player) {
paulo@0 87 LJField *const p = v[player]->field;
paulo@0 88 LJControl *const ctl = v[player]->control;
paulo@0 89 LJInput in = {0, 0, 0, 0};
paulo@0 90 int curTime = getTime();
paulo@0 91
paulo@0 92 addKeysToInput(&in, readPad(player), p, ctl);
paulo@0 93
paulo@0 94 // when returning from pause, catch up the speed control
paulo@0 95 if (curTime - lastTime > 10
paulo@0 96 || curTime - lastTime < -10) {
paulo@0 97 lastTime = curTime;
paulo@0 98 }
paulo@0 99
paulo@0 100 {
paulo@0 101 int irsAttempted = (p->sounds & (LJSND_SPAWN | LJSND_HOLD))
paulo@0 102 && in.rotation && ctl->initialRotate;
paulo@0 103
paulo@0 104 // The next line does ALL the game logic.
paulo@0 105 LJBits updatedRows = frame(p, &in) | gimmicks(p, ctl);
paulo@0 106
paulo@0 107 v[player]->backDirty |= updatedRows;
paulo@0 108 if (irsAttempted && (p->sounds & LJSND_ROTATE)) {
paulo@0 109 p->sounds |= LJSND_IRS;
paulo@0 110 }
paulo@0 111 }
paulo@0 112
paulo@0 113 // items is a partly view-based gimmick
paulo@0 114 if (p->gimmick == LJGM_ITEMS && (p->sounds & LJSND_SPAWN)) {
paulo@0 115 v[player]->hideNext = (v[player]->field->nPieces > 7);
paulo@0 116 v[player]->frontDirty |= LJ_DIRTY_NEXT;
paulo@0 117 }
paulo@0 118
paulo@0 119 // five, four, three, two, one
paulo@0 120 int curCountdown = ctl->countdown;
paulo@0 121 if (p->gimmick == LJGM_ULTRA && p->gameTime >= 10500) {
paulo@0 122 curCountdown = (int)(10859 - p->gameTime) / 60;
paulo@0 123 } else if (p->gimmick == LJGM_BTYPE) {
paulo@0 124 curCountdown = 40 - p->lines;
paulo@0 125 } else if (p->gimmick == LJGM_BABY) {
paulo@0 126 curCountdown = (309 - v[player]->control->presses) / 10;
paulo@0 127 } else if (p->gimmick == LJGM_DRILL && (p->sounds & LJSND_LINE)) {
paulo@0 128 int line = bfffo(p->tempRows);
paulo@0 129 if (line < curCountdown)
paulo@0 130 curCountdown = line;
paulo@0 131 }
paulo@0 132
paulo@0 133 // we have to wait for the new piece to come out
paulo@0 134 // so that the score is credited properly
paulo@0 135 if (curCountdown <= 0
paulo@0 136 && (p->state == LJS_NEW_PIECE
paulo@0 137 || p->state == LJS_FALLING
paulo@0 138 || p->state == LJS_LANDED)) {
paulo@0 139 p->state = LJS_GAMEOVER;
paulo@0 140 }
paulo@0 141
paulo@0 142 playSoundEffects(v[player], p->sounds, curCountdown);
paulo@0 143 ctl->countdown = curCountdown;
paulo@0 144
paulo@0 145 // Update speedometer
paulo@0 146 if (p->sounds & LJSND_LOCK) {
paulo@0 147 for (int i = N_SPEED_METER_PIECES - 2; i >= 0; --i) {
paulo@0 148 v[player]->lockTime[i + 1] = v[player]->lockTime[i];
paulo@0 149 }
paulo@0 150 v[player]->lockTime[0] = p->gameTime;
paulo@0 151 if (v[player]->nLockTimes < N_SPEED_METER_PIECES) {
paulo@0 152 ++v[player]->nLockTimes;
paulo@0 153 }
paulo@0 154 v[player]->frontDirty = LJ_DIRTY_SCORE;
paulo@0 155 }
paulo@0 156
paulo@0 157 // If the piece was just spawned, move the trail to the piece's
paulo@0 158 // starting position and redraw next pieces.
paulo@0 159 if (p->sounds & (LJSND_SPAWN | LJSND_HOLD)) {
paulo@0 160 v[player]->trailY = p->y;
paulo@0 161 v[player]->frontDirty |= LJ_DIRTY_NEXT;
paulo@0 162 }
paulo@0 163 }
paulo@0 164
paulo@0 165 ++lastTime;
paulo@0 166 }
paulo@0 167
paulo@0 168 for (unsigned int player = 0; player < nPlayers; ++player) {
paulo@0 169 LJField *const p = v[player]->field;
paulo@0 170 if (p->state == LJS_GAMEOVER && v[player]->hidePF) {
paulo@0 171 v[player]->hidePF = 0;
paulo@0 172 v[player]->backDirty |= (1 << LJ_PF_VIS_HT) - 1;
paulo@0 173 }
paulo@0 174
paulo@0 175 updField(v[player], v[player]->backDirty);
paulo@0 176 v[player]->frontDirty |= v[player]->backDirty;
paulo@0 177 v[player]->backDirty = 0;
paulo@0 178
paulo@0 179 // If piece is falling or landed, and it wasn't just spawned,
paulo@0 180 // draw the piece and its shadow.
paulo@0 181
paulo@0 182 if (p->sounds & (LJSND_SPAWN | LJSND_HOLD)) {
paulo@0 183 // piece was just spawned, so don't draw the piece
paulo@0 184 }
paulo@0 185 // Otherwise, if the piece is falling or landed, draw it.
paulo@0 186 else if (p->state == LJS_FALLING || p->state == LJS_LANDED
paulo@0 187 || p->sounds & LJSND_LOCK) {
paulo@0 188 if (v[player]->hideShadow != LJSHADOW_NO_FALLING) {
paulo@0 189 if (p->state == LJS_FALLING && v[player]->hideShadow < LJSHADOW_NONE) {
paulo@0 190 drawShadow(v[player]);
paulo@0 191 }
paulo@0 192 drawFallingPiece(v[player]);
paulo@0 193 }
paulo@0 194 }
paulo@0 195
paulo@0 196 ljBeginDraw(v[player], getTime() - lastTime < 2);
paulo@0 197 drawScore(v[player]);
paulo@0 198 blitField(v[player]);
paulo@0 199 ljEndDraw(v[player]);
paulo@0 200 }
paulo@0 201 }
paulo@0 202
paulo@0 203 #if WITH_REPLAY
paulo@0 204 {
paulo@0 205 int player = 0;
paulo@0 206 if (v[player]->control->replaySrc) {
paulo@0 207 replayClose(v[player]->control->replaySrc);
paulo@0 208 v[player]->control->replaySrc = NULL;
paulo@0 209 }
paulo@0 210 if (v[player]->control->replayDst) {
paulo@0 211 replayClose(v[player]->control->replayDst);
paulo@0 212 v[player]->control->replayDst = NULL;
paulo@0 213 }
paulo@0 214 }
paulo@0 215 #endif
paulo@0 216 }