3 * Summary: Non-enchantment spells that didn't fit anywhere else.
4 * Mostly Transmutations.
16 #include "godconduct.h"
25 #include "mon-place.h"
28 #include "player-stats.h"
33 #include "transform.h"
35 void cast_cure_poison(int pow
)
37 if (you
.duration
[DUR_POISONING
] > 0)
38 reduce_poison_player(2 + random2(pow
) + random2(3));
40 canned_msg(MSG_NOTHING_HAPPENS
);
43 bool cast_sublimation_of_blood(int pow
)
47 int wielded
= you
.equip
[EQ_WEAPON
];
51 if (you
.inv
[wielded
].base_type
== OBJ_FOOD
52 && you
.inv
[wielded
].sub_type
== FOOD_CHUNK
)
54 mpr("The chunk of flesh you are holding crumbles to dust.");
56 mpr("A flood of magical energy pours into your mind!");
58 inc_mp(7 + random2(7), false);
60 dec_inv_item_quantity(wielded
, 1);
62 if (mons_genus(you
.inv
[wielded
].plus
) == MONS_ORC
)
63 did_god_conduct(DID_DESECRATE_ORCISH_REMAINS
, 2);
65 else if (is_blood_potion(you
.inv
[wielded
]))
67 mprf("The blood within %s froths and boils.",
68 you
.inv
[wielded
].quantity
> 1 ? "one of your flasks"
69 : "the flask you are holding");
71 mpr("A flood of magical energy pours into your mind!");
73 inc_mp(7 + random2(7), false);
75 remove_oldest_blood_potion(you
.inv
[wielded
]);
76 dec_inv_item_quantity(wielded
, 1);
84 if (you
.duration
[DUR_DEATHS_DOOR
])
86 mpr("A conflicting enchantment prevents the spell from "
87 "coming into effect.");
89 else if (you
.species
== SP_VAMPIRE
&& you
.hunger_state
<= HS_SATIATED
)
91 mpr("You don't have enough blood to draw power from your "
94 else if (!enough_hp(2, true))
95 mpr("Your attempt to draw power from your own body fails.");
101 mpr("You draw magical energy from your own body!");
103 while (you
.magic_points
< you
.max_magic_points
&& you
.hp
> 1
104 && (you
.species
!= SP_VAMPIRE
|| you
.hunger
- food
>= 7000))
111 if (you
.species
== SP_VAMPIRE
)
114 for (int loopy
= 0; loopy
< (you
.hp
> 1 ? 3 : 0); ++loopy
)
115 if (x_chance_in_y(6, pow
))
118 if (x_chance_in_y(6, pow
))
122 make_hungry(food
, false);
129 bool cast_death_channel(int pow
, god_type god
)
131 bool success
= false;
133 if (you
.duration
[DUR_DEATH_CHANNEL
] < 30 * BASELINE_DELAY
)
137 mpr("Malign forces permeate your being, awaiting release.");
139 you
.increase_duration(DUR_DEATH_CHANNEL
, 15 + random2(1 + pow
/3), 100);
141 if (god
!= GOD_NO_GOD
)
142 you
.attribute
[ATTR_DIVINE_DEATH_CHANNEL
] = static_cast<int>(god
);
145 canned_msg(MSG_NOTHING_HAPPENS
);
152 // 1 = undead only (Yred religion ability)
153 // 2 = orcs only (Beogh religion ability)
154 bool recall(int type_recalled
)
156 int loopy
= 0; // general purpose looping variable {dlb}
157 bool success
= false; // more accurately: "apparent success" {dlb}
160 int end_count
= (MAX_MONSTERS
- 1);
162 monster
* mons
= NULL
;
164 // someone really had to make life difficult {dlb}:
165 // sometimes goes through monster list backwards
168 start_count
= (MAX_MONSTERS
- 1);
173 for (loopy
= start_count
; loopy
!= end_count
+ step_value
;
178 if (mons
->type
== MONS_NO_MONSTER
)
181 if (!mons
->friendly())
184 if (mons_class_is_stationary(mons
->type
)
185 || mons_is_conjured(mons
->type
))
190 if (!monster_habitable_grid(mons
, DNGN_FLOOR
))
193 if (type_recalled
== 1) // undead
195 if (mons
->holiness() != MH_UNDEAD
)
198 else if (type_recalled
== 2) // Beogh
200 if (!is_orcish_follower(mons
))
205 if (empty_surrounds(you
.pos(), DNGN_FLOOR
, 3, false, empty
)
206 && mons
->move_to_pos(empty
))
208 // only informed if monsters recalled are visible {dlb}:
209 if (simple_monster_message(mons
, " is recalled."))
213 break; // no more room to place monsters {dlb}
217 mpr("Nothing appears to have answered your call.");
222 // Cast_phase_shift: raises evasion (by 8 currently) via Translocations.
223 void cast_phase_shift(int pow
)
225 if (!you
.duration
[DUR_PHASE_SHIFT
])
226 mpr("You feel the strange sensation of being on two planes at once.");
228 mpr("You feel the material plane grow further away.");
230 you
.increase_duration(DUR_PHASE_SHIFT
, 5 + random2(pow
), 30);
231 you
.redraw_evasion
= true;
234 static bool _feat_is_passwallable(dungeon_feature_type feat
)
236 // Irony: you can passwall through a secret door but not a door.
237 // Worked stone walls are out, they're not diggable and
238 // are used for impassable walls...
242 case DNGN_SLIMY_WALL
:
243 case DNGN_CLEAR_ROCK_WALL
:
244 case DNGN_SECRET_DOOR
:
251 bool cast_passwall(const coord_def
& delta
, int pow
)
253 int shallow
= 1 + (you
.skills
[SK_EARTH_MAGIC
] / 8);
254 int range
= shallow
+ random2(pow
) / 25;
255 int maxrange
= shallow
+ pow
/ 25;
258 for (dest
= you
.pos() + delta
;
259 in_bounds(dest
) && _feat_is_passwallable(grd(dest
));
262 int walls
= (dest
- you
.pos()).rdist() - 1;
265 mpr("That's not a passable wall.");
269 // Below here, failing to cast yields information to the
270 // player, so we don't make the spell abort (return true).
271 if (!in_bounds(dest
))
272 mpr("You sense an overwhelming volume of rock.");
273 else if (feat_is_solid(grd(dest
)))
274 mpr("Something is blocking your path through the rock.");
275 else if (is_feat_dangerous(grd(dest
), true))
277 if (grd(dest
) == DNGN_DEEP_WATER
)
278 mpr("You sense a large body of water on the other side of the rock.");
279 else if (grd(dest
) == DNGN_LAVA
)
280 mpr("You sense an intense heat on the other side of the rock.");
282 mprf(MSGCH_ERROR
, "Unhandled dangerous feature: ",
283 feature_description(dest
, false, DESC_PLAIN
).c_str());
285 else if (walls
> maxrange
)
286 mpr("This rock feels extremely deep.");
287 else if (walls
> range
)
288 mpr("You fail to penetrate the rock.");
291 // Passwall delay is reduced, and the delay cannot be interrupted.
292 start_delay(DELAY_PASSWALL
, 1 + walls
, dest
.x
, dest
.y
);
297 static int _intoxicate_monsters(coord_def where
, int pow
, int, actor
*)
301 monster
* mons
= monster_at(where
);
303 || mons_intel(mons
) < I_NORMAL
304 || mons
->holiness() != MH_NATURAL
305 || mons
->res_poison() > 0)
310 mons
->add_ench(mon_enchant(ENCH_CONFUSION
, 0, KC_YOU
));
314 void cast_intoxicate(int pow
)
316 potion_effect(POT_CONFUSION
, 10 + (100 - pow
) / 10);
318 if (one_chance_in(20)
319 && lose_stat(STAT_INT
, 1 + random2(3), false,
320 "casting intoxication"))
322 mpr("Your head spins!");
325 apply_area_visible(_intoxicate_monsters
, pow
, true);
328 // The intent of this spell isn't to produce helpful potions
329 // for drinking, but rather to provide ammo for the Evaporate
330 // spell out of corpses, thus potentially making it useful.
331 // Producing helpful potions would break game balance here...
332 // and producing more than one potion from a corpse, or not
333 // using up the corpse might also lead to game balance problems. - bwr
334 bool cast_fulsome_distillation(int pow
, bool check_range
)
337 item_def
*corpse
= corpse_at(you
.pos(), &num_corpses
);
338 if (num_corpses
&& you
.flight_mode() == FL_LEVITATE
)
341 // If there is only one corpse, distill it; otherwise, ask the player
342 // which corpse to use.
346 // Allow using Z to victory dance fulsome.
349 mpr("The spell fizzles.");
353 if (num_corpses
== -1)
354 mpr("You can't reach the corpse!");
356 mpr("There aren't any corpses here.");
359 // Use the only corpse available without prompting.
362 // Search items at the player's location for corpses.
363 // The last corpse detected earlier is irrelevant.
365 for (stack_iterator
si(you
.pos(), true); si
; ++si
)
367 if (item_is_corpse(*si
))
369 const std::string corpsedesc
=
370 get_menu_colour_prefix_tags(*si
, DESC_NOCAP_THE
);
371 const std::string prompt
=
372 make_stringf("Distill a potion from %s?",
375 if (yesno(prompt
.c_str(), true, 0, false))
390 potion_type pot_type
= POT_WATER
;
392 switch (mons_corpse_effect(corpse
->plus
))
395 pot_type
= POT_WATER
;
398 case CE_CONTAMINATED
:
399 pot_type
= (mons_weight(corpse
->plus
) >= 900)
400 ? POT_DEGENERATION
: POT_CONFUSION
;
404 case CE_POISON_CONTAM
:
405 pot_type
= POT_POISON
;
408 case CE_MUTAGEN_RANDOM
:
409 case CE_MUTAGEN_GOOD
: // unused
410 case CE_RANDOM
: // unused
411 pot_type
= POT_MUTATION
;
414 case CE_MUTAGEN_BAD
: // unused
415 case CE_ROTTEN
: // actually this only occurs via mangling
416 case CE_HCL
: // necrophage
417 pot_type
= POT_DECAY
;
420 case CE_NOCORPSE
: // shouldn't occur
425 switch (corpse
->plus
)
427 case MONS_RED_WASP
: // paralysis attack
428 pot_type
= POT_PARALYSIS
;
431 case MONS_YELLOW_WASP
: // slowing attack
432 pot_type
= POT_SLOWING
;
439 struct monsterentry
* smc
= get_monster_data(corpse
->plus
);
441 for (int nattk
= 0; nattk
< 4; ++nattk
)
443 if (smc
->attack
[nattk
].flavour
== AF_POISON_MEDIUM
444 || smc
->attack
[nattk
].flavour
== AF_POISON_STRONG
445 || smc
->attack
[nattk
].flavour
== AF_POISON_STR
446 || smc
->attack
[nattk
].flavour
== AF_POISON_INT
447 || smc
->attack
[nattk
].flavour
== AF_POISON_DEX
448 || smc
->attack
[nattk
].flavour
== AF_POISON_STAT
)
450 pot_type
= POT_STRONG_POISON
;
454 const bool was_orc
= (mons_genus(corpse
->plus
) == MONS_ORC
);
456 // We borrow the corpse's object to make our potion.
457 corpse
->base_type
= OBJ_POTIONS
;
458 corpse
->sub_type
= pot_type
;
459 corpse
->quantity
= 1;
463 corpse
->inscription
.clear();
464 item_colour(*corpse
); // sets special as well
466 // Always identify said potion.
467 set_ident_type(*corpse
, ID_KNOWN_TYPE
);
469 mprf("You extract %s from the corpse.",
470 corpse
->name(DESC_NOCAP_A
).c_str());
472 // Try to move the potion to the player (for convenience).
473 if (move_item_to_player(corpse
->index(), 1) != 1)
474 mpr("Unfortunately, you can't carry it right now!");
477 did_god_conduct(DID_DESECRATE_ORCISH_REMAINS
, 2);
482 void remove_condensation_shield()
484 mpr("Your icy shield evaporates.", MSGCH_DURATION
);
485 you
.duration
[DUR_CONDENSATION_SHIELD
] = 0;
486 you
.redraw_armour_class
= true;
489 void cast_condensation_shield(int pow
)
491 if (you
.shield() || you
.duration
[DUR_FIRE_SHIELD
])
492 canned_msg(MSG_SPELL_FIZZLES
);
495 if (you
.duration
[DUR_CONDENSATION_SHIELD
] > 0)
497 mpr("The disc of vapour around you crackles some more.");
498 you
.increase_duration(DUR_CONDENSATION_SHIELD
,
499 5 + roll_dice(2,3), 30);
503 mpr("A crackling disc of dense vapour forms in the air!");
504 you
.increase_duration(DUR_CONDENSATION_SHIELD
,
505 10 + roll_dice(2, pow
/ 5), 30);
506 you
.redraw_armour_class
= true;
511 void cast_stoneskin(int pow
)
514 && (you
.species
!= SP_VAMPIRE
|| you
.hunger_state
< HS_SATIATED
))
516 mpr("This spell does not affect your undead flesh.");
520 if (you
.form
!= TRAN_NONE
521 && you
.form
!= TRAN_STATUE
522 && you
.form
!= TRAN_BLADE_HANDS
)
524 mpr("This spell does not affect your current form.");
528 if (you
.duration
[DUR_STONEMAIL
] || you
.duration
[DUR_ICY_ARMOUR
])
530 mpr("This spell conflicts with another spell still in effect.");
534 if (you
.duration
[DUR_STONESKIN
])
535 mpr("Your skin feels harder.");
538 if (you
.form
== TRAN_STATUE
)
539 mpr("Your stone body feels more resilient.");
541 mpr("Your skin hardens.");
543 you
.redraw_armour_class
= true;
546 you
.increase_duration(DUR_STONESKIN
, 10 + random2(pow
) + random2(pow
), 50);