/****************************************************************************
*                                                                           *
*        skills_android.c - skills and abilities unique to androids         *
*                                                                           *
****************************************************************************/

#include <sys/types.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mud.h"

extern void transStatApply args((CHAR_DATA *ch, int strMod, int spdMod, int intMod, int conMod));
extern void transStatRemove args((CHAR_DATA *ch));

void do_absorb(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    char charBuf[MAX_STRING_LENGTH];
    char victBuf[MAX_STRING_LENGTH];
    char roomBuf[MAX_STRING_LENGTH];
    int dam = 0;
    

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_absorb]->skill_level[ch->class] )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

	if (ch->focus < skill_table[gsn_absorb]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_absorb]->focus;

    WAIT_STATE( ch, skill_table[gsn_absorb]->beats );
    if ( can_use_skill(ch, number_percent(),gsn_absorb ) )
    {
	dam = get_attmod(ch, victim) * number_range( 2, 8 );
	if (dam > 0)
	{
        switch( number_range( 1, 2 ) )
        {
          default:
            sprintf( charBuf, "You grab $N tightly, draining $M of some of $S energy. &W[$t]" );
            sprintf( victBuf, "$n grabs you tightly, draining you of some of your energy. &W[$t]" );
            sprintf( roomBuf, "$n grabs $N tightly, draining $M of some of $S energy. &W[$t]" );
          break;
        
          case 1:
            sprintf( charBuf, "You grab $N tightly, draining $M of some of $S energy. &W[$t]" );
            sprintf( victBuf, "$n grabs you tightly, draining you of some of your energy. &W[$t]" );
            sprintf( roomBuf, "$n grabs $N tightly, draining $M of some of $S energy. &W[$t]" );
          break;
  
          case 2:
            sprintf( charBuf, "You reach out and grab $N with one hand, draining $M of some of $S energy. &W[$t]" );
            sprintf( victBuf, "$n reaches out and grabs you with one hand, draining you of some of your energy. &W[$t]" );
            sprintf( roomBuf, "$n reaches out and grabs $N with one hand, draining $M of some of $S energy. &W[$t]" );
          break;
        }
/*	act( AT_SKILL, "You grab $N tightly, draining $M of some of $S energy. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );
 *	act( AT_SKILL, "$n grabs you tightly, draining you of some of your energy. &W[$t]", ch, num_punct(dam), victim, TO_VICT );
 *	act( AT_SKILL, "$n grabs $N tightly, draining $M of some of $S energy. &W[$t]", ch, num_punct(dam), victim, TO_NOTVICT );*/
	act( AT_SKILL, charBuf, ch, num_punct(dam), victim, TO_CHAR );
	act( AT_SKILL, victBuf, ch, num_punct(dam), victim, TO_VICT );
	act( AT_SKILL, roomBuf, ch, num_punct(dam), victim, TO_NOTVICT );

	learn_from_success( ch, gsn_absorb );
	xSET_BIT(ch->act, PLR_2XPL_GAIN);
	global_retcode = damage( ch, victim, dam, gsn_absorb  );
	if (xIS_SET(ch->act, PLR_2XPL_GAIN))
        {
          xREMOVE_BIT(ch->act, PLR_2XPL_GAIN);
        }
	}
    }

	else
    {
	act( AT_SKILL, "You missed $N while trying to grab $M.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "You quickly dodge out of the way from $n's open fist.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$N quickly dodges out of the way from $n's open fist.", ch, NULL, victim, TO_NOTVICT );

	learn_from_failure( ch, gsn_absorb );
	global_retcode = damage( ch, victim, 0, gsn_absorb );
	if (xIS_SET(ch->act, PLR_2XPL_GAIN))
        {
          xREMOVE_BIT(ch->act, PLR_2XPL_GAIN);
        }
    }
	
	if (dam > 0)
	{
		dam = victim->mana * 0.05;
		if (dam > 0)
		{
			if (victim->mana < dam)
			{
				dam = victim->mana;
				victim->mana = 0;
			}
			else
				victim->mana -= dam;

			ch->mana += dam;
		}
	}

	if (ch->mana > ch->max_mana)
		ch->mana = ch->max_mana;


	return;
}

void do_rocket_punch(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_rocket_punch]->skill_level[ch->class] )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

	if ( !IS_NPC(ch) && ch->mana < skill_table[gsn_rocket_punch]->min_mana )
	{
	    send_to_char( "You don't have enough energy.\n\r", ch );
	    return;
	}

	if (ch->focus < skill_table[gsn_rocket_punch]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_rocket_punch]->focus;

    WAIT_STATE( ch, skill_table[gsn_rocket_punch]->beats );
    if ( can_use_skill(ch, number_percent(),gsn_rocket_punch ) )
    {
	dam = get_attmod(ch, victim) * number_range( 22, 27 );
	if (ch->charge > 0)
		dam = chargeDamMult(ch, dam);
	act( AT_SKILL, "Your fists detach, rockets firing them toward $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$N is smashed by the flying fists, "
                       "which quickly return and reattach to your arms. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );
	act( AT_SKILL, "$n's fists detach, rockets firing them toward you.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "You are smashed by the flying fists, "
                       "which quickly return and reattach to $n's arms. &W[$t]", ch, num_punct(dam), victim, TO_VICT );
	act( AT_SKILL, "$n's fists detach, rockets firing them toward $N.", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "$N is smashed by the flying fists, "
                       "which quickly return and reattach to $n's arms. &W[$t]", ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_rocket_punch);
        dam = portal_counter(ch, victim, dam, gsn_rocket_punch );
        
        if (dam > 0)
          global_retcode = damage( ch, victim, dam, TYPE_HIT );
    }
    else
    {
	act( AT_SKILL, "You missed $N with your rocket punch.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n misses you with $s rocket punch.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$n missed $N with a rocket punch.", ch, NULL, victim, TO_NOTVICT );
	learn_from_failure( ch, gsn_rocket_punch );
	global_retcode = damage( ch, victim, 0, TYPE_HIT );
    }
	ch->mana -= skill_table[gsn_rocket_punch]->min_mana;
    return;
}

