
#include <stdio.h>
#include "config.h"
#include "structs.h"
#include "utils.h"
#include "command.h"
#include "db.h"
#include "functions.h"
#include "movement.h"


/* EXTERNAL VARIABLES ETC */
extern int axis_limit,mask,shift;
extern struct grid_index_element *grid_list;
extern struct room_data *tmp_room;
extern struct zone_data *zone_list;

extern char buf[SMALL_BUFSIZE];
extern char buf1[SMALL_BUFSIZE];
extern char buf2[SMALL_BUFSIZE];

void do_position(struct char_data *ch, char *arg)
{
   int pos=ch->POSITION;

   if(pos == POS_ASLEEP) {
      sprintf(buf,"stops sleeping and ");
      sprintf(buf1,"You stop sleeping and ");
   } else if(pos == POS_RESTING) {
      sprintf(buf,"stops resting and ");
      sprintf(buf1,"You stop resting and ");
   } else {
      sprintf(buf,"\0");
      sprintf(buf1,"\0");
   }

   if(pos == POS_FIGHTING) {
      send_2_output("You can't do that whilst you are fighting!\n\r",ch->desc);
      return;
   } else if(!shrt_cmp(arg,"stand")) {
      ch->POSITION=POS_STANDING;
      if(pos > POS_RESTING) {
         strcat(buf,"stands up.");
         strcat(buf1,"You stand up.\n\r");
      } else if(pos < POS_SITTING) {
         strcat(buf,"stands up.");
         strcat(buf1,"stand up.\n\r");
      } else {
         send_2_output("You are already standing!\n\r",ch->desc);
         return;
      }
   } else if(!shrt_cmp(arg,"rest")) {
      ch->POSITION=POS_RESTING;
      if(pos < POS_RESTING) {
         strcat(buf,"rests.");
         strcat(buf1,"rest.\n\r");
      } else if(pos > POS_RESTING) {
         send_2_output("You lie down and rest your weary body.\n\r",ch->desc);
         send_2_room(ch,IGNR_INVIS,"lies down and rests his weary body.");
         return;
      } else {
         send_2_output("You are already resting!\n\r",ch->desc);
         return;
      }
   } else if(!shrt_cmp(arg,"sit")) {
      ch->POSITION=POS_SITTING;
      if(pos > POS_SITTING) {
         send_2_output("You sit down.\n\r",ch->desc);
         send_2_room(ch,IGNR_INVIS,"sits down.");
         return;
      } else if(pos < POS_SITTING) {
         strcat(buf,"sits up.");
         strcat(buf1,"sit up.\n\r");
      } else {
         send_2_output("You are already sitting!\n\r",ch->desc);
         return;
      }
   } else if(!shrt_cmp(arg, "sleep")) {
      ch->POSITION=POS_ASLEEP;
      if(pos > POS_RESTING) {
         send_2_output("You lie down and fall asleep.\n\r",ch->desc);
         send_2_room(ch,IGNR_INVIS,"lies down and falls asleep.");
         return;
      } else if(pos > POS_ASLEEP) {
         strcat(buf,"falls asleep.");
         strcat(buf1,"fall asleep.\n\r");
      } else {
         send_2_output("You are already asleep!\n\r",ch->desc);
         return;
      }
   } else if(!shrt_cmp(arg, "wake")) {
      if(pos != POS_ASLEEP) {
         send_2_output("You are already awake!\n\r",ch->desc);
         return;
      } else {
         ch->POSITION=POS_SITTING;
         strcat(buf,"sits up.");
         strcat(buf1,"sit up.\n\r");
      }
   }
   send_2_room(ch,IGNR_INVIS,buf);
   send_2_output(buf1,ch->desc);
   return;
}

