#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "struct.h"

/*
 *	Return current player
 */
 
tag Me()
{
	return(SysFlags[0]);
}

/*
 *	Transfer an item between two places, or signal a state shift
 */
 
static int ar[MAXU];

void Tree_Unlink(x)
tag x;
{
	register tag t;
	if(LOC(x)==-1)
		return;
	if(OBJECT(LOC(x))->ob_Child==x)
	{
		OBJECT(LOC(x))->ob_Child= OBJECT(x)->ob_Next;
		return;
	}
	t=OBJECT(LOC(x))->ob_Child;
	while(t!= -1)
	{
		if(OBJECT(t)->ob_Next==x)
		{
			OBJECT(t)->ob_Next=OBJECT(x)->ob_Next;
			return;
		}
		t=OBJECT(t)->ob_Next;
	}
	fprintf(stderr,"[WARNING]: Item Tree Corruption.\n");
}

void Tree_Link(i,c)
tag i,c;
{
	if(c!=-1)
	{
		OBJECT(i)->ob_Next=OBJECT(c)->ob_Child;
		OBJECT(c)->ob_Child=i;
	}
	else
	{
		OBJECT(i)->ob_Next= -1;
	}
}

void MoveItem(a,b)
tag a,b;
{
	if(TYPE(a)==FL_OBJECT)
		FLAGS(a)&=~OFL_WORN;
	if(LOC(a)==b)
		return;
	if(b==-2)
	{		/* Special code for State change */
		b=LOC(a);
		return;
	}
/*	CheckRedraw(a,LOC(a),ar);*/
	Tree_Unlink(a);
	LOC(a)=b;
	Tree_Link(a,b);
/*	CheckRedraw(a,LOC(a),ar);*/
}

/*
 *	Check to see if we need to do a redraw
 */
 
CheckRedraw(i,a,b)
tag i;
int a;
int *b;
{
	int c=ISOBJ(0);
	if(a==-1)
		return(0);
	while(c<ISOBJ(MAXU))
	{
		if(TYPE(i)==FL_PLAYER&&!CANSEE(c,i))
		{
			c++;
			continue;
		}
		if(LOC(c)==a)
			b[VAL(c)]=1;
		c++;
	}
	return(1);
}

/*
 *	Mark it redrawn
 */

void MarkClean(x)
tag x;
{
	if(OBJ(x)<MAXU&&OBJ(x)>=0)
		ar[VAL(x)]=0;
}

/*
 *	Do redraw checking stuff
 */
 
static int rdip=0;

ChkRedraw()
{
	return(rdip);
}

/*
 *	Actually do the redrawing
 */
 
void DoRedraw()
{
	return;

/*	tag v=Me();
	tag c=ISOBJ(0);
	if(rdip==1)
		return;
	rdip=1;
	while(c<ISOBJ(MAXU))
	{
		if(ar[VAL(c)])
		{
			SysFlags[0]=c;
			if(UserArray[VAL(c)].us_State=US_CMD)
			{
				WriteToHandle(UserArray[OBJ(Me())].us_Handle,PK_UPDT,"");
				C_Look();
			}
		}
		ar[VAL(c)]=0;
		c++;
	}
	SysFlags[0]=v;
	rdip=0;
*/
}	

/*
 *	Count currently active users
 */

UsersActive()
{
	int n=0;
	tag ct=ISOBJ(0);
	while(ct<ISOBJ(MAXU))
	{
		if(LOC(ct)!=ISOBJ(-1)) n++;
		ct++;
	}
	return(n);
}

/*
 *	Weigh up items
 */
 
Weight(o)
tag o;
{
	return(WeightRec(o,0));
}

WeightRec(o,d)
tag o;
int d;
{
	int ct=OBJECT(o)->ob_Child;
	int v=(TYPE(o)==FL_OBJECT)?WEIGHT(o):0;
	if(d>20)
		return(0);
	while(ct!=-1)
	{
		if(ISITEM(ct)&&TYPE(ct)==FL_OBJECT)
		{
			v+=((TYPE(ct)==FL_OBJECT)?WEIGHT(ct):0)+WeightRec(ct,d+1);
		}
		ct=OBJECT(ct)->ob_Next;
	}
	return(v);
}

/*
 *	Print up a message
 */
 
void PMsg(x)
tag x;
{
	extern char **Messages;
	UPrintf("%s",Messages[MSG(x)]);
}

/*
 *	Perform an action
 */
 
void Does(a,b,c,d)
tag a,b,d;
int c;
{
	extern char **Messages;
	DoesT(a,Messages[MSG(b)],c,d);
}

/*
  DoesT()
  ExecTable()
  Arg();
  NextLineMove();
  IsDark();
  CanPut();
 */

/*
 *	Driver for doing actions
 */
 
void DoesT(a,b,c,d)
tag a,d;
int c;
char *b;
{
	int ct=ISOBJ(0);
	if(LOC(a)== ISOBJ(-1))
		return;
	while(ct<ISOBJ(MAXU))
	{
		DoesProcess(a,b,c,d,ct);
		ct++;
	}
	ct=ISOBJ(0);
	while(ct<ISOBJ(MAXU))
	{
		if(SNOOP(ct)>=ISOBJ(MAXU))
			DoesProcess(a,b,c,d,SNOOP(ct));
		ct++;
	}
}

/*
 *	Capitalised Item Name
 */
 
char *MakeCName(x)
tag x;
{
	static char bf[128];
	if(strlen(NAME(x))>127)
		return(NAME(x));	/* Bail Out */
	strcpy(bf,NAME(x));
	if(islower(*bf))
		*bf=toupper(*bf);
	return(bf);
}

/*
 *	Logic for doing actions
 */
 
