SC/finger/
SC/notes/
SC/player/s/
/* Original by Alathon */

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"

void	add_rune	args( ( CHAR_DATA *ch, int type, int part ) );
void	remove_rune	args( ( CHAR_DATA *ch, int type, int part ) );
void	runecast	args( ( CHAR_DATA *ch, CHAR_DATA *victim, char *arg ) );

const	int	runemax[5] = { 15, 5, 5, 8, 8 };

struct cost_type
{
  int spell;
  int cost;
  int target;
  int wait;
};

const	struct	cost_type	cost_table	[]	=
{
  {	65,	300,	TAR_CHAR_OFFENSIVE,	9	},
  {	66,	300,	TAR_CHAR_OFFENSIVE,	9	},
  {	68,	300,	TAR_CHAR_OFFENSIVE,	9	},
  {	72,	300,	TAR_CHAR_OFFENSIVE,	9	},
  {	80,	750,	TAR_CHAR_DEFENSIVE,	10	},
  {	96,	400,	TAR_CHAR_OFFENSIVE,	10	},
  {	129,	500,	TAR_CHAR_OFFENSIVE,	10	},
  {	132,	500,	TAR_CHAR_OFFENSIVE,	10	},
  {	264,	250,	TAR_CHAR_DEFENSIVE,	10	},
  {	257,	750,	TAR_CHAR_DEFENSIVE,	10	},
  {	272,	100,	TAR_CHAR_DEFENSIVE,	10	},
  {	513,	750,	TAR_CHAR_OFFENSIVE,	9	},
  {	516,	400,	TAR_IGNORE,		10	},
  {	528,	600,	TAR_CHAR_OFFENSIVE,	10	},
  {	544,	500,	TAR_CHAR_OFFENSIVE,	10	},
  {	1025,	200,	TAR_CHAR_SELF,		10	},
  {	1026,	250,	TAR_CHAR_SELF,		10	},
  {	1028,	750,	TAR_CHAR_SELF,		8	},
  {	1032,	100,	TAR_CHAR_SELF,		10	},
  {	1056,	250,	TAR_CHAR_DEFENSIVE,	10	},
  {	2049,	350,	TAR_CHAR_DEFENSIVE,	10	},
  {	2052,	350,	TAR_CHAR_DEFENSIVE,	10	},
  {	2064,	400,	TAR_CHAR_SELF,		10	},
  {	2080,	100,	TAR_CHAR_OFFENSIVE,	10	},
  {	4097,	100,	TAR_CHAR_DEFENSIVE,	10	},
  {	4128,	400,	TAR_CHAR_OFFENSIVE,	8	},
  {	16385,	750,	TAR_CHAR_SELF,		8	},
  {     16386,  750,    TAR_CHAR_SELF,		8	},
  {     16388,  750,    TAR_CHAR_SELF,          8	},
  {     16392,  750,    TAR_CHAR_SELF,          8	},
  {     16400,  750,    TAR_CHAR_SELF,	        8	},
  {     16416,  750,    TAR_CHAR_SELF,          8	}
};


void do_learn( CHAR_DATA *ch, char *argument )
{
  int type = 0;
  int cost = 0;
  char buf[MAX_STRING_LENGTH];

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
  { send_to_char( "\n\rYou simply don't understand rune magic.\n\r", ch );
    return;
  }
  cost = UMIN( 200, 50 + ch->pcdata->powers[P_LEARNED_NUM] * 10 );

  if ( argument[0] == '\0' )
  { send_to_char( "\n\rYou can learn the following runes:\n\r", ch );
    send_to_char( "Primary: earth air fire water energy negative\n\r", ch );
    send_to_char( "Secondary: life death creation destruction protection\n\r", ch );
    send_to_char( "           transformation movement abjuration\n\r", ch );
    return;
  }
  else if ( !str_cmp( argument, "air" ) )
    type = RUNE_AIR;
  else if ( !str_cmp( argument, "earth" ) )
    type = RUNE_EARTH;
  else if ( !str_cmp( argument, "fire" ) )
    type = RUNE_FIRE;
  else if ( !str_cmp( argument, "water" ) )
    type = RUNE_WATER;
  else if ( !str_cmp( argument, "energy" ) )
    type = RUNE_ENERGY;
  else if ( !str_cmp( argument, "negative" ) )
    type = RUNE_NEGATIVE;
  else if ( !str_cmp( argument, "life" ) )
    type = RUNE_LIFE;
  else if ( !str_cmp( argument, "death" ) )
    type = RUNE_DEATH;
  else if ( !str_cmp( argument, "creation" ) )
    type = RUNE_CREATION;
  else if ( !str_cmp( argument, "destruction" ) )
    type = RUNE_DESTRUCTION;
  else if ( !str_cmp( argument, "protection" ) )
    type = RUNE_PROTECTION;
  else if ( !str_cmp( argument, "transformation" ) )
    type = RUNE_TRANSFORMATION;
  else if ( !str_cmp( argument, "movement" ) )
    type = RUNE_MOVEMENT;
  else if ( !str_cmp( argument, "abjuration" ) )
    type = RUNE_ABJURATION;
  else if ( !str_cmp( argument, "cost" ) )
  { sprintf( buf, "\n\rIt will cost you %d primal to learn another rune.\n\r", cost );
    send_to_char( buf, ch );
    return;
  }
  else if ( !str_cmp( argument, "learned" ) )
  {
    return;
  }
  else
  { send_to_char( "Thats not a rune.\n\r", ch );
    return;
  }

  if ( IS_SET(ch->pcdata->powers[P_LEARNED],type) )
  { send_to_char( "But you already know that rune!\n\r", ch );
    return;
  }
  if ( ch->pcdata->primal < cost )
  { send_to_char( "You don't have enough primal to learn another rune.\n\r", ch );
    return;
  }

  ch->pcdata->primal -= cost;
  SET_BIT(ch->pcdata->powers[P_LEARNED],type);
  ch->pcdata->powers[P_LEARNED_NUM]++;
  send_to_char( "You have learned how to use a new rune!\n\r", ch );
  return;
}