void  do_unlock(struct char_data *ch,char *arg,char mode)
{
	char *name1;
	int  exit;

	if(mode == LOCKED) {
		name1 = "lock";
	} else {
		name1 = "unlock";
	}

	if(!get_target(buf,arg,1)) {
		sprintf(buf,"%s what?\n\r",name1);
		send_2_output(buf,ch->desc);
		return;
   } else if((exit=exit_cmp(buf,ch->in_room)) > -1) {
		if(!BTST(ch->in_room->exits[exit]->status,OPEN+CLOSED+LOCKED)) {
			send_2_output("That direction does not have a door!\n\r",ch->desc);
		} else if(BTST(ch->in_room->exits[exit]->status,mode)) {
			sprintf(buf,"It is already %sed\n\r",name1);
			send_2_output(buf,ch->desc);
		} else if(match_key(ch,ch->in_room->exits[exit]->key)) {
			BCLR(ch->in_room->exits[exit]->status,CLOSED+OPEN+LOCKED);
			BSET(ch->in_room->exits[exit]->status,mode);
			sprintf(buf,"You %s the %s %s\n\r",name1,exit_list[exit].name,
               (ch->in_room->exits[exit]->alias ? ch->in_room->exits[exit]->alias : "door"));
			send_2_output(buf,ch->desc);
			sprintf(buf,"%ss the %s %s",name1,exit_list[exit].name,
               (ch->in_room->exits[exit]->alias ? ch->in_room->exits[exit]->alias : "door"));
      	send_2_room(ch,IGNR_INVIS,buf);
		} else {
			sprintf(buf,"You don't have the right key to %s that!\n\r",name1);
			send_2_output(buf,ch->desc);
		}
		return;
	}
	sprintf(buf,"You can't %s that!\n\r",name1);
	send_2_output(buf,ch->desc);
}

void  do_open(struct char_data *ch,char *arg,char mode)
{
	char *name1,*name2;
	int  exit;

	if(mode == CLOSED) {
		name1 = "close";
		name2 = "closed";
	} else {
		name1 = "open";
		name2 = "open";
	}

	if(!get_target(buf,arg,1)) {
		sprintf(buf,"%s what?\n\r",name1);
		send_2_output(buf,ch->desc);
		return;
   } else if((exit=exit_cmp(buf,ch->in_room)) > -1) {
		if(!BTST(ch->in_room->exits[exit]->status,OPEN+CLOSED+LOCKED)) {
			send_2_output("That direction does not have a door!\n\r",ch->desc);
		} else if(BTST(ch->in_room->exits[exit]->status,mode)) {
			sprintf(buf,"It is already %s\n\r",name2);
			send_2_output(buf,ch->desc);
		} else if(BTST(ch->in_room->exits[exit]->status,LOCKED)) {
			sprintf(buf,"The %s is locked\n\r",
					(ch->in_room->exits[exit]->alias ? ch->in_room->exits[exit]->alias : "door"));
			send_2_output(buf,ch->desc);
		} else {
			BCLR(ch->in_room->exits[exit]->status,CLOSED+OPEN);
			BSET(ch->in_room->exits[exit]->status,mode);
			sprintf(buf,"You %s the %s %s\n\r",name1,exit_list[exit].name,
               (ch->in_room->exits[exit]->alias ? ch->in_room->exits[exit]->alias : "door"));
			send_2_output(buf,ch->desc);
			sprintf(buf,"%ss the %s %s",name1,exit_list[exit].name,
					(ch->in_room->exits[exit]->alias ? ch->in_room->exits[exit]->alias : "door"));
      	send_2_room(ch,IGNR_INVIS,buf);
		}
		return;
	}
	sprintf(buf,"You can't %s that!\n\r",name1);
	send_2_output(buf,ch->desc);
}
void	do_scan(struct char_data *ch)
{
	do_look(ch,"+");
	do_exit(ch);
}	
void  do_exit(struct char_data *ch)
{
	long tmp_idnum;
   int  x,y,z,room,zone,found=0,c;

	send_2_output("\n\rExits:-\n\r",ch->desc);

	if(BTST(ch->in_room->flags,VOID_ROOM)) {
		send_2_output("You can go in any direction you please...\n\r",ch->desc);
		return;
	}
   /* Search through the exit list */
	for(c=0;c<10;c++) 
	{
		if((ch->in_room->exits[c]) && 
			(ch->LEVEL >= GOD || !BTST(ch->in_room->exits[c]->status,HIDDEN))) 
		{
			get_adjacent_room(&x,&y,&z,&room,IN_ROOM(ch),c);
			if(((zone = get_zone(x,y,z)) > -1) && zone_list[zone].room[room]) 
			{
				if(BTST(ch->in_room->exits[c]->status,CLOSED+LOCKED))
				{
					if(ch->LEVEL >= GOD)
						sprintf(buf,"%9s - A Door leading to %s.\n\r",exit_list[c].name,zone_list[zone].room[room]->name);
					else
						sprintf(buf,"%9s - A Door.\n\r",exit_list[c].name);
				}
				else
					sprintf(buf,"%9s - %s.\n\r",exit_list[c].name,zone_list[zone].room[room]->name);
			} 
			else 
			{
				sprintf(buf,"%9s - Nothing.\n\r",exit_list[c].name);
			}
			send_2_output(buf,ch->desc);
			found++;
		}
	}
	if(!found)
      send_2_output("There are no visible exits!\n\r",ch->desc);
}