void do_electric_shield(CHAR_DATA *ch, char *argument )
{
	AFFECT_DATA af;
	int shieldGsn = 0;
	int nacMod = 0;

	if ( !IS_NPC(ch)) 
	{
		if (ch->pcdata->learned[gsn_electric_shield4] > 0)
		{
			shieldGsn = gsn_electric_shield4;
			nacMod = 1500;
		}
		else if (ch->pcdata->learned[gsn_electric_shield3] > 0)
		{
			shieldGsn = gsn_electric_shield3;
			nacMod = 1000;
		}
		else if (ch->pcdata->learned[gsn_electric_shield2] > 0)
		{
			shieldGsn = gsn_electric_shield2;
			nacMod = 750;
		}
		else
		{
			shieldGsn = gsn_electric_shield;
			nacMod = 500;
		}
	}

	if ( !IS_NPC(ch)
		&& !xIS_SET(ch->affected_by, AFF_ELECTRICSHIELD)
		&& ch->mana < skill_table[shieldGsn]->min_mana )
	{
	    send_to_char( "You don't have enough energy.\n\r", ch );
	    return;
	}

	if (xIS_SET(ch->affected_by, AFF_ELECTRICSHIELD))
	{
//	    send_to_char( "Your electric shield is already up.\n\r", ch );
//            return;
            act( AT_SKILL, "You clench your fists and power down your electric shield.", ch, NULL, NULL, TO_CHAR );
            act( AT_SKILL, "The crackling electric shield around $n vanishes.", ch, NULL, NULL, TO_NOTVICT );
            xREMOVE_BIT( ch->affected_by, AFF_ELECTRICSHIELD );
            affect_strip( ch, shieldGsn );
	    return;
	}

    if ( can_use_skill(ch, number_percent(),shieldGsn ) )
    {
	act( AT_SKILL, "You clench your fists as a powerful electric shield sparks up around you.", ch, NULL, NULL, TO_CHAR );
	act( AT_SKILL, "A crackling electric shield sparks up around $n.", ch, NULL, NULL, TO_NOTVICT );

	learn_from_success( ch, shieldGsn );
	af.type      = shieldGsn;
	af.duration  = (8) * DUR_CONV;
	af.location  = APPLY_NATURALAC;
	af.bitvector = meb(AFF_ELECTRICSHIELD);
	af.modifier  = nacMod;
	affect_to_char( ch, &af );
    }
    else
    {
	act( AT_SKILL, "You clench your fists as nothing happens...", ch, NULL, NULL, TO_CHAR );
	act( AT_SKILL, "You see $n clench $s fists, for no apparent reason.", ch, NULL, NULL, TO_NOTVICT );
	learn_from_failure( ch, shieldGsn );
    }
	ch->mana -= skill_table[shieldGsn]->min_mana;
	return;
}

void do_self_destruct(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;
    int chargesUsed = 0;
    char arg[MAX_STRING_LENGTH];
    //int addCharges = 0;
    double attmod = 0.000;

    if ( IS_NPC(ch))
    {
	send_to_char( "Bad NPC!  Be nice to players.\n\r", ch );
	return;
    }

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_self_destruct]->skill_level[ch->class] )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

	if ( !IS_NPC(ch) && ch->mana < skill_table[gsn_self_destruct]->min_mana )
	{
	    send_to_char( "You don't have enough energy.\n\r", ch );
	    return;
	}

        if( argument[0] != '\0' )
        {
          one_argument( argument, arg );
          if( arg[0] != '\0' && is_number( arg ) )
          {
            chargesUsed = atoi( arg );
		if( chargesUsed < 10)
		{
			send_to_char( "You must use at least 10 charges to self destruct with any force.\n\r", ch );
			return;
		}
          }
	    else
	    {
		send_to_char( "You need to specify a number of charges to use.\n\r", ch );
		return;
	    }
        }
	  else
	  {
		send_to_char( "You need to specify a number of charges to use.\n\r", ch );
		return;
	  }

	if ( !IS_NPC(ch) && ch->pcdata->sd_charge < chargesUsed )
	{
	    send_to_char( "You don't have that many charges!\n\r", ch );
	    return;
	}
	if (ch->focus < skill_table[gsn_self_destruct]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_self_destruct]->focus;

    WAIT_STATE( ch, skill_table[gsn_self_destruct]->beats );
