?? oandxcontroller.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 + -