Apply the new ground_level method.
[crawl.git] / crawl-ref / source / spl-selfench.cc
blob6a9f7bd77c7e0fc046b2c35ce5fc13b95cb3d70f
1 /*
2 * File: spl-selfench.cc
3 * Summary: Self-enchantment spells.
4 */
6 #include "AppHdr.h"
8 #include "spl-selfench.h"
9 #include "externs.h"
11 #include "areas.h"
12 #include "delay.h"
13 #include "env.h"
14 #include "godconduct.h"
15 #include "hints.h"
16 #include "it_use2.h"
17 #include "itemprop.h"
18 #include "libutil.h"
19 #include "message.h"
20 #include "misc.h"
21 #include "religion.h"
22 #include "spl-cast.h"
23 #include "spl-other.h"
24 #include "spl-util.h"
25 #include "stuff.h"
26 #include "transform.h"
27 #include "view.h"
29 int allowed_deaths_door_hp(void)
31 int hp = you.skills[SK_NECROMANCY] / 2;
33 if (you.religion == GOD_KIKUBAAQUDGHA && !player_under_penance())
34 hp += you.piety / 15;
36 return std::max(hp, 1);
39 bool cast_deaths_door(int pow)
41 if (you.is_undead)
42 mpr("You're already dead!");
43 else if (you.duration[DUR_DEATHS_DOOR])
44 mpr("Your appeal for an extension has been denied.");
45 else
47 mpr("You feel invincible!");
48 mpr("You seem to hear sand running through an hourglass...",
49 MSGCH_SOUND);
51 set_hp(allowed_deaths_door_hp(), false);
52 deflate_hp(you.hp_max, false);
54 you.set_duration(DUR_DEATHS_DOOR, 10 + random2avg(13, 3)
55 + (random2(pow) / 10));
57 if (you.duration[DUR_DEATHS_DOOR] > 25 * BASELINE_DELAY)
58 you.duration[DUR_DEATHS_DOOR] = (23 + random2(5)) * BASELINE_DELAY;
59 return true;
62 return false;
65 static bool _know_spell(spell_type spell)
67 if (spell == NUM_SPELLS)
68 return (false);
70 if (!you.has_spell(spell))
72 mprf("You don't know how to extend %s.", spell_title(spell));
73 return (false);
76 int fail = spell_fail(spell);
77 dprf("fail = %d", fail);
79 if (fail > random2(50) + 50)
81 mprf("Your knowledge of %s fails you.", spell_title(spell));
82 return (false);
85 return (true);
88 static spell_type _brand_spell()
90 const item_def *wpn = you.weapon();
92 if (!wpn)
93 return NUM_SPELLS;
95 const int wpn_type = get_vorpal_type(*wpn);
96 switch(get_weapon_brand(*wpn))
98 case SPWPN_FLAMING:
99 case SPWPN_FLAME:
100 return SPELL_FIRE_BRAND;
101 case SPWPN_FREEZING:
102 case SPWPN_FROST:
103 return SPELL_FREEZING_AURA;
104 case SPWPN_VORPAL:
105 if (wpn_type == DVORP_CRUSHING)
106 return SPELL_MAXWELLS_SILVER_HAMMER;
107 return NUM_SPELLS;
108 case SPWPN_VENOM:
109 if (wpn_type == DVORP_CRUSHING)
110 return NUM_SPELLS;
111 return SPELL_POISON_WEAPON;
112 case SPWPN_PAIN:
113 return SPELL_EXCRUCIATING_WOUNDS;
114 case SPWPN_DRAINING:
115 return SPELL_LETHAL_INFUSION;
116 case SPWPN_DISTORTION:
117 return SPELL_WARP_BRAND;
118 default:
119 return NUM_SPELLS;
123 static spell_type _transform_spell()
125 switch(you.form)
127 case TRAN_BLADE_HANDS:
128 return SPELL_BLADE_HANDS;
129 case TRAN_SPIDER:
130 return SPELL_SPIDER_FORM;
131 case TRAN_STATUE:
132 return SPELL_STATUE_FORM;
133 case TRAN_ICE_BEAST:
134 return SPELL_ICE_FORM;
135 case TRAN_DRAGON:
136 return SPELL_DRAGON_FORM;
137 case TRAN_LICH:
138 return SPELL_NECROMUTATION;
139 case TRAN_BAT:
140 return NUM_SPELLS; // no spell
141 case TRAN_PIG:
142 return SPELL_PORKALATOR; // Kirke/Nemelex only
143 default:
144 return NUM_SPELLS;
148 void extension(int pow)
150 int contamination = random2(2);
152 if (you.duration[DUR_HASTE] && _know_spell(SPELL_HASTE))
154 potion_effect(POT_SPEED, pow);
155 contamination++;
158 if (you.duration[DUR_SLOW] && _know_spell(SPELL_SLOW)) // heh heh
159 potion_effect(POT_SLOWING, pow);
161 if (you.duration[DUR_LEVITATION] && !you.duration[DUR_CONTROLLED_FLIGHT]
162 && _know_spell(SPELL_LEVITATION))
164 levitate_player(pow);
167 if (you.duration[DUR_INVIS] && _know_spell(SPELL_INVISIBILITY))
169 potion_effect(POT_INVISIBILITY, pow);
170 contamination++;
173 if (you.duration[DUR_ICY_ARMOUR] && _know_spell(SPELL_OZOCUBUS_ARMOUR))
174 ice_armour(pow, true);
176 if (you.duration[DUR_REPEL_MISSILES] && _know_spell(SPELL_REPEL_MISSILES))
177 missile_prot(pow);
179 if (you.duration[DUR_REGENERATION] && _know_spell(SPELL_REGENERATION)
180 && you.form != TRAN_LICH)
182 cast_regen(pow);
185 if (you.duration[DUR_DEFLECT_MISSILES]
186 && _know_spell(SPELL_DEFLECT_MISSILES))
188 deflection(pow);
191 if (you.duration[DUR_FIRE_SHIELD] && _know_spell(SPELL_RING_OF_FLAMES))
193 you.increase_duration(DUR_FIRE_SHIELD, random2(pow / 20), 50);
194 mpr("Your ring of flames roars with new vigour!");
197 if (!you.duration[DUR_WEAPON_BRAND] < 1 && _know_spell(_brand_spell()))
199 you.increase_duration(DUR_WEAPON_BRAND, 5 + random2(8), 80);
202 if (you.duration[DUR_SWIFTNESS] && _know_spell(SPELL_SWIFTNESS))
203 cast_swiftness(pow);
205 if (you.duration[DUR_INSULATION] && _know_spell(SPELL_INSULATION))
206 cast_insulation(pow);
208 if (you.duration[DUR_CONTROLLED_FLIGHT] && _know_spell(SPELL_FLY))
209 cast_fly(pow);
211 if (you.duration[DUR_CONTROL_TELEPORT]
212 && _know_spell(SPELL_CONTROL_TELEPORT))
214 cast_teleport_control(pow);
217 if (you.duration[DUR_RESIST_POISON] && _know_spell(SPELL_RESIST_POISON))
218 cast_resist_poison(pow);
220 if (you.duration[DUR_TRANSFORMATION] && _know_spell(_transform_spell()))
222 mpr("Your transformation has been extended.");
223 you.increase_duration(DUR_TRANSFORMATION, random2(pow), 100,
224 "Your transformation has been extended.");
226 if (you.form == TRAN_LICH
227 && is_good_god(you.religion))
229 // possible with Xom or a card
230 excommunication();
233 // Give a warning if it won't last long enough for the
234 // timeout messages.
235 transformation_expiration_warning();
238 if (you.duration[DUR_STONESKIN] && _know_spell(SPELL_STONESKIN))
239 cast_stoneskin(pow);
241 if (you.duration[DUR_PHASE_SHIFT] && _know_spell(SPELL_PHASE_SHIFT))
242 cast_phase_shift(pow);
244 if (you.duration[DUR_SEE_INVISIBLE] && _know_spell(SPELL_SEE_INVISIBLE))
245 cast_see_invisible(pow);
247 if (you.duration[DUR_SILENCE] && _know_spell(SPELL_SILENCE))
248 cast_silence(pow); //how precisely did you cast extension?
250 if (you.duration[DUR_CONDENSATION_SHIELD]
251 && _know_spell(SPELL_CONDENSATION_SHIELD))
253 cast_condensation_shield(pow);
256 if (you.duration[DUR_DEATH_CHANNEL] && _know_spell(SPELL_DEATH_CHANNEL))
257 cast_death_channel(pow);
259 if (you.duration[DUR_DEATHS_DOOR] && _know_spell(SPELL_DEATHS_DOOR))
260 cast_deaths_door(pow); // just for the fail message
262 if (contamination)
263 contaminate_player(contamination, true);
266 void remove_ice_armour()
268 mpr("Your icy armour melts away.", MSGCH_DURATION);
269 you.redraw_armour_class = true;
270 you.duration[DUR_ICY_ARMOUR] = 0;
273 void ice_armour(int pow, bool extending)
275 if (!player_effectively_in_light_armour())
277 if (!extending)
278 mpr("You are wearing too much armour.");
280 return;
283 if (you.duration[DUR_STONEMAIL] || you.duration[DUR_STONESKIN])
285 if (!extending)
286 mpr("The spell conflicts with another spell still in effect.");
288 return;
291 if (you.duration[DUR_ICY_ARMOUR])
292 mpr("Your icy armour thickens.");
293 else
295 if (you.form == TRAN_ICE_BEAST)
296 mpr("Your icy body feels more resilient.");
297 else
298 mpr("A film of ice covers your body!");
300 you.redraw_armour_class = true;
303 you.increase_duration(DUR_ICY_ARMOUR, 20 + random2(pow) + random2(pow), 50,
304 NULL);
307 void missile_prot(int pow)
309 you.increase_duration(DUR_REPEL_MISSILES, 8 + roll_dice(2, pow), 100,
310 "You feel protected from missiles.");
313 void deflection(int pow)
315 you.increase_duration(DUR_DEFLECT_MISSILES, 15 + random2(pow), 100,
316 "You feel very safe from missiles.");
319 void remove_regen(bool divine_ability)
321 mpr("Your skin stops crawling.", MSGCH_DURATION);
322 you.duration[DUR_REGENERATION] = 0;
323 if (divine_ability)
325 mpr("You feel less resistant to magic.", MSGCH_DURATION);
326 you.attribute[ATTR_DIVINE_REGENERATION] = 0;
330 void cast_regen(int pow, bool divine_ability)
332 you.increase_duration(DUR_REGENERATION, 5 + roll_dice(2, pow / 3 + 1), 100,
333 "Your skin crawls.");
335 if (divine_ability)
337 mpr("You feel resistant to magic.");
338 you.attribute[ATTR_DIVINE_REGENERATION] = 1;
342 void cast_berserk(void)
344 go_berserk(true);
347 void cast_swiftness(int power)
349 if (you.in_water())
351 mpr("The water foams!");
352 return;
355 if (!you.duration[DUR_SWIFTNESS] && player_movement_speed() <= 6)
357 mpr("You can't move any more quickly.");
358 return;
361 // [dshaligram] Removed the on-your-feet bit. Sounds odd when
362 // you're levitating, for instance.
363 you.increase_duration(DUR_SWIFTNESS, 20 + random2(power), 100,
364 "You feel quick.");
365 did_god_conduct(DID_HASTY, 8, true);
368 void cast_fly(int power)
370 const int dur_change = 25 + random2(power) + random2(power);
371 const bool was_levitating = you.airborne();
373 you.increase_duration(DUR_LEVITATION, dur_change, 100);
374 you.increase_duration(DUR_CONTROLLED_FLIGHT, dur_change, 100);
376 burden_change();
378 if (!was_levitating)
379 float_player(true);
380 else
381 mpr("You feel more buoyant.");
384 void cast_insulation(int power)
386 you.increase_duration(DUR_INSULATION, 10 + random2(power), 100,
387 "You feel insulated.");
390 void cast_resist_poison(int power)
392 you.increase_duration(DUR_RESIST_POISON, 10 + random2(power), 100,
393 "You feel resistant to poison.");
396 void cast_teleport_control(int power)
398 you.increase_duration(DUR_CONTROL_TELEPORT, 10 + random2(power), 50,
399 "You feel in control.");
402 int cast_selective_amnesia(std::string *pre_msg)
404 if (you.spell_no == 0)
406 canned_msg(MSG_NO_SPELLS);
407 return (0);
410 int keyin = 0;
411 spell_type spell;
412 int slot;
414 // Pick a spell to forget.
415 while (true)
417 mpr("Forget which spell ([?*] list [ESC] exit)? ", MSGCH_PROMPT);
418 keyin = get_ch();
420 if (key_is_escape(keyin))
422 canned_msg(MSG_OK);
423 return (-1);
426 if (keyin == '?' || keyin == '*')
428 keyin = list_spells(false, false, false);
429 redraw_screen();
432 if (!isaalpha(keyin))
434 mesclr();
435 continue;
438 spell = get_spell_by_letter(keyin);
439 slot = get_spell_slot_by_letter(keyin);
441 if (spell == SPELL_NO_SPELL)
442 mpr("You don't know that spell.");
443 else
444 break;
447 if (pre_msg)
448 mpr(pre_msg->c_str());
450 const int ep_gain = spell_mana(spell);
451 del_spell_from_memory_by_slot(slot);
453 if (ep_gain > 0)
455 inc_mp(ep_gain, false);
456 mpr("The spell releases its latent energy back to you as "
457 "it unravels.");
460 return (1);
463 void cast_see_invisible(int pow)
465 if (you.can_see_invisible())
466 mpr("You feel as though your vision will be sharpened longer.");
467 else
469 mpr("Your vision seems to sharpen.");
471 // We might have to turn autopickup back on again.
472 // TODO: Once the spell times out we might want to check all monsters
473 // in LOS for invisibility and turn autopickup off again, if
474 // needed.
475 autotoggle_autopickup(false);
478 // No message if you already are under the spell.
479 you.increase_duration(DUR_SEE_INVISIBLE, 10 + random2(2 + pow/2), 100);
482 void cast_silence(int pow)
484 if (!you.attribute[ATTR_WAS_SILENCED])
485 mpr("A profound silence engulfs you.");
487 you.attribute[ATTR_WAS_SILENCED] = 1;
489 you.increase_duration(DUR_SILENCE, 10 + random2avg(pow, 2), 100);
490 invalidate_agrid(true);
492 if (you.beheld())
493 you.update_beholders();
495 learned_something_new(HINT_YOU_SILENCE);
498 void cast_liquefaction(int pow)
500 flash_view_delay(BROWN, 80);
501 flash_view_delay(YELLOW, 80);
502 flash_view_delay(BROWN, 140);
504 mpr("The ground around you becomes liquefied!");
506 you.increase_duration(DUR_LIQUEFYING, 10 + random2avg(pow, 2), 100);
507 invalidate_agrid(true);