1 /**
2  * \file effects.c
3  * \brief Handler and auxiliary functions for every effect in the game
4  *
5  * Copyright (c) 2007 Andi Sidwell
6  * Copyright (c) 2016 Ben Semmler, Nick McConnell
7  *
8  * This work is free software; you can redistribute it and/or modify it
9  * under the terms of either:
10  *
11  * a) the GNU General Public License as published by the Free Software
12  *    Foundation, version 2, or
13  *
14  * b) the "Angband licence":
15  *    This software may be copied and distributed for educational, research,
16  *    and not for profit purposes provided that this copyright and statement
17  *    are included in all such copies.  Other copyrights may also apply.
18  */
19 
20 #include "angband.h"
21 #include "cave.h"
22 #include "effects.h"
23 #include "game-input.h"
24 #include "generate.h"
25 #include "init.h"
26 #include "mon-desc.h"
27 #include "mon-lore.h"
28 #include "mon-make.h"
29 #include "mon-msg.h"
30 #include "mon-predicate.h"
31 #include "mon-spell.h"
32 #include "mon-summon.h"
33 #include "mon-util.h"
34 #include "mon-timed.h"
35 #include "obj-chest.h"
36 #include "obj-curse.h"
37 #include "obj-desc.h"
38 #include "obj-gear.h"
39 #include "obj-ignore.h"
40 #include "obj-knowledge.h"
41 #include "obj-make.h"
42 #include "obj-pile.h"
43 #include "obj-power.h"
44 #include "obj-tval.h"
45 #include "obj-util.h"
46 #include "player-calcs.h"
47 #include "player-history.h"
48 #include "player-spell.h"
49 #include "player-timed.h"
50 #include "player-util.h"
51 #include "project.h"
52 #include "source.h"
53 #include "target.h"
54 #include "trap.h"
55 
56 
57 /**
58  * ------------------------------------------------------------------------
59  * Structures and helper functions for effects
60  * ------------------------------------------------------------------------ */
61 typedef struct effect_handler_context_s {
62 	const effect_index effect;
63 	const struct source origin;
64 	const struct object *obj;
65 	const bool aware;
66 	const int dir;
67 	const int beam;
68 	const int boost;
69 	const random_value value;
70 	const int subtype, radius, other, y, x;
71 	const char *msg;
72 	bool ident;
73 	struct command *cmd;
74 } effect_handler_context_t;
75 
76 typedef bool (*effect_handler_f)(effect_handler_context_t *);
77 
78 /**
79  * Structure for effects
80  */
81 struct effect_kind {
82 	u16b index;          /* Effect index */
83 	bool aim;            /* Whether the effect requires aiming */
84 	const char *info;    /* Effect info (for spell tips) */
85 	effect_handler_f handler;    /* Function to perform the effect */
86 	const char *desc;    /* Effect description */
87 };
88 
89 
90 /**
91  * Stat adjectives
92  */
desc_stat(int stat,bool positive)93 static const char *desc_stat(int stat, bool positive)
94 {
95 	struct obj_property *prop = lookup_obj_property(OBJ_PROPERTY_STAT, stat);
96 	if (positive) {
97 		return prop->adjective;
98 	}
99 	return prop->neg_adj;
100 }
101 
102 
effect_calculate_value(effect_handler_context_t * context,bool use_boost)103 int effect_calculate_value(effect_handler_context_t *context, bool use_boost)
104 {
105 	int final = 0;
106 
107 	if (context->value.base > 0 ||
108 		(context->value.dice > 0 && context->value.sides > 0)) {
109 		final = context->value.base +
110 			damroll(context->value.dice, context->value.sides);
111 	}
112 
113 	/* Device boost */
114 	if (use_boost) {
115 		final *= (100 + context->boost);
116 		final /= 100;
117 	}
118 
119 	return final;
120 }
121 
get_target(struct source origin,int dir,struct loc * grid,int * flags)122 static void get_target(struct source origin, int dir, struct loc *grid,
123 					   int *flags)
124 {
125 	switch (origin.what) {
126 		case SRC_MONSTER: {
127 			struct monster *monster = cave_monster(cave, origin.which.monster);
128 			int conf_level, accuracy = 100;
129 
130 			if (!monster) break;
131 
132 			conf_level = monster_effect_level(monster, MON_TMD_CONF);
133 			while (conf_level) {
134 				accuracy *= (100 - CONF_RANDOM_CHANCE);
135 				accuracy /= 100;
136 				conf_level--;
137 			}
138 
139 			*flags |= (PROJECT_PLAY);
140 
141 			if (randint1(100) > accuracy) {
142 				dir = randint1(9);
143 				*grid = loc_sum(monster->grid, ddgrid[dir]);
144 			} else if (monster->target.midx > 0) {
145 				struct monster *mon = cave_monster(cave, monster->target.midx);
146 				*grid = mon->grid;
147 			} else {
148 				struct loc decoy = cave_find_decoy(cave);
149 				if (!loc_is_zero(decoy)) {
150 					*grid = decoy;
151 				} else {
152 					*grid = player->grid;
153 				}
154 			}
155 
156 			break;
157 		}
158 
159 		case SRC_PLAYER:
160 			if (dir == DIR_TARGET && target_okay()) {
161 				target_get(grid);
162 			} else {
163 				/* Use the adjacent grid in the given direction as target */
164 				*grid = loc_sum(player->grid, ddgrid[dir]);
165 			}
166 
167 			break;
168 
169 		default:
170 			*flags |= PROJECT_PLAY;
171 			*grid = player->grid;
172 			break;
173 	}
174 }
175 
176 /**
177  * Check for monster targeting another monster
178  */
monster_target_monster(effect_handler_context_t * context)179 static struct monster *monster_target_monster(effect_handler_context_t *context)
180 {
181 	if (context->origin.what == SRC_MONSTER) {
182 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
183 		if (!mon) return NULL;
184 		if (mon->target.midx > 0) {
185 			struct monster *t_mon = cave_monster(cave, mon->target.midx);
186 			assert(t_mon);
187 			return t_mon;
188 		}
189 	}
190 	return NULL;
191 }
192 
193 /**
194  * Apply the project() function in a direction, or at a target
195  */
project_aimed(struct source origin,int typ,int dir,int dam,int flg,const struct object * obj)196 static bool project_aimed(struct source origin,
197 						  int typ, int dir, int dam, int flg,
198 						  const struct object *obj)
199 {
200 	struct loc grid = loc(-1, -1);
201 
202 	/* Pass through the target if needed */
203 	flg |= (PROJECT_THRU);
204 
205 	get_target(origin, dir, &grid, &flg);
206 
207 	/* Aim at the target, do NOT explode */
208 	return (project(origin, 0, grid, dam, typ, flg, 0, 0, obj));
209 }
210 
211 /**
212  * Apply the project() function to grids around the target
213  */
project_touch(int dam,int rad,int typ,bool aware,const struct object * obj)214 static bool project_touch(int dam, int rad, int typ, bool aware,
215 						  const struct object *obj)
216 {
217 	struct loc pgrid = player->grid;
218 
219 	int flg = PROJECT_GRID | PROJECT_KILL | PROJECT_HIDE | PROJECT_ITEM | PROJECT_THRU;
220 	if (aware) flg |= PROJECT_AWARE;
221 	return (project(source_player(), rad, pgrid, dam, typ, flg, 0, 0, obj));
222 }
223 
224 /**
225  * Selects items that have at least one removable curse.
226  */
item_tester_uncursable(const struct object * obj)227 static bool item_tester_uncursable(const struct object *obj)
228 {
229 	struct curse_data *c = obj->known->curses;
230 	if (c) {
231 		size_t i;
232 		for (i = 1; i < z_info->curse_max; i++) {
233 			if (c[i].power < 100) {
234 				return true;
235 			}
236 		}
237 	}
238     return false;
239 }
240 
241 /**
242  * Removes an individual curse from an object.
243  */
remove_object_curse(struct object * obj,int index,bool message)244 static void remove_object_curse(struct object *obj, int index, bool message)
245 {
246 	struct curse_data *c = &obj->curses[index];
247 	char *name = curses[index].name;
248 	char *removed = format("The %s curse is removed!", name);
249 	int i;
250 
251 	c->power = 0;
252 	c->timeout = 0;
253 	if (message) {
254 		msg(removed);
255 	}
256 
257 	/* Check to see if that was the last one */
258 	for (i = 1; i < z_info->curse_max; i++) {
259 		if (obj->curses[i].power) {
260 			return;
261 		}
262 	}
263 
264 	mem_free(obj->curses);
265 	obj->curses = NULL;
266 }
267 
268 /**
269  * Attempts to remove a curse from an object.
270  */
uncurse_object(struct object * obj,int strength,char * dice_string)271 static bool uncurse_object(struct object *obj, int strength, char *dice_string)
272 {
273 	int index = 0;
274 
275 	if (get_curse(&index, obj, dice_string)) {
276 		struct curse_data curse = obj->curses[index];
277 		char o_name[80];
278 
279 		if (curse.power >= 100) {
280 			/* Curse is permanent */
281 			return false;
282 		} else if (strength >= curse.power) {
283 			/* Successfully removed this curse */
284 			remove_object_curse(obj->known, index, false);
285 			remove_object_curse(obj, index, true);
286 		} else if (!of_has(obj->flags, OF_FRAGILE)) {
287 			/* Failure to remove, object is now fragile */
288 			object_desc(o_name, sizeof(o_name), obj, ODESC_FULL);
289 			msgt(MSG_CURSED, "The spell fails; your %s is now fragile.", o_name);
290 			of_on(obj->flags, OF_FRAGILE);
291 			player_learn_flag(player, OF_FRAGILE);
292 		} else if (one_in_(4)) {
293 			/* Failure - unlucky fragile object is destroyed */
294 			struct object *destroyed;
295 			bool none_left = false;
296 			msg("There is a bang and a flash!");
297 			take_hit(player, damroll(5, 5), "Failed uncursing");
298 			if (object_is_carried(player, obj)) {
299 				destroyed = gear_object_for_use(obj, 1, false, &none_left);
300 				if (destroyed->artifact) {
301 					/* Artifacts are marked as lost */
302 					history_lose_artifact(player, destroyed->artifact);
303 				}
304 				object_delete(&destroyed->known);
305 				object_delete(&destroyed);
306 			} else {
307 				square_delete_object(cave, obj->grid, obj, true, true);
308 			}
309 		} else {
310 			/* Non-destructive failure */
311 			msg("The removal fails.");
312 		}
313 	} else {
314 		return false;
315 	}
316 	player->upkeep->notice |= (PN_COMBINE);
317 	player->upkeep->update |= (PU_BONUS);
318 	player->upkeep->redraw |= (PR_EQUIP | PR_INVEN);
319 	return true;
320 }
321 
322 /**
323  * Selects items that have at least one unknown rune.
324  */
item_tester_unknown(const struct object * obj)325 static bool item_tester_unknown(const struct object *obj)
326 {
327     return object_runes_known(obj) ? false : true;
328 }
329 
330 /**
331  * Bit flags for the enchant() function
332  */
333 #define ENCH_TOHIT   0x01
334 #define ENCH_TODAM   0x02
335 #define ENCH_TOBOTH  0x03
336 #define ENCH_TOAC	0x04
337 
338 /**
339  * Used by the enchant() function (chance of failure)
340  */
341 static const int enchant_table[16] =
342 {
343 	0, 10,  20, 40, 80,
344 	160, 280, 400, 550, 700,
345 	800, 900, 950, 970, 990,
346 	1000
347 };
348 
349 /**
350  * Hook to specify "weapon"
351  */
item_tester_hook_weapon(const struct object * obj)352 static bool item_tester_hook_weapon(const struct object *obj)
353 {
354 	return tval_is_weapon(obj);
355 }
356 
357 
358 /**
359  * Hook to specify "armour"
360  */
item_tester_hook_armour(const struct object * obj)361 static bool item_tester_hook_armour(const struct object *obj)
362 {
363 	return tval_is_armor(obj);
364 }
365 
366 /**
367  * Tries to increase an items bonus score, if possible.
368  *
369  * \returns true if the bonus was increased
370  */
enchant_score(s16b * score,bool is_artifact)371 static bool enchant_score(s16b *score, bool is_artifact)
372 {
373 	int chance;
374 
375 	/* Artifacts resist enchantment half the time */
376 	if (is_artifact && randint0(100) < 50) return false;
377 
378 	/* Figure out the chance to enchant */
379 	if (*score < 0) chance = 0;
380 	else if (*score > 15) chance = 1000;
381 	else chance = enchant_table[*score];
382 
383 	/* If we roll less-than-or-equal to chance, it fails */
384 	if (randint1(1000) <= chance) return false;
385 
386 	/* Increment the score */
387 	++*score;
388 
389 	return true;
390 }
391 
392 /**
393  * Helper function for enchant() which tries increasing an item's bonuses
394  *
395  * \returns true if a bonus was increased
396  */
enchant2(struct object * obj,s16b * score)397 static bool enchant2(struct object *obj, s16b *score)
398 {
399 	bool result = false;
400 	bool is_artifact = obj->artifact ? true : false;
401 	if (enchant_score(score, is_artifact)) result = true;
402 	return result;
403 }
404 
405 /**
406  * Enchant an item
407  *
408  * Revamped!  Now takes item pointer, number of times to try enchanting, and a
409  * flag of what to try enchanting.  Artifacts resist enchantment some of the
410  * time. Also, any enchantment attempt (even unsuccessful) kicks off a parallel
411  * attempt to uncurse a cursed item.
412  *
413  * Note that an item can technically be enchanted all the way to +15 if you
414  * wait a very, very, long time.  Going from +9 to +10 only works about 5% of
415  * the time, and from +10 to +11 only about 1% of the time.
416  *
417  * Note that this function can now be used on "piles" of items, and the larger
418  * the pile, the lower the chance of success.
419  *
420  * \returns true if the item was changed in some way
421  */
enchant(struct object * obj,int n,int eflag)422 bool enchant(struct object *obj, int n, int eflag)
423 {
424 	int i, prob;
425 	bool res = false;
426 
427 	/* Large piles resist enchantment */
428 	prob = obj->number * 100;
429 
430 	/* Missiles are easy to enchant */
431 	if (tval_is_ammo(obj)) prob = prob / 20;
432 
433 	/* Try "n" times */
434 	for (i = 0; i < n; i++)
435 	{
436 		/* Roll for pile resistance */
437 		if (prob > 100 && randint0(prob) >= 100) continue;
438 
439 		/* Try the three kinds of enchantment we can do */
440 		if ((eflag & ENCH_TOHIT) && enchant2(obj, &obj->to_h)) res = true;
441 		if ((eflag & ENCH_TODAM) && enchant2(obj, &obj->to_d)) res = true;
442 		if ((eflag & ENCH_TOAC)  && enchant2(obj, &obj->to_a)) res = true;
443 	}
444 
445 	/* Update knowledge */
446 	assert(obj->known);
447 	obj->known->to_h = obj->to_h;
448 	obj->known->to_d = obj->to_d;
449 	obj->known->to_a = obj->to_a;
450 
451 	/* Failure */
452 	if (!res) return (false);
453 
454 	/* Recalculate bonuses, gear */
455 	player->upkeep->update |= (PU_BONUS | PU_INVEN);
456 
457 	/* Combine the pack (later) */
458 	player->upkeep->notice |= (PN_COMBINE);
459 
460 	/* Redraw stuff */
461 	player->upkeep->redraw |= (PR_INVEN | PR_EQUIP );
462 
463 	/* Success */
464 	return (true);
465 }
466 
467 /**
468  * Enchant an item (in the inventory or on the floor)
469  * Note that "num_ac" requires armour, else weapon
470  * Returns true if attempted, false if cancelled
471  *
472  * Enchanting with the TOBOTH flag will try to enchant
473  * both to_hit and to_dam with the same flag.  This
474  * may not be the most desirable behavior (ACB).
475  */
enchant_spell(int num_hit,int num_dam,int num_ac,struct command * cmd)476 bool enchant_spell(int num_hit, int num_dam, int num_ac, struct command *cmd)
477 {
478 	bool okay = false;
479 
480 	struct object *obj;
481 
482 	char o_name[80];
483 
484 	const char *q, *s;
485 	int itemmode = (USE_EQUIP | USE_INVEN | USE_QUIVER | USE_FLOOR);
486 	item_tester filter = num_ac ?
487 		item_tester_hook_armour : item_tester_hook_weapon;
488 
489 	/* Get an item */
490 	q = "Enchant which item? ";
491 	s = "You have nothing to enchant.";
492 	if (cmd) {
493 		if (cmd_get_item(cmd, "tgtitem", &obj, q, s, filter,
494 				itemmode)) {
495 			return false;
496 		}
497 	} else if (!get_item(&obj, q, s, 0, filter, itemmode))
498 		return false;
499 
500 	/* Description */
501 	object_desc(o_name, sizeof(o_name), obj, ODESC_BASE);
502 
503 	/* Describe */
504 	msg("%s %s glow%s brightly!",
505 		(object_is_carried(player, obj) ? "Your" : "The"), o_name,
506 			   ((obj->number > 1) ? "" : "s"));
507 
508 	/* Enchant */
509 	if (num_dam && enchant(obj, num_hit, ENCH_TOBOTH)) okay = true;
510 	else if (enchant(obj, num_hit, ENCH_TOHIT)) okay = true;
511 	else if (enchant(obj, num_dam, ENCH_TODAM)) okay = true;
512 	if (enchant(obj, num_ac, ENCH_TOAC)) okay = true;
513 
514 	/* Failure */
515 	if (!okay) {
516 		event_signal(EVENT_INPUT_FLUSH);
517 
518 		/* Message */
519 		msg("The enchantment failed.");
520 	}
521 
522 	/* Something happened */
523 	return (true);
524 }
525 
526 /**
527  * Brand weapons (or ammo)
528  *
529  * Turns the (non-magical) object into an ego-item of 'brand_type'.
530  */
brand_object(struct object * obj,const char * name)531 void brand_object(struct object *obj, const char *name)
532 {
533 	int i;
534 	struct ego_item *ego;
535 	bool ok = false;
536 
537 	/* You can never modify artifacts, ego items or worthless items */
538 	if (obj && obj->kind->cost && !obj->artifact && !obj->ego) {
539 		char o_name[80];
540 		char brand[20];
541 
542 		object_desc(o_name, sizeof(o_name), obj, ODESC_BASE);
543 		strnfmt(brand, sizeof(brand), "of %s", name);
544 
545 		/* Describe */
546 		msg("The %s %s surrounded with an aura of %s.", o_name,
547 			(obj->number > 1) ? "are" : "is", name);
548 
549 		/* Get the right ego type for the object */
550 		for (i = 0; i < z_info->e_max; i++) {
551 			ego = &e_info[i];
552 
553 			/* Match the name */
554 			if (!ego->name) continue;
555 			if (streq(ego->name, brand)) {
556 				struct poss_item *poss;
557 				for (poss = ego->poss_items; poss; poss = poss->next)
558 					if (poss->kidx == obj->kind->kidx)
559 						ok = true;
560 			}
561 			if (ok) break;
562 		}
563 
564 		assert(ok);
565 
566 		/* Make it an ego item */
567 		obj->ego = &e_info[i];
568 		ego_apply_magic(obj, 0);
569 		player_know_object(player, obj);
570 
571 		/* Update the gear */
572 		player->upkeep->update |= (PU_INVEN);
573 
574 		/* Combine the pack (later) */
575 		player->upkeep->notice |= (PN_COMBINE);
576 
577 		/* Window stuff */
578 		player->upkeep->redraw |= (PR_INVEN | PR_EQUIP);
579 
580 		/* Enchant */
581 		enchant(obj, randint0(3) + 4, ENCH_TOHIT | ENCH_TODAM);
582 	} else {
583 		event_signal(EVENT_INPUT_FLUSH);
584 		msg("The branding failed.");
585 	}
586 }
587 
588 /**
589  * Hook for "get_item()".  Determine if something is rechargable.
590  */
item_tester_hook_recharge(const struct object * obj)591 static bool item_tester_hook_recharge(const struct object *obj)
592 {
593 	/* Recharge staves and wands */
594 	if (tval_can_have_charges(obj)) return true;
595 
596 	return false;
597 }
598 
599 /**
600  * Hook to specify a staff
601  */
item_tester_hook_staff(const struct object * obj)602 static bool item_tester_hook_staff(const struct object *obj)
603 {
604 	return obj->tval == TV_STAFF;
605 }
606 
607 /**
608  * Hook to specify "ammo"
609  */
item_tester_hook_ammo(const struct object * obj)610 static bool item_tester_hook_ammo(const struct object *obj)
611 {
612 	return tval_is_ammo(obj);
613 }
614 
615 /**
616  * Hook to specify bolts
617  */
item_tester_hook_bolt(const struct object * obj)618 static bool item_tester_hook_bolt(const struct object *obj)
619 {
620 	return obj->tval == TV_BOLT;
621 }
622 
623 /**
624  * ------------------------------------------------------------------------
625  * Effect handlers
626  * ------------------------------------------------------------------------ */
627 /**
628  * Dummy effect, to tell the effect code to pick one of the next
629  * context->value.base effects at random.
630  */
effect_handler_RANDOM(effect_handler_context_t * context)631 bool effect_handler_RANDOM(effect_handler_context_t *context)
632 {
633 	return true;
634 }
635 
636 /**
637  * Deal damage from the current monster or trap to the player
638  */
effect_handler_DAMAGE(effect_handler_context_t * context)639 bool effect_handler_DAMAGE(effect_handler_context_t *context)
640 {
641 	int dam = effect_calculate_value(context, false);
642 	char killer[80];
643 
644 	/* Always ID */
645 	context->ident = true;
646 
647 	switch (context->origin.what) {
648 		case SRC_MONSTER: {
649 			struct monster *mon = cave_monster(cave,
650 											   context->origin.which.monster);
651 			struct monster *t_mon = monster_target_monster(context);
652 			struct loc decoy = cave_find_decoy(cave);
653 
654 			/* Damage another monster */
655 			if (t_mon) {
656 				bool fear = false;
657 
658 				mon_take_nonplayer_hit(dam, t_mon, MON_MSG_NONE, MON_MSG_DIE);
659 				if (fear && monster_is_visible(t_mon)) {
660 					add_monster_message(t_mon, MON_MSG_FLEE_IN_TERROR, true);
661 				}
662 				return true;
663 			}
664 
665 			/* Destroy a decoy */
666 			if (decoy.y && decoy.x) {
667 				square_destroy_decoy(cave, decoy);
668 				return true;
669 			}
670 
671 			monster_desc(killer, sizeof(killer), mon, MDESC_DIED_FROM);
672 			break;
673 		}
674 
675 		case SRC_TRAP: {
676 			struct trap *trap = context->origin.which.trap;
677 			char *article = is_a_vowel(trap->kind->desc[0]) ? "an " : "a ";
678 			strnfmt(killer, sizeof(killer), "%s%s", article, trap->kind->desc);
679 			break;
680 		}
681 
682 		case SRC_OBJECT: {
683 			/* Must be a cursed weapon */
684 			struct object *obj = context->origin.which.object;
685 			object_desc(killer, sizeof(killer), obj, ODESC_PREFIX | ODESC_BASE);
686 			break;
687 		}
688 
689 		case SRC_CHEST_TRAP: {
690 			struct chest_trap *trap = context->origin.which.chest_trap;
691 			strnfmt(killer, sizeof(killer), "%s", trap->msg_death);
692 			break;
693 		}
694 
695 		case SRC_PLAYER: {
696 			if (context->msg) {
697 				my_strcpy(killer, context->msg, sizeof(killer));
698 			} else {
699 				my_strcpy(killer, "yourself", sizeof(killer));
700 			}
701 			break;
702 		}
703 
704 		case SRC_NONE: {
705 			my_strcpy(killer, "a bug", sizeof(killer));
706 			break;
707 		}
708 	}
709 
710 	/* Hit the player */
711 	take_hit(player, dam, killer);
712 
713 	return true;
714 }
715 
716 
717 /**
718  * Heal the player by a given percentage of their wounds, or a minimum
719  * amount, whichever is larger.
720  *
721  * context->value.base should be the minimum, and
722  * context->value.m_bonus the percentage
723  */
effect_handler_HEAL_HP(effect_handler_context_t * context)724 bool effect_handler_HEAL_HP(effect_handler_context_t *context)
725 {
726 	int num;
727 
728 	/* Paranoia */
729 	if ((context->value.m_bonus <= 0) && (context->value.base <= 0))
730 		return (true);
731 
732 	/* Always ID */
733 	context->ident = true;
734 
735 	/* No healing needed */
736 	if (player->chp >= player->mhp) return (true);
737 
738 	/* Figure percentage healing level */
739 	num = ((player->mhp - player->chp) * context->value.m_bonus) / 100;
740 
741 	/* Enforce minimum */
742 	if (num < context->value.base) num = context->value.base;
743 
744 	/* Gain hitpoints */
745 	player->chp += num;
746 
747 	/* Enforce maximum */
748 	if (player->chp >= player->mhp) {
749 		player->chp = player->mhp;
750 		player->chp_frac = 0;
751 	}
752 
753 	/* Redraw */
754 	player->upkeep->redraw |= (PR_HP);
755 
756 	/* Print a nice message */
757 	if (num < 5)
758 		msg("You feel a little better.");
759 	else if (num < 15)
760 		msg("You feel better.");
761 	else if (num < 35)
762 		msg("You feel much better.");
763 	else
764 		msg("You feel very good.");
765 
766 	return (true);
767 }
768 
769 
770 /**
771  * Monster self-healing.
772  */
effect_handler_MON_HEAL_HP(effect_handler_context_t * context)773 bool effect_handler_MON_HEAL_HP(effect_handler_context_t *context)
774 {
775 	assert(context->origin.what == SRC_MONSTER);
776 
777 	int midx = context->origin.which.monster;
778 	struct monster *mon = midx > 0 ? cave_monster(cave, midx) : NULL;
779 
780 	int amount = effect_calculate_value(context, false);
781 	char m_name[80], m_poss[80];
782 	bool seen;
783 
784 	if (!mon) return true;
785 
786 	/* Get the monster name (or "it") */
787 	monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);
788 
789 	/* Get the monster possessive ("his"/"her"/"its") */
790 	monster_desc(m_poss, sizeof(m_poss), mon, MDESC_PRO_VIS | MDESC_POSS);
791 
792 	seen = (!player->timed[TMD_BLIND] && monster_is_visible(mon));
793 
794 	/* Heal some */
795 	mon->hp += amount;
796 
797 	/* Fully healed */
798 	if (mon->hp >= mon->maxhp) {
799 		mon->hp = mon->maxhp;
800 
801 		if (seen)
802 			msg("%s looks REALLY healthy!", m_name);
803 		else
804 			msg("%s sounds REALLY healthy!", m_name);
805 	} else if (seen) { /* Partially healed */
806 		msg("%s looks healthier.", m_name);
807 	} else {
808 		msg("%s sounds healthier.", m_name);
809 	}
810 
811 	/* Redraw (later) if needed */
812 	if (player->upkeep->health_who == mon)
813 		player->upkeep->redraw |= (PR_HEALTH);
814 
815 	/* Cancel fear */
816 	if (mon->m_timed[MON_TMD_FEAR]) {
817 		mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE);
818 		msg("%s recovers %s courage.", m_name, m_poss);
819 	}
820 
821 	/* ID */
822 	context->ident = true;
823 
824 	return true;
825 }
826 
827 /**
828  * Monster healing of kin.
829  */
effect_handler_MON_HEAL_KIN(effect_handler_context_t * context)830 bool effect_handler_MON_HEAL_KIN(effect_handler_context_t *context)
831 {
832 	assert(context->origin.what == SRC_MONSTER);
833 
834 	int midx = context->origin.which.monster;
835 	struct monster *mon = midx > 0 ? cave_monster(cave, midx) : NULL;
836 	if (!mon) return true;
837 
838 	int amount = effect_calculate_value(context, false);
839 	char m_name[80], m_poss[80];
840 	bool seen;
841 
842 	/* Find a nearby monster */
843 	mon = choose_nearby_injured_kin(cave, mon);
844 	if (!mon) return true;
845 
846 	/* Get the monster name (or "it") */
847 	monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);
848 
849 	/* Get the monster possessive ("his"/"her"/"its") */
850 	monster_desc(m_poss, sizeof(m_poss), mon, MDESC_PRO_VIS | MDESC_POSS);
851 
852 	seen = (!player->timed[TMD_BLIND] && monster_is_visible(mon));
853 
854 	/* Heal some */
855 	mon->hp = MIN(mon->hp + amount, mon->maxhp);
856 
857 	if (seen) {
858 		if (mon->hp == mon->maxhp) {
859 			msg("%s looks REALLY healthy!", m_name);
860 		} else if (seen) { /* Partially healed */
861 			msg("%s looks healthier.", m_name);
862 		}
863 	}
864 
865 	/* Redraw (later) if needed */
866 	if (player->upkeep->health_who == mon)
867 		player->upkeep->redraw |= (PR_HEALTH);
868 
869 	/* Cancel fear */
870 	if (mon->m_timed[MON_TMD_FEAR]) {
871 		mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOMESSAGE);
872 		msg("%s recovers %s courage.", m_name, m_poss);
873 	}
874 
875 	/* ID */
876 	context->ident = true;
877 
878 	return true;
879 }
880 
881 /**
882  * Feed the player, or set their satiety level.
883  */
effect_handler_NOURISH(effect_handler_context_t * context)884 bool effect_handler_NOURISH(effect_handler_context_t *context)
885 {
886 	int amount = effect_calculate_value(context, false);
887 	amount *= z_info->food_value;
888 	if (context->subtype == 0) {
889 		/* Increase food level by amount */
890 		player_inc_timed(player, TMD_FOOD, MAX(amount, 0), false, false);
891 	} else if (context->subtype == 1) {
892 		/* Decrease food level by amount */
893 		player_dec_timed(player, TMD_FOOD, MAX(amount, 0), false);
894 	} else if (context->subtype == 2) {
895 		/* Set food level to amount, vomiting if necessary */
896 		bool message = player->timed[TMD_FOOD] > amount;
897 		if (message) {
898 			msg("You vomit!");
899 		}
900 		player_set_timed(player, TMD_FOOD, MAX(amount, 0), false);
901 	} else if (context->subtype == 3) {
902 		/* Increase food level to amount if needed */
903 		if (player->timed[TMD_FOOD] < amount) {
904 			player_set_timed(player, TMD_FOOD, MAX(amount + 1, 0), false);
905 		}
906 	} else {
907 		return false;
908 	}
909 	context->ident = true;
910 	return true;
911 }
912 
effect_handler_CRUNCH(effect_handler_context_t * context)913 bool effect_handler_CRUNCH(effect_handler_context_t *context)
914 {
915 	if (one_in_(2))
916 		msg("It's crunchy.");
917 	else
918 		msg("It nearly breaks your tooth!");
919 	context->ident = true;
920 	return true;
921 }
922 
923 /**
924  * Cure a player status condition.
925  */
effect_handler_CURE(effect_handler_context_t * context)926 bool effect_handler_CURE(effect_handler_context_t *context)
927 {
928 	int type = context->subtype;
929 	(void) player_clear_timed(player, type, true);
930 	context->ident = true;
931 	return true;
932 }
933 
934 /**
935  * Set a (positive or negative) player status condition.
936  */
effect_handler_TIMED_SET(effect_handler_context_t * context)937 bool effect_handler_TIMED_SET(effect_handler_context_t *context)
938 {
939 	int amount = effect_calculate_value(context, false);
940 	player_set_timed(player, context->subtype, MAX(amount, 0), true);
941 	context->ident = true;
942 	return true;
943 
944 }
945 
946 /**
947  * Extend a (positive or negative) player status condition.
948  * If context->other is set, increase by that amount if the player already
949  * has the status
950  */
effect_handler_TIMED_INC(effect_handler_context_t * context)951 bool effect_handler_TIMED_INC(effect_handler_context_t *context)
952 {
953 	int amount = effect_calculate_value(context, false);
954 	struct monster *t_mon = monster_target_monster(context);
955 	struct loc decoy = cave_find_decoy(cave);
956 
957 	context->ident = true;
958 
959 	/* Destroy decoy if it's a monster attack */
960 	if (cave->mon_current > 0 && decoy.y && decoy.x) {
961 		square_destroy_decoy(cave, decoy);
962 		return true;
963 	}
964 
965 	/* Check for monster targeting another monster */
966 	if (t_mon) {
967 		int mon_tmd_effect = -1;
968 
969 		/* Will do until monster and player timed effects are fused */
970 		switch (context->subtype) {
971 			case TMD_CONFUSED: {
972 				mon_tmd_effect = MON_TMD_CONF;
973 				break;
974 			}
975 			case TMD_SLOW: {
976 				mon_tmd_effect = MON_TMD_SLOW;
977 				break;
978 			}
979 			case TMD_PARALYZED: {
980 				mon_tmd_effect = MON_TMD_HOLD;
981 				break;
982 			}
983 			case TMD_BLIND: {
984 				mon_tmd_effect = MON_TMD_STUN;
985 				break;
986 			}
987 			case TMD_AFRAID: {
988 				mon_tmd_effect = MON_TMD_FEAR;
989 				break;
990 			}
991 			case TMD_AMNESIA: {
992 				mon_tmd_effect = MON_TMD_SLEEP;
993 				break;
994 			}
995 			default: {
996 				break;
997 			}
998 		}
999 		if (mon_tmd_effect >= 0) {
1000 			mon_inc_timed(t_mon, mon_tmd_effect, MAX(amount, 0), 0);
1001 		}
1002 		return true;
1003 	}
1004 
1005 	if (!player->timed[context->subtype] || !context->other) {
1006 		player_inc_timed(player, context->subtype, MAX(amount, 0), true, true);
1007 	} else {
1008 		player_inc_timed(player, context->subtype, context->other, true, true);
1009 	}
1010 	return true;
1011 }
1012 
1013 /**
1014  * Extend a (positive or negative) player status condition unresistably.
1015  * If context->other is set, increase by that amount if the player already
1016  * has the status
1017  */
effect_handler_TIMED_INC_NO_RES(effect_handler_context_t * context)1018 bool effect_handler_TIMED_INC_NO_RES(effect_handler_context_t *context)
1019 {
1020 	int amount = effect_calculate_value(context, false);
1021 
1022 	if (!player->timed[context->subtype] || !context->other)
1023 		player_inc_timed(player, context->subtype, MAX(amount, 0), true, false);
1024 	else
1025 		player_inc_timed(player, context->subtype, context->other, true, false);
1026 	context->ident = true;
1027 	return true;
1028 }
1029 
1030 /**
1031  * Extend a (positive or negative) monster status condition.
1032  */
effect_handler_MON_TIMED_INC(effect_handler_context_t * context)1033 bool effect_handler_MON_TIMED_INC(effect_handler_context_t *context)
1034 {
1035 	assert(context->origin.what == SRC_MONSTER);
1036 
1037 	int amount = effect_calculate_value(context, false);
1038 	struct monster *mon = cave_monster(cave, context->origin.which.monster);
1039 
1040 	if (mon) {
1041 		mon_inc_timed(mon, context->subtype, MAX(amount, 0), 0);
1042 		context->ident = true;
1043 	}
1044 
1045 	return true;
1046 }
1047 
1048 /**
1049  * Reduce a (positive or negative) player status condition.
1050  * If context->other is set, decrease by the current value / context->other
1051  */
effect_handler_TIMED_DEC(effect_handler_context_t * context)1052 bool effect_handler_TIMED_DEC(effect_handler_context_t *context)
1053 {
1054 	int amount = effect_calculate_value(context, false);
1055 	if (context->other)
1056 		amount = player->timed[context->subtype] / context->other;
1057 	(void) player_dec_timed(player, context->subtype, MAX(amount, 0), true);
1058 	context->ident = true;
1059 	return true;
1060 }
1061 
1062 /**
1063  * Create a glyph.
1064  */
effect_handler_GLYPH(effect_handler_context_t * context)1065 bool effect_handler_GLYPH(effect_handler_context_t *context)
1066 {
1067 	struct loc decoy = cave_find_decoy(cave);
1068 
1069 	/* Always notice */
1070 	context->ident = true;
1071 
1072 	/* Only one decoy at a time */
1073 	if (!loc_is_zero(decoy) && (context->subtype == GLYPH_DECOY)) {
1074 		msg("You can only deploy one decoy at a time.");
1075 		return false;
1076 	}
1077 
1078 	/* See if the effect works */
1079 	if (!square_istrappable(cave, player->grid)) {
1080 		msg("There is no clear floor on which to cast the spell.");
1081 		return false;
1082 	}
1083 
1084 	/* Push objects off the grid */
1085 	if (square_object(cave, player->grid))
1086 		push_object(player->grid);
1087 
1088 	/* Create a glyph */
1089 	square_add_glyph(cave, player->grid, context->subtype);
1090 
1091 	return true;
1092 }
1093 
1094 /**
1095  * Create a web.
1096  */
effect_handler_WEB(effect_handler_context_t * context)1097 bool effect_handler_WEB(effect_handler_context_t *context)
1098 {
1099 	int rad = 1;
1100 	struct monster *mon = NULL;
1101 	struct loc grid;
1102 
1103 	/* Get the monster creating */
1104 	if (cave->mon_current > 0) {
1105 		mon = cave_monster(cave, cave->mon_current);
1106 	} else {
1107 		/* Player can't currently create webs */
1108 		return false;
1109 	}
1110 
1111 	/* Always notice */
1112 	context->ident = true;
1113 
1114 	/* Increase the radius for higher spell power */
1115 	if (mon->race->spell_power > 40) rad++;
1116 	if (mon->race->spell_power > 80) rad++;
1117 
1118 	/* Check within the radius for clear floor */
1119 	for (grid.y = mon->grid.y - rad; grid.y <= mon->grid.y + rad; grid.y++) {
1120 		for (grid.x = mon->grid.x - rad; grid.x <= mon->grid.x + rad; grid.x++){
1121 			if (distance(grid, mon->grid) > rad) continue;
1122 
1123 			/* Require a floor grid with no existing traps or glyphs */
1124 			if (!square_iswebbable(cave, grid)) continue;
1125 
1126 			/* Create a web */
1127 			square_add_web(cave, grid);
1128 		}
1129 	}
1130 
1131 	return true;
1132 }
1133 
1134 /**
1135  * Restore a stat; the stat index is context->subtype
1136  */
effect_handler_RESTORE_STAT(effect_handler_context_t * context)1137 bool effect_handler_RESTORE_STAT(effect_handler_context_t *context)
1138 {
1139 	int stat = context->subtype;
1140 
1141 	/* ID */
1142 	context->ident = true;
1143 
1144 	/* Check bounds */
1145 	if (stat < 0 || stat >= STAT_MAX) return false;
1146 
1147 	/* Not needed */
1148 	if (player->stat_cur[stat] == player->stat_max[stat])
1149 		return true;
1150 
1151 	/* Restore */
1152 	player->stat_cur[stat] = player->stat_max[stat];
1153 
1154 	/* Recalculate bonuses */
1155 	player->upkeep->update |= (PU_BONUS);
1156 	update_stuff(player);
1157 
1158 	/* Message */
1159 	msg("You feel less %s.", desc_stat(stat, false));
1160 
1161 	return (true);
1162 }
1163 
1164 /**
1165  * Drain a stat temporarily.  The stat index is context->subtype.
1166  */
effect_handler_DRAIN_STAT(effect_handler_context_t * context)1167 bool effect_handler_DRAIN_STAT(effect_handler_context_t *context)
1168 {
1169 	int stat = context->subtype;
1170 	int flag = sustain_flag(stat);
1171 
1172 	/* Bounds check */
1173 	if (flag < 0) return false;
1174 
1175 	/* ID */
1176 	context->ident = true;
1177 
1178 	/* Sustain */
1179 	if (player_of_has(player, flag)) {
1180 		/* Notice effect */
1181 		equip_learn_flag(player, flag);
1182 
1183 		/* Message */
1184 		msg("You feel very %s for a moment, but the feeling passes.",
1185 				   desc_stat(stat, false));
1186 
1187 		return (true);
1188 	}
1189 
1190 	/* Attempt to reduce the stat */
1191 	if (player_stat_dec(player, stat, false)){
1192 		int dam = effect_calculate_value(context, false);
1193 
1194 		/* Notice effect */
1195 		equip_learn_flag(player, flag);
1196 
1197 		/* Message */
1198 		msgt(MSG_DRAIN_STAT, "You feel very %s.", desc_stat(stat, false));
1199 		if (dam)
1200 			take_hit(player, dam, "stat drain");
1201 	}
1202 
1203 	return (true);
1204 }
1205 
1206 /**
1207  * Lose a stat point permanently, in a stat other than the one specified
1208  * in context->subtype.
1209  */
effect_handler_LOSE_RANDOM_STAT(effect_handler_context_t * context)1210 bool effect_handler_LOSE_RANDOM_STAT(effect_handler_context_t *context)
1211 {
1212 	int safe_stat = context->subtype;
1213 	int loss_stat = randint1(STAT_MAX - 1);
1214 
1215 	/* Avoid the safe stat */
1216 	loss_stat = (loss_stat + safe_stat) % STAT_MAX;
1217 
1218 	/* Attempt to reduce the stat */
1219 	if (player_stat_dec(player, loss_stat, true)) {
1220 		msgt(MSG_DRAIN_STAT, "You feel very %s.", desc_stat(loss_stat, false));
1221 	}
1222 
1223 	/* ID */
1224 	context->ident = true;
1225 
1226 	return (true);
1227 }
1228 
1229 
1230 /**
1231  * Gain a stat point.  The stat index is context->subtype.
1232  */
effect_handler_GAIN_STAT(effect_handler_context_t * context)1233 bool effect_handler_GAIN_STAT(effect_handler_context_t *context)
1234 {
1235 	int stat = context->subtype;
1236 
1237 	/* Attempt to increase */
1238 	if (player_stat_inc(player, stat)) {
1239 		msg("You feel very %s!", desc_stat(stat, true));
1240 	}
1241 
1242 	/* Notice */
1243 	context->ident = true;
1244 
1245 	return (true);
1246 }
1247 
1248 /**
1249  * Restores any drained experience
1250  */
effect_handler_RESTORE_EXP(effect_handler_context_t * context)1251 bool effect_handler_RESTORE_EXP(effect_handler_context_t *context)
1252 {
1253 	/* Restore experience */
1254 	if (player->exp < player->max_exp) {
1255 		/* Message */
1256 		if (context->origin.what != SRC_NONE)
1257 			msg("You feel your life energies returning.");
1258 		player_exp_gain(player, player->max_exp - player->exp);
1259 
1260 		/* Recalculate max. hitpoints */
1261 		update_stuff(player);
1262 	}
1263 
1264 	/* Did something */
1265 	context->ident = true;
1266 
1267 	return (true);
1268 }
1269 
1270 /* Note the divisor of 2, a slight hack to simplify food description */
effect_handler_GAIN_EXP(effect_handler_context_t * context)1271 bool effect_handler_GAIN_EXP(effect_handler_context_t *context)
1272 {
1273 	int amount = effect_calculate_value(context, false);
1274 	if (player->exp < PY_MAX_EXP) {
1275 		msg("You feel more experienced.");
1276 		player_exp_gain(player, amount / 2);
1277 	}
1278 	context->ident = true;
1279 
1280 	return true;
1281 }
1282 
1283 /**
1284  * Drain some light from the player's light source, if possible
1285  */
effect_handler_DRAIN_LIGHT(effect_handler_context_t * context)1286 bool effect_handler_DRAIN_LIGHT(effect_handler_context_t *context)
1287 {
1288 	int drain = effect_calculate_value(context, false);
1289 
1290 	int light_slot = slot_by_name(player, "light");
1291 	struct object *obj = slot_object(player, light_slot);
1292 
1293 	if (obj && !of_has(obj->flags, OF_NO_FUEL) && (obj->timeout > 0)) {
1294 		/* Reduce fuel */
1295 		obj->timeout -= drain;
1296 		if (obj->timeout < 1) obj->timeout = 1;
1297 
1298 		/* Notice */
1299 		if (!player->timed[TMD_BLIND]) {
1300 			msg("Your light dims.");
1301 			context->ident = true;
1302 		}
1303 
1304 		/* Redraw stuff */
1305 		player->upkeep->redraw |= (PR_EQUIP);
1306 	}
1307 
1308 	return true;
1309 }
1310 
1311 /**
1312  * Drain mana from the player, healing the caster.
1313  */
effect_handler_DRAIN_MANA(effect_handler_context_t * context)1314 bool effect_handler_DRAIN_MANA(effect_handler_context_t *context)
1315 {
1316 	int drain = effect_calculate_value(context, false);
1317 	bool monster = context->origin.what != SRC_TRAP;
1318 	char m_name[80];
1319 	struct monster *mon = NULL;
1320 	struct monster *t_mon = monster_target_monster(context);
1321 	struct loc decoy = cave_find_decoy(cave);
1322 
1323 	context->ident = true;
1324 
1325 	if (monster) {
1326 		assert(context->origin.what == SRC_MONSTER);
1327 
1328 		mon = cave_monster(cave, context->origin.which.monster);
1329 
1330 		/* Get the monster name (or "it") */
1331 		monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);
1332 	}
1333 
1334 	/* Target is another monster - disenchant it */
1335 	if (t_mon) {
1336 		mon_inc_timed(t_mon, MON_TMD_DISEN, MAX(drain, 0), 0);
1337 		return true;
1338 	}
1339 
1340 	/* Target was a decoy - destroy it */
1341 	if (decoy.y && decoy.x) {
1342 		square_destroy_decoy(cave, decoy);
1343 		return true;
1344 	}
1345 
1346 	/* The player has no mana */
1347 	if (!player->csp) {
1348 		msg("The draining fails.");
1349 		if (monster) {
1350 			update_smart_learn(mon, player, 0, PF_NO_MANA, -1);
1351 		}
1352 		return true;
1353 	}
1354 
1355 	/* Drain the given amount if the player has that much, or all of it */
1356 	if (drain >= player->csp) {
1357 		drain = player->csp;
1358 		player->csp = 0;
1359 		player->csp_frac = 0;
1360 	} else {
1361 		player->csp -= drain;
1362 	}
1363 
1364 	/* Heal the monster */
1365 	if (monster) {
1366 		if (mon->hp < mon->maxhp) {
1367 			mon->hp += (6 * drain);
1368 			if (mon->hp > mon->maxhp)
1369 				mon->hp = mon->maxhp;
1370 
1371 			/* Redraw (later) if needed */
1372 			if (player->upkeep->health_who == mon)
1373 				player->upkeep->redraw |= (PR_HEALTH);
1374 
1375 			/* Special message */
1376 			if (monster_is_visible(mon))
1377 				msg("%s appears healthier.", m_name);
1378 		}
1379 	}
1380 
1381 	/* Redraw mana */
1382 	player->upkeep->redraw |= PR_MANA;
1383 
1384 	return true;
1385 }
1386 
effect_handler_RESTORE_MANA(effect_handler_context_t * context)1387 bool effect_handler_RESTORE_MANA(effect_handler_context_t *context)
1388 {
1389 	int amount = effect_calculate_value(context, false);
1390 	if (!amount) amount = player->msp;
1391 	if (player->csp < player->msp) {
1392 		player->csp += amount;
1393 		if (player->csp > player->msp) {
1394 			player->csp = player->msp;
1395 			player->csp_frac = 0;
1396 			msg("You feel your head clear.");
1397 		} else
1398 			msg("You feel your head clear somewhat.");
1399 		player->upkeep->redraw |= (PR_MANA);
1400 	}
1401 	context->ident = true;
1402 
1403 	return true;
1404 }
1405 
1406 /**
1407  * Attempt to uncurse an object
1408  */
effect_handler_REMOVE_CURSE(effect_handler_context_t * context)1409 bool effect_handler_REMOVE_CURSE(effect_handler_context_t *context)
1410 {
1411 	const char *prompt = "Uncurse which item? ";
1412 	const char *rejmsg = "You have no curses to remove.";
1413 	int itemmode = (USE_EQUIP | USE_INVEN | USE_QUIVER | USE_FLOOR);
1414 	int strength = effect_calculate_value(context, false);
1415 	struct object *obj = NULL;
1416 	char dice_string[20];
1417 
1418 	context->ident = true;
1419 
1420 	if (context->cmd) {
1421 		if (cmd_get_item(context->cmd, "tgtitem", &obj, prompt,
1422 				rejmsg, item_tester_uncursable, itemmode)) {
1423 			return false;
1424 		}
1425 	} else if (!get_item(&obj, prompt, rejmsg, 0, item_tester_uncursable,
1426 			itemmode))
1427 		return false;
1428 
1429 	/* Get the possible dice strings */
1430 	if ((context->value.dice == 1) && context->value.base) {
1431 		strnfmt(dice_string, sizeof(dice_string), "%d+d%d",
1432 				context->value.base, context->value.sides);
1433 	} else if (context->value.dice && context->value.base) {
1434 		strnfmt(dice_string, sizeof(dice_string), "%d+%dd%d",
1435 				context->value.base, context->value.dice, context->value.sides);
1436 	} else if (context->value.dice == 1) {
1437 		strnfmt(dice_string, sizeof(dice_string), "d%d", context->value.sides);
1438 	} else if (context->value.dice) {
1439 		strnfmt(dice_string, sizeof(dice_string), "%dd%d",
1440 				context->value.dice, context->value.sides);
1441 	} else {
1442 		strnfmt(dice_string, sizeof(dice_string), "%d", context->value.base);
1443 	}
1444 
1445 	return uncurse_object(obj, strength, dice_string);
1446 }
1447 
1448 /**
1449  * Set word of recall as appropriate
1450  */
effect_handler_RECALL(effect_handler_context_t * context)1451 bool effect_handler_RECALL(effect_handler_context_t *context)
1452 {
1453 	int target_depth;
1454 	context->ident = true;
1455 
1456 	/* No recall */
1457 	if (OPT(player, birth_no_recall) && !player->total_winner) {
1458 		msg("Nothing happens.");
1459 		return true;
1460 	}
1461 
1462 	/* No recall from quest levels with force_descend */
1463 	if (OPT(player, birth_force_descend) && (is_quest(player->depth))) {
1464 		msg("Nothing happens.");
1465 		return true;
1466 	}
1467 
1468 	/* No recall from single combat */
1469 	if (player->upkeep->arena_level) {
1470 		msg("Nothing happens.");
1471 		return true;
1472 	}
1473 
1474 	/* Warn the player if they're descending to an unrecallable level */
1475 	target_depth = dungeon_get_next_level(player->max_depth, 1);
1476 	if (OPT(player, birth_force_descend) && !(player->depth) &&
1477 			(is_quest(target_depth))) {
1478 		if (!get_check("Are you sure you want to descend? ")) {
1479 			return false;
1480 		}
1481 	}
1482 
1483 	/* Activate recall */
1484 	if (!player->word_recall) {
1485 		/* Reset recall depth */
1486 		if (player->depth > 0) {
1487 			if (player->depth != player->max_depth) {
1488 				if (get_check("Set recall depth to current depth? ")) {
1489 					player->recall_depth = player->max_depth = player->depth;
1490 				}
1491 			} else {
1492 				player->recall_depth = player->max_depth;
1493 			}
1494 		} else {
1495 			if (OPT(player, birth_levels_persist)) {
1496 				/* Persistent levels players get to choose */
1497 				if (!player_get_recall_depth(player)) return false;
1498 			}
1499 		}
1500 
1501 		player->word_recall = randint0(20) + 15;
1502 		msg("The air about you becomes charged...");
1503 	} else {
1504 		/* Deactivate recall */
1505 		if (!get_check("Word of Recall is already active.  Do you want to cancel it? "))
1506 			return false;
1507 
1508 		player->word_recall = 0;
1509 		msg("A tension leaves the air around you...");
1510 	}
1511 
1512 	/* Redraw status line */
1513 	player->upkeep->redraw |= PR_STATUS;
1514 	handle_stuff(player);
1515 
1516 	return true;
1517 }
1518 
effect_handler_DEEP_DESCENT(effect_handler_context_t * context)1519 bool effect_handler_DEEP_DESCENT(effect_handler_context_t *context)
1520 {
1521 	int i;
1522 
1523 	/* Calculate target depth */
1524 	int target_increment = (4 / z_info->stair_skip) + 1;
1525 	int target_depth = dungeon_get_next_level(player->max_depth,
1526 											  target_increment);
1527 	for (i = 5; i > 0; i--) {
1528 		if (is_quest(target_depth)) break;
1529 		if (target_depth >= z_info->max_depth - 1) break;
1530 
1531 		target_depth++;
1532 	}
1533 
1534 	if (target_depth > player->depth) {
1535 		msgt(MSG_TPLEVEL, "The air around you starts to swirl...");
1536 		player->deep_descent = 3 + randint1(4);
1537 
1538 		/* Redraw status line */
1539 		player->upkeep->redraw |= PR_STATUS;
1540 		handle_stuff(player);
1541 	} else {
1542 		msgt(MSG_TPLEVEL, "You sense a malevolent presence blocking passage to the levels below.");
1543 	}
1544 	context->ident = true;
1545 	return true;
1546 }
1547 
effect_handler_ALTER_REALITY(effect_handler_context_t * context)1548 bool effect_handler_ALTER_REALITY(effect_handler_context_t *context)
1549 {
1550 	msg("The world changes!");
1551 	dungeon_change_level(player, player->depth);
1552 	context->ident = true;
1553 	return true;
1554 }
1555 
1556 /**
1557  * Map an area around a point, usually the player.
1558  * The height to map above and below the player is context->y,
1559  * the width either side of the player context->x.
1560  * For player level dependent areas, we use the hack of applying value dice
1561  * and sides as the height and width.
1562  */
effect_handler_MAP_AREA(effect_handler_context_t * context)1563 bool effect_handler_MAP_AREA(effect_handler_context_t *context)
1564 {
1565 	int i, x, y;
1566 	int x1, x2, y1, y2;
1567 	int dist_y = context->y ? context->y : context->value.dice;
1568 	int dist_x = context->x ? context->x : context->value.sides;
1569 	struct loc centre = origin_get_loc(context->origin);
1570 
1571 	/* Pick an area to map */
1572 	y1 = centre.y - dist_y;
1573 	y2 = centre.y + dist_y;
1574 	x1 = centre.x - dist_x;
1575 	x2 = centre.x + dist_x;
1576 
1577 	/* Drag the co-ordinates into the dungeon */
1578 	if (y1 < 0) y1 = 0;
1579 	if (x1 < 0) x1 = 0;
1580 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1581 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1582 
1583 	/* Scan the dungeon */
1584 	for (y = y1; y < y2; y++) {
1585 		for (x = x1; x < x2; x++) {
1586 			struct loc grid = loc(x, y);
1587 
1588 			/* Some squares can't be mapped */
1589 			if (square_isno_map(cave, grid)) continue;
1590 
1591 			/* All non-walls are "checked" */
1592 			if (!square_seemslikewall(cave, grid)) {
1593 				if (!square_in_bounds_fully(cave, grid)) continue;
1594 
1595 				/* Memorize normal features */
1596 				if (!square_isfloor(cave, grid))
1597 					square_memorize(cave, grid);
1598 
1599 				/* Memorize known walls */
1600 				for (i = 0; i < 8; i++) {
1601 					int yy = y + ddy_ddd[i];
1602 					int xx = x + ddx_ddd[i];
1603 
1604 					/* Memorize walls (etc) */
1605 					if (square_seemslikewall(cave, loc(xx, yy)))
1606 						square_memorize(cave, loc(xx, yy));
1607 				}
1608 			}
1609 
1610 			/* Forget unprocessed, unknown grids in the mapping area */
1611 			if (square_isnotknown(cave, grid))
1612 				square_forget(cave, grid);
1613 		}
1614 	}
1615 
1616 	/* Unmark grids */
1617 	for (y = y1 - 1; y < y2 + 1; y++) {
1618 		for (x = x1 - 1; x < x2 + 1; x++) {
1619 			struct loc grid = loc(x, y);
1620 			if (!square_in_bounds(cave, grid)) continue;
1621 			square_unmark(cave, grid);
1622 		}
1623 	}
1624 
1625 	/* Fully update the visuals */
1626 	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
1627 
1628 	/* Redraw whole map, monster list */
1629 	player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST);
1630 
1631 	/* Notice */
1632 	context->ident = true;
1633 
1634 	return true;
1635 }
1636 
1637 /**
1638  * Map an area around the recently detected monsters.
1639  * The height to map above and below each monster is context->y,
1640  * the width either side of each monster context->x.
1641  * For player level dependent areas, we use the hack of applying value dice
1642  * and sides as the height and width.
1643  */
effect_handler_READ_MINDS(effect_handler_context_t * context)1644 bool effect_handler_READ_MINDS(effect_handler_context_t *context)
1645 {
1646 	int i;
1647 	int dist_y = context->y ? context->y : context->value.dice;
1648 	int dist_x = context->x ? context->x : context->value.sides;
1649 	bool found = false;
1650 
1651 	/* Scan monsters */
1652 	for (i = 1; i < cave_monster_max(cave); i++) {
1653 		struct monster *mon = cave_monster(cave, i);
1654 
1655 		/* Skip dead monsters */
1656 		if (!mon->race) continue;
1657 
1658 		/* Detect all appropriate monsters */
1659 		if (mflag_has(mon->mflag, MFLAG_MARK)) {
1660 			/* Map around it */
1661 			effect_simple(EF_MAP_AREA, source_monster(i), "0", 0, 0, 0,
1662 						  dist_y, dist_x, NULL);
1663 			found = true;
1664 		}
1665 	}
1666 
1667 	if (found) {
1668 		msg("Images form in your mind!");
1669 		context->ident = true;
1670 		return true;
1671 	}
1672 
1673 	return false;
1674 }
1675 
1676 /**
1677  * Detect traps around the player.  The height to detect above and below the
1678  * player is context->y, the width either side of the player context->x.
1679  */
effect_handler_DETECT_TRAPS(effect_handler_context_t * context)1680 bool effect_handler_DETECT_TRAPS(effect_handler_context_t *context)
1681 {
1682 	int x, y;
1683 	int x1, x2, y1, y2;
1684 
1685 	bool detect = false;
1686 
1687 	struct object *obj;
1688 
1689 	/* Pick an area to detect */
1690 	y1 = player->grid.y - context->y;
1691 	y2 = player->grid.y + context->y;
1692 	x1 = player->grid.x - context->x;
1693 	x2 = player->grid.x + context->x;
1694 
1695 	if (y1 < 0) y1 = 0;
1696 	if (x1 < 0) x1 = 0;
1697 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1698 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1699 
1700 
1701 	/* Scan the dungeon */
1702 	for (y = y1; y < y2; y++) {
1703 		for (x = x1; x < x2; x++) {
1704 			struct loc grid = loc(x, y);
1705 
1706 			if (!square_in_bounds_fully(cave, grid)) continue;
1707 
1708 			/* Detect traps */
1709 			if (square_isplayertrap(cave, grid))
1710 				/* Reveal trap */
1711 				if (square_reveal_trap(cave, grid, true, false))
1712 					detect = true;
1713 
1714 			/* Scan all objects in the grid to look for traps on chests */
1715 			for (obj = square_object(cave, grid); obj; obj = obj->next) {
1716 				/* Skip anything not a trapped chest */
1717 				if (!is_trapped_chest(obj)) continue;
1718 
1719 				/* Identify once */
1720 				if (!obj->known || obj->known->pval != obj->pval) {
1721 					/* Hack - know the pile */
1722 					square_know_pile(cave, grid);
1723 
1724 					/* Know the trap */
1725 					obj->known->pval = obj->pval;
1726 
1727 					/* Notice it */
1728 					disturb(player);
1729 
1730 					/* We found something to detect */
1731 					detect = true;
1732 				}
1733 			}
1734 			/* Mark as trap-detected */
1735 			sqinfo_on(square(cave, loc(x, y))->info, SQUARE_DTRAP);
1736 		}
1737 	}
1738 
1739 	/* Describe */
1740 	if (detect)
1741 		msg("You sense the presence of traps!");
1742 
1743 	/* Trap detection always makes you aware, even if no traps are present */
1744 	else
1745 		msg("You sense no traps.");
1746 
1747 	/* Notice */
1748 	context->ident = true;
1749 
1750 	return true;
1751 }
1752 
1753 /**
1754  * Detect doors around the player.  The height to detect above and below the
1755  * player is context->y, the width either side of the player context->x.
1756  */
effect_handler_DETECT_DOORS(effect_handler_context_t * context)1757 bool effect_handler_DETECT_DOORS(effect_handler_context_t *context)
1758 {
1759 	int x, y;
1760 	int x1, x2, y1, y2;
1761 
1762 	bool doors = false;
1763 
1764 	/* Pick an area to detect */
1765 	y1 = player->grid.y - context->y;
1766 	y2 = player->grid.y + context->y;
1767 	x1 = player->grid.x - context->x;
1768 	x2 = player->grid.x + context->x;
1769 
1770 	if (y1 < 0) y1 = 0;
1771 	if (x1 < 0) x1 = 0;
1772 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1773 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1774 
1775 	/* Scan the dungeon */
1776 	for (y = y1; y < y2; y++) {
1777 		for (x = x1; x < x2; x++) {
1778 			struct loc grid = loc(x, y);
1779 
1780 			if (!square_in_bounds_fully(cave, grid)) continue;
1781 
1782 			/* Detect secret doors */
1783 			if (square_issecretdoor(cave, grid)) {
1784 				/* Put an actual door */
1785 				place_closed_door(cave, grid);
1786 
1787 				/* Memorize */
1788 				square_memorize(cave, grid);
1789 				square_light_spot(cave, grid);
1790 
1791 				/* Obvious */
1792 				doors = true;
1793 			}
1794 
1795 			/* Forget unknown doors in the mapping area */
1796 			if (square_isdoor(player->cave, grid) &&
1797 				square_isnotknown(cave, grid)) {
1798 				square_forget(cave, grid);
1799 			}
1800 		}
1801 	}
1802 
1803 	/* Describe */
1804 	if (doors)
1805 		msg("You sense the presence of doors!");
1806 	else if (context->aware)
1807 		msg("You sense no doors.");
1808 
1809 	context->ident = true;
1810 
1811 	return true;
1812 }
1813 
1814 /**
1815  * Detect stairs around the player.  The height to detect above and below the
1816  * player is context->y, the width either side of the player context->x.
1817  */
effect_handler_DETECT_STAIRS(effect_handler_context_t * context)1818 bool effect_handler_DETECT_STAIRS(effect_handler_context_t *context)
1819 {
1820 	int x, y;
1821 	int x1, x2, y1, y2;
1822 
1823 	bool stairs = false;
1824 
1825 	/* Pick an area to detect */
1826 	y1 = player->grid.y - context->y;
1827 	y2 = player->grid.y + context->y;
1828 	x1 = player->grid.x - context->x;
1829 	x2 = player->grid.x + context->x;
1830 
1831 	if (y1 < 0) y1 = 0;
1832 	if (x1 < 0) x1 = 0;
1833 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1834 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1835 
1836 	/* Scan the dungeon */
1837 	for (y = y1; y < y2; y++) {
1838 		for (x = x1; x < x2; x++) {
1839 			struct loc grid = loc(x, y);
1840 
1841 			if (!square_in_bounds_fully(cave, grid)) continue;
1842 
1843 			/* Detect stairs */
1844 			if (square_isstairs(cave, grid)) {
1845 				/* Memorize */
1846 				square_memorize(cave, grid);
1847 				square_light_spot(cave, grid);
1848 
1849 				/* Obvious */
1850 				stairs = true;
1851 			}
1852 		}
1853 	}
1854 
1855 	/* Describe */
1856 	if (stairs)
1857 		msg("You sense the presence of stairs!");
1858 	else if (context->aware)
1859 		msg("You sense no stairs.");
1860 
1861 	context->ident = true;
1862 	return true;
1863 }
1864 
1865 
1866 /**
1867  * Detect buried gold around the player.  The height to detect above and below
1868  * the player is context->y, the width either side of the player context->x.
1869  */
effect_handler_DETECT_GOLD(effect_handler_context_t * context)1870 bool effect_handler_DETECT_GOLD(effect_handler_context_t *context)
1871 {
1872 	int x, y;
1873 	int x1, x2, y1, y2;
1874 
1875 	bool gold_buried = false;
1876 
1877 	/* Pick an area to detect */
1878 	y1 = player->grid.y - context->y;
1879 	y2 = player->grid.y + context->y;
1880 	x1 = player->grid.x - context->x;
1881 	x2 = player->grid.x + context->x;
1882 
1883 	if (y1 < 0) y1 = 0;
1884 	if (x1 < 0) x1 = 0;
1885 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1886 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1887 
1888 	/* Scan the dungeon */
1889 	for (y = y1; y < y2; y++) {
1890 		for (x = x1; x < x2; x++) {
1891 			struct loc grid = loc(x, y);
1892 
1893 			if (!square_in_bounds_fully(cave, grid)) continue;
1894 
1895 			/* Magma/Quartz + Known Gold */
1896 			if (square_hasgoldvein(cave, grid)) {
1897 				/* Memorize */
1898 				square_memorize(cave, grid);
1899 				square_light_spot(cave, grid);
1900 
1901 				/* Detect */
1902 				gold_buried = true;
1903 			} else if (square_hasgoldvein(player->cave, grid)) {
1904 				/* Something removed previously seen or
1905 				 * detected buried gold.  Notice the change. */
1906 				square_forget(cave, grid);
1907 			}
1908 		}
1909 	}
1910 
1911 	/* Message unless we're silently detecting */
1912 	if (context->origin.what != SRC_NONE) {
1913 		if (gold_buried) {
1914 			msg("You sense the presence of buried treasure!");
1915 		} else if (context->aware) {
1916 			msg("You sense no buried treasure.");
1917 		}
1918 	}
1919 
1920 	context->ident = true;
1921 	return true;
1922 }
1923 
1924 /**
1925  * This is a helper for effect_handler_SENSE_OBJECTS and
1926  * effect_handler_DETECT_OBJECTS to remove remembered objects at locations
1927  * sensed or detected as empty.
1928  */
forget_remembered_objects(struct chunk * c,struct chunk * knownc,struct loc grid)1929 static void forget_remembered_objects(struct chunk *c, struct chunk *knownc, struct loc grid)
1930 {
1931 	struct object *obj = square_object(knownc, grid);
1932 
1933 	while (obj) {
1934 		struct object *next = obj->next;
1935 		struct object *original = c->objects[obj->oidx];
1936 
1937 		assert(original);
1938 		square_excise_object(knownc, grid, obj);
1939 		obj->grid = loc(0, 0);
1940 
1941 		/* Delete objects which no longer exist anywhere */
1942 		if (obj->notice & OBJ_NOTICE_IMAGINED) {
1943 			delist_object(knownc, obj);
1944 			object_delete(&obj);
1945 			original->known = NULL;
1946 			delist_object(c, original);
1947 			object_delete(&original);
1948 		}
1949 		obj = next;
1950 	}
1951 }
1952 
1953 /**
1954  * Sense objects around the player.  The height to sense above and below the
1955  * player is context->y, the width either side of the player context->x
1956  */
effect_handler_SENSE_OBJECTS(effect_handler_context_t * context)1957 bool effect_handler_SENSE_OBJECTS(effect_handler_context_t *context)
1958 {
1959 	int x, y;
1960 	int x1, x2, y1, y2;
1961 
1962 	bool objects = false;
1963 
1964 	/* Pick an area to sense */
1965 	y1 = player->grid.y - context->y;
1966 	y2 = player->grid.y + context->y;
1967 	x1 = player->grid.x - context->x;
1968 	x2 = player->grid.x + context->x;
1969 
1970 	if (y1 < 0) y1 = 0;
1971 	if (x1 < 0) x1 = 0;
1972 	if (y2 > cave->height - 1) y2 = cave->height - 1;
1973 	if (x2 > cave->width - 1) x2 = cave->width - 1;
1974 
1975 	/* Scan the area for objects */
1976 	for (y = y1; y <= y2; y++) {
1977 		for (x = x1; x <= x2; x++) {
1978 			struct loc grid = loc(x, y);
1979 			struct object *obj = square_object(cave, grid);
1980 
1981 			if (!obj) {
1982 				/* If empty, remove any remembered objects. */
1983 				forget_remembered_objects(cave, player->cave, grid);
1984 				continue;
1985 			}
1986 
1987 			/* Notice an object is detected */
1988 			objects = true;
1989 
1990 			/* Mark the pile as aware */
1991 			square_sense_pile(cave, grid);
1992 		}
1993 	}
1994 
1995 	if (objects)
1996 		msg("You sense the presence of objects!");
1997 	else if (context->aware)
1998 		msg("You sense no objects.");
1999 
2000 	/* Redraw whole map, monster list */
2001 	player->upkeep->redraw |= PR_ITEMLIST;
2002 
2003 	context->ident = true;
2004 	return true;
2005 }
2006 
2007 /**
2008  * Detect objects around the player.  The height to detect above and below the
2009  * player is context->y, the width either side of the player context->x
2010  */
effect_handler_DETECT_OBJECTS(effect_handler_context_t * context)2011 bool effect_handler_DETECT_OBJECTS(effect_handler_context_t *context)
2012 {
2013 	int x, y;
2014 	int x1, x2, y1, y2;
2015 
2016 	bool objects = false;
2017 
2018 	/* Pick an area to detect */
2019 	y1 = player->grid.y - context->y;
2020 	y2 = player->grid.y + context->y;
2021 	x1 = player->grid.x - context->x;
2022 	x2 = player->grid.x + context->x;
2023 
2024 	if (y1 < 0) y1 = 0;
2025 	if (x1 < 0) x1 = 0;
2026 	if (y2 > cave->height - 1) y2 = cave->height - 1;
2027 	if (x2 > cave->width - 1) x2 = cave->width - 1;
2028 
2029 	/* Scan the area for objects */
2030 	for (y = y1; y <= y2; y++) {
2031 		for (x = x1; x <= x2; x++) {
2032 			struct loc grid = loc(x, y);
2033 			struct object *obj = square_object(cave, grid);
2034 
2035 			if (!obj) {
2036 				/* If empty, remove any remembered objects. */
2037 				forget_remembered_objects(cave, player->cave, grid);
2038 				continue;
2039 			}
2040 
2041 			/* Notice an object is detected */
2042 			if (!ignore_item_ok(obj)) {
2043 				objects = true;
2044 			}
2045 
2046 			/* Mark the pile as seen */
2047 			square_know_pile(cave, grid);
2048 		}
2049 	}
2050 
2051 	if (objects)
2052 		msg("You detect the presence of objects!");
2053 	else if (context->aware)
2054 		msg("You detect no objects.");
2055 
2056 	/* Redraw whole map, monster list */
2057 	player->upkeep->redraw |= PR_ITEMLIST;
2058 
2059 	context->ident = true;
2060 	return true;
2061 }
2062 
2063 /**
2064  * Detect monsters which satisfy the given predicate around the player.
2065  * The height to detect above and below the player is y_dist,
2066  * the width either side of the player x_dist.
2067  */
detect_monsters(int y_dist,int x_dist,monster_predicate pred)2068 static bool detect_monsters(int y_dist, int x_dist, monster_predicate pred)
2069 {
2070 	int i, x, y;
2071 	int x1, x2, y1, y2;
2072 
2073 	bool monsters = false;
2074 
2075 	/* Set the detection area */
2076 	y1 = player->grid.y - y_dist;
2077 	y2 = player->grid.y + y_dist;
2078 	x1 = player->grid.x - x_dist;
2079 	x2 = player->grid.x + x_dist;
2080 
2081 	if (y1 < 0) y1 = 0;
2082 	if (x1 < 0) x1 = 0;
2083 	if (y2 > cave->height - 1) y2 = cave->height - 1;
2084 	if (x2 > cave->width - 1) x2 = cave->width - 1;
2085 
2086 	/* Scan monsters */
2087 	for (i = 1; i < cave_monster_max(cave); i++) {
2088 		struct monster *mon = cave_monster(cave, i);
2089 
2090 		/* Skip dead monsters */
2091 		if (!mon->race) continue;
2092 
2093 		/* Location */
2094 		y = mon->grid.y;
2095 		x = mon->grid.x;
2096 
2097 		/* Only detect nearby monsters */
2098 		if (x < x1 || y < y1 || x > x2 || y > y2) continue;
2099 
2100 		/* Detect all appropriate, obvious monsters */
2101 		if (pred(mon) && !monster_is_camouflaged(mon)) {
2102 			/* Detect the monster */
2103 			mflag_on(mon->mflag, MFLAG_MARK);
2104 			mflag_on(mon->mflag, MFLAG_SHOW);
2105 
2106 			/* Note invisible monsters */
2107 			if (monster_is_invisible(mon)) {
2108 				struct monster_lore *lore = get_lore(mon->race);
2109 				rf_on(lore->flags, RF_INVISIBLE);
2110 			}
2111 
2112 			/* Update monster recall window */
2113 			if (player->upkeep->monster_race == mon->race)
2114 				/* Redraw stuff */
2115 				player->upkeep->redraw |= (PR_MONSTER);
2116 
2117 			/* Update the monster */
2118 			update_mon(mon, cave, false);
2119 
2120 			/* Detect */
2121 			monsters = true;
2122 		}
2123 	}
2124 
2125 	return monsters;
2126 }
2127 
2128 /**
2129  * Detect living monsters around the player.  The height to detect above and
2130  * below the player is context->value.dice, the width either side of the player
2131  * context->value.sides.
2132  */
effect_handler_DETECT_LIVING_MONSTERS(effect_handler_context_t * context)2133 bool effect_handler_DETECT_LIVING_MONSTERS(effect_handler_context_t *context)
2134 {
2135 	bool monsters = detect_monsters(context->y, context->x, monster_is_living);
2136 
2137 	if (monsters)
2138 		msg("You sense life!");
2139 	else if (context->aware)
2140 		msg("You sense no life.");
2141 
2142 	context->ident = true;
2143 	return true;
2144 }
2145 
2146 
2147 /**
2148  * Detect visible monsters around the player; note that this means monsters
2149  * which are in principle visible, not monsters the player can currently see.
2150  *
2151  * The height to detect above and
2152  * below the player is context->value.dice, the width either side of the player
2153  * context->value.sides.
2154  */
effect_handler_DETECT_VISIBLE_MONSTERS(effect_handler_context_t * context)2155 bool effect_handler_DETECT_VISIBLE_MONSTERS(effect_handler_context_t *context)
2156 {
2157 	bool monsters = detect_monsters(context->y, context->x,
2158 									monster_is_not_invisible);
2159 
2160 	if (monsters)
2161 		msg("You sense the presence of monsters!");
2162 	else if (context->aware)
2163 		msg("You sense no monsters.");
2164 
2165 	context->ident = true;
2166 	return true;
2167 }
2168 
2169 
2170 /**
2171  * Detect invisible monsters around the player.  The height to detect above and
2172  * below the player is context->value.dice, the width either side of the player
2173  * context->value.sides.
2174  */
effect_handler_DETECT_INVISIBLE_MONSTERS(effect_handler_context_t * context)2175 bool effect_handler_DETECT_INVISIBLE_MONSTERS(effect_handler_context_t *context)
2176 {
2177 	bool monsters = detect_monsters(context->y, context->x,
2178 									monster_is_invisible);
2179 
2180 	if (monsters)
2181 		msg("You sense the presence of invisible creatures!");
2182 	else if (context->aware)
2183 		msg("You sense no invisible creatures.");
2184 
2185 	context->ident = true;
2186 	return true;
2187 }
2188 
2189 /**
2190  * Detect monsters susceptible to fear around the player.  The height to detect
2191  * above and below the player is context->value.dice, the width either side of
2192  * the player context->value.sides.
2193  */
effect_handler_DETECT_FEARFUL_MONSTERS(effect_handler_context_t * context)2194 bool effect_handler_DETECT_FEARFUL_MONSTERS(effect_handler_context_t *context)
2195 {
2196 	bool monsters = detect_monsters(context->y, context->x, monster_is_fearful);
2197 
2198 	if (monsters)
2199 		msg("These monsters could provide good sport.");
2200 	else if (context->aware)
2201 		msg("You smell no fear in the air.");
2202 
2203 	context->ident = true;
2204 	return true;
2205 }
2206 
2207 /**
2208  * Detect evil monsters around the player.  The height to detect above and
2209  * below the player is context->value.dice, the width either side of the player
2210  * context->value.sides.
2211  */
effect_handler_DETECT_EVIL(effect_handler_context_t * context)2212 bool effect_handler_DETECT_EVIL(effect_handler_context_t *context)
2213 {
2214 	bool monsters = detect_monsters(context->y, context->x, monster_is_evil);
2215 
2216 	if (monsters)
2217 		msg("You sense the presence of evil creatures!");
2218 	else if (context->aware)
2219 		msg("You sense no evil creatures.");
2220 
2221 	context->ident = true;
2222 	return true;
2223 }
2224 
2225 /**
2226  * Detect monsters possessing a spirit around the player.
2227  * The height to detect above and below the player is context->value.dice,
2228  * the width either side of the player context->value.sides.
2229  */
effect_handler_DETECT_SOUL(effect_handler_context_t * context)2230 bool effect_handler_DETECT_SOUL(effect_handler_context_t *context)
2231 {
2232 	bool monsters = detect_monsters(context->y, context->x, monster_has_spirit);
2233 
2234 	if (monsters)
2235 		msg("You sense the presence of spirits!");
2236 	else if (context->aware)
2237 		msg("You sense no spirits.");
2238 
2239 	context->ident = true;
2240 	return true;
2241 }
2242 
2243 /**
2244  * Identify an unknown rune of an item.
2245  */
effect_handler_IDENTIFY(effect_handler_context_t * context)2246 bool effect_handler_IDENTIFY(effect_handler_context_t *context)
2247 {
2248 	struct object *obj;
2249 	const char *q, *s;
2250 	int itemmode = (USE_EQUIP | USE_INVEN | USE_QUIVER | USE_FLOOR);
2251 	bool used = false;
2252 
2253 	context->ident = true;
2254 
2255 	/* Get an item */
2256 	q = "Identify which item? ";
2257 	s = "You have nothing to identify.";
2258 	if (context->cmd) {
2259 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
2260 				item_tester_unknown, itemmode)) {
2261 			return used;
2262 		}
2263 	} else if (!get_item(&obj, q, s, 0, item_tester_unknown, itemmode))
2264 		return used;
2265 
2266 	/* Identify the object */
2267 	object_learn_unknown_rune(player, obj);
2268 
2269 	return true;
2270 }
2271 
2272 
2273 /**
2274  * Create stairs at the player location
2275  */
effect_handler_CREATE_STAIRS(effect_handler_context_t * context)2276 bool effect_handler_CREATE_STAIRS(effect_handler_context_t *context)
2277 {
2278 	context->ident = true;
2279 
2280 	/* Only allow stairs to be created on empty floor */
2281 	if (!square_isfloor(cave, player->grid)) {
2282 		msg("There is no empty floor here.");
2283 		return false;
2284 	}
2285 
2286 	/* Fails for persistent levels (for now) */
2287 	if (OPT(player, birth_levels_persist)) {
2288 		msg("Nothing happens!");
2289 		return false;
2290 	}
2291 
2292 	/* Push objects off the grid */
2293 	if (square_object(cave, player->grid))
2294 		push_object(player->grid);
2295 
2296 	square_add_stairs(cave, player->grid, player->depth);
2297 
2298 	return true;
2299 }
2300 
2301 /**
2302  * Apply disenchantment to the player's stuff.
2303  */
effect_handler_DISENCHANT(effect_handler_context_t * context)2304 bool effect_handler_DISENCHANT(effect_handler_context_t *context)
2305 {
2306 	int i, count = 0;
2307 	struct object *obj;
2308 	char o_name[80];
2309 
2310 	/* Count slots */
2311 	for (i = 0; i < player->body.count; i++) {
2312 		/* Ignore rings, amulets and lights */
2313 		if (slot_type_is(i, EQUIP_RING)) continue;
2314 		if (slot_type_is(i, EQUIP_AMULET)) continue;
2315 		if (slot_type_is(i, EQUIP_LIGHT)) continue;
2316 
2317 		/* Count disenchantable slots */
2318 		count++;
2319 	}
2320 
2321 	/* Pick one at random */
2322 	for (i = player->body.count - 1; i >= 0; i--) {
2323 		/* Ignore rings, amulets and lights */
2324 		if (slot_type_is(i, EQUIP_RING)) continue;
2325 		if (slot_type_is(i, EQUIP_AMULET)) continue;
2326 		if (slot_type_is(i, EQUIP_LIGHT)) continue;
2327 
2328 		if (one_in_(count--)) break;
2329 	}
2330 
2331 	/* Notice */
2332 	context->ident = true;
2333 
2334 	/* Get the item */
2335 	obj = slot_object(player, i);
2336 
2337 	/* No item, nothing happens */
2338 	if (!obj) return true;
2339 
2340 	/* Nothing to disenchant */
2341 	if ((obj->to_h <= 0) && (obj->to_d <= 0) && (obj->to_a <= 0))
2342 		return true;
2343 
2344 	/* Describe the object */
2345 	object_desc(o_name, sizeof(o_name), obj, ODESC_BASE);
2346 
2347 	/* Artifacts have a 60% chance to resist */
2348 	if (obj->artifact && (randint0(100) < 60)) {
2349 		/* Message */
2350 		msg("Your %s (%c) resist%s disenchantment!", o_name, I2A(i),
2351 			((obj->number != 1) ? "" : "s"));
2352 
2353 		return true;
2354 	}
2355 
2356 	/* Apply disenchantment, depending on which kind of equipment */
2357 	if (slot_type_is(i, EQUIP_WEAPON) || slot_type_is(i, EQUIP_BOW)) {
2358 		/* Disenchant to-hit */
2359 		if (obj->to_h > 0) obj->to_h--;
2360 		if ((obj->to_h > 5) && (randint0(100) < 20)) obj->to_h--;
2361 		obj->known->to_h = obj->to_h;
2362 
2363 		/* Disenchant to-dam */
2364 		if (obj->to_d > 0) obj->to_d--;
2365 		if ((obj->to_d > 5) && (randint0(100) < 20)) obj->to_d--;
2366 		obj->known->to_d = obj->to_d;
2367 	} else {
2368 		/* Disenchant to-ac */
2369 		if (obj->to_a > 0) obj->to_a--;
2370 		if ((obj->to_a > 5) && (randint0(100) < 20)) obj->to_a--;
2371 		obj->known->to_a = obj->to_a;
2372 	}
2373 
2374 	/* Message */
2375 	msg("Your %s (%c) %s disenchanted!", o_name, I2A(i),
2376 		((obj->number != 1) ? "were" : "was"));
2377 
2378 	/* Recalculate bonuses */
2379 	player->upkeep->update |= (PU_BONUS);
2380 
2381 	/* Window stuff */
2382 	player->upkeep->redraw |= (PR_EQUIP);
2383 
2384 	return true;
2385 }
2386 
2387 /**
2388  * Enchant an item (in the inventory or on the floor)
2389  * Note that armour, to hit or to dam is controlled by context->subtype
2390  *
2391  * Work on incorporating enchant_spell() has been postponed...NRM
2392  */
effect_handler_ENCHANT(effect_handler_context_t * context)2393 bool effect_handler_ENCHANT(effect_handler_context_t *context)
2394 {
2395 	int value = randcalc(context->value, player->depth, RANDOMISE);
2396 	bool used = false;
2397 	context->ident = true;
2398 
2399 	if ((context->subtype & ENCH_TOBOTH) == ENCH_TOBOTH) {
2400 		if (enchant_spell(value, value, 0, context->cmd))
2401 			used = true;
2402 	}
2403 	else if (context->subtype & ENCH_TOHIT) {
2404 		if (enchant_spell(value, 0, 0, context->cmd))
2405 			used = true;
2406 	}
2407 	else if (context->subtype & ENCH_TODAM) {
2408 		if (enchant_spell(0, value, 0, context->cmd))
2409 			used = true;
2410 	}
2411 	if (context->subtype & ENCH_TOAC) {
2412 		if (enchant_spell(0, 0, value, context->cmd))
2413 			used = true;
2414 	}
2415 
2416 	return used;
2417 }
2418 
2419 /**
2420  * Returns N which is the 1 in N chance for recharging to fail.
2421  */
recharge_failure_chance(const struct object * obj,int strength)2422 int recharge_failure_chance(const struct object *obj, int strength) {
2423 	/* Ease of recharge ranges from 9 down to 4 (wands) or 3 (staffs) */
2424 	int ease_of_recharge = (100 - obj->kind->level) / 10;
2425 	int raw_chance = strength + ease_of_recharge
2426 		- 2 * (obj->pval / obj->number);
2427 	return raw_chance > 1 ? raw_chance : 1;
2428 }
2429 
2430 /**
2431  * Recharge a wand or staff from the pack or on the floor.  Recharge strength
2432  * is context->value.base.
2433  *
2434  * It is harder to recharge high level, and highly charged wands.
2435  */
effect_handler_RECHARGE(effect_handler_context_t * context)2436 bool effect_handler_RECHARGE(effect_handler_context_t *context)
2437 {
2438 	int i, t;
2439 	int strength = context->value.base;
2440 	int itemmode = (USE_INVEN | USE_FLOOR | SHOW_RECHARGE);
2441 	struct object *obj;
2442 	bool used = false;
2443 	const char *q, *s;
2444 
2445 	/* Immediately obvious */
2446 	context->ident = true;
2447 
2448 	/* Used to show recharge failure rates */
2449 	player->upkeep->recharge_pow = strength;
2450 
2451 	/* Get an item */
2452 	q = "Recharge which item? ";
2453 	s = "You have nothing to recharge.";
2454 	if (context->cmd) {
2455 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
2456 				item_tester_hook_recharge, itemmode)) {
2457 			return used;
2458 		}
2459 	} else if (!get_item(&obj, q, s, 0, item_tester_hook_recharge,
2460 				  itemmode)) {
2461 		return (used);
2462 	}
2463 
2464 	i = recharge_failure_chance(obj, strength);
2465 	/* Back-fire */
2466 	if ((i <= 1) || one_in_(i)) {
2467 		struct object *destroyed;
2468 		bool none_left = false;
2469 
2470 		msg("The recharge backfires!");
2471 		msg("There is a bright flash of light.");
2472 
2473 		/* Reduce and describe inventory */
2474 		if (object_is_carried(player, obj))
2475 			destroyed = gear_object_for_use(obj, 1, true, &none_left);
2476 		else
2477 			destroyed = floor_object_for_use(obj, 1, true, &none_left);
2478 		if (destroyed->known)
2479 			object_delete(&destroyed->known);
2480 		object_delete(&destroyed);
2481 	} else {
2482 		/* Extract a "power" */
2483 		int ease_of_recharge = (100 - obj->kind->level) / 10;
2484 		t = (strength / (10 - ease_of_recharge)) + 1;
2485 
2486 		/* Recharge based on the power */
2487 		if (t > 0) obj->pval += 2 + randint1(t);
2488 	}
2489 
2490 	/* Combine the pack (later) */
2491 	player->upkeep->notice |= (PN_COMBINE);
2492 
2493 	/* Redraw stuff */
2494 	player->upkeep->redraw |= (PR_INVEN);
2495 
2496 	/* Something was done */
2497 	return true;
2498 }
2499 
2500 /**
2501  * Apply a "project()" directly to all viewable monsters.  If context->other is
2502  * set, the effect damage boost is applied.  This is a hack - NRM
2503  *
2504  * Note that affected monsters are NOT auto-tracked by this usage.
2505  */
effect_handler_PROJECT_LOS(effect_handler_context_t * context)2506 bool effect_handler_PROJECT_LOS(effect_handler_context_t *context)
2507 {
2508 	int i;
2509 	int dam = effect_calculate_value(context, context->other ? true : false);
2510 	int typ = context->subtype;
2511 	struct loc origin = origin_get_loc(context->origin);
2512 	int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
2513 
2514 	/* Affect all (nearby) monsters */
2515 	for (i = 1; i < cave_monster_max(cave); i++) {
2516 		struct monster *mon = cave_monster(cave, i);
2517 
2518 		/* Paranoia -- Skip dead monsters */
2519 		if (!mon->race) continue;
2520 
2521 		/* Require line of sight */
2522 		if (!los(cave, origin, mon->grid)) continue;
2523 
2524 		/* Jump directly to the monster */
2525 		(void)project(source_player(), 0, mon->grid, dam, typ, flg, 0, 0,
2526 					  context->obj);
2527 		context->ident = true;
2528 	}
2529 
2530 	/* Result */
2531 	return true;
2532 }
2533 
2534 /**
2535  * Just like PROJECT_LOS except the player's awareness of an object using
2536  * this effect is relevant.
2537  *
2538  * Note that affected monsters are NOT auto-tracked by this usage.
2539  */
effect_handler_PROJECT_LOS_AWARE(effect_handler_context_t * context)2540 bool effect_handler_PROJECT_LOS_AWARE(effect_handler_context_t *context)
2541 {
2542 	int i;
2543 	int dam = effect_calculate_value(context, context->other ? true : false);
2544 	int typ = context->subtype;
2545 
2546 	int flg = PROJECT_JUMP | PROJECT_KILL | PROJECT_HIDE;
2547 
2548 	if (context->aware) flg |= PROJECT_AWARE;
2549 
2550 	/* Affect all (nearby) monsters */
2551 	for (i = 1; i < cave_monster_max(cave); i++) {
2552 		struct monster *mon = cave_monster(cave, i);
2553 		struct loc grid;
2554 
2555 		/* Paranoia -- Skip dead monsters */
2556 		if (!mon->race) continue;
2557 
2558 		/* Location */
2559 		grid = mon->grid;
2560 
2561 		/* Require line of sight */
2562 		if (!square_isview(cave, grid)) continue;
2563 
2564 		/* Jump directly to the target monster */
2565 		(void)project(source_player(), 0, grid, dam, typ, flg, 0, 0, context->obj);
2566 		context->ident = true;
2567 	}
2568 
2569 	/* Result */
2570 	return true;
2571 }
2572 
effect_handler_ACQUIRE(effect_handler_context_t * context)2573 bool effect_handler_ACQUIRE(effect_handler_context_t *context)
2574 {
2575 	int num = effect_calculate_value(context, false);
2576 	acquirement(player->grid, player->depth, num, true);
2577 	context->ident = true;
2578 	return true;
2579 }
2580 
2581 /**
2582  * Wake up all monsters in line of sight
2583  */
effect_handler_WAKE(effect_handler_context_t * context)2584 bool effect_handler_WAKE(effect_handler_context_t *context)
2585 {
2586 	int i;
2587 	bool woken = false;
2588 
2589 	struct loc origin = origin_get_loc(context->origin);
2590 
2591 	/* Wake everyone nearby */
2592 	for (i = 1; i < cave_monster_max(cave); i++) {
2593 		struct monster *mon = cave_monster(cave, i);
2594 		if (mon->race) {
2595 			int radius = z_info->max_sight * 2;
2596 			int dist = distance(origin, mon->grid);
2597 
2598 			/* Skip monsters too far away */
2599 			if ((dist < radius) && mon->m_timed[MON_TMD_SLEEP]) {
2600 				/* Monster wakes, closer means likelier to become aware */
2601 				monster_wake(mon, false, 100 - 2 * dist);
2602 				woken = true;
2603 			}
2604 		}
2605 	}
2606 
2607 	/* Messages */
2608 	if (woken) {
2609 		msg("You hear a sudden stirring in the distance!");
2610 	}
2611 
2612 	context->ident = true;
2613 
2614 	return true;
2615 }
2616 
2617 /**
2618  * Summon context->value monsters of context->subtype type.
2619  */
effect_handler_SUMMON(effect_handler_context_t * context)2620 bool effect_handler_SUMMON(effect_handler_context_t *context)
2621 {
2622 	int summon_max = effect_calculate_value(context, false);
2623 	int summon_type = context->subtype;
2624 	int level_boost = context->other;
2625 	int message_type = summon_message_type(summon_type);
2626 	int fallback_type = summon_fallback_type(summon_type);
2627 	int count = 0, val = 0, attempts = 0;
2628 
2629 	sound(message_type);
2630 
2631 	/* No summoning in arena levels */
2632 	if (player->upkeep->arena_level) return true;
2633 
2634 	/* Monster summon */
2635 	if (context->origin.what == SRC_MONSTER) {
2636 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
2637 		int rlev;
2638 
2639 		assert(mon);
2640 
2641 		/* Set the kin_base if necessary */
2642 		if (summon_type == summon_name_to_idx("KIN")) {
2643 			kin_base = mon->race->base;
2644 		}
2645 
2646 		/* Continue summoning until we reach the current dungeon level */
2647 		rlev = mon->race->level;
2648 		while ((val < player->depth * rlev) && (attempts < summon_max)) {
2649 			int temp;
2650 
2651 			/* Get a monster */
2652 			temp = summon_specific(mon->grid, rlev + level_boost, summon_type,
2653 								   false, false);
2654 
2655 			val += temp * temp;
2656 
2657 			/* Increase the attempt in case no monsters were available. */
2658 			attempts++;
2659 
2660 			/* Increase count of summoned monsters */
2661 			if (val > 0)
2662 				count++;
2663 		}
2664 
2665 		/* If the summon failed and there's a fallback type, use that */
2666 		if ((count == 0) && (fallback_type >= 0)) {
2667 			attempts = 0;
2668 			while ((val < player->depth * rlev) && (attempts < summon_max)) {
2669 				int temp;
2670 
2671 				/* Get a monster */
2672 				temp = summon_specific(mon->grid, rlev + level_boost,
2673 									   fallback_type, false, false);
2674 
2675 				val += temp * temp;
2676 
2677 				/* Increase the attempt in case no monsters were available. */
2678 				attempts++;
2679 
2680 				/* Increase count of summoned monsters */
2681 				if (val > 0)
2682 					count++;
2683 			}
2684 		}
2685 
2686 		/* Summoner failed */
2687 		if (!count)
2688 			msg("But nothing comes.");
2689 	} else {
2690 		/* If not a monster summon, it's simple */
2691 		while (summon_max) {
2692 			count += summon_specific(player->grid, player->depth + level_boost,
2693 									 summon_type, true, one_in_(4));
2694 			summon_max--;
2695 		}
2696 	}
2697 
2698 	/* Identify */
2699 	context->ident = true;
2700 
2701 	/* Message for the blind */
2702 	if (count && player->timed[TMD_BLIND])
2703 		msgt(message_type, "You hear %s appear nearby.",
2704 			 (count > 1 ? "many things" : "something"));
2705 
2706 	return true;
2707 }
2708 
2709 /**
2710  * Delete all non-unique monsters of a given "type" from the level
2711  * -------
2712  * Warning - this function assumes that the entered monster symbol is an ASCII
2713  *		   character, which may not be true in the future - NRM
2714  * -------
2715  */
effect_handler_BANISH(effect_handler_context_t * context)2716 bool effect_handler_BANISH(effect_handler_context_t *context)
2717 {
2718 	int i;
2719 	unsigned dam = 0;
2720 
2721 	char typ;
2722 
2723 	context->ident = true;
2724 
2725 	if (!get_com("Choose a monster race (by symbol) to banish: ", &typ))
2726 		return false;
2727 
2728 	/* Delete the monsters of that "type" */
2729 	for (i = 1; i < cave_monster_max(cave); i++) {
2730 		struct monster *mon = cave_monster(cave, i);
2731 
2732 		/* Paranoia -- Skip dead monsters */
2733 		if (!mon->race) continue;
2734 
2735 		/* Hack -- Skip Unique Monsters */
2736 		if (monster_is_unique(mon)) continue;
2737 
2738 		/* Skip "wrong" monsters (see warning above) */
2739 		if ((char) mon->race->d_char != typ) continue;
2740 
2741 		/* Delete the monster */
2742 		delete_monster_idx(i);
2743 
2744 		/* Take some damage */
2745 		dam += randint1(4);
2746 	}
2747 
2748 	/* Hurt the player */
2749 	take_hit(player, dam, "the strain of casting Banishment");
2750 
2751 	/* Update monster list window */
2752 	player->upkeep->redraw |= PR_MONLIST;
2753 
2754 	/* Success */
2755 	return true;
2756 }
2757 
2758 /**
2759  * Delete all nearby (non-unique) monsters.  The radius of effect is
2760  * context->radius if passed, otherwise the player view radius.
2761  */
effect_handler_MASS_BANISH(effect_handler_context_t * context)2762 bool effect_handler_MASS_BANISH(effect_handler_context_t *context)
2763 {
2764 	int i;
2765 	int radius = context->radius ? context->radius : z_info->max_sight;
2766 	unsigned dam = 0;
2767 
2768 	context->ident = true;
2769 
2770 	/* Delete the (nearby) monsters */
2771 	for (i = 1; i < cave_monster_max(cave); i++) {
2772 		struct monster *mon = cave_monster(cave, i);
2773 
2774 		/* Paranoia -- Skip dead monsters */
2775 		if (!mon->race) continue;
2776 
2777 		/* Hack -- Skip unique monsters */
2778 		if (monster_is_unique(mon)) continue;
2779 
2780 		/* Skip distant monsters */
2781 		if (mon->cdis > radius) continue;
2782 
2783 		/* Delete the monster */
2784 		delete_monster_idx(i);
2785 
2786 		/* Take some damage */
2787 		dam += randint1(3);
2788 	}
2789 
2790 	/* Hurt the player */
2791 	take_hit(player, dam, "the strain of casting Mass Banishment");
2792 
2793 	/* Update monster list window */
2794 	player->upkeep->redraw |= PR_MONLIST;
2795 
2796 	return true;
2797 }
2798 
2799 /**
2800  * Probe nearby monsters
2801  */
effect_handler_PROBE(effect_handler_context_t * context)2802 bool effect_handler_PROBE(effect_handler_context_t *context)
2803 {
2804 	int i;
2805 
2806 	bool probe = false;
2807 
2808 	/* Probe all (nearby) monsters */
2809 	for (i = 1; i < cave_monster_max(cave); i++) {
2810 		struct monster *mon = cave_monster(cave, i);
2811 
2812 		/* Paranoia -- Skip dead monsters */
2813 		if (!mon->race) continue;
2814 
2815 		/* Require line of sight */
2816 		if (!square_isview(cave, mon->grid)) continue;
2817 
2818 		/* Probe visible monsters */
2819 		if (monster_is_visible(mon)) {
2820 			char m_name[80];
2821 
2822 			/* Start the message */
2823 			if (!probe) msg("Probing...");
2824 
2825 			/* Get "the monster" or "something" */
2826 			monster_desc(m_name, sizeof(m_name), mon,
2827 					MDESC_IND_HID | MDESC_CAPITAL);
2828 
2829 			/* Describe the monster */
2830 			msg("%s has %d hit point%s.", m_name, mon->hp, (mon->hp == 1) ? "" : "s");
2831 
2832 			/* Learn all of the non-spell, non-treasure flags */
2833 			lore_do_probe(mon);
2834 
2835 			/* Probe worked */
2836 			probe = true;
2837 		}
2838 	}
2839 
2840 	/* Done */
2841 	if (probe) {
2842 		msg("That's all.");
2843 		context->ident = true;
2844 	}
2845 
2846 	return true;
2847 }
2848 
2849 /**
2850  * Teleport player or monster up to context->value.base grids away.
2851  *
2852  * If no spaces are readily available, the distance may increase.
2853  * Try very hard to move the player/monster at least a quarter that distance.
2854  * Setting context->subtype allows monsters to teleport the player away.
2855  * Setting context->y and context->x treats them as y and x coordinates
2856  * and teleports the monster from that grid.
2857  */
effect_handler_TELEPORT(effect_handler_context_t * context)2858 bool effect_handler_TELEPORT(effect_handler_context_t *context)
2859 {
2860 	struct loc start = loc(context->x, context->y);
2861 	int dis = context->value.base;
2862 	int perc = context->value.m_bonus;
2863 	int pick;
2864 	struct loc grid;
2865 
2866 	struct jumps {
2867 		struct loc grid;
2868 		struct jumps *next;
2869 	} *spots = NULL;
2870 	int num_spots = 0;
2871 	int current_score = 2 * MAX(z_info->dungeon_wid, z_info->dungeon_hgt);
2872 	bool only_vault_grids_possible = true;
2873 
2874 	bool is_player = (context->origin.what != SRC_MONSTER || context->subtype);
2875 	struct monster *t_mon = monster_target_monster(context);
2876 
2877 	context->ident = true;
2878 
2879 	/* No teleporting in arena levels */
2880 	if (player->upkeep->arena_level) return true;
2881 
2882 	/* Establish the coordinates to teleport from, if we don't know already */
2883 	if (!loc_is_zero(start)) {
2884 		/* We're good */
2885 	} else if (t_mon) {
2886 		/* Monster targeting another monster */
2887 		start = t_mon->grid;
2888 	} else if (is_player) {
2889 		/* Decoys get destroyed */
2890 		struct loc decoy = cave_find_decoy(cave);
2891 		if (!loc_is_zero(decoy) && context->subtype) {
2892 			square_destroy_decoy(cave, decoy);
2893 			return true;
2894 		}
2895 
2896 		start = player->grid;
2897 
2898 		/* Check for a no teleport grid */
2899 		if (square_isno_teleport(cave, start) &&
2900 			((dis > 10) || (dis == 0))) {
2901 			msg("Teleportation forbidden!");
2902 			return true;
2903 		}
2904 
2905 		/* Check for a no teleport curse */
2906 		if (player_of_has(player, OF_NO_TELEPORT)) {
2907 			equip_learn_flag(player, OF_NO_TELEPORT);
2908 			msg("Teleportation forbidden!");
2909 			return true;
2910 		}
2911 	} else {
2912 		assert(context->origin.what == SRC_MONSTER);
2913 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
2914 		start = mon->grid;
2915 	}
2916 
2917 	/* Percentage of the largest cardinal distance to an edge */
2918 	if (perc) {
2919 		int vertical = MAX(start.y, cave->height - start.y);
2920 		int horizontal = MAX(start.x, cave->width - start.x);
2921 		dis = (MAX(vertical, horizontal) * perc) / 100;
2922 	}
2923 
2924 	/* Randomise the distance a little */
2925 	if (one_in_(2)) {
2926 		dis -= randint0(dis / 4);
2927 	} else {
2928 		dis += randint0(dis / 4);
2929 	}
2930 
2931 	/* Make a list of the best grids, scoring by how good an approximation
2932 	 * the distance from the start is to the distance we want */
2933 	for (grid.y = 1; grid.y < cave->height - 1; grid.y++) {
2934 		for (grid.x = 1; grid.x < cave->width - 1; grid.x++) {
2935 			int d = distance(grid, start);
2936 			int score = ABS(d - dis);
2937 			struct jumps *new;
2938 
2939 			/* Must move */
2940 			if (d == 0) continue;
2941 
2942 			/* Require "naked" floor space */
2943 			if (!square_isempty(cave, grid)) continue;
2944 
2945 			/* No monster teleport onto glyph of warding */
2946 			if (!is_player && square_iswarded(cave, grid)) continue;
2947 
2948 			/* No teleporting into vaults and such, unless there's no choice */
2949 			if (square_isvault(cave, grid)) {
2950 				if (!only_vault_grids_possible) {
2951 					continue;
2952 				}
2953 			} else {
2954 				/* Just starting to consider non-vault grids, so reset score */
2955 				if (only_vault_grids_possible) {
2956 					current_score = 2 * MAX(z_info->dungeon_wid,
2957 											z_info->dungeon_hgt);
2958 				}
2959 				only_vault_grids_possible = false;
2960 			}
2961 
2962 			/* Do we have better spots already? */
2963 			if (score > current_score) continue;
2964 
2965 			/* Make a new spot */
2966 			new = mem_zalloc(sizeof(struct jumps));
2967 			new->grid = grid;
2968 
2969 			/* If improving start a new list, otherwise extend the old one */
2970 			if (score < current_score) {
2971 				current_score = score;
2972 				while (spots) {
2973 					struct jumps *next = spots->next;
2974 					mem_free(spots);
2975 					spots = next;
2976 				}
2977 				spots = new;
2978 				num_spots = 1;
2979 			} else {
2980 				new->next = spots;
2981 				spots = new;
2982 				num_spots++;
2983 			}
2984 		}
2985 	}
2986 
2987 	/* Report failure (very unlikely) */
2988 	if (!num_spots) {
2989 		msg("Failed to find teleport destination!");
2990 		return true;
2991 	}
2992 
2993 	/* Pick a spot */
2994 	pick = randint0(num_spots);
2995 	while (pick) {
2996 		struct jumps *next = spots->next;
2997 		mem_free(spots);
2998 		spots = next;
2999 		pick--;
3000 	}
3001 
3002 	/* Sound */
3003 	sound(is_player ? MSG_TELEPORT : MSG_TPOTHER);
3004 
3005 	/* Move player */
3006 	monster_swap(start, spots->grid);
3007 
3008 	/* Clear any projection marker to prevent double processing */
3009 	sqinfo_off(square(cave, spots->grid)->info, SQUARE_PROJECT);
3010 
3011 	/* Clear monster target if it's no longer visible */
3012 	if (!target_able(target_get_monster())) {
3013 		target_set_monster(NULL);
3014 	}
3015 
3016 	/* Lots of updates after monster_swap */
3017 	handle_stuff(player);
3018 
3019 	while (spots) {
3020 		struct jumps *next = spots->next;
3021 		mem_free(spots);
3022 		spots = next;
3023 	}
3024 
3025 	return true;
3026 }
3027 
3028 /**
3029  * Teleport player or target monster to a grid near the given location
3030  * Setting context->y and context->x treats them as y and x coordinates
3031  * Setting context->subtype allows monsters to teleport toward the player.
3032  *
3033  * This function is slightly obsessive about correctness.
3034  * This function allows teleporting into vaults (!)
3035  */
effect_handler_TELEPORT_TO(effect_handler_context_t * context)3036 bool effect_handler_TELEPORT_TO(effect_handler_context_t *context)
3037 {
3038 	struct monster *mon = NULL;
3039 	struct loc start, aim, land;
3040 	int dis = 0, ctr = 0, dir = DIR_TARGET;
3041 	struct monster *t_mon = monster_target_monster(context);
3042 
3043 	context->ident = true;
3044 
3045 	/* No teleporting in arena levels */
3046 	if (player->upkeep->arena_level) return true;
3047 
3048 	if (context->origin.what == SRC_MONSTER) {
3049 		mon = cave_monster(cave, context->origin.which.monster);
3050 		assert(mon);
3051 	}
3052 
3053 	/* Where are we coming from? */
3054 	if (t_mon) {
3055 		/* Monster being teleported */
3056 		start = t_mon->grid;
3057 	} else if (context->subtype) {
3058 		/* Monster teleporting to the player */
3059 		start = mon->grid;
3060 	} else {
3061 		/* Targeted decoys get destroyed */
3062 		struct loc decoy = cave_find_decoy(cave);
3063 		if (!loc_is_zero(decoy) && mon) {
3064 			square_destroy_decoy(cave, decoy);
3065 			return true;
3066 		}
3067 
3068 		/* Player being teleported */
3069 		start = player->grid;
3070 
3071 		/* Check for a no teleport grid */
3072 		if (square_isno_teleport(cave, start)) {
3073 			msg("Teleportation forbidden!");
3074 			return true;
3075 		}
3076 
3077 		/* Check for a no teleport curse */
3078 		if (player_of_has(player, OF_NO_TELEPORT)) {
3079 			equip_learn_flag(player, OF_NO_TELEPORT);
3080 			msg("Teleportation forbidden!");
3081 			return true;
3082 		}
3083 	}
3084 
3085 	/* Where are we going? */
3086 	if (context->y && context->x) {
3087 		/* Effect was given co-ordinates */
3088 		aim = loc(context->x, context->y);
3089 	} else if (mon) {
3090 		/* Spell cast by monster */
3091 		if (context->subtype) {
3092 			/* Monster teleporting to player */
3093 			aim = player->grid;
3094 			dis = 2;
3095 		} else {
3096 			/* Player being teleported to monster */
3097 			aim = mon->grid;
3098 		}
3099 	} else {
3100 		/* Player choice */
3101 		do {
3102 			get_aim_dir(&dir);
3103 		} while (dir == DIR_TARGET && !target_okay());
3104 
3105 		if (dir == DIR_TARGET)
3106 			target_get(&aim);
3107 		else
3108 			aim = loc_offset(start, ddx[dir], ddy[dir]);
3109 
3110 		/* Randomise the landing a bit if it's a vault */
3111 		if (square_isvault(cave, aim)) dis = 10;
3112 	}
3113 
3114 	/* Find a usable location */
3115 	while (1) {
3116 		/* Pick a nearby legal location */
3117 		while (1) {
3118 			land = rand_loc(aim, dis, dis);
3119 			if (square_in_bounds_fully(cave, land)) break;
3120 		}
3121 
3122 		/* Accept "naked" floor grids */
3123 		if (square_isempty(cave, land)) break;
3124 
3125 		/* Occasionally advance the distance */
3126 		if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
3127 			ctr = 0;
3128 			dis++;
3129 		}
3130 	}
3131 
3132 	/* Sound */
3133 	sound(MSG_TELEPORT);
3134 
3135 	/* Move player or monster */
3136 	monster_swap(start, land);
3137 
3138 	/* Clear any projection marker to prevent double processing */
3139 	sqinfo_off(square(cave, land)->info, SQUARE_PROJECT);
3140 
3141 	/* Lots of updates after monster_swap */
3142 	handle_stuff(player);
3143 
3144 	return true;
3145 }
3146 
3147 /**
3148  * Teleport the player one level up or down (random when legal)
3149  */
effect_handler_TELEPORT_LEVEL(effect_handler_context_t * context)3150 bool effect_handler_TELEPORT_LEVEL(effect_handler_context_t *context)
3151 {
3152 	bool up = true;
3153 	bool down = true;
3154 	int target_depth = dungeon_get_next_level(player->max_depth, 1);
3155 	struct monster *t_mon = monster_target_monster(context);
3156 	struct loc decoy = cave_find_decoy(cave);
3157 
3158 	context->ident = true;
3159 
3160 	/* No teleporting in arena levels */
3161 	if (player->upkeep->arena_level) return true;
3162 
3163 	/* Check for monster targeting another monster */
3164 	if (t_mon) {
3165 		/* Monster is just gone */
3166 		add_monster_message(t_mon, MON_MSG_DISAPPEAR, false);
3167 		delete_monster_idx(t_mon->midx);
3168 		return true;
3169 	}
3170 
3171 	/* Targeted decoys get destroyed */
3172 	if (decoy.y && decoy.x) {
3173 		square_destroy_decoy(cave, decoy);
3174 		return true;
3175 	}
3176 
3177 	/* Check for a no teleport grid */
3178 	if (square_isno_teleport(cave, player->grid)) {
3179 		msg("Teleportation forbidden!");
3180 		return true;
3181 	}
3182 
3183 	/* Check for a no teleport curse */
3184 	if (player_of_has(player, OF_NO_TELEPORT)) {
3185 		equip_learn_flag(player, OF_NO_TELEPORT);
3186 		msg("Teleportation forbidden!");
3187 		return true;
3188 	}
3189 
3190 	/* Resist hostile teleport */
3191 	if (context->origin.what == SRC_MONSTER &&
3192 			player_resists(player, ELEM_NEXUS)) {
3193 		msg("You resist the effect!");
3194 		return true;
3195 	}
3196 
3197 	/* No going up with force_descend or in the town */
3198 	if (OPT(player, birth_force_descend) || !player->depth)
3199 		up = false;
3200 
3201 	/* No forcing player down to quest levels if they can't leave */
3202 	if (!up && is_quest(target_depth))
3203 		down = false;
3204 
3205 	/* Can't leave quest levels or go down deeper than the dungeon */
3206 	if (is_quest(player->depth) || (player->depth >= z_info->max_depth - 1))
3207 		down = false;
3208 
3209 	/* Determine up/down if not already done */
3210 	if (up && down) {
3211 		if (randint0(100) < 50)
3212 			up = false;
3213 		else
3214 			down = false;
3215 	}
3216 
3217 	/* Now actually do the level change */
3218 	if (up) {
3219 		msgt(MSG_TPLEVEL, "You rise up through the ceiling.");
3220 		target_depth = dungeon_get_next_level(player->depth, -1);
3221 		dungeon_change_level(player, target_depth);
3222 	} else if (down) {
3223 		msgt(MSG_TPLEVEL, "You sink through the floor.");
3224 
3225 		if (OPT(player, birth_force_descend)) {
3226 			target_depth = dungeon_get_next_level(player->max_depth, 1);
3227 			dungeon_change_level(player, target_depth);
3228 		} else {
3229 			target_depth = dungeon_get_next_level(player->depth, 1);
3230 			dungeon_change_level(player, target_depth);
3231 		}
3232 	} else {
3233 		msg("Nothing happens.");
3234 	}
3235 
3236 	return true;
3237 }
3238 
3239 /**
3240  * The rubble effect
3241  *
3242  * This causes rubble to fall into empty squares.
3243  */
effect_handler_RUBBLE(effect_handler_context_t * context)3244 bool effect_handler_RUBBLE(effect_handler_context_t *context)
3245 {
3246 	/*
3247 	 * First we work out how many grids we want to fill with rubble.  Then we
3248 	 * check that we can actually do this, by counting the number of grids
3249 	 * available, limiting the number of rubble grids to this number if
3250 	 * necessary.
3251 	 */
3252 	int rubble_grids = randint1(3);
3253 	int open_grids = count_feats(NULL, square_isempty, false);
3254 
3255 	if (rubble_grids > open_grids) {
3256 		rubble_grids = open_grids;
3257 	}
3258 
3259 	/* Avoid infinite loops */
3260 	int iterations = 0;
3261 
3262 	while (rubble_grids > 0 && iterations < 10) {
3263 		/* Look around the player */
3264 		for (int d = 0; d < 8; d++) {
3265 			/* Extract adjacent (legal) location */
3266 			struct loc grid = loc_sum(player->grid, ddgrid_ddd[d]);
3267 			if (!square_in_bounds_fully(cave, grid)) continue;
3268 			if (!square_isempty(cave, grid)) continue;
3269 
3270 			if (one_in_(3)) {
3271 				if (one_in_(2))
3272 					square_set_feat(cave, grid, FEAT_PASS_RUBBLE);
3273 				else
3274 					square_set_feat(cave, grid, FEAT_RUBBLE);
3275 				rubble_grids--;
3276 			}
3277 		}
3278 
3279 		iterations++;
3280 	}
3281 
3282 	context->ident = true;
3283 
3284 	/* Fully update the visuals */
3285 	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
3286 
3287 	/* Redraw monster list */
3288 	player->upkeep->redraw |= (PR_MONLIST | PR_ITEMLIST);
3289 
3290 	return true;
3291 }
3292 
effect_handler_GRANITE(effect_handler_context_t * context)3293 bool effect_handler_GRANITE(effect_handler_context_t *context)
3294 {
3295 	struct trap *trap = context->origin.which.trap;
3296 	square_set_feat(cave, trap->grid, FEAT_GRANITE);
3297 
3298 	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
3299 	player->upkeep->redraw |= (PR_MONLIST | PR_ITEMLIST);
3300 
3301 	return true;
3302 }
3303 
3304 /**
3305  * The destruction effect
3306  *
3307  * This effect "deletes" monsters (instead of killing them).
3308  *
3309  * This is always an effect centred on the player; it is similar to the
3310  * earthquake effect.
3311  */
effect_handler_DESTRUCTION(effect_handler_context_t * context)3312 bool effect_handler_DESTRUCTION(effect_handler_context_t *context)
3313 {
3314 	int k, r = context->radius;
3315 	int elem = context->subtype;
3316 	int py = player->grid.y;
3317 	int px = player->grid.x;
3318 	struct loc grid;
3319 
3320 	context->ident = true;
3321 
3322 	/* No effect in town or arena */
3323 	if ((!player->depth) || (player->upkeep->arena_level)) {
3324 		msg("The ground shakes for a moment.");
3325 		return true;
3326 	}
3327 
3328 	/* Big area of affect */
3329 	for (grid.y = (py - r); grid.y <= (py + r); grid.y++) {
3330 		for (grid.x = (px - r); grid.x <= (px + r); grid.x++) {
3331 			/* Skip illegal grids */
3332 			if (!square_in_bounds_fully(cave, grid)) continue;
3333 
3334 			/* Extract the distance */
3335 			k = distance(loc(px, py), grid);
3336 
3337 			/* Stay in the circle of death */
3338 			if (k > r) continue;
3339 
3340 			/* Lose room and vault */
3341 			sqinfo_off(square(cave, grid)->info, SQUARE_ROOM);
3342 			sqinfo_off(square(cave, grid)->info, SQUARE_VAULT);
3343 
3344 			/* Forget completely */
3345 			if (!square_isbright(cave, grid)) {
3346 				sqinfo_off(square(cave, grid)->info, SQUARE_GLOW);
3347 			}
3348 			sqinfo_off(square(cave, grid)->info, SQUARE_SEEN);
3349 			square_forget(cave, grid);
3350 			square_light_spot(cave, grid);
3351 
3352 			/* Deal with player later */
3353 			if (loc_eq(grid, player->grid)) continue;
3354 
3355 			/* Delete the monster (if any) */
3356 			delete_monster(grid);
3357 
3358 			/* Don't remove stairs */
3359 			if (square_isstairs(cave, grid)) continue;
3360 
3361 			/* Destroy any grid that isn't a permament wall */
3362 			if (!square_isperm(cave, grid)) {
3363 				/* Deal with artifacts */
3364 				struct object *obj = square_object(cave, grid);
3365 				while (obj) {
3366 					if (obj->artifact) {
3367 						if (OPT(player, birth_lose_arts) ||
3368 							obj_is_known_artifact(obj)) {
3369 							history_lose_artifact(player, obj->artifact);
3370 							obj->artifact->created = true;
3371 						} else {
3372 							obj->artifact->created = false;
3373 						}
3374 					}
3375 					obj = obj->next;
3376 				}
3377 
3378 				/* Delete objects */
3379 				square_excise_pile(player->cave, grid);
3380 				square_excise_pile(cave, grid);
3381 				square_destroy(cave, grid);
3382 			}
3383 		}
3384 	}
3385 
3386 	/* Player is affected */
3387 	if (elem == ELEM_LIGHT) {
3388 		msg("There is a searing blast of light!");
3389 		equip_learn_element(player, ELEM_LIGHT);
3390 		if (!player_resists(player, ELEM_LIGHT)) {
3391 			(void)player_inc_timed(player, TMD_BLIND, 10 + randint1(10), true,
3392 								   true);
3393 		}
3394 	} else if (elem == ELEM_DARK) {
3395 		msg("Darkness seems to crush you!");
3396 		equip_learn_element(player, ELEM_DARK);
3397 		if (!player_resists(player, ELEM_DARK)) {
3398 			(void)player_inc_timed(player, TMD_BLIND, 10 + randint1(10), true,
3399 								   true);
3400 		}
3401 	}
3402 
3403 	/* Fully update the visuals */
3404 	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
3405 
3406 	/* Redraw monster list */
3407 	player->upkeep->redraw |= (PR_MONLIST | PR_ITEMLIST);
3408 
3409 	return true;
3410 }
3411 
3412 /**
3413  * Induce an earthquake of the radius context->radius centred on the instigator.
3414  *
3415  * This will turn some walls into floors and some floors into walls.
3416  *
3417  * The player will take damage and jump into a safe grid if possible,
3418  * otherwise, he will tunnel through the rubble instantaneously.
3419  *
3420  * Monsters will take damage, and jump into a safe grid if possible,
3421  * otherwise they will be buried in the rubble, disappearing from
3422  * the level in the same way that they do when banished.
3423  *
3424  * Note that players and monsters (except eaters of walls and passers
3425  * through walls) will never occupy the same grid as a wall (or door).
3426  */
effect_handler_EARTHQUAKE(effect_handler_context_t * context)3427 bool effect_handler_EARTHQUAKE(effect_handler_context_t *context)
3428 {
3429 	int r = context->radius;
3430 	bool targeted = context->subtype ? true : false;
3431 
3432 	struct loc pgrid = player->grid;
3433 	int i, y, x;
3434 	struct loc offset, safe_grid = loc(0, 0);
3435 	int safe_grids = 0;
3436 	int damage = 0;
3437 	bool hurt = false;
3438 	bool map[32][32];
3439 
3440 	struct loc centre = origin_get_loc(context->origin);
3441 
3442 	context->ident = true;
3443 
3444 	if ((player->depth) && ((!player->upkeep->arena_level)
3445 							|| (context->origin.what == SRC_MONSTER))) {
3446 		msg("The ground shakes! The ceiling caves in!");
3447 	} else {
3448 		/* No effect in town or arena */
3449 		msg("The ground shakes for a moment.");
3450 		return true;
3451 	}
3452 
3453 	/* Sometimes ask for a target */
3454 	if (targeted) {
3455 		int dir = DIR_TARGET;
3456 		get_aim_dir(&dir);
3457 		if ((dir == DIR_TARGET) && target_okay()) {
3458 			target_get(&centre);
3459 		}
3460 	}
3461 
3462 	/* Paranoia -- Enforce maximum range */
3463 	if (r > 15) r = 15;
3464 
3465 	/* Initialize a map of the maximal blast area */
3466 	for (y = 0; y < 32; y++)
3467 		for (x = 0; x < 32; x++)
3468 			map[y][x] = false;
3469 
3470 	/* Check around the epicenter */
3471 	for (offset.y = -r; offset.y <= r; offset.y++) {
3472 		for (offset.x = -r; offset.x <= r; offset.x++) {
3473 			/* Extract the location */
3474 			struct loc grid = loc_sum(centre, offset);
3475 
3476 			/* Skip illegal grids */
3477 			if (!square_in_bounds_fully(cave, grid)) continue;
3478 
3479 			/* Skip distant grids */
3480 			if (distance(centre, grid) > r) continue;
3481 
3482 			/* Lose room and vault */
3483 			sqinfo_off(square(cave, grid)->info, SQUARE_ROOM);
3484 			sqinfo_off(square(cave, grid)->info, SQUARE_VAULT);
3485 
3486 			/* Forget completely */
3487 			if (!square_isbright(cave, grid)) {
3488 				sqinfo_off(square(cave, grid)->info, SQUARE_GLOW);
3489 			}
3490 			sqinfo_off(square(cave, grid)->info, SQUARE_SEEN);
3491 			square_forget(cave, grid);
3492 			square_light_spot(cave, grid);
3493 
3494 			/* Skip the epicenter */
3495 			if (loc_is_zero(offset)) continue;
3496 
3497 			/* Skip most grids */
3498 			if (randint0(100) < 85) continue;
3499 
3500 			/* Damage this grid */
3501 			map[16 + grid.y - centre.y][16 + grid.x - centre.x] = true;
3502 
3503 			/* Take note of player damage */
3504 			if (loc_eq(grid, pgrid)) hurt = true;
3505 		}
3506 	}
3507 
3508 	/* First, affect the player (if necessary) */
3509 	if (hurt) {
3510 		/* Check around the player */
3511 		for (i = 0; i < 8; i++) {
3512 			/* Get the location */
3513 			struct loc grid = loc_sum(pgrid, ddgrid_ddd[i]);
3514 
3515 			/* Skip non-empty grids - allow pushing into traps and webs */
3516 			if (!square_isopen(cave, grid)) continue;
3517 
3518 			/* Important -- Skip grids marked for damage */
3519 			if (map[16 + grid.y - centre.y][16 + grid.x - centre.x]) continue;
3520 
3521 			/* Count "safe" grids, apply the randomizer */
3522 			if ((++safe_grids > 1) && (randint0(safe_grids) != 0)) continue;
3523 
3524 			/* Save the safe location */
3525 			safe_grid = grid;
3526 		}
3527 
3528 		/* Random message */
3529 		switch (randint1(3))
3530 		{
3531 			case 1:
3532 			{
3533 				msg("The cave ceiling collapses on you!");
3534 				break;
3535 			}
3536 			case 2:
3537 			{
3538 				msg("The cave floor twists in an unnatural way!");
3539 				break;
3540 			}
3541 			default:
3542 			{
3543 				msg("The cave quakes!");
3544 				msg("You are pummeled with debris!");
3545 				break;
3546 			}
3547 		}
3548 
3549 		/* Hurt the player a lot */
3550 		if (!safe_grids) {
3551 			/* Message and damage */
3552 			msg("You are severely crushed!");
3553 			damage = 300;
3554 		} else {
3555 			/* Destroy the grid, and push the player to (relative) safety */
3556 			switch (randint1(3)) {
3557 				case 1: {
3558 					msg("You nimbly dodge the blast!");
3559 					damage = 0;
3560 					break;
3561 				}
3562 				case 2: {
3563 					msg("You are bashed by rubble!");
3564 					damage = damroll(10, 4);
3565 					(void)player_inc_timed(player, TMD_STUN, randint1(50),
3566 										   true, true);
3567 					break;
3568 				}
3569 				case 3: {
3570 					msg("You are crushed between the floor and ceiling!");
3571 					damage = damroll(10, 4);
3572 					(void)player_inc_timed(player, TMD_STUN, randint1(50),
3573 										   true, true);
3574 					break;
3575 				}
3576 			}
3577 
3578 			/* Move player */
3579 			monster_swap(pgrid, safe_grid);
3580 		}
3581 
3582 		/* Take some damage */
3583 		if (damage) take_hit(player, damage, "an earthquake");
3584 	}
3585 
3586 
3587 	/* Examine the quaked region */
3588 	for (offset.y = -r; offset.y <= r; offset.y++) {
3589 		for (offset.x = -r; offset.x <= r; offset.x++) {
3590 			/* Extract the location */
3591 			struct loc grid = loc_sum(centre, offset);
3592 
3593 			/* Skip unaffected grids */
3594 			if (!map[16 + grid.y - centre.y][16 + grid.x - centre.x]) continue;
3595 
3596 			/* Process monsters */
3597 			if (square(cave, grid)->mon > 0) {
3598 				struct monster *mon = square_monster(cave, grid);
3599 
3600 				/* Most monsters cannot co-exist with rock */
3601 				if (!flags_test(mon->race->flags, RF_SIZE, RF_KILL_WALL,
3602 								RF_PASS_WALL, FLAG_END)) {
3603 					char m_name[80];
3604 
3605 					/* Assume not safe */
3606 					safe_grids = 0;
3607 
3608 					/* Monster can move to escape the wall */
3609 					if (!rf_has(mon->race->flags, RF_NEVER_MOVE)) {
3610 						/* Look for safety */
3611 						for (i = 0; i < 8; i++) {
3612 							/* Get the grid */
3613 							struct loc safe = loc_sum(grid, ddgrid_ddd[i]);
3614 
3615 							/* Skip non-empty grids */
3616 							if (!square_isempty(cave, safe)) continue;
3617 
3618 							/* Hack -- no safety on glyph of warding */
3619 							if (square_iswarded(cave, safe)) continue;
3620 
3621 							/* Important -- Skip quake grids */
3622 							if (map[16 + safe.y - centre.y]
3623 								[16 + safe.x - centre.x]) continue;
3624 
3625 							/* Count safe grids, apply the randomizer */
3626 							if ((++safe_grids > 1) &&
3627 								(randint0(safe_grids) != 0))
3628 								continue;
3629 
3630 							/* Save the safe grid */
3631 							safe_grid = safe;
3632 						}
3633 					}
3634 
3635 					/* Describe the monster */
3636 					monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);
3637 
3638 					/* Scream in pain */
3639 					msg("%s wails out in pain!", m_name);
3640 
3641 					/* Take damage from the quake */
3642 					damage = (safe_grids ? damroll(4, 8) : (mon->hp + 1));
3643 
3644 					/* Monster is certainly awake, not thinking about player */
3645 					monster_wake(mon, false, 0);
3646 
3647 					/* If the quake finished the monster off, show message */
3648 					if (mon->hp < damage && mon->hp >= 0)
3649 						msg("%s is embedded in the rock!", m_name);
3650 
3651 					/* Apply damage directly */
3652 					mon->hp -= damage;
3653 
3654 					/* Delete (not kill) "dead" monsters */
3655 					if (mon->hp < 0) {
3656 						/* Delete the monster */
3657 						delete_monster(grid);
3658 
3659 						/* No longer safe */
3660 						safe_grids = 0;
3661 					}
3662 
3663 					/* Escape from the rock */
3664 					if (safe_grids)
3665 						/* Move the monster */
3666 						monster_swap(grid, safe_grid);
3667 				}
3668 			}
3669 		}
3670 	}
3671 
3672 	/* Player may have moved */
3673 	pgrid = player->grid;
3674 
3675 	/* Important -- no wall on player */
3676 	map[16 + pgrid.y - centre.y][16 + pgrid.x - centre.x] = false;
3677 
3678 
3679 	/* Examine the quaked region and damage marked grids if possible */
3680 	for (offset.y = -r; offset.y <= r; offset.y++) {
3681 		for (offset.x = -r; offset.x <= r; offset.x++) {
3682 			/* Extract the location */
3683 			struct loc grid = loc_sum(centre, offset);
3684 
3685 			/* Ignore invalid grids */
3686 			if (!square_in_bounds_fully(cave, grid)) continue;
3687 
3688 			/* Note unaffected grids for light changes, etc. */
3689 			if (!map[16 + grid.y - centre.y][16 + grid.x - centre.x])
3690 				square_light_spot(cave, grid);
3691 
3692 			/* Destroy location and all objects (if valid) */
3693 			else if (square_changeable(cave, grid)) {
3694 				square_excise_pile(cave, grid);
3695 				square_earthquake(cave, grid);
3696 			}
3697 		}
3698 	}
3699 
3700 	/* Fully update the visuals */
3701 	player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS);
3702 
3703 	/* Update the health bar */
3704 	player->upkeep->redraw |= (PR_HEALTH);
3705 
3706 	/* Window stuff */
3707 	player->upkeep->redraw |= (PR_MONLIST | PR_ITEMLIST);
3708 
3709 	return true;
3710 }
3711 
effect_handler_LIGHT_LEVEL(effect_handler_context_t * context)3712 bool effect_handler_LIGHT_LEVEL(effect_handler_context_t *context)
3713 {
3714 	bool full = context->value.base ? true : false;
3715 	if (full)
3716 		msg("An image of your surroundings forms in your mind...");
3717 	wiz_light(cave, player, full);
3718 	context->ident = true;
3719 	return true;
3720 }
3721 
effect_handler_DARKEN_LEVEL(effect_handler_context_t * context)3722 bool effect_handler_DARKEN_LEVEL(effect_handler_context_t *context)
3723 {
3724 	bool full = context->value.base ? true : false;
3725 	if (full)
3726 		msg("A great blackness rolls through the dungeon...");
3727 	wiz_dark(cave, player, full);
3728 	context->ident = true;
3729 	return true;
3730 }
3731 
3732 /**
3733  * Call light around the player
3734  */
effect_handler_LIGHT_AREA(effect_handler_context_t * context)3735 bool effect_handler_LIGHT_AREA(effect_handler_context_t *context)
3736 {
3737 	/* Message */
3738 	if (!player->timed[TMD_BLIND])
3739 		msg("You are surrounded by a white light.");
3740 
3741 	/* Light up the room */
3742 	light_room(player->grid, true);
3743 
3744 	/* Assume seen */
3745 	context->ident = true;
3746 	return (true);
3747 }
3748 
3749 
3750 /**
3751  * Call darkness around the player or target monster
3752  */
effect_handler_DARKEN_AREA(effect_handler_context_t * context)3753 bool effect_handler_DARKEN_AREA(effect_handler_context_t *context)
3754 {
3755 	struct loc target = player->grid;
3756 	bool message = player->timed[TMD_BLIND] ? false : true;
3757 	struct monster *t_mon = monster_target_monster(context);
3758 	struct loc decoy = cave_find_decoy(cave);
3759 	bool decoy_unseen = false;
3760 
3761 	/* Check for monster targeting another monster */
3762 	if (t_mon) {
3763 		char m_name[80];
3764 		target = t_mon->grid;
3765 		monster_desc(m_name, sizeof(m_name), t_mon, MDESC_TARG);
3766 		if (message) {
3767 			msg("Darkness surrounds %s.", m_name);
3768 			message = false;
3769 		}
3770 	}
3771 
3772 	/* Check for decoy */
3773 	if (!loc_is_zero(decoy)) {
3774 		target = decoy;
3775 		if (!los(cave, player->grid, decoy) ||
3776 			player->timed[TMD_BLIND]) {
3777 			decoy_unseen = true;
3778 		}
3779 		if (message && !decoy_unseen) {
3780 			msg("Darkness surrounds the decoy.");
3781 			message = false;
3782 		}
3783 	}
3784 
3785 	if (message) {
3786 		msg("Darkness surrounds you.");
3787 	}
3788 
3789 	/* Darken the room */
3790 	light_room(target, false);
3791 
3792 	/* Hack - blind the player directly if player-cast */
3793 	if (context->origin.what == SRC_PLAYER &&
3794 		!player_resists(player, ELEM_DARK)) {
3795 		(void)player_inc_timed(player, TMD_BLIND, 3 + randint1(5), true, true);
3796 	}
3797 
3798 	/* Assume seen */
3799 	context->ident = !decoy_unseen;
3800 	return (true);
3801 }
3802 
3803 /**
3804  * Project from the player's grid at the player, with full intensity out to
3805  * its radius
3806  * Affect the player (even when player-cast), grids, objects, and monsters
3807  */
effect_handler_SPOT(effect_handler_context_t * context)3808 bool effect_handler_SPOT(effect_handler_context_t *context)
3809 {
3810 	struct loc pgrid = player->grid;
3811 	int dam = effect_calculate_value(context, false);
3812 	int rad = context->radius ? context->radius : 0;
3813 
3814 	int flg = PROJECT_STOP | PROJECT_PLAY | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_SELF;
3815 
3816 	/* Handle increasing radius with player level */
3817 	if (context->other && context->origin.what == SRC_PLAYER) {
3818 		rad += player->lev / context->other;
3819 	}
3820 
3821 	/* Aim at the target, explode */
3822 	if (project(context->origin, rad, pgrid, dam, context->subtype, flg, 0,
3823 				rad, NULL))
3824 		context->ident = true;
3825 
3826 	return true;
3827 }
3828 
3829 /**
3830  * Project from the player's grid, act as a ball, with full intensity out as
3831  * far as the given diameter
3832  * Affect grids, objects, and monsters
3833  */
effect_handler_SPHERE(effect_handler_context_t * context)3834 bool effect_handler_SPHERE(effect_handler_context_t *context)
3835 {
3836 	struct loc pgrid = player->grid;
3837 	int dam = effect_calculate_value(context, false);
3838 	int rad = context->radius ? context->radius : 0;
3839 	int diameter_of_source = context->other ? context->other : 0;
3840 
3841 	int flg = PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
3842 
3843 	/* Aim at the target, explode */
3844 	if (project(context->origin, rad, pgrid, dam, context->subtype, flg, 0,
3845 				diameter_of_source, NULL))
3846 		context->ident = true;
3847 
3848 	return true;
3849 }
3850 
3851 /**
3852  * Cast a ball spell
3853  * Stop if we hit a monster or the player, act as a ball
3854  * Allow target mode to pass over monsters
3855  * Affect grids, objects, and monsters
3856  */
effect_handler_BALL(effect_handler_context_t * context)3857 bool effect_handler_BALL(effect_handler_context_t *context)
3858 {
3859 	int dam = effect_calculate_value(context, true);
3860 	int rad = context->radius ? context->radius : 2;
3861 	struct loc target = loc(-1, -1);
3862 
3863 	int flg = PROJECT_THRU | PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
3864 
3865 	/* Player or monster? */
3866 	switch (context->origin.what) {
3867 		case SRC_MONSTER: {
3868 			struct monster *mon = cave_monster(cave, context->origin.which.monster);
3869 			int conf_level, accuracy = 100;
3870 			struct monster *t_mon = monster_target_monster(context);
3871 
3872 			assert(mon);
3873 
3874 			conf_level = monster_effect_level(mon, MON_TMD_CONF);
3875 			while (conf_level) {
3876 				accuracy *= (100 - CONF_RANDOM_CHANCE);
3877 				accuracy /= 100;
3878 				conf_level--;
3879 			}
3880 
3881 			/* Powerful monster */
3882 			if (monster_is_powerful(mon)) {
3883 				rad++;
3884 			}
3885 
3886 			flg |= PROJECT_PLAY;
3887 			flg &= ~(PROJECT_STOP | PROJECT_THRU);
3888 
3889 			if (randint1(100) > accuracy) {
3890 				/* Confused direction */
3891 				int dir = randint1(9);
3892 				target = loc_sum(mon->grid, ddgrid[dir]);
3893 			} else if (t_mon) {
3894 				/* Target monster */
3895 				target = t_mon->grid;
3896 			} else {
3897 				/* Target player */
3898 				struct loc decoy = cave_find_decoy(cave);
3899 				if (!loc_is_zero(decoy)) {
3900 					target = decoy;
3901 				} else {
3902 					target = player->grid;
3903 				}
3904 			}
3905 
3906 			break;
3907 		}
3908 
3909 		case SRC_TRAP: {
3910 			struct trap *trap = context->origin.which.trap;
3911 			flg |= PROJECT_PLAY;
3912 			target = trap->grid;
3913 			break;
3914 		}
3915 
3916 		case SRC_PLAYER:
3917 			/* Ask for a target if no direction given */
3918 			if (context->dir == DIR_TARGET && target_okay()) {
3919 				flg &= ~(PROJECT_STOP | PROJECT_THRU);
3920 				target_get(&target);
3921 			} else {
3922 				target = loc_sum(player->grid, ddgrid[context->dir]);
3923 			}
3924 
3925 			if (context->other) rad += player->lev / context->other;
3926 			break;
3927 
3928 		default:
3929 			break;
3930 	}
3931 
3932 	/* Aim at the target, explode */
3933 	if (project(context->origin, rad, target, dam, context->subtype, flg, 0, 0, context->obj))
3934 		context->ident = true;
3935 
3936 	return true;
3937 }
3938 
3939 
3940 /**
3941  * Breathe an element, in a cone from the breather
3942  * Affect grids, objects, and monsters
3943  * context->subtype is element, context->other degrees of arc
3944  * If context->radius is set it is radius of breath, but it usually isn't
3945  */
effect_handler_BREATH(effect_handler_context_t * context)3946 bool effect_handler_BREATH(effect_handler_context_t *context)
3947 {
3948 	int dam = effect_calculate_value(context, false);
3949 	int type = context->subtype;
3950 
3951 	struct loc target = loc(-1, -1);
3952 
3953 	/* Diameter of source starts at 4, so full strength up to 3 grids from
3954 	 * the breather. */
3955 	int diameter_of_source = 4;
3956 
3957 	/* Minimum breath width is 20 degrees */
3958 	int degrees_of_arc = MAX(context->other, 20);
3959 
3960 	int flg = PROJECT_ARC | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
3961 
3962 	/* Distance breathed generally has no fixed limit. */
3963 	int rad = context->radius ? context->radius : z_info->max_range;
3964 
3965 	/* Player or monster? */
3966 	if (context->origin.what == SRC_MONSTER) {
3967 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
3968 		struct monster *t_mon = monster_target_monster(context);
3969 		int conf_level, accuracy = 100;
3970 
3971 		flg |= PROJECT_PLAY;
3972 
3973 		conf_level = monster_effect_level(mon, MON_TMD_CONF);
3974 		while (conf_level) {
3975 			accuracy *= (100 - CONF_RANDOM_CHANCE);
3976 			accuracy /= 100;
3977 			conf_level--;
3978 		}
3979 
3980 		if (randint1(100) > accuracy) {
3981 			/* Confused direction. */
3982 			int dir = randint1(9);
3983 
3984 			target = loc_sum(mon->grid, ddgrid[dir]);
3985 		} else if (t_mon) {
3986 			/* Target monster. */
3987 			target = t_mon->grid;
3988 		} else {
3989 			/* Target player. */
3990 			struct loc decoy = cave_find_decoy(cave);
3991 			if (!loc_is_zero(decoy)) {
3992 				target = decoy;
3993 			} else {
3994 				target = player->grid;
3995 			}
3996 		}
3997 
3998 		dam = breath_dam(type, mon->hp);
3999 
4000 		/* Powerful monster */
4001 		if (monster_is_powerful(mon)) {
4002 			/* Breath is now full strength at 5 grids */
4003 			diameter_of_source *= 3;
4004 			diameter_of_source /= 2;
4005 		}
4006 	} else if (context->origin.what == SRC_PLAYER) {
4007 		msgt(projections[type].msgt, "You breathe %s.", projections[type].desc);
4008 
4009 		/* Ask for a target if no direction given */
4010 		if (context->dir == DIR_TARGET && target_okay()) {
4011 			target_get(&target);
4012 		} else {
4013 			target = loc_sum(player->grid, ddgrid[context->dir]);
4014 		}
4015 	}
4016 
4017 	/* Adjust the diameter of the energy source */
4018 	if (degrees_of_arc < 60) {
4019 		/* Narrower cone means energy drops off less quickly. We now have:
4020 		 * - 30 degree regular breath  | full strength at 5 grids
4021 		 * - 30 degree powerful breath | full strength at 9 grids
4022 		 * - 20 degree regular breath  | full strength at 11 grids
4023 		 * - 20 degree powerful breath | full strength at 17 grids
4024 		 * where grids are measured from the breather. */
4025 		diameter_of_source = diameter_of_source * 60 / degrees_of_arc;
4026 
4027 		/* Max */
4028 		if (diameter_of_source > 25)
4029 			diameter_of_source = 25;
4030 	}
4031 
4032 	/* Breathe at the target */
4033 	if (project(context->origin, rad, target, dam, type, flg, degrees_of_arc,
4034 				diameter_of_source, context->obj))
4035 		context->ident = true;
4036 
4037 	return true;
4038 }
4039 
4040 
4041 /**
4042  * Cast an arc-shaped spell.  This is nothing more than a sphere spell
4043  * centered on the caster with a value for degrees_of_arc (how many degrees
4044  * wide the the arc is) that is not 360, essentially the same as a breath.
4045  * The direction given will be the center of the arc, which travels outwards
4046  * from the caster to a distance given by rad. -LM-
4047  *
4048  * Because all arcs start out as being one grid wide, arc spells with a
4049  * value for degrees_of_arc less than (roughly) 60 do not dissipate as
4050  * quickly.
4051  *
4052  * Affect grids, objects, and monsters
4053  * context->subtype is element, context->radius radius,
4054  * context->other degrees of arc (minimum 20)
4055  */
effect_handler_ARC(effect_handler_context_t * context)4056 bool effect_handler_ARC(effect_handler_context_t *context)
4057 {
4058 	int dam = effect_calculate_value(context, true);
4059 	int type = context->subtype;
4060 	int rad = context->radius;
4061 
4062 	struct loc target = loc(-1, -1);
4063 
4064 	/* Diameter of source starts at 4, so full strength up to 3 grids from
4065 	 * the caster. */
4066 	int diameter_of_source = 4;
4067 
4068 	/* Short beams now have their own effect, so we set a minimum arc width */
4069 	int degrees_of_arc = MAX(context->other, 20);
4070 
4071 	int flg = PROJECT_ARC | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
4072 
4073 	/* Radius of zero means no fixed limit. */
4074 	if (rad == 0) {
4075 		rad = z_info->max_range;
4076 	}
4077 
4078 	/* Player or monster? */
4079 	if (context->origin.what == SRC_MONSTER) {
4080 		flg |= PROJECT_PLAY;
4081 		target =  player->grid;
4082 	} else if (context->origin.what == SRC_PLAYER) {
4083 		/* Ask for a target if no direction given */
4084 		if (context->dir == DIR_TARGET && target_okay()) {
4085 			target_get(&target);
4086 		} else {
4087 			target = loc_sum(player->grid, ddgrid[context->dir]);
4088 		}
4089 	}
4090 
4091 	/* Diameter of the energy source. */
4092 	if (degrees_of_arc < 60) {
4093 			diameter_of_source = diameter_of_source * 60 / degrees_of_arc;
4094 	}
4095 
4096 	/* Max */
4097 	if (diameter_of_source > 25) {
4098 		diameter_of_source = 25;
4099 	}
4100 
4101 	/* Aim at the target */
4102 	if (project(context->origin, rad, target, dam, type, flg, degrees_of_arc,
4103 				diameter_of_source, context->obj)) {
4104 		context->ident = true;
4105 	}
4106 
4107 	return true;
4108 }
4109 
4110 /**
4111  * Cast an defined length beam spell.
4112  *
4113  * Affect grids, objects, and monsters
4114  * context->subtype is element, context->radius radius
4115  * context->other allows an added radius of 1 every time the player level
4116  * increases by a multiple of context->other, and will only take effect for
4117  * player spells
4118  */
effect_handler_SHORT_BEAM(effect_handler_context_t * context)4119 bool effect_handler_SHORT_BEAM(effect_handler_context_t *context)
4120 {
4121 	int dam = effect_calculate_value(context, false);
4122 	int type = context->subtype;
4123 	bool addons = (context->origin.what == SRC_PLAYER) && (context->other > 0);
4124 	int rad = context->radius + (addons ? player->lev / context->other : 0);
4125 
4126 	struct loc target = loc(-1, -1);
4127 
4128 	/* Diameter of source is the same as the radius, so the effect is
4129 	 * essentially full strength for its entire length. */
4130 	int diameter_of_source = rad;
4131 
4132 	int flg = PROJECT_ARC | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
4133 
4134 	/* Player or monster? */
4135 	if (context->origin.what == SRC_MONSTER) {
4136 		flg |= PROJECT_PLAY;
4137 		target = player->grid;
4138 	} else if (context->origin.what == SRC_PLAYER) {
4139 		/* Ask for a target if no direction given */
4140 		if (context->dir == DIR_TARGET && target_okay()) {
4141 			target_get(&target);
4142 		} else {
4143 			target = loc_sum(player->grid, ddgrid[context->dir]);
4144 		}
4145 	}
4146 
4147 	/* Check bounds */
4148 	if (diameter_of_source > 25) {
4149 		diameter_of_source = 25;
4150 	}
4151 
4152 	/* Aim at the target */
4153 	if (project(context->origin, rad, target, dam, type, flg, 0,
4154 				diameter_of_source, context->obj)) {
4155 		context->ident = true;
4156 	}
4157 
4158 	return true;
4159 }
4160 
4161 /**
4162  * Crack a whip, or spit at the player; actually just a finite length beam
4163  * Affect grids, objects, and monsters
4164  * context->radius is length of beam
4165  */
effect_handler_LASH(effect_handler_context_t * context)4166 bool effect_handler_LASH(effect_handler_context_t *context)
4167 {
4168 	int dam = effect_calculate_value(context, false);
4169 	int rad = context->radius;
4170 
4171 	int flg = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_ARC;
4172 	int type;
4173 
4174 	struct loc target = loc(-1, -1);
4175 
4176 	/* Diameter of source is the same as the radius, so the effect is
4177 	 * essentially full strength for its entire length. */
4178 	int diameter_of_source = rad;
4179 
4180 	/* Monsters only */
4181 	if (context->origin.what == SRC_MONSTER) {
4182 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
4183 		struct monster *t_mon = monster_target_monster(context);
4184 		int i;
4185 
4186 		flg |= PROJECT_PLAY;
4187 
4188 		/* Target player or monster? */
4189 		if (t_mon) {
4190 			target = t_mon->grid;
4191 		} else {
4192 			struct loc decoy = cave_find_decoy(cave);
4193 			if (!loc_is_zero(decoy)) {
4194 				target = decoy;
4195 			} else {
4196 				target = player->grid;
4197 			}
4198 		}
4199 
4200 		/* Paranoia */
4201 		if (rad > z_info->max_range) rad = z_info->max_range;
4202 
4203 		/* Get the type (default is PROJ_MISSILE) */
4204 		type = mon->race->blow[0].effect->lash_type;
4205 
4206 		/* Scan through all blows for damage */
4207 		for (i = 0; i < z_info->mon_blows_max; i++) {
4208 			/* Extract the attack infomation */
4209 			random_value dice = mon->race->blow[i].dice;
4210 
4211 			/* Full damage of first blow, plus half damage of others */
4212 			dam += randcalc(dice, mon->race->level, RANDOMISE) / (i ? 2 : 1);
4213 			if (!mon->race->blow[i].next) break;
4214 		}
4215 
4216 		/* No damaging blows */
4217 		if (!dam) return false;
4218 	} else {
4219 		return false;
4220 	}
4221 
4222 	/* Check bounds */
4223 	if (diameter_of_source > 25) {
4224 		diameter_of_source = 25;
4225 	}
4226 
4227 	/* Lash the target */
4228 	if (project(context->origin, rad, target, dam, type, flg, 0,
4229 				diameter_of_source, context->obj)) {
4230 		context->ident = true;
4231 	}
4232 
4233 	return true;
4234 }
4235 
4236 /**
4237  * Cast multiple non-jumping ball spells at the same target.
4238  *
4239  * Targets absolute coordinates instead of a specific monster, so that
4240  * the death of the monster doesn't change the target's location.
4241  */
effect_handler_SWARM(effect_handler_context_t * context)4242 bool effect_handler_SWARM(effect_handler_context_t *context)
4243 {
4244 	int dam = effect_calculate_value(context, true);
4245 	int num = context->value.m_bonus;
4246 
4247 	struct loc target = loc_sum(player->grid, ddgrid[context->dir]);
4248 
4249 	int flg = PROJECT_THRU | PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
4250 
4251 	/* Ask for a target if no direction given (early detonation) */
4252 	if ((context->dir == DIR_TARGET) && target_okay()) {
4253 		target_get(&target);
4254 	}
4255 
4256 	while (num--) {
4257 		/* Aim at the target.  Hurt items on floor. */
4258 		if (project(source_player(), context->radius, target, dam,
4259 					context->subtype, flg, 0, 0, context->obj))
4260 			context->ident = true;
4261 	}
4262 
4263 	return true;
4264 }
4265 
4266 /**
4267  * Strike the target with a ball from above
4268  */
effect_handler_STRIKE(effect_handler_context_t * context)4269 bool effect_handler_STRIKE(effect_handler_context_t *context)
4270 {
4271 	int dam = effect_calculate_value(context, true);
4272 	struct loc target = player->grid;
4273 	int flg = PROJECT_JUMP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
4274 
4275 	/* Ask for a target; if no direction given, the player is struck  */
4276 	if ((context->dir == DIR_TARGET) && target_okay()) {
4277 		target_get(&target);
4278 	}
4279 
4280 	/* Enforce line of sight */
4281 	if (!projectable(cave, player->grid, target, PROJECT_NONE) ||
4282 		!square_isknown(cave, target)) {
4283 		return false;
4284 	}
4285 
4286 	/* Aim at the target.  Hurt items on floor. */
4287 	if (project(source_player(), context->radius, target, dam, context->subtype,
4288 				flg, 0, 0, context->obj)) {
4289 		context->ident = true;
4290 	}
4291 
4292 	return true;
4293 }
4294 
4295 /**
4296  * Cast a line spell in every direction
4297  * Stop if we hit a monster, act as a ball
4298  * Affect grids, objects, and monsters
4299  */
effect_handler_STAR(effect_handler_context_t * context)4300 bool effect_handler_STAR(effect_handler_context_t *context)
4301 {
4302 	int dam = effect_calculate_value(context, true);
4303 	int i;
4304 	struct loc target;
4305 
4306 	int flg = PROJECT_THRU | PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL;
4307 
4308 	/* Describe */
4309 	if (!player->timed[TMD_BLIND])
4310 		msg("Light shoots in all directions!");
4311 
4312 	for (i = 0; i < 8; i++) {
4313 		/* Use the current direction */
4314 		target = loc_sum(player->grid, ddgrid_ddd[i]);
4315 
4316 		/* Aim at the target */
4317 		if (project(source_player(), 0, target, dam, context->subtype, flg, 0,
4318 					0, context->obj))
4319 			context->ident = true;
4320 	}
4321 
4322 	return true;
4323 }
4324 
4325 
4326 /**
4327  * Cast a ball spell in every direction
4328  * Stop if we hit a monster, act as a ball
4329  * Affect grids, objects, and monsters
4330  */
effect_handler_STAR_BALL(effect_handler_context_t * context)4331 bool effect_handler_STAR_BALL(effect_handler_context_t *context)
4332 {
4333 	int dam = effect_calculate_value(context, true);
4334 	int i;
4335 	struct loc target;
4336 
4337 	int flg = PROJECT_STOP | PROJECT_THRU | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
4338 
4339 	for (i = 0; i < 8; i++) {
4340 		/* Use the current direction */
4341 		target = loc_sum(player->grid, ddgrid_ddd[i]);
4342 
4343 		/* Aim at the target, explode */
4344 		if (project(source_player(), context->radius, target, dam,
4345 					context->subtype, flg, 0, 0, context->obj))
4346 			context->ident = true;
4347 	}
4348 	return true;
4349 }
4350 
4351 /**
4352  * Cast a bolt spell
4353  * Stop if we hit a monster, as a bolt
4354  * Affect monsters (not grids or objects)
4355  */
effect_handler_BOLT(effect_handler_context_t * context)4356 bool effect_handler_BOLT(effect_handler_context_t *context)
4357 {
4358 	int dam = effect_calculate_value(context, true);
4359 	int flg = PROJECT_STOP | PROJECT_KILL;
4360 	(void) project_aimed(context->origin, context->subtype, context->dir, dam,
4361 						 flg, context->obj);
4362 	if (!player->timed[TMD_BLIND])
4363 		context->ident = true;
4364 	return true;
4365 }
4366 
4367 /**
4368  * Cast a beam spell
4369  * Pass through monsters, as a beam
4370  * Affect monsters (not grids or objects)
4371  */
effect_handler_BEAM(effect_handler_context_t * context)4372 bool effect_handler_BEAM(effect_handler_context_t *context)
4373 {
4374 	int dam = effect_calculate_value(context, true);
4375 	int flg = PROJECT_BEAM | PROJECT_KILL;
4376 	(void) project_aimed(context->origin, context->subtype, context->dir, dam,
4377 						 flg, context->obj);
4378 	if (!player->timed[TMD_BLIND])
4379 		context->ident = true;
4380 	return true;
4381 }
4382 
4383 /**
4384  * Cast a bolt spell, or rarely, a beam spell
4385  * context->other is used as any adjustment to the regular beam chance
4386  */
effect_handler_BOLT_OR_BEAM(effect_handler_context_t * context)4387 bool effect_handler_BOLT_OR_BEAM(effect_handler_context_t *context)
4388 {
4389 	int beam = context->beam + context->other;
4390 
4391 	if (randint0(100) < beam)
4392 		return effect_handler_BEAM(context);
4393 	else
4394 		return effect_handler_BOLT(context);
4395 }
4396 
4397 /**
4398  * Cast a line spell
4399  * Pass through monsters, as a beam
4400  * Affect monsters and grids (not objects)
4401  */
effect_handler_LINE(effect_handler_context_t * context)4402 bool effect_handler_LINE(effect_handler_context_t *context)
4403 {
4404 	int dam = effect_calculate_value(context, true);
4405 	int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL;
4406 	if (project_aimed(context->origin, context->subtype, context->dir, dam, flg, context->obj))
4407 		context->ident = true;
4408 	return true;
4409 }
4410 
4411 /**
4412  * Cast an alter spell
4413  * Affect objects and grids (not monsters)
4414  */
effect_handler_ALTER(effect_handler_context_t * context)4415 bool effect_handler_ALTER(effect_handler_context_t *context)
4416 {
4417 	int flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_ITEM;
4418 	if (project_aimed(context->origin, context->subtype, context->dir, 0, flg, context->obj))
4419 		context->ident = true;
4420 	return true;
4421 }
4422 
4423 /**
4424  * Cast a bolt spell
4425  * Stop if we hit a monster, as a bolt
4426  * Affect monsters (not grids or objects)
4427  * Like BOLT, but only identifies on noticing an effect
4428  */
effect_handler_BOLT_STATUS(effect_handler_context_t * context)4429 bool effect_handler_BOLT_STATUS(effect_handler_context_t *context)
4430 {
4431 	int dam = effect_calculate_value(context, true);
4432 	int flg = PROJECT_STOP | PROJECT_KILL;
4433 	if (project_aimed(context->origin, context->subtype, context->dir, dam, flg, context->obj))
4434 		context->ident = true;
4435 	return true;
4436 }
4437 
4438 /**
4439  * Cast a bolt spell
4440  * Stop if we hit a monster, as a bolt
4441  * Affect monsters (not grids or objects)
4442  * The same as BOLT_STATUS, but done as a separate function to aid descriptions
4443  */
effect_handler_BOLT_STATUS_DAM(effect_handler_context_t * context)4444 bool effect_handler_BOLT_STATUS_DAM(effect_handler_context_t *context)
4445 {
4446 	int dam = effect_calculate_value(context, true);
4447 	int flg = PROJECT_STOP | PROJECT_KILL;
4448 	if (project_aimed(context->origin, context->subtype, context->dir, dam, flg, context->obj))
4449 		context->ident = true;
4450 	return true;
4451 }
4452 
4453 /**
4454  * Cast a bolt spell
4455  * Stop if we hit a monster, as a bolt
4456  * Affect monsters (not grids or objects)
4457  * Notice stuff based on awareness of the effect
4458  */
effect_handler_BOLT_AWARE(effect_handler_context_t * context)4459 bool effect_handler_BOLT_AWARE(effect_handler_context_t *context)
4460 {
4461 	int dam = effect_calculate_value(context, true);
4462 	int flg = PROJECT_STOP | PROJECT_KILL;
4463 	if (context->aware) flg |= PROJECT_AWARE;
4464 	if (project_aimed(context->origin, context->subtype, context->dir, dam, flg, context->obj))
4465 		context->ident = true;
4466 	return true;
4467 }
4468 
4469 /**
4470  * Affect adjacent grids (radius 1 ball attack)
4471  */
effect_handler_TOUCH(effect_handler_context_t * context)4472 bool effect_handler_TOUCH(effect_handler_context_t *context)
4473 {
4474 	int dam = effect_calculate_value(context, true);
4475 	int rad = context->radius ? context->radius : 1;
4476 
4477 	if (context->origin.what == SRC_MONSTER) {
4478 		struct monster *mon = cave_monster(cave, context->origin.which.monster);
4479 		struct monster *t_mon = monster_target_monster(context);
4480 		struct loc decoy = cave_find_decoy(cave);
4481 
4482 		/* Target decoy */
4483 		if (decoy.y && decoy.x) {
4484 			int flg = PROJECT_GRID | PROJECT_KILL | PROJECT_HIDE | PROJECT_ITEM | PROJECT_THRU;
4485 			return (project(source_trap(square_trap(cave, decoy)),
4486 					rad, decoy, dam, context->subtype,flg, 0, 0, context->obj));
4487 		}
4488 
4489 		/* Monster cast at monster */
4490 		if (t_mon) {
4491 			int flg = PROJECT_GRID | PROJECT_KILL | PROJECT_HIDE | PROJECT_ITEM | PROJECT_THRU;
4492 			return (project(source_monster(mon->target.midx), rad,
4493 							t_mon->grid, dam, context->subtype,
4494 							flg, 0, 0, context->obj));
4495 		}
4496 	}
4497 
4498 	if (project_touch(dam, rad, context->subtype, false, context->obj))
4499 		context->ident = true;
4500 	return true;
4501 }
4502 
4503 /**
4504  * Affect adjacent grids (radius 1 ball attack)
4505  * Notice stuff based on awareness of the effect
4506  */
effect_handler_TOUCH_AWARE(effect_handler_context_t * context)4507 bool effect_handler_TOUCH_AWARE(effect_handler_context_t *context)
4508 {
4509 	int dam = effect_calculate_value(context, true);
4510 	int rad = context->radius ? context->radius : 1;
4511 	if (project_touch(dam, rad, context->subtype, context->aware, context->obj))
4512 		context->ident = true;
4513 	return true;
4514 }
4515 
4516 /**
4517  * Curse the player's armor
4518  */
effect_handler_CURSE_ARMOR(effect_handler_context_t * context)4519 bool effect_handler_CURSE_ARMOR(effect_handler_context_t *context)
4520 {
4521 	struct object *obj;
4522 
4523 	char o_name[80];
4524 
4525 	/* Curse the body armor */
4526 	obj = equipped_item_by_slot_name(player, "body");
4527 
4528 	/* Nothing to curse */
4529 	if (!obj) return (true);
4530 
4531 	/* Describe */
4532 	object_desc(o_name, sizeof(o_name), obj, ODESC_FULL);
4533 
4534 	/* Attempt a saving throw for artifacts */
4535 	if (obj->artifact && (randint0(100) < 50)) {
4536 		msg("A %s tries to %s, but your %s resists the effects!",
4537 				   "terrible black aura", "surround your armor", o_name);
4538 	} else {
4539 		int num = randint1(3);
4540 		int max_tries = 20;
4541 		msg("A terrible black aura blasts your %s!", o_name);
4542 
4543 		/* Take down bonus a wee bit */
4544 		obj->to_a -= randint1(3);
4545 
4546 		/* Try to find enough appropriate curses */
4547 		while (num && max_tries) {
4548 			int pick = randint1(z_info->curse_max - 1);
4549 			int power = 10 * m_bonus(9, player->depth);
4550 			if (!curses[pick].poss[obj->tval]) {
4551 				max_tries--;
4552 				continue;
4553 			}
4554 			append_object_curse(obj, pick, power);
4555 			num--;
4556 		}
4557 
4558 		/* Recalculate bonuses */
4559 		player->upkeep->update |= (PU_BONUS);
4560 
4561 		/* Recalculate mana */
4562 		player->upkeep->update |= (PU_MANA);
4563 
4564 		/* Window stuff */
4565 		player->upkeep->redraw |= (PR_INVEN | PR_EQUIP);
4566 	}
4567 
4568 	context->ident = true;
4569 
4570 	return (true);
4571 }
4572 
4573 
4574 /**
4575  * Curse the player's weapon
4576  */
effect_handler_CURSE_WEAPON(effect_handler_context_t * context)4577 bool effect_handler_CURSE_WEAPON(effect_handler_context_t *context)
4578 {
4579 	struct object *obj;
4580 
4581 	char o_name[80];
4582 
4583 	/* Curse the weapon */
4584 	obj = equipped_item_by_slot_name(player, "weapon");
4585 
4586 	/* Nothing to curse */
4587 	if (!obj) return (true);
4588 
4589 	/* Describe */
4590 	object_desc(o_name, sizeof(o_name), obj, ODESC_FULL);
4591 
4592 	/* Attempt a saving throw */
4593 	if (obj->artifact && (randint0(100) < 50)) {
4594 		msg("A %s tries to %s, but your %s resists the effects!",
4595 				   "terrible black aura", "surround your weapon", o_name);
4596 	} else {
4597 		int num = randint1(3);
4598 		int max_tries = 20;
4599 		msg("A terrible black aura blasts your %s!", o_name);
4600 
4601 		/* Hurt it a bit */
4602 		obj->to_h = 0 - randint1(3);
4603 		obj->to_d = 0 - randint1(3);
4604 
4605 		/* Curse it */
4606 		while (num) {
4607 			int pick = randint1(z_info->curse_max - 1);
4608 			int power = 10 * m_bonus(9, player->depth);
4609 			if (!curses[pick].poss[obj->tval]) {
4610 				max_tries--;
4611 				continue;
4612 			}
4613 			append_object_curse(obj, pick, power);
4614 			num--;
4615 		}
4616 
4617 		/* Recalculate bonuses */
4618 		player->upkeep->update |= (PU_BONUS);
4619 
4620 		/* Recalculate mana */
4621 		player->upkeep->update |= (PU_MANA);
4622 
4623 		/* Window stuff */
4624 		player->upkeep->redraw |= (PR_INVEN | PR_EQUIP);
4625 	}
4626 
4627 	context->ident = true;
4628 
4629 	/* Notice */
4630 	return (true);
4631 }
4632 
4633 
4634 /**
4635  * Brand the current weapon
4636  */
effect_handler_BRAND_WEAPON(effect_handler_context_t * context)4637 bool effect_handler_BRAND_WEAPON(effect_handler_context_t *context)
4638 {
4639 	struct object *obj = equipped_item_by_slot_name(player, "weapon");
4640 
4641 	/* Select the brand */
4642 	const char *brand = one_in_(2) ? "Flame" : "Frost";
4643 
4644 	/* Brand the weapon */
4645 	brand_object(obj, brand);
4646 
4647 	context->ident = true;
4648 	return true;
4649 }
4650 
4651 
4652 /**
4653  * Brand some (non-magical) ammo
4654  */
effect_handler_BRAND_AMMO(effect_handler_context_t * context)4655 bool effect_handler_BRAND_AMMO(effect_handler_context_t *context)
4656 {
4657 	struct object *obj;
4658 	const char *q, *s;
4659 	int itemmode = (USE_INVEN | USE_QUIVER | USE_FLOOR);
4660 	bool used = false;
4661 
4662 	/* Select the brand */
4663 	const char *brand = one_in_(3) ? "Flame" : (one_in_(2) ? "Frost" : "Venom");
4664 
4665 	context->ident = true;
4666 
4667 	/* Get an item */
4668 	q = "Brand which kind of ammunition? ";
4669 	s = "You have nothing to brand.";
4670 	if (context->cmd) {
4671 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
4672 				item_tester_hook_ammo, itemmode)) {
4673 			return used;
4674 		}
4675 	} else if (!get_item(&obj, q, s, 0, item_tester_hook_ammo, itemmode))
4676 		return used;
4677 
4678 	/* Brand the ammo */
4679 	brand_object(obj, brand);
4680 
4681 	/* Done */
4682 	return (true);
4683 }
4684 
4685 /**
4686  * Enchant some (non-magical) bolts
4687  */
effect_handler_BRAND_BOLTS(effect_handler_context_t * context)4688 bool effect_handler_BRAND_BOLTS(effect_handler_context_t *context)
4689 {
4690 	struct object *obj;
4691 	const char *q, *s;
4692 	int itemmode = (USE_INVEN | USE_QUIVER | USE_FLOOR);
4693 	bool used = false;
4694 
4695 	context->ident = true;
4696 
4697 	/* Get an item */
4698 	q = "Brand which bolts? ";
4699 	s = "You have no bolts to brand.";
4700 	if (context->cmd) {
4701 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
4702 				item_tester_hook_bolt, itemmode)) {
4703 			return used;
4704 		}
4705 	} else if (!get_item(&obj, q, s, 0, item_tester_hook_bolt, itemmode))
4706 		return used;
4707 
4708 	/* Brand the bolts */
4709 	brand_object(obj, "Flame");
4710 
4711 	/* Done */
4712 	return (true);
4713 }
4714 
4715 
4716 /**
4717  * Turn a staff into arrows
4718  */
effect_handler_CREATE_ARROWS(effect_handler_context_t * context)4719 bool effect_handler_CREATE_ARROWS(effect_handler_context_t *context)
4720 {
4721 	int lev;
4722 	struct object *obj, *staff, *arrows;
4723 	const char *q, *s;
4724 	int itemmode = (USE_INVEN | USE_FLOOR);
4725 	bool good = false, great = false;
4726 	bool none_left = false;
4727 
4728 	/* Get an item */
4729 	q = "Make arrows from which staff? ";
4730 	s = "You have no staff to use.";
4731 	if (context->cmd) {
4732 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
4733 				item_tester_hook_staff, itemmode)) {
4734 			return false;
4735 		}
4736 	} else if (!get_item(&obj, q, s, 0, item_tester_hook_staff,
4737 				  itemmode)) {
4738 		return false;
4739 	}
4740 
4741 	/* Extract the object "level" */
4742 	lev = obj->kind->level;
4743 
4744 	/* Roll for good */
4745 	if (randint1(lev) > 25) {
4746 		good = true;
4747 		/* Roll for great */
4748 		if (randint1(lev) > 50) {
4749 			great = true;
4750 		}
4751 	}
4752 
4753 	/* Destroy the staff */
4754 	if (object_is_carried(player, obj)) {
4755 		staff = gear_object_for_use(obj, 1, true, &none_left);
4756 	} else {
4757 		staff = floor_object_for_use(obj, 1, true, &none_left);
4758 	}
4759 
4760 	if (staff->known) {
4761 		object_delete(&staff->known);
4762 	}
4763 	object_delete(&staff);
4764 
4765 	/* Make some arrows */
4766 	arrows = make_object(cave, player->lev, good, great, false, NULL, TV_ARROW);
4767 	drop_near(cave, &arrows, 0, player->grid, true, true);
4768 
4769 	return true;
4770 }
4771 
4772 /**
4773  * Draw energy from a magical device
4774  */
effect_handler_TAP_DEVICE(effect_handler_context_t * context)4775 bool effect_handler_TAP_DEVICE(effect_handler_context_t *context)
4776 {
4777 	int lev;
4778 	int energy = 0;
4779 	struct object *obj;
4780 	bool used = false;
4781 	int itemmode = (USE_INVEN | USE_FLOOR);
4782 	const char *q, *s;
4783 	char *item = "";
4784 
4785 	/* Get an item */
4786 	q = "Drain charges from which item? ";
4787 	s = "You have nothing to drain charges from.";
4788 	if (context->cmd) {
4789 		if (cmd_get_item(context->cmd, "tgtitem", &obj, q, s,
4790 				item_tester_hook_recharge, itemmode)) {
4791 			return used;
4792 		}
4793 	} else if (!get_item(&obj, q, s, 0, item_tester_hook_recharge,
4794 				  itemmode)) {
4795 		return (used);
4796 	}
4797 
4798 	/* Extract the object "level" */
4799 	lev = obj->kind->level;
4800 
4801 	/* Extract the object's energy and get its generic name. */
4802 	if (tval_is_staff(obj)) {
4803 		energy = (5 + lev) * 3 * obj->pval / 2;
4804 		item = "staff";
4805 	} else if (tval_is_wand(obj)) {
4806 		energy = (5 + lev) * 3 * obj->pval / 2;
4807 		item = "wand";
4808 	}
4809 
4810 	/* Turn energy into mana. */
4811 	if (energy < 36) {
4812 		/* Require a resonable amount of energy */
4813 		msg("That %s had no useable energy", item);
4814 	} else {
4815 		/* If mana below maximum, increase mana and drain object. */
4816 		if (player->csp < player->msp) {
4817 			/* Drain the object. */
4818 			obj->pval = 0;
4819 
4820 
4821 			/* Combine / Reorder the pack (later) */
4822 			player->upkeep->notice |= (PN_COMBINE);
4823 
4824 			/* Redraw stuff */
4825 			player->upkeep->redraw |= (PR_INVEN);
4826 
4827 			/* Increase mana. */
4828 			player->csp += energy / 6;
4829 			player->csp_frac = 0;
4830 			if (player->csp > player->msp) {
4831 				(player->csp = player->msp);
4832 			}
4833 
4834 			msg("You feel your head clear.");
4835 			used = true;
4836 
4837 			player->upkeep->redraw |= (PR_MANA);
4838 		} else {
4839 			char *cap = string_make(item);
4840 			my_strcap(cap);
4841 			msg("Your mana was already at its maximum.  %s not drained.", cap);
4842 			string_free(cap);
4843 		}
4844 	}
4845 
4846 	return (used);
4847 }
4848 
4849 /**
4850  * Draw energy from a nearby undead
4851  */
effect_handler_TAP_UNLIFE(effect_handler_context_t * context)4852 bool effect_handler_TAP_UNLIFE(effect_handler_context_t *context)
4853 {
4854 	int amount = effect_calculate_value(context, false);
4855 	struct loc target;
4856 	struct monster *mon = NULL;
4857 	char m_name[80];
4858 	int drain = 0;
4859 	bool fear = false;
4860 	bool dead = false;
4861 
4862 	context->ident = true;
4863 
4864 	/* Closest living monster */
4865 	if (!target_set_closest(TARGET_KILL, monster_is_undead)) {
4866 		return false;
4867 	}
4868 	target_get(&target);
4869 	mon = target_get_monster();
4870 
4871 	/* Hurt the monster */
4872 	monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG);
4873 	msg("You draw power from the %s.", m_name);
4874 	drain = MIN(mon->hp, amount) / 4;
4875 	dead = mon_take_hit(mon, amount, &fear, " is destroyed!");
4876 
4877 	/* Gain mana */
4878 	effect_simple(EF_RESTORE_MANA, context->origin, format("%d", drain), 0, 0,
4879 				  0, 0, 0, NULL);
4880 
4881 	/* Handle fear for surviving monsters */
4882 	if (!dead && monster_is_visible(mon)) {
4883 		message_pain(mon, amount);
4884 		if (fear) {
4885 			add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true);
4886 		}
4887 	}
4888 
4889 	return true;
4890 }
4891 
4892 /**
4893  * Perform a player shapechange
4894  */
effect_handler_SHAPECHANGE(effect_handler_context_t * context)4895 bool effect_handler_SHAPECHANGE(effect_handler_context_t *context)
4896 {
4897 	struct player_shape *shape = player_shape_by_idx(context->subtype);
4898 	bool ident = false;
4899 
4900 	assert(shape);
4901 
4902 	/* Change shape */
4903 	player->shape = lookup_player_shape(shape->name);
4904 	msg("You assume the shape of a %s!", shape->name);
4905 	msg("Your gear merges into your body.");
4906 
4907 	/* Do effect */
4908 	if (shape->effect) {
4909 		(void) effect_do(shape->effect, source_player(), NULL, &ident, true,
4910 						 0, 0, 0, NULL);
4911 	}
4912 
4913 	/* Update */
4914 	shape_learn_on_assume(player, shape->name);
4915 	player->upkeep->update |= (PU_BONUS);
4916 	player->upkeep->redraw |= (PR_TITLE | PR_MISC);
4917 	handle_stuff(player);
4918 
4919 	return true;
4920 }
4921 
4922 /**
4923  * Curse a monster for direct damage
4924  */
effect_handler_CURSE(effect_handler_context_t * context)4925 bool effect_handler_CURSE(effect_handler_context_t *context)
4926 {
4927 	int dam = effect_calculate_value(context, false);
4928 	struct monster *mon = target_get_monster();
4929 	bool fear = false;
4930 	bool dead = false;
4931 
4932 	context->ident = true;
4933 
4934 	/* Need to choose a monster, not just point */
4935 	if (!mon) {
4936 		msg("No monster selected!");
4937 		return false;
4938 	}
4939 
4940 	/* Hit it */
4941 	dead = mon_take_hit(mon, dam, &fear, " dies!");
4942 
4943 	/* Handle fear for surviving monsters */
4944 	if (!dead && monster_is_visible(mon)) {
4945 		message_pain(mon, dam);
4946 		if (fear) {
4947 			add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true);
4948 		}
4949 	}
4950 
4951 	return true;
4952 }
4953 
4954 /**
4955  * Take control of a monster
4956  */
effect_handler_COMMAND(effect_handler_context_t * context)4957 bool effect_handler_COMMAND(effect_handler_context_t *context)
4958 {
4959 	int amount = effect_calculate_value(context, false);
4960 	struct monster *mon = target_get_monster();
4961 
4962 	context->ident = true;
4963 
4964 	/* Need to choose a monster, not just point */
4965 	if (!mon) {
4966 		msg("No monster selected!");
4967 		return false;
4968 	}
4969 
4970 	/* Wake up, become aware */
4971 	monster_wake(mon, false, 100);
4972 
4973 	/* Explicit saving throw */
4974 	if (randint1(player->lev) < randint1(mon->race->level)) {
4975 		char m_name[80];
4976 		monster_desc(m_name, sizeof(m_name), mon, MDESC_STANDARD);
4977 		msg("%s resists your command!", m_name);
4978 		return false;
4979 	}
4980 
4981 	/* Player is commanding */
4982 	player_set_timed(player, TMD_COMMAND, MAX(amount, 0), false);
4983 
4984 	/* Monster is commanded */
4985 	mon_inc_timed(mon, MON_TMD_COMMAND, MAX(amount, 0), 0);
4986 
4987 	return true;
4988 }
4989 
4990 /**
4991  * Jump next to a living monster and draw hitpoints and nourishment from it
4992  */
effect_handler_JUMP_AND_BITE(effect_handler_context_t * context)4993 bool effect_handler_JUMP_AND_BITE(effect_handler_context_t *context)
4994 {
4995 	int amount = effect_calculate_value(context, false);
4996 	struct loc victim, grid;
4997 	int d, first_d = randint0(8);
4998 	struct monster *mon = NULL;
4999 	char m_name[80];
5000 	int drain = 0;
5001 	bool fear = false;
5002 	bool dead = false;
5003 
5004 	context->ident = true;
5005 
5006 	/* Closest living monster */
5007 	if (!target_set_closest(TARGET_KILL, monster_is_living)) {
5008 		return false;
5009 	}
5010 	target_get(&victim);
5011 	mon = target_get_monster();
5012 	monster_desc(m_name, sizeof(m_name), mon, MDESC_TARG);
5013 
5014 	/* Look next to the monster */
5015 	for (d = first_d; d < first_d + 8; d++) {
5016 		grid = loc_sum(victim, ddgrid_ddd[d % 8]);
5017 		if (square_isplayertrap(cave, grid)) continue;
5018 		if (square_iswebbed(cave, grid)) continue;
5019 		if (square_isopen(cave, grid)) break;
5020 	}
5021 
5022 	/* Needed to be adjacent */
5023 	if (d == first_d + 8) {
5024 		msg("Not enough room next to %s!", m_name);
5025 		return false;
5026 	}
5027 
5028 	/* Sound */
5029 	sound(MSG_TELEPORT);
5030 
5031 	/* Move player */
5032 	monster_swap(player->grid, grid);
5033 
5034 	/* Now bite it */
5035 	drain = MIN(mon->hp, amount);
5036 	if (drain == 0) return true;
5037 	if (OPT(player, show_damage)) {
5038 		msg("You bite %s. (%d)", m_name, drain);
5039 	} else {
5040 		msg("You bite %s.", m_name);
5041 	}
5042 	dead = mon_take_hit(mon, amount, &fear, " is drained dry!");
5043 
5044 	/* Heal and nourish */
5045 	effect_simple(EF_HEAL_HP, context->origin, format("%d", drain), 0, 0, 0,
5046 				  0, 0, NULL);
5047 	player_inc_timed(player, TMD_FOOD, MAX(drain, 0), false, false);
5048 
5049 	/* Handle fear for surviving monsters */
5050 	if (!dead && monster_is_visible(mon)) {
5051 		message_pain(mon, amount);
5052 		if (fear) {
5053 			add_monster_message(mon, MON_MSG_FLEE_IN_TERROR, true);
5054 		}
5055 	}
5056 
5057 	return true;
5058 }
5059 
5060 /**
5061  * Move up to 4 spaces then do melee blows.
5062  * Could vary the length of the move without much work.
5063  */
effect_handler_MOVE_ATTACK(effect_handler_context_t * context)5064 bool effect_handler_MOVE_ATTACK(effect_handler_context_t *context)
5065 {
5066 	int blows = effect_calculate_value(context, false);
5067 	int moves = 4;
5068 	int d, i;
5069 	struct loc target = player->grid;
5070 	struct loc next_grid, grid_diff;
5071 	bool fear;
5072 	struct monster *mon;
5073 
5074 	/* Ask for a target */
5075 	if (context->dir == DIR_TARGET) {
5076 		target_get(&target);
5077 	} else {
5078 		target = loc_sum(player->grid, ddgrid[context->dir]);
5079 	}
5080 
5081 	mon = square_monster(cave, target);
5082 	if (mon == NULL || !monster_is_obvious(mon)) {
5083 		msg("This spell must target a monster.");
5084 		return false;
5085 	}
5086 
5087 	while (distance(player->grid, target) > 1 && moves > 0) {
5088 		int choice[] = { 0, 1, -1 };
5089 		bool attack = false;
5090 		grid_diff = loc_diff(target, player->grid);
5091 
5092 		/* Choice of direction simplified by prioritizing diagonals */
5093 		if (grid_diff.x == 0) {
5094 			d = (grid_diff.y < 0) ? 0 : 4; /* up : down */
5095 		} else if (grid_diff.y == 0) {
5096 			d = (grid_diff.x < 0) ? 6 : 2; /* left : right */
5097 		} else if (grid_diff.x < 0) {
5098 			d = (grid_diff.y < 0) ? 7 : 5; /* up-left : down-left */
5099 		} else {/* grid_diff.x > 0 */
5100 			d = (grid_diff.y < 0) ? 1 : 3; /* up-right : down-right */
5101 		}
5102 
5103 		/* We'll give up to 3 choices: d, d + 1, d - 1 */
5104 		for (i = 0; i < 3; i++) {
5105 			int d_test = (d + choice[i] + 8) % 8;
5106 			next_grid = loc_sum(player->grid, clockwise_grid[d_test]);
5107 			if (square_ispassable(cave, next_grid)) {
5108 				d = d_test;
5109 				if (square_monster(cave, next_grid)) attack = true;
5110 				break;
5111 			} else if (i == 2) {
5112 				msg("The way is barred.");
5113 				return moves != 4;
5114 			}
5115 		}
5116 
5117 		move_player(clockwise_ddd[d], false);
5118 		moves--;
5119 		if (attack) return false;
5120 	}
5121 
5122 	/* Reduce blows based on distance traveled, round to nearest blow */
5123 	blows = (blows * moves + 2) / 4;
5124 
5125 	/* Should return some energy if monster dies early */
5126 	while (blows-- > 0) {
5127 		if (py_attack_real(player, target, &fear)) break;
5128 	}
5129 
5130 	return true;
5131 }
5132 
5133  /**
5134  * Enter single combat with an enemy
5135  */
effect_handler_SINGLE_COMBAT(effect_handler_context_t * context)5136 bool effect_handler_SINGLE_COMBAT(effect_handler_context_t *context)
5137 {
5138 	struct monster *mon = target_get_monster();
5139 	context->ident = true;
5140 
5141 	/* Already in an arena */
5142 	if (player->upkeep->arena_level) {
5143 		msg("You are already in single combat!");
5144 		return false;
5145 	}
5146 
5147 	/* Need to choose a monster, not just point */
5148 	if (mon) {
5149 		int old_idx = mon->midx;
5150 
5151 		/* Monsters with high spell power can resist */
5152 		if (randint0(mon->race->spell_power) > player->lev) {
5153 			char m_name[80];
5154 			monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL);
5155 			msg("%s resists!", m_name);
5156 			return true;
5157 		}
5158 
5159 		/* Swap the targeted monster with the first in the monster list */
5160 		if (old_idx == 1) {
5161 			/* Do nothing */
5162 			;
5163 		} else if (cave_monster(cave, 1)->race) {
5164 			monster_index_move(old_idx, cave_monster_max(cave));
5165 			monster_index_move(1, old_idx);
5166 			monster_index_move(cave_monster_max(cave), 1);
5167 		} else {
5168 			monster_index_move(old_idx, 1);
5169 		}
5170 		target_set_monster(cave_monster(cave, 1));
5171 	} else {
5172 		msg("No monster selected!");
5173 		return false;
5174 	}
5175 
5176 	/* Head to the arena */
5177 	player->upkeep->arena_level = true;
5178 	dungeon_change_level(player, player->depth);
5179 	return true;
5180 }
5181 
5182 
effect_handler_MELEE_BLOWS(effect_handler_context_t * context)5183 bool effect_handler_MELEE_BLOWS(effect_handler_context_t *context)
5184 {
5185 	int blows = effect_calculate_value(context, false);
5186 	int dam = context->radius;
5187 	bool fear;
5188 	int taim;
5189 	struct loc target = loc(-1, -1);
5190 	struct loc grid = player->grid;
5191 	struct monster *mon = NULL;
5192 
5193 	/* players only for now */
5194 	if (context->origin.what != SRC_PLAYER)
5195 		return false;
5196 
5197 	/* Ask for a target if no direction given */
5198 	if (context->dir == DIR_TARGET && target_okay()) {
5199 		target_get(&target);
5200 	} else {
5201 		target = loc_sum(player->grid, ddgrid[context->dir]);
5202 	}
5203 
5204 	/* Check target validity */
5205 	taim = distance(grid, target);
5206 	mon = square_monster(cave, target);
5207 	if (taim > 1) {
5208 		msgt(MSG_GENERIC, "Target too far away (%d).", taim);
5209 		return false;
5210 	} else if (!mon) {
5211 		msg("You must attack a monster.");
5212 		return false;
5213 	}
5214 
5215 	while ((blows-- > 0) && mon) {
5216 		/* Test for damaging the monster */
5217 		int hp = mon->hp;
5218 		if (py_attack_real(player, target, &fear)) return true;
5219 		/*mon = square_monster(cave, target); */
5220 		if (mon && (mon->hp == hp)) continue;
5221 
5222 		/* Apply side-effects */
5223 		if (project(context->origin, 0, target, dam, context->subtype,
5224 					PROJECT_KILL, 0, 0, context->obj)) {
5225 			context->ident = true;
5226 		}
5227 	}
5228 	return true;
5229 }
5230 
effect_handler_SWEEP(effect_handler_context_t * context)5231 bool effect_handler_SWEEP(effect_handler_context_t *context)
5232 {
5233 	int blows = effect_calculate_value(context, false);
5234 	bool fear;
5235 	int i;
5236 	struct loc target;
5237 
5238 	/* Players only for now */
5239 	if (context->origin.what != SRC_PLAYER)	return false;
5240 
5241 	/* Doing these like >1 blows means spinning around multiple times. */
5242 	while (blows-- > 0) {
5243 		for (i = 0; i < 8; i++) {
5244 			target = loc_sum(player->grid, clockwise_grid[i]);
5245 			if (square_monster(cave, target) != NULL)
5246 				py_attack_real(player, target, &fear);
5247 		}
5248 	}
5249 
5250 	/* Should return some energy if all enemies killed and blows remain? */
5251 	return true;
5252 }
5253 
5254 
5255 
5256 /**
5257  * One Ring activation
5258  */
effect_handler_BIZARRE(effect_handler_context_t * context)5259 bool effect_handler_BIZARRE(effect_handler_context_t *context)
5260 {
5261 	context->ident = true;
5262 
5263 	/* Pick a random effect */
5264 	switch (randint1(10))
5265 	{
5266 		case 1:
5267 		case 2:
5268 		{
5269 			/* Message */
5270 			msg("You are surrounded by a malignant aura.");
5271 
5272 			/* Decrease all stats (permanently) */
5273 			player_stat_dec(player, STAT_STR, true);
5274 			player_stat_dec(player, STAT_INT, true);
5275 			player_stat_dec(player, STAT_WIS, true);
5276 			player_stat_dec(player, STAT_DEX, true);
5277 			player_stat_dec(player, STAT_CON, true);
5278 
5279 			/* Lose some experience (permanently) */
5280 			player_exp_lose(player, player->exp / 4, true);
5281 
5282 			return true;
5283 		}
5284 
5285 		case 3:
5286 		{
5287 			/* Message */
5288 			msg("You are surrounded by a powerful aura.");
5289 
5290 			/* Dispel monsters */
5291 			effect_simple(EF_PROJECT_LOS, context->origin, "1000", PROJ_DISP_ALL, 0, 0, 0, 0, NULL);
5292 
5293 			return true;
5294 		}
5295 
5296 		case 4:
5297 		case 5:
5298 		case 6:
5299 		{
5300 			/* Mana Ball */
5301 			int flg = PROJECT_THRU | PROJECT_STOP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
5302 			struct loc target = loc_sum(player->grid, ddgrid[context->dir]);
5303 
5304 			/* Ask for a target if no direction given */
5305 			if ((context->dir == DIR_TARGET) && target_okay()) {
5306 				flg &= ~(PROJECT_STOP | PROJECT_THRU);
5307 
5308 				target_get(&target);
5309 			}
5310 
5311 			/* Aim at the target, explode */
5312 			return (project(source_player(), 3, target, 300, PROJ_MANA, flg, 0,
5313 							0, context->obj));
5314 		}
5315 
5316 		case 7:
5317 		case 8:
5318 		case 9:
5319 		case 10:
5320 		{
5321 			/* Mana Bolt */
5322 			int flg = PROJECT_STOP | PROJECT_KILL | PROJECT_THRU;
5323 			struct loc target = loc_sum(player->grid, ddgrid[context->dir]);
5324 
5325 			/* Use an actual target */
5326 			if ((context->dir == DIR_TARGET) && target_okay())
5327 				target_get(&target);
5328 
5329 			/* Aim at the target, do NOT explode */
5330 			return project(source_player(), 0, target, 250, PROJ_MANA, flg, 0,
5331 						   0, context->obj);
5332 		}
5333 	}
5334 
5335 	return false;
5336 }
5337 
5338 /**
5339  * The "wonder" effect.
5340  *
5341  * This spell should become more useful (more
5342  * controlled) as the player gains experience levels.
5343  * Thus, add 1/5 of the player's level to the die roll.
5344  * This eliminates the worst effects later on, while
5345  * keeping the results quite random.  It also allows
5346  * some potent effects only at high level
5347  */
effect_handler_WONDER(effect_handler_context_t * context)5348 bool effect_handler_WONDER(effect_handler_context_t *context)
5349 {
5350 	int plev = player->lev;
5351 	int die = effect_calculate_value(context, false);
5352 	int subtype = 0, radius = 0, other = 0, y = 0, x = 0;
5353 	int beam = context->beam;
5354 	effect_handler_f handler = NULL;
5355 	random_value value = { 0, 0, 0, 0 };
5356 
5357 	context->ident = true;
5358 
5359 	if (die > 100)
5360 		msg("You feel a surge of power!");
5361 
5362 	if (die < 8) {
5363 		subtype = PROJ_MON_CLONE;
5364 		handler = effect_handler_BOLT;
5365 	} else if (die < 14) {
5366 		subtype = PROJ_MON_SPEED;
5367 		value.base = 100;
5368 		handler = effect_handler_BOLT;
5369 	} else if (die < 26) {
5370 		subtype = PROJ_MON_HEAL;
5371 		value.dice = 4;
5372 		value.sides = 6;
5373 		handler = effect_handler_BOLT;
5374 	} else if (die < 31) {
5375 		subtype = PROJ_MON_POLY;
5376 		value.base = plev;
5377 		handler = effect_handler_BOLT;
5378 	} else if (die < 36) {
5379 		beam -= 10;
5380 		subtype = PROJ_MISSILE;
5381 		value.dice = 3 + ((plev - 1) / 5);
5382 		value.sides = 4;
5383 		handler = effect_handler_BOLT_OR_BEAM;
5384 	} else if (die < 41) {
5385 		subtype = PROJ_MON_CONF;
5386 		value.base = plev;
5387 		handler = effect_handler_BOLT;
5388 	} else if (die < 46) {
5389 		subtype = PROJ_POIS;
5390 		value.base = 20 + plev / 2;
5391 		radius = 3;
5392 		handler = effect_handler_BALL;
5393 	} else if (die < 51) {
5394 		subtype = PROJ_LIGHT_WEAK;
5395 		value.dice = 6;
5396 		value.sides = 8;
5397 		handler = effect_handler_LINE;
5398 	} else if (die < 56) {
5399 		subtype = PROJ_ELEC;
5400 		value.dice = 3 + ((plev - 5) / 6);
5401 		value.sides = 6;
5402 		handler = effect_handler_BEAM;
5403 	} else if (die < 61) {
5404 		beam -= 10;
5405 		subtype = PROJ_COLD;
5406 		value.dice = 5 + ((plev - 5) / 4);
5407 		value.sides = 8;
5408 		handler = effect_handler_BOLT_OR_BEAM;
5409 	} else if (die < 66) {
5410 		subtype = PROJ_ACID;
5411 		value.dice = 6 + ((plev - 5) / 4);
5412 		value.sides = 8;
5413 		handler = effect_handler_BOLT_OR_BEAM;
5414 	} else if (die < 71) {
5415 		subtype = PROJ_FIRE;
5416 		value.dice = 8 + ((plev - 5) / 4);
5417 		value.sides = 8;
5418 		handler = effect_handler_BOLT_OR_BEAM;
5419 	} else if (die < 76) {
5420 		subtype = PROJ_MON_DRAIN;
5421 		value.base = 75;
5422 		handler = effect_handler_BOLT;
5423 	} else if (die < 81) {
5424 		subtype = PROJ_ELEC;
5425 		value.base = 30 + plev / 2;
5426 		radius = 2;
5427 		handler = effect_handler_BALL;
5428 	} else if (die < 86) {
5429 		subtype = PROJ_ACID;
5430 		value.base = 40 + plev;
5431 		radius = 2;
5432 		handler = effect_handler_BALL;
5433 	} else if (die < 91) {
5434 		subtype = PROJ_ICE;
5435 		value.base = 70 + plev;
5436 		radius = 3;
5437 		handler = effect_handler_BALL;
5438 	} else if (die < 96) {
5439 		subtype = PROJ_FIRE;
5440 		value.base = 80 + plev;
5441 		radius = 3;
5442 		handler = effect_handler_BALL;
5443 	} else if (die < 101) {
5444 		subtype = PROJ_MON_DRAIN;
5445 		value.base = 100 + plev;
5446 		handler = effect_handler_BOLT;
5447 	} else if (die < 104) {
5448 		radius = 12;
5449 		handler = effect_handler_EARTHQUAKE;
5450 	} else if (die < 106) {
5451 		radius = 15;
5452 		handler = effect_handler_DESTRUCTION;
5453 	} else if (die < 108) {
5454 		handler = effect_handler_BANISH;
5455 	} else if (die < 110) {
5456 		subtype = PROJ_DISP_ALL;
5457 		value.base = 120;
5458 		handler = effect_handler_PROJECT_LOS;
5459 	}
5460 
5461 	if (handler != NULL) {
5462 		effect_handler_context_t new_context = {
5463 			context->effect,
5464 			context->origin,
5465 			context->obj,
5466 			context->aware,
5467 			context->dir,
5468 			beam,
5469 			context->boost,
5470 			value,
5471 			subtype, radius, other, y, x,
5472 			NULL,
5473 			context->ident,
5474 			context->cmd
5475 		};
5476 
5477 		return handler(&new_context);
5478 	} else {
5479 		/* RARE */
5480 		effect_simple(EF_PROJECT_LOS, context->origin, "150", PROJ_DISP_ALL, 0, 0, 0, 0, NULL);
5481 		effect_simple(EF_PROJECT_LOS, context->origin, "20", PROJ_MON_SLOW, 0, 0, 0, 0, NULL);
5482 		effect_simple(EF_PROJECT_LOS, context->origin, "40", PROJ_SLEEP_ALL, 0, 0, 0, 0, NULL);
5483 		effect_simple(EF_HEAL_HP, context->origin, "300", 0, 0, 0, 0, 0, NULL);
5484 
5485 		return true;
5486 	}
5487 }
5488 
5489 
5490 /**
5491  * ------------------------------------------------------------------------
5492  * Properties of effects
5493  * ------------------------------------------------------------------------ */
5494 /**
5495  * Useful things about effects.
5496  */
5497 static const struct effect_kind effects[] =
5498 {
5499 	{ EF_NONE, false, NULL, NULL, NULL },
5500 	#define F(x) effect_handler_##x
5501 	#define EFFECT(x, a, b, c, d, e)	{ EF_##x, a, b, F(x), e },
5502 	#include "list-effects.h"
5503 	#undef EFFECT
5504 	#undef F
5505 	{ EF_MAX, false, NULL, NULL, NULL }
5506 };
5507 
5508 
5509 static const char *effect_names[] = {
5510 	NULL,
5511 	#define EFFECT(x, a, b, c, d, e)	#x,
5512 	#include "list-effects.h"
5513 	#undef EFFECT
5514 };
5515 
5516 /*
5517  * Utility functions
5518  */
5519 
5520 /**
5521  * Free all the effects in a structure
5522  *
5523  * \param source the effects being freed
5524  */
free_effect(struct effect * source)5525 void free_effect(struct effect *source)
5526 {
5527 	struct effect *e = source, *e_next;
5528 	while (e) {
5529 		e_next = e->next;
5530 		dice_free(e->dice);
5531 		if (e->msg) {
5532 			string_free(e->msg);
5533 		}
5534 		mem_free(e);
5535 		e = e_next;
5536 	}
5537 }
5538 
effect_valid(const struct effect * effect)5539 bool effect_valid(const struct effect *effect)
5540 {
5541 	if (!effect) return false;
5542 	return effect->index > EF_NONE && effect->index < EF_MAX;
5543 }
5544 
effect_aim(const struct effect * effect)5545 bool effect_aim(const struct effect *effect)
5546 {
5547 	const struct effect *e = effect;
5548 
5549 	if (!effect_valid(effect))
5550 		return false;
5551 
5552 	while (e) {
5553 		if (effects[e->index].aim) return true;
5554 		e = e->next;
5555 	}
5556 
5557 	return false;
5558 }
5559 
effect_info(const struct effect * effect)5560 const char *effect_info(const struct effect *effect)
5561 {
5562 	if (!effect_valid(effect))
5563 		return NULL;
5564 
5565 	return effects[effect->index].info;
5566 }
5567 
effect_desc(const struct effect * effect)5568 const char *effect_desc(const struct effect *effect)
5569 {
5570 	if (!effect_valid(effect))
5571 		return NULL;
5572 
5573 	return effects[effect->index].desc;
5574 }
5575 
effect_lookup(const char * name)5576 effect_index effect_lookup(const char *name)
5577 {
5578 	size_t i;
5579 
5580 	for (i = 0; i < N_ELEMENTS(effect_names); i++) {
5581 		const char *effect_name = effect_names[i];
5582 
5583 		/* Test for equality */
5584 		if (effect_name != NULL && streq(name, effect_name))
5585 			return i;
5586 	}
5587 
5588 	return EF_MAX;
5589 }
5590 
5591 /**
5592  * Translate a string to an effect parameter subtype index
5593  */
effect_subtype(int index,const char * type)5594 int effect_subtype(int index, const char *type)
5595 {
5596 	int val = -1;
5597 
5598 	/* If not a numerical value, assign according to effect index */
5599 	if (sscanf(type, "%d", &val) != 1) {
5600 		switch (index) {
5601 				/* Projection name */
5602 			case EF_PROJECT_LOS:
5603 			case EF_PROJECT_LOS_AWARE:
5604 			case EF_DESTRUCTION:
5605 			case EF_SPOT:
5606 			case EF_SPHERE:
5607 			case EF_BALL:
5608 			case EF_BREATH:
5609 			case EF_ARC:
5610 			case EF_SHORT_BEAM:
5611 			case EF_LASH:
5612 			case EF_SWARM:
5613 			case EF_STRIKE:
5614 			case EF_STAR:
5615 			case EF_STAR_BALL:
5616 			case EF_BOLT:
5617 			case EF_BEAM:
5618 			case EF_BOLT_OR_BEAM:
5619 			case EF_LINE:
5620 			case EF_ALTER:
5621 			case EF_BOLT_STATUS:
5622 			case EF_BOLT_STATUS_DAM:
5623 			case EF_BOLT_AWARE:
5624 			case EF_MELEE_BLOWS:
5625 			case EF_TOUCH:
5626 			case EF_TOUCH_AWARE: {
5627 				val = proj_name_to_idx(type);
5628 				break;
5629 			}
5630 
5631 				/* Timed effect name */
5632 			case EF_CURE:
5633 			case EF_TIMED_SET:
5634 			case EF_TIMED_INC:
5635 			case EF_TIMED_INC_NO_RES:
5636 			case EF_TIMED_DEC: {
5637 				val = timed_name_to_idx(type);
5638 				break;
5639 			}
5640 
5641 				/* Nourishment types */
5642 			case EF_NOURISH: {
5643 				if (streq(type, "INC_BY"))
5644 					val = 0;
5645 				else if (streq(type, "DEC_BY"))
5646 					val = 1;
5647 				else if (streq(type, "SET_TO"))
5648 					val = 2;
5649 				else if (streq(type, "INC_TO"))
5650 					val = 3;
5651 				break;
5652 			}
5653 
5654 				/* Monster timed effect name */
5655 			case EF_MON_TIMED_INC: {
5656 				val = mon_timed_name_to_idx(type);
5657 				break;
5658 			}
5659 
5660 				/* Summon name */
5661 			case EF_SUMMON: {
5662 				val = summon_name_to_idx(type);
5663 				break;
5664 			}
5665 
5666 				/* Stat name */
5667 			case EF_RESTORE_STAT:
5668 			case EF_DRAIN_STAT:
5669 			case EF_LOSE_RANDOM_STAT:
5670 			case EF_GAIN_STAT: {
5671 				val = stat_name_to_idx(type);
5672 				break;
5673 			}
5674 
5675 				/* Enchant type name - not worth a separate function */
5676 			case EF_ENCHANT: {
5677 				if (streq(type, "TOBOTH"))
5678 					val = ENCH_TOBOTH;
5679 				else if (streq(type, "TOHIT"))
5680 					val = ENCH_TOHIT;
5681 				else if (streq(type, "TODAM"))
5682 					val = ENCH_TODAM;
5683 				else if (streq(type, "TOAC"))
5684 					val = ENCH_TOAC;
5685 				break;
5686 			}
5687 
5688 				/* Player shape name */
5689 			case EF_SHAPECHANGE: {
5690 				val = shape_name_to_idx(type);
5691 				break;
5692 			}
5693 
5694 				/* Targeted earthquake */
5695 			case EF_EARTHQUAKE: {
5696 				if (streq(type, "TARGETED"))
5697 					val = 1;
5698 				else if (streq(type, "NONE"))
5699 					val = 0;
5700 				break;
5701 			}
5702 
5703 				/* Inscribe a glyph */
5704 			case EF_GLYPH: {
5705 				if (streq(type, "WARDING"))
5706 					val = GLYPH_WARDING;
5707 				else if (streq(type, "DECOY"))
5708 					val = GLYPH_DECOY;
5709 				break;
5710 			}
5711 
5712 				/* Allow teleport away */
5713 			case EF_TELEPORT: {
5714 				if (streq(type, "AWAY"))
5715 					val = 1;
5716 				break;
5717 			}
5718 
5719 				/* Allow monster teleport toward */
5720 			case EF_TELEPORT_TO: {
5721 				if (streq(type, "SELF"))
5722 					val = 1;
5723 				break;
5724 			}
5725 
5726 				/* Some effects only want a radius, so this is a dummy */
5727 			default: {
5728 				if (streq(type, "NONE"))
5729 					val = 0;
5730 			}
5731 		}
5732 	}
5733 
5734 	return val;
5735 }
5736 
5737 /**
5738  * ------------------------------------------------------------------------
5739  * Execution of effects
5740  * ------------------------------------------------------------------------ */
5741 /**
5742  * Execute an effect chain.
5743  *
5744  * \param effect is the effect chain
5745  * \param origin is the origin of the effect (player, monster etc.)
5746  * \param obj    is the object making the effect happen (or NULL)
5747  * \param ident  will be updated if the effect is identifiable
5748  *               (NB: no effect ever sets *ident to false)
5749  * \param aware  indicates whether the player is aware of the effect already
5750  * \param dir    is the direction the effect will go in
5751  * \param beam   is the base chance out of 100 that a BOLT_OR_BEAM effect will beam
5752  * \param boost  is the extent to which skill surpasses difficulty, used as % boost. It
5753  *               ranges from 0 to 138.
5754  * \param cmd    If the effect is invoked as part of a command, this is the
5755  *               the command structure - used primarily so repeating the
5756  *               command can use the same information without prompting the
5757  *               player again.  Use NULL for this if not invoked as part of
5758  *               a command.
5759  */
effect_do(struct effect * effect,struct source origin,struct object * obj,bool * ident,bool aware,int dir,int beam,int boost,struct command * cmd)5760 bool effect_do(struct effect *effect,
5761 		struct source origin,
5762 		struct object *obj,
5763 		bool *ident,
5764 		bool aware,
5765 		int dir,
5766 		int beam,
5767 		int boost,
5768 		struct command *cmd)
5769 {
5770 	bool completed = false;
5771 	effect_handler_f handler;
5772 	random_value value = { 0, 0, 0, 0 };
5773 
5774 	do {
5775 		int random_choices = 0, leftover = 0;
5776 
5777 		if (!effect_valid(effect)) {
5778 			msg("Bad effect passed to effect_do(). Please report this bug.");
5779 			return false;
5780 		}
5781 
5782 		if (effect->dice != NULL)
5783 			random_choices = dice_roll(effect->dice, &value);
5784 
5785 		/* Deal with special random effect */
5786 		if (effect->index == EF_RANDOM) {
5787 			int choice = randint0(random_choices);
5788 			leftover = random_choices - choice;
5789 
5790 			/* Skip to the chosen effect */
5791 			effect = effect->next;
5792 			while (choice--)
5793 				effect = effect->next;
5794 
5795 			/* Roll the damage, if needed */
5796 			if (effect->dice != NULL)
5797 				(void) dice_roll(effect->dice, &value);
5798 		}
5799 
5800 		/* Handle the effect */
5801 		handler = effects[effect->index].handler;
5802 		if (handler != NULL) {
5803 			effect_handler_context_t context = {
5804 				effect->index,
5805 				origin,
5806 				obj,
5807 				aware,
5808 				dir,
5809 				beam,
5810 				boost,
5811 				value,
5812 				effect->subtype,
5813 				effect->radius,
5814 				effect->other,
5815 				effect->y,
5816 				effect->x,
5817 				effect->msg,
5818 				*ident,
5819 				cmd
5820 			};
5821 
5822 			completed = handler(&context) || completed;
5823 			*ident = context.ident;
5824 		}
5825 
5826 		/* Get the next effect, if there is one */
5827 		if (leftover)
5828 			/* Skip the remaining non-chosen effects */
5829 			while (leftover--)
5830 				effect = effect->next;
5831 		else
5832 			effect = effect->next;
5833 	} while (effect);
5834 
5835 	return completed;
5836 }
5837 
5838 /**
5839  * Perform a single effect with a simple dice string and parameters
5840  * Calling with ident a valid pointer will (depending on effect) give success
5841  * information; ident = NULL will ignore this
5842  */
effect_simple(int index,struct source origin,const char * dice_string,int subtype,int radius,int other,int y,int x,bool * ident)5843 void effect_simple(int index,
5844 				   struct source origin,
5845 				   const char *dice_string,
5846 				   int subtype,
5847 				   int radius,
5848 				   int other,
5849 				   int y,
5850 				   int x,
5851 				   bool *ident)
5852 {
5853 	struct effect effect;
5854 	int dir = DIR_TARGET;
5855 	bool dummy_ident = false;
5856 
5857 	/* Set all the values */
5858 	memset(&effect, 0, sizeof(effect));
5859 	effect.index = index;
5860 	effect.dice = dice_new();
5861 	dice_parse_string(effect.dice, dice_string);
5862 	effect.subtype = subtype;
5863 	effect.radius = radius;
5864 	effect.other = other;
5865 	effect.y = y;
5866 	effect.x = x;
5867 
5868 	/* Direction if needed */
5869 	if (effect_aim(&effect))
5870 		get_aim_dir(&dir);
5871 
5872 	/* Do the effect */
5873 	if (!ident) {
5874 		ident = &dummy_ident;
5875 	}
5876 
5877 	effect_do(&effect, origin, NULL, ident, true, dir, 0, 0, NULL);
5878 	dice_free(effect.dice);
5879 }
5880