void do_runeweave( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  char def1[MAX_STRING_LENGTH];
  char def2[MAX_STRING_LENGTH];
  CHAR_DATA *victim = NULL;
  CHAR_DATA *vch;
  CHAR_DATA *vch_next;
  AFFECT_DATA af;
  int rune1, rune2, spell, slot, i, cost, dam=0, target = TAR_CHAR_SELF;
  bool match = FALSE;


  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN || ch->level < 2 )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }

  /* arguments out of order for kludgy targeting */
  argument = one_argument( argument, arg2 );
  argument = one_argument( argument, arg3 );
  argument = one_argument( argument, arg1 );

  if ( arg2[0] == '\0' || arg3[0] == '\0' )
  { send_to_char( "You must specify two runes to weave.\n\r", ch );
    return;
  }


  if ( !str_prefix( arg2, "air" ) )
    rune1 = RUNE_AIR;
  else if ( !str_prefix( arg2, "earth" ) )
    rune1 = RUNE_EARTH;
  else if ( !str_prefix( arg2, "fire" ) )
    rune1 = RUNE_FIRE;
  else if ( !str_prefix( arg2, "water" ) )
    rune1 = RUNE_WATER;
  else if ( !str_prefix( arg2, "energy" ) )
    rune1 = RUNE_ENERGY;
  else if ( !str_prefix( arg2, "negative" ) )
    rune1 = RUNE_NEGATIVE;
  else
  { sprintf( buf, "You know of no rune of %s.\n\r", arg2 );
    send_to_char( buf, ch );
    return;
  }

  if ( !str_prefix( arg3, "life" ) )
    rune2 = RUNE_LIFE;
  else if ( !str_prefix( arg3, "death" ) )
    rune2 = RUNE_DEATH;
  else if ( !str_prefix( arg3, "creation" ) )
    rune2 = RUNE_CREATION;
  else if ( !str_prefix( arg3, "destruction" ) )
    rune2 = RUNE_DESTRUCTION;
  else if ( !str_prefix( arg3, "protection" ) )
    rune2 = RUNE_PROTECTION;
  else if ( !str_prefix( arg3, "transformation" ) )
    rune2 = RUNE_TRANSFORMATION;
  else if ( !str_prefix( arg3, "movement" ) )
    rune2 = RUNE_MOVEMENT;
  else if ( !str_prefix( arg3, "abjuration" ) )
    rune2 = RUNE_ABJURATION;
  else
  { sprintf( buf, "You know of no rune of %s.\n\r", arg3 );
    send_to_char( buf, ch );
    return;
  }

  if ( !IS_SET(ch->pcdata->powers[P_LEARNED],rune1) || !IS_SET(ch->pcdata->powers[P_LEARNED],rune2) )
  { send_to_char( "You have not learned the uses of that rune.\n\r", ch );
    return;
  }

  spell = rune1 + rune2;
  slot = 0; cost = 30000;
  while ( slot < MAX_RUNESPELLS && !match )
  {
    if ( cost_table[slot].spell == spell )
    {
      match = TRUE;
      cost = cost_table[slot].cost;
      target = cost_table[slot].target;
    }
    else
     slot++;
  }

  if ( !match )
  { send_to_char( "There is no such spell..yet.\n\r", ch );
    return;
  }
  if ( ch->mana < cost )
  { send_to_char( "You don't have enough mana.\n\r", ch );
    return;
  }

  if ( cost_table[slot].target == TAR_CHAR_SELF || cost_table[slot].target == TAR_IGNORE )
    victim = ch;
  else if ( cost_table[slot].target == TAR_CHAR_OFFENSIVE )
  { if ( arg1[0] == '\0' )
    { if ( ch->fighting != NULL )
        victim = ch->fighting;
      else
      { send_to_char( "Weave at who?\n\r", ch );
        return;
      }
    }
    else if ( ( victim = get_char_room( ch, arg1 ) ) == NULL )
    {
      send_to_char( "They aren't here.\n\r", ch );
      WAIT_STATE( ch, 4 );
      return;
    }
    timer_check( ch, victim );
  }
  else
  { if ( arg1[0] == '\0' )
      victim = ch;
    else if ( ( victim = get_char_room( ch, arg1 ) ) == NULL )
    { send_to_char( "They aren't here.\n\r", ch );
      return;
    }
  }

  if ( !IS_NPC(victim) && victim->level < 2 )
  { send_to_char( "No runeweaving on mortals.\n\r", ch );
    return;
  }

  sprintf( def1, "You move your hands in mystick patterns, uttering runes under your breath." );
  sprintf( def2, "$n moves $s hands in a complex pattern, while muttering broken phrases." );

  switch( spell )
  {
    case RUNE_AIR + RUNE_LIFE:
    	if ( is_affected(victim,gsn_wind_curse) )
    	{
    	  stc( "They are already so cursed.\n\r", ch );
    	  break;
    	}
    	act( "A pale blue mist settles around $N.", ch, NULL, victim, TO_CHAR );
    	act( "A pale blue mist settles around $N.", ch, NULL, victim, TO_ROOM );
        af.type      = gsn_wind_curse;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind *2/3;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_EARTH + RUNE_LIFE:
        if ( is_affected(victim,gsn_earth_curse) )
        {
          stc( "They are already so cursed.\n\r", ch );
          break;
        }
        act( "A dull yellow mist settles around $N.", ch, NULL, victim, TO_CHAR );
        act( "A dull yellow mist settles around $N.", ch, NULL, victim, TO_ROOM );
        af.type      = gsn_earth_curse;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind *2/3; 
        af.bitvector = 0 *2/3;;
        affect_to_char( victim, &af );
        break;
    case RUNE_FIRE + RUNE_LIFE:
        if ( is_affected(victim,gsn_flame_curse) )
        {
          stc( "They are already so cursed.\n\r", ch );
          break;
        }
        act( "A blood red mist settles around $N.", ch, NULL, victim, TO_CHAR );
        act( "A blood red mist settles around $N.", ch, NULL, victim, TO_ROOM );
        af.type      = gsn_flame_curse;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind *2/3;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_WATER + RUNE_LIFE:
        if ( is_affected(victim,gsn_water_curse) )
        {
          stc( "They are already so cursed.\n\r", ch );
          break;
        }
        act( "A murky mist settles around $N.", ch, NULL, victim, TO_CHAR );
        act( "A murky mist settles around $N.", ch, NULL, victim, TO_ROOM );
        af.type      = gsn_water_curse;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind *2/3;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    /* ENERGY + LIFE */
    case 80:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	for ( i = 0; i < ch->pcdata->powers[P_ENERGY]; i += 33 )
	  runecast( ch, victim, "heal" );
	break;
    /* NEGATIVE + LIFE */
    case 96:
    	if ( !IS_NPC(victim) && IS_SET(victim->pcdata->actnew,NEW_NEGATIVE_BLOCK) )
    	{
    	  if ( victim == ch )
    	  {
    	    stc( "You failed.\n\r", ch );
    	    return;
    	  }
    	  act( "Dark energy streaks toward and is absorbed by $N.", ch, NULL, victim, TO_CHAR );
    	  act( "Dark energy streaks toward and is absorbed by you!", ch, NULL, victim, TO_VICT );
    	  act( "Dark energy streaks toward and is absorbed by $N.", ch, NULL, victim, TO_NOTVICT );
	  victim->hit += dice( ch->pcdata->mind/8, ch->pcdata->powers[P_NEGATIVE] );
	  victim->hit = UMIN( victim->hit, victim->max_hit );
    	}
    	else
    	{
    	  act( "Dark energy streaks from you to $N, and rebounds!", ch, NULL, victim,TO_CHAR);
    	  act( "Dark energy streaks from $n to you, and rebounds to $m!", ch, NULL, victim, TO_VICT );
    	  act( "Dark energy streaks from $n to $N, then rebounds.", ch, NULL, victim, TO_NOTVICT );
    	  dam = dice( ch->pcdata->mind/4, ch->pcdata->powers[P_NEGATIVE] );
    	  i = victim->hit;
    	  damage( ch, victim, dam, DAM_NEGATIVE );
    	  if ( victim != NULL && victim->hit > 0 )
    	    ch->hit = UMIN( ch->max_hit, ch->hit + (i - victim->hit) );
	}
    	break;

    /* AIR + DEATH */
    case 129:
    	act( "A bolt of lightning leaps from your fingers toward $N!", ch, NULL, victim, TO_CHAR );
    	act( "A bolt of lightning leaps from $n's fingers toward you!", ch, NULL, victim, TO_VICT );
    	act( "A bolt of lightning leaps from $n's fingers toward $N!", ch, NULL, victim, TO_NOTVICT );
        if ( !IS_NPC(victim) && IS_SET(victim->pcdata->actnew,NEW_AIR_BLOCK) )
        { act( "The lightning bolt rebounds!", ch, NULL, NULL, TO_CHAR );
          act( "The lightning bolt rebounds!", ch, NULL, NULL, TO_ROOM );
          dam = dice( ch->pcdata->mind / 4, ch->pcdata->powers[P_AIR] );
	  damage( ch, ch, dam, DAM_LIGHTNING );
          break;
        }
        else
        {
	  dam = dice( ch->pcdata->mind / 2, ch->pcdata->powers[P_AIR] );
	  damage( ch, victim, dam, DAM_LIGHTNING );
	}
	break;
    /* FIRE + DEATH */
    case 132:
	act( "A lance of flame streaks from your fingers toward $N!", ch, NULL, victim, TO_CHAR );
	act( "A lance of flame streaks from $n's fingers toward you!", ch, NULL, victim, TO_VICT );
	act( "A lance of flame streaks from $n's fingers toward $N!", ch, NULL, victim, TO_NOTVICT );
	if ( !IS_NPC(victim) && IS_SET(victim->pcdata->actnew,NEW_FIRE_BLOCK) )
	{ act( "The flame lance rebounds!", ch, NULL, NULL, TO_CHAR );
	  act( "The flame lance rebounds!", ch, NULL, NULL, TO_ROOM );
	  dam = dice( ch->pcdata->mind / 4, ch->pcdata->powers[P_AIR] );
	  damage( ch, ch, dam, DAM_FIRE );
	  break;
	}
	else
	{ dam = dice( ch->pcdata->mind / 2, ch->pcdata->powers[P_FIRE] );
          if ( !IS_NPC(victim) && IS_SET(victim->pcdata->actnew,NEW_VAN_REHL) )
          { REMOVE_BIT(victim->pcdata->actnew,NEW_VAN_REHL);
            act( "Their icy barrier melts!", ch, NULL, victim, TO_CHAR );
            act( "Your icy barrier melts!", ch, NULL, victim, TO_VICT );
          }
	  damage( ch, victim, dam, DAM_FIRE );
	}
	break;
    /* AIR + CREATION */
    case 257:
    	if ( IS_NPC(victim) )
    	{
    	  stc( "Nothing happens.\n\r", ch );
    	  return;
    	}
    	act( "Ball lightning crackles around $N.", ch, NULL, victim, TO_CHAR );
    	act( "Ball lightning crackles around $N.", ch, NULL, victim, TO_ROOM );
    	if ( !IS_SET(victim->pcdata->actnew,NEW_BALL_LIGHTNING) )
    	  SET_BIT(victim->pcdata->actnew,NEW_BALL_LIGHTNING);
    	break;
    /* WATER + CREATION */
    case 264:
        act( def1, ch, NULL, victim, TO_CHAR );
        act( def2, ch, NULL, victim, TO_ROOM );
        if ( is_affected(victim,skill_lookup("flame breath")) )
        {
          affect_strip(victim,skill_lookup("flame breath"));
          act( "The flames are doused.", ch, NULL, victim, TO_CHAR );
          act( "Your skin abruptly stops burning.", ch, NULL, victim, TO_VICT );
          act( "The flames burning $N are doused.", ch, NULL, victim, TO_ROOM );
        }
        break;
    /* ENERGY + CREATION */
    case 272:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	if ( ch->pcdata->powers[P_ENERGY] < 25 )
	  runecast( ch, victim, "cure light" );
	else if ( ch->pcdata->powers[P_ENERGY] < 50 )
	  runecast( ch, victim, "cure serious" );
	else if ( ch->pcdata->powers[P_ENERGY] < 75 )
	{
	  runecast( ch, victim, "cure critical" );
	  runecast( ch, victim, "refresh" );
	}
	else
	{
	  runecast( ch, victim, "heal" );
	  runecast( ch, victim, "refresh" );
	  runecast( ch, victim, "cure poison" );
	}
	break;
    /* AIR + DESTRUCTION */
    case 513:
    	act( "You launch a gust of wind into $N.", ch, NULL, victim, TO_CHAR );
    	act( "$n's gust of wind slams into you!", ch, NULL, victim, TO_VICT );
    	act( "$n's gust of wind slams into $N.", ch, NULL, victim, TO_NOTVICT );
    	if ( !IS_NPC(victim) )
    	{ if ( victim->class == CLASS_FIST )
    	  { if ( IS_SET(victim->pcdata->actnew,NEW_FIGUREEIGHT) )
	      REMOVE_BIT(victim->pcdata->actnew,NEW_FIGUREEIGHT);
	    if ( victim->pcdata->powers[F_KI] > 0 )
	      victim->pcdata->powers[F_KI]--;
	  }
	  else if ( IS_CLASS(victim,CLASS_SORCERER ) )
	    lose_chant( victim );

	  if ( is_affected(victim,gsn_kiwall) )
	    affect_strip(victim,gsn_kiwall);

        }
        break;
    /* FIRE + DESTRUCTION */
    case 516:
	act( "Fire sprays forth from your hands, engulfing the room in flame!", ch, NULL, victim, TO_CHAR );
	act( "The room is is engulfed in flame!", ch, NULL, victim, TO_ROOM );
	for ( vch = char_list; vch != NULL; vch = vch_next )
	{ vch_next = vch->next;
	  if ( vch->in_room == NULL )
	    continue;
	  if ( vch->in_room == ch->in_room )
	  { if ( vch != ch && !is_same_group( ch, vch ) )
	    { if ( !IS_NPC(vch) && IS_SET(vch->pcdata->actnew,NEW_FIRE_BLOCK) )
	      { act( "The flames flow around $N.", ch, NULL, vch, TO_CHAR );
	        act( "The flames flow around you.", ch, NULL, vch, TO_VICT );
	        act( "The flames flow around $N.", ch, NULL, vch, TO_ROOM );
	      }
	      else
	      { dam = dice( ch->pcdata->mind / 4, ch->pcdata->powers[P_FIRE] );
	        if ( !IS_NPC(vch) && IS_SET(vch->pcdata->actnew,NEW_VAN_REHL) )
	        { REMOVE_BIT(vch->pcdata->actnew,NEW_VAN_REHL);
	          act( "Their icy barrier melts!", ch, NULL, vch, TO_CHAR );
	          act( "Your icy barrier melts!", ch, NULL, vch, TO_VICT );
	        }
	        damage( ch, vch, dam, DAM_FIRE );
	      }
	    }
	  }
	}
	break;
    /* ENERGY + DESTRUCTION */
    case 528:
	runecast( ch, victim, "dispel magic" );
	if ( victim != ch && victim->fighting == NULL )
	  victim->fighting = ch;
	break;
    /* NEGATIVE + DESTRUCTION */
    case 544:
    	act( "You launch a pearlescent ball of light at $N.", ch, NULL, victim, TO_CHAR );
    	act( "$n launches a pearlescent ball of light at you!", ch, NULL, victim, TO_VICT );
    	act( "$n launches a pearlescent ball of light at $N.", ch, NULL, victim, TO_NOTVICT );
    	if ( !IS_CLASS(victim,CLASS_MAZOKU) )
    	  break;
    	if ( victim->pcdata->powers[M_CTIME] <= 0 )
    	  break;
    	act( ".. the dark energies surrounding $N are dispelled!", ch, NULL, victim, TO_CHAR );
    	act( ".. you lose control of your dark energies!", ch, NULL, victim, TO_VICT );
    	act( ".. the dark energies surrounding $N are dispelled!", ch, NULL, victim, TO_NOTVICT );
    	victim->pcdata->powers[M_CTIME] = 0;
    	victim->pcdata->powers[M_CTYPE] = 0;
	break;
    /* AIR + PROTECTION */
    case 1025:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	runecast( ch, victim, "shield" );
	break;
    /* EARTH + PROTECTION */
    case 1026:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	runecast( ch, victim, "stone skin" );
	break;
    /* FIRE + PROTECTION */
    case 1028:
        if ( is_affected( ch, gsn_balus_wall ) )
        affect_strip( ch, gsn_balus_wall );
      
        af.type      = gsn_balus_wall;
        af.duration  = 30;
        af.location  = APPLY_NONE;
        af.modifier  = 0;
        af.bitvector = 0;
        affect_to_char( ch, &af );
	act( "A reddish shield shimmers into existance in front of you.", ch, NULL, NULL, TO_CHAR );
	act( "A reddish shield shimmers into existance in front of $n.", ch, NULL, NULL, TO_ROOM );
	break;
    /* WATER + PROTECTION */
    case 1032:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	runecast( ch, victim, "armor" );
	break;
    case 1056:
    /* NEGATIVE + PROTECTION */
    	if ( IS_NPC(victim) )
    	{ 
    	  stc( "All your base are belong to us.\n\r", ch );
    	  return;
    	}
    	act( "A black helix swirls up around you.", victim, NULL, NULL, TO_CHAR );
    	act( "A black helix swirls up around $n.", victim, NULL, NULL, TO_ROOM );
    	if ( !IS_SET(victim->pcdata->actnew,NEW_NEGATIVE_BLOCK) )
    	  SET_BIT(victim->pcdata->actnew,NEW_NEGATIVE_BLOCK);
    	break;
    /* AIR + TRANSFORMATION */
    case 2049:
    	if ( IS_NPC(victim) )
    	{ act( "You failed.", ch, NULL, NULL, TO_CHAR );
    	  break;
    	}
    	act( "Inverted runes of air swirl up around you.", victim, NULL, NULL, TO_CHAR );
    	act( "Oddly disfigured runes swirl up around $n.", victim, NULL, NULL, TO_ROOM );
    	if ( IS_SET(victim->pcdata->actnew,NEW_FIRE_BLOCK) )
    	{ REMOVE_BIT(victim->pcdata->actnew,NEW_FIRE_BLOCK);
    	  act( "The inverted fire runes crumble.", ch, NULL, NULL, TO_CHAR );
    	}
    	SET_BIT(victim->pcdata->actnew,NEW_AIR_BLOCK);
    	break;
    case 2052:
        if ( IS_NPC(victim) )
        { act( "You failed.", ch, NULL, NULL, TO_CHAR );
          break;
        }
        act( "Inverted runes of fire ignite all around you.", victim, NULL, NULL, TO_CHAR );
        act( "Oddly disfigured runes ignite all around $n.", victim, NULL, NULL, TO_ROOM );
        if ( IS_SET(victim->pcdata->actnew,NEW_AIR_BLOCK) )
        { REMOVE_BIT(victim->pcdata->actnew,NEW_AIR_BLOCK);
          act( "The inverted air runes fade away.", ch, NULL, NULL, TO_CHAR );
        }
        SET_BIT(victim->pcdata->actnew,NEW_FIRE_BLOCK);
        break;

    /* ENERGY + TRANSFORMATION */
    case 2064:
        if ( IS_SET(ch->act, PLR_TRUESIGHT) )
        { send_to_char( "Your vision returns to normal.\n\r", ch );
          REMOVE_BIT(ch->act,PLR_TRUESIGHT);
        }
        else
        { send_to_char( "Your vision increases beyond mortal standards.\n\r", ch );
          SET_BIT(ch->act,PLR_TRUESIGHT);
        }
        break;
    /* NEGATIVE + TRANSFORMATION */
    case 2080:
        if ( !IS_NPC(victim) && IS_SET(victim->pcdata->actnew,NEW_NEGATIVE_BLOCK) )
        {
          if ( victim == ch )
          {
            stc( "You failed.\n\r", ch );
            return;
          }
          act( "Dark energy streaks toward and is absorbed by $N.", ch, NULL, victim, TO_CHAR );
          act( "Dark energy streaks toward and is absorbed by you!", ch, NULL, victim, TO_VICT );
          act( "Dark energy streaks toward and is absorbed by $N.", ch, NULL, victim, TO_NOTVICT
);
          victim->mana += dice( ch->pcdata->mind/4, ch->pcdata->powers[P_NEGATIVE] );
          victim->mana = UMIN( victim->mana, victim->max_mana );
        }
        else
        {
          act( "Dark energy streaks from you to $N, and rebounds!", ch, NULL, victim,TO_CHAR);
          act( "Dark energy streaks from $n to you, and rebounds to $m!", ch, NULL, victim, TO_VICT );
          act( "Dark energy streaks from $n to $N, then rebounds.", ch, NULL, victim, TO_NOTVICT );
          dam = dice( ch->pcdata->mind/4, ch->pcdata->powers[P_NEGATIVE] );
          if ( IS_AFFECTED(victim,AFF_HOLY_RESIST) )
            dam -= dam * number_percent() / 100;
          if ( victim->mana > dam )
            victim->mana -= dam;
          else
          { dam = victim->mana - 1;
            victim->mana = 1;
          }
          ch->mana = UMIN( ch->max_mana, ch->mana + dam/2 );
        }
        break;
    case RUNE_AIR + RUNE_MOVEMENT:
	act( def1, ch, NULL, victim, TO_CHAR );
	act( def2, ch, NULL, victim, TO_ROOM );
	runecast( ch, ch, "fly" );
	break;
    case RUNE_NEGATIVE + RUNE_MOVEMENT:
    	act( "A black haze surrounds you, sapping your strength!", ch, NULL, victim, TO_VICT );
    	act( "A black haze descends upon $N", ch, NULL, victim, TO_CHAR );
    	act( "A black haze descends upon $N", ch, NULL, victim, TO_ROOM );
    	dam = dice( 10, 15 );
    	victim->move = UMAX( victim->move - dam, 1 );
    	ch->move = UMIN( ch->move + dam, ch->max_move );
    	if ( IS_CLASS(victim, CLASS_SAIYAN) )
    	{
    	  victim->pcdata->powers[S_STRENGTH] = UMAX(
    	    victim->pcdata->powers[S_STRENGTH] - dam,
    	    victim->pcdata->powers[S_STRENGTH_MAX]/2 );
    	  victim->pcdata->powers[S_SPEED] = UMAX(
    	    victim->pcdata->powers[S_SPEED] - dam,
    	    victim->pcdata->powers[S_SPEED_MAX]/2 );
    	  victim->pcdata->powers[S_AEGIS] = UMAX(
    	    victim->pcdata->powers[S_AEGIS] - dam,
    	    victim->pcdata->powers[S_AEGIS_MAX]/2 );
    	}
    	break;
    case RUNE_AIR + RUNE_ABJURATION:
   	act( "A dome of azure energy encases you.", ch, NULL, victim, TO_CHAR );
   	act( "A dome of azure energy encases $n.", ch, NULL, victim, TO_ROOM );
	if ( is_affected( ch, gsn_earth_ward ) )
	  affect_strip( ch, gsn_earth_ward );
	if ( is_affected( ch, gsn_wind_ward ) )
	  affect_strip( ch, gsn_wind_ward ) ;
	if ( is_affected( ch, gsn_flame_ward ) )
	  affect_strip( ch, gsn_flame_ward );
	if ( is_affected( ch, gsn_water_ward ) )
	  affect_strip( ch, gsn_water_ward );
	if ( is_affected( ch, gsn_spirit_ward ) )
	  affect_strip( ch, gsn_spirit_ward );
	if ( is_affected( ch, gsn_negative_ward ) )
	  affect_strip( ch, gsn_negative_ward );
	af.type      = gsn_wind_ward;
   	af.location  = 0;
   	af.modifier  = 0;
   	af.duration  = ch->pcdata->mind*15;
   	af.bitvector = 0;
   	affect_to_char( ch, &af );
   	break;
    case RUNE_EARTH + RUNE_ABJURATION:
        act( "A dome of verdant energy encases you.", ch, NULL, victim, TO_CHAR );
        act( "A dome of verdant energy encases $n.", ch, NULL, victim, TO_ROOM );
        if ( is_affected( ch, gsn_wind_ward ) )
          affect_strip( ch, gsn_wind_ward );
        if ( is_affected( ch, gsn_earth_ward ) )
          affect_strip( ch, gsn_earth_ward );
        if ( is_affected( ch, gsn_flame_ward ) )
          affect_strip( ch, gsn_flame_ward );
        if ( is_affected( ch, gsn_water_ward ) )
          affect_strip( ch, gsn_water_ward );
        if ( is_affected( ch, gsn_spirit_ward ) )
          affect_strip( ch, gsn_spirit_ward );
        if ( is_affected( ch, gsn_negative_ward ) )
          affect_strip( ch, gsn_negative_ward );
        af.type      = gsn_earth_ward;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind*15;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_FIRE + RUNE_ABJURATION:
        act( "A dome of crimson energy encases you.", ch, NULL, victim, TO_CHAR );
        act( "A dome of crimson energy encases $n.", ch, NULL, victim, TO_ROOM );
        if ( is_affected( ch, gsn_earth_ward ) )
          affect_strip( ch, gsn_earth_ward );
        if ( is_affected( ch, gsn_wind_ward ) )
          affect_strip( ch, gsn_wind_ward );
        if ( is_affected( ch, gsn_flame_ward ) )
          affect_strip( ch, gsn_flame_ward );
        if ( is_affected( ch, gsn_water_ward ) )
          affect_strip( ch, gsn_water_ward );
        if ( is_affected( ch, gsn_spirit_ward ) )
          affect_strip( ch, gsn_spirit_ward );
        if ( is_affected( ch, gsn_negative_ward ) )
          affect_strip( ch, gsn_negative_ward );
        af.type      = gsn_flame_ward;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind*15; 
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_WATER + RUNE_ABJURATION:
        act( "A dome of sea green energy encases you.", ch, NULL, victim, TO_CHAR );
        act( "A dome of sea green energy encases $n.", ch, NULL, victim, TO_ROOM );
        if ( is_affected( ch, gsn_earth_ward ) )
          affect_strip( ch, gsn_earth_ward );
        if ( is_affected( ch, gsn_flame_ward ) )
          affect_strip( ch, gsn_flame_ward );
        if ( is_affected( ch, gsn_wind_ward ) )
          affect_strip( ch, gsn_wind_ward );
        if ( is_affected( ch, gsn_water_ward ) )
          affect_strip( ch, gsn_water_ward );
        if ( is_affected( ch, gsn_spirit_ward ) )
          affect_strip( ch, gsn_spirit_ward );
        if ( is_affected( ch, gsn_negative_ward ) )
          affect_strip( ch, gsn_negative_ward );
        af.type      = gsn_water_ward;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind*15;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_ENERGY + RUNE_ABJURATION:
        act( "A dome of pale white energy encases you.", ch, NULL, victim, TO_CHAR );
        act( "A dome of pale white energy encases $n.", ch, NULL, victim, TO_ROOM );
        if ( is_affected( ch, gsn_earth_ward ) )
          affect_strip( ch, gsn_earth_ward );
        if ( is_affected( ch, gsn_flame_ward ) )
          affect_strip( ch, gsn_flame_ward );
        if ( is_affected( ch, gsn_water_ward ) )
          affect_strip( ch, gsn_water_ward );
        if ( is_affected( ch, gsn_wind_ward ) )
          affect_strip( ch, gsn_wind_ward );
        if ( is_affected( ch, gsn_spirit_ward ) )
          affect_strip( ch, gsn_spirit_ward );
        if ( is_affected( ch, gsn_negative_ward ) )
          affect_strip( ch, gsn_negative_ward );
        af.type      = gsn_spirit_ward;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind*15;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    case RUNE_NEGATIVE + RUNE_ABJURATION:
        act( "A dome of obsidian energy encases you.", ch, NULL, victim, TO_CHAR );
        act( "A dome of obsidian energy encases $n.", ch, NULL, victim, TO_ROOM );
        if ( is_affected( ch, gsn_earth_ward ) )
          affect_strip( ch, gsn_earth_ward );
        if ( is_affected( ch, gsn_flame_ward ) )
          affect_strip( ch, gsn_flame_ward );
        if ( is_affected( ch, gsn_water_ward ) )
          affect_strip( ch, gsn_water_ward );
        if ( is_affected( ch, gsn_spirit_ward ) )
          affect_strip( ch, gsn_spirit_ward );
        if ( is_affected( ch, gsn_wind_ward ) )
          affect_strip( ch, gsn_wind_ward );
        if ( is_affected( ch, gsn_negative_ward ) )
          affect_strip( ch, gsn_negative_ward );
        af.type      = gsn_negative_ward;
        af.location  = 0;
        af.modifier  = 0;
        af.duration  = ch->pcdata->mind*15;
        af.bitvector = 0;
        affect_to_char( victim, &af );
        break;
    default:
	send_to_char( "Nothing happens.\n\r", ch );
	return;
  }

  if ( victim != NULL && target == TAR_CHAR_OFFENSIVE && victim != ch
    && victim->position >= POS_STUNNED )
  { if ( ch->fighting == NULL )
      ch->fighting = victim;
    if ( victim->fighting == NULL )
      victim->fighting = ch;
  }
  WAIT_STATE( ch, cost_table[slot].wait );
  ch->mana -= cost;
  return;
}

