/* NetHack 3.6 tilemap.c $NHDT-Date: 1447306925 2015/11/12 05:42:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.25 $ */ /* NetHack may be freely redistributed. See license for details. */ /* * This source file is compiled twice: * once without TILETEXT defined to make tilemap.{o,obj}, * then again with it defined to produce tiletxt.{o,obj}. */ #include "hack.h" const char *FDECL(tilename, (int, int)); void NDECL(init_tilemap); void FDECL(process_substitutions, (FILE *)); #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) extern void FDECL(exit, (int)); #endif #endif #if defined(WIN32) #define STATUES_LOOK_LIKE_MONSTERS #endif #define MON_GLYPH 1 #define OBJ_GLYPH 2 #define OTH_GLYPH 3 /* fortunately unnecessary */ #define EXTRA_SCROLL_DESCR_COUNT ((SCR_BLANK_PAPER - SCR_STINKING_CLOUD) - 1) /* note that the ifdefs here should be the opposite sense from monst.c/ * objects.c/rm.h */ struct conditionals { int sequence, predecessor; const char *name; } conditionals[] = { #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_HELL_HOUND, "Cerberus" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHOCKING_SPHERE, "beholder" }, { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" }, { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" }, { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" }, { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" }, #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_CROESUS, "Charon" }, #endif #ifndef MAIL { MON_GLYPH, PM_FAMINE, "mail daemon" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHAMAN_KARNOV, "Earendil" }, { MON_GLYPH, PM_SHAMAN_KARNOV, "Elwing" }, /* commented out in monst.c at present */ { MON_GLYPH, PM_CHROMATIC_DRAGON, "Goblin King" }, { MON_GLYPH, PM_NEANDERTHAL, "High-elf" }, /* objects commented out in objects.c at present */ { OBJ_GLYPH, SILVER_DRAGON_SCALE_MAIL, "shimmering dragon scale mail" }, { OBJ_GLYPH, SILVER_DRAGON_SCALES, "shimmering dragon scales" }, /* allow slime mold to look like slice of pizza, since we * don't know what a slime mold should look like when renamed anyway */ #ifndef MAIL { OBJ_GLYPH, SCR_STINKING_CLOUD + EXTRA_SCROLL_DESCR_COUNT, "stamped / mail" }, #endif { 0, 0, 0 } }; /* * Some entries in glyph2tile[] should be substituted for on various levels. * The tiles used for the substitute entries will follow the usual ones in * other.til in the order given here, which should have every substitution * for the same set of tiles grouped together. You will have to change * more code in process_substitutions()/substitute_tiles() if the sets * overlap in the future. */ struct substitute { int first_glyph, last_glyph; const char *sub_name; /* for explanations */ const char *level_test; } substitutes[] = { { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "mine walls", "In_mines(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "gehennom walls", "In_hell(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "knox walls", "Is_knox(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "sokoban walls", "In_sokoban(plev)" } }; #ifdef TILETEXT /* * entry is the position of the tile within the monsters/objects/other set */ const char * tilename(set, entry) int set, entry; { int i, j, condnum, tilenum; static char buf[BUFSZ]; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); (void) def_char_to_objclass(']'); condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { if (set == MON_GLYPH && tilenum == entry) return mons[i].mname; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { if (set == MON_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } if (set == MON_GLYPH && tilenum == entry) return "invisible monster"; tilenum = 0; /* set-relative number */ for (i = 0; i < NUM_OBJECTS; i++) { /* prefer to give the description - that's all the tile's * appearance should reveal */ if (set == OBJ_GLYPH && tilenum == entry) { if (!obj_descr[i].oc_descr) return obj_descr[i].oc_name; if (!obj_descr[i].oc_name) return obj_descr[i].oc_descr; Sprintf(buf, "%s / %s", obj_descr[i].oc_descr, obj_descr[i].oc_name); return buf; } tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { if (set == OBJ_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } tilenum = 0; /* set-relative number */ for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { if (set == OTH_GLYPH && tilenum == entry) { if (*defsyms[i].explanation) { return defsyms[i].explanation; } else { Sprintf(buf, "cmap %d", tilenum); return buf; } } tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { if (set == OTH_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } /* explosions */ tilenum = MAXPCHARS - MAXEXPCHARS; i = entry - tilenum; if (i < (MAXEXPCHARS * EXPL_MAX)) { if (set == OTH_GLYPH) { static const char *explosion_types[] = { /* hack.h */ "dark", "noxious", "muddy", "wet", "magical", "fiery", "frosty" }; Sprintf(buf, "explosion %s %d", explosion_types[i / MAXEXPCHARS], i % MAXEXPCHARS); return buf; } } tilenum += (MAXEXPCHARS * EXPL_MAX); i = entry - tilenum; if (i < (NUM_ZAP << 2)) { if (set == OTH_GLYPH) { Sprintf(buf, "zap %d %d", i / 4, i % 4); return buf; } } tilenum += (NUM_ZAP << 2); i = entry - tilenum; if (i < WARNCOUNT) { if (set == OTH_GLYPH) { Sprintf(buf, "warning %d", i); return buf; } } tilenum += WARNCOUNT; for (i = 0; i < SIZE(substitutes); i++) { j = entry - tilenum; if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) { if (set == OTH_GLYPH) { Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j); return buf; } } tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } Sprintf(buf, "unknown %d %d", set, entry); return buf; } #else /* TILETEXT */ #define TILE_FILE "tile.c" #ifdef AMIGA #define SOURCE_TEMPLATE "NH:src/%s" #else #ifdef MAC #define SOURCE_TEMPLATE ":src:%s" #else #define SOURCE_TEMPLATE "../src/%s" #endif #endif short tilemap[MAX_GLYPH]; #ifdef STATUES_LOOK_LIKE_MONSTERS int lastmontile, lastobjtile, lastothtile, laststatuetile; #else int lastmontile, lastobjtile, lastothtile; #endif /* Number of tiles for invisible monsters */ #define NUM_INVIS_TILES 1 /* * set up array to map glyph numbers to tile numbers * * assumes tiles are numbered sequentially through monsters/objects/other, * with entries for all supported compilation options * * "other" contains cmap and zaps (the swallow sets are a repeated portion * of cmap), as well as the "flash" glyphs for the new warning system * introduced in 3.3.1. */ void init_tilemap() { int i, j, condnum, tilenum; int corpsetile, swallowbase; for (i = 0; i < MAX_GLYPH; i++) { tilemap[i] = -1; } corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE; swallowbase = NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; /* add number compiled out */ for (i = 0; conditionals[i].sequence; i++) { switch (conditionals[i].sequence) { case MON_GLYPH: corpsetile++; swallowbase++; break; case OBJ_GLYPH: if (conditionals[i].predecessor < CORPSE) corpsetile++; swallowbase++; break; case OTH_GLYPH: if (conditionals[i].predecessor < S_sw_tl) swallowbase++; break; } } condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_MON_OFF + i] = tilenum; tilemap[GLYPH_PET_OFF + i] = tilenum; tilemap[GLYPH_DETECT_OFF + i] = tilenum; tilemap[GLYPH_RIDDEN_OFF + i] = tilenum; tilemap[GLYPH_BODY_OFF + i] = corpsetile; j = GLYPH_SWALLOW_OFF + 8 * i; tilemap[j] = swallowbase; tilemap[j + 1] = swallowbase + 1; tilemap[j + 2] = swallowbase + 2; tilemap[j + 3] = swallowbase + 3; tilemap[j + 4] = swallowbase + 4; tilemap[j + 5] = swallowbase + 5; tilemap[j + 6] = swallowbase + 6; tilemap[j + 7] = swallowbase + 7; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } tilemap[GLYPH_INVISIBLE] = tilenum++; lastmontile = tilenum - 1; for (i = 0; i < NUM_OBJECTS; i++) { tilemap[GLYPH_OBJ_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } lastobjtile = tilenum - 1; for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { tilemap[GLYPH_CMAP_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) { tilemap[GLYPH_EXPLODE_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < NUM_ZAP << 2; i++) { tilemap[GLYPH_ZAP_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXEXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < WARNCOUNT; i++) { tilemap[GLYPH_WARNING_OFF + i] = tilenum; tilenum++; } #ifndef STATUES_LOOK_LIKE_MONSTERS /* statue patch: statues still use the same glyph as in vanilla */ for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_STATUE_OFF + i] = tilemap[GLYPH_OBJ_OFF + STATUE]; } #endif lastothtile = tilenum - 1; #ifdef STATUES_LOOK_LIKE_MONSTERS /* skip over the substitutes to get to the grayscale statues */ for (i = 0; i < SIZE(substitutes); i++) { tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* statue patch: statues look more like the monster */ condnum = 0; /* doing monsters again, so reset */ for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_STATUE_OFF + i] = tilenum; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } laststatuetile = tilenum - 1; #endif } const char *prolog[] = { "", "", "void", "substitute_tiles(plev)", "d_level *plev;", "{", "\tint i;", "" }; const char *epilog[] = { "}" }; /* write out the substitutions in an easily-used form. */ void process_substitutions(ofp) FILE *ofp; { int i, j, k, span, start; fprintf(ofp, "\n\n"); j = 0; /* unnecessary */ span = -1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { j = i; span++; fprintf(ofp, "short std_tiles%d[] = { ", span); for (k = substitutes[i].first_glyph; k < substitutes[i].last_glyph; k++) fprintf(ofp, "%d, ", tilemap[k]); fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); } } for (i = 0; i < SIZE(prolog); i++) { fprintf(ofp, "%s\n", prolog[i]); } j = -1; span = -1; start = lastothtile + 1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { if (i != 0) { /* finish previous span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); } j = i; span++; } if (i != j) fprintf(ofp, "\t} else "); fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[i].first_glyph, substitutes[i].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n", start, substitutes[i].first_glyph); start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* finish last span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); for (i = 0; i < SIZE(epilog); i++) { fprintf(ofp, "%s\n", epilog[i]); } fprintf(ofp, "\nint total_tiles_used = %d;\n", start); lastothtile = start - 1; } int main() { register int i; char filename[30]; FILE *ofp; init_tilemap(); /* * create the source file, "tile.c" */ Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE); if (!(ofp = fopen(filename, "w"))) { perror(filename); exit(EXIT_FAILURE); } fprintf(ofp, "/* This file is automatically generated. Do not edit. */\n"); fprintf(ofp, "\n#include \"hack.h\"\n\n"); fprintf(ofp, "short glyph2tile[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { fprintf(ofp, "%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n'); } fprintf(ofp, "%s};\n", (i % 12) ? "\n" : ""); process_substitutions(ofp); fprintf(ofp, "\n#define MAXMONTILE %d\n", lastmontile); fprintf(ofp, "#define MAXOBJTILE %d\n", lastobjtile); fprintf(ofp, "#define MAXOTHTILE %d\n", lastothtile); fprintf(ofp, "\n/*tile.c*/\n"); fclose(ofp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif /* TILETEXT */