/* MAKE SURE TO JAVA_REMOVE_FROM_FIELD to everyone */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "emlen.h"

#ifndef WINDOWS
#include <sys/time.h>
#include <dirent.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/types.h>
#endif


COMBAT_FIELD *field_list=NULL;
COMBAT_FIELD *free_field_list=NULL;
bool closeto=FALSE;
#define FIELD_TICK_WAIT 5


bool remove_from_combat_field(CHAR_DATA *ch);
bool remove_from_combat_field_yes(CHAR_DATA *ch);

void act_to_non_java(char *arg, CHAR_DATA *ch) {
CHAR_DATA *c;
if (!ch->in_room) return;
for (c=ch->in_room->more->people;c;c=c->next_in_room) {
	if (IS_JAVA(c)) continue;
	if (c==ch) continue;
	act(arg,c,NULL,ch,TO_CHAR);
	}
return;
}

#ifndef OLD_FIGHT
bool nobody_near(CHAR_DATA *c) {
int x,y;
COMBAT_FIELD *cf;
if (!c->fgt || !c->fgt->field) return TRUE;
x=c->fgt->pos_x;
y=c->fgt->pos_y;
cf=c->fgt->field;
if (x>0 && cf->map[x-1][y]!=NULL) return FALSE;
if (x<6 && cf->map[x+1][y]!=NULL) return FALSE;
if (y>0 && cf->map[x][y-1]!=NULL) return FALSE;
if (y<6 && cf->map[x][y+1]!=NULL) return FALSE;
return TRUE;
}


/* For field_move, we can be sure fgt exists, as well as field and other
   related sub-structures.  POSSIBLE debug trap later if problems arise. */
void field_move(CHAR_DATA *ch, int dir) {
int i,j;
int x,y;
int tx,ty;
char buf[500];
COMBAT_FIELD *f=ch->fgt->field;
if (dir==-1) return;
if (ch->position==POSITION_GROUNDFIGHTING) return;

i=ch->fgt->pos_x;
j=ch->fgt->pos_y;
if (dir==DIR_NORTH && j>0) {
	x=i;
	y=j-1;
	} else
if (dir==DIR_SOUTH && j<6) {
	x=i;
	y=j+1;
	} else
if (dir==DIR_EAST && i<6) {
	x=i+1;
	y=j;
	} else
if (dir==DIR_WEST && i>0) {
	x=i-1;
	y=j;
	} else
	{ /* moving off battle field... */
	/*fprintf(stderr,"%s tried to move in dir %d.\n",NAME(ch),dir);
	*/
	send_to_char("If you want to flee, type FLEE...\n\r",ch);
	return;
	}
if (f->map[x][y]!=NULL) {
	/* Okay, we moved INTO someone.. attack!! */
	if (IS_PLAYER(ch) && IS_PLAYER(f->map[x][y]) && FIGHTING(f->map[x][y])!=ch && FIGHTING(ch)!=f->map[x][y] && !not_is_same_align(ch,f->map[x][y])) {
		return;
		}
	if (IS_MOB(ch) && IS_MOB(f->map[x][y]) && FIGHTING(ch)!=f->map[x][y] &&
		FIGHTING(f->map[x][y])!=ch) {
		return;
		}
	/* CHECK FOR FRIENDS/ETC HERE */
	hitop=FALSE;
	multi_hit(ch,f->map[x][y],TYPE_UNDEFINED);
        if (hitop) {
		java_hit_field(f,ch,i,j,x,y);
		} else
		{ /* Send miss here? */
		}
	} else
	{
	/*for (tx=0;tx<7;tx++) {
		for (ty=0;ty<7;ty++) {
			if (f->map[tx][ty]) {*/
				java_update_field(f,ch,i,j,x,y);
				/*}
			}
		}*/
	f->map[i][j]=NULL;
	f->map[x][y]=ch;
	ch->fgt->pos_x=x;
	ch->fgt->pos_y=y;
	if (ch->move<4) {
	send_to_char("You are too exhausted to move!\n\r",ch);
	return;
	}
	SUBMOVE(ch,3);
/* sprintf(buf,"$N moves to %d, %d.",x,y);
	act_to_non_java(buf,ch);*/
/*	if (!IS_JAVA(ch)) {
		sprintf(buf,"You advance.\n\r");
		send_to_char(buf,ch);
		}*/

	}
return;
}
#endif