void do_tattoo( CHAR_DATA *ch, char *argument )
{
  int cost, mcost, location, type;
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
  { send_to_char( "You know nothing of the ancient art of tattooing.\n\r", ch );
    return;
  }
  if ( ch->level < 2 )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  if ( arg1[0] == '\0' || arg2[0] == '\0' )
  { send_to_char( "You must specify both a location, and a rune to tattoo.\n\r", ch );
    return;
  }

  if ( !str_cmp( arg1, "torso" ) )
    location = TORSO;
  else if ( !str_cmp( arg1, "leftarm" ) )
    location = LEFTARM;
  else if ( !str_cmp( arg1, "rightarm" ) )
    location = RIGHTARM;
  else if ( !str_cmp( arg1, "leftleg" ) )
    location = LEFTLEG;
  else if ( !str_cmp( arg1, "rightleg" ) )
    location = RIGHTLEG;
  else
  { send_to_char( "\n\rYou can tattoo runes on the following bodyparts:\n\r", ch );
    send_to_char( "Torso, leftarm, rightarm, leftleg, rightleg.\n\r", ch );
    return;
  }

  if ( !str_cmp( arg2, "earth" ) )
    type = RUNE_EARTH;
  else if ( !str_cmp( arg2, "air" ) )
    type = RUNE_AIR;
  else if ( !str_cmp( arg2, "fire" ) )
    type = RUNE_FIRE;
  else if ( !str_cmp( arg2, "water" ) )
    type = RUNE_WATER;
  else
  { send_to_char( "\n\rYou can tattoo the following runes onto your body:\n\r", ch );
    send_to_char( "Earth, air, fire, water.\n\r", ch );
    return;
  }

  if ( !IS_SET(ch->pcdata->powers[P_LEARNED],type) )
  { send_to_char( "\n\rBut you don't know that rune!\n\r", ch );
    return;
  }

  cost = 10 + get_runes( ch, RUNE_ALL, location ) * 10;
  if ( ch->pcdata->primal < cost )
  { send_to_char( "You don't have enough primal.\n\r", ch );
    return;
  }
  mcost = cost * 25;
  if ( ch->mana < mcost )
  { send_to_char( "You don't have enough mana.\n\r", ch );
    return;
  }

  if ( get_runes( ch, RUNE_ALL, location ) >= runemax[location] )
  { send_to_char( "There is no more space for another rune there.\n\r", ch );
    return;
  }

  add_rune( ch, type, location );
  ch->pcdata->primal -= cost;
  ch->mana -= mcost;
  sprintf( buf, "\n\rYou tattoo a rune of %s onto your %s.\n\r", arg2, arg1 );
  send_to_char( buf, ch );
  WAIT_STATE( ch, 12 );
  return;
}

int get_runes( CHAR_DATA *ch, int type, int part )
{
  int i;
  int num = 0;

  if ( IS_NPC(ch) )
    return 0;
  if ( ch->class != CLASS_PATRYN )
    return 0;
  if ( part > 4 || part < 0 )
    return 0;

  if ( type != RUNE_ALL )
  {
    for ( i = 0; i < runemax[part]; i++ )
      if ( ch->pcdata->runes[part][i] == type )
	num++;
  }
  else
  {
    for ( i = 0; i < runemax[part]; i++ )
      if ( ch->pcdata->runes[part][i] != 0 )
	num++;
  }

  return URANGE( 0, num, 15 );
}


void add_rune( CHAR_DATA *ch, int type, int part )
{
  int i = 0;

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
    return;

  if ( get_runes( ch, RUNE_ALL, part ) >= runemax[part] )
    return;
  while ( ch->pcdata->runes[part][i] != 0 && i < runemax[part] - 1 )
    i++;
  ch->pcdata->runes[part][i] = type;
  return;
}

void remove_rune( CHAR_DATA *ch, int type, int part )
{
  int i = 0;

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
    return;

  if ( get_runes( ch, type, part ) == 0 )
    return;

  while ( ch->pcdata->runes[part][i] != type )
    i++;

  ch->pcdata->runes[part][i] = 0;
  return;
}

