⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 host.cpp

📁 分布式坦克游戏
💻 CPP
📖 第 1 页 / 共 3 页
字号:
            }
    }
}

/*------------------------------------------------------------------------------

  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 + -