/*============================================================*/
/*============================================================*/
/*==														==*/
/*==			Net Opponent Handling Routines				==*/
/*==														==*/
/*============================================================*/
/*============================================================*/


/*========================================================  Includes  */

#include "Globals.h"
#include "UnivUtilities.h"
#include "AppleTalkDDP.h"
#include "NetOpponent.h"
#include "AnimCursor.h"
#include "SoundUtils.h"
#include "PlayUtils.h"
#include "Replay.h"
#include "Render.h"


/*========================================================  Functions  */
/*========================================================  SendSynchPulse  */

OSErr SendSynchPulse (void)

{
	OSErr			netErr;
	short			helloMessage;
	
	helloMessage = kHelloIndicator;
	netErr = SendOutgoingDDP((long)&helloMessage, 2);
	
	return (netErr);
}


/*========================================================  SendThisEnvironment  */

OSErr SendThisEnvironment (void)

{
	environMessage	thisMessage;
	OSErr			theErr;

	thisMessage.speed = speedFlag;
	thisMessage.version = kNetworkVersion;
	thisMessage.arena = arenaSize;
	thisMessage.goal = thePlayer.whichGoal;
	thisMessage.spotPts = spotPoints;
	thisMessage.league = isLeague;
	thisMessage.scoredLast = leftScoredLast;
	thisMessage.limited = netOnly;
	
	theErr = SendOutgoingDDP((long)&thisMessage, kEnviroMessageSize);
	
	return(theErr);
}


/*========================================================  BegForSomething  */

OSErr BegForSomething (short anythingLove)

{
	requestMessage	requestor;
	OSErr			theErr;
	
	requestor.requested = anythingLove;
	requestor.firstArgument = 0;
	requestor.secondArgument = 0;
	
	theErr = SendOutgoingDDP((long)&requestor, kRequestSize);
	
	return (theErr);
}


/*========================================================  WaitForSynch  */

Boolean WaitForSynch (short timeOut)

{
	long			imVeryBored, dummyLong;
	OSErr			theErr;
	short			helloMessage, replyMessage;
	Boolean			iHearYou;
	
	replyMessage = 0;
	dummyLong = 0;
	iHearYou = FALSE;
	imVeryBored = Ticks + timeOut;
	
	theErr = RequestReceiveDDP();
	
	while ((Ticks < imVeryBored)  && (!iHearYou))
	{
		IncrementCursor();
		
		theErr = PollSpecificDDP((long)&replyMessage, 2, 3);
		
		if (CommandPeriodDown())
			break;
		
		if ((theErr == noErr) && (replyMessage == kHelloIndicator))
		{
			iHearYou = TRUE;
			Delay(4, &dummyLong);
		}
		else if (theErr == kNetErrWrongSize)
		{
			if (lastByteCount == kRequestSize)
			{
				if (firstPackageShort == kRequestEnvironment)
					theErr = SendThisEnvironment();
				else
					theErr = BegForSomething(kGotYourEnvironment);
			}
			else if (lastByteCount == kEnviroMessageSize)
			{
				theErr = BegForSomething(kGotYourEnvironment);
			}
		}
		
		SendSynchPulse();
	}
	
	InitCursor();
	return (iHearYou);
}


/*========================================================  ConfirmEnvironmentMatch  */

Boolean ConfirmEnvironmentMatch (void)

