Angband 3.0.9b.
[angband.git] / src / spells1.c
blobc74a6bf661acf9cffccb9cc9b0cffdbc1e0b0287
1 /* File: spells1.c */
3 /*
4 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6 * This software may be copied and distributed for educational, research,
7 * and not for profit purposes provided that this copyright and statement
8 * are included in all such copies. Other copyrights may also apply.
9 */
11 #include "angband.h"
13 #include "script.h"
17 * Helper function -- return a "nearby" race for polymorphing
19 * Note that this function is one of the more "dangerous" ones...
21 s16b poly_r_idx(int r_idx)
23 monster_race *r_ptr = &r_info[r_idx];
25 int i, r, lev1, lev2;
27 /* Hack -- Uniques never polymorph */
28 if (r_ptr->flags1 & (RF1_UNIQUE)) return (r_idx);
30 /* Allowable range of "levels" for resulting monster */
31 lev1 = r_ptr->level - ((randint(20)/randint(9))+1);
32 lev2 = r_ptr->level + ((randint(20)/randint(9))+1);
34 /* Pick a (possibly new) non-unique race */
35 for (i = 0; i < 1000; i++)
37 /* Pick a new race, using a level calculation */
38 r = get_mon_num((p_ptr->depth + r_ptr->level) / 2 + 5);
40 /* Handle failure */
41 if (!r) break;
43 /* Obtain race */
44 r_ptr = &r_info[r];
46 /* Ignore unique monsters */
47 if (r_ptr->flags1 & (RF1_UNIQUE)) continue;
49 /* Ignore monsters with incompatible levels */
50 if ((r_ptr->level < lev1) || (r_ptr->level > lev2)) continue;
52 /* Use that index */
53 r_idx = r;
55 /* Done */
56 break;
59 /* Result */
60 return (r_idx);
65 * Teleport a monster, normally up to "dis" grids away.
67 * Attempt to move the monster at least "dis/2" grids away.
69 * But allow variation to prevent infinite loops.
71 void teleport_away(int m_idx, int dis)
73 int ny, nx, oy, ox, d, i, min;
75 bool look = TRUE;
77 monster_type *m_ptr = &mon_list[m_idx];
80 /* Paranoia */
81 if (!m_ptr->r_idx) return;
83 /* Save the old location */
84 oy = m_ptr->fy;
85 ox = m_ptr->fx;
87 /* Minimum distance */
88 min = dis / 2;
90 /* Look until done */
91 while (look)
93 /* Verify max distance */
94 if (dis > 200) dis = 200;
96 /* Try several locations */
97 for (i = 0; i < 500; i++)
99 /* Pick a (possibly illegal) location */
100 while (1)
102 ny = rand_spread(oy, dis);
103 nx = rand_spread(ox, dis);
104 d = distance(oy, ox, ny, nx);
105 if ((d >= min) && (d <= dis)) break;
108 /* Ignore illegal locations */
109 if (!in_bounds_fully(ny, nx)) continue;
111 /* Require "empty" floor space */
112 if (!cave_empty_bold(ny, nx)) continue;
114 /* Hack -- no teleport onto glyph of warding */
115 if (cave_feat[ny][nx] == FEAT_GLYPH) continue;
117 /* No teleporting into vaults and such */
118 /* if (cave_info[ny][nx] & (CAVE_ICKY)) continue; */
120 /* This grid looks good */
121 look = FALSE;
123 /* Stop looking */
124 break;
127 /* Increase the maximum distance */
128 dis = dis * 2;
130 /* Decrease the minimum distance */
131 min = min / 2;
134 /* Sound */
135 sound(MSG_TPOTHER);
137 /* Swap the monsters */
138 monster_swap(oy, ox, ny, nx);
143 * Teleport the player to a location up to "dis" grids away.
145 * If no such spaces are readily available, the distance may increase.
146 * Try very hard to move the player at least a quarter that distance.
148 void teleport_player(int dis)
150 int py = p_ptr->py;
151 int px = p_ptr->px;
153 int d, i, min, y, x;
155 bool look = TRUE;
158 /* Initialize */
159 y = py;
160 x = px;
162 /* Minimum distance */
163 min = dis / 2;
165 /* Look until done */
166 while (look)
168 /* Verify max distance */
169 if (dis > 200) dis = 200;
171 /* Try several locations */
172 for (i = 0; i < 500; i++)
174 /* Pick a (possibly illegal) location */
175 while (1)
177 y = rand_spread(py, dis);
178 x = rand_spread(px, dis);
179 d = distance(py, px, y, x);
180 if ((d >= min) && (d <= dis)) break;
183 /* Ignore illegal locations */
184 if (!in_bounds_fully(y, x)) continue;
186 /* Require "naked" floor space */
187 if (!cave_naked_bold(y, x)) continue;
189 /* No teleporting into vaults and such */
190 if (cave_info[y][x] & (CAVE_ICKY)) continue;
192 /* This grid looks good */
193 look = FALSE;
195 /* Stop looking */
196 break;
199 /* Increase the maximum distance */
200 dis = dis * 2;
202 /* Decrease the minimum distance */
203 min = min / 2;
206 /* Sound */
207 sound(MSG_TELEPORT);
209 /* Move player */
210 monster_swap(py, px, y, x);
212 /* Handle stuff XXX XXX XXX */
213 handle_stuff();
219 * Teleport player to a grid near the given location
221 * This function is slightly obsessive about correctness.
222 * This function allows teleporting into vaults (!)
224 void teleport_player_to(int ny, int nx)
226 int py = p_ptr->py;
227 int px = p_ptr->px;
229 int y, x;
231 int dis = 0, ctr = 0;
233 /* Initialize */
234 y = py;
235 x = px;
237 /* Find a usable location */
238 while (1)
240 /* Pick a nearby legal location */
241 while (1)
243 y = rand_spread(ny, dis);
244 x = rand_spread(nx, dis);
245 if (in_bounds_fully(y, x)) break;
248 /* Accept "naked" floor grids */
249 if (cave_naked_bold(y, x)) break;
251 /* Occasionally advance the distance */
252 if (++ctr > (4 * dis * dis + 4 * dis + 1))
254 ctr = 0;
255 dis++;
259 /* Sound */
260 sound(MSG_TELEPORT);
262 /* Move player */
263 monster_swap(py, px, y, x);
265 /* Handle stuff XXX XXX XXX */
266 handle_stuff();
272 * Teleport the player one level up or down (random when legal)
274 void teleport_player_level(void)
276 if (adult_ironman)
278 msg_print("Nothing happens.");
279 return;
283 if (!p_ptr->depth)
285 message(MSG_TPLEVEL, 0, "You sink through the floor.");
287 /* New depth */
288 p_ptr->depth++;
290 /* Leaving */
291 p_ptr->leaving = TRUE;
294 else if (is_quest(p_ptr->depth) || (p_ptr->depth >= MAX_DEPTH-1))
296 message(MSG_TPLEVEL, 0, "You rise up through the ceiling.");
298 /* New depth */
299 p_ptr->depth--;
301 /* Leaving */
302 p_ptr->leaving = TRUE;
305 else if (rand_int(100) < 50)
307 message(MSG_TPLEVEL, 0, "You rise up through the ceiling.");
309 /* New depth */
310 p_ptr->depth--;
312 /* Leaving */
313 p_ptr->leaving = TRUE;
316 else
318 message(MSG_TPLEVEL, 0, "You sink through the floor.");
320 /* New depth */
321 p_ptr->depth++;
323 /* Leaving */
324 p_ptr->leaving = TRUE;
334 * Return a color to use for the bolt/ball spells
336 static byte spell_color(int type)
338 /* Analyze */
339 switch (type)
341 case GF_MISSILE: return (TERM_VIOLET);
342 case GF_ACID: return (TERM_SLATE);
343 case GF_ELEC: return (TERM_BLUE);
344 case GF_FIRE: return (TERM_RED);
345 case GF_COLD: return (TERM_WHITE);
346 case GF_POIS: return (TERM_GREEN);
347 case GF_HOLY_ORB: return (TERM_L_DARK);
348 case GF_MANA: return (TERM_L_DARK);
349 case GF_ARROW: return (TERM_WHITE);
350 case GF_WATER: return (TERM_SLATE);
351 case GF_NETHER: return (TERM_L_GREEN);
352 case GF_CHAOS: return (TERM_VIOLET);
353 case GF_DISENCHANT: return (TERM_VIOLET);
354 case GF_NEXUS: return (TERM_L_RED);
355 case GF_CONFUSION: return (TERM_L_UMBER);
356 case GF_SOUND: return (TERM_YELLOW);
357 case GF_SHARD: return (TERM_UMBER);
358 case GF_FORCE: return (TERM_UMBER);
359 case GF_INERTIA: return (TERM_L_WHITE);
360 case GF_GRAVITY: return (TERM_L_WHITE);
361 case GF_TIME: return (TERM_L_BLUE);
362 case GF_LITE_WEAK: return (TERM_ORANGE);
363 case GF_LITE: return (TERM_ORANGE);
364 case GF_DARK_WEAK: return (TERM_L_DARK);
365 case GF_DARK: return (TERM_L_DARK);
366 case GF_PLASMA: return (TERM_RED);
367 case GF_METEOR: return (TERM_RED);
368 case GF_ICE: return (TERM_WHITE);
371 /* Standard "color" */
372 return (TERM_WHITE);
378 * Find the attr/char pair to use for a spell effect
380 * It is moving (or has moved) from (x,y) to (nx,ny).
382 * If the distance is not "one", we (may) return "*".
384 static u16b bolt_pict(int y, int x, int ny, int nx, int typ)
386 int base;
388 byte k;
390 byte a;
391 char c;
393 if (!(use_graphics && (arg_graphics == GRAPHICS_DAVID_GERVAIS)))
395 /* No motion (*) */
396 if ((ny == y) && (nx == x)) base = 0x30;
398 /* Vertical (|) */
399 else if (nx == x) base = 0x40;
401 /* Horizontal (-) */
402 else if (ny == y) base = 0x50;
404 /* Diagonal (/) */
405 else if ((ny-y) == (x-nx)) base = 0x60;
407 /* Diagonal (\) */
408 else if ((ny-y) == (nx-x)) base = 0x70;
410 /* Weird (*) */
411 else base = 0x30;
413 /* Basic spell color */
414 k = spell_color(typ);
416 /* Obtain attr/char */
417 a = misc_to_attr[base+k];
418 c = misc_to_char[base+k];
420 else
422 int add;
424 /* No motion (*) */
425 if ((ny == y) && (nx == x)) {base = 0x00; add = 0;}
427 /* Vertical (|) */
428 else if (nx == x) {base = 0x40; add = 0;}
430 /* Horizontal (-) */
431 else if (ny == y) {base = 0x40; add = 1;}
433 /* Diagonal (/) */
434 else if ((ny-y) == (x-nx)) {base = 0x40; add = 2;}
436 /* Diagonal (\) */
437 else if ((ny-y) == (nx-x)) {base = 0x40; add = 3;}
439 /* Weird (*) */
440 else {base = 0x00; add = 0;}
442 if (typ >= 0x40) k = 0;
443 else k = typ;
445 /* Obtain attr/char */
446 a = misc_to_attr[base+k];
447 c = misc_to_char[base+k] + add;
450 /* Create pict */
451 return (PICT(a,c));
458 * Decreases players hit points and sets death flag if necessary
460 * Invulnerability needs to be changed into a "shield" XXX XXX XXX
462 * Hack -- this function allows the user to save (or quit) the game
463 * when he dies, since the "You die." message is shown before setting
464 * the player to "dead".
466 void take_hit(int dam, cptr kb_str)
468 int old_chp = p_ptr->chp;
470 int warning = (p_ptr->mhp * op_ptr->hitpoint_warn / 10);
473 /* Paranoia */
474 if (p_ptr->is_dead) return;
477 /* Disturb */
478 disturb(1, 0);
480 /* Mega-Hack -- Apply "invulnerability" */
481 if (p_ptr->timed[TMD_INVULN] && (dam < 9000)) return;
483 /* Hurt the player */
484 p_ptr->chp -= dam;
486 /* Display the hitpoints */
487 p_ptr->redraw |= (PR_HP);
489 /* Window stuff */
490 p_ptr->window |= (PW_PLAYER_0 | PW_PLAYER_1);
492 /* Dead player */
493 if (p_ptr->chp < 0)
495 /* Hack -- Note death */
496 message(MSG_DEATH, 0, "You die.");
497 message_flush();
499 /* Note cause of death */
500 my_strcpy(p_ptr->died_from, kb_str, sizeof(p_ptr->died_from));
502 /* No longer a winner */
503 p_ptr->total_winner = FALSE;
505 /* Note death */
506 p_ptr->is_dead = TRUE;
508 /* Leaving */
509 p_ptr->leaving = TRUE;
511 /* Dead */
512 return;
515 /* Hitpoint warning */
516 if (p_ptr->chp < warning)
518 /* Hack -- bell on first notice */
519 if (old_chp > warning)
521 bell("Low hitpoint warning!");
524 /* Message */
525 message(MSG_HITPOINT_WARN, 0, "*** LOW HITPOINT WARNING! ***");
526 message_flush();
535 * Does a given class of objects (usually) hate acid?
536 * Note that acid can either melt or corrode something.
538 static bool hates_acid(const object_type *o_ptr)
540 /* Analyze the type */
541 switch (o_ptr->tval)
543 /* Wearable items */
544 case TV_ARROW:
545 case TV_BOLT:
546 case TV_BOW:
547 case TV_SWORD:
548 case TV_HAFTED:
549 case TV_POLEARM:
550 case TV_HELM:
551 case TV_CROWN:
552 case TV_SHIELD:
553 case TV_BOOTS:
554 case TV_GLOVES:
555 case TV_CLOAK:
556 case TV_SOFT_ARMOR:
557 case TV_HARD_ARMOR:
558 case TV_DRAG_ARMOR:
560 return (TRUE);
563 /* Staffs/Scrolls are wood/paper */
564 case TV_STAFF:
565 case TV_SCROLL:
567 return (TRUE);
570 /* Ouch */
571 case TV_CHEST:
573 return (TRUE);
576 /* Junk is useless */
577 case TV_SKELETON:
578 case TV_BOTTLE:
579 case TV_JUNK:
581 return (TRUE);
585 return (FALSE);
590 * Does a given object (usually) hate electricity?
592 static bool hates_elec(const object_type *o_ptr)
594 switch (o_ptr->tval)
596 case TV_RING:
597 case TV_WAND:
598 case TV_ROD:
600 return (TRUE);
604 return (FALSE);
609 * Does a given object (usually) hate fire?
610 * Hafted/Polearm weapons have wooden shafts.
611 * Arrows/Bows are mostly wooden.
613 static bool hates_fire(const object_type *o_ptr)
615 /* Analyze the type */
616 switch (o_ptr->tval)
618 /* Wearable */
619 case TV_LITE:
620 case TV_ARROW:
621 case TV_BOW:
622 case TV_HAFTED:
623 case TV_POLEARM:
624 case TV_BOOTS:
625 case TV_GLOVES:
626 case TV_CLOAK:
627 case TV_SOFT_ARMOR:
629 return (TRUE);
632 /* Books */
633 case TV_MAGIC_BOOK:
634 case TV_PRAYER_BOOK:
636 return (TRUE);
639 /* Chests */
640 case TV_CHEST:
642 return (TRUE);
645 /* Staffs/Scrolls burn */
646 case TV_STAFF:
647 case TV_SCROLL:
649 return (TRUE);
653 return (FALSE);
658 * Does a given object (usually) hate cold?
660 static bool hates_cold(const object_type *o_ptr)
662 switch (o_ptr->tval)
664 case TV_POTION:
665 case TV_FLASK:
666 case TV_BOTTLE:
668 return (TRUE);
672 return (FALSE);
684 * Melt something
686 static int set_acid_destroy(const object_type *o_ptr)
688 u32b f1, f2, f3;
689 if (!hates_acid(o_ptr)) return (FALSE);
690 object_flags(o_ptr, &f1, &f2, &f3);
691 if (f3 & (TR3_IGNORE_ACID)) return (FALSE);
692 return (TRUE);
697 * Electrical damage
699 static int set_elec_destroy(const object_type *o_ptr)
701 u32b f1, f2, f3;
702 if (!hates_elec(o_ptr)) return (FALSE);
703 object_flags(o_ptr, &f1, &f2, &f3);
704 if (f3 & (TR3_IGNORE_ELEC)) return (FALSE);
705 return (TRUE);
710 * Burn something
712 static int set_fire_destroy(const object_type *o_ptr)
714 u32b f1, f2, f3;
715 if (!hates_fire(o_ptr)) return (FALSE);
716 object_flags(o_ptr, &f1, &f2, &f3);
717 if (f3 & (TR3_IGNORE_FIRE)) return (FALSE);
718 return (TRUE);
723 * Freeze things
725 static int set_cold_destroy(const object_type *o_ptr)
727 u32b f1, f2, f3;
728 if (!hates_cold(o_ptr)) return (FALSE);
729 object_flags(o_ptr, &f1, &f2, &f3);
730 if (f3 & (TR3_IGNORE_COLD)) return (FALSE);
731 return (TRUE);
738 * This seems like a pretty standard "typedef"
740 typedef int (*inven_func)(const object_type *);
743 * Destroys a type of item on a given percent chance
744 * Note that missiles are no longer necessarily all destroyed
746 * Returns number of items destroyed.
748 static int inven_damage(inven_func typ, int perc)
750 int i, j, k, amt;
752 object_type *o_ptr;
754 char o_name[80];
756 bool damage;
758 /* Count the casualties */
759 k = 0;
761 /* Scan through the slots backwards */
762 for (i = 0; i < INVEN_PACK; i++)
764 o_ptr = &inventory[i];
766 /* Skip non-objects */
767 if (!o_ptr->k_idx) continue;
769 /* Hack -- for now, skip artifacts */
770 if (artifact_p(o_ptr)) continue;
772 /* Give this item slot a shot at death */
773 if ((*typ)(o_ptr))
775 /* Scale the destruction chance up */
776 int chance = perc * 100;
778 damage = FALSE;
780 /* Analyze the type to see if we just damage it */
781 switch (o_ptr->tval)
783 /* Weapons */
784 case TV_BOW:
785 case TV_SWORD:
786 case TV_HAFTED:
787 case TV_POLEARM:
788 case TV_DIGGING:
790 /* Chance to damage it */
791 if (rand_int(10000) < perc)
793 /* Damage the item */
794 o_ptr->to_h--;
795 o_ptr->to_d--;
797 /* Damaged! */
798 damage = TRUE;
800 else continue;
802 break;
805 /* Wearable items */
806 case TV_HELM:
807 case TV_CROWN:
808 case TV_SHIELD:
809 case TV_BOOTS:
810 case TV_GLOVES:
811 case TV_CLOAK:
812 case TV_SOFT_ARMOR:
813 case TV_HARD_ARMOR:
814 case TV_DRAG_ARMOR:
816 /* Chance to damage it */
817 if (rand_int(10000) < perc)
819 /* Damage the item */
820 o_ptr->to_a--;
822 /* Damaged! */
823 damage = TRUE;
825 else continue;
827 break;
830 /* Rods are tough */
831 case TV_ROD:
833 chance = (chance / 4);
835 break;
839 /* Damage instead of destroy */
840 if (damage)
842 /* Calculate bonuses */
843 p_ptr->update |= (PU_BONUS);
845 /* Window stuff */
846 p_ptr->window |= (PW_EQUIP | PW_PLAYER_0 | PW_PLAYER_1);
848 /* Casualty count */
849 amt = o_ptr->number;
852 /* Count the casualties */
853 else for (amt = j = 0; j < o_ptr->number; ++j)
855 if (rand_int(10000) < chance) amt++;
858 /* Some casualities */
859 if (amt)
861 /* Get a description */
862 object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 3);
864 /* Message */
865 message_format(MSG_DESTROY, 0, "%sour %s (%c) %s %s!",
866 ((o_ptr->number > 1) ?
867 ((amt == o_ptr->number) ? "All of y" :
868 (amt > 1 ? "Some of y" : "One of y")) : "Y"),
869 o_name, index_to_label(i),
870 ((amt > 1) ? "were" : "was"),
871 (damage ? "damaged" : "destroyed"));
873 /* Damage already done? */
874 if (damage) continue;
876 /* Hack -- If rods, wands, or staves are destroyed, the total
877 * maximum timeout or charges of the stack needs to be reduced,
878 * unless all the items are being destroyed. -LM-
880 if (((o_ptr->tval == TV_WAND) ||
881 (o_ptr->tval == TV_STAFF) ||
882 (o_ptr->tval == TV_ROD)) &&
883 (amt < o_ptr->number))
885 o_ptr->pval -= o_ptr->pval * amt / o_ptr->number;
888 /* Destroy "amt" items */
889 inven_item_increase(i, -amt);
890 inven_item_optimize(i);
892 /* Count the casualties */
893 k += amt;
898 /* Return the casualty count */
899 return (k);
906 * Acid has hit the player, attempt to affect some armor.
908 * Note that the "base armor" of an object never changes.
910 * If any armor is damaged (or resists), the player takes less damage.
912 static int minus_ac(void)
914 object_type *o_ptr = NULL;
916 u32b f1, f2, f3;
918 char o_name[80];
921 /* Pick a (possibly empty) inventory slot */
922 switch (randint(6))
924 case 1: o_ptr = &inventory[INVEN_BODY]; break;
925 case 2: o_ptr = &inventory[INVEN_ARM]; break;
926 case 3: o_ptr = &inventory[INVEN_OUTER]; break;
927 case 4: o_ptr = &inventory[INVEN_HANDS]; break;
928 case 5: o_ptr = &inventory[INVEN_HEAD]; break;
929 case 6: o_ptr = &inventory[INVEN_FEET]; break;
932 /* Nothing to damage */
933 if (!o_ptr->k_idx) return (FALSE);
935 /* No damage left to be done */
936 if (o_ptr->ac + o_ptr->to_a <= 0) return (FALSE);
939 /* Describe */
940 object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 0);
942 /* Extract the flags */
943 object_flags(o_ptr, &f1, &f2, &f3);
945 /* Object resists */
946 if (f3 & (TR3_IGNORE_ACID))
948 msg_format("Your %s is unaffected!", o_name);
950 return (TRUE);
953 /* Message */
954 msg_format("Your %s is damaged!", o_name);
956 /* Damage the item */
957 o_ptr->to_a--;
959 /* Calculate bonuses */
960 p_ptr->update |= (PU_BONUS);
962 /* Window stuff */
963 p_ptr->window |= (PW_EQUIP | PW_PLAYER_0 | PW_PLAYER_1);
965 /* Item was damaged */
966 return (TRUE);
971 * Hurt the player with Acid
973 void acid_dam(int dam, cptr kb_str)
975 int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
977 /* Total Immunity */
978 if (p_ptr->immune_acid || (dam <= 0)) return;
980 /* Resist the damage */
981 if (p_ptr->resist_acid) dam = (dam + 2) / 3;
982 if (p_ptr->timed[TMD_OPP_ACID]) dam = (dam + 2) / 3;
984 /* If any armor gets hit, defend the player */
985 if (minus_ac()) dam = (dam + 1) / 2;
987 /* Take damage */
988 take_hit(dam, kb_str);
990 /* Inventory damage */
991 inven_damage(set_acid_destroy, inv);
996 * Hurt the player with electricity
998 void elec_dam(int dam, cptr kb_str)
1000 int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1002 /* Total immunity */
1003 if (p_ptr->immune_elec || (dam <= 0)) return;
1005 /* Resist the damage */
1006 if (p_ptr->timed[TMD_OPP_ELEC]) dam = (dam + 2) / 3;
1007 if (p_ptr->resist_elec) dam = (dam + 2) / 3;
1009 /* Take damage */
1010 take_hit(dam, kb_str);
1012 /* Inventory damage */
1013 inven_damage(set_elec_destroy, inv);
1020 * Hurt the player with Fire
1022 void fire_dam(int dam, cptr kb_str)
1024 int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1026 /* Totally immune */
1027 if (p_ptr->immune_fire || (dam <= 0)) return;
1029 /* Resist the damage */
1030 if (p_ptr->resist_fire) dam = (dam + 2) / 3;
1031 if (p_ptr->timed[TMD_OPP_FIRE]) dam = (dam + 2) / 3;
1033 /* Take damage */
1034 take_hit(dam, kb_str);
1036 /* Inventory damage */
1037 inven_damage(set_fire_destroy, inv);
1042 * Hurt the player with Cold
1044 void cold_dam(int dam, cptr kb_str)
1046 int inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
1048 /* Total immunity */
1049 if (p_ptr->immune_cold || (dam <= 0)) return;
1051 /* Resist the damage */
1052 if (p_ptr->resist_cold) dam = (dam + 2) / 3;
1053 if (p_ptr->timed[TMD_OPP_COLD]) dam = (dam + 2) / 3;
1055 /* Take damage */
1056 take_hit(dam, kb_str);
1058 /* Inventory damage */
1059 inven_damage(set_cold_destroy, inv);
1067 * Increase a stat by one randomized level
1069 * Most code will "restore" a stat before calling this function,
1070 * in particular, stat potions will always restore the stat and
1071 * then increase the fully restored value.
1073 bool inc_stat(int stat)
1075 int value, gain;
1077 /* Then augment the current/max stat */
1078 value = p_ptr->stat_cur[stat];
1080 /* Cannot go above 18/100 */
1081 if (value < 18+100)
1083 /* Gain one (sometimes two) points */
1084 if (value < 18)
1086 gain = ((rand_int(100) < 75) ? 1 : 2);
1087 value += gain;
1090 /* Gain 1/6 to 1/3 of distance to 18/100 */
1091 else if (value < 18+98)
1093 /* Approximate gain value */
1094 gain = (((18+100) - value) / 2 + 3) / 2;
1096 /* Paranoia */
1097 if (gain < 1) gain = 1;
1099 /* Apply the bonus */
1100 value += randint(gain) + gain / 2;
1102 /* Maximal value */
1103 if (value > 18+99) value = 18 + 99;
1106 /* Gain one point at a time */
1107 else
1109 value++;
1112 /* Save the new value */
1113 p_ptr->stat_cur[stat] = value;
1115 /* Bring up the maximum too */
1116 if (value > p_ptr->stat_max[stat])
1118 p_ptr->stat_max[stat] = value;
1121 /* Recalculate bonuses */
1122 p_ptr->update |= (PU_BONUS);
1124 /* Success */
1125 return (TRUE);
1128 /* Nothing to gain */
1129 return (FALSE);
1135 * Decreases a stat by an amount indended to vary from 0 to 100 percent.
1137 * Note that "permanent" means that the *given* amount is permanent,
1138 * not that the new value becomes permanent. This may not work exactly
1139 * as expected, due to "weirdness" in the algorithm, but in general,
1140 * if your stat is already drained, the "max" value will not drop all
1141 * the way down to the "cur" value.
1143 bool dec_stat(int stat, int amount, bool permanent)
1145 int cur, max, loss, same, res = FALSE;
1148 /* Get the current value */
1149 cur = p_ptr->stat_cur[stat];
1150 max = p_ptr->stat_max[stat];
1152 /* Note when the values are identical */
1153 same = (cur == max);
1155 /* Damage "current" value */
1156 if (cur > 3)
1158 /* Handle "low" values */
1159 if (cur <= 18)
1161 if (amount > 90) cur--;
1162 if (amount > 50) cur--;
1163 if (amount > 20) cur--;
1164 cur--;
1167 /* Handle "high" values */
1168 else
1170 /* Hack -- Decrement by a random amount between one-quarter */
1171 /* and one-half of the stat bonus times the percentage, with a */
1172 /* minimum damage of half the percentage. -CWS */
1173 loss = (((cur-18) / 2 + 1) / 2 + 1);
1175 /* Paranoia */
1176 if (loss < 1) loss = 1;
1178 /* Randomize the loss */
1179 loss = ((randint(loss) + loss) * amount) / 100;
1181 /* Maximal loss */
1182 if (loss < amount/2) loss = amount/2;
1184 /* Lose some points */
1185 cur = cur - loss;
1187 /* Hack -- Only reduce stat to 17 sometimes */
1188 if (cur < 18) cur = (amount <= 20) ? 18 : 17;
1191 /* Prevent illegal values */
1192 if (cur < 3) cur = 3;
1194 /* Something happened */
1195 if (cur != p_ptr->stat_cur[stat]) res = TRUE;
1198 /* Damage "max" value */
1199 if (permanent && (max > 3))
1201 /* Handle "low" values */
1202 if (max <= 18)
1204 if (amount > 90) max--;
1205 if (amount > 50) max--;
1206 if (amount > 20) max--;
1207 max--;
1210 /* Handle "high" values */
1211 else
1213 /* Hack -- Decrement by a random amount between one-quarter */
1214 /* and one-half of the stat bonus times the percentage, with a */
1215 /* minimum damage of half the percentage. -CWS */
1216 loss = (((max-18) / 2 + 1) / 2 + 1);
1217 if (loss < 1) loss = 1;
1218 loss = ((randint(loss) + loss) * amount) / 100;
1219 if (loss < amount/2) loss = amount/2;
1221 /* Lose some points */
1222 max = max - loss;
1224 /* Hack -- Only reduce stat to 17 sometimes */
1225 if (max < 18) max = (amount <= 20) ? 18 : 17;
1228 /* Hack -- keep it clean */
1229 if (same || (max < cur)) max = cur;
1231 /* Something happened */
1232 if (max != p_ptr->stat_max[stat]) res = TRUE;
1235 /* Apply changes */
1236 if (res)
1238 /* Actually set the stat to its new value. */
1239 p_ptr->stat_cur[stat] = cur;
1240 p_ptr->stat_max[stat] = max;
1242 /* Recalculate bonuses */
1243 p_ptr->update |= (PU_BONUS);
1246 /* Done */
1247 return (res);
1252 * Restore a stat. Return TRUE only if this actually makes a difference.
1254 bool res_stat(int stat)
1256 /* Restore if needed */
1257 if (p_ptr->stat_cur[stat] != p_ptr->stat_max[stat])
1259 /* Restore */
1260 p_ptr->stat_cur[stat] = p_ptr->stat_max[stat];
1262 /* Recalculate bonuses */
1263 p_ptr->update |= (PU_BONUS);
1265 /* Success */
1266 return (TRUE);
1269 /* Nothing to restore */
1270 return (FALSE);
1277 * Apply disenchantment to the player's stuff
1279 * This function is also called from the "melee" code.
1281 * The "mode" is currently unused.
1283 * Return "TRUE" if the player notices anything.
1285 bool apply_disenchant(int mode)
1287 int t = 0;
1289 object_type *o_ptr;
1291 char o_name[80];
1294 /* Unused parameter */
1295 (void)mode;
1297 /* Pick a random slot */
1298 switch (randint(8))
1300 case 1: t = INVEN_WIELD; break;
1301 case 2: t = INVEN_BOW; break;
1302 case 3: t = INVEN_BODY; break;
1303 case 4: t = INVEN_OUTER; break;
1304 case 5: t = INVEN_ARM; break;
1305 case 6: t = INVEN_HEAD; break;
1306 case 7: t = INVEN_HANDS; break;
1307 case 8: t = INVEN_FEET; break;
1310 /* Get the item */
1311 o_ptr = &inventory[t];
1313 /* No item, nothing happens */
1314 if (!o_ptr->k_idx) return (FALSE);
1317 /* Nothing to disenchant */
1318 if ((o_ptr->to_h <= 0) && (o_ptr->to_d <= 0) && (o_ptr->to_a <= 0))
1320 /* Nothing to notice */
1321 return (FALSE);
1325 /* Describe the object */
1326 object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 0);
1329 /* Artifacts have 60% chance to resist */
1330 if (artifact_p(o_ptr) && (rand_int(100) < 60))
1332 /* Message */
1333 msg_format("Your %s (%c) resist%s disenchantment!",
1334 o_name, index_to_label(t),
1335 ((o_ptr->number != 1) ? "" : "s"));
1337 /* Notice */
1338 return (TRUE);
1342 /* Disenchant tohit */
1343 if (o_ptr->to_h > 0) o_ptr->to_h--;
1344 if ((o_ptr->to_h > 5) && (rand_int(100) < 20)) o_ptr->to_h--;
1346 /* Disenchant todam */
1347 if (o_ptr->to_d > 0) o_ptr->to_d--;
1348 if ((o_ptr->to_d > 5) && (rand_int(100) < 20)) o_ptr->to_d--;
1350 /* Disenchant toac */
1351 if (o_ptr->to_a > 0) o_ptr->to_a--;
1352 if ((o_ptr->to_a > 5) && (rand_int(100) < 20)) o_ptr->to_a--;
1354 /* Message */
1355 msg_format("Your %s (%c) %s disenchanted!",
1356 o_name, index_to_label(t),
1357 ((o_ptr->number != 1) ? "were" : "was"));
1359 /* Recalculate bonuses */
1360 p_ptr->update |= (PU_BONUS);
1362 /* Window stuff */
1363 p_ptr->window |= (PW_EQUIP | PW_PLAYER_0 | PW_PLAYER_1);
1365 /* Notice */
1366 return (TRUE);
1371 * Apply Nexus
1373 static void apply_nexus(const monster_type *m_ptr)
1375 int max1, cur1, max2, cur2, ii, jj;
1377 switch (randint(7))
1379 case 1: case 2: case 3:
1381 teleport_player(200);
1382 break;
1385 case 4: case 5:
1387 teleport_player_to(m_ptr->fy, m_ptr->fx);
1388 break;
1391 case 6:
1393 if (rand_int(100) < p_ptr->skills[SKILL_SAV])
1395 msg_print("You resist the effects!");
1396 break;
1399 /* Teleport Level */
1400 teleport_player_level();
1401 break;
1404 case 7:
1406 if (rand_int(100) < p_ptr->skills[SKILL_SAV])
1408 msg_print("You resist the effects!");
1409 break;
1412 msg_print("Your body starts to scramble...");
1414 /* Pick a pair of stats */
1415 ii = rand_int(A_MAX);
1416 for (jj = ii; jj == ii; jj = rand_int(A_MAX)) /* loop */;
1418 max1 = p_ptr->stat_max[ii];
1419 cur1 = p_ptr->stat_cur[ii];
1420 max2 = p_ptr->stat_max[jj];
1421 cur2 = p_ptr->stat_cur[jj];
1423 p_ptr->stat_max[ii] = max2;
1424 p_ptr->stat_cur[ii] = cur2;
1425 p_ptr->stat_max[jj] = max1;
1426 p_ptr->stat_cur[jj] = cur1;
1428 p_ptr->update |= (PU_BONUS);
1430 break;
1440 * Mega-Hack -- track "affected" monsters (see "project()" comments)
1442 static int project_m_n;
1443 static int project_m_x;
1444 static int project_m_y;
1449 * We are called from "project()" to "damage" terrain features
1451 * We are called both for "beam" effects and "ball" effects.
1453 * The "r" parameter is the "distance from ground zero".
1455 * Note that we determine if the player can "see" anything that happens
1456 * by taking into account: blindness, line-of-sight, and illumination.
1458 * We return "TRUE" if the effect of the projection is "obvious".
1460 * Hack -- We also "see" grids which are "memorized".
1462 * Perhaps we should affect doors and/or walls.
1464 static bool project_f(int who, int r, int y, int x, int dam, int typ)
1466 bool obvious = FALSE;
1468 /* Unused parameters */
1469 (void)who;
1470 (void)r;
1471 (void)dam;
1473 #if 0 /* unused */
1474 /* Reduce damage by distance */
1475 dam = (dam + r) / (r + 1);
1476 #endif /* 0 */
1478 /* Analyze the type */
1479 switch (typ)
1481 /* Ignore most effects */
1482 case GF_ACID:
1483 case GF_ELEC:
1484 case GF_FIRE:
1485 case GF_COLD:
1486 case GF_PLASMA:
1487 case GF_METEOR:
1488 case GF_ICE:
1489 case GF_SHARD:
1490 case GF_FORCE:
1491 case GF_SOUND:
1492 case GF_MANA:
1493 case GF_HOLY_ORB:
1495 break;
1498 /* Destroy Traps (and Locks) */
1499 case GF_KILL_TRAP:
1501 /* Reveal secret doors */
1502 if (cave_feat[y][x] == FEAT_SECRET)
1504 place_closed_door(y, x);
1506 /* Check line of sight */
1507 if (player_has_los_bold(y, x))
1509 obvious = TRUE;
1513 /* Destroy traps */
1514 if ((cave_feat[y][x] == FEAT_INVIS) ||
1515 ((cave_feat[y][x] >= FEAT_TRAP_HEAD) &&
1516 (cave_feat[y][x] <= FEAT_TRAP_TAIL)))
1518 /* Check line of sight */
1519 if (player_has_los_bold(y, x))
1521 msg_print("There is a bright flash of light!");
1522 obvious = TRUE;
1525 /* Forget the trap */
1526 cave_info[y][x] &= ~(CAVE_MARK);
1528 /* Destroy the trap */
1529 cave_set_feat(y, x, FEAT_FLOOR);
1532 /* Locked doors are unlocked */
1533 else if ((cave_feat[y][x] >= FEAT_DOOR_HEAD + 0x01) &&
1534 (cave_feat[y][x] <= FEAT_DOOR_HEAD + 0x07))
1536 /* Unlock the door */
1537 cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
1539 /* Check line of sound */
1540 if (player_has_los_bold(y, x))
1542 msg_print("Click!");
1543 obvious = TRUE;
1547 break;
1550 /* Destroy Doors (and traps) */
1551 case GF_KILL_DOOR:
1553 /* Destroy all doors and traps */
1554 if ((cave_feat[y][x] == FEAT_OPEN) ||
1555 (cave_feat[y][x] == FEAT_BROKEN) ||
1556 (cave_feat[y][x] == FEAT_INVIS) ||
1557 ((cave_feat[y][x] >= FEAT_TRAP_HEAD) &&
1558 (cave_feat[y][x] <= FEAT_TRAP_TAIL)) ||
1559 ((cave_feat[y][x] >= FEAT_DOOR_HEAD) &&
1560 (cave_feat[y][x] <= FEAT_DOOR_TAIL)))
1562 /* Check line of sight */
1563 if (player_has_los_bold(y, x))
1565 /* Message */
1566 msg_print("There is a bright flash of light!");
1567 obvious = TRUE;
1569 /* Visibility change */
1570 if ((cave_feat[y][x] >= FEAT_DOOR_HEAD) &&
1571 (cave_feat[y][x] <= FEAT_DOOR_TAIL))
1573 /* Update the visuals */
1574 p_ptr->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
1578 /* Forget the door */
1579 cave_info[y][x] &= ~(CAVE_MARK);
1581 /* Destroy the feature */
1582 cave_set_feat(y, x, FEAT_FLOOR);
1585 break;
1588 /* Destroy walls (and doors) */
1589 case GF_KILL_WALL:
1591 /* Non-walls (etc) */
1592 if (cave_floor_bold(y, x)) break;
1594 /* Permanent walls */
1595 if (cave_feat[y][x] >= FEAT_PERM_EXTRA) break;
1597 /* Granite */
1598 if (cave_feat[y][x] >= FEAT_WALL_EXTRA)
1600 /* Message */
1601 if (cave_info[y][x] & (CAVE_MARK))
1603 msg_print("The wall turns into mud!");
1604 obvious = TRUE;
1607 /* Forget the wall */
1608 cave_info[y][x] &= ~(CAVE_MARK);
1610 /* Destroy the wall */
1611 cave_set_feat(y, x, FEAT_FLOOR);
1614 /* Quartz / Magma with treasure */
1615 else if (cave_feat[y][x] >= FEAT_MAGMA_H)
1617 /* Message */
1618 if (cave_info[y][x] & (CAVE_MARK))
1620 msg_print("The vein turns into mud!");
1621 msg_print("You have found something!");
1622 obvious = TRUE;
1625 /* Forget the wall */
1626 cave_info[y][x] &= ~(CAVE_MARK);
1628 /* Destroy the wall */
1629 cave_set_feat(y, x, FEAT_FLOOR);
1631 /* Place some gold */
1632 place_gold(y, x);
1635 /* Quartz / Magma */
1636 else if (cave_feat[y][x] >= FEAT_MAGMA)
1638 /* Message */
1639 if (cave_info[y][x] & (CAVE_MARK))
1641 msg_print("The vein turns into mud!");
1642 obvious = TRUE;
1645 /* Forget the wall */
1646 cave_info[y][x] &= ~(CAVE_MARK);
1648 /* Destroy the wall */
1649 cave_set_feat(y, x, FEAT_FLOOR);
1652 /* Rubble */
1653 else if (cave_feat[y][x] == FEAT_RUBBLE)
1655 /* Message */
1656 if (cave_info[y][x] & (CAVE_MARK))
1658 msg_print("The rubble turns into mud!");
1659 obvious = TRUE;
1662 /* Forget the wall */
1663 cave_info[y][x] &= ~(CAVE_MARK);
1665 /* Destroy the rubble */
1666 cave_set_feat(y, x, FEAT_FLOOR);
1668 /* Hack -- place an object */
1669 if (rand_int(100) < 10)
1671 /* Found something */
1672 if (player_can_see_bold(y, x))
1674 msg_print("There was something buried in the rubble!");
1675 obvious = TRUE;
1678 /* Place gold */
1679 place_object(y, x, FALSE, FALSE);
1683 /* Destroy doors (and secret doors) */
1684 else /* if (cave_feat[y][x] >= FEAT_DOOR_HEAD) */
1686 /* Hack -- special message */
1687 if (cave_info[y][x] & (CAVE_MARK))
1689 msg_print("The door turns into mud!");
1690 obvious = TRUE;
1693 /* Forget the wall */
1694 cave_info[y][x] &= ~(CAVE_MARK);
1696 /* Destroy the feature */
1697 cave_set_feat(y, x, FEAT_FLOOR);
1700 /* Update the visuals */
1701 p_ptr->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
1703 /* Fully update the flow */
1704 p_ptr->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW);
1706 break;
1709 /* Make doors */
1710 case GF_MAKE_DOOR:
1712 /* Require a "naked" floor grid */
1713 if (!cave_naked_bold(y, x)) break;
1715 /* Create closed door */
1716 cave_set_feat(y, x, FEAT_DOOR_HEAD + 0x00);
1718 /* Observe */
1719 if (cave_info[y][x] & (CAVE_MARK)) obvious = TRUE;
1721 /* Update the visuals */
1722 p_ptr->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
1724 break;
1727 /* Make traps */
1728 case GF_MAKE_TRAP:
1730 /* Require a "naked" floor grid */
1731 if (!cave_naked_bold(y, x)) break;
1733 /* Place a trap */
1734 place_trap(y, x);
1736 break;
1739 /* Lite up the grid */
1740 case GF_LITE_WEAK:
1741 case GF_LITE:
1743 /* Turn on the light */
1744 cave_info[y][x] |= (CAVE_GLOW);
1746 /* Grid is in line of sight */
1747 if (player_has_los_bold(y, x))
1749 if (!p_ptr->timed[TMD_BLIND])
1751 /* Observe */
1752 obvious = TRUE;
1755 /* Fully update the visuals */
1756 p_ptr->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS);
1759 break;
1762 /* Darken the grid */
1763 case GF_DARK_WEAK:
1764 case GF_DARK:
1766 /* Turn off the light */
1767 cave_info[y][x] &= ~(CAVE_GLOW);
1769 /* Hack -- Forget "boring" grids */
1770 if (cave_feat[y][x] <= FEAT_INVIS)
1772 /* Forget */
1773 cave_info[y][x] &= ~(CAVE_MARK);
1776 /* Grid is in line of sight */
1777 if (player_has_los_bold(y, x))
1779 /* Observe */
1780 obvious = TRUE;
1782 /* Fully update the visuals */
1783 p_ptr->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS);
1786 /* All done */
1787 break;
1791 /* Return "Anything seen?" */
1792 return (obvious);
1798 * We are called from "project()" to "damage" objects
1800 * We are called both for "beam" effects and "ball" effects.
1802 * Perhaps we should only SOMETIMES damage things on the ground.
1804 * The "r" parameter is the "distance from ground zero".
1806 * Note that we determine if the player can "see" anything that happens
1807 * by taking into account: blindness, line-of-sight, and illumination.
1809 * Hack -- We also "see" objects which are "memorized".
1811 * We return "TRUE" if the effect of the projection is "obvious".
1813 static bool project_o(int who, int r, int y, int x, int dam, int typ)
1815 s16b this_o_idx, next_o_idx = 0;
1817 bool obvious = FALSE;
1819 u32b f1, f2, f3;
1821 char o_name[80];
1824 /* Unused parameters */
1825 (void)who;
1826 (void)r;
1827 (void)dam;
1829 #if 0 /* unused */
1830 /* Reduce damage by distance */
1831 dam = (dam + r) / (r + 1);
1832 #endif /* 0 */
1835 /* Scan all objects in the grid */
1836 for (this_o_idx = cave_o_idx[y][x]; this_o_idx; this_o_idx = next_o_idx)
1838 object_type *o_ptr;
1840 bool is_art = FALSE;
1841 bool ignore = FALSE;
1842 bool plural = FALSE;
1843 bool do_kill = FALSE;
1845 cptr note_kill = NULL;
1847 /* Get the object */
1848 o_ptr = &o_list[this_o_idx];
1850 /* Get the next object */
1851 next_o_idx = o_ptr->next_o_idx;
1853 /* Extract the flags */
1854 object_flags(o_ptr, &f1, &f2, &f3);
1856 /* Get the "plural"-ness */
1857 if (o_ptr->number > 1) plural = TRUE;
1859 /* Check for artifact */
1860 if (artifact_p(o_ptr)) is_art = TRUE;
1862 /* Analyze the type */
1863 switch (typ)
1865 /* Acid -- Lots of things */
1866 case GF_ACID:
1868 if (hates_acid(o_ptr))
1870 do_kill = TRUE;
1871 note_kill = (plural ? " melt!" : " melts!");
1872 if (f3 & (TR3_IGNORE_ACID)) ignore = TRUE;
1874 break;
1877 /* Elec -- Rings and Wands */
1878 case GF_ELEC:
1880 if (hates_elec(o_ptr))
1882 do_kill = TRUE;
1883 note_kill = (plural ? " are destroyed!" : " is destroyed!");
1884 if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
1886 break;
1889 /* Fire -- Flammable objects */
1890 case GF_FIRE:
1892 if (hates_fire(o_ptr))
1894 do_kill = TRUE;
1895 note_kill = (plural ? " burn up!" : " burns up!");
1896 if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
1898 break;
1901 /* Cold -- potions and flasks */
1902 case GF_COLD:
1904 if (hates_cold(o_ptr))
1906 note_kill = (plural ? " shatter!" : " shatters!");
1907 do_kill = TRUE;
1908 if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
1910 break;
1913 /* Fire + Elec */
1914 case GF_PLASMA:
1916 if (hates_fire(o_ptr))
1918 do_kill = TRUE;
1919 note_kill = (plural ? " burn up!" : " burns up!");
1920 if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
1922 if (hates_elec(o_ptr))
1924 ignore = FALSE;
1925 do_kill = TRUE;
1926 note_kill = (plural ? " are destroyed!" : " is destroyed!");
1927 if (f3 & (TR3_IGNORE_ELEC)) ignore = TRUE;
1929 break;
1932 /* Fire + Cold */
1933 case GF_METEOR:
1935 if (hates_fire(o_ptr))
1937 do_kill = TRUE;
1938 note_kill = (plural ? " burn up!" : " burns up!");
1939 if (f3 & (TR3_IGNORE_FIRE)) ignore = TRUE;
1941 if (hates_cold(o_ptr))
1943 ignore = FALSE;
1944 do_kill = TRUE;
1945 note_kill = (plural ? " shatter!" : " shatters!");
1946 if (f3 & (TR3_IGNORE_COLD)) ignore = TRUE;
1948 break;
1951 /* Hack -- break potions and such */
1952 case GF_ICE:
1953 case GF_SHARD:
1954 case GF_FORCE:
1955 case GF_SOUND:
1957 if (hates_cold(o_ptr))
1959 note_kill = (plural ? " shatter!" : " shatters!");
1960 do_kill = TRUE;
1962 break;
1965 /* Mana -- destroys everything */
1966 case GF_MANA:
1968 do_kill = TRUE;
1969 note_kill = (plural ? " are destroyed!" : " is destroyed!");
1970 break;
1973 /* Holy Orb -- destroys cursed non-artifacts */
1974 case GF_HOLY_ORB:
1976 if (cursed_p(o_ptr))
1978 do_kill = TRUE;
1979 note_kill = (plural ? " are destroyed!" : " is destroyed!");
1981 break;
1984 /* Unlock chests */
1985 case GF_KILL_TRAP:
1986 case GF_KILL_DOOR:
1988 /* Chests are noticed only if trapped or locked */
1989 if (o_ptr->tval == TV_CHEST)
1991 /* Disarm/Unlock traps */
1992 if (o_ptr->pval > 0)
1994 /* Disarm or Unlock */
1995 o_ptr->pval = (0 - o_ptr->pval);
1997 /* Identify */
1998 object_known(o_ptr);
2000 /* Notice */
2001 if (o_ptr->marked)
2003 msg_print("Click!");
2004 obvious = TRUE;
2009 break;
2014 /* Attempt to destroy the object */
2015 if (do_kill)
2017 /* Effect "observed" */
2018 if (o_ptr->marked)
2020 obvious = TRUE;
2021 object_desc(o_name, sizeof(o_name), o_ptr, FALSE, 0);
2024 /* Artifacts, and other objects, get to resist */
2025 if (is_art || ignore)
2027 /* Observe the resist */
2028 if (o_ptr->marked)
2030 msg_format("The %s %s unaffected!",
2031 o_name, (plural ? "are" : "is"));
2035 /* Kill it */
2036 else
2038 /* Describe if needed */
2039 if (o_ptr->marked && note_kill)
2041 message_format(MSG_DESTROY, 0, "The %s%s", o_name, note_kill);
2044 /* Delete the object */
2045 delete_object_idx(this_o_idx);
2047 /* Redraw */
2048 lite_spot(y, x);
2053 /* Return "Anything seen?" */
2054 return (obvious);
2060 * Helper function for "project()" below.
2062 * Handle a beam/bolt/ball causing damage to a monster.
2064 * This routine takes a "source monster" (by index) which is mostly used to
2065 * determine if the player is causing the damage, and a "radius" (see below),
2066 * which is used to decrease the power of explosions with distance, and a
2067 * location, via integers which are modified by certain types of attacks
2068 * (polymorph and teleport being the obvious ones), a default damage, which
2069 * is modified as needed based on various properties, and finally a "damage
2070 * type" (see below).
2072 * Note that this routine can handle "no damage" attacks (like teleport) by
2073 * taking a "zero" damage, and can even take "parameters" to attacks (like
2074 * confuse) by accepting a "damage", using it to calculate the effect, and
2075 * then setting the damage to zero. Note that the "damage" parameter is
2076 * divided by the radius, so monsters not at the "epicenter" will not take
2077 * as much damage (or whatever)...
2079 * Note that "polymorph" is dangerous, since a failure in "place_monster()"'
2080 * may result in a dereference of an invalid pointer. XXX XXX XXX
2082 * Various messages are produced, and damage is applied.
2084 * Just "casting" a substance (i.e. plasma) does not make you immune, you must
2085 * actually be "made" of that substance, or "breathe" big balls of it.
2087 * We assume that "Plasma" monsters, and "Plasma" breathers, are immune
2088 * to plasma.
2090 * We assume "Nether" is an evil, necromantic force, so it doesn't hurt undead,
2091 * and hurts evil less. If can breath nether, then it resists it as well.
2093 * Damage reductions use the following formulas:
2094 * Note that "dam = dam * 6 / (randint(6) + 6);"
2095 * gives avg damage of .655, ranging from .858 to .500
2096 * Note that "dam = dam * 5 / (randint(6) + 6);"
2097 * gives avg damage of .544, ranging from .714 to .417
2098 * Note that "dam = dam * 4 / (randint(6) + 6);"
2099 * gives avg damage of .444, ranging from .556 to .333
2100 * Note that "dam = dam * 3 / (randint(6) + 6);"
2101 * gives avg damage of .327, ranging from .427 to .250
2102 * Note that "dam = dam * 2 / (randint(6) + 6);"
2103 * gives something simple.
2105 * In this function, "result" messages are postponed until the end, where
2106 * the "note" string is appended to the monster name, if not NULL. So,
2107 * to make a spell have "no effect" just set "note" to NULL. You should
2108 * also set "notice" to FALSE, or the player will learn what the spell does.
2110 * We attempt to return "TRUE" if the player saw anything "useful" happen.
2112 static bool project_m(int who, int r, int y, int x, int dam, int typ)
2114 int tmp;
2116 monster_type *m_ptr;
2117 monster_race *r_ptr;
2118 monster_lore *l_ptr;
2120 cptr name;
2122 /* Is the monster "seen"? */
2123 bool seen = FALSE;
2125 /* Were the effects "obvious" (if seen)? */
2126 bool obvious = FALSE;
2128 /* Were the effects "irrelevant"? */
2129 bool skipped = FALSE;
2132 /* Polymorph setting (true or false) */
2133 int do_poly = 0;
2135 /* Teleport setting (max distance) */
2136 int do_dist = 0;
2138 /* Confusion setting (amount to confuse) */
2139 int do_conf = 0;
2141 /* Stunning setting (amount to stun) */
2142 int do_stun = 0;
2144 /* Sleep amount (amount to sleep) */
2145 int do_sleep = 0;
2147 /* Fear amount (amount to fear) */
2148 int do_fear = 0;
2151 /* Hold the monster name */
2152 char m_name[80];
2154 /* Assume no note */
2155 cptr note = NULL;
2157 /* Assume a default death */
2158 cptr note_dies = " dies.";
2161 /* Walls protect monsters */
2162 if (!cave_floor_bold(y,x)) return (FALSE);
2165 /* No monster here */
2166 if (!(cave_m_idx[y][x] > 0)) return (FALSE);
2168 /* Never affect projector */
2169 if (cave_m_idx[y][x] == who) return (FALSE);
2172 /* Obtain monster info */
2173 m_ptr = &mon_list[cave_m_idx[y][x]];
2174 r_ptr = &r_info[m_ptr->r_idx];
2175 l_ptr = &l_list[m_ptr->r_idx];
2176 name = (r_name + r_ptr->name);
2177 if (m_ptr->ml) seen = TRUE;
2180 /* Reduce damage by distance */
2181 dam = (dam + r) / (r + 1);
2184 /* Get the monster name (BEFORE polymorphing) */
2185 monster_desc(m_name, sizeof(m_name), m_ptr, 0);
2189 /* Some monsters get "destroyed" */
2190 if ((r_ptr->flags3 & (RF3_DEMON)) ||
2191 (r_ptr->flags3 & (RF3_UNDEAD)) ||
2192 (r_ptr->flags2 & (RF2_STUPID)) ||
2193 (strchr("Evg", r_ptr->d_char)))
2195 /* Special note at death */
2196 note_dies = " is destroyed.";
2200 /* Analyze the damage type */
2201 switch (typ)
2203 /* Magic Missile -- pure damage */
2204 case GF_MISSILE:
2206 if (seen) obvious = TRUE;
2207 break;
2210 /* Acid */
2211 case GF_ACID:
2213 if (seen) obvious = TRUE;
2214 if (r_ptr->flags3 & (RF3_IM_ACID))
2216 note = " resists a lot.";
2217 dam /= 9;
2218 if (seen) l_ptr->flags3 |= (RF3_IM_ACID);
2220 break;
2223 /* Electricity */
2224 case GF_ELEC:
2226 if (seen) obvious = TRUE;
2227 if (r_ptr->flags3 & (RF3_IM_ELEC))
2229 note = " resists a lot.";
2230 dam /= 9;
2231 if (seen) l_ptr->flags3 |= (RF3_IM_ELEC);
2233 break;
2236 /* Fire damage */
2237 case GF_FIRE:
2239 if (seen) obvious = TRUE;
2240 if (r_ptr->flags3 & (RF3_IM_FIRE))
2242 note = " resists a lot.";
2243 dam /= 9;
2244 if (seen) l_ptr->flags3 |= (RF3_IM_FIRE);
2246 break;
2249 /* Cold */
2250 case GF_COLD:
2252 if (seen) obvious = TRUE;
2253 if (r_ptr->flags3 & (RF3_IM_COLD))
2255 note = " resists a lot.";
2256 dam /= 9;
2257 if (seen) l_ptr->flags3 |= (RF3_IM_COLD);
2259 break;
2262 /* Poison */
2263 case GF_POIS:
2265 if (seen) obvious = TRUE;
2266 if (r_ptr->flags3 & (RF3_IM_POIS))
2268 note = " resists a lot.";
2269 dam /= 9;
2270 if (seen) l_ptr->flags3 |= (RF3_IM_POIS);
2272 break;
2275 /* Holy Orb -- hurts Evil */
2276 case GF_HOLY_ORB:
2278 if (seen) obvious = TRUE;
2279 if (r_ptr->flags3 & (RF3_EVIL))
2281 dam *= 2;
2282 note = " is hit hard.";
2283 if (seen) l_ptr->flags3 |= (RF3_EVIL);
2285 break;
2288 /* Arrow -- no defense XXX */
2289 case GF_ARROW:
2291 if (seen) obvious = TRUE;
2292 break;
2295 /* Plasma */
2296 case GF_PLASMA:
2298 if (seen) obvious = TRUE;
2299 if (r_ptr->flags3 & RF3_RES_PLAS)
2301 note = " resists.";
2302 dam *= 3; dam /= (randint(6)+6);
2303 if (seen) l_ptr->flags3 |= RF3_RES_PLAS;
2305 break;
2308 /* Nether -- see above */
2309 case GF_NETHER:
2311 if (seen) obvious = TRUE;
2312 if (r_ptr->flags3 & (RF3_UNDEAD))
2314 note = " is immune.";
2315 dam = 0;
2316 if (seen) l_ptr->flags3 |= (RF3_UNDEAD);
2318 else if (r_ptr->flags4 & (RF4_BR_NETH))
2320 note = " resists.";
2321 dam *= 3; dam /= (randint(6)+6);
2323 else if (r_ptr->flags3 & (RF3_EVIL))
2325 dam /= 2;
2326 note = " resists somewhat.";
2327 if (seen) l_ptr->flags3 |= (RF3_EVIL);
2329 break;
2332 /* Water damage */
2333 case GF_WATER:
2335 if (seen) obvious = TRUE;
2336 if (r_ptr->flags3 & RF3_IM_WATER)
2338 note = " is immune.";
2339 dam = 0;
2340 if (seen) l_ptr->flags3 |= RF3_IM_WATER;
2342 break;
2345 /* Chaos -- Chaos breathers resist */
2346 case GF_CHAOS:
2348 if (seen) obvious = TRUE;
2349 do_poly = TRUE;
2350 do_conf = (5 + randint(11) + r) / (r + 1);
2351 if (r_ptr->flags4 & (RF4_BR_CHAO))
2353 note = " resists.";
2354 dam *= 3; dam /= (randint(6)+6);
2355 do_poly = FALSE;
2357 break;
2360 /* Shards -- Shard breathers resist */
2361 case GF_SHARD:
2363 if (seen) obvious = TRUE;
2364 if (r_ptr->flags4 & (RF4_BR_SHAR))
2366 note = " resists.";
2367 dam *= 3; dam /= (randint(6)+6);
2369 break;
2372 /* Sound -- Sound breathers resist */
2373 case GF_SOUND:
2375 if (seen) obvious = TRUE;
2376 do_stun = (10 + randint(15) + r) / (r + 1);
2377 if (r_ptr->flags4 & (RF4_BR_SOUN))
2379 note = " resists.";
2380 dam *= 2; dam /= (randint(6)+6);
2382 break;
2385 /* Confusion */
2386 case GF_CONFUSION:
2388 if (seen) obvious = TRUE;
2389 do_conf = (10 + randint(15) + r) / (r + 1);
2390 if (r_ptr->flags4 & (RF4_BR_CONF))
2392 note = " resists.";
2393 dam *= 2; dam /= (randint(6)+6);
2395 else if (r_ptr->flags3 & (RF3_NO_CONF))
2397 note = " resists somewhat.";
2398 dam /= 2;
2400 break;
2403 /* Disenchantment */
2404 case GF_DISENCHANT:
2406 if (seen) obvious = TRUE;
2407 if (r_ptr->flags3 & RF3_RES_DISE)
2409 note = " resists.";
2410 dam *= 3; dam /= (randint(6)+6);
2411 if (seen) l_ptr->flags3 |= RF3_RES_DISE;
2413 break;
2416 /* Nexus */
2417 case GF_NEXUS:
2419 if (seen) obvious = TRUE;
2420 if (r_ptr->flags3 & RF3_RES_NEXUS)
2422 note = " resists.";
2423 dam *= 3; dam /= (randint(6)+6);
2424 if (seen) l_ptr->flags3 |= RF3_RES_NEXUS;
2426 break;
2429 /* Force */
2430 case GF_FORCE:
2432 if (seen) obvious = TRUE;
2433 do_stun = (randint(15) + r) / (r + 1);
2434 if (r_ptr->flags4 & (RF4_BR_WALL))
2436 note = " resists.";
2437 dam *= 3; dam /= (randint(6)+6);
2439 break;
2442 /* Inertia -- breathers resist */
2443 case GF_INERTIA:
2445 if (seen) obvious = TRUE;
2446 if (r_ptr->flags4 & (RF4_BR_INER))
2448 note = " resists.";
2449 dam *= 3; dam /= (randint(6)+6);
2451 break;
2454 /* Time -- breathers resist */
2455 case GF_TIME:
2457 if (seen) obvious = TRUE;
2458 if (r_ptr->flags4 & (RF4_BR_TIME))
2460 note = " resists.";
2461 dam *= 3; dam /= (randint(6)+6);
2463 break;
2466 /* Gravity -- breathers resist */
2467 case GF_GRAVITY:
2469 if (seen) obvious = TRUE;
2471 /* Higher level monsters can resist the teleportation better */
2472 if (randint(127) > r_ptr->level)
2473 do_dist = 10;
2475 if (r_ptr->flags4 & (RF4_BR_GRAV))
2477 note = " resists.";
2478 dam *= 3; dam /= (randint(6)+6);
2479 do_dist = 0;
2481 break;
2484 /* Pure damage */
2485 case GF_MANA:
2487 if (seen) obvious = TRUE;
2488 break;
2491 /* Meteor -- powerful magic missile */
2492 case GF_METEOR:
2494 if (seen) obvious = TRUE;
2495 break;
2498 /* Ice -- Cold + Cuts + Stun */
2499 case GF_ICE:
2501 if (seen) obvious = TRUE;
2502 do_stun = (randint(15) + 1) / (r + 1);
2503 if (r_ptr->flags3 & (RF3_IM_COLD))
2505 note = " resists a lot.";
2506 dam /= 9;
2507 if (seen) l_ptr->flags3 |= (RF3_IM_COLD);
2509 break;
2513 /* Drain Life */
2514 case GF_OLD_DRAIN:
2516 if (seen) obvious = TRUE;
2517 if ((r_ptr->flags3 & (RF3_UNDEAD)) ||
2518 (r_ptr->flags3 & (RF3_DEMON)) ||
2519 (strchr("Egv", r_ptr->d_char)))
2521 if (r_ptr->flags3 & (RF3_UNDEAD))
2523 if (seen) l_ptr->flags3 |= (RF3_UNDEAD);
2525 if (r_ptr->flags3 & (RF3_DEMON))
2527 if (seen) l_ptr->flags3 |= (RF3_DEMON);
2530 note = " is unaffected!";
2531 obvious = FALSE;
2532 dam = 0;
2535 break;
2538 /* Polymorph monster (Use "dam" as "power") */
2539 case GF_OLD_POLY:
2541 if (seen) obvious = TRUE;
2543 /* Attempt to polymorph (see below) */
2544 do_poly = TRUE;
2546 /* Powerful monsters can resist */
2547 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
2548 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
2550 note = " is unaffected!";
2551 do_poly = FALSE;
2552 obvious = FALSE;
2555 /* No "real" damage */
2556 dam = 0;
2558 break;
2562 /* Clone monsters (Ignore "dam") */
2563 case GF_OLD_CLONE:
2565 if (seen) obvious = TRUE;
2567 /* Heal fully */
2568 m_ptr->hp = m_ptr->maxhp;
2570 /* Speed up */
2571 if (m_ptr->mspeed < 150) m_ptr->mspeed += 10;
2573 /* Attempt to clone. */
2574 if (multiply_monster(cave_m_idx[y][x]))
2576 note = " spawns!";
2579 /* No "real" damage */
2580 dam = 0;
2582 break;
2586 /* Heal Monster (use "dam" as amount of healing) */
2587 case GF_OLD_HEAL:
2589 if (seen) obvious = TRUE;
2591 /* Wake up */
2592 m_ptr->csleep = 0;
2594 /* Heal */
2595 m_ptr->hp += dam;
2597 /* No overflow */
2598 if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
2600 /* Redraw (later) if needed */
2601 if (p_ptr->health_who == cave_m_idx[y][x]) p_ptr->redraw |= (PR_HEALTH);
2603 /* Message */
2604 note = " looks healthier.";
2606 /* No "real" damage */
2607 dam = 0;
2608 break;
2612 /* Speed Monster (Ignore "dam") */
2613 case GF_OLD_SPEED:
2615 if (seen) obvious = TRUE;
2617 /* Speed up */
2618 if (m_ptr->mspeed < 150) m_ptr->mspeed += 10;
2619 note = " starts moving faster.";
2621 /* No "real" damage */
2622 dam = 0;
2623 break;
2627 /* Slow Monster (Use "dam" as "power") */
2628 case GF_OLD_SLOW:
2630 if (seen) obvious = TRUE;
2632 /* Powerful monsters can resist */
2633 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
2634 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
2636 note = " is unaffected!";
2637 obvious = FALSE;
2640 /* Normal monsters slow down */
2641 else
2643 if (m_ptr->mspeed > 60) m_ptr->mspeed -= 10;
2644 note = " starts moving slower.";
2647 /* No "real" damage */
2648 dam = 0;
2649 break;
2653 /* Sleep (Use "dam" as "power") */
2654 case GF_OLD_SLEEP:
2656 if (seen) obvious = TRUE;
2658 /* Attempt a saving throw */
2659 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
2660 (r_ptr->flags3 & (RF3_NO_SLEEP)) ||
2661 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
2663 /* Memorize a flag */
2664 if (r_ptr->flags3 & (RF3_NO_SLEEP))
2666 if (seen) l_ptr->flags3 |= (RF3_NO_SLEEP);
2669 /* No obvious effect */
2670 note = " is unaffected!";
2671 obvious = FALSE;
2673 else
2675 /* Go to sleep (much) later */
2676 note = " falls asleep!";
2677 do_sleep = 500;
2680 /* No "real" damage */
2681 dam = 0;
2682 break;
2686 /* Confusion (Use "dam" as "power") */
2687 case GF_OLD_CONF:
2689 if (seen) obvious = TRUE;
2691 /* Get confused later */
2692 do_conf = damroll(3, (dam / 2)) + 1;
2694 /* Attempt a saving throw */
2695 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
2696 (r_ptr->flags3 & (RF3_NO_CONF)) ||
2697 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
2699 /* Memorize a flag */
2700 if (r_ptr->flags3 & (RF3_NO_CONF))
2702 if (seen) l_ptr->flags3 |= (RF3_NO_CONF);
2705 /* Resist */
2706 do_conf = 0;
2708 /* No obvious effect */
2709 note = " is unaffected!";
2710 obvious = FALSE;
2713 /* No "real" damage */
2714 dam = 0;
2715 break;
2720 /* Lite, but only hurts susceptible creatures */
2721 case GF_LITE_WEAK:
2723 /* Hurt by light */
2724 if (r_ptr->flags3 & (RF3_HURT_LITE))
2726 /* Obvious effect */
2727 if (seen) obvious = TRUE;
2729 /* Memorize the effects */
2730 if (seen) l_ptr->flags3 |= (RF3_HURT_LITE);
2732 /* Special effect */
2733 note = " cringes from the light!";
2734 note_dies = " shrivels away in the light!";
2737 /* Normally no damage */
2738 else
2740 /* No damage */
2741 dam = 0;
2744 break;
2749 /* Lite -- opposite of Dark */
2750 case GF_LITE:
2752 if (seen) obvious = TRUE;
2753 if (r_ptr->flags4 & (RF4_BR_LITE))
2755 note = " resists.";
2756 dam *= 2; dam /= (randint(6)+6);
2758 else if (r_ptr->flags3 & (RF3_HURT_LITE))
2760 if (seen) l_ptr->flags3 |= (RF3_HURT_LITE);
2761 note = " cringes from the light!";
2762 note_dies = " shrivels away in the light!";
2763 dam *= 2;
2765 break;
2769 /* Dark -- opposite of Lite */
2770 case GF_DARK:
2772 if (seen) obvious = TRUE;
2773 if (r_ptr->flags4 & (RF4_BR_DARK))
2775 note = " resists.";
2776 dam *= 2; dam /= (randint(6)+6);
2778 break;
2782 /* Stone to Mud */
2783 case GF_KILL_WALL:
2785 /* Hurt by rock remover */
2786 if (r_ptr->flags3 & (RF3_HURT_ROCK))
2788 /* Notice effect */
2789 if (seen) obvious = TRUE;
2791 /* Memorize the effects */
2792 if (seen) l_ptr->flags3 |= (RF3_HURT_ROCK);
2794 /* Cute little message */
2795 note = " loses some skin!";
2796 note_dies = " dissolves!";
2799 /* Usually, ignore the effects */
2800 else
2802 /* No damage */
2803 dam = 0;
2806 break;
2810 /* Teleport undead (Use "dam" as "power") */
2811 case GF_AWAY_UNDEAD:
2813 /* Only affect undead */
2814 if (r_ptr->flags3 & (RF3_UNDEAD))
2816 if (seen) obvious = TRUE;
2817 if (seen) l_ptr->flags3 |= (RF3_UNDEAD);
2818 do_dist = dam;
2821 /* Others ignore */
2822 else
2824 /* Irrelevant */
2825 skipped = TRUE;
2828 /* No "real" damage */
2829 dam = 0;
2830 break;
2834 /* Teleport evil (Use "dam" as "power") */
2835 case GF_AWAY_EVIL:
2837 /* Only affect undead */
2838 if (r_ptr->flags3 & (RF3_EVIL))
2840 if (seen) obvious = TRUE;
2841 if (seen) l_ptr->flags3 |= (RF3_EVIL);
2842 do_dist = dam;
2845 /* Others ignore */
2846 else
2848 /* Irrelevant */
2849 skipped = TRUE;
2852 /* No "real" damage */
2853 dam = 0;
2854 break;
2858 /* Teleport monster (Use "dam" as "power") */
2859 case GF_AWAY_ALL:
2861 /* Obvious */
2862 if (seen) obvious = TRUE;
2864 /* Prepare to teleport */
2865 do_dist = dam;
2867 /* No "real" damage */
2868 dam = 0;
2869 break;
2873 /* Turn undead (Use "dam" as "power") */
2874 case GF_TURN_UNDEAD:
2876 /* Only affect undead */
2877 if (r_ptr->flags3 & (RF3_UNDEAD))
2879 /* Learn about type */
2880 if (seen) l_ptr->flags3 |= (RF3_UNDEAD);
2882 /* Obvious */
2883 if (seen) obvious = TRUE;
2885 /* Apply some fear */
2886 do_fear = damroll(3, (dam / 2)) + 1;
2888 /* Attempt a saving throw */
2889 if (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
2891 /* No obvious effect */
2892 note = " is unaffected!";
2893 obvious = FALSE;
2894 do_fear = 0;
2898 /* Others ignore */
2899 else
2901 /* Irrelevant */
2902 skipped = TRUE;
2905 /* No "real" damage */
2906 dam = 0;
2907 break;
2911 /* Turn evil (Use "dam" as "power") */
2912 case GF_TURN_EVIL:
2914 /* Only affect evil */
2915 if (r_ptr->flags3 & (RF3_EVIL))
2917 /* Learn about type */
2918 if (seen) l_ptr->flags3 |= (RF3_EVIL);
2920 /* Obvious */
2921 if (seen) obvious = TRUE;
2923 /* Apply some fear */
2924 do_fear = damroll(3, (dam / 2)) + 1;
2926 /* Attempt a saving throw */
2927 if (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10)
2929 /* No obvious effect */
2930 note = " is unaffected!";
2931 obvious = FALSE;
2932 do_fear = 0;
2936 /* Others ignore */
2937 else
2939 /* Irrelevant */
2940 skipped = TRUE;
2943 /* No "real" damage */
2944 dam = 0;
2945 break;
2949 /* Turn monster (Use "dam" as "power") */
2950 case GF_TURN_ALL:
2952 /* Obvious */
2953 if (seen) obvious = TRUE;
2955 /* Apply some fear */
2956 do_fear = damroll(3, (dam / 2)) + 1;
2958 /* Attempt a saving throw */
2959 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
2960 (r_ptr->flags3 & (RF3_NO_FEAR)) ||
2961 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
2963 /* No obvious effect */
2964 note = " is unaffected!";
2965 obvious = FALSE;
2966 do_fear = 0;
2969 /* No "real" damage */
2970 dam = 0;
2971 break;
2975 /* Dispel undead */
2976 case GF_DISP_UNDEAD:
2978 /* Only affect undead */
2979 if (r_ptr->flags3 & (RF3_UNDEAD))
2981 /* Learn about type */
2982 if (seen) l_ptr->flags3 |= (RF3_UNDEAD);
2984 /* Obvious */
2985 if (seen) obvious = TRUE;
2987 /* Message */
2988 note = " shudders.";
2989 note_dies = " dissolves!";
2992 /* Others ignore */
2993 else
2995 /* Irrelevant */
2996 skipped = TRUE;
2998 /* No damage */
2999 dam = 0;
3002 break;
3006 /* Dispel evil */
3007 case GF_DISP_EVIL:
3009 /* Only affect evil */
3010 if (r_ptr->flags3 & (RF3_EVIL))
3012 /* Learn about type */
3013 if (seen) l_ptr->flags3 |= (RF3_EVIL);
3015 /* Obvious */
3016 if (seen) obvious = TRUE;
3018 /* Message */
3019 note = " shudders.";
3020 note_dies = " dissolves!";
3023 /* Others ignore */
3024 else
3026 /* Irrelevant */
3027 skipped = TRUE;
3029 /* No damage */
3030 dam = 0;
3033 break;
3037 /* Dispel monster */
3038 case GF_DISP_ALL:
3040 /* Obvious */
3041 if (seen) obvious = TRUE;
3043 /* Message */
3044 note = " shudders.";
3045 note_dies = " dissolves!";
3047 break;
3051 /* Default */
3052 default:
3054 /* Irrelevant */
3055 skipped = TRUE;
3057 /* No damage */
3058 dam = 0;
3060 break;
3065 /* Absolutely no effect */
3066 if (skipped) return (FALSE);
3069 /* "Unique" monsters cannot be polymorphed */
3070 if (r_ptr->flags1 & (RF1_UNIQUE)) do_poly = FALSE;
3073 /* "Unique" monsters can only be "killed" by the player */
3074 if (r_ptr->flags1 & (RF1_UNIQUE))
3076 /* Uniques may only be killed by the player */
3077 if ((who > 0) && (dam > m_ptr->hp)) dam = m_ptr->hp;
3081 /* Check for death */
3082 if (dam > m_ptr->hp)
3084 /* Extract method of death */
3085 note = note_dies;
3088 /* Mega-Hack -- Handle "polymorph" -- monsters get a saving throw */
3089 else if (do_poly && (randint(90) > r_ptr->level))
3091 /* Default -- assume no polymorph */
3092 note = " is unaffected!";
3094 /* Pick a "new" monster race */
3095 tmp = poly_r_idx(m_ptr->r_idx);
3097 /* Handle polymorph */
3098 if (tmp != m_ptr->r_idx)
3100 /* Obvious */
3101 if (seen) obvious = TRUE;
3103 /* Monster polymorphs */
3104 note = " changes!";
3106 /* Turn off the damage */
3107 dam = 0;
3109 /* "Kill" the "old" monster */
3110 delete_monster_idx(cave_m_idx[y][x]);
3112 /* Create a new monster (no groups) */
3113 (void)place_monster_aux(y, x, tmp, FALSE, FALSE);
3115 /* Hack -- Assume success XXX XXX XXX */
3117 /* Hack -- Get new monster */
3118 m_ptr = &mon_list[cave_m_idx[y][x]];
3120 /* Hack -- Get new race */
3121 r_ptr = &r_info[m_ptr->r_idx];
3125 /* Handle "teleport" */
3126 else if (do_dist)
3128 /* Obvious */
3129 if (seen) obvious = TRUE;
3131 /* Message */
3132 note = " disappears!";
3134 /* Teleport */
3135 teleport_away(cave_m_idx[y][x], do_dist);
3137 /* Hack -- get new location */
3138 y = m_ptr->fy;
3139 x = m_ptr->fx;
3142 /* Sound and Impact breathers never stun */
3143 else if (do_stun &&
3144 !(r_ptr->flags4 & (RF4_BR_SOUN)) &&
3145 !(r_ptr->flags4 & (RF4_BR_WALL)))
3147 /* Obvious */
3148 if (seen) obvious = TRUE;
3150 /* Get confused */
3151 if (m_ptr->stunned)
3153 note = " is more dazed.";
3154 tmp = m_ptr->stunned + (do_stun / 2);
3156 else
3158 note = " is dazed.";
3159 tmp = do_stun;
3162 /* Apply stun */
3163 m_ptr->stunned = (tmp < 200) ? tmp : 200;
3166 /* Confusion and Chaos breathers (and sleepers) never confuse */
3167 else if (do_conf &&
3168 !(r_ptr->flags3 & (RF3_NO_CONF)) &&
3169 !(r_ptr->flags4 & (RF4_BR_CONF)) &&
3170 !(r_ptr->flags4 & (RF4_BR_CHAO)))
3172 /* Obvious */
3173 if (seen) obvious = TRUE;
3175 /* Already partially confused */
3176 if (m_ptr->confused)
3178 note = " looks more confused.";
3179 tmp = m_ptr->confused + (do_conf / 2);
3182 /* Was not confused */
3183 else
3185 note = " looks confused.";
3186 tmp = do_conf;
3189 /* Apply confusion */
3190 m_ptr->confused = (tmp < 200) ? tmp : 200;
3194 /* Fear */
3195 if (do_fear)
3197 /* Increase fear */
3198 tmp = m_ptr->monfear + do_fear;
3200 /* Set fear */
3201 m_ptr->monfear = (tmp < 200) ? tmp : 200;
3205 /* If another monster did the damage, hurt the monster by hand */
3206 if (who > 0)
3208 /* Redraw (later) if needed */
3209 if (p_ptr->health_who == cave_m_idx[y][x]) p_ptr->redraw |= (PR_HEALTH);
3211 /* Wake the monster up */
3212 m_ptr->csleep = 0;
3214 /* Hurt the monster */
3215 m_ptr->hp -= dam;
3217 /* Dead monster */
3218 if (m_ptr->hp < 0)
3220 /* Generate treasure, etc */
3221 monster_death(cave_m_idx[y][x]);
3223 /* Delete the monster */
3224 delete_monster_idx(cave_m_idx[y][x]);
3226 /* Give detailed messages if destroyed */
3227 if (note) msg_format("%^s%s", m_name, note);
3230 /* Damaged monster */
3231 else
3233 /* Give detailed messages if visible or destroyed */
3234 if (note && seen) msg_format("%^s%s", m_name, note);
3236 /* Hack -- Pain message */
3237 else if (dam > 0) message_pain(cave_m_idx[y][x], dam);
3239 /* Hack -- handle sleep */
3240 if (do_sleep) m_ptr->csleep = do_sleep;
3244 /* If the player did it, give him experience, check fear */
3245 else
3247 bool fear = FALSE;
3249 /* Hurt the monster, check for fear and death */
3250 if (mon_take_hit(cave_m_idx[y][x], dam, &fear, note_dies))
3252 /* Dead monster */
3255 /* Damaged monster */
3256 else
3258 /* Give detailed messages if visible or destroyed */
3259 if (note && seen) msg_format("%^s%s", m_name, note);
3261 /* Hack -- Pain message */
3262 else if (dam > 0) message_pain(cave_m_idx[y][x], dam);
3264 /* Take note */
3265 if ((fear || do_fear) && (m_ptr->ml))
3267 /* Message */
3268 message_format(MSG_FLEE, m_ptr->r_idx,
3269 "%^s flees in terror!", m_name);
3272 /* Hack -- handle sleep */
3273 if (do_sleep) m_ptr->csleep = do_sleep;
3278 /* Verify this code XXX XXX XXX */
3280 /* Update the monster */
3281 update_mon(cave_m_idx[y][x], FALSE);
3283 /* Redraw the monster grid */
3284 lite_spot(y, x);
3287 /* Update monster recall window */
3288 if (p_ptr->monster_race_idx == m_ptr->r_idx)
3290 /* Window stuff */
3291 p_ptr->window |= (PW_MONSTER);
3295 /* Track it */
3296 project_m_n++;
3297 project_m_x = x;
3298 project_m_y = y;
3301 /* Return "Anything seen?" */
3302 return (obvious);
3311 * Helper function for "project()" below.
3313 * Handle a beam/bolt/ball causing damage to the player.
3315 * This routine takes a "source monster" (by index), a "distance", a default
3316 * "damage", and a "damage type". See "project_m()" above.
3318 * If "rad" is non-zero, then the blast was centered elsewhere, and the damage
3319 * is reduced (see "project_m()" above). This can happen if a monster breathes
3320 * at the player and hits a wall instead.
3322 * We return "TRUE" if any "obvious" effects were observed.
3324 * Actually, for historical reasons, we just assume that the effects were
3325 * obvious. XXX XXX XXX
3327 static bool project_p(int who, int r, int y, int x, int dam, int typ)
3329 int k = 0;
3331 /* Hack -- assume obvious */
3332 bool obvious = TRUE;
3334 /* Player blind-ness */
3335 bool blind = (p_ptr->timed[TMD_BLIND] ? TRUE : FALSE);
3337 /* Source monster */
3338 monster_type *m_ptr;
3340 /* Monster name (for attacks) */
3341 char m_name[80];
3343 /* Monster name (for damage) */
3344 char killer[80];
3346 /* Hack -- messages */
3347 cptr act = NULL;
3350 /* No player here */
3351 if (!(cave_m_idx[y][x] < 0)) return (FALSE);
3353 /* Never affect projector */
3354 if (cave_m_idx[y][x] == who) return (FALSE);
3357 /* Limit maximum damage XXX XXX XXX */
3358 if (dam > 1600) dam = 1600;
3360 /* Reduce damage by distance */
3361 dam = (dam + r) / (r + 1);
3364 /* Get the source monster */
3365 m_ptr = &mon_list[who];
3367 /* Get the monster name */
3368 monster_desc(m_name, sizeof(m_name), m_ptr, 0);
3370 /* Get the monster's real name */
3371 monster_desc(killer, sizeof(killer), m_ptr, 0x88);
3374 /* Analyze the damage */
3375 switch (typ)
3377 /* Standard damage -- hurts inventory too */
3378 case GF_ACID:
3380 if (blind) msg_print("You are hit by acid!");
3381 acid_dam(dam, killer);
3382 break;
3385 /* Standard damage -- hurts inventory too */
3386 case GF_FIRE:
3388 if (blind) msg_print("You are hit by fire!");
3389 fire_dam(dam, killer);
3390 break;
3393 /* Standard damage -- hurts inventory too */
3394 case GF_COLD:
3396 if (blind) msg_print("You are hit by cold!");
3397 cold_dam(dam, killer);
3398 break;
3401 /* Standard damage -- hurts inventory too */
3402 case GF_ELEC:
3404 if (blind) msg_print("You are hit by lightning!");
3405 elec_dam(dam, killer);
3406 break;
3409 /* Standard damage -- also poisons player */
3410 case GF_POIS:
3412 if (blind) msg_print("You are hit by poison!");
3413 if (p_ptr->resist_pois) dam = (dam + 2) / 3;
3414 if (p_ptr->timed[TMD_OPP_POIS]) dam = (dam + 2) / 3;
3415 take_hit(dam, killer);
3416 if (!(p_ptr->resist_pois || p_ptr->timed[TMD_OPP_POIS]))
3418 (void)inc_timed(TMD_POISONED, rand_int(dam) + 10);
3420 break;
3423 /* Standard damage */
3424 case GF_MISSILE:
3426 if (blind) msg_print("You are hit by something!");
3427 take_hit(dam, killer);
3428 break;
3431 /* Holy Orb -- Player only takes partial damage */
3432 case GF_HOLY_ORB:
3434 if (blind) msg_print("You are hit by something!");
3435 dam /= 2;
3436 take_hit(dam, killer);
3437 break;
3440 /* Arrow -- no dodging XXX */
3441 case GF_ARROW:
3443 if (blind) msg_print("You are hit by something sharp!");
3444 take_hit(dam, killer);
3445 break;
3448 /* Plasma -- No resist XXX */
3449 case GF_PLASMA:
3451 if (blind) msg_print("You are hit by something!");
3452 take_hit(dam, killer);
3453 if (!p_ptr->resist_sound)
3455 int k = (randint((dam > 40) ? 35 : (dam * 3 / 4 + 5)));
3456 (void)inc_timed(TMD_STUN, k);
3458 break;
3461 /* Nether -- drain experience */
3462 case GF_NETHER:
3464 if (blind) msg_print("You are hit by something strange!");
3465 if (p_ptr->resist_nethr)
3467 dam *= 6; dam /= (randint(6) + 6);
3469 else
3471 if (p_ptr->hold_life && (rand_int(100) < 75))
3473 msg_print("You keep hold of your life force!");
3475 else
3477 s32b d = 200 + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
3479 if (p_ptr->hold_life)
3481 msg_print("You feel your life slipping away!");
3482 lose_exp(d / 10);
3484 else
3486 msg_print("You feel your life draining away!");
3487 lose_exp(d);
3491 take_hit(dam, killer);
3492 break;
3495 /* Water -- stun/confuse */
3496 case GF_WATER:
3498 if (blind) msg_print("You are hit by something!");
3499 if (!p_ptr->resist_sound)
3501 (void)inc_timed(TMD_STUN, randint(40));
3503 if (!p_ptr->resist_confu)
3505 (void)inc_timed(TMD_CONFUSED, randint(5) + 5);
3507 take_hit(dam, killer);
3508 break;
3511 /* Chaos -- many effects */
3512 case GF_CHAOS:
3514 if (blind) msg_print("You are hit by something strange!");
3515 if (p_ptr->resist_chaos)
3517 dam *= 6; dam /= (randint(6) + 6);
3519 if (!p_ptr->resist_confu && !p_ptr->resist_chaos)
3521 (void)inc_timed(TMD_CONFUSED, rand_int(20) + 10);
3523 if (!p_ptr->resist_chaos)
3525 (void)inc_timed(TMD_IMAGE, randint(10));
3527 if (!p_ptr->resist_nethr && !p_ptr->resist_chaos)
3529 if (p_ptr->hold_life && (rand_int(100) < 75))
3531 msg_print("You keep hold of your life force!");
3533 else
3535 s32b d = 5000 + (p_ptr->exp / 100) * MON_DRAIN_LIFE;
3537 if (p_ptr->hold_life)
3539 msg_print("You feel your life slipping away!");
3540 lose_exp(d / 10);
3542 else
3544 msg_print("You feel your life draining away!");
3545 lose_exp(d);
3549 take_hit(dam, killer);
3550 break;
3553 /* Shards -- mostly cutting */
3554 case GF_SHARD:
3556 if (blind) msg_print("You are hit by something sharp!");
3557 if (p_ptr->resist_shard)
3559 dam *= 6; dam /= (randint(6) + 6);
3561 else
3563 (void)inc_timed(TMD_CUT, dam);
3565 take_hit(dam, killer);
3566 break;
3569 /* Sound -- mostly stunning */
3570 case GF_SOUND:
3572 if (blind) msg_print("You are hit by something!");
3573 if (p_ptr->resist_sound)
3575 dam *= 5; dam /= (randint(6) + 6);
3577 else
3579 int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
3580 (void)inc_timed(TMD_STUN, k);
3582 take_hit(dam, killer);
3583 break;
3586 /* Pure confusion */
3587 case GF_CONFUSION:
3589 if (blind) msg_print("You are hit by something!");
3590 if (p_ptr->resist_confu)
3592 dam *= 5; dam /= (randint(6) + 6);
3594 if (!p_ptr->resist_confu)
3596 (void)inc_timed(TMD_CONFUSED, randint(20) + 10);
3598 take_hit(dam, killer);
3599 break;
3602 /* Disenchantment -- see above */
3603 case GF_DISENCHANT:
3605 if (blind) msg_print("You are hit by something strange!");
3606 if (p_ptr->resist_disen)
3608 dam *= 6; dam /= (randint(6) + 6);
3610 else
3612 (void)apply_disenchant(0);
3614 take_hit(dam, killer);
3615 break;
3618 /* Nexus -- see above */
3619 case GF_NEXUS:
3621 if (blind) msg_print("You are hit by something strange!");
3622 if (p_ptr->resist_nexus)
3624 dam *= 6; dam /= (randint(6) + 6);
3626 else
3628 apply_nexus(m_ptr);
3630 take_hit(dam, killer);
3631 break;
3634 /* Force -- mostly stun */
3635 case GF_FORCE:
3637 if (blind) msg_print("You are hit by something!");
3638 if (!p_ptr->resist_sound)
3640 (void)inc_timed(TMD_STUN, randint(20));
3642 take_hit(dam, killer);
3643 break;
3646 /* Inertia -- slowness */
3647 case GF_INERTIA:
3649 if (blind) msg_print("You are hit by something strange!");
3650 (void)inc_timed(TMD_SLOW, rand_int(4) + 4);
3651 take_hit(dam, killer);
3652 break;
3655 /* Lite -- blinding */
3656 case GF_LITE:
3658 if (blind) msg_print("You are hit by something!");
3659 if (p_ptr->resist_lite)
3661 dam *= 4; dam /= (randint(6) + 6);
3663 else if (!blind && !p_ptr->resist_blind)
3665 (void)inc_timed(TMD_BLIND, randint(5) + 2);
3667 take_hit(dam, killer);
3668 break;
3671 /* Dark -- blinding */
3672 case GF_DARK:
3674 if (blind) msg_print("You are hit by something!");
3675 if (p_ptr->resist_dark)
3677 dam *= 4; dam /= (randint(6) + 6);
3679 else if (!blind && !p_ptr->resist_blind)
3681 (void)inc_timed(TMD_BLIND, randint(5) + 2);
3683 take_hit(dam, killer);
3684 break;
3687 /* Time -- bolt fewer effects XXX */
3688 case GF_TIME:
3690 if (blind) msg_print("You are hit by something strange!");
3692 switch (randint(10))
3694 case 1: case 2: case 3: case 4: case 5:
3696 msg_print("You feel life has clocked back.");
3697 lose_exp(100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
3698 break;
3701 case 6: case 7: case 8: case 9:
3703 switch (randint(6))
3705 case 1: k = A_STR; act = "strong"; break;
3706 case 2: k = A_INT; act = "bright"; break;
3707 case 3: k = A_WIS; act = "wise"; break;
3708 case 4: k = A_DEX; act = "agile"; break;
3709 case 5: k = A_CON; act = "hale"; break;
3710 case 6: k = A_CHR; act = "beautiful"; break;
3713 msg_format("You're not as %s as you used to be...", act);
3715 p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
3716 if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
3717 p_ptr->update |= (PU_BONUS);
3718 break;
3721 case 10:
3723 msg_print("You're not as powerful as you used to be...");
3725 for (k = 0; k < A_MAX; k++)
3727 p_ptr->stat_cur[k] = (p_ptr->stat_cur[k] * 3) / 4;
3728 if (p_ptr->stat_cur[k] < 3) p_ptr->stat_cur[k] = 3;
3730 p_ptr->update |= (PU_BONUS);
3731 break;
3734 take_hit(dam, killer);
3735 break;
3738 /* Gravity -- stun plus slowness plus teleport */
3739 case GF_GRAVITY:
3741 if (blind) msg_print("You are hit by something strange!");
3742 msg_print("Gravity warps around you.");
3744 /* Higher level players can resist the teleportation better */
3745 if (randint(127) > p_ptr->lev)
3746 teleport_player(5);
3748 (void)inc_timed(TMD_SLOW, rand_int(4) + 4);
3749 if (!p_ptr->resist_sound)
3751 int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
3752 (void)inc_timed(TMD_STUN, k);
3754 take_hit(dam, killer);
3755 break;
3758 /* Pure damage */
3759 case GF_MANA:
3761 if (blind) msg_print("You are hit by something!");
3762 take_hit(dam, killer);
3763 break;
3766 /* Pure damage */
3767 case GF_METEOR:
3769 if (blind) msg_print("You are hit by something!");
3770 take_hit(dam, killer);
3771 break;
3774 /* Ice -- cold plus stun plus cuts */
3775 case GF_ICE:
3777 if (blind) msg_print("You are hit by something sharp!");
3778 cold_dam(dam, killer);
3779 if (!p_ptr->resist_shard)
3781 (void)inc_timed(TMD_CUT, damroll(5, 8));
3783 if (!p_ptr->resist_sound)
3785 (void)inc_timed(TMD_STUN, randint(15));
3787 break;
3791 /* Default */
3792 default:
3794 /* No damage */
3795 dam = 0;
3797 break;
3802 /* Disturb */
3803 disturb(1, 0);
3806 /* Return "Anything seen?" */
3807 return (obvious);
3815 * Generic "beam"/"bolt"/"ball" projection routine.
3817 * Input:
3818 * who: Index of "source" monster (negative for "player")
3819 * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
3820 * y,x: Target location (or location to travel "towards")
3821 * dam: Base damage roll to apply to affected monsters (or player)
3822 * typ: Type of damage to apply to monsters (and objects)
3823 * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
3825 * Return:
3826 * TRUE if any "effects" of the projection were observed, else FALSE
3828 * Allows a monster (or player) to project a beam/bolt/ball of a given kind
3829 * towards a given location (optionally passing over the heads of interposing
3830 * monsters), and have it do a given amount of damage to the monsters (and
3831 * optionally objects) within the given radius of the final location.
3833 * A "bolt" travels from source to target and affects only the target grid.
3834 * A "beam" travels from source to target, affecting all grids passed through.
3835 * A "ball" travels from source to the target, exploding at the target, and
3836 * affecting everything within the given radius of the target location.
3838 * Traditionally, a "bolt" does not affect anything on the ground, and does
3839 * not pass over the heads of interposing monsters, much like a traditional
3840 * missile, and will "stop" abruptly at the "target" even if no monster is
3841 * positioned there, while a "ball", on the other hand, passes over the heads
3842 * of monsters between the source and target, and affects everything except
3843 * the source monster which lies within the final radius, while a "beam"
3844 * affects every monster between the source and target, except for the casting
3845 * monster (or player), and rarely affects things on the ground.
3847 * Two special flags allow us to use this function in special ways, the
3848 * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
3849 * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
3850 * actually projecting from the source monster (or player).
3852 * The player will only get "experience" for monsters killed by himself
3853 * Unique monsters can only be destroyed by attacks from the player
3855 * Only 256 grids can be affected per projection, limiting the effective
3856 * "radius" of standard ball attacks to nine units (diameter nineteen).
3858 * One can project in a given "direction" by combining PROJECT_THRU with small
3859 * offsets to the initial location (see "line_spell()"), or by calculating
3860 * "virtual targets" far away from the player.
3862 * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
3863 * continuing until it actually hits somethings (useful for "stone to mud").
3865 * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
3867 * Balls must explode BEFORE hitting walls, or they would affect monsters
3868 * on both sides of a wall. Some bug reports indicate that this is still
3869 * happening in 2.7.8 for Windows, though it appears to be impossible.
3871 * We "pre-calculate" the blast area only in part for efficiency.
3872 * More importantly, this lets us do "explosions" from the "inside" out.
3873 * This results in a more logical distribution of "blast" treasure.
3874 * It also produces a better (in my opinion) animation of the explosion.
3875 * It could be (but is not) used to have the treasure dropped by monsters
3876 * in the middle of the explosion fall "outwards", and then be damaged by
3877 * the blast as it spreads outwards towards the treasure drop location.
3879 * Walls and doors are included in the blast area, so that they can be
3880 * "burned" or "melted" in later versions.
3882 * This algorithm is intended to maximize simplicity, not necessarily
3883 * efficiency, since this function is not a bottleneck in the code.
3885 * We apply the blast effect from ground zero outwards, in several passes,
3886 * first affecting features, then objects, then monsters, then the player.
3887 * This allows walls to be removed before checking the object or monster
3888 * in the wall, and protects objects which are dropped by monsters killed
3889 * in the blast, and allows the player to see all affects before he is
3890 * killed or teleported away. The semantics of this method are open to
3891 * various interpretations, but they seem to work well in practice.
3893 * We process the blast area from ground-zero outwards to allow for better
3894 * distribution of treasure dropped by monsters, and because it provides a
3895 * pleasing visual effect at low cost.
3897 * Note that the damage done by "ball" explosions decreases with distance.
3898 * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
3900 * Notice the "napalm" effect of "beam" weapons. First they "project" to
3901 * the target, and then the damage "flows" along this beam of destruction.
3902 * The damage at every grid is the same as at the "center" of a "ball"
3903 * explosion, since the "beam" grids are treated as if they ARE at the
3904 * center of a "ball" explosion.
3906 * Currently, specifying "beam" plus "ball" means that locations which are
3907 * covered by the initial "beam", and also covered by the final "ball", except
3908 * for the final grid (the epicenter of the ball), will be "hit twice", once
3909 * by the initial beam, and once by the exploding ball. For the grid right
3910 * next to the epicenter, this results in 150% damage being done. The center
3911 * does not have this problem, for the same reason the final grid in a "beam"
3912 * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
3913 * grids which are covered by the "ball" will NOT work, as then they will
3914 * receive LESS damage than they should. Do not combine "beam" with "ball".
3916 * The array "gy[],gx[]" with current size "grids" is used to hold the
3917 * collected locations of all grids in the "blast area" plus "beam path".
3919 * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
3920 * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
3921 * first blast grid (see above) with radius "N" from the blast center. Note
3922 * that only the first gm[1] grids in the blast area thus take full damage.
3923 * Also, note that gm[rad+1] is always equal to "grids", which is the total
3924 * number of blast grids.
3926 * Note that once the projection is complete, (y2,x2) holds the final location
3927 * of bolts/beams, and the "epicenter" of balls.
3929 * Note also that "rad" specifies the "inclusive" radius of projection blast,
3930 * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
3931 * implementation of the "distance" function. Also, a bolt can be properly
3932 * viewed as a "ball" with a "rad" of "zero".
3934 * Note that if no "target" is reached before the beam/bolt/ball travels the
3935 * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
3936 * may be relevant even for bolts, since they have a "1x1" mini-blast.
3938 * Note that for consistency, we "pretend" that the bolt actually takes "time"
3939 * to move from point A to point B, even if the player cannot see part of the
3940 * projection path. Note that in general, the player will *always* see part
3941 * of the path, since it either starts at the player or ends on the player.
3943 * Hack -- we assume that every "projection" is "self-illuminating".
3945 * Hack -- when only a single monster is affected, we automatically track
3946 * (and recall) that monster, unless "PROJECT_JUMP" is used.
3948 * Note that all projections now "explode" at their final destination, even
3949 * if they were being projected at a more distant destination. This means
3950 * that "ball" spells will *always* explode.
3952 * Note that we must call "handle_stuff()" after affecting terrain features
3953 * in the blast radius, in case the "illumination" of the grid was changed,
3954 * and "update_view()" and "update_monsters()" need to be called.
3956 bool project(int who, int rad, int y, int x, int dam, int typ, int flg)
3958 int py = p_ptr->py;
3959 int px = p_ptr->px;
3961 int i, t, dist;
3963 int y1, x1;
3964 int y2, x2;
3966 int msec = op_ptr->delay_factor * op_ptr->delay_factor;
3968 /* Assume the player sees nothing */
3969 bool notice = FALSE;
3971 /* Assume the player has seen nothing */
3972 bool visual = FALSE;
3974 /* Assume the player has seen no blast grids */
3975 bool drawn = FALSE;
3977 /* Is the player blind? */
3978 bool blind = (p_ptr->timed[TMD_BLIND] ? TRUE : FALSE);
3980 /* Number of grids in the "path" */
3981 int path_n = 0;
3983 /* Actual grids in the "path" */
3984 u16b path_g[512];
3986 /* Number of grids in the "blast area" (including the "beam" path) */
3987 int grids = 0;
3989 /* Coordinates of the affected grids */
3990 byte gx[256], gy[256];
3992 /* Encoded "radius" info (see above) */
3993 byte gm[16];
3996 /* Hack -- Jump to target */
3997 if (flg & (PROJECT_JUMP))
3999 x1 = x;
4000 y1 = y;
4002 /* Clear the flag */
4003 flg &= ~(PROJECT_JUMP);
4006 /* Start at player */
4007 else if (who < 0)
4009 x1 = px;
4010 y1 = py;
4013 /* Start at monster */
4014 else if (who > 0)
4016 x1 = mon_list[who].fx;
4017 y1 = mon_list[who].fy;
4020 /* Oops */
4021 else
4023 x1 = x;
4024 y1 = y;
4028 /* Default "destination" */
4029 y2 = y;
4030 x2 = x;
4033 /* Hack -- verify stuff */
4034 if (flg & (PROJECT_THRU))
4036 if ((x1 == x2) && (y1 == y2))
4038 flg &= ~(PROJECT_THRU);
4043 /* Hack -- Assume there will be no blast (max radius 16) */
4044 for (dist = 0; dist < 16; dist++) gm[dist] = 0;
4047 /* Initial grid */
4048 y = y1;
4049 x = x1;
4051 /* Collect beam grids */
4052 if (flg & (PROJECT_BEAM))
4054 gy[grids] = y;
4055 gx[grids] = x;
4056 grids++;
4060 /* Calculate the projection path */
4061 path_n = project_path(path_g, MAX_RANGE, y1, x1, y2, x2, flg);
4064 /* Hack -- Handle stuff */
4065 handle_stuff();
4067 /* Project along the path */
4068 for (i = 0; i < path_n; ++i)
4070 int oy = y;
4071 int ox = x;
4073 int ny = GRID_Y(path_g[i]);
4074 int nx = GRID_X(path_g[i]);
4076 /* Hack -- Balls explode before reaching walls */
4077 if (!cave_floor_bold(ny, nx) && (rad > 0)) break;
4079 /* Advance */
4080 y = ny;
4081 x = nx;
4083 /* Collect beam grids */
4084 if (flg & (PROJECT_BEAM))
4086 gy[grids] = y;
4087 gx[grids] = x;
4088 grids++;
4091 /* Only do visuals if requested */
4092 if (!blind && !(flg & (PROJECT_HIDE)))
4094 /* Only do visuals if the player can "see" the bolt */
4095 if (player_has_los_bold(y, x))
4097 u16b p;
4099 byte a;
4100 char c;
4102 /* Obtain the bolt pict */
4103 p = bolt_pict(oy, ox, y, x, typ);
4105 /* Extract attr/char */
4106 a = PICT_A(p);
4107 c = PICT_C(p);
4109 /* Visual effects */
4110 print_rel(c, a, y, x);
4111 move_cursor_relative(y, x);
4113 Term_fresh();
4114 if (p_ptr->window) window_stuff();
4116 Term_xtra(TERM_XTRA_DELAY, msec);
4118 lite_spot(y, x);
4120 Term_fresh();
4121 if (p_ptr->window) window_stuff();
4123 /* Display "beam" grids */
4124 if (flg & (PROJECT_BEAM))
4126 /* Obtain the explosion pict */
4127 p = bolt_pict(y, x, y, x, typ);
4129 /* Extract attr/char */
4130 a = PICT_A(p);
4131 c = PICT_C(p);
4133 /* Visual effects */
4134 print_rel(c, a, y, x);
4137 /* Hack -- Activate delay */
4138 visual = TRUE;
4141 /* Hack -- delay anyway for consistency */
4142 else if (visual)
4144 /* Delay for consistency */
4145 Term_xtra(TERM_XTRA_DELAY, msec);
4151 /* Save the "blast epicenter" */
4152 y2 = y;
4153 x2 = x;
4155 /* Start the "explosion" */
4156 gm[0] = 0;
4158 /* Hack -- make sure beams get to "explode" */
4159 gm[1] = grids;
4161 /* Explode */
4162 /* Hack -- remove final beam grid */
4163 if (flg & (PROJECT_BEAM))
4165 grids--;
4168 /* Determine the blast area, work from the inside out */
4169 for (dist = 0; dist <= rad; dist++)
4171 /* Scan the maximal blast area of radius "dist" */
4172 for (y = y2 - dist; y <= y2 + dist; y++)
4174 for (x = x2 - dist; x <= x2 + dist; x++)
4176 /* Ignore "illegal" locations */
4177 if (!in_bounds(y, x)) continue;
4179 /* Enforce a "circular" explosion */
4180 if (distance(y2, x2, y, x) != dist) continue;
4182 /* Ball explosions are stopped by walls */
4183 if (!los(y2, x2, y, x)) continue;
4185 /* Save this grid */
4186 gy[grids] = y;
4187 gx[grids] = x;
4188 grids++;
4192 /* Encode some more "radius" info */
4193 gm[dist+1] = grids;
4197 /* Speed -- ignore "non-explosions" */
4198 if (!grids) return (FALSE);
4201 /* Display the "blast area" if requested */
4202 if (!blind && !(flg & (PROJECT_HIDE)))
4204 /* Then do the "blast", from inside out */
4205 for (t = 0; t <= rad; t++)
4207 /* Dump everything with this radius */
4208 for (i = gm[t]; i < gm[t+1]; i++)
4210 /* Extract the location */
4211 y = gy[i];
4212 x = gx[i];
4214 /* Only do visuals if the player can "see" the blast */
4215 if (player_has_los_bold(y, x))
4217 u16b p;
4219 byte a;
4220 char c;
4222 drawn = TRUE;
4224 /* Obtain the explosion pict */
4225 p = bolt_pict(y, x, y, x, typ);
4227 /* Extract attr/char */
4228 a = PICT_A(p);
4229 c = PICT_C(p);
4231 /* Visual effects -- Display */
4232 print_rel(c, a, y, x);
4236 /* Hack -- center the cursor */
4237 move_cursor_relative(y2, x2);
4239 /* Flush each "radius" separately */
4240 Term_fresh();
4242 /* Flush */
4243 if (p_ptr->window) window_stuff();
4245 /* Delay (efficiently) */
4246 if (visual || drawn)
4248 Term_xtra(TERM_XTRA_DELAY, msec);
4252 /* Flush the erasing */
4253 if (drawn)
4255 /* Erase the explosion drawn above */
4256 for (i = 0; i < grids; i++)
4258 /* Extract the location */
4259 y = gy[i];
4260 x = gx[i];
4262 /* Hack -- Erase if needed */
4263 if (player_has_los_bold(y, x))
4265 lite_spot(y, x);
4269 /* Hack -- center the cursor */
4270 move_cursor_relative(y2, x2);
4272 /* Flush the explosion */
4273 Term_fresh();
4275 /* Flush */
4276 if (p_ptr->window) window_stuff();
4281 /* Check features */
4282 if (flg & (PROJECT_GRID))
4284 /* Start with "dist" of zero */
4285 dist = 0;
4287 /* Scan for features */
4288 for (i = 0; i < grids; i++)
4290 /* Hack -- Notice new "dist" values */
4291 if (gm[dist+1] == i) dist++;
4293 /* Get the grid location */
4294 y = gy[i];
4295 x = gx[i];
4297 /* Affect the feature in that grid */
4298 if (project_f(who, dist, y, x, dam, typ)) notice = TRUE;
4303 /* Update stuff if needed */
4304 if (p_ptr->update) update_stuff();
4307 /* Check objects */
4308 if (flg & (PROJECT_ITEM))
4310 /* Start with "dist" of zero */
4311 dist = 0;
4313 /* Scan for objects */
4314 for (i = 0; i < grids; i++)
4316 /* Hack -- Notice new "dist" values */
4317 if (gm[dist+1] == i) dist++;
4319 /* Get the grid location */
4320 y = gy[i];
4321 x = gx[i];
4323 /* Affect the object in the grid */
4324 if (project_o(who, dist, y, x, dam, typ)) notice = TRUE;
4329 /* Check monsters */
4330 if (flg & (PROJECT_KILL))
4332 /* Mega-Hack */
4333 project_m_n = 0;
4334 project_m_x = 0;
4335 project_m_y = 0;
4337 /* Start with "dist" of zero */
4338 dist = 0;
4340 /* Scan for monsters */
4341 for (i = 0; i < grids; i++)
4343 /* Hack -- Notice new "dist" values */
4344 if (gm[dist+1] == i) dist++;
4346 /* Get the grid location */
4347 y = gy[i];
4348 x = gx[i];
4350 /* Affect the monster in the grid */
4351 if (project_m(who, dist, y, x, dam, typ)) notice = TRUE;
4354 /* Player affected one monster (without "jumping") */
4355 if ((who < 0) && (project_m_n == 1) && !(flg & (PROJECT_JUMP)))
4357 /* Location */
4358 x = project_m_x;
4359 y = project_m_y;
4361 /* Track if possible */
4362 if (cave_m_idx[y][x] > 0)
4364 monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
4366 /* Hack -- auto-recall */
4367 if (m_ptr->ml) monster_race_track(m_ptr->r_idx);
4369 /* Hack - auto-track */
4370 if (m_ptr->ml) health_track(cave_m_idx[y][x]);
4376 /* Check player */
4377 if (flg & (PROJECT_KILL))
4379 /* Start with "dist" of zero */
4380 dist = 0;
4382 /* Scan for player */
4383 for (i = 0; i < grids; i++)
4385 /* Hack -- Notice new "dist" values */
4386 if (gm[dist+1] == i) dist++;
4388 /* Get the grid location */
4389 y = gy[i];
4390 x = gx[i];
4392 /* Affect the player */
4393 if (project_p(who, dist, y, x, dam, typ))
4395 notice = TRUE;
4397 /* Only affect the player once */
4398 break;
4404 /* Return "something was noticed" */
4405 return (notice);