/* Returns direction if the mob/target is next to the person on the field */
int is_fighting_near(CHAR_DATA *ch, CHAR_DATA *target) {
#ifndef OLD_FIGHT
COMBAT_FIELD *cf=ch->fgt->field;
int i=ch->fgt->pos_x;
int j=ch->fgt->pos_y;
if (cf==NULL) return -1;
if (!target) {
	remove_from_combat_field(ch);
	return -1;
	}
check_fgt(target);
if (cf!=target->fgt->field) return -1;
if (i>0 && cf->map[i-1][j]==target) return DIR_WEST;
if (i<6 && cf->map[i+1][j]==target) return DIR_EAST;
if (j>0 && cf->map[i][j-1]==target) return DIR_NORTH;
if (j<6 && cf->map[i][j+1]==target) return DIR_SOUTH;
return -1;
#else
return 1;
#endif
}

/* This updates all combat field movement, etc */
void combat_field_update(void) {
#ifndef OLD_FIGHT
COMBAT_FIELD *f;
int pif=0;
CHAR_DATA *cif=NULL;
COMBAT_FIELD *f_next;
int i,j;
for (f=field_list;f!=NULL;f=f_next) {
	f_next=f->next;
	for (i=0;i<7;i++) {
		for (j=0; j<7; j++) {
			if (f->map[i][j]) {
				CHAR_DATA *c=f->map[i][j];
				cif=c;
				pif++;
				if (!c->fgt) continue; /* ERROR */
				if ((--c->fgt->field_ticks) == 0) {
					if (c->fgt->next_command==NULL && (IS_MOB(c) /*|| !IS_JAVA(c)*/ || c->fgt->auto_toggles ||
						(is_fighting_near(c,FIGHTING(c))!=-1 && c->fgt->next_command==NULL))) { /* CHANGE AUTOS LATER */
						if (is_fighting_near(c,FIGHTING(c))!=-1) {
							field_move(c,is_fighting_near(c,FIGHTING(c)));
							} else {
							field_move(c,find_attack_direction(c,FIGHTING(c)));
							}
						} else {
						if (c->fgt->next_command) {
							interpret(c,c->fgt->next_command);
							}
						}
					if (c->fgt) {
						c->fgt->field_ticks=number_range(FIELD_TICK_WAIT-1,FIELD_TICK_WAIT+1);
						if (nobody_near(c)) {
							c->fgt->field_ticks--;
							if (IS_MOB(c) && number_range(1,2)==2) c->fgt->field_ticks--;
							}
	/* Add speed-up enhancements here */
						if (c->fgt->next_command) {
							java_cnc(c);
							free(c->fgt->next_command);
							}
						c->fgt->next_command=NULL;
						}
					}
				}
			}
		}		
	if (pif==1 && cif!=NULL && FIGHTING(cif)==NULL) {
		remove_from_combat_field_yes(cif);
		}
	}
#endif
return;
}

/* Returns TRUE if ch will attack victim, FALSE if ch will just go for
   target and ignore victim */
#ifndef OLD_FIGHT
bool good_hit(CHAR_DATA *ch, CHAR_DATA *victim) {
if (IS_MOB(ch) && IS_PLAYER(victim)) return TRUE;
if (not_is_same_align(ch,victim)) return TRUE;
return FALSE;
}