{
	environMessage	theirMessage;
	long			timeToBail;
	OSErr			theErr;
	Boolean			confirmed, needEnviron, sheSaysOkay, sheWants;
	
	theirMessage.speed = 0L;
	theirMessage.version = 0;
	theirMessage.arena = -1;
	theirMessage.goal = -1;
	theirMessage.spotPts = 0;
	theirMessage.league = 0;
	theirMessage.scoredLast = !leftScoredLast;
	theirMessage.limited = TRUE;
	
	theErr = RequestReceiveDDP();
	
	timeToBail = Ticks + 3600;
	confirmed = FALSE;
	sheSaysOkay = FALSE;
	sheWants = FALSE;
	needEnviron = TRUE;
	
	theErr = BegForSomething(kRequestEnvironment);
	
	while ((!confirmed) && (Ticks < timeToBail))
	{
		IncrementCursor();
		
		if (CommandPeriodDown())
			timeToBail = Ticks;
		
		theErr = PollSpecificDDP((long)&theirMessage, kEnviroMessageSize, 2);
		
		if (theErr == noErr)
		{
			needEnviron = FALSE;
		}
		else if ((theErr == kNetErrWrongSize) && (lastByteCount == kRequestSize))
		{
			if (firstPackageShort == kRequestEnvironment)
			{
				sheWants = TRUE;
			}
			else if (firstPackageShort == kGotYourEnvironment)
			{
				sheWants = FALSE;
				sheSaysOkay = TRUE;
				
				if (!needEnviron)
				{
					confirmed = TRUE;
				}
			}
		}
		
		if (sheWants)
		{
			theErr = SendThisEnvironment();
			sheWants = FALSE;
		}
		else if (needEnviron)
			theErr = BegForSomething(kRequestEnvironment);
		else
			theErr = BegForSomething(kGotYourEnvironment);
	}
	
	if (!confirmed)								/* why did we leave the loop */
		MinorError(kMinorNoNetConfirm);			/* inform user of error */
	else
	{
		if (theirMessage.version != kNetworkVersion)
		{
			MinorError(kMinorWrongNetVersion);
			confirmed = FALSE;
		}
		else if (theirMessage.arena != arenaSize)
		{
			if (theirMessage.arena > arenaSize)
				MinorError(kMinorArenaTooBig);
			else
				MinorError(kMinorArenaTooSmall);
			confirmed = FALSE;
		}
		else if (theirMessage.limited && netOnly)
		{
			MinorError(kMinorNeedOneValidCopy);
			confirmed = FALSE;
		}
		else
		{
			theirSpeed = theirMessage.speed;
			confirmed = DetermineMasterSlave();
			if (confirmed)
			{
				netMirroring = (theirMessage.goal == thePlayer.whichGoal);
				spottedPoints = theirMessage.spotPts;
				theirLeague = theirMessage.league;
				if (!imTheMaster)
					leftScoredLast = theirMessage.scoredLast;
			}
			else
			{
				MinorError(kMinorNoMasterPossible);
			}
		}
	}
	
	InitCursor();
	return (confirmed);
}


/*========================================================  WhatsTheGamesOutcome  */

Boolean WhatsTheGamesOutcome (void)

{
	typedef struct
	{
		short		playerTotGoals;
		short		opponentTotGoals;
		short		playerTotFouls;
		short		opponentTotFouls;
		short		playerTotCrits;
		short		opponentTotCrits;
		Boolean		playerWon;
	} outcomeMessage;
	
	outcomeMessage	thisMessage, theirMessage;
	long			timeToBail, dummyLong;
	OSErr			theErr;
	short			outcomeMessageSize;
	Boolean			confirmed;
	
	thisMessage.playerTotGoals = opponentTotalGoals;
	thisMessage.opponentTotGoals = playerTotalGoals;
	thisMessage.playerTotFouls = opponentTotalFouls;
	thisMessage.opponentTotFouls = playerTotalFouls;
	thisMessage.playerTotCrits = opponentTotalCrits;
	thisMessage.opponentTotCrits = playerTotalCrits;
	if (playerWonTheGame == kPlayerWon)
		thisMessage.playerWon = kOpponentWon;
	else
		thisMessage.playerWon = kPlayerWon;
	
	theirMessage.playerTotGoals = 0;
	theirMessage.opponentTotGoals = 0;
	theirMessage.playerTotFouls = 0;
	theirMessage.opponentTotFouls = 0;
	theirMessage.playerTotCrits = 0;
	theirMessage.opponentTotCrits = 0;
	theirMessage.playerWon = 0;
	
	outcomeMessageSize = (short)sizeof(theirMessage);
	
	timeToBail = Ticks + 300;
	confirmed = FALSE;
	
	theErr = RequestReceiveDDP();
	
	while ((!confirmed) && (Ticks < timeToBail))
	{
		theErr = PollSpecificDDP((long)&theirMessage, outcomeMessageSize, 2);
		if (theErr == noErr)
		{
			confirmed = TRUE;
			Delay(4, &dummyLong);
		}
		theErr = SendOutgoingDDP((long)&thisMessage, outcomeMessageSize);
	}
	
	theErr = SendOutgoingDDP((long)&thisMessage, outcomeMessageSize);
	
	if ((confirmed) && (!imTheMaster))
	{
		playerTotalGoals = theirMessage.playerTotGoals;
		opponentTotalGoals = theirMessage.opponentTotGoals;
		playerTotalFouls = theirMessage.playerTotFouls;
		opponentTotalFouls = theirMessage.opponentTotFouls;
		playerTotalCrits = theirMessage.playerTotCrits;
		opponentTotalCrits = theirMessage.opponentTotCrits;
		playerWonTheGame = theirMessage.playerWon;
	}
	
	return (confirmed);
}


