Mercurial > hg > index.fcgi > lj > lj046
comparison src/ljplay.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c238b868767a |
---|---|
1 /* Game loop frontend for LOCKJAW, an implementation of the Soviet Mind Game | |
2 | |
3 Copyright (C) 2006 Damian Yerrick <tepples+lj@spamcop.net> | |
4 | |
5 This work is free software; you can redistribute it and/or modify | |
6 it under the terms of the GNU General Public License as published by | |
7 the Free Software Foundation; either version 2 of the License, or | |
8 (at your option) any later version. | |
9 | |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
16 along with this program; if not, write to the Free Software | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 Original game concept and design by Alexey Pajitnov. | |
20 The Software is not sponsored or endorsed by Alexey Pajitnov[player], Elorg, | |
21 or The Tetris Company LLC. | |
22 | |
23 */ | |
24 | |
25 #include "ljplay.h" | |
26 #ifndef WITH_REPLAY | |
27 #define WITH_REPLAY 0 | |
28 #endif | |
29 | |
30 #if WITH_REPLAY | |
31 #include "ljreplay.h" | |
32 extern const char demoFilename[]; | |
33 | |
34 #endif | |
35 | |
36 | |
37 void play(LJView *const v[], size_t nPlayers) { | |
38 int canceled = 0; | |
39 | |
40 for (unsigned int player = 0; player < nPlayers; ++player) { | |
41 LJField *const p = v[player]->field; | |
42 LJControl *const ctl = v[player]->control; | |
43 | |
44 ctl->countdown = 6; | |
45 ctl->presses = 0; | |
46 | |
47 /* Load replay if needed */ | |
48 #if WITH_REPLAY | |
49 if (p->gimmick < 0) { | |
50 ctl->replaySrc = openReplay(demoFilename, p); | |
51 if (!ctl->replaySrc) { | |
52 return; | |
53 } | |
54 v[player]->backDirty = ~0; | |
55 playRedrawScreen(v[player]); | |
56 } else { | |
57 ctl->replaySrc = 0; | |
58 } | |
59 #endif | |
60 } | |
61 if (!v[0]->control->replaySrc) { | |
62 for (unsigned int player = 0; player < nPlayers; ++player) { | |
63 LJField *const p = v[player]->field; | |
64 newGame(p); | |
65 initGimmicks(p); | |
66 v[player]->nLockTimes = 0; | |
67 v[player]->hideNext = 0; | |
68 updField(v[player], ~0); | |
69 } | |
70 startingAnimation(v[0]); | |
71 for (unsigned int player = 0; player < nPlayers; ++player) { | |
72 v[player]->control->lastKeys = 0; | |
73 v[player]->control->repressKeys = 0; | |
74 blitField(v[player]); | |
75 } | |
76 } | |
77 | |
78 int lastTime = getTime(); | |
79 | |
80 while(v[0]->field->state != LJS_GAMEOVER && !canceled) { | |
81 if (getTime() == lastTime) { | |
82 yieldCPU(); | |
83 } | |
84 canceled |= ljHandleConsoleButtons(v[0]); | |
85 while (getTime() - lastTime > 0) { | |
86 for (unsigned int player = 0; player < nPlayers; ++player) { | |
87 LJField *const p = v[player]->field; | |
88 LJControl *const ctl = v[player]->control; | |
89 LJInput in = {0, 0, 0, 0}; | |
90 int curTime = getTime(); | |
91 | |
92 addKeysToInput(&in, readPad(player), p, ctl); | |
93 | |
94 // when returning from pause, catch up the speed control | |
95 if (curTime - lastTime > 10 | |
96 || curTime - lastTime < -10) { | |
97 lastTime = curTime; | |
98 } | |
99 | |
100 { | |
101 int irsAttempted = (p->sounds & (LJSND_SPAWN | LJSND_HOLD)) | |
102 && in.rotation && ctl->initialRotate; | |
103 | |
104 // The next line does ALL the game logic. | |
105 LJBits updatedRows = frame(p, &in) | gimmicks(p, ctl); | |
106 | |
107 v[player]->backDirty |= updatedRows; | |
108 if (irsAttempted && (p->sounds & LJSND_ROTATE)) { | |
109 p->sounds |= LJSND_IRS; | |
110 } | |
111 } | |
112 | |
113 // items is a partly view-based gimmick | |
114 if (p->gimmick == LJGM_ITEMS && (p->sounds & LJSND_SPAWN)) { | |
115 v[player]->hideNext = (v[player]->field->nPieces > 7); | |
116 v[player]->frontDirty |= LJ_DIRTY_NEXT; | |
117 } | |
118 | |
119 // five, four, three, two, one | |
120 int curCountdown = ctl->countdown; | |
121 if (p->gimmick == LJGM_ULTRA && p->gameTime >= 10500) { | |
122 curCountdown = (int)(10859 - p->gameTime) / 60; | |
123 } else if (p->gimmick == LJGM_BTYPE) { | |
124 curCountdown = 40 - p->lines; | |
125 } else if (p->gimmick == LJGM_BABY) { | |
126 curCountdown = (309 - v[player]->control->presses) / 10; | |
127 } else if (p->gimmick == LJGM_DRILL && (p->sounds & LJSND_LINE)) { | |
128 int line = bfffo(p->tempRows); | |
129 if (line < curCountdown) | |
130 curCountdown = line; | |
131 } | |
132 | |
133 // we have to wait for the new piece to come out | |
134 // so that the score is credited properly | |
135 if (curCountdown <= 0 | |
136 && (p->state == LJS_NEW_PIECE | |
137 || p->state == LJS_FALLING | |
138 || p->state == LJS_LANDED)) { | |
139 p->state = LJS_GAMEOVER; | |
140 } | |
141 | |
142 playSoundEffects(v[player], p->sounds, curCountdown); | |
143 ctl->countdown = curCountdown; | |
144 | |
145 // Update speedometer | |
146 if (p->sounds & LJSND_LOCK) { | |
147 for (int i = N_SPEED_METER_PIECES - 2; i >= 0; --i) { | |
148 v[player]->lockTime[i + 1] = v[player]->lockTime[i]; | |
149 } | |
150 v[player]->lockTime[0] = p->gameTime; | |
151 if (v[player]->nLockTimes < N_SPEED_METER_PIECES) { | |
152 ++v[player]->nLockTimes; | |
153 } | |
154 v[player]->frontDirty = LJ_DIRTY_SCORE; | |
155 } | |
156 | |
157 // If the piece was just spawned, move the trail to the piece's | |
158 // starting position and redraw next pieces. | |
159 if (p->sounds & (LJSND_SPAWN | LJSND_HOLD)) { | |
160 v[player]->trailY = p->y; | |
161 v[player]->frontDirty |= LJ_DIRTY_NEXT; | |
162 } | |
163 } | |
164 | |
165 ++lastTime; | |
166 } | |
167 | |
168 for (unsigned int player = 0; player < nPlayers; ++player) { | |
169 LJField *const p = v[player]->field; | |
170 if (p->state == LJS_GAMEOVER && v[player]->hidePF) { | |
171 v[player]->hidePF = 0; | |
172 v[player]->backDirty |= (1 << LJ_PF_VIS_HT) - 1; | |
173 } | |
174 | |
175 updField(v[player], v[player]->backDirty); | |
176 v[player]->frontDirty |= v[player]->backDirty; | |
177 v[player]->backDirty = 0; | |
178 | |
179 // If piece is falling or landed, and it wasn't just spawned, | |
180 // draw the piece and its shadow. | |
181 | |
182 if (p->sounds & (LJSND_SPAWN | LJSND_HOLD)) { | |
183 // piece was just spawned, so don't draw the piece | |
184 } | |
185 // Otherwise, if the piece is falling or landed, draw it. | |
186 else if (p->state == LJS_FALLING || p->state == LJS_LANDED | |
187 || p->sounds & LJSND_LOCK) { | |
188 if (v[player]->hideShadow != LJSHADOW_NO_FALLING) { | |
189 if (p->state == LJS_FALLING && v[player]->hideShadow < LJSHADOW_NONE) { | |
190 drawShadow(v[player]); | |
191 } | |
192 drawFallingPiece(v[player]); | |
193 } | |
194 } | |
195 | |
196 ljBeginDraw(v[player], getTime() - lastTime < 2); | |
197 drawScore(v[player]); | |
198 blitField(v[player]); | |
199 ljEndDraw(v[player]); | |
200 } | |
201 } | |
202 | |
203 #if WITH_REPLAY | |
204 { | |
205 int player = 0; | |
206 if (v[player]->control->replaySrc) { | |
207 replayClose(v[player]->control->replaySrc); | |
208 v[player]->control->replaySrc = NULL; | |
209 } | |
210 if (v[player]->control->replayDst) { | |
211 replayClose(v[player]->control->replayDst); | |
212 v[player]->control->replayDst = NULL; | |
213 } | |
214 } | |
215 #endif | |
216 } |