/* Returns best direction for ch to attack victim */
/* 0,0      6,0 */
/*		*/
/* 0,6      6,6 */
int find_attack_direction(CHAR_DATA *ch, CHAR_DATA *victim) {
COMBAT_FIELD *cf;
int i,j,x,y;
if (!victim) return -1;
if (!ch->fgt || !victim->fgt) return -1;
if ( (cf=ch->fgt->field) == NULL ) return -1;
if (cf!=victim->fgt->field) return -1;
i=ch->fgt->pos_x;
j=ch->fgt->pos_y;
x=victim->fgt->pos_x;
y=victim->fgt->pos_y;
if (i<x && j<y) {
	if (cf->map[i][j+1]!=NULL && cf->map[i][j+1]!=victim && !good_hit(ch,cf->map[i][j+1])) return DIR_NORTH;
	if (cf->map[i+1][j]!=NULL && cf->map[i+1][j]!=victim && !good_hit(ch,cf->map[i+1][j])) return DIR_WEST;
	return ((number_range(1,2)==2)?DIR_SOUTH:DIR_EAST);
	}
if (i>x && j>y) {
	if (cf->map[i][j-1]!=NULL && cf->map[i][j-1]!=victim && !good_hit(ch,cf->map[i][j-1])) return DIR_EAST;
	if (cf->map[i-1][j]!=NULL && cf->map[i-1][j]!=victim && !good_hit(ch,cf->map[i-1][j])) return DIR_SOUTH;
	return ((number_range(1,2)==2)?DIR_NORTH:DIR_WEST);
	}
if (i>x && j<y) {
	if (cf->map[i][j+1]!=NULL && cf->map[i][j+1]!=victim && !good_hit(ch,cf->map[i][j+1])) return DIR_NORTH;
	if (cf->map[i-1][j]!=NULL && cf->map[i-1][j]!=victim && !good_hit(ch,cf->map[i-1][j])) return DIR_EAST;
	return ((number_range(1,2)==2)?DIR_SOUTH:DIR_WEST);
	}
if (i<x && j>y) {
	if (cf->map[i][j-1]!=NULL && cf->map[i][j-1]!=victim && !good_hit(ch,cf->map[i][j-1])) return DIR_SOUTH;
	if (cf->map[i+1][j]!=NULL && cf->map[i+1][j]!=victim && !good_hit(ch,cf->map[i+1][j])) return DIR_WEST;
	return ((number_range(1,2)==2)?DIR_NORTH:DIR_EAST);
	}
if (i<x) {
	if (cf->map[i+1][j]!=NULL && cf->map[i+1][j]!=victim && !good_hit(ch,cf->map[i+1][j])) return ((number_range(1,2)==2)?DIR_NORTH:DIR_SOUTH);
	return DIR_EAST;
	}
if (i>x) {
	if (cf->map[i-1][j]!=NULL && cf->map[i-1][j]!=victim && !good_hit(ch,cf->map[i-1][j])) return ((number_range(1,2)==2)?DIR_NORTH:DIR_SOUTH);
	return DIR_WEST;
	}
if (j<y) {
	if (cf->map[i][j+1]!=NULL && cf->map[i][j+1]!=victim && !good_hit(ch,cf->map[i][j+1])) return ((number_range(1,2)==2)?DIR_EAST:DIR_WEST);
	return DIR_SOUTH;
	}
if (j>y) {
	if (cf->map[i][j-1]!=NULL && cf->map[i][j-1]!=victim && !good_hit(ch,cf->map[i][j-1])) return ((number_range(1,2)==2)?DIR_EAST:DIR_WEST);
	return DIR_NORTH;
	}
return -1;
}

int find_flee_direction(CHAR_DATA *ch, CHAR_DATA *victim) {
COMBAT_FIELD *cf;
int i,j,x,y;
if (!ch->fgt || !victim->fgt) return -1;
if ( (cf=ch->fgt->field) == NULL ) return -1;
if (cf!=victim->fgt->field) return -1;
i=ch->fgt->pos_x;
j=ch->fgt->pos_y;
x=victim->fgt->pos_x;
y=victim->fgt->pos_y;
if (i<x && j<y) return ((number_range(1,2)==2)?DIR_NORTH:DIR_WEST);
if (i>x && j>y) return ((number_range(1,2)==2)?DIR_SOUTH:DIR_EAST);
if (i>x && j<y) return ((number_range(1,2)==2)?DIR_NORTH:DIR_EAST);
if (i<x && j>y) return ((number_range(1,2)==2)?DIR_SOUTH:DIR_WEST);
if (i<x) return DIR_WEST;
if (i>x) return DIR_EAST;
if (j<y) return DIR_NORTH;
if (j>y) return DIR_SOUTH;
return -1;
}