//    ch->pcdata->sd_charge = 0;

    ch->pcdata->sd_charge -= chargesUsed;
    dam = 2 * (chargesUsed-10);

	if( attmod >= .33 && attmod <= .5)  // 2x the character's PL or lower: 60 to kill.
	  dam *= .75;				// Less than 3x the character's PL: 77 to kill.
	else if( attmod >= .25 )		// Less than 4x the character's PL: 144 to kill.
	  dam *= .375;			
	else if( attmod >= .2 )			// Less than 5x the character's PL: 210 to kill.
	  dam *= .25;

    if ( can_use_skill(ch, number_percent(),gsn_self_destruct ) )
    {
       act( AT_RED, "Sensing your end is near, sparks of information course through your electronic veins", ch, NULL, victim, TO_CHAR );
      actl( AT_RED, "and activate the dormant nuclear warhead hidden deep within your cold, titanium body.", ch, NULL, victim, TO_CHAR );
       act( AT_RED, "With no further qualms against external damage, you charge fearlessly towards $N", ch, NULL, victim, TO_CHAR );
      actl( AT_RED, "and pierce through $S defenses with your self-destructive blitzkrieg. Catching $M in", ch, NULL, victim, TO_CHAR );
      actl( AT_RED, "an inescapable bear hug, you glare deep into $S eyes and whisper, &C\"This is the end.\"", ch, NULL, victim, TO_CHAR );
       act( AT_WHITE, "Your warhead ignites. [$t]", ch, num_punct(dam), victim, TO_CHAR );

       act( AT_RED, "Sensing $s end is near, sparks of information course through $n's electronic veins", ch, NULL, victim, TO_VICT  );
      actl( AT_RED, "and activate the dormant nuclear warhead hidden deep within $s cold, titanium body.", ch, NULL, victim, TO_VICT );
       act( AT_RED, "With no further qualms against external damage, $e charges fearlessly towards you", ch, NULL, victim, TO_VICT  );
      actl( AT_RED, "and pierces through your defenses with $s self-destructive blitzkrieg. Catching you in", ch, NULL, victim, TO_VICT  );
      actl( AT_RED, "an inescapable bear hug, $e glares deep into your eyes and whispers, &C\"This is the end.\"", ch, NULL, victim, TO_VICT  );
       act( AT_WHITE, "$n's warhead ignites. [$t]", ch, num_punct(dam), victim, TO_VICT  );

       act( AT_RED, "Sensing your end is near, sparks of information course through $n's electronic veins", ch, NULL, victim, TO_NOTVICT );
      actl( AT_RED, "and activate the dormant nuclear warhead hidden deep within $s cold, titanium body.", ch, NULL, victim, TO_NOTVICT );
       act( AT_RED, "With no further qualms against external damage, $e charges fearlessly towards $N", ch, NULL, victim, TO_NOTVICT );
      actl( AT_RED, "and pierces through $S defenses with $s self-destructive blitzkrieg. Catching $M in", ch, NULL, victim, TO_NOTVICT );
      actl( AT_RED, "an inescapable bear hug, $e glares deep into $S eyes and whispers, &C\"This is the end.\"", ch, NULL, victim, TO_NOTVICT );
       act( AT_WHITE, "$n's warhead ignites. [$t]", ch, num_punct(dam), victim, TO_NOTVICT );

//	learn_from_success( ch, gsn_self_destruct );
    }
    else
    {
	dam /= 2;
	 act( AT_RED, "In a last ditch effort, you ignite the dormant nuclear warhead buried deep within your", ch, NULL, victim, TO_CHAR );
	actl( AT_RED, "mechanical frame. Diving for $N, you attempt to seal his fate in a cold bearhug, but", ch, NULL, victim, TO_CHAR );
	actl( AT_RED, "$E manages to evade you, caught only by the outermost edge of the resulting explosion! [$t]", ch, num_punct(dam), victim, TO_CHAR );

	 act( AT_RED, "In a last ditch effort, you ignite the dormant nuclear warhead buried deep within your", ch, NULL, victim, TO_VICT );
	actl( AT_RED, "mechanical frame. Diving for $N, you attempt to seal his fate in a cold bearhug, but", ch, NULL, victim, TO_VICT );
	actl( AT_RED, "$E manages to evade you, caught only by the outermost edge of the resulting explosion! [$t]", ch, num_punct(dam), victim, TO_VICT );

	 act( AT_RED, "In a last ditch effort, you ignite the dormant nuclear warhead buried deep within your", ch, NULL, victim, TO_NOTVICT);
	actl( AT_RED, "mechanical frame. Diving for $N, you attempt to seal his fate in a cold bearhug, but", ch, NULL, victim, TO_NOTVICT);
	actl( AT_RED, "$E manages to evade you, caught only by the outermost edge of the resulting explosion! [$t]", ch, num_punct(dam), victim, TO_NOTVICT);

	//learn_from_failure( ch, gsn_self_destruct );
	//global_retcode = damage( ch, victim, 0, gsn_self_destruct );
	//global_retcode = damage( ch, ch, dam, gsn_self_destruct  );
    }

	attmod = get_attmod(ch, victim);

	// More than 5x the character's PL? No IK.
	if( attmod < .2)
	{
	  act( AT_WHITE, "As the smoke clears, $N stands completely unharmed. Your charges weren't enough...", ch, NULL, victim, TO_CHAR );
	  act( AT_WHITE, "As the smoke clears, you stand completely unharmed. $n's charges weren't enough.", ch, NULL, victim, TO_VICT );
	  act( AT_WHITE, "As the smoke clears, $N stands completely unharmed. $n's charges weren't enough...", ch, NULL, victim, TO_NOTVICT );
	  dam *= 0;
	}



	// Killing the victim.
	victim->hit -= dam;

	if (victim->hit > 0)
	{
 		act( AT_WHITE, "As the smoke clears, $N stands battered and bruised, but alive...", ch, NULL, victim, TO_CHAR );
		act( AT_WHITE, "As the smoke clears, you stand battered and bruised, but alive!", ch, NULL, victim, TO_VICT );
		act( AT_WHITE, "As the smoke clears, $N stands battered and bruised, but alive...", ch, NULL, victim, TO_NOTVICT );
	}



	if (victim->hit < 0)
	{
		victim->hit = -100;
		global_retcode = damage( ch, victim, 1, gsn_self_destruct );
		//update_pos( victim );
		
	}


	// Killing the character.
	
	ch->hit = -100;
	global_retcode = damage( ch, ch, 1, gsn_self_destruct   );

	// Old "Kill the Character" code and leftovers.
	//	dam2 = 1;

	//	dam = ch->max_hit * 2;
	//	dam = 50 * ((chargesUsed-50)/10);

	ch->mana -= skill_table[gsn_self_destruct]->min_mana;
    return;
}

void do_duplicate(CHAR_DATA *ch, char *argument )
{
	return;
}

void do_uppercut( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_uppercut]->skill_level[ch->class] )
    {
	send_to_char(
	    "You better leave the martial arts to fighters.\n\r", ch );
	return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch) && ch->mana < skill_table[gsn_uppercut]->min_mana )
    {
      send_to_char( "You don't have enough energy.\n\r", ch );
      return;
    }
	if (ch->focus < skill_table[gsn_uppercut]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_uppercut]->focus;

    WAIT_STATE( ch, skill_table[gsn_uppercut]->beats );
    ch->mana -= skill_table[gsn_uppercut]->min_mana;
    if ( can_use_skill( ch, number_percent(), gsn_uppercut ) )
    {
	act( AT_SKILL, "You launch your fist upwards, hitting $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n launchs $s fist upwards, hitting you.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$n launchs $s fist upwards, hitting $N.", ch, NULL, victim, TO_NOTVICT );

	learn_from_success( ch, gsn_uppercut );
	global_retcode = damage( ch, victim, (get_attmod(ch,victim) * number_range( 6, 10 )), TYPE_HIT );
    }
    else
    {
	act( AT_SKILL, "You launch your fist upwards, but you miss $N.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n launchs $s fist upwards, but $e misses you.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$n launchs $s fist upwards, but $e misses $N.", ch, NULL, victim, TO_NOTVICT );
	learn_from_failure( ch, gsn_uppercut );
	global_retcode = damage( ch, victim, 0, TYPE_HIT );
    }
    return;
}