/*========================================================  PrepareStandardMessage  */

void PrepareStandardMessage (void)

{
	if (imTheMaster)
	{
		masterMessage.messageType = frameCounter;
		
		masterMessage.ballIsPoint = ((long)theBall.isRect.top << 16) | 
				(long)theBall.isRect.left;
		masterMessage.eraserPoint = ((long)theBall.eraser.top << 16) | 
				(long)theBall.eraser.left;
		masterMessage.playerIsPoint = ((long)thePlayer.isRect.top << 16) | 
				(long)thePlayer.isRect.left;
		masterMessage.opponentIsPoint = ((long)theOpponent.isRect.top << 16) | 
				(long)theOpponent.isRect.left;
		
		masterMessage.opponentXPos = theOpponent.xPos;
		masterMessage.opponentZPos = theOpponent.zPos;
		
		masterMessage.playerArrayDirSrc = (char)thePlayer.dirFlagSrc;
		masterMessage.playerPostArray = ((char)thePlayer.postFlagSrc << 4) | 
				(char)thePlayer.arrayFlagMask;
		masterMessage.playerDirPostMask = ((char)thePlayer.dirFlagMask << 4) | 
				(char)thePlayer.postFlagMask;
		
		masterMessage.opponentArrayDirSrc = (char)theOpponent.dirFlagSrc;
		masterMessage.opponentPostArray = ((char)theOpponent.postFlagSrc << 4) | 
				(char)theOpponent.arrayFlagMask;
		masterMessage.opponentDirPostMask = ((char)theOpponent.dirFlagMask << 4) | 
				(char)theOpponent.postFlagMask;
		
		masterMessage.ballWhosMode = ((char)theBall.mode << 4) | 
				(char)antiWhosBall[whosGotBall];
		
		masterMessage.playerOpponentMode = ((char)thePlayer.mode << 4) | 
				(char)theOpponent.mode;
		
		masterMessage.bitFlags = ((char)theBall.dontDraw << 4) | 
				((char)theBall.eraseTheBall << 3) | 
				((char)theDoor.doorOpen << 2) | 
				((char)theDoor.doorState << 1) | 
				(char)playerInBack;
		
		masterMessage.packedFoulsRead = ((char)opponentFouls << 4) | (char)playerFouls;
		masterMessage.playerScoreReads = playerScore;
		masterMessage.opponentScoreReads = opponentScore;
		masterMessage.soundPlayed = (unsigned char)wasLastSound;
	}
	else
	{
		slaveMessage.messageType = frameCounter;
		
		if (netMirroring)
			slaveMessage.mouseH = -thePlayer.hMouse;
		else
			slaveMessage.mouseH = thePlayer.hMouse;
		slaveMessage.mouseV = thePlayer.vMouse;
		
		slaveMessage.bits = ((char)thePlayer.bashApplied << 2) | 
				((char)thePlayer.buttonIs << 1) | 
				(char)thePlayer.brakeApplied;
	}
}


/*========================================================  SendMessage  */

void SendMessage (void)

{
	OSErr			theErr;
	
	if (imTheMaster)
		theErr = SendOutgoingDDP((long)&masterMessage, masterSendSize);
	else
		theErr = SendOutgoingDDP((long)&slaveMessage, slaveSendSize);
}


/*========================================================  SendModalMessage  */

Boolean SendModalMessage (short theMessage)

