summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/mstuff2.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/mstuff2.cc')
-rw-r--r--stone_soup/crawl-ref/source/mstuff2.cc1768
1 files changed, 0 insertions, 1768 deletions
diff --git a/stone_soup/crawl-ref/source/mstuff2.cc b/stone_soup/crawl-ref/source/mstuff2.cc
deleted file mode 100644
index d4460a0697..0000000000
--- a/stone_soup/crawl-ref/source/mstuff2.cc
+++ /dev/null
@@ -1,1768 +0,0 @@
-/*
- * File: mstuff2.cc
- * Summary: Misc monster related functions.
- * Written by: Linley Henzell
- *
- * Change History (most recent first):
- *
- * <5> 31 July 2000 JDJ Fixed mon_throw to use lnchType.
- * <4> 29 July 2000 JDJ Tweaked mons_throw so it doesn't index past
- * the end of the array when monsters don't have
- * a weapon equipped.
- * <3> 25 July 2000 GDL Fixed Manticores
- * <2> 28 July 2000 GDL Revised monster throwing
- * <1> -/--/-- LRH Created
- */
-
-#include "AppHdr.h"
-#include "mstuff2.h"
-
-#include <string>
-#include <string.h>
-#include <stdio.h>
-
-#include "externs.h"
-
-#include "beam.h"
-#include "debug.h"
-#include "effects.h"
-#include "itemname.h"
-#include "itemprop.h"
-#include "items.h"
-#include "misc.h"
-#include "monplace.h"
-#include "monstuff.h"
-#include "mon-util.h"
-#include "player.h"
-#include "spells2.h"
-#include "spells4.h"
-#include "spl-cast.h"
-#include "stuff.h"
-#include "view.h"
-#include "wpn-misc.h"
-
-static unsigned char monster_abjuration(int pow, bool test);
-
-// XXX: must fix species abils to not use duration 15
-// -- ummm ... who wrote this? {dlb}
-
-// NB: only works because grid location already verified
-// to be some sort of trap prior to function call: {dlb}
-void mons_trap(struct monsters *monster)
-{
- if (!is_trap_square(monster->x, monster->y))
- return;
-
- int temp_rand = 0; // probability determination {dlb}
-
- // single calculation permissible {dlb}
- bool monsterNearby = mons_near(monster);
-
- // new function call {dlb}
- int which_trap = trap_at_xy(monster->x, monster->y);
- if (which_trap == -1)
- return;
-
- bool trapKnown = (grd[monster->x][monster->y] != DNGN_UNDISCOVERED_TRAP);
- bool revealTrap = false; // more sophisticated trap uncovering {dlb}
- bool projectileFired = false; // <sigh> I had to do it, I swear {dlb}
- int damage_taken = -1; // must initialize at -1 for this f(x) {dlb}
-
- struct bolt beem;
-
-
- // flying monsters neatly avoid mechanical traps
- // and may actually exit this function early: {dlb}
- if (mons_flies(monster))
- {
- if (trap_category(env.trap[which_trap].type) == DNGN_TRAP_MECHANICAL)
- {
- if (trapKnown)
- simple_monster_message(monster, " flies safely over a trap.");
-
- return; // early return {dlb}
- }
- }
-
- //
- // Trap damage to monsters is not a function of level, beacuse they
- // are fairly stupid and tend to have fewer hp than players -- this
- // choice prevents traps from easily killing large monsters fairly
- // deep within the dungeon.
- //
- switch (env.trap[which_trap].type)
- {
- case TRAP_DART:
- projectileFired = true;
- strcpy(beem.beam_name, " dart");
- beem.damage = dice_def( 1, 4 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_DART;
- break;
- case TRAP_NEEDLE:
- projectileFired = true;
- strcpy(beem.beam_name, " needle");
- beem.damage = dice_def( 1, 0 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_NEEDLE;
- break;
- case TRAP_ARROW:
- projectileFired = true;
- strcpy(beem.beam_name, "n arrow");
- beem.damage = dice_def( 1, 7 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_ARROW;
- break;
- case TRAP_SPEAR:
- projectileFired = true;
- strcpy(beem.beam_name, " spear");
- beem.damage = dice_def( 1, 10 );
- beem.colour = OBJ_WEAPONS;
- beem.type = WPN_SPEAR;
- break;
- case TRAP_BOLT:
- projectileFired = true;
- strcpy(beem.beam_name, " bolt");
- beem.damage = dice_def( 1, 13 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_BOLT;
- break;
- case TRAP_AXE:
- projectileFired = true;
- strcpy(beem.beam_name, "n axe");
- beem.damage = dice_def( 1, 15 );
- beem.colour = OBJ_WEAPONS;
- beem.type = WPN_HAND_AXE;
- break;
- // teleport traps are *never* revealed through
- // the triggering action of a monster, as any
- // number of factors could have been in play: {dlb}
- case TRAP_TELEPORT:
- monster_teleport(monster, true);
- break;
- // amnesia traps do not affect monsters (yet) and
- // only monsters of normal+ IQ will direct a msg
- // to the player - also, *never* revealed: {dlb}
- case TRAP_AMNESIA:
- if (mons_intel(monster->type) > I_ANIMAL)
- simple_monster_message(monster,
- " seems momentarily disoriented.");
- break;
- // blade traps sometimes fail to trigger altogether,
- // resulting in an "early return" from this f(x) for
- // some - otherwise, blade *always* revealed: {dlb}
- case TRAP_BLADE:
- if (one_chance_in(5))
- {
- if (trapKnown)
- {
- simple_monster_message(monster,
- " fails to trigger a blade trap.");
- }
- return; // early return {dlb}
- }
- else if (random2(monster->evasion) > 8)
- {
- if (monsterNearby && !simple_monster_message(monster,
- " avoids a huge, swinging blade."))
- {
- mpr("A huge blade swings out!");
- }
-
- damage_taken = -1; // just to be certain {dlb}
- }
- else
- {
- if (monsterNearby)
- {
- strcpy(info, "A huge blade swings out");
-
- if (player_monster_visible( monster ))
- {
- strcat(info, " and slices into ");
- strcat(info, ptr_monam( monster, DESC_NOCAP_THE ));
- }
-
- strcat(info, "!");
- mpr(info);
- }
-
- damage_taken = 10 + random2avg(29, 2);
- damage_taken -= random2(1 + monster->armour_class);
-
- if (damage_taken < 0)
- damage_taken = 0;
- }
-
- revealTrap = true;
- break;
-
- // zot traps are out to get *the player*! Hostile monsters
- // benefit and friendly monsters suffer - such is life - on
- // rare occasion, the trap affects nearby players, triggering
- // an "early return" - zot traps are *never* revealed - instead,
- // enchantment messages serve as clues to the trap's presence: {dlb}
- case TRAP_ZOT:
- if (monsterNearby)
- {
- if (one_chance_in(5))
- {
- mpr("The power of Zot is invoked against you!");
- miscast_effect( SPTYP_RANDOM, 10 + random2(30),
- 75 + random2(100), 0, "the power of Zot" );
- return; // early return {dlb}
- }
- }
-
- // output triggering message to player, where appropriate: {dlb}
- if (!silenced(monster->x, monster->y)
- && !silenced(you.x_pos, you.y_pos))
- {
- if (monsterNearby)
- strcpy(info, "You hear a loud \"Zot\"!");
- else
- strcpy(info, "You hear a distant \"Zot\"!");
- mpr(info);
- }
-
- // determine trap effects upon monster, based upon
- // whether it is naughty or nice to the player: {dlb}
-
- // NB: beem[].colour values are mislabeled as colours (?) -
- // cf. mons_ench_f2() [which are also mislabeled] {dlb}
- temp_rand = random2(16);
-
- beem.thrower = KILL_MON; // probably unnecessary
- beem.aux_source = NULL;
-
- if (mons_friendly(monster))
- {
- beem.colour = ((temp_rand < 3) ? CYAN : //paralyze - 3 in 16
- (temp_rand < 7) ? RED // confuse - 4 in 16
- : BLACK); // slow - 9 in 16
- }
- else
- {
- beem.colour = ((temp_rand < 3) ? BLUE : //haste - 3 in 16 {dlb}
- (temp_rand < 7) ? MAGENTA //invis - 4 in 16 {dlb}
- : GREEN); // heal - 9 in 16 {dlb}
- }
-
- mons_ench_f2(monster, beem);
- damage_taken = 0; // just to be certain {dlb}
- break;
- }
-
-
- // go back and handle projectile traps: {dlb}
- bool apply_poison = false;
-
- if (projectileFired)
- {
- // projectile traps *always* revealed after "firing": {dlb}
- revealTrap = true;
-
- // determine whether projectile hits, calculate damage: {dlb}
- if (((20 + (you.your_level * 2)) * random2(200)) / 100
- >= monster->evasion)
- {
- damage_taken = roll_dice( beem.damage );
- damage_taken -= random2(1 + monster->armour_class);
-
- if (damage_taken < 0)
- damage_taken = 0;
-
- if (beem.colour == OBJ_MISSILES
- && beem.type == MI_NEEDLE
- && random2(100) < 50 - (3*monster->armour_class/2))
- {
- apply_poison = true;
- }
- }
- else
- {
- damage_taken = -1; // negative damage marks a miss
- }
-
- if (monsterNearby)
- {
- snprintf( info, INFO_SIZE, "A%s %s %s%s!",
- beem.beam_name,
- (damage_taken >= 0) ? "hits" : "misses",
- ptr_monam( monster, DESC_NOCAP_THE ),
- (damage_taken == 0) ? ", but does no damage" : "" );
-
- mpr(info);
- }
-
- if (apply_poison)
- poison_monster( monster, false );
-
- // generate "fallen" projectile, where appropriate: {dlb}
- if (random2(10) < 7)
- {
- beem.target_x = monster->x;
- beem.target_y = monster->y;
- itrap(beem, which_trap);
- }
- }
-
-
- // reveal undiscovered traps, where appropriate: {dlb}
- if (monsterNearby && !trapKnown && revealTrap)
- {
- grd[monster->x][monster->y] = trap_category(env.trap[which_trap].type);
- }
-
- // apply damage and handle death, where appropriate: {dlb}
- if (damage_taken > 0)
- {
- hurt_monster(monster, damage_taken);
-
- if (monster->hit_points < 1)
- {
- monster_die(monster, KILL_MISC, 0);
- monster->speed_increment = 1;
- }
- }
-
- return;
-} // end mons_trap()
-
-void mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
-{
- // always do setup. It might be done already, but it doesn't
- // hurt to do it again (cheap).
- setup_mons_cast(monster, pbolt, spell_cast);
-
- // single calculation permissible {dlb}
- bool monsterNearby = mons_near(monster);
-
- int sumcount = 0;
- int sumcount2;
- int summonik = 0;
- int duration = 0;
-
-#if DEBUG_DIAGNOSTICS
- snprintf( info, INFO_SIZE, "Mon #%d casts %s (#%d)", monster_index(monster),
- mons_spell_name( spell_cast ), spell_cast );
-
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- if (spell_cast == MS_HELLFIRE_BURST || spell_cast == MS_BRAIN_FEED
- || spell_cast == MS_SMITE || spell_cast == MS_MUTATION)
- { // etc.
- if (monster->foe == MHITYOU || monster->foe == MHITNOT)
- {
- if (monsterNearby)
- direct_effect( pbolt );
- return;
- }
-
- mons_direct_effect( pbolt, monster_index(monster) );
- return;
- }
-
- switch (spell_cast)
- {
- case MS_VAMPIRE_SUMMON:
- sumcount2 = 3 + random2(3) + monster->hit_dice / 5;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- int mons = MONS_GIANT_BAT;
-
- if (!one_chance_in(3))
- {
- switch (random2(4))
- {
- case 0:
- mons = MONS_ORANGE_RAT;
- break;
-
- case 1:
- mons = MONS_GREEN_RAT;
- break;
-
- case 2:
- mons = MONS_GREY_RAT;
- break;
-
- case 3:
- default:
- mons = MONS_RAT;
- break;
- }
- }
-
- create_monster( mons, ENCH_ABJ_V, SAME_ATTITUDE(monster),
- monster->x, monster->y, monster->foe, 250 );
- }
- return;
-
- case MS_LEVEL_SUMMON: // summon anything appropriate for level
- if (!mons_friendly(monster) && monsterNearby
- && monster_abjuration(1, true) > 0 && coinflip())
- {
- monster_abjuration( monster->hit_dice * 10, false );
- return;
- }
-
- sumcount2 = 1 + random2(4) + random2( monster->hit_dice / 7 + 1 );
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( RANDOM_MONSTER, ENCH_ABJ_V, SAME_ATTITUDE(monster),
- monster->x, monster->y, monster->foe, 250 );
- }
- return;
-
- case MS_FAKE_RAKSHASA_SUMMON:
- sumcount2 = (coinflip() ? 2 : 3);
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( MONS_RAKSHASA_FAKE, ENCH_ABJ_III,
- SAME_ATTITUDE(monster), monster->x, monster->y,
- monster->foe, 250 );
- }
- return;
-
- case MS_SUMMON_DEMON: // class 2-4 demons
- if (!mons_friendly(monster) && monsterNearby
- && monster_abjuration(1, true) > 0 && coinflip())
- {
- monster_abjuration(monster->hit_dice * 10, false);
- return;
- }
-
- sumcount2 = 1 + random2(2) + random2( monster->hit_dice / 10 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( summon_any_demon(DEMON_COMMON), duration,
- SAME_ATTITUDE(monster), monster->x, monster->y,
- monster->foe, 250 );
- }
- return;
-
- case MS_ANIMATE_DEAD:
- // see special handling in monstuff::handle_spell {dlb}
- animate_dead( 5 + random2(5), SAME_ATTITUDE(monster), monster->foe, 1 );
- return;
-
- case MS_SUMMON_DEMON_LESSER: // class 5 demons
- sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( summon_any_demon(DEMON_LESSER), duration,
- SAME_ATTITUDE(monster), monster->x, monster->y,
- monster->foe, 250 );
- }
- return;
-
- case MS_SUMMON_UFETUBUS:
- sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 5 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( MONS_UFETUBUS, duration, SAME_ATTITUDE(monster),
- monster->x, monster->y, monster->foe, 250 );
- }
- return;
-
- case MS_SUMMON_BEAST: // Geryon
- create_monster( MONS_BEAST, ENCH_ABJ_IV, SAME_ATTITUDE(monster),
- monster->x, monster->y, monster->foe, 250 );
- return;
-
- case MS_SUMMON_UNDEAD: // summon undead around player
- if (!mons_friendly(monster) && monsterNearby
- && monster_abjuration(1, true) > 0 && coinflip())
- {
- monster_abjuration( monster->hit_dice * 10, false );
- return;
- }
-
- sumcount2 = 2 + random2(2) + random2( monster->hit_dice / 4 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 5;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- do
- {
- summonik = random2(241); // hmmmm ... {dlb}
- }
- while (mons_class_holiness(summonik) != MH_UNDEAD);
-
- create_monster(summonik, duration, SAME_ATTITUDE(monster),
- you.x_pos, you.y_pos, monster->foe, 250);
- }
- return;
-
- case MS_TORMENT:
- if (!monsterNearby || mons_friendly(monster))
- return;
-
- simple_monster_message(monster, " calls on the powers of Hell!");
-
- torment(monster->x, monster->y);
- return;
-
- case MS_SUMMON_DEMON_GREATER:
- if (!mons_friendly(monster) && !monsterNearby &&
- monster_abjuration(1, true) > 0 && coinflip())
- {
- monster_abjuration(monster->hit_dice * 10, false);
- return;
- }
-
- sumcount2 = 1 + random2( monster->hit_dice / 10 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( summon_any_demon(DEMON_GREATER), duration,
- SAME_ATTITUDE(monster), monster->x, monster->y,
- monster->foe, 250 );
- }
- return;
-
- // Journey -- Added in Summon Lizards and Draconian
- case MS_SUMMON_LIZARDS:
- if (!mons_friendly( monster ) && !monsterNearby &&
- monster_abjuration( 1, true ) > 0 && coinflip())
- {
- monster_abjuration( monster->hit_dice * 10, false );
- return;
- }
-
- sumcount2 = 1 + random2(3) + random2( monster->hit_dice / 5 + 1 );
-
- duration = ENCH_ABJ_II + monster->hit_dice / 10;
- if (duration > ENCH_ABJ_VI)
- duration = ENCH_ABJ_VI;
-
- for (sumcount = 0; sumcount < sumcount2; sumcount++)
- {
- create_monster( rand_dragon( DRAGON_LIZARD ), duration,
- SAME_ATTITUDE(monster),
- monster->x, monster->y, monster->foe, 250 );
- }
- break;
-
- case MS_CANTRIP:
- // Monster spell of uselessness, just prints a message.
- // This spell exists so that some monsters with really strong
- // spells (ie orc priest) can be toned down a bit. -- bwr
- //
- // XXX: Needs expansion, and perhaps different priest/mage flavours.
- switch (random2(7))
- {
- case 0:
- simple_monster_message( monster, " glows brightly for a moment.",
- MSGCH_MONSTER_ENCHANT );
- break;
- case 1:
- mpr( "You feel troubled." );
- break;
- case 2:
- mpr( "You feel a wave of unholy energy pass over you." );
- break;
- case 3:
- simple_monster_message( monster, " looks stronger.",
- MSGCH_MONSTER_ENCHANT );
- break;
- case 4:
- simple_monster_message( monster, " becomes somewhat translucent.",
- MSGCH_MONSTER_ENCHANT );
- break;
- case 5:
- simple_monster_message( monster, "'s eyes start to glow.",
- MSGCH_MONSTER_ENCHANT );
- break;
- case 6:
- default:
- if (one_chance_in(20))
- mpr( "You resist (whatever that was supposed to do)." );
- else
- mpr( "You resist." );
- break;
- }
- return;
- }
-
- fire_beam( pbolt );
-} // end mons_cast()
-
-
-/*
- * setup bolt structure for monster spell casting.
- *
- */
-
-void setup_mons_cast(struct monsters *monster, struct bolt &pbolt, int spell_cast)
-{
- // always set these -- used by things other than fire_beam()
- pbolt.ench_power = 12 * monster->hit_dice;
-
- if (spell_cast == MS_TELEPORT)
- pbolt.ench_power = 2000;
- else if (spell_cast == MS_PAIN) // this is cast by low HD monsters
- pbolt.ench_power *= 2;
-
- pbolt.beam_source = monster_index(monster);
-
- // set bolt type
- if (spell_cast == MS_HELLFIRE_BURST
- || spell_cast == MS_BRAIN_FEED
- || spell_cast == MS_SMITE || spell_cast == MS_MUTATION)
- { // etc.
- switch (spell_cast)
- {
- case MS_HELLFIRE_BURST:
- pbolt.type = DMNBM_HELLFIRE;
- break;
- case MS_BRAIN_FEED:
- pbolt.type = DMNBM_BRAIN_FEED;
- break;
- case MS_SMITE:
- pbolt.type = DMNBM_SMITING;
- break;
- case MS_MUTATION:
- pbolt.type = DMNBM_MUTATION;
- break;
- }
- return;
- }
-
- // the below are no-ops since they don't involve direct_effect,
- // fire_tracer, or beam.
- switch (spell_cast)
- {
- case MS_VAMPIRE_SUMMON:
- case MS_LEVEL_SUMMON: // summon anything appropriate for level
- case MS_FAKE_RAKSHASA_SUMMON:
- case MS_SUMMON_DEMON:
- case MS_ANIMATE_DEAD:
- case MS_SUMMON_DEMON_LESSER:
- case MS_SUMMON_UFETUBUS:
- case MS_SUMMON_BEAST: // Geryon
- case MS_SUMMON_UNDEAD: // summon undead around player
- case MS_SUMMON_LIZARDS:
- case MS_TORMENT:
- case MS_SUMMON_DEMON_GREATER:
- case MS_CANTRIP:
- return;
- default:
- break;
- }
-
- // Need to correct this for power of spellcaster
- int power = 12 * monster->hit_dice;
-
- struct bolt theBeam = mons_spells(spell_cast, power);
-
- pbolt.colour = theBeam.colour;
- pbolt.range = theBeam.range;
- pbolt.rangeMax = theBeam.rangeMax;
- pbolt.hit = theBeam.hit;
- pbolt.damage = theBeam.damage;
- pbolt.ench_power = theBeam.ench_power;
- pbolt.type = theBeam.type;
- pbolt.flavour = theBeam.flavour;
- pbolt.thrower = theBeam.thrower;
- pbolt.aux_source = NULL;
- strcpy( pbolt.beam_name, theBeam.beam_name );
- pbolt.is_beam = theBeam.is_beam;
- pbolt.source_x = monster->x;
- pbolt.source_y = monster->y;
- pbolt.is_tracer = false;
-
- if (pbolt.beam_name[0] && pbolt.beam_name[0] != '0')
- pbolt.aux_source = pbolt.beam_name;
- else
- pbolt.aux_source = NULL;
-
- if (spell_cast == MS_HASTE
- || spell_cast == MS_INVIS
- || spell_cast == MS_HEAL || spell_cast == MS_TELEPORT)
- {
- pbolt.target_x = monster->x;
- pbolt.target_y = monster->y;
- }
-} // end setup_mons_cast()
-
-
-void monster_teleport(struct monsters *monster, bool instan)
-{
- if (!instan)
- {
- if (mons_del_ench(monster, ENCH_TP_I, ENCH_TP_IV))
- {
- simple_monster_message(monster, " seems more stable.");
- }
- else
- mons_add_ench(monster, (coinflip() ? ENCH_TP_III : ENCH_TP_IV ));
-
- return;
- }
-
- simple_monster_message(monster, " disappears!");
-
- // pick the monster up
- mgrd[monster->x][monster->y] = NON_MONSTER;
-
- char ogrid = monster_habitat(monster->type);
-
- int newx, newy;
- while(true)
- {
- newx = 10 + random2(GXM - 20);
- newy = 10 + random2(GYM - 20);
-
- // don't land on top of another monster
- if (mgrd[newx][newy] != NON_MONSTER)
- continue;
-
- // monsters going to the same habitat
- if (ogrid == grd[newx][newy])
- break;
-
- // DEEP_WATER monsters can be teleported to SHALLOW_WATER
- if (ogrid == DNGN_DEEP_WATER && grd[newx][newy] == DNGN_SHALLOW_WATER)
- break;
- }
-
- monster->x = newx;
- monster->y = newy;
-
- mgrd[monster->x][monster->y] = monster_index(monster);
-
- /* Mimics change form/colour when t'ported */
- if (mons_is_mimic( monster->type ))
- {
- monster->type = MONS_GOLD_MIMIC + random2(5);
- monster->number = get_mimic_colour( monster );
- }
-} // end monster_teleport()
-
-void setup_dragon(struct monsters *monster, struct bolt &pbolt)
-{
- const int type = (mons_genus( monster->type ) == MONS_DRACONIAN)
- ? draco_subspecies( monster ) : monster->type;
- int scaling = 100;
-
- strcpy(pbolt.beam_name, ptr_monam( monster, DESC_PLAIN ));
-
- switch (type)
- {
- case MONS_FIREDRAKE:
- case MONS_HELL_HOUND:
- case MONS_DRAGON:
- case MONS_LINDWURM:
- case MONS_XTAHUA:
- strcat(pbolt.beam_name, "'s blast of flame");
- pbolt.flavour = BEAM_FIRE;
- pbolt.colour = RED;
- pbolt.aux_source = "blast of fiery breath";
- break;
-
- case MONS_ICE_DRAGON:
- strcat(pbolt.beam_name, "'s blast of cold");
- pbolt.flavour = BEAM_COLD;
- pbolt.colour = WHITE;
- pbolt.aux_source = "blast of icy breath";
- break;
-
- case MONS_RED_DRACONIAN:
- snprintf( pbolt.beam_name, ITEMNAME_SIZE, "%s's searing breath",
- ptr_monam( monster, DESC_PLAIN ) );
-#ifdef DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "bolt name: '%s'", pbolt.beam_name );
-#endif
- pbolt.flavour = BEAM_FIRE;
- pbolt.colour = RED;
- pbolt.aux_source = "blast of searing breath";
- scaling = 65;
- break;
-
- case MONS_WHITE_DRACONIAN:
- snprintf( pbolt.beam_name, ITEMNAME_SIZE, "%s's chilling breath",
- ptr_monam( monster, DESC_PLAIN ) );
-#ifdef DEBUG_DIAGNOSTICS
- mprf( MSGCH_DIAGNOSTICS, "bolt name: '%s'", pbolt.beam_name );
-#endif
- pbolt.flavour = BEAM_COLD;
- pbolt.colour = WHITE;
- pbolt.aux_source = "blast of chilling breath";
- scaling = 65;
- break;
-
- default:
- DEBUGSTR("Bad monster class in setup_dragon()");
- break;
- }
-
- pbolt.range = 4;
- pbolt.rangeMax = 13;
- pbolt.damage = dice_def( 3, (monster->hit_dice * 2) );
- pbolt.damage.size = scaling * pbolt.damage.size / 100;
- pbolt.type = SYM_ZAP;
- pbolt.hit = 30;
- pbolt.beam_source = monster_index(monster);
- pbolt.thrower = KILL_MON;
- pbolt.is_beam = true;
-} // end setup_dragon();
-
-void setup_generic_throw(struct monsters *monster, struct bolt &pbolt)
-{
- pbolt.range = 9;
- pbolt.rangeMax = 9;
- pbolt.beam_source = monster_index(monster);
-
- pbolt.type = SYM_MISSILE;
- pbolt.flavour = BEAM_MISSILE;
- pbolt.thrower = KILL_MON_MISSILE;
- pbolt.aux_source = NULL;
- pbolt.is_beam = false;
-}
-
-// decide if something is launched or thrown
-// pass -1 for launcher class & 0 for type if no weapon is weilded
-
-void throw_type( int lnchClass, int lnchType, int wepClass, int wepType,
- bool &launched, bool &thrown )
-{
- if (wepClass == OBJ_MISSILES
- && lnchClass == OBJ_WEAPONS
- && launches_things(lnchType) && wepType == launched_by(lnchType))
- {
- launched = true;
- }
-
- if (wepClass == OBJ_WEAPONS)
- {
- if (wepType == WPN_DAGGER || wepType == WPN_HAND_AXE || wepType == WPN_SPEAR)
- {
- thrown = true;
- }
- }
-
- if (wepClass == OBJ_MISSILES)
- {
- if (wepType == MI_DART || wepType == MI_STONE || wepType == MI_LARGE_ROCK)
- {
- thrown = true;
- }
- }
-
- // launched overrides thrown
- if (launched == true)
- thrown = false;
-}
-
-bool mons_throw(struct monsters *monster, struct bolt &pbolt, int hand_used)
-{
- // this was assumed during cleanup down below:
- ASSERT( hand_used == monster->inv[MSLOT_MISSILE] );
-
- // XXX: ugly hack, but avoids adding dynamic allocation to this code
- static char throw_buff[ ITEMNAME_SIZE ];
-
- int baseHit = 0, baseDam = 0; // from thrown or ammo
- int ammoHitBonus = 0, ammoDamBonus = 0; // from thrown or ammo
- int lnchHitBonus = 0, lnchDamBonus = 0; // special add from launcher
- int exHitBonus = 0, exDamBonus = 0; // 'extra' bonus from skill/dex/str
-
- int hitMult = 0;
- int damMult = 0;
-
- bool launched = false; // item is launched
- bool thrown = false; // item is sensible thrown item
-
- // some initial convenience & initializations
- int wepClass = mitm[hand_used].base_type;
- int wepType = mitm[hand_used].sub_type;
-
- int weapon = monster->inv[MSLOT_WEAPON];
-
- int lnchClass = (weapon != NON_ITEM) ? mitm[weapon].base_type : -1;
- int lnchType = (weapon != NON_ITEM) ? mitm[weapon].sub_type : 0;
-
- item_def item = mitm[hand_used]; // copy changed for venom launchers
- item.quantity = 1;
-
- pbolt.range = 9;
- pbolt.beam_source = monster_index(monster);
-
- pbolt.type = SYM_MISSILE;
- pbolt.colour = item.colour;
- pbolt.flavour = BEAM_MISSILE;
- pbolt.thrower = KILL_MON_MISSILE;
- pbolt.aux_source = NULL;
-
- // figure out if we're thrown or launched
- throw_type( lnchClass, lnchType, wepClass, wepType, launched, thrown );
-
- // extract launcher bonuses due to magic
- if (launched)
- {
- lnchHitBonus = mitm[ weapon ].plus;
- lnchDamBonus = mitm[ weapon ].plus2;
- }
-
- // extract weapon/ammo bonuses due to magic
- ammoHitBonus = item.plus;
- ammoDamBonus = item.plus2;
-
- if (thrown)
- {
- // Darts are easy.
- if (wepClass == OBJ_MISSILES && wepType == MI_DART)
- {
- baseHit = 5;
- hitMult = 40;
- damMult = 25;
- }
- else
- {
- baseHit = 0;
- hitMult = 30;
- damMult = 25;
- }
-
- baseDam = property( item, PWPN_DAMAGE );
-
- if (wepClass == OBJ_MISSILES) // throw missile
- // ammo damage needs adjusting here - OBJ_MISSILES
- // don't get separate tohit/damage bonuses!
- ammoDamBonus = ammoHitBonus;
-
- // give monster "skill" bonuses based on HD
- exHitBonus = (hitMult * monster->hit_dice) / 10 + 1;
- exDamBonus = (damMult * monster->hit_dice) / 10 + 1;
- }
-
- if (launched)
- {
- switch (lnchType)
- {
- case WPN_BLOWGUN:
- baseHit = 2;
- hitMult = 60;
- damMult = 0;
- lnchDamBonus = 0;
- break;
- case WPN_BOW:
- case WPN_LONGBOW:
- baseHit = 0;
- hitMult = 60;
- damMult = 35;
- // monsters get half the launcher damage bonus,
- // which is about as fair as I can figure it.
- lnchDamBonus = (lnchDamBonus + 1) / 2;
- break;
- case WPN_CROSSBOW:
- baseHit = 4;
- hitMult = 70;
- damMult = 30;
- break;
- case WPN_HAND_CROSSBOW:
- baseHit = 2;
- hitMult = 50;
- damMult = 20;
- break;
- case WPN_SLING:
- baseHit = 1;
- hitMult = 40;
- damMult = 20;
- // monsters get half the launcher damage bonus,
- // which is about as fair as I can figure it.
- lnchDamBonus /= 2;
- break;
- }
-
- baseDam = property( item, PWPN_DAMAGE );
-
- // missiles don't have pluses2; use hit bonus
- ammoDamBonus = ammoHitBonus;
-
- exHitBonus = (hitMult * monster->hit_dice) / 10 + 1;
- exDamBonus = (damMult * monster->hit_dice) / 10 + 1;
-
- // elven bow w/ elven arrow, also orcish
- if (get_equip_race( mitm[monster->inv[MSLOT_WEAPON]] )
- == get_equip_race( mitm[monster->inv[MSLOT_MISSILE]] ))
- {
- baseHit++;
- baseDam++;
-
- if (get_equip_race(mitm[monster->inv[MSLOT_WEAPON]]) == ISFLAG_ELVEN)
- pbolt.hit++;
- }
-
- // monsters no longer gain unfair advantages with weapons of fire/ice
- // and incorrect ammo. They now have same restriction as players.
-
- const int bow_brand = get_weapon_brand(mitm[monster->inv[MSLOT_WEAPON]]);
-
- const int ammo_brand = get_ammo_brand( item );
-
- bool poison = (ammo_brand == SPMSL_POISONED
- || ammo_brand == SPMSL_POISONED_II);
-
- // POISON brand launchers poison ammo
- if (bow_brand == SPWPN_VENOM && ammo_brand == SPMSL_NORMAL)
- set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );
-
-
- // WEAPON or AMMO of FIRE
- if ((bow_brand == SPWPN_FLAME || ammo_brand == SPMSL_FLAME)
- && bow_brand != SPWPN_FROST && ammo_brand != SPMSL_ICE)
- {
- baseHit += 2;
- exDamBonus += 6;
- pbolt.flavour = BEAM_FIRE;
- strcpy(pbolt.beam_name, "bolt of ");
-
- if (poison)
- strcat(pbolt.beam_name, "poison ");
-
- strcat(pbolt.beam_name, "flame");
- pbolt.colour = RED;
- pbolt.type = SYM_ZAP;
- }
-
- // WEAPON or AMMO of FROST
- if ((bow_brand == SPWPN_FROST || ammo_brand == SPMSL_ICE)
- && bow_brand != SPWPN_FLAME && ammo_brand != SPMSL_FLAME)
- {
- baseHit += 2;
- exDamBonus += 6;
- pbolt.flavour = BEAM_COLD;
- strcpy(pbolt.beam_name, "bolt of ");
-
- if (poison)
- strcat(pbolt.beam_name, "poison ");
-
- strcat(pbolt.beam_name, "frost");
- pbolt.colour = WHITE;
- pbolt.type = SYM_ZAP;
- }
-
- // Note: we already have 10 energy taken off. -- bwr
- if (lnchType == WPN_CROSSBOW)
- monster->speed_increment += ((bow_brand == SPWPN_SPEED) ? 4 : -2);
- else if (bow_brand == SPWPN_SPEED)
- monster->speed_increment += 5;
- }
-
- // monster intelligence bonus
- if (mons_intel(monster->type) == I_HIGH)
- exHitBonus += 10;
-
- // now, if a monster is, for some reason, throwing something really
- // stupid, it will have baseHit of 0 and damage of 0. Ah well.
- strcpy(info, ptr_monam( monster, DESC_CAP_THE) );
-
- strcat(info, (launched) ? " shoots " : " throws ");
-
- if (strlen(pbolt.beam_name) > 0)
- {
- strcat(info, "a ");
- strcat(info, pbolt.beam_name);
- }
- else
- {
- // build shoot message
- char str_pass[ ITEMNAME_SIZE ];
- item_name( item, DESC_NOCAP_A, str_pass );
- strcat(info, str_pass);
-
- // build beam name
- item_name( item, DESC_PLAIN, str_pass );
- strcpy(pbolt.beam_name, str_pass);
- }
-
- strcat(info, ".");
- mpr(info);
-
-
- if (launched)
- {
- snprintf( throw_buff, sizeof(throw_buff), "Shot with a%s %s by %s",
- (is_vowel(pbolt.beam_name[0]) ? "n" : ""), pbolt.beam_name,
- ptr_monam( monster, DESC_NOCAP_A ) );
- }
- else
- {
- snprintf( throw_buff, sizeof(throw_buff), "Hit by a%s %s thrown by %s",
- (is_vowel(pbolt.beam_name[0]) ? "n" : ""), pbolt.beam_name,
- ptr_monam( monster, DESC_NOCAP_A ) );
- }
-
- pbolt.aux_source = throw_buff;
-
- // add everything up.
- pbolt.hit = baseHit + random2avg(exHitBonus, 2) + ammoHitBonus;
- pbolt.damage = dice_def( 1, baseDam + random2avg(exDamBonus, 2) + ammoDamBonus );
-
- if (launched)
- {
- pbolt.damage.size += lnchDamBonus;
- pbolt.hit += lnchHitBonus;
- }
- scale_dice(pbolt.damage);
-
- // decrease inventory
- fire_beam( pbolt, &item );
-
- if (dec_mitm_item_quantity( hand_used, 1 ))
- monster->inv[MSLOT_MISSILE] = NON_ITEM;
-
-
- return (true);
-} // end mons_throw()
-
-// should really do something about mons_hit, but can't be bothered
-void spore_goes_pop(struct monsters *monster)
-{
- struct bolt beam;
- int type = monster->type;
-
- if (monster == NULL)
- return;
-
- beam.is_tracer = false;
- beam.is_explosion = true;
- beam.beam_source = monster_index(monster);
- beam.type = SYM_BURST;
- beam.target_x = monster->x;
- beam.target_y = monster->y;
- beam.thrower = KILL_MON; // someone else's explosion
- beam.aux_source = NULL;
-
- if (type == MONS_GIANT_SPORE)
- {
- beam.flavour = BEAM_SPORE;
- strcpy(beam.beam_name, "explosion of spores");
- beam.colour = LIGHTGREY;
- beam.damage = dice_def( 3, 15 );
- beam.ex_size = 2;
- strcpy( info, "The giant spore explodes!" );
- }
- else
- {
- beam.flavour = BEAM_ELECTRICITY;
- strcpy(beam.beam_name, "blast of lightning");
- beam.colour = LIGHTCYAN;
- beam.damage = dice_def( 3, 20 );
- beam.ex_size = coinflip() ? 3 : 2;
- strcpy( info, "The ball lightning explodes!" );
- }
-
- if (mons_near(monster))
- {
- viewwindow(1, false);
- mpr( info );
- }
-
- explosion(beam);
-} // end spore_goes_pop()
-
-bolt mons_spells( int spell_cast, int power )
-{
- ASSERT(power > 0);
-
- bolt beam;
-
- strcpy(beam.beam_name, "****"); // initialize to some bogus values so we can catch problems
- beam.colour = 1000;
- beam.range = beam.rangeMax = 8;
- beam.hit = -1;
- beam.damage = dice_def( 1, 0 );
- beam.ench_power = -1;
- beam.type = -1;
- beam.flavour = -1;
- beam.thrower = -1;
- beam.is_beam = false;
- beam.is_explosion = false;
-
- switch (spell_cast)
- {
- case MS_MMISSILE:
- beam.colour = LIGHTMAGENTA; //inv_colour [throw_2];
- strcpy(beam.beam_name, "magic dart"); // inv_name [throw_2]);
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 4 + (power / 100) );
- beam.hit = 1500;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
- break;
-
- case MS_FLAME:
- beam.colour = RED;
- strcpy(beam.beam_name, "puff of flame");
- beam.range = 6;
- beam.rangeMax = 10;
-
- // should this be the same as magic missile?
- // No... magic missile is special in that it has a really
- // high to-hit value, so these should do more damage -- bwr
- beam.damage = dice_def( 3, 5 + (power / 40) );
-
- beam.hit = 60;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_FIRE;
- beam.is_beam = false;
- break;
-
- case MS_FROST:
- beam.colour = WHITE;
- strcpy(beam.beam_name, "puff of frost");
- beam.range = 6;
- beam.rangeMax = 10;
-
- // should this be the same as magic missile?
- // see MS_FLAME -- bwr
- beam.damage = dice_def( 3, 5 + (power / 40) );
-
- beam.hit = 60;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_COLD;
- beam.is_beam = false;
- break;
-
- case MS_PARALYSIS:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_PARALYSIS;
- beam.thrower = KILL_MON_MISSILE;
- beam.is_beam = true;
- break;
-
- case MS_SLOW:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_SLOW;
- beam.thrower = KILL_MON_MISSILE;
- beam.is_beam = true;
- break;
-
- case MS_HASTE: // (self)
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_HASTE;
- beam.thrower = KILL_MON_MISSILE;
- beam.is_beam = true;
- break;
-
- case MS_CONFUSE:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_CONFUSION;
- beam.thrower = KILL_MON_MISSILE;
- beam.is_beam = true;
- break;
-
- case MS_VENOM_BOLT:
- strcpy(beam.beam_name, "bolt of poison");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 6 + power / 13 );
- beam.colour = LIGHTGREEN;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_POISON;
- beam.hit = 7 + random2(power) / 80;
- beam.is_beam = true;
- break;
-
- case MS_POISON_ARROW:
- strcpy( beam.beam_name, "poison arrow" );
- beam.damage = dice_def( 4, 5 + power / 12 );
- beam.colour = LIGHTGREEN;
- beam.type = SYM_MISSILE;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_POISON_ARROW;
- beam.hit = 40 + power / 5;
- beam.range = beam.rangeMax = 8;
- break;
-
- case MS_FIRE_BOLT:
- strcpy(beam.beam_name, "bolt of fire");
- beam.range = 4;
- beam.rangeMax = 13;
- beam.damage = dice_def( 3, 8 + power / 11 );
- beam.colour = RED;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_FIRE;
- beam.hit = 8 + random2(power) / 80; // hit
- beam.is_beam = true;
- break;
-
- case MS_COLD_BOLT:
- strcpy(beam.beam_name, "bolt of cold");
- beam.range = 4;
- beam.rangeMax = 13;
- beam.damage = dice_def( 3, 8 + power / 11 );
- beam.colour = WHITE;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_COLD;
- beam.hit = 8 + random2(power) / 80; // hit
- beam.is_beam = true;
- break;
-
- case MS_LIGHTNING_BOLT:
- strcpy(beam.beam_name, "bolt of lightning");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 10 + power / 9 );
- beam.colour = LIGHTCYAN;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_ELECTRICITY;
- beam.hit = 10 + random2(power) / 40;
- beam.is_beam = true;
- break;
-
- case MS_INVIS:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_INVISIBILITY;
- beam.thrower = KILL_MON;
- beam.is_beam = true;
- break;
-
- case MS_FIREBALL:
- beam.colour = RED;
- strcpy(beam.beam_name, "fireball");
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 7 + power / 10 );
- beam.hit = 40;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_FIRE; // why not BEAM_FIRE? {dlb}
- beam.is_beam = false;
- beam.is_explosion = true;
- break;
-
- case MS_HEAL:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_HEALING;
- beam.thrower = KILL_MON;
- beam.hit = 5 + (power / 5);
- beam.is_beam = true;
- break;
-
- case MS_TELEPORT:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_TELEPORT; // 6 is used by digging
- beam.thrower = KILL_MON;
- beam.is_beam = true;
- break;
-
- case MS_TELEPORT_OTHER:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_TELEPORT; // 6 is used by digging
- beam.thrower = KILL_MON;
- beam.is_beam = true;
- break;
-
- case MS_BLINK:
- beam.is_beam = false;
- break;
-
- case MS_CRYSTAL_SPEAR: // was splinters
- strcpy(beam.beam_name, "crystal spear");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 12 + power / 10 );
- beam.colour = WHITE;
- beam.type = SYM_MISSILE;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_MMISSILE;
- beam.hit = 6; // + random2(power) / 10;
- beam.is_beam = false;
- break;
-
- case MS_DIG:
- strcpy(beam.beam_name, "0");
- beam.range = 3;
- beam.rangeMax = 7 + random2(power) / 10;
- beam.type = 0;
- beam.flavour = BEAM_DIGGING;
- beam.thrower = KILL_MON;
- beam.is_beam = true;
- break;
-
- case MS_NEGATIVE_BOLT: // negative energy
- strcpy(beam.beam_name, "bolt of negative energy");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 6 + power / 13 );
- beam.colour = DARKGREY;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_NEG;
- beam.hit = 7 + random2(power) / 80;
- beam.is_beam = true;
- break;
-
- // 20, 21 are used
-
- case MS_ORB_ENERGY: // mystic blast
- beam.colour = LIGHTMAGENTA;
- strcpy(beam.beam_name, "orb of energy");
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 7 + (power / 14) );
- beam.hit = 10 + (power / 20);
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
- break;
-
- // 23 is brain feed
-
- case MS_STEAM_BALL:
- beam.colour = LIGHTGREY;
- strcpy(beam.beam_name, "ball of steam");
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 6 );
- beam.hit = 11;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_FIRE; // fire - I think this is appropriate
- beam.is_beam = false;
- break;
-
- // 27 is summon devils
- // 28 is animate dead
-
- case MS_PAIN:
- strcpy(beam.beam_name, "0");
- beam.range = 7;
- beam.rangeMax = 14;
- beam.type = 0;
- beam.flavour = BEAM_PAIN; // pain
- beam.thrower = KILL_MON;
- // beam.damage = dice_def( 1, 50 );
- beam.damage = dice_def( 1, 7 + (power / 20) );
- beam.ench_power = 50;
- beam.is_beam = true;
- break;
-
- // 30 is smiting
-
- case MS_STICKY_FLAME:
- beam.colour = RED;
- strcpy(beam.beam_name, "sticky flame");
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 3 + power / 50 );
- beam.hit = 8 + power / 15;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_FIRE;
- beam.is_beam = false;
- break;
-
- case MS_POISON_BLAST: // demon
- strcpy(beam.beam_name, "blast of poison");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 3 + power / 25 );
- beam.colour = LIGHTGREEN;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_POISON;
- beam.hit = 7 + random2(power) / 80;
- beam.is_beam = true;
- beam.is_big_cloud = true;
- break;
-
- case MS_PURPLE_BLAST: // purple bang thing
- beam.colour = LIGHTMAGENTA;
- strcpy(beam.beam_name, "orb of energy");
- beam.range = 6;
- beam.rangeMax = 10;
- beam.damage = dice_def( 3, 10 + power / 15 );
- beam.hit = 10 + power / 20;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
- beam.is_explosion = true;
- break;
-
- case MS_ENERGY_BOLT: // eye of devastation
- beam.colour = YELLOW;
- strcpy(beam.beam_name, "bolt of energy");
- beam.range = 9;
- beam.rangeMax = 23;
- beam.damage = dice_def( 3, 20 );
- beam.hit = 9;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_NUKE; // a magical missile which destroys walls
- beam.is_beam = true;
- break;
-
- case MS_STING: // sting
- beam.colour = GREEN;
- strcpy(beam.beam_name, "sting");
- beam.range = 8;
- beam.rangeMax = 12;
- beam.damage = dice_def( 1, 6 + power / 25 );
- beam.hit = 60;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_POISON;
- beam.is_beam = false;
- break;
-
- case MS_IRON_BOLT:
- beam.colour = LIGHTCYAN;
- strcpy(beam.beam_name, "iron bolt");
- beam.range = 4;
- beam.rangeMax = 8;
- beam.damage = dice_def( 3, 8 + (power / 9) );
- beam.hit = 6 + (power / 25);
- beam.type = SYM_MISSILE;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE; // similarly unresisted thing
- beam.is_beam = false;
- break;
-
- case MS_STONE_ARROW:
- beam.colour = LIGHTGREY;
- strcpy(beam.beam_name, "stone arrow");
- beam.range = 8;
- beam.rangeMax = 12;
- beam.damage = dice_def( 3, 5 + (power / 10) );
- beam.hit = 5 + power / 47;
- beam.type = SYM_MISSILE;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE; // similarly unresisted thing
- beam.is_beam = false;
- break;
-
- case MS_POISON_SPLASH:
- beam.colour = GREEN;
- strcpy(beam.beam_name, "splash of poison");
- beam.range = 5;
- beam.rangeMax = 10;
- beam.damage = dice_def( 1, 4 + power / 10 );
- beam.hit = 9;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_POISON;
- beam.is_beam = false;
- break;
-
- case MS_DISINTEGRATE:
- strcpy(beam.beam_name, "0");
- beam.range = 7;
- beam.rangeMax = 14;
- beam.type = 0;
- beam.flavour = BEAM_DISINTEGRATION;
- beam.thrower = KILL_MON;
- beam.ench_power = 50;
- // beam.hit = 30 + (power / 10);
- beam.damage = dice_def( 1, 30 + (power / 10) );
- beam.is_beam = true;
- break;
-
- case MS_MARSH_GAS: // swamp drake
- strcpy(beam.beam_name, "foul vapour");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 2 + power / 25 );
- beam.colour = GREEN;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_POISON;
- beam.hit = 7 + random2(power) / 80;
- beam.is_beam = true;
- beam.is_big_cloud = true;
- break;
-
- case MS_MIASMA: // death drake
- strcpy( beam.beam_name, "foul vapour" );
- beam.damage = dice_def( 3, 5 + power / 24 );
- beam.colour = DARKGREY;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_MIASMA;
- beam.hit = 80 + power / 20;
- beam.is_beam = true;
- beam.is_big_cloud = true;
- beam.range = beam.rangeMax = 8;
- break;
-
- case MS_QUICKSILVER_BOLT: // Quicksilver dragon
- beam.colour = random_colour();
- strcpy(beam.beam_name, "bolt of energy");
- beam.range = 9;
- beam.rangeMax = 23;
- beam.damage = dice_def( 3, 25 );
- beam.hit = 9;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON_MISSILE;
- beam.flavour = BEAM_MMISSILE;
- beam.is_beam = false;
- break;
-
- case MS_HELLFIRE: // fiend's hellfire
- strcpy(beam.beam_name, "hellfire");
- beam.colour = RED;
- beam.range = 4;
- beam.rangeMax = 13;
- beam.damage = dice_def( 3, 25 );
- beam.hit = 20;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_HELLFIRE;
- beam.is_beam = true;
- beam.is_explosion = true;
- break;
-
- case MS_METAL_SPLINTERS:
- strcpy(beam.beam_name, "spray of metal splinters");
- beam.range = 7;
- beam.rangeMax = 16;
- beam.damage = dice_def( 3, 20 + power / 20 );
- beam.colour = CYAN;
- beam.type = SYM_ZAP;
- beam.thrower = KILL_MON;
- beam.flavour = BEAM_FRAG;
- beam.hit = 15 + random2(power) / 50;
- beam.is_beam = true;
- break;
-
- case MS_BANISHMENT:
- strcpy(beam.beam_name, "0");
- beam.range = 5;
- beam.rangeMax = 9;
- beam.type = 0;
- beam.flavour = BEAM_BANISH;
- beam.thrower = KILL_MON_MISSILE;
- beam.is_beam = true;
- break;
-
- case MS_BLINK_OTHER:
- strcpy(beam.beam_name, "0");
- beam.type = 0;
- beam.flavour = BEAM_BLINK;
- beam.thrower = KILL_MON;
- beam.is_beam = true;
- beam.is_enchant = true;
- beam.range = 8;
- beam.rangeMax = 8;
- break;
-
- default:
- DEBUGSTR("Unknown spell");
- }
-
- return (beam);
-} // end mons_spells()
-
-static unsigned char monster_abjuration(int pow, bool test)
-{
-
- unsigned char result = 0;
- struct monsters *monster = 0; // NULL {dlb}
-
- if (!test)
- mpr("Send 'em back where they came from!");
-
- for (int ab = 0; ab < MAX_MONSTERS; ab++)
- {
- int abjLevel;
-
- monster = &menv[ab];
-
- if (monster->type == -1 || !mons_near(monster))
- continue;
-
- if (!mons_friendly(monster))
- continue;
-
- abjLevel = mons_has_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
- if (abjLevel == ENCH_NONE)
- continue;
-
- result++;
-
- if (test)
- continue;
-
- if (pow > 60)
- pow = 60;
-
- abjLevel -= 1 + (random2(pow) / 3);
-
- if (abjLevel < ENCH_ABJ_I)
- monster_die(monster, KILL_RESET, 0);
- else
- {
- simple_monster_message(monster, " shudders.");
- mons_del_ench(monster, ENCH_ABJ_I, ENCH_ABJ_VI);
- mons_add_ench(monster, abjLevel);
- }
- }
-
- return result;
-} // end monster_abjuration()