void do_evolve( CHAR_DATA *ch, char *argument )
{

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

	if (argument[0] == '\0')
    {
		send_to_char( "How do you want to evolve?\n\r", ch );
		return;
    }

	if (str_prefix(argument, "semi-perfect form")
		&& str_prefix(argument, "perfect form")
		&& str_prefix(argument, "ultra-perfect form"))
    {
		send_to_char( "You can't evolve into that.\n\r", ch );
		return;
    }

	if ( (!str_prefix(argument, "semi-perfect form") && ch->pcdata->learned[gsn_semiperfect] <= 0)
		|| (!str_prefix(argument, "perfect form") && ch->pcdata->learned[gsn_perfect] <= 0)
		|| (!str_prefix(argument, "ultra-perfect form") && ch->pcdata->learned[gsn_ultraperfect] <= 0))
    {
		send_to_char( "You must absorb more energy before you can evolve into that form.\n\r", ch );
		return;
    }

	if (!str_prefix(argument, "semi-perfect form")
		&& ch->pcdata->learned[gsn_semiperfect] > 0)
	{
		if (ch->mana < skill_table[gsn_semiperfect]->min_mana)
		{
		    send_to_char( "You don't have enough energy.\n\r", ch );
		    return;
		}

		if (xIS_SET(ch->affected_by, AFF_SEMIPERFECT))
		{
		    send_to_char( "You are already in that form.\n\r", ch );
		    return;
		}

		xSET_BIT(ch->affected_by, AFF_SEMIPERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_PERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_ULTRAPERFECT);
//		act( AT_SKILL, "You evolve into your semi-perfect form.", ch, NULL, NULL, TO_CHAR );
//		act( AT_SKILL, "$n evolves into $s semi-perfect form.", ch, NULL, NULL, TO_NOTVICT );
		act( AT_PURPLE, "Your horns shift closer together, your features becoming more humanoid as "
                                "you grow in size and complete your evolution to a Semi-Perfect form.", ch, NULL, NULL, TO_CHAR );
		act( AT_PURPLE, "$n's horns shift closer together, $s features becoming more humanoid as "
                                "$e grows in size and completes $s evolution to a Semi-Perfect form.", ch, NULL, NULL, TO_NOTVICT );
		ch->pl = ch->exp * 8;
		transStatApply(ch, 8, 8, 8, 8);
                ch->mana -= skill_table[gsn_semiperfect]->min_mana;
		return;
	}

	if (!str_prefix(argument, "perfect form")
		&& ch->pcdata->learned[gsn_perfect] > 0)
	{
		if (ch->mana < skill_table[gsn_perfect]->min_mana)
		{
		    send_to_char( "You don't have enough energy.\n\r", ch );
		    return;
		}

		if (xIS_SET(ch->affected_by, AFF_PERFECT))
		{
		    send_to_char( "You are already in that form.\n\r", ch );
		    return;
		}

		xSET_BIT(ch->affected_by, AFF_PERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_SEMIPERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_ULTRAPERFECT);
//		act( AT_SKILL, "You evolve into your perfect form.", ch, NULL, NULL, TO_CHAR );
//		act( AT_SKILL, "$n evolves into $s perfect form.", ch, NULL, NULL, TO_NOTVICT );
		act( AT_PURPLE, "You surge with energy as your body becomes more compact, efficient, and almost "
                                "human.  Your horns fuse into a kind of hat, your tail retracts up under your "
                                "wings as you evolve to a Perfect form.", ch, NULL, NULL, TO_CHAR );
		act( AT_PURPLE, "$n surges with energy as $s body becomes more compact, efficient, and almost "
                                "human.  $n's horns fuse into a kind of hat, $s tail retracts up under $s wings "
                                "as $e evolves to a Perfect form.", ch, NULL, NULL, TO_NOTVICT );
		ch->pl = ch->exp * 18;
		transStatApply(ch, 18, 18, 18, 18);
                ch->mana -= skill_table[gsn_perfect]->min_mana;
		return;
	}

	if (!str_prefix(argument, "ultra-perfect form")
		&& ch->pcdata->learned[gsn_ultraperfect] > 0)
	{
		if (ch->mana < skill_table[gsn_ultraperfect]->min_mana)
		{
		    send_to_char( "You don't have enough energy.\n\r", ch );
		    return;
		}

		if (xIS_SET(ch->affected_by, AFF_ULTRAPERFECT))
		{
		    send_to_char( "You are already in that form.\n\r", ch );
		    return;
		}

		xSET_BIT(ch->affected_by, AFF_ULTRAPERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_PERFECT);
		xREMOVE_BIT(ch->affected_by, AFF_SEMIPERFECT);
//		act( AT_SKILL, "You evolve into your ultra-perfect form.", ch, NULL, NULL, TO_CHAR );
//		act( AT_SKILL, "$n evolves into $s ultra-perfect form.", ch, NULL, NULL, TO_NOTVICT );
		act( AT_PURPLE, "You draw on newfound power, your body moving with perfect grace and "
                                "efficiency, your entire form free from blemish or impurity.  You calmly stand "
                                "in this most human of forms, having evolved to an Ultra-Perfect being.", ch, NULL, NULL, TO_CHAR );
		act( AT_PURPLE, "$n draws on newfound power, $s body moving with perfect grace and efficiency, "
                                "$s entire form free from blemish or impurity.  $n calmly stands in this most "
                                "human of forms, having evolved to an Ultra-Perfect being.", ch, NULL, NULL, TO_NOTVICT );
		ch->pl = ch->exp * 27;
		transStatApply(ch, 27, 27, 27, 27);
                ch->mana -= skill_table[gsn_ultraperfect]->min_mana;
		return;
	}

	return;
}

/*
 * Checks to see if the android is able to absorb part (or all)
 * of a Ki attack.  This function must be added to the ki attack
 * code for it to be checked.
 */