{
	long			timeOut;
	OSErr			theErr;
	Boolean			modeConfirmed;
	
	if (imTheMaster)
		masterMessage.messageType = theMessage;
	else
		slaveMessage.messageType = theMessage;
	
	timeOut = Ticks + 240L;
	modeConfirmed = FALSE;
	
	while ((Ticks < timeOut) && (!modeConfirmed))
	{
		if (imTheMaster)
		{
			theErr = SendOutgoingDDP((long)&masterMessage, masterSendSize);
			theErr = PollSpecificDDP ((long)&slaveMessage, slaveSendSize, 3);
			if ((theErr == noErr) && (slaveMessage.messageType == kConfirmMessage))
			{
				modeConfirmed = TRUE;
			}
		}
		else
		{
			theErr = SendOutgoingDDP((long)&slaveMessage, slaveSendSize);
			theErr = PollSpecificDDP ((long)&masterMessage, masterSendSize, 3);
			if ((theErr == noErr) && (masterMessage.messageType == kConfirmMessage))
			{
				modeConfirmed = TRUE;
			}
		}
	}
	
	if (modeConfirmed)
		return(TRUE);
	else
		return(FALSE);
}


/*========================================================  ConfirmModalMessage  */

void ConfirmModalMessage (void)

{
	OSErr			theErr;
	
	if (imTheMaster)
	{
		masterMessage.messageType = kConfirmMessage;
		theErr = SendOutgoingDDP((long)&masterMessage, masterSendSize);
	}
	else
	{
		slaveMessage.messageType = kConfirmMessage;
		theErr = SendOutgoingDDP((long)&slaveMessage, slaveSendSize);
	}
}


/*========================================================  ReceiveMessage  */

void ReceiveMessage (void)

{
	OSErr			theErr;
	Boolean			itWorked;
	
	#if kDemoVersion
		return;
	#else
		if (imTheMaster)
			theErr = PollSpecificDDP ((long)&slaveMessage, slaveSendSize, loopDelay);
		else
			theErr = PollSpecificDDP ((long)&masterMessage, masterSendSize, loopDelay);
		
		madeThePickUp = FALSE;
		
		if (theErr == noErr)
		{
			if (imTheMaster)
				newFrameCount = slaveMessage.messageType;
			else
				newFrameCount = masterMessage.messageType;
			
			switch (newFrameCount)
			{
				case kGameIsOverMessage:
					ConfirmModalMessage();
					itWorked = WhatsTheGamesOutcome();
					if (playerScore > opponentScore)
					{
						lengthOfApplause = 1500;
						StartApplauseSound();
					}
					else
					{
						lengthOfMob = 1500;
						StartMobSound();
					}
					DoSlaveGameOver();
					break;
				case kInstantReplayMessage:
					ConfirmModalMessage();
					DoInstantReplay();
					break;
				case kAbortGameMessage:
					ConfirmModalMessage();
					if (!gameIsOver)
					{
						TurnSMSOff();
						FlushEvents(everyEvent, kRemoveAllEvents);
						MinorError(kMinorOpponentAborted);
					}
					primaryMode = kIdleMode;
					break;
				case kEndGameMessage:
					ConfirmModalMessage();
					gameIsOver = TRUE;
					primaryMode = kIdleMode;
					break;
				case kConfirmMessage:
					break;
				default:
					if ((newFrameCount < frameCounter) && (loopDelay < 3))
						loopDelay++;
					else if ((newFrameCount > frameCounter) && (loopDelay > 1))
						loopDelay--;
					
					TranslateStandardMessage();
					
					if (imTheMaster)
						frameCounter = newFrameCount;
					
					lastFrameCount = newFrameCount;
					madeThePickUp = TRUE;
					if (frameCounter < 32000)
					{
						frameCounter++;
					}
					else
					{
						frameCounter = 0;
						newFrameCount = 0;
						lastFrameCount = 0;
					}
					break;
			}
		}
	#endif
}


/*========================================================  TranslateStandardMessage  */

void TranslateStandardMessage (void)

