paulo@0: /* options code for LOCKJAW, an implementation of the Soviet Mind Game paulo@0: paulo@0: Copyright (C) 2007-2008 Damian Yerrick paulo@0: paulo@0: This work is free software; you can redistribute it and/or modify paulo@0: it under the terms of the GNU General Public License as published by paulo@0: the Free Software Foundation; either version 2 of the License, or paulo@0: (at your option) any later version. paulo@0: paulo@0: This program is distributed in the hope that it will be useful, paulo@0: but WITHOUT ANY WARRANTY; without even the implied warranty of paulo@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the paulo@0: GNU General Public License for more details. paulo@0: paulo@0: You should have received a copy of the GNU General Public License paulo@0: along with this program; if not, write to the Free Software paulo@0: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA paulo@0: paulo@0: Original game concept and design by Alexey Pajitnov. paulo@0: The Software is not sponsored or endorsed by Alexey Pajitnov, Elorg, paulo@0: or The Tetris Company LLC. paulo@0: paulo@0: */ paulo@0: paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include "options.h" paulo@0: #include "ljplay.h" paulo@0: #include "ljlocale.h" paulo@0: paulo@0: #ifdef HAS_FPU paulo@0: #define siprintf sprintf paulo@0: #define MIN_SHADOW 0 paulo@0: #define N_SHADOWS LJSHADOW_N_STYLES paulo@0: #define FACTORY_SHADOW 0 paulo@0: #include "ljpc.h" paulo@0: #else paulo@0: #define MIN_SHADOW LJSHADOW_COLORED paulo@0: #define N_SHADOWS (LJSHADOW_N_STYLES - 2) paulo@0: #define FACTORY_SHADOW MIN_SHADOW paulo@0: #endif paulo@0: paulo@0: const FourCC optionsBoolNames[2] = { paulo@0: {"Off"}, {"On"} paulo@0: }; paulo@0: paulo@0: const FourCC gimmickNames[LJGM_N_GIMMICKS] = { paulo@0: {"Mara"}, {"Line"}, {"Time"}, {"DrlA"}, {"Item"}, {"Keys"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsGarbageNames[LJGARBAGE_N_STYLES] = { paulo@0: {"Off"}, {"Lv.1"}, {"Lv.2"}, {"Lv.3"}, {"Lv.4"}, paulo@0: {"HRD"}, {"DrlG"}, {"Zigz"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsScoringNames[LJSCORE_N_STYLES] = { paulo@0: {"LJ"}, {"Fibo"}, {"HotL"}, {"TDSl"}, {"NESl"}, {"LJns"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsKickLimitNames[N_KICK_LIMITS] = { paulo@0: {"Off"}, {"1"}, {"2"}, {"3"}, {"4"}, {"5"}, {"Inf"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsSpeedCurveNames[] = { paulo@0: {"Zero"}, {"Rhy0"}, {"Exp"}, {"Rh20"}, paulo@0: {"TGM2"}, {"TAPD"}, {"TAD3"}, paulo@0: {"NESc"}, {"GBc"}, {"GBHL"} paulo@0: }; paulo@0: paulo@0: static const FourCC optionsWindowedNames[2] = { paulo@0: {"FulS"}, {"Wind"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsShadowNames[LJSHADOW_N_STYLES] = { paulo@0: {"tl25"}, {"tl50"}, {"tlsC"}, {"tlsM"}, {"Off"}, {"invF"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsLockDelayNames[2] = { paulo@0: {"SBSC"}, {"Inf"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsSBSCNames[2] = { paulo@0: {"SBSC"}, {.i=0} paulo@0: }; paulo@0: paulo@0: const FourCC optionsTspinNames[] = { paulo@0: {"Off"}, {"Imob"}, {"CrnT"}, {"WKT"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsLockdownNames[] = { paulo@0: {"OLD"}, {"EntR"}, {"StpR"}, {"MovR"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsHoldStyleNames[] = { paulo@0: {"Off"}, {"HldE"}, {"HldR"}, {"HldN"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsDropScoringNames[LJDROP_N_STYLES] = { paulo@0: {"None"}, {"ConD"}, {"S1H1"}, {"S1H2"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsGravNames[] = { paulo@0: {"Naiv"}, {"Stky"}, {"byCo"}, {"Casc"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsPieceSetNames[LJRAND_N_PIECE_SETS] = { paulo@0: {"IJLO"}, paulo@0: {"JLOT"}, paulo@0: {"SZSZ"}, paulo@0: {"IIII"}, paulo@0: {"AllP"}, paulo@0: {"TTTT"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsRandNames[LJRAND_N_RANDS] = { paulo@0: {"Unif"}, paulo@0: {"Bag"}, paulo@0: {"Bag+"}, paulo@0: {"Bag2"}, paulo@0: {"Hist"}, paulo@0: {"His6"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsLineDelayNames[] = { paulo@0: {"SBSC"}, {.i=0} paulo@0: }; paulo@0: paulo@0: const FourCC optionsZangiNames[] = { paulo@0: {"Slid"}, {"Lock"}, {"LocU"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsGluingNames[] = { paulo@0: {"Off"}, {"Squ"}, {"Stky"}, {"byCo"} paulo@0: }; paulo@0: paulo@0: const FourCC optionsRotNames[N_ROTATION_SYSTEMS] = { paulo@0: {"SRS"}, {"Sega"}, {"ARS"}, {"Tngn"}, paulo@0: {"NRSR"}, {"NRSL"}, {"TOD4"}, {"TDX"} paulo@0: }; paulo@0: paulo@0: paulo@0: const OptionsLine commonOptionsMenu[] = { paulo@0: {{"gimm"}, gimmickNames, paulo@0: 0, LJGM_N_GIMMICKS, 0 }, paulo@0: {{"pfw"}, NULL, paulo@0: 4, LJ_PF_WID - 4 + 1, 10 }, paulo@0: {{"pfh"}, NULL, paulo@0: 8, LJ_PF_VIS_HT - 8 + 1, LJ_PF_VIS_HT }, paulo@0: {{"vzsp"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: {{"spdc"}, optionsSpeedCurveNames, paulo@0: 0, LJSPD_N_CURVES, LJSPD_EXP }, paulo@0: {{"are"}, NULL, paulo@0: 0, 121, 0, OPTSTYLE_FRAMES }, paulo@0: {{"piec"}, optionsPieceSetNames, paulo@0: 0, LJRAND_N_PIECE_SETS, LJRAND_4BLK }, paulo@0: {{"rand"}, optionsRandNames, paulo@0: 0, LJRAND_N_RANDS, LJRAND_BAG }, paulo@0: paulo@0: {{"hold"}, optionsHoldStyleNames, paulo@0: 0, LJHOLD_N_STYLES, LJHOLD_EMPTY }, paulo@0: {{"rots"}, optionsRotNames, paulo@0: 0, N_ROTATION_SYSTEMS, 0 }, paulo@0: {{"upkl"}, optionsKickLimitNames, paulo@0: 0, N_KICK_LIMITS, N_KICK_LIMITS - 1 }, paulo@0: {{"lock"}, optionsLockdownNames, paulo@0: 0, LJLOCK_N_STYLES, LJLOCK_MOVE }, paulo@0: {{"sldt"}, optionsLockDelayNames, paulo@0: 0, 129, 0, OPTSTYLE_FRAMES }, paulo@0: {{"deep"}, optionsBoolNames, paulo@0: 0, 2, 0 }, paulo@0: paulo@0: {{"clrd"}, optionsSBSCNames, paulo@0: 0, 121, 0, OPTSTYLE_FRAMES }, paulo@0: {{"grav"}, optionsGravNames, paulo@0: 0, LJGRAV_N_ALGOS, LJGRAV_NAIVE }, paulo@0: {{"glue"}, optionsGluingNames, paulo@0: 0, LJGLUING_N_STYLES, LJGLUING_NONE }, paulo@0: {{"lsco"}, optionsScoringNames, paulo@0: 0, LJSCORE_N_STYLES }, paulo@0: {{"dsco"}, optionsDropScoringNames, paulo@0: 0, LJDROP_N_STYLES, 0 }, paulo@0: {{"tspn"}, optionsTspinNames, paulo@0: 0, LJTS_N_ALGOS, LJTS_TDS }, paulo@0: {{"garb"}, optionsGarbageNames, paulo@0: 0, LJGARBAGE_N_STYLES, 0 }, paulo@0: paulo@0: {{"dasd"}, NULL, paulo@0: 1, 120, 10, OPTSTYLE_FRAMES }, paulo@0: {{"dass"}, NULL, paulo@0: 0, 10, 1, OPTSTYLE_FRAC_G }, paulo@0: {{"idas"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: {{"irs"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: {{"8way"}, optionsBoolNames, paulo@0: 0, 2, 0 }, paulo@0: paulo@0: {{"sfds"}, NULL, paulo@0: 1, 3, 1, OPTSTYLE_FRAC_G }, paulo@0: {{"sfdl"}, optionsZangiNames, paulo@0: 0, LJZANGI_N_STYLES, LJZANGI_SLIDE }, paulo@0: {{"hrdl"}, optionsZangiNames, paulo@0: 0, LJZANGI_N_STYLES, LJZANGI_LOCK }, paulo@0: paulo@0: {{"tls"}, optionsShadowNames + MIN_SHADOW, paulo@0: MIN_SHADOW, N_SHADOWS, FACTORY_SHADOW }, paulo@0: {{"invs"}, optionsBoolNames, paulo@0: 0, 2, 0 }, paulo@0: {{"next"}, NULL, paulo@0: 0, LJ_NEXT_PIECES + 1, 6 }, paulo@0: {{"srph"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: paulo@0: #ifdef HAS_FPU paulo@0: {{"inpv"}, NULL, paulo@0: 0, LJ_NEXT_PIECES + 1, 0 }, paulo@0: {{"mblr"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: {{"lidp"}, optionsBoolNames, paulo@0: 0, 2, 1 }, paulo@0: {{"rec"}, optionsBoolNames, paulo@0: 0, 2, 0 }, paulo@0: {{"wndw"}, optionsWindowedNames, paulo@0: 0, 2, 1 } paulo@0: #endif paulo@0: }; paulo@0: paulo@0: const OptionsPage optionsPages[] = { paulo@0: {OPTIONS_GIMMICK, "Game"}, paulo@0: {OPTIONS_WIDTH, "Rules: Well"}, paulo@0: {OPTIONS_HOLD_PIECE, "Rules: Movement"}, paulo@0: {OPTIONS_LINE_DELAY, "Rules: Line clear"}, paulo@0: {OPTIONS_SIDEWAYS_DELAY, "Control: Movement"}, paulo@0: {OPTIONS_SOFT_DROP_SPEED, "Control: Drop"}, paulo@0: {OPTIONS_SHADOW, "Display"}, paulo@0: #ifdef HAS_FPU paulo@0: {OPTIONS_MENU_LEN, "PC"}, paulo@0: {PC_OPTIONS_MENU_LEN, NULL} paulo@0: #else paulo@0: {OPTIONS_MENU_LEN, NULL} paulo@0: #endif paulo@0: }; paulo@0: paulo@0: void setOptionsValueToFourCC(char *dst, FourCC f) { paulo@0: const char *valueName = ljGetFourCCName(f); paulo@0: if (valueName) { paulo@0: strncpy(dst, paulo@0: valueName, paulo@0: OPTIONS_VALUE_LEN - 1); paulo@0: dst[OPTIONS_VALUE_LEN - 1] = 0; paulo@0: } else { paulo@0: strncpy(dst, f.c, 4); paulo@0: dst[4] = 0; paulo@0: } paulo@0: } paulo@0: paulo@0: struct DisabledOption { paulo@0: unsigned char name; paulo@0: unsigned char value; paulo@0: unsigned char name2; paulo@0: char reason[45]; paulo@0: }; paulo@0: paulo@0: /* paulo@0: Semantics: paulo@0: If option name is set to value, paulo@0: then gray out option name2 and draw its value as reason. paulo@0: */ paulo@0: #define N_DISABLED_OPTIONS 12 paulo@0: const struct DisabledOption disabledOptions[N_DISABLED_OPTIONS] = { paulo@0: { OPTIONS_LOCKDOWN, LJLOCK_NOW, paulo@0: OPTIONS_SOFT_DROP, "Lockdown is immediate" }, paulo@0: { OPTIONS_LOCKDOWN, LJLOCK_NOW, paulo@0: OPTIONS_HARD_DROP, "Lockdown is immediate" }, paulo@0: { OPTIONS_LOCKDOWN, LJLOCK_NOW, paulo@0: OPTIONS_LOCK_DELAY, "Lockdown is immediate" }, paulo@0: { OPTIONS_LOCK_DELAY, 128, paulo@0: OPTIONS_LOCKDOWN, "Lockdown is manual" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_DEATH, paulo@0: OPTIONS_SOFT_DROP_SPEED,"Death: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM, paulo@0: OPTIONS_SOFT_DROP_SPEED,"Rhythm: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_DEATH, paulo@0: OPTIONS_SMOOTH_GRAVITY, "Death: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM, paulo@0: OPTIONS_SMOOTH_GRAVITY, "Rhythm: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_DEATH, paulo@0: OPTIONS_SOFT_DROP, "Death: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM, paulo@0: OPTIONS_SOFT_DROP, "Rhythm: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_DEATH, paulo@0: OPTIONS_HARD_DROP, "Death: pieces land instantly" }, paulo@0: { OPTIONS_SPEED_CURVE, LJSPD_RHYTHM, paulo@0: OPTIONS_HARD_DROP, "Rhythm: pieces land instantly" }, paulo@0: }; paulo@0: paulo@0: const char *isDisabledOption(const unsigned char *prefs, int y) { paulo@0: for (int i = 0; i < N_DISABLED_OPTIONS; ++i) { paulo@0: if (y == disabledOptions[i].name2) { paulo@0: int name = disabledOptions[i].name; paulo@0: int value = disabledOptions[i].value; paulo@0: paulo@0: if (prefs[name] == value) { paulo@0: return disabledOptions[i].reason; paulo@0: } paulo@0: } paulo@0: } paulo@0: return NULL; paulo@0: } paulo@0: paulo@0: paulo@0: const char *getOptionsValueStr(char *dst, int line, int value) { paulo@0: const OptionsLine *l = &(commonOptionsMenu[line]); paulo@0: FourCC f = {.i = 0}; paulo@0: const char *desc = NULL; paulo@0: paulo@0: switch (l->style) { paulo@0: case OPTSTYLE_DEFAULT: paulo@0: if (l->valueNames) { paulo@0: f = l->valueNames[value - l->minValue]; paulo@0: } else { paulo@0: siprintf(dst, "%d", value); paulo@0: } paulo@0: break; paulo@0: paulo@0: case OPTSTYLE_FRAMES: paulo@0: if (l->valueNames paulo@0: && value == l->minValue paulo@0: && l->valueNames[0].i) { paulo@0: paulo@0: // override first with name 0 paulo@0: f = l->valueNames[0]; paulo@0: } else if (l->valueNames paulo@0: && value == l->minValue paulo@0: + l->nValues - 1 paulo@0: && l->valueNames[1].i) { paulo@0: paulo@0: // override second with name 1 paulo@0: f = l->valueNames[1]; paulo@0: } else { paulo@0: if (value >= 60) { paulo@0: int ds = value / 6; paulo@0: int s = ds / 10; paulo@0: ds -= s * 10; paulo@0: siprintf(dst, "%d/60 s (%d.%d s)", value, s, ds); paulo@0: } else { paulo@0: int ms = value * 50 / 3; paulo@0: siprintf(dst, "%d/60 s (%d ms)", value, ms); paulo@0: } paulo@0: } break; paulo@0: paulo@0: case OPTSTYLE_FRAC_G: paulo@0: if (value > 6) { paulo@0: int dHz = 600 / value; paulo@0: int Hz = dHz / 10; paulo@0: dHz -= Hz * 10; paulo@0: siprintf(dst, "1/%dG (%d.%d Hz)", value, Hz, dHz); paulo@0: } else if (value > 0) { paulo@0: if (value > 1) { paulo@0: dst[0] = '1'; paulo@0: dst[1] = '/'; paulo@0: dst += 2; paulo@0: } paulo@0: siprintf(dst, "%dG (%d Hz)", value, 60 / value); paulo@0: } else { paulo@0: strcpy(dst, "Instant"); paulo@0: } paulo@0: break; paulo@0: paulo@0: default: paulo@0: strncpy(dst, "Unknown option style.", OPTIONS_VALUE_LEN - 1); paulo@0: dst[OPTIONS_VALUE_LEN - 1] = 0; paulo@0: break; paulo@0: } paulo@0: paulo@0: /* If we have a fourCC, use it. */ paulo@0: if (f.i != 0) { paulo@0: setOptionsValueToFourCC(dst, f); paulo@0: desc = ljGetFourCCDesc(f); paulo@0: } paulo@0: return desc; paulo@0: } paulo@0: paulo@0: void unpackCommonOptions(LJView *v, const unsigned char *prefs) { paulo@0: if (prefs[OPTIONS_GIMMICK] < 255) paulo@0: v->field->gimmick = prefs[OPTIONS_GIMMICK]; paulo@0: if (prefs[OPTIONS_WIDTH] < 255) { paulo@0: int width = prefs[OPTIONS_WIDTH]; paulo@0: v->field->leftWall = (LJ_PF_WID - width) / 2; paulo@0: v->field->rightWall = v->field->leftWall + width; paulo@0: } paulo@0: if (prefs[OPTIONS_HEIGHT] < 255) paulo@0: v->field->ceiling = prefs[OPTIONS_HEIGHT]; paulo@0: if (prefs[OPTIONS_ENTER_ABOVE] < 255) paulo@0: v->field->enterAbove = prefs[OPTIONS_ENTER_ABOVE]; paulo@0: if (prefs[OPTIONS_SPEED_CURVE] < 255) paulo@0: v->field->speedState.curve = prefs[OPTIONS_SPEED_CURVE]; paulo@0: if (prefs[OPTIONS_ENTRY_DELAY] < 255) paulo@0: v->field->areStyle = prefs[OPTIONS_ENTRY_DELAY]; paulo@0: if (prefs[OPTIONS_PIECE_SET] < 255) paulo@0: v->field->pieceSet = prefs[OPTIONS_PIECE_SET]; paulo@0: if (prefs[OPTIONS_RANDOMIZER] < 255) paulo@0: v->field->randomizer = prefs[OPTIONS_RANDOMIZER]; paulo@0: paulo@0: if (prefs[OPTIONS_ROTATION_SYSTEM] < 255) paulo@0: v->field->rotationSystem = prefs[OPTIONS_ROTATION_SYSTEM]; paulo@0: if (prefs[OPTIONS_FLOOR_KICKS] < 255) paulo@0: v->field->maxUpwardKicks = prefs[OPTIONS_FLOOR_KICKS] == N_KICK_LIMITS - 1 paulo@0: ? 128 paulo@0: : prefs[OPTIONS_FLOOR_KICKS]; paulo@0: if (prefs[OPTIONS_HOLD_PIECE] < 255) paulo@0: v->field->holdStyle = prefs[OPTIONS_HOLD_PIECE]; paulo@0: if (prefs[OPTIONS_LOCKDOWN] < 255) paulo@0: v->field->lockReset = prefs[OPTIONS_LOCKDOWN]; paulo@0: if (prefs[OPTIONS_LOCK_DELAY] < 255) paulo@0: v->field->setLockDelay = prefs[OPTIONS_LOCK_DELAY]; paulo@0: if (prefs[OPTIONS_BOTTOM_BLOCKS] < 255) paulo@0: v->field->bottomBlocks = prefs[OPTIONS_BOTTOM_BLOCKS]; paulo@0: paulo@0: if (prefs[OPTIONS_LINE_DELAY] < 255) paulo@0: v->field->setLineDelay = prefs[OPTIONS_LINE_DELAY]; paulo@0: if (prefs[OPTIONS_T_SPIN] < 255) paulo@0: v->field->tSpinAlgo = prefs[OPTIONS_T_SPIN]; paulo@0: if (prefs[OPTIONS_CLEAR_GRAVITY] < 255) paulo@0: v->field->clearGravity = prefs[OPTIONS_CLEAR_GRAVITY]; paulo@0: if (prefs[OPTIONS_GLUING] < 255) paulo@0: v->field->gluing = prefs[OPTIONS_GLUING]; paulo@0: if (prefs[OPTIONS_SCORING] < 255) paulo@0: v->field->scoreStyle = prefs[OPTIONS_SCORING]; paulo@0: if (prefs[OPTIONS_DROP_SCORING] < 255) paulo@0: v->field->dropScoreStyle = prefs[OPTIONS_DROP_SCORING]; paulo@0: if (prefs[OPTIONS_GARBAGE] < 255) paulo@0: v->field->garbageStyle = prefs[OPTIONS_GARBAGE]; paulo@0: paulo@0: if (prefs[OPTIONS_SIDEWAYS_DELAY] < 255) paulo@0: v->control->dasDelay = prefs[OPTIONS_SIDEWAYS_DELAY]; paulo@0: if (prefs[OPTIONS_SIDEWAYS_SPEED] < 255) paulo@0: v->control->dasSpeed = prefs[OPTIONS_SIDEWAYS_SPEED]; paulo@0: if (v->control->dasDelay < v->control->dasSpeed) { paulo@0: v->control->dasDelay = v->control->dasSpeed; paulo@0: } paulo@0: if (prefs[OPTIONS_INITIAL_SIDEWAYS] < 255) paulo@0: v->control->initialDAS = prefs[OPTIONS_INITIAL_SIDEWAYS]; paulo@0: if (prefs[OPTIONS_IRS] < 255) paulo@0: v->control->initialRotate = prefs[OPTIONS_IRS]; paulo@0: if (prefs[OPTIONS_DIAGONAL_MOTION] < 255) paulo@0: v->control->allowDiagonals = prefs[OPTIONS_DIAGONAL_MOTION]; paulo@0: if (prefs[OPTIONS_SOFT_DROP_SPEED] < 255) paulo@0: v->control->softDropSpeed = prefs[OPTIONS_SOFT_DROP_SPEED] - 1; paulo@0: if (prefs[OPTIONS_SOFT_DROP] < 255) paulo@0: v->control->softDropLock = prefs[OPTIONS_SOFT_DROP]; paulo@0: if (prefs[OPTIONS_HARD_DROP] < 255) paulo@0: v->control->hardDropLock = prefs[OPTIONS_HARD_DROP]; paulo@0: paulo@0: if (prefs[OPTIONS_SHADOW] < 255) paulo@0: v->hideShadow = prefs[OPTIONS_SHADOW]; paulo@0: if (prefs[OPTIONS_HIDE_PF] < 255) paulo@0: v->hidePF = prefs[OPTIONS_HIDE_PF]; paulo@0: if (prefs[OPTIONS_NEXT_PIECES] < 255) paulo@0: v->nextPieces = prefs[OPTIONS_NEXT_PIECES]; paulo@0: if (prefs[OPTIONS_SMOOTH_GRAVITY] < 255) paulo@0: v->smoothGravity = prefs[OPTIONS_SMOOTH_GRAVITY]; paulo@0: } paulo@0: paulo@0: void initOptions(unsigned char *prefs) { paulo@0: for (int i = 0; i < OPTIONS_MENU_LEN; ++i) { paulo@0: prefs[i] = commonOptionsMenu[i].startValue; paulo@0: } paulo@0: } paulo@0: paulo@0: LJBits menuReadPad(void); paulo@0: void vsync(void); paulo@0: paulo@0: void options(LJView *v, unsigned char *prefs) { paulo@0: int page = 0, y = 0; paulo@0: int redraw = 2; paulo@0: int done = 0; paulo@0: LJBits lastKeys = ~0; paulo@0: int dasDir = 0; paulo@0: int dasCounter = 0; paulo@0: const OptionsLine const *optionsMenu = commonOptionsMenu; paulo@0: int lastClock = getTime(); paulo@0: int erase = -1; paulo@0: paulo@0: optionsWinInit(); paulo@0: paulo@0: while (!done) { paulo@0: if (redraw) { paulo@0: if (redraw == 2) { paulo@0: redraw = 1; paulo@0: optionsDrawPage(page, prefs); paulo@0: } paulo@0: if (redraw == 1) { paulo@0: if (erase >= 0) { paulo@0: vsync(); paulo@0: optionsDrawRow(prefs, paulo@0: erase - optionsPages[page].start, paulo@0: erase, prefs[erase], 0); paulo@0: erase = -1; paulo@0: } paulo@0: optionsDrawRow(prefs, paulo@0: y - optionsPages[page].start, paulo@0: y, prefs[y], 1); paulo@0: redraw = 0; paulo@0: } paulo@0: } else { paulo@0: optionsIdle(); paulo@0: } paulo@0: paulo@0: LJBits keys = menuReadPad(); paulo@0: LJBits sounds = 0; paulo@0: int lastY = y; paulo@0: LJBits newKeys = keys & ~lastKeys; paulo@0: LJBits dasKeys = 0; paulo@0: paulo@0: if (getTime() != lastClock) { paulo@0: // Handle DAS within options (fixed at 250 ms 30 Hz) paulo@0: lastClock = getTime(); paulo@0: if (keys & dasDir) { paulo@0: ++dasCounter; paulo@0: if (dasCounter >= 15) { paulo@0: dasCounter -= 2; paulo@0: dasKeys = dasDir; paulo@0: } paulo@0: } else { paulo@0: dasCounter = 0; paulo@0: } paulo@0: } paulo@0: paulo@0: if (newKeys & VKEY_UP paulo@0: || ((dasKeys & VKEY_UP) paulo@0: && y > optionsPages[page].start)) { paulo@0: dasDir = VKEY_UP; paulo@0: if (y <= 0) { paulo@0: while (optionsPages[page].name) { paulo@0: ++page; paulo@0: } paulo@0: y = optionsPages[page].start - 1; paulo@0: } else { paulo@0: --y; paulo@0: } paulo@0: } paulo@0: if (newKeys & VKEY_DOWN paulo@0: || ((dasKeys & VKEY_DOWN) paulo@0: && y < optionsPages[page + 1].start - 1)) { paulo@0: dasDir = VKEY_DOWN; paulo@0: ++y; paulo@0: if (y >= optionsPages[page + 1].start paulo@0: && !optionsPages[page + 1].name) { paulo@0: y = 0; paulo@0: } paulo@0: } paulo@0: paulo@0: if (!isDisabledOption(prefs, y)) { paulo@0: if ((newKeys | dasKeys) & VKEY_RIGHT) { paulo@0: int num = prefs[y] + 1; paulo@0: paulo@0: if (num >= optionsMenu[y].minValue + optionsMenu[y].nValues) { paulo@0: prefs[y] = optionsMenu[y].minValue; paulo@0: } else { paulo@0: prefs[y] = num; paulo@0: } paulo@0: paulo@0: sounds |= LJSND_ROTATE; paulo@0: // XXX: need to redraw the whole box (redraw = 2) paulo@0: // if options have become enabled or disabled paulo@0: redraw = 1; paulo@0: dasDir = VKEY_RIGHT; paulo@0: } paulo@0: paulo@0: if ((newKeys | dasKeys) & VKEY_LEFT) { paulo@0: int num = prefs[y] - 1; paulo@0: paulo@0: if (num < optionsMenu[y].minValue) { paulo@0: prefs[y] = optionsMenu[y].minValue + optionsMenu[y].nValues - 1; paulo@0: } else { paulo@0: prefs[y] = num; paulo@0: } paulo@0: paulo@0: sounds |= LJSND_ROTATE; paulo@0: redraw = 1; paulo@0: dasDir = VKEY_LEFT; paulo@0: } paulo@0: } paulo@0: paulo@0: // Rotate left: Go to the top of the previous page if it exists. paulo@0: if (newKeys & VKEY_ROTL) { paulo@0: if (page > 0) { paulo@0: y = optionsPages[page - 1].start; paulo@0: } else { paulo@0: y = 0; paulo@0: } paulo@0: } paulo@0: paulo@0: // Rotate right: If on last page, finish; paulo@0: // otherwise, go to the top of the next page. paulo@0: if (newKeys & VKEY_ROTR) { paulo@0: if (!optionsPages[page + 1].name) { paulo@0: done = 1; paulo@0: } else { paulo@0: y = optionsPages[page + 1].start; paulo@0: } paulo@0: } paulo@0: paulo@0: // Start: finish paulo@0: if (newKeys & VKEY_START) { paulo@0: done = 1; paulo@0: } paulo@0: paulo@0: if (lastY != y) { paulo@0: sounds |= LJSND_SHIFT; paulo@0: paulo@0: // calculate which page the cursor has moved to paulo@0: int lastPage = page; paulo@0: while (y < optionsPages[page].start) { paulo@0: --page; paulo@0: } paulo@0: while (y >= optionsPages[page + 1].start) { paulo@0: ++page; paulo@0: } paulo@0: paulo@0: if (lastPage == page) { paulo@0: erase = lastY; paulo@0: if (redraw < 1) { paulo@0: redraw = 1; paulo@0: } paulo@0: } else { paulo@0: // turning the page paulo@0: sounds |= LJSND_HOLD; paulo@0: redraw = 2; // redraw the whole screen paulo@0: } paulo@0: } paulo@0: lastKeys = keys; paulo@0: paulo@0: if (done) { paulo@0: sounds |= LJSND_LINE; paulo@0: } paulo@0: playSoundEffects(v, sounds, 100); paulo@0: } paulo@0: }