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 }
|