comparison src/speed.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:b8d68efd036c
1 /* Speed curve tables for LOCKJAW, an implementation of the Soviet Mind Game
2
3 Copyright (C) 2006-2007 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, Elorg,
21 or The Tetris Company LLC.
22
23 */
24 #include "lj.h"
25 #include "ljcontrol.h"
26
27 static const LJFixed initialGravity[LJSPD_N_CURVES] = {
28 [LJSPD_RHYTHMZERO] = 0,
29 [LJSPD_RHYTHM] = LJITOFIX(20)
30 };
31
32 /**
33 * The default speed curve for each gimmick. A negative value
34 * means that the gimmick uses the player's chosen speed curve.
35 */
36 static const signed char defaultSpeedCurve[LJGM_N_GIMMICKS] = {
37 [LJGM_ATYPE] = -1,
38 [LJGM_BTYPE] = -1,
39 [LJGM_ULTRA] = -1,
40 [LJGM_DRILL] = -1,
41 [LJGM_ITEMS] = -1,
42 [LJGM_BABY] = LJSPD_ZERO
43 };
44
45 /* The new speed curve code ****************************************/
46
47 #define SCGRAV(n, d) ((n) * 2048 / (d))
48
49 enum {
50 SPEEDTYPE_RHYTHM,
51 SPEEDTYPE_TGM,
52 SPEEDTYPE_LINES,
53 SPEEDTYPE_PIECES
54 };
55
56 typedef struct LJSpeedStep {
57 unsigned short level, gravity;
58 signed char are, das, lock, line;
59 } LJSpeedStep;
60
61 typedef struct LJSpeedCurve {
62 char name[32];
63 unsigned char type, sectionLen;
64 unsigned char nSteps;
65 const LJSpeedStep steps[];
66 } LJSpeedCurve;
67
68 const LJSpeedCurve scMaster = {
69 "Master",
70 SPEEDTYPE_TGM, 100,
71 33,
72 {
73 { 0, SCGRAV( 4,256),25,16,30,40},
74 { 30, SCGRAV( 6,256),25,16,30,40},
75 { 35, SCGRAV( 8,256),25,16,30,40},
76 { 40, SCGRAV( 10,256),25,16,30,40},
77 { 50, SCGRAV( 12,256),25,16,30,40},
78 { 60, SCGRAV( 16,256),25,16,30,40},
79 { 70, SCGRAV( 32,256),25,16,30,40},
80 { 80, SCGRAV( 48,256),25,16,30,40},
81 { 90, SCGRAV( 64,256),25,16,30,40},
82 {100, SCGRAV( 80,256),25,16,30,40},
83 {120, SCGRAV( 96,256),25,16,30,40},
84 {140, SCGRAV(112,256),25,16,30,40},
85 {160, SCGRAV(128,256),25,16,30,40},
86 {170, SCGRAV(144,256),25,16,30,40},
87 {200, SCGRAV( 4,256),25,16,30,40},
88 {220, SCGRAV( 32,256),25,16,30,40},
89 {230, SCGRAV( 64,256),25,16,30,40},
90 {233, SCGRAV( 96,256),25,16,30,40},
91 {236, SCGRAV(128,256),25,16,30,40},
92 {239, SCGRAV(160,256),25,16,30,40},
93 {243, SCGRAV(192,256),25,16,30,40},
94 {247, SCGRAV(224,256),25,16,30,40},
95 {251, SCGRAV( 1,1), 25,16,30,40},
96 {300, SCGRAV( 2,1), 25,16,30,40},
97 {330, SCGRAV( 3,1), 25,16,30,40},
98 {360, SCGRAV( 4,1), 25,16,30,40},
99 {400, SCGRAV( 5,1), 25,16,30,40},
100 {450, SCGRAV( 3,1), 25,16,30,40},
101 {500, SCGRAV(20,1), 25,10,30,25},
102 {600, SCGRAV(20,1), 25,10,30,16},
103 {700, SCGRAV(20,1), 16,10,30,12},
104 {800, SCGRAV(20,1), 12,10,30, 6},
105 {900, SCGRAV(20,1), 12, 8,17, 6}
106 }
107 };
108
109 const LJSpeedCurve scDeath = {
110 "Death",
111 SPEEDTYPE_TGM, 100,
112 6,
113 {
114 { 0, SCGRAV(20,1), 18,12,30, 8},
115 {100, SCGRAV(20,1), 14,12,26, 0},
116 {200, SCGRAV(20,1), 14,11,22, 0},
117 {300, SCGRAV(20,1), 8,10,18, 6},
118 {400, SCGRAV(20,1), 7, 8,15, 5},
119 {500, SCGRAV(20,1), 6, 8,15, 4}
120 }
121 };
122
123 const LJSpeedCurve scNES = {
124 "NES",
125 SPEEDTYPE_LINES, 10,
126 15,
127 {
128 { 0, SCGRAV(1,48), 10,-1, 0,30},
129 { 10, SCGRAV(1,43), 10,-1, 0,30},
130 { 20, SCGRAV(1,38), 10,-1, 0,30},
131 { 30, SCGRAV(1,33), 10,-1, 0,30},
132 { 40, SCGRAV(1,28), 10,-1, 0,30},
133 { 50, SCGRAV(1,23), 10,-1, 0,30},
134 { 60, SCGRAV(1,18), 10,-1, 0,30},
135 { 70, SCGRAV(1,13), 10,-1, 0,30},
136 { 80, SCGRAV(1, 8), 10,-1, 0,30},
137 { 90, SCGRAV(1, 6), 10,-1, 0,30},
138 {100, SCGRAV(1, 5), 10,-1, 0,30},
139 {130, SCGRAV(1, 4), 10,-1, 0,30},
140 {160, SCGRAV(1, 3), 10,-1, 0,30},
141 {190, SCGRAV(1, 2), 10,-1, 0,30},
142 {290, SCGRAV(1, 1), 10,-1, 0,30},
143 }
144 };
145
146 const LJSpeedCurve scGB = {
147 "Game Boy",
148 SPEEDTYPE_LINES, 10,
149 18,
150 {
151 { 0, SCGRAV(1,53), 0,-1, 0,90},
152 { 10, SCGRAV(1,49), 0,-1, 0,90},
153 { 20, SCGRAV(1,45), 0,-1, 0,90},
154 { 30, SCGRAV(1,41), 0,-1, 0,90},
155 { 40, SCGRAV(1,37), 0,-1, 0,90},
156 { 50, SCGRAV(1,33), 0,-1, 0,90},
157 { 60, SCGRAV(1,28), 0,-1, 0,90},
158 { 70, SCGRAV(1,22), 0,-1, 0,90},
159 { 80, SCGRAV(1,17), 0,-1, 0,90},
160 { 90, SCGRAV(1,11), 0,-1, 0,90},
161 {100, SCGRAV(1,10), 0,-1, 0,90},
162 {110, SCGRAV(1, 9), 0,-1, 0,90},
163 {120, SCGRAV(1, 8), 0,-1, 0,90},
164 {130, SCGRAV(1, 7), 0,-1, 0,90},
165 {140, SCGRAV(1, 6), 0,-1, 0,90},
166 {160, SCGRAV(1, 5), 0,-1, 0,90},
167 {180, SCGRAV(1, 4), 0,-1, 0,90},
168 {200, SCGRAV(1, 3), 0,-1, 0,90},
169 }
170 };
171
172 const LJSpeedCurve scZero = {
173 "Zero",
174 SPEEDTYPE_LINES, 10,
175 1,
176 {
177 { 0, SCGRAV(0, 1),-1,-1,40,-1}
178 }
179 };
180
181 const LJSpeedCurve scExponential = {
182 "Exponential",
183 SPEEDTYPE_PIECES, 60,
184 34,
185 {
186 { 0, SCGRAV( 1,60),-1,-1,40,-1 },
187 { 30, SCGRAV( 1,42),-1,-1,40,-1 },
188 { 60, SCGRAV( 2,60),-1,-1,40,-1 },
189 { 90, SCGRAV( 2,42),-1,-1,40,-1 },
190 {120, SCGRAV( 4,60),-1,-1,40,-1 },
191 {150, SCGRAV( 4,42),-1,-1,40,-1 },
192 {180, SCGRAV( 8,60),-1,-1,40,-1 },
193 {210, SCGRAV( 8,42),-1,-1,40,-1 },
194 {240, SCGRAV( 16,60),-1,-1,40,-1 },
195 {270, SCGRAV( 16,42),-1,-1,40,-1 },
196 {300, SCGRAV( 32,60),-1,-1,40,-1 },
197 {330, SCGRAV( 32,42),-1,-1,40,-1 },
198 {360, SCGRAV( 64,60),-1,-1,40,-1 },
199 {390, SCGRAV( 64,42),-1,-1,40,-1 },
200 {420, SCGRAV(128,60),-1,-1,40,-1 },
201 {450, SCGRAV(128,42),-1,-1,40,-1 },
202 {480, SCGRAV(256,60),-1,-1,40,-1 },
203 {510, SCGRAV(256,42),-1,-1,40,-1 },
204 {540, SCGRAV(512,60),-1,-1,40,-1 },
205 {570, SCGRAV(512,42),-1,-1,40,-1 },
206 {600, SCGRAV( 20, 1),-1,-1,40,-1 },
207 {630, SCGRAV( 20, 1),-1,-1,30,-1 },
208 {660, SCGRAV( 20, 1),-1,-1,24,-1 },
209 {690, SCGRAV( 20, 1),-1,-1,20,-1 },
210 {720, SCGRAV( 20, 1),-1,-1,17,-1 },
211 {750, SCGRAV( 20, 1),-1,-1,15,-1 },
212 {780, SCGRAV( 20, 1),-1,-1,13,-1 },
213 {810, SCGRAV( 20, 1),-1,-1,12,-1 },
214 {840, SCGRAV( 20, 1),-1,-1,11,-1 },
215 {870, SCGRAV( 20, 1),-1,-1,10,-1 },
216 {900, SCGRAV( 20, 1),-1,-1, 9,-1 },
217 {930, SCGRAV( 20, 1),-1,-1, 8,-1 },
218 {960, SCGRAV( 20, 1),-1,-1, 7,-1 },
219 {990, SCGRAV( 20, 1),-1,-1, 6,-1 }
220 }
221 };
222
223 static const LJSpeedCurve *const newSpeedCurves[LJSPD_N_CURVES] = {
224 [LJSPD_EXP] = &scExponential,
225 [LJSPD_ZERO] = &scZero,
226 [LJSPD_TGM] = &scMaster,
227 [LJSPD_DEATH] = &scDeath,
228 [LJSPD_DEATH300] = &scDeath,
229 [LJSPD_NES] = &scNES,
230 [LJSPD_GB] = &scGB,
231 [LJSPD_GBHEART] = &scGB,
232 };
233
234 /**
235 * Performs a fast binary search of a speed step table.
236 */
237 static const LJSpeedStep *getSpeedStep(const LJSpeedStep *steps,
238 size_t nSteps, int level) {
239 unsigned int lo = 0;
240 unsigned int hi = nSteps;
241
242 while (hi - lo > 1) {
243 size_t mid = (hi + lo) / 2;
244 unsigned int here = steps[mid].level;
245 if (here == level) {
246 return &(steps[mid]);
247 } else if (here < level) {
248 lo = mid;
249 } else {
250 hi = mid;
251 }
252 }
253 return &(steps[lo]);
254 }
255
256 /**
257 * Updates the level after each piece has retired.
258 * @return nonzero iff a new section has happened
259 */
260 int updLevelAfterPiece(LJField *p) {
261 int curveID = p->speedState.curve;
262 const LJSpeedCurve *curve = newSpeedCurves[curveID];
263 if (!curve) {
264 return 0;
265 }
266 unsigned int sectionLen = curve->sectionLen;
267 unsigned int oldLevel = p->speedState.level;
268 unsigned int oldSection = oldLevel / sectionLen;
269 unsigned int oldSectionPos = oldLevel % sectionLen;
270
271 switch (curve->type) {
272 case SPEEDTYPE_TGM:
273 if (oldSectionPos + 1 >= sectionLen) {
274 return 0;
275 }
276 // otherwise fall through to +1 per piece
277
278 case SPEEDTYPE_PIECES:
279 p->speedState.level = oldLevel + 1;
280 break;
281
282 default:
283 return 0;
284 }
285
286 unsigned int newSection = p->speedState.level / sectionLen;
287 return newSection > oldSection;
288 }
289
290 /**
291 * Updates the level after lines have been cleared.
292 * @return nonzero iff a new section has happened
293 */
294 int updLevelAfterLines(LJField *p, unsigned int nLines) {
295 int curveID = p->speedState.curve;
296 const LJSpeedCurve *curve = newSpeedCurves[curveID];
297 if (!curve) {
298 return 0;
299 }
300 unsigned int sectionLen = curve->sectionLen;
301 unsigned int oldLevel = p->speedState.level;
302 unsigned int oldSection = oldLevel / sectionLen;
303
304 switch (curve->type) {
305 case SPEEDTYPE_TGM:
306 case SPEEDTYPE_LINES:
307 p->speedState.level = oldLevel + nLines;
308 break;
309
310 default:
311 return 0;
312 }
313
314 unsigned int newSection = p->speedState.level / sectionLen;
315 return newSection > oldSection;
316 }
317
318 void setSpeedNew(LJField *p, LJControl *c) {
319 int curveID = p->speedState.curve;
320 const LJSpeedCurve *curve = newSpeedCurves[curveID];
321 if (!curve) {
322 return;
323 }
324 const LJSpeedStep *step =
325 getSpeedStep(curve->steps, curve->nSteps, p->speedState.level);
326
327 p->speed.gravity = step->gravity << 5;
328
329 p->speed.entryDelay = step->are;
330 if (p->speed.entryDelay > p->areStyle) {
331 p->speed.entryDelay = p->areStyle;
332 }
333
334 if (step->das > 0 && c->dasDelay > step->das) {
335 c->dasDelay = step->das;
336 }
337
338 if (p->setLockDelay >= 128) {
339 p->speed.lockDelay = 127;
340 } else if (p->setLockDelay > 0) {
341 p->speed.lockDelay = p->setLockDelay;
342 } else if (step->lock > 0) {
343 p->speed.lockDelay = step->lock;
344 }
345
346 if (p->setLineDelay > 0) {
347 p->speed.lineDelay = p->setLineDelay;
348 } else if (step->line >= 0) {
349 p->speed.lineDelay = step->line;
350 } else {
351 p->speed.lineDelay = p->speed.entryDelay;
352 }
353 }
354
355
356
357 /* Old speed curve system is below this line ***********************/
358
359
360
361 void initSpeed(LJField *p) {
362 if (defaultSpeedCurve[p->gimmick] >= 0) {
363 p->speedState.curve = defaultSpeedCurve[p->gimmick];
364 }
365 p->speed.gravity = initialGravity[p->speedState.curve];
366
367 switch (p->speedState.curve) {
368 case LJSPD_RHYTHM:
369 case LJSPD_RHYTHMZERO:
370 p->speedState.level = 60;
371 p->bpmCounter = 0;
372 p->speedupCounter = 0;
373 break;
374 case LJSPD_TGM:
375 case LJSPD_DEATH:
376 case LJSPD_EXP:
377 p->speedState.level = -1;
378 break;
379 case LJSPD_DEATH300:
380 p->speedState.level = 300;
381 break;
382 case LJSPD_GBHEART:
383 p->speedState.level = 100;
384 break;
385 default:
386 p->speedState.level = 0;
387 break;
388 }
389 }
390
391
392 void setSpeed(LJField *p, LJControl *c) {
393 p->speed.entryDelay = p->areStyle;
394
395 // Default line delay is equal to the entry delay,
396 // but speed curves and setLineDelay can override this
397 p->speed.lineDelay = p->speed.entryDelay;
398 switch (p->speedState.curve) {
399
400 case LJSPD_RHYTHM:
401 case LJSPD_RHYTHMZERO:
402 // If we've already banked five pieces' worth of time,
403 // add 20 points instead of banking another.
404 if (p->bpmCounter <= -18000) {
405 // removed in 0.21 because other curves don't reward for drops
406 // p->score += 20;
407 } else {
408 p->bpmCounter -= 3600; // number of frames per minute
409 }
410 p->speed.lockDelay = 3600 / p->speedState.level;
411 p->speed.gravity = (p->speedState.curve == LJSPD_RHYTHM) ? ljitofix(20) : 0;
412 break;
413
414 default:
415 if (updLevelAfterPiece(p)) {
416 p->sounds |= LJSND_SECTIONUP;
417 }
418 setSpeedNew(p, c);
419 break;
420 }
421
422 if (p->setLockDelay >= 128) {
423 p->speed.lockDelay = 127;
424 } else if (p->setLockDelay > 0) {
425 p->speed.lockDelay = p->setLockDelay;
426 }
427 if (p->setLineDelay > 0) {
428 p->speed.lineDelay = p->setLineDelay;
429 }
430 }
431