COMBAT_FIELD *new_combat_field(void) {
COMBAT_FIELD *cf;
if (!free_field_list) {
	cf=mem_alloc(sizeof(*cf));
	} else
	{
	cf=free_field_list;
	free_field_list=free_field_list->next;
	}
bzero(cf,sizeof(*cf));
cf->next=field_list;
field_list=cf;
return cf;
}

void free_combat_field(COMBAT_FIELD *cf) {
COMBAT_FIELD *cc;
if (cf==field_list) {
	field_list=field_list->next;
	cf->next=free_field_list;
	free_field_list=cf;
	return;
	}
for (cc=field_list;cc!=NULL;cc=cc->next) {
	if (cc->next==cf) {
		cc->next=cf->next;
		cf->next=free_field_list;
		free_field_list=cf;
		}
	}
/* Uh oh, not found.. don't worry about it */
return;
}
#endif

/* ------------------------------------------------------------------------ */
/* Create a combat field if neither the char or victim is in one already */
/* If one is, use that one, place appropriately.  If both have a combat */
/* field, then something somewhere is messed up. */
/* Please note this only adds the character to the field */
/* ------------------------------------------------------------------------ */
void add_to_combat_field(CHAR_DATA *ch, CHAR_DATA *victim) {
#ifndef OLD_FIGHT
int i,j;
COMBAT_FIELD *cf;
check_fgt(ch);
if (!victim) {
	fprintf(stderr,"NULL victim in add to combat field.\n");
	return;
	}
check_fgt(victim);
if (ch->fgt->field) return; /* This IS possible.. perhas give them notification? */
if (ch->fgt->field && ch->fgt->field!=victim->fgt->field) {
	/* We're screwed... char in combat field, but not the same as
           victim, or the victim isn't in one. */
	return;
	}
ch->fgt->field_ticks=number_range(2,5);
if (victim->fgt->field) {
	int xx,yy;
	xx=0;
	yy=0;
	cf=victim->fgt->field;
	xx=victim->fgt->pos_x;
	yy=victim->fgt->pos_y;
	/* Place ch in victim's combat field */
	if (closeto && xx<6 && cf->map[xx+1][yy]==NULL) {
		cf->map[xx+1][yy]=ch;
		ch->fgt->pos_x=xx+1;
		ch->fgt->pos_y=yy;
		ch->fgt->field=cf;
		java_add_to_field(ch->fgt->field,ch,xx+1,yy);
		return;
		}
	if (closeto && xx>0 && cf->map[xx-1][yy]==NULL) {
		cf->map[xx-1][yy]=ch;
		ch->fgt->pos_x=xx-1;
		ch->fgt->pos_y=yy;
		ch->fgt->field=cf;
		java_add_to_field(ch->fgt->field,ch,xx-1,yy);
		return;
		}
	if (closeto && yy>0 && cf->map[xx][yy-1]==NULL) {
		cf->map[xx][yy-1]=ch;
		ch->fgt->pos_x=xx;
		ch->fgt->pos_y=yy-1;
		ch->fgt->field=cf;
		java_add_to_field(ch->fgt->field,ch,xx,yy-1);
		return;
		}
	if (closeto && yy<6 && cf->map[xx][yy+1]==NULL) {
		cf->map[xx][yy+1]=ch;
		ch->fgt->pos_x=xx;
		ch->fgt->pos_y=yy+1;
		ch->fgt->field=cf;
		java_add_to_field(ch->fgt->field,ch,xx,yy+1);
		return;
		}


	if (IS_MOB(ch)) {  /* Mob, place at top */
	for (i=0; i<7; i++) {
		for (j=0; j<7; j+=2) {
			if (cf->map[i][j]!=NULL) continue;
			cf->map[i][j]=ch;
			ch->fgt->pos_x=i;
			ch->fgt->pos_y=j;
			ch->fgt->field=cf;
			java_add_to_field(ch->fgt->field,ch,i,j);
			return;
			}
		for (j=1; j<7; j+=2) {
			if (cf->map[i][j]!=NULL) continue;
			cf->map[i][j]=ch;
			ch->fgt->pos_x=i;
			ch->fgt->pos_y=j;
			ch->fgt->field=cf;
			java_add_to_field(ch->fgt->field,ch,i,j);
			return;
			}
		}
	/* Holy shit.. no room in the WHOLE field - error here */
	} else
	{
	for (i=6; i>=0; i--) {
		for (j=5; j>=0; j-=2) {
			if (cf->map[i][j]!=NULL) continue;
			cf->map[i][j]=ch;
			ch->fgt->pos_x=i;
			ch->fgt->pos_y=j;
			ch->fgt->field=cf;
			java_add_to_field(ch->fgt->field,ch,i,j);
			return;
			}
		for (j=6; j>=0; j-=2) {
			if (cf->map[i][j]!=NULL) continue;
			cf->map[i][j]=ch;
			ch->fgt->pos_x=i;
			ch->fgt->pos_y=j;
			ch->fgt->field=cf;
			java_add_to_field(ch->fgt->field,ch,i,j);
			return;
			}
		}
	/* Holy shit.. no free space for this player.. error */
	}
	}
/* Victim isn't in a combat field.. we have to make one. */
cf=new_combat_field();
if (IS_MOB(ch)) {
	i=2; j=0;
	} else
	{
	i=4; j=6;
	}
ch->fgt->pos_x=i;
ch->fgt->pos_y=j;
ch->fgt->field=cf;
cf->map[i][j]=ch;
java_add_to_field(ch->fgt->field,ch,i,j);
/* Don't place victim in the field yet... perhaps later? */
#endif
return;
}

