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 +