int ki_absorb( CHAR_DATA *ch, CHAR_DATA *victim, int damage, int ki_sn )
{
    int newDam = 0;
    int reduction = 0;
    int kiGain = 0;
 
    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	return (damage);
    }

    if( ch->race != race_lookup( "android" ) )
    {
        return (damage);
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_ki_absorb]->skill_level[ch->class] )
    {
	return (damage);
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	return (damage);
    }

    if( !IS_NPC( ch ) && IS_SET( ch->pcdata->combatFlags, CMB_NO_KI_ABSORB ) )
    {
      return (damage);
    }

    if( number_range( 1, 100 ) > 25 )
    {
        return (damage);
    }

    if (ch->focus < skill_table[gsn_ki_absorb]->focus)
    {
	return (damage);
    }
    else
    	ch->focus -= skill_table[gsn_ki_absorb]->focus;

    WAIT_STATE( ch, skill_table[gsn_ki_absorb]->beats );
    if ( can_use_skill( ch, number_percent(), gsn_ki_absorb ) )
    {
	act( AT_SKILL, "$N's Ki attack washes over your outstretched hands as you absorb some of it.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "Your Ki attack washes over $n's outstretched hands as $e absorbs some of it.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$N's Ki attack washes over $n's outstretched hands as $e absorbs some of it.", ch, NULL, victim, TO_NOTVICT );

	learn_from_success( ch, gsn_ki_absorb );
        switch( number_range( 1, 4 ) )
        {
          case 1:
            reduction = 25;
          break;

          case 2:
            reduction = 50;
          break;

          case 3:
            reduction = 75;
          break;

          case 4:
            reduction = 100;
          break;
        }
        newDam = damage * reduction / 100;
        kiGain = skill_table[ki_sn]->min_mana * reduction / 100;

        ch->mana = UMAX( ch->max_mana, ch->mana + kiGain );
    }
    else
    {
	act( AT_SKILL, "You hold your hands forward in a futile attempt to absorb $N's Ki attack.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n holds $s hands forward in a futile attempt to absorb your Ki attack.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$n holds $s hands forward in a futile attempt to absorb $N's Ki attack.", ch, NULL, victim, TO_NOTVICT );
	learn_from_failure( ch, gsn_ki_absorb );
        newDam = damage;
    }
    return (newDam);
}

void do_hells_flash( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_hells_flash]->skill_level[ch->class] )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

    if ( !IS_NPC(ch) && ch->mana < skill_table[gsn_hells_flash]->min_mana )
    {
      send_to_char( "You don't have enough energy.\n\r", ch );
      return;
    }
	if (ch->focus < skill_table[gsn_hells_flash]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_hells_flash]->focus;

    WAIT_STATE( ch, skill_table[gsn_hells_flash]->beats );
    ch->mana -= skill_table[gsn_hells_flash]->min_mana;
    if ( can_use_skill( ch, number_percent(), gsn_hells_flash ) )
    {
        dam = get_attmod( ch, victim ) * number_range( 35, 39 );
        if( ch->charge > 0 )
          dam = chargeDamMult( ch, dam );
	act( AT_SKILL, "Your hands unhinge at the wrist, exposing a frightening array of nozzles", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "and barrels.  The smell of rocket fuel permeates the air as you unleash", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "a hellish inferno upon $N. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );
	act( AT_SKILL, "$n's hands unhinge at the wrist, exposing a frightening array of nozzles", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "and barrels.  The smell of rocket fuel permeates the air as $e unleashes", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "a hellish inferno upon you. &W[$t]", ch, num_punct(dam), victim, TO_VICT );
	act( AT_SKILL, "$n's hands unhinge at the wrist, exposing a frightening array of nozzles", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "and barrels.  The smell of rocket fuel permeats the air as $n unleashes", ch, NULL, victim, TO_NOTVICT );
	act( AT_SKILL, "a hellish inferno upon $N. &W[$t]", ch, num_punct(dam), victim, TO_NOTVICT );

	learn_from_success( ch, gsn_hells_flash );
	global_retcode = damage( ch, victim, dam, gsn_hells_flash );
    }
    else
    {
	act( AT_SKILL, "Your hands unhinge at the wrist but only a weak puff of smoke escapes.", ch, NULL, victim, TO_CHAR );
	act( AT_SKILL, "$n's hands unhinge at the wrist but only a weak puff of smoke escapes.", ch, NULL, victim, TO_VICT );
	act( AT_SKILL, "$n's hands unhinge at the wrist but only a weak puff of smoke escapes.", ch, NULL, victim, TO_NOTVICT );
	learn_from_failure( ch, gsn_hells_flash );
	global_retcode = damage( ch, victim, 0, gsn_hells_flash );
    }
    return;
}

