summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/spells4.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/spells4.cc')
-rw-r--r--stone_soup/crawl-ref/source/spells4.cc3155
1 files changed, 0 insertions, 3155 deletions
diff --git a/stone_soup/crawl-ref/source/spells4.cc b/stone_soup/crawl-ref/source/spells4.cc
deleted file mode 100644
index 076be063a6..0000000000
--- a/stone_soup/crawl-ref/source/spells4.cc
+++ /dev/null
@@ -1,3155 +0,0 @@
-/*
- * File: spells4.cc
- * Summary: new spells, focusing on transmigration, divination and
- * other neglected areas of Crawl magic ;^)
- * Written by: Copyleft Josh Fishman 1999-2000, All Rights Preserved
- *
- * Change History (most recent first):
- *
- * <2> 29jul2000 jdj Made a zillion functions static.
- * <1> 06jan2000 jmf Created
- */
-
-#include "AppHdr.h"
-
-#include <string>
-#include <stdio.h>
-
-#include "externs.h"
-
-#include "abyss.h"
-#include "beam.h"
-#include "cloud.h"
-#include "debug.h"
-#include "delay.h"
-#include "describe.h"
-#include "direct.h"
-#include "dungeon.h"
-#include "effects.h"
-#include "it_use2.h"
-#include "itemname.h"
-#include "itemprop.h"
-#include "items.h"
-#include "invent.h"
-#include "misc.h"
-#include "monplace.h"
-#include "monstuff.h"
-#include "mon-util.h"
-#include "mstuff2.h"
-#include "ouch.h"
-#include "player.h"
-#include "randart.h"
-#include "religion.h"
-#include "skills.h"
-#include "spells1.h"
-#include "spells4.h"
-#include "spl-cast.h"
-#include "spl-util.h"
-#include "stuff.h"
-#include "view.h"
-
-enum DEBRIS // jmf: add for shatter, dig, and Giants to throw
-{
- DEBRIS_METAL, // 0
- DEBRIS_ROCK,
- DEBRIS_STONE,
- DEBRIS_WOOD,
- DEBRIS_CRYSTAL,
- NUM_DEBRIS
-}; // jmf: ...and I'll actually implement the items Real Soon Now...
-
-// static int make_a_random_cloud(int x, int y, int pow, int ctype);
-static int make_a_rot_cloud(int x, int y, int pow, int ctype);
-static int quadrant_blink(int x, int y, int pow, int garbage);
-
-//void cast_animate_golem(int pow); // see actual function for reasoning {dlb}
-//void cast_detect_magic(int pow); //jmf: as above...
-//void cast_eringyas_surprising_bouquet(int powc);
-void do_monster_rot(int mon);
-
-//jmf: FIXME: put somewhere else (misc.cc?)
-// A feeble attempt at Nethack-like completeness for cute messages.
-const char *your_hand( bool plural )
-{
- static char hand_buff[80];
-
- switch (you.attribute[ATTR_TRANSFORMATION])
- {
- default:
- mpr("ERROR: unknown transformation in your_hand() (spells4.cc)");
- case TRAN_NONE:
- case TRAN_STATUE:
- if (you.species == SP_TROLL || you.species == SP_GHOUL)
- {
- strcpy(hand_buff, "claw");
- break;
- }
- // or fall-through
- case TRAN_ICE_BEAST:
- case TRAN_LICH:
- strcpy(hand_buff, "hand");
- break;
- case TRAN_SPIDER:
- strcpy(hand_buff, "front leg");
- break;
- case TRAN_SERPENT_OF_HELL:
- case TRAN_DRAGON:
- strcpy(hand_buff, "foreclaw");
- break;
- case TRAN_BLADE_HANDS:
- strcpy(hand_buff, "scythe-like blade");
- break;
- case TRAN_AIR:
- strcpy(hand_buff, "misty tendril");
- break;
- }
-
- if (plural)
- strcat(hand_buff, "s");
-
- return (hand_buff);
-}
-
-// I need to make some debris for metal, crystal and stone.
-// They could go in OBJ_MISSILES, but I think I'd rather move
-// MI_LARGE_ROCK into OBJ_DEBRIS and code giants to throw any
-// OBJ_DEBRIS they get their meaty mits on.
-static void place_debris(int x, int y, int debris_type)
-{
-#ifdef USE_DEBRIS_CODE
- switch (debris_type)
- {
- // hate to say this, but the first parameter only allows specific quantity
- // for *food* and nothing else -- and I would hate to see that parameter
- // (force_unique) abused any more than it already has been ... {dlb}:
- case DEBRIS_STONE:
- large = items( random2(3), OBJ_MISSILES, MI_LARGE_ROCK, true, 1, 250 );
- small = items( 3 + random2(6) + random2(6) + random2(6),
- OBJ_MISSILES, MI_STONE, true, 1, 250 );
- break;
- case DEBRIS_METAL:
- case DEBRIS_WOOD:
- case DEBRIS_CRYSTAL:
- break;
- }
-
- if (small != NON_ITEM)
- move_item_to_grid( &small, x, y );
-
- if (large != NON_ITEM)
- move_item_to_grid( &large, x, y );
-
-#else
- UNUSED( x );
- UNUSED( y );
- UNUSED( debris_type );
- return;
-#endif
-} // end place_debris()
-
-// just to avoid typing this over and over
-// now returns true if monster died -- bwr
-inline bool player_hurt_monster(int monster, int damage)
-{
- ASSERT( monster != NON_MONSTER );
-
- if (damage > 0)
- {
- hurt_monster( &menv[monster], damage );
-
- if (menv[monster].hit_points > 0)
- print_wounds( &menv[monster] );
- else
- {
- monster_die( &menv[monster], KILL_YOU, 0 );
- return (true);
- }
- }
-
- return (false);
-} // end player_hurt_monster()
-
-
-// Here begin the actual spells:
-static int shatter_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- dice_def dam_dice( 0, 5 + pow / 4 ); // number of dice set below
- const int monster = mgrd[x][y];
-
- if (monster == NON_MONSTER)
- return (0);
-
- // Removed a lot of silly monsters down here... people, just because
- // it says ice, rock, or iron in the name doesn't mean it's actually
- // made out of the substance. -- bwr
- switch (menv[monster].type)
- {
- case MONS_ICE_BEAST: // 3/2 damage
- case MONS_SIMULACRUM_SMALL:
- case MONS_SIMULACRUM_LARGE:
- dam_dice.num = 4;
- break;
-
- case MONS_SKELETON_SMALL: // double damage
- case MONS_SKELETON_LARGE:
- case MONS_CURSE_SKULL:
- case MONS_CLAY_GOLEM:
- case MONS_STONE_GOLEM:
- case MONS_IRON_GOLEM:
- case MONS_CRYSTAL_GOLEM:
- case MONS_EARTH_ELEMENTAL:
- case MONS_GARGOYLE:
- case MONS_SKELETAL_DRAGON:
- case MONS_SKELETAL_WARRIOR:
- dam_dice.num = 6;
- break;
-
- case MONS_VAPOUR:
- case MONS_INSUBSTANTIAL_WISP:
- case MONS_AIR_ELEMENTAL:
- case MONS_FIRE_ELEMENTAL:
- case MONS_WATER_ELEMENTAL:
- case MONS_SPECTRAL_WARRIOR:
- case MONS_FREEZING_WRAITH:
- case MONS_WRAITH:
- case MONS_PHANTOM:
- case MONS_PLAYER_GHOST:
- case MONS_SHADOW:
- case MONS_HUNGRY_GHOST:
- case MONS_FLAYED_GHOST:
- case MONS_SMOKE_DEMON: //jmf: I hate these bastards...
- dam_dice.num = 0;
- break;
-
- case MONS_PULSATING_LUMP:
- case MONS_JELLY:
- case MONS_SLIME_CREATURE:
- case MONS_BROWN_OOZE:
- case MONS_AZURE_JELLY:
- case MONS_DEATH_OOZE:
- case MONS_ACID_BLOB:
- case MONS_ROYAL_JELLY:
- case MONS_OOZE:
- case MONS_SPECTRAL_THING:
- case MONS_JELLYFISH:
- dam_dice.num = 1;
- dam_dice.size /= 2;
- break;
-
- case MONS_DANCING_WEAPON: // flies, but earth based
- case MONS_MOLTEN_GARGOYLE:
- case MONS_QUICKSILVER_DRAGON:
- // Soft, earth creatures... would normally resist to 1 die, but
- // are sensitive to this spell. -- bwr
- dam_dice.num = 2;
- break;
-
- default: // normal damage
- if (mons_flies( &menv[monster] ))
- dam_dice.num = 1;
- else
- dam_dice.num = 3;
- break;
- }
-
- int damage = roll_dice( dam_dice ) - random2( menv[monster].armour_class );
-
- if (damage > 0)
- player_hurt_monster( monster, damage );
- else
- damage = 0;
-
- return (damage);
-} // end shatter_monsters()
-
-static int shatter_items(int x, int y, int pow, int garbage)
-{
- UNUSED( pow );
- UNUSED( garbage );
-
- int broke_stuff = 0, next, obj = igrd[x][y];
-
- if (obj == NON_ITEM)
- return 0;
-
- while (obj != NON_ITEM)
- {
- next = mitm[obj].link;
-
- switch (mitm[obj].base_type)
- {
- case OBJ_POTIONS:
- if (!one_chance_in(10))
- {
- broke_stuff++;
- destroy_item(obj);
- }
- break;
-
- default:
- break;
- }
-
- obj = next;
- }
-
- if (broke_stuff)
- {
- if (!silenced(x, y) && !silenced(you.x_pos, you.y_pos))
- mpr("You hear glass break.", MSGCH_SOUND);
-
- return 1;
- }
-
- return 0;
-} // end shatter_items()
-
-static int shatter_walls(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- int chance = 0;
- int stuff = 0;
-
- // if not in-bounds then we can't really shatter it -- bwr
- if (x <= 5 || x >= GXM - 5 || y <= 5 || y >= GYM - 5)
- return (0);
-
- switch (grd[x][y])
- {
- case DNGN_SECRET_DOOR:
- if (see_grid(x, y))
- mpr("A secret door shatters!");
- grd[x][y] = DNGN_FLOOR;
- stuff = DEBRIS_WOOD;
- chance = 100;
- break;
-
- case DNGN_CLOSED_DOOR:
- case DNGN_OPEN_DOOR:
- if (see_grid(x, y))
- mpr("A door shatters!");
- grd[x][y] = DNGN_FLOOR;
- stuff = DEBRIS_WOOD;
- chance = 100;
- break;
-
- case DNGN_METAL_WALL:
- case DNGN_SILVER_STATUE:
- stuff = DEBRIS_METAL;
- chance = pow / 10;
- break;
-
- case DNGN_ORCISH_IDOL:
- case DNGN_GRANITE_STATUE:
- chance = 50;
- stuff = DEBRIS_STONE;
- break;
-
- case DNGN_STONE_WALL:
- chance = pow / 6;
- stuff = DEBRIS_STONE;
- break;
-
- case DNGN_ROCK_WALL:
- chance = pow / 4;
- stuff = DEBRIS_ROCK;
- break;
-
- case DNGN_ORANGE_CRYSTAL_STATUE:
- chance = pow / 6;
- stuff = DEBRIS_CRYSTAL;
- break;
-
- case DNGN_GREEN_CRYSTAL_WALL:
- chance = 50;
- stuff = DEBRIS_CRYSTAL;
- break;
-
- default:
- break;
- }
-
- if (stuff && random2(100) < chance)
- {
- if (!silenced( x, y ))
- noisy( 30, x, y );
-
- grd[x][y] = DNGN_FLOOR;
- place_debris(x, y, stuff);
- return (1);
- }
-
- return (0);
-} // end shatter_walls()
-
-void cast_shatter(int pow)
-{
- int damage = 0;
- const bool sil = silenced( you.x_pos, you.y_pos );
-
- if (!sil)
- noisy( 30, you.x_pos, you.y_pos );
-
- snprintf(info, INFO_SIZE, "The dungeon %s!", (sil ? "shakes" : "rumbles"));
- mpr(info, (sil? MSGCH_PLAIN : MSGCH_SOUND));
-
- switch (you.attribute[ATTR_TRANSFORMATION])
- {
- case TRAN_NONE:
- case TRAN_SPIDER:
- case TRAN_LICH:
- case TRAN_DRAGON:
- case TRAN_AIR:
- case TRAN_SERPENT_OF_HELL:
- break;
-
- case TRAN_STATUE: // full damage
- damage = 15 + random2avg( (pow / 5), 4 );
- break;
-
- case TRAN_ICE_BEAST: // 1/2 damage
- damage = 10 + random2avg( (pow / 5), 4 ) / 2;
- break;
-
- case TRAN_BLADE_HANDS: // 2d3 damage
- mpr("Your scythe-like blades vibrate painfully!");
- damage = 2 + random2avg(5, 2);
- break;
-
- default:
- mpr("cast_shatter(): unknown transformation in spells4.cc");
- }
-
- if (damage)
- ouch(damage, 0, KILLED_BY_TARGETTING);
-
- int rad = 3 + (you.skills[SK_EARTH_MAGIC] / 5);
-
- apply_area_within_radius(shatter_items, you.x_pos, you.y_pos, pow, rad, 0);
- apply_area_within_radius(shatter_monsters, you.x_pos, you.y_pos, pow, rad, 0);
- int dest = apply_area_within_radius( shatter_walls, you.x_pos, you.y_pos,
- pow, rad, 0 );
-
- if (dest && !sil)
- mpr("Ka-crash!", MSGCH_SOUND);
-} // end cast_shatter()
-
-// cast_forescry: raises evasion (by 8 currently) via divination
-void cast_forescry(int pow)
-{
- if (!you.duration[DUR_FORESCRY])
- mpr("You begin to receive glimpses of the immediate future...");
-
- you.duration[DUR_FORESCRY] += 5 + random2(pow);
-
- if (you.duration[DUR_FORESCRY] > 30)
- you.duration[DUR_FORESCRY] = 30;
-
- you.redraw_evasion = 1;
-} // end cast_forescry()
-
-void cast_see_invisible(int pow)
-{
- if (player_see_invis())
- mpr("Nothing seems to happen.");
- else
- mpr("Your vision seems to sharpen.");
-
- // no message if you already are under the spell
- you.duration[DUR_SEE_INVISIBLE] += 10 + random2(2 + (pow / 2));
-
- if (you.duration[DUR_SEE_INVISIBLE] > 100)
- you.duration[DUR_SEE_INVISIBLE] = 100;
-} // end cast_see_invisible()
-
-#if 0
-// FIXME: This would be kinda cool if implemented right.
-// The idea is that, like detect_secret_doors, the spell gathers all
-// sorts of information about a thing and then tells the caster a few
-// cryptic hints. So for a (+3,+5) Mace of Flaming, one might detect
-// "enchantment and heat", but for a cursed ring of hunger, one might
-// detect "enchantment and ice" (since it gives you a 'deathly cold'
-// feeling when you put it on) or "necromancy" (since it's evil).
-// A weapon of Divine Wrath and a randart that makes you angry might
-// both give similar messages. The key would be to not tell more than
-// hints about whether an item is benign or cursed, but give info
-// on how strong its enchantment is (and therefore how valuable it
-// probably is).
-static void cast_detect_magic(int pow)
-{
- struct dist bmove;
- int x, y;
- int monster = 0, item = 0, next; //int max;
- FixedVector < int, NUM_SPELL_TYPES > found;
- int strong = 0; // int curse = 0;
-
- for (next = 0; next < NUM_SPELL_TYPES; next++)
- {
- found[next] = 0;
- }
-
- mpr("Which direction?", MSGCH_PROMPT);
- direction( bmove, DIR_DIR );
-
- if (!bmove.isValid)
- {
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- if (bmove.dx == 0 && bmove.dy == 0)
- {
- mpr("You detect a divination in progress.");
- return;
- }
-
- x = you.x_pos + bmove.dx;
- y = you.y_pos + bmove.dy;
-
- monster = mgrd[x][y];
- if (monster == NON_MONSTER)
- goto do_items;
- else
- goto all_done;
-
- do_items:
- item = igrd[x][y];
-
- if (item == NON_ITEM)
- goto all_done;
-
- while (item != NON_ITEM)
- {
- next = mitm[item].link;
- if (is_dumpable_artifact
- (mitm[item].base_type, mitm[item].sub_type, mitm[item].plus,
- mitm[item].plus2, mitm[item].special, 0, 0))
- {
- strong++;
- //FIXME: do checks for randart properties
- }
- else
- {
- switch (mitm[item].base_type)
- {
- case OBJ_WEAPONS:
- found[SPTYP_ENCHANTMENT] += (mitm[item].plus > 50);
- found[SPTYP_ENCHANTMENT] += (mitm[item].plus2 > 50);
- break;
-
- case OBJ_MISSILES:
- found[SPTYP_ENCHANTMENT] += (mitm[item].plus > 50);
- found[SPTYP_ENCHANTMENT] += (mitm[item].plus2 > 50);
- break;
-
- case OBJ_ARMOUR:
- found[SPTYP_ENCHANTMENT] += mitm[item].plus;
- }
- }
- }
-
- all_done:
- if (monster)
- {
- mpr("You detect a morphogenic field, such as a monster might have.");
- }
- if (strong)
- {
- mpr("You detect very strong enchantments.");
- return;
- }
- else
- {
- //FIXME:
- }
- return;
-}
-#endif
-
-// The description idea was okay, but this spell just isn't that exciting.
-// So I'm converting it to the more practical expose secret doors. -- bwr
-void cast_detect_secret_doors(int pow)
-{
- int found = 0;
-
- for (int x = you.x_pos - 8; x <= you.x_pos + 8; x++)
- {
- for (int y = you.y_pos - 8; y <= you.y_pos + 8; y++)
- {
- if (x < 5 || x > GXM - 5 || y < 5 || y > GYM - 5)
- continue;
-
- if (!see_grid(x, y))
- continue;
-
- if (grd[x][y] == DNGN_SECRET_DOOR && random2(pow) > random2(15))
- {
- grd[x][y] = DNGN_CLOSED_DOOR;
- found++;
- }
- }
- }
-
- if (found)
- {
- redraw_screen();
-
- snprintf( info, INFO_SIZE, "You detect %s secret door%s.",
- (found > 1) ? "some" : "a", (found > 1) ? "s" : "" );
- mpr( info );
- }
-} // end cast_detect_secret_doors()
-
-void cast_summon_butterflies(int pow)
-{
- // explicitly limiting the number
- int num = 4 + random2(3) + random2( pow ) / 10;
- if (num > 16)
- num = 16;
-
- for (int scount = 1; scount < num; scount++)
- {
- create_monster( MONS_BUTTERFLY, ENCH_ABJ_III, BEH_FRIENDLY,
- you.x_pos, you.y_pos, MHITYOU, 250 );
- }
-}
-
-void cast_summon_large_mammal(int pow)
-{
- int mon;
- int temp_rand = random2(pow);
-
- if (temp_rand < 10)
- mon = MONS_JACKAL;
- else if (temp_rand < 15)
- mon = MONS_HOUND;
- else
- {
- switch (temp_rand % 7)
- {
- case 0:
- if (you.species == SP_HILL_ORC && one_chance_in(3))
- mon = MONS_WARG;
- else
- mon = MONS_WOLF;
- break;
- case 1:
- case 2:
- mon = MONS_WAR_DOG;
- break;
- case 3:
- case 4:
- mon = MONS_HOUND;
- break;
- default:
- mon = MONS_JACKAL;
- break;
- }
- }
-
- create_monster( mon, ENCH_ABJ_III, BEH_FRIENDLY, you.x_pos, you.y_pos,
- you.pet_target, 250 );
-}
-
-void cast_sticks_to_snakes(int pow)
-{
- int mon, i, behaviour;
-
- int how_many = 0;
-
- int max = 1 + random2( 1 + you.skills[SK_TRANSMIGRATION] ) / 4;
-
- int dur = ENCH_ABJ_III + random2(pow) / 20;
- if (dur > ENCH_ABJ_V)
- dur = ENCH_ABJ_V;
-
- const int weapon = you.equip[EQ_WEAPON];
-
- if (weapon == -1)
- {
- snprintf( info, INFO_SIZE, "Your %s feel slithery!", your_hand(true));
- mpr(info);
- return;
- }
-
- behaviour = item_cursed( you.inv[ weapon ] ) ? BEH_HOSTILE
- : BEH_FRIENDLY;
-
- if ((you.inv[ weapon ].base_type == OBJ_MISSILES
- && (you.inv[ weapon ].sub_type == MI_ARROW)))
- {
- if (you.inv[ weapon ].quantity < max)
- max = you.inv[ weapon ].quantity;
-
- for (i = 0; i <= max; i++)
- {
- //jmf: perhaps also check for poison ammo?
- if (pow > 50 || (pow > 25 && one_chance_in(3)))
- mon = MONS_SNAKE;
- else
- mon = MONS_SMALL_SNAKE;
-
- if (create_monster( mon, dur, behaviour, you.x_pos, you.y_pos,
- MHITYOU, 250 ) != -1)
- {
- how_many++;
- }
- }
- }
-
- if (you.inv[ weapon ].base_type == OBJ_WEAPONS
- && (you.inv[ weapon ].sub_type == WPN_CLUB
- || you.inv[ weapon ].sub_type == WPN_SPEAR
- || you.inv[ weapon ].sub_type == WPN_QUARTERSTAFF
- || you.inv[ weapon ].sub_type == WPN_SCYTHE
- || you.inv[ weapon ].sub_type == WPN_GIANT_CLUB
- || you.inv[ weapon ].sub_type == WPN_GIANT_SPIKED_CLUB
- || you.inv[ weapon ].sub_type == WPN_BOW
- || you.inv[ weapon ].sub_type == WPN_LONGBOW
- || you.inv[ weapon ].sub_type == WPN_ANCUS
- || you.inv[ weapon ].sub_type == WPN_HALBERD
- || you.inv[ weapon ].sub_type == WPN_GLAIVE
- || you.inv[ weapon ].sub_type == WPN_BLOWGUN))
- {
- how_many = 1;
-
- // Upsizing Snakes to Brown Snakes as the base class for using
- // the really big sticks (so bonus applies really only to trolls,
- // ogres, and most importantly ogre magi). Still it's unlikely
- // any character is strong enough to bother lugging a few of
- // these around. -- bwr
- if (item_mass( you.inv[ weapon ] ) < 500)
- mon = MONS_SNAKE;
- else
- mon = MONS_BROWN_SNAKE;
-
- if (pow > 90 && one_chance_in(3))
- mon = MONS_GREY_SNAKE;
-
- if (pow > 70 && one_chance_in(3))
- mon = MONS_BLACK_SNAKE;
-
- if (pow > 40 && one_chance_in(3))
- mon = MONS_YELLOW_SNAKE;
-
- if (pow > 20 && one_chance_in(3))
- mon = MONS_BROWN_SNAKE;
-
- create_monster(mon, dur, behaviour, you.x_pos, you.y_pos, MHITYOU, 250);
- }
-
-#ifdef USE_DEBRIS_CODE
- if (you.inv[ weapon ].base_type == OBJ_DEBRIS
- && (you.inv[ weapon ].sub_type == DEBRIS_WOOD))
- {
- // this is how you get multiple big snakes
- how_many = 1;
- mpr("FIXME: implement OBJ_DEBRIS conversion! (spells4.cc)");
- }
-#endif // USE_DEBRIS_CODE
-
- if (how_many > you.inv[you.equip[EQ_WEAPON]].quantity)
- how_many = you.inv[you.equip[EQ_WEAPON]].quantity;
-
- if (how_many)
- {
- dec_inv_item_quantity( you.equip[EQ_WEAPON], how_many );
-
- snprintf( info, INFO_SIZE, "You create %s snake%s!",
- how_many > 1 ? "some" : "a", how_many > 1 ? "s" : "");
- }
- else
- {
- snprintf( info, INFO_SIZE, "Your %s feel slithery!", your_hand(true));
- }
-
- mpr(info);
- return;
-} // end cast_sticks_to_snakes()
-
-void cast_summon_dragon(int pow)
-{
- int happy;
-
- // Removed the chance of multiple dragons... one should be more
- // than enough, and if it isn't, the player can cast again...
- // especially since these aren't on the Abjuration plan... they'll
- // last until they die (maybe that should be changed, but this is
- // a very high level spell so it might be okay). -- bwr
- happy = (random2(pow) > 5);
-
- if (create_monster( MONS_DRAGON, ENCH_ABJ_III,
- (happy ? BEH_FRIENDLY : BEH_HOSTILE),
- you.x_pos, you.y_pos, MHITYOU, 250 ) != -1)
- {
- strcpy(info, "A dragon appears.");
-
- if (!happy)
- strcat(info, " It doesn't look very happy.");
- }
- else
- strcpy(info, "Nothing happens.");
-
- mpr(info);
-} // end cast_summon_dragon()
-
-void cast_conjure_ball_lightning( int pow )
-{
- int num = 3 + random2( 2 + pow / 50 );
-
- // but restricted so that the situation doesn't get too gross.
- // Each of these will explode for 3d20 damage. -- bwr
- if (num > 8)
- num = 8;
-
- bool summoned = false;
-
- for (int i = 0; i < num; i++)
- {
- int tx = -1, ty = -1;
-
- for (int j = 0; j < 10; j++)
- {
- if (!random_near_space( you.x_pos, you.y_pos, tx, ty, true, true)
- && distance( you.x_pos, you.y_pos, tx, ty ) <= 5)
- {
- break;
- }
- }
-
- // if we fail, we'll try the ol' summon next to player trick.
- if (tx == -1 || ty == -1)
- {
- tx = you.x_pos;
- ty = you.y_pos;
- }
-
- int mon = mons_place( MONS_BALL_LIGHTNING, BEH_FRIENDLY, MHITNOT,
- true, tx, ty );
-
- // int mon = create_monster( MONS_BALL_LIGHTNING, 0, BEH_FRIENDLY,
- // tx, ty, MHITNOT, 250 );
-
- if (mon != -1)
- {
- mons_add_ench( &menv[mon], ENCH_SHORT_LIVED );
- summoned = true;
- }
- }
-
- if (summoned)
- mpr( "You create some ball lightning!" );
- else
- canned_msg( MSG_NOTHING_HAPPENS );
-}
-
-static int sleep_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
- int mnstr = mgrd[x][y];
-
- if (mnstr == NON_MONSTER) return 0;
- if (mons_holiness(&menv[mnstr]) != MH_NATURAL) return 0;
- if (check_mons_resist_magic( &menv[mnstr], pow )) return 0;
-
- // Why shouldn't we be able to sleep friendly monsters? -- bwr
- // if (mons_friendly( &menv[mnstr] )) return 0;
-
- //jmf: now that sleep == hibernation:
- if (mons_res_cold( &menv[mnstr] ) > 0 && coinflip()) return 0;
- if (mons_has_ench( &menv[mnstr], ENCH_SLEEP_WARY )) return 0;
-
- menv[mnstr].behaviour = BEH_SLEEP;
- mons_add_ench( &menv[mnstr], ENCH_SLEEP_WARY );
-
- if (mons_class_flag( menv[mnstr].type, M_COLD_BLOOD ) && coinflip())
- mons_add_ench( &menv[mnstr], ENCH_SLOW );
-
- return 1;
-} // end sleep_monsters()
-
-void cast_mass_sleep(int pow)
-{
- apply_area_visible(sleep_monsters, pow);
-} // end cast_mass_sleep()
-
-static int tame_beast_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
- int which_mons = mgrd[x][y];
-
- if (which_mons == NON_MONSTER) return 0;
-
- struct monsters *monster = &menv[which_mons];
-
- if (mons_holiness(monster) != MH_NATURAL) return 0;
- if (mons_intel_type(monster->type) != I_ANIMAL) return 0;
- if (mons_friendly(monster)) return 0;
-
- // 50% bonus for dogs, add cats if they get implemented
- if (monster->type == MONS_HOUND || monster->type == MONS_WAR_DOG
- || monster->type == MONS_BLACK_BEAR)
- {
- pow += (pow / 2);
- }
-
- if (you.species == SP_HILL_ORC && monster->type == MONS_WARG)
- pow += (pow / 2);
-
- if (check_mons_resist_magic(monster, pow))
- return 0;
-
- // I'd like to make the monsters affected permanently, but that's
- // pretty powerful. Maybe a small (pow/10) chance of being permanently
- // tamed, large chance of just being enslaved.
- simple_monster_message(monster, " is tamed!");
-
- if (random2(100) < random2(pow / 10))
- monster->attitude = ATT_FRIENDLY; // permanent, right?
- else
- mons_add_ench(monster, ENCH_CHARM);
-
- return 1;
-} // end tame_beast_monsters()
-
-void cast_tame_beasts(int pow)
-{
- apply_area_visible(tame_beast_monsters, pow);
-} // end cast_tame_beasts()
-
-static int ignite_poison_objects(int x, int y, int pow, int garbage)
-{
- UNUSED( pow );
- UNUSED( garbage );
-
- int obj = igrd[x][y], next, strength = 0;
-
- if (obj == NON_ITEM)
- return (0);
-
- while (obj != NON_ITEM)
- {
- next = mitm[obj].link;
- if (mitm[obj].base_type == OBJ_POTIONS)
- {
- switch (mitm[obj].sub_type)
- {
- // intentional fall-through all the way down
- case POT_STRONG_POISON:
- strength += 20;
- case POT_DEGENERATION:
- strength += 10;
- case POT_POISON:
- strength += 10;
- destroy_item(obj);
- default:
- break;
- }
- }
-
- // FIXME: impliment burning poisoned ammo
- // else if ( it's ammo that's poisoned) {
- // strength += number_of_ammo;
- // destroy_item(ammo);
- // }
- obj = next;
- }
-
- if (strength > 0)
- place_cloud(CLOUD_FIRE, x, y, strength + roll_dice(3, strength / 4) );
-
- return (strength);
-} // end ignite_poison_objects()
-
-static int ignite_poison_clouds( int x, int y, int pow, int garbage )
-{
- UNUSED( pow );
- UNUSED( garbage );
-
- bool did_anything = false;
-
- const int cloud = env.cgrid[x][y];
-
- if (cloud != EMPTY_CLOUD)
- {
- if (env.cloud[ cloud ].type == CLOUD_STINK
- || env.cloud[ cloud ].type == CLOUD_STINK_MON)
- {
- did_anything = true;
- env.cloud[ cloud ].type = CLOUD_FIRE;
-
- env.cloud[ cloud ].decay /= 2;
-
- if (env.cloud[ cloud ].decay < 1)
- env.cloud[ cloud ].decay = 1;
- }
- else if (env.cloud[ cloud ].type == CLOUD_POISON
- || env.cloud[ cloud ].type == CLOUD_POISON_MON)
- {
- did_anything = true;
- env.cloud[ cloud ].type = CLOUD_FIRE;
- }
- }
-
- return ((int) did_anything);
-} // end ignite_poison_clouds()
-
-static int ignite_poison_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- struct bolt beam;
- beam.flavour = BEAM_FIRE; // this is dumb, only used for adjust!
-
- dice_def dam_dice( 0, 5 + pow / 7 ); // dice added below if applicable
-
- const int mon_index = mgrd[x][y];
- if (mon_index == NON_MONSTER)
- return (0);
-
- struct monsters *const mon = &menv[ mon_index ];
-
- // Monsters which have poison corpses or poisonous attacks:
- if (mons_corpse_effect( mon->type ) == CE_POISONOUS
- || mon->type == MONS_GIANT_ANT
- || mon->type == MONS_SMALL_SNAKE
- || mon->type == MONS_SNAKE
- || mon->type == MONS_JELLYFISH
- || mons_is_mimic( mon->type ))
- {
- dam_dice.num = 3;
- }
-
- // Monsters which are poisoned:
- int strength = 0;
-
- // first check for player poison:
- int ench = mons_has_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
- if (ench != ENCH_NONE)
- strength += ench - ENCH_YOUR_POISON_I + 1;
-
- // ... now monster poison:
- ench = mons_has_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
- if (ench != ENCH_NONE)
- strength += ench - ENCH_POISON_I + 1;
-
- // strength is now the sum of both poison types (although only
- // one should actually be present at a given time):
- dam_dice.num += strength;
-
- int damage = roll_dice( dam_dice );
- if (damage > 0)
- {
- damage = mons_adjust_flavoured( mon, beam, damage );
-
-#if DEBUG_DIAGNOSTICS
- snprintf( info, INFO_SIZE, "Dice: %dd%d; Damage: %d",
- dam_dice.num, dam_dice.size, damage );
-
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- if (!player_hurt_monster( mon_index, damage ))
- {
- // Monster survived, remove any poison.
- mons_del_ench( mon, ENCH_POISON_I, ENCH_POISON_IV );
- mons_del_ench( mon, ENCH_YOUR_POISON_I, ENCH_YOUR_POISON_IV );
- }
-
- return (1);
- }
-
- return (0);
-}
-
-void cast_ignite_poison(int pow)
-{
- int damage = 0, strength = 0, pcount = 0, acount = 0, totalstrength = 0;
- char item;
- bool wasWielding = false;
- char str_pass[ ITEMNAME_SIZE ];
-
- // temp weapon of venom => temp fire brand
- const int wpn = you.equip[EQ_WEAPON];
-
- if (wpn != -1
- && you.duration[DUR_WEAPON_BRAND]
- && get_weapon_brand( you.inv[wpn] ) == SPWPN_VENOM)
- {
- if (set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, SPWPN_FLAMING ))
- {
- in_name( wpn, DESC_CAP_YOUR, str_pass );
- strcpy( info, str_pass );
- strcat( info, " bursts into flame!" );
- mpr(info);
-
- you.wield_change = true;
- you.duration[DUR_WEAPON_BRAND] += 1 + you.duration[DUR_WEAPON_BRAND] / 2;
- if (you.duration[DUR_WEAPON_BRAND] > 80)
- you.duration[DUR_WEAPON_BRAND] = 80;
- }
- }
-
- totalstrength = 0;
-
- for (item = 0; item < ENDOFPACK; item++)
- {
- if (!you.inv[item].quantity)
- continue;
-
- strength = 0;
-
- if (you.inv[item].base_type == OBJ_MISSILES)
- {
- if (you.inv[item].special == 3)
- { // burn poison ammo
- strength = you.inv[item].quantity;
- acount += you.inv[item].quantity;
- }
- }
-
- if (you.inv[item].base_type == OBJ_POTIONS)
- {
- switch (you.inv[item].sub_type)
- {
- case POT_STRONG_POISON:
- strength += 20 * you.inv[item].quantity;
- break;
- case POT_DEGENERATION:
- case POT_POISON:
- strength += 10 * you.inv[item].quantity;
- break;
- default:
- break;
- } // end switch
-
- if (strength)
- pcount += you.inv[item].quantity;
- }
-
- if (strength)
- {
- you.inv[item].quantity = 0;
- if (item == you.equip[EQ_WEAPON])
- {
- you.equip[EQ_WEAPON] = -1;
- wasWielding = true;
- }
- }
-
- totalstrength += strength;
- }
-
- if (acount > 0)
- mpr("Some ammo you are carrying burns!");
-
- if (pcount > 0)
- {
- snprintf( info, INFO_SIZE, "%s potion%s you are carrying explode%s!",
- pcount > 1 ? "Some" : "A",
- pcount > 1 ? "s" : "",
- pcount > 1 ? "" : "s");
- mpr(info);
- }
-
- if (wasWielding == true)
- canned_msg( MSG_EMPTY_HANDED );
-
- if (totalstrength)
- {
- place_cloud(CLOUD_FIRE, you.x_pos, you.y_pos,
- random2(totalstrength / 4 + 1) + random2(totalstrength / 4 + 1) +
- random2(totalstrength / 4 + 1) + random2(totalstrength / 4 + 1) + 1);
- }
-
- // player is poisonous
- if (you.mutation[MUT_SPIT_POISON] || you.mutation[MUT_STINGER]
- || you.attribute[ATTR_TRANSFORMATION] == TRAN_SPIDER // poison attack
- || (!player_is_shapechanged()
- && (you.species == SP_GREEN_DRACONIAN // poison breath
- || you.species == SP_KOBOLD // poisonous corpse
- || you.species == SP_NAGA))) // spit poison
- {
- damage = roll_dice( 3, 5 + pow / 7 );
- }
-
- // player is poisoned
- damage += roll_dice( you.poison, 6 );
-
- if (damage)
- {
- const int resist = player_res_fire();
-
- if (resist > 0)
- {
- mpr("You feel like your blood is boiling!");
- damage = damage / 3;
- }
- else if (resist < 0)
- {
- damage *= 3;
- mpr("The poison in your system burns terribly!");
- }
- else
- {
- mpr("The poison in your system burns!");
- }
-
- ouch( damage, 0, KILLED_BY_TARGETTING );
-
- if (you.poison > 0)
- {
- mpr( "You feel that the poison has left your system." );
- you.poison = 0;
- }
- }
-
- apply_area_visible(ignite_poison_clouds, pow);
- apply_area_visible(ignite_poison_objects, pow);
- apply_area_visible(ignite_poison_monsters, pow);
-} // end cast_ignite_poison()
-
-void cast_silence(int pow)
-{
- if (!you.attribute[ATTR_WAS_SILENCED])
- mpr("A profound silence engulfs you.");
-
- you.attribute[ATTR_WAS_SILENCED] = 1;
-
- you.duration[DUR_SILENCE] += 10 + random2avg( pow, 2 );
-
- if (you.duration[DUR_SILENCE] > 100)
- you.duration[DUR_SILENCE] = 100;
-} // end cast_silence()
-
-
-/* ******************************************************************
-// no hooks for this anywhere {dlb}:
-
-void cast_animate_golem(int pow)
-{
- // must have more than 20 max_hitpoints
-
- // must be wielding a Scroll of Paper (for chem)
-
- // must be standing on a pile of <foo> (for foo in: wood, metal, rock, stone)
-
- // Will cost you 5-10% of max_hitpoints, or 20 + some, whichever is more
- mpr("You imbue the inanimate form with a portion of your life force.");
-
- naughty(NAUGHTY_CREATED_LIFE, 10);
-}
-
-****************************************************************** */
-
-static int discharge_monsters( int x, int y, int pow, int garbage )
-{
- UNUSED( garbage );
-
- const int mon = mgrd[x][y];
- int damage = 0;
-
- struct bolt beam;
- beam.flavour = BEAM_ELECTRICITY; // used for mons_adjust_flavoured
-
- if (x == you.x_pos && y == you.y_pos)
- {
- mpr( "You are struck by lightning." );
- damage = 3 + random2( 5 + pow / 10 );
- damage = check_your_resists( damage, BEAM_ELECTRICITY );
- ouch( damage, 0, KILLED_BY_WILD_MAGIC );
- }
- else if (mon == NON_MONSTER)
- return (0);
- else if (mons_res_elec(&menv[mon]) > 0 || mons_flies(&menv[mon]))
- return (0);
- else
- {
- damage = 3 + random2( 5 + pow / 10 );
- damage = mons_adjust_flavoured( &menv[mon], beam, damage );
-
- if (damage)
- {
- strcpy( info, ptr_monam( &(menv[mon]), DESC_CAP_THE ) );
- strcat( info, " is struck by lightning." );
- mpr( info );
-
- player_hurt_monster( mon, damage );
- }
- }
-
- // Recursion to give us chain-lightning -- bwr
- // Low power slight chance added for low power characters -- bwr
- if ((pow >= 10 && !one_chance_in(3)) || (pow >= 3 && one_chance_in(10)))
- {
- mpr( "The lightning arcs!" );
- pow /= (coinflip() ? 2 : 3);
- damage += apply_random_around_square( discharge_monsters, x, y,
- true, pow, 1 );
- }
- else if (damage > 0)
- {
- // Only printed if we did damage, so that the messages in
- // cast_discharge() are clean. -- bwr
- mpr( "The lightning grounds out." );
- }
-
- return (damage);
-} // end discharge_monsters()
-
-void cast_discharge( int pow )
-{
- int num_targs = 1 + random2( 1 + pow / 25 );
- int dam;
-
- dam = apply_random_around_square( discharge_monsters, you.x_pos, you.y_pos,
- true, pow, num_targs );
-
-#if DEBUG_DIAGNOSTICS
- snprintf( info, INFO_SIZE, "Arcs: %d Damage: %d", num_targs, dam );
- mpr( info, MSGCH_DIAGNOSTICS );
-#endif
-
- if (dam == 0)
- {
- if (coinflip())
- mpr("The air around you crackles with electrical energy.");
- else
- {
- bool plural = coinflip();
- snprintf( info, INFO_SIZE, "%s blue arc%s ground%s harmlessly %s you.",
- plural ? "Some" : "A",
- plural ? "s" : "",
- plural ? " themselves" : "s itself",
- plural ? "around" : (coinflip() ? "beside" :
- coinflip() ? "behind" : "before")
- );
-
- mpr(info);
- }
- }
-} // end cast_discharge()
-
-// NB: this must be checked against the same effects
-// in fight.cc for all forms of attack !!! {dlb}
-// This function should be currently unused (the effect is too powerful)
-static int distortion_monsters(int x, int y, int pow, int message)
-{
- int specdam = 0;
- int monster_attacked = mgrd[x][y];
-
- if (monster_attacked == NON_MONSTER)
- return 0;
-
- struct monsters *defender = &menv[monster_attacked];
-
- if (pow > 100)
- pow = 100;
-
- if (x == you.x_pos && y == you.y_pos)
- {
- if (you.skills[SK_TRANSLOCATIONS] < random2(8))
- {
- miscast_effect( SPTYP_TRANSLOCATION, pow / 9 + 1, pow, 100,
- "a distortion effect" );
- }
- else
- {
- miscast_effect( SPTYP_TRANSLOCATION, 1, 1, 100,
- "a distortion effect" );
- }
-
- return 1;
- }
-
- if (defender->type == MONS_BLINK_FROG) // any others resist?
- {
- int hp = defender->hit_points;
- int max_hp = defender->max_hit_points;
-
- mpr("The blink frog basks in the translocular energy.");
-
- if (hp < max_hp)
- hp += 1 + random2(1 + pow / 4) + random2(1 + pow / 7);
-
- if (hp > max_hp)
- hp = max_hp;
-
- defender->hit_points = hp;
- return 1;
- }
- else if (coinflip())
- {
- strcpy(info, "Space bends around ");
- strcat(info, ptr_monam(defender, DESC_NOCAP_THE));
- strcat(info, ".");
- mpr(info);
- specdam += 1 + random2avg( 7, 2 ) + random2(pow) / 40;
- }
- else if (coinflip())
- {
- strcpy(info, "Space warps horribly around ");
- strcat(info, ptr_monam( defender, DESC_NOCAP_THE ));
- strcat(info, "!");
- mpr(info);
-
- specdam += 3 + random2avg( 12, 2 ) + random2(pow) / 25;
- }
- else if (one_chance_in(3))
- {
- monster_blink(defender);
- return 1;
- }
- else if (one_chance_in(3))
- {
- monster_teleport(defender, coinflip());
- return 1;
- }
- else if (one_chance_in(3))
- {
- monster_die(defender, KILL_RESET, 0);
- return 1;
- }
- else if (message)
- {
- mpr("Nothing seems to happen.");
- return 1;
- }
-
- player_hurt_monster(monster_attacked, specdam);
-
- return (specdam);
-} // end distortion_monsters()
-
-void cast_bend(int pow)
-{
- apply_one_neighbouring_square( distortion_monsters, pow );
-} // end cast_bend()
-
-// Really this is just applying the best of Band/Warp weapon/Warp field
-// into a spell that gives the "make monsters go away" benefit without
-// the insane damage potential. -- bwr
-int disperse_monsters(int x, int y, int pow, int message)
-{
- UNUSED( message );
-
- const int monster_attacked = mgrd[x][y];
-
- if (monster_attacked == NON_MONSTER)
- return 0;
-
- struct monsters *defender = &menv[monster_attacked];
-
- if (defender->type == MONS_BLINK_FROG)
- {
- simple_monster_message(defender, " resists.");
- return 1;
- }
- else if (check_mons_resist_magic(defender, pow))
- {
- if (coinflip())
- {
- simple_monster_message(defender, " partially resists.");
- monster_blink(defender);
- }
- else
- simple_monster_message(defender, " resists.");
-
- return 1;
- }
- else
- {
- monster_teleport( defender, true );
- return 1;
- }
-
- return 0;
-}
-
-void cast_dispersal(int pow)
-{
- if (apply_area_around_square( disperse_monsters,
- you.x_pos, you.y_pos, pow ) == 0)
- {
- mpr( "There is a brief shimmering in the air around you." );
- }
-}
-
-static int spell_swap_func(int x, int y, int pow, int message)
-{
- UNUSED( message );
-
- int monster_attacked = mgrd[x][y];
-
- if (monster_attacked == NON_MONSTER)
- return 0;
-
- struct monsters *defender = &menv[monster_attacked];
-
- if (defender->type == MONS_BLINK_FROG
- || check_mons_resist_magic( defender, pow ))
- {
- simple_monster_message( defender, " resists." );
- }
- else
- {
- // Swap doesn't seem to actually swap, but just sets the
- // monster's location equal to the players... this being because
- // the acr.cc call is going to move the player afterwards (for
- // the regular friendly monster swap). So we'll go through
- // standard swap procedure here... since we really want to apply
- // the same swap_places function as with friendly monsters...
- // see note over there. -- bwr
- int old_x = defender->x;
- int old_y = defender->y;
-
- if (swap_places( defender ))
- {
- you.x_pos = old_x;
- you.y_pos = old_y;
- }
- }
-
- return 1;
-}
-
-void cast_swap(int pow)
-{
- apply_one_neighbouring_square( spell_swap_func, pow );
-}
-
-static int make_a_rot_cloud(int x, int y, int pow, int ctype)
-{
- int next = 0, obj = mgrd[x][y];
-
- if (obj == NON_MONSTER)
- return 0;
-
- while (obj != NON_ITEM)
- {
- next = mitm[obj].link;
-
- if (mitm[obj].base_type == OBJ_CORPSES
- && mitm[obj].sub_type == CORPSE_BODY)
- {
- if (!mons_skeleton(mitm[obj].plus))
- destroy_item(obj);
- else
- {
- mitm[obj].sub_type = CORPSE_SKELETON;
- mitm[obj].special = 200;
- mitm[obj].colour = LIGHTGREY;
- }
-
- place_cloud(ctype, x, y,
- (3 + random2(pow / 4) + random2(pow / 4) +
- random2(pow / 4)));
- return 1;
- }
-
- obj = next;
- }
-
- return 0;
-} // end make_a_rot_cloud()
-
-int make_a_normal_cloud(int x, int y, int pow, int ctype)
-{
- place_cloud( ctype, x, y,
- (3 + random2(pow / 4) + random2(pow / 4) + random2(pow / 4)) );
-
- return 1;
-} // end make_a_normal_cloud()
-
-#if 0
-
-static int make_a_random_cloud(int x, int y, int pow, int ctype)
-{
- if (ctype == CLOUD_NONE)
- ctype = CLOUD_BLACK_SMOKE;
-
- unsigned char cloud_material;
-
- switch (random2(9))
- {
- case 0:
- cloud_material = CLOUD_FIRE;
- break;
- case 1:
- cloud_material = CLOUD_STINK;
- break;
- case 2:
- cloud_material = CLOUD_COLD;
- break;
- case 3:
- cloud_material = CLOUD_POISON;
- break;
- case 4:
- cloud_material = CLOUD_BLUE_SMOKE;
- break;
- case 5:
- cloud_material = CLOUD_STEAM;
- break;
- case 6:
- cloud_material = CLOUD_PURP_SMOKE;
- break;
- default:
- cloud_material = ctype;
- break;
- }
-
- // that last bit is equivalent to "random2(pow/4) + random2(pow/4)
- // + random2(pow/4)" {dlb}
- // can you see the pattern? {dlb}
- place_cloud(cloud_material, x, y, 3 + random2avg(3 * (pow / 4) - 2, 3));
-
- return 1;
-} // end make_a_random_cloud()
-
-#endif
-
-static int passwall(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- char dx, dy, nx = x, ny = y;
- int howdeep = 0;
- bool done = false;
- int shallow = 1 + (you.skills[SK_EARTH_MAGIC] / 8);
-
- // allow statues as entry points?
- if (grd[x][y] != DNGN_ROCK_WALL)
- // Irony: you can start on a secret door but not a door.
- // Worked stone walls are out, they're not diggable and
- // are used for impassable walls... I'm not sure we should
- // even allow statues (should be contiguous rock) -- bwr
- {
- mpr("That's not a passable wall.");
- return 0;
- }
-
- dx = x - you.x_pos;
- dy = y - you.y_pos;
-
- while (!done)
- {
- // I'm trying to figure proper borders out {dlb}
- // FIXME: dungeon border?
- if (nx > (GXM - 1) || ny > (GYM - 1) || nx < 2 || ny < 2)
- {
- mpr("You sense an overwhelming volume of rock.");
- return 0;
- }
-
- switch (grd[nx][ny])
- {
- default:
- done = true;
- break;
- case DNGN_ROCK_WALL:
- case DNGN_ORCISH_IDOL:
- case DNGN_GRANITE_STATUE:
- case DNGN_SECRET_DOOR:
- nx += dx;
- ny += dy;
- howdeep++;
- break;
- }
- }
-
- int range = shallow + random2(pow) / 25;
-
- if (howdeep > shallow)
- {
- mpr("This rock feels deep.");
-
- if (yesno("Try anyway?"))
- {
- if (howdeep > range)
- {
- ouch(1 + you.hp, 0, KILLED_BY_PETRIFICATION);
- //jmf: not return; if wizard, successful transport is option
- }
- }
- else
- {
- if (one_chance_in(30))
- mpr("Wuss.");
- else
- canned_msg(MSG_OK);
- return 1;
- }
- }
-
- // Note that the delay was (1 + howdeep * 2), but now that the
- // delay is stopped when the player is attacked it can be much
- // shorter since its harder to use for quick escapes. -- bwr
- start_delay( DELAY_PASSWALL, 2 + howdeep, nx, ny );
-
- return 1;
-} // end passwall()
-
-void cast_passwall(int pow)
-{
- apply_one_neighbouring_square(passwall, pow);
-} // end cast_passwall()
-
-static int intoxicate_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( pow );
- UNUSED( garbage );
-
- int mon = mgrd[x][y];
-
- if (mon == NON_MONSTER)
- return 0;
- if (mons_intel(menv[mon].type) < I_NORMAL)
- return 0;
- if (mons_holiness(&menv[mon]) != MH_NATURAL)
- return 0;
- if (mons_res_poison(&menv[mon]) > 0)
- return 0;
-
- mons_add_ench(&menv[mon], ENCH_CONFUSION);
- return 1;
-} // end intoxicate_monsters()
-
-void cast_intoxicate(int pow)
-{
- potion_effect( POT_CONFUSION, 10 + (100 - pow) / 10);
-
- if (one_chance_in(20) && lose_stat( STAT_INTELLIGENCE, 1 + random2(3) ))
- mpr("Your head spins!");
-
- apply_area_visible(intoxicate_monsters, pow);
-} // end cast_intoxicate()
-
-// intended as a high-level Elven (a)bility
-static int glamour_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- int mon = mgrd[x][y];
-
- // Power in this function is already limited by a function of
- // experience level (10 + level / 2) since it's only an ability,
- // never an actual spell. -- bwr
-
- if (mon == NON_MONSTER)
- return (0);
-
- if (one_chance_in(5))
- return (0);
-
- if (mons_intel(menv[mon].type) < I_NORMAL)
- return (0);
-
- if (mons_class_holiness(mon) != MH_NATURAL)
- return (0);
-
- if (!mons_is_humanoid( menv[mon].type ))
- return (0);
-
- const char show_char = mons_char( menv[mon].type );
-
- // gargoyles are immune.
- if (menv[mon].type == MONS_GARGOYLE
- || menv[mon].type == MONS_METAL_GARGOYLE
- || menv[mon].type == MONS_MOLTEN_GARGOYLE)
- {
- return (0);
- }
-
- // orcs resist thru hatred of elves
- // elves resist cause they're elves
- // boggarts are malevolent highly magical wee-folk
- if (show_char == 'o' || show_char == 'e' || menv[mon].type == MONS_BOGGART)
- pow = (pow / 2) + 1;
-
- if (check_mons_resist_magic(&menv[mon], pow))
- return (0);
-
- switch (random2(6))
- {
- case 0:
- mons_add_ench(&menv[mon], ENCH_FEAR);
- break;
- case 1:
- case 4:
- mons_add_ench(&menv[mon], ENCH_CONFUSION);
- break;
- case 2:
- case 5:
- mons_add_ench(&menv[mon], ENCH_CHARM);
- break;
- case 3:
- menv[mon].behaviour = BEH_SLEEP;
- break;
- }
-
- // why no, there's no message as to which effect happened >:^)
- if (!one_chance_in(4))
- {
- strcpy(info, ptr_monam( &(menv[mon]), DESC_CAP_THE));
-
- switch (random2(4))
- {
- case 0:
- strcat(info, " looks dazed.");
- break;
- case 1:
- strcat(info, " blinks several times.");
- break;
- case 2:
- strcat(info, " rubs its eye");
- if (menv[mon].type != MONS_CYCLOPS)
- strcat(info, "s");
- strcat(info, ".");
- break;
- case 4:
- strcat(info, " tilts its head.");
- break;
- }
-
- mpr(info);
- }
-
- return (1);
-} // end glamour_monsters()
-
-void cast_glamour(int pow)
-{
- apply_area_visible(glamour_monsters, pow);
-} // end cast_glamour()
-
-bool backlight_monsters(int x, int y, int pow, int garbage)
-{
- UNUSED( pow );
- UNUSED( garbage );
-
- int mon = mgrd[x][y];
-
- if (mon == NON_MONSTER)
- return (false);
-
- switch (menv[mon].type)
- {
- //case MONS_INSUBSTANTIAL_WISP: //jmf: I'm not sure if these glow or not
- //case MONS_VAPOUR:
- case MONS_UNSEEN_HORROR: // consider making this visible? probably not.
- return (false);
-
- case MONS_FIRE_VORTEX:
- case MONS_ANGEL:
- case MONS_FIEND:
- case MONS_SHADOW:
- case MONS_EFREET:
- case MONS_HELLION:
- case MONS_GLOWING_SHAPESHIFTER:
- case MONS_FIRE_ELEMENTAL:
- case MONS_AIR_ELEMENTAL:
- case MONS_SHADOW_FIEND:
- case MONS_SPECTRAL_WARRIOR:
- case MONS_ORANGE_RAT:
- case MONS_BALRUG:
- case MONS_SPATIAL_VORTEX:
- case MONS_PIT_FIEND:
- case MONS_SHINING_EYE:
- case MONS_DAEVA:
- case MONS_SPECTRAL_THING:
- case MONS_ORB_OF_FIRE:
- case MONS_EYE_OF_DEVASTATION:
- return (false); // already glowing or invisible
- default:
- break;
- }
-
- int lvl = mons_has_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_IV );
-
- if (lvl == ENCH_NONE)
- simple_monster_message( &menv[mon], " is outlined in light." );
- else if (lvl == ENCH_BACKLIGHT_IV)
- simple_monster_message( &menv[mon], " glows brighter for a moment." );
- else
- {
- // remove old level
- mons_del_ench( &menv[mon], ENCH_BACKLIGHT_I, ENCH_BACKLIGHT_III, true );
- simple_monster_message( &menv[mon], " glows brighter." );
- }
-
- // this enchantment wipes out invisibility (neat)
- mons_del_ench( &menv[mon], ENCH_INVIS );
- mons_add_ench( &menv[mon], ENCH_BACKLIGHT_IV );
-
- return (true);
-} // end backlight_monsters()
-
-void cast_evaporate(int pow)
-{
- // experimenting with allowing the potion to be thrown... we're
- // still making it have to be "in hands" at this point. -- bwr
- struct dist spelld;
- struct bolt beem;
-
- const int potion = prompt_invent_item( "Throw which potion?", OBJ_POTIONS );
-
- if (potion == -1)
- {
- snprintf( info, INFO_SIZE, "Wisps of steam play over your %s!",
- your_hand(true) );
-
- mpr(info);
- return;
- }
- else if (you.inv[potion].base_type != OBJ_POTIONS)
- {
- mpr( "This spell works only on potions!" );
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- mpr( STD_DIRECTION_PROMPT, MSGCH_PROMPT );
-
- message_current_target();
-
- direction( spelld, DIR_NONE, TARG_ENEMY );
-
- if (!spelld.isValid)
- {
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- beem.target_x = spelld.tx;
- beem.target_y = spelld.ty;
-
- beem.source_x = you.x_pos;
- beem.source_y = you.y_pos;
-
- strcpy( beem.beam_name, "potion" );
- beem.colour = you.inv[potion].colour;
- beem.range = 9;
- beem.rangeMax = 9;
- beem.type = SYM_FLASK;
- beem.beam_source = MHITYOU;
- beem.thrower = KILL_YOU_MISSILE;
- beem.aux_source = NULL;
- beem.is_beam = false;
- beem.is_tracer = false;
-
- beem.hit = you.dex / 2 + roll_dice( 2, you.skills[SK_RANGED_COMBAT] / 2 + 1 );
- beem.damage = dice_def( 1, 0 ); // no damage, just producing clouds
- beem.ench_power = pow; // used for duration only?
-
- beem.flavour = BEAM_POTION_STINKING_CLOUD;
-
- switch (you.inv[potion].sub_type)
- {
- case POT_STRONG_POISON:
- beem.flavour = BEAM_POTION_POISON;
- beem.ench_power *= 2;
- break;
-
- case POT_DEGENERATION:
- beem.flavour = (coinflip() ? BEAM_POTION_POISON : BEAM_POTION_MIASMA);
- beem.ench_power *= 2;
- break;
-
- case POT_POISON:
- beem.flavour = BEAM_POTION_POISON;
- break;
-
- case POT_DECAY:
- beem.flavour = BEAM_POTION_MIASMA;
- beem.ench_power *= 2;
- break;
-
- case POT_PARALYSIS:
- beem.ench_power *= 2;
- // fall through
- case POT_CONFUSION:
- case POT_SLOWING:
- beem.flavour = BEAM_POTION_STINKING_CLOUD;
- break;
-
- case POT_WATER:
- case POT_PORRIDGE:
- beem.flavour = BEAM_POTION_STEAM;
- break;
-
- case POT_BERSERK_RAGE:
- beem.flavour = (coinflip() ? BEAM_POTION_FIRE : BEAM_POTION_STEAM);
- break;
-
- case POT_MUTATION:
- case POT_GAIN_STRENGTH:
- case POT_GAIN_DEXTERITY:
- case POT_GAIN_INTELLIGENCE:
- case POT_EXPERIENCE:
- case POT_MAGIC:
- switch (random2(5))
- {
- case 0: beem.flavour = BEAM_POTION_FIRE; break;
- case 1: beem.flavour = BEAM_POTION_COLD; break;
- case 2: beem.flavour = BEAM_POTION_POISON; break;
- case 3: beem.flavour = BEAM_POTION_MIASMA; break;
- default: beem.flavour = BEAM_POTION_RANDOM; break;
- }
- break;
-
- default:
- switch (random2(12))
- {
- case 0: beem.flavour = BEAM_POTION_FIRE; break;
- case 1: beem.flavour = BEAM_POTION_STINKING_CLOUD; break;
- case 2: beem.flavour = BEAM_POTION_COLD; break;
- case 3: beem.flavour = BEAM_POTION_POISON; break;
- case 4: beem.flavour = BEAM_POTION_RANDOM; break;
- case 5: beem.flavour = BEAM_POTION_BLUE_SMOKE; break;
- case 6: beem.flavour = BEAM_POTION_BLACK_SMOKE; break;
- case 7: beem.flavour = BEAM_POTION_PURP_SMOKE; break;
- default: beem.flavour = BEAM_POTION_STEAM; break;
- }
- break;
- }
-
- if (coinflip())
- exercise( SK_RANGED_COMBAT, 1 );
-
- fire_beam(beem);
-
- // both old and new code use up a potion:
- dec_inv_item_quantity( potion, 1 );
-
- return;
-} // end cast_evaporate()
-
-// The intent of this spell isn't to produce helpful potions
-// for drinking, but rather to provide ammo for the Evaporate
-// spell out of corpses, thus potentially making it useful.
-// Producing helpful potions would break game balance here...
-// and producing more than one potion from a corpse, or not
-// using up the corpse might also lead to game balance problems. -- bwr
-void cast_fulsome_distillation( int powc )
-{
- char str_pass[ ITEMNAME_SIZE ];
-
- if (powc > 50)
- powc = 50;
-
- int corpse = -1;
-
- // Search items at the players location for corpses.
- // XXX: Turn this into a separate function and merge with
- // the messes over in butchery, animating, and maybe even
- // item pickup from stacks (which would make it easier to
- // create a floor stack menu system later) -- bwr
- for (int curr_item = igrd[you.x_pos][you.y_pos];
- curr_item != NON_ITEM;
- curr_item = mitm[curr_item].link)
- {
- if (mitm[curr_item].base_type == OBJ_CORPSES
- && mitm[curr_item].sub_type == CORPSE_BODY)
- {
- it_name( curr_item, DESC_NOCAP_THE, str_pass );
- snprintf( info, INFO_SIZE, "Distill a potion from %s?", str_pass );
-
- if (yesno( info, true, 0, false ))
- {
- corpse = curr_item;
- break;
- }
- }
- }
-
- if (corpse == -1)
- {
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- const bool rotten = (mitm[corpse].special < 100);
- const bool big_monster = (mons_type_hit_dice( mitm[corpse].plus ) >= 5);
- const bool power_up = (rotten && big_monster);
-
- int potion_type = POT_WATER;
-
- switch (mitm[corpse].plus)
- {
- case MONS_GIANT_BAT: // extracting batty behaviour : 1
- case MONS_UNSEEN_HORROR: // extracting batty behaviour : 7
- case MONS_GIANT_BLOWFLY: // extracting batty behaviour : 5
- potion_type = POT_CONFUSION;
- break;
-
- case MONS_RED_WASP: // paralysis attack : 8
- case MONS_YELLOW_WASP: // paralysis attack : 4
- potion_type = POT_PARALYSIS;
- break;
-
- case MONS_SNAKE: // clean meat, but poisonous attack : 2
- case MONS_GIANT_ANT: // clean meat, but poisonous attack : 3
- potion_type = (power_up ? POT_POISON : POT_CONFUSION);
- break;
-
- case MONS_ORANGE_RAT: // poisonous meat, but draining attack : 3
- potion_type = (power_up ? POT_DECAY : POT_POISON);
- break;
-
- case MONS_SPINY_WORM: // 12
- potion_type = (power_up ? POT_DECAY : POT_STRONG_POISON);
- break;
-
- default:
- switch (mons_corpse_effect( mitm[corpse].plus ))
- {
- case CE_CLEAN:
- potion_type = (power_up ? POT_CONFUSION : POT_WATER);
- break;
-
- case CE_CONTAMINATED:
- potion_type = (power_up ? POT_DEGENERATION : POT_POISON);
- break;
-
- case CE_POISONOUS:
- potion_type = (power_up ? POT_STRONG_POISON : POT_POISON);
- break;
-
- case CE_MUTAGEN_RANDOM:
- case CE_MUTAGEN_GOOD: // unused
- case CE_RANDOM: // unused
- potion_type = POT_MUTATION;
- break;
-
- case CE_MUTAGEN_BAD: // unused
- case CE_ROTTEN: // actually this only occurs via mangling
- case CE_HCL: // necrophage
- potion_type = (power_up ? POT_DECAY : POT_STRONG_POISON);
- break;
-
- case CE_NOCORPSE: // shouldn't occur
- default:
- break;
- }
- break;
- }
-
- // If not powerful enough, we downgrade the potion
- if (random2(50) > powc + 10 * rotten)
- {
- switch (potion_type)
- {
- case POT_DECAY:
- case POT_DEGENERATION:
- case POT_STRONG_POISON:
- potion_type = POT_POISON;
- break;
-
- case POT_MUTATION:
- case POT_POISON:
- potion_type = POT_CONFUSION;
- break;
-
- case POT_PARALYSIS:
- potion_type = POT_SLOWING;
- break;
-
- case POT_CONFUSION:
- case POT_SLOWING:
- default:
- potion_type = POT_WATER;
- break;
- }
- }
-
- // We borrow the corpse's object to make our potion:
- mitm[corpse].base_type = OBJ_POTIONS;
- mitm[corpse].sub_type = potion_type;
- mitm[corpse].quantity = 1;
- mitm[corpse].plus = 0;
- mitm[corpse].plus2 = 0;
- item_colour( mitm[corpse] ); // sets special as well
-
- it_name( corpse, DESC_NOCAP_A, str_pass );
- snprintf( info, INFO_SIZE, "You extract %s from the corpse.",
- str_pass );
- mpr( info );
-
- // try to move the potion to the player (for convenience)
- if (move_item_to_player( corpse, 1 ) != 1)
- {
- mpr( "Unfortunately, you can't carry it right now!" );
- }
-}
-
-void make_shuggoth(int x, int y, int hp)
-{
- int mon = create_monster( MONS_SHUGGOTH, 100 + random2avg(58, 3),
- BEH_HOSTILE, x, y, MHITNOT, 250 );
-
- if (mon != -1)
- {
- menv[mon].hit_points = hp;
- menv[mon].max_hit_points = hp;
- }
-
- return;
-} // end make_shuggoth()
-
-static int rot_living(int x, int y, int pow, int message)
-{
- UNUSED( message );
-
- int mon = mgrd[x][y];
- int ench;
-
- if (mon == NON_MONSTER)
- return 0;
-
- if (mons_holiness(&menv[mon]) != MH_NATURAL)
- return 0;
-
- if (check_mons_resist_magic(&menv[mon], pow))
- return 0;
-
- ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
-
- if (ench >= 50)
- ench = ENCH_YOUR_ROT_IV;
- else if (ench >= 35)
- ench = ENCH_YOUR_ROT_III;
- else if (ench >= 20)
- ench = ENCH_YOUR_ROT_II;
- else
- ench = ENCH_YOUR_ROT_I;
-
- mons_add_ench(&menv[mon], ench);
-
- return 1;
-} // end rot_living()
-
-static int rot_undead(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- int mon = mgrd[x][y];
- int ench;
-
- if (mon == NON_MONSTER)
- return 0;
-
- if (mons_holiness(&menv[mon]) != MH_UNDEAD)
- return 0;
-
- if (check_mons_resist_magic(&menv[mon], pow))
- return 0;
-
- // this does not make sense -- player mummies are
- // immune to rotting (or have been) -- so what is
- // the schema in use here to determine rotting??? {dlb}
-
- //jmf: up for discussion. it is clearly unfair to
- // rot player mummies.
- // the `shcema' here is: corporeal non-player undead
- // rot, discorporeal undead don't rot. if you wanna
- // insist that monsters get the same treatment as
- // players, I demand my player mummies get to worship
- // the evil mummy & orc god.
- switch (menv[mon].type)
- {
- case MONS_NECROPHAGE:
- case MONS_ZOMBIE_SMALL:
- case MONS_LICH:
- case MONS_MUMMY:
- case MONS_VAMPIRE:
- case MONS_ZOMBIE_LARGE:
- case MONS_WIGHT:
- case MONS_GHOUL:
- case MONS_BORIS:
- case MONS_ANCIENT_LICH:
- case MONS_VAMPIRE_KNIGHT:
- case MONS_VAMPIRE_MAGE:
- case MONS_GUARDIAN_MUMMY:
- case MONS_GREATER_MUMMY:
- case MONS_MUMMY_PRIEST:
- break;
- case MONS_ROTTING_HULK:
- default:
- return 0; // immune (no flesh) or already rotting
- }
-
- ench = ((random2(pow) + random2(pow) + random2(pow) + random2(pow)) / 4);
-
- if (ench >= 50)
- ench = ENCH_YOUR_ROT_IV;
- else if (ench >= 35)
- ench = ENCH_YOUR_ROT_III;
- else if (ench >= 20)
- ench = ENCH_YOUR_ROT_II;
- else
- ench = ENCH_YOUR_ROT_I;
-
- mons_add_ench(&menv[mon], ench);
-
- return 1;
-} // end rot_undead()
-
-static int rot_corpses(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- return make_a_rot_cloud(x, y, pow, CLOUD_MIASMA);
-} // end rot_corpses()
-
-void cast_rotting(int pow)
-{
- apply_area_visible(rot_living, pow);
- apply_area_visible(rot_undead, pow);
- apply_area_visible(rot_corpses, pow);
- return;
-} // end cast_rotting()
-
-void do_monster_rot(int mon)
-{
- int damage = 1 + random2(3);
-
- if (mons_holiness(&menv[mon]) == MH_UNDEAD && random2(5))
- {
- apply_area_cloud(make_a_normal_cloud, menv[mon].x, menv[mon].y,
- 10, 1, CLOUD_MIASMA);
- }
-
- player_hurt_monster( mon, damage );
- return;
-} // end do_monster_rot()
-
-static int snake_charm_monsters(int x, int y, int pow, int message)
-{
- UNUSED( message );
-
- int mon = mgrd[x][y];
-
- if (mon == NON_MONSTER) return 0;
- if (mons_friendly(&menv[mon])) return 0;
- if (one_chance_in(4)) return 0;
- if (mons_char(menv[mon].type) != 'S') return 0;
- if (check_mons_resist_magic(&menv[mon], pow)) return 0;
-
- menv[mon].attitude = ATT_FRIENDLY;
- snprintf( info, INFO_SIZE, "%s sways back and forth.", ptr_monam( &(menv[mon]), DESC_CAP_THE ));
- mpr(info);
-
- return 1;
-}
-
-void cast_snake_charm(int pow)
-{
- // powc = (you.experience_level * 2) + (you.skills[SK_INVOCATIONS] * 3);
- apply_one_neighbouring_square(snake_charm_monsters, pow);
-}
-
-void cast_fragmentation(int pow) // jmf: ripped idea from airstrike
-{
- struct dist beam;
- struct bolt blast;
- int debris = 0;
- int trap;
- bool explode = false;
- bool hole = true;
- const char *what = NULL;
-
- mpr("Fragment what (e.g. a wall)?", MSGCH_PROMPT);
- direction( beam, DIR_TARGET, TARG_ENEMY );
-
- if (!beam.isValid)
- {
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- //FIXME: if (player typed '>' to attack floor) goto do_terrain;
- blast.beam_source = MHITYOU;
- blast.thrower = KILL_YOU;
- blast.aux_source = NULL;
- blast.ex_size = 1; // default
- blast.type = '#';
- blast.colour = 0;
- blast.target_x = beam.tx;
- blast.target_y = beam.ty;
- blast.is_tracer = false;
- blast.flavour = BEAM_FRAG;
-
- // Number of dice vary... 3 is easy/common, but it can get as high as 6.
- blast.damage = dice_def( 0, 5 + pow / 10 );
-
- const int grid = grd[beam.tx][beam.ty];
- const int mon = mgrd[beam.tx][beam.ty];
-
- const bool okay_to_dest = ((beam.tx > 5 && beam.tx < GXM - 5)
- && (beam.ty > 5 && beam.ty < GYM - 5));
-
- if (mon != NON_MONSTER)
- {
- // This needs its own hand_buff... we also need to do it first
- // in case the target dies. -- bwr
- char explode_msg[80];
-
- snprintf( explode_msg, sizeof( explode_msg ), "%s explodes!",
- ptr_monam( &(menv[mon]), DESC_CAP_THE ) );
-
- switch (menv[mon].type)
- {
- case MONS_ICE_BEAST: // blast of ice fragments
- case MONS_SIMULACRUM_SMALL:
- case MONS_SIMULACRUM_LARGE:
- explode = true;
- strcpy(blast.beam_name, "icy blast");
- blast.colour = WHITE;
- blast.damage.num = 2;
- blast.flavour = BEAM_ICE;
- if (player_hurt_monster(mon, roll_dice( blast.damage )))
- blast.damage.num += 1;
- break;
-
- case MONS_FLYING_SKULL:
- case MONS_SKELETON_SMALL:
- case MONS_SKELETON_LARGE: // blast of bone
- explode = true;
-
- snprintf( info, INFO_SIZE, "The sk%s explodes into sharp fragments of bone!",
- (menv[mon].type == MONS_FLYING_SKULL) ? "ull" : "eleton");
-
- strcpy(blast.beam_name, "blast of bone shards");
-
- blast.colour = LIGHTGREY;
-
- if (random2(50) < (pow / 5)) // potential insta-kill
- {
- monster_die(&menv[mon], KILL_YOU, 0);
- blast.damage.num = 4;
- }
- else
- {
- blast.damage.num = 2;
- if (player_hurt_monster(mon, roll_dice( blast.damage )))
- blast.damage.num = 4;
- }
- goto all_done; // i.e. no "Foo Explodes!"
-
- case MONS_WOOD_GOLEM:
- explode = false;
- simple_monster_message(&menv[mon], " shudders violently!");
-
- // We use blast.damage not only for inflicting damage here,
- // but so that later on we'll know that the spell didn't
- // fizzle (since we don't actually explode wood golems). -- bwr
- blast.damage.num = 2;
- player_hurt_monster( mon, roll_dice( blast.damage ) );
- break;
-
- case MONS_IRON_GOLEM:
- case MONS_METAL_GARGOYLE:
- explode = true;
- strcpy( blast.beam_name, "blast of metal fragments" );
- blast.colour = CYAN;
- blast.damage.num = 4;
- if (player_hurt_monster(mon, roll_dice( blast.damage )))
- blast.damage.num += 2;
- break;
-
- case MONS_CLAY_GOLEM: // assume baked clay and not wet loam
- case MONS_STONE_GOLEM:
- case MONS_EARTH_ELEMENTAL:
- case MONS_GARGOYLE:
- explode = true;
- blast.ex_size = 2;
- strcpy(blast.beam_name, "blast of rock fragments");
- blast.colour = BROWN;
- blast.damage.num = 3;
- if (player_hurt_monster(mon, roll_dice( blast.damage )))
- blast.damage.num += 1;
- break;
-
- case MONS_CRYSTAL_GOLEM:
- explode = true;
- blast.ex_size = 2;
- strcpy(blast.beam_name, "blast of crystal shards");
- blast.colour = WHITE;
- blast.damage.num = 4;
- if (player_hurt_monster(mon, roll_dice( blast.damage )))
- blast.damage.num += 2;
- break;
-
- default:
- blast.damage.num = 1; // to mark that a monster was targetted
-
- // Yes, this spell does lousy damage if the
- // monster isn't susceptable. -- bwr
- player_hurt_monster( mon, roll_dice( 1, 5 + pow / 25 ) );
- goto do_terrain;
- }
-
- mpr( explode_msg );
- goto all_done;
- }
-
- do_terrain:
- // FIXME: do nothing in Abyss & Pandemonium?
-
- switch (grid)
- {
- //
- // Stone and rock terrain
- //
- case DNGN_ROCK_WALL:
- case DNGN_SECRET_DOOR:
- blast.colour = env.rock_colour;
- // fall-through
- case DNGN_STONE_WALL:
- what = "wall";
- if (player_in_branch( BRANCH_HALL_OF_ZOT ))
- blast.colour = env.rock_colour;
- // fall-through
- case DNGN_ORCISH_IDOL:
- if (what == NULL)
- what = "stone idol";
- if (blast.colour == 0)
- blast.colour = DARKGREY;
- // fall-through
- case DNGN_GRANITE_STATUE: // normal rock -- big explosion
- if (what == NULL)
- what = "statue";
-
- explode = true;
-
- strcpy(blast.beam_name, "blast of rock fragments");
- blast.damage.num = 3;
- if (blast.colour == 0)
- blast.colour = LIGHTGREY;
-
- if (okay_to_dest
- && (grid == DNGN_ORCISH_IDOL
- || grid == DNGN_GRANITE_STATUE
- || (pow >= 40 && grid == DNGN_ROCK_WALL && one_chance_in(3))
- || (pow >= 60 && grid == DNGN_STONE_WALL && one_chance_in(10))))
- {
- // terrain blew up real good:
- blast.ex_size = 2;
- grd[beam.tx][beam.ty] = DNGN_FLOOR;
- debris = DEBRIS_ROCK;
- }
- break;
-
- //
- // Metal -- small but nasty explosion
- //
-
- case DNGN_METAL_WALL:
- what = "metal wall";
- blast.colour = CYAN;
- // fallthru
- case DNGN_SILVER_STATUE:
- if (what == NULL)
- {
- what = "silver statue";
- blast.colour = WHITE;
- }
-
- explode = true;
- strcpy( blast.beam_name, "blast of metal fragments" );
- blast.damage.num = 4;
-
- if (okay_to_dest && pow >= 80 && random2(500) < pow / 5)
- {
- blast.damage.num += 2;
- grd[beam.tx][beam.ty] = DNGN_FLOOR;
- debris = DEBRIS_METAL;
- }
- break;
-
- //
- // Crystal
- //
-
- case DNGN_GREEN_CRYSTAL_WALL: // crystal -- large & nasty explosion
- what = "crystal wall";
- blast.colour = GREEN;
- // fallthru
- case DNGN_ORANGE_CRYSTAL_STATUE:
- if (what == NULL)
- {
- what = "crystal statue";
- blast.colour = LIGHTRED; //jmf: == orange, right?
- }
-
- explode = true;
- blast.ex_size = 2;
- strcpy(blast.beam_name, "blast of crystal shards");
- blast.damage.num = 5;
-
- if (okay_to_dest
- && ((grid == DNGN_GREEN_CRYSTAL_WALL && coinflip())
- || (grid == DNGN_ORANGE_CRYSTAL_STATUE
- && pow >= 50 && one_chance_in(10))))
- {
- blast.ex_size = coinflip() ? 3 : 2;
- grd[beam.tx][beam.ty] = DNGN_FLOOR;
- debris = DEBRIS_CRYSTAL;
- }
- break;
-
- //
- // Traps
- //
-
- case DNGN_UNDISCOVERED_TRAP:
- case DNGN_TRAP_MECHANICAL:
- trap = trap_at_xy( beam.tx, beam.ty );
- if (trap != -1
- && trap_category( env.trap[trap].type ) != DNGN_TRAP_MECHANICAL)
- {
- // non-mechanical traps don't explode with this spell -- bwr
- break;
- }
-
- // undiscovered traps appear as exploding from the floor -- bwr
- what = ((grid == DNGN_UNDISCOVERED_TRAP) ? "floor" : "trap");
-
- explode = true;
- hole = false; // to hit monsters standing on traps
- strcpy( blast.beam_name, "blast of fragments" );
- blast.colour = env.floor_colour; // in order to blend in
- blast.damage.num = 2;
-
- // Exploded traps are nonfunctional, ammo is also ruined -- bwr
- if (okay_to_dest)
- {
- grd[beam.tx][beam.ty] = DNGN_FLOOR;
- env.trap[trap].type = TRAP_UNASSIGNED;
- }
- break;
-
- //
- // Stone doors and arches
- //
-
- case DNGN_OPEN_DOOR:
- case DNGN_CLOSED_DOOR:
- // Doors always blow up, stone arches never do (would cause problems)
- if (okay_to_dest)
- grd[beam.tx][beam.ty] = DNGN_FLOOR;
-
- // fall-through
- case DNGN_STONE_ARCH: // floor -- small explosion
- explode = true;
- hole = false; // to hit monsters standing on doors
- strcpy( blast.beam_name, "blast of rock fragments" );
- blast.colour = LIGHTGREY;
- blast.damage.num = 2;
- break;
-
- //
- // Permarock and floor are unaffected -- bwr
- //
- case DNGN_PERMAROCK_WALL:
- case DNGN_FLOOR:
- explode = false;
- snprintf( info, INFO_SIZE, "%s seems to be unnaturally hard.",
- (grid == DNGN_PERMAROCK_WALL) ? "That wall"
- : "The dungeon floor" );
- explode = false;
- break;
-
- case DNGN_TRAP_III: // What are these? Should they explode? -- bwr
- default:
- // FIXME: cute message for water?
- break;
- }
-
- all_done:
- if (explode && blast.damage.num > 0)
- {
- if (what != NULL)
- {
- snprintf( info, INFO_SIZE, "The %s explodes!", what);
- mpr(info);
- }
-
- explosion( blast, hole );
- }
- else if (blast.damage.num == 0)
- {
- // if damage dice are zero we assume that nothing happened at all.
- canned_msg(MSG_SPELL_FIZZLES);
- }
-
- if (debris)
- place_debris(beam.tx, beam.ty, debris);
-} // end cast_fragmentation()
-
-void cast_twist(int pow)
-{
- struct dist targ;
- struct bolt tmp; // used, but ignored
-
- // level one power cap -- bwr
- if (pow > 25)
- pow = 25;
-
- // Get target, using DIR_TARGET for targetting only,
- // since we don't use fire_beam() for this spell.
- if (spell_direction(targ, tmp, DIR_TARGET) == -1)
- return;
-
- const int mons = mgrd[ targ.tx ][ targ.ty ];
-
- // anything there?
- if (mons == NON_MONSTER || targ.isMe)
- {
- mpr("There is no monster there!");
- return;
- }
-
- // Monster can magically save vs attack.
- if (check_mons_resist_magic( &menv[ mons ], pow * 2 ))
- {
- simple_monster_message( &menv[ mons ], " resists." );
- return;
- }
-
- // Roll the damage... this spell is pretty low on damage, because
- // it can target any monster in LOS (high utility). This is
- // similar to the damage done by Magic Dart (although, the
- // distribution is much more uniform). -- bwr
- int damage = 1 + random2( 3 + pow / 5 );
-
- // Inflict the damage
- player_hurt_monster( mons, damage );
- return;
-} // end cast_twist()
-
-//
-// This version of far strike is a bit too creative for level one, in
-// order to make it work we needed to put a lot of restrictions on it
-// (like the damage limitation), which wouldn't be necessary if it were
-// a higher level spell. This code might come back as a high level
-// translocation spell later (maybe even with special effects if it's
-// using some of Josh's ideas about occasionally losing the weapon).
-// Would potentially make a good high-level, second book Warper spell
-// (since Translocations is a utility school, it should be higher level
-// that usual... especially if it turns into a flavoured smiting spell).
-// This can all wait until after the next release (as it would be better
-// to have a proper way to do a single weapon strike here (you_attack
-// does far more than we need or want here)). --bwr
-//
-
-void cast_far_strike(int pow)
-{
- struct dist targ;
- struct bolt tmp; // used, but ignored
-
- // Get target, using DIR_TARGET for targetting only,
- // since we don't use fire_beam() for this spell.
- if (spell_direction(targ, tmp, DIR_TARGET) == -1)
- return;
-
- // Get the target monster...
- if (mgrd[targ.tx][targ.ty] == NON_MONSTER
- || targ.isMe)
- {
- mpr("There is no monster there!");
- return;
- }
-
- // Start with weapon base damage...
- const int weapon = you.equip[ EQ_WEAPON ];
-
- int damage = 3; // default unarmed damage
- int speed = 10; // default unarmed time
-
- if (weapon != -1) // if not unarmed
- {
- // look up the damage base
- if (you.inv[ weapon ].base_type == OBJ_WEAPONS)
- {
- damage = property( you.inv[ weapon ], PWPN_DAMAGE );
- speed = property( you.inv[ weapon ], PWPN_SPEED );
-
- if (get_weapon_brand( you.inv[ weapon ] ) == SPWPN_SPEED)
- {
- speed *= 5;
- speed /= 10;
- }
- }
- else if (item_is_staff( you.inv[ weapon ] ))
- {
- damage = property( you.inv[ weapon ], PWPN_DAMAGE );
- speed = property( you.inv[ weapon ], PWPN_SPEED );
- }
- }
-
- // Because we're casting a spell (and don't want to make this level
- // one spell too good), we're not applying skill speed bonuses and at
- // the very least guaranteeing one full turn (speed == 10) like the
- // other spells (if any thing else related to speed is changed, at
- // least leave this right before the application to you.time_taken).
- // Leaving skill out of the speed bonus is an important part of
- // keeping this spell from becoming a "better than actual melee"
- // spell... although, it's fine if that's the case for early Warpers,
- // Fighter types, and such that pick up this trivial first level spell,
- // shouldn't be using it instead of melee (but rather as an accessory
- // long range plinker). Therefore, we tone things down to try and
- // guarantee that the spell is never begins to approach real combat
- // (although the magic resistance check might end up with a higher
- // hit rate than attacking against EV for high level Warpers). -- bwr
- if (speed < 10)
- speed = 10;
-
- you.time_taken *= speed;
- you.time_taken /= 10;
-
- // Apply strength only to damage (since we're only interested in
- // force here, not finesse... the dex/to-hit part of combat is
- // instead handled via magical ability). This part could probably
- // just be removed, as it's unlikely to make any real difference...
- // if it is, the Warper stats in newgame.cc should be changed back
- // to the standard 6 int-4 dex of spellcasters. -- bwr
- int dammod = 78;
- const int dam_stat_val = you.strength;
-
- if (dam_stat_val > 11)
- dammod += (random2(dam_stat_val - 11) * 2);
- else if (dam_stat_val < 9)
- dammod -= (random2(9 - dam_stat_val) * 3);
-
- damage *= dammod;
- damage /= 78;
-
- struct monsters *monster = &menv[ mgrd[targ.tx][targ.ty] ];
-
- // apply monster's AC
- if (monster->armour_class > 0)
- damage -= random2( 1 + monster->armour_class );
-
-#if 0
- // Removing damage limiter since it's categorized at level 4 right now.
-
- // Force transmitted is limited by skill...
- const int limit = (you.skills[SK_TRANSLOCATIONS] + 1) / 2 + 3;
- if (damage > limit)
- damage = limit;
-#endif
-
- // Roll the damage...
- damage = 1 + random2( damage );
-
- // Monster can magically save vs attack (this could be replaced or
- // augmented with an EV check).
- if (check_mons_resist_magic( monster, pow * 2 ))
- {
- simple_monster_message( monster, " resists." );
- return;
- }
-
- // Inflict the damage
- hurt_monster( monster, damage );
- if (monster->hit_points < 1)
- monster_die( monster, KILL_YOU, 0 );
- else
- print_wounds( monster );
-
- return;
-} // end cast_far_strike()
-
-void cast_apportation(int pow)
-{
- struct dist beam;
-
- mpr("Pull items from where?");
-
- direction( beam, DIR_TARGET );
-
- if (!beam.isValid)
- {
- canned_msg(MSG_SPELL_FIZZLES);
- return;
- }
-
- // it's already here!
- if (beam.isMe)
- {
- mpr( "That's just silly." );
- return;
- }
-
- // Protect the player from destroying the item
- const int grid = grd[ you.x_pos ][ you.y_pos ];
-
- if (grid == DNGN_LAVA || grid == DNGN_DEEP_WATER)
- {
- mpr( "That would be silly while over this terrain!" );
- return;
- }
-
- // If this is ever changed to allow moving objects that can't
- // be seen, it should at least only allow moving from squares
- // that have been phyisically (and maybe magically) seen and
- // should probably have a range check as well. In these cases
- // the spell should probably be upped to at least two, or three
- // if magic mapped squares are allowed. Right now it's okay
- // at one... it has a few uses, but you still have to get line
- // of sight to the object first so it will only help a little
- // with snatching runes or the orb (although it can be quite
- // useful for getting items out of statue rooms or the abyss). -- bwr
- if (!see_grid( beam.tx, beam.ty ))
- {
- mpr( "You cannot see there!" );
- return;
- }
-
- // Let's look at the top item in that square...
- const int item = igrd[ beam.tx ][ beam.ty ];
- if (item == NON_ITEM)
- {
- const int mon = mgrd[ beam.tx ][ beam.ty ];
-
- if (mon == NON_MONSTER)
- mpr( "There are no items there." );
- else if (mons_is_mimic( menv[ mon ].type ))
- {
- snprintf( info, INFO_SIZE, "%s twitches.",
- ptr_monam( &(menv[ mon ]), DESC_CAP_THE ) );
- mpr( info );
- }
- else
- mpr( "This spell does not work on creatures." );
-
- return;
- }
-
- // mass of one unit
- const int unit_mass = item_mass( mitm[ item ] );
- // assume we can pull everything
- int max_units = mitm[ item ].quantity;
-
- // item has mass: might not move all of them
- if (unit_mass > 0)
- {
- const int max_mass = pow * 30 + random2( pow * 20 );
-
- // most units our power level will allow
- max_units = max_mass / unit_mass;
- }
-
- if (max_units <= 0)
- {
- mpr( "The mass is resisting your pull." );
- return;
- }
-
- // Failure should never really happen after all the above checking,
- // but we'll handle it anyways...
- if (move_top_item( beam.tx, beam.ty, you.x_pos, you.y_pos ))
- {
- if (max_units < mitm[ item ].quantity)
- {
- mitm[ item ].quantity = max_units;
- mpr( "You feel that some mass got lost in the cosmic void." );
- }
- else
- {
- mpr( "Yoink!" );
- snprintf( info, INFO_SIZE, "You pull the item%s to yourself.",
- (mitm[ item ].quantity > 1) ? "s" : "" );
- mpr( info );
- }
- }
- else
- mpr( "The spell fails." );
-}
-
-void cast_sandblast(int pow)
-{
- bool big = true;
- struct dist spd;
- struct bolt beam;
-
- // this type of power manipulation should be done with the others,
- // currently over in it_use2.cc (ack) -- bwr
- // int hurt = 2 + random2(5) + random2(4) + random2(pow) / 20;
-
- big = false;
-
- if (you.equip[EQ_WEAPON] != -1)
- {
- int wep = you.equip[EQ_WEAPON];
- if (you.inv[wep].base_type == OBJ_MISSILES
- && (you.inv[wep].sub_type == MI_STONE || you.inv[wep].sub_type == MI_LARGE_ROCK))
- big = true;
- }
-
- if (spell_direction(spd, beam) == -1)
- return;
-
- if (spd.isMe)
- {
- canned_msg(MSG_UNTHINKING_ACT);
- return;
- }
-
- if (big)
- {
- dec_inv_item_quantity( you.equip[EQ_WEAPON], 1 );
- zapping(ZAP_SANDBLAST, pow, beam);
- }
- else
- {
- zapping(ZAP_SMALL_SANDBLAST, pow, beam);
- }
-} // end cast_sandblast()
-
-void cast_condensation_shield(int pow)
-{
- if (you.equip[EQ_SHIELD] != -1 || you.fire_shield)
- canned_msg(MSG_SPELL_FIZZLES);
- else
- {
- if (you.duration[DUR_CONDENSATION_SHIELD] > 0)
- you.duration[DUR_CONDENSATION_SHIELD] += 5 + roll_dice(2, 3);
- else
- {
- mpr("A crackling disc of dense vapour forms in the air!");
- you.redraw_armour_class = 1;
-
- you.duration[DUR_CONDENSATION_SHIELD] = 10 + roll_dice(2, pow / 5);
- }
-
- if (you.duration[DUR_CONDENSATION_SHIELD] > 30)
- you.duration[DUR_CONDENSATION_SHIELD] = 30;
- }
-
- return;
-} // end cast_condensation_shield()
-
-static int quadrant_blink(int x, int y, int pow, int garbage)
-{
- UNUSED( garbage );
-
- if (x == you.x_pos && y == you.y_pos)
- return (0);
-
- if (you.level_type == LEVEL_ABYSS)
- {
- abyss_teleport( false );
- you.pet_target = MHITNOT;
- return (1);
- }
-
- if (pow > 100)
- pow = 100;
-
- // setup: Brent's new algorithm
- // we are interested in two things: distance of a test point from
- // the ideal 'line', and the distance of a test point from two
- // actual points, one in the 'correct' direction and one in the
- // 'incorrect' direction.
-
- // scale distance by 10 for more interesting numbers.
- int l,m; // for line equation lx + my = 0
- l = (x - you.x_pos);
- m = (you.y_pos - y);
-
- int tx, ty; // test x,y
- int rx, ry; // x,y relative to you.
- int sx, sy; // test point in the correct direction
- int bx = x; // best x
- int by = y; // best y
-
- int best_dist = 10000;
-
- sx = l;
- sy = -m;
-
- // for each point (a,b), distance from the line is | la + mb |
-
- for(int tries = pow * pow / 500 + 1; tries > 0; tries--)
- {
- if (!random_near_space(you.x_pos, you.y_pos, tx, ty))
- return 0;
-
- rx = tx - you.x_pos;
- ry = ty - you.y_pos;
-
- int dist = l * rx + m * ry;
- dist *= 10 * dist; // square and multiply by 10
-
- // check distance to test points
- int dist1 = distance(rx, ry, sx, sy) * 10;
- int dist2 = distance(rx, ry, -sx, -sy) * 10;
-
- // 'good' points will always be closer to test point 1
- if (dist2 < dist1)
- dist += 80; // make the point less attractive
-
- if (dist < best_dist)
- {
- best_dist = dist;
- bx = tx;
- by = ty;
- }
- }
-
- you.x_pos = bx;
- you.y_pos = by;
-
- return (1);
-}
-
-void cast_semi_controlled_blink(int pow)
-{
- apply_one_neighbouring_square(quadrant_blink, pow);
- return;
-}
-
-void cast_stoneskin(int pow)
-{
- if (you.is_undead)
- {
- mpr("This spell does not affect your undead flesh.");
- return;
- }
-
- if (you.attribute[ATTR_TRANSFORMATION] != TRAN_NONE
- && you.attribute[ATTR_TRANSFORMATION] != TRAN_STATUE
- && you.attribute[ATTR_TRANSFORMATION] != TRAN_BLADE_HANDS)
- {
- mpr("This spell does not affect your current form.");
- return;
- }
-
- if (you.duration[DUR_STONEMAIL] || you.duration[DUR_ICY_ARMOUR])
- {
- mpr("This spell conflicts with another spell still in effect.");
- return;
- }
-
- if (you.duration[DUR_STONESKIN])
- mpr( "Your skin feels harder." );
- else
- {
- if (you.attribute[ATTR_TRANSFORMATION] == TRAN_STATUE)
- mpr( "Your stone body feels more resilient." );
- else
- mpr( "Your skin hardens." );
-
- you.redraw_armour_class = 1;
- }
-
- you.duration[DUR_STONESKIN] += 10 + random2(pow) + random2(pow);
-
- if (you.duration[DUR_STONESKIN] > 50)
- you.duration[DUR_STONESKIN] = 50;
-}