{
	short		wasGotBall, wasPlayerFouls, wasOpponentFouls;
	short		rawPlayerDirSrc, rawPlayerDirMask;
	short		rawOpponentDirSrc, rawOpponentDirMask;
	Boolean		tempDoorState;
	
	#if kDemoVersion
		return;
	#else
		if (imTheMaster)
		{
			theOpponent.hMouse = slaveMessage.mouseH;
			theOpponent.vMouse = slaveMessage.mouseV;
			theOpponent.bashApplied = (Boolean)((slaveMessage.bits >> 2) & 0x01);
			theOpponent.buttonIs = (Boolean)((slaveMessage.bits >> 1) & 0x01);
			theOpponent.brakeApplied = (Boolean)(slaveMessage.bits & 0x01);
		}
		else
		{
			if (netMirroring)
			{
				theBall.isRect.left = screenWide - 
						LoWrd(masterMessage.ballIsPoint) - 16;
				theBall.eraser.left = screenWide - 
						LoWrd(masterMessage.eraserPoint) - 16;
				theOpponent.isRect.left = screenWide - 
						LoWrd(masterMessage.playerIsPoint) - 32;
				thePlayer.isRect.left = screenWide - 
						LoWrd(masterMessage.opponentIsPoint) - 32;
				
				theDoor.doorOpen = !(Boolean)((masterMessage.bitFlags >> 2) & 0x01);
				
				thePlayer.xPos = -masterMessage.opponentXPos;
				thePlayer.zPos = masterMessage.opponentZPos;
			}
			else
			{
				theBall.isRect.left = LoWrd(masterMessage.ballIsPoint);
				theBall.eraser.left = LoWrd(masterMessage.eraserPoint);
				theOpponent.isRect.left = LoWrd(masterMessage.playerIsPoint);
				thePlayer.isRect.left = LoWrd(masterMessage.opponentIsPoint);
				theDoor.doorOpen = (Boolean)((masterMessage.bitFlags >> 2) & 0x01);
				thePlayer.xPos = masterMessage.opponentXPos;
				thePlayer.zPos = masterMessage.opponentZPos;
			}
			theBall.isRect.top = HiWrd(masterMessage.ballIsPoint);
			theBall.isRect.right = theBall.isRect.left + 16;
			theBall.isRect.bottom = theBall.isRect.top + 12;
			
			theBall.eraser.top = HiWrd(masterMessage.eraserPoint);
			theBall.eraser.right = theBall.eraser.left + 16;
			theBall.eraser.bottom = theBall.eraser.top + 12;
			
			theOpponent.isRect.top = HiWrd(masterMessage.playerIsPoint);
			theOpponent.isRect.right = theOpponent.isRect.left + 32;
			theOpponent.isRect.bottom = theOpponent.isRect.top + 44;
			
			thePlayer.isRect.top = HiWrd(masterMessage.opponentIsPoint);
			thePlayer.isRect.right = thePlayer.isRect.left + 32;
			thePlayer.isRect.bottom = thePlayer.isRect.top + 44;
			
			theOpponent.arrayFlagMask = (short)(masterMessage.playerPostArray & 0x0F);
			thePlayer.arrayFlagMask = (short)(masterMessage.opponentPostArray & 0x0F);
			
			rawPlayerDirSrc = (short)(masterMessage.playerArrayDirSrc & 0x0F);
			rawPlayerDirMask = (short)((masterMessage.playerDirPostMask >> 4) & 0x0F);
			rawOpponentDirSrc = (short)(masterMessage.opponentArrayDirSrc & 0x0F);
			rawOpponentDirMask = (short)((masterMessage.opponentDirPostMask >> 4) & 0x0F);
			
			if (netMirroring)
			{
				if (theOpponent.arrayFlagMask == kFadeMask)
				{
					theOpponent.dirFlagSrc = rawPlayerDirSrc;
					theOpponent.dirFlagMask = rawPlayerDirMask;
				}
				else
				{
					theOpponent.dirFlagSrc = antiFacing[rawPlayerDirSrc];
					theOpponent.dirFlagMask = antiFacing[rawPlayerDirMask];
				}
				if (thePlayer.arrayFlagMask == kFadeMask)
				{
					thePlayer.dirFlagSrc = rawOpponentDirSrc;
					thePlayer.dirFlagMask = rawOpponentDirMask;
				}
				else
				{
					thePlayer.dirFlagSrc = antiFacing[rawOpponentDirSrc];
					thePlayer.dirFlagMask = antiFacing[rawOpponentDirMask];
				}
			}
			else
			{
				theOpponent.dirFlagSrc = rawPlayerDirSrc;
				theOpponent.dirFlagMask = rawPlayerDirMask;
				thePlayer.dirFlagSrc = rawOpponentDirSrc;
				thePlayer.dirFlagMask = rawOpponentDirMask;
			}
			
			theOpponent.postFlagSrc = (short)((masterMessage.playerPostArray >> 4) & 0x0F);
			theOpponent.postFlagMask = (short)(masterMessage.playerDirPostMask & 0x0F);
			
			thePlayer.postFlagSrc = (short)((masterMessage.opponentPostArray >> 4) & 0x0F);
			thePlayer.postFlagMask = (short)(masterMessage.opponentDirPostMask & 0x0F);
			
			theBall.mode = (masterMessage.ballWhosMode >> 4) & 0x0F;
			wasGotBall = whosGotBall;
			whosGotBall = (short)(masterMessage.ballWhosMode & 0x0F);
			if (whosGotBall != wasGotBall)
			{
				switch (whosGotBall)
				{
					case kPlayerHasBall:
						theOpponent.loopsBallHeld = 0;
						if (thePlayer.loopsBallHeld == 0)
							thePlayer.loopsBallHeld = kLoopLimitOnHeldBall;
						break;
					case kOpponentHasBall:
						thePlayer.loopsBallHeld = 0;
						if (theOpponent.loopsBallHeld == 0)
							theOpponent.loopsBallHeld = kLoopLimitOnHeldBall;
						break;
					case kBallIsNotHere:
						thePlayer.loopsBallHeld = 0;
						theOpponent.loopsBallHeld = 0;
						break;
					default:
						break;
				}
				
				UpdateBallTimers(&thePlayer);
				UpdateBallTimers(&theOpponent);
				UpdateArrows();
			}
			
			thePlayer.mode = masterMessage.playerOpponentMode & 0x0F;
			theOpponent.mode = (masterMessage.playerOpponentMode >> 4) & 0x0F;
			
			theBall.dontDraw = (Boolean)((masterMessage.bitFlags >> 4) & 0x01);
			theBall.eraseTheBall = (Boolean)((masterMessage.bitFlags >> 3) & 0x01);
			tempDoorState = (Boolean)((masterMessage.bitFlags >> 1) & 0x01);
			if (tempDoorState != theDoor.doorState)
				theDoor.stateChanged = TRUE;
			theDoor.doorState = tempDoorState;
			playerInBack = !((Boolean)(masterMessage.bitFlags & 0x01));
			
			wasPlayerFouls = playerFouls;
			playerFouls = (masterMessage.packedFoulsRead >> 4) & 0x0F;
			
			if (wasPlayerFouls != playerFouls)
			{
				lengthOfMob = 90;
				StartMobSound();
				DisplayPlayerFouls(playerFouls);
			}
			
			wasOpponentFouls = opponentFouls;
			opponentFouls = masterMessage.packedFoulsRead & 0x0F;
			if (wasOpponentFouls != opponentFouls)
			{
				lengthOfApplause = 90;
				StartApplauseSound();
				DisplayOpponentFouls(opponentFouls);
			}
			
			if (masterMessage.playerScoreReads > opponentScore)
			{
				opponentScore = masterMessage.playerScoreReads;
				lengthOfMob = 120;
				StartMobSound();
				UpdateOpponentScore();
			}
			if (masterMessage.opponentScoreReads > playerScore)
			{
				playerScore = masterMessage.opponentScoreReads;
				lengthOfApplause = 120;
				StartApplauseSound();
				UpdatePlayerScore();
			}
			
			wasLastSound = (short)masterMessage.soundPlayed;
		}
	#endif
}


