New feature: riot shields protect against damage from some directions.

For more info, see http://thepit.ja-galaxy-forum.com/index.php?t=msg&th=23452&start=0&

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8434 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2017-07-29 21:18:13 +00:00
parent 8a82802932
commit 11729a132e
22 changed files with 498 additions and 19 deletions
+17
View File
@@ -2714,6 +2714,15 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
cnt++;
}
}
//////////////////// SHIELD
if ( Item[gpItemDescObject->usItem].usRiotShieldStrength > 0 )
{
swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[40], szUDBGenSecondaryStatsExplanationsTooltipText[40] );
SetRegionFastHelpText( &(gUDBFasthelpRegions[iFirstDataRegion + cnt]), pStr );
MSYS_EnableRegion( &gUDBFasthelpRegions[iFirstDataRegion + cnt] );
++cnt;
}
}
//////////////////////////////////////////////////////
@@ -6255,6 +6264,14 @@ void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject )
++cnt;
}
}
//////////////////// SHIELD
if ( (Item[gpItemDescObject->usItem].usRiotShieldStrength > 0 && !fComparisonMode) ||
(fComparisonMode && Item[gpComparedItemDescObject->usItem].usRiotShieldStrength > 0) )
{
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 38, gItemDescGenSecondaryRegions[cnt].sLeft + sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
++cnt;
}
}
void DrawPropertyValueInColour( INT16 iValue, UINT8 ubNumLine, UINT8 ubNumRegion, BOOLEAN fComparisonMode, BOOLEAN fModifier, BOOLEAN fHigherBetter, UINT16 uiOverwriteColour = 0, BOOLEAN fPercentSign = FALSE )
+154
View File
@@ -2571,6 +2571,105 @@ return( iImpact );
}
*/
// Flugente: riot shields
void DamageRiotShield( SOLDIERTYPE* pSoldier, INT32& rsDamage, INT32& rsSecondaryDamage )
{
if ( !pSoldier )
return;
OBJECTTYPE* pObj = pSoldier->GetEquippedRiotShield( );
if ( pObj && rsDamage > 0 && Item[pObj->usItem].usRiotShieldStrength > 0 )
{
INT32 damage_original = rsDamage;
UINT16 shieldstrength = Item[pObj->usItem].usRiotShieldStrength;
UINT16 damagetoshield = 2 * damage_original / shieldstrength;
pSoldier->RiotShieldTakeDamage( damagetoshield );
INT32 damage_new = max( 0, min( damage_original, ((100.0f - shieldstrength) / 100.0f) * (damage_original - shieldstrength) ) );
if ( rsSecondaryDamage > 0 )
rsSecondaryDamage = max( 0, rsSecondaryDamage * damage_new / damage_original );
rsDamage = damage_new;
}
}
// Flugente: handle bullet impact on riot shield. Returns true if bullet should be removed
BOOLEAN DamageRiotShield_Bullet( SOLDIERTYPE* pSoldier, BULLET* pBullet )
{
UINT16 ubAmmoType = 0;
SOLDIERTYPE * pFirer = NULL;
if ( pBullet->ubFirerID != NOBODY )
pFirer = pBullet->pFirer;
// HEADROCK HAM 5: Fragments read attacking weapon from explosive, not from firer. Theoretically,
// all bullets should read this value...
UINT16 usAttackingWeapon = 0;
if ( pBullet->ubFirerID == NOBODY || pBullet->fFragment )
{
usAttackingWeapon = pBullet->fromItem;
}
else
{
usAttackingWeapon = pFirer->usAttackingWeapon;
}
if ( pBullet->usFlags & BULLET_FLAG_KNIFE )
{
UINT16 usItem = (Item[pBullet->fromItem].bloodieditem>0 ? Item[pBullet->fromItem].bloodieditem : pBullet->fromItem);
UINT16 usItemStatus = (pBullet->ubItemStatus>1 ? pBullet->ubItemStatus - Random( 2 ) : pBullet->ubItemStatus);
// Add item
CreateItem( usItem, usItemStatus, &gTempObject );
AddItemToPool( pSoldier->sGridNo, &gTempObject, -1, pSoldier->pathing.bLevel, 0, 0 );
// Make team look for items
NotifySoldiersToLookforItems( );
// Flugente: if this guy has the disease, or the blade was already infected, the new one will be too
if ( pSoldier->sDiseasePoints[0] > 0 || pBullet->usFlags & BULLET_FLAG_INFECTED )
(*&gTempObject)[0]->data.sObjectFlag |= INFECTED;
ubAmmoType = AMMO_KNIFE;
// as we've already stopped the bullet, get out of here
return TRUE;
}
else if ( pBullet->fFragment )
{
// Read ammo type from the explosive data.
ubAmmoType = Explosive[Item[usAttackingWeapon].ubClassIndex].ubFragType;
}
else
{
ubAmmoType = AMMO_REGULAR;
if ( pFirer )
ubAmmoType = pFirer->inv[pFirer->ubAttackingHand][0]->data.gun.ubGunAmmoType;
}
INT32 impact_original = max(0, pBullet->iImpact - pBullet->iImpactReduction);
FLOAT damagepercentage = (FLOAT)((FLOAT)AmmoTypes[ubAmmoType].armourImpactReductionDivisor / (FLOAT)max( 1, AmmoTypes[ubAmmoType].armourImpactReductionMultiplier ));
damagepercentage *= 1.0f + max( AmmoTypes[ubAmmoType].dDamageModifierArmouredVehicle, AmmoTypes[ubAmmoType].dDamageModifierTank );
INT32 impact_new = impact_original * damagepercentage;
INT32 tmp = 0;
DamageRiotShield( pSoldier, impact_new, tmp );
INT32 impactreduction = impact_original - impact_new / damagepercentage;
pBullet->iImpactReduction += impactreduction;
return (pBullet->iImpact <= pBullet->iImpactReduction);
}
BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntended )
{
INT32 iImpact, iDamage;
@@ -6365,6 +6464,8 @@ void MoveBullet( INT32 iBullet )
FIXEDPT qWindowBottomHeight;
FIXEDPT qWindowTopHeight;
UINT16 lastriotshieldholder = NOBODY; // added by Flugente
pBullet = GetBulletPtr( iBullet );
// CHECK MIN TIME ELAPSED
@@ -6913,6 +7014,33 @@ void MoveBullet( INT32 iBullet )
pStructure = gpLocalStructure[iStructureLoop];
if (pStructure && pStructure->sCubeOffset == sDesiredLevel)
{
// Flugente: a riot shield would cover the entire front of a tile. We thus cannot check whether the person would be hit, as the bullet might miss a soldier
// Instead, we check whether the structure is indeed a person, whether that person has a riot shield equipped, and whether that shield faces the bullet before it would hit the soldier
// the same bullet cannot hit a shield multiple times
if ( lastriotshieldholder != pStructure->usStructureID && pStructure->fFlags & STRUCTURE_PERSON )
{
SOLDIERTYPE* pTarget = MercPtrs[pStructure->usStructureID];
lastriotshieldholder = pStructure->usStructureID;
// check for riot shield contact
if ( pTarget && pTarget->IsRiotShieldEquipped( ) )
{
UINT8 bulletdir_inverse = GetDirectionToGridNoFromGridNo( pTarget->sGridNo, pBullet->sOrigGridNo );
// check whether the opposite direction of the bullet is the direction the soldier looks, or adjacant to that. That would mean the shield is between bullet and soldier
if ( bulletdir_inverse == pTarget->ubDirection || bulletdir_inverse == gOneCCDirection[pTarget->ubDirection] || bulletdir_inverse == gOneCDirection[pTarget->ubDirection] )
{
if ( DamageRiotShield_Bullet( pTarget, pBullet ) )
{
RemoveBullet( pBullet->iBullet );
return;
}
}
}
}
if (((*(pStructure->pShape))[pBullet->bLOSIndexX][pBullet->bLOSIndexY] & AtHeight[iCurrCubesAboveLevelZ]) > 0)
{
if (pStructure->fFlags & STRUCTURE_PERSON)
@@ -7103,6 +7231,32 @@ void MoveBullet( INT32 iBullet )
}
}
}
// Flugente: a riot shield would cover the entire front of a tile. We thus cannot check whether the person would be hit, as the bullet might miss a soldier
// Instead, we check whether the structure is indeed a person, whether that person has a riot shield equipped, and whether that shield faces the bullet before it would hit the soldier
if ( lastriotshieldholder != pStructure->usStructureID && pStructure->fFlags & STRUCTURE_PERSON )
{
SOLDIERTYPE* pTarget = MercPtrs[pStructure->usStructureID];
lastriotshieldholder = pStructure->usStructureID;
// check for riot shield contact
if ( pTarget && pTarget->IsRiotShieldEquipped( ) )
{
UINT8 bulletdir = GetDirectionToGridNoFromGridNo( pBullet->sOrigGridNo, pTarget->sGridNo );
// check whether the direction of the bullet is the direction the soldier looks, or adjacant to that. That would mean the shield is hit after the and soldier
if ( bulletdir == pTarget->ubDirection || bulletdir == gOneCCDirection[pTarget->ubDirection] || bulletdir == gOneCDirection[pTarget->ubDirection] )
{
if ( DamageRiotShield_Bullet( pTarget, pBullet ) )
{
RemoveBullet( pBullet->iBullet );
return;
}
}
}
}
}
}
}
+3
View File
@@ -248,4 +248,7 @@ void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuz
// HEADROCK HAM 5: New function, completely replaces the Counter Force Frequency check.
FLOAT CalcCounterForceChange( SOLDIERTYPE * pShooter, UINT32 uiCounterForceAccuracy, FLOAT dCounterForceMax, FLOAT dMuzzleOffset, FLOAT bRecoil, FLOAT dPrevCounterForce, UINT32 uiIntendedBullets );
// Flugente: riot shields
void DamageRiotShield( SOLDIERTYPE* pSoldier, INT32& rsDamage, INT32& rsSecondaryDamage );
#endif
+31
View File
@@ -1404,6 +1404,12 @@ INT16 AStarPathfinder::CalcAP(int const terrainCost, UINT8 const direction)
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
movementAPCost *= gItemSettings.fShieldMovementAPCostModifier;
}
if (terrainCost == TRAVELCOST_FENCE)
{
switch( movementModeToUseForAPs )
@@ -3629,6 +3635,12 @@ if(!GridNoOnVisibleWorldTile(iDestination))
if ( TERRAIN_IS_HIGH_WATER( gpWorldLevelData[ newLoc ].ubTerrainID ) )
ubAPCost = (ubAPCost * (100 + s->GetBackgroundValue(BG_SWIMMING))) / 100;
// Flugente: riot shields lower movement speed
if ( s->IsRiotShieldEquipped( ) )
{
ubAPCost *= gItemSettings.fShieldMovementAPCostModifier;
}
// SANDRO - moved backpack check to here
// Moa: backpack penalty
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( s ) != ITEM_NOT_FOUND )
@@ -4699,6 +4711,13 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
sMovementAPsCost += APBPConstants[AP_STEALTH_MODIFIER];
}
}
// Flugente: riot shields lower movement speed
if ( pSold->IsRiotShieldEquipped( ) )
{
sMovementAPsCost *= gItemSettings.fShieldMovementAPCostModifier;
}
// Check for backpack
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
// sMovementAPsCost += APBPConstants[AP_MODIFIER_PACK];
@@ -4747,11 +4766,13 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SANDRO - This part was modified "a bit"
sMovementAPsCost = sTileCost;
// Check for reverse mode
if ( pSold->bReverse || bReverse )
{
sMovementAPsCost += APBPConstants[AP_REVERSE_MODIFIER];
}
// STOMP traits - Athletics trait decreases movement cost
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSold, ATHLETICS_NT ))
{
@@ -4818,6 +4839,16 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl
sPointsRun += APBPConstants[AP_STEALTH_MODIFIER];
}
}
// Flugente: riot shields lower movement speed
if ( pSold->IsRiotShieldEquipped( ) )
{
sPointsWalk *= gItemSettings.fShieldMovementAPCostModifier;
sPointsCrawl *= gItemSettings.fShieldMovementAPCostModifier;
sPointsSwat *= gItemSettings.fShieldMovementAPCostModifier;
sPointsRun *= gItemSettings.fShieldMovementAPCostModifier;
}
// Check for backpack
//if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSold ) != ITEM_NOT_FOUND )
//{
+24 -5
View File
@@ -474,6 +474,12 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u
sPoints = max(1, (INT16)((sPoints * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5));
}
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
sPoints *= gItemSettings.fShieldMovementAPCostModifier;
}
// Flugente: scuba fins reduce movement cost in water, but increase cost on land
if ( pSoldier->inv[LEGPOS].exists() && HasItemFlag( pSoldier->inv[LEGPOS].usItem, SCUBA_FINS ) )
{
@@ -715,6 +721,13 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir,
{
sPoints = max(1, (INT16)((sPoints * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5));
}
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
sPoints *= gItemSettings.fShieldMovementAPCostModifier;
}
// Check if doors if not player's merc (they have to open them manually)
if ( sSwitchValue == TRAVELCOST_DOOR && pSoldier->bTeam != gbPlayerNum )
{
@@ -4209,17 +4222,23 @@ INT16 GetAPsProne( SOLDIERTYPE *pSoldier, BOOLEAN fBackpackCheck )
// SANDRO - Added feature to calculate start run cost (for Athletics trait)
INT16 GetAPsStartRun( SOLDIERTYPE *pSoldier )
{
INT16 val = APBPConstants[AP_START_RUN_COST];
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
val *= gItemSettings.fShieldMovementAPCostModifier;
// Athletics trait
if ( HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT ) && gGameOptions.fNewTraitSystem )
return( max( 1, (INT16)((APBPConstants[AP_START_RUN_COST] * (100 - gSkillTraitValues.ubATAPsMovementReduction)/100) + 0.5 )) );
else
return( APBPConstants[AP_START_RUN_COST] );
if( HAS_SKILL_TRAIT( pSoldier, ATHLETICS_NT ) && gGameOptions.fNewTraitSystem )
val = max( 1, (INT16)((val * (100 - gSkillTraitValues.ubATAPsMovementReduction) / 100) + 0.5) );
return val;
}
// SANDRO - Added feature to calculate APs for handling doors (for Ambidextrous trait)
INT16 GetAPsToOpenDoor( SOLDIERTYPE *pSoldier )
{
if( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) )
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT ) )
return( max( 1, (INT16)((APBPConstants[AP_OPEN_DOOR] * (100 - gSkillTraitValues.ubAMHandleDoorsAPsReduction)/100) + 0.5 )) );
else
return( APBPConstants[AP_OPEN_DOOR] );
+2 -1
View File
@@ -1510,7 +1510,8 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier )
// ONLY DO THIS IF CERTAIN CONDITIONS ARISE!
// For one, only do for mercs!
if ( pSoldier->ubBodyType <= REGFEMALE )
// Flugente: don't do this while equipping a shield, as this renders them almost useless
if ( pSoldier->ubBodyType <= REGFEMALE && !pSoldier->IsRiotShieldEquipped( ) )
{
// Secondly, don't if we are going to collapse
if ( pSoldier->stats.bLife >= OKLIFE && pSoldier->bBreath > 0 && pSoldier->pathing.bLevel == 0 )
+109 -2
View File
@@ -8917,7 +8917,7 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier
pSoldier->sAniDelay = (INT16)uiTerrainDelay;
// If a moving animation and w/re on drugs, increase speed....
// If a moving animation and we're on drugs, increase speed....
if ( gAnimControl[pSoldier->usAnimState].uiFlags & ANIM_MOVING )
{
if ( pSoldier->newdrugs.size[DRUG_EFFECT_AP] )
@@ -8949,6 +8949,7 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier
pSoldier->sAniDelay = (INT16)(pSoldier->sAniDelay * 2);
}
}
// SANDRO - STOMP traits - bonus to movement speed for Athletics
if ( gGameOptions.fNewTraitSystem && (gAnimControl[pSoldier->usAnimState].uiFlags & ANIM_MOVING) )
{
@@ -8958,6 +8959,12 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier
}
}
// Flugente: riot shields lower movement speed
if ( pSoldier->IsRiotShieldEquipped( ) )
{
pSoldier->sAniDelay = gItemSettings.fShieldMovementAPCostModifier * pSoldier->sAniDelay;
}
//pSoldier->sAniDelay = pSoldier->sAniDelay * ( 1 * gTacticalStatus.bRealtimeSpeed / 2 );
}
@@ -9900,6 +9907,33 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
default:
break;
}
// Flugente: do we have a riot shield equipped?
if ( this->IsRiotShieldEquipped( ) )
{
// if we have equipped a riot shield and are being attacked in melee, ignore damage from some directions
if ( ubReason == TAKE_DAMAGE_BLADE || ubReason == TAKE_DAMAGE_HANDTOHAND || ubReason == TAKE_DAMAGE_TENTACLES )
{
if ( ubAttacker != NOBODY && MercPtrs[ubAttacker] )
{
UINT8 attackdir_inverse = GetDirectionToGridNoFromGridNo( this->sGridNo, MercPtrs[ubAttacker]->sGridNo );
// if the shield faces the direction of the attacker, we block the attack
if ( attackdir_inverse == this->ubDirection || attackdir_inverse == gOneCCDirection[this->ubDirection] || attackdir_inverse == gOneCDirection[this->ubDirection] )
{
// damaging even a wooden shield is hard. For that reason we lower the initial damage.
INT32 damage = sLifeDeduct / 3;
INT32 breathdamage = sBreathLoss;
DamageRiotShield( this, damage, breathdamage );
sLifeDeduct = damage;
sBreathLoss = breathdamage;
PlayJA2Sample( (UINT32)(S_WOOD_IMPACT1 + Random(3)), RATE_11025, SoundVolume( MIDVOLUME, this->sGridNo ), 1, SoundDir( this->sGridNo ) );
}
}
}
}
// Deduct life!, Show damage if we want!
bOldLife = this->stats.bLife;
@@ -17360,7 +17394,7 @@ BOOLEAN SOLDIERTYPE::UseSkill( UINT8 iSkill, INT32 usMapPos, UINT8 ID )
case SKILLS_RADIO_JAM:
return JamCommunications( );
break;
case SKILLS_RADIO_SCAN_FOR_JAM:
return ScanForJam( );
break;
@@ -19244,6 +19278,79 @@ UINT16 SOLDIERTYPE::GetInteractiveActionSkill( INT32 sGridNo, UINT8 usLevel, UIN
return 0;
}
// Flugente: riot shields
OBJECTTYPE* SOLDIERTYPE::GetEquippedRiotShield()
{
OBJECTTYPE* pObj = NULL;
if ( this->inv[HANDPOS].exists( ) && Item[this->inv[HANDPOS].usItem].usRiotShieldStrength > 0 )
pObj = &(this->inv[HANDPOS]);
if ( this->inv[SECONDHANDPOS].exists( ) && Item[this->inv[SECONDHANDPOS].usItem].usRiotShieldStrength > 0 )
pObj = &(this->inv[SECONDHANDPOS]);
return pObj;
}
BOOLEAN SOLDIERTYPE::IsRiotShieldEquipped()
{
// shield is not erect if prone
if ( gAnimControl[this->usAnimState].ubEndHeight == ANIM_PRONE )
return FALSE;
// no shield while swimming
if ( TERRAIN_IS_HIGH_WATER(this->sGridNo) )
return FALSE;
return (GetEquippedRiotShield() != NULL);
}
void SOLDIERTYPE::DestroyEquippedRiotShield( )
{
// create graphic (destroyed shield item?)
OBJECTTYPE* pObj = GetEquippedRiotShield( );
if ( pObj )
{
if ( Item[pObj->usItem].usBuddyItem )
{
CreateItem( Item[pObj->usItem].usBuddyItem, 100, pObj );
// Flugente: why would we keep a piece of scrap in our hands in the first place? just drop it to the ground
AddItemToPool( this->sGridNo, pObj, 1, this->pathing.bLevel, 0, -1 );
NotifySoldiersToLookforItems( );
}
// Delete object
DeleteObj( pObj );
}
// dirty interface panel
DirtyMercPanelInterface( this, DIRTYLEVEL2 );
this->DoMercBattleSound( BATTLE_SOUND_CURSE1 );
}
void SOLDIERTYPE::RiotShieldTakeDamage( INT32 sDamage )
{
OBJECTTYPE* pObj = GetEquippedRiotShield();
if ( pObj )
{
PlayJA2Sample( (UINT32)(S_METAL_IMPACT1 + +Random( 3 )), RATE_11025, SoundVolume( MIDVOLUME, this->sGridNo ), 1, SoundDir( this->sGridNo ) );
(*pObj)[0]->data.objectStatus -= sDamage;
// if shield should have been destroyed, do so
if ( (*pObj)[0]->data.objectStatus < 1 )
{
DestroyEquippedRiotShield( );
}
}
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
INT8 bBandaged; //,savedOurTurn;
+6
View File
@@ -1943,6 +1943,12 @@ public:
// Flugente: interactive actions
UINT16 GetInteractiveActionSkill( INT32 sGridNo, UINT8 usLevel, UINT16 usType );
// Flugente: riot shields
OBJECTTYPE* GetEquippedRiotShield();
BOOLEAN IsRiotShieldEquipped();
void DestroyEquippedRiotShield();
void RiotShieldTakeDamage(INT32 sDamage);
//////////////////////////////////////////////////////////////////////////////
}; // SOLDIERTYPE;