📄 host.cpp
字号:
}
}
}
/*------------------------------------------------------------------------------
Function: LocateNewTankPos
Purpose: Finds a position for the new tank. Make sure the rectangle is vacant
and that the distance from other tanks is suitable. Calculates the
tanks direction to point to the center of the map.
Input: XPos,YPos, Dir - output params.
Output: None.
Remarks:
------------------------------------------------------------------------------*/
void
CHost::LocateNewTankPos(int &XPos, int &YPos, int &Dir)
{
#define PI double( 3.14159265359 )
#define MAX_TRIES 10
#define MIN_SQR_DIST (100 * 100)
DWORD dwMaxDist = 0;
CSize size(TANK_WIDTH, TANK_HEIGHT);
CPoint BestPos;
for (int i=0; i<MAX_TRIES; i++)
{ // Start looking
CPoint pos;
TANKS_APP->m_gGameManager.FindVacantRect(size, pos);
DWORD dwCurDist = TANKS_APP->m_gGameManager.GetMinDistanceFromTanks (pos);
if (MIN_SQR_DIST < dwCurDist)
{ // We found a spot that satisfies us - stop looking
BestPos = pos;
break;
}
if (dwMaxDist < dwCurDist)
{ // Found better position
dwMaxDist = dwCurDist;
BestPos = pos;
}
}
XPos = BestPos.x;
YPos = BestPos.y;
// Let's place all tanks facing the center of the board:
double dx = XPos - (MAP_WIDTH / 2);
double dy = YPos - (MAP_HEIGHT / 2);
if (0.0 == dx)
{ // Either point up or down
Dir = (dy > 0.0) ? 18 : 6;
}
double alpha = atan2 (dy, dx) * 180.0 / PI; // -180 <= alpha <= 180
Dir = (MAX_DIRECTIONS - int(alpha / 15.0)) % MAX_DIRECTIONS;
ASSERT (Dir >= 0 && Dir < MAX_DIRECTIONS);
if (Dir < 0 || Dir >= MAX_DIRECTIONS)
Dir = 0;
}
/*------------------------------------------------------------------------------
Function: MapAndGetAvailTankID
Purpose: Get the new tank's ID. Try to satisfy the player's request.
Input: bReqTankID - the requested tank ID.
Output: The new tanks ID.
Remarks:
------------------------------------------------------------------------------*/
BYTE
CHost::MapAndGetAvailTankID(BYTE bReqTankID)
{
BYTE bInd = bReqTankID; // Assume we take the request
if (m_aPlayersID[bInd] != CCommManager::INVALID_PLAYER_ID) {
// We can't satisfy the request - lets find a vacant place:
for (int i = 0; i < MAX_TANKS; i++)
if (CCommManager::INVALID_PLAYER_ID == m_aPlayersID[i])
break;
ASSERT(i != MAX_TANKS); // We must have a vacant place
if (i == MAX_TANKS) // In case of emergency - take any place:
i = bReqTankID;
bInd = BYTE(i);
}
m_aPlayersID[bInd] = m_idFrom;
return bInd;
}
int
CHost::LookupTankID (DPID id)
{ // Returns 0..MAX_TANKS-1 or -1 (no found) or -2 (host)
if (id == m_CommManager.GetHostID())
return -2; //Host
for (UINT i = 0; i < MAX_TANKS; i++)
if (id == m_aPlayersID[i])
return int(i);
return -1; // Not found
}
/*------------------------------------------------------------------------------
Function: HandleMessage
Purpose: Handle message send to the game host from a game player (either
remote or local).
Input: idFrom - the DirectPlay ID of the sending player
bFromJudge - flag indicating the message was send by the local tank.
Output: None.
Remarks:
------------------------------------------------------------------------------*/
void
CHost::HandleMessage(DPID idFrom, BOOL bFromJudge)
{
// Save message originator locally for reply options:
m_idFrom = idFrom;
// Decode the buffer into a message:
CMessage Msg(m_Message.m_aBuffer, (BYTE)m_Message.m_dwLength, SERVER_MSG);
// Update table of player's RTTs:
UpdatePlayerRTT (Msg.GetTime());
switch (Msg.GetType()) {
case CMessage::MANOUVER_SET:// All players get the manouver set (excluding the sender)
// One of the tanks is dispatching his manouver set notification to all:
// The message contains the data that should be
// send to all other tanks except the sender of this message.
// The message params are exactly the same, so we simply re-dispatch it!
NET_GAME_TRACE (("Host got MANOUVER_SET from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
SendToAllButSender();
break;
case CMessage::REMOVE_TANK: // Tell all the players a tank dies
NET_GAME_TRACE (("Host got REMOVE_TANK from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
SendToAllButSender ();
break;
case CMessage::ADD_BONUS: // Tell all the players a bonus is added / eaten
// Set message time to current game time:
*(PDWORD(&m_Message.m_aBuffer[1])) = TANKS_APP->m_gTimer.GetLocalTime();
NET_GAME_TRACE (("Host got ADD_BONUS from tank %d (game time = %d)",
LookupTankID(m_idFrom), *(PDWORD(&m_Message.m_aBuffer[1]))));
SendToAll ();
break;
case CMessage::ADD_BOMBER: // Tell all the players a bomber is in the air
NET_GAME_TRACE (("Host got ADD_BOMBER from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
SendToAll ();
break;
case CMessage::REQUEST_TANK: // A new tank (player) is joining the game session:
NET_GAME_TRACE (("Host got REQUEST_TANK from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
HandleRequestTank (BYTE(Msg.m_UnionData.TankRequestParam.bID));
break;
case CMessage::CHECK_SUM: // Check sum message from a remote or local player
NET_SYNC_TRACE (("Host got CHECK_SUM from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
HandleCheckSum (Msg, bFromJudge);
break;
case CMessage::CHAT: // Dispatch msg to all players except sender:
SendToAll();
break;
default:
NET_GAME_TRACE (("Host got unknown game message from tank %d (game time = %d)",
LookupTankID(m_idFrom), Msg.GetTime ()));
ASSERT(FALSE);
}
}
void
CHost::RemovePlayerFromArray(DPID idPlayer)
{
int i = LookupTankID (idPlayer);
ASSERT (i >= 0);
if (i < 0) // This should never happen
return;
PRINT_TANK_SYNC_STATS (i);
m_aPlayersID[i] = CCommManager::INVALID_PLAYER_ID;
if (m_GameManager.IsAlive (i))
{ // Non-gracefull player disconnection happaned
CMessage::MessageData Params;
// Create tank removal notification message:
Params.TankRemoveParam.ID = BYTE(i);
Params.TankRemoveParam.Explode = TRUE;
// Compose message from data:
CMessage Msg(CMessage::REMOVE_TANK, Params, SERVER_MSG);
// Pack message to buffer:
m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
SendToAll ();
}
}
void
CHost::SendToAllButSender()
{
for (UINT i = 0; i < MAX_TANKS; i++)
if ((m_aPlayersID[i] != m_idFrom) &&
(m_aPlayersID[i] != CCommManager::INVALID_PLAYER_ID)) {
m_CommManager.SendAsHost (m_aPlayersID[i]);
}
}
void
CHost::SendToAll ()
{
for (UINT i = 0; i < MAX_TANKS; i++)
if (m_aPlayersID[i] != CCommManager::INVALID_PLAYER_ID)
{ // A valid player
m_CommManager.SendAsHost (m_aPlayersID[i]); // Send as host
}
}
void
CHost::SendBonusStatus()
{
CMessage::MessageData MsgData;
// Get Bonus state from GameManager:
m_GameManager.GetBonusState(MsgData);
// Compose new message from data:
CMessage Msg(CMessage::ADD_BONUS, MsgData, SERVER_MSG);
// Pack message to buffer:
m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
// Send to last reported:
ReplyToSender();
}
void
CHost::SendAddTank(int iTankID)
{
CMessage::MessageData MsgData;
// Get tank's state and position:
BOOL bRes = m_GameManager.GetTankStatusAndPos(iTankID, MsgData);
if (!bRes)
return; // Tank just died between our fingers...
// Under no-circumstances should a remote player get it's local tanks this way:
MsgData.TankParam.Local = FALSE;
CMessage Msg(CMessage::ADD_TANK, MsgData, SERVER_MSG);
// Pack message to buffer:
m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
// Send to last reporter:
ReplyToSender();
}
void
CHost::SendTankPos
( int iTankID, // Setting position of tank ID
int nXPos, // X Pos
int nYPos) // Y Pos
{
CMessage::MessageData MsgData;
MsgData.TankPosParam.XPos = nXPos;
MsgData.TankPosParam.YPos = nYPos;
MsgData.TankPosParam.ID = iTankID;
// Compose message from data:
CMessage Msg(CMessage::SET_TANK_POS, MsgData, SERVER_MSG);
// Pack message to buffer:
m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
// Send to all other tanks, except reporter:
SendToAllButSender();
}
void
CHost::SendTankZombie(int iTankID, BOOL bZombie, BOOL bToAll)
{
CMessage::MessageData MsgData;
MsgData.TankZombieParam.ID = BYTE(iTankID);
MsgData.TankZombieParam.Zombie = BYTE(bZombie);
// Compose message from data:
CMessage Msg(CMessage::SET_TANK_ZOMBIE, MsgData, SERVER_MSG);
// Pack message to buffer:
m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
if (bToAll)
{ // Send to all tanks:
SendToAll();
} else
{
ReplyToSender();
}
}
void
CHost::SendTankStatus(int iTankID)
{
CMessage::MessageData MsgData;
// Get tank's status:
BOOL bRes = m_GameManager.GetTankStatus(iTankID, MsgData);
if (! bRes)
return;
// Override the judge's game-manager ammo counters and FF flag, with
// data from the judge's tables:
MsgData.TankParam.Shells = m_JudgeViewOfTanks[iTankID].Shells;
MsgData.TankParam.Bullets = m_JudgeViewOfTanks[iTankID].Bullets;
MsgData.TankParam.Mines = m_JudgeViewOfTanks[iTankID].Mines;
MsgData.TankParam.FastFire =
m_JudgeViewOfTanks[iTankID].FastFire;
// Under no-circumstances should a remote player get it's local tanks this way:
MsgData.TankParam.Local = FALSE;
// Compose message from data:
CMessage Msg(CMessage::SET_TANK_STATUS, MsgData, SERVER_MSG);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -