From 5b618acbca35621d699dc4ba3064f2a3228a5131 Mon Sep 17 00:00:00 2001 From: j-p-e-g Date: Mon, 20 Aug 2007 12:23:38 +0000 Subject: Added throwing nets. These still need work, and thus are not for 0.3. Obviously. Summary: New item type MI_THROWING_NET. The enchantment of a net describes its state, i.e. whether it's brand-new or almost falling apart (happens at -8). New attribute ATTR_CAUGHT (for monsters ENCH_CAUGHT) that means the victim cannot move and instead struggles against the net until it manages to wriggle out of it (takes a while depending on size) or it is destroyed. Monsters can still use items and spells when trapped. New trap type TRAP_NET that currently is the only source of throwing nets, though Gladiators (and some types of hunters maybe?) should start with a few, and David suggested also allowing the creation of nets for shops. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2020 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/mon-util.cc | 161 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 1 deletion(-) (limited to 'crawl-ref/source/mon-util.cc') diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 08df90314e..dd2a7b36d0 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -1689,6 +1689,11 @@ bool mons_is_confused(const monsters *m) !mons_class_flag(m->type, M_CONFUSED)); } +bool mons_is_caught(const monsters *m) +{ + return (m->has_ench(ENCH_CAUGHT)); +} + bool mons_is_fleeing(const monsters *m) { return (m->behaviour == BEH_FLEE); @@ -1727,7 +1732,8 @@ bool mons_looks_distracted(const monsters *m) && !mons_friendly(m) && ((m->foe != MHITYOU && !mons_is_batty(m)) || mons_is_confused(m) - || mons_is_fleeing(m))); + || mons_is_fleeing(m) + || mons_is_caught(m))); } bool mons_should_fire(struct bolt &beam) @@ -1844,6 +1850,20 @@ bool ms_low_hitpoint_cast( const monsters *mon, spell_type monspell ) return (ret); } +// spells for a quick get-away +// currently only used to get out of a net +bool ms_quick_get_away( const monsters *mon, spell_type monspell ) +{ + switch (monspell) + { + case SPELL_TELEPORT_SELF: + case SPELL_BLINK: + return true; + default: + return false; + } +} + // Checks to see if a particular spell is worth casting in the first place. bool ms_waste_of_time( const monsters *mon, spell_type monspell ) { @@ -2708,6 +2728,11 @@ bool monsters::pickup_missile(item_def &item, int near, bool force) // much work for now. const item_def *miss = missiles(); + + // monster may not pick up trapping net + if (mons_is_caught(this) && item.sub_type == MI_THROWING_NET) + return (false); + if (miss && items_stack(*miss, item)) return (pickup(item, MSLOT_MISSILE, near)); @@ -3000,6 +3025,11 @@ bool monsters::backlit() const return (has_ench(ENCH_BACKLIGHT)); } +bool monsters::caught() const +{ + return (mons_is_caught(this)); +} + int monsters::shield_bonus() const { // XXX: Monsters don't actually get shields yet. @@ -3032,6 +3062,8 @@ int monsters::melee_evasion(const actor *act) const int evasion = ev; if (paralysed() || asleep() || one_chance_in(20)) evasion = 0; + else if (caught()) + evasion /= (body_size(PSIZE_BODY) + 2); else if (confused()) evasion /= 2; return (evasion); @@ -3629,6 +3661,11 @@ void monsters::remove_enchantment_effect(const mon_enchant &me, bool quiet) simple_monster_message(this, " is no longer rotting."); break; + case ENCH_CAUGHT: + if (!quiet) + simple_monster_message(this, " breaks free."); + break; + case ENCH_ABJ: case ENCH_SHORT_LIVED: add_ench( mon_enchant(ENCH_ABJ) ); @@ -3748,6 +3785,10 @@ void monsters::timeout_enchantments(int levels) blink(); break; + case ENCH_CAUGHT: + del_ench(i->first); + break; + default: break; } @@ -3850,6 +3891,121 @@ void monsters::apply_enchantment(const mon_enchant &me) decay_enchantment(me); break; + case ENCH_CAUGHT: + { + if (mons_is_paralysed(this) || this->behaviour == BEH_SLEEP) + break; + + int net, next; + for (net = igrd[x][y]; net != NON_ITEM; net = next) + { + next = mitm[net].link; + + if (mitm[net].base_type == OBJ_MISSILES + && mitm[net].sub_type == MI_THROWING_NET) + { + break; + } + } + + if (net == NON_ITEM) // really shouldn't happen! + { + del_ench(ENCH_CAUGHT); + break; + } + + // handled in handle_pickup + if (mons_itemuse(type) == MONUSE_EATS_ITEMS) + break; + + // the enchantment doubles as the durability of a net + // the more corroded it gets, the more easily it will break + int hold = mitm[net].plus; // this will usually be negative + int mon_size = body_size(PSIZE_BODY); + + // smaller monsters can escape more quickly + if (mon_size < random2(SIZE_BIG) // BIG = 5 + && !has_ench(ENCH_BERSERK)) + { + if (mons_near(this) && !player_monster_visible(this)) + mpr("Something wriggles in the net."); + else + simple_monster_message(this, " struggles to escape the net."); + + // confused monsters have trouble finding the exit + if (has_ench(ENCH_CONFUSION) && !one_chance_in(5)) + break; + + decay_enchantment(me, 2*(NUM_SIZE_LEVELS - mon_size) - hold); + + // frayed nets are easier to escape + if (mon_size <= -(hold-1)/2) + decay_enchantment(me, (NUM_SIZE_LEVELS - mon_size)); + } + else // large (and above) monsters always thrash the net and destroy it + { // e.g. ogre, large zombie (large); centaur, nage, hydra (big) + + if (mons_near(this) && !player_monster_visible(this)) + mpr("Something wriggles in the net."); + else + simple_monster_message(this, " struggles against the net."); + + // confused monsters more likely to struggle without result + if (has_ench(ENCH_CONFUSION) && one_chance_in(3)) + break; + + // nets get destroyed more quickly for larger monsters + // and if already strongly frayed + int damage = 0; + + // tiny: 1/6, little: 2/5, small: 3/4, medium and above: always + if (random2(SIZE_GIANT - mon_size) <= mon_size) + damage++; + + // extra damage for large (50%) and big (always) + if (mon_size == SIZE_BIG || mon_size == SIZE_LARGE && coinflip()) + damage++; + + // overall damage per struggle: + // tiny -> 1/6 + // little -> 2/5 + // small -> 3/4 + // medium -> 1 + // large -> 1,5 + // big -> 2 + + // extra damage if already damaged + if (random2(body_size(PSIZE_BODY) - hold + 1) >= 4) + damage++; + + // berserking doubles damage dealt + if (has_ench(ENCH_BERSERK)) + damage *= 2; + + mitm[net].plus -= damage; + + if (mitm[net].plus < -7) + { + if (mons_near(this)) + { + if (player_monster_visible(this)) + { + mprf("The net rips apart, and %s comes free!", + name(DESC_NOCAP_THE).c_str()); + } + else + { + mpr("All of a sudden the net rips apart!"); + } + } + dec_mitm_item_quantity( net, 1 ); + + del_ench(ENCH_CAUGHT, true); + } + + } + break; + } case ENCH_CONFUSION: if (!mons_class_flag(type, M_CONFUSED)) decay_enchantment(me); @@ -4386,6 +4542,9 @@ int mon_enchant::calc_duration(const monsters *mons, case ENCH_CONFUSION: cturn = 120 / modded_speed(mons, 5); break; + case ENCH_CAUGHT: + cturn = 90 / mod_speed(25, mons->speed); + break; case ENCH_POISON: cturn = 1000 * deg / mod_speed(125, mons->speed); break; -- cgit v1.2.3-54-g00ecf