mirror of
https://github.com/1dot13/source.git
synced 2026-08-19 14:20:30 +02:00
New feature: Covert ops
- you can disguise members of your team as civilians or soldiers and, if careful, avoid detection by the enemy. - For more info, see http://www.bears-pit.com/board/ubbthreads.php/topics/309312/New_feature_Covert_operations.html#Post309312 - GameDir revision >= 1529 is needed for this feature - fixed a bug that could cause inventory items to be treated like armed bombs - bloodcats can now be skinned git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5529 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
@@ -387,67 +387,65 @@ void HandleEndTurnDrugAdjustments( SOLDIERTYPE *pSoldier )
|
||||
}
|
||||
|
||||
// Flugente: always do the following checks. Thereby, if the effect runs out, our stats will be back to normal
|
||||
// only do the checks for the player team, as soldiers do not have a gMercProfiles
|
||||
if ( pSoldier->bTeam == gbPlayerNum)
|
||||
//////////////// STRENGTH ////////////////
|
||||
pSoldier->bExtraStrength = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_STRENGTH ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_STRENGTH ];
|
||||
|
||||
//////////////// DEXTERITY ////////////////
|
||||
pSoldier->bExtraDexterity = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_DEXTERITY ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_DEXTERITY ];
|
||||
|
||||
//////////////// AGILITY ////////////////
|
||||
pSoldier->bExtraAgility = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_AGILITY ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_AGILITY ];
|
||||
|
||||
//////////////// WISDOM ////////////////
|
||||
pSoldier->bExtraWisdom = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_WISDOM ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_WISDOM ];
|
||||
|
||||
// if our sideeffect count is 1 (which should occur a while AFTER we took the drug), we suddenly become blind for a few turns...
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_BLIND ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_BLIND ] == 1 )
|
||||
{
|
||||
//////////////// STRENGTH ////////////////
|
||||
pSoldier->bExtraStrength = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_STRENGTH ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_STRENGTH ];
|
||||
pSoldier->bBlindedCounter = 3;
|
||||
}
|
||||
|
||||
//////////////// DEXTERITY ////////////////
|
||||
pSoldier->bExtraDexterity = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_DEXTERITY ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_DEXTERITY ];
|
||||
// if our sideeffect count is 1 (which should occur a while AFTER we took the drug), we get a heart-attack and get knocked out...
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_KNOCKOUT ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_KNOCKOUT ] == 1 )
|
||||
{
|
||||
// Keel over...
|
||||
DeductPoints( pSoldier, 0, 20000 );
|
||||
}
|
||||
|
||||
//////////////// AGILITY ////////////////
|
||||
pSoldier->bExtraAgility = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_AGILITY ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_AGILITY ];
|
||||
// if we have a life damaging effect, deduct life points
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_LIFEDAMAGE ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_LIFEDAMAGE ] > 0 )
|
||||
{
|
||||
pSoldier->EVENT_SoldierGotHit( 0, 400, 0, pSoldier->ubDirection, 320, NOBODY , FIRE_WEAPON_NO_SPECIAL, pSoldier->bAimShotLocation, 0, -1 );
|
||||
|
||||
//////////////// WISDOM ////////////////
|
||||
pSoldier->bExtraWisdom = pSoldier->drugs.bDrugEffect[ DRUG_TYPE_WISDOM ] - pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_WISDOM ];
|
||||
|
||||
// if our sideeffect count is 1 (which should occur a while AFTER we took the drug), we suddenly become blind for a few turns...
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_BLIND ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_BLIND ] == 1 )
|
||||
/*if ( pSoldier->stats.bLife > OKLIFE )
|
||||
{
|
||||
pSoldier->bBlindedCounter = 3;
|
||||
}
|
||||
|
||||
// if our sideeffect count is 1 (which should occur a while AFTER we took the drug), we get a heart-attack and get knocked out...
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_KNOCKOUT ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_KNOCKOUT ] == 1 )
|
||||
{
|
||||
// Keel over...
|
||||
DeductPoints( pSoldier, 0, 20000 );
|
||||
}
|
||||
|
||||
// if we have a life damaging effect, deduct life points
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_LIFEDAMAGE ] == 0 && pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_LIFEDAMAGE ] > 0 )
|
||||
{
|
||||
if ( pSoldier->stats.bLife > OKLIFE )
|
||||
{
|
||||
INT8 lifepointdamage = pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_LIFEDAMAGE ];
|
||||
INT8 lifepointdamage = pSoldier->drugs.bDrugSideEffect[ DRUG_TYPE_LIFEDAMAGE ];
|
||||
|
||||
INT8 applieddamage = pSoldier->stats.bLife;
|
||||
INT8 applieddamage = pSoldier->stats.bLife;
|
||||
|
||||
pSoldier->stats.bLife = max(OKLIFE - 1, pSoldier->stats.bLife - lifepointdamage);
|
||||
pSoldier->stats.bLife = max(OKLIFE - 8, pSoldier->stats.bLife - lifepointdamage);
|
||||
|
||||
applieddamage -= pSoldier->stats.bLife;
|
||||
applieddamage -= pSoldier->stats.bLife;
|
||||
|
||||
pSoldier->iHealableInjury += (applieddamage * 100);
|
||||
}
|
||||
}
|
||||
pSoldier->iHealableInjury += (applieddamage * 100);
|
||||
}*/
|
||||
}
|
||||
|
||||
// if we took an antidote, reduce poisoning
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_CUREPOISON ] > 0 )
|
||||
// if we took an antidote, reduce poisoning
|
||||
if ( pSoldier->drugs.bDrugEffect[ DRUG_TYPE_CUREPOISON ] > 0 )
|
||||
{
|
||||
if ( pSoldier->bPoisonSum > 0 )
|
||||
{
|
||||
if ( pSoldier->bPoisonSum > 0 )
|
||||
if ( pSoldier->bPoisonBleeding > 0 )
|
||||
{
|
||||
if ( pSoldier->bPoisonBleeding > 0 )
|
||||
{
|
||||
pSoldier->bPoisonBleeding--;
|
||||
}
|
||||
else if ( pSoldier->bPoisonLife > 0 )
|
||||
{
|
||||
pSoldier->bPoisonLife--;
|
||||
}
|
||||
|
||||
pSoldier->bPoisonSum--;
|
||||
pSoldier->bPoisonBleeding--;
|
||||
}
|
||||
else if ( pSoldier->bPoisonLife > 0 )
|
||||
{
|
||||
pSoldier->bPoisonLife--;
|
||||
}
|
||||
|
||||
pSoldier->bPoisonSum--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2318,6 +2318,13 @@ void HandleRenderFaceAdjustments( FACETYPE *pFace, BOOLEAN fDisplayBuffer, BOOLE
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: add an icon if we are currently in disguise
|
||||
if ( MercPtrs[ pFace->ubSoldierID ]->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
|
||||
{
|
||||
DoRightIcon( uiRenderBuffer, pFace, sFaceX, sFaceY, bNumRightIcons, 22 );
|
||||
bNumRightIcons++;
|
||||
}
|
||||
|
||||
switch( pSoldier->bAssignment )
|
||||
{
|
||||
case DOCTOR:
|
||||
|
||||
@@ -101,6 +101,7 @@ static INT8 bTempFrequency;
|
||||
|
||||
void BombMessageBoxCallBack( UINT8 ubExitValue );
|
||||
void TacticalFunctionSelectionMessageBoxCallBack( UINT8 ubExitValue ); // Flugente: callback after deciding what tactical function to use
|
||||
void CorpseMessageBoxCallBack( UINT8 ubExitValue ); // Flugente: callback after deciding what to do with a corpse
|
||||
void BoobyTrapMessageBoxCallBack( UINT8 ubExitValue );
|
||||
void SwitchMessageBoxCallBack( UINT8 ubExitValue );
|
||||
void BoobyTrapDialogueCallBack( void );
|
||||
@@ -133,6 +134,8 @@ void StartBombMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo );
|
||||
void StartTacticalFunctionSelectionMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel ); // added by Flugente
|
||||
void CleanWeapons();
|
||||
|
||||
void StartCorpseMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel ); // added by Flugente
|
||||
|
||||
BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel )
|
||||
{
|
||||
BOOLEAN fBadChangeToGetThrough = FALSE;
|
||||
@@ -1647,6 +1650,11 @@ void HandleTacticalFunctionSelection( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||
}
|
||||
|
||||
|
||||
void HandleSoldierUseCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
StartCorpseMessageBox( pSoldier, sGridNo, bLevel );
|
||||
}
|
||||
|
||||
void SoldierHandleDropItem( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
// LOOK IN PANDING DATA FOR ITEM TO DROP, AND LOCATION
|
||||
@@ -2441,6 +2449,12 @@ OBJECTTYPE* InternalAddItemToPool( INT32 *psGridNo, OBJECTTYPE *pObject, INT8 bV
|
||||
bRenderZHeightAboveLevel = 0;
|
||||
}
|
||||
|
||||
// Flugente: if this item is a corpse, don't add it to the world. Instead spawn a corpse in its position
|
||||
if ( HasItemFlag(pObject->usItem, CORPSE) && AddCorpseFromObject(pObject, *psGridNo, ubLevel ) )
|
||||
{
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
//CHRISL: We need to make sure that item stacks follow the OldInv stacking limits
|
||||
// Copy the object we're working with the gTempObject so that we can use pObject later in this function
|
||||
OBJECTTYPE poolObject = OBJECTTYPE(*pObject);
|
||||
@@ -4418,6 +4432,19 @@ INT32 AdjustGridNoForItemPlacement( SOLDIERTYPE *pSoldier, INT32 sGridNo )
|
||||
return( sActionGridNo );
|
||||
}
|
||||
|
||||
// Flugente
|
||||
void StartCorpseMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
gpTempSoldier = pSoldier;
|
||||
|
||||
// determine what is possible with this corpse
|
||||
BOOLEAN fDecapitate = TRUE;
|
||||
BOOLEAN fTakeClothes = TRUE;
|
||||
BOOLEAN fTakeCorpse = TRUE;
|
||||
|
||||
if ( fDecapitate && fTakeClothes )
|
||||
DoMessageBox( MSG_BOX_BASIC_SMALL_BUTTONS, TacticalStr[ CORPSE_SELECTION_STR ], GAME_SCREEN, MSG_BOX_FLAG_FOUR_NUMBERED_BUTTONS, CorpseMessageBoxCallBack, NULL );
|
||||
}
|
||||
|
||||
void StartBombMessageBox( SOLDIERTYPE * pSoldier, INT32 sGridNo )
|
||||
{
|
||||
@@ -4667,6 +4694,36 @@ void TacticalFunctionSelectionMessageBoxCallBack( UINT8 ubExitValue )
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: callback after deciding what to do with a corpse
|
||||
void CorpseMessageBoxCallBack( UINT8 ubExitValue )
|
||||
{
|
||||
if (gpTempSoldier)
|
||||
{
|
||||
INT32 nextGridNoinSight = gpTempSoldier->sGridNo;
|
||||
nextGridNoinSight = NewGridNo( nextGridNoinSight, DirectionInc( gpTempSoldier->ubDirection ) );
|
||||
|
||||
INT8 level = gpTempSoldier->bTargetLevel;
|
||||
|
||||
switch (ubExitValue)
|
||||
{
|
||||
case 1:
|
||||
DecapitateCorpse( gpTempSoldier, nextGridNoinSight, level );
|
||||
break;
|
||||
case 2:
|
||||
GutCorpse( gpTempSoldier, nextGridNoinSight, level );
|
||||
break;
|
||||
case 3:
|
||||
StripCorpse( gpTempSoldier, nextGridNoinSight, level );
|
||||
break;
|
||||
case 4:
|
||||
TakeCorpse( gpTempSoldier, nextGridNoinSight, level );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN HandItemWorks( SOLDIERTYPE *pSoldier, INT8 bSlot )
|
||||
{
|
||||
BOOLEAN fItemJustBroke = FALSE, fItemWorks = TRUE;
|
||||
|
||||
@@ -135,6 +135,8 @@ void HandleSoldierUseRemote( SOLDIERTYPE *pSoldier, INT32 sGridNo );
|
||||
|
||||
void HandleTacticalFunctionSelection( SOLDIERTYPE *pSoldier, INT32 sGridNo ); // Flugente: in tactical, open a selection box for different actions
|
||||
|
||||
void HandleSoldierUseCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel ); // Flugente: handle corpses
|
||||
|
||||
BOOLEAN ItemPoolOKForDisplay( ITEM_POOL *pItemPool, INT8 bZLevel );
|
||||
INT16 GetNumOkForDisplayItemsInPool( ITEM_POOL *pItemPool, INT8 bZLevel );
|
||||
|
||||
|
||||
@@ -2523,7 +2523,16 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
|
||||
SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr );
|
||||
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] );
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////// COVERT ITEM
|
||||
if ( HasItemFlag(gpItemDescObject->usItem, COVERT) )
|
||||
{
|
||||
swprintf( pStr, L"%s%s", szUDBGenSecondaryStatsTooltipText[ 31 ], szUDBGenSecondaryStatsExplanationsTooltipText[ 31 ]);
|
||||
SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + cnt ]), pStr );
|
||||
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + cnt ] );
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
@@ -5532,7 +5541,14 @@ void DrawSecondaryStats( OBJECTTYPE * gpItemDescObject )
|
||||
{
|
||||
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 11, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////// COVERT ITEM
|
||||
if ( HasItemFlag(gpItemDescObject->usItem, COVERT) )
|
||||
{
|
||||
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoSecondaryIcon, 30, gItemDescGenSecondaryRegions[cnt].sLeft+sOffsetX, gItemDescGenSecondaryRegions[cnt].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawWeaponValues( OBJECTTYPE * gpItemDescObject )
|
||||
@@ -8938,8 +8954,9 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
|
||||
// Print Values
|
||||
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
|
||||
{
|
||||
if (UsingNewCTHSystem() == false && cnt2 > 0)
|
||||
break;
|
||||
// Flugente: no idea why we would want to skip this in OCTH, commenting this out
|
||||
//if (UsingNewCTHSystem() == false && cnt2 > 0)
|
||||
//break;
|
||||
SetFontForeground( 5 );
|
||||
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
|
||||
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
|
||||
|
||||
@@ -13148,11 +13148,11 @@ void BombInventoryMessageBoxCallBack( UINT8 ubExitValue )
|
||||
if ( gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( gpItemDescSoldier, DEMOLITIONS_NT ))
|
||||
{
|
||||
// increase trap level for Demolitions trait
|
||||
gpItemDescSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( max( 10, (8 + gSkillTraitValues.ubDEPlacedBombLevelBonus)), (( EffectiveExplosive( gpItemDescSoldier ) / 20) + (EffectiveExpLevel( gpItemDescSoldier ) / 3) + gSkillTraitValues.ubDEPlacedBombLevelBonus) );
|
||||
(*gpItemDescObject)[0]->data.bTrap = __min( max( 10, (8 + gSkillTraitValues.ubDEPlacedBombLevelBonus)), (( EffectiveExplosive( gpItemDescSoldier ) / 20) + (EffectiveExpLevel( gpItemDescSoldier ) / 3) + gSkillTraitValues.ubDEPlacedBombLevelBonus) );
|
||||
}
|
||||
else
|
||||
{
|
||||
gpItemDescSoldier->inv[ HANDPOS ][0]->data.bTrap = __min( 10, ( EffectiveExplosive( gpItemDescSoldier ) / 20) + (EffectiveExpLevel( gpItemDescSoldier ) / 3) );
|
||||
(*gpItemDescObject)[0]->data.bTrap = __min( 10, ( EffectiveExplosive( gpItemDescSoldier ) / 20) + (EffectiveExpLevel( gpItemDescSoldier ) / 3) );
|
||||
}
|
||||
|
||||
// Flugente: We armed a bomb in our inventory. We will NOT add it to the item pool and the world bombs.
|
||||
@@ -13164,8 +13164,8 @@ void BombInventoryMessageBoxCallBack( UINT8 ubExitValue )
|
||||
// so we add 2 to all owner IDs passed through here and subtract 2 later
|
||||
//if (gpItemDescSoldier->inv[HANDPOS].MoveThisObjectTo(gTempObject, 1) == 0)
|
||||
{
|
||||
gTempObject[0]->data.misc.ubBombOwner = gpItemDescSoldier->ubID + 2;
|
||||
gTempObject[0]->data.ubDirection = gpItemDescSoldier->ubDirection; // Flugente: direction of bomb is direction of soldier
|
||||
(*gpItemDescObject)[0]->data.misc.ubBombOwner = gpItemDescSoldier->ubID + 2;
|
||||
(*gpItemDescObject)[0]->data.ubDirection = gpItemDescSoldier->ubDirection; // Flugente: direction of bomb is direction of soldier
|
||||
|
||||
//AddItemToPool( gsTempGridNo, &gTempObject, VISIBLE, gpItemDescSoldier->pathing.bLevel, WORLD_ITEM_ARMED_BOMB, 0 );
|
||||
}
|
||||
|
||||
@@ -3357,6 +3357,21 @@ void SMInvClickCamoCallback( MOUSE_REGION * pRegion, INT32 iReason )
|
||||
// Say OK acknowledge....
|
||||
gpSMCurrentMerc->DoMercBattleSound( BATTLE_SOUND_COOL1 );
|
||||
}
|
||||
else if ( ApplySpyKit( gpSMCurrentMerc, gpItemPointer ) )
|
||||
{
|
||||
// Dirty
|
||||
fInterfacePanelDirty = DIRTYLEVEL2;
|
||||
|
||||
// Check if it's the same now!
|
||||
if ( gpItemPointer->exists() == false )
|
||||
{
|
||||
gbCompatibleApplyItem = FALSE;
|
||||
EndItemPointer( );
|
||||
}
|
||||
|
||||
// Say OK acknowledge....
|
||||
gpSMCurrentMerc->DoMercBattleSound( BATTLE_SOUND_COOL1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send message
|
||||
|
||||
+53
-6
@@ -734,13 +734,13 @@ extern OBJECTTYPE gTempObject;
|
||||
#define CAMO_REMOVAL 0x00000400 //1024 // item can be used to remove camo
|
||||
#define CLEANING_KIT 0x00000800 //2048 // weapon cleaning kit
|
||||
|
||||
/*#define ENEMY_NET_1_LVL_4 0x00001000 //4096
|
||||
#define ENEMY_NET_2_LVL_4 0x00002000 //8192
|
||||
#define ENEMY_NET_3_LVL_4 0x00004000 //16384
|
||||
#define ENEMY_NET_4_LVL_4 0x00008000 //32768
|
||||
#define CLOTHES_CIVILIAN 0x00001000 //4096 // with this item you can disguise as a civilian
|
||||
#define GAROTTE 0x00002000 //8192 // this item is a garotte
|
||||
#define COVERT 0x00004000 //16384 // if LBE, any gun inside will be covert. On a gun, it will covert in any LBE, even if the LBE does not have that tag itself
|
||||
#define CORPSE 0x00008000 //32768 // a dead body
|
||||
|
||||
#define PLAYER_NET_1_LVL_1 0x00010000 //65536
|
||||
#define PLAYER_NET_2_LVL_1 0x00020000 //131072
|
||||
#define SKIN_BLOODCAT 0x00010000 //65536 // retrieve this by skinning (=decapitating) a bloodcat
|
||||
/*#define PLAYER_NET_2_LVL_1 0x00020000 //131072
|
||||
#define PLAYER_NET_3_LVL_1 0x00040000 //262144
|
||||
#define PLAYER_NET_4_LVL_1 0x00080000 //524288
|
||||
|
||||
@@ -760,6 +760,49 @@ extern OBJECTTYPE gTempObject;
|
||||
#define PLAYER_NET_4_LVL_4 0x80000000 //2147483648*/
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// -------- added by Flugente: flags for objects --------
|
||||
// the numbering of these flags is important. DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
|
||||
#define CORPSE_M_SMALL 0x00000001 //1
|
||||
#define CORPSE_M_BIG 0x00000002 //2
|
||||
#define CORPSE_F 0x00000004 //4
|
||||
#define CORPSE_NO_HEAD 0x00000008 //8
|
||||
|
||||
#define CORPSE_HAIR_BROWN 0x00000010 //16
|
||||
#define CORPSE_HAIR_BLACK 0x00000020 //32
|
||||
#define CORPSE_HAIR_WHITE 0x00000040 //64
|
||||
#define CORPSE_HAIR_BLOND 0x00000080 //128
|
||||
|
||||
#define CORPSE_HAIR_RED 0x00000100 //256
|
||||
#define CORPSE_SKIN_PINK 0x00000200 //512
|
||||
#define CORPSE_SKIN_TAN 0x00000400 //1024
|
||||
#define CORPSE_SKIN_DARK 0x00000800 //2048
|
||||
|
||||
#define CORPSE_SKIN_BLACK 0x00001000 //4096
|
||||
#define CORPSE_VEST_BROWN 0x00002000 //8192
|
||||
#define CORPSE_VEST_grey 0x00004000 //16384
|
||||
#define CORPSE_VEST_GREEN 0x00008000 //32768
|
||||
|
||||
#define CORPSE_VEST_JEAN 0x00010000 //65536
|
||||
#define CORPSE_VEST_RED 0x00020000 //131072
|
||||
#define CORPSE_VEST_BLUE 0x00040000 //262144
|
||||
#define CORPSE_VEST_YELLOW 0x00080000 //524288
|
||||
|
||||
#define CORPSE_VEST_WHITE 0x00100000 //1048576
|
||||
#define CORPSE_VEST_BLACK 0x00200000 //2097152
|
||||
#define CORPSE_VEST_GYELLOW 0x00400000 //4194304
|
||||
#define CORPSE_VEST_PURPLE 0x00800000 //8388608
|
||||
|
||||
#define CORPSE_PANTS_GREEN 0x01000000 //16777216
|
||||
#define CORPSE_PANTS_JEAN 0x02000000 //33554432
|
||||
#define CORPSE_PANTS_TAN 0x04000000 //67108864
|
||||
#define CORPSE_PANTS_BLACK 0x08000000 //134217728
|
||||
|
||||
#define CORPSE_PANTS_BLUE 0x10000000 //268435456
|
||||
#define CORPSE_PANTS_BEIGE 0x20000000 //536870912
|
||||
#define CORPSE_STRIPPED 0x40000000 //1073741824
|
||||
//#define unused 0x80000000 //2147483648*/
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
// replaces candamage
|
||||
//#define ITEM_DAMAGEABLE 0x0001
|
||||
//// replaces canrepair
|
||||
@@ -1703,6 +1746,10 @@ enum
|
||||
IMP_TEACHING_EXP,
|
||||
IMP_LOCKPICKING_EXP,
|
||||
|
||||
// Flugente: added covert ops
|
||||
IMP_COVERT,
|
||||
IMP_COVERT_EXP,
|
||||
|
||||
MAX_IMP_ITEM_TYPES
|
||||
};
|
||||
|
||||
|
||||
@@ -9144,6 +9144,23 @@ BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAP
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
// Flugente: apply disguise
|
||||
BOOLEAN ApplySpyKit( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj)
|
||||
{
|
||||
if (pObj->exists() == false || !HasItemFlag(pObj->usItem, (CLOTHES_CIVILIAN)) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// we get the civilian disguise. AP costs will be checked and deducted here
|
||||
if ( !pSoldier->DisguiseAsCivilian() )
|
||||
return FALSE;
|
||||
|
||||
UseKitPoints( pObj, 100, pSoldier );
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
BOOLEAN ApplyCanteen( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs )
|
||||
{
|
||||
INT16 sPointsToUse;
|
||||
|
||||
@@ -196,6 +196,7 @@ void WaterDamage( SOLDIERTYPE *pSoldier );
|
||||
INT8 FindObj( SOLDIERTYPE * pSoldier, UINT16 usItem, INT8 bLower = 0, INT8 bUpper = NUM_INV_SLOTS );
|
||||
|
||||
BOOLEAN ApplyCammo( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs );
|
||||
BOOLEAN ApplySpyKit( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj); // Flugente: apply disguise
|
||||
|
||||
UINT32 ConvertProfileMoneyValueToObjectTypeMoneyValue( UINT8 ubStatus );
|
||||
UINT8 ConvertObjectTypeMoneyValueToProfileMoneyValue( UINT32 uiMoneyAmount );
|
||||
@@ -484,6 +485,7 @@ typedef struct
|
||||
{
|
||||
UINT8 usWaterType; // type of water source in this sector
|
||||
UINT16 usNaturalDirt; // extra dirt percentage when firing in this sector
|
||||
UINT8 usCurfewValue; // determines wether mercs disguising as civilian are automatically discovered (certain sectors are 'restricted' to civilians)
|
||||
} SECTOR_EXT_DATA;
|
||||
|
||||
// get dirt increase for object with attachments, fConsiderAmmo: with ammo
|
||||
|
||||
@@ -6104,11 +6104,11 @@ void EnterCombatMode( UINT8 ubStartingTeam )
|
||||
|
||||
if (!is_client || is_server) //hayden
|
||||
{
|
||||
StartPlayerTeamTurn( FALSE, TRUE );
|
||||
StartPlayerTeamTurn( FALSE, TRUE );
|
||||
if(is_client)send_EndTurn( ubStartingTeam ); //hayden
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
//ScreenMsg( FONT_YELLOW, MSG_CHAT, L"client skipped EnterCombatMode");
|
||||
if(is_client)startCombat(ubStartingTeam);//clients other than server meet and send request for combat for server
|
||||
}
|
||||
|
||||
+518
-31
@@ -275,8 +275,8 @@ BOOLEAN gbCorpseValidForDecapitation[ NUM_CORPSES ] =
|
||||
1,
|
||||
1,
|
||||
1,
|
||||
1, // Bloodcat - changed to 1 to allow gutting
|
||||
1, // Cow - changed to 1 to allow gutting
|
||||
1, // Bloodcat - changed to 1 to allow skinning (works like decapitating)
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@@ -495,6 +495,9 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
|
||||
// Copy elements in
|
||||
memcpy( pCorpse, pCorpseDef, sizeof( ROTTING_CORPSE_DEFINITION ) );
|
||||
|
||||
if ( pCorpseDef->fHeadTaken )
|
||||
pCorpse->def.usFlags |= ROTTING_CORPSE_HEAD_TAKEN;
|
||||
|
||||
uiDirectionUseFlag = ANITILE_USE_DIRECTION_FOR_START_FRAME;
|
||||
|
||||
// If we are a soecial type...
|
||||
@@ -818,7 +821,7 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
|
||||
// Setup some values!
|
||||
memset( &Corpse, 0, sizeof( Corpse ) );
|
||||
Corpse.ubBodyType = pSoldier->ubBodyType;
|
||||
Corpse.sGridNo = pSoldier->sGridNo;
|
||||
Corpse.sGridNo = pSoldier->sGridNo;
|
||||
Corpse.dXPos = pSoldier->dXPos;
|
||||
Corpse.dYPos = pSoldier->dYPos;
|
||||
Corpse.bLevel = pSoldier->pathing.bLevel;
|
||||
@@ -895,6 +898,18 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
|
||||
Corpse.name[9] = '\0';
|
||||
#endif
|
||||
|
||||
// Flugente: mark if this was an army soldier ( we use this to steal his clothes later on )
|
||||
if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR )
|
||||
Corpse.usFlags |= ROTTING_CORPSE_FROM_ADMIN;
|
||||
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY )
|
||||
Corpse.usFlags |= ROTTING_CORPSE_FROM_TROOP;
|
||||
else if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE )
|
||||
Corpse.usFlags |= ROTTING_CORPSE_FROM_ELITE;
|
||||
|
||||
// if this soldier's uniform was damaged (gunfire, blade attacks, explosions) then don't allow to take the uniform. We can't stay hidden if we're covered in blood :-)
|
||||
if ( pSoldier->bSoldierFlagMask &SOLDIER_DAMAGED_UNIFORM )
|
||||
Corpse.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
|
||||
|
||||
// Determine corpse type!
|
||||
ubType = (UINT8)gubAnimSurfaceCorpseID[ pSoldier->ubBodyType][ pSoldier->usAnimState ];
|
||||
|
||||
@@ -1763,7 +1778,7 @@ INT32 FindNearestAvailableGridNoForCorpse( ROTTING_CORPSE_DEFINITION *pDef, INT8
|
||||
|
||||
BOOLEAN IsValidDecapitationCorpse( ROTTING_CORPSE *pCorpse )
|
||||
{
|
||||
if ( (pCorpse->def.usFlags & ROTTING_CORPSE_GUTTED) )
|
||||
if ( (pCorpse->def.usFlags & ROTTING_CORPSE_HEAD_TAKEN) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
@@ -1797,14 +1812,12 @@ ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo, INT8 bLevel )
|
||||
}
|
||||
|
||||
|
||||
void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
ROTTING_CORPSE *pCorpse;
|
||||
ROTTING_CORPSE_DEFINITION CorpseDef;
|
||||
UINT16 usHeadIndex = HEAD_1;
|
||||
static UINT16 usBloodCatMeatIndex = 1566;
|
||||
static UINT16 usCowMeatIndex = 1565;
|
||||
|
||||
static UINT16 usBloodCatSkinIndex = 232;
|
||||
|
||||
pCorpse = GetCorpseAtGridNo( sGridNo, bLevel );
|
||||
|
||||
@@ -1812,41 +1825,30 @@ void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( IsValidDecapitationCorpse( pCorpse ) )
|
||||
{
|
||||
// Decapitate.....
|
||||
// Copy corpse definition...
|
||||
memcpy( &CorpseDef, &(pCorpse->def), sizeof( ROTTING_CORPSE_DEFINITION ) );
|
||||
|
||||
// Flugente: if the corpse is of a cow or a bloodcat, we don't take its head, we simply gut it and give meat instead of a head
|
||||
if ( CorpseDef.ubType == BLOODCAT_DEAD || CorpseDef.ubType == COW_DEAD )
|
||||
{
|
||||
pCorpse->def.usFlags |= (ROTTING_CORPSE_HEAD_TAKEN|ROTTING_CORPSE_GUTTED);
|
||||
|
||||
if ( CorpseDef.ubType == BLOODCAT_DEAD )
|
||||
{
|
||||
if ( HasItemFlag(usBloodCatMeatIndex, MEAT_BLOODCAT) || GetFirstItemWithFlag(&usBloodCatMeatIndex, MEAT_BLOODCAT) )
|
||||
usHeadIndex = usBloodCatMeatIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( HasItemFlag(usCowMeatIndex, COW_MEAT) || GetFirstItemWithFlag(&usCowMeatIndex, COW_MEAT) )
|
||||
usHeadIndex = usCowMeatIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add new one...
|
||||
CorpseDef.ubType = gDecapitatedCorpse[ CorpseDef.ubType ];
|
||||
|
||||
pCorpse->def.usFlags |= (ROTTING_CORPSE_HEAD_TAKEN|ROTTING_CORPSE_GUTTED);
|
||||
|
||||
|
||||
pCorpse->def.usFlags |= ROTTING_CORPSE_HEAD_TAKEN;
|
||||
CorpseDef.fHeadTaken = TRUE;
|
||||
|
||||
if ( CorpseDef.ubType != 0 )
|
||||
{
|
||||
// Remove old one...
|
||||
RemoveCorpse( pCorpse->iID );
|
||||
|
||||
AddRottingCorpse( &CorpseDef );
|
||||
INT32 iCorpseID = AddRottingCorpse( &CorpseDef );
|
||||
|
||||
if ( iCorpseID != -1 )
|
||||
{
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_HEAD_TAKEN;
|
||||
}
|
||||
}
|
||||
|
||||
// Add head item.....
|
||||
@@ -1880,6 +1882,12 @@ void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
|
||||
}
|
||||
|
||||
if ( pCorpse->def.ubType == BLOODCAT_DEAD )
|
||||
{
|
||||
if ( HasItemFlag(usBloodCatSkinIndex, SKIN_BLOODCAT) || GetFirstItemWithFlag(&usBloodCatSkinIndex, SKIN_BLOODCAT) )
|
||||
usHeadIndex = usBloodCatSkinIndex;
|
||||
}
|
||||
|
||||
if ( usHeadIndex > 0 )
|
||||
{
|
||||
CreateItem( usHeadIndex, 100, &gTempObject );
|
||||
@@ -1889,7 +1897,404 @@ void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
NotifySoldiersToLookforItems( );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: can this corpse be gutted?
|
||||
BOOLEAN IsValidGutCorpse( ROTTING_CORPSE *pCorpse )
|
||||
{
|
||||
if ( pCorpse->def.ubType == ROTTING_STAGE2 || (pCorpse->def.usFlags & ROTTING_CORPSE_GUTTED) )
|
||||
return( FALSE );
|
||||
|
||||
return( pCorpse->def.ubType == BLOODCAT_DEAD || pCorpse->def.ubType == COW_DEAD );
|
||||
}
|
||||
|
||||
// Flugente: gut a corpse
|
||||
void GutCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
ROTTING_CORPSE *pCorpse = GetCorpseAtGridNo( sGridNo, bLevel );
|
||||
|
||||
if ( pCorpse == NULL )
|
||||
return;
|
||||
|
||||
// can this thing be gutted?
|
||||
if ( IsValidGutCorpse( pCorpse ) )
|
||||
{
|
||||
// numbers for the meat acquired by gutting. These values respond to the standard GameDir values, if they have other values in the ini, no problem, we'll search for them
|
||||
static UINT16 usBloodCatMeatIndex = 1566;
|
||||
static UINT16 usCowMeatIndex = 1565;
|
||||
UINT16 meatindex = 0;
|
||||
|
||||
pCorpse->def.usFlags |= ROTTING_CORPSE_GUTTED;
|
||||
|
||||
if ( pCorpse->def.ubType == BLOODCAT_DEAD )
|
||||
{
|
||||
if ( HasItemFlag(usBloodCatMeatIndex, MEAT_BLOODCAT) || GetFirstItemWithFlag(&usBloodCatMeatIndex, MEAT_BLOODCAT) )
|
||||
meatindex = usBloodCatMeatIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( HasItemFlag(usCowMeatIndex, COW_MEAT) || GetFirstItemWithFlag(&usCowMeatIndex, COW_MEAT) )
|
||||
meatindex = usCowMeatIndex;
|
||||
}
|
||||
|
||||
if ( meatindex > 0 )
|
||||
{
|
||||
CreateItem( meatindex, 100, &gTempObject );
|
||||
AddItemToPool( sGridNo, &gTempObject, INVISIBLE, 0, 0, 0 );
|
||||
|
||||
// All teams lok for this...
|
||||
NotifySoldiersToLookforItems( );
|
||||
}
|
||||
}
|
||||
else
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"Not possible, you sick, sick individual!" );
|
||||
}
|
||||
|
||||
// Flugente: can clothes be taken off of this corpse?
|
||||
BOOLEAN IsValidStripCorpse( ROTTING_CORPSE *pCorpse )
|
||||
{
|
||||
if ( pCorpse->def.ubType == ROTTING_STAGE2 || (pCorpse->def.usFlags & ROTTING_CORPSE_CLOTHES_TAKEN) )
|
||||
return( FALSE );
|
||||
|
||||
// is there a uniform we can take?
|
||||
if ( !(pCorpse->def.usFlags & (ROTTING_CORPSE_FROM_ADMIN|ROTTING_CORPSE_FROM_TROOP|ROTTING_CORPSE_FROM_ELITE)) )
|
||||
return( FALSE );
|
||||
|
||||
return( CorpseOkToDress(pCorpse, NULL) );
|
||||
}
|
||||
|
||||
|
||||
// Flugente: take the clothes off a corpse and wear them
|
||||
void StripCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
ROTTING_CORPSE *pCorpse = GetCorpseAtGridNo( sGridNo, bLevel );
|
||||
|
||||
if ( pCorpse == NULL )
|
||||
return;
|
||||
|
||||
// can this thing be stripped?
|
||||
if ( IsValidStripCorpse( pCorpse ) )
|
||||
{
|
||||
// if this fits our body, try to wear it
|
||||
if ( CorpseOkToDress(pCorpse, pSoldier) && pSoldier->DisguiseAsSoldierFromCorpse( pCorpse->def.usFlags ) )
|
||||
{
|
||||
// we took the clothes, mark this
|
||||
pCorpse->def.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
|
||||
}
|
||||
}
|
||||
else
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"No clothes to take!" );
|
||||
}
|
||||
|
||||
// Flugente: can clothes be taken off of this corpse?
|
||||
BOOLEAN IsValidTakeCorpse( ROTTING_CORPSE *pCorpse )
|
||||
{
|
||||
if ( pCorpse->def.ubType >= BLOODCAT_DEAD || pCorpse->def.ubType == NO_CORPSE )
|
||||
return( FALSE );
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
// Flugente: take a corpse into your hand, thereby removing it from the field
|
||||
void TakeCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
ROTTING_CORPSE *pCorpse = GetCorpseAtGridNo( sGridNo, bLevel );
|
||||
|
||||
if ( pCorpse == NULL )
|
||||
return;
|
||||
|
||||
// can this corpse be picked up?
|
||||
if ( IsValidTakeCorpse( pCorpse ) )
|
||||
{
|
||||
// is there a 'corpse' item?
|
||||
UINT16 corpseitem = 0;
|
||||
if ( GetFirstItemWithFlag(&corpseitem, CORPSE) )
|
||||
{
|
||||
// we have to make sure this can be placed in our hands, as corpses can only be carried in hands.
|
||||
// At this point, we will have a knife in our first hand, so check if our second hand is free
|
||||
if ( !(pSoldier->inv[SECONDHANDPOS].exists()) )
|
||||
{
|
||||
CreateItem( corpseitem, 100, &gTempObject );
|
||||
|
||||
if(CanItemFitInPosition(pSoldier, &gTempObject, SECONDHANDPOS, FALSE))
|
||||
{
|
||||
// determine Body type
|
||||
if ( pCorpse->def.ubBodyType == BIGMALE || pCorpse->def.ubBodyType == STOCKYMALE || pCorpse->def.ubBodyType == FATCIV )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_M_BIG;
|
||||
else if ( pCorpse->def.ubBodyType == REGFEMALE || pCorpse->def.ubBodyType == MINICIV || pCorpse->def.ubBodyType == DRESSCIV )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_F;
|
||||
|
||||
if ( pCorpse->def.usFlags & ROTTING_CORPSE_HEAD_TAKEN )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_NO_HEAD;
|
||||
|
||||
if ( pCorpse->def.usFlags & ROTTING_CORPSE_CLOTHES_TAKEN )
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_STRIPPED;
|
||||
|
||||
// now we have to get the correct flags for the object from the corpse, so that upon recreating the corpse, it looks the same
|
||||
UINT8 headpal = 0, skinpal = 0, vestpal = 0, pantspal = 0;
|
||||
GetPaletteRepIndexFromID(pCorpse->def.HeadPal, &headpal);
|
||||
GetPaletteRepIndexFromID(pCorpse->def.SkinPal, &skinpal);
|
||||
GetPaletteRepIndexFromID(pCorpse->def.VestPal, &vestpal);
|
||||
GetPaletteRepIndexFromID(pCorpse->def.PantsPal, &pantspal);
|
||||
|
||||
switch ( headpal )
|
||||
{
|
||||
case 0:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_HAIR_BLOND;
|
||||
break;
|
||||
case 1:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_HAIR_BROWN;
|
||||
break;
|
||||
case 2:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_HAIR_BLACK;
|
||||
break;
|
||||
case 3:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_HAIR_WHITE;
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_HAIR_RED;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( skinpal )
|
||||
{
|
||||
case 13:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_SKIN_PINK;
|
||||
break;
|
||||
case 14:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_SKIN_TAN;
|
||||
break;
|
||||
case 15:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_SKIN_DARK;
|
||||
break;
|
||||
case 16:
|
||||
default:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_SKIN_BLACK;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( vestpal )
|
||||
{
|
||||
case 17:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_BROWN;
|
||||
break;
|
||||
case 18:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_grey;
|
||||
break;
|
||||
case 19:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_GREEN;
|
||||
break;
|
||||
case 20:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_JEAN;
|
||||
break;
|
||||
case 21:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_RED;
|
||||
break;
|
||||
case 22:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_BLUE;
|
||||
break;
|
||||
case 23:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_YELLOW;
|
||||
break;
|
||||
case 24:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_WHITE;
|
||||
break;
|
||||
case 25:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_BLACK;
|
||||
break;
|
||||
case 26:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_GYELLOW;
|
||||
break;
|
||||
case 27:
|
||||
default:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_VEST_PURPLE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( pantspal )
|
||||
{
|
||||
case 7:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_GREEN;
|
||||
break;
|
||||
case 8:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_JEAN;
|
||||
break;
|
||||
case 9:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_TAN;
|
||||
break;
|
||||
case 10:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_BLACK;
|
||||
break;
|
||||
case 11:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_BLUE;
|
||||
break;
|
||||
case 12:
|
||||
default:
|
||||
gTempObject[0]->data.sObjectFlag |= CORPSE_PANTS_BEIGE;
|
||||
break;
|
||||
}
|
||||
|
||||
gTempObject.MoveThisObjectTo(pSoldier->inv[SECONDHANDPOS], ALL_OBJECTS, pSoldier, SECONDHANDPOS);
|
||||
|
||||
if ( pCorpse->def.ubType != 0 )
|
||||
{
|
||||
// Remove corpse...
|
||||
RemoveCorpse( pCorpse->iID );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"No free hand to carry corpse!" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: create a corpse from an object and plce it in the world
|
||||
BOOLEAN AddCorpseFromObject(OBJECTTYPE* pObj, INT32 sGridNo, INT8 bLevel )
|
||||
{
|
||||
if ( !pObj || !HasItemFlag(pObj->usItem, CORPSE) )
|
||||
return FALSE;
|
||||
|
||||
ROTTING_CORPSE_DEFINITION Corpse;
|
||||
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_M_BIG )
|
||||
{
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_NO_HEAD )
|
||||
Corpse.ubType = MMERC_JFK;
|
||||
else
|
||||
Corpse.ubType = MMERC_BCK;
|
||||
|
||||
Corpse.ubBodyType = BIGMALE;
|
||||
}
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_F )
|
||||
{
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_NO_HEAD )
|
||||
Corpse.ubType = FMERC_JFK;
|
||||
else
|
||||
Corpse.ubType = FMERC_BCK;
|
||||
|
||||
Corpse.ubBodyType = REGFEMALE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_M_SMALL )
|
||||
Corpse.ubType = SMERC_JFK;
|
||||
else
|
||||
Corpse.ubType = SMERC_BCK;
|
||||
|
||||
Corpse.ubBodyType = REGMALE;
|
||||
}
|
||||
|
||||
Corpse.sGridNo = sGridNo;
|
||||
|
||||
Corpse.dXPos = CenterX(Corpse.sGridNo);
|
||||
Corpse.dYPos = CenterY(Corpse.sGridNo);
|
||||
|
||||
Corpse.sHeightAdjustment = 0;
|
||||
|
||||
// check the objects flagmask and set the corpse palette IDs accordingly
|
||||
|
||||
// Hair
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_HAIR_BROWN )
|
||||
SET_PALETTEREP_ID( Corpse.HeadPal, "BROWNHEAD" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_HAIR_BLACK )
|
||||
SET_PALETTEREP_ID( Corpse.HeadPal, "BLACKHEAD" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_HAIR_WHITE )
|
||||
SET_PALETTEREP_ID( Corpse.HeadPal, "WHITEHEAD" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_HAIR_BLOND )
|
||||
SET_PALETTEREP_ID( Corpse.HeadPal, "BLONDHEAD" );
|
||||
else
|
||||
SET_PALETTEREP_ID( Corpse.HeadPal, "REDHEAD" );
|
||||
|
||||
// Skin
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_SKIN_PINK )
|
||||
SET_PALETTEREP_ID( Corpse.SkinPal, "PINKSKIN" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_SKIN_TAN )
|
||||
SET_PALETTEREP_ID( Corpse.SkinPal, "TANSKIN" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_SKIN_DARK )
|
||||
SET_PALETTEREP_ID( Corpse.SkinPal, "DARKSKIN" );
|
||||
else
|
||||
SET_PALETTEREP_ID( Corpse.SkinPal, "BLACKSKIN" );
|
||||
|
||||
// Vest
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_BROWN )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "BROWNVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_grey )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "greyVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_GREEN )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "GREENVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_JEAN )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "JEANVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_RED )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "REDVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_BLUE )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "BLUEVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_YELLOW )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "YELLOWVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_WHITE )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "WHITEVEST" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_BLACK )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "BLACKSHIRT" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_GYELLOW )
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "GYELLOWSHIRT" );
|
||||
else
|
||||
SET_PALETTEREP_ID( Corpse.VestPal, "PURPLESHIRT" );
|
||||
|
||||
// Pants
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_GREEN )
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "GREENPANTS" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_JEAN )
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "JEANPANTS" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_TAN )
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "TANPANTS" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_BLACK )
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "BLACKPANTS" );
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_BLUE )
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "BLUEPANTS" );
|
||||
else
|
||||
SET_PALETTEREP_ID( Corpse.PantsPal, "BEIGEPANTS" );
|
||||
|
||||
//SET_PALETTEREP_ID( Corpse.VestPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].vest );
|
||||
//SET_PALETTEREP_ID( Corpse.PantsPal, gUniformColors[ UNIFORM_ENEMY_TROOP ].pants );
|
||||
|
||||
Corpse.ubDirection = NORTH;
|
||||
Corpse.uiTimeOfDeath = GetWorldTotalMin();
|
||||
|
||||
Corpse.usFlags = 0; // no flags here, at least not the new ones
|
||||
|
||||
Corpse.bLevel = bLevel;
|
||||
|
||||
Corpse.bVisible = 1;
|
||||
Corpse.bNumServicingCrows = 0;
|
||||
Corpse.ubProfile = NO_PROFILE;
|
||||
Corpse.fHeadTaken = FALSE;
|
||||
Corpse.ubAIWarningValue = 20;
|
||||
|
||||
INT32 iCorpseID = AddRottingCorpse( &Corpse );
|
||||
|
||||
if ( iCorpseID != -1 )
|
||||
{
|
||||
AllMercsOnTeamLookForCorpse(&( gRottingCorpse[ iCorpseID ] ), OUR_TEAM);
|
||||
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_NO_HEAD )
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_HEAD_TAKEN;
|
||||
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_STRIPPED )
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_CLOTHES_TAKEN;
|
||||
|
||||
// TODO: change this so it always fits, not dependant these colours
|
||||
if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_YELLOW && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_GREEN )
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_ADMIN;
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_RED && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_GREEN )
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_TROOP;
|
||||
else if ( (*pObj)[0]->data.sObjectFlag & CORPSE_VEST_BLACK && (*pObj)[0]->data.sObjectFlag & CORPSE_PANTS_BLACK )
|
||||
gRottingCorpse[ iCorpseID ].def.usFlags |= ROTTING_CORPSE_FROM_ELITE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -2552,3 +2957,85 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
|
||||
return( canbezombie );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Flugente: can we take the clothes of this corpse?
|
||||
// calling this with NULL for soldier will give a general answer for any bodytype
|
||||
BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier )
|
||||
{
|
||||
if ( !pCorpse )
|
||||
return FALSE;
|
||||
|
||||
switch ( pCorpse->def.ubType )
|
||||
{
|
||||
case SMERC_JFK:
|
||||
case SMERC_BCK:
|
||||
case SMERC_FWD:
|
||||
case SMERC_DHD:
|
||||
case SMERC_PRN:
|
||||
case SMERC_WTR:
|
||||
case SMERC_FALL:
|
||||
case SMERC_FALLF:
|
||||
case M_DEAD1:
|
||||
case M_DEAD2:
|
||||
case H_DEAD1:
|
||||
case H_DEAD2:
|
||||
case S_DEAD1:
|
||||
case S_DEAD2:
|
||||
case C_DEAD1:
|
||||
case C_DEAD2:
|
||||
if ( pSoldier )
|
||||
{
|
||||
if ( pSoldier->ubBodyType == REGMALE )
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
|
||||
case MMERC_JFK:
|
||||
case MMERC_BCK:
|
||||
case MMERC_FWD:
|
||||
case MMERC_DHD:
|
||||
case MMERC_PRN:
|
||||
case MMERC_WTR:
|
||||
case MMERC_FALL:
|
||||
case MMERC_FALLF:
|
||||
case FT_DEAD1:
|
||||
case FT_DEAD2:
|
||||
if ( pSoldier )
|
||||
{
|
||||
if ( pSoldier->ubBodyType == BIGMALE || pSoldier->ubBodyType == STOCKYMALE )
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
|
||||
case FMERC_JFK:
|
||||
case FMERC_BCK:
|
||||
case FMERC_FWD:
|
||||
case FMERC_DHD:
|
||||
case FMERC_PRN:
|
||||
case FMERC_WTR:
|
||||
case FMERC_FALL:
|
||||
case FMERC_FALLF:
|
||||
case W_DEAD1:
|
||||
case W_DEAD2:
|
||||
if ( pSoldier )
|
||||
{
|
||||
if ( pSoldier->ubBodyType == REGFEMALE )
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return TRUE;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -91,8 +91,12 @@ enum RottingCorpseDefines
|
||||
|
||||
// Flugente: corpses can now be gutted after they have been decapitated. Atm there is no corpse that can be both gutted and decapitated (to be done later)
|
||||
#define ROTTING_CORPSE_HEAD_TAKEN 0x00001000 // head has been taken off
|
||||
#define ROTTING_CORPSE_GUTTED 0x00001000 // corpse has been gutted
|
||||
#define ROTTING_CORPSE_GUTTED 0x00002000 // corpse has been gutted
|
||||
#define ROTTING_CORPSE_CLOTHES_TAKEN 0x00004000 // corpse is without clothes (atm not visually)
|
||||
|
||||
#define ROTTING_CORPSE_FROM_ADMIN 0x00010000 // corpse is from a admin (used to take his clothes)
|
||||
#define ROTTING_CORPSE_FROM_TROOP 0x00020000 // corpse is from a regular soldier (used to take his clothes)
|
||||
#define ROTTING_CORPSE_FROM_ELITE 0x00040000 // corpse is from a elite soldier (used to take his clothes)
|
||||
typedef struct
|
||||
{
|
||||
UINT8 ubType;
|
||||
@@ -199,6 +203,16 @@ ROTTING_CORPSE *GetCorpseAtGridNo( INT32 sGridNo , INT8 bLevel );
|
||||
BOOLEAN IsValidDecapitationCorpse( ROTTING_CORPSE *pCorpse );
|
||||
void DecapitateCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel );
|
||||
|
||||
// Flugente: actions for the covert opts trait
|
||||
BOOLEAN IsValidGutCorpse( ROTTING_CORPSE *pCorpse );
|
||||
void GutCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel );
|
||||
BOOLEAN IsValidStripCorpse( ROTTING_CORPSE *pCorpse );
|
||||
void StripCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel );
|
||||
BOOLEAN IsValidTakeCorpse( ROTTING_CORPSE *pCorpse );
|
||||
void TakeCorpse( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel );
|
||||
|
||||
BOOLEAN AddCorpseFromObject(OBJECTTYPE* pObj, INT32 sGridNo, INT8 bLevel );
|
||||
|
||||
void GetBloodFromCorpse( SOLDIERTYPE *pSoldier );
|
||||
|
||||
UINT16 GetCorpseStructIndex( ROTTING_CORPSE_DEFINITION *pCorpseDef, BOOLEAN fForImage );
|
||||
@@ -221,4 +235,7 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo );
|
||||
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState );
|
||||
#endif
|
||||
|
||||
// Flugente: can we take the clothes of this corpse?
|
||||
BOOLEAN CorpseOkToDress( ROTTING_CORPSE * pCorpse, SOLDIERTYPE* pSoldier );
|
||||
|
||||
#endif
|
||||
@@ -2926,7 +2926,10 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier )
|
||||
case 752:
|
||||
|
||||
// Code: decapitate
|
||||
DecapitateCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel );
|
||||
//DecapitateCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel );
|
||||
|
||||
// Flugente: instead of jsut decapitating, we call a selection window where we can choose what to do with the corpse
|
||||
HandleSoldierUseCorpse( pSoldier, pSoldier->sTargetGridNo, pSoldier->bTargetLevel ); // Flugente: handle corpses
|
||||
break;
|
||||
|
||||
case 753:
|
||||
|
||||
@@ -6315,6 +6315,10 @@ void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sD
|
||||
}
|
||||
}
|
||||
|
||||
// Flugente: if hit in legs or torso, blood will be on our uniform - this unifrom can't be used to disguise someone anymore
|
||||
if ( ubHitLocation == AIM_SHOT_TORSO || ubHitLocation == AIM_SHOT_LEGS )
|
||||
pSoldier->bSoldierFlagMask |= SOLDIER_DAMAGED_UNIFORM;
|
||||
|
||||
// IF HERE AND GUY IS DEAD, RETURN!
|
||||
if ( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD )
|
||||
{
|
||||
@@ -6361,6 +6365,10 @@ void SoldierGotHitGunFire( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sD
|
||||
|
||||
void SoldierGotHitExplosion( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
|
||||
{
|
||||
// Flugente: if hit in legs or torso, blood will be on our uniform - this unifrom can't be used to disguise someone anymore
|
||||
if ( ubHitLocation == AIM_SHOT_TORSO || ubHitLocation == AIM_SHOT_LEGS )
|
||||
pSoldier->bSoldierFlagMask |= SOLDIER_DAMAGED_UNIFORM;
|
||||
|
||||
INT32 sNewGridNo;
|
||||
|
||||
// IF HERE AND GUY IS DEAD, RETURN!
|
||||
@@ -6529,6 +6537,9 @@ void SoldierGotHitExplosion( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16
|
||||
|
||||
void SoldierGotHitBlade( SOLDIERTYPE *pSoldier, UINT16 usWeaponIndex, INT16 sDamage, UINT16 bDirection, UINT16 sRange, UINT8 ubAttackerID, UINT8 ubSpecial, UINT8 ubHitLocation )
|
||||
{
|
||||
// Flugente: if hit in legs or torso, blood will be on our uniform - this unifrom can't be used to disguise someone anymore
|
||||
if ( ubHitLocation == AIM_SHOT_TORSO || ubHitLocation == AIM_SHOT_LEGS )
|
||||
pSoldier->bSoldierFlagMask |= SOLDIER_DAMAGED_UNIFORM;
|
||||
|
||||
// IF HERE AND GUY IS DEAD, RETURN!
|
||||
if ( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD )
|
||||
@@ -11684,7 +11695,8 @@ void SOLDIERTYPE::EVENT_SoldierBeginBladeAttack( INT32 sGridNo, UINT8 ubDirectio
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( IsValidDecapitationCorpse( pCorpse ) )
|
||||
// Flugente: decapitation action now also performs gutting, stripping and taking corpses
|
||||
if ( IsValidDecapitationCorpse( pCorpse ) || IsValidGutCorpse( pCorpse ) || IsValidStripCorpse( pCorpse ) || IsValidTakeCorpse( pCorpse ) )
|
||||
{
|
||||
this->EVENT_InitNewSoldierAnim( DECAPITATE, 0 , FALSE );
|
||||
}
|
||||
@@ -14393,6 +14405,742 @@ void SOLDIERTYPE::CleanWeapon()
|
||||
}
|
||||
}
|
||||
|
||||
extern INT16 uiNIVSlotType[NUM_INV_SLOTS];
|
||||
|
||||
// do we look like a civilian?
|
||||
BOOLEAN SOLDIERTYPE::LooksLikeACivilian( void )
|
||||
{
|
||||
// if we have any camo: not covert
|
||||
if ( GetWornCamo(this) > 0 || GetWornUrbanCamo(this) > 0 || GetWornDesertCamo(this) > 0 || GetWornSnowCamo(this) > 0 )
|
||||
return FALSE;
|
||||
|
||||
if ( UsingNewInventorySystem() )
|
||||
{
|
||||
INT8 invsize = (INT8)this->inv.size();
|
||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop) // ... for all items in our inventory ...
|
||||
{
|
||||
if ( this->inv[bLoop].exists() )
|
||||
{
|
||||
// if we have a back pack: not covert
|
||||
if ( bLoop == BPACKPOCKPOS )
|
||||
return FALSE;
|
||||
|
||||
// do not check the LBE itself (we already checked for camo above)
|
||||
if ( bLoop >= VESTPOCKPOS && bLoop <= CPACKPOCKPOS )
|
||||
continue;
|
||||
|
||||
BOOLEAN checkfurther = FALSE;
|
||||
// further checks it item is not covert. This means that a gun that has that tag will not be detectedif if its inside a pocket!
|
||||
if ( bLoop == HANDPOS || bLoop == SECONDHANDPOS || bLoop == GUNSLINGPOCKPOS || bLoop == HELMETPOS || bLoop == VESTPOS || bLoop == LEGPOS || bLoop == HEAD1POS || bLoop == HEAD2POS )
|
||||
checkfurther = TRUE;
|
||||
else if ( bLoop == KNIFEPOCKPOS && !HasItemFlag(this->inv[bLoop].usItem, COVERT) )
|
||||
checkfurther = TRUE;
|
||||
else if ( !HasItemFlag(this->inv[bLoop].usItem, COVERT) )
|
||||
{
|
||||
checkfurther = TRUE;
|
||||
|
||||
// item will be detected if someone looks - check for the LBE item that gave us this slot. If that one is covert, this item is also covert
|
||||
UINT8 checkslot = 0;
|
||||
switch (uiNIVSlotType[bLoop])
|
||||
{
|
||||
case 3:
|
||||
checkslot = VESTPOCKPOS;
|
||||
break;
|
||||
case 4:
|
||||
if ( bLoop == 23 || bLoop == 35 || bLoop == 36 || bLoop == 37 || bLoop == 38 )
|
||||
checkslot = LTHIGHPOCKPOS;
|
||||
else
|
||||
checkslot = RTHIGHPOCKPOS;
|
||||
break;
|
||||
case 5:
|
||||
checkslot = CPACKPOCKPOS;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
// found a slot to check for LBE
|
||||
if ( checkslot > 0 )
|
||||
{
|
||||
// if LBE is covert
|
||||
if ( this->inv[checkslot].exists() && HasItemFlag(this->inv[checkslot].usItem, COVERT) )
|
||||
// pass for this item
|
||||
checkfurther = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( checkfurther )
|
||||
{
|
||||
// if that item is a gun, explosives, military armour or facewear, we're screwed
|
||||
if ( (Item[this->inv[bLoop].usItem].usItemClass & (IC_WEAPON|IC_GRENADE|IC_BOMB) ) ||
|
||||
( (Item[this->inv[bLoop].usItem].usItemClass & (IC_ARMOUR) ) && !Item[this->inv[bLoop].usItem].leatherjacket && Armour[ Item[this->inv[bLoop].usItem].ubClassIndex ].ubProtection > 10 ) ||
|
||||
( Item[this->inv[bLoop].usItem].nightvisionrangebonus > 0 || Item[this->inv[bLoop].usItem].hearingrangebonus > 0 )
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // old inventory system. No LBE here, nothing fancy
|
||||
{
|
||||
INT8 invsize = (INT8)this->inv.size();
|
||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop) // ... for all items in our inventory ...
|
||||
{
|
||||
if ( this->inv[bLoop].exists() )
|
||||
{
|
||||
if ( !HasItemFlag(this->inv[bLoop].usItem, COVERT) )
|
||||
{
|
||||
// if that item is a gun, explosives, military armour or facewear, we're screwed
|
||||
if ( (Item[this->inv[bLoop].usItem].usItemClass & (IC_WEAPON|IC_GRENADE|IC_BOMB) ) ||
|
||||
( (Item[this->inv[bLoop].usItem].usItemClass & (IC_ARMOUR) ) && !Item[this->inv[bLoop].usItem].leatherjacket && Armour[ Item[this->inv[bLoop].usItem].ubClassIndex ].ubProtection > 10 ) ||
|
||||
( Item[this->inv[bLoop].usItem].nightvisionrangebonus > 0 || Item[this->inv[bLoop].usItem].hearingrangebonus > 0 )
|
||||
)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// do we look like a soldier?
|
||||
BOOLEAN SOLDIERTYPE::LooksLikeASoldier( void )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// is our equipment too good for a soldier?
|
||||
BOOLEAN SOLDIERTYPE::EquipmentTooGood( BOOLEAN fCloselook )
|
||||
{
|
||||
// check the guns in our hands an rifle sling
|
||||
// alert if we have more than 2, any of them has too much attachments or they are way too cool
|
||||
UINT8 numberofguns = 0;
|
||||
UINT8 ubCurrentProgress = CurrentPlayerProgressPercentage();
|
||||
UINT8 maxcoolnessallowed = 1 + ubCurrentProgress / 10;
|
||||
maxcoolnessallowed += 2; // TODO adjust for level and uniform
|
||||
UINT16 maxitemsize = 4;
|
||||
|
||||
if ( UsingNewInventorySystem() )
|
||||
{
|
||||
INT8 invsize = (INT8)this->inv.size();
|
||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop) // ... for all items in our inventory ...
|
||||
{
|
||||
if ( this->inv[bLoop].exists() )
|
||||
{
|
||||
// if we have a back pack: not covert
|
||||
if ( bLoop == BPACKPOCKPOS )
|
||||
return FALSE;
|
||||
|
||||
// further checks it item is not covert. This means that a gun that has that tag will not be detectedif if its inside a pocket!
|
||||
if ( bLoop == HANDPOS || bLoop == SECONDHANDPOS || bLoop == GUNSLINGPOCKPOS || bLoop == HELMETPOS || bLoop == VESTPOS || bLoop == LEGPOS || bLoop == HEAD1POS || bLoop == HEAD2POS ||
|
||||
!HasItemFlag(this->inv[bLoop].usItem, COVERT) )
|
||||
{
|
||||
// item will be detected if someone looks - check for the LBE item that gave us this slot. If that one is covert, this item is also covert
|
||||
UINT8 checkslot = 0;
|
||||
switch (uiNIVSlotType[bLoop])
|
||||
{
|
||||
case 3:
|
||||
checkslot = VESTPOCKPOS;
|
||||
break;
|
||||
case 4:
|
||||
if ( bLoop == 23 || bLoop == 35 || bLoop == 36 || bLoop == 37 || bLoop == 38 )
|
||||
checkslot = LTHIGHPOCKPOS;
|
||||
else
|
||||
checkslot = RTHIGHPOCKPOS;
|
||||
break;
|
||||
case 5:
|
||||
checkslot = CPACKPOCKPOS;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
// found a slot to check for LBE
|
||||
if ( checkslot > 0 )
|
||||
{
|
||||
// if LBE is covert
|
||||
if ( this->inv[checkslot].exists() && HasItemFlag(this->inv[checkslot].usItem, COVERT) )
|
||||
// pass for this item
|
||||
continue;
|
||||
}
|
||||
|
||||
// if that item is a gun, explosives, military armour or facewear, investigate further
|
||||
if ( (Item[this->inv[bLoop].usItem].usItemClass & (IC_GUN|IC_LAUNCHER|IC_ARMOUR|IC_FACE) ) )
|
||||
{
|
||||
if ( (Item[this->inv[bLoop].usItem].usItemClass & (IC_GUN|IC_LAUNCHER) ) )
|
||||
{
|
||||
++numberofguns;
|
||||
|
||||
if ( numberofguns > 2 )
|
||||
return TRUE;
|
||||
|
||||
OBJECTTYPE * pObj = &(this->inv[bLoop]); // ... get pointer for this item ...
|
||||
|
||||
if ( pObj != NULL )
|
||||
{
|
||||
for(INT16 i = 0; i < pObj->ubNumberOfObjects; ++i) // ... there might be multiple items here (item stack), so for each one ...
|
||||
{
|
||||
// loop over every item and its attachments
|
||||
if ( Item[pObj->usItem].ubCoolness > maxcoolnessallowed )
|
||||
return TRUE;
|
||||
|
||||
UINT8 numberofattachments = 0;
|
||||
// for every objects, we also have to check wether there are weapon attachments (eg. underbarrel grenade launchers), and cool them down too
|
||||
attachmentList::iterator iterend = (*pObj)[i]->attachments.end();
|
||||
for (attachmentList::iterator iter = (*pObj)[i]->attachments.begin(); iter != iterend; ++iter)
|
||||
{
|
||||
if ( iter->exists() )
|
||||
{
|
||||
// loop over every item and its attachments
|
||||
if ( Item[iter->usItem].ubCoolness > maxcoolnessallowed )
|
||||
return TRUE;
|
||||
|
||||
++numberofattachments;
|
||||
}
|
||||
}
|
||||
|
||||
// no ordinary soldier is allowed that many attachemnts > not covert
|
||||
if ( numberofattachments > gGameExternalOptions.iMaxEnemyAttachments )
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // old inventory system. No LBE here, nothing fancy
|
||||
{
|
||||
INT8 invsize = (INT8)this->inv.size();
|
||||
for ( INT8 bLoop = 0; bLoop < invsize; ++bLoop) // ... for all items in our inventory ...
|
||||
{
|
||||
if ( this->inv[bLoop].exists() )
|
||||
{
|
||||
// if that item is a gun, explosives, military armour or facewear, investigate further
|
||||
if ( !HasItemFlag(this->inv[bLoop].usItem, COVERT) && (Item[this->inv[bLoop].usItem].usItemClass & (IC_GUN|IC_LAUNCHER|IC_ARMOUR|IC_FACE) ) )
|
||||
{
|
||||
if ( (Item[this->inv[bLoop].usItem].usItemClass & (IC_GUN|IC_LAUNCHER) ) )
|
||||
{
|
||||
++numberofguns;
|
||||
|
||||
if ( numberofguns > 2 )
|
||||
return TRUE;
|
||||
|
||||
OBJECTTYPE * pObj = &(this->inv[bLoop]); // ... get pointer for this item ...
|
||||
|
||||
if ( pObj != NULL )
|
||||
{
|
||||
for(INT16 i = 0; i < pObj->ubNumberOfObjects; ++i) // ... there might be multiple items here (item stack), so for each one ...
|
||||
{
|
||||
// loop over every item and its attachments
|
||||
if ( Item[pObj->usItem].ubCoolness > maxcoolnessallowed )
|
||||
return TRUE;
|
||||
|
||||
UINT8 numberofattachments = 0;
|
||||
// for every objects, we also have to check wether there are weapon attachments (eg. underbarrel grenade launchers), and cool them down too
|
||||
attachmentList::iterator iterend = (*pObj)[i]->attachments.end();
|
||||
for (attachmentList::iterator iter = (*pObj)[i]->attachments.begin(); iter != iterend; ++iter)
|
||||
{
|
||||
if ( iter->exists() )
|
||||
{
|
||||
// loop over every item and its attachments
|
||||
if ( Item[iter->usItem].ubCoolness > maxcoolnessallowed )
|
||||
return TRUE;
|
||||
|
||||
++numberofattachments;
|
||||
}
|
||||
}
|
||||
|
||||
// no ordinary soldier is allowed that many attachments > not covert
|
||||
if ( numberofattachments > gGameExternalOptions.iMaxEnemyAttachments )
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
// are we in covert mode? we need to have the correct flag set, and not wear anything suspicious, or behave in a suspicious way
|
||||
BOOLEAN SOLDIERTYPE::SeemsLegit( UINT8 ubObserverID )
|
||||
{
|
||||
SOLDIERTYPE* pSoldier = MercPtrs[ubObserverID];
|
||||
|
||||
if ( !pSoldier )
|
||||
return TRUE;
|
||||
|
||||
// if we don't have the Flag: not covert
|
||||
// important: no messages up to this point. the function will get called a lot, up to this point there is nothing unusual
|
||||
if ( !(this->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) ) )
|
||||
return FALSE;
|
||||
|
||||
// if we are in a suspicious stance: not covert
|
||||
if ( this->usAnimState == NINJA_SPINKICK ||
|
||||
this->usAnimState == NINJA_PUNCH ||
|
||||
this->usAnimState == NINJA_LOWKICK ||
|
||||
this->usAnimState == PUNCH_LOW ||
|
||||
this->usAnimState == DECAPITATE ||
|
||||
this->usAnimState == CROWBAR_ATTACK ||
|
||||
this->usAnimState == THROW_GRENADE_STANCE ||
|
||||
this->usAnimState == THROW_KNIFE_SP_BM ||
|
||||
this->usAnimState == DODGE_ONE ||
|
||||
this->usAnimState == SLICE ||
|
||||
this->usAnimState == STAB ||
|
||||
this->usAnimState == CROUCH_STAB ||
|
||||
this->usAnimState == PUNCH ||
|
||||
this->usAnimState == PUNCH_BREATH ||
|
||||
this->usAnimState == KICK_DOOR ||
|
||||
this->usAnimState == CUTTING_FENCE ||
|
||||
this->usAnimState == THROW_KNIFE ||
|
||||
this->usAnimState == PLANT_BOMB ||
|
||||
this->usAnimState == USE_REMOTE ||
|
||||
this->usAnimState == TAKE_BLOOD_FROM_CORPSE ||
|
||||
this->usAnimState == PICK_LOCK ||
|
||||
this->usAnimState == LOCKPICK_CROUCHED ||
|
||||
this->usAnimState == STEAL_ITEM_CROUCHED ||
|
||||
this->usAnimState == JUMPWINDOWS
|
||||
)
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s was seen performing suspicious activities!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN looklikeaciv = this->LooksLikeACivilian();
|
||||
|
||||
// if we are trying to dress like a civilian, but aren't sucessful: not covert
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV && !looklikeaciv)
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s does not look like a civilian!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN looklikeasoldier = this->LooksLikeASoldier();
|
||||
|
||||
// if we are trying to dress like a soldier, but aren't sucessful: not covert
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER && !looklikeasoldier)
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s does not look like a soldier!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
UINT8 covertlevel = NUM_SKILL_TRAITS( this, COVERT_NT ); // our level in covert operations
|
||||
INT32 distance = GetRangeFromGridNoDiff(this->sGridNo, pSoldier->sGridNo);
|
||||
|
||||
// if we are closer than this, our cover will always break if we do not have the skill
|
||||
// if we have the skill, our cover will blow if we dress up as a soldier, but not if we are dressed like a civilian
|
||||
INT32 discoverrange = gSkillTraitValues.sCOCloseDetectionRange;
|
||||
|
||||
if ( distance < discoverrange )
|
||||
{
|
||||
switch ( covertlevel )
|
||||
{
|
||||
case 2:
|
||||
// a covert ops expert can get as close as he wants, even dressed up as a soldier, without arousing suspicion
|
||||
// exceptions: we are discovered if we are close and bleeding, or if we are drunk while dressed as a soldier
|
||||
{
|
||||
// if we are openly bleeding: not covert
|
||||
if ( this->bBleeding > 0 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s bleeding was discovered!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER && GetDrunkLevel( this ) != SOBER )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s is drunk and doesn't look like a soldier!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// at lvl covert ops, we can be discovered if we are too close to the enemy and bleed or dressed up as a soldier
|
||||
// however, if we are dressed up as a civilian, we can get as close as we like, we won't be discovered
|
||||
{
|
||||
// if we are openly bleeding: not covert
|
||||
if ( this->bBleeding > 0 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s bleeding was discovered!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"On closer inspection, %s's disguise does not hold!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
// without the covert ops skill, we can only dress up as civilians. We will be discovered if we get too close to the enemy
|
||||
if ( (this->bSoldierFlagMask & SOLDIER_COVERT_NPC_SPECIAL) == 0 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"On closer inspection, %s's disguise does not hold!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV )
|
||||
{
|
||||
// civilians are suspicious if they are found in certain sectors. Especially at night
|
||||
// sector specific value:
|
||||
// 0 - civilians are always ok
|
||||
// 1 - civilians are suspicious at night
|
||||
// 2 - civilians are always suspicious
|
||||
|
||||
UINT8 sectordata = 0;
|
||||
UINT8 ubSectorId = SECTOR(gWorldSectorX, gWorldSectorY);
|
||||
if ( gbWorldSectorZ > 0 )
|
||||
// underground we are always suspicious
|
||||
sectordata = 2;
|
||||
else if ( ubSectorId >= 0 && ubSectorId < 256 )
|
||||
sectordata = SectorExternalData[ubSectorId][gbWorldSectorZ].usCurfewValue;
|
||||
|
||||
if ( sectordata > 1 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s isn't supposed to be here!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
// is it night?
|
||||
else if ( sectordata == 1 && GetTimeOfDayAmbientLightLevel() < NORMAL_LIGHTLEVEL_DAY + 2 )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s isn't supposed to be here at this time!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
INT32 cnt;
|
||||
ROTTING_CORPSE * pCorpse;
|
||||
for ( cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
||||
{
|
||||
pCorpse = &(gRottingCorpse[ cnt ] );
|
||||
|
||||
if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 && PythSpacesAway( this->sGridNo, pCorpse->def.sGridNo ) <= 5 )
|
||||
{
|
||||
// a corpse was found near our position. If the soldier observing us can see it, he will be alarmed
|
||||
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s was seen near a fresh corpse!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
// if our equipment is too good, that is suspicious... not covert!
|
||||
if ( this->EquipmentTooGood( (distance < discoverrange) ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s equipment raises a few eyebrows!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// are we targeting a buddy of our observer?
|
||||
if ( this->ubTargetID && MercPtrs[this->ubTargetID] && MercPtrs[this->ubTargetID]->bTeam == pSoldier->bTeam )
|
||||
{
|
||||
// if we aiming at a soldier, others will notice our intent... not covert!
|
||||
if ( WeaponReady(this) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s is seen targeting a soldier!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// even as a soldier, we will be caught around fresh corpses
|
||||
if (distance < gSkillTraitValues.sCOCloseDetectionRangeSoldierCorpse)
|
||||
{
|
||||
// check wether we are around a fresh corpse - this will make us much more suspicious
|
||||
// I deem this necessary, to avoid cheap exploits by nefarious players :-)
|
||||
INT32 cnt;
|
||||
ROTTING_CORPSE * pCorpse;
|
||||
for ( cnt = 0; cnt < giNumRottingCorpse; ++cnt )
|
||||
{
|
||||
pCorpse = &(gRottingCorpse[ cnt ] );
|
||||
|
||||
if ( pCorpse && pCorpse->fActivated && pCorpse->def.ubAIWarningValue > 0 && PythSpacesAway( this->sGridNo, pCorpse->def.sGridNo ) <= 5 )
|
||||
{
|
||||
// a corpse was found near our position. If the soldier observing us can see it, he will be alarmed
|
||||
if ( SoldierTo3DLocationLineOfSightTest( pSoldier, pCorpse->def.sGridNo, pCorpse->def.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
{
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s was seen near a fresh corpse!", this->name );
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// do we recognize someone else as a combatant?
|
||||
BOOLEAN SOLDIERTYPE::RecognizeAsCombatant(UINT8 ubTargetID)
|
||||
{
|
||||
// this will only work with the new trait system
|
||||
if (!gGameOptions.fNewTraitSystem)
|
||||
return TRUE;
|
||||
|
||||
SOLDIERTYPE* pSoldier = MercPtrs[ubTargetID];
|
||||
|
||||
if ( !pSoldier )
|
||||
return TRUE;
|
||||
|
||||
// if neither of the 2 persons is covert, always return true
|
||||
if ( ( (pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0 ) && ( (this->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0 ) )
|
||||
return TRUE;
|
||||
|
||||
// only members of the player team can ever be covert, sorry AI
|
||||
if ( pSoldier->bTeam != OUR_TEAM )
|
||||
return TRUE;
|
||||
|
||||
// neutral characters just dont care
|
||||
if ( this->aiData.bNeutral )
|
||||
return TRUE;
|
||||
|
||||
// check for for vehicles and creatures... weird things happen
|
||||
if ( IsVehicle(pSoldier) || pSoldier->bTeam == CREATURE_TEAM || this->bTeam == CREATURE_TEAM )
|
||||
return TRUE;
|
||||
|
||||
// checking someone from our team...
|
||||
if ( this->bTeam == pSoldier->bTeam )
|
||||
{
|
||||
// not in covert mode: we recognize him
|
||||
if ( (pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER)) == 0 )
|
||||
return TRUE;
|
||||
else
|
||||
// we don't because we accept that he is covert (to not blow his cover)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// hack: if this is attacking us at this very moment by punching, do not recognize him...
|
||||
// this resolves the problem that we attack someone from behind and kill him instantly, but the game mechanic forces him to turn before
|
||||
// only allow this if we are not yet alerted (we are suprised, so we don't recognize him in the moment of the attack
|
||||
// also: only allow if he's next to us
|
||||
if ( this->aiData.bAlertStatus < STATUS_RED && pSoldier->ubTargetID == this->ubID )
|
||||
{
|
||||
INT32 nextGridNoinSight = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) );
|
||||
if ( nextGridNoinSight == this->sGridNo && this->pathing.bLevel == pSoldier->pathing.bLevel )
|
||||
{
|
||||
if ( pSoldier->usAnimState == PUNCH )
|
||||
return FALSE;
|
||||
else if ( pSoldier->usAnimState == PUNCH_BREATH )
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// do we recognize this guy as an enemy?
|
||||
if ( !pSoldier->SeemsLegit(this->ubID) )
|
||||
{
|
||||
// aha, he/she's a spy! Blow cover
|
||||
if ( pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) )
|
||||
{
|
||||
pSoldier->LooseDisguise();
|
||||
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"%s has seen through %s disguise!", this->name, pSoldier->name );
|
||||
|
||||
// we have uncovered a spy! Get alerted, if we aren't already
|
||||
if ( this->aiData.bAlertStatus < STATUS_BLACK )
|
||||
this->aiData.bAlertStatus = STATUS_BLACK;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// dress up in our natural state
|
||||
void SOLDIERTYPE::LooseDisguise( void )
|
||||
{
|
||||
// show our true colours
|
||||
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
|
||||
|
||||
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
|
||||
{
|
||||
UINT8 ubProfileIndex;
|
||||
MERCPROFILESTRUCT * pProfile;
|
||||
|
||||
ubProfileIndex = this->ubProfile;
|
||||
pProfile = &(gMercProfiles[ubProfileIndex]);
|
||||
|
||||
SET_PALETTEREP_ID ( this->VestPal, pProfile->VEST );
|
||||
SET_PALETTEREP_ID ( this->PantsPal, pProfile->PANTS );
|
||||
|
||||
// Use palette from HVOBJECT, then use substitution for pants, etc
|
||||
memcpy( this->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( this->p8BPPPalette ) * 256 );
|
||||
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->HeadPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->VestPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->PantsPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->SkinPal );
|
||||
|
||||
this->CreateSoldierPalettes();
|
||||
}
|
||||
|
||||
// loose any covert flags
|
||||
// if we are disguised as a civilian, remove that flag, and give us back a civilian clothes item
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV )
|
||||
{
|
||||
this->bSoldierFlagMask &= ~SOLDIER_COVERT_CIV;
|
||||
|
||||
UINT16 civilianclothesitem = 0;
|
||||
if ( GetFirstItemWithFlag(&civilianclothesitem, CLOTHES_CIVILIAN) )
|
||||
{
|
||||
CreateItem( civilianclothesitem, 100, &gTempObject );
|
||||
|
||||
if ( !AutoPlaceObject( this, &gTempObject, FALSE ) )
|
||||
AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
// if we are also disguised as a soldier, remove that flag
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
this->bSoldierFlagMask &= ~SOLDIER_COVERT_SOLDIER;
|
||||
}
|
||||
}
|
||||
|
||||
// dress up like a civilian
|
||||
BOOLEAN SOLDIERTYPE::DisguiseAsCivilian( void )
|
||||
{
|
||||
// this will only work with the new trait system
|
||||
if (!gGameOptions.fNewTraitSystem)
|
||||
return FALSE;
|
||||
|
||||
UINT8 skilllevel = NUM_SKILL_TRAITS( this, COVERT_NT );
|
||||
|
||||
INT16 apcost = (APBPConstants[AP_DISGUISE] * ( gSkillTraitValues.sCODisguiseAPReduction * skilllevel))/100;
|
||||
if ( !EnoughPoints( this, apcost, 0, TRUE ) )
|
||||
return( FALSE );
|
||||
|
||||
this->bSoldierFlagMask |= SOLDIER_COVERT_CIV;
|
||||
|
||||
// wear an enemy uniform
|
||||
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
|
||||
|
||||
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
|
||||
{
|
||||
// wear something random
|
||||
switch( Random( 7 ) )
|
||||
{
|
||||
case 0: SET_PALETTEREP_ID( this->VestPal, "WHITEVEST" ); break;
|
||||
case 1: SET_PALETTEREP_ID( this->VestPal, "BLACKSHIRT" ); break;
|
||||
case 2: SET_PALETTEREP_ID( this->VestPal, "PURPLESHIRT" ); break;
|
||||
case 3: SET_PALETTEREP_ID( this->VestPal, "BLUEVEST" ); break;
|
||||
case 4: SET_PALETTEREP_ID( this->VestPal, "BROWNVEST" ); break;
|
||||
case 5: SET_PALETTEREP_ID( this->VestPal, "JEANVEST" ); break;
|
||||
case 6: SET_PALETTEREP_ID( this->VestPal, "REDVEST" ); break;
|
||||
}
|
||||
|
||||
switch( Random( 3 ) )
|
||||
{
|
||||
case 0: SET_PALETTEREP_ID( this->PantsPal, "TANPANTS" ); break;
|
||||
case 1: SET_PALETTEREP_ID( this->PantsPal, "BEIGEPANTS" ); break;
|
||||
case 2: SET_PALETTEREP_ID( this->PantsPal, "GREENPANTS" ); break;
|
||||
}
|
||||
|
||||
// Use palette from HVOBJECT, then use substitution for pants, etc
|
||||
memcpy( this->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( this->p8BPPPalette ) * 256 );
|
||||
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->HeadPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->VestPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->PantsPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->SkinPal );
|
||||
|
||||
this->CreateSoldierPalettes();
|
||||
}
|
||||
|
||||
// if we are also disguised as a soldier, remove that flag
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_SOLDIER )
|
||||
{
|
||||
this->bSoldierFlagMask &= ~SOLDIER_COVERT_SOLDIER;
|
||||
}
|
||||
|
||||
DeductPoints( this, apcost, 0 );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// dress up like an enemy soldier
|
||||
BOOLEAN SOLDIERTYPE::DisguiseAsSoldierFromCorpse( UINT32 usFlag )
|
||||
{
|
||||
// this will only work with the new trait system
|
||||
if (!gGameOptions.fNewTraitSystem)
|
||||
return FALSE;
|
||||
|
||||
// action is only possible if we have the covert ops trait
|
||||
UINT8 skilllevel = NUM_SKILL_TRAITS( this, COVERT_NT );
|
||||
if ( skilllevel < 1)
|
||||
return FALSE;
|
||||
|
||||
INT16 apcost = (APBPConstants[AP_DISGUISE] * ( gSkillTraitValues.sCODisguiseAPReduction * skilllevel))/100;
|
||||
if ( !EnoughPoints( this, apcost, 0, TRUE ) )
|
||||
return( FALSE );
|
||||
|
||||
UINT8 uniformtype = 0;
|
||||
|
||||
if ( usFlag & ROTTING_CORPSE_FROM_ADMIN )
|
||||
uniformtype = UNIFORM_ENEMY_ADMIN;
|
||||
else if ( usFlag & ROTTING_CORPSE_FROM_TROOP )
|
||||
uniformtype = UNIFORM_ENEMY_TROOP;
|
||||
else if ( usFlag & ROTTING_CORPSE_FROM_ELITE )
|
||||
uniformtype = UNIFORM_ENEMY_ELITE;
|
||||
else
|
||||
// no uniform here, so nothing to wear
|
||||
return FALSE;
|
||||
|
||||
this->bSoldierFlagMask |= SOLDIER_COVERT_SOLDIER;
|
||||
|
||||
// wear an enemy uniform
|
||||
UINT16 usPaletteAnimSurface = LoadSoldierAnimationSurface( this, this->usAnimState );
|
||||
|
||||
if ( usPaletteAnimSurface != INVALID_ANIMATION_SURFACE )
|
||||
{
|
||||
SET_PALETTEREP_ID(this->VestPal, gUniformColors[ uniformtype ].vest );
|
||||
SET_PALETTEREP_ID(this->PantsPal, gUniformColors[ uniformtype ].pants );
|
||||
|
||||
// Use palette from HVOBJECT, then use substitution for pants, etc
|
||||
memcpy( this->p8BPPPalette, gAnimSurfaceDatabase[ usPaletteAnimSurface ].hVideoObject->pPaletteEntry, sizeof( this->p8BPPPalette ) * 256 );
|
||||
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->HeadPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->VestPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->PantsPal );
|
||||
SetPaletteReplacement( this->p8BPPPalette, this->SkinPal );
|
||||
|
||||
this->CreateSoldierPalettes();
|
||||
}
|
||||
|
||||
// if we are disguised as a civilian, remove that flag, and give us back a civilian clothes item
|
||||
if ( this->bSoldierFlagMask & SOLDIER_COVERT_CIV )
|
||||
{
|
||||
this->bSoldierFlagMask &= ~SOLDIER_COVERT_CIV;
|
||||
|
||||
UINT16 civilianclothesitem = 0;
|
||||
if ( GetFirstItemWithFlag(&civilianclothesitem, CLOTHES_CIVILIAN) )
|
||||
{
|
||||
CreateItem( civilianclothesitem, 100, &gTempObject );
|
||||
AddItemToPool( sGridNo, &gTempObject, 1, 0, 0, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
DeductPoints( this, apcost, 0 );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
|
||||
{
|
||||
INT8 bBandaged; //,savedOurTurn;
|
||||
@@ -16455,13 +17203,13 @@ BOOLEAN HAS_SKILL_TRAIT( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber )
|
||||
{
|
||||
for ( INT8 bCnt = 0; bCnt < min(30,bMaxTraits); bCnt++ )
|
||||
{
|
||||
if ( uiSkillTraitNumber > 0 && uiSkillTraitNumber <= NUM_MAJOR_TRAITS )
|
||||
if ( uiSkillTraitNumber > 0 && (uiSkillTraitNumber <= NUM_MAJOR_TRAITS || uiSkillTraitNumber == COVERT_NT) )
|
||||
{
|
||||
if (pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber)
|
||||
{
|
||||
return( TRUE );
|
||||
}
|
||||
else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS )
|
||||
else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && (pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS || pSoldier->stats.ubSkillTraits[ bCnt ] == COVERT_NT) )
|
||||
{
|
||||
bNumMajorTraitsCounted++;
|
||||
}
|
||||
@@ -16511,14 +17259,14 @@ INT8 NUM_SKILL_TRAITS( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber )
|
||||
{
|
||||
for ( INT8 bCnt = 0; bCnt < min(30,bMaxTraits); bCnt++ )
|
||||
{
|
||||
if ( uiSkillTraitNumber > 0 && uiSkillTraitNumber <= NUM_MAJOR_TRAITS )
|
||||
if ( uiSkillTraitNumber > 0 && (uiSkillTraitNumber <= NUM_MAJOR_TRAITS || uiSkillTraitNumber == COVERT_NT) )
|
||||
{
|
||||
if ( pSoldier->stats.ubSkillTraits[ bCnt ] == uiSkillTraitNumber )
|
||||
{
|
||||
bNumberOfTraits++;
|
||||
bNumMajorTraitsCounted++;
|
||||
}
|
||||
else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS )
|
||||
else if ( pSoldier->stats.ubSkillTraits[ bCnt ] > 0 && (pSoldier->stats.ubSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS || pSoldier->stats.ubSkillTraits[ bCnt ] == COVERT_NT ) )
|
||||
{
|
||||
bNumMajorTraitsCounted++;
|
||||
}
|
||||
@@ -16537,7 +17285,7 @@ INT8 NUM_SKILL_TRAITS( SOLDIERTYPE * pSoldier, UINT8 uiSkillTraitNumber )
|
||||
}
|
||||
}
|
||||
// cannot have more than one same minor trait
|
||||
if( uiSkillTraitNumber > NUM_MAJOR_TRAITS )
|
||||
if( uiSkillTraitNumber > NUM_MAJOR_TRAITS && uiSkillTraitNumber != COVERT_NT)
|
||||
return ( min(1, bNumberOfTraits) );
|
||||
else
|
||||
return ( min(2, bNumberOfTraits) );
|
||||
|
||||
@@ -345,12 +345,12 @@ enum
|
||||
// easier than adding 32 differently named variables. DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
|
||||
#define SOLDIER_DRUGGED 0x00000001 //1 // Soldier is on drugs
|
||||
#define SOLDIER_NO_AP 0x00000002 //2 // Soldier has no APs this turn (fix for reinforcement bug)
|
||||
/*#define WH40K_BOLTER 0x00000004 //4
|
||||
#define WH40K_FLAMER 0x00000008 //8
|
||||
#define SOLDIER_COVERT_CIV 0x00000004 //4 // Soldier is currently disguised as a civilian
|
||||
#define SOLDIER_COVERT_SOLDIER 0x00000008 //8 // Soldier is currently disguised as an enemy soldier
|
||||
|
||||
#define WH40K_POWER_ARMOR 0x00000010 //16
|
||||
#define WH40K_POWER_PACK 0x00000020 //32
|
||||
#define WH40K_JUMPPACK 0x00000040 //64
|
||||
#define SOLDIER_DAMAGED_UNIFORM 0x00000010 //16 // Soldier's uniform is damged (and thus can't be taken off of his corpse)
|
||||
#define SOLDIER_COVERT_NPC_SPECIAL 0x00000020 //32 // Special flag for NPCs wehn recruited (used for covert stuff)
|
||||
/*#define WH40K_JUMPPACK 0x00000040 //64
|
||||
#define WH40K_DISPLACER 0x00000080 //128
|
||||
|
||||
#define WH40K_ROSARIUS 0x00000100 //256
|
||||
@@ -1456,6 +1456,34 @@ public:
|
||||
|
||||
// use any cleaning kits to clean weapons in inventory
|
||||
void CleanWeapon();
|
||||
|
||||
// Flugente: functions for the covert ops trait
|
||||
|
||||
// are we in covert mode? we need to have the correct flag set, and not wear anything suspicious, or behave in a suspicious way
|
||||
|
||||
// do we look like a civilian?
|
||||
BOOLEAN LooksLikeACivilian( void );
|
||||
|
||||
// do we look like a soldier?
|
||||
BOOLEAN LooksLikeASoldier( void );
|
||||
|
||||
// is our equipment too good for a soldier?
|
||||
BOOLEAN EquipmentTooGood( BOOLEAN fCloselook );
|
||||
|
||||
// does soldier ubObserverID recognize us as his enemy?
|
||||
BOOLEAN SeemsLegit( UINT8 ubObserverID );
|
||||
|
||||
// do we recognize someone else as a combatant?
|
||||
BOOLEAN RecognizeAsCombatant(UINT8 ubTargetID);
|
||||
|
||||
// loose disguise, dress up in our natural state
|
||||
void LooseDisguise( void );
|
||||
|
||||
// dress up like a civilian
|
||||
BOOLEAN DisguiseAsCivilian( void );
|
||||
|
||||
// dress up like an enemy soldier
|
||||
BOOLEAN DisguiseAsSoldierFromCorpse( UINT32 usFlag );
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
}; // SOLDIERTYPE;
|
||||
|
||||
@@ -1701,6 +1701,16 @@ BOOLEAN RecruitRPC( UINT8 ubCharNum )
|
||||
GiveQuestRewardPoint( pSoldier->sSectorX, pSoldier->sSectorY, 6, MIGUEL );
|
||||
}
|
||||
|
||||
// Flugente: people recruited in Arulco are known to the enemy as civilians or even soldiers. So they will be covert whn recruiting them. Of course, this is not for the rebels...
|
||||
if ( ubCharNum == DEVIN || ubCharNum == HAMOUS || ubCharNum == SLAY || ubCharNum == VINCE || ubCharNum == MADDOG || ubCharNum == MICKY )
|
||||
{
|
||||
pNewSoldier->bSoldierFlagMask |= (SOLDIER_COVERT_CIV|SOLDIER_COVERT_NPC_SPECIAL);
|
||||
}
|
||||
else if ( ubCharNum == IGGY || ubCharNum == CONRAD )
|
||||
{
|
||||
pNewSoldier->bSoldierFlagMask |= (SOLDIER_COVERT_SOLDIER|SOLDIER_COVERT_NPC_SPECIAL);
|
||||
}
|
||||
|
||||
// handle town loyalty adjustment
|
||||
HandleTownLoyaltyForNPCRecruitment( pNewSoldier );
|
||||
|
||||
@@ -2650,14 +2660,14 @@ INT8 ProfileHasSkillTrait( INT32 ubProfileID, INT8 bSkillTrait )
|
||||
{
|
||||
for ( INT8 bCnt = 0; bCnt < gSkillTraitValues.ubMaxNumberOfTraits; bCnt++ )
|
||||
{
|
||||
if ( bSkillTrait > 0 && bSkillTrait <= NUM_MAJOR_TRAITS )
|
||||
if ( bSkillTrait > 0 && (bSkillTrait <= DOCTOR_NT || bSkillTrait == COVERT_NT ) )
|
||||
{
|
||||
if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] == bSkillTrait )
|
||||
{
|
||||
bNumTraits++;
|
||||
bNumMajorTraitsCounted++;
|
||||
}
|
||||
else if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] > 0 && gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] <= NUM_MAJOR_TRAITS )
|
||||
else if ( gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] > 0 && (gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] <= DOCTOR_NT || gMercProfiles[ubProfileID].bSkillTraits[ bCnt ] <= COVERT_NT) )
|
||||
{
|
||||
bNumMajorTraitsCounted++;
|
||||
}
|
||||
@@ -2676,7 +2686,7 @@ INT8 ProfileHasSkillTrait( INT32 ubProfileID, INT8 bSkillTrait )
|
||||
}
|
||||
}
|
||||
// cannot have more than 1 rade of minor traits or 2 grades of a major traits
|
||||
if( bSkillTrait > NUM_MAJOR_TRAITS )
|
||||
if( bSkillTrait > DOCTOR_NT && bSkillTrait != COVERT_NT )
|
||||
return ( min(1, bNumTraits) );
|
||||
else
|
||||
return ( min(2, bNumTraits) );
|
||||
|
||||
@@ -238,7 +238,7 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier )
|
||||
CHAR16 pStrAux[50];
|
||||
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]);
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1] + 19] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2]] );
|
||||
//swprintf( pStrInfo, L"%s\n", pStrInfo );
|
||||
}
|
||||
@@ -247,7 +247,7 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier )
|
||||
CHAR16 pStrAux[50];
|
||||
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]]);
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + 19] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]] );
|
||||
}
|
||||
else if (( pSoldier->stats.ubSkillTraits[0] == pSoldier->stats.ubSkillTraits[2] ) && pSoldier->stats.ubSkillTraits[0] != 0 )
|
||||
@@ -255,7 +255,7 @@ void SoldierTooltip( SOLDIERTYPE* pSoldier )
|
||||
CHAR16 pStrAux[50];
|
||||
swprintf( pStrAux, L"(%s)", gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[0]]);
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_1], pStrInfo, pStrAux );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + 19] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_2], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[2] + NEWTRAIT_MERCSKILL_EXPERTOFFSET] );
|
||||
swprintf( pStrInfo, gzTooltipStrings[STR_TT_SKILL_TRAIT_3], pStrInfo, gzMercSkillTextNew[pSoldier->stats.ubSkillTraits[1]] );
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4449,7 +4449,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
|
||||
/*// Flugente: spawn items while debugging
|
||||
if ( gusSelectedSoldier != NOBODY )
|
||||
{
|
||||
static UINT16 usitem = 1576;
|
||||
static UINT16 usitem = 142;
|
||||
static INT16 status = 100;
|
||||
static FLOAT temperature = 0.0;
|
||||
|
||||
|
||||
+65
-5
@@ -8960,8 +8960,21 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget,
|
||||
|
||||
if ( iImpact > 0 && !TANK( pTarget ) )
|
||||
{
|
||||
// Flugente: ammo can now add the lifedamage drug effect. This will kill the target in a few turns.
|
||||
// this is intended to work on darts, but it is possible on any ammo
|
||||
if ( AmmoTypes[ubAmmoType].ammoflag & AMMO_NEUROTOXIN )
|
||||
{
|
||||
pTarget->bSoldierFlagMask |= SOLDIER_DRUGGED;
|
||||
|
||||
if ( AmmoTypes[ubAmmoType].dart && sHitBy > 20 )
|
||||
// Add lifedamage effects
|
||||
pTarget->drugs.bFutureDrugEffect[ DRUG_TYPE_LIFEDAMAGE ] = min(pTarget->drugs.bFutureDrugEffect[ DRUG_TYPE_LIFEDAMAGE ] + 3, 127);
|
||||
pTarget->drugs.bDrugEffectRate[DRUG_TYPE_LIFEDAMAGE] = 1;
|
||||
pTarget->drugs.bDrugEffect[DRUG_TYPE_LIFEDAMAGE] = 0;
|
||||
pTarget->drugs.bDrugSideEffectRate[DRUG_TYPE_LIFEDAMAGE] = 0;
|
||||
pTarget->drugs.bDrugSideEffect[DRUG_TYPE_LIFEDAMAGE] = 127;
|
||||
pTarget->drugs.bTimesDrugUsedSinceSleep[ DRUG_TYPE_LIFEDAMAGE ]++;
|
||||
}
|
||||
else if ( AmmoTypes[ubAmmoType].dart && sHitBy > 20 )
|
||||
{
|
||||
if (pubSpecial)
|
||||
{
|
||||
@@ -9434,13 +9447,13 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
|
||||
|
||||
INT32 iImpact, iFluke, iBonus;
|
||||
|
||||
// Flugente: check for underbarrel weapons and use that object if necessary (think of bayonets)
|
||||
OBJECTTYPE* pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) );
|
||||
|
||||
if (fBladeAttack)
|
||||
{
|
||||
iImpact = ( EffectiveExpLevel( pSoldier ) / 2); // 0 to 4 for level
|
||||
|
||||
// Flugente: check for underbarrel weapons and use that object if necessary (think of bayonets)
|
||||
OBJECTTYPE* pObj = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) );
|
||||
|
||||
|
||||
iImpact += GetDamage(pObj);
|
||||
|
||||
iImpact += EffectiveStrength( pSoldier, FALSE ) / 20; // 0 to 5 for strength, adjusted by damage taken
|
||||
@@ -9677,6 +9690,34 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
|
||||
iBonus += 10; // +10%
|
||||
}
|
||||
|
||||
// Flugente: if we are using a garotte, there is a chance that we score an instakill
|
||||
// our level in covert ops and wether the target is aware of us has a huge impact
|
||||
if ( pObj && HasItemFlag(pObj->usItem, GAROTTE) )
|
||||
{
|
||||
INT32 instakillchance = 0;
|
||||
INT32 resistchance = 20;
|
||||
|
||||
if ( !SoldierTo3DLocationLineOfSightTest( pSoldier, pTarget->sGridNo, pTarget->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
instakillchance += 30;
|
||||
|
||||
UINT8 skilllevel = NUM_SKILL_TRAITS( pSoldier, COVERT_NT );
|
||||
instakillchance += skilllevel * gSkillTraitValues.sCoMeleeInstakillBonus;
|
||||
|
||||
if ( pTarget->aiData.bAlertStatus == STATUS_YELLOW )
|
||||
resistchance += 20;
|
||||
else if ( pTarget->aiData.bAlertStatus >= STATUS_RED )
|
||||
resistchance += 50;
|
||||
|
||||
if ( pTarget->bCollapsed )
|
||||
resistchance = 0;
|
||||
|
||||
// killchance gets lowered if garotte is in bad shape
|
||||
instakillchance *= ( (*pObj)[0]->data.objectStatus / 100 );
|
||||
|
||||
if ( Random(instakillchance) >= Random(resistchance) )
|
||||
iImpact += 500;
|
||||
}
|
||||
|
||||
// apply all bonuses
|
||||
iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly
|
||||
|
||||
@@ -9925,6 +9966,25 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
|
||||
{
|
||||
iAttRating += gSkillTraitValues.bCtHModifierHtHAttack; // Make HtH attacks a little more problematic for untrained mercs
|
||||
|
||||
// Flugente: if we are using a garotte, alter the attack rating on wether we are used in to this weapon, and wether our target can see us
|
||||
if ( HasItemFlag(usInHand, GAROTTE) )
|
||||
{
|
||||
// using a garotte is pretty hard, we get a malus as default value
|
||||
INT32 garottemodifier = -30;
|
||||
|
||||
UINT8 skilllevel = NUM_SKILL_TRAITS( pAttacker, COVERT_NT );
|
||||
garottemodifier += skilllevel * gSkillTraitValues.sCOMeleeCTHBonus;
|
||||
|
||||
if ( pDefender->bCollapsed )
|
||||
garottemodifier += 80;
|
||||
|
||||
// if this guy can see us, get a big malus!
|
||||
else if ( SoldierTo3DLocationLineOfSightTest( pAttacker, pDefender->sGridNo, pDefender->pathing.bLevel, 3, TRUE, CALC_FROM_WANTED_DIR ) )
|
||||
garottemodifier -= 80;
|
||||
|
||||
iAttRating += garottemodifier;
|
||||
}
|
||||
|
||||
// bare hands - bonus for Martial arts
|
||||
if (!pAttacker->usAttackingWeapon && HAS_SKILL_TRAIT( pAttacker, MARTIAL_ARTS_NT ))
|
||||
{
|
||||
|
||||
+47
-1
@@ -172,6 +172,49 @@ enum
|
||||
AMMO_FLAME,
|
||||
};
|
||||
|
||||
// -------- added by Flugente: various ammo flags --------
|
||||
// flags used for various ammo properties (easier than adding 32 differently named variables). DO NOT CHANGE THEM, UNLESS YOU KNOW WHAT YOU ARE DOING!!!
|
||||
#define AMMO_NEUROTOXIN 0x00000001 //1 // this ammo adds the cyanide drug effect to its target, killing it in a few turns
|
||||
/*#define FULL_SANDBAG 0x00000002 //2
|
||||
#define SHOVEL 0x00000004 //4
|
||||
#define CONCERTINA 0x00000008 //8
|
||||
|
||||
#define WATER_DRUM 0x00000010 //16 // water drums allow to refill canteens in the sector they are in
|
||||
#define MEAT_BLOODCAT 0x00000020 //32 // retrieve this by gutting a bloodcat
|
||||
#define COW_MEAT 0x00000040 //64 // retrieve this by gutting a cow
|
||||
#define BELT_FED 0x00000080 //128 // item can be fed externally
|
||||
|
||||
#define AMMO_BELT 0x00000100 //256 // this item can be used to feed externally
|
||||
#define AMMO_BELT_VEST 0x00000200 //512 // this is a vest that can contain AMMO_BELT items in its medium slots
|
||||
#define COVERT_OPS_KIT 0x00000400 //1024 // this kit can restore the covert ops disguise
|
||||
#define RAG 0x00000800 //2048 // this item is a rag and can be used to remove camo
|
||||
|
||||
#define ENEMY_NET_1_LVL_4 0x00001000 //4096
|
||||
#define ENEMY_NET_2_LVL_4 0x00002000 //8192
|
||||
#define ENEMY_NET_3_LVL_4 0x00004000 //16384
|
||||
#define ENEMY_NET_4_LVL_4 0x00008000 //32768
|
||||
|
||||
#define PLAYER_NET_1_LVL_1 0x00010000 //65536
|
||||
#define PLAYER_NET_2_LVL_1 0x00020000 //131072
|
||||
#define PLAYER_NET_3_LVL_1 0x00040000 //262144
|
||||
#define PLAYER_NET_4_LVL_1 0x00080000 //524288
|
||||
|
||||
#define PLAYER_NET_1_LVL_2 0x00100000 //1048576
|
||||
#define PLAYER_NET_2_LVL_2 0x00200000 //2097152
|
||||
#define PLAYER_NET_3_LVL_2 0x00400000 //4194304
|
||||
#define PLAYER_NET_4_LVL_2 0x00800000 //8388608
|
||||
|
||||
#define PLAYER_NET_1_LVL_3 0x01000000 //16777216
|
||||
#define PLAYER_NET_2_LVL_3 0x02000000 //33554432
|
||||
#define PLAYER_NET_3_LVL_3 0x04000000 //67108864
|
||||
#define PLAYER_NET_4_LVL_3 0x08000000 //134217728
|
||||
|
||||
#define PLAYER_NET_1_LVL_4 0x10000000 //268435456
|
||||
#define PLAYER_NET_2_LVL_4 0x20000000 //536870912
|
||||
#define PLAYER_NET_3_LVL_4 0x40000000 //1073741824
|
||||
#define PLAYER_NET_4_LVL_4 0x80000000 //2147483648*/
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 uiIndex;
|
||||
@@ -216,10 +259,13 @@ typedef struct
|
||||
BOOLEAN tracerEffect;
|
||||
FLOAT temperatureModificator; // Flugente: modificator for weapon temperature
|
||||
INT16 poisonPercentage; // Flugente: modificator for weapon temperature
|
||||
FLOAT dirtModificator; // Flugente: modificator for weapon temperature
|
||||
FLOAT dirtModificator; // Flugente: modificator for dirt generation
|
||||
|
||||
//zilpin: pellet spread patterns externalized in XML
|
||||
INT32 spreadPattern;
|
||||
|
||||
// Flugente: item flag for various properties. Way easier than 32 boolean flags
|
||||
UINT32 ammoflag;
|
||||
|
||||
} AMMOTYPE;
|
||||
|
||||
|
||||
+39
-33
@@ -81,7 +81,8 @@ ammotypeStartElementHandle(void *userData, const XML_Char *name, const XML_Char
|
||||
strcmp(name, "monsterSpit") == 0 ||
|
||||
strcmp(name, "temperatureModificator") == 0 ||
|
||||
strcmp(name, "PoisonPercentage") == 0 ||
|
||||
strcmp(name, "dirtModificator") == 0 ))
|
||||
strcmp(name, "dirtModificator") == 0 ||
|
||||
strcmp(name, "ammoflag") == 0 ))
|
||||
{
|
||||
pData->curElement = ELEMENT_PROPERTY;
|
||||
|
||||
@@ -298,6 +299,11 @@ ammotypeEndElementHandle(void *userData, const XML_Char *name)
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curAmmoType.dirtModificator = (FLOAT) atof(pData->szCharData);
|
||||
}
|
||||
else if(strcmp(name, "ammoflag") == 0)
|
||||
{
|
||||
pData->curElement = ELEMENT;
|
||||
pData->curAmmoType.ammoflag = (UINT32) atol(pData->szCharData);
|
||||
}
|
||||
|
||||
pData->maxReadDepth--;
|
||||
}
|
||||
@@ -390,39 +396,39 @@ BOOLEAN WriteAmmoTypeStats()
|
||||
|
||||
FilePrintf(hFile,"\t<AMMOTYPE>\r\n");
|
||||
|
||||
FilePrintf(hFile,"\t\t<uiIndex>%d</uiIndex>\r\n", cnt );
|
||||
FilePrintf(hFile,"\t\t<fontColour>%d</fontColour>\r\n", AmmoTypes[cnt].fontColour );
|
||||
FilePrintf(hFile,"\t\t<grayed>%d</grayed>\r\n", AmmoTypes[cnt].grayed );
|
||||
FilePrintf(hFile,"\t\t<offNormal>%d</offNormal>\r\n", AmmoTypes[cnt].offNormal );
|
||||
FilePrintf(hFile,"\t\t<onNormal>%d</onNormal>\r\n", AmmoTypes[cnt].onNormal );
|
||||
FilePrintf(hFile,"\t\t<structureImpactReductionMultiplier>%d</structureImpactReductionMultiplier>\r\n", AmmoTypes[cnt].structureImpactReductionMultiplier );
|
||||
FilePrintf(hFile,"\t\t<structureImpactReductionDivisor>%d</structureImpactReductionDivisor>\r\n", AmmoTypes[cnt].structureImpactReductionDivisor );
|
||||
FilePrintf(hFile,"\t\t<armourImpactReductionMultiplier>%d</armourImpactReductionMultiplier>\r\n", AmmoTypes[cnt].armourImpactReductionMultiplier );
|
||||
FilePrintf(hFile,"\t\t<armourImpactReductionDivisor>%d</armourImpactReductionDivisor>\r\n", AmmoTypes[cnt].armourImpactReductionDivisor );
|
||||
FilePrintf(hFile,"\t\t<beforeArmourDamageMultiplier>%d</beforeArmourDamageMultiplier>\r\n", AmmoTypes[cnt].beforeArmourDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<beforeArmourDamageDivisor>%d</beforeArmourDamageDivisor>\r\n", AmmoTypes[cnt].beforeArmourDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<afterArmourDamageMultiplier>%d</afterArmourDamageMultiplier>\r\n", AmmoTypes[cnt].afterArmourDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<afterArmourDamageDivisor>%d</afterArmourDamageDivisor>\r\n", AmmoTypes[cnt].afterArmourDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<zeroMinimumDamage>%d</zeroMinimumDamage>\r\n", AmmoTypes[cnt].zeroMinimumDamage );
|
||||
FilePrintf(hFile,"\t\t<canGoThrough>%d</canGoThrough>\r\n", AmmoTypes[cnt].canGoThrough );
|
||||
FilePrintf(hFile,"\t\t<standardIssue>%d</standardIssue>\r\n", AmmoTypes[cnt].standardIssue );
|
||||
FilePrintf(hFile,"\t\t<numberOfBullets>%d</numberOfBullets>\r\n", AmmoTypes[cnt].numberOfBullets );
|
||||
FilePrintf(hFile,"\t\t<multipleBulletDamageMultiplier>%d</multipleBulletDamageMultiplier>\r\n", AmmoTypes[cnt].multipleBulletDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<multipleBulletDamageDivisor>%d</multipleBulletDamageDivisor>\r\n", AmmoTypes[cnt].multipleBulletDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<highExplosive>%d</highExplosive>\r\n", AmmoTypes[cnt].highExplosive );
|
||||
FilePrintf(hFile,"\t\t<explosionSize>%d</explosionSize>\r\n", AmmoTypes[cnt].explosionSize );
|
||||
FilePrintf(hFile,"\t\t<antiTank>%d</antiTank>\r\n", AmmoTypes[cnt].antiTank );
|
||||
FilePrintf(hFile,"\t\t<dart>%d</dart>\r\n", AmmoTypes[cnt].dart );
|
||||
FilePrintf(hFile,"\t\t<knife>%d</knife>\r\n", AmmoTypes[cnt].knife );
|
||||
FilePrintf(hFile,"\t\t<monsterSpit>%d</monsterSpit>\r\n", AmmoTypes[cnt].monsterSpit );
|
||||
FilePrintf(hFile,"\t\t<acidic>%d</acidic>\r\n", AmmoTypes[cnt].acidic );
|
||||
FilePrintf(hFile,"\t\t<ignoreArmour>%d</ignoreArmour>\r\n", AmmoTypes[cnt].ignoreArmour );
|
||||
FilePrintf(hFile,"\t\t<lockBustingPower>%d</lockBustingPower>\r\n", AmmoTypes[cnt].lockBustingPower );
|
||||
FilePrintf(hFile,"\t\t<tracerEffect>%d</tracerEffect>\r\n", AmmoTypes[cnt].tracerEffect );
|
||||
FilePrintf(hFile,"\t\t<temperatureModificator>%4.2f</temperatureModificator>\r\n", AmmoTypes[cnt].temperatureModificator );
|
||||
FilePrintf(hFile,"\t\t<PoisonPercentage>%d</PoisonPercentage>\r\n", AmmoTypes[cnt].poisonPercentage );
|
||||
FilePrintf(hFile,"\t\t<uiIndex>%d</uiIndex>\r\n", cnt );
|
||||
FilePrintf(hFile,"\t\t<fontColour>%d</fontColour>\r\n", AmmoTypes[cnt].fontColour );
|
||||
FilePrintf(hFile,"\t\t<grayed>%d</grayed>\r\n", AmmoTypes[cnt].grayed );
|
||||
FilePrintf(hFile,"\t\t<offNormal>%d</offNormal>\r\n", AmmoTypes[cnt].offNormal );
|
||||
FilePrintf(hFile,"\t\t<onNormal>%d</onNormal>\r\n", AmmoTypes[cnt].onNormal );
|
||||
FilePrintf(hFile,"\t\t<structureImpactReductionMultiplier>%d</structureImpactReductionMultiplier>\r\n", AmmoTypes[cnt].structureImpactReductionMultiplier );
|
||||
FilePrintf(hFile,"\t\t<structureImpactReductionDivisor>%d</structureImpactReductionDivisor>\r\n", AmmoTypes[cnt].structureImpactReductionDivisor );
|
||||
FilePrintf(hFile,"\t\t<armourImpactReductionMultiplier>%d</armourImpactReductionMultiplier>\r\n", AmmoTypes[cnt].armourImpactReductionMultiplier );
|
||||
FilePrintf(hFile,"\t\t<armourImpactReductionDivisor>%d</armourImpactReductionDivisor>\r\n", AmmoTypes[cnt].armourImpactReductionDivisor );
|
||||
FilePrintf(hFile,"\t\t<beforeArmourDamageMultiplier>%d</beforeArmourDamageMultiplier>\r\n", AmmoTypes[cnt].beforeArmourDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<beforeArmourDamageDivisor>%d</beforeArmourDamageDivisor>\r\n", AmmoTypes[cnt].beforeArmourDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<afterArmourDamageMultiplier>%d</afterArmourDamageMultiplier>\r\n", AmmoTypes[cnt].afterArmourDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<afterArmourDamageDivisor>%d</afterArmourDamageDivisor>\r\n", AmmoTypes[cnt].afterArmourDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<zeroMinimumDamage>%d</zeroMinimumDamage>\r\n", AmmoTypes[cnt].zeroMinimumDamage );
|
||||
FilePrintf(hFile,"\t\t<canGoThrough>%d</canGoThrough>\r\n", AmmoTypes[cnt].canGoThrough );
|
||||
FilePrintf(hFile,"\t\t<standardIssue>%d</standardIssue>\r\n", AmmoTypes[cnt].standardIssue );
|
||||
FilePrintf(hFile,"\t\t<numberOfBullets>%d</numberOfBullets>\r\n", AmmoTypes[cnt].numberOfBullets );
|
||||
FilePrintf(hFile,"\t\t<multipleBulletDamageMultiplier>%d</multipleBulletDamageMultiplier>\r\n", AmmoTypes[cnt].multipleBulletDamageMultiplier );
|
||||
FilePrintf(hFile,"\t\t<multipleBulletDamageDivisor>%d</multipleBulletDamageDivisor>\r\n", AmmoTypes[cnt].multipleBulletDamageDivisor );
|
||||
FilePrintf(hFile,"\t\t<highExplosive>%d</highExplosive>\r\n", AmmoTypes[cnt].highExplosive );
|
||||
FilePrintf(hFile,"\t\t<explosionSize>%d</explosionSize>\r\n", AmmoTypes[cnt].explosionSize );
|
||||
FilePrintf(hFile,"\t\t<antiTank>%d</antiTank>\r\n", AmmoTypes[cnt].antiTank );
|
||||
FilePrintf(hFile,"\t\t<dart>%d</dart>\r\n", AmmoTypes[cnt].dart );
|
||||
FilePrintf(hFile,"\t\t<knife>%d</knife>\r\n", AmmoTypes[cnt].knife );
|
||||
FilePrintf(hFile,"\t\t<monsterSpit>%d</monsterSpit>\r\n", AmmoTypes[cnt].monsterSpit );
|
||||
FilePrintf(hFile,"\t\t<acidic>%d</acidic>\r\n", AmmoTypes[cnt].acidic );
|
||||
FilePrintf(hFile,"\t\t<ignoreArmour>%d</ignoreArmour>\r\n", AmmoTypes[cnt].ignoreArmour );
|
||||
FilePrintf(hFile,"\t\t<lockBustingPower>%d</lockBustingPower>\r\n", AmmoTypes[cnt].lockBustingPower );
|
||||
FilePrintf(hFile,"\t\t<tracerEffect>%d</tracerEffect>\r\n", AmmoTypes[cnt].tracerEffect );
|
||||
FilePrintf(hFile,"\t\t<temperatureModificator>%4.2f</temperatureModificator>\r\n", AmmoTypes[cnt].temperatureModificator );
|
||||
FilePrintf(hFile,"\t\t<PoisonPercentage>%d</PoisonPercentage>\r\n", AmmoTypes[cnt].poisonPercentage );
|
||||
FilePrintf(hFile,"\t\t<dirtModificator>%4.2f</dirtModificator>\r\n", AmmoTypes[cnt].dirtModificator );
|
||||
|
||||
FilePrintf(hFile,"\t\t<ammoflag>%d</ammoflag>\r\n", AmmoTypes[cnt].ammoflag );
|
||||
|
||||
FilePrintf(hFile,"\t</AMMOTYPE>\r\n");
|
||||
}
|
||||
|
||||
+47
-33
@@ -446,7 +446,7 @@ void ReevaluateBestSightingPosition( SOLDIERTYPE * pSoldier, INT8 bInterruptDuel
|
||||
{
|
||||
for ( ubLoop = 0; ubLoop < gubBestToMakeSightingSize; ubLoop++ )
|
||||
{
|
||||
if ( (gubBestToMakeSighting[ ubLoop ] == NOBODY) || (bInterruptDuelPts > MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) )
|
||||
if ( pSoldier->RecognizeAsCombatant(gubBestToMakeSighting[ ubLoop ]) && (gubBestToMakeSighting[ ubLoop ] == NOBODY) || (bInterruptDuelPts > MercPtrs[ gubBestToMakeSighting[ ubLoop ] ]->aiData.bInterruptDuelPts ) )
|
||||
{
|
||||
if ( gubBestToMakeSighting[ gubBestToMakeSightingSize - 1 ] != NOBODY )
|
||||
{
|
||||
@@ -509,36 +509,43 @@ void HandleBestSightingPositionInRealtime( void )
|
||||
if (gubBestToMakeSighting[ 1 ] == NOBODY)
|
||||
{ // The_Bob - real time sneaking code 01/06/09
|
||||
// if real time sneaking conditions are met...
|
||||
// this is now in the preferences window - SANDRO
|
||||
// this is now in the preferences window - SANDRO
|
||||
if (gGameSettings.fOptions[TOPTION_ALLOW_REAL_TIME_SNEAK] && MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == OUR_TEAM && NobodyAlerted() )
|
||||
{
|
||||
// get rid of the item under cursor (we gotta react FAST)
|
||||
CancelItemPointer();
|
||||
// select (and center screen on) the merc who saw the enemy
|
||||
// HEADROCK HAM 3.6: A much-requested toggle.
|
||||
if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID &&
|
||||
!gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak)
|
||||
SelectSoldier (MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID, false, true);
|
||||
// if not quiet, emit a message warning the player
|
||||
if (!gGameExternalOptions.fQuietRealTimeSneak)
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_ENEMIES_SPOOTED]);
|
||||
{
|
||||
// get rid of the item under cursor (we gotta react FAST)
|
||||
CancelItemPointer();
|
||||
// select (and center screen on) the merc who saw the enemy
|
||||
// HEADROCK HAM 3.6: A much-requested toggle.
|
||||
if (gusSelectedSoldier != (UINT16)MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID &&
|
||||
!gGameExternalOptions.fNoAutoFocusChangeInRealtimeSneak)
|
||||
SelectSoldier (MercPtrs[gubBestToMakeSighting[ 0 ]]->ubID, false, true);
|
||||
// if not quiet, emit a message warning the player
|
||||
if (!gGameExternalOptions.fQuietRealTimeSneak)
|
||||
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[MSG113_RTM_ENEMIES_SPOOTED]);
|
||||
|
||||
return; // and do nothing
|
||||
}
|
||||
return; // and do nothing
|
||||
}
|
||||
else if ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam != OUR_TEAM && MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 )
|
||||
{
|
||||
// otherwise, simply award the turn to the team that saw the enemy first
|
||||
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
||||
}
|
||||
else
|
||||
// otherwise, simply award the turn to the team that saw the enemy first
|
||||
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
// if 1st and 2nd on same team, or 1st and 3rd on same team, or there IS no 3rd, award turn to 1st
|
||||
if ( ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam ) ||
|
||||
if ( /*MercPtrs[gubBestToMakeSighting[ 0 ]]->aiData.bOppCnt > 0 &&*/ ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 1 ]]->bTeam ) ||
|
||||
( (gubBestToMakeSighting[ 2 ] == NOBODY) || ( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam == MercPtrs[gubBestToMakeSighting[ 2 ]]->bTeam ) )
|
||||
)
|
||||
{
|
||||
EnterCombatMode( MercPtrs[gubBestToMakeSighting[ 0 ]]->bTeam );
|
||||
}
|
||||
else // give turn to 2nd best but interrupt to 1st
|
||||
else //if ( MercPtrs[gubBestToMakeSighting[ 1 ]]->aiData.bOppCnt > 0 ) // give turn to 2nd best but interrupt to 1st
|
||||
{
|
||||
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Entering combat mode: turn for 2nd best, int for best" );
|
||||
|
||||
@@ -1766,7 +1773,7 @@ void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT
|
||||
{
|
||||
// if neither side is neutral AND
|
||||
// if this soldier is an opponent (fights for different side)
|
||||
if (pSoldier->bActive && pOpponent->bActive && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide))
|
||||
if (pSoldier->bActive && pOpponent->bActive && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
{
|
||||
RemoveOneOpponent(pSoldier);
|
||||
}
|
||||
@@ -2199,6 +2206,9 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo,
|
||||
return;
|
||||
}
|
||||
|
||||
// Flugente: update our sight concerning this guy, otherwise we could get way with open attacks because this does not get updated
|
||||
pSoldier->RecognizeAsCombatant(pOpponent->ubID);
|
||||
|
||||
// if we're seeing a guy we didn't see on our last chance to look for him
|
||||
if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_CURRENTLY)
|
||||
{
|
||||
@@ -2503,7 +2513,7 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo,
|
||||
|
||||
// if both of us are not neutral, AND
|
||||
// if this man is actually a true opponent (we're not on the same side)
|
||||
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide))
|
||||
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
{
|
||||
AddOneOpponent(pSoldier);
|
||||
|
||||
@@ -3002,7 +3012,7 @@ IAN COMMENTED THIS OUT MAY 1997 - DO WE NEED THIS?
|
||||
if (pOpponent)
|
||||
{
|
||||
// check to see if OPPONENT considers US neutral
|
||||
if ( (pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY) && !pOpponent->aiData.bNeutral && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && (pSoldier->bSide != pOpponent->bSide) )
|
||||
if ( (pOpponent->aiData.bOppList[ubTarget] == SEEN_CURRENTLY) && !pOpponent->aiData.bNeutral && !CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && (pSoldier->bSide != pOpponent->bSide) && pOpponent->RecognizeAsCombatant(pSoldier->ubID) )
|
||||
{
|
||||
RemoveOneOpponent(pOpponent);
|
||||
}
|
||||
@@ -3501,20 +3511,24 @@ void SaySeenQuote( SOLDIERTYPE *pSoldier, BOOLEAN fSeenCreature, BOOLEAN fVirgin
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flugente: no quotes on seeing enemy when covert
|
||||
if ( (pSoldier->bSoldierFlagMask & (SOLDIER_COVERT_CIV|SOLDIER_COVERT_SOLDIER) ) == 0 )
|
||||
{
|
||||
#ifdef ENGLISH
|
||||
if ( Random( 100 ) < 30 )
|
||||
{
|
||||
pSoldier->DoMercBattleSound( BATTLE_SOUND_ENEMY );
|
||||
}
|
||||
else
|
||||
{
|
||||
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
}
|
||||
if ( Random( 100 ) < 30 )
|
||||
{
|
||||
pSoldier->DoMercBattleSound( BATTLE_SOUND_ENEMY );
|
||||
}
|
||||
else
|
||||
{
|
||||
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
}
|
||||
#else
|
||||
//ddd TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) )
|
||||
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
//ddd TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
if(Chance(gGameExternalOptions.iChanceSayAnnoyingPhrase) )
|
||||
TacticalCharacterDialogue( pSoldier, QUOTE_SEE_ENEMY );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6821,7 +6835,7 @@ void DecayIndividualOpplist(SOLDIERTYPE *pSoldier)
|
||||
{
|
||||
// they are NOT visible now!
|
||||
(*pPersOL)++;
|
||||
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide))
|
||||
if (!CONSIDERED_NEUTRAL( pOpponent, pSoldier ) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
{
|
||||
RemoveOneOpponent(pSoldier);
|
||||
}
|
||||
@@ -7084,7 +7098,7 @@ void RecalculateOppCntsDueToBecomingNeutral( SOLDIERTYPE * pSoldier )
|
||||
pOpponent = MercSlots[uiLoop];
|
||||
|
||||
// for every active, living soldier on ANOTHER team
|
||||
if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) )
|
||||
if (pOpponent && pOpponent->stats.bLife && !pOpponent->aiData.bNeutral && (pOpponent->bTeam != pSoldier->bTeam) && !CONSIDERED_NEUTRAL( pSoldier, pOpponent ) && (pSoldier->bSide != pOpponent->bSide) && pSoldier->RecognizeAsCombatant(pOpponent->ubID) )
|
||||
{
|
||||
if ( pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY )
|
||||
{
|
||||
|
||||
@@ -157,12 +157,21 @@ typedef enum
|
||||
DEMOLITIONS_NT, // 17
|
||||
TEACHING_NT, // 18
|
||||
SCOUTING_NT, // 19
|
||||
|
||||
// Flugente: new traits have to go here, even if they are major traits, as otherwise the existing traits in profiles get mixed up
|
||||
COVERT_NT, // 20
|
||||
|
||||
NUM_SKILLTRAITS_NT
|
||||
} SkillTraitNew;
|
||||
|
||||
#define NUM_MAJOR_TRAITS 9
|
||||
#define NUM_MAJOR_TRAITS 10
|
||||
#define NUM_MINOR_TRAITS 10
|
||||
|
||||
// Flugente: I've had it with this hardcoding madness. Without this, adding or removing a new trait would crash anything related to a bubblehelp display of traits
|
||||
// always check every use of these enums and every use of the skill-strings if you add a new trait
|
||||
#define NEWTRAIT_MERCSKILL_EXPERTOFFSET NUM_MAJOR_TRAITS + NUM_MINOR_TRAITS
|
||||
#define NEWTRAIT_MERCSKILL_OFFSET_ALL NEWTRAIT_MERCSKILL_EXPERTOFFSET + NUM_MAJOR_TRAITS
|
||||
|
||||
// SANDRO - new set of character traits
|
||||
typedef enum
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user