void do_ki_burst(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
	send_to_char( "You can't concentrate enough for that.\n\r", ch );
	return;
    }

    if ((ch->race == 9)
    &&   (ch->exp < skill_table[gsn_genocide]->skill_level[ch->class]) )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }
    else
    {
      if ((!IS_NPC(ch))
      &&  (ch->exp < skill_table[gsn_ki_burst]->skill_level[ch->class]))
      {
	  send_to_char( "You can't do that.\n\r", ch );
	  return;
      }
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
	send_to_char( "You aren't fighting anyone.\n\r", ch );
	return;
    }

	if ( !IS_NPC(ch) && ch->mana < skill_table[gsn_ki_burst]->min_mana )
	{
	    send_to_char( "You don't have enough energy.\n\r", ch );
	    return;
	}
	if (ch->focus < skill_table[gsn_ki_burst]->focus)
    {
		send_to_char( "You need to focus more.\n\r", ch );
		return;
    }
    else
    	ch->focus -= skill_table[gsn_ki_burst]->focus;

    WAIT_STATE( ch, skill_table[gsn_ki_burst]->beats );
    if (ch->race != 9)
    {
      if ( can_use_skill(ch, number_percent(),gsn_ki_burst ) )
      {
	  dam = get_attmod(ch, victim) * number_range( 45, 55 );
	  if (ch->charge > 0)
		dam = chargeDamMult(ch, dam);
	  act( AT_SKILL, "You clench your fists and gather your energy about you, bringing a black", ch, NULL, victim, TO_CHAR );
	  act( AT_SKILL, "and purple aura flaring up around you.  With a thought it explodes outward,", ch, NULL, victim, TO_CHAR );
        act( AT_SKILL, "forming a deadly sphere that sends $N reeling. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );
	  act( AT_SKILL, "$n clenches $s fists as a black and purple aura flares up around $m.", ch, NULL, victim, TO_VICT );
	  act( AT_SKILL, "The aura explodes outward, forming a deadly sphere that sends you reeling. &W[$t]"
                     , ch, num_punct(dam), victim, TO_VICT );
	  act( AT_SKILL, "$n clenches $s fists as a black and purple aura flares up around $m.", ch, NULL, victim, TO_NOTVICT );
	  act( AT_SKILL, "The aura explodes outward, forming a deadly sphere that sends $N reeling. &W[$t]"
			     , ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_ki_burst );
        dam = ki_absorb( victim, ch, dam, gsn_ki_burst  );
        dam = portal_counter(ch, victim, dam, gsn_ki_burst  );
        
        if (dam > 0)
          global_retcode = damage( ch, victim, dam, gsn_ki_burst );
      }
      else
      {
	  act( AT_SKILL, "You missed $N with your ki burst.", ch, NULL, victim, TO_CHAR );
	  act( AT_SKILL, "$n misses you with $s ki burst.", ch, NULL, victim, TO_VICT );
	  act( AT_SKILL, "$n missed $N with a ki burst.", ch, NULL, victim, TO_NOTVICT );
	  learn_from_failure( ch, gsn_ki_burst );
	  global_retcode = damage( ch, victim, 0, gsn_ki_burst );
      }
    }
    else
    {
      if ( can_use_skill(ch, number_percent(),gsn_genocide ) )
      {
	  dam = get_attmod(ch, victim) * number_range( 45, 55 );
	  if (ch->charge > 0)
		dam = chargeDamMult(ch, dam);
	  act( AT_PINK, "You clench your fists and gather your energy about you, bringing a black", ch, NULL, victim, TO_CHAR );
	  act( AT_PINK, "and purple aura flaring up around you.  With a thought it explodes outward,", ch, NULL, victim, TO_CHAR );
        act( AT_PINK, "forming a deadly sphere that sends $N reeling. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );
	  act( AT_PINK, "$n clenches $s fists as a black and purple aura flares up around $m.", ch, NULL, victim, TO_VICT );
	  act( AT_PINK, "The aura explodes outward, forming a deadly sphere that sends you reeling. &W[$t]"
                     , ch, num_punct(dam), victim, TO_VICT );
	  act( AT_PINK, "$n clenches $s fists as a black and purple aura flares up around $m.", ch, NULL, victim, TO_NOTVICT );
	  act( AT_PINK, "The aura explodes outward, forming a deadly sphere that sends $N reeling. &W[$t]"
			     , ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_genocide );
        dam = ki_absorb( victim, ch, dam, gsn_ki_burst  );
        dam = portal_counter(ch, victim, dam, gsn_ki_burst  );
        
        if (dam > 0)
          global_retcode = damage( ch, victim, dam, gsn_ki_burst );
      }
      else
      {
	  act( AT_PURPLE, "You missed $N with your ki burst.", ch, NULL, victim, TO_CHAR );
	  act( AT_PURPLE, "$n misses you with $s ki burst.", ch, NULL, victim, TO_VICT );
	  act( AT_PURPLE, "$n missed $N with a ki burst.", ch, NULL, victim, TO_NOTVICT );
	  learn_from_failure( ch, gsn_genocide );
	  global_retcode = damage( ch, victim, 0, TYPE_HIT );
      }
    }

	ch->mana -= skill_table[gsn_ki_burst]->min_mana;
    return;
}

void do_ssd_bomber(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
        send_to_char( "You can't concentrate enough for that.\n\r", ch );
        return;
    }

    if ((ch->race == 9)
    &&   (ch->exp < skill_table[gsn_genocide]->skill_level[ch->class]) )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return;
    }
    else
    {
      if ( (!IS_NPC(ch))
      &&   (ch->exp < skill_table[gsn_ssd_bomber]->skill_level[ch->class]))
      {
	  send_to_char( "You can't do that.\n\r", ch );
	  return;
      }
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
        send_to_char( "You aren't fighting anyone.\n\r", ch );
        return;
    }

        if ( ch->mana < skill_table[gsn_ssd_bomber]->min_mana )
        {
            send_to_char( "You don't have enough energy.\n\r", ch );
            return;
        }
        if (ch->focus < skill_table[gsn_ssd_bomber]->focus)
    {
                send_to_char( "You need to focus more.\n\r", ch );
                return;
    }
    else
        ch->focus -= skill_table[gsn_ssd_bomber]->focus;

    WAIT_STATE( ch, skill_table[gsn_ssd_bomber]->beats );
    if (ch->race != 9)
    {
      if ( can_use_skill(ch, number_percent(),gsn_ssd_bomber ) )
      {
        dam = get_attmod(ch, victim) * number_range( 44, 54 );
        if (ch->charge > 0)
                dam = chargeDamMult(ch, dam);

	  act( AT_SKILL, "You clasp your hands forward, as if charging an "
	 	       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  You push your hands forward, sending the "
		       "'Deadly Bomb' after $N which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t]",
			ch, num_punct(dam), victim, TO_CHAR );
	  act( AT_SKILL, "$n clasps $s hands forward, as if charging an "
		       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  $n pushes $s hands forward, sending the "
		       "'Deadly Bomb' after you which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t]",
			ch, num_punct(dam), victim, TO_VICT );
	  act( AT_SKILL, "$n clasps $s hands forward, as if charging an "
		       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  $n pushes $s hands forward, sending the "
		       "'Deadly Bomb' after $N which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t] ",
			ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_ssd_bomber );
        dam = portal_counter(ch, victim, dam, gsn_ssd_bomber  );
        
        if (dam > 0)
          global_retcode = damage( ch, victim, dam, gsn_ssd_bomber );
      }
      else
      {
        act( AT_SKILL, "You missed $N with your ssd bomber attack.", ch, NULL, victim, TO_CHAR );
        act( AT_SKILL, "$n misses you with $s ssd bomber attack.", ch, NULL, victim, TO_VICT );
        act( AT_SKILL, "$n missed $N with a ssd bomber attack.", ch, NULL, victim, TO_NOTVICT );
        learn_from_failure( ch, gsn_ssd_bomber );
        global_retcode = damage( ch, victim, 0, gsn_ssd_bomber );
      }
    }
    else
    {
      if ( can_use_skill(ch, number_percent(),gsn_genocide ) )
      {
        dam = get_attmod(ch, victim) * number_range( 44, 54 );
        if (ch->charge > 0)
                dam = chargeDamMult(ch, dam);

	  act( AT_PINK, "You clasp your hands forward, as if charging an "
	 	       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  You push your hands forward, sending the "
		       "'Deadly Bomb' after $N which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t]",
			ch, num_punct(dam), victim, TO_CHAR );
	  act( AT_PINK, "$n clasps $s hands forward, as if charging an "
		       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  $n pushes $s hands forward, sending the "
		       "'Deadly Bomb' after you which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t]",
			ch, num_punct(dam), victim, TO_VICT );
	  act( AT_PINK, "$n clasps $s hands forward, as if charging an "
		       "enery ball.  Suddenly, it surges with incredible "
		       "power, entangled in a spider-web-like sphere of "
		       "energy.  $n pushes $s hands forward, sending the "
		       "'Deadly Bomb' after $N which eventually causes a "
		       "tremendous explosion, giving its name credit. &W[$t] ",
			ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_genocide );
        dam = portal_counter(ch, victim, dam, gsn_ssd_bomber  );
        
        if (dam > 0)
          global_retcode = damage( ch, victim, dam, TYPE_HIT );
      }
      else
      {
        act( AT_PURPLE, "You missed $N with your ssd bomber attack.", ch, NULL, victim, TO_CHAR );
        act( AT_PURPLE, "$n misses you with $s ssd bomber attack.", ch, NULL, victim, TO_VICT );
        act( AT_PURPLE, "$n missed $N with a ssd bomber attack.", ch, NULL, victim, TO_NOTVICT );
        learn_from_failure( ch, gsn_genocide );
        global_retcode = damage( ch, victim, 0, gsn_ssd_bomber );
      }
    }

        ch->mana -= skill_table[gsn_ssd_bomber]->min_mana;
    return;
}

