/* $Id$ */
/* File: cmd5.c */

/* Purpose: Spell/Prayer commands */

/*
 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
 *
 * This software may be copied and distributed for educational, research, and
 * not for profit purposes provided that this copyright and statement are
 * included in all such copies.
 */

#define SERVER

#include "angband.h"

/* Max radius of antimagic field generated by a monster */
#define MONSTER_ANTIDIS		8

/* Chance of weps/armors got discounted when enchanting via spells,
 * in percent.	[40] */
#define ENCHANT_DISCOUNT_CHANCE	40


#if 0 /* currently disabled because it's unused, just to kill compiler warning */
/*
 * Return the skill associated with the realm
 */
static int find_realm_skill(int realm)
{
        switch (realm)
        {
        case REALM_MAGERY:
                return SKILL_MAGERY;
        case REALM_PRAYER:
                return SKILL_PRAY;
        case REALM_SORCERY:
                return SKILL_SORCERY;
        case REALM_SHADOW:
                return SKILL_SHADOW;
        case REALM_HUNT:
//                return SKILL_ARCHERY;
                return SKILL_HUNTING;
        case REALM_FIGHTING:
//                return SKILL_MASTERY;
                return SKILL_TECHNIQUE;
//        case REALM_PSI:
//                return SKILL_;
        };
        return 0;
}

/*
 * Returns spell chance of failure for spell		-RAK-
 */
static s16b spell_chance(int Ind, int realm, magic_type *s_ptr)
{
	player_type *p_ptr = Players[Ind];

	int chance, minfail, minminfail;

	/* Extract the base spell failure rate */
	chance = s_ptr->sfail;

	/* Reduce failure rate by "effective" level adjustment */
	minfail = 5;
	chance -= 3 * (get_skill(p_ptr, find_realm_skill(realm)) - s_ptr->slevel);

	/* Reduce failure rate by INT/WIS adjustment */
	//chance -= adj_mag_stat[p_ptr->stat_ind[magic_info[realm].spell_stat]] - 3;

	/* Not enough mana to cast */
	if (s_ptr->smana > p_ptr->csp)
	{
		/* Hack -- Since at the moment casting spells without enough mana*/
		/* is impossible, I'm taking this out, as it confuses people. */
		/* chance += 5 * (s_ptr->smana - p_ptr->csp); */
	}

	/* Extract the minimum failure rate */
	//minfail = adj_mag_fail[p_ptr->stat_ind[magic_info[realm].spell_stat]];

	/* Non mage/sorceror/priest characters never get too good */
#if 0 // NEED to find a good way to do that without class
	if ((p_ptr->pclass != CLASS_MAGE) && (p_ptr->pclass != CLASS_PRIEST)
 #ifdef ENABLE_CPRIEST
	    && (p_ptr->pclass != CLASS_CPRIEST)
 #endif
	    && (p_ptr->pclass != CLASS_SORCERER)) {
		if (minfail < 5) minfail = 5;
	}
#else
	minminfail = 8 - get_skill_scale(p_ptr, find_realm_skill(realm), 5)
		- get_skill_scale(p_ptr, SKILL_MAGIC, 3);
	if (minminfail > 5) minminfail = 5;

	if (minfail < minminfail) minfail = minminfail;

#endif
	/* Hack -- Priest prayer penalty for "edged" weapons  -DGK */
	if ((realm == REALM_PRAYER) && (p_ptr->icky_wield)) chance += 25;

	/* Minimum failure rate */
	if (chance < minfail) chance = minfail;

	/* Stunning makes spells harder */
	if (p_ptr->stun > 50) chance += 25;
	else if (p_ptr->stun) chance += 15;

	/* Always a 5 percent chance of working */
	if (chance > 95) chance = 95;

	/* Return the chance */
	return (chance);
}
#endif

/* ok, it's hacked :) */
/* of course, you can optimize it further by bandling
 * monsters and players into one loop..		- Jir - */
bool check_antimagic(int Ind, int percentage) {
	player_type *p_ptr = Players[Ind];
	worldpos *wpos = &p_ptr->wpos;
	monster_type *m_ptr;
	monster_race *r_ptr;
	cave_type **zcave;
	int i, x, y, x2 = p_ptr->px, y2 = p_ptr->py, m_idx;
	int dis, antichance, antidis;

	if (!percentage || !(zcave = getcave(wpos))) return(FALSE);

	for (i = 1; i <= NumPlayers; i++) {
		player_type *q_ptr = Players[i];

		/* Skip disconnected players */
		if (q_ptr->conn == NOT_CONNECTED) continue;

		/* Skip players not on this depth */
		if (!inarea(&q_ptr->wpos, &p_ptr->wpos)) continue;

		/* Compute distance */
		if (q_ptr->antimagic_dis < distance(y2, x2, q_ptr->py, q_ptr->px))
			continue;

		antichance = q_ptr->antimagic;

		if (i != Ind) antichance -= p_ptr->lev >> 1;

		if (antichance > ANTIMAGIC_CAP) antichance = ANTIMAGIC_CAP;/* AM cap */

		/* Reduction for party */
		if ((i != Ind) && player_in_party(p_ptr->party, i))
			antichance = (antichance * (100 - AM_PARTY_REDUCTION)) / 100;

		/* Got disrupted ? */
		if (magik((antichance * percentage) / 100)) {
			if (i == Ind) {
#ifdef USE_SOUND_2010
				if (p_ptr->sfx_am) sound(Ind, "am_field", NULL, SFX_TYPE_MISC, FALSE);
#endif
				msg_format(Ind, "\377%cYour own anti-magic field disrupts your attempts.", COLOUR_AM_OWN);
			} else {
#ifdef USE_SOUND_2010
				sound_pair(Ind, i, "am_field", NULL, SFX_TYPE_MISC);
#endif
				switch (q_ptr->name[strlen(q_ptr->name) - 1]) {
				case 's': case 'x': case 'z':
					msg_format(Ind, "\377%c%s' anti-magic field disrupts your attempts.", COLOUR_AM_PLY, q_ptr->name);
					break;
				default:
					msg_format(Ind, "\377%c%s's anti-magic field disrupts your attempts.", COLOUR_AM_PLY, q_ptr->name);
				}
				switch (p_ptr->name[strlen(p_ptr->name) - 1]) {
				case 's': case 'x': case 'z':
					msg_format(i, "\377%cYour anti-magic field disrupts %s' attempts.", COLOUR_AM_PLY, p_ptr->name);
					break;
				default:
					msg_format(i, "\377%cYour anti-magic field disrupts %s's attempts.", COLOUR_AM_PLY, p_ptr->name);
				}
			}
			return TRUE;
		}
	}

	/* Scan the maximal area of radius "MONSTER_ANTIDIS" */
	dis = 1;
	for (i = 1; i <= tdi[MONSTER_ANTIDIS]; i++) {
		if (i == tdi[dis]) dis++;

		y = y2 + tdy[i];
		x = x2 + tdx[i];

		/* Ignore "illegal" locations */
		if (!in_bounds2(wpos, y, x)) continue;

		if ((m_idx = zcave[y][x].m_idx) <= 0) continue;

		m_ptr = &m_list[m_idx];	// pfft, bad design

		/* dont use removed monsters */
		if (!m_ptr->r_idx) continue;

		r_ptr = race_inf(m_ptr);

		if (!(r_ptr->flags7 & RF7_DISBELIEVE)) continue;

		antichance = r_ptr->level / 2 + 30;
		antidis = r_ptr->level / 15 + 3;

		if (dis > antidis) continue;
		if (antichance > ANTIMAGIC_CAP) antichance = ANTIMAGIC_CAP; /* AM cap */

		/* Got disrupted ? */
		if (magik((antichance * percentage) / 100)) {
			if (p_ptr->mon_vis[m_idx]) {
				char m_name[MNAME_LEN];

				monster_desc(Ind, m_name, m_idx, 0);
				switch (m_name[strlen(m_name) - 1]) {
				case 's': case 'x': case 'z':
					msg_format(Ind, "\377%c%^s' anti-magic field disrupts your attempts.", COLOUR_AM_MON, m_name);
					break;
				default:
					msg_format(Ind, "\377%c%^s's anti-magic field disrupts your attempts.", COLOUR_AM_MON, m_name);
				}
			} else {
				msg_format(Ind, "\377%cAn anti-magic field disrupts your attempts.", COLOUR_AM_MON);
			}
#ifdef USE_SOUND_2010
			sound(Ind, "am_field", NULL, SFX_TYPE_MON_MISC, FALSE);
#endif
			return TRUE;
		}
	}

	/* Assume no antimagic */
	return FALSE;
}

#if 0 /* not used? - mikaelh */
/*
 * Brand the current weapon
 */
static void brand_weapon(int Ind) {
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr;
	o_ptr = &p_ptr->inventory[INVEN_WIELD];

	/* you can never modify artifacts / ego-items */
	/* you can never modify broken / cursed items */
	if ((o_ptr->k_idx) &&
	    (!artifact_p(o_ptr)) && (!ego_item_p(o_ptr)) &&
	    (!broken_p(o_ptr)) && (!cursed_p(o_ptr)))
	{
		cptr act = NULL;

		char o_name[ONAME_LEN];

		if (rand_int(100) < 25) {
			act = "is covered in a fiery shield!";
			o_ptr->name2 = EGO_BRAND_FIRE;
		} else {
			act = "glows deep, icy blue!";
			o_ptr->name2 = EGO_BRAND_COLD;
		}

		object_desc(Ind, o_name, o_ptr, FALSE, 0);

		msg_format(Ind, "Your %s %s", o_name, act);

		enchant(Ind, o_ptr, rand_int(3) + 4, ENCH_TOHIT | ENCH_TODAM);

		/* Hack -- you don't sell the wep blessed by your god, do you? :) */
		o_ptr->discount = 100;
	} else
		msg_print(Ind, "The Branding failed.");
}
#endif // 0

/*
 * Use a ghostly ability. --KLJ--
 */
