/** * This function takes a pointer to a grid info struct describing the * contents of a grid location (as obtained through the function map_info) * and fills in the character and attr pairs for display. * * ap and cp are filled with the attr/char pair for the monster, object or * floor tile that is at the "top" of the grid (monsters covering objects, * which cover floor, assuming all are present). * * tap and tcp are filled with the attr/char pair for the floor, regardless * of what is on it. This can be used by graphical displays with * transparency to place an object onto a floor tile, is desired. * * Any lighting effects are also applied to these pairs, clear monsters allow * the underlying colour or feature to show through (ATTR_CLEAR and * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on. * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster * looks strange when examined, but this flag is currently ignored. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * The "zero" entry in the feature/object/monster arrays are * used to provide "special" attr/char codes, with "monster zero" being * used for the player attr/char, "object zero" being used for the "pile" * attr/char, and "feature zero" being used for the "darkness" attr/char. * * TODO: * The transformations for tile colors, or brightness for the 16x16 * tiles should be handled differently. One possibility would be to * extend feature_type with attr/char definitions for the different states. * This will probably be done outside of the current text->graphics mappings * though. */ void grid_data_as_text(struct grid_data *g, int *ap, wchar_t *cp, int *tap, wchar_t *tcp) { struct feature *feat = &f_info[g->f_idx]; int a = feat_x_attr[g->lighting][feat->fidx]; wchar_t c = feat_x_char[g->lighting][feat->fidx]; bool skip_objects = false; /* Get the colour for ASCII */ if (use_graphics == GRAPHICS_NONE) grid_get_attr(g, &a); /* Save the terrain info for the transparency effects */ (*tap) = a; (*tcp) = c; /* There is a trap in this grid, and we are not hallucinating */ if (g->trap && (!g->hallucinate)) { /* Change graphics to indicate visible traps, skip objects if a web */ skip_objects = get_trap_graphics(cave, g, &a, &c); } if (!skip_objects) { /* If there's an object, deal with that. */ if (g->unseen_money) { /* $$$ gets an orange star*/ a = object_kind_attr(unknown_gold_kind); c = object_kind_char(unknown_gold_kind); } else if (g->unseen_object) { /* Everything else gets a red star */ a = object_kind_attr(unknown_item_kind); c = object_kind_char(unknown_item_kind); } else if (g->first_kind) { if (g->hallucinate) { /* Just pick a random object to display. */ hallucinatory_object(&a, &c); } else if (g->multiple_objects) { /* Get the "pile" feature instead */ a = object_kind_attr(pile_kind); c = object_kind_char(pile_kind); } else { /* Normal attr and char */ a = object_kind_attr(g->first_kind); c = object_kind_char(g->first_kind); } } } /* Handle monsters, the player and trap borders */ if (g->m_idx > 0) { if (g->hallucinate) { /* Just pick a random monster to display. */ hallucinatory_monster(&a, &c); } else if (!monster_is_mimicking(cave_monster(cave, g->m_idx))) { struct monster *mon = cave_monster(cave, g->m_idx); byte da; wchar_t dc; /* Desired attr & char */ da = monster_x_attr[mon->race->ridx]; dc = monster_x_char[mon->race->ridx]; /* Special handling of attrs and/or chars */ if (da & 0x80) { /* Special attr/char codes */ a = da; c = dc; } else if (OPT(player, purple_uniques) && rf_has(mon->race->flags, RF_UNIQUE)) { /* Turn uniques purple if desired (violet, actually) */ a = COLOUR_VIOLET; c = dc; } else if (rf_has(mon->race->flags, RF_ATTR_MULTI) || rf_has(mon->race->flags, RF_ATTR_FLICKER) || rf_has(mon->race->flags, RF_ATTR_RAND)) { /* Multi-hued monster */ a = mon->attr ? mon->attr : da; c = dc; } else if (!flags_test(mon->race->flags, RF_SIZE, RF_ATTR_CLEAR, RF_CHAR_CLEAR, FLAG_END)) { /* Normal monster (not "clear" in any way) */ a = da; /* Desired attr & char. da is not used, should a be set to it?*/ /*da = monster_x_attr[mon->race->ridx];*/ dc = monster_x_char[mon->race->ridx]; c = dc; } else if (a & 0x80) { /* Hack -- Bizarre grid under monster */ a = da; c = dc; } else if (!rf_has(mon->race->flags, RF_CHAR_CLEAR)) { /* Normal char, Clear attr, monster */ c = dc; } else if (!rf_has(mon->race->flags, RF_ATTR_CLEAR)) { /* Normal attr, Clear char, monster */ a = da; } /* Store the drawing attr so we can use it elsewhere */ mon->attr = a; } } else if (g->is_player) { struct monster_race *race = &r_info[0]; /* Get the "player" attr */ a = monster_x_attr[race->ridx]; if ((OPT(player, hp_changes_color)) && !(a & 0x80)) { switch(player->chp * 10 / player->mhp) { case 10: case 9: { a = COLOUR_WHITE; break; } case 8: case 7: { a = COLOUR_YELLOW; break; } case 6: case 5: { a = COLOUR_ORANGE; break; } case 4: case 3: { a = COLOUR_L_RED; break; } case 2: case 1: case 0: { a = COLOUR_RED; break; } default: { a = COLOUR_WHITE; break; } } } /* Get the "player" char */ c = monster_x_char[race->ridx]; } /* Result */ (*ap) = a; (*cp) = c; }
/** * This function takes a pointer to a grid info struct describing the * contents of a grid location (as obtained through the function map_info) * and fills in the character and attr pairs for display. * * ap and cp are filled with the attr/char pair for the monster, object or * floor tile that is at the "top" of the grid (monsters covering objects, * which cover floor, assuming all are present). * * tap and tcp are filled with the attr/char pair for the floor, regardless * of what is on it. This can be used by graphical displays with * transparency to place an object onto a floor tile, is desired. * * Any lighting effects are also applied to these pairs, clear monsters allow * the underlying colour or feature to show through (ATTR_CLEAR and * CHAR_CLEAR), multi-hued colour-changing (ATTR_MULTI) is applied, and so on. * Technically, the flag "CHAR_MULTI" is supposed to indicate that a monster * looks strange when examined, but this flag is currently ignored. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * The "zero" entry in the feature/object/monster arrays are * used to provide "special" attr/char codes, with "monster zero" being * used for the player attr/char, "object zero" being used for the "pile" * attr/char, and "feature zero" being used for the "darkness" attr/char. * * TODO: * The transformations for tile colors, or brightness for the 16x16 * tiles should be handled differently. One possibility would be to * extend feature_type with attr/char definitions for the different states. * This will probably be done outside of the current text->graphics mappings * though. */ void grid_data_as_text(grid_data *g, int *ap, wchar_t *cp, int *tap, wchar_t *tcp) { feature_type *f_ptr = &f_info[g->f_idx]; int a = feat_x_attr[g->lighting][f_ptr->fidx]; wchar_t c = feat_x_char[g->lighting][f_ptr->fidx]; /* Check for trap detection boundaries */ if (use_graphics == GRAPHICS_NONE) grid_get_attr(g, &a); else if (g->trapborder && tf_has(f_ptr->flags, TF_FLOOR) && (g->m_idx || g->first_kind)) { /* if there is an object or monster here, and this is a plain floor * display the border here rather than an overlay below */ a = feat_x_attr[g->lighting][FEAT_DTRAP_FLOOR]; c = feat_x_char[g->lighting][FEAT_DTRAP_FLOOR]; } /* Save the terrain info for the transparency effects */ (*tap) = a; (*tcp) = c; /* There is a trap in this grid, and we are not hallucinating */ if (g->trap && (!g->hallucinate)) /* Change graphics to indicate a trap (if visible) */ get_trap_graphics(cave, g, &a, &c); /* If there's an object, deal with that. */ if (g->unseen_money) { /* $$$ gets an orange star*/ a = object_kind_attr(&k_info[7]); c = object_kind_char(&k_info[7]); } else if (g->unseen_object) { /* Everything else gets a red star */ a = object_kind_attr(&k_info[6]); c = object_kind_char(&k_info[6]); } else if (g->first_kind) { if (g->hallucinate) { /* Just pick a random object to display. */ hallucinatory_object(&a, &c); } else if (g->multiple_objects) { /* Get the "pile" feature instead */ a = object_kind_attr(&k_info[0]); c = object_kind_char(&k_info[0]); } else { /* Normal attr and char */ a = object_kind_attr(g->first_kind); c = object_kind_char(g->first_kind); } } /* Handle monsters, the player and trap borders */ if (g->m_idx > 0) { if (g->hallucinate) { /* Just pick a random monster to display. */ hallucinatory_monster(&a, &c); } else if (!is_mimicking(cave_monster(cave, g->m_idx))) { monster_type *m_ptr = cave_monster(cave, g->m_idx); byte da; wchar_t dc; /* Desired attr & char */ da = monster_x_attr[m_ptr->race->ridx]; dc = monster_x_char[m_ptr->race->ridx]; /* Special handling of attrs and/or chars */ if (da & 0x80) { /* Special attr/char codes */ a = da; c = dc; } else if (OPT(purple_uniques) && rf_has(m_ptr->race->flags, RF_UNIQUE)) { /* Turn uniques purple if desired (violet, actually) */ a = COLOUR_VIOLET; c = dc; } else if (rf_has(m_ptr->race->flags, RF_ATTR_MULTI) || rf_has(m_ptr->race->flags, RF_ATTR_FLICKER) || rf_has(m_ptr->race->flags, RF_ATTR_RAND)) { /* Multi-hued monster */ a = m_ptr->attr ? m_ptr->attr : da; c = dc; } else if (!flags_test(m_ptr->race->flags, RF_SIZE, RF_ATTR_CLEAR, RF_CHAR_CLEAR, FLAG_END)) { /* Normal monster (not "clear" in any way) */ a = da; /* Desired attr & char. da is not used, should a be set to it?*/ /*da = monster_x_attr[m_ptr->race->ridx];*/ dc = monster_x_char[m_ptr->race->ridx]; c = dc; } else if (a & 0x80) { /* Hack -- Bizarre grid under monster */ a = da; c = dc; } else if (!rf_has(m_ptr->race->flags, RF_CHAR_CLEAR)) { /* Normal char, Clear attr, monster */ c = dc; } else if (!rf_has(m_ptr->race->flags, RF_ATTR_CLEAR)) { /* Normal attr, Clear char, monster */ a = da; } /* Store the drawing attr so we can use it elsewhere */ m_ptr->attr = a; } } else if (g->is_player) { monster_race *r_ptr = &r_info[0]; /* Get the "player" attr */ a = monster_x_attr[r_ptr->ridx]; if ((OPT(hp_changes_color)) && !(a & 0x80)) { switch(player->chp * 10 / player->mhp) { case 10: case 9: { a = COLOUR_WHITE; break; } case 8: case 7: { a = COLOUR_YELLOW; break; } case 6: case 5: { a = COLOUR_ORANGE; break; } case 4: case 3: { a = COLOUR_L_RED; break; } case 2: case 1: case 0: { a = COLOUR_RED; break; } default: { a = COLOUR_WHITE; break; } } } /* Get the "player" char */ c = monster_x_char[r_ptr->ridx]; } else if (g->trapborder && (g->f_idx) && !(g->first_kind) && (use_graphics != GRAPHICS_NONE)) { /* No overlay is used, so we can use the trap border overlay */ a = feat_x_attr[g->lighting][FEAT_DTRAP_WALL]; c = feat_x_char[g->lighting][FEAT_DTRAP_WALL]; } /* Result */ (*ap) = a; (*cp) = c; }
/** * Return the "attr" for a given item. * Use "flavor" if available. * Default to user definitions. */ byte object_attr(const struct object *obj) { return object_kind_attr(obj->kind); }
/** * Format a section of the object list: a header followed by object list entry * rows. * * This function will process each entry for the given section. It will display: * - object char; * - number of objects; * - object name (truncated, if needed to fit the line); * - object distance from the player (aligned to the right side of the list). * By passing in a NULL textblock, the maximum line width of the section can * be found. * * \param list is the object list to format. * \param tb is the textblock to produce or NULL if only the dimensions need to * be calculated. * \param lines_to_display are the number of entries to display (not including * the header). * \param max_width is the maximum line width. * \param prefix is the beginning of the header; the remainder is appended with * the number of objects. * \param max_width_result is returned with the width needed to format the list * without truncation. */ static void object_list_format_section(const object_list_t *list, textblock *tb, object_list_section_t section, int lines_to_display, int max_width, const char *prefix, bool show_others, size_t *max_width_result) { int remaining_object_total = 0; int line_count = 0; int entry_index; int total; char line_buffer[200]; const char *punctuation = (lines_to_display == 0) ? "." : ":"; const char *others = (show_others) ? "other " : ""; size_t max_line_length = 0; if (list == NULL || list->entries == NULL) return; total = list->distinct_entries; if (list->total_entries[section] == 0) { max_line_length = strnfmt(line_buffer, sizeof(line_buffer), "%s no objects.\n", prefix); if (tb != NULL) textblock_append(tb, "%s", line_buffer); /* Force a minimum width so that the prompt doesn't get cut off. */ if (max_width_result != NULL) *max_width_result = MAX(max_line_length, 40); return; } max_line_length = strnfmt(line_buffer, sizeof(line_buffer), "%s %d %sobject%s%s\n", prefix, list->total_entries[section], others, PLURAL(list->total_entries[section]), punctuation); if (tb != NULL) textblock_append(tb, "%s", line_buffer); for (entry_index = 0; entry_index < total && line_count < lines_to_display; entry_index++) { char location[20] = { '\0' }; byte line_attr; size_t full_width; const char *direction_y = (list->entries[entry_index].dy <= 0) ? "N" : "S"; const char *direction_x = (list->entries[entry_index].dx <= 0) ? "W" : "E"; line_buffer[0] = '\0'; if (list->entries[entry_index].count[section] == 0) continue; /* Build the location string. */ strnfmt(location, sizeof(location), " %d %s %d %s", abs(list->entries[entry_index].dy), direction_y, abs(list->entries[entry_index].dx), direction_x); /* Get width available for object name: 2 for char and space; location * includes padding; last -1 for some reason? */ full_width = max_width - 2 - utf8_strlen(location) - 1; /* Add the object count and clip the object name to fit. */ object_list_format_name(&list->entries[entry_index], line_buffer, sizeof(line_buffer)); utf8_clipto(line_buffer, full_width); /* Calculate the width of the line for dynamic sizing; use a fixed max * width for location and object char. */ max_line_length = MAX(max_line_length, utf8_strlen(line_buffer) + 12 + 2); /* textblock_append_pict will safely add the object symbol, regardless * of ASCII/graphics mode. */ if (tb != NULL && tile_width == 1 && tile_height == 1) { byte a = COLOUR_RED; wchar_t c = L'*'; if (!is_unknown(list->entries[entry_index].object) && list->entries[entry_index].object->kind != NULL) { a = object_kind_attr(list->entries[entry_index].object->kind); c = object_kind_char(list->entries[entry_index].object->kind); } textblock_append_pict(tb, a, c); textblock_append(tb, " "); } /* Add the left-aligned and padded object name which will align the * location to the right. */ if (tb != NULL) { /* * Hack - Because object name strings are UTF8, we have to add * additional padding for any raw bytes that might be consolidated * into one displayed character. */ full_width += strlen(line_buffer) - utf8_strlen(line_buffer); line_attr = object_list_entry_line_attribute(&list->entries[entry_index]); textblock_append_c(tb, line_attr, "%-*s%s\n", full_width, line_buffer, location); } line_count++; } /* Don't worry about the "...others" line, since it's probably shorter than * what's already printed. */ if (max_width_result != NULL) *max_width_result = max_line_length; /* Bail since we don't have enough room to display the remaining count or * since we've displayed them all. */ if (lines_to_display <= 0 || lines_to_display >= list->total_entries[section]) return; /* Count the remaining objects, starting where we left off in the above * loop. */ remaining_object_total = total - entry_index; if (tb != NULL) textblock_append(tb, "%6s...and %d others.\n", " ", remaining_object_total); }