bool remove_from_combat_field_yes(CHAR_DATA *ch) { /* returns TRUE if 
						  nobody left on field */
#ifndef OLD_FIGHT
int i,j;
COMBAT_FIELD *cf;
if (!ch->fgt) return FALSE;
cf=ch->fgt->field;
if (!cf) return FALSE;
if (cf->map[ch->fgt->pos_x][ch->fgt->pos_y]!=ch) {
	/* Character not found at marked position! */
	return FALSE;
	}
cf->map[ch->fgt->pos_x][ch->fgt->pos_y]=NULL;
java_remove_from_combat_field(cf,ch,ch->fgt->pos_x,ch->fgt->pos_y);
ch->fgt->pos_x=0;
ch->fgt->pos_y=0;
ch->fgt->field=NULL;
/* fprintf(stderr,"Removed %s from combat_field yes.\n",NAME(ch));
*/
/* Now check if we can free the field */
for (i=0; i<7; i++) {
	for (j=0; j<7; j++) {
		if (cf->map[i][j]!=NULL) return FALSE;
		}
	}
/* Nobody left, let's free this baby */
free_combat_field(cf);
/*fprintf(stderr,"Free'd the combat field.\n");
*/
#endif
return TRUE;
}




bool remove_from_combat_field(CHAR_DATA *ch) { /* returns TRUE if 
						  nobody left on field */
#ifndef OLD_FIGHT
int i,j;
COMBAT_FIELD *cf;
if (!ch->fgt) return FALSE;
cf=ch->fgt->field;
if (!cf) return FALSE;
if (cf->map[ch->fgt->pos_x][ch->fgt->pos_y]!=ch) {
	/* Character not found at marked position! */
	return FALSE;
	}
/* Now check if there are any others left fighting this bloke */
for (i=0; i<7; i++) {
	for (j=0; j<7; j++) {
		if (!cf->map[i][j]) continue;
		if (cf->map[i][j]->in_room != ch->in_room) continue;
		if (cf->map[i][j]->position<=POSITION_STUNNED) continue;
		if (FIGHTING(cf->map[i][j])==ch) return FALSE;
		}
	}
java_remove_from_combat_field(cf,ch,ch->fgt->pos_x,ch->fgt->pos_y);
cf->map[ch->fgt->pos_x][ch->fgt->pos_y]=NULL;
ch->fgt->pos_x=0;
ch->fgt->pos_y=0;
ch->fgt->field=NULL;
/* fprintf(stderr,"Removed %s from combat field.\n",NAME(ch));
*/
/* Now check if we can free the field */
for (i=0; i<7; i++) {
	for (j=0; j<7; j++) {
		if (cf->map[i][j]!=NULL) return FALSE;
		}
	}
/* Nobody left, let's free this baby */
free_combat_field(cf);
/*fprintf(stderr,"Free'd the combat field.\n");
*/
#endif
return TRUE;
}