/* * Initialise buttons. */ void button_init(button_add_f add, button_kill_f kill) { /* Prepare mouse button arrays */ button_mse = C_ZNEW(MAX_MOUSE_BUTTONS, button_mouse); button_backup = C_ZNEW(MAX_MOUSE_BUTTONS, button_mouse); /* Initialise the hooks */ button_add_hook = add; button_kill_hook = kill; }
/* * Using k_info[], init rarity data for the entire dungeon. */ bool init_obj_alloc(void) { int k_max = z_info->k_max; int item, lev; /* Free obj_allocs if allocated */ FREE(obj_alloc); /* Allocate and wipe */ obj_alloc = C_ZNEW((MAX_O_DEPTH + 1) * k_max, byte); obj_alloc_great = C_ZNEW((MAX_O_DEPTH + 1) * k_max, byte); /* Wipe the totals */ C_WIPE(obj_total, MAX_O_DEPTH + 1, u32b); C_WIPE(obj_total_great, MAX_O_DEPTH + 1, u32b); /* Init allocation data */ for (item = 1; item < k_max; item++) { const object_kind *kind = &k_info[item]; int min = kind->alloc_min; int max = kind->alloc_max; /* If an item doesn't have a rarity, move on */ if (!kind->alloc_prob) continue; /* Go through all the dungeon levels */ for (lev = 0; lev <= MAX_O_DEPTH; lev++) { int rarity = kind->alloc_prob; /* Save the probability in the standard table */ if ((lev < min) || (lev > max)) rarity = 0; obj_total[lev] += rarity; obj_alloc[(lev * k_max) + item] = rarity; /* Save the probability in the "great" table if relevant */ if (!kind_is_good(kind)) rarity = 0; obj_total_great[lev] += rarity; obj_alloc_great[(lev * k_max) + item] = rarity; } } return TRUE; }
static void autoinscribe_init(void) { /* Paranoia */ autoinscribe_clean(); inscriptions = C_ZNEW(AUTOINSCRIPTIONS_MAX, autoinscription); }
/* * Choose and create an instance of an object kind */ static void wiz_create_artifact(void) { size_t num, i; menu_type *menu = menu_new(MN_SKIN_COLUMNS, &wiz_create_item_menu); tval_desc *a_tvals; choose_artifact = TRUE; a_tvals = C_ZNEW(N_ELEMENTS(tvals), tval_desc); for (num = i = 0; i < N_ELEMENTS(tvals); i++) { /* Don't show tvals with no artifacts. */ if (!(tvals[i].can_be_artifact)) continue; /* Increment number of items in list. */ a_tvals[num++] = tvals[i]; } menu->selections = all_letters; menu->title = "What kind of artifact?"; screen_save(); clear_from(0); menu_setpriv(menu, num, a_tvals); menu_layout(menu, &wiz_create_item_area); menu_select(menu, 0, FALSE); screen_load(); FREE(a_tvals); }
/** * Computes the intersection of a bitfield and multiple bitflags. * * The flags not specified in `...` are cleared in `flags`. The bitfeild size * is supplied in `size`. TRUE is returned when changes were made, FALSE * otherwise. * * WARNING: FLAG_END must be the final argument in the `...` list. */ bool flags_mask(bitflag *flags, const size_t size, ...) { int f; va_list args; bool delta = FALSE; bitflag *mask; /* Build the mask */ mask = C_ZNEW(size, bitflag); va_start(args, size); /* Process each flag in the va-args */ for (f = va_arg(args, int); f != FLAG_END; f = va_arg(args, int)) flag_on(mask, size, f); va_end(args); delta = flag_inter(flags, mask, size); /* Free the mask */ FREE(mask); return delta; }
/* * Display known monsters. */ static void do_cmd_knowledge_monsters(const char *name, int row) { group_funcs r_funcs = { N_ELEMENTS(monster_group), FALSE, race_name, m_cmp_race, default_group, mon_summary }; member_funcs m_funcs = { display_monster, mon_lore, m_xchar, m_xattr, recall_prompt, 0, 0 }; int *monsters; int m_count = 0; int i; size_t j; for (i = 0; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; if (!OPT(cheat_know) && !l_list[i].sights) continue; if (!r_ptr->name) continue; if (rf_has(r_ptr->flags, RF_UNIQUE)) m_count++; for (j = 1; j < N_ELEMENTS(monster_group) - 1; j++) { const char *pat = monster_group[j].chars; if (strchr(pat, r_ptr->d_char)) m_count++; } } default_join = C_ZNEW(m_count, join_t); monsters = C_ZNEW(m_count, int); m_count = 0; for (i = 0; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; if (!OPT(cheat_know) && !l_list[i].sights) continue; if (!r_ptr->name) continue; for (j = 0; j < N_ELEMENTS(monster_group) - 1; j++) { const char *pat = monster_group[j].chars; if (j == 0 && !(rf_has(r_ptr->flags, RF_UNIQUE))) continue; else if (j > 0 && !strchr(pat, r_ptr->d_char)) continue; monsters[m_count] = m_count; default_join[m_count].oid = i; default_join[m_count++].gid = j; } } display_knowledge("monsters", monsters, m_count, r_funcs, m_funcs, " Sym Kills"); FREE(default_join); FREE(monsters); }
/** * Display list of monster traps. */ bool trap_menu(void) { menu_type menu; menu_iter menu_f = { trap_tag, 0, trap_display, trap_action, 0 }; region area = { 15, 1, 48, -1 }; ui_event_data evt = { EVT_NONE, 0, 0, 0, 0 }; size_t i, num = 0; u16b *choice; /* See how many traps available */ if (player_has(PF_EXTRA_TRAP)) num = 1 + (p_ptr->lev / 4); else num = 1 + (p_ptr->lev / 6); /* Create the array */ choice = C_ZNEW(num, u16b); /* Obvious */ for (i = 0; i < num; i++) { choice[i] = i; } /* Clear space */ area.page_rows = num + 2; /* Return here if there are no traps */ if (!num) { FREE(choice); return FALSE; } /* Save the screen and clear it */ screen_save(); /* Help text */ /* Set up the menu */ WIPE(&menu, menu); menu_init(&menu, MN_SKIN_SCROLL, &menu_f); menu.title = "Choose an advanced monster trap (ESC to cancel):"; menu_setpriv(&menu, num, choice); menu_layout(&menu, &area); prt("", area.row + 1, area.col); /* Select an entry */ evt = menu_select(&menu, 0); /* Free memory */ FREE(choice); /* Load screen */ screen_load(); return (evt.type != EVT_ESCAPE); }
/** * Create a cache of slay combinations found on ego items, and the values of * these combinations. This is to speed up slay_power(), which will be called * many times for ego items during the game. * * \param items is the set of ego types from which we are extracting slay * combinations */ errr create_slay_cache(struct ego_item *items) { int i; int j; int count = 0; bitflag cacheme[OF_SIZE]; bitflag slay_mask[OF_SIZE]; bitflag **dupcheck; ego_item_type *e_ptr; /* Build the slay mask */ create_mask(slay_mask, FALSE, OFT_SLAY, OFT_KILL, OFT_BRAND, OFT_MAX); /* Calculate necessary size of slay_cache */ dupcheck = C_ZNEW(z_info->e_max, bitflag *); for (i = 0; i < z_info->e_max; i++) { dupcheck[i] = C_ZNEW(OF_SIZE, bitflag); e_ptr = items + i; /* Find the slay flags on this ego */ of_copy(cacheme, e_ptr->flags); of_inter(cacheme, slay_mask); /* Only consider non-empty combinations of slay flags */ if (!of_is_empty(cacheme)) { /* Skip previously scanned combinations */ for (j = 0; j < i; j++) if (of_is_equal(cacheme, dupcheck[j])) continue; /* msg("Found a new slay combo on an ego item"); */ count++; of_copy(dupcheck[i], cacheme); } } /* Allocate slay_cache with an extra empty element for an iteration stop */ slay_cache = C_ZNEW((count + 1), struct flag_cache); count = 0; /* Populate the slay_cache */ for (i = 0; i < z_info->e_max; i++) { if (!of_is_empty(dupcheck[i])) { of_copy(slay_cache[count].flags, dupcheck[i]); slay_cache[count].value = 0; count++; /*msg("Cached a slay combination");*/ } } for (i = 0; i < z_info->e_max; i++) FREE(dupcheck[i]); FREE(dupcheck); /* Success */ return 0; }
/** * Select an ego affix that fits the object. * * \param o_ptr is the object looking for an affix. * \param level is the effective generation level (not necc. dungeon level) * \param max_lev is the highest quality of affix we're allowed. * \param min_lev is the lowest quality of affix we're allowed. */ static int obj_find_affix(object_type *o_ptr, int level, int max_lev, int min_lev) { int i, j, success = 0; long total = 0L; alloc_entry *table; ego_item_type *ego; bool material = FALSE, make = FALSE, quality = FALSE; table = C_ZNEW(z_info->e_max, alloc_entry); /* Look through an item's existing affixes for material/make/quality */ for (i = 0; i < MAX_AFFIXES && o_ptr->affix[i]; i++) { if (affix_is_quality(o_ptr->affix[i]->eidx)) quality = TRUE; if (affix_is_make(o_ptr->affix[i]->eidx)) make = TRUE; if (affix_is_material(o_ptr->affix[i]->eidx)) material = TRUE; } /* Go through all possible affixes and find ones legal for this item */ for (i = 0; i < z_info->e_max; i++) { ego = &e_info[i]; /* Test if this is a legal ego-item type for this object & level */ for (j = 0; j < EGO_TVALS_MAX; j++) { if (o_ptr->tval == ego->tval[j] && o_ptr->sval >= ego->min_sval[j] && o_ptr->sval <= ego->max_sval[j] && level >= ego->alloc_min[j] && p_ptr->depth <= ego->alloc_max[j] && ((affix_is_quality(i) && !quality) || (affix_is_make(i) && !make) || (affix_is_material(i) && !material) || (affix_is_suffix(i))) && max_lev >= ego->level[j] && min_lev <= ego->level[j]) { table[i].prob3 = ego->alloc_prob[j]; table[i].index = ego->eidx; break; } } total += table[i].prob3; } /* Choose at random from all legal affixes */ success = table_pick(total, z_info->e_max, table); mem_free(table); if (success > 0) return success; /* No legal affixes */ return 0; }
static void autoinscribe_init(void) { if (inscriptions) FREE(inscriptions); inscriptions = 0; inscriptions_count = 0; inscriptions = C_ZNEW(AUTOINSCRIPTIONS_MAX, autoinscription); }
/** * Display list of places to jump to. */ bool jump_menu(int level, int *location) { menu_type menu; menu_iter menu_f = { jump_tag, 0, jump_display, jump_action, 0 }; region area = { 15, 1, 48, -1 }; ui_event_data evt = { EVT_NONE, 0, 0, 0, 0 }; int cursor = 0, j = 0; size_t i; u16b *choice; /* Dungeon only is easy */ if (OPT(adult_dungeon)) { *location = level + 1; return TRUE; } /* Create the array */ choice = C_ZNEW(15, u16b); /* Get the possible stages */ for (i = 0; i < NUM_STAGES; i++) if ((stage_map[i][DEPTH] == level) && (stage_map[i][LOCALITY] != 0)) choice[j++] = i; /* Clear space */ area.page_rows = j + 2; /* Save the screen and clear it */ screen_save(); /* Set up the menu */ WIPE(&menu, menu); menu.title = "Which region do you want to be transported to?"; menu.cmd_keys = " \n\r"; menu_init(&menu, MN_SKIN_SCROLL, &menu_f); menu_setpriv(&menu, j, choice); menu_layout(&menu, &area); /* Select an entry */ evt = menu_select(&menu, cursor); /* Set it */ if (evt.type == EVT_SELECT) *location = place; /* Free memory */ FREE(choice); /* Load screen */ screen_load(); return (evt.type != EVT_ESCAPE); }
/** * Select an ego theme that fits the object. * * \param o_ptr is the object looking for aa theme * \param level is the effective generation level (not necc. dungeon level) */ static int obj_find_theme(object_type *o_ptr, int level) { int i, j, k, wgt, num, success = 0; long total = 0L; alloc_entry *table; struct theme *theme; table = C_ZNEW(z_info->theme_max, alloc_entry); /* Go through all possible themes and find ones legal for this item */ for (i = 0; i < z_info->theme_max; i++) { theme = &themes[i]; /* Test if this is a legal theme for this object & level */ for (j = 0; j < EGO_TVALS_MAX; j++) { if (o_ptr->tval == theme->tval[j] && o_ptr->sval >= theme->min_sval[j] && o_ptr->sval <= theme->max_sval[j] && level >= theme->alloc_min[j] && p_ptr->depth <= theme->alloc_max[j]) { table[i].index = theme->index; break; } } if (table[i].index) { /* It's legal, so check for relevant affixes */ wgt = num = 0; for (j = 0; j < MAX_AFFIXES; j++) { if (!o_ptr->affix[j]) continue; for (k = 0; k < theme->num_affixes; k++) if (o_ptr->affix[j]->eidx == theme->affix[k]) { num++; wgt += theme->aff_wgt[k]; } } if (num > 1) table[i].prob3 = (wgt * 8 * wgt) / theme->tot_wgt; } total += table[i].prob3; } /* Choose at random from all legal themes, if we pass the roll */ if (randint0(200) < total) success = table_pick(total, z_info->theme_max, table); mem_free(table); if (success > 0) return success; /* No legal themes */ return 0; }
/* * Set the number of history items. */ static bool history_set_num(size_t num) { history_info *new_list; if (num > HISTORY_MAX) num = HISTORY_MAX; if (num < history_size) return FALSE; if (num == history_size) return FALSE; /* Allocate new memory, copy across */ /* XXX Should use mem_realloc() */ new_list = C_ZNEW(num, history_info); C_COPY(new_list, history_list, history_ctr, history_info); FREE(history_list); history_list = new_list; history_size = num; return TRUE; }
/* * Display known ego_items */ static void do_cmd_knowledge_ego_items(const char *name, int row) { group_funcs obj_f = {TV_GOLD, FALSE, ego_grp_name, e_cmp_tval, default_group, 0}; member_funcs ego_f = {display_ego_item, desc_ego_fake, 0, 0, recall_prompt, 0, 0}; int *egoitems; int e_count = 0; int i, j; /* HACK: currently no more than 3 tvals for one ego type */ egoitems = C_ZNEW(z_info->e_max * EGO_TVALS_MAX, int); default_join = C_ZNEW(z_info->e_max * EGO_TVALS_MAX, join_t); for (i = 0; i < z_info->e_max; i++) { if (e_info[i].everseen || OPT(cheat_xtra)) { for (j = 0; j < EGO_TVALS_MAX && e_info[i].tval[j]; j++) { int gid = obj_group_order[e_info[i].tval[j]]; /* Ignore duplicate gids */ if (j > 0 && gid == default_join[e_count - 1].gid) continue; egoitems[e_count] = e_count; default_join[e_count].oid = i; default_join[e_count++].gid = gid; } } } display_knowledge("ego items", egoitems, e_count, obj_f, ego_f, NULL); FREE(default_join); FREE(egoitems); }
/* * Initialise buttons. */ void button_init(void) { /* Prepare mouse button arrays */ button_1d_list = C_ZNEW(MAX_MOUSE_BUTTONS, button_mouse_1d); button_backups = NULL; button_stack = NULL; /* initialize the global numbers */ button_1d_start_x = 0; button_1d_start_y = 0; button_1d_length = 0; button_1d_num = 0; button_num = 0; mouse_press = 0; /* Initialise the hooks */ button_add_2d_hook = NULL; button_add_1d_hook = NULL; button_kill_hook = NULL; button_print_hook = NULL; button_get_hook = NULL; }
static void init_ego_allocs(void) { struct alloc_entry *table; int i; ego_item_type *e_ptr; s16b num[MAX_DEPTH]; s16b aux[MAX_DEPTH]; /* Clear the "aux" array */ (void)C_WIPE(aux, MAX_DEPTH, s16b); /* Clear the "num" array */ (void)C_WIPE(num, MAX_DEPTH, s16b); /* Size of "alloc_ego_table" */ alloc_ego_size = 0; /* Scan the ego items */ for (i = 1; i < z_info->e_max; i++) { /* Get the i'th ego item */ e_ptr = &e_info[i]; /* Legal items */ if (e_ptr->rarity) { /* Count the entries */ alloc_ego_size++; /* Group by level */ num[e_ptr->level]++; } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH; i++) { /* Group by level */ num[i] += num[i-1]; } /*** Initialize ego-item allocation info ***/ /* Allocate the alloc_ego_table */ alloc_ego_table = C_ZNEW(alloc_ego_size, alloc_entry); /* Get the table entry */ table = alloc_ego_table; /* Scan the ego-items */ for (i = 1; i < z_info->e_max; i++) { /* Get the i'th ego item */ e_ptr = &e_info[i]; /* Count valid pairs */ if (e_ptr->rarity) { int p, x, y, z; /* Extract the base level */ x = e_ptr->level; /* Extract the base probability */ p = (100 / e_ptr->rarity); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } }
/** * Attempt to create an artifact. If the object is already set to be an * artifact, use that. If the object kind is already set, check only artifacts * for that kind. * * \param o_ptr is the object to turn into an artifact * \param level is the effective creation level */ static bool make_artifact(object_type *o_ptr, int level) { int i, j, basemin = 0, basemax = 0, success = 0, entry = 0; long total = 0L; bool art_ok = TRUE; object_kind *kind; alloc_entry *table; artifact_type *a_ptr = NULL; /* Make sure birth no artifacts isn't set */ if (OPT(birth_no_artifacts)) art_ok = FALSE; /* Special handling of quest artifacts - these override the birth option */ if (o_ptr->artifact) { switch (o_ptr->artifact->aidx) { case ART_GROND: case ART_MORGOTH: art_ok = TRUE; } } if (!art_ok) return FALSE; /* No artifacts in the town */ if (!p_ptr->depth) return FALSE; /* Create the allocation table from allowed artifacts TODO: initialise it once at init and then restrict it here */ table = C_ZNEW(z_info->a_max, alloc_entry); for (i = 0; !o_ptr->artifact && i < z_info->a_max; i++) { a_ptr = &a_info[i]; /* Skip non-existent entries */ if (!a_ptr->name || !a_ptr->alloc_prob[0]) continue; /* Cannot make an artifact twice */ if (a_ptr->created) continue; /* Find the base object if we don't already have one */ if (!o_ptr->kind) { kind = lookup_kind(a_ptr->tval, a_ptr->sval); /* Make sure we now have a base object kind */ if (!kind) continue; basemin = kind->alloc_min; basemax = kind->alloc_max; } else { /* If we do have a kind, it must match */ if (a_ptr->tval != o_ptr->tval || a_ptr->sval != o_ptr->sval) continue; basemin = o_ptr->kind->alloc_min; basemax = o_ptr->kind->alloc_max; } /* Enforce minimum base object level (loosely) */ if (basemin > level) { /* Get the out-of-depth factor */ int d = (basemin - level) * 3; /* Roll for out-of-depth creation */ if (randint0(d) != 0) continue; } /* Enforce maximum base object level (strictly) */ if (basemax && basemax < p_ptr->depth) continue; for (j = 0; j < ART_ALLOC_MAX && a_ptr->alloc_prob[j]; j++) { /* Enforce minimum depth (loosely) */ if (a_ptr->alloc_min[j] > level) { /* Get the out-of-depth factor */ int d = (a_ptr->alloc_min[j] - level) * 2; /* Roll for out-of-depth creation */ if (randint0(d) != 0) continue; } /* Enforce maximum depth (strictly) */ if (a_ptr->alloc_max[j] < p_ptr->depth) continue; /* Looks good - add this artifact to the table */ table[entry].index = a_ptr->aidx; table[entry++].prob3 = a_ptr->alloc_prob[j]; total += a_ptr->alloc_prob[j]; } } /* Choose an artifact from the table, then free it */ if (!o_ptr->artifact) { success = table_pick(total, entry, table); if (success > 0) { a_ptr = &a_info[success]; o_ptr->artifact = a_ptr; } } mem_free(table); if (o_ptr->artifact) { /* If we haven't got a base object yet, do it now */ if (!o_ptr->kind) { kind = lookup_kind(a_ptr->tval, a_ptr->sval); /* Make sure we now have a base object kind */ if (!kind) return FALSE; object_prep(o_ptr, kind, level, RANDOMISE); o_ptr->artifact = a_ptr; } /* Paranoia -- no artifact stacks (yet) */ if (o_ptr->number != 1) return FALSE; /* Actually make the object into the chosen artifact */ copy_artifact_data(o_ptr, o_ptr->artifact); o_ptr->artifact->created = 1; return TRUE; } /* We didn't manage to select a legal artifact */ return FALSE; }
/* * Initialise an empty history list. */ static void history_init(size_t entries) { history_ctr = 0; history_size = entries; history_list = C_ZNEW(history_size, history_info); }
/* * 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; /* Open the file */ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname); fh = file_open(buf, MODE_WRITE, FTYPE_TEXT); /* Oops */ if (!fh) { msg("Cannot create spoiler file."); return; } /* Dump to the spoiler file */ text_out_hook = text_out_to_file; text_out_file = fh; /* Dump the header */ text_out("Monster Spoilers for %s\n", buildid); text_out("------------------------------------------\n\n"); /* Allocate the "who" array */ who = C_ZNEW(z_info->r_max, u16b); /* Scan the monsters */ for (i = 1; i < z_info->r_max; i++) { monster_race *r_ptr = &r_info[i]; /* Use that monster */ if (r_ptr->name) who[count++] = (u16b)i; } sort(who, count, sizeof(*who), cmp_monsters); /* * List all monsters in order (except the ghost). */ for (n = 0; n < count; n++) { int r_idx = who[n]; monster_race *r_ptr = &r_info[r_idx]; /* Prefix */ if (rf_has(r_ptr->flags, RF_QUESTOR)) { text_out("[Q] "); } else if (rf_has(r_ptr->flags, RF_UNIQUE)) { text_out("[U] "); } else { text_out("The "); } /* Name */ text_out("%s (", r_ptr->name); /* ---)--- */ /* Color */ text_out(attr_to_text(r_ptr->d_attr)); /* Symbol --(-- */ text_out(" '%c')\n", r_ptr->d_char); /* Indent */ text_out("=== "); /* Number */ text_out("Num:%d ", r_idx); /* Level */ text_out("Lev:%d ", r_ptr->level); /* Rarity */ text_out("Rar:%d ", r_ptr->rarity); /* Speed */ if (r_ptr->speed >= 110) { text_out("Spd:+%d ", (r_ptr->speed - 110)); } else { text_out("Spd:-%d ", (110 - r_ptr->speed)); } /* Hitpoints */ text_out("Hp:%d ", r_ptr->avg_hp); /* Armor Class */ text_out("Ac:%d ", r_ptr->ac); /* Experience */ text_out("Exp:%ld\n", (long)(r_ptr->mexp)); /* Describe */ describe_monster(r_idx, TRUE); /* Terminate the entry */ text_out("\n"); } /* Free the "who" array */ FREE(who); /* Check for errors */ if (!file_close(fh)) { msg("Cannot close spoiler file."); return; } msg("Successfully created a spoiler file."); }
/* * Create a spoiler file for monsters */ static void spoil_mon_desc(const char *fname) { int i, n = 0; char buf[1024]; char nam[80]; char lev[80]; char rar[80]; char spd[80]; char ac[80]; char hp[80]; char exp[80]; u16b *who; /* We use either ascii or system-specific encoding */ int encoding = (OPT(xchars_to_file)) ? SYSTEM_SPECIFIC : ASCII; /* Build the filename */ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, fname); fh = file_open(buf, MODE_WRITE, FTYPE_TEXT); /* Oops */ if (!fh) { msg("Cannot create spoiler file."); return; } /* Dump the header */ x_file_putf(fh, encoding, "Monster Spoilers for %s\n", buildid); x_file_putf(fh, encoding, "------------------------------------------\n\n"); /* Dump the header */ x_file_putf(fh, encoding, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n", "Name", "Lev", "Rar", "Spd", "Hp", "Ac", "Visual Info"); x_file_putf(fh, encoding, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n", "----", "---", "---", "---", "--", "--", "-----------"); /* Allocate the "who" array */ who = C_ZNEW(z_info->r_max, u16b); /* Scan the monsters (except the ghost) */ for (i = 1; i < z_info->r_max - 1; i++) { monster_race *r_ptr = &r_info[i]; /* Use that monster */ if (r_ptr->name) who[n++] = (u16b)i; } /* Sort the array by dungeon depth of monsters */ sort(who, n, sizeof(*who), cmp_monsters); /* Scan again */ for (i = 0; i < n; i++) { monster_race *r_ptr = &r_info[who[i]]; const char *name = r_ptr->name; /* Get the "name" */ if (rf_has(r_ptr->flags, RF_QUESTOR)) { strnfmt(nam, sizeof(nam), "[Q] %s", name); } else if (rf_has(r_ptr->flags, RF_UNIQUE)) { strnfmt(nam, sizeof(nam), "[U] %s", name); } else { strnfmt(nam, sizeof(nam), "The %s", name); } /* Level */ strnfmt(lev, sizeof(lev), "%d", r_ptr->level); /* Rarity */ strnfmt(rar, sizeof(rar), "%d", r_ptr->rarity); /* Speed */ if (r_ptr->speed >= 110) strnfmt(spd, sizeof(spd), "+%d", (r_ptr->speed - 110)); else strnfmt(spd, sizeof(spd), "-%d", (110 - r_ptr->speed)); /* Armor Class */ strnfmt(ac, sizeof(ac), "%d", r_ptr->ac); /* Hitpoints */ strnfmt(hp, sizeof(hp), "%d", r_ptr->avg_hp); /* Experience */ strnfmt(exp, sizeof(exp), "%ld", (long)(r_ptr->mexp)); /* Hack -- use visual instead */ strnfmt(exp, sizeof(exp), "%s '%c'", attr_to_text(r_ptr->d_attr), r_ptr->d_char); /* Dump the info */ x_file_putf(fh, encoding, "%-40.40s%4s%4s%6s%8s%4s %11.11s\n", nam, lev, rar, spd, hp, ac, exp); } /* End it */ file_putf(fh, "\n"); /* Free the "who" array */ FREE(who); /* Check for errors */ if (!file_close(fh)) { msg("Cannot close spoiler file."); return; } /* Worked */ msg("Successfully created a spoiler file."); }
static void init_race_allocs(void) { int i; monster_race *r_ptr; alloc_entry *table; s16b num[MAX_DEPTH]; s16b aux[MAX_DEPTH]; /* Clear the "aux" array */ (void)C_WIPE(aux, MAX_DEPTH, s16b); /* Clear the "num" array */ (void)C_WIPE(num, MAX_DEPTH, s16b); /* Size of "alloc_race_table" */ alloc_race_size = 0; /* Scan the monsters (not the ghost) */ for (i = 1; i < z_info->r_max - 1; i++) { /* Get the i'th race */ r_ptr = &r_info[i]; /* Legal monsters */ if (r_ptr->rarity) { /* Count the entries */ alloc_race_size++; /* Group by level */ num[r_ptr->level]++; } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH; i++) { /* Group by level */ num[i] += num[i-1]; } /* Paranoia */ if (!num[0]) quit("No town monsters!"); /*** Initialize monster allocation info ***/ /* Allocate the alloc_race_table */ alloc_race_table = C_ZNEW(alloc_race_size, alloc_entry); /* Get the table entry */ table = alloc_race_table; /* Scan the monsters (not the ghost) */ for (i = 1; i < z_info->r_max - 1; i++) { /* Get the i'th race */ r_ptr = &r_info[i]; /* Count valid pairs */ if (r_ptr->rarity) { int p, x, y, z; /* Extract the base level */ x = r_ptr->level; /* Extract the base probability */ p = (100 / r_ptr->rarity); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } }
/* * Initialize some other arrays */ static errr init_other(void) { int i; /*** Prepare the various "bizarre" arrays ***/ /* Initialize the "macro" package */ (void)macro_init(); /* Initialize the "quark" package */ (void)quarks_init(); /* Initialize squelch things */ autoinscribe_init(); squelch_init(); init_cmd_know(); /* Initialize the "message" package */ (void)messages_init(); /*** Prepare grid arrays ***/ /* Array of grids */ view_g = C_ZNEW(VIEW_MAX, u16b); /* Array of grids */ temp_g = C_ZNEW(TEMP_MAX, u16b); /* Hack -- use some memory twice */ temp_y = ((byte*)(temp_g)) + 0; temp_x = ((byte*)(temp_g)) + TEMP_MAX; /*** Prepare dungeon arrays ***/ /* Padded into array */ cave_info = C_ZNEW(DUNGEON_HGT, byte_256); cave_info2 = C_ZNEW(DUNGEON_HGT, byte_256); /* Feature array */ cave_feat = C_ZNEW(DUNGEON_HGT, byte_wid); /* Entity arrays */ cave_o_idx = C_ZNEW(DUNGEON_HGT, s16b_wid); cave_m_idx = C_ZNEW(DUNGEON_HGT, s16b_wid); /* Flow arrays */ cave_cost = C_ZNEW(DUNGEON_HGT, byte_wid); cave_when = C_ZNEW(DUNGEON_HGT, byte_wid); /*** Prepare "vinfo" array ***/ /* Used by "update_view()" */ (void)vinfo_init(); /*** Prepare entity arrays ***/ /* Objects */ o_list = C_ZNEW(z_info->o_max, object_type); /* Monsters */ mon_list = C_ZNEW(z_info->m_max, monster_type); /*** Prepare lore array ***/ /* Lore */ l_list = C_ZNEW(z_info->r_max, monster_lore); /*** Prepare mouse buttons ***/ button_init(button_add_text, button_kill_text); /*** Prepare quest array ***/ /* Quests */ q_list = C_ZNEW(MAX_Q_IDX, quest); /*** Prepare the inventory ***/ /* Allocate it */ inventory = C_ZNEW(ALL_INVEN_TOTAL, object_type); /*** Prepare the options ***/ option_set_defaults(); /* Initialize the window flags */ for (i = 0; i < ANGBAND_TERM_MAX; i++) { /* Assume no flags */ op_ptr->window_flag[i] = 0L; } /*** Pre-allocate space for the "format()" buffer ***/ /* Hack -- Just call the "format()" function */ (void)format("I wish you could swim, like dolphins can swim..."); /* Success */ return (0); }
/* * Pickup all gold at the player's current location. */ static void py_pickup_gold(void) { int py = p_ptr->py; int px = p_ptr->px; s32b total_gold = 0L; byte *treasure; s16b this_o_idx = 0; s16b next_o_idx = 0; object_type *o_ptr; int sound_msg; bool verbal = FALSE; /* Allocate an array of ordinary gold objects */ treasure = C_ZNEW(SV_GOLD_MAX, byte); /* Pick up all the ordinary gold objects */ for (this_o_idx = cave->o_idx[py][px]; this_o_idx; this_o_idx = next_o_idx) { /* Get the object */ o_ptr = object_byid(this_o_idx); /* Get the next object */ next_o_idx = o_ptr->next_o_idx; /* Ignore if not legal treasure */ if ((o_ptr->tval != TV_GOLD) || (o_ptr->sval >= SV_GOLD_MAX)) continue; /* Note that we have this kind of treasure */ treasure[o_ptr->sval]++; /* Remember whether feedback message is in order */ if (!squelch_item_ok(o_ptr)) verbal = TRUE; /* Increment total value */ total_gold += (s32b)o_ptr->pval[DEFAULT_PVAL]; /* Delete the gold */ delete_object_idx(this_o_idx); } /* Pick up the gold, if present */ if (total_gold) { char buf[1024]; char tmp[80]; int i, count, total; object_kind *kind; /* Build a message */ (void)strnfmt(buf, sizeof(buf), "You have found %ld gold pieces worth of ", (long)total_gold); /* Count the types of treasure present */ for (total = 0, i = 0; i < SV_GOLD_MAX; i++) { if (treasure[i]) total++; } /* List the treasure types */ for (count = 0, i = 0; i < SV_GOLD_MAX; i++) { /* Skip if no treasure of this type */ if (!treasure[i]) continue; /* Get this object index */ kind = lookup_kind(TV_GOLD, i); if (!kind) continue; /* Get the object name */ object_kind_name(tmp, sizeof tmp, kind, TRUE); /* Build up the pickup string */ my_strcat(buf, tmp, sizeof(buf)); /* Added another kind of treasure */ count++; /* Add a comma if necessary */ if ((total > 2) && (count < total)) my_strcat(buf, ",", sizeof(buf)); /* Add an "and" if necessary */ if ((total >= 2) && (count == total-1)) my_strcat(buf, " and", sizeof(buf)); /* Add a space or period if necessary */ if (count < total) my_strcat(buf, " ", sizeof(buf)); else my_strcat(buf, ".", sizeof(buf)); } /* Determine which sound to play */ if (total_gold < 200) sound_msg = MSG_MONEY1; else if (total_gold < 600) sound_msg = MSG_MONEY2; else sound_msg = MSG_MONEY3; /* Display the message */ if (verbal) msgt(sound_msg, "%s", buf); /* Add gold to purse */ p_ptr->au += total_gold; /* Redraw gold */ p_ptr->redraw |= (PR_GOLD); } /* Free the gold array */ FREE(treasure); }
/* * Initialize some other arrays */ static errr init_alloc(void) { int i, j; object_kind *k_ptr; feature_type *f_ptr; monster_race *r_ptr; ego_item_type *e_ptr; alloc_entry *table; s16b num[MAX_DEPTH_ALL]; s16b aux[MAX_DEPTH_ALL]; /*** Analyze object allocation info ***/ /* Clear the "aux" array */ (void)C_WIPE(aux, MAX_DEPTH_ALL, s16b); /* Clear the "num" array */ (void)C_WIPE(num, MAX_DEPTH_ALL, s16b); /* Size of "alloc_kind_table" */ alloc_kind_size = 0; /* Scan the objects */ for (i = 1; i < z_info->k_max; i++) { k_ptr = &k_info[i]; /* Scan allocation pairs */ for (j = 0; j < 4; j++) { /* Count the "legal" entries */ if (k_ptr->chance[j]) { /* Count the entries */ alloc_kind_size++; /* Group by level */ num[k_ptr->locale[j]]++; } } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH_ALL; i++) { /* Group by level */ num[i] += num[i-1]; } /* Paranoia */ if (!num[0]) quit("No town objects!"); /*** Initialize object allocation info ***/ /* Allocate the alloc_kind_table */ alloc_kind_table = C_ZNEW(alloc_kind_size, alloc_entry); /* Get the table entry */ table = alloc_kind_table; /* Scan the objects */ for (i = 1; i < z_info->k_max; i++) { k_ptr = &k_info[i]; /* Scan allocation pairs */ for (j = 0; j < 4; j++) { /* Count the "legal" entries */ if (k_ptr->chance[j]) { int p, x, y, z; /* Extract the base level */ x = k_ptr->locale[j]; /* Extract the base probability */ p = (100 / k_ptr->chance[j]); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } } /*** Analyze feature allocation info ***/ /* Clear the "aux" array */ (void)C_WIPE(&aux, MAX_DEPTH_ALL, s16b); /* Clear the "num" array */ (void)C_WIPE(&num, MAX_DEPTH_ALL, s16b); /* Size of "alloc_feat_table" */ alloc_feat_size = 0; /* Scan the features */ for (i = 1; i < z_info->f_max; i++) { /* Get the i'th race */ f_ptr = &f_info[i]; /* Legal features */ if (f_ptr->f_rarity) { /* Count the entries */ alloc_feat_size++; /* Group by level */ num[f_ptr->f_level]++; } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH_ALL; i++) { /* Group by level */ num[i] += num[i-1]; } /* Paranoia - not really necessary */ if (!num[0]) quit("No town features!"); /*** Initialize feature allocation info ***/ /* Allocate the alloc_feat_table */ alloc_feat_table = C_ZNEW(alloc_feat_size, alloc_entry); /* Get the table entry */ table = alloc_feat_table; /* Scan the features */ for (i = 1; i < z_info->f_max; i++) { /* Get the i'th feature */ f_ptr = &f_info[i]; /* Count valid pairs */ if (f_ptr->f_rarity) { int p, x, y, z; /* Extract the base level */ x = f_ptr->f_level; /* Extract the base probability */ p = (100 / f_ptr->f_rarity); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } /*** Analyze monster allocation info ***/ /* Clear the "aux" array */ (void)C_WIPE(aux, MAX_DEPTH_ALL, s16b); /* Clear the "num" array */ (void)C_WIPE(num, MAX_DEPTH_ALL, s16b); /* Size of "alloc_race_table" */ alloc_race_size = 0; /* Scan the monsters*/ for (i = 1; i < z_info->r_max; i++) { /* Get the i'th race */ r_ptr = &r_info[i]; /* Legal monsters */ if (r_ptr->rarity) { /* Count the entries */ alloc_race_size++; /* Group by level */ num[r_ptr->level]++; } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH_ALL; i++) { /* Group by level */ num[i] += num[i-1]; } /* Paranoia */ if (!num[0]) quit("No town monsters!"); /*** Initialize monster allocation info ***/ /* Allocate the alloc_race_table */ alloc_race_table = C_ZNEW(alloc_race_size, alloc_entry); /* Get the table entry */ table = alloc_race_table; /* Scan the monsters*/ for (i = 1; i < z_info->r_max; i++) { /* Get the i'th race */ r_ptr = &r_info[i]; /* Count valid pairs */ if (r_ptr->rarity) { int p, x, y, z; /* Extract the base level */ x = r_ptr->level; /* Extract the base probability */ p = (100 / r_ptr->rarity); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } /*** Analyze ego_item allocation info ***/ /* Clear the "aux" array */ (void)C_WIPE(aux, MAX_DEPTH_ALL, s16b); /* Clear the "num" array */ (void)C_WIPE(num, MAX_DEPTH_ALL, s16b); /* Size of "alloc_ego_table" */ alloc_ego_size = 0; /* Scan the ego items */ for (i = 1; i < z_info->e_max; i++) { /* Get the i'th ego item */ e_ptr = &e_info[i]; /* Legal items */ if (e_ptr->rarity) { /* Count the entries */ alloc_ego_size++; /* Group by level */ num[e_ptr->level]++; } } /* Collect the level indexes */ for (i = 1; i < MAX_DEPTH_ALL; i++) { /* Group by level */ num[i] += num[i-1]; } /*** Initialize ego-item allocation info ***/ /* Allocate the alloc_ego_table */ alloc_ego_table = C_ZNEW(alloc_ego_size, alloc_entry); /* Get the table entry */ table = alloc_ego_table; /* Scan the ego-items */ for (i = 1; i < z_info->e_max; i++) { /* Get the i'th ego item */ e_ptr = &e_info[i]; /* Count valid pairs */ if (e_ptr->rarity) { int p, x, y, z; /* Extract the base level */ x = e_ptr->level; /* Extract the base probability */ p = (100 / e_ptr->rarity); /* Skip entries preceding our locale */ y = (x > 0) ? num[x-1] : 0; /* Skip previous entries at this locale */ z = y + aux[x]; /* Load the entry */ table[z].index = i; table[z].level = x; table[z].prob1 = p; table[z].prob2 = p; table[z].prob3 = p; /* Another entry complete for this locale */ aux[x]++; } } /* Success */ return (0); }
/* * Display list of svals to be squelched. */ static bool sval_menu(int tval, const char *desc) { menu_type menu; menu_iter menu_f = { NULL, NULL, sval_display, sval_action }; region area = { 1, 5, -1, -1 }; int num = 0; size_t i; squelch_choice *choice; /* Create the array, with entries both for aware and unaware squelch */ choice = C_ZNEW(2 * z_info->k_max, squelch_choice); /* Iterate over all possible object kinds, finding ones which can be squelched */ for (i = 1; i < z_info->k_max; i++) { object_kind *k_ptr = &k_info[i]; /* Skip empty objects, unseen objects, and incorrect tvals */ if (!k_ptr->name) continue; if (k_ptr->tval != tval) continue; if (!k_ptr->aware) { /* can unaware squelch anything */ /* XXX Eddie should it be required that unaware squelched flavors have been seen this game, if so, how to save that info? */ choice[num].idx = i; choice[num].aware = FALSE; num++; } if (k_ptr->everseen || k_ptr->tval == TV_GOLD) { /* aware squelch requires everseen */ /* do not require awareness for aware squelch, so people can set at game start */ choice[num].idx = i; choice[num].aware = TRUE; num++; } } /* Return here if there are no objects */ if (!num) { FREE(choice); return FALSE; } /* sort by name in squelch menus except for categories of items that are aware from the start */ switch(tval) { case TV_LIGHT: case TV_MAGIC_BOOK: case TV_PRAYER_BOOK: case TV_DRAG_ARMOR: case TV_GOLD: /* leave sorted by sval */ break; default: /* sort by name */ ang_sort_comp = ang_sort_comp_hook_squelch_choices; ang_sort_swap = ang_sort_swap_hook_squelch_choices; ang_sort((void*)choice, NULL, num); } /* Save the screen and clear it */ screen_save(); clear_from(0); /* Help text */ /* Output to the screen */ text_out_hook = text_out_to_screen; /* Indent output */ text_out_indent = 1; text_out_wrap = 79; Term_gotoxy(1, 0); /* Display some helpful information */ text_out("Use the "); text_out_c(TERM_L_GREEN, "movement keys"); text_out(" to scroll the list or "); text_out_c(TERM_L_GREEN, "ESC"); text_out(" to return to the previous menu. "); text_out_c(TERM_L_BLUE, "Enter"); text_out(" toggles the current setting."); text_out_indent = 0; /* Run menu */ menu_init(&menu, MN_SKIN_SCROLL, &menu_f); menu_setpriv(&menu, num, choice); menu_layout(&menu, &area); menu_select(&menu, 0); /* Free memory */ FREE(choice); /* Load screen */ screen_load(); return TRUE; }
/* * Initialize some other arrays */ static errr init_other(void) { int i; /*** Prepare the various "bizarre" arrays ***/ /* Initialize the "macro" package */ (void)macro_init(); /* Initialize the "quark" package */ (void)quarks_init(); /* Initialize squelch things */ autoinscribe_init(); init_cmd_know(); /* Initialize the "message" package */ (void)messages_init(); /*** Prepare grid arrays ***/ /* Array of grids */ view_g = C_ZNEW(VIEW_MAX, u16b); /* Array of grids */ temp_g = C_ZNEW(TEMP_MAX, u16b); /* Hack -- use some memory twice */ temp_y = ((byte*)(temp_g)) + 0; temp_x = ((byte*)(temp_g)) + TEMP_MAX; /* Array of grids */ fire_g = C_ZNEW(VIEW_MAX, u16b); /* has_LIGHT patch causes both temp_g and temp_x/y to be used in targetting mode: can't use the same memory any more. */ temp_y = C_ZNEW(TEMP_MAX, byte); temp_x = C_ZNEW(TEMP_MAX, byte); /* Array of dynamic grids */ dyna_g = C_ZNEW(DYNA_MAX, dynamic_grid_type); /* Array of stacked monster messages */ mon_msg = C_ZNEW(MAX_STORED_MON_MSG, monster_race_message); mon_message_hist = C_ZNEW(MAX_STORED_MON_CODES, monster_message_history); /* Prepare monster movement array*/ mon_moment_info = C_ZNEW(z_info->m_max, move_moment_type); /*** Prepare dungeon arrays ***/ /* Padded into array */ cave_info = C_ZNEW(MAX_DUNGEON_HGT, u16b_256); /* Feature array */ cave_feat = C_ZNEW(MAX_DUNGEON_HGT, byte_wid); /* Entity arrays */ cave_o_idx = C_ZNEW(MAX_DUNGEON_HGT, s16b_wid); cave_m_idx = C_ZNEW(MAX_DUNGEON_HGT, s16b_wid); cave_x_idx = C_ZNEW(MAX_DUNGEON_HGT, s16b_wid); #ifdef MONSTER_SMELL /* Flow arrays */ cave_when = C_ZNEW(MAX_DUNGEON_HGT, byte_wid); #endif /* MONSTER_SMELL */ /*start with cost at center 0*/ for (i = 0; i < MAX_FLOWS; i++) { cost_at_center[i] = 0; } /*** Prepare "vinfo" array ***/ /* Used by "update_view()" */ (void)vinfo_init(); /*** Prepare entity arrays ***/ /* Objects */ o_list = C_ZNEW(z_info->o_max, object_type); /* Monsters */ mon_list = C_ZNEW(z_info->m_max, monster_type); /* Effects */ x_list = C_ZNEW(z_info->x_max, effect_type); /*** Prepare mosnter lore array ***/ /* Lore */ l_list = C_ZNEW(z_info->r_max, monster_lore); /*** Prepare terrain lore array ***/ /* Lore */ f_l_list = C_ZNEW(z_info->f_max, feature_lore); /*** Prepare artifact lore array ***/ /* Lore */ a_l_list = C_ZNEW(z_info->art_max, artifact_lore); /*** Prepare mouse buttons ***/ button_init(button_add_text, button_kill_text); /*** Prepare the inventory ***/ /* Allocate it */ inventory = C_ZNEW(ALL_INVEN_TOTAL, object_type); /*** Prepare the stores ***/ /* Allocate the stores */ store = C_ZNEW(MAX_STORES, store_type); /* Fill in each store */ for (i = 0; i < MAX_STORES; i++) { /* Get the store */ store_type *st_ptr = &store[i]; /* Assume full stock */ st_ptr->stock_size = STORE_INVEN_MAX; /* Allocate the stock */ st_ptr->stock = C_ZNEW(st_ptr->stock_size, object_type); } /*** Prepare the options ***/ /* Initialize the options */ for (i = 0; i < OPT_MAX; i++) { /* Default value */ op_ptr->opt[i] = options[i].normal; } /* Initialize the window flags */ for (i = 0; i < ANGBAND_TERM_MAX; i++) { /* Assume no flags */ op_ptr->window_flag[i] = 0L; } /*Clear the update flags*/ p_ptr->notice = 0L; p_ptr->update = 0L; p_ptr->redraw = 0L; /*** Pre-allocate space for the "format()" buffer ***/ /* Hack -- Just call the "format()" function */ (void)format("%s", MAINTAINER); /* Success */ return (0); }
/* * Identify a character, allow recall of monsters * * Several "special" responses recall "multiple" monsters: * ^A (all monsters) * ^U (all unique monsters) * ^N (all non-unique monsters) * * The responses may be sorted in several ways, see below. * * Note that the player ghosts are ignored, since they do not exist. */ void do_cmd_query_symbol(void) { int i, n, r_idx; char buf[128]; struct keypress sym; struct keypress query; bool all = FALSE; bool uniq = FALSE; bool norm = FALSE; bool recall = FALSE; u16b *who; /* Get a character, or abort */ if (!get_com("Enter character to be identified, or control+[ANU]: ", &sym)) return; /* Describe */ if (sym.code == KTRL('A')) { all = TRUE; my_strcpy(buf, "Full monster list.", sizeof(buf)); } else if (sym.code == KTRL('U')) { all = uniq = TRUE; my_strcpy(buf, "Unique monster list.", sizeof(buf)); } else if (sym.code == KTRL('N')) { all = norm = TRUE; my_strcpy(buf, "Non-unique monster list.", sizeof(buf)); } else { lookup_symbol(sym, buf, sizeof(buf)); } /* Display the result */ prt(buf, 0, 0); /* Allocate the "who" array */ who = C_ZNEW(z_info->r_max, u16b); /* Collect matching monsters */ for (n = 0, i = 1; i < z_info->r_max - 1; i++) { monster_race *r_ptr = &r_info[i]; monster_lore *l_ptr = &l_list[i]; /* Nothing to recall */ if (!OPT(cheat_know) && !l_ptr->sights) continue; /* Require non-unique monsters if needed */ if (norm && rf_has(r_ptr->flags, RF_UNIQUE)) continue; /* Require unique monsters if needed */ if (uniq && !rf_has(r_ptr->flags, RF_UNIQUE)) continue; /* Collect "appropriate" monsters */ if (all || (r_ptr->d_char == (char)sym.code)) who[n++] = i; } /* Nothing to recall */ if (!n) { /* XXX XXX Free the "who" array */ FREE(who); return; } /* Buttons */ button_add("[y]", 'y'); button_add("[k]", 'k'); /* Don't collide with the repeat button */ button_add("[n]", 'q'); redraw_stuff(p_ptr); /* Prompt */ put_str("Recall details? (y/k/n): ", 0, 40); /* Query */ query = inkey(); /* Restore */ prt(buf, 0, 0); /* Buttons */ button_kill('y'); button_kill('k'); button_kill('q'); redraw_stuff(p_ptr); /* Interpret the response */ if (query.code == 'k') { /* Sort by kills (and level) */ sort(who, n, sizeof(*who), cmp_pkill); } else if (query.code == 'y' || query.code == 'p') { /* Sort by level; accept 'p' as legacy */ sort(who, n, sizeof(*who), cmp_level); } else { /* Any unsupported response is "nope, no history please" */ /* XXX XXX Free the "who" array */ FREE(who); return; } /* Start at the end */ i = n - 1; /* Button */ button_add("[r]", 'r'); button_add("[-]", '-'); button_add("[+]", '+'); redraw_stuff(p_ptr); /* Scan the monster memory */ while (1) { /* Extract a race */ r_idx = who[i]; /* Hack -- Auto-recall */ monster_race_track(r_idx); /* Hack -- Handle stuff */ handle_stuff(p_ptr); /* Hack -- Begin the prompt */ roff_top(r_idx); /* Hack -- Complete the prompt */ Term_addstr(-1, TERM_WHITE, " [(r)ecall, ESC]"); /* Interact */ while (1) { /* Recall */ if (recall) { /* Save screen */ screen_save(); /* Recall on screen */ screen_roff(who[i]); /* Hack -- Complete the prompt (again) */ Term_addstr(-1, TERM_WHITE, " [(r)ecall, ESC]"); } /* Command */ query = inkey(); /* Unrecall */ if (recall) { /* Load screen */ screen_load(); } /* Normal commands */ if (query.code != 'r') break; /* Toggle recall */ recall = !recall; } /* Stop scanning */ if (query.code == ESCAPE) break; /* Move to "prev" monster */ if (query.code == '-') { if (++i == n) i = 0; } /* Move to "next" monster */ else { if (i-- == 0) i = n - 1; } } /* Button */ button_kill('r'); button_kill('-'); button_kill('+'); redraw_stuff(p_ptr); /* Re-display the identity */ prt(buf, 0, 0); /* Free the "who" array */ FREE(who); }