summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-10 18:21:32 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-10 18:21:32 +0000
commitd5f99b33e02371f88fa0028b496f48539d9ec8a1 (patch)
tree868a9c60ad96c7e320dd6843dd318785e03ae6d2 /crawl-ref/source
parent6e2e9d806ac731c0e421e7bfb4ab5497ea73730b (diff)
downloadcrawl-ref-d5f99b33e02371f88fa0028b496f48539d9ec8a1.tar.gz
crawl-ref-d5f99b33e02371f88fa0028b496f48539d9ec8a1.zip
Identification overhaul part II. Okay, not really. ;)
Applying Matthew's latest patch (1789869): Identify items you see monsters use. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2068 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/acr.cc27
-rw-r--r--crawl-ref/source/command.cc1
-rw-r--r--crawl-ref/source/debug.cc187
-rw-r--r--crawl-ref/source/debug.h1
-rw-r--r--crawl-ref/source/direct.cc12
-rw-r--r--crawl-ref/source/enum.h6
-rw-r--r--crawl-ref/source/externs.h10
-rw-r--r--crawl-ref/source/fight.cc51
-rw-r--r--crawl-ref/source/fight.h2
-rw-r--r--crawl-ref/source/itemname.cc25
-rw-r--r--crawl-ref/source/mon-util.cc167
-rw-r--r--crawl-ref/source/monstuff.cc95
-rw-r--r--crawl-ref/source/monstuff.h3
-rw-r--r--crawl-ref/source/view.cc24
14 files changed, 547 insertions, 64 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 89f55868d9..98a3697da4 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -669,6 +669,33 @@ static void handle_wizard_command( void )
}
}
you.wield_change = true;
+
+ // Forget things that nearby monsters are carrying, as well
+ // (for use with the "give monster an item" wizard targetting
+ // command).
+ for (i = 0; i < MAX_MONSTERS; i++)
+ {
+ monsters* mon = &menv[i];
+
+ if (!invalid_monster(mon) && mons_near(mon))
+ {
+ for (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.base_type, item.sub_type,
+ ID_UNKNOWN_TYPE );
+
+ unset_ident_flags( item, ISFLAG_IDENT_MASK );
+ }
+ }
+ }
break;
case 'X':
diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc
index 167f93c0c3..8cdc6b6ed1 100644
--- a/crawl-ref/source/command.cc
+++ b/crawl-ref/source/command.cc
@@ -541,6 +541,7 @@ static const char *targeting_help_1 =
"<h>Wizard targeting comands:</h>\n"
"<w>F</w>: make target friendly\n"
"<w>s</w>: force target to shout or speak\n"
+ "<w>g</w>: give item to monster\n"
#endif
;
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 5edb16a701..541e6d2974 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -2603,6 +2603,193 @@ void debug_make_monster_shout(monsters* mon)
}
#endif
+#ifdef WIZARD
+void wizard_give_monster_item(monsters *mon)
+{
+ mon_itemuse_type item_use = mons_itemuse( mon->type );
+ if (item_use < MONUSE_STARTING_EQUIPMENT)
+ {
+ mpr("That type of monster can't use any items.");
+ return;
+ }
+
+ int player_slot = prompt_invent_item( "Give which item to monster?",
+ MT_DROP, -1 );
+
+ if (player_slot == PROMPT_ABORT)
+ return;
+
+ for (int i = 0; i < NUM_EQUIP; i++)
+ if (you.equip[i] == player_slot)
+ {
+ mpr("Can't give equipped items to a monster.");
+ return;
+ }
+
+ item_def &item = you.inv[player_slot];
+ mon_inv_type mon_slot;
+
+ switch(item.base_type)
+ {
+ case OBJ_WEAPONS:
+ // Let wizard specify which slot to put weapon into via
+ // inscriptions.
+ if (item.inscription.find("first") != std::string::npos
+ || item.inscription.find("primary") != std::string::npos)
+ {
+ mpr("Putting weapon into primary slot by inscription");
+ mon_slot = MSLOT_WEAPON;
+ break;
+ }
+ else if (item.inscription.find("second") != std::string::npos
+ || item.inscription.find("alt") != std::string::npos)
+ {
+ mpr("Putting weapon into alt slot by inscription");
+ mon_slot = MSLOT_ALT_WEAPON;
+ break;
+ }
+
+ // For monsters which can wield two weapons, prefer whichever
+ // slot is empty (if there is an empty slot).
+ if (mons_wields_two_weapons(mon))
+ {
+ if (mon->inv[MSLOT_WEAPON] == NON_ITEM)
+ {
+ mpr("Dual wielding monster, putting into empty primary slot");
+ mon_slot = MSLOT_WEAPON;
+ break;
+ }
+ else if (mon->inv[MSLOT_ALT_WEAPON] == NON_ITEM)
+ {
+ mpr("Dual wielding monster, putting into empty alt slot");
+ mon_slot = MSLOT_ALT_WEAPON;
+ break;
+ }
+ }
+
+ // Try to replace a ranged weapon with a ranged weapon and
+ // a non-ranged weapon with a non-ranged weapon
+ if (mon->inv[MSLOT_WEAPON] != NON_ITEM
+ && (is_range_weapon(mitm[mon->inv[MSLOT_WEAPON]])
+ == is_range_weapon(item)))
+ {
+ mpr("Replacing primary slot with similar weapon");
+ mon_slot = MSLOT_WEAPON;
+ break;
+ }
+ if (mon->inv[MSLOT_ALT_WEAPON] != NON_ITEM
+ && (is_range_weapon(mitm[mon->inv[MSLOT_ALT_WEAPON]])
+ == is_range_weapon(item)))
+ {
+ mpr("Replacing alt slot with similar weapon");
+ mon_slot = MSLOT_ALT_WEAPON;
+ break;
+ }
+
+ // Prefer the empty slot (if any)
+ if (mon->inv[MSLOT_WEAPON] == NON_ITEM)
+ {
+ mpr("Putting weapon into empty primary slot");
+ mon_slot = MSLOT_WEAPON;
+ break;
+ }
+ else if (mon->inv[MSLOT_ALT_WEAPON] == NON_ITEM)
+ {
+ mpr("Putting weapon into empty alt slot");
+ mon_slot = MSLOT_ALT_WEAPON;
+ break;
+ }
+
+ // Default to primary weapon slot
+ mpr("Defaulting to primary slot");
+ mon_slot = MSLOT_WEAPON;
+ break;
+
+ case OBJ_ARMOUR:
+ mon_slot = MSLOT_ARMOUR;
+ break;
+ case OBJ_MISSILES:
+ mon_slot = MSLOT_MISSILE;
+ break;
+ case OBJ_WANDS:
+ mon_slot = MSLOT_WAND;
+ break;
+ case OBJ_SCROLLS:
+ mon_slot = MSLOT_SCROLL;
+ break;
+ case OBJ_POTIONS:
+ mon_slot = MSLOT_POTION;
+ break;
+ case OBJ_MISCELLANY:
+ mon_slot = MSLOT_MISCELLANY;
+ break;
+ default:
+ mpr("You can't give that type of item to a monster.");
+ return;
+ }
+
+ // Shouldn't be be using MONUSE_MAGIC_ITEMS?
+ if (item_use == MONUSE_STARTING_EQUIPMENT
+ && !mons_is_unique( mon->type ))
+ {
+ switch(mon_slot)
+ {
+ case MSLOT_WEAPON:
+ case MSLOT_ALT_WEAPON:
+ case MSLOT_ARMOUR:
+ case MSLOT_MISSILE:
+ break;
+
+ default:
+ mpr("That type of monster can only use weapons and armour.");
+ return;
+ }
+ }
+
+ int index = get_item_slot(10);
+
+ if (index == NON_ITEM)
+ {
+ mpr("Too many items on level, bailing.");
+ return;
+ }
+
+ // Move monster's old item to player's inventory as last step
+ int old_eq = NON_ITEM;
+ if (mon->inv[mon_slot] != NON_ITEM)
+ {
+ old_eq = mon->inv[mon_slot];
+
+ // Alternative weapons don't get (un)wielded unless the monster
+ // can wield two weapons.
+ if (mon_slot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))
+ mon->unequip(*(mon->mslot_item(mon_slot)), mon_slot, 1, true);
+ }
+
+ item_def &new_item = mitm[index];
+ new_item = item;
+ new_item.link = NON_ITEM;
+ new_item.x = 0;
+ new_item.y = 0;
+
+ mon->inv[mon_slot] = index;
+
+ // Alternative weapons don't get (un)wielded unless the monster
+ // can wield two weapons.
+ if (mon_slot != MSLOT_ALT_WEAPON || mons_wields_two_weapons(mon))
+ mon->equip(new_item, mon_slot, 1);
+
+ // Item is gone from player's inventory
+ dec_inv_item_quantity(player_slot, item.quantity);
+
+ // Monster's old item moves to player's inventory.
+ if (old_eq != NON_ITEM)
+ {
+ mpr("Fetching monster's old item.");
+ move_item_to_player(old_eq, mitm[old_eq].quantity);
+ }
+}
+#endif
#ifdef DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/debug.h b/crawl-ref/source/debug.h
index 6dd314f592..5e8b80ee76 100644
--- a/crawl-ref/source/debug.h
+++ b/crawl-ref/source/debug.h
@@ -160,6 +160,7 @@ void debug_dismiss_all_monsters();
class monsters;
void debug_make_monster_shout(monsters* mon);
+void wizard_give_monster_item(monsters* mon);
#ifdef DEBUG_DIAGNOSTICS
void generate_map_stats();
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 9c347adaeb..88da50188a 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -600,8 +600,17 @@ void direction(dist& moves, targeting_type restricts,
debug_make_monster_shout(&menv[mid]);
break;
-#endif
+ case CMD_TARGET_WIZARD_GIVE_ITEM:
+ if (!you.wizard || !in_bounds(moves.tx, moves.ty))
+ break;
+ mid = mgrd[moves.tx][moves.ty];
+ if (mid == NON_MONSTER) // can put in terrain description here
+ break;
+
+ wizard_give_monster_item(&menv[mid]);
+ break;
+#endif
case CMD_TARGET_DESCRIBE:
full_describe_square(moves.target());
@@ -1915,6 +1924,7 @@ command_type targeting_behaviour::get_command(int key)
#ifdef WIZARD
case 'F': return CMD_TARGET_WIZARD_MAKE_FRIENDLY;
case 's': return CMD_TARGET_WIZARD_MAKE_SHOUT;
+ case 'g': return CMD_TARGET_WIZARD_GIVE_ITEM;
#endif
case 'v': return CMD_TARGET_DESCRIBE;
case '?': return CMD_TARGET_HELP;
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 2fd4585600..1718d6cc9d 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -758,6 +758,7 @@ enum command_type
CMD_TARGET_DESCRIBE,
CMD_TARGET_WIZARD_MAKE_FRIENDLY,
CMD_TARGET_WIZARD_MAKE_SHOUT,
+ CMD_TARGET_WIZARD_GIVE_ITEM,
CMD_TARGET_HELP,
// Disable/enable -more- prompts.
@@ -1605,8 +1606,9 @@ enum item_type_id_type
enum item_type_id_state_type // used for values in id[4][50]
{
ID_UNKNOWN_TYPE = 0,
- ID_KNOWN_TYPE,
- ID_TRIED_TYPE
+ ID_MON_TRIED_TYPE,
+ ID_TRIED_TYPE,
+ ID_KNOWN_TYPE
};
enum jewellery_type
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index f326a6a251..b93b613304 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1111,8 +1111,9 @@ public:
bool pickup_misc(item_def &item, int near);
bool pickup_missile(item_def &item, int near, bool force);
bool eat_corpse(item_def &carrion, int near);
- void equip(const item_def &item, int slot, int near = -1);
- void unequip(const item_def &item, int slot, int near = -1);
+ void equip(item_def &item, int slot, int near = -1);
+ bool unequip(item_def &item, int slot, int near = -1,
+ bool force = false);
bool can_use_missile(const item_def &item) const;
@@ -1192,7 +1193,10 @@ private:
bool need_message(int &near) const;
bool pickup(item_def &item, int slot, int near, bool force_merge = false);
- void equip_weapon(const item_def &item, int near);
+ void equip_weapon(item_def &item, int near);
+ void equip_armour(item_def &item, int near);
+ void unequip_weapon(item_def &item, int near);
+ void unequip_armour(item_def &item, int near);
bool decay_enchantment(const mon_enchant &me, bool decay_degree = true);
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index e32961c628..9619b92e38 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -286,7 +286,7 @@ melee_attack::melee_attack(actor *attk, actor *defn,
: attacker(attk), defender(defn),
atk(NULL), def(NULL),
cancel_attack(false),
- did_hit(false), perceived_attack(false),
+ did_hit(false), perceived_attack(false), obvious_effect(false),
needs_message(false), attacker_visible(false), defender_visible(false),
attacker_invisible(false), defender_invisible(false),
unarmed_ok(allow_unarmed),
@@ -1615,6 +1615,8 @@ bool melee_attack::distortion_affects_defender()
if (one_chance_in(3))
{
emit_nodmg_hit_message();
+ if (defender_visible)
+ obvious_effect = true;
defender->blink();
return (false);
}
@@ -1626,6 +1628,8 @@ bool melee_attack::distortion_affects_defender()
if (!one_chance_in(3))
{
emit_nodmg_hit_message();
+ if (defender_visible)
+ obvious_effect = true;
defender->teleport(coinflip(), one_chance_in(5));
return (false);
}
@@ -1633,6 +1637,19 @@ bool melee_attack::distortion_affects_defender()
if (you.level_type != LEVEL_ABYSS && coinflip())
{
emit_nodmg_hit_message();
+
+ if (defender->atype() == ACT_PLAYER && attacker_visible
+ && weapon != NULL && !is_artefact(*weapon))
+ {
+ // If the player is being sent to the Abyss by being attacked
+ // with a distortion weapon, then we have to ID it before
+ // the player goes to Abyss, while the weapon object is
+ // still in memory.
+ set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
+ }
+ else if (defender_visible)
+ obvious_effect = true;
+
defender->banish( atk? atk->name(DESC_PLAIN, true)
: attacker->name(DESC_PLAIN) );
return (true);
@@ -1643,10 +1660,13 @@ bool melee_attack::distortion_affects_defender()
bool melee_attack::apply_damage_brand()
{
+ bool ret = false;
+
// Monster resistance to the brand.
int res = 0;
-
+
special_damage = 0;
+ obvious_effect = false;
switch (damage_brand)
{
case SPWPN_FLAMING:
@@ -1718,12 +1738,24 @@ bool melee_attack::apply_damage_brand()
case SPWPN_STAFF_OF_OLGREB:
if (!one_chance_in(4))
{
+ int old_poison = 0;
+
+ if (defender->atype() == ACT_PLAYER)
+ old_poison = you.duration[DUR_POISONING];
+
// Poison monster message needs to arrive after hit message.
emit_nodmg_hit_message();
// Weapons of venom do two levels of poisoning to the player,
// but only one level to monsters.
defender->poison( attacker, 2 );
+
+ if (defender->atype() == ACT_PLAYER
+ && old_poison < you.duration[DUR_POISONING])
+ {
+ obvious_effect = true;
+ }
+
}
break;
@@ -1747,6 +1779,8 @@ bool melee_attack::apply_damage_brand()
break;
}
+ obvious_effect = true;
+
// vampire bat form
if (you.species == SP_VAMPIRE && attacker->atype() == ACT_PLAYER
&& you.attribute[ATTR_TRANSFORMATION] == TRAN_BAT)
@@ -1853,8 +1887,7 @@ bool melee_attack::apply_damage_brand()
break;
case SPWPN_DISTORTION:
- if (distortion_affects_defender())
- return (true);
+ ret = distortion_affects_defender();
break;
case SPWPN_CONFUSE:
@@ -1885,7 +1918,15 @@ bool melee_attack::apply_damage_brand()
}
}
- return (false);
+ obvious_effect = obvious_effect || (special_damage_message != "");
+
+ if (obvious_effect && attacker_visible && weapon != NULL
+ && !is_artefact(*weapon))
+ {
+ set_ident_flags(*weapon, ISFLAG_KNOW_TYPE);
+ }
+
+ return (ret);
}
// Returns true if a head got lopped off.
diff --git a/crawl-ref/source/fight.h b/crawl-ref/source/fight.h
index 900e90c156..58ecd98160 100644
--- a/crawl-ref/source/fight.h
+++ b/crawl-ref/source/fight.h
@@ -65,7 +65,7 @@ public:
monsters *atk, *def;
bool cancel_attack;
- bool did_hit, perceived_attack;
+ bool did_hit, perceived_attack, obvious_effect;
// If all or part of the action is visible to the player, we need a message.
bool needs_message;
diff --git a/crawl-ref/source/itemname.cc b/crawl-ref/source/itemname.cc
index 1c13c750ae..ee02552c5d 100644
--- a/crawl-ref/source/itemname.cc
+++ b/crawl-ref/source/itemname.cc
@@ -213,16 +213,28 @@ std::string item_def::name(description_level_type descrip,
}
}
- const bool tried = (!ident && item_type_tried(*this));
+ const bool tried = (!ident && item_type_tried(*this));
+ std::string tried_str = "";
+
+ if (tried)
+ {
+ item_type_id_state_type id_type =
+ get_ident_type(this->base_type, this->sub_type);
+ if (id_type == ID_MON_TRIED_TYPE)
+ tried_str = "tried by monster";
+ else
+ tried_str = "tried";
+ }
+
if ( with_inscription && !(this->inscription.empty()) )
{
buff << " {";
if ( tried )
- buff << "tried, ";
+ buff << tried_str << ", ";
buff << this->inscription << "}";
}
else if ( tried )
- buff << " {tried}";
+ buff << " {" << tried_str << "}";
return buff.str();
}
@@ -1559,7 +1571,8 @@ bool item_type_tried( const item_def& item )
const item_type_id_type idt = objtype_to_idtype(item.base_type);
if (idt != NUM_IDTYPE && item.sub_type < 50)
- return ( type_ids[idt][item.sub_type] == ID_TRIED_TYPE );
+ return ( type_ids[idt][item.sub_type] == ID_TRIED_TYPE
+ || type_ids[idt][item.sub_type] == ID_MON_TRIED_TYPE);
else
return false;
}
@@ -1574,8 +1587,8 @@ void set_ident_type( object_class_type basetype, int subtype,
{
// Don't allow overwriting of known type with tried unless forced.
if (!force
- && setting == ID_TRIED_TYPE
- && get_ident_type( basetype, subtype ) == ID_KNOWN_TYPE)
+ && (setting == ID_MON_TRIED_TYPE || setting == ID_TRIED_TYPE)
+ && setting <= get_ident_type( basetype, subtype ))
{
return;
}
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index ff7ef0d590..58b4c5bb2b 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2459,14 +2459,19 @@ void monsters::swap_slots(mon_inv_type a, mon_inv_type b)
inv[b] = swap;
}
-void monsters::equip_weapon(const item_def &item, int near)
+void monsters::equip_weapon(item_def &item, int near)
{
+ if (need_message(near))
+ mprf("%s wields %s.", name(DESC_CAP_THE).c_str(),
+ item.name(DESC_NOCAP_A).c_str());
+
const int brand = get_weapon_brand(item);
if (brand == SPWPN_PROTECTION)
ac += 5;
if (brand != SPWPN_NORMAL && need_message(near))
{
+ bool message_given = true;
switch (brand)
{
case SPWPN_FLAMING:
@@ -2499,52 +2504,137 @@ void monsters::equip_weapon(const item_def &item, int near)
case SPWPN_RETURNING:
mpr("It wiggles slightly.");
break;
+ case SPWPN_DISTORTION:
+ mpr("Its appearance distorts for a moment.");
+ break;
+ default:
+ message_given = false;
}
+ if (message_given)
+ set_ident_flags(item, ISFLAG_KNOW_TYPE);
}
}
-void monsters::equip(const item_def &item, int slot, int near)
+void monsters::equip_armour(item_def &item, int near)
+{
+ if (need_message(near))
+ mprf("%s wears %s.", name(DESC_CAP_THE).c_str(),
+ item.name(DESC_NOCAP_A).c_str());
+
+ ac += property( item, PARM_AC );
+
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac += armour_plus;
+ ev += property( item, PARM_EVASION ) / 2;
+
+ if (ev < 1)
+ ev = 1; // This *shouldn't* happen.
+}
+
+void monsters::equip(item_def &item, int slot, int near)
{
switch (item.base_type)
{
case OBJ_WEAPONS:
- if (need_message(near))
- mprf("%s wields %s.", name(DESC_CAP_THE).c_str(),
- item.name(DESC_NOCAP_A).c_str());
equip_weapon(item, near);
break;
case OBJ_ARMOUR:
- {
- ac += property( item, PARM_AC );
-
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac += armour_plus;
- ev += property( item, PARM_EVASION ) / 2;
-
- if (ev < 1)
- ev = 1; // This *shouldn't* happen.
+ equip_armour(item, near);
break;
- }
default:
break;
}
}
-void monsters::unequip(const item_def &item, int slot, int near)
+void monsters::unequip_weapon(item_def &item, int near)
{
- // XXX: Handle armour removal when armour swapping is implemented.
+ if (need_message(near))
+ mprf("%s unwields %s.", name(DESC_CAP_THE).c_str(),
+ item.name(DESC_NOCAP_A).c_str());
+
+ const int brand = get_weapon_brand(item);
+ if (brand == SPWPN_PROTECTION)
+ ac -= 5;
+
+ if (brand != SPWPN_NORMAL && need_message(near))
+ {
+ bool message_given = true;
+ switch (brand)
+ {
+ case SPWPN_FLAMING:
+ mpr("It stops flaming.");
+ break;
+
+ case SPWPN_HOLY_WRATH:
+ mpr("It stops glowing.");
+ break;
+
+ case SPWPN_ELECTROCUTION:
+ mpr("It stops crackling.");
+ break;
+
+ case SPWPN_VENOM:
+ mpr("It stops dripping with poison.");
+ break;
+
+ case SPWPN_DISTORTION:
+ mpr("Its appearance distorts for a moment.");
+ break;
+
+ default:
+ message_given = false;
+ }
+ if (message_given)
+ set_ident_flags(item, ISFLAG_KNOW_TYPE);
+ }
+}
+
+void monsters::unequip_armour(item_def &item, int near)
+{
+ if (need_message(near))
+ mprf("%s takes off %s.", name(DESC_CAP_THE).c_str(),
+ item.name(DESC_NOCAP_A).c_str());
+
+ ac -= property( item, PARM_AC );
+
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac -= armour_plus;
+ ev -= property( item, PARM_EVASION ) / 2;
+
+ if (ev < 1)
+ ev = 1; // This *shouldn't* happen.
+}
+
+bool monsters::unequip(item_def &item, int slot, int near, bool force)
+{
+ if (item.cursed() && !force)
+ return false;
+
+ if (!force && mons_near(this) && player_monster_visible(this))
+ set_ident_flags(item, ISFLAG_KNOW_CURSE);
+
switch (item.base_type)
{
case OBJ_WEAPONS:
- if (get_weapon_brand(item) == SPWPN_PROTECTION)
- ac -= 5;
+ unequip_weapon(item, near);
+ break;
+
+ // Armour swapping not implemented yet, but armour can be
+ // removed if wizard forces monster to wear a new piece of
+ // armour with the "give item" wizard command.
+ case OBJ_ARMOUR:
+ unequip_armour(item, near);
break;
default:
break;
}
+
+ return true;
}
void monsters::lose_pickup_energy()
@@ -2597,16 +2687,28 @@ bool monsters::drop_item(int eslot, int near)
if (index == NON_ITEM)
return (true);
- // Cannot drop cursed weapon or armour.
- if ((eslot == MSLOT_WEAPON || eslot == MSLOT_ARMOUR)
- && mitm[index].cursed())
- return (false);
+ // Unequip equipped items before dropping them; unequip() prevents
+ // cursed items from being removed.
+ bool was_unequipped = false;
+ if (eslot == MSLOT_WEAPON || eslot == MSLOT_ARMOUR
+ || (eslot == MSLOT_ALT_WEAPON && mons_wields_two_weapons(this) ))
+ {
+ if (!unequip(mitm[index], eslot, near))
+ return (false);
+ was_unequipped = true;
+ }
const std::string iname = mitm[index].name(DESC_NOCAP_A);
move_item_to_grid(&index, x, y);
if (index == inv[eslot])
+ {
+ // Re-equip item if we somehow failed to drop it.
+ if (was_unequipped)
+ equip(mitm[index], eslot, near);
+
return (false);
+ }
if (need_message(near))
mprf("%s drops %s.", name(DESC_CAP_THE).c_str(), iname.c_str());
@@ -2869,21 +2971,16 @@ bool monsters::need_message(int &near) const
void monsters::swap_weapons(int near)
{
- const item_def *weap = mslot_item(MSLOT_WEAPON);
- const item_def *alt = mslot_item(MSLOT_ALT_WEAPON);
+ item_def *weap = mslot_item(MSLOT_WEAPON);
+ item_def *alt = mslot_item(MSLOT_ALT_WEAPON);
if (weap)
- unequip(*weap, MSLOT_WEAPON, !alt && need_message(near));
+ if(!unequip(*weap, MSLOT_WEAPON, near))
+ // Item was cursed
+ return;
swap_slots(MSLOT_WEAPON, MSLOT_ALT_WEAPON);
- if (need_message(near))
- {
- if (!alt && weap)
- mprf("%s unwields %s.", name(DESC_CAP_THE).c_str(),
- weap->name(DESC_NOCAP_A).c_str());
- }
-
if (alt)
equip(*alt, MSLOT_WEAPON, near);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 120c4be4da..0e51695aa6 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2587,7 +2587,10 @@ static bool handle_potion(monsters *monster, bolt & beem)
return (false);
else
{
- bool imbibed = false;
+ bool imbibed = false;
+ item_type_id_state_type ident = ID_UNKNOWN_TYPE;
+ bool was_visible =
+ mons_near(monster) && player_monster_visible(monster);
const int potion_type = mitm[monster->inv[MSLOT_POTION]].sub_type;
switch (potion_type)
@@ -2602,7 +2605,10 @@ static bool handle_potion(monsters *monster, bolt & beem)
simple_monster_message(monster, " drinks a potion.");
if (heal_monster(monster, 5 + random2(7), false))
+ {
simple_monster_message(monster, " is healed!");
+ ident = ID_MON_TRIED_TYPE;
+ }
if (mitm[monster->inv[MSLOT_POTION]].sub_type
== POT_HEAL_WOUNDS)
@@ -2614,8 +2620,10 @@ static bool handle_potion(monsters *monster, bolt & beem)
{
monster->del_ench(ENCH_POISON);
monster->del_ench(ENCH_SICK);
- monster->del_ench(ENCH_CONFUSION);
- monster->del_ench(ENCH_ROT);
+ if (monster->del_ench(ENCH_CONFUSION))
+ ident = ID_KNOWN_TYPE;
+ if (monster->del_ench(ENCH_ROT))
+ ident = ID_KNOWN_TYPE;
}
imbibed = true;
@@ -2646,6 +2654,7 @@ static bool handle_potion(monsters *monster, bolt & beem)
imbibed = true;
}
+ ident = ID_KNOWN_TYPE;
break;
}
@@ -2653,6 +2662,9 @@ static bool handle_potion(monsters *monster, bolt & beem)
{
if (dec_mitm_item_quantity( monster->inv[MSLOT_POTION], 1 ))
monster->inv[MSLOT_POTION] = NON_ITEM;
+
+ if (ident != ID_UNKNOWN_TYPE && was_visible)
+ set_ident_type(OBJ_POTIONS, potion_type, ident);
}
return (imbibed);
@@ -2704,6 +2716,13 @@ static bool handle_reaching(monsters *monster)
}
}
+ // Player saw the item reach
+ if (ret && !is_artefact(mitm[wpn]) && mons_near(monster)
+ && player_monster_visible(monster))
+ {
+ set_ident_flags(mitm[wpn], ISFLAG_KNOW_TYPE);
+ }
+
return ret;
} // end handle_reaching()
@@ -2730,10 +2749,14 @@ static bool handle_scroll(monsters *monster)
return (false);
else
{
- bool read = false;
+ bool read = false;
+ item_type_id_state_type ident = ID_UNKNOWN_TYPE;
+ bool was_visible =
+ mons_near(monster) && player_monster_visible(monster);
// notice how few cases are actually accounted for here {dlb}:
- switch (mitm[monster->inv[MSLOT_SCROLL]].sub_type)
+ const int scroll_type = mitm[monster->inv[MSLOT_SCROLL]].sub_type;
+ switch (scroll_type)
{
case SCR_TELEPORTATION:
if (!monster->has_ench(ENCH_TP))
@@ -2742,7 +2765,8 @@ static bool handle_scroll(monsters *monster)
{
simple_monster_message(monster, " reads a scroll.");
monster_teleport(monster, false);
- read = true;
+ read = true;
+ ident = ID_KNOWN_TYPE;
}
}
break;
@@ -2755,7 +2779,8 @@ static bool handle_scroll(monsters *monster)
simple_monster_message(monster, " reads a scroll.");
simple_monster_message(monster, " blinks!");
monster_blink(monster);
- read = true;
+ read = true;
+ ident = ID_KNOWN_TYPE;
}
}
break;
@@ -2767,7 +2792,8 @@ static bool handle_scroll(monsters *monster)
create_monster( MONS_ABOMINATION_SMALL, 2,
SAME_ATTITUDE(monster), monster->x, monster->y,
monster->foe, 250 );
- read = true;
+ read = true;
+ ident = ID_KNOWN_TYPE;
}
break;
}
@@ -2776,6 +2802,9 @@ static bool handle_scroll(monsters *monster)
{
if (dec_mitm_item_quantity( monster->inv[MSLOT_SCROLL], 1 ))
monster->inv[MSLOT_SCROLL] = NON_ITEM;
+
+ if (ident != ID_UNKNOWN_TYPE && was_visible)
+ set_ident_type(OBJ_SCROLLS, scroll_type, ident);
}
return read;
@@ -2806,8 +2835,10 @@ static bool handle_wand(monsters *monster, bolt &beem)
}
else if (coinflip())
{
- bool niceWand = false;
- bool zap = false;
+ bool niceWand = false;
+ bool zap = false;
+ bool was_visible =
+ mons_near(monster) && player_monster_visible(monster);
// map wand type to monster spell type
int mzap = map_wand_to_mspell(mitm[monster->inv[MSLOT_WAND]].sub_type);
@@ -2845,7 +2876,8 @@ static bool handle_wand(monsters *monster, bolt &beem)
beem.aux_source = item.name(DESC_PLAIN);
- switch (mitm[monster->inv[MSLOT_WAND]].sub_type)
+ const int wand_type = mitm[monster->inv[MSLOT_WAND]].sub_type;
+ switch (wand_type)
{
// these have been deemed "too tricky" at this time {dlb}:
case WAND_POLYMORPH_OTHER:
@@ -2931,6 +2963,14 @@ static bool handle_wand(monsters *monster, bolt &beem)
beem.is_tracer = false;
fire_beam( beem );
+ if (was_visible)
+ {
+ if (niceWand || beem.name != "0" || beem.obvious_effect)
+ set_ident_type(OBJ_WANDS, wand_type, ID_KNOWN_TYPE);
+ else
+ set_ident_type(OBJ_WANDS, wand_type, ID_MON_TRIED_TYPE);
+ }
+
return (true);
}
}
@@ -3516,6 +3556,39 @@ int mons_pick_best_missile(monsters *mons, item_def **launcher,
}
}
+bool mons_eq_obvious_ego(const item_def &item, const struct monsters *mon)
+{
+ if (is_artefact(item))
+ return false;
+
+ // Only do weapons for now
+ if (item.base_type != OBJ_WEAPONS)
+ return false;
+
+ int ego = item.special;
+
+ switch(ego)
+ {
+
+ case SPWPN_FLAMING:
+ case SPWPN_FREEZING:
+ case SPWPN_HOLY_WRATH:
+ case SPWPN_VENOM:
+ // Electric branded weapons are constantly crackling
+ case SPWPN_ELECTROCUTION:
+ // Unlike SPWPN_FLAME, SPWPN_FROST has a persistant visual effect.
+ case SPWPN_FROST:
+ return true;
+
+ // SPWPN_FLAME just "glows red for a moment" when first equipped,
+ // so it isn't obvious after that.
+ case SPWPN_FLAME:
+ return false;
+ }
+
+ return false;
+}
+
//---------------------------------------------------------------
//
// handle_throw
diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h
index 152c44787f..9612fed7af 100644
--- a/crawl-ref/source/monstuff.h
+++ b/crawl-ref/source/monstuff.h
@@ -173,4 +173,7 @@ int mons_missile_damage(const item_def *launch,
const item_def *missile);
int mons_thrown_weapon_damage(const item_def *weap);
+bool mons_eq_obvious_ego(const item_def &item,
+ const struct monsters *mon = NULL);
+
#endif
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 896eb12874..ad6f9641e3 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -1009,6 +1009,29 @@ void monster_grid(bool do_updates)
}
}
+static void learn_visible_mon_eq_egos(monsters *mon)
+{
+ for (int i = 0; i < NUM_MONSTER_SLOTS; i++)
+ {
+ mon_inv_type slot = static_cast<mon_inv_type>(i);
+ int index = mon->inv[slot];
+
+ if (index == NON_ITEM)
+ continue;
+
+ // Alternate weapons aren't wielded (and thus have no
+ // visible differences) unless the monster can wield two
+ // weapons at once.
+ if (slot == MSLOT_ALT_WEAPON && !mons_wields_two_weapons(mon))
+ continue;
+
+ item_def &item = mitm[index];
+
+ if (mons_eq_obvious_ego(item, mon))
+ set_ident_flags(item, ISFLAG_KNOW_TYPE);
+ }
+}
+
void fire_monster_alerts()
{
for (int s = 0; s < MAX_MONSTERS; s++)
@@ -1028,6 +1051,7 @@ void fire_monster_alerts()
interrupt_activity( AI_SEE_MONSTER, monster );
}
seen_monster( monster );
+ learn_visible_mon_eq_egos(monster);
// Monster was viewed this turn
monster->flags |= MF_WAS_IN_VIEW;