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