Exemplo n.º 1
0
/*
 * Handle monster hitting a real trap.
 */
void mon_hit_trap(int m_idx, int y, int x)
{
	feature_type *f_ptr;
	monster_type *m_ptr = &m_list[m_idx];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];

	int feat = cave_feat[y][x];

	bool fear;

	/* Option */
	if (!variant_hit_traps) return;

	/* Hack --- don't activate unknown invisible traps */
	if (cave_feat[y][x] == FEAT_INVIS) return;

	/* Get feature */
	f_ptr = &f_info[cave_feat[y][x]];

	/* Hack --- trapped doors */
	/* XXX XXX Dangerous */
	while (!(f_ptr->spell) && !(f_ptr->blow.method) && (f_ptr->flags1 & (FF1_TRAP)))
	{
		pick_trap(y,x);

		/* Error */
		if (cave_feat[y][x] == feat) break;

		feat = cave_feat[y][x];

		/* Get feature */
		f_ptr = &f_info[feat];

	}

	/* Use covered or bridged if necessary */
	if ((f_ptr->flags2 & (FF2_COVERED)) || (f_ptr->flags2 & (FF2_BRIDGED)))
	{
		f_ptr = &f_info[f_ptr->mimic];
	}

	/* Hack -- monster falls onto trap */
	if ((m_ptr->fy!=y)|| (m_ptr->fx !=x))
	{
		/* Move monster */
		monster_swap(m_ptr->fy, m_ptr->fx, y, x);
	}

	/* Apply the object */
	if ((cave_o_idx[y][x]) && (f_ptr->flags1 & (FF1_HIT_TRAP)))
	{
		object_type *o_ptr = &o_list[cave_o_idx[y][x]];

		char o_name[80];

		int power = 0;

		switch (o_ptr->tval)
		{
			case TV_BOW:
			{
				object_type *j_ptr;
				u32b f1,f2,f3;

				int i, shots = 1;

				/* Get bow */
				j_ptr = o_ptr;

				/* Get bow flags */
				object_flags(o_ptr,&f1,&f2,&f3);

				/* Apply extra shots */
				if (f1 & (TR1_SHOTS)) shots += j_ptr->pval;

				/* Test for hit */
				for (i = 0; i < shots; i++)
				{
					if (j_ptr->next_o_idx)
					{
						int ammo = j_ptr->next_o_idx;
						object_type *i_ptr;
						object_type object_type_body;

						/* Use ammo instead of bow */
						o_ptr = &o_list[ammo];

						/* Describe ammo */
						object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0);

						if ((ammo) && (test_hit_fire((j_ptr->to_h + o_ptr->to_h)* BTH_PLUS_ADJ + f_ptr->power,  r_ptr->ac * (r_ptr->flags2 & (RF2_ARMOR) ? 2 : 1), TRUE)))
						{
							int k, mult;

							switch (j_ptr->sval)
							{
								case SV_SLING:
								case SV_SHORT_BOW:
								mult = 2;
								break;
								case SV_LONG_BOW:
								case SV_LIGHT_XBOW:
									mult = 3;
									break;
								case SV_HEAVY_XBOW:
									mult = 4;
									break;
								default:
									mult = 1;
									break;
							}

							/* Apply extra might */
							if (f1 & (TR1_MIGHT)) mult += j_ptr->pval;

							k = damroll(o_ptr->dd, o_ptr->ds);
							k *= mult;

							k = tot_dam_aux(o_ptr, k, m_ptr);

							k = critical_shot(o_ptr->weight, o_ptr->to_h + j_ptr->to_h, k);
							k += o_ptr->to_d + j_ptr->to_d;

							/* No negative damage */
							if (k < 0) k = 0;

							/* Trap description */
							msg_format("%^s hits you.",o_name);

							/* Damage, check for fear and death */
							(void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL);

						}
						else
						{
							/* Trap description */
							msg_format("%^s narrowly misses you.",o_name);
						}

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Drop nearby - some chance of breakage */
						drop_near(i_ptr,y,x,breakage_chance(i_ptr));

						/* Decrease the item */
						floor_item_increase(ammo, -1);
						floor_item_optimize(ammo);

						break;
					}
					else
					{
						/* Disarm */
						cave_alter_feat(y,x,FS_DISARM);
					}
				}
			}

			case TV_SHOT:
			case TV_ARROW:
			case TV_BOLT:
			case TV_HAFTED:
			case TV_SWORD:
			case TV_POLEARM:
			{
				object_type *i_ptr;
				object_type object_type_body;

				/* Describe ammo */
				object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0);

				/* Test for hit */
				if (test_hit_norm(o_ptr->to_h * BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac, TRUE))
				{
					int k;

					k = damroll(o_ptr->dd, o_ptr->ds);

					k = tot_dam_aux(o_ptr, k, m_ptr);

					k = critical_norm(o_ptr->weight, o_ptr->to_h, k);
					k += o_ptr->to_d;

					/* Armour reduces total damage */
					k -= (k * ((p_ptr->ac < 150) ? p_ptr->ac : 150) / 250);

					/* No negative damage */
					if (k < 0) k = 0;

					/* Trap description */
					msg_format("%^s hits you.",o_name);

					/* Damage, check for fear and death */
					(void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL);

				}
				else
				{
					/* Trap description */
					msg_format("%^s narrowly misses you.",o_name);					
				}

				/* Get local object */
				i_ptr = &object_type_body;

				/* Obtain a local object */
				object_copy(i_ptr, o_ptr);

				/* Modify quantity */
				i_ptr->number = 1;

				/* Drop nearby - some chance of breakage */
				drop_near(i_ptr,y,x,breakage_chance(i_ptr));

				/* Decrease the item */
				floor_item_increase(cave_o_idx[y][x], -1);
				floor_item_optimize(cave_o_idx[y][x]);

				/* Disarm if runs out */
				if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);

				break;
			}

			case TV_WAND:
			case TV_STAFF:
			{
				if (o_ptr->pval > 0)
				{
					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* XXX Hack -- new unstacking code */
					o_ptr->stackc++;

					/* No spare charges */	
					if (o_ptr->stackc >= o_ptr->number)
					{
						/* Use a charge off the stack */
						o_ptr->pval--;

						/* Reset the stack count */
						o_ptr->stackc = 0;
					}

					/* XXX Hack -- unstack if necessary */
					if ((o_ptr->number > 1) &&
					((!variant_pval_stacks) || 
					((!object_known_p(o_ptr) && (o_ptr->pval == 2) && (o_ptr->stackc > 1)) ||
					  (!object_known_p(o_ptr) && (rand_int(o_ptr->number) <= o_ptr->stackc) &&
					  (o_ptr->stackc != 1) && (o_ptr->pval > 2)))))
					{
						object_type *i_ptr;
						object_type object_type_body;

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Reset stack counter */
						i_ptr->stackc = 0;
 
				 		/* Unstack the used item */
				 		o_ptr->number--;

						/* Reduce the charges on the new item */
						if (o_ptr->stackc > 1)
						{
							i_ptr->pval-=2;
							o_ptr->stackc--;
						}
						else if (!o_ptr->stackc)
						{
							i_ptr->pval--;
							o_ptr->pval++;
							o_ptr->stackc = o_ptr->number-1;
						}

						(void)floor_carry(y,x,i_ptr);
					}
				}
				else
				{
					/* Disarm if runs out */
					cave_alter_feat(y,x,FS_DISARM);
				}

				break;
			}

			case TV_ROD:
			case TV_DRAG_ARMOR:
			{
				if (!((o_ptr->timeout) && ((!o_ptr->stackc) || (o_ptr->stackc >= o_ptr->number))))
				{
					int tmpval;

					/* Store pval */
					tmpval = o_ptr->timeout;

					/* Time rod out */
					o_ptr->timeout = o_ptr->pval;

					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* Has a power */
					/* Hack -- check if we are stacking rods */
					if ((o_ptr->timeout > 0) && (!(tmpval) || stack_force_times))
					{
						/* Hack -- one more rod charging */
						if (o_ptr->timeout) o_ptr->stackc++;

						/* Reset stack count */
						if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0;

						/* Hack -- always use maximum timeout */
						if (tmpval > o_ptr->timeout) o_ptr->timeout = tmpval;
					}

					/* XXX Hack -- unstack if necessary */
					if ((o_ptr->number > 1) && (o_ptr->timeout > 0))
					{
						object_type *i_ptr;
						object_type object_type_body;

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Clear stack counter */
						i_ptr->stackc = 0;

						/* Restore "charge" */
						o_ptr->timeout = tmpval;

						/* Unstack the used item */
						o_ptr->number--;

						/* Reset the stack if required */
						if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0;

						(void)floor_carry(y,x,i_ptr);
					}
				}
				break;
			}

			case TV_POTION:
			case TV_SCROLL:
			case TV_FLASK:
			case TV_FOOD:
			{
				/* Hack -- boring food */
				if ((o_ptr->tval == TV_FOOD) && (o_ptr->sval >= SV_FOOD_MIN_FOOD))
				{
					/* Disarm */
					cave_alter_feat(y,x,FS_DISARM);
				}
				else
				{
					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* Decrease the item */
					floor_item_increase(cave_o_idx[y][x], -1);
					floor_item_optimize(cave_o_idx[y][x]);

					/* Disarm if runs out */
					if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);
				}

				break;
			}

			case TV_RUNESTONE:
			{
				u32b runes = p_ptr->cur_runes;

				int num = 0;
				s16b book[26];

				/* Hack -- use current rune */
				p_ptr->cur_runes = (2 << (o_ptr->sval-1));

				/* Fill the book with spells */
				fill_book(o_ptr,book,&num);

				/* Unhack */
				p_ptr->cur_runes = runes;

				/* Get a power */
				power = book[rand_int(num)];

				/* Decrease the item */
				floor_item_increase(cave_o_idx[y][x], -1);
				floor_item_optimize(cave_o_idx[y][x]);

				/* Disarm if runs out */
				if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);

				break;
			}

			default:
			{
				/* Disarm */
				cave_alter_feat(y,x,FS_DISARM);

				break;
			}
		}

		/* Has a power */
		if (power > 0)
		{
			spell_type *s_ptr = &s_info[power];

			int ap_cnt;

			/* Object is used */
			if (k_info[o_ptr->k_idx].used < MAX_SHORT) k_info[o_ptr->k_idx].used++;

			/* Scan through all four blows */
			for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
			{
				int damage = 0;

				/* Extract the attack infomation */
				int effect = s_ptr->blow[ap_cnt].effect;
				int method = s_ptr->blow[ap_cnt].method;
				int d_dice = s_ptr->blow[ap_cnt].d_dice;
				int d_side = s_ptr->blow[ap_cnt].d_side;
				int d_plus = s_ptr->blow[ap_cnt].d_plus;

				/* Hack -- no more attacks */
				if (!method) break;

				/* Mega hack -- dispel evil/undead objects */
				if (!d_side)
				{
					d_plus += 25 * d_dice;
				}

				/* Roll out the damage */
				if ((d_dice) && (d_side))
				{
					damage = damroll(d_dice, d_side) + d_plus;
				}
				else
				{
					damage = d_plus;
				}

				(void)project_m(0,0,y,x,damage, effect);
				(void)project_f(0,0,y,x,damage, effect);
			}
		}
	}

	/* Regular traps */
	else
	{
		if (f_ptr->spell)
		{
	      		make_attack_spell_aux(0,y,x,f_ptr->spell);
		}
		else if (f_ptr->blow.method)
		{
			int damage = damroll(f_ptr->blow.d_side,f_ptr->blow.d_dice);
   
			/* Apply the blow */
			project_m(0, 0, y, x, damage, f_ptr->blow.effect);
		}

		/* Get feature */
		f_ptr = &f_info[cave_feat[p_ptr->py][p_ptr->px]];

		if (f_ptr->flags1 & (FF1_HIT_TRAP))
		{
			/* Modify the location hit by the trap */
			cave_alter_feat(y,x,FS_HIT_TRAP);
		}
		else if (f_ptr->flags1 & (FF1_SECRET))
		{
			/* Discover */
			cave_alter_feat(y,x,FS_SECRET);
		}
	}
}
Exemplo n.º 2
0
/*
 * do_cmd_mind calls this function if the player's class
 * is 'Reckoner'.
 */
static bool cast_reckoner_spell(int spell)
{
	/* this will vary based on the spells, and what they depend on */
	int     plev = p_ptr->lev;
	int 	b;
	int		py = p_ptr->py;
	int		px = p_ptr->px;
	int 	dir;
	
	/* spell code */
	switch (spell)
	{
    			case 0:	
    					if (plev < 30) 
    					{
    					teleport_player(plev);
    					}  
    					else
    					{
    					teleport_player(plev * 3);
    					}
    					break;
    					
				case 1: 
						b = (randint(50) + plev);
						if (b < 10)
						{
						unlite_area(randint(plev *2), (randint(plev / 5) + 2));
						}
						else if (b < 25)
						{
						unlite_room(py, px);
						}
						else if  (b < 50)
						{
						lite_room(py, px);
						}
						else 
						{
						lite_area(randint(plev * 2), (randint(plev / 5) + 3));
						}
						
						break;
				
				case 2: b = (randint(50) + plev);
						if (b < 20)
						{
						speed_monsters();
						}
						else if (b < 30)
						{
						slow_monsters();
						}
						else if (b < 55)
						{
						sleep_monsters();
						}
						else if (b < 75)
						{
							if (!p_ptr->fast)
							{
								(void)set_fast(randint(plev) + plev);
							}
							else
							{
								(void)set_fast(p_ptr->fast + randint(5));
							}
							break;
						}
						else
						{
						(void)set_fast(p_ptr->fast + b);
						slow_monsters();
						sleep_monsters();
						}
						 break;
				case 3:  if (!get_aim_dir(&dir)) return FALSE; 
						 (void)fire_bolt(GF_NETHER, dir,
								damroll((plev / 2), (3 + plev / 3)));
						 break;
				
				case 4:  if (!get_aim_dir(&dir)) return FALSE;
						 (void)wall_to_mud(dir);
						 break;
						 
				case 5:  (void)hp_player(damroll((plev / 3), plev));
						 (void)set_cut(0);
						 break;
						 
				case 6:  set_recall(); break;
				
				case 7:  if (!get_aim_dir(&dir)) return FALSE;
						 (void)poly_monster(dir);
						 break;
				case 8:  if (plev < 40)
						 {
						 map_area();
						 (void)set_tim_esp(p_ptr->tim_esp + 10);
						 }
						 else
						 {
						 wiz_lite();
						 (void)set_tim_esp(p_ptr->tim_esp + plev);
						 }
						 break;
				case 9:  msg_print("The world changes!");
			
 						 /* Leaving */
						 p_ptr->leaving = TRUE;
						 			
						 break;
				case 10: break;
				case 11: break;
				case 12: break;
				case 13: break;
				case 14: break;
			    case 15: break;
			    case 16: break;
			    case 17: break;
			    case 18: break;
			    case 19: break;
			    case 20: break;
	}

	return TRUE;
}
Exemplo n.º 3
0
/*
 * do_cmd_mind calls this function if the player's class
 * is 'Officer'.
 */
static bool cast_officer_spell(int spell)
{
	/* this will vary based on the spells, and what they depend on */
	int             plev = p_ptr->lev;
	int				dir;
	int 			time = randint(20) + 20;
	
	/* spell code */
	switch (spell)
	{
    			case 0:  if (!get_aim_dir(&dir)) return FALSE;
							(void)fear_monster(dir, plev);
						 break;
				case 1:  if (!get_aim_dir(&dir)) return FALSE;
							(void)fire_bolt(GF_STUN, dir,
							damroll(plev, 5));
						 break;
				case 2:  if (!get_aim_dir(&dir)) return FALSE; 
						 	(void)fire_bolt(GF_CHARM, dir,
						 	damroll(plev, plev));
						 break;
				case 3:  (void)hp_player(damroll((plev / 2), (plev * 2)));
						 (void)set_afraid(0);
						 (void)set_stun(0);
						 (void)set_cut(0);
						 (void)do_res_stat(A_STR);
				 		 (void)do_res_stat(A_INT);
				 		 (void)do_res_stat(A_WIS);
				 		 (void)do_res_stat(A_DEX);
				 		 (void)do_res_stat(A_CON);
				 		 (void)do_res_stat(A_CHR);
						 break;
				case 4:  (void)detect_monsters_normal();
						 break;
				case 5:  (void)set_protevil(p_ptr->protevil + randint(25) + 3 * p_ptr->lev);
						 if (!p_ptr->fast)
						{
							(void)set_fast(randint(20) + plev);
						}
						else
						{
							(void)set_fast(p_ptr->fast + randint(5));
						}
						(void)set_oppose_acid(p_ptr->oppose_acid + time);
						(void)set_oppose_elec(p_ptr->oppose_elec + time);
						(void)set_oppose_fire(p_ptr->oppose_fire + time);
						(void)set_oppose_cold(p_ptr->oppose_cold + time);
						(void)set_oppose_pois(p_ptr->oppose_pois + time);
						(void)set_invuln(p_ptr->invuln + ((plev / 20) + randint(2)));
						break;
				case 6:  if (!get_aim_dir(&dir)) return FALSE;
							fire_ball(GF_CHARM, dir,
				        				  (plev * 4), (plev / 8));
						 break;
				case 7:  break;
				case 8:  break;
				case 9:  break;
				case 10: break;
				case 11: break;
				case 12: break;
				case 13: break;
				case 14: break;
				case 15: break;
				case 16: break;
			    case 17: break;
			    case 18: break;
			    case 19: break;
			    case 20: break;
	}

	return TRUE;
}
Exemplo n.º 4
0
/*
 * Chests have traps too.  High-level chests can be very dangerous, no
 * matter what level they are opened at.  Various traps added in Oangband. -LM-
 *
 * Exploding chest destroys contents (and traps).
 * Note that the chest itself is never destroyed.
 */
static void chest_trap(int y, int x, s16b o_idx)
{
	int i, trap, nasty_tricks_count;
	int j;

	object_type *o_ptr = &o_list[o_idx];

	/* Compensate for the averaging routine in the summon monster function. */
	int summon_level = o_ptr->pval + o_ptr->pval - p_ptr->depth;

	/* Ignore disarmed chests */
	if (o_ptr->pval <= 0) return;

	/* Obtain the traps */
	trap = chest_traps[o_ptr->pval];

	/* Lose strength */
	if (trap & (CHEST_LOSE_STR))
	{
		msg_print("A small needle has pricked you!");
		take_hit(damroll(1, 4), "a poison needle");
		(void)do_dec_stat(A_STR);
	}

	/* Lose constitution */
	if (trap & (CHEST_LOSE_CON))
	{
		msg_print("A small needle has pricked you!");
		take_hit(damroll(1, 4), "a poison needle");
		(void)do_dec_stat(A_CON);
	}

	/* Poison */
	if (trap & (CHEST_POISON))
	{
		msg_print("A puff of green gas surrounds you!");
		pois_hit(25);
	}

	/* Paralyze */
	if (trap & (CHEST_PARALYZE))
	{
		msg_print("A puff of yellow gas surrounds you!");
		if (!p_ptr->free_act)
		{
			(void)set_paralyzed(p_ptr->paralyzed + 10 + randint1(20));
		}
	}

	/* Summon monsters */
	if (trap & (CHEST_SUMMON))
	{
		int num = 2 + randint1(3);
		msg_print("You are enveloped in a cloud of smoke!");
		(void)summon_specific(y, x, FALSE, summon_level, 0, num);
	}

	/* Explode */
	if (trap & (CHEST_EXPLODE))
	{
		msg_print("There is a sudden explosion!");
		msg_print("Everything inside the chest is destroyed!");
		o_ptr->pval = 0;
		take_hit(damroll(5, 8), "an exploding chest");
	}

	/* Scatter contents. */
	if (trap & (CHEST_SCATTER))
	{
		msg_print("The contents of the chest scatter all over the dungeon!");
		chest_death(TRUE, y, x, o_idx);
		o_ptr->pval = 0;
	}

	/* Elemental summon. */
	if (trap & (CHEST_E_SUMMON))
	{
		j = randint1(3) + 5;
		msg_print("Elemental beings appear to protect their treasures!");
		(void) summon_specific(y, x, FALSE, summon_level, SUMMON_ELEMENTAL, j);
	}

	/* Force clouds, then summon birds. */
	if (trap & (CHEST_BIRD_STORM))
	{
		msg_print("A storm of birds swirls around you!");

		j = randint1(3) + 3;
		for (i = 0; i < j; i++)
			(void)fire_meteor(0, GF_FORCE, y, x, o_ptr->pval / 5, 7, TRUE);

		j = randint1(5) + o_ptr->pval /5;
		(void)summon_specific(y, x, TRUE, summon_level, SUMMON_BIRD, j);
	}

	/* Various colorful summonings. */
	if (trap & (CHEST_H_SUMMON))
	{
		/* Summon demons. */
		if (randint0(4) == 0)
		{
			msg_print("Demons materialize in clouds of fire and brimstone!");

			j = randint1(3) + 2;
			for (i = 0; i < j; i++)
			{
				(void)fire_meteor(0, GF_FIRE, y, x, 10, 5, TRUE);
				(void)summon_specific(y, x, FALSE, summon_level, SUMMON_DEMON, 1);
			}
		}

		/* Summon dragons. */
		else if (randint0(3) == 0)
		{
			msg_print("Draconic forms loom out of the darkness!");

			j = randint1(3) + 2;
			(void)summon_specific(y, x, FALSE, summon_level, SUMMON_DRAGON, j);
		}

		/* Summon hybrids. */
		else if (randint0(2) == 0)
		{
			msg_print("Creatures strange and twisted assault you!");

			j = randint1(5) + 3;
			(void)summon_specific(y, x, FALSE, summon_level, SUMMON_HYBRID, j);
		}

		/* Summon vortices (scattered) */
		else
		{
			msg_print("Vortices coalesce and wreak destruction!");

			j = randint1(3) + 2;
			(void)summon_specific(y, x, TRUE, summon_level, SUMMON_VORTEX, j);
		}
	}

	/* Dispel player. */
	if (trap & (CHEST_RUNES_OF_EVIL))
	{
		/* Message. */
		msg_print("Hideous voices bid: 'Let the darkness have thee!'");

		/* Determine how many nasty tricks can be played. */
		nasty_tricks_count = 4 + randint0(3);

		/* This is gonna hurt... */
		for (; nasty_tricks_count > 0; nasty_tricks_count--)
		{
			/* ...but a high saving throw does help a little. */
			if (!check_save(2 * o_ptr->pval))
			{
				if (randint0(6) == 0) take_hit(damroll(5, 20), "a chest dispel-player trap");
				else if (randint0(5) == 0) (void)set_cut(p_ptr->cut + 200);
				else if (randint0(4) == 0)
				{
					if (!p_ptr->free_act)
						(void)set_paralyzed(p_ptr->paralyzed + 2 +
						randint0(6));
					else
						(void)set_stun(p_ptr->stun + 10 +
						randint0(100));
				}
				else if (randint0(3) == 0) apply_disenchant(0);
				else if (randint0(2) == 0)
				{
					(void)do_dec_stat(A_STR);
					(void)do_dec_stat(A_DEX);
					(void)do_dec_stat(A_CON);
					(void)do_dec_stat(A_INT);
					(void)do_dec_stat(A_WIS);
					(void)do_dec_stat(A_CHR);
				}
				else (void)fire_meteor(0, GF_NETHER, y, x, 150, 1, TRUE);
			}
		}
	}
}
/**
 * Melee effect handler: Drain the player's experience.
 */
static void melee_effect_handler_EXP_80(melee_effect_handler_context_t *context)
{
	melee_effect_experience(context, 50, damroll(80, 6));
}
Exemplo n.º 6
0
/**
 * Attack the monster at the given location with a single blow.
 */
static bool py_attack_real(int y, int x, bool *fear) {
	size_t i;

	/* Information about the target of the attack */
	monster_type *m_ptr = cave_monster_at(cave, y, x);
	char m_name[80];
	bool stop = FALSE;

	/* The weapon used */
	object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD];

	/* Information about the attack */
	int bonus = p_ptr->state.to_h + o_ptr->to_h;
	int chance = p_ptr->state.skills[SKILL_TO_HIT_MELEE] + bonus * BTH_PLUS_ADJ;
	bool do_quake = FALSE;
	bool success = FALSE;

	/* Default to punching for one damage */
	const char *hit_verb = "punch";
	int dmg = 1;
	u32b msg_type = MSG_HIT;

	/* Extract monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0);

	/* Auto-Recall if possible and visible */
	if (m_ptr->ml) monster_race_track(m_ptr->race);

	/* Track a new monster */
	if (m_ptr->ml) health_track(p_ptr, m_ptr);

	/* Handle player fear (only for invisible monsters) */
	if (check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) {
		msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name);
		return FALSE;
	}

	/* Disturb the monster */
	mon_clear_timed(m_ptr, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, FALSE);

	/* See if the player hit */
	success = test_hit(chance, m_ptr->race->ac, m_ptr->ml);

	/* If a miss, skip this hit */
	if (!success) {
		msgt(MSG_MISS, "You miss %s.", m_name);
		return FALSE;
	}

	/* Handle normal weapon */
	if (o_ptr->kind) {
		const struct slay *best_s_ptr = NULL;

		hit_verb = "hit";

		/* Get the best attack from all slays or
		 * brands on all non-launcher equipment */
		for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) {
			struct object *obj = &p_ptr->inventory[i];
			if (obj->kind)
				improve_attack_modifier(obj, m_ptr, &best_s_ptr, TRUE, FALSE);
		}

		improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr, TRUE, FALSE);
		if (best_s_ptr != NULL)
			hit_verb = best_s_ptr->melee_verb;

		dmg = damroll(o_ptr->dd, o_ptr->ds);
		dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult;

		dmg += o_ptr->to_d;
		dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type);

		/* Learn by use for the weapon */
		object_notice_attack_plusses(o_ptr);

		if (check_state(p_ptr, OF_IMPACT, p_ptr->state.flags) && dmg > 50) {
			do_quake = TRUE;
			wieldeds_notice_flag(p_ptr, OF_IMPACT);
		}
	}

	/* Learn by use for other equipped items */
	wieldeds_notice_on_attack();

	/* Apply the player damage bonuses */
	dmg += p_ptr->state.to_d;

	/* No negative damage; change verb if no damage done */
	if (dmg <= 0) {
		dmg = 0;
		msg_type = MSG_MISS;
		hit_verb = "fail to harm";
	}

	for (i = 0; i < N_ELEMENTS(melee_hit_types); i++) {
		const char *dmg_text = "";

		if (msg_type != melee_hit_types[i].msg)
			continue;

		if (OPT(show_damage))
			dmg_text = format(" (%d)", dmg);

		if (melee_hit_types[i].text)
			msgt(msg_type, "You %s %s%s. %s", hit_verb, m_name, dmg_text,
					melee_hit_types[i].text);
		else
			msgt(msg_type, "You %s %s%s.", hit_verb, m_name, dmg_text);
	}

	/* Confusion attack */
	if (p_ptr->confusing) {
		p_ptr->confusing = FALSE;
		msg("Your hands stop glowing.");

		mon_inc_timed(m_ptr, MON_TMD_CONF,
				(10 + randint0(p_ptr->lev) / 10), MON_TMD_FLG_NOTIFY, FALSE);
	}

	/* Damage, check for fear and death */
	stop = mon_take_hit(m_ptr, dmg, fear, NULL);

	if (stop)
		(*fear) = FALSE;

	/* Apply earthquake brand */
	if (do_quake) {
		earthquake(p_ptr->py, p_ptr->px, 10);
		if (cave->m_idx[y][x] == 0) stop = TRUE;
	}

	return stop;
}
Exemplo n.º 7
0
/*
 * Do an effect, given an object.
 * Boost is the extent to which skill surpasses difficulty, used as % boost. It
 * ranges from 0 to 138.
 */
