/* TURN.C
 * This module has the functions to get user moves
 */

#include	<proto/all.h>
#include	<intuition/intuition.h>
#include	<stdlib.h>
#include	<string.h>
#include	<math.h>
#include	"defns.h"
#include	"externs.h"

USHORT	fix;	/*used to pass by reference auto variables*/

VOID	manturn(cp,np,pp,nhp)
struct	playerinfo	*cp,*np,*pp;	/* current, following, previous players */
USHORT	nhp; /*number of human players.*/
{
	struct	IntuiMessage	*msg;
	struct	card	c;
	USHORT	fin=0,code,exch=0,temp; /*flag showing whether a card has been dropped*/
	ULONG	class,gid,fdpvis=0;
	struct	Gadget	*gaddr;
	/* deselect fup,fdp*/
	temp = RemoveGList(wind,&stdgad[FUPG],2);
	RefreshGList(&stdgad[FUPG],wind,NULL,2);
	stdgad[FUPG].Flags &= ~SELECTED;
	stdgad[FDPG].Flags &= ~SELECTED;
	DrawImage(wind->RPort,packim[0][0],FDPX,FDPY);
	TXTOUT(180,21,1,0,cp->name)
	if(nhp>1 && !cp->viewcard)
	{/* change players at keyboard*/
		OffMenu(wind,0x0020); /*reorder off*/
		OffMenu(wind,0xf862); /*modmem off*/
		OffMenu(wind,0x0040); /*about off*/
		TXTOUT(MESX,MESY,3,0,"Press Continue to display cards")
		WAITCONT;
		OnMenu(wind,0x0020); /*reorder on*/
		OnMenu(wind,0xf862); /*modmem on*/
		OnMenu(wind,0x0040); /*about on*/
	}
	AddGList(wind,&stdgad[FUPG],temp,2,NULL);
	disphand(cp);
	handgads(cp->nchld,cp->yc);	/*place gadget over each card*/
	TXTOUT(MESX,MESY,1,0,"Select Move                     ")
	while(!fin && !exgm && !quit)
	{
		cont=0;
		Wait(1l<<mp->mp_SigBit);
		while(msg=(struct IntuiMessage *)GetMsg(mp))
		{
			class=msg->Class;
			code=msg->Code;
			gaddr=(struct Gadget *)(msg->IAddress);
			ReplyMsg((struct Message *)msg);
			switch(class)
			{
			case GADGETUP:
				gid=gaddr->GadgetID;
				if(gid>=HANDG1 && gid<=HANDG7 && gaddr->Flags&SELECTED && !exch)
				{ /*card from selected*/
					if(stdgad[FUPG].Flags&SELECTED && !fdpvis)
					{ /*exchange with top of fup*/
						gid = gid - HANDG1 +1;
						exch=1;
						c=NEXTFUP;
						PUTFUP((cp->hand[gid]));
						cp->hand[gid]=c;
						disphand(cp);
						RefreshGList(&hgads[1],wind,NULL,cp->nchld);
						DRAWFUP
						DrawImage(wind->RPort,packim[0][0],FDPX,FDPY);
						maintainmem(cp,pp,np,c,CURRPLRHOLDS);
						maintainmem(cp,pp,np,fup[fuptc],CURRPLRDROPD);
						TXTOUT(MESX,MESY,3,0,"Exchange made - hit continue")
					}
					else if(stdgad[FDPG].Flags&SELECTED)
						{ /*exhange fdp top card*/
							exch=1;
							gid = gid - HANDG1 +1;
							maintainmem(cp,pp,np,fup[fuptc],GONEPAST);
							maintainmem(cp,pp,np,fup[fuptc],CURRPLRDROPD);
							c=NEXTFDP;
							PUTFUP((cp->hand[gid]));
							cp->hand[gid]=c;
							disphand(cp);
							RefreshGList(&hgads[1],wind,NULL,cp->nchld);
							DRAWFUP
							cp->mem[CARD2(c)] |= CURRPLRHOLDS;
							DrawImage(wind->RPort,packim[0][0],FDPX,FDPY);
							maintainmem(cp,pp,np,fup[fuptc],CURRPLRDROPD);
							TXTOUT(MESX,MESY,3,0,"Exchange made - hit continue")
						}
				}
				else if(gid==FDPG && !fdpvis && !exch)
					{/*make fdp visible*/
						DRAWFDP
						fdpvis=1; /*prevents use of fup*/
					}
				else if(gid>=SETGAD0 && gid<=SETGAD5) /*add to set*/
					if(addtofus(cp,gid-SETGAD0))
					{
						handgads(cp->nchld,cp->yc);
						REMHAND(cp)
						disphand(cp);
						if(!cp->nchld) fin=1; /*no card left*/
					}
					else ;
				else if(gid==SUBMITG) /*submit new set*/
					if(temp=submitset(cp))
					{
						handgads(cp->nchld,cp->yc);
						REMHAND(cp)
						disphand(cp);
						if(!cp->nchld) fin=1; /*no cards left*/
						TXTOUT(MESX,MESY,1,0,"Submission Accepted           ");
					}
					else
					{
						TXTOUT(MESX,MESY,2,0,"Submission Rejected             ");
					}
				else if(gid==FUPG && !exch && fdpvis)
					{	/*do not take fdp card*/
						TXTOUT(MESX,MESY,3,0,"Exchange made - hit continue")
						maintainmem(cp,pp,np,fup[fuptc],GONEPAST);
						maintainmem(cp,pp,np,fup[fuptc],CURRPLRDROPD);
						c=NEXTFDP;
						PUTFUP(c);
						maintainmem(cp,pp,np,fup[fuptc],CURRPLRDROPD);
						exch=1;
						DrawImage(wind->RPort,packim[0][0],FDPX,FDPY);
						DRAWFUP;
					}
				else 
				{
					if(cont && exch) fin=1; /*exchange must be made to finish move*/
					else if(cont && !exch && !fin)
					{
						TXTOUT(MESX,MESY,2,0,"No exchange made yet     ")
					}
				}
				break;
			case MENUPICK:
				prgenmsg(class,code,(APTR)gaddr,cp);
				break;
			}
		}
	}
	handgads(0,0);
	if(!cp->viewcard) hidecards(cp);
	TXTOUT(180,21,1,0,"                 ") /*remove name*/
	TXTOUT(MESX,MESY,3,0,"                              ")
}

						
VOID	disphand(struct playerinfo *p)
{
	register	USHORT	i,x=HANDLEFT,y=p->yc+HANDTOP,v;
	char	b[4];
	for(i=1,v=0;i<=p->nchld;i++) v += p->hand[i].n;
	TXTOUT(270,p->yc+HVTPY,1,0,"     ");
	stci_d(out,v);
	TXTOUT(270,p->yc+HVTPY,1,0,out);
	stci_d(b,p->turn);
	TXTOUT(270,p->yc+NWTPY+9,1,0,b);
	if(p->nchld)
	{
		DrawImage(wind->RPort,packim[0][CARD2(p->hand[1])],x,y);
		for(i=2;i<=p->nchld;i++)
			DrawImage(wind->RPort,packim[1][CARD2(p->hand[i])],x-(i-1)*17,y);
	}
	else REMHAND(p);
}

