diff src/options.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/options.c	Fri Mar 13 00:39:12 2009 -0700
     1.3 @@ -0,0 +1,642 @@
     1.4 +/* options code for LOCKJAW, an implementation of the Soviet Mind Game
     1.5 +
     1.6 +Copyright (C) 2007-2008 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 +
    1.28 +
    1.29 +#include <string.h>
    1.30 +#include <stdio.h>
    1.31 +#include "options.h"
    1.32 +#include "ljplay.h"
    1.33 +#include "ljlocale.h"
    1.34 +
    1.35 +#ifdef HAS_FPU
    1.36 +#define siprintf sprintf
    1.37 +#define MIN_SHADOW 0
    1.38 +#define N_SHADOWS LJSHADOW_N_STYLES
    1.39 +#define FACTORY_SHADOW 0
    1.40 +#include "ljpc.h"
    1.41 +#else
    1.42 +#define MIN_SHADOW LJSHADOW_COLORED
    1.43 +#define N_SHADOWS (LJSHADOW_N_STYLES - 2)
    1.44 +#define FACTORY_SHADOW MIN_SHADOW
    1.45 +#endif
    1.46 +
    1.47 +const FourCC optionsBoolNames[2] = {
    1.48 +  {"Off"}, {"On"}
    1.49 +};
    1.50 +
    1.51 +const FourCC gimmickNames[LJGM_N_GIMMICKS] = {
    1.52 +  {"Mara"}, {"Line"}, {"Time"}, {"DrlA"}, {"Item"}, {"Keys"}
    1.53 +};
    1.54 +
    1.55 +const FourCC optionsGarbageNames[LJGARBAGE_N_STYLES] = {
    1.56 +  {"Off"}, {"Lv.1"}, {"Lv.2"}, {"Lv.3"}, {"Lv.4"},
    1.57 +  {"HRD"}, {"DrlG"}, {"Zigz"}
    1.58 +};
    1.59 +
    1.60 +const FourCC optionsScoringNames[LJSCORE_N_STYLES] = {
    1.61 +  {"LJ"}, {"Fibo"}, {"HotL"}, {"TDSl"}, {"NESl"}, {"LJns"}
    1.62 +};
    1.63 +
    1.64 +const FourCC optionsKickLimitNames[N_KICK_LIMITS] = {
    1.65 +  {"Off"}, {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"Inf"}
    1.66 +};
    1.67 +
    1.68 +const FourCC optionsSpeedCurveNames[] = {
    1.69 +  {"Zero"}, {"Rhy0"}, {"Exp"},  {"Rh20"},
    1.70 +  {"TGM2"}, {"TAPD"}, {"TAD3"},
    1.71 +  {"NESc"}, {"GBc"},  {"GBHL"}
    1.72 +};
    1.73 +
    1.74 +static const FourCC optionsWindowedNames[2] = {
    1.75 +  {"FulS"}, {"Wind"}
    1.76 +};
    1.77 +
    1.78 +const FourCC optionsShadowNames[LJSHADOW_N_STYLES] = {
    1.79 +  {"tl25"}, {"tl50"}, {"tlsC"}, {"tlsM"}, {"Off"}, {"invF"}
    1.80 +};
    1.81 +
    1.82 +const FourCC optionsLockDelayNames[2] = {
    1.83 +  {"SBSC"}, {"Inf"}
    1.84 +};
    1.85 +
    1.86 +const FourCC optionsSBSCNames[2] = {
    1.87 +  {"SBSC"}, {.i=0}
    1.88 +};
    1.89 +
    1.90 +const FourCC optionsTspinNames[] = {
    1.91 +  {"Off"}, {"Imob"}, {"CrnT"}, {"WKT"}
    1.92 +};
    1.93 +
    1.94 +const FourCC optionsLockdownNames[] = {
    1.95 +  {"OLD"}, {"EntR"}, {"StpR"}, {"MovR"}
    1.96 +};
    1.97 +
    1.98 +const FourCC optionsHoldStyleNames[] = {
    1.99 +  {"Off"}, {"HldE"}, {"HldR"}, {"HldN"}
   1.100 +};
   1.101 +
   1.102 +const FourCC optionsDropScoringNames[LJDROP_N_STYLES] = {
   1.103 +  {"None"}, {"ConD"}, {"S1H1"}, {"S1H2"}
   1.104 +};
   1.105 +
   1.106 +const FourCC optionsGravNames[] = {
   1.107 +  {"Naiv"}, {"Stky"}, {"byCo"}, {"Casc"}
   1.108 +};
   1.109 +
   1.110 +const FourCC optionsPieceSetNames[LJRAND_N_PIECE_SETS] = {
   1.111 +  {"IJLO"},
   1.112 +  {"JLOT"},
   1.113 +  {"SZSZ"},
   1.114 +  {"IIII"},
   1.115 +  {"AllP"},
   1.116 +  {"TTTT"}
   1.117 +};
   1.118 +
   1.119 +const FourCC optionsRandNames[LJRAND_N_RANDS] = {
   1.120 +  {"Unif"},
   1.121 +  {"Bag"},
   1.122 +  {"Bag+"},
   1.123 +  {"Bag2"},
   1.124 +  {"Hist"},
   1.125 +  {"His6"}
   1.126 +};
   1.127 +
   1.128 +const FourCC optionsLineDelayNames[] = {
   1.129 +  {"SBSC"}, {.i=0}
   1.130 +};
   1.131 +
   1.132 +const FourCC optionsZangiNames[] = {
   1.133 +  {"Slid"}, {"Lock"}, {"LocU"}
   1.134 +};
   1.135 +
   1.136 +const FourCC optionsGluingNames[] = {
   1.137 +  {"Off"}, {"Squ"}, {"Stky"}, {"byCo"}
   1.138 +};
   1.139 +
   1.140 +const FourCC optionsRotNames[N_ROTATION_SYSTEMS] = {
   1.141 +  {"SRS"},  {"Sega"}, {"ARS"},  {"Tngn"},
   1.142 +  {"NRSR"}, {"NRSL"}, {"TOD4"}, {"TDX"}
   1.143 +};
   1.144 +
   1.145 +
   1.146 +const OptionsLine commonOptionsMenu[] = {
   1.147 +  {{"gimm"}, gimmickNames,
   1.148 +    0, LJGM_N_GIMMICKS,       0 },
   1.149 +  {{"pfw"},  NULL,
   1.150 +    4, LJ_PF_WID - 4 + 1,     10 },
   1.151 +  {{"pfh"},  NULL,
   1.152 +    8, LJ_PF_VIS_HT - 8 + 1,  LJ_PF_VIS_HT },
   1.153 +  {{"vzsp"}, optionsBoolNames,
   1.154 +    0, 2,                     1 },
   1.155 +  {{"spdc"}, optionsSpeedCurveNames,
   1.156 +    0, LJSPD_N_CURVES,        LJSPD_EXP },
   1.157 +  {{"are"},  NULL,
   1.158 +    0, 121,                   0, OPTSTYLE_FRAMES },
   1.159 +  {{"piec"}, optionsPieceSetNames,
   1.160 +    0, LJRAND_N_PIECE_SETS,   LJRAND_4BLK },
   1.161 +  {{"rand"}, optionsRandNames,
   1.162 +    0, LJRAND_N_RANDS,        LJRAND_BAG },
   1.163 +
   1.164 +  {{"hold"}, optionsHoldStyleNames,
   1.165 +    0, LJHOLD_N_STYLES,       LJHOLD_EMPTY },
   1.166 +  {{"rots"}, optionsRotNames,
   1.167 +    0, N_ROTATION_SYSTEMS,    0 },
   1.168 +  {{"upkl"}, optionsKickLimitNames,
   1.169 +    0, N_KICK_LIMITS,         N_KICK_LIMITS - 1 },
   1.170 +  {{"lock"}, optionsLockdownNames,
   1.171 +    0, LJLOCK_N_STYLES,       LJLOCK_MOVE },
   1.172 +  {{"sldt"}, optionsLockDelayNames,
   1.173 +    0, 129,                   0, OPTSTYLE_FRAMES },
   1.174 +  {{"deep"}, optionsBoolNames,
   1.175 +    0, 2,                     0 },
   1.176 +
   1.177 +  {{"clrd"}, optionsSBSCNames,
   1.178 +    0, 121,                   0, OPTSTYLE_FRAMES },
   1.179 +  {{"grav"}, optionsGravNames,
   1.180 +    0, LJGRAV_N_ALGOS,        LJGRAV_NAIVE },
   1.181 +  {{"glue"}, optionsGluingNames,
   1.182 +    0, LJGLUING_N_STYLES,     LJGLUING_NONE },
   1.183 +  {{"lsco"}, optionsScoringNames,
   1.184 +    0, LJSCORE_N_STYLES },
   1.185 +  {{"dsco"}, optionsDropScoringNames,
   1.186 +    0, LJDROP_N_STYLES,       0 },
   1.187 +  {{"tspn"}, optionsTspinNames,
   1.188 +    0, LJTS_N_ALGOS,          LJTS_TDS },
   1.189 +  {{"garb"}, optionsGarbageNames,
   1.190 +    0, LJGARBAGE_N_STYLES,    0 },
   1.191 +
   1.192 +  {{"dasd"}, NULL,
   1.193 +    1, 120,                   10, OPTSTYLE_FRAMES },
   1.194 +  {{"dass"}, NULL,
   1.195 +    0, 10,                    1, OPTSTYLE_FRAC_G },
   1.196 +  {{"idas"}, optionsBoolNames,
   1.197 +    0, 2,                     1 },
   1.198 +  {{"irs"},  optionsBoolNames,
   1.199 +    0, 2,                     1 },
   1.200 +  {{"8way"}, optionsBoolNames,
   1.201 +    0, 2,                     0 },
   1.202 +
   1.203 +  {{"sfds"}, NULL,
   1.204 +    1, 3, 1, OPTSTYLE_FRAC_G },
   1.205 +  {{"sfdl"}, optionsZangiNames,
   1.206 +    0, LJZANGI_N_STYLES,      LJZANGI_SLIDE },
   1.207 +  {{"hrdl"}, optionsZangiNames,
   1.208 +    0, LJZANGI_N_STYLES,      LJZANGI_LOCK },
   1.209 +
   1.210 +  {{"tls"},  optionsShadowNames + MIN_SHADOW,
   1.211 +    MIN_SHADOW, N_SHADOWS,    FACTORY_SHADOW },
   1.212 +  {{"invs"}, optionsBoolNames,
   1.213 +    0, 2,                     0 },
   1.214 +  {{"next"}, NULL,
   1.215 +    0, LJ_NEXT_PIECES + 1,    6 },
   1.216 +  {{"srph"}, optionsBoolNames,
   1.217 +    0, 2,                     1 },
   1.218 +
   1.219 +#ifdef HAS_FPU
   1.220 +  {{"inpv"}, NULL,
   1.221 +    0, LJ_NEXT_PIECES + 1,    0 },
   1.222 +  {{"mblr"}, optionsBoolNames,
   1.223 +    0, 2,                     1 },
   1.224 +  {{"lidp"}, optionsBoolNames,
   1.225 +    0, 2,                     1 },
   1.226 +  {{"rec"},  optionsBoolNames,
   1.227 +    0, 2,                     0 },
   1.228 +  {{"wndw"}, optionsWindowedNames,
   1.229 +    0, 2,                     1 }
   1.230 +#endif
   1.231 +};
   1.232 +
   1.233 +const OptionsPage optionsPages[] = {
   1.234 +  {OPTIONS_GIMMICK, "Game"},
   1.235 +  {OPTIONS_WIDTH, "Rules: Well"},
   1.236 +  {OPTIONS_HOLD_PIECE, "Rules: Movement"},
   1.237 +  {OPTIONS_LINE_DELAY, "Rules: Line clear"},
   1.238 +  {OPTIONS_SIDEWAYS_DELAY, "Control: Movement"},
   1.239 +  {OPTIONS_SOFT_DROP_SPEED, "Control: Drop"},
   1.240 +  {OPTIONS_SHADOW, "Display"},
   1.241 +#ifdef HAS_FPU
   1.242 +  {OPTIONS_MENU_LEN, "PC"},
   1.243 +  {PC_OPTIONS_MENU_LEN, NULL}
   1.244 +#else
   1.245 +  {OPTIONS_MENU_LEN, NULL}
   1.246 +#endif
   1.247 +};
   1.248 +
   1.249 +void setOptionsValueToFourCC(char *dst, FourCC f) {
   1.250 +  const char *valueName = ljGetFourCCName(f);
   1.251 +  if (valueName) {
   1.252 +    strncpy(dst,
   1.253 +            valueName,
   1.254 +            OPTIONS_VALUE_LEN - 1);
   1.255 +    dst[OPTIONS_VALUE_LEN - 1] = 0;
   1.256 +  } else {
   1.257 +    strncpy(dst, f.c, 4);
   1.258 +    dst[4] = 0;
   1.259 +  }
   1.260 +}
   1.261 +
   1.262 +struct DisabledOption {
   1.263 +  unsigned char name;
   1.264 +  unsigned char value;
   1.265 +  unsigned char name2;
   1.266 +  char reason[45];
   1.267 +};
   1.268 +
   1.269 +/*
   1.270 +   Semantics:
   1.271 +   If option name is set to value,
   1.272 +   then gray out option name2 and draw its value as reason.
   1.273 +*/
   1.274 +#define N_DISABLED_OPTIONS 12
   1.275 +const struct DisabledOption disabledOptions[N_DISABLED_OPTIONS] = {
   1.276 +  {  OPTIONS_LOCKDOWN,     LJLOCK_NOW,
   1.277 +     OPTIONS_SOFT_DROP, "Lockdown is immediate" },
   1.278 +  {  OPTIONS_LOCKDOWN,     LJLOCK_NOW,
   1.279 +     OPTIONS_HARD_DROP, "Lockdown is immediate" },
   1.280 +  {  OPTIONS_LOCKDOWN,     LJLOCK_NOW,
   1.281 +     OPTIONS_LOCK_DELAY,     "Lockdown is immediate" },
   1.282 +  {  OPTIONS_LOCK_DELAY,     128,
   1.283 +     OPTIONS_LOCKDOWN,     "Lockdown is manual" },
   1.284 +  {  OPTIONS_SPEED_CURVE,    LJSPD_DEATH,
   1.285 +     OPTIONS_SOFT_DROP_SPEED,"Death: pieces land instantly" },
   1.286 +  {  OPTIONS_SPEED_CURVE,    LJSPD_RHYTHM,
   1.287 +     OPTIONS_SOFT_DROP_SPEED,"Rhythm: pieces land instantly" },
   1.288 +  {  OPTIONS_SPEED_CURVE,    LJSPD_DEATH,
   1.289 +     OPTIONS_SMOOTH_GRAVITY, "Death: pieces land instantly" },
   1.290 +  {  OPTIONS_SPEED_CURVE,    LJSPD_RHYTHM,
   1.291 +     OPTIONS_SMOOTH_GRAVITY, "Rhythm: pieces land instantly" },
   1.292 +  {  OPTIONS_SPEED_CURVE,    LJSPD_DEATH,
   1.293 +     OPTIONS_SOFT_DROP,      "Death: pieces land instantly" },
   1.294 +  {  OPTIONS_SPEED_CURVE,    LJSPD_RHYTHM,
   1.295 +     OPTIONS_SOFT_DROP,      "Rhythm: pieces land instantly" },
   1.296 +  {  OPTIONS_SPEED_CURVE,    LJSPD_DEATH,
   1.297 +     OPTIONS_HARD_DROP,      "Death: pieces land instantly" },
   1.298 +  {  OPTIONS_SPEED_CURVE,    LJSPD_RHYTHM,
   1.299 +     OPTIONS_HARD_DROP,      "Rhythm: pieces land instantly" },
   1.300 +};
   1.301 +
   1.302 +const char *isDisabledOption(const unsigned char *prefs, int y) {
   1.303 +  for (int i = 0; i < N_DISABLED_OPTIONS; ++i) {
   1.304 +    if (y == disabledOptions[i].name2) {
   1.305 +      int name = disabledOptions[i].name;
   1.306 +      int value = disabledOptions[i].value;
   1.307 +
   1.308 +      if (prefs[name] == value) {
   1.309 +        return disabledOptions[i].reason;
   1.310 +      }
   1.311 +    }
   1.312 +  }
   1.313 +  return NULL;
   1.314 +}
   1.315 +
   1.316 +
   1.317 +const char *getOptionsValueStr(char *dst, int line, int value) {
   1.318 +  const OptionsLine *l = &(commonOptionsMenu[line]);
   1.319 +  FourCC f = {.i = 0};
   1.320 +  const char *desc = NULL;
   1.321 +
   1.322 +  switch (l->style) {
   1.323 +  case OPTSTYLE_DEFAULT:
   1.324 +    if (l->valueNames) {
   1.325 +      f = l->valueNames[value - l->minValue];
   1.326 +    } else {
   1.327 +      siprintf(dst, "%d", value);
   1.328 +    }
   1.329 +    break;
   1.330 +    
   1.331 +  case OPTSTYLE_FRAMES:
   1.332 +    if (l->valueNames
   1.333 +        && value == l->minValue
   1.334 +        && l->valueNames[0].i) {
   1.335 +        
   1.336 +      // override first with name 0
   1.337 +      f = l->valueNames[0];
   1.338 +    } else if (l->valueNames
   1.339 +                && value == l->minValue
   1.340 +                            + l->nValues - 1
   1.341 +                && l->valueNames[1].i) {
   1.342 +
   1.343 +      // override second with name 1
   1.344 +      f = l->valueNames[1];
   1.345 +    } else {
   1.346 +      if (value >= 60) {
   1.347 +        int ds = value / 6;
   1.348 +        int s = ds / 10;
   1.349 +        ds -= s * 10;
   1.350 +        siprintf(dst, "%d/60 s (%d.%d s)", value, s, ds);
   1.351 +      } else {
   1.352 +        int ms = value * 50 / 3;
   1.353 +        siprintf(dst, "%d/60 s (%d ms)", value, ms);
   1.354 +      }
   1.355 +    } break;
   1.356 +
   1.357 +  case OPTSTYLE_FRAC_G:
   1.358 +    if (value > 6) {
   1.359 +      int dHz = 600 / value;
   1.360 +      int Hz = dHz / 10;
   1.361 +      dHz -= Hz * 10;
   1.362 +      siprintf(dst, "1/%dG (%d.%d Hz)", value, Hz, dHz);
   1.363 +    } else if (value > 0) {
   1.364 +      if (value > 1) {
   1.365 +        dst[0] = '1';
   1.366 +        dst[1] = '/';
   1.367 +        dst += 2;
   1.368 +      }
   1.369 +      siprintf(dst, "%dG (%d Hz)", value, 60 / value);
   1.370 +    } else {
   1.371 +      strcpy(dst, "Instant");
   1.372 +    }
   1.373 +    break;
   1.374 +
   1.375 +  default:
   1.376 +    strncpy(dst, "Unknown option style.", OPTIONS_VALUE_LEN - 1);
   1.377 +    dst[OPTIONS_VALUE_LEN - 1] = 0;
   1.378 +    break;
   1.379 +  }
   1.380 +  
   1.381 +  /* If we have a fourCC, use it. */
   1.382 +  if (f.i != 0) {
   1.383 +    setOptionsValueToFourCC(dst, f);
   1.384 +    desc = ljGetFourCCDesc(f);
   1.385 +  }
   1.386 +  return desc;
   1.387 +}
   1.388 +
   1.389 +void unpackCommonOptions(LJView *v, const unsigned char *prefs) {
   1.390 +  if (prefs[OPTIONS_GIMMICK] < 255)
   1.391 +    v->field->gimmick = prefs[OPTIONS_GIMMICK];
   1.392 +  if (prefs[OPTIONS_WIDTH] < 255) {
   1.393 +    int width = prefs[OPTIONS_WIDTH];
   1.394 +    v->field->leftWall = (LJ_PF_WID - width) / 2;
   1.395 +    v->field->rightWall = v->field->leftWall + width;
   1.396 +  }
   1.397 +  if (prefs[OPTIONS_HEIGHT] < 255)
   1.398 +    v->field->ceiling = prefs[OPTIONS_HEIGHT];
   1.399 +  if (prefs[OPTIONS_ENTER_ABOVE] < 255)
   1.400 +    v->field->enterAbove = prefs[OPTIONS_ENTER_ABOVE];
   1.401 +  if (prefs[OPTIONS_SPEED_CURVE] < 255)
   1.402 +    v->field->speedState.curve = prefs[OPTIONS_SPEED_CURVE];
   1.403 +  if (prefs[OPTIONS_ENTRY_DELAY] < 255)
   1.404 +    v->field->areStyle = prefs[OPTIONS_ENTRY_DELAY];
   1.405 +  if (prefs[OPTIONS_PIECE_SET] < 255)
   1.406 +    v->field->pieceSet = prefs[OPTIONS_PIECE_SET];
   1.407 +  if (prefs[OPTIONS_RANDOMIZER] < 255)
   1.408 +    v->field->randomizer = prefs[OPTIONS_RANDOMIZER];
   1.409 +
   1.410 +  if (prefs[OPTIONS_ROTATION_SYSTEM] < 255)
   1.411 +    v->field->rotationSystem = prefs[OPTIONS_ROTATION_SYSTEM];
   1.412 +  if (prefs[OPTIONS_FLOOR_KICKS] < 255)
   1.413 +    v->field->maxUpwardKicks = prefs[OPTIONS_FLOOR_KICKS] == N_KICK_LIMITS - 1
   1.414 +                               ? 128
   1.415 +                               : prefs[OPTIONS_FLOOR_KICKS];
   1.416 +  if (prefs[OPTIONS_HOLD_PIECE] < 255)
   1.417 +    v->field->holdStyle = prefs[OPTIONS_HOLD_PIECE];
   1.418 +  if (prefs[OPTIONS_LOCKDOWN] < 255)
   1.419 +    v->field->lockReset = prefs[OPTIONS_LOCKDOWN];
   1.420 +  if (prefs[OPTIONS_LOCK_DELAY] < 255)
   1.421 +    v->field->setLockDelay = prefs[OPTIONS_LOCK_DELAY];
   1.422 +  if (prefs[OPTIONS_BOTTOM_BLOCKS] < 255)
   1.423 +    v->field->bottomBlocks = prefs[OPTIONS_BOTTOM_BLOCKS];
   1.424 +
   1.425 +  if (prefs[OPTIONS_LINE_DELAY] < 255)
   1.426 +    v->field->setLineDelay = prefs[OPTIONS_LINE_DELAY];
   1.427 +  if (prefs[OPTIONS_T_SPIN] < 255)
   1.428 +    v->field->tSpinAlgo = prefs[OPTIONS_T_SPIN];
   1.429 +  if (prefs[OPTIONS_CLEAR_GRAVITY] < 255)
   1.430 +    v->field->clearGravity = prefs[OPTIONS_CLEAR_GRAVITY];
   1.431 +  if (prefs[OPTIONS_GLUING] < 255)
   1.432 +    v->field->gluing = prefs[OPTIONS_GLUING];
   1.433 +  if (prefs[OPTIONS_SCORING] < 255)
   1.434 +    v->field->scoreStyle = prefs[OPTIONS_SCORING];
   1.435 +  if (prefs[OPTIONS_DROP_SCORING] < 255)
   1.436 +    v->field->dropScoreStyle = prefs[OPTIONS_DROP_SCORING];
   1.437 +  if (prefs[OPTIONS_GARBAGE] < 255)
   1.438 +    v->field->garbageStyle = prefs[OPTIONS_GARBAGE];
   1.439 +
   1.440 +  if (prefs[OPTIONS_SIDEWAYS_DELAY] < 255)
   1.441 +    v->control->dasDelay = prefs[OPTIONS_SIDEWAYS_DELAY];
   1.442 +  if (prefs[OPTIONS_SIDEWAYS_SPEED] < 255)
   1.443 +    v->control->dasSpeed = prefs[OPTIONS_SIDEWAYS_SPEED];
   1.444 +  if (v->control->dasDelay < v->control->dasSpeed) {
   1.445 +    v->control->dasDelay = v->control->dasSpeed;
   1.446 +  }
   1.447 +  if (prefs[OPTIONS_INITIAL_SIDEWAYS] < 255)
   1.448 +    v->control->initialDAS = prefs[OPTIONS_INITIAL_SIDEWAYS];
   1.449 +  if (prefs[OPTIONS_IRS] < 255)
   1.450 +    v->control->initialRotate = prefs[OPTIONS_IRS];
   1.451 +  if (prefs[OPTIONS_DIAGONAL_MOTION] < 255)
   1.452 +    v->control->allowDiagonals = prefs[OPTIONS_DIAGONAL_MOTION];
   1.453 +  if (prefs[OPTIONS_SOFT_DROP_SPEED] < 255)
   1.454 +    v->control->softDropSpeed  = prefs[OPTIONS_SOFT_DROP_SPEED] - 1;
   1.455 +  if (prefs[OPTIONS_SOFT_DROP] < 255)
   1.456 +    v->control->softDropLock = prefs[OPTIONS_SOFT_DROP];
   1.457 +  if (prefs[OPTIONS_HARD_DROP] < 255)
   1.458 +    v->control->hardDropLock = prefs[OPTIONS_HARD_DROP];
   1.459 +
   1.460 +  if (prefs[OPTIONS_SHADOW] < 255)
   1.461 +    v->hideShadow = prefs[OPTIONS_SHADOW];
   1.462 +  if (prefs[OPTIONS_HIDE_PF] < 255)
   1.463 +    v->hidePF = prefs[OPTIONS_HIDE_PF];
   1.464 +  if (prefs[OPTIONS_NEXT_PIECES] < 255)
   1.465 +    v->nextPieces = prefs[OPTIONS_NEXT_PIECES];
   1.466 +  if (prefs[OPTIONS_SMOOTH_GRAVITY] < 255)
   1.467 +    v->smoothGravity = prefs[OPTIONS_SMOOTH_GRAVITY];
   1.468 +}
   1.469 +
   1.470 +void initOptions(unsigned char *prefs) {
   1.471 +  for (int i = 0; i < OPTIONS_MENU_LEN; ++i) {
   1.472 +    prefs[i] = commonOptionsMenu[i].startValue;
   1.473 +  }
   1.474 +}
   1.475 +
   1.476 +LJBits menuReadPad(void);
   1.477 +void vsync(void);
   1.478 +
   1.479 +void options(LJView *v, unsigned char *prefs) {
   1.480 +  int page = 0, y = 0;
   1.481 +  int redraw = 2;
   1.482 +  int done = 0;
   1.483 +  LJBits lastKeys = ~0;
   1.484 +  int dasDir = 0;
   1.485 +  int dasCounter = 0;
   1.486 +  const OptionsLine const *optionsMenu = commonOptionsMenu;
   1.487 +  int lastClock = getTime();
   1.488 +  int erase = -1;
   1.489 +  
   1.490 +  optionsWinInit();
   1.491 +    
   1.492 +  while (!done) {
   1.493 +    if (redraw) {
   1.494 +      if (redraw == 2) {
   1.495 +        redraw = 1;
   1.496 +        optionsDrawPage(page, prefs);
   1.497 +      }
   1.498 +      if (redraw == 1) {
   1.499 +        if (erase >= 0) {
   1.500 +          vsync();
   1.501 +          optionsDrawRow(prefs,
   1.502 +                         erase - optionsPages[page].start,
   1.503 +                         erase, prefs[erase], 0);
   1.504 +          erase = -1;
   1.505 +        }
   1.506 +        optionsDrawRow(prefs,
   1.507 +                       y - optionsPages[page].start,
   1.508 +                       y, prefs[y], 1);
   1.509 +        redraw = 0;
   1.510 +      }
   1.511 +    } else {
   1.512 +      optionsIdle();
   1.513 +    }
   1.514 +    
   1.515 +    LJBits keys = menuReadPad();
   1.516 +    LJBits sounds = 0;
   1.517 +    int lastY = y;
   1.518 +    LJBits newKeys = keys & ~lastKeys;
   1.519 +    LJBits dasKeys = 0;
   1.520 +
   1.521 +    if (getTime() != lastClock) {
   1.522 +      // Handle DAS within options (fixed at 250 ms 30 Hz)
   1.523 +      lastClock = getTime();
   1.524 +      if (keys & dasDir) {
   1.525 +        ++dasCounter;
   1.526 +        if (dasCounter >= 15) {
   1.527 +          dasCounter -= 2;
   1.528 +          dasKeys = dasDir;
   1.529 +        }
   1.530 +      } else {
   1.531 +        dasCounter = 0;
   1.532 +      }
   1.533 +    }
   1.534 +    
   1.535 +    if (newKeys & VKEY_UP
   1.536 +        || ((dasKeys & VKEY_UP)
   1.537 +            && y > optionsPages[page].start)) {
   1.538 +      dasDir = VKEY_UP;
   1.539 +      if (y <= 0) {
   1.540 +        while (optionsPages[page].name) {
   1.541 +          ++page;
   1.542 +        }
   1.543 +        y = optionsPages[page].start - 1;
   1.544 +      } else {
   1.545 +        --y;
   1.546 +      }
   1.547 +    }
   1.548 +    if (newKeys & VKEY_DOWN
   1.549 +        || ((dasKeys & VKEY_DOWN)
   1.550 +             && y < optionsPages[page + 1].start - 1)) {
   1.551 +      dasDir = VKEY_DOWN;
   1.552 +      ++y;
   1.553 +      if (y >= optionsPages[page + 1].start
   1.554 +          && !optionsPages[page + 1].name) {
   1.555 +        y = 0;
   1.556 +      }
   1.557 +    }
   1.558 +
   1.559 +    if (!isDisabledOption(prefs, y)) {    
   1.560 +      if ((newKeys | dasKeys) & VKEY_RIGHT) {
   1.561 +        int num = prefs[y] + 1;
   1.562 +
   1.563 +        if (num >= optionsMenu[y].minValue + optionsMenu[y].nValues) {
   1.564 +          prefs[y] = optionsMenu[y].minValue;
   1.565 +        } else {
   1.566 +          prefs[y] = num;
   1.567 +        }
   1.568 +
   1.569 +        sounds |= LJSND_ROTATE;
   1.570 +        // XXX: need to redraw the whole box (redraw = 2)
   1.571 +        // if options have become enabled or disabled
   1.572 +        redraw = 1;
   1.573 +        dasDir = VKEY_RIGHT;
   1.574 +      }
   1.575 +
   1.576 +      if ((newKeys | dasKeys) & VKEY_LEFT) {
   1.577 +        int num = prefs[y] - 1;
   1.578 +
   1.579 +        if (num < optionsMenu[y].minValue) {
   1.580 +          prefs[y] = optionsMenu[y].minValue + optionsMenu[y].nValues - 1;
   1.581 +        } else {
   1.582 +          prefs[y] = num;
   1.583 +        }
   1.584 +
   1.585 +        sounds |= LJSND_ROTATE;
   1.586 +        redraw = 1;
   1.587 +        dasDir = VKEY_LEFT;
   1.588 +      }
   1.589 +    }
   1.590 +
   1.591 +    // Rotate left: Go to the top of the previous page if it exists.
   1.592 +    if (newKeys & VKEY_ROTL) {
   1.593 +      if (page > 0) {
   1.594 +        y = optionsPages[page - 1].start;
   1.595 +      } else {
   1.596 +        y = 0;
   1.597 +      }
   1.598 +    }
   1.599 +
   1.600 +    // Rotate right: If on last page, finish;
   1.601 +    // otherwise, go to the top of the next page.
   1.602 +    if (newKeys & VKEY_ROTR) {
   1.603 +      if (!optionsPages[page + 1].name) {
   1.604 +        done = 1;
   1.605 +      } else {
   1.606 +        y = optionsPages[page + 1].start;
   1.607 +      }
   1.608 +    }
   1.609 +    
   1.610 +    // Start: finish
   1.611 +    if (newKeys & VKEY_START) {
   1.612 +      done = 1;
   1.613 +    }
   1.614 +
   1.615 +    if (lastY != y) {
   1.616 +      sounds |= LJSND_SHIFT;
   1.617 +
   1.618 +      // calculate which page the cursor has moved to
   1.619 +      int lastPage = page;
   1.620 +      while (y < optionsPages[page].start) {
   1.621 +        --page;
   1.622 +      }
   1.623 +      while (y >= optionsPages[page + 1].start) {
   1.624 +        ++page;
   1.625 +      }
   1.626 +      
   1.627 +      if (lastPage == page) {
   1.628 +        erase = lastY;
   1.629 +        if (redraw < 1) {
   1.630 +          redraw = 1;
   1.631 +        }
   1.632 +      } else {
   1.633 +        // turning the page
   1.634 +        sounds |= LJSND_HOLD;
   1.635 +        redraw = 2;  // redraw the whole screen
   1.636 +      }
   1.637 +    }
   1.638 +    lastKeys = keys;
   1.639 +    
   1.640 +    if (done) {
   1.641 +      sounds |= LJSND_LINE;
   1.642 +    }
   1.643 +    playSoundEffects(v, sounds, 100);
   1.644 +  }
   1.645 +}