Mercurial > hg > index.fcgi > lj > lj046-2players
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 |