VOID	compacthand(struct card h[],USHORT *n)
{
	register	USHORT	s,d;
	for(d=1;d!=*n && !CDEQU(h[d],nulcard);d++);	/*find first nulcard*/
	if(d!=*n)
	{
		for(s=d+1;s<=*n;s++) 
			if(!CDEQU(h[s],nulcard)) h[d++]=h[s];
		*n=d-1;
	}
	if(CDEQU(h[*n],nulcard) && *n!=0) --*n;
}

VOID	handgads(USHORT n,USHORT y)
{/* put gadgets over users cards*/
	static	USHORT	num=0;
	register	USHORT	i;
	y+=HANDTOP;
	if(num) 
	{
		RemoveGList(wind,&hgads[1],num);
		RefreshGList(&hgads[1],wind,NULL,num);
	}
	for(i=1;i<=n;i++)
	{ /*initialise next gadget*/
		hgads[i-1].NextGadget = &hgads[i];
		hgads[i].TopEdge = y;
		hgads[i].Flags &= ~(SELECTED | GADGDISABLED);
	}
	hgads[i-1].NextGadget = NULL;
	if(i!=1) AddGList(wind,&hgads[1],~0,i-1,NULL);
	num=i-1;
}

VOID	hidecards(struct playerinfo *p)
{
	register	USHORT	i;
	char	b[4];
	TXTOUT(270,p->yc+HVTPY,1,0,"     ");
	stci_d(b,p->turn);
	TXTOUT(270,p->yc+NWTPY+9,1,0,b);
	if(p->nchld)
	{
		DrawImage(wind->RPort,packim[0][0],HANDLEFT,p->yc+HANDTOP);
		for(i=2;i<=p->nchld;i++) DrawImage(wind->RPort,packim[1][0],HANDLEFT-(i-1)*17,p->yc+HANDTOP);
	}
	else REMHAND(p);
}

USHORT	submitset(struct playerinfo *p)
{/* submit set from user */
	struct	card	t[10];
	register	USHORT	i,d,n,samesuit=1,samenum=1;
	for(i=1,d=0;i<=p->nchld;i++)
		if(hgads[i].Flags&SELECTED) t[++d]=p->hand[i];	/*copy selected cards*/
	for(i=2;i<=d;i++)
	{
		if(t[i-1].n!=t[i].n) samenum=0;	/*not same number*/
		if(t[i-1].s!=t[i].s) samesuit=0;	/*not same suit*/
	}
	if(d<3 ||(!samesuit && !samenum)) return 0; /*rejected*/
	if(samesuit)
	{/*check set forms continuous sequence*/
		fix=d; /*cannot pass address of d*/
		ssortn(t,&fix);	/*sort on number only*/
		d=fix;
		for(i=2;i<=d;i++)
			if((t[i-1].n!=t[i].n-1) && !(t[i-1].n==KING && t[i].n==ACE)) return 0; /*rejected*/
	}
	/*set accepted if this point reached*/
	for(i=1;i<=p->nchld;i++) if(hgads[i].Flags&SELECTED) p->hand[i]=nulcard;
	compacthand(p->hand,&p->nchld);
	for(i=0;i<=5 && fupset[i]->ncard!=0;i++) ;/*find empty set*/
	fupset[i]->ncard=d;
	
	if(samesuit)
		for(n=1;n<=d;n++)
		{
			fupset[i]->cards[n+t[1].n-1]=t[n];
			maintainmem(NULL,NULL,NULL,t[n],INFUPSET);
		}
		/*cards inserted so that card n is at fupset[i]->card[n] to simplify addition to both ends of the set*/
	else
		for(n=1;n<=d;n++)
		{
			fupset[i]->cards[n]=t[n];
			maintainmem(NULL,NULL,NULL,t[n],INFUPSET);
		}
	sortdispset();
	return 1;	/*accepted...tells program to redo gadgets for cards*/
}

VOID	sortdispset()
{
	static	USHORT	num=0;
	register	USHORT	i,j,f,e=1;
	register	ULONG	l;
	struct	set	*s;
	if(num)
	{ /*remove any gadgets already in place*/
		RemoveGList(wind,&setgads[0],num);
		RefreshGList(&setgads[0],wind,NULL,num);
	}
	while(e) /*ensure largest set comes first*/
		for(i=0,e=0;i<5;i++)
		{
			if(fupset[i]->ncard<fupset[i+1]->ncard)
			{
				e=1; /*exchange made*/
				s=fupset[i];fupset[i]=fupset[i+1];fupset[i+1]=s;
			}
		}
	num=0;
	for(i=0;i<=5;i++)
		if(fupset[i]->ncard!=0)
		{
			for(j=14;CDEQU(fupset[i]->cards[j],nulcard);j--) ;
			f=j;
			if(i<=2) l=566; else l=416;
			DrawImage(wind->RPort,packim[0][CARD2(fupset[i]->cards[j])],l,setpos[i]);
			j--;
			for(;!CDEQU(fupset[i]->cards[j],nulcard) && j;j--) 
				DrawImage(wind->RPort,packim[1][CARD2(fupset[i]->cards[j])],l-(f-j)*17,setpos[i]);
			if(i!=0) setgads[i-1].NextGadget = &setgads[i];
			setgads[i].LeftEdge = l-17*(fupset[i]->ncard-1);
			setgads[i].Width = (fupset[i]->ncard-1)*17+64;
			setgads[i].NextGadget = NULL;
			num++;	/*number of gadgets added*/
		}
	if(num) AddGList(wind,&setgads[0],~0,num,NULL);
}
	
VOID	ssortn(struct card a[],USHORT *n)
{ /*selection sort a[] on card number only..Faster version for fupset*/
	register	USHORT	i,j,minpos;
	struct	card	t,minval;
	for(i=1;i<*n;i++)
	{
		minval.n=15;minpos=0;
		for(j=i;j<=*n;j++) if(a[j].n<=minval.n) minval=a[minpos=j];
		a[minpos]=a[i];
		a[i]=minval;
	}
	/*decide whether ace is high or low*/
	if(a[1].n==ACE && (a[2].n!=2 || a[3].n!=3) && a[*n].n==KING && a[(*n)-1].n==QUEEN)
	{ /*put ace at end*/
		t=a[1];a[1]=nulcard;
		compacthand(a,n);
		a[++(*n)]=t;
	}
}