void do_runestats( CHAR_DATA *ch, char *argument )
{
  int part, rune;
  char *message[5][15];
  char buf[MAX_STRING_LENGTH];

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
  { send_to_char( "What do you think you are, a Patryn?\n\r", ch );
    return;
  }

  for ( part = 0; part < 5; part++ )
    for ( rune = 0; rune < runemax[part]; rune++ )
    { if ( ch->pcdata->runes[part][rune] == RUNE_AIR )
	message[part][rune] = "air";
      else if ( ch->pcdata->runes[part][rune] == RUNE_EARTH )
	message[part][rune] = "earth";
      else if ( ch->pcdata->runes[part][rune] == RUNE_FIRE )
	message[part][rune] = "fire";
      else if ( ch->pcdata->runes[part][rune] == RUNE_WATER )
	message[part][rune] = "water";
      else if ( ch->pcdata->runes[part][rune] == RUNE_NONE )
	message[part][rune] = "none";
      else
	message[part][rune] = "?err?";
    }

  send_to_char( "\n\rYou have the following runes on you:\n\r", ch );

  sprintf( buf, "Torso: %s %s %s %s %s %s %s %s\n\r",
	message[0][0],message[0][1],message[0][2],message[0][3],
	message[0][4],message[0][5],message[0][6],message[0][7] );
  send_to_char( buf, ch );
  sprintf( buf, "       %s %s %s %s %s %s %s\n\r",
	message[0][8],message[0][9],message[0][10],message[0][11],
	message[0][12],message[0][13],message[0][14] );
  send_to_char( buf, ch );
  sprintf( buf, "Left Arm: %s %s %s %s %s\n\r",
	message[1][0],message[1][1],message[1][2],message[1][3],message[1][4] );
  send_to_char( buf, ch );
  sprintf( buf, "Right Arm: %s %s %s %s %s\n\r",
	message[2][0],message[2][1],message[2][2],message[2][3],message[2][4] );
  send_to_char( buf, ch );
  sprintf( buf, "Left Leg: %s %s %s %s %s %s %s %s\n\r",
	message[3][0],message[3][1],message[3][2],message[3][3],
	message[3][4],message[3][5],message[3][6],message[3][7] );
  send_to_char( buf, ch );
  sprintf( buf, "Right Leg: %s %s %s %s %s %s %s %s\n\r\n\r",
	message[4][0],message[4][1],message[4][2],message[4][3],
	message[4][4],message[4][5],message[4][6],message[4][7] );
  send_to_char( buf, ch );

  return;

}

