From be871d682e8087ab38c5e9e054190daf6f81fff2 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Fri, 6 Nov 2009 19:26:31 -0800 Subject: Split up debug.cc --- crawl-ref/source/wiz-item.cc | 1330 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1330 insertions(+) create mode 100644 crawl-ref/source/wiz-item.cc (limited to 'crawl-ref/source/wiz-item.cc') diff --git a/crawl-ref/source/wiz-item.cc b/crawl-ref/source/wiz-item.cc new file mode 100644 index 0000000000..9eaacc7c32 --- /dev/null +++ b/crawl-ref/source/wiz-item.cc @@ -0,0 +1,1330 @@ +/* + * File: wiz-item.cc + * Summary: Item related wizard functions. + * Written by: Linley Henzell and Jesse Jones + */ + +#include "AppHdr.h" + +#include "wiz-item.h" + +#include + +#include "artefact.h" +#include "coordit.h" +#include "message.h" +#include "cio.h" +#include "dbg-util.h" +#include "decks.h" +#include "effects.h" +#include "items.h" +#include "item_use.h" +#include "it_use2.h" +#include "invent.h" +#include "makeitem.h" +#include "monstuff.h" +#include "mon-util.h" +#include "options.h" +#include "religion.h" +#include "spl-book.h" +#include "spl-util.h" +#include "stash.h" +#include "stuff.h" +#include "terrain.h" +#include "view.h" + +#ifdef WIZARD +static void _make_all_books() +{ + for (int i = 0; i < NUM_FIXED_BOOKS; ++i) + { + int thing = items(0, OBJ_BOOKS, i, true, 0, MAKE_ITEM_NO_RACE, + 0, 0, AQ_WIZMODE); + if (thing == NON_ITEM) + continue; + + move_item_to_grid(&thing, you.pos()); + + item_def book(mitm[thing]); + + mark_had_book(book); + set_ident_flags(book, ISFLAG_KNOW_TYPE); + set_ident_flags(book, ISFLAG_IDENT_MASK); + + mprf("%s", book.name(DESC_PLAIN).c_str()); + } +} + +//--------------------------------------------------------------- +// +// create_spec_object +// +//--------------------------------------------------------------- +void wizard_create_spec_object() +{ + char specs[80]; + char keyin; + monster_type mon; + + object_class_type class_wanted = OBJ_UNASSIGNED; + + int thing_created; + + while (class_wanted == OBJ_UNASSIGNED) + { + mpr(") - weapons ( - missiles [ - armour / - wands ? - scrolls", + MSGCH_PROMPT); + mpr("= - jewellery ! - potions : - books | - staves 0 - The Orb", + MSGCH_PROMPT); + mpr("} - miscellany X - corpses % - food $ - gold ESC - exit", + MSGCH_PROMPT); + + mpr("What class of item? ", MSGCH_PROMPT); + + keyin = toupper( get_ch() ); + + if (keyin == ')') + class_wanted = OBJ_WEAPONS; + else if (keyin == '(') + class_wanted = OBJ_MISSILES; + else if (keyin == '[' || keyin == ']') + class_wanted = OBJ_ARMOUR; + else if (keyin == '/' || keyin == '\\') + class_wanted = OBJ_WANDS; + else if (keyin == '?') + class_wanted = OBJ_SCROLLS; + else if (keyin == '=' || keyin == '"') + class_wanted = OBJ_JEWELLERY; + else if (keyin == '!') + class_wanted = OBJ_POTIONS; + else if (keyin == ':' || keyin == '+') + class_wanted = OBJ_BOOKS; + else if (keyin == '|') + class_wanted = OBJ_STAVES; + else if (keyin == '0' || keyin == 'O') + class_wanted = OBJ_ORBS; + else if (keyin == '}' || keyin == '{') + class_wanted = OBJ_MISCELLANY; + else if (keyin == 'X' || keyin == '&') + class_wanted = OBJ_CORPSES; + else if (keyin == '%') + class_wanted = OBJ_FOOD; + else if (keyin == '$') + class_wanted = OBJ_GOLD; + else if (keyin == ESCAPE || keyin == ' ' + || keyin == '\r' || keyin == '\n') + { + canned_msg( MSG_OK ); + return; + } + } + + // Allocate an item to play with. + thing_created = get_item_slot(); + if (thing_created == NON_ITEM) + { + mpr("Could not allocate item."); + return; + } + + // turn item into appropriate kind: + if (class_wanted == OBJ_ORBS) + { + mitm[thing_created].base_type = OBJ_ORBS; + mitm[thing_created].sub_type = ORB_ZOT; + mitm[thing_created].quantity = 1; + } + else if (class_wanted == OBJ_GOLD) + { + int amount = debug_prompt_for_int( "How much gold? ", true ); + if (amount <= 0) + { + canned_msg( MSG_OK ); + return; + } + + mitm[thing_created].base_type = OBJ_GOLD; + mitm[thing_created].sub_type = 0; + mitm[thing_created].quantity = amount; + } + else if (class_wanted == OBJ_CORPSES) + { + mon = debug_prompt_for_monster(); + + if (mon == MONS_NO_MONSTER || mon == MONS_PROGRAM_BUG) + { + mpr("No such monster."); + return; + } + + if (mons_weight(mon) <= 0) + { + if (!yesno("That monster doesn't leave corpses; make one " + "anyway?")) + { + return; + } + } + + if (mon >= MONS_DRACONIAN_CALLER && mon <= MONS_DRACONIAN_SCORCHER) + { + mpr("You can't make a draconian corpse by its job."); + mon = MONS_DRACONIAN; + } + + monsters dummy; + dummy.type = mon; + + if (mons_genus(mon) == MONS_HYDRA) + dummy.number = debug_prompt_for_int("How many heads? ", false); + + if (fill_out_corpse(&dummy, mitm[thing_created], true) == -1) + { + mpr("Failed to create corpse."); + mitm[thing_created].clear(); + return; + } + } + else + { + if (class_wanted == OBJ_BOOKS) + mpr("What type of item? (\"all\" for all) ", MSGCH_PROMPT); + else + mpr("What type of item? ", MSGCH_PROMPT); + get_input_line( specs, sizeof( specs ) ); + + std::string temp = specs; + trim_string(temp); + lowercase(temp); + strcpy(specs, temp.c_str()); + + if (class_wanted == OBJ_BOOKS && temp == "all") + { + _make_all_books(); + return; + } + + if (specs[0] == '\0') + { + canned_msg( MSG_OK ); + return; + } + + if (!get_item_by_name(&mitm[thing_created], specs, class_wanted, true)) + { + mpr("No such item."); + + // Clean up item + destroy_item(thing_created); + return; + } + } + + // Deck colour (which control rarity) already set. + if (!is_deck(mitm[thing_created])) + item_colour( mitm[thing_created] ); + + move_item_to_grid( &thing_created, you.pos() ); + + if (thing_created != NON_ITEM) + { + // orig_monnum is used in corpses for things like the Animate + // Dead spell, so leave it alone. + if (class_wanted != OBJ_CORPSES) + origin_acquired(mitm[thing_created], AQ_WIZMODE); + canned_msg(MSG_SOMETHING_APPEARS); + + // Tell the stash tracker. + maybe_update_stashes(); + } +} + +const char* _prop_name[ARTP_NUM_PROPERTIES] = { + "Brand", + "AC", + "EV", + "Str", + "Int", + "Dex", + "Fire", + "Cold", + "Elec", + "Pois", + "Neg", + "Mag", + "SInv", + "Inv", + "Lev", + "Blnk", + "Bers", + "Nois", + "NoSpl", + "RndTl", + "NoTel", + "Anger", + "Metab", + "Mut", + "Acc", + "Dam", + "Curse", + "Stlth", + "MP", + "Spirit" +}; + +#define ARTP_VAL_BOOL 0 +#define ARTP_VAL_POS 1 +#define ARTP_VAL_ANY 2 + +char _prop_type[ARTP_NUM_PROPERTIES] = { + ARTP_VAL_POS, //BRAND + ARTP_VAL_ANY, //AC + ARTP_VAL_ANY, //EVASION + ARTP_VAL_ANY, //STRENGTH + ARTP_VAL_ANY, //INTELLIGENCE + ARTP_VAL_ANY, //DEXTERITY + ARTP_VAL_ANY, //FIRE + ARTP_VAL_ANY, //COLD + ARTP_VAL_BOOL, //ELECTRICITY + ARTP_VAL_BOOL, //POISON + ARTP_VAL_BOOL, //NEGATIVE_ENERGY + ARTP_VAL_POS, //MAGIC + ARTP_VAL_BOOL, //EYESIGHT + ARTP_VAL_BOOL, //INVISIBLE + ARTP_VAL_BOOL, //LEVITATE + ARTP_VAL_BOOL, //BLINK + ARTP_VAL_BOOL, //BERSERK + ARTP_VAL_POS, //NOISES + ARTP_VAL_BOOL, //PREVENT_SPELLCASTING + ARTP_VAL_BOOL, //CAUSE_TELEPORTATION + ARTP_VAL_BOOL, //PREVENT_TELEPORTATION + ARTP_VAL_POS, //ANGRY + ARTP_VAL_POS, //METABOLISM + ARTP_VAL_POS, //MUTAGENIC + ARTP_VAL_ANY, //ACCURACY + ARTP_VAL_ANY, //DAMAGE + ARTP_VAL_POS, //CURSED + ARTP_VAL_ANY, //STEALTH + ARTP_VAL_ANY, //MAGICAL_POWER + ARTP_VAL_BOOL //SPIRIT_SHIELD +}; + +static void _tweak_randart(item_def &item) +{ + if (item_is_equipped(item)) + { + mpr("You can't tweak the randart properties of an equipped item.", + MSGCH_PROMPT); + return; + } + + artefact_properties_t props; + artefact_wpn_properties(item, props); + + std::string prompt = ""; + + std::vector choice_to_prop; + for (unsigned int i = 0, choice_num = 0; i < ARTP_NUM_PROPERTIES; ++i) + { + if (_prop_name[i] == std::string("UNUSED")) + continue; + choice_to_prop.push_back(i); + if (choice_num % 8 == 0 && choice_num != 0) + prompt += "\n"; + + char choice; + char buf[80]; + + if (choice_num < 26) + choice = 'A' + choice_num; + else + choice = '1' + choice_num - 26; + + if (props[i]) + sprintf(buf, "%c) %-5s ", choice, _prop_name[i]); + else + sprintf(buf, "%c) %-5s ", choice, _prop_name[i]); + + prompt += buf; + + choice_num++; + } + formatted_message_history(prompt, MSGCH_PROMPT, 0, 80); + + mpr("Change which field? ", MSGCH_PROMPT); + + char keyin = tolower( get_ch() ); + unsigned int choice; + + if (isalpha(keyin)) + choice = keyin - 'a'; + else if (isdigit(keyin) && keyin != '0') + choice = keyin - '1' + 26; + else + return; + + if (choice >= choice_to_prop.size()) + return; + + unsigned int prop = choice_to_prop[choice]; + ASSERT(prop >= 0); + ASSERT(prop < ARRAYSZ(_prop_type)); + + int val; + switch (_prop_type[prop]) + { + case ARTP_VAL_BOOL: + mprf(MSGCH_PROMPT, "Toggling %s to %s.", _prop_name[prop], + props[prop] ? "off" : "on"); + artefact_set_property(item, static_cast(prop), + !props[prop]); + break; + + case ARTP_VAL_POS: + mprf(MSGCH_PROMPT, "%s was %d.", _prop_name[prop], props[prop]); + val = debug_prompt_for_int("New value? ", true); + + if (val < 0) + { + mprf(MSGCH_PROMPT, "Value for %s must be non-negative", + _prop_name[prop]); + return; + } + artefact_set_property(item, static_cast(prop), + val); + break; + case ARTP_VAL_ANY: + mprf(MSGCH_PROMPT, "%s was %d.", _prop_name[prop], props[prop]); + val = debug_prompt_for_int("New value? ", false); + artefact_set_property(item, static_cast(prop), + val); + break; + } + + if (Options.autoinscribe_artefacts) + item.inscription = artefact_auto_inscription(item); +} + +void wizard_tweak_object(void) +{ + char specs[50]; + char keyin; + + int item = prompt_invent_item("Tweak which item? ", MT_INVLIST, -1); + if (item == PROMPT_ABORT) + { + canned_msg( MSG_OK ); + return; + } + + if (item == you.equip[EQ_WEAPON]) + you.wield_change = true; + + const bool is_art = is_artefact(you.inv[item]); + + while (true) + { + void *field_ptr = NULL; + + while (true) + { + mpr(you.inv[item].name(DESC_INVENTORY_EQUIP).c_str()); + + if (is_art) + { + mpr("a - plus b - plus2 c - art props d - quantity " + "e - flags ESC - exit", MSGCH_PROMPT); + } + else + { + mpr("a - plus b - plus2 c - special d - quantity " + "e - flags ESC - exit", MSGCH_PROMPT); + } + + mpr("Which field? ", MSGCH_PROMPT); + + keyin = tolower( get_ch() ); + + if (keyin == 'a') + field_ptr = &(you.inv[item].plus); + else if (keyin == 'b') + field_ptr = &(you.inv[item].plus2); + else if (keyin == 'c') + field_ptr = &(you.inv[item].special); + else if (keyin == 'd') + field_ptr = &(you.inv[item].quantity); + else if (keyin == 'e') + field_ptr = &(you.inv[item].flags); + else if (keyin == ESCAPE || keyin == ' ' + || keyin == '\r' || keyin == '\n') + { + canned_msg( MSG_OK ); + return; + } + + if (keyin >= 'a' && keyin <= 'e') + break; + } + + if (is_art && keyin == 'c') + { + _tweak_randart(you.inv[item]); + continue; + } + + if (keyin != 'c' && keyin != 'e') + { + const short *const ptr = static_cast< short * >( field_ptr ); + mprf("Old value: %d (0x%04x)", *ptr, *ptr ); + } + else + { + const long *const ptr = static_cast< long * >( field_ptr ); + mprf("Old value: %ld (0x%08lx)", *ptr, *ptr ); + } + + mpr("New value? ", MSGCH_PROMPT); + get_input_line( specs, sizeof( specs ) ); + + if (specs[0] == '\0') + return; + + char *end; + const bool hex = (keyin == 'e'); + int new_value = strtol(specs, &end, hex ? 16 : 0); + + if (new_value == 0 && end == specs) + return; + + if (keyin != 'c' && keyin != 'e') + { + short *ptr = static_cast< short * >( field_ptr ); + *ptr = new_value; + } + else + { + long *ptr = static_cast< long * >( field_ptr ); + *ptr = new_value; + } + } +} + +// Returns whether an item of this type can be an artefact. +static bool _item_type_can_be_artefact( int type) +{ + return (type == OBJ_WEAPONS || type == OBJ_ARMOUR || type == OBJ_JEWELLERY + || type == OBJ_BOOKS); +} + +static bool _make_book_randart(item_def &book) +{ + char type; + + do + { + mpr("Make book fixed [t]heme or fixed [l]evel? ", MSGCH_PROMPT); + type = tolower(getch()); + } + while (type != 't' && type != 'l'); + + if (type == 'l') + return make_book_level_randart(book); + else + return make_book_theme_randart(book); +} + +void wizard_value_artefact() +{ + int i = prompt_invent_item( "Value of which artefact?", MT_INVLIST, -1 ); + + if (!prompt_failed(i)) + { + const item_def& item(you.inv[i]); + if (!is_artefact(item)) + mpr("That item is not an artefact!"); + else + mprf("%s", debug_art_val_str(item).c_str()); + } +} + +void wizard_create_all_artefacts() +{ + // Create all unrandarts. + for (int i = 0; i < NO_UNRANDARTS; ++i) + { + const int index = i + UNRAND_START; + const unrandart_entry* entry = get_unrand_entry(index); + + // Skip dummy entries. + if (entry->base_type == OBJ_UNASSIGNED) + continue; + + int islot = get_item_slot(); + if (islot == NON_ITEM) + break; + + item_def& item = mitm[islot]; + make_item_unrandart(item, index); + item.quantity = 1; + set_ident_flags(item, ISFLAG_IDENT_MASK); + + msg::streams(MSGCH_DIAGNOSTICS) << "Made " << item.name(DESC_NOCAP_A) + << " (" << debug_art_val_str(item) + << ")" << std::endl; + move_item_to_grid(&islot, you.pos()); + } + + // Create Horn of Geryon + int islot = get_item_slot(); + if (islot != NON_ITEM) + { + item_def& item = mitm[islot]; + item.clear(); + item.base_type = OBJ_MISCELLANY; + item.sub_type = MISC_HORN_OF_GERYON; + item.quantity = 1; + item_colour(item); + + set_ident_flags(item, ISFLAG_IDENT_MASK); + move_item_to_grid(&islot, you.pos()); + + msg::streams(MSGCH_DIAGNOSTICS) << "Made " << item.name(DESC_NOCAP_A) + << std::endl; + } +} + +void wizard_make_object_randart() +{ + int i = prompt_invent_item( "Make an artefact out of which item?", + MT_INVLIST, -1 ); + + if (prompt_failed(i)) + return; + + item_def &item(you.inv[i]); + + if (is_unrandom_artefact(item)) + { + mpr("That item is already an unrandom artefact."); + return; + } + + if (!_item_type_can_be_artefact(item.base_type)) + { + mpr("That item cannot be turned into an artefact."); + return; + } + + if (you.weapon() == &item) + you.wield_change = true; + + if (is_random_artefact(item)) + { + if (!yesno("Is already a randart; wipe and re-use?")) + { + canned_msg(MSG_OK); + return; + } + + if (item_is_equipped(item)) + unuse_artefact(item); + + item.special = 0; + item.flags &= ~ISFLAG_RANDART; + item.props.clear(); + } + + mpr("Fake item as gift from which god (ENTER to leave alone): ", + MSGCH_PROMPT); + char name[80]; + if (!cancelable_get_line(name, sizeof( name )) && name[0]) + { + god_type god = string_to_god(name, false); + if (god == GOD_NO_GOD) + mpr("No such god, leaving item origin alone."); + else + { + mprf("God gift of %s.", god_name(god, false).c_str()); + item.orig_monnum = -god; + } + } + + if (item.base_type == OBJ_BOOKS) + { + if (!_make_book_randart(item)) + { + mpr("Failed to turn book into randart."); + return; + } + } + else if (!make_item_randart(item)) + { + mpr("Failed to turn item into randart."); + return; + } + + if (Options.autoinscribe_artefacts) + add_autoinscription(item, artefact_auto_inscription(you.inv[i])); + + // If equipped, apply new randart benefits. + if (item_is_equipped(item)) + use_artefact(item); + + mpr(item.name(DESC_INVENTORY_EQUIP).c_str()); +} + +// Returns whether an item of this type can be cursed. +static bool _item_type_can_be_cursed(int type) +{ + return (type == OBJ_WEAPONS || type == OBJ_ARMOUR || type == OBJ_JEWELLERY); +} + +void wizard_uncurse_item() +{ + const int i = prompt_invent_item("(Un)curse which item?", MT_INVLIST, -1); + + if (!prompt_failed(i)) + { + item_def& item(you.inv[i]); + + if (item_cursed(item)) + do_uncurse_item(item); + else if (_item_type_can_be_cursed(item.base_type)) + do_curse_item(item); + else + mpr("That type of item cannot be cursed."); + } +} + +void wizard_identify_pack() +{ + mpr("You feel a rush of knowledge."); + for (int i = 0; i < ENDOFPACK; ++i) + { + item_def& item = you.inv[i]; + if (item.is_valid()) + { + set_ident_type(item, ID_KNOWN_TYPE); + set_ident_flags(item, ISFLAG_IDENT_MASK); + } + } + you.wield_change = true; + you.redraw_quiver = true; +} + +void wizard_unidentify_pack() +{ + mpr("You feel a rush of antiknowledge."); + for (int i = 0; i < ENDOFPACK; ++i) + { + item_def& item = you.inv[i]; + if (item.is_valid()) + { + set_ident_type(item, ID_UNKNOWN_TYPE); + unset_ident_flags(item, ISFLAG_IDENT_MASK); + } + } + you.wield_change = true; + you.redraw_quiver = true; + + // Forget things that nearby monsters are carrying, as well. + // (For use with the "give monster an item" wizard targetting + // command.) + for (int i = 0; i < MAX_MONSTERS; ++i) + { + monsters* mon = &menv[i]; + + if (mon->alive() && mons_near(mon)) + { + for (int j = 0; j < NUM_MONSTER_SLOTS; ++j) + { + if (mon->inv[j] == NON_ITEM) + continue; + + item_def &item = mitm[mon->inv[j]]; + + if (!item.is_valid()) + continue; + + set_ident_type(item, ID_UNKNOWN_TYPE); + unset_ident_flags(item, ISFLAG_IDENT_MASK); + } + } + } +} + +void wizard_list_items() +{ + bool has_shops = false; + + for (int i = 0; i < MAX_SHOPS; ++i) + if (env.shop[i].type != SHOP_UNASSIGNED) + { + has_shops = true; + break; + } + + if (has_shops) + { + mpr("Shop items:"); + + for (int i = 0; i < MAX_SHOPS; ++i) + if (env.shop[i].type != SHOP_UNASSIGNED) + { + for (stack_iterator si(coord_def(0, i+5)); si; ++si) + mpr(si->name(DESC_PLAIN, false, false, false).c_str()); + } + + mpr(EOL); + } + + mpr("Item stacks (by location and top item):"); + for (int i = 0; i < MAX_ITEMS; ++i) + { + item_def &item(mitm[i]); + if (!item.is_valid() || item.held_by_monster()) + continue; + + if (item.link != NON_ITEM) + { + mprf("(%2d,%2d): %s", item.pos.x, item.pos.y, + item.name(DESC_PLAIN, false, false, false).c_str() ); + } + } + + mpr(EOL); + mpr("Floor items (stacks only show top item):"); + + const coord_def start(1,1), end(GXM-1, GYM-1); + for (rectangle_iterator ri(start, end); ri; ++ri) + { + int item = igrd(*ri); + if (item != NON_ITEM) + { + mprf("%3d at (%2d,%2d): %s", item, ri->x, ri->y, + mitm[item].name(DESC_PLAIN, false, false, false).c_str()); + } + } +} + +//--------------------------------------------------------------- +// +// debug_item_statistics +// +//--------------------------------------------------------------- +static void _debug_acquirement_stats(FILE *ostat) +{ + if (feat_destroys_items(grd(you.pos()))) + { + mpr("You must stand on a square which doesn't destroy items " + "in order to do this."); + return; + } + + int p = get_item_slot(11); + if (p == NON_ITEM) + { + mpr("Too many items on level."); + return; + } + mitm[p].base_type = OBJ_UNASSIGNED; + + mesclr(); + mpr("[a] Weapons [b] Armours [c] Jewellery [d] Books"); + mpr("[e] Staves [f] Food [g] Miscellaneous"); + mpr("What kind of item would you like to get acquirement stats on? ", + MSGCH_PROMPT); + + object_class_type type; + const int keyin = tolower( get_ch() ); + switch ( keyin ) + { + case 'a': type = OBJ_WEAPONS; break; + case 'b': type = OBJ_ARMOUR; break; + case 'c': type = OBJ_JEWELLERY; break; + case 'd': type = OBJ_BOOKS; break; + case 'e': type = OBJ_STAVES; break; + case 'f': type = OBJ_FOOD; break; + case 'g': type = OBJ_MISCELLANY; break; + default: + canned_msg( MSG_OK ); + return; + } + + const int num_itrs = debug_prompt_for_int("How many iterations? ", true); + + if (num_itrs == 0) + { + canned_msg( MSG_OK ); + return; + } + + int last_percent = 0; + int acq_calls = 0; + int total_quant = 0; + int max_plus = -127; + int total_plus = 0; + int num_arts = 0; + + int subtype_quants[256]; + int ego_quants[SPWPN_DEBUG_RANDART]; + + memset(subtype_quants, 0, sizeof(subtype_quants)); + memset(ego_quants, 0, sizeof(ego_quants)); + + for (int i = 0; i < num_itrs; ++i) + { + if (kbhit()) + { + getch(); + mpr("Stopping early due to keyboard input."); + break; + } + + int item_index = NON_ITEM; + + if (!acquirement(type, AQ_WIZMODE, true, &item_index) + || item_index == NON_ITEM + || !mitm[item_index].is_valid()) + { + mpr("Acquirement failed, stopping early."); + break; + } + + item_def &item(mitm[item_index]); + + acq_calls++; + total_quant += item.quantity; + subtype_quants[item.sub_type] += item.quantity; + + max_plus = std::max(max_plus, item.plus + item.plus2); + total_plus += item.plus + item.plus2; + + if (is_artefact(item)) + num_arts++; + else if (type == OBJ_ARMOUR) // Exclude artefacts when counting egos. + ego_quants[get_armour_ego_type(item)]++; + + // Include artefacts for weapon brands. + if (type == OBJ_WEAPONS) + ego_quants[get_weapon_brand(item)]++; + + destroy_item(item_index, true); + + int curr_percent = acq_calls * 100 / num_itrs; + if (curr_percent > last_percent) + { + mesclr(); + mprf("%2d%% done.", curr_percent); + last_percent = curr_percent; + } + } + + if (total_quant == 0 || acq_calls == 0) + { + mpr("No items generated."); + return; + } + + fprintf(ostat, "acquirement called %d times, total quantity = %d\n\n", + acq_calls, total_quant); + + fprintf(ostat, "%5.2f%% artefacts.\n", + 100.0 * (float) num_arts / (float) acq_calls); + + if (type == OBJ_WEAPONS) + { + fprintf(ostat, "Maximum combined pluses: %d\n", max_plus); + fprintf(ostat, "Average combined pluses: %5.2f\n\n", + (float) total_plus / (float) acq_calls); + + fprintf(ostat, "Egos (including artefacts):\n"); + + const char* names[] = { + "normal", + "flaming", + "freezing", + "holy wrath", + "electrocution", + "orc slaying", + "dragon slaying", + "venom", + "protection", + "draining", + "speed", + "vorpal", + "flame", + "frost", + "vampiricism", + "pain", + "distortion", + "reaching", + "returning", + "chaos", + "confusion", + }; + + for (int i = 0; i <= SPWPN_CONFUSE; ++i) + if (ego_quants[i] > 0) + { + fprintf(ostat, "%14s: %5.2f\n", names[i], + 100.0 * (float) ego_quants[i] / (float) acq_calls); + } + + fprintf(ostat, "\n\n"); + } + else if (type == OBJ_ARMOUR) + { + fprintf(ostat, "Maximum plus: %d\n", max_plus); + fprintf(ostat, "Average plus: %5.2f\n\n", + (float) total_plus / (float) acq_calls); + + fprintf(ostat, "Egos (excluding artefacts):\n"); + + const char* names[] = { + "normal", + "running", + "fire resistance", + "cold resistance", + "poison resistance", + "see invis", + "darkness", + "strength", + "dexterity", + "intelligence", + "ponderous", + "levitation", + "magic reistance", + "protection", + "stealth", + "resistance", + "positive energy", + "archmagi", + "preservation", + "reflection" + }; + + const int non_art = acq_calls - num_arts; + for (int i = 0; i <= SPARM_REFLECTION; ++i) + { + if (ego_quants[i] > 0) + fprintf(ostat, "%17s: %5.2f\n", names[i], + 100.0 * (float) ego_quants[i] / (float) non_art); + } + fprintf(ostat, "\n\n"); + } + + item_def item; + item.quantity = 1; + item.base_type = type; + + int max_width = 0; + for (int i = 0; i < 256; ++i) + { + if (subtype_quants[i] == 0) + continue; + + item.sub_type = i; + + std::string name = item.name(DESC_DBNAME, true, true); + + max_width = std::max(max_width, (int) name.length()); + } + + char format_str[80]; + sprintf(format_str, "%%%ds: %%6.2f\n", max_width); + + for (int i = 0; i < 256; ++i) + { + if (subtype_quants[i] == 0) + continue; + + item.sub_type = i; + + std::string name = item.name(DESC_DBNAME, true, true); + + fprintf(ostat, format_str, name.c_str(), + (float) subtype_quants[i] * 100.0 / (float) total_quant); + } + fprintf(ostat, "----------------------\n"); + + mpr("Results written into 'items.stat'."); +} + +static void _debug_rap_stats(FILE *ostat) +{ + int i = prompt_invent_item( "Generate randart stats on which item?", + MT_INVLIST, -1 ); + + if (i == PROMPT_ABORT) + { + canned_msg( MSG_OK ); + return; + } + + // A copy of the item, rather than a reference to the inventory item, + // so we can fiddle with the item at will. + item_def item(you.inv[i]); + + // Start off with a non-artefact item. + item.flags &= ~ISFLAG_ARTEFACT_MASK; + item.special = 0; + item.props.clear(); + + if (!make_item_randart(item)) + { + mpr("Can't make a randart out of that type of item."); + return; + } + + // -1 = always bad, 1 = always good, 0 = depends on value + const int good_or_bad[] = { + 1, //ARTP_BRAND + 0, //ARTP_AC + 0, //ARTP_EVASION + 0, //ARTP_STRENGTH + 0, //ARTP_INTELLIGENCE + 0, //ARTP_DEXTERITY + 0, //ARTP_FIRE + 0, //ARTP_COLD + 1, //ARTP_ELECTRICITY + 1, //ARTP_POISON + 1, //ARTP_NEGATIVE_ENERGY + 1, //ARTP_MAGIC + 1, //ARTP_EYESIGHT + 1, //ARTP_INVISIBLE + 1, //ARTP_LEVITATE + 1, //ARTP_BLINK + 1, //ARTP_CAN_TELEPORT + 1, //ARTP_BERSERK + 1, //ARTP_UNUSED_1 + -1, //ARTP_NOISES + -1, //ARTP_PREVENT_SPELLCASTING + -1, //ARTP_CAUSE_TELEPORTATION + -1, //ARTP_PREVENT_TELEPORTATION + -1, //ARTP_ANGRY + -1, //ARTP_METABOLISM + -1, //ARTP_MUTAGENIC + 0, //ARTP_ACCURACY + 0, //ARTP_DAMAGE + -1, //ARTP_CURSED + 0, //ARTP_STEALTH + 0 //ARTP_MAGICAL_POWER + }; + + // No bounds checking to speed things up a bit. + int all_props[ARTP_NUM_PROPERTIES]; + int good_props[ARTP_NUM_PROPERTIES]; + int bad_props[ARTP_NUM_PROPERTIES]; + for (i = 0; i < ARTP_NUM_PROPERTIES; ++i) + { + all_props[i] = 0; + good_props[i] = 0; + bad_props[i] = 0; + } + + int max_props = 0, total_props = 0; + int max_good_props = 0, total_good_props = 0; + int max_bad_props = 0, total_bad_props = 0; + int max_balance_props = 0, total_balance_props = 0; + + int num_randarts = 0, bad_randarts = 0; + + artefact_properties_t proprt; + + for (i = 0; i < RANDART_SEED_MASK; ++i) + { + if (kbhit()) + { + getch(); + mpr("Stopping early due to keyboard input."); + break; + } + + item.special = i; + + // Generate proprt once and hand it off to randart_is_bad(), + // so that randart_is_bad() doesn't generate it a second time. + artefact_wpn_properties( item, proprt ); + if (randart_is_bad(item, proprt)) + { + bad_randarts++; + continue; + } + + num_randarts++; + proprt[ARTP_CURSED] = 0; + + int num_props = 0, num_good_props = 0, num_bad_props = 0; + for (int j = 0; j < ARTP_NUM_PROPERTIES; ++j) + { + const int val = proprt[j]; + if (val) + { + num_props++; + all_props[j]++; + switch (good_or_bad[j]) + { + case -1: + num_bad_props++; + break; + case 1: + num_good_props++; + break; + case 0: + if (val > 0) + { + good_props[j]++; + num_good_props++; + } + else + { + bad_props[j]++; + num_bad_props++; + } + } + } + } + + int balance = num_good_props - num_bad_props; + + max_props = std::max(max_props, num_props); + max_good_props = std::max(max_good_props, num_good_props); + max_bad_props = std::max(max_bad_props, num_bad_props); + max_balance_props = std::max(max_balance_props, balance); + + total_props += num_props; + total_good_props += num_good_props; + total_bad_props += num_bad_props; + total_balance_props += balance; + + if (i % 16777 == 0) + { + mesclr(); + float curr_percent = (float) i * 1000.0 + / (float) RANDART_SEED_MASK; + mprf("%4.1f%% done.", curr_percent / 10.0); + } + + } + + fprintf(ostat, "Randarts generated: %d valid, %d invalid\n\n", + num_randarts, bad_randarts); + + fprintf(ostat, "max # of props = %d, avg # = %5.2f\n", + max_props, (float) total_props / (float) num_randarts); + fprintf(ostat, "max # of good props = %d, avg # = %5.2f\n", + max_good_props, (float) total_good_props / (float) num_randarts); + fprintf(ostat, "max # of bad props = %d, avg # = %5.2f\n", + max_bad_props, (float) total_bad_props / (float) num_randarts); + fprintf(ostat, "max (good - bad) props = %d, avg # = %5.2f\n\n", + max_balance_props, + (float) total_balance_props / (float) num_randarts); + + const char* rap_names[] = { + "ARTP_BRAND", + "ARTP_AC", + "ARTP_EVASION", + "ARTP_STRENGTH", + "ARTP_INTELLIGENCE", + "ARTP_DEXTERITY", + "ARTP_FIRE", + "ARTP_COLD", + "ARTP_ELECTRICITY", + "ARTP_POISON", + "ARTP_NEGATIVE_ENERGY", + "ARTP_MAGIC", + "ARTP_EYESIGHT", + "ARTP_INVISIBLE", + "ARTP_LEVITATE", + "ARTP_BLINK", + "ARTP_BERSERK", + "ARTP_NOISES", + "ARTP_PREVENT_SPELLCASTING", + "ARTP_CAUSE_TELEPORTATION", + "ARTP_PREVENT_TELEPORTATION", + "ARTP_ANGRY", + "ARTP_METABOLISM", + "ARTP_MUTAGENIC", + "ARTP_ACCURACY", + "ARTP_DAMAGE", + "ARTP_CURSED", + "ARTP_STEALTH", + "ARTP_MAGICAL_POWER" + }; + + fprintf(ostat, " All Good Bad\n"); + fprintf(ostat, " --------------------\n"); + + for (i = 0; i < ARTP_NUM_PROPERTIES; ++i) + { + if (all_props[i] == 0) + continue; + + fprintf(ostat, "%-25s: %5.2f%% %5.2f%% %5.2f%%\n", rap_names[i], + (float) all_props[i] * 100.0 / (float) num_randarts, + (float) good_props[i] * 100.0 / (float) num_randarts, + (float) bad_props[i] * 100.0 / (float) num_randarts); + } + + fprintf(ostat, "\n-----------------------------------------\n\n"); + mpr("Results written into 'items.stat'."); +} + +void debug_item_statistics( void ) +{ + FILE *ostat = fopen("items.stat", "a"); + + if (!ostat) + { + mprf(MSGCH_ERROR, "Can't write items.stat: %s", strerror(errno)); + return; + } + + mpr("Generate stats for: [a] acquirement [b] randart properties"); + + const int keyin = tolower( get_ch() ); + switch ( keyin ) + { + case 'a': _debug_acquirement_stats(ostat); break; + case 'b': _debug_rap_stats(ostat); + default: + canned_msg( MSG_OK ); + break; + } + + fclose(ostat); +} + +void wizard_draw_card() +{ + msg::streams(MSGCH_PROMPT) << "Which card? " << std::endl; + char buf[80]; + if (cancelable_get_line_autohist(buf, sizeof buf)) + { + mpr("Unknown card."); + return; + } + + std::string wanted = buf; + lowercase(wanted); + + bool found_card = false; + for ( int i = 0; i < NUM_CARDS; ++i ) + { + const card_type c = static_cast(i); + std::string card = card_name(c); + lowercase(card); + if ( card.find(wanted) != std::string::npos ) + { + card_effect(c, DECK_RARITY_LEGENDARY); + found_card = true; + break; + } + } + if (!found_card) + mpr("Unknown card."); +} +#endif + + -- cgit v1.2.3-54-g00ecf