void do_cmd_ghost_power(int Ind, int ability) {
	player_type *p_ptr = Players[Ind];
	magic_type *s_ptr = &ghost_spells[ability];
	int plev = p_ptr->lev;
	int i, j = 0;

	/* Check for ghost-ness */
	if (!p_ptr->ghost) return;

	/* Must not be confused */
	if (p_ptr->confused) {
		/* Message */
		msg_print(Ind, "You are too confused!");
		return;
	}

	/* Check spells */
	for (i = 0; i < 64; i++) {
		s_ptr = &ghost_spells[i];

		/* Check for existence */
		if (s_ptr->slevel >= 99) continue;

		/* Next spell */
		if (j++ == ability) break;
	}

	/* Check for level */
	if (s_ptr->slevel > plev) {
		/* Message */
		msg_print(Ind, "You aren't powerful enough to use that ability.");
		return;
	}

	/* S(he) is no longer afk */
	un_afk_idle(Ind);

	/* Spell effects */
	switch(i) {
	case 0:
		teleport_player(Ind, 10, TRUE);
		break;
	case 1:
		get_aim_dir(Ind);
		p_ptr->current_spell = 1;
		return;
	case 2:
		get_aim_dir(Ind);
		p_ptr->current_spell = 2;
		return;
	case 3:
		teleport_player(Ind, plev * 8, TRUE);
		break;
	case 4:
		get_aim_dir(Ind);
		p_ptr->current_spell = 4;
		return;
	case 5:
		get_aim_dir(Ind);
		p_ptr->current_spell = 5;
		return;
	case 6:
		get_aim_dir(Ind);
		p_ptr->current_spell = 6;
		return;
	}

	/* Take a turn */
	p_ptr->energy -= level_speed(&p_ptr->wpos);

	take_xp_hit(Ind, s_ptr->slevel * s_ptr->smana,
	    "the strain of ghostly powers", TRUE, TRUE, TRUE, 0);
}


/*
 * Directional ghost ability
 */
void do_cmd_ghost_power_aux(int Ind, int dir) {
	player_type *p_ptr = Players[Ind];
	magic_type *s_ptr;

	/* Verify spell number */
	if (p_ptr->current_spell < 0)
		return;

	/* Acquire spell pointer */
	s_ptr = &ghost_spells[p_ptr->current_spell];

	/* S(he) is no longer afk */
	un_afk_idle(Ind);

	/* We assume everything is still OK to cast */
	switch (p_ptr->current_spell) {
	case 1:
		(void)fear_monster(Ind, dir, 10 + p_ptr->lev + get_skill_scale(p_ptr, SKILL_DEVICE, 50));
		break;
	case 2:
		confuse_monster(Ind, dir, 10 + p_ptr->lev + get_skill_scale(p_ptr, SKILL_DEVICE, 50));
		break;
	case 4:
		sprintf(p_ptr->attacker, " casts a nether bolt for");
		fire_bolt_or_beam(Ind, p_ptr->lev * 2, GF_NETHER, dir, 50 + damroll(5, 5) + p_ptr->lev, p_ptr->attacker);
		break;
	case 5:
		sprintf(p_ptr->attacker, " casts a nether ball for");
		fire_ball(Ind, GF_NETHER, dir, 100 + 2 * p_ptr->lev, 2, p_ptr->attacker);
		break;
	case 6:
		sprintf(p_ptr->attacker, " casts a darkness storm for");
		fire_ball(Ind, GF_DARK, dir, p_ptr->lev * 5 + damroll(10, 10), 3, p_ptr->attacker);
		break;
	}

	/* No more spell */
	p_ptr->current_spell = -1;

	/* Take a turn */
	p_ptr->energy -= level_speed(&p_ptr->wpos);

	take_xp_hit(Ind, s_ptr->slevel * s_ptr->smana,
	    "the strain of ghostly powers", TRUE, TRUE, TRUE, 0);
}

/* old spinning, now unused. Added spin_attack() to replace it - C. Blue */
void do_spin(int Ind) {
	player_type *p_ptr = Players[Ind];
	int d, x, y;

	for (d = 1; d <= 9; d++) {
		if (d == 5) continue;

		x = p_ptr->px + ddx[d];
		y = p_ptr->py + ddy[d];

		if (!in_bounds(y, x)) continue;
		py_attack(Ind, y, x, TRUE);
	}
}

bool mimic_power_hindered(int Ind) {
	player_type *p_ptr = Players[Ind];

	/* No magic */
	if (p_ptr->anti_magic) {
		msg_format(Ind, "\377%cYour anti-magic shell disrupts your attempt.", COLOUR_AM_OWN);
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		return TRUE;
	}
	if (p_ptr->antimagic) {
#ifdef USE_SOUND_2010
		sound(Ind, "am_field", NULL, SFX_TYPE_MISC, FALSE);
#endif
		msg_format(Ind, "\377%cYour anti-magic field disrupts your attempt.", COLOUR_AM_OWN);
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		return TRUE;
	}

	/* Not when confused */
	if (p_ptr->confused) {
		/* Paranoia? Cease fire-till-kill! */
		p_ptr->shooting_till_kill = FALSE;
		p_ptr->shooty_till_kill = FALSE;
		p_ptr->shoot_till_kill_mimic = 0;

		msg_print(Ind, "You are too confused!");
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		return TRUE;
	}

	/* power successfully used */
	return FALSE;
}

static void do_mimic_power(int Ind, int power, int dir) {
	player_type *p_ptr = Players[Ind];
	monster_race *r_ptr = &r_info[p_ptr->body_monster];
	int rlev = (r_ptr->level + p_ptr->lev * 2 + 1) / 3;
	int j, chance;
	magic_type *s_ptr = &innate_powers[power];

	//j = power;

	p_ptr->energy -= level_speed(&p_ptr->wpos);

	if (mimic_power_hindered(Ind)) return;

	j = power / 32;

	if (j < 0 || j > 3) {
		msg_format(Ind, "SERVER ERROR: Tried to use a strange innate power(%d)!", power);
		return;
	}

	/* confirm the power */
	if (!(p_ptr->innate_spells[j] & (1U << (power - j * 32)))) {
		msg_print(Ind, "You cannot use that power.");

		/* Paranoia? Cease fire-till-kill! */
		p_ptr->shooting_till_kill = FALSE;
		p_ptr->shooty_till_kill = FALSE;
		p_ptr->shoot_till_kill_mimic = 0;
		return;
	}

	j = power;

	/* Check mana */
	if (s_ptr->smana > p_ptr->csp) {
		msg_print(Ind, "You do not have enough mana to use this power.");
		//msg_format(Ind, "You need %d mana to use this power.", s_ptr->smana);

		/* Cease fire-till-kill! */
		p_ptr->shooting_till_kill = FALSE;
		p_ptr->shooty_till_kill = FALSE;
		p_ptr->shoot_till_kill_mimic = 0;
		return;
	}

	/* S(he) is no longer afk */
	un_afk_idle(Ind);

#if 0 /* note: currently s_ptr->slevel is always 0 and there is no SKILL_MAGERY (0 too), so chance = sptr->sfail basically. */
	/* Spell failure chance -- Hack, use the same stats as magery*/
//	chance = spell_chance(Ind, REALM_MAGERY, s_ptr);
//	chance = spell_chance(Ind, REALM_MIMIC, s_ptr);
#else /* instead use newly added adj_int_pow[] - C. Blue */
	chance = (s_ptr->sfail * adj_int_pow[p_ptr->stat_ind[A_INT]]) / 100;
	if (chance < 1) chance = 1; /* minimum fail chance */
	if (chance > 99) chance = 99; /* maximum fail chance */
#endif

	if (j >= 32 && interfere(Ind, cfg.spell_interfere)) return; /* mimic spells interference chance */

	/* Failed spell */
	if (rand_int(100) < chance) {
		msg_format(Ind, "\377%cYou failed to use the power!", COLOUR_MD_FAIL);
	/* Clients > 4.4.5.10 can already send a dir != 0 here, for directed spells */
	/* Clients >= 4.4.6.2 can also use '+' (dir==11) fallback to manual mode here: */
	} else if (dir != 0 && dir != 11) {
		p_ptr->current_spell = j;
		do_mimic_power_aux(Ind, dir);
		return;
	}
	/* Non-directed spells // old way of handling directed spells.
	   OR: New way of '+' fallback to manual mode! (dir==11) */
	else {
		/* Hack -- preserve current 'realm' */
		p_ptr->current_realm = REALM_MIMIC;

  /* 0-31 = RF4, 32-63 = RF5, 64-95 = RF6 */
  switch(j) {


/* RF_4 ------------------------------------------------------------------------------------------------- */

//#define RF4_SHRIEK                      0x00000001      /* Shriek for help */
    case 0:
	shriek(Ind);
	break;
//#define RF4_UNMAGIC                     0x00000002      /* Cancel player's timed spell */
    case 1:
      break;
//#define RF4_S_ANIMAL                    0x00000004  /* Summon animals */
    case 2:
	break;
//#define RF4_ROCKET                      0x00000008  /* TY: Rocket */
    case 3:
//#define RF4_ARROW_1			0x00000010	/* Fire an arrow (light) */
    case 4:
//#define RF4_ARROW_2			0x00000020	/* Fire a shot (heavy) */
    case 5:
//#define RF4_ARROW_3			0x00000040	/* Fire a bolt (heavy) */
    case 6:
//#define RF4_ARROW_4			0x00000080	/* Generic missile */
    case 7:
//#define RF4_BR_ACID			0x00000100	/* Breathe Acid */
    case 8:
//#define RF4_BR_ELEC			0x00000200	/* Breathe Elec */
    case 9:
//#define RF4_BR_FIRE			0x00000400	/* Breathe Fire */
    case 10:
//#define RF4_BR_COLD			0x00000800	/* Breathe Cold */
    case 11:
//#define RF4_BR_POIS			0x00001000	/* Breathe Poison */
    case 12:
//#define RF4_BR_NETH			0x00002000	/* Breathe Nether */
    case 13:
//#define RF4_BR_LITE			0x00004000	/* Breathe Lite */
    case 14:
//#define RF4_BR_DARK			0x00008000	/* Breathe Dark */
    case 15:
//#define RF4_BR_CONF			0x00010000	/* Breathe Confusion */
    case 16:
//#define RF4_BR_SOUN			0x00020000	/* Breathe Sound */
    case 17:
//#define RF4_BR_CHAO			0x00040000	/* Breathe Chaos */
    case 18:
//#define RF4_BR_DISE			0x00080000	/* Breathe Disenchant */
    case 19:
//#define RF4_BR_NEXU			0x00100000	/* Breathe Nexus */
    case 20:
//#define RF4_BR_TIME			0x00200000	/* Breathe Time */
    case 21:
//#define RF4_BR_INER			0x00400000	/* Breathe Inertia */
    case 22:
//#define RF4_BR_GRAV			0x00800000	/* Breathe Gravity */
    case 23:
//#define RF4_BR_SHAR			0x01000000	/* Breathe Shards */
    case 24:
//#define RF4_BR_PLAS			0x02000000	/* Breathe Plasma */
    case 25:
//#define RF4_BR_WALL			0x04000000	/* Breathe Force */
    case 26:
//#define RF4_BR_MANA			0x08000000	/* Breathe Mana */
    case 27:
//#define RF4_BR_DISI                     0x10000000  /* Breathe Disintegration */
    case 28:
//#define RF4_BR_NUKE                     0x20000000  /* TY: Toxic Breath */
    case 29:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;
//#define RF4_MOAN                        0x40000000      /* For Halloween event :) -C. Blue */
    case 30:
	break;
// #define RF4_BOULDER			0x80000000
    case 31:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;


/* RF_5 ------------------------------------------------------------------------------------------------- */

// RF5_BA_ACID			0x00000001	/* Acid Ball */
    case 32:
// RF5_BA_ELEC			0x00000002	/* Elec Ball */
    case 33:
// RF5_BA_FIRE			0x00000004	/* Fire Ball */
    case 34:
// RF5_BA_COLD			0x00000008	/* Cold Ball */
    case 35:
// RF5_BA_POIS			0x00000010	/* Poison Ball */
    case 36:
// RF5_BA_NETH			0x00000020	/* Nether Ball */
    case 37:
// RF5_BA_WATE			0x00000040	/* Water Ball */
    case 38:
// RF5_BA_MANA			0x00000080	/* Mana Storm */
    case 39:
// RF5_BA_DARK			0x00000100	/* Darkness Storm */
    case 40:
// RF5_DRAIN_MANA		0x00000200	/* Drain Mana */
    case 41:
//      msg_print(Ind, "Haha, you wish ... :)");
// RF5_MIND_BLAST		0x00000400	/* Blast Mind */
    case 42:
// RF5_BRAIN_SMASH		0x00000800	/* Smash Brain */
    case 43:
//#define RF5_CURSE                       0x00001000      /* Cause Wound */
    case 44:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;
//UNUSED
    case 45:
	break;
//#define RF5_BA_NUKE                     0x00004000  /* TY: Nuke Ball */
    case 46:
//#define RF5_BA_CHAO                     0x00008000  /* Chaos Ball */
    case 47:
// RF5_BO_ACID			0x00010000	/* Acid Bolt */
    case 48:
// RF5_BO_ELEC			0x00020000	/* Elec Bolt (unused) */
    case 49:
// RF5_BO_FIRE			0x00040000	/* Fire Bolt */
    case 50:
// RF5_BO_COLD			0x00080000	/* Cold Bolt */
    case 51:
// RF5_BO_POIS			0x00100000	/* Poison Bolt (unused) */
    case 52:
// RF5_BO_NETH			0x00200000	/* Nether Bolt */
    case 53:
// RF5_BO_WATE			0x00400000	/* Water Bolt */
    case 54:
// RF5_BO_MANA			0x00800000	/* Mana Bolt */
    case 55:
// RF5_BO_PLAS			0x01000000	/* Plasma Bolt */
    case 56:
// RF5_BO_ICEE			0x02000000	/* Ice Bolt */
    case 57:
// RF5_MISSILE			0x04000000	/* Magic Missile */
    case 58:
// RF5_SCARE			0x08000000	/* Frighten Player */
    case 59:
// RF5_BLIND			0x10000000	/* Blind Player */
    case 60:
// RF5_CONF			0x20000000	/* Confuse Player */
    case 61:
// RF5_SLOW			0x40000000	/* Slow Player */
    case 62:
// RF5_HOLD			0x80000000	/* Paralyze Player */
    case 63:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;


/* RF_6 ------------------------------------------------------------------------------------------------- */

// RF6_HASTE			0x00000001	/* Speed self */
    case 64:
	if(!p_ptr->fast) set_fast(Ind, 3 + rlev / 6 + randint(2 + rlev / 4), 10);
	break;
// RF6_HAND_DOOM		0x00000002	/* Should we...? */ /* YES! */
    case 65:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;
// RF6_HEAL			0x00000004	/* Heal self */
    case 66:
	if (p_ptr->lev >= 40) hp_player(Ind, ((rlev + 100) * (rlev + 100)) / 100);//225..400 (335 as eg avg)
	else hp_player(Ind, ((rlev + 5) * (rlev + 30)) / 14);
	//hp_player(Ind, rlev * 2);
	break;
//#define RF6_S_ANIMALS                   0x00000008      /* Summon animals */
    case 67:
	break;
// RF6_BLINK			0x00000010	/* Teleport Short */
    case 68:
	teleport_player(Ind, 10, TRUE);
	break;
// RF6_TPORT			0x00000020	/* Teleport Long */
    case 69:
	teleport_player(Ind, 200, FALSE);
	break;
//#define RF6_RAISE_DEAD                  0x00000040      /* Raise Dead */
    case 70:
	break;
//#define RF6_S_BUG                       0x00000080      /* Summon Software bug */
    case 71:
	break;
//#define RF6_TELE_TO                     0x00000100      /* Move player to monster */
    case 72:
// RF6_TELE_AWAY		0x00000200	/* Move player far away */
    case 73:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;
// RF6_TELE_LEVEL		0x00000400	/* Move player vertically */
    case 74:
    //Disabled to sync with scrolls.      teleport_player_level(Ind, FALSE);	/* wrong way, but useful */
	break;
//#define RF6_S_RNG                       0x00000800      /* Summon RNG */
    case 75:
	break;
// RF6_DARKNESS		0x00001000	/* Create Darkness */
    case 76:
	//unlite_room(Ind, &p_ptr->wpos, p_ptr->py, p_ptr->px); --not really useful, instead let's buff it:
	unlite_area(Ind, TRUE, 10, 3); //causes darkness damage around the player!
      break;
// RF6_TRAPS			0x00002000	/* Create Traps */
    case 77:
// RF6_FORGET			0x00004000	/* Cause amnesia */
    case 78:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;
//      msg_print(Ind, "Haha, you wish ... :)");
	break;


/* RF_0 ------------------------------------------------------------------------------------------------- */

//#define RF0_BO_DISE
    case 96+7:
//#define RF0_BA_DISE
    case 96+8:
//#define RF0_BR_ICE
    case 96+18:
//#define RF0_BR_WATER
    case 96+19:
	p_ptr->current_spell = j;
	get_aim_dir(Ind);
	return;


//following flags are just RF6_S_... summoning spells */
    default:
	msg_format(Ind, "Bad innate power %d.", power);
	break;
    }
	}

	if (s_ptr->smana <= p_ptr->csp) {
		/* Use some mana */
		p_ptr->csp -= s_ptr->smana;
	}
	/* Over-exert the player */
	else {
		int oops = s_ptr->smana - p_ptr->csp;

		/* No mana left */
		p_ptr->csp = 0;
		p_ptr->csp_frac = 0;

		/* Message */
		msg_print(Ind, "You faint from the effort!");

		/* Hack -- bypass free action */
		(void)set_paralyzed(Ind, p_ptr->paralyzed + randint(5 * oops + 1));

		/* Damage CON (possibly permanently) */
		if (rand_int(100) < 50) {
			bool perm = (rand_int(100) < 25);

			/* Message */
			msg_print(Ind, "You have damaged your health!");

			/* Reduce constitution */
			(void)dec_stat(Ind, A_CON, 15 + randint(10), perm);
		}

		/* Cease fire-till-kill! */
		p_ptr->shooting_till_kill = FALSE;
		p_ptr->shooty_till_kill = FALSE;
		p_ptr->shoot_till_kill_mimic = 0;
	}

	/* Display the spellpoints */
	p_ptr->redraw |= (PR_MANA);
}

/*
 * Finish casting a spell that required a direction --KLJ--
 */
/* (Toned down) versions of the hitpoints/x modifiers to determine breath damage as used for monster spells. */
#define MIMIC_DIV2 20
#define MIMIC_DIV3 25
#define MIMIC_DIV4 30
void do_mimic_power_aux(int Ind, int dir) {
	player_type *p_ptr = Players[Ind];
	monster_race *r_ptr = &r_info[p_ptr->body_monster];
	int rad;
	int rlev = (r_ptr->level + p_ptr->lev * 2 + 1) / 3;
	int rlev_bonus;
	magic_type *s_ptr = &innate_powers[p_ptr->current_spell];

#if 1 /* Fire-till-kill */
	int cs = p_ptr->current_spell;

	if (p_ptr->shooting_till_kill) { /* we were shooting till kill last turn? */
		p_ptr->shooting_till_kill = FALSE; /* well, gotta re-test for another success now.. */
		if (dir == 5) p_ptr->shooty_till_kill = TRUE; /* so for now we are just ATTEMPTING to shoot till kill (assumed we have a monster for target) */
	}
#endif

	/* We need to check again here, in case we're called from handle_direction(), even though it's slightly paranoiish */
	if (mimic_power_hindered(Ind)) return;

	if (rlev > 50) rlev = 50;
	rlev_bonus = (rlev * rlev) / 10; /* polynomially growing summand for bolt and ball spells */

	/* Determine the radius of the blast */
	rad = (r_ptr->flags2 & RF2_POWERFUL) ? 3 : 2;

	if (!is_newer_than(&p_ptr->version, 4, 4, 5, 10, 0, 0)) {
		/* Only fire in direction 5 if we have a target */
		if ((dir == 5) && !target_okay(Ind)) {
			/* Reset current spell */
			p_ptr->current_spell = -1;
			/* Done */
			return;
		}
	}
//s_printf("dmpa dir,current_spell=%d,%d\n", dir, p_ptr->current_spell);

	/* We assume that the spell can be cast, and so forth */
	switch(p_ptr->current_spell) {
//#define RF4_ARROW_1			0x00000010	/* Fire arrow(s) (light) */
		/* XXX: ARROW_1 gives extra-shot to the player; we'd better
		 * remove this 'innate' power? (see calc_body_bonus) */
    case 3:
	sprintf(p_ptr->attacker, " fires a rocket for");
	msg_print(Ind, "You fire a rocket.");
	fire_ball(Ind, GF_ROCKET, dir, (((p_ptr->mhp * 10) / MIMIC_DIV2) > 600) ? 600 : ((p_ptr->mhp * 10) / MIMIC_DIV2), rad, p_ptr->attacker);
	break;
    case 4:
	{
		//cool stuff, needs some testing:
		//int k;
		//for (k = 0; k < 1 + rlev / 20; k++) {
			sprintf(p_ptr->attacker, " fires an arrow for");
			msg_print(Ind, "You fire an arrow.");
			fire_bolt(Ind, GF_ARROW, dir, damroll(1 + rlev / 8, 6), p_ptr->attacker);
			break;
		//}
	}
//#define RF4_ARROW_2			0x00000020	/* Fire shot (heavy) */
    case 5:
	sprintf(p_ptr->attacker, " fires a shot for");
	msg_print(Ind, "You fire a shot.");
	fire_bolt(Ind, GF_SHOT, dir, damroll(3 + rlev / 15, 6), p_ptr->attacker);
	break;
//#define RF4_ARROW_3			0x00000040	/* Fire bolt (heavy) */
    case 6:
	sprintf(p_ptr->attacker, " fires a bolt for");
	msg_print(Ind, "You fire a bolt.");
	fire_bolt(Ind, GF_BOLT, dir, damroll(3 + rlev / 15, 6), p_ptr->attacker);
	break;
//#define RF4_ARROW_4			0x00000080	/* Fire generic missile (heavy) */
    case 7:
	sprintf(p_ptr->attacker, " fires a missile for");
	msg_print(Ind, "You fire a missile.");
	fire_bolt(Ind, GF_MISSILE, dir, damroll(3 + rlev / 15, 6), p_ptr->attacker);
	break;
//#define RF4_BR_ACID			0x00000100	/* Breathe Acid */
    case 8:
	sprintf(p_ptr->attacker, " breathes acid for");
	msg_print(Ind, "You breathe acid.");
	fire_ball(Ind, GF_ACID, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 500) ? 500 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_ELEC			0x00000200	/* Breathe Elec */
    case 9:
	sprintf(p_ptr->attacker, " breathes lightning for");
	msg_print(Ind, "You breathe lightning.");
	fire_ball(Ind, GF_ELEC, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 500) ? 500 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_FIRE			0x00000400	/* Breathe Fire */
    case 10:
	sprintf(p_ptr->attacker, " breathes fire for");
	msg_print(Ind, "You breathe fire.");
	fire_ball(Ind, GF_FIRE, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 500) ? 500 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_COLD			0x00000800	/* Breathe Cold */
    case 11:
	sprintf(p_ptr->attacker, " breathes frost for");
	msg_print(Ind, "You breathe frost.");
	fire_ball(Ind, GF_COLD, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 500) ? 500 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_POIS			0x00001000	/* Breathe Poison */
    case 12:
	sprintf(p_ptr->attacker, " breathes gas for");
	msg_print(Ind, "You breathe gas.");
	fire_ball(Ind, GF_POIS, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 450) ? 450 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_NETH			0x00002000	/* Breathe Nether */
    case 13:
	sprintf(p_ptr->attacker, " breathes nether for");
	msg_print(Ind, "You breathe nether.");
	fire_ball(Ind, GF_NETHER, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 450) ? 450 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_LITE			0x00004000	/* Breathe Lite */
    case 14:
	sprintf(p_ptr->attacker, " breathes light for");
	msg_print(Ind, "You breathe light.");
	fire_ball(Ind, GF_LITE, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 400) ? 400 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_DARK			0x00008000	/* Breathe Dark */
    case 15:
	sprintf(p_ptr->attacker, " breathes darkness for");
	msg_print(Ind, "You breathe darkness.");
	fire_ball(Ind, GF_DARK, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 400) ? 400 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_CONF			0x00010000	/* Breathe Confusion */
    case 16:
	sprintf(p_ptr->attacker, " breathes confusion for");
	msg_print(Ind, "You breathe confusion.");
	fire_ball(Ind, GF_CONFUSION, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 350) ? 350 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_SOUN			0x00020000	/* Breathe Sound */
    case 17:
	sprintf(p_ptr->attacker, " breathes sound for");
	msg_print(Ind, "You breathe sound.");
	fire_ball(Ind, GF_SOUND, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 350) ? 350 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_CHAO			0x00040000	/* Breathe Chaos */
    case 18:
	sprintf(p_ptr->attacker, " breathes chaos for");
	msg_print(Ind, "You breathe chaos.");
	fire_ball(Ind, GF_CHAOS, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 450) ? 450 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_DISE			0x00080000	/* Breathe Disenchant */
    case 19:
	sprintf(p_ptr->attacker, " breathes disenchantment for");
	msg_print(Ind, "You breathe disenchantment.");
	fire_ball(Ind, GF_DISENCHANT, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 400) ? 400 : ((p_ptr->chp * 10) / MIMIC_DIV4), rad, p_ptr->attacker);
	break;
//#define RF4_BR_NEXU			0x00100000	/* Breathe Nexus */
    case 20:
	sprintf(p_ptr->attacker, " breathes nexus for");
	msg_print(Ind, "You breathe nexus.");
	fire_ball(Ind, GF_NEXUS, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 250) ? 250 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_TIME			0x00200000	/* Breathe Time */
    case 21:
	sprintf(p_ptr->attacker, " breathes time for");
	msg_print(Ind, "You breathe time.");
	fire_ball(Ind, GF_TIME, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 200) ? 200 : ((p_ptr->chp * 10) / MIMIC_DIV3), rad, p_ptr->attacker);
	break;
//#define RF4_BR_INER			0x00400000	/* Breathe Inertia */
    case 22:
	sprintf(p_ptr->attacker, " breathes inertia for");
	msg_print(Ind, "You breathe inertia.");
	fire_ball(Ind, GF_INERTIA, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 200) ? 200 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_GRAV			0x00800000	/* Breathe Gravity */
    case 23:
	sprintf(p_ptr->attacker, " breathes gravity for");
	msg_print(Ind, "You breathe gravity.");
	fire_ball(Ind, GF_GRAVITY, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 200) ? 200 : ((p_ptr->chp * 10) / MIMIC_DIV3) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_SHAR			0x01000000	/* Breathe Shards */
    case 24:
	sprintf(p_ptr->attacker, " breathes shards for");
	msg_print(Ind, "You breathe shards.");
	fire_ball(Ind, GF_SHARDS, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 350) ? 350 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_PLAS			0x02000000	/* Breathe Plasma */
    case 25:
	sprintf(p_ptr->attacker, " breathes plasma for");
	msg_print(Ind, "You breathe plasma.");
	fire_ball(Ind, GF_PLASMA, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 150) ? 150 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_WALL			0x04000000	/* Breathe Force */
    case 26:
	sprintf(p_ptr->attacker, " breathes force for");
	msg_print(Ind, "You breathe force.");
	fire_ball(Ind, GF_FORCE, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 200) ? 200 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
//#define RF4_BR_MANA			0x08000000	/* Breathe Mana */
    case 27:
	sprintf(p_ptr->attacker, " breathes mana for");
	msg_print(Ind, "You breathe mana.");
	fire_ball(Ind, GF_MANA, dir, (((p_ptr->chp * 10) / MIMIC_DIV3) > 250) ? 250 : ((p_ptr->chp * 10) / MIMIC_DIV3) , rad, p_ptr->attacker);
	break;
/* RF4_BR_DISI */
    case 28:
	sprintf(p_ptr->attacker, " breathes disintegration for");
	msg_print(Ind, "You breathe disintegration.");
	fire_ball(Ind, GF_DISINTEGRATE, dir,
	    (((p_ptr->chp * 10) / MIMIC_DIV3) > 300 ? 300 : ((p_ptr->chp * 10) / MIMIC_DIV3)), rad, p_ptr->attacker);
	break;
/* RF4_BR_NUKE */
    case 29:
	sprintf(p_ptr->attacker, " breathes toxic waste for");
	msg_print(Ind, "You breathe toxic waste.");
	fire_ball(Ind, GF_NUKE, dir,
	    (((p_ptr->chp * 10) / MIMIC_DIV3) > 450 ? 450 : ((p_ptr->chp * 10) / MIMIC_DIV3)), rad, p_ptr->attacker);
	break;
/* RF4_BOULDER */
    case 31:
	sprintf(p_ptr->attacker, " hurls a boulder at you for");
	msg_print(Ind, "You hurl a boulder.");
	fire_bolt(Ind, GF_BOULDER, dir, damroll(1 + rlev / 7, 12), p_ptr->attacker);
	break;

/* RF5 */

