1 /* SCCS Id: @(#)tilemap.c 3.4 2000/06/04 */
2 /* NetHack may be freely redistributed. See license for details. */
5 * This source file is compiled twice:
6 * once without TILETEXT defined to make tilemap.{o,obj},
7 * then again with it defined to produce tiletxt.{o,obj}.
12 const char * FDECL(tilename, (int, int));
13 void NDECL(init_tilemap);
14 void FDECL(process_substitutions, (FILE *));
16 #if defined(MICRO) || defined(WIN32)
18 #if !defined(MSDOS) && !defined(WIN32)
19 extern void FDECL(exit, (int));
25 #define OTH_GLYPH 3 /* fortunately unnecessary */
27 /* note that the ifdefs here should be the opposite sense from monst.c/
32 int sequence, predecessor;
35 #ifndef CHARON /* not supported yet */
36 { MON_GLYPH, PM_HELL_HOUND, "Cerberus" },
38 /* commented out in monst.c at present */
39 { MON_GLYPH, PM_SHOCKING_SPHERE, "beholder" },
40 { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" },
41 { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" },
42 { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" },
44 { MON_GLYPH, PM_JABBERWOCK, "Keystone Kop" },
45 { MON_GLYPH, PM_JABBERWOCK, "Kop Sergeant" },
46 { MON_GLYPH, PM_JABBERWOCK, "Kop Lieutenant" },
47 { MON_GLYPH, PM_JABBERWOCK, "Kop Kaptain" },
49 { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" },
50 #ifndef CHARON /* not supported yet */
51 { MON_GLYPH, PM_CROESUS, "Charon" },
54 { MON_GLYPH, PM_FAMINE, "mail daemon" },
57 { MON_GLYPH, PM_SAMURAI, "tourist" },
59 /* commented out in monst.c at present */
60 { MON_GLYPH, PM_SHAMAN_KARNOV, "Earendil" },
61 { MON_GLYPH, PM_SHAMAN_KARNOV, "Elwing" },
63 { MON_GLYPH, PM_LORD_SATO, "Twoflower" },
65 /* commented out in monst.c at present */
66 { MON_GLYPH, PM_CHROMATIC_DRAGON, "Goblin King" },
67 { MON_GLYPH, PM_NEANDERTHAL, "High-elf" },
69 { MON_GLYPH, PM_ROSHI, "guide" },
72 { OBJ_GLYPH, CLUB, "rubber hose" },
74 /* objects commented out in objects.c at present */
75 { OBJ_GLYPH, SILVER_DRAGON_SCALE_MAIL, "shimmering dragon scale mail" },
76 { OBJ_GLYPH, SILVER_DRAGON_SCALES, "shimmering dragon scales" },
78 { OBJ_GLYPH, LEATHER_JACKET, "Hawaiian shirt" },
79 { OBJ_GLYPH, LEATHER_JACKET, "T-shirt" },
80 { OBJ_GLYPH, LOCK_PICK, "credit card" },
81 { OBJ_GLYPH, MAGIC_LAMP, "expensive camera" },
84 { OBJ_GLYPH, TOWEL, "saddle" },
86 /* allow slime mold to look like slice of pizza, since we
87 * don't know what a slime mold should look like when renamed anyway
90 { OBJ_GLYPH, SCR_STINKING_CLOUD+4, "stamped / mail" },
97 * Some entries in glyph2tile[] should be substituted for on various levels.
98 * The tiles used for the substitute entries will follow the usual ones in
99 * other.til in the order given here, which should have every substitution
100 * for the same set of tiles grouped together. You will have to change
101 * more code in process_substitutions()/substitute_tiles() if the sets
102 * overlap in the future.
105 int first_glyph, last_glyph;
106 const char *sub_name; /* for explanations */
107 const char *level_test;
109 { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
110 "mine walls", "In_mines(plev)" },
111 { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
112 "gehennom walls", "In_hell(plev)" },
113 { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
114 "knox walls", "Is_knox(plev)" },
115 { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall,
116 "sokoban walls", "In_sokoban(plev)" }
123 * entry is the position of the tile within the monsters/objects/other set
129 int i, j, condnum, tilenum;
130 static char buf[BUFSZ];
132 /* Note: these initializers don't do anything except guarantee that
133 we're linked properly.
137 (void) def_char_to_objclass(']');
139 condnum = tilenum = 0;
141 for (i = 0; i < NUMMONS; i++) {
142 if (set == MON_GLYPH && tilenum == entry)
143 return mons[i].mname;
145 while (conditionals[condnum].sequence == MON_GLYPH &&
146 conditionals[condnum].predecessor == i) {
147 if (set == MON_GLYPH && tilenum == entry)
148 return conditionals[condnum].name;
153 if (set == MON_GLYPH && tilenum == entry)
154 return "invisible monster";
156 tilenum = 0; /* set-relative number */
157 for (i = 0; i < NUM_OBJECTS; i++) {
158 /* prefer to give the description - that's all the tile's
159 * appearance should reveal */
160 if (set == OBJ_GLYPH && tilenum == entry) {
161 if ( !obj_descr[i].oc_descr )
162 return obj_descr[i].oc_name;
163 if ( !obj_descr[i].oc_name )
164 return obj_descr[i].oc_descr;
166 Sprintf(buf, "%s / %s",
167 obj_descr[i].oc_descr,
168 obj_descr[i].oc_name);
173 while (conditionals[condnum].sequence == OBJ_GLYPH &&
174 conditionals[condnum].predecessor == i) {
175 if (set == OBJ_GLYPH && tilenum == entry)
176 return conditionals[condnum].name;
182 tilenum = 0; /* set-relative number */
183 for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) {
184 if (set == OTH_GLYPH && tilenum == entry) {
185 if (*defsyms[i].explanation)
186 return defsyms[i].explanation;
188 /* if SINKS are turned off, this
189 * string won't be there (and can't be there
190 * to prevent symbol-identification and
191 * special-level mimic appearances from
192 * thinking the items exist)
196 Sprintf(buf, "sink");
199 Sprintf(buf, "cmap %d", tilenum);
206 while (conditionals[condnum].sequence == OTH_GLYPH &&
207 conditionals[condnum].predecessor == i) {
208 if (set == OTH_GLYPH && tilenum == entry)
209 return conditionals[condnum].name;
215 tilenum = MAXPCHARS - MAXEXPCHARS;
217 if (i < (MAXEXPCHARS * EXPL_MAX)) {
218 if (set == OTH_GLYPH) {
219 static char *explosion_types[] = { /* hack.h */
220 "dark", "noxious", "muddy", "wet",
221 "magical", "fiery", "frosty"
223 Sprintf(buf, "explosion %s %d",
224 explosion_types[i / MAXEXPCHARS], i % MAXEXPCHARS);
228 tilenum += (MAXEXPCHARS * EXPL_MAX);
231 if (i < (NUM_ZAP << 2)) {
232 if (set == OTH_GLYPH) {
233 Sprintf(buf, "zap %d %d", i/4, i%4);
237 tilenum += (NUM_ZAP << 2);
241 if (set == OTH_GLYPH) {
242 Sprintf(buf, "warning %d", i);
246 tilenum += WARNCOUNT;
248 for (i = 0; i < SIZE(substitutes); i++) {
250 if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) {
251 if (set == OTH_GLYPH) {
252 Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j);
256 tilenum += substitutes[i].last_glyph
257 - substitutes[i].first_glyph + 1;
260 Sprintf(buf, "unknown %d %d", set, entry);
266 #define TILE_FILE "tile.c"
269 # define SOURCE_TEMPLATE "NH:src/%s"
272 # define SOURCE_TEMPLATE ":src:%s"
274 # define SOURCE_TEMPLATE "../src/%s"
278 short tilemap[MAX_GLYPH];
279 int lastmontile, lastobjtile, lastothtile;
281 /* Number of tiles for invisible monsters */
282 #define NUM_INVIS_TILES 1
285 * set up array to map glyph numbers to tile numbers
287 * assumes tiles are numbered sequentially through monsters/objects/other,
288 * with entries for all supported compilation options
290 * "other" contains cmap and zaps (the swallow sets are a repeated portion
291 * of cmap), as well as the "flash" glyphs for the new warning system
292 * introduced in 3.3.1.
297 int i, j, condnum, tilenum;
298 int corpsetile, swallowbase;
300 for (i = 0; i < MAX_GLYPH; i++) {
304 corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE;
305 swallowbase= NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl;
307 /* add number compiled out */
308 for (i = 0; conditionals[i].sequence; i++) {
309 switch (conditionals[i].sequence) {
315 if (conditionals[i].predecessor < CORPSE)
320 if (conditionals[i].predecessor < S_sw_tl)
326 condnum = tilenum = 0;
327 for (i = 0; i < NUMMONS; i++) {
328 tilemap[GLYPH_MON_OFF+i] = tilenum;
329 tilemap[GLYPH_PET_OFF+i] = tilenum;
330 tilemap[GLYPH_DETECT_OFF+i] = tilenum;
331 tilemap[GLYPH_RIDDEN_OFF+i] = tilenum;
332 tilemap[GLYPH_BODY_OFF+i] = corpsetile;
333 j = GLYPH_SWALLOW_OFF + 8*i;
334 tilemap[j] = swallowbase;
335 tilemap[j+1] = swallowbase+1;
336 tilemap[j+2] = swallowbase+2;
337 tilemap[j+3] = swallowbase+3;
338 tilemap[j+4] = swallowbase+4;
339 tilemap[j+5] = swallowbase+5;
340 tilemap[j+6] = swallowbase+6;
341 tilemap[j+7] = swallowbase+7;
343 while (conditionals[condnum].sequence == MON_GLYPH &&
344 conditionals[condnum].predecessor == i) {
349 tilemap[GLYPH_INVISIBLE] = tilenum++;
350 lastmontile = tilenum - 1;
352 for (i = 0; i < NUM_OBJECTS; i++) {
353 tilemap[GLYPH_OBJ_OFF+i] = tilenum;
355 while (conditionals[condnum].sequence == OBJ_GLYPH &&
356 conditionals[condnum].predecessor == i) {
361 lastobjtile = tilenum - 1;
363 for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) {
364 tilemap[GLYPH_CMAP_OFF+i] = tilenum;
366 while (conditionals[condnum].sequence == OTH_GLYPH &&
367 conditionals[condnum].predecessor == i) {
373 for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) {
374 tilemap[GLYPH_EXPLODE_OFF+i] = tilenum;
376 while (conditionals[condnum].sequence == OTH_GLYPH &&
377 conditionals[condnum].predecessor == (i + MAXPCHARS)) {
383 for (i = 0; i < NUM_ZAP << 2; i++) {
384 tilemap[GLYPH_ZAP_OFF+i] = tilenum;
386 while (conditionals[condnum].sequence == OTH_GLYPH &&
387 conditionals[condnum].predecessor == (i + MAXEXPCHARS)) {
393 for (i = 0; i < WARNCOUNT; i++) {
394 tilemap[GLYPH_WARNING_OFF+i] = tilenum;
398 lastothtile = tilenum - 1;
401 const char *prolog[] = {
405 "substitute_tiles(plev)",
412 const char *epilog[] = {
416 /* write out the substitutions in an easily-used form. */
418 process_substitutions(ofp)
421 int i, j, k, span, start;
423 fprintf(ofp, "\n\n");
425 j = 0; /* unnecessary */
427 for (i = 0; i < SIZE(substitutes); i++) {
429 || substitutes[i].first_glyph != substitutes[j].first_glyph
430 || substitutes[i].last_glyph != substitutes[j].last_glyph) {
433 fprintf(ofp, "short std_tiles%d[] = { ", span);
434 for (k = substitutes[i].first_glyph;
435 k < substitutes[i].last_glyph; k++)
436 fprintf(ofp, "%d, ", tilemap[k]);
437 fprintf(ofp, "%d };\n",
438 tilemap[substitutes[i].last_glyph]);
442 for (i = 0; i < SIZE(prolog); i++) {
443 fprintf(ofp, "%s\n", prolog[i]);
447 start = lastothtile + 1;
448 for (i = 0; i < SIZE(substitutes); i++) {
450 || substitutes[i].first_glyph != substitutes[j].first_glyph
451 || substitutes[i].last_glyph != substitutes[j].last_glyph) {
452 if (i != 0) { /* finish previous span */
453 fprintf(ofp, "\t} else {\n");
454 fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
455 substitutes[j].first_glyph,
456 substitutes[j].last_glyph);
457 fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n",
458 span, substitutes[j].first_glyph);
459 fprintf(ofp, "\t}\n\n");
464 if (i != j) fprintf(ofp, "\t} else ");
465 fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test);
466 fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
467 substitutes[i].first_glyph,
468 substitutes[i].last_glyph);
469 fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n",
470 start, substitutes[i].first_glyph);
471 start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1;
473 /* finish last span */
474 fprintf(ofp, "\t} else {\n");
475 fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n",
476 substitutes[j].first_glyph,
477 substitutes[j].last_glyph);
478 fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n",
479 span, substitutes[j].first_glyph);
480 fprintf(ofp, "\t}\n\n");
482 for (i = 0; i < SIZE(epilog); i++) {
483 fprintf(ofp, "%s\n", epilog[i]);
486 fprintf(ofp, "\nint total_tiles_used = %d;\n", start);
487 lastothtile = start - 1;
499 * create the source file, "tile.c"
501 Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE);
502 if (!(ofp = fopen(filename, "w"))) {
506 fprintf(ofp,"/* This file is automatically generated. Do not edit. */\n");
507 fprintf(ofp,"\n#include \"hack.h\"\n\n");
508 fprintf(ofp,"short glyph2tile[MAX_GLYPH] = {\n");
510 for (i = 0; i < MAX_GLYPH; i++) {
511 fprintf(ofp,"%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n');
513 fprintf(ofp,"%s};\n", (i % 12) ? "\n" : "");
515 process_substitutions(ofp);
517 fprintf(ofp,"\n#define MAXMONTILE %d\n", lastmontile);
518 fprintf(ofp,"#define MAXOBJTILE %d\n", lastobjtile);
519 fprintf(ofp,"#define MAXOTHTILE %d\n", lastothtile);
521 fprintf(ofp,"\n/*tile.c*/\n");
529 #endif /* TILETEXT */