1 /*
2 * File: grafmode.c
3 * Purpose: load a list of possible graphics modes.
4 *
5 * Copyright (c) 2011 Brett Reid
6 *
7 * This work is free software; you can redistribute it and/or modify it
8 * under the terms of:
9 *
10 * b) the "Angband license":
11 * This software may be copied and distributed for educational, research,
12 * and not for profit purposes provided that this copyright and statement
13 * are included in all such copies. Other copyrights may also apply.
14 */
15
16 #include "c-angband.h"
17 #include "grafmode.h"
18 #include "../common/parser.h"
19
20 /* Forward-compatibility with V4XX */
21 #define mem_zalloc ralloc
22 #define mem_free rnfree
23 /* XXX */
24
25 graphics_mode *graphics_modes = NULL;
26 graphics_mode *current_graphics_mode = NULL;
27 int graphics_mode_high_id = 0;
28 int num_graphics_modes = 0;
29
parse_graf_n(struct parser * p)30 static enum parser_error parse_graf_n(struct parser *p) {
31 int i;
32 graphics_mode *list = parser_priv(p);
33 graphics_mode *mode = malloc(sizeof(graphics_mode));
34 if (!mode) {
35 return PARSE_ERROR_OUT_OF_MEMORY;
36 }
37 mode->pNext = list;
38 mode->grafID = parser_getuint(p, "index");
39 strncpy(mode->menuname, parser_getstr(p, "menuname"), 32);
40
41 mode->alphablend = 0;
42 mode->overdrawRow = 0;
43 mode->overdrawMax = 0;
44 strncpy(mode->file, "", 32);
45
46 strncpy(mode->pref, "none", 32);
47
48 /* MAngband-specific properties: */
49 strncpy(mode->mask, "", 32);
50 mode->transparent = 0;
51 mode->lightmap = 0;
52 for (i = 0; i < 4; i++) {
53 mode->light_offset[i][0] = 0;
54 mode->light_offset[i][1] = 0;
55 }
56 parser_setpriv(p, mode);
57 return PARSE_ERROR_NONE;
58 }
59
parse_graf_i(struct parser * p)60 static enum parser_error parse_graf_i(struct parser *p) {
61 graphics_mode *mode = parser_priv(p);
62 if (!mode) {
63 return PARSE_ERROR_INVALID_VALUE;
64 }
65 mode->cell_width = parser_getuint(p, "wid");
66 mode->cell_height = parser_getuint(p, "hgt");
67 strncpy(mode->file, parser_getstr(p, "filename"), 32);
68 return PARSE_ERROR_NONE;
69 }
70
parse_graf_m(struct parser * p)71 static enum parser_error parse_graf_m(struct parser *p) {
72 graphics_mode *mode = parser_priv(p);
73 if (!mode) {
74 return PARSE_ERROR_INVALID_VALUE;
75 }
76 strncpy(mode->mask, parser_getstr(p, "filename"), 32);
77 return PARSE_ERROR_NONE;
78 }
79
parse_graf_p(struct parser * p)80 static enum parser_error parse_graf_p(struct parser *p) {
81 graphics_mode *mode = parser_priv(p);
82 if (!mode) {
83 return PARSE_ERROR_INVALID_VALUE;
84 }
85 strncpy(mode->pref, parser_getstr(p, "prefname"), 32);
86 return PARSE_ERROR_NONE;
87 }
88
parse_graf_x(struct parser * p)89 static enum parser_error parse_graf_x(struct parser *p) {
90 graphics_mode *mode = parser_priv(p);
91 if (!mode) {
92 return PARSE_ERROR_INVALID_VALUE;
93 }
94 mode->alphablend = parser_getuint(p, "alpha");
95 mode->overdrawRow = parser_getuint(p, "row");
96 mode->overdrawMax = parser_getuint(p, "max");
97 return PARSE_ERROR_NONE;
98 }
99
parse_graf_t(struct parser * p)100 static enum parser_error parse_graf_t(struct parser *p) {
101 graphics_mode *mode = parser_priv(p);
102 if (!mode) {
103 return PARSE_ERROR_INVALID_VALUE;
104 }
105 mode->transparent = parser_getuint(p, "transparent");
106 mode->lightmap = parser_getuint(p, "lightmap");
107 if (!mode->transparent) mode->lightmap = 0;
108 return PARSE_ERROR_NONE;
109 }
110
parse_graf_l(struct parser * p)111 static enum parser_error parse_graf_l(struct parser *p) {
112 graphics_mode *mode = parser_priv(p);
113 u32b level;
114 if (!mode) {
115 return PARSE_ERROR_INVALID_VALUE;
116 }
117 level = parser_getuint(p, "level");
118 if (level > 3) {
119 return PARSE_ERROR_INVALID_VALUE;
120 }
121 mode->light_offset[level][0] = parser_getuint(p, "yoffset");
122 mode->light_offset[level][1] = parser_getuint(p, "xoffset");
123 return PARSE_ERROR_NONE;
124 }
125
init_parse_grafmode(void)126 static struct parser *init_parse_grafmode(void) {
127 struct parser *p = parser_new();
128 parser_setpriv(p, NULL);
129
130 parser_reg(p, "V sym version", ignored);
131 parser_reg(p, "N uint index str menuname", parse_graf_n);
132 parser_reg(p, "I uint wid uint hgt str filename", parse_graf_i);
133 parser_reg(p, "M str maskfilename", parse_graf_m);
134 parser_reg(p, "P str prefname", parse_graf_p);
135 parser_reg(p, "X uint alpha uint row uint max", parse_graf_x);
136 parser_reg(p, "T uint transparent uint lightmap", parse_graf_t);
137 parser_reg(p, "L uint level int yoffset int xoffset", parse_graf_l);
138
139 return p;
140 }
141
finish_parse_grafmode(struct parser * p)142 errr finish_parse_grafmode(struct parser *p) {
143 graphics_mode *mode, *n;
144 int max = 0;
145 int count = 0;
146 int i;
147
148 /* see how many graphics modes we have and what the highest index is */
149 if (p) {
150 mode = parser_priv(p);
151 while (mode) {
152 if (mode->grafID > max) {
153 max = mode->grafID;
154 }
155 count++;
156 mode = mode->pNext;
157 }
158 }
159
160 /* copy the loaded modes to the global variable */
161 graphics_modes = realloc(graphics_modes, sizeof(graphics_mode) * (count+1+num_graphics_modes));
162 for (i = 0; i < num_graphics_modes; i++) {
163 graphics_modes[i].pNext = &(graphics_modes[i+1]);
164 }
165 if (p) {
166 mode = parser_priv(p);
167 for (i = count-1; i >= 0; i--, mode = mode->pNext) {
168 int j = i + num_graphics_modes;
169 memcpy(&(graphics_modes[j]), mode, sizeof(graphics_mode));
170 /* HACK -- auto-assign grafID, unlike V. */
171 graphics_modes[j].grafID = j + 1;
172 graphics_modes[j].pNext = &(graphics_modes[j+1]);
173 }
174 }
175 num_graphics_modes += count;
176 count = num_graphics_modes;
177
178 /* hardcode the no graphics option */
179 graphics_modes[count].pNext = NULL;
180 graphics_modes[count].grafID = GRAPHICS_NONE;
181 graphics_modes[count].alphablend = 0;
182 graphics_modes[count].overdrawRow = 0;
183 graphics_modes[count].overdrawMax = 0;
184 strncpy(graphics_modes[count].pref, "none", 8);
185 strncpy(graphics_modes[count].file, "", 32);
186 strncpy(graphics_modes[count].menuname, "None", 32);
187
188 graphics_mode_high_id = count;
189
190 /* set the default graphics mode to be no graphics */
191 current_graphics_mode = &(graphics_modes[count]);
192
193 if (p) {
194 mode = parser_priv(p);
195 while (mode) {
196 n = mode->pNext;
197 mem_free(mode);
198 mode = n;
199 }
200
201 parser_setpriv(p, NULL);
202 parser_destroy(p);
203 }
204 return PARSE_ERROR_NONE;
205 }
206
print_error(const char * name,struct parser * p)207 static void print_error(const char *name, struct parser *p) {
208 struct parser_state s;
209 parser_getstate(p, &s);
210 printf("Parse error in %s line %d column %d: %s: %s\n", name,
211 s.line, s.col, s.msg, parser_error_str[s.error]);
212 /* FIXME? message_flush(); */
213 }
214
add_graphics_modes(const char * filename,bool buildpath)215 bool add_graphics_modes(const char *filename, bool buildpath) {
216 char buf[1024];
217
218 ang_file *f;
219 struct parser *p;
220 errr e = 0;
221
222 int line_no = 0;
223
224 /* Build the filename */
225 if (buildpath)
226 path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, filename);
227 else
228 my_strcpy(buf, filename, sizeof(buf));
229
230 f = file_open(buf, MODE_READ, -1);
231 if (!f) {
232 e = PARSE_ERROR_GENERIC;
233 } else {
234 char line[1024];
235
236 p = init_parse_grafmode();
237 while (file_getl(f, line, sizeof line)) {
238 line_no++;
239 e = parser_parse(p, line);
240 if (e != PARSE_ERROR_NONE) {
241 print_error(buf, p);
242 break;
243 }
244 }
245
246 finish_parse_grafmode(p);
247 file_close(f);
248 }
249
250 /* Result */
251 return e == PARSE_ERROR_NONE;
252 }
253
init_graphics_modes(const char * filename)254 bool init_graphics_modes(const char *filename) {
255 char buf[1024];
256 ang_dir *dir;
257 errr e = 0;
258
259 /* Read the 'main' file first */
260 if (filename)
261 add_graphics_modes(filename, TRUE);
262
263 /** Scan for definitions **/
264
265 /* Open the directory */
266 dir = my_dopen(ANGBAND_DIR_XTRA_GRAF);
267 if (!dir) return FALSE;
268
269 /* Read every filename */
270 while (my_dread(dir, buf, sizeof buf)) {
271 /* Skip 'main' file (it has already been read) */
272 if (filename && !my_stricmp(buf, filename))
273 continue;
274 /* Check for file extension */
275 if (isuffix(buf, ".txt"))
276 add_graphics_modes(buf, TRUE);
277 }
278
279 /* Done */
280 my_dclose(dir);
281
282 /* Result */
283 return e == PARSE_ERROR_NONE;
284 }
285
286 #if 0
287 bool init_graphics_modes(const char *filename) {
288 char buf[1024];
289
290 ang_file *f;
291 struct parser *p;
292 errr e = 0;
293
294 int line_no = 0;
295
296 /* Build the filename */
297 path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, filename);
298
299 f = file_open(buf, MODE_READ, -1);
300 if (!f) {
301 finish_parse_grafmode(NULL);
302 } else {
303 char line[1024];
304
305 p = init_parse_grafmode();
306 while (file_getl(f, line, sizeof line)) {
307 line_no++;
308
309 e = parser_parse(p, line);
310 if (e != PARSE_ERROR_NONE) {
311 print_error(buf, p);
312 break;
313 }
314 }
315
316 finish_parse_grafmode(p);
317 file_close(f);
318 }
319
320 /* Result */
321 return e == PARSE_ERROR_NONE;
322 }
323 #endif
324
close_graphics_modes(void)325 void close_graphics_modes(void) {
326 if (graphics_modes) {
327 mem_free(graphics_modes);
328 graphics_modes = NULL;
329 }
330 num_graphics_modes = 0;
331 graphics_mode_high_id = 0;
332 }
333
get_graphics_mode(byte id)334 graphics_mode* get_graphics_mode(byte id) {
335 graphics_mode *test = graphics_modes;
336 while (test) {
337 if (test->grafID == id) {
338 return test;
339 }
340 test = test->pNext;
341 }
342 return NULL;
343 }
344
get_num_graphics_modes(void)345 size_t get_num_graphics_modes(void) {
346 return num_graphics_modes;
347 }
348