📄 tankobj.cpp
字号:
{ // We got a forced position and direction (due to checksum mismatch)
SetNewPos (m_iNewForcedXPos, m_iNewForcedYPos);
m_bForceNewPos = FALSE; // Turn it off
m_bImageChanged = TRUE;
}
else
{ // Normal game play
if (ManouverSet & CManouverSet::FORWARD_MASK)
{ // Move forward
m_dVelocity = fabs(m_dVelocity);
ms.SetBit (CManouverSet::FORWARD);
bTryToMove = TRUE;
} else if (ManouverSet & CManouverSet::BACKWARD_MASK)
{ // Move backwards
m_dVelocity = -1.0 * fabs(m_dVelocity);
ms.SetBit (CManouverSet::BACKWARD);
bTryToMove = TRUE;
}
else
StopMovement (); // No movement chosen
if (bTryToMove)
{ // Tank tried to move
if (CalcNewPos(dwCurTime) < 0)
{ //
// Failed to move - out of map case
//
UndoMovement ();
if (m_uDirectionIndex != uLastDir)
{ // If we moved AND rotated, cancel rotation as well.
m_uDirectionIndex = uLastDir;
m_hTankImage = himgLastImage;
}
ms.UnsetBit (CManouverSet::FORWARD); // Cancel movements:
ms.UnsetBit (CManouverSet::BACKWARD);
ms.UnsetBit (CManouverSet::TURN_RIGHT); // Cancel roations
ms.UnsetBit (CManouverSet::TURN_LEFT);
m_bImageChanged = FALSE;
}
else
{
// Tries to move and successded (so far, collision not tested yet)
m_bImageChanged = TRUE;
}
} // end of movement attempt
} // end of normal game play
} // end of if (m_bUseManouverSet)
//
// handle reaction:
//
CReaction Reaction = m_ObjList.GetGameReaction (this);
if (m_CommManager.IsHost() && (BONUS_NONE != Reaction.GetBonusType()))
//
// If this the host machine and a tank just hit a bonus, tell all the other
// players (including this player) that the bonus has just been eaten.
// This will cause a ADD_BONUS message to arrive with the Tank ID in
// the LifeSpan. The game manager, upon receipt of such a message will call
// the EatBonus method for the correct tank object.
//
m_CommManager.NotifyBonusEaten (m_uTankID);
//
// update state (shield level, image)
//
UINT ExplosionReact = Reaction.GetExplosionIntensity();
if (ExplosionReact)
{ // We are hit:
m_uShieldLevel -= ExplosionReact;
if (LONG(m_uShieldLevel) < 0)
{
// We are hit badly - that's the end:
if (m_bLocal) // If it's a remote tank, we have to
// wait for the judge decision...
Kill();
else
m_uShieldLevel = 0;
}
if (m_bLocal)
// If it's a local tank, update shield status.
m_pDlgWnd->SetShieldLevel (m_uShieldLevel);
}
//
// update position:
//
TerrainType TerrainReact = Reaction.GetTerrainDifficulty();
switch (TerrainReact)
{
case TERR_BLOCKED:
case HIT_TANK:
// we are blocked - rewind the new position:
UndoMovement ();
if (m_uDirectionIndex != uLastDir) {
// There was also a rotation, undo it.
m_uDirectionIndex = uLastDir;
m_hTankImage = himgLastImage;
}
m_bImageChanged = FALSE;
// Cancel all movements and rotations:
ms.UnsetBit (CManouverSet::TURN_RIGHT);
ms.UnsetBit (CManouverSet::TURN_LEFT);
ms.UnsetBit (CManouverSet::FORWARD);
ms.UnsetBit (CManouverSet::BACKWARD);
break;
case TERR_EMPTY:
m_dVelocity = TANK_MAX_VELOCITY;
break;
case TERR_75SPEED:
m_dVelocity = TANK_75_VELOCITY;
break;
case TERR_50SPEED:
m_dVelocity = TANK_50_VELOCITY;
break;
case TERR_25SPEED:
m_dVelocity = TANK_25_VELOCITY;
break;
default:
ASSERT (FALSE);
break;
}
if (m_bUseManouverSet)
{ // Can we use the manouver set to react to the user's whim
//
// check the fire controls, and spawn bullet/shell/mine if needed:
//
if ((ManouverSet & CManouverSet::FIRE_SHELL_MASK) && // Fire shell button is pressed and
m_uShells) // we have shells
{
if (ShellsEnabled(dwCurTime)) // we can fire a new shell
FireShell(dwCurTime);
ms.SetBit (CManouverSet::FIRE_SHELL);
}
if ((ManouverSet & CManouverSet::FIRE_BULLET_MASK) && // Fire bullet button is pressed and
m_uBullets) // we have bullets and
{
if (BulletsEnabled(dwCurTime)) // we can fire a new bullet
FireBullet(dwCurTime);
ms.SetBit (CManouverSet::FIRE_BULLET);
}
if ((ManouverSet & CManouverSet::DROP_MINE_MASK) && // Drop mine button is pressed and
m_uMines) // we have mines
{
if (MinesEnabled(dwCurTime)) // we can fire a new mine
// Try to drop a mine (may fail if there's no vacant room on the map)
DropMine(dwCurTime);
ms.SetBit (CManouverSet::DROP_MINE);
}
if ((ManouverSet & CManouverSet::AERIAL_SUPPORT_MASK) && // Bomber button is pressed and
!m_bBomberInSetup && // we don't already have a bomber in setup mode and
m_bBomberAvail) // we have the bomber icon on
{
LaunchBomber();
// Notice, we don't set the bomber bit in the ms. Only when the bomber starts to fly
// (after its setup mode) it sends ADD_BOMBER to all other players.
}
}
// Before we leave - update the last tick calculated:
// Check the fire rate bonus expiration time:
if (m_dwFireRateBonusLastTick && (m_dwFireRateBonusLastTick <= dwCurTime))
{ // turn off the fire rate bonus (timeout):
m_dwBulletFireDelay = BULLET_FIRE_DELAY;
m_dwShellFireDelay = SHELL_FIRE_DELAY;
m_dwFireRateBonusLastTick = 0;
if (m_bLocal)
// Turn of the icon
m_pDlgWnd->SetFastFireRate (FALSE);
}
SendManouverSet (ms); // Notify other tanks on the network of our actions.
// Store newly calculated position in table:
PosEntry NewPos(dwCurTime, m_Pos.x, m_Pos.y);
m_PosTable.AddHead(NewPos);
return STATE_ALIVE;
}
#pragma warning (default : 4701)
inline BOOL
CTankObj::BulletsEnabled(DWORD dwCurTime)
{
return (dwCurTime - m_dwLastBulletFiredTick >= m_dwBulletFireDelay);
}
inline BOOL
CTankObj::MinesEnabled(DWORD dwCurTime)
{
return (dwCurTime - m_dwLastMineDropTick >= MINE_FIRE_DELAY);
}
inline BOOL
CTankObj::ShellsEnabled(DWORD dwCurTime)
{
return (dwCurTime - m_dwLastShellFiredTick >= m_dwShellFireDelay);
}
void
CTankObj::FireShell(DWORD dwCurTime)
{
// update flags:
m_uShells--;
m_dwLastShellFiredTick = dwCurTime;
// spawn shell and send message to game mananger:
CMessage::MessageData Params;
Params.ShellParam.wXPos = WORD(m_SpawnOffsets[m_uDirectionIndex].iShellXOffset + m_Pos.x);
Params.ShellParam.wYPos = WORD(m_SpawnOffsets[m_uDirectionIndex].iShellYOffset + m_Pos.y);
Params.ShellParam.bDirectionIndex = BYTE(m_uDirectionIndex);
Params.ShellParam.bParentTankID = BYTE(m_uTankID);
VERIFY (m_MsgQueue.Enqueue(CMessage::ADD_SHELL, Params));
if (m_bLocal)
{
// Update display
m_pDlgWnd->SetShellsCount(m_uShells);
}
// Play the sound
TANKS_APP->m_gSoundManager.Play(CSoundManager::FIRE_SHELL);
}
void
CTankObj::FireBullet(DWORD dwCurTime)
{
// update flags:
m_uBullets--;
m_dwLastBulletFiredTick = dwCurTime;
// spawn bullet and send message to game mananger:
CMessage::MessageData Params;
Params.BulletParam.wXPos = WORD(m_SpawnOffsets[m_uDirectionIndex].iBulletXOffset + m_Pos.x);
Params.BulletParam.wYPos = WORD(m_SpawnOffsets[m_uDirectionIndex].iBulletYOffset + m_Pos.y);
Params.BulletParam.bDirectionIndex = BYTE(m_uDirectionIndex);
Params.BulletParam.bParentTankID = BYTE(m_uTankID);
VERIFY (m_MsgQueue.Enqueue(CMessage::ADD_BULLET, Params));
if (m_bLocal)
{
// Update display
m_pDlgWnd->SetBulletsCount(m_uBullets);
}
// Play sound
TANKS_APP->m_gSoundManager.Play(CSoundManager::FIRE_BULLET);
}
BOOL
CTankObj::DropMine(DWORD dwCurTime)
{
CMine tmpMine (m_SpawnOffsets[m_uDirectionIndex].iMineXOffset + m_Pos.x,
m_SpawnOffsets[m_uDirectionIndex].iMineYOffset + m_Pos.y);
CReaction Reaction = m_ObjList.GetGameReaction (&tmpMine);
// check that we can spawn:
if ((Reaction.GetTerrainDifficulty() == TERR_EMPTY) && // board is empty
(tmpMine.GetMapPosition(tmpMine.GetPos()) == (X_FULL_IN_MAP | Y_FULL_IN_MAP))) // and fully in map
{
// update flags:
m_uMines--;
m_dwLastMineDropTick = dwCurTime;
// spawn mine and send message to game mananger:
CMessage::MessageData Params;
Params.MineParam.wXPos = WORD(tmpMine.GetPos().x);
Params.MineParam.wYPos = WORD(tmpMine.GetPos().y);
VERIFY (m_MsgQueue.Enqueue(CMessage::ADD_MINE, Params));
if (m_bLocal)
{
// Update display
m_pDlgWnd->SetMinesCount(m_uMines);
}
return TRUE; // Mine dropped
}
return FALSE; // Mine cannot be dropped
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -