1 /* aNetHack 0.0.1 tilemap.c $ANH-Date: 1470537037 2016/08/07 02:30:37 $ $ANH-Branch: aNetHack-3.6.0 $:$ANH-Revision: 1.32 $ */
2 /* aNetHack 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 *));
15 boolean
FDECL(acceptable_tilename
, (int, const char *, const char *));
17 #if defined(MICRO) || defined(WIN32)
19 #if !defined(MSDOS) && !defined(WIN32)
20 extern void FDECL(exit
, (int));
24 #if defined(MSDOS) || defined(WIN32) || defined(X11_GRAPHICS)
25 #define STATUES_LOOK_LIKE_MONSTERS
30 #define OTH_GLYPH 3 /* fortunately unnecessary */
32 #define EXTRA_SCROLL_DESCR_COUNT ((SCR_BLANK_PAPER - SCR_STINKING_CLOUD) - 1)
34 /* note that the ifdefs here should be the opposite sense from monst.c/
39 int sequence
, predecessor
;
42 #ifndef CHARON /* not supported yet */
43 { MON_GLYPH
, PM_HELL_HOUND
, "Cerberus" },
45 /* commented out in monst.c at present */
46 { MON_GLYPH
, PM_SHOCKING_SPHERE
, "beholder" },
47 { MON_GLYPH
, PM_BABY_SILVER_DRAGON
, "baby shimmering dragon" },
48 { MON_GLYPH
, PM_SILVER_DRAGON
, "shimmering dragon" },
49 { MON_GLYPH
, PM_JABBERWOCK
, "vorpal jabberwock" },
50 { MON_GLYPH
, PM_VAMPIRE_LORD
, "vampire mage" },
51 #ifndef CHARON /* not supported yet */
52 { MON_GLYPH
, PM_CROESUS
, "Charon" },
55 { MON_GLYPH
, PM_FAMINE
, "mail daemon" },
57 /* commented out in monst.c at present */
58 { MON_GLYPH
, PM_SHAMAN_KARNOV
, "Earendil" },
59 { MON_GLYPH
, PM_SHAMAN_KARNOV
, "Elwing" },
60 /* commented out in monst.c at present */
61 { MON_GLYPH
, PM_CHROMATIC_DRAGON
, "Goblin King" },
62 { MON_GLYPH
, PM_NEANDERTHAL
, "High-elf" },
63 /* objects commented out in objects.c at present */
64 { OBJ_GLYPH
, SILVER_DRAGON_SCALE_MAIL
, "shimmering dragon scale mail" },
65 { OBJ_GLYPH
, SILVER_DRAGON_SCALES
, "shimmering dragon scales" },
66 /* allow slime mold to look like slice of pizza, since we
67 * don't know what a slime mold should look like when renamed anyway
70 { OBJ_GLYPH
, SCR_STINKING_CLOUD
+ EXTRA_SCROLL_DESCR_COUNT
, "stamped / mail" },
76 * Some entries in glyph2tile[] should be substituted for on various levels.
77 * The tiles used for the substitute entries will follow the usual ones in
78 * other.til in the order given here, which should have every substitution
79 * for the same set of tiles grouped together. You will have to change
80 * more code in process_substitutions()/substitute_tiles() if the sets
81 * overlap in the future.
84 int first_glyph
, last_glyph
;
85 const char *sub_name
; /* for explanations */
86 const char *level_test
;
87 } substitutes
[] = { { GLYPH_CMAP_OFF
+ S_vwall
, GLYPH_CMAP_OFF
+ S_trwall
,
88 "mine walls", "In_mines(plev)" },
89 { GLYPH_CMAP_OFF
+ S_vwall
, GLYPH_CMAP_OFF
+ S_trwall
,
90 "gehennom walls", "In_hell(plev)" },
91 { GLYPH_CMAP_OFF
+ S_vwall
, GLYPH_CMAP_OFF
+ S_trwall
,
92 "knox walls", "Is_knox(plev)" },
93 { GLYPH_CMAP_OFF
+ S_vwall
, GLYPH_CMAP_OFF
+ S_trwall
,
94 "sokoban walls", "In_sokoban(plev)" } };
99 * entry is the position of the tile within the monsters/objects/other set
105 int i
, j
, condnum
, tilenum
;
106 static char buf
[BUFSZ
];
108 /* Note: these initializers don't do anything except guarantee that
109 we're linked properly.
113 (void) def_char_to_objclass(']');
115 condnum
= tilenum
= 0;
117 for (i
= 0; i
< NUMMONS
; i
++) {
118 if (set
== MON_GLYPH
&& tilenum
== entry
)
119 return mons
[i
].mname
;
121 while (conditionals
[condnum
].sequence
== MON_GLYPH
122 && conditionals
[condnum
].predecessor
== i
) {
123 if (set
== MON_GLYPH
&& tilenum
== entry
)
124 return conditionals
[condnum
].name
;
129 if (set
== MON_GLYPH
&& tilenum
== entry
)
130 return "invisible monster";
132 tilenum
= 0; /* set-relative number */
133 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
134 /* prefer to give the description - that's all the tile's
135 * appearance should reveal */
136 if (set
== OBJ_GLYPH
&& tilenum
== entry
) {
137 if (!obj_descr
[i
].oc_descr
)
138 return obj_descr
[i
].oc_name
;
139 if (!obj_descr
[i
].oc_name
)
140 return obj_descr
[i
].oc_descr
;
142 Sprintf(buf
, "%s / %s", obj_descr
[i
].oc_descr
,
143 obj_descr
[i
].oc_name
);
148 while (conditionals
[condnum
].sequence
== OBJ_GLYPH
149 && conditionals
[condnum
].predecessor
== i
) {
150 if (set
== OBJ_GLYPH
&& tilenum
== entry
)
151 return conditionals
[condnum
].name
;
157 tilenum
= 0; /* set-relative number */
158 for (i
= 0; i
< (MAXPCHARS
- MAXEXPCHARS
); i
++) {
159 if (set
== OTH_GLYPH
&& tilenum
== entry
) {
160 if (*defsyms
[i
].explanation
) {
161 return defsyms
[i
].explanation
;
163 Sprintf(buf
, "cmap %d", tilenum
);
168 while (conditionals
[condnum
].sequence
== OTH_GLYPH
169 && conditionals
[condnum
].predecessor
== i
) {
170 if (set
== OTH_GLYPH
&& tilenum
== entry
)
171 return conditionals
[condnum
].name
;
177 tilenum
= MAXPCHARS
- MAXEXPCHARS
;
179 if (i
< (MAXEXPCHARS
* EXPL_MAX
)) {
180 if (set
== OTH_GLYPH
) {
181 static const char *explosion_types
[] = {
183 "dark", "noxious", "muddy", "wet", "magical", "fiery",
186 Sprintf(buf
, "explosion %s %d", explosion_types
[i
/ MAXEXPCHARS
],
191 tilenum
+= (MAXEXPCHARS
* EXPL_MAX
);
194 if (i
< (NUM_ZAP
<< 2)) {
195 if (set
== OTH_GLYPH
) {
196 Sprintf(buf
, "zap %d %d", i
/ 4, i
% 4);
200 tilenum
+= (NUM_ZAP
<< 2);
204 if (set
== OTH_GLYPH
) {
205 Sprintf(buf
, "warning %d", i
);
209 tilenum
+= WARNCOUNT
;
211 for (i
= 0; i
< SIZE(substitutes
); i
++) {
213 if (j
<= substitutes
[i
].last_glyph
- substitutes
[i
].first_glyph
) {
214 if (set
== OTH_GLYPH
) {
215 Sprintf(buf
, "sub %s %d", substitutes
[i
].sub_name
, j
);
219 tilenum
+= substitutes
[i
].last_glyph
- substitutes
[i
].first_glyph
+ 1;
222 Sprintf(buf
, "unknown %d %d", set
, entry
);
228 #define TILE_FILE "tile.c"
231 #define SOURCE_TEMPLATE "NH:src/%s"
234 #define SOURCE_TEMPLATE ":src:%s"
236 #define SOURCE_TEMPLATE "../src/%s"
240 short tilemap
[MAX_GLYPH
];
242 #ifdef STATUES_LOOK_LIKE_MONSTERS
243 int lastmontile
, lastobjtile
, lastothtile
, laststatuetile
;
245 int lastmontile
, lastobjtile
, lastothtile
;
248 /* Number of tiles for invisible monsters */
249 #define NUM_INVIS_TILES 1
252 * set up array to map glyph numbers to tile numbers
254 * assumes tiles are numbered sequentially through monsters/objects/other,
255 * with entries for all supported compilation options
257 * "other" contains cmap and zaps (the swallow sets are a repeated portion
258 * of cmap), as well as the "flash" glyphs for the new warning system
259 * introduced in 3.3.1.
264 int i
, j
, condnum
, tilenum
;
265 int corpsetile
, swallowbase
;
267 for (i
= 0; i
< MAX_GLYPH
; i
++) {
271 corpsetile
= NUMMONS
+ NUM_INVIS_TILES
+ CORPSE
;
272 swallowbase
= NUMMONS
+ NUM_INVIS_TILES
+ NUM_OBJECTS
+ S_sw_tl
;
274 /* add number compiled out */
275 for (i
= 0; conditionals
[i
].sequence
; i
++) {
276 switch (conditionals
[i
].sequence
) {
282 if (conditionals
[i
].predecessor
< CORPSE
)
287 if (conditionals
[i
].predecessor
< S_sw_tl
)
293 condnum
= tilenum
= 0;
294 for (i
= 0; i
< NUMMONS
; i
++) {
295 tilemap
[GLYPH_MON_OFF
+ i
] = tilenum
;
296 tilemap
[GLYPH_PET_OFF
+ i
] = tilenum
;
297 tilemap
[GLYPH_DETECT_OFF
+ i
] = tilenum
;
298 tilemap
[GLYPH_RIDDEN_OFF
+ i
] = tilenum
;
299 tilemap
[GLYPH_BODY_OFF
+ i
] = corpsetile
;
300 j
= GLYPH_SWALLOW_OFF
+ 8 * i
;
301 tilemap
[j
] = swallowbase
;
302 tilemap
[j
+ 1] = swallowbase
+ 1;
303 tilemap
[j
+ 2] = swallowbase
+ 2;
304 tilemap
[j
+ 3] = swallowbase
+ 3;
305 tilemap
[j
+ 4] = swallowbase
+ 4;
306 tilemap
[j
+ 5] = swallowbase
+ 5;
307 tilemap
[j
+ 6] = swallowbase
+ 6;
308 tilemap
[j
+ 7] = swallowbase
+ 7;
310 while (conditionals
[condnum
].sequence
== MON_GLYPH
311 && conditionals
[condnum
].predecessor
== i
) {
316 tilemap
[GLYPH_INVISIBLE
] = tilenum
++;
317 lastmontile
= tilenum
- 1;
319 for (i
= 0; i
< NUM_OBJECTS
; i
++) {
320 tilemap
[GLYPH_OBJ_OFF
+ i
] = tilenum
;
322 while (conditionals
[condnum
].sequence
== OBJ_GLYPH
323 && conditionals
[condnum
].predecessor
== i
) {
328 lastobjtile
= tilenum
- 1;
330 for (i
= 0; i
< (MAXPCHARS
- MAXEXPCHARS
); i
++) {
331 tilemap
[GLYPH_CMAP_OFF
+ i
] = tilenum
;
333 while (conditionals
[condnum
].sequence
== OTH_GLYPH
334 && conditionals
[condnum
].predecessor
== i
) {
340 for (i
= 0; i
< (MAXEXPCHARS
* EXPL_MAX
); i
++) {
341 tilemap
[GLYPH_EXPLODE_OFF
+ i
] = tilenum
;
343 while (conditionals
[condnum
].sequence
== OTH_GLYPH
344 && conditionals
[condnum
].predecessor
== (i
+ MAXPCHARS
)) {
350 for (i
= 0; i
< NUM_ZAP
<< 2; i
++) {
351 tilemap
[GLYPH_ZAP_OFF
+ i
] = tilenum
;
353 while (conditionals
[condnum
].sequence
== OTH_GLYPH
354 && conditionals
[condnum
].predecessor
== (i
+ MAXEXPCHARS
)) {
360 for (i
= 0; i
< WARNCOUNT
; i
++) {
361 tilemap
[GLYPH_WARNING_OFF
+ i
] = tilenum
;
365 #ifndef STATUES_LOOK_LIKE_MONSTERS
366 /* statue patch: statues still use the same glyph as in vanilla */
368 for (i
= 0; i
< NUMMONS
; i
++) {
369 tilemap
[GLYPH_STATUE_OFF
+ i
] = tilemap
[GLYPH_OBJ_OFF
+ STATUE
];
373 lastothtile
= tilenum
- 1;
375 #ifdef STATUES_LOOK_LIKE_MONSTERS
376 /* skip over the substitutes to get to the grayscale statues */
377 for (i
= 0; i
< SIZE(substitutes
); i
++) {
378 tilenum
+= substitutes
[i
].last_glyph
- substitutes
[i
].first_glyph
+ 1;
381 /* statue patch: statues look more like the monster */
382 condnum
= 0; /* doing monsters again, so reset */
383 for (i
= 0; i
< NUMMONS
; i
++) {
384 tilemap
[GLYPH_STATUE_OFF
+ i
] = tilenum
;
386 while (conditionals
[condnum
].sequence
== MON_GLYPH
387 && conditionals
[condnum
].predecessor
== i
) {
392 laststatuetile
= tilenum
- 1;
396 const char *prolog
[] = { "", "", "void", "substitute_tiles(plev)",
397 "d_level *plev;", "{", "\tint i;", "" };
399 const char *epilog
[] = { "}" };
401 /* write out the substitutions in an easily-used form. */
403 process_substitutions(ofp
)
406 int i
, j
, k
, span
, start
;
408 fprintf(ofp
, "\n\n");
410 j
= 0; /* unnecessary */
412 for (i
= 0; i
< SIZE(substitutes
); i
++) {
413 if (i
== 0 || substitutes
[i
].first_glyph
!= substitutes
[j
].first_glyph
414 || substitutes
[i
].last_glyph
!= substitutes
[j
].last_glyph
) {
417 fprintf(ofp
, "short std_tiles%d[] = { ", span
);
418 for (k
= substitutes
[i
].first_glyph
;
419 k
< substitutes
[i
].last_glyph
; k
++)
420 fprintf(ofp
, "%d, ", tilemap
[k
]);
421 fprintf(ofp
, "%d };\n", tilemap
[substitutes
[i
].last_glyph
]);
425 for (i
= 0; i
< SIZE(prolog
); i
++) {
426 fprintf(ofp
, "%s\n", prolog
[i
]);
430 start
= lastothtile
+ 1;
431 for (i
= 0; i
< SIZE(substitutes
); i
++) {
432 if (i
== 0 || substitutes
[i
].first_glyph
!= substitutes
[j
].first_glyph
433 || substitutes
[i
].last_glyph
!= substitutes
[j
].last_glyph
) {
434 if (i
!= 0) { /* finish previous span */
435 fprintf(ofp
, "\t} else {\n");
436 fprintf(ofp
, "\t\tfor (i = %d; i <= %d; i++)\n",
437 substitutes
[j
].first_glyph
,
438 substitutes
[j
].last_glyph
);
439 fprintf(ofp
, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n",
440 span
, substitutes
[j
].first_glyph
);
441 fprintf(ofp
, "\t}\n\n");
447 fprintf(ofp
, "\t} else ");
448 fprintf(ofp
, "\tif (%s) {\n", substitutes
[i
].level_test
);
449 fprintf(ofp
, "\t\tfor (i = %d; i <= %d; i++)\n",
450 substitutes
[i
].first_glyph
, substitutes
[i
].last_glyph
);
451 fprintf(ofp
, "\t\t\tglyph2tile[i] = %d + i - %d;\n", start
,
452 substitutes
[i
].first_glyph
);
453 start
+= substitutes
[i
].last_glyph
- substitutes
[i
].first_glyph
+ 1;
455 /* finish last span */
456 fprintf(ofp
, "\t} else {\n");
457 fprintf(ofp
, "\t\tfor (i = %d; i <= %d; i++)\n",
458 substitutes
[j
].first_glyph
, substitutes
[j
].last_glyph
);
459 fprintf(ofp
, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span
,
460 substitutes
[j
].first_glyph
);
461 fprintf(ofp
, "\t}\n\n");
463 for (i
= 0; i
< SIZE(epilog
); i
++) {
464 fprintf(ofp
, "%s\n", epilog
[i
]);
467 lastothtile
= start
- 1;
468 #ifdef STATUES_LOOK_LIKE_MONSTERS
469 start
= laststatuetile
+ 1;
471 fprintf(ofp
, "\nint total_tiles_used = %d;\n", start
);
484 * create the source file, "tile.c"
486 Sprintf(filename
, SOURCE_TEMPLATE
, TILE_FILE
);
487 if (!(ofp
= fopen(filename
, "w"))) {
492 "/* This file is automatically generated. Do not edit. */\n");
493 fprintf(ofp
, "\n#include \"hack.h\"\n\n");
494 fprintf(ofp
, "short glyph2tile[MAX_GLYPH] = {\n");
496 for (i
= 0; i
< MAX_GLYPH
; i
++) {
497 fprintf(ofp
, "%2d,%c", tilemap
[i
], (i
% 12) ? ' ' : '\n');
499 fprintf(ofp
, "%s};\n", (i
% 12) ? "\n" : "");
501 process_substitutions(ofp
);
503 fprintf(ofp
, "\n#define MAXMONTILE %d\n", lastmontile
);
504 fprintf(ofp
, "#define MAXOBJTILE %d\n", lastobjtile
);
505 fprintf(ofp
, "#define MAXOTHTILE %d\n", lastothtile
);
506 #ifdef STATUES_LOOK_LIKE_MONSTERS
507 fprintf(ofp
, "/* #define MAXSTATUETILE %d */\n", laststatuetile
);
509 fprintf(ofp
, "\n/*tile.c*/\n");
517 #endif /* TILETEXT */
521 const char *betterlabel
;
522 const char *expectedlabel
;
524 {S_stone
, "dark part of a room", "dark part of a room"},
525 {S_vwall
, "vertical wall", "wall"},
526 {S_hwall
, "horizontal wall", "wall"},
527 {S_tlcorn
, "top left corner wall", "wall"},
528 {S_trcorn
, "top right corner wall", "wall"},
529 {S_blcorn
, "bottom left corner wall", "wall"},
530 {S_brcorn
, "bottom right corner wall", "wall"},
531 {S_crwall
, "cross wall", "wall"},
532 {S_tuwall
, "tuwall", "wall"},
533 {S_tdwall
, "tdwall", "wall"},
534 {S_tlwall
, "tlwall", "wall"},
535 {S_trwall
, "trwall", "wall"},
536 {S_ndoor
, "no door", "doorway"},
537 {S_vodoor
, "vertical open door", "open door"},
538 {S_hodoor
, "horizontal open door", "open door"},
539 {S_vcdoor
, "vertical closed door", "closed door"},
540 {S_hcdoor
, "horizontal closed door", "closed door"},
541 {S_bars
, "iron bars", "iron bars"},
542 {S_tree
, "tree", "tree"},
543 {S_room
, "room", "floor of a room"},
544 {S_darkroom
, "darkroom", "dark part of a room"},
545 {S_corr
, "corridor", "corridor"},
546 {S_litcorr
, "lit corridor", "lit corridor"},
547 {S_upstair
, "up stairs", "staircase up"},
548 {S_dnstair
, "down stairs", "staircase down"},
549 {S_upladder
, "up ladder", "ladder up"},
550 {S_dnladder
, "down ladder", "ladder down"},
551 {S_altar
, "altar", "altar"},
552 {S_grave
, "grave", "grave"},
553 {S_throne
, "throne", "opulent throne"},
554 {S_sink
, "sink", "sink"},
555 {S_fountain
, "fountain", "fountain"},
556 {S_pool
, "pool", "water"},
557 {S_ice
, "ice", "ice"},
558 {S_lava
, "lava", "molten lava"},
559 {S_vodbridge
, "vertical open drawbridge", "lowered drawbridge"},
560 {S_hodbridge
, "horizontal open drawbridge", "lowered drawbridge"},
561 {S_vcdbridge
, "vertical closed drawbridge", "raised drawbridge"},
562 {S_hcdbridge
, "horizontal closed drawbridge", "raised drawbridge"},
563 {S_air
, "air", "air"},
564 {S_cloud
, "cloud", "cloud"},
565 {S_water
, "water", "water"},
566 {S_arrow_trap
, "arrow trap", "arrow trap"},
567 {S_dart_trap
, "dart trap", "dart trap"},
568 {S_falling_rock_trap
, "falling rock trap", "falling rock trap"},
569 {S_squeaky_board
, "squeaky board", "squeaky board"},
570 {S_bear_trap
, "bear trap", "bear trap"},
571 {S_land_mine
, "land mine", "land mine"},
572 {S_rolling_boulder_trap
, "rolling boulder trap", "rolling boulder trap"},
573 {S_sleeping_gas_trap
, "sleeping gas trap", "sleeping gas trap"},
574 {S_rust_trap
, "rust trap", "rust trap"},
575 {S_fire_trap
, "fire trap", "fire trap"},
576 {S_pit
, "pit", "pit"},
577 {S_spiked_pit
, "spiked pit", "spiked pit"},
578 {S_hole
, "hole", "hole"},
579 {S_trap_door
, "trap door", "trap door"},
580 {S_teleportation_trap
, "teleportation trap", "teleportation trap"},
581 {S_level_teleporter
, "level teleporter", "level teleporter"},
582 {S_magic_portal
, "magic portal", "magic portal"},
583 {S_web
, "web", "web"},
584 {S_statue_trap
, "statue trap", "statue trap"},
585 {S_magic_trap
, "magic trap", "magic trap"},
586 {S_anti_magic_trap
, "anti magic trap", "anti-magic field"},
587 {S_polymorph_trap
, "polymorph trap", "polymorph trap"},
588 {S_vibrating_square
, "vibrating square", "vibrating square"},
589 {S_vbeam
, "vertical beam", "cmap 65"},
590 {S_hbeam
, "horizontal beam", "cmap 66"},
591 {S_lslant
, "left slant beam", "cmap 67"},
592 {S_rslant
, "right slant beam", "cmap 68"},
593 {S_digbeam
, "dig beam", "cmap 69"},
594 {S_flashbeam
, "flash beam", "cmap 70"},
595 {S_boomleft
, "boom left", "cmap 71"},
596 {S_boomright
, "boom right", "cmap 72"},
597 {S_ss1
, "shield1", "cmap 73"},
598 {S_ss2
, "shield2", "cmap 74"},
599 {S_ss3
, "shield3", "cmap 75"},
600 {S_ss4
, "shield4", "cmap 76"},
601 {S_poisoncloud
, "poison cloud", "poison cloud"},
602 {S_goodpos
, "valid position", "valid position"},
603 {S_sw_tl
, "swallow top left", "cmap 79"},
604 {S_sw_tc
, "swallow top center", "cmap 80"},
605 {S_sw_tr
, "swallow top right", "cmap 81"},
606 {S_sw_ml
, "swallow middle left", "cmap 82"},
607 {S_sw_mr
, "swallow middle right", "cmap 83"},
608 {S_sw_bl
, "swallow bottom left ", "cmap 84"},
609 {S_sw_bc
, "swallow bottom center", "cmap 85"},
610 {S_sw_br
, "swallow bottom right", "cmap 86"},
611 {S_explode1
, "explosion top left", "explosion dark 0"},
612 {S_explode2
, "explosion top centre", "explosion dark 1"},
613 {S_explode3
, "explosion top right", "explosion dark 2"},
614 {S_explode4
, "explosion middle left", "explosion dark 3"},
615 {S_explode5
, "explosion middle center", "explosion dark 4"},
616 {S_explode6
, "explosion middle right", "explosion dark 5"},
617 {S_explode7
, "explosion bottom left", "explosion dark 6"},
618 {S_explode8
, "explosion bottom center", "explosion dark 7"},
619 {S_explode9
, "explosion bottom right", "explosion dark 8"},
623 acceptable_tilename(idx
, encountered
, expected
)
625 const char *encountered
, *expected
;
627 if (idx
>= 0 && idx
< SIZE(altlabels
)) {
628 if (!strcmp(altlabels
[idx
].expectedlabel
, expected
)) {
629 if (!strcmp(altlabels
[idx
].betterlabel
, encountered
))