void do_erase( CHAR_DATA *ch, char *argument )
{
  char arg1[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char buf[MAX_STRING_LENGTH];
  int rune, part;

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }

  argument = one_argument( argument, arg1 );
  argument = one_argument( argument, arg2 );

  if ( arg1[0] == '\0' || arg2[0] == '\0' )
  { send_to_char( "You must specify a body part and a rune to erase.\n\r", ch );
    return;
  }

  if ( !str_cmp( arg1, "torso" ) )
    part = TORSO;
  else if ( !str_cmp( arg1, "leftarm" ) )
    part = LEFTARM;
  else if ( !str_cmp( arg1, "rightarm" ) )
    part = RIGHTARM;
  else if ( !str_cmp( arg1, "leftleg" ) )
    part = LEFTLEG;
  else if ( !str_cmp( arg1, "rightleg" ) )
    part = RIGHTLEG;
  else
  { send_to_char( "That is not an acceptable body part.\n\r", ch );
    return;
  }

  if ( !str_cmp( arg2, "earth" ) )
    rune = RUNE_EARTH;
  else if ( !str_cmp( arg2, "air" ) )
    rune = RUNE_AIR;
  else if ( !str_cmp( arg2, "fire" ) )
    rune = RUNE_FIRE;
  else if ( !str_cmp( arg2, "water" ) )
    rune = RUNE_WATER;
  else
  { send_to_char( "That is not an acceptable rune.\n\r", ch );
    return;
  }

  if ( get_runes(ch,rune,part) == 0 )
  { send_to_char( "But you have none of those runes there!\n\r", ch );
    return;
  }

  if ( ch->pcdata->primal < 25 || ch->mana < 1000 )
  { send_to_char( "It costs 25 primal and 1000 mana to erase a rune.\n\r", ch );
    return;
  }

  ch->pcdata->primal -= 25;
  ch->mana -= 1000;
  remove_rune(ch,rune,part);
  sprintf( buf, "You painstakingly remove the rune of %s from your %s.\n\r", arg2, arg1 );
  send_to_char( buf, ch );
  return;
}

