/*
Airmail code by Trithemius - pbohme@concentric.net
*/

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

DECLARE_DO_FUN(do_look);

static char *	const	dir_name	[]		=
{
    "north", "east", "south", "west", "up", "down"
};

#define MAX_SPECTATORS 100

bool check_airmail_dir(CHAR_DATA* ch, ROOM_INDEX_DATA* to_room, EXIT_DATA* pexit)
{
	   /* impassable door*/
return !(IS_SET(pexit->exit_info, EX_CLOSED) && 
	   (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_NOPASS))) ||
	   /* unenterable room */
       (!is_room_owner(ch,to_room) && room_is_private(to_room)) ||
	   /* elemental difficulties.. */
       ((to_room->sector_type == SECT_AIR ||
         to_room->sector_type == SECT_WATER_NOSWIM)
         && !IS_AFFECTED(ch,AFF_FLYING));
}

void airmail_damage(CHAR_DATA* ch, CHAR_DATA* victim, int num)
{
	/* Make the damage depend on the force of the throw and how far flown */
	int amount = number_range(5 * victim->size, 5 * victim->size * (num + 1));

	WAIT_STATE(ch, PULSE_VIOLENCE);
	damage(ch,victim, amount, TYPE_UNDEFINED, DAM_BASH, FALSE);
	check_killer(ch, victim);
}

void airmail_char(CHAR_DATA *ch, CHAR_DATA *victim, int door, CHAR_DATA* lst[], int* spectator_count, int num)
{
   ROOM_INDEX_DATA *in_room;
   ROOM_INDEX_DATA *to_room;
   EXIT_DATA *pexit;
   CHAR_DATA* target;
   int s;

/*   
   in_room = ch->in_room;
*/
   in_room = victim->in_room;
   pexit = in_room->exit[door];

   if(pexit)
   {
	   to_room = pexit->u1.to_room;
   }

   /* End of the line */
   if(num <= 0)
   {
	   /* It didn't go far..  */
	  if(in_room == ch->in_room)
	  {
		  act("With a mighty heave you throw $M $T.", ch, victim, dir_name[door], TO_CHAR);
		  act("With a mighty heave $n throws $N into the air!", ch, NULL, victim, TO_ROOM);
	  }

	  act("$n lands in an unceremonious heap.", 
		  victim, NULL, NULL, TO_ROOM);
	  act("You hear a confused racket as $N completes $S erstwhile journey.", 
		  ch, NULL, victim, TO_CHAR);
      send_to_char("Your journey is suddenly arrested by the floor.\n\r", victim);

	  /* Keep the spectators informed.. */
	  for(s = 0; s < *spectator_count; s++)
	  {
		  act("You hear a confused racket as $N completes $S erstwhile journey.", 
			  lst[s], NULL, victim, TO_CHAR);
	  }

	  airmail_damage(ch, victim, num);
   }
   else if(pexit == NULL || to_room == NULL)
   {
	   /* It didn't go far..  */
	  if(in_room == ch->in_room)
	  {
		  act("With a mighty heave you throw $M $T.", ch, victim, dir_name[door], TO_CHAR);
		  act("With a mighty heave $n throws $N into the air!", ch, NULL, victim, TO_ROOM);
	  }

	  act("$n crashes into the wall and lands in a disgruntled heap.", victim, NULL, NULL, TO_ROOM);
      send_to_char("*CRUNCH* is the sound of you bouncing.\n\r", victim);

	  if(in_room == ch->in_room)
	  {
		  act("*CRUNCH* is the sound of $N bouncing.", ch, NULL, victim, TO_CHAR);
	  }
	  else
	  {
		  act("You hear a confused racket as $N completes $S erstwhile journey.", 
			  ch, NULL, victim, TO_CHAR);

		  /* Keep the spectators informed.. */
		  for(s = 0; s < *spectator_count; s++)
		  {
			  act("You hear a confused racket as $N completes $S erstwhile journey.", 
				  lst[s], NULL, victim, TO_CHAR);
		  }
	  }

	  airmail_damage(ch, victim, num);
   }
   else if(!check_airmail_dir(ch, to_room, pexit))
   {
	  act("$n gets a physics lesson from the $d and lands in a disgruntled heap.", victim, NULL, pexit->keyword, TO_ROOM);
      act("OWCH! is the sound of you missing the $d.", victim, NULL, pexit->keyword, TO_CHAR);

	  if(in_room == ch->in_room)
	  {
		  act("Ooooh!  With a neato crunch $N bounced!", ch, NULL, victim, TO_CHAR);
	  }
	  else
	  {
		  act("You hear a confused racket as $N completes $S erstwhile journey.", 
			  ch, NULL, victim, TO_CHAR);

		  /* Keep the spectators informed.. */
		  for(s = 0; s < *spectator_count; s++)
		  {
			  act("You hear a confused racket as $N completes $S erstwhile journey.", 
				  lst[s], NULL, victim, TO_CHAR);
		  }
	  }

	  airmail_damage(ch, victim, num);
   }
   else 
   {
      if(ch->fighting != NULL)
      {
         stop_fighting(ch, TRUE);
         if(ch->position == POS_FIGHTING)
         {
            ch->position = POS_STANDING;
         }
      }

	  /* only way to tell if this is the initial throw or not */
	  if(in_room == ch->in_room)
	  {
		  act("With a mighty heave you throw $M $T.", ch, victim, dir_name[door], TO_CHAR);
		  act("With a mighty heave $n throws $N into the air!", ch, NULL, victim, TO_ROOM);

		  /* First time through?  Add spectators in this room */
		  target = in_room->people;
		  while(target && *spectator_count < MAX_SPECTATORS)
		  {
			  if(target != ch && target != victim)
			  {
				lst[(*spectator_count)++] = target;
			  }

			  target = target->next_in_room;
		  }
	  }
	  else
	  {
		  /* This one to the player only, to cut down on spam  */
		  act("You hear swooshing noises to the $T.", ch, victim, dir_name[door], TO_CHAR);
	  }


      act("$n cuts a perfect arc as $E sails $T.", victim, NULL, dir_name[door], TO_ROOM);
      char_from_room(victim);
      char_to_room(victim, to_room);

	  act("In a swoosh of air $n sails in looking quite confused.", victim, NULL, NULL, TO_ROOM);
      do_look(victim, "auto");

	  /* Figure collisions */
	  target = to_room->people;
	  while(target)
	  {
		  /* Hm. */
		  if(target == victim)
		  {
			  target = target->next_in_room;
			  continue;
		  }

		  if((target->size + victim->size) * 10 > number_range(0, 200))
		  {
			  /* They collide, and a fight ensues */
			  act("The $n smashes headlong into $N!", victim, NULL, target, TO_ROOM);
			  act("You smash into $N!", victim, NULL, target, TO_CHAR);
			  act("$n crashes into you!", victim, NULL, target, TO_VICT);
			  act("There is a confused shriek as the $N crashes into someone.", ch, NULL, victim, TO_CHAR);

			  /* Keep the spectators informed.. */
			  for(s = 0; s < *spectator_count; s++)
			  {
				  act("There is a confused shriek as the $N crashes into someone.", lst[s], NULL, victim, TO_CHAR);
			  }

			  airmail_damage(victim, target, num);
			  airmail_damage(target, victim, num);
			  break;
		  }
		  
		  target = target->next_in_room;
	  }

	  if(!target)
	  {
  		  /* Add spectators in this room */
		  target = to_room->people;
		  while(target && *spectator_count < MAX_SPECTATORS)
		  {
			  if(target != ch && target != victim)
			  {
				lst[(*spectator_count)++] = target;
			  }
			  target = target->next_in_room;
		  }

		  /* recurse to keep going */
		  airmail_char(ch, victim, door, lst, spectator_count, num - 1);
	  }
   }

   return;
}

void do_airmail(CHAR_DATA *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *victim = NULL;
	char* tmp;
	int door;
	int force = 3;
	CHAR_DATA* lst[MAX_SPECTATORS];
	int spectator_count = 0;

	/* Get a victim */
    tmp = one_argument(argument,arg);
    victim = get_char_room(ch, arg);
	if (victim == NULL)
	{
		send_to_char("Um, airmail -who-?\n\r",ch);
		return;
	}

	/* Figure out how far we can throw this sucker */
	/* Heavily weighted for physical size */
	force = URANGE(0,
		           (get_curr_stat(ch, STAT_STR) / 5) - ((victim->size - ch->size) * 2),
				   5);

	/* Heh, not very far at all.. */
	if(force <= 0)
	{
		/* Oops, ya done pissed 'em off */
		send_to_char("You grunt and heave but they refuse to budge!\r\n", ch);
		damage(ch,victim,0,TYPE_UNDEFINED,DAM_BASH,FALSE);
		return;
	}

	/* Get a direction or pick one.. */
    one_argument(tmp, arg);
	if(arg[0] == '\0') door = number_door();
    if ( !str_cmp( arg, "n" ) || !str_cmp( arg, "north" ) ) door = 0;
    else if ( !str_cmp( arg, "e" ) || !str_cmp( arg, "east"  ) ) door = 1;
    else if ( !str_cmp( arg, "s" ) || !str_cmp( arg, "south" ) ) door = 2;
    else if ( !str_cmp( arg, "w" ) || !str_cmp( arg, "west"  ) ) door = 3;
    else if ( !str_cmp( arg, "u" ) || !str_cmp( arg, "up"    ) ) door = 4;
    else if ( !str_cmp( arg, "d" ) || !str_cmp( arg, "down"  ) ) door = 5;	
	else door = number_door();

	airmail_char(ch, victim, door, lst, &spectator_count, force);
}
