1 /* source/spells.c: player/creature spells, breaths, wands, scrolls, etc. code
2 
3    Copyright (c) 1989-94 James E. Wilson, Robert A. Koeneke
4 
5    This software may be copied and distributed for educational, research, and
6    not for profit purposes provided that this copyright and statement are
7    included in all such copies. */
8 
9 #ifdef __TURBOC__
10 #include	<stdio.h>
11 #include	<stdlib.h>
12 #endif /* __TURBOC__ */
13 
14 #include "config.h"
15 #include "constant.h"
16 #include "types.h"
17 #include "externs.h"
18 
19 #ifdef USG
20 #ifndef ATARIST_MWC
21 #include <string.h>
22 #endif
23 #else
24 #include <strings.h>
25 #endif
26 
27 #if defined(LINT_ARGS)
28 static void replace_spot(int, int, int);
29 #else
30 static void replace_spot();
31 #endif
32 
33 /* Following are spell procedure/functions			-RAK-	*/
34 /* These routines are commonly used in the scroll, potion, wands, and	 */
35 /* staves routines, and are occasionally called from other areas.	  */
36 /* Now included are creature spells also.		       -RAK    */
37 
monster_name(m_name,m_ptr,r_ptr)38 void monster_name (m_name, m_ptr, r_ptr)
39 char *m_name;
40 monster_type *m_ptr;
41 creature_type *r_ptr;
42 {
43   if (!m_ptr->ml)
44     (void) strcpy (m_name, "It");
45   else
46     (void) sprintf (m_name, "The %s", r_ptr->name);
47 }
48 
lower_monster_name(m_name,m_ptr,r_ptr)49 void lower_monster_name (m_name, m_ptr, r_ptr)
50 char *m_name;
51 monster_type *m_ptr;
52 creature_type *r_ptr;
53 {
54   if (!m_ptr->ml)
55     (void) strcpy (m_name, "it");
56   else
57     (void) sprintf (m_name, "the %s", r_ptr->name);
58 }
59 
60 /* Sleep creatures adjacent to player			-RAK-	*/
sleep_monsters1(y,x)61 int sleep_monsters1(y, x)
62 int y, x;
63 {
64   register int i, j;
65   register cave_type *c_ptr;
66   register monster_type *m_ptr;
67   register creature_type *r_ptr;
68   int sleep;
69   vtype out_val, m_name;
70 
71   sleep = FALSE;
72   for (i = y-1; i <= y+1; i++)
73     for (j = x-1; j <= x+1; j++)
74       {
75 	c_ptr = &cave[i][j];
76 	if (c_ptr->cptr > 1)
77 	  {
78 	    m_ptr = &m_list[c_ptr->cptr];
79 	    r_ptr = &c_list[m_ptr->mptr];
80 
81 	    monster_name (m_name, m_ptr, r_ptr);
82 	    if ((randint(MAX_MONS_LEVEL) < r_ptr->level) ||
83 		(CD_NO_SLEEP & r_ptr->cdefense))
84 	      {
85 		if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP))
86 		  c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP;
87 		(void) sprintf(out_val, "%s is unaffected.", m_name);
88 		msg_print(out_val);
89 	      }
90 	    else
91 	      {
92 		sleep = TRUE;
93 		m_ptr->csleep = 500;
94 		(void) sprintf(out_val, "%s falls asleep.", m_name);
95 		msg_print(out_val);
96 	      }
97 	  }
98       }
99   return(sleep);
100 }
101 
102 /* Detect any treasure on the current panel		-RAK-	*/
detect_treasure()103 int detect_treasure()
104 {
105   register int i, j, detect;
106   register cave_type *c_ptr;
107 
108   detect = FALSE;
109   for (i = panel_row_min; i <= panel_row_max; i++)
110     for (j = panel_col_min; j <= panel_col_max; j++)
111       {
112 	c_ptr = &cave[i][j];
113 	if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval == TV_GOLD) &&
114 	    !test_light(i, j))
115 	  {
116 	    c_ptr->fm = TRUE;
117 	    lite_spot(i, j);
118 	    detect = TRUE;
119 	  }
120       }
121   return(detect);
122 }
123 
124 
125 /* Detect all objects on the current panel		-RAK-	*/
detect_object()126 int detect_object()
127 {
128   register int i, j, detect;
129   register cave_type *c_ptr;
130 
131   detect = FALSE;
132   for (i = panel_row_min; i <= panel_row_max; i++)
133     for (j = panel_col_min; j <= panel_col_max; j++)
134       {
135 	c_ptr = &cave[i][j];
136 	if ((c_ptr->tptr != 0) && (t_list[c_ptr->tptr].tval < TV_MAX_OBJECT)
137 	    && !test_light(i, j))
138 	  {
139 	    c_ptr->fm = TRUE;
140 	    lite_spot(i, j);
141 	    detect = TRUE;
142 	  }
143       }
144   return(detect);
145 }
146 
147 
148 /* Locates and displays traps on current panel		-RAK-	*/
detect_trap()149 int detect_trap()
150 {
151   register int i, j;
152   int detect;
153   register cave_type *c_ptr;
154   register inven_type *t_ptr;
155 
156   detect = FALSE;
157   for (i = panel_row_min; i <= panel_row_max; i++)
158     for (j = panel_col_min; j <= panel_col_max; j++)
159       {
160 	c_ptr = &cave[i][j];
161 	if (c_ptr->tptr != 0)
162 	  if (t_list[c_ptr->tptr].tval == TV_INVIS_TRAP)
163 	    {
164 	      c_ptr->fm = TRUE;
165 	      change_trap(i, j);
166 	      detect = TRUE;
167 	    }
168 	  else if (t_list[c_ptr->tptr].tval == TV_CHEST)
169 	    {
170 	      t_ptr = &t_list[c_ptr->tptr];
171 	      known2(t_ptr);
172 	    }
173       }
174   return(detect);
175 }
176 
177 
178 /* Locates and displays all secret doors on current panel -RAK-	*/
detect_sdoor()179 int detect_sdoor()
180 {
181   register int i, j, detect;
182   register cave_type *c_ptr;
183 
184   detect = FALSE;
185   for (i = panel_row_min; i <= panel_row_max; i++)
186     for (j = panel_col_min; j <= panel_col_max; j++)
187       {
188 	c_ptr = &cave[i][j];
189 	if (c_ptr->tptr != 0)
190 	  /* Secret doors  */
191 	  if (t_list[c_ptr->tptr].tval == TV_SECRET_DOOR)
192 	    {
193 	      c_ptr->fm = TRUE;
194 	      change_trap(i, j);
195 	      detect = TRUE;
196 	    }
197 	/* Staircases	 */
198 	  else if (((t_list[c_ptr->tptr].tval == TV_UP_STAIR) ||
199 		    (t_list[c_ptr->tptr].tval == TV_DOWN_STAIR)) &&
200 		   !c_ptr->fm)
201 	    {
202 	      c_ptr->fm = TRUE;
203 	      lite_spot(i, j);
204 	      detect = TRUE;
205 	    }
206       }
207   return(detect);
208 }
209 
210 
211 /* Locates and displays all invisible creatures on current panel -RAK-*/
detect_invisible()212 int detect_invisible()
213 {
214   register int i, flag;
215   register monster_type *m_ptr;
216 #ifdef ATARIST_MWC
217   int32u holder;
218 #endif
219 
220   flag = FALSE;
221   for (i = mfptr - 1; i >= MIN_MONIX; i--)
222     {
223       m_ptr = &m_list[i];
224       if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
225 #ifdef ATARIST_MWC
226 	  ((holder = CM_INVISIBLE) & c_list[m_ptr->mptr].cmove))
227 #else
228 	  (CM_INVISIBLE & c_list[m_ptr->mptr].cmove))
229 #endif
230 	{
231 	  m_ptr->ml = TRUE;
232 	  /* works correctly even if hallucinating */
233 	  print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
234 		(int)m_ptr->fx);
235 	  flag = TRUE;
236 	}
237     }
238   if (flag)
239     {
240       msg_print("You sense the presence of invisible creatures!");
241       msg_print(CNIL);
242       /* must unlight every monster just lighted */
243       creatures(FALSE);
244     }
245   return(flag);
246 }
247 
248 
249 /* Light an area: 1.  If corridor  light immediate area -RAK-*/
250 /*		  2.  If room  light entire room plus immediate area.     */
light_area(y,x)251 int light_area(y, x)
252 register int y, x;
253 {
254   register int i, j, light;
255 
256   if (py.flags.blind < 1)
257     msg_print("You are surrounded by a white light.");
258   light = TRUE;
259   if (cave[y][x].lr && (dun_level > 0))
260     light_room(y, x);
261   /* Must always light immediate area, because one might be standing on
262      the edge of a room, or next to a destroyed area, etc.  */
263   for (i = y-1; i <= y+1; i++)
264     for (j = x-1; j <=  x+1; j++)
265       {
266 	cave[i][j].pl = TRUE;
267 	lite_spot(i, j);
268       }
269   return(light);
270 }
271 
272 
273 /* Darken an area, opposite of light area		-RAK-	*/
unlight_area(y,x)274 int unlight_area(y, x)
275 int y, x;
276 {
277   register int i, j;
278   int tmp1, tmp2, unlight;
279   int start_row, start_col, end_row, end_col;
280   register cave_type *c_ptr;
281 
282   unlight = FALSE;
283   if (cave[y][x].lr && (dun_level > 0))
284     {
285       tmp1 = (SCREEN_HEIGHT/2);
286       tmp2 = (SCREEN_WIDTH /2);
287       start_row = (y/tmp1)*tmp1 + 1;
288       start_col = (x/tmp2)*tmp2 + 1;
289       end_row = start_row + tmp1 - 1;
290       end_col = start_col + tmp2 - 1;
291       for (i = start_row; i <= end_row; i++)
292 	{
293 	  for (j = start_col; j <= end_col; j++)
294 	    {
295 	      c_ptr = &cave[i][j];
296 	      if (c_ptr->lr && c_ptr->fval <= MAX_CAVE_FLOOR)
297 		{
298 		  c_ptr->pl = FALSE;
299 		  c_ptr->fval = DARK_FLOOR;
300 		  lite_spot (i, j);
301 		  if (!test_light(i, j))
302 		    unlight = TRUE;
303 		}
304 	    }
305 	}
306     }
307   else
308     for (i = y-1; i <= y+1; i++)
309       for (j = x-1; j <= x+1; j++)
310 	{
311 	  c_ptr = &cave[i][j];
312 	  if ((c_ptr->fval == CORR_FLOOR) && c_ptr->pl)
313 	    {
314 	      /* pl could have been set by star-lite wand, etc */
315 	      c_ptr->pl = FALSE;
316 	      unlight = TRUE;
317 	    }
318 	}
319 
320   if (unlight && py.flags.blind <= 0)
321     msg_print("Darkness surrounds you.");
322 
323   return(unlight);
324 }
325 
326 
327 /* Map the current area plus some			-RAK-	*/
map_area()328 void map_area()
329 {
330   register cave_type *c_ptr;
331   register int i7, i8, n, m;
332   int i, j, k, l;
333 
334   i = panel_row_min - randint(10);
335   j = panel_row_max + randint(10);
336   k = panel_col_min - randint(20);
337   l = panel_col_max + randint(20);
338   for (m = i; m <= j; m++)
339     for (n = k; n <= l; n++)
340       if (in_bounds(m, n) && (cave[m][n].fval <= MAX_CAVE_FLOOR))
341 	for (i7 = m-1; i7 <= m+1; i7++)
342 	  for (i8 = n-1; i8 <= n+1; i8++)
343 	    {
344 	      c_ptr = &cave[i7][i8];
345 	      if (c_ptr->fval >= MIN_CAVE_WALL)
346 		c_ptr->pl = TRUE;
347 	      else if ((c_ptr->tptr != 0) &&
348 		       (t_list[c_ptr->tptr].tval >= TV_MIN_VISIBLE) &&
349 		       (t_list[c_ptr->tptr].tval <= TV_MAX_VISIBLE))
350 		c_ptr->fm = TRUE;
351 	    }
352   prt_map();
353 }
354 
355 
356 /* Identify an object					-RAK-	*/
ident_spell()357 int ident_spell()
358 {
359   int item_val;
360   bigvtype out_val, tmp_str;
361   register int ident;
362   register inven_type *i_ptr;
363 
364   ident = FALSE;
365   if (get_item(&item_val, "Item you wish identified?", 0, INVEN_ARRAY_SIZE,
366 	       CNIL, CNIL))
367     {
368       ident = TRUE;
369       identify(&item_val);
370       i_ptr = &inventory[item_val];
371       known2(i_ptr);
372       objdes(tmp_str, i_ptr, TRUE);
373       if (item_val >= INVEN_WIELD)
374 	{
375 	  calc_bonuses();
376 	  (void) sprintf (out_val, "%s: %s", describe_use(item_val), tmp_str);
377 	}
378       else
379 	(void) sprintf(out_val, "%c %s", item_val+97, tmp_str);
380       msg_print(out_val);
381     }
382   return(ident);
383 }
384 
385 
386 /* Get all the monsters on the level pissed off.	-RAK-	*/
aggravate_monster(dis_affect)387 int aggravate_monster (dis_affect)
388 int dis_affect;
389 {
390   register int i, aggravate;
391   register monster_type *m_ptr;
392 
393   aggravate = FALSE;
394   for (i = mfptr - 1; i >= MIN_MONIX; i--)
395     {
396       m_ptr = &m_list[i];
397       m_ptr->csleep = 0;
398       if ((m_ptr->cdis <= dis_affect) && (m_ptr->cspeed < 2))
399 	{
400 	  m_ptr->cspeed++;
401 	  aggravate = TRUE;
402 	}
403     }
404   if (aggravate)
405     msg_print ("You hear a sudden stirring in the distance!");
406   return(aggravate);
407 }
408 
409 
410 /* Surround the fool with traps (chuckle)		-RAK-	*/
trap_creation()411 int trap_creation()
412 {
413   register int i, j, trap;
414   register cave_type *c_ptr;
415 
416   trap = TRUE;
417   for (i = char_row-1; i <= char_row+1; i++)
418     for (j = char_col-1; j <= char_col+1; j++)
419       {
420 	/* Don't put a trap under the player, since this can lead to
421 	   strange situations, e.g. falling through a trap door while
422 	   trying to rest, setting off a falling rock trap and ending
423 	   up under the rock.  */
424 	if (i == char_row && j == char_col)
425 	  continue;
426 	c_ptr = &cave[i][j];
427 	if (c_ptr->fval <= MAX_CAVE_FLOOR)
428 	  {
429 	    if (c_ptr->tptr != 0)
430 	      (void) delete_object(i, j);
431 	    place_trap(i, j, randint(MAX_TRAP)-1);
432 	    /* don't let player gain exp from the newly created traps */
433 	    t_list[c_ptr->tptr].p1 = 0;
434 	    /* open pits are immediately visible, so call lite_spot */
435 	    lite_spot(i, j);
436 	  }
437       }
438   return(trap);
439 }
440 
441 
442 /* Surround the player with doors.			-RAK-	*/
door_creation()443 int door_creation()
444 {
445   register int i, j, door;
446   int k;
447   register cave_type *c_ptr;
448 
449   door = FALSE;
450   for (i = char_row-1; i <= char_row+1; i++)
451     for (j = char_col-1; j <=  char_col+1; j++)
452       if ((i != char_row) || (j != char_col))
453 	{
454 	  c_ptr = &cave[i][j];
455 	  if (c_ptr->fval <= MAX_CAVE_FLOOR)
456 	    {
457 	      door = TRUE;
458 	      if (c_ptr->tptr != 0)
459 		(void) delete_object(i, j);
460 	      k = popt();
461 	      c_ptr->fval = BLOCKED_FLOOR;
462 	      c_ptr->tptr = k;
463 	      invcopy(&t_list[k], OBJ_CLOSED_DOOR);
464 	      lite_spot(i, j);
465 	    }
466 	}
467   return(door);
468 }
469 
470 
471 /* Destroys any adjacent door(s)/trap(s)		-RAK-	*/
td_destroy()472 int td_destroy()
473 {
474   register int i, j, destroy;
475   register cave_type *c_ptr;
476 
477   destroy = FALSE;
478   for (i = char_row-1; i <= char_row+1; i++)
479     for (j = char_col-1; j <= char_col+1; j++)
480       {
481 	c_ptr = &cave[i][j];
482 	if (c_ptr->tptr != 0)
483 	  {
484 	    if (((t_list[c_ptr->tptr].tval >= TV_INVIS_TRAP) &&
485 		 (t_list[c_ptr->tptr].tval <= TV_CLOSED_DOOR) &&
486 		 (t_list[c_ptr->tptr].tval != TV_RUBBLE)) ||
487 		(t_list[c_ptr->tptr].tval == TV_SECRET_DOOR))
488 	      {
489 		if (delete_object(i, j))
490 		  destroy = TRUE;
491 	      }
492 	    else if ((t_list[c_ptr->tptr].tval == TV_CHEST)
493 		     && (t_list[c_ptr->tptr].flags != 0))
494 	      {
495 		/* destroy traps on chest and unlock */
496 		t_list[c_ptr->tptr].flags &= ~(CH_TRAPPED|CH_LOCKED);
497 		t_list[c_ptr->tptr].name2 = SN_UNLOCKED;
498 		msg_print ("You have disarmed the chest.");
499 		known2(&t_list[c_ptr->tptr]);
500 		destroy = TRUE;
501 	      }
502 	  }
503       }
504   return(destroy);
505 }
506 
507 
508 /* Display all creatures on the current panel		-RAK-	*/
detect_monsters()509 int detect_monsters()
510 {
511   register int i, detect;
512   register monster_type *m_ptr;
513 #ifdef ATARIST_MWC
514   int32u holder;
515 #endif
516 
517   detect = FALSE;
518   for (i = mfptr - 1; i >= MIN_MONIX; i--)
519     {
520       m_ptr = &m_list[i];
521       if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
522 #ifdef ATARIST_MWC
523 	  (((holder = CM_INVISIBLE) & c_list[m_ptr->mptr].cmove) == 0))
524 #else
525 	  ((CM_INVISIBLE & c_list[m_ptr->mptr].cmove) == 0))
526 #endif
527 	{
528 	  m_ptr->ml = TRUE;
529 	  /* works correctly even if hallucinating */
530 	  print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
531 		(int)m_ptr->fx);
532 	  detect = TRUE;
533 	}
534     }
535   if (detect)
536     {
537       msg_print("You sense the presence of monsters!");
538       msg_print(CNIL);
539       /* must unlight every monster just lighted */
540       creatures(FALSE);
541     }
542   return(detect);
543 }
544 
545 
546 /* Leave a line of light in given dir, blue light can sometimes	*/
547 /* hurt creatures.				       -RAK-   */
light_line(dir,y,x)548 void light_line(dir, y, x)
549 int dir, y, x;
550 {
551   register int i;
552   register cave_type *c_ptr;
553   register monster_type *m_ptr;
554   register creature_type *r_ptr;
555   int dist, flag;
556   vtype out_val, m_name;
557 
558   dist = -1;
559   flag = FALSE;
560   do
561     {
562       /* put mmove at end because want to light up current spot */
563       dist++;
564       c_ptr = &cave[y][x];
565       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
566 	flag = TRUE;
567       else
568 	{
569 	  if (!c_ptr->pl && !c_ptr->tl)
570 	    {
571 	      /* set pl so that lite_spot will work */
572 	      c_ptr->pl = TRUE;
573 	      if (c_ptr->fval == LIGHT_FLOOR)
574 		{
575 		  if (panel_contains(y, x))
576 		    light_room(y, x);
577 		}
578 	      else
579 		lite_spot(y, x);
580 	    }
581 	  /* set pl in case tl was true above */
582 	  c_ptr->pl = TRUE;
583 	  if (c_ptr->cptr > 1)
584 	    {
585 	      m_ptr = &m_list[c_ptr->cptr];
586 	      r_ptr = &c_list[m_ptr->mptr];
587 	      /* light up and draw monster */
588 	      update_mon ((int)c_ptr->cptr);
589 	      monster_name (m_name, m_ptr, r_ptr);
590 	      if (CD_LIGHT & r_ptr->cdefense)
591 		{
592 		  if (m_ptr->ml)
593 		    c_recall[m_ptr->mptr].r_cdefense |= CD_LIGHT;
594 		  i = mon_take_hit((int)c_ptr->cptr, damroll(2, 8));
595 		  if (i >= 0)
596 		    {
597 		      (void) sprintf(out_val,
598 			     "%s shrivels away in the light!", m_name);
599 		      msg_print(out_val);
600 		      prt_experience();
601 		    }
602 		  else
603 		    {
604 		      (void) sprintf(out_val, "%s cringes from the light!",
605 				     m_name);
606 		      msg_print (out_val);
607 		    }
608 		}
609 	    }
610 	}
611       (void) mmove(dir, &y, &x);
612     }
613   while (!flag);
614 }
615 
616 
617 /* Light line in all directions				-RAK-	*/
starlite(y,x)618 void starlite(y, x)
619 register int y, x;
620 {
621   register int i;
622 
623   if (py.flags.blind < 1)
624     msg_print("The end of the staff bursts into a blue shimmering light.");
625   for (i = 1; i <= 9; i++)
626     if (i != 5)
627       light_line(i, y, x);
628 }
629 
630 
631 /* Disarms all traps/chests in a given direction	-RAK-	*/
disarm_all(dir,y,x)632 int disarm_all(dir, y, x)
633 int dir, y, x;
634 {
635   register cave_type *c_ptr;
636   register inven_type *t_ptr;
637   register int disarm, dist;
638 
639   disarm = FALSE;
640   dist = -1;
641   do
642     {
643       /* put mmove at end, in case standing on a trap */
644       dist++;
645       c_ptr = &cave[y][x];
646       /* note, must continue upto and including the first non open space,
647 	 because secret doors have fval greater than MAX_OPEN_SPACE */
648       if (c_ptr->tptr != 0)
649 	{
650 	  t_ptr = &t_list[c_ptr->tptr];
651 	  if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_VIS_TRAP))
652 	    {
653 	      if (delete_object(y, x))
654 		disarm = TRUE;
655 	    }
656 	  else if (t_ptr->tval == TV_CLOSED_DOOR)
657 	    t_ptr->p1 = 0;  /* Locked or jammed doors become merely closed. */
658 	  else if (t_ptr->tval == TV_SECRET_DOOR)
659 	    {
660 	      c_ptr->fm = TRUE;
661 	      change_trap(y, x);
662 	      disarm = TRUE;
663 	    }
664 	  else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0))
665 	    {
666 	      msg_print("Click!");
667 	      t_ptr->flags &= ~(CH_TRAPPED|CH_LOCKED);
668 	      disarm = TRUE;
669 	      t_ptr->name2 = SN_UNLOCKED;
670 	      known2(t_ptr);
671 	    }
672 	}
673       (void) mmove(dir, &y, &x);
674     }
675   while ((dist <= OBJ_BOLT_RANGE) && c_ptr->fval <= MAX_OPEN_SPACE);
676   return(disarm);
677 }
678 
679 
680 /* Return flags for given type area affect		-RAK-	*/
get_flags(typ,weapon_type,harm_type,destroy)681 void get_flags(typ, weapon_type, harm_type, destroy)
682 int typ;
683 int32u *weapon_type; int *harm_type;
684 int (**destroy)();
685 {
686   switch(typ)
687     {
688     case GF_MAGIC_MISSILE:
689       *weapon_type = 0;
690       *harm_type   = 0;
691       *destroy	   = set_null;
692       break;
693     case GF_LIGHTNING:
694       *weapon_type = CS_BR_LIGHT;
695       *harm_type   = CD_LIGHT;
696       *destroy	   = set_lightning_destroy;
697       break;
698     case GF_POISON_GAS:
699       *weapon_type = CS_BR_GAS;
700       *harm_type   = CD_POISON;
701       *destroy	   = set_null;
702       break;
703     case GF_ACID:
704       *weapon_type = CS_BR_ACID;
705       *harm_type   = CD_ACID;
706       *destroy	   = set_acid_destroy;
707       break;
708     case GF_FROST:
709       *weapon_type = CS_BR_FROST;
710       *harm_type   = CD_FROST;
711       *destroy	   = set_frost_destroy;
712       break;
713     case GF_FIRE:
714       *weapon_type = CS_BR_FIRE;
715       *harm_type   = CD_FIRE;
716       *destroy	   = set_fire_destroy;
717       break;
718     case GF_HOLY_ORB:
719       *weapon_type = 0;
720       *harm_type   = CD_EVIL;
721       *destroy	   = set_null;
722       break;
723     default:
724       msg_print("ERROR in get_flags()\n");
725     }
726 }
727 
728 
729 /* Shoot a bolt in a given direction			-RAK-	*/
fire_bolt(typ,dir,y,x,dam,bolt_typ)730 void fire_bolt(typ, dir, y, x, dam, bolt_typ)
731 int typ, dir, y, x, dam;
732 char *bolt_typ;
733 {
734   int i, oldy, oldx, dist, flag;
735   int32u weapon_type; int harm_type;
736   int (*dummy)();
737   register cave_type *c_ptr;
738   register monster_type *m_ptr;
739   register creature_type *r_ptr;
740   vtype out_val, m_name;
741 
742   flag = FALSE;
743   get_flags(typ, &weapon_type, &harm_type, &dummy);
744   oldy = y;
745   oldx = x;
746   dist = 0;
747   do
748     {
749       (void) mmove(dir, &y, &x);
750       dist++;
751       c_ptr = &cave[y][x];
752       lite_spot(oldy, oldx);
753       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
754 	flag = TRUE;
755       else
756 	{
757 	  if (c_ptr->cptr > 1)
758 	    {
759 	      flag = TRUE;
760 	      m_ptr = &m_list[c_ptr->cptr];
761 	      r_ptr = &c_list[m_ptr->mptr];
762 
763 	      /* light up monster and draw monster, temporarily set
764 		 pl so that update_mon() will work */
765 	      i = c_ptr->pl;
766 	      c_ptr->pl = TRUE;
767 	      update_mon ((int)c_ptr->cptr);
768 	      c_ptr->pl = i;
769 	      /* draw monster and clear previous bolt */
770 	      put_qio();
771 
772 	      lower_monster_name(m_name, m_ptr, r_ptr);
773 	      (void) sprintf(out_val, "The %s strikes %s.", bolt_typ, m_name);
774 	      msg_print(out_val);
775 	      if (harm_type & r_ptr->cdefense)
776 		{
777 		  dam = dam*2;
778 		  if (m_ptr->ml)
779 		    c_recall[m_ptr->mptr].r_cdefense |= harm_type;
780 		}
781 	      else if (weapon_type & r_ptr->spells)
782 		{
783 		  dam = dam / 4;
784 		  if (m_ptr->ml)
785 		    c_recall[m_ptr->mptr].r_spells |= weapon_type;
786 		}
787 	      monster_name(m_name, m_ptr, r_ptr);
788 	      i = mon_take_hit((int)c_ptr->cptr, dam);
789 	      if (i >= 0)
790 		{
791 		  (void) sprintf(out_val, "%s dies in a fit of agony.",
792 				 m_name);
793 		  msg_print(out_val);
794 		  prt_experience();
795 		}
796 	      else if (dam > 0)
797 		{
798 		  (void) sprintf (out_val, "%s screams in agony.", m_name);
799 		  msg_print (out_val);
800 		}
801 	    }
802 	  else if (panel_contains(y, x) && (py.flags.blind < 1))
803 	    {
804 	      print('*', y, x);
805 	      /* show the bolt */
806 	      put_qio();
807 	    }
808 	}
809       oldy = y;
810       oldx = x;
811     }
812   while (!flag);
813 }
814 
815 
816 /* Shoot a ball in a given direction.  Note that balls have an	*/
817 /* area affect.					      -RAK-   */
fire_ball(typ,dir,y,x,dam_hp,descrip)818 void fire_ball(typ, dir, y, x, dam_hp, descrip)
819 int typ, dir, y, x, dam_hp;
820 char *descrip;
821 {
822   register int i, j;
823   int dam, max_dis, thit, tkill, k, tmp;
824   int oldy, oldx, dist, flag, harm_type;
825   int32u weapon_type;
826   int (*destroy)();
827   register cave_type *c_ptr;
828   register monster_type *m_ptr;
829   register creature_type *r_ptr;
830   vtype out_val;
831 
832   thit	 = 0;
833   tkill	 = 0;
834   max_dis = 2;
835   get_flags(typ, &weapon_type, &harm_type, &destroy);
836   flag = FALSE;
837   oldy = y;
838   oldx = x;
839   dist = 0;
840   do
841     {
842       (void) mmove(dir, &y, &x);
843       dist++;
844       lite_spot(oldy, oldx);
845       if (dist > OBJ_BOLT_RANGE)
846 	flag = TRUE;
847       else
848 	{
849 	  c_ptr = &cave[y][x];
850 	  if ((c_ptr->fval >= MIN_CLOSED_SPACE) || (c_ptr->cptr > 1))
851 	    {
852 	      flag = TRUE;
853 	      if (c_ptr->fval >= MIN_CLOSED_SPACE)
854 		{
855 		  y = oldy;
856 		  x = oldx;
857 		}
858 	      /* The ball hits and explodes.		     */
859 	      /* The explosion.			     */
860 	      for (i = y-max_dis; i <= y+max_dis; i++)
861 		for (j = x-max_dis; j <= x+max_dis; j++)
862 		  if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
863 		      && los(y, x, i, j))
864 		    {
865 		      c_ptr = &cave[i][j];
866 		      if ((c_ptr->tptr != 0) &&
867 			  (*destroy)(&t_list[c_ptr->tptr]))
868 			(void) delete_object(i, j);
869 		      if (c_ptr->fval <= MAX_OPEN_SPACE)
870 			{
871 			  if (c_ptr->cptr > 1)
872 			    {
873 			      m_ptr = &m_list[c_ptr->cptr];
874 			      r_ptr = &c_list[m_ptr->mptr];
875 
876 			      /* lite up creature if visible, temp
877 				 set pl so that update_mon works */
878 			      tmp = c_ptr->pl;
879 			      c_ptr->pl = TRUE;
880 			      update_mon((int)c_ptr->cptr);
881 
882 			      thit++;
883 			      dam = dam_hp;
884 			      if (harm_type & r_ptr->cdefense)
885 				{
886 				  dam = dam*2;
887 				  if (m_ptr->ml)
888 				    c_recall[m_ptr->mptr].r_cdefense |=harm_type;
889 				}
890 			      else if (weapon_type & r_ptr->spells)
891 				{
892 				  dam = dam / 4;
893 				  if (m_ptr->ml)
894 				    c_recall[m_ptr->mptr].r_spells |=weapon_type;
895 				}
896 			      dam = (dam/(distance(i, j, y, x)+1));
897 			      k = mon_take_hit((int)c_ptr->cptr, dam);
898 			      if (k >= 0)
899 				tkill++;
900 			      c_ptr->pl = tmp;
901 			    }
902 			  else if (panel_contains(i, j) &&(py.flags.blind < 1))
903 			    print('*', i, j);
904 			}
905 		    }
906 	      /* show ball of whatever */
907 	      put_qio();
908 
909 	      for (i = (y - 2); i <= (y + 2); i++)
910 		for (j = (x - 2); j <= (x + 2); j++)
911 		  if (in_bounds(i, j) && panel_contains(i, j) &&
912 		      (distance(y, x, i, j) <= max_dis))
913 		    lite_spot(i, j);
914 
915 	      /* End  explosion.		     */
916 	      if (thit == 1)
917 		{
918 		  (void) sprintf(out_val,
919 				 "The %s envelops a creature!",
920 				 descrip);
921 		  msg_print(out_val);
922 		}
923 	      else if (thit > 1)
924 		{
925 		  (void) sprintf(out_val,
926 				 "The %s envelops several creatures!",
927 				 descrip);
928 		  msg_print(out_val);
929 		}
930 	      if (tkill == 1)
931 		msg_print("There is a scream of agony!");
932 	      else if (tkill > 1)
933 		msg_print("There are several screams of agony!");
934 	      if (tkill >= 0)
935 		prt_experience();
936 	      /* End ball hitting.		     */
937 	    }
938 	  else if (panel_contains(y, x) && (py.flags.blind < 1))
939 	    {
940 	      print('*', y, x);
941 	      /* show bolt */
942 	      put_qio();
943 	    }
944 	  oldy = y;
945 	  oldx = x;
946 	}
947     }
948   while (!flag);
949 }
950 
951 
952 /* Breath weapon works like a fire_ball, but affects the player. */
953 /* Note the area affect.			      -RAK-   */
breath(typ,y,x,dam_hp,ddesc,monptr)954 void breath(typ, y, x, dam_hp, ddesc, monptr)
955 int typ, y, x, dam_hp;
956 char *ddesc;
957 int monptr;
958 {
959   register int i, j;
960   int dam, max_dis, harm_type;
961   int32u weapon_type;
962   int32u tmp, treas;
963   int (*destroy)();
964   register cave_type *c_ptr;
965   register monster_type *m_ptr;
966   register creature_type *r_ptr;
967 #ifdef ATARIST_MWC
968   int32u holder;
969 #endif
970 
971   max_dis = 2;
972   get_flags(typ, &weapon_type, &harm_type, &destroy);
973   for (i = y-2; i <= y+2; i++)
974     for (j = x-2; j <= x+2; j++)
975       if (in_bounds(i, j) && (distance(y, x, i, j) <= max_dis)
976 	  && los(y, x, i, j))
977 	{
978 	  c_ptr = &cave[i][j];
979 	  if ((c_ptr->tptr != 0) &&
980 	      (*destroy)(&t_list[c_ptr->tptr]))
981 	    (void) delete_object(i, j);
982 	  if (c_ptr->fval <= MAX_OPEN_SPACE)
983 	    {
984 	      /* must test status bit, not py.flags.blind here, flag could have
985 		 been set by a previous monster, but the breath should still
986 		 be visible until the blindness takes effect */
987 	      if (panel_contains(i, j) && !(py.flags.status & PY_BLIND))
988 		print('*', i, j);
989 	      if (c_ptr->cptr > 1)
990 		{
991 		  m_ptr = &m_list[c_ptr->cptr];
992 		  r_ptr = &c_list[m_ptr->mptr];
993 		  dam = dam_hp;
994 		  if (harm_type & r_ptr->cdefense)
995 		    dam = dam*2;
996 		  else if (weapon_type & r_ptr->spells)
997 		    dam = (dam / 4);
998 		  dam = (dam/(distance(i, j, y, x)+1));
999 		  /* can not call mon_take_hit here, since player does not
1000 		     get experience for kill */
1001 		  m_ptr->hp = m_ptr->hp - dam;
1002 		  m_ptr->csleep = 0;
1003 		  if (m_ptr->hp < 0)
1004 		    {
1005 		      treas = monster_death((int)m_ptr->fy, (int)m_ptr->fx,
1006 					    r_ptr->cmove);
1007 		      if (m_ptr->ml)
1008 			{
1009 #ifdef ATARIST_MWC
1010 			  holder = CM_TREASURE;
1011 			  tmp = (c_recall[m_ptr->mptr].r_cmove & holder)
1012 			    >> CM_TR_SHIFT;
1013 			  if (tmp > ((treas & holder) >> CM_TR_SHIFT))
1014 			    treas = (treas & ~holder)|(tmp << CM_TR_SHIFT);
1015 			  c_recall[m_ptr->mptr].r_cmove = treas |
1016 			    (c_recall[m_ptr->mptr].r_cmove & ~holder);
1017 #else
1018 			  tmp = (c_recall[m_ptr->mptr].r_cmove & CM_TREASURE)
1019 			    >> CM_TR_SHIFT;
1020 			  if (tmp > ((treas & CM_TREASURE) >> CM_TR_SHIFT))
1021 			    treas = (treas & ~CM_TREASURE)|(tmp<<CM_TR_SHIFT);
1022 			  c_recall[m_ptr->mptr].r_cmove = treas |
1023 			    (c_recall[m_ptr->mptr].r_cmove & ~CM_TREASURE);
1024 #endif
1025 			}
1026 
1027 		      /* It ate an already processed monster.Handle normally.*/
1028 		      if (monptr < c_ptr->cptr)
1029 			delete_monster((int) c_ptr->cptr);
1030 		      /* If it eats this monster, an already processed monster
1031 			 will take its place, causing all kinds of havoc.
1032 			 Delay the kill a bit. */
1033 		      else
1034 			fix1_delete_monster((int) c_ptr->cptr);
1035 		    }
1036 		}
1037 	      else if (c_ptr->cptr == 1)
1038 		{
1039 		  dam = (dam_hp/(distance(i, j, y, x)+1));
1040 		  /* let's do at least one point of damage */
1041 		  /* prevents randint(0) problem with poison_gas, also */
1042 		  if (dam == 0)
1043 		    dam = 1;
1044 		  switch(typ)
1045 		    {
1046 		    case GF_LIGHTNING: light_dam(dam, ddesc); break;
1047 		    case GF_POISON_GAS: poison_gas(dam, ddesc); break;
1048 		    case GF_ACID: acid_dam(dam, ddesc); break;
1049 		    case GF_FROST: cold_dam(dam, ddesc); break;
1050 		    case GF_FIRE: fire_dam(dam, ddesc); break;
1051 		    }
1052 		}
1053 	    }
1054 	}
1055   /* show the ball of gas */
1056   put_qio();
1057 
1058   for (i = (y - 2); i <= (y + 2); i++)
1059     for (j = (x - 2); j <= (x + 2); j++)
1060       if (in_bounds(i, j) && panel_contains(i, j) &&
1061 	  (distance(y, x, i, j) <= max_dis))
1062 	lite_spot(i, j);
1063 }
1064 
1065 
1066 /* Recharge a wand, staff, or rod.  Sometimes the item breaks. -RAK-*/
recharge(num)1067 int recharge(num)
1068 register int num;
1069 {
1070   int i, j, item_val;
1071   register int res;
1072   register inven_type *i_ptr;
1073 
1074   res = FALSE;
1075   if (!find_range(TV_STAFF, TV_WAND, &i, &j))
1076     msg_print("You have nothing to recharge.");
1077   else if (get_item(&item_val, "Recharge which item?", i, j, CNIL, CNIL))
1078     {
1079       i_ptr = &inventory[item_val];
1080       res = TRUE;
1081       /* recharge I = recharge(20) = 1/6 failure for empty 10th level wand */
1082       /* recharge II = recharge(60) = 1/10 failure for empty 10th level wand*/
1083       /* make it harder to recharge high level, and highly charged wands, note
1084 	 that i can be negative, so check its value before trying to call
1085 	 randint().  */
1086       i = num + 50 - (int)i_ptr->level - i_ptr->p1;
1087       if (i < 19)
1088 	i = 1;	/* Automatic failure.  */
1089       else
1090 	i = randint (i/10);
1091 
1092       if (i == 1)
1093 	{
1094 	  msg_print("There is a bright flash of light.");
1095 	  inven_destroy(item_val);
1096 	}
1097       else
1098 	{
1099 	  num = (num/(i_ptr->level+2)) + 1;
1100 	  i_ptr->p1 += 2 + randint(num);
1101 	  if (known2_p(i_ptr))
1102 	    clear_known2(i_ptr);
1103 	  clear_empty(i_ptr);
1104 	}
1105     }
1106   return(res);
1107 }
1108 
1109 
1110 /* Increase or decrease a creatures hit points		-RAK-	*/
hp_monster(dir,y,x,dam)1111 int hp_monster(dir, y, x, dam)
1112 int dir, y, x, dam;
1113 {
1114   register int i;
1115   int flag, dist, monster;
1116   register cave_type *c_ptr;
1117   register monster_type *m_ptr;
1118   register creature_type *r_ptr;
1119   vtype out_val, m_name;
1120 
1121   monster = FALSE;
1122   flag = FALSE;
1123   dist = 0;
1124   do
1125     {
1126       (void) mmove(dir, &y, &x);
1127       dist++;
1128       c_ptr = &cave[y][x];
1129       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1130 	flag = TRUE;
1131       else if (c_ptr->cptr > 1)
1132 	{
1133 	  flag = TRUE;
1134 	  m_ptr = &m_list[c_ptr->cptr];
1135 	  r_ptr = &c_list[m_ptr->mptr];
1136 	  monster_name (m_name, m_ptr, r_ptr);
1137 	  monster = TRUE;
1138 	  i = mon_take_hit((int)c_ptr->cptr, dam);
1139 	  if (i >= 0)
1140 	    {
1141 	      (void) sprintf(out_val, "%s dies in a fit of agony.", m_name);
1142 	      msg_print(out_val);
1143 	      prt_experience();
1144 	    }
1145 	  else if (dam > 0)
1146 	    {
1147 	      (void) sprintf(out_val, "%s screams in agony.", m_name);
1148 	      msg_print(out_val);
1149 	    }
1150 	}
1151     }
1152   while (!flag);
1153   return(monster);
1154 }
1155 
1156 
1157 /* Drains life; note it must be living.		-RAK-	*/
drain_life(dir,y,x)1158 int drain_life(dir, y, x)
1159 int dir, y, x;
1160 {
1161   register int i;
1162   int flag, dist, drain;
1163   register cave_type *c_ptr;
1164   register monster_type *m_ptr;
1165   register creature_type *r_ptr;
1166   vtype out_val, m_name;
1167 
1168   drain = FALSE;
1169   flag = FALSE;
1170   dist = 0;
1171   do
1172     {
1173       (void) mmove(dir, &y, &x);
1174       dist++;
1175       c_ptr = &cave[y][x];
1176       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1177 	flag = TRUE;
1178       else if (c_ptr->cptr > 1)
1179 	{
1180 	  flag = TRUE;
1181 	  m_ptr = &m_list[c_ptr->cptr];
1182 	  r_ptr = &c_list[m_ptr->mptr];
1183 	  if ((r_ptr->cdefense & CD_UNDEAD) == 0)
1184 	    {
1185 	      drain = TRUE;
1186 	      monster_name (m_name, m_ptr, r_ptr);
1187 	      i = mon_take_hit((int)c_ptr->cptr, 75);
1188 	      if (i >= 0)
1189 		{
1190 		  (void) sprintf(out_val, "%s dies in a fit of agony.",m_name);
1191 		  msg_print(out_val);
1192 		  prt_experience();
1193 		}
1194 	      else
1195 		{
1196 		  (void) sprintf(out_val, "%s screams in agony.", m_name);
1197 		  msg_print(out_val);
1198 		}
1199 	    }
1200 	  else
1201 	    c_recall[m_ptr->mptr].r_cdefense |= CD_UNDEAD;
1202 	}
1203     }
1204   while (!flag);
1205   return(drain);
1206 }
1207 
1208 
1209 /* Increase or decrease a creatures speed		-RAK-	*/
1210 /* NOTE: cannot slow a winning creature (BALROG)		 */
speed_monster(dir,y,x,spd)1211 int speed_monster(dir, y, x, spd)
1212 int dir, y, x, spd;
1213 {
1214   int flag, dist, speed;
1215   register cave_type *c_ptr;
1216   register monster_type *m_ptr;
1217   register creature_type *r_ptr;
1218   vtype out_val, m_name;
1219 
1220   speed = FALSE;
1221   flag = FALSE;
1222   dist = 0;
1223   do
1224     {
1225       (void) mmove(dir, &y, &x);
1226       dist++;
1227       c_ptr = &cave[y][x];
1228       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1229 	flag = TRUE;
1230       else if (c_ptr->cptr > 1)
1231 	{
1232 	  flag = TRUE;
1233 	  m_ptr = &m_list[c_ptr->cptr];
1234 	  r_ptr = &c_list[m_ptr->mptr];
1235 	  monster_name (m_name, m_ptr, r_ptr);
1236 	  if (spd > 0)
1237 	    {
1238 	      m_ptr->cspeed += spd;
1239 	      m_ptr->csleep = 0;
1240 	      (void) sprintf (out_val, "%s starts moving faster.", m_name);
1241 	      msg_print (out_val);
1242 	      speed = TRUE;
1243 	    }
1244 	  else if (randint(MAX_MONS_LEVEL) > r_ptr->level)
1245 	    {
1246 	      m_ptr->cspeed += spd;
1247 	      m_ptr->csleep = 0;
1248 	      (void) sprintf (out_val, "%s starts moving slower.", m_name);
1249 	      msg_print (out_val);
1250 	      speed = TRUE;
1251 	    }
1252 	  else
1253 	    {
1254 	      m_ptr->csleep = 0;
1255 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
1256 	      msg_print(out_val);
1257 	    }
1258 	}
1259     }
1260   while (!flag);
1261   return(speed);
1262 }
1263 
1264 
1265 /* Confuse a creature					-RAK-	*/
confuse_monster(dir,y,x)1266 int confuse_monster(dir, y, x)
1267 int dir, y, x;
1268 {
1269   int flag, dist, confuse;
1270   register cave_type *c_ptr;
1271   register monster_type *m_ptr;
1272   register creature_type *r_ptr;
1273   vtype out_val, m_name;
1274 
1275   confuse = FALSE;
1276   flag = FALSE;
1277   dist = 0;
1278   do
1279     {
1280       (void) mmove(dir, &y, &x);
1281       dist++;
1282       c_ptr = &cave[y][x];
1283       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1284 	flag = TRUE;
1285       else if (c_ptr->cptr > 1)
1286 	{
1287 	  m_ptr = &m_list[c_ptr->cptr];
1288 	  r_ptr = &c_list[m_ptr->mptr];
1289 	  monster_name (m_name, m_ptr, r_ptr);
1290 	  flag = TRUE;
1291 	  if ((randint(MAX_MONS_LEVEL) < r_ptr->level) ||
1292 	      (CD_NO_SLEEP & r_ptr->cdefense))
1293 	    {
1294 	      if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP))
1295 		c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP;
1296 	      /* Monsters which resisted the attack should wake up.
1297 		 Monsters with innate resistence ignore the attack.  */
1298 	      if (! (CD_NO_SLEEP & r_ptr->cdefense))
1299 		m_ptr->csleep = 0;
1300 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
1301 	      msg_print(out_val);
1302 	    }
1303 	  else
1304 	    {
1305 	      if (m_ptr->confused)
1306 		m_ptr->confused += 3;
1307 	      else
1308 		m_ptr->confused = 2 + randint(16);
1309 	      confuse = TRUE;
1310 	      m_ptr->csleep = 0;
1311 	      (void) sprintf(out_val, "%s appears confused.", m_name);
1312 	      msg_print(out_val);
1313 	    }
1314 	}
1315     }
1316   while (!flag);
1317   return(confuse);
1318 }
1319 
1320 
1321 /* Sleep a creature.					-RAK-	*/
sleep_monster(dir,y,x)1322 int sleep_monster(dir, y, x)
1323 int dir, y, x;
1324 {
1325   int flag, dist, sleep;
1326   register cave_type *c_ptr;
1327   register monster_type *m_ptr;
1328   register creature_type *r_ptr;
1329   vtype out_val, m_name;
1330 
1331   sleep = FALSE;
1332   flag = FALSE;
1333   dist = 0;
1334   do
1335     {
1336       (void) mmove(dir, &y, &x);
1337       dist++;
1338       c_ptr = &cave[y][x];
1339       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1340 	flag = TRUE;
1341       else if (c_ptr->cptr > 1)
1342 	{
1343 	  m_ptr = &m_list[c_ptr->cptr];
1344 	  r_ptr = &c_list[m_ptr->mptr];
1345 	  flag = TRUE;
1346 	  monster_name (m_name, m_ptr, r_ptr);
1347 	  if ((randint(MAX_MONS_LEVEL) < r_ptr->level) ||
1348 	      (CD_NO_SLEEP & r_ptr->cdefense))
1349 	    {
1350 	      if (m_ptr->ml && (r_ptr->cdefense & CD_NO_SLEEP))
1351 		c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP;
1352 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
1353 	      msg_print(out_val);
1354 	    }
1355 	  else
1356 	    {
1357 	      m_ptr->csleep = 500;
1358 	      sleep = TRUE;
1359 	      (void) sprintf(out_val, "%s falls asleep.", m_name);
1360 	      msg_print(out_val);
1361 	    }
1362 	}
1363     }
1364   while (!flag);
1365   return(sleep);
1366 }
1367 
1368 
1369 /* Turn stone to mud, delete wall.			-RAK-	*/
wall_to_mud(dir,y,x)1370 int wall_to_mud(dir, y, x)
1371 int dir, y, x;
1372 {
1373   int i, wall, dist;
1374   bigvtype out_val, tmp_str;
1375   register int flag;
1376   register cave_type *c_ptr;
1377   register monster_type *m_ptr;
1378   register creature_type *r_ptr;
1379   vtype m_name;
1380 
1381   wall = FALSE;
1382   flag = FALSE;
1383   dist = 0;
1384   do
1385     {
1386       (void) mmove(dir, &y, &x);
1387       dist++;
1388       c_ptr = &cave[y][x];
1389       /* note, this ray can move through walls as it turns them to mud */
1390       if (dist == OBJ_BOLT_RANGE)
1391 	flag = TRUE;
1392       if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL))
1393 	{
1394 	  flag = TRUE;
1395 	  (void) twall(y, x, 1, 0);
1396 	  if (test_light(y, x))
1397 	    {
1398 	      msg_print("The wall turns into mud.");
1399 	      wall = TRUE;
1400 	    }
1401 	}
1402       else if ((c_ptr->tptr != 0) && (c_ptr->fval >= MIN_CLOSED_SPACE))
1403 	{
1404 	  flag = TRUE;
1405 	  if (panel_contains(y, x) && test_light(y, x))
1406 	    {
1407 	      objdes(tmp_str, &t_list[c_ptr->tptr], FALSE);
1408 	      (void) sprintf(out_val, "The %s turns into mud.", tmp_str);
1409 	      msg_print(out_val);
1410 	      wall = TRUE;
1411 	    }
1412 	  if (t_list[c_ptr->tptr].tval == TV_RUBBLE)
1413 	      {
1414 		(void) delete_object(y, x);
1415 		if (randint(10) == 1)
1416 		  {
1417 		    place_object(y, x, FALSE);
1418 		    if (test_light(y, x))
1419 		      msg_print("You have found something!");
1420 		  }
1421 		lite_spot(y, x);
1422 	      }
1423 	      else (void) delete_object(y, x);
1424 	}
1425       if (c_ptr->cptr > 1)
1426 	{
1427 	  m_ptr = &m_list[c_ptr->cptr];
1428 	  r_ptr = &c_list[m_ptr->mptr];
1429 	  if (CD_STONE & r_ptr->cdefense)
1430 	    {
1431 	      monster_name (m_name, m_ptr, r_ptr);
1432 	      i = mon_take_hit((int)c_ptr->cptr, 100);
1433 	      /* Should get these messages even if the monster is not
1434 		 visible.  */
1435 	      if (i >= 0)
1436 		{
1437 		  c_recall[i].r_cdefense |= CD_STONE;
1438 		  (void) sprintf(out_val, "%s dissolves!", m_name);
1439 		  msg_print(out_val);
1440 		  prt_experience(); /* print msg before calling prt_exp */
1441 		}
1442 	      else
1443 		{
1444 		  c_recall[m_ptr->mptr].r_cdefense |= CD_STONE;
1445 		  (void) sprintf(out_val, "%s grunts in pain!",m_name);
1446 		  msg_print(out_val);
1447 		}
1448 	      flag = TRUE;
1449 	    }
1450 	}
1451     }
1452   while (!flag);
1453   return(wall);
1454 }
1455 
1456 
1457 /* Destroy all traps and doors in a given direction	-RAK-	*/
td_destroy2(dir,y,x)1458 int td_destroy2(dir, y, x)
1459 int dir, y, x;
1460 {
1461   register int destroy2, dist;
1462   register cave_type *c_ptr;
1463   register inven_type *t_ptr;
1464 
1465   destroy2 = FALSE;
1466   dist= 0;
1467   do
1468     {
1469       (void) mmove(dir, &y, &x);
1470       dist++;
1471       c_ptr = &cave[y][x];
1472       /* must move into first closed spot, as it might be a secret door */
1473       if (c_ptr->tptr != 0)
1474 	{
1475 	  t_ptr = &t_list[c_ptr->tptr];
1476 	  if ((t_ptr->tval == TV_INVIS_TRAP) || (t_ptr->tval == TV_CLOSED_DOOR)
1477 	      || (t_ptr->tval == TV_VIS_TRAP) || (t_ptr->tval == TV_OPEN_DOOR)
1478 	      || (t_ptr->tval == TV_SECRET_DOOR))
1479 	    {
1480 	      if (delete_object(y, x))
1481 		{
1482 		  msg_print("There is a bright flash of light!");
1483 		  destroy2 = TRUE;
1484 		}
1485 	    }
1486 	  else if ((t_ptr->tval == TV_CHEST) && (t_ptr->flags != 0))
1487 	    {
1488 	      msg_print("Click!");
1489 	      t_ptr->flags &= ~(CH_TRAPPED|CH_LOCKED);
1490 	      destroy2 = TRUE;
1491 	      t_ptr->name2 = SN_UNLOCKED;
1492 	      known2(t_ptr);
1493 	    }
1494 	}
1495     }
1496   while ((dist <= OBJ_BOLT_RANGE) || c_ptr->fval <= MAX_OPEN_SPACE);
1497   return(destroy2);
1498 }
1499 
1500 
1501 /* Polymorph a monster					-RAK-	*/
1502 /* NOTE: cannot polymorph a winning creature (BALROG)		 */
poly_monster(dir,y,x)1503 int poly_monster(dir, y, x)
1504 int dir, y, x;
1505 {
1506   int dist, flag, poly;
1507   register cave_type *c_ptr;
1508   register creature_type *r_ptr;
1509   register monster_type *m_ptr;
1510   vtype out_val, m_name;
1511 
1512   poly = FALSE;
1513   flag = FALSE;
1514   dist = 0;
1515   do
1516     {
1517       (void) mmove(dir, &y, &x);
1518       dist++;
1519       c_ptr = &cave[y][x];
1520       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1521 	flag = TRUE;
1522       else if (c_ptr->cptr > 1)
1523 	{
1524 	  m_ptr = &m_list[c_ptr->cptr];
1525 	  r_ptr = &c_list[m_ptr->mptr];
1526 	  if (randint(MAX_MONS_LEVEL) > r_ptr->level)
1527 	    {
1528 	      flag = TRUE;
1529 	      delete_monster((int)c_ptr->cptr);
1530 	      /* Place_monster() should always return TRUE here.  */
1531 	      poly = place_monster(y, x,
1532 				   randint(m_level[MAX_MONS_LEVEL]-m_level[0])
1533 				   - 1 + m_level[0], FALSE);
1534 	      /* don't test c_ptr->fm here, only pl/tl */
1535 	      if (poly && panel_contains(y, x) && (c_ptr->tl || c_ptr->pl))
1536 		poly = TRUE;
1537 	    }
1538 	  else
1539 	    {
1540 	      monster_name (m_name, m_ptr, r_ptr);
1541 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
1542 	      msg_print(out_val);
1543 	    }
1544 	}
1545     }
1546   while (!flag);
1547   return(poly);
1548 }
1549 
1550 
1551 /* Create a wall.					-RAK-	*/
build_wall(dir,y,x)1552 int build_wall(dir, y, x)
1553 int dir, y, x;
1554 {
1555   register int i;
1556   int build, damage, dist, flag;
1557   register cave_type *c_ptr;
1558   register monster_type *m_ptr;
1559   register creature_type *r_ptr;
1560   vtype m_name, out_val;
1561 #ifdef ATARIST_MWC
1562   int32u holder;
1563 #endif
1564 
1565   build = FALSE;
1566   dist = 0;
1567   flag = FALSE;
1568   do
1569     {
1570       (void) mmove(dir, &y, &x);
1571       dist++;
1572       c_ptr = &cave[y][x];
1573       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1574 	flag = TRUE;
1575       else
1576 	{
1577 	  if (c_ptr->tptr != 0)
1578 	    (void) delete_object(y, x);
1579 	  if (c_ptr->cptr > 1)
1580 	    {
1581 	      /* stop the wall building */
1582 	      flag = TRUE;
1583 	      m_ptr = &m_list[c_ptr->cptr];
1584 	      r_ptr = &c_list[m_ptr->mptr];
1585 
1586 #ifdef ATARIST_MWC
1587 	      if (!(r_ptr->cmove & (holder = CM_PHASE)))
1588 #else
1589 	      if (!(r_ptr->cmove & CM_PHASE))
1590 #endif
1591 		{
1592 		  /* monster does not move, can't escape the wall */
1593 		  if (r_ptr->cmove & CM_ATTACK_ONLY)
1594 		    damage = 3000; /* this will kill everything */
1595 		  else
1596 		    damage = damroll (4, 8);
1597 
1598 		  monster_name (m_name, m_ptr, r_ptr);
1599 		  (void) sprintf (out_val, "%s wails out in pain!", m_name);
1600 		  msg_print (out_val);
1601 		  i = mon_take_hit((int)c_ptr->cptr, damage);
1602 		  if (i >= 0)
1603 		    {
1604 		      (void) sprintf (out_val, "%s is embedded in the rock.",
1605 				      m_name);
1606 		      msg_print (out_val);
1607 		      prt_experience();
1608 		    }
1609 		}
1610 	      else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X')
1611 		{
1612 		  /* must be an earth elemental or an earth spirit, or a Xorn
1613 		     increase its hit points */
1614 		  m_ptr->hp += damroll(4, 8);
1615 		}
1616 	    }
1617 	  c_ptr->fval  = MAGMA_WALL;
1618 	  c_ptr->fm = FALSE;
1619 	  /* Permanently light this wall if it is lit by player's lamp.  */
1620 	  c_ptr->pl = (c_ptr->tl || c_ptr->pl);
1621 	  lite_spot(y, x);
1622 	  i++;
1623 	  build = TRUE;
1624 	}
1625     }
1626   while (!flag);
1627   return(build);
1628 }
1629 
1630 
1631 /* Replicate a creature					-RAK-	*/
clone_monster(dir,y,x)1632 int clone_monster(dir, y, x)
1633 int dir, y, x;
1634 {
1635   register cave_type *c_ptr;
1636   register int dist, flag;
1637 
1638   dist = 0;
1639   flag = FALSE;
1640   do
1641     {
1642       (void) mmove(dir, &y, &x);
1643       dist++;
1644       c_ptr = &cave[y][x];
1645       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1646 	flag = TRUE;
1647       else if (c_ptr->cptr > 1)
1648 	{
1649 	  m_list[c_ptr->cptr].csleep = 0;
1650 	  /* monptr of 0 is safe here, since can't reach here from creatures */
1651 	  return multiply_monster(y, x, (int)m_list[c_ptr->cptr].mptr, 0);
1652 	}
1653     }
1654   while (!flag);
1655   return(FALSE);
1656 }
1657 
1658 
1659 /* Move the creature record to a new location		-RAK-	*/
teleport_away(monptr,dis)1660 void teleport_away(monptr, dis)
1661 int monptr, dis;
1662 {
1663   register int yn, xn, ctr;
1664   register monster_type *m_ptr;
1665 
1666   m_ptr = &m_list[monptr];
1667   ctr = 0;
1668   do
1669     {
1670       do
1671 	{
1672 	  yn = m_ptr->fy + (randint(2*dis+1) - (dis + 1));
1673 	  xn = m_ptr->fx + (randint(2*dis+1) - (dis + 1));
1674 	}
1675       while (!in_bounds(yn, xn));
1676       ctr++;
1677       if (ctr > 9)
1678 	{
1679 	  ctr = 0;
1680 	  dis += 5;
1681 	}
1682     }
1683   while ((cave[yn][xn].fval >= MIN_CLOSED_SPACE) || (cave[yn][xn].cptr != 0));
1684   move_rec((int)m_ptr->fy, (int)m_ptr->fx, yn, xn);
1685   lite_spot((int)m_ptr->fy, (int)m_ptr->fx);
1686   m_ptr->fy = yn;
1687   m_ptr->fx = xn;
1688   /* this is necessary, because the creature is not currently visible
1689      in its new position */
1690   m_ptr->ml = FALSE;
1691   m_ptr->cdis = distance (char_row, char_col, yn, xn);
1692   update_mon (monptr);
1693 }
1694 
1695 
1696 /* Teleport player to spell casting creature		-RAK-	*/
teleport_to(ny,nx)1697 void teleport_to(ny, nx)
1698 int ny, nx;
1699 {
1700   int dis, ctr, y, x;
1701   register int i, j;
1702   register cave_type *c_ptr;
1703 
1704   dis = 1;
1705   ctr = 0;
1706   do
1707     {
1708       y = ny + (randint(2*dis+1) - (dis + 1));
1709       x = nx + (randint(2*dis+1) - (dis + 1));
1710       ctr++;
1711       if (ctr > 9)
1712 	{
1713 	  ctr = 0;
1714 	  dis++;
1715 	}
1716     }
1717   while (!in_bounds(y, x) || (cave[y][x].fval >= MIN_CLOSED_SPACE)
1718 	 || (cave[y][x].cptr >= 2));
1719   move_rec(char_row, char_col, y, x);
1720   for (i = char_row-1; i <= char_row+1; i++)
1721     for (j = char_col-1; j <= char_col+1; j++)
1722       {
1723 	c_ptr = &cave[i][j];
1724 	c_ptr->tl = FALSE;
1725 	lite_spot(i, j);
1726       }
1727   lite_spot(char_row, char_col);
1728   char_row = y;
1729   char_col = x;
1730   check_view();
1731   /* light creatures */
1732   creatures(FALSE);
1733 }
1734 
1735 
1736 /* Teleport all creatures in a given direction away	-RAK-	*/
teleport_monster(dir,y,x)1737 int teleport_monster(dir, y, x)
1738 int dir, y, x;
1739 {
1740   register int flag, result, dist;
1741   register cave_type *c_ptr;
1742 
1743   flag = FALSE;
1744   result = FALSE;
1745   dist = 0;
1746   do
1747     {
1748       (void) mmove(dir, &y, &x);
1749       dist++;
1750       c_ptr = &cave[y][x];
1751       if ((dist > OBJ_BOLT_RANGE) || c_ptr->fval >= MIN_CLOSED_SPACE)
1752 	flag = TRUE;
1753       else if (c_ptr->cptr > 1)
1754 	{
1755 	  m_list[c_ptr->cptr].csleep = 0; /* wake it up */
1756 	  teleport_away((int)c_ptr->cptr, MAX_SIGHT);
1757 	  result = TRUE;
1758 	}
1759     }
1760   while (!flag);
1761   return(result);
1762 }
1763 
1764 
1765 /* Delete all creatures within max_sight distance	-RAK-	*/
1766 /* NOTE : Winning creatures cannot be genocided			 */
mass_genocide()1767 int mass_genocide()
1768 {
1769   register int i, result;
1770   register monster_type *m_ptr;
1771   register creature_type *r_ptr;
1772 #ifdef ATARIST_MWC
1773   int32u holder;
1774 #endif
1775 
1776   result = FALSE;
1777   for (i = mfptr - 1; i >= MIN_MONIX; i--)
1778     {
1779       m_ptr = &m_list[i];
1780       r_ptr = &c_list[m_ptr->mptr];
1781 #ifdef ATARIST_MWC
1782       if ((m_ptr->cdis <= MAX_SIGHT) &&
1783 	  ((r_ptr->cmove & (holder = CM_WIN)) == 0))
1784 #else
1785       if ((m_ptr->cdis <= MAX_SIGHT) && ((r_ptr->cmove & CM_WIN) == 0))
1786 #endif
1787 	{
1788 	  delete_monster(i);
1789 	  result = TRUE;
1790 	}
1791     }
1792   return(result);
1793 }
1794 
1795 /* Delete all creatures of a given type from level.	-RAK-	*/
1796 /* This does not keep creatures of type from appearing later.	 */
1797 /* NOTE : Winning creatures can not be genocided. */
genocide()1798 int genocide()
1799 {
1800   register int i, killed;
1801   char typ;
1802   register monster_type *m_ptr;
1803   register creature_type *r_ptr;
1804   vtype out_val;
1805 #ifdef ATARIST_MWC
1806   int32u holder;
1807 #endif
1808 
1809   killed = FALSE;
1810   if (get_com("Which type of creature do you wish exterminated?", &typ))
1811     for (i = mfptr - 1; i >= MIN_MONIX; i--)
1812       {
1813 	m_ptr = &m_list[i];
1814 	r_ptr = &c_list[m_ptr->mptr];
1815 	if (typ == c_list[m_ptr->mptr].cchar)
1816 #ifdef ATARIST_MWC
1817 	  if ((r_ptr->cmove & (holder = CM_WIN)) == 0)
1818 #else
1819 	  if ((r_ptr->cmove & CM_WIN) == 0)
1820 #endif
1821 	    {
1822 	      delete_monster(i);
1823 	      killed = TRUE;
1824 	    }
1825 	  else
1826 	    {
1827 	      /* genocide is a powerful spell, so we will let the player
1828 		 know the names of the creatures he did not destroy,
1829 		 this message makes no sense otherwise */
1830 	      (void) sprintf(out_val, "The %s is unaffected.", r_ptr->name);
1831 	      msg_print(out_val);
1832 	    }
1833       }
1834   return(killed);
1835 }
1836 
1837 
1838 /* Change speed of any creature .			-RAK-	*/
1839 /* NOTE: cannot slow a winning creature (BALROG)		 */
speed_monsters(spd)1840 int speed_monsters(spd)
1841 int spd;
1842 {
1843   register int i, speed;
1844   register monster_type *m_ptr;
1845   register creature_type *r_ptr;
1846   vtype out_val, m_name;
1847 
1848   speed = FALSE;
1849   for (i = mfptr - 1; i >= MIN_MONIX; i--)
1850     {
1851       m_ptr = &m_list[i];
1852       r_ptr = &c_list[m_ptr->mptr];
1853       monster_name (m_name, m_ptr, r_ptr);
1854 
1855       if ((m_ptr->cdis > MAX_SIGHT) ||
1856 	  !los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
1857 	/* do nothing */
1858 	;
1859       else if (spd > 0)
1860 	{
1861 	  m_ptr->cspeed += spd;
1862 	  m_ptr->csleep = 0;
1863 	  if (m_ptr->ml)
1864 	    {
1865 	      speed = TRUE;
1866 	      (void) sprintf (out_val, "%s starts moving faster.", m_name);
1867 	      msg_print (out_val);
1868 	    }
1869 	}
1870       else if (randint(MAX_MONS_LEVEL) > r_ptr->level)
1871 	{
1872 	  m_ptr->cspeed += spd;
1873 	  m_ptr->csleep = 0;
1874 	  if (m_ptr->ml)
1875 	    {
1876 	      (void) sprintf (out_val, "%s starts moving slower.", m_name);
1877 	      msg_print (out_val);
1878 	      speed = TRUE;
1879 	    }
1880 	}
1881       else if (m_ptr->ml)
1882 	{
1883 	  m_ptr->csleep = 0;
1884 	  (void) sprintf(out_val, "%s is unaffected.", m_name);
1885 	  msg_print(out_val);
1886 	}
1887     }
1888   return(speed);
1889 }
1890 
1891 
1892 /* Sleep any creature .		-RAK-	*/
sleep_monsters2()1893 int sleep_monsters2()
1894 {
1895   register int i, sleep;
1896   register monster_type *m_ptr;
1897   register creature_type *r_ptr;
1898   vtype out_val, m_name;
1899 
1900   sleep = FALSE;
1901   for (i = mfptr - 1; i >= MIN_MONIX; i--)
1902     {
1903       m_ptr = &m_list[i];
1904       r_ptr = &c_list[m_ptr->mptr];
1905       monster_name (m_name, m_ptr, r_ptr);
1906       if ((m_ptr->cdis > MAX_SIGHT) ||
1907 	  !los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
1908 	/* do nothing */
1909 	;
1910       else if ((randint(MAX_MONS_LEVEL) < r_ptr->level) ||
1911 	  (CD_NO_SLEEP & r_ptr->cdefense))
1912 	{
1913 	  if (m_ptr->ml)
1914 	    {
1915 	      if (r_ptr->cdefense & CD_NO_SLEEP)
1916 		c_recall[m_ptr->mptr].r_cdefense |= CD_NO_SLEEP;
1917 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
1918 	      msg_print(out_val);
1919 	    }
1920 	}
1921       else
1922 	{
1923 	  m_ptr->csleep = 500;
1924 	  if (m_ptr->ml)
1925 	    {
1926 	      (void) sprintf(out_val, "%s falls asleep.", m_name);
1927 	      msg_print(out_val);
1928 	      sleep = TRUE;
1929 	    }
1930 	}
1931     }
1932   return(sleep);
1933 }
1934 
1935 
1936 /* Polymorph any creature that player can see.	-RAK-	*/
1937 /* NOTE: cannot polymorph a winning creature (BALROG)		 */
mass_poly()1938 int mass_poly()
1939 {
1940   register int i;
1941   int y, x, mass;
1942   register monster_type *m_ptr;
1943   register creature_type *r_ptr;
1944 #ifdef ATARIST_MWC
1945   int32u holder;
1946 #endif
1947 
1948   mass = FALSE;
1949   for (i = mfptr - 1; i >= MIN_MONIX; i--)
1950     {
1951       m_ptr = &m_list[i];
1952       if (m_ptr->cdis <= MAX_SIGHT)
1953 	{
1954 	  r_ptr = &c_list[m_ptr->mptr];
1955 #ifdef ATARIST_MWC
1956 	  if ((r_ptr->cmove & (holder = CM_WIN)) == 0)
1957 #else
1958 	  if ((r_ptr->cmove & CM_WIN) == 0)
1959 #endif
1960 	    {
1961 	      y = m_ptr->fy;
1962 	      x = m_ptr->fx;
1963 	      delete_monster(i);
1964 	      /* Place_monster() should always return TRUE here.  */
1965 	      mass = place_monster(y, x,
1966 				   randint(m_level[MAX_MONS_LEVEL]-m_level[0])
1967 				   - 1 + m_level[0], FALSE);
1968 	    }
1969 	}
1970     }
1971   return(mass);
1972 }
1973 
1974 
1975 /* Display evil creatures on current panel		-RAK-	*/
detect_evil()1976 int detect_evil()
1977 {
1978   register int i, flag;
1979   register monster_type *m_ptr;
1980 
1981   flag = FALSE;
1982   for (i = mfptr - 1; i >= MIN_MONIX; i--)
1983     {
1984       m_ptr = &m_list[i];
1985       if (panel_contains((int)m_ptr->fy, (int)m_ptr->fx) &&
1986 	  (CD_EVIL & c_list[m_ptr->mptr].cdefense))
1987 	{
1988 	  m_ptr->ml = TRUE;
1989 	  /* works correctly even if hallucinating */
1990 	  print((char)c_list[m_ptr->mptr].cchar, (int)m_ptr->fy,
1991 		(int)m_ptr->fx);
1992 	  flag = TRUE;
1993 	}
1994     }
1995   if (flag)
1996     {
1997       msg_print("You sense the presence of evil!");
1998       msg_print(CNIL);
1999       /* must unlight every monster just lighted */
2000       creatures(FALSE);
2001     }
2002   return(flag);
2003 }
2004 
2005 
2006 /* Change players hit points in some manner		-RAK-	*/
hp_player(num)2007 int hp_player(num)
2008 int num;
2009 {
2010   register int res;
2011   register struct misc *m_ptr;
2012 
2013   res = FALSE;
2014   m_ptr = &py.misc;
2015   if (m_ptr->chp < m_ptr->mhp)
2016     {
2017       m_ptr->chp += num;
2018       if (m_ptr->chp > m_ptr->mhp)
2019 	{
2020 	  m_ptr->chp = m_ptr->mhp;
2021 	  m_ptr->chp_frac = 0;
2022 	}
2023       prt_chp();
2024 
2025       num = num / 5;
2026       if (num < 3) {
2027 	if (num == 0) msg_print("You feel a little better.");
2028 	else	      msg_print("You feel better.");
2029       } else {
2030 	if (num < 7) msg_print("You feel much better.");
2031 	else	     msg_print("You feel very good.");
2032       }
2033       res = TRUE;
2034     }
2035   return(res);
2036 }
2037 
2038 
2039 /* Cure players confusion				-RAK-	*/
cure_confusion()2040 int cure_confusion()
2041 {
2042   register int cure;
2043   register struct flags *f_ptr;
2044 
2045   cure = FALSE;
2046   f_ptr = &py.flags;
2047   if (f_ptr->confused > 1)
2048     {
2049       f_ptr->confused = 1;
2050       cure = TRUE;
2051     }
2052   return(cure);
2053 }
2054 
2055 
2056 /* Cure players blindness				-RAK-	*/
cure_blindness()2057 int cure_blindness()
2058 {
2059   register int cure;
2060   register struct flags *f_ptr;
2061 
2062   cure = FALSE;
2063   f_ptr = &py.flags;
2064   if (f_ptr->blind > 1)
2065     {
2066       f_ptr->blind = 1;
2067       cure = TRUE;
2068     }
2069   return(cure);
2070 }
2071 
2072 
2073 /* Cure poisoning					-RAK-	*/
cure_poison()2074 int cure_poison()
2075 {
2076   register int cure;
2077   register struct flags *f_ptr;
2078 
2079   cure = FALSE;
2080   f_ptr = &py.flags;
2081   if (f_ptr->poisoned > 1)
2082     {
2083       f_ptr->poisoned = 1;
2084       cure = TRUE;
2085     }
2086   return(cure);
2087 }
2088 
2089 
2090 /* Cure the players fear				-RAK-	*/
remove_fear()2091 int remove_fear()
2092 {
2093   register int result;
2094   register struct flags *f_ptr;
2095 
2096   result = FALSE;
2097   f_ptr = &py.flags;
2098   if (f_ptr->afraid > 1)
2099     {
2100       f_ptr->afraid = 1;
2101       result = TRUE;
2102     }
2103   return(result);
2104 }
2105 
2106 
2107 /* This is a fun one.  In a given block, pick some walls and	*/
2108 /* turn them into open spots.  Pick some open spots and turn	 */
2109 /* them into walls.  An "Earthquake" effect.	       -RAK-   */
earthquake()2110 void earthquake()
2111 {
2112   register int i, j;
2113   register cave_type *c_ptr;
2114   register monster_type *m_ptr;
2115   register creature_type *r_ptr;
2116   int damage, tmp;
2117   vtype out_val, m_name;
2118 #ifdef ATARIST_MWC
2119   int32u holder;
2120 #endif
2121 
2122   for (i = char_row-8; i <= char_row+8; i++)
2123     for (j = char_col-8; j <= char_col+8; j++)
2124       if (((i != char_row) || (j != char_col)) &&
2125 	  in_bounds(i, j) && (randint(8) == 1))
2126 	{
2127 	  c_ptr = &cave[i][j];
2128 	  if (c_ptr->tptr != 0)
2129 	    (void) delete_object(i, j);
2130 	  if (c_ptr->cptr > 1)
2131 	    {
2132 	      m_ptr = &m_list[c_ptr->cptr];
2133 	      r_ptr = &c_list[m_ptr->mptr];
2134 
2135 #ifdef ATARIST_MWC
2136 	      if (!(r_ptr->cmove & (holder = CM_PHASE)))
2137 #else
2138 	      if (!(r_ptr->cmove & CM_PHASE))
2139 #endif
2140 		{
2141 		  if(r_ptr->cmove & CM_ATTACK_ONLY)
2142 		    damage = 3000; /* this will kill everything */
2143 		  else
2144 		    damage = damroll (4, 8);
2145 
2146 		  monster_name (m_name, m_ptr, r_ptr);
2147 		  (void) sprintf (out_val, "%s wails out in pain!", m_name);
2148 		  msg_print (out_val);
2149 		  i = mon_take_hit((int)c_ptr->cptr, damage);
2150 		  if (i >= 0)
2151 		    {
2152 		      (void) sprintf (out_val, "%s is embedded in the rock.",
2153 				      m_name);
2154 		      msg_print (out_val);
2155 		      prt_experience();
2156 		    }
2157 		}
2158 	      else if (r_ptr->cchar == 'E' || r_ptr->cchar == 'X')
2159 		{
2160 		  /* must be an earth elemental or an earth spirit, or a Xorn
2161 		     increase its hit points */
2162 		  m_ptr->hp += damroll(4, 8);
2163 		}
2164 	    }
2165 
2166 	  if ((c_ptr->fval >= MIN_CAVE_WALL) && (c_ptr->fval != BOUNDARY_WALL))
2167 	    {
2168 	      c_ptr->fval  = CORR_FLOOR;
2169 	      c_ptr->pl = FALSE;
2170 	      c_ptr->fm = FALSE;
2171 	    }
2172 	  else if (c_ptr->fval <= MAX_CAVE_FLOOR)
2173 	    {
2174 	      tmp = randint(10);
2175 	      if (tmp < 6)
2176 		c_ptr->fval  = QUARTZ_WALL;
2177 	      else if (tmp < 9)
2178 		c_ptr->fval  = MAGMA_WALL;
2179 	      else
2180 		c_ptr->fval  = GRANITE_WALL;
2181 
2182 	      c_ptr->fm = FALSE;
2183 	    }
2184 	  lite_spot(i, j);
2185 	}
2186 }
2187 
2188 
2189 /* Evil creatures don't like this.		       -RAK-   */
protect_evil()2190 int protect_evil()
2191 {
2192   register int res;
2193   register struct flags *f_ptr;
2194 
2195   f_ptr = &py.flags;
2196   if (f_ptr->protevil == 0)
2197     res = TRUE;
2198   else
2199     res = FALSE;
2200   f_ptr->protevil += randint(25) + 3*py.misc.lev;
2201   return(res);
2202 }
2203 
2204 
2205 /* Create some high quality mush for the player.	-RAK-	*/
create_food()2206 void create_food()
2207 {
2208   register cave_type *c_ptr;
2209 
2210   c_ptr = &cave[char_row][char_col];
2211   if (c_ptr->tptr != 0)
2212     {
2213       /* take no action here, don't want to destroy object under player */
2214       msg_print ("There is already an object under you.");
2215       /* set free_turn_flag so that scroll/spell points won't be used */
2216       free_turn_flag = TRUE;
2217     }
2218   else
2219     {
2220       place_object(char_row, char_col, FALSE);
2221       invcopy(&t_list[c_ptr->tptr], OBJ_MUSH);
2222     }
2223 }
2224 
2225 
2226 /* Attempts to destroy a type of creature.  Success depends on	*/
2227 /* the creatures level VS. the player's level		 -RAK-	 */
dispel_creature(cflag,damage)2228 int dispel_creature(cflag, damage)
2229 int cflag;
2230 int damage;
2231 {
2232   register int i;
2233   int k, dispel;
2234   register monster_type *m_ptr;
2235   register creature_type *r_ptr;
2236   vtype out_val, m_name;
2237 
2238   dispel = FALSE;
2239   for (i = mfptr - 1; i >= MIN_MONIX; i--)
2240     {
2241       m_ptr = &m_list[i];
2242       if ((m_ptr->cdis <= MAX_SIGHT) &&
2243 	  (cflag & c_list[m_ptr->mptr].cdefense) &&
2244 	  los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx))
2245 	{
2246 	  r_ptr = &c_list[m_ptr->mptr];
2247 	  c_recall[m_ptr->mptr].r_cdefense |= cflag;
2248 	  monster_name (m_name, m_ptr, r_ptr);
2249 	  k = mon_take_hit (i, randint(damage));
2250 	  /* Should get these messages even if the monster is not
2251 	     visible.  */
2252 	  if (k >= 0)
2253 	    (void) sprintf(out_val, "%s dissolves!", m_name);
2254 	  else
2255 	    (void) sprintf(out_val, "%s shudders.", m_name);
2256 	  msg_print(out_val);
2257 	  dispel = TRUE;
2258 	  if (k >= 0)
2259 	    prt_experience();
2260 	}
2261     }
2262   return(dispel);
2263 }
2264 
2265 
2266 /* Attempt to turn (confuse) undead creatures.	-RAK-	*/
turn_undead()2267 int turn_undead()
2268 {
2269   register int i, turn_und;
2270   register monster_type *m_ptr;
2271   register creature_type *r_ptr;
2272   vtype out_val, m_name;
2273 
2274   turn_und = FALSE;
2275   for (i = mfptr - 1; i >= MIN_MONIX; i--)
2276     {
2277       m_ptr = &m_list[i];
2278       r_ptr = &c_list[m_ptr->mptr];
2279       if ((m_ptr->cdis <= MAX_SIGHT) &&
2280 	  (CD_UNDEAD & r_ptr->cdefense) &&
2281 	  (los(char_row, char_col, (int)m_ptr->fy, (int)m_ptr->fx)))
2282 	{
2283 	  monster_name (m_name, m_ptr, r_ptr);
2284 	  if (((py.misc.lev+1) > r_ptr->level) ||
2285 	      (randint(5) == 1))
2286 	    {
2287 	      if (m_ptr->ml)
2288 		{
2289 		  (void) sprintf(out_val, "%s runs frantically!", m_name);
2290 		  msg_print(out_val);
2291 		  turn_und = TRUE;
2292 		  c_recall[m_ptr->mptr].r_cdefense |= CD_UNDEAD;
2293 		}
2294 	      m_ptr->confused = py.misc.lev;
2295 	    }
2296 	  else if (m_ptr->ml)
2297 	    {
2298 	      (void) sprintf(out_val, "%s is unaffected.", m_name);
2299 	      msg_print(out_val);
2300 	    }
2301 	}
2302     }
2303   return(turn_und);
2304 }
2305 
2306 
2307 /* Leave a glyph of warding. Creatures will not pass over! -RAK-*/
warding_glyph()2308 void warding_glyph()
2309 {
2310   register int i;
2311   register cave_type *c_ptr;
2312 
2313   c_ptr = &cave[char_row][char_col];
2314   if (c_ptr->tptr == 0)
2315     {
2316       i = popt();
2317       c_ptr->tptr = i;
2318       invcopy(&t_list[i], OBJ_SCARE_MON);
2319     }
2320 }
2321 
2322 
2323 /* Lose a strength point.				-RAK-	*/
lose_str()2324 void lose_str()
2325 {
2326   if (!py.flags.sustain_str)
2327     {
2328       (void) dec_stat (A_STR);
2329       msg_print("You feel very sick.");
2330     }
2331   else
2332     msg_print("You feel sick for a moment,  it passes.");
2333 }
2334 
2335 
2336 /* Lose an intelligence point.				-RAK-	*/
lose_int()2337 void lose_int()
2338 {
2339   if (!py.flags.sustain_int)
2340     {
2341       (void) dec_stat(A_INT);
2342       msg_print("You become very dizzy.");
2343     }
2344   else
2345     msg_print("You become dizzy for a moment,  it passes.");
2346 }
2347 
2348 
2349 /* Lose a wisdom point.					-RAK-	*/
lose_wis()2350 void lose_wis()
2351 {
2352   if (!py.flags.sustain_wis)
2353     {
2354       (void) dec_stat(A_WIS);
2355       msg_print("You feel very naive.");
2356     }
2357   else
2358     msg_print("You feel naive for a moment,  it passes.");
2359 }
2360 
2361 
2362 /* Lose a dexterity point.				-RAK-	*/
lose_dex()2363 void lose_dex()
2364 {
2365   if (!py.flags.sustain_dex)
2366     {
2367       (void) dec_stat(A_DEX);
2368       msg_print("You feel very sore.");
2369     }
2370   else
2371     msg_print("You feel sore for a moment,  it passes.");
2372 }
2373 
2374 
2375 /* Lose a constitution point.				-RAK-	*/
lose_con()2376 void lose_con()
2377 {
2378   if (!py.flags.sustain_con)
2379     {
2380       (void) dec_stat(A_CON);
2381       msg_print("You feel very sick.");
2382     }
2383   else
2384     msg_print("You feel sick for a moment,  it passes.");
2385 }
2386 
2387 
2388 /* Lose a charisma point.				-RAK-	*/
lose_chr()2389 void lose_chr()
2390 {
2391   if (!py.flags.sustain_chr)
2392     {
2393       (void) dec_stat(A_CHR);
2394       msg_print("Your skin starts to itch.");
2395     }
2396   else
2397     msg_print("Your skin starts to itch, but feels better now.");
2398 }
2399 
2400 
2401 /* Lose experience					-RAK-	*/
lose_exp(amount)2402 void lose_exp(amount)
2403 int32 amount;
2404 {
2405   register int i;
2406   register struct misc *m_ptr;
2407   register class_type *c_ptr;
2408 
2409   m_ptr = &py.misc;
2410   if (amount > m_ptr->exp)
2411     m_ptr->exp = 0;
2412   else
2413     m_ptr->exp -= amount;
2414   prt_experience();
2415 
2416   i = 0;
2417   while ((player_exp[i] * m_ptr->expfact / 100) <= m_ptr->exp)
2418     i++;
2419   /* increment i once more, because level 1 exp is stored in player_exp[0] */
2420   i++;
2421 
2422   if (m_ptr->lev != i)
2423     {
2424       m_ptr->lev = i;
2425 
2426       calc_hitpoints();
2427       c_ptr = &class[m_ptr->pclass];
2428       if (c_ptr->spell == MAGE)
2429 	{
2430 	  calc_spells(A_INT);
2431 	  calc_mana(A_INT);
2432 	}
2433       else if (c_ptr->spell == PRIEST)
2434 	{
2435 	  calc_spells(A_WIS);
2436 	  calc_mana(A_WIS);
2437 	}
2438       prt_level();
2439       prt_title();
2440     }
2441 }
2442 
2443 
2444 /* Slow Poison						-RAK-	*/
slow_poison()2445 int slow_poison()
2446 {
2447   register int slow;
2448   register struct flags *f_ptr;
2449 
2450   slow = FALSE;
2451   f_ptr = &py.flags;
2452   if (f_ptr->poisoned > 0)
2453     {
2454       f_ptr->poisoned = f_ptr->poisoned / 2;
2455       if (f_ptr->poisoned < 1)	f_ptr->poisoned = 1;
2456       slow = TRUE;
2457       msg_print("The effect of the poison has been reduced.");
2458     }
2459   return(slow);
2460 }
2461 
2462 
2463 /* Bless						-RAK-	*/
bless(amount)2464 void bless(amount)
2465 int amount;
2466 {
2467   py.flags.blessed += amount;
2468 }
2469 
2470 
2471 /* Detect Invisible for period of time			-RAK-	*/
detect_inv2(amount)2472 void detect_inv2(amount)
2473 int amount;
2474 {
2475   py.flags.detect_inv += amount;
2476 }
2477 
2478 
replace_spot(y,x,typ)2479 static void replace_spot(y, x, typ)
2480 int y, x, typ;
2481 {
2482   register cave_type *c_ptr;
2483 
2484   c_ptr = &cave[y][x];
2485   switch(typ)
2486     {
2487     case 1: case 2: case 3:
2488       c_ptr->fval  = CORR_FLOOR;
2489       break;
2490     case 4: case 7: case 10:
2491       c_ptr->fval  = GRANITE_WALL;
2492       break;
2493     case 5: case 8: case 11:
2494       c_ptr->fval  = MAGMA_WALL;
2495       break;
2496     case 6: case 9: case 12:
2497       c_ptr->fval  = QUARTZ_WALL;
2498       break;
2499     }
2500   c_ptr->pl = FALSE;
2501   c_ptr->fm = FALSE;
2502   c_ptr->lr = FALSE;  /* this is no longer part of a room */
2503   if (c_ptr->tptr != 0)
2504     (void) delete_object(y, x);
2505   if (c_ptr->cptr > 1)
2506     delete_monster((int)c_ptr->cptr);
2507 }
2508 
2509 
2510 /* The spell of destruction.				-RAK-	*/
2511 /* NOTE : Winning creatures that are deleted will be considered	 */
2512 /*	  as teleporting to another level.  This will NOT win the*/
2513 /*	  game.						       */
destroy_area(y,x)2514 void destroy_area(y, x)
2515 register int y, x;
2516 {
2517   register int i, j, k;
2518 
2519   if (dun_level > 0)
2520     {
2521       for (i = (y-15); i <= (y+15); i++)
2522 	for (j = (x-15); j <= (x+15); j++)
2523 	  if (in_bounds(i, j) && (cave[i][j].fval != BOUNDARY_WALL))
2524 	    {
2525 	      k = distance(i, j, y, x);
2526 	      if (k == 0) /* clear player's spot, but don't put wall there */
2527 		replace_spot(i, j, 1);
2528 	      else if (k < 13)
2529 		replace_spot(i, j, randint(6));
2530 	      else if (k < 16)
2531 		replace_spot(i, j, randint(9));
2532 	    }
2533     }
2534   msg_print("There is a searing blast of light!");
2535   py.flags.blind += 10 + randint(10);
2536 }
2537 
2538 
2539 /* Enchants a plus onto an item.			-RAK-	*/
enchant(plusses,limit)2540 int enchant(plusses, limit)
2541 int16 *plusses;
2542 int16 limit; /* maximum bonus allowed; usually 10, but weapon's maximum damage
2543 		when enchanting melee weapons to damage */
2544 {
2545   register int chance, res;
2546 
2547   if (limit <= 0) /* avoid randint(0) call */
2548     return(FALSE);
2549   chance = 0;
2550   res = FALSE;
2551   if (*plusses > 0)
2552     {
2553       chance = *plusses;
2554       if (randint(100) == 1) /* very rarely allow enchantment over limit */
2555 	chance = randint(chance) - 1;
2556     }
2557   if (randint(limit) > chance)
2558     {
2559       *plusses += 1;
2560       res = TRUE;
2561     }
2562   return(res);
2563 }
2564 
2565 
2566 /* Removes curses from items in inventory		-RAK-	*/
remove_curse()2567 int remove_curse()
2568 {
2569   register int i, result;
2570   register inven_type *i_ptr;
2571 #ifdef ATARIST_MWC
2572   int32u holder = TR_CURSED;
2573 #endif
2574 
2575   result = FALSE;
2576   for (i = INVEN_WIELD; i <= INVEN_OUTER; i++)
2577     {
2578       i_ptr = &inventory[i];
2579 #ifdef ATARIST_MWC
2580       if (holder & i_ptr->flags)
2581 #else
2582       if (TR_CURSED & i_ptr->flags)
2583 #endif
2584 	{
2585 #ifdef ATARIST_MWC
2586 	  i_ptr->flags &= ~holder;
2587 #else
2588 	  i_ptr->flags &= ~TR_CURSED;
2589 #endif
2590 	  calc_bonuses();
2591 	  result = TRUE;
2592 	}
2593     }
2594   return(result);
2595 }
2596 
2597 
2598 /* Restores any drained experience			-RAK-	*/
restore_level()2599 int restore_level()
2600 {
2601   register int restore;
2602   register struct misc *m_ptr;
2603 
2604   restore = FALSE;
2605   m_ptr = &py.misc;
2606   if (m_ptr->max_exp > m_ptr->exp)
2607     {
2608       restore = TRUE;
2609       msg_print("You feel your life energies returning.");
2610       /* this while loop is not redundant, ptr_exp may reduce the exp level */
2611       while (m_ptr->exp < m_ptr->max_exp)
2612 	{
2613 	  m_ptr->exp = m_ptr->max_exp;
2614 	  prt_experience();
2615 	}
2616     }
2617   return(restore);
2618 }
2619