Mercurial > hg > index.fcgi > lj > lj046
comparison src/old_pc_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:f6cb8b5fdacb |
---|---|
1 /* PC option screen for LOCKJAW, an implementation of the Soviet Mind Game | |
2 | |
3 Copyright (C) 2006 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 #include "ljpc.h" | |
26 #include <ctype.h> | |
27 #include "ljpath.h" | |
28 #include <string.h> | |
29 #include "options.h" | |
30 #include "ljlocale.h" | |
31 | |
32 #define OPTIONS_OFFSET 0 | |
33 #define optionsMenu (commonOptionsMenu + OPTIONS_OFFSET) | |
34 | |
35 | |
36 | |
37 #if 0 | |
38 static int getOptionValueByName(int row, const char *value) { | |
39 for (int x = 0; x < optionsMenu[row].nValues; ++x) { | |
40 if (!ustrcmp(value, optionsMenu[row].valueNames[x])) { | |
41 return x + optionsMenu[row].minValue; | |
42 } | |
43 } | |
44 return -1; | |
45 } | |
46 | |
47 static void setOptionValueByNumber(struct LJPrefs *prefs, | |
48 int row, const char *value) { | |
49 if (value[0] >= '0' && value[0] <= '9') { | |
50 int num = atoi(value); | |
51 if (num >= optionsMenu[row].minValue | |
52 && num < optionsMenu[row].minValue + optionsMenu[row].nValues) { | |
53 prefs->number[row] = num; | |
54 } | |
55 } | |
56 } | |
57 | |
58 static void setOptionValueByName(struct LJPrefs *prefs, | |
59 int row, const char *value) { | |
60 int num = getOptionValueByName(row, value); | |
61 | |
62 if (num >= 0) { | |
63 prefs->number[row] = num; | |
64 } | |
65 } | |
66 | |
67 static void setOptionValueByBoolean(struct LJPrefs *prefs, | |
68 int row, const char *value) { | |
69 int num = atoi(value); | |
70 | |
71 if (num >= 0) { | |
72 prefs->number[row] = num ? 1 : 0; | |
73 } | |
74 } | |
75 #endif | |
76 | |
77 /* parse_ini_line ******************* | |
78 */ | |
79 int parse_ini_line(const char *in, char *key, char *var, char *val) | |
80 { | |
81 int c; | |
82 char *kstart = key; | |
83 | |
84 /* Skip whitespace before key */ | |
85 while(*in && isspace(*in)) | |
86 in++; | |
87 | |
88 /* Parse key */ | |
89 if(*in == '[') /* if we have a new key, load it */ | |
90 { | |
91 in++; | |
92 | |
93 /* Skip whitespace before actual key */ | |
94 while(*in && isspace(*in)) | |
95 in++; | |
96 | |
97 for(c = *in++; | |
98 c != 0 && c != ']' && c != '\n' && c != '\r'; | |
99 c = *in++) | |
100 { | |
101 if(!isspace(c)) | |
102 *key++ = c; | |
103 } | |
104 *key = 0; | |
105 /* Strip whitespace after key */ | |
106 do { | |
107 *key-- = 0; | |
108 } while(key >= kstart && isspace(*key)); | |
109 } | |
110 | |
111 /* Skip whitespace before variable */ | |
112 while(*in && isspace(*in)) | |
113 in++; | |
114 if(*in == 0) /* if there is no variable, don't do anything */ | |
115 return 0; | |
116 | |
117 for(c = *in++; | |
118 c != 0 && c != '=' && c != '\n' && c != '\r'; | |
119 c = *in++) | |
120 { | |
121 if(!isspace(c)) | |
122 { | |
123 *var++ = c; | |
124 } | |
125 } | |
126 *var = 0; | |
127 | |
128 /* Skip whitespace before value */ | |
129 while(*in && isspace(*in)) | |
130 in++; | |
131 | |
132 /* Get value */ | |
133 kstart = val; | |
134 for(c = *in++; | |
135 c != 0 && c != '\n' && c != '\r'; | |
136 c = *in++) | |
137 { | |
138 *val++ = c; | |
139 } | |
140 /* Strip whitespace after value */ | |
141 do { | |
142 *val-- = 0; | |
143 } while(val >= kstart && isspace(*val)); | |
144 | |
145 return 0; | |
146 } | |
147 | |
148 static const char ljIniName[] = "lj.ini"; | |
149 | |
150 /** | |
151 * Finds a FourCC in a list. | |
152 * @param needle the fourCC to search for | |
153 * @param haystack a list of fourCCs | |
154 * @param haystackLen the length of this list | |
155 * @return the index within haystack where needle was found | |
156 * or -1 if not found | |
157 */ | |
158 int findFourCC(const char *needle, | |
159 const FourCC *haystack, size_t haystackLen) { | |
160 for (size_t i = 0; i < haystackLen; ++i) { | |
161 if (!strncmp(haystack[i].c, needle, 4)) { | |
162 return i; | |
163 } | |
164 } | |
165 return -1; | |
166 } | |
167 | |
168 void loadOption(struct LJPrefs *prefs, | |
169 const char *name, const char *value) { | |
170 for (int i = 0; i < PC_OPTIONS_MENU_LEN; ++i) { | |
171 if (!strncmp(optionsMenu[i].name.c, name, 4)) { | |
172 if (isdigit(value[0])) { | |
173 unsigned long int n = strtoul(value, NULL, 10); | |
174 if (n >= optionsMenu[i].minValue | |
175 && n < optionsMenu[i].minValue + optionsMenu[i].nValues) { | |
176 prefs->number[i] = n; | |
177 } else { | |
178 allegro_message("ignoring out of range %s=%lu\n", | |
179 name, n); | |
180 } | |
181 } else if (optionsMenu[i].valueNames) { | |
182 int nValueNames = (optionsMenu[i].style == OPTSTYLE_FRAMES | |
183 ? 2 | |
184 : optionsMenu[i].nValues); | |
185 int foundValue = findFourCC(value, optionsMenu[i].valueNames, nValueNames); | |
186 if (optionsMenu[i].style == OPTSTYLE_FRAMES | |
187 && foundValue > 0) { | |
188 foundValue = optionsMenu[i].nValues - 1; | |
189 } | |
190 prefs->number[i] = foundValue + optionsMenu[i].minValue; | |
191 } | |
192 return; | |
193 } | |
194 } | |
195 } | |
196 | |
197 int loadOptions(struct LJPrefs *prefs) { | |
198 FILE *fp = ljfopen(ljIniName, "rt"); | |
199 char key[1024], var[1024], val[1024], input_buf[1024]; | |
200 | |
201 if (!fp) return 0; | |
202 | |
203 key[0] = 0; | |
204 var[0] = 0; | |
205 val[0] = 0; | |
206 | |
207 while(fgets (input_buf, sizeof(input_buf), fp)) { | |
208 parse_ini_line(input_buf, key, var, val); | |
209 | |
210 if(!ustrcmp ("Skin", var)) { | |
211 ustrzcpy(skinName, sizeof(skinName) - 1, val); | |
212 } else { | |
213 loadOption(prefs, var, val); | |
214 } | |
215 } | |
216 fclose(fp); | |
217 | |
218 if (prefs->number[OPTIONS_SIDEWAYS_DELAY] < prefs->number[OPTIONS_SIDEWAYS_SPEED]) { | |
219 prefs->number[OPTIONS_SIDEWAYS_DELAY] = prefs->number[OPTIONS_SIDEWAYS_SPEED]; | |
220 } | |
221 | |
222 return 0; | |
223 } | |
224 | |
225 void saveOption(int i, int n, FILE *out) { | |
226 char name[8], value[8]; | |
227 int nameIdx = -1; | |
228 | |
229 strncpy(name, optionsMenu[i].name.c, 4); | |
230 name[4] = 0; | |
231 | |
232 if (optionsMenu[i].valueNames) { | |
233 if (optionsMenu[i].style == OPTSTYLE_FRAMES) { | |
234 if (n == optionsMenu[i].minValue) { | |
235 nameIdx = 0; | |
236 } else if (n == optionsMenu[i].minValue + optionsMenu[i].nValues - 1) { | |
237 nameIdx = 1; | |
238 } | |
239 } else { | |
240 nameIdx = n - optionsMenu[i].minValue; | |
241 } | |
242 if (nameIdx >= 0 | |
243 && optionsMenu[i].valueNames[nameIdx].i == 0) { | |
244 nameIdx = -1; | |
245 } | |
246 } | |
247 | |
248 if (nameIdx >= 0) { | |
249 strncpy(value, optionsMenu[i].valueNames[nameIdx].c, 4); | |
250 value[4] = 0; | |
251 fprintf(out, "%s=%s\n", | |
252 name, value); | |
253 } else { | |
254 fprintf(out, "%s=%d\n", | |
255 name, n); | |
256 } | |
257 } | |
258 | |
259 void saveOptions(const struct LJPrefs *prefs) { | |
260 FILE *out = ljfopen(ljIniName, "wt"); | |
261 | |
262 if (out) { | |
263 for (int i = 0; i < PC_OPTIONS_MENU_LEN; ++i) { | |
264 saveOption(i, prefs->number[i], out); | |
265 } | |
266 fprintf(out, "Skin=%s\n", | |
267 skinName); | |
268 fclose(out); | |
269 } | |
270 } | |
271 | |
272 void unpackOptions(LJView *v, const struct LJPrefs *prefs) { | |
273 unpackCommonOptions(v, prefs->number); | |
274 | |
275 v->plat->nextAbove = prefs->number[OPTIONS_NEXT_ABOVE]; | |
276 v->showTrails = prefs->number[OPTIONS_TRAILS]; | |
277 autoPause = prefs->number[OPTIONS_AUTO_PAUSE]; | |
278 } | |
279 | |
280 /******************************************************************** | |
281 | |
282 Allegro based option drawing code | |
283 | |
284 ********************************************************************/ | |
285 | |
286 #define OPTIONS_TOP 100 | |
287 #define OPTIONS_ROW_HT 40 | |
288 #define OPTIONS_ROW_LEFT 80 | |
289 #define OPTIONS_ROW_MID 400 | |
290 #define OPTIONS_ROW_RIGHT 760 | |
291 #define OPTIONS_MENU_VIS 7 | |
292 #define OPTIONS_FONT aver32 | |
293 | |
294 | |
295 /** | |
296 * @param y number of option to draw | |
297 * @param hilite bitfield: 1=focused, 0=not | |
298 */ | |
299 void optionsDrawRow(const unsigned char *prefs, | |
300 int dstY, int line, int value, int hilite) { | |
301 unsigned int ht = text_height(OPTIONS_FONT); | |
302 int buttonY = OPTIONS_TOP + OPTIONS_ROW_HT * dstY; | |
303 int rowBg = bgColor; | |
304 const char *nameText; | |
305 char altNameText[8]; | |
306 char valueText[OPTIONS_VALUE_LEN]; | |
307 const char *valueOverride = isDisabledOption(prefs, line); | |
308 int textcolor = fgColor; | |
309 const char *valueDesc = NULL; | |
310 | |
311 { | |
312 nameText = ljGetFourCCName(optionsMenu[line].name); | |
313 if (!nameText) { | |
314 strncpy(altNameText, optionsMenu[line].name.c, 4); | |
315 altNameText[4] = 0; | |
316 nameText = altNameText; | |
317 } | |
318 } | |
319 | |
320 if (valueOverride) { | |
321 hilite |= 2; | |
322 textcolor = makecol(128, 128, 128); | |
323 } | |
324 | |
325 if (hilite == 3) { | |
326 rowBg = makecol(204, 204, 204); | |
327 } else if (hilite == 1) { | |
328 rowBg = hiliteColor; | |
329 } | |
330 | |
331 // If the value of this option is within range, format it as a string. | |
332 if (value >= optionsMenu[line].minValue | |
333 && value < optionsMenu[line].minValue + optionsMenu[line].nValues) { | |
334 if (valueOverride) { | |
335 ustrzcpy(valueText, sizeof(valueText), "overridden"); | |
336 valueDesc = valueOverride; | |
337 } else { | |
338 valueDesc = getOptionsValueStr(valueText, line + OPTIONS_OFFSET, value); | |
339 } | |
340 } else { | |
341 valueText[0] = '\0'; | |
342 } | |
343 | |
344 // draw current option | |
345 acquire_screen(); | |
346 rectfill(screen, | |
347 OPTIONS_ROW_LEFT, buttonY, | |
348 OPTIONS_ROW_RIGHT - 1, buttonY + OPTIONS_ROW_HT - 1, | |
349 rowBg); | |
350 textout_ex(screen, OPTIONS_FONT, nameText, | |
351 OPTIONS_ROW_LEFT + 8, buttonY + (OPTIONS_ROW_HT - ht) / 2, | |
352 textcolor, rowBg); | |
353 textout_ex(screen, OPTIONS_FONT, | |
354 valueText, | |
355 OPTIONS_ROW_MID, buttonY + (OPTIONS_ROW_HT - ht) / 2, | |
356 textcolor, rowBg); | |
357 | |
358 // For an enabled selected item, draw the frame | |
359 if (hilite == 1) { | |
360 rect(screen, | |
361 OPTIONS_ROW_LEFT, buttonY, | |
362 OPTIONS_ROW_RIGHT - 1, buttonY + OPTIONS_ROW_HT - 1, | |
363 fgColor); | |
364 } | |
365 | |
366 // For a selected item, draw the help text | |
367 if (hilite & 1) { | |
368 buttonY = OPTIONS_TOP + OPTIONS_ROW_HT * OPTIONS_MENU_VIS; | |
369 rectfill(screen, | |
370 OPTIONS_ROW_LEFT, buttonY, | |
371 OPTIONS_ROW_RIGHT - 1, buttonY + OPTIONS_ROW_HT * 5 / 2 - 1, | |
372 bgColor); | |
373 | |
374 const char *descText = ljGetFourCCDesc(optionsMenu[line].name); | |
375 if (descText) { | |
376 textout_ex(screen, OPTIONS_FONT, descText, | |
377 OPTIONS_ROW_LEFT, | |
378 buttonY + OPTIONS_ROW_HT - ht / 2, | |
379 textcolor, bgColor); | |
380 } | |
381 if (valueDesc) { | |
382 textout_ex(screen, OPTIONS_FONT, valueDesc, | |
383 OPTIONS_ROW_LEFT, | |
384 buttonY + 2 * OPTIONS_ROW_HT - ht / 2, | |
385 textcolor, bgColor); | |
386 } | |
387 } | |
388 | |
389 release_screen(); | |
390 } | |
391 | |
392 void optionsClearRow(int dstY, int hilite) { | |
393 int buttonY = OPTIONS_TOP + OPTIONS_ROW_HT * dstY; | |
394 rectfill(screen, | |
395 OPTIONS_ROW_LEFT, buttonY, | |
396 OPTIONS_ROW_RIGHT - 1, buttonY + OPTIONS_ROW_HT * 5 / 2 - 1, | |
397 bgColor); | |
398 } | |
399 | |
400 void optionsDrawPage(int page, const unsigned char *prefs) { | |
401 int nPages = 0; | |
402 for (; optionsPages[nPages].name; ++nPages) { } | |
403 | |
404 vsync(); | |
405 acquire_screen(); | |
406 rectfill(screen, 320, 32, SCREEN_W - 1, 63, bgColor); | |
407 textprintf_right_ex(screen, aver32, | |
408 SCREEN_W - 16, 32, fgColor, -1, | |
409 "(%d/%d) %s", | |
410 page + 1, nPages, optionsPages[page].name); | |
411 | |
412 for (int i = optionsPages[page].start; | |
413 i < optionsPages[page + 1].start; ++i) { | |
414 optionsDrawRow(prefs, i - optionsPages[page].start, | |
415 i, prefs[i], 0); | |
416 } | |
417 for (int i = optionsPages[page + 1].start; | |
418 i < optionsPages[page].start + OPTIONS_MENU_VIS; ++i) { | |
419 optionsClearRow(i - optionsPages[page].start, 0); | |
420 } | |
421 release_screen(); | |
422 } | |
423 | |
424 void optionsWinInit(void) { | |
425 acquire_screen(); | |
426 clear_to_color(screen, bgColor); | |
427 textout_ex(screen, aver32, "LOCKJAW > Options", 16, 32, fgColor, -1); | |
428 textout_ex(screen, aver32, "Rotate: change page; Up/Down: select", 16, 522, fgColor, -1); | |
429 textout_ex(screen, aver32, "Left/Right change; Enter: exit", 16, 552, fgColor, -1); | |
430 release_screen(); | |
431 | |
432 } | |
433 | |
434 void optionsIdle(void) { | |
435 rest(10); | |
436 } |