The &" command now shows the total experience value of all monster on the level.
&G now prevents dismissed monsters from dropping their original equipment, except for unrandarts and fixed arts. You can force the dismissed monsters to drop all of their non-summoned items by adding "keepitem" to the regexp string.
&R can now either change the random monster spawn rate for the current level, or immediately spawn a given number of random monsters.
&^D can be used to examine and alter player enchantments/durations.
The targeting command "S" can be used to turn a permanent monster into a summoned one.
The targeting command "~" can be used to polymorph a monster into one of a particular type.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7870 c06c8d41-db1a-0410-9941-cceddc491573
2WWSPLCXLSMBGTXUC33EQ5YBOA5IBFSMJSTZ2TU6HZIMZZWZJWGAC
J7VTRSN2BLWL7QJMHG73LBUOUL6WNNT2ZAVEDMGYB6SDX3L5GGYQC
5IWO6LXJBETPTZA7F67UJURUU3FWGFBHRZILC7KQ2KJQSMTIS66AC
3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC
L254F6ZIU2HWGLFFGPIORTN4C3TDQ3E5JZ7Z7GQA5AEDIKL6PKDAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
O7S3ILRELHICJXXTDGMF7KPPZWYHPYCNDPV2I77FZXXH4I454B4QC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
Y4NA3JSN63RLATF4NNBPSR5CWF5Z7UEMWCGVX4B6NOAR47CGM4GQC
HZ7DYCFH4VUDNUBNP5Z2HSYJWJRIVUEQVYWG7NTCMYNZJQT7NIPQC
L5CVPV5IUBSO4EE3WK4O6SQGIMIEPSMQONFBWEVGJBR2HATLPZIAC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
KFZYPFHHOWRUZEK2PW26EI73Z6I6DLHW2YEJV2CB5XBWFRRNBFXQC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
X5OHFTHRXTI5KHFIYFJ6DB3W5MY3JUJKNTL4HF37MKABYNCOBOZAC
3IMZJEIBQTRXX5OLN7NUZ3QSGNVH2VPVTBDESVVWXIYURTHF3VXAC
3FBKOX4Y5QYPMBOCSAMHNZXCY7Z75YDQDL4EJZHZIGDXL7RMZ7TAC
ZNMT5CZHP2FC4HTLNA7KYEDGFBXSCUE5QHJOALVPE6RDPHSEDXRQC
Y5RFQ6KNJCBQUSV2T6WDR7TPZLZYLOAWBVMUTHDXGOZQDZ2U423AC
RV4L36J3DCVW3SONFFYAVK44XJQOFVNPGKHET7VOIFYHWZHCJRNAC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
BINKDWGFGUPTOA7IE5KK4ZIELGU5WC3X47MYXOWU4X43EGAC5DUAC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
46MRRHVYJ3BS74R2BEVUWEWJCI4FCRBSLZ3NWMQCE6FUCNE5P73QC
CCRQESB4ADT4WA7FGLNZZXAJ6G5QMCTYCZIWORBN45P6ZPILC34AC
4FQAKUKUO6PCAZ3N4HUR5XL6E4VA5UQUZ3AEDGRBLVY7W2LMWI7QC
4QRLZDW4KBFG34B3MCG4375NHFR3WKWSLWQKRMQ3OE5R26WCZBBQC
36DYXIWAQTBOCZBCUPYWDKAXVWDU3TRMSM3OCQZGGMWE2KPERJMAC
FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC
QO5ZJWQ3JK3PEGBPTQSAYIPEJEHG2M2KTD74227G5VG7DVXUL3BQC
YFIVTYI7PMVAXV23DUPXPAQNEY3YSFIXQGSN32I3WVHMMD5XS5DQC
CIPVRZGLOZHCERK6YPOBV3P2E4IAB4H6D5EHLRQE2O5E4P4VCBUAC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
7GJR755MBM55KIOP3DGSZIIAEQ5E2PRBHLEXZOU2ZMXHHZ5JI3GQC
case CMD_TARGET_WIZARD_MAKE_SUMMONED:
if (!you.wizard || !in_bounds(moves.target))
break;
mid = mgrd(moves.target);
if (mid == NON_MONSTER) // can put in terrain description here
break;
wizard_make_monster_summoned(&menv[mid]);
break;
case CMD_TARGET_WIZARD_POLYMORPH:
if (!you.wizard || !in_bounds(moves.target))
break;
mid = mgrd(moves.target);
if (mid == NON_MONSTER) // can put in terrain description here
break;
wizard_polymorph_monster(&menv[mid]);
break;
#endif
// 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_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 (!_item_type_can_be_artefact(item.base_type))
{
mpr("That item cannot be turned into an artefact.");
return;
}
int j;
// Set j == equipment slot of chosen item, remove old randart benefits.
for (j = 0; j < NUM_EQUIP; j++)
{
if (you.equip[j] == i)
{
if (j == EQ_WEAPON)
you.wield_change = true;
if (is_random_artefact( item ))
unuse_randart( i );
break;
}
}
if (is_random_artefact(item))
{
if (!yesno("Is already a randart; wipe and re-use?"))
{
canned_msg( MSG_OK );
// If equipped, re-apply benefits.
if (j != NUM_EQUIP)
use_randart( i );
return;
}
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_randarts)
{
add_autoinscription(item,
randart_auto_inscription(you.inv[i]));
}
// If equipped, apply new randart benefits.
if (j != NUM_EQUIP)
use_randart( i );
static const char* dur_names[NUM_DURATIONS] =
{
"invis",
"conf",
"paralysis",
"slow",
"mesmerised",
"haste",
"might",
"levitation",
"berserker",
"poisoning",
"confusing touch",
"sure blade",
"backlight",
"deaths door",
"fire shield",
"building rage",
"exhausted",
"liquid flames",
"icy armour",
"repel missiles",
"prayer",
"piety pool",
"divine vigour",
"divine stamina",
"divine shield",
"regeneration",
"swiftness",
"stonemail",
"controlled flight",
"teleport",
"control teleport",
"breath weapon",
"transformation",
"death channel",
"deflect missiles",
"forescry",
"see invisible",
"weapon brand",
"silence",
"condensation shield",
"stoneskin",
"repel undead",
"gourmand",
"bargain",
"insulation",
"resist poison",
"resist fire",
"resist cold",
"slaying",
"stealth",
"magic shield",
"sleep",
"sage",
"telepathy",
"petrified",
"lowered mr",
"repel stairs move",
"repel stairs climb"
};
void wizard_edit_durations( void )
{
std::vector<int> durs;
size_t max_len = 0;
for (int i = 0; i < NUM_DURATIONS; i++)
{
if (!you.duration[i])
continue;
max_len = std::max(strlen(dur_names[i]), max_len);
durs.push_back(i);
}
if (durs.size() > 0)
{
for (unsigned int i = 0; i < durs.size(); i++)
{
int dur = durs[i];
mprf(MSGCH_PROMPT, "%c) %-*s : %d", 'a' + i, max_len,
dur_names[dur], you.duration[dur]);
}
mpr("", MSGCH_PROMPT);
mpr("Edit which duration (letter or name)? ", MSGCH_PROMPT);
}
else
mpr("Edit which duration (name)? ", MSGCH_PROMPT);
char buf[80];
if (cancelable_get_line_autohist(buf, sizeof buf) || strlen(buf) == 0)
{
canned_msg( MSG_OK );
return;
}
strcpy(buf, lowercase_string(trimmed_string(buf)).c_str());
if (strlen(buf) == 0)
{
canned_msg( MSG_OK );
return;
}
int choice = -1;
if (strlen(buf) == 1)
{
if (durs.size() == 0)
{
mpr("No existing durations to choose from.", MSGCH_PROMPT);
return;
}
choice = buf[0] - 'a';
if (choice < 0 || choice >= (int) durs.size())
{
mpr("Invalid choice.", MSGCH_PROMPT);
return;
}
choice = durs[choice];
}
else
{
std::vector<int> matches;
std::vector<std::string> match_names;
max_len = 0;
for (int i = 0; i < NUM_DURATIONS; i++)
{
if (strcmp(dur_names[i], buf) == 0)
{
choice = i;
break;
}
if (strstr(dur_names[i], buf) != NULL)
{
matches.push_back(i);
match_names.push_back(dur_names[i]);
}
}
if (choice != -1)
;
else if (matches.size() == 1)
choice = matches[0];
else if (matches.size() == 0)
{
mprf(MSGCH_PROMPT, "No durations matching '%s'.", buf);
return;
}
else
{
std::string prefix = "No exact match for duration '";
prefix += buf;
prefix += "', possible matches are: ";
mpr_comma_separated_list(prefix, match_names, " and ", ", ",
MSGCH_DIAGNOSTICS);
return;
}
}
sprintf(buf, "Set '%s' to: ", dur_names[choice]);
int num = _debug_prompt_for_int(buf, false);
if (num == 0)
{
mpr("Can't set duration directly to 0, setting it to 1 instead.",
MSGCH_PROMPT);
num = 1;
}
you.duration[choice] = num;
}
}
// Make all of the monster's original equipment disappear, unless it's a fixed
// artefact or unrand artefact.
static void _vanish_orig_eq(monsters* mons)
{
for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
{
if (mons->inv[i] == NON_ITEM)
continue;
item_def &item(mitm[mons->inv[i]]);
if (!is_valid_item(item))
continue;
if (item.orig_place != 0 || item.orig_monnum != 0
|| !item.inscription.empty()
|| is_unrandom_artefact(item)
|| is_fixed_artefact(item)
|| (item.flags & (ISFLAG_DROPPED | ISFLAG_THROWN | ISFLAG_NOTED_GET
| ISFLAG_BEEN_IN_INV) ) )
{
continue;
}
item.flags |= ISFLAG_SUMMONED;
}
}
// Make all of the monsters' original equipment disappear unless "keepitem"
// is found in the regex (except for fixed arts and unrand arts).
bool keep_item = false;
if (strstr(buf, "keepitem") != NULL)
{
std::string str = replace_all(buf, "keepitem", "");
trim_string(str);
strcpy(buf, str.c_str());
keep_item = true;
}
void wizard_make_monster_summoned(monsters* mon)
{
int summon_type = 0;
if (mon->is_summoned(NULL, &summon_type) || summon_type != 0)
{
mpr("Monster is already summoned.", MSGCH_PROMPT);
return;
}
if (mons_is_unique(mon->type))
{
mpr("Can't make unique monsters summoned.");
return;
}
int dur = _debug_prompt_for_int("What summon longevity (1 to 6)? ", true);
if (dur < 1 || dur > 6)
{
canned_msg( MSG_OK );
return;
}
mpr("[a] clone [b] animated [c] chaos [d] miscast [e] zot", MSGCH_PROMPT);
mpr("[f] wrath [g] aid [m] misc [s] spell",
MSGCH_PROMPT);
mpr("Which summon type? ", MSGCH_PROMPT);
char choice = tolower(getch());
if (!(choice >= 'a' && choice <= 'g') && choice != 'm' && choice != 's')
{
canned_msg( MSG_OK );
return;
}
int type = 0;
switch (choice)
{
case 'a': type = MON_SUMM_CLONE; break;
case 'b': type = MON_SUMM_ANIMATE; break;
case 'c': type = MON_SUMM_CHAOS; break;
case 'd': type = MON_SUMM_MISCAST; break;
case 'e': type = MON_SUMM_ZOT; break;
case 'f': type = MON_SUMM_WRATH; break;
case 'g': type = MON_SUMM_AID; break;
case 'm': type = 0; break;
case 's':
{
char specs[80];
mpr( "Cast which spell by name? ", MSGCH_PROMPT );
get_input_line( specs, sizeof( specs ) );
if (specs[0] == '\0')
{
canned_msg( MSG_OK );
return;
}
spell_type spell = spell_by_name(specs, true);
if (spell == SPELL_NO_SPELL)
{
mpr("No such spell.", MSGCH_PROMPT);
return;
}
type = (int) spell;
break;
}
default:
DEBUGSTR("Invalid summon type choice.");
break;
}
mon->mark_summoned(dur, true, type);
}
void wizard_polymorph_monster(monsters* mon)
{
int old_type = mon->type;
int type = _debug_prompt_for_monster();
if (type == -1)
{
canned_msg( MSG_OK );
return;
}
if (invalid_monster_class(type) || type == MONS_PROGRAM_BUG)
{
mpr("Invalid monster type.", MSGCH_PROMPT);
return;
}
if (type == old_type)
{
mpr("Old type and new type are the same, not polymorphing.");
return;
}
if (mons_species(type) == mons_species(old_type))
{
mpr("Target species must be different than current species.");
return;
}
monster_polymorph(mon, (monster_type) type, PPT_SAME, true);
if (!mon->alive())
{
mpr("Polymorph killed monster?", MSGCH_ERROR);
return;
}
mon->check_redraw(mon->pos());
if (mon->type == old_type)
mpr("Polymorph failed.");
else if (mon->type != type)
mpr("Monster turned into something other than the desired type.");
// Returns whether an item of this type can be an artefact, or cursed.
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)
// Returns whether an item of this type can be cursed.
static bool _item_type_can_be_cursed( int type)
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);
return (type == OBJ_WEAPONS || type == OBJ_ARMOUR || type == OBJ_JEWELLERY);
case '+':
{
int i = prompt_invent_item( "Make an artefact out of which item?",
MT_INVLIST, -1 );
if (prompt_failed(i))
break;
item_def &item(you.inv[i]);
if (!_item_type_can_be_artefact(item.base_type))
{
mpr("That item cannot be turned into an artefact.");
break;
}
int j;
// Set j == equipment slot of chosen item, remove old randart benefits.
for (j = 0; j < NUM_EQUIP; j++)
{
if (you.equip[j] == i)
{
if (j == EQ_WEAPON)
you.wield_change = true;
if (is_random_artefact( item ))
unuse_randart( i );
break;
}
}
if (is_random_artefact(item))
{
if (!yesno("Is already a randart; wipe and re-use?"))
{
canned_msg( MSG_OK );
// If equipped, re-apply benefits.
if (j != NUM_EQUIP)
use_randart( i );
return;
}
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.");
break;
}
}
else if (!make_item_randart( item ))
{
mpr("Failed to turn item into randart.");
break;
}
if (Options.autoinscribe_randarts)
{
add_autoinscription(item,
randart_auto_inscription(you.inv[i]));
}
// If equipped, apply new randart benefits.
if (j != NUM_EQUIP)
use_randart( i );
}
else
{
// 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;