summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-11-02 15:05:33 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-11-02 15:05:33 +0000
commitd8537ce97fcc261408188af698b908948a0a2b84 (patch)
tree5783fae57cda6312329c0c1d46a0d82cc27181f8 /crawl-ref/source
parentee11c9b3ddae51109d602aa87fc5eb96a3d9e4a4 (diff)
downloadcrawl-ref-d8537ce97fcc261408188af698b908948a0a2b84.tar.gz
crawl-ref-d8537ce97fcc261408188af698b908948a0a2b84.zip
Experimental support for monster shields, needs more work for rationalising shield class for monsters with player and beam to-hit.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2727 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/beam.cc26
-rw-r--r--crawl-ref/source/debug.cc4
-rw-r--r--crawl-ref/source/enum.h1
-rw-r--r--crawl-ref/source/fight.cc25
-rw-r--r--crawl-ref/source/makeitem.cc85
-rw-r--r--crawl-ref/source/mon-util.cc72
6 files changed, 166 insertions, 47 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 4e532cb96d..ba3c94cacc 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -3129,14 +3129,14 @@ static int affect_player( bolt &beam )
#endif
if (hit < block)
{
- you.shield_blocks++;
mprf( "You block the %s.", beam.name.c_str() );
- exercise( SK_SHIELDS, exer + 1 );
+ you.shield_block_succeeded();
return (BEAM_STOP);
}
// some training just for the "attempt"
- exercise( SK_SHIELDS, exer );
+ if (coinflip())
+ exercise( SK_SHIELDS, exer );
}
if (player_light_armour(true) && !beam.aimed_at_feet
@@ -3878,6 +3878,26 @@ static int affect_monster(bolt &beam, monsters *mon)
return (0);
}
+ // The monster may block the beam.
+ if (!engulfs && beam_is_blockable(beam))
+ {
+ const int shield_block = mon->shield_bonus();
+ if (shield_block > 0)
+ {
+ const int hit = random2( beam.hit * 130 / 100
+ + mon->shield_block_penalty() );
+ if (hit < shield_block && mons_near(mon)
+ && player_monster_visible(mon))
+ {
+ mprf("%s blocks the %s.",
+ mon->name(DESC_CAP_THE).c_str(),
+ beam.name.c_str());
+ mon->shield_block_succeeded();
+ return (BEAM_STOP);
+ }
+ }
+ }
+
update_hurt_or_helped(beam, mon);
// the beam hit.
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index d2cbb2510e..d3d020b1ab 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1448,8 +1448,8 @@ void stethoscope(int mwh)
(menv[i].foe == MHITNOT) ? "none" :
(menv[menv[i].foe].type == -1) ? "unassigned monster"
: menv[menv[i].foe].name(DESC_PLAIN, true).c_str()),
- menv[i].foe,
- menv[i].foe_memory,
+ menv[i].foe,
+ menv[i].foe_memory,
menv[i].target_x, menv[i].target_y );
// print resistances
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index eb4859627b..a7cecf10c4 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1825,6 +1825,7 @@ enum mon_inv_type // (int) menv[].inv[]
// for monsters that can use two weapons.
MSLOT_MISSILE,
MSLOT_ARMOUR,
+ MSLOT_SHIELD,
MSLOT_MISCELLANY,
MSLOT_POTION,
MSLOT_WAND,
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 4a5a9c7f5d..e132835e88 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -545,9 +545,16 @@ bool melee_attack::player_attack()
if (Options.tutorial_left)
Options.tut_melee_counter++;
- // This actually does more than calculate damage - it also sets up
- // messages, etc.
- player_calc_hit_damage();
+ const bool shield_blocked = attack_shield_blocked(true);
+
+ if (shield_blocked)
+ damage_done = 0;
+ else
+ {
+ // This actually does more than calculate damage - it also sets up
+ // messages, etc.
+ player_calc_hit_damage();
+ }
bool hit_woke_orc = false;
if (you.religion == GOD_BEOGH && mons_species(def->type) == MONS_ORC
@@ -564,7 +571,7 @@ bool melee_attack::player_attack()
if (damage_done > 0 || !defender_visible)
player_announce_hit();
- else if (damage_done <= 0)
+ else if (!shield_blocked && damage_done <= 0)
no_damage_message =
make_stringf("You %s %s.",
attack_verb.c_str(),
@@ -584,6 +591,10 @@ bool melee_attack::player_attack()
}
player_sustain_passive_damage();
+
+ // At this point, pretend we didn't hit at all.
+ if (shield_blocked)
+ did_hit = false;
}
else
player_warn_miss();
@@ -854,6 +865,8 @@ bool melee_attack::player_aux_unarmed()
did_hit = false;
if (to_hit >= def->ev || one_chance_in(30))
{
+ if (attack_shield_blocked(true))
+ continue;
if (player_apply_aux_unarmed())
return (true);
}
@@ -2865,8 +2878,8 @@ bool melee_attack::attack_shield_blocked(bool verbose)
pro_block /= 3;
#ifdef DEBUG_DIAGNOSTICS
- mprf(MSGCH_DIAGNOSTICS, "Pro-block: %d, Con-block: %d",
- pro_block, con_block);
+ mprf(MSGCH_DIAGNOSTICS, "Defender: %s, Pro-block: %d, Con-block: %d",
+ def_name(DESC_PLAIN).c_str(), pro_block, con_block);
#endif
if (pro_block >= con_block)
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index 2fef1653bf..e0a5e70030 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -3222,12 +3222,12 @@ static item_make_species_type give_weapon(monsters *mon, int level,
const int temp_rand = random2(100);
item.sub_type = ((temp_rand > 79) ? WPN_LONG_SWORD : // 20%
- (temp_rand > 59) ? WPN_SHORT_SWORD : // 20%
- (temp_rand > 45) ? WPN_SCIMITAR : // 14%
- (temp_rand > 31) ? WPN_MACE : // 14%
- (temp_rand > 18) ? WPN_BOW : // 13%
- (temp_rand > 5) ? WPN_HAND_CROSSBOW // 13%
- : WPN_LONGBOW); // 6%
+ (temp_rand > 59) ? WPN_SHORT_SWORD : // 20%
+ (temp_rand > 45) ? WPN_SCIMITAR : // 14%
+ (temp_rand > 31) ? WPN_MACE : // 14%
+ (temp_rand > 18) ? WPN_BOW : // 13%
+ (temp_rand > 5) ? WPN_HAND_CROSSBOW // 13%
+ : WPN_LONGBOW); // 6%
break;
}
@@ -3830,6 +3830,78 @@ static void give_ammo(monsters *mon, int level,
}
}
+static bool make_item_for_monster(
+ monsters *mons,
+ object_class_type base,
+ int subtype,
+ int level,
+ item_make_species_type race = MAKE_ITEM_NO_RACE,
+ int allow_uniques = 0)
+{
+ const int bp = get_item_slot();
+ if (bp == NON_ITEM)
+ return (false);
+
+ const int thing_created =
+ items( allow_uniques, base, subtype, true, level, race );
+
+ if (thing_created == NON_ITEM)
+ return (false);
+
+ give_monster_item(mons, thing_created);
+ return (true);
+}
+
+void give_shield(monsters *mon, int level)
+{
+ switch (mon->type)
+ {
+ case MONS_DAEVA:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+
+ case MONS_DEEP_ELF_SOLDIER:
+ case MONS_DEEP_ELF_FIGHTER:
+ if (one_chance_in(5))
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level, MAKE_ITEM_ELVEN);
+ break;
+ case MONS_NAGA_WARRIOR:
+ case MONS_VAULT_GUARD:
+ if (one_chance_in(3))
+ make_item_for_monster(mon, OBJ_ARMOUR,
+ one_chance_in(3)? ARM_LARGE_SHIELD
+ : ARM_SHIELD,
+ level, MAKE_ITEM_NO_RACE);
+ break;
+ case MONS_DRACONIAN_KNIGHT:
+ if (coinflip())
+ make_item_for_monster(mon, OBJ_ARMOUR,
+ coinflip()? ARM_LARGE_SHIELD : ARM_SHIELD,
+ level, MAKE_ITEM_NO_RACE);
+ break;
+ case MONS_DEEP_ELF_KNIGHT:
+ if (coinflip())
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level, MAKE_ITEM_ELVEN);
+ break;
+ case MONS_NORRIS:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_BUCKLER,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ case MONS_NORBERT:
+ case MONS_LOUISE:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_LARGE_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ case MONS_DONALD:
+ make_item_for_monster(mon, OBJ_ARMOUR, ARM_SHIELD,
+ level * 2 + 1, MAKE_ITEM_RANDOM_RACE, 1);
+ break;
+ }
+}
+
void give_armour(monsters *mon, int level)
{
const int bp = get_item_slot();
@@ -4071,6 +4143,7 @@ void give_item(int mid, int level_number) //mv: cleanup+minor changes
give_ammo(mons, level_number, item_race);
give_armour(mons, 1 + level_number / 2);
+ give_shield(mons, 1 + level_number / 2);
} // end give_item()
jewellery_type get_random_amulet_type()
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 5cf5aa1168..84e27d4843 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2765,14 +2765,19 @@ void monsters::equip_armour(item_def &item, int near)
mprf("%s wears %s.", name(DESC_CAP_THE).c_str(),
item.name(DESC_NOCAP_A).c_str());
- ac += property( item, PARM_AC );
+ const equipment_type eq = get_armour_slot(item);
+ if (eq != EQ_SHIELD)
+ {
+ ac += property( item, PARM_AC );
+
+ const int armour_plus = item.plus;
+ ASSERT(abs(armour_plus) < 20);
+ if (abs(armour_plus) < 20)
+ ac += armour_plus;
+ }
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac += armour_plus;
+ // Shields can affect evasion.
ev += property( item, PARM_EVASION ) / 2;
-
if (ev < 1)
ev = 1; // This *shouldn't* happen.
}
@@ -2842,14 +2847,18 @@ void monsters::unequip_armour(item_def &item, int 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 equipment_type eq = get_armour_slot(item);
+ if (eq != EQ_SHIELD)
+ {
+ ac -= property( item, PARM_AC );
- const int armour_plus = item.plus;
- ASSERT(abs(armour_plus) < 20);
- if (abs(armour_plus) < 20)
- ac -= armour_plus;
+ 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.
}
@@ -3107,6 +3116,17 @@ bool monsters::wants_armour(const item_def &item) const
return (!mslot_item(MSLOT_ARMOUR));
}
+static mon_inv_type equip_slot_to_mslot(equipment_type eq)
+{
+ switch (eq)
+ {
+ case EQ_WEAPON: return MSLOT_WEAPON;
+ case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
+ case EQ_SHIELD: return MSLOT_SHIELD;
+ default: return (NUM_MONSTER_SLOTS);
+ }
+}
+
bool monsters::pickup_armour(item_def &item, int near, bool force)
{
ASSERT(item.base_type == OBJ_ARMOUR);
@@ -3114,21 +3134,24 @@ bool monsters::pickup_armour(item_def &item, int near, bool force)
if (!force && !wants_armour(item))
return (false);
- // XXX: Monsters can only equip body armour (as of 0.3).
- if (get_armour_slot(item) != EQ_BODY_ARMOUR)
+ const equipment_type eq = get_armour_slot(item);
+ // XXX: Monsters can only equip body armour and shields (as of 0.4).
+ // They can still be forced to wear stuff - this is needed for bardings.
+ if (!force && eq != EQ_BODY_ARMOUR && eq != EQ_SHIELD)
return (false);
+ const mon_inv_type mslot = equip_slot_to_mslot(eq);
// XXX: Very simplistic armour evaluation for the moment.
- if (const item_def *existing_armour = slot_item(EQ_BODY_ARMOUR))
+ if (const item_def *existing_armour = slot_item(eq))
{
if (!force && existing_armour->armour_rating() >= item.armour_rating())
return (false);
- if (!drop_item(MSLOT_ARMOUR, near))
+ if (!drop_item(mslot, near))
return (false);
}
- return pickup(item, MSLOT_ARMOUR, near);
+ return pickup(item, mslot, near);
}
bool monsters::pickup_weapon(item_def &item, int near, bool force)
@@ -3302,16 +3325,6 @@ void monsters::wield_melee_weapon(int near)
}
}
-static mon_inv_type equip_slot_to_mslot(equipment_type eq)
-{
- switch (eq)
- {
- case EQ_WEAPON: return MSLOT_WEAPON;
- case EQ_BODY_ARMOUR: return MSLOT_ARMOUR;
- default: return (NUM_MONSTER_SLOTS);
- }
-}
-
item_def *monsters::slot_item(equipment_type eq)
{
return mslot_item(equip_slot_to_mslot(eq));
@@ -3325,7 +3338,7 @@ item_def *monsters::mslot_item(mon_inv_type mslot) const
item_def *monsters::shield()
{
- return (NULL);
+ return (mslot_item(MSLOT_SHIELD));
}
std::string monsters::name(description_level_type desc) const
@@ -3465,12 +3478,11 @@ bool monsters::caught() const
int monsters::shield_bonus() const
{
- // XXX: Monsters don't actually get shields yet.
const item_def *shld = const_cast<monsters*>(this)->shield();
if (shld)
{
const int shld_c = property(*shld, PARM_AC);
- return (random2(shld_c + random2(hit_dice / 2)) / 2);
+ return (random2(1 + shld_c) + random2(hit_dice / 2));
}
return (-100);
}