Mercurial > hg > index.fcgi > lj > lj046
diff src/speed.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/speed.c Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,431 @@ 1.4 +/* Speed curve tables for LOCKJAW, an implementation of the Soviet Mind Game 1.5 + 1.6 +Copyright (C) 2006-2007 Damian Yerrick <tepples+lj@spamcop.net> 1.7 + 1.8 +This work is free software; you can redistribute it and/or modify 1.9 +it under the terms of the GNU General Public License as published by 1.10 +the Free Software Foundation; either version 2 of the License, or 1.11 +(at your option) any later version. 1.12 + 1.13 +This program is distributed in the hope that it will be useful, 1.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 1.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.16 +GNU General Public License for more details. 1.17 + 1.18 +You should have received a copy of the GNU General Public License 1.19 +along with this program; if not, write to the Free Software 1.20 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.21 + 1.22 +Original game concept and design by Alexey Pajitnov. 1.23 +The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, 1.24 +or The Tetris Company LLC. 1.25 + 1.26 +*/ 1.27 +#include "lj.h" 1.28 +#include "ljcontrol.h" 1.29 + 1.30 +static const LJFixed initialGravity[LJSPD_N_CURVES] = { 1.31 + [LJSPD_RHYTHMZERO] = 0, 1.32 + [LJSPD_RHYTHM] = LJITOFIX(20) 1.33 +}; 1.34 + 1.35 +/** 1.36 + * The default speed curve for each gimmick. A negative value 1.37 + * means that the gimmick uses the player's chosen speed curve. 1.38 + */ 1.39 +static const signed char defaultSpeedCurve[LJGM_N_GIMMICKS] = { 1.40 + [LJGM_ATYPE] = -1, 1.41 + [LJGM_BTYPE] = -1, 1.42 + [LJGM_ULTRA] = -1, 1.43 + [LJGM_DRILL] = -1, 1.44 + [LJGM_ITEMS] = -1, 1.45 + [LJGM_BABY] = LJSPD_ZERO 1.46 +}; 1.47 + 1.48 +/* The new speed curve code ****************************************/ 1.49 + 1.50 +#define SCGRAV(n, d) ((n) * 2048 / (d)) 1.51 + 1.52 +enum { 1.53 + SPEEDTYPE_RHYTHM, 1.54 + SPEEDTYPE_TGM, 1.55 + SPEEDTYPE_LINES, 1.56 + SPEEDTYPE_PIECES 1.57 +}; 1.58 + 1.59 +typedef struct LJSpeedStep { 1.60 + unsigned short level, gravity; 1.61 + signed char are, das, lock, line; 1.62 +} LJSpeedStep; 1.63 + 1.64 +typedef struct LJSpeedCurve { 1.65 + char name[32]; 1.66 + unsigned char type, sectionLen; 1.67 + unsigned char nSteps; 1.68 + const LJSpeedStep steps[]; 1.69 +} LJSpeedCurve; 1.70 + 1.71 +const LJSpeedCurve scMaster = { 1.72 + "Master", 1.73 + SPEEDTYPE_TGM, 100, 1.74 + 33, 1.75 + { 1.76 + { 0, SCGRAV( 4,256),25,16,30,40}, 1.77 + { 30, SCGRAV( 6,256),25,16,30,40}, 1.78 + { 35, SCGRAV( 8,256),25,16,30,40}, 1.79 + { 40, SCGRAV( 10,256),25,16,30,40}, 1.80 + { 50, SCGRAV( 12,256),25,16,30,40}, 1.81 + { 60, SCGRAV( 16,256),25,16,30,40}, 1.82 + { 70, SCGRAV( 32,256),25,16,30,40}, 1.83 + { 80, SCGRAV( 48,256),25,16,30,40}, 1.84 + { 90, SCGRAV( 64,256),25,16,30,40}, 1.85 + {100, SCGRAV( 80,256),25,16,30,40}, 1.86 + {120, SCGRAV( 96,256),25,16,30,40}, 1.87 + {140, SCGRAV(112,256),25,16,30,40}, 1.88 + {160, SCGRAV(128,256),25,16,30,40}, 1.89 + {170, SCGRAV(144,256),25,16,30,40}, 1.90 + {200, SCGRAV( 4,256),25,16,30,40}, 1.91 + {220, SCGRAV( 32,256),25,16,30,40}, 1.92 + {230, SCGRAV( 64,256),25,16,30,40}, 1.93 + {233, SCGRAV( 96,256),25,16,30,40}, 1.94 + {236, SCGRAV(128,256),25,16,30,40}, 1.95 + {239, SCGRAV(160,256),25,16,30,40}, 1.96 + {243, SCGRAV(192,256),25,16,30,40}, 1.97 + {247, SCGRAV(224,256),25,16,30,40}, 1.98 + {251, SCGRAV( 1,1), 25,16,30,40}, 1.99 + {300, SCGRAV( 2,1), 25,16,30,40}, 1.100 + {330, SCGRAV( 3,1), 25,16,30,40}, 1.101 + {360, SCGRAV( 4,1), 25,16,30,40}, 1.102 + {400, SCGRAV( 5,1), 25,16,30,40}, 1.103 + {450, SCGRAV( 3,1), 25,16,30,40}, 1.104 + {500, SCGRAV(20,1), 25,10,30,25}, 1.105 + {600, SCGRAV(20,1), 25,10,30,16}, 1.106 + {700, SCGRAV(20,1), 16,10,30,12}, 1.107 + {800, SCGRAV(20,1), 12,10,30, 6}, 1.108 + {900, SCGRAV(20,1), 12, 8,17, 6} 1.109 + } 1.110 +}; 1.111 + 1.112 +const LJSpeedCurve scDeath = { 1.113 + "Death", 1.114 + SPEEDTYPE_TGM, 100, 1.115 + 6, 1.116 + { 1.117 + { 0, SCGRAV(20,1), 18,12,30, 8}, 1.118 + {100, SCGRAV(20,1), 14,12,26, 0}, 1.119 + {200, SCGRAV(20,1), 14,11,22, 0}, 1.120 + {300, SCGRAV(20,1), 8,10,18, 6}, 1.121 + {400, SCGRAV(20,1), 7, 8,15, 5}, 1.122 + {500, SCGRAV(20,1), 6, 8,15, 4} 1.123 + } 1.124 +}; 1.125 + 1.126 +const LJSpeedCurve scNES = { 1.127 + "NES", 1.128 + SPEEDTYPE_LINES, 10, 1.129 + 15, 1.130 + { 1.131 + { 0, SCGRAV(1,48), 10,-1, 0,30}, 1.132 + { 10, SCGRAV(1,43), 10,-1, 0,30}, 1.133 + { 20, SCGRAV(1,38), 10,-1, 0,30}, 1.134 + { 30, SCGRAV(1,33), 10,-1, 0,30}, 1.135 + { 40, SCGRAV(1,28), 10,-1, 0,30}, 1.136 + { 50, SCGRAV(1,23), 10,-1, 0,30}, 1.137 + { 60, SCGRAV(1,18), 10,-1, 0,30}, 1.138 + { 70, SCGRAV(1,13), 10,-1, 0,30}, 1.139 + { 80, SCGRAV(1, 8), 10,-1, 0,30}, 1.140 + { 90, SCGRAV(1, 6), 10,-1, 0,30}, 1.141 + {100, SCGRAV(1, 5), 10,-1, 0,30}, 1.142 + {130, SCGRAV(1, 4), 10,-1, 0,30}, 1.143 + {160, SCGRAV(1, 3), 10,-1, 0,30}, 1.144 + {190, SCGRAV(1, 2), 10,-1, 0,30}, 1.145 + {290, SCGRAV(1, 1), 10,-1, 0,30}, 1.146 + } 1.147 +}; 1.148 + 1.149 +const LJSpeedCurve scGB = { 1.150 + "Game Boy", 1.151 + SPEEDTYPE_LINES, 10, 1.152 + 18, 1.153 + { 1.154 + { 0, SCGRAV(1,53), 0,-1, 0,90}, 1.155 + { 10, SCGRAV(1,49), 0,-1, 0,90}, 1.156 + { 20, SCGRAV(1,45), 0,-1, 0,90}, 1.157 + { 30, SCGRAV(1,41), 0,-1, 0,90}, 1.158 + { 40, SCGRAV(1,37), 0,-1, 0,90}, 1.159 + { 50, SCGRAV(1,33), 0,-1, 0,90}, 1.160 + { 60, SCGRAV(1,28), 0,-1, 0,90}, 1.161 + { 70, SCGRAV(1,22), 0,-1, 0,90}, 1.162 + { 80, SCGRAV(1,17), 0,-1, 0,90}, 1.163 + { 90, SCGRAV(1,11), 0,-1, 0,90}, 1.164 + {100, SCGRAV(1,10), 0,-1, 0,90}, 1.165 + {110, SCGRAV(1, 9), 0,-1, 0,90}, 1.166 + {120, SCGRAV(1, 8), 0,-1, 0,90}, 1.167 + {130, SCGRAV(1, 7), 0,-1, 0,90}, 1.168 + {140, SCGRAV(1, 6), 0,-1, 0,90}, 1.169 + {160, SCGRAV(1, 5), 0,-1, 0,90}, 1.170 + {180, SCGRAV(1, 4), 0,-1, 0,90}, 1.171 + {200, SCGRAV(1, 3), 0,-1, 0,90}, 1.172 + } 1.173 +}; 1.174 + 1.175 +const LJSpeedCurve scZero = { 1.176 + "Zero", 1.177 + SPEEDTYPE_LINES, 10, 1.178 + 1, 1.179 + { 1.180 + { 0, SCGRAV(0, 1),-1,-1,40,-1} 1.181 + } 1.182 +}; 1.183 + 1.184 +const LJSpeedCurve scExponential = { 1.185 + "Exponential", 1.186 + SPEEDTYPE_PIECES, 60, 1.187 + 34, 1.188 + { 1.189 + { 0, SCGRAV( 1,60),-1,-1,40,-1 }, 1.190 + { 30, SCGRAV( 1,42),-1,-1,40,-1 }, 1.191 + { 60, SCGRAV( 2,60),-1,-1,40,-1 }, 1.192 + { 90, SCGRAV( 2,42),-1,-1,40,-1 }, 1.193 + {120, SCGRAV( 4,60),-1,-1,40,-1 }, 1.194 + {150, SCGRAV( 4,42),-1,-1,40,-1 }, 1.195 + {180, SCGRAV( 8,60),-1,-1,40,-1 }, 1.196 + {210, SCGRAV( 8,42),-1,-1,40,-1 }, 1.197 + {240, SCGRAV( 16,60),-1,-1,40,-1 }, 1.198 + {270, SCGRAV( 16,42),-1,-1,40,-1 }, 1.199 + {300, SCGRAV( 32,60),-1,-1,40,-1 }, 1.200 + {330, SCGRAV( 32,42),-1,-1,40,-1 }, 1.201 + {360, SCGRAV( 64,60),-1,-1,40,-1 }, 1.202 + {390, SCGRAV( 64,42),-1,-1,40,-1 }, 1.203 + {420, SCGRAV(128,60),-1,-1,40,-1 }, 1.204 + {450, SCGRAV(128,42),-1,-1,40,-1 }, 1.205 + {480, SCGRAV(256,60),-1,-1,40,-1 }, 1.206 + {510, SCGRAV(256,42),-1,-1,40,-1 }, 1.207 + {540, SCGRAV(512,60),-1,-1,40,-1 }, 1.208 + {570, SCGRAV(512,42),-1,-1,40,-1 }, 1.209 + {600, SCGRAV( 20, 1),-1,-1,40,-1 }, 1.210 + {630, SCGRAV( 20, 1),-1,-1,30,-1 }, 1.211 + {660, SCGRAV( 20, 1),-1,-1,24,-1 }, 1.212 + {690, SCGRAV( 20, 1),-1,-1,20,-1 }, 1.213 + {720, SCGRAV( 20, 1),-1,-1,17,-1 }, 1.214 + {750, SCGRAV( 20, 1),-1,-1,15,-1 }, 1.215 + {780, SCGRAV( 20, 1),-1,-1,13,-1 }, 1.216 + {810, SCGRAV( 20, 1),-1,-1,12,-1 }, 1.217 + {840, SCGRAV( 20, 1),-1,-1,11,-1 }, 1.218 + {870, SCGRAV( 20, 1),-1,-1,10,-1 }, 1.219 + {900, SCGRAV( 20, 1),-1,-1, 9,-1 }, 1.220 + {930, SCGRAV( 20, 1),-1,-1, 8,-1 }, 1.221 + {960, SCGRAV( 20, 1),-1,-1, 7,-1 }, 1.222 + {990, SCGRAV( 20, 1),-1,-1, 6,-1 } 1.223 + } 1.224 +}; 1.225 + 1.226 +static const LJSpeedCurve *const newSpeedCurves[LJSPD_N_CURVES] = { 1.227 + [LJSPD_EXP] = &scExponential, 1.228 + [LJSPD_ZERO] = &scZero, 1.229 + [LJSPD_TGM] = &scMaster, 1.230 + [LJSPD_DEATH] = &scDeath, 1.231 + [LJSPD_DEATH300] = &scDeath, 1.232 + [LJSPD_NES] = &scNES, 1.233 + [LJSPD_GB] = &scGB, 1.234 + [LJSPD_GBHEART] = &scGB, 1.235 +}; 1.236 + 1.237 +/** 1.238 + * Performs a fast binary search of a speed step table. 1.239 + */ 1.240 +static const LJSpeedStep *getSpeedStep(const LJSpeedStep *steps, 1.241 + size_t nSteps, int level) { 1.242 + unsigned int lo = 0; 1.243 + unsigned int hi = nSteps; 1.244 + 1.245 + while (hi - lo > 1) { 1.246 + size_t mid = (hi + lo) / 2; 1.247 + unsigned int here = steps[mid].level; 1.248 + if (here == level) { 1.249 + return &(steps[mid]); 1.250 + } else if (here < level) { 1.251 + lo = mid; 1.252 + } else { 1.253 + hi = mid; 1.254 + } 1.255 + } 1.256 + return &(steps[lo]); 1.257 +} 1.258 + 1.259 +/** 1.260 + * Updates the level after each piece has retired. 1.261 + * @return nonzero iff a new section has happened 1.262 + */ 1.263 +int updLevelAfterPiece(LJField *p) { 1.264 + int curveID = p->speedState.curve; 1.265 + const LJSpeedCurve *curve = newSpeedCurves[curveID]; 1.266 + if (!curve) { 1.267 + return 0; 1.268 + } 1.269 + unsigned int sectionLen = curve->sectionLen; 1.270 + unsigned int oldLevel = p->speedState.level; 1.271 + unsigned int oldSection = oldLevel / sectionLen; 1.272 + unsigned int oldSectionPos = oldLevel % sectionLen; 1.273 + 1.274 + switch (curve->type) { 1.275 + case SPEEDTYPE_TGM: 1.276 + if (oldSectionPos + 1 >= sectionLen) { 1.277 + return 0; 1.278 + } 1.279 + // otherwise fall through to +1 per piece 1.280 + 1.281 + case SPEEDTYPE_PIECES: 1.282 + p->speedState.level = oldLevel + 1; 1.283 + break; 1.284 + 1.285 + default: 1.286 + return 0; 1.287 + } 1.288 + 1.289 + unsigned int newSection = p->speedState.level / sectionLen; 1.290 + return newSection > oldSection; 1.291 +} 1.292 + 1.293 +/** 1.294 + * Updates the level after lines have been cleared. 1.295 + * @return nonzero iff a new section has happened 1.296 + */ 1.297 +int updLevelAfterLines(LJField *p, unsigned int nLines) { 1.298 + int curveID = p->speedState.curve; 1.299 + const LJSpeedCurve *curve = newSpeedCurves[curveID]; 1.300 + if (!curve) { 1.301 + return 0; 1.302 + } 1.303 + unsigned int sectionLen = curve->sectionLen; 1.304 + unsigned int oldLevel = p->speedState.level; 1.305 + unsigned int oldSection = oldLevel / sectionLen; 1.306 + 1.307 + switch (curve->type) { 1.308 + case SPEEDTYPE_TGM: 1.309 + case SPEEDTYPE_LINES: 1.310 + p->speedState.level = oldLevel + nLines; 1.311 + break; 1.312 + 1.313 + default: 1.314 + return 0; 1.315 + } 1.316 + 1.317 + unsigned int newSection = p->speedState.level / sectionLen; 1.318 + return newSection > oldSection; 1.319 +} 1.320 + 1.321 +void setSpeedNew(LJField *p, LJControl *c) { 1.322 + int curveID = p->speedState.curve; 1.323 + const LJSpeedCurve *curve = newSpeedCurves[curveID]; 1.324 + if (!curve) { 1.325 + return; 1.326 + } 1.327 + const LJSpeedStep *step = 1.328 + getSpeedStep(curve->steps, curve->nSteps, p->speedState.level); 1.329 + 1.330 + p->speed.gravity = step->gravity << 5; 1.331 + 1.332 + p->speed.entryDelay = step->are; 1.333 + if (p->speed.entryDelay > p->areStyle) { 1.334 + p->speed.entryDelay = p->areStyle; 1.335 + } 1.336 + 1.337 + if (step->das > 0 && c->dasDelay > step->das) { 1.338 + c->dasDelay = step->das; 1.339 + } 1.340 + 1.341 + if (p->setLockDelay >= 128) { 1.342 + p->speed.lockDelay = 127; 1.343 + } else if (p->setLockDelay > 0) { 1.344 + p->speed.lockDelay = p->setLockDelay; 1.345 + } else if (step->lock > 0) { 1.346 + p->speed.lockDelay = step->lock; 1.347 + } 1.348 + 1.349 + if (p->setLineDelay > 0) { 1.350 + p->speed.lineDelay = p->setLineDelay; 1.351 + } else if (step->line >= 0) { 1.352 + p->speed.lineDelay = step->line; 1.353 + } else { 1.354 + p->speed.lineDelay = p->speed.entryDelay; 1.355 + } 1.356 +} 1.357 + 1.358 + 1.359 + 1.360 +/* Old speed curve system is below this line ***********************/ 1.361 + 1.362 + 1.363 + 1.364 +void initSpeed(LJField *p) { 1.365 + if (defaultSpeedCurve[p->gimmick] >= 0) { 1.366 + p->speedState.curve = defaultSpeedCurve[p->gimmick]; 1.367 + } 1.368 + p->speed.gravity = initialGravity[p->speedState.curve]; 1.369 + 1.370 + switch (p->speedState.curve) { 1.371 + case LJSPD_RHYTHM: 1.372 + case LJSPD_RHYTHMZERO: 1.373 + p->speedState.level = 60; 1.374 + p->bpmCounter = 0; 1.375 + p->speedupCounter = 0; 1.376 + break; 1.377 + case LJSPD_TGM: 1.378 + case LJSPD_DEATH: 1.379 + case LJSPD_EXP: 1.380 + p->speedState.level = -1; 1.381 + break; 1.382 + case LJSPD_DEATH300: 1.383 + p->speedState.level = 300; 1.384 + break; 1.385 + case LJSPD_GBHEART: 1.386 + p->speedState.level = 100; 1.387 + break; 1.388 + default: 1.389 + p->speedState.level = 0; 1.390 + break; 1.391 + } 1.392 +} 1.393 + 1.394 + 1.395 +void setSpeed(LJField *p, LJControl *c) { 1.396 + p->speed.entryDelay = p->areStyle; 1.397 + 1.398 + // Default line delay is equal to the entry delay, 1.399 + // but speed curves and setLineDelay can override this 1.400 + p->speed.lineDelay = p->speed.entryDelay; 1.401 + switch (p->speedState.curve) { 1.402 + 1.403 + case LJSPD_RHYTHM: 1.404 + case LJSPD_RHYTHMZERO: 1.405 + // If we've already banked five pieces' worth of time, 1.406 + // add 20 points instead of banking another. 1.407 + if (p->bpmCounter <= -18000) { 1.408 + // removed in 0.21 because other curves don't reward for drops 1.409 + // p->score += 20; 1.410 + } else { 1.411 + p->bpmCounter -= 3600; // number of frames per minute 1.412 + } 1.413 + p->speed.lockDelay = 3600 / p->speedState.level; 1.414 + p->speed.gravity = (p->speedState.curve == LJSPD_RHYTHM) ? ljitofix(20) : 0; 1.415 + break; 1.416 + 1.417 + default: 1.418 + if (updLevelAfterPiece(p)) { 1.419 + p->sounds |= LJSND_SECTIONUP; 1.420 + } 1.421 + setSpeedNew(p, c); 1.422 + break; 1.423 + } 1.424 + 1.425 + if (p->setLockDelay >= 128) { 1.426 + p->speed.lockDelay = 127; 1.427 + } else if (p->setLockDelay > 0) { 1.428 + p->speed.lockDelay = p->setLockDelay; 1.429 + } 1.430 + if (p->setLineDelay > 0) { 1.431 + p->speed.lineDelay = p->setLineDelay; 1.432 + } 1.433 +} 1.434 +