void runecast( CHAR_DATA *ch, CHAR_DATA *victim, char *arg )
{
  int sn = skill_lookup( arg );
  int lev = ch->pcdata->will;

  (*skill_table[sn].spell_fun) ( sn, lev, ch, victim );

  if ( skill_table[sn].target == TAR_CHAR_OFFENSIVE && ch != victim )
  { CHAR_DATA *vch;
    CHAR_DATA *vch_next;
    for ( vch = char_list; vch != NULL; vch = vch_next )
    { vch_next = vch->next_in_room;
      if ( victim == vch && victim->fighting == NULL )
      { multi_hit( victim, ch, TYPE_UNDEFINED );
	break;
      }
    }
  }

  return;
}

void do_runetrain( CHAR_DATA *ch, char *argument )
{
  int rune, cost;
  char buf[MAX_STRING_LENGTH];
  char * const runenames[] = { "motherfucker", "shitface", "air", "earth", "fire", "water", "energy", "negative" };

  if ( IS_NPC(ch) )
    return;
  if ( ch->class != CLASS_PATRYN || ch->level < 2 )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }
  
  if ( argument[0] == '\0' )
  { send_to_char( "Your understanding of the following runes can be trained:\n\r", ch );
    sprintf( buf, "Air    %5d  Earth  %5d  Fire     %5d\n\r",
	150 * (ch->pcdata->powers[P_AIR]+1) * (ch->pcdata->powers[P_AIR]+1),
	150 * (ch->pcdata->powers[P_EARTH]+1) * (ch->pcdata->powers[P_EARTH]+1),
	150 * (ch->pcdata->powers[P_FIRE]+1) * (ch->pcdata->powers[P_FIRE]+1) );
    send_to_char( buf, ch );
    sprintf( buf, "Water  %5d  Energy %5d  Negative %5d\n\r", 
   	150 * (ch->pcdata->powers[P_WATER]+1) * (ch->pcdata->powers[P_WATER]+1),
   	150 * (ch->pcdata->powers[P_ENERGY]+1) * (ch->pcdata->powers[P_ENERGY]+1),
   	150 * (ch->pcdata->powers[P_NEGATIVE]+1) * (ch->pcdata->powers[P_NEGATIVE]+1) );
    send_to_char( buf, ch );
    return;
  }

  if ( !str_cmp( argument, "air" ) )
    rune = P_AIR;
  else if ( !str_cmp( argument, "earth" ) )
    rune = P_EARTH;
  else if ( !str_cmp( argument, "fire" ) )
    rune = P_FIRE;
  else if ( !str_cmp( argument, "water" ) )
    rune = P_WATER;
  else if ( !str_cmp( argument, "energy" ) )
    rune = P_ENERGY;
  else if ( !str_cmp( argument, "negative" ) )
    rune = P_NEGATIVE;
  else
  { send_to_char( "You can't runetrain that.\n\r", ch );
    return;
  }

  cost = 150 * (ch->pcdata->powers[rune]+1) * ( ch->pcdata->powers[rune]+1);
  if ( ch->pcdata->powers[rune] >= 100 )
  { send_to_char( "You already understand all the uses of that rune.\n\r", ch );
    return;
  }
  if ( ch->exp < cost )
  { sprintf( buf, "You need %d experience to train that rune.\n\r", cost );
    send_to_char( buf, ch );
    return;
  }

  ch->exp -= cost;
  ch->pcdata->powers[rune]++;
  sprintf( buf, "Your understanding of the rune of %s improves.\n\r", runenames[rune] );
  send_to_char( buf, ch );
  return;
}