void do_electrichellball(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
        send_to_char( "You can't concentrate enough for that.\n\r", ch );
        return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_electrichellball]->skill_level[ch->class] )
    {
        send_to_char( "You can't do that.\n\r", ch );
        return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
        send_to_char( "You aren't fighting anyone.\n\r", ch );
        return;
    }

    if (ch->race == 6)
    {
      if (ch->pcdata->absorb_pl_mod != 5)
      {
	  act( AT_DGREY, "You bring your palms together, but nothing happens.  ", ch, NULL, victim, TO_CHAR );
	  act( AT_DGREY, "You seem to be missing something... ", ch, NULL, victim, TO_CHAR );
	  act( AT_DGREY, "$n brings $s palms together, but nothing happens. Odd. ", ch, NULL, victim, TO_VICT );
	  act( AT_DGREY, "$n brings $s palms together, but nothing happens. Odd. ", ch, NULL, victim, TO_NOTVICT );

        return;
      }
    }

        if ( ch->mana < skill_table[gsn_electrichellball]->min_mana )
        {
            send_to_char( "You don't have enough energy.\n\r", ch );
            return;
        }
        if (ch->focus < skill_table[gsn_electrichellball]->focus)
    {
                send_to_char( "You need to focus more.\n\r", ch );
                return;
    }
    else
        ch->focus -= skill_table[gsn_electrichellball]->focus;

    WAIT_STATE( ch, skill_table[gsn_electrichellball]->beats );
    if ( can_use_skill(ch, number_percent(),gsn_electrichellball ) )
    {
        dam = get_attmod(ch, victim) * number_range( 62, 69 );
        if (ch->charge > 0)
                dam = chargeDamMult(ch, dam);

	act( AT_SKILL, "You bring your palms near each other infront of "
		       "yourself and begin to charge an incredible amount "
		       "of energy into a small space. You create an energy "
		       "ball so dense it almost resembles a black hole. "
		       "Violent bolts of red electricity stream forth from "
		       "from the energy ball as it cannot be compacted any "
		       "further. Shouting 'NOW DIE' at your enemy, you fire "
		       "the attack. The energy ball impacts with $N and "
		       "explodes; engulfing $m in a gigantic explosion. &W[$t]",
			ch, num_punct(dam), victim, TO_CHAR );
	act( AT_SKILL, "$n brings $s palms near each other infront of "
		       "$mself and begins to charge an incredible amount "
		       "of energy into a small space. $n creates an energy "
		       "ball so dense it almost resembles a black hole. "
		       "Violent bolts of red electricity stream forth from "
		       "from the energy ball as it cannot be compacted any "
		       "further. Shouting 'NOW DIE' at you, $n fires the "
		       "attack. The energy ball impacts with you and "
		       "explodes; engulfing you in a gigantic explosion. &W[$t]",
			ch, num_punct(dam), victim, TO_VICT );
	act( AT_SKILL, "$n brings $s palms near each other infront of "
		       "$mself and begins to charge an incredible amount "
		       "of energy into a small space. $n creates an energy "
		       "ball so dense it almost resembles a black hole. "
		       "Violent bolts of red electricity stream forth from "
		       "from the energy ball as it cannot be compacted any "
		       "further. Shouting 'NOW DIE' at $N, $n fires the "
		       "attack. The energy ball impacts with $N and "
		       "explodes; engulfing $m in a gigantic explosion. &W[$t]",
			ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_electrichellball );
        global_retcode = damage( ch, victim, dam, gsn_electrichellball  );
    }
    else
    {
        act( AT_SKILL, "You missed $N with your electric hell ball.", ch, NULL, victim, TO_CHAR );
        act( AT_SKILL, "$n misses you with $s electric hell ball.", ch, NULL, victim, TO_VICT );
        act( AT_SKILL, "$n missed $N with an electric hell ball.", ch, NULL, victim, TO_NOTVICT );
        learn_from_failure( ch, gsn_electrichellball );
        global_retcode = damage( ch, victim, 0, gsn_electrichellball  );
    }
        ch->mana -= skill_table[gsn_electrichellball]->min_mana;
    return;
}

