#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "struct.h"
#include "sysconfig.h"

extern PACKET *Get_Packet();

USER UserArray[MAXU];

extern char GameName[];

Bind_To_Server()
{
	printf("Game compiled and booted\n");
	return(packet_init());
}

/*
 *	Respond to messages
 */
 
#ifdef NET
void Exec_Packet_Response()
{
	PACKET *p=Get_Packet();
	if(!p)
		return;
	switch(p->pk_Code)
	{
		case PK_DISC:Disconnect(p);break;
		case PK_CONN:Connect(p);break;
		case PK_TXLN:Command(p);break;
		case PK_SRVD:exit(0);break; /* Server going splat */
		default:printf("Unhandled packet received (%d).\n",
				p->pk_Code);
	}
}	
#endif

/*
 *	Mark user to be killed off
 */
 
void KillConnection(u)
tag u;
{
	UserArray[OBJ(u)].us_State=US_IDLE;
}

/*
 *	handle a connection
 */
 
#ifdef NET
void Connect(p)
PACKET *p;
{
/*
 *	Entry: uid in pk_Data pk_Handle holds system handle of user
 */
	int ct=0;
	while(ct<MAXU)
	{
		if(UserArray[ct].us_State==US_IDLE)
		{
			goto gotslot;
		}
		ct++;
	}
	WriteToHandle(p->pk_Handle,PK_TXLN,"Sorry the game is currently full.\n");
	WriteToHandle(p->pk_Handle,PK_DISC,NULL);
	return;
gotslot:if(ReadUptime()>SYS_MAXUPTIME)
        {
            WriteToHandle(p->pk_Handle,PK_TXLN,"Sorry the machine is too busy.\n");
            WriteToHandle(p->pk_Handle,PK_DISC,NULL);
            return;
        }
#endif
#ifndef NET

/*
 *	Main connection driver
 */
 
void Do_Connection(ct)
int ct;
{
	PACKET a;
	PACKET *p = &a;
	p->pk_Handle=ct;
#endif
	UserArray[ct].us_State=US_GNAM;
	UserArray[ct].us_Handle=p->pk_Handle;
	{
		char block[128];
		FILE *f=fopen("MOTD.TXT","r");
		if(f)
		{
			while(fgets(block,127,f))
			{
				block[strlen(block)-1]=0;
				WriteToHandle(p->pk_Handle,PK_TXLN,block);
			}
			fclose(f);
		}
		else
			WriteToHandle(p->pk_Handle,PK_TXLN,"Welcome to MAGIC\n\n");
	}
	WriteToHandle(p->pk_Handle,PK_DISA,NULL);
	WriteToHandle(p->pk_Handle,PK_PRMP,"Name: ");
	WriteToHandle(p->pk_Handle,PK_ENAB,0);
}

#ifdef NET
void Disconnect(p)
PACKET *p;
{
	int n=WhichUser(p->pk_Handle);
	if(n==-1)
	{
		fprintf(stderr,"***WARNING: Anomalous Disconnect packet ignored.\n");
		return;
	}
/*
 *	For the moment
 */
#ifndef TELNET
	WriteToHandle(p->pk_Handle,PK_PRMP,"chat> ");
#endif
#else
void Do_Disconnect(n)
tag n;
{
#endif
 	Exit_Player(ISOBJ(n));
	UserArray[VAL(n)].us_State=US_IDLE;
}

/*
 *	Process a command
 */
 
#ifdef NET
void Command(p)
PACKET *p;
{
	int n=WhichUser(p->pk_Handle);
	if(n==-1)
	{
		printf("***WARNING: Anomalous Command packet ignored.\n");
		return;
	}
#else
void Do_Net_Driver(n,t)
tag n;
char *t;
{
	PACKET pp;
	PACKET *p= &pp;
/*	printf("RECEIVED '%s' from %d.\n",t,n);*//*D BUG*/
	strcpy(p->pk_Text,t);
	p->pk_Handle=n;
#endif
	n=VAL(n);
	switch(UserArray[VAL(n)].us_State)
	{
		case US_CMD:DoCommand(n,p);break;
		case US_GNAM:Create_Player(n,p);break;
		case US_GEPW:Check_PW(n,p);break;
		case US_SEPW:GetPW_1(n,p);break;
		case US_VEPW:GetPW_2(n,p);break;
		case US_CPWC:ChPW_1(n,p);break;
		case US_CPWN:ChPW_2(n,p);break;
		case US_CPWV:ChPW_3(n,p);break;
		default:printf("***WARNING: User in unknown state, packet discarded.\n");
	}
}

/*
 *	Perform a login
 */
 
void Create_Player(n,p)
tag n;
PACKET *p;
{
	extern char *Is_Legal_Name();
	char *x=Is_Legal_Name(p->pk_Text,ISOBJ(n));
	if(x)
	{
		WriteToHandle(p->pk_Handle,PK_TXLN,x);
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		return;
	}
	SetName(ISOBJ(n),p->pk_Text);
	ADJ(ISOBJ(n))= -1;
	NOUN(ISOBJ(n))=28000+n;
	WriteToHandle(p->pk_Handle,PK_NECH,NULL);
	if(LoadUser(ISOBJ(n),p->pk_Text))
	{
		LOC(ISOBJ(n))= ISOBJ(-1);
		SETVIS(ISOBJ(n),ISNUM(32767));
		OBJECT(n)->ob_Child= -1;
		OBJECT(n)->ob_Next= -1;
		UserArray[n].us_State=US_GEPW;
		WriteToHandle(p->pk_Handle,PK_PRMP,"This persona exists, what is its password: ");
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		return;
	}
	UserArray[n].us_State=US_SEPW;
	WriteToHandle(p->pk_Handle,PK_PRMP,"Give me a password for this persona (DO NOT USE ANY MACHINE PASSWORDS): ");
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	OBJECT(n)->ob_Child= -1;
	OBJECT(n)->ob_Next= -1;
	LOC(ISOBJ(n))=ISNUM(-1);
	SETVIS(ISOBJ(n),ISNUM(32767));
}

int Check_PW(n,p)
tag n;
PACKET *p;
{
	extern struct Word *FindNumWord();
	if(CryptX(p->pk_Text)!=PLAYER(ISOBJ(n))->pl_PwKey)
	{
		struct Word *wd;
		WriteToHandle(p->pk_Handle,PK_TXLN,"Incorrect.");
		WriteToHandle(p->pk_Handle,PK_ECHO,NULL);
		WriteToHandle(p->pk_Handle,PK_PRMP,"Name: ");
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		wd=FindNumWord(28000+n,3);
		if(wd)
			DelWord(wd);
		UserArray[VAL(n)].us_State=US_GNAM;
		return(0);
	}
	SysFlags[0]=ISOBJ(n);
	WriteToHandle(p->pk_Handle,PK_PRMP,">>>");
	UserArray[VAL(n)].us_State=US_CMD;
	WriteToHandle(p->pk_Handle,PK_ECHO,NULL);
	ExecTable(5);
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	return(1);
}

void GetPW_1(n,p)
tag n;
PACKET *p;
{
	PLAYER(ISOBJ(n))->pl_PwKey=CryptX(p->pk_Text);
	WriteToHandle(p->pk_Handle,PK_PRMP,"Again to make sure: ");
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	UserArray[VAL(n)].us_State=US_VEPW;
}

void ChPW_2(n,p)
tag n;
PACKET *p;
{
	PLAYER(ISOBJ(n))->pl_PwKey=CryptX(p->pk_Text);
	WriteToHandle(p->pk_Handle,PK_PRMP,"Again to make sure: ");
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	UserArray[VAL(n)].us_State=US_CPWV;
}

void ChPW_1(n,p)
tag n;
PACKET *p;
{
	if(CryptX(p->pk_Text)!=PLAYER(ISOBJ(n))->pl_PwKey)
	{
		WriteToHandle(p->pk_Handle,PK_TXLN,"Sorry..");
		UserArray[VAL(n)].us_State=US_CMD;
		WriteToHandle(p->pk_Handle,PK_PRMP,">>>");
		WriteToHandle(p->pk_Handle,PK_ECHO,NULL);
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		ExecTable(1);
		return;
	}
	WriteToHandle(p->pk_Handle,PK_PRMP,"New Password: ");
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	UserArray[VAL(n)].us_State=US_CPWN;
}

void GetPW_2(n,p)
tag n;
PACKET *p;
{
	if(CryptX(p->pk_Text)!=PLAYER(ISOBJ(n))->pl_PwKey)
	{
		WriteToHandle(p->pk_Handle,PK_TXLN,"Incorrect - try again.\n");
		UserArray[VAL(n)].us_State=US_SEPW;
		WriteToHandle(p->pk_Handle,PK_PRMP,"Give me a password for this persona: ");
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		return;
	}
	SysFlags[0]=ISOBJ(n);
	WriteToHandle(p->pk_Handle,PK_PRMP,">>>");
	UserArray[VAL(n)].us_State=US_CMD;
	WriteToHandle(p->pk_Handle,PK_ECHO,NULL);
	ExecTable(4);
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
}

void ChPW_3(n,p)
tag n;
PACKET *p;
{
	if(CryptX(p->pk_Text)!=PLAYER(ISOBJ(n))->pl_PwKey)
	{
		WriteToHandle(p->pk_Handle,PK_TXLN,"Incorrect - try again.\n");
		UserArray[VAL(n)].us_State=US_CPWN;
		WriteToHandle(p->pk_Handle,PK_PRMP,"Give me a password for this persona: ");
		WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
		return;
	}
	WriteToHandle(p->pk_Handle,PK_PRMP,">>>");
	UserArray[VAL(n)].us_State=US_CMD;
	WriteToHandle(p->pk_Handle,PK_ECHO,NULL);
	WriteToHandle(p->pk_Handle,PK_ENAB,NULL);
	ExecTable(1);
}
	
void DoCommand(n,p)
tag n;
PACKET *p;
{
	SysFlags[0]=ISOBJ(n);
	ReportInput(p->pk_Text,ISOBJ(n));
	if(Parser(p->pk_Text))
	{
		WhatThings();
		ExecTable(0);
	}
	if(UserArray[VAL(n)].us_State!=US_IDLE)	/* If not dead */
	{
		ExecTable(1);
		WriteToHandle(p->pk_Handle,PK_ENAB,0);
	}
}

/*
 *	Called every second
 */
	
void Exec_Time_Event()
{
	ExecTable(6);
}

WhichUser(n)
tag n;
{
	int ct=0;
	while(ct<MAXU)
	{
		if(UserArray[ct].us_State!=US_IDLE&&
		   UserArray[ct].us_Handle==VAL(n))
		   	return(ct);
		ct++;
	}
	return(-1);
}