VC++2008开发网络百家乐街机游戏(下)
4.2.3 系统管理功能组
系统管理功能组是后台服务端软件的核心部分,由【场局生成控制】、【游戏路单打印】、【历史营业记录】、【营业利润统计】及【营业日报打印】等几个模块组成。【场局生成控制】负责每场百家乐游戏的场局生成及开局操作;【游戏路单打印】在本场百家乐游戏开局后由游戏管理人员以密闭信封打印出来置于箱中,以便游戏结束后由玩家核对的确保游戏公平;其余三个模块是游戏运营的数据分析,可以根据运营商的需求以各种方式统计出游戏的运行效益。
4.2.3.1 场局生成控制
场局生成控制负责每一场百家乐游戏的路单生成,开局之后游戏根据此模块生成的路单运行每一局游戏,本游戏设计每场百家乐为一百八十局,因此做如下的界面设计:
场局生成控制中关键是根据百家乐游戏的规则设计出发牌函数,由计算机模拟发牌由此生成本场百家乐的全部发牌记录表与庄闲记录表。根据百家乐游戏的规则,计算机模拟百家乐发牌由闲家开始,再发庄家,
庄家与闲家各发两张牌后,分计出庄闲两家的牌点数再根据补牌规则表计算出第三张补牌,共模拟一百八十局场次,计算函数如下:
void CTH_ROUND_INIView::OnBnClickedScButton()
{
// TODO: 在此添加控件通知处理程序代码
……
//以循环方式发牌18行代表18轮
for(int i=0;i<18;i )
{
CString* string_lpjl=new CString[10];
CString* string_fpjl=new CString[10];
//每局发牌每轮10场
for(int j=0;j<10;j )
{
//庄家变量
int int_bankerindex1,int_bankerindex2,int_bankerindex3;
//闲家变量
int int_playindex1,int_playindex2,int_playindex3;
//庄家与闲家点数
int int_banker_sumpoint,int_play_sumpoint;
CString string_banker_sumpoint,string_play_sumpoint;
//计算机模拟随机抽牌,按先闲家后庄家的规则顺序,庄闲各发两张牌
int_playindex1=rand()R 1;
int_bankerindex1=rand()R 1;
int_playindex2=rand()R 1;
int_bankerindex2=rand()R 1;
//计算出合计的点数
int_banker_sumpoint=Return_resultpoint(Return_puckpoint(int_bankerindex1) Return_puckpoint(int_bankerindex2));
int_play_sumpoint=Return_resultpoint(Return_puckpoint(int_playindex1) Return_puckpoint(int_playindex2));
//根据百家乐第三张牌的发牌规则表,计算第三张发牌
if(int_banker_sumpoint>=8||int_play_sumpoint>=8)
{
string_lpjl[j]=Return_ysstring(int_banker_sumpoint,int_play_sumpoint);
string_banker_sumpoint.Format("%d|%d",int_bankerindex1,int_bankerindex2);
string_play_sumpoint.Format("%d|%d",int_playindex1,int_playindex2);
string_fpjl[j]=string_banker_sumpoint "=" string_play_sumpoint;
}
else
{
int_playindex3=rand()R 1;
int_bankerindex3=rand()R 1;
, ; if(int_play_sumpoint==6||int_play_sumpoint==7)
{
, ; if(int_banker_sumpoint<=5)
{
int_banker_sumpoint=Return_resultpoint(int_banker_sumpoint Return_puckpoint(int_bankerindex3));
string_lpjl[j]=Return_ysstring(int_banker_sumpoint,int_play_sumpoint);
string_banker_sumpoint.Format("%d|%d|%d",int_bankerindex1,int_bankerindex2,int_bankerindex3);
string_play_sumpoint.Format("%d|%d",int_playindex1,int_playindex2);
string_fpjl[j]=string_banker_sumpoint "=" string_play_sumpoint;
}
else
{
string_lpjl[j]=Return_ysstring(int_banker_sumpoint,int_play_sumpoint);
string_banker_sumpoint.Format("%d|%d",int_bankerindex1,int_bankerindex2);
string_play_sumpoint.Format("%d|%d",int_playindex1,int_playindex2);
string_fpjl[j]=string_banker_sumpoint "=" string_play_sumpoint;
}
}
else
{
int int_play3=Return_puckpoint(int_playindex3);
int_play_sumpoint=Return_resultpoint(int_play_sumpoint int_play3);
if((int_banker_sumpoint==7)||(int_banker_sumpoint==6&&(int_play3==0||int_play3==1||int_play3==2||int_play3==3||int_play3==4||
int_play3==5||int_play3==8||int_play3==9)) ||(int_banker_sumpoint==5&&(int_play3==0||int_play3==1||int_play3==2||int_play3==3||int_play3==8||int_play3==9))
||(int_banker_sumpoint==4&&(int_play3==0||int_play3==1||int_play3==8||int_play3==9))
||(int_banker_sumpoint==3&&int_play3==8))
{
string_lpjl[j]=Return_ysstring(int_banker_sumpoint,int_play_sumpoint);
string_banker_sumpoint.Format("%d|%d",int_bankerindex1,int_bankerindex2);
string_play_sumpoint.Format("%d|%d|%d",int_playindex1,int_playindex2,int_playindex3);
string_fpjl[j]=string_banker_sumpoint "=" string_play_sumpoint;
}
else
{ int_banker_sumpoint=Return_resultpoint(int_banker_sumpoint Return_puckpoint(int_bankerindex3));
string_lpjl[j]=Return_ysstring(int_banker_sumpoint,int_play_sumpoint);
string_banker_sumpoint.Format("%d|%d|%d",int_bankerindex1,int_bankerindex2,int_bankerindex3);
string_play_sumpoint.Format("%d|%d|%d",int_playindex1,int_playindex2,int_playindex3);
string_fpjl[j]=string_banker_sumpoint "=" string_play_sumpoint;
}
}
}
}
//将记录载入百家乐路单记录表
CString sql_lpjl="insert into th_round_lpjl(A,B,C,D,E,F,G,H,I,J) values('";
sql_lpjl =string_lpjl[0];
sql_lpjl ="','";
sql_lpjl =string_lpjl[1];
sql_lpjl ="','";
sql_lpjl =string_lpjl[2];
sql_lpjl ="','";
sql_lpjl =string_lpjl[3];
sql_lpjl ="','";
sql_lpjl =string_lpjl[4];
sql_lpjl ="','";
sql_lpjl =string_lpjl[5];
sql_lpjl ="','";
sql_lpjl =string_lpjl[6];
sql_lpjl ="','";
sql_lpjl =string_lpjl[7];
sql_lpjl ="','";
sql_lpjl =string_lpjl[8];
sql_lpjl ="','";
sql_lpjl =string_lpjl[9];
sql_lpjl ="')";
m_datado.Exec(sql_lpjl);
//将记录载入百家乐发牌记录表(注:每场的发牌记录与路单记录是一一对应的)
CString sql_fpjl="insert into th_round_fpjl(A,B,C,D,E,F,G,H,I,J) values('";
sql_fpjl =string_fpjl[0];
sql_fpjl ="','";
sql_fpjl =string_fpjl[1];
sql_fpjl ="','";
sql_fpjl =string_fpjl[2];
sql_fpjl ="','";
sql_fpjl =string_fpjl[3];
sql_fpjl ="','";
sql_fpjl =string_fpjl[4];
sql_fpjl ="','";
sql_fpjl =string_fpjl[5];
sql_fpjl ="','";
sql_fpjl =string_fpjl[6];
sql_fpjl ="','";
sql_fpjl =string_fpjl[7];
sql_fpjl ="','";
sql_fpjl =string_fpjl[8];
sql_fpjl ="','";
sql_fpjl =string_fpjl[9];
sql_fpjl ="')";
m_datado.Exec(sql_fpjl);
delete [] string_fpjl;
delete [] string_lpjl;
}
//数据库记录备份
CString sql_bak="insert into th_round_lpjl_bak select * from th_round_lpjl";
m_datado.Exec(sql_bak);
m_datado.Close();
}
catch(...)
{
MessageBox("数据错误!");
}
//刷新显示的记录表
Update_data();
}
else
{
MessageBox("请清空场局后再随机生成!","提示",MB_ICONINFORMATION);
}
4.2.3.2 游戏路单打印
根据百家乐游戏的规则,在游戏开始前须将生成好的每场游戏结果路单打印出来,锁入透明的玻璃箱中,以便玩家在游戏结束后能够核对该局游戏的结果,以示公平.因此软件设计【游戏路单打印】模块,操作人员在每场百家乐生成之后进入此模块打印游戏路单.首先使用aResReport VC 专用报表设计工具设计出百家乐路单,在开发环境中添加aResReport OCX ActiveX的控件支持,编码根据百家乐游戏路单记录表生成本场的百家乐数据报表,由操作人员打印出来.生成路单的函数如下:
void CTH_ROUND_CTLView::OnQdButton()
{
// TODO: Add your control notification handler code here
m_art.InitAresData();
m_art.SetPrintOrientation(2);
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable("select * from th_round_lpjl");
int count=m_datado.GetRecordCount();
m_art.InsertRow("TAB",0,count);
if(count>0)
{
m_datado.MoveFirst();
//利用循环将数据载入报表文件
for(int i=0;i<count;i )
{
CString stra=m_datado.GetField("A");
m_art.SetVarData("A",i,stra);
CString strb=m_datado.GetField("B");
m_art.SetVarData("B",i,strb);
CString strc=m_datado.GetField("C");
m_art.SetVarData("C",i,strc);
CString strd=m_datado.GetField("D");
m_art.SetVarData("D",i,strd);
CString stre=m_datado.GetField("E");
m_art.SetVarData("E",i,stre);
CString strf=m_datado.GetField("F");
m_art.SetVarData("F",i,strf);
CString strg=m_datado.GetField("G");
m_art.SetVarData("G",i,strg);
CString strh=m_datado.GetField("H");
m_art.SetVarData("H",i,strh);
CString stri=m_datado.GetField("I");
m_art.SetVarData("I",i,stri);
CString strj=m_datado.GetField("J");
m_art.SetVarData("J",i,strj);
m_datado.MoveNext();
}
m_art.SetPrintOrientation(2);
m_art.ReSetPageCount(1);
m_art.SetCurPage(1);
m_art.UpdateCurPageData();
}
m_datado.Close();
}
catch(...)
{
}
}
运行界面截图如下:
本模块还提供将游戏路单数据导入文本文件做电子存储的功能,函数如下:
void CTH_ROUND_CTLView::OnBnClickedKlButton()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlgFileOpen(FALSE);
// dlgFileOpen.m_ofn.lStructSize=structsize;
dlgFileOpen.m_ofn.lpstrFilter = "文本文件*.TXT所有的文件(*.*)*.*";
//TCHAR lpstrFilename[MAX_PATH] = "";
dlgFileOpen.m_ofn.lpstrFile;//=lpstrFilename;
dlgFileOpen.m_ofn.lStructSize=88;
//标题栏
dlgFileOpen.m_ofn.lpstrTitle="保存记录到文件";
//显示以“只读方式打开”
dlgFileOpen.m_ofn.Flags&=~OFN_HIDEREADONLY;
//显示“帮助”,对应于当前的HLP文件
///dlgFileOpen.m_ofn.Flags|=OFN_ENABLETEMPLATEHANDLE;
//dlgFileOpen.m_ofn.Flags|=OFN_EXPLORER|OFN_SHOWHELP;//|OFN_EXPLORER;
//dlgFileOpen.m_ofn.lpTemplateName=MAKEINTRESOURCE(IDD_FILEOPENPREVEIW);
if(dlgFileOpen.DoModal()==IDOK&&dlgFileOpen.GetPathName()!="")
{
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable("select * from th_round_lpjl");
int num=m_datado.GetRecordCount();
if(num>0)
{
//导出报表文件格式设置
CString string_line_head=" LuckPoker Recorder n"; string_line_head ="┌──┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐n";
string_line_head ="│ │A │B │C │D │E │F │G │H │I │J │n";
CStdioFile lpjl_file; lpjl_file.Open(dlgFileOpen.GetPathName(),CStdioFile::modeCreate|CStdioFile::modeWrite);
lpjl_file.WriteString(string_line_head);
m_datado.MoveFirst();
for(int i=0;i<num;i )
{
CString string_head;
if(i<10)
string_head.Format("│%d │",i);
else
string_head.Format("│%d │",i);
CString stra=m_datado.GetField("A");
CString strb=m_datado.GetField("B");
CString strc=m_datado.GetField("C");
CString strd=m_datado.GetField("D");
CString stre=m_datado.GetField("E");
CString strf=m_datado.GetField("F");
CString strg=m_datado.GetField("G");
CString strh=m_datado.GetField("H");
CString stri=m_datado.GetField("I");
CString strj=m_datado.GetField("J");
CString str1=Lpad_string(stra," ",6);
CString str2=Lpad_string(strb," ",6);
CString str3=Lpad_string(strc," ",6);
CString str4=Lpad_string(strd," ",6);
CString str5=Lpad_string(stre," ",6);
CString str6=Lpad_string(strf," ",6);
CString str7=Lpad_string(strg," ",6);
CString str8=Lpad_string(strh," ",6);
CString str9=Lpad_string(stri," ",6);
CString str10=Lpad_string(strj," ",6);
CString string_end;
string_end.Format("│n");
CString string_addline="├──┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┤n";
string_addline =string_head;
string_addline =str1;
string_addline ="│";
string_addline =str2;
string_addline ="│";
string_addline =str3;
string_addline ="│";
string_addline =str4;
string_addline ="│";
string_addline =str5;
string_addline ="│";
string_addline =str6;
string_addline ="│";
string_addline =str7;
string_addline ="│";
string_addline =str8;
string_addline ="│";
string_addline =str9;
string_addline ="│";
string_addline =str10;
string_addline =string_end;
lpjl_file.WriteString(string_addline);
m_datado.MoveNext();
}
CString string_line_end="└──┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘n";
lpjl_file.WriteString(string_line_end);
lpjl_file.Close();
}
m_datado.Close();
MessageBox("你所保存的文件是:" (CString)dlgFileOpen.m_ofn.lpstrFile,"提示",MB_ICONINFORMATION);
}
catch(...)
{
}
}
}
运行后导出格式截图如下:
4.3 游戏时钟端设计
游戏时钟控制台是控制的整个百家乐游戏启停运行的,操作人员通过游戏时钟控制台控制前台客户端游戏的运行与暂停,整个游戏的开局与倒计时皆可在此模块操控.
4.3.1 软件界面布置
打开Visual C 2008 IDE环境,新建以TH_ROUND_TIM命名的MFC Dialog工程方案,布置Dialog界面的控件如下图:
4.3.2 模块编码
根据该款百家乐街机游戏的设计思想,游戏时钟控制台通过网络数据源读取服务端的ACCESS 2007数据库,并由操控数据库中的th_round_time同步时钟记录表控制前台客户端的运行,因此采用定时进程的设计思想编写该模块的核心函数,编码如下:
void CTH_ROUND_TIMDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
if(bool_end)
{
CString strdjs,strsubdjs;
//读取游戏设置的倒计时数值
labelccdjs:
try
{
m_djs.GetWindowText(strdjs);
strsubdjs.Format("%d",atoi(strdjs.operator LPCTSTR())-1);
CDATABE_ADO m_ado;
m_ado.Open("TH_ROUND","admin/admin","flyingtjf");
m_ado.OpenTable("select * from th_round_time");
m_ado.SetField("djs",strsubdjs);
m_djs.SetWindowText(strsubdjs);
m_ado.Close();
}
catch(...)
{
goto labelccdjs;
}
if(atoi(strsubdjs.operator LPCTSTR())==10&&string_gameregular=="BTOC")
{
//在倒计时几秒时阻断前端客户机的一切上分操作
if(bool_sfcdpx)
{
run_cdpx();
}
else
{
if(bool_sfzdsc)
{
run_zdsf();
}
}
}
//将游戏时钟控制台置于等待状态
if(atoi(strsubdjs.operator LPCTSTR())==0)
{
labelstart:
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable("select * from th_round_wait");
m_datado.SetField("reset","1");
m_datado.Close();
}
catch(...)
{
goto labelstart;
}
//在前台客户端游戏运行发牌动画时同步等待
Sleep(10000);
CString bool_waitmac="1";
do
{
label:
try
{
CDATABE_ADO m_ado;
m_ado.Open("TH_ROUND","admin/admin","flyingtjf");
m_ado.OpenTable("select * from th_round_wait");
bool_waitmac=m_ado.GetField("waitmac");
m_ado.Close();
}
catch(...)
{
goto label;
}
}
while(bool_waitmac=="1");
//下一轮游戏倒计时开始
CString bufferdjs;
{
label1:
try
{
CDATABE_ADO m_ado;
m_ado.Open("TH_ROUND","admin/admin","flyingtjf");
m_ado.OpenTable("select * from th_round_info");
bufferdjs=m_ado.GetField("倒计时");
string_gameregular=m_ado.GetField("游戏规则");
…
//读取设置的基础数据
}
//场次计数
CString string_bjcc;
m_bjcc.GetWindowText(string_bjcc);
labelccjs:
try
{
CDATABE_ADO m_ado;
……
m_datado.Close();
}
catch(...)
{
goto labelend;
}
//180局游戏运行完毕后,时钟控制台自动停止
if(atoi(string_bjcc.operator LPCTSTR())>=179)
{
KillTimer(1);
bool_end=false;
//总局数计数
…
MessageBox("本局场次已结束!","提示");
}
}
}
CDialog::OnTimer(nIDEvent);
}
4.4 前台客户端设计
前台客户端是整个百家乐游戏操作设计要求最高的一块,要考虑到街机的改装与移植,因此将PC机的整个键盘区域在软件中重新定义,以便能够支持十个玩家同时操作一台前端主机而不冲突,前台客户端采用一台主机通过分屏器连接十台显示器方式,由十个玩家分别操作各自的控制台按键上退分.
4.4.1 软件界面设计
因为前台客户端面向游戏玩家,设计界面尽量美观和谐,可操作性强,游戏的操作同时支持十个玩家,按键按小注,大注,取消,红庄,黑闲,绿和六个设计,发牌动画安排在屏幕的左上方.屏幕右上方安排百家乐游戏的整场路单结果,画面如下:
打开Visual C 2008 IDE环境,新建以TH_ROUND_WIN命名的MFC Dialog工程方案,整个前台工程全部由编码完成,不涉及控件运用.
4.4.2 模块编码
前台客户端编码主要分三块,一是利用多线程技术同步读取游戏时钟控制台的时钟数据,二是对PC键盘进行十区域分割支持多个玩家同时操作,三是针对每场的百家乐游戏根据事先生成好的游戏路单结果逐场发牌并结合玩家的下分计算出玩家的输赢状况回馈显示,详细介绍如下:
4.4.2.1 游戏同步时钟读取
游戏同步时钟是后台控制前端游戏画面同步显示与数据运行速度的关键,根据系统的性能要求采用工作者线程技术读取后台的同步时钟数据,首先在TH_ROUND_WINDlg.h头文件中定义新的同步时钟读取消息,编码如下: #define WM_READTIMER WM_USER 1;
再定义对应此消息的用户界面响应函数: LRESULT Read_timer(WPARAM wParam,LPARAM lParam);此函数是整个前端客户软件的核心所在,联系了后台的同步时钟与动画显示等一系列功能.再定义工作者线程变量: CWinThread* m_PDrawThread;
准备工作就绪开始运用函数编码,利用工作者线程读取后台的同步时钟需利用全局函数做消息循环的响应控制,如下:
UINT Play_timer(LPVOID sound)
{
while(1)
{
AfxGetMainWnd()->PostMessageA(WM_READTIMER);
Sleep(1000);
}
return 0;
}
此函数利用无穷循环以秒级单位向用户界面不断发送读时钟的消息,与游戏时钟控制台保持同步显示.此函数的启动在工程的OnInitDialog()函数中编码完成,如下:
……
if(m_PDrawThread)
{
StopDraw=true;
m_PDrawThread->ResumeThread();
::WaitForSingleObject(m_PDrawThread->m_hThread,INFINITE);
delete m_PDrawThread;
}
m_PDrawThread=AfxBeginThread(Play_timer,&m_hWnd,THREAD_PRIORITY_ABOVE_NORMAL,0,CREATE_SUSPENDED);
m_PDrawThread->m_bAutoDelete=false;
StopDraw=false;
m_PDrawThread->ResumeThread();
……
此处编码确保前台客户端游戏启动时能及时发送用户界面读时函数,与时钟控制台同步运行,用户界面读时函数的编码如下:
LRESULT CTH_ROUND_WINDlg::Read_timer(WPARAM wParam,LPARAM lParam)
{
//初始化倒计时等一些基本参数
……
if(int_djs<=11&&bool_hidesfyf)
{
//倒计时达11秒时开始隐藏上局游戏发牌,准备新局的发牌
Hide_sf();
Reset_winfz();
//读取本局游戏路单记录,准备本局游戏发牌
…
Show_aviprev();
string_bjlprec=Return_bjlprec();
Return_bcfp();
bool_hidesfyf=false;
}
//倒计时达6秒,本局游戏开始发牌
if(int_djs<=6&&bool_hide6)
{
Move_play1_prev();//闲家第一张牌
bool_hide6=false;
}
if(int_djs<=5&&bool_hide5)
{
Move_banker1_prev();//庄家第一张牌
bool_hide5=false;
}
if(int_djs<=4&&bool_hide4)
{
Move_play2_prev();//闲家第二张牌
bool_hide4=false;
}
if(int_djs<=3&&bool_hide3)
{
Move_banker2_prev();//庄家第二张牌
bool_hide3=false;
}
if(int_djs<=2&&bool_hide2)
{
Move_play3_prev();//闲家第三张牌,如有则显示,无则不显示
bool_hide2=false;
}
if(int_djs<=1&&bool_hide1)
{
Move_banker3_prev();//庄家第三张牌,如有则显示,无则不显示
bool_hide1=false;
}
if(int_djs==0)
, ; {
m_PDrawThread->SuspendThread();//挂起读时工作者线程
//calculate
……
CString retstravi=Add_bjlprec();//在游戏画面右上角的游戏路单记录中增加本局结果显示
Calculate_grade(retstravi);//根据本局结果结合玩家的游戏下分计算各玩家的输赢状况
//end
……
Move_end();
m_PDrawThread->ResumeThread();//本局游戏结束,恢复读时线程
}
//游戏结束时判断开局
m_sumcc.GetWindowText(string_bjcc);
if(string_bjcc=="180")
{
Show_sumcc();
if(bool_hylpjl)
{
bool_hylpjl=false;
Hide_bjlprec();
Show_bjlprec();
}
}
//游戏开局后隐藏上一轮的游戏记录
m_sumcc.GetWindowText(string_bjcc);
if(string_bjcc=="0")
{
Hide_bjlprec();
Reset_winfz();
}
}
玩家输赢分值计算函数的核心编码举例如下:
void CTH_ROUND_WINDlg::Calculate_grade_btoc(CString retstring)
{
//读取赔率参数
……
if(retstring=="红色")
{
for(int i=0;i<10;i )
{
//循环计算十个玩家的输赢分值并回馈显示
CString string_monzsf,string_redmonyfz,string_blackmonyfz,string_greenmonyfz;
m_zsf[i].GetWindowText(string_monzsf);
m_red[i].GetWindowText(string_redmonyfz);
m_black[i].GetWindowText(string_blackmonyfz);
m_green[i].GetWindowText(string_greenmonyfz);
int int_zsf=atoi(string_monzsf.operator LPCTSTR());
int int_red=atoi(string_redmonyfz.operator LPCTSTR());
int int_black=atoi(string_blackmonyfz.operator LPCTSTR());
int int_green=atoi(string_greenmonyfz.operator LPCTSTR());
if(int_red>0)
{
int int_yf,int_addzsf;
if(string_csq=="red")
{
int_yf=(int)(floor(int_red*(int_redcomrate-1)*(1.00-double_csl)));
int_addzsf=int_yf int_red;
}
else
{
int_yf=int_red*(int_redcomrate-1);
int_addzsf=int_yf int_red;
}
int_zsf =int_addzsf;
string_monzsf.Format("%d",int_zsf);
CString string_winfz;
if(int_addzsf-int_black-int_green>0)
string_winfz.Format("+%d",int_addzsf-int_black-int_green);
if(int_addzsf-int_black-int_green<0)
string_winfz.Format("-%d",abs(int_addzsf-int_black-int_green));
m_yf[i].SetText(string_winfz);
}
else
{
CString string_falfz;
string_falfz.Format("-%d",int_black int_green);
if(string_falfz!="-")
m_yf[i].SetText(string_falfz);
}
//写入后台数据库中
CString strsql;
if(i==0)
strsql="select * from th_round_single01";
……
if(i==8)
strsql="select * from th_round_single09";
if(i==9)
strsql="select * from th_round_single10";
labelred:
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable(strsql);
m_datado.SetField("single_ztf",string_monzsf);
m_datado.SetField("red","0");
m_datado.SetField("black","0");
m_datado.SetField("green","0");
m_zsf[i].SetWindowText(string_monzsf);
m_red[i].SetWindowText("0");
m_black[i].SetWindowText("0");
m_green[i].SetWindowText("0");
m_datado.Close();
}
catch(...)
{
goto labelred;
}
}
}
if(retstring=="黑色")
{
……
}
if(retstring=="绿色")
{
……
}
}
4.4.2.2 PC键盘十区域分割定义
本游戏前端软件采用一台PC主机或BOX模拟器通过分屏器连接十台显示器的模式,软件在同一画面上支持十个玩家同时操作,因此基于PC机平台研发时须对PC的标准键盘进行十区域的划分,安装时采用专用的PC键盘串接卡连接到各个游戏柜的控制台上方便操作,考虑键盘电路的复用组合状况,要求支持多线程的键盘按键并不能按键冲突干扰,经过对键盘电路的研究分析,作如下的组合划分:
机器号 下分按键一 下分按键二 取消 红 黑 绿
————————————————————————————————————————
1: Q(81) W(87) E(69) U(85) R(82) I(73)
2: O(79) P(80) 7(0x67) 9(0x69) 8(0x68) (0x6B)
3: A(65) S(83) D(68) J(74) F(70) K(75)
4: ~(192) -(189) (187) Insert(45) Home(36) PageUp(33)
5: Z(90) X(88) C(67) M(77) V(86) <(188)
6: BACK(0x8) 4(0x64) 5(0x65) >(190) 6(0x66) /(0x6F)
7: T(84) Y(89) F3(0x72) [(219) F7(0x76) ](221)
8: F12(0x7B) B(66) N(78) 下(0x28) 左(0x25) 右(0x27)
9: ?(191) -(0x6D) "(222) 0(0x60) 上(0x26) del(0x2E)
10: G(71) H(72) ESC(0x1B) F6(0x75) F4(0x73) F11(0x7A)
(注:括弧中为键盘按键的ASCII键码值)
首先在PreTranslateMessage函数中截取键盘消息,编码如下:
BOOL CTH_ROUND_WINDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
BOOL bHandleNow = FALSE;
CString strdjs;
m_djs.GetWindowText(strdjs);
int intdjs=atoi(strdjs.operator LPCTSTR());
if(intdjs>7)
{
switch (pMsg->message)
{
case WM_KEYDOWN:
switch (pMsg->wParam)
{
//单注按键
//01
//0
case 81:
//A
case 87:
//B
case 69:
……
//01:RED-BLACK-GREEN
case 85:
case 82:
case 73:
……
//退出
case VK_RETURN:
bHandleNow = TRUE;
break;
}
if (bHandleNow)
{
OnKeyDown(pMsg->wParam, LOWORD(pMsg ->lParam), HIWORD(pMsg->lParam));
}
break;
}
}
return bHandleNow;
}
在OnKeyDown函数中响应玩家的所有按键操作,编码如下:
void CTH_ROUND_WINDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
//响应关机按钮
if(nChar==VK_RETURN)
{
typedef int (CALLBACK*SHUTDOWNDLG)(int);
HINSTANCE hInst=LoadLibrary("shell32.dll");
SHUTDOWNDLG ShutDownDialog;
if(hInst!=NULL)
{
ShutDownDialog=(SHUTDOWNDLG)GetProcAddress(hInst,(LPSTR)60);
(*ShutDownDialog)(0);
}
exit(0);
}
//一号机到十号机的按键划分
if(nChar==81||nChar==87||nChar==69||nChar==85||nChar==82||nChar==73)
Mac_sf01(nChar);//一号机按键函数
……
if(nChar==71||nChar==72||nChar==0x1B||nChar==0x75||nChar==0x73||nChar==0x7A)
Mac_sf10(nChar);//十号机按键函数
CDialog::OnKeyDown(nChar, nRepCnt, nFlags);
}
以一号机为例介绍按键函数部分编码如下:
void CTH_ROUND_WINDlg::Mac_sf01(UINT nChar)
{
CString strdjs;
m_djs.GetWindowText(strdjs);
int intdjs=atoi(strdjs.operator LPCTSTR());
if(nChar==81)//小分按键
{
m_sf[0].ShowWindow(SW_SHOW);
m_sf[0].SetText(string_dzsf1);
return;
}
if(nChar==87)//大分按键
{
m_sf[0].ShowWindow(SW_SHOW);
m_sf[0].SetText(string_dzsf2);
return;
}
if(nChar==69&&intdjs>10)//取消按键分值
{
……
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable("select * from th_round_single01");
m_datado.SetField("single_ztf",string_hyzsf);
m_datado.SetField("red","0");
m_datado.SetField("black","0");
m_datado.SetField("green","0");
m_zsf[0].SetWindowText(string_hyzsf);
m_red[0].SetWindowText("0");
m_black[0].SetWindowText("0");
m_green[0].SetWindowText("0");
m_datado.Close();
}
catch(...)
{
}
m_sf[0].ShowWindow(SW_HIDE);
return;
}
if(nChar==85&&(intdjs>10||string_bjlprec!="红色"))//红色下分
{
……
if(Determined_sf(atoi(string_dzsf.operator LPCTSTR()),0))
{
try
{
CDATABE_ADO m_datado;
m_datado.Open("TH_ROUND","admin/admin","flyingtjf");
m_datado.OpenTable("select * from th_round_single01");
int intsf=atoi(string_dzsf.operator LPCTSTR());
int intsingle_ztf=atoi(m_datado.GetField("single_ztf").operator LPCTSTR());
int int_red=atoi(string_red.operator LPCTSTR());
if(intsingle_ztf-intsf>=0)
{
intsingle_ztf-=intsf;
CString strsingle_ztf;
strsingle_ztf.Format("%d",intsingle_ztf);
int_red =intsf;
CString strsingle_red;
strsingle_red.Format("%d",int_red);
m_datado.SetField("single_ztf",strsingle_ztf);
m_datado.SetField("red",strsingle_red);
m_zsf[0].SetWindowText(strsingle_ztf);
m_red[0].SetWindowText(strsingle_red);
}
m_datado.Close();
}
catch(...)
{
}
}
m_sf[0].ShowWindow(SW_HIDE);
return;
}
if(nChar==82&&(intdjs>10||string_bjlprec!="黑色"))//黑色下分
{
……
}
if(nChar==73&&(intdjs>10||string_bjlprec!="绿色"))//绿色下分
{
……
}
}