void do_supernova(CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    int dam = 0;

    if ( IS_NPC(ch) && IS_AFFECTED( ch, AFF_CHARM ) )
    {
        send_to_char( "You can't concentrate enough for that.\n\r", ch );
        return;
    }

    if ( !IS_NPC(ch)
    &&   ch->exp < skill_table[gsn_supernova]->skill_level[ch->class] )
    {
        send_to_char( "You can't do that.\n\r", ch );
        return;
    }

    if ( ( victim = who_fighting( ch ) ) == NULL )
    {
        send_to_char( "You aren't fighting anyone.\n\r", ch );
        return;
    }

    if (ch->race == 6)
    {
      if ((ch->pcdata->absorb_pl_mod != 6)
       && (!IS_IMMORTAL(ch)))
      {
	  act( AT_DGREY, "You ask the souls of your bio-android brethren to aid you, but too few reply.  ", ch, NULL, victim, TO_CHAR );
	  act( AT_DGREY, "You seem to be missing something... ", ch, NULL, victim, TO_CHAR );
	  act( AT_DGREY, "$n closes his eyes and breathes deeply, but nothing happens. Odd. ", ch, NULL, victim, TO_VICT );
	  act( AT_DGREY, "$n closes his eyes and breathes deeply, but nothing happens. Odd. ", ch, NULL, victim, TO_NOTVICT );

        return;
      }
    }

        if ( ch->mana < skill_table[gsn_supernova]->min_mana )
        {
            send_to_char( "You don't have enough energy.\n\r", ch );
            return;
        }
        if (ch->focus < skill_table[gsn_supernova]->focus)
    {
                send_to_char( "You need to focus more.\n\r", ch );
                return;
    }
    else
        ch->focus -= skill_table[gsn_supernova]->focus;


    WAIT_STATE( ch, skill_table[gsn_supernova]->beats );
    if ( can_use_skill(ch, number_percent(),gsn_supernova ) )
    {
        dam = get_attmod(ch, victim) * number_range( 75, 80 );
        if (ch->charge > 0)
                dam = chargeDamMult(ch, dam);

	act( AT_DGREY, "You close your eyes and breathe deeply, calling "
                     "forth the knowledge gleaned from the DNA of your " 
                     "fellow biological androids. The absolute, "
                     "unblemished power of their collective souls begins "
                     "to pulse steadily inside you, begging to be used "
                     "to their full, perfect potential. ", ch, NULL, victim, TO_CHAR );
	act( AT_DGREY, "Your eyes shoot open, your fists opening up wide "
                     "into fanned fingers that stretch as far as possible "
                     "from your twin palms. A sound of shattered glass "
                     "breaks the air, so piercingly sharp it almost "
                     "detracts from the fact that an ever-shrinking, near- "
                     "invisible shell of energy has formed around $N, and "
                     "shows no sign of yielding. ", ch, NULL, victim, TO_CHAR );
	act( AT_DGREY, "'&RSUPERNOVA!&z' you call out through involuntary "
                     "cackles of pure superiority and perfection. The shell "
                     "around your opponent suddenly erupts with blindingly "
                     "white light, slowing fading to inky black nothingness. "
                     "As the shell cracks and dissipates, your opponent is "
                     "left lying motionless on the ground in complete and utter "
                     "shambles. Whatever just happened, it really hurt. &W[$t]", ch, num_punct(dam), victim, TO_CHAR );

	act( AT_DGREY, "$n closes $s eyes and breathes deeply, an eerie feeling "
                     "filling your body. You can hear... no... *feel* voices. "
                     "They are speaking in hushed tones, but all at once they form "
                     "such a rumbling... such a rumbling... in your head... you "
                     "can barely... think...", ch, NULL, victim, TO_VICT );
	act( AT_DGREY, "$n's eyes shoot open and $s fists open wide, displaying "
                     "fanned fingers extended far from $s twin palms. A sound "
                     "of shattered glass breaks the air, silencing the voices "
                     "that had suddenly developed in your head. You are thrown "
                     "back to reality to find yourself in the exact center of an "
                     "ever-shrinking shell of energy, barely visible save the slight "
                     "shine of its edges. This could be bad.", ch, NULL, victim, TO_VICT );
	act( AT_DGREY, "'&RSUPERNOVA!&z' $e calls out between seemingly involuntary "
                     "cackles. Your vision suddenly fills with blindingly white "
                     "light, light as intense and unexpected as the pain that "
                     "fills your body. The pain is unrelentless, filling your being"
                     "completely with pure, unadulterated torture. Your vision begins "
                     "to fade to an inky black... you can feel yourself falling, "
                     "the matter around you dissipating... is this the end? &W[$t]", ch, num_punct(dam), victim, TO_VICT );

	act( AT_DGREY, "$n closes $s eyes and breathes deeply, an unsettling expression "
                     "oozing onto $N's face. $E seems inwardly disturbed, and "
                     "begins looking around in confusion at voices that are not there. "
                     "$n, on the other hand, is unnaturally calm and seems at inner peace. ", ch, NULL, victim, TO_NOTVICT );
	act( AT_DGREY, "$n's eyes shoot open and $s fists open wide, displaying "
                     "fanned fingers extended far from $s twin palms. A sound "
                     "of shattered glass breaks the air, throwing $N back "
                     "to reality to find $Mself in the center of a large, ever- "
                     "shrinking sphere of translucent energy. The confusion that "
                     "once painted $S face quickly changes to panic and realization "
                     "of impending doom. ", ch, NULL, victim, TO_NOTVICT );
	act( AT_DGREY, "'&RSUPERNOVA!&z' $e calls out between seemingly involuntary "
                     "cackles. The sphere fills with a blinding white light "
                     "milliseconds before you see $N's expression change to one of "
                     "absolute pain. Almost immediately, the light fades to a black "
                     "so deep it seems to absorb the ambient light into a pitch black "
                     "'hole'. The sphere cracks and falls to pieces which dissipate "
                     "into thin air, leaving behind a broken, wounded $N. &W[$t]", ch, num_punct(dam), victim, TO_NOTVICT );

        learn_from_success( ch, gsn_supernova );
        global_retcode = damage( ch, victim, dam, gsn_supernova  );
    }
    else
    {
        act( AT_SKILL, "You close your eyes to call upon the souls of your bio-android brethren, but none reply.", ch, NULL, victim, TO_CHAR );
        act( AT_SKILL, "$n closes his eyes, but nothing further happens.", ch, NULL, victim, TO_VICT );
        act( AT_SKILL, "$n closes his eyes, but nothing further happens.", ch, NULL, victim, TO_NOTVICT );
        learn_from_failure( ch, gsn_supernova );
        global_retcode = damage( ch, victim, 0, gsn_supernova );
    }
        ch->mana -= skill_table[gsn_supernova]->min_mana;
    return;
}