bool effect_do(effect_type effect, bool *ident, bool aware, int dir, int beam,
	int boost)
{
	int py = p_ptr->py;
	int px = p_ptr->px;
	int dam, chance, dur;

	if (effect < 1 || effect > EF_MAX)
	{
		msg("Bad effect passed to do_effect().  Please report this bug.");
		return FALSE;
	}

	switch (effect)
	{
		case EF_POISON:
		{
			player_inc_timed(p_ptr, TMD_POISONED, damroll(2, 7) + 10, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_BLIND:
		{
			player_inc_timed(p_ptr, TMD_BLIND, damroll(4, 25) + 75, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_SCARE:
		{
			player_inc_timed(p_ptr, TMD_AFRAID, randint0(10) + 10, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_CONFUSE:
		{
			player_inc_timed(p_ptr, TMD_CONFUSED, damroll(4, 5) + 10, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_HALLUC:
		{
			player_inc_timed(p_ptr, TMD_IMAGE, randint0(250) + 250, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_PARALYZE:
		{
			player_inc_timed(p_ptr, TMD_PARALYZED, randint0(5) + 5, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_SLOW:
		{
			if (player_inc_timed(p_ptr, TMD_SLOW, randint1(25) + 15, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_CURE_POISON:
		{
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_BLINDNESS:
		{
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_PARANOIA:
		{
			if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_CONFUSION:
		{
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_MIND:
		{
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_IMAGE, TRUE)) *ident = TRUE;
			if (!of_has(p_ptr->state.flags, OF_RES_CONFU) &&
				player_inc_timed(p_ptr, TMD_OPP_CONF, damroll(4, 10), TRUE, TRUE))
			    	*ident = TRUE;
			return TRUE;
		}

		case EF_CURE_BODY:
		{
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			return TRUE;
		}


		case EF_CURE_LIGHT:
		{
			if (hp_player(20)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_dec_timed(p_ptr, TMD_CUT, 20, TRUE)) *ident = TRUE;
			if (player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_SERIOUS:
		{
			if (hp_player(40)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_CRITICAL:
		{
			if (hp_player(60)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_FULL:
		{
			int amt = (p_ptr->mhp * 35) / 100;
			if (amt < 300) amt = 300;

			if (hp_player(amt)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_FULL2:
		{
			if (hp_player(1200)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AMNESIA, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_TEMP:
		{
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CONFUSED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL1:
		{
			if (hp_player(500)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL2:
		{
			if (hp_player(1000)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_HEAL3:
		{
			if (hp_player(500)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_GAIN_EXP:
		{
			if (p_ptr->exp < PY_MAX_EXP)
			{
				msg("You feel more experienced.");
				player_exp_gain(p_ptr, 100000L);
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_LOSE_EXP:
		{
			if (!check_state(p_ptr, OF_HOLD_LIFE, p_ptr->state.flags) && (p_ptr->exp > 0))
			{
				msg("You feel your memories fade.");
				player_exp_lose(p_ptr, p_ptr->exp / 4, FALSE);
				*ident = TRUE;
			}
			*ident = TRUE;
			wieldeds_notice_flag(p_ptr, OF_HOLD_LIFE);
			return TRUE;
		}

		case EF_RESTORE_EXP:
		{
			if (restore_level()) *ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_MANA:
		{
			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				msg("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_GAIN_STR:
		case EF_GAIN_INT:
		case EF_GAIN_WIS:
		case EF_GAIN_DEX:
		case EF_GAIN_CON:
		case EF_GAIN_CHR:
		{
			int stat = effect - EF_GAIN_STR;
			if (do_inc_stat(stat)) *ident = TRUE;
			return TRUE;
		}

		case EF_GAIN_ALL:
		{
			if (do_inc_stat(A_STR)) *ident = TRUE;
			if (do_inc_stat(A_INT)) *ident = TRUE;
			if (do_inc_stat(A_WIS)) *ident = TRUE;
			if (do_inc_stat(A_DEX)) *ident = TRUE;
			if (do_inc_stat(A_CON)) *ident = TRUE;
			if (do_inc_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_BRAWN:
		{
			/* Pick a random stat to decrease other than strength */
			int stat = randint0(A_MAX-1) + 1;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_STR);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_INTELLECT:
		{
			/* Pick a random stat to decrease other than intelligence */
			int stat = randint0(A_MAX-1);
			if (stat >= A_INT) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_INT);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_CONTEMPLATION:
		{
			/* Pick a random stat to decrease other than wisdom */
			int stat = randint0(A_MAX-1);
			if (stat >= A_WIS) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_WIS);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_TOUGHNESS:
		{
			/* Pick a random stat to decrease other than constitution */
			int stat = randint0(A_MAX-1);
			if (stat >= A_CON) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_CON);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_NIMBLENESS:
		{
			/* Pick a random stat to decrease other than dexterity */
			int stat = randint0(A_MAX-1);
			if (stat >= A_DEX) stat++;

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_DEX);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_PLEASING:
		{
			/* Pick a random stat to decrease other than charisma */
			int stat = randint0(A_MAX-1);

			if (do_dec_stat(stat, TRUE))
			{
				do_inc_stat(A_CHR);
				*ident = TRUE;
			}

			return TRUE;
		}

		case EF_LOSE_STR:
		case EF_LOSE_INT:
		case EF_LOSE_WIS:
		case EF_LOSE_DEX:
		case EF_LOSE_CON:
		case EF_LOSE_CHR:
		{
			int stat = effect - EF_LOSE_STR;

			take_hit(p_ptr, damroll(5, 5), "stat drain");
			(void)do_dec_stat(stat, FALSE);
			*ident = TRUE;

			return TRUE;
		}

		case EF_LOSE_CON2:
		{
			take_hit(p_ptr, damroll(10, 10), "poisonous food");
			(void)do_dec_stat(A_CON, FALSE);
			*ident = TRUE;

			return TRUE;
		}

		case EF_RESTORE_STR:
		case EF_RESTORE_INT:
		case EF_RESTORE_WIS:
		case EF_RESTORE_DEX:
		case EF_RESTORE_CON:
		case EF_RESTORE_CHR:
		{
			int stat = effect - EF_RESTORE_STR;
			if (do_res_stat(stat)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURE_NONORLYBIG:
		{
			msg("You feel life flow through your body!");
			restore_level();
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_IMAGE, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);

			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;

			/* Recalculate max. hitpoints */
			update_stuff(p_ptr);

			hp_player(5000);

			*ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_ALL:
		{
			/* Life, above, also gives these effects */
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_RESTORE_ST_LEV:
		{
			if (restore_level()) *ident = TRUE;
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (do_res_stat(A_WIS)) *ident = TRUE;
			if (do_res_stat(A_DEX)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (do_res_stat(A_CHR)) *ident = TRUE;
			return TRUE;
		}

		case EF_TMD_INFRA:
		{
			if (player_inc_timed(p_ptr, TMD_SINFRA, 100 + damroll(4, 25), TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_TMD_SINVIS:
		{
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_SINVIS, 12 + damroll(2, 6), TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_TMD_ESP:
		{
			if (player_clear_timed(p_ptr, TMD_BLIND, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_TELEPATHY, 12 + damroll(6, 6), TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}


		case EF_ENLIGHTENMENT:
		{
			msg("An image of your surroundings forms in your mind...");
			wiz_light();
			*ident = TRUE;
			return TRUE;
		}


		case EF_ENLIGHTENMENT2:
		{
			msg("You begin to feel more enlightened...");
			message_flush();
			wiz_light();
			(void)do_inc_stat(A_INT);
			(void)do_inc_stat(A_WIS);
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			(void)detect_treasure(TRUE);
			identify_pack();
			*ident = TRUE;
			return TRUE;
		}

		case EF_HERO:
		{
			dur = randint1(25) + 25;
			if (hp_player(10)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_HERO, dur, TRUE, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_SHERO:
		{
			dur = randint1(25) + 25;
			if (hp_player(30)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE;
			return TRUE;
		}


		case EF_RESIST_ACID:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(10) + 10, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_ELEC:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(10) + 10, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_FIRE:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_COLD:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_POIS:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(10) + 10, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RESIST_ALL:
		{
			if (player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE))
				*ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE))
				*ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE))
				*ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE))
				*ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_TREASURE:
		{
			if (detect_treasure(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_TRAP:
		{
			if (detect_traps(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_DOORSTAIR:
		{
			if (detect_doorstairs(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_INVIS:
		{
			if (detect_monsters_invis(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_EVIL:
		{
			if (detect_monsters_evil(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_DETECT_ALL:
		{
			if (detect_all(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_ENCHANT_TOHIT:
		{
			*ident = TRUE;
			return enchant_spell(1, 0, 0);
		}

		case EF_ENCHANT_TODAM:
		{
			*ident = TRUE;
			return enchant_spell(0, 1, 0);
		}

		case EF_ENCHANT_WEAPON:
		{
			*ident = TRUE;
			return enchant_spell(randint1(3), randint1(3), 0);
		}

		case EF_ENCHANT_ARMOR:
		{
			*ident = TRUE;
			return enchant_spell(0, 0, 1);
		}

		case EF_ENCHANT_ARMOR2:
		{
			*ident = TRUE;
			return enchant_spell(0, 0, randint1(3) + 2);
		}

		case EF_RESTORE_ITEM:
		{
			*ident = TRUE;
			return restore_item();
		}

		case EF_IDENTIFY:
		{
			*ident = TRUE;
			if (!ident_spell()) return FALSE;
			return TRUE;
		}

		case EF_REMOVE_CURSE:
		{
			if (remove_curse())
			{
				if (!p_ptr->timed[TMD_BLIND])
					msg("The air around your body glows blue for a moment...");
				else
					msg("You feel as if someone is watching over you.");

				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_REMOVE_CURSE2:
		{
			remove_all_curse();
			*ident = TRUE;
			return TRUE;
		}

		case EF_LIGHT:
		{
			if (light_area(damroll(2, 8), 2)) *ident = TRUE;
			return TRUE;
		}

		case EF_SUMMON_MON:
		{
			int i;
			sound(MSG_SUM_MONSTER);

			for (i = 0; i < randint1(3); i++)
			{
				if (summon_specific(py, px, p_ptr->depth, 0, 1))
					*ident = TRUE;
			}
			return TRUE;
		}

		case EF_SUMMON_UNDEAD:
		{
			int i;
			sound(MSG_SUM_UNDEAD);

			for (i = 0; i < randint1(3); i++)
			{
				if (summon_specific(py, px, p_ptr->depth,
					S_UNDEAD, 1))
					*ident = TRUE;
			}
			return TRUE;
		}

		case EF_TELE_PHASE:
		{
			teleport_player(10);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_LONG:
		{
			teleport_player(100);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_LEVEL:
		{
			(void)teleport_player_level();
			*ident = TRUE;
			return TRUE;
		}

		case EF_CONFUSING:
		{
			if (p_ptr->confusing == 0)
			{
				msg("Your hands begin to glow.");
				p_ptr->confusing = TRUE;
				*ident = TRUE;
			}
			return TRUE;
		}

		case EF_MAPPING:
		{
			map_area();
			*ident = TRUE;
			return TRUE;
		}

		case EF_RUNE:
		{
			warding_glyph();
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACQUIRE:
		{
			acquirement(py, px, p_ptr->depth, 1, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACQUIRE2:
		{
			acquirement(py, px, p_ptr->depth, randint1(2) + 1,
				TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ANNOY_MON:
		{
			msg("There is a high pitched humming noise.");
			aggravate_monsters(0);
			*ident = TRUE;
			return TRUE;
		}

		case EF_CREATE_TRAP:
		{
			/* Hack -- no traps in the town */
			if (p_ptr->depth == 0)
				return TRUE;

			trap_creation();
			msg("You hear a low-pitched whistling sound.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DESTROY_TDOORS:
		{
			if (destroy_doors_touch()) *ident = TRUE;
			return TRUE;
		}

		case EF_RECHARGE:
		{
			*ident = TRUE;
			if (!recharge(60)) return FALSE;
			return TRUE;
		}

		case EF_BANISHMENT:
		{
			*ident = TRUE;
			if (!banishment()) return FALSE;
			return TRUE;
		}

		case EF_DARKNESS:
		{
			if (!check_state(p_ptr, OF_RES_DARK, p_ptr->state.flags))
				(void)player_inc_timed(p_ptr, TMD_BLIND, 3 + randint1(5), TRUE, TRUE);
			unlight_area(10, 3);
			wieldeds_notice_flag(p_ptr, OF_RES_DARK);
			*ident = TRUE;
			return TRUE;
		}

		case EF_PROTEVIL:
		{
			if (player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 *
				p_ptr->lev, TRUE, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_SATISFY:
		{
			if (player_set_food(p_ptr, PY_FOOD_MAX - 1)) *ident = TRUE;
			return TRUE;
		}

		case EF_CURSE_WEAPON:
		{
			if (curse_weapon()) *ident = TRUE;
			return TRUE;
		}

		case EF_CURSE_ARMOR:
		{
			if (curse_armor()) *ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING:
		{
			if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(12) + 6, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING2:
		{
			if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(24) + 12, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_BLESSING3:
		{
			if (player_inc_timed(p_ptr, TMD_BLESSED, randint1(48) + 24, TRUE, TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_RECALL:
		{
			set_recall();
			*ident = TRUE;
			return TRUE;
		}

		case EF_DEEP_DESCENT:
		{
			int i, target_depth = p_ptr->depth;
			
			/* Calculate target depth */
			for (i = 2; i > 0; i--) {
				if (is_quest(target_depth)) break;
				if (target_depth >= MAX_DEPTH - 1) break;
				
				target_depth++;
			}

			if (target_depth > p_ptr->depth) {
				msgt(MSG_TPLEVEL, "You sink through the floor...");
				dungeon_change_level(target_depth);
				*ident = TRUE;
				return TRUE;
			} else {
				msgt(MSG_TPLEVEL, "You sense a malevolent presence blocking passage to the levels below.");
				*ident = TRUE;
				return FALSE;
			}
		}

		case EF_LOSHASTE:
		{
			if (speed_monsters()) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSSLEEP:
		{
			if (sleep_monsters(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSSLOW:
		{
			if (slow_monsters()) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSCONF:
		{
			if (confuse_monsters(aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LOSKILL:
		{
			(void)mass_banishment();
			*ident = TRUE;
			return TRUE;
		}

		case EF_EARTHQUAKES:
		{
			earthquake(py, px, 10);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DESTRUCTION2:
		{
			destroy_area(py, px, 15, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ILLUMINATION:
		{
			if (light_area(damroll(2, 15), 3)) *ident = TRUE;
			return TRUE;
		}

		case EF_CLAIRVOYANCE:
		{
			*ident = TRUE;
			wiz_light();
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			return TRUE;
		}

		case EF_PROBING:
		{
			*ident = probing();
			return TRUE;
		}

		case EF_STONE_TO_MUD:
		{
			if (wall_to_mud(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_CONFUSE2:
		{
			*ident = TRUE;
			confuse_monster(dir, 20, aware);
			return TRUE;
		}

		case EF_BIZARRE:
		{
			*ident = TRUE;
			ring_of_power(dir);
			return TRUE;
		}

		case EF_STAR_BALL:
		{
			int i;
			*ident = TRUE;
			for (i = 0; i < 8; i++) fire_ball(GF_ELEC, ddd[i],
				(150 * (100 + boost) / 100), 3);
			return TRUE;
		}

		case EF_RAGE_BLESS_RESIST:
		{
			dur = randint1(50) + 50;
			*ident = TRUE;
			(void)hp_player(30);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(50) + 50, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(50) + 50, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(50) + 50, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(50) + 50, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(50) + 50, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(50) + 50, TRUE, TRUE);
			return TRUE;
		}

		case EF_SLEEPII:
		{
			*ident = TRUE;
			sleep_monsters_touch(aware);
			return TRUE;
		}

		case EF_RESTORE_LIFE:
		{
			*ident = TRUE;
			restore_level();
			return TRUE;
		}

		case EF_MISSILE:
		{
			*ident = TRUE;
			dam = damroll(3, 4) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_MISSILE, dir, dam);
			return TRUE;
		}

		case EF_DISPEL_EVIL:
		{
			*ident = TRUE;
			dam = p_ptr->lev * 5 * (100 + boost) / 100;
			dispel_evil(dam);
			return TRUE;
		}

		case EF_DISPEL_EVIL60:
		{
			dam = 60 * (100 + boost) / 100;
			if (dispel_evil(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISPEL_UNDEAD:
		{
			dam = 60 * (100 + boost) / 100;
			if (dispel_undead(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISPEL_ALL:
		{
			dam = 120 * (100 + boost) / 100;
			if (dispel_monsters(dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_HASTE:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (player_set_timed(p_ptr, TMD_FAST, damroll(2, 10) + 20, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE);
			}

			return TRUE;
		}

		case EF_HASTE1:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (player_set_timed(p_ptr, TMD_FAST, randint1(20) + 20, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE);
			}

			return TRUE;
		}

		case EF_HASTE2:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				if (player_set_timed(p_ptr, TMD_FAST, randint1(75) + 75, TRUE)) *ident = TRUE;
			}
			else
			{
				(void)player_inc_timed(p_ptr, TMD_FAST, 5, TRUE, TRUE);
			}

			return TRUE;
		}


		case EF_FIRE_BOLT:
		{
			*ident = TRUE;
			dam = damroll(9, 8) * (100 + boost) / 100;
			fire_bolt(GF_FIRE, dir, dam);
			return TRUE;
		}

		case EF_FIRE_BOLT2:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_FIRE, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BOLT3:
		{
			dam = damroll(16, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_FIRE, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BOLT72:
		{
			dam = 72 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 2);
			return TRUE;
		}

		case EF_FIRE_BALL:
		{
			dam = 144 * (100 + boost) / 100;
			fire_ball(GF_FIRE, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FIRE_BALL2:
		{
			dam = 120 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 3);
			return TRUE;
		}

		case EF_FIRE_BALL200:
		{
			dam = 200 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 3);
			return TRUE;
		}

		case EF_COLD_BOLT:
		{
			dam = damroll(6, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt_or_beam(beam, GF_COLD, dir, dam);
			return TRUE;
		}

		case EF_COLD_BOLT2:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_COLD, dir, dam);
			return TRUE;
		}

		case EF_COLD_BALL2:
		{
			dam = 200 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 3);
			return TRUE;
		}

		case EF_COLD_BALL50:
		{
			dam = 50 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			return TRUE;
		}

		case EF_COLD_BALL100:
		{
			dam = 100 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			return TRUE;
		}

		case EF_COLD_BALL160:
		{
			dam = 160 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 3);
			return TRUE;
		}

		case EF_ACID_BOLT:
		{
			dam = damroll(5, 8) * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_ACID, dir, dam);
			return TRUE;
		}

		case EF_ACID_BOLT2:
		{
			dam = damroll(10, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_ACID, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACID_BOLT3:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt_or_beam(beam, GF_ACID, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ACID_BALL:
		{
			dam = 120 * (100 + boost) / 100;
			fire_ball(GF_ACID, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ELEC_BOLT:
		{
			dam = damroll(6, 6) * (100 + boost) / 100;
			*ident = TRUE;
			fire_beam(GF_ELEC, dir, dam);
			return TRUE;
		}

		case EF_ELEC_BALL:
		{
			dam = 64 * (100 + boost) / 100;
			fire_ball(GF_ELEC, dir, dam, 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_ELEC_BALL2:
		{
			dam = 250 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ELEC, dir, dam, 3);
			return TRUE;
		}


		case EF_ARROW:
		{
			dam = 150 * (100 + boost) / 100;
			*ident = TRUE;
			fire_bolt(GF_ARROW, dir, dam);
			return TRUE;
		}

		case EF_REM_FEAR_POIS:
		{
			*ident = TRUE;
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			return TRUE;
		}

		case EF_STINKING_CLOUD:
		{
			dam = 12 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_POIS, dir, dam, 3);
			return TRUE;
		}


		case EF_DRAIN_LIFE1:
		{
			dam = 90 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE2:
		{
			dam = 120 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE3:
		{
			dam = 150 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRAIN_LIFE4:
		{
			dam = 250 * (100 + boost) / 100;
			if (drain_life(dir, dam)) *ident = TRUE;
			return TRUE;
		}

		case EF_FIREBRAND:
		{
			*ident = TRUE;
			if (!brand_bolts()) return FALSE;
			return TRUE;
		}

		case EF_MANA_BOLT:
		{
			dam = damroll(12, 8) * (100 + boost) / 100;
			fire_bolt(GF_MANA, dir, dam);
			*ident = TRUE;
			return TRUE;
		}

		case EF_MON_HEAL:
		{
			if (heal_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_HASTE:
		{
			if (speed_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SLOW:
		{
			if (slow_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_CONFUSE:
		{
			if (confuse_monster(dir, 10, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SLEEP:
		{
			if (sleep_monster(dir, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_CLONE:
		{
			if (clone_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_MON_SCARE:
		{
			if (fear_monster(dir, 10, aware)) *ident = TRUE;
			return TRUE;
		}

		case EF_LIGHT_LINE:
		{
			msg("A line of shimmering blue light appears.");
			light_line(dir);
			*ident = TRUE;
			return TRUE;
		}

		case EF_TELE_OTHER:
		{
			if (teleport_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_DISARMING:
		{
			if (disarm_trap(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_TDOOR_DEST:
		{
			if (destroy_door(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_POLYMORPH:
		{
			if (poly_monster(dir)) *ident = TRUE;
			return TRUE;
		}

		case EF_STARLIGHT:
		{
			int i;
			if (!p_ptr->timed[TMD_BLIND])
				msg("Light shoots in all directions!");
			for (i = 0; i < 8; i++) light_line(ddd[i]);
			*ident = TRUE;
			return TRUE;
		}

		case EF_STARLIGHT2:
		{
			int k;
			for (k = 0; k < 8; k++) strong_light_line(ddd[k]);
			*ident = TRUE;
			return TRUE;
		}

		case EF_BERSERKER:
		{
			dur = randint1(50) + 50;
			if (player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_WONDER:
		{
			if (effect_wonder(dir, randint1(100) + p_ptr->lev / 5,
				beam)) *ident = TRUE;
			return TRUE;
		}

		case EF_WAND_BREATH:
		{
			/* table of random ball effects and their damages */
			const int breath_types[] = {
				GF_ACID, 200,
				GF_ELEC, 160,
				GF_FIRE, 200,
				GF_COLD, 160,
				GF_POIS, 120
			};
			/* pick a random (type, damage) tuple in the table */
			int which = 2 * randint0(sizeof(breath_types) / (2 * sizeof(int)));
			fire_ball(breath_types[which], dir, breath_types[which + 1], 3);
			*ident = TRUE;
			return TRUE;
		}

		case EF_STAFF_MAGI:
		{
			if (do_res_stat(A_INT)) *ident = TRUE;
			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				*ident = TRUE;
				msg("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
			}
			return TRUE;
		}

		case EF_STAFF_HOLY:
		{
			dam = 120 * (100 + boost) / 100;
			if (dispel_evil(dam)) *ident = TRUE;
			if (player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 *
				p_ptr->lev, TRUE, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_AFRAID, TRUE)) *ident = TRUE;
			if (hp_player(50)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_STUN, TRUE)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_CUT, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_BREATH:
		{
			const int breath_types[] =
			{
				GF_FIRE, 80,
				GF_COLD, 80,
			};

			int which = 2 * randint0(N_ELEMENTS(breath_types) / 2);
			fire_ball(breath_types[which], dir, breath_types[which + 1], 2);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_GOOD:
		{
			msg("You feel less thirsty.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_DEATH:
		{
			msg("A feeling of Death flows through your body.");
			take_hit(p_ptr, 5000, "a potion of Death");
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_RUIN:
		{
			msg("Your nerves and muscles feel weak and lifeless!");
			take_hit(p_ptr, damroll(10, 10), "a potion of Ruination");
			player_stat_dec(p_ptr, A_DEX, TRUE);
			player_stat_dec(p_ptr, A_WIS, TRUE);
			player_stat_dec(p_ptr, A_CON, TRUE);
			player_stat_dec(p_ptr, A_STR, TRUE);
			player_stat_dec(p_ptr, A_CHR, TRUE);
			player_stat_dec(p_ptr, A_INT, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_DETONATE:
		{
			msg("Massive explosions rupture your body!");
			take_hit(p_ptr, damroll(50, 20), "a potion of Detonation");
			(void)player_inc_timed(p_ptr, TMD_STUN, 75, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_CUT, 5000, TRUE, TRUE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_DRINK_SALT:
		{
			msg("The potion makes you vomit!");
			player_set_food(p_ptr, PY_FOOD_STARVE - 1);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_inc_timed(p_ptr, TMD_PARALYZED, 4, TRUE, FALSE);
			*ident = TRUE;
			return TRUE;
		}

		case EF_FOOD_GOOD:
		{
			msg("That tastes good.");
			*ident = TRUE;
			return TRUE;
		}

		case EF_FOOD_WAYBREAD:
		{
			msg("That tastes good.");
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)hp_player(damroll(4, 8));
			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_EMERGENCY:
		{
			(void)player_set_timed(p_ptr, TMD_IMAGE, rand_spread(250, 50), TRUE);
			(void)player_set_timed(p_ptr, TMD_OPP_FIRE, rand_spread(30, 10), TRUE);
			(void)player_set_timed(p_ptr, TMD_OPP_COLD, rand_spread(30, 10), TRUE);
			(void)hp_player(200);
			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_TERROR:
		{
			if (player_set_timed(p_ptr, TMD_TERROR, rand_spread(100, 20), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_STONE:
		{
			if (player_set_timed(p_ptr, TMD_STONESKIN, rand_spread(80, 20), TRUE))
				*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_DEBILITY:
		{
			int stat = one_in_(2) ? A_STR : A_CON;

			if (p_ptr->csp < p_ptr->msp)
			{
				p_ptr->csp = p_ptr->msp;
				p_ptr->csp_frac = 0;
				msg("Your feel your head clear.");
				p_ptr->redraw |= (PR_MANA);
				*ident = TRUE;
			}

			(void)do_dec_stat(stat, FALSE);

			*ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_SPRINTING:
		{
			if (player_inc_timed(p_ptr, TMD_SPRINT, 100, TRUE, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_SHROOM_PURGING:
		{
			player_set_food(p_ptr, PY_FOOD_FAINT - 1);
			if (do_res_stat(A_STR)) *ident = TRUE;
			if (do_res_stat(A_CON)) *ident = TRUE;
			if (player_clear_timed(p_ptr, TMD_POISONED, TRUE)) *ident = TRUE;
			return TRUE;
		}

		case EF_RING_ACID:
		{
			dam = 70 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ACID, dir, dam, 2);
			player_inc_timed(p_ptr, TMD_OPP_ACID, randint1(20) + 20, TRUE, TRUE);
			return TRUE;
		}

		case EF_RING_FLAMES:
		{
			dam = 80 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_FIRE, dir, dam, 2);
			player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE);
			return TRUE;
		}

		case EF_RING_ICE:
		{
			dam = 75 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_COLD, dir, dam, 2);
			player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE);
			return TRUE;
		}

		case EF_RING_LIGHTNING:
		{
			dam = 85 * (100 + boost) / 100;
			*ident = TRUE;
			fire_ball(GF_ELEC, dir, dam, 2);
			player_inc_timed(p_ptr, TMD_OPP_ELEC, randint1(20) + 20, TRUE, TRUE);
			return TRUE;
		}

		case EF_DRAGON_BLUE:
		{
			dam = 100 * (100 + boost) / 100;
			msgt(MSG_BR_ELEC, "You breathe lightning.");
			fire_ball(GF_ELEC, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_GREEN:
		{
			dam = 150 * (100 + boost) / 100;
			msgt(MSG_BR_GAS, "You breathe poison gas.");
			fire_ball(GF_POIS, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_RED:
		{
			dam = 200 * (100 + boost) / 100;
			msgt(MSG_BR_FIRE, "You breathe fire.");
			fire_ball(GF_FIRE, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_MULTIHUED:
		{
			static const struct
			{
				int msg_sound;
				const char *msg;
				int typ;
			} mh[] =
			{
				{ MSG_BR_ELEC,  "lightning",  GF_ELEC },
				{ MSG_BR_FROST, "frost",      GF_COLD },
				{ MSG_BR_ACID,  "acid",       GF_ACID },
				{ MSG_BR_GAS,   "poison gas", GF_POIS },
				{ MSG_BR_FIRE,  "fire",       GF_FIRE }
			};

			int chance = randint0(5);
			dam = 250 * (100 + boost) / 100;
			msgt(mh[chance].msg_sound, "You breathe %s.", mh[chance].msg);
			fire_ball(mh[chance].typ, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_BRONZE:
		{
			dam = 120 * (100 + boost) / 100;
			msgt(MSG_BR_CONF, "You breathe confusion.");
			fire_ball(GF_CONFU, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_GOLD:
		{
			dam = 130 * (100 + boost) / 100;
			msgt(MSG_BR_SOUND, "You breathe sound.");
			fire_ball(GF_SOUND, dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_CHAOS:
		{
			dam = 220 * (100 + boost) / 100;
			chance = randint0(2);
			msgt((chance == 1 ? MSG_BR_CHAOS : MSG_BR_DISEN),
					"You breathe %s.",
					((chance == 1 ? "chaos" : "disenchantment")));
			fire_ball((chance == 1 ? GF_CHAOS : GF_DISEN),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_LAW:
		{
			dam = 230 * (100 + boost) / 100;
			chance = randint0(2);
			msgt((chance == 1 ? MSG_BR_SOUND : MSG_BR_SHARDS), "You breathe %s.",
			           ((chance == 1 ? "sound" : "shards")));
			fire_ball((chance == 1 ? GF_SOUND : GF_SHARD),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_BALANCE:
		{
			dam = 250 * (100 + boost) / 100;
			chance = randint0(4);
			msg("You breathe %s.",
			           ((chance == 1) ? "chaos" :
			            ((chance == 2) ? "disenchantment" :
			             ((chance == 3) ? "sound" : "shards"))));
			fire_ball(((chance == 1) ? GF_CHAOS :
			           ((chance == 2) ? GF_DISEN :
			            ((chance == 3) ? GF_SOUND : GF_SHARD))),
			          dir, dam, 2);
			return TRUE;
		}

		case EF_DRAGON_SHINING:
		{
			dam = 200 * (100 + boost) / 100;
			chance = randint0(2);
			msgt((chance == 0 ? MSG_BR_LIGHT : MSG_BR_DARK), "You breathe %s.",
			        ((chance == 0 ? "light" : "darkness")));
			fire_ball((chance == 0 ? GF_LIGHT : GF_DARK), dir, dam,
				2);
			return TRUE;
		}

		case EF_DRAGON_POWER:
		{
			dam = 300 * (100 + boost) / 100;
			msgt(MSG_BR_ELEMENTS, "You breathe the elements.");
			fire_ball(GF_MISSILE, dir, dam, 2);
			return TRUE;
		}

		case EF_TRAP_DOOR:
		{
			msg("You fall through a trap door!");
			if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) {
				msg("You float gently down to the next level.");
			} else {
				take_hit(p_ptr, damroll(2, 8), "a trap");
			}
			wieldeds_notice_flag(p_ptr, OF_FEATHER);

			dungeon_change_level(p_ptr->depth + 1);
			return TRUE;
		}

		case EF_TRAP_PIT:
		{
			msg("You fall into a pit!");
			if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) {
				msg("You float gently to the bottom of the pit.");
			} else {
				take_hit(p_ptr, damroll(2, 6), "a trap");
			}
			wieldeds_notice_flag(p_ptr, OF_FEATHER);
			return TRUE;
		}

		case EF_TRAP_PIT_SPIKES:
		{
			msg("You fall into a spiked pit!");

			if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) {
				msg("You float gently to the floor of the pit.");
				msg("You carefully avoid touching the spikes.");
			} else {
				int dam = damroll(2, 6);

				/* Extra spike damage */
				if (one_in_(2)) {
					msg("You are impaled!");
					dam *= 2;
					(void)player_inc_timed(p_ptr, TMD_CUT, randint1(dam), TRUE, TRUE);
				}

				take_hit(p_ptr, dam, "a trap");
			}
			wieldeds_notice_flag(p_ptr, OF_FEATHER);
			return TRUE;
		}

		case EF_TRAP_PIT_POISON:
		{
			msg("You fall into a spiked pit!");

			if (check_state(p_ptr, OF_FEATHER, p_ptr->state.flags)) {
				msg("You float gently to the floor of the pit.");
				msg("You carefully avoid touching the spikes.");
			} else {
				int dam = damroll(2, 6);

				/* Extra spike damage */
				if (one_in_(2)) {
					msg("You are impaled on poisonous spikes!");
					(void)player_inc_timed(p_ptr, TMD_CUT, randint1(dam * 2), TRUE, TRUE);
					(void)player_inc_timed(p_ptr, TMD_POISONED, randint1(dam * 4), TRUE, TRUE);
				}

				take_hit(p_ptr, dam, "a trap");
			}
			wieldeds_notice_flag(p_ptr, OF_FEATHER);
			return TRUE;
		}

		case EF_TRAP_RUNE_SUMMON:
		{
			int i;
			int num = 2 + randint1(3);

			msgt(MSG_SUM_MONSTER, "You are enveloped in a cloud of smoke!");

			/* Remove trap */
			cave->info[py][px] &= ~(CAVE_MARK);
			cave_set_feat(cave, py, px, FEAT_FLOOR);

			for (i = 0; i < num; i++)
				(void)summon_specific(py, px, p_ptr->depth, 0, 1);

			return TRUE;
		}

		case EF_TRAP_RUNE_TELEPORT:
		{
			msg("You hit a teleport trap!");
			teleport_player(100);
			return TRUE;
		}

		case EF_TRAP_SPOT_FIRE:
		{
			int dam;

			msg("You are enveloped in flames!");
			dam = damroll(4, 6);
			dam = adjust_dam(p_ptr, GF_FIRE, dam, RANDOMISE,
					check_for_resist(p_ptr, GF_FIRE, p_ptr->state.flags, TRUE));
			if (dam) {
				take_hit(p_ptr, dam, "a fire trap");
				inven_damage(p_ptr, GF_FIRE, MIN(dam * 5, 300));
			}
			return TRUE;
		}

		case EF_TRAP_SPOT_ACID:
		{
			int dam;

			msg("You are splashed with acid!");
			dam = damroll(4, 6);
			dam = adjust_dam(p_ptr, GF_ACID, dam, RANDOMISE,
					check_for_resist(p_ptr, GF_ACID, p_ptr->state.flags, TRUE));
			if (dam) {
				take_hit(p_ptr, dam, "an acid trap");
				inven_damage(p_ptr, GF_ACID, MIN(dam * 5, 300));
			}
			return TRUE;
		}

		case EF_TRAP_DART_SLOW:
		{
			if (trap_check_hit(125)) {
				msg("A small dart hits you!");
				take_hit(p_ptr, damroll(1, 4), "a trap");
				(void)player_inc_timed(p_ptr, TMD_SLOW, randint0(20) + 20, TRUE, FALSE);
			} else {
				msg("A small dart barely misses you.");
			}
			return TRUE;
		}

		case EF_TRAP_DART_LOSE_STR:
		{
			if (trap_check_hit(125)) {
				msg("A small dart hits you!");
				take_hit(p_ptr, damroll(1, 4), "a trap");
				(void)do_dec_stat(A_STR, FALSE);
			} else {
				msg("A small dart barely misses you.");
			}
			return TRUE;
		}

		case EF_TRAP_DART_LOSE_DEX:
		{
			if (trap_check_hit(125)) {
				msg("A small dart hits you!");
				take_hit(p_ptr, damroll(1, 4), "a trap");
				(void)do_dec_stat(A_DEX, FALSE);
			} else {
				msg("A small dart barely misses you.");
			}
			return TRUE;
		}

		case EF_TRAP_DART_LOSE_CON:
		{
			if (trap_check_hit(125)) {
				msg("A small dart hits you!");
				take_hit(p_ptr, damroll(1, 4), "a trap");
				(void)do_dec_stat(A_CON, FALSE);
			} else {
				msg("A small dart barely misses you.");
			}
			return TRUE;
		}

		case EF_TRAP_GAS_BLIND:
		{
			msg("You are surrounded by a black gas!");
			(void)player_inc_timed(p_ptr, TMD_BLIND, randint0(50) + 25, TRUE, TRUE);
			return TRUE;
		}

		case EF_TRAP_GAS_CONFUSE:
		{
			msg("You are surrounded by a gas of scintillating colors!");
			(void)player_inc_timed(p_ptr, TMD_CONFUSED, randint0(20) + 10, TRUE, TRUE);
			return TRUE;
		}

		case EF_TRAP_GAS_POISON:
		{
			msg("You are surrounded by a pungent green gas!");
			(void)player_inc_timed(p_ptr, TMD_POISONED, randint0(20) + 10, TRUE, TRUE);
			return TRUE;
		}

		case EF_TRAP_GAS_SLEEP:
		{
			msg("You are surrounded by a strange white mist!");
			(void)player_inc_timed(p_ptr, TMD_PARALYZED, randint0(10) + 5, TRUE, TRUE);
			return TRUE;
		}


		case EF_XXX:
		case EF_MAX:
			break;
	}

	/* Not used */
	msg("Effect not handled.");
	return FALSE;
}
Exemplo n.º 8
0
/* Potions for the quaffing				-RAK-	*/
void quaff()
{
  int32u i, l;
  int j, k, item_val;
  int ident;
  register inven_type *i_ptr;
  register struct misc *m_ptr;
  register struct flags *f_ptr;

  free_turn_flag = TRUE;
  if (inven_ctr == 0)
    msg_print("But you are not carrying anything.");
  else if (!find_range(TV_POTION1, TV_POTION2, &j, &k))
    msg_print("You are not carrying any potions.");
  else if (get_item(&item_val, "Quaff which potion?", j, k, 0))
    {
      i_ptr = &inventory[item_val];
      i = i_ptr->flags;
      free_turn_flag = FALSE;
      ident = FALSE;
      if (i == 0)
	{
	  msg_print ("You feel less thirsty.");
	  ident = TRUE;
	}
      else while (i != 0)
	{
	  j = bit_pos(&i) + 1;
	  if (i_ptr->tval == TV_POTION2)
	    j += 32;
	  /* Potions						*/
	  switch(j)
	    {
	    case 1:
	      if (inc_stat (A_STR))
		{
		  msg_print("Wow!  What bulging muscles!");
		  ident = TRUE;
		}
	      break;
	    case 2:
	      ident = TRUE;
	      lose_str();
	      break;
	    case 3:
	      if (res_stat (A_STR))
		{
		  msg_print("You feel warm all over.");
		  ident = TRUE;
		}
	      break;
	    case 4:
	      if (inc_stat (A_INT))
		{
		  msg_print("Aren't you brilliant!");
		  ident = TRUE;
		}
	      break;
	    case 5:
	      ident = TRUE;
	      lose_int();
	      break;
	    case 6:
	      if (res_stat (A_INT))
		{
		  msg_print("You have a warm feeling.");
		  ident = TRUE;
		}
	      break;
	    case 7:
	      if (inc_stat (A_WIS))
		{
		  msg_print("You suddenly have a profound thought!");
		  ident = TRUE;
		}
	      break;
	    case 8:
	      ident = TRUE;
	      lose_wis();
	      break;
	    case 9:
	      if (res_stat (A_WIS))
		{
		  msg_print("You feel your wisdom returning.");
		  ident = TRUE;
		}
	      break;
	    case 10:
	      if (inc_stat (A_CHR))
		{
		  msg_print("Gee, ain't you cute!");
		  ident = TRUE;
		}
	      break;
	    case 11:
	      ident = TRUE;
	      lose_chr();
	      break;
	    case 12:
	      if (res_stat (A_CHR))
		{
		  msg_print("You feel your looks returning.");
		  ident = TRUE;
		}
	      break;
	    case 13:
	      ident = hp_player(damroll(2, 7));
	      if (py.flags.cut>0) {
		py.flags.cut-=10;
		if (py.flags.cut<0) py.flags.cut=0;
		ident = TRUE;
		msg_print("Your wounds heal.");
	      }
	      break;
	    case 14:
	      ident = hp_player(damroll(4, 7));
	      if (py.flags.cut>0) {
		py.flags.cut=(py.flags.cut/2)-50;
		if (py.flags.cut<0) py.flags.cut=0;
		ident = TRUE;
		msg_print("Your wounds heal.");
	      }
	      break;
	    case 15:
	      ident = hp_player(damroll(6, 7));
	      if (py.flags.cut>0) {
		py.flags.cut=0;
		ident = TRUE;
		msg_print("Your wounds heal.");
	      }
 	      if (py.flags.stun>0) {
		if (py.flags.stun>50) {
		  py.misc.ptohit+=20;
		  py.misc.ptodam+=20;
		} else {
		  py.misc.ptohit+=5;
		  py.misc.ptodam+=5;
		}
		py.flags.stun=0;
		ident = TRUE;
		msg_print("Your head stops stinging.");
	      }
	      break;
	    case 16:
	      ident = hp_player(400);
	      if (py.flags.stun>0) {
		if (py.flags.stun>50) {
		  py.misc.ptohit+=20;
		  py.misc.ptodam+=20;
		} else {
		  py.misc.ptohit+=5;
		  py.misc.ptodam+=5;
		}
		py.flags.stun=0;
		ident = TRUE;
		msg_print("Your head stops stinging.");
	      }
	      if (py.flags.cut>0) {
		py.flags.cut=0;
		ident = TRUE;
		msg_print("Your wounds heal.");
	      }
	      break;
	    case 17:
	      if (inc_stat (A_CON))
		{
		  msg_print("You feel tingly for a moment.");
		  ident = TRUE;
		}
	      break;
	    case 18:
	      m_ptr = &py.misc;
	      if (m_ptr->exp < MAX_EXP)
		{
		  l = (m_ptr->exp / 2) + 10;
		  if (l > 100000L)  l = 100000L;
		  m_ptr->exp += l;
		  msg_print("You feel more experienced.");
		  prt_experience();
		  ident = TRUE;
		}
	      break;
	    case 19:
	      f_ptr = &py.flags;
	      if (!f_ptr->free_act)
		{
		  /* paralysis must == 0, otherwise could not drink potion */
		  msg_print("You fall asleep.");
		  f_ptr->paralysis += randint(4) + 4;
		  ident = TRUE;
		}
	      break;
	    case 20:
	      f_ptr = &py.flags;
	      if (!py.flags.blindness_resist) {
	        if (f_ptr->blind == 0)
		  {
		    msg_print("You are covered by a veil of darkness.");
		    ident = TRUE;
		  }
	        f_ptr->blind += randint(100) + 100;
	      }
	      break;
	    case 21:
	      f_ptr = &py.flags;
	      if (!f_ptr->confusion_resist)
		{
	          if (f_ptr->confused == 0)
		    {
		      msg_print("Hey!  This is good stuff!  * Hick! *");
		      ident = TRUE;
		    }
	          f_ptr->confused += randint(20) + 12;
                }
              break;
	    case 22:
	      f_ptr = &py.flags;
	      if (f_ptr->poisoned == 0)
		{
		  msg_print("You feel very sick.");
		  ident = TRUE;
		}
	      if (!f_ptr->poison_resist)
		f_ptr->poisoned += randint(15) + 10;
	      break;
	    case 23:
	      if (py.flags.fast == 0)
		ident = TRUE;
	      if (py.flags.fast <= 0)
		  {
		    py.flags.fast += randint(25) + 15;
		  }
	      else
		py.flags.fast += randint(5);
	      break;
	    case 24:
	      if (py.flags.slow == 0)
		ident = TRUE;
	      py.flags.slow += randint(25) + 15;
	      break;
	    case 26:
	      if (inc_stat (A_DEX))
		{
		  msg_print("You feel more limber!");
		  ident = TRUE;
		}
	      break;
	    case 27:
	      if (res_stat (A_DEX))
		{
		  msg_print("You feel less clumsy.");
		  ident = TRUE;
		}
	      break;
	    case 28:
	      if (res_stat (A_CON))
		{
		  msg_print("You feel your health returning!");
		  ident = TRUE;
		}
	      break;
	    case 29:
	      ident = cure_blindness();
	      break;
	    case 30:
	      ident = cure_confusion();
	      break;
	    case 31:
	      ident = cure_poison();
	      break;
	    case 34:
	      if (!py.flags.hold_life && py.misc.exp>0) {
		  int32 m, scale;
		  msg_print("You feel your memories fade.");
		  m = py.misc.exp / 5;
		  if (py.misc.exp > MAX_SHORT) {
		    scale = MAX_LONG / py.misc.exp;
		    m+=(randint((int)scale)*py.misc.exp)/(scale*5);
		  }
		  else m+=randint((int)py.misc.exp)/5;
		  lose_exp(m);
		  ident=TRUE;
	      }
	      else msg_print
	     ("You feel you memories fade for a moment, but quickly return.");
	      break;
	    case 35:
	      f_ptr = &py.flags;
	      (void) cure_poison();
	      if (f_ptr->food > 150)  f_ptr->food = 150;
	      f_ptr->paralysis = 4;
	      msg_print("The potion makes you vomit!");
	      ident = TRUE;
	      break;
	    case 37:
	      if (py.flags.hero == 0)
		ident = TRUE;
	      py.flags.hero += randint(25) + 25;
	      break;
	    case 38:
	      if (py.flags.shero == 0)
		ident = TRUE;
	      py.flags.shero += randint(25) + 25;
	      break;
	    case 39:
	      ident = remove_fear();
	      break;
	    case 40:
	      ident = restore_level();
	      break;
	    case 41:
	      f_ptr = &py.flags;
	      if (f_ptr->resist_heat == 0)
		ident = TRUE;
	      f_ptr->resist_heat += randint(10) + 10;
	      break;
	    case 42:
	      f_ptr = &py.flags;
	      if (f_ptr->resist_cold == 0)
		ident = TRUE;
	      f_ptr->resist_cold += randint(10) + 10;
	      break;
	    case 43:
	      if (py.flags.detect_inv == 0)
		ident = TRUE;
	      detect_inv2(randint(12)+12);
	      break;
	    case 44:
	      ident = slow_poison();
	      break;
	    case 45:
	      ident = cure_poison();
	      break;
	    case 46:
	      m_ptr = &py.misc;
	      if (m_ptr->cmana < m_ptr->mana)
		{
		  m_ptr->cmana = m_ptr->mana;
		  ident = TRUE;
		  msg_print("Your feel your head clear.");
		  prt_cmana();
		}
	      break;
	    case 47:
	      f_ptr = &py.flags;
	      if (f_ptr->tim_infra == 0)
		{
		  msg_print("Your eyes begin to tingle.");
		  ident = TRUE;
		}
	      f_ptr->tim_infra += 100 + randint(100);
	      break;
	    case 48:
	      wizard_light(TRUE);
	      if (!res_stat(A_WIS)) inc_stat(A_WIS);
	      if (!res_stat(A_INT)) inc_stat(A_INT);
	      msg_print("You feel more enlightened!");
	      identify_pack();
	      ident=TRUE;
	      break;
	    case 49:
	      msg_print("Massive explosions rupture your body!");
	      take_hit(damroll(50,20),"a potion of Detonation");
	      cut_player(5000);
	      stun_player(75);
	      ident=TRUE;
	      break;
	    case 50:
	      msg_print("A feeling of Death flows through your body.");
	      take_hit(5000,"a potion of Death");
	      ident=TRUE;
	      break;
	    case 51:
	      if (restore_level() | res_stat(A_STR) | res_stat(A_CON) |
		  res_stat(A_DEX) | res_stat(A_WIS) | res_stat(A_INT) |
		  res_stat(A_CHR) | hp_player(5000) | cure_poison() |
		  cure_blindness() | cure_confusion() | (py.flags.stun>0) |
		  (py.flags.cut>0) | (py.flags.image>0) | remove_fear()) {
	       ident=TRUE;
	       py.flags.cut=0;
	       py.flags.image=0;
	       if (py.flags.stun>0) {
	         if (py.flags.stun>50) {
		   py.misc.ptohit+=20;
		   py.misc.ptodam+=20;
		 } else {
		   py.misc.ptohit+=5;
		   py.misc.ptodam+=5;
	         }
		 py.flags.stun=0;
               }
  	      }
	      break;
            case 52:
	      if (inc_stat(A_DEX) | inc_stat(A_WIS) | inc_stat(A_INT) |
		  inc_stat(A_STR) | inc_stat(A_CHR) | inc_stat(A_CON)) {
		ident=TRUE;
		msg_print("You feel power flow through your body!");
	      }
	      break;
	    case 53:
	      take_hit(damroll(10,10),"a potion of Ruination");
	      ruin_stat(A_DEX);
	      ruin_stat(A_WIS);
	      ruin_stat(A_CON);
	      ruin_stat(A_STR);
	      ruin_stat(A_CHR);
	      ruin_stat(A_INT);
	      ident=TRUE;
	      msg_print("Your nerves and muscles feel weak and lifeless");
	      break;
	    case 54:
	      wizard_light(TRUE);
	      msg_print("An image of your surroundings forms in your mind");
	      ident = TRUE;
	      break;
	    case 55:
	      msg_print("You feel you know yourself a little better...");
	      self_knowledge();
	      ident = TRUE;
	      break; 
	    case 56: /*  *Healing*  */
              ident = hp_player(1200);
              if (py.flags.stun>0) {
                if (py.flags.stun>50) {
                  py.misc.ptohit+=20;
                  py.misc.ptodam+=20;
	        } else {
                  py.misc.ptohit+=5;
                  py.misc.ptodam+=5;
	        }
                py.flags.stun=0;
                ident = TRUE;
                msg_print("Your head stops stinging.");
	      }
              if (py.flags.cut>0) {
                py.flags.cut=0;
                ident = TRUE;
                msg_print("Your wounds heal.");
	      }
              if (cure_blindness()) ident = TRUE;
              if (cure_confusion()) ident = TRUE;
              if (cure_poison()) ident = TRUE;
              break;
	    default:
	      if (1) {
		char tmp_str[100];
		msg_print ("Internal error in potion()");
		sprintf(tmp_str, "Number %d...", j);
		msg_print (tmp_str);
	      }
	      break;
	    }
	  /* End of Potions.					*/
	}
      if (ident)
	{
	  if (!known1_p(i_ptr))
	    {
	      m_ptr = &py.misc;
	      /* round half-way case up */
	      m_ptr->exp += (i_ptr->level + (m_ptr->lev >> 1)) / m_ptr->lev;
	      prt_experience();

	      identify(&item_val);
	      i_ptr = &inventory[item_val];
	    }
	}
Exemplo n.º 9
0
/**
 * Save a "bones" file for a dead character.  Now activated and (slightly) 
 * altered.  Allows the inclusion of personalized strings. 
 */
static void make_bones(void)
{
    ang_file *fp;

    char str[1024];
    ui_event_data answer;
    byte choice = 0;

    int i;

    /* Ignore wizards and borgs */
    if (!(p_ptr->noscore & 0x00FF)) {
	/* Ignore people who die in town */
	if (p_ptr->depth) {
	    int level;
	    char tmp[128];

	    /* Slightly more tenacious saving routine. */
	    for (i = 0; i < 5; i++) {
		/* Ghost hovers near level of death. */
		if (i == 0)
		    level = p_ptr->depth;
		else
		    level = p_ptr->depth + 5 - damroll(2, 4);
		if (level < 1)
		    level = randint1(4);

		/* XXX XXX XXX "Bones" name */
		sprintf(tmp, "bone.%03d", level);

		/* Build the filename */
		path_build(str, 1024, ANGBAND_DIR_BONE, tmp);

		/* Attempt to open the bones file */
		fp = file_open(str, MODE_READ, FTYPE_TEXT);

		/* Close it right away */
		if (fp)
		    file_close(fp);

		/* Do not over-write a previous ghost */
		if (fp)
		    continue;

		/* If no file by that name exists, we can make a new one. */
		if (!(fp))
		    break;
	    }

	    /* Failure */
	    if (fp)
		return;

	    /* Try to write a new "Bones File" */
	    fp = file_open(str, MODE_WRITE, FTYPE_TEXT);

	    /* Not allowed to write it? Weird. */
	    if (!fp)
		return;

	    /* Save the info */
	    if (op_ptr->full_name[0] != '\0')
		file_putf(fp, "%s\n", op_ptr->full_name);
	    else
		file_putf(fp, "Anonymous\n");



	    file_putf(fp, "%d\n", p_ptr->psex);
	    file_putf(fp, "%d\n", p_ptr->prace);
	    file_putf(fp, "%d\n", p_ptr->pclass);

	    /* Clear screen */
	    Term_clear();

	    while (1) {
		/* Ask the player if he wants to add a personalized string. */
		prt("Information about your character has been saved", 15, 0);
		prt("in a bones file.  Would you like to give the", 16, 0);
		prt("ghost a special message or description? (yes/no)", 17, 0);
		button_add("Yes", 'y');
		button_add("No", 'n');

		answer = inkey_ex();

		/* Clear last line */
		clear_from(15);
		clear_from(16);

		/* Determine what the personalized string will be used for.  */
		if ((answer.key == 'Y') || (answer.key == 'y')) {
		    prt("Will you add something for your ghost to say,", 15, 0);
		    prt("or add to the monster description?", 16, 0);
		    prt("((M)essage/(D)escription)", 17, 0);

		    /* Buttons */
		    button_kill('y');
		    button_kill('n');
		    button_add("M", 'M');
		    button_add("D", 'D');
		    button_add("ESC", ESCAPE);

		    while (1) {
			answer = inkey_ex();

			clear_from(15);
			clear_from(16);

			if ((answer.key == 'M') || (answer.key == 'm')) {
			    choice = 1;
			    break;
			} else if ((answer.key == 'D') || (answer.key == 'd')) {
			    choice = 2;
			    break;
			} else {
			    choice = 0;
			    break;
			}
		    }
		} else if ((answer.key == 'N') || (answer.key == 'n')
			   || (answer.key == ESCAPE)) {
		    choice = 0;
		    break;
		}

		button_kill_all();

		/* If requested, get the personalized string, and write it and
		 * info on how it should be used in the bones file.  Otherwise,
		 * indicate the absence of such a string. */
		if (choice)
		    file_putf(fp, "%d:%s\n", choice,
			      get_personalized_string(choice));
		else
		    file_putf(fp, "0: \n");

		/* Close and save the Bones file */
		file_close(fp);

		return;
	    }
	}
    }
}
Exemplo n.º 10
0
static bool cast_mage_spell(int spell, int dir)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int plev = p_ptr->lev;

	/* Hack -- chance of "beam" instead of "bolt" */
	int beam = beam_chance();

	/* Spells. */
	switch (spell)
	{
		case SPELL_MAGIC_MISSILE:
		{
			fire_bolt_or_beam(beam-10, GF_MISSILE, dir,
			                  damroll(3 + ((plev - 1) / 5), 4));
			break;
		}

		case SPELL_DETECT_MONSTERS:
		{
			(void)detect_monsters_normal(TRUE);
			break;
		}

		case SPELL_PHASE_DOOR:
		{
			teleport_player(10);
			break;
		}

		case SPELL_LIGHT_AREA:
		{
			(void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1);
			break;
		}

		case SPELL_OBJECT_DETECTION:
		{
			(void)detect_treasure(TRUE, TRUE);
			break;
		}

		case SPELL_CURE_LIGHT_WOUNDS:
		{

			heal_player(15, 15);
			player_dec_timed(p_ptr, TMD_CUT, 20, TRUE);
			player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE);
			player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case SPELL_FIND_TRAPS_DOORS:
		{
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			break;
		}

		case SPELL_STINKING_CLOUD:
		{
			fire_ball(GF_POIS, dir, 10 + (plev / 2), 2);
			break;
		}

		case SPELL_CONFUSE_MONSTER:
		{
			(void)confuse_monster(dir, plev, TRUE);
			break;
		}

		case SPELL_LIGHTNING_BOLT:
		{
			fire_beam(GF_ELEC, dir, damroll(3+((plev-5)/6), 6));
			break;
		}

		case SPELL_TRAP_DOOR_DESTRUCTION:
		{
			(void)destroy_doors_touch();
			break;
		}

		case SPELL_SLEEP_MONSTER:
		{
			(void)sleep_monster(dir, TRUE);
			break;
		}

		case SPELL_CURE_POISON:
		{
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			break;
		}

		case SPELL_TELEPORT_SELF:
		{
			teleport_player(plev * 5);
			break;
		}

		case SPELL_SPEAR_OF_LIGHT:
		{
			msg("A line of blue shimmering light appears.");
			light_line(dir);
			break;
		}

		case SPELL_FROST_BOLT:
		{
			fire_bolt_or_beam(beam-10, GF_COLD, dir,
			                  damroll(5+((plev-5)/4), 8));
			break;
		}

		case SPELL_TURN_STONE_TO_MUD:
		{
			(void)wall_to_mud(dir);
			break;
		}

		case SPELL_SATISFY_HUNGER:
		{
			player_set_food(p_ptr, PY_FOOD_MAX - 1);
			break;
		}

		case SPELL_RECHARGE_ITEM_I:
		{
			return recharge(2 + plev / 5);
		}

		case SPELL_WONDER:
		{
			(void)spell_wonder(dir);
			break;
		}

		case SPELL_POLYMORPH_OTHER:
		{
			(void)poly_monster(dir);
			break;
		}

		case SPELL_IDENTIFY:
		{
			return ident_spell();
		}

		case SPELL_MASS_SLEEP:
		{
			(void)sleep_monsters(TRUE);
			break;
		}

		case SPELL_FIRE_BOLT:
		{
			fire_bolt_or_beam(beam, GF_FIRE, dir,
			                  damroll(6+((plev-5)/4), 8));
			break;
		}

		case SPELL_SLOW_MONSTER:
		{
			(void)slow_monster(dir);
			break;
		}

		case SPELL_FROST_BALL:
		{
			fire_ball(GF_COLD, dir, 30 + (plev), 2);
			break;
		}

		case SPELL_RECHARGE_ITEM_II: /* greater recharging */
		{
			return recharge(50 + plev);
		}

		case SPELL_TELEPORT_OTHER:
		{
			(void)teleport_monster(dir);
			break;
		}

		case SPELL_BEDLAM:
		{
			fire_ball(GF_OLD_CONF, dir, plev, 4);
			break;
		}

		case SPELL_FIRE_BALL:
		{
			fire_ball(GF_FIRE, dir, 55 + (plev), 2);
			break;
		}

		case SPELL_WORD_OF_DESTRUCTION:
		{
			destroy_area(py, px, 15, TRUE);
			break;
		}

		case SPELL_BANISHMENT:
		{
			return banishment();
		}

		case SPELL_DOOR_CREATION:
		{
			(void)door_creation();
			break;
		}

		case SPELL_STAIR_CREATION:
		{
			(void)stair_creation();
			break;
		}

		case SPELL_TELEPORT_LEVEL:
		{
			(void)teleport_player_level();
			break;
		}

		case SPELL_EARTHQUAKE:
		{
			earthquake(py, px, 10);
			break;
		}

		case SPELL_WORD_OF_RECALL:
		{
			return set_recall();
		}

		case SPELL_ACID_BOLT:
		{
			fire_bolt_or_beam(beam, GF_ACID, dir, damroll(8+((plev-5)/4), 8));
			break;
		}

		case SPELL_CLOUD_KILL:
		{
			fire_ball(GF_POIS, dir, 40 + (plev / 2), 3);
			break;
		}

		case SPELL_ACID_BALL:
		{
			fire_ball(GF_ACID, dir, 40 + (plev), 2);
			break;
		}

		case SPELL_ICE_STORM:
		{
			fire_ball(GF_ICE, dir, 50 + (plev * 2), 3);
			break;
		}

		case SPELL_METEOR_SWARM:
		{
			fire_swarm(2 + plev / 20, GF_METEOR, dir, 30 + plev / 2, 1);
			break;
		}

		case SPELL_MANA_STORM:
		{
			fire_ball(GF_MANA, dir, 300 + (plev * 2), 3);
			break;
		}
		case SPELL_DETECT_INVISIBLE:
		{
			(void)detect_monsters_normal(TRUE);
			(void)detect_monsters_invis(TRUE);
			break;
		}

		case SPELL_TREASURE_DETECTION:
		{
			(void)detect_treasure(TRUE, FALSE);
			break;
		}

		case SPELL_SHOCK_WAVE:
		{
			fire_ball(GF_SOUND, dir, 10 + plev, 2);
			break;
		}

		case SPELL_EXPLOSION:
		{
			fire_ball(GF_SHARD, dir, 20 + (plev * 2), 2);
			break;
		}

		case SPELL_MASS_BANISHMENT:
		{
			(void)mass_banishment();
			break;
		}

		case SPELL_RESIST_FIRE:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_RESIST_COLD:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_ELEMENTAL_BRAND: /* elemental brand */
		{
			return brand_ammo();
		}

		case SPELL_RESIST_POISON:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_POIS, randint1(20) + 20, TRUE, TRUE);
			break;
		}

		case SPELL_RESISTANCE:
		{
			int time = randint1(20) + 20;
			(void)player_inc_timed(p_ptr, TMD_OPP_ACID, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_ELEC, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, time, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_POIS, time, TRUE, TRUE);
			break;
		}

		case SPELL_HEROISM:
		{
			int dur = randint1(25) + 25;
			(void)hp_player(10);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_HERO, dur, TRUE, TRUE);
			break;
		}

		case SPELL_SHIELD:
		{
			(void)player_inc_timed(p_ptr, TMD_SHIELD, randint1(20) + 30, TRUE, TRUE);
			break;
		}

		case SPELL_BERSERKER:
		{
			int dur = randint1(25) + 25;
			(void)hp_player(30);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_inc_timed(p_ptr, TMD_BOLD, dur, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_SHERO, dur, TRUE, TRUE);
			break;
		}

		case SPELL_HASTE_SELF:
		{
			if (!p_ptr->timed[TMD_FAST])
			{
				(void)player_set_timed(p_ptr, TMD_FAST, randint1(20) + plev, TRUE);
			}
			else
			{
				(void)player_inc_timed(p_ptr, TMD_FAST, randint1(5), TRUE, TRUE);
			}
			break;
		}

		case SPELL_RIFT:
		{
			fire_beam(GF_GRAVITY, dir,	40 + damroll(plev, 7));
			break;
		}

		case SPELL_REND_SOUL: /* rend soul */
		{
			fire_bolt_or_beam(beam / 4, GF_NETHER, dir, damroll(11, plev));
			break;
		}

		case SPELL_CHAOS_STRIKE: /* chaos strike */
		{
			fire_bolt_or_beam(beam, GF_CHAOS, dir, damroll(13, plev));
			break;
		}

		case SPELL_RUNE_OF_PROTECTION: /* rune of protection */
		{
			warding_glyph_spell();
			break;
		}

		case SPELL_ENCHANT_ARMOR: /* enchant armor */
		{
			return enchant_spell(0, 0, randint0(3) + plev / 20);
		}

		case SPELL_ENCHANT_WEAPON: /* enchant weapon */
		{
			return enchant_spell(randint0(4) + plev / 20,
			                     randint0(4) + plev / 20, 0);
		}
	}

	/* Success */
	return (TRUE);
}
Exemplo n.º 11
0
static bool cast_priest_spell(int spell, int dir)
{
	int py = p_ptr->py;
	int px = p_ptr->px;

	int plev = p_ptr->lev;

	int amt;

	switch (spell)
	{
		case PRAYER_DETECT_EVIL:
		{
			(void)detect_monsters_evil(TRUE);
			break;
		}

		case PRAYER_CURE_LIGHT_WOUNDS:
		{
			(void)heal_player(15, 15);
			(void)player_dec_timed(p_ptr, TMD_CUT, 20, TRUE);
			(void)player_dec_timed(p_ptr, TMD_CONFUSED, 20, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_BLESS:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(12) + 12, TRUE, TRUE);
			break;
		}

		case PRAYER_REMOVE_FEAR:
		{
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			break;
		}

		case PRAYER_CALL_LIGHT:
		{
			(void)light_area(damroll(2, (plev / 2)), (plev / 10) + 1);
			break;
		}

		case PRAYER_FIND_TRAPS_DOORS:
		{
			(void)detect_traps(TRUE);
			(void)detect_doorstairs(TRUE);
			break;
		}

		case PRAYER_SCARE_MONSTER:
		{
			(void)fear_monster(dir, plev, TRUE);
			break;
		}

		case PRAYER_PORTAL:
		{
			teleport_player(plev * 3);
			break;
		}

		case PRAYER_CURE_SERIOUS_WOUNDS:
		{
			(void)heal_player(20, 25);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_CHANT:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(24) + 24, TRUE, TRUE);
			break;
		}

		case PRAYER_SANCTUARY:
		{
			(void)sleep_monsters_touch(TRUE);
			break;
		}

		case PRAYER_SATISFY_HUNGER:
		{
			player_set_food(p_ptr, PY_FOOD_MAX - 1);
			break;
		}
		
        /* Remove curse has been removed in 3.4 until curses are redone
		case PRAYER_REMOVE_CURSE:
		{
			remove_curse();
			break;
		}
		*/

		case PRAYER_RESIST_HEAT_COLD:
		{
			(void)player_inc_timed(p_ptr, TMD_OPP_FIRE, randint1(10) + 10, TRUE, TRUE);
			(void)player_inc_timed(p_ptr, TMD_OPP_COLD, randint1(10) + 10, TRUE, TRUE);
			break;
		}

		case PRAYER_NEUTRALIZE_POISON:
		{
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			break;
		}

		case PRAYER_ORB_OF_DRAINING:
		{
			fire_ball(GF_HOLY_ORB, dir,
				(damroll(3, 6) + plev +
				 (player_has(PF_ZERO_FAIL)
					? (plev / 2)
					: (plev / 4))),	
				((plev < 30) ? 2 : 3));
			break;
		}

		case PRAYER_CURE_CRITICAL_WOUNDS:
		{
			(void)heal_player(25, 30);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_SENSE_INVISIBLE:
		{
			(void)player_inc_timed(p_ptr, TMD_SINVIS, randint1(24) + 24, TRUE, TRUE);
			break;
		}

		case PRAYER_PROTECTION_FROM_EVIL:
		{
			(void)player_inc_timed(p_ptr, TMD_PROTEVIL, randint1(25) + 3 * p_ptr->lev, TRUE,
				TRUE);
			break;
		}

		case PRAYER_EARTHQUAKE:
		{
			earthquake(py, px, 10);
			break;
		}

		case PRAYER_SENSE_SURROUNDINGS:
		{
			map_area();
			break;
		}

		case PRAYER_CURE_MORTAL_WOUNDS:
		{
			(void)heal_player(30, 50);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_TURN_UNDEAD:
		{
			(void)turn_undead(TRUE);
			break;
		}

		case PRAYER_PRAYER:
		{
			(void)player_inc_timed(p_ptr, TMD_BLESSED, randint1(48) + 48, TRUE, TRUE);
			break;
		}

		case PRAYER_DISPEL_UNDEAD:
		{
			(void)dispel_undead(randint1(plev * 3));
			break;
		}

		case PRAYER_HEAL:
		{
			amt = (p_ptr->mhp * 35) / 100;
                        if (amt < 300) amt = 300;
			
			(void)hp_player(amt);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_DISPEL_EVIL:
		{
			(void)dispel_evil(randint1(plev * 3));
			break;
		}

		case PRAYER_GLYPH_OF_WARDING:
		{
			warding_glyph_spell();
			break;
		}

		case PRAYER_HOLY_WORD:
		{
			(void)dispel_evil(randint1(plev * 4));
			(void)hp_player(1000);
			(void)player_clear_timed(p_ptr, TMD_AFRAID, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			break;
		}

		case PRAYER_DETECT_MONSTERS:
		{
			(void)detect_monsters_normal(TRUE);
			break;
		}

		case PRAYER_DETECTION:
		{
			(void)detect_all(TRUE);
			break;
		}

		case PRAYER_PERCEPTION:
		{
			return ident_spell();
		}

		case PRAYER_PROBING:
		{
			(void)probing();
			break;
		}

		case PRAYER_CLAIRVOYANCE:
		{
			wiz_light(FALSE);
			break;
		}

		case PRAYER_CURE_SERIOUS_WOUNDS2:
		{
			(void)heal_player(20, 25);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			break;
		}

		case PRAYER_CURE_MORTAL_WOUNDS2:
		{
			(void)heal_player(30, 50);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			(void)player_clear_timed(p_ptr, TMD_AMNESIA, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CONFUSED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_BLIND, TRUE);
			(void)player_clear_timed(p_ptr, TMD_POISONED, TRUE);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			break;
		}

		case PRAYER_HEALING:
		{
			(void)hp_player(2000);
			(void)player_clear_timed(p_ptr, TMD_STUN, TRUE);
			(void)player_clear_timed(p_ptr, TMD_CUT, TRUE);
			break;
		}

		case PRAYER_RESTORATION:
		{
			(void)do_res_stat(A_STR);
			(void)do_res_stat(A_INT);
			(void)do_res_stat(A_WIS);
			(void)do_res_stat(A_DEX);
			(void)do_res_stat(A_CON);
			break;
		}

		case PRAYER_REMEMBRANCE:
		{
			(void)restore_level();
			break;
		}

		case PRAYER_DISPEL_UNDEAD2:
		{
			(void)dispel_undead(randint1(plev * 4));
			break;
		}

		case PRAYER_DISPEL_EVIL2:
		{
			(void)dispel_evil(randint1(plev * 4));
			break;
		}

		case PRAYER_BANISH_EVIL:
		{
			if (banish_evil(100))
			{
				msg("The power of your god banishes evil!");
			}
			break;
		}

		case PRAYER_WORD_OF_DESTRUCTION:
		{
			destroy_area(py, px, 15, TRUE);
			break;
		}

		case PRAYER_ANNIHILATION:
		{
			drain_life(dir, 200);
			break;
		}

		case PRAYER_UNBARRING_WAYS:
		{
			(void)destroy_doors_touch();
			break;
		}

		case PRAYER_RECHARGING:
		{
			return recharge(20 + plev);
		}
		
        /* Dispel Curse has been removed in 3.4 until curses are redone 
		case PRAYER_DISPEL_CURSE:
		{
			(void)remove_all_curse();
			break;
		}
		*/
		
		case PRAYER_ENCHANT_WEAPON:
		{
			return enchant_spell(randint0(4) + 1, randint0(4) + 1, 0);
		}

		case PRAYER_ENCHANT_ARMOUR:
		{
			return enchant_spell(0, 0, randint0(3) + 2);
		}

		case PRAYER_ELEMENTAL_BRAND:
		{
			brand_weapon();
			break;
		}

		case PRAYER_BLINK:
		{
			teleport_player(10);
			break;
		}

		case PRAYER_TELEPORT_SELF:
		{
			teleport_player(plev * 8);
			break;
		}

		case PRAYER_TELEPORT_OTHER:
		{
			(void)teleport_monster(dir);
			break;
		}

		case PRAYER_TELEPORT_LEVEL:
		{
			(void)teleport_player_level();
			break;
		}

		case PRAYER_WORD_OF_RECALL:
		{
			return set_recall();
		}

		case PRAYER_ALTER_REALITY:
		{
			msg("The world changes!");

			/* Leaving */
			p_ptr->leaving = TRUE;

			break;
		}
	}

	/* Success */
	return (TRUE);
}
Exemplo n.º 12
0
static void do_cmd_eat_food_aux(obj_ptr obj)
{
    int  lev = k_info[obj->k_idx].level;
    bool ident = FALSE;

    if (music_singing_any()) bard_stop_singing();
    if (hex_spelling_any()) stop_hex_spell_all();
    warlock_stop_singing();

    if (object_is_mushroom(obj) && obj->art_name && obj->timeout)
    {
        msg_print("Your mushroom is still charging.");
        return;
    }

    sound(SOUND_EAT);
    energy_use = 100;
    ident = FALSE;

    /* Food may have effects */
    if (obj->tval == TV_FOOD)
    {
        switch (obj->sval)
        {
            case SV_FOOD_POISON:
            {
                if (!res_save_default(RES_POIS))
                {
                    if (set_poisoned(p_ptr->poisoned + randint0(10) + 10, FALSE))
                        ident = TRUE;
                }
                break;
            }

            case SV_FOOD_BLINDNESS:
            {
                if (!res_save_default(RES_BLIND))
                {
                    if (set_blind(p_ptr->blind + randint0(200) + 200, FALSE))
                        ident = TRUE;
                }
                break;
            }

            case SV_FOOD_PARANOIA:
            {
                if (!fear_save_p(fear_threat_level()))
                    ident = fear_add_p(FEAR_SCARED);
                break;
            }

            case SV_FOOD_CONFUSION:
            {
                if (!res_save_default(RES_CONF))
                {
                    if (set_confused(p_ptr->confused + randint0(10) + 10, FALSE))
                        ident = TRUE;
                }
                break;
            }

            case SV_FOOD_HALLUCINATION:
            {
                if (!res_save_default(RES_CHAOS))
                {
                    if (set_image(p_ptr->image + randint0(25) + 25, FALSE))
                        ident = TRUE;
                }
                break;
            }

            case SV_FOOD_PARALYSIS:
            {
                if (!p_ptr->free_act)
                {
                    if (set_paralyzed(randint1(4), FALSE))
                    {
                        ident = TRUE;
                    }
                }
                else equip_learn_flag(OF_FREE_ACT);
                break;
            }

            case SV_FOOD_WEAKNESS:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(6, 6), "poisonous food", -1);
                do_dec_stat(A_STR);
                ident = TRUE;
                break;
            }

            case SV_FOOD_SICKNESS:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(6, 6), "poisonous food", -1);
                do_dec_stat(A_CON);
                ident = TRUE;
                break;
            }

            case SV_FOOD_STUPIDITY:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(8, 8), "poisonous food", -1);
                do_dec_stat(A_INT);
                ident = TRUE;
                break;
            }

            case SV_FOOD_NAIVETY:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(8, 8), "poisonous food", -1);
                do_dec_stat(A_WIS);
                ident = TRUE;
                break;
            }

            case SV_FOOD_UNHEALTH:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(10, 10), "poisonous food", -1);
                do_dec_stat(A_CON);
                ident = TRUE;
                break;
            }

            case SV_FOOD_DISEASE:
            {
                take_hit(DAMAGE_NOESCAPE, damroll(10, 10), "poisonous food", -1);
                do_dec_stat(A_STR);
                ident = TRUE;
                break;
            }

            case SV_FOOD_CURE_POISON:
            {
                if (set_poisoned(0, TRUE)) ident = TRUE;
                break;
            }

            case SV_FOOD_CURE_BLINDNESS:
            {
                if (set_blind(0, TRUE)) ident = TRUE;
                break;
            }

            case SV_FOOD_CURE_PARANOIA:
            {
                if (p_ptr->afraid)
                {
                    fear_clear_p();
                    ident = TRUE;
                }
                break;
            }

            case SV_FOOD_CURE_CONFUSION:
            {
                if (set_confused(0, TRUE)) ident = TRUE;
                break;
            }

            case SV_FOOD_CURE_SERIOUS:
            {
                if (hp_player(damroll(6, 8))) ident = TRUE;
                if (set_cut((p_ptr->cut / 2) - 50, TRUE)) ident = TRUE;
                break;
            }

            case SV_FOOD_RESTORE_STR:
            {
                if (do_res_stat(A_STR)) ident = TRUE;
                break;
            }

            case SV_FOOD_RESTORE_CON:
            {
                if (do_res_stat(A_CON)) ident = TRUE;
                break;
            }

            case SV_FOOD_RESTORING:
            {
                if (do_res_stat(A_STR)) ident = TRUE;
                if (do_res_stat(A_INT)) ident = TRUE;
                if (do_res_stat(A_WIS)) ident = TRUE;
                if (do_res_stat(A_DEX)) ident = TRUE;
                if (do_res_stat(A_CON)) ident = TRUE;
                if (do_res_stat(A_CHR)) ident = TRUE;
                break;
            }
            case SV_FOOD_RATION:
            case SV_FOOD_BISCUIT:
            case SV_FOOD_JERKY:
            case SV_FOOD_SLIME_MOLD:
            {
                msg_print("That tastes good.");
                ident = TRUE;
                break;
            }
            case SV_FOOD_AMBROSIA:
            {
                msg_print("That tastes divine!");
                set_poisoned(0, TRUE);
                hp_player(damroll(15, 15));
                do_res_stat(A_STR);
                do_res_stat(A_INT);
                do_res_stat(A_WIS);
                do_res_stat(A_DEX);
                do_res_stat(A_CON);
                do_res_stat(A_CHR);
                restore_level();
                ident = TRUE;
                break;
            }

            case SV_FOOD_WAYBREAD:
            {
                msg_print("That tastes good.");
                set_poisoned(0, TRUE);
                hp_player(damroll(4, 8));
                ident = TRUE;
                break;
            }

            case SV_FOOD_PINT_OF_ALE:
            case SV_FOOD_PINT_OF_WINE:
            {
                msg_print("That tastes good.");
                ident = TRUE;
                break;
            }
        }
    }

    if (prace_is_(RACE_SNOTLING) && object_is_mushroom(obj))
    {
        int dur = lev + randint1(lev);
        set_fast(p_ptr->fast + dur, FALSE);
        set_shield(p_ptr->shield + dur, FALSE);
        set_hero(p_ptr->hero + dur, FALSE);
        set_tim_building_up(p_ptr->tim_building_up + dur, FALSE);
    }

    if (!object_is_aware(obj))
    {
        virtue_add(VIRTUE_KNOWLEDGE, -1);
        virtue_add(VIRTUE_PATIENCE, -1);
        virtue_add(VIRTUE_CHANCE, 1);
    }

    /* We have tried it */
    if (obj->tval == TV_FOOD) object_tried(obj);

    stats_on_use(obj, 1);

    /* The player is now aware of the object */
    if (ident && !object_is_aware(obj))
    {
        object_aware(obj);
        stats_on_notice(obj, 1);
        gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
        p_ptr->notice |= PN_OPTIMIZE_PACK;
    }
/*
 * Generate a new dungeon level
 *
 * Note that "dun_body" adds about 4000 bytes of memory to the stack.
 */
static bool cave_gen(void)
{
    int i, k, y, x;

    dun_data dun_body;

    /* Global data */
    dun = &dun_body;

    dun->destroyed = FALSE;
    dun->empty_level = FALSE;
    dun->cavern = FALSE;
    dun->laketype = 0;

    /* Fill the arrays of floors and walls in the good proportions */
    set_floor_and_wall(dungeon_type);

    /* Prepare allocation table */
    get_mon_num_prep(get_monster_hook(), NULL);

    /* Randomize the dungeon creation values */
    dun_tun_rnd = rand_range(DUN_TUN_RND_MIN, DUN_TUN_RND_MAX);
    dun_tun_chg = rand_range(DUN_TUN_CHG_MIN, DUN_TUN_CHG_MAX);
    dun_tun_con = rand_range(DUN_TUN_CON_MIN, DUN_TUN_CON_MAX);
    dun_tun_pen = rand_range(DUN_TUN_PEN_MIN, DUN_TUN_PEN_MAX);
    dun_tun_jct = rand_range(DUN_TUN_JCT_MIN, DUN_TUN_JCT_MAX);

    /* Actual maximum number of rooms on this level */
    dun->row_rooms = cur_hgt / BLOCK_HGT;
    dun->col_rooms = cur_wid / BLOCK_WID;

    /* Initialize the room table */
    for (y = 0; y < dun->row_rooms; y++)
    {
        for (x = 0; x < dun->col_rooms; x++)
        {
            dun->room_map[y][x] = FALSE;
        }
    }

    /* No rooms yet */
    dun->cent_n = 0;

    /* Empty arena levels */
    if (ironman_empty_levels || ((d_info[dungeon_type].flags1 & DF1_ARENA) && (empty_levels && one_in_(EMPTY_LEVEL))))
    {
        dun->empty_level = TRUE;
        if (cheat_room)
            msg_print("Arena level.");
    }

    if (dun->empty_level)
    {
        /* Start with floors */
        for (y = 0; y < cur_hgt; y++)
        {
            for (x = 0; x < cur_wid; x++)
            {
                place_floor_bold(y, x);
            }
        }

        /* Special boundary walls -- Top and bottom */
        for (x = 0; x < cur_wid; x++)
        {
            place_extra_bold(0, x);
            place_extra_bold(cur_hgt - 1, x);
        }

        /* Special boundary walls -- Left and right */
        for (y = 1; y < (cur_hgt - 1); y++)
        {
            place_extra_bold(y, 0);
            place_extra_bold(y, cur_wid - 1);
        }
    }
    else
    {
        /* Start with walls */
        for (y = 0; y < cur_hgt; y++)
        {
            for (x = 0; x < cur_wid; x++)
            {
                place_extra_bold(y, x);
            }
        }
    }


    /* Generate various caverns and lakes */
    gen_caverns_and_lakes();


    /* Build maze */
    if (d_info[dungeon_type].flags1 & DF1_MAZE)
    {
        build_maze_vault(cur_wid/2-1, cur_hgt/2-1, cur_wid-4, cur_hgt-4, FALSE);

        /* Place 3 or 4 down stairs near some walls */
        if (!alloc_stairs(feat_down_stair, rand_range(4, 5), 3)) return FALSE;

        /* Place 1 or 2 up stairs near some walls */
        if (!alloc_stairs(feat_up_stair, 1, 2)) return FALSE;
    }

    /* Build some rooms */
    else
    {
        int tunnel_fail_count = 0;

        /*
         * Build each type of room in turn until we cannot build any more.
         */
        if (!generate_rooms()) return FALSE;


        /* Make a hole in the dungeon roof sometimes at level 1
           But not in Angband. See Issue #3 */
        if (dun_level == 1 && dungeon_type != DUNGEON_ANGBAND)
        {
            while (one_in_(DUN_MOS_DEN))
            {
                place_trees(randint1(cur_wid - 2), randint1(cur_hgt - 2));
            }
        }

        /* Destroy the level if necessary */
        if (dun->destroyed) destroy_level();

        /* Hack -- Add some rivers */
        if (one_in_(7) && (randint1(dun_level) > 5))
        {
            int feat1 = 0, feat2 = 0;

            /* Choose water or lava */
            if ( randint1(MAX_DEPTH * 2) - 1 > dun_level
              && ( (d_info[dungeon_type].flags1 & DF1_WATER_RIVER)
                || (no_wilderness && one_in_(3)) ) )
            {
                feat1 = feat_deep_water;
                feat2 = feat_shallow_water;
            }
            else if  (d_info[dungeon_type].flags1 & DF1_LAVA_RIVER)
            {
                feat1 = feat_deep_lava;
                feat2 = feat_shallow_lava;
            }
            else feat1 = 0;

            if (feat1)
            {
                feature_type *f_ptr = &f_info[feat1];

                /* Only add river if matches lake type or if have no lake at all */
                if (((dun->laketype == LAKE_T_LAVA) && have_flag(f_ptr->flags, FF_LAVA)) ||
                    ((dun->laketype == LAKE_T_WATER) && have_flag(f_ptr->flags, FF_WATER)) ||
                     !dun->laketype)
                {
                    add_river(feat1, feat2);
                }
            }
        }

        /* Hack -- Scramble the room order */
        for (i = 0; i < dun->cent_n; i++)
        {
            int ty, tx;
            int pick = rand_range(0, i);

            ty = dun->cent[i].y;
            tx = dun->cent[i].x;
            dun->cent[i].y = dun->cent[pick].y;
            dun->cent[i].x = dun->cent[pick].x;
            dun->cent[pick].y = ty;
            dun->cent[pick].x = tx;
        }

        /* Start with no tunnel doors */
        dun->door_n = 0;

        /* Hack -- connect the first room to the last room */
        y = dun->cent[dun->cent_n-1].y;
        x = dun->cent[dun->cent_n-1].x;

        /* Connect all the rooms together */
        for (i = 0; i < dun->cent_n; i++)
        {
            int j;

            /* Reset the arrays */
            dun->tunn_n = 0;
            dun->wall_n = 0;

            /* Connect the room to the previous room */
            if (randint1(dun_level) > d_info[dungeon_type].tunnel_percent)
            {
                /* make cave-like tunnel */
                (void)build_tunnel2(dun->cent[i].x, dun->cent[i].y, x, y, 2, 2);
            }
            else
            {
                /* make normal tunnel */
                if (!build_tunnel(dun->cent[i].y, dun->cent[i].x, y, x)) tunnel_fail_count++;
            }

            if (tunnel_fail_count >= 2) return FALSE;

            /* Turn the tunnel into corridor */
            for (j = 0; j < dun->tunn_n; j++)
            {
                cave_type *c_ptr;
                feature_type *f_ptr;

                /* Access the grid */
                y = dun->tunn[j].y;
                x = dun->tunn[j].x;

                /* Access the grid */
                c_ptr = &cave[y][x];
                f_ptr = &f_info[c_ptr->feat];

                /* Clear previous contents (if not a lake), add a floor */
                if (!have_flag(f_ptr->flags, FF_MOVE) || (!have_flag(f_ptr->flags, FF_WATER) && !have_flag(f_ptr->flags, FF_LAVA)))
                {
                    /* Clear mimic type */
                    c_ptr->mimic = 0;

                    place_floor_grid(c_ptr);
                }
            }

            /* Apply the piercings that we found */
            for (j = 0; j < dun->wall_n; j++)
            {
                cave_type *c_ptr;

                /* Access the grid */
                y = dun->wall[j].y;
                x = dun->wall[j].x;

                /* Access the grid */
                c_ptr = &cave[y][x];

                /* Clear mimic type */
                c_ptr->mimic = 0;

                /* Clear previous contents, add up floor */
                place_floor_grid(c_ptr);

                /* Occasional doorway */
                if ((randint0(100) < dun_tun_pen) && !(d_info[dungeon_type].flags1 & DF1_NO_DOORS))
                {
                    /* Place a random door */
                    place_random_door(y, x, TRUE);
                }
            }

            /* Remember the "previous" room */
            y = dun->cent[i].y;
            x = dun->cent[i].x;
        }

        /* Place intersection doors */
        for (i = 0; i < dun->door_n; i++)
        {
            /* Extract junction location */
            y = dun->door[i].y;
            x = dun->door[i].x;

            /* Try placing doors */
            try_door(y, x - 1);
            try_door(y, x + 1);
            try_door(y - 1, x);
            try_door(y + 1, x);
        }

        if (!alloc_stairs(feat_down_stair, rand_range(4, 5), 3)) return FALSE;

        /* Place 1 or 2 up stairs near some walls */
        if (!alloc_stairs(feat_up_stair, rand_range(1, 2), 3)) return FALSE;
    }

    if (!dun->laketype)
    {
        if (d_info[dungeon_type].stream2)
        {
            /* Hack -- Add some quartz streamers */
            for (i = 0; i < DUN_STR_QUA; i++)
            {
                build_streamer(d_info[dungeon_type].stream2, DUN_STR_QC);
            }
        }

        if (d_info[dungeon_type].stream1)
        {
            /* Hack -- Add some magma streamers */
            for (i = 0; i < DUN_STR_MAG; i++)
            {
                build_streamer(d_info[dungeon_type].stream1, DUN_STR_MC);
            }
        }
    }

    /* Special boundary walls -- Top and bottom */
    for (x = 0; x < cur_wid; x++)
    {
        set_bound_perm_wall(&cave[0][x]);
        set_bound_perm_wall(&cave[cur_hgt - 1][x]);
    }

    /* Special boundary walls -- Left and right */
    for (y = 1; y < (cur_hgt - 1); y++)
    {
        set_bound_perm_wall(&cave[y][0]);
        set_bound_perm_wall(&cave[y][cur_wid - 1]);
    }

    /* Determine the character location */
    if (!new_player_spot()) return FALSE;

    /* Basic "amount" */
    k = (dun_level / 3);
    if (k > 10) k = 10;
    if (k < 2) k = 2;

    /* Pick a base number of monsters */
    i = d_info[dungeon_type].min_m_alloc_level;

    /* To make small levels a bit more playable */
    if (cur_hgt < MAX_HGT || cur_wid < MAX_WID)
    {
        int small_tester = i;

        i = (i * cur_hgt) / MAX_HGT;
        i = (i * cur_wid) / MAX_WID;
        i += 1;

        if (i > small_tester) i = small_tester;
        else if (cheat_hear)
        {
            msg_format("Reduced monsters base from %d to %d", small_tester, i);

        }
    }


    if (dungeon_type != DUNGEON_ARENA)
    {
        i += randint1(8);

        /* Put some monsters in the dungeon */
        for (i = (dun_level < 50 ? (i+k) : (i+k)*6/10); i > 0; i--)
        {
            (void)alloc_monster(0, PM_ALLOW_SLEEP);
        }
    }

    /* Place some traps in the dungeon */
    alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_TRAP, randint1(k*3/2));

    /* Put some rubble in corridors (except NO_CAVE dungeon (Castle)) */
    if (!(d_info[dungeon_type].flags1 & DF1_NO_CAVE)) alloc_object(ALLOC_SET_CORR, ALLOC_TYP_RUBBLE, randint1(k));

    if (dungeon_type != DUNGEON_ARENA)
    {
        /* Put some objects in rooms */
        alloc_object(ALLOC_SET_ROOM, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ROOM, 3));

        /* Put some objects/gold in the dungeon */
        alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_OBJECT, randnor(DUN_AMT_ITEM, 3));
        alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_GOLD, randnor(DUN_AMT_GOLD, 3));

        /* Experimental: Guarantee certain objects. Give surprise goodies. */
        if (one_in_(2))
            alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_FOOD, 1);
        if (dun_level <= 15)
            alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_LIGHT, 1);
        if (dun_level >= 10 && one_in_(2))
            alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_RECALL, 1);
        if (dun_level >= 10 && one_in_(20))
            alloc_object(ALLOC_SET_BOTH, ALLOC_TYP_SKELETON, damroll(3, 5));

        _mon_give_extra_drop(MFLAG2_DROP_BASIC, 1);
        _mon_give_extra_drop(MFLAG2_DROP_UTILITY, randint0(4));
        if (dun_level > max_dlv[dungeon_type])
            _mon_give_extra_drop(MFLAG2_DROP_PRIZE, 1);

    }

    /* Set back to default */
    object_level = base_level;

    /* Put the Guardian */
    if (!alloc_guardian(TRUE)) return FALSE;

    if (dun->empty_level && (!one_in_(DARK_EMPTY) || (randint1(100) > dun_level)) && !(d_info[dungeon_type].flags1 & DF1_DARKNESS))
    {
        /* Lite the cave */
        for (y = 0; y < cur_hgt; y++)
        {
            for (x = 0; x < cur_wid; x++)
            {
                cave[y][x].info |= (CAVE_GLOW);
            }
        }
    }

    return TRUE;
}
Exemplo n.º 14
0
Arquivo: cmd2.c Projeto: mtadd/angband
/*
 * Chests have traps too.
 *
 * Exploding chest destroys contents (and traps).
 * Note that the chest itself is never destroyed.
 */
static void chest_trap(int y, int x, s16b o_idx)
{
	int i, trap;

	object_type *o_ptr = object_byid(o_idx);


	/* Ignore disarmed chests */
	if (o_ptr->pval[DEFAULT_PVAL] <= 0) return;

	/* Obtain the traps */
	trap = chest_traps[o_ptr->pval[DEFAULT_PVAL]];

	/* Lose strength */
	if (trap & (CHEST_LOSE_STR))
	{
		msg("A small needle has pricked you!");
		take_hit(p_ptr, damroll(1, 4), "a poison needle");
		(void)do_dec_stat(A_STR, FALSE);
	}

	/* Lose constitution */
	if (trap & (CHEST_LOSE_CON))
	{
		msg("A small needle has pricked you!");
		take_hit(p_ptr, damroll(1, 4), "a poison needle");
		(void)do_dec_stat(A_CON, FALSE);
	}

	/* Poison */
	if (trap & (CHEST_POISON))
	{
		msg("A puff of green gas surrounds you!");
		(void)player_inc_timed(p_ptr, TMD_POISONED, 10 + randint1(20), TRUE, TRUE);
	}

	/* Paralyze */
	if (trap & (CHEST_PARALYZE))
	{
		msg("A puff of yellow gas surrounds you!");
		(void)player_inc_timed(p_ptr, TMD_PARALYZED, 10 + randint1(20), TRUE, TRUE);
	}

	/* Summon monsters */
	if (trap & (CHEST_SUMMON))
	{
		int num = 2 + randint1(3);
		msg("You are enveloped in a cloud of smoke!");
		sound(MSG_SUM_MONSTER);
		for (i = 0; i < num; i++)
		{
			(void)summon_specific(y, x, p_ptr->depth, 0, 1);
		}
	}

	/* Explode */
	if (trap & (CHEST_EXPLODE))
	{
		msg("There is a sudden explosion!");
		msg("Everything inside the chest is destroyed!");
		o_ptr->pval[DEFAULT_PVAL] = 0;
		take_hit(p_ptr, damroll(5, 8), "an exploding chest");
	}
}
Exemplo n.º 15
0
/*
 * Attack the player via physical attacks.
 */
bool make_attack_normal(int m_idx)
{
	monster_type *m_ptr = &m_list[m_idx];

	monster_race *r_ptr = &r_info[m_ptr->r_idx];

	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	int ap_cnt;

	int i, k, tmp, ac, rlev;
	int do_cut, do_stun;

	s32b gold;

	object_type *o_ptr;

	char o_name[80];

	char m_name[80];

	char ddesc[80];

	bool blinked;


	/* Not allowed to attack */
	if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE);


	/* Total armor */
	ac = p_ptr->ac + p_ptr->to_a;

	/* Extract the effective monster level */
	rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);


	/* Get the monster name (or "it") */
	monster_desc(m_name, m_ptr, 0);

	/* Get the "died from" information (i.e. "a kobold") */
	monster_desc(ddesc, m_ptr, 0x88);


	/* Assume no blink */
	blinked = FALSE;

	/* Scan through all blows */
	for (ap_cnt = 0; ap_cnt < MONSTER_BLOW_MAX; ap_cnt++)
	{
		bool visible = FALSE;
		bool obvious = FALSE;

		int power = 0;
		int damage = 0;

		cptr act = NULL;

		/* Extract the attack infomation */
		int effect = r_ptr->blow[ap_cnt].effect;
		int method = r_ptr->blow[ap_cnt].method;
		int d_dice = r_ptr->blow[ap_cnt].d_dice;
		int d_side = r_ptr->blow[ap_cnt].d_side;


		/* Hack -- no more attacks */
		if (!method) break;


		/* Handle "leaving" */
		if (p_ptr->leaving) break;


		/* Extract visibility (before blink) */
		if (m_ptr->ml) visible = TRUE;



		/* Extract the attack "power" */
		switch (effect)
		{
			case RBE_HURT:      power = 60; break;
			case RBE_POISON:    power =  5; break;
			case RBE_UN_BONUS:  power = 20; break;
			case RBE_UN_POWER:  power = 15; break;
			case RBE_EAT_GOLD:  power =  5; break;
			case RBE_EAT_ITEM:  power =  5; break;
			case RBE_EAT_FOOD:  power =  5; break;
			case RBE_EAT_LIGHT:  power =  5; break;
			case RBE_ACID:      power =  0; break;
			case RBE_ELEC:      power = 10; break;
			case RBE_FIRE:      power = 10; break;
			case RBE_COLD:      power = 10; break;
			case RBE_BLIND:     power =  2; break;
			case RBE_CONFUSE:   power = 10; break;
			case RBE_TERRIFY:   power = 10; break;
			case RBE_PARALYZE:  power =  2; break;
			case RBE_LOSE_STR:  power =  0; break;
			case RBE_LOSE_DEX:  power =  0; break;
			case RBE_LOSE_CON:  power =  0; break;
			case RBE_LOSE_INT:  power =  0; break;
			case RBE_LOSE_WIS:  power =  0; break;
			case RBE_LOSE_CHR:  power =  0; break;
			case RBE_LOSE_ALL:  power =  2; break;
			case RBE_SHATTER:   power = 60; break;
			case RBE_EXP_10:    power =  5; break;
			case RBE_EXP_20:    power =  5; break;
			case RBE_EXP_40:    power =  5; break;
			case RBE_EXP_80:    power =  5; break;
			case RBE_HALLU:     power = 10; break;
		}


		/* Monster hits player */
		if (!effect || check_hit(power, rlev))
		{
			/* Always disturbing */
			disturb(1, 0);


			/* Hack -- Apply "protection from evil" */
			if ((p_ptr->protevil > 0) &&
			    (r_ptr->flags3 & (RF3_EVIL)) &&
			    (p_ptr->lev >= rlev) &&
			    ((rand_int(100) + p_ptr->lev) > 50))
			{
				/* Remember the Evil-ness */
				if (m_ptr->ml)
				{
					l_ptr->flags3 |= (RF3_EVIL);
				}

				/* Message */
				msg_format("%^s is repelled.", m_name);

				/* Hack -- Next attack */
				continue;
			}


			/* Assume no cut or stun */
			do_cut = do_stun = 0;

			/* Describe the attack method */
			switch (method)
			{
				case RBM_HIT:
				{
					act = "hits you.";
					do_cut = do_stun = 1;
					break;
				}

				case RBM_TOUCH:
				{
					act = "touches you.";
					break;
				}

				case RBM_PUNCH:
				{
					act = "punches you.";
					do_stun = 1;
					break;
				}

				case RBM_KICK:
				{
					act = "kicks you.";
					do_stun = 1;
					break;
				}

				case RBM_CLAW:
				{
					act = "claws you.";
					do_cut = 1;
					break;
				}

				case RBM_BITE:
				{
					act = "bites you.";
					do_cut = 1;
					break;
				}

				case RBM_STING:
				{
					act = "stings you.";
					break;
				}

				case RBM_XXX1:
				{
					act = "XXX1's you.";
					break;
				}

				case RBM_BUTT:
				{
					act = "butts you.";
					do_stun = 1;
					break;
				}

				case RBM_CRUSH:
				{
					act = "crushes you.";
					do_stun = 1;
					break;
				}

				case RBM_ENGULF:
				{
					act = "engulfs you.";
					break;
				}

				case RBM_XXX2:
				{
					act = "XXX2's you.";
					break;
				}

				case RBM_CRAWL:
				{
					act = "crawls on you.";
					break;
				}

				case RBM_DROOL:
				{
					act = "drools on you.";
					break;
				}

				case RBM_SPIT:
				{
					act = "spits on you.";
					break;
				}

				case RBM_XXX3:
				{
					act = "XXX3's on you.";
					break;
				}

				case RBM_GAZE:
				{
					act = "gazes at you.";
					break;
				}

				case RBM_WAIL:
				{
					act = "wails at you.";
					break;
				}

				case RBM_SPORE:
				{
					act = "releases spores at you.";
					break;
				}

				case RBM_XXX4:
				{
					act = "projects XXX4's at you.";
					break;
				}

				case RBM_BEG:
				{
					act = "begs you for money.";
					break;
				}

				case RBM_INSULT:
				{
					act = desc_insult[rand_int(MAX_DESC_INSULT)];
					break;
				}

				case RBM_MOAN:
				{
					act = desc_moan[rand_int(MAX_DESC_MOAN)];
					break;
				}

				case RBM_XXX5:
				{
					act = "XXX5's you.";
					break;
				}
			}

			/* Message */
			if (act) msg_format("%^s %s", m_name, act);


			/* Hack -- assume all attacks are obvious */
			obvious = TRUE;

			/* Roll out the damage */
			damage = damroll(d_dice, d_side);

			/* Apply appropriate damage */
			switch (effect)
			{
				case 0:
				{
					/* Hack -- Assume obvious */
					obvious = TRUE;

					/* Hack -- No damage */
					damage = 0;

					break;
				}

				case RBE_HURT:
				{
					/* Obvious */
					obvious = TRUE;

					/* Hack -- Player armor reduces total damage */
					damage -= (damage * ((ac < 150) ? ac : 150) / 250);

					/* Take damage */
					take_hit(damage, ddesc);

					break;
				}

				case RBE_POISON:
				{
					int resist_percent = 0;

					/* Grab a current % resist value */
					resist_percent = resist_player_current(RES_POIS);

					if (resist_percent > 15) damage = damage * (3/4);

					/* Take damage */
					take_hit(damage, ddesc);

					/* Take "poison" effect */
					if (!resist_percent)
					{
						if (set_poisoned(p_ptr->poisoned + randint(rlev) + 5))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_POIS);

					break;
				}

				case RBE_UN_BONUS:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Apply disenchantment */
					if (apply_disenchant(0)) obvious = TRUE;

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_DISEN);

					break;
				}

				case RBE_UN_POWER:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Find an item */
					for (k = 0; k < 10; k++)
					{
						/* Pick an item */
						i = rand_int(INVEN_PACK);

						/* Obtain the item */
						o_ptr = &inventory[i];

						/* Skip non-objects */
						if (!o_ptr->k_idx) continue;

						/* Drain charged wands/staffs */
						if (((o_ptr->tval == TV_STAFF) ||
						     (o_ptr->tval == TV_WAND)) &&
						    (o_ptr->pval > 0))
						{
							/* Calculate healed hitpoints */
							int heal = rlev * o_ptr->pval * o_ptr->number;

							/* Don't heal more than max hp */
							heal = MIN(heal, m_ptr->maxhp - m_ptr->hp);

							/* Message */
							msg_print("Energy drains from your pack!");

							/* Obvious */
							obvious = TRUE;

							/* Heal */
							m_ptr->hp += heal;

							/* Redraw (later) if needed */
							if (p_ptr->health_who == m_idx)
								p_ptr->redraw |= (PR_HEALTH);

							/* Uncharge */
							o_ptr->pval = 0;

							/* Combine / Reorder the pack */
							p_ptr->notice |= (PN_COMBINE | PN_REORDER);

							/* Window stuff */
							p_ptr->window |= (PW_INVEN);

							/* Done */
							break;
						}
					}

					break;
				}

				case RBE_EAT_GOLD:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Obvious */
					obvious = TRUE;

					/* Saving throw (unless paralyzed) based on dex and level */
					if (!p_ptr->paralyzed &&
					    (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
					                      p_ptr->lev)))
					{
						/* Saving throw message */
						msg_print("You quickly protect your money pouch!");

						/* Occasional blink anyway */
						if (rand_int(3)) blinked = TRUE;
					}

					/* Eat gold */
					else
					{
						gold = (p_ptr->au / 10) + randint(25);
						if (gold < 2) gold = 2;
						if (gold > 5000) gold = (p_ptr->au / 20) + randint(3000);
						if (gold > p_ptr->au) gold = p_ptr->au;
						p_ptr->au -= gold;
						if (gold <= 0)
						{
							msg_print("Nothing was stolen.");
						}
						else if (p_ptr->au)
						{
							msg_print("Your purse feels lighter.");
							msg_format("%ld coins were stolen!", (long)gold);
						}
						else
						{
							msg_print("Your purse feels lighter.");
							msg_print("All of your coins were stolen!");
						}

						/* Redraw gold */
						p_ptr->redraw |= (PR_GOLD);

						/* Window stuff */
						p_ptr->window |= (PW_PLAYER_0 | PW_PLAYER_1);

						/* Blink away */
						blinked = TRUE;
					}

					break;
				}

				case RBE_EAT_ITEM:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Saving throw (unless paralyzed) based on dex and level */
					if (!p_ptr->paralyzed &&
					    (rand_int(100) < (adj_dex_safe[p_ptr->stat_ind[A_DEX]] +
					                      p_ptr->lev)))
					{
						/* Saving throw message */
						msg_print("You grab hold of your backpack!");

						/* Occasional "blink" anyway */
						blinked = TRUE;

						/* Obvious */
						obvious = TRUE;

						/* Done */
						break;
					}

					/* Find an item */
					for (k = 0; k < 10; k++)
					{
						object_type *i_ptr;
						object_type object_type_body;

						/* Pick an item */
						i = rand_int(INVEN_PACK);

						/* Obtain the item */
						o_ptr = &inventory[i];

						/* Skip non-objects */
						if (!o_ptr->k_idx) continue;

						/* Skip artifacts */
						if (artifact_p(o_ptr)) continue;

						/* Get a description */
						object_desc(o_name, o_ptr, FALSE, 3);

						/* Message */
						msg_format("%sour %s (%c) was stolen!",
						           ((o_ptr->number > 1) ? "One of y" : "Y"),
						           o_name, index_to_label(i));

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain local object */
						object_copy(i_ptr, o_ptr);

						/* Modify number */
						i_ptr->number = 1;

						/* Carry the object */
						(void)monster_carry(m_idx, i_ptr);

						/* Steal the items */
						inven_item_increase(i, -1);
						inven_item_optimize(i);

						/* Obvious */
						obvious = TRUE;

						/* Blink away */
						blinked = TRUE;

						/* Done */
						break;
					}

					break;
				}

				case RBE_EAT_FOOD:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Steal some food */
					for (k = 0; k < 10; k++)
					{
						/* Pick an item from the pack */
						i = rand_int(INVEN_PACK);

						/* Get the item */
						o_ptr = &inventory[i];

						/* Skip non-objects */
						if (!o_ptr->k_idx) continue;

						/* Skip non-food objects */
						if (o_ptr->tval != TV_FOOD) continue;

						/* Get a description */
						object_desc(o_name, o_ptr, FALSE, 0);

						/* Message */
						msg_format("%sour %s (%c) was eaten!",
						           ((o_ptr->number > 1) ? "One of y" : "Y"),
						           o_name, index_to_label(i));

						/* Steal the items */
						inven_item_increase(i, -1);
						inven_item_optimize(i);

						/* Obvious */
						obvious = TRUE;

						/* Done */
						break;
					}

					break;
				}

				case RBE_EAT_LIGHT:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Get the light */
					o_ptr = &inventory[INVEN_LIGHT];

					/* Drain fuel */
					if ((o_ptr->pval > 0) && (!artifact_p(o_ptr)))
					{
						/* Reduce fuel */
						o_ptr->pval -= (250 + randint(250));
						if (o_ptr->pval < 1) o_ptr->pval = 1;

						/* Notice */
						if (!p_ptr->blind)
						{
							msg_print("Your light dims.");
							obvious = TRUE;
						}

						/* Window stuff */
						p_ptr->window |= (PW_EQUIP);
					}

					break;
				}

				case RBE_ACID:
				{
					/* Obvious */
					obvious = TRUE;

					/* Message */
					msg_print("You are covered in acid!");

					/* Special damage */
					acid_dam(damage, ddesc);

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_ACID);

					break;
				}

				case RBE_ELEC:
				{
					/* Obvious */
					obvious = TRUE;

					/* Message */
					msg_print("You are struck by electricity!");

					/* Take damage (special) */
					elec_dam(damage, ddesc);

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_ELEC);

					break;
				}

				case RBE_FIRE:
				{
					/* Obvious */
					obvious = TRUE;

					/* Message */
					msg_print("You are enveloped in flames!");

					/* Take damage (special) */
					fire_dam(damage, ddesc);

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_FIRE);

					break;
				}

				case RBE_COLD:
				{
					/* Obvious */
					obvious = TRUE;

					/* Message */
					msg_print("You are covered with frost!");

					/* Take damage (special) */
					cold_dam(damage, ddesc);

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_COLD);

					break;
				}

				case RBE_BLIND:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Increase "blind" */
					if (!p_ptr->immune_blind)
					{
						if (set_blind(p_ptr->blind + 10 + randint(rlev)))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_BLIND);

					break;
				}

				case RBE_CONFUSE:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Increase "confused" */
					if (!p_ptr->immune_conf)
					{
						if (set_confused(p_ptr->confused + 3 + randint(rlev)))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_CONFU);

					break;
				}

				case RBE_TERRIFY:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Increase "afraid" */
					if (!p_ptr->immune_fear)
					{
						msg_print("You stand your ground!");
						obvious = TRUE;
					}
					else
					{
						if (set_afraid(p_ptr->afraid + 3 + randint(rlev)))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_FEAR);

					break;
				}

				case RBE_PARALYZE:
				{
					/* Hack -- Prevent perma-paralysis via damage */
					if (p_ptr->paralyzed && (damage < 1)) damage = 1;

					/* Take damage */
					take_hit(damage, ddesc);

					/* Increase "paralyzed" */
					if (p_ptr->free_act)
					{
						msg_print("You are unaffected!");
						obvious = TRUE;
					}
					else if (rand_int(100) < p_ptr->skill_sav)
					{
						msg_print("You resist the effects!");
						obvious = TRUE;
					}
					else
					{
						if (set_paralyzed(p_ptr->paralyzed + 3 + randint(rlev)))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_FREE);

					break;
				}

				case RBE_LOSE_STR:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_STR)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_INT:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_INT)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_WIS:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_WIS)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_DEX:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_DEX)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_CON:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_CON)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_CHR:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stat) */
					if (do_dec_stat(A_CHR)) obvious = TRUE;

					break;
				}

				case RBE_LOSE_ALL:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Damage (stats) */
					if (do_dec_stat(A_STR)) obvious = TRUE;
					if (do_dec_stat(A_DEX)) obvious = TRUE;
					if (do_dec_stat(A_CON)) obvious = TRUE;
					if (do_dec_stat(A_INT)) obvious = TRUE;
					if (do_dec_stat(A_WIS)) obvious = TRUE;
					if (do_dec_stat(A_CHR)) obvious = TRUE;

					break;
				}

				case RBE_SHATTER:
				{
					/* Obvious */
					obvious = TRUE;

					/* Hack -- Reduce damage based on the player armor class */
					damage -= (damage * ((ac < 150) ? ac : 150) / 250);

					/* Take damage */
					take_hit(damage, ddesc);

					/* Radius 8 earthquake centered at the monster */
					if (damage > 23) earthquake(m_ptr->fy, m_ptr->fx, 8);

					break;
				}

				case RBE_EXP_10:
				{
					/* Obvious */
					obvious = TRUE;

					/* Take damage */
					take_hit(damage, ddesc);

					if (p_ptr->hold_life && (rand_int(100) < 95))
					{
						msg_print("You keep hold of your life force!");
					}
					else
					{
						s32b d = damroll(10, 6) + (p_ptr->exp/100) * MON_DRAIN_LIFE;
						if (p_ptr->hold_life)
						{
							msg_print("You feel your life slipping away!");
							lose_exp(d/10);
						}
						else
						{
							msg_print("You feel your life draining away!");
							lose_exp(d);
						}
					}
					break;
				}

				case RBE_EXP_20:
				{
					/* Obvious */
					obvious = TRUE;

					/* Take damage */
					take_hit(damage, ddesc);

					if (p_ptr->hold_life && (rand_int(100) < 90))
					{
						msg_print("You keep hold of your life force!");
					}
					else
					{
						s32b d = damroll(20, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;

						if (p_ptr->hold_life)
						{
							msg_print("You feel your life slipping away!");
							lose_exp(d / 10);
						}
						else
						{
							msg_print("You feel your life draining away!");
							lose_exp(d);
						}
					}
					break;
				}

				case RBE_EXP_40:
				{
					/* Obvious */
					obvious = TRUE;

					/* Take damage */
					take_hit(damage, ddesc);

					if (p_ptr->hold_life && (rand_int(100) < 75))
					{
						msg_print("You keep hold of your life force!");
					}
					else
					{
						s32b d = damroll(40, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;

						if (p_ptr->hold_life)
						{
							msg_print("You feel your life slipping away!");
							lose_exp(d / 10);
						}
						else
						{
							msg_print("You feel your life draining away!");
							lose_exp(d);
						}
					}
					break;
				}

				case RBE_EXP_80:
				{
					/* Obvious */
					obvious = TRUE;

					/* Take damage */
					take_hit(damage, ddesc);

					if (p_ptr->hold_life && (rand_int(100) < 50))
					{
						msg_print("You keep hold of your life force!");
					}
					else
					{
						s32b d = damroll(80, 6) + (p_ptr->exp / 100) * MON_DRAIN_LIFE;

						if (p_ptr->hold_life)
						{
							msg_print("You feel your life slipping away!");
							lose_exp(d / 10);
						}
						else
						{
							msg_print("You feel your life draining away!");
							lose_exp(d);
						}
					}
					break;
				}

				case RBE_HALLU:
				{
					/* Take damage */
					take_hit(damage, ddesc);

					/* Increase "image" */
					if (!p_ptr->immune_conf)
					{
						if (set_image(p_ptr->image + 3 + randint(rlev / 2)))
						{
							obvious = TRUE;
						}
					}

					/* Learn about the player */
					update_smart_learn(m_idx, DRS_RES_CHAOS);

					break;
				}
			}


			/* Hack -- only one of cut or stun */
			if (do_cut && do_stun)
			{
				/* Cancel cut */
				if (rand_int(100) < 50)
				{
					do_cut = 0;
				}

				/* Cancel stun */
				else
				{
					do_stun = 0;
				}
			}

			/* Handle cut */
			if (do_cut)
			{
				int k;

				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(d_dice, d_side, damage);

				/* Roll for damage */
				switch (tmp)
				{
					case 0: k = 0; break;
					case 1: k = randint(5); break;
					case 2: k = randint(5) + 5; break;
					case 3: k = randint(20) + 20; break;
					case 4: k = randint(50) + 50; break;
					case 5: k = randint(100) + 100; break;
					case 6: k = 300; break;
					default: k = 500; break;
				}

				/* Apply the cut */
				if (k) (void)set_cut(p_ptr->cut + k);
			}

			/* Handle stun */
			if (do_stun)
			{
				int k;

				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(d_dice, d_side, damage);

				/* Roll for damage */
				switch (tmp)
				{
					case 0: k = 0; break;
					case 1: k = randint(5); break;
					case 2: k = randint(10) + 10; break;
					case 3: k = randint(20) + 20; break;
					case 4: k = randint(30) + 30; break;
					case 5: k = randint(40) + 40; break;
					case 6: k = 100; break;
					default: k = 200; break;
				}

				/* Apply the stun */
				if (k) (void)set_stun(p_ptr->stun + k);
			}
		}

		/* Monster missed player */
		else
		{
			/* Analyze failed attacks */
			switch (method)
			{
				case RBM_HIT:
				case RBM_TOUCH:
				case RBM_PUNCH:
				case RBM_KICK:
				case RBM_CLAW:
				case RBM_BITE:
				case RBM_STING:
				case RBM_XXX1:
				case RBM_BUTT:
				case RBM_CRUSH:
				case RBM_ENGULF:
				case RBM_XXX2:

				/* Visible monsters */
				if (m_ptr->ml)
				{
					/* Disturbing */
					disturb(1, 0);

					/* Message */
					msg_format("%^s misses you.", m_name);
				}

				break;
			}
		}


		/* Analyze "visible" monsters only */
		if (visible)
		{
			/* Count "obvious" attacks (and ones that cause damage) */
			if (obvious || damage || (l_ptr->blows[ap_cnt] > 10))
			{
				/* Count attacks of this type */
				if (l_ptr->blows[ap_cnt] < MAX_UCHAR)
				{
					l_ptr->blows[ap_cnt]++;
				}
			}
		}
	}


	/* Blink away */
	if (blinked)
	{
		msg_print("There is a puff of smoke!");
		teleport_away(m_idx, MAX_SIGHT * 2 + 5);
	}


	/* Always notice cause of death */
	if (p_ptr->is_dead && (l_ptr->deaths < MAX_SHORT))
	{
		l_ptr->deaths++;
	}


	/* Assume we attacked */
	return (TRUE);
}
Exemplo n.º 16
0
/*
 * Handle player hitting a real trap
 */
void hit_trap(int y, int x)
{
	int i, num, dam;

	const char *name = "a trap";


	/* Disturb the player */
	disturb(0, 0);

	/* Analyze XXX XXX XXX */
	switch (cave->feat[y][x])
	{
		case FEAT_TRAP_HEAD + 0x00:
		{
			msg("You fall through a trap door!");
			if (p_ptr->state.flags[OF_FEATHER])
			{
				msg("You float gently down to the next level.");
			}
			else
			{
				dam = damroll(2, 8);
				take_hit(dam, name);
			}
			wieldeds_notice_flag(OF_FEATHER);

			/* New depth */
			dungeon_change_level(p_ptr->depth + 1);
			
			break;
		}

		case FEAT_TRAP_HEAD + 0x01:
		{
			msg("You fall into a pit!");
			if (p_ptr->state.flags[OF_FEATHER])
			{
				msg("You float gently to the bottom of the pit.");
			}
			else
			{
				dam = damroll(2, 6);
				take_hit(dam, name);
			}
			wieldeds_notice_flag(OF_FEATHER);
			break;
		}

		case FEAT_TRAP_HEAD + 0x02:
		{
			msg("You fall into a spiked pit!");

			if (p_ptr->state.flags[OF_FEATHER])
			{
				msg("You float gently to the floor of the pit.");
				msg("You carefully avoid touching the spikes.");
			}
			else
			{
				/* Base damage */
				dam = damroll(2, 6);

				/* Extra spike damage */
				if (one_in_(2))
				{
					msg("You are impaled!");

					dam = dam * 2;
					(void)inc_timed(TMD_CUT, randint1(dam), TRUE);
				}

				/* Take the damage */
				take_hit(dam, name);
			}
			wieldeds_notice_flag(OF_FEATHER);
			break;
		}

		case FEAT_TRAP_HEAD + 0x03:
		{
			msg("You fall into a spiked pit!");

			if (p_ptr->state.flags[OF_FEATHER])
			{
				msg("You float gently to the floor of the pit.");
				msg("You carefully avoid touching the spikes.");
			}
			else
			{
				/* Base damage */
				dam = damroll(2, 6);

				/* Extra spike damage */
				if (one_in_(2))
				{
					msg("You are impaled on poisonous spikes!");

					dam = dam * 2;
					(void)inc_timed(TMD_CUT, randint1(dam), TRUE);

					if (p_ptr->state.flags[OF_RES_POIS] || p_ptr->timed[TMD_OPP_POIS])
					{
						msg("The poison does not affect you!");
					}
					else
					{
						dam = dam * 2;
						(void)inc_timed(TMD_POISONED, randint1(dam), TRUE);
					}

					wieldeds_notice_flag(OF_RES_POIS);
				}

				/* Take the damage */
				take_hit(dam, name);
			}
			wieldeds_notice_flag(OF_FEATHER);

			break;
		}

		case FEAT_TRAP_HEAD + 0x04:
		{
			sound(MSG_SUM_MONSTER);
			msg("You are enveloped in a cloud of smoke!");
			cave->info[y][x] &= ~(CAVE_MARK);
			cave_set_feat(cave, y, x, FEAT_FLOOR);
			num = 2 + randint1(3);
			for (i = 0; i < num; i++)
			{
				(void)summon_specific(y, x, p_ptr->depth, 0, 1);
			}
			break;
		}

		case FEAT_TRAP_HEAD + 0x05:
		{
			msg("You hit a teleport trap!");
			teleport_player(100);
			break;
		}

		case FEAT_TRAP_HEAD + 0x06:
		{
			msg("You are enveloped in flames!");
			dam = damroll(4, 6);
			fire_dam(dam, "a fire trap");
			break;
		}

		case FEAT_TRAP_HEAD + 0x07:
		{
			msg("You are splashed with acid!");
			dam = damroll(4, 6);
			acid_dam(dam, "an acid trap");
			break;
		}

		case FEAT_TRAP_HEAD + 0x08:
		{
			if (trap_check_hit(125))
			{
				msg("A small dart hits you!");
				dam = damroll(1, 4);
				take_hit(dam, name);
				(void)inc_timed(TMD_SLOW, randint0(20) + 20, TRUE);
			}
			else
			{
				msg("A small dart barely misses you.");
			}
			break;
		}

		case FEAT_TRAP_HEAD + 0x09:
		{
			if (trap_check_hit(125))
			{
				msg("A small dart hits you!");
				dam = damroll(1, 4);
				take_hit(dam, name);
				(void)do_dec_stat(A_STR, FALSE);
			}
			else
			{
				msg("A small dart barely misses you.");
			}
			break;
		}

		case FEAT_TRAP_HEAD + 0x0A:
		{
			if (trap_check_hit(125))
			{
				msg("A small dart hits you!");
				dam = damroll(1, 4);
				take_hit(dam, name);
				(void)do_dec_stat(A_DEX, FALSE);
			}
			else
			{
				msg("A small dart barely misses you.");
			}
			break;
		}

		case FEAT_TRAP_HEAD + 0x0B:
		{
			if (trap_check_hit(125))
			{
				msg("A small dart hits you!");
				dam = damroll(1, 4);
				take_hit(dam, name);
				(void)do_dec_stat(A_CON, FALSE);
			}
			else
			{
				msg("A small dart barely misses you.");
			}
			break;
		}

		case FEAT_TRAP_HEAD + 0x0C:
		{
			msg("You are surrounded by a black gas!");
			if (!p_ptr->state.flags[OF_RES_BLIND])
				(void)inc_timed(TMD_BLIND, randint0(50) + 25, TRUE);
			wieldeds_notice_flag(OF_RES_BLIND);

			break;
		}

		case FEAT_TRAP_HEAD + 0x0D:
		{
			msg("You are surrounded by a gas of scintillating colors!");
			if (!p_ptr->state.flags[OF_RES_CONFU])
				(void)inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);
			wieldeds_notice_flag(OF_RES_CONFU);

			break;
		}

		case FEAT_TRAP_HEAD + 0x0E:
		{
			msg("You are surrounded by a pungent green gas!");
			if (!p_ptr->state.flags[OF_RES_POIS] && !p_ptr->timed[TMD_OPP_POIS])
				(void)inc_timed(TMD_POISONED, randint0(20) + 10, TRUE);
			wieldeds_notice_flag(OF_RES_POIS);

			break;
		}

		case FEAT_TRAP_HEAD + 0x0F:
		{
			msg("You are surrounded by a strange white mist!");
			if (!p_ptr->state.flags[OF_FREE_ACT])
				(void)inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE);
			wieldeds_notice_flag(OF_FREE_ACT);

			break;
		}
	}
}
Exemplo n.º 17
0
/**
 * Attack the monster at the given location with a single blow.
 */
bool py_attack_real(int y, int x, bool *fear) {
	/* Information about the target of the attack */
	monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]);
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	char m_name[80];
	bool stop = FALSE;

	/* The weapon used */
	object_type *o_ptr = &p_ptr->inventory[INVEN_WIELD];

	/* Information about the attack */
	int bonus = p_ptr->state.to_h + o_ptr->to_h;
	int chance = p_ptr->state.skills[SKILL_TO_HIT_MELEE] + bonus * BTH_PLUS_ADJ;
	bool do_quake = FALSE;
	bool success = FALSE;

	/* Default to punching for one damage */
	const char *hit_verb = "punch";
	int dmg = 1;
	u32b msg_type = MSG_HIT;

	/* Extract monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0);

	/* Auto-Recall if possible and visible */
	if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

	/* Track a new monster */
	if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]);

	/* Handle player fear (only for invisible monsters) */
	if (p_ptr->state.flags[OF_AFRAID]) {
		msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name);
		return FALSE;
	}

	/* Disturb the monster */
	mon_clear_timed(cave->m_idx[y][x], MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE);

	/* See if the player hit */
	success = test_hit(chance, r_ptr->ac, m_ptr->ml);

	/* If a miss, skip this hit */
	if (!success) {
		msgt(MSG_MISS, "You miss %s.", m_name);
		return FALSE;
	}

	/* Handle normal weapon */
	if (o_ptr->kind) {
		int i;
		const struct slay *best_s_ptr = NULL;

		hit_verb = "hit";

		/* Get the best attack from all slays or
		 * brands on all non-launcher equipment */
		for (i = INVEN_LEFT; i < INVEN_TOTAL; i++) {
			struct object *obj = &p_ptr->inventory[i];
			if (obj->kind)
				improve_attack_modifier(obj, m_ptr, &best_s_ptr, TRUE, FALSE);
		}

		improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr, TRUE, FALSE);
		if (best_s_ptr != NULL)
			hit_verb = best_s_ptr->melee_verb;

		dmg = damroll(o_ptr->dd, o_ptr->ds);
		dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult;

		dmg += o_ptr->to_d;
		dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type);

		/* Learn by use for the weapon */
		object_notice_attack_plusses(o_ptr);

		if (p_ptr->state.flags[OF_IMPACT] && dmg > 50) {
			do_quake = TRUE;
			wieldeds_notice_flag(OF_IMPACT);
		}
	}

	/* Learn by use for other equipped items */
	wieldeds_notice_offweapon_attack_plusses();

	/* Apply the player damage bonuses */
	dmg += p_ptr->state.to_d;

	/* No negative damage */
	if (dmg <= 0) dmg = 0;

	/* Tell the player what happened */
	if (dmg <= 0)
		msgt(MSG_MISS, "You fail to harm %s.", m_name);
	else if (msg_type == MSG_HIT)
		msgt(MSG_HIT, "You %s %s.", hit_verb, m_name);
	else if (msg_type == MSG_HIT_GOOD)
		msgt(MSG_HIT_GOOD, "You %s %s. %s", hit_verb, m_name, "It was a good hit!");
	else if (msg_type == MSG_HIT_GREAT)
		msgt(MSG_HIT_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a great hit!");
	else if (msg_type == MSG_HIT_SUPERB)
		msgt(MSG_HIT_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a superb hit!");
	else if (msg_type == MSG_HIT_HI_GREAT)
		msgt(MSG_HIT_HI_GREAT, "You %s %s. %s", hit_verb, m_name, "It was a *GREAT* hit!");
	else if (msg_type == MSG_HIT_HI_SUPERB)
		msgt(MSG_HIT_HI_SUPERB, "You %s %s. %s", hit_verb, m_name, "It was a *SUPERB* hit!");

	/* Complex message */
	if (p_ptr->wizard)
		msg("You do %d (out of %d) damage.", dmg, m_ptr->hp);

	/* Confusion attack */
	if (p_ptr->confusing) {
		p_ptr->confusing = FALSE;
		msg("Your hands stop glowing.");

		mon_inc_timed(cave->m_idx[y][x], MON_TMD_CONF,
				(10 + randint0(p_ptr->lev) / 10), MON_TMD_FLG_NOTIFY);
	}

	/* Damage, check for fear and death */
	stop = mon_take_hit(cave->m_idx[y][x], dmg, fear, NULL);

	if (stop)
		(*fear) = FALSE;

	/* Apply earthquake brand */
	if (do_quake) {
		earthquake(p_ptr->py, p_ptr->px, 10);
		if (cave->m_idx[y][x] == 0) stop = TRUE;
	}

	return stop;
}
Exemplo n.º 18
0
/*
 * Throw an object from the pack or floor.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Should throwing a weapon do full damage?  Should it allow the magic
 * to hit bonus of the weapon to have an effect?  Should it ever cause
 * the item to be destroyed?  Should it do any damage at all?
 */
void do_cmd_throw(cmd_code code, cmd_arg args[])
{
	int dir, item;
	int i, j, y, x;
	s16b ty, tx;
	int chance, tdam, tdis;
	int weight;

	object_type *o_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	bool hit_body = FALSE;

	byte missile_attr;
	char missile_char;

	char o_name[80];

	u32b msg_type = 0;

	int path_n;
	u16b path_g[256];

	int msec = op_ptr->delay_factor * op_ptr->delay_factor;

	/* Get item to throw and direction in which to throw it. */
	item = args[0].item;
	dir = args[1].direction;

	/* Make sure the player isn't throwing wielded items */
	if (item >= INVEN_WIELD && item < QUIVER_START)
	{
		msg_print("You have cannot throw wielded items.");
		return;
	}

	/* Check the item being thrown is usable by the player. */
	if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
	{
		msg_format("That item is not within your reach.");
		return;
	}

	/* Get the object */
	o_ptr = object_from_item_idx(item);
	object_notice_on_firing(o_ptr);

	/* Get local object */
	i_ptr = &object_type_body;

	/* Obtain a local object */
	object_copy(i_ptr, o_ptr);

	/* Distribute the charges of rods/wands/staves between the stacks */
	distribute_charges(o_ptr, i_ptr, 1);

	/* Single object */
	i_ptr->number = 1;

	/* Reduce and describe inventory */
	if (item >= 0)
	{
		inven_item_increase(item, -1);
		inven_item_describe(item);
		inven_item_optimize(item);
	}

	/* Reduce and describe floor item */
	else
	{
		floor_item_increase(0 - item, -1);
		floor_item_optimize(0 - item);
	}


	/* Description */
	object_desc(o_name, sizeof(o_name), i_ptr, ODESC_FULL);

	/* Find the color and symbol for the object for throwing */
	missile_attr = object_attr(i_ptr);
	missile_char = object_char(i_ptr);


	/* Enforce a minimum "weight" of one pound */
	weight = ((i_ptr->weight > 10) ? i_ptr->weight : 10);

	/* Hack -- Distance -- Reward strength, penalize weight */
	tdis = (adj_str_blow[p_ptr->state.stat_ind[A_STR]] + 20) * 10 / weight;

	/* Max distance of 10 */
	if (tdis > 10) tdis = 10;

	/* Hack -- Base damage from thrown object */
	tdam = damroll(i_ptr->dd, i_ptr->ds);
	if (!tdam) tdam = 1;
	tdam += i_ptr->to_d;

	/* Chance of hitting */
	chance = (p_ptr->state.skills[SKILL_TO_HIT_THROW] + (p_ptr->state.to_h * BTH_PLUS_ADJ));


	/* Take a turn */
	p_ptr->energy_use = 100;


	/* Start at the player */
	y = p_ptr->py;
	x = p_ptr->px;

	/* Predict the "target" location */
	ty = p_ptr->py + 99 * ddy[dir];
	tx = p_ptr->px + 99 * ddx[dir];

	/* Check for "target request" */
	if ((dir == 5) && target_okay())
	{
		target_get(&tx, &ty);
	}

	/* Calculate the path */
	path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0);


	/* Hack -- Handle stuff */
	handle_stuff();

	/* Project along the path */
	for (i = 0; i < path_n; ++i)
	{
		int ny = GRID_Y(path_g[i]);
		int nx = GRID_X(path_g[i]);

		/* Hack -- Stop before hitting walls */
		if (!cave_floor_bold(ny, nx)) break;

		/* Advance */
		x = nx;
		y = ny;

		/* Only do visuals if the player can "see" the missile */
		if (player_can_see_bold(y, x))
		{
			/* Visual effects */
			print_rel(missile_char, missile_attr, y, x);
			move_cursor_relative(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();

			Term_xtra(TERM_XTRA_DELAY, msec);
			light_spot(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();
		}

		/* Delay anyway for consistency */
		else
		{
			/* Pause anyway, for consistancy */
			Term_xtra(TERM_XTRA_DELAY, msec);
		}

		/* Handle monster */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x);

			int visible = m_ptr->ml;

			/* Note the collision */
			hit_body = TRUE;

			/* Did we hit it (penalize range) */
			if (test_hit(chance2, r_ptr->ac, m_ptr->ml))
			{
				const char *hit_verb = "hits";
				bool fear = FALSE;
				const slay_t *best_s_ptr = NULL;

				/* Assume a default death */
				cptr note_dies = " dies.";

				/* Some monsters get "destroyed" */
				if (monster_is_unusual(r_ptr))
				{
					/* Special note at death */
					note_dies = " is destroyed.";
				}

				/* Apply special damage  - brought forward to fill in hit_verb XXX XXX XXX */
				improve_attack_modifier(i_ptr, m_ptr, &best_s_ptr);
				if (best_s_ptr != NULL)
				{
					tdam *= best_s_ptr->mult;
					hit_verb = best_s_ptr->range_verb;
				}
				/* Apply special damage XXX XXX XXX */
				tdam = critical_shot(i_ptr->weight, i_ptr->to_h, tdam, &msg_type);

				/* No negative damage; change verb if no damage done */
				if (tdam <= 0)
				{
					tdam = 0;
					hit_verb = "fail to harm";
				}

				/* Handle unseen monster */
				if (!visible)
				{
					/* Invisible monster */
					msg_format("The %s finds a mark.", o_name);
				}

				/* Handle visible monster */
				else
				{
					char m_name[80];

					/* Get "the monster" or "it" */
					monster_desc(m_name, sizeof(m_name), m_ptr, 0);

					/* Tell the player what happened */
					if (msg_type == MSG_SHOOT_HIT)
						message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name);
					else
					{
						if (msg_type == MSG_HIT_GOOD)
						{
							message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a good hit!");
						}
						else if (msg_type == MSG_HIT_GREAT)
						{
							message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a great hit!");
						}
						else if (msg_type == MSG_HIT_SUPERB)
						{
							message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a superb hit!");
						}
					}
					/* Hack -- Track this monster race */
					if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

					/* Hack -- Track this monster */
					if (m_ptr->ml) health_track(cave_m_idx[y][x]);
				}

				/* Learn the bonuses */
				/* XXX Eddie This is messed up, better done for firing, */
				/* should use that method [split last] instead */
				/* check if inven_optimize removed what o_ptr referenced */
				if (object_similar(i_ptr, o_ptr, OSTACK_PACK))
					object_notice_attack_plusses(o_ptr);
				object_notice_attack_plusses(i_ptr);

				/* Complex message */
				if (p_ptr->wizard)
					msg_format("You do %d (out of %d) damage.",
							   tdam, m_ptr->hp);

				/* Hit the monster, check for death */
				if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies))
				{
					/* Dead monster */
				}

				/* No death */
				else
				{
					/* Message */
					message_pain(cave_m_idx[y][x], tdam);

					/* Take note */
					if (fear && m_ptr->ml)
					{
						char m_name[80];

						/* Get the monster name (or "it") */
						monster_desc(m_name, sizeof(m_name), m_ptr, 0);

						/* Message */
						message_format(MSG_FLEE, m_ptr->r_idx,
						               "%^s flees in terror!", m_name);
					}
				}
			}

			/* Stop looking */
			break;
		}
	}

	/* Chance of breakage (during attacks) */
	j = (hit_body ? breakage_chance(i_ptr) : 0);

	/* Drop (or break) near that location */
	drop_near(i_ptr, j, y, x, TRUE);
}
Exemplo n.º 19
0
/**
 * Handle things that need updating once every 10 game turns
 */
void process_world(struct chunk *c)
{
	int i, y, x;

	/* Compact the monster list if we're approaching the limit */
	if (cave_monster_count(cave) + 32 > z_info->level_monster_max)
		compact_monsters(64);

	/* Too many holes in the monster list - compress */
	if (cave_monster_count(cave) + 32 < cave_monster_max(cave))
		compact_monsters(0);

	/*** Check the Time ***/

	/* Play an ambient sound at regular intervals. */
	if (!(turn % ((10L * z_info->day_length) / 4)))
		play_ambient_sound();

	/*** Handle stores and sunshine ***/

	if (!player->depth) {
		/* Daybreak/Nighfall in town */
		if (!(turn % ((10L * z_info->day_length) / 2))) {
			bool dawn;

			/* Check for dawn */
			dawn = (!(turn % (10L * z_info->day_length)));

			/* Day breaks */
			if (dawn)
				msg("The sun has risen.");

			/* Night falls */
			else
				msg("The sun has fallen.");

			/* Illuminate */
			cave_illuminate(c, dawn);
		}
	} else {
		/* Update the stores once a day (while in the dungeon).
		   The changes are not actually made until return to town,
		   to avoid giving details away in the knowledge menu. */
		if (!(turn % (10L * z_info->store_turns))) daycount++;
	}


	/* Check for creature generation */
	if (one_in_(z_info->alloc_monster_chance))
		(void)pick_and_place_distant_monster(cave, loc(player->px, player->py),
											 z_info->max_sight + 5, true,
											 player->depth);

	/*** Damage over Time ***/

	/* Take damage from poison */
	if (player->timed[TMD_POISONED])
		take_hit(player, 1, "poison");

	/* Take damage from cuts */
	if (player->timed[TMD_CUT]) {
		/* Mortal wound or Deep Gash */
		if (player->timed[TMD_CUT] > TMD_CUT_SEVERE)
			i = 3;

		/* Severe cut */
		else if (player->timed[TMD_CUT] > TMD_CUT_NASTY)
			i = 2;

		/* Other cuts */
		else
			i = 1;

		/* Take damage */
		take_hit(player, i, "a fatal wound");
	}


	/*** Check the Food, and Regenerate ***/

	/* Digest normally */
	if (!(turn % 100)) {
		/* Basic digestion rate based on speed */
		i = turn_energy(player->state.speed) * 2;

		/* Regeneration takes more food */
		if (player_of_has(player, OF_REGEN)) i += 30;

		/* Slow digestion takes less food */
		if (player_of_has(player, OF_SLOW_DIGEST)) i /= 5;

		/* Minimal digestion */
		if (i < 1) i = 1;

		/* Digest some food */
		player_set_food(player, player->food - i);
	}

	/* Getting Faint */
	if (player->food < PY_FOOD_FAINT) {
		/* Faint occasionally */
		if (!player->timed[TMD_PARALYZED] && one_in_(10)) {
			/* Message */
			msg("You faint from the lack of food.");
			disturb(player, 1);

			/* Faint (bypass free action) */
			(void)player_inc_timed(player, TMD_PARALYZED, 1 + randint0(5),
								   true, false);
		}
	}

	/* Starve to death (slowly) */
	if (player->food < PY_FOOD_STARVE) {
		/* Calculate damage */
		i = (PY_FOOD_STARVE - player->food) / 10;

		/* Take damage */
		take_hit(player, i, "starvation");
	}

	/* Regenerate Hit Points if needed */
	if (player->chp < player->mhp)
		player_regen_hp();

	/* Regenerate mana if needed */
	if (player->csp < player->msp)
		player_regen_mana();

	/* Timeout various things */
	decrease_timeouts();

	/* Process light */
	player_update_light();


	/*** Process Inventory ***/

	/* Handle experience draining */
	if (player_of_has(player, OF_DRAIN_EXP)) {
		if ((player->exp > 0) && one_in_(10)) {
			s32b d = damroll(10, 6) +
				(player->exp / 100) * z_info->life_drain_percent;
			player_exp_lose(player, d / 10, false);
		}

		equip_learn_flag(player, OF_DRAIN_EXP);
	}

	/* Recharge activatable objects and rods */
	recharge_objects();

	/* Notice things after time */
	if (!(turn % 100))
		equip_learn_after_time(player);

	/* Decrease trap timeouts */
	for (y = 0; y < cave->height; y++) {
		for (x = 0; x < cave->width; x++) {
			struct trap *trap = cave->squares[y][x].trap;
			while (trap) {
				if (trap->timeout) {
					trap->timeout--;
					if (!trap->timeout)
						square_light_spot(cave, y, x);
				}
				trap = trap->next;
			}
		}
	}


	/*** Involuntary Movement ***/

	/* Delayed Word-of-Recall */
	if (player->word_recall) {
		/* Count down towards recall */
		player->word_recall--;

		/* Activate the recall */
		if (!player->word_recall) {
			/* Disturbing! */
			disturb(player, 0);

			/* Determine the level */
			if (player->depth) {
				msgt(MSG_TPLEVEL, "You feel yourself yanked upwards!");
				dungeon_change_level(0);
			} else {
				msgt(MSG_TPLEVEL, "You feel yourself yanked downwards!");
                
                /* Force descent to a lower level if allowed */
                if (OPT(birth_force_descend) &&
					player->max_depth < z_info->max_depth - 1 &&
					!is_quest(player->max_depth)) {
                    player->max_depth = dungeon_get_next_level(player->max_depth, 1);
                }

				/* New depth - back to max depth or 1, whichever is deeper */
				dungeon_change_level(player->max_depth < 1 ? 1: player->max_depth);
			}
		}
	}

	/* Delayed Deep Descent */
	if (player->deep_descent) {
		/* Count down towards recall */
		player->deep_descent--;

		/* Activate the recall */
		if (player->deep_descent == 0) {
			int target_increment;
			int target_depth = player->max_depth;

			/* Calculate target depth */
			target_increment = (4 / z_info->stair_skip) + 1;
			target_depth = dungeon_get_next_level(player->max_depth, target_increment);

			disturb(player, 0);

			/* Determine the level */
			if (target_depth > player->depth) {
				msgt(MSG_TPLEVEL, "The floor opens beneath you!");
				dungeon_change_level(target_depth);
			} else {
				/* Otherwise do something disastrous */
				msgt(MSG_TPLEVEL, "You are thrown back in an explosion!");
				effect_simple(EF_DESTRUCTION, "0", 0, 5, 0, NULL);
			}		
		}
	}
}
Exemplo n.º 20
0
/*
 * Attack the monster at the given location
 *
 * If no "weapon" is available, then "punch" the monster one time.
 *
 * We get blows until energy drops below that required for another blow, or
 * until the target monster dies. We use a wrapper to work out the number of
 * blows. We don't allow @ to spend more than 100 energy in one go, to avoid
 * slower monsters getting double moves.
 */
bool py_attack_real(int y, int x)
{
	int bonus, chance;

	monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	object_type *o_ptr;

	char m_name[80];

	bool fear = FALSE;

	bool do_quake = FALSE;
	bool dead = FALSE;

	u32b msg_type = 0;
	bool success = FALSE;
	
	const char *hit_verb = "ERROR";
	int dmg = 1;
	
	/* Default to punching for one damage */
	/* Maybe handle monster melee here -Simon */
	if(!rp_ptr->p_monster_index)
	{
		hit_verb = "punch";
		msg_type = MSG_HIT;
	}

	/*
	 * Hack -- if advanced innate attacks are disabled for this race, fall back
	 * on defaults <player>'s 1d1.
	 */
	 /* TODO: this -Simon */
	/* if (p_ptr->flags[NO_INNATE])
	{
			p_ptr = &r_info[0];
	} */


	/* Extract monster name (or "it") */
	monster_desc(m_name, sizeof(m_name), m_ptr, 0);

	/* Auto-Recall if possible and visible */
	if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

	/* Track a new monster */
	if (m_ptr->ml) health_track(cave_m_idx[y][x]);

	/* Handle player fear (only for invisible monsters) */
	if (p_ptr->state.afraid)
	{
		message_format(MSG_AFRAID, 0,
				"You are too afraid to attack %s!",
				m_name);
		return (FALSE);
	}

	/* Disturb the monster */
	wake_monster(m_ptr);

	/* Get the weapon */
	o_ptr = &p_ptr->inventory[INVEN_WIELD];
	
		/* Calculate the "attack quality" */
	bonus = p_ptr->state.to_h + o_ptr->to_h;
	chance = (p_ptr->state.skills[SKILL_TO_HIT_MELEE] + (bonus * BTH_PLUS_ADJ));

	/* Handle innate melee -Simon */
	if(!o_ptr->k_idx && rp_ptr->p_monster_index)
	{
		for (int num = 0; (num < MONSTER_BLOW_MAX) && !dead; num++)
		{
			const slay_t *best_s_ptr = NULL;
			int type = GF_ARROW, type2 = 0, i;
			int flg = PROJECT_KILL | PROJECT_STOP | PROJECT_HIDE; // | PROJECT_PASS; TODO: figure out what this is and implement it -Simon
			char *p = "";
						
			if (!r_info[rp_ptr->p_monster_index].blow[num].method && !dead)
				continue;
					
			/* Test for hit */
			if (test_hit(chance, r_info[m_ptr->r_idx].ac, m_ptr->ml))
			{
				int mul = 1;
				int k = 0;
				
				/* Get the method */
				switch (r_info[rp_ptr->p_monster_index].blow[num].method)
				{
					case RBM_HIT:	p = "hit"; break;
					case RBM_TOUCH:	p = "touch"; break;
					case RBM_PUNCH:	p = "punch"; break;
					case RBM_KICK:	p = "kick"; break;
					case RBM_CLAW:	p = "claw"; break;
					case RBM_BITE:	p = "bite"; break;
					case RBM_STING:	p = "sting"; break;
					case RBM_BUTT:	p = "butt"; break;
					case RBM_CRUSH:	p = "crush"; break;
					case RBM_ENGULF:p = "engulf"; break;
					case RBM_PECK:	p = "peck"; break;
					case RBM_CRAWL:	p = "crawl on"; break;
					case RBM_DROOL:	p = "drool on"; break;
					case RBM_SPIT:	p = "spit on"; break;
					case RBM_SLIME:	p = "slime"; break;
					case RBM_GAZE:	p = "gaze at"; break;
					case RBM_WAIL:	p = "wail at"; break;
					case RBM_SPORE:	p = "release spores at"; break;
					case RBM_BEG:	p = "beg for money"; break;
					case RBM_INSULT:	p = "insult"; break;
					default: p = "attack";
				}

				/* Get the effect */
				switch (r_info[rp_ptr->p_monster_index].blow[num].effect)
				{
					case RBE_HURT: type = GF_ARROW; break;
					case RBE_DISEASE: type = GF_POIS; mul = 2; break;
					case RBE_POISON: type = GF_POIS; mul = 2; break;
					case RBE_LOSE_MANA: type = GF_DISENCHANT; break;
					case RBE_UN_BONUS: type = GF_DISENCHANT; mul = 2; break;
					case RBE_UN_POWER: type = GF_DISENCHANT; mul = 2; break; /* ? */
					case RBE_EAT_LIGHT: type = GF_DARK; mul = 2; break;
					case RBE_ACID: type = GF_ACID; mul = 2; break;
					case RBE_ELEC: type = GF_ELEC; mul = 2; break;
					case RBE_FIRE: type = GF_FIRE; mul = 2; break;
					case RBE_COLD: type = GF_COLD; mul = 2; break;
					case RBE_BLIND: type2 = GF_OLD_CONF; break; /* ? */
					case RBE_CONFUSE: type2 = GF_OLD_CONF; break;
					case RBE_TERRIFY: type2 = GF_TURN_ALL; break; /* ? */
					case RBE_PARALYZE: type2 = GF_OLD_SLEEP; break; /* ? */
					/* Earthquake would be natural, but all monsters
					 * with RBE_SHATTER are already humanoids
					 */
					case RBE_SHATTER: type = GF_ARROW; break;
					case RBE_EXP_10: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_20: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_40: type = GF_NETHER; mul = 2; break;
					case RBE_EXP_80: type = GF_NETHER; mul = 2; break;
					/* GF_CHAOS will polymorph, so it is bad */
					case RBE_HALLU: type = GF_DISENCHANT; mul = 2; break;
					default: type = GF_ARROW;
				}
			
				k = damroll(r_info[rp_ptr->p_monster_index].blow[num].d_dice, r_info[rp_ptr->p_monster_index].blow[num].d_side);
				/* Get the best attack from all slays or
				 * brands on all non-launcher equipment */
				for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
					improve_attack_modifier(&p_ptr->inventory[i], m_ptr, &best_s_ptr);
					
				if (best_s_ptr != NULL)
				{
					if (best_s_ptr->mult > mul)
					{
						p = best_s_ptr->melee_verb;
						mul = best_s_ptr->mult;
						if (best_s_ptr->resist_flag == RF_IM_ACID)
							type = GF_ACID;
						else if (best_s_ptr->resist_flag == RF_IM_ELEC)
							type = GF_ELEC;
						else if (best_s_ptr->resist_flag == RF_IM_FIRE)
							type = GF_FIRE;
						else if (best_s_ptr->resist_flag == RF_IM_COLD)
							type = GF_COLD;
						else if (best_s_ptr->resist_flag == RF_IM_POIS)
							type = GF_POIS;
					}
				}
				
				k *= mul;
				message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.", p, m_name);
				/* Add to-dam bonus only if did some damage */
				if (k) k += p_ptr->state.to_d;
				if (k < 0) k = 0;
				
				/* Learn by use for other equipped items */
				wieldeds_notice_on_attack();
					
				/* If there is an extra effect, project it also, using 4*level as power */
				if (type2)
				{
					project(-1, 0, y, x, 4 * p_ptr->lev, type2, flg);
				}
							       
				/* Confusion attack */
				if (p_ptr->confusing)
				{
					/* Message */
					if (p_ptr->confusing)
						msg_print("Your limbs stop glowing.");
				
					/* Cancel glowing hands */
					p_ptr->confusing = FALSE;

					/* Confuse the monster */
					if (rf_has(r_ptr->flags, RF_NO_CONF))
					{
						if (m_ptr->ml)
						{
							rf_on(l_ptr->flags, RF_NO_CONF);
						}
						msg_format("%^s is unaffected.", m_name);
					}
					else if (randint0(100) < r_ptr->level)
					{
						msg_format("%^s appears slightly perplexed.", m_name);
					}
					else
					{
						msg_format("%^s appears confused.", m_name);
						m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
					}
				}
				
				/* Damage, check for fear and death */
				/* Makes elemental attacks do half their damage physically -Simon */
				if (type != GF_ARROW)
				{
					project(-1, 0, y, x, (k + 1)/2, type, flg);
					/* Make the physical portion TOP SECRET -Simon */
					flg &= ~(PROJECT_AWARE);
					project(-1, 0, y, x, k/2, GF_ARROW, flg);
				}
				else
					project(-1, 0, y, x, k, type, flg);
				/* Hack: check if the square is empty after we project the attack into it -Simon */
				dead = (cave_m_idx[y][x] == 0);
			
				/* Hack -- delay fear messages */
				if (fear && m_ptr->ml && !dead)
					message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name);
			}
			/* Player misses */
			else
			{
				/* Message */
				message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);
			}
		}	
		return (TRUE);
	}
	
	else
	{
		/* See if the player hit */
		success = test_hit(chance, r_ptr->ac, m_ptr->ml);

		/* If a miss, skip this hit */
		if (!success)
		{
			message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);
			return (FALSE);
		}

		/* Handle normal weapon */
		if (o_ptr->k_idx)
		{
			int i;
			const slay_t *best_s_ptr = NULL;

			hit_verb = "hit";

			/* Get the best attack from all slays or
			 * brands on all non-launcher equipment */
			for (i = INVEN_FINGER; i < INVEN_TOTAL; i++)
				improve_attack_modifier(&p_ptr->inventory[i], m_ptr,
				&best_s_ptr);

			improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr);
			if (best_s_ptr != NULL)
				hit_verb = best_s_ptr->melee_verb;

			dmg = damroll(o_ptr->dd, o_ptr->ds);
			dmg *= (best_s_ptr == NULL) ? 1 : best_s_ptr->mult;

			if (p_ptr->state.impact && (dmg > 50))
				do_quake = TRUE;

			dmg += o_ptr->to_d;
			dmg = critical_norm(o_ptr->weight, o_ptr->to_h, dmg, &msg_type);

			/* Learn by use for the weapon */
			object_notice_attack_plusses(o_ptr);

			if (do_quake)
				wieldeds_notice_flag(OF_IMPACT);
		}

		/* Learn by use for other equipped items */
		wieldeds_notice_on_attack();

		/* Apply the player damage bonuses */
		dmg += p_ptr->state.to_d;

		/* No negative damage */
		if (dmg <= 0) dmg = 0;

		/* Tell the player what happened */
		if (dmg <= 0)
			message_format(MSG_MISS, m_ptr->r_idx,
						   "You fail to harm %s.", m_name);
		else if (msg_type == MSG_HIT)
			message_format(MSG_HIT, m_ptr->r_idx, "You %s %s.",
						   hit_verb, m_name);
		else if (msg_type == MSG_HIT_GOOD)
			message_format(MSG_HIT_GOOD, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a good hit!");
		else if (msg_type == MSG_HIT_GREAT)
			message_format(MSG_HIT_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a great hit!");
		else if (msg_type == MSG_HIT_SUPERB)
			message_format(MSG_HIT_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a superb hit!");
		else if (msg_type == MSG_HIT_HI_GREAT)
			message_format(MSG_HIT_HI_GREAT, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *GREAT* hit!");
		else if (msg_type == MSG_HIT_HI_SUPERB)
			message_format(MSG_HIT_HI_SUPERB, m_ptr->r_idx, "You %s %s. %s",
						   hit_verb, m_name, "It was a *SUPERB* hit!");

		/* Complex message */
		if (p_ptr->wizard)
			msg_format("You do %d (out of %d) damage.", dmg, m_ptr->hp);

		/* Confusion attack */
		if (p_ptr->confusing)
		{
			/* Cancel glowing hands */
			p_ptr->confusing = FALSE;

			/* Message */
			msg_print("Your limbs stop glowing.");

			/* Update the lore */
			if (m_ptr->ml)
				rf_on(l_ptr->flags, RF_NO_CONF);

			/* Confuse the monster */
			if (rf_has(r_ptr->flags, RF_NO_CONF))
				msg_format("%^s is unaffected.", m_name);
			else if (randint0(100) < r_ptr->level)
				msg_format("%^s is unaffected.", m_name);
			else
			{
				msg_format("%^s appears confused.", m_name);
				m_ptr->confused += 10 + randint0(p_ptr->lev) / 5;
			}
		}

		/* Damage, check for fear and death */
		dead = mon_take_hit(cave_m_idx[y][x], dmg, &fear, NULL);

		/* Hack -- delay fear messages */
		if (fear && m_ptr->ml)
			message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!",
			m_name);

		/* Mega-Hack -- apply earthquake brand */
		if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10);

		return (dead);
	}
}
Exemplo n.º 21
0
/*
 * The "wonder" effect.
 *
 * Returns TRUE if the effect is evident.
 */
bool effect_wonder(int dir, int die, int beam)
{
/* This spell should become more useful (more
   controlled) as the player gains experience levels.
   Thus, add 1/5 of the player's level to the die roll.
   This eliminates the worst effects later on, while
   keeping the results quite random.  It also allows
   some potent effects only at high level. */

	bool visible = FALSE;
	int py = p_ptr->py;
	int px = p_ptr->px;
	int plev = p_ptr->lev;

	if (die > 100)
	{
		/* above 100 the effect is always visible */
		msg("You feel a surge of power!");
		visible = TRUE;
	}

	if (die < 8) visible = clone_monster(dir);
	else if (die < 14) visible = speed_monster(dir);
	else if (die < 26) visible = heal_monster(dir);
	else if (die < 31) visible = poly_monster(dir);
	else if (die < 36)
		visible = fire_bolt_or_beam(beam - 10, GF_MISSILE, dir,
		                            damroll(3 + ((plev - 1) / 5), 4));
	else if (die < 41) visible = confuse_monster(dir, plev, FALSE);
	else if (die < 46) visible = fire_ball(GF_POIS, dir, 20 + (plev / 2), 3);
	else if (die < 51) visible = light_line(dir);
	else if (die < 56)
		visible = fire_beam(GF_ELEC, dir, damroll(3+((plev-5)/6), 6));
	else if (die < 61)
		visible = fire_bolt_or_beam(beam-10, GF_COLD, dir,
		                            damroll(5+((plev-5)/4), 8));
	else if (die < 66)
		visible = fire_bolt_or_beam(beam, GF_ACID, dir,
		                            damroll(6+((plev-5)/4), 8));
	else if (die < 71)
		visible = fire_bolt_or_beam(beam, GF_FIRE, dir,
		                            damroll(8+((plev-5)/4), 8));
	else if (die < 76) visible = drain_life(dir, 75);
	else if (die < 81) visible = fire_ball(GF_ELEC, dir, 30 + plev / 2, 2);
	else if (die < 86) visible = fire_ball(GF_ACID, dir, 40 + plev, 2);
	else if (die < 91) visible = fire_ball(GF_ICE, dir, 70 + plev, 3);
	else if (die < 96) visible = fire_ball(GF_FIRE, dir, 80 + plev, 3);
	/* above 100 'visible' is already true */
	else if (die < 101) drain_life(dir, 100 + plev);
	else if (die < 104) earthquake(py, px, 12);
	else if (die < 106) destroy_area(py, px, 15, TRUE);
	else if (die < 108) banishment();
	else if (die < 110) dispel_monsters(120);
	else /* RARE */
	{
		dispel_monsters(150);
		slow_monsters();
		sleep_monsters(TRUE);
		hp_player(300);
	}

	return visible;
}
Exemplo n.º 22
0
/*
 * Fire an object from the pack or floor.
 *
 * You may only fire items that "match" your missile launcher.
 *
 * See "calc_bonuses()" for more calculations and such.
 *
 * Note that "firing" a missile is MUCH better than "throwing" it.
 *
 * Note: "unseen" monsters are very hard to hit.
 *
 * Objects are more likely to break if they "attempt" to hit a monster.
 *
 * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.
 * The "extra shot" code works by decreasing the amount of energy
 * required to make each shot, spreading the shots out over time.
 *
 * Note that when firing missiles, the launcher multiplier is applied
 * after all the bonuses are added in, making multipliers very useful.
 *
 * Note that Bows of "Extra Might" get extra range and an extra bonus
 * for the damage multiplier.
 */
void do_cmd_fire(cmd_code code, cmd_arg args[])
{
	int dir, item;
	int i, j, y, x;
	s16b ty, tx;
	int tdam, tdis, thits;
	int bonus, chance;

	object_type *o_ptr;
	object_type *j_ptr;

	object_type *i_ptr;
	object_type object_type_body;

	bool hit_body = FALSE;

	byte missile_attr;
	char missile_char;

	char o_name[80];

	u32b msg_type = 0;

	int path_n;
	u16b path_g[256];

	int msec = op_ptr->delay_factor * op_ptr->delay_factor;

	/* Get the "bow" */
	j_ptr = &p_ptr->inventory[INVEN_BOW];

	/* Require a usable launcher */
	if (!j_ptr->tval || !p_ptr->state.ammo_tval)
	{
		msg_print("You have nothing to fire with.");
		return;
	}

	/* Get item to fire and direction to fire in. */
	item = args[0].item;
	dir = args[1].direction;

	/* Check the item being fired is usable by the player. */
	if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR)))
	{
		msg_format("That item is not within your reach.");
		return;
	}

	/* Get the object for the ammo */
	o_ptr = object_from_item_idx(item);

	/* Check the ammo can be used with the launcher */
	if (o_ptr->tval != p_ptr->state.ammo_tval)
	{
		msg_format("That ammo cannot be fired by your current weapon.");
		return;
	}

	/* Base range XXX XXX */
	tdis = 6 + 2 * p_ptr->state.ammo_mult;

	/* Start at the player */
	x = p_ptr->px;
	y = p_ptr->py;

	/* Predict the "target" location */
	ty = y + 99 * ddy[dir];
	tx = x + 99 * ddx[dir];

	/* Check for target validity */
	if ((dir == 5) && target_okay())
	{
		target_get(&tx, &ty);
		if (distance(y, x, ty, tx) > tdis)
		{
			if (!get_check("Target out of range.  Fire anyway? "))
				return;
		}
	}

	/* Sound */
	sound(MSG_SHOOT);

	object_notice_on_firing(o_ptr);

	/* Describe the object */
	object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR);

	/* Find the color and symbol for the object for throwing */
	missile_attr = object_attr(o_ptr);
	missile_char = object_char(o_ptr);

	/* Use the proper number of shots */
	thits = p_ptr->state.num_fire;

	/* Actually "fire" the object */
	bonus = (p_ptr->state.to_h + o_ptr->to_h + j_ptr->to_h);
	chance = p_ptr->state.skills[SKILL_TO_HIT_BOW] +
			(bonus * BTH_PLUS_ADJ);

	/* Take a (partial) turn */
	p_ptr->energy_use = (100 / thits);

	/* Calculate the path */
	path_n = project_path(path_g, tdis, y, x, ty, tx, 0);

	/* Hack -- Handle stuff */
	handle_stuff();

	/* Project along the path */
	for (i = 0; i < path_n; ++i)
	{
		int ny = GRID_Y(path_g[i]);
		int nx = GRID_X(path_g[i]);

		/* Hack -- Stop before hitting walls */
		if (!cave_floor_bold(ny, nx)) break;

		/* Advance */
		x = nx;
		y = ny;

		/* Only do visuals if the player can "see" the missile */
		if (player_can_see_bold(y, x))
		{
			/* Visual effects */
			print_rel(missile_char, missile_attr, y, x);
			move_cursor_relative(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();

			Term_xtra(TERM_XTRA_DELAY, msec);
			light_spot(y, x);

			Term_fresh();
			if (p_ptr->redraw) redraw_stuff();
		}

		/* Delay anyway for consistency */
		else
		{
			/* Pause anyway, for consistancy */
			Term_xtra(TERM_XTRA_DELAY, msec);
		}

		/* Handle monster */
		if (cave_m_idx[y][x] > 0)
		{
			monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];
			monster_race *r_ptr = &r_info[m_ptr->r_idx];

			int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x);
			int visible = m_ptr->ml;
			int multiplier = 1;

			const char *hit_verb = "hits";
			const slay_t *best_s_ptr = NULL;

			/* Note the collision */
			hit_body = TRUE;

			/* Did we hit it (penalize distance travelled) */
			if (test_hit(chance2, r_ptr->ac, m_ptr->ml))
			{
				bool fear = FALSE;

				/* Assume a default death */
				cptr note_dies = " dies.";

				improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr);
				improve_attack_modifier(j_ptr, m_ptr, &best_s_ptr);
				if (best_s_ptr != NULL)
					hit_verb = best_s_ptr->range_verb;

				/* Some monsters get "destroyed" */
				if (monster_is_unusual(r_ptr))
				{
					/* Special note at death */
					note_dies = " is destroyed.";
				}

				/* Calculate multiplier */
				multiplier = p_ptr->state.ammo_mult;
				if (best_s_ptr != NULL) multiplier += best_s_ptr->mult;

				/* Apply damage: multiplier, slays, criticals, bonuses */
				tdam = damroll(o_ptr->dd, o_ptr->ds);
				tdam += o_ptr->to_d + j_ptr->to_d;
				tdam *= multiplier;
				tdam = critical_shot(o_ptr->weight, o_ptr->to_h, tdam, &msg_type);

				object_notice_attack_plusses(o_ptr);
				object_notice_attack_plusses(&p_ptr->inventory[INVEN_BOW]);

				/* No negative damage; change verb if no damage done */
				if (tdam <= 0)
				{
					tdam = 0;
					hit_verb = "fail to harm";
				}

				/* Handle unseen monster */
				if (!visible)
				{
					/* Invisible monster */
					message_format(MSG_SHOOT_HIT, 0, "The %s finds a mark.", o_name);
				}

				/* Handle visible monster */
				else
				{
					char m_name[80];

					/* Get "the monster" or "it" */
					monster_desc(m_name, sizeof(m_name), m_ptr, 0);

					/* Tell the player what happened */
					if (msg_type == MSG_SHOOT_HIT)
						message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name);
					else
					{
						if (msg_type == MSG_HIT_GOOD)
						{
							message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a good hit!");
						}
						else if (msg_type == MSG_HIT_GREAT)
						{
							message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a great hit!");
						}
						else if (msg_type == MSG_HIT_SUPERB)
						{
							message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name,
										   "It was a superb hit!");
						}
					}
					/* Hack -- Track this monster race */
					if (m_ptr->ml) monster_race_track(m_ptr->r_idx);

					/* Hack -- Track this monster */
					if (m_ptr->ml) health_track(cave_m_idx[y][x]);

				}

				/* Complex message */
				if (p_ptr->wizard)
				{
					msg_format("You do %d (out of %d) damage.",
					           tdam, m_ptr->hp);
				}

				/* Hit the monster, check for death */
				if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies))
				{
					/* Dead monster */
				}

				/* No death */
				else
				{
					/* Message */
					message_pain(cave_m_idx[y][x], tdam);

					/* Take note */
					if (fear && m_ptr->ml)
					{
						char m_name[80];

						/* Get the monster name (or "it") */
						monster_desc(m_name, sizeof(m_name), m_ptr, 0);

						/* Message */
						message_format(MSG_FLEE, m_ptr->r_idx,
						               "%^s flees in terror!", m_name);
					}
				}
			}

			/* Stop looking */
			break;
		}
	}



	/* Get local object */
	i_ptr = &object_type_body;

	/* Obtain a local object */
	object_copy(i_ptr, o_ptr);

	/* Single object */
	i_ptr->number = 1;

	if (item >= 0)
	{
		inven_item_increase(item, -1);
		inven_item_describe(item);
		inven_item_optimize(item);
	}

	/* Reduce and describe floor item */
	else
	{
		floor_item_increase(0 - item, -1);
		floor_item_optimize(0 - item);
	}


	/* Chance of breakage (during attacks) */
	j = (hit_body ? breakage_chance(i_ptr) : 0);

	/* Drop (or break) near that location */
	drop_near(i_ptr, j, y, x, TRUE);
}
/**
 * Melee effect handler: Drain the player's experience.
 */
static void melee_effect_handler_EXP_40(melee_effect_handler_context_t *context)
{
	melee_effect_experience(context, 75, damroll(40, 6));
}
Exemplo n.º 24
0
static void do_cmd_eat_food_aux(int item)
{
	int ident, lev;
	object_type *o_ptr;

	/* Get the item (in the pack) */
	if (item >= 0)
	{
		o_ptr = &inventory[item];
	}

	/* Get the item (on the floor) */
	else
	{
		o_ptr = &o_list[0 - item];
	}

	/* Sound */
	sound(SOUND_EAT);

	/* Take a turn */
	energy_use = 100;

	/* Identity not known yet */
	ident = FALSE;

	/* Object level */
	lev = get_object_level(o_ptr);

	/* Analyze the food */
	switch (o_ptr->sval)
	{
#ifdef JP
		/* それぞれの食べ物の感想をオリジナルより細かく表現 */
		case SV_FOOD_SLIME_MOLD:
		{
			msg_print("これはなんとも形容しがたい味だ。");
			ident = TRUE;
			break;
		}

		case SV_FOOD_RATION:
		{
			msg_print("これはおいしい。");
			ident = TRUE;
			break;
		}
#else
		case SV_FOOD_RATION:
		case SV_FOOD_SLIME_MOLD:
		{
			msg_print("That tastes good.");
			ident = TRUE;
			break;
		}
#endif

		case SV_FOOD_WAYBREAD:
		{
#ifdef JP
			msg_print("これはひじょうに美味だ。");
#else
			msg_print("That tastes good.");
#endif
			(void)set_poisoned(0);
			(void)hp_player(damroll(4, 8));
			ident = TRUE;
			break;
		}
	}

	/* Combine / Reorder the pack (later) */
	p_ptr->notice |= (PN_COMBINE | PN_REORDER);

	/* We have tried it */
	object_tried(o_ptr);

	/* The player is now aware of the object */
	if (ident && !object_aware_p(o_ptr))
	{
		object_aware(o_ptr);
		gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);
	}
Exemplo n.º 25
0
/*
 * do_cmd_mind calls this function if the player's class
 * is 'Medium'.
 */
static bool cast_medium_spell(int spell)
{
	/* this will vary based on the spells, and what they depend on */
	int             b = 0;
	int 			dir;
	int             plev = p_ptr->lev;

	/* spell code */
	switch (spell)
	{
		case 0:
			/* Mindblast */
			if (!get_aim_dir(&dir)) return FALSE;

			if (randint(100) < plev * 2)
				(void)fire_bolt_or_beam(100, GF_PSI, dir,
								damroll(3 + ((plev - 1) / 4), (3 + plev / 15)));
			else
				(void)fire_ball(GF_PSI, dir,
								damroll(3 + ((plev - 1) / 4), (3 + plev / 15)),
								0);
			break;
		case 1:
			if (plev > 44)
				wiz_lite();
			else if (plev > 19)
				map_area();

			if (plev < 30)
			{
				b = detect_monsters_normal();
				if (plev > 14)
					b |= detect_monsters_invis();

				if (plev > 4)
				{
					b |= detect_traps();
					b |= detect_doors();
				}
			}
			else
			{
				b = detect_all();
			}

			if (plev > 24)
			{
				(void)set_tim_esp(p_ptr->tim_esp + plev);
			}

			if (!b) msg_print("You feel safe.");
			break;
		case 2:
			/* Minor displace */
			teleport_player(plev);
			break;
		case 3:
			/* Major displace */
			teleport_player(plev * 5);
			break;
		case 4:
			/* Psychic Disturbance */
			msg_print("You disturb specters from beyond the veil!");
			(void)project(-1, 2 + plev / 8, p_ptr->py, p_ptr->px,
						  damroll((plev / 2), plev), GF_CONFUSION, PROJECT_KILL);
			break;
		case 5:
			/* spirit blast  ---  not 'true' TK */
			if (!get_aim_dir(&dir)) return FALSE;
			(void)fire_ball(GF_SOUND, dir, damroll(8 + ((plev - 5) / 4), 8),
							(plev > 20 ? (plev - 20) / 8 + 1 : 0));
			break;
		case 6:
			/* Character Armour */
			(void)set_shield(p_ptr->shield + plev);
			if (plev > 14) (void)set_oppose_acid(p_ptr->oppose_acid + plev);
			if (plev > 19) (void)set_oppose_fire(p_ptr->oppose_fire + plev);
			if (plev > 24) (void)set_oppose_cold(p_ptr->oppose_cold + plev);
			if (plev > 29) (void)set_oppose_elec(p_ptr->oppose_elec + plev);
			if (plev > 34) (void)set_oppose_pois(p_ptr->oppose_pois + plev);
			break;
		case 7:
			ident_spell();
			break;
		case 8:
			if (!get_aim_dir(&dir)) return FALSE; 
			(void)fire_bolt(GF_DOMINATION, dir,
					damroll((plev / 2), (3 + plev / 3)));
			break;
		case 9:
			/* Soul Purge */
			msg_print("The anguish of the dead emanates from your brain!");
			
			(void)project(-1, 2 + plev / 10, p_ptr->py, p_ptr->px,
						  damroll(plev, 4), GF_PSI, PROJECT_KILL);
			break;
		case 10:
			/* Adrenaline */
			(void)set_afraid(0);
			(void)set_stun(0);

			/*
			 * Only heal when Adrenalin Channeling is not active. We check
			 * that by checking if the player isn't fast and 'heroed' atm.
			 */
			if (!p_ptr->fast || !(p_ptr->hero || p_ptr->shero))
			{
				(void)hp_player(plev);
			}

			b = 10 + randint((plev * 3) / 2);
			if (plev < 35)
				(void)set_hero(p_ptr->hero + b);
			else
				(void)set_shero(p_ptr->shero + b);

			if (!p_ptr->fast)
			{
				/* Haste */
				(void)set_fast(b);
			}
			else
			{
				(void)set_fast(p_ptr->fast + b);
			}
			break;
		case 11:
			/* Psychic Drain Turned into MEGA-STUN*/
			if (!get_aim_dir(&dir)) return FALSE;

			b = damroll(plev * 2, 3);

			/* This is always a radius-0 ball now */
			if (fire_ball(GF_STUN, dir, b, 0))
			p_ptr->energy -= randint(150);
			break;
		case 12:
			/* Entropic Blast */
			msg_print
				("A wave of pure entropic force blasts out from your spirit!");
			(void)project(-1, 3 + plev / 10, p_ptr->py, p_ptr->px,
						  plev * (plev > 39 ? 4 : 3), GF_FORCE,
						  PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID);
			break;
		default:
			msg_print("Unknown Mindcrafter power!");
	}


	return TRUE;
}
Exemplo n.º 26
0
static void cmd_racial_power_aux(const mutation_type *mut_ptr)
{
	s16b        plev = p_ptr->lev;
	int         dir = 0;

	if (racial_aux(mut_ptr->level, mut_ptr->cost, mut_ptr->stat, mut_ptr->diff))
	{
		switch (p_ptr->prace)
		{
			case RACE_DWARF:
			{
				msg_print("You examine your surroundings.");
				(void)detect_traps();
				(void)detect_doors();
				(void)detect_stairs();
				break;
			}

			case RACE_HOBBIT:
			{
				object_type *q_ptr;
				object_type forge;

				/* Get local object */
				q_ptr = &forge;

				/* Create the food ration */
				object_prep(q_ptr, 21);

				/* Drop the object from heaven */
				(void)drop_near(q_ptr, -1, p_ptr->py, p_ptr->px);
				msg_print("You cook some food.");

				break;
			}

			case RACE_GNOME:
			{
				msg_print("Blink!");
				teleport_player(10 + plev);
				break;
			}

			case RACE_HALF_ORC:
			{
				msg_print("You play tough.");
				(void)set_afraid(0);
				break;
			}

			case RACE_HALF_TROLL:
			{
				msg_print("RAAAGH!");
				if (!p_ptr->shero)
				{
					(void)hp_player(30);
				}
				(void)set_afraid(0);
				(void)set_shero(p_ptr->shero + 10 + randint1(plev));

				break;
			}

			case RACE_AMBERITE:
			{
				/* Hack - use levels to choose ability */
				if (mut_ptr->level == 30)
				{
					msg_print("You picture the Pattern in your mind and walk it...");
					(void)set_poisoned(0);
					(void)set_image(0);
					(void)set_stun(0);
					(void)set_cut(0);
					(void)set_blind(0);
					(void)set_afraid(0);
					(void)do_res_stat(A_STR, 200);
					(void)do_res_stat(A_INT, 200);
					(void)do_res_stat(A_WIS, 200);
					(void)do_res_stat(A_DEX, 200);
					(void)do_res_stat(A_CON, 200);
					(void)do_res_stat(A_CHR, 200);
					(void)restore_level();
				}

				else if (mut_ptr->level == 40)
				{
					/* No effect in arena or quest */
					if (p_ptr->inside_quest)
					{
						msg_print("There is no effect.");
					}
					else
					{
						msg_print("You start walking around. Your surroundings change.");

						if (autosave_l) do_cmd_save_game(TRUE);

						/* Leaving */
						p_ptr->leaving = TRUE;
					}
				}
				break;
			}

			case RACE_BARBARIAN:
			{
				msg_print("Raaagh!");
				if (!p_ptr->shero)
				{
					(void)hp_player(30);
				}

				(void)set_afraid(0);
				(void)set_shero(p_ptr->shero + 10 + randint1(plev));
				break;
			}

			case RACE_HALF_OGRE:
			{
				msg_print("You carefully set an explosive rune...");
				(void)explosive_rune();
				break;
			}

			case RACE_HALF_GIANT:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You bash at a stone wall.");
				(void)wall_to_mud(dir);
				break;
			}

			case RACE_HALF_TITAN:
			{
				msg_print("You examine your foes...");
				(void)probing();
				break;
			}

			case RACE_CYCLOPS:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You throw a huge boulder.");
				(void)fire_bolt(GF_MISSILE, dir, (3 * plev) / 2);
				break;
			}

			case RACE_YEEK:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You make a horrible scream!");
				(void)fear_monster(dir, plev);
				break;
			}

			case RACE_KLACKON:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You spit acid.");
				if (plev < 25)
					(void)fire_bolt(GF_ACID, dir, plev);
				else
					(void)fire_ball(GF_ACID, dir, plev, 2);
				break;
			}

			case RACE_KOBOLD:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You throw a dart of poison.");
				(void)fire_bolt(GF_POIS, dir, plev);
				break;
			}

			case RACE_NIBELUNG:
			{
				msg_print("You examine your surroundings.");
				(void)detect_traps();
				(void)detect_doors();
				(void)detect_stairs();
				break;
			}

			case RACE_DARK_ELF:
			{
				if (!get_aim_dir(&dir)) break;
				msg_print("You cast a magic missile.");
				(void)fire_bolt_or_beam(10, GF_MISSILE, dir,
				    damroll(3 + ((plev - 1) / 5), 4));
				break;
			}

			case RACE_DRACONIAN:
			{
				int  Type = (one_in_(3) ? GF_COLD : GF_FIRE);
				cptr Type_desc = ((Type == GF_COLD) ? "cold" : "fire");

				if (randint1(100) < plev)
				{
					switch (p_ptr->pclass)
					{
						case CLASS_WARRIOR:
						case CLASS_RANGER:
							if (one_in_(3))
							{
								Type = GF_MISSILE;
								Type_desc = "the elements";
							}
							else
							{
								Type = GF_SHARDS;
								Type_desc = "shards";
							}
							break;
						case CLASS_MAGE:
						case CLASS_WARRIOR_MAGE:
						case CLASS_HIGH_MAGE:
							if (one_in_(3))
							{
								Type = GF_MANA;
								Type_desc = "mana";
							}
							else
							{
								Type = GF_DISENCHANT;
								Type_desc = "disenchantment";
							}
							break;
						case CLASS_CHAOS_WARRIOR:
							if (!one_in_(3))
							{
								Type = GF_CONFUSION;
								Type_desc = "confusion";
							}
							else
							{
								Type = GF_CHAOS;
								Type_desc = "chaos";
							}
							break;
						case CLASS_MONK:
							if (!one_in_(3))
							{
								Type = GF_CONFUSION;
								Type_desc = "confusion";
							}
							else
							{
								Type = GF_SOUND;
								Type_desc = "sound";
							}
							break;
						case CLASS_MINDCRAFTER:
							if (!one_in_(3))
							{
								Type = GF_CONFUSION;
								Type_desc = "confusion";
							}
							else
							{
								Type = GF_PSI;
								Type_desc = "mental energy";
							}
							break;
						case CLASS_PRIEST:
						case CLASS_PALADIN:
							if (one_in_(3))
							{
								Type = GF_HELL_FIRE;
								Type_desc = "hellfire";
							}
							else
							{
								Type = GF_HOLY_FIRE;
								Type_desc = "holy fire";
							}
							break;
						case CLASS_ROGUE:
							if (one_in_(3))
							{
								Type = GF_DARK;
								Type_desc = "darkness";
							}
							else
							{
								Type = GF_POIS;
								Type_desc = "poison";
							}
							break;
					}
				}

				if (!get_aim_dir(&dir)) break;
				msg_format("You breathe %s.", Type_desc);
				(void)fire_ball(Type, dir, plev * 2,
				    (plev / 15) + 1);
				break;
			}

			case RACE_MIND_FLAYER:
			{
				if (!get_aim_dir(&dir)) break;
				else
				{
					msg_print("You concentrate and your eyes glow red...");
					(void)fire_bolt(GF_PSI, dir, plev);
				}

				break;
			}

			case RACE_IMP:
			{
				if (!get_aim_dir(&dir)) break;
				if (plev >= 30)
				{
					msg_print("You cast a ball of fire.");
					(void)fire_ball(GF_FIRE, dir, plev, 2);
				}
				else
				{
					msg_print("You cast a bolt of fire.");
					(void)fire_bolt(GF_FIRE, dir, plev);
				}
				break;
			}

			case RACE_GOLEM:
			{
				(void)set_shield(p_ptr->shield + rand_range(30, 50));
				break;
			}

			case RACE_SKELETON:
			case RACE_ZOMBIE:
			{
				msg_print("You attempt to restore your lost energies.");
				(void)restore_level();
				break;
			}

			case RACE_VAMPIRE:
			{
				int y, x, dummy;
				cave_type *c_ptr;

				/* Only works on adjacent monsters */
				if (!get_rep_dir(&dir)) break;
				y = p_ptr->py + ddy[dir];
				x = p_ptr->px + ddx[dir];

				/* Paranoia */
				if (!in_bounds2(y, x)) break;

				c_ptr = area(y, x);

				if (!c_ptr->m_idx)
				{
					msg_print("You bite into thin air!");
					break;
				}

				msg_print("You grin and bare your fangs...");
				dummy = plev + randint1(plev) * MAX(1, plev / 10);   /* Dmg */
				if (drain_gain_life(dir, dummy))
				{
					/* Gain nutritional sustenance: 150/hp drained */
					/* A Food ration gives 5000 food points (by contrast) */
					/* Don't ever get more than "Full" this way */
					/* But if we ARE Gorged,  it won't cure us */
					dummy = p_ptr->food + MIN(5000, 100 * dummy);
					if (p_ptr->food < PY_FOOD_MAX)   /* Not gorged already */
						(void)set_food(dummy >= PY_FOOD_MAX ? PY_FOOD_MAX - 1 : dummy);
				}
				else
					msg_print("Yechh. That tastes foul.");
				break;
			}

			case RACE_SPECTRE:
			{
				msg_print("You emit an eldritch howl!");
				if (!get_aim_dir(&dir)) break;
				(void)fear_monster(dir, plev);
				break;
			}

			case RACE_SPRITE:
			{
				msg_print("You throw some magic dust...");
				if (plev < 25)
					(void)sleep_monsters_touch();
				else
					(void)sleep_monsters();
				break;
			}
			case RACE_GHOUL:
			{
				if (mut_ptr->level == 30)
				{
					/* Sense living */
					(void)detect_monsters_living();
				}
				else
				{
					eat_corpse();
				}
				break;
			}
			default:
				msg_print("This race has no bonus power.");
				p_ptr->energy_use = 0;
		}
	}

	/* Redraw mana and hp */
	p_ptr->redraw |= (PR_HP | PR_MANA);

	/* Window stuff */
	p_ptr->window |= (PW_PLAYER | PW_SPELL);
}
Exemplo n.º 27
0
/*
 * do_cmd_mind calls this function if the player's class
 * is 'Naturalist'.
 */
static bool cast_nature_spell(int spell)
{
	/* this will vary based on the spells, and what they depend on */
	int             plev = p_ptr->lev;
	int 			dir;
	int 			px = p_ptr->px;
	int				py = p_ptr->py;
	
	/* spell code */
	switch (spell)
	{
	case 0: /* Detect Creatures */
		(void)detect_monsters_normal();
		break;
	case 1: /* First Aid */
		(void)hp_player(damroll(2, 8));
		(void)set_cut(p_ptr->cut - 15);
		break;
	case 2: /* Detect Doors + Traps */
		(void)detect_traps();
		(void)detect_doors();
		(void)detect_stairs();
		break;
	case 3: /* Produce Food */
		(void)set_food(PY_FOOD_MAX - 1);
		break;
	case 4: /* Daylight */
		(void)lite_area(damroll(2, (plev / 2)), (plev / 10) + 1);
		break;
	case 5: /* Animal Taming */
		if (!get_aim_dir(&dir)) return FALSE;
		(void)charm_animal(dir, plev);
		break;
	case 6: /* Resist Environment */
		(void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20);
		(void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20);
		(void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20);
		break;
	case 7: /* Cure Wounds + Poison */
		(void)hp_player(damroll(plev, 8));
		(void)set_cut(0);
		(void)set_poisoned(0);
		break;
	case 8: /* Stone to Mud */
		if (!get_aim_dir(&dir)) return FALSE;
		(void)wall_to_mud(dir);
		break;
	case 9: /* Lightning Bolt */
		if (!get_aim_dir(&dir)) return FALSE;
		fire_bolt_or_beam(100, GF_ELEC, dir,
			damroll(3 + ((plev - 5) / 4), 8));
		break;
	case 10: /* Ray of Sunlight */
		if (!get_aim_dir(&dir)) return FALSE;
		msg_print("A line of sunlight appears.");
		(void)lite_line(dir);
		break;
	case 11: /* Entangle */
		slow_monsters();
		break;
	case 12: /* Stone Skin */
		(void)set_shield(p_ptr->shield + randint(20) + 30);
		break;
	case 13: /* Resistance True */
		(void)set_oppose_acid(p_ptr->oppose_acid + randint(20) + 20);
		(void)set_oppose_elec(p_ptr->oppose_elec + randint(20) + 20);
		(void)set_oppose_fire(p_ptr->oppose_fire + randint(20) + 20);
		(void)set_oppose_cold(p_ptr->oppose_cold + randint(20) + 20);
		(void)set_oppose_pois(p_ptr->oppose_pois + randint(20) + 20);
		break;
	case 14: /* Stone Tell */
		return identify_fully();
	case 15: /* Earthquake */
		earthquake(py, px, 10);
		break;
	case 16: /* Blizzard */
		if (!get_aim_dir(&dir)) return FALSE;
		fire_ball(GF_COLD, dir, 70 + plev, (plev / 12) + 1);
		break;
	case 17: /* Lightning Storm */
		if (!get_aim_dir(&dir)) return FALSE;
		fire_ball(GF_ELEC, dir, 90 + plev, (plev / 12) + 1);
		break;
	case 18: /* Whirlpool */
		if (!get_aim_dir(&dir)) return FALSE;
		fire_ball(GF_WATER, dir, 100 + plev, (plev / 12) + 1);
		break;
	case 19: /* Call Sunlight */
		fire_ball(GF_LITE, 0, 150, 8);
		wiz_lite();
		break;
	case 20: /* Nature's Wrath */
		(void)dispel_monsters(plev * 4);
		earthquake(py, px, 20 + (plev / 2));
		project(0, 1 + plev / 12, py, px,
			100 + plev, GF_DISINTEGRATE, PROJECT_KILL | PROJECT_ITEM);
		break;
	default:
		msg_format("You cast an unknown Nature spell: %d.", spell);
		msg_print(NULL);
	}

	return TRUE;
}
Exemplo n.º 28
0
Arquivo: cmd3.c Projeto: fph/mortsil
void prise_silmaril(void)
{
	object_type   *o_ptr;
	object_type   *w_ptr;
	artefact_type *a_ptr;

	object_type object_type_body;

	cptr freed_msg = NULL; // default to soothe compiler warnings

	bool freed = FALSE;

	int slot = 0;
	
	int dam = 0;
	int prt = 0;
	int net_dam = 0;
	int prt_percent = 0;
	int hit_result = 0;
	int crit_bonus_dice = 0;
	int pd = 0;
	int noise = 0;
	u32b dummy_noticed_flag;
	
	int mds = p_ptr->mds;
	int attack_mod = p_ptr->skill_use[S_MEL];

	char o_name[80];

	// the Crown is on the ground
	o_ptr = &o_list[cave_o_idx[p_ptr->py][p_ptr->px]];
				
	switch (o_ptr->name1)
	{
		case ART_MORGOTH_3:
		{
			pd = 15;
			noise = 5;
			freed_msg = "You have freed a Silmaril!";
			break;
		}
		case ART_MORGOTH_2:
		{
			pd = 25;
			noise = 10;
						
			if (p_ptr->crown_shatter)	freed_msg = "The fates be damned! You free a second Silmaril.";
			else						freed_msg = "You free a second Silmaril.";
			
			break;
		}
		case ART_MORGOTH_1:
		{
			pd = 30;
			noise = 15;
			
			freed_msg = "You free the final Silmaril. You have a very bad feeling about this.";
			
			msg_print("Looking into the hallowed light of the final Silmaril, you are filled with a strange dread.");
			if (!get_check("Are you sure you wish to proceed? ")) return;
			
			break;
		}
	}
	
	/* Get the weapon */
	w_ptr = &inventory[INVEN_WIELD];

	// undo rapid attack penalties
	if (p_ptr->active_ability[S_MEL][MEL_RAPID_ATTACK])
	{
		// undo strength adjustment to the attack
		mds = total_mds(w_ptr, 0);
		
		// undo the dexterity adjustment to the attack
		attack_mod += 3;
	}
	
	/* Test for hit */
	hit_result = hit_roll(attack_mod, 0, PLAYER, NULL, TRUE);
	
	/* Make some noise */
	stealth_score -= noise;
	
	// Determine damage
	if (hit_result > 0)
	{
		crit_bonus_dice = crit_bonus(hit_result, w_ptr->weight, &r_info[R_IDX_MORGOTH], S_MEL, FALSE);
		
		dam = damroll(p_ptr->mdd + crit_bonus_dice, mds);
		prt = damroll(pd, 4);
		
		prt_percent = prt_after_sharpness(w_ptr, &dummy_noticed_flag);
		prt = (prt * prt_percent) / 100;
		net_dam = dam - prt;
		
		/* No negative damage */
		if (net_dam < 0) net_dam = 0;
		
		//update_combat_rolls1b(PLAYER, TRUE);
		update_combat_rolls2(p_ptr->mdd + crit_bonus_dice, mds, dam, pd, 4, prt, prt_percent, GF_HURT, TRUE);
	}
	
	
	// if you succeed in prising out a Silmaril...
	if (net_dam > 0)
	{
		freed = TRUE;
		
		switch (o_ptr->name1)
		{
			case ART_MORGOTH_3:
			{
				break;
			}
			case ART_MORGOTH_2:
			{
				if (!p_ptr->crown_shatter && one_in_(2))
				{
					shatter_weapon(2);
					freed = FALSE;
				}
				break;
			}
			case ART_MORGOTH_1:
			{
				if (!p_ptr->crown_shatter)
				{
					shatter_weapon(3);
					freed = FALSE;
				}
				else
				{
					p_ptr->cursed = TRUE;
				}
				break;
			}
		}
		
		if (freed)
		{
			// change its type to that of the crown with one less silmaril
			o_ptr->name1--;
			
			// get the details of this new crown
			a_ptr = &a_info[o_ptr->name1];
			
			// modify the existing crown
			object_into_artefact(o_ptr, a_ptr);
			
			// report success
			msg_print(freed_msg);
			
			// Get new local object
			o_ptr = &object_type_body;
			
			// Make Silmaril
			object_prep(o_ptr, lookup_kind(TV_LIGHT, SV_LIGHT_SILMARIL));
			
			// Get it
			slot = inven_carry(o_ptr);

			/* Get the object again */
			o_ptr = &inventory[slot];
			
			/* Describe the object */
			object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 3);
			
			/* Message */
			msg_format("You have %s (%c).", o_name, index_to_label(slot));

			// Break the truce (always)
			break_truce(TRUE);
		
			// add a note to the notes file
			do_cmd_note("Cut a Silmaril from Morgoth's crown", p_ptr->depth);
		}
	}
	
	// if you fail to prise out a Silmaril...
	else
	{
		msg_print("Try though you might, you were unable to free a Silmaril.");
		msg_print("Perhaps you should try again or use a different weapon.");

		if (pd == 15) msg_print("(The combat rolls window shows what is happening.)");

		// Break the truce if creatures see
		break_truce(FALSE);
	}

	// check for taking of final Silmaril
	if ((pd == 30) && freed)
	{
		msg_print("Until you escape you must now roll twice for every skill check, taking the worse result each time.");
		msg_print("You hear a cry of veangance echo through the iron hells.");
		wake_all_monsters(0);
	}
}
Exemplo n.º 29
0
/**
 * Handle player hitting a real trap.  Rewritten in Oangband to allow a
 * greater variety of traps, with effects controlled by dungeon level.
 * To allow a trap to choose one of a variety of effects consistantly,
 * the quick RNG is often used, and xy coordinates input as a seed value.
 */
extern void hit_trap(int y, int x)
{
    int i, j, k, num;
    int dam = 0;

    int nastyness, selection;

    feature_type *f_ptr = &f_info[cave_feat[y][x]];

    cptr name = f_ptr->name;

    /* Use the "simple" RNG to insure that traps are consistant. */
    Rand_quick = TRUE;

    /* Use the coordinates of the trap to seed the RNG. */
    Rand_value = y * x;

    /* Disturb the player */
    disturb(0, 0);

    /* Analyze XXX XXX XXX */
    switch (cave_feat[y][x]) {
    /* trap door. */
    case FEAT_TRAP_HEAD + 0x00:
    {
        Rand_quick = FALSE;

        /* Paranoia -NRM- */
        if (((stage_map[p_ptr->stage][STAGE_TYPE] == CAVE)
                || (stage_map[p_ptr->stage][STAGE_TYPE] == VALLEY))
                && (!stage_map[p_ptr->stage][DOWN])) {
            cave_info[y][x] &= ~(CAVE_MARK);
            cave_set_feat(y, x, FEAT_FLOOR);
            msg_print("The trap fails!");
            break;
        }


        msg_print("You fall through a trap door!");
        if (p_ptr->state.ffall) {
            notice_obj(OF_FEATHER, 0);
            msg_print("You float gently down to the next level.");
        } else {
            dam = damroll(2, 8);
            take_hit(dam, name);
        }
        /* Remember where we came from */
        p_ptr->last_stage = p_ptr->stage;

        if (!stage_map[p_ptr->stage][DOWN]) {
            /* Set the ways forward and back */
            stage_map[255][UP] = p_ptr->stage;
            stage_map[p_ptr->stage][DOWN] = 255;
            stage_map[255][DEPTH] = p_ptr->depth + 1;
        }

        /* New stage */
        p_ptr->stage = stage_map[p_ptr->stage][DOWN];

        /* New depth */
        p_ptr->depth = stage_map[p_ptr->stage][DEPTH];

        /* Leaving */
        p_ptr->leaving = TRUE;

        Rand_quick = TRUE;

        break;
    }

    /* pits. */
    case FEAT_TRAP_HEAD + 0x01:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(20) == 1)
            nastyness += 20;
        else if (randint1(5) == 1)
            nastyness += 10;

        /* Player is now in pit. */
        monster_swap(p_ptr->py, p_ptr->px, y, x);

        /* Center on player. */
        y = p_ptr->py;
        x = p_ptr->px;

        /* pit of daggers. */
        if ((nastyness > 80) && (randint1(3) != 3)) {
            msg_print("You fall into a pit of daggers!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid setting off the daggers.");
            }

            else {
                /* a trap of morgul. */
                if (randint1(6) == 1) {
                    Rand_quick = FALSE;


                    msg_print
                    ("A single coldly gleaming dagger pierces you deeply!");
                    msg_print
                    ("You feel a deadly chill slowly withering your soul.");

                    /* activate the Black Breath. */
                    p_ptr->black_breath = TRUE;

                    /* lots of damage. */
                    dam = damroll(20, 15);

                    /* undead may be attracted. */
                    if (randint1(2) == 1) {
                        msg_print
                        ("Undead suddenly appear and call you to them!");

                        k = randint1(3) + 2;
                        for (i = 0; i < k; i++) {
                            summon_specific(y, x, FALSE, p_ptr->depth,
                                            SUMMON_UNDEAD);
                        }
                    }

                    /* morgul-traps are one-time only. */
                    cave_info[y][x] &= ~(CAVE_MARK);
                    cave_set_feat(y, x, FEAT_FLOOR);

                    Rand_quick = TRUE;
                }

                else {
                    Rand_quick = FALSE;

                    /* activate the ordinary daggers. */
                    msg_print("Daggers pierce you everywhere!");

                    k = randint1(10) + 5;
                    for (i = 0; i < k; i++) {
                        dam += damroll(3, 4);
                    }

                    Rand_quick = TRUE;
                }

                /* cut the player. */
                (void) inc_timed(TMD_CUT, randint1(dam), TRUE);

                /* Take the damage. */
                take_hit(dam, name);
            }
        }

        /* poisoned spiked pit. */
        else if ((nastyness > 55) && (randint1(3) != 3)) {
            msg_print("You fall into a spiked pit!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid touching the spikes.");
            }

            else {
                Rand_quick = FALSE;

                /* Base damage */
                dam = damroll(2, 6);

                /* Extra spike damage */
                if (randint0(100) < 85) {
                    bool was_poisoned;

                    msg_print("You are impaled on poisonous spikes!");

                    dam = dam * (randint1(6) + 3);
                    (void) inc_timed(TMD_CUT, randint1(dam), TRUE);

                    was_poisoned = pois_hit(dam);

                    if (!was_poisoned)
                        msg_print("The poison does not affect you!");
                }

                /* Take the damage */
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        /* spiked pit. */
        else if ((nastyness > 30) && (randint1(3) != 3)) {
            msg_print("You fall into a spiked pit!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid touching the spikes.");
            }

            else {
                Rand_quick = FALSE;

                /* Base damage */
                dam = damroll(2, 6);

                /* Extra spike damage */
                if (randint0(100) < 85) {
                    msg_print("You are impaled!");

                    dam = dam * (2 + randint1(4));
                    (void) inc_timed(TMD_CUT, randint1(dam), TRUE);
                }

                /* Take the damage */
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        /* ordinary pit in all other cases. */
        else {
            msg_print("You fall into a pit!");
            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the bottom of the pit.");
            } else {
                Rand_quick = FALSE;

                dam = damroll(2, 6);
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        break;
    }

    /* stat-reducing dart traps. */
    case FEAT_TRAP_HEAD + 0x02:
    {
        /* decide if the dart hits. */
        if (check_trap_hit(50 + p_ptr->depth)) {
            /* select a stat to drain. */
            selection = randint0(6);

            Rand_quick = FALSE;

            msg_print("A small dart hits you!");
            dam = damroll(1, 4);
            take_hit(dam, name);

            /* Determine how dangerous the trap is allowed to be. */
            nastyness = randint1(p_ptr->depth);

            /* decide how much to drain the stat by. */
            if ((nastyness > 50) && (randint1(3) == 1)) {
                num = randint1(4);
            } else
                num = 1;

            /* drain the stat. */
            for (i = 0; i < num; i++) {
                (void) do_dec_stat(selection);
            }

            Rand_quick = TRUE;
        } else {
            msg_print("A small dart barely misses you.");
        }
        break;
    }

    /* discolored spots. */
    case FEAT_TRAP_HEAD + 0x03:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(5) == 1)
            nastyness += 10;

        /* pick a elemental attack type. */
        selection = randint1(4);


        /* electicity trap. */
        if (selection == 1) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are struck by lightning!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You get zapped!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            elec_dam(dam, "an electricity trap");
            Rand_quick = TRUE;

        }

        /* frost trap. */
        if (selection == 2) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are lost within a blizzard!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are coated in frost!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            cold_dam(dam, "a frost trap");
            Rand_quick = TRUE;
        }

        /* fire trap. */
        if (selection == 3) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are enveloped in a column of fire!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are surrounded by flames!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            fire_dam(dam, "a fire trap");
            Rand_quick = TRUE;
        }

        /* acid trap. */
        if (selection == 4) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("A cauldron of acid is tipped over your head!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are splashed with acid!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            acid_dam(dam, "an acid trap");
            Rand_quick = TRUE;
        }

        break;
    }

    /* gas traps. */
    case FEAT_TRAP_HEAD + 0x04:
    {
        selection = randint1(4);

        /* blinding trap. */
        if (selection == 1) {
            msg_print("You are surrounded by a black gas!");
            if (!p_ptr->state.no_blind) {
                Rand_quick = FALSE;

                (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE);

                Rand_quick = TRUE;
            }
        } else
            notice_obj(OF_SEEING, 0);

        /* confusing trap. */
        if (selection == 2) {
            msg_print
            ("You are surrounded by a gas of scintillating colors!");
            if (!p_resist_good(P_RES_CONFU)) {
                Rand_quick = FALSE;

                (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);

                Rand_quick = TRUE;
            } else
                notice_other(IF_RES_CONFU, 0);
        }

        /* poisoning trap. */
        if (selection == 3) {
            msg_print("You are surrounded by a pungent green gas!");

            Rand_quick = FALSE;

            pois_hit(25);

            Rand_quick = TRUE;
        }

        /* sleeping trap. */
        if (selection == 4) {
            msg_print("You are surrounded by a strange white mist!");
            if (!p_ptr->state.free_act) {
                (void) inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE);
            } else
                notice_obj(OF_FREE_ACT, 0);
        }

        break;
    }

    /* summoning traps. */
    case FEAT_TRAP_HEAD + 0x05:
    {
        sound(MSG_SUM_MONSTER);
        /* sometimes summon thieves. */
        if ((p_ptr->depth > 8) && (randint1(5) == 1)) {
            msg_print("You have aroused a den of thieves!");

            Rand_quick = FALSE;

            num = 2 + randint1(3);
            for (i = 0; i < num; i++) {
                (void) summon_specific(y, x, FALSE, p_ptr->depth,
                                       SUMMON_THIEF);
            }

            Rand_quick = TRUE;
        }

        /* sometimes summon a nasty unique. */
        else if (randint1(8) == 1) {
            msg_print("You are enveloped in a cloud of smoke!");

            Rand_quick = FALSE;

            (void) summon_specific(y, x, FALSE, p_ptr->depth + 5,
                                   SUMMON_UNIQUE);

            Rand_quick = TRUE;
        }

        /* otherwise, the ordinary summon monsters. */
        else {
            msg_print("You are enveloped in a cloud of smoke!");

            Rand_quick = FALSE;

            num = 2 + randint1(3);
            for (i = 0; i < num; i++) {
                (void) summon_specific(y, x, FALSE, p_ptr->depth, 0);
            }

            Rand_quick = TRUE;
        }

        /* these are all one-time traps. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        break;
    }

    /* dungeon alteration traps. */
    case FEAT_TRAP_HEAD + 0x06:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(5) == 1)
            nastyness += 10;

        /* make room for alterations. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        /* Everything truely random from here on. */
        Rand_quick = FALSE;

        /* dungeon destruction trap. */
        if ((nastyness > 60) && (randint1(12) == 1)) {
            msg_print
            ("A ear-splitting howl shatters your mind as the dungeon is smashed by hammer blows!");

            (void) destroy_level(FALSE);

            /* the player is hard-hit. */
            (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);
            (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE);
            (void) inc_timed(TMD_STUN, randint1(50) + 50, TRUE);
            dam = damroll(15, 15);
            take_hit(dam, name);
        }

        /* earthquake trap. */
        else if ((nastyness > 20) && (randint1(4) == 1)) {
            msg_print("A tremor shakes the earth around you");
            earthquake(y, x, 10, FALSE);
        }

        /* falling rock trap. */
        else if ((nastyness > 4) && (randint1(2) == 1)) {
            msg_print("A rock falls on your head.");
            dam = damroll(2, 10);
            take_hit(dam, name);

            (void) inc_timed(TMD_STUN, randint1(10) + 10, TRUE);
        }

        /* a few pebbles. */
        else {
            msg_print("A bunch of pebbles rain down on you.");
            dam = damroll(1, 8);
            take_hit(dam, name);
        }

        Rand_quick = TRUE;

        break;
    }

    /* various char and equipment-alteration traps, lumped together to
     * avoid any one effect being too common (some of them can be rather
     * nasty). */
    case FEAT_TRAP_HEAD + 0x07:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint0(100);

        /* these are all one-time traps. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        /* Everything truely random from here on. */
        Rand_quick = FALSE;

        /* trap of drain wands. */
        if (nastyness < 15) {
            /* Hold the object information. */
            object_type *o_ptr;

            /* Find an item */
            for (i = 0; i < 20; i++) {
                /* Pick an item */
                i = randint0(INVEN_PACK - p_ptr->pack_size_reduce);

                /* Obtain the item */
                o_ptr = &p_ptr->inventory[i];

                /* use "num" to decide if a item can be uncharged.  By
                 * default, assume it can't. */
                num = 0;

                /* Skip non-objects */
                if (!o_ptr->k_idx)
                    continue;

                /* Drain charged wands/staffs/rods */
                if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)
                        || (o_ptr->tval == TV_ROD)) {
                    /* case of charged wands/staffs. */
                    if (((o_ptr->tval == TV_STAFF)
                            || (o_ptr->tval == TV_WAND)) && (o_ptr->pval))
                        num = 1;

                    /* case of charged rods. */
                    if ((o_ptr->tval == TV_ROD)
                            && (o_ptr->timeout < randcalc(o_ptr->time, 0,
                                                          MINIMISE)))
                        num = 1;


                    if (num == 1) {
                        /* Message */
                        msg_print("Energy drains from your pack!");

                        /* Uncharge */
                        if ((o_ptr->tval == TV_STAFF)
                                || (o_ptr->tval == TV_WAND))
                            o_ptr->pval = 0;

                        if (o_ptr->tval == TV_ROD)
                            o_ptr->timeout = randcalc(o_ptr->time, 0, RANDOMISE) * o_ptr->number * 2;


                        /* Combine / Reorder the pack */
                        p_ptr->notice |= (PN_COMBINE | PN_REORDER);

                        /* not more than one inventory slot effected. */
                        break;
                    } else
                        continue;
                }
            }
        }

        /* trap of forgetting. */
        else if (nastyness < 35) {
            if (check_save(100)) {
                msg_print("You hang on to your memories!");
            } else if (lose_all_info()) {
                msg_print("Your memories fade away.");
            }
        }

        /* trap of alter reality. */
        else if (nastyness < 50) {
            if (OPT(adult_ironman))
                msg_print("Nothing happens.");
            else {
                msg_print("The world changes!");

                /* Leaving */
                p_ptr->leaving = TRUE;
            }
        }

        /* trap of remold player. */
        else if (nastyness < 75) {
            int max1, cur1, max2, cur2, ii, jj;

            msg_print("You feel yourself being twisted by wild magic!");

            if (check_save(100)) {
                msg_print("You resist the effects!");
            } else {
                msg_print("Your body starts to scramble...");

                /* Pick a pair of stats */
                ii = randint0(6);
                for (jj = ii; jj == ii; jj = randint0(6))	/* loop */
                    ;

                max1 = p_ptr->stat_max[ii];
                cur1 = p_ptr->stat_cur[ii];
                max2 = p_ptr->stat_max[jj];
                cur2 = p_ptr->stat_cur[jj];

                p_ptr->stat_max[ii] = max2;
                p_ptr->stat_cur[ii] = cur2;
                p_ptr->stat_max[jj] = max1;
                p_ptr->stat_cur[jj] = cur1;

                p_ptr->update |= (PU_BONUS);
            }
        }

        /* time ball trap. */
        else if (nastyness < 90) {
            msg_print("You feel time itself assault you!");

            /* Target the player with a radius 0 ball attack. */
            fire_meteor(0, GF_TIME, p_ptr->py, p_ptr->px, 75, 0, TRUE);
        }

        /* trap of bugs gone berserk. */
        else {
            /* explain what the dickens is going on. */
            msg_print("GRUESOME Gnawing Bugs leap out at you!");

            if (!p_resist_good(P_RES_CONFU)) {
                (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);
            } else
                notice_other(IF_RES_CONFU, 0);

            if (!p_resist_good(P_RES_CHAOS)) {
                (void) inc_timed(TMD_IMAGE, randint1(40), TRUE);
            } else
                notice_other(IF_RES_CHAOS, 0);

            /* XXX (hard coded) summon 3-6 bugs. */
            k = randint1(4) + 2;
            for (i = 0; i < k; ++i) {
                /* Look for a location */
                for (j = 0; j < 20; ++j) {
                    /* Pick a (scattered) distance. */
                    int d = (j / 10) + randint1(3);

                    /* Pick a location */
                    scatter(&y, &x, y, x, d, 0);

                    /* Require passable terrain */
                    if (!cave_passable_bold(y, x))
                        continue;

                    /* Hack -- no summon on glyph of warding */
                    if (cave_feat[y][x] == FEAT_RUNE_PROTECT)
                        continue;

                    /* Okay */
                    break;
                }

                /* Attempt to place the awake bug */
                place_monster_aux(y, x, 453, FALSE, TRUE);
            }

            /* herald the arrival of bugs. */
            msg_print("AAAAAAAHHHH! THEY'RE EVERYWHERE!");
        }

        Rand_quick = TRUE;

        break;
    }

    /* teleport trap */
    case FEAT_TRAP_HEAD + 0x08:
    {
        if (stage_map[p_ptr->stage][STAGE_TYPE] >= CAVE)
            msg_print("You teleport across the dungeon.");
        else
            msg_print("You teleport across the wilderness.");

        Rand_quick = FALSE;

        teleport_player(250, FALSE);

        Rand_quick = TRUE;

        break;
    }

    /* murder holes. */
    case FEAT_TRAP_HEAD + 0x09:
    {
        /* hold the object info. */
        object_type *o_ptr;
        object_type object_type_body;

        /* hold the missile type and name. */
        int sval = 0;
        int tval = 0;
        cptr missile_name = "";



        /* Determine the missile type and base damage. */
        if (randint1(3) == 1) {
            if (p_ptr->depth < 40) {
                missile_name = "shot";
                dam = damroll(2, 3);
                tval = TV_SHOT;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker shot";
                dam = damroll(3, 7);
                tval = TV_SHOT;
                sval = SV_AMMO_HEAVY;
            }
        }

        else if (randint1(2) == 1) {
            if (p_ptr->depth < 55) {
                missile_name = "arrow";
                dam = damroll(2, 4);
                tval = TV_ARROW;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker arrow";
                dam = damroll(3, 9);
                tval = TV_ARROW;
                sval = SV_AMMO_HEAVY;
            }
        }

        else {
            if (p_ptr->depth < 65) {
                missile_name = "bolt";
                dam = damroll(2, 5);
                tval = TV_BOLT;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker bolt";
                dam = damroll(3, 11);
                tval = TV_BOLT;
                sval = SV_AMMO_HEAVY;
            }
        }

        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            msg_format("A %s hits you from above.", missile_name);

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was well-aimed!");
                dam *= 1 + randint1(2);
            }
            if (randint1(2) == 1) {
                msg_print("It gouges you!");
                dam = 3 * dam / 2;

                /* cut the player. */
                (void) inc_timed(TMD_CUT, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_format("A %s wizzes by your head.", missile_name);

        /* these will eventually run out of ammo. */

        Rand_quick = FALSE;

        if (randint0(8) == 0) {
            cave_info[y][x] &= ~(CAVE_MARK);
            cave_set_feat(y, x, FEAT_FLOOR);
        }

        Rand_quick = TRUE;

        /* Get local object */
        o_ptr = &object_type_body;

        /* Make a missile, identify it, and drop it near the player. */
        object_prep(o_ptr, lookup_kind(tval, sval), MINIMISE);
        object_aware(o_ptr);
        object_known(o_ptr);
        drop_near(o_ptr, -1, y, x, TRUE);

        break;
    }

    /* falling tree branch */
    case FEAT_TRAP_HEAD + 0x0A:
    {
        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            /* Take damage */
            dam = damroll(3, 5);
            msg_print("A branch hits you from above.");

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was heavy!");
                dam = 3 * dam / 2;

                /* stun the player. */
                (void) inc_timed(TMD_STUN, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_print("A falling branch just misses you.");

        /* No more */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_TREE);

        break;
    }

    /* falling tree branch */
    case FEAT_TRAP_HEAD + 0x0B:
    {
        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            /* Take damage */
            dam = damroll(3, 5);
            msg_print("A branch hits you from above.");

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was heavy!");
                dam = 3 * dam / 2;

                /* stun the player. */
                (void) inc_timed(TMD_STUN, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_print("A falling branch just misses you.");

        /* No more */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_TREE2);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0C:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0D:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0E:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0F:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    }

    /* Revert to usage of the complex RNG. */
    Rand_quick = FALSE;
}
Exemplo n.º 30
0
/*
 * Attack the player via physical attacks.
 */
bool make_attack_normal(int m_idx)
{
	monster_type *m_ptr = &m_list[m_idx];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];
	monster_lore *l_ptr = &l_list[m_ptr->r_idx];

	int ap_cnt;

	int tmp, ac, rlev;
	int do_cut, do_stun, touched;

	char m_name[80];

	char ddesc[80];

	bool blinked;


	/* Not allowed to attack */
	if (r_ptr->flags1 & (RF1_NEVER_BLOW)) return (FALSE);


	/* Total armor */
	ac = p_ptr->ac + p_ptr->to_a;

	/* Extract the effective monster level */
	rlev = ((r_ptr->level >= 1) ? r_ptr->level : 1);


	/* Get the monster name (or "it") */
	monster_desc(m_name, m_ptr, 0);

	/* Get the "died from" information (i.e. "a goblin") */
	monster_desc(ddesc, m_ptr, 0x88);


	/* Assume no blink */
	blinked = FALSE;

	/* Scan through all four blows */
	for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
	{
		bool visible = FALSE;
		bool obvious = FALSE;

		int power = 0;
		int damage = 0;

		cptr act = NULL;

		/* Extract the attack infomation */
		int effect = r_ptr->blow[ap_cnt].effect;
		int method = r_ptr->blow[ap_cnt].method;
		int d_dice = r_ptr->blow[ap_cnt].d_dice;
		int d_side = r_ptr->blow[ap_cnt].d_side;


		/* Hack -- no more attacks */
		if (!method) break;


		/* Handle "leaving" */
		if (p_ptr->leaving) break;

		/* Extract visibility (before blink) */
		if (m_ptr->ml) visible = TRUE;

		/* Skip 'tricky' attacks */
		if (method > RBM_MAX_NORMAL) continue;

		/* Assume no cut or stun or touched */
		do_cut = do_stun = touched = 0;

		/* Extract the attack "power". Elemental attacks upgraded. */
		switch (effect)
		{
			case GF_HURT: power = 60; break;
			case GF_WOUND: power = 60; break;
			case GF_BATTER: power = 60; break;
			case GF_SHATTER: power = 60; break;

			case GF_UN_BONUS:	power = 20; break;
			case GF_UN_POWER:	power = 15; break;
			case GF_LOSE_MANA: power = 45; break;
			case GF_EAT_GOLD:	power =  5; break;
			case GF_EAT_ITEM:	power =  5; break;
			case GF_EAT_FOOD:	power =  45; break;
			case GF_EAT_LITE:	power =  45; break;
			case GF_HUNGER: power = 45; break;

			case GF_POIS:	power =  25; break;
			case GF_ACID:		power = 50; break;
			case GF_ELEC:		power = 50; break;
			case GF_FIRE:		power = 50; break;
			case GF_COLD:		power = 50; break;

			case GF_BLIND:	power =  5; break;
			case GF_CONFUSION:	power = 10; break;
			case GF_TERRIFY:	power = 10; break;
			case GF_PARALYZE:	power =  5; break;
			case GF_HALLU:     power = 10; break;
			case GF_DISEASE:	power = 10; break;

			case GF_LOSE_STR:	power =  0; break;
			case GF_LOSE_DEX:	power =  0; break;
			case GF_LOSE_CON:	power =  0; break;
			case GF_LOSE_INT:	power =  0; break;
			case GF_LOSE_WIS:	power =  0; break;
			case GF_LOSE_CHR:	power =  0; break;
			case GF_LOSE_ALL:	power =  2; break;

			case GF_EXP_10:	power =  5; break;
			case GF_EXP_20:	power =  5; break;
			case GF_EXP_40:	power =  5; break;
			case GF_EXP_80:	power =  5; break;

			/* Need to add extra flavours in here */
		}

		/* Roll out the damage */
		damage = damroll(d_dice, d_side);

		/* Describe the attack method */
		switch (method)
		{
			case RBM_HIT:
			{
				/* Handle special effect types */
				if (effect == GF_WOUND)
				{
					if      (damage >= 30) act = "gouges you";
					else if (damage >= 20) act = "slashes you";
					else if (damage >= 5)  act = "cuts you";
					else                act = "scratches you";

					/* Usually don't stun */
					if (!rand_int(5)) do_stun = 1;

					do_cut = touched = 1;
				}
				else if (effect == GF_BATTER)
				{
					if      (damage >= 30) act = "bludgeons you";
					else if (damage >= 20) act = "batters you";
					else if (damage >= 5)  act = "bashes you";
					else                act = "hits you";

					/* Usually don't cut */
					if (!rand_int(5)) do_cut = 1;

					do_stun = touched = 1;
				}
				else
				{
					act = "hits you";
					do_cut = do_stun = touched = 1;
				}

				break;
			}

			case RBM_TOUCH:
			{
				act = "touches you";
				touched = 1;
				break;
			}

			case RBM_PUNCH:
			{
				act = "punches you";
				do_stun = touched = 1;
				break;
			}

			case RBM_KICK:
			{
				act = "kicks you";
				do_stun = touched = 1;
				break;
			}

			case RBM_CLAW:
			{
				if      (damage >= 25) act = "slashes you";
				else if (damage >=  5) act = "claws you";
				else                act = "scratches you";
				do_cut = touched = 1;
				break;
			}

			case RBM_BITE:
			{
				if (damage >= 5) act = "bites you";
				else          act = "nips you";
				do_cut = touched = 1;
				break;
			}

			case RBM_PECK:
			{
				act = "pecks you";
				do_stun = touched = 1;
				break;
			}

			case RBM_STING:
			{
				act = "stings you";
				touched = 1;
				break;
			}

			case RBM_VOMIT:
			{
				act = "vomits on you";
				touched = 1;
				break;
			}

			case RBM_BUTT:
			{
				if (damage >= rand_range(10, 20)) act = "tramples you";
				else                           act = "butts you";
				do_stun = touched = 1;
				break;
			}

			case RBM_CRUSH:
			{
				if (damage >= 10) act = "crushes you";
				else           act = "squeezes you";
				do_stun = touched = 1;
				break;
			}

			case RBM_ENGULF:
			{
				if (damage >= randint(50)) act = "envelops you";
				else                    act = "engulfs you";
				touched = 1;
				break;
			}

			case RBM_CRAWL:
			{
				act = "crawls on you";
				touched = 1;
				break;
			}

			case RBM_DROOL:
			{
				act = "drools on you";
				break;
			}

			case RBM_SLIME:
			{
				act = "slimes you!";
				break;
			}

			case RBM_SPIT:
			{
				act = "spits on you";
				break;
			}

			case RBM_GAZE:
			{
				if      (damage >= rand_range(20, 30))
					act = "glares at you terribly";
				else if (damage >= rand_range(5, 30))
					act = "gazes upon you";
				else act = "gazes at you";
				break;
			}

			case RBM_WAIL:
			{
				act = "wails horribly";
				break;
			}

			case RBM_SPORE:
			{
				act = "releases a cloud of spores";
				break;
			}

			case RBM_LASH:
			{
				act = "lashes you with a whip";
				touched = 1;
				break;
			}

			case RBM_BEG:
			{
				act = "begs you for money";
				break;
			}

			case RBM_INSULT:
			{
				act = desc_insult[rand_int(8)];
				break;
			}

			case RBM_MOAN:
			{
				act = desc_moan[rand_int(4)];
				break;
			}
		}

		/* Monster hits player */
		if (!effect || check_hit(power, rlev, m_idx))
		{
			/* Always disturbing */
			disturb(1, 0);

			/* Hack -- Apply "protection from evil" */
			if ((p_ptr->protevil > 0) &&
			    (r_ptr->flags3 & (RF3_EVIL)) &&
			    (p_ptr->lev >= rlev) &&
			    ((rand_int(100) + p_ptr->lev) > 50))
			{
				/* Remember the Evil-ness */
				if (m_ptr->ml)
				{
					l_ptr->flags3 |= (RF3_EVIL);
				}

				/* Message */
				msg_format("%^s is repelled.", m_name);

				/* Hack -- Next attack */
				continue;
			}


			/* Message */
			if (act)
			{
				if (damage > p_ptr->chp / 3)
					msg_format("%^s %s!", m_name, act);
				else
					msg_format("%^s %s.", m_name, act);
			}

			/* Check for usage */
			if (rand_int(100)<damage)
			{
				int slot;

				/* Pick a (possibly empty) inventory slot */
				switch (randint(6))
				{
					case 1: slot = INVEN_BODY; break;
					case 2: slot = INVEN_ARM; break;
					case 3: slot = INVEN_OUTER; break;
					case 4: slot = INVEN_HANDS; break;
					case 5: slot = INVEN_HEAD; break;
					case 6: slot = INVEN_FEET; break;
				}

				/* Object used? */
				object_usage(INVEN_WIELD);
			}

			if (effect)
			{
				/* New result routine */
				obvious = project_p(m_idx,0,p_ptr->py,p_ptr->px,damage,effect);
			}
			else
			{
				obvious = TRUE;
			}

			/* Hack -- only one of cut or stun */
			if (do_cut && do_stun)
			{
				/* Cancel cut */
				if (rand_int(100) < 50)
				{
					do_cut = 0;
				}

				/* Cancel stun */
				else
				{
					do_stun = 0;
				}
			}

			/* Handle cut */
			if (do_cut)
			{
				int k;

				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(d_dice, d_side, damage, effect);

				/* Roll for damage */
				switch (tmp)
				{
					case 0: k = 0; break;
					case 1: k = randint(5); break;
					case 2: k = randint(5) + 5; break;
					case 3: k = randint(20) + 20; break;
					case 4: k = randint(50) + 50; break;
					case 5: k = randint(100) + 100; break;
					case 6: k = 300; break;
					default: k = 500; break;
				}

				/* Apply the cut */
				if (k) (void)set_cut(p_ptr->cut + k);
			}

			/* Handle stun */
			if (do_stun)
			{
				int k;

				/* Critical hit (zero if non-critical) */
				tmp = monster_critical(d_dice, d_side, damage, effect);

				/* Roll for damage */
				switch (tmp)
				{
					case 0: k = 0; break;
					case 1: k = randint(5); break;
					case 2: k = randint(8) + 8; break;
					case 3: k = randint(15) + 15; break;
					case 4: k = randint(25) + 25; break;
					case 5: k = randint(35) + 35; break;
					case 6: k = randint(45) + 45; break;
					default: k = 100; break;
				}

				/* Apply the stun */
				if (k) (void)set_stun(p_ptr->stun + k);
			}
		}

		/* Monster missed player */
		else if (touched)
		{
			/* Visible monsters */
			if (m_ptr->ml)
			{
				/* Disturbing */
				disturb(1, 0);

				/* Message */
				msg_format("%^s misses you.", m_name);
			}
		}


		/* Analyze "visible" monsters only */
		if (visible)
		{
			/* Count "obvious" attacks (and ones that cause damage) */
			if (obvious || damage || (l_ptr->blows[ap_cnt] > 10))
			{
				/* Count attacks of this type */
				if (l_ptr->blows[ap_cnt] < MAX_UCHAR)
				{
					l_ptr->blows[ap_cnt]++;
				}
			}
		}
	}


	/* Blink away */
	if (blinked)
	{
		msg_print("There is a puff of smoke!");
		teleport_away(m_idx, MAX_SIGHT * 2 + 5);
	}


	/* Always notice cause of death */
	if (p_ptr->is_dead && (l_ptr->deaths < MAX_SHORT))
	{
		l_ptr->deaths++;
	}


	/* Assume we attacked */
	return (TRUE);
}