⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oandxcontroller.cpp

📁 Symbian OS C++ for Mobile Phones Volume 3 源码
💻 CPP
字号:
// oandxcontroller.cpp
//
// Copyright (c) 2006 Symbian Ltd.  All rights reserved.
//

#include "oandxcontroller.h"
#include "oandxengine.h"
#include "oandxappview.h"
#include "oandxappui.h"
#include "oandxdefs.h"


// -------- (de)allocation --------

COandXController* COandXController::NewL(MOandXGameObserver* aObserver)
/**
	Factory function allocates new instance of COandXController.
	
	@param	aObserver		Observer to notify when game events occur.
	@return					New, initialized instance of COandXController.
							This object is owned by the caller.
 */
	{
	COandXController* self = new(ELeave) COandXController(aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

COandXController::COandXController(MOandXGameObserver* aObserver)
/**
	Record observer to notify when game events occur, and
	clears the board.
	
	@param	aObserver		Observer to notify when game events occur.
 */
:	iObserver(aObserver),
	iState(EStBlank)
	{
    // empty
	}

void COandXController::ConstructL()
/**
	Second-phase constructor allocates an asynchronous callback
	to delete the transport outside transport AO handling.
 */
	{
	TCallBack cb(ConnectionCloserCallBack, this);
	iConnectionCloser = new(ELeave) CAsyncCallBack(cb, CActive::EPriorityHigh);
	}

COandXController::~COandXController()
/**
	If a transport is in use then delete it.
 */
	{
	delete iConnectionCloser;
	DeleteTransport();
	}


// -------- transport --------

void COandXController::AllocTransportL(TUid aTransportUid, TBool aRequireAddress, TBool aInitListen)
/**
	Factory function allocates a new transport.

	@pre This controller is not currently using a transport.
 */
	{
	TRAN_LOG3(">COandXController::AllocTransportL,uid=0x%08x,ra=%d,il=%d", aTransportUid.iUid, aRequireAddress, aInitListen);
	
	__ASSERT_DEBUG(iTransportInterface == 0, Panic(EAtAlreadyExists));

	TBuf<KMaxAddressLen> address;
	if (aRequireAddress)
		{
		_LIT(KTitle, "Enter address");
		CEikDialog* dlg = new(ELeave) CTextInputDialog(KTitle, address);
		dlg->ExecuteLD(R_TEXTINPUT_DIALOG);
		}
	
	iTransportInterface = CTransportInterface::NewL(aTransportUid, *this, address, aInitListen);
	
	TRAN_LOG1("<COandXController::AllocTransportL,ti=0x%08x", iTransportInterface);
	}

TInt COandXController::ConnectionCloserCallBack(TAny* aPtr)
/**
	This callback function is queued when a link error is detected or
	when a multiplayer game ends.  It tears down the current transport.

	@param	aPtr			Standard 32bit callback value.  This is actually
							the required this pointer.
	@return					KErrNone.  This arbitrary value is used to satisfy
							the callback signature.
 */
	{
	COandXController* self = static_cast<COandXController*>(aPtr);
	self->DeleteTransport();
	return KErrNone;
	}

void COandXController::DeleteTransport()
/**
	Deletes the current transport.  This cannot be called when handling
	a transport AO event.
 */
	{
	delete iTransportInterface;
	iTransportInterface = 0;
	}


// -------- start / stop game --------

void COandXController::OfferGameL(TUid aTransportUid, TBool aRequireAddress)
/**
	Start a new game where this device is the host, and sends the
	first move.  Any existing game is cancelled.
 */
	{
	ResetCurrentGame();
	
	iLocalUserSymbol = ETileCross;
	AllocTransportL(aTransportUid, aRequireAddress, /*aInitListen*/ EFalse);
	iState = EStWaitLocalMove;
	iObserver->ResetView();
	}

void COandXController::JoinGameL(TUid aTransportUid, TBool aRequireAddress)
/**
	Join a game which is being hosted on a remote device.
	This device is noughts and the remote device makes
	the first move.
 */
	{
	ResetCurrentGame();
	
	iLocalUserSymbol = ETileNought;
	AllocTransportL(aTransportUid, aRequireAddress, /*aInitListen*/ ETrue);
	iState = EStWaitRemoteMove;
	iObserver->ResetView();
	}

void COandXController::ResetCurrentGame()
/**
	Helper function for OfferGameL and JoinGameL closes any
	current transport link and resets the current game so it
	is not drawn.
 */
	{
	iState = EStBlank;
	iObserver->ResetView();
	DeleteTransport();
	Engine().Reset();
	}

// -------- game move --------

TBool COandXController::DrawableGame() const
/**
	Predicate function is used by the UI to determine whether there
	is a drawable game.  This can be a game which is in progress or
	which has finished, but it cannot be a game which has been aborted,
	e.g. because of resource failure or a lost connection, or which
	has not yet been started.

	@return					Whether the UI should redraw the game.
 */
	{
	return iState != EStBlank;
	}

void COandXController::HitSquareL(TInt aIndex)
/**
	The UI calls this function when the user selects a square.
	If it is the local player's turn and the selected square is
	blank then it selects the square and sends the move to the
	remote player.  Otherwise this function just returns, which
	saves the UI from having to determine whether the move is
	legal.

	@param	aIndex			Selected square's index.
 */
    {
    TRAN_LOG2(">COandXController::HitSquareL,idx=%d,st=%d", aIndex, iState);
    
    if (!(	iState == EStWaitLocalMove
		&&	Engine().TryMakeMove(aIndex, IsCrossTurn()) ))
        {
        return;
		}

    iObserver->RedrawSquare(aIndex);
	iObserver->RedrawCurrentPlayer();

	// send the move to the remote player
	SendMove(aIndex);

    TRAN_LOG0("<COandXController::HitSquareL");
    }

TBool COandXController::IsCrossTurn() const
/**
	The UI calls this function to find out whether it should
	draw the current player symbol as a nought or a cross.

	@return					Whether the last selected player was crosses.
 */
    {
	TBool ownTurn = (iState == EStWaitLocalMove);
	TBool amCross = (iLocalUserSymbol == ETileCross);
	return ownTurn == amCross;
    }

void COandXController::CheckForGameOver(COandXController::TState aNotOverState)
/**
	Checks if the game has ended, either as a draw or as a win for
	one of the players.  If the game has ended then it notifies the
	local user and tears down the transport.  (This is done as soon
	as possible instead of waiting for another game to start to save
	power.)  If the game has finished the game's state is set to
	EStFinished.

	This helper function combines the is used by SentPayload and
	ReceivedPayload.

	@param	aNotOverState	State to transition to if the game has not
							completed.  (Otherwise this controller
							transitions to EStFinished.)
 */
	{
	TInt winner = Engine().GameWonBy();
	if (winner == 0)
		iState = aNotOverState;
	else
		{
        iState = EStFinished;
        iObserver->ReportWinner(winner);
		iConnectionCloser->CallBack();
		}
	}

void COandXController::SendIndexL()
/**
	Send a custom index to the remote device to test invalid input handling.
	
	This function can only be called if the remote device is waiting for this
	device to send an index, else it would not be listening for input.
 */
	{
	if (iState != EStWaitLocalMove)
		return;
	
	// ask the user to specify the index
	TBuf<KMaxIndexLen> idxText;
	_LIT(KTitle, "Enter index");
	CEikDialog* dlg = new(ELeave) CTextInputDialog(KTitle, idxText);
	dlg->ExecuteLD(R_TEXTINPUT_DIALOG);
	
	TInt idxVal;
	TInt r = TLex(idxText).Val(idxVal);
	User::LeaveIfError(r);
	SendMove(idxVal);
	}

void COandXController::SendMove(TInt aIndex)
/**
	Convert the supplied index to an ASCII character and send it
	to the remote device.
 */
	{
	__ASSERT_DEBUG(iState == EStWaitLocalMove, Panic(ESmBadState));
	
	iState = EStWaitSendingLocalMove;
	TBuf<KPayloadLen> pyl(KPayloadLen);
	pyl[0] = '0' + aIndex;
	iTransportInterface->SendPayload(pyl);
	}

// -------- implement MTransportObserver --------

void COandXController::ReceivedPayload(const TDesC& aPayload)
	{
	__ASSERT_DEBUG(iState == EStWaitRemoteMove, Panic(ERpBadState));

	// extract the tile number from the payload
	TInt tileIndex = aPayload[0] - '0';
	TRAN_LOG1("-COandXController::ReceivedPayload,tileIndex=%d", tileIndex);
	
	TBool validTile = (tileIndex >= 0) && (tileIndex < KNumberOfTiles);
	COandXEngine& eng = Engine();
	validTile = validTile && eng.SquareStatus(tileIndex) == ETileBlank;
	
	if (! validTile)
		{
		_LIT(KInvalidMsg, "Received invalid tile index.");
		TerminateGame(KInvalidMsg);
		}
	else
		{
		eng.TryMakeMove(tileIndex, IsCrossTurn());
		iObserver->RedrawSquare(tileIndex);
		iObserver->RedrawCurrentPlayer();

		CheckForGameOver(EStWaitLocalMove);
		}
	}

void COandXController::SentPayload()
	{
	__ASSERT_DEBUG(iState == EStWaitSendingLocalMove, Panic(ESpBadState));

	CheckForGameOver(EStWaitRemoteMove);
	}

void COandXController::LostConnection(TInt aError)
/**
	Implement MTransportObserver by displaying an error dialog to
	notify the user the connection has been lost, and resetting the game.
	
	@param	aError			Symbian OS error code, the reason for the
							lost connection.  Not used.
 */
	{
	(void) aError;
	
	_LIT(KMessage, "Lost connection to remote device.");
	TerminateGame(KMessage);
	}

void COandXController::TerminateGame(const TDesC& aMsg)
/**
	This function is called when the game has to be terminated
	because of an error condition.
	
	@param	aMsg			Error messge to display to user.
 */
	{
	iState = EStBlank;
	iObserver->ResetView();
	
	_LIT(KEndGame, "End of game");
	CEikonEnv* ee = CEikonEnv::Static();
	ee->AlertWin(KEndGame, aMsg);
	
	// call after dialog dismissed so doesn't run and delete
	// transport while dialog is displayed.
	iConnectionCloser->CallBack();
	}

TInt COandXController::StartedLookingForServiceL()
/**
	Implement MTransportObserver by displaying a modal dialog
	which reads "Waiting for host.".
	
	@return					ExecuteLD return code.
	@see StoppedLookingForService
 */
	{
	_LIT(KMessage, "Waiting for host.");
	return RunWaitDialogL(KMessage);
	}

void COandXController::StoppedLookingForService()
/**
	Implement MTransportObserver by dismissing the dialog
	raised by StartedLookingForServiceL.
	
	@see StartedLookingForServiceL
 */
	{
	CancelWaitDialog();
	}

TInt COandXController::StartedConnectingToServiceL()
/**
	Implement MTransportObserver by raising a modal
	dialog which says "Connecting to service.".
	
	@return					ExecuteLD return code.
	@see StoppedConnectingToService
 */
	{
	_LIT(KMessage, "Connecting to service.");
	return RunWaitDialogL(KMessage);
	}

void COandXController::StoppedConnectingToService()
/**
	Implement MTransportObserver by dismissing the modal
	dialog raised by StartedConnectingToServiceL.
	
	@see StartedConnectingToServiceL
 */
	{
	CancelWaitDialog();
	}

TInt COandXController::StartedWaitingForClientL()
/**
	Implement MTransportObserver by raising a modal
	dialog which says "Waiting for client.".
	
	@return					ExecuteLD return code.
	@see StoppedWaitingForClient
 */
	{
	_LIT(KMessage, "Waiting for client.");
	return RunWaitDialogL(KMessage);
	}

void COandXController::StoppedWaitingForClient()
/**
	Implement MTransportObserver by dismissing the dialog
	raised by StartedWaitingForClientL.
 */
	{
	CancelWaitDialog();
	}

TBool COandXController::RunWaitDialogL(const TDesC& aMessage)
/**
	This helper function puts up a modal dialog.  The dialog is
	dismissed by CancelWaitDialog(), which is called when the
	actual event, such as connecting to a remote device, occurs.
	It can also be dismissed by the user selecting the Cancel
	option.
	
	@param	aMessage		Message to display in wait dialog.
	@return					EFalse if the user cancelled the dialog;
							ETrue if the application cancelled the dialog.
	@see CancelWaitDialog
 */
	{
	iAppDismiss = EFalse;
	iWaitDialog = new(ELeave) CWaitDialog(aMessage);
	iWaitDialog->ExecuteLD(R_WAIT_DIALOG);
	iWaitDialog = 0;
	return iAppDismiss;
	}

void COandXController::CancelWaitDialog()
/**
	This helper functions dismisses the dialog raised by RunWaitDialogL.
	
	@see RunWaitDialogL.
 */
	{
	TRAPD(r, iWaitDialog->TryExitL(EEikBidCancel));
	iAppDismiss = (r == KErrNone);
	}


// -------- debugging --------

#ifdef _DEBUG

void COandXController::Panic(COandXController::TPanic aPanic)
	{
	_LIT(KPanicCat, "OANDXCTRL");
	User::Panic(KPanicCat, aPanic);
	}

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -