diff options
Diffstat (limited to 'stone_soup/crawl-ref/source/spells2.cc')
-rw-r--r-- | stone_soup/crawl-ref/source/spells2.cc | 1602 |
1 files changed, 0 insertions, 1602 deletions
diff --git a/stone_soup/crawl-ref/source/spells2.cc b/stone_soup/crawl-ref/source/spells2.cc deleted file mode 100644 index 3c61fc2aa7..0000000000 --- a/stone_soup/crawl-ref/source/spells2.cc +++ /dev/null @@ -1,1602 +0,0 @@ -/* - * File: spells2.cc - * Summary: Implementations of some additional spells. - * Written by: Linley Henzell - * - * Modified for Crawl Reference by $Author$ on $Date$ - * - * Change History (most recent first): - * - * <4> 03jan1999 jmf Changed summon_small_mammals so at - * higher levels it indeed summons in plural. - * Removed some IMHO unnecessary failure msgs. - * (from e.g. animate_dead). - * Added protection by special deities. - * <3> 10/11/99 BCR fixed range bug in burn_freeze, - * vamp_drain, and summon_elemental - * <2> 5/26/99 JDJ detect_items uses '~' instead of '*'. - * <1> -/--/-- LRH Created - */ - -#include "AppHdr.h" -#include "spells2.h" - -#include <stdio.h> -#include <string.h> - -#include "externs.h" - -#include "beam.h" -#include "cloud.h" -#include "direct.h" -#include "dungeon.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 "ouch.h" -#include "player.h" -#include "randart.h" -#include "spells4.h" -#include "spl-cast.h" -#include "stuff.h" -#include "view.h" -#include "wpn-misc.h" - -int raise_corpse( int corps, int corx, int cory, int corps_beh, - int corps_hit, int actual ); - -unsigned char detect_traps( int pow ) -{ - unsigned char traps_found = 0; - - if (pow > 50) - pow = 50; - - const int range = 8 + random2(8) + pow; - - for (int count_x = 0; count_x < MAX_TRAPS; count_x++) - { - const int etx = env.trap[ count_x ].x; - const int ety = env.trap[ count_x ].y; - - // Used to just be visible screen: - // if (etx > you.x_pos - 15 && etx < you.x_pos + 15 - // && ety > you.y_pos - 8 && ety < you.y_pos + 8) - - if (grid_distance( you.x_pos, you.y_pos, etx, ety ) < range) - { - if (grd[ etx ][ ety ] == DNGN_UNDISCOVERED_TRAP) - { - traps_found++; - - grd[ etx ][ ety ] = trap_category( env.trap[count_x].type ); - env.map[etx - 1][ety - 1] = '^'; - } - } - } - - return (traps_found); -} // end detect_traps() - -unsigned char detect_items( int pow ) -{ - if (pow > 50) - pow = 50; - - unsigned char items_found = 0; - const int map_radius = 8 + random2(8) + pow; - - mpr("You detect items!"); - - for (int i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++) - { - for (int j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++) - { - if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5)) - continue; - - if (igrd[i][j] != NON_ITEM) - { - unsigned short flags = env.map[i - 1][j - 1]; - flags = !flags || (flags & ENVF_DETECTED)? - ENVF_DETECTED - : 0; - env.map[i - 1][j - 1] = '~' | ENVF_DETECT_ITEM | flags; - } - } - } - - return (items_found); -} // end detect_items() - -static void fuzz_detect_creatures(int pow, int *fuzz_radius, int *fuzz_chance) -{ -#ifdef DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "dc_fuzz: Power is %d", pow); -#endif - - if (pow < 1) - pow = 1; - - *fuzz_radius = pow >= 50? 1 : 2; - - // Fuzz chance starts off at 100% and declines to a low of 10% for obscenely - // powerful castings (pow caps around the 60 mark). - *fuzz_chance = 100 - 90 * (pow - 1) / 59; - if (*fuzz_chance < 10) - *fuzz_chance = 10; -} - -static void mark_detected_creature(int gridx, int gridy, const monsters *mon, - int fuzz_chance, int fuzz_radius) -{ - if (fuzz_radius && fuzz_chance > random2(100)) - { - const int fuzz_diam = 2 * fuzz_radius + 1; - - int gx, gy; - bool found_good = false; - for (int itry = 0; itry < 5; ++itry) - { - gx = gridx + random2(fuzz_diam) - fuzz_radius; - gy = gridy + random2(fuzz_diam) - fuzz_radius; - - if (in_map_grid(gx, gy) && !feat_blocks_movement(grd[gx][gy])) - { - found_good = true; - break; - } - } - - if (found_good) - { - gridx = gx; - gridy = gy; - } - } - - const int envx = gridx - 1, - envy = gridy - 1; - - unsigned short flags = env.map[envx][envy]; - flags = !flags || (flags & ENVF_DETECTED)? - ENVF_DETECTED - : 0; - - env.map[envx][envy] = - mons_char( mon->type ) | ENVF_DETECT_MONS | flags; -} - -unsigned char detect_creatures( int pow ) -{ - int fuzz_radius = 0, fuzz_chance = 0; - fuzz_detect_creatures(pow, &fuzz_radius, &fuzz_chance); - - if (pow > 50) - pow = 50; - - unsigned char creatures_found = 0; - const int map_radius = 8 + random2(8) + pow; - - // Clear the map so detect creatures is more useful and the detection - // fuzz is harder to analyse by averaging. - clear_map(); - - mpr("You detect creatures!"); - - for (int i = you.x_pos - map_radius; i < you.x_pos + map_radius; i++) - { - for (int j = you.y_pos - map_radius; j < you.y_pos + map_radius; j++) - { - if (i < 5 || j < 5 || i > (GXM - 5) || j > (GYM - 5)) - continue; - - if (mgrd[i][j] != NON_MONSTER) - { - struct monsters *mon = &menv[ mgrd[i][j] ]; - mark_detected_creature(i, j, mon, fuzz_chance, fuzz_radius); - - // Assuming that highly intelligent spellcasters can - // detect scyring. -- bwr - if (mons_intel( mon->type ) == I_HIGH - && mons_class_flag( mon->type, M_SPELLCASTER )) - { - behaviour_event( mon, ME_DISTURB, MHITYOU, - you.x_pos, you.y_pos ); - } - } - } - } - - return (creatures_found); -} // end detect_creatures() - -int corpse_rot(int power) -{ - UNUSED( power ); - - char adx = 0; - char ady = 0; - - char minx = you.x_pos - 6; - char maxx = you.x_pos + 7; - char miny = you.y_pos - 6; - char maxy = you.y_pos + 7; - char xinc = 1; - char yinc = 1; - - if (coinflip()) - { - minx = you.x_pos + 6; - maxx = you.x_pos - 7; - xinc = -1; - } - - if (coinflip()) - { - miny = you.y_pos + 6; - maxy = you.y_pos - 7; - yinc = -1; - } - - for (adx = minx; adx != maxx; adx += xinc) - { - if (adx == 7 || adx == -7) - return 0; - - for (ady = miny; ady != maxy; ady += yinc) - { - if (see_grid(adx, ady)) - { - if (igrd[adx][ady] == NON_ITEM - || env.cgrid[adx][ady] != EMPTY_CLOUD) - { - continue; - } - - int objl = igrd[adx][ady]; - int hrg = 0; - - while (objl != NON_ITEM) - { - if (mitm[objl].base_type == OBJ_CORPSES - && mitm[objl].sub_type == CORPSE_BODY) - { - if (!mons_skeleton(mitm[objl].plus)) - destroy_item(objl); - else - { - mitm[objl].sub_type = CORPSE_SKELETON; - mitm[objl].special = 200; - mitm[objl].colour = LIGHTGREY; - } - - place_cloud(CLOUD_MIASMA, adx, ady, - 4 + random2avg(16, 3)); - - goto out_of_raise; - } - hrg = mitm[objl].link; - objl = hrg; - } - - out_of_raise: - objl = 1; - } - } - } - - if (you.species != SP_MUMMY) // josh declares mummies cannot smell {dlb} - mpr("You smell decay."); - - // should make zombies decay into skeletons - - return 0; -} // end corpse_rot() - -int animate_dead( int power, int corps_beh, int corps_hit, int actual ) -{ - UNUSED( power ); - - int adx = 0; - int ady = 0; - - int minx = you.x_pos - 6; - int maxx = you.x_pos + 7; - int miny = you.y_pos - 6; - int maxy = you.y_pos + 7; - int xinc = 1; - int yinc = 1; - - int number_raised = 0; - - if (coinflip()) - { - minx = you.x_pos + 6; - maxx = you.x_pos - 7; - xinc = -1; - } - - if (coinflip()) - { - miny = you.y_pos + 6; - maxy = you.y_pos - 7; - yinc = -1; - } - - for (adx = minx; adx != maxx; adx += xinc) - { - if ((adx == 7) || (adx == -7)) - return 0; - - for (ady = miny; ady != maxy; ady += yinc) - { - if (see_grid(adx, ady)) - { - if (igrd[adx][ady] != NON_ITEM) - { - int objl = igrd[adx][ady]; - int hrg = 0; - - //this searches all the items on the ground for a corpse - while (objl != NON_ITEM) - { - if (mitm[objl].base_type == OBJ_CORPSES) - { - number_raised += raise_corpse(objl, adx, ady, - corps_beh, corps_hit, actual); - break; - } - - hrg = mitm[objl].link; - objl = hrg; - } - - objl = 1; - } - } - } - } - - if (actual == 0) - return number_raised; - - if (number_raised > 0) - { - mpr("The dead are walking!"); - //else - // mpr("The dark energy consumes the dead!"); - no, this - // means that no corpses were found. Better to say: - // mpr("You receive no reply."); - //jmf: Why do I have to get an uninformative message when some random - //jmf: monster fails to do something? - // IMHO there's too much noise already. - } - - return number_raised; -} // end animate_dead() - -int animate_a_corpse( int axps, int ayps, int corps_beh, int corps_hit, - int class_allowed ) -{ - if (igrd[axps][ayps] == NON_ITEM) - return 0; - - int objl = igrd[axps][ayps]; - // This searches all the items on the ground for a corpse - while (objl != NON_ITEM) - { - if (mitm[objl].base_type != OBJ_CORPSES - || (class_allowed == CORPSE_SKELETON - && mitm[objl].sub_type != CORPSE_SKELETON)) - { - objl = mitm[objl].link; - continue; - } - - if (raise_corpse(objl, axps, ayps, - corps_beh, corps_hit, 1 ) > 0) - mpr("The dead are walking!"); - break; - } - - return 0; -} // end animate_a_corpse() - -int raise_corpse( int corps, int corx, int cory, - int corps_beh, int corps_hit, int actual ) -{ - int returnVal = 1; - - if (!mons_zombie_size(mitm[corps].plus)) - returnVal = 0; - else if (actual != 0) - { - int type; - if (mitm[corps].sub_type == CORPSE_BODY) - { - if (mons_zombie_size(mitm[corps].plus) == Z_SMALL) - type = MONS_ZOMBIE_SMALL; - else - type = MONS_ZOMBIE_LARGE; - } - else - { - if (mons_zombie_size(mitm[corps].plus) == Z_SMALL) - type = MONS_SKELETON_SMALL; - else - type = MONS_SKELETON_LARGE; - } - - create_monster( type, 0, corps_beh, corx, cory, corps_hit, - mitm[corps].plus ); - - destroy_item(corps); - } - - return returnVal; -} // end raise_corpse() - -void cast_twisted(int power, int corps_beh, int corps_hit) -{ - int total_mass = 0; - int num_corpses = 0; - int type_resurr = MONS_ABOMINATION_SMALL; - char colour; - - unsigned char rotted = 0; - - if (igrd[you.x_pos][you.y_pos] == NON_ITEM) - { - mpr("There's nothing here!"); - return; - } - - int objl = igrd[you.x_pos][you.y_pos]; - int next; - - while (objl != NON_ITEM) - { - next = mitm[objl].link; - - if (mitm[objl].base_type == OBJ_CORPSES - && mitm[objl].sub_type == CORPSE_BODY) - { - total_mass += mons_weight( mitm[objl].plus ); - - num_corpses++; - if (mitm[objl].special < 100) - rotted++; - - destroy_item( objl ); - } - - objl = next; - } - -#if DEBUG_DIAGNOSTICS - snprintf( info, INFO_SIZE, "Mass for abomination: %d", total_mass); - mpr( info, MSGCH_DIAGNOSTICS ); -#endif - - // This is what the old statement pretty much boils down to, - // the average will be approximately 10 * power (or about 1000 - // at the practical maximum). That's the same as the mass - // of a hippogriff, a spiny frog, or a steam dragon. Thus, - // material components are far more important to this spell. -- bwr - total_mass += roll_dice( 20, power ); - -#if DEBUG_DIAGNOSTICS - snprintf( info, INFO_SIZE, "Mass including power bonus: %d", total_mass); - mpr( info, MSGCH_DIAGNOSTICS ); -#endif - - if (total_mass < 400 + roll_dice( 2, 500 ) - || num_corpses < (coinflip() ? 3 : 2)) - { - mpr("The spell fails."); - mpr("The corpses collapse into a pulpy mess."); - return; - } - - if (total_mass > 500 + roll_dice( 3, 1000 )) - type_resurr = MONS_ABOMINATION_LARGE; - - if (rotted == num_corpses) - colour = BROWN; - else if (rotted >= random2( num_corpses )) - colour = RED; - else - colour = LIGHTRED; - - int mon = create_monster( type_resurr, 0, corps_beh, you.x_pos, you.y_pos, - corps_hit, colour ); - - if (mon == -1) - mpr("The corpses collapse into a pulpy mess."); - else - { - mpr("The heap of corpses melds into an agglomeration of writhing flesh!"); - if (type_resurr == MONS_ABOMINATION_LARGE) - { - menv[mon].hit_dice = 8 + total_mass / ((colour == LIGHTRED) ? 500 : - (colour == RED) ? 1000 - : 2500); - - if (menv[mon].hit_dice > 30) - menv[mon].hit_dice = 30; - - // XXX: No convenient way to get the hit dice size right now. - menv[mon].hit_points = hit_points( menv[mon].hit_dice, 2, 5 ); - menv[mon].max_hit_points = menv[mon].hit_points; - - if (colour == LIGHTRED) - menv[mon].armour_class += total_mass / 1000; - } - } -} // end cast_twisted() - -bool brand_weapon(int which_brand, int power) -{ - int temp_rand; // probability determination {dlb} - int duration_affected = 0; //jmf: NB: now HOW LONG, not WHICH BRAND. - - const int wpn = you.equip[EQ_WEAPON]; - - if (you.duration[DUR_WEAPON_BRAND]) - return false; - - if (wpn == -1) - return false; - - if (you.inv[wpn].base_type != OBJ_WEAPONS - || launches_things(you.inv[wpn].sub_type)) - { - return false; - } - - if (is_fixed_artefact( you.inv[wpn] ) - || is_random_artefact( you.inv[wpn] ) - || get_weapon_brand( you.inv[wpn] ) != SPWPN_NORMAL ) - { - return false; - } - - char str_pass[ ITEMNAME_SIZE ]; - in_name( wpn, DESC_CAP_YOUR, str_pass ); - strcpy( info, str_pass ); - - const int wpn_type = damage_type(you.inv[wpn]); - - switch (which_brand) // use SPECIAL_WEAPONS here? - { - case SPWPN_FLAMING: - strcat(info, " bursts into flame!"); - duration_affected = 7; - break; - - case SPWPN_FREEZING: - strcat(info, " glows blue."); - duration_affected = 7; - break; - - case SPWPN_VENOM: - if (wpn_type == DVORP_CRUSHING) - return false; - - strcat(info, " starts dripping with poison."); - duration_affected = 15; - break; - - case SPWPN_DRAINING: - strcat(info, " crackles with unholy energy."); - duration_affected = 12; - break; - - case SPWPN_VORPAL: - if (wpn_type != DVORP_SLICING) - return false; - - strcat(info, " glows silver and looks extremely sharp."); - duration_affected = 10; - break; - - case SPWPN_DISTORTION: //jmf: added for Warp Weapon - strcat(info, " seems to "); - - temp_rand = random2(6); - strcat(info, (temp_rand == 0) ? "twist" : - (temp_rand == 1) ? "bend" : - (temp_rand == 2) ? "vibrate" : - (temp_rand == 3) ? "flex" : - (temp_rand == 4) ? "wobble" - : "twang"); - - strcat( info, coinflip() ? " oddly." : " strangely." ); - duration_affected = 5; - - // [dshaligram] Clamping power to 2. - power = 2; - - // This brand is insanely powerful, this isn't even really - // a start to balancing it, but it needs something. -- bwr - // [dshaligram] At level 7 it's costly enough to experiment - // with removing the miscast effect. We may need to revise the spell - // to level 8 or 9. XXX. - // miscast_effect(SPTYP_TRANSLOCATION, - // 9, 90, 100, "a distortion effect"); - break; - - case SPWPN_DUMMY_CRUSHING: //jmf: added for Maxwell's Silver Hammer - if (wpn_type != DVORP_CRUSHING) - return false; - - which_brand = SPWPN_VORPAL; - strcat(info, " glows silver and feels heavier."); - duration_affected = 7; - break; - } - - set_item_ego_type( you.inv[wpn], OBJ_WEAPONS, which_brand ); - - mpr(info); - you.wield_change = true; - - int dur_change = duration_affected + roll_dice( 2, power ); - - you.duration[DUR_WEAPON_BRAND] += dur_change; - - if (you.duration[DUR_WEAPON_BRAND] > 50) - you.duration[DUR_WEAPON_BRAND] = 50; - - return true; -} // end brand_weapon() - -bool restore_stat(unsigned char which_stat, bool suppress_msg) -{ - bool statRestored = false; - - // a bit hackish, but cut me some slack, man! -- - // besides, a little recursion never hurt anyone {dlb}: - if (which_stat == STAT_ALL) - { - for (unsigned char loopy = STAT_STRENGTH; loopy < NUM_STATS; loopy++) - { - if (restore_stat(loopy, suppress_msg) == true) - statRestored = true; - } - return statRestored; // early return {dlb} - } - - // the real function begins here {dlb}: - char *ptr_stat = 0; // NULL {dlb} - char *ptr_stat_max = 0; // NULL {dlb} - char *ptr_redraw = 0; // NULL {dlb} - - if (!suppress_msg) - strcpy(info, "You feel your "); - - if (which_stat == STAT_RANDOM) - which_stat = random2(NUM_STATS); - - switch (which_stat) - { - case STAT_STRENGTH: - if (!suppress_msg) - strcat(info, "strength"); - - ptr_stat = &you.strength; - ptr_stat_max = &you.max_strength; - ptr_redraw = &you.redraw_strength; - break; - - case STAT_DEXTERITY: - if (!suppress_msg) - strcat(info, "dexterity"); - - ptr_stat = &you.dex; - ptr_stat_max = &you.max_dex; - ptr_redraw = &you.redraw_dexterity; - break; - - case STAT_INTELLIGENCE: - if (!suppress_msg) - strcat(info, "intelligence"); - - ptr_stat = &you.intel; - ptr_stat_max = &you.max_intel; - ptr_redraw = &you.redraw_intelligence; - break; - } - - if (*ptr_stat < *ptr_stat_max) - { - if (!suppress_msg) - { - strcat(info, " returning."); - mpr(info); - } - - *ptr_stat = *ptr_stat_max; - *ptr_redraw = 1; - statRestored = true; - - if (ptr_stat == &you.strength) - burden_change(); - } - - return statRestored; -} // end restore_stat() - -void turn_undead(int pow) -{ - struct monsters *monster; - - mpr("You attempt to repel the undead."); - - for (int tu = 0; tu < MAX_MONSTERS; tu++) - { - monster = &menv[tu]; - - if (monster->type == -1 || !mons_near(monster)) - continue; - - // used to inflict random2(5) + (random2(pow) / 20) damage, - // in addition {dlb} - if (mons_holiness(monster) == MH_UNDEAD) - { - if (check_mons_resist_magic( monster, pow )) - { - simple_monster_message( monster, " resists." ); - continue; - } - - if (!mons_add_ench(monster, ENCH_FEAR)) - continue; - - simple_monster_message( monster, " is repelled!" ); - - //mv: must be here to work - behaviour_event( monster, ME_SCARE, MHITYOU ); - - // reduce power based on monster turned - pow -= monster->hit_dice * 3; - if (pow <= 0) - break; - - } // end "if mons_holiness" - } // end "for tu" -} // end turn_undead() - -void holy_word(int pow, bool silent) -{ - struct monsters *monster; - - if (!silent) - mpr("You speak a Word of immense power!"); - - // doubt this will ever happen, but it's here as a safety -- bwr - if (pow > 300) - pow = 300; - - for (int tu = 0; tu < MAX_MONSTERS; tu++) - { - monster = &menv[tu]; - - if (monster->type == -1 || !mons_near(monster)) - continue; - - if (mons_holiness(monster) == MH_UNDEAD - || mons_holiness(monster) == MH_DEMONIC) - { - simple_monster_message(monster, " convulses!"); - - hurt_monster( monster, roll_dice( 2, 15 ) + (random2(pow) / 3) ); - - if (monster->hit_points < 1) - { - monster_die(monster, KILL_YOU, 0); - continue; - } - - if (monster->speed_increment >= 25) - monster->speed_increment -= 20; - - mons_add_ench(monster, ENCH_FEAR); - } // end "if mons_holiness" - } // end "for tu" -} // end holy_word() - -// poisonous light passes right through invisible players -// and monsters, and so, they are unaffected by this spell -- -// assumes only you can cast this spell (or would want to) -void cast_toxic_radiance(void) -{ - struct monsters *monster; - - mpr("You radiate a sickly green light!"); - - show_green = GREEN; - viewwindow(1, false); - more(); - mesclr(); - - // determine whether the player is hit by the radiance: {dlb} - if (you.invis) - { - mpr("The light passes straight through your body."); - } - else if (!player_res_poison()) - { - mpr("You feel rather sick."); - poison_player(2); - } - - // determine which monsters are hit by the radiance: {dlb} - for (int toxy = 0; toxy < MAX_MONSTERS; toxy++) - { - monster = &menv[toxy]; - - if (monster->type != -1 && mons_near(monster)) - { - if (!mons_has_ench(monster, ENCH_INVIS)) - { - poison_monster(monster, true); - - if (coinflip()) // 50-50 chance for a "double hit" {dlb} - poison_monster(monster, true); - - } - else if (player_see_invis()) - { - // message player re:"miss" where appropriate {dlb} - strcpy(info, "The light passes through "); - strcat(info, ptr_monam( monster, DESC_NOCAP_THE )); - strcat(info, "."); - mpr(info); - } - } - } -} // end cast_toxic_radiance() - -void cast_refrigeration(int pow) -{ - struct monsters *monster = 0; // NULL {dlb} - int hurted = 0; - struct bolt beam; - int toxy; - - beam.flavour = BEAM_COLD; - - const dice_def dam_dice( 3, 5 + pow / 10 ); - - mpr("The heat is drained from your surroundings."); - - show_green = LIGHTCYAN; - viewwindow(1, false); - more(); - mesclr(); - - // Do the player: - hurted = roll_dice( dam_dice ); - hurted = check_your_resists( hurted, beam.flavour ); - - if (hurted > 0) - { - mpr("You feel very cold."); - ouch( hurted, 0, KILLED_BY_FREEZING ); - - // Note: this used to be 12!... and it was also applied even if - // the player didn't take damage from the cold, so we're being - // a lot nicer now. -- bwr - scrolls_burn( 5, OBJ_POTIONS ); - } - - // Now do the monsters: - for (toxy = 0; toxy < MAX_MONSTERS; toxy++) - { - monster = &menv[toxy]; - - if (monster->type == -1) - continue; - - if (mons_near(monster)) - { - snprintf( info, INFO_SIZE, "You freeze %s.", - ptr_monam( monster, DESC_NOCAP_THE )); - - mpr(info); - - hurted = roll_dice( dam_dice ); - hurted = mons_adjust_flavoured( monster, beam, hurted ); - - if (hurted > 0) - { - hurt_monster( monster, hurted ); - - if (monster->hit_points < 1) - monster_die(monster, KILL_YOU, 0); - else - { - print_wounds(monster); - - //jmf: "slow snakes" finally available - if (mons_class_flag( monster->type, M_COLD_BLOOD ) && coinflip()) - mons_add_ench(monster, ENCH_SLOW); - } - } - } - } -} // end cast_refrigeration() - -void drain_life(int pow) -{ - int hp_gain = 0; - int hurted = 0; - struct monsters *monster = 0; // NULL {dlb} - - mpr("You draw life from your surroundings."); - - // Incoming power to this function is skill in INVOCATIONS, so - // we'll add an assert here to warn anyone who tries to use - // this function with spell level power. - ASSERT( pow <= 27 ); - - show_green = DARKGREY; - viewwindow(1, false); - more(); - mesclr(); - - for (int toxy = 0; toxy < MAX_MONSTERS; toxy++) - { - monster = &menv[toxy]; - - if (monster->type == -1) - continue; - - if (mons_holiness(monster) != MH_NATURAL) - continue; - - if (mons_res_negative_energy( monster )) - continue; - - if (mons_near(monster)) - { - strcpy(info, "You draw life from "); - strcat(info, ptr_monam( monster, DESC_NOCAP_THE )); - strcat(info, "."); - mpr(info); - - hurted = 3 + random2(7) + random2(pow); - - hurt_monster(monster, hurted); - - hp_gain += hurted; - - if (monster->hit_points < 1) - monster_die(monster, KILL_YOU, 0); - else - print_wounds(monster); - } - } - - hp_gain /= 2; - - if (hp_gain > pow * 2) - hp_gain = pow * 2; - - if (hp_gain) - { - mpr( "You feel life flooding into your body." ); - inc_hp( hp_gain, false ); - } -} // end drain_life() - -int vampiric_drain(int pow) -{ - int inflicted = 0; - int mgr = 0; - struct monsters *monster = 0; // NULL - struct dist vmove; - - dirc: - mpr("Which direction?", MSGCH_PROMPT); - direction( vmove, DIR_DIR, TARG_ENEMY ); - - if (!vmove.isValid) - { - canned_msg(MSG_SPELL_FIZZLES); - return -1; - } - - mgr = mgrd[you.x_pos + vmove.dx][you.y_pos + vmove.dy]; - - if (vmove.dx == 0 && vmove.dy == 0) - { - mpr("You can't do that."); - goto dirc; - } - - if (mgr == NON_MONSTER) - { - mpr("There isn't anything there!"); - return -1; - } - - monster = &menv[mgr]; - - const int holy = mons_holiness(monster); - - if (holy == MH_UNDEAD || holy == MH_DEMONIC) - { - mpr("Aaaarggghhhhh!"); - dec_hp(random2avg(39, 2) + 10, false); - return -1; - } - - if (mons_res_negative_energy( monster )) - { - canned_msg(MSG_NOTHING_HAPPENS); - return -1; - } - - // The practical maximum of this is about 25 (pow @ 100). -- bwr - inflicted = 3 + random2avg( 9, 2 ) + random2(pow) / 7; - - if (inflicted >= monster->hit_points) - inflicted = monster->hit_points; - - if (inflicted >= you.hp_max - you.hp) - inflicted = you.hp_max - you.hp; - - if (inflicted == 0) - { - canned_msg(MSG_NOTHING_HAPPENS); - return -1; - } - - hurt_monster(monster, inflicted); - - strcpy(info, "You feel life coursing from "); - strcat(info, ptr_monam( monster, DESC_NOCAP_THE )); - strcat(info, " into your body!"); - mpr(info); - - print_wounds(monster); - - if (monster->hit_points < 1) - monster_die(monster, KILL_YOU, 0); - - inc_hp(inflicted / 2, false); - - return 1; -} // end vampiric_drain() - -// Note: this function is currently only used for Freeze. -- bwr -char burn_freeze(int pow, char flavour) -{ - int mgr = NON_MONSTER; - struct monsters *monster = 0; // NULL {dlb} - struct dist bmove; - - if (pow > 25) - pow = 25; - - while (mgr == NON_MONSTER) - { - mpr("Which direction?", MSGCH_PROMPT); - direction( bmove, DIR_DIR, TARG_ENEMY ); - - if (!bmove.isValid) - { - canned_msg(MSG_SPELL_FIZZLES); - return -1; - } - - if (bmove.isMe) - { - canned_msg(MSG_UNTHINKING_ACT); - return -1; - } - - mgr = mgrd[you.x_pos + bmove.dx][you.y_pos + bmove.dy]; - - // Yes, this is strange, but it does maintain the original behaviour - if (mgr == NON_MONSTER) - { - mpr("There isn't anything close enough!"); - return -1; - } - } - - monster = &menv[mgr]; - - strcpy(info, "You "); - strcat(info, (flavour == BEAM_FIRE) ? "burn" : - (flavour == BEAM_COLD) ? "freeze" : - (flavour == BEAM_MISSILE) ? "crush" : - (flavour == BEAM_ELECTRICITY) ? "zap" - : "______"); - - strcat(info, " "); - strcat(info, ptr_monam( monster, DESC_NOCAP_THE )); - strcat(info, "."); - mpr(info); - - int hurted = roll_dice( 1, 3 + pow / 3 ); - - struct bolt beam; - - beam.flavour = flavour; - - if (flavour != BEAM_MISSILE) - hurted = mons_adjust_flavoured(monster, beam, hurted); - - if (hurted) - { - hurt_monster(monster, hurted); - - if (monster->hit_points < 1) - monster_die(monster, KILL_YOU, 0); - else - { - print_wounds(monster); - - if (flavour == BEAM_COLD) - { - if (mons_class_flag( monster->type, M_COLD_BLOOD ) && coinflip()) - mons_add_ench(monster, ENCH_SLOW); - - const int cold_res = mons_res_cold( monster ); - if (cold_res <= 0) - { - const int stun = (1 - cold_res) * random2( 2 + pow / 5 ); - monster->speed_increment -= stun; - } - } - } - } - - return 1; -} // end burn_freeze() - -// 'unfriendly' is percentage chance summoned elemental goes -// postal on the caster (after taking into account -// chance of that happening to unskilled casters -// anyway) -int summon_elemental(int pow, int restricted_type, - unsigned char unfriendly) -{ - int type_summoned = MONS_PROGRAM_BUG; // error trapping {dlb} - char summ_success = 0; - struct dist smove; - - int dir_x; - int dir_y; - int targ_x; - int targ_y; - - int numsc = ENCH_ABJ_II + (random2(pow) / 5); - - if (numsc > ENCH_ABJ_VI) - numsc = ENCH_ABJ_VI; - - for (;;) - { - mpr("Summon from material in which direction?", MSGCH_PROMPT); - - direction( smove, DIR_DIR ); - - if (!smove.isValid) - { - canned_msg(MSG_NOTHING_HAPPENS); - return (-1); - } - - dir_x = smove.dx; - dir_y = smove.dy; - targ_x = you.x_pos + dir_x; - targ_y = you.y_pos + dir_y; - - if (mgrd[ targ_x ][ targ_y ] != NON_MONSTER) - mpr("Not there!"); - else if (dir_x == 0 && dir_y == 0) - mpr("You can't summon an elemental from yourself!"); - else - break; - } - - if (grd[ targ_x ][ targ_y ] == DNGN_ROCK_WALL - && (restricted_type == 0 || restricted_type == MONS_EARTH_ELEMENTAL)) - { - type_summoned = MONS_EARTH_ELEMENTAL; - - if (targ_x > 6 && targ_x < 74 && targ_y > 6 && targ_y < 64) - grd[ targ_x ][ targ_y ] = DNGN_FLOOR; - } - else if ((env.cgrid[ targ_x ][ targ_y ] != EMPTY_CLOUD - && (env.cloud[env.cgrid[ targ_x ][ targ_y ]].type == CLOUD_FIRE - || env.cloud[env.cgrid[ targ_x ][ targ_y ]].type == CLOUD_FIRE_MON)) - && (restricted_type == 0 || restricted_type == MONS_FIRE_ELEMENTAL)) - { - type_summoned = MONS_FIRE_ELEMENTAL; - delete_cloud( env.cgrid[ targ_x ][ targ_y ] ); - } - else if ((grd[ targ_x ][ targ_y ] == DNGN_LAVA) - && (restricted_type == 0 || restricted_type == MONS_FIRE_ELEMENTAL)) - { - type_summoned = MONS_FIRE_ELEMENTAL; - } - else if ((grd[ targ_x ][ targ_y ] == DNGN_DEEP_WATER - || grd[ targ_x ][ targ_y ] == DNGN_SHALLOW_WATER - || grd[ targ_x ][ targ_y ] == DNGN_BLUE_FOUNTAIN) - && (restricted_type == 0 || restricted_type == MONS_WATER_ELEMENTAL)) - { - type_summoned = MONS_WATER_ELEMENTAL; - } - else if ((grd[ targ_x ][ targ_y ] >= DNGN_FLOOR - && env.cgrid[ targ_x ][ targ_y ] == EMPTY_CLOUD) - && (restricted_type == 0 || restricted_type == MONS_AIR_ELEMENTAL)) - { - type_summoned = MONS_AIR_ELEMENTAL; - } - - // found something to summon - if (type_summoned == MONS_PROGRAM_BUG) - { - canned_msg(MSG_NOTHING_HAPPENS); - return (-1); - } - - // silly - ice for water? 15jan2000 {dlb} - // little change here to help with the above... and differentiate - // elements a bit... {bwr} - // - Water elementals are now harder to be made reliably friendly - // - Air elementals are harder because they're more dynamic/dangerous - // - Earth elementals are more static and easy to tame (as before) - // - Fire elementals fall in between the two (10 is still fairly easy) - if ((type_summoned == MONS_FIRE_ELEMENTAL - && random2(10) >= you.skills[SK_FIRE_MAGIC]) - - || (type_summoned == MONS_WATER_ELEMENTAL - && random2((you.species == SP_MERFOLK) ? 5 : 15) - >= you.skills[SK_ICE_MAGIC]) - - || (type_summoned == MONS_AIR_ELEMENTAL - && random2(15) >= you.skills[SK_AIR_MAGIC]) - - || (type_summoned == MONS_EARTH_ELEMENTAL - && random2(5) >= you.skills[SK_EARTH_MAGIC]) - - || random2(100) < unfriendly) - { - summ_success = create_monster( type_summoned, numsc, BEH_HOSTILE, - targ_x, targ_y, MHITYOU, 250 ); - - if (summ_success >= 0) - mpr( "The elemental doesn't seem to appreciate being summoned." ); - } - else - { - summ_success = create_monster( type_summoned, numsc, BEH_FRIENDLY, - targ_x, targ_y, you.pet_target, 250 ); - } - - return (summ_success >= 0); -} // end summon_elemental() - -//jmf: beefed up higher-level casting of this (formerly lame) spell -void summon_small_mammals(int pow) -{ - int thing_called = MONS_PROGRAM_BUG; // error trapping{dlb} - - int pow_spent = 0; - int pow_left = pow + 1; - int summoned = 0; - int summoned_max = pow / 16; - - if (summoned_max > 5) - summoned_max = 5; - if (summoned_max < 1) - summoned_max = 1; - - while (pow_left > 0 && summoned < summoned_max) - { - summoned++; - pow_spent = 1 + random2(pow_left); - pow_left -= pow_spent; - - switch (pow_spent) - { - case 75: - case 74: - case 38: - thing_called = MONS_ORANGE_RAT; - break; - - case 65: - case 64: - case 63: - case 27: - case 26: - case 25: - thing_called = MONS_GREEN_RAT; - break; - - case 57: - case 56: - case 55: - case 54: - case 53: - case 52: - case 20: - case 18: - case 16: - case 14: - case 12: - case 10: - thing_called = coinflip() ? MONS_QUOKKA : MONS_GREY_RAT; - break; - - default: - thing_called = coinflip() ? MONS_GIANT_BAT : MONS_RAT; - break; - } - - create_monster( thing_called, ENCH_ABJ_III, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, 250 ); - } -} // end summon_small_mammals() - -void summon_scorpions(int pow) -{ - int numsc = 1 + random2(pow) / 10 + random2(pow) / 10; - - numsc = stepdown_value(numsc, 2, 2, 6, 8); //see stuff.cc - 12jan2000 {dlb} - - for (int scount = 0; scount < numsc; scount++) - { - if (random2(pow) <= 3) - { - if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) - { - mpr("A scorpion appears. It doesn't look very happy."); - } - } - else - { - if (create_monster( MONS_SCORPION, ENCH_ABJ_III, BEH_FRIENDLY, - you.x_pos, you.y_pos, - you.pet_target, 250 ) != -1) - { - mpr("A scorpion appears."); - } - } - } -} // end summon_scorpions() - -void summon_ice_beast_etc(int pow, int ibc, bool divine_gift) -{ - int numsc = ENCH_ABJ_II + (random2(pow) / 4); - int beha = divine_gift? BEH_GOD_GIFT : BEH_FRIENDLY; - - if (numsc > ENCH_ABJ_VI) - numsc = ENCH_ABJ_VI; - - switch (ibc) - { - case MONS_ICE_BEAST: - mpr("A chill wind blows around you."); - break; - - case MONS_IMP: - mpr("A beastly little devil appears in a puff of flame."); - break; - - case MONS_WHITE_IMP: - mpr("A beastly little devil appears in a puff of frigid air."); - break; - - case MONS_SHADOW_IMP: - mpr("A shadowy apparition takes form in the air."); - break; - - case MONS_ANGEL: - mpr("You open a gate to the realm of Zin!"); - break; - - case MONS_DAEVA: - mpr("You are momentarily dazzled by a brilliant golden light."); - break; - - default: - mpr("A demon appears!"); - if (random2(pow) < 4) - { - beha = BEH_HOSTILE; - mpr("It doesn't look very happy."); - } - break; - - } - - create_monster( ibc, numsc, beha, you.x_pos, you.y_pos, MHITYOU, 250 ); -} // end summon_ice_beast_etc() - -bool summon_swarm( int pow, bool unfriendly, bool god_gift ) -{ - int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb} - int numsc = 2 + random2(pow) / 10 + random2(pow) / 25; - bool summoned = false; - - // see stuff.cc - 12jan2000 {dlb} - numsc = stepdown_value( numsc, 2, 2, 6, 8 ); - - for (int scount = 0; scount < numsc; scount++) - { - switch (random2(14)) - { - case 0: - case 1: // prototypical swarming creature {dlb} - thing_called = MONS_KILLER_BEE; - break; - - case 2: // comment said "larva", code read scorpion {dlb} - thing_called = MONS_SCORPION; - break; // think: "The Arrival" {dlb} - - case 3: //jmf: technically not insects but still cool - thing_called = MONS_WORM; - break; // but worms kinda "swarm" so s'ok {dlb} - - case 4: // comment read "larva", code was for scorpion - thing_called = MONS_GIANT_MOSQUITO; - break; // changed into giant mosquito 12jan2000 {dlb} - - case 5: // think: scarabs in "The Mummy" {dlb} - thing_called = MONS_GIANT_BEETLE; - break; - - case 6: //jmf: blowfly instead of queen bee - thing_called = MONS_GIANT_BLOWFLY; - break; - - // queen bee added if more than x bees in swarm? {dlb} - // the above would require code rewrite - worth it? {dlb} - - case 8: //jmf: changed to red wasp; was wolf spider - thing_called = MONS_WOLF_SPIDER; //jmf: spiders aren't insects - break; // think: "Kingdom of the Spiders" {dlb} - // not just insects!!! - changed back {dlb} - - case 9: - thing_called = MONS_BUTTERFLY; // comic relief? {dlb} - break; - - case 10: // change into some kind of snake -- {dlb} - thing_called = MONS_YELLOW_WASP; // do wasps swarm? {dlb} - break; // think: "Indiana Jones" and snakepit? {dlb} - - default: // 3 in 14 chance, 12jan2000 {dlb} - thing_called = MONS_GIANT_ANT; - break; - } // end switch - - int behaviour = BEH_HOSTILE; // default to unfriendly - - // Note: friendly, non-god_gift means spell. - if (god_gift) - behaviour = BEH_GOD_GIFT; - else if (!unfriendly && random2(pow) > 7) - behaviour = BEH_FRIENDLY; - - if (create_monster( thing_called, ENCH_ABJ_III, behaviour, - you.x_pos, you.y_pos, MHITYOU, 250 )) - { - summoned = true; - } - } - - return (summoned); -} // end summon_swarm() - -void summon_undead(int pow) -{ - int temp_rand = 0; - int thing_called = MONS_PROGRAM_BUG; // error trapping {dlb} - - int numsc = 1 + random2(pow) / 30 + random2(pow) / 30; - numsc = stepdown_value(numsc, 2, 2, 6, 8); //see stuff.cc {dlb} - - mpr("You call on the undead to aid you!"); - - for (int scount = 0; scount < numsc; scount++) - { - temp_rand = random2(25); - - thing_called = ((temp_rand > 8) ? MONS_WRAITH : // 64% - (temp_rand > 3) ? MONS_SPECTRAL_WARRIOR // 20% - : MONS_FREEZING_WRAITH); // 16% - - if (random2(pow) < 6) - { - if (create_monster( thing_called, ENCH_ABJ_V, BEH_HOSTILE, - you.x_pos, you.y_pos, MHITYOU, 250 ) != -1) - { - mpr("You sense a hostile presence."); - } - } - else - { - if (create_monster( thing_called, ENCH_ABJ_V, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, 250 ) != -1) - { - mpr("An insubstantial figure forms in the air."); - } - } - } // end for loop - - //jmf: Kiku sometimes deflects this - if (!you.is_undead - && !(you.religion == GOD_KIKUBAAQUDGHA - && (!player_under_penance() - && you.piety >= 100 && random2(200) <= you.piety))) - { - disease_player( 25 + random2(50) ); - } -} // end summon_undead() - -void summon_things( int pow ) -{ - int big_things = 0; - int numsc = 2 + (random2(pow) / 10) + (random2(pow) / 10); - - if (one_chance_in(3) && !lose_stat( STAT_INTELLIGENCE, 1, true )) - mpr("Your call goes unanswered."); - else - { - numsc = stepdown_value( numsc, 2, 2, 6, -1 ); - - while (numsc > 2) - { - if (one_chance_in(4)) - break; - - numsc -= 2; - big_things++; - } - - if (numsc > 8) - numsc = 8; - - if (big_things > 8) - big_things = 8; - - while (big_things > 0) - { - create_monster( MONS_TENTACLED_MONSTROSITY, 0, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, 250 ); - big_things--; - } - - while (numsc > 0) - { - create_monster( MONS_ABOMINATION_LARGE, 0, BEH_FRIENDLY, - you.x_pos, you.y_pos, you.pet_target, 250 ); - numsc--; - } - - snprintf( info, INFO_SIZE, "Some Thing%s answered your call!", - (numsc + big_things > 1) ? "s" : "" ); - - mpr(info); - } - - return; -} |