/* * File: it_use3.cc * Summary: Functions for using some of the wackier inventory items. * Written by: Linley Henzell * * Modified for Crawl Reference by $Author$ on $Date$ * * Change History (most recent first): * * <4> 6/13/99 BWR Auto ID Channel staff * <3> 5/22/99 BWR SPWLD_POWER is now HP/13 - 3 * <2> 5/20/99 BWR Capped SPWLD_POWER to +20 * <1> -/--/-- LRH Created */ #include "AppHdr.h" #include "it_use3.h" #include #include #include "externs.h" #include "beam.h" #include "cloud.h" #include "database.h" #include "decks.h" #include "directn.h" #include "effects.h" #include "fight.h" #include "food.h" #include "invent.h" #include "items.h" #include "it_use2.h" #include "itemname.h" #include "itemprop.h" #include "mapmark.h" #include "message.h" #include "misc.h" #include "monplace.h" #include "monstuff.h" #include "overmap.h" #include "player.h" #include "randart.h" #include "religion.h" #include "skills.h" #include "skills2.h" #include "spells1.h" #include "spells2.h" #include "spells3.h" #include "spl-book.h" #include "spl-cast.h" #include "spl-util.h" #include "state.h" #include "stuff.h" #include "view.h" #include "xom.h" static bool ball_of_energy(void); static bool ball_of_fixation(void); static bool ball_of_seeing(void); static bool box_of_beasts(void); static bool disc_of_storms(void); static bool efreet_flask(void); void special_wielded() { const int wpn = you.equip[EQ_WEAPON]; const int old_plus = you.inv[wpn].plus; const int old_plus2 = you.inv[wpn].plus2; const char old_colour = you.inv[wpn].colour; bool makes_noise = false; switch (you.special_wield) { case SPWLD_SING: case SPWLD_NOISE: { makes_noise = (one_chance_in(20) && !silenced(you.x_pos, you.y_pos)); if (makes_noise) { std::string msg; if (you.special_wield == SPWLD_SING) { msg = getSpeakString("Singing Sword"); if (!msg.empty()) { // "Your Singing Sword" sounds disrespectful // (as if there could be more than one!) msg = replace_all(msg, "@Your_weapon@", "@The_weapon@"); msg = replace_all(msg, "@your_weapon@", "@the_weapon@"); } } else // SPWLD_NOISE { msg = getSpeakString("noisy weapon"); if (!msg.empty()) { msg = replace_all(msg, "@Your_weapon@", "Your @weapon@"); msg = replace_all(msg, "@your_weapon@", "your @weapon@"); } } // Set appropriate channel (will usually be TALK). msg_channel_type channel = MSGCH_TALK; // Disallow anything with VISUAL in it. if (!msg.empty() && msg.find("VISUAL") != std::string::npos) msg = ""; if (!msg.empty()) { std::string param = ""; std::string::size_type pos = msg.find(":"); if (pos != std::string::npos) param = msg.substr(0, pos); if (!param.empty()) { bool match = true; if (param == "DANGER") channel = MSGCH_DANGER; else if (param == "WARN") channel = MSGCH_WARN; else if (param == "SOUND") channel = MSGCH_SOUND; else if (param == "PLAIN") channel = MSGCH_PLAIN; else if (param == "SPELL" || param == "ENCHANT") msg = ""; // disallow these as well, channel stays TALK else if (param != "TALK") match = false; if (match && !msg.empty()) msg = msg.substr(pos + 1); } } if (msg.empty()) // give default noises { if (you.special_wield == SPWLD_SING) msg = "@The_weapon@ sings."; else { channel = MSGCH_SOUND; msg = "You hear a strange noise."; } } // replace weapon references msg = replace_all(msg, "@The_weapon@", "The @weapon@"); msg = replace_all(msg, "@the_weapon@", "the @weapon@"); msg = replace_all(msg, "@weapon@", you.inv[wpn].name(DESC_BASENAME)); mpr(msg.c_str(), channel); } // makes_noise break; } case SPWLD_CURSE: if (one_chance_in(30)) curse_an_item(false); break; case SPWLD_VARIABLE: do_uncurse_item( you.inv[wpn] ); if (x_chance_in_y(2, 5)) // 40% chance {dlb} you.inv[wpn].plus += (coinflip() ? +1 : -1); if (x_chance_in_y(2, 5)) // 40% chance {dlb} you.inv[wpn].plus2 += (coinflip() ? +1 : -1); if (you.inv[wpn].plus < -4) you.inv[wpn].plus = -4; else if (you.inv[wpn].plus > 16) you.inv[wpn].plus = 16; if (you.inv[wpn].plus2 < -4) you.inv[wpn].plus2 = -4; else if (you.inv[wpn].plus2 > 16) you.inv[wpn].plus2 = 16; you.inv[wpn].colour = random_colour(); break; case SPWLD_TORMENT: if (one_chance_in(200)) { torment(TORMENT_SPWLD, you.x_pos, you.y_pos); did_god_conduct(DID_UNHOLY, 1); } break; case SPWLD_ZONGULDROK: if (one_chance_in(5)) { animate_dead(&you, 1 + random2(3), BEH_HOSTILE, MHITYOU); did_god_conduct(DID_NECROMANCY, 1); } break; case SPWLD_POWER: you.inv[wpn].plus = stepdown_value( -4 + (you.hp / 5), 4, 4, 4, 20 ); you.inv[wpn].plus2 = you.inv[wpn].plus; break; case SPWLD_OLGREB: // Giving Olgreb's staff a little lift since staves of poison have // been made better. -- bwr you.inv[wpn].plus = you.skills[SK_POISON_MAGIC] / 3; you.inv[wpn].plus2 = you.inv[wpn].plus; break; case SPWLD_WUCAD_MU: you.inv[wpn].plus = ((you.intel > 25) ? 22 : you.intel - 3); you.inv[wpn].plus2 = ((you.intel > 25) ? 13 : you.intel / 2); break; case SPWLD_SHADOW: if (x_chance_in_y(player_spec_death() + 1, 8)) { create_monster( mgen_data(MONS_SHADOW, BEH_FRIENDLY, 2, you.pos(), you.pet_target)); did_god_conduct(DID_NECROMANCY, 1); } show_green = DARKGREY; break; //case SPWLD_PRUNE: default: return; } if (makes_noise) noisy(25, you.x_pos, you.y_pos); if (old_plus != you.inv[wpn].plus || old_plus2 != you.inv[wpn].plus2 || old_colour != you.inv[wpn].colour) { you.wield_change = true; } } // end special_wielded() static bool _reaching_weapon_attack(const item_def& wpn) { dist beam; mpr("Attack whom?", MSGCH_PROMPT); direction(beam, DIR_TARGET, TARG_ENEMY, 2); if (!beam.isValid) return (false); if (beam.isMe) { canned_msg(MSG_UNTHINKING_ACT); return (false); } const int x_distance = abs(beam.tx - you.x_pos); const int y_distance = abs(beam.ty - you.y_pos); if (x_distance > 2 || y_distance > 2) { mpr("Your weapon cannot reach that far!"); return (false); } else if (!see_grid_no_trans(beam.tx, beam.ty)) { mpr("There's a wall in the way."); return (false); } else if (mgrd[beam.tx][beam.ty] == NON_MONSTER) { // Must return true, otherwise you get a free discovery // of invisible monsters. Maybe we shouldn't do practice // here to prevent scumming...but that would just encourage // finding popcorn monsters. mpr("You attack empty space."); return (true); } // BCR - Added a check for monsters in the way. Only checks cardinal // directions. Knight moves are ignored. Assume the weapon // slips between the squares. // If we're attacking more than a space away... if (x_distance > 1 || y_distance > 1) { const int x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2); const int y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2); bool success = false; // If either the x or the y is the same, we should check for // a monster: if ((beam.tx == you.x_pos || beam.ty == you.y_pos) && mgrd[x_middle][y_middle] != NON_MONSTER) { const int skill = weapon_skill( wpn.base_type, wpn.sub_type ); if (x_chance_in_y(5 + (3 * skill), 40)) { mpr("You reach to attack!"); success = you_attack(mgrd[beam.tx][beam.ty], false); } else { mpr("You could not reach far enough!"); return (true); } } else { mpr("You reach to attack!"); success = you_attack(mgrd[beam.tx][beam.ty], false); } if (success) { int mid = mgrd[beam.tx][beam.ty]; if (mid != NON_MONSTER) { monsters *mon = &menv[mgrd[beam.tx][beam.ty]]; if (mons_is_mimic( mon->type )) mimic_alert(mon); } } } else you_attack(mgrd[beam.tx][beam.ty], false); return (true); } static bool evoke_horn_of_geryon() { // Note: This assumes that the Vestibule has not been changed. bool rc = false; if (player_in_branch( BRANCH_VESTIBULE_OF_HELL )) { mpr("You produce a weird and mournful sound."); for (int count_x = 0; count_x < GXM; count_x++) for (int count_y = 0; count_y < GYM; count_y++) { if (grd[count_x][count_y] == DNGN_STONE_ARCH) { rc = true; map_marker *marker = env.markers.find(coord_def(count_x, count_y), MAT_FEATURE); if (marker) { map_feature_marker *featm = dynamic_cast(marker); grd[count_x][count_y] = featm->feat; env.markers.remove(marker); } } } if (rc) mpr("Your way has been unbarred."); } else { mpr("You produce a hideous howling noise!", MSGCH_SOUND); create_monster( mgen_data(MONS_BEAST, BEH_HOSTILE, 4, you.pos(), MHITYOU)); } return (rc); } static bool evoke_sceptre_of_asmodeus() { bool rc = true; if (one_chance_in(21)) rc = false; else if (coinflip()) { // Summon devils, maybe a Fiend. const monster_type mtype = (one_chance_in(4) ? MONS_FIEND : summon_any_demon(DEMON_COMMON)); const bool good_summon = create_monster( mgen_data(mtype, BEH_HOSTILE, 6, you.pos(), MHITYOU)) != -1; if (good_summon) { if (mtype == MONS_FIEND) mpr("\"Your arrogance condemns you, mortal!\""); else mpr("The Sceptre summons one of its servants."); } else mpr("The air shimmers briefly."); } else { // Cast a destructive spell const spell_type spl = static_cast( random_choose_weighted( 114, SPELL_BOLT_OF_FIRE, 57, SPELL_LIGHTNING_BOLT, 57, SPELL_BOLT_OF_DRAINING, 12, SPELL_HELLFIRE, 0 )); your_spells( spl, you.skills[SK_EVOCATIONS] * 8, false ); } return (true); } // Returns true if item successfully evoked. bool evoke_wielded() { int power = 0; int pract = 0; // By how much Evocations is practised. bool did_work = false; // Used for default "nothing happens" message. const int wield = you.equip[EQ_WEAPON]; if (you.duration[DUR_BERSERKER]) { canned_msg( MSG_TOO_BERSERK ); return (false); } else if (wield == -1) { mpr("You aren't wielding anything!"); crawl_state.zero_turns_taken(); return (false); } item_def& wpn = you.inv[wield]; bool unevokable = false; // Check inscriptions. if (!check_warning_inscriptions(wpn, OPER_EVOKE)) return (false); switch (wpn.base_type) { case OBJ_WEAPONS: if (get_weapon_brand(wpn) == SPWPN_REACHING) { if (_reaching_weapon_attack(wpn)) { pract = 0; did_work = true; } else return (false); } else if (is_fixed_artefact( wpn )) { switch (wpn.special) { case SPWPN_STAFF_OF_DISPATER: if (you.duration[DUR_DEATHS_DOOR] || !enough_hp(11, true) || !enough_mp(5, true)) { break; } mpr("You feel the staff feeding on your energy!"); dec_hp( 5 + random2avg(19, 2), false, "Staff of Dispater" ); dec_mp( 2 + random2avg(5, 2) ); make_hungry(100, false, true); power = you.skills[SK_EVOCATIONS] * 8; your_spells( SPELL_HELLFIRE, power, false ); pract = (coinflip() ? 2 : 1); did_work = true; break; case SPWPN_SCEPTRE_OF_ASMODEUS: if (evoke_sceptre_of_asmodeus()) { make_hungry(200, false, true); did_work = true; pract = 1; } break; case SPWPN_STAFF_OF_OLGREB: if (!enough_mp( 4, true ) || you.skills[SK_EVOCATIONS] < random2(6)) { break; } dec_mp(4); make_hungry(50, false, true); pract = 1; did_work = true; power = 10 + you.skills[SK_EVOCATIONS] * 8; your_spells( SPELL_OLGREBS_TOXIC_RADIANCE, power, false ); if (x_chance_in_y(you.skills[SK_EVOCATIONS] + 1, 10)) your_spells( SPELL_VENOM_BOLT, power, false ); break; case SPWPN_STAFF_OF_WUCAD_MU: if (you.magic_points == you.max_magic_points || you.skills[SK_EVOCATIONS] < random2(25)) { break; } mpr("Magical energy flows into your mind!"); inc_mp( 3 + random2(5) + you.skills[SK_EVOCATIONS] / 3, false ); make_hungry(50, false, true); pract = 1; did_work = true; if (one_chance_in(3)) { miscast_effect( SPTYP_DIVINATION, random2(9), random2(70), 100, "the Staff of Wucad Mu" ); } break; default: unevokable = true; break; } } else { unevokable = true; } break; case OBJ_STAVES: if (item_is_rod( wpn )) { pract = staff_spell( wield ); // [ds] Early exit, no turns are lost. if (pract == -1) return (false); did_work = true; // staff_spell() will handle messages } else if (wpn.sub_type == STAFF_CHANNELING) { if (you.magic_points < you.max_magic_points && x_chance_in_y(you.skills[SK_EVOCATIONS] + 11, 40)) { mpr("You channel some magical energy."); inc_mp( 1 + random2(3), false ); make_hungry(50, false, true); pract = (one_chance_in(5) ? 1 : 0); did_work = true; if (!item_type_known(wpn)) { set_ident_type( OBJ_STAVES, wpn.sub_type, ID_KNOWN_TYPE ); set_ident_flags( wpn, ISFLAG_KNOW_TYPE ); mprf("You are wielding %s.", wpn.name(DESC_NOCAP_A).c_str()); more(); you.wield_change = true; } } } else { unevokable = true; } break; case OBJ_MISCELLANY: did_work = true; // easier to do it this way for misc items if (is_deck(wpn)) { evoke_deck(wpn); pract = 1; break; } switch (wpn.sub_type) { case MISC_BOTTLED_EFREET: if (efreet_flask()) pract = 2; break; case MISC_CRYSTAL_BALL_OF_SEEING: if (ball_of_seeing()) pract = 1; break; case MISC_AIR_ELEMENTAL_FAN: if (you.skills[SK_EVOCATIONS] <= random2(30)) canned_msg(MSG_NOTHING_HAPPENS); else { cast_summon_elemental(100, GOD_NO_GOD, MONS_AIR_ELEMENTAL, 4); pract = (one_chance_in(5) ? 1 : 0); } break; case MISC_LAMP_OF_FIRE: if (you.skills[SK_EVOCATIONS] <= random2(30)) canned_msg(MSG_NOTHING_HAPPENS); else { cast_summon_elemental(100, GOD_NO_GOD, MONS_FIRE_ELEMENTAL, 4); pract = (one_chance_in(5) ? 1 : 0); } break; case MISC_STONE_OF_EARTH_ELEMENTALS: if (you.skills[SK_EVOCATIONS] <= random2(30)) canned_msg(MSG_NOTHING_HAPPENS); else { cast_summon_elemental(100, GOD_NO_GOD, MONS_EARTH_ELEMENTAL, 4); pract = (one_chance_in(5) ? 1 : 0); } break; case MISC_HORN_OF_GERYON: if (evoke_horn_of_geryon()) pract = 1; break; case MISC_BOX_OF_BEASTS: if (box_of_beasts()) pract = 1; break; case MISC_CRYSTAL_BALL_OF_ENERGY: if (ball_of_energy()) pract = 1; break; case MISC_CRYSTAL_BALL_OF_FIXATION: if (ball_of_fixation()) pract = 1; break; case MISC_DISC_OF_STORMS: if (disc_of_storms()) pract = (coinflip() ? 2 : 1); break; default: did_work = false; unevokable = true; break; } break; default: unevokable = true; break; } if (!did_work) canned_msg(MSG_NOTHING_HAPPENS); else if (pract > 0) exercise( SK_EVOCATIONS, pract ); if (!unevokable) you.turn_is_over = true; else crawl_state.zero_turns_taken(); return (did_work); } // end evoke_wielded() static bool efreet_flask(void) { bool friendly = x_chance_in_y(10 + you.skills[SK_EVOCATIONS] / 3, 20); mpr("You open the flask..."); const int monster = create_monster( mgen_data(MONS_EFREET, friendly ? BEH_FRIENDLY : BEH_HOSTILE, 0, you.pos(), friendly ? you.pet_target : MHITYOU, MG_FORCE_BEH)); if (monster != -1) { mpr("...and a huge efreet comes out."); if (player_angers_monster(&menv[monster])) friendly = false; mpr(friendly ? "\"Thank you for releasing me!\"" : "It howls insanely!"); } else canned_msg(MSG_NOTHING_HAPPENS); dec_inv_item_quantity(you.equip[EQ_WEAPON], 1); return (true); } static bool ball_of_seeing(void) { int use = 0; bool ret = false; mpr("You gaze into the crystal ball."); use = (!you.duration[DUR_CONF] ? random2(you.skills[SK_EVOCATIONS] * 6) : random2(5)); if (use < 2) { lose_stat( STAT_INTELLIGENCE, 1, false, "using a ball of seeing"); } else if (use < 5 && enough_mp(1, true)) { mpr("You feel power drain from you!"); set_mp(0, false); } else if (use < 10 || you.level_type == LEVEL_LABYRINTH) { if (you.level_type == LEVEL_LABYRINTH) mpr("You see a maze of twisty little passages, all alike."); confuse_player( 10 + random2(10), false ); } else if (use < 15 || coinflip()) { mpr("You see nothing."); } else if (magic_mapping( 15, 50 + random2( you.skills[SK_EVOCATIONS]), true)) { mpr("You see a map of your surroundings!"); ret = true; } else { mpr("You see nothing."); } return (ret); } // end ball_of_seeing() static bool disc_of_storms(void) { int temp_rand = 0; // probability determination {dlb} int disc_count = 0; const int fail_rate = (30 - you.skills[SK_EVOCATIONS]); bool ret = false; if (player_res_electricity() || x_chance_in_y(fail_rate, 100)) canned_msg(MSG_NOTHING_HAPPENS); else if (x_chance_in_y(fail_rate, 100)) mpr("The disc glows for a moment, then fades."); else if (x_chance_in_y(fail_rate, 100)) mpr("Little bolts of electricity crackle over the disc."); else { mpr("The disc erupts in an explosion of electricity!"); disc_count = roll_dice( 2, 1 + you.skills[SK_EVOCATIONS] / 7 ); while (disc_count) { bolt beam; temp_rand = random2(3); zap_type which_zap = ((temp_rand > 1) ? ZAP_LIGHTNING : (temp_rand > 0) ? ZAP_ELECTRICITY : ZAP_ORB_OF_ELECTRICITY); beam.source_x = you.x_pos; beam.source_y = you.y_pos; beam.target_x = you.x_pos + random2(13) - 6; beam.target_y = you.y_pos + random2(13) - 6; // Non-controlleable, so no player tracer. zapping( which_zap, 30 + you.skills[SK_EVOCATIONS] * 2, beam ); disc_count--; } ret = true; } return (ret); } void tome_of_power(int slot) { int powc = 5 + you.skills[SK_EVOCATIONS] + roll_dice( 5, you.skills[SK_EVOCATIONS] ); msg::stream << "The book opens to a page covered in " << weird_writing() << '.' << std::endl; you.turn_is_over = true; if (!yesno("Read it?")) return; set_ident_flags( you.inv[slot], ISFLAG_KNOW_TYPE ); if (player_mutation_level(MUT_BLURRY_VISION) > 0 && x_chance_in_y(player_mutation_level(MUT_BLURRY_VISION), 4)) { mpr("The page is too blurry for you to read."); return; } mpr("You find yourself reciting the magical words!"); exercise( SK_EVOCATIONS, 1 ); if (x_chance_in_y(7, 50)) { mpr("A cloud of weird smoke pours from the book's pages!"); big_cloud( random_smoke_type(), KC_YOU, you.x_pos, you.y_pos, 20, 10 + random2(8) ); xom_is_stimulated(16); } else if (x_chance_in_y(2, 43)) { mpr("A cloud of choking fumes pours from the book's pages!"); big_cloud(CLOUD_POISON, KC_YOU, you.x_pos, you.y_pos, 20, 7 + random2(5)); xom_is_stimulated(64); } else if (x_chance_in_y(2, 41)) { mpr("A cloud of freezing gas pours from the book's pages!"); big_cloud(CLOUD_COLD, KC_YOU, you.x_pos, you.y_pos, 20, 8 + random2(5)); xom_is_stimulated(64); } else if (x_chance_in_y(3, 39)) { if (one_chance_in(5)) { mpr("The book disappears in a mighty explosion!"); dec_inv_item_quantity( slot, 1 ); } bolt beam; beam.type = dchar_glyph(DCHAR_FIRED_BURST); beam.damage = dice_def( 3, 15 ); // unsure about this // BEAM_EXPLOSION instead? [dlb] beam.flavour = BEAM_FIRE; beam.target_x = you.x_pos; beam.target_y = you.y_pos; beam.name = "fiery explosion"; beam.colour = RED; // your explosion, (not someone else's explosion) beam.beam_source = NON_MONSTER; beam.thrower = KILL_YOU; beam.aux_source = "an exploding tome of Destruction"; beam.ex_size = 2; beam.is_tracer = false; beam.is_explosion = true; explosion(beam); xom_is_stimulated(255); } else if (one_chance_in(36)) { if (create_monster( mgen_data(MONS_ABOMINATION_SMALL, BEH_HOSTILE, 6, you.pos(), MHITYOU)) != -1) { mpr("A horrible Thing appears!"); mpr("It doesn't look too friendly."); } xom_is_stimulated(255); } else { viewwindow(true, false); int temp_rand = random2(23) + random2(you.skills[SK_EVOCATIONS] / 3); if (temp_rand > 25) temp_rand = 25; const spell_type spell_casted = ((temp_rand > 24) ? SPELL_LEHUDIBS_CRYSTAL_SPEAR : (temp_rand > 21) ? SPELL_BOLT_OF_FIRE : (temp_rand > 18) ? SPELL_BOLT_OF_COLD : (temp_rand > 16) ? SPELL_LIGHTNING_BOLT : (temp_rand > 10) ? SPELL_FIREBALL : (temp_rand > 9) ? SPELL_VENOM_BOLT : (temp_rand > 8) ? SPELL_BOLT_OF_DRAINING : (temp_rand > 7) ? SPELL_BOLT_OF_INACCURACY : (temp_rand > 6) ? SPELL_STICKY_FLAME : (temp_rand > 5) ? SPELL_TELEPORT_SELF : (temp_rand > 4) ? SPELL_CIGOTUVIS_DEGENERATION : (temp_rand > 3) ? SPELL_POLYMORPH_OTHER : (temp_rand > 2) ? SPELL_MEPHITIC_CLOUD : (temp_rand > 1) ? SPELL_THROW_FLAME : (temp_rand > 0) ? SPELL_THROW_FROST : SPELL_MAGIC_DART); your_spells( spell_casted, powc, false ); } } void skill_manual(int slot) { // Removed confirmation request because you know it's // a manual in advance. you.turn_is_over = true; item_def& manual(you.inv[slot]); set_ident_flags( manual, ISFLAG_KNOW_TYPE ); const int skill = manual.plus; mprf("You read about %s.", skill_name(skill)); exercise(skill, 500); if (--manual.plus2 <= 0) { mpr("The manual crumbles into dust."); dec_inv_item_quantity( slot, 1 ); } else mpr("The manual looks somewhat more worn."); xom_is_stimulated(14); } static bool box_of_beasts() { bool success = false; mpr("You open the lid..."); if (x_chance_in_y(60 + you.skills[SK_EVOCATIONS], 100)) { monster_type beasty = MONS_PROGRAM_BUG; // If you worship a good god, don't summon an evil beast (in // this case, the hell hound). do { int temp_rand = random2(11); beasty = ((temp_rand == 0) ? MONS_GIANT_BAT : (temp_rand == 1) ? MONS_HOUND : (temp_rand == 2) ? MONS_JACKAL : (temp_rand == 3) ? MONS_RAT : (temp_rand == 4) ? MONS_ICE_BEAST : (temp_rand == 5) ? MONS_SNAKE : (temp_rand == 6) ? MONS_YAK : (temp_rand == 7) ? MONS_BUTTERFLY : (temp_rand == 8) ? MONS_BROWN_SNAKE : (temp_rand == 9) ? MONS_GIANT_LIZARD : MONS_HELL_HOUND); } while (player_will_anger_monster(beasty)); beh_type beha = BEH_FRIENDLY; unsigned short hitting = you.pet_target; if (one_chance_in(you.skills[SK_EVOCATIONS] + 5)) { beha = BEH_HOSTILE; hitting = MHITYOU; } if (create_monster( mgen_data(beasty, beha, 2 + random2(4), you.pos(), hitting)) != -1) { success = true; mpr("...and something leaps out!"); xom_is_stimulated(14); } } else { if (!one_chance_in(6)) mpr("...but nothing happens."); else { mpr("...but the box appears empty."); you.inv[you.equip[EQ_WEAPON]].sub_type = MISC_EMPTY_EBONY_CASKET; } } return (success); } static bool ball_of_energy(void) { int use = 0; int proportional = 0; bool ret = false; mpr("You gaze into the crystal ball."); use = ((!you.duration[DUR_CONF]) ? random2(you.skills[SK_EVOCATIONS] * 6) : random2(6)); if (use < 2 || you.max_magic_points == 0) { lose_stat(STAT_INTELLIGENCE, 1, false, "using a ball of energy"); } else if (use < 4 && enough_mp(1, true) || you.magic_points == you.max_magic_points) { mpr( "You feel your power drain away!" ); set_mp( 0, false ); } else if (use < 6) { confuse_player( 10 + random2(10), false ); } else { proportional = you.magic_points * 100; proportional /= you.max_magic_points; if (random2avg(77 - you.skills[SK_EVOCATIONS] * 2, 4) > proportional || one_chance_in(25)) { mpr( "You feel your power drain away!" ); set_mp( 0, false ); } else { mpr( "You are suffused with power!" ); inc_mp( 6 + roll_dice( 2, you.skills[SK_EVOCATIONS] ), false ); ret = true; } } return (ret); } static bool ball_of_fixation(void) { mpr("You gaze into the crystal ball."); mpr("You are mesmerised by a rainbow of scintillating colours!"); const int duration = random_range(15, 40); you.duration[DUR_PARALYSIS] = duration; you.duration[DUR_SLOW] = duration; return (true); }