/*========================================================  InitializeMessages  */

void InitializeMessages (void)

{
	if (!imTheMaster)
	{
		masterMessage.messageType = 0;
		masterMessage.ballIsPoint = ((long)theBall.isRect.top << 16) | 
				(long)theBall.isRect.left;
		masterMessage.eraserPoint = ((long)theBall.eraser.top << 16) | 
				(long)theBall.eraser.left;
		masterMessage.playerIsPoint = ((long)theOpponent.isRect.top << 16) | 
				(long)theOpponent.isRect.left;
		masterMessage.opponentIsPoint = ((long)thePlayer.isRect.top << 16) | 
				(long)thePlayer.isRect.left;
		
		masterMessage.playerArrayDirSrc = (char)theOpponent.dirFlagSrc;
		masterMessage.playerPostArray = ((char)theOpponent.postFlagSrc << 4) | 
				(char)theOpponent.arrayFlagMask;
		masterMessage.playerDirPostMask = ((char)theOpponent.dirFlagMask << 4) | 
				(char)theOpponent.postFlagMask;
		
		masterMessage.opponentArrayDirSrc = (char)thePlayer.dirFlagSrc;
		masterMessage.opponentPostArray = ((char)thePlayer.postFlagSrc << 4) | 
				(char)thePlayer.arrayFlagMask;
		masterMessage.opponentDirPostMask = ((char)thePlayer.dirFlagMask << 4) | 
				(char)thePlayer.postFlagMask;
		
		masterMessage.ballWhosMode = ((char)theBall.mode << 4) | 
				(char)antiWhosBall[whosGotBall];
		
		masterMessage.playerOpponentMode = ((char)theOpponent.mode << 4) | 
				(char)thePlayer.mode;
		
		masterMessage.bitFlags = ((char)theBall.dontDraw << 4) | 
				((char)theBall.eraseTheBall << 3) | 
				((char)theDoor.doorOpen << 2) | 
				((char)theDoor.doorState << 1) | 
				(char)playerInBack;
		
		masterMessage.packedFoulsRead = ((char)playerFouls << 4) | (char)opponentFouls;
		masterMessage.playerScoreReads = playerScore;
		masterMessage.opponentScoreReads = opponentScore;
		masterMessage.soundPlayed = (unsigned char)wasLastSound;
	}
	else
	{
		slaveMessage.messageType = 0;
		if (netMirroring)
			slaveMessage.mouseH = -theOpponent.hMouse;
		else
			slaveMessage.mouseH = theOpponent.hMouse;
		slaveMessage.mouseV = theOpponent.vMouse;
		slaveMessage.bits = 0x00;
	}
}


