annotate src/options.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
rev   line source
paulo@0 1 /* options code for LOCKJAW, an implementation of the Soviet Mind Game
paulo@0 2
paulo@0 3 Copyright (C) 2007-2008 Damian Yerrick <tepples+lj@spamcop.net>
paulo@0 4
paulo@0 5 This work is free software; you can redistribute it and/or modify
paulo@0 6 it under the terms of the GNU General Public License as published by
paulo@0 7 the Free Software Foundation; either version 2 of the License, or
paulo@0 8 (at your option) any later version.
paulo@0 9
paulo@0 10 This program is distributed in the hope that it will be useful,
paulo@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
paulo@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
paulo@0 13 GNU General Public License for more details.
paulo@0 14
paulo@0 15 You should have received a copy of the GNU General Public License
paulo@0 16 along with this program; if not, write to the Free Software
paulo@0 17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
paulo@0 18
paulo@0 19 Original game concept and design by Alexey Pajitnov.
paulo@0 20 The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg,
paulo@0 21 or The Tetris Company LLC.
paulo@0 22
paulo@0 23 */
paulo@0 24
paulo@0 25
paulo@0 26 #include <string.h>
paulo@0 27 #include <stdio.h>
paulo@0 28 #include "options.h"
paulo@0 29 #include "ljplay.h"
paulo@0 30 #include "ljlocale.h"
paulo@0 31
paulo@0 32 #ifdef HAS_FPU
paulo@0 33 #define siprintf sprintf
paulo@0 34 #define MIN_SHADOW 0
paulo@0 35 #define N_SHADOWS LJSHADOW_N_STYLES
paulo@0 36 #define FACTORY_SHADOW 0
paulo@0 37 #include "ljpc.h"
paulo@0 38 #else
paulo@0 39 #define MIN_SHADOW LJSHADOW_COLORED
paulo@0 40 #define N_SHADOWS (LJSHADOW_N_STYLES - 2)
paulo@0 41 #define FACTORY_SHADOW MIN_SHADOW
paulo@0 42 #endif
paulo@0 43
paulo@0 44 const FourCC optionsBoolNames[2] = {
paulo@0 45 {"Off"}, {"On"}
paulo@0 46 };
paulo@0 47
paulo@0 48 const FourCC gimmickNames[LJGM_N_GIMMICKS] = {
paulo@0 49 {"Mara"}, {"Line"}, {"Time"}, {"DrlA"}, {"Item"}, {"Keys"}
paulo@0 50 };
paulo@0 51
paulo@0 52 const FourCC optionsGarbageNames[LJGARBAGE_N_STYLES] = {
paulo@0 53 {"Off"}, {"Lv.1"}, {"Lv.2"}, {"Lv.3"}, {"Lv.4"},
paulo@0 54 {"HRD"}, {"DrlG"}, {"Zigz"}
paulo@0 55 };
paulo@0 56
paulo@0 57 const FourCC optionsScoringNames[LJSCORE_N_STYLES] = {
paulo@0 58 {"LJ"}, {"Fibo"}, {"HotL"}, {"TDSl"}, {"NESl"}, {"LJns"}
paulo@0 59 };
paulo@0 60
paulo@0 61 const FourCC optionsKickLimitNames[N_KICK_LIMITS] = {
paulo@0 62 {"Off"}, {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"Inf"}
paulo@0 63 };
paulo@0 64
paulo@0 65 const FourCC optionsSpeedCurveNames[] = {
paulo@0 66 {"Zero"}, {"Rhy0"}, {"Exp"}, {"Rh20"},
paulo@0 67 {"TGM2"}, {"TAPD"}, {"TAD3"},
paulo@0 68 {"NESc"}, {"GBc"}, {"GBHL"}
paulo@0 69 };
paulo@0 70
paulo@0 71 static const FourCC optionsWindowedNames[2] = {
paulo@0 72 {"FulS"}, {"Wind"}
paulo@0 73 };
paulo@0 74
paulo@0 75 const FourCC optionsShadowNames[LJSHADOW_N_STYLES] = {
paulo@0 76 {"tl25"}, {"tl50"}, {"tlsC"}, {"tlsM"}, {"Off"}, {"invF"}
paulo@0 77 };
paulo@0 78
paulo@0 79 const FourCC optionsLockDelayNames[2] = {
paulo@0 80 {"SBSC"}, {"Inf"}
paulo@0 81 };
paulo@0 82
paulo@0 83 const FourCC optionsSBSCNames[2] = {
paulo@0 84 {"SBSC"}, {.i=0}
paulo@0 85 };
paulo@0 86
paulo@0 87 const FourCC optionsTspinNames[] = {
paulo@0 88 {"Off"}, {"Imob"}, {"CrnT"}, {"WKT"}
paulo@0 89 };
paulo@0 90
paulo@0 91 const FourCC optionsLockdownNames[] = {
paulo@0 92 {"OLD"}, {"EntR"}, {"StpR"}, {"MovR"}
paulo@0 93 };
paulo@0 94
paulo@0 95 const FourCC optionsHoldStyleNames[] = {
paulo@0 96 {"Off"}, {"HldE"}, {"HldR"}, {"HldN"}
paulo@0 97 };
paulo@0 98
paulo@0 99 const FourCC optionsDropScoringNames[LJDROP_N_STYLES] = {
paulo@0 100 {"None"}, {"ConD"}, {"S1H1"}, {"S1H2"}
paulo@0 101 };
paulo@0 102
paulo@0 103 const FourCC optionsGravNames[] = {
paulo@0 104 {"Naiv"}, {"Stky"}, {"byCo"}, {"Casc"}
paulo@0 105 };
paulo@0 106
paulo@0 107 const FourCC optionsPieceSetNames[LJRAND_N_PIECE_SETS] = {
paulo@0 108 {"IJLO"},
paulo@0 109 {"JLOT"},
paulo@0 110 {"SZSZ"},
paulo@0 111 {"IIII"},
paulo@0 112 {"AllP"},
paulo@0 113 {"TTTT"}
paulo@0 114 };
paulo@0 115
paulo@0 116 const FourCC optionsRandNames[LJRAND_N_RANDS] = {
paulo@0 117 {"Unif"},
paulo@0 118 {"Bag"},
paulo@0 119 {"Bag+"},
paulo@0 120 {"Bag2"},
paulo@0 121 {"Hist"},
paulo@0 122 {"His6"}
paulo@0 123 };
paulo@0 124
paulo@0 125 const FourCC optionsLineDelayNames[] = {
paulo@0 126 {"SBSC"}, {.i=0}
paulo@0 127 };
paulo@0 128
paulo@0 129 const FourCC optionsZangiNames[] = {
paulo@0 130 {"Slid"}, {"Lock"}, {"LocU"}
paulo@0 131 };
paulo@0 132
paulo@0 133 const FourCC optionsGluingNames[] = {
paulo@0 134 {"Off"}, {"Squ"}, {"Stky"}, {"byCo"}
paulo@0 135 };
paulo@0 136
paulo@0 137 const FourCC optionsRotNames[N_ROTATION_SYSTEMS] = {
paulo@0 138 {"SRS"}, {"Sega"}, {"ARS"}, {"Tngn"},
paulo@0 139 {"NRSR"}, {"NRSL"}, {"TOD4"}, {"TDX"}
paulo@0 140 };
paulo@0 141
paulo@0 142
paulo@0 143 const OptionsLine commonOptionsMenu[] = {
paulo@0 144 {{"gimm"}, gimmickNames,
paulo@0 145 0, LJGM_N_GIMMICKS, 0 },
paulo@0 146 {{"pfw"}, NULL,
paulo@0 147 4, LJ_PF_WID - 4 + 1, 10 },
paulo@0 148 {{"pfh"}, NULL,
paulo@0 149 8, LJ_PF_VIS_HT - 8 + 1, LJ_PF_VIS_HT },
paulo@0 150 {{"vzsp"}, optionsBoolNames,
paulo@0 151 0, 2, 1 },
paulo@0 152 {{"spdc"}, optionsSpeedCurveNames,
paulo@0 153 0, LJSPD_N_CURVES, LJSPD_EXP },
paulo@0 154 {{"are"}, NULL,
paulo@0 155 0, 121, 0, OPTSTYLE_FRAMES },
paulo@0 156 {{"piec"}, optionsPieceSetNames,
paulo@0 157 0, LJRAND_N_PIECE_SETS, LJRAND_4BLK },
paulo@0 158 {{"rand"}, optionsRandNames,
paulo@0 159 0, LJRAND_N_RANDS, LJRAND_BAG },
paulo@0 160
paulo@0 161 {{"hold"}, optionsHoldStyleNames,
paulo@0 162 0, LJHOLD_N_STYLES, LJHOLD_EMPTY },
paulo@0 163 {{"rots"}, optionsRotNames,
paulo@0 164 0, N_ROTATION_SYSTEMS, 0 },
paulo@0 165 {{"upkl"}, optionsKickLimitNames,
paulo@0 166 0, N_KICK_LIMITS, N_KICK_LIMITS - 1 },
paulo@0 167 {{"lock"}, optionsLockdownNames,
paulo@0 168 0, LJLOCK_N_STYLES, LJLOCK_MOVE },
paulo@0 169 {{"sldt"}, optionsLockDelayNames,
paulo@0 170 0, 129, 0, OPTSTYLE_FRAMES },
paulo@0 171 {{"deep"}, optionsBoolNames,
paulo@0 172 0, 2, 0 },
paulo@0 173
paulo@0 174 {{"clrd"}, optionsSBSCNames,
paulo@0 175 0, 121, 0, OPTSTYLE_FRAMES },
paulo@0 176 {{"grav"}, optionsGravNames,
paulo@0 177 0, LJGRAV_N_ALGOS, LJGRAV_NAIVE },
paulo@0 178 {{"glue"}, optionsGluingNames,
paulo@0 179 0, LJGLUING_N_STYLES, LJGLUING_NONE },
paulo@0 180 {{"lsco"}, optionsScoringNames,
paulo@0 181 0, LJSCORE_N_STYLES },
paulo@0 182 {{"dsco"}, optionsDropScoringNames,
paulo@0 183 0, LJDROP_N_STYLES, 0 },
paulo@0 184 {{"tspn"}, optionsTspinNames,
paulo@0 185 0, LJTS_N_ALGOS, LJTS_TDS },
paulo@0 186 {{"garb"}, optionsGarbageNames,
paulo@0 187 0, LJGARBAGE_N_STYLES, 0 },
paulo@0 188
paulo@0 189 {{"dasd"}, NULL,
paulo@0 190 1, 120, 10, OPTSTYLE_FRAMES },
paulo@0 191 {{"dass"}, NULL,
paulo@0 192 0, 10, 1, OPTSTYLE_FRAC_G },
paulo@0 193 {{"idas"}, optionsBoolNames,
paulo@0 194 0, 2, 1 },
paulo@0 195 {{"irs"}, optionsBoolNames,
paulo@0 196 0, 2, 1 },
paulo@0 197 {{"8way"}, optionsBoolNames,
paulo@0 198 0, 2, 0 },
paulo@0 199
paulo@0 200 {{"sfds"}, NULL,
paulo@0 201 1, 3, 1, OPTSTYLE_FRAC_G },
paulo@0 202 {{"sfdl"}, optionsZangiNames,
paulo@0 203 0, LJZANGI_N_STYLES, LJZANGI_SLIDE },
paulo@0 204 {{"hrdl"}, optionsZangiNames,
paulo@0 205 0, LJZANGI_N_STYLES, LJZANGI_LOCK },
paulo@0 206
paulo@0 207 {{"tls"}, optionsShadowNames + MIN_SHADOW,
paulo@0 208 MIN_SHADOW, N_SHADOWS, FACTORY_SHADOW },
paulo@0 209 {{"invs"}, optionsBoolNames,
paulo@0 210 0, 2, 0 },
paulo@0 211 {{"next"}, NULL,
paulo@0 212 0, LJ_NEXT_PIECES + 1, 6 },
paulo@0 213 {{"srph"}, optionsBoolNames,
paulo@0 214 0, 2, 1 },
paulo@0 215
paulo@0 216 #ifdef HAS_FPU
paulo@0 217 {{"inpv"}, NULL,
paulo@0 218 0, LJ_NEXT_PIECES + 1, 0 },
paulo@0 219 {{"mblr"}, optionsBoolNames,
paulo@0 220 0, 2, 1 },
paulo@0 221 {{"lidp"}, optionsBoolNames,
paulo@0 222 0, 2, 1 },
paulo@0 223 {{"rec"}, optionsBoolNames,
paulo@0 224 0, 2, 0 },
paulo@0 225 {{"wndw"}, optionsWindowedNames,
paulo@0 226 0, 2, 1 }
paulo@0 227 #endif
paulo@0 228 };
paulo@0 229
paulo@0 230 const OptionsPage optionsPages[] = {
paulo@0 231 {OPTIONS_GIMMICK, "Game"},
paulo@0 232 {OPTIONS_WIDTH, "Rules: Well"},
paulo@0 233 {OPTIONS_HOLD_PIECE, "Rules: Movement"},
paulo@0 234 {OPTIONS_LINE_DELAY, "Rules: Line clear"},
paulo@0 235 {OPTIONS_SIDEWAYS_DELAY, "Control: Movement"},
paulo@0 236 {OPTIONS_SOFT_DROP_SPEED, "Control: Drop"},
paulo@0 237 {OPTIONS_SHADOW, "Display"},
paulo@0 238 #ifdef HAS_FPU
paulo@0 239 {OPTIONS_MENU_LEN, "PC"},
paulo@0 240 {PC_OPTIONS_MENU_LEN, NULL}
paulo@0 241 #else
paulo@0 242 {OPTIONS_MENU_LEN, NULL}
paulo@0 243 #endif
paulo@0 244 };
paulo@0 245
paulo@0 246 void setOptionsValueToFourCC(char *dst, FourCC f) {
paulo@0 247 const char *valueName = ljGetFourCCName(f);
paulo@0 248 if (valueName) {
paulo@0 249 strncpy(dst,
paulo@0 250 valueName,
paulo@0 251 OPTIONS_VALUE_LEN - 1);
paulo@0 252 dst[OPTIONS_VALUE_LEN - 1] = 0;
paulo@0 253 } else {
paulo@0 254 strncpy(dst, f.c, 4);
paulo@0 255 dst[4] = 0;
paulo@0 256 }
paulo@0 257 }
paulo@0 258
paulo@0 259 struct DisabledOption {
paulo@0 260 unsigned char name;
paulo@0 261 unsigned char value;
paulo@0 262 unsigned char name2;
paulo@0 263 char reason[45];
paulo@0 264 };
paulo@0 265
paulo@0 266 /*
paulo@0 267 Semantics:
paulo@0 268 If option name is set to value,
paulo@0 269 then gray out option name2 and draw its value as reason.
paulo@0 270 */
paulo@0 271 #define N_DISABLED_OPTIONS 12
paulo@0 272 const struct DisabledOption disabledOptions[N_DISABLED_OPTIONS] = {
paulo@0 273 { OPTIONS_LOCKDOWN, LJLOCK_NOW,
paulo@0 274 OPTIONS_SOFT_DROP, "Lockdown is immediate" },
paulo@0 275 { OPTIONS_LOCKDOWN, LJLOCK_NOW,
paulo@0 276 OPTIONS_HARD_DROP, "Lockdown is immediate" },
paulo@0 277 { OPTIONS_LOCKDOWN, LJLOCK_NOW,
paulo@0 278 OPTIONS_LOCK_DELAY, "Lockdown is immediate" },
paulo@0 279 { OPTIONS_LOCK_DELAY, 128,
paulo@0 280 OPTIONS_LOCKDOWN, "Lockdown is manual" },
paulo@0 281 { OPTIONS_SPEED_CURVE, LJSPD_DEATH,
paulo@0 282 OPTIONS_SOFT_DROP_SPEED,"Death: pieces land instantly" },
paulo@0 283 { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM,
paulo@0 284 OPTIONS_SOFT_DROP_SPEED,"Rhythm: pieces land instantly" },
paulo@0 285 { OPTIONS_SPEED_CURVE, LJSPD_DEATH,
paulo@0 286 OPTIONS_SMOOTH_GRAVITY, "Death: pieces land instantly" },
paulo@0 287 { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM,
paulo@0 288 OPTIONS_SMOOTH_GRAVITY, "Rhythm: pieces land instantly" },
paulo@0 289 { OPTIONS_SPEED_CURVE, LJSPD_DEATH,
paulo@0 290 OPTIONS_SOFT_DROP, "Death: pieces land instantly" },
paulo@0 291 { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM,
paulo@0 292 OPTIONS_SOFT_DROP, "Rhythm: pieces land instantly" },
paulo@0 293 { OPTIONS_SPEED_CURVE, LJSPD_DEATH,
paulo@0 294 OPTIONS_HARD_DROP, "Death: pieces land instantly" },
paulo@0 295 { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM,
paulo@0 296 OPTIONS_HARD_DROP, "Rhythm: pieces land instantly" },
paulo@0 297 };
paulo@0 298
paulo@0 299 const char *isDisabledOption(const unsigned char *prefs, int y) {
paulo@0 300 for (int i = 0; i < N_DISABLED_OPTIONS; ++i) {
paulo@0 301 if (y == disabledOptions[i].name2) {
paulo@0 302 int name = disabledOptions[i].name;
paulo@0 303 int value = disabledOptions[i].value;
paulo@0 304
paulo@0 305 if (prefs[name] == value) {
paulo@0 306 return disabledOptions[i].reason;
paulo@0 307 }
paulo@0 308 }
paulo@0 309 }
paulo@0 310 return NULL;
paulo@0 311 }
paulo@0 312
paulo@0 313
paulo@0 314 const char *getOptionsValueStr(char *dst, int line, int value) {
paulo@0 315 const OptionsLine *l = &(commonOptionsMenu[line]);
paulo@0 316 FourCC f = {.i = 0};
paulo@0 317 const char *desc = NULL;
paulo@0 318
paulo@0 319 switch (l->style) {
paulo@0 320 case OPTSTYLE_DEFAULT:
paulo@0 321 if (l->valueNames) {
paulo@0 322 f = l->valueNames[value - l->minValue];
paulo@0 323 } else {
paulo@0 324 siprintf(dst, "%d", value);
paulo@0 325 }
paulo@0 326 break;
paulo@0 327
paulo@0 328 case OPTSTYLE_FRAMES:
paulo@0 329 if (l->valueNames
paulo@0 330 && value == l->minValue
paulo@0 331 && l->valueNames[0].i) {
paulo@0 332
paulo@0 333 // override first with name 0
paulo@0 334 f = l->valueNames[0];
paulo@0 335 } else if (l->valueNames
paulo@0 336 && value == l->minValue
paulo@0 337 + l->nValues - 1
paulo@0 338 && l->valueNames[1].i) {
paulo@0 339
paulo@0 340 // override second with name 1
paulo@0 341 f = l->valueNames[1];
paulo@0 342 } else {
paulo@0 343 if (value >= 60) {
paulo@0 344 int ds = value / 6;
paulo@0 345 int s = ds / 10;
paulo@0 346 ds -= s * 10;
paulo@0 347 siprintf(dst, "%d/60 s (%d.%d s)", value, s, ds);
paulo@0 348 } else {
paulo@0 349 int ms = value * 50 / 3;
paulo@0 350 siprintf(dst, "%d/60 s (%d ms)", value, ms);
paulo@0 351 }
paulo@0 352 } break;
paulo@0 353
paulo@0 354 case OPTSTYLE_FRAC_G:
paulo@0 355 if (value > 6) {
paulo@0 356 int dHz = 600 / value;
paulo@0 357 int Hz = dHz / 10;
paulo@0 358 dHz -= Hz * 10;
paulo@0 359 siprintf(dst, "1/%dG (%d.%d Hz)", value, Hz, dHz);
paulo@0 360 } else if (value > 0) {
paulo@0 361 if (value > 1) {
paulo@0 362 dst[0] = '1';
paulo@0 363 dst[1] = '/';
paulo@0 364 dst += 2;
paulo@0 365 }
paulo@0 366 siprintf(dst, "%dG (%d Hz)", value, 60 / value);
paulo@0 367 } else {
paulo@0 368 strcpy(dst, "Instant");
paulo@0 369 }
paulo@0 370 break;
paulo@0 371
paulo@0 372 default:
paulo@0 373 strncpy(dst, "Unknown option style.", OPTIONS_VALUE_LEN - 1);
paulo@0 374 dst[OPTIONS_VALUE_LEN - 1] = 0;
paulo@0 375 break;
paulo@0 376 }
paulo@0 377
paulo@0 378 /* If we have a fourCC, use it. */
paulo@0 379 if (f.i != 0) {
paulo@0 380 setOptionsValueToFourCC(dst, f);
paulo@0 381 desc = ljGetFourCCDesc(f);
paulo@0 382 }
paulo@0 383 return desc;
paulo@0 384 }
paulo@0 385
paulo@0 386 void unpackCommonOptions(LJView *v, const unsigned char *prefs) {
paulo@0 387 if (prefs[OPTIONS_GIMMICK] < 255)
paulo@0 388 v->field->gimmick = prefs[OPTIONS_GIMMICK];
paulo@0 389 if (prefs[OPTIONS_WIDTH] < 255) {
paulo@0 390 int width = prefs[OPTIONS_WIDTH];
paulo@0 391 v->field->leftWall = (LJ_PF_WID - width) / 2;
paulo@0 392 v->field->rightWall = v->field->leftWall + width;
paulo@0 393 }
paulo@0 394 if (prefs[OPTIONS_HEIGHT] < 255)
paulo@0 395 v->field->ceiling = prefs[OPTIONS_HEIGHT];
paulo@0 396 if (prefs[OPTIONS_ENTER_ABOVE] < 255)
paulo@0 397 v->field->enterAbove = prefs[OPTIONS_ENTER_ABOVE];
paulo@0 398 if (prefs[OPTIONS_SPEED_CURVE] < 255)
paulo@0 399 v->field->speedState.curve = prefs[OPTIONS_SPEED_CURVE];
paulo@0 400 if (prefs[OPTIONS_ENTRY_DELAY] < 255)
paulo@0 401 v->field->areStyle = prefs[OPTIONS_ENTRY_DELAY];
paulo@0 402 if (prefs[OPTIONS_PIECE_SET] < 255)
paulo@0 403 v->field->pieceSet = prefs[OPTIONS_PIECE_SET];
paulo@0 404 if (prefs[OPTIONS_RANDOMIZER] < 255)
paulo@0 405 v->field->randomizer = prefs[OPTIONS_RANDOMIZER];
paulo@0 406
paulo@0 407 if (prefs[OPTIONS_ROTATION_SYSTEM] < 255)
paulo@0 408 v->field->rotationSystem = prefs[OPTIONS_ROTATION_SYSTEM];
paulo@0 409 if (prefs[OPTIONS_FLOOR_KICKS] < 255)
paulo@0 410 v->field->maxUpwardKicks = prefs[OPTIONS_FLOOR_KICKS] == N_KICK_LIMITS - 1
paulo@0 411 ? 128
paulo@0 412 : prefs[OPTIONS_FLOOR_KICKS];
paulo@0 413 if (prefs[OPTIONS_HOLD_PIECE] < 255)
paulo@0 414 v->field->holdStyle = prefs[OPTIONS_HOLD_PIECE];
paulo@0 415 if (prefs[OPTIONS_LOCKDOWN] < 255)
paulo@0 416 v->field->lockReset = prefs[OPTIONS_LOCKDOWN];
paulo@0 417 if (prefs[OPTIONS_LOCK_DELAY] < 255)
paulo@0 418 v->field->setLockDelay = prefs[OPTIONS_LOCK_DELAY];
paulo@0 419 if (prefs[OPTIONS_BOTTOM_BLOCKS] < 255)
paulo@0 420 v->field->bottomBlocks = prefs[OPTIONS_BOTTOM_BLOCKS];
paulo@0 421
paulo@0 422 if (prefs[OPTIONS_LINE_DELAY] < 255)
paulo@0 423 v->field->setLineDelay = prefs[OPTIONS_LINE_DELAY];
paulo@0 424 if (prefs[OPTIONS_T_SPIN] < 255)
paulo@0 425 v->field->tSpinAlgo = prefs[OPTIONS_T_SPIN];
paulo@0 426 if (prefs[OPTIONS_CLEAR_GRAVITY] < 255)
paulo@0 427 v->field->clearGravity = prefs[OPTIONS_CLEAR_GRAVITY];
paulo@0 428 if (prefs[OPTIONS_GLUING] < 255)
paulo@0 429 v->field->gluing = prefs[OPTIONS_GLUING];
paulo@0 430 if (prefs[OPTIONS_SCORING] < 255)
paulo@0 431 v->field->scoreStyle = prefs[OPTIONS_SCORING];
paulo@0 432 if (prefs[OPTIONS_DROP_SCORING] < 255)
paulo@0 433 v->field->dropScoreStyle = prefs[OPTIONS_DROP_SCORING];
paulo@0 434 if (prefs[OPTIONS_GARBAGE] < 255)
paulo@0 435 v->field->garbageStyle = prefs[OPTIONS_GARBAGE];
paulo@0 436
paulo@0 437 if (prefs[OPTIONS_SIDEWAYS_DELAY] < 255)
paulo@0 438 v->control->dasDelay = prefs[OPTIONS_SIDEWAYS_DELAY];
paulo@0 439 if (prefs[OPTIONS_SIDEWAYS_SPEED] < 255)
paulo@0 440 v->control->dasSpeed = prefs[OPTIONS_SIDEWAYS_SPEED];
paulo@0 441 if (v->control->dasDelay < v->control->dasSpeed) {
paulo@0 442 v->control->dasDelay = v->control->dasSpeed;
paulo@0 443 }
paulo@0 444 if (prefs[OPTIONS_INITIAL_SIDEWAYS] < 255)
paulo@0 445 v->control->initialDAS = prefs[OPTIONS_INITIAL_SIDEWAYS];
paulo@0 446 if (prefs[OPTIONS_IRS] < 255)
paulo@0 447 v->control->initialRotate = prefs[OPTIONS_IRS];
paulo@0 448 if (prefs[OPTIONS_DIAGONAL_MOTION] < 255)
paulo@0 449 v->control->allowDiagonals = prefs[OPTIONS_DIAGONAL_MOTION];
paulo@0 450 if (prefs[OPTIONS_SOFT_DROP_SPEED] < 255)
paulo@0 451 v->control->softDropSpeed = prefs[OPTIONS_SOFT_DROP_SPEED] - 1;
paulo@0 452 if (prefs[OPTIONS_SOFT_DROP] < 255)
paulo@0 453 v->control->softDropLock = prefs[OPTIONS_SOFT_DROP];
paulo@0 454 if (prefs[OPTIONS_HARD_DROP] < 255)
paulo@0 455 v->control->hardDropLock = prefs[OPTIONS_HARD_DROP];
paulo@0 456
paulo@0 457 if (prefs[OPTIONS_SHADOW] < 255)
paulo@0 458 v->hideShadow = prefs[OPTIONS_SHADOW];
paulo@0 459 if (prefs[OPTIONS_HIDE_PF] < 255)
paulo@0 460 v->hidePF = prefs[OPTIONS_HIDE_PF];
paulo@0 461 if (prefs[OPTIONS_NEXT_PIECES] < 255)
paulo@0 462 v->nextPieces = prefs[OPTIONS_NEXT_PIECES];
paulo@0 463 if (prefs[OPTIONS_SMOOTH_GRAVITY] < 255)
paulo@0 464 v->smoothGravity = prefs[OPTIONS_SMOOTH_GRAVITY];
paulo@0 465 }
paulo@0 466
paulo@0 467 void initOptions(unsigned char *prefs) {
paulo@0 468 for (int i = 0; i < OPTIONS_MENU_LEN; ++i) {
paulo@0 469 prefs[i] = commonOptionsMenu[i].startValue;
paulo@0 470 }
paulo@0 471 }
paulo@0 472
paulo@0 473 LJBits menuReadPad(void);
paulo@0 474 void vsync(void);
paulo@0 475
paulo@0 476 void options(LJView *v, unsigned char *prefs) {
paulo@0 477 int page = 0, y = 0;
paulo@0 478 int redraw = 2;
paulo@0 479 int done = 0;
paulo@0 480 LJBits lastKeys = ~0;
paulo@0 481 int dasDir = 0;
paulo@0 482 int dasCounter = 0;
paulo@0 483 const OptionsLine const *optionsMenu = commonOptionsMenu;
paulo@0 484 int lastClock = getTime();
paulo@0 485 int erase = -1;
paulo@0 486
paulo@0 487 optionsWinInit();
paulo@0 488
paulo@0 489 while (!done) {
paulo@0 490 if (redraw) {
paulo@0 491 if (redraw == 2) {
paulo@0 492 redraw = 1;
paulo@0 493 optionsDrawPage(page, prefs);
paulo@0 494 }
paulo@0 495 if (redraw == 1) {
paulo@0 496 if (erase >= 0) {
paulo@0 497 vsync();
paulo@0 498 optionsDrawRow(prefs,
paulo@0 499 erase - optionsPages[page].start,
paulo@0 500 erase, prefs[erase], 0);
paulo@0 501 erase = -1;
paulo@0 502 }
paulo@0 503 optionsDrawRow(prefs,
paulo@0 504 y - optionsPages[page].start,
paulo@0 505 y, prefs[y], 1);
paulo@0 506 redraw = 0;
paulo@0 507 }
paulo@0 508 } else {
paulo@0 509 optionsIdle();
paulo@0 510 }
paulo@0 511
paulo@0 512 LJBits keys = menuReadPad();
paulo@0 513 LJBits sounds = 0;
paulo@0 514 int lastY = y;
paulo@0 515 LJBits newKeys = keys & ~lastKeys;
paulo@0 516 LJBits dasKeys = 0;
paulo@0 517
paulo@0 518 if (getTime() != lastClock) {
paulo@0 519 // Handle DAS within options (fixed at 250 ms 30 Hz)
paulo@0 520 lastClock = getTime();
paulo@0 521 if (keys & dasDir) {
paulo@0 522 ++dasCounter;
paulo@0 523 if (dasCounter >= 15) {
paulo@0 524 dasCounter -= 2;
paulo@0 525 dasKeys = dasDir;
paulo@0 526 }
paulo@0 527 } else {
paulo@0 528 dasCounter = 0;
paulo@0 529 }
paulo@0 530 }
paulo@0 531
paulo@0 532 if (newKeys & VKEY_UP
paulo@0 533 || ((dasKeys & VKEY_UP)
paulo@0 534 && y > optionsPages[page].start)) {
paulo@0 535 dasDir = VKEY_UP;
paulo@0 536 if (y <= 0) {
paulo@0 537 while (optionsPages[page].name) {
paulo@0 538 ++page;
paulo@0 539 }
paulo@0 540 y = optionsPages[page].start - 1;
paulo@0 541 } else {
paulo@0 542 --y;
paulo@0 543 }
paulo@0 544 }
paulo@0 545 if (newKeys & VKEY_DOWN
paulo@0 546 || ((dasKeys & VKEY_DOWN)
paulo@0 547 && y < optionsPages[page + 1].start - 1)) {
paulo@0 548 dasDir = VKEY_DOWN;
paulo@0 549 ++y;
paulo@0 550 if (y >= optionsPages[page + 1].start
paulo@0 551 && !optionsPages[page + 1].name) {
paulo@0 552 y = 0;
paulo@0 553 }
paulo@0 554 }
paulo@0 555
paulo@0 556 if (!isDisabledOption(prefs, y)) {
paulo@0 557 if ((newKeys | dasKeys) & VKEY_RIGHT) {
paulo@0 558 int num = prefs[y] + 1;
paulo@0 559
paulo@0 560 if (num >= optionsMenu[y].minValue + optionsMenu[y].nValues) {
paulo@0 561 prefs[y] = optionsMenu[y].minValue;
paulo@0 562 } else {
paulo@0 563 prefs[y] = num;
paulo@0 564 }
paulo@0 565
paulo@0 566 sounds |= LJSND_ROTATE;
paulo@0 567 // XXX: need to redraw the whole box (redraw = 2)
paulo@0 568 // if options have become enabled or disabled
paulo@0 569 redraw = 1;
paulo@0 570 dasDir = VKEY_RIGHT;
paulo@0 571 }
paulo@0 572
paulo@0 573 if ((newKeys | dasKeys) & VKEY_LEFT) {
paulo@0 574 int num = prefs[y] - 1;
paulo@0 575
paulo@0 576 if (num < optionsMenu[y].minValue) {
paulo@0 577 prefs[y] = optionsMenu[y].minValue + optionsMenu[y].nValues - 1;
paulo@0 578 } else {
paulo@0 579 prefs[y] = num;
paulo@0 580 }
paulo@0 581
paulo@0 582 sounds |= LJSND_ROTATE;
paulo@0 583 redraw = 1;
paulo@0 584 dasDir = VKEY_LEFT;
paulo@0 585 }
paulo@0 586 }
paulo@0 587
paulo@0 588 // Rotate left: Go to the top of the previous page if it exists.
paulo@0 589 if (newKeys & VKEY_ROTL) {
paulo@0 590 if (page > 0) {
paulo@0 591 y = optionsPages[page - 1].start;
paulo@0 592 } else {
paulo@0 593 y = 0;
paulo@0 594 }
paulo@0 595 }
paulo@0 596
paulo@0 597 // Rotate right: If on last page, finish;
paulo@0 598 // otherwise, go to the top of the next page.
paulo@0 599 if (newKeys & VKEY_ROTR) {
paulo@0 600 if (!optionsPages[page + 1].name) {
paulo@0 601 done = 1;
paulo@0 602 } else {
paulo@0 603 y = optionsPages[page + 1].start;
paulo@0 604 }
paulo@0 605 }
paulo@0 606
paulo@0 607 // Start: finish
paulo@0 608 if (newKeys & VKEY_START) {
paulo@0 609 done = 1;
paulo@0 610 }
paulo@0 611
paulo@0 612 if (lastY != y) {
paulo@0 613 sounds |= LJSND_SHIFT;
paulo@0 614
paulo@0 615 // calculate which page the cursor has moved to
paulo@0 616 int lastPage = page;
paulo@0 617 while (y < optionsPages[page].start) {
paulo@0 618 --page;
paulo@0 619 }
paulo@0 620 while (y >= optionsPages[page + 1].start) {
paulo@0 621 ++page;
paulo@0 622 }
paulo@0 623
paulo@0 624 if (lastPage == page) {
paulo@0 625 erase = lastY;
paulo@0 626 if (redraw < 1) {
paulo@0 627 redraw = 1;
paulo@0 628 }
paulo@0 629 } else {
paulo@0 630 // turning the page
paulo@0 631 sounds |= LJSND_HOLD;
paulo@0 632 redraw = 2; // redraw the whole screen
paulo@0 633 }
paulo@0 634 }
paulo@0 635 lastKeys = keys;
paulo@0 636
paulo@0 637 if (done) {
paulo@0 638 sounds |= LJSND_LINE;
paulo@0 639 }
paulo@0 640 playSoundEffects(v, sounds, 100);
paulo@0 641 }
paulo@0 642 }