1 /* $Id$ */
2 /* File: spells1.c */
3
4 /* Purpose: Spell code (part 1) */
5
6 /*
7 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
8 *
9 * This software may be copied and distributed for educational, research, and
10 * not for profit purposes provided that this copyright and statement are
11 * included in all such copies.
12 */
13
14 #define SERVER
15
16 #include "angband.h"
17
18
19 /* 1/x chance of reducing stats (for elemental attacks) */
20 #define HURT_CHANCE 16
21
22 /* chance of equipments getting hurt from attacks, in percent [2] */
23 #define HARM_EQUIP_CHANCE 0
24
25 /* macro to determine the way stat gets reduced by element attacks */
26 #define DAM_STAT_TYPE(inv) \
27 (magik(inv*25) ? STAT_DEC_NORMAL : STAT_DEC_TEMPORARY)
28
29 /*
30 * Maximum lower limit for player teleportation. [30]
31 * This should make teleportation of high-lv players look 'more random'.
32 * To disable, comment it out.
33 */
34 #define TELEPORT_MIN_LIMIT 30
35
36 /* Default radius of Space-Time anchor. [12] */
37 #define ST_ANCHOR_DIS 12
38
39 /* Limitation for teleport radius on the wilderness. [20] */
40 #define WILDERNESS_TELEPORT_RADIUS 40
41
42 /* Macro to test in project_p() whether we are hurt by a PvP
43 (player vs player) or a normal PvM (player vs monster) attack */
44 #define IS_PVP (who < 0 && who >= -NumPlayers)
45 /* Similar purpose macro (also for take_hit)
46 (Note: While i > 0 can also mean special PROJECTOR_... causes,
47 i < 0 is exclusively reserved for monsters.) */
48 #define IS_PLAYER(i) (i > 0 && i <= NumPlayers)
49 #define IS_MONSTER(i) (i < 0)
50
51 /* Take damage before applying polymorph effect?
52 Traditionally, polymorph would cancel damage instead. - C. Blue */
53 #define DAMAGE_BEFORE_POLY
54
55 /* Don't allow (ball spell) explosions to extend the effective
56 reach of the caster over MAX_RANGE? */
57 #define NO_EXPLOSION_OUT_OF_MAX_RANGE
58
59 /* Typical resistance check for all GF_OLD_ and GF_TURN_ attacks */
60 #define RES_OLD(lev, dam) ((lev) > randint(((dam) - 5) < 1 ? 1 : ((dam) - 5)) + 5)
61
62 /* Sleep power of any GF_OLD_SLEEP spell [500] */
63 #define GF_OLD_SLEEP_DUR 300
64
65
66 /*
67 * Potions "smash open" and cause an area effect when
68 * (1) they are shattered while in the player's inventory,
69 * due to cold (etc) attacks;
70 * (2) they are thrown at a monster, or obstacle;
71 * (3) they are shattered by a "cold ball" or other such spell
72 * while lying on the floor.
73 *
74 * Arguments:
75 * who --- who caused the potion to shatter (0=player)
76 * potions that smash on the floor are assumed to
77 * be caused by no-one (who = 1), as are those that
78 * shatter inside the player inventory.
79 * (Not anymore -- I changed this; TY)
80 * y, x --- coordinates of the potion (or player if
81 * the potion was in her inventory);
82 * o_ptr --- pointer to the potion object.
83 */
84 /*
85 * Copy & Pasted from ToME :) - Jir -
86 * NOTE:
87 * seemingly TV_POTION2 are not haldled right (ToME native bug?).
88 */
potion_smash_effect(int who,worldpos * wpos,int y,int x,int o_sval)89 bool potion_smash_effect(int who, worldpos *wpos, int y, int x, int o_sval) {
90 int radius = 2;
91 int dt = 0;
92 int dam = 0;
93 bool ident = FALSE;
94 bool angry = FALSE;
95 int flg = (PROJECT_NORF | PROJECT_JUMP | PROJECT_ITEM | PROJECT_KILL | PROJECT_SELF | PROJECT_NODO);
96
97 switch (o_sval) {
98 case SV_POTION_SLIME_MOLD:
99 case SV_POTION_WATER: /* perhaps a 'water' attack? */
100 case SV_POTION_APPLE_JUICE:
101 return TRUE;
102
103 case SV_POTION_INFRAVISION:
104 case SV_POTION_DETECT_INVIS:
105 case SV_POTION_SLOW_POISON:
106 case SV_POTION_CURE_POISON:
107 case SV_POTION_RESIST_HEAT:
108 case SV_POTION_RESIST_COLD:
109 case SV_POTION_RESTORE_EXP:
110 case SV_POTION_ENLIGHTENMENT:
111 case SV_POTION_STAR_ENLIGHTENMENT:
112 case SV_POTION_SELF_KNOWLEDGE:
113 case SV_POTION_RESISTANCE:
114 case SV_POTION_INVULNERABILITY:
115 // case SV_POTION_NEW_LIFE:
116 /* All of the above potions have no effect when shattered */
117 return FALSE;
118
119 case SV_POTION_EXPERIENCE:
120 dt = GF_EXP;
121 dam = 1; /* level */
122 ident = TRUE;
123 break;
124 case SV_POTION_BOLDNESS:
125 radius = 3;
126 dt = GF_REMFEAR;
127 // ident = TRUE;
128 dam = 1; /* dummy */
129 break;
130 case SV_POTION_SALT_WATER:
131 dt = GF_OLD_CONF;
132 dam = damroll(10, 5);
133 ident = TRUE;
134 angry = TRUE;
135
136 /* terraform hack: melt ice^^ (Ding's suggestion) */
137 {
138 cave_type **zcave;
139 if (!(zcave = getcave(wpos))) return TRUE; //paranoia
140 if (zcave[y][x].feat == FEAT_ICE_WALL) { //100% chance for now, beats fire magic o_O
141 if (who < 0 && who > PROJECTOR_UNUSUAL) msg_print(-who, "The ice wall melts.");
142 cave_set_feat_live(wpos, y, x, FEAT_SHAL_WATER);
143 }
144 }
145
146 break;
147 case SV_POTION_LOSE_MEMORIES:
148 dt = GF_OLD_CONF;
149 dam = damroll(10, 11);
150 ident = TRUE;
151 angry = TRUE;
152 break;
153 case SV_POTION_DEC_STR:
154 radius = 1;
155 dt = GF_DEC_STR;
156 dam = 1; /* dummy */
157 ident = TRUE;
158 angry = TRUE;
159 break;
160 case SV_POTION_DEC_INT:
161 angry = TRUE;
162 break;
163 case SV_POTION_DEC_WIS:
164 angry = TRUE;
165 break;
166 case SV_POTION_DEC_DEX:
167 radius = 1;
168 dt = GF_DEC_DEX;
169 dam = 1; /* dummy */
170 ident = TRUE;
171 angry = TRUE;
172 break;
173 case SV_POTION_DEC_CON:
174 radius = 1;
175 dt = GF_DEC_CON;
176 dam = 1; /* dummy */
177 ident = TRUE;
178 angry = TRUE;
179 break;
180 case SV_POTION_DEC_CHR:
181 angry = TRUE;
182 break;
183 case SV_POTION_RES_STR:
184 radius = 1;
185 dt = GF_RES_STR;
186 dam = 1; /* dummy */
187 break;
188 case SV_POTION_RES_INT:
189 break;
190 case SV_POTION_RES_WIS:
191 break;
192 case SV_POTION_RES_DEX:
193 radius = 1;
194 dt = GF_RES_DEX;
195 dam = 1; /* dummy */
196 break;
197 case SV_POTION_RES_CON:
198 radius = 1;
199 dt = GF_RES_CON;
200 dam = 1; /* dummy */
201 break;
202 case SV_POTION_RES_CHR:
203 break;
204 case SV_POTION_INC_STR:
205 radius = 1;
206 dt = GF_INC_STR;
207 dam = 1; /* dummy */
208 ident = TRUE;
209 break;
210 case SV_POTION_INC_INT:
211 break;
212 case SV_POTION_INC_WIS:
213 break;
214 case SV_POTION_INC_DEX:
215 radius = 1;
216 dt = GF_INC_DEX;
217 dam = 1; /* dummy */
218 ident = TRUE;
219 break;
220 case SV_POTION_INC_CON:
221 radius = 1;
222 dt = GF_INC_CON;
223 dam = 1; /* dummy */
224 ident = TRUE;
225 break;
226 case SV_POTION_INC_CHR:
227 break;
228 case SV_POTION_AUGMENTATION:
229 radius = 1;
230 dt = GF_AUGMENTATION;
231 dam = 1; /* dummy */
232 ident = TRUE;
233 break;
234 case SV_POTION_HEROISM:
235 case SV_POTION_BERSERK_STRENGTH:
236 radius = 1;
237 dt = GF_HERO_MONSTER;
238 dam = damroll(2, 10);
239 ident = TRUE;
240 break;
241 case SV_POTION_SLOWNESS:
242 radius = 1;
243 dt = GF_OLD_SLOW;
244 dam = damroll(10, 5);
245 ident = TRUE;
246 angry = TRUE;
247 break;
248 case SV_POTION_POISON:
249 dt = GF_POIS;
250 dam = 7;
251 ident = TRUE;
252 angry = TRUE;
253 break;
254 case SV_POTION_BLINDNESS:
255 radius = 1;
256 dam = damroll(3, 5);
257 dt = GF_BLIND;
258 ident = TRUE;
259 angry = TRUE;
260 break;
261 case SV_POTION_CONFUSION: /* Booze */
262 radius = 1;
263 dam = damroll(10, 8);
264 dt = GF_OLD_CONF;
265 ident = TRUE;
266 angry = TRUE;
267 break;
268 case SV_POTION_SLEEP:
269 dt = GF_OLD_SLEEP;
270 dam = damroll(10, 8);
271 angry = TRUE;
272 ident = TRUE;
273 break;
274 case SV_POTION_RUINATION:
275 radius = 1;
276 dt = GF_RUINATION;
277 ident = TRUE;
278 angry = TRUE;
279 dam = 1; /* dummy */
280 break;
281 case SV_POTION_DETONATIONS:
282 radius = 3;
283 // dt = GF_DISINTEGRATE; /* GF_ROCKET;/* was GF_SHARD */
284 dt = GF_DETONATION; /* GF_DETONATION like GF_ROCKET does partially DISI ;) - C. Blue */
285 dam = damroll(45, 25);
286 aggravate_monsters_floorpos(wpos, y, x);
287 angry = TRUE;
288 ident = TRUE;
289 flg |= PROJECT_LODF; /* obsolete because of PROJECT_JUMP, but just in case */
290 #ifdef USE_SOUND_2010
291 if (who < 0 && who > PROJECTOR_UNUSUAL) sound(-who, "detonation", NULL, SFX_TYPE_MISC, FALSE);
292 #endif
293 break;
294 case SV_POTION_DEATH:
295 // dt = GF_DEATH_RAY; /* !! */ /* not implemented yet. */
296 dt = GF_NETHER_WEAK; /* special damage type solemnly for potion smash effect */
297 dam = damroll(30,30);
298 angry = TRUE;
299 radius = 2;
300 ident = TRUE;
301 break;
302 case SV_POTION_SPEED:
303 dt = GF_OLD_SPEED;
304 dam = damroll(5, 3);
305 ident = TRUE;
306 break;
307 case SV_POTION_CURE_LIGHT:
308 dt = GF_OLD_HEAL;
309 dam = damroll(2,3);
310 ident = TRUE;
311 break;
312 case SV_POTION_CURE_SERIOUS:
313 dt = GF_OLD_HEAL;
314 dam = damroll(4,3);
315 ident = TRUE;
316 break;
317 case SV_POTION_CURE_CRITICAL:
318 dt = GF_OLD_HEAL;
319 dam = damroll(6,3);
320 ident = TRUE;
321 break;
322 case SV_POTION_CURING:
323 dt = GF_CURING; //GF_OLD_HEAL;
324 dam = 0x4 + 0x8 + 0x10 + 0x20; //damroll(5,10);
325 ident = TRUE;
326 break;
327 case SV_POTION_HEALING:
328 dt = GF_OLD_HEAL;
329 dam = damroll(10,10);
330 ident = TRUE;
331 break;
332 case SV_POTION_STAR_HEALING:
333 dt = GF_OLD_HEAL;
334 dam = damroll(30,20);
335 radius = 1;
336 ident = TRUE;
337 break;
338 case SV_POTION_LIFE:
339 dt = GF_LIFEHEAL;
340 dam = damroll(30,20);
341 radius = 1;
342 ident = TRUE;
343 break;
344 #if 0 /* silly. people DRINK these */
345 case SV_POTION_RESTORE_MANA: /* MANA */
346 dt = GF_MANA;
347 dam = damroll(8,10);
348 radius = 1;
349 ident = TRUE;
350 break;
351 case SV_POTION_STAR_RESTORE_MANA: /* MANA */
352 dt = GF_MANA;
353 dam = damroll(12,10);
354 radius = 1;
355 ident = TRUE;
356 break;
357 #endif
358 default:
359 /* Do nothing */ ;
360 return FALSE;
361 }
362
363 /* doh! project halves the dam ?! */
364 if (dt != GF_CURING) dam *= 2;
365
366 (void) project(who, radius, wpos, y, x, dam, dt,
367 flg, "");
368
369 if (ident && who < 0 && who > PROJECTOR_UNUSUAL) {
370 player_type *p_ptr = Players[-who];
371 object_type forge;
372 int lev;
373
374 invcopy(&forge, lookup_kind(TV_POTION, o_sval));
375 lev = k_info[forge.k_idx].level;
376
377 /* Combine / Reorder the pack (later) */
378 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
379
380 /* The player is now aware of the object */
381 if (!object_aware_p(-who, &forge)) {
382 object_aware(-who, &forge);
383 if (!(p_ptr->mode & MODE_PVP)) gain_exp(-who, (lev + (p_ptr->lev >> 1)) / p_ptr->lev);
384 }
385
386 /* Window stuff */
387 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
388 }
389
390 /* XXX those potions that explode need to become "known" */
391 return angry;
392 }
393
394
395 /*
396 * Helper function -- return a "nearby" race for polymorphing
397 *
398 * Note that this function is one of the more "dangerous" ones...
399 */
poly_r_idx(int r_idx)400 s16b poly_r_idx(int r_idx) {
401 monster_race *r_ptr = &r_info[r_idx];
402 int i, r, lev1, lev2;
403
404 /* Hack -- Uniques never polymorph */
405 if (r_ptr->flags1 & RF1_UNIQUE) return (r_idx);
406
407 get_mon_num_hook = dungeon_aux;
408 get_mon_num_prep(0, reject_uniques);
409
410 /* Allowable range of "levels" for resulting monster */
411 lev1 = r_ptr->level - ((randint(20)/randint(9))+1);
412 lev2 = r_ptr->level + ((randint(20)/randint(9))+1);
413
414 /* Pick a (possibly new) non-unique race */
415 for (i = 0; i < 1000; i++) {
416 /* Pick a new race, using a level calculation */
417 /* Don't base this on "dlev" */
418 /*r = get_mon_num((dlev + r_ptr->level) / 2 + 5, (dlev + r_ptr->level) / 2);*/
419 r = get_mon_num(r_ptr->level + 5, r_ptr->level);
420
421 /* Handle failure */
422 if (!r) break;
423
424 /* Obtain race */
425 r_ptr = &r_info[r];
426
427 /* Ignore unique monsters */
428 // if (r_ptr->flags1 & RF1_UNIQUE) continue;
429
430 /* Ignore monsters with incompatible levels */
431 if ((r_ptr->level < lev1) || (r_ptr->level > lev2)) continue;
432
433 /* Use that index */
434 r_idx = r;
435
436 /* Done */
437 break;
438 }
439
440 /* Result */
441 return (r_idx);
442 }
443
444 /*
445 * It is radius-based now.
446 *
447 * TODO:
448 * - give some messages
449 * - allow monsters to have st-anchor?
450 */
451 //bool check_st_anchor(struct worldpos *wpos)
check_st_anchor(struct worldpos * wpos,int y,int x)452 bool check_st_anchor(struct worldpos *wpos, int y, int x) {
453 int i;
454 // dun_level *l_ptr = getfloor(wpos);
455
456 for (i = 1; i <= NumPlayers; i++) {
457 player_type *q_ptr = Players[i];
458
459 /* Skip disconnected players */
460 if (q_ptr->conn == NOT_CONNECTED) continue;
461
462 /* Skip players not on this depth */
463 if (!inarea(&q_ptr->wpos, wpos)) continue;
464
465 /* Maybe CAVE_ICKY/CAVE_STCK can be checked here */
466
467 // if (!q_ptr->st_anchor) continue;
468 // if (!q_ptr->anti_tele) continue;
469 // if ((!q_ptr->res_tele) && (rand_int(100) < 67)) continue;
470 if (!q_ptr->resist_continuum) continue;
471
472 /* Compute distance */
473 if (distance(y, x, q_ptr->py, q_ptr->px) > ST_ANCHOR_DIS)
474 continue;
475
476 // if(istown(wpos) && randint(100)>q_ptr->lev) continue;
477
478 return TRUE;
479 }
480
481 /* Assume no st_anchor */
482 return FALSE;
483 }
484
485
486 /*
487 * Teleport a monster, normally up to "dis" grids away.
488 *
489 * Attempt to move the monster at least "dis/2" grids away.
490 *
491 * But allow variation to prevent infinite loops.
492 */
teleport_away(int m_idx,int dis)493 bool teleport_away(int m_idx, int dis) {
494 int oy, ox, d, i, min;
495 int ny = 0, nx = 0, max_dis = 200, tries = 5000;
496 #ifdef USE_SOUND_2010
497 int org_dis = dis;
498 #endif
499
500 bool look = TRUE;
501
502 monster_type *m_ptr = &m_list[m_idx];
503 monster_race *r_ptr = race_inf(m_ptr);
504 dun_level *l_ptr;
505 struct worldpos *wpos;
506 cave_type **zcave;
507
508 /* Paranoia */
509 if (!m_ptr->r_idx) return FALSE;
510
511 if (r_ptr->flags9 & RF9_IM_TELE) return FALSE;
512
513 /* Save the old location */
514 oy = m_ptr->fy;
515 ox = m_ptr->fx;
516
517 /* Space/Time Anchor */
518 if (check_st_anchor(&m_ptr->wpos, oy, ox)) return FALSE;
519
520
521 wpos = &m_ptr->wpos;
522 if (!(zcave = getcave(wpos))) return FALSE;
523 l_ptr = getfloor(wpos);
524
525 /* No teleporting/blinking out of any vaults (!) */
526 if (zcave[oy][ox].info & CAVE_ICKY) return FALSE;
527
528 /* set distance according to map size, to avoid 'No empty field' failures for very small maps! */
529 if (l_ptr && distance(1, 1, l_ptr->wid, l_ptr->hgt) < max_dis)
530 max_dis = distance(1, 1, l_ptr->wid, l_ptr->hgt);
531
532 /* Verify max distance */
533 if (dis > max_dis) dis = max_dis;
534
535 /* Minimum distance */
536 min = dis / 2;
537
538 /* Look until done */
539 while (look) {
540 /* Verify max distance once here */
541 if (dis > max_dis) dis = max_dis;
542
543 /* Try several locations */
544 for (i = 0; i < 500; i++) {
545 /* Pick a (possibly illegal) location */
546 while (--tries) {
547 ny = rand_spread(oy, dis);
548 nx = rand_spread(ox, dis);
549 d = distance(oy, ox, ny, nx);
550 if ((d >= min) && (d <= dis)) break;
551 }
552 if (!tries) return FALSE;
553
554 /* Ignore illegal locations */
555 if (!in_bounds4(l_ptr, ny, nx)) continue;
556
557 /* Require "empty" floor space */
558 if (!cave_empty_bold(zcave, ny, nx)) continue;
559
560 /* Hack -- no teleport onto glyph of warding */
561 if (zcave[ny][nx].feat == FEAT_GLYPH) continue;
562 if (zcave[ny][nx].feat == FEAT_RUNE) continue;
563 /* No teleporting into vaults and such */
564 if (zcave[ny][nx].info & CAVE_ICKY) continue;
565
566 /* No teleportation onto protected grid (8-town-houses) */
567 if (zcave[ny][nx].info & CAVE_PROT) continue;
568 if (f_info[zcave[ny][nx].feat].flags1 & FF1_PROTECTED) continue;
569 /* Not onto (dungeon) stores */
570 if (zcave[ny][nx].feat == FEAT_SHOP) continue;
571
572 /* Space/Time Anchor */
573 if (check_st_anchor(&m_ptr->wpos, ny, nx)) return FALSE;
574
575 /* This grid looks good */
576 look = FALSE;
577
578 /* Stop looking */
579 break;
580 }
581
582 /* Increase the maximum distance */
583 dis = dis * 2;
584
585 /* Decrease the minimum distance */
586 min = min / 2;
587 }
588
589 /* Update the new location */
590 zcave[ny][nx].m_idx = m_idx;
591 cave_midx_debug(wpos, ny, nx, m_idx);
592
593 /* Update the old location */
594 zcave[oy][ox].m_idx = 0;
595
596 /* Move the monster */
597 m_ptr->fy = ny;
598 m_ptr->fx = nx;
599
600 /* Update the monster (new location) */
601 update_mon(m_idx, TRUE);
602
603 /* Redraw the old grid */
604 everyone_lite_spot(wpos, oy, ox);
605
606 /* Redraw the new grid */
607 everyone_lite_spot(wpos, ny, nx);
608
609 #ifdef USE_SOUND_2010
610 if (org_dis <= 20 && org_dis >= 10) sound_near_monster(m_idx, "blink", NULL, SFX_TYPE_COMMAND);
611 else if (org_dis > 20) sound_near_monster(m_idx, "teleport", NULL, SFX_TYPE_COMMAND);
612 #endif
613
614 /* Succeeded. */
615 return TRUE;
616 }
617
618
619 /*
620 * Teleport monster next to the player
621 */
teleport_to_player(int Ind,int m_idx)622 void teleport_to_player(int Ind, int m_idx) {
623 player_type *p_ptr = Players[Ind];
624 int ny = 0, nx = 0, oy, ox, d, i, min;
625 int dis = 2, max_dis = 200;
626 bool look = TRUE;
627
628 monster_type *m_ptr = &m_list[m_idx];
629 // int attempts = 200;
630 int attempts = 5000;
631
632 struct worldpos *wpos = &m_ptr->wpos;
633 dun_level *l_ptr;
634 cave_type **zcave;
635 // if(p_ptr->resist_continuum) {msg_print("The space-time continuum can't be disrupted."); return;}
636
637 /* Paranoia */
638 if (!m_ptr->r_idx) return;
639
640 /* "Skill" test */
641 // if (randint(100) > m_ptr->level) return; /* not here */
642
643 if(!(zcave = getcave(wpos))) return;
644 l_ptr = getfloor(wpos);
645
646 /* Save the old location */
647 oy = m_ptr->fy;
648 ox = m_ptr->fx;
649
650 /* Hrm, I cannot remember/see why it's commented out..
651 * maybe pets and golems need it? */
652 // if (check_st_anchor(wpos)) return;
653 if (check_st_anchor(wpos, oy, ox)) return;
654
655 /* set distance according to map size, to avoid 'No empty field' failures for very small maps! */
656 if (l_ptr && distance(1, 1, l_ptr->wid, l_ptr->hgt) < max_dis)
657 max_dis = distance(1, 1, l_ptr->wid, l_ptr->hgt);
658
659 /* Verify max distance */
660 if (dis > max_dis) dis = max_dis;
661
662 /* Minimum distance */
663 min = dis / 2;
664
665 /* Look until done */
666 while (look) {
667 /* Verify max distance */
668 if (dis > max_dis) dis = max_dis;
669
670 /* Try several locations */
671 for (i = 0; i < 500; i++) {
672 /* Pick a (possibly illegal) location */
673 while (--attempts) {
674 ny = rand_spread(p_ptr->py, dis);
675 nx = rand_spread(p_ptr->px, dis);
676 d = distance(p_ptr->py, p_ptr->px, ny, nx);
677 if ((d >= min) && (d <= dis)) break;
678 }
679 if (!attempts) return;
680
681 /* Ignore illegal locations */
682 if (!in_bounds(ny, nx)) continue;
683
684 /* Require "empty" floor space */
685 if (!cave_empty_bold(zcave, ny, nx)) continue;
686
687 /* Hack -- no teleport onto glyph of warding */
688 if (zcave[ny][nx].feat == FEAT_GLYPH) continue;
689 if (zcave[ny][nx].feat == FEAT_RUNE) continue;
690 #if 0
691 if (cave[ny][nx].feat == FEAT_MINOR_GLYPH) continue;
692
693 /* ...nor onto the Pattern */
694 if ((cave[ny][nx].feat >= FEAT_PATTERN_START) &&
695 (cave[ny][nx].feat <= FEAT_PATTERN_XTRA2)) continue;
696 #endif /* 0 */
697
698 /* No teleporting into vaults and such */
699 /* if (cave[ny][nx].info & (CAVE_ICKY)) continue; */
700 if (zcave[ny][nx].info & CAVE_ICKY) continue;
701
702 /* No teleportation onto protected grid (8-town-houses) */
703 if (zcave[ny][nx].info & CAVE_PROT) continue;
704 if (f_info[zcave[ny][nx].feat].flags1 & FF1_PROTECTED) continue;
705 /* Not onto (dungeon) stores */
706 if (zcave[ny][nx].feat == FEAT_SHOP) continue;
707
708 if (check_st_anchor(wpos, ny, nx)) return;
709
710 /* This grid looks good */
711 look = FALSE;
712
713 /* Stop looking */
714 break;
715 }
716
717 /* Increase the maximum distance */
718 dis = dis * 2;
719
720 /* Decrease the minimum distance */
721 min = min / 2;
722 }
723
724 #ifdef USE_SOUND_2010
725 sound(Ind, "blink", NULL, SFX_TYPE_COMMAND, FALSE);
726 #else
727 // sound(SOUND_TPOTHER);
728 #endif
729
730 /* Update the new location */
731 zcave[ny][nx].m_idx = m_idx;
732 cave_midx_debug(wpos, ny, nx, m_idx);
733
734 /* Update the old location */
735 zcave[oy][ox].m_idx = 0;
736
737 /* Move the monster */
738 m_ptr->fy = ny;
739 m_ptr->fx = nx;
740
741 /* Update the monster (new location) */
742 update_mon(m_idx, TRUE);
743
744 /* Redraw the old grid */
745 everyone_lite_spot(wpos, oy, ox);
746
747 /* Redraw the new grid */
748 everyone_lite_spot(wpos, ny, nx);
749 }
750
751
752 /*
753 * Teleport the player to a location up to "dis" grids away.
754 *
755 * If no such spaces are readily available, the distance may increase.
756 * Try very hard to move the player at least a quarter that distance.
757 */
teleport_player(int Ind,int dis,bool ignore_pvp)758 bool teleport_player(int Ind, int dis, bool ignore_pvp) {
759 player_type *p_ptr = Players[Ind];
760 #if defined(USE_SOUND_2010) || defined(ENABLE_SELF_FLASHING)
761 int org_dis = dis;
762 #endif
763 int d, i, min, ox, oy, x = p_ptr->py, y = p_ptr->px;
764 int xx , yy, m_idx, max_dis = 150, tries = 3000; /* (max_dis was 200 at some point) */
765 worldpos *wpos = &p_ptr->wpos;
766 dun_level *l_ptr;
767
768 bool look = TRUE;
769 bool left_shop = (dis == 1) || istown(wpos) //istown hack: prevent teleporting people who can't swim into the lake in Bree
770 || isdungeontown(wpos); //for IDDC random towns to avoid lava/water item destruction on logging in
771
772 /* Space/Time Anchor */
773 cave_type **zcave;
774 if(!(zcave = getcave(wpos))) return FALSE;
775 l_ptr = getfloor(wpos);
776
777 if ((p_ptr->global_event_temp & PEVF_NOTELE_00)) return FALSE;
778 if (l_ptr && (l_ptr->flags2 & LF2_NO_TELE)) return FALSE;
779 if (in_sector00(&p_ptr->wpos) && (sector00flags2 & LF2_NO_TELE)) return FALSE;
780
781 /* Hack -- Teleportation when died is always allowed */
782 if (!p_ptr->death) {
783 if (p_ptr->mode & MODE_PVP) {
784 #ifdef HOSTILITY_ABORTS_RUNNING
785 #if 1
786 /* hack: cut down phase door range in pvp, since rules dont allow running anymore */
787 if (dis == 10) dis = 5;
788 // if (dis <= 20) dis /= 2;
789 #else
790 if (ignore_pvp) dis /= 2; /* phase door spell by default works in pvp */
791 #endif
792 #endif
793
794 if (!ignore_pvp && p_ptr->pvp_prevent_tele) {
795 msg_print(Ind, "\377yThere's no easy way out of this fight!");
796 s_printf("%s TELEPORT_FAIL: pvp_prevent_tele for %s.\n", showtime(), p_ptr->name);
797 return FALSE;
798 }
799 }
800 if (p_ptr->anti_tele || check_st_anchor(wpos, p_ptr->py, p_ptr->px)) {
801 msg_print(Ind, "\377oYou are surrounded by an anti-teleportation field!");
802 s_printf("%s TELEPORT_FAIL: Anti-Tele for %s.\n", showtime(), p_ptr->name);
803 return FALSE;
804 }
805 if (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) {
806 msg_print(Ind, "\377RThis location suppresses teleportation!");
807 s_printf("%s TELEPORT_FAIL: Cave-Stck for %s.\n", showtime(), p_ptr->name);
808 return FALSE;
809 }
810
811 #ifdef AUTO_RET_NEW
812 /* Don't allow phase/teleport for auto-retaliation methods */
813 if (p_ptr->auto_retaliaty) {
814 msg_print(Ind, "\377yYou cannot use means of self-translocation for auto-retaliation.");
815 return FALSE;
816 }
817 #endif
818
819 // if (p_ptr->wpos.wz && (l_ptr->flags1 & LF1_NO_MAGIC)) return;
820 /* Hack -- on the wilderness one cannot teleport very far */
821 /* Double death isnt nice */
822 if (!wpos->wz && !istown(wpos) && dis > WILDERNESS_TELEPORT_RADIUS)
823 dis = WILDERNESS_TELEPORT_RADIUS;
824 }
825
826 /* set distance according to map size, to avoid 'No empty field' failures for very small maps! */
827 if (l_ptr && distance(1, 1, l_ptr->wid, l_ptr->hgt) < max_dis)
828 max_dis = distance(1, 1, l_ptr->wid, l_ptr->hgt);
829
830 /* Verify max distance */
831 if (dis > max_dis) dis = max_dis;
832
833 /* Verify max distance once here */
834 if (dis > max_dis) dis = max_dis;
835
836 /* Minimum distance */
837 min = dis / 2;
838
839 #ifdef TELEPORTATION_MIN_LIMIT
840 if (min > TELEPORT_MIN_LIMIT) min = TELEPORT_MIN_LIMIT;
841 #endif // TELEPORTATION_MIN_LIMIT
842
843 /* Look until done */
844 while (look && tries) {
845 /* Verify max distance */
846 if (dis > max_dis) dis = max_dis;
847
848 /* Try several locations */
849 for (i = 0; i < 500; i++) {
850 /* Pick a (possibly illegal) location */
851 while (--tries) {
852 y = rand_spread(p_ptr->py, dis);
853 x = rand_spread(p_ptr->px, dis);
854
855 d = distance(p_ptr->py, p_ptr->px, y, x);
856 //plog(format("y%d x%d d%d min%d dis%d", y, x, d, min, dis));
857 if ((d >= min) && (d <= dis)) break;
858 }
859 /* Avoid server hang-up on 100%-tree-maps */
860 if (!tries) break;
861
862 /* Ignore illegal locations */
863 if (!in_bounds4(l_ptr, y, x)) continue;
864
865 /* Require floor space if not ghost */
866 if (!p_ptr->ghost && !cave_naked_bold(zcave, y, x)) continue;
867
868 /* never teleport onto perma-walls (happens to ghosts in khazad) */
869 if (cave_perma_bold(zcave, y, x)) continue;
870
871 /* Require empty space if a ghost */
872 if (p_ptr->ghost && zcave[y][x].m_idx) continue;
873
874 /* No teleporting into vaults and such */
875 if (zcave[y][x].info & CAVE_ICKY) continue;
876 /* This prevents teleporting into broken vaults where layouts overlap :/ annoying bug */
877 if (zcave[y][x].info & CAVE_STCK) continue;
878 /* No teleporting into monster nests (experimental, 2008-05-26) */
879 if (zcave[y][x].info & CAVE_NEST_PIT) continue;
880
881 /* Prevent landing onto a store entrance */
882 if (zcave[y][x].feat == FEAT_SHOP) continue;
883
884 if (left_shop) {
885 if (zcave[y][x].feat == FEAT_SHAL_LAVA ||
886 zcave[y][x].feat == FEAT_DEEP_LAVA)
887 if (!(p_ptr->immune_fire || (p_ptr->resist_fire && p_ptr->oppose_fire)))
888 continue;
889 if (zcave[y][x].feat == FEAT_DEEP_WATER)
890 //if (!(p_ptr->immune_water || p_ptr->res_water ||
891 if (!(p_ptr->can_swim || p_ptr->levitate || p_ptr->ghost || p_ptr->tim_wraith))
892 continue;
893 }
894
895 /* Never break into st-anchor */
896 if (!p_ptr->death && check_st_anchor(wpos, y, x)) return FALSE;
897
898 /* This grid looks good */
899 look = FALSE;
900
901 /* Stop looking */
902 break;
903 }
904
905 /* Increase the maximum distance */
906 dis = dis * 2;
907
908 /* Decrease the minimum distance */
909 min = min / 2;
910 }
911
912 /* No empty field on this map o_O */
913 if (!tries) {
914 s_printf("%s TELEPORT_FAIL: No empty field found for %s.\n", showtime(), p_ptr->name);
915 msg_print(Ind, "oThe teleportation spell strangely fizzles!");
916 return FALSE;
917 }
918
919 break_cloaking(Ind, 7);
920 stop_precision(Ind);
921 stop_shooting_till_kill(Ind);
922
923 store_exit(Ind);
924
925 /* Save the old location */
926 oy = p_ptr->py;
927 ox = p_ptr->px;
928
929 #ifdef USE_SOUND_2010
930 /* note: currently 10 is the usual phase door distance, and spells can get it up to 12. */
931 if (org_dis <= 20 && org_dis >= 7) sound(Ind, "phase_door", NULL, SFX_TYPE_COMMAND, TRUE);
932 else if (org_dis > 20) {
933 sound(Ind, "teleport", NULL, SFX_TYPE_COMMAND, TRUE);
934 #ifdef TELEPORT_SURPRISES
935 p_ptr->teleported = 3;
936 #endif
937 }
938 #else
939 #ifdef TELEPORT_SURPRISES
940 if (org_dis > 20) p_ptr->teleported = 3;
941 #endif
942 #endif
943
944 /* Move the player */
945 p_ptr->py = y;
946 p_ptr->px = x;
947
948 grid_affects_player(Ind);
949
950 /* The player isn't on his old spot anymore */
951 zcave[oy][ox].m_idx = 0;
952
953 /* The player is on his new spot */
954 zcave[y][x].m_idx = 0 - Ind;
955 cave_midx_debug(wpos, y, x, -Ind);
956
957 /* Redraw the old spot */
958 everyone_lite_spot(wpos, oy, ox);
959
960 /* Don't leave me alone Daisy! */
961 if (!p_ptr->ghost) {
962 for (d = 1; d <= 9; d++) {
963 if (d == 5) continue;
964
965 xx = ox + ddx[d];
966 yy = oy + ddy[d];
967
968 if (!in_bounds4(l_ptr, yy, xx)) continue;
969
970 if ((m_idx = zcave[yy][xx].m_idx) > 0) {
971 monster_race *r_ptr = race_inf(&m_list[m_idx]);
972
973 if ((r_ptr->flags6 & RF6_TPORT) &&
974 !((r_ptr->flags3 & RF3_RES_TELE) || (r_ptr->flags9 & RF9_IM_TELE))) {
975 /*
976 * The latter limitation is to avoid
977 * totally unkillable suckers...
978 */
979 if (!(m_list[m_idx].csleep) && mon_will_run(Ind, m_idx) == FALSE) {
980 /* "Skill" test */
981 if (randint(100) < r_ptr->level)
982 teleport_to_player(Ind, m_idx);
983 }
984 }
985 }
986 }
987 }
988
989 #ifdef ENABLE_SELF_FLASHING
990 /* flicker player for a moment, to allow for easy location */
991 /* not for phase door, except when our view panel has changed from it */
992 if (p_ptr->flash_self >= 0 &&
993 (org_dis > 20 || !local_panel(Ind)))
994 p_ptr->flash_self = cfg.fps / FLASH_SELF_DIV;
995 #endif
996
997 /* Redraw the new spot */
998 everyone_lite_spot(wpos, p_ptr->py, p_ptr->px);
999
1000 /* Check for new panel (redraw map) */
1001 verify_panel(Ind);
1002
1003 /* Update stuff */
1004 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW);
1005
1006 /* Update the monsters */
1007 p_ptr->update |= (PU_DISTANCE);
1008
1009 /* Window stuff */
1010 p_ptr->window |= (PW_OVERHEAD);
1011
1012 /* Handle stuff XXX XXX XXX */
1013 if (!p_ptr->death) handle_stuff(Ind);
1014
1015 return TRUE;
1016 }
1017
1018
1019 /*
1020 * Force teleportation of a player
1021 * - mikaelh
1022 */
teleport_player_force(int Ind,int dis)1023 void teleport_player_force(int Ind, int dis) {
1024 bool anti_tele, death;
1025 player_type *p_ptr = Players[Ind];
1026
1027 /* Turn off anti-tele */
1028 anti_tele = p_ptr->anti_tele;
1029 /* set death flag as hack to escape no-tele vault grids */
1030 death = p_ptr->death;
1031
1032 /* hacks */
1033 p_ptr->anti_tele = FALSE; /* actually already covered by p_ptr->death below */
1034 p_ptr->death = TRUE;
1035
1036 teleport_player(Ind, dis, TRUE);
1037
1038 /* Restore anti-tele */
1039 p_ptr->anti_tele = anti_tele;
1040 /* restore death flag */
1041 p_ptr->death = death;
1042 }
1043
1044
1045 /*
1046 * Teleport player to a grid near the given location
1047 *
1048 * This function is slightly obsessive about correctness.
1049 * (Not anymore: This function allows teleporting into vaults (!))
1050 */
teleport_player_to(int Ind,int ny,int nx)1051 void teleport_player_to(int Ind, int ny, int nx) {
1052 player_type *p_ptr = Players[Ind];
1053
1054 int y, x, oy, ox, dis = 1, ctr = 0;
1055 struct worldpos *wpos = &p_ptr->wpos;
1056 int tries = 3000;
1057 dun_level *l_ptr;
1058 cave_type **zcave;
1059 bool town = istown(wpos);//prevent teleporting people who can't swim into the lake in Bree
1060
1061 if (!(zcave = getcave(wpos))) return;
1062 if (p_ptr->anti_tele) return;
1063 if (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) return;
1064 l_ptr = getfloor(wpos);
1065
1066 if ((p_ptr->global_event_temp & PEVF_NOTELE_00)) return;
1067 if (l_ptr && (l_ptr->flags2 & LF2_NO_TELE)) return;
1068 if (in_sector00(&p_ptr->wpos) && (sector00flags2 & LF2_NO_TELE)) return;
1069 // if (p_ptr->wpos.wz && (l_ptr->flags1 & LF1_NO_MAGIC)) return;
1070
1071 if (ny < 1) ny = 1;
1072 if (nx < 1) nx = 1;
1073 if (ny > MAX_HGT - 2) ny = MAX_HGT - 2;
1074 if (nx > MAX_WID - 2) nx = MAX_WID - 2;
1075
1076 /* Space/Time Anchor */
1077 if (check_st_anchor(wpos, ny, nx)) return;
1078
1079 /* Find a usable location */
1080 while (tries) {
1081 /* Pick a nearby legal location */
1082 while (--tries) {
1083 y = rand_spread(ny, dis);
1084 x = rand_spread(nx, dis);
1085 if (in_bounds4(l_ptr, y, x)) break;
1086
1087 /* Occasionally advance the distance */
1088 if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
1089 ctr = 0;
1090 dis++;
1091 }
1092 }
1093 if (!tries) return;
1094
1095 if (town) {
1096 if (zcave[y][x].feat == FEAT_SHAL_LAVA ||
1097 zcave[y][x].feat == FEAT_DEEP_LAVA)
1098 if (!(p_ptr->immune_fire || (p_ptr->resist_fire && p_ptr->oppose_fire))) {
1099 /* Occasionally advance the distance */
1100 if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
1101 ctr = 0;
1102 dis++;
1103 }
1104 continue;
1105 }
1106 if (zcave[y][x].feat == FEAT_DEEP_WATER)
1107 //if (!(p_ptr->immune_water || p_ptr->res_water ||
1108 if (!(p_ptr->can_swim || p_ptr->levitate || p_ptr->ghost || p_ptr->tim_wraith)) {
1109 /* Occasionally advance the distance */
1110 if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
1111 ctr = 0;
1112 dis++;
1113 }
1114 continue;
1115 }
1116 }
1117
1118 /* Cant telep in houses */
1119 if (((wpos->wz == 0) && !(zcave[y][x].info & CAVE_ICKY)) || (wpos->wz)) {
1120 /* No tele-to into no-tele vaults */
1121 if (cave_naked_bold(zcave, y, x) &&
1122 !(zcave[y][x].info & CAVE_STCK)) {
1123 /* Never break into st-anchor */
1124 if (!check_st_anchor(wpos, y, x)) {
1125 /* tele-to success */
1126 break;
1127 }
1128 }
1129 }
1130
1131 /* Occasionally advance the distance */
1132 if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
1133 ctr = 0;
1134 dis++;
1135 }
1136 }
1137
1138 store_exit(Ind);
1139
1140 /* Log, to distinguish MOVE_BODY vs TELE_TO related kills just in case */
1141 s_printf("TELE_TO: '%s' was teleported to %d,%d", p_ptr->name, x, y);
1142 if ((zcave[y][x].info & CAVE_ICKY)) s_printf(" (ICKY)");
1143 if ((zcave[y][x].info & CAVE_STCK)) s_printf(" (STCK)");
1144 s_printf(".\n");
1145
1146 /* Save the old location */
1147 oy = p_ptr->py;
1148 ox = p_ptr->px;
1149
1150 /* Move the player */
1151 p_ptr->py = y;
1152 p_ptr->px = x;
1153
1154 grid_affects_player(Ind);
1155
1156 /* The player isn't here anymore */
1157 zcave[oy][ox].m_idx = 0;
1158
1159 /* The player is now here */
1160 zcave[y][x].m_idx = 0 - Ind;
1161 cave_midx_debug(wpos, y, x, -Ind);
1162
1163 /* Redraw the old spot */
1164 everyone_lite_spot(wpos, oy, ox);
1165
1166 #ifdef ENABLE_SELF_FLASHING
1167 #if 0 /* not for tele-to - let's regarded it as a 'blink' here */
1168 /* flicker player for a moment, to allow for easy location */
1169 if (p_ptr->flash_self >= 0) p_ptr->flash_self = cfg.fps / FLASH_SELF_DIV;
1170 #else /* exception when our view panel has changed from this tele-to */
1171 if (p_ptr->flash_self >= 0 && !local_panel(Ind)) p_ptr->flash_self = cfg.fps / FLASH_SELF_DIV;
1172 #endif
1173 #endif
1174
1175 /* Redraw the new spot */
1176 everyone_lite_spot(wpos, p_ptr->py, p_ptr->px);
1177
1178 /* Check for new panel (redraw map) */
1179 verify_panel(Ind);
1180
1181 /* Update stuff */
1182 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW);
1183
1184 /* Update the monsters */
1185 p_ptr->update |= (PU_DISTANCE);
1186
1187 /* Window stuff */
1188 p_ptr->window |= (PW_OVERHEAD);
1189
1190 /* Handle stuff XXX XXX XXX */
1191 handle_stuff(Ind);
1192
1193 #ifdef USE_SOUND_2010
1194 sound(Ind, "blink", NULL, SFX_TYPE_COMMAND, TRUE);
1195 #endif
1196 }
teleport_player_to_force(int Ind,int ny,int nx)1197 void teleport_player_to_force(int Ind, int ny, int nx) {
1198 bool anti_tele, death;
1199 player_type *p_ptr = Players[Ind];
1200
1201 /* Turn off anti-tele */
1202 anti_tele = p_ptr->anti_tele;
1203 /* set death flag as hack to escape no-tele vault grids */
1204 death = p_ptr->death;
1205
1206 /* hacks */
1207 p_ptr->anti_tele = FALSE; /* actually already covered by p_ptr->death below */
1208 p_ptr->death = TRUE;
1209
1210 teleport_player_to(Ind, ny, nx);
1211
1212 /* Restore anti-tele */
1213 p_ptr->anti_tele = anti_tele;
1214 /* restore death flag */
1215 p_ptr->death = death;
1216 }
1217
1218
1219
1220 /*
1221 * Teleport the player one level up or down (random when legal)
1222 *
1223 * Note that keeping the "players_on_depth" array correct is VERY important,
1224 * otherwise levels with players still on them might be destroyed, or empty
1225 * levels could be kept around, wasting memory.
1226 */
1227
1228 /* in the wilderness, teleport to a neighboring wilderness level.
1229 * 'force' : TRUE only for level-unstaticing, ie administration work.
1230 * (can transport players out of dungeons in ways that are not 'legal' (ironman etc).
1231 * New: Disallow entering/exiting dungeons this way.
1232 */
teleport_player_level(int Ind,bool force)1233 void teleport_player_level(int Ind, bool force) {
1234 player_type *p_ptr = Players[Ind];
1235 struct worldpos *wpos = &p_ptr->wpos;
1236 struct worldpos new_depth, old_wpos;
1237 dun_level *l_ptr = getfloor(&p_ptr->wpos);
1238 char *msg = "\377rCritical bug!";
1239 cave_type **zcave;
1240 int tries = 100;
1241
1242 if (!(zcave = getcave(wpos))) return;
1243 if ((zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) && !force) return;
1244 // if (p_ptr->wpos.wz && (l_ptr->flags1 & LF1_NO_MAGIC)) return;
1245
1246 if ((p_ptr->global_event_temp & PEVF_NOTELE_00)) return;
1247 if (l_ptr && (l_ptr->flags2 & LF2_NO_TELE)) return;
1248 if (in_sector00(&p_ptr->wpos) && (sector00flags2 & LF2_NO_TELE)) return;
1249
1250 /* Space/Time Anchor */
1251 if (p_ptr->anti_tele && !force) return;
1252 if (check_st_anchor(&p_ptr->wpos, p_ptr->py, p_ptr->px) && !force) return;
1253
1254 wpcopy(&old_wpos, wpos);
1255 wpcopy(&new_depth, wpos);
1256
1257 /* If in the wilderness, teleport to a random neighboring level.
1258 This is especially important to prevent player from entering dungeons
1259 that have NO_ENTRY_WOR or similar flags (eg Valinor)! - C. Blue */
1260 if (wpos->wz == 0) {
1261 /* get a valid neighbor */
1262 do {
1263 switch (rand_int(4)) {
1264 case DIR_NORTH:
1265 if (new_depth.wy < MAX_WILD_Y - 1)
1266 new_depth.wy++;
1267 msg = "A gust of wind blows you north.";
1268 break;
1269 case DIR_EAST:
1270 if (new_depth.wx < MAX_WILD_X - 1)
1271 new_depth.wx++;
1272 msg = "A gust of wind blows you east.";
1273 break;
1274 case DIR_SOUTH:
1275 if (new_depth.wy > 0)
1276 new_depth.wy--;
1277 msg = "A gust of wind blows you south.";
1278 break;
1279 case DIR_WEST:
1280 if (new_depth.wx > 0)
1281 new_depth.wx--;
1282 msg = "A gust of wind blows you west.";
1283 break;
1284 }
1285 } while (inarea(wpos, &new_depth) && --tries);
1286 if (!tries) {
1287 msg = "There is a large magical discharge in the air.";
1288 return;
1289 }
1290
1291 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
1292 /* update the players new wilderness location */
1293
1294 /* update the players wilderness map */
1295 if (!p_ptr->ghost)
1296 p_ptr->wild_map[(new_depth.wx + new_depth.wy * MAX_WILD_X) / 8] |=
1297 (1 << ((new_depth.wx + new_depth.wy * MAX_WILD_X) % 8));
1298 /* sometimes go down */
1299 } else if ((can_go_down(wpos, 0x1) && wpos->wz > 1 &&
1300 ((!can_go_up(wpos, 0x1) || wpos->wz >= -1 || (rand_int(100) < 50)) ||
1301 (wpos->wz < 0 && wild_info[wpos->wy][wpos->wx].dungeon->flags2 & DF2_IRON)))
1302 || (force && can_go_down_simple(wpos))) {
1303 new_depth.wz--;
1304 msg = "You sink through the floor.";
1305 p_ptr->new_level_method = (new_depth.wz || (istown(&new_depth)) ? LEVEL_RAND : LEVEL_OUTSIDE_RAND);
1306 }
1307 /* else go up */
1308 else if ((can_go_up(wpos, 0x1) && wpos->wz < -1 &&
1309 !(wpos->wz > 0 && wild_info[wpos->wy][wpos->wx].tower->flags2 & DF2_IRON))
1310 || (force && can_go_up_simple(wpos))) {
1311 new_depth.wz++;
1312 msg = "You rise up through the ceiling.";
1313 p_ptr->new_level_method = (new_depth.wz || (istown(&new_depth)) ? LEVEL_RAND : LEVEL_OUTSIDE_RAND);
1314 } else {
1315 msg = "There is a large magical discharge in the air.";
1316 return;
1317 }
1318
1319 /* Tell the player */
1320 msg_print(Ind, msg);
1321
1322 #ifdef USE_SOUND_2010
1323 sound(Ind, "teleport", NULL, SFX_TYPE_COMMAND, TRUE);
1324 #endif
1325
1326 /* Remove the player */
1327 zcave[p_ptr->py][p_ptr->px].m_idx = 0;
1328
1329 /* Show that he's left */
1330 everyone_lite_spot(wpos, p_ptr->py, p_ptr->px);
1331
1332 /* Forget his lite and viewing area */
1333 forget_lite(Ind);
1334 forget_view(Ind);
1335
1336 /* Change the wpos */
1337 wpcopy(wpos, &new_depth);
1338
1339 /* One less player here */
1340 new_players_on_depth(&old_wpos, -1, TRUE);
1341
1342 /* One more player here */
1343 new_players_on_depth(wpos, 1, TRUE);
1344
1345 p_ptr->new_level_flag = TRUE;
1346 }
1347
1348 /* Like teleport_player_level() but does this for ALL players on a wpos at once
1349 so they end up together again. Added for quest_prepare_zcave(). - C. Blue
1350 Note: This bypasses all teleportation-preventing aspects.
1351 New: Disallow entering/exiting dungeons this way. */
teleport_players_level(struct worldpos * wpos)1352 void teleport_players_level(struct worldpos *wpos) {
1353 int i, method = LEVEL_OUTSIDE_RAND, tries = 100;
1354 player_type *p_ptr;
1355 struct worldpos new_wpos, old_wpos;
1356 char *msg = "\377rCritical bug!";
1357 cave_type **zcave;
1358
1359 if (!(zcave = getcave(wpos))) return;
1360
1361 wpcopy(&old_wpos, wpos);
1362 wpcopy(&new_wpos, wpos);
1363
1364 /* If in the wilderness, teleport to a random neighboring level.
1365 This is especially important to prevent player from entering dungeons
1366 that have NO_ENTRY_WOR or similar flags (eg Valinor)! - C. Blue */
1367 if (wpos->wz == 0) {
1368 /* get a valid neighbor */
1369 do {
1370 switch (rand_int(4)) {
1371 case DIR_NORTH:
1372 if (new_wpos.wy < MAX_WILD_Y - 1)
1373 new_wpos.wy++;
1374 msg = "A sudden magical gust of wind blows you north.";
1375 break;
1376 case DIR_EAST:
1377 if (new_wpos.wx < MAX_WILD_X - 1)
1378 new_wpos.wx++;
1379 msg = "A sudden magical gust of wind blows you east.";
1380 break;
1381 case DIR_SOUTH:
1382 if (new_wpos.wy > 0)
1383 new_wpos.wy--;
1384 msg = "A sudden magical gust of wind blows you south.";
1385 break;
1386 case DIR_WEST:
1387 if (new_wpos.wx > 0)
1388 new_wpos.wx--;
1389 msg = "A sudden magical gust of wind blows you west.";
1390 break;
1391 }
1392 } while (inarea(wpos, &new_wpos) && --tries);
1393 if (!tries) {
1394 msg = "There is a large magical discharge in the air.";
1395 s_printf("Warning: teleport_players_level() failed.");
1396 return;
1397 }
1398
1399 method = LEVEL_OUTSIDE_RAND;
1400 /* sometimes go down */
1401 } else if ((can_go_down(wpos, 0x1) && wpos->wz > 1 &&
1402 ((!can_go_up(wpos, 0x1) || wpos->wz >= -1 || (rand_int(100) < 50)) ||
1403 (wpos->wz < 0 && wild_info[wpos->wy][wpos->wx].dungeon->flags2 & DF2_IRON)))
1404 || (can_go_down_simple(wpos))) {
1405 new_wpos.wz--;
1406 msg = "Some arcane magic suddenly makes you sink through the floor.";
1407 method = (new_wpos.wz || (istown(&new_wpos)) ? LEVEL_RAND : LEVEL_OUTSIDE_RAND);
1408 }
1409 /* else go up */
1410 else if ((can_go_up(wpos, 0x1) && wpos->wz < -1 &&
1411 !(wpos->wz > 0 && wild_info[wpos->wy][wpos->wx].tower->flags2 & DF2_IRON))
1412 || (can_go_up_simple(wpos))) {
1413 new_wpos.wz++;
1414 msg = "Some arcane magic suddenly makes You rise up through the ceiling.";
1415 method = (new_wpos.wz || (istown(&new_wpos)) ? LEVEL_RAND : LEVEL_OUTSIDE_RAND);
1416 } else {
1417 msg = "There is a large magical discharge in the air.";
1418 s_printf("Warning: teleport_players_level() failed.");
1419 return;
1420 }
1421
1422 for (i = 1; i <= NumPlayers; i++) {
1423 p_ptr = Players[i];
1424 if (!inarea(&p_ptr->wpos, wpos)) continue;
1425
1426 p_ptr->new_level_method = method;
1427
1428 /* update the players new wilderness location */
1429
1430 /* update the players wilderness map */
1431 if(!p_ptr->ghost)
1432 p_ptr->wild_map[(new_wpos.wx + new_wpos.wy * MAX_WILD_X) / 8] |=
1433 (1 << ((new_wpos.wx + new_wpos.wy * MAX_WILD_X) % 8));
1434
1435 /* Tell the player */
1436 msg_print(i, msg);
1437
1438 #ifdef USE_SOUND_2010
1439 sound(i, "teleport", NULL, SFX_TYPE_COMMAND, TRUE);
1440 #endif
1441
1442 /* Remove the player */
1443 zcave[p_ptr->py][p_ptr->px].m_idx = 0;
1444
1445 /* Show that he's left */
1446 everyone_lite_spot(wpos, p_ptr->py, p_ptr->px);
1447
1448 /* Forget his lite and viewing area */
1449 forget_lite(i);
1450 forget_view(i);
1451
1452 /* One less player here */
1453 new_players_on_depth(&old_wpos, -1, TRUE);
1454
1455 /* Change the wpos */
1456 wpcopy(&p_ptr->wpos, &new_wpos);
1457
1458 p_ptr->new_level_flag = TRUE;
1459
1460 /* One more player here */
1461 new_players_on_depth(&new_wpos, 1, TRUE);
1462 }
1463 }
1464
1465 #ifndef EXTENDED_TERM_COLOURS
1466 /*
1467 * Return a color to use for the bolt/ball spells
1468 */
spell_color(int type)1469 byte spell_color(int type)
1470 {
1471 /* Hack -- fake monochrome */
1472 if (!use_color) return (TERM_WHITE);
1473
1474 /* Analyze */
1475 switch (type) /* colourful ToME ones :) */
1476 {
1477 case GF_MISSILE: return (TERM_SLATE);
1478 case GF_ACID: return (TERM_ACID);
1479 case GF_ELEC: return (TERM_ELEC);
1480 case GF_FIRE: return (TERM_FIRE);
1481 case GF_COLD: return (TERM_COLD);
1482 case GF_POIS: return (TERM_POIS);
1483 case GF_UNBREATH: return (randint(7) < 3 ? TERM_L_GREEN : TERM_GREEN);
1484 // case GF_HOLY_ORB: return (TERM_L_DARK);
1485 case GF_HOLY_ORB: return (randint(6) == 1 ? TERM_ORANGE : TERM_L_DARK);
1486 case GF_HOLY_FIRE: return (randint(3) != 1 ? TERM_ORANGE : (randint(2) == 1 ? TERM_YELLOW : TERM_WHITE));
1487 case GF_HELL_FIRE: return (randint(5) == 1 ? TERM_RED : TERM_L_DARK);
1488 case GF_MANA: return (randint(5) != 1 ? TERM_VIOLET : TERM_L_BLUE);
1489 case GF_ARROW: return (TERM_L_UMBER);
1490 case GF_WATER: return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
1491 case GF_WAVE: return (randint(4) == 1 ? TERM_L_BLUE : TERM_BLUE);
1492 case GF_VAPOUR: return (randint(10) == 1 ? TERM_BLUE : TERM_L_BLUE);
1493 case GF_NETHER_WEAK:
1494 case GF_NETHER: return (randint(4) == 1 ? TERM_L_GREEN : TERM_L_DARK);
1495 case GF_CHAOS: return (TERM_MULTI);
1496 case GF_DISENCHANT: return (randint(4) != 1 ? TERM_ORANGE : TERM_BLUE);
1497 case GF_NEXUS: return (randint(5) < 3 ? TERM_L_RED : TERM_VIOLET);
1498 case GF_CONFUSION: return (TERM_CONF);
1499 case GF_SOUND: return (TERM_SOUN);
1500 case GF_SHARDS: return (TERM_SHAR);
1501 case GF_FORCE: return (randint(5) < 3 ? TERM_L_WHITE : TERM_ORANGE);
1502 case GF_INERTIA: return (randint(5) < 3 ? TERM_SLATE : TERM_L_WHITE);
1503 case GF_GRAVITY: return (randint(3) == 1? TERM_L_UMBER : TERM_UMBER);
1504 case GF_TIME: return (randint(3) == 1? TERM_GREEN : TERM_L_BLUE);
1505 case GF_LITE_WEAK: return (TERM_LITE);
1506 case GF_LITE: return (TERM_LITE);
1507 case GF_DARK_WEAK: return (TERM_DARKNESS);
1508 case GF_DARK: return (TERM_DARKNESS);
1509 case GF_PLASMA: return (randint(5) == 1? TERM_RED : TERM_L_RED);
1510 case GF_METEOR: return (randint(3) == 1? TERM_RED : TERM_UMBER);
1511 case GF_ICE: return (randint(4) == 1? TERM_L_BLUE : TERM_WHITE);
1512 case GF_INFERNO:
1513 case GF_DETONATION:
1514 case GF_ROCKET: return (randint(6) < 4 ? TERM_L_RED : (randint(4) == 1 ? TERM_RED : TERM_L_UMBER));
1515 case GF_NUKE: return (mh_attr(2));
1516 case GF_DISINTEGRATE: return (randint(3) != 1 ? TERM_L_DARK : (randint(2) == 1 ? TERM_ORANGE : TERM_VIOLET));
1517 case GF_PSI: return (randint(5) != 1 ? (rand_int(2) ? (rand_int(2) ? TERM_YELLOW : TERM_L_BLUE) : 127) : TERM_WHITE);
1518 /* new spell - the_sandman */
1519 case GF_CURSE: return (randint(2) == 1 ? TERM_DARKNESS : TERM_L_DARK);
1520 case GF_OLD_DRAIN: return (TERM_DARKNESS);
1521 /* Druids stuff */
1522 case GF_HEALINGCLOUD: return (TERM_LITE);//return (randint(5) > 1 ? TERM_WHITE : TERM_L_BLUE);
1523 case GF_WATERPOISON: return (TERM_COLD);//return (randint(2) == 1 ? TERM_L_BLUE : (randint(2) == 1 ? TERM_BLUE : (randint(2) == 1 ? TERM_GREEN : TERM_L_GREEN)));
1524 case GF_ICEPOISON: return (TERM_SHAR);//return (randint(3) > 1 ? TERM_UMBER : (randint(2) == 1 ? TERM_GREEN : TERM_SLATE));
1525 /* To remove some hacks? */
1526 case GF_THUNDER: return (randint(3) != 1 ? TERM_ELEC : (randint(2) == 1 ? TERM_YELLOW : TERM_LITE));
1527 case GF_ANNIHILATION: return (randint(2) == 1 ? TERM_DARKNESS : TERM_L_DARK);
1528 }
1529
1530 /* Standard "color" */
1531 return (TERM_WHITE);
1532 }
1533
1534 /* returns whether a spell type's colours require server-side animation or not.
1535 (for efficient animations in process_effects()) - C. Blue */
spell_color_animation(int type)1536 bool spell_color_animation(int type)
1537 {
1538 /* Hack -- fake monochrome */
1539 if (!use_color) return FALSE;
1540
1541 /* Analyze */
1542 switch (type) /* colourful ToME ones :) */
1543 {
1544 case GF_MISSILE: return FALSE;
1545 case GF_ACID: return FALSE;
1546 case GF_ELEC: return FALSE;
1547 case GF_FIRE: return FALSE;
1548 case GF_COLD: return FALSE;
1549 case GF_POIS: return FALSE;
1550 case GF_UNBREATH: return TRUE;//(randint(7)<3?TERM_L_GREEN:TERM_GREEN);
1551 // case GF_HOLY_ORB: return FALSE;
1552 case GF_HOLY_ORB: return TRUE;//(randint(6)==1?TERM_ORANGE:TERM_L_DARK);
1553 case GF_HOLY_FIRE: return TRUE;//(randint(3)!=1?TERM_ORANGE:(randint(2)==1?TERM_YELLOW:TERM_WHITE));
1554 case GF_HELL_FIRE: return TRUE;//(randint(5)==1?TERM_RED:TERM_L_DARK);
1555 case GF_MANA: return TRUE;//(randint(5)!=1?TERM_VIOLET:TERM_L_BLUE);
1556 case GF_ARROW: return FALSE;
1557 case GF_WATER: return TRUE;//(randint(4)==1?TERM_L_BLUE:TERM_BLUE);
1558 case GF_WAVE: return TRUE;//(randint(4)==1?TERM_L_BLUE:TERM_BLUE);
1559 case GF_VAPOUR: return TRUE;
1560 case GF_NETHER_WEAK:
1561 case GF_NETHER: return TRUE;//(randint(4)==1?TERM_SLATE:TERM_L_DARK);
1562 case GF_CHAOS: return FALSE;
1563 case GF_DISENCHANT: return TRUE;//(randint(4)==1?TERM_ORANGE:TERM_BLUE;//TERM_L_BLUE:TERM_VIOLET);
1564 case GF_NEXUS: return TRUE;//(randint(5)<3?TERM_L_RED:TERM_VIOLET);
1565 case GF_CONFUSION: return FALSE;
1566 case GF_SOUND: return FALSE;//(randint(4)==1?TERM_VIOLET:TERM_WHITE);
1567 case GF_SHARDS: return FALSE;//(randint(5)<3?TERM_UMBER:TERM_SLATE);
1568 case GF_FORCE: return TRUE;//(randint(5)<3?TERM_L_WHITE:TERM_ORANGE);
1569 case GF_INERTIA: return TRUE;//(randint(5)<3?TERM_SLATE:TERM_L_WHITE);
1570 case GF_GRAVITY: return TRUE;//(randint(3)==1?TERM_L_UMBER:TERM_UMBER);
1571 case GF_TIME: return TRUE;//(randint(3)==1?TERM_GREEN:TERM_L_BLUE);
1572 case GF_LITE_WEAK: return FALSE;
1573 case GF_LITE: return FALSE;
1574 case GF_DARK_WEAK: return FALSE;
1575 case GF_DARK: return FALSE;
1576 case GF_PLASMA: return TRUE;//(randint(5)==1?TERM_RED:TERM_L_RED);
1577 case GF_METEOR: return TRUE;//(randint(3)==1?TERM_RED:TERM_UMBER);
1578 case GF_ICE: return TRUE;//(randint(4)==1?TERM_L_BLUE:TERM_WHITE);
1579 case GF_INFERNO:
1580 case GF_DETONATION:
1581 case GF_ROCKET: return TRUE;//(randint(6)<4?TERM_L_RED:(randint(4)==1?TERM_RED:TERM_L_UMBER));
1582 case GF_NUKE: return TRUE;//(mh_attr(2));
1583 case GF_DISINTEGRATE: return TRUE;//(randint(3)!=1?TERM_L_DARK:(randint(2)==1?TERM_VIOLET:TERM_L_ORANGE));//TERM_ORANGE:TERM_L_UMBER));
1584 case GF_PSI: return TRUE;//(randint(5)!=1?(rand_int(2)?(rand_int(2)?TERM_YELLOW:TERM_L_BLUE):127):TERM_WHITE);
1585 /* new spell - the_sandman */
1586 case GF_CURSE: return TRUE;//(randint(2)==1?TERM_DARKNESS:TERM_L_DARK);
1587 case GF_OLD_DRAIN: return FALSE;
1588 /* Druids stuff */
1589 case GF_HEALINGCLOUD: return FALSE;//return (randint(5)>1?TERM_WHITE:TERM_L_BLUE);
1590 case GF_WATERPOISON: return FALSE;//return (randint(2)==1?TERM_L_BLUE:(randint(2)==1?TERM_BLUE:(randint(2)==1?TERM_GREEN:TERM_L_GREEN)));
1591 case GF_ICEPOISON: return FALSE;//return (randint(3)>1?TERM_UMBER:(randint(2)==1?TERM_GREEN:TERM_SLATE));
1592 /* To remove some hacks? */
1593 case GF_THUNDER: return TRUE;//(randint(3)!=1?TERM_ELEC:(randint(2)==1?TERM_YELLOW:TERM_LITE));
1594 case GF_ANNIHILATION: return TRUE;//(randint(2)==1?TERM_DARKNESS:TERM_L_DARK);
1595 }
1596
1597 /* Standard "color" */
1598 return FALSE;
1599 }
1600 #else
1601 /*
1602 * Return a color to use for the bolt/ball spells
1603 */
spell_color(int type)1604 byte spell_color(int type)
1605 {
1606 /* Hack -- fake monochrome */
1607 if (!use_color) return (TERM_WHITE);
1608
1609 /* Analyze */
1610 switch (type) /* colourful ToME ones :) */
1611 {
1612 case GF_MISSILE: return (TERM_SLATE);
1613 case GF_ACID: return (TERM_ACID);
1614 case GF_ELEC: return (TERM_ELEC);
1615 case GF_FIRE: return (TERM_FIRE);
1616 case GF_COLD: return (TERM_COLD);
1617 case GF_POIS: return (TERM_POIS);
1618 case GF_UNBREATH: return (TERM_UNBREATH);
1619 // case GF_HOLY_ORB: return (TERM_L_DARK);
1620 case GF_HOLY_ORB: return (TERM_HOLYORB);
1621 case GF_HOLY_FIRE: return (TERM_HOLYFIRE);
1622 case GF_HELL_FIRE: return (TERM_HELLFIRE);
1623 case GF_MANA: return (TERM_MANA);
1624 case GF_ARROW: return (TERM_L_UMBER);
1625 case GF_VAPOUR: return (TERM_L_BLUE);//animate with some dark blue maybe?
1626 case GF_WATER: return (TERM_WATE);
1627 case GF_WAVE: return (TERM_WATE);
1628 case GF_NETHER_WEAK:
1629 case GF_NETHER: return (TERM_NETH);
1630 case GF_CHAOS: return (TERM_MULTI);
1631 case GF_DISENCHANT: return (TERM_DISE);
1632 case GF_NEXUS: return (TERM_NEXU);
1633 case GF_CONFUSION: return (TERM_CONF);
1634 case GF_SOUND: return (TERM_SOUN);
1635 case GF_SHARDS: return (TERM_SHAR);
1636 case GF_FORCE: return (TERM_FORC);
1637 case GF_INERTIA: return (TERM_INER);
1638 case GF_GRAVITY: return (TERM_GRAV);
1639 case GF_TIME: return (TERM_TIME);
1640 case GF_LITE_WEAK: return (TERM_LITE);
1641 case GF_LITE: return (TERM_LITE);
1642 case GF_DARK_WEAK: return (TERM_DARKNESS);
1643 case GF_DARK: return (TERM_DARKNESS);
1644 case GF_PLASMA: return (TERM_PLAS);
1645 case GF_METEOR: return (TERM_METEOR);
1646 case GF_ICE: return (TERM_ICE);
1647 case GF_INFERNO:
1648 case GF_DETONATION:
1649 case GF_ROCKET: return (TERM_DETO);
1650 case GF_NUKE: return (TERM_NUKE);
1651 case GF_DISINTEGRATE: return (TERM_DISI);
1652 case GF_PSI: return (TERM_PSI);
1653 /* new spell - the_sandman */
1654 case GF_CURSE: return (TERM_CURSE);
1655 case GF_OLD_DRAIN: return (TERM_DARKNESS);
1656 /* Druids stuff */
1657 case GF_HEALINGCLOUD: return (TERM_LITE);//return (randint(5)>1?TERM_WHITE:TERM_L_BLUE);
1658 case GF_WATERPOISON: return (TERM_COLD);//return (randint(2)==1?TERM_L_BLUE:(randint(2)==1?TERM_BLUE:(randint(2)==1?TERM_GREEN:TERM_L_GREEN)));
1659 case GF_ICEPOISON: return (TERM_SHAR);//return (randint(3)>1?TERM_UMBER:(randint(2)==1?TERM_GREEN:TERM_SLATE));
1660 /* To remove some hacks? */
1661 case GF_THUNDER: return (TERM_THUNDER);
1662 case GF_ANNIHILATION: return (TERM_ANNI);
1663 }
1664
1665 /* Standard "color" */
1666 return (TERM_WHITE);
1667 }
1668 #endif
1669
1670 /*
1671 * Decreases players hit points and sets death flag if necessary
1672 *
1673 * XXX XXX XXX Invulnerability needs to be changed into a "shield"
1674 *
1675 * XXX XXX XXX Hack -- this function allows the user to save (or quit)
1676 * the game when he dies, since the "You die." message is shown before
1677 * setting the player to "dead".
1678 */
1679 /* Poison/Cut timed damages, curse damages etc can bypass the shield.
1680 * It's hack; in the future, this function should be called with flags
1681 * that tells 'what kind of damage'.
1682 */
1683 bool bypass_invuln = FALSE;
take_hit(int Ind,int damage,cptr hit_from,int Ind_attacker)1684 void take_hit(int Ind, int damage, cptr hit_from, int Ind_attacker) {
1685 cptr hit_from_real = hit_from; /* non-hallucinated attacker */
1686 player_type *p_ptr = Players[Ind];
1687
1688 // The "number" that the character is displayed as before the hit
1689 int old_num, new_num;
1690
1691 /* Amulet of Immortality */
1692 if (p_ptr->admin_invuln) return;
1693
1694 /* Heavenly invulnerability? */
1695 if (p_ptr->martyr && !bypass_invuln) {
1696 break_cloaking(Ind, 0); /* still notice! paranoia though, rogues can't use martyr */
1697 return;
1698 }
1699
1700 /* Paranoia */
1701 if (p_ptr->death) return;
1702
1703 /* towns are safe-zones from ALL hostile actions - except blood bond */
1704 if (IS_PLAYER(Ind_attacker)) {
1705 if ((istown(&p_ptr->wpos) || istown(&Players[Ind_attacker]->wpos)) &&
1706 (!check_blood_bond(Ind_attacker, Ind) ||
1707 p_ptr->afk || Players[Ind_attacker]->afk))
1708 return;
1709 }
1710
1711 if (!p_ptr->no_alert) {
1712 if (((p_ptr->alert_afk_dam && p_ptr->afk)
1713 #ifdef ALERT_OFFPANEL_DAM
1714 /* new: alert when we're off-panel (cmd_locate) */
1715 || (p_ptr->alert_offpanel_dam && (p_ptr->panel_row_old != p_ptr->panel_row || p_ptr->panel_col_old != p_ptr->panel_col))
1716 #endif
1717 )
1718 /* don't alert about 0-damage terrain effect */
1719 && (damage || -Ind_attacker != PROJECTOR_TERRAIN)
1720 #ifdef USE_SOUND_2010
1721 ) {
1722 Send_warning_beep(Ind);
1723 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
1724 #else
1725 && p_ptr->paging == 0) {
1726 p_ptr->paging = 1;
1727 #endif
1728 }
1729
1730 /* warn if taking (continuous) damage while inside a store! */
1731 if (p_ptr->store_num != -1) {
1732 #ifdef USE_SOUND_2010
1733 Send_warning_beep(Ind);
1734 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
1735 #else
1736 if (p_ptr->paging == 0) p_ptr->paging = 1;
1737 #endif
1738 /* continuous-damage message only */
1739 if (bypass_invuln) msg_print(Ind, "\377RWarning - you are taking damage!");
1740 }
1741 }
1742
1743 // The "number" that the character is displayed as before the hit
1744 /* Now displays corresponding to mana amount if disruption shield
1745 is acitavted (C. Blue) */
1746 /* if (!p_ptr->tim_manashield)
1747 {
1748 */ old_num = (p_ptr->chp * 95) / (p_ptr->mhp*10);
1749 if (old_num >= 7) old_num = 10;
1750 /* }
1751 else if (p_ptr->msp > 0)
1752 {
1753
1754 old_num = (p_ptr->csp * 95) / (p_ptr->msp*10);
1755 if (old_num >= 7) old_num = 10;
1756 } */
1757
1758 /* for MODE_PVP only: prevent easy fleeing from PvP encounter >=) */
1759 if (IS_PLAYER(Ind_attacker) ||
1760 (!p_ptr->wpos.wx && !p_ptr->wpos.wy && p_ptr->wpos.wz == 1)) {
1761 p_ptr->pvp_prevent_tele = PVP_COOLDOWN_TELEPORT;
1762 p_ptr->redraw |= PR_DEPTH;
1763 }
1764
1765 // This is probably unused
1766 // int warning = (p_ptr->mhp * hitpoint_warn / 10);
1767
1768 /* Hack -- player is secured inside a store/house except in dungeons */
1769 /* XXX make sure it doesn't "leak"!
1770 * Glitchy side-effect: Player stops suffering from poison/cuts while in a store!
1771 * ..to fix that, bypass_invuln check has been added. */
1772 if (p_ptr->store_num != -1 && !p_ptr->wpos.wz && !bypass_invuln) return;
1773
1774 /* Silyl admin games -- only in totally safe environment! */
1775 if (p_ptr->admin_set_defeat &&
1776 -Ind_attacker != PROJECTOR_TERRAIN &&
1777 ge_special_sector &&
1778 (p_ptr->wpos.wx == WPOS_ARENA_X && p_ptr->wpos.wy == WPOS_ARENA_Y &&
1779 p_ptr->wpos.wz == WPOS_ARENA_Z)) {
1780 p_ptr->admin_set_defeat--;
1781 p_ptr->chp = -1;
1782 p_ptr->deathblow = 1;
1783 break_cloaking(Ind, 0);
1784 goto destined_defeat;
1785 }
1786
1787 /* Disturb - except when in PvP! */
1788 if (strcmp(hit_from, "life draining") &&
1789 !IS_PLAYER(Ind_attacker)
1790 /* hack: no longer disturb on crossing terrain that we're immune to: */
1791 && (damage || -Ind_attacker != PROJECTOR_TERRAIN))
1792 disturb(Ind, 1, 0);
1793
1794 /* Mega-Hack -- Apply "invulnerability" */
1795 if (p_ptr->invuln && (!bypass_invuln) && !p_ptr->invuln_applied) {
1796 /* 1 in 2 chance to fully deflect the damage */
1797 if (magik(40)) {
1798 msg_print(Ind, "The attack is fully deflected by a magic shield.");
1799 if (-Ind_attacker != PROJECTOR_TERRAIN) break_cloaking(Ind, 0);
1800 return;
1801 }
1802
1803 /* Otherwise damage is reduced by the shield */
1804 damage = (damage + 1) / 2;
1805 }
1806
1807 if (IS_PLAYER(Ind_attacker)) {
1808 Players[Ind_attacker]->test_count++;
1809 Players[Ind_attacker]->test_dam += damage;
1810 }
1811
1812 /* Re allowed by evileye for power */
1813 #if 1
1814 //if (p_ptr->tim_manashield)
1815 if (p_ptr->tim_manashield && (!bypass_invuln)) {
1816 if (p_ptr->csp > 0) {
1817 int taken;
1818
1819 switch(p_ptr->pclass) {
1820 case CLASS_MAGE:
1821 taken = (damage * 2 ) / 2;//mana shield works with a ratio of SP<->damage points
1822 break;
1823 default:
1824 taken = (damage * 2 ) / 1;
1825 break;
1826 }
1827
1828 if (p_ptr->csp < taken) {
1829 switch(p_ptr->pclass) {
1830 case CLASS_MAGE:
1831 damage = ((taken - p_ptr->csp) / 2) * 2;
1832 break;
1833 default:
1834 damage = ((taken - p_ptr->csp) / 2) * 1;
1835 break;
1836 }
1837
1838 p_ptr->csp = 0;
1839 /* mana shield stops on empty mana! */
1840 set_tim_manashield(Ind, 0);
1841 } else {
1842 damage = 0;
1843 p_ptr->csp -= taken;
1844 }
1845
1846 /* Display the spellpoints */
1847 p_ptr->redraw |= (PR_MANA);
1848 }
1849 }
1850 #endif
1851
1852 /* Admin silly stuff */
1853 if (IS_PLAYER(Ind_attacker) && Players[Ind_attacker]->admin_godly_strike) {
1854 Players[Ind_attacker]->admin_godly_strike--;
1855 damage = p_ptr->chp + 1;
1856 }
1857
1858 /* Hurt the player */
1859 p_ptr->chp -= damage;
1860 p_ptr->deathblow = damage;
1861
1862 /* for cloaking as well as shadow running:
1863 floor damage (like in nether realm) ain't supposed to break it! - C. Blue */
1864 //both ifs should work properly.
1865 if (-Ind_attacker != PROJECTOR_TERRAIN) break_cloaking(Ind, 0);
1866 // if (strcmp(hit_from, "hazardous environment")) break_cloaking(Ind, 0);
1867
1868 destined_defeat:
1869
1870 /* Update health bars */
1871 update_health(0 - Ind);
1872
1873 /* Display the hitpoints */
1874 p_ptr->redraw |= (PR_HP);
1875
1876 /* Figure out of if the player's "number" has changed */
1877 /* Now displays corresponding to mana amount if disruption shield
1878 is acitavted (C. Blue) */
1879 /* if (!p_ptr->tim_manashield)
1880 {
1881 */ new_num = (p_ptr->chp * 95) / (p_ptr->mhp*10);
1882 if (new_num > TURN_CHAR_INTO_NUMBER) new_num = 10;
1883 /* }
1884 else
1885 {
1886 new_num = (p_ptr->csp * 95) / (p_ptr->msp*10);
1887 if (new_num >= 7) new_num = 10;
1888 }
1889 */
1890 /* If so then refresh everyone's view of this player */
1891 if (new_num != old_num)
1892 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
1893
1894 /* Window stuff */
1895 p_ptr->window |= (PW_PLAYER);
1896
1897 /* Dead player */
1898 if (p_ptr->chp < 0) {
1899 if (IS_PLAYER(Ind_attacker)) {
1900 if (check_blood_bond(Ind, Ind_attacker)) {
1901 player_type *p2_ptr = Players[Ind_attacker];
1902 p_ptr->chp = p_ptr->mhp;
1903 p2_ptr->chp = p2_ptr->mhp;
1904 p_ptr->csp = p_ptr->msp;
1905 p2_ptr->csp = p2_ptr->msp;
1906 p_ptr->redraw |= PR_HP | PR_MANA;
1907 p2_ptr->redraw |= PR_HP | PR_MANA;
1908
1909 s_printf("BLOOD_BOND: %s won the blood bond against %s\n", p2_ptr->name, p_ptr->name);
1910 msg_broadcast_format(0, "\374\377c*** %s won the blood bond against %s. ***", p2_ptr->name, p_ptr->name);
1911
1912 remove_hostility(Ind, p2_ptr->name);
1913 remove_hostility(Ind_attacker, p_ptr->name);
1914
1915 remove_blood_bond(Ind, Ind_attacker);
1916 remove_blood_bond(Ind_attacker, Ind);
1917
1918 target_set(Ind, 0);
1919 target_set(Ind_attacker, 0);
1920
1921 /* Remove stun/KO */
1922 set_stun(Ind, 0);
1923 set_stun(Ind_attacker, 0);
1924
1925 teleport_player(Ind, 4, TRUE);
1926
1927 return;
1928 }
1929 /* get real killer (for log file and scoreboard) in case we're hallucinating */
1930 } else if (p_ptr->image && IS_MONSTER(Ind_attacker)) {
1931 /* get real monster name, in case we're hallucinating */
1932 hit_from_real = r_name + race_inf(&m_list[-Ind_attacker])->name;
1933 }
1934
1935 /* Note cause of death */
1936 /* To preserve the players original (pre-ghost) cause
1937 of death, use died_from_list. To preserve the original
1938 depth, use died_from_depth. */
1939
1940 (void)strcpy(p_ptr->died_from, hit_from); /* todo: blindness/no esp (fuzzy like for spell hits) */
1941 (void)strcpy(p_ptr->really_died_from, hit_from_real);
1942 if (!p_ptr->ghost) {
1943 strcpy(p_ptr->died_from_list, hit_from_real);
1944 p_ptr->died_from_depth = getlevel(&p_ptr->wpos);
1945 /* Hack to remember total winning */
1946 if (p_ptr->total_winner) strcat(p_ptr->died_from_list, "\001");
1947 }
1948
1949 /* No longer a winner */
1950 // p_ptr->total_winner = FALSE;
1951
1952 /* Note death */
1953 p_ptr->death = TRUE;
1954 p_ptr->deathblow = damage;
1955
1956 /* Dead */
1957 return;
1958 }
1959
1960 if (p_ptr->warning_rest != 3 && !p_ptr->warning_rest_cooldown
1961 && p_ptr->max_plv >= 3
1962 && p_ptr->chp * 10 / p_ptr->mhp <= 5) {
1963 msg_print(Ind, "\374\377oHINT: Press \377RSHIFT+r\377o to rest, so your hit points will");
1964 msg_print(Ind, "\374\377o regenerate faster. (Also true for mana and stamina.)");
1965 p_ptr->warning_rest++;
1966 p_ptr->warning_rest_cooldown = 3;//minutes
1967 acc_set_flags(p_ptr->accountname, ACC_WARN_REST, TRUE);
1968 s_printf("warning_rest: %s\n", p_ptr->name);
1969 }
1970 }
1971
1972
1973 /* Decrease player's sanity. This is a copy of the function above. */
1974 void take_sanity_hit(int Ind, int damage, cptr hit_from) {
1975 player_type *p_ptr = Players[Ind];
1976 #if 0
1977 int old_csane = p_ptr->csane;
1978 int warning = (p_ptr->msane * hitpoint_warn / 10);
1979 #endif // 0
1980
1981 /* Heavenly invulnerability? */
1982 if (p_ptr->martyr && !bypass_invuln) return;
1983
1984 /* Amulet of Immortality */
1985 if (p_ptr->admin_invuln) return;
1986
1987 /* Paranoia */
1988 if (p_ptr->death) return;
1989
1990 /* Hack -- player is secured inside a store/house except in dungeons */
1991 if (p_ptr->store_num != -1 && !p_ptr->wpos.wz && !bypass_invuln) return;
1992
1993 /* For 'Arena Monster Challenge' event: */
1994 if (safe_area(Ind)) {
1995 msg_print(Ind, "\377wYou feel disturbed, but the feeling passes.");
1996 return;
1997 }
1998
1999 #if 0 //Ind_attacker not available - players cannot cast insanity-draining effects on other players anyway
2000 /* towns are safe-zones from ALL hostile actions - except blood bond */
2001 if (IS_PLAYER(Ind_attacker)) {
2002 if ((istown(&p_ptr->wpos) || istown(&Players[Ind_attacker]->wpos)) &&
2003 (!check_blood_bond(Ind_attacker, Ind) ||
2004 p_ptr->afk || Players[Ind_attacker]->afk))
2005 return;
2006 }
2007 #endif
2008
2009 if (((p_ptr->alert_afk_dam && p_ptr->afk)
2010 #ifdef ALERT_OFFPANEL_DAM
2011 /* new: alert when we're off-panel (cmd_locate) */
2012 || (p_ptr->alert_offpanel_dam && (p_ptr->panel_row_old != p_ptr->panel_row || p_ptr->panel_col_old != p_ptr->panel_col))
2013 #endif
2014 )
2015 #ifdef USE_SOUND_2010
2016 ) {
2017 Send_warning_beep(Ind);
2018 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
2019 #else
2020 && p_ptr->paging == 0) {
2021 p_ptr->paging = 1;
2022 #endif
2023 }
2024
2025 /* warn if taking (continuous) damage while inside a store! */
2026 if (p_ptr->store_num != -1) {
2027 #ifdef USE_SOUND_2010
2028 Send_warning_beep(Ind);
2029 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
2030 #else
2031 if (p_ptr->paging == 0) p_ptr->paging = 1;
2032 #endif
2033 //there's already a message given, usually..
2034 //msg_print(Ind, "\377RWarning - you are taking sanity damage!");
2035 }
2036
2037 #ifdef USE_SOUND_2010
2038 sound(Ind, "insanity", NULL, SFX_TYPE_MISC, FALSE);
2039 #endif
2040
2041 /* Mega-Hack -- Apply "invulnerability" */
2042 if (p_ptr->invuln && (!bypass_invuln) && !p_ptr->invuln_applied) {
2043 /* 1 in 2 chance to fully deflect the damage */
2044 if (magik(40)) {
2045 msg_print(Ind, "The attack is fully deflected by a magic shield.");
2046 return;
2047 }
2048
2049 /* Otherwise damage is reduced by the shield */
2050 damage = (damage + 1) / 2;
2051 }
2052
2053
2054 /* Disturb */
2055 disturb(Ind, 1, 0);
2056
2057 /* Having WEIRD_MIND or EMPTY_MIND form helps, as well as being mindcrafter */
2058 if(p_ptr->reduce_insanity == 1) damage = (damage * (9 + rand_int(4))) / 12;
2059 if(p_ptr->reduce_insanity == 2) damage = (damage * (6 + rand_int(7))) / 12;
2060
2061 /* Hurt the player */
2062 p_ptr->csane -= damage;
2063
2064 /* Display the hitpoints */
2065 p_ptr->redraw |= (PR_SANITY);
2066
2067 /* Window stuff */
2068 p_ptr->window |= (PW_PLAYER);
2069
2070 /* Dead player */
2071 if (p_ptr->csane < 0) {
2072 /* Hack -- Note death */
2073 msg_print(Ind, "\377vYou turn into an unthinking vegetable.");
2074 /* msg_print(Ind, "\377RYou die.");
2075 msg_print(Ind, NULL); - already in xtra2.c (C. Blue)*/
2076
2077
2078 /* Note cause of death */
2079 /* To preserve the players original (pre-ghost) cause
2080 of death, use died_from_list. To preserve the original
2081 depth, use died_from_depth. */
2082
2083 (void)strcpy(p_ptr->died_from, "insanity");
2084 (void)strcpy(p_ptr->really_died_from, hit_from);
2085 if (!p_ptr->ghost) {
2086 strcpy(p_ptr->died_from_list, "insanity");
2087 p_ptr->died_from_depth = getlevel(&p_ptr->wpos);
2088 /* Hack to remember total winning */
2089 if (p_ptr->total_winner) strcat(p_ptr->died_from_list, "\001");
2090 }
2091
2092 /* No longer a winner */
2093 // p_ptr->total_winner = FALSE;
2094
2095 /* Note death */
2096 p_ptr->death = TRUE;
2097 p_ptr->deathblow = damage;
2098
2099 /* This way, player dies without becoming a ghost. */
2100 // ptr->ghost = 1;
2101
2102 /* Dead */
2103 break_cloaking(Ind, 0);
2104 break_shadow_running(Ind);
2105 stop_precision(Ind);
2106 stop_shooting_till_kill(Ind);
2107 return;
2108 }
2109
2110 /* Insanity warning (better message needed!) */
2111 if (p_ptr->csane < p_ptr->msane / 8) {
2112 /* Message */
2113 msg_print(Ind, "\377fYou can hardly suppress screaming out insane laughters!");
2114 msg_print(Ind, NULL);
2115 break_cloaking(Ind, 0);
2116 break_shadow_running(Ind);
2117 stop_precision(Ind);
2118 } else if (p_ptr->csane < p_ptr->msane / 4) {
2119 /* Message */
2120 msg_print(Ind, "\377RYou feel severly disturbed and paranoid..");
2121 msg_print(Ind, NULL);
2122 stop_precision(Ind);
2123 } else if (p_ptr->csane < p_ptr->msane / 2) {
2124 /* Message */
2125 msg_print(Ind, "\377rYou feel insanity creep into your mind..");
2126 msg_print(Ind, NULL);
2127 }
2128 }
2129
2130 /* Decrease player's exp. This is another copy of the function above.
2131 * if mode is 'TRUE', it's permanent.
2132 * if fatal, player dies if runs out of exp.
2133 *
2134 * if not permanent nor fatal, use lose_exp instead.
2135 * - Jir -
2136 */
2137 void take_xp_hit(int Ind, int damage, cptr hit_from, bool mode, bool fatal, bool disturb) {
2138 player_type *p_ptr = Players[Ind];
2139
2140 /* Amulet of Immortality */
2141 if (p_ptr->admin_invuln) return;
2142
2143 /* Paranoia */
2144 if (p_ptr->death) return;
2145
2146 if (disturb) {
2147 break_cloaking(Ind, 0);
2148 stop_precision(Ind);
2149 }
2150
2151 if (p_ptr->lev == 99) {
2152 //msg_print(Ind, "You are impervious to life force drain!");
2153 return;
2154 }
2155
2156 /* arena is safe, although this may be doubtful */
2157 if (safe_area(Ind)) return;
2158
2159 #if 0
2160 /* Hack -- player is secured inside a store/house except in dungeons */
2161 if (p_ptr->store_num != -1 && !p_ptr->wpos.wz && !bypass_invuln) return;
2162
2163 if (((p_ptr->alert_afk_dam && p_ptr->afk)
2164 #ifdef ALERT_OFFPANEL_DAM
2165 /* new: alert when we're off-panel (cmd_locate) */
2166 || (p_ptr->alert_offpanel_dam && (p_ptr->panel_row_old != p_ptr->panel_row || p_ptr->panel_col_old != p_ptr->panel_col))
2167 #endif
2168 )
2169 #ifdef USE_SOUND_2010
2170 ) {
2171 Send_warning_beep(Ind);
2172 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
2173 #else
2174 && p_ptr->paging == 0) {
2175 p_ptr->paging = 1;
2176 #endif
2177 }
2178
2179 /* warn if taking (continuous) damage while inside a store! */
2180 if (p_ptr->store_num != -1) {
2181 #ifdef USE_SOUND_2010
2182 Send_warning_beep(Ind);
2183 //sound(Ind, "warning", "page", SFX_TYPE_MISC, FALSE);
2184 #else
2185 if (p_ptr->paging == 0) p_ptr->paging = 1;
2186 #endif
2187 /* continuous-damage message only */
2188 if (bypass_invuln) msg_print(Ind, "\377RWarning - your experience is getting drained!");
2189 }
2190 #endif
2191
2192 /* Disturb */
2193 // disturb(Ind, 1, 0);
2194
2195 /* Hurt the player */
2196 p_ptr->exp -= damage;
2197 if (mode && p_ptr->max_exp) {
2198 p_ptr->max_exp -= damage;
2199 /* don't reduce max_exp to zero, in case someone insane
2200 tries to cheeze events requiring 0 exp this way ;) */
2201 if (p_ptr->max_exp < 1) p_ptr->max_exp = 1;
2202 }
2203
2204 check_experience(Ind);
2205
2206 /* Dead player */
2207 if (fatal && p_ptr->exp == 0) {
2208 /* Hack -- Note death */
2209 /* msg_print(Ind, "\377RYou die.");
2210 msg_print(Ind, NULL); - what's so 'hacky' about this?
2211 It's in xtra2.c anyways, so gone here now. C. Blue */
2212
2213 /* Note cause of death */
2214 /* To preserve the players original (pre-ghost) cause
2215 of death, use died_from_list. To preserve the original
2216 depth, use died_from_depth. */
2217
2218 (void)strcpy(p_ptr->died_from, hit_from);
2219 if (!p_ptr->ghost) {
2220 strcpy(p_ptr->died_from_list, hit_from);
2221 p_ptr->died_from_depth = getlevel(&p_ptr->wpos);
2222 /* Hack to remember total winning */
2223 if (p_ptr->total_winner) strcat(p_ptr->died_from_list, "\001");
2224 }
2225
2226 /* No longer a winner */
2227 // p_ptr->total_winner = FALSE;
2228
2229 /* Note death */
2230 p_ptr->death = TRUE;
2231 p_ptr->deathblow = 0;
2232
2233 /* Dead */
2234 break_cloaking(Ind, 0);
2235 break_shadow_running(Ind);
2236 stop_precision(Ind);
2237 stop_shooting_till_kill(Ind);
2238 return;
2239 }
2240 }
2241
2242
2243
2244 /*
2245 * Note that amulets, rods, and high-level spell books are immune
2246 * to "inventory damage" of any kind. Also sling ammo and shovels.
2247 */
2248
2249
2250 /*
2251 * Does a given class of objects (usually) hate acid?
2252 * Note that acid can either melt or corrode something.
2253 */
2254 static bool hates_acid(object_type *o_ptr)
2255 {
2256 /* Analyze the type */
2257 switch (o_ptr->tval) {
2258 /* Wearable items */
2259 case TV_ARROW:
2260 case TV_BOLT:
2261 case TV_BOW:
2262 case TV_BOOMERANG:
2263 case TV_SWORD:
2264 case TV_BLUNT:
2265 case TV_POLEARM:
2266 case TV_AXE:
2267 case TV_HELM:
2268 case TV_CROWN:
2269 case TV_SHIELD:
2270 case TV_BOOTS:
2271 case TV_GLOVES:
2272 case TV_CLOAK:
2273 case TV_SOFT_ARMOR:
2274 case TV_HARD_ARMOR:
2275 case TV_DRAG_ARMOR:
2276
2277 case TV_LITE:
2278 return (TRUE);
2279
2280 /* Staffs/Scrolls are wood/paper */
2281 case TV_STAFF:
2282 case TV_SCROLL:
2283 case TV_PARCHMENT:
2284 case TV_BOOK:
2285 return (TRUE);
2286
2287 /* Ouch */
2288 case TV_CHEST:
2289 return (TRUE);
2290
2291 /* Junk is useless */
2292 case TV_SKELETON:
2293 case TV_JUNK:
2294 return (TRUE);
2295 }
2296
2297 return (FALSE);
2298 }
2299
2300 /*
2301 * Does a given object (usually) hate electricity?
2302 */
2303 static bool hates_elec(object_type *o_ptr)
2304 {
2305 switch (o_ptr->tval) {
2306 case TV_RING:
2307 case TV_WAND:
2308 return (TRUE);
2309 }
2310
2311 return (FALSE);
2312 }
2313
2314 /*
2315 * Does a given object (usually) hate fire?
2316 * Blunt/Polearm weapons have wooden shafts.
2317 * Arrows/Bows are mostly wooden.
2318 */
2319 bool hates_fire(object_type *o_ptr)
2320 {
2321 /* Analyze the type */
2322 switch (o_ptr->tval) {
2323 /* Wearable */
2324 case TV_GLOVES:
2325 if (o_ptr->sval == SV_SET_OF_GAUNTLETS) return FALSE;
2326 case TV_ARROW:
2327 case TV_BOW:
2328 case TV_BLUNT:
2329 case TV_POLEARM:
2330 case TV_AXE:
2331 case TV_BOOTS:
2332 case TV_CLOAK:
2333 case TV_SOFT_ARMOR:
2334 return (TRUE);
2335 case TV_HELM:
2336 if (o_ptr->sval == SV_HARD_LEATHER_CAP || o_ptr->sval == SV_CLOTH_CAP) return TRUE;
2337 return FALSE;
2338 case TV_BOOMERANG:
2339 if (o_ptr->sval == SV_BOOM_S_METAL || o_ptr->sval == SV_BOOM_METAL) return(FALSE);
2340 return (TRUE);
2341
2342 /* Chests */
2343 case TV_CHEST:
2344 if (o_ptr->sval == SV_CHEST_RUINED ||
2345 o_ptr->sval == SV_CHEST_SMALL_WOODEN || o_ptr->sval == SV_CHEST_LARGE_WOODEN) return(TRUE);
2346 return (FALSE);
2347
2348 /* Staffs/Scrolls burn */
2349 case TV_STAFF:
2350 case TV_SCROLL:
2351 case TV_PARCHMENT:
2352 case TV_BOOK:
2353 return (TRUE);
2354
2355 /* Potions evaporate */
2356 case TV_POTION:
2357 case TV_POTION2:
2358 case TV_FLASK:
2359 case TV_BOTTLE: //just melts
2360 return (TRUE);
2361
2362 /* Junk, partially */
2363 case TV_SKELETON:
2364 return TRUE;
2365 }
2366
2367 return (FALSE);
2368 }
2369
2370 /*
2371 * Does a given object (usually) hate cold?
2372 */
2373 static bool hates_cold(object_type *o_ptr)
2374 {
2375 switch (o_ptr->tval) {
2376 case TV_POTION:
2377 case TV_POTION2:
2378 case TV_FLASK:
2379 //case TV_BOTTLE: <- empty! unlike potions..
2380 return (TRUE);
2381 }
2382
2383 return (FALSE);
2384 }
2385
2386 /*
2387 * Does a given object (usually) hate impact?
2388 */
2389 static bool hates_impact(object_type *o_ptr)
2390 {
2391 switch (o_ptr->tval) {
2392 case TV_POTION:
2393 case TV_POTION2:
2394 case TV_FLASK:
2395 case TV_BOTTLE:
2396 case TV_EGG:
2397 return (TRUE);
2398 }
2399
2400 return (FALSE);
2401 }
2402
2403 /*
2404 * Does a given object (usually) hate water?
2405 */
2406 bool hates_water(object_type *o_ptr)
2407 {
2408 switch (o_ptr->tval) {
2409 // case TV_POTION: /* dilutes */
2410 // case TV_POTION2: /* dilutes */
2411 case TV_SCROLL: /* fades */
2412 case TV_BOOK:
2413 return (TRUE);
2414 }
2415
2416 return (FALSE);
2417 }
2418
2419 /*
2420 * Does a given object rust from water? (for equip_damage()) - C. Blue
2421 */
2422 static bool can_rust(object_type *o_ptr)
2423 {
2424 switch (o_ptr->tval) {
2425 #if 0
2426 case TV_GLOVES: if (o_ptr->sval == SV_LEATHER_GLOVES || o_ptr->sval == SV_SET_OF_ELVEN_GLOVES) return FALSE;
2427 case TV_BOOMERANG: if (o_ptr->sval == SV_BOOM_WOOD || o_ptr->sval == SV_BOOM_S_WOOD) return(FALSE); else return(TRUE);
2428 case TV_CROWN: if (o_ptr->sval == SV_IRON_CROWN) return(TRUE); else return(FALSE);
2429 case TV_SHIELD: if (o_ptr->sval == SV_SMALL_LEATHER_SHIELD || o_ptr->sval == SV_LARGE_LEATHER_SHIELD) return(FALSE); else return(TRUE);
2430 case TV_HARD_ARMOR: if (o_ptr->sval == SV_MITHRIL_CHAIN_MAIL || o_ptr->sval == SV_MITHRIL_PLATE_MAIL || o_ptr->sval == SV_ADAMANTITE_PLATE_MAIL) return (FALSE); else return(TRUE);
2431 case TV_HELM: if (o_ptr->sval == SV_HARD_LEATHER_CAP) return(FALSE); else return(TRUE);
2432 #else
2433 case TV_GLOVES:
2434 case TV_BOOMERANG:
2435 case TV_CROWN:
2436 case TV_SHIELD:
2437 case TV_HARD_ARMOR:
2438 case TV_HELM:
2439 #endif
2440 case TV_SWORD:
2441 // :) case TV_BLUNT:
2442 case TV_POLEARM:
2443 case TV_AXE:
2444 return (TRUE);
2445 }
2446
2447 return (FALSE);
2448 }
2449
2450
2451
2452 /*
2453 * Melt something
2454 */
2455 static int set_acid_destroy(object_type *o_ptr)
2456 {
2457 u32b f1, f2, f3, f4, f5, f6, esp;
2458
2459 if (!hates_acid(o_ptr)) return (FALSE);
2460 /* Extract the flags */
2461 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2462 if (f3 & TR3_IGNORE_ACID) return (FALSE);
2463 return (TRUE);
2464 }
2465
2466 /*
2467 * Electrical damage
2468 */
2469 static int set_elec_destroy(object_type *o_ptr)
2470 {
2471 u32b f1, f2, f3, f4, f5, f6, esp;
2472
2473 if (!hates_elec(o_ptr)) return (FALSE);
2474 /* Extract the flags */
2475 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2476 if (f3 & TR3_IGNORE_ELEC) return (FALSE);
2477 return (TRUE);
2478 }
2479
2480 /*
2481 * Burn something
2482 */
2483 static int set_fire_destroy(object_type *o_ptr)
2484 {
2485 u32b f1, f2, f3, f4, f5, f6, esp;
2486
2487 if (!hates_fire(o_ptr)) return (FALSE);
2488 /* Extract the flags */
2489 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2490 if (f3 & TR3_IGNORE_FIRE) return (FALSE);
2491 return (TRUE);
2492 }
2493
2494 /*
2495 * Freeze things
2496 */
2497 int set_cold_destroy(object_type *o_ptr)
2498 {
2499 u32b f1, f2, f3, f4, f5, f6, esp;
2500
2501 if (!hates_cold(o_ptr)) return (FALSE);
2502 /* Extract the flags */
2503 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2504 if (f3 & TR3_IGNORE_COLD) return (FALSE);
2505 return (TRUE);
2506 }
2507
2508 /*
2509 * Crash things
2510 */
2511 int set_impact_destroy(object_type *o_ptr)
2512 {
2513 u32b f1, f2, f3, f4, f5, f6, esp;
2514
2515 if (!hates_impact(o_ptr)) return (FALSE);
2516 /* Extract the flags */
2517 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2518 /* Hack -- borrow flag */
2519 // if (f3 & TR3_IGNORE_COLD) return (FALSE);
2520 return (TRUE);
2521 }
2522
2523 /*
2524 * Soak something
2525 */
2526 int set_water_destroy(object_type *o_ptr)
2527 {
2528 u32b f1, f2, f3, f4, f5, f6, esp;
2529
2530 if (!hates_water(o_ptr)) return (FALSE);
2531 /* Extract the flags */
2532 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2533 if (f5 & TR5_IGNORE_WATER) return (FALSE);
2534 return (TRUE);
2535 }
2536
2537 /*
2538 * Rust
2539 */
2540 static int set_rust_destroy(object_type *o_ptr)
2541 {
2542 u32b f1, f2, f3, f4, f5, f6, esp;
2543
2544 if (!can_rust(o_ptr)) return (FALSE);
2545 /* Extract the flags */
2546 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2547 if ((f3 & TR3_IGNORE_ACID) || (f5 & TR5_IGNORE_WATER)) return (FALSE);
2548 return (TRUE);
2549 }
2550
2551 /*
2552 * Burn/Crash things
2553 */
2554 /*
2555 * Does a given object (usually) hate GF_ROCKET damage,
2556 * ie hates_fire() or hates_impact()?
2557 * (Note: Add shards too in case hates_shards() is ever added to the game)
2558 */
2559 int set_rocket_destroy(object_type *o_ptr)
2560 {
2561 u32b f1, f2, f3, f4, f5, f6, esp;
2562
2563 if (!hates_impact(o_ptr)) {
2564 if (!hates_fire(o_ptr)) return (FALSE);
2565 /* Extract the flags */
2566 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2567 if (f3 & TR3_IGNORE_FIRE) return (FALSE);
2568 }
2569 return (TRUE);
2570 }
2571
2572 /*
2573 * Every things
2574 */
2575 int set_all_destroy(object_type *o_ptr)
2576 {
2577 if (artifact_p(o_ptr)) return (FALSE);
2578 // if (is_realm_book(o_ptr) && o_ptr->sval >= SV_BOOK_MIN_GOOD) return (FALSE);
2579 if (is_realm_book(o_ptr)) {
2580 u32b f1, f2, f3, f4, f5, f6, esp;
2581 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
2582 /* Hack^2 -- use this as a sign of being 'high books' */
2583 if (f3 & TR3_IGNORE_ELEC) return (FALSE);
2584 }
2585 return (TRUE);
2586 }
2587
2588
2589
2590 /*
2591 * This seems like a pretty standard "typedef"
2592 */
2593 //typedef int (*inven_func)(object_type *);
2594
2595 /*
2596 * Destroys a type of item on a given percent chance
2597 * Note that missiles are no longer necessarily all destroyed
2598 * Destruction taken from "melee.c" code for "stealing".
2599 * Returns number of items destroyed.
2600 */
2601 int inven_damage(int Ind, inven_func typ, int perc) {
2602 player_type *p_ptr = Players[Ind];
2603 int i, j, k, amt;
2604 object_type *o_ptr;
2605 char o_name[ONAME_LEN];
2606
2607 if (safe_area(Ind)) return(FALSE);
2608 /* secret dungeon master is unaffected (potion shatter effects might be bad) */
2609 if (p_ptr->admin_dm) return(FALSE);
2610
2611 /* Count the casualties */
2612 k = 0;
2613
2614 /* Scan through the slots backwards */
2615 for (i = 0; i < INVEN_TOTAL; i++) {
2616 /* Hack -- equipments are harder to be harmed */
2617 if (i >= INVEN_PACK && i != INVEN_AMMO && !magik(HARM_EQUIP_CHANCE))
2618 continue;
2619
2620 /* Get the item in that slot */
2621 o_ptr = &p_ptr->inventory[i];
2622
2623 /* Hack -- for now, skip artifacts */
2624 if (artifact_p(o_ptr)) continue;
2625
2626 /* Give this item slot a shot at death */
2627 if ((*typ)(o_ptr)) {
2628 /* Count the casualties */
2629 for (amt = j = 0; j < o_ptr->number; ++j) {
2630 if (rand_int(100) < perc) amt++;
2631 }
2632
2633 /* Some casualities */
2634 if (amt) {
2635 /* Get a description */
2636 object_desc(Ind, o_name, o_ptr, FALSE, 3);
2637
2638 /* Message */
2639 msg_format(Ind, "\376\377o%sour %s (%c) %s destroyed!",
2640 ((o_ptr->number > 1) ?
2641 ((amt == o_ptr->number) ? "All of y" :
2642 (amt > 1 ? "Some of y" : "One of y")) : "Y"),
2643 o_name, index_to_label(i),
2644 ((amt > 1) ? "were" : "was"));
2645
2646 /* Potions smash open */
2647 if (k_info[o_ptr->k_idx].tval == TV_POTION &&
2648 typ != set_water_destroy) /* MEGAHACK */
2649 // && typ != set_cold_destroy)
2650 {
2651 // (void)potion_smash_effect(0, &p_ptr->wpos, p_ptr->py, p_ptr->px, o_ptr->sval);
2652 bypass_invuln = TRUE;
2653 (void)potion_smash_effect(PROJECTOR_POTION, &p_ptr->wpos, p_ptr->py, p_ptr->px, o_ptr->sval);
2654 bypass_invuln = FALSE;
2655 }
2656
2657 /* Destroy "amt" items */
2658 if (o_ptr->tval == TV_WAND) (void)divide_charged_item(o_ptr, amt);
2659 inven_item_increase(Ind, i, -amt);
2660 inven_item_optimize(Ind, i);
2661
2662 /* Count the casualties */
2663 k += amt;
2664 }
2665 }
2666 }
2667
2668 /* Return the casualty count */
2669 return (k);
2670 }
2671
2672
2673
2674
2675 /*
2676 * Acid, water or fire has hit the player, attempt to affect some armor. - C. Blue
2677 * Note that the "base armor" of an object never changes.
2678 * If any armor is damaged (or resists), the player takes less damage. <- not implemented atm
2679 */
2680 /* Hack -- 'water' means it was water damage (and not acid).
2681 * TODO: add IGNORE_WATER flags */
2682 int equip_damage(int Ind, int typ) {
2683 player_type *p_ptr = Players[Ind];
2684 object_type *o_ptr = NULL;
2685 char o_name[ONAME_LEN];
2686 int shield_bonus = 0;
2687 u32b dummy, f2, f5;
2688
2689 if (safe_area(Ind)) return(FALSE);
2690 if (p_ptr->admin_dm) return(FALSE);
2691
2692 /* Pick a (possibly empty) inventory slot */
2693 #if !defined(NEW_SHIELDS_NO_AC) || !defined(USE_NEW_SHIELDS)
2694 // switch (rand_int(is_weapon(p_ptr->inventory[INVEN_ARM].tval) ? 5 : 6)) { /* in case of DUAL_WIELD */
2695 switch (rand_int(p_ptr->inventory[INVEN_ARM].tval == TV_SHIELD ? 6 : 5)) { /* in case of DUAL_WIELD */
2696 #else
2697 switch (rand_int(5)) {
2698 #endif
2699 case 0: o_ptr = &p_ptr->inventory[INVEN_BODY]; break;
2700 case 1: o_ptr = &p_ptr->inventory[INVEN_OUTER]; break;
2701 case 2: o_ptr = &p_ptr->inventory[INVEN_HANDS]; break;
2702 case 3: o_ptr = &p_ptr->inventory[INVEN_HEAD]; break;
2703 case 4: o_ptr = &p_ptr->inventory[INVEN_FEET]; break;
2704 case 5: o_ptr = &p_ptr->inventory[INVEN_ARM];
2705 #ifdef USE_NEW_SHIELDS
2706 shield_bonus = o_ptr->to_a;
2707 #endif
2708 break;
2709 }
2710
2711 /* Nothing to damage */
2712 if (!o_ptr->k_idx) return (FALSE);
2713
2714 switch (typ) {
2715 case GF_WATER:
2716 if (!set_rust_destroy(o_ptr)) return(FALSE); else break; /* for some equipped items set_rust_destroy and set_water_destroy may be different */
2717 case GF_ACID:
2718 if (!set_acid_destroy(o_ptr)) return(FALSE); else break;
2719 case GF_FIRE:
2720 if (!set_fire_destroy(o_ptr)) return(FALSE); else break;
2721 default: return(FALSE);
2722 }
2723
2724 /* hack: not disenchantable -> cannot be damaged either */
2725 object_flags(o_ptr, &dummy, &f2, &dummy, &dummy, &f5, &dummy, &dummy);
2726 if ((f2 & TR2_RES_DISEN) || (f5 & TR5_IGNORE_DISEN)) return FALSE;
2727
2728 /* No damage left to be done */
2729 if (o_ptr->ac + o_ptr->to_a + shield_bonus <= 0) return (FALSE);
2730
2731 /* Describe */
2732 object_desc(Ind, o_name, o_ptr, FALSE, 0);
2733
2734 /* Message */
2735 msg_format(Ind, "\376\377oYour %s is damaged!", o_name);
2736
2737 /* Damage the item */
2738 o_ptr->to_a--;
2739
2740 /* Calculate bonuses */
2741 p_ptr->update |= (PU_BONUS);
2742
2743 /* Window stuff */
2744 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
2745
2746 /* Item was damaged */
2747 return (TRUE);
2748 }
2749
2750 /*
2751 * Acid or water has hit the player but he blocked it. Damage the shield! - C. Blue
2752 * Note that the "base armor" of an object never changes.
2753 */
2754 #ifndef NEW_SHIELDS_NO_AC
2755 int shield_takes_damage(int Ind, int typ) {
2756 player_type *p_ptr = Players[Ind];
2757 object_type *o_ptr = &p_ptr->inventory[INVEN_ARM];
2758 char o_name[ONAME_LEN];
2759 u32b dummy, f2, f5;
2760
2761 if (safe_area(Ind)) return(FALSE);
2762 if (p_ptr->admin_dm) return(FALSE);
2763
2764 /* Nothing to damage */
2765 if (!o_ptr->k_idx) return (FALSE);
2766
2767 switch (typ) {
2768 case GF_WATER:
2769 if (p_ptr->immune_water || !set_rust_destroy(o_ptr))
2770 return(FALSE);
2771 else break; /* for some equipped items set_rust_destroy and set_water_destroy may be different */
2772 case GF_ACID:
2773 if (p_ptr->immune_acid || !set_acid_destroy(o_ptr))
2774 return(FALSE);
2775 else break;
2776 case GF_FIRE:
2777 if (p_ptr->immune_fire || !set_fire_destroy(o_ptr))
2778 return(FALSE);
2779 else break;
2780 default: return(FALSE);
2781 }
2782
2783 /* hack: not disenchantable -> cannot be damaged either */
2784 object_flags(o_ptr, &dummy, &f2, &dummy, &dummy, &f5, &dummy, &dummy);
2785 if ((f2 & TR2_RES_DISEN) || (f5 & TR5_IGNORE_DISEN)) return FALSE;
2786
2787 /* No damage left to be done */
2788 #ifdef USE_NEW_SHIELDS
2789 if (o_ptr->ac + o_ptr->to_a * 2 <= 0) return (FALSE);
2790 #else
2791 if (o_ptr->ac + o_ptr->to_a <= 0) return (FALSE);
2792 #endif
2793
2794 /* Describe */
2795 object_desc(Ind, o_name, o_ptr, FALSE, 0);
2796
2797 /* Message */
2798 msg_format(Ind, "\376\377oYour %s is damaged!", o_name);
2799
2800 /* Damage the item */
2801 o_ptr->to_a--;
2802
2803 /* Calculate bonuses */
2804 p_ptr->update |= (PU_BONUS);
2805
2806 /* Window stuff */
2807 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
2808
2809 /* Item was damaged */
2810 return (TRUE);
2811 }
2812 #endif
2813
2814 int weapon_takes_damage(int Ind, int typ, int slot) {
2815 player_type *p_ptr = Players[Ind];
2816 object_type *o_ptr = &p_ptr->inventory[slot];
2817 char o_name[ONAME_LEN];
2818 u32b dummy, f2, f5;
2819
2820 if (safe_area(Ind)) return(FALSE);
2821 if (p_ptr->admin_dm) return(FALSE);
2822
2823 /* Nothing to damage */
2824 if (!o_ptr->k_idx) return (FALSE);
2825
2826 switch (typ) {
2827 case GF_WATER:
2828 /* hack -- decrease the variety of damaging attacks a bit, mercifully */
2829 if (o_ptr->tval == TV_BLUNT || o_ptr->tval == TV_POLEARM) return(FALSE);
2830
2831 if (p_ptr->immune_water || !set_rust_destroy(o_ptr))
2832 return(FALSE);
2833 break; /* for some equipped items set_rust_destroy and set_water_destroy may be different */
2834 case GF_ACID:
2835 /* hack -- decrease the variety of damaging attacks a bit, mercifully */
2836 if (o_ptr->tval == TV_BLUNT || o_ptr->tval == TV_POLEARM) return(FALSE);
2837
2838 if (p_ptr->immune_acid || !set_acid_destroy(o_ptr))
2839 return(FALSE);
2840 break;
2841 case GF_FIRE:
2842 /* hack -- decrease the variety of damaging attacks a bit, mercifully */
2843 if (o_ptr->tval == TV_SWORD || o_ptr->tval == TV_AXE) return(FALSE);
2844
2845 if (p_ptr->immune_fire || !set_fire_destroy(o_ptr))
2846 return(FALSE);
2847 break;
2848 default: return(FALSE);
2849 }
2850
2851 /* hack: not disenchantable -> cannot be damaged either */
2852 object_flags(o_ptr, &dummy, &f2, &dummy, &dummy, &f5, &dummy, &dummy);
2853 if ((f2 & TR2_RES_DISEN) || (f5 & TR5_IGNORE_DISEN)) return FALSE;
2854
2855 /* No damage left to be done */
2856 if (o_ptr->to_d <= -10) return (FALSE);
2857
2858 /* Describe */
2859 object_desc(Ind, o_name, o_ptr, FALSE, 0);
2860
2861 /* Message */
2862 msg_format(Ind, "\376\377oYour %s is damaged!", o_name);
2863
2864 /* Damage the item */
2865 o_ptr->to_d--;
2866
2867 /* Calculate bonuses */
2868 p_ptr->update |= (PU_BONUS);
2869
2870 /* Window stuff */
2871 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
2872
2873 /* Item was damaged */
2874 return (TRUE);
2875 }
2876
2877
2878 /*
2879 * Hurt the player with Acid
2880 */
2881 int acid_dam(int Ind, int dam, cptr kb_str, int Ind_attacker)
2882 {
2883 player_type *p_ptr = Players[Ind];
2884
2885 int inv, hurt_eq;
2886
2887 dam -= p_ptr->reduc_acid * dam / 100;
2888
2889 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
2890
2891 /* this is SO much softer than MAngband, heh. I think it's good tho - C. Blue */
2892 hurt_eq = (dam < 30) ? 15 : (dam < 60) ? 33 : 100;
2893 if (p_ptr->resist_acid && p_ptr->oppose_acid) hurt_eq = (hurt_eq + 2) / 3;
2894 else if (p_ptr->resist_acid || p_ptr->oppose_acid) hurt_eq = (hurt_eq + 1) / 2;
2895
2896 /* Total Immunity */
2897 if (p_ptr->immune_acid || (dam <= 0)) return(0);
2898
2899 /* Resist the damage */
2900 if (p_ptr->suscep_acid) dam = dam * 2;
2901 if (p_ptr->resist_acid) dam = (dam + 2) / 3;
2902 if (p_ptr->oppose_acid) dam = (dam + 2) / 3;
2903
2904 /* Don't kill inventory in bloodbond... */
2905 int breakable = 1;
2906 if (IS_PLAYER(Ind_attacker)) {
2907 if (check_blood_bond(Ind, Ind_attacker)) {
2908 breakable = 0;
2909 }
2910 }
2911
2912 if ((!(p_ptr->oppose_acid || p_ptr->resist_acid)) &&
2913 randint(HURT_CHANCE) == 1 && breakable)
2914 (void) do_dec_stat(Ind, A_CHR, DAM_STAT_TYPE(inv));
2915
2916 /* If any armor gets hit, defend the player */
2917 /* let's tone it down a bit; since immunity completely protects all eq,
2918 let's have resistance work similar - C. Blue */
2919 // if (magik(33) && equip_damage(Ind, GF_ACID)) dam = (dam + 1) / 2;
2920 // if (magik(50) && equip_damage(Ind, GF_ACID)) dam = (dam + 1) / 2;
2921 // if (equip_damage(Ind, GF_ACID)) dam = (dam + 1) / 2;
2922 if (magik(hurt_eq) && breakable) equip_damage(Ind, GF_ACID);
2923
2924 /* Take damage */
2925 // take_hit(Ind, dam, kb_str, Ind_attacker);
2926
2927 /* Inventory damage */
2928 if (!(p_ptr->oppose_acid && p_ptr->resist_acid) && breakable)
2929 inven_damage(Ind, set_acid_destroy, inv);
2930
2931 return(dam);
2932 }
2933
2934 /*
2935 * Hurt the player with electricity
2936 */
2937 int elec_dam(int Ind, int dam, cptr kb_str, int Ind_attacker)
2938 {
2939 player_type *p_ptr = Players[Ind];
2940
2941 int inv;
2942
2943 dam -= p_ptr->reduc_elec * dam / 100;
2944
2945 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
2946
2947 /* Total immunity */
2948 if (p_ptr->immune_elec || (dam <= 0)) return(0);
2949
2950 /* Resist the damage */
2951 if (p_ptr->suscep_elec) dam = dam * 2;
2952 if (p_ptr->oppose_elec) dam = (dam + 2) / 3;
2953 if (p_ptr->resist_elec) dam = (dam + 2) / 3;
2954
2955 /* Don't kill inventory in bloodbond... */
2956 int breakable = 1;
2957 if (IS_PLAYER(Ind_attacker)) {
2958 if (check_blood_bond(Ind, Ind_attacker)) {
2959 breakable = 0;
2960 }
2961 }
2962
2963 if ((!(p_ptr->oppose_elec || p_ptr->resist_elec)) &&
2964 randint(HURT_CHANCE) == 1 && breakable)
2965 (void) do_dec_stat(Ind, A_DEX, DAM_STAT_TYPE(inv));
2966
2967 /* Take damage */
2968 // take_hit(Ind, dam, kb_str, Ind_attacker);
2969
2970 /* Inventory damage */
2971 if (!(p_ptr->oppose_elec && p_ptr->resist_elec) && breakable)
2972 inven_damage(Ind, set_elec_destroy, inv);
2973
2974 return(dam);
2975 }
2976
2977 /*
2978 * Hurt the player with Fire
2979 */
2980 int fire_dam(int Ind, int dam, cptr kb_str, int Ind_attacker)
2981 {
2982 player_type *p_ptr = Players[Ind];
2983
2984 int inv, hurt_eq;
2985
2986 dam -= p_ptr->reduc_fire * dam / 100;
2987
2988 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
2989
2990 hurt_eq = (dam < 30) ? 15 : (dam < 60) ? 33 : 100;
2991 if (p_ptr->resist_fire && p_ptr->oppose_fire) hurt_eq = (hurt_eq + 2) / 3;
2992 else if (p_ptr->resist_fire || p_ptr->oppose_fire) hurt_eq = (hurt_eq + 1) / 2;
2993
2994 /* Totally immune */
2995 if (p_ptr->immune_fire || (dam <= 0)) return(0);
2996
2997 /* Resist the damage */
2998 if (p_ptr->suscep_fire) dam = dam * 2;
2999 if (p_ptr->resist_fire) dam = (dam + 2) / 3;
3000 if (p_ptr->oppose_fire) dam = (dam + 2) / 3;
3001
3002 /* Don't kill inventory in bloodbond... */
3003 int breakable = 1;
3004 if (IS_PLAYER(Ind_attacker)) {
3005 if (check_blood_bond(Ind, Ind_attacker)) {
3006 breakable = 0;
3007 }
3008 }
3009
3010 if ((!(p_ptr->oppose_fire || p_ptr->resist_fire)) &&
3011 randint(HURT_CHANCE) == 1 && breakable)
3012 (void) do_dec_stat(Ind, A_STR, DAM_STAT_TYPE(inv));
3013
3014 if (magik(hurt_eq) && breakable) equip_damage(Ind, GF_FIRE);
3015
3016 /* Take damage */
3017 // take_hit(Ind, dam, kb_str, Ind_attacker);
3018
3019 /* Inventory damage */
3020 if (!(p_ptr->resist_fire && p_ptr->oppose_fire) && breakable)
3021 inven_damage(Ind, set_fire_destroy, inv);
3022
3023 return(dam);
3024 }
3025
3026 /*
3027 * Hurt the player with Cold
3028 */
3029 int cold_dam(int Ind, int dam, cptr kb_str, int Ind_attacker)
3030 {
3031 player_type *p_ptr = Players[Ind];
3032
3033 int inv;
3034
3035 dam -= p_ptr->reduc_cold * dam / 100;
3036
3037 inv = (dam < 30) ? 1 : (dam < 60) ? 2 : 3;
3038
3039 /* Total immunity */
3040 if (p_ptr->immune_cold || (dam <= 0)) return(0);
3041
3042 /* Resist the damage */
3043 if (p_ptr->suscep_cold) dam = dam * 2;
3044 if (p_ptr->resist_cold) dam = (dam + 2) / 3;
3045 if (p_ptr->oppose_cold) dam = (dam + 2) / 3;
3046
3047 /* Don't kill inventory in bloodbond... */
3048 int breakable = 1;
3049 if (IS_PLAYER(Ind_attacker)) {
3050 if (check_blood_bond(Ind, Ind_attacker)) {
3051 breakable = 0;
3052 }
3053 }
3054
3055 if ((!(p_ptr->oppose_cold || p_ptr->resist_cold)) &&
3056 randint(HURT_CHANCE) == 1 && breakable)
3057 (void) do_dec_stat(Ind, A_STR, DAM_STAT_TYPE(inv));
3058
3059 /* Take damage */
3060 // take_hit(Ind, dam, kb_str, Ind_attacker);
3061
3062 /* Inventory damage */
3063 if (!(p_ptr->resist_cold && p_ptr->oppose_cold) && breakable)
3064 inven_damage(Ind, set_cold_destroy, inv);
3065
3066 return(dam);
3067 }
3068
3069
3070
3071
3072
3073 /*
3074 * Increases a stat by one randomized level -RAK-
3075 *
3076 * Note that this function (used by stat potions) now restores
3077 * the stat BEFORE increasing it.
3078 */
3079 bool inc_stat(int Ind, int stat)
3080 {
3081 player_type *p_ptr = Players[Ind];
3082
3083 int value, gain;
3084
3085 /* Then augment the current/max stat */
3086 value = p_ptr->stat_cur[stat];
3087
3088 /* Cannot go above 18/100 */
3089 if (value < 18 + 100) {
3090 /* Gain one (sometimes two) points */
3091 if (value < 18) {
3092 gain = ((rand_int(100) < 75) ? 1 : 2);
3093 value += gain;
3094 }
3095 /* Gain 1/6 to 1/3 of distance to 18/100 */
3096 else if (value < 18+98) {
3097 /* Approximate gain value */
3098 gain = (((18+100) - value) / 2 + 3) / 2;
3099
3100 /* Paranoia */
3101 if (gain < 1) gain = 1;
3102
3103 /* 4 points at once is too much */
3104 if (gain > 17) gain = 17;
3105
3106 /* Apply the bonus */
3107 value += randint(gain) + gain / 2;
3108
3109 /* Maximal value */
3110 if (value > 18+99) value = 18 + 99;
3111 }
3112
3113 /* Gain one point at a time */
3114 else value++;
3115
3116 /* Save the new value */
3117 p_ptr->stat_cur[stat] = value;
3118
3119 /* Bring up the maximum too */
3120 if (value > p_ptr->stat_max[stat])
3121 p_ptr->stat_max[stat] = value;
3122
3123 /* Recalculate bonuses */
3124 p_ptr->update |= (PU_BONUS);
3125
3126 /* Success */
3127 return (TRUE);
3128 }
3129
3130 /* Nothing to gain */
3131 return (FALSE);
3132 }
3133
3134
3135
3136 /*
3137 * Decreases a stat by an amount indended to vary from 0 to 100 percent.
3138 *
3139 * Amount could be a little higher in extreme cases to mangle very high
3140 * stats from massive assaults. -CWS
3141 *
3142 * Note that "permanent" means that the *given* amount is permanent,
3143 * not that the new value becomes permanent. This may not work exactly
3144 * as expected, due to "weirdness" in the algorithm, but in general,
3145 * if your stat is already drained, the "max" value will not drop all
3146 * the way down to the "cur" value.
3147 */
3148 bool dec_stat(int Ind, int stat, int amount, int mode)
3149 {
3150 player_type *p_ptr = Players[Ind];
3151
3152 int cur, max, loss = 0, same, res = FALSE;
3153
3154 if (safe_area(Ind)) return(FALSE);
3155
3156 /* Acquire current value */
3157 cur = p_ptr->stat_cur[stat];
3158 max = p_ptr->stat_max[stat];
3159
3160 /* Note when the values are identical */
3161 same = (cur == max);
3162
3163 /* Damage "current" value */
3164 if (cur > 3) {
3165 /* Handle "low" values */
3166 if (cur <= 18) {
3167 if (amount > 90) loss++;
3168 if (amount > 50) loss++;
3169 if (amount > 20) loss++;
3170 loss++;
3171 cur -= loss;
3172 }
3173 /* Handle "high" values */
3174 else {
3175 /* Hack -- Decrement by a random amount between one-quarter */
3176 /* and one-half of the stat bonus times the percentage, with a */
3177 /* minimum damage of half the percentage. -CWS */
3178 loss = (((cur-18) / 2 + 1) / 2 + 1);
3179
3180 /* Paranoia */
3181 if (loss < 1) loss = 1;
3182
3183 /* Randomize the loss */
3184 loss = ((randint(loss) + loss) * amount) / 100;
3185
3186 /* Maximal loss */
3187 if (loss < amount/2) loss = amount/2;
3188
3189 /* Lose some points */
3190 cur = cur - loss;
3191
3192 /* Hack -- Only reduce stat to 17 sometimes */
3193 if (cur < 18) cur = (amount <= 20) ? 18 : 17;
3194 }
3195
3196 /* Prevent illegal values */
3197 if (cur < 3) cur = 3;
3198
3199 /* Something happened */
3200 if (cur != p_ptr->stat_cur[stat]) res = TRUE;
3201 }
3202
3203 /* Damage "max" value */
3204 if ((mode == STAT_DEC_PERMANENT) && (max > 3)) {
3205 /* Handle "low" values */
3206 if (max <= 18) {
3207 if (amount > 90) max--;
3208 if (amount > 50) max--;
3209 if (amount > 20) max--;
3210 max--;
3211 }
3212 /* Handle "high" values */
3213 else {
3214 /* Hack -- Decrement by a random amount between one-quarter */
3215 /* and one-half of the stat bonus times the percentage, with a */
3216 /* minimum damage of half the percentage. -CWS */
3217 loss = (((max-18) / 2 + 1) / 2 + 1);
3218 loss = ((randint(loss) + loss) * amount) / 100;
3219 if (loss < amount/2) loss = amount/2;
3220
3221 /* Lose some points */
3222 max = max - loss;
3223
3224 /* Hack -- Only reduce stat to 17 sometimes */
3225 if (max < 18) max = (amount <= 20) ? 18 : 17;
3226 }
3227
3228 /* Hack -- keep it clean */
3229 if (same || (max < cur)) max = cur;
3230
3231 /* Something happened */
3232 if (max != p_ptr->stat_max[stat]) res = TRUE;
3233 }
3234
3235 /* Apply changes */
3236 if (res) {
3237 /* Actually set the stat to its new value. */
3238 p_ptr->stat_cur[stat] = cur;
3239 p_ptr->stat_max[stat] = max;
3240
3241 if (mode == STAT_DEC_TEMPORARY) {
3242 u16b dectime;
3243
3244 /* a little crude, perhaps */
3245 dectime = rand_int(getlevel(&p_ptr->wpos)*50) + 50;
3246
3247 /* prevent overflow, stat_cnt = u16b */
3248 /* or add another temporary drain... */
3249 if ( ((p_ptr->stat_cnt[stat]+dectime)<p_ptr->stat_cnt[stat]) ||
3250 (p_ptr->stat_los[stat]>0) )
3251
3252 {
3253 p_ptr->stat_cnt[stat] += dectime;
3254 p_ptr->stat_los[stat] += loss;
3255 }
3256 else
3257 {
3258 p_ptr->stat_cnt[stat] = dectime;
3259 p_ptr->stat_los[stat] = loss;
3260 }
3261 }
3262
3263 /* Recalculate bonuses */
3264 //WIS drain -> Sanity changes; p_ptr->update |= (PU_BONUS); */
3265 p_ptr->update |= (PU_BONUS | PU_MANA | PU_HP | PU_SANITY);
3266 }
3267
3268 /* Done */
3269 return (res);
3270 }
3271
3272
3273 /*
3274 * Restore a stat. Return TRUE only if this actually makes a difference.
3275 */
3276 bool res_stat(int Ind, int stat)
3277 {
3278 player_type *p_ptr = Players[Ind];
3279
3280 /* temporary drain is gone */
3281 p_ptr->stat_los[stat] = 0;
3282 p_ptr->stat_cnt[stat] = 0;
3283
3284 /* Restore if needed */
3285 if (p_ptr->stat_cur[stat] != p_ptr->stat_max[stat])
3286 {
3287 /* Restore */
3288 p_ptr->stat_cur[stat] = p_ptr->stat_max[stat];
3289
3290 /* Recalculate bonuses */
3291 // p_ptr->update |= (PU_BONUS);
3292 p_ptr->update |= (PU_BONUS | PU_MANA | PU_HP | PU_SANITY);
3293
3294 /* Success */
3295 return (TRUE);
3296 }
3297
3298 /* Nothing to restore */
3299 return (FALSE);
3300 }
3301
3302
3303
3304
3305 /*
3306 * Apply disenchantment to the player's stuff
3307 *
3308 * XXX XXX XXX This function is also called from the "melee" code
3309 *
3310 *
3311 * If "mode is set to 0 then a random slot will be used, if not the "mode"
3312 * slot will be used.
3313 *
3314 * Return "TRUE" if the player notices anything
3315 */
3316 bool apply_disenchant(int Ind, int mode)
3317 {
3318 player_type *p_ptr = Players[Ind];
3319 int t = mode;
3320 object_type *o_ptr;
3321 char o_name[ONAME_LEN];
3322 u32b f1, f2, f3, f4, f5, f6, esp;
3323
3324 if (safe_area(Ind)) return(FALSE);
3325
3326 /* Unused */
3327 // mode = mode;
3328
3329 if(!mode) mode = randint(9);
3330 else if(mode < 1 || mode > 9) return (FALSE);
3331
3332 /* Pick a random slot */
3333 switch (mode) {
3334 case 1: t = INVEN_WIELD; break;
3335 case 2: t = INVEN_BOW; break;
3336 case 3: t = INVEN_BODY; break;
3337 case 4: t = INVEN_OUTER; break;
3338 case 5: t = INVEN_ARM; break;
3339 case 6: t = INVEN_HEAD; break;
3340 case 7: t = INVEN_HANDS; break;
3341 case 8: t = INVEN_FEET; break;
3342 case 9: t = INVEN_AMMO; break;
3343 }
3344
3345 /* Get the item */
3346 o_ptr = &p_ptr->inventory[t];
3347
3348 /* No item, nothing happens */
3349 if (!o_ptr->k_idx) return (FALSE);
3350
3351 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
3352
3353 /* Describe the object */
3354 object_desc(Ind, o_name, o_ptr, FALSE, 0);
3355
3356 /* Special treatment for new ego-type: Ethereal (ammunition):
3357 Ethereal items don't get disenchanted, but rather disappear completely! */
3358 if (o_ptr->name2 == EGO_ETHEREAL || o_ptr->name2b == EGO_ETHEREAL) {
3359 int i = randint(o_ptr->number / 5);
3360 if (!i) i = 1;
3361 msg_format(Ind, "\376\377o%s of your %s (%c) %s away!",
3362 (o_ptr->number == i ? "All" : (i != 1 ? "Some" : "One")), o_name, index_to_label(t),
3363 ((i != 1) ? "fade" : "fades"));
3364 inven_item_increase(Ind, t, -i);
3365 inven_item_optimize(Ind, t);
3366 /* Recalculate bonuses */
3367 p_ptr->update |= (PU_BONUS);
3368 /* Window stuff */
3369 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
3370 /* Notice */
3371 return (TRUE);
3372 }
3373
3374 /* Nothing to disenchant */
3375 if ((o_ptr->to_h <= 0) && (o_ptr->to_d <= 0) && (o_ptr->to_a <= 0)) {
3376 /* Nothing to notice */
3377 return (FALSE);
3378 }
3379
3380 if ((f2 & TR2_RES_DISEN) || (f5 & TR5_IGNORE_DISEN)) {
3381 msg_format(Ind, "Your %s (%c) %s unaffected!",
3382 o_name, index_to_label(t),
3383 ((o_ptr->number != 1) ? "are" : "is"));
3384 /* Notice */
3385 return (TRUE);
3386 }
3387
3388 /* Artifacts have 70%(randart) or 80%(trueart) chance to resist */
3389 if ((artifact_p(o_ptr) && (rand_int(100) < 70)) ||
3390 (true_artifact_p(o_ptr) && (rand_int(100) < 80))) {
3391 /* Message */
3392 msg_format(Ind, "Your %s (%c) resist%s!",
3393 o_name, index_to_label(t),
3394 ((o_ptr->number != 1) ? "" : "s"));
3395
3396 /* Notice */
3397 return (TRUE);
3398 }
3399
3400 /* Disenchant tohit */
3401 if (o_ptr->to_h > 0) {
3402 if (o_ptr->to_h > 0) o_ptr->to_h--;
3403 if ((o_ptr->to_h > 7) && (rand_int(100) < 33)) o_ptr->to_h--;
3404 if ((o_ptr->to_h > 15) && (rand_int(100) < 25)) o_ptr->to_h--;
3405 }
3406 /* Disenchant todam */
3407 if (o_ptr->to_d > 0) {
3408 if (o_ptr->to_d > 0) o_ptr->to_d--;
3409 if ((o_ptr->to_d > 7) && (rand_int(100) < 33)) o_ptr->to_d--;
3410 if ((o_ptr->to_d > 15) && (rand_int(100) < 25)) o_ptr->to_d--;
3411 }
3412 /* Disenchant toac */
3413 if (o_ptr->to_a > 0) {
3414 if (o_ptr->to_a > 0) o_ptr->to_a--;
3415 if ((o_ptr->to_a > 7) && (rand_int(100) < 33)) o_ptr->to_a--;
3416 if ((o_ptr->to_a > 15) && (rand_int(100) < 25)) o_ptr->to_a--;
3417 }
3418 /* Message */
3419 msg_format(Ind, "\376\377oYour %s (%c) %s disenchanted!",
3420 o_name, index_to_label(t),
3421 ((o_ptr->number != 1) ? "were" : "was"));
3422
3423 /* Recalculate bonuses */
3424 p_ptr->update |= (PU_BONUS);
3425
3426 /* Window stuff */
3427 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
3428
3429 /* ? */
3430 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
3431
3432 /* Notice */
3433 return (TRUE);
3434 }
3435
3436
3437 /*
3438 * Apply 'discharging' ie electricity damage to the player's stuff - C. Blue
3439 * the reason for adding this is, to bring electricity on par with other base elements.
3440 *
3441 * Return "TRUE" if the player notices anything
3442 */
3443 bool apply_discharge(int Ind, int dam)
3444 {
3445 player_type *p_ptr = Players[Ind];
3446
3447 int i, chance = 95;
3448 bool damaged_any = FALSE, damaged;
3449 object_type *o_ptr;
3450 char o_name[ONAME_LEN];
3451 u32b fx, f2, f3;
3452
3453 if (safe_area(Ind)) return(FALSE);
3454
3455 if ((p_ptr->oppose_elec && p_ptr->resist_elec) ||
3456 p_ptr->immune_elec) return(FALSE);
3457
3458 /* note: used same values as in elec_dam */
3459 if (dam >= 30) chance -= 10;
3460 if (dam >= 60) chance -= 10;
3461
3462 /* Scan through the slots backwards */
3463 // for (i = 0; i < INVEN_PACK; i++)
3464 for (i = 0; i < INVEN_TOTAL; i++) /* Let's see what will happen.. */
3465 {
3466 /* Hack -- equipments are harder to be harmed */
3467 if (i >= INVEN_PACK && i != INVEN_AMMO && !magik(HARM_EQUIP_CHANCE))
3468 continue;
3469
3470 /* Get the item */
3471 o_ptr = &p_ptr->inventory[i];
3472 /* No item, nothing happens */
3473 if (!o_ptr->k_idx) return (FALSE);
3474
3475 if (magik(chance)) continue;
3476 // if (o_ptr->tval == TV_AMULET && magik(50)) continue; /* further reduce chance? */
3477
3478 object_flags(o_ptr, &fx, &f2, &f3, &fx, &fx, &fx, &fx);
3479
3480 /* Hack -- for now, skip artifacts */
3481 if (artifact_p(o_ptr) ||
3482 (f3 & TR3_IGNORE_ELEC) ||
3483 (f2 & TR2_IM_ELEC) ||
3484 (f2 & TR2_RES_ELEC)) continue;
3485
3486 damaged = FALSE;
3487
3488 /* Get the item in that slot */
3489 o_ptr = &p_ptr->inventory[i];
3490
3491 /* Describe the object */
3492 object_desc(Ind, o_name, o_ptr, FALSE, 0);
3493
3494 /* damage it */
3495 if (o_ptr->tval != TV_ROD && o_ptr->tval != TV_LITE && o_ptr->tval != TV_POTION && o_ptr->tval != TV_FOOD) {
3496 if (o_ptr->timeout) damaged = TRUE;
3497 if (o_ptr->timeout > 1000) o_ptr->timeout -= 80 + rand_int(41);
3498 else if (o_ptr->timeout > 100) o_ptr->timeout -= 15 + rand_int(11);
3499 else if (o_ptr->timeout > 10) o_ptr->timeout -= 3 + rand_int(3);
3500 else if (o_ptr->timeout) o_ptr->timeout--;
3501 } else if (o_ptr->tval == TV_ROD) {
3502 if (o_ptr->pval < 30000) {
3503 o_ptr->pval += 5;
3504 damaged = TRUE;
3505 }
3506 }
3507
3508 if (o_ptr->pval) switch (o_ptr->tval) {
3509 case TV_AMULET: if (o_ptr->pval < 2) break; /* stop at +1 */
3510 case TV_STAFF:
3511 case TV_WAND:
3512 o_ptr->pval--;
3513 damaged = TRUE;
3514 break;
3515 } else if (o_ptr->bpval > 1 && o_ptr->tval == TV_AMULET) {
3516 o_ptr->bpval--;
3517 damaged = TRUE;
3518 }
3519
3520 /* Special treatment for new ego-type: Ethereal (ammunition): */
3521 if (is_ammo(o_ptr->tval) && (o_ptr->name2 == EGO_ETHEREAL || o_ptr->name2b == EGO_ETHEREAL)) {
3522 msg_format(Ind, "\376\377o%s %s (%c) fades away!",
3523 o_ptr->number == 1 ? "Your" : "One of your", o_name, index_to_label(i));
3524 inven_item_increase(Ind, i, -1);
3525 inven_item_optimize(Ind, i);
3526 p_ptr->update |= (PU_BONUS);
3527 damaged_any = TRUE;
3528 }
3529 /* Message */
3530 else if (damaged) {
3531 msg_format(Ind, "\376\377oYour %s (%c) %s discharged!",
3532 o_name, index_to_label(i), ((o_ptr->number != 1) ? "were" : "was"));
3533 damaged_any = TRUE;
3534 }
3535 }
3536
3537 /* Window stuff */
3538 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
3539
3540 /* ? */
3541 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
3542
3543 return (damaged_any);
3544 }
3545 bool apply_discharge_item(int o_idx, int dam)
3546 {
3547 int chance = 95;
3548 bool damaged = FALSE;
3549 object_type *o_ptr = &o_list[o_idx];
3550 u32b fx, f2, f3;
3551
3552 /* No item, nothing happens */
3553 if (!o_ptr->k_idx) return (FALSE);
3554
3555 /* note: used same values as in elec_dam */
3556 if (dam >= 30) chance -= 10;
3557 if (dam >= 60) chance -= 10;
3558
3559 if (magik(chance)) return(FALSE);
3560 // if (o_ptr->tval == TV_AMULET && magik(50)) return(FALSE); /* further reduce chance? */
3561
3562 object_flags(o_ptr, &fx, &f2, &f3, &fx, &fx, &fx, &fx);
3563
3564 /* Hack -- for now, skip artifacts */
3565 if (artifact_p(o_ptr) ||
3566 (f3 & TR3_IGNORE_ELEC) ||
3567 (f2 & TR2_IM_ELEC) ||
3568 (f2 & TR2_RES_ELEC)) return(FALSE);
3569
3570 /* damage it */
3571 if (o_ptr->tval != TV_ROD && o_ptr->tval != TV_LITE && o_ptr->tval != TV_POTION && o_ptr->tval != TV_FOOD) {
3572 if (o_ptr->timeout) damaged = TRUE;
3573 if (o_ptr->timeout > 1000) o_ptr->timeout -= 80 + rand_int(41);
3574 else if (o_ptr->timeout > 100) o_ptr->timeout -= 15 + rand_int(11);
3575 else if (o_ptr->timeout > 10) o_ptr->timeout -= 3 + rand_int(3);
3576 else if (o_ptr->timeout) o_ptr->timeout--;
3577 } else if (o_ptr->tval == TV_ROD) {
3578 if (o_ptr->pval < 30000) {
3579 o_ptr->pval += 5;
3580 damaged = TRUE;
3581 }
3582 }
3583
3584 if (o_ptr->pval) switch (o_ptr->tval) {
3585 case TV_AMULET: if (o_ptr->pval < 2) break; /* stop at +1 */
3586 case TV_STAFF:
3587 case TV_WAND:
3588 o_ptr->pval--;
3589 damaged = TRUE;
3590 break;
3591 } else if (o_ptr->bpval > 1 && o_ptr->tval == TV_AMULET) {
3592 o_ptr->bpval--;
3593 damaged = TRUE;
3594 }
3595
3596 /* Special treatment for new ego-type: Ethereal (ammunition): */
3597 if (is_ammo(o_ptr->tval) && (o_ptr->name2 == EGO_ETHEREAL || o_ptr->name2b == EGO_ETHEREAL)) {
3598 if (o_ptr->number == 1) delete_object_idx(o_idx, TRUE);
3599 else o_ptr->number--;
3600 damaged = TRUE;
3601 }
3602
3603 return (damaged);
3604 }
3605
3606
3607 /*
3608 * Apply Nexus
3609 */
3610 static void apply_nexus(int Ind, monster_type *m_ptr, int Ind_attacker)
3611 {
3612 player_type *p_ptr = Players[Ind];
3613 int max1, cur1, max2, cur2, ii, jj;
3614
3615 int chance = (195 - p_ptr->skill_sav) / 2;
3616 if (p_ptr->res_tele) chance = 50;
3617
3618 if (p_ptr->martyr) return;
3619
3620 if (IS_PLAYER(Ind_attacker))
3621 s_printf("APPLY_NEXUS_PY: %s by %s\n", p_ptr->name, Players[Ind_attacker]->name);
3622
3623 switch (randint((safe_area(Ind) || (p_ptr->mode & MODE_PVP)) ? 5 : 8)) { /* don't do baaad things in Monster Arena Challenge */
3624 case 4: case 5:
3625 {
3626 if (p_ptr->anti_tele || magik(chance))
3627 {
3628 msg_print(Ind, "You resist the effects!");
3629 break;
3630 }
3631
3632 if (m_ptr)
3633 teleport_player_to(Ind, m_ptr->fy, m_ptr->fx);
3634 else
3635 teleport_player(Ind, 200, TRUE);
3636 break;
3637 }
3638
3639 case 1: case 2: case 3:
3640 {
3641 if (p_ptr->anti_tele || magik(chance))
3642 {
3643 msg_print(Ind, "You resist the effects!");
3644 break;
3645 }
3646
3647 teleport_player(Ind, 200, TRUE);
3648 break;
3649 }
3650
3651 case 6:
3652 {
3653 if (rand_int(100) < p_ptr->skill_sav || magik(chance))
3654 {
3655 msg_print(Ind, "You resist the effects!");
3656 break;
3657 }
3658
3659 /* Teleport Level */
3660 teleport_player_level(Ind, FALSE);
3661 break;
3662 }
3663
3664 case 7:
3665 {
3666 if (rand_int(100) < p_ptr->skill_sav)
3667 {
3668 msg_print(Ind, "You resist the effects!");
3669 break;
3670 }
3671
3672 msg_print(Ind, "\376\377oYour body starts to scramble...");
3673 s_printf("NEXUS_SCRAMBLE: %s\n", p_ptr->name);
3674
3675 /* Pick a pair of stats */
3676 ii = rand_int(6);
3677 for (jj = ii; jj == ii; jj = rand_int(6)) /* loop */;
3678
3679 max1 = p_ptr->stat_max[ii];
3680 cur1 = p_ptr->stat_cur[ii];
3681 max2 = p_ptr->stat_max[jj];
3682 cur2 = p_ptr->stat_cur[jj];
3683
3684 p_ptr->stat_max[ii] = max2;
3685 p_ptr->stat_cur[ii] = cur2;
3686 p_ptr->stat_max[jj] = max1;
3687 p_ptr->stat_cur[jj] = cur1;
3688
3689 p_ptr->update |= (PU_BONUS | PU_MANA | PU_HP | PU_SANITY);
3690
3691 break;
3692 }
3693
3694 case 8:
3695 {
3696 if (check_st_anchor(&p_ptr->wpos, p_ptr->py, p_ptr->px)) break;
3697 if (p_ptr->anti_tele || magik(chance))
3698 {
3699 msg_print(Ind, "You resist the effects!");
3700 break;
3701 }
3702
3703 msg_print(Ind, "\376\377oYour backpack starts to scramble...");
3704
3705 if(m_ptr){
3706 ii = 10 + m_ptr->level / 3;
3707 if (ii > 50) ii = 50;
3708 }
3709 else
3710 ii = 25;
3711
3712 do_player_scatter_items(Ind, 5, ii);
3713
3714 break;
3715 }
3716 }
3717 }
3718
3719
3720 /*
3721 * Apply Polymorph
3722 */
3723
3724 /* Ho Ho Ho... I really want this to have a chance of turning people into
3725 a fruit bat, but something tells me I should put that off until the next version...
3726
3727 I CANT WAIT. DOING FRUIT BAT RIGHT NOW!!!
3728 -APD-
3729 */
3730 static void apply_morph(int Ind, int power, char * killer, int Ind_attacker)
3731 {
3732 player_type *p_ptr = Players[Ind];
3733 #if 0
3734 int max1, cur1, max2, cur2, ii, jj;
3735 #endif
3736
3737 if (p_ptr->martyr) return;
3738
3739 if (IS_PLAYER(Ind_attacker))
3740 s_printf("APPLY_MORPH_PY: %s by %s\n", p_ptr->name, Players[Ind_attacker]->name);
3741
3742 switch (randint(2)) {
3743 #if 1
3744 case 1: msg_print(Ind, "You resist the effects!");
3745 break;
3746 #else
3747 case 1:
3748 if (rand_int(40 + power*2) < p_ptr->skill_sav) {
3749 msg_print(Ind, "You resist the effects!");
3750 break;
3751 }
3752
3753 msg_print(Ind, "\376\377oYour body starts to scramble...");
3754 s_printf("MORPH_SCRAMBLE: %s\n", p_ptr->name);
3755
3756 /* Pick a pair of stats */
3757 ii = rand_int(6);
3758 for (jj = ii; jj == ii; jj = rand_int(6)) /* loop */;
3759
3760 max1 = p_ptr->stat_max[ii];
3761 cur1 = p_ptr->stat_cur[ii];
3762 max2 = p_ptr->stat_max[jj];
3763 cur2 = p_ptr->stat_cur[jj];
3764
3765 p_ptr->stat_max[ii] = max2;
3766 p_ptr->stat_cur[ii] = cur2;
3767 p_ptr->stat_max[jj] = max1;
3768 p_ptr->stat_cur[jj] = cur1;
3769
3770 p_ptr->update |= (PU_BONUS | PU_HP | PU_MANA | PU_SANITY);
3771
3772 break;
3773 #endif
3774 case 2:
3775 if (!p_ptr->fruit_bat) {
3776 if (rand_int(10 + power * 4) < p_ptr->skill_sav) {
3777 msg_print(Ind, "You resist the effects!");
3778 } else {
3779 s_printf("MORPH_FRUITBAT: %s\n", p_ptr->name);
3780 /* FRUIT BAT!!!!!! */
3781 if (p_ptr->body_monster) do_mimic_change(Ind, 0, TRUE);
3782 msg_print(Ind, "\377yYou have been turned into a fruit bat!");
3783 strcpy(p_ptr->died_from, killer);
3784 strcpy(p_ptr->really_died_from, killer);
3785 p_ptr->fruit_bat = -1;
3786 p_ptr->deathblow = 0;
3787 player_death(Ind);
3788 }
3789 } else if (p_ptr->fruit_bat == 2) {
3790 /* no saving throw for being restored..... */
3791 msg_print(Ind, "You have been restored!");
3792 p_ptr->fruit_bat = 0;
3793 p_ptr->update |= (PU_BONUS | PU_HP);
3794 } else {
3795 msg_print(Ind, "You feel certain you are a fruit bat!");
3796 }
3797 }
3798 }
3799
3800
3801
3802 /* For project_..():
3803 Decrease the damage over the radius. */
3804 static int radius_damage(int dam, int div, int typ) {
3805 switch (typ) {
3806 /* When these are cast as 'ball spells' they'd be gimped too much probably: */
3807 case GF_TELEPORT_PLAYER: //Kurzel - This and many others (buffs) could go here (pending approval..)!
3808 case GF_OLD_SLOW:
3809 case GF_OLD_CONF:
3810 case GF_OLD_SLEEP:
3811 case GF_TURN_ALL:
3812
3813 /* These must not be reduced, since 'dam' stores the functionality */
3814 case GF_RECALL_PLAYER: /* not for recall (dam is timeout) - mikaelh */
3815 case GF_CURE_PLAYER:
3816 case GF_RESTORE_PLAYER:
3817 case GF_CURING:
3818 case GF_RESURRECT_PLAYER:
3819
3820 return (dam);
3821 }
3822
3823 /* default: half damage per grid of distance */
3824 return (dam / div);
3825 }
3826
3827
3828
3829 /*
3830 * Hack -- track "affected" monsters
3831 */
3832 static int project_m_n;
3833 static int project_m_x;
3834 static int project_m_y;
3835
3836
3837
3838 /*
3839 * We are called from "project()" to "damage" terrain features
3840 *
3841 * We are called both for "beam" effects and "ball" effects.
3842 *
3843 * The "r" parameter is the "distance from ground zero".
3844 *
3845 * Note that we determine if the player can "see" anything that happens
3846 * by taking into account: blindness, line-of-sight, and illumination.
3847 *
3848 * We return "TRUE" if the effect of the projection is "obvious".
3849 *
3850 * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
3851 *
3852 * XXX XXX XXX Perhaps we should affect doors?
3853 */
3854 static bool project_f(int Ind, int who, int r, struct worldpos *wpos, int y, int x, int dam, int typ) {
3855 bool obvious = FALSE;
3856 // bool quiet = ((Ind <= 0) ? TRUE : FALSE);
3857 bool quiet = ((Ind <= 0 || who <= PROJECTOR_UNUSUAL) ? TRUE : FALSE);
3858 int div;
3859
3860 player_type *p_ptr = (quiet ? NULL : Players[Ind]);
3861
3862 byte *w_ptr = (quiet ? NULL : &p_ptr->cave_flag[y][x]);
3863 cave_type *c_ptr;
3864 cave_type **zcave;
3865
3866
3867 if (!(zcave = getcave(wpos))) return(FALSE);
3868 c_ptr = &zcave[y][x];
3869
3870 /* Extract radius */
3871 div = r + 1;
3872 /* Decrease damage */
3873 dam = radius_damage(dam, div, typ);
3874
3875 /* XXX XXX */
3876 who = who ? who : 0;
3877
3878
3879 /* Analyze the type */
3880 switch (typ) {
3881 /* Ignore most effects */
3882 case GF_ACID:
3883 if (!allow_terraforming(wpos, FEAT_TREE)) break;
3884 /* Destroy trees */
3885 if (c_ptr->feat == FEAT_TREE || c_ptr->feat == FEAT_BUSH) {
3886 #if 0 /* no msg spam maybe */
3887 /* Hack -- special message */
3888 if (!quiet && player_can_see_bold(Ind, y, x)) {
3889 msg_print(Ind, "The tree decays!");
3890 /* Notice */
3891 note_spot(Ind, y, x);
3892 obvious = TRUE;
3893 }
3894 #endif
3895 /* Destroy the tree */
3896 cave_set_feat_live(wpos, y, x, FEAT_DEAD_TREE);
3897 }
3898
3899 /* Burn grass et al */
3900 if (c_ptr->feat == FEAT_GRASS || c_ptr->feat == FEAT_IVY ||
3901 c_ptr->feat == FEAT_WEB ||
3902 c_ptr->feat == FEAT_CROP || c_ptr->feat == FEAT_FLOWER /* :( */)
3903 cave_set_feat_live(wpos, y, x, FEAT_DIRT);//(was FEAT_MUD) or maybe FEAT_ASH?
3904
3905 break;
3906
3907 case GF_NUKE:
3908 if (!allow_terraforming(wpos, FEAT_TREE)) break;
3909 /* damage organic material */
3910 if (c_ptr->feat == FEAT_GRASS || c_ptr->feat == FEAT_IVY ||
3911 /*c_ptr->feat == FEAT_WEB ||*/
3912 c_ptr->feat == FEAT_CROP || c_ptr->feat == FEAT_FLOWER /* :( */)
3913 cave_set_feat_live(wpos, y, x, FEAT_DIRT);
3914 break;
3915
3916 case GF_ICE:
3917 case GF_ICEPOISON:
3918 case GF_SHARDS:
3919 case GF_FORCE:
3920 if (!allow_terraforming(wpos, FEAT_TREE)) break;
3921 /* Shred certain feats */
3922 if (c_ptr->feat == FEAT_WEB || c_ptr->feat == FEAT_FLOWER /* :( */)
3923 cave_set_feat_live(wpos, y, x, FEAT_DIRT);
3924 break;
3925 case GF_ELEC:
3926 case GF_COLD:
3927 case GF_THUNDER: /* a gestalt now, to remove hacky tri-bolt on thunderstorm */
3928 case GF_SOUND:
3929 case GF_MANA: /* <- no web/flower destructing abilities at this time? :-p */
3930 case GF_HOLY_ORB:
3931 case GF_CURSE: /* new spell - the_sandman */
3932 /* Druidry: */
3933 case GF_HEALINGCLOUD:
3934 break;
3935
3936 case GF_EARTHQUAKE:
3937 earthquake(wpos, y, x, 0);
3938 break;
3939
3940 case GF_STONE_WALL:
3941 /* Require a "naked" floor grid */
3942 if (!cave_naked_bold(zcave, y, x)) break;
3943 if (!allow_terraforming(wpos, FEAT_WALL_EXTRA)) break;
3944 /* Beware of the houses in town */
3945 if ((wpos->wz == 0) && (zcave[y][x].info & CAVE_ICKY)) break;
3946 /* Not if it's an open house door - mikaelh */
3947 if (c_ptr->feat == FEAT_HOME_OPEN) break;
3948
3949 /* Place a wall */
3950 if (c_ptr->feat != FEAT_WALL_EXTRA) c_ptr->info &= ~CAVE_NEST_PIT; /* clear teleport protection for nest grid if changed */
3951 cave_set_feat_live(wpos, y, x, FEAT_WALL_EXTRA);
3952
3953 /* Notice */
3954 if (!quiet) note_spot(Ind, y, x);
3955 /* Redraw */
3956 everyone_lite_spot(wpos, y, x);
3957 break;
3958
3959 /* Burn trees and grass */
3960 case GF_HOLY_FIRE:
3961 if (!allow_terraforming(wpos, FEAT_TREE)) break;
3962 /* Holy Fire doesn't destroy trees! */
3963 /* spider webs (Cirith Ungol!) */
3964 if (c_ptr->feat == FEAT_WEB)
3965 cave_set_feat_live(wpos, y, x, FEAT_ASH);
3966
3967 #if 1 /* FEAT_ICE_WALL are tunneable, so probably no harm in making them meltable too */
3968 if (c_ptr->feat == FEAT_ICE_WALL && !rand_int((410 - (dam < 370 ? dam : 370)) / 4))
3969 cave_set_feat_live(wpos, y, x, FEAT_SHAL_WATER);
3970 #endif
3971 break;
3972
3973 case GF_FIRE:
3974 case GF_METEOR:
3975 case GF_PLASMA:
3976 case GF_HELL_FIRE:
3977 case GF_INFERNO:
3978 //GF_DETONATION and GF_ROCKET disintegrate anyway
3979 if (!allow_terraforming(wpos, FEAT_TREE)) break;
3980 /* Destroy trees */
3981 if (c_ptr->feat == FEAT_TREE ||
3982 c_ptr->feat == FEAT_BUSH ||
3983 c_ptr->feat == FEAT_DEAD_TREE) {
3984 #if 0 /* no need for message spam maybe - and spot is note'd in cave_set_feat_live already */
3985 /* Hack -- special message */
3986 if (!quiet && player_can_see_bold(Ind, y, x)) {
3987 msg_print(Ind, "The tree burns to the ground!");
3988 /* Notice */
3989 note_spot(Ind, y, x);
3990 obvious = TRUE;
3991 }
3992 #endif
3993 /* Destroy the tree */
3994 cave_set_feat_live(wpos, y, x, FEAT_ASH);
3995 }
3996
3997 /* Burn grass, spider webs (Cirith Ungol!) and more.. */
3998 if (c_ptr->feat == FEAT_GRASS || c_ptr->feat == FEAT_IVY ||
3999 c_ptr->feat == FEAT_WEB ||
4000 c_ptr->feat == FEAT_CROP || c_ptr->feat == FEAT_FLOWER /* :( */)
4001 cave_set_feat_live(wpos, y, x, FEAT_ASH);
4002
4003 /* misc flavour: turn mud to dirt and/or shallow water into nothing (steam)? */
4004 //if (c_ptr->feat == FEAT_MUD) cave_set_feat_live(wpos, y, x, FEAT_DIRT);
4005 if (c_ptr->feat == FEAT_SHAL_WATER) cave_set_feat_live(wpos, y, x, FEAT_MUD);
4006
4007 #if 1 /* FEAT_ICE_WALL are tunneable, so probably no harm in making them meltable too */
4008 if (c_ptr->feat == FEAT_ICE_WALL && !rand_int((410 - (dam < 370 ? dam : 370)) / 4))
4009 cave_set_feat_live(wpos, y, x, FEAT_SHAL_WATER);
4010 #endif
4011 break;
4012
4013 /* Destroy Traps (and Locks) */
4014 case GF_KILL_TRAP:
4015 {
4016 struct c_special *cs_ptr;
4017 /* Destroy invisible traps */
4018 // if (c_ptr->feat == FEAT_INVIS)
4019 if ((cs_ptr = GetCS(c_ptr, CS_TRAPS))) {
4020 /* Hack -- special message */
4021 if (!quiet && player_can_see_bold(Ind, y, x)) {
4022 msg_print(Ind, "There is a bright flash of light!");
4023 obvious = TRUE;
4024 }
4025
4026 /* Destroy the trap */
4027 // c_ptr->feat = FEAT_FLOOR;
4028 cs_erase(c_ptr, cs_ptr);
4029
4030 if (!quiet) {
4031 /* Notice */
4032 note_spot(Ind, y, x);
4033
4034 /* Redraw */
4035 if (c_ptr->o_idx && !c_ptr->m_idx)
4036 /* Make sure no traps are displayed on the screen anymore - mikaelh */
4037 everyone_clear_ovl_spot(wpos, y, x);
4038 else
4039 everyone_lite_spot(wpos, y, x);
4040 }
4041 }
4042
4043 /* Secret / Locked doors are found and unlocked */
4044 else if ((c_ptr->feat == FEAT_SECRET) ||
4045 ((c_ptr->feat >= FEAT_DOOR_HEAD + 0x01) &&
4046 (c_ptr->feat <= FEAT_DOOR_HEAD + 0x07))) {
4047 /* Notice */
4048 if (!quiet && (*w_ptr & CAVE_MARK)) {
4049 msg_print(Ind, "Click!");
4050 obvious = TRUE;
4051 }
4052
4053 /* Unlock the door */
4054 c_ptr->feat = FEAT_DOOR_HEAD + 0x00;
4055
4056 /* Clear mimic feature */
4057 if ((cs_ptr = GetCS(c_ptr, CS_MIMIC)))
4058 cs_erase(c_ptr, cs_ptr);
4059
4060 if (!quiet) {
4061 /* Notice */
4062 note_spot(Ind, y, x);
4063
4064 /* Redraw */
4065 if (c_ptr->o_idx && !c_ptr->m_idx)
4066 /* Make sure no traps are displayed on the screen anymore - mikaelh */
4067 everyone_clear_ovl_spot(wpos, y, x);
4068 else
4069 everyone_lite_spot(wpos, y, x);
4070 }
4071 }
4072
4073 break;
4074 }
4075
4076 /* Destroy Doors (and traps) */
4077 case GF_KILL_DOOR:
4078 {
4079 byte feat = twall_erosion(wpos, y, x);
4080 struct c_special *cs_ptr;
4081
4082 /* Destroy invisible traps */
4083 // if (c_ptr->feat == FEAT_INVIS)
4084 if ((cs_ptr = GetCS(c_ptr, CS_TRAPS))) {
4085 /* Hack -- special message */
4086 if (!quiet && player_can_see_bold(Ind, y, x)) {
4087 msg_print(Ind, "There is a bright flash of light!");
4088 obvious = TRUE;
4089 }
4090
4091 /* Destroy the feature */
4092 // c_ptr->feat = FEAT_FLOOR;
4093 cs_erase(c_ptr, cs_ptr);
4094
4095 /* Forget the wall */
4096 everyone_forget_spot(wpos, y, x);
4097
4098 if (!quiet) {
4099 /* Notice */
4100 note_spot(Ind, y, x);
4101
4102 /* Redraw */
4103 if (c_ptr->o_idx && !c_ptr->m_idx)
4104 /* Make sure no traps are displayed on the screen anymore - mikaelh */
4105 everyone_clear_ovl_spot(wpos, y, x);
4106 else
4107 everyone_lite_spot(wpos, y, x);
4108 }
4109 }
4110
4111 /* Destroy all visible traps and open doors */
4112 if ((c_ptr->feat == FEAT_OPEN) ||
4113 (c_ptr->feat == FEAT_BROKEN)) {
4114 /* Hack -- special message */
4115 if (!quiet && (*w_ptr & CAVE_MARK)) {
4116 msg_print(Ind, "There is a bright flash of light!");
4117 obvious = TRUE;
4118 }
4119
4120 /* Destroy the feature */
4121 cave_set_feat_live(wpos, y, x, feat);
4122 /* Forget the wall */
4123 everyone_forget_spot(wpos, y, x);
4124
4125 if (!quiet) {
4126 /* Notice */
4127 note_spot(Ind, y, x);
4128
4129 /* Redraw */
4130 if (c_ptr->o_idx && !c_ptr->m_idx)
4131 /* Make sure no traps are displayed on the screen anymore - mikaelh */
4132 everyone_clear_ovl_spot(wpos, y, x);
4133 else
4134 everyone_lite_spot(wpos, y, x);
4135 }
4136 }
4137
4138 /* Destroy all closed doors */
4139 if ((c_ptr->feat >= FEAT_DOOR_HEAD) &&
4140 (c_ptr->feat <= FEAT_DOOR_TAIL)) {
4141 /* Hack -- special message */
4142 if (!quiet && (*w_ptr & CAVE_MARK)) {
4143 msg_print(Ind, "There is a bright flash of light!");
4144 obvious = TRUE;
4145 }
4146
4147 /* Destroy the feature */
4148 cave_set_feat_live(wpos, y, x, feat);
4149
4150 /* Forget the wall */
4151 everyone_forget_spot(wpos, y, x);
4152
4153 if (!quiet) {
4154 /* Notice */
4155 note_spot(Ind, y, x);
4156
4157 /* Redraw */
4158 everyone_lite_spot(wpos, y, x);
4159
4160 /* Update some things */
4161 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
4162 }
4163 }
4164 break;
4165 }
4166
4167 /* Destroy walls (and doors) */
4168 case GF_KILL_WALL:
4169 {
4170 byte feat = twall_erosion(wpos, y, x);
4171
4172 if (!allow_terraforming(wpos, FEAT_TREE)) break;
4173 /* Non-walls (etc) */
4174 if (cave_los(zcave, y, x)) break;
4175 /* Permanent walls */
4176 if ((c_ptr->feat >= FEAT_PERM_EXTRA || c_ptr->feat == FEAT_PERM_CLEAR)
4177 && !(c_ptr->feat >= FEAT_SANDWALL && c_ptr->feat <= FEAT_SANDWALL_K)) break;
4178
4179 /* the_sandman: sandwalls are stm-able too? */
4180 /* fixed it and also added the treasures in sandwalls - mikaelh */
4181 /* Sandwall */
4182 if (c_ptr->feat == FEAT_SANDWALL) {
4183 /* Message */
4184 if (!quiet && (*w_ptr & CAVE_MARK)) {
4185 msg_print(Ind, "The sandwall collapses!");
4186 obvious = TRUE;
4187 }
4188
4189 /* Destroy the wall */
4190 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_SAND : feat);
4191 }
4192 /* Sandwall with treasure */
4193 else if (c_ptr->feat == FEAT_SANDWALL_H || c_ptr->feat == FEAT_SANDWALL_K) {
4194 /* Message */
4195 if (!quiet && (*w_ptr & CAVE_MARK)) {
4196 msg_print(Ind, "The sandwall collapses!");
4197 if (!istown(wpos)) msg_print(Ind, "You have found something!");
4198 obvious = TRUE;
4199 }
4200
4201 /* Destroy the wall */
4202 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_SAND : feat);
4203
4204 /* Place some gold */
4205 if (!istown(wpos)) place_gold(wpos, y, x, 0);
4206 }
4207 /* Granite */
4208 else if (c_ptr->feat >= FEAT_WALL_EXTRA) {
4209 /* Message */
4210 if (!quiet && (*w_ptr & CAVE_MARK)) {
4211 msg_print(Ind, "The wall turns into mud!");
4212 obvious = TRUE;
4213 }
4214
4215 /* Destroy the wall */
4216 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_MUD : feat);
4217 }
4218 /* Quartz / Magma with treasure */
4219 else if (c_ptr->feat >= FEAT_MAGMA_H) {
4220 /* Message */
4221 if (!quiet && (*w_ptr & CAVE_MARK)) {
4222 msg_print(Ind, "The vein turns into mud!");
4223 if (!istown(wpos)) msg_print(Ind, "You have found something!");
4224 obvious = TRUE;
4225 }
4226
4227 /* Destroy the wall */
4228 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_MUD : feat);
4229
4230 /* Place some gold */
4231 if (!istown(wpos)) place_gold(wpos, y, x, 0);
4232 }
4233
4234 /* Quartz / Magma */
4235 else if (c_ptr->feat >= FEAT_MAGMA) {
4236 /* Message */
4237 if (!quiet && (*w_ptr & CAVE_MARK)) {
4238 msg_print(Ind, "The vein turns into mud!");
4239 obvious = TRUE;
4240 }
4241
4242 /* Destroy the wall */
4243 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_MUD : feat);
4244 }
4245
4246 /* Rubble */
4247 else if (c_ptr->feat == FEAT_RUBBLE) {
4248 /* Message */
4249 if (!quiet && (*w_ptr & CAVE_MARK)) {
4250 msg_print(Ind, "The rubble turns into mud!");
4251 obvious = TRUE;
4252 }
4253
4254 /* Destroy the rubble */
4255 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_MUD : feat);
4256
4257 /* Hack -- place an object */
4258 if (rand_int(100) < 10) {
4259 /* Found something */
4260 if (!quiet && player_can_see_bold(Ind, y, x) && !istown(wpos)) {
4261 msg_print(Ind, "There was something buried in the rubble!");
4262 obvious = TRUE;
4263 }
4264
4265 /* Place object */
4266 if (!istown(wpos)) {
4267 place_object_restrictor = RESF_NONE;
4268 place_object(wpos, y, x, FALSE, FALSE, FALSE, make_resf(p_ptr) | RESF_LOW, default_obj_theme, p_ptr->luck, ITEM_REMOVAL_NORMAL);
4269 }
4270 }
4271 }
4272
4273 /* House doors are immune */
4274 else if (c_ptr->feat == FEAT_HOME) {
4275 /* Message */
4276 if (!quiet && (*w_ptr & CAVE_MARK)) {
4277 msg_print(Ind, "The door resists.");
4278 obvious = TRUE;
4279 }
4280 }
4281
4282 /* Destroy doors (and secret doors) */
4283 else if (c_ptr->feat >= FEAT_DOOR_HEAD) {
4284 /* Hack -- special message */
4285 if (!quiet && (*w_ptr & CAVE_MARK)) {
4286 msg_print(Ind, "The door turns into mud!");
4287 obvious = TRUE;
4288 }
4289
4290 /* Destroy the feature */
4291 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_MUD : feat);
4292 }
4293
4294 /* Forget the wall */
4295 everyone_forget_spot(wpos, y, x);
4296
4297 if (!quiet) {
4298 /* Notice */
4299 note_spot(Ind, y, x);
4300
4301 /* Redraw */
4302 everyone_lite_spot(wpos, y, x);
4303
4304 /* Update some things */
4305 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
4306 }
4307
4308 break;
4309 }
4310
4311 /* Make doors */
4312 case GF_MAKE_DOOR:
4313 if (!allow_terraforming(wpos, FEAT_TREE)) break;
4314 /* Require a "naked" floor grid */
4315 if (!cave_naked_bold(zcave, y, x)) break;
4316
4317 /* Create a closed door */
4318 c_ptr->feat = FEAT_DOOR_HEAD + 0x00;
4319
4320 if (!quiet) {
4321 /* Notice */
4322 note_spot(Ind, y, x);
4323 /* Redraw */
4324 everyone_lite_spot(wpos, y, x);
4325 /* Observe */
4326 if (*w_ptr & CAVE_MARK) obvious = TRUE;
4327 /* Update some things */
4328 p_ptr->update |= (PU_VIEW | PU_LITE | PU_MONSTERS);
4329 }
4330 break;
4331
4332 /* Make traps */
4333 case GF_MAKE_TRAP:
4334 if (!allow_terraforming(wpos, FEAT_TREE)) break;
4335 /* Require a "naked" floor grid */
4336 if ((zcave[y][x].feat != FEAT_MORE && zcave[y][x].feat != FEAT_LESS) && cave_perma_bold(zcave, y, x)) break;
4337
4338 /* Place a trap */
4339 place_trap(wpos, y, x, dam);
4340
4341 if (!quiet) {
4342 /* Notice */
4343 note_spot(Ind, y, x);
4344 /* Redraw */
4345 everyone_lite_spot(wpos, y, x);
4346 }
4347 break;
4348
4349 /* Lite up the grid */
4350 case GF_LITE_WEAK:
4351 case GF_LITE:
4352 /* don't ruin the mood :> (allow turning on light inside houses though) */
4353 if ((!(wpos->wz == 0 && (season_halloween || season_newyearseve))) || (c_ptr->info & CAVE_ICKY)) {
4354 /* Turn on the light */
4355 c_ptr->info |= CAVE_GLOW;
4356
4357 if (!quiet) {
4358 /* Notice */
4359 note_spot_depth(wpos, y, x);
4360 /* Redraw */
4361 everyone_lite_spot(wpos, y, x);
4362 /* Observe */
4363 if (player_can_see_bold(Ind, y, x)) obvious = TRUE;
4364 }
4365 }
4366
4367 /* Mega-Hack -- Update the monster in the affected grid */
4368 /* This allows "spear of light" (etc) to work "correctly" */
4369 if (c_ptr->m_idx > 0) update_mon(c_ptr->m_idx, FALSE);
4370 break;
4371
4372 /* Darken the grid */
4373 case GF_DARK_WEAK:
4374 case GF_DARK:
4375 /* Notice */
4376 if (!quiet && player_can_see_bold(Ind, y, x)) obvious = TRUE;
4377
4378 /* Turn off the light. */
4379 c_ptr->info &= ~CAVE_GLOW;
4380
4381 /* Hack -- Forget "boring" grids */
4382 // if (c_ptr->feat <= FEAT_INVIS)
4383 if (cave_plain_floor_grid(c_ptr)) {
4384 /* Forget the wall */
4385 everyone_forget_spot(wpos, y, x);
4386 if (!quiet)
4387 /* Notice */
4388 note_spot(Ind, y, x);
4389 }
4390 if (!quiet)
4391 /* Redraw */
4392 everyone_lite_spot(wpos, y, x);
4393
4394 /* Mega-Hack -- Update the monster in the affected grid */
4395 /* This allows "spear of light" (etc) to work "correctly" */
4396 if (c_ptr->m_idx > 0) update_mon(c_ptr->m_idx, FALSE);
4397
4398 /* All done */
4399 break;
4400
4401 case GF_KILL_GLYPH:
4402 {
4403 byte feat = twall_erosion(wpos, y, x);
4404 if (!allow_terraforming(wpos, FEAT_TREE)) break;
4405 if (c_ptr->feat == FEAT_GLYPH || c_ptr->feat == FEAT_RUNE)
4406 cave_set_feat_live(wpos, y, x, (feat == FEAT_FLOOR) ? FEAT_DIRT : feat);
4407 }
4408
4409 /* from PernA - Jir - */
4410 #if 0
4411 case GF_MAKE_GLYPH:
4412 /* Require a "naked" floor grid */
4413 if (!cave_clean_bold(zcave, y, x)) break;
4414 if((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
4415 cave_set_feat_live(&p_ptr->wpos, y, x, FEAT_GLYPH);
4416 break;
4417 #endif
4418
4419 // GF_ROCKET and GF_DISINTEGRATE are handled in project()
4420
4421 case GF_WATER:
4422 case GF_WAVE:
4423 case GF_VAPOUR:
4424 case GF_WATERPOISON: //New druid stuff
4425 {
4426 int p1 = 0;
4427 int p2 = 0;
4428 int f1 = FEAT_NONE;
4429 int f2 = FEAT_NONE;
4430 int f = FEAT_NONE;
4431 int k;
4432
4433 if (!allow_terraforming(wpos, FEAT_SHAL_WATER)) break;
4434 /* "Permanent" features will stay */
4435 if ((f_info[c_ptr->feat].flags1 & FF1_PERMANENT)) break;
4436 /* Needs more than 30 damage */
4437 if (dam < 30) break;
4438
4439 bool old_rand = Rand_quick;
4440 u32b tmp_seed = Rand_value;
4441
4442 if ((c_ptr->feat == FEAT_FLOOR) ||
4443 (c_ptr->feat == FEAT_DIRT) ||
4444 (c_ptr->feat == FEAT_GRASS)) {
4445 /* p1 % chance to create this feat */
4446 p1 = 20; f1 = FEAT_SHAL_WATER;
4447
4448 if (c_ptr->feat == FEAT_DIRT)
4449 /* reduce feat1 chance */
4450 p1 = 10;
4451 /* p2 % chance to create this feat */
4452 p2 = 15; f2 = FEAT_MUD;
4453 }
4454 else if (c_ptr->feat == FEAT_SHAL_LAVA) {
4455 /* 15% chance to convert it to normal floor */
4456 p1 = 15; f1 = FEAT_VOLCANIC;//FEAT_ROCKY, FEAT_ASH
4457 }
4458
4459 /* Use the stored/quick RNG */
4460 Rand_quick = TRUE;
4461 //using fixed seed here to make sure that repeated casting won't cover 100% of the area with water:
4462 Rand_value = (3623 * wpos->wy + 29753) * (2843 * wpos->wx + 48869) + (1741 * y + 22109) * y * x + (x + 96779) * x + 42 + wpos->wz;
4463
4464 k = rand_int(100);
4465
4466 /* Restore RNG */
4467 Rand_quick = old_rand;
4468 Rand_value = tmp_seed;
4469
4470 if (k < p1) f = f1;
4471 else if (k < p1 + p2) f = f2;
4472
4473 if (f) {
4474 //uses static array set in generate.c, fix! if (f == FEAT_FLOOR) place_floor_live(wpos, y, x);
4475 // else
4476 cave_set_feat_live(wpos, y, x, f);
4477 /* Notice */
4478 if (!quiet) note_spot(Ind, y, x);
4479 /* Redraw */
4480 everyone_lite_spot(wpos, y, x);
4481 // if (seen) obvious = TRUE;
4482 }
4483 break;
4484 }
4485 }
4486
4487 /* Return "Anything seen?" */
4488 return (obvious);
4489 }
4490
4491
4492
4493 /*
4494 * We are called from "project()" to "damage" objects
4495 *
4496 * We are called both for "beam" effects and "ball" effects.
4497 *
4498 * Perhaps we should only SOMETIMES damage things on the ground.
4499 *
4500 * The "r" parameter is the "distance from ground zero".
4501 *
4502 * Note that we determine if the player can "see" anything that happens
4503 * by taking into account: blindness, line-of-sight, and illumination.
4504 *
4505 * XXX XXX XXX We also "see" grids which are "memorized", probably a hack
4506 *
4507 * We return "TRUE" if the effect of the projection is "obvious".
4508 */
4509 static bool project_i(int Ind, int who, int r, struct worldpos *wpos, int y, int x, int dam, int typ)
4510 {
4511 player_type *p_ptr = NULL;
4512 u16b this_o_idx, next_o_idx = 0;
4513 bool obvious = FALSE;
4514 bool quiet = ((Ind <= 0 || Ind >= 0 - PROJECTOR_UNUSUAL) ? TRUE : FALSE);
4515 u32b f1, f2, f3, f4, f5, f6, esp;
4516 char o_name[ONAME_LEN];
4517 int o_sval = 0;
4518 bool is_potion = FALSE, is_basic_potion = FALSE, is_meltable = FALSE;
4519
4520 int div;
4521 cave_type **zcave;
4522 cave_type *c_ptr;
4523 object_type *o_ptr;
4524 object_kind *k_ptr;
4525
4526 if (!(zcave = getcave(wpos))) return(FALSE);
4527 c_ptr = &zcave[y][x];
4528 // o_ptr = &o_list[c_ptr->o_idx];
4529
4530 /* Nothing here */
4531 if (!c_ptr->o_idx) return (FALSE);
4532
4533 /* Set the player pointer */
4534 if (!quiet) p_ptr = Players[Ind];
4535
4536 /* Extract radius */
4537 div = r + 1;
4538
4539 /* Adjust damage */
4540 dam = radius_damage(dam, div, typ);
4541
4542
4543 /* XXX XXX */
4544 who = who ? who : 0;
4545
4546 /* Scan all objects in the grid */
4547 for (this_o_idx = c_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx) {
4548 bool is_art = FALSE;
4549 bool ignore = FALSE;
4550 bool plural = FALSE;
4551 bool do_kill = FALSE;
4552 bool do_smash_effect = FALSE;
4553
4554 cptr note_kill = NULL;
4555
4556 /* Acquire object */
4557 o_ptr = &o_list[this_o_idx];
4558 k_ptr = &k_info[o_ptr->k_idx];
4559 /* Check for (nothing), execute hack to protect such items */
4560 if (nothing_test(o_ptr, NULL, wpos, x, y, 3)) {
4561 // s_printf("NOTHINGHACK: spell doesn't meet item at wpos %d,%d,%d.\n", wpos->wx, wpos->wy, wpos->wz);
4562 return(FALSE);
4563 }
4564
4565 /* Acquire next object */
4566 next_o_idx = o_ptr->next_o_idx;
4567
4568 /* Extract the flags */
4569 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
4570
4571 /* get object name */
4572 if ((Ind >= 0) && ((0 - Ind) > PROJECTOR_UNUSUAL))
4573 object_desc(Ind, o_name, o_ptr, FALSE, 0);
4574
4575 /* Get the "plural"-ness */
4576 if (o_ptr->number > 1) plural = TRUE;
4577
4578 /* Check for artifact */
4579 if (artifact_p(o_ptr)) is_art = TRUE;
4580
4581 /* Stormbringer is artifact-like - C. Blue */
4582 if (o_ptr->name2 == EGO_STORMBRINGER) is_art = TRUE;
4583
4584 o_sval = o_ptr->sval;
4585 /* potion_smash_effect only takes sval as parameter, so it can't handle TV_POTION2 at this time.
4586 For this reason, add is_basic_potion: It determines whether smash effect is applied. */
4587 is_potion = ((k_info[o_ptr->k_idx].tval == TV_POTION) || (k_info[o_ptr->k_idx].tval == TV_POTION2));
4588 is_basic_potion = (k_info[o_ptr->k_idx].tval == TV_POTION);
4589 is_meltable = (k_info[o_ptr->k_idx].tval == TV_BOTTLE);
4590
4591 /* Analyze the type */
4592 switch (typ) {
4593 /* Identify */
4594 case GF_IDENTIFY:
4595 {
4596 do_kill = FALSE;
4597
4598 /* Identify it fully */
4599 if (!quiet) object_aware(Ind, o_ptr);
4600 object_known(o_ptr);
4601 break;
4602 }
4603
4604 /* Acid -- Lots of things */
4605 case GF_ACID:
4606 {
4607 if (hates_acid(o_ptr)) {
4608 do_kill = TRUE;
4609 note_kill = (plural ? " melt!" : " melts!");
4610 if (f3 & TR3_IGNORE_ACID) ignore = TRUE;
4611 }
4612 break;
4613 }
4614
4615 /* Elec -- Rings and Wands, and now much more to make IM_ELEC better, and elec less laughed at */
4616 case GF_ELEC:
4617 {
4618 if (hates_elec(o_ptr))
4619 {
4620 do_kill = TRUE;
4621 note_kill = (plural ? " are destroyed!" : " is destroyed!");
4622 if (f3 & TR3_IGNORE_ELEC) ignore = TRUE;
4623 }
4624 else apply_discharge_item(this_o_idx, dam);
4625 break;
4626 }
4627
4628 /* Fire -- Flammable objects */
4629 case GF_FIRE:
4630 {
4631 do_smash_effect = TRUE;
4632 if (hates_fire(o_ptr)) {
4633 do_kill = TRUE;
4634 if (is_meltable)
4635 note_kill = (plural ? " melt!" : " melts!");
4636 else if (is_potion)
4637 note_kill = (plural ? " evaporate!" : " evaporates!");
4638 else
4639 note_kill = (plural ? " burn up!" : " burns up!");
4640 if (f3 & TR3_IGNORE_FIRE) ignore = TRUE;
4641 }
4642 break;
4643 }
4644
4645 /* Cold -- potions and flasks */
4646 case GF_COLD:
4647 {
4648 if (hates_cold(o_ptr)) {
4649 note_kill = (plural ? " shatter!" : " shatters!");
4650 do_kill = TRUE;
4651 if (f3 & TR3_IGNORE_COLD) ignore = TRUE;
4652 #ifdef USE_SOUND_2010
4653 else if (!quiet) sound(Ind, "shatter_potion", NULL, SFX_TYPE_MISC, FALSE);
4654 #endif
4655 }
4656 break;
4657 }
4658
4659 /* Cold -- potions and flasks */
4660 case GF_WATER:
4661 case GF_WAVE:
4662 //case GF_VAPOUR:
4663 case GF_WATERPOISON:
4664 {
4665 if (hates_water(o_ptr)) {
4666 note_kill = (plural ? " are soaked!" : " is soaked!");
4667 do_kill = TRUE;
4668 if (f5 & TR5_IGNORE_WATER) ignore = TRUE;
4669 }
4670 break;
4671 }
4672
4673 /* Fire + Elec + a bit Force */
4674 case GF_PLASMA:
4675 {
4676 do_smash_effect = TRUE;
4677 ignore = TRUE;
4678
4679 if (hates_fire(o_ptr)) {
4680 do_kill = TRUE;
4681 if (!(f3 & TR3_IGNORE_FIRE)) {
4682 ignore = FALSE;
4683 if (is_meltable)
4684 note_kill = (plural ? " melt!" : " melts!");
4685 else if (is_potion)
4686 note_kill = (plural ? " evaporate!" : " evaporates!");
4687 else
4688 note_kill = (plural ? " burn up!" : " burns up!");
4689 }
4690 }
4691
4692 if (hates_elec(o_ptr)) {
4693 do_kill = TRUE;
4694 if (!(f3 & TR3_IGNORE_ELEC)) {
4695 ignore = FALSE;
4696 note_kill = (plural ? " are destroyed!" : " is destroyed!");
4697 }
4698 }
4699 else apply_discharge_item(this_o_idx, dam / 2);
4700
4701 /* Note: Force item destruction is probably already covered
4702 by applied fire item destruction above */
4703
4704 break;
4705 }
4706
4707 /* Fire + Impact */
4708 case GF_METEOR:
4709 {
4710 do_smash_effect = TRUE;
4711 ignore = TRUE;
4712 if (hates_fire(o_ptr)) {
4713 do_kill = TRUE;
4714 if (!(f3 & TR3_IGNORE_FIRE)) {
4715 ignore = FALSE;
4716 if (is_meltable)
4717 note_kill = (plural ? " melt!" : " melts!");
4718 else if (is_potion)
4719 note_kill = (plural ? " evaporate!" : " evaporates!");
4720 else
4721 note_kill = (plural ? " burn up!" : " burns up!");
4722 }
4723 }
4724 if (hates_impact(o_ptr)) {
4725 do_kill = TRUE;
4726 if (!(f3 & TR3_IGNORE_COLD)) {
4727 ignore = FALSE;
4728 note_kill = (plural ? " shatter!" : " shatters!");
4729 #ifdef USE_SOUND_2010
4730 if (!quiet) sound(Ind, "shatter_potion", NULL, SFX_TYPE_MISC, FALSE);
4731 #endif
4732 }
4733 }
4734 break;
4735 }
4736
4737 /* Hack -- break potions and such */
4738 case GF_ICE:
4739 case GF_ICEPOISON:
4740 {
4741 if (hates_cold(o_ptr) || hates_impact(o_ptr)) {
4742 note_kill = (plural ? " shatter!" : " shatters!");
4743 do_kill = TRUE;
4744 #ifdef USE_SOUND_2010
4745 if (!quiet) sound(Ind, "shatter_potion", NULL, SFX_TYPE_MISC, FALSE);
4746 #endif
4747 }
4748 break;
4749 }
4750
4751 case GF_SHARDS:
4752 case GF_FORCE:
4753 case GF_SOUND:
4754 case GF_THUNDER:
4755 {
4756 if (hates_impact(o_ptr)) {
4757 note_kill = (plural ? " shatter!" : " shatters!");
4758 do_kill = TRUE;
4759 #ifdef USE_SOUND_2010
4760 if (!quiet) sound(Ind, "shatter_potion", NULL, SFX_TYPE_MISC, FALSE);
4761 #endif
4762 }
4763 break;
4764 }
4765
4766 /* Mana -- destroys everything -- except IGNORE_MANA items :p */
4767 case GF_ANNIHILATION:
4768 case GF_MANA:
4769 {
4770 if (!(f5 & (TR5_IGNORE_MANA | TR5_RES_MANA))) {
4771 do_smash_effect = TRUE;
4772 do_kill = TRUE;
4773 note_kill = (plural ? " are destroyed!" : " is destroyed!");
4774 }
4775 break;
4776 }
4777
4778 case GF_DISINTEGRATE:
4779 {
4780 do_smash_effect = FALSE;
4781 do_kill = TRUE;
4782 note_kill = is_potion ? (plural ? " evaporate!" : " evaporates!")
4783 : (plural ? " is pulverized!" : " is pulverized!");
4784 // note_kill = (plural ? " evaporate!" : " evaporates!");
4785 break;
4786 }
4787
4788 case GF_DISENCHANT:
4789 {
4790 if ((f2 & TR2_RES_DISEN) || (f5 & TR5_IGNORE_DISEN)) break;
4791 if (artifact_p(o_ptr) && magik(100)) break;
4792
4793 if (o_ptr->timeout) o_ptr->timeout /= 2;
4794
4795 if (o_ptr->to_h > k_ptr->to_h) o_ptr->to_h--;
4796 if (o_ptr->to_d > k_ptr->to_d) o_ptr->to_d--;
4797 if (o_ptr->to_a > k_ptr->to_a) o_ptr->to_a--;
4798
4799 switch (o_ptr->tval) {
4800 case TV_ROD: break;
4801 case TV_WAND:
4802 case TV_STAFF:
4803 o_ptr->pval = 0;
4804 break;
4805 default:
4806 /* changed from >0 to >1 to make items retain a slice of their actual abilities */
4807 if ((o_ptr->pval > 1 || o_ptr->bpval > 1)
4808 && !is_ammo(o_ptr->tval)
4809 && o_ptr->tval != TV_CHEST
4810 && o_ptr->tval != TV_BOOK
4811 && (o_ptr->tval != TV_RING || o_ptr->sval != SV_RING_POLYMORPH)) {
4812 if (o_ptr->pval > 1) {
4813 if (o_ptr->bpval > 1 && rand_int(2)) o_ptr->bpval--;
4814 else o_ptr->pval--;
4815 } else o_ptr->bpval--;
4816 }
4817 break;
4818 }
4819 break;
4820 }
4821
4822 case GF_INFERNO:
4823 case GF_DETONATION:
4824 case GF_ROCKET:
4825 {
4826 do_smash_effect = TRUE; /* allow coolness, while preventing exploiting via m_ptr->hit_proj_id; */
4827 do_kill = TRUE;
4828 note_kill = is_potion ? (plural ? " evaporate!" : " evaporates!")
4829 : (plural ? " is pulverized!" : " is pulverized!");
4830 // note_kill = (plural ? " evaporate!" : " evaporates!");
4831 break;
4832 }
4833
4834 /* Holy Orb -- destroys cursed non-artifacts */
4835 case GF_HOLY_ORB:
4836 case GF_HOLY_FIRE:
4837 {
4838 do_smash_effect = TRUE;
4839 if (cursed_p(o_ptr)
4840 //should be enabled maybe? || hates_fire(o_ptr)
4841 ) {
4842 do_kill = TRUE;
4843 note_kill = (plural ? " are destroyed!" : " is destroyed!");
4844 }
4845 break;
4846 }
4847
4848 case GF_HELL_FIRE:
4849 do_smash_effect = TRUE;
4850 if (hates_fire(o_ptr)) {
4851 do_kill = TRUE;
4852 if (is_meltable)
4853 note_kill = (plural ? " melt!" : " melts!");
4854 else if (is_potion)
4855 note_kill = (plural ? " evaporate!" : " evaporates!");
4856 else
4857 note_kill = (plural ? " burn up!" : " burns up!");
4858 if (f3 & TR3_IGNORE_FIRE) ignore = TRUE;
4859 } else if (!cursed_p(o_ptr) && magik(10)) {
4860 note_kill = (plural ? " are destroyed!" : " is destroyed!");
4861 do_kill = TRUE;
4862 }
4863 break;
4864
4865 /* Unlock chests */
4866 case GF_KILL_TRAP:
4867 case GF_KILL_DOOR:
4868 {
4869 /* Chests are noticed only if trapped or locked */
4870 if (o_ptr->tval == TV_CHEST)
4871 {
4872 /* Disarm/Unlock traps */
4873 if (o_ptr->pval > 0)
4874 {
4875 /* Disarm or Unlock */
4876 o_ptr->pval = (0 - o_ptr->pval);
4877
4878 /* Identify */
4879 object_known(o_ptr);
4880
4881 /* Notice */
4882 // if (!quiet && p_ptr->obj_vis[c_ptr->o_idx])
4883 if (!quiet && p_ptr->obj_vis[this_o_idx])
4884 {
4885 msg_print(Ind, "Click!");
4886 obvious = TRUE;
4887 }
4888 }
4889 }
4890
4891 break;
4892 }
4893
4894 /* Nexus, Gravity -- teleports the object away */
4895 case GF_NEXUS:
4896 case GF_GRAVITY:
4897 {
4898 int j, dist = (typ == GF_NEXUS ? 80 : 15);
4899 object_type tmp_obj = *o_ptr;
4900 if (check_st_anchor(wpos, y, x)) break;
4901 // if (seen) obvious = TRUE;
4902
4903 do_smash_effect = TRUE;
4904
4905 /* no tricks to get stuff out of suspended guild halls ;> */
4906 if ((c_ptr->info & CAVE_GUILD_SUS)) break;
4907
4908 note_kill = (plural ? " disappear!" : " disappears!");
4909
4910 for (j = 0; j < 10; j++) {
4911 s16b cx = x + dist - rand_int(dist * 2);
4912 s16b cy = y + dist - rand_int(dist * 2);
4913 if (!in_bounds(cy, cx)) continue;
4914 if (!cave_floor_bold(zcave, cy, cx) ||
4915 cave_perma_bold(zcave, cy, cx)) continue;
4916
4917 // (void)floor_carry(cy, cx, &tmp_obj);
4918 drop_near(&tmp_obj, 0, wpos, cy, cx);
4919
4920 /* XXX not working? */
4921 if (!quiet && note_kill)
4922 msg_format_near_site(y, x, wpos, 0, TRUE, "\377oThe %s%s", o_name, note_kill);
4923
4924 delete_object_idx(this_o_idx, FALSE);
4925 break;
4926 }
4927 break;
4928 }
4929
4930 }
4931
4932
4933 /* Attempt to destroy the object */
4934 // if (is_basic_potion && do_smash_effect) potion_smash_effect(who, wpos, y, x, o_sval);
4935
4936 // if(do_kill && (wpos->wz))
4937 if (do_kill) {
4938 /* Effect "observed" */
4939 // if (!quiet && p_ptr->obj_vis[c_ptr->o_idx])
4940 if (!quiet && p_ptr->obj_vis[this_o_idx]) {
4941 obvious = TRUE;
4942 }
4943
4944 /* Artifacts, and other objects, get to resist */
4945 if (is_art || ignore) {
4946 /* Observe the resist */
4947 // if (!quiet && p_ptr->obj_vis[c_ptr->o_idx])
4948 if (!quiet && p_ptr->obj_vis[this_o_idx]) {
4949 msg_format(Ind, "The %s %s unaffected!",
4950 o_name, (plural ? "are" : "is"));
4951 }
4952 }
4953
4954 /* Kill it */
4955 else {
4956 /* Describe if needed */
4957 // if (!quiet && p_ptr->obj_vis[c_ptr->o_idx] && note_kill)
4958 if (!quiet && p_ptr->obj_vis[this_o_idx] && note_kill) {
4959 msg_format(Ind, "\377oThe %s%s", o_name, note_kill);
4960 }
4961
4962 /* Delete the object */
4963 // delete_object(wpos, y, x);
4964 delete_object_idx(this_o_idx, TRUE);
4965
4966 /* Potions produce effects when 'shattered' */
4967 if (is_basic_potion && do_smash_effect) {
4968 /* prevent mass deto exploit */
4969 if (mon_hit_proj_id == mon_hit_proj_id2) {
4970 mon_hit_proj_id++;
4971 (void)potion_smash_effect(who, wpos, y, x, o_sval);
4972 mon_hit_proj_id2++;
4973 } else (void)potion_smash_effect(who, wpos, y, x, o_sval);
4974 }
4975
4976 if (!quiet) {
4977 /* Redraw */
4978 everyone_lite_spot(wpos, y, x);
4979 }
4980 }
4981 }
4982 }
4983
4984 /* Return "Anything seen?" */
4985 return (obvious);
4986 }
4987
4988
4989 #if 0 /* commented out in project_m */
4990 /*
4991 * Psionic attacking of high level demons/undead can backlash
4992 */
4993 static bool psi_backlash(int Ind, int m_idx, int dam)
4994 {
4995 monster_type *m_ptr = &m_list[m_idx];
4996 monster_race *r_ptr = race_inf(m_ptr);
4997 char m_name[MNAME_LEN];
4998 player_type *p_ptr;
4999
5000 if (!Ind) return FALSE;
5001
5002 p_ptr = Players[Ind];
5003
5004 if ((r_ptr->flags3 & (RF3_UNDEAD | RF3_DEMON)) &&
5005 (r_ptr->level > p_ptr->lev/2) && !rand_int(2))
5006 {
5007 monster_desc(Ind, m_name, m_idx, 0);
5008 msg_format(Ind, "%^s's corrupted mind backlashes your attack!",
5009 m_name);
5010 project(0 - Ind, m_idx, 0, p_ptr->py, p_ptr->px ,dam / 3, GF_PSI, 0, "");
5011 return TRUE;
5012 }
5013 return FALSE;
5014 }
5015 #endif
5016
5017
5018 /*
5019 * Helper function for "project()" below.
5020 *
5021 * Handle a beam/bolt/ball causing damage to a monster.
5022 *
5023 * This routine takes a "source monster" (by index) which is mostly used to
5024 * determine if the player is causing the damage, and a "radius" (see below),
5025 * which is used to decrease the power of explosions with distance, and a
5026 * location, via integers which are modified by certain types of attacks
5027 * (polymorph and teleport being the obvious ones), a default damage, which
5028 * is modified as needed based on various properties, and finally a "damage
5029 * type" (see below).
5030 *
5031 * Note that this routine can handle "no damage" attacks (like teleport) by
5032 * taking a "zero" damage, and can even take "parameters" to attacks (like
5033 * confuse) by accepting a "damage", using it to calculate the effect, and
5034 * then setting the damage to zero. Note that the "damage" parameter is
5035 * divided by the radius, so monsters not at the "epicenter" will not take
5036 * as much damage (or whatever)...
5037 *
5038 * Note that "polymorph" is dangerous, since a failure in "place_monster()"'
5039 * may result in a dereference of an invalid pointer. XXX XXX XXX
5040 *
5041 * Various messages are produced, and damage is applied.
5042 *
5043 * Just "casting" a substance (i.e. plasma) does not make you immune, you must
5044 * actually be "made" of that substance, or "breathe" big balls of it.
5045 *
5046 * We assume that "Plasma" monsters, and "Plasma" breathers, are immune
5047 * to plasma.
5048 *
5049 * We assume "Nether" is an evil, necromantic force, so it doesn't hurt undead,
5050 * and hurts evil less. If can breath nether, then it resists it as well.
5051 *
5052 * Damage reductions use the following formulas:
5053 * Note that "dam = dam * 6 / (randint(6) + 6);"
5054 * gives avg damage of .655, ranging from .858 to .500
5055 * Note that "dam = dam * 5 / (randint(6) + 6);"
5056 * gives avg damage of .544, ranging from .714 to .417
5057 * Note that "dam = dam * 4 / (randint(6) + 6);"
5058 * gives avg damage of .444, ranging from .556 to .333
5059 * Note that "dam = dam * 3 / (randint(6) + 6);"
5060 * gives avg damage of .327, ranging from .427 to .250
5061 * Note that "dam = dam * 2 / (randint(6) + 6);"
5062 * gives something simple.
5063 *
5064 * In this function, "result" messages are postponed until the end, where
5065 * the "note" string is appended to the monster name, if not NULL. So,
5066 * to make a spell have "no effect" just set "note" to NULL. You should
5067 * also set "notice" to FALSE, or the player will learn what the spell does.
5068 *
5069 * We attempt to return "TRUE" if the player saw anything "useful" happen.
5070 *
5071 * IMPORTANT: Keep approx_damage() in sync with this.
5072 */
5073 static bool project_m(int Ind, int who, int y_origin, int x_origin, int r, struct worldpos *wpos, int y, int x, int dam, int typ, int flg)
5074 {
5075 int i = 0, div, k, k_elec, k_sound, k_lite;
5076
5077 monster_type *m_ptr;
5078 monster_race *r_ptr;
5079
5080 cptr name;
5081
5082 /* Is the monster "seen"? */
5083 bool seen;
5084 /* Were the "effects" obvious (if seen)? */
5085 bool obvious = FALSE;
5086
5087 /* do not notice things the player did to themselves by ball spell */
5088 /* fix me XXX XXX XXX */
5089
5090 int priest_spell = 0;
5091 /* the_sandman: the priest spell? (0 or 1) */
5092 if (dam == 9999 && typ == GF_OLD_DRAIN) {
5093 priest_spell = 1;
5094 dam = 2; // the real damage
5095 }
5096
5097 /* Polymorph setting (true or false) */
5098 int do_poly = 0;
5099 /* Teleport setting (max distance) */
5100 int do_dist = 0;
5101 /* Blindness setting (amount to confuse) */
5102 int do_blind = 0;
5103 /* Confusion setting (amount to confuse) */
5104 int do_conf = 0;
5105 /* Stunning setting (amount to stun) */
5106 int do_stun = 0;
5107 /* Sleep amount (amount to sleep) */
5108 int do_sleep = 0;
5109 /* Fear amount (amount to fear) */
5110 int do_fear = 0;
5111
5112 /* Hold the monster name */
5113 char m_name[MNAME_LEN];
5114
5115 bool resist = FALSE;
5116 /* Assume no note */
5117 cptr note = NULL;
5118
5119 /* Assume a default death */
5120 cptr note_dies = " dies";
5121 bool quiet; /* no message output */
5122 bool quiet_dam = FALSE; /* no damage message output */
5123
5124 int plev = 25; /* replacement dummy for when a monster isn't
5125 affected by a real player but by eg a trap */
5126
5127 cave_type **zcave;
5128 cave_type *c_ptr;
5129 player_type *p_ptr = NULL;
5130
5131
5132 if (!(zcave = getcave(wpos))) return(FALSE);
5133 c_ptr = &zcave[y][x];
5134
5135 /* hack -- by trap */
5136 quiet = ((Ind <= 0 || who <= PROJECTOR_UNUSUAL) ? TRUE : (0 - Ind == c_ptr->m_idx ? TRUE : FALSE));
5137
5138 // if(quiet) return(FALSE);
5139 if (Ind <= 0 || 0 - Ind == c_ptr->m_idx) return(FALSE);
5140 if (!quiet) {
5141 p_ptr = Players[Ind];
5142 plev = p_ptr->lev;
5143 }
5144
5145 /* Nobody here */
5146 if (c_ptr->m_idx <= 0) return (FALSE);
5147
5148 /* Acquire monster pointer */
5149 m_ptr = &m_list[c_ptr->m_idx];
5150
5151 /* Prevent recursively afflicted potion_smash_effect() hits */
5152 if (mon_hit_proj_id != mon_hit_proj_id2) {
5153 if (m_ptr->hit_proj_id == mon_hit_proj_id) return(FALSE);
5154 else m_ptr->hit_proj_id = mon_hit_proj_id;
5155 }
5156
5157 /* Acquire race pointer */
5158 r_ptr = race_inf(m_ptr);
5159
5160 /* Acquire name */
5161 name = r_name_get(m_ptr);
5162
5163 /* Never affect projector */
5164 if ((who > 0) && (c_ptr->m_idx == who)) return (FALSE);
5165
5166 /* Never hurt golem */
5167 if (who < 0 && who > PROJECTOR_UNUSUAL) {
5168 //if (IS_PVP) {
5169 if (Players[-who]->id == m_ptr->owner) return (FALSE);
5170 }
5171
5172 /* Set the "seen" flag */
5173 if (!quiet) {
5174 seen = p_ptr->mon_vis[c_ptr->m_idx];
5175 /* Cannot 'hear' if too far */
5176 if (!seen && distance(p_ptr->py, p_ptr->px, y, x) > MAX_SIGHT)
5177 quiet = TRUE;
5178 }
5179 else seen = FALSE;
5180
5181
5182 /* Get the monster name (BEFORE polymorphing) */
5183 if (!quiet) monster_desc(Ind, m_name, c_ptr->m_idx, 0);
5184
5185
5186 /* Handle reflection - it's back, though weaker - C. Blue */
5187 if ((r_ptr->flags2 & RF2_REFLECTING) &&
5188 (flg & PROJECT_KILL) && !(flg & (PROJECT_NORF | PROJECT_JUMP)) /* only for fire_bolt() */
5189 && magik(50)) {
5190 if (seen) msg_print(Ind, "Your attack was deflected.");
5191 return TRUE; /* notice */
5192 }
5193
5194 #ifdef USE_BLOCKING
5195 /* handle blocking (deflection) */
5196 if (strchr("hHJkpPty", r_ptr->d_char) && /* leaving out Yeeks (else Serpent Man 'J') */
5197 !(r_ptr->flags3 & RF3_ANIMAL) && !(r_ptr->flags8 & RF8_NO_BLOCK) &&
5198 (flg & PROJECT_KILL) && !(flg & (PROJECT_NORF | PROJECT_JUMP | PROJECT_NODF)) /* only for fire_bolt() */
5199 && !rand_int(52 - r_ptr->level / 3)) { /* small chance to block spells */
5200 if (seen) {
5201 char hit_desc[MAX_CHARS];
5202 sprintf(hit_desc, "\377%c%s blocks.", COLOUR_BLOCK_MON, m_name);
5203 hit_desc[0] = toupper(hit_desc[0]);
5204 msg_print(Ind, hit_desc);
5205 }
5206 return TRUE; /* notice */
5207 }
5208 #endif
5209
5210
5211 /* Extract radius */
5212 div = r + 1;
5213
5214 /* Decrease damage */
5215 dam = radius_damage(dam, div, typ);
5216
5217
5218 /* Mega-Hack */
5219 project_m_n++;
5220 project_m_x = x;
5221 project_m_y = y;
5222
5223
5224
5225 /* Some monsters get "destroyed" */
5226 if ((r_ptr->flags3 & RF3_DEMON) ||
5227 (r_ptr->flags3 & RF3_UNDEAD) ||
5228 (r_ptr->flags2 & RF2_STUPID) ||
5229 (strchr("AEvg", r_ptr->d_char)))
5230 {
5231 /* Special note at death */
5232 note_dies = " is destroyed";
5233 }
5234
5235
5236 /* Hack: GF_LIFEHEAL might heal or kill a monster */
5237 if (typ == GF_LIFEHEAL) {
5238 if (r_ptr->flags3 & RF3_UNDEAD) {
5239 typ = GF_HOLY_FIRE;
5240 } else {
5241 typ = GF_OLD_HEAL;
5242 }
5243 }
5244
5245
5246 /* Analyze the damage type */
5247 switch (typ) {
5248 /* psionic mana drain */
5249 case GF_SILENCE:
5250 /* hacks: extract power (probability for succeeding) */
5251 i = dam % 100; /* 1..51 (school 10..50) */
5252 k = dam - (i * 100);
5253 /* calculate resistance % chance based on skill level and monster level */
5254 i += 18;
5255 i *= i;
5256 i = i / (r_ptr->level ? r_ptr->level : 1);
5257 if (i > 69) i = 69; /* cap at 95% */
5258 i = (i * 138) / 100; /* finalize calculation */
5259 i = 100 - i;
5260 #ifdef TEST_SERVER
5261 s_printf("GF_SILENCE: chance i=%d, duration k=%d\n", i, k);
5262 #endif
5263 /* test resistance */
5264 if (!((r_ptr->flags4 & RF4_SPELLCASTER_MASK) |
5265 (r_ptr->flags5 & RF5_SPELLCASTER_MASK) |
5266 (r_ptr->flags6 & RF6_SPELLCASTER_MASK) |
5267 (r_ptr->flags0 & RF0_SPELLCASTER_MASK)) ||
5268 (r_ptr->level >= 98 && (r_ptr->flags1 & RF1_UNIQUE)) ||
5269 m_ptr->silenced != 0) { /* successful attempt also leads to cooldown! */
5270 note = " is unaffected";
5271 } else if (((r_ptr->flags1 & RF1_UNIQUE) && magik(50)) ||
5272 ((r_ptr->flags2 & RF2_POWERFUL) && magik(50)) ||
5273 magik(i)) {
5274 /* hack: A few turns of immunity from another attempt! */
5275 m_ptr->silenced = -k;
5276 note = " resists the effect";
5277 } else {
5278 /* extract and apply duration */
5279 m_ptr->silenced = k;
5280 note = " loses psychic energy";
5281 }
5282 /* no real HP damage */
5283 dam = 0; quiet_dam = TRUE;
5284 break;
5285 /* PSIONICS */
5286 case GF_PSI:
5287 {
5288 if (seen) obvious = TRUE;
5289 note_dies = " collapses, a mindless husk,";
5290
5291 /* Check resist/immunity */
5292 if ((r_ptr->flags9 & RF9_IM_PSI) || (r_ptr->flags2 & RF2_EMPTY_MIND) ||
5293 (r_ptr->flags3 & RF3_NONLIVING))
5294 {
5295 note = " is unaffected";
5296 dam = 0;
5297 quiet_dam = TRUE;
5298 break;
5299 } else if ((r_ptr->flags9 & RF9_RES_PSI) && rand_int(3)) {
5300 resist = TRUE;
5301 } else if ((r_ptr->flags3 & RF3_UNDEAD) && rand_int(2)) {
5302 resist = TRUE;
5303 } else if ((r_ptr->flags2 & RF2_STUPID) ||
5304 ((r_ptr->flags3 & RF3_ANIMAL) && !(r_ptr->flags2 & RF2_CAN_SPEAK))) {
5305 resist = TRUE;
5306 } else if (r_ptr->flags2 & RF2_WEIRD_MIND) {
5307 if (rand_int(5)) resist = TRUE;
5308 else {
5309 note = " resists somewhat";
5310 dam = (dam * 3 + 1) / 4;
5311 }
5312 } else if (!rand_int(20)) {
5313 resist = TRUE;
5314 }
5315
5316 /* Check backlash vs caster */
5317 // if (psi_backlash(Ind, c_ptr->m_idx, dam)) resist = TRUE;
5318
5319 /* Check susceptibility */
5320 #if 0
5321 /* vs f-im evil: similar dam to ood, somewhat more than (holy) ff (at 0 s.pow).
5322 however: max mana cost is only 15 instead of 25(ff:30). */
5323 /* note: could be && !(uni && powerful), but some hi-lv
5324 uniques might need powerful flag, strangely lacking it:
5325 nodens, mephistopheles, kronos, mouth of sauron */
5326 if ((r_ptr->flags2 & RF2_SMART) &&
5327 !(r_ptr->flags1 & RF1_UNIQUE)) {
5328 if ((r_ptr->flags2 & RF2_SMART) &&
5329 !((r_ptr->flags1 & RF1_UNIQUE) &&
5330 (r_ptr->flags2 & RF2_POWERFUL))) {
5331 #endif /* fine for now maybe: */
5332 if (r_ptr->flags2 & RF2_SMART) {
5333 if (!resist) {
5334 note = " is hit hard";
5335 dam += dam / 2;
5336 }
5337 }
5338 if (((m_ptr->confused > 0) && !rand_int(3)) ||
5339 ((m_ptr->confused > 20) && !rand_int(3)) ||
5340 ((m_ptr->confused > 50) && !rand_int(3))) {
5341 resist = FALSE;
5342 dam = dam * (3 + randint(7)) / 4;
5343 }
5344
5345 /* Apply resistance, damage, and effects */
5346 if (resist) {
5347 note = " resists";
5348 dam /= 2;
5349 if (!(r_ptr->flags3 & RF3_NO_CONF) && !rand_int(10)) do_conf = randint(8);
5350 } else if (randint(dam > 20 ? 20 : dam) > randint(r_ptr->level)) {
5351 do_stun = randint(6);
5352 do_conf = randint(20);
5353 if (!(r_ptr->flags3 & RF3_NO_SLEEP)) do_sleep = rand_int(2) ? 5 + randint(randint(60)) : 0;
5354 if (!(r_ptr->flags3 & RF3_NO_FEAR)) do_fear = randint(15);
5355 }
5356 break;
5357 }
5358 /* Mindcrafter's charm spell, makes monsters ignore you and your teammates (mostly..) */
5359 case GF_CHARMIGNORE: {
5360 int res = 1;
5361
5362 /* No "real" damage */
5363 dam = 0;
5364 quiet_dam = TRUE;
5365
5366 /* paranoia */
5367 if (Ind < 1) break;
5368
5369 /* don't affect sleeping targets maybe */
5370 if (m_ptr->csleep) break;
5371
5372 /* don't affect hurt monsters! */
5373 if (m_ptr->hp < m_ptr->maxhp) {
5374 note = " seems too agitated to be charmed";
5375 break;
5376 }
5377
5378 /* not successfully charmed? */
5379 if ((r_ptr->flags9 & RF9_IM_PSI) ||
5380 (r_ptr->flags1 & RF1_UNIQUE) ||
5381 (r_ptr->flags3 & RF3_UNDEAD) ||
5382 (r_ptr->flags2 & RF2_EMPTY_MIND) ||
5383 (r_ptr->flags3 & RF3_NONLIVING)) {
5384 note = " is unaffected";
5385 break;
5386 }
5387 if (r_ptr->flags2 & RF2_SMART) res <<= 1;
5388 if (r_ptr->flags3 & RF3_NO_CONF) res <<= 1;
5389 if (r_ptr->flags1 & RF1_UNIQUE) res <<= 1;
5390 if (r_ptr->flags2 & RF2_POWERFUL) res <<= 1;
5391 if (magik(100 - 100 / res)) {
5392 note = " resists the effect";
5393 break;
5394 }
5395
5396 /* remember who charmed us */
5397 m_ptr->charmedignore = Ind;
5398
5399 /* count our victims, just for optimization atm */
5400 p_ptr->mcharming++;
5401 note = " seems to forget you were an enemy";
5402 break;
5403 }
5404
5405 /* Earthquake the area */
5406 case GF_EARTHQUAKE:
5407 {
5408 dam = 0;
5409 break;
5410 }
5411
5412 /* Magic Missile -- pure damage */
5413 case GF_MISSILE:
5414 {
5415 if (seen) obvious = TRUE;
5416 break;
5417 }
5418
5419
5420 /* Acid */
5421 case GF_ACID:
5422 {
5423 if (seen) obvious = TRUE;
5424 if (r_ptr->flags3 & RF3_IM_ACID)
5425 {
5426 note = " is immune";
5427 dam = 0;
5428 #ifdef OLD_MONSTER_LORE
5429 if (seen) r_ptr->r_flags3 |= RF3_IM_ACID;
5430 #endif
5431 }
5432 else if (r_ptr->flags9 & RF9_RES_ACID)
5433 {
5434 note = " resists";
5435 dam /= 4;
5436 #ifdef OLD_MONSTER_LORE
5437 if (seen) r_ptr->r_flags9 |= RF9_RES_ACID;
5438 #endif
5439 }
5440 else if (r_ptr->flags9 & RF9_SUSCEP_ACID)
5441 {
5442 note = " is hit hard";
5443 dam *= 2;
5444 #ifdef OLD_MONSTER_LORE
5445 if (seen) r_ptr->r_flags9 |= RF9_SUSCEP_ACID;
5446 #endif
5447 }
5448 break;
5449 }
5450
5451 /* Electricity */
5452 case GF_ELEC:
5453 {
5454 if (seen) obvious = TRUE;
5455 if (r_ptr->flags3 & RF3_IM_ELEC)
5456 {
5457 note = " is immune";
5458 dam = 0;
5459 #ifdef OLD_MONSTER_LORE
5460 if (seen) r_ptr->r_flags3 |= RF3_IM_ELEC;
5461 #endif
5462 }
5463 else if (r_ptr->flags9 & RF9_RES_ELEC)
5464 {
5465 note = " resists";
5466 dam /= 4;
5467 #ifdef OLD_MONSTER_LORE
5468 if (seen) r_ptr->r_flags9 |= RF9_RES_ELEC;
5469 #endif
5470 }
5471 else if (r_ptr->flags9 & RF9_SUSCEP_ELEC)
5472 {
5473 note = " is hit hard";
5474 dam *= 2;
5475 #ifdef OLD_MONSTER_LORE
5476 if (seen) r_ptr->r_flags9 |= RF9_SUSCEP_ELEC;
5477 #endif
5478 }
5479 break;
5480 }
5481
5482 /* Fire damage */
5483 case GF_FIRE:
5484 {
5485 if (seen) obvious = TRUE;
5486 if (r_ptr->flags3 & RF3_IM_FIRE)
5487 {
5488 note = " is immune";
5489 dam = 0;
5490 #ifdef OLD_MONSTER_LORE
5491 if (seen) r_ptr->r_flags3 |= RF3_IM_FIRE;
5492 #endif
5493 }
5494 else if (r_ptr->flags9 & RF9_RES_FIRE)
5495 {
5496 note = " resists";
5497 dam /= 4;
5498 #ifdef OLD_MONSTER_LORE
5499 if (seen) r_ptr->r_flags9 |= RF9_RES_FIRE;
5500 #endif
5501 }
5502 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
5503 {
5504 note = " is hit hard";
5505 dam *= 2;
5506 #ifdef OLD_MONSTER_LORE
5507 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_FIRE;
5508 #endif
5509 }
5510 break;
5511 }
5512
5513 /* Cold */
5514 case GF_COLD:
5515 {
5516 if (seen) obvious = TRUE;
5517 if (r_ptr->flags3 & RF3_IM_COLD)
5518 {
5519 note = " is immune";
5520 dam = 0;
5521 #ifdef OLD_MONSTER_LORE
5522 if (seen) r_ptr->r_flags3 |= RF3_IM_COLD;
5523 #endif
5524 }
5525 else if (r_ptr->flags9 & RF9_RES_COLD)
5526 {
5527 note = " resists";
5528 dam /= 4;
5529 #ifdef OLD_MONSTER_LORE
5530 if (seen) r_ptr->r_flags9 |= RF9_RES_COLD;
5531 #endif
5532 }
5533 else if (r_ptr->flags3 & RF3_SUSCEP_COLD)
5534 {
5535 note = " is hit hard";
5536 dam *= 2;
5537 #ifdef OLD_MONSTER_LORE
5538 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_COLD;
5539 #endif
5540 }
5541 break;
5542 }
5543
5544 /* Poison */
5545 case GF_POIS:
5546 {
5547 if (seen) obvious = TRUE;
5548 if ((r_ptr->flags3 & RF3_IM_POIS) ||
5549 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
5550 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
5551 {
5552 note = " is immune";
5553 dam = 0;
5554 #ifdef OLD_MONSTER_LORE
5555 if (seen) r_ptr->r_flags3 |= RF3_IM_POIS;
5556 #endif
5557 }
5558 else if (r_ptr->flags9 & RF9_RES_POIS)
5559 {
5560 note = " resists";
5561 dam /= 4;
5562 #ifdef OLD_MONSTER_LORE
5563 if (seen) r_ptr->r_flags9 |= RF9_RES_POIS;
5564 #endif
5565 }
5566 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
5567 {
5568 note = " is hit hard";
5569 dam *= 2;
5570 #ifdef OLD_MONSTER_LORE
5571 if (seen) r_ptr->r_flags9 |= RF9_SUSCEP_POIS;
5572 #endif
5573 }
5574 break;
5575 }
5576
5577 /* Thick Poison */
5578 case GF_UNBREATH:
5579 {
5580 if (seen) obvious = TRUE;
5581 // if (magik(15)) do_pois = (10 + randint(11) + r) / (r + 1);
5582 if ((r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
5583 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)) ||
5584 (m_ptr->r_idx == RI_MORGOTH)) /* <- Morgoth */
5585 {
5586 note = " is immune";
5587 dam = 0;
5588 // do_pois = 0;
5589 }
5590 else if (r_ptr->flags3 & RF3_IM_POIS)
5591 {
5592 note = " resists";
5593 dam = (dam * 2) / 4;
5594 #ifdef OLD_MONSTER_LORE
5595 if (seen) r_ptr->r_flags3 |= RF3_IM_POIS;
5596 #endif
5597 }
5598 else if (r_ptr->flags9 & RF9_RES_POIS)
5599 {
5600 note = " resists slightly";
5601 dam = (dam * 3) / 4;
5602 #ifdef OLD_MONSTER_LORE
5603 if (seen) r_ptr->r_flags9 |= RF9_RES_POIS;
5604 #endif
5605 }
5606 #if 0
5607 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
5608 {
5609 note = " is hit hard";
5610 dam *= 2;
5611 #ifdef OLD_MONSTER_LORE
5612 if (seen) r_ptr->r_flags9 |= RF9_SUSCEP_POIS;
5613 #endif
5614 }
5615 #endif
5616 break;
5617 }
5618
5619 case GF_HELL_FIRE:
5620 {
5621 if (seen) obvious = TRUE;
5622 if (r_ptr->flags3 & (RF3_GOOD))
5623 {
5624 if (r_ptr->flags3 & RF3_IM_FIRE)
5625 {
5626 note = " resists";
5627 dam *= 2; dam /= 2;//(randint(4)+3);
5628 #ifdef OLD_MONSTER_LORE
5629 if (seen) r_ptr->r_flags3 |= RF3_IM_FIRE;
5630 #endif
5631 }
5632 else if (r_ptr->flags9 & RF9_RES_FIRE)
5633 {
5634 note = " is hit";
5635 dam = (dam * 3) / 2;
5636 #ifdef OLD_MONSTER_LORE
5637 if (seen) r_ptr->r_flags9 |= RF9_RES_FIRE;
5638 #endif
5639 }
5640 #if 0
5641 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
5642 {
5643 note = " is hit hard";
5644 dam *= 2;
5645 #ifdef OLD_MONSTER_LORE
5646 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_FIRE;
5647 #endif
5648 }
5649 #endif
5650 else
5651 {
5652 dam *= 2;
5653 note = " is hit hard";
5654 //note = " is hit";
5655 }
5656 #ifdef OLD_MONSTER_LORE
5657 if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
5658 #endif
5659 }
5660 else
5661 {
5662 if (r_ptr->flags3 & RF3_IM_FIRE)
5663 {
5664 note = " resists a lot";
5665 dam *= 2; dam /= 4;//(randint(6)+10);
5666 #ifdef OLD_MONSTER_LORE
5667 if (seen) r_ptr->r_flags3 |= RF3_IM_FIRE;
5668 #endif
5669 }
5670 else if (r_ptr->flags9 & RF9_RES_FIRE)
5671 {
5672 note = " resists";
5673 dam = (dam * 3) / 4;
5674 #ifdef OLD_MONSTER_LORE
5675 if (seen) r_ptr->r_flags9 |= RF9_RES_FIRE;
5676 #endif
5677 }
5678 #if 0
5679 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
5680 {
5681 note = " resists slightly";
5682 dam /= 2;
5683 #ifdef OLD_MONSTER_LORE
5684 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_FIRE;
5685 #endif
5686 }
5687 #endif
5688 else
5689 {
5690 note = " is hit";
5691 //dam *= 5; dam /= (randint(3)+4);
5692 }
5693 }
5694 if (r_ptr->flags3 & (RF3_EVIL)) dam = (dam * 2) / 3;
5695 break;
5696 }
5697
5698 /* Holy Orb -- hurts Evil */
5699 case GF_HOLY_ORB:
5700 {
5701 if (seen) obvious = TRUE;
5702 if (r_ptr->flags3 & (RF3_GOOD))
5703 {
5704 dam = 0;
5705 note = " is immune";
5706 #ifdef OLD_MONSTER_LORE
5707 if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
5708 #endif
5709 }
5710 if (r_ptr->flags3 & RF3_EVIL)
5711 {
5712 note = " is hit hard";
5713 dam *= 2;
5714 #ifdef OLD_MONSTER_LORE
5715 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
5716 #endif
5717 }
5718 break;
5719 }
5720
5721 /* Holy Fire -- hurts Evil, Good are immune, others _resist_ */
5722 case GF_HOLY_FIRE:
5723 {
5724 if (seen) obvious = TRUE;
5725 if (r_ptr->flags3 & (RF3_GOOD)) {
5726 dam = 0;
5727 note = " is immune";
5728 #ifdef OLD_MONSTER_LORE
5729 if (seen) r_ptr->r_flags3 |= (RF3_GOOD);
5730 #endif
5731 } else if (r_ptr->flags3 & (RF3_EVIL)) {
5732 if (r_ptr->flags3 & RF3_IM_FIRE) {
5733 note = " resists";
5734 dam *= 2; dam = (dam * 2) / 3;//(randint(4)+3);
5735 #ifdef OLD_MONSTER_LORE
5736 if (seen) r_ptr->r_flags3 |= RF3_IM_FIRE;
5737 #endif
5738 } else if (r_ptr->flags9 & RF9_RES_FIRE) {
5739 note = " is hit";
5740 dam = (dam * 6) / 4;
5741 #ifdef OLD_MONSTER_LORE
5742 if (seen) r_ptr->r_flags9 |= RF9_RES_FIRE;
5743 #endif
5744 }
5745 #if 0
5746 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE) {
5747 note = " is hit hard";
5748 dam *= 2;
5749 #ifdef OLD_MONSTER_LORE
5750 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_FIRE;
5751 #endif
5752 }
5753 #endif
5754 else {
5755 dam *= 2;
5756 note = " is hit hard";
5757 //note = " is hit";
5758 }
5759 #ifdef OLD_MONSTER_LORE
5760 if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
5761 #endif
5762 } else {
5763 if (r_ptr->flags3 & RF3_IM_FIRE) {
5764 note = " resists a lot";
5765 dam *= 2; dam /= 3;//(randint(6)+10);
5766 #ifdef OLD_MONSTER_LORE
5767 if (seen) r_ptr->r_flags3 |= RF3_IM_FIRE;
5768 #endif
5769 } else if (r_ptr->flags9 & RF9_RES_FIRE) {
5770 note = " resists";
5771 dam = (dam * 3) / 4;
5772 #ifdef OLD_MONSTER_LORE
5773 if (seen) r_ptr->r_flags9 |= RF9_RES_FIRE;
5774 #endif
5775 }
5776 #if 0
5777 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE) {
5778 note = " resists slightly";
5779 dam /= 2;
5780 #ifdef OLD_MONSTER_LORE
5781 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_FIRE;
5782 #endif
5783 }
5784 #endif
5785 else {
5786 note = " resists somewhat";
5787 // dam *= 5; dam /= (randint(3)+4);
5788 }
5789 }
5790 break;
5791 }
5792
5793 /* Arrow -- XXX no defense */
5794 case GF_ARROW:
5795 {
5796 if (seen) obvious = TRUE;
5797 break;
5798 }
5799
5800 /* Plasma -- Fire/Elec/Force */
5801 case GF_PLASMA:
5802 {
5803 if (seen) obvious = TRUE;
5804
5805 do_stun = randint(15) / div;
5806
5807 if ((r_ptr->flags3 & RF3_IM_FIRE) && (r_ptr->flags3 & RF3_IM_ELEC)) {
5808 note = " resists a lot";
5809 dam /= 9;
5810 } else {
5811 if (r_ptr->flags3 & RF3_IM_FIRE) {
5812 note = " resists a lot";
5813 dam /= 4;
5814 } else if (prefix(name, "Plasma") ||
5815 (r_ptr->flags4 & RF4_BR_PLAS) ||
5816 (r_ptr->flags3 & RF3_RES_PLAS)) {
5817 note = " resists";
5818 dam *= 3; dam /= (randint(6) + 6);
5819 } else if (r_ptr->flags9 & RF9_RES_FIRE) {
5820 note = " resists somewhat";
5821 dam *= 3;
5822 dam /= 5;
5823 } else if (r_ptr->flags3 & RF3_SUSCEP_FIRE) {
5824 note = " is hit hard";
5825 dam = (dam * 3) / 2;
5826 }
5827
5828 if ((r_ptr->flags9 & RF9_RES_ELEC) || (r_ptr->flags3 & RF3_IM_ELEC)) {
5829 dam *= 4;
5830 dam /= 5;
5831 } else if (r_ptr->flags9 & RF9_SUSCEP_ELEC) dam = (dam * 4) / 3;
5832 }
5833
5834 //todo maybe: stun effect? might be op?
5835
5836 break;
5837 }
5838
5839 /* Nether -- see above */
5840 case GF_NETHER_WEAK:
5841 case GF_NETHER:
5842 if (seen) obvious = TRUE;
5843 if (r_ptr->flags3 & RF3_UNDEAD) {
5844 note = " is immune";
5845 dam = 0;
5846 #ifdef OLD_MONSTER_LORE
5847 if (seen) r_ptr->r_flags3 |= RF3_UNDEAD;
5848 #endif
5849 } else if ((r_ptr->flags4 & RF4_BR_NETH) || (r_ptr->flags3 & RF3_RES_NETH)) {
5850 note = " resists";
5851 dam *= 3; dam /= (randint(6) + 6);
5852 }
5853 // else if (r_ptr->flags3 & RF3_EVIL)
5854 else if (r_ptr->flags3 & RF3_DEMON) {
5855 dam /= 2;
5856 note = " resists somewhat";
5857 #ifdef OLD_MONSTER_LORE
5858 // if (seen) r_ptr->r_flags3 |= RF3_EVIL;
5859 if (seen) r_ptr->r_flags3 |= RF3_DEMON;
5860 #endif
5861 }
5862 break;
5863
5864 /* Water (acid) damage -- Water spirits/elementals are immune */
5865 case GF_WATER:
5866 case GF_VAPOUR:
5867 {
5868 if (seen) obvious = TRUE;
5869 if (r_ptr->flags9 & RF9_IM_WATER) {
5870 note = " is immune";
5871 dam = 0;
5872 } else if (r_ptr->flags7 & RF7_AQUATIC) {
5873 note = " resists a lot";
5874 dam /= 9;
5875 } else if (r_ptr->flags3 & RF3_RES_WATE) {
5876 note = " resists";
5877 dam /= 4;
5878 }
5879 break;
5880 }
5881
5882 /* Wave = Water + Force */
5883 case GF_WAVE:
5884 {
5885 if (seen) obvious = TRUE;
5886 if (r_ptr->flags9 & RF9_IM_WATER) {
5887 note = " is immune";
5888 dam = 0;
5889 } else if (r_ptr->flags7 & RF7_AQUATIC) {
5890 note = " resists a lot";
5891 dam /= 9;
5892 } else if (r_ptr->flags3 & RF3_RES_WATE) {
5893 note = " resists";
5894 dam /= 4;
5895 } else do_stun = randint(15) / div;
5896 break;
5897 }
5898
5899 /* Chaos -- Chaos breathers resist */
5900 case GF_CHAOS:
5901 {
5902 if (seen) obvious = TRUE;
5903 if (rand_int(r_ptr->level) < 15) do_poly = TRUE;
5904 do_conf = (5 + randint(11)) / div;
5905 if ((r_ptr->flags4 & RF4_BR_CHAO) || (r_ptr->flags9 & RF9_RES_CHAOS)) {
5906 note = " resists";
5907 dam *= 3; dam /= randint(6) + 6;
5908 do_poly = FALSE;
5909 }
5910 break;
5911 }
5912
5913 /* Shards -- Shard breathers resist */
5914 case GF_SHARDS:
5915 if (seen) obvious = TRUE;
5916 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS)) {
5917 note = " resists";
5918 dam *= 3; dam /= (randint(6) + 6);
5919 }
5920 break;
5921
5922 /* Rocket: Shard resistance helps (PernA) */
5923 case GF_INFERNO:
5924 case GF_DETONATION:
5925 case GF_ROCKET:
5926 #if 0
5927 // if (magik(12)) do_cut = (10 + randint(15) +r) / (r + 1);
5928 if ((r_ptr->flags4 & (RF4_BR_SHAR)) || (r_ptr->flags9 & RF9_RES_SHARDS) ||
5929 (r_ptr->flags3 & RF3_IM_FIRE) || prefix(name, "Plasma") ||
5930 (r_ptr->flags4 & RF4_BR_PLAS) || (r_ptr->flags3 & RF3_RES_PLAS) ||
5931 (r_ptr->flags9 & RF9_RES_FIRE)) {
5932 note = " resists somewhat";
5933 dam /= 2;
5934 // do_cut = 0;
5935 }
5936 #else /* more distinct */
5937 {
5938 int res1 = 0, res2 = 0, res3 = 0; //shard,sound,fire
5939 if ((r_ptr->flags4 & (RF4_BR_SHAR)) || (r_ptr->flags9 & RF9_RES_SHARDS))
5940 res1 = 1;
5941 if ((r_ptr->flags4 & RF4_BR_PLAS) || (r_ptr->flags3 & RF3_RES_PLAS) || prefix(name, "Plasma")) {
5942 res2 = res3 = 1;
5943 }
5944 if ((r_ptr->flags4 & (RF4_BR_SOUN)) || (r_ptr->flags9 & RF9_RES_SOUND))
5945 res2 = 1;
5946 if (r_ptr->flags3 & RF3_IM_FIRE)
5947 res3 = 3;
5948 else if (r_ptr->flags9 & RF9_RES_FIRE)
5949 res3 = 1;
5950
5951 switch (res1 + res2 + res3) {
5952 case 0: break;
5953 case 1: case 2:
5954 note = " resists somewhat";
5955 dam = (dam * 3 + 3) / 4;
5956 // do_cut = 0;
5957 break;
5958 default:
5959 note = " resists";
5960 dam /= 2;
5961 break;
5962 }
5963 }
5964 #endif
5965 if (seen) obvious = TRUE;
5966 break;
5967
5968 /* Sound -- Sound breathers resist */
5969 case GF_STUN:
5970 do_stun = (10 + randint(15)) / div;
5971 break;
5972
5973 /* Sound -- Sound breathers resist */
5974 case GF_SOUND:
5975 if (seen) obvious = TRUE;
5976 do_stun = randint(15) / div;
5977 if ((r_ptr->flags4 & RF4_BR_SOUN) || (r_ptr->flags9 & RF9_RES_SOUND)) {
5978 note = " resists";
5979 dam *= 3; dam /= (randint(6) + 6);
5980 } else if (r_ptr->flags3 & RF3_NO_STUN) {
5981 note = " resists somewhat";
5982 dam /= 2;
5983 }
5984 break;
5985
5986 /* Confusion */
5987 case GF_CONFUSION:
5988 if (seen) obvious = TRUE;
5989 do_conf = (10 + randint(15)) / div;
5990 if ((r_ptr->flags4 & RF4_BR_CONF) ||
5991 (r_ptr->flags4 & RF4_BR_CHAO) || (r_ptr->flags9 & RF9_RES_CHAOS)) {
5992 note = " resists";
5993 dam *= 3; dam /= (randint(6) + 6);
5994 } else if (r_ptr->flags3 & RF3_NO_CONF) {
5995 note = " resists somewhat";
5996 dam /= 2;
5997 }
5998 break;
5999
6000 /* Disenchantment -- Breathers and Disenchanters resist */
6001 case GF_DISENCHANT:
6002 {
6003 if (seen) obvious = TRUE;
6004 if ((r_ptr->flags4 & RF4_BR_DISE) ||
6005 prefix(name, "Disen") ||
6006 (r_ptr->flags3 & RF3_RES_DISE)) {
6007 note = " resists";
6008 dam *= 3; dam /= (randint(6) + 6);
6009 }
6010 break;
6011 }
6012
6013 /* Nexus -- Breathers and Existers resist */
6014 case GF_NEXUS:
6015 {
6016 if (seen) obvious = TRUE;
6017 if ((r_ptr->flags4 & RF4_BR_NEXU) ||
6018 prefix(name, "Nexus") ||
6019 (r_ptr->flags3 & RF3_RES_NEXU))
6020 {
6021 note = " resists";
6022 dam *= 3; dam /= (randint(6) + 6);
6023 }
6024 break;
6025 }
6026
6027 /* Force */
6028 case GF_FORCE:
6029 {
6030 if (seen) obvious = TRUE;
6031 do_stun = randint(15) / div;
6032 if (r_ptr->flags4 & RF4_BR_WALL) {
6033 note = " resists";
6034 dam *= 3; dam /= (randint(6) + 6);
6035 }
6036 break;
6037 }
6038
6039 /* Inertia -- breathers resist */
6040 case GF_INERTIA: //Slowing effect -- NOTE: KEEP CONSISTENT WITH GF_CURSE AND GF_OLD_SLOW
6041 {
6042 if (seen) obvious = TRUE;
6043 if (r_ptr->flags4 & RF4_BR_INER) {
6044 note = " resists";
6045 dam *= 3; dam /= (randint(6) + 6);
6046 }
6047 /* Powerful monsters can resist */
6048 else if (r_ptr->flags1 & RF1_UNIQUE) {
6049 } else if (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) + 10) { /* cannot randint higher? (see 'resist' branch below) */
6050 } else if (RES_OLD(r_ptr->level, dam)) {
6051 } else if (m_ptr->mspeed >= 100 && m_ptr->mspeed > m_ptr->speed - 10) /* Normal monsters slow down */
6052 // else if (m_ptr->mspeed >= 100) /* Normal monsters slow down */
6053 {
6054 // if (m_ptr->mspeed > 100) m_ptr->mspeed -= 10;
6055 m_ptr->mspeed -= 10;
6056 note = " starts moving slower";
6057 }
6058
6059 break;
6060 }
6061
6062 /* Time -- breathers resist */
6063 case GF_TIME:
6064 {
6065 if (seen) obvious = TRUE;
6066 if ((r_ptr->flags4 & RF4_BR_TIME) || (r_ptr->flags9 & RF9_RES_TIME)
6067 || (r_ptr->flags3 & RF3_DEMON) || (r_ptr->flags3 & RF3_NONLIVING)
6068 || (r_ptr->flags3 & RF3_UNDEAD) || (r_ptr->d_char == 'A'))
6069 {
6070 note = " resists";
6071 dam *= 3; dam /= (randint(6) + 6);
6072 }
6073 #if 1 /* fixed & sanified */
6074 else if (!quiet && rand_int(3) == 0) { /* only occur if a player cast this */
6075 long t = m_ptr->hp / 10, tp = damroll(2, plev);
6076
6077 note = " loses precious seconds to you";
6078 m_ptr->energy -= m_ptr->energy / 4;
6079
6080 if (t > dam) t = dam;
6081 if (t > tp) t = tp;
6082 p_ptr->energy += (t * level_speed(&p_ptr->wpos)) / 500;
6083 /* Prevent too much energy, preventing overflow too. */
6084 limit_energy(p_ptr);
6085 }
6086 #endif
6087 break;
6088 }
6089
6090 /* Gravity -- breathers resist */
6091 case GF_GRAVITY:
6092 {
6093 bool resist_tele = FALSE;
6094 // dun_level *l_ptr = getfloor(wpos);
6095
6096 if (seen) obvious = TRUE;
6097
6098 if ((r_ptr->flags3 & RF3_RES_TELE) || (r_ptr->flags9 & RF9_IM_TELE)) {
6099 if ((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags9 & RF9_IM_TELE)) {
6100 #ifdef OLD_MONSTER_LORE
6101 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6102 #endif
6103 note = " resists";
6104 resist_tele = TRUE;
6105 } else if (m_ptr->level > randint(100)) {
6106 #ifdef OLD_MONSTER_LORE
6107 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6108 #endif
6109 note = " resists";
6110 resist_tele = TRUE;
6111 }
6112 }
6113
6114 if (!resist_tele) do_dist = 10;
6115 else do_dist = 0;
6116
6117 if ((r_ptr->flags4 & RF4_BR_GRAV) ||
6118 (r_ptr->flags7 & RF7_CAN_FLY)) {
6119 note = " resists";
6120 dam *= 3; dam /= (randint(6) + 6);
6121 do_dist = 0;
6122 }
6123
6124 //todo maybe: stun effect? might be op?
6125
6126 break;
6127 }
6128
6129 /* Pure damage */
6130 case GF_MANA:
6131 {
6132 if (r_ptr->flags9 & RF9_RES_MANA) {
6133 dam /= 3;
6134 note = " resists";
6135 } else if (r_ptr->flags4 & RF4_BR_MANA) {
6136 dam /= 2;
6137 note = " resists somewhat";
6138 }
6139 if (seen) obvious = TRUE;
6140 break;
6141 }
6142
6143 /* Meteor -- powerful magic missile */
6144 case GF_METEOR:
6145 {
6146 if (seen) obvious = TRUE;
6147 do_stun = randint(15) / div;
6148 break;
6149 }
6150
6151 /* Ice -- Cold + Cuts + Stun */
6152 case GF_ICE:
6153 {
6154 if (seen) obvious = TRUE;
6155 do_stun = randint(15) / div;
6156 k = dam;
6157
6158 dam = (k * 3) / 5;/* 60% COLD damage */
6159 if (r_ptr->flags3 & RF3_IM_COLD)
6160 {
6161 note = " is immune to cold";
6162 dam = 0;
6163 #ifdef OLD_MONSTER_LORE
6164 if (seen) r_ptr->r_flags3 |= RF3_IM_COLD;
6165 #endif
6166 }
6167 else if (r_ptr->flags9 & RF9_RES_COLD)
6168 {
6169 note = " resists cold";
6170 dam /= 4;
6171 #ifdef OLD_MONSTER_LORE
6172 if (seen) r_ptr->r_flags9 |= RF9_RES_COLD;
6173 #endif
6174 }
6175 else if (r_ptr->flags3 & RF3_SUSCEP_COLD)
6176 {
6177 note = " is hit hard by cold";
6178 dam *= 2;
6179 #ifdef OLD_MONSTER_LORE
6180 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_COLD;
6181 #endif
6182 }
6183
6184 k = (k * 2) / 5;/* 40% SHARDS damage */
6185 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS))
6186 {
6187 //note = " resists";
6188 k = (k * 3) / (randint(6) + 6);
6189 }
6190 dam = dam + k;
6191 break;
6192 }
6193
6194 /* Thunder -- Elec + Sound + Light */
6195 case GF_THUNDER:
6196 {
6197 if (seen) obvious = TRUE;
6198
6199 k_elec = dam / 3; /* 33% ELEC damage */
6200 if (r_ptr->flags3 & RF3_IM_ELEC)
6201 {
6202 note = " is immune to lightning";
6203 k_elec = 0;
6204 #ifdef OLD_MONSTER_LORE
6205 if (seen) r_ptr->r_flags3 |= RF3_IM_ELEC;
6206 #endif
6207 }
6208 else if (r_ptr->flags9 & RF9_RES_ELEC)
6209 {
6210 note = " resists lightning";
6211 k_elec /= 4;
6212 #ifdef OLD_MONSTER_LORE
6213 if (seen) r_ptr->r_flags9 |= RF9_RES_ELEC;
6214 #endif
6215 }
6216 else if (r_ptr->flags9 & RF9_SUSCEP_ELEC)
6217 {
6218 note = " is hit hard by lightning";
6219 k_elec *= 2;
6220 #ifdef OLD_MONSTER_LORE
6221 if (seen) r_ptr->r_flags3 |= RF3_SUSCEP_ELEC;
6222 #endif
6223 }
6224
6225 k_sound = dam / 3; /* 33% SOUND damage */
6226 do_stun = randint(15) / div;
6227 if ((r_ptr->flags4 & RF4_BR_SOUN) || (r_ptr->flags9 & RF9_RES_SOUND))
6228 {
6229 //note = " resists";
6230 k_sound *= 3;
6231 k_sound /= (randint(6) + 6);
6232 }
6233
6234 k_lite = dam / 3; /* 33% LIGHT damage */
6235 do_blind = damroll(3, (k_lite / 20)) + 1;
6236 if (r_ptr->d_char == 'A') {
6237 //note = " is immune";
6238 k_lite = do_blind = 0;
6239 } else if ((r_ptr->flags4 & RF4_BR_LITE) || (r_ptr->flags9 & RF9_RES_LITE)) {
6240 //note = " resists";
6241 k_lite *= 2;
6242 k_lite /= (randint(6) + 6);
6243 do_blind = 0;
6244 } else if (r_ptr->flags3 & RF3_HURT_LITE) {
6245 #ifdef OLD_MONSTER_LORE
6246 if (seen) r_ptr->r_flags3 |= RF3_HURT_LITE;
6247 #endif
6248 //note = " cringes from the light";
6249 //note_dies = " shrivels away in the light";
6250 dam *= 2;
6251 }
6252
6253 dam = k_elec + k_sound + k_lite;
6254 break;
6255 }
6256
6257 /* Drain Life */
6258 case GF_OLD_DRAIN:
6259 if (seen) obvious = TRUE;
6260
6261 /* Prevent internal overflow (int) - allow up to 35% leech */
6262 if (m_ptr->hp > 9362)
6263 dam = (m_ptr->hp / 100) * dam;
6264 else if (m_ptr->hp > 936)
6265 dam = ((m_ptr->hp / 10) * dam) / 10;
6266 else
6267 dam = (m_ptr->hp * dam) / 100;
6268 /* Make it have an effect on low-HP monsters such as townies */
6269 if (!dam) dam = 1;
6270
6271 if (typ == GF_OLD_DRAIN) p_ptr->ret_dam = dam;
6272 else p_ptr->ret_dam = 0; /* paranoia */
6273
6274 if ((r_ptr->flags3 & RF3_UNDEAD) ||
6275 // (r_ptr->flags3 & RF3_DEMON) ||
6276 (r_ptr->flags3 & RF3_NONLIVING) ||
6277 (r_ptr->flags1 & RF1_UNIQUE) ||
6278 (strchr("Egv", r_ptr->d_char)))
6279 {
6280 #ifdef OLD_MONSTER_LORE
6281 if (r_ptr->flags3 & RF3_UNDEAD) {
6282 if (seen) r_ptr->r_flags3 |= RF3_UNDEAD;
6283 }
6284 // if (r_ptr->flags3 & RF3_DEMON) {
6285 // if (seen) r_ptr->r_flags3 |= RF3_DEMON;
6286 // }
6287 if (r_ptr->flags3 & RF3_NONLIVING) {
6288 if (seen) r_ptr->r_flags3 |= RF3_NONLIVING;
6289 }
6290 if (r_ptr->flags1 & RF1_UNIQUE) {
6291 if (seen) r_ptr->r_flags1 |= RF1_UNIQUE;
6292 }
6293 #endif
6294
6295 note = " is unaffected";
6296 obvious = FALSE;
6297 dam = 0;
6298 quiet_dam = TRUE;
6299 p_ptr->ret_dam = 0;
6300 }
6301
6302 /* the_sandman: return 15% of the damage to player. This is special
6303 since (we're not using the upto 35% rule because for the spell
6304 (drain cloud) it will be too much) we aim for balance
6305 HACK: the priest_spell variable is defined above.
6306 */
6307 if (priest_spell) {
6308 //msg_format(Ind, "\377gYou are healed for %d hit points", (dam * 15) / 100);
6309 if (dam) hp_player_quiet(Ind, (dam * 15) / 100, TRUE);
6310 p_ptr->ret_dam = 0;
6311 }
6312
6313 break;
6314
6315 case GF_ANNIHILATION:
6316 i = dam - 1;
6317 if (seen) obvious = TRUE;
6318 if (m_ptr->hp > 9362)
6319 dam = (m_ptr->hp / 100) * dam;
6320 else if (m_ptr->hp > 936)
6321 dam = ((m_ptr->hp / 10) * dam) / 10;
6322 else
6323 dam = (m_ptr->hp * dam) / 100;
6324 /* Make it have an effect on low-HP monsters such as townies */
6325 if (!dam) dam = 1;
6326
6327 if (dam > i * 200) {
6328 dam = i * 200;
6329 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6330 (r_ptr->flags3 & RF3_UNDEAD) ||
6331 (r_ptr->flags3 & RF3_NONLIVING)) {
6332 note = " resists";
6333 dam *= 3; dam /= (randint(6) + 6);
6334 }
6335 }
6336
6337 if (dam < i * 10 + 100) {
6338 dam = i * 10 + 100;
6339 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6340 (r_ptr->flags3 & RF3_UNDEAD) ||
6341 (r_ptr->flags3 & RF3_NONLIVING)) {
6342 note = " resists";
6343 dam *= 3; dam /= (randint(6) + 6);
6344 }
6345 }
6346 break;
6347
6348 /* Polymorph monster (Use "dam" as "power") */
6349 case GF_OLD_POLY:
6350 if (seen) obvious = TRUE;
6351
6352 /* Attempt to polymorph (see below) */
6353 do_poly = TRUE;
6354
6355 /* Powerful monsters can resist */
6356 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6357 (r_ptr->level > randint((dam - 10) < 1 ? 1 : (dam - 10)) + 10))
6358 {
6359 note = " is unaffected";
6360 do_poly = FALSE;
6361 obvious = FALSE;
6362 }
6363
6364 /* No "real" damage */
6365 dam = 0;
6366 quiet_dam = TRUE;
6367
6368 break;
6369
6370 /* Clone monsters (Ignore "dam") */
6371 case GF_OLD_CLONE:
6372 if (seen) obvious = TRUE;
6373
6374 /* Heal fully */
6375 m_ptr->hp = m_ptr->maxhp;
6376
6377 /* Speed up */
6378 if (m_ptr->mspeed < 150) m_ptr->mspeed += 10;
6379
6380 /* Attempt to clone. */
6381 if (multiply_monster(c_ptr->m_idx)) {
6382 note = " spawns";
6383 }
6384
6385 /* No "real" damage */
6386 dam = 0;
6387 quiet_dam = TRUE;
6388
6389 break;
6390
6391 /* Heal Monster (use "dam" as amount of healing) */
6392 case GF_OLD_HEAL:
6393 {
6394 if (seen) obvious = TRUE;
6395
6396 /* Wake up */
6397 m_ptr->csleep = 0;
6398
6399 /* Heal */
6400 m_ptr->hp += dam;
6401
6402 /* No overflow */
6403 if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
6404
6405 /* Redraw (later) if needed */
6406 update_health(c_ptr->m_idx);
6407
6408 /* Message */
6409 note = " looks healthier";
6410
6411 /* No "real" damage */
6412 dam = 0;
6413 quiet_dam = TRUE;
6414 break;
6415 }
6416
6417
6418 /* Heroism/Berserk Strength for monsters */
6419 case GF_HERO_MONSTER:
6420 {
6421 if (seen) obvious = TRUE;
6422
6423 /* Wake up */
6424 m_ptr->csleep = 0;
6425
6426 /* Heal */
6427 m_ptr->hp += dam;
6428
6429 /* No overflow */
6430 if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
6431
6432 /* Redraw (later) if needed */
6433 update_health(c_ptr->m_idx);
6434
6435 /* Message */
6436 note = " looks healthier";
6437
6438 /* No "real" damage */
6439 dam = 0;
6440 quiet_dam = TRUE;
6441
6442 /* No 'break;' here =) */
6443 }
6444
6445
6446 /* Remove monster's fear */
6447 case GF_REMFEAR:
6448 {
6449 if (m_ptr->monfear) {
6450 m_ptr->monfear = 0;
6451 /* Message */
6452 note = " becomes courageous again";
6453 if (seen) obvious = TRUE;
6454 }
6455
6456 /* No "real" damage */
6457 dam = 0;
6458 quiet_dam = TRUE;
6459 break;
6460 }
6461
6462
6463 /* Speed Monster (Ignore "dam") */
6464 case GF_OLD_SPEED:
6465 if ((r_ptr->flags7 & RF7_NO_DEATH) || m_ptr->mspeed >= 150) {
6466 note = "is unaffected";
6467 } else {
6468 if (seen) obvious = TRUE;
6469
6470 /* Speed up */
6471 m_ptr->mspeed += 10;
6472 note = " starts moving faster";
6473 }
6474
6475 /* No "real" damage */
6476 dam = 0;
6477 quiet_dam = TRUE;
6478 break;
6479
6480
6481 /* Slow Monster (Use "dam" as "power") */
6482 case GF_OLD_SLOW: //Slowing effect -- NOTE: KEEP CONSISTENT WITH GF_INERTIA AND GF_CURSE
6483 {
6484 if (seen) obvious = TRUE;
6485
6486 /* Powerful monsters can resist */
6487 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6488 (r_ptr->flags4 & RF4_BR_INER)) {
6489 note = " is unaffected";
6490 obvious = FALSE;
6491 } else if (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) + 10) { /* cannot randint higher? (see 'resist' branch below) */
6492 note = " resists easily"; /* vs damaging it's "resists a lot" and vs effects it's "resists easily" :-o */
6493 obvious = FALSE;
6494 } else if (RES_OLD(r_ptr->level, dam)) {
6495 note = " resists";
6496 obvious = FALSE;
6497 }
6498 else if (m_ptr->mspeed >= 100 && m_ptr->mspeed > m_ptr->speed - 10) /* Normal monsters slow down */
6499 // else if (m_ptr->mspeed >= 100) /* Normal monsters slow down */
6500 {
6501 // if (m_ptr->mspeed > 100) m_ptr->mspeed -= 10;
6502 m_ptr->mspeed -= 10;
6503 note = " starts moving slower";
6504 } else {
6505 note = " is unaffected";
6506 obvious = FALSE;
6507 }
6508
6509 /* No "real" damage */
6510 dam = 0;
6511 quiet_dam = TRUE;
6512 break;
6513 }
6514
6515
6516 /* Sleep (Use "dam" as "power") */
6517 case GF_OLD_SLEEP:
6518 {
6519 if (seen) obvious = TRUE;
6520
6521 /* Attempt a saving throw */
6522 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6523 (r_ptr->flags3 & RF3_NO_SLEEP) ||
6524 RES_OLD(r_ptr->level, dam))
6525 {
6526 note = " resists";
6527 if (r_ptr->flags1 & RF1_UNIQUE) note = " is unaffected";
6528 /* Memorize a flag */
6529 if (r_ptr->flags3 & RF3_NO_SLEEP) {
6530 #ifdef OLD_MONSTER_LORE
6531 if (seen) r_ptr->r_flags3 |= RF3_NO_SLEEP;
6532 #endif
6533 note = " is unaffected";
6534 }
6535
6536 /* No obvious effect */
6537 obvious = FALSE;
6538 } else {
6539 /* Go to sleep (much) later */
6540 note = " falls asleep";
6541 do_sleep = GF_OLD_SLEEP_DUR;
6542 }
6543
6544 /* No "real" damage */
6545 dam = 0;
6546 quiet_dam = TRUE;
6547 break;
6548 }
6549
6550
6551 /* Confusion (Use "dam" as "power") */
6552 case GF_OLD_CONF:
6553 {
6554 if (seen) obvious = TRUE;
6555
6556 /* Get confused later */
6557 do_conf = damroll(3, (dam / 2)) + 1;
6558
6559 /* Attempt a saving throw */
6560 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6561 (r_ptr->flags3 & RF3_NO_CONF) ||
6562 RES_OLD(r_ptr->level, dam))
6563 {
6564 /* No obvious effect */
6565 note = " resists";
6566 obvious = FALSE;
6567
6568 if (r_ptr->flags1 & RF1_UNIQUE) note = " is unaffected";
6569
6570 /* Memorize a flag */
6571 if (r_ptr->flags3 & RF3_NO_CONF) {
6572 #ifdef OLD_MONSTER_LORE
6573 if (seen) r_ptr->r_flags3 |= RF3_NO_CONF;
6574 #endif
6575 note = " is unaffected";
6576 }
6577
6578 /* Resist */
6579 do_conf = 0;
6580 }
6581
6582 /* No "real" damage */
6583 dam = 0;
6584 quiet_dam = TRUE;
6585 break;
6586 }
6587
6588 /* Confusion (Use "dam" as "power") */
6589 case GF_BLIND:
6590 {
6591 if (seen) obvious = TRUE;
6592
6593 /* Get blinded later */
6594 do_blind = dam;
6595
6596 /* No "real" damage */
6597 dam = 0;
6598 quiet_dam = TRUE;
6599 break;
6600 }
6601
6602 /* The new cursing spell - basically slow/blind/conf all in one. the_sandman */
6603 /* Following the pattern, use "dam" as "power". */
6604 case GF_CURSE:
6605 {
6606 /* Assume no obvious effect */
6607 obvious = FALSE;
6608 int curse = randint(3);
6609 if (curse == 1) { //Slowing effect -- NOTE: KEEP CONSISTENT WITH GF_INERTIA AND GF_OLD_SLOW
6610 /* if (((r_ptr->flags1 & RF1_UNIQUE) && magik(r_ptr->level * 4)) ||
6611 magik(r_ptr->level * 2)) {*/
6612 if ((r_ptr->flags1 & RF1_UNIQUE) ||
6613 (r_ptr->flags4 & RF4_BR_INER)) {
6614 note = " is unaffected";
6615 } else if (RES_OLD(r_ptr->level, dam / 3)) {
6616 note = " resists";
6617 } else if (m_ptr->mspeed > 100 && m_ptr->mspeed > m_ptr->speed - 10) {
6618 m_ptr->mspeed -= 10;
6619 note = " starts moving slower";
6620 if (seen) obvious = TRUE;
6621 } else {
6622 note = " is unaffected";
6623 }
6624 dam = 0;
6625 quiet_dam = TRUE;
6626 break;
6627 } else if (curse == 2) { //Conf
6628 /* Get confused later */
6629 do_conf = damroll(3, (dam / 2)) + 1;
6630
6631 /* Attempt a saving throw */
6632 if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags3 & RF3_NO_CONF) ||
6633 RES_OLD(r_ptr->level, dam / 3))
6634 {
6635 note = " resists";
6636 if (r_ptr->flags1 & RF1_UNIQUE) note = " is unaffected";
6637
6638 /* Memorize a flag */
6639 if (r_ptr->flags3 & RF3_NO_CONF) {
6640 #ifdef OLD_MONSTER_LORE
6641 if (seen) r_ptr->r_flags3 |= RF3_NO_CONF;
6642 #endif
6643 note = " is unaffected";
6644 }
6645 /* Resist */
6646 do_conf = 0;
6647 }
6648 //let's do some actual damage, too?
6649 // dam = 0;
6650 // quiet_dam = TRUE;
6651 break;
6652 } else { //Blind
6653 do_blind = dam;
6654 dam = 0;
6655 quiet_dam = TRUE;
6656 /* No obvious effect */
6657 obvious = FALSE;
6658 }
6659 break;
6660 }
6661
6662 /* Healing Cloud damages undead beings - the_sandman */
6663 case GF_HEALINGCLOUD:
6664 {
6665 if (r_ptr->flags3 & RF3_UNDEAD) {
6666 #ifdef OLD_MONSTER_LORE
6667 if (seen) r_ptr->r_flags3 |= RF3_UNDEAD;
6668 #endif
6669 if (seen) obvious = TRUE;
6670 note = " crackles in the light";
6671 note_dies = " evaporates into thin air";
6672 } else {
6673 dam = 0;
6674 quiet = TRUE;
6675 }
6676 break;
6677 }
6678
6679 /* Vapour + poison ownage - the_sandman */
6680 case GF_WATERPOISON:
6681 {
6682 switch (randint(2)) {
6683 case 1: { // Poison!
6684 if (seen) obvious = TRUE;
6685 if ((r_ptr->flags3 & RF3_IM_POIS) ||
6686 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
6687 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
6688 {
6689 note = " is immune";
6690 dam = 0;
6691 #ifdef OLD_MONSTER_LORE
6692 if (seen) r_ptr->r_flags3 |= RF3_IM_POIS;
6693 #endif
6694 } else if (r_ptr->flags9 & RF9_RES_POIS) {
6695 note = " resists";
6696 dam /= 4;
6697 #ifdef OLD_MONSTER_LORE
6698 if (seen) r_ptr->flags9 |= RF9_RES_POIS;
6699 #endif
6700 } else if (r_ptr->flags9 & RF9_SUSCEP_POIS) {
6701 note = " is hit hard";
6702 dam *= 2;
6703 #ifdef OLD_MONSTER_LORE
6704 if (seen) r_ptr->flags9 |= RF9_SUSCEP_POIS;
6705 #endif
6706 }
6707 break;
6708 }
6709 default: { // Water
6710 if (seen) obvious = TRUE;
6711 if (r_ptr->flags9 & RF9_IM_WATER) {
6712 note = " is immune";
6713 dam = 0;
6714 } else if (r_ptr->flags7 & RF7_AQUATIC) {
6715 note = " resists a lot";
6716 dam /= 9;
6717 } else if (r_ptr->flags3 & RF3_RES_WATE) {
6718 note = " resists";
6719 dam /= 4;
6720 }
6721 break;
6722 }
6723 }
6724 break;
6725 }
6726
6727 /* Random between ice (shards+water) and poison. At the moment its 3:1:1 shards:water:poison chance
6728 - the_sandman */
6729 case GF_ICEPOISON:
6730 {
6731 switch (randint(5)) {
6732 case 1: // Shards
6733 case 3:
6734 case 5: {
6735 if (seen) obvious = TRUE;
6736 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS))
6737 {
6738 note = " resists";
6739 dam *= 3; dam /= (randint(6) + 6);
6740 }
6741 break;
6742 }
6743 case 2: { // Water
6744 if (seen) obvious = TRUE;
6745 if (r_ptr->flags9 & RF9_IM_WATER) {
6746 note = " is immune";
6747 dam = 0;
6748 } else if (r_ptr->flags7 & RF7_AQUATIC) {
6749 note = " resists a lot";
6750 dam /= 9;
6751 } else if (r_ptr->flags3 & RF3_RES_WATE) {
6752 note = " resists";
6753 dam /= 4;
6754 }
6755 break;
6756 }
6757 default: { // Poison
6758 if (seen) obvious = TRUE;
6759 if ((r_ptr->flags3 & RF3_IM_POIS) ||
6760 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
6761 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
6762 {
6763 note = " is immune";
6764 dam = 0;
6765 #ifdef OLD_MONSTER_LORE
6766 if (seen) r_ptr->r_flags3 |= RF3_IM_POIS;
6767 #endif
6768 }
6769 else if (r_ptr->flags9 & RF9_RES_POIS)
6770 {
6771 note = " resists";
6772 dam /= 4;
6773 #ifdef OLD_MONSTER_LORE
6774 if (seen) r_ptr->r_flags9 |= RF9_RES_POIS;
6775 #endif
6776 }
6777 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
6778 {
6779 note = " is hit hard";
6780 dam *= 2;
6781 #ifdef OLD_MONSTER_LORE
6782 if (seen) r_ptr->r_flags9 |= RF9_SUSCEP_POIS;
6783 #endif
6784 }
6785 break;
6786 }
6787 }
6788 break;
6789 }
6790
6791 /* Lite, but only hurts susceptible creatures */
6792 case GF_LITE_WEAK:
6793 {
6794 /* Hurt by light */
6795 if (r_ptr->flags3 & RF3_HURT_LITE) {
6796 /* Obvious effect */
6797 if (seen) obvious = TRUE;
6798
6799 #ifdef OLD_MONSTER_LORE
6800 /* Memorize the effects */
6801 if (seen) r_ptr->r_flags3 |= RF3_HURT_LITE;
6802 #endif
6803
6804 /* Special effect */
6805 note = " cringes from the light";
6806 note_dies = " shrivels away in the light";
6807 }
6808
6809 /* Normally no damage */
6810 else {
6811 /* No damage */
6812 dam = 0;
6813 quiet = TRUE;
6814 }
6815
6816 break;
6817 }
6818
6819
6820
6821 /* Lite -- opposite of Dark */
6822 case GF_LITE:
6823 {
6824 if (seen) obvious = TRUE;
6825
6826 /* Get blinded later */
6827 do_blind = damroll(3, (dam / 20)) + 1;
6828
6829 if (r_ptr->d_char == 'A') {
6830 note = " is immune";
6831 dam = do_blind = 0;
6832 } else if ((r_ptr->flags4 & RF4_BR_LITE) || (r_ptr->flags9 & RF9_RES_LITE)) {
6833 note = " resists";
6834 dam *= 3; dam /= (randint(6) + 6);
6835 do_blind = 0;
6836 } else if (r_ptr->flags3 & RF3_HURT_LITE) {
6837 #ifdef OLD_MONSTER_LORE
6838 if (seen) r_ptr->r_flags3 |= RF3_HURT_LITE;
6839 #endif
6840 note = " cringes from the light";
6841 note_dies = " shrivels away in the light";
6842 dam *= 2;
6843 }
6844 break;
6845 }
6846
6847
6848 /* Dark -- opposite of Lite */
6849 case GF_DARK:
6850 {
6851 if (seen) obvious = TRUE;
6852
6853 /* Get blinded later */
6854 do_blind = damroll(3, (dam / 20)) + 1;
6855
6856 if ((r_ptr->flags4 & RF4_BR_DARK) || (r_ptr->flags9 & RF9_RES_DARK)
6857 || (r_ptr->flags3 & RF3_UNDEAD)) {
6858 note = " resists";
6859 dam *= 3; dam /= (randint(6) + 6);
6860 do_blind = 0;
6861 }
6862 break;
6863 }
6864
6865 /* Stone to Mud */
6866 case GF_KILL_WALL:
6867 {
6868 /* Hurt by rock remover */
6869 if (r_ptr->flags3 & RF3_HURT_ROCK) {
6870 /* Notice effect */
6871 if (seen) obvious = TRUE;
6872
6873 #ifdef OLD_MONSTER_LORE
6874 /* Memorize the effects */
6875 if (seen) r_ptr->r_flags3 |= RF3_HURT_ROCK;
6876 #endif
6877
6878 /* Cute little message */
6879 note = " loses some skin";
6880 note_dies = " dissolves";
6881 }
6882
6883 /* Usually, ignore the effects */
6884 else {
6885 /* No damage */
6886 dam = 0;
6887 quiet = TRUE;
6888 }
6889
6890 break;
6891 }
6892
6893
6894 /* Teleport undead (Use "dam" as "power") */
6895 case GF_AWAY_UNDEAD:
6896 {
6897 /* Only affect undead */
6898 if (!(r_ptr->flags9 & RF9_IM_TELE) &&
6899 (r_ptr->flags3 & (RF3_UNDEAD)))
6900 {
6901 bool resists_tele = FALSE;
6902
6903 if ((r_ptr->flags3 & (RF3_RES_TELE)) || (r_ptr->flags9 & RF9_IM_TELE)) {
6904 if ((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags9 & RF9_IM_TELE)) {
6905 #ifdef OLD_MONSTER_LORE
6906 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6907 #endif
6908 note = " is unaffected";
6909 resists_tele = TRUE;
6910 } else if (m_ptr->level > randint(100)) {
6911 #ifdef OLD_MONSTER_LORE
6912 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6913 #endif
6914 note = " resists";
6915 resists_tele = TRUE;
6916 }
6917 }
6918
6919 if (!resists_tele) {
6920 if (seen) obvious = TRUE;
6921 #ifdef OLD_MONSTER_LORE
6922 if (seen) r_ptr->r_flags3 |= (RF3_UNDEAD);
6923 #endif
6924 do_dist = dam;
6925 }
6926 }
6927
6928 /* No "real" damage */
6929 dam = 0;
6930 quiet_dam = TRUE;
6931 break;
6932 }
6933
6934
6935 /* Teleport evil (Use "dam" as "power") */
6936 case GF_AWAY_EVIL:
6937 {
6938 /* Only affect undead */
6939 if (!(r_ptr->flags9 & RF9_IM_TELE) &&
6940 !(r_ptr->flags3 & (RF3_EVIL))) {
6941 bool resists_tele = FALSE;
6942
6943 if ((r_ptr->flags3 & (RF3_RES_TELE)) || (r_ptr->flags9 & RF9_IM_TELE)) {
6944 if ((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags9 & RF9_IM_TELE)) {
6945 #ifdef OLD_MONSTER_LORE
6946 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6947 #endif
6948 note = " is unaffected";
6949 resists_tele = TRUE;
6950 } else if (m_ptr->level > randint(100)) {
6951 #ifdef OLD_MONSTER_LORE
6952 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6953 #endif
6954 note = " resists";
6955 resists_tele = TRUE;
6956 }
6957 }
6958
6959 if (!resists_tele) {
6960 if (seen) obvious = TRUE;
6961 #ifdef OLD_MONSTER_LORE
6962 if (seen) r_ptr->r_flags3 |= (RF3_EVIL);
6963 #endif
6964 do_dist = dam;
6965 }
6966 }
6967
6968 /* No "real" damage */
6969 dam = 0;
6970 quiet_dam = TRUE;
6971 break;
6972 }
6973
6974
6975 /* Teleport monster (Use "dam" as "power") */
6976 case GF_AWAY_ALL:
6977 {
6978 bool resists_tele = FALSE;
6979 // dun_level *l_ptr = getfloor(wpos);
6980
6981 if (!(r_ptr->flags9 & RF9_IM_TELE) &&
6982 !(r_ptr->flags3 & (RF3_RES_TELE))) {
6983 if (r_ptr->flags1 & (RF1_UNIQUE)) {
6984 #ifdef OLD_MONSTER_LORE
6985 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6986 #endif
6987 note = " is unaffected";
6988 resists_tele = TRUE;
6989 } else if (m_ptr->level > randint(100)) {
6990 #ifdef OLD_MONSTER_LORE
6991 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
6992 #endif
6993 note = " resists";
6994 resists_tele = TRUE;
6995 }
6996
6997 if (!resists_tele) {
6998 /* Obvious */
6999 if (seen) obvious = TRUE;
7000 /* Prepare to teleport */
7001 do_dist = dam;
7002 }
7003 }
7004
7005 /* No "real" damage */
7006 dam = 0;
7007 quiet_dam = TRUE;
7008 break;
7009 }
7010
7011
7012 /* Turn undead (Use "dam" as "power") */
7013 case GF_TURN_UNDEAD:
7014 {
7015 /* Only affect undead */
7016 if (r_ptr->flags3 & RF3_UNDEAD) {
7017 #ifdef OLD_MONSTER_LORE
7018 /* Learn about type */
7019 if (seen) r_ptr->r_flags3 |= RF3_UNDEAD;
7020 #endif
7021
7022 /* Obvious */
7023 if (seen) obvious = TRUE;
7024
7025 /* Apply some fear */
7026 do_fear = damroll(3, (dam / 2)) + 1;
7027
7028 /* Attempt a saving throw */
7029 if (RES_OLD(r_ptr->level, dam)) {
7030 /* No obvious effect */
7031 note = " is unaffected";
7032 obvious = FALSE;
7033 do_fear = 0;
7034 }
7035 }
7036
7037 /* No "real" damage */
7038 dam = 0;
7039 quiet_dam = TRUE;
7040 break;
7041 }
7042
7043
7044 /* Turn evil (Use "dam" as "power") */
7045 case GF_TURN_EVIL:
7046 {
7047 /* Only affect evil */
7048 if (r_ptr->flags3 & RF3_EVIL) {
7049 #ifdef OLD_MONSTER_LORE
7050 /* Learn about type */
7051 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
7052 #endif
7053
7054 /* Obvious */
7055 if (seen) obvious = TRUE;
7056
7057 /* Apply some fear */
7058 do_fear = damroll(3, (dam / 2)) + 1;
7059
7060 /* Attempt a saving throw */
7061 if (RES_OLD(r_ptr->level, dam)) {
7062 /* No obvious effect */
7063 note = " is unaffected";
7064 obvious = FALSE;
7065 do_fear = 0;
7066 }
7067 }
7068
7069 /* No "real" damage */
7070 dam = 0;
7071 quiet_dam = TRUE;
7072 break;
7073 }
7074
7075
7076 /* Turn monster (Use "dam" as "power") */
7077 case GF_TURN_ALL:
7078 {
7079 /* Obvious */
7080 if (seen) obvious = TRUE;
7081
7082 /* Apply some fear */
7083 do_fear = damroll(3, (dam / 2)) + 1;
7084
7085 /* Attempt a saving throw */
7086 if ((r_ptr->flags1 & RF1_UNIQUE) ||
7087 (r_ptr->flags3 & RF3_NO_FEAR)) {
7088 /* No obvious effect */
7089 note = " is unaffected";
7090 obvious = FALSE;
7091 do_fear = 0;
7092 } else if (RES_OLD(r_ptr->level, dam)) {
7093 note = " resists the effect";
7094 obvious = FALSE;
7095 do_fear = 0;
7096 }
7097
7098 /* No "real" damage */
7099 dam = 0;
7100 quiet_dam = TRUE;
7101 break;
7102 }
7103
7104
7105 /* Dispel undead */
7106 case GF_DISP_UNDEAD:
7107 {
7108 /* Only affect undead */
7109 if (r_ptr->flags3 & RF3_UNDEAD) {
7110 #ifdef OLD_MONSTER_LORE
7111 /* Learn about type */
7112 if (seen) r_ptr->r_flags3 |= RF3_UNDEAD;
7113 #endif
7114
7115 /* Obvious */
7116 if (seen) obvious = TRUE;
7117
7118 /* Message */
7119 note = " shudders";
7120 note_dies = " dissolves";
7121 }
7122 /* Ignore other monsters */
7123 else {
7124 /* No damage */
7125 dam = 0;
7126 quiet = TRUE;
7127 }
7128
7129 break;
7130 }
7131
7132
7133 /* Dispel evil */
7134 case GF_DISP_EVIL:
7135 {
7136 /* Only affect evil */
7137 if (r_ptr->flags3 & RF3_EVIL) {
7138 #ifdef OLD_MONSTER_LORE
7139 /* Learn about type */
7140 if (seen) r_ptr->r_flags3 |= RF3_EVIL;
7141 #endif
7142
7143 /* Obvious */
7144 if (seen) obvious = TRUE;
7145
7146 /* Message */
7147 note = " shudders";
7148 note_dies = " dissolves";
7149 }
7150 /* Ignore other monsters */
7151 else {
7152 /* No damage */
7153 dam = 0;
7154 quiet = TRUE;
7155 }
7156
7157 break;
7158 }
7159
7160 case GF_DISP_DEMON:
7161 {
7162 /* Only affect evil */
7163 if (r_ptr->flags3 & RF3_DEMON) {
7164 #ifdef OLD_MONSTER_LORE
7165 /* Learn about type */
7166 if (seen) r_ptr->r_flags3 |= RF3_DEMON;
7167 #endif
7168
7169 /* Obvious */
7170 if (seen) obvious = TRUE;
7171
7172 /* Message */
7173 note = " shudders";
7174 note_dies = " dissolves";
7175 }
7176 /* Ignore other monsters */
7177 else {
7178 /* No damage */
7179 dam = 0;
7180 quiet = TRUE;
7181 }
7182
7183 break;
7184 }
7185
7186 /* Dispel monster */
7187 case GF_DISP_ALL:
7188 {
7189 /* Obvious */
7190 if (seen) obvious = TRUE;
7191
7192 /* Message */
7193 note = " shudders";
7194 note_dies = " dissolves";
7195
7196 break;
7197 }
7198
7199 /* Nuclear waste */
7200 case GF_NUKE:
7201 {
7202 if (seen) obvious = TRUE;
7203
7204 if ((r_ptr->flags3 & RF3_IM_POIS) ||
7205 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
7206 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
7207 {
7208 note = " is immune";
7209 dam = 0;
7210 #ifdef OLD_MONSTER_LORE
7211 if (seen) r_ptr->r_flags3 |= (RF3_IM_POIS);
7212 #endif
7213 } else if (r_ptr->flags9 & (RF9_RES_POIS)) {
7214 note = " resists";
7215 dam *= 3; dam /= (randint(6) + 6 );
7216 #ifdef OLD_MONSTER_LORE
7217 if (seen) r_ptr->r_flags9 |= (RF9_RES_POIS);
7218 #endif
7219 }
7220 else if (randint(3) == 1) do_poly = TRUE;
7221 break;
7222 }
7223
7224
7225 /* Pure damage */
7226 case GF_DISINTEGRATE:
7227 {
7228 if (seen) obvious = TRUE;
7229 if (r_ptr->flags3 & (RF3_HURT_ROCK)) {
7230 #ifdef OLD_MONSTER_LORE
7231 if (seen) r_ptr->r_flags3 |= (RF3_HURT_ROCK);
7232 #endif
7233 note = " loses some skin";
7234 note_dies = " evaporates";
7235 dam *= 2;
7236 }
7237
7238 if (r_ptr->flags1 & RF1_UNIQUE) {
7239 if (rand_int(m_ptr->level + 10) > rand_int(plev)) {
7240 note = " resists";
7241 dam >>= 3;
7242 }
7243 }
7244 break;
7245 }
7246 case GF_HOLD:
7247 case GF_DOMINATE:
7248 if(!quiet){
7249 if((!(r_ptr->flags1 & (RF1_UNIQUE|RF1_NEVER_MOVE)) &&
7250 !(r_ptr->flags9 & RF9_IM_PSI) && !(r_ptr->flags7 & RF7_MULTIPLY)) ||
7251 is_admin(p_ptr))
7252 m_ptr->owner = p_ptr->id;
7253 note = " starts following you";
7254 }
7255 dam = 0;
7256 quiet_dam = TRUE;
7257 break;
7258
7259 /* Teleport monster TO */
7260 case GF_TELE_TO:
7261 {
7262 bool resists_tele = FALSE;
7263 // dun_level *l_ptr = getfloor(wpos);
7264
7265 /* Teleport to nowhere..? */
7266 if (quiet) break;
7267
7268 if (!(r_ptr->flags9 & RF9_IM_TELE) &&
7269 !(r_ptr->flags3 & (RF3_RES_TELE))) {
7270 if (r_ptr->flags1 & (RF1_UNIQUE)) {
7271 #ifdef OLD_MONSTER_LORE
7272 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
7273 #endif
7274 note = " is unaffected";
7275 resists_tele = TRUE;
7276 } else if (m_ptr->level > randint(100)) {
7277 #ifdef OLD_MONSTER_LORE
7278 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
7279 #endif
7280 note = " resists";
7281 resists_tele = TRUE;
7282 }
7283 } else {
7284 #ifdef OLD_MONSTER_LORE
7285 if (seen) r_ptr->r_flags3 |= RF3_RES_TELE;
7286 #endif
7287 note = " is unaffected";
7288 resists_tele = TRUE;
7289 }
7290
7291 if (!resists_tele) {
7292 /* Obvious */
7293 if (seen) obvious = TRUE;
7294
7295 /* Prepare to teleport */
7296 // do_dist = dam;
7297 teleport_to_player(Ind, c_ptr->m_idx);
7298
7299 /* Hack -- get new location */
7300 y = m_ptr->fy;
7301 x = m_ptr->fx;
7302
7303 /* Hack -- get new grid */
7304 c_ptr = &zcave[y][x];
7305 }
7306
7307 /* No "real" damage */
7308 dam = 0;
7309 quiet_dam = TRUE;
7310 break;
7311 }
7312
7313 /* Hand of Doom */
7314 case GF_HAND_DOOM:
7315 {
7316 #if 0 /* okay, do that! ;) */
7317 if (r_ptr->r_flags1 & RF1_UNIQUE) {
7318 note = " resists";
7319 dam = 0;
7320 } else
7321 #endif // 0
7322 {
7323 int dummy = (((s32b) ((65 + randint(25)) * (m_ptr->hp))) / 100);
7324 // msg_print(Ind, "You feel your life fade away!");
7325
7326 if (m_ptr->hp - dummy < 1) dummy = m_ptr->hp - 1;
7327
7328 dam = dummy;
7329 }
7330 break;
7331 }
7332
7333 /* Sleep (Use "dam" as "power") */
7334 case GF_STASIS:
7335 if (seen) obvious = TRUE;
7336
7337 /* Attempt a saving throw */
7338 if ((r_ptr->flags1 & (RF1_UNIQUE)) ||
7339 RES_OLD(r_ptr->level, dam)) {
7340 note = " is unaffected";
7341 obvious = FALSE;
7342 } else {
7343 /* Go to sleep (much) later */
7344 note = " is suspended";
7345 do_sleep = GF_OLD_SLEEP_DUR;
7346 }
7347
7348 /* No "real" damage */
7349 dam = 0;
7350 quiet_dam = TRUE;
7351 break;
7352
7353 /* Decrease strength */
7354 case GF_DEC_STR:
7355 if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NO_DEATH)) {
7356 msg_print_near_monster(c_ptr->m_idx, "is unaffected");
7357 } else {
7358 for (i = 0; i < 4; i++) {
7359 if ((m_ptr->blow[i].d_dice > 1) && (m_ptr->blow[i].org_d_dice - m_ptr->blow[i].d_dice < 3)) {
7360 m_ptr->blow[i].d_dice -= 1;
7361 msg_print_near_monster(c_ptr->m_idx, "appears weaker");
7362 }
7363 else if ((m_ptr->blow[i].d_side > 1) && (m_ptr->blow[i].org_d_side - m_ptr->blow[i].d_side < 3)) {
7364 m_ptr->blow[i].d_side -= 1;
7365 msg_print_near_monster(c_ptr->m_idx, "appears weaker");
7366 }
7367 }
7368 }
7369 dam = 0;
7370 quiet = TRUE;
7371 break;
7372
7373 /* Decrease dexterity */
7374 case GF_DEC_DEX:
7375 if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NO_DEATH)) {
7376 msg_print_near_monster(c_ptr->m_idx, "is unaffected");
7377 } else {
7378 if ((m_ptr->org_ac - m_ptr->ac < m_ptr->org_ac / 2) && (m_ptr->org_ac - m_ptr->ac < 30)) {
7379 if (m_ptr->ac) msg_print_near_monster(c_ptr->m_idx, "appears clumsy");
7380 if (m_ptr->ac) m_ptr->ac--;
7381 if (m_ptr->ac) m_ptr->ac--;
7382 if (m_ptr->ac) m_ptr->ac--;
7383 }
7384 }
7385 dam = 0;
7386 quiet = TRUE;
7387 break;
7388
7389 /* Decrease dexterity */
7390 case GF_DEC_CON:
7391 if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NO_DEATH)) {
7392 msg_print_near_monster(c_ptr->m_idx, "is unaffected");
7393 } else {
7394 if ((m_ptr->org_maxhp - m_ptr->maxhp < m_ptr->org_maxhp / 2) && (m_ptr->org_maxhp - m_ptr->maxhp < 20)) {
7395 if (m_ptr->maxhp > 1) msg_print_near_monster(c_ptr->m_idx, "appears less healthy");
7396 if (m_ptr->maxhp > 50) m_ptr->maxhp -= 10;
7397 if (m_ptr->maxhp > 30) m_ptr->maxhp -= 6;
7398 if (m_ptr->maxhp > 10) m_ptr->maxhp -= 3;
7399 if (m_ptr->maxhp > 1) m_ptr->maxhp -= 1;
7400 if (m_ptr->maxhp < m_ptr->hp) m_ptr->hp = m_ptr->maxhp;
7401 }
7402 }
7403 dam = 0;
7404 quiet = TRUE;
7405 break;
7406
7407 /* Restore strength */
7408 case GF_RES_STR:
7409 dam = 0; /* hack :) */
7410 for (i = 0; i < 4; i++) {
7411 /* if (m_ptr->blow[i].d_dice < r_ptr->blow[i].d_dice) m_ptr->blow[i].d_dice = r_ptr->blow[i].d_dice;
7412 if (m_ptr->blow[i].d_side < r_ptr->blow[i].d_side) m_ptr->blow[i].d_side = r_ptr->blow[i].d_side;
7413 */ if (m_ptr->blow[i].d_dice < r_ptr->blow[i].org_d_dice) {
7414 m_ptr->blow[i].d_dice = r_ptr->blow[i].org_d_dice;
7415 dam = 1;
7416 }
7417 if (m_ptr->blow[i].d_side < r_ptr->blow[i].org_d_side) {
7418 m_ptr->blow[i].d_side = r_ptr->blow[i].org_d_side;
7419 dam = 1;
7420 }
7421 }
7422 if (dam) msg_print_near_monster(c_ptr->m_idx, "appears less weak");
7423 dam = 0;
7424 quiet = TRUE;
7425 break;
7426
7427 /* Restore dexterity */
7428 case GF_RES_DEX:
7429 /*if (m_ptr->ac < r_ptr->ac) {
7430 m_ptr->ac = r_ptr->ac;*/
7431 if (m_ptr->ac < m_ptr->org_ac) {
7432 m_ptr->ac = m_ptr->org_ac;
7433 msg_print_near_monster(c_ptr->m_idx, "appears less clumsy");
7434 }
7435 dam = 0;
7436 quiet = TRUE;
7437 break;
7438
7439 /* Restore constitution */
7440 case GF_RES_CON:
7441 /*if (m_ptr->hp < r_ptr->hside * r_ptr->hdice) {
7442 m_ptr->hp = r_ptr->hside * r_ptr->hdice;*/
7443 if (m_ptr->maxhp < m_ptr->org_maxhp) {
7444 m_ptr->hp += m_ptr->org_maxhp - m_ptr->maxhp;
7445 m_ptr->maxhp = m_ptr->org_maxhp;
7446 msg_print_near_monster(c_ptr->m_idx, "appears less sick");
7447 }
7448 dam = 0;
7449 quiet = TRUE;
7450 break;
7451
7452 /* Increase strength! */
7453 case GF_INC_STR:
7454 if (!(r_ptr->flags7 & RF7_NO_DEATH))
7455 for (i = 0; i < 4; i++) { /* increase the value which has less effect on total damage output - C. Blue :) */
7456 /* do a 'restore strenght' before increasing it */
7457 if (m_ptr->blow[i].d_dice < r_ptr->blow[i].org_d_dice) m_ptr->blow[i].d_dice = r_ptr->blow[i].org_d_dice;
7458 if (m_ptr->blow[i].d_side < r_ptr->blow[i].org_d_side) m_ptr->blow[i].d_side = r_ptr->blow[i].org_d_side;
7459
7460 if (m_ptr->blow[i].d_dice > m_ptr->blow[i].d_side) {
7461 m_ptr->blow[i].d_dice++;
7462 msg_print_near_monster(c_ptr->m_idx, "appears stronger");
7463 }
7464 else if (m_ptr->blow[i].d_side > 0 && m_ptr->blow[i].d_dice > 0) {
7465 m_ptr->blow[i].d_side++;
7466 msg_print_near_monster(c_ptr->m_idx, "appears stronger");
7467 }
7468 }
7469 dam = 0;
7470 quiet = TRUE;
7471 break;
7472
7473 /* Increase dexterity! */
7474 case GF_INC_DEX:
7475 if (!(r_ptr->flags7 & RF7_NO_DEATH)) {
7476 if (m_ptr->ac < m_ptr->org_ac) m_ptr->ac = m_ptr->org_ac;
7477 m_ptr->ac += 5;
7478 msg_print_near_monster(c_ptr->m_idx, "appears more dextrous");
7479 }
7480 dam = 0;
7481 quiet = TRUE;
7482 break;
7483
7484 /* Increase constitution! */
7485 case GF_INC_CON:
7486 if (!(r_ptr->flags7 & RF7_NO_DEATH)) {
7487 if (m_ptr->maxhp < m_ptr->org_maxhp) { /* include a restore con here */
7488 m_ptr->hp += m_ptr->org_maxhp - m_ptr->maxhp;
7489 m_ptr->maxhp = m_ptr->org_maxhp;
7490 }
7491
7492 m_ptr->hp += ((r_ptr->hside * r_ptr->hdice) / 10) + 2;
7493 m_ptr->maxhp += ((r_ptr->hside * r_ptr->hdice) / 10) + 2;
7494 msg_print_near_monster(c_ptr->m_idx, "appears healthier");
7495 }
7496
7497 dam = 0;
7498 quiet = TRUE;
7499 break;
7500
7501 /* Augmentation! (who'd do such a thing, silyl..) */
7502 case GF_AUGMENTATION:
7503 if (!(r_ptr->flags7 & RF7_NO_DEATH)) {
7504 msg_print_near_monster(c_ptr->m_idx, "appears more powerful!");
7505 for (i = 0; i < 4; i++) { /* increase the value which has less effect on total damage output - C. Blue :) */
7506 if (m_ptr->blow[i].d_dice < r_ptr->blow[i].org_d_dice) m_ptr->blow[i].d_dice = r_ptr->blow[i].org_d_dice;
7507 if (m_ptr->blow[i].d_side < r_ptr->blow[i].org_d_side) m_ptr->blow[i].d_side = r_ptr->blow[i].org_d_side;
7508
7509 if (m_ptr->blow[i].d_dice > m_ptr->blow[i].d_side) m_ptr->blow[i].d_dice++;
7510 else if (m_ptr->blow[i].d_side > 0 && m_ptr->blow[i].d_dice > 0) m_ptr->blow[i].d_side++;
7511 }
7512
7513 if (m_ptr->ac < m_ptr->org_ac) m_ptr->ac = m_ptr->org_ac;
7514
7515 m_ptr->ac += 5;
7516
7517 if (m_ptr->maxhp < m_ptr->org_maxhp) {
7518 m_ptr->hp += m_ptr->org_maxhp - m_ptr->maxhp;
7519 m_ptr->maxhp = m_ptr->org_maxhp;
7520 }
7521
7522 m_ptr->hp += ((r_ptr->hside * r_ptr->hdice) / 10) + 2;
7523 m_ptr->maxhp += ((r_ptr->hside * r_ptr->hdice) / 10) + 2;
7524 }
7525
7526 dam = 0;
7527 quiet = TRUE;
7528 break;
7529
7530 /* Ruination! (now we're talking) */
7531 case GF_RUINATION:
7532 if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NO_DEATH)) {
7533 msg_print_near_monster(c_ptr->m_idx, "is unaffected");
7534 } else {
7535 msg_print_near_monster(c_ptr->m_idx, "appears less powerful.");
7536 for (i = 0; i < 4; i++) {
7537 if ((m_ptr->blow[i].d_dice > 1) && (m_ptr->blow[i].org_d_dice - m_ptr->blow[i].d_dice < 3)) {
7538 m_ptr->blow[i].d_dice -= 1;
7539 }
7540 else if ((m_ptr->blow[i].d_side > 1) && (m_ptr->blow[i].org_d_side - m_ptr->blow[i].d_side < 3)) {
7541 m_ptr->blow[i].d_side -= 1;
7542 }
7543 }
7544
7545 if ((m_ptr->org_ac - m_ptr->ac < m_ptr->org_ac / 2) && (m_ptr->org_ac - m_ptr->ac < 30)) {
7546 if (m_ptr->ac) m_ptr->ac -= 1;
7547 if (m_ptr->ac) m_ptr->ac -= 1;
7548 if (m_ptr->ac) m_ptr->ac -= 1;
7549 }
7550
7551 if ((m_ptr->org_maxhp - m_ptr->maxhp < m_ptr->org_maxhp / 2) && (m_ptr->org_maxhp - m_ptr->maxhp < 20)) {
7552 if (m_ptr->hp > 50) m_ptr->hp -= 10;
7553 if (m_ptr->hp > 30) m_ptr->hp -= 6;
7554 if (m_ptr->hp > 10) m_ptr->hp -= 3;
7555 if (m_ptr->hp > 1) m_ptr->hp -= 1;
7556 if (m_ptr->maxhp < m_ptr->hp) m_ptr->hp = m_ptr->maxhp;
7557 }
7558 }
7559 dam = 0;
7560 quiet = TRUE;
7561 break;
7562
7563 /* Give experience! (dam -> +levels) */
7564 case GF_EXP:
7565 if (!(r_ptr->flags7 & RF7_NO_DEATH) && m_ptr->level < MONSTER_LEVEL_MAX) {
7566 msg_print_near_monster(c_ptr->m_idx, "appears more experienced");
7567 if (dam < 1) dam = 1;
7568 m_ptr->exp = MONSTER_EXP(m_ptr->level + dam);
7569 monster_check_experience(c_ptr->m_idx, FALSE);
7570 }
7571 dam = 0;
7572 quiet = TRUE;
7573 break;
7574
7575 case GF_CURING:
7576 if (m_ptr->confused) {
7577 m_ptr->confused = 0;
7578 msg_print_near_monster(c_ptr->m_idx, "is no longer confused.");
7579 }
7580 if (m_ptr->stunned) {
7581 m_ptr->stunned = 0;
7582 msg_print_near_monster(c_ptr->m_idx, "is no longer stunned.");
7583 }
7584
7585 dam = 0; /* hack :) */
7586 for (i = 0; i < 4; i++) {
7587 if (m_ptr->blow[i].d_dice < r_ptr->blow[i].org_d_dice) {
7588 m_ptr->blow[i].d_dice = r_ptr->blow[i].org_d_dice;
7589 dam = 1;
7590 }
7591 if (m_ptr->blow[i].d_side < r_ptr->blow[i].org_d_side) {
7592 m_ptr->blow[i].d_side = r_ptr->blow[i].org_d_side;
7593 dam = 1;
7594 }
7595 }
7596 if (dam) msg_print_near_monster(c_ptr->m_idx, "appears less weak");
7597
7598 if (m_ptr->ac < m_ptr->org_ac) {
7599 m_ptr->ac = m_ptr->org_ac;
7600 msg_print_near_monster(c_ptr->m_idx, "appears less clumsy");
7601 }
7602
7603 if (m_ptr->maxhp < m_ptr->org_maxhp) {
7604 m_ptr->hp += m_ptr->org_maxhp - m_ptr->maxhp;
7605 m_ptr->maxhp = m_ptr->org_maxhp;
7606 msg_print_near_monster(c_ptr->m_idx, "appears less sick");
7607 }
7608 dam = 0;
7609 quiet = TRUE;
7610 break;
7611
7612 /* Default */
7613 default:
7614 /* No damage */
7615 dam = 0;
7616 quiet_dam = TRUE;
7617 break;
7618 }
7619
7620 /* "Unique" monsters cannot be polymorphed */
7621 if (r_ptr->flags1 & RF1_UNIQUE) do_poly = FALSE;
7622 /* nor IM_TELE monsters.. */
7623 if (r_ptr->flags9 & RF9_IM_TELE) do_poly = FALSE;
7624
7625 /* No polymorphing in Bree - mikaelh */
7626 if (in_bree(wpos)) do_poly = FALSE;
7627
7628
7629 /* "Unique" monsters can only be "killed" by the player */
7630 if (r_ptr->flags1 & RF1_UNIQUE) {
7631 /* Uniques may only be killed by the player */
7632 if ((who > 0) && (dam > m_ptr->hp)) dam = m_ptr->hp;
7633 }
7634
7635
7636 /* Check for death */
7637 if ((dam > m_ptr->hp) &&
7638 /* Some mosnters are immune to death */
7639 !(r_ptr->flags7 & RF7_NO_DEATH)) {
7640 /* Extract method of death */
7641 note = note_dies;
7642 }
7643
7644
7645 /* hack: No polymorphing in IDDC, because live-spawning isn't possible.
7646 So polymorphing would just remove the monsters completely everytime. */
7647 if (do_poly && in_irondeepdive(wpos)) do_poly = FALSE;
7648
7649 #ifndef DAMAGE_BEFORE_POLY
7650 /* Mega-Hack -- Handle "polymorph" -- monsters get a saving throw */
7651 if (do_poly && (randint(90) > r_ptr->level)) {
7652 /* Default -- assume no polymorph */
7653 if (!do_sleep) note = " is unaffected";
7654
7655 /* Pick a "new" monster race */
7656 i = poly_r_idx(m_ptr->r_idx);
7657
7658 /* Handle polymorh */
7659 if (i != m_ptr->r_idx) {
7660 int clone, clone_summoning;
7661
7662 /* Obvious */
7663 if (seen) obvious = TRUE;
7664
7665 /* Monster polymorphs */
7666 note = " changes";
7667
7668 /* Turn off the damage */
7669 dam = 0;
7670 quiet_dam = TRUE;
7671
7672 /* Save clone status - mikaelh */
7673 clone = m_list[c_ptr->m_idx].clone;
7674 clone_summoning = m_list[c_ptr->m_idx].clone_summoning;
7675
7676 /* "Kill" the "old" monster */
7677 delete_monster_idx(c_ptr->m_idx, TRUE);
7678
7679 /* Create a new monster (no groups) */
7680 (void)place_monster_aux(wpos, y, x, i, FALSE, FALSE, clone, clone_summoning);
7681
7682 /* XXX XXX XXX Hack -- Assume success */
7683 if(!quiet && c_ptr->m_idx == 0) {
7684 msg_format(Ind, "%^s disappears!", m_name);
7685 return(FALSE);
7686 }
7687
7688 /* Hack -- Get new monster */
7689 m_ptr = &m_list[c_ptr->m_idx];
7690
7691 /* Hack -- Get new race */
7692 r_ptr = race_inf(m_ptr);
7693 }
7694 }
7695 #endif
7696
7697 /* Handle "teleport" */
7698 if (do_dist) {
7699 /* Obvious */
7700 if (seen) obvious = TRUE;
7701
7702 /* Message */
7703 note = " disappears";
7704
7705 /* Teleport */
7706 /* TODO: handle failure (eg. st-anchor) */
7707
7708 // teleport_away(c_ptr->m_idx, do_dist);
7709 m_ptr->do_dist = do_dist;
7710
7711 /* Hack -- get new location */
7712 y = m_ptr->fy;
7713 x = m_ptr->fx;
7714
7715 /* Hack -- get new grid */
7716 c_ptr = &zcave[y][x];
7717 }
7718
7719 /* Sound and Impact breathers never stun */
7720 if (do_stun &&
7721 !(r_ptr->flags4 & RF4_BR_SOUN) &&
7722 !(r_ptr->flags4 & RF4_BR_PLAS) &&
7723 !(r_ptr->flags4 & RF4_BR_WALL) &&
7724 !(r_ptr->flags3 & RF3_NO_STUN)) {
7725 /* Obvious */
7726 if (seen) obvious = TRUE;
7727
7728 #if 0
7729 /* Get stunned */
7730 if (m_ptr->stunned) {
7731 if (!do_sleep) note = " is more dazed";
7732 i = m_ptr->stunned + (do_stun / 2);
7733 } else {
7734 if (!do_sleep) note = " is dazed";
7735 i = do_stun;
7736 }
7737 #else
7738 if (m_ptr->stunned > 100) {
7739 note = " is knocked out";
7740 i = m_ptr->stunned + (do_stun / 4);
7741 } else if (m_ptr->stunned > 50) {
7742 if (!do_sleep) note = " is heavily dazed";
7743 i = m_ptr->stunned + (do_stun / 3);
7744 } else if (m_ptr->stunned) {
7745 if (!do_sleep) note = " is more dazed";
7746 i = m_ptr->stunned + (do_stun / 2);
7747 } else {
7748 if (!do_sleep) note = " is dazed";
7749 i = do_stun;
7750 }
7751 #endif
7752
7753 /* Apply stun */
7754 m_ptr->stunned = (i < 200) ? i : 200;
7755 }
7756
7757 /* Confusion and Chaos breathers (and sleepers) never confuse */
7758 if (do_conf &&
7759 !(r_ptr->flags3 & RF3_NO_CONF) &&
7760 !(r_ptr->flags4 & RF4_BR_CONF) &&
7761 !(r_ptr->flags4 & RF4_BR_CHAO) &&
7762 !(r_ptr->flags9 & RF9_RES_CHAOS)) {
7763 /* Obvious */
7764 if (seen) obvious = TRUE;
7765
7766 /* Already partially confused */
7767 if (m_ptr->confused) {
7768 if (!do_sleep) note = " looks more confused";
7769 i = m_ptr->confused + (do_conf / 2);
7770 }
7771 /* Was not confused */
7772 else {
7773 if (!do_sleep) note = " looks confused";
7774 i = do_conf;
7775 }
7776
7777 /* Apply confusion */
7778 m_ptr->confused = (i < 200) ? i : 200;
7779 }
7780
7781 /* Blindness (confusion): Not for uniques or powerful monsters */
7782 if (do_blind &&
7783 !(r_ptr->flags2 & RF2_POWERFUL) &&
7784 !(r_ptr->flags2 & RF2_PASS_WALL) && /* Ethereal monsters */
7785 !((r_ptr->flags4 & RF4_BR_LITE) && (r_ptr->flags4 & RF4_BR_DARK)) &&
7786 !(r_ptr->flags3 & RF3_UNDEAD) &&
7787 !(r_ptr->flags3 & RF3_NONLIVING) &&
7788 !(r_ptr->flags3 & RF3_DEMON) &&
7789 !(r_ptr->flags3 & RF3_DRAGON) &&
7790 !(r_ptr->flags3 & RF3_DRAGONRIDER) &&
7791 !(r_ptr->flags1 & RF1_UNIQUE) &&
7792 (m_ptr->level < 45))
7793 /* !((r_ptr->flags3 & RF3_DEMON) && (m_ptr->level >= 40)) &&
7794 !((r_ptr->flags3 & RF3_DRAGON) && (m_ptr->level >= 40)) &&
7795 !((r_ptr->flags3 & RF3_DRAGONRIDER) && (m_ptr->level >= 40)) &&
7796 !(r_ptr->flags1 & RF1_UNIQUE))*/
7797 /* !(((r_ptr->flags3 & RF3_DEMON) ||
7798 (r_ptr->flags3 & RF3_DRAGON) ||
7799 (r_ptr->flags3 & RF3_DRAGONRIDER) ||
7800 (r_ptr->flags1 & RF1_UNIQUE)) &&
7801 RES_OLD(r_ptr->level, dam)) <- this line would require a " resists." note btw. */
7802 {
7803 /* Obvious */
7804 if (seen) obvious = TRUE;
7805
7806 /* Not too confused yet? */
7807 if (m_ptr->confused < do_blind) {
7808 i = do_blind;
7809 if (!do_sleep) {
7810 /* Already confused */
7811 if (m_ptr->confused) {
7812 note = " looks more confused";
7813 }
7814 /* Was not confused */
7815 else {
7816 note = " gropes around blindly";
7817 }
7818 }
7819 }
7820
7821 /* Apply confusion */
7822 m_ptr->confused = (i < 200) ? i : 200;
7823 } else if (do_blind) {
7824 if (note == NULL) {
7825 /* No obvious effect */
7826 note = " is unaffected";
7827 obvious = FALSE;
7828 }
7829 }
7830
7831 /* Fear */
7832 if (do_fear) {
7833 /* Increase fear */
7834 i = m_ptr->monfear + do_fear;
7835
7836 /* Set fear */
7837 m_ptr->monfear = (i < 200) ? i : 200;
7838 m_ptr->monfear_gone = 0;
7839 }
7840
7841
7842 /* If another monster did the damage, hurt the monster by hand */
7843 if (who > 0 || who <= PROJECTOR_UNUSUAL) {
7844 /* Redraw (later) if needed */
7845 update_health(c_ptr->m_idx);
7846
7847 /* Some mosnters are immune to death */
7848 if (r_ptr->flags7 & RF7_NO_DEATH) dam = 0;
7849
7850 /* Wake the monster up */
7851 m_ptr->csleep = 0;
7852
7853 /* Hurt the monster */
7854 m_ptr->hp -= dam;
7855
7856 /* Dead monster */
7857 if (m_ptr->hp < 0) {
7858 /* Since a non-player killed it, there will be no reward/loot */
7859 if (r_ptr->flags1 & RF1_UNIQUE) m_ptr->clone = 90; /* still allow some experience to be gained */
7860 else m_ptr->clone = 75;
7861
7862 /* Generate treasure, etc */
7863 if (!quiet) monster_death(Ind, c_ptr->m_idx);
7864
7865 /* Delete the monster */
7866 delete_monster_idx(c_ptr->m_idx, FALSE);
7867
7868 /* Give detailed messages if destroyed */
7869 /* DEG Death message with damage. */
7870 if ((r_ptr->flags1 & RF1_UNIQUE) && (!quiet && note))
7871 msg_format(Ind, "%^s%s by \377e%d \377wdamage.", m_name, note, dam);
7872 else if (!quiet && note)
7873 msg_format(Ind, "%^s%s by \377g%d \377wdamage.", m_name, note, dam);
7874
7875 #ifdef DAMAGE_BEFORE_POLY
7876 do_poly = FALSE;
7877 #endif
7878 }
7879
7880 /* Damaged monster */
7881 else {
7882 /* Give detailed messages if visible or destroyed */
7883 if (!quiet && note && seen) msg_format(Ind, "%^s%s.", m_name, note);
7884
7885 /* Hack -- Pain message */
7886 else if (!quiet && dam > 0) message_pain(Ind, c_ptr->m_idx, dam);
7887
7888 /* Hack -- handle sleep */
7889 if (do_sleep) m_ptr->csleep = do_sleep;
7890 }
7891 }
7892
7893 /* If the player did it, give him experience, check fear */
7894 else {
7895 bool fear = FALSE;
7896
7897 if (m_ptr->questor && (m_ptr->questor_invincible || (r_ptr->flags7 & RF7_NO_DEATH) || !(m_ptr->questor_hostile & 0x1))) return obvious;
7898
7899 if (p_ptr->admin_godly_strike) {
7900 p_ptr->admin_godly_strike--;
7901 if (!(r_ptr->flags1 & RF1_UNIQUE)) dam = m_ptr->hp + 1;
7902 }
7903
7904 /* Hurt the monster, check for fear and death */
7905 if (!quiet && mon_take_hit(Ind, c_ptr->m_idx, dam, &fear, note_dies))
7906 {
7907 /* Dead monster */
7908 #ifdef DAMAGE_BEFORE_POLY
7909 do_poly = FALSE;
7910 #endif
7911 }
7912
7913 /* Damaged monster */
7914 else {
7915 /* Give detailed messages if visible or destroyed */
7916 /* DEG Changed for added damage message. */
7917 if (!quiet && seen) {
7918 if (note) {
7919 if (!quiet_dam) {
7920 if (r_ptr->flags1 & RF1_UNIQUE) {
7921 if (p_ptr->r_killed[m_ptr->r_idx] == 1) {
7922 msg_format(Ind, "\377D%^s%s and takes \377e%d \377Ddamage.", m_name, note, dam);
7923 if (p_ptr->warn_unique_credit) Send_beep(Ind);
7924 } else
7925 msg_format(Ind, "%^s%s and takes \377e%d \377wdamage.", m_name, note, dam);
7926 } else
7927 msg_format(Ind, "%^s%s and takes \377g%d \377wdamage.", m_name, note, dam);
7928 } else {
7929 msg_format(Ind, "%^s%s.", m_name, note);
7930 }
7931 }
7932 /* Hack -- Pain message */
7933 else if (dam > 0) message_pain(Ind, c_ptr->m_idx, dam);
7934
7935 /* Take note */
7936 if (fear || do_fear) {
7937 #ifdef USE_SOUND_2010
7938 #else
7939 sound(Ind, SOUND_FLEE);
7940 #endif
7941 /* Message */
7942 if (m_ptr->r_idx != RI_MORGOTH)
7943 msg_format(Ind, "%^s flees in terror!", m_name);
7944 else
7945 msg_format(Ind, "%^s retreats!", m_name);
7946 }
7947 }
7948 #if 0 /* see above */
7949 /* Take note */
7950 if (!quiet && (fear || do_fear) && (p_ptr->mon_vis[c_ptr->m_idx])) {
7951 #ifdef USE_SOUND_2010
7952 #else
7953 sound(Ind, SOUND_FLEE);
7954 #endif
7955
7956 /* Message */
7957 if (m_ptr->r_idx != RI_MORGOTH)
7958 msg_format(Ind, "%^s flees in terror!", m_name);
7959 else
7960 msg_format(Ind, "%^s retreats!", m_name);
7961 }
7962 #endif
7963
7964 /* Hack -- handle sleep */
7965 if (do_sleep) m_ptr->csleep = do_sleep;
7966
7967 #ifdef ANTI_SEVEN_EXPLOIT /* code part: 'monster gets hit by a projection' */
7968 /* isn't there any player in our casting-los? */
7969 /* only ball spells/explosions, NOT clouds/walls/beams/bolts/traps/etc */
7970 // if ((flg & PROJECT_JUMP) && (flg & PROJECT_KILL) && !(flg & PROJECT_STAY) &&
7971 // if ((flg & PROJECT_KILL) && !(flg & PROJECT_STAY) &&
7972 if ((flg & PROJECT_KILL) && /* well, why not for lasting effects too actually */
7973 /* some sanity/efficiency checks:.. */
7974 y_origin && x_origin && dam) {
7975 /* first, make sure we don't have another potential target in our LOS.
7976 If we have, we can just go for him and ignore whoever shot us previously.
7977 NOTE: this stuff should probably be evaluated in monster target choosing
7978 code already, for efficiency. */
7979 bool got_potential_target = FALSE;
7980 int p;
7981 /* make sure only monsters who NEED to use this actually do use it.. (Morgoth doesn't) */
7982 if ((r_ptr->flags2 & RF2_PASS_WALL) && (r_ptr->flags2 & RF2_KILL_WALL)) {
7983 got_potential_target = TRUE;
7984 }
7985 else if ((r_ptr->flags2 & RF2_PASS_WALL) || (r_ptr->flags2 & RF2_KILL_WALL)) {
7986 if (!m_ptr->closest_player || m_ptr->closest_player > NumPlayers ||
7987 !inarea(&Players[m_ptr->closest_player]->wpos, &m_ptr->wpos))
7988 got_potential_target = TRUE;
7989 else if (projectable_wall_perm(&m_ptr->wpos, m_ptr->fy, m_ptr->fx,
7990 Players[m_ptr->closest_player]->py, Players[m_ptr->closest_player]->px, MAX_RANGE)) {
7991 got_potential_target = TRUE;
7992 }
7993 }
7994 if (!got_potential_target) {
7995 for (p = 1; p <= NumPlayers; p++) {
7996 if (inarea(&Players[p]->wpos, &m_ptr->wpos) &&
7997 projectable_wall(&m_ptr->wpos, m_ptr->fy, m_ptr->fx, Players[p]->py, Players[p]->px, MAX_RANGE)) {
7998 got_potential_target = TRUE;
7999 break;
8000 }
8001 }
8002 }
8003 /* Ok, noone else to go after, so we have to go for the one who actually hit us */
8004 if (!got_potential_target) {
8005 /* if we got hit by anything closer than last time, go for this one instead */
8006 p = distance(m_ptr->fy, m_ptr->fx, y_origin, x_origin);
8007 /* paranoia probably, but doesn't cost much: avoid silliness */
8008 if (!p) m_ptr->previous_direction = 0;
8009 /* start ANTI_SEVEN_EXPLOIT: */
8010 else {
8011 if (m_ptr->previous_direction == 0) {
8012 /* note: instead of closest dis to ANY player we just save m_ptr->cdis
8013 at this time - relatively ineffective but also not mattering much probably. */
8014 m_ptr->cdis_on_damage = m_ptr->cdis;
8015 /* start behaving special */
8016 m_ptr->previous_direction = -1;
8017 /* accept any epicenter of damage (which is closer than 999,999: always TRUE) */
8018 m_ptr->damage_tx = 999;
8019 m_ptr->damage_ty = 999;
8020 m_ptr->damage_dis = 999;
8021 }
8022 if (p < m_ptr->damage_dis) {
8023 m_ptr->damage_ty = y_origin;
8024 m_ptr->damage_tx = x_origin;
8025 m_ptr->damage_dis = p;
8026 m_ptr->p_tx = p_ptr->px;
8027 m_ptr->p_ty = p_ptr->py;
8028 }
8029 }
8030 }
8031 }
8032 #endif
8033 }
8034 }
8035
8036 #ifdef DAMAGE_BEFORE_POLY
8037 /* Mega-Hack -- Handle "polymorph" -- monsters get a saving throw */
8038 if (do_poly && (randint(90) > r_ptr->level)) {
8039 /* Default -- assume no polymorph */
8040 if (!do_sleep) note = " is unaffected";
8041
8042 /* Pick a "new" monster race */
8043 i = poly_r_idx(m_ptr->r_idx);
8044
8045 /* Handle polymorh */
8046 if (i != m_ptr->r_idx) {
8047 int clone, clone_summoning;
8048
8049 /* Obvious */
8050 if (seen) obvious = TRUE;
8051
8052 /* Monster polymorphs */
8053 note = " changes";
8054
8055 /* Save clone status - mikaelh */
8056 clone = m_list[c_ptr->m_idx].clone;
8057 clone_summoning = m_list[c_ptr->m_idx].clone_summoning;
8058
8059 /* "Kill" the "old" monster */
8060 delete_monster_idx(c_ptr->m_idx, TRUE);
8061
8062 /* Create a new monster (no groups) */
8063 (void)place_monster_aux(wpos, y, x, i, FALSE, FALSE, clone, clone_summoning);
8064
8065 /* XXX XXX XXX Hack -- Assume success */
8066 if (!quiet) {
8067 if (c_ptr->m_idx == 0) {
8068 msg_format(Ind, "%^s disappears!", m_name);
8069 return (FALSE);
8070 } else msg_format(Ind, "%^s changes!", m_name);
8071 }
8072 }
8073 }
8074 #endif
8075
8076 /* Update the monster XXX XXX XXX */
8077 update_mon(c_ptr->m_idx, FALSE);
8078
8079 if (!quiet) {
8080 /* Hack -- Redraw the monster grid anyway */
8081 everyone_lite_spot(wpos, y, x);
8082 }
8083
8084 /* Return "Anything seen?" */
8085 return (obvious);
8086 }
8087
8088
8089
8090
8091
8092
8093 /*
8094 * Helper function for "project()" below.
8095 *
8096 * Handle a beam/bolt/ball causing damage to the player.
8097 *
8098 * This routine takes a "source monster" (by index), a "distance", a default
8099 * "damage", and a "damage type". See "project_m()" above.
8100 *
8101 * If "rad" is non-zero, then the blast was centered elsewhere, and the damage
8102 * is reduced (see "project_m()" above). This can happen if a monster breathes
8103 * at the player and hits a wall instead.
8104 *
8105 * We return "TRUE" if any "obvious" effects were observed. XXX XXX Actually,
8106 * we just assume that the effects were obvious, for historical reasons.
8107 */
8108 /*
8109 * Megahack -- who < -999 means 'by something strange'. - Jir -
8110 *
8111 * NOTE: unlike the note above, 'rad' doesn't seem to be used for damage-
8112 * reducing purpose, I don't know why.
8113 */
8114 //static bool project_p(int Ind, int who, int r, struct worldpos *wpos, int y, int x, int dam, int typ, int rad)
8115 static bool project_p(int Ind, int who, int r, struct worldpos *wpos, int y, int x, int dam, int typ, int rad, int flg, char *attacker)
8116 {
8117 player_type *p_ptr;
8118 monster_race *r_ptr;
8119
8120 int k = 0;
8121 int div, k_elec, k_sound, k_lite;
8122 bool kinetic_shield = FALSE;
8123 /* Hack -- assume obvious */
8124 bool obvious = TRUE;
8125 /* Player blind-ness */
8126 bool blind;
8127 /* Player needs a "description" (he is blind) */
8128 bool fuzzy = FALSE;
8129 /* Player is damaging herself (eg. by shattering potion) */
8130 bool self = FALSE;
8131
8132 /* Source monster */
8133 monster_type *m_ptr = NULL;
8134 /* Monster name (for attacks) */
8135 char m_name[MNAME_LEN], m_name_gen[MNAME_LEN];
8136 /* Monster name (for damage) */
8137 char killer[MNAME_LEN];
8138 /* Colour of the damage, either r (standard) or e (unique monster) */
8139 char damcol = 'o';
8140 int psi_resists = 0, hack_dam = 0;
8141 /* Hack -- messages */
8142 // cptr act = NULL;
8143 /* For resist_time: Limit randomization of effect */
8144 int time_influence_choices;
8145 /* Another player casting attack spell on us? */
8146 bool friendly_player = FALSE;
8147
8148 /* Bad player number */
8149 if (Ind <= 0) return (FALSE);
8150
8151 p_ptr = Players[Ind];
8152
8153 /* Player has already been hit, return - mikaelh */
8154 if (p_ptr->got_hit) return (FALSE);
8155
8156 r_ptr = &r_info[p_ptr->body_monster];
8157
8158 /* Catch healing hacks */
8159 if (typ == GF_HEAL_PLAYER) {
8160 hack_dam = dam & 0x3C00;
8161 dam = dam & 0x03FF;
8162 }
8163
8164 /* shadow running protects from taking ranged damage - C. Blue
8165 note: currently thereby also affecting friendly effects' 'damage'. */
8166 if (p_ptr->shadow_running) dam /= 3;
8167
8168 blind = (p_ptr->blind ? TRUE : FALSE);
8169
8170 /* Player is not here */
8171 if ((x != p_ptr->px) || (y != p_ptr->py) || (!inarea(wpos,&p_ptr->wpos))) return (FALSE);
8172
8173 /* Player cannot hurt himself */
8174 if (0 - who == Ind) {
8175 if (flg & (PROJECT_SELF | PROJECT_PLAY)) self = TRUE;
8176 else return (FALSE);
8177 }
8178
8179 /* Mega-Hack -- Players cannot hurt other players */
8180 if (cfg.use_pk_rules == PK_RULES_NEVER && who <= 0 &&
8181 who > PROJECTOR_UNUSUAL
8182 && !(flg & PROJECT_PLAY)) /* except if it's an explicitely player-affecting spell! */
8183 return (FALSE);
8184
8185 /* Store/house is safe -- NOT in dungeon! */
8186 if (p_ptr->store_num != -1 && istown(wpos)) return(FALSE);
8187
8188 /* Extract radius */
8189 div = r + 1;
8190
8191 /* Damage decrease over radius */
8192 dam = radius_damage(dam, div, typ);
8193
8194 /* Hack -- always do at least one point of damage */
8195 if (dam <= 0) dam = 1;
8196
8197 /* Hack -- Never do excessive damage */
8198 if (dam > MAGICAL_CAP) dam = MAGICAL_CAP;
8199
8200 /* If the player is blind, be more descriptive */
8201 if (blind) fuzzy = TRUE;
8202
8203 /* If the player is hit by a trap, be more descritive */
8204 if (who <= PROJECTOR_UNUSUAL) fuzzy = TRUE;
8205
8206 if (who > 0) {
8207 /* Get the source monster */
8208 m_ptr = &m_list[who];
8209
8210 /* Get the monster name for actions */
8211 monster_desc(Ind, m_name, who, 0);
8212 monster_desc(Ind, m_name_gen, who, 0x02);
8213
8214 /* Get the monster's killing name */
8215 monster_desc(Ind, killer, who, 0x88);
8216
8217 /* Get the monster's real name */
8218 monster_desc(Ind, p_ptr->really_died_from, who, 0x100);
8219
8220 /* Unique monsters cause different damage message colour */
8221 if (race_inf(m_ptr)->flags1 & RF1_UNIQUE) damcol = 'L';
8222 }
8223 /* hack -- by trap */
8224 else if (who == PROJECTOR_TRAP) {
8225 if (attacker) {
8226 sprintf(killer, "a%s %s", is_a_vowel(attacker[0]) ? "n" : "", attacker);
8227 sprintf(m_name, "a%s %s", is_a_vowel(attacker[0]) ? "n" : "", attacker);
8228 sprintf(m_name_gen, "the %s", attacker);
8229 } else {
8230 /* Hopefully never. */
8231 /* OUTDATED: Actually this can happen if player's not on the trap (eg. door traps) */
8232 sprintf(killer, "a mysterious accident");
8233 sprintf(m_name, "something");
8234 sprintf(m_name_gen, "the");
8235 }
8236 }
8237 /* hack -- by shattering potion */
8238 else if (who == PROJECTOR_POTION) {
8239 /* TODO: add potion name */
8240 sprintf(killer, "an evaporating potion");
8241 sprintf(m_name, "an evaporating potion");
8242 sprintf(m_name_gen, "the");
8243 }
8244 /* hack -- by malformed invocation (runespell backlash) */
8245 else if (who == PROJECTOR_RUNE) {
8246 sprintf(killer, "a malformed invocation");
8247 sprintf(m_name, "a malformed invocation");
8248 sprintf(m_name_gen, "the");
8249 }
8250 /* hack -- another player who has logged out */
8251 else if (who == PROJECTOR_PLAYER) {
8252 sprintf(killer, "another player");
8253 sprintf(m_name, "another player");
8254 sprintf(m_name_gen, "its");
8255
8256 /* Assume they were friendly */
8257 friendly_player = TRUE;
8258
8259 /* Will hurt other players if it was a damaging spell!
8260 So we should just exit here. Only drawback might be,
8261 that in PvP a player cannot die from his opponent's
8262 remaining nox cloud after he killed him ;). - C. Blue */
8263 return FALSE;
8264 }
8265 else if (who == PROJECTOR_TERRAIN) {
8266 dun_level *l_ptr = getfloor(wpos);
8267 if ((l_ptr && (l_ptr->flags2 & LF2_FAIR_TERRAIN_DAM)) ||
8268 (in_sector00(wpos) && (sector00flags2 & LF2_FAIR_TERRAIN_DAM)))
8269 dam = (p_ptr->mhp * (8 + rand_int(5))) / 15 + 1;
8270 /* (4hp is lvl 1 char's min); maybe TODO: give high level players a slight advantage (cause higher loss if they die) */
8271
8272 sprintf(killer, "hazardous environment");
8273 sprintf(m_name, "hazardous environment");
8274 sprintf(m_name_gen, "the");
8275 }
8276 /* hack -- by shattering potion */
8277 else if (who <= PROJECTOR_UNUSUAL) {
8278 /* TODO: add potion name */
8279 sprintf(killer, "something weird");
8280 sprintf(m_name, "something");
8281 sprintf(m_name_gen, "some");
8282 }
8283 else if (self) {
8284 sprintf(killer, p_ptr->male ? "himself" : "herself");
8285 sprintf(m_name, "It's yourself who");
8286 sprintf(m_name_gen, "your own");
8287
8288 /* Do not apply Stair-GoI/deflection etc. on one's own helpful self-affecting spells */
8289 if ((typ == GF_HEAL_PLAYER) || (typ == GF_AWAY_ALL) ||
8290 (typ == GF_WRAITH_PLAYER) || (typ == GF_SPEED_PLAYER) ||
8291 (typ == GF_SHIELD_PLAYER) || (typ == GF_RECALL_PLAYER) ||
8292 (typ == GF_BLESS_PLAYER) || (typ == GF_REMFEAR_PLAYER) ||
8293 (typ == GF_REMCONF_PLAYER) || (typ == GF_REMIMAGE_PLAYER) ||
8294 (typ == GF_SATHUNGER_PLAYER) || (typ == GF_RESFIRE_PLAYER) ||
8295 (typ == GF_RESCOLD_PLAYER) || (typ == GF_CUREPOISON_PLAYER) ||
8296 (typ == GF_SEEINVIS_PLAYER) || (typ == GF_SEEMAP_PLAYER) ||
8297 (typ == GF_CURECUT_PLAYER) || (typ == GF_CURESTUN_PLAYER) ||
8298 (typ == GF_DETECTCREATURE_PLAYER) || (typ == GF_DETECTDOOR_PLAYER) ||
8299 (typ == GF_DETECTTRAP_PLAYER) || (typ == GF_TELEPORTLVL_PLAYER) ||
8300 (typ == GF_RESPOIS_PLAYER) || (typ == GF_RESELEC_PLAYER) ||
8301 (typ == GF_RESACID_PLAYER) || (typ == GF_HPINCREASE_PLAYER) ||
8302 (typ == GF_HERO_PLAYER) || (typ == GF_SHERO_PLAYER) || (typ == GF_MINDBOOST_PLAYER) ||
8303 (typ == GF_TELEPORT_PLAYER) || (typ == GF_ZEAL_PLAYER) ||
8304 (typ == GF_RESTORE_PLAYER) || (typ == GF_REMCURSE_PLAYER) ||
8305 (typ == GF_CURE_PLAYER) || (typ == GF_RESURRECT_PLAYER) ||
8306 (typ == GF_SANITY_PLAYER) || (typ == GF_SOULCURE_PLAYER) ||
8307 (typ == GF_OLD_HEAL) || (typ == GF_OLD_SPEED) || (typ == GF_PUSH) ||
8308 (typ == GF_HEALINGCLOUD) || /* Also not a hostile spell */
8309 (typ == GF_MINDBOOST_PLAYER) || (typ == GF_IDENTIFY) ||
8310 (typ == GF_SLOWPOISON_PLAYER) || (typ == GF_CURING) ||
8311 (typ == GF_OLD_POLY)) /* may (un)polymorph himself */
8312 friendly_player = TRUE;
8313 }
8314 else if (IS_PVP) {
8315 // strcpy(killer, p_ptr->play_vis[0 - who] ? Players[0 - who]->name : "It");
8316 // strcpy(m_name, p_ptr->play_vis[0 - who] ? Players[0 - who]->name : "It");
8317 sprintf(killer, "%s", p_ptr->play_vis[0 - who] ? Players[0 - who]->name : "It");
8318 sprintf(m_name, "%s", p_ptr->play_vis[0 - who] ? Players[0 - who]->name : "It");
8319 if (p_ptr->play_vis[0 - who]) {
8320 if (Players[0 - who]->name[strlen(Players[0 - who]->name) - 1] != 's')
8321 sprintf(m_name_gen, "%s's", Players[0 - who]->name);
8322 else
8323 sprintf(m_name_gen, "%s'", Players[0 - who]->name);
8324 } else
8325 sprintf(m_name_gen, "its");
8326 strcpy(p_ptr->really_died_from, Players[0 - who]->name);
8327
8328 /* Do not become hostile if it was a friendly spell */
8329 if ((typ != GF_HEAL_PLAYER) && (typ != GF_AWAY_ALL) &&
8330 (typ != GF_WRAITH_PLAYER) && (typ != GF_SPEED_PLAYER) &&
8331 (typ != GF_SHIELD_PLAYER) && (typ != GF_RECALL_PLAYER) &&
8332 (typ != GF_BLESS_PLAYER) && (typ != GF_REMFEAR_PLAYER) &&
8333 (typ != GF_REMCONF_PLAYER) && (typ != GF_REMIMAGE_PLAYER) &&
8334 (typ != GF_SATHUNGER_PLAYER) && (typ != GF_RESFIRE_PLAYER) &&
8335 (typ != GF_RESCOLD_PLAYER) && (typ != GF_CUREPOISON_PLAYER) &&
8336 (typ != GF_SEEINVIS_PLAYER) && (typ != GF_SEEMAP_PLAYER) &&
8337 (typ != GF_CURECUT_PLAYER) && (typ != GF_CURESTUN_PLAYER) &&
8338 (typ != GF_DETECTCREATURE_PLAYER) && (typ != GF_DETECTDOOR_PLAYER) &&
8339 (typ != GF_DETECTTRAP_PLAYER) && (typ != GF_TELEPORTLVL_PLAYER) &&
8340 (typ != GF_RESPOIS_PLAYER) && (typ != GF_RESELEC_PLAYER) &&
8341 (typ != GF_RESACID_PLAYER) && (typ != GF_HPINCREASE_PLAYER) &&
8342 (typ != GF_HERO_PLAYER) && (typ != GF_SHERO_PLAYER) && (typ != GF_MINDBOOST_PLAYER) &&
8343 (typ != GF_TELEPORT_PLAYER) && (typ != GF_ZEAL_PLAYER) &&
8344 (typ != GF_RESTORE_PLAYER) && (typ != GF_REMCURSE_PLAYER) &&
8345 (typ != GF_CURE_PLAYER) && (typ != GF_RESURRECT_PLAYER) &&
8346 (typ != GF_SANITY_PLAYER) && (typ != GF_SOULCURE_PLAYER) &&
8347 (typ != GF_OLD_HEAL) && (typ != GF_OLD_SPEED) && (typ != GF_PUSH) &&
8348 (typ != GF_HEALINGCLOUD) && /* Also not a hostile spell */
8349 (typ != GF_MINDBOOST_PLAYER) && (typ != GF_IDENTIFY) &&
8350 (typ != GF_SLOWPOISON_PLAYER) && (typ != GF_CURING) &&
8351 (typ != GF_OLD_POLY)) /* Non-hostile players may (un)polymorph each other */
8352 { /* If this was intentional, make target hostile */
8353 if (check_hostile(0 - who, Ind)) {
8354 /* Make target hostile if not already */
8355 if (!check_hostile(Ind, 0 - who)) {
8356 bool result = FALSE;
8357
8358 if (Players[Ind]->pvpexception < 2)
8359 result = add_hostility(Ind, killer, FALSE);
8360
8361 /* Log it if no blood bond - mikaelh */
8362 if (!player_list_find(p_ptr->blood_bond, Players[0 - who]->id)) {
8363 s_printf("%s attacked %s (spell; result %d).\n", p_ptr->name, Players[0 - who]->name, result);
8364 }
8365 }
8366 }
8367
8368 /* Hostile players hit each other */
8369 if (check_hostile(Ind, 0 - who)) {
8370 #ifdef EXPERIMENTAL_PVP_SPELL_DAM
8371 int __dam = randint(dam);
8372 if (randint(1)) __dam *= -1;
8373 dam += __dam;
8374 #else
8375 /* XXX Reduce damage to 1/3 */
8376 dam = (dam + PVP_SPELL_DAM_REDUCTION - 1) / PVP_SPELL_DAM_REDUCTION;
8377 #endif
8378 }
8379
8380 /* people not in the same party hit each other */
8381 else if (!Players[0 - who]->party || !p_ptr->party ||
8382 (!player_in_party(Players[0 - who]->party, Ind)))
8383 {
8384 #if 0 /* NO - C. Blue */
8385 #else /* changed it to YES.. - still C. Blue - but added an if..*/
8386 if (check_hostile(0 - who, Ind)) {
8387 #ifdef EXPERIMENTAL_PVP_SPELL_DAM
8388 int __dam = randint(dam);
8389 if (randint(1)) __dam *= -1;
8390 dam += __dam;
8391 #else
8392 /* XXX Reduce damage by 1/3 */
8393 dam = (dam + PVP_SPELL_DAM_REDUCTION - 1) / PVP_SPELL_DAM_REDUCTION;
8394 #endif
8395 #ifdef KURZEL_PK
8396 if (!magik(NEUTRAL_FIRE_CHANCE))
8397 #else
8398 if ((cfg.use_pk_rules == PK_RULES_DECLARE &&
8399 !(p_ptr->pkill & PKILL_KILLER)) &&
8400 !magik(NEUTRAL_FIRE_CHANCE))
8401 #endif
8402 //#endif (<- use this endif, if above #if 0 becomes #if 1 again) /* Just return without harming: */
8403 return(FALSE);
8404 } else { return(FALSE); }
8405 #endif /* ..and remove this one accordingly */
8406 } else {
8407 /* Players in the same party can't harm each others */
8408 #if FRIEND_FIRE_CHANCE
8409 #ifdef EXPERIMENTAL_PVP_SPELL_DAM
8410 int __dam = randint(dam);
8411 if (randint(1)) __dam *= -1;
8412 dam += __dam;
8413 #else
8414 dam = (dam + PVP_SPELL_DAM_REDUCTION - 1) / PVP_SPELL_DAM_REDUCTION;
8415 #endif
8416 if (!magik(FRIEND_FIRE_CHANCE))
8417 #endif
8418 return(FALSE);
8419 }
8420 /* If it's a support spell (friendly), remember the caster's level for henc anti-cheeze
8421 to prevent him from getting exp until the supporting effects surely have run out: */
8422 } else if (typ != GF_OLD_POLY) {
8423 if (p_ptr->supp < Players[0 - who]->max_lev) p_ptr->supp = Players[0 - who]->max_lev;
8424 if (p_ptr->supp_top < Players[0 - who]->max_plv) p_ptr->supp_top = Players[0 - who]->max_plv;
8425 p_ptr->support_timer = cfg.spell_stack_limit ? cfg.spell_stack_limit : 200;
8426
8427 friendly_player = TRUE;
8428 /* It's a non-hostile, yet possibly damaging spell which isn't
8429 affected by 'friendly fire' rules or pvp rules, but counts
8430 more like 'an accident' if it really damages someone. Usually
8431 it is probably a supportive spell though. (eg GF_HEALINGCLOUD) */
8432 } else {
8433 friendly_player = TRUE;
8434 }
8435 }
8436
8437
8438 /* PvP often gives same message output as fuzzy */
8439 if (!strcmp(attacker,"") || !strcmp(m_name,"")) fuzzy = TRUE;
8440
8441 /* Ghost-check (also checks for admin status) */
8442 /* GHOST CHECK */
8443 if ((p_ptr->ghost && ((typ == GF_HEAL_PLAYER) || /*(typ == GF_AWAY_ALL) ||*/
8444 (typ == GF_WRAITH_PLAYER) || (typ == GF_SPEED_PLAYER) ||
8445 /*(typ == GF_SHIELD_PLAYER) || (typ == GF_RECALL_PLAYER) ||*/
8446 (typ == GF_BLESS_PLAYER) || (typ == GF_REMFEAR_PLAYER) ||
8447 (typ == GF_REMCONF_PLAYER) || (typ == GF_REMIMAGE_PLAYER) ||
8448 (typ == GF_SATHUNGER_PLAYER) || /*(typ == GF_RESFIRE_PLAYER) ||
8449 (typ == GF_RESCOLD_PLAYER) ||*/ (typ == GF_CUREPOISON_PLAYER) ||
8450 (typ == GF_SEEINVIS_PLAYER) || (typ == GF_SEEMAP_PLAYER) ||
8451 (typ == GF_CURECUT_PLAYER) || /*(typ == GF_CURESTUN_PLAYER) ||*/
8452 (typ == GF_DETECTCREATURE_PLAYER) || (typ == GF_DETECTDOOR_PLAYER) ||
8453 (typ == GF_DETECTTRAP_PLAYER) || /*(typ == GF_TELEPORTLVL_PLAYER) ||
8454 (typ == GF_RESPOIS_PLAYER) || (typ == GF_RESELEC_PLAYER) ||
8455 (typ == GF_RESACID_PLAYER) ||*/ (typ == GF_HPINCREASE_PLAYER) ||
8456 (typ == GF_HERO_PLAYER) || (typ == GF_SHERO_PLAYER) ||
8457 /*(typ == GF_TELEPORT_PLAYER) ||*/ (typ == GF_ZEAL_PLAYER) || (typ == GF_REMCURSE_PLAYER) ||
8458 (typ == GF_RESTORE_PLAYER) || (typ == GF_CURING) ||
8459 (typ == GF_CURE_PLAYER) || /*(typ == GF_RESURRECT_PLAYER) ||
8460 (typ == GF_SANITY_PLAYER) || (typ == GF_SOULCURE_PLAYER) ||*/
8461 (typ == GF_OLD_HEAL) || (typ == GF_OLD_SPEED) ||
8462 (typ == GF_HEALINGCLOUD) || /* shoo ghost, shoo */
8463 (typ == GF_IDENTIFY) || (typ == GF_SLOWPOISON_PLAYER) ||
8464 (typ == GF_OLD_POLY) || (typ == GF_MINDBOOST_PLAYER)))
8465 ||
8466 /* ADMIN CHECK */
8467 (is_admin(p_ptr) && ((typ == GF_HEAL_PLAYER) || (typ == GF_AWAY_ALL) ||
8468 (typ == GF_WRAITH_PLAYER) || (typ == GF_SPEED_PLAYER) ||
8469 (typ == GF_SHIELD_PLAYER) || (typ == GF_RECALL_PLAYER) ||
8470 (typ == GF_BLESS_PLAYER) || (typ == GF_REMFEAR_PLAYER) ||
8471 (typ == GF_REMCONF_PLAYER) || (typ == GF_REMIMAGE_PLAYER) ||
8472 (typ == GF_SATHUNGER_PLAYER) || (typ == GF_RESFIRE_PLAYER) ||
8473 (typ == GF_RESCOLD_PLAYER) || (typ == GF_CUREPOISON_PLAYER) ||
8474 (typ == GF_SEEINVIS_PLAYER) || (typ == GF_SEEMAP_PLAYER) ||
8475 (typ == GF_CURECUT_PLAYER) || (typ == GF_CURESTUN_PLAYER) ||
8476 (typ == GF_DETECTCREATURE_PLAYER) || (typ == GF_DETECTDOOR_PLAYER) ||
8477 (typ == GF_DETECTTRAP_PLAYER) || (typ == GF_TELEPORTLVL_PLAYER) ||
8478 (typ == GF_RESPOIS_PLAYER) || (typ == GF_RESELEC_PLAYER) ||
8479 (typ == GF_RESACID_PLAYER) || (typ == GF_HPINCREASE_PLAYER) ||
8480 (typ == GF_HERO_PLAYER) || (typ == GF_SHERO_PLAYER) ||
8481 (typ == GF_TELEPORT_PLAYER) || (typ == GF_ZEAL_PLAYER) ||
8482 (typ == GF_RESTORE_PLAYER) || (typ == GF_REMCURSE_PLAYER) ||
8483 (typ == GF_CURE_PLAYER) || (typ == GF_RESURRECT_PLAYER) ||
8484 (typ == GF_SANITY_PLAYER) || (typ == GF_SOULCURE_PLAYER) ||
8485 (typ == GF_OLD_HEAL) || (typ == GF_OLD_SPEED) ||
8486 (typ == GF_HEALINGCLOUD) || (typ == GF_MINDBOOST_PLAYER) ||
8487 (typ == GF_SLOWPOISON_PLAYER) || (typ == GF_CURING) ||
8488 (typ == GF_OLD_POLY) || (typ == GF_IDENTIFY))))
8489 { /* No effect on ghosts / admins */
8490 #if 0 //redundant?
8491 /* Skip non-connected players */
8492 if (p_ptr->conn != NOT_CONNECTED) {
8493 /* Disturb */
8494 disturb(Ind, 1, 0);
8495 }
8496 #endif
8497 /* Return "Anything seen?" */
8498 return (obvious);
8499 }
8500
8501
8502
8503 #ifndef NEW_DODGING
8504 /* Bolt attack from a monster, a player or a trap */
8505 // if ((!rad) && get_skill(p_ptr, SKILL_DODGE) && (who > 0))
8506 /* Hack -- HIDE(direct) spell cannot be dodged */
8507 if (!friendly_player &&
8508 get_skill(p_ptr, SKILL_DODGE) && !(flg & PROJECT_HIDE | PROJECT_JUMP | PROJECT_NODO))
8509 {
8510 if ((!rad) && (who >= PROJECTOR_TRAP)) {
8511 // int chance = (p_ptr->dodge_level - ((r_info[who].level * 5) / 6)) / 3;
8512 /* Hack -- let's use 'dam' for now */
8513 int chance = (p_ptr->dodge_level - dam / 6) / 3;
8514
8515 if ((chance > 0) && magik(chance)) {
8516 // msg_print(Ind, "You dodge a magical attack!");
8517 msg_format(Ind, "\377%cYou dodge the projectile!", COLOUR_DODGE_GOOD);
8518 return (TRUE);
8519 }
8520 }
8521 /* MEGAHACK -- allow to dodge 'bolt' traps */
8522 else if ((rad < 2) && (who == PROJECTOR_TRAP)) {
8523 /* Hack -- let's use 'dam' for now */
8524 int chance = (p_ptr->dodge_level - dam / 4) / 4;
8525
8526 if ((chance > 0) && magik(chance)) {
8527 msg_format(Ind, "\377%cYou dodge a magical attack!", COLOUR_DODGE_GOOD);
8528 return (TRUE);
8529 }
8530 }
8531 }
8532 #else
8533 /* Bolt attack from a monster, a player or a trap */
8534 // if (!p_ptr->blind && !(flg & (PROJECT_HIDE | PROJECT_GRID | PROJECT_JUMP)) && magik(apply_dodge_chance(Ind, getlevel(wpos) + 1000))) { /* hack - more difficult to dodge ranged attacks */
8535 if (!friendly_player &&
8536 !p_ptr->blind && !(flg & (PROJECT_HIDE | PROJECT_JUMP | PROJECT_STAY | PROJECT_NODO)) && magik(apply_dodge_chance(Ind, getlevel(wpos)))) {
8537 if ((!rad) && (who >= PROJECTOR_TRAP)) {
8538 msg_format(Ind, "\377%cYou dodge %s projectile!", COLOUR_DODGE_GOOD, m_name_gen);
8539 return (TRUE);
8540 }
8541 /* MEGAHACK -- allow to dodge 'bolt' traps */
8542 else if ((rad < 2) && (who == PROJECTOR_TRAP)) {
8543 msg_format(Ind, "\377%cYou dodge %s magical attack!", COLOUR_DODGE_GOOD, m_name_gen);
8544 return (TRUE);
8545 }
8546 }
8547 #endif
8548
8549
8550 /* Reflection */
8551 #if 0
8552 /* Effects done by the plane cannot bounce */
8553 if (!friendly_player && p_ptr->reflect && !a_rad && !(randint(10) == 1) && ((who != -101) && (who != -100))) {
8554 int t_y, t_x;
8555 int max_attempts = 10;
8556
8557 if (blind) msg_print("Something bounces!");
8558 else msg_print("The attack bounces!");
8559
8560 /* Choose 'new' target */
8561 do {
8562 t_y = m_list[who].fy - 1 + randint(3);
8563 t_x = m_list[who].fx - 1 + randint(3);
8564 max_attempts--;
8565 } while (max_attempts && in_bounds2(t_y, t_x) &&
8566 !(player_has_los_bold(t_y, t_x)));
8567
8568 if (max_attempts < 1) {
8569 t_y = m_list[who].fy;
8570 t_x = m_list[who].fx;
8571 }
8572
8573 project(0, 0, t_y, t_x, dam, typ, (PROJECT_STOP|PROJECT_KILL), "");
8574
8575 disturb(1, 0);
8576 return(TRUE);
8577 }
8578 #endif
8579 /* pre-calc kinetic shield mana tax before doing the reflection check below */
8580 if (!friendly_player && p_ptr->kinetic_shield && (typ == GF_ARROW || typ == GF_MISSILE)
8581 && p_ptr->csp >= dam / 7 &&
8582 !rad && who != PROJECTOR_POTION && who != PROJECTOR_TERRAIN &&
8583 (flg & PROJECT_KILL) && !(flg & (PROJECT_NORF | PROJECT_JUMP | PROJECT_STAY | PROJECT_NODF))) {
8584 /* drain mana */
8585 p_ptr->csp -= dam / 7;
8586 p_ptr->redraw |= PR_MANA;
8587 /* test for success */
8588 if (rand_int(2) == 0) kinetic_shield = TRUE;
8589 }
8590 /* Effects done by the plane cannot bounce,
8591 balls / clouds / storms / walls (and beams atm too) cannot bounce - C. Blue */
8592 if (!friendly_player && (
8593 /* kinetic shield? (same as reflect basically) */
8594 kinetic_shield
8595 /* reflect? */
8596 || (p_ptr->reflect &&
8597 !rad && who != PROJECTOR_POTION && who != PROJECTOR_TERRAIN &&
8598 (flg & PROJECT_KILL) && !(flg & (PROJECT_NORF | PROJECT_JUMP | PROJECT_STAY | PROJECT_NODF)) &&
8599 rand_int(20) < ((typ == GF_ARROW || typ == GF_MISSILE) ? 15 : 9))
8600 #ifdef USE_BLOCKING
8601 /* using a shield? requires USE_BLOCKING */
8602 || (magik(apply_block_chance(p_ptr, p_ptr->shield_deflect / 5)) &&
8603 !rad && who != PROJECTOR_POTION && who != PROJECTOR_TERRAIN &&
8604 (flg & PROJECT_KILL) && !(flg & (PROJECT_NORF | PROJECT_JUMP | PROJECT_STAY | PROJECT_NODF)) &&
8605 rand_int(20) < ((typ == GF_ARROW || typ == GF_MISSILE) ? 15 : 9))
8606 #endif
8607 ))
8608 {
8609 int t_y, t_x, ay, ax;
8610 int max_attempts = 10;
8611
8612 if (blind) msg_print(Ind, "Something bounces!");
8613 else {
8614 if (p_ptr->play_vis[0 - who])
8615 msg_format(Ind, "%s attack bounces!", m_name_gen);
8616 else
8617 msg_print(Ind, "Its attack bounces!");
8618 }
8619
8620 /* if ((who != PROJECTOR_TRAP) && who) isn't this wrong? */
8621 if (who && (who > PROJECTOR_UNUSUAL)) { /* can only hit a monster or a player when bouncing */
8622 if (who < 0) {
8623 ay = Players[-who]->py;
8624 ax = Players[-who]->px;
8625 } else {
8626 ay = m_list[who].fy;
8627 ax = m_list[who].fx;
8628 }
8629
8630
8631 /* Choose 'new' target */
8632 do {
8633 t_y = ay - 1 + randint(3);
8634 t_x = ax - 1 + randint(3);
8635 max_attempts--;
8636 }
8637 #if 0
8638 while (max_attempts && in_bounds2(wpos, t_y, t_x) &&
8639 !(player_has_los_bold(Ind, t_y, t_x)));
8640 #else // 0
8641 while (max_attempts && (!in_bounds2(wpos, t_y, t_x) ||
8642 !(player_has_los_bold(Ind, t_y, t_x))));
8643 #endif // 0
8644
8645 if (max_attempts < 1) {
8646 t_y = ay;
8647 t_x = ax;
8648 }
8649
8650 // project(0, 0, wpos, t_y, t_x, dam, typ, (PROJECT_STOP|PROJECT_KILL));
8651 project(0 - Ind, 0, wpos, t_y, t_x, dam, typ, (PROJECT_STOP|PROJECT_KILL), "");
8652 }
8653
8654 disturb(Ind, 1, 0);
8655 return TRUE;
8656 }
8657
8658
8659 #ifdef USE_BLOCKING
8660 /* Bolt attacks: Took cover behind a shield? requires USE_BLOCKING */
8661 if (!friendly_player && /* cannot take cover from clouds or LOS projections (latter might be subject to change?) - C. Blue */
8662 /* jump for LOS projecting, stay for clouds; !norf was already checked above -- not sure if fire_beam was covered (PROJECT_BEAM)! */
8663 !rad && (flg & PROJECT_KILL) &&
8664 !(flg & (PROJECT_NORF | PROJECT_JUMP | PROJECT_STAY | PROJECT_NODF))
8665 ) /* requires stances to * 2 etc.. post-king -> best stance */
8666 {
8667 if (p_ptr->shield_deflect && magik(apply_block_chance(p_ptr, p_ptr->shield_deflect) / ((flg & PROJECT_LODF) ? 2 : 1))) {
8668 if (blind) msg_format(Ind, "\377%cSomething glances off your shield!", COLOUR_BLOCK_GOOD);
8669 else msg_format(Ind, "\377%cYou deflect %s attack!", COLOUR_BLOCK_GOOD, m_name_gen);
8670 #ifdef USE_SOUND_2010
8671 if (p_ptr->sfx_defense) sound(Ind, "block_shield", NULL, SFX_TYPE_ATTACK, FALSE);//not block_shield_projectile (silly for magical attacks)
8672 #endif
8673
8674 #ifndef NEW_SHIELDS_NO_AC
8675 /* if we hid behind the shield from an acidic attack, damage the shield probably! */
8676 if (magik((dam < 5 ? 5 : (dam < 50 ? 10 : 25)))) shield_takes_damage(Ind, typ);
8677 #endif
8678
8679 disturb(Ind, 1, 0);
8680 return TRUE;
8681 }
8682 }
8683 /* Ball attacks: Took cover behind a shield? requires USE_BLOCKING */
8684 else if (!friendly_player && /* cannot take cover from clouds or LOS projections (latter might be subject to change?) - C. Blue */
8685 /* jump for LOS projecting, stay for clouds; !norf was already checked above -- not sure if fire_beam was covered (PROJECT_BEAM)! */
8686 (flg & PROJECT_KILL) && (flg & PROJECT_NORF) && !(flg & (PROJECT_JUMP | PROJECT_STAY | PROJECT_NODF))) /* PROJECT_STAY to exempt 'cloud' spells! */
8687 /* requires stances to * 2 etc.. post-king -> best stance */
8688 {
8689 if (p_ptr->shield_deflect && magik(apply_block_chance(p_ptr, p_ptr->shield_deflect) / ((flg & PROJECT_LODF) ? 4 : 2))) {
8690 if (blind) msg_format(Ind, "\377%cSomething hurls along your shield!", COLOUR_BLOCK_GOOD);
8691 else msg_format(Ind, "\377%cYou cover before %s attack!", COLOUR_BLOCK_GOOD, m_name_gen);
8692
8693 #ifndef NEW_SHIELDS_NO_AC
8694 /* if we hid behind the shield from an acidic attack, damage the shield probably! */
8695 if (magik((dam < 5 ? 5 : (dam < 50 ? 10 : 25)))) shield_takes_damage(Ind, typ);
8696 #endif
8697
8698 disturb(Ind, 1, 0);
8699 return TRUE;
8700 }
8701 }
8702 #endif
8703
8704 /* Test for stair GOI already, to prevent not only damage but according effects too! - C. Blue */
8705 /* Mega-Hack -- Apply "invulnerability" */
8706 if (!friendly_player && p_ptr->invuln && (!bypass_invuln)) {
8707 /* 1 in 2 chance to fully deflect the damage */
8708 if (magik(40)) {
8709 msg_print(Ind, "The attack is fully deflected by a magic shield.");
8710 if (who != PROJECTOR_TERRAIN) break_cloaking(Ind, 0);
8711 return(TRUE);
8712 }
8713 dam = (dam + 1) / 2;
8714
8715 /* prevent multiple damage cutting */
8716 p_ptr->invuln_applied = TRUE;
8717 }
8718
8719
8720 /* Analyze the damage */
8721 switch (typ) {
8722 /* Psionics */
8723 case GF_PSI:
8724 if (rand_int(100) < p_ptr->skill_sav) psi_resists++;
8725 if (p_ptr->mindboost && magik(p_ptr->mindboost_power)) psi_resists++;
8726 if ((p_ptr->shero || p_ptr->berserk) && (rand_int(100) >= p_ptr->skill_sav)) psi_resists--;
8727 if (p_ptr->confused) psi_resists--;
8728 if (p_ptr->image) psi_resists--;
8729 if (p_ptr->stun) psi_resists--;
8730 if ((p_ptr->afraid) && (rand_int(100) >= p_ptr->skill_sav)) psi_resists--;
8731
8732 if (psi_resists > 0) {
8733 /* No side effects */
8734
8735 /* Reduce damage */
8736 for (k = 0; k < psi_resists ; k++) {
8737 dam = dam * 4 / (4 + randint(5));
8738 }
8739
8740 /* Telepathy reduces damage */
8741 if (p_ptr->telepathy) dam = dam * (3 + randint(6)) / 9;
8742 } else {
8743 /* Telepathy increases damage */
8744 if (p_ptr->telepathy) dam = dam * (6 + randint(6)) / 6;
8745 }
8746 if (p_ptr->pclass == CLASS_MINDCRAFTER) dam /= 2;
8747
8748 if (fuzzy) msg_format(Ind, "Your mind is hit by mental energy for \377%c%d \377wdamage!", damcol, dam);
8749 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8750
8751 if (psi_resists <= 0) {
8752 /* Unresisted */
8753 if (!p_ptr->resist_conf &&
8754 !(p_ptr->mindboost && magik(p_ptr->mindboost_power)))
8755 //set_confused(Ind, p_ptr->confused + rand_int(20) + 10); too long for pvp?
8756 set_confused(Ind, p_ptr->confused + rand_int(5) + 5);
8757
8758 /* At the moment:
8759 No sleep/stun/fear effects (like it has on monsters), or image(hallu)
8760 */
8761 }
8762 take_hit(Ind, dam, killer, -who);
8763 if (!IS_PVP) take_sanity_hit(Ind, dam / 8, killer); /* note: traps deal ~130..320 damage (depth 0..100) */
8764 break;
8765
8766 /* Standard damage -- hurts inventory too */
8767 case GF_ACID:
8768 dam = acid_dam(Ind, dam, killer, -who);
8769 if (who == PROJECTOR_TERRAIN && dam == 0) ;
8770 else if (fuzzy) msg_format(Ind, "You are hit by acid for \377%c%d \377wdamage!", damcol, dam);
8771 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8772 take_hit(Ind, dam, killer, -who);
8773 break;
8774
8775 /* Standard damage -- hurts inventory too */
8776 case GF_FIRE:
8777 dam = fire_dam(Ind, dam, killer, -who);
8778 if (who == PROJECTOR_TERRAIN && dam == 0) ;
8779 else if (fuzzy) msg_format(Ind, "You are hit by fire for \377%c%d \377wdamage!", damcol, dam);
8780 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8781 take_hit(Ind, dam, killer, -who);
8782 break;
8783
8784 /* Standard damage -- hurts inventory too */
8785 case GF_COLD:
8786 dam = cold_dam(Ind, dam, killer, -who);
8787 if (who == PROJECTOR_TERRAIN && dam == 0) ;
8788 else if (fuzzy) msg_format(Ind, "You are hit by cold for \377%c%d \377wdamage!", damcol, dam);
8789 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8790 take_hit(Ind, dam, killer, -who);
8791 break;
8792
8793 /* Standard damage -- hurts inventory too */
8794 case GF_ELEC:
8795 dam = elec_dam(Ind, dam, killer, -who);
8796 apply_discharge(Ind, dam);
8797 if (who == PROJECTOR_TERRAIN && dam == 0) ;
8798 else if (fuzzy) msg_format(Ind, "You are hit by lightning for \377%c%d \377wdamage!", damcol, dam);
8799 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8800 take_hit(Ind, dam, killer, -who);
8801 break;
8802
8803 /* Standard damage -- also poisons player */
8804 case GF_POIS:
8805 if (p_ptr->immune_poison) {
8806 dam = 0;
8807 if (who == PROJECTOR_TERRAIN) ;
8808 else if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
8809 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8810 } else {
8811 if (p_ptr->resist_pois) dam = (dam + 2) / 3;
8812 if (p_ptr->oppose_pois) dam = (dam + 2) / 3;
8813 if (p_ptr->suscep_pois) dam = (dam + 2) * 2;
8814
8815 if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
8816 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8817 take_hit(Ind, dam, killer, -who);
8818 if (!(p_ptr->resist_pois || p_ptr->oppose_pois) && dam > 0) {
8819 /* don't poison for too long in pvp */
8820 if (IS_PVP) {
8821 if (p_ptr->poisoned < 10) (void)set_poisoned(Ind, p_ptr->poisoned + rand_int(4), -who);
8822 } else {
8823 (void)set_poisoned(Ind, p_ptr->poisoned + rand_int(dam) + 10, -who);
8824 }
8825 }
8826 }
8827 break;
8828
8829 /* Standard damage */
8830 case GF_MISSILE:
8831 if (p_ptr->biofeedback) dam /= 2;
8832 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
8833 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8834 take_hit(Ind, dam, killer, -who);
8835 break;
8836
8837 #ifdef ARCADE_SERVER
8838 case GF_PUSH:
8839 // msg_print(Ind, "You are pushed by something!");
8840 msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8841 (void)set_pushed(Ind, dam);
8842 break;
8843 #endif
8844
8845 case GF_HELL_FIRE:
8846 if (p_ptr->body_monster && (r_ptr->flags3 & RF3_GOOD)) dam *= 2;
8847 if (p_ptr->suscep_good) dam = (dam * 3) / 4;
8848 if (p_ptr->suscep_evil) dam *= 2;
8849 if (p_ptr->immune_fire) dam /= 2;
8850 else {
8851 if (p_ptr->resist_fire) dam = ((dam + 2) * 3) / 4;
8852 if (p_ptr->oppose_fire) dam = ((dam + 2) * 3) / 4;
8853 if (p_ptr->suscep_fire) dam = ((dam + 2) * 5) / 3;
8854 }
8855 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
8856 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8857 take_hit(Ind, dam, killer, -who);
8858 break;
8859
8860 /* Holy Orb -- Player only takes partial damage */
8861 case GF_HOLY_ORB:
8862 if (p_ptr->suscep_evil) dam = (dam * 3) / 4;
8863 if (p_ptr->suscep_good) dam *= 2;
8864 if (p_ptr->body_monster && (r_ptr->flags3 & RF3_GOOD)) dam /= 4;
8865 if (p_ptr->pclass == CLASS_PRIEST) dam = 0;
8866 if (p_ptr->pclass == CLASS_PALADIN) dam /= 2;
8867 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
8868 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8869 take_hit(Ind, dam, killer, -who);
8870 break;
8871
8872 case GF_HOLY_FIRE:
8873 if (p_ptr->suscep_evil) dam = (dam * 3) / 4;
8874 if (p_ptr->suscep_good) dam *= 2;
8875 if (p_ptr->body_monster && (r_ptr->flags3 & RF3_GOOD)) dam /= 4;
8876 if (p_ptr->immune_fire) dam /= 2;
8877 else {
8878 if (p_ptr->resist_fire) dam = ((dam + 2) * 3) / 4;
8879 if (p_ptr->oppose_fire) dam = ((dam + 2) * 3) / 4;
8880 if (p_ptr->suscep_fire) dam = ((dam + 2) * 4) / 3;
8881 }
8882 if (p_ptr->pclass == CLASS_PRIEST) dam = 0;
8883 if (p_ptr->pclass == CLASS_PALADIN) dam /= 2;
8884 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
8885 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8886 take_hit(Ind, dam, killer, -who);
8887 break;
8888
8889 /* Arrow -- XXX no dodging */
8890 case GF_ARROW:
8891 if (p_ptr->biofeedback) dam /= 2;
8892 if (fuzzy) msg_format(Ind, "You are hit by something sharp for \377%c%d \377wdamage!", damcol, dam);
8893 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8894 take_hit(Ind, dam, killer, -who);
8895 break;
8896
8897 /* Plasma -- Fire/Lightning/Force */
8898 case GF_PLASMA:
8899 {
8900 bool ignore_fire = p_ptr->oppose_fire || p_ptr->resist_fire || p_ptr->immune_fire;
8901 bool ignore_elec = p_ptr->oppose_elec || p_ptr->resist_elec || p_ptr->immune_elec;
8902 bool inven_fire = (p_ptr->oppose_fire && p_ptr->resist_fire) || p_ptr->immune_fire;
8903 bool inven_elec = (p_ptr->oppose_elec && p_ptr->resist_elec) || p_ptr->immune_elec;
8904
8905 if (p_ptr->immune_fire && p_ptr->immune_elec) dam = (dam + 8) / 9;
8906 else {
8907 if (p_ptr->immune_fire) dam = (dam + 3) / 4;
8908 else if (p_ptr->resist_plasma) {
8909 dam *= 3;
8910 dam = (dam + 6) / (randint(6) + 6);
8911 }
8912 else if (p_ptr->resist_fire || p_ptr->oppose_fire) {
8913 dam *= 3;
8914 dam = (dam + 4) / 5;
8915 } else if (p_ptr->suscep_fire) dam = (dam * 3) / 2;
8916
8917 if (p_ptr->resist_elec || p_ptr->oppose_elec || p_ptr->immune_elec)
8918 dam = ((dam + 4) * 4) / 5;
8919 else if (p_ptr->suscep_elec) dam = (dam * 4) / 3;
8920 }
8921
8922
8923 if (fuzzy) msg_format(Ind, "You are hit by something hot for \377%c%d \377wdamage!", damcol, dam);
8924 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8925
8926 take_hit(Ind, dam, killer, -who);
8927
8928 if (!p_ptr->resist_sound) {
8929 int k = (randint((dam > 40) ? 35 : (dam * 3 / 4 + 5)));
8930 (void)set_stun(Ind, p_ptr->stun + k);
8931 }
8932
8933 /* Reduce stats */
8934 if (!ignore_fire && !ignore_elec) {
8935 if (randint(HURT_CHANCE) == 1) {
8936 if (rand_int(3)) (void) do_dec_stat(Ind, A_STR, DAM_STAT_TYPE((dam < 30) ? 1 : (dam < 60) ? 2 : 3));
8937 else (void) do_dec_stat(Ind, A_DEX, DAM_STAT_TYPE((dam < 30) ? 1 : (dam < 60) ? 2 : 3));
8938 }
8939 } else if (ignore_elec) {
8940 if (randint(HURT_CHANCE) == 1)
8941 (void) do_dec_stat(Ind, A_STR, DAM_STAT_TYPE((dam < 30) ? 1 : (dam < 60) ? 2 : 3));
8942 } else if (ignore_fire) {
8943 if (randint(HURT_CHANCE) == 1)
8944 (void) do_dec_stat(Ind, A_DEX, DAM_STAT_TYPE((dam < 30) ? 1 : (dam < 60) ? 2 : 3));
8945 }
8946
8947 /* Don't kill inventory in bloodbond... */
8948 if (IS_PVP && check_blood_bond(Ind, -who)) break;
8949
8950 /* Inventory damage */
8951 if (inven_fire && inven_elec) break;
8952 if (!inven_fire && !inven_elec) {
8953 if (rand_int(3)) inven_damage(Ind, set_fire_destroy, (dam < 30) ? 1 : (dam < 60) ? 2 : 3);
8954 else inven_damage(Ind, set_elec_destroy, (dam < 30) ? 1 : (dam < 60) ? 2 : 3);
8955 } else if (inven_elec) inven_damage(Ind, set_fire_destroy, (dam < 30) ? 1 : (dam < 60) ? 2 : 3);
8956 else inven_damage(Ind, set_elec_destroy, (dam < 30) ? 1 : (dam < 60) ? 2 : 3);
8957
8958 break;
8959 }
8960
8961 /* Nether -- drain experience */
8962 case GF_NETHER_WEAK:
8963 /* potion smash effect of a Potion of Death */
8964 if (p_ptr->suscep_life || p_ptr->ghost) {
8965 dam = 0;
8966 if (who == PROJECTOR_TERRAIN) ;
8967 else if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
8968 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8969 break;
8970 }
8971 case GF_NETHER:
8972 if (p_ptr->immune_neth) {
8973 dam = 0;
8974 if (who == PROJECTOR_TERRAIN) ;
8975 else if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
8976 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8977 } else if (p_ptr->resist_neth) {
8978 dam *= 6; dam /= (randint(6) + 6);
8979 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
8980 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8981 take_hit(Ind, dam, killer, -who); /* Prevent going down to level 1 and then taking full damage -> instakill */
8982 } else {
8983 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
8984 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
8985 take_hit(Ind, dam, killer, -who); /* Prevent going down to level 1 and then taking full damage -> instakill */
8986
8987 if (p_ptr->lev == 99 || (p_ptr->mode & MODE_PVP)) {
8988 msg_print(Ind, "You are unaffected!");
8989 } else if (p_ptr->hold_life && (rand_int(100) < 75)) {
8990 msg_print(Ind, "You keep hold of your life force!");
8991 } else if (p_ptr->hold_life) {
8992 msg_print(Ind, "You feel your life slipping away!");
8993 lose_exp(Ind, 200 + (p_ptr->exp/1000) * MON_DRAIN_LIFE);
8994 } else {
8995 msg_print(Ind, "You feel your life draining away!");
8996 lose_exp(Ind, 200 + (p_ptr->exp/100) * MON_DRAIN_LIFE);
8997 }
8998 }
8999 break;
9000
9001 /* Water -- stun/confuse */
9002 case GF_WATER:
9003 case GF_WAVE:
9004 if (p_ptr->immune_water) {
9005 dam = 0;
9006 //doesn't make much sense-- if (who == PROJECTOR_TERRAIN) ; else
9007 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9008 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9009 take_hit(Ind, dam, killer, -who);
9010 } else {
9011 if (p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC))
9012 {
9013 dam = (dam + 3) / 4;
9014 }
9015 else if (p_ptr->resist_water)
9016 {
9017 dam = (dam + 2) / 3;
9018 }
9019 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9020 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9021 if (TOOL_EQUIPPED(p_ptr) != SV_TOOL_TARPAULIN && magik(20 + dam / 20) &&
9022 !(p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)))
9023 {
9024 if (!p_ptr->resist_water || magik(50)) {
9025 /* Don't kill inventory in bloodbond... */
9026 int breakable = 1;
9027 if (IS_PVP) {
9028 if (check_blood_bond(Ind, -who)) {
9029 breakable = 0;
9030 }
9031 }
9032 if (breakable) {
9033 inven_damage(Ind, set_water_destroy, 1);
9034 if (magik(50)) equip_damage(Ind, GF_WATER);
9035 }
9036 }
9037 }
9038 take_hit(Ind, dam, killer, -who);
9039 if ((!p_ptr->resist_water) &&
9040 !(p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)))
9041 {
9042 if (!p_ptr->resist_sound)
9043 {
9044 if (IS_PVP) {
9045 (void)set_stun(Ind, p_ptr->stun + randint(10));
9046 } else { /* pvm */
9047 (void)set_stun(Ind, p_ptr->stun + randint(40));
9048 }
9049 }
9050 if (!p_ptr->resist_conf &&
9051 !(p_ptr->mindboost && magik(p_ptr->mindboost_power)))
9052 {
9053 if (IS_PVP) {
9054 // (void)set_confused(Ind, p_ptr->confused + randint(2));
9055 } else { /* pvm */
9056 (void)set_confused(Ind, p_ptr->confused + randint(5) + 5);
9057 }
9058 }
9059 }
9060 }
9061 break;
9062
9063 case GF_VAPOUR:
9064 if (p_ptr->immune_water) {
9065 dam = 0;
9066 //not really needed-- if (who == PROJECTOR_TERRAIN) ; else
9067 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9068 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9069 take_hit(Ind, dam, killer, -who);
9070 } else {
9071 if (p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC))
9072 dam = (dam + 3) / 4;
9073 else if (p_ptr->resist_water)
9074 dam = (dam + 2) / 3;
9075 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9076 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9077
9078 /* no item damage */
9079
9080 take_hit(Ind, dam, killer, -who);
9081
9082 /* no stun/conf */
9083 }
9084 break;
9085
9086 /* Stun */
9087 case GF_STUN:
9088 if (fuzzy) msg_print(Ind, "You are hit by something!");
9089 if (!p_ptr->resist_sound)
9090 {
9091 (void)set_stun(Ind, p_ptr->stun + randint(40));
9092 }
9093 dam = 0;
9094 break;
9095
9096 /* Chaos -- many effects */
9097 case GF_CHAOS:
9098 if (p_ptr->resist_chaos) {
9099 // dam *= 6; dam /= (randint(7) + 8);
9100 dam *= 6; dam /= (randint(6) + 6);
9101 }
9102 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9103 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9104
9105 take_hit(Ind, dam, killer, -who); /* Prevent going down to level 1 and then taking full damage -> instakill */
9106
9107 if (!p_ptr->resist_conf)
9108 (void)set_confused(Ind, p_ptr->confused + rand_int(20) + 10);
9109 if (!p_ptr->resist_chaos && !(p_ptr->mode & MODE_PVP))
9110 (void)set_image(Ind, p_ptr->image + randint(10));
9111 if (!p_ptr->resist_neth && !p_ptr->resist_chaos) {
9112 if (p_ptr->lev == 99 || (p_ptr->mode & MODE_PVP)) {
9113 msg_print(Ind, "You are unaffected!");
9114 } else if (p_ptr->hold_life && (rand_int(100) < 75)) {
9115 msg_print(Ind, "You keep hold of your life force!");
9116 } else if (p_ptr->hold_life) {
9117 msg_print(Ind, "You feel your life slipping away!");
9118 lose_exp(Ind, 500 + (p_ptr->exp/1000) * MON_DRAIN_LIFE);
9119 } else {
9120 msg_print(Ind, "You feel your life draining away!");
9121 lose_exp(Ind, 5000 + (p_ptr->exp/100) * MON_DRAIN_LIFE);
9122 }
9123 }
9124 break;
9125
9126 /* Shards -- mostly cutting */
9127 case GF_SHARDS:
9128 if (p_ptr->biofeedback) dam /= 2;
9129 if (p_ptr->resist_shard)
9130 dam *= 6; dam /= (randint(6) + 6);
9131 if (fuzzy) msg_format(Ind, "You are hit by something sharp for \377%c%d \377wdamage!", damcol, dam);
9132 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9133 take_hit(Ind, dam, killer, -who);
9134 if ((!p_ptr->resist_shard) && (!p_ptr->no_cut))
9135 (void)set_cut(Ind, p_ptr->cut + dam, -who);
9136 break;
9137
9138 /* Sound -- mostly stunning */
9139 case GF_SOUND:
9140 /* Making the stun effect's power depend on body mass of the monster, giving gold dragons more respect again;
9141 or more dependant on the damage to better fit certain monstes - C. Blue
9142 body masses: 90k kavlax, 110k mature gold d, 170k mature d turtle / ancient d, 190k ancient d turtle / wyrms
9143 hp: 500 drakes + mature turtle, 620 mature gold d + ancient turtle, 700 ancient turtle, 1.3k kavlax, 1.5k ancient d, 5k wyrms */
9144 if (p_ptr->biofeedback) dam /= 2;
9145 if (p_ptr->resist_sound)
9146 {
9147 dam *= 5; dam /= (randint(6) + 6);
9148 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9149 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9150 }
9151 else
9152 {
9153 int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
9154 /* for medium dragons/turtles */
9155 if (dam > 100 && p_ptr->stun < 35) k = 35;
9156 /* for kavlax, ancient things, wyrms, and (unfortunately? dunno..) also aether vortex/hound */
9157 if (dam > 200 && p_ptr->stun < 50) k = 50;
9158 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9159 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9160 (void)set_stun(Ind, p_ptr->stun + k);
9161 }
9162 take_hit(Ind, dam, killer, -who);
9163 break;
9164
9165 /* Pure confusion */
9166 case GF_CONFUSION:
9167 if (p_ptr->resist_conf || p_ptr->resist_chaos)
9168 {
9169 dam *= 5; dam /= (randint(6) + 6);
9170 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9171 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9172 }
9173 else
9174 {
9175 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9176 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9177 (void)set_confused(Ind, p_ptr->confused + randint(20) + 10);
9178 }
9179 take_hit(Ind, dam, killer, -who);
9180 break;
9181
9182 /* Disenchantment -- see above */
9183 case GF_DISENCHANT:
9184 if (p_ptr->resist_disen)
9185 {
9186 dam *= 6; dam /= (randint(6) + 6);
9187 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9188 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9189 }
9190 else
9191 {
9192 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9193 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9194 (void)apply_disenchant(Ind, 0);
9195 }
9196 take_hit(Ind, dam, killer, -who);
9197 break;
9198
9199 /* Nexus -- see above */
9200 case GF_NEXUS:
9201 if (p_ptr->resist_nexus)
9202 {
9203 dam *= 6; dam /= (randint(6) + 6);
9204 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9205 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9206 }
9207 else
9208 {
9209 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9210 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9211 apply_nexus(Ind, m_ptr, -who);
9212 }
9213 take_hit(Ind, dam, killer, -who);
9214 break;
9215
9216 /* Force -- mostly stun */
9217 case GF_FORCE:
9218 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9219 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9220 if (!p_ptr->resist_sound)
9221 {
9222 (void)set_stun(Ind, p_ptr->stun + randint(20));
9223 }
9224 take_hit(Ind, dam, killer, -who);
9225 break;
9226
9227 /* Inertia -- slowness */
9228 case GF_INERTIA:
9229 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9230 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9231 if (p_ptr->mindboost && magik(p_ptr->mindboost_power))
9232 { /* resist the effect */
9233 } else if (!p_ptr->free_act) {
9234 (void)set_slow(Ind, p_ptr->slow + rand_int(4) + 4);
9235 } else {
9236 (void)set_slow(Ind, p_ptr->slow + rand_int(3) + 2);
9237 }
9238 take_hit(Ind, dam, killer, -who);
9239 break;
9240
9241 /* Lite -- blinding */
9242 case GF_LITE:
9243 if (p_ptr->suscep_lite) {
9244 dam *= 2;
9245 }
9246 if (p_ptr->resist_lite) {
9247 dam *= 4; dam /= (randint(6) + 6);
9248 }
9249 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9250 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9251 if (!p_ptr->resist_lite && !blind && !p_ptr->resist_blind) {
9252 (void)set_blind(Ind, p_ptr->blind + randint(5) + 2);
9253 }
9254 take_hit(Ind, dam, killer, -who);
9255 break;
9256
9257 /* Dark -- blinding */
9258 case GF_DARK:
9259 if (p_ptr->resist_dark) {
9260 dam *= 4; dam /= (randint(6) + 6);
9261 }
9262 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9263 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9264 if (!p_ptr->resist_dark && !blind && !p_ptr->resist_blind) {
9265 (void)set_blind(Ind, p_ptr->blind + randint(5) + 2);
9266 }
9267 take_hit(Ind, dam, killer, -who);
9268 break;
9269
9270 /* Time -- bolt fewer effects XXX */
9271 case GF_TIME:
9272 if (p_ptr->resist_time) {
9273 dam *= 6;
9274 dam /= (randint(6) + 6);
9275 }
9276 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9277 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9278 take_hit(Ind, dam, killer, -who); /* Prevent going down to level 1 and then taking full damage -> instakill */
9279
9280 if ((p_ptr->mode & MODE_PVP)) break;
9281 else if (p_ptr->resist_time) {
9282 /* a little hack for high-elven runemasters: super low time damage has no drain effects */
9283 if (flg & PROJECT_RNAF) break;
9284
9285 time_influence_choices = randint(9);
9286 }
9287 /* hack: very little time damage won't result in ruination */
9288 else if (dam < 10) time_influence_choices = randint(9);
9289 else time_influence_choices = randint(10);
9290
9291 switch (time_influence_choices) {
9292 case 1: case 2: case 3: case 4: case 5:
9293 if (p_ptr->resist_time) {
9294 /* let's disable it for now to improve time resistance: */
9295 if (magik(25)) {
9296 if (p_ptr->lev == 99) msg_print(Ind, "You are unaffected!");
9297 else {
9298 msg_print(Ind, "You feel life has clocked back.");
9299 lose_exp(Ind, (p_ptr->exp / 100) * MON_DRAIN_LIFE / 4);
9300 }
9301 } else {
9302 msg_print(Ind, "You feel as if life has clocked back, but the feeling passes.");
9303 }
9304 } else {
9305 if (p_ptr->lev == 99) msg_print(Ind, "You are unaffected.");
9306 else {
9307 msg_print(Ind, "You feel life has clocked back.");
9308 lose_exp(Ind, 100 + (p_ptr->exp / 100) * MON_DRAIN_LIFE);
9309 }
9310 }
9311 break;
9312
9313 case 6: case 7: case 8: case 9:
9314 /* Sustenance slightly helps (50%) */
9315 do_dec_stat_time(Ind, rand_int(6), STAT_DEC_NORMAL, 50, p_ptr->resist_time ? 1 : 2, TRUE);
9316 break;
9317
9318 case 10:
9319 msg_print(Ind, "You're not as powerful as you used to be...");
9320 for (k = 0; k < 6; k++) {
9321 /* Sustenance slightly helps (50%) */
9322 do_dec_stat_time(Ind, rand_int(6), STAT_DEC_NORMAL, 50, p_ptr->resist_time ? 1 : 3, FALSE);
9323 }
9324 break;
9325 }
9326
9327 break;
9328
9329 /* Gravity -- stun plus slowness plus teleport */
9330 case GF_GRAVITY:
9331 /* Feather fall (flying implies it, so flying is covered too) lets us resist gravity */
9332 if (p_ptr->feather_fall) {
9333 dam *= 6; dam /= (randint(6) + 6);
9334 }
9335 if (fuzzy) msg_format(Ind, "You are hit by something strange for \377%c%d \377wdamage!", damcol, dam);
9336 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9337 msg_print(Ind, "Gravity warps around you.");
9338 if (!p_ptr->martyr) teleport_player(Ind, 5, TRUE);
9339 (void)set_slow(Ind, p_ptr->slow + rand_int(4) + 3);
9340 if (!p_ptr->resist_sound) {
9341 int k = (randint((dam > 90) ? 35 : (dam / 3 + 5)));
9342 (void)set_stun(Ind, p_ptr->stun + k);
9343 }
9344 take_hit(Ind, dam, killer, -who);
9345 break;
9346
9347 /* Pure damage */
9348 case GF_MANA:
9349 if (p_ptr->resist_mana) { dam *= 6; dam /= (randint(6) + 6); }
9350 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9351 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9352 take_hit(Ind, dam, killer, -who);
9353 break;
9354
9355 /* Pure damage */
9356 case GF_METEOR:
9357 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9358 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9359 take_hit(Ind, dam, killer, -who);
9360 if (!p_ptr->resist_sound) (void)set_stun(Ind, p_ptr->stun + 25 + randint(15));
9361 break;
9362
9363 /* Ice -- cold plus stun plus cuts */
9364 case GF_ICE:
9365 k = dam;
9366 dam = (k * 3) / 5;/* 60% COLD damage, total cold damage is saved in 'dam' */
9367 k = (k * 2) / 5;/* 40% SHARDS damage, total shard damage is saved in 'k' */
9368 if (p_ptr->biofeedback) k = (k * 2) / 3;
9369 if (p_ptr->resist_shard) k *= 6; k /= (randint(6) + 6);
9370 dam = cold_dam(Ind, dam, killer, -who);
9371 dam = dam + k;
9372 if (fuzzy) msg_format(Ind, "You are hit by something sharp for \377%c%d \377wdamage!", damcol, dam);
9373 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9374 take_hit(Ind, dam, killer, -who);
9375 if ((!p_ptr->resist_shard) && (!p_ptr->no_cut))
9376 (void)set_cut(Ind, p_ptr->cut + damroll(5, 8), -who);
9377 if (!p_ptr->resist_sound)
9378 (void)set_stun(Ind, p_ptr->stun + randint(15));
9379 break;
9380
9381 /* Thunder -- elec plus sound plus light */
9382 case GF_THUNDER:
9383 k_elec = dam / 3; /* 33% ELEC damage, total elec damage is saved in 'k_elec' */
9384 k_elec = elec_dam(Ind, k_elec, killer, -who);
9385 k_sound = dam / 3; /* 33% SOUND damage, total sound damage is saved in 'k_sound' */
9386 if (p_ptr->biofeedback) k_sound /= 2;
9387 if (p_ptr->resist_sound)
9388 {
9389 k_sound *= 5;
9390 k_sound /= (randint(6) + 6);
9391 }
9392 k_lite = dam / 3; /* 33% LIGHT damage, total light damage is saved in 'k_site' */
9393 if (p_ptr->suscep_lite) {
9394 k_lite *= 2;
9395 }
9396 if (p_ptr->resist_lite) {
9397 k_lite *= 4; k_lite /= (randint(6) + 6);
9398 }
9399 dam = k_elec + k_sound + k_lite;
9400 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9401 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9402 take_hit(Ind, dam, killer, -who);
9403 if (!p_ptr->resist_sound)
9404 (void)set_stun(Ind, p_ptr->stun + randint(15));
9405 if (!p_ptr->resist_lite && !blind && !p_ptr->resist_blind)
9406 (void)set_blind(Ind, p_ptr->blind + randint(5) + 2);
9407 break;
9408
9409 /* Druid's early tox spell: 50% poison, 50% water. No side effects from the water attk */
9410 case GF_WATERPOISON:
9411 switch (randint(2)) {
9412 case 1: { // Poison!
9413 if (p_ptr->immune_poison) {
9414 dam = 0;
9415 //not really needed-- if (who == PROJECTOR_TERRAIN) ; else
9416 if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
9417 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9418 } else {
9419 if (p_ptr->resist_pois) dam = (dam + 2) / 3;
9420 if (p_ptr->oppose_pois) dam = (dam + 2) / 3;
9421 if (p_ptr->suscep_pois) dam = (dam + 2) * 2;
9422 if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
9423 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9424 take_hit(Ind, dam, killer, -who);
9425 if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
9426 {
9427 (void)set_poisoned(Ind, p_ptr->poisoned + rand_int(dam) + 10, -who);
9428 }
9429 }
9430 }
9431 default: { // Water
9432 if (p_ptr->immune_water) {
9433 dam = 0;
9434 //not really needed-- if (who == PROJECTOR_TERRAIN) ; else
9435 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9436 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9437 } else {
9438 if (p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)) {
9439 dam = (dam + 3) / 4;
9440 } else if (p_ptr->resist_water) {
9441 dam = (dam + 2) / 3;
9442 }
9443 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9444 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9445 if (TOOL_EQUIPPED(p_ptr) != SV_TOOL_TARPAULIN && magik(20 + dam / 20) &&
9446 !(p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)))
9447 {
9448 if (!p_ptr->resist_water || magik(50)) {
9449 /* Don't kill inventory in bloodbond... */
9450 int breakable = 1;
9451 if (IS_PVP) {
9452 if (check_blood_bond(Ind, -who)) {
9453 breakable = 0;
9454 }
9455 }
9456 if (breakable) {
9457 inven_damage(Ind, set_water_destroy, 1);
9458 if (magik(50)) equip_damage(Ind, GF_WATER);
9459 }
9460 }
9461 }
9462 }
9463 take_hit(Ind, dam, killer, -who);
9464 }
9465 }
9466 break;
9467
9468 /* Druid's higher tox spell: 60%shards, 10%water, 10%poison. No side effects from water/shards. */
9469 case GF_ICEPOISON:
9470 switch (randint(5)) {
9471 case 1: // Shards
9472 case 3:
9473 case 5: {
9474 if (p_ptr->biofeedback) dam /= 2;
9475 if (p_ptr->resist_shard) {
9476 dam *= 6; dam /= (randint(6) + 6);
9477 }
9478 if (fuzzy) msg_format(Ind, "You are hit by something sharp for \377%c%d \377wdamage!", damcol, dam);
9479 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9480 take_hit(Ind, dam, killer, -who);
9481 break;
9482 }
9483 case 2: { // Water
9484 if (p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)) {
9485 dam = (dam + 3) / 4;
9486 }
9487 if (p_ptr->immune_water) {
9488 dam = 0;
9489 //not really needed-- if (who == PROJECTOR_TERRAIN) ; else
9490 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9491 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9492 } else {
9493 if (p_ptr->resist_water) {
9494 dam = (dam + 2) / 3;
9495 }
9496 if (fuzzy) msg_format(Ind, "You are hit by something for \377%c%d \377wdamage!", damcol, dam);
9497 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9498 if (TOOL_EQUIPPED(p_ptr) != SV_TOOL_TARPAULIN && magik(20 + dam / 20) &&
9499 !(p_ptr->body_monster && (r_ptr->flags7 & RF7_AQUATIC)))
9500 {
9501 if (!p_ptr->resist_water || magik(50)) {
9502 /* Don't kill inventory in bloodbond... */
9503 int breakable = 1;
9504 if (IS_PVP) {
9505 if (check_blood_bond(Ind, -who)) {
9506 breakable = 0;
9507 }
9508 }
9509 if (breakable) {
9510 inven_damage(Ind, set_water_destroy, 1);
9511 if (magik(25)) equip_damage(Ind, GF_WATER);
9512 }
9513 }
9514 }
9515 take_hit(Ind, dam, killer, -who);
9516 }
9517 break;
9518 }
9519 default: { // Poison
9520 if (p_ptr->immune_poison) {
9521 dam = 0;
9522 //not really needed-- if (who == PROJECTOR_TERRAIN) ; else
9523 if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
9524 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9525 } else {
9526 if (p_ptr->resist_pois) dam = (dam + 2) / 3;
9527 if (p_ptr->oppose_pois) dam = (dam + 2) / 3;
9528 if (p_ptr->suscep_pois) dam = (dam + 2) * 2;
9529 if (fuzzy) msg_format(Ind, "You are hit by poison for \377%c%d \377wdamage!", damcol, dam);
9530 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9531 take_hit(Ind, dam, killer, -who);
9532 if (!(p_ptr->resist_pois || p_ptr->oppose_pois)) {
9533 (void)set_poisoned(Ind, p_ptr->poisoned + rand_int(dam) + 10, -who);
9534 }
9535 }
9536 break;
9537 }
9538 }
9539 break;
9540
9541 case GF_CURSE: {
9542 int curse = randint(3);
9543 if (curse == 1) { //Slow
9544 if (fuzzy) msg_print(Ind, "Your body seems difficult to move!");
9545 else msg_format(Ind, "%s curses at you, slowing your movements!", killer);
9546 if (p_ptr->pspeed <= 100) {
9547 /* unaffected */
9548 } else if (p_ptr->mindboost && magik(p_ptr->mindboost_power)) {
9549 /* resist the effect */
9550 } else if (!p_ptr->free_act) {
9551 (void)set_slow(Ind, p_ptr->slow + rand_int(3) + 4);
9552 } else {
9553 (void)set_slow(Ind, p_ptr->slow + rand_int(3) + 2);
9554 }
9555 dam = 0;
9556 } else if (curse == 2) { //Conf
9557 dam = damroll(3, (dam / 2)) + 1;
9558 if (p_ptr->resist_conf || p_ptr->resist_chaos){
9559 if (fuzzy) msg_format(Ind, "Your mind is hit by confusion for \377%c%d \377wdamage!", damcol, dam);
9560 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9561 dam *= 5; dam /= (randint(6) + 6);
9562 }else{
9563 if (fuzzy) msg_format(Ind, "Your mind is hit by confusion for \377%c%d \377wdamage!", damcol, dam);
9564 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
9565 if (!(p_ptr->mindboost && magik(p_ptr->mindboost_power)))
9566 (void)set_confused(Ind, p_ptr->confused + randint(5) + 5);
9567 }
9568 take_hit(Ind, dam, killer, -who);
9569 } else { //Blind
9570 if (fuzzy) msg_print(Ind, "Your eyes suddenly burn!");
9571 else msg_format(Ind, "%s casts a spell, burning your eyes!", killer);
9572 if (!blind && !p_ptr->resist_blind) (void)set_blind(Ind, p_ptr->blind + randint(5) + 2);
9573 dam = 0;
9574 }
9575 break;
9576 }
9577
9578 /* Teleport other -- Teleports */
9579 case GF_AWAY_ALL:
9580 {
9581 if (p_ptr->martyr) break;
9582
9583 if (IS_PVP) {
9584 /* protect players in inns */
9585 cave_type **zcave;
9586 cave_type *c_ptr;
9587 if ((zcave = getcave(wpos))) {
9588 c_ptr = &zcave[p_ptr->py][p_ptr->px];
9589 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) break;
9590 }
9591
9592 /* protect AFK players */
9593 if (p_ptr->afk) break;
9594
9595 /* Log PvP teleports - mikaelh */
9596 s_printf("%s teleported (GF_AWAY_ALL) %s at (%d,%d,%d).\n", Players[0 - who]->name, p_ptr->name,
9597 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
9598
9599 /* Tell the one who caused it */
9600 msg_format(0 - who, "You teleport %s away.", Players[0 - who]->play_vis[Ind] ? p_ptr->name : "It");
9601 }
9602
9603 if (fuzzy) msg_print(Ind, "Someone teleports you away!");
9604 else msg_format(Ind, "%^s teleports you away!", killer);
9605 teleport_player(Ind, 200, TRUE);
9606 break;
9607 }
9608
9609 case GF_WRAITH_PLAYER:
9610 {
9611 if (fuzzy) msg_print(Ind, "You feel less constant!");
9612 else msg_format(Ind, "%^s turns you into a wraith!", killer);
9613 set_tim_wraith(Ind, dam);
9614 break;
9615 }
9616
9617 case GF_BLESS_PLAYER:
9618 {
9619 if (dam < 18) p_ptr->blessed_power = 8;
9620 else if (dam < 33) p_ptr->blessed_power = 14;
9621 else p_ptr->blessed_power = 20;
9622 (void)set_blessed(Ind, dam);
9623 break;
9624 }
9625
9626 /* a special family, actually cumulative.. hacky, yeah */
9627 case GF_REMFEAR_PLAYER: /* just fear */
9628 set_afraid(Ind, 0);
9629 /* Stay bold for some turns */
9630 (void)set_res_fear(Ind, dam);
9631 break;
9632 case GF_REMCONF_PLAYER: /* confusion, and ALSO fear */
9633 set_afraid(Ind, 0);
9634 /* Stay bold for some turns */
9635 (void)set_res_fear(Ind, dam);
9636
9637 set_confused(Ind, 0);
9638 break;
9639 case GF_REMIMAGE_PLAYER: /* hallu, and ALSO conf/fear */
9640 set_afraid(Ind, 0);
9641 /* Stay bold for some turns */
9642 (void)set_res_fear(Ind, dam);
9643
9644 set_confused(Ind, 0);
9645
9646 set_image(Ind, 0);
9647 break;
9648
9649 case GF_REMCURSE_PLAYER: /* only remove one curse */
9650 #ifdef NEW_REMOVE_CURSE
9651 if (dam) remove_curse_aux(Ind, 0x1 + 0x2, -who);
9652 else remove_curse_aux(Ind, 0x2, -who);
9653 #endif
9654 break;
9655
9656 case GF_HPINCREASE_PLAYER:
9657 {
9658 (void)hp_player(Ind, dam);
9659 break;
9660 }
9661
9662 case GF_HERO_PLAYER:
9663 {
9664 (void)set_hero(Ind, dam); /* removed stacking */
9665 break;
9666 }
9667
9668 case GF_SHERO_PLAYER:
9669 {
9670 (void)set_shero(Ind, dam); /* removed stacking */
9671 break;
9672 }
9673
9674 case GF_SATHUNGER_PLAYER:
9675 {
9676 if (!p_ptr->suscep_life) {
9677 if (p_ptr->male)
9678 msg_format_near(Ind, "\377y%s looks like he is going to explode.", p_ptr->name);
9679 else
9680 msg_format_near(Ind, "\377y%s looks like she is going to explode.", p_ptr->name);
9681 (void)set_food(Ind, PY_FOOD_MAX - 1);
9682 }
9683 break;
9684 }
9685
9686 case GF_RESFIRE_PLAYER:
9687 {
9688 (void)set_oppose_fire(Ind, dam); /* removed stacking */
9689 break;
9690 }
9691
9692 case GF_RESELEC_PLAYER:
9693 {
9694 (void)set_oppose_elec(Ind, dam); /* removed stacking */
9695 break;
9696 }
9697
9698 case GF_RESPOIS_PLAYER:
9699 {
9700 (void)set_oppose_pois(Ind, dam); /* removed stacking */
9701 break;
9702 }
9703
9704 case GF_RESACID_PLAYER:
9705 {
9706 (void)set_oppose_acid(Ind, dam); /* removed stacking */
9707 break;
9708 }
9709
9710 case GF_RESCOLD_PLAYER:
9711 {
9712 (void)set_oppose_cold(Ind, dam); /* removed stacking */
9713 break;
9714 }
9715
9716 case GF_CUREPOISON_PLAYER:
9717 {
9718 (void)set_poisoned(Ind, 0, 0);
9719 break;
9720 }
9721
9722 case GF_SLOWPOISON_PLAYER:
9723 if (p_ptr->poisoned && !p_ptr->slow_poison) p_ptr->slow_poison = 1;
9724 break;
9725
9726 case GF_SEEINVIS_PLAYER:
9727 {
9728 (void)set_tim_invis(Ind, dam); /* removed stacking */
9729 break;
9730 }
9731
9732 case GF_ZEAL_PLAYER:
9733 {
9734 (void)set_zeal(Ind, dam, 9 + randint(5));
9735 break;
9736 }
9737 case GF_SEEMAP_PLAYER:
9738 {
9739 map_area(Ind);
9740 break;
9741 }
9742 case GF_DETECTCREATURE_PLAYER:
9743 {
9744 (void)detect_creatures(Ind);
9745 break;
9746 }
9747
9748 case GF_CURESTUN_PLAYER:
9749 {
9750 (void)set_stun(Ind, p_ptr->stun - dam);
9751 break;
9752 }
9753
9754 case GF_DETECTDOOR_PLAYER:
9755 {
9756 (void)detect_sdoor(Ind, DEFAULT_RADIUS);
9757 break;
9758 }
9759
9760 case GF_DETECTTRAP_PLAYER:
9761 {
9762 (void)detect_trap(Ind, DEFAULT_RADIUS);
9763 break;
9764 }
9765
9766 case GF_CURECUT_PLAYER:
9767 {
9768 (void)set_cut(Ind, p_ptr->cut - dam, -who);
9769 break;
9770 }
9771
9772 case GF_TELEPORTLVL_PLAYER:
9773 {
9774 if (p_ptr->martyr) break;
9775 teleport_player_level(Ind, FALSE);
9776 break;
9777 }
9778
9779 case GF_HEAL_PLAYER:
9780 {
9781 /* hacks */
9782 if (hack_dam & 0x2000) /* CCW */
9783 (void)set_stun(Ind, 0);
9784 if (hack_dam & 0x1000) /* CSW */
9785 (void)set_confused(Ind, 0);
9786 if (hack_dam & 0x800) { /* CLW */
9787 (void)set_blind(Ind, 0);
9788 (void)set_cut(Ind, 0, 0);
9789 }
9790 if (hack_dam & 0x400) { /* holy curing PBAoE */
9791 if (Ind != -who) dam = (dam * 3) / 2; /* heals allies for 3/4 of the self-heal amount */
9792 }
9793
9794 #if 0 /* causes a prob with 'Cure Wounds' spell - targetting cannot determine if to skip vampires or not -_- */
9795 if (p_ptr->ghost || (r_ptr->flags3 & RF3_UNDEAD) || p_ptr->suscep_life) {
9796 if (rand_int(100) < p_ptr->skill_sav)
9797 msg_print(Ind, "You shudder, but you resist the effect!");
9798 else {
9799 /* Message */
9800 msg_print(Ind, "You somehow feel.. cleaned!");
9801 dam /= 3; /* full dam is too harsh */
9802
9803 /* Don't let the player get killed by it - mikaelh */
9804 if (p_ptr->chp <= dam) dam = p_ptr->chp - 1;
9805 take_hit(Ind, dam, killer, -who);
9806 }
9807 } else
9808 #endif
9809 {
9810 //(spammy) msg_format_near(Ind, "\377g%s has been healed for %d hit points!.", p_ptr->name, dam);
9811 if (IS_PLAYER(-who) /* paranoia? */
9812 && -who != Ind) { /* don't notify ourselves about healing ourselves */
9813 msg_format(-who, "\377w%s has been healed for \377g%d\377w hit points.", p_ptr->name, dam);
9814 msg_format(Ind, "\377g%s heals you for %d hit points", Players[-who]->name, dam);
9815 } else msg_format(Ind, "\377gYou are healed for %d hit points", dam);
9816
9817 hp_player_quiet(Ind, dam, FALSE);
9818 dam = 0;
9819 }
9820 break;
9821 }
9822
9823 /* The druid spell; Note that it _damages_ undead-players instead of healing :-) - the_sandman */
9824 case GF_HEALINGCLOUD:
9825 {
9826 if (p_ptr->ghost || (r_ptr->flags3 & RF3_UNDEAD) || p_ptr->suscep_life) {
9827 if (rand_int(100) < p_ptr->skill_sav)
9828 msg_print(Ind, "You shudder, but you resist the effect!");
9829 else {
9830 /* Message */
9831 msg_print(Ind, "You somehow feel.. cleaned!");
9832 dam /= 3; /* full dam is too harsh */
9833
9834 /* Don't let the player get killed by it - mikaelh */
9835 if (p_ptr->chp <= dam) dam = p_ptr->chp - 1;
9836 take_hit(Ind, dam, killer, -who);
9837 }
9838 } else {
9839 /* Healed */
9840 msg_format(Ind, "\377gYou are healed for %d points.", dam);
9841 //(spammy) msg_format_near(Ind, "\377g%s has been healed for %d hit points.", p_ptr->name, dam);
9842
9843 hp_player_quiet(Ind, dam, FALSE);
9844 dam = 0;
9845 }
9846 break;
9847 }
9848
9849 case GF_SPEED_PLAYER:
9850 {
9851 if (dam > 10) dam = 10; /* cap speed bonus for others */
9852 if (dam > p_ptr->lev / 3) dam = p_ptr->lev / 3; /* works less well for low level targets */
9853 if (dam < 1) dam = 1;
9854
9855 if (fuzzy) msg_print(Ind, "You feel faster!");
9856 else msg_format(Ind, "%^s speeds you up!", killer);
9857 (void)set_fast(Ind, 10 + (dam * 5), dam); /* removed stacking */
9858 break;
9859 }
9860
9861 case GF_EXTRA_STATS:
9862 {
9863 do_xtra_stats(Ind, 10 + (dam * 5), (int)(dam/10));
9864 break;
9865 }
9866
9867 case GF_EXTRA_SPR:
9868 {
9869 dam = dam - 30;
9870 if (dam < 0) break;
9871 do_focus_shot(Ind, 200 + dam * 5, (dam/6));
9872 break;
9873 }
9874
9875 case GF_SHIELD_PLAYER:
9876 {
9877 if (dam > 10) dam = 10; /* cap AC bonus for others - Kurzel */
9878 if (fuzzy) msg_print(Ind, "You feel protected!");
9879 else msg_format(Ind, "%^s shields you!", killer);
9880
9881 (void)set_shield(Ind, 10 + (dam * 5), dam, SHIELD_NONE, 0, 0); /* removed stacking */
9882 break;
9883 }
9884
9885 case GF_TELEPORT_PLAYER:
9886 {
9887 if (p_ptr->martyr) break;
9888
9889 if (IS_PVP) {
9890 /* protect players in inns */
9891 cave_type **zcave;
9892 cave_type *c_ptr;
9893 if ((zcave = getcave(wpos))) {
9894 c_ptr = &zcave[p_ptr->py][p_ptr->px];
9895 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) break;
9896 }
9897
9898 /* protect AFK players */
9899 if (p_ptr->afk) break;
9900
9901 /* Log PvP teleports - mikaelh */
9902 s_printf("%s teleported (GF_TELEPORT_PLAYER) %s at (%d,%d,%d).\n", Players[0 - who]->name, p_ptr->name,
9903 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
9904
9905 /* Tell the one who caused it */
9906 msg_format(0 - who, "You teleport %s away.", Players[0 - who]->play_vis[Ind] ? p_ptr->name : "It");
9907 }
9908
9909 if (fuzzy) msg_print(Ind, "Someone teleports you away!");
9910 else msg_format(Ind, "%^s teleports you away!", killer);
9911
9912 teleport_player(Ind, dam, TRUE);
9913 break;
9914 }
9915
9916 case GF_RECALL_PLAYER:
9917 dam = 0;
9918 if (p_ptr->afk) break;
9919
9920 /* prevent silly things */
9921 if (in_irondeepdive(&p_ptr->wpos) && !irondeepdive_bottom(&p_ptr->wpos)) {
9922 msg_print(Ind, "\377oThere is some static discharge in the air around you, but nothing happens.");
9923 break;
9924 }
9925
9926 if (!p_ptr->word_recall) {
9927 #ifdef SEPARATE_RECALL_DEPTHS
9928 p_ptr->recall_pos.wz = get_recall_depth(&p_ptr->wpos, p_ptr);
9929 #else
9930 p_ptr->recall_pos.wz = p_ptr->max_dlv;
9931 #endif
9932 p_ptr->word_recall = dam;
9933 if (fuzzy) msg_print(Ind, "\377oThe air around you suddenly becomes charged!");
9934 else msg_format(Ind, "\377o%^s charges the air around you!", killer);
9935 } else {
9936 p_ptr->word_recall = 0;
9937 if (fuzzy) msg_print(Ind, "\377oA tension leaves the air around you!");
9938 else msg_format(Ind, "\377o%^s dispels the tension from the air around you!", killer);
9939 }
9940 p_ptr->redraw |= (PR_DEPTH);
9941 break;
9942
9943 case GF_RESTORE_PLAYER:
9944 if (dam & 0x1) { /* Restore food */
9945 set_food(Ind, PY_FOOD_MAX - 1);
9946 }
9947 if (dam & 0x2) { /* Restore exp */
9948 (void)restore_level(Ind);
9949 }
9950 if (dam & 0x4) { /* Restore stats */
9951 (void)do_res_stat(Ind, A_STR);
9952 (void)do_res_stat(Ind, A_CON);
9953 (void)do_res_stat(Ind, A_DEX);
9954 (void)do_res_stat(Ind, A_WIS);
9955 (void)do_res_stat(Ind, A_INT);
9956 (void)do_res_stat(Ind, A_CHR);
9957 }
9958 if (dam & 0x8) { /* Black breath (herbal tea) */
9959 if (p_ptr->black_breath) {
9960 msg_print(Ind, "The hold of the Black Breath on you is broken!");
9961 p_ptr->black_breath = FALSE;
9962 }
9963 }
9964 break;
9965 case GF_CURING:
9966 case GF_CURE_PLAYER:
9967 if (dam & 0x1) { /* Slow Poison */
9968 if (p_ptr->poisoned && !p_ptr->slow_poison) p_ptr->slow_poison = 1;
9969 }
9970 if (dam & 0x2) { /* Ungorge */
9971 if (p_ptr->food >= PY_FOOD_MAX) set_food(Ind, PY_FOOD_MAX - 1);
9972 }
9973 if (dam & 0x4) { /* Neutralise Poison */
9974 (void)set_poisoned(Ind, 0, 0);
9975 }
9976 if (dam & 0x8) { /* Close cuts */
9977 (void)set_cut(Ind, 0, 0);
9978 }
9979 if (dam & 0x10) { /* Remove conf/blind/stun */
9980 (void)set_confused(Ind, 0);
9981 (void)set_blind(Ind, 0);
9982 (void)set_stun(Ind, 0);
9983 }
9984 if (dam & 0x20) { /* Remove hallu */
9985 set_image(Ind, 0);
9986 }
9987 if (dam & 0x40) { /* Restore stats */
9988 (void)do_res_stat(Ind, A_STR);
9989 (void)do_res_stat(Ind, A_CON);
9990 (void)do_res_stat(Ind, A_DEX);
9991 (void)do_res_stat(Ind, A_WIS);
9992 (void)do_res_stat(Ind, A_INT);
9993 (void)do_res_stat(Ind, A_CHR);
9994 }
9995 if (dam & 0x80) { /* Restore exp */
9996 (void)restore_level(Ind);
9997 }
9998 break;
9999 case GF_RESURRECT_PLAYER:
10000 //if (p_ptr->ghost)
10001 resurrect_player(Ind, dam);
10002 break;
10003 case GF_SANITY_PLAYER:
10004 msg_format(Ind, "%s waves over your eyes, murmuring some words..", killer);
10005 set_afraid(Ind, 0);
10006 /* Stay bold for some turns */
10007 (void)set_res_fear(Ind, dam);
10008 (void)set_confused(Ind, 0);
10009 (void)set_image(Ind, 0);
10010
10011 if (dam > 0) {
10012 #if 1
10013 /* Testing new version that increases sanity - mikaelh */
10014 p_ptr->csane += dam;
10015 if (p_ptr->csane > p_ptr->msane) p_ptr->csane = p_ptr->msane;
10016 p_ptr->update |= PU_SANITY;
10017 p_ptr->redraw |= PR_SANITY;
10018 p_ptr->window |= (PW_PLAYER);
10019 #else
10020 if (p_ptr->csane < p_ptr->msane * dam / 12) {
10021 p_ptr->csane = p_ptr->msane * dam / 12;
10022 /* the_sandman mika's addition, really */
10023 if (p_ptr->csane>p_ptr->msane) p_ptr->csane = p_ptr->msane;
10024 p_ptr->update |= PU_SANITY;
10025 p_ptr->redraw |= PR_SANITY;
10026 p_ptr->window |= (PW_PLAYER);
10027 }
10028 #endif
10029 /* Give feedback to the healer so he knows when he may stop - C. Blue */
10030 if (p_ptr->csane == p_ptr->msane) msg_format_near(Ind, "%s appears to be in full command of %s mental faculties.", p_ptr->name, p_ptr->male ? "his" : "her");
10031 }
10032 break;
10033 case GF_SOULCURE_PLAYER:
10034 /* priest variant hurts undead, druid tea is fine */
10035 if (p_ptr->suscep_life) {
10036 msg_print(Ind, "You feel a calming warmth touching your soul.");
10037 take_hit(Ind, (p_ptr->chp / 3) * 2, killer, -who);
10038 }
10039 if (p_ptr->black_breath) {
10040 msg_print(Ind, "The hold of the Black Breath on you is broken!");
10041 p_ptr->black_breath = FALSE;
10042 }
10043 break;
10044 case GF_MINDBOOST_PLAYER:
10045 {
10046 if (dam > 95) dam = 95;
10047 set_mindboost(Ind, dam, 15 + randint(6));
10048 break;
10049 }
10050
10051 case GF_OLD_CONF:
10052
10053 if (fuzzy || self) msg_print(Ind, "You hear puzzling noises!");
10054 else msg_format(Ind, "%^s creates a mesmerising illusion!", killer);
10055
10056 if (p_ptr->resist_conf ||
10057 (p_ptr->mindboost && magik(p_ptr->mindboost_power)))
10058 {
10059 msg_print(Ind, "You disbelieve the feeble spell.");
10060 }
10061 else if (rand_int(100 + dam*6) < p_ptr->skill_sav)
10062 {
10063 msg_print(Ind, "You disbelieve the feeble spell.");
10064 }
10065 //else set_confused(Ind, p_ptr->confused + dam); too much for pvp
10066 else set_confused(Ind, p_ptr->confused + 2 + rand_int(3));
10067
10068 dam = 0;
10069 break;
10070
10071 case GF_OLD_SLOW:
10072
10073 if (fuzzy || self) msg_print(Ind, "Something drains power from your muscles!");
10074 else msg_format(Ind, "%^s drains power from your muscles!", killer);
10075
10076 if (p_ptr->free_act)
10077 {
10078 msg_print(Ind, "You are unaffected!");
10079 }
10080 else if (rand_int(100 + dam*6) < p_ptr->skill_sav ||
10081 (p_ptr->mindboost && magik(p_ptr->mindboost_power)))
10082 {
10083 msg_print(Ind, "You resist the effects!");
10084 }
10085 //else set_slow(Ind, p_ptr->slow + dam); too much for pvp..
10086 else set_slow(Ind, p_ptr->slow + 2 + rand_int(3));
10087
10088 dam = 0;
10089 break;
10090
10091 case GF_TURN_ALL:
10092
10093 if (fuzzy || self) msg_print(Ind, "Something mumbles, and you hear scary noises!");
10094 else msg_format(Ind, "%^s casts a fearful illusion!", killer);
10095
10096 if (p_ptr->resist_fear)
10097 {
10098 msg_print(Ind, "You refuse to be frightened.");
10099 }
10100 else if (rand_int(100 + dam*6) < p_ptr->skill_sav)
10101 {
10102 msg_print(Ind, "You refuse to be frightened.");
10103 }
10104 else
10105 {
10106 //(void)set_afraid(Ind, p_ptr->afraid + dam); too much for pvp
10107 (void)set_afraid(Ind, p_ptr->afraid + 2 + rand_int(3));
10108 }
10109
10110 dam = 0;
10111 break;
10112
10113 case GF_OLD_POLY:
10114 s_printf("PLAYER_POLY: %s -> %s ", Players[0 - who]->name, p_ptr->name);
10115 if (p_ptr->afk) break;
10116 if (fuzzy || self) msg_print(Ind, "You feel bizzare!");
10117 else msg_format(Ind, "%^s polymorphs you!", killer);
10118 if (p_ptr->resist_nexus) {
10119 s_printf("resists\n");
10120 msg_print(Ind, "You resist the effects!");
10121 } else {
10122 s_printf("morphs\n");
10123 msg_print(Ind, "The magic continuum twists around you!");
10124 apply_morph(Ind, dam, killer, -who);
10125 }
10126 break;
10127
10128 /* PernA ones */
10129 /* Rocket -- stun, cut, fire, raw impact */
10130 case GF_INFERNO:
10131 case GF_DETONATION:
10132 case GF_ROCKET:
10133 {
10134 bool ignore_heat = (p_ptr->resist_fire && p_ptr->oppose_fire) || p_ptr->immune_fire;
10135 if (p_ptr->resist_shard)
10136 dam = (dam * 5) / 6;
10137 if (p_ptr->resist_sound)
10138 dam = (dam * 5) / 6;
10139 if (p_ptr->immune_fire)
10140 dam = (dam * 3) / 4;
10141 else if (p_ptr->resist_fire || p_ptr->oppose_fire)
10142 dam = (dam * 4) / 5;
10143
10144 if (fuzzy) msg_format(Ind, "There is an explosion around you of \377%c%d \377wdamage!", damcol, dam);
10145 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
10146
10147 if (!p_ptr->resist_shard && !p_ptr->no_cut)
10148 (void)set_cut(Ind, p_ptr->cut + ( dam / 2), -who );
10149 if (!p_ptr->resist_sound)
10150 (void)set_stun(Ind, p_ptr->stun + randint(20));
10151
10152 if (!p_ptr->resist_shard || !p_ptr->resist_sound || !ignore_heat) {
10153 /* Don't kill inventory in bloodbond... */
10154 int breakable = 1;
10155 if (IS_PVP) {
10156 if (check_blood_bond(Ind, -who)) {
10157 breakable = 0;
10158 }
10159 }
10160 if (breakable) {
10161 if (p_ptr->resist_shard && p_ptr->resist_sound) inven_damage(Ind, set_fire_destroy, 3);
10162 else if (ignore_heat) inven_damage(Ind, set_impact_destroy, 3);
10163 else inven_damage(Ind, set_rocket_destroy, 4);
10164 }
10165 }
10166
10167 take_hit(Ind, dam, killer, -who);
10168 break;
10169 }
10170
10171 /* Standard damage -- also poisons / mutates player */
10172 case GF_NUKE:
10173 {
10174 if (p_ptr->immune_poison) {
10175 dam = 0;
10176 if (who == PROJECTOR_TERRAIN) ; else /* RL-Doom? ;) */
10177 if (fuzzy) msg_format(Ind, "You are hit by radiation for \377%c%d \377wdamage!", damcol, dam);
10178 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
10179 } else {
10180 if (p_ptr->resist_pois) dam = (2 * dam + 2) / 5;
10181 if (p_ptr->oppose_pois) dam = (2 * dam + 2) / 5;
10182 if (p_ptr->suscep_pois) dam = (5 * dam + 2) / 3;
10183 if (fuzzy) msg_format(Ind, "You are hit by radiation for \377%c%d \377wdamage!", damcol, dam);
10184 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
10185 take_hit(Ind, dam, killer, -who);
10186 if (!(p_ptr->resist_pois || p_ptr->oppose_pois))
10187 {
10188 set_poisoned(Ind, p_ptr->poisoned + rand_int(dam) + 10, -who);
10189
10190 #if 0 // dang, later..
10191 if (randint(5) == 1) { /* 6 */
10192 msg_print("You undergo a freakish metamorphosis!");
10193 if (randint(4)==1) /* 4 */
10194 do_poly_self();
10195 else
10196 corrupt_player();
10197 }
10198 #endif // 0
10199
10200 if (randint(6) == 1) {
10201 /* Don't kill inventory in bloodbond... */
10202 int breakable = 1;
10203 if (IS_PVP) {
10204 if (check_blood_bond(Ind, -who))
10205 breakable = 0;
10206 }
10207 if (breakable) inven_damage(Ind, set_acid_destroy, 2);
10208 }
10209 }
10210 }
10211 break;
10212 }
10213
10214 /* Standard damage */
10215 case GF_DISINTEGRATE:
10216 {
10217 if (p_ptr->body_monster && (r_ptr->flags3 & RF3_HURT_ROCK)) dam = (dam * 3) / 2;
10218 if (fuzzy) msg_format(Ind, "You are hit by pure energy for \377%c%d \377wdamage!", damcol, dam);
10219 else msg_format(Ind, "%s \377%c%d \377wdamage!", attacker, damcol, dam);
10220 take_hit(Ind, dam, killer, -who);
10221 break;
10222 }
10223
10224 /* GF_BLIND - C. Blue */
10225 case GF_BLIND:
10226 {
10227 if (p_ptr->resist_blind)
10228 {
10229 msg_print(Ind, "You are unaffected!");
10230 }
10231 else if (rand_int(100 + dam*6) < p_ptr->skill_sav)
10232 {
10233 msg_print(Ind, "You resist the effects!");
10234 }
10235 else if (!p_ptr->blind)
10236 {
10237 (void)set_blind(Ind, dam);
10238 }
10239 break;
10240 }
10241
10242 /* For shattering potions, but maybe work for wands too? */
10243 case GF_OLD_HEAL:
10244 {
10245 if (fuzzy) msg_print(Ind, "You are hit by something invigorating!");
10246 (void)hp_player(Ind, dam);
10247 dam = 0;
10248 break;
10249 }
10250
10251 case GF_OLD_SPEED:
10252 {
10253 if (fuzzy) msg_print(Ind, "You are hit by something!");
10254 (void)set_fast(Ind, p_ptr->fast + randint(5), 10); /* not removed stacking */
10255 dam = 0;
10256 break;
10257 }
10258
10259 case GF_TELE_TO:
10260 {
10261 // bool resists_tele = FALSE;
10262 // dun_level *l_ptr = getfloor(wpos);
10263 int chance = (195 - p_ptr->skill_sav) / 2;
10264 if (p_ptr->res_tele) chance = 50;
10265
10266 if (p_ptr->martyr) break;
10267
10268 if (IS_PVP) {
10269 /* protect players in inns */
10270 cave_type **zcave;
10271 cave_type *c_ptr;
10272 if ((zcave = getcave(wpos))) {
10273 c_ptr = &zcave[p_ptr->py][p_ptr->px];
10274 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) break;
10275 }
10276
10277 /* protect AFK players */
10278 if (p_ptr->afk) break;
10279
10280 /* Log PvP teleports - mikaelh */
10281 s_printf("%s teleported (GF_TELE_TO) %s at (%d,%d,%d).\n", Players[0 - who]->name, p_ptr->name,
10282 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
10283
10284 /* Tell the one who caused it */
10285 msg_format(0 - who, "You command %s to return.", Players[0 - who]->play_vis[Ind] ? p_ptr->name : "It");
10286 }
10287
10288 /* Teleport to nowhere..? */
10289 if (who >= 0 || who <= PROJECTOR_UNUSUAL) break;
10290
10291 if (p_ptr->anti_tele)
10292 {
10293 msg_print(Ind, "You are unaffected!");
10294 }
10295 else if (magik(chance))
10296 {
10297 msg_print(Ind, "You resist the effect!");
10298 }
10299 else
10300 {
10301 player_type *q_ptr = Players[0 - who];
10302
10303 msg_format(Ind, "%^s commands you to return.", q_ptr->name);
10304
10305 /* Prepare to teleport */
10306 teleport_player_to(Ind, q_ptr->py, q_ptr->px);
10307
10308 }
10309
10310 /* No "real" damage */
10311 dam = 0;
10312 break;
10313 }
10314
10315 /* Hand of Doom */
10316 case GF_HAND_DOOM:
10317 {
10318 /* Teleport to nowhere..? */
10319 if (who >= 0 || who <= PROJECTOR_UNUSUAL) break;
10320
10321 msg_format(Ind, "%^s invokes the Hand of Doom!",
10322 Players[0 - who]->name);
10323
10324 if (rand_int(100) < p_ptr->skill_sav)
10325 {
10326 msg_print(Ind, "You resist the effects!");
10327 }
10328 else
10329 {
10330 int dummy = (((s32b) ((65 + randint(25)) * (p_ptr->chp))) / 100);
10331 if (p_ptr->chp - dummy < 1) dummy = p_ptr->chp - 1;
10332 msg_print(Ind, "You feel your life fade away!");
10333 bypass_invuln = TRUE;
10334 take_hit(Ind, dummy, Players[0-who]->name, -who);
10335 bypass_invuln = FALSE;
10336 curse_equipment(Ind, 100, 20);
10337 }
10338 break;
10339 }
10340
10341 case GF_AWAY_UNDEAD:
10342 {
10343 if (p_ptr->martyr) break;
10344
10345 if (IS_PVP) {
10346 /* protect players in inns */
10347 cave_type **zcave;
10348 cave_type *c_ptr;
10349 if ((zcave = getcave(wpos))) {
10350 c_ptr = &zcave[p_ptr->py][p_ptr->px];
10351 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) break;
10352 }
10353
10354 /* protect AFK players */
10355 if (p_ptr->afk) break;
10356
10357 /* Log PvP teleports - mikaelh */
10358 s_printf("%s teleported (GF_AWAY_UNDEAD) %s at (%d,%d,%d).\n", Players[0 - who]->name, p_ptr->name,
10359 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
10360 }
10361
10362 if (p_ptr->ghost || p_ptr->suscep_life) {
10363
10364 /* Only affect undead */
10365 if (p_ptr->res_tele)
10366 {
10367 msg_print(Ind, "You are unaffected!");
10368 }
10369 // else if (p_ptr->lev+50 < randint(150))
10370 else if (rand_int(100) < p_ptr->skill_sav)
10371 {
10372 teleport_player(Ind, dam, TRUE);
10373 }
10374 else
10375 {
10376 msg_print(Ind, "You resist the effect!");
10377 }
10378
10379 }
10380
10381 /* No "real" damage */
10382 dam = 0;
10383 break;
10384 }
10385
10386 /* Teleport evil (Use "dam" as "power") */
10387 case GF_AWAY_EVIL:
10388 {
10389 if (p_ptr->martyr) break;
10390
10391 if (IS_PVP) {
10392 /* protect players in inns */
10393 cave_type **zcave;
10394 cave_type *c_ptr;
10395 if ((zcave = getcave(wpos))) {
10396 c_ptr = &zcave[p_ptr->py][p_ptr->px];
10397 if (f_info[c_ptr->feat].flags1 & FF1_PROTECTED) break;
10398 }
10399
10400 /* protect AFK players */
10401 if (p_ptr->afk) break;
10402
10403 /* Log PvP teleports - mikaelh */
10404 s_printf("%s teleported (GF_AWAY_EVIL) %s at (%d,%d,%d).\n", Players[0 - who]->name, p_ptr->name,
10405 p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
10406 }
10407
10408 if (p_ptr->suscep_good) {
10409 /* Only affect evil */
10410 if (p_ptr->res_tele)
10411 msg_print(Ind, "You are unaffected!");
10412 // else if (p_ptr->lev+50 < randint(150))
10413 else if (rand_int(100) < p_ptr->skill_sav)
10414 teleport_player(Ind, dam, TRUE);
10415 else
10416 msg_print(Ind, "You resist the effect!");
10417 }
10418 /* No "real" damage */
10419 dam = 0;
10420 break;
10421 }
10422 #if 0 //already defined above for affecting ALL players!
10423 /* Teleport monster (Use "dam" as "power") */
10424 case GF_AWAY_ALL:
10425 {
10426 if (p_ptr->martyr) break;
10427
10428 if (p_ptr->body_monster) {
10429 bool resists_tele = FALSE;
10430 dun_level *l_ptr = getfloor(wpos);
10431
10432 if (p_ptr->res_tele)
10433 msg_print(Ind, "You are unaffected!");
10434 // else if (p_ptr->lev+50 < randint(150))
10435 else if (rand_int(100) < p_ptr->skill_sav)
10436 teleport_player(Ind, dam, TRUE);
10437 else
10438 msg_print(Ind, "You resist the effect!");
10439 }
10440
10441 /* No "real" damage */
10442 dam = 0;
10443 break;
10444 }
10445 #endif
10446
10447 /* Turn undead (Use "dam" as "power") */
10448 case GF_TURN_UNDEAD:
10449 {
10450 if (p_ptr->body_monster){
10451
10452 /* Only affect undead */
10453 if (p_ptr->ghost || (r_ptr->flags3 & RF3_UNDEAD))
10454 {
10455 if (p_ptr->resist_fear && !p_ptr->ghost)
10456 {
10457 msg_print(Ind, "You are unaffected!");
10458 }
10459 /* Attempt a saving throw */
10460 //else if (RES_OLD(p_ptr->lev, dam))
10461 else if (rand_int(100) < p_ptr->skill_sav)
10462 {
10463 msg_print(Ind, "You resist the effect!");
10464 } else {
10465 (void)set_afraid(Ind, p_ptr->afraid + damroll(3, (dam / 2)) + 1);
10466 }
10467 }
10468
10469 }
10470 /* No "real" damage */
10471 dam = 0;
10472 break;
10473 }
10474
10475
10476 /* Turn evil (Use "dam" as "power") */
10477 case GF_TURN_EVIL:
10478 {
10479 /* Only affect evil */
10480 if (p_ptr->suscep_good) {
10481 if (p_ptr->resist_fear)
10482 msg_print(Ind, "You are unaffected!");
10483 else if (rand_int(100) < p_ptr->skill_sav)
10484 // else if (RES_OLD(p_ptr->lev, dam))
10485 {
10486 msg_print(Ind, "You resist the effect!");
10487 } else {
10488 (void)set_afraid(Ind, p_ptr->afraid + damroll(3, (dam / 2)) + 1);
10489 }
10490 }
10491 /* No "real" damage */
10492 dam = 0;
10493 break;
10494 }
10495
10496 #if 0 //already defined above for affecting ALL players!
10497 /* Turn monster (Use "dam" as "power") */
10498 case GF_TURN_ALL:
10499 {
10500 if (p_ptr->body_monster){
10501
10502 /* Attempt a saving throw */
10503 if ((p_ptr->resist_fear) ||
10504 {
10505 /* No obvious effect */
10506 msg_print(Ind, "You are unaffected!");
10507 }
10508 else if (rand_int(100) < p_ptr->skill_sav)
10509 // else if (RES_OLD(p_ptr->lev, dam))
10510 {
10511 msg_print(Ind, "You resist the effect!");
10512 }
10513 else
10514 {
10515 (void)set_afraid(Ind, p_ptr->afraid + damroll(3, (dam / 2)) + 1);
10516 }
10517 }
10518 /* No "real" damage */
10519 dam = 0;
10520 break;
10521 }
10522 #endif
10523
10524 /* Dispel undead */
10525 case GF_DISP_UNDEAD:
10526 {
10527 if (p_ptr->body_monster){
10528 /* Only affect undead */
10529
10530 if (p_ptr->ghost || (r_ptr->flags3 & RF3_UNDEAD))
10531 {
10532 if (rand_int(100) < p_ptr->skill_sav)
10533 {
10534 msg_print(Ind, "You shudder, but you resist the effect!");
10535 }
10536 else
10537 {
10538 /* Message */
10539 msg_print(Ind, "You shudder!");
10540 dam /= 3; /* full dam is too harsh */
10541 take_hit(Ind, dam, killer, -who);
10542 }
10543 }
10544
10545 /* Ignore other monsters */
10546 else
10547 {
10548 /* No damage */
10549 dam = 0;
10550 }
10551 }
10552 break;
10553 }
10554
10555
10556 /* Dispel evil */
10557 case GF_DISP_EVIL:
10558 {
10559 /* Only affect evil */
10560 if (p_ptr->suscep_good) {
10561 if (rand_int(100) < p_ptr->skill_sav)
10562 msg_print(Ind, "You shudder, but you resist the effect!");
10563 else {
10564 msg_print(Ind, "You shudder!");
10565 dam /= 3; /* full dam is too harsh */
10566 take_hit(Ind, dam, killer, -who);
10567 }
10568 }
10569
10570 /* Ignore other monsters */
10571 else
10572 {
10573 /* No damage */
10574 dam = 0;
10575 }
10576 break;
10577 }
10578
10579 case GF_DISP_DEMON:
10580 {
10581 if (p_ptr->body_monster){
10582 /* Only affect evil */
10583 if (r_ptr->flags3 & RF3_DEMON)
10584 {
10585 if (rand_int(100) < p_ptr->skill_sav)
10586 {
10587 msg_print(Ind, "You shudder, but you resist the effect!");
10588 }
10589 else
10590 {
10591 /* Message */
10592 msg_print(Ind, "You shudder!");
10593 dam /= 3; /* full dam is too harsh */
10594 take_hit(Ind, dam, killer, -who);
10595 }
10596 }
10597
10598 /* Ignore other monsters */
10599 else
10600 {
10601 /* No damage */
10602 dam = 0;
10603 }
10604 }
10605 break;
10606 }
10607
10608 /* Dispel monster */
10609 case GF_DISP_ALL:
10610 {
10611 #if 0 /* well, since Maiar use it, let's make it work on all players (for PvP/BB) */
10612 if (p_ptr->body_monster) {
10613 if (rand_int(100) < p_ptr->skill_sav)
10614 msg_print(Ind, "You shudder, but you resist the effect!");
10615 else {
10616 /* Message */
10617 msg_print(Ind, "You shudder!");
10618 dam /= 4; /* full dam is too harsh */
10619 take_hit(Ind, dam, killer, -who);
10620 }
10621 }
10622 #else
10623 if (rand_int(100) < p_ptr->skill_sav)
10624 msg_print(Ind, "You shudder, but you resist the effect!");
10625 else {
10626 /* Message */
10627 msg_print(Ind, "You shudder!");
10628 take_hit(Ind, dam, killer, -who);
10629 }
10630 #endif
10631 break;
10632 }
10633
10634 /* Default */
10635 default:
10636
10637 /* No damage */
10638 dam = 0;
10639
10640 break;
10641
10642 }
10643
10644 /* Damage messages in pvp fights - mikaelh */
10645 if (who < 0 && who > PROJECTOR_UNUSUAL && dam > 0)
10646 // if (IS_PVP && dam > 0)
10647 {
10648 if (check_hostile(-who, Ind))
10649 msg_format(-who, "%s is hit for \377y%d \377wdamage.", p_ptr->name, dam);
10650 }
10651
10652 /* Player was hit - mikaelh */
10653 p_ptr->got_hit = TRUE;
10654
10655 #if 0 //redundant?
10656 /* Skip non-connected players */
10657 if (p_ptr->conn != NOT_CONNECTED && (dam || who != PROJECTOR_TERRAIN)) {
10658 /* Disturb */
10659 disturb(Ind, 1, 0);
10660 }
10661 #endif
10662
10663 /* Return "Anything seen?" */
10664 return (obvious);
10665 }
10666
10667
10668
10669
10670
10671
10672
10673
10674
10675 /*
10676 * Find the char to use to draw a moving bolt
10677 * It is moving (or has moved) from (x,y) to (nx,ny).
10678 * If the distance is not "one", we (may) return "*".
10679 */
10680 static char bolt_char(int y, int x, int ny, int nx)
10681 {
10682 if ((ny == y) && (nx == x)) return '*';
10683 if (ny == y) return '-';
10684 if (nx == x) return '|';
10685 if ((ny-y) == (x-nx)) return '/';
10686 if ((ny-y) == (nx-x)) return '\\';
10687 return '*';
10688 }
10689
10690
10691
10692 /*
10693 * Generic "beam"/"bolt"/"ball" projection routine. -BEN-
10694 *
10695 * Input:
10696 * who: Index of "source" monster (or "zero" if "player")
10697 * rad: Radius of explosion (0 = beam/bolt, 1 to 9 = ball)
10698 * y,x: Target location (or location to travel "towards")
10699 * dam: Base damage roll to apply to affected monsters (or player)
10700 * typ: Type of damage to apply to monsters (and objects)
10701 * flg: Extra bit flags (see PROJECT_xxxx in "defines.h")
10702 *
10703 * Return:
10704 * TRUE if any "effects" of the projection were observed, else FALSE
10705 *
10706 * Allows a monster (or player) to project a beam/bolt/ball of a given kind
10707 * towards a given location (optionally passing over the heads of interposing
10708 * monsters), and have it do a given amount of damage to the monsters (and
10709 * optionally objects) within the given radius of the final location.
10710 *
10711 * A "bolt" travels from source to target and affects only the target grid.
10712 * A "beam" travels from source to target, affecting all grids passed through.
10713 * A "ball" travels from source to the target, exploding at the target, and
10714 * affecting everything within the given radius of the target location.
10715 *
10716 * Traditionally, a "bolt" does not affect anything on the ground, and does
10717 * not pass over the heads of interposing monsters, much like a traditional
10718 * missile, and will "stop" abruptly at the "target" even if no monster is
10719 * positioned there, while a "ball", on the other hand, passes over the heads
10720 * of monsters between the source and target, and affects everything except
10721 * the source monster which lies within the final radius, while a "beam"
10722 * affects every monster between the source and target, except for the casting
10723 * monster (or player), and rarely affects things on the ground.
10724 *
10725 * Two special flags allow us to use this function in special ways, the
10726 * "PROJECT_HIDE" flag allows us to perform "invisible" projections, while
10727 * the "PROJECT_JUMP" flag allows us to affect a specific grid, without
10728 * actually projecting from the source monster (or player).
10729 *
10730 * The player will only get "experience" for monsters killed by himself
10731 * Unique monsters can only be destroyed by attacks from the player
10732 *
10733 * Only 256 grids can be affected per projection, limiting the effective
10734 * "radius" of standard ball attacks to nine units (diameter nineteen).
10735 *
10736 * One can project in a given "direction" by combining PROJECT_THRU with small
10737 * offsets to the initial location (see "line_spell()"), or by calculating
10738 * "virtual targets" far away from the player.
10739 *
10740 * One can also use PROJECT_THRU to send a beam/bolt along an angled path,
10741 * continuing until it actually hits somethings (useful for "stone to mud").
10742 *
10743 * Bolts and Beams explode INSIDE walls, so that they can destroy doors.
10744 *
10745 * Balls must explode BEFORE hitting walls, or they would affect monsters
10746 * on both sides of a wall. Some bug reports indicate that this is still
10747 * happening in 2.7.8 for Windows, though it appears to be impossible.
10748 *
10749 * We "pre-calculate" the blast area only in part for efficiency.
10750 * More importantly, this lets us do "explosions" from the "inside" out.
10751 * This results in a more logical distribution of "blast" treasure.
10752 * It also produces a better (in my opinion) animation of the explosion.
10753 * It could be (but is not) used to have the treasure dropped by monsters
10754 * in the middle of the explosion fall "outwards", and then be damaged by
10755 * the blast as it spreads outwards towards the treasure drop location.
10756 *
10757 * Walls and doors are included in the blast area, so that they can be
10758 * "burned" or "melted" in later versions.
10759 *
10760 * This algorithm is intended to maximize simplicity, not necessarily
10761 * efficiency, since this function is not a bottleneck in the code.
10762 *
10763 * We apply the blast effect from ground zero outwards, in several passes,
10764 * first affecting features, then objects, then monsters, then the player.
10765 * This allows walls to be removed before checking the object or monster
10766 * in the wall, and protects objects which are dropped by monsters killed
10767 * in the blast, and allows the player to see all affects before he is
10768 * killed or teleported away. The semantics of this method are open to
10769 * various interpretations, but they seem to work well in practice.
10770 *
10771 * We process the blast area from ground-zero outwards to allow for better
10772 * distribution of treasure dropped by monsters, and because it provides a
10773 * pleasing visual effect at low cost.
10774 *
10775 * Note that the damage done by "ball" explosions decreases with distance.
10776 * This decrease is rapid, grids at radius "dist" take "1/dist" damage.
10777 *
10778 * Notice the "napalm" effect of "beam" weapons. First they "project" to
10779 * the target, and then the damage "flows" along this beam of destruction.
10780 * The damage at every grid is the same as at the "center" of a "ball"
10781 * explosion, since the "beam" grids are treated as if they ARE at the
10782 * center of a "ball" explosion.
10783 *
10784 * Currently, specifying "beam" plus "ball" means that locations which are
10785 * covered by the initial "beam", and also covered by the final "ball", except
10786 * for the final grid (the epicenter of the ball), will be "hit twice", once
10787 * by the initial beam, and once by the exploding ball. For the grid right
10788 * next to the epicenter, this results in 150% damage being done. The center
10789 * does not have this problem, for the same reason the final grid in a "beam"
10790 * plus "bolt" does not -- it is explicitly removed. Simply removing "beam"
10791 * grids which are covered by the "ball" will NOT work, as then they will
10792 * receive LESS damage than they should. Do not combine "beam" with "ball".
10793 *
10794 * The array "gy[],gx[]" with current size "grids" is used to hold the
10795 * collected locations of all grids in the "blast area" plus "beam path".
10796 *
10797 * Note the rather complex usage of the "gm[]" array. First, gm[0] is always
10798 * zero. Second, for N>1, gm[N] is always the index (in gy[],gx[]) of the
10799 * first blast grid (see above) with radius "N" from the blast center. Note
10800 * that only the first gm[1] grids in the blast area thus take full damage.
10801 * Also, note that gm[rad+1] is always equal to "grids", which is the total
10802 * number of blast grids.
10803 *
10804 * Note that once the projection is complete, (y2,x2) holds the final location
10805 * of bolts/beams, and the "epicenter" of balls.
10806 *
10807 * Note also that "rad" specifies the "inclusive" radius of projection blast,
10808 * so that a "rad" of "one" actually covers 5 or 9 grids, depending on the
10809 * implementation of the "distance" function. Also, a bolt can be properly
10810 * viewed as a "ball" with a "rad" of "zero".
10811 *
10812 * Note that if no "target" is reached before the beam/bolt/ball travels the
10813 * maximum distance allowed (MAX_RANGE), no "blast" will be induced. This
10814 * may be relevant even for bolts, since they have a "1x1" mini-blast.
10815 *
10816 * Some people have requested an "auto-explode ball attacks at max range"
10817 * option, which should probably be handled by this function. XXX XXX XXX
10818 *
10819 * Note that for consistency, we "pretend" that the bolt actually takes "time"
10820 * to move from point A to point B, even if the player cannot see part of the
10821 * projection path. Note that in general, the player will *always* see part
10822 * of the path, since it either starts at the player or ends on the player.
10823 *
10824 * Hack -- we assume that every "projection" is "self-illuminating".
10825 */
10826 #if 0
10827 bool lua_project(int who, int rad, struct worldpos *wpos, int y, int x, int dam, int typ, int flg, char attacker[80])
10828 {
10829 return(project(who, rad, wpos, y, x, dam, typ, flg, attacker));
10830 }
10831 #endif
10832 bool project(int who, int rad, struct worldpos *wpos_tmp, int y, int x, int dam, int typ, int flg, char *attacker)
10833 {
10834 int i, j, t;
10835 int y1, x1, y2, x2;
10836 int /*y0, x0,*/ y9, x9;
10837 int dist, dist_hack = 0, true_dist = 0;
10838 int who_can_see[26], num_can_see = 0;
10839 int terrain_resistance = -1, terrain_damage = -1;
10840 bool old_tacit = suppress_message, suppress_explosion = FALSE;
10841
10842 #ifdef OPTIMIZED_ANIMATIONS
10843 int path_y[MAX_RANGE];
10844 int path_x[MAX_RANGE];
10845 int path_num = 0;
10846 #endif
10847
10848 struct worldpos wpos_fix, *wpos = &wpos_fix;
10849 /* copy wpos in case it was a monster's wpos that gets erased from mon_take_hit() if monster dies */
10850 wpos_fix = *wpos_tmp;
10851
10852 /* Affected location(s) */
10853 cave_type *c_ptr, *c_ptr2;
10854
10855 /* Assume the player sees nothing */
10856 bool notice = FALSE;
10857
10858 /* Assume the player has seen nothing */
10859 /*bool visual = FALSE;*/
10860
10861 /* Assume the player has seen no blast grids */
10862 bool drawn = FALSE;
10863
10864 /* Is the player blind? */
10865 /* Blindness is currently ignored for this function */
10866 /*bool blind;*/
10867
10868 /* Number of grids in the "blast area" (including the "beam" path) */
10869 int grids = 0;
10870
10871 int effect = 0;
10872
10873 bool players_only = FALSE; /* spell affects players only */
10874
10875 /* Coordinates of the affected grids */
10876 // byte gx[256], gy[256];
10877 // byte gx[tdi[PREPARE_RADIUS]], gy[tdi[PREPARE_RADIUS]];
10878 byte gx[512], gy[512];
10879
10880 /* Encoded "radius" info (see above) */
10881 // byte gm[16];
10882 byte gm[PREPARE_RADIUS];
10883
10884 /* for cave_proj(): allow it to travel onto certain terrain,
10885 but not really much further - C. Blue */
10886 bool broke_on_terrain1 = FALSE, broke_on_terrain2 = FALSE;
10887
10888 dun_level *l_ptr;
10889 cave_type **zcave;
10890
10891 if (!(zcave = getcave(wpos))) return(FALSE);
10892 l_ptr = getfloor(wpos);
10893
10894 /* Spells which never affect monsters, read:
10895 Spells which we want to exclude from merely _waking monsters up_!
10896 Note: Bolt spells will still be 'stopped' when hitting a monster. */
10897 if ((typ == GF_HEAL_PLAYER) || (typ == GF_WRAITH_PLAYER) ||
10898 (typ == GF_SPEED_PLAYER) || (typ == GF_SHIELD_PLAYER) ||
10899 (typ == GF_RECALL_PLAYER) || (typ == GF_BLESS_PLAYER) ||
10900 (typ == GF_REMFEAR_PLAYER) || (typ == GF_SATHUNGER_PLAYER) ||
10901 (typ == GF_REMCONF_PLAYER) || (typ == GF_REMIMAGE_PLAYER) ||
10902 (typ == GF_RESFIRE_PLAYER) || (typ == GF_RESCOLD_PLAYER) ||
10903 (typ == GF_CUREPOISON_PLAYER) || (typ == GF_SEEINVIS_PLAYER) ||
10904 (typ == GF_SEEMAP_PLAYER) || (typ == GF_CURECUT_PLAYER) ||
10905 (typ == GF_CURESTUN_PLAYER) || (typ == GF_DETECTCREATURE_PLAYER) ||
10906 (typ == GF_DETECTDOOR_PLAYER) || (typ == GF_DETECTTRAP_PLAYER) ||
10907 (typ == GF_TELEPORTLVL_PLAYER) || (typ == GF_RESPOIS_PLAYER) ||
10908 (typ == GF_RESELEC_PLAYER) || (typ == GF_RESACID_PLAYER) ||
10909 (typ == GF_HPINCREASE_PLAYER) || (typ == GF_HERO_PLAYER) ||
10910 (typ == GF_SHERO_PLAYER) || (typ == GF_TELEPORT_PLAYER) ||
10911 (typ == GF_ZEAL_PLAYER) || (typ == GF_MINDBOOST_PLAYER) ||
10912 (typ == GF_RESTORE_PLAYER) || (typ == GF_REMCURSE_PLAYER) ||
10913 (typ == GF_CURE_PLAYER) || (typ == GF_RESURRECT_PLAYER) ||
10914 (typ == GF_SANITY_PLAYER) || (typ == GF_SOULCURE_PLAYER) ||
10915 (typ == GF_IDENTIFY) || (typ == GF_SLOWPOISON_PLAYER))
10916 players_only = TRUE;
10917
10918
10919 #ifdef PROJECTION_FLUSH_LIMIT
10920 count_project++;
10921 #endif // PROJECTION_FLUSH_LIMIT
10922
10923 /* Location of player */
10924 /*y0 = py;
10925 x0 = px;*/
10926
10927
10928 /* Hack -- Jump to target */
10929 if (flg & PROJECT_JUMP) {
10930 x1 = x;
10931 y1 = y;
10932
10933 /* Clear the flag (well, needed?) */
10934 // flg &= ~(PROJECT_JUMP);
10935 }
10936
10937 /* Hack -- Start at a player */
10938 else if (who < 0 && who > PROJECTOR_UNUSUAL)
10939 // else if (IS_PVP)
10940 {
10941 x1 = Players[0 - who]->px;
10942 y1 = Players[0 - who]->py;
10943 }
10944
10945 /* Start at a monster */
10946 else if (who > 0) {
10947 x1 = m_list[who].fx;
10948 y1 = m_list[who].fy;
10949 }
10950 #if 1
10951 /* Oops */
10952 else {
10953 x1 = x;
10954 y1 = y;
10955 }
10956 #endif /* 0 */
10957
10958 /* Default "destination" */
10959 y2 = y; x2 = x;
10960
10961
10962 /* Hack -- verify stuff */
10963 if ((flg & PROJECT_THRU) && (x1 == x2) && (y1 == y2))
10964 flg &= ~PROJECT_THRU;
10965
10966
10967
10968 /* Hack -- Assume there will be no blast (max radius 16) */
10969 // for (dist = 0; dist < 16; dist++) gm[dist] = 0;
10970 for (dist = 0; dist < PREPARE_RADIUS; dist++) gm[dist] = 0;
10971
10972
10973 /* Hack -- Handle stuff */
10974 /*handle_stuff();*/
10975
10976
10977 #ifdef DOUBLE_LOS_SAFETY
10978 /* Use projectable..() check to pre-determine if the line of fire is ok
10979 and we may skip redundant checking that appears further below. */
10980 bool ok_DLS;
10981 if (IS_PVP) { /* ..but we're not a monster? */
10982 #ifndef PY_PROJ_WALL
10983 ok_DLS = projectable(wpos, y1, x1, y2, x2, MAX_RANGE);
10984 #else
10985 ok_DLS = projectable_wall(wpos, y1, x1, y2, x2, MAX_RANGE);
10986 #endif
10987 } else { /* Catch indirect attack spells! Those are RF4_ROCKET and RF4_BR_DISI. */
10988 /* Monsters always could target players in walls (even if the projection explodes _before_ the wall)
10989 so we only need to use projectable_wall() here. */
10990 ok_DLS = projectable_wall(wpos, y1, x1, y2, x2, MAX_RANGE);
10991 }
10992 /* hack: catch non 'dir == 5' projections, aka manually directed */
10993 if (x1 == x2 || y1 == y2 || ABS(x2 - x1) == ABS(y2 - y1)) ok_DLS = FALSE;
10994 #endif
10995
10996
10997 /* Start at the source */
10998 x = x9 = x1;
10999 y = y9 = y1;
11000 dist = 0;
11001
11002 /* Project until done */
11003 while (TRUE) {
11004 /* Gather beam grids */
11005 if (flg & PROJECT_BEAM) {
11006 if (project_time_effect & EFF_WALL) {
11007 effect = new_effect(who, typ, dam, project_time, project_interval, wpos, y, x, 0, project_time_effect);
11008 if (effect != -1) zcave[y][x].effect = effect;
11009 }
11010 gy[grids] = y;
11011 gx[grids] = x;
11012 grids++;
11013 #if DEBUG_LEVEL > 1
11014 if(grids > 500) s_printf("grids %d\n", grids);
11015 #endif /* DEBUG_LEVEL */
11016 }
11017
11018 /* Check the grid */
11019 c_ptr = &zcave[y][x];
11020
11021 /* XXX XXX Hack -- Display "beam" grids */
11022 if (!(flg & PROJECT_HIDE) &&
11023 dist && (flg & PROJECT_BEAM))
11024 #ifdef PROJECTION_FLUSH_LIMIT
11025 if (count_project < PROJECTION_FLUSH_LIMIT)
11026 #endif // PROJECTION_FLUSH_LIMIT
11027 {
11028 /* Hack -- Visual effect -- "explode" the grids */
11029 for (j = 1; j < NumPlayers + 1; j++) {
11030 player_type *p_ptr = Players[j];
11031 int dispx, dispy;
11032 byte attr;
11033
11034 if (p_ptr->conn == NOT_CONNECTED)
11035 continue;
11036
11037 if(!inarea(&p_ptr->wpos, wpos))
11038 continue;
11039
11040 if (p_ptr->blind)
11041 continue;
11042
11043 if (!panel_contains(y, x))
11044 continue;
11045
11046 if (!player_has_los_bold(j, y, x))
11047 continue;
11048
11049 dispx = x - p_ptr->panel_col_prt;
11050 dispy = y - p_ptr->panel_row_prt;
11051
11052 attr = spell_color(typ);
11053
11054 p_ptr->scr_info[dispy][dispx].c = '*';
11055 p_ptr->scr_info[dispy][dispx].a = attr;
11056
11057 Send_char(j, dispx, dispy, attr, '*');
11058 }
11059 }
11060
11061
11062 /* Analyze whether the projection can overcome terrain in its way - C. Blue */
11063 /* Check: Fire vs Trees */
11064 if (allow_terraforming(wpos, FEAT_TREE)) {
11065 switch (c_ptr->feat) {
11066 case FEAT_TREE: terrain_resistance = 50; break;
11067 case FEAT_IVY: terrain_resistance = 0; break;
11068 case FEAT_BUSH: terrain_resistance = 20; break;
11069 case FEAT_DEAD_TREE: terrain_resistance = 30; break;
11070 default: terrain_resistance = -1; break;
11071 }
11072 switch (typ) {
11073 case GF_FIRE: terrain_damage = 100; break;
11074 case GF_METEOR: terrain_damage = 150; break;
11075 case GF_PLASMA: terrain_damage = 120; break;
11076 case GF_HELL_FIRE: terrain_damage = 130; break;
11077 default: terrain_damage = -1; break;
11078 }
11079 }
11080
11081 /* Accordingly, stop the projection or have it go on unhindered */
11082 if (terrain_damage >= 0 && terrain_resistance >= 0 &&
11083 magik(terrain_damage - terrain_resistance)) {
11084 /* go on unhindered by terrain, destroy terrain even */
11085 } else {
11086 /* Never pass through walls */
11087 if (flg & PROJECT_GRAV) { /* Running along the floor?.. */
11088 if (dist && !cave_floor_bold(zcave, y, x)) break;
11089 #ifndef PROJ_MON_ON_WALL
11090 } else if (IS_PVP) { /* ..or rather levitating through the air? */
11091 if (dist && !cave_contact(zcave, y, x)
11092 #ifdef DOUBLE_LOS_SAFETY
11093 && !ok_DLS
11094 #endif
11095 ) break;
11096 #endif
11097 } else { /* monsters can target certain non-los grid types directly */
11098 if (dist) {
11099 #ifdef PROJ_ON_WALL
11100 if (broke_on_terrain1) break;
11101 #else
11102 #ifdef DOUBLE_LOS_SAFETY
11103 if ((!cave_proj(zcave, y, x) && !ok_DLS)
11104 #else
11105 if (!cave_proj(zcave, y, x)
11106 #endif
11107 || broke_on_terrain1) break;
11108 #endif
11109 else if (!cave_contact(zcave, y, x)
11110 #ifdef DOUBLE_LOS_SAFETY
11111 && !ok_DLS
11112 #endif
11113 ) {
11114 #ifndef PROJ_MON_ON_WALL
11115 /* if there isn't a player on the grid, we can't target it */
11116 if (zcave[y][x].m_idx >= 0) break;
11117 #else
11118 /* if there isn't a player/monster on the grid, we can't target it */
11119 if (zcave[y][x].m_idx == 0) break;
11120 #endif
11121 /* can't travel any further for sure now */
11122 broke_on_terrain1 = TRUE;
11123 }
11124 }
11125 }
11126 }
11127
11128
11129 /* Check for arrival at "final target" (if desired) */
11130 if (!(flg & PROJECT_THRU) && (x == x2) && (y == y2)) break;
11131
11132 /* If allowed, and we have moved at all, stop when we hit anybody */
11133 /* -AD- Only stop if it isn't a party member */
11134 if ((c_ptr->m_idx != 0) && dist && (flg & PROJECT_STOP)) {
11135 if (who > 0) {
11136 /* hit first player (ignore monster) */
11137 if (c_ptr->m_idx < 0) break;
11138 }
11139 else if (who < 0) {
11140 /* always hit monsters */
11141 if (c_ptr->m_idx > 0) break;
11142
11143 /* Hostile players hit each other */
11144 if (check_hostile(0 - who, 0 - c_ptr->m_idx)) break;
11145
11146 /* If player hits himself, he hits others too */
11147 if (flg & PROJECT_PLAY) break;
11148
11149 #if 0 /* covered by PROJECT_PLAY above now */
11150 /* Always affect players (regardless of hostility/party state): */
11151 if (typ == GF_OLD_POLY) break;
11152 #endif
11153
11154 #if 0 /* neutral people hit each other ..NOT! - C. Blue FF$$$ */
11155 if (!Players[0 - who]->party) break;
11156
11157 /* people not in the same party hit each other ..NOT! - C. Blue */
11158 if (!player_in_party(Players[0 - who]->party, 0 - c_ptr->m_idx))
11159 #if FRIEND_FIRE_CHANCE
11160 if (!magik(FRIEND_FIRE_CHANCE))
11161 #endif
11162 break;
11163 #endif
11164 }
11165 // else break; // Huh? always break? XXX XXX
11166 }
11167
11168
11169 /* Calculate the new location */
11170 y9 = y;
11171 x9 = x;
11172 mmove2(&y9, &x9, y1, x1, y2, x2);
11173 #ifdef DOUBLE_LOS_SAFETY
11174 /* After we reached our target we have no more need for double-los-safety */
11175 if (y9 == y2 && x9 == x2) ok_DLS = FALSE;
11176 #endif
11177
11178
11179 /* Keep track of the distance traveled */
11180 dist++;
11181
11182 /* Distance stuff: The 'dist > MAX_RANGE' part is basically obsolete
11183 now that distance() is used to achieve 'true' distance. */
11184
11185 /* Distance to target too great?
11186 Use distance() to form a 'natural' circle shaped radius instead of a square shaped radius,
11187 monsters do this too */
11188 if ((true_dist = distance(y1, x1, y9, x9)) > MAX_RANGE) break;
11189
11190 /* Nothing can travel furthur than the maximal distance */
11191 if (dist > MAX_RANGE) break;
11192
11193 /* Hack -- Balls explode BEFORE reaching walls or doors */
11194 if (flg & PROJECT_GRAV) { /* Running along the floor?.. */
11195 if (!cave_floor_bold(zcave, y9, x9) && (rad > 0)) break;
11196 #ifndef PROJ_MON_ON_WALL
11197 } else if (IS_PVP) { /* ..or rather levitating through the air? */
11198 if (!cave_contact(zcave, y9, x9)
11199 #ifdef DOUBLE_LOS_SAFETY
11200 && !ok_DLS
11201 #endif
11202 && (rad > 0)) break;
11203 #endif
11204 } else { /* monsters can target certain non-los grid types directly */
11205 if (rad > 0) {
11206 #ifdef PROJ_ON_WALL
11207 if (broke_on_terrain2) break;
11208 #else
11209 #ifdef DOUBLE_LOS_SAFETY
11210 if ((!cave_proj(zcave, y9, x9) && !ok_DLS)
11211 #else
11212 if (!cave_proj(zcave, y9, x9)
11213 #endif
11214 || broke_on_terrain2) break;
11215 #endif
11216 else if (!cave_contact(zcave, y9, x9)
11217 #ifdef DOUBLE_LOS_SAFETY
11218 && !ok_DLS
11219 #endif
11220 ) {
11221 #ifndef PROJ_MON_ON_WALL
11222 /* if there isn't a player on the grid, we can't target it */
11223 if (zcave[y9][x9].m_idx >= 0) break;
11224 #else
11225 /* if there isn't a player/monster on the grid, we can't target it */
11226 if (zcave[y9][x9].m_idx == 0) break;
11227 #endif
11228 /* can't travel any further for sure now */
11229 broke_on_terrain2 = TRUE;
11230 }
11231 }
11232 }
11233
11234
11235 /* Only do visual effects (and delay) if requested */
11236 if (!(flg & PROJECT_HIDE))
11237 #ifndef OPTIMIZED_ANIMATIONS
11238 if (count_project < PROJECTION_FLUSH_LIMIT)
11239 #endif // PROJECTION_FLUSH_LIMIT
11240 {
11241 #ifdef PROJECTION_FLUSH_LIMIT
11242 for (j = 1; j < NumPlayers + 1; j++) {
11243 player_type *p_ptr = Players[j];
11244 int dispy, dispx;
11245 char ch;
11246 byte attr;
11247
11248 if (p_ptr->conn == NOT_CONNECTED)
11249 continue;
11250
11251 if (!inarea(&p_ptr->wpos, wpos))
11252 continue;
11253
11254 if (p_ptr->blind)
11255 continue;
11256
11257 if (!panel_contains(y9, x9))
11258 continue;
11259
11260 if (!player_has_los_bold(j, y9, x9))
11261 continue;
11262
11263 dispx = x9 - p_ptr->panel_col_prt;
11264 dispy = y9 - p_ptr->panel_row_prt;
11265
11266 ch = bolt_char(y, x, y9, x9);
11267 attr = spell_color(typ);
11268
11269 p_ptr->scr_info[dispy][dispx].c = ch;
11270 p_ptr->scr_info[dispy][dispx].a = attr;
11271
11272 Send_char(j, dispx, dispy, attr, ch);
11273
11274 /* Hack -- Show bolt char */
11275 if (dist % 2) Send_flush(j);
11276 }
11277 #else /* OPTIMIZED_ANIMATIONS */
11278 /* Save the path */
11279 if (path_num < MAX_RANGE) {
11280 path_y[path_num] = y9;
11281 path_x[path_num] = x9;
11282 path_num++;
11283 }
11284 #endif /* OPTIMIZED_ANIMATIONS */
11285 }
11286
11287 /* Clean up */
11288 everyone_lite_spot(wpos, y9, x9);
11289
11290 /* Save the new location */
11291 y = y9;
11292 x = x9;
11293 }
11294
11295 if (project_time_effect & EFF_WALL) {
11296 flg &= ~(PROJECT_STAY);
11297 project_time = 0;
11298 project_interval = 0;
11299 project_time_effect = 0;
11300 }
11301
11302 /* Hack: Usually, elemental bolt spells will not hurt floor/item if they already hurt a monster/player.
11303 Some bolt spells (poly) don't need this flag, since they don't hurt items/floor at all. */
11304 if ((flg & PROJECT_EVSG) && zcave[y][x].m_idx != 0)
11305 flg &= ~(PROJECT_GRID | PROJECT_ITEM);
11306
11307 /* hack: FF1_BLOCK_CONTACT grids prevent explosions,
11308 since those would carry over on the other side if it's
11309 just a wall of thickness 1 and possibly hit monsters there. */
11310 if (f_info[zcave[y9][x9].feat].flags1 & FF1_BLOCK_CONTACT) suppress_explosion = TRUE;
11311
11312 #ifdef OPTIMIZED_ANIMATIONS
11313 if (path_num) {
11314 /* Pick a random spot along the path */
11315 i = rand_int(path_num);
11316 y9 = path_y[i];
11317 x9 = path_x[i];
11318
11319 for (j = 1; j < NumPlayers + 1; j++) {
11320 player_type *p_ptr = Players[j];
11321 int dispy, dispx;
11322 char ch;
11323 byte attr;
11324
11325 if (p_ptr->conn == NOT_CONNECTED)
11326 continue;
11327
11328 if (!inarea(&p_ptr->wpos, wpos))
11329 continue;
11330
11331 if (p_ptr->blind)
11332 continue;
11333
11334 if (!panel_contains(y9, x9))
11335 continue;
11336
11337 if (!player_has_los_bold(j, y9, x9))
11338 continue;
11339
11340 dispx = x9 - p_ptr->panel_col_prt;
11341 dispy = y9 - p_ptr->panel_row_prt;
11342
11343 ch = bolt_char(y, x, y9, x9);
11344 attr = spell_color(typ);
11345
11346 p_ptr->scr_info[dispy][dispx].c = ch;
11347 p_ptr->scr_info[dispy][dispx].a = attr;
11348
11349 Send_char(j, dispx, dispy, attr, ch);
11350
11351 /* Flush once */
11352 Send_flush(j);
11353 }
11354
11355 /* Redraw later */
11356 everyone_lite_later_spot(wpos, y9, x9);
11357 }
11358 #endif /* OPTIMIZED_ANIMATIONS */
11359
11360 /* Save the "blast epicenter" */
11361 y2 = y;
11362 x2 = x;
11363
11364 /* Start the "explosion" */
11365 gm[0] = 0;
11366
11367 /* Hack -- make sure beams get to "explode" */
11368 gm[1] = grids;
11369
11370 /* Ported hack for reflection */
11371 dist_hack = dist;
11372
11373 /* If we found a "target", explode there */
11374 if (true_dist <= MAX_RANGE && !suppress_explosion) {
11375 /* Mega-Hack -- remove the final "beam" grid */
11376 // if ((flg & PROJECT_BEAM) && (grids > 0)) grids--;
11377
11378 dist = 0;
11379
11380 for (i = 0; i <= tdi[rad]; i++) {
11381 /* Encode some more "radius" info */
11382 if (i == tdi[dist]) {
11383 gm[++dist] = grids;
11384 #if DEBUG_LEVEL > 2
11385 s_printf("dist:%d i:%d\n", dist, i);
11386 #endif
11387 if (dist > rad) break;
11388 }
11389
11390 y = y2 + tdy[i];
11391 x = x2 + tdx[i];
11392
11393 /* Ignore "illegal" locations */
11394 if (!in_bounds3(wpos, l_ptr, y, x)) continue;
11395
11396 #ifdef NO_EXPLOSION_OUT_OF_MAX_RANGE
11397 /* Don't create explosions that exceed MAX_RANGE from the caster */
11398 if (distance(y, x, y1, x1) > MAX_RANGE) continue;
11399 #endif
11400
11401 #if 1
11402 if ((typ == GF_DISINTEGRATE) ||
11403 /* Reduce disintegration effect of rockets to radius 1 - C. Blue */
11404 ((typ == GF_ROCKET || typ == GF_DETONATION) && (ABS(y - y2) <= 1) && (ABS(x - x2) <= 1)) )
11405 {
11406 c_ptr2 = &zcave[y][x];
11407 if (cave_valid_bold(zcave,y,x))
11408 // && (cave[y][x].feat < FEAT_PATTERN_START
11409 // || cave[y][x].feat > FEAT_PATTERN_XTRA2))
11410 {
11411 if (
11412 //(c_ptr->feat != FEAT_WATER) &&
11413 (c_ptr2->feat != FEAT_SHAL_WATER) &&
11414 (c_ptr2->feat != FEAT_DEEP_WATER) &&
11415 (c_ptr2->feat != FEAT_TAINTED_WATER) &&
11416 (c_ptr2->feat != FEAT_DEEP_LAVA) &&
11417 (c_ptr2->feat != FEAT_SHAL_LAVA) &&
11418 //(c_ptr2->feat != FEAT_ASH) &&
11419 (c_ptr2->feat != FEAT_MUD) &&
11420 (c_ptr2->feat != FEAT_DIRT) &&
11421 (c_ptr2->feat != FEAT_HOME_OPEN) &&
11422 (c_ptr2->feat != FEAT_HOME))
11423 {
11424 if (allow_terraforming(wpos, FEAT_TREE)) {
11425 if (randint(2) == 1)
11426 cave_set_feat_live(wpos, y, x, FEAT_FLOOR);
11427 else
11428 cave_set_feat_live(wpos, y, x, FEAT_ASH);
11429 }
11430 }
11431
11432 /* Update some things -- similar to GF_KILL_WALL */
11433 // p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
11434 }
11435 }
11436 #endif /* 1 */
11437 /* else */ /* HERE!!!!*/
11438 /* Ball explosions are stopped by walls */
11439 if (!los(wpos, y2, x2, y, x)) continue;
11440
11441 /* Save this grid */
11442 gy[grids] = y;
11443 gx[grids] = x;
11444 grids++;
11445 if(grids > 500) printf("grids %d\n", grids);
11446 }
11447
11448 #if 0
11449 /* Determine the blast area, work from the inside out */
11450 for (dist = 0; dist <= rad; dist++) {
11451 /* Scan the maximal blast area of radius "dist" */
11452 for (y = y2 - dist; y <= y2 + dist; y++) {
11453 for (x = x2 - dist; x <= x2 + dist; x++) {
11454 /* Ignore "illegal" locations */
11455 if (!in_bounds2(wpos, y, x)) continue;
11456
11457 /* Enforce a "circular" explosion */
11458 if (distance(y2, x2, y, x) != dist) continue;
11459
11460 #if 0
11461 if (typ == GF_DISINTEGRATE) {
11462 if (cave_valid_bold(y,x) &&
11463 (cave[y][x].feat < FEAT_PATTERN_START
11464 || cave[y][x].feat > FEAT_PATTERN_XTRA2))
11465 cave_set_feat_live(y, x, FEAT_FLOOR);
11466
11467 /* Update some things -- similar to GF_KILL_WALL */
11468 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW | PU_MONSTERS);
11469 }
11470 #endif /* 0 */
11471 /* else */ /* HERE!!!!*/
11472 /* Ball explosions are stopped by walls */
11473 if (!los(wpos, y2, x2, y, x)) continue;
11474
11475 /* Save this grid */
11476 gy[grids] = y;
11477 gx[grids] = x;
11478 grids++;
11479 if(grids>500) printf("grids %d\n", grids);
11480 }
11481 }
11482
11483 /* Encode some more "radius" info */
11484 gm[dist+1] = grids;
11485 }
11486 #endif // 0
11487 }
11488
11489 /* Speed -- ignore "non-explosions" */
11490 if (!grids) return (FALSE);
11491
11492 #ifndef OPTIMIZED_ANIMATIONS
11493 /* Display the "blast area" */
11494 if (!(flg & PROJECT_HIDE))
11495 #ifdef PROJECTION_FLUSH_LIMIT
11496 if (count_project < PROJECTION_FLUSH_LIMIT)
11497 #endif // PROJECTION_FLUSH_LIMIT
11498 {
11499 /* Then do the "blast", from inside out */
11500 for (t = 0; t <= rad; t++) {
11501 /* Reset who can see */
11502 num_can_see = 0;
11503
11504 /* Dump everything with this radius */
11505 for (i = gm[t]; i < gm[t+1]; i++) {
11506 /* Extract the location */
11507 y = gy[i];
11508 x = gx[i];
11509
11510 for (j = 1; j < NumPlayers + 1; j++) {
11511 player_type *p_ptr = Players[j];
11512 int dispy, dispx;
11513 byte attr;
11514 int k;
11515 bool flag = TRUE;
11516
11517 if (p_ptr->conn == NOT_CONNECTED)
11518 continue;
11519
11520 if (!inarea(&p_ptr->wpos, wpos))
11521 continue;
11522
11523 if (p_ptr->blind)
11524 continue;
11525
11526 if (!panel_contains(y, x))
11527 continue;
11528
11529 if (!player_has_los_bold(j, y, x))
11530 continue;
11531
11532 attr = spell_color(typ);
11533
11534 dispx = x - p_ptr->panel_col_prt;
11535 dispy = y - p_ptr->panel_row_prt;
11536
11537 p_ptr->scr_info[dispy][dispx].c = '*';
11538 p_ptr->scr_info[dispy][dispx].a = attr;
11539
11540 Send_char(j, dispx, dispy, attr, '*');
11541
11542 drawn = TRUE;
11543
11544 for (k = 0; k < num_can_see; k++) {
11545 if (who_can_see[k] == j)
11546 flag = FALSE;
11547 }
11548
11549 if (flag) who_can_see[num_can_see++] = j;
11550 }
11551 }
11552
11553 /* Flush each "radius" seperately */
11554 for (j = 0; j < num_can_see; j++) {
11555 /* Show this radius and delay */
11556 Send_flush(who_can_see[j]);
11557 }
11558 }
11559
11560 /* Flush the erasing */
11561 if (drawn) {
11562 /* Erase the explosion drawn above */
11563 for (i = 0; i < grids; i++) {
11564 /* Extract the location */
11565 y = gy[i];
11566 x = gx[i];
11567
11568 /* Erase if needed */
11569 everyone_lite_spot(wpos, y, x);
11570 }
11571
11572 /* Flush the explosion */
11573 for (j = 0; j < num_can_see; j++) {
11574 /* Show this radius and delay */
11575 Send_flush(who_can_see[j]);
11576 }
11577 }
11578 }
11579 #endif
11580
11581
11582 /* Check features */
11583 if (flg & PROJECT_GRID) {
11584 /* Start with "dist" of zero */
11585 dist = 0;
11586
11587 /* Effect ? */
11588 if (flg & PROJECT_STAY) {
11589 /* I believe it's not right */
11590 // effect = new_effect(typ, dam, project_time, py, px, rad, project_time_effect);
11591 /* MEGAHACK -- quick hack to make fire_wall work
11592 * this should be rewritten! - Jir -
11593 *
11594 * It registers the 'wall' as if it was a ball:
11595 *
11596 * |--dist_hack--|
11597 * (y,x) *------+------* (y2,x2)
11598 * +pseudo 'centre'
11599 */
11600 if (rad == 0) {
11601 #if 1 /* Kurzel's patch commented this out - but this is required for fireworks! */
11602 effect = new_effect(who, typ, dam, project_time, project_interval, wpos,
11603 (y + y2) / 2, (x + x2) / 2, dist_hack / 2 + 1,
11604 project_time_effect);
11605 #endif
11606 #ifdef ARCADE_SERVER
11607 #if 0
11608 if (project_time_effect & EFF_CROSSHAIR_A || project_time_effect & EFF_CROSSHAIR_B ||
11609 project_time_effect & EFF_CROSSHAIR_C) {
11610 msg_broadcast(0, "making an effect");
11611 player_type *pfft_ptr = Players[project_interval];
11612 pfft_ptr->e = effect;
11613 }
11614 #endif
11615 #endif
11616 } else {
11617 effect = new_effect(who, typ, dam, project_time, project_interval, wpos,
11618 y2, x2, rad, project_time_effect);
11619 }
11620 project_interval = 0;
11621 project_time = 0;
11622 project_time_effect = 0;
11623 }
11624
11625 /* Now hurt the cave grids (and objects) from the inside out */
11626 for (i = 0; i < grids; i++) {
11627 /* Hack -- Notice new "dist" values */
11628 if (gm[dist+1] == i) dist++;
11629
11630 /* Get the grid location */
11631 y = gy[i];
11632 x = gx[i];
11633
11634 if(!in_bounds(y,x)) continue;
11635 /* Affect the feature */
11636 if ((flg & PROJECT_STAY) || (flg & PROJECT_FULL)) dist = 0;
11637 if (project_f(0 - who, who, dist, wpos, y, x, dam, typ)) notice = TRUE;
11638
11639 /* Effect ? */
11640 if (flg & PROJECT_STAY) {
11641 if (effect != -1) /* check that we're not out of effects - mikaelh */
11642 {
11643 zcave[y][x].effect = effect;
11644 everyone_lite_spot(wpos, y, x);
11645 }
11646 }
11647 }
11648 }
11649
11650 /* PROJECT_DUMY means we don't have to project on floor/items/monsters/players,
11651 because the effect was just for visual entertainment.. - C. Blue */
11652 if (flg & PROJECT_DUMY) return(FALSE);
11653
11654 /* Check objects */
11655 if (flg & PROJECT_ITEM) {
11656 /* Start with "dist" of zero */
11657 dist = 0;
11658
11659 /* Now hurt the cave grids (and objects) from the inside out */
11660 for (i = 0; i < grids; i++) {
11661 /* Hack -- Notice new "dist" values */
11662 if (gm[dist+1] == i) dist++;
11663
11664 /* Get the grid location */
11665 y = gy[i];
11666 x = gx[i];
11667
11668 if(!in_bounds(y,x)) continue;
11669 /* Affect the object */
11670 if ((flg & PROJECT_STAY) || (flg & PROJECT_FULL)) dist = 0;
11671 if (project_i(0 - who, who, dist, wpos, y, x, dam, typ)) notice = TRUE;
11672 }
11673 }
11674
11675
11676 /* Check monsters */
11677 /* eww, hope traps won't kill the server here.. - Jir - */
11678 if ((flg & PROJECT_KILL) && !players_only) {
11679 /* Start with "dist" of zero */
11680 dist = 0;
11681
11682 /* Mega-Hack */
11683 project_m_n = 0;
11684 project_m_x = 0;
11685 project_m_y = 0;
11686
11687 if (who < 0 && who > PROJECTOR_UNUSUAL &&
11688 // if (IS_PVP &&
11689 Players[0 - who]->taciturn_messages)
11690 suppress_message = TRUE;
11691
11692 /* Now hurt the monsters, from inside out */
11693 for (i = 0; i < grids; i++) {
11694 /* Hack -- Notice new "dist" values */
11695 if (gm[dist+1] == i) dist++;
11696
11697 /* Get the grid location */
11698 y = gy[i];
11699 x = gx[i];
11700
11701 /* paranoia */
11702 if (!in_bounds2(wpos, y, x)) continue;
11703
11704 #ifndef PROJ_MON_ON_WALL
11705 /* Walls protect monsters */
11706 // if (!cave_floor_bold(zcave, y, x)) continue;
11707 /* Monsters can be hit on dark pits */
11708 if (!cave_contact(zcave, y, x)) continue;
11709 #else
11710 /* Walls only protect monsters if it's not the very epicenter of the blast. */
11711 if (!cave_contact(zcave, y, x) && y != y2 && x != x2) continue;
11712 #endif
11713
11714 /* Affect the monster */
11715 // if (project_m(0-who, who, y2, x2, dist, wpos, y, x, dam, typ)) notice = TRUE;
11716
11717 if (zcave[y][x].m_idx <= 0) continue;
11718
11719 // if (grids <= 1 && (zcave[y][x].m_idx > 0))
11720 /* if (grids <= 1)
11721 {
11722 monster_type *m_ptr = &m_list[zcave[y][x].m_idx];
11723 monster_race *ref_ptr = race_inf(m_ptr);
11724 monster_race *ref_ptr = race_inf(&m_list[zcave[y][x].m_idx]);
11725 }
11726 */
11727 if ((flg & PROJECT_STAY) || (flg & PROJECT_FULL)) dist = 0;
11728 if (project_m(0 - who, who, y2, x2, dist, wpos, y, x, dam, typ, flg)) notice = TRUE;
11729 }
11730
11731 /* Mega-Hack */
11732 if ((who < 0) && (project_m_n == 1) && (who > PROJECTOR_UNUSUAL))
11733 // if (IS_PVP && project_m_n == 1)
11734 {
11735 /* Location */
11736 x = project_m_x;
11737 y = project_m_y;
11738
11739 /* Still here */
11740 if (who < 0) {
11741 player_type *p_ptr = Players[0 - who];
11742 int m_idx = zcave[y][x].m_idx;
11743
11744 /* Hack - auto-track monster */
11745 if (m_idx > 0) {
11746 if (p_ptr->mon_vis[m_idx]) health_track(0 - who, m_idx);
11747 } else {
11748 if (p_ptr->play_vis[0 - m_idx]) health_track(0 - who, m_idx);
11749 }
11750 }
11751 }
11752
11753 suppress_message = old_tacit;
11754 }
11755
11756 /* Check player */
11757 if (flg & PROJECT_KILL) {
11758 /* Start with "dist" of zero */
11759 dist = 0;
11760
11761 /* Clear the got_hit flags - mikaelh */
11762 for (i = 1; i <= NumPlayers; i++) {
11763 player_type *p_ptr = Players[i];
11764
11765 if (p_ptr->conn == NOT_CONNECTED)
11766 continue;
11767
11768 p_ptr->got_hit = FALSE;
11769 }
11770
11771 /* Now see if the player gets hurt */
11772 for (i = 0; i < grids; i++) {
11773 /* Who is at the location */
11774 int player_idx;
11775
11776 /* Hack -- Notice new "dist" values */
11777 if (gm[dist+1] == i) dist++;
11778
11779 /* Get the grid location */
11780 y = gy[i];
11781 x = gx[i];
11782
11783 /* Set the player index */
11784 /* paranoia */
11785 if (!in_bounds2(wpos, y, x)) continue;
11786
11787 player_idx = 0 - zcave[y][x].m_idx;
11788
11789 /* Affect the player */
11790 if ((flg & PROJECT_STAY) || (flg & PROJECT_FULL)) dist = 0;
11791 if (project_p(player_idx, who, dist, wpos, y, x, dam, typ, rad, flg, attacker)) notice = TRUE;
11792 /* reset stair-goi helper flag (used by project_p()) again */
11793 if (player_idx >= 1 && player_idx <= NumPlayers) Players[player_idx]->invuln_applied = FALSE;
11794 }
11795 }
11796
11797 #ifdef OPTIMIZED_ANIMATIONS
11798 /* Display the "blast area" */
11799 if (!(flg & PROJECT_HIDE))
11800 #ifdef PROJECTION_FLUSH_LIMIT
11801 if (count_project < PROJECTION_FLUSH_LIMIT)
11802 #endif // PROJECTION_FLUSH_LIMIT
11803 {
11804 /* Then do the "blast", from inside out */
11805 for (t = 0; t <= rad; t++) {
11806 /* Reset who can see */
11807 num_can_see = 0;
11808
11809 /* Dump everything with this radius */
11810 for (i = gm[t]; i < gm[t+1]; i++) {
11811 /* Extract the location */
11812 y = gy[i];
11813 x = gx[i];
11814
11815 for (j = 1; j < NumPlayers + 1; j++) {
11816 player_type *p_ptr = Players[j];
11817 int dispy, dispx;
11818 byte attr;
11819 int k;
11820 bool flag = TRUE;
11821
11822 if (p_ptr->conn == NOT_CONNECTED)
11823 continue;
11824
11825 if (!inarea(&p_ptr->wpos, wpos))
11826 continue;
11827
11828 if (p_ptr->blind)
11829 continue;
11830
11831 if (!panel_contains(y, x))
11832 continue;
11833
11834 if (!player_has_los_bold(j, y, x))
11835 continue;
11836
11837 attr = spell_color(typ);
11838
11839 dispx = x - p_ptr->panel_col_prt;
11840 dispy = y - p_ptr->panel_row_prt;
11841
11842 p_ptr->scr_info[dispy][dispx].c = '*';
11843 p_ptr->scr_info[dispy][dispx].a = attr;
11844
11845 Send_char(j, dispx, dispy, attr, '*');
11846
11847 drawn = TRUE;
11848
11849 for (k = 0; k < num_can_see; k++) {
11850 if (who_can_see[k] == j)
11851 flag = FALSE;
11852 }
11853
11854 if (flag)
11855 who_can_see[num_can_see++] = j;
11856 }
11857 }
11858 }
11859
11860 /* Flush the whole thing */
11861 for (j = 0; j < num_can_see; j++) {
11862 /* Show this radius and delay */
11863 Send_flush(who_can_see[j]);
11864 }
11865
11866 /* Flush the erasing */
11867 if (drawn) {
11868 /* Erase the explosion drawn above */
11869 for (i = 0; i < grids; i++) {
11870 /* Extract the location */
11871 y = gy[i];
11872 x = gx[i];
11873
11874 /* Erase a bit later */
11875 everyone_lite_later_spot(wpos, y, x);
11876 }
11877 }
11878 }
11879 #endif
11880
11881 /* Return "something was noticed" */
11882 return (notice);
11883 }
11884
11885 /* Check whether player is actually in an area that offers unusual safety from various
11886 attacks and effects. This is used for special events like Arena Monster Challenge - C. Blue */
11887 int safe_area(int Ind) {
11888 player_type *p_ptr = Players[Ind];
11889 // dungeon_type *d_ptr = getdungeon(&p_ptr->wpos);
11890
11891 /* For 'Arena Monster Challenge' event: */
11892 if (ge_special_sector &&
11893 (p_ptr->wpos.wx == WPOS_ARENA_X && p_ptr->wpos.wy == WPOS_ARENA_Y && p_ptr->wpos.wz == WPOS_ARENA_Z))
11894 return 1;
11895
11896 /* default: usual situation - not safe */
11897 return 0;
11898 }
11899
11900
11901 /* Helper function for monster_is_safe() to determine how damaging a
11902 * projection is and if we should therefore try to move out of it. - C. Blue
11903 * IMPORTANT: Keep in sync with project_m(). */
11904 int approx_damage(int m_idx, int dam, int typ) {
11905 int j = 0, k, k_elec, k_sound, k_lite;
11906
11907 monster_type *m_ptr = &m_list[m_idx];
11908 monster_race *r_ptr = race_inf(m_ptr);
11909 cptr name = r_name_get(m_ptr);
11910
11911 if (dam == 9999 && typ == GF_OLD_DRAIN) dam = 2; /* Priest drain-life spell hack */
11912
11913 #if 0
11914 int do_poly = 0;
11915 int do_dist = 0;
11916 int do_blind = 0;
11917 int do_conf = 0;
11918 int do_stun = 0;
11919 int do_sleep = 0;
11920 // int do_fear = 0;
11921 #endif
11922
11923 bool resist = FALSE;
11924
11925 /* Hack: GF_LIFEHEAL might heal or kill a monster */
11926 if (typ == GF_LIFEHEAL) {
11927 if (r_ptr->flags3 & RF3_UNDEAD) {
11928 typ = GF_HOLY_FIRE;
11929 } else {
11930 typ = GF_OLD_HEAL;
11931 }
11932 }
11933
11934 switch (typ) {
11935 case GF_SILENCE:
11936 if (!((r_ptr->flags4 & RF4_SPELLCASTER_MASK) |
11937 (r_ptr->flags5 & RF5_SPELLCASTER_MASK) |
11938 (r_ptr->flags6 & RF6_SPELLCASTER_MASK) |
11939 (r_ptr->flags0 & RF0_SPELLCASTER_MASK)) ||
11940 (r_ptr->level >= 98 && (r_ptr->flags1 & RF1_UNIQUE)))
11941 dam = 0;
11942 else if ((r_ptr->flags1 & RF1_UNIQUE) ||
11943 (r_ptr->flags2 & RF2_POWERFUL))
11944 dam /= 2;
11945 #if 0 /* 0 => use 'dam' as 'avoidance' factor although there is no real damage here */
11946 dam = 0;
11947 #endif
11948 break;
11949
11950 case GF_PSI:
11951 if ((r_ptr->flags9 & RF9_IM_PSI) || (r_ptr->flags2 & RF2_EMPTY_MIND) ||
11952 (r_ptr->flags3 & RF3_NONLIVING))
11953 {
11954 dam = 0;
11955 break;
11956 } else if (r_ptr->flags9 & RF9_RES_PSI) {
11957 resist = TRUE;
11958 } else if (r_ptr->flags3 & RF3_UNDEAD) {
11959 resist = TRUE;
11960 } else if ((r_ptr->flags2 & RF2_STUPID) ||
11961 ((r_ptr->flags3 & RF3_ANIMAL) && !(r_ptr->flags2 & RF2_CAN_SPEAK))) {
11962 resist = TRUE;
11963 } else if (r_ptr->flags2 & RF2_WEIRD_MIND)
11964 dam = (dam * 3 + 1) / 4;
11965
11966 if ((r_ptr->flags2 & RF2_SMART) && !resist) dam += dam / 2;
11967
11968 if (resist) dam /= 2;
11969 break;
11970
11971 case GF_CHARMIGNORE:
11972 dam = 0;
11973 break;
11974
11975 case GF_EARTHQUAKE:
11976 dam = 0;
11977 break;
11978
11979 case GF_MISSILE:
11980 break;
11981
11982 case GF_ACID:
11983 if (r_ptr->flags3 & RF3_IM_ACID)
11984 dam = 0;
11985 else if (r_ptr->flags9 & RF9_RES_ACID)
11986 dam /= 4;
11987 else if (r_ptr->flags9 & RF9_SUSCEP_ACID)
11988 dam *= 2;
11989 break;
11990
11991 case GF_ELEC:
11992 if (r_ptr->flags3 & RF3_IM_ELEC)
11993 dam = 0;
11994 else if (r_ptr->flags9 & RF9_RES_ELEC)
11995 dam /= 4;
11996 else if (r_ptr->flags9 & RF9_SUSCEP_ELEC)
11997 dam *= 2;
11998 break;
11999
12000 case GF_FIRE:
12001 if (r_ptr->flags3 & RF3_IM_FIRE)
12002 dam = 0;
12003 else if (r_ptr->flags9 & RF9_RES_FIRE)
12004 dam /= 4;
12005 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
12006 dam *= 2;
12007 break;
12008
12009 case GF_COLD:
12010 if (r_ptr->flags3 & RF3_IM_COLD)
12011 dam = 0;
12012 else if (r_ptr->flags9 & RF9_RES_COLD)
12013 dam /= 4;
12014 else if (r_ptr->flags3 & RF3_SUSCEP_COLD)
12015 dam *= 2;
12016 break;
12017
12018 case GF_POIS:
12019 if ((r_ptr->flags3 & RF3_IM_POIS) ||
12020 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
12021 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
12022 dam = 0;
12023 else if (r_ptr->flags9 & RF9_RES_POIS)
12024 dam /= 4;
12025 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
12026 dam *= 2;
12027 break;
12028
12029 case GF_UNBREATH:
12030 // if (magik(15)) do_pois = (10 + randint(11) + r) / (r + 1);
12031 if ((r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
12032 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)) ||
12033 (m_ptr->r_idx == RI_MORGOTH)) /* <- Morgoth */
12034 dam = 0;
12035 // do_pois = 0;
12036 else if (r_ptr->flags3 & RF3_IM_POIS)
12037 dam = (dam * 2) / 4;
12038 else if (r_ptr->flags9 & RF9_RES_POIS)
12039 dam = (dam * 3) / 4;
12040 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
12041 dam = (dam * 3) / 2;
12042 break;
12043
12044 case GF_HELL_FIRE:
12045 if (r_ptr->flags3 & (RF3_GOOD)) {
12046 if (r_ptr->flags3 & RF3_IM_FIRE) {
12047 dam *= 2; dam /= 2;//(randint(4)+3);
12048 } else if (r_ptr->flags9 & RF9_RES_FIRE)
12049 dam = (dam * 3) / 2;
12050 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
12051 dam *= 2;
12052 else
12053 dam *= 2;
12054 } else {
12055 if (r_ptr->flags3 & RF3_IM_FIRE) {
12056 dam *= 2; dam /= 4;//(randint(6)+10);
12057 } else if (r_ptr->flags9 & RF9_RES_FIRE)
12058 dam = (dam * 3) / 4;
12059 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
12060 dam /= 2;
12061 else ;
12062 //dam *= 5; dam /= (randint(3)+4);
12063 }
12064 if (r_ptr->flags3 & (RF3_EVIL)) dam = (dam * 2) / 3;
12065 break;
12066
12067 case GF_HOLY_ORB:
12068 if (r_ptr->flags3 & (RF3_GOOD))
12069 dam = 0;
12070 if (r_ptr->flags3 & RF3_EVIL)
12071 dam *= 2;
12072 break;
12073
12074 case GF_HOLY_FIRE:
12075 if (r_ptr->flags3 & (RF3_GOOD))
12076 dam = 0;
12077 else if (r_ptr->flags3 & (RF3_EVIL)) {
12078 if (r_ptr->flags3 & RF3_IM_FIRE) {
12079 dam *= 2; dam = (dam * 2) / 3;//(randint(4)+3);
12080 } else if (r_ptr->flags9 & RF9_RES_FIRE)
12081 dam = (dam * 6) / 4;
12082 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
12083 dam *= 2;
12084 else
12085 dam *= 2;
12086 } else {
12087 if (r_ptr->flags3 & RF3_IM_FIRE) {
12088 dam *= 2; dam /= 3;//(randint(6)+10);
12089 } else if (r_ptr->flags9 & RF9_RES_FIRE)
12090 dam = (dam * 3) / 4;
12091 else if (r_ptr->flags3 & RF3_SUSCEP_FIRE)
12092 dam /= 2;
12093 else ;
12094 // dam *= 5; dam /= (randint(3)+4);
12095 }
12096 break;
12097
12098 case GF_ARROW:
12099 break;
12100
12101 case GF_PLASMA:
12102 if (r_ptr->flags3 & RF3_IM_FIRE)
12103 dam /= 5;
12104 else if (prefix(name, "Plasma") ||
12105 (r_ptr->flags4 & RF4_BR_PLAS) ||
12106 (r_ptr->flags3 & RF3_RES_PLAS))
12107 dam /= 3;
12108 else if (r_ptr->flags9 & RF9_RES_FIRE)
12109 dam = (dam * 3) / 5;
12110 break;
12111
12112 case GF_NETHER_WEAK:
12113 case GF_NETHER:
12114 if (r_ptr->flags3 & RF3_UNDEAD)
12115 dam = 0;
12116 else if ((r_ptr->flags4 & RF4_BR_NETH) || (r_ptr->flags3 & RF3_RES_NETH))
12117 dam /= 3;
12118 else if (r_ptr->flags3 & RF3_DEMON)
12119 dam /= 2;
12120 #if 0
12121 else if (r_ptr->flags3 & RF3_EVIL)
12122 dam /= 2;
12123 #endif
12124 break;
12125
12126 case GF_WATER:
12127 case GF_VAPOUR:
12128 if (r_ptr->flags9 & RF9_IM_WATER)
12129 dam = 0;
12130 else if (r_ptr->flags7 & RF7_AQUATIC)
12131 dam /= 9;
12132 else if (r_ptr->flags3 & RF3_RES_WATE)
12133 dam /= 4;
12134 break;
12135
12136 case GF_WAVE:
12137 if (r_ptr->flags9 & RF9_IM_WATER)
12138 dam = 0;
12139 else if (r_ptr->flags7 & RF7_AQUATIC)
12140 dam /= 9;
12141 else if (r_ptr->flags3 & RF3_RES_WATE)
12142 dam /= 4;
12143 else
12144 //do_stun = 7;
12145 break;
12146
12147 case GF_CHAOS:
12148 //if (r_ptr->level / 2 < 15) ;//do_poly = TRUE;
12149 //do_conf = 10;
12150 if ((r_ptr->flags4 & RF4_BR_CHAO) || (r_ptr->flags9 & RF9_RES_CHAOS)) {
12151 dam /= 3;
12152 //do_conf = 0;
12153 //do_poly = FALSE;
12154 }
12155 break;
12156
12157 case GF_SHARDS:
12158 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS))
12159 dam /= 3;
12160 break;
12161 case GF_INFERNO:
12162 case GF_DETONATION:
12163 case GF_ROCKET:
12164 {
12165 int res1 = 0, res2 = 0, res3 = 0; //shard,sound,fire
12166 if ((r_ptr->flags4 & (RF4_BR_SHAR)) || (r_ptr->flags9 & RF9_RES_SHARDS))
12167 res1 = 1;
12168 if ((r_ptr->flags4 & RF4_BR_PLAS) || (r_ptr->flags3 & RF3_RES_PLAS) || prefix(name, "Plasma")) {
12169 res2 = res3 = 1;
12170 }
12171 if ((r_ptr->flags4 & (RF4_BR_SOUN)) || (r_ptr->flags9 & RF9_RES_SOUND))
12172 res2 = 1;
12173 if (r_ptr->flags3 & RF3_IM_FIRE)
12174 res3 = 3;
12175 else if (r_ptr->flags9 & RF9_RES_FIRE)
12176 res3 = 1;
12177
12178 switch (res1 + res2 + res3) {
12179 case 0: break;
12180 case 1: case 2:
12181 dam = (dam * 3 + 3) / 4;
12182 // do_cut = 0;
12183 break;
12184 default:
12185 dam /= 2;
12186 break;
12187 }
12188 }
12189 break;
12190
12191 case GF_STUN:
12192 //do_stun = 18;
12193 if (r_ptr->flags9 & RF9_RES_SOUND) ;//do_stun /= 4;
12194 break;
12195
12196 case GF_SOUND:
12197 //do_stun = 18;
12198 if ((r_ptr->flags4 & RF4_BR_SOUN) || (r_ptr->flags9 & RF9_RES_SOUND)) {
12199 dam /= 3;
12200 //do_stun = 0;
12201 }
12202 break;
12203
12204 case GF_CONFUSION:
12205 //do_conf = 18;
12206 if ((r_ptr->flags4 & RF4_BR_CONF) ||
12207 (r_ptr->flags4 & RF4_BR_CHAO) || (r_ptr->flags9 & RF9_RES_CHAOS))
12208 dam /= 3;
12209 else if (r_ptr->flags3 & RF3_NO_CONF)
12210 dam /= 2;
12211 break;
12212
12213 case GF_DISENCHANT:
12214 if ((r_ptr->flags4 & RF4_BR_DISE) ||
12215 prefix(name, "Disen") ||
12216 (r_ptr->flags3 & RF3_RES_DISE))
12217 dam /= 3;
12218 break;
12219
12220 case GF_NEXUS:
12221 if ((r_ptr->flags4 & RF4_BR_NEXU) ||
12222 prefix(name, "Nexus") ||
12223 (r_ptr->flags3 & RF3_RES_NEXU))
12224 dam /= 3;
12225 break;
12226
12227 case GF_FORCE:
12228 //do_stun = 8;
12229 if (r_ptr->flags4 & RF4_BR_WALL) dam /= 3;
12230 break;
12231
12232 case GF_INERTIA:
12233 if (r_ptr->flags4 & RF4_BR_INER) dam /= 3;
12234 break;
12235
12236 case GF_TIME: //Note: Also steals energy!
12237 if ((r_ptr->flags4 & RF4_BR_TIME) || (r_ptr->flags9 & RF9_RES_TIME)
12238 || (r_ptr->flags3 & RF3_DEMON) || (r_ptr->flags3 & RF3_NONLIVING)
12239 || (r_ptr->flags3 & RF3_UNDEAD))
12240 dam /= 3;
12241 break;
12242
12243 case GF_GRAVITY:
12244 {
12245 bool resist_tele = FALSE;
12246 if ((r_ptr->flags3 & RF3_RES_TELE) || (r_ptr->flags9 & RF9_IM_TELE)) {
12247 if ((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags9 & RF9_IM_TELE))
12248 resist_tele = TRUE;
12249 }
12250
12251 if (!resist_tele) ;//do_dist = 10;
12252 else ;//do_dist = 0;
12253
12254 if (r_ptr->flags4 & RF4_BR_GRAV) {
12255 dam /= 3;
12256 //do_dist = 0;
12257 }
12258 break;
12259 }
12260
12261 case GF_MANA:
12262 if (r_ptr->flags9 & RF9_RES_MANA)
12263 dam /= 3;
12264 else if (r_ptr->flags4 & RF4_BR_MANA)
12265 dam /= 2;
12266 break;
12267
12268 case GF_METEOR:
12269 break;
12270
12271 case GF_ICE:
12272 //do_stun = 8;
12273 k = dam;
12274
12275 dam = (k * 3) / 5;/* 60% COLD damage */
12276 if (r_ptr->flags3 & RF3_IM_COLD)
12277 dam = 0;
12278 else if (r_ptr->flags9 & RF9_RES_COLD)
12279 dam /= 4;
12280 else if (r_ptr->flags3 & RF3_SUSCEP_COLD)
12281 dam *= 2;
12282
12283 k = (k * 2) / 5;/* 40% SHARDS damage */
12284 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS))
12285 k /= 3;
12286 dam = dam + k;
12287 break;
12288
12289 case GF_THUNDER:
12290 k_elec = dam / 3; /* 33% ELEC damage */
12291 if (r_ptr->flags3 & RF3_IM_ELEC)
12292 k_elec = 0;
12293 else if (r_ptr->flags9 & RF9_RES_ELEC)
12294 k_elec /= 4;
12295 else if (r_ptr->flags9 & RF9_SUSCEP_ELEC)
12296 k_elec *= 2;
12297
12298 k_sound = dam / 3; /* 33% SOUND damage */
12299 //do_stun = 8;
12300 if ((r_ptr->flags4 & RF4_BR_SOUN) || (r_ptr->flags9 & RF9_RES_SOUND)) {
12301 k_sound /= 3;
12302 //do_stun = 0;
12303 }
12304
12305 k_lite = dam / 3; /* 33% LIGHT damage */
12306 //do_blind = damroll(3, (k_lite / 20)) + 1;
12307 if (r_ptr->d_char == 'A') {
12308 k_lite = 0;
12309 //do_blind = 0;
12310 } else if ((r_ptr->flags4 & RF4_BR_LITE) || (r_ptr->flags9 & RF9_RES_LITE)) {
12311 k_lite /= 4;
12312 //do_blind = 0;
12313 } else if (r_ptr->flags3 & RF3_HURT_LITE) {
12314 k_lite *= 2;
12315 }
12316
12317 dam = k_elec + k_sound + k_lite;
12318 break;
12319
12320 case GF_OLD_DRAIN:
12321 if (m_ptr->hp > 9362)
12322 dam = (m_ptr->hp / 100) * dam;
12323 else if (m_ptr->hp > 936)
12324 dam = ((m_ptr->hp / 10) * dam) / 10;
12325 else
12326 dam = (m_ptr->hp * dam) / 100;
12327
12328 if ((r_ptr->flags3 & RF3_UNDEAD) ||
12329 // (r_ptr->flags3 & RF3_DEMON) ||
12330 (r_ptr->flags3 & RF3_NONLIVING) ||
12331 (r_ptr->flags1 & RF1_UNIQUE) ||
12332 (strchr("Egv", r_ptr->d_char)))
12333 dam = 0;
12334 break;
12335
12336 case GF_ANNIHILATION:
12337 j = dam - 1;
12338 if (m_ptr->hp > 9362)
12339 dam = (m_ptr->hp / 100) * dam;
12340 else if (m_ptr->hp > 936)
12341 dam = ((m_ptr->hp / 10) * dam) / 10;
12342 else
12343 dam = (m_ptr->hp * dam) / 100;
12344
12345 if (dam > j * 200) {
12346 dam = j * 200;
12347 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12348 (r_ptr->flags3 & RF3_UNDEAD) ||
12349 (r_ptr->flags3 & RF3_NONLIVING)) {
12350 dam /= 3;
12351 }
12352 }
12353
12354 if (dam < j * 10 + 100) {
12355 dam = j * 10 + 100;
12356 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12357 (r_ptr->flags3 & RF3_UNDEAD) ||
12358 (r_ptr->flags3 & RF3_NONLIVING)) {
12359 dam /= 3;
12360 }
12361 }
12362
12363 break;
12364
12365 case GF_OLD_POLY:
12366 //do_poly = TRUE;
12367 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12368 (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) / 2 + 10))
12369 ;//do_poly = FALSE;
12370
12371 dam = 0;
12372 break;
12373
12374 case GF_OLD_CLONE:
12375 case GF_OLD_HEAL:
12376 case GF_HERO_MONSTER:
12377 case GF_REMFEAR:
12378 case GF_OLD_SPEED:
12379 dam = 0;
12380 break;
12381
12382 case GF_OLD_SLOW:
12383 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12384 (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) + 10) ||
12385 (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) / 2 + 10) || /* RES_OLD() */
12386 !(m_ptr->mspeed >= 100 && m_ptr->mspeed > m_ptr->speed - 10))
12387 dam = 0;
12388 break;
12389
12390 case GF_OLD_SLEEP:
12391 if (!((r_ptr->flags1 & RF1_UNIQUE) ||
12392 (r_ptr->flags3 & RF3_NO_SLEEP) ||
12393 (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) / 2 + 10))) /* RES_OLD() */
12394 ;//do_sleep = GF_OLD_SLEEP_DUR;
12395 dam = 0;
12396 break;
12397
12398 case GF_OLD_CONF:
12399 //do_conf = damroll(3, (dam / 2)) + 1;
12400 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12401 (r_ptr->flags3 & RF3_NO_CONF) ||
12402 (r_ptr->level > ((dam - 10) < 1 ? 1 : (dam - 10)) / 2 + 10)) /* RES_OLD() */
12403 ;//do_conf = 0;
12404 dam = 0;
12405 break;
12406
12407 case GF_BLIND:
12408 //do_blind = dam;
12409 dam = 0;
12410 break;
12411
12412 case GF_CURSE:
12413 //do_conf = (damroll(3, (dam / 2)) + 1) / 3;
12414 //do_blind = dam / 3;
12415 if ((r_ptr->flags1 & RF1_UNIQUE) ||
12416 (r_ptr->level > ((dam / 3 - 10) < 1 ? 1 : (dam / 3 - 10)) / 2 + 10)) /* RES_OLD */
12417 ;//do_blind = do_conf = 0;
12418 if (r_ptr->flags3 & RF3_NO_CONF) ;//do_conf = 0;
12419 dam /= 3;
12420 break;
12421
12422 case GF_HEALINGCLOUD:
12423 if (!(r_ptr->flags3 & RF3_UNDEAD))
12424 dam = 0;
12425 break;
12426
12427 case GF_WATERPOISON:
12428 k = dam / 2;
12429 if ((r_ptr->flags3 & RF3_IM_POIS) ||
12430 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
12431 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
12432 k = 0;
12433 else if (r_ptr->flags9 & RF9_RES_POIS)
12434 k /= 4;
12435 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
12436 k *= 2;
12437 j = k;
12438
12439 k = dam / 2;
12440 if (r_ptr->flags9 & RF9_IM_WATER)
12441 k = 0;
12442 else if (r_ptr->flags7 & RF7_AQUATIC)
12443 k /= 9;
12444 else if (r_ptr->flags3 & RF3_RES_WATE)
12445 k /= 4;
12446 dam = j + k;
12447 break;
12448
12449 case GF_ICEPOISON:
12450 k = (dam * 3) / 5;
12451 if ((r_ptr->flags4 & RF4_BR_SHAR) || (r_ptr->flags9 & RF9_RES_SHARDS))
12452 k /= 3;
12453 j = k;
12454
12455 k = dam / 5;
12456 if (r_ptr->flags9 & RF9_IM_WATER)
12457 k = 0;
12458 else if (r_ptr->flags7 & RF7_AQUATIC)
12459 k /= 9;
12460 else if (r_ptr->flags3 & RF3_RES_WATE)
12461 k /= 4;
12462 j += k;
12463
12464 k = dam / 5;
12465 if ((r_ptr->flags3 & RF3_IM_POIS) ||
12466 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
12467 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
12468 k = 0;
12469 else if (r_ptr->flags9 & RF9_RES_POIS)
12470 k /= 4;
12471 else if (r_ptr->flags9 & RF9_SUSCEP_POIS)
12472 k *= 2;
12473 dam = j + k;
12474 break;
12475
12476 case GF_LITE_WEAK:
12477 if (!(r_ptr->flags3 & RF3_HURT_LITE))
12478 dam = 0;
12479 break;
12480
12481 case GF_LITE:
12482 //do_blind = damroll(3, (dam / 20)) + 1;
12483
12484 if (r_ptr->d_char == 'A') {
12485 dam = 0;
12486 //do_blind = 0;
12487 } else if ((r_ptr->flags4 & RF4_BR_LITE) || (r_ptr->flags9 & RF9_RES_LITE)) {
12488 dam /= 3;
12489 //do_blind = 0;
12490 } else if (r_ptr->flags3 & RF3_HURT_LITE) {
12491 dam *= 2;
12492 }
12493 break;
12494
12495 case GF_DARK:
12496 //do_blind = damroll(3, (dam / 20)) + 1;
12497 if ((r_ptr->flags4 & RF4_BR_DARK) || (r_ptr->flags9 & RF9_RES_DARK)
12498 || (r_ptr->flags3 & RF3_UNDEAD)) {
12499 dam /= 3;
12500 //do_blind = 0;
12501 }
12502 break;
12503
12504 case GF_KILL_WALL:
12505 if (!(r_ptr->flags3 & RF3_HURT_ROCK))
12506 dam = 0;
12507 break;
12508
12509 case GF_AWAY_UNDEAD:
12510 case GF_AWAY_EVIL:
12511 case GF_AWAY_ALL:
12512 case GF_TURN_UNDEAD:
12513 case GF_TURN_EVIL:
12514 case GF_TURN_ALL:
12515 dam = 0;
12516 break;
12517
12518 case GF_DISP_UNDEAD:
12519 if (!(r_ptr->flags3 & RF3_UNDEAD))
12520 dam = 0;
12521 break;
12522 case GF_DISP_EVIL:
12523 if (!(r_ptr->flags3 & RF3_EVIL))
12524 dam = 0;
12525 break;
12526 case GF_DISP_DEMON:
12527 if (!(r_ptr->flags3 & RF3_DEMON))
12528 dam = 0;
12529 break;
12530 case GF_DISP_ALL:
12531 break;
12532
12533 case GF_NUKE:
12534 if ((r_ptr->flags3 & RF3_IM_POIS) ||
12535 (r_ptr->flags3 & (RF3_NONLIVING)) || (r_ptr->flags3 & (RF3_UNDEAD)) ||
12536 (r_ptr->d_char == 'A') || ((r_ptr->d_char == 'U') && (r_ptr->flags3 & RF3_DEMON)))
12537 dam = 0;
12538 else if (r_ptr->flags9 & (RF9_RES_POIS))
12539 dam /= 3;
12540 break;
12541
12542 case GF_DISINTEGRATE:
12543 if (r_ptr->flags3 & (RF3_HURT_ROCK))
12544 dam *= 2;
12545 if (r_ptr->flags1 & RF1_UNIQUE)
12546 dam >>= 1;
12547 break;
12548
12549 case GF_HOLD:
12550 case GF_DOMINATE:
12551 case GF_TELE_TO:
12552 case GF_HAND_DOOM:
12553 case GF_STASIS:
12554 case GF_DEC_STR:
12555 case GF_DEC_DEX:
12556 case GF_DEC_CON:
12557 case GF_RES_STR:
12558 case GF_RES_DEX:
12559 case GF_RES_CON:
12560 case GF_INC_STR:
12561 case GF_INC_DEX:
12562 case GF_INC_CON:
12563 case GF_AUGMENTATION:
12564 case GF_RUINATION:
12565 default:
12566 /* No damage */
12567 dam = 0;
12568 break;
12569 }
12570
12571 #if 0
12572 /* maybe TODO: */
12573 int do_poly = 0;
12574 int do_dist = 0;
12575 int do_blind = 0;
12576 int do_conf = 0;
12577 int do_stun = 0;
12578 int do_sleep = 0;
12579 // int do_fear = 0;
12580 #endif
12581
12582 return (dam);
12583 }
12584