Fix a bug in wizard-spawning monsters (max was used instead of min.)
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8852 c06c8d41-db1a-0410-9941-cceddc491573
DWWOM6V2Z4RQVT6AKW6OYLSFOUE4W5PTP2SH4AAZE2E4EIH4RLUAC
GOQ2HHZ5YVL4PENYF4MYBVRRVSUFJP2EHV4DLY6ODSH75GHV5VOQC
P6CQZRWDS3QNWW7W5LJYH4KU6YRSWZT5M4X3KLLTJY23CRBA7RXAC
OMAUFQNBWGX4FDABHQCVPGDYRVKMDASGQJVRH7AOPPEMHAP2LQSQC
6XFZFU6LCT4LF3S7DXF7TBZJ2FIWT5GZLJDKDC7WMY6AQ63IVTWAC
O32JR5WZFNW66UKZ44PW7VMLA7UGOECJOL4FFBTCIDUYXCE7WP4AC
RKTQ6YB75PHPN6PNVYXRW4UMVYA62GZVQVV7LPJSQYKMUOJVRFQQC
MIC2SDBOCS63ZDNBQ2VRZMTFOYJL5DUQVR67I7Z3KBJGDBNZJIGAC
2UBGHTABAAOWTCULH7HWGSVXVCHJR3ZBTD3Q2YRULMK2J4DHMQ3AC
JHDGOKFOJXQQ46LHUWKS2T2Z4EHJRFFDQ4BY6KETX6IGFGKV6YYQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
USIGLWEX5AA7IJ2U6ZMKFMMVZMRAKC3TKXAPBOF457DP4ND6ZT5AC
O7S3ILRELHICJXXTDGMF7KPPZWYHPYCNDPV2I77FZXXH4I454B4QC
2WWSPLCXLSMBGTXUC33EQ5YBOA5IBFSMJSTZ2TU6HZIMZZWZJWGAC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
CCRQESB4ADT4WA7FGLNZZXAJ6G5QMCTYCZIWORBN45P6ZPILC34AC
46MRRHVYJ3BS74R2BEVUWEWJCI4FCRBSLZ3NWMQCE6FUCNE5P73QC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
FMBJCM5LJKCG326YRJGOOJU6QNWONXAHK2AB4CP4SAOHKJ5CORXQC
X5OHFTHRXTI5KHFIYFJ6DB3W5MY3JUJKNTL4HF37MKABYNCOBOZAC
6CWMT6I76TMTHT7BVOVZJ7ATDMZ3VBKKICIRRZBOSGLHJMDS2DWQC
IGBJ3ZY5G73GTHPRNWKC6XMQDINRGCTIXKBHTEZ7JLUJS6H4JRBAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
4FQAKUKUO6PCAZ3N4HUR5XL6E4VA5UQUZ3AEDGRBLVY7W2LMWI7QC
Y4NA3JSN63RLATF4NNBPSR5CWF5Z7UEMWCGVX4B6NOAR47CGM4GQC
4QRLZDW4KBFG34B3MCG4375NHFR3WKWSLWQKRMQ3OE5R26WCZBBQC
FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
WJS4U5UXQH6ENQLZRWLID56EITQT2B3G72NVSS6RFCYZVWOK6J2QC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
IXLNOTBJGHKESBCTME6QAR6XVWFNCHYGMS62V62ZJEA7VLQHXO2QC
6DO3DRQ3FSJWBJD2ZW47BTNHCSBSOKCUV5HL34XO3CWPXP4QC6CAC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
7GJR755MBM55KIOP3DGSZIIAEQ5E2PRBHLEXZOU2ZMXHHZ5JI3GQC
KFZYPFHHOWRUZEK2PW26EI73Z6I6DLHW2YEJV2CB5XBWFRRNBFXQC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
QKV56RZTWOX64VLWW52R2DEUM3HGGZNLRAJ2ZV2BHW5K422OPNJQC
LJK4ZQATLSB4MKZG3ARZX5V6RFGTN3NLCN6GTCUGJQKU26SOXMUAC
3CY6KJWHQUZFZGO2C7VVCO32RRHUIMQQQJAE2MUXFF45F7ECRLJQC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
7VCVH6XKT4L4PSCBF6XRYV3WQQDVGDMA73RHPV6IOWMQ2S7B5XAQC
3FBKOX4Y5QYPMBOCSAMHNZXCY7Z75YDQDL4EJZHZIGDXL7RMZ7TAC
HQ5FYPDFIQNNDMKDSGWAAXYIVIRK42B4OBA2LESP2OA5SPKSTLVQC
AUXVWXWIFSTWFA6VZXN2FMG7FQEKRZVV6MD32VQQ7J2RKCXHAVGAC
DH3D44HGNRXTSZLL5HTHKOPKCO4VZQZVBEMFOAPRJGQMLGN2BFQAC
ZHFUXYUHS6V47WK2NRH7OU6RX77NRKTXOZC3MND2GG7PEEWSGFTAC
L5CVPV5IUBSO4EE3WK4O6SQGIMIEPSMQONFBWEVGJBR2HATLPZIAC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
FUEEIUKGHHFPIRZCN3N753GONWAZTWQ2ZWR53IBJAAZ6FZUNGOMAC
5IWO6LXJBETPTZA7F67UJURUU3FWGFBHRZILC7KQ2KJQSMTIS66AC
ETV7O3ZWPY5D4R2AOPI6IRAWUTZR55LNYBBSSXLIN6NLZSCCBQBQC
EJ4GIPFSSQCQASUMRF4CR2WPUQOTEHFRGLOYEZ7BH6YEMIR6DN4QC
5XNQ3SSNBFXFNWA6DPM74W6FH65NX665P3DMH6YCWVFOPZTJSYCQC
TLA5UN6LZPXGKERI27EFY4HKIIU3VU5Y7ZU54WXL6ANBUV2VOTMQC
NNMFGXB5BJXGHTLNP4IL3IZ6TRQWZGANE4CXRNSD2EGY47QW3I6QC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
VTJOYDSSNQZOK23N65C64NUGDTGPL6QZWGCALRQHQDQXAPYBRKMAC
4VDKJOSBXI4KTWFJT4KWRF6EAQYQEXHJORP3L7RTDJXAYTKQELNAC
WP5VP57D5BWKDAS7AA224OV2RX4O4BPTI2BLY7TS3T2O2PLUGXCQC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
U6OTXM3JN7SGPVIGQ5F6NR2I7J5V7KOWFQ7AVNNRQQDNLBEDMYFQC
SZBMBNW34N2SM7Y6QBKBSA7OMLEMLFGCE4NSMHCBH6ORU2MYY2MQC
L254F6ZIU2HWGLFFGPIORTN4C3TDQ3E5JZ7Z7GQA5AEDIKL6PKDAC
KQNIGKATHT4YSPJFPJGIGPD6VNR5B753SE2JN2LCXZZJNHCGY3DQC
HCVH2CWL32UD66O6Z7ZYDUASWN3RF5TW6FSWURGMD7MELKB772FAC
WXEZCJ2BPVJU2AL4QZR4IY34UCPHF6QBXKQAT4MJUKY4VEULGMXQC
NUYGFMQOZK32XUFTDPGTZ25L7JGOU532S2D4MELYJB5GQL7KNGOAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
GMSGNBZKUJ3DDTOGLQJ3VUBUYIECAW6PDDHYFPGSOHSG2TUUKJRAC
F4WAQJD7KLOXHZOTOT6WG26PVIDHYNVS3AV6ZNXGAS7PDR4HBWQAC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
ITSYPZJ5HOJO3YTPUGAIZSV373744ZHJO7ANDLUGFBV5XMZLLABAC
NXIVXEHVXS22UDSQL4KZQ4VHK3XTW7DAGA5LLL3EXY5MHPIUXL7AC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
5BYWI6JJMVTQLCOMPHQNSFC2HW5LYGYFBHBIOU7D4T4B2AIUZV4AC
RBAGQ2PB7V5YAM5KSHSZR2E3MLKDSRVM5XYGI2TIXP5QMVBOQHDQC
GZMPIDNMBXZ4B2ZWKREHBPAVN53J6WRVY5W5KY52KEBHKU6IW4IQC
AMFTO4UE74UYQBU3R2EYUU6BJ7SC4O4NOAFICRTLMT3MIFRQ6AKAC
MC5GWSF6I7TGB422CBRCP6IPX5SV36OX4LAXEE33C65GKCDI64IQC
B7MSPF6X2RLGWN4M6ZZF3WSOPKGYPTTD7LIJVST7DXN27DG6JHNAC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
T2AT2ZAM5WK7JNFXBQCVXBEX4AMJ6ELQMOPQM4JZUBBYOVLCMO4AC
Q34XE6SMDPGFALBB7DSQWDVIPPGXYAH6I3FDTB56S4RRHOBKJREAC
S7Y7E2KDAFMTLDIXUTR673SYL5N35VXYGLRU67L42WHVYG5SEPBQC
EHX5GT72I5BJTHAR2W57UQQVBOMAPBJGZXZ35GNUPBBNDPS7S7WAC
ID2OZJTHFXL74RVUCS3JCMDQEUHAXCQFZU7235VU6IEVAAUWD2FAC
// last updated 12 Jun 2008 {jpeg}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
void wizard_value_randart();
void wizard_uncurse_item();
void wizard_create_all_artefacts();
void wizard_heal(bool super_heal);
void wizard_set_hunger_state();
void wizard_spawn_control();
void wizard_create_portal();
void wizard_identify_pack();
void wizard_unidentify_pack();
void wizard_create_feature_number();
void wizard_create_feature_name();
void wizard_list_branches();
void wizard_map_level();
void wizard_gain_piety();
void wizard_list_items();
}
void wizard_value_randart()
{
int i = prompt_invent_item( "Value of which randart?", MT_INVLIST, -1 );
if (!prompt_failed(i))
{
if (!is_random_artefact( you.inv[i] ))
mpr("That item is not an artefact!");
else
mprf("randart val: %d", randart_value(you.inv[i]));
}
}
void wizard_create_all_artefacts()
{
// Create all unrandarts. Start at 1; the unrandart at 0 is a dummy.
for (int i = 1; i < NO_UNRANDARTS; i++)
{
int islot = get_item_slot();
if (islot == NON_ITEM)
break;
item_def& item = mitm[islot];
make_item_unrandart(item, i);
item.quantity = 1;
set_ident_flags(item, ISFLAG_IDENT_MASK);
msg::streams(MSGCH_DIAGNOSTICS) << "Made " << item.name(DESC_NOCAP_A)
<< std::endl;
move_item_to_grid(&islot, you.pos());
}
// Create all fixed artefacts.
for (int i = SPWPN_START_FIXEDARTS; i < SPWPN_START_NOGEN_FIXEDARTS; i++)
{
int islot = get_item_slot();
if (islot == NON_ITEM)
break;
item_def& item = mitm[islot];
if (make_item_fixed_artefact(item, false, i))
{
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;
}
}
// 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;
}
}
// 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_heal(bool super_heal)
{
if (super_heal)
{
// Clear more stuff and give a HP boost.
you.magic_contamination = 0;
you.duration[DUR_LIQUID_FLAMES] = 0;
if (you.duration[DUR_MESMERISED])
{
you.duration[DUR_MESMERISED] = 0;
you.mesmerised_by.clear();
}
// If we're repeating then do the HP increase all at once.
int amount = 10;
if (crawl_state.cmd_repeat_goal > 0)
{
amount *= crawl_state.cmd_repeat_goal;
crawl_state.cancel_cmd_repeat();
}
inc_hp(amount, true);
}
// Clear most status ailments.
you.rotting = 0;
you.disease = 0;
you.duration[DUR_CONF] = 0;
you.duration[DUR_POISONING] = 0;
set_hp(abs(you.hp_max), false);
set_mp(you.max_magic_points, false);
set_hunger(10999, true);
you.redraw_hit_points = true;
}
void wizard_set_hunger_state()
{
mpr( "Set hunger state to s(T)arving, (N)ear starving, "
"(H)ungry, (S)atiated, (F)ull or (E)ngorged?", MSGCH_PROMPT );
const int c = tolower(getch());
// Values taken from food.cc.
switch (c)
{
case 't': you.hunger = 500; break;
case 'n': you.hunger = 1200; break;
case 'h': you.hunger = 2400; break;
case 's': you.hunger = 5000; break;
case 'f': you.hunger = 8000; break;
case 'e': you.hunger = 12000; break;
default: canned_msg(MSG_OK); break;
}
food_change();
if (you.species == SP_GHOUL && you.hunger_state >= HS_SATIATED)
mpr("Ghouls can never be full or above!");
}
void wizard_spawn_control()
{
mpr("(c)hange spawn rate or (s)pawn monsters? ", MSGCH_PROMPT);
const int c = tolower(getch());
char specs[256];
bool done = false;
if (c == 'c')
{
mprf(MSGCH_PROMPT, "Set monster spawn rate to what? (now %d) ",
env.spawn_random_rate);
if (!cancelable_get_line(specs, sizeof(specs)))
{
const int rate = atoi(specs);
if (rate)
{
env.spawn_random_rate = rate;
done = true;
}
}
}
else if (c == 's')
{
// 50 spots are reserved for non-wandering monsters.
int max_spawn = MAX_MONSTERS - 50;
for (int i = 0; i < MAX_MONSTERS; i++)
if (menv[i].alive())
max_spawn--;
if (max_spawn <= 0)
{
mpr("Level already filled with monsters, get rid of some "
"of them first.", MSGCH_PROMPT);
return;
}
mprf(MSGCH_PROMPT, "Spawn how many random monsters (max %d)? ",
max_spawn);
if (!cancelable_get_line(specs, sizeof(specs)))
{
const int num = std::min(atoi(specs), max_spawn);
if (num > 0)
{
int curr_rate = env.spawn_random_rate;
// Each call to spawn_random_monsters() will spawn one with
// the rate at 5 or less.
env.spawn_random_rate = 5;
for (int i = 0; i < num; i++)
spawn_random_monsters();
env.spawn_random_rate = curr_rate;
done = true;
}
}
}
if (!done)
canned_msg(MSG_OK);
}
void wizard_create_portal()
{
mpr("Destination for portal (defaults to 'bazaar')? ", MSGCH_PROMPT);
char specs[256];
if (cancelable_get_line(specs, sizeof(specs)))
{
canned_msg( MSG_OK );
return;
}
std::string dst = specs;
dst = trim_string(dst);
dst = replace_all(dst, " ", "_");
if (dst.empty())
dst = "bazaar";
if (!find_map_by_name(dst) && !random_map_for_tag(dst))
{
mprf("No map named '%s' or tagged '%s'.", dst.c_str(), dst.c_str());
}
else
{
map_wiz_props_marker *marker = new map_wiz_props_marker(you.pos());
marker->set_property("dst", dst);
marker->set_property("desc", "wizard portal, dest = " + dst);
env.markers.add(marker);
dungeon_terrain_changed(you.pos(), DNGN_ENTER_PORTAL_VAULT, false);
}
}
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 (is_valid_item(item))
{
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 (is_valid_item(item))
{
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 (!is_valid_item(item))
continue;
set_ident_type(item, ID_UNKNOWN_TYPE);
unset_ident_flags(item, ISFLAG_IDENT_MASK);
}
}
}
}
void wizard_create_feature_number()
{
char specs[256];
int feat_num;
mpr("Create which feature (by number)? ", MSGCH_PROMPT);
if (!cancelable_get_line(specs, sizeof(specs))
&& (feat_num = atoi(specs)))
{
dungeon_feature_type feat = static_cast<dungeon_feature_type>(feat_num);
dungeon_terrain_changed(you.pos(), feat, false);
#ifdef USE_TILE
env.tile_flv(you.pos()).special = 0;
#endif
}
else
canned_msg(MSG_OK);
void wizard_create_feature_name()
{
char specs[256];
mpr("Create which feature (by name)? ", MSGCH_PROMPT);
get_input_line(specs, sizeof specs);
if (!cancelable_get_line(specs, sizeof(specs)) && specs[0] != 0)
{
// Accept both "shallow_water" and "Shallow water"
std::string name = lowercase_string(specs);
name = replace_all(name, " ", "_");
dungeon_feature_type feat = dungeon_feature_by_name(name);
if (feat == DNGN_UNSEEN) // no exact match
{
std::vector<std::string> matches = dungeon_feature_matches(name);
if (matches.empty())
{
mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
name.c_str());
return;
}
// Only one possible match, use that.
if (matches.size() == 1)
{
name = matches[0];
feat = dungeon_feature_by_name(name);
}
// Multiple matches, list them to wizard
else
{
std::string prefix = "No exact match for feature '" +
name + "', possible matches are: ";
// Use mpr_comma_separated_list() because the list
// might be *LONG*.
mpr_comma_separated_list(prefix, matches, " and ", ", ",
MSGCH_DIAGNOSTICS);
return;
}
}
mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
you.pos().x, you.pos().y, name.c_str(), feat);
dungeon_terrain_changed(you.pos(), feat, false);
#ifdef USE_TILE
env.tile_flv(you.pos()).special = 0;
void wizard_list_branches()
{
for (int i = 0; i < NUM_BRANCHES; i++)
{
if (branches[i].startdepth != - 1)
{
mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) is on level %d of %s",
i, branches[i].longname, branches[i].startdepth,
branches[branches[i].parent_branch].abbrevname);
}
else if (i == BRANCH_SWAMP || i == BRANCH_SHOALS)
{
mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) was not generated "
"this game", i, branches[i].longname);
}
}
}
void wizard_map_level()
{
if (testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
|| testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE))
{
if (!yesno("Force level to be mappable?", true, 'n'))
{
canned_msg( MSG_OK );
return;
}
unset_level_flags(LFLAG_NOT_MAPPABLE | LFLAG_NO_MAGIC_MAP);
unset_branch_flags(BFLAG_NOT_MAPPABLE | BFLAG_NO_MAGIC_MAP);
}
magic_mapping(1000, 100, true, true);
}
void wizard_gain_piety()
{
if (you.religion == GOD_NO_GOD)
{
mpr("You are not religious!");
return;
}
else if (you.religion == GOD_XOM) // increase amusement instead
{
xom_is_stimulated(50, XM_NORMAL, true);
return;
}
const int old_piety = you.piety;
const int old_penance = you.penance[you.religion];
if (old_piety >= MAX_PIETY && !old_penance)
{
mprf("Your piety (%d) is already %s maximum.",
old_piety, old_piety == MAX_PIETY ? "at" : "above");
}
// Even at maximum, you can still gain gifts.
// Try at least once for maximum, or repeat until something
// happens. Rarely, this might result in several gifts during the
// same round!
do
{
gain_piety(50);
}
while (old_piety < MAX_PIETY && old_piety == you.piety
&& old_penance == you.penance[you.religion]);
if (old_penance)
{
mprf("Congratulations, your penance was decreased from %d to %d!",
old_penance, you.penance[you.religion]);
}
else if (you.piety > old_piety)
{
mprf("Congratulations, your piety went from %d to %d!",
old_piety, you.piety);
}
}
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 (!is_valid_item(item) || held_by_monster(item))
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):");
for (int i = 1; i < GXM; i++)
for (int j = 1; j < GYM; j++)
{
int item = igrd[i][j];
if (item != NON_ITEM)
{
mprf("%3d at (%2d,%2d): %s", item, i, j,
mitm[item].name(DESC_PLAIN, false, false, false).c_str());
}
}
}
#endif
// 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);
}
case CONTROL('G'):
save_ghost(true);
break;
case CONTROL('D'): wizard_edit_durations(); break;
case CONTROL('F'): debug_fight_statistics(false, true); break;
case CONTROL('G'): save_ghost(true); break;
case CONTROL('H'): wizard_set_hunger_state(); break;
case CONTROL('I'): debug_item_statistics(); break;
case CONTROL('X'): wizard_set_xl(); break;
case 'O': debug_test_explore(); break;
case 'S': wizard_set_skill_level(); break;
case 'A': wizard_set_all_skills(); break;
case 'a': acquirement(OBJ_RANDOM, AQ_WIZMODE); break;
case 'v': wizard_value_randart(); break;
case '+': wizard_make_object_randart(); break;
case '|': wizard_create_all_artefacts(); break;
case 'C': wizard_uncurse_item(); break;
case 'g': wizard_exercise_skill(); break;
case 'G': wizard_dismiss_all_monsters(); break;
case 'c': wizard_draw_card(); break;
case 'H': wizard_heal(true); break;
case 'h': wizard_heal(false); break;
case 'b': blink(1000, true, true); break;
case '~': wizard_interlevel_travel(); break;
case '"': debug_list_monsters(); break;
case 't': wizard_tweak_object(); break;
case 'T': debug_make_trap(); break;
case '\\': debug_make_shop(); break;
case 'f': debug_fight_statistics(false); break;
case 'F': debug_fight_statistics(true); break;
case 'm': wizard_create_spec_monster(); break;
case 'M': wizard_create_spec_monster_name(); break;
case 'R': wizard_spawn_control(); break;
case 'r': wizard_change_species(); break;
case '>': wizard_place_stairs(true); break;
case '<': wizard_place_stairs(false); break;
case 'P': wizard_create_portal(); break;
case 'L': debug_place_map(); break;
case 'i': wizard_identify_pack(); break;
case 'I': wizard_unidentify_pack(); break;
case 'z': wizard_cast_spec_spell(); break;
case 'Z': wizard_cast_spec_spell_name(); break;
case '(': wizard_create_feature_number(); break;
case ')': wizard_create_feature_name(); break;
case '[': demonspawn(); break;
case ':': wizard_list_branches(); break;
case '{': wizard_map_level(); break;
case '@': wizard_set_stats(); break;
case '^': wizard_gain_piety(); break;
case '_': wizard_get_religion(); break;
case '\'': wizard_list_items(); break;
case 'd': case 'D': wizard_level_travel(true); break;
case 'u': case 'U': wizard_level_travel(false); break;
case '%': case 'o': wizard_create_spec_object(); break;
break;
case 'a':
acquirement( OBJ_RANDOM, AQ_WIZMODE );
break;
case 'v':
{
// This command isn't very exciting... feel free to replace.
int i = prompt_invent_item( "Value of which item?", MT_INVLIST, -1 );
if (prompt_failed(i))
break;
else if (!is_random_artefact( you.inv[i] ))
mpr("That item is not an artefact!");
else
mprf("randart val: %d", randart_value(you.inv[i]));
break;
}
case '+':
wizard_make_object_randart();
break;
case '|':
// Create all unrandarts.
for (tmp = 1; tmp < NO_UNRANDARTS; tmp++)
{
int islot = get_item_slot();
if (islot == NON_ITEM)
break;
make_item_unrandart( mitm[islot], tmp );
mitm[ islot ].quantity = 1;
set_ident_flags( mitm[ islot ], ISFLAG_IDENT_MASK );
msg::streams(MSGCH_DIAGNOSTICS) << "Made "
<< mitm[islot].name(DESC_NOCAP_A)
<< std::endl;
move_item_to_grid( &islot, you.pos() );
}
// Create all fixed artefacts.
for (tmp = SPWPN_START_FIXEDARTS;
tmp < SPWPN_START_NOGEN_FIXEDARTS; tmp++)
{
int islot = get_item_slot();
if (islot == NON_ITEM)
break;
if (make_item_fixed_artefact( mitm[ islot ], false, tmp ))
{
mitm[ islot ].quantity = 1;
item_colour( mitm[ islot ] );
set_ident_flags( mitm[ islot ], ISFLAG_IDENT_MASK );
move_item_to_grid( &islot, you.pos() );
msg::streams(MSGCH_DIAGNOSTICS) <<
"Made " << mitm[islot].name(DESC_NOCAP_A) << std::endl;
}
}
// Create Horn of Geryon
{
int islot = get_item_slot();
if (islot == NON_ITEM)
break;
mitm[islot].base_type = OBJ_MISCELLANY;
mitm[islot].sub_type = MISC_HORN_OF_GERYON;
mitm[islot].plus = 0;
mitm[islot].plus2 = 0;
mitm[islot].special = 0;
mitm[islot].flags = 0;
mitm[islot].quantity = 1;
item_colour(mitm[islot]);
set_ident_flags( mitm[ islot ], ISFLAG_IDENT_MASK );
move_item_to_grid( &islot, you.pos() );
msg::streams(MSGCH_DIAGNOSTICS) << "Made "
<< mitm[islot].name(DESC_NOCAP_A)
<< std::endl;
}
break;
case 'C':
{
// This command isn't very exciting but it's useful for debugging.
int i = prompt_invent_item( "(Un)curse which item?", MT_INVLIST, -1 );
if (prompt_failed(i))
break;
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.");
break;
case 'g':
wizard_exercise_skill();
break;
case 'G':
wizard_dismiss_all_monsters();
break;
case 'c':
wizard_draw_card();
break;
case 'H': // super-heal
you.magic_contamination = 0;
you.duration[DUR_LIQUID_FLAMES] = 0;
if (you.duration[DUR_MESMERISED])
{
you.duration[DUR_MESMERISED] = 0;
you.mesmerised_by.clear();
}
// If we're repeating &H then do the HP increase all at once.
tmp = 10;
if (crawl_state.cmd_repeat_goal > 0)
{
tmp *= crawl_state.cmd_repeat_goal;
crawl_state.cancel_cmd_repeat();
}
inc_hp( tmp, true );
// intentional fall-through
case 'h':
you.rotting = 0;
you.disease = 0;
you.duration[DUR_CONF] = 0;
you.duration[DUR_POISONING] = 0;
set_hp( abs(you.hp_max), false );
set_mp( you.max_magic_points, false);
set_hunger( 10999, true );
you.redraw_hit_points = true;
break;
case CONTROL('H'):
mpr( "Set hunger state to s(T)arving, (N)ear starving, (H)ungry, (S)atiated, (F)ull or (E)ngorged?", MSGCH_PROMPT );
tmp = tolower(getch());
// Values taken from food.cc.
switch (tmp)
{
case 't':
you.hunger = 500;
break;
case 'n':
you.hunger = 1200;
break;
case 'h':
you.hunger = 2400;
break;
case 's':
you.hunger = 5000;
break;
case 'f':
you.hunger = 8000;
break;
case 'e':
you.hunger = 12000;
break;
default:
canned_msg( MSG_OK );
break;
}
food_change();
if (you.species == SP_GHOUL && you.hunger_state >= HS_SATIATED)
mpr("Ghouls can never be full or above!");
break;
case 'b':
// wizards can always blink, with no restrictions or
// magical contamination.
blink(1000, true, true);
break;
case '~':
wizard_interlevel_travel();
break;
case '"':
debug_list_monsters();
break;
case 'd':
case 'D':
wizard_level_travel(true);
break;
case 'u':
case 'U':
wizard_level_travel(false);
break;
case '%':
case 'o':
wizard_create_spec_object();
break;
case 't':
wizard_tweak_object();
break;
case 'T':
debug_make_trap();
break;
case '\\':
debug_make_shop();
break;
case CONTROL('F'):
debug_fight_statistics(false, true);
break;
case 'f':
debug_fight_statistics(false);
break;
case 'F':
debug_fight_statistics(true);
case 'M':
wizard_create_spec_monster_name();
case '=':
mprf( "Cost level: %d Skill points: %d Next cost level: %d",
you.skill_cost_level, you.total_skill_points,
skill_cost_needed( you.skill_cost_level + 1 ) );
case 'R':
mpr( "(c)hange spawn rate or (s)pawn monsters? ", MSGCH_PROMPT );
tmp = tolower(getch());
if (tmp != 'c' && tmp != 's')
{
canned_msg( MSG_OK );
break;
}
if (tmp == 'c')
{
sprintf(specs, "Set monster spawn rate to what? (now %d) ",
env.spawn_random_rate);
mpr(specs, MSGCH_PROMPT );
if (cancelable_get_line( specs, sizeof( specs ) )
|| strlen(specs) == 0)
{
canned_msg( MSG_OK );
break;
}
{
// 50 spots are reserved for non-wandering monsters.
int max_spawn = MAX_MONSTERS - 50;
for (int i = 0; i < MAX_MONSTERS; i++)
{
if (menv[i].alive())
max_spawn--;
}
if (max_spawn <= 0)
{
mpr("Level already filled with monsters, get rid of some "
"of them first.", MSGCH_PROMPT);
return;
}
sprintf(specs, "Spawn how many random monsters (max %d)? ",
max_spawn);
mpr(specs, MSGCH_PROMPT );
if (cancelable_get_line( specs, sizeof( specs ) )
|| strlen(specs) == 0)
{
canned_msg( MSG_OK );
break;
}
int num = atoi(specs);
if (num <= 0)
{
canned_msg( MSG_OK );
break;
}
num = std::max(num, max_spawn);
int curr_rate = env.spawn_random_rate;
// Each call to spawn_random_monsters() will spawn one with
// the rate at 5 or less.
env.spawn_random_rate = 5;
for (int i = 0; i < num; i++)
spawn_random_monsters();
env.spawn_random_rate = curr_rate;
}
break;
case 'r':
wizard_change_species();
break;
case '>':
wizard_place_stairs(true);
break;
case '<':
wizard_place_stairs(false);
xom_acts(coinflip(), random_range(0, MAX_PIETY - 100));
break;
case 'P':
{
mpr( "Destination for portal (defaults to 'bazaar')? ", MSGCH_PROMPT );
if (cancelable_get_line( specs, sizeof( specs ) ))
{
canned_msg( MSG_OK );
break;
}
std::string dst = specs;
dst = trim_string(dst);
dst = replace_all(dst, " ", "_");
if (dst.empty())
dst = "bazaar";
if (!find_map_by_name(dst) && !random_map_for_tag(dst))
{
mprf("No map named '%s' or tagged '%s'.",
dst.c_str(), dst.c_str());
break;
}
map_wiz_props_marker *marker = new map_wiz_props_marker(you.pos());
marker->set_property("dst", dst);
marker->set_property("desc", "wizard portal, dest = " + dst);
env.markers.add(marker);
dungeon_terrain_changed(you.pos(), DNGN_ENTER_PORTAL_VAULT, false);
break;
case 'L':
debug_place_map();
break;
case 'i':
mpr( "You feel a rush of knowledge." );
for (int i = 0; i < ENDOFPACK; i++)
{
if (is_valid_item( you.inv[i] ))
{
set_ident_type( you.inv[i], ID_KNOWN_TYPE );
set_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
}
}
you.wield_change = true;
you.redraw_quiver = true;
case 'I':
mpr( "You feel a rush of antiknowledge." );
for (int i = 0; i < ENDOFPACK; i++)
{
if (is_valid_item( you.inv[i] ))
{
set_ident_type( you.inv[i], ID_UNKNOWN_TYPE );
unset_ident_flags( you.inv[i], ISFLAG_IDENT_MASK );
}
}
you.wield_change = true;
you.redraw_quiver = true;
monsters* mon = &menv[i];
if (!invalid_monster(mon) && 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 (!is_valid_item(item))
continue;
set_ident_type( item, ID_UNKNOWN_TYPE );
unset_ident_flags( item, ISFLAG_IDENT_MASK );
}
}
formatted_mpr(formatted_string::parse_string(
"Not a <magenta>Wizard</magenta> Command."));
break;
case CONTROL('I'):
debug_item_statistics();
break;
case 'X':
if (you.religion == GOD_XOM)
xom_acts(abs(you.piety - 100));
else
xom_acts(coinflip(), random_range(0, MAX_PIETY - 100));
break;
case 'z':
wizard_cast_spec_spell(); // Cast spell by number.
break;
case 'Z':
wizard_cast_spec_spell_name(); // Cast spell by name.
break;
case '(':
mpr( "Create which feature (by number)? ", MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
if (specs[0] != '\0')
if (const int feat_num = atoi(specs))
{
dungeon_feature_type feat =
static_cast<dungeon_feature_type>( feat_num );
dungeon_terrain_changed(you.pos(), feat, false);
#ifdef USE_TILE
env.tile_flv[you.pos().x][you.pos().y].special = 0;
#endif
}
case ')':
mpr("Create which feature (by name)? ", MSGCH_PROMPT);
get_input_line(specs, sizeof specs);
if (*specs)
{
// Accept both "shallow_water" and "Shallow water"
std::string name = lowercase_string(specs);
name = replace_all(name, " ", "_");
dungeon_feature_type feat = dungeon_feature_by_name(name);
if (feat == DNGN_UNSEEN)
{
std::vector<std::string> matches =
dungeon_feature_matches(name);
if (matches.empty())
{
mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
name.c_str());
return;
}
// Only one possible match, use that.
if (matches.size() == 1)
{
name = matches[0];
feat = dungeon_feature_by_name(name);
}
// Multiple matches, list them to wizard
else
{
std::string prefix = "No exact match for feature '" +
name + "', possible matches are: ";
// Use mpr_comma_separated_list() because the list
// might be *LONG*.
mpr_comma_separated_list(prefix, matches, " and ", ", ",
MSGCH_DIAGNOSTICS);
return;
}
}
mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
you.pos().x, you.pos().y, name.c_str(), feat);
dungeon_terrain_changed(you.pos(), feat, false);
#ifdef USE_TILE
env.tile_flv[you.pos().x][you.pos().y].special = 0;
#endif
}
break;
case ']':
if (!wizard_add_mutation())
mpr( "Failure to give mutation." );
break;
case '[':
demonspawn();
break;
case ':':
for (int i = 0; i < NUM_BRANCHES; i++)
{
if (branches[i].startdepth != - 1)
{
mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) is on level %d of %s",
i, branches[i].longname, branches[i].startdepth,
branches[branches[i].parent_branch].abbrevname);
}
else if (i == BRANCH_SWAMP || i == BRANCH_SHOALS)
{
mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) was not generated "
"this game", i, branches[i].longname);
}
}
break;
case '{':
if (testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
|| testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE))
{
if (!yesno("Force level to be mappable?", true, 'n'))
{
canned_msg( MSG_OK );
return;
}
unset_level_flags(LFLAG_NOT_MAPPABLE | LFLAG_NO_MAGIC_MAP);
unset_branch_flags(BFLAG_NOT_MAPPABLE | BFLAG_NO_MAGIC_MAP);
}
magic_mapping(1000, 100, true, true);
break;
case '@':
wizard_set_stats();
break;
case CONTROL('D'):
wizard_edit_durations();
break;
case '^':
{
if (you.religion == GOD_NO_GOD)
{
mpr("You are not religious!");
break;
}
else if (you.religion == GOD_XOM) // increase amusement instead
{
xom_is_stimulated(50, XM_NORMAL, true);
break;
}
const int old_piety = you.piety;
const int old_penance = you.penance[you.religion];
if (old_piety >= MAX_PIETY && !old_penance)
{
mprf("Your piety (%d) is already %s maximum.",
old_piety, old_piety == MAX_PIETY ? "at" : "above");
}
// Even at maximum, you can still gain gifts.
// Try at least once for maximum, or repeat until something
// happens. Rarely, this might result in several gifts during the
// same round!
do
{
gain_piety(50);
}
while (old_piety < MAX_PIETY && old_piety == you.piety
&& old_penance == you.penance[you.religion]);
if (old_penance)
{
mprf("Congratulations, your penance was decreased from %d to %d!",
old_penance, you.penance[you.religion]);
}
else if (you.piety > old_piety)
{
mprf("Congratulations, your piety went from %d to %d!",
old_piety, you.piety);
}
}
break;
case '=':
mprf( "Cost level: %d Skill points: %d Next cost level: %d",
you.skill_cost_level, you.total_skill_points,
skill_cost_needed( you.skill_cost_level + 1 ) );
break;
case '_':
wizard_get_religion();
break;
case '\'':
{
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)
{
int objl = igrd[0][i + 5];
while (objl != NON_ITEM)
{
item_def &item(mitm[objl]);
std::string name = item.name(DESC_PLAIN, false,
false, false);
mpr(name.c_str());
objl = item.link;
}
}
mpr(EOL);
}
mpr("Item stacks (by location and top item):");
for (int i = 0; i < MAX_ITEMS; i++)
{
item_def &item(mitm[i]);
if (!is_valid_item(item) || held_by_monster(item))
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):");
for (int i = 1; i < GXM; i++)
for (int j = 1; j < GYM; j++)
{
int item = igrd[i][j];
if (item != NON_ITEM)
{
mprf("%3d at (%2d,%2d): %s",
item, i, j,
mitm[item].name(DESC_PLAIN, false, false,
false).c_str() );
}
}
break;
default:
if (!silent_fail)
formatted_mpr(formatted_string::parse_string("Not a <magenta>Wizard</magenta> Command."));
break;
}