1    | /*	SCCS Id: @(#)tiletext.c	3.3	1999/10/24	*/
2    | /* NetHack may be freely redistributed.  See license for details. */
3    | 
4    | #include "config.h"
5    | #include "tile.h"
6    | 
7    | pixval ColorMap[3][MAXCOLORMAPSIZE];
8    | int colorsinmap;
9    | pixval MainColorMap[3][MAXCOLORMAPSIZE];
10   | int colorsinmainmap;
11   | 
12   | static short color_index[MAXCOLORMAPSIZE];
13   | static int num_colors;
14   | static char charcolors[MAXCOLORMAPSIZE];
15   | 
16   | static int placeholder_init = 0;
17   | static pixel placeholder[TILE_Y][TILE_X];
18   | static FILE *tile_file;
19   | static int tile_set, tile_set_indx;
20   | #if (TILE_X==8)
21   | static const char *text_sets[] = { "monthin.txt", "objthin.txt", "oththin.txt" };
22   | #else
23   | static const char *text_sets[] = { "monsters.txt", "objects.txt", "other.txt" };
24   | #endif
25   | 
26   | extern const char *FDECL(tilename, (int, int));
27   | static void FDECL(read_text_colormap, (FILE *));
28   | static boolean FDECL(write_text_colormap, (FILE *));
29   | static boolean FDECL(read_txttile, (FILE *, pixel(*)[TILE_X]));
30   | static void FDECL(write_txttile, (FILE *, pixel(*)[TILE_X]));
31   | 
32   | /* Ugh.  DICE doesn't like %[A-Z], so we have to spell it out... */
33   | #define FORMAT_STRING \
34   | "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789] = (%d, %d, %d) "
35   | 
36   | static void
37   | read_text_colormap(txtfile)
38   | FILE *txtfile;
39   | {
40   | 	int i, r, g, b;
41   | 	char c[2];
42   | 
43   | 	for (i = 0; i < MAXCOLORMAPSIZE; i++)
44   | 		color_index[i] = -1;
45   | 
46   | 	num_colors = 0;
47   | 	while (fscanf(txtfile, FORMAT_STRING, c, &r, &g, &b) == 4) {
48   | 		color_index[(int) c[0]] = num_colors;
49   | 		ColorMap[CM_RED][num_colors] = r;
50   | 		ColorMap[CM_GREEN][num_colors] = g;
51   | 		ColorMap[CM_BLUE][num_colors] = b;
52   | 		num_colors++;
53   | 	}
54   | 	colorsinmap = num_colors;
55   | }
56   | 
57   | #undef FORMAT_STRING
58   | 
59   | static boolean
60   | write_text_colormap(txtfile)
61   | FILE *txtfile;
62   | {
63   | 	int i;
64   | 	char c;
65   | 
66   | 	num_colors = colorsinmainmap;
67   | 	if (num_colors > 62) {
68   | 		Fprintf(stderr, "too many colors (%d)\n", num_colors);
69   | 		return FALSE;
70   | 	}
71   | 	for (i = 0; i < num_colors; i++) {
72   | 		if (i < 26) c = 'A' + i;
73   | 		else if (i < 52) c = 'a' + i - 26;
74   | 		else c = '0' + i - 52;
75   | 
76   | 		charcolors[i] = c;
77   | 		Fprintf(txtfile, "%c = (%d, %d, %d)\n", c,
78   | 						(int)MainColorMap[CM_RED][i],
79   | 						(int)MainColorMap[CM_GREEN][i],
80   | 						(int)MainColorMap[CM_BLUE][i]);
81   | 	}
82   | 	return TRUE;
83   | }
84   | 
85   | static boolean
86   | read_txttile(txtfile, pixels)
87   | FILE *txtfile;
88   | pixel (*pixels)[TILE_X];
89   | {
90   | 	int ph, i, j, k;
91   | 	char buf[BUFSZ], ttype[BUFSZ];
92   | 	const char *p;
93   | 	char c[2];
94   | 
95   | 	if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0)
96   | 		return FALSE;
97   | 	
98   | 	ph = strcmp(ttype, "placeholder") == 0;
99   | 
100  | 	if (!ph && strcmp(ttype,"tile") != 0)
101  | 		Fprintf(stderr,
102  | 			"Keyword \"%s\" unexpected for entry %d\n",
103  | 			ttype, i);
104  | 
105  | 	if (tile_set != 0) {
106  | 	    /* check tile name, but not relative number, which will
107  | 	     * change when tiles are added
108  | 	     */
109  | 	    p = tilename(tile_set, tile_set_indx);
110  | 	    if (p && strcmp(p, buf)) {
111  | 		Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n",
112  | 				tile_set_indx, i, text_sets[tile_set-1]);
113  | 		Fprintf(stderr, "\tfound '%s' while expecting '%s'\n",
114  | 				buf, p);
115  | 	    }
116  | 	}
117  | 	tile_set_indx++;
118  | 		
119  | 	/* look for non-whitespace at each stage */
120  | 	if (fscanf(txtfile, "%1s", c) < 0) {
121  | 		Fprintf(stderr, "unexpected EOF\n");
122  | 		return FALSE;
123  | 	}
124  | 	if (c[0] != '{') {
125  | 		Fprintf(stderr, "didn't find expected '{'\n");
126  | 		return FALSE;
127  | 	}
128  | 	for (j = 0; j < TILE_Y; j++) {
129  | 		for (i = 0; i < TILE_X; i++) {
130  | 			if (fscanf(txtfile, "%1s", c) < 0) {
131  | 				Fprintf(stderr, "unexpected EOF\n");
132  | 				return FALSE;
133  | 			}
134  | 			k = color_index[(int) c[0]];
135  | 			if (k == -1)
136  | 				Fprintf(stderr,
137  | 					"color %c not in colormap!\n", c[0]);
138  | 			else {
139  | 				pixels[j][i].r = ColorMap[CM_RED][k];
140  | 				pixels[j][i].g = ColorMap[CM_GREEN][k];
141  | 				pixels[j][i].b = ColorMap[CM_BLUE][k];
142  | 			}
143  | 		}
144  | 	}
145  | 	if ( ph ) {
146  | 	    /* remember it for later */
147  | 	    memcpy( placeholder, pixels, sizeof(placeholder) );
148  | 	}
149  | 	if (fscanf(txtfile, "%1s ", c) < 0) {
150  | 		Fprintf(stderr, "unexpected EOF\n");
151  | 		return FALSE;
152  | 	}
153  | 	if (c[0] != '}') {
154  | 		Fprintf(stderr, "didn't find expected '}'\n");
155  | 		return FALSE;
156  | 	}
157  | #ifdef _DCC
158  | 	/* DICE again... it doesn't seem to eat whitespace after the } like
159  | 	 * it should, so we have to do so manually.
160  | 	 */
161  | 	while ((*c = fgetc(txtfile)) != EOF && isspace(*c))
162  | 		;
163  | 	ungetc(*c, txtfile);
164  | #endif
165  | 	return TRUE;
166  | }
167  | 
168  | static void
169  | write_txttile(txtfile, pixels)
170  | FILE *txtfile;
171  | pixel (*pixels)[TILE_X];
172  | {
173  | 	const char *p;
174  | 	const char *type;
175  | 	int i, j, k;
176  | 
177  | 	if ( memcmp(placeholder, pixels, sizeof(placeholder)) == 0 )
178  | 	    type = "placeholder";
179  | 	else
180  | 	    type = "tile";
181  | 
182  | 	if (tile_set == 0)
183  | 		Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx);
184  | 	else {
185  | 		p = tilename(tile_set, tile_set_indx);
186  | 		if (p)
187  | 		    Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p);
188  | 		else
189  | 		    Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx);
190  | 	}
191  | 	tile_set_indx++;
192  | 
193  | 	Fprintf(txtfile, "{\n");
194  | 	for (j = 0; j < TILE_Y; j++) {
195  | 		Fprintf(txtfile, "  ");
196  | 		for (i = 0; i < TILE_X; i++) {
197  | 			for (k = 0; k < num_colors; k++) {
198  | 				if (ColorMap[CM_RED][k] == pixels[j][i].r &&
199  | 				    ColorMap[CM_GREEN][k] == pixels[j][i].g &&
200  | 				    ColorMap[CM_BLUE][k] == pixels[j][i].b)
201  | 					break;
202  | 			}
203  | 			if (k >= num_colors)
204  | 				Fprintf(stderr, "color not in colormap!\n");
205  | 			(void) fputc(charcolors[k], txtfile);
206  | 		}
207  | 		Fprintf(txtfile, "\n");
208  | 	}
209  | 	Fprintf(txtfile, "}\n");
210  | }
211  | 
212  | /* initialize main colormap from globally accessed ColorMap */
213  | void
214  | init_colormap()
215  | {
216  | 	int i;
217  | 
218  | 	colorsinmainmap = colorsinmap;
219  | 	for (i = 0; i < colorsinmap; i++) {
220  | 		MainColorMap[CM_RED][i] = ColorMap[CM_RED][i];
221  | 		MainColorMap[CM_GREEN][i] = ColorMap[CM_GREEN][i];
222  | 		MainColorMap[CM_BLUE][i] = ColorMap[CM_BLUE][i];
223  | 	}
224  | }
225  | 
226  | /* merge new colors from ColorMap into MainColorMap */
227  | void
228  | merge_colormap()
229  | {
230  | 	int i, j;
231  | 
232  | 	for (i = 0; i < colorsinmap; i++) {
233  | 		for (j = 0; j < colorsinmainmap; j++) {
234  | 		    if (MainColorMap[CM_RED][j] == ColorMap[CM_RED][i] &&
235  | 			MainColorMap[CM_GREEN][j] == ColorMap[CM_GREEN][i] &&
236  | 			MainColorMap[CM_BLUE][j] == ColorMap[CM_BLUE][i])
237  | 			    break;
238  | 		}
239  | 		if (j >= colorsinmainmap) {	/* new color */
240  | 		    if (colorsinmainmap >= MAXCOLORMAPSIZE) {
241  | 			Fprintf(stderr,
242  | 			    "Too many colors to merge -- excess ignored.\n");
243  | 		    }
244  | 		    j = colorsinmainmap;
245  | 		    MainColorMap[CM_RED][j] = ColorMap[CM_RED][i];
246  | 		    MainColorMap[CM_GREEN][j] = ColorMap[CM_GREEN][i];
247  | 		    MainColorMap[CM_BLUE][j] = ColorMap[CM_BLUE][i];
248  | 		    colorsinmainmap++;
249  | 		}
250  | 	}
251  | }
252  | 
253  | boolean
254  | fopen_text_file(filename, type)
255  | const char *filename;
256  | const char *type;
257  | {
258  | 	const char *p;
259  | 	int i;
260  | 
261  | 	if (tile_file != (FILE *)0) {
262  | 		Fprintf(stderr, "can only open one text file at at time\n");
263  | 		return FALSE;
264  | 	}
265  | 
266  | 	tile_file = fopen(filename, type);
267  | 	if (tile_file == (FILE *)0) {
268  | 		Fprintf(stderr, "cannot open text file %s\n", filename);
269  | 		return FALSE;
270  | 	}
271  | 
272  | 	p = rindex(filename, '/');
273  | 	if (p) p++;
274  | 	else p = filename;
275  | 
276  | 	tile_set = 0;
277  | 	for (i = 0; i < SIZE(text_sets); i++) {
278  | 		if (!strcmp(p, text_sets[i]))
279  | 			tile_set = i+1;
280  | 	}
281  | 	tile_set_indx = 0;
282  | 
283  | 	if (!strcmp(type, RDTMODE)) {
284  | 		/* Fill placeholder with noise */
285  | 		if ( !placeholder_init ) {
286  | 		    placeholder_init++;
287  | 		    for ( i=0; i<sizeof(placeholder); i++ )
288  | 			((char*)placeholder)[i]=i%256;
289  | 		}
290  | 
291  | 		read_text_colormap(tile_file);
292  | 		if (!colorsinmainmap)
293  | 			init_colormap();
294  | 		else
295  | 			merge_colormap();
296  | 		return TRUE;
297  | 	} else if (!strcmp(type, WRTMODE)) {
298  | 		if (!colorsinmainmap) {
299  | 			Fprintf(stderr, "no colormap set yet\n");
300  | 			return FALSE;
301  | 		}
302  | 		return(write_text_colormap(tile_file));
303  | 	} else {
304  | 		Fprintf(stderr, "bad mode (%s) for fopen_text_file\n", type);
305  | 		return FALSE;
306  | 	}
307  | }
308  | 
309  | boolean
310  | read_text_tile(pixels)
311  | pixel (*pixels)[TILE_X];
312  | {
313  | 	return(read_txttile(tile_file, pixels));
314  | }
315  | 
316  | boolean
317  | write_text_tile(pixels)
318  | pixel (*pixels)[TILE_X];
319  | {
320  | 	write_txttile(tile_file, pixels);
321  | 	return TRUE;
322  | }
323  | 
324  | int
325  | fclose_text_file()
326  | {
327  | 	int ret;
328  | 
329  | 	ret = fclose(tile_file);
330  | 	tile_file = (FILE *)0;
331  | 	return ret;
332  | }