void  do_direction(struct char_data *ch,int dir)
{
	int zone_x,zone_y,zone_z,room;
   struct exit_data *exit;

	// CRTH - Mod for swimmers!!
	if(ch->POSITION != POS_SWIMMING && BTST(ch->in_room->flags,WATER_ROOM) && ch->LEVEL < IMP){
		send_2_output("You will have to swim for it.",ch->desc);
		return;
	} else if(ch->POSITION == POS_FIGHTING) {
      send_2_output("If you want to leave a fight, type 'flee'!\n\r",ch->desc);
      return;
   } else if(!BTST(ch->in_room->flags,VOID_ROOM) && ch->LEVEL < IMP) { 
		if(ch->in_room->exits[dir] == 0) {
			send_2_output("You can't go that way.\n\r",ch->desc);
			return;
		} else if(!valid_exit(ch,ch->in_room->exits[dir])) {
			return;
		}
	}
	/* Get the room we want to enter (can always enter none existant rooms) */
	tmp_room=get_adjacent_room(&zone_x,&zone_y,&zone_z,&room,IN_ROOM(ch),dir);

	/* Is it a valid room (!EVIL !CLERIC etc)? */
	if(valid_room(ch,tmp_room)) {
		if(tmp_room->MOVE_COST)
			ch->MOVE -= tmp_room->MOVE_COST;
//		else
//			ch->MOVE -= 3;
		if(!BTST(tmp_room->flags,WATER_ROOM) && ch->POSITION == POS_SWIMMING)
			ch->POSITION = POS_STANDING;
		sprintf(buf,"leaves %s",exit_list[dir].name);
		char_from_room(ch,buf);
		char_2_room(ch,tmp_room,"has arrived");
	}
}

int valid_room(struct char_data *ch,struct room_data *room)
{
   int ppl=0;
   struct char_data *who, *who_next;

   if(ch->LEVEL == IMP) {
      return(1);
	} else if(room->MOVE_COST > ch->MOVE) {
		send_2_output("You are too tired to move...\n\r",ch->desc);
		return(0);
   } else if(BTST(room->SEX,sex_bits[ch->SEX]) || BTST(room->CLASS,class_bits[ch->CLASS])
		|| BTST(room->ALIGN,align[ch->ALIGN/660].bit)) {
      send_2_output("An unseen force prevents you from entering.\n\r",ch->desc);
      return(0);
	} else if(!room->MAX_LEVEL) {
         send_2_output("That direction is under construction!\n\r",ch->desc);
         return(0);
   } else if(room->MAX_LEVEL < ch->LEVEL) {
         sprintf(buf,"You have to be level %d or less to go there.\n\r",room->MAX_LEVEL);
         send_2_output(buf,ch->desc);
         return(0);
   } else if(room->MIN_LEVEL > ch->LEVEL) {
         sprintf(buf,"You have to be at least level %d to go there.\n\r",room->MIN_LEVEL);
         send_2_output(buf,ch->desc);
         return(0);
   } else if(BTST(room->flags,PRIVATE)) {
      for(who=room->people;who;who=who_next) {
         who_next=who->next_in_room;
         ppl++;
      }
      if(ppl>=2) {
         send_2_output("Private room: room is full at the moment.\n\r",ch->desc);
         return(0);
      }
   }
   return(1);
}

/* Return 0 for invalid and 1 for valid */
int   valid_exit(struct char_data *ch, struct exit_data *exit)
{
   if(ch->LEVEL >= GOD || !exit) {
      return(1);
   } else if(BTST(exit->status,CLOSED)) {
      if(exit->alias) {
         sprintf(buf,"The %s is closed.\n\r",buf1);
         send_2_output(buf,ch->desc);
      } else {
         send_2_output("The door is closed.\n\r",ch->desc);
      }
      return(0);
   } else if(BTST(exit->status,LOCKED)) {
      if(exit->alias) {
         sprintf(buf,"The %s is locked.\n\r",exit->alias);
         send_2_output(buf,ch->desc);
      } else {
         send_2_output("That door is locked.\n\r",ch->desc);
      }
      return(0);
   }
   return(1);
}

void  do_follow(struct char_data *ch, char *arg)
{
   struct char_data *who, *next_who;

   if(!get_arg(buf,arg,1)) {
      send_2_output("Am I supposed to guess who you want to follow??\n\r",ch->desc);
      return;
   }

   for(who=ch->in_room->people;who;who=next_who) {
      next_who=who->next_in_room;
      if(!shrt_cmp(buf,who->name)) {
         if(who == ch) {
            send_2_output("You start walking around in circles\n\r",ch->desc);
            send_2_room(ch,IGNR_INVIS,"starts walking around in circles");
            return;
         } else {
            follow_leader(ch,who);
            return;
         }
      }
   }

   send_2_output("They don't appear to be around.\n\r",ch->desc);
   return;
}