/*========================================================  SpotPoints  */

Boolean SpotPoints (void)

{
	#define			rSpotDialogID		191
	#define			kButtSpotOkay		1
	#define			kEditSpotPoints		2
	#define			kUserBalloonNames	4
	#define			kNamesTitleLeft		6
	#define			kNamesTitleTop		16
	
	DialogPtr		spotDialog;
	PicHandle		thePict;
	Handle			iHandle;
	Rect			iRect;
	Str255			tempStr;
	long			tempLong;
	short			itemHit, iType;
	Boolean			leaveDialog, userOkayed;
	
	CenterDialog(rSpotDialogID);
	if (doZooms)
		ZoomOutDialogRect(rSpotDialogID);
	
	NumToString(speedFlag, tempStr);
	
	spotPoints = 0;
	ParamText("\p4", tempStr, "\p", "\p");
	
	spotDialog = GetNewDialog(rSpotDialogID, kNilPointer, kPutInFront);
	
	SetPort((GrafPtr)spotDialog);
	ShowWindow((GrafPtr)spotDialog);
	
	GetDItem(spotDialog, kUserBalloonNames, &iType, &iHandle, &iRect);
	if (isColor)
		thePict = GetPicture(kBalloon4PictID);
	else
		thePict = GetPicture(kBalloon1PictID);
	if (thePict != kNilPointer)
	{
		DrawPicture(thePict, &iRect);
		ReleaseResource((Handle)thePict);
	}
	
	GetIndString(tempStr, rMiscStrings, 11);
	if (tempStr[0] == 0)
		PasStringCopy((StringPtr)"\pSpot PointsÉ", (StringPtr)tempStr);
	MoveTo(kNamesTitleLeft, kNamesTitleTop);
	DrawString(tempStr);
	
	DrawDefaultButton(spotDialog, kButtSpotOkay);
	SelIText(spotDialog, kEditSpotPoints, 0, 32767);
	
	leaveDialog = FALSE;
	
	while (!leaveDialog)
	{
		ModalDialog(kNilPointer, &itemHit);
		
		switch (itemHit)
		{
			case kButtSpotOkay:
				GetDItem(spotDialog, kEditSpotPoints, &iType, &iHandle, &iRect);
				GetIText(iHandle, tempStr);
				StringToNum(tempStr, &tempLong);
				spotPoints = (short)tempLong;
				if ((spotPoints > 4) || (spotPoints < 0))
				{
					SysBeep(20);
					SelIText(spotDialog, kEditSpotPoints, 0, 32767);
				}
				else
				{
					userOkayed = TRUE;
					leaveDialog = TRUE;
				}
				break;
			default:
				break;
		}
	}
	
	DisposDialog(spotDialog);
	return (userOkayed);
}


