/** * Display the monster list statically. This will force the list to be * displayed to the provided dimensions. Contents will be adjusted accordingly. * * In order to support more efficient monster flicker animations, this function * uses a shared list object so that it's not constantly allocating and freeing * the list. * * \param height is the height of the list. * \param width is the width of the list. */ void monster_list_show_subwindow(int height, int width) { textblock *tb; monster_list_t *list; int i; if (height < 1 || width < 1) return; tb = textblock_new(); list = monster_list_shared_instance(); /* Force an update if detected monsters */ for (i = 1; i < cave_monster_max(cave); i++) { if (mflag_has(cave_monster(cave, i)->mflag, MFLAG_MARK)) { list->creation_turn = -1; break; } } monster_list_reset(list); monster_list_collect(list); monster_list_get_glyphs(list); monster_list_sort(list, monster_list_standard_compare); /* Draw the list to exactly fit the subwindow. */ monster_list_format_textblock(list, tb, height, width, NULL, NULL); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/** * Display monster recall modally and wait for a keypress. * * This is intended to be called when the main window is active (hence the * message flushing). * * \param race is the monster race we are describing. * \param lore is the known information about the monster race. */ void lore_show_interactive(const monster_race *race, const monster_lore *lore) { textblock *tb; assert(race && lore); event_signal(EVENT_MESSAGE_FLUSH); tb = textblock_new(); lore_description(tb, race, lore, FALSE); textui_textblock_show(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/** * Display the monster list interactively. This will dynamically size the list * for the best appearance. This should only be used in the main term. * * \param height is the height limit for the list. * \param width is the width limit for the list. */ void monster_list_show_interactive(int height, int width) { textblock *tb; monster_list_t *list; size_t max_width = 0, max_height = 0; int safe_height, safe_width; region r; if (height < 1 || width < 1) return; tb = textblock_new(); list = monster_list_new(); monster_list_collect(list); monster_list_get_glyphs(list); monster_list_sort(list, monster_list_standard_compare); /* Figure out optimal display rect. Large numbers are passed as the height * and width limit so that we can calculate the maximum number of rows and * columns to display the list nicely. We then adjust those values as * needed to fit in the main term. Height is adjusted to account for the * texblock prompt. The list is positioned on the right side of the term * underneath the status line. */ monster_list_format_textblock(list, NULL, 1000, 1000, &max_height, &max_width); safe_height = MIN(height - 2, (int)max_height + 2); safe_width = MIN(width - 13, (int)max_width); r.col = -safe_width; r.row = 1; r.width = safe_width; r.page_rows = safe_height; /* * Actually draw the list. We pass in max_height to the format function so * that all lines will be appended to the textblock. The textblock itself * will handle fitting it into the region. However, we have to pass * safe_width so that the format function will pad the lines properly so * that the location string is aligned to the right edge of the list. */ monster_list_format_textblock(list, tb, (int)max_height, safe_width, NULL, NULL); region_erase_bordered(&r); textui_textblock_show(tb, r, NULL); textblock_free(tb); monster_list_free(list); }
/* * Output object information */ static textblock *object_info_out(const object_type *o_ptr, oinfo_detail_t mode) { bool something = FALSE; bool full = mode & OINFO_FULL; bool terse = mode & OINFO_TERSE; bool subjective = mode & OINFO_SUBJ; bool ego = mode & OINFO_EGO; bool dummy = mode & OINFO_DUMMY; textblock *tb = textblock_new(); if (subjective) describe_origin(tb, o_ptr); if (!terse) describe_flavor_text(tb, o_ptr); if (describe_set(tb, o_ptr, mode)) something = TRUE; if (describe_stats(tb, o_ptr, mode)) something = TRUE; if (describe_bonus(tb, o_ptr, mode)) something = TRUE; if (describe_slays(tb, o_ptr, mode)) something = TRUE; if (describe_brands(tb, o_ptr, mode)) something = TRUE; if (describe_immune(tb, o_ptr, mode)) something = TRUE; if (describe_sustains(tb, o_ptr, mode)) something = TRUE; if (describe_misc_magic(tb, o_ptr, mode)) something = TRUE; if (ego && describe_ego(tb, o_ptr)) something = TRUE; if (describe_ignores(tb, o_ptr, mode)) something = TRUE; if (describe_curses(tb, o_ptr, mode)) something = TRUE; if (describe_effect(tb, o_ptr, mode)) something = TRUE; if (subjective && describe_combat(tb, o_ptr, mode)) { something = TRUE; textblock_append(tb, "\n"); } if (!terse && describe_food(tb, o_ptr, subjective, full)) something = TRUE; if (describe_light(tb, o_ptr, terse)) something = TRUE; if (!terse && subjective && describe_digger(tb, o_ptr, mode)) something = TRUE; //if (!something) // textblock_append(tb, "\n"); if (!terse && !dummy) { textblock_append(tb, "\n"); textblock_append(tb, obj_class_info[o_ptr->tval]); textblock_append(tb, "\n"); } return tb; }
/** * Display monster recall statically. * * This is intended to be called in a subwindow, since it clears the entire * window before drawing, and has no interactivity. * * \param race is the monster race we are describing. * \param lore is the known information about the monster race. */ void lore_show_subwindow(const monster_race *race, const monster_lore *lore) { int y; textblock *tb; assert(race && lore); /* Erase the window, since textui_textblock_place() only clears what it * needs */ for (y = 0; y < Term->hgt; y++) Term_erase(0, y, 255); tb = textblock_new(); lore_description(tb, race, lore, FALSE); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/** * Display the object list statically. This will force the list to be displayed * to the provided dimensions. Contents will be adjusted accordingly. * * In order to be more efficient, this function uses a shared list object so * that it's not constantly allocating and freeing the list. * * \param height is the height of the list. * \param width is the width of the list. */ void object_list_show_subwindow(int height, int width) { textblock *tb; object_list_t *list; if (height < 1 || width < 1) return; tb = textblock_new(); list = object_list_shared_instance(); object_list_reset(list); object_list_collect(list); object_list_sort(list, object_list_standard_compare); /* Draw the list to exactly fit the subwindow. */ object_list_format_textblock(list, tb, height, width, NULL, NULL); textui_textblock_place(tb, SCREEN_REGION, NULL); textblock_free(tb); }
/* * Output object information */ static textblock *object_info_out(const object_type *o_ptr, oinfo_detail_t mode) { bitflag flags[OF_SIZE]; bitflag pval_flags[MAX_PVALS][OF_SIZE]; bool something = FALSE; bool known = object_is_known(o_ptr); bool full = mode & OINFO_FULL; bool terse = mode & OINFO_TERSE; bool subjective = mode & OINFO_SUBJ; bool ego = mode & OINFO_EGO; textblock *tb = textblock_new(); /* Grab the object flags */ if (full) { object_flags(o_ptr, flags); object_pval_flags(o_ptr, pval_flags); } else { object_flags_known(o_ptr, flags); object_pval_flags_known(o_ptr, pval_flags); } if (subjective) describe_origin(tb, o_ptr); if (!terse) describe_flavor_text(tb, o_ptr); if (!full && !known) { textblock_append(tb, "You do not know the full extent of this item's powers.\n"); if (SENSING_REVEALS_FLAG_COUNT) { if (object_was_sensed(o_ptr)) { int unlearned = object_num_unlearned_flags(o_ptr); switch(unlearned) { case 0: textblock_append(tb, "It has no unknown flags.\n"); break; case 1: textblock_append(tb, "It has 1 unknown flag.\n", unlearned); break; default: textblock_append(tb, "It has %d unknown flags.\n", unlearned); break; } } } something = TRUE; } if (describe_curses(tb, o_ptr, flags)) something = TRUE; if (describe_stats(tb, o_ptr, pval_flags, mode)) something = TRUE; if (describe_slays(tb, flags, o_ptr->tval)) something = TRUE; if (describe_immune(tb, flags)) something = TRUE; if (describe_ignores(tb, flags)) something = TRUE; if (describe_sustains(tb, flags)) something = TRUE; if (describe_misc_magic(tb, flags)) something = TRUE; if (ego && describe_ego(tb, o_ptr->ego)) something = TRUE; if (something) textblock_append(tb, "\n"); if (describe_effect(tb, o_ptr, full, terse, subjective)) { something = TRUE; textblock_append(tb, "\n"); } if (subjective && describe_combat(tb, o_ptr, mode)) { something = TRUE; textblock_append(tb, "\n"); } if (!terse && describe_food(tb, o_ptr, subjective, full)) something = TRUE; if (describe_light(tb, o_ptr, flags, terse)) something = TRUE; if (!terse && subjective && describe_digger(tb, o_ptr, mode)) something = TRUE; if (!something) textblock_append(tb, "\n\nThis item does not seem to possess any special abilities."); return tb; }
/* * Output object information */ static textblock *object_info_out(const object_type *o_ptr, oinfo_detail_t mode) { bitflag flags[OF_SIZE]; bitflag pval_flags[MAX_PVALS][OF_SIZE]; bool something = FALSE; bool known = object_is_known(o_ptr); bool full = mode & OINFO_FULL; bool terse = mode & OINFO_TERSE; bool subjective = mode & OINFO_SUBJ; bool ego = mode & OINFO_EGO; textblock *tb = textblock_new(); /* Grab the object flags */ if (full) { object_flags(o_ptr, flags); object_pval_flags(o_ptr, pval_flags); } else { object_flags_known(o_ptr, flags); object_pval_flags_known(o_ptr, pval_flags); } if (subjective) describe_origin(tb, o_ptr); if (!terse) describe_flavor_text(tb, o_ptr, mode); if (!full && !known) { textblock_append(tb, "You do not know the full extent of this item's powers.\n"); something = TRUE; } if (describe_curses(tb, o_ptr, flags)) something = TRUE; if (describe_stats(tb, o_ptr, pval_flags, mode)) something = TRUE; if (describe_slays(tb, flags, o_ptr->tval)) something = TRUE; if (describe_immune(tb, flags)) something = TRUE; if (describe_ignores(tb, flags)) something = TRUE; dedup_hates_flags(flags); if (describe_hates(tb, flags)) something = TRUE; if (describe_sustains(tb, flags)) something = TRUE; if (describe_misc_magic(tb, flags)) something = TRUE; if (ego && describe_ego(tb, o_ptr->ego)) something = TRUE; if (something) textblock_append(tb, "\n"); if (!ego && describe_effect(tb, o_ptr, full, terse, subjective)) { something = TRUE; textblock_append(tb, "\n"); } if (subjective && describe_combat(tb, o_ptr, mode)) { something = TRUE; textblock_append(tb, "\n"); } if (!terse && describe_food(tb, o_ptr, subjective, full)) something = TRUE; if (describe_light(tb, o_ptr, flags, mode)) something = TRUE; if (!terse && subjective && describe_digger(tb, o_ptr, mode)) something = TRUE; if (!something) textblock_append(tb, "\n\nThis item does not seem to possess any special abilities."); return tb; }
/** * Output object information */ static textblock *object_info_out(const struct object *obj, int mode) { bitflag flags[OF_SIZE]; struct element_info el_info[N_ELEMENTS(elements)]; bool something = false; bool known = object_all_but_flavor_is_known(obj); bool terse = mode & OINFO_TERSE ? true : false; bool subjective = mode & OINFO_SUBJ ? true : false; bool ego = mode & OINFO_EGO ? true : false; textblock *tb = textblock_new(); const struct object *known_obj = obj->known ? obj->known : obj; /* Unaware objects get simple descriptions */ if (obj->kind != known_obj->kind) { textblock_append(tb, "\n\nYou do not know what this is.\n"); return tb; } /* Grab the object flags */ get_known_flags(obj, mode, flags); /* Grab the element info */ get_known_elements(obj, mode, el_info); if (subjective) describe_origin(tb, obj, terse); if (!terse) describe_flavor_text(tb, obj, ego); if (!known) { textblock_append(tb, "You do not know the full extent of this item's powers.\n"); something = true; } if (describe_curses(tb, obj, flags)) something = true; if (describe_stats(tb, obj, mode)) something = true; if (describe_slays(tb, obj)) something = true; if (describe_brands(tb, obj)) something = true; if (describe_elements(tb, el_info)) something = true; if (describe_protects(tb, flags)) something = true; if (describe_ignores(tb, el_info)) something = true; if (describe_hates(tb, el_info)) something = true; if (describe_sustains(tb, flags)) something = true; if (describe_misc_magic(tb, flags)) something = true; if (describe_light(tb, obj, mode)) something = true; if (ego && describe_ego(tb, obj->ego)) something = true; if (something) textblock_append(tb, "\n"); /* Skip all the very specific information where we are giving general ego knowledge rather than for a single item - abilities can vary */ if (!ego) { if (describe_effect(tb, obj, terse, subjective)) { something = true; textblock_append(tb, "\n"); } if (subjective && describe_combat(tb, obj)) { something = true; textblock_append(tb, "\n"); } if (!terse && subjective && describe_digger(tb, obj)) something = true; } /* Don't append anything in terse (for chararacter dump) */ if (!something && !terse) textblock_append(tb, "\n\nThis item does not seem to possess any special abilities."); return tb; }
/** * Create a spoiler file for monsters (-SHAWN-) */ static void spoil_mon_info(const char *fname) { char buf[1024]; int i, n; u16b *who; int count = 0; textblock *tb = NULL; /* Open the file */ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname); fh = file_open(buf, MODE_WRITE, FTYPE_TEXT); if (!fh) { msg("Cannot create spoiler file."); return; } /* Dump the header */ tb = textblock_new(); textblock_append(tb, "Monster Spoilers for %s\n", buildid); textblock_append(tb, "------------------------------------------\n\n"); textblock_to_file(tb, fh, 0, 75); textblock_free(tb); tb = NULL; /* Allocate the "who" array */ who = mem_zalloc(z_info->r_max * sizeof(u16b)); /* Scan the monsters */ for (i = 1; i < z_info->r_max; i++) { struct monster_race *race = &r_info[i]; /* Use that monster */ if (race->name) who[count++] = (u16b)i; } sort(who, count, sizeof(*who), cmp_monsters); /* List all monsters in order. */ for (n = 0; n < count; n++) { int r_idx = who[n]; const struct monster_race *race = &r_info[r_idx]; const struct monster_lore *lore = &l_list[r_idx]; tb = textblock_new(); /* Line 1: prefix, name, color, and symbol */ if (rf_has(race->flags, RF_QUESTOR)) textblock_append(tb, "[Q] "); else if (rf_has(race->flags, RF_UNIQUE)) textblock_append(tb, "[U] "); else textblock_append(tb, "The "); /* As of 3.5, race->name and race->text are stored as UTF-8 strings; * there is no conversion from the source edit files. */ textblock_append_utf8(tb, race->name); textblock_append(tb, " ("); /* ---)--- */ textblock_append(tb, attr_to_text(race->d_attr)); textblock_append(tb, " '%c')\n", race->d_char); /* Line 2: number, level, rarity, speed, HP, AC, exp */ textblock_append(tb, "=== "); textblock_append(tb, "Num:%d ", r_idx); textblock_append(tb, "Lev:%d ", race->level); textblock_append(tb, "Rar:%d ", race->rarity); if (race->speed >= 110) textblock_append(tb, "Spd:+%d ", (race->speed - 110)); else textblock_append(tb, "Spd:-%d ", (110 - race->speed)); textblock_append(tb, "Hp:%d ", race->avg_hp); textblock_append(tb, "Ac:%d ", race->ac); textblock_append(tb, "Exp:%ld\n", (long)(race->mexp)); /* Normal description (with automatic line breaks) */ lore_description(tb, race, lore, true); textblock_append(tb, "\n"); textblock_to_file(tb, fh, 0, 75); textblock_free(tb); tb = NULL; } /* Free the "who" array */ mem_free(who); /* Check for errors */ if (!file_close(fh)) { msg("Cannot close spoiler file."); return; } msg("Successfully created a spoiler file."); }
int edit_text(char *buffer, int buflen) { int len = strlen(buffer); bool done = FALSE; int cursor = 0; while (!done) { int x, y; struct keypress ke; region area = { 1, HIST_INSTRUCT_ROW + 1, 71, 5 }; textblock *tb = textblock_new(); size_t *line_starts = NULL, *line_lengths = NULL; size_t n_lines; /* Display on screen */ clear_from(HIST_INSTRUCT_ROW); textblock_append(tb, buffer); textblock_append(tb, "\n"); /* XXX This shouldn't be necessary */ textui_textblock_place(tb, area, NULL); n_lines = textblock_calculate_lines(tb, &line_starts, &line_lengths, area.width); /* Set cursor to current editing position */ get_screen_loc(cursor, &x, &y, n_lines, line_starts, line_lengths); Term_gotoxy(1 + x, 19 + y); ke = inkey(); switch (ke.code) { case ESCAPE: return -1; case KC_ENTER: done = TRUE; break; case ARROW_LEFT: if (cursor > 0) cursor--; break; case ARROW_RIGHT: if (cursor < len) cursor++; break; case ARROW_DOWN: { int add = line_lengths[y] + 1; if (cursor + add < len) cursor += add; break; } case ARROW_UP: if (y > 0) { int up = line_lengths[y - 1] + 1; if (cursor - up >= 0) cursor -= up; } break; case KC_END: cursor = MAX(0, len); break; case KC_HOME: cursor = 0; break; case KC_BACKSPACE: case KC_DELETE: { /* Refuse to backspace into oblivion */ if ((ke.code == KC_BACKSPACE && cursor == 0) || (ke.code == KC_DELETE && cursor >= len)) break; /* Move the string from k to nul along to the left by 1 */ if (ke.code == KC_BACKSPACE) memmove(&buffer[cursor - 1], &buffer[cursor], len - cursor); else memmove(&buffer[cursor], &buffer[cursor + 1], len - cursor - 1); /* Decrement */ if (ke.code == KC_BACKSPACE) cursor--; len--; /* Terminate */ buffer[len] = '\0'; break; } default: { bool atnull = (buffer[cursor] == 0); if (!isprint(ke.code)) break; if (atnull) { /* Make sure we have enough room for a new character */ if ((cursor + 1) >= buflen) break; } else { /* Make sure we have enough room to add a new character */ if ((cursor + 1) >= buflen) break; /* Move the rest of the buffer along to make room */ memmove(&buffer[cursor + 1], &buffer[cursor], len - cursor); } /* Insert the character */ buffer[cursor++] = (char)ke.code; len++; /* Terminate */ buffer[len] = '\0'; break; } } textblock_free(tb); } return 0; }