void do_circle( CHAR_DATA *ch, char *argument )
{
  if ( !IS_CLASS( ch, CLASS_PATRYN ) )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }
  if ( IS_SUIT(ch) )
  { send_to_char( "Not in a mobile suit.\n\r", ch );
    return;
  }
  if ( IS_SET(ch->pcdata->actnew,NEW_CIRCLE) )
  { send_to_char( "Your circle is already closed!\n\r", ch );
    return;
  }
  if ( ch->position < POS_RESTING || ch->position > POS_RESTING )
  { send_to_char( "You must be at rest to close the circle of your being.\n\r", ch );
    return;
  }
  if ( argument[0] == '\0' )
  { send_to_char( "You close the circle of your being.\n\r", ch );
    SET_BIT(ch->pcdata->actnew,NEW_CIRCLE);
    return;
  }
  else
    send_to_char( "Sorry, multi-person circling is still in the works.\n\r", ch );

  return;
}

void do_defenses( CHAR_DATA *ch, char *argument )
{ 
  char arg[MAX_INPUT_LENGTH];
  argument = one_argument( argument, arg );
  
  if ( !IS_CLASS(ch,CLASS_PATRYN) )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }

  if ( ch->level < 2 )
  { send_to_char( "Huh?\n\r", ch );
    return;
  }

  if ( arg[0] == '\0' )
  {
    if ( IS_SET(ch->pcdata->powers[P_BITS],P_DEFENSES) )
      send_to_char( "Your defenses are raised.\n\r", ch );
    else
      send_to_char( "Your defenses are lowered.\n\r", ch );
  }
  else if ( !str_prefix( arg, "raise" ) )
  {
    if ( IS_SET(ch->pcdata->powers[P_BITS],P_DEFENSES) )
      send_to_char( "Your defenses are already raised.\n\r", ch );
    else
    { SET_BIT(ch->pcdata->powers[P_BITS],P_DEFENSES);
      send_to_char( "You raise your defenses.\n\r", ch );
    }
  }
  else if ( !str_prefix( arg, "lower" ) )
  {
    if ( !IS_SET(ch->pcdata->powers[P_BITS],P_DEFENSES) )
      send_to_char( "Your defenses are already lowered.\n\r", ch );
    else
    { REMOVE_BIT(ch->pcdata->powers[P_BITS],P_DEFENSES);
      send_to_char( "You lower your defenses.\n\r", ch );
    }
  }
  else
   send_to_char( "Acceptable arguments are raise, lower, or nothing.\n\r", ch );

  return;
}