void DoesProcess(a,b,c,d,ct)
tag a,d,ct;
int c;
char *b;
{
	if(ct==a)
	{
		ct++;
		return;
	}
	if(LOC(ct)!=LOC(a))
	{
		ct++;
		return;
	}
	if((TYPE(a)==FL_PLAYER)&&(c&4)&&(FLAGS(ct)&PFL_DEAF))
	{
		ct++;
		return;
	}
	if((TYPE(a)==FL_PLAYER)&&(c&16)&&(FLAGS(ct)&PFL_ASLEEP))
	{
		ct++;
		return;
	}
	if((c&8)&&(FLAGS(ct)&PFL_BLIND))
	{
		ct++;
		return;
	}
	if(TYPE(a)==FL_PLAYER&&CANSEE(ct,a)==0)
	{
		if((c&8)&&(FLAGS(ct)&PFL_BLIND))
		{
			ct++;
			return;
		}
		if(c&1)
		{
			ct++;
			return;
		}
		if(c&2)
		{
			TellUser(ct,"Someone");
		}
		else
			TellUser(ct,"%s",MakeCName(a));
	}
	else
		TellUser(ct,"%s",MakeCName(a));
	TellUser(ct," %s ",b);
	if(d!= ISOBJ(-1))
	{
		if(d==ct)
			TellUser(ct,"you.\n");
		else
		{
			if(TYPE(d)==FL_PLAYER&&(!CANSEE(ct,d)))
			{
				TellUser(ct,"someone.\n");
			}
			else
				TellUser(ct,"%s.\n",NAME(d));
		}
	}
	else
		TellUser(ct,"\n");
	if(FLAGS(ct)&PFL_ASLEEP)
	{
		FLAGS(ct)&=~PFL_ASLEEP;
		TellUser(ct,"You wake up.\n");
	}
	ct++;
}

/*
 *	See if can move an item around
 */

CanPut(a,b)
tag a,b;
{
	tag ct=OBJECT(b)->ob_Child;
	int v=0;
	if(TYPE(b)==FL_PLAYER)
	{
		return(PCanPut(a,b));
	}
	while(ct!=-1)
	{
		if(ISITEM(ct)&&TYPE(ct)==FL_OBJECT)
			v+=SIZE(ct);
		ct=OBJECT(ct)->ob_Next;
	}
	if(v+SIZE(a)>SIZE(b))
		return(0);
	return(1);
}


PCanPut(a,b)
ITEM a,b;
{
	int v=Weight(a);
	ITEM i=a;
	int ct=0;
	while(ct<NObs())
	{
		if(LOC(i)==-1)
			break;
		if(LOC(i)==b)
		{
			v=0;
			break;
		}
		i=LOC(i);
		ct++;
	}
/*	printf("Weight=%d, ContWait=%d, Str=%d.\n",v,Weight(b),STRENGTH(b));*/
	if(v+Weight(b)>10*STRENGTH(b))
		return(0);
	return(1);
}

/*
 *	Darkness analyser
 */

IsDarkFor(x)
tag x;
{
	return(IsDark(LOC(x),x));
}

IsDark(x,y)
tag x;
tag y;
{
	int ct;
	if(x==ISOBJ(-1))
		return(0);
	if(y==ISOBJ(-1))
		return(0);
	ct=OBJECT(x)->ob_Child;
	if(TYPE(y)==FL_PLAYER)
	{
		if(FLAGS(y)&PFL_BLIND)
			return(1);
		if(FLAGS(y)&PFL_ASLEEP)
			return(1);
	}
	if(TYPE(y)==FL_PLAYER&&(FLAGS(y)&PFL_SEEDARK))
		return(0);
	if((TYPE(x)==FL_ROOM)&&((FLAGS(x)&RFL_DARK)==0))
		return(0);
	while(ct != -1)
	{
		if(ISITEM(ct)&&TYPE(ct)==FL_OBJECT)
		{
			if(((FLAGS(ct)&OFL_LIT0)&&STATE(ct)==0)||
			  ((FLAGS(ct)&OFL_LITALL)))
			{
				if(LOC(ct)==x)
					return(0);
			}
		}
		if(TYPE(ct)==FL_PLAYER&&IsDark(ct,y)==0)
			return(0);
		ct=OBJECT(ct)->ob_Next;
	}
	return(1);
}

/*
 *	Remove someone from the game
 */
 
void Exit_Player(n)
tag n;
{
	extern struct Word *FindNumWord();
	struct Word *wd;
	tag ct=ISOBJ(0);
	tag v=SysFlags[0];
	SysFlags[0]=n;
	if(n>=ISOBJ(MAXU))
	{
		MoveItem(n,ISOBJ(-1));
	}
	else
	{
		if(UserArray[VAL(n)].us_State==US_CMD)
			ExecTable(7);
		UserArray[n].us_State=US_IDLE;
		MoveItem(n,ISOBJ(-1));
	}
/*	printf("DESNOOPING");*/
	SETSNOOP(n,ISOBJ(-1));
	while(ct<ISOBJ(MAXU))
	{
		if(SNOOP(ct)==n)
		{
			SETSNOOP(ct,-1);
			SendIO(ct,"You can no longer snoop on %s\n",NAME(n));
		}
		ct++;
	}
	if(n>=ISOBJ(MAXU))
	{
		SysFlags[0]=v;
		return;
	}
/*	printf("EXITING");*/
	wd=FindNumWord(28000+VAL(n),3);
	if(!wd)
	{
/*		printf("Erk! - User without name\n")*/;
	}
	else
		DelWord(wd);
	SetName(n,"[FREE SLOT]");
	SysFlags[0]=v;
}