void  do_group(struct char_data *ch)
{
   struct char_data *who, *next_who;

   if(!ch->leader && !ch->followers) {
      send_2_output("You are not a member of a group!\n\r",ch->desc);
      return;
   } else {
      if(ch->leader) {
         sprintf(buf,"You are a member of %s's group:\n\r",ch->leader->name);
         send_2_output(buf,ch->desc);
         who=ch->leader;
      } else {
         send_2_output("Members of your group:\n\r",ch->desc);
         who=ch->followers;
      }
      for(who=who;who;who=next_who) {
         next_who=who->next_follower;
         sprintf(buf,"[%2d] HP:%d(%d) MA:%d(%d) MV:%d(%d)\t%s\n\r",
            who->LEVEL,who->HIT,who->MAX_HIT,who->MANA,who->MAX_MANA,who->MOVE,who->MAX_MOVE,who->name);
         send_2_output(buf,ch->desc);
      }
   }
   return;
}

void  do_ungroup(struct char_data *ch)
{
   struct char_data *who, *next_who;

   if(!ch->leader && !ch->followers) {
      send_2_output("You are not a member of a group.\n\r",ch->desc);
   } else if(ch->leader) {
      sprintf(buf,"You stop following %s.\n\r",ch->leader->name);
      send_2_output(buf,ch->desc);
      dump_leader(ch);
   } else {
      send_2_output("You disband the group.\n\r",ch->desc);
      disband_followers(ch);
   }
   return;
}

void  do_flee(struct char_data *ch)
{
   return;
}


void char_2_room(struct char_data *ch,struct room_data *room,char *msg)
{
	ch->in_room = room;
   ch->next_in_room=room->people;
   room->people=ch;
  	send_2_room(ch,IGNR_INVIS,msg);
   do_look(ch,"+");
}

void char_from_room(struct char_data *ch, char *msg)
{
   struct char_data *who;

	/* Is the character in a room? */
	if(!IN_ROOM(ch))
		return;

   if(ANY_PEOPLE(ch) == ch) {
      ANY_PEOPLE(ch) = ch->next_in_room;
   } else {
      for(who=ANY_PEOPLE(ch);(who->next_in_room != ch) && who;who=who->next_in_room);
      who->next_in_room=ch->next_in_room;
   }
	if(!ANY_PEOPLE(ch) && !ANY_OBJECTS(ch) && BTST(ROOM_FLAGS(ch),VOID_ROOM)) {
		delete_void_room(IN_ROOM(ch));
	} else {
   	send_2_room(ch,IGNR_INVIS,msg);
	}
	IN_ROOM(ch) = 0x0;
}


/* Get the adjacent room to 'idnum' in the direction of 'dir' */
/* x,y,z: Returns the co-ordinates of the target zone */
/*  room: Returns the adjacent room */
/*   dir: The direction of travel */
struct room_data *get_adjacent_room(
int (*x),int (*y),int (*z),int (*room),struct room_data *s_room,int dir)
{
	int room_x,room_y;

	(*x) = s_room->X;
	(*y) = s_room->Y;
	(*z) = s_room->Z;

	if((room_x=(s_room->ROOM%ZONE_WIDTH)+exit_list[dir].X)<0 || room_x >(ZONE_WIDTH-1)) {
		if(((*x) += exit_list[dir].X)<(axis_limit*-1) || (*x) >axis_limit) {
			(*x) &= mask;
		} else {
			room_x -= (ZONE_WIDTH*exit_list[dir].X);
		}
	}
	if((room_y=(s_room->ROOM/ZONE_WIDTH)+exit_list[dir].Y)<0 || room_y >(ZONE_WIDTH-1)) {
		if(((*y) += exit_list[dir].Y)<(axis_limit*-1) || (*y) >axis_limit) {
			(*y) &= mask;
		} else {
			room_y -= (ZONE_WIDTH*exit_list[dir].Y);
		}
	}
	if(((*z) += exit_list[dir].Z)<(axis_limit*-1) || (*z) >axis_limit)
		(*z) &= mask;
	(*room) = (room_y*ZONE_WIDTH)+room_x;

	/* Return the address of the room data */
	return(get_room((*x),(*y),(*z),(*room)));
}

