台州四张是浙江台州地区流行的一种简单玩法的扑克游戏,以牌九为基础,对牌九进行了扩展,使玩法变得更有趣味性和竞技性。
游戏玩家为4人,牌数:32张牌,不包括大、小王,由2张红Q、2张黑J、4张10、2张红9、4张7、4张6、2张红5、4张4、2张2、黑桃A、黑桃3组成
每家各分4张牌
由玩家自由组合,把4张牌组合成2对2张牌,再分别对比这两对牌,都赢者为赢家。
比牌时先比小牌,再比大牌
比牌大小按牌九的规则
点数大小: 9点>8点>7点>6点>5点>4点>3点>2点>1点>0点提示:同样点数,取里面最大的一张牌比大小,(大小按对子出现的顺序,A和3按最小的计算)0点没有大小之分,都一样大,同样大的对子或点数,上家赢。 没有对牌,则以二牌之和的个位数分胜负。若没有以上的对牌,则以二牌之和的个位数分胜负.最大是9,最小是0
牌点一样大的话,算上家胜出。
基于网狐架构台州四张游戏的开发-游戏设计这个游戏的设计比较简单,按客户的要求,没有下注,加注等按扭,只需要每局规定固定的底分,赢家赢,输家输就可以了。
服务器要处理的是发牌,自动分牌,比牌。
客户端要处理的是分牌,比牌,显示结果。
先说说客户端的设计,游戏设计成2-4人都可以玩,可以分牌,客户端需要两个按扭,一个分牌,一个比牌,需要12个扑克控件,每人3个,一个显示4张扑克,其它两个显示分牌后的两张扑克。还要有一个积分控件,用于显示游戏结果。
服务器部分很简单,只需要一个游戏逻辑类,用于处理发牌,分牌,比牌,需要处理两个网络事件,一个是分牌事件,一个是比牌事件,还有一个是游戏结束事件,再有一个就是定时器事件,处理客户端超时没有分牌,没有比牌的事件。
游戏开始每人发4张牌,由玩家自己组合成两组牌,每组2张,所以在客户端设计一个分牌按扭,按下按扭后4张扑克分为两组
//分牌按钮LRESULT CGameClientDlg::OnFenPai(WPARAM wParam, LPARAM lParam){
//获取扑克 //用户分牌
CMD_S_FenPai myfenpai; BYTE bTiCount,bNoChuCount; BYTE NoTiCardData[4];bNoChuCount=m_GameClientView.m_CardControl[SwitchViewChairID(GetMeChairID())].GetNoShootCard(NoTiCardData,2);
if (bNoChuCount==2){ bTiCount=m_GameClientView.m_CardControl[SwitchViewChairID(GetMeChairID())].GetShootCard(myfenpai.bfCardData,2);bNoChuCount=m_GameClientView.m_CardControl[SwitchViewChairID(GetMeChairID())].GetNoShootCard(myfenpai.bnCardData,2);
if (m_GameLogic.CompareCard(myfenpai.bfCardData,myfenpai.bnCardData,2)==true) { BYTE tempcarddata[2]; memcpy(tempcarddata,myfenpai.bfCardData,sizeof(tempcarddata)); memcpy(myfenpai.bfCardData,myfenpai.bnCardData,sizeof(tempcarddata)); memcpy(myfenpai.bnCardData,tempcarddata,sizeof(tempcarddata));
}
m_GameClientView.m_FenCardControl[SwitchViewChairID(GetMeChairID())][0].SetCardData(myfenpai.bfCardData,2);m_GameClientView.m_FenCardControl[SwitchViewChairID(GetMeChairID())][1].SetCardData(myfenpai.bnCardData,2);
m_GameClientView.m_FenCardControl[SwitchViewChairID(GetMeChairID())][0].SetDisplayFlag(true);m_GameClientView.m_FenCardControl[SwitchViewChairID(GetMeChairID())][1].SetDisplayFlag(true);
m_GameClientView.m_CardControl[SwitchViewChairID(GetMeChairID())].ShowWindow(false);
SendData(SUB_C_FENPAI,&myfenpai,sizeof(myfenpai)); m_GameClientView.m_btFenpai.ShowWindow(SW_HIDE); //m_GameClientView.m_btAddGold.ShowWindow(SW_SHOW);KillGameTimer(IDI_FENPAI_TIME);
}
return 0;
}
分牌后发送SUB_C_FENPAI给服务器
服务器收到SUB_C_FENPAI消息后进行如下处理
//分牌事件bool CTableFrameSink::OnUserFenPai(BYTE bfCardData[2],BYTE bnCardData[2],WORD wChairID){memcpy(m_bTableCardFenArray[wChairID][0],bfCardData,2);memcpy(m_bTableCardFenArray[wChairID][1],bnCardData,2);bBoolfen[wChairID]=true;bool fenover=true;
for (WORD i=0;i<m_wPlayerCount;i++) { if (m_pITableFrame->GetServerUserItem(i)!=NULL) { if (bBoolfen==false) fenover=false; }
}
if (fenover){ m_pITableFrame->SendTableData(INVALID_CHAIR,SUB_S_XIA_ZHU);}return true;
}收到消息后,把分牌扑克数据保存到服务器数组,然后循环判断是不是都已经分牌了,如果都分牌了,就发送SUB_S_XIA_ZHU消息给客户端,客户端收到后进行下注处理,下一编讲下注处理部
首先计算最大下注,在游戏开始计算玩家中最少积分的玩家积分数
//发送开始 CMD_S_GameStart GameStart; memset(&GameStart,0,sizeof(GameStart)); //计算下注 bool bCalculateGold=false; for (WORD i=0;i<m_wPlayerCount;i++) { pIServerUserItem=m_pITableFrame->GetServerUserItem(i); if (pIServerUserItem!=NULL) { m_bPlayStatus=true; m_lTableGold[i*2+1]=m_pGameServiceOption->lCellScore; if (bCalculateGold==false) { bCalculateGold=true; pUserScore=pIServerUserItem->GetUserScore(); ASSERT(pUserScore->lScore>m_pGameServiceOption->lCellScore); m_lMaxGold=pUserScore->lScore; } else { pUserScore=pIServerUserItem->GetUserScore(); ASSERT(pUserScore->lScore>1L); m_lMaxGold=__min(m_lMaxGold,pUserScore->lScore); } } }
GameStart.lMaxGold=m_lMaxGold; GameStart.lTurnMaxGold=m_lMaxGold/4L; GameStart.lTurnBasicGold=m_lTurnBasicGold;
计算出最少积分玩家的积分除4为最大下注数,游戏开始时发送给玩家
客户端在游戏到游戏开始时
m_GameClientView.SetUserGoldInfo(wViewChairID,true,lBaseGold);
//用户筹码void CGameClientView::SetUserGoldInfo(WORD wViewChairID, bool bTableGold, DWORD dwGold){ //参数判断 WORD wGoldPos=wViewChairID*2+((bTableGold==true)?1:0); if (wGoldPos>=CountArray(m_GoldStation)) return;
//设置变量 DWORD m_dwAllGold=0L; m_GoldView[wGoldPos].SetGold(dwGold); for (int i=0;i<CountArray(m_GoldStation);i++) m_dwAllGold+=m_GoldView.GetGold();
//更新视图 UpdateGameView(NULL);
return;}
设置加注按扭的值,此处是根据客户的要求设定的方法。只有4个值可以下注
第一次为庄家下注,然后下家下注,下家下注只能大于等于上家
当所有玩家下注结束进行比牌处理:
服务器端
//比牌事件bool CTableFrameSink::OnBiPaiCard(BYTE bitwince){
for (WORD i=0;i<m_wPlayerCount;i++) { //没分牌自动分牌 if (m_bTableCardFenArray[0][0]==0) {
memcpy(m_bTableCardFenArray[0],&m_bTableCardArray[0],2); memcpy(m_bTableCardFenArray[1],&m_bTableCardArray[2],2); }
} WORD wWinerUser=DeduceWiner(0,1,bitwince); for (WORD i=0;i<m_wPlayerCount;i++) { if (i==wWinerUser) bBoolWin[bitwince]=true; else bBoolWin[bitwince]=false;
} CMD_S_GAMEBI gamebi; memset(&gamebi,0,sizeof(CMD_S_GAMEBI)); for (WORD i=0;i<m_wPlayerCount;i++) { memcpy(gamebi.bfCardData,m_bTableCardFenArray[0],sizeof(m_bTableCardFenArray[0])); memcpy(gamebi.bnCardData,m_bTableCardFenArray[1],sizeof(m_bTableCardFenArray[1])); memcpy(gamebi.bBoolWin,bBoolWin,sizeof(bBoolWin));
}
gamebi.bCardTwice=bitwince;
m_pITableFrame->SendTableData(INVALID_CHAIR,SUB_S_BI_CARD,&gamebi,sizeof(gamebi)); m_firstwinder=wWinerUser; bicount=1; //设置定时器 m_pITableFrame->SetGameTimer(IDI_BIPAITIME,1000L,1,NULL);
return true;}
//二次比牌事件bool CTableFrameSink::OnBiPaiTwoCard(BYTE bitwince){
for (WORD i=0;i<m_wPlayerCount;i++) { if (m_pITableFrame->GetServerUserItem(i)!=NULL) { if (i!=m_firstwinder) { if (m_GameLogic.CompareCard(m_bTableCardFenArray[1],m_bTableCardFenArray[m_firstwinder][1],2)==true) bBoolWin[bitwince]=true; else bBoolWin[bitwince]=false; } } } CMD_S_GAMEBI gamebi;memset(&gamebi,0,sizeof(CMD_S_GAMEBI)); for (WORD i=0;i<m_wPlayerCount;i++) { memcpy(gamebi.bfCardData,m_bTableCardFenArray[0],sizeof(m_bTableCardFenArray[0])); memcpy(gamebi.bnCardData,m_bTableCardFenArray[1],sizeof(m_bTableCardFenArray[1])); memcpy(gamebi.bBoolWin,bBoolWin,sizeof(bBoolWin));
}
gamebi.bCardTwice=bitwince;
m_pITableFrame->SendTableData(INVALID_CHAIR,SUB_S_BI_CARD,&gamebi,sizeof(gamebi));
m_pITableFrame->SetGameTimer(IDI_GAMEEND,3000L,1,NULL); return true;}
比牌进行两次,先对比小牌,小牌中的赢家再和其它3家对比大牌,两次都赢才为赢,否则为合//对比扑克bool CGameLogic::CompareCard(BYTE bFirstList[], BYTE bNextList[], BYTE bCardCount){ //获取类型 BYTE bNextType=GetCardType(bNextList,bCardCount); BYTE bFirstType=GetCardType(bFirstList,bCardCount); //两手牌的最大值 BYTE FirstMaxValue=GetMaxValue(bFirstList); BYTE NextMaxValue=GetMaxValue(bNextList); //两手牌的最小值 BYTE FirstMinValue=GetMinValue(bFirstList); BYTE NextMinValue=GetMinValue(bNextList); //最大牌的花色// BYTE FirstColor=GetMaxColor(bFirstList);// BYTE NextColor=GetMaxColor(bNextList);
stCardType sFirstCard,sNextCard; sFirstCard=GetCardLevel(bFirstList); sNextCard=GetCardLevel(bNextList); if(sFirstCard.nLevel==sNextCard.nLevel) { if(sFirstCard.nCardType==CT_SINGLE && sNextCard.nCardType==CT_SINGLE) { BYTE FirstTotalValue=(GetCardLogicValue(bFirstList[0])+GetCardLogicValue(bFirstList[1]))%10; BYTE NextTotalValue=(GetCardLogicValue(bNextList[0])+GetCardLogicValue(bNextList[1]))%10; if(FirstTotalValue==NextTotalValue) { return true; } else { return FirstTotalValue>NextTotalValue; } } else { return sFirstCard.nCardType>sNextCard.nCardType;//对 } } else { return sFirstCard.nLevel<sNextCard.nLevel ? true: false; }
return false;
}比牌之后游戏结束
{ //定义变量 CMD_S_GameEnd GameEnd; memset(&GameEnd,0,sizeof(GameEnd)); tagScoreInfo ScoreInfo[m_wPlayerCount]; memset(&ScoreInfo,0,sizeof(ScoreInfo)); LONG lTax=0L;
for (WORD i=0;i<m_wPlayerCount;i++) { pIServerUserItem=m_pITableFrame->GetServerUserItem(i); if (pIServerUserItem!=NULL && bBoolgiveup==false) { //积分信息 if (i!=m_firstwinder) { if (bBoolWin[0]==false && bBoolWin[1]==false) { Bankuser=m_firstwinder; GameEnd.lGameGold-=(m_lTableGold[i*2]+m_pGameServiceOption->lCellScore);GameEnd.lGameGold[m_firstwinder]=GameEnd.lGameGold[m_firstwinder]-GameEnd.lGameGold+GameEnd.lGameGold*m_pITableFrame->GetTableShuilv()/100L;lTax=lTax-GameEnd.lGameGold*m_pITableFrame->GetTableShuilv()/100L; } else {
} }
} }
for (WORD i=0;i<m_wPlayerCount;i++) { pIServerUserItem=m_pITableFrame->GetServerUserItem(i); if (pIServerUserItem!=NULL && bBoolgiveup==true) { GameEnd.lGameGold-=m_pGameServiceOption->lCellScore;if (GameEnd.lGameGold[m_firstwinder]!=0){ GameEnd.lGameGold[m_firstwinder]+=(m_pGameServiceOption->lCellScore-m_pGameServiceOption->lCellScore*m_pITableFrame->GetTableShuilv()/100L); lTax=lTax+m_pGameServiceOption->lCellScore*m_pITableFrame->GetTableShuilv()/100L;}
} }
GameEnd.lTax=lTax; ScoreInfo[m_firstwinder].lRevenue=lTax; //发送信息 m_pITableFrame->SendTableData(INVALID_CHAIR,SUB_S_GAME_END,&GameEnd,sizeof(GameEnd)); m_pITableFrame->SendLookonData(INVALID_CHAIR,SUB_S_GAME_END,&GameEnd,sizeof(GameEnd));
//修改用户分数
for (WORD i=0;i<m_wPlayerCount;i++) { pIServerUserItem=m_pITableFrame->GetServerUserItem(i); if (pIServerUserItem!=NULL) { if (m_bPlayStatus==TRUE) { ScoreInfo.lScore=GameEnd.lGameGold; ScoreInfo.ScoreKind=(GameEnd.lGameGold>0L)?enScoreKind_Win:enScoreKind_Lost; m_pITableFrame->WriteUserScore(i,ScoreInfo.lScore ,ScoreInfo.lRevenue ,ScoreInfo.ScoreKind); } } }
//结束游戏 m_pITableFrame->ConcludeGame();
return true;
客户端收到游戏结束消息后进行如下处理
//游戏结束bool CGameClientDlg::OnSubGameEnd(const void * pBuffer, WORD wDataSize){ //效验参数 if (wDataSize!=sizeof(CMD_S_GameEnd)) return false; CMD_S_GameEnd * pGameEnd=(CMD_S_GameEnd *)pBuffer;
//播放声音 if (IsLookonMode()==false) { if (pGameEnd->lGameGold[GetMeChairID()]>0L) PlayGameSound(AfxGetInstanceHandle(),TEXT("GAME_WIN")); else PlayGameSound(AfxGetInstanceHandle(),TEXT("GAME_LOST")); } else PlayGameSound(GetModuleHandle(NULL),TEXT("GAME_END"));
//游戏正常结束 BYTE bCardData[5]; m_GameClientView.m_ScoreView.ResetScore(); for (WORD i=0;i<GAME_PLAYER;i++) { //设置信息 const tagUserData * pUserData=GetUserData(i); if (pUserData!=NULL) m_GameClientView.m_ScoreView.SetGameScore(pUserData->wChairID,pUserData->szName,pGameEnd->lGameGold);
} m_GameClientView.m_ScoreView.SetTax(pGameEnd->lTax); m_GameClientView.m_ScoreView.ShowWindow(SW_SHOW);
//设置控件 KillGameTimer(IDI_GIVE_UP);
//设置状态 SetGameStatus(GS_FREE);
//游戏变量 m_lTurnMaxGold=0L; m_lTurnBasicGold=0L; memset(m_bPlayStatus,0,sizeof(m_bPlayStatus));
//辅助变量 m_lGoldShow=0L; m_bShowHand=false; m_bMeAddGold=false; memset(m_szName,0,sizeof(m_szName));
//设置界面 if (IsLookonMode()==false) { m_GameClientView.m_btStart.ShowWindow(SW_SHOW); m_GameClientView.m_btStart.SetFocus(); //SetGameTimer(GetMeChairID(),IDI_START_GAME,30); }
return true;}