// RF5_BA_ACID			0x00000001	/* Acid Ball */
    case 32:
	sprintf(p_ptr->attacker, " casts an acid ball for");
	msg_print(Ind, "You cast an acid ball.");
	fire_ball(Ind, GF_ACID, dir, randint(rlev * 3) + 15 + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_ELEC			0x00000002	/* Elec Ball */
    case 33:
	sprintf(p_ptr->attacker, " casts a lightning ball for");
	msg_print(Ind, "You cast a lightning ball.");
	fire_ball(Ind, GF_ELEC, dir, randint(rlev * 3 / 2) + 8 + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_FIRE			0x00000004	/* Fire Ball */
    case 34:
	sprintf(p_ptr->attacker, " casts a fire ball for");
	msg_print(Ind, "You cast a fire ball.");
	fire_ball(Ind, GF_FIRE, dir, randint(rlev * 7 / 2) + 10 + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_COLD			0x00000008	/* Cold Ball */
    case 35:
	sprintf(p_ptr->attacker, " casts a cold ball for");
	msg_print(Ind, "You cast a cold ball.");
	fire_ball(Ind, GF_COLD, dir, randint(rlev * 2) + 10 + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_POIS			0x00000010	/* Poison Ball */
    case 36:
	sprintf(p_ptr->attacker, " casts a stinking cloud for");
	msg_print(Ind, "You cast a stinking cloud.");
//	fire_ball(Ind, GF_POIS, dir, damroll(12, 2) , rad, p_ptr->attacker);
	fire_cloud(Ind, GF_POIS, dir, damroll(3 + rlev / 3, 2), rad, 4, 9, p_ptr->attacker);
	break;
// RF5_BA_NETH			0x00000020	/* Nether Ball */
    case 37:
	sprintf(p_ptr->attacker, " casts a nether ball for");
	msg_print(Ind, "You cast a nether ball.");
	fire_ball(Ind, GF_NETHER, dir, 50  + damroll(10, 10) + rlev + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_WATE			0x00000040	/* Water Ball */
    case 38:
	sprintf(p_ptr->attacker, " casts a water ball for");
	msg_print(Ind, "You cast a water ball.");
	fire_ball(Ind, GF_WATER, dir, randint(rlev * 5 / 2) + 50 + rlev_bonus / 2, rad, p_ptr->attacker);
	break;
// RF5_BA_MANA			0x00000080	/* Mana Storm */
    case 39:
	sprintf(p_ptr->attacker, " invokes a mana storm for");
	msg_print(Ind, "You invoke a mana storm.");
	fire_ball(Ind, GF_MANA, dir, damroll(10, 10) + (rlev * 2) + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_BA_DARK			0x00000100	/* Darkness Storm */
    case 40:
	sprintf(p_ptr->attacker, " invokes a darkness storm for");
	msg_print(Ind, "You invoke a darkness storm.");
	fire_ball(Ind, GF_DARK, dir, damroll(10, 10) + (rlev * 2) + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF5_MIND_BLAST		0x00000400	/* Blast Mind */
    case 42:
    //sprintf(p_ptr->attacker, " tries to blast your mind for");
	sprintf(p_ptr->attacker, " focusses on your mind for");
	fire_bolt(Ind, GF_PSI, dir, damroll(3 + rlev / 5, 8), "");
	break;
// RF5_BRAIN_SMASH		0x00000800	/* Smash Brain */
    case 43:
	sprintf(p_ptr->attacker, " focusses on your mind for");
	fire_bolt(Ind, GF_PSI, dir, damroll(5 + rlev / 4, 8), "");
	break;
// RF5_CAUSE_1			0x00001000	/* Cause Wound */
    case 44:
#if 0
	sprintf(p_ptr->attacker, " causes wounds for");
	msg_print(Ind, "You cause wounds.");
	fire_bolt(Ind, GF_MANA, dir, damroll(3 + rlev / 4, 8), p_ptr->attacker);
	break;
#else
	{
	int power = 10 + rlev / 2 + randint(rlev / 2);

	sprintf(p_ptr->attacker, " causes wounds for");
	if (power < 15) msg_print(Ind, "You point and curse!");
	else if (power < 35) msg_print(Ind, "You point and curse horribly!");
	else if (power < 50) msg_print(Ind, "You point and incant terribly!");
	else msg_print(Ind, "You scream the word 'DIE'!");
	fire_bolt(Ind, GF_CAUSE, dir, power, p_ptr->attacker);
	break;
	}
#endif
// RF5_CAUSE_2			0x00002000	/* XXX */
    case 45:
	break;
/* RF5_BA_NUKE */
    case 32+14:
	sprintf(p_ptr->attacker, " invokes radiation for");
	msg_print(Ind, "You invoke radiation.");
	fire_ball(Ind, GF_NUKE, dir, (rlev + damroll(10, 6)) + rlev_bonus, 2, p_ptr->attacker);
	break;
/* RF5_BA_CHAO */
    case 32+15:
	sprintf(p_ptr->attacker, " invokes raw chaos for");
	msg_print(Ind, "You invoke raw chaos.");
	fire_ball(Ind, GF_CHAOS, dir, (rlev * 2) + damroll(10, 10) + rlev_bonus, 4, p_ptr->attacker);
	break;
// RF5_BO_ACID			0x00010000	/* Acid Bolt */
    case 48:
	sprintf(p_ptr->attacker, " casts an acid bolt for");
	msg_print(Ind, "You cast an acid bolt.");
	fire_bolt(Ind, GF_ACID, dir, damroll(7, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_ELEC			0x00020000	/* Elec Bolt (unused) */
    case 49:
	sprintf(p_ptr->attacker, " casts a lightning bolt for");
	msg_print(Ind, "You cast a lightning bolt.");
	fire_bolt(Ind, GF_ELEC, dir, damroll(5, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_FIRE			0x00040000	/* Fire Bolt */
    case 50:
	sprintf(p_ptr->attacker, " casts a fire bolt for");
	msg_print(Ind, "You cast a fire bolt.");
	fire_bolt(Ind, GF_FIRE, dir, damroll(8, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_COLD			0x00080000	/* Cold Bolt */
    case 51:
	sprintf(p_ptr->attacker, " casts a frost bolt for");
	msg_print(Ind, "You cast a frost bolt.");
	fire_bolt(Ind, GF_COLD, dir, damroll(6, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_POIS			0x00100000	/* Poison Bolt (unused) */
    case 52:
	sprintf(p_ptr->attacker, " casts a poison bolt for");
	msg_print(Ind, "You cast a poison bolt.");
	fire_bolt(Ind, GF_POIS, dir, damroll(6, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_NETH			0x00200000	/* Nether Bolt */
    case 53:
	sprintf(p_ptr->attacker, " casts a nether bolt for");
	msg_print(Ind, "You cast a nether bolt.");
	fire_bolt(Ind, GF_NETHER, dir, 30 + damroll(5, 5) + (rlev * 3) / 2 + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_WATE			0x00400000	/* Water Bolt */
    case 54:
	sprintf(p_ptr->attacker, " casts a water bolt for");
	msg_print(Ind, "You cast a water bolt.");
	fire_bolt(Ind, GF_WATER, dir, damroll(10, 10) + (rlev) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_MANA			0x00800000	/* Mana Bolt */
    case 55:
	sprintf(p_ptr->attacker, " casts a mana bolt for");
	msg_print(Ind, "You cast a mana bolt.");
	fire_bolt(Ind, GF_MANA, dir, randint(rlev * 7 / 4) + 50 + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_PLAS			0x01000000	/* Plasma Bolt */
    case 56:
	sprintf(p_ptr->attacker, " casts a plasma bolt for");
	msg_print(Ind, "You cast a plasma bolt.");
	fire_bolt(Ind, GF_PLASMA, dir, 10 + damroll(8, 7) + (rlev) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_BO_ICEE			0x02000000	/* Ice Bolt */
    case 57:
	sprintf(p_ptr->attacker, " casts an ice bolt for");
	msg_print(Ind, "You cast an ice bolt.");
	fire_bolt(Ind, GF_ICE, dir, damroll(6, 6) + (rlev) + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF5_MISSILE			0x04000000	/* Magic Missile */
    case 58:
	sprintf(p_ptr->attacker, " fires a magic missile for");
	msg_print(Ind, "You fire a magic missile.");
	fire_bolt(Ind, GF_MISSILE, dir, damroll(2, 6) + (rlev / 3) + rlev_bonus / 5, p_ptr->attacker);
	break;
// RF5_SCARE			0x08000000	/* Frighten Player */
    case 59:
	sprintf(p_ptr->attacker, " focusses on your mind");
	fire_grid_bolt(Ind, GF_TURN_ALL, dir, damroll(2, 6) + (rlev / 3), p_ptr->attacker);
	break;
// RF5_BLIND			0x10000000	/* Blind Player */
    case 60:
	sprintf(p_ptr->attacker, " focusses on your mind");
	fire_grid_bolt(Ind, GF_BLIND, dir, damroll(2, 6) + (rlev / 3), p_ptr->attacker);
	break;
// RF5_CONF			0x20000000	/* Confuse Player */
    case 61:
	sprintf(p_ptr->attacker, " focusses on your mind");
	fire_grid_bolt(Ind, GF_CONFUSION, dir, damroll(2, 6) + (rlev / 3), p_ptr->attacker);
	break;
// RF5_SLOW			0x40000000	/* Slow Player */
    case 62:
	sprintf(p_ptr->attacker, " concentrates on your body");
	fire_grid_bolt(Ind, GF_OLD_SLOW, dir, damroll(2, 6) + (rlev / 3), p_ptr->attacker);
	break;
// RF5_HOLD			0x80000000	/* Paralyze Player */
    case 63:
	sprintf(p_ptr->attacker, " concentrates on your body");
	fire_grid_bolt(Ind, GF_STASIS, dir, damroll(2, 6) + (rlev / 3), p_ptr->attacker);
	break;
// RF6_HAND_DOOM		0x00000002	/* Should we...? */ /* YES! */
    case 65:
	sprintf(p_ptr->attacker, " invokes the hand of doom for");
	msg_print(Ind, "You invoke the hand of doom.");
	(void)project_hook(Ind, GF_HAND_DOOM, dir, 1, PROJECT_STOP | PROJECT_KILL, p_ptr->attacker);
	break;
// RF6_TELE_TO
    case 72:
	sprintf(p_ptr->attacker, " commands you to return");
	(void)project_hook(Ind, GF_TELE_TO, dir, 1, PROJECT_STOP | PROJECT_KILL, p_ptr->attacker);
	break;
// RF6_TELE_AWAY
    case 73:
	sprintf(p_ptr->attacker, " invokes a teleportation spell");
	(void)fire_beam(Ind, GF_AWAY_ALL, dir, rlev, p_ptr->attacker);
	break;
// RF6_TRAPS			0x00002000	/* Create Traps */
    case 77:
	sprintf(p_ptr->attacker, " cackles evilly");
#if 0 /* Note: These traps would be exploitable for xp badly. */
	//msg_print(Ind, "You cackle evilly.");
	fire_ball(Ind, GF_MAKE_TRAP, dir, 1, 1 + rlev / 30, p_ptr->attacker);
#endif
	break;
// RF6_FORGET
    case 78:
	sprintf(p_ptr->attacker, " tries to blank your mind");
	fire_grid_bolt(Ind, GF_CONFUSION, dir, damroll(4, 6) + (rlev / 2), p_ptr->attacker);
	break;

//TODO: implement 96+ mimic spells, aka RF0_, aka innate_spells[3]
/* RF0_BO_DISE */
    case 96+7:
	sprintf(p_ptr->attacker, " casts a disenchantment bolt for");
	msg_print(Ind, "You cast a disenchantment bolt.");
	//fire_bolt(Ind, GF_DISENCHANT, dir, damroll(7, 8) + (rlev / 3) + rlev_bonus / 3, p_ptr->attacker);
	fire_bolt(Ind, GF_DISENCHANT, dir, 25 + damroll(4, 5) + (rlev * 3) / 2 + rlev_bonus / 3, p_ptr->attacker);
	break;
// RF0_BA_DISE			0x00010000	/* Acid Bolt */
    case 96+8:
	sprintf(p_ptr->attacker, " casts a disenchantment ball");
	msg_print(Ind, "You cast a  disenchantment ball.");
	//fire_ball(Ind, GF_DISENCHANT, dir, (rlev * 2) + damroll(10, 10) + rlev_bonus, 4, p_ptr->attacker);
	fire_ball(Ind, GF_DISENCHANT, dir, 60 + damroll(10, 10) + rlev + rlev_bonus, rad, p_ptr->attacker);
	break;
// RF0_BR_ICE
    case 96+18:
	sprintf(p_ptr->attacker, " breathes ice for");
	msg_print(Ind, "You breathe ice.");
	fire_ball(Ind, GF_ICE, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 350) ? 350 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;
// RF5_BR_WATER
    case 96+19:
	sprintf(p_ptr->attacker, " breathes water for");
	msg_print(Ind, "You breathe water.");
	fire_ball(Ind, GF_WATER, dir, (((p_ptr->chp * 10) / MIMIC_DIV4) > 300) ? 300 : ((p_ptr->chp * 10) / MIMIC_DIV4) , rad, p_ptr->attacker);
	break;

	default: /* For some reason we got called for a spell that
		    doesn't require a direction */
		msg_format(Ind, "SERVER ERROR: do_mimic_power_aux() called for non-directional power %d!", p_ptr->current_spell);
		p_ptr->current_spell = -1;
		return;
	}

	//p_ptr->energy -= level_speed(&p_ptr->wpos);

	if (s_ptr->smana <= p_ptr->csp) {
		/* Use some mana */
		p_ptr->csp -= s_ptr->smana;
	}

	/* Over-exert the player */
	else {
		int oops = s_ptr->smana - p_ptr->csp;

		/* No mana left */
		p_ptr->csp = 0;
		p_ptr->csp_frac = 0;

		/* Message */
		msg_print(Ind, "You faint from the effort!");

		/* Hack -- bypass free action */
		(void)set_paralyzed(Ind, p_ptr->paralyzed + randint(5 * oops + 1));

		/* Damage CON (possibly permanently) */
		if (rand_int(100) < 50) {
			bool perm = (rand_int(100) < 25);

			/* Message */
			msg_print(Ind, "You have damaged your health!");

			/* Reduce constitution */
			(void)dec_stat(Ind, A_CON, 15 + randint(10), perm);
		}

		/* Cease fire-till-kill! */
		p_ptr->shooting_till_kill = FALSE;
		p_ptr->shooty_till_kill = FALSE;
		p_ptr->shoot_till_kill_mimic = 0;
	}

	/* Reset current spell */
	p_ptr->current_spell = -1;

	/* Resend mana */
	p_ptr->redraw |= (PR_MANA);

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

#if 1 /* Fire-Till-Kill */
	if (p_ptr->shooty_till_kill) {
		int ftk;
 #if 0
		if (cs < 32) {
			ftk = monster_spell4[cs].ftk;
		} else if (cs < 64) {
			ftk = monster_spell5[cs - 32].ftk;
		} else {
			ftk = monster_spell6[cs - 64].ftk;
		}
 #else
		ftk = innate_powers[cs].ftk;
 #endif
		/* spell actually doesn't allow ftk? */
		if (!ftk) return;

		/* To continue shooting_till_kill, check if spell requires clean LOS to target
		   with no other monsters in the way, so we won't wake up more monsters accidentally. */
 #ifndef PY_PROJ_WALL
		if (ftk == 1 && !projectable_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return;
 #else
		if (ftk == 1 && !projectable_wall_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return;
 #endif

		/* We lost our target? (monster dead?) */
		if (dir != 5 || !target_okay(Ind)) return;

		/* we're now indeed ftk */
		p_ptr->shooting_till_kill = TRUE;
		p_ptr->shoot_till_kill_mimic = cs + 1;
		/* disable other ftk types */
		p_ptr->shoot_till_kill_spell = 0;
		p_ptr->shoot_till_kill_rcraft = FALSE;
		p_ptr->shoot_till_kill_wand = 0;
		p_ptr->shoot_till_kill_rod = 0;
	}
#endif
}

void do_mimic_change(int Ind, int r_idx, bool force) {
	player_type *p_ptr = Players[Ind];

	if (p_ptr->body_monster == r_idx) {
		//already using this form
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		return;
	}

	/* Insufficient skill */
	if (!force && r_info[r_idx].level > get_skill_scale(p_ptr, SKILL_MIMIC, 100)) {
		msg_print(Ind, "You do need a higher mimicry skill to use that shape.");
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		return;
	}

	if (!force && mimic_power_hindered(Ind)) return;

#if 1
	/* Corrupted Priest: Reverse all heavy-cursed boni for true demon form - the only time during which they too get flipped item boni. */
#ifdef VAMPIRES_INV_CURSED
 #ifdef ENABLE_CPRIEST
	if (p_ptr->pclass == CLASS_CPRIEST) {
		if (p_ptr->body_monster != RI_BLOODTHIRSTER && r_idx == RI_BLOODTHIRSTER) {
			int i;

			for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) inverse_cursed(&p_ptr->inventory[i]);
		} else if (p_ptr->body_monster == RI_BLOODTHIRSTER && r_idx != RI_BLOODTHIRSTER) {
			int i;

			for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) reverse_cursed(&p_ptr->inventory[i]);
		}
	}
 #endif
#endif
#endif

	/* mimics can easily restore from chauve-souris fruit bat form */
	if (p_ptr->fruit_bat == 2) p_ptr->fruit_bat = 0;

	p_ptr->body_monster_prev = p_ptr->body_monster;
	p_ptr->body_monster = r_idx;
	p_ptr->body_changed = TRUE;

	if (p_ptr->tim_wraith) p_ptr->tim_wraith = 1; /* in xtra2.c it would prevent regular wraithform on istari */

	if (!force) p_ptr->warning_mimic = 1;

	if (r_idx) {
		msg_format(Ind, "You polymorph into a %s!", r_info[r_idx].name + r_name);
		msg_format_near(Ind, "%s polymorphs into a %s!", p_ptr->name, r_info[r_idx].name + r_name);
	} else {
		msg_print(Ind, "You polymorph back to normal form.");
		msg_format_near(Ind, "%s polymorphs back to normal form.", p_ptr->name);
	}

	break_cloaking(Ind, 0); /* can happen, if vampire rogue! */
	break_shadow_running(Ind); /* can happen, if vampire rogue! */
	stop_precision(Ind);
	stop_shooting_till_kill(Ind);

	note_spot(Ind, p_ptr->py, p_ptr->px);
	everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);

	/* Piece together a 32-bit random seed */
	p_ptr->mimic_seed = (u32b)rand_int(0xFFFF) << 16;
	p_ptr->mimic_seed += rand_int(0xFFFF);

	/* Penalise form-switching just for using a spell */
	//p_ptr->csp /= 2;

	/* Recalculate mana */
	p_ptr->update |= (PU_MANA | PU_HP | PU_BONUS | PU_VIEW);

	/* Tell the client */
	p_ptr->redraw |= PR_VARIOUS | PR_MANA;//PR_MANA was for when p_ptr->csp was reduced as form-switch penalty

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

#if 0 /* 0'ed - keep form 'saved' instead! */
#if POLY_RING_METHOD == 1
	/* clear temporary mimicking from polymorph ring */
	p_ptr->tim_mimic = 0;
	p_ptr->tim_mimic_what = 0;
#endif
#endif
}

void do_cmd_mimic(int Ind, int spell, int dir) {
	player_type *p_ptr = Players[Ind];
	int j, k, offset = 3; /* offset: 3 polymorph powers */
	bool using_free_mimic = FALSE;
	bool admin = is_admin(p_ptr);
	int skill_mimic = get_skill_scale(p_ptr, SKILL_MIMIC, 100);

	/* should it..? */
	//dun_level *l_ptr = getfloor(&p_ptr->wpos);
	//(changed it to no_tele)	if (l_ptr && l_ptr->flags1 & LF1_NO_MAGIC) return;

	if (!skill_mimic) {
		Send_confirm(Ind, PKT_ACTIVATE_SKILL);
		msg_print(Ind, "You are too solid.");
		return;
	}

	/* No anti-magic fields around ? */
	/* Innate powers aren't hindered */
	if ((!spell || spell - offset >= 32) && check_antimagic(Ind, 100)) {
		p_ptr->energy -= level_speed(&p_ptr->wpos);
		return;
	}
	if (spell == 0 || spell == 1) {
		j = p_ptr->body_monster;
		k = 0;

		while (TRUE) {
			j++;
			k++;
			if (k >= MAX_R_IDX - 1) {
				//j = 0;
				msg_print(Ind, "You don't know any forms!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			}

			if (j >= MAX_R_IDX - 1) j = 0;

			if (p_ptr->pclass == CLASS_DRUID) {
				if (mimic_druid(j, p_ptr->lev) || (j == 0)) {
					/* (S)he is no longer afk */
					un_afk_idle(Ind);
					do_mimic_change(Ind, j, TRUE);
					p_ptr->energy -= level_speed(&p_ptr->wpos);
					return;
				} else continue;
			}
			if (p_ptr->prace == RACE_VAMPIRE) {
				if (mimic_vampire(j, p_ptr->lev) || (j == 0)) {
					/* (S)he is no longer afk */
					un_afk_idle(Ind);
					do_mimic_change(Ind, j, TRUE);
					p_ptr->energy -= level_speed(&p_ptr->wpos);
					return;
				} else continue;
			}

			if (r_info[j].level > skill_mimic) continue;
			if (r_info[j].flags1 & RF1_UNIQUE) continue;
			if (r_info[j].flags8 & RF8_PSEUDO_UNIQUE) continue;
			if (p_ptr->r_mimicry[j] < r_info[j].level) continue;
			if (p_ptr->r_mimicry[j] < 1 && j) continue;
			if (strlen(r_info[j].name + r_name) <= 1) continue;
			//if (!r_info[j].level && !mon_allowed(&r_info[j])) continue;
			if (!mon_allowed_chance(&r_info[j])) continue;
			if ((j != 0) && ((p_ptr->pclass == CLASS_SHAMAN) && !mimic_shaman(j))) continue;

			/* Don't accidentally poly into a form that suppresses polymorphing,
			   to do so you need to use 'Polymorph into...' */
			if (r_info[j].flags7 & RF7_DISBELIEVE) continue;

			if (spell == 1) { /* check for extremities matching? */
				if ((p_ptr->inventory[INVEN_HEAD].tval || p_ptr->inventory[INVEN_NECK].tval)
				    && !r_info[j].body_parts[BODY_HEAD]) continue;
				if (p_ptr->inventory[INVEN_ARM].tval
				    && !r_info[j].body_parts[BODY_ARMS]) continue;
				if (p_ptr->inventory[INVEN_HANDS].tval
				    && !(r_info[j].body_parts[BODY_ARMS] && r_info[j].body_parts[BODY_FINGER])) continue;
				if ((p_ptr->inventory[INVEN_WIELD].tval || p_ptr->inventory[INVEN_BOW].tval)
				    && !r_info[j].body_parts[BODY_WEAPON]) continue;
				if (p_ptr->inventory[INVEN_RIGHT].tval
				    && !r_info[j].body_parts[BODY_FINGER]) continue;
				if (p_ptr->inventory[INVEN_LEFT].tval
				    && r_info[j].body_parts[BODY_FINGER] < 2) continue;
				if ((p_ptr->inventory[INVEN_BODY].tval || p_ptr->inventory[INVEN_OUTER].tval || p_ptr->inventory[INVEN_AMMO].tval)
				    && !r_info[j].body_parts[BODY_TORSO]) continue;
				if (p_ptr->inventory[INVEN_FEET].tval
				    && !r_info[j].body_parts[BODY_LEGS]) continue;
				/* combined stuff */
				if (p_ptr->inventory[INVEN_TOOL].tval && !(
				    r_info[j].body_parts[BODY_ARMS] || r_info[j].body_parts[BODY_WEAPON])) continue;
				if (p_ptr->inventory[INVEN_LITE].tval && !(
				    r_info[j].body_parts[BODY_ARMS] || r_info[j].body_parts[BODY_WEAPON] ||
				    r_info[j].body_parts[BODY_FINGER] || r_info[j].body_parts[BODY_HEAD])) continue;
			}

			/* Ok we found */
			break;
		}

		/* (S)he is no longer afk */
		un_afk_idle(Ind);

		do_mimic_change(Ind, j, FALSE);
		if (skill_mimic <= 70) p_ptr->energy -= level_speed(&p_ptr->wpos);
		else p_ptr->energy -= (level_speed(&p_ptr->wpos) * (55 - skill_mimic / 2)) / 20;//1-pt resolution
	} else if (spell >= 20000) { /* hack: 20000 masks poly into.. */
		k = p_ptr->body_monster;

		if (spell == 32767) j = p_ptr->body_monster_prev; /* hack: 32767 marks 'poly into previous' */
		else j = spell - 20000;

		if (p_ptr->pclass == CLASS_DRUID) { /* SPecial ^^ */
			if (mimic_druid(j, p_ptr->lev) || (j == 0)) {
				/* (S)he is no longer afk */
				un_afk_idle(Ind);

				do_mimic_change(Ind, j, TRUE);
				p_ptr->energy -= level_speed(&p_ptr->wpos);
			} else {
				msg_print(Ind, "You cannot use that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
			}
		} else if (p_ptr->prace == RACE_VAMPIRE) {
			if (mimic_vampire(j, p_ptr->lev) || (j == 0)) {
				/* (S)he is no longer afk */
				un_afk_idle(Ind);

				do_mimic_change(Ind, j, TRUE);
				p_ptr->energy -= level_speed(&p_ptr->wpos);
			} else {
				msg_print(Ind, "You cannot use that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
			}
		} else {
			if ((j >= MAX_R_IDX - 1) || (j < 0)) {
				msg_print(Ind, "That form does not exist in the realm!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if (k == j) {
				msg_print(Ind, "You are already using that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if (r_info[j].flags1 & RF1_UNIQUE) {
				msg_print(Ind, "That form is unique!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if (r_info[j].flags8 & RF8_PSEUDO_UNIQUE) {
				msg_print(Ind, "That form is unlearnable!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if (j && p_ptr->r_mimicry[j] < 1
			    && !(p_ptr->tim_mimic && p_ptr->tim_mimic_what == j)
			    && !admin) {
				if (!p_ptr->free_mimic) {
					msg_print(Ind, "You have no experience with that form at all!");
					Send_confirm(Ind, PKT_ACTIVATE_SKILL);
					return;
				} else using_free_mimic = TRUE;
			} else if (p_ptr->r_mimicry[j] < r_info[j].level
			    && !(p_ptr->tim_mimic && p_ptr->tim_mimic_what == j)
			    && !admin) {
				if (!p_ptr->free_mimic) {
					msg_print(Ind, "You have not yet learned that form!");
					Send_confirm(Ind, PKT_ACTIVATE_SKILL);
					return;
				} else using_free_mimic = TRUE;
			}

			if (strlen(r_info[j].name + r_name) <= 1) {	/* <- ??? */
				msg_print(Ind, "You cannot use that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			}
			//if (!r_info[j].level && !mon_allowed(&r_info[j])){	/* <- ? */
			else if (!mon_allowed_chance(&r_info[j])) {	/* ! - C. Blue */
				msg_print(Ind, "You cannot use that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if ((j != 0) && ((p_ptr->pclass == CLASS_SHAMAN) && !mimic_shaman(j))) {
				msg_print(Ind, "You cannot use that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			} else if (r_info[j].level > skill_mimic) {
				msg_print(Ind, "You are not powerful enough to change into that form!");
				Send_confirm(Ind, PKT_ACTIVATE_SKILL);
				return;
			}

			/* using up PvP-mode free mimic transformation? */
			if (j && using_free_mimic) p_ptr->free_mimic--;

			/* Activation tax */
			else if (j && p_ptr->r_mimicry[j] < r_info[j].level
			    && p_ptr->tim_mimic_what == j && p_ptr->tim_mimic > 10)
				p_ptr->tim_mimic -= 10;

			/* Ok we found */
			do_mimic_change(Ind, j, using_free_mimic);
			if (skill_mimic <= 70) p_ptr->energy -= level_speed(&p_ptr->wpos);
			else p_ptr->energy -= (level_speed(&p_ptr->wpos) * (55 - skill_mimic / 2)) / 20;//1-pt resolution
		}
	} else {
		/* (S)he is no longer afk */
		un_afk_idle(Ind);

		do_mimic_power(Ind, spell - offset, dir);
	}
}

/*
 * School spells !
 */
/* Hrm, 'item' should be used for spells like Identify;
 * TODO: revise the PKT_ACTIVATE_SKILL packet type
 */
void cast_school_spell(int Ind, int book, int spell, int dir, int item, int aux) {
	player_type *p_ptr = Players[Ind];
	object_type *o_ptr = &p_ptr->inventory[book];
	int ftk_maybe;
	int ftk_type;
#ifdef ENABLE_XID_SPELL
 #ifdef XID_REPEAT
	/* Note: item and current_item are treated synonymously here, which looks confusing. Could clean this up a bit maybe. */
	bool rep = p_ptr->command_rep_active
	    && p_ptr->current_item != -1; //extra sanity check, superfluous?

	p_ptr->command_rep = 0;
	p_ptr->command_rep_active = FALSE;
	if (rep) item = p_ptr->current_item;
 #endif
#endif

	if (p_ptr->shooting_till_kill) { /* we were shooting till kill last turn? */
		p_ptr->shooting_till_kill = FALSE; /* well, gotta re-test for another success now.. */
		if (dir == 5) p_ptr->shooty_till_kill = TRUE; /* so for now we are just ATTEMPTING to shoot till kill (assumed we have a monster for target) */
	}

	if (!can_use_verbose(Ind, o_ptr)) return;

	if (o_ptr->tval != TV_BOOK) {
		/* log for debugging */
		s_printf("CAST_SCHOOL_SPELL_ERROR: TV_BOOK != %d ('%s')\n", o_ptr->tval, p_ptr->name);

		//msg_print(Ind, "Ahah dont try to hack your client please :) :: tval");
		return;
	} else if (o_ptr->sval == SV_SPELLBOOK) {
		if (o_ptr->pval != spell) {
			/* log for debugging */
			s_printf("CAST_SCHOOL_SPELL_ERROR: SV_SPELLBOOK - %d != %d ('%s')\n", o_ptr->pval, spell, p_ptr->name);

			//msg_print(Ind, "Ahah dont try to hack your client please :) :: sval 255");
			return;
		}
	} else {
		if (MY_VERSION < (4 << 12 | 4 << 8 | 1U << 4 | 8)) {
			if (exec_lua(Ind, format("return spell_in_book(%d, %d)", o_ptr->sval, spell)) == FALSE) {
			/* no longer supported! to make s_aux.lua slimmer */
				/* log for debugging */
				s_printf("CAST_SCHOOL_SPELL_ERROR: MY_VERSION < - %d, %d ('%s')\n", o_ptr->sval, spell, p_ptr->name);

				//msg_print(Ind, "Ahah dont try to hack your client please :) :: sval != 255");
				return;
			}
		} else {
			if (exec_lua(Ind, format("return spell_in_book2(%d, %d, %d)", book, o_ptr->sval, spell)) == FALSE) {
				/* log for debugging */
				s_printf("CAST_SCHOOL_SPELL_ERROR: MY_VERSION >= - %d, %d, %d ('%s')\n", book, o_ptr->sval, spell, p_ptr->name);

				//msg_print(Ind, "Ahah dont try to hack your client please :) :: sval != 255");
				return;
			}
		}
	}

	/* New '+' feat in 4.4.6.2 */
	if (dir == 11) {
		get_aim_dir(Ind);
		p_ptr->current_realm = REALM_SCHOOL;
		p_ptr->current_item = item;
		p_ptr->current_book = book;
		p_ptr->current_spell = spell;
		p_ptr->current_aux = aux;
		return;
	}

	break_cloaking(Ind, 5);
	break_shadow_running(Ind);
	stop_precision(Ind);
	stop_shooting_till_kill(Ind);

	/* No magic */
	if (p_ptr->anti_magic) {
		p_ptr->energy -= level_speed(&p_ptr->wpos); //full turn lost
		msg_format(Ind, "\377%cYour anti-magic shell disrupts any magic attempts.", COLOUR_AM_OWN);
#ifdef ENABLE_XID_SPELL
 #ifndef XID_REPEAT
		p_ptr->current_item = -1;
		XID_paranoia(p_ptr);
 #endif
#endif
		return;
	}
	if (p_ptr->antimagic) {
#ifdef USE_SOUND_2010
		sound(Ind, "am_field", NULL, SFX_TYPE_MISC, FALSE);
#endif
		p_ptr->energy -= level_speed(&p_ptr->wpos); //full turn lost
		msg_format(Ind, "\377%cYour anti-magic field disrupts any magic attempts.", COLOUR_AM_OWN);
#ifdef ENABLE_XID_SPELL
 #ifndef XID_REPEAT
		p_ptr->current_item = -1;
		XID_paranoia(p_ptr);
 #endif
#endif
		return;
	}

	/* Disruption shield prevents interfering! */
	if (!p_ptr->tim_manashield && interfere(Ind, cfg.spell_interfere)) {
		p_ptr->energy -= level_speed(&p_ptr->wpos); //full turn lost
#ifdef ENABLE_XID_SPELL
 #ifndef XID_REPEAT
		p_ptr->current_item = -1;
		XID_paranoia(p_ptr);
 #endif
#endif
		return; /* school spell casting interference chance */
	}

	/* TODO: use energy */

	/* (S)he is no longer afk */
	un_afk_idle(Ind);

#if 0 /* client-side, lacks Ind to set 'player' */
	/* Sanity check for direction */
	if (exec_lua(0, format("return pre_exec_spell_dir(%d)", spell)) && (dir == -1)) return;
#endif

#ifdef LIMIT_SPELLS
	p_ptr->limit_spells = aux;
#endif

	/* Actualy cast the choice */
	if (spell != -1) {
		ftk_maybe = (exec_lua(Ind, format("return cast_school_spell(%d, %d, spell(%d), nil, {dir = %d, book = %d, item = %d, aux = %d})", Ind, spell, spell, dir, book, item, aux)));
		ftk_type = (exec_lua(Ind, format("return get_spell_ftk(%d)", spell)));

#ifdef LIMIT_SPELLS
		p_ptr->limit_spells = 0; //paranoia?
#endif

#ifdef ENABLE_XID_SPELL
 #ifdef XID_REPEAT
		/* hack: repeat ID-spell attempt until item is successfully identified */
		if (rep && ftk_maybe && !object_known_p(Ind, &p_ptr->inventory[item])) {
			sockbuf_t *conn_q = get_conn_q(Ind);
			p_ptr->command_rep = PKT_ACTIVATE_SKILL;
			p_ptr->command_rep_active = TRUE;
			Packet_printf(conn_q, "%c%c%hd%hd%c%hd%hd", PKT_ACTIVATE_SKILL, MKEY_SCHOOL, book, spell, dir, item, aux);
		} else {
			p_ptr->current_item = -1;
			XID_paranoia(p_ptr);
		}
 #else
		p_ptr->current_item = -1;
		XID_paranoia(p_ptr);
 #endif
#endif

		if (!p_ptr->warning_macros && dir != 5 && dir < 10) {
			msg_print(Ind, "\374\377oHINT: Create a '\377Rmacro\377o' aka hotkey to cast a spell with a single keypress!");
			msg_print(Ind, "\374\377o      Press '\377R%\377o' and then '\377Rz\377o' to invoke the macro wizard.");
			p_ptr->warning_macros = 1;
			s_printf("warning_macros (spell): %s\n", p_ptr->name);
		}

#if 1 /* Fire-Till-Kill */
		if (p_ptr->shooty_till_kill && ftk_maybe) {
			/* spell actually doesn't allow ftk? */
			if (ftk_type == 0) return;

			/* To continue shooting_till_kill, check if spell requires clean LOS to target
			   with no other monsters in the way, so we won't wake up more monsters accidentally. */
#ifndef PY_PROJ_WALL
			if (ftk_type == 1 && !projectable_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return;
#else
			if (ftk_type == 1 && !projectable_wall_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return;
#endif

			/* We lost our target? (monster dead?) */
			if (dir != 5 || !target_okay(Ind)) return;

			/* we're now indeed ftk */
			p_ptr->shooting_till_kill = TRUE;
			p_ptr->shoot_till_kill_book = book;
			p_ptr->shoot_till_kill_spell = spell + 1;
			/* disable other ftk types */
			p_ptr->shoot_till_kill_mimic = FALSE;
			p_ptr->shoot_till_kill_rcraft = FALSE;
			p_ptr->shoot_till_kill_wand = FALSE;
			p_ptr->shoot_till_kill_rod = FALSE;
		}
#endif
	}
#ifdef LIMIT_SPELLS
	else p_ptr->limit_spells = aux; //paranoia?
#endif
}

bool cast_rune_spell(int Ind, u16b lo, u16b hi, int dir) {
	player_type *p_ptr = Players[Ind];
	int ftk_maybe, ftk_type;

	/* FTK */
	if (p_ptr->shooting_till_kill) {
		p_ptr->shooting_till_kill = FALSE;
		if (dir == 5) p_ptr->shooty_till_kill = TRUE;
	}
	if (dir == 11) {
		get_aim_dir(Ind);
		p_ptr->current_rcraft = 1;
		p_ptr->current_rcraft_e_flags = lo;
		p_ptr->current_rcraft_m_flags = hi;
		return FALSE;
	}

	/* Paranoia */
	break_cloaking(Ind, 5);
	break_shadow_running(Ind);
	stop_precision(Ind);
	stop_shooting_till_kill(Ind);
	un_afk_idle(Ind);

	/* Cast the spell, handle FTK */
	u32b u = ((u32b)lo) | ((u32b)hi << 16);
	if (u) {
		ftk_maybe = exec_lua(Ind, format("return cast_rune_spell(%d, %d, %d)", Ind, dir, u));
		ftk_type = exec_lua(Ind, format("return rcraft_ftk(%d)", u));
		if (p_ptr->shooty_till_kill && ftk_maybe) {
			if (ftk_type == 0) return FALSE;
#ifndef PY_PROJ_WALL
			if (ftk_type == 1 && !projectable_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return FALSE;
#else
			if (ftk_type == 1 && !projectable_wall_real(Ind, p_ptr->py, p_ptr->px, p_ptr->target_row, p_ptr->target_col, MAX_RANGE)) return FALSE;
#endif
			if (dir != 5 || !target_okay(Ind)) return FALSE;
			p_ptr->shooting_till_kill = TRUE;
			p_ptr->shoot_till_kill_rcraft = TRUE;
			p_ptr->FTK_e_flags = lo;
			p_ptr->FTK_m_flags = hi;
			p_ptr->FTK_energy = exec_lua(Ind, format("return rspell_energy(%d, %d)", Ind, u));
			p_ptr->shoot_till_kill_spell = FALSE;
			p_ptr->shoot_till_kill_mimic = FALSE;
			p_ptr->shoot_till_kill_wand = FALSE;
			p_ptr->shoot_till_kill_rod = FALSE;
		}
		return ftk_maybe; // True if an attempt was made, for auto-retaliation
	}
	return FALSE;
}

/* Mimic powers, moved to their own functions - C. Blue */
void shriek(int Ind) {
	player_type *p_ptr = Players[Ind];

	msg_print(Ind, "You emit a high-pitched humming noise.");
	msg_format_near(Ind, "%s emits a high-pitched humming noise.", p_ptr->name);
#ifdef USE_SOUND_2010
	/* allow us to annoy others ;) */
	sound_near(Ind, "shriek", NULL, SFX_TYPE_MON_SPELL);
#endif
	aggravate_monsters(Ind, -1);
}