VOID	hsort(struct card a[],USHORT n)
{ /* sort player cards.. sorts by number within suit */
	register	USHORT	i,j,maxpos,max;
	struct	card	maxval;
	for(i=1;i<n;i++)
	{
		maxval.n=0;maxval.s=0;maxpos=0;max=0;
		for(j=i;j<=n;j++) if(CARD2(a[j])>=max)
		{
			maxval=a[maxpos=j];
			max=CARD2(maxval);
		}
		a[maxpos]=a[i];
		a[i]=maxval;
	}
}



VOID	maintainmem(cp,pp,np,card,flag)
struct	playerinfo	*cp,*pp,*np;
struct	card	card;
USHORT	flag;
{
	register	USHORT	n=CARD2(card);
	switch(flag)
	{
	case CURRPLRHOLDS:
		if(cp) cp->mem[n] |= flag;
		if(pp) pp->mem[n] |= NEXTPLRHOLDS;
		if(np) np->mem[n] |= PREVPLRHOLDS;
		break;
	case CURRPLRDROPD:
		if(cp)
		{
			cp->mem[n] |= flag;
			cp->mem[n] &= ~CURRPLRHOLDS;
		}
		if(pp)
		{
			pp->mem[n] |= NEXTPLRDROPD;
			pp->mem[n] &= ~NEXTPLRHOLDS;
		}
		if(np)
		{
			np->mem[n] |= PREVPLRDROPD;
			np->mem[n] &= ~PREVPLRHOLDS;
		}
		break;
	case GONEPAST:
	case INFUPSET:
		plr[1]->mem[n] |= flag;
		plr[1]->mem[n] &= ~(CURRPLRHOLDS | PREVPLRHOLDS | NEXTPLRHOLDS);
		plr[2]->mem[n] |= flag;
		plr[2]->mem[n] &= ~(CURRPLRHOLDS | PREVPLRHOLDS | NEXTPLRHOLDS);
		plr[3]->mem[n] |= flag;
		plr[3]->mem[n] &= ~(CURRPLRHOLDS | PREVPLRHOLDS | NEXTPLRHOLDS);
		break;
	}
}


USHORT	addtofus(struct playerinfo *p,ULONG set)
{
	register	struct	card	*fsc,*phc;
	register	USHORT	*fsn,phn,nomore,i,f,l,c=0; /*change made flag*/
	USHORT	ncrd=p->nchld;
	char	b[4];
	fsc=fupset[set]->cards;fsn=&fupset[set]->ncard;
	phc=p->hand;phn=p->nchld;
	for(f=1;CDEQU(fsc[f],nulcard);f++) ; /*find first card of set*/
	l=f+(*fsn)-1; /*position of last card of set*/
	if(fsc[f].s==fsc[f+1].s) /*same suit*/
		for(nomore=0;!nomore && !quit && !exgm;)
		{
			for(nomore=1,i=1;i<=phn && !quit && !exgm;i++)
			{
				if(hgads[i].Flags&SELECTED && !CDEQU(phc[i],nulcard))
				{
					if(fsc[f].n==phc[i].n+1 && fsc[f].s==phc[i].s)
					{ /*add before first card of set*/
						fsc[--f]=phc[i];
						maintainmem(NULL,NULL,NULL,phc[i],INFUPSET);
						(*fsn)++;
						phc[i]=nulcard;
						c=1; /*change made*/
						nomore=0;
					}
					else if(((fsc[l].n==phc[i].n-1 && phc[i].n!=2) || (fsc[l].n==KING && phc[i].n==ACE))
						&& fsc[l].s==phc[i].s)
					{ /*add after last card*/
						fsc[++l]=phc[i];
						maintainmem(NULL,NULL,NULL,phc[i],INFUPSET);
						phc[i]=nulcard;
						c=1;
						(*fsn)++;
						nomore=0;
					}
				}
			}
		}
	else /*same number set*/
		for(i=1;i<=phn && !quit && !exgm;i++)
			if(hgads[i].Flags&SELECTED && !CDEQU(p->hand[i],nulcard))
			{
				if(fsc[l].n==phc[i].n)
				{ /*insert after last card*/
					fsc[++l]=phc[i];
					maintainmem(NULL,NULL,NULL,phc[i],INFUPSET);
					(*fsn)++;
					phc[i]=nulcard;
					c=1;
				}
			}
	if(c)
	{
		sortdispset(); /*redisplay sets if changes made*/
		compacthand(p->hand,&p->nchld);
		ncrd-=p->nchld;
		stci_d(b,ncrd);
		TXTOUT(MESX,MESY,1,0,"                ");
		TXTOUT(MESX,MESY,1,0,b);
		TXTOUT(MESX+2*FWIDTH,MESY,1,0,"Cards Added                   ");
	}
	else
	{
		TXTOUT(MESX,MESY,2,0,"No cards added               ");
	}

	return c;
}
