📄 doc.cpp
字号:
// Doc.cpp : implementation of the CBfieldDoc class
// Battlefield document -- most real work is here
#include "stdafx.h"
#include "bfield.h"
#include "insert.h"
#include "bsocket.h"
#include "Doc.h"
#include "ConnDlg.h"
#include "HostDlg.h"
#include "packet.h"
#include "mainfrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
///////////////////////
// CBfieldDoc
IMPLEMENT_DYNCREATE(CBfieldDoc, CDocument)
BEGIN_MESSAGE_MAP(CBfieldDoc, CDocument)
//{{AFX_MSG_MAP(CBfieldDoc)
ON_COMMAND(IDM_CONNECT, OnConnect)
ON_COMMAND(IDM_HOST, OnHost)
ON_UPDATE_COMMAND_UI(IDM_CONNECT, OnUpdateConnect)
ON_UPDATE_COMMAND_UI(ID_TURN, OnUpdateTurn)
ON_UPDATE_COMMAND_UI(IDM_HOST, OnUpdateHost)
ON_COMMAND(IDM_RESIGN, OnResign)
ON_UPDATE_COMMAND_UI(IDM_RESIGN, OnUpdateResign)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////
// CBfieldDoc construction/destruction
CBfieldDoc::CBfieldDoc()
{
sockfile=NULL;
xmit=NULL;
rcv=NULL;
MyTurn=FALSE;
}
CBfieldDoc::~CBfieldDoc()
{
NetClose();
}
BOOL CBfieldDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
NetClose();
// empty grids
for (int i=0;i<2;i++)
for (int x=0;x<10;x++)
for (int y=0;y<10;y++)
grid[i][x][y]='.';
mode=0;
placed=0;
HitCt[0]=0;
HitCt[1]=0;
MyTurn=FALSE;
return TRUE;
}
///////////////////////
// CBfieldDoc serialization -- not used
void CBfieldDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
///////////////////////
// CBfieldDoc diagnostics
#ifdef _DEBUG
void CBfieldDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CBfieldDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
///////////////////////
// CBfieldDoc commands
// Get state based on current mode
char CBfieldDoc::GetState(int x,int y)
{
return grid[mode][x][y];
}
// Handle mouse click from view
void CBfieldDoc::OnClick(int x,int y)
{
if (grid[mode][x][y]!='.'||x>9||y>9)
{
AfxMessageBox("Please click a blank square");
return;
}
if (mode==0) // setup
{
int q,step=1;
CInsert dlg;
if (placed==0x1F)
{
AfxMessageBox("You have placed all your pieces");
return;
}
// set up placement dialog
dlg.m_placed=placed;
dlg.m_x=x;
dlg.m_y=y;
// call dialog
int res=dlg.DoModal();
if (res==-1) return;
if (res=='.') return; // shouldn't happen
// check for piece sticking over edge
if ((dlg.m_Dir==DIR_WEST && x-dlg.m_Len<-1)||
(dlg.m_Dir==DIR_EAST && x+dlg.m_Len>10)||
(dlg.m_Dir==DIR_NORTH && y-dlg.m_Len<-1)||
(dlg.m_Dir==DIR_SOUTH && y+dlg.m_Len>10))
{
AfxMessageBox(
"The piece must completely fit on the board");
return;
}
// Now check for overlapping pieces
if (dlg.m_Dir==DIR_WEST||dlg.m_Dir==DIR_NORTH) step=-1;
if (dlg.m_Dir==DIR_EAST||dlg.m_Dir==DIR_WEST)
{
for (q=0;q<dlg.m_Len;q++)
if (grid[0][x+step*q][y]!='.')
{
AfxMessageBox(
"The piece overlaps another piece!");
return;
}
// set it up
for (q=0;q<dlg.m_Len;q++)
grid[0][x+step*q][y]=res;
}
else
{
for (q=0;q<dlg.m_Len;q++)
if (grid[0][x][y+step*q]!='.')
{
AfxMessageBox(
"The piece overlaps another piece!");
return;
}
for (q=0;q<dlg.m_Len;q++)
grid[0][x][y+step*q]=res;
}
// mark it as placed and redraw
placed|=dlg.m_Piece;
UpdateAllViews(NULL);
}
else // not in setup mode -- hostile click!
{
CPacket pkt;
if (!MyTurn) return; // no cheating
// build outbound packet
pkt.cmd=CMD_CLICK;
pkt.x=x;
pkt.y=y;
pkt.Serialize(*xmit);
xmit->Flush(); // make sure to send it
// get reply -- might block for a bit
// but assuming everything works, no big deal
pkt.Serialize(*rcv);
if (pkt.cmd!=CMD_REPLY)
{
AfxMessageBox("Bad reply");
return;
}
// update board
grid[1][pkt.x][pkt.y]=pkt.data;
// count our hits
if (pkt.data!='X') HitCt[0]++;
// check for win!
if (HitCt[0]==17)
{
AfxMessageBox("You win!");
NetClose();
OnNewDocument();
UpdateAllViews(NULL);
}
UpdateAllViews(NULL);
MyTurn=FALSE;
}
}
int CBfieldDoc::GetMode(void)
{
return mode;
}
// Come here to connect to host
// Host must be ready
void CBfieldDoc::OnConnect()
{
CConnDlg dlg;
if (dlg.DoModal()==IDCANCEL) return;
mode=-1;
UpdateStatus();
if (!socket.Create())
{
err(socket.GetLastError());
return;
}
if (!socket.Connect(dlg.m_Host,dlg.m_Port))
if (socket.GetLastError()!=WSAECONNREFUSED)
{
mode=0;
err(socket.GetLastError());
socket.Close();
return;
}
else
{
// Host not ready yet
mode=0;
AfxMessageBox("Host not available");
socket.Close();
return;
}
sockfile=new CSocketFile(&socket);
xmit=new CArchive(sockfile,CArchive::store);
rcv=new CArchive(sockfile,CArchive::load);
mode=1;
UpdateStatus();
UpdateAllViews(NULL);
}
//Here to set up as host
void CBfieldDoc::OnHost()
{
CHostDlg dlg;
if (dlg.DoModal()==IDCANCEL) return;
mode=-1;
UpdateStatus();
if (!hostsocket.Create(dlg.m_Port))
{
err(GetLastError());
return;
}
if (!hostsocket.Listen())
{
err(GetLastError());
return;
}
// wait for connection or error -- blocks
while (!hostsocket.Accept(socket) &&
!hostsocket.GetLastError());
if (hostsocket.GetLastError())
{
err(hostsocket.GetLastError());
return;
}
hostsocket.Close(); // no more connections
sockfile=new CSocketFile(&socket);
xmit=new CArchive(sockfile,CArchive::store);
rcv=new CArchive(sockfile,CArchive::load);
mode=1;
UpdateStatus();
UpdateAllViews(NULL);
MyTurn=TRUE;
AfxMessageBox("Connected: It is your turn");
}
// Enable connect menu
void CBfieldDoc::OnUpdateConnect(CCmdUI* pCmdUI)
{
pCmdUI->Enable(mode==0&&placed==0x1F);
}
// Enable host menu
void CBfieldDoc::OnUpdateHost(CCmdUI* pCmdUI)
{
pCmdUI->Enable(mode==0&&placed==0x1F);
}
// Resign game
void CBfieldDoc::OnResign()
{
CPacket pkt;
if (AfxMessageBox(
"Do you really want to quit?",MB_YESNO)==IDNO)
return;
pkt.cmd=CMD_RESIGN;
pkt.Serialize(*xmit);
NetClose();
OnNewDocument();
UpdateAllViews(NULL);
}
// Enable Resign
void CBfieldDoc::OnUpdateResign(CCmdUI* pCmdUI)
{
pCmdUI->Enable(mode==1&&MyTurn);
}
// Very bad general error routine
void CBfieldDoc::err(int ern)
{
CString s;
s.Format("%x-%x",ern,GetLastError());
AfxMessageBox(s);
}
// Close network connection
void CBfieldDoc::NetClose()
{
if (xmit) delete xmit;
if (rcv) delete rcv;
if (sockfile) delete sockfile;
socket.Close();
sockfile=NULL;
xmit=NULL;
rcv=NULL;
mode=0;
placed=0;
}
void CBfieldDoc::OnCloseDocument()
{
NetClose();
CDocument::OnCloseDocument();
}
// CBattleSocket calls this when data is available
void CBfieldDoc::GoAhead(void)
{
CPacket pkt;
CPacket outgoing;
UpdateStatus();
pkt.Serialize(*rcv); // get packet
if (pkt.cmd==CMD_RESIGN) // quitter?
{
AfxMessageBox("Your opponent resigned");
NetClose();
OnNewDocument();
UpdateAllViews(NULL);
return;
}
if (pkt.cmd!=CMD_CLICK)
{
AfxMessageBox("Unexpected error");
return;
}
// prepare reply
outgoing.data=grid[0][pkt.x][pkt.y];
outgoing.cmd=CMD_REPLY;
outgoing.x=pkt.x;
outgoing.y=pkt.y;
if (outgoing.data=='.') // convert our . to outbound X
outgoing.data='X';
else
HitCt[1]++; // He hit us!
// send it
outgoing.Serialize(*xmit);
xmit->Flush();
// check for loss
if (HitCt[1]==17)
{
AfxMessageBox("You lose!");
NetClose();
OnNewDocument();
UpdateAllViews(NULL);
}
MyTurn=TRUE;
CString msg;
if (outgoing.data!='X')
msg.Format("Opponent hit: %c. ",outgoing.data);
msg=msg+"It is your turn";
AfxMessageBox(msg);
}
BOOL CBfieldDoc::GetTurn()
{
return MyTurn;
}
// Helper function to update status bar
void CBfieldDoc::UpdateStatus(void)
{
CMainFrame *fw=(CMainFrame *)AfxGetMainWnd();
fw->UpdateStatus();
}
// We are ready if all pieces are placed (0x1F)
BOOL CBfieldDoc::GetReady(void)
{
return placed==0x1F;
}
// This updates the status bar pane
void CBfieldDoc::OnUpdateTurn(CCmdUI* pCmdUI)
{
int mode=GetMode();
BOOL turn=GetTurn();
CString s;
if (!mode)
{
if (placed==0x1F)
s="Ready to connect";
else
s="Setting up...";
}
else
{
if (mode==-1) s="Connecting...";
if (turn)
s="Your turn";
else
s="Waiting...";
}
CString counts;
counts.Format("(%d/%d)",HitCt[0],HitCt[1]);
s+=counts;
pCmdUI->SetText(s);
pCmdUI->Enable(TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -