- New feature: zombies can now spawn from corpses, if you specify that option in the preferences screen (by Flugente)

o if set to off, no zombies will spawn. This can also be changed in mid-game
o for more information on how this works and how to set it up, see http://www.bears-pit.com/board/ubbthreads.php/topics/295746/Zombies_WH40K_and_more.html#Post295746
o with the tag <PoisonPercentage>, you can now poison guns or ammo. This is the percentage of damage dealt that will be poisonous (see zombie thread for an explanation)
o The zombie option can only be enabled in a single player game

o AI fix: to prevent the endless clock problem, the AI now ends the turn if the same actor calls the decision routine over 100 times in a single turn.

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@5313 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Wanne
2012-05-29 22:49:17 +00:00
parent 744ce2ee9c
commit c90f4bce47
73 changed files with 4481 additions and 609 deletions
+27 -1
View File
@@ -1305,16 +1305,42 @@ BOOLEAN RenderSoldierSmallFaceForAutoBandagePanel( INT32 iIndex, INT16 sCurrentX
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 107, 107, 57 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 222, 181, 115 ) ) );
// poisoned bleeding in purple
if ( pSoldier->bPoisonBleeding )
{
iStartY = sCurrentYPosition + 29 - 27*(pSoldier->stats.bLifeMax - pSoldier->bBleeding + pSoldier->bPoisonBleeding)/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 107, 57, 107 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 222, 115, 181 ) ) );
}
//pink one for bandaged.
iStartY += 27*pSoldier->bBleeding/100;
iStartY = sCurrentYPosition + 29 - 27*(pSoldier->stats.bLifeMax - pSoldier->bBleeding)/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 156, 57, 57 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 222, 132, 132 ) ) );
// get amount of poisoned bandage
INT8 bPoisonBandage = pSoldier->bPoisonSum - pSoldier->bPoisonBleeding - pSoldier->bPoisonLife;
if ( bPoisonBandage )
{
// poisoned bandage in bright green
iStartY = sCurrentYPosition + 29 - 27*(pSoldier->stats.bLife + bPoisonBandage)/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 57, 156, 57 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 132, 222, 132 ) ) );
}
//red one for actual health
iStartY = sCurrentYPosition + 29 - 27*pSoldier->stats.bLife/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 107, 8, 8 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 206, 0, 0 ) ) );
// poisoned life
if ( pSoldier->bPoisonLife )
{
iStartY = sCurrentYPosition + 29 - 27*pSoldier->bPoisonLife/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+36, iStartY, sCurrentXPosition+37, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 8, 107, 8 ) ) );
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+37, iStartY, sCurrentXPosition+38, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 0, 206, 0 ) ) );
}
//BREATH BAR
iStartY = sCurrentYPosition + 29 - 27*pSoldier->bBreathMax/100;
ColorFillVideoSurfaceArea( FRAME_BUFFER, sCurrentXPosition+39, iStartY, sCurrentXPosition+40, sCurrentYPosition+29, Get16BPPColor( FROMRGB( 8, 8, 132 ) ) );
+4
View File
@@ -1035,6 +1035,10 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType )
VIDEO_OVERLAY_DESC VideoOverlayDesc;
CHAR16 gzTauntQuote[ 320 ];
// Flugente: zombies don't talk
if ( pCiv->IsZombie() )
return;
// if we have a different quote on, return, this one is not important
if ( gCivQuoteData.bActive )
{
+4 -1
View File
@@ -334,8 +334,9 @@ void HandleEndTurnDrugAdjustments( SOLDIERTYPE *pSoldier )
// bBandaged = BANDAGED( pSoldier );
// increase life
pSoldier->bPoisonLife = max(pSoldier->bPoisonSum, pSoldier->bPoisonLife + pSoldier->stats.bLife - __min( pSoldier->stats.bLife + LIFE_GAIN_PER_REGEN_POINT, pSoldier->stats.bLifeMax ) );
pSoldier->stats.bLife = __min( pSoldier->stats.bLife + LIFE_GAIN_PER_REGEN_POINT, pSoldier->stats.bLifeMax );
//SANDRO - Insta-healable injury reduction
if( pSoldier->iHealableInjury > 0 )
{
@@ -345,12 +346,14 @@ void HandleEndTurnDrugAdjustments( SOLDIERTYPE *pSoldier )
if ( pSoldier->stats.bLife == pSoldier->stats.bLifeMax )
{
pSoldier->bBleeding = 0;
pSoldier->bPoisonBleeding = 0;
pSoldier->iHealableInjury = 0;
}
else if ( pSoldier->bBleeding + pSoldier->stats.bLife > pSoldier->stats.bLifeMax )
{
// got to reduce amount of bleeding
pSoldier->bBleeding = (pSoldier->stats.bLifeMax - pSoldier->stats.bLife);
pSoldier->bPoisonBleeding = min(pSoldier->bPoisonBleeding, (pSoldier->stats.bLifeMax - pSoldier->stats.bLife));
}
// decrement counter
+1 -1
View File
@@ -4575,7 +4575,7 @@ void SetOffBoobyTrapInMapScreen( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObject )
}
// injure the inventory character
pSoldier->SoldierTakeDamage( 0, ubPtsDmg, ubPtsDmg, TAKE_DAMAGE_EXPLOSION, NOBODY, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( 0, ubPtsDmg, 0, ubPtsDmg, TAKE_DAMAGE_EXPLOSION, NOBODY, NOWHERE, 0, TRUE );
// play the sound
PlayJA2Sample( EXPLOSION_1, RATE_11025, BTNVOLUME, 1, MIDDLEPAN );
+14 -4
View File
@@ -760,13 +760,23 @@ void RenderTopmostTacticalInterface( )
SetFontForeground( FONT_MCOLOR_WHITE );
bool showDamage = true;
if (gGameExternalOptions.ubEnemyHitCount > 0 && pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == CREATURE_TEAM)
if (gGameExternalOptions.ubEnemyHitCount > 0 && ( pSoldier->bTeam == ENEMY_TEAM || pSoldier->bTeam == CREATURE_TEAM) )
showDamage = false;
if (showDamage)
{
gprintfdirty( sDamageX, sDamageY, L"-%d", pSoldier->sDamage );
mprintf( sDamageX, sDamageY, L"-%d", pSoldier->sDamage );
{
if ( pSoldier->sDamage >= 0 )
{
gprintfdirty( sDamageX, sDamageY, L"-%d", pSoldier->sDamage );
mprintf( sDamageX, sDamageY, L"-%d", pSoldier->sDamage );
}
else // Flugente: it is possible that someone might regain negative damage as zombies can regenerate health through bleeding
{
SetFontForeground( FONT_MCOLOR_LTGREEN );
gprintfdirty( sDamageX, sDamageY, L"+%d", -pSoldier->sDamage );
mprintf( sDamageX, sDamageY, L"+%d", -pSoldier->sDamage );
SetFontForeground( FONT_MCOLOR_WHITE );
}
}
else
{
+4
View File
@@ -2268,6 +2268,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum
DeleteTalkingMenu();
SetSoldierNeutral( pSoldier );
pSoldier->bBleeding = 0; // make sure he doesn't bleed now...
pSoldier->bPoisonBleeding = 0;
RecalculateOppCntsDueToBecomingNeutral( pSoldier );
if ( gTacticalStatus.uiFlags & INCOMBAT )
{
@@ -4445,6 +4446,9 @@ UINT32 CalcPatientMedicalCost( SOLDIERTYPE * pSoldier )
uiCost += ( 25 * ( OKLIFE - pSoldier->stats.bLife ) );
}
// charge additional $13 for every poison point that has to be cured
uiCost += 13 * pSoldier->bPoisonSum;
// also charge $2 for each point of bleeding that must be stopped
if ( pSoldier->bBleeding > 0 )
{
+164 -236
View File
@@ -95,6 +95,8 @@ UINT32 guiItemInfoArmorIcon;
UINT32 guiItemInfoSecondaryIcon;
// HEADROCK HAM 4: This replaces "Misc" icons.
UINT32 guiItemInfoAdvancedIcon;
// Flugente: added icons for WH40K
UINT32 guiItemInfoWH40KIcon;
// HEADROCK HAM 4: New tooltip regions for UDB replace the old regions.
#define NUM_UDB_FASTHELP_REGIONS 102
@@ -1376,6 +1378,10 @@ BOOLEAN InternalInitEnhancedDescBox()
strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoAdvancedIcons.STI" );
CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoAdvancedIcon ) );
// Flugente: added icons for WH40K
VObjectDesc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
strcpy( VObjectDesc.ImageFile, "INTERFACE\\ItemInfoWH40KIcons.STI" );
CHECKF( AddVideoObject( &VObjectDesc, &guiItemInfoWH40KIcon ) );
}
return (TRUE);
@@ -1879,7 +1885,7 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
CHAR16 pStr[1000];
///////////////// PRIMARY DATA - ICONS
for (cnt = 0; cnt < 4; cnt++)
for (cnt = 0; cnt < 5; cnt++)
{
MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ],
(INT16)(gItemDescGenRegions[cnt][0].sLeft),
@@ -1919,6 +1925,14 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 3 ] );
}
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
//////////////////// POISON PERCENTAGE
{
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + 4 ] );
}
}
}
}
@@ -3850,6 +3864,51 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
}
}
}
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
if(!cnt) cnt += 2;
if (cnt >= sFirstLine && cnt < sLastLine)
{
SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), gzUDBGenIndexTooltipText[ 0 ] );
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] );
iRegionsCreated++;
for (cnt2 = 1; cnt2 < 4; cnt2++)
{
MSYS_DefineRegion( &gUDBFasthelpRegions[ iRegionsCreated ],
(INT16)(gItemDescAdvIndexRegions[cnt-sFirstLine][cnt2].sLeft),
(INT16)(gItemDescAdvIndexRegions[cnt-sFirstLine][cnt2].sTop),
(INT16)(gItemDescAdvIndexRegions[cnt-sFirstLine][cnt2].sRight),
(INT16)(gItemDescAdvIndexRegions[cnt-sFirstLine][cnt2].sBottom),
MSYS_PRIORITY_HIGHEST, MSYS_NO_CURSOR, MSYS_NO_CALLBACK, ItemDescCallback );
MSYS_AddRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) + cnt2]);
SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) + cnt2]), gzUDBGenIndexTooltipText[ cnt2 ] );
SetRegionHelpEndCallback( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) + cnt2]), HelpTextDoneCallback );
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) + cnt2] );
iRegionsCreated++;
}
}
++cnt;
///////////////////// poison percentage
// only draw if item is poisoned in any way
if ( Item[gpItemDescObject->usItem].bPoisonPercentage != 0 || (Item[gpItemDescObject->usItem].usItemClass == IC_GUN && AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].poisonPercentage != 0 ) )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[ 56 ], szUDBAdvStatsExplanationsTooltipText[ 56 ]);
SetRegionFastHelpText( &(gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ]), pStr );
MSYS_EnableRegion( &gUDBFasthelpRegions[ iFirstDataRegion + (cnt-sFirstLine) ] );
}
cnt++;
}
}
gubDescBoxTotalAdvLines = (UINT8)cnt;
}
@@ -3866,6 +3925,7 @@ void DeleteEnhancedDescBox( UINT32 guiCurrentItemDescriptionScreen )
// HEADROCK HAM 4: Delete new icons
DeleteVideoObjectFromIndex( guiItemInfoSecondaryIcon );
DeleteVideoObjectFromIndex( guiItemInfoAdvancedIcon );
DeleteVideoObjectFromIndex( guiItemInfoWH40KIcon );
if ( UsingEDBSystem() > 0 )
{
@@ -4244,6 +4304,13 @@ void DrawAmmoStats( OBJECTTYPE * gpItemDescObject )
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAmmoIcon, 16, gItemDescGenRegions[3][0].sLeft+sOffsetX, gItemDescGenRegions[3][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
//////////////// POISON PERCENTAGE
{
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWH40KIcon, 6, gItemDescGenRegions[4][0].sLeft+sOffsetX, gItemDescGenRegions[4][0].sTop+sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
}
DrawSecondaryStats( gpItemDescObject );
}
@@ -5130,6 +5197,25 @@ void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject )
}
}
}
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
if(!cnt) cnt += 2;
++cnt; // for the new index-line
///////////////////// poison percentage
// only draw if item is poisoned in any way
if ( Item[gpItemDescObject->usItem].bPoisonPercentage != 0 || (Item[gpItemDescObject->usItem].usItemClass == IC_GUN && AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].poisonPercentage != 0 ) )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoWH40KIcon, 6, gItemDescAdvRegions[cnt-sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt-sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
cnt++;
}
}
}
void DrawMiscStats( OBJECTTYPE * gpItemDescObject )
@@ -7246,7 +7332,6 @@ void DrawWeaponValues( OBJECTTYPE * gpItemDescObject )
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
}
}
if (gubDescBoxPage == 2)
{
@@ -7511,6 +7596,59 @@ void DrawAmmoValues( OBJECTTYPE * gpItemDescObject, int shotsLeft )
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
}
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] ) // Flugente Zombies
{
///////////////////// POISON PERCENTAGE
// Set line to draw into
ubNumLine = 4;
// Set Y coordinates
sTop = gItemDescGenRegions[ubNumLine][1].sTop;
sHeight = gItemDescGenRegions[ubNumLine][1].sBottom - sTop;
// base modificator
INT16 basevalue = AmmoTypes[Magazine[ Item[ gpItemDescObject->usItem ].ubClassIndex].ubAmmoType].poisonPercentage;
INT16 modificator = 0; // Does not exist (yet?)
INT16 finalvalue = basevalue - modificator;
// Print base value
SetFontForeground( 5 );
sLeft = gItemDescGenRegions[ubNumLine][1].sLeft;
sWidth = gItemDescGenRegions[ubNumLine][1].sRight - sLeft;
swprintf( pStr, L"%d", basevalue );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
// modifier
SetFontForeground( 5 );
if ( modificator > 0 )
{
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%d", modificator );
}
else if ( modificator < 0 )
{
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%d", modificator );
}
else
{
swprintf( pStr, L"--" );
}
sLeft = gItemDescGenRegions[ubNumLine][2].sLeft;
sWidth = gItemDescGenRegions[ubNumLine][2].sRight - sLeft;
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
// Print final value
SetFontForeground( FONT_MCOLOR_WHITE );
sLeft = gItemDescGenRegions[ubNumLine][3].sLeft;
sWidth = gItemDescGenRegions[ubNumLine][3].sRight - sLeft;
swprintf( pStr, L"%d", finalvalue );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
mprintf( usX, usY, pStr );
}
}
else if (gubDescBoxPage == 2)
{
@@ -10660,47 +10798,6 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
cnt++;
}
///////////////////// MAX COUNTER FORCE
iFloatModifier[0] = CalcCounterForceMax( gpItemDescSoldier, gpItemDescObject, ANIM_STAND );
iFloatModifier[1] = CalcCounterForceMax( gpItemDescSoldier, gpItemDescObject, ANIM_CROUCH );
iFloatModifier[2] = CalcCounterForceMax( gpItemDescSoldier, gpItemDescObject, ANIM_PRONE );
if ((iFloatModifier[0] != 0 || iFloatModifier[1] != 0 || iFloatModifier[2] != 0) && UsingNewCTHSystem() == true && Item[gpItemDescObject->usItem].usItemClass == IC_GUN )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
// Print Values
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
{
SetFontForeground( 5 );
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
if (iFloatModifier[cnt2] > 0)
{
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
else if (iFloatModifier[cnt2] < 0)
{
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%3.1f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
else
{
swprintf( pStr, L"--" );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
mprintf( usX, usY, pStr );
}
}
cnt++;
}
// HEADROCK HAM 5: Counter-Force Frequency has been removed from the game in favour of a more realistic system.
/*
@@ -10783,7 +10880,7 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
iFloatModifier[0] = Weapon[ Item[gpItemDescObject->usItem].ubClassIndex].usOverheatingSingleShotTemperature;
iFloatModifier[0] = Weapon[ gpItemDescObject->usItem ].usOverheatingSingleShotTemperature;
iFloatModifier[1] = GetSingleShotTemperature( gpItemDescObject ) - iFloatModifier[0];
iFloatModifier[2] = GetSingleShotTemperature( gpItemDescObject );
@@ -10890,7 +10987,7 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
iFloatModifier[0] = Weapon[ Item[gpItemDescObject->usItem].ubClassIndex].usOverheatingJamThreshold;
iFloatModifier[0] = Weapon[ gpItemDescObject->usItem ].usOverheatingJamThreshold;
iFloatModifier[1] = GetOverheatJamThreshold(gpItemDescObject) - iFloatModifier[0];
iFloatModifier[2] = GetOverheatJamThreshold(gpItemDescObject);
@@ -10943,7 +11040,7 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
iFloatModifier[0] = Weapon[ Item[gpItemDescObject->usItem].ubClassIndex].usOverheatingDamageThreshold;
iFloatModifier[0] = Weapon[ gpItemDescObject->usItem ].usOverheatingDamageThreshold;
iFloatModifier[1] = GetOverheatDamageThreshold(gpItemDescObject) - iFloatModifier[0];
iFloatModifier[2] = GetOverheatDamageThreshold(gpItemDescObject);
@@ -11070,11 +11167,14 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
cnt++;
}
}
// Flugente Zombies
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
///////////////////////////////////////////////////// INDEXES
if(!cnt) cnt += 2;
// various overheating modificators
if ( ( Item[gpItemDescObject->usItem].overheatTemperatureModificator != 0.0 ) || ( Item[gpItemDescObject->usItem].overheatCooldownModificator != 0.0 ) || ( Item[gpItemDescObject->usItem].overheatJamThresholdModificator != 0.0 ) || ( Item[gpItemDescObject->usItem].overheatDamageThresholdModificator != 0.0 ) )
{
///////////////////////////////////////////////////// INDEXES
if (cnt >= sFirstLine && cnt < sLastLine)
{
SetFontForeground( FONT_MCOLOR_WHITE );
@@ -11099,31 +11199,32 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
++cnt;
///////////////////// TEMPERATURE MODIFICATOR
iFloatModifier[0] = Item[gpItemDescObject->usItem].overheatTemperatureModificator;
iFloatModifier[1] = 0.0; // doesn't exist (yet?)
iFloatModifier[2] = iFloatModifier[0];
///////////////////// poison percentage
iModifier[0] = Item[gpItemDescObject->usItem].bPoisonPercentage;
if ( iFloatModifier[0] != 0 )
UINT8 ammotype = (*gpItemDescObject)[0]->data.gun.ubGunAmmoType; // ... get type of ammunition used ...
iModifier[1] = AmmoTypes[ammotype].poisonPercentage;
iModifier[2] = iModifier[0] + iModifier[1];
// only draw if item is poisoned in any way
if ( iModifier[0] != 0 || iModifier[1] != 0 || iModifier[2] != 0 )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
// Print Values
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
{
SetFontForeground( 5 );
SetRGBFontForeground( 0, 255, 0 );
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
if (iFloatModifier[cnt2] > 0)
if (iModifier[cnt2] > 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
swprintf( pStr, L"%d", iModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
@@ -11133,10 +11234,7 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
else if (iFloatModifier[cnt2] < 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
swprintf( pStr, L"%d", iModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
@@ -11154,176 +11252,6 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
}
cnt++;
}
///////////////////// COOLDOWN FACTOR MODIFICATOR
iFloatModifier[0] = Item[gpItemDescObject->usItem].overheatCooldownModificator;
iFloatModifier[1] = 0.0; // doesn't exist (yet?)
iFloatModifier[2] = iFloatModifier[0];
if ( iFloatModifier[0] != 0 )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
// Print Values
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
{
SetFontForeground( 5 );
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
if (iFloatModifier[cnt2] > 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else if (iFloatModifier[cnt2] < 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else
{
swprintf( pStr, L"--" );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
mprintf( usX, usY, pStr );
}
}
cnt++;
}
///////////////////// JAM THRESHOLD FACTOR MODIFICATOR
iFloatModifier[0] = Item[gpItemDescObject->usItem].overheatJamThresholdModificator;
iFloatModifier[1] = 0.0; // doesn't exist (yet?)
iFloatModifier[2] = iFloatModifier[0];
if ( iFloatModifier[0] != 0 )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
// Print Values
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
{
SetFontForeground( 5 );
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
if (iFloatModifier[cnt2] > 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else if (iFloatModifier[cnt2] < 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else
{
swprintf( pStr, L"--" );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
mprintf( usX, usY, pStr );
}
}
cnt++;
}
///////////////////// DAMAGE THRESHOLD MODIFICATOR
iFloatModifier[0] = Item[gpItemDescObject->usItem].overheatDamageThresholdModificator;
iFloatModifier[1] = 0.0; // doesn't exist (yet?)
iFloatModifier[2] = iFloatModifier[0];
if ( iFloatModifier[0] != 0 )
{
if (cnt >= sFirstLine && cnt < sLastLine)
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt-sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt-sFirstLine][1].sBottom - sTop;
// Print Values
for (UINT8 cnt2 = 0; cnt2 < 3; cnt2++)
{
SetFontForeground( 5 );
sLeft = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sLeft;
sWidth = gItemDescAdvRegions[cnt-sFirstLine][cnt2+1].sRight - sLeft;
if (iFloatModifier[cnt2] > 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTNEGATIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else if (iFloatModifier[cnt2] < 0)
{
if ( cnt2 == 1 )
SetFontForeground( ITEMDESC_FONTPOSITIVE );
swprintf( pStr, L"%4.2f", iFloatModifier[cnt2] );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
#ifdef CHINESE
wcscat( pStr, ChineseSpecString1 );
#else
wcscat( pStr, L"%" );
#endif
}
else
{
swprintf( pStr, L"--" );
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY);
}
mprintf( usX, usY, pStr );
}
}
cnt++;
}
}
}
}
+27 -9
View File
@@ -2928,8 +2928,17 @@ void RenderSMPanel( BOOLEAN *pfDirty )
else
{
GetMoraleString( gpSMCurrentMerc, pMoraleStr );
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_POPUPTEXT ], gpSMCurrentMerc->stats.bLife, gpSMCurrentMerc->stats.bLifeMax, gpSMCurrentMerc->bBreath, gpSMCurrentMerc->bBreathMax, pMoraleStr );
// Flugente: added a display for poison, only show text if actualy poisoned
if ( gpSMCurrentMerc->bPoisonSum > 0 )
{
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_WITH_POISON_POPUPTEXT ], gpSMCurrentMerc->stats.bLife, gpSMCurrentMerc->stats.bLifeMax, gpSMCurrentMerc->bPoisonSum, gpSMCurrentMerc->stats.bLifeMax, gpSMCurrentMerc->bBreath, gpSMCurrentMerc->bBreathMax, pMoraleStr );
}
else
{
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_POPUPTEXT ], gpSMCurrentMerc->stats.bLife, gpSMCurrentMerc->stats.bLifeMax, gpSMCurrentMerc->bBreath, gpSMCurrentMerc->bBreathMax, pMoraleStr );
}
SetRegionFastHelpText( &(gSM_SELMERCBarsRegion), pStr );
}
}
else
@@ -5442,16 +5451,25 @@ void RenderTEAMPanel( BOOLEAN fDirty )
}
else
{
GetMoraleString( pSoldier, pMoraleStr );
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_POPUPTEXT ], pSoldier->stats.bLife, pSoldier->stats.bLifeMax, pSoldier->bBreath, pSoldier->bBreathMax, pMoraleStr );
SetRegionFastHelpText( &(gTEAM_BarsRegions[ cnt ]), pStr );
GetMoraleString( pSoldier, pMoraleStr );
// Flugente: added a display for poison, only show text if actually poisoned
if ( pSoldier->bPoisonSum > 0 )
{
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_WITH_POISON_POPUPTEXT ], pSoldier->stats.bLife, pSoldier->stats.bLifeMax, pSoldier->bPoisonSum, pSoldier->stats.bLifeMax, pSoldier->bBreath, pSoldier->bBreathMax, pMoraleStr );
}
else
{
swprintf( pStr, TacticalStr[ MERC_VITAL_STATS_POPUPTEXT ], pSoldier->stats.bLife, pSoldier->stats.bLifeMax, pSoldier->bBreath, pSoldier->bBreathMax, pMoraleStr );
}
SetRegionFastHelpText( &(gTEAM_BarsRegions[ cnt ]), pStr );
}
}
else
{
SetRegionFastHelpText( &(gTEAM_BarsRegions[ cnt ]), L"" );
}
}
else
{
SetRegionFastHelpText( &(gTEAM_BarsRegions[ cnt ]), L"" );
}
}
if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) )
{
+83 -18
View File
@@ -24,22 +24,30 @@
#endif
#define LIFE_BAR_SHADOW FROMRGB( 108, 12, 12 )
#define LIFE_BAR FROMRGB( 200, 0, 0 )
#define LIFE_BAR FROMRGB( 200, 0, 0 )
#define BANDAGE_BAR_SHADOW FROMRGB( 156, 60, 60 )
#define BANDAGE_BAR FROMRGB( 222, 132, 132 )
#define BANDAGE_BAR FROMRGB( 222, 132, 132 )
#define BLEEDING_BAR_SHADOW FROMRGB( 128, 128, 60 )
#define BLEEDING_BAR FROMRGB( 240, 240, 20 )
#define CURR_BREATH_BAR_SHADOW FROMRGB( 8, 12, 118 ) // the MAX max breatth, always at 100%
#define CURR_BREATH_BAR FROMRGB( 8, 12, 160 )
#define CURR_MAX_BREATH FROMRGB( 0, 0, 0 ) // the current max breath, black
#define CURR_MAX_BREATH_SHADOW FROMRGB( 0, 0, 0 )
#define MORALE_BAR_SHADOW FROMRGB( 8, 112, 12 )
#define MORALE_BAR FROMRGB( 8, 180, 12 )
#define BREATH_BAR_SHADOW FROMRGB( 60, 108, 108 ) // the lt blue current breath
#define BREATH_BAR FROMRGB( 113, 178, 218 )
#define BLEEDING_BAR FROMRGB( 240, 240, 20 )
#define POISON_LIFE_BAR_SHADOW FROMRGB( 12, 108, 12 )
#define POISON_LIFE_BAR FROMRGB( 0, 200, 0 )
#define POISON_BANDAGE_BAR_SHADOW FROMRGB( 80, 186, 80 )
#define POISON_BANDAGE_BAR FROMRGB( 152, 252, 152 )
#define POISON_BLEEDING_BAR_SHADOW FROMRGB( 128, 60, 128 )
#define POISON_BLEEDING_BAR FROMRGB( 240, 20, 240 )
#define CURR_BREATH_BAR_SHADOW FROMRGB( 8, 12, 118 ) // the MAX max breatth, always at 100%
#define CURR_BREATH_BAR FROMRGB( 8, 12, 160 )
#define CURR_MAX_BREATH FROMRGB( 0, 0, 0 ) // the current max breath, black
#define CURR_MAX_BREATH_SHADOW FROMRGB( 0, 0, 0 )
#define MORALE_BAR_SHADOW FROMRGB( 8, 112, 12 )
#define MORALE_BAR FROMRGB( 8, 180, 12 )
#define BREATH_BAR_SHADOW FROMRGB( 60, 108, 108 ) // the lt blue current breath
#define BREATH_BAR FROMRGB( 113, 178, 218 )
#define BREATH_BAR_SHAD_BACK FROMRGB( 1,1,1 )
#define FACE_WIDTH 48
#define FACE_HEIGHT 43
#define FACE_WIDTH 48
#define FACE_HEIGHT 43
// backgrounds for breath max background
@@ -162,12 +170,15 @@ void DrawLifeUIBarEx( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos, INT16 sWi
pDestBuf = LockVideoSurface( uiBuffer, &uiDestPitchBYTES );
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
dStart = sYPos;
dEnd = 0;
// FIRST DO MAX LIFE
dPercentage = (FLOAT)pSoldier->stats.bLife / (FLOAT)100;
FLOAT dstart1 = dStart - dEnd;
dStart = (FLOAT)( dStart - dEnd );
dEnd = dPercentage * sHeight;
dStart = sYPos;
usLineColor = Get16BPPColor( LIFE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos, (INT32)dStart, sXPos, (INT32)( dStart - dEnd ) , usLineColor, pDestBuf );
@@ -177,15 +188,33 @@ void DrawLifeUIBarEx( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos, INT16 sWi
usLineColor = Get16BPPColor( LIFE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos+ 2, (INT32)dStart, sXPos + 2, (INT32)( dStart - dEnd ), usLineColor, pDestBuf );
// NOW DO BANDAGE
// poisoned life first
if ( pSoldier->bPoisonLife )
{
dPercentage = (FLOAT)pSoldier->bPoisonLife / (FLOAT)100;
FLOAT dpoisonStart = (FLOAT)( dstart1 );
FLOAT dpoisonEnd = dPercentage * sHeight;
usLineColor = Get16BPPColor( POISON_LIFE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos, (INT32)dpoisonStart, sXPos, (INT32)( dpoisonStart - dpoisonEnd ) , usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_LIFE_BAR );
RectangleDraw( TRUE, sXPos+ 1, (INT32)dpoisonStart, sXPos + 1, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_LIFE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos+ 2, (INT32)dpoisonStart, sXPos + 2, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
}
// NOW DO BANDAGE
// Calculate bandage
FLOAT dstart2 = dStart - dEnd;
bBandage = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
if ( bBandage )
{
dPercentage = (FLOAT)bBandage / (FLOAT)100;
dStart = (FLOAT)( sYPos - dEnd );
dStart = (FLOAT)( dStart - dEnd );
dEnd = ( dPercentage * sHeight );
usLineColor = Get16BPPColor( BANDAGE_BAR_SHADOW );
@@ -198,7 +227,26 @@ void DrawLifeUIBarEx( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos, INT16 sWi
RectangleDraw( TRUE, sXPos+ 2, (INT32)dStart, sXPos + 2, (INT32)( dStart - dEnd ), usLineColor, pDestBuf );
}
// get amount of poisoned bandage
INT8 bPoisonBandage = pSoldier->bPoisonSum - pSoldier->bPoisonBleeding - pSoldier->bPoisonLife;
if ( bPoisonBandage )
{
dPercentage = (FLOAT)bPoisonBandage / (FLOAT)100;
FLOAT dpoisonStart = (FLOAT)( dstart2 );
FLOAT dpoisonEnd = dPercentage * sHeight;
usLineColor = Get16BPPColor( POISON_BANDAGE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos, (INT32)dpoisonStart, sXPos, (INT32)( dpoisonStart - dpoisonEnd ) , usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_BANDAGE_BAR );
RectangleDraw( TRUE, sXPos+ 1, (INT32)dpoisonStart, sXPos + 1, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_BANDAGE_BAR_SHADOW );
RectangleDraw( TRUE, sXPos+ 2, (INT32)dpoisonStart, sXPos + 2, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
}
// NOW DO BLEEDING
FLOAT dstart3 = dStart - dEnd;
if ( pSoldier->bBleeding )
{
dPercentage = (FLOAT)pSoldier->bBleeding / (FLOAT)100;
@@ -215,6 +263,23 @@ void DrawLifeUIBarEx( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos, INT16 sWi
RectangleDraw( TRUE, sXPos+ 2, (INT32)dStart, sXPos + 2, (INT32)( dStart - dEnd ), usLineColor, pDestBuf );
}
// poisoned bleeding
if ( pSoldier->bPoisonBleeding )
{
dPercentage = (FLOAT)pSoldier->bPoisonBleeding / (FLOAT)100;
FLOAT dpoisonStart = (FLOAT)( dstart3 );
FLOAT dpoisonEnd = dPercentage * sHeight;
usLineColor = Get16BPPColor( POISON_BLEEDING_BAR_SHADOW );
RectangleDraw( TRUE, sXPos, (INT32)dpoisonStart, sXPos, (INT32)( dpoisonStart - dpoisonEnd ) , usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_BLEEDING_BAR );
RectangleDraw( TRUE, sXPos+ 1, (INT32)dpoisonStart, sXPos + 1, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
usLineColor = Get16BPPColor( POISON_BLEEDING_BAR_SHADOW );
RectangleDraw( TRUE, sXPos+ 2, (INT32)dpoisonStart, sXPos + 2, (INT32)( dpoisonStart - dpoisonEnd ), usLineColor, pDestBuf );
}
UnLockVideoSurface( uiBuffer );
}
+69
View File
@@ -2210,6 +2210,21 @@ void DrawSelectedUIAboveGuy( UINT16 usSoldierID )
}
}
}
if ( pSoldier->IsZombie() )
{
swprintf(NameStr, pSoldier->name);
// Display name
SetFont( TINYFONT1 );
SetFontBackground( FONT_MCOLOR_BLACK );
SetFontForeground( FONT_MCOLOR_WHITE );
//legion2
FindFontCenterCoordinates( sXPos, (INT16)( sYPos -10 ), (INT16)(80 ), 1, NameStr, TINYFONT1, &sX, &sY );
gprintfdirty( sX, sY, NameStr );
mprintf( sX, sY, NameStr );
}
//------------
}
}
@@ -3162,6 +3177,7 @@ void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sW
UINT8 *pDestBuf;
UINT16 usLineColor;
INT8 bBandage;
INT8 bPoisonBandage;
// Draw breath points
@@ -3174,6 +3190,8 @@ void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sW
// get amt bandaged
bBandage = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
// get amount of poisoned bandage
bPoisonBandage = pSoldier->bPoisonSum - pSoldier->bPoisonBleeding - pSoldier->bPoisonLife;
// NOW DO BLEEDING
@@ -3194,6 +3212,23 @@ void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sW
}
}
// poisoned bleeding
if ( pSoldier->bPoisonBleeding )
{
dPercentage = (FLOAT)( pSoldier->stats.bLifeMax - pSoldier->bBleeding + pSoldier->bPoisonBleeding )/ (FLOAT)100;
dWidth = dPercentage * sWidth;
if(gbPixelDepth==16)
{
usLineColor = Get16BPPColor( FROMRGB( 240, 20, 240 ) );
RectangleDraw( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
else if(gbPixelDepth==8)
{
// DB Need to change this to a color from the 8-bit standard palette
usLineColor = COLOR_GREEN;
RectangleDraw8( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
}
if( bBandage )
{
@@ -3212,6 +3247,23 @@ void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sW
}
}
// poisoned bandage
if ( bPoisonBandage )
{
dPercentage = (FLOAT)( pSoldier->stats.bLife + bPoisonBandage )/ (FLOAT)100;
dWidth = dPercentage * sWidth;
if(gbPixelDepth==16)
{
usLineColor = Get16BPPColor( FROMRGB( 132, 222, 132 ) );
RectangleDraw( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
else if(gbPixelDepth==8)
{
// DB Need to change this to a color from the 8-bit standard palette
usLineColor = COLOR_GREEN;
RectangleDraw8( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
}
dPercentage = (FLOAT)pSoldier->stats.bLife / (FLOAT)100;
dWidth = dPercentage * sWidth;
@@ -3227,6 +3279,23 @@ void DrawBarsInUIBox( SOLDIERTYPE *pSoldier , INT16 sXPos, INT16 sYPos, INT16 sW
RectangleDraw8( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
// poisoned life
if ( pSoldier->bPoisonLife )
{
dPercentage = (FLOAT)( pSoldier->bPoisonLife )/ (FLOAT)100;
dWidth = dPercentage * sWidth;
if(gbPixelDepth==16)
{
usLineColor = Get16BPPColor( FROMRGB( 0, 200, 0 ) );
RectangleDraw( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
else if(gbPixelDepth==8)
{
// DB Need to change this to a color from the 8-bit standard palette
usLineColor = COLOR_GREEN;
RectangleDraw8( TRUE, sXPos + 3, sYPos + 1, (INT32)( sXPos + dWidth + 3 ), sYPos + 1, usLineColor, pDestBuf );
}
}
dPercentage = (FLOAT)( pSoldier->bBreathMax ) / (FLOAT)100;
+7
View File
@@ -846,6 +846,10 @@ void GenerateRandomEquipment( SOLDIERCREATE_STRUCT *pp, INT8 bSoldierClass, INT8
}
}
break;
case SOLDIER_CLASS_ZOMBIE:
// zombies get no items at all...
break;
}
for ( i = 0; i < pp->Inv.size(); i++ )
@@ -1052,6 +1056,8 @@ void ChooseWeaponForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp, INT8 bWeaponC
bStatus += (INT8)(HighestPlayerProgressPercentage() / 10);
bStatus = (INT8)min( 100, bStatus );
break;
case SOLDIER_CLASS_ZOMBIE:
bStatus = (INT8)(1); // if a zombie gets anything, it'll be broken
default:
bStatus = (INT8)(50 + Random( 51 ) );
break;
@@ -2105,6 +2111,7 @@ void ChooseFaceGearForSoldierCreateStruct( SOLDIERCREATE_STRUCT *pp )
break;
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_GREEN_MILITIA:
case SOLDIER_CLASS_ZOMBIE:
break;
}
}
+6
View File
@@ -219,6 +219,9 @@ typedef enum
#define GS_CARTRIDGE_IN_CHAMBER 0x01
#define GS_WEAPON_BEING_RELOADED 0x02
// Flugente: define for maximum temperature
#define OVERHEATING_MAX_TEMPERATURE 60000.0
//forward declaration
class OBJECTTYPE;
class SOLDIERTYPE;
@@ -956,6 +959,9 @@ typedef struct
BOOLEAN blockironsight; // if a gun or any attachment have this property, the iron sight won't be usable (if there is at least one other usable sight)
// Flugente poison system
INT16 bPoisonPercentage;
} INVTYPE;
// CHRISL: Added new structures to handle LBE gear and the two new XML files that will be needed to deal
+51 -8
View File
@@ -3042,7 +3042,7 @@ UINT32 CalculateCarriedWeight( SOLDIERTYPE * pSoldier )
UINT32 uiTotalWeight = 0;
UINT32 uiPercent;
UINT8 ubLoop;
UINT8 ubStrengthForCarrying;
UINT16 ubStrengthForCarrying;
//Pulmu: Changes for dynamic ammo weight
for( ubLoop = 0; ubLoop < pSoldier->inv.size(); ubLoop++)
@@ -7418,7 +7418,7 @@ BOOLEAN CreateGun( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj )
pStackedObject->data.ubImprintID = NO_PROFILE;
// Flugente FTW 1: temperature on creation is 0
pStackedObject->data.bTemperature = 0.0;
pStackedObject->data.bTemperature = 0.0f;
if (Weapon[ usItem ].ubWeaponClass == MONSTERCLASS)
{
@@ -7533,6 +7533,7 @@ BOOLEAN CreateItem( UINT16 usItem, INT16 bStatus, OBJECTTYPE * pObj )
{
(*pObj)[0]->data.objectStatus = bStatus;
}
//ADB ubWeight has been removed, see comments in OBJECTTYPE
//pObj->ubWeight = CalculateObjectWeight( pObj );
fRet = TRUE;
@@ -9189,6 +9190,41 @@ void ActivateXRayDevice( SOLDIERTYPE * pSoldier )
pSoldier->uiXRayActivatedTime = GetWorldTotalSeconds();
}
void TurnOnXRayEffects( SOLDIERTYPE * pSoldier )
{
SOLDIERTYPE * pSoldier2;
UINT32 uiSlot;
// first, scan through all mercs and turn off xrayed flag for anyone
// previously xrayed by this guy
for ( uiSlot = 0; uiSlot < guiNumMercSlots; ++uiSlot )
{
pSoldier2 = MercSlots[ uiSlot ];
if ( pSoldier2 )
{
if ( (pSoldier2->ubMiscSoldierFlags & SOLDIER_MISC_XRAYED) && (pSoldier2->aiData.ubXRayedBy == pSoldier->ubID) )
{
pSoldier2->ubMiscSoldierFlags &= (~SOLDIER_MISC_XRAYED);
pSoldier2->aiData.ubXRayedBy = NOBODY;
}
}
}
// now turn on xray for anyone within range
for ( uiSlot = 0; uiSlot < guiNumMercSlots; ++uiSlot )
{
pSoldier2 = MercSlots[ uiSlot ];
if ( pSoldier2 )
{
if ( pSoldier2->bTeam != pSoldier->bTeam && PythSpacesAway( pSoldier->sGridNo, pSoldier2->sGridNo ) < XRAY_RANGE )
{
pSoldier2->ubMiscSoldierFlags |= SOLDIER_MISC_XRAYED;
pSoldier2->aiData.ubXRayedBy = pSoldier->ubID;
}
}
}
pSoldier->uiXRayActivatedTime = GetWorldTotalSeconds();
}
void TurnOffXRayEffects( SOLDIERTYPE * pSoldier )
{
SOLDIERTYPE * pSoldier2;
@@ -9453,13 +9489,17 @@ INT16 GetGearAPBonus( SOLDIERTYPE * pSoldier )
{
INT16 bonus=0;
for (int j = HELMETPOS; j <= HEAD2POS; j++)
for (int j = HELMETPOS; j <= HEAD2POS; ++j)
{
if (pSoldier->inv[j].exists() == true) {
bonus += Item[pSoldier->inv[j].usItem].APBonus;
if (pSoldier->inv[j].exists() == true)
{
OBJECTTYPE* pObj = &pSoldier->inv[j];
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
if(iter->exists()){
attachmentList::iterator iterend = (*pObj)[0]->attachments.begin();
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != iterend; ++iter)
{
if(iter->exists())
{
bonus += Item[iter->usItem].APBonus;
}
}
@@ -11020,7 +11060,9 @@ BOOLEAN HasThermalOptics( SOLDIERTYPE * pSoldier )
if (!IsWeapon(pSoldier->inv[i].usItem) || (IsWeapon(pSoldier->inv[i].usItem) && usingGunScope == true) )
{
if (Item[pSoldier->inv[i].usItem].thermaloptics)
{
return TRUE;
}
}
}
}
@@ -13414,6 +13456,8 @@ BOOLEAN HasAttachmentOfClass( OBJECTTYPE * pObj, UINT32 aFlag )
return( FALSE );
}
extern void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags);
///////////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 5: Item Transformation.
// Item Transformation is a new way to interact with items. Where Merges combine two items into one, a Transformation
@@ -13816,4 +13860,3 @@ UINT64 GetAvailableAttachmentPoint (OBJECTTYPE * pObject, UINT8 subObject)
return point;
}
+2 -4
View File
@@ -225,6 +225,7 @@ void CheckEquipmentForFragileItemDamage( SOLDIERTYPE *pSoldier, INT32 iDamage );
#define XRAY_TIME 5
extern void ActivateXRayDevice( SOLDIERTYPE * pSoldier );
extern void TurnOnXRayEffects( SOLDIERTYPE * pSoldier );
extern void TurnOffXRayEffects( SOLDIERTYPE * pSoldier );
OBJECTTYPE* FindLaunchableAttachment( OBJECTTYPE * pObj, UINT16 usWeapon );
UINT16 FindLegalGrenade(UINT16 usItem);
@@ -448,7 +449,7 @@ BOOLEAN UseTotalMedicalKitPoints( SOLDIERTYPE * pSoldier, UINT16 usPointsToConsu
FLOAT GetItemCooldownFactor( OBJECTTYPE * pObj );
void GetScopeLists( OBJECTTYPE * pObj, std::map<INT8, OBJECTTYPE*>& arScopeMap );
// check if item belongs to a specific attachemnt class
// check if item belongs to a specific attachment class
BOOLEAN IsAttachmentClass( UINT16 usItem, UINT32 aFlag );
BOOLEAN HasAttachmentOfClass( OBJECTTYPE * pObj, UINT32 aFlag );
@@ -459,6 +460,3 @@ bool IsAttachmentPointAvailable( UINT64 point, UINT32 attachmentID, BOOLEAN only
UINT64 GetAvailableAttachmentPoint ( OBJECTTYPE * pObject, UINT8 subObject );
#endif
+2 -2
View File
@@ -702,7 +702,7 @@ void HandleDoorTrap( SOLDIERTYPE * pSoldier, DOOR * pDoor )
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Trap gone off %d", gTacticalStatus.ubAttackBusyCount) );
DebugAttackBusy( "!!!!!!! Trap gone off\n" );
pSoldier->SoldierTakeDamage( 0, (UINT16) (10 + PreRandom( 10 )), (UINT16) ((3 + PreRandom( 3 ) * 1000)), TAKE_DAMAGE_ELECTRICITY, NOBODY, pDoor->sGridNo, 0, TRUE );
pSoldier->SoldierTakeDamage( 0, (UINT16) (10 + PreRandom( 10 )), 0, (UINT16) ((3 + PreRandom( 3 ) * 1000)), TAKE_DAMAGE_ELECTRICITY, NOBODY, pDoor->sGridNo, 0, TRUE );
break;
case SUPER_ELECTRIC:
@@ -717,7 +717,7 @@ void HandleDoorTrap( SOLDIERTYPE * pSoldier, DOOR * pDoor )
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Trap gone off %d", gTacticalStatus.ubAttackBusyCount) );
DebugAttackBusy( "!!!!!!! Trap gone off\n" );
pSoldier->SoldierTakeDamage( 0, (UINT16) (20 + PreRandom( 20 )), (UINT16) ((6 + PreRandom( 6 ) * 1000)), TAKE_DAMAGE_ELECTRICITY, NOBODY, pDoor->sGridNo, 0, TRUE );
pSoldier->SoldierTakeDamage( 0, (UINT16) (20 + PreRandom( 20 )), 0, (UINT16) ((6 + PreRandom( 6 ) * 1000)), TAKE_DAMAGE_ELECTRICITY, NOBODY, pDoor->sGridNo, 0, TRUE );
break;
+1
View File
@@ -48,6 +48,7 @@
#include "WorldDat.h"
// HEADROCK HAM 3.6: This must be included, for testing whether Bloodcats and Enemies can see one another.
#include "Campaign Types.h"
#include "soldier tile.h" // added by Flugente
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
-16
View File
@@ -109,20 +109,6 @@ extern SOLDIERTYPE *pTMilitiaSoldier;
extern BOOLEAN SoldierCanAffordNewStance( SOLDIERTYPE *pSoldier, UINT8 ubDesiredStance );
void ResetMilitia()
{
UINT8 ubNumGreen = 0;
@@ -2370,5 +2356,3 @@ void MilitiaControlMenuBtnCallBack( MOUSE_REGION * pRegion, INT32 iReason )
// return;
//}
+9 -1
View File
@@ -88,6 +88,8 @@ MoraleEvent gbMoraleEvent[NUM_MORALE_EVENTS] =
{ TACTICAL_MORALE_EVENT, -1}, // MORALE_PSYCHO_UNABLE_TO_PSYCHO,
{ STRATEGIC_MORALE_EVENT, +1}, // MORALE_PACIFIST_GAIN_NONCOMBAT,
{ TACTICAL_MORALE_EVENT, +1}, // MORALE_MALICIOUS_HIT,
// added by SANDRO
{ TACTICAL_MORALE_EVENT, -1}, //MORALE_KHORNATE_RANGED_COMBAT,
};
BOOLEAN gfSomeoneSaidMoraleQuote = FALSE;
@@ -523,7 +525,7 @@ void UpdateSoldierMorale( SOLDIERTYPE * pSoldier, INT8 bMoraleEvent )
}
}
}
else if ( bMoraleMod != MORALE_PSYCHO_UNABLE_TO_PSYCHO)
else if ( bMoraleMod != MORALE_PSYCHO_UNABLE_TO_PSYCHO && bMoraleMod != MORALE_KHORNATE_RANGED_COMBAT)
{
switch( pProfile->bAttitude )
{
@@ -909,6 +911,12 @@ void HandleMoraleEvent( SOLDIERTYPE *pSoldier, INT8 bMoraleEvent, INT16 sMapX, I
HandleMoraleEventForSoldier( pSoldier, bMoraleEvent );
break;
// added by Flugente
case MORALE_KHORNATE_RANGED_COMBAT:
Assert( pSoldier );
HandleMoraleEventForSoldier( pSoldier, bMoraleEvent );
break;
default:
// debug message
ScreenMsg( MSG_FONT_RED, MSG_BETAVERSION, L"Invalid morale event type = %d. AM/CC-1", bMoraleEvent );
+3
View File
@@ -49,6 +49,9 @@ typedef enum
MORALE_PSYCHO_UNABLE_TO_PSYCHO,
MORALE_PACIFIST_GAIN_NONCOMBAT,
MORALE_MALICIOUS_HIT,
// added by Flugente
MORALE_KHORNATE_RANGED_COMBAT,
NUM_MORALE_EVENTS
} MoraleEventNames;
+30 -4
View File
@@ -6975,10 +6975,12 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated )
if (pTeamSoldier->iHealableInjury < 0)
pTeamSoldier->iHealableInjury = 0;
pTeamSoldier->bPoisonLife = min(pTeamSoldier->bPoisonSum, pTeamSoldier->bPoisonLife + OKLIFE - pTeamSoldier->stats.bLife);
pTeamSoldier->stats.bLife = OKLIFE;
}
pTeamSoldier->bBleeding = 0; // let's think, the autobandage was done for the militia too
pTeamSoldier->bPoisonBleeding = 0;
}
}
gTacticalStatus.Team[ MILITIA_TEAM ].bAwareOfOpposition = FALSE;
@@ -7255,6 +7257,26 @@ UINT8 NumEnemyInSector( )
}
UINT8 NumZombiesInSector( )
{
SOLDIERTYPE *pTeamSoldier;
INT32 cnt = 0;
UINT8 ubNumZombies = 0;
for ( pTeamSoldier = Menptr, cnt = 0; cnt < TOTAL_SOLDIERS; ++pTeamSoldier, ++cnt )
{
if ( pTeamSoldier->bActive && pTeamSoldier->bInSector && pTeamSoldier->stats.bLife > 0 )
{
if ( pTeamSoldier->IsZombie() )
{
++ubNumZombies;
}
}
}
return( ubNumZombies );
}
UINT8 NumEnemyInSectorExceptCreatures()
{
SOLDIERTYPE *pTeamSoldier;
@@ -7582,13 +7604,13 @@ BOOLEAN KillIncompacitatedEnemyInSector( )
// KIll......
// SANDRO - if the soldier is bleeding out, consider this damage as done by the last attacker
if ( pTeamSoldier->ubAttackerID != NOBODY )
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubAttackerID, NOWHERE, 0, TRUE );
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 0, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubAttackerID, NOWHERE, 0, TRUE );
else if ( pTeamSoldier->ubPreviousAttackerID != NOBODY )
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE );
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 0, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE );
else if ( pTeamSoldier->ubNextToPreviousAttackerID != NOBODY )
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE );
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 0, 100, TAKE_DAMAGE_BLOODLOSS, pTeamSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE );
else
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
pTeamSoldier->SoldierTakeDamage( ANIM_CROUCH, pTeamSoldier->stats.bLife, 0, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
fReturnVal = TRUE;
}
@@ -7767,6 +7789,10 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker )
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("HandleSuppressionFire: loop = %d, numslots = %d ",uiLoop, guiNumMercSlots));
pSoldier = MercSlots[uiLoop];
// Flugente: zombies do not receive any suppression at all!
if ( pSoldier != NULL && pSoldier->IsZombie() )
continue;
// Has this character received any Suppression Points since the last attack?
// HEADROCK: Suppression Points accumulate by bullets flying near the character. It includes
// friendly fire at a certain distance. As of HAM 3.2, it also happens with nearby explosions.
+3
View File
@@ -393,4 +393,7 @@ BOOLEAN WillAirRaidBeStopped( INT16 sSectorX, INT16 sSectorY );
// HEADROCK HAM 3.5: Externalized for First Arrival enemy check
extern UINT8 NumEnemyInSector();
// Flugente
extern UINT8 NumZombiesInSector();
#endif
+398
View File
@@ -43,6 +43,9 @@
#include "strategic.h"
#include "qarray.h"
#include "Interface.h"
#include "Campaign Types.h"
//#include "Queen Command.h"
#endif
#include "Animation Control.h"
@@ -580,6 +583,10 @@ INT32 AddRottingCorpse( ROTTING_CORPSE_DEFINITION *pCorpseDef )
pCorpse->pAniTile->uiUserData = iIndex;
pCorpse->iID = iIndex;
// copy name of corpse definition...
memcpy( &(pCorpse->name), &(pCorpseDef->name), sizeof(CHAR16) * 10 );
pCorpse->name[9] = '\0';
pCorpse->fActivated = TRUE;
if ( Random( 100 ) > 50 )
@@ -853,6 +860,36 @@ BOOLEAN TurnSoldierIntoCorpse( SOLDIERTYPE *pSoldier, BOOLEAN fRemoveMerc, BOOLE
Corpse.usFlags |= ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE;
}
// Flugente Zombies: Determine if a zombie can rise from this corpse
switch ( gGameExternalOptions.sZombieRiseBehaviour )
{
case 3:
// a zombie might rise again
if ( pSoldier->IsZombie() && Random( 2 ) > 0 )
Corpse.usFlags |= ROTTING_CORPSE_NEVER_RISE_AGAIN;
break;
case 2:
// death tosses a coin...
if ( Random( 2 ) > 0 )
Corpse.usFlags |= ROTTING_CORPSE_NEVER_RISE_AGAIN;
break;
case 1:
// no flag, the dead shall rise for eternity!
break;
case 0:
default:
// a killed zombie won't rise again
if ( pSoldier->IsZombie() )
Corpse.usFlags |= ROTTING_CORPSE_NEVER_RISE_AGAIN;
break;
}
// Flugente: copy name of soldier...
memcpy( &(Corpse.name), &(pSoldier->name), sizeof(CHAR16) * 10 );
Corpse.name[9] = '\0';
// Determine corpse type!
ubType = (UINT8)gubAnimSurfaceCorpseID[ pSoldier->ubBodyType][ pSoldier->usAnimState ];
@@ -2046,3 +2083,364 @@ UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo )
return( ubHighestWarning );
}
// Flugente Zombies: resurrect zombies
void RaiseZombies( void )
{
if ( gGameSettings.fOptions[TOPTION_ZOMBIES] )
{
// if gGameExternalOptions.fZombieSpawnWaves is true, zombies will spawn from all corpses (while there is still room for more), creating a wave of zombies. with lots of bodies lying around, this can be a lot.
// if GameExternalOptions.fZombieSpawnWaves is false, each zombie can spawn randomly, you will get zombies on msot turns, but they won't spawn a whole horde at once
if ( ( gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) || !gGameExternalOptions.fZombieSpawnWaves )
{
ROTTING_CORPSE * pCorpse;
BOOLEAN zombieshaverisen = FALSE;
SECTORINFO *pSector = &SectorInfo[ SECTOR( gWorldSectorX, gWorldSectorY ) ];
for ( INT32 cnt = giNumRottingCorpse - 1; cnt >= 0; --cnt )
{
if ( pSector->ubNumCreatures < gGameExternalOptions.ubGameMaximumNumberOfCreatures ) // ... if there is still room for more zombies (zombies count as creatures until a separate ZOMBIE_TEAM is implemented)...
{
pCorpse = &(gRottingCorpse[ cnt ] );
// if zombies should spawn individually, roll for every corpse individually
if ( gGameExternalOptions.fZombieSpawnWaves || ( !gGameExternalOptions.fZombieSpawnWaves && (INT8) ( Random( 100 ) ) > 100 - gGameExternalOptions.sZombieRiseWaveFrequency ) )
{
if ( pCorpse->fActivated && pCorpse->def.fHeadTaken == FALSE ) // ... if corpse is active, and still has a head ...
{
if ( !(pCorpse->def.usFlags & ROTTING_CORPSE_NEVER_RISE_AGAIN) ) // ... if corpse is already that of a zombie, don't create zombie again ...
{
if ( !TileIsOutOfBounds(pCorpse->def.sGridNo) ) // ... if corpse is on existing coordinates ...
{
if ( WhoIsThere2( pCorpse->def.sGridNo, pCorpse->def.bLevel ) == NOBODY ) // ... if nobody else is on that position ...
{
UINT16 recanimstate = STANDING;
if ( CorpseOkToSpawnZombie( pCorpse, &recanimstate ) ) // ... a zombie can be created from this corpse, in the corresponding animstate ...
{
zombieshaverisen = TRUE;
CreateZombiefromCorpse( pCorpse, recanimstate );
//++pSector->ubNumZombies;
//++pSector->ubZombiesInBattle;
RemoveCorpse( cnt );
}
}
}
}
}
}
}
else
{
// if there is no more room, we can skip this
break;
}
}
if ( zombieshaverisen )
{
#ifdef JA2TESTVERSION
ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_BETAVERSION, L"A wave of zombies is created");
#endif
// Play sound
PlayJA2SampleFromFile( "Sounds\\zombie1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
}
}
}
}
// Flugente Zombies 1.0: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState )
{
SOLDIERCREATE_STRUCT MercCreateStruct;
MercCreateStruct.ubProfile = NO_PROFILE;
MercCreateStruct.bTeam = CREATURE_TEAM; // should be ZOMBIE_TEAM, once that is properly implemented
MercCreateStruct.sInsertionGridNo = pCorpse->def.sGridNo;
MercCreateStruct.sSectorX = gWorldSectorX;
MercCreateStruct.sSectorY = gWorldSectorY;
MercCreateStruct.bSectorZ = gbWorldSectorZ;
MercCreateStruct.bBodyType = pCorpse->def.ubBodyType;
MercCreateStruct.ubDirection = pCorpse->def.ubDirection;
MercCreateStruct.fOnRoof = pCorpse->def.bLevel > 0 ? TRUE : FALSE;
// add important stats according to difficulty level
// bLife is actually lower than bLifeMax. Because zombies have poison absorption, they can and will heal themselves over time, thereby gaining more life if they are not put down fast
switch( gGameExternalOptions.sZombieDifficultyLevel )
{
case 4:
MercCreateStruct.bLifeMax = (INT8)( 70 + Random( 30 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(15));
MercCreateStruct.bAgility = (INT8)( 50 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 60 + Random( 15 ) );
MercCreateStruct.bStrength = (INT8)( 80 + Random( 20 ) );
break;
case 3:
MercCreateStruct.bLifeMax = (INT8)( 60 + Random( 20 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(10 + Random(10));
MercCreateStruct.bAgility = (INT8)( 40 + Random( 10 ) );
MercCreateStruct.bDexterity = (INT8)( 45 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 60 + Random( 20 ) );
break;
case 2:
MercCreateStruct.bLifeMax = (INT8)( 45 + Random( 15 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(10));
MercCreateStruct.bAgility = (INT8)( 30 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 30 + Random( 10 ) );
MercCreateStruct.bStrength = (INT8)( 45 + Random( 20 ) );
break;
case 1:
default:
MercCreateStruct.bLifeMax = (INT8)( 35 + Random( 10 ) );
MercCreateStruct.bLife = MercCreateStruct.bLifeMax - (INT8)(5 + Random(5));
MercCreateStruct.bAgility = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bDexterity = (INT8)( 15 + Random( 5 ) );
MercCreateStruct.bStrength = (INT8)( 30 + Random( 20 ) );
break;
}
// FIX: something's wrong with the FATCIV-bodytype when dying... this is to ensure they die absolutely fast
//if ( MercCreateStruct.bBodyType == FATCIV )
//MercCreateStruct.bLifeMax = OKLIFE;
MercCreateStruct.bExpLevel = 1;
MercCreateStruct.bMarksmanship = 1;
MercCreateStruct.bMedical = 1;
MercCreateStruct.bMechanical = 1;
MercCreateStruct.bExplosive = 1;
MercCreateStruct.bLeadership = 1;
MercCreateStruct.bWisdom = 1;
MercCreateStruct.bMorale = 90;
MercCreateStruct.bAIMorale = MORALE_FEARLESS;
SET_PALETTEREP_ID ( MercCreateStruct.HeadPal, pCorpse->def.HeadPal );
SET_PALETTEREP_ID ( MercCreateStruct.PantsPal, pCorpse->def.PantsPal );
SET_PALETTEREP_ID ( MercCreateStruct.VestPal, pCorpse->def.VestPal );
SET_PALETTEREP_ID ( MercCreateStruct.SkinPal, pCorpse->def.SkinPal );
MercCreateStruct.fVisible = TRUE;
// do not generate a new palette, thereby using the old palette of the corpse
MercCreateStruct.fNoGenNewPalette = TRUE;
INT8 iNewIndex;
if ( TacticalCreateSoldier( &MercCreateStruct, (UINT8 *)&iNewIndex ) )
{
/* certain values have to be set afterwards - the alternative to edit each and every function that gets called from TacticalCreateSoldier() subsequently and
* make an exception for zombies every time...
*/
SOLDIERTYPE* pNewSoldier = MercPtrs[ (UINT8)iNewIndex ];
pNewSoldier->bActionPoints = 60;
pNewSoldier->bInitialActionPoints = 60;
pNewSoldier->sBreathRed = 0;
pNewSoldier->ubInsertionDirection = pCorpse->def.ubDirection;
//pNewSoldier->sHeightAdjustment = pCorpse->def.sHeightAdjustment;
pNewSoldier->sDesiredHeight = 3;
pNewSoldier->ubDesiredHeight = 3; // this forces pNewSoldier to rise up to crouching position
pNewSoldier->ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
pNewSoldier->aiData.bOrders = SEEKENEMY;
pNewSoldier->aiData.bAttitude = AGGRESSIVE;
////////////// stuff for poisoning ///////////////////////////////////
// this is important - by declaring the gap between bLife and bLifeMax as bBleeding, the zombies will bleed (even more if they are damaged)
// all their lifepoints are also poisoned. Thereby all bleeding damage will be poisoned bleeding damage
// as they have bPoisonAbsorption of at least 200%, they will absorp this poison damage
// This leads to them GAINING life through bleeding
// They can thereby regain their health in battle (although not very fast)
pNewSoldier->bBleeding = pNewSoldier->stats.bLifeMax - pNewSoldier->stats.bLife;
pNewSoldier->bPoisonSum = pNewSoldier->stats.bLifeMax;
pNewSoldier->bPoisonLife = pNewSoldier->stats.bLife;
pNewSoldier->bPoisonBleeding = pNewSoldier->bPoisonSum - pNewSoldier->bPoisonLife;
// zombies get 200% poison absorption, but no resistance to it, as it would reduce their healing
pNewSoldier->bPoisonResistance = 0;
pNewSoldier->bPoisonAbsorption = 200 + Random(100);
//////////////////////////////////////////////////////////////////////
memcpy( &(pNewSoldier->name), &(pCorpse->name), sizeof(CHAR16) * 10 );
pNewSoldier->name[9] = '\0';
// add skills according to difficulty level
switch( gGameExternalOptions.sZombieDifficultyLevel )
{
case 4:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[2] = ATHLETICS_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = MARTIALARTS_OT;
}
break;
case 3:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = ATHLETICS_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = HANDTOHAND_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
case 2:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = MARTIAL_ARTS_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
case 1:
default:
if ( gGameOptions.fNewTraitSystem )
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_NT;
pNewSoldier->stats.ubSkillTraits[2] = NO_SKILLTRAIT_NT;
}
else
{
pNewSoldier->stats.ubSkillTraits[0] = NO_SKILLTRAIT_OT;
pNewSoldier->stats.ubSkillTraits[1] = NO_SKILLTRAIT_OT;
}
break;
}
AddSoldierToSectorNoCalculateDirectionUseAnimation( iNewIndex, usAnimState, 0 );
// If this corpse has camo, use palette from hvobject
if ( pCorpse->def.ubType == ROTTING_STAGE2 )
{
memcpy( pNewSoldier->p8BPPPalette, gpTileCache[ pCorpse->iCachedTileID ].pImagery->vo->pPaletteEntry, sizeof( pCorpse->p8BPPPalette ) * 256 );
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_CAMO_PALETTE )
{
pNewSoldier->bCamo = 60;
pNewSoldier->wornCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE )
{
pNewSoldier->urbanCamo = 60;
pNewSoldier->wornUrbanCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE )
{
pNewSoldier->desertCamo = 60;
pNewSoldier->wornDesertCamo = 60;
}
else if ( pCorpse->def.usFlags & ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE )
{
pNewSoldier->snowCamo = 60;
pNewSoldier->wornSnowCamo = 60;
}
// Reload palettes....
if ( pNewSoldier->bInSector )
{
pNewSoldier->CreateSoldierPalettes( );
}
// Set a pending animation to change stance first...
//SendChangeSoldierStanceEvent( pNewSoldier, ANIM_CROUCH );
// Change to standing,unless we can getup with an animation
pNewSoldier->EVENT_InitNewSoldierAnim( STANDING, 0, TRUE );
pNewSoldier->BeginSoldierGetup( );
// So we can see them!
AllTeamsLookForAll(ALLOW_INTERRUPTS);
}
}
// Flugente Zombies: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState )
{
BOOLEAN canbezombie = FALSE;
*pAnimState = FALLBACKHIT_STOP;
switch ( pCorpse->def.ubType )
{
case SMERC_BCK:
case SMERC_DHD:
case SMERC_FALL:
case MMERC_BCK:
case MMERC_DHD:
case MMERC_FALL:
case FMERC_BCK:
case FMERC_DHD:
case FMERC_FALL:
case ROTTING_STAGE2:
canbezombie = TRUE;
*pAnimState = FALLBACKHIT_STOP;
break;
case SMERC_FWD:
case SMERC_PRN:
case SMERC_FALLF:
case MMERC_FWD:
case MMERC_PRN:
case MMERC_FALLF:
case FMERC_FWD:
case FMERC_PRN:
case FMERC_FALLF:
canbezombie = TRUE;
*pAnimState = FALLFORWARD_HITDEATH_STOP;
break;
case M_DEAD1:
canbezombie = TRUE;
*pAnimState = GENERIC_HIT_DEATH;
break;
case M_DEAD2:
canbezombie = TRUE;
*pAnimState = CIV_DIE2;
case H_DEAD1:
case K_DEAD1:
case FT_DEAD1:
case S_DEAD1:
case W_DEAD1:
case C_DEAD1:
case H_DEAD2:
case K_DEAD2:
case FT_DEAD2:
case S_DEAD2:
case W_DEAD2:
case C_DEAD2:
canbezombie = TRUE;
*pAnimState = STANDING;
default:
;
}
return( canbezombie );
}
+38 -21
View File
@@ -26,14 +26,14 @@ enum RottingCorpseDefines
MMERC_FALL,
MMERC_FALLF,
FMERC_JFK,
FMERC_BCK,
FMERC_FWD,
FMERC_JFK, // head has exploded
FMERC_BCK, // body lying backward
FMERC_FWD, // body lying forward
FMERC_DHD,
FMERC_PRN,
FMERC_WTR,
FMERC_FALL,
FMERC_FALLF,
FMERC_PRN, // body lying on the belly while looking forward, one leg to the side
FMERC_WTR, // body lying in water
FMERC_FALL, // body lying backward, fallen from roof
FMERC_FALLF, // body lying forward, fallen from roof
// CIVS
M_DEAD1,
@@ -73,17 +73,19 @@ enum RottingCorpseDefines
#define ROTTING_CORPSE_FIND_SWEETSPOT_FROM_GRIDNO 0x001 //Find the closest spot to the given gridno
#define ROTTING_CORPSE_FIND_SWEETSPOT_FROM_GRIDNO 0x001 //Find the closest spot to the given gridno
#define ROTTING_CORPSE_USE_NORTH_ENTRY_POINT 0x002 //Find the spot closest to the north entry grid
#define ROTTING_CORPSE_USE_SOUTH_ENTRY_POINT 0x004 //Find the spot closest to the south entry grid
#define ROTTING_CORPSE_USE_EAST_ENTRY_POINT 0x008 //Find the spot closest to the east entry grid
#define ROTTING_CORPSE_USE_WEST_ENTRY_POINT 0x010 //Find the spot closest to the west entry grid
#define ROTTING_CORPSE_USE_CAMO_PALETTE 0x020 //We use cammo palette here....
#define ROTTING_CORPSE_VEHICLE 0x040 //Vehicle Corpse
#define ROTTING_CORPSE_USE_STEALTH_PALETTE 0x080 //We use stealth palette here....
#define ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE 0x100 //We use urban palette here....
#define ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE 0x200 //We use desert palette here....
#define ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE 0x400 //We use snow palette here....
#define ROTTING_CORPSE_VEHICLE 0x040 //Vehicle Corpse
#define ROTTING_CORPSE_USE_STEALTH_PALETTE 0x080 //We use stealth palette here....
#define ROTTING_CORPSE_USE_URBAN_CAMO_PALETTE 0x100 //We use urban palette here....
#define ROTTING_CORPSE_USE_DESERT_CAMO_PALETTE 0x200 //We use desert palette here....
#define ROTTING_CORPSE_USE_SNOW_CAMO_PALETTE 0x400 //We use snow palette here....
#define ROTTING_CORPSE_NEVER_RISE_AGAIN 0x800 //a zombie cannot be created from this corpse (if not set, it'll eventually rise again )
typedef struct
{
@@ -94,26 +96,29 @@ typedef struct
FLOAT dYPos;
INT16 sHeightAdjustment;
PaletteRepID HeadPal; // Palette reps
PaletteRepID PantsPal;
PaletteRepID VestPal;
PaletteRepID SkinPal;
PaletteRepID HeadPal; // Palette reps
PaletteRepID PantsPal;
PaletteRepID VestPal;
PaletteRepID SkinPal;
UINT8 ubDirection;
UINT32 uiTimeOfDeath;
UINT32 uiTimeOfDeath;
UINT16 usFlags;
UINT16 usFlags;
INT8 bLevel;
INT8 bVisible;
INT8 bNumServicingCrows;
UINT8 ubProfile;
BOOLEAN fHeadTaken;
UINT8 ubAIWarningValue;
BOOLEAN fHeadTaken;
UINT8 ubAIWarningValue;
UINT8 ubFiller[ 12 ];
// Flugente: added name so we can display individual name if corpse gets resurrected...
CHAR16 name[ 10 ];
} ROTTING_CORPSE_DEFINITION;
@@ -135,6 +140,9 @@ typedef struct
BOOLEAN fAttractCrowsOnlyWhenOnScreen;
INT32 iID;
// Flugente: added name so we can display individual name if corpse gets resurrected...
CHAR16 name[ 10 ];
} ROTTING_CORPSE;
@@ -192,4 +200,13 @@ INT32 GetGridNoOfCorpseGivenProfileID( UINT8 ubProfileID );
void DecayRottingCorpseAIWarnings( void );
UINT8 GetNearestRottingCorpseAIWarning( INT32 sGridNo );
// Flugente: Raise zombies
void RaiseZombies( void );
// Flugente: create a zombie from a corpse
void CreateZombiefromCorpse( ROTTING_CORPSE * pCorpse, UINT16 usAnimState );
// Flugente: returns true if a zombie can be raised from this corpse, and returns the correct pAnimState for the new zombie
BOOLEAN CorpseOkToSpawnZombie( ROTTING_CORPSE * pCorpse, UINT16* pAnimState );
#endif
+14 -6
View File
@@ -18,7 +18,7 @@
#include "Soldier Control.h"
#endif
INT8 EffectiveStrength( SOLDIERTYPE * pSoldier )
INT8 EffectiveStrength( SOLDIERTYPE *pSoldier)
{
INT8 bBandaged;
INT32 iEffStrength;
@@ -29,9 +29,9 @@ INT8 EffectiveStrength( SOLDIERTYPE * pSoldier )
bBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding;
if (pSoldier->stats.bStrength > 0)
{
iEffStrength = pSoldier->stats.bStrength / 2;
iEffStrength += (pSoldier->stats.bStrength / 2) * (pSoldier->stats.bLife + bBandaged / 2) / (pSoldier->stats.bLifeMax);
{
iEffStrength = ( pSoldier->stats.bStrength )/ 2;
iEffStrength += ( (pSoldier->stats.bStrength ) / 2) * (pSoldier->stats.bLife + bBandaged / 2) / (pSoldier->stats.bLifeMax);
}
else
{
@@ -164,7 +164,7 @@ INT8 EffectiveExpLevel( SOLDIERTYPE * pSoldier )
iEffExpLevel -= 1;
}
}
if (iEffExpLevel > 10)
{
// can't go over 10 - SANDRO
@@ -476,7 +476,7 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod )
case OPEN_WITH_CROWBAR:
// Add for crowbar...
iSkill = EffectiveStrength( pSoldier ) + 20;
fForceDamnSound = TRUE;
fForceDamnSound = TRUE;
break;
case SMASH_DOOR_CHECK:
@@ -546,6 +546,14 @@ INT32 SkillCheck( SOLDIERTYPE * pSoldier, INT8 bReason, INT8 bChanceMod )
iSkill /= 2;
}
}
break;
case ATTACH_POWER_PACK: // added by Flugente
// technicians can attach it, other people can'
if ( HAS_SKILL_TRAIT( pSoldier, TECHNICIAN_NT ))
iSkill = 100;
else
iSkill = 0;
break;
default:
iSkill = 0;
+1
View File
@@ -41,6 +41,7 @@ enum SkillChecks
ATTACHING_SPECIAL_ITEM_CHECK,
ATTACHING_SPECIAL_ELECTRONIC_ITEM_CHECK,
DISARM_ELECTRONIC_TRAP_CHECK,
ATTACH_POWER_PACK, // Flugente: attach a power pack to power armor
} ;
+3
View File
@@ -3485,6 +3485,9 @@ BOOLEAN HandleSoldierDeath( SOLDIERTYPE *pSoldier , BOOLEAN *pfMadeCorpse )
case SOLDIER_CLASS_CREATURE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
break;
case SOLDIER_CLASS_ZOMBIE :
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsZombies++;
break;
default :
if ( CREATURE_OR_BLOODCAT( pSoldier ) )
gMercProfiles[ MercPtrs[ ubAttacker ]->ubProfile ].records.usKillsCreatures++;
+427 -138
View File
@@ -110,6 +110,8 @@
#include "Dialogue Control.h"
#include "IMP Skill Trait.h" // added by Flugente
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
class SOLDIERTYPE;
@@ -135,6 +137,10 @@ extern INT16 DirIncrementer[8];
#define MIN_SUBSEQUENT_SNDS_DELAY 2000
#include "connect.h"
extern void TeleportSelectedSoldier( void );
extern BOOLEAN AddSoldierToSectorNoCalculateDirectionUseAnimation( UINT8 ubID, UINT16 usAnimState, UINT16 usAnimCode );
// Enumerate extended directions
enum
{
@@ -996,6 +1002,12 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src)
this->wornSnowCamo = src.wornSnowCamo;
this->bScopeMode = USE_BEST_SCOPE;
this->bPoisonBleeding = 0;
this->bPoisonLife = 0;
this->bPoisonSum = 0;
this->bPoisonResistance = 0;
this->bPoisonAbsorption = 0;
}
return *this;
}
@@ -1337,6 +1349,7 @@ MERCPROFILESTRUCT& MERCPROFILESTRUCT::operator=(const OLD_MERCPROFILESTRUCT_101&
this->records.usKillsAdmins = (src.usKills/4);
this->records.usKillsHostiles = 0;
this->records.usKillsCreatures = 0;
this->records.usKillsZombies = 0;
this->records.usKillsTanks = 0;
this->records.usKillsOthers = 0;
this->records.usAssistsMercs = (src.usAssists*3/4);
@@ -1476,7 +1489,7 @@ MERCPROFILESTRUCT& MERCPROFILESTRUCT::operator=(const OLD_MERCPROFILESTRUCT_101&
this->iMercMercContractLength = src.iMercMercContractLength;//Used for MERC mercs, specifies how many days the merc has gone since last page
this->uiTotalCostToDate = src.uiTotalCostToDate;// The total amount of money that has been paid to the merc for their salary
this->uiTotalCostToDate = src.uiTotalCostToDate;// The total amount of money that has been paid to the merc for their salary
}
return *this;
}
@@ -1669,7 +1682,7 @@ void HandleSystemNewAISituation( SOLDIERTYPE *pSoldier, BOOLEAN fResetABC );
UINT16 *CreateEnemyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen );
UINT16 *CreateEnemyGreyGlow16BPPPalette( SGPPaletteEntry *pPalette, UINT32 rscale, UINT32 gscale, BOOLEAN fAdjustGreen );
void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed );
void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed, BOOLEAN fAllowPoisoning );
INT32 CheckBleeding( SOLDIERTYPE *pSoldier );
void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT8 ubNewDirection, BOOLEAN fInitalMove, UINT16 usAnimState );
@@ -5409,7 +5422,7 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1
HandleMoraleEvent( this, MORALE_TOOK_LOTS_OF_DAMAGE, this->sSectorX, this->sSectorY, this->bSectorZ );
}
}
// SWITCH IN TYPE OF WEAPON
if ( ubSpecial == FIRE_WEAPON_TOSSED_OBJECT_SPECIAL )
{
@@ -5652,12 +5665,14 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1
// OK, If we are a vehicle.... damage vehicle...( people inside... )
if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
this->SoldierTakeDamage( ANIM_CROUCH, sDamage, sBreathLoss, ubReason, this->ubAttackerID, NOWHERE, FALSE, TRUE );
this->SoldierTakeDamage( ANIM_CROUCH, sDamage, 0, sBreathLoss, ubReason, this->ubAttackerID, NOWHERE, FALSE, TRUE );
return;
}
INT16 poisondamage = (INT16) ( sDamage * MercPtrs[ubAttackerID]->GetPoisonDamagePercentage() / 100 );
// DEDUCT LIFE
ubCombinedLoss = this->SoldierTakeDamage( ANIM_CROUCH, sDamage, sBreathLoss, ubReason, this->ubAttackerID, NOWHERE, FALSE, TRUE );
ubCombinedLoss = this->SoldierTakeDamage( ANIM_CROUCH, sDamage, poisondamage, sBreathLoss, ubReason, this->ubAttackerID, NOWHERE, FALSE, TRUE );
// ATE: OK, Let's check our ASSIGNMENT state,
// If anything other than on a squad or guard, make them guard....
@@ -7053,10 +7068,6 @@ void SOLDIERTYPE::EVENT_BeginMercTurn( BOOLEAN fFromRealTime, INT32 iRealTimeCou
{
HandleEndTurnDrugAdjustments( this );
}
else
{
HandleEndTurnDrugAdjustments( this );
}
// ATE: Don't bleed if in AUTO BANDAGE!
if ( !gTacticalStatus.fAutoBandageMode )
@@ -8657,7 +8668,16 @@ void SOLDIERTYPE::BeginSoldierClimbUpRoof( void )
this->ubPendingDirection = bNewDirection;
//this->usPendingAnimation = CLIMBUPROOF;
this->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE );
// Flugente: In case an animation is missing (zombies with bodytype of civilians), we TELEPORT instead
if ( IsAnimationValidForBodyType( this, CLIMBUPROOF ) == FALSE )
{
SetSoldierHeight( 50.0 );
TeleportSoldier( this, this->sTempNewGridNo, TRUE );
EndAIGuysTurn( this);
}
else
this->EVENT_InitNewSoldierAnim( CLIMBUPROOF, 0 , FALSE );
this->InternalReceivingSoldierCancelServices( FALSE );
this->InternalGivingSoldierCancelServices( FALSE );
@@ -8810,7 +8830,7 @@ void SOLDIERTYPE::BeginSoldierClimbWallUp( void )
UINT32 SleepDartSuccumbChance( SOLDIERTYPE * pSoldier )
{
UINT32 uiChance;
INT8 bEffectiveStrength;
INT16 bEffectiveStrength;
// figure out base chance of succumbing,
bEffectiveStrength = EffectiveStrength( pSoldier );
@@ -9006,12 +9026,12 @@ void HandleTakeDamageDeath( SOLDIERTYPE *pSoldier, UINT8 bOldLife, UINT8 ubReaso
}
UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBreathLoss, UINT8 ubReason, UINT8 ubAttacker, INT32 sSourceGrid, INT16 sSubsequent, BOOLEAN fShowDamage )
UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sPoisonAdd, INT16 sBreathLoss, UINT8 ubReason, UINT8 ubAttacker, INT32 sSourceGrid, INT16 sSubsequent, BOOLEAN fShowDamage )
{
#ifdef JA2BETAVERSION
if (is_networked) {
CHAR tmpMPDbgString[512];
sprintf(tmpMPDbgString,"SoldierTakeDamage ( bHeight : %i , sLifeDeduct : %i , sBreathLoss : %i , ubReason : %i , ubAttacker : %i , sSourceGrid : %i , sSubsequent : %i , fShowDamage : %i )\n", bHeight , sLifeDeduct , sBreathLoss , ubReason , ubAttacker , sSourceGrid , sSubsequent , fShowDamage );
sprintf(tmpMPDbgString,"SoldierTakeDamage ( bHeight : %i , sLifeDeduct : %i , sPoisonAdd : %i , sBreathLoss : %i , ubReason : %i , ubAttacker : %i , sSourceGrid : %i , sSubsequent : %i , fShowDamage : %i )\n", bHeight , sLifeDeduct , sPoisonAdd, sBreathLoss , ubReason , ubAttacker , sSourceGrid , sSubsequent , fShowDamage );
MPDebugMsg(tmpMPDbgString);
}
#endif
@@ -9025,6 +9045,11 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
this->ubLastDamageReason = ubReason;
// check: poison damage cannot be higher than damage
sPoisonAdd = min(sPoisonAdd, sLifeDeduct);
// reduce poison damage by poison resistance
sPoisonAdd = (INT16)(sPoisonAdd * (100 - this->GetPoisonResistance())/100);
// CJC Jan 21 99: add check to see if we are hurting an enemy in an enemy-controlled
// sector; if so, this is a sign of player activity
@@ -9059,6 +9084,11 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
// Deduct life!, Show damage if we want!
bOldLife = this->stats.bLife;
// we need this to relation to decide how to redistribute poison points
FLOAT dpoisonliferelation = 1.0;
if ( bOldLife > 0 )
dpoisonliferelation = (FLOAT)(this->bPoisonLife / bOldLife);
// OK, If we are a vehicle.... damage vehicle...( people inside... )
if ( this->flags.uiStatusFlags & SOLDIER_VEHICLE )
{
@@ -9182,11 +9212,41 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
if (sLifeDeduct > this->stats.bLife)
{
this->stats.bLife = 0;
this->bPoisonSum = 0;
this->bPoisonLife = 0;
this->bPoisonBleeding = 0;
}
else
{
// we might have poison absorption
INT16 sLifeGainAbsorption = (INT16) ((sPoisonAdd * this->GetPoisonAbsorption())/100);
// life reduction gets reduced itself by life gained through absorption
sLifeDeduct -= sLifeGainAbsorption;
// poison points however get increased by absorped life points (poison was absorbed, not resisted)
INT16 poisongained = sPoisonAdd + sLifeGainAbsorption;
// Decrease Health
this->stats.bLife -= sLifeDeduct;
// life may increase by poison absorption, so make sure it doesn't rise too much
this->stats.bLife = min(this->stats.bLife, this->stats.bLifeMax);
// increase poisoning
this->bPoisonSum = min(this->stats.bLifeMax, this->bPoisonSum + poisongained);
// increase poison life if we gained life through absorption
if ( sLifeGainAbsorption > 0 )
this->bPoisonLife = min(this->bPoisonSum, this->bPoisonLife + sLifeGainAbsorption);
// if no life was lost, also add sPoisonAdd to bPoisonLife
if ( sLifeDeduct <= 0 )
this->bPoisonLife = min(this->bPoisonSum, this->bPoisonLife + sPoisonAdd);
else
// we reduce bPoisonLife according to old percentage of poison life to life
this->bPoisonLife -= (INT8) (dpoisonliferelation * sLifeDeduct);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -9211,7 +9271,8 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
// ATE: Put some logic in here to allow enemies to die quicker.....
// Are we an enemy?
if ( this->bSide != gbPlayerNum && !this->aiData.bNeutral && this->ubProfile == NO_PROFILE )
// zombies don't die suddenly, as they regenerate health by bloodloss and poison. You have to make sure they die!
if ( this->bSide != gbPlayerNum && !this->aiData.bNeutral && this->ubProfile == NO_PROFILE && !this->IsZombie() )
{
// ATE: Give them a chance to fall down...
if ( this->stats.bLife > 0 && this->stats.bLife < ( OKLIFE - 1 ) )
@@ -9219,11 +9280,15 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
// Are we taking damage from bleeding?
if ( ubReason == TAKE_DAMAGE_BLOODLOSS )
{
// Fifty-fifty chance to die now!
// Fifty-fifty chance to die now!
if ( Random( 3 ) == 0 || gTacticalStatus.Team[ this->bTeam ].bMenInSector == 1 )
{
// Kill!
this->stats.bLife = 0;
this->bPoisonSum = 0;
this->bPoisonLife = 0;
this->bPoisonBleeding = 0;
}
}
else
@@ -9233,10 +9298,20 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
{
// Kill!
this->stats.bLife = 0;
this->bPoisonSum = 0;
this->bPoisonLife = 0;
this->bPoisonBleeding = 0;
}
}
}
}
else if ( this->IsZombie() && this->stats.bLife > 0 && this->stats.bLife < OKLIFE )
{
// a zombie doesn't automatically die, so he would normally stand up again after being hit.
// We don't want that, because he is dying, so we manually skip that animation
this->usPendingAnimation = NO_PENDING_ANIMATION;
}
if ( fShowDamage )
{
@@ -9247,6 +9322,10 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
if ( this->stats.bLife < 0 )
{
this->stats.bLife = 0;
this->bPoisonSum = 0;
this->bPoisonLife = 0;
this->bPoisonBleeding = 0;
}
@@ -9267,11 +9346,29 @@ UINT8 SOLDIERTYPE::SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBr
{
// HTH does 1 pt bleeding per hit
this->bBleeding = this->bBleeding + 1;
// add poison point according to poison/life relation
this->bPoisonBleeding += (INT8) (dpoisonliferelation );
}
}
else
{
this->bBleeding = this->stats.bLifeMax - ( this->stats.bLife + bBandage );
// if we would actually bleed _less_ after applying the damage received (poison absorption), we reduce bleeding only if the new bBandage would be zero
// by this, we can continue bleeding, and eventually bleeding
// the normal behaviour is unchanged, as this case can't happen without poison absorption
if ( sLifeDeduct < 0 )
{
INT8 oldBleeding = this->bBleeding;
this->bBleeding = min(this->bBleeding, this->stats.bLifeMax - this->stats.bLife );
this->bPoisonBleeding = max(0, this->bPoisonBleeding - (oldBleeding - this->bBleeding));
}
else
{
this->bBleeding = this->stats.bLifeMax - ( this->stats.bLife + bBandage );
// we increase bPoisonLife according to old percentage of poison life to life
this->bPoisonBleeding += (INT8) (dpoisonliferelation * sLifeDeduct);
}
}
}
@@ -10089,7 +10186,7 @@ BOOLEAN SOLDIERTYPE::CheckSoldierHitRoof( void )
//this->EVENT_InitNewSoldierAnim( FALLFORWARD_ROOF, 0 , FALSE );
// Deduct hitpoints/breath for falling!
this->SoldierTakeDamage( ANIM_CROUCH, 100, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
this->SoldierTakeDamage( ANIM_CROUCH, 100, 0, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
fReturnVal = TRUE;
@@ -10104,7 +10201,7 @@ BOOLEAN SOLDIERTYPE::CheckSoldierHitRoof( void )
this->usPendingAnimation = FALLOFF;
// Deduct hitpoints/breath for falling!
this->SoldierTakeDamage( ANIM_CROUCH, 100, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
this->SoldierTakeDamage( ANIM_CROUCH, 100, 0, 5000, TAKE_DAMAGE_FALLROOF, NOBODY, NOWHERE, 0, TRUE );
fReturnVal = TRUE;
}
@@ -10139,15 +10236,21 @@ void SOLDIERTYPE::BeginSoldierClimbDownRoof( void )
SetUIBusy( this->ubID );
}
this->sTempNewGridNo = NewGridNo( this->sGridNo, (UINT16)DirectionInc(bNewDirection ) );
bNewDirection = gTwoCDirection[ bNewDirection ];
this->ubPendingDirection = bNewDirection;
this->EVENT_InitNewSoldierAnim( JUMPDOWNWALL, 0 , FALSE );
// Flugente: In case an animation is missing (zombies with bodytype of civilians), we TELEPORT instead
if ( IsAnimationValidForBodyType( this, JUMPDOWNWALL ) == FALSE )
{
SetSoldierHeight( 0.0 );
TeleportSoldier( this, this->sTempNewGridNo, TRUE );
EndAIGuysTurn( this);
}
else
this->EVENT_InitNewSoldierAnim( JUMPDOWNWALL, 0 , FALSE );
this->InternalReceivingSoldierCancelServices( FALSE );
this->InternalGivingSoldierCancelServices( FALSE );
@@ -10952,6 +11055,9 @@ void SOLDIERTYPE::ReviveSoldier( void )
this->stats.bLife = this->stats.bLifeMax;
this->bBleeding = 0;
this->bPoisonBleeding = 0;
this->bPoisonLife = 0;
this->bPoisonSum = 0;
this->iHealableInjury = 0; // added by SANDRO
this->ubDesiredHeight = ANIM_STAND;
@@ -11376,7 +11482,7 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
#if (defined JA2UB || defined JA113NODEMO)
if ( fMartialArtist && !Item[usItem].crowbar && this->ubBodyType == REGMALE)
#else
if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE ) // SANDRO - added check for body type
if ( fMartialArtist && !AreInMeanwhile( ) && !Item[usItem].crowbar && this->ubBodyType == REGMALE && !IsZombie() ) // SANDRO - added check for body type
#endif
{
// Are we in attack mode yet?
@@ -11391,66 +11497,136 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio
}
else
{
// Look at stance of target
switch( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight )
// Flugente: civilians can be zombies too, but they do not have a 'punch' animation. Simple fix: They 'attack' without animation...
// CHECK IF WE CAN DO THIS ANIMATION!
if ( this->IsZombie() && IsAnimationValidForBodyType( this, PUNCH ) == FALSE )
{
case ANIM_STAND:
case ANIM_CROUCH:
if ( !Item[usItem].crowbar )
if ( gGameExternalOptions.fZombieExplodingCivs )
{
this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE );
// Solution 1: zombie explodes, killing himself and eventually also killing his target
// Lower hitpoints, to ensure we will die in explosion (otherwise there might be multiple explosions or zombies not dying correctly...)
if ( stats.bLife > 2 )
stats.bLife = 2;
// Explosion of a Jar of RDX Crystals
IgniteExplosion( this->ubID, this->sX, this->sY, (INT16) (gpWorldLevelData[this->sGridNo].sHeight), this->sGridNo, 136, this->pathing.bLevel );
}
else
{
this->EVENT_InitNewSoldierAnim( CROWBAR_ATTACK, 0 , FALSE );
}
// CHECK IF HE CAN SEE US, IF SO CHANGE DIR
if ( pTSoldier->aiData.bOppList[ this->ubID ] == 0 && pTSoldier->bTeam != this->bTeam )
{
// Get direction to target
// IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T TURN
if ( !( pTSoldier->flags.uiStatusFlags & ( SOLDIER_MONSTER | SOLDIER_ANIMAL | SOLDIER_VEHICLE ) ) )
// Solution 2: Crude simulation of a 'melee' attack (this is a rig-up, a better solution needs to be found).
// do we 'hit'?
if ( Random(100) > 30 )
{
// OK, stop merc....
pTSoldier->EVENT_StopMerc( pTSoldier->sGridNo, pTSoldier->ubDirection );
// Play sound
PlayJA2SampleFromFile( "Sounds\\zombie_swish1.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
if ( pTSoldier->bTeam != gbPlayerNum )
INT8 oldlife = pTSoldier->stats.bLife;
INT16 damage = (INT16)(5 + Random(20));
if ( pTSoldier->stats.bLife - damage < 0 )
damage = oldlife;
// We've got a problem if we kill someone outright ithout him collapsing properly...
// FIX: We'll adjust our damage, so if we'd kill someone without collapsing first, we lower our damage, to let him collapse
// After all, this whole thing's a rig up, so there shouldn't be a problem with that
if ( oldlife >= OKLIFE && oldlife <= damage )
damage -= (INT16)((5 + Random(5)));
INT16 breathdamage = (INT16)(500 + Random(1500));
if ( pTSoldier->bBreath - breathdamage < 0 )
breathdamage = pTSoldier->bBreath;
INT16 poisondamage = (INT16) ( sDamage * this->GetPoisonDamagePercentage() / 100 );
// zombies do ~50% poison damage
pTSoldier->SoldierTakeDamage( 0, damage, poisondamage, breathdamage, TAKE_DAMAGE_HANDTOHAND, this->ubID, pTSoldier->sGridNo, 0, TRUE );
if ( pTSoldier->stats.bLife == 0 )
{
CancelAIAction( pTSoldier, TRUE );
// FINISH HIM!
HandleTakeDamageDeath( pTSoldier, oldlife, TAKE_DAMAGE_BLOODLOSS );
}
else if ( pTSoldier->stats.bLife < OKLIFE && !pTSoldier->bCollapsed )
{
// let the target collapse...
SoldierCollapse(pTSoldier);
}
ubTDirection = (UINT8)GetDirectionFromGridNo( this->sGridNo, pTSoldier );
SendSoldierSetDesiredDirectionEvent( pTSoldier, ubTDirection );
}
}
break;
case ANIM_PRONE:
// CHECK OUR STANCE
// ATE: Added this for CIV body types 'cause of elliot
if ( !IS_MERC_BODY_TYPE( this ) )
{
this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE );
}
else
{
if ( gAnimControl[ this->usAnimState ].ubEndHeight != ANIM_CROUCH )
{
// SET DESIRED STANCE AND SET PENDING ANIMATION
SendChangeSoldierStanceEvent( this, ANIM_CROUCH );
this->usPendingAnimation = PUNCH_LOW;
}
else
{
// USE crouched one
// NEED TO CHANGE STANCE IF NOT CROUCHD!
this->EVENT_InitNewSoldierAnim( PUNCH_LOW, 0 , FALSE );
// Play sound
PlayJA2SampleFromFile( "Sounds\\zombie_swish2.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN );
}
// zombie is done doing harm...
EndAIGuysTurn( this);
}
// ensure that we are running on our way to the next enemy
this->EVENT_InitNewSoldierAnim( RUNNING, 0 , FALSE );
}
else
{
// Look at stance of target
switch( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight )
{
case ANIM_STAND:
case ANIM_CROUCH:
if ( !Item[usItem].crowbar )
{
this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE );
}
else
{
this->EVENT_InitNewSoldierAnim( CROWBAR_ATTACK, 0 , FALSE );
}
// CHECK IF HE CAN SEE US, IF SO CHANGE DIR
if ( pTSoldier->aiData.bOppList[ this->ubID ] == 0 && pTSoldier->bTeam != this->bTeam )
{
// Get direction to target
// IF WE ARE AN ANIMAL, CAR, MONSTER, DONT'T TURN
if ( !( pTSoldier->flags.uiStatusFlags & ( SOLDIER_MONSTER | SOLDIER_ANIMAL | SOLDIER_VEHICLE ) ) )
{
// OK, stop merc....
pTSoldier->EVENT_StopMerc( pTSoldier->sGridNo, pTSoldier->ubDirection );
if ( pTSoldier->bTeam != gbPlayerNum )
{
CancelAIAction( pTSoldier, TRUE );
}
ubTDirection = (UINT8)GetDirectionFromGridNo( this->sGridNo, pTSoldier );
SendSoldierSetDesiredDirectionEvent( pTSoldier, ubTDirection );
}
}
break;
case ANIM_PRONE:
// CHECK OUR STANCE
// ATE: Added this for CIV body types 'cause of elliot
if ( !IS_MERC_BODY_TYPE( this ) )
{
this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE );
}
else
{
if ( gAnimControl[ this->usAnimState ].ubEndHeight != ANIM_CROUCH )
{
// SET DESIRED STANCE AND SET PENDING ANIMATION
SendChangeSoldierStanceEvent( this, ANIM_CROUCH );
this->usPendingAnimation = PUNCH_LOW;
}
else
{
// USE crouched one
// NEED TO CHANGE STANCE IF NOT CROUCHD!
this->EVENT_InitNewSoldierAnim( PUNCH_LOW, 0 , FALSE );
}
}
break;
}
break;
}
}
@@ -11682,7 +11858,7 @@ void SOLDIERTYPE::EVENT_SoldierEnterVehicle( INT32 sGridNo, UINT8 ubDirection )
UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT16 sStatus )
{
UINT32 uiDressSkill, uiPossible, uiActual, uiMedcost, uiDeficiency, uiAvailAPs, uiUsedAPs;
UINT8 ubBelowOKlife, ubPtsLeft = 0;
UINT8 ubBelowOKlife = 0, ubPtsLeft = 0;
BOOLEAN fRanOut = FALSE;
BOOLEAN fOnSurgery = FALSE;
INT8 bInitialBleeding;
@@ -11860,6 +12036,10 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
// use up appropriate # of actual healing points
ubPtsLeft -= (2 * ubBelowOKlife);
// raise bPoisonLife, reduce bPoisonBleeding
pVictim->bPoisonLife = min(pVictim->bPoisonLife + ubBelowOKlife, pVictim->bPoisonSum);
pVictim->bPoisonBleeding = max(0, pVictim->bPoisonBleeding - ubBelowOKlife);
}
else
{
@@ -11875,12 +12055,17 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
pVictim->bBleeding -= ( ubPtsLeft / 2);
ubPtsLeft = ubPtsLeft % 2; // if ptsLeft was odd, ptsLeft = 1
// raise bPoisonLife, reduce bPoisonBleeding
pVictim->bPoisonLife = min(pVictim->bPoisonLife + ( ubPtsLeft / 2), pVictim->bPoisonSum);
pVictim->bPoisonBleeding = max(0, pVictim->bPoisonBleeding - ( ubPtsLeft / 2));
}
// this should never happen any more, but make sure bleeding not negative
if (pVictim->bBleeding < 0)
{
pVictim->bBleeding = 0;
pVictim->bPoisonBleeding = 0;
}
// if this healing brought the patient out of the worst of it, cancel dying
@@ -11970,11 +12155,13 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
if (pVictim->bBleeding >= (usLifeReturned/100))
{
pVictim->bBleeding -= (usLifeReturned/100);
pVictim->bPoisonBleeding = max(0, pVictim->bPoisonBleeding - (usLifeReturned/100) );
uiMedcost += (usLifeReturned / 200); // add medkit points cost for unbandaged part
}
else
{
pVictim->bBleeding = 0;
pVictim->bPoisonBleeding = 0;
uiMedcost += max( 0, (((usLifeReturned/100) - pVictim->bBleeding) / 2)); // add medkit points cost for unbandaged part
}
}
@@ -11983,6 +12170,7 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
pVictim->stats.bLife = pVictim->stats.bLifeMax;
pVictim->iHealableInjury = 0;
pVictim->bBleeding = 0;
pVictim->bPoisonBleeding = 0;
}
// Reduce max breath based on life returned
if ( (pVictim->bBreathMax - (((usLifeReturned/100) * gSkillTraitValues.usDOSurgeryMaxBreathLoss )/ 100)) <= BREATHMAX_ABSOLUTE_MINIMUM )
@@ -12010,10 +12198,12 @@ UINT32 SOLDIERTYPE::SoldierDressWound( SOLDIERTYPE *pVictim, INT16 sKitPts, INT1
{
ubPtsLeft -= pVictim->bBleeding;
pVictim->bBleeding = 0;
pVictim->bPoisonBleeding = 0;
}
else // bandage what we can
{
pVictim->bBleeding -= ubPtsLeft;
pVictim->bPoisonBleeding = max(0, pVictim->bPoisonBleeding - ubPtsLeft);
ubPtsLeft = 0;
}
@@ -13189,6 +13379,8 @@ INT32 SOLDIERTYPE::GetDamageResistance(BOOLEAN fAutoResolve, BOOLEAN fCalcBreath
resistance += gGameExternalOptions.sEnemyRegularDamageResistance;
else if (this->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteDamageResistance != 0)
resistance += gGameExternalOptions.sEnemyEliteDamageResistance;
else if (IsZombie())
resistance += gGameExternalOptions.sEnemyZombieDamageResistance;
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -13236,6 +13428,74 @@ INT32 SOLDIERTYPE::GetDamageResistance(BOOLEAN fAutoResolve, BOOLEAN fCalcBreath
return( resistance );
}
INT16 SOLDIERTYPE::GetSoldierCriticalDamageBonus( void )
{
INT16 val = 0;
return val;
}
BOOLEAN SOLDIERTYPE::IsZombie( void )
{
return( ubSoldierClass == SOLDIER_CLASS_ZOMBIE );
}
INT16 SOLDIERTYPE::GetPoisonResistance( void )
{
// Flugente: resistance can per definition only be between -100 and 100 (at least that's my definition)
INT16 val = bPoisonResistance;
// without WH40K, there are no modifiers
val = max(-100, val);
val = min(100, val);
return( val );
}
INT16 SOLDIERTYPE::GetPoisonAbsorption( void )
{
// Flugente: absorption can per definition only be >= 0 (at least that's my definition)
INT16 val = bPoisonAbsorption;
val = max(0, val);
return( val );
}
INT16 SOLDIERTYPE::GetPoisonDamagePercentage( void )
{
// Flugente: this percentage has to be between 0% and 100%
INT16 val = 0;
// zombies poison damage percentage is externalised
if ( IsZombie() )
val += gGameExternalOptions.sZombiePoisonDamagePercentage;
if ( this->usAttackingWeapon )
{
val += Item[this->usAttackingWeapon].bPoisonPercentage;
if ( Item[this->usAttackingWeapon].usItemClass == IC_GUN )
{
// check for modificators (attachments, poisoned ammunition)
// check for poisoned ammunition
UINT8 ammotype = this->inv[ this->ubAttackingHand ][0]->data.gun.ubGunAmmoType;
val += AmmoTypes[ammotype].poisonPercentage;
// check for attachments with a bonus to poison (currently, none exist)
}
}
val = max(0, val);
val = min(100, val);
return( val );
}
INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
{
INT8 bBandaged; //,savedOurTurn;
@@ -13244,94 +13504,116 @@ INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
if ( pSoldier->stats.bLife != 0 )
{
// if merc is hurt beyond the minimum required to bleed, or he's dying
if ( ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD) || pSoldier->stats.bLife < OKLIFE )
// Flugente: also allow bleeding if we would regenerate health through it, which happens when we have enough absorption and are poisoned enough (only guaranteed if fully poisoned)
if ( ( ( pSoldier->bBleeding > MIN_BLEEDING_THRESHOLD) || pSoldier->stats.bLife < OKLIFE ) || ( pSoldier->bPoisonSum == pSoldier->stats.bLifeMax && pSoldier->GetPoisonAbsorption() >= 200 ) )
{
// if he's NOT in the process of being bandaged or DOCTORed
if ( ( pSoldier->ubServiceCount == 0 ) && ( AnyDoctorWhoCanHealThisPatient( pSoldier, HEALABLE_EVER ) == NULL ) )
{
// may drop blood whether or not any bleeding takes place this turn
if ( pSoldier->bTilesMoved < 1 )
{
iBlood = ( ( pSoldier->bBleeding - MIN_BLEEDING_THRESHOLD ) / BLOODDIVISOR ); // + pSoldier->dying;
if ( iBlood > MAXBLOODQUANTITY )
{
iBlood = MAXBLOODQUANTITY;
}
}
{
iBlood = ( ( pSoldier->bBleeding - MIN_BLEEDING_THRESHOLD ) / BLOODDIVISOR ); // + pSoldier->dying;
if ( iBlood > MAXBLOODQUANTITY )
{
iBlood = MAXBLOODQUANTITY;
}
}
else
{
iBlood = NOBLOOD;
}
{
iBlood = NOBLOOD;
}
// Are we in a different mode?
if ( !(gTacticalStatus.uiFlags & TURNBASED ) || !(gTacticalStatus.uiFlags & INCOMBAT ) )
{
pSoldier->dNextBleed -= (FLOAT)RT_NEXT_BLEED_MODIFIER;
}
{
pSoldier->dNextBleed -= (FLOAT)RT_NEXT_BLEED_MODIFIER;
}
else
{
// Do a single step descrease
pSoldier->dNextBleed--;
}
{
// Do a single step descrease
pSoldier->dNextBleed--;
}
// if it's time to lose some blood
if ( pSoldier->dNextBleed <= 0)
{
// first, calculate if soldier is bandaged
bBandaged = pSoldier->stats.bLifeMax - pSoldier->bBleeding - pSoldier->stats.bLife;
{
// first, calculate if soldier is bandaged
bBandaged = pSoldier->stats.bLifeMax - pSoldier->bBleeding - pSoldier->stats.bLife;
// as long as he's bandaged and not "dying"
if ( bBandaged && pSoldier->stats.bLife >= OKLIFE )
{
// just bleeding through existing bandages
pSoldier->bBleeding++;
SoldierBleed( pSoldier, TRUE );
}
else // soldier is either not bandaged at all or is dying
{
if ( pSoldier->stats.bLife < OKLIFE ) // if he's dying
// as long as he's bandaged and not "dying"
if ( bBandaged && pSoldier->stats.bLife >= OKLIFE )
{
// if he's conscious, and he hasn't already, say his "dying quote"
if ( ( pSoldier->stats.bLife >= CONSCIOUSNESS ) && !pSoldier->flags.fDyingComment )
// just bleeding through existing bandages
pSoldier->bBleeding++;
SoldierBleed( pSoldier, TRUE, TRUE );
}
else // soldier is either not bandaged at all or is dying
{
if ( pSoldier->stats.bLife < OKLIFE ) // if he's dying
{
TacticalCharacterDialogue( pSoldier, QUOTE_SERIOUSLY_WOUNDED );
// if he's conscious, and he hasn't already, say his "dying quote"
if ( ( pSoldier->stats.bLife >= CONSCIOUSNESS ) && !pSoldier->flags.fDyingComment )
{
TacticalCharacterDialogue( pSoldier, QUOTE_SERIOUSLY_WOUNDED );
pSoldier->flags.fDyingComment = TRUE;
}
pSoldier->flags.fDyingComment = TRUE;
}
// can't permit lifemax to ever bleed beneath OKLIFE, or that
// soldier might as well be dead!
if (pSoldier->stats.bLifeMax >= OKLIFE)
{
// bleeding while "dying" costs a PERMANENT point of life each time!
pSoldier->stats.bLifeMax--;
pSoldier->bBleeding--;
if ( pSoldier->iHealableInjury >= 100) // added check for insta-healable injury - SANDRO
pSoldier->iHealableInjury -= 100;
}
}
}
// can't permit lifemax to ever bleed beneath OKLIFE, or that
// soldier might as well be dead!
if (pSoldier->stats.bLifeMax >= OKLIFE)
{
// Flugente: reduce PERMANENT points of life only if through 'normal' bleeding, not by poisoning
// problem is that this function applies every bleeding cycle, while loosing points through natural restoration (too much poison in body) only happens every hour.
// so one might lose 1pt of life through poisoning at 8:00, and then lose 30 points of life PERMANTENLY in the following hour without dying
// We bypass this by only allowing PERMANTENT lifeloss if really bleeding
if ( pSoldier->bBleeding )
{
// bleeding while "dying" costs a PERMANENT point of life each time!
pSoldier->stats.bLifeMax--;
pSoldier->bBleeding = max(0, pSoldier->bBleeding - 1);
// either way, a point of life (health) is lost because of bleeding
// This will also update the life bar
// the lost point might be poisoned
pSoldier->bPoisonSum = max(0, pSoldier->bPoisonSum - 1);
SoldierBleed( pSoldier, FALSE );
// also adjust poisoned bleeding
pSoldier->bPoisonBleeding = max(0, pSoldier->bPoisonBleeding - 1);
if ( pSoldier->iHealableInjury >= 100) // added check for insta-healable injury - SANDRO
pSoldier->iHealableInjury -= 100;
}
}
}
}
// either way, a point of life (health) is lost because of bleeding
// Flugente: not true anymore! We might be fully bandaged, not bleeding, but still receive poison damage that will lower our life. So check if we're bleeding!
if ( pSoldier->bBleeding )
{
// This will also update the life bar
SoldierBleed( pSoldier, FALSE, TRUE );
}
else
{
// just to update everything, like going unconscious or dying
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 0, 0, 0, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
}
// if he's not dying (which includes him saying the dying quote just
// now), and he hasn't warned us that he's bleeding yet, he does so
// Also, not if they are being bandaged....
if ( ( pSoldier->stats.bLife >= OKLIFE ) && !pSoldier->flags.fDyingComment && !pSoldier->flags.fWarnedAboutBleeding && !gTacticalStatus.fAutoBandageMode && pSoldier->ubServiceCount == 0 )
{
// if he's not dying (which includes him saying the dying quote just
// now), and he hasn't warned us that he's bleeding yet, he does so
// Also, not if they are being bandaged....
if ( ( pSoldier->stats.bLife >= OKLIFE ) && !pSoldier->flags.fDyingComment && !pSoldier->flags.fWarnedAboutBleeding && !gTacticalStatus.fAutoBandageMode && pSoldier->ubServiceCount == 0 )
{
TacticalCharacterDialogue( pSoldier, QUOTE_STARTING_TO_BLEED );
// "starting to bleed" quote
pSoldier->flags.fWarnedAboutBleeding = TRUE;
}
pSoldier->dNextBleed = CalcSoldierNextBleed( pSoldier );
}
pSoldier->dNextBleed = CalcSoldierNextBleed( pSoldier );
}
}
}
@@ -13340,10 +13622,8 @@ INT32 CheckBleeding( SOLDIERTYPE *pSoldier )
}
void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed )
void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed, BOOLEAN fAllowPoisoning )
{
INT8 bOldLife;
// OK, here make some stuff happen for bleeding
// A banaged bleed does not show damage taken , just through existing bandages
@@ -13360,21 +13640,30 @@ void SoldierBleed( SOLDIERTYPE *pSoldier, BOOLEAN fBandagedBleed )
SetInfoChar( pSoldier->ubID );
}
}
// if poisoning is allowed, if we are poisoned and we can be sure that we are really bleeding (safety reasons), there is a chance that the poisoning spreads
// this simply means that the new Bleeding point will also be a poisoned bleeding point
INT16 poisondamage = 0;
if ( fAllowPoisoning && pSoldier->bPoisonSum > 0 && pSoldier->bBleeding )
{
INT8 bleedingpercentagepoison = (INT8) (100 * pSoldier->bPoisonSum / pSoldier->stats.bLifeMax);
bOldLife = pSoldier->stats.bLife;
if ( (INT8) Random(100) < bleedingpercentagepoison )
poisondamage = 1;
}
// If we are already dead, don't show damage!
if ( !fBandagedBleed )
{
// SANDRO - if the soldier is bleeding out, consider this damage as done by the last attacker
if ( pSoldier->ubAttackerID != NOBODY )
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubAttackerID, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, poisondamage, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubAttackerID, NOWHERE, 0, TRUE );
else if ( pSoldier->ubPreviousAttackerID != NOBODY )
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, poisondamage, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubPreviousAttackerID, NOWHERE, 0, TRUE );
else if ( pSoldier->ubNextToPreviousAttackerID != NOBODY )
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, poisondamage, 100, TAKE_DAMAGE_BLOODLOSS, pSoldier->ubNextToPreviousAttackerID, NOWHERE, 0, TRUE );
else
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( ANIM_CROUCH, 1, poisondamage, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
}
}
+32 -5
View File
@@ -309,6 +309,7 @@ enum
SOLDIER_CLASS_ELITE_MILITIA,
SOLDIER_CLASS_CREATURE,
SOLDIER_CLASS_MINER,
SOLDIER_CLASS_ZOMBIE,
};
#define SOLDIER_CLASS_ENEMY( bSoldierClass ) ( ( bSoldierClass >= SOLDIER_CLASS_ADMINISTRATOR ) && ( bSoldierClass <= SOLDIER_CLASS_ARMY ) )
@@ -1143,6 +1144,21 @@ public:
// I don't know if this is a good idea at all...
//INT16 filler;
// Flugente: Is this the correct position?
INT8 bScopeMode;
///////////////////////////////////////////////////////
// Flugente Zombies: Added variables for the poison system
INT8 bPoisonBleeding; // The number of bleeding points that are also poison points
//INT8 bPoisonBandaged; // The number of bandaged lifepoints that are also poison points
INT8 bPoisonLife; // The number of Lifepoints that are also poison points
INT8 bPoisonSum; // The sum of poison points;
INT16 bPoisonResistance; // poison resistance reduces the amount of poison damage received. It is applied before poison absorption
INT16 bPoisonAbsorption; // for x points of poison damage received, you gain x * (bPoisonAbsorption / 100) poison life points
///////////////////////////////////////////////////////
#ifdef JA2UB
//ja25
BOOLEAN fIgnoreGetupFromCollapseCheck;
@@ -1151,10 +1167,7 @@ public:
UINT8 ubPercentDamageInflictedByTeam[NUM_ASSIST_SLOTS]; //The percent of damage inflicted by the player team. Each element corresponds to the Soldier ID. Each element contains the percent damage inflicted by that merc
#endif
// Flugente: Is this the correct position?
INT8 bScopeMode;
char endOfPOD; // marker for end of POD (plain old data)
// Note: Place all non-POD items at the end (after endOfPOD)
@@ -1229,7 +1242,8 @@ public:
void ChangeSoldierStance( UINT8 ubDesiredStance );
void StopSoldier( void );
void ReviveSoldier( void );
UINT8 SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sBreathDeduct, UINT8 ubReason, UINT8 ubAttacker, INT32 sSourceGrid, INT16 sSubsequent, BOOLEAN fShowDamage );
// Flugente: added poison damage, which should be smaller or equal than sLifeDeduct
UINT8 SoldierTakeDamage( INT8 bHeight, INT16 sLifeDeduct, INT16 sPoisonAdd, INT16 sBreathDeduct, UINT8 ubReason, UINT8 ubAttacker, INT32 sSourceGrid, INT16 sSubsequent, BOOLEAN fShowDamage );
// Palette functions for soldiers
@@ -1330,6 +1344,19 @@ public:
// returns damage resistance in percent
INT32 GetDamageResistance( BOOLEAN fAutoResolve = FALSE, BOOLEAN fCalcBreathLoss = FALSE);
INT16 GetSoldierCriticalDamageBonus( void ); // Flugente: determines critical damage bonus depending on class, skill, etc.
// Flugente: Zombies
BOOLEAN IsZombie( void );
// Flugente: poison system
// These functions might one day be modified by traits etc. We'll keep that in these functions and not clutter the rest of the code
INT16 GetPoisonResistance( void );
INT16 GetPoisonAbsorption( void );
// returns the poison percentage of the damage we will be doing with the weapon currently in our hand
INT16 GetPoisonDamagePercentage( void );
//////////////////////////////////////////////////////////////////////////////
}; // SOLDIERTYPE;
#define SIZEOF_SOLDIERTYPE_POD offsetof( SOLDIERTYPE, endOfPOD )
+51 -5
View File
@@ -341,6 +341,7 @@ SOLDIERCREATE_STRUCT::SOLDIERCREATE_STRUCT() {
SOLDIERCREATE_STRUCT::SOLDIERCREATE_STRUCT(const SOLDIERCREATE_STRUCT& src) {
memcpy(this, &src, SIZEOF_SOLDIERCREATE_STRUCT_POD);
this->Inv = src.Inv;
this->fNoGenNewPalette = src.fNoGenNewPalette;
}
// Assignment operator
@@ -349,6 +350,7 @@ SOLDIERCREATE_STRUCT& SOLDIERCREATE_STRUCT::operator=(const SOLDIERCREATE_STRUCT
if (this != &src) {
memcpy(this, &src, SIZEOF_SOLDIERCREATE_STRUCT_POD);
this->Inv = src.Inv;
this->fNoGenNewPalette = src.fNoGenNewPalette;
}
return *this;
}
@@ -1727,6 +1729,10 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
{
swprintf( pSoldier->name, gzLateLocalizedString[ 36 ] );
}
else if ( pSoldier->IsZombie() )
{
swprintf( pSoldier->name, TacticalStr[ ZOMBIE_TEAM_MERC_NAME ] );
}
else
{
swprintf( pSoldier->name, TacticalStr[ CREATURE_TEAM_MERC_NAME ] ); break;
@@ -1735,7 +1741,8 @@ BOOLEAN TacticalCopySoldierFromCreateStruct( SOLDIERTYPE *pSoldier, SOLDIERCREAT
}
//Generate colors for soldier based on the body type.
GeneratePaletteForSoldier( pSoldier, pCreateStruct->ubSoldierClass );
if ( !pCreateStruct->fNoGenNewPalette )
GeneratePaletteForSoldier( pSoldier, pCreateStruct->ubSoldierClass );
// Copy item info over
pSoldier->inv = pCreateStruct->Inv;
@@ -2170,6 +2177,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
switch( ubSoldierClass )
{
case SOLDIER_CLASS_ADMINISTRATOR:
case SOLDIER_CLASS_ZOMBIE:
pp->bExpLevel = (INT8) 2 + bExpLevelModifier;
break;
case SOLDIER_CLASS_ARMY:
@@ -2287,7 +2295,7 @@ void CreateDetailedPlacementGivenBasicPlacementInfo( SOLDIERCREATE_STRUCT *pp, B
//If it is a detailed placement, don't do this yet, as detailed placements may have their
//own equipment.
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("CreateDetailedPlacementGivenBasicPlacementInfo: generate random equipment"));
if( !bp->fDetailedPlacement && ubSoldierClass != SOLDIER_CLASS_NONE && ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_MINER )
if( !bp->fDetailedPlacement && ubSoldierClass != SOLDIER_CLASS_NONE && ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_MINER && ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
GenerateRandomEquipment( pp, ubSoldierClass, bp->bRelativeEquipmentLevel);
DecideToAssignSniperOrders(pp);
@@ -2455,7 +2463,7 @@ void CreateDetailedPlacementGivenStaticDetailedPlacementAndBasicPlacementInfo(
//{
// ReplaceExtendedGuns( pp, bp->ubSoldierClass );
//}
if( bp->ubSoldierClass != SOLDIER_CLASS_NONE && bp->ubSoldierClass != SOLDIER_CLASS_CREATURE && bp->ubSoldierClass != SOLDIER_CLASS_MINER )
if( bp->ubSoldierClass != SOLDIER_CLASS_NONE && bp->ubSoldierClass != SOLDIER_CLASS_CREATURE && bp->ubSoldierClass != SOLDIER_CLASS_MINER && bp->ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
{
GenerateRandomEquipment( pp, bp->ubSoldierClass, bp->bRelativeEquipmentLevel);
DecideToAssignSniperOrders(pp);
@@ -2650,7 +2658,7 @@ SOLDIERTYPE* ReserveTacticalSoldierForAutoresolve( UINT8 ubSoldierClass )
//returns the pointer to that soldier. This is used when copying the exact status of
//all remaining enemy troops (or creatures) to finish the battle in autoresolve. To
//signify that the troop has already been reserved, we simply set their gridno to NOWHERE.
if( ubSoldierClass != SOLDIER_CLASS_CREATURE )
if( ubSoldierClass != SOLDIER_CLASS_CREATURE && ubSoldierClass != SOLDIER_CLASS_ZOMBIE )
{ //use the enemy team
iStart = gTacticalStatus.Team[ ENEMY_TEAM ].bFirstID;
iEnd = gTacticalStatus.Team[ ENEMY_TEAM ].bLastID;
@@ -2660,7 +2668,7 @@ SOLDIERTYPE* ReserveTacticalSoldierForAutoresolve( UINT8 ubSoldierClass )
iStart = gTacticalStatus.Team[ CREATURE_TEAM ].bFirstID;
iEnd = gTacticalStatus.Team[ CREATURE_TEAM ].bLastID;
}
for( i = iStart; i <= iEnd; i++ )
for( i = iStart; i <= iEnd; ++i )
{
if( MercPtrs[ i ]->bActive && MercPtrs[ i ]->bInSector && MercPtrs[ i ]->stats.bLife && !TileIsOutOfBounds(MercPtrs[ i ]->sGridNo))
{
@@ -2792,6 +2800,40 @@ SOLDIERTYPE* TacticalCreateEliteEnemy()
return( pSoldier );
}
//USED BY STRATEGIC AI and AUTORESOLVE
SOLDIERTYPE* TacticalCreateZombie()
{
BASIC_SOLDIERCREATE_STRUCT bp;
SOLDIERCREATE_STRUCT pp;
UINT8 ubID;
SOLDIERTYPE * pSoldier;
if( guiCurrentScreen == AUTORESOLVE_SCREEN && !gfPersistantPBI )
{
pSoldier = ReserveTacticalSoldierForAutoresolve( SOLDIER_CLASS_ZOMBIE );
if( pSoldier ) return pSoldier;
}
memset( &bp, 0, sizeof( BASIC_SOLDIERCREATE_STRUCT ) );
RandomizeRelativeLevel( &( bp.bRelativeAttributeLevel ), SOLDIER_CLASS_ZOMBIE );
RandomizeRelativeLevel( &( bp.bRelativeEquipmentLevel ), SOLDIER_CLASS_ZOMBIE );
bp.bTeam = CREATURE_TEAM;//ZOMBIE_TEAM;
bp.bOrders = SEEKENEMY;
bp.bAttitude = AGGRESSIVE;
bp.bBodyType = -1;
bp.ubSoldierClass = SOLDIER_CLASS_ZOMBIE;
CreateDetailedPlacementGivenBasicPlacementInfo( &pp, &bp );
pSoldier = TacticalCreateSoldier( &pp, &ubID );
if ( pSoldier )
{
// send soldier to centre of map, roughly
pSoldier->aiData.sNoiseGridno = (CENTRAL_GRIDNO + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) + ( Random( CENTRAL_RADIUS * 2 + 1 ) - CENTRAL_RADIUS ) * WORLD_COLS);
pSoldier->aiData.ubNoiseVolume = MAX_MISC_NOISE_DURATION;
}
return( pSoldier );
}
SOLDIERTYPE* ReserveTacticalMilitiaSoldierForAutoresolve( UINT8 ubSoldierClass )
{
INT32 i, iStart, iEnd;
@@ -4195,6 +4237,8 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 10 + ubProgress/4; // 10-35% chance
else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA )
iChance = ubProgress/4; // 0-25% chance
else if (ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
if( foundHtH ) // if found brass knuckless, increase the chance (doesn't happen often)
iChance += 35;
@@ -4238,6 +4282,8 @@ BOOLEAN AssignTraitsToSoldier( SOLDIERTYPE *pSoldier, SOLDIERCREATE_STRUCT *pCre
iChance = 25 + ubProgress*2/5; // 25-65% chance
else if( ubSolClass == SOLDIER_CLASS_ADMINISTRATOR || ubSolClass == SOLDIER_CLASS_GREEN_MILITIA )
iChance = 10 + ubProgress*2/5; // 10-50% chance
else if (ubSolClass == SOLDIER_CLASS_ZOMBIE )
iChance = 100; // 100% chance
// modify the chance by preset ini setting
if( gGameExternalOptions.bAssignedTraitsRarity != 0 )
+4
View File
@@ -305,6 +305,9 @@ public:
INT8 bUseGivenVehicleID;
BOOLEAN fHasKeys;
// Flugente: do not generate new palette for soldier (for soldiers that are created from existing soldiers/corpses, like doppelgangers and zombies)
BOOLEAN fNoGenNewPalette;
//
// New and OO stuff goes after here. Above this point any changes will goof up reading from files.
//
@@ -420,6 +423,7 @@ SOLDIERTYPE* TacticalCreateSoldier( SOLDIERCREATE_STRUCT *pCreateStruct, UINT8 *
SOLDIERTYPE* TacticalCreateAdministrator();
SOLDIERTYPE* TacticalCreateEliteEnemy();
SOLDIERTYPE* TacticalCreateArmyTroop();
SOLDIERTYPE* TacticalCreateZombie(); // Flugente Zombies
SOLDIERTYPE* TacticalCreateMilitia( UINT8 ubMilitiaClass );
SOLDIERTYPE* TacticalCreateCreature( INT8 bCreatureBodyType );
+1
View File
@@ -2106,6 +2106,7 @@ SOLDIERTYPE * SwapLarrysProfiles( SOLDIERTYPE * pSoldier )
pNewProfile->records.usKillsRegulars = gMercProfiles[ ubSrcProfile ].records.usKillsRegulars;
pNewProfile->records.usKillsAdmins = gMercProfiles[ ubSrcProfile ].records.usKillsAdmins;
pNewProfile->records.usKillsCreatures = gMercProfiles[ ubSrcProfile ].records.usKillsCreatures;
pNewProfile->records.usKillsZombies = gMercProfiles[ ubSrcProfile ].records.usKillsZombies;
pNewProfile->records.usKillsTanks = gMercProfiles[ ubSrcProfile ].records.usKillsTanks;
pNewProfile->records.usKillsOthers = gMercProfiles[ ubSrcProfile ].records.usKillsOthers;
pNewProfile->records.usAssistsMercs = gMercProfiles[ ubSrcProfile ].records.usAssistsMercs;
+5
View File
@@ -273,6 +273,11 @@ void HandleTacticalEndTurn( )
// Flugente FTW 1: Cool down all items not in a soldier's inventory
CoolDownWorldItems( FALSE );
// Flugente: raise zombies if in gamescreen and option set
if ( guiCurrentScreen == GAME_SCREEN )
{
RaiseZombies();
}
}
+4
View File
@@ -120,6 +120,9 @@
#include "connect.h"
#include "fresh_header.h"
#include "IMP Skill Trait.h" // added by Flugente
//forward declarations of common classes to eliminate includes
class OBJECTTYPE;
class SOLDIERTYPE;
@@ -4316,6 +4319,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent )
// Get life back
pSoldier->stats.bLife = pSoldier->stats.bLifeMax;
pSoldier->bBleeding = 0;
pSoldier->bPoisonBleeding = 0;
// SANDRO - erase insta-healable injury
pSoldier->iHealableInjury = 0;
+2 -2
View File
@@ -1330,7 +1330,7 @@ BOOLEAN InjurePersonInVehicle( INT32 iId, SOLDIERTYPE *pSoldier, UINT8 ubPointsO
}
// otherwise hurt them
pSoldier->SoldierTakeDamage( 0, ubPointsOfDmg, ubPointsOfDmg, TAKE_DAMAGE_GUNFIRE, NOBODY, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( 0, ubPointsOfDmg, 0, ubPointsOfDmg, TAKE_DAMAGE_GUNFIRE, NOBODY, NOWHERE, 0, TRUE );
pSoldier->HandleSoldierTakeDamageFeedback( );
@@ -1359,7 +1359,7 @@ BOOLEAN KillPersonInVehicle( INT32 iId, SOLDIERTYPE *pSoldier )
}
// otherwise hurt them
pSoldier->SoldierTakeDamage( 0, 100, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
pSoldier->SoldierTakeDamage( 0, 100, 0, 100, TAKE_DAMAGE_BLOODLOSS, NOBODY, NOWHERE, 0, TRUE );
return( TRUE );
}
+64 -13
View File
@@ -334,9 +334,6 @@ bool gbForceWeaponNotReady = false;
bool gbForceWeaponReady = false;
// Flugente: define for maximum temperature
#define OVERHEATING_MAX_TEMPERATURE 60000.0
enum
{
WEAPON_ELEMENT_NONE = 0,
@@ -1328,6 +1325,22 @@ BOOLEAN OKFireWeapon( SOLDIERTYPE *pSoldier )
}
// Flugente FTW 1: Get percentage: temperature/damagethreshold
FLOAT GetGunOverheatDamagePercentage( FLOAT usTemperature, UINT16 usIndx )
{
FLOAT damagethreshold = Weapon[Item[ usIndx ].ubClassIndex].usOverheatingDamageThreshold;
return usTemperature/ damagethreshold ;
}
// Flugente FTW 1: Get percentage: temperature/jamthreshold
FLOAT GetGunOverheatJamPercentage( FLOAT usTemperature, UINT16 usIndx )
{
FLOAT jamthreshold = Weapon[Item[ usIndx ].ubClassIndex].usOverheatingJamThreshold;
return usTemperature/ jamthreshold ;
}
BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
{
// ignore passed in target gridno for now
@@ -5187,6 +5200,7 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi
// AGILITY OR EXPERIENCE
FLOAT iTempPenalty = (FLOAT)__max((pTarget->stats.bExpLevel*10), pTarget->stats.bAgility);
iBaseModifier += (iTempPenalty * gGameCTHConstants.BASE_AGILE_TARGET) / 100;
}
@@ -6235,19 +6249,19 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime,
if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE )
{
// 13% penalty per tile closer than min range
iChance -= 13 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE );
iChance -= (INT32)(13 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ));
}
else
{
// at anything other than point-blank range
if (iRange > POINT_BLANK_RANGE + 10 * (AIM_PENALTY_TARGET_CROUCHED / 3) )
{
iChance -= AIM_PENALTY_TARGET_CROUCHED;
iChance -= (INT32)(AIM_PENALTY_TARGET_CROUCHED);
}
else if (iRange > POINT_BLANK_RANGE)
{
// at close range give same bonus as prone, up to maximum of AIM_PENALTY_TARGET_CROUCHED
iChance -= 3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE); // penalty -3%/tile
iChance -= (INT32)(3 * ((iRange - POINT_BLANK_RANGE) / CELL_X_SIZE)); // penalty -3%/tile
}
}
break;
@@ -6255,7 +6269,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime,
if ( TANK( pSoldier ) && iRange < MIN_TANK_RANGE )
{
// 25% penalty per tile closer than min range
iChance -= 25 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE );
iChance -= (INT32)(25 * ( ( MIN_TANK_RANGE - iRange ) / CELL_X_SIZE ) * iPenalty);
}
else
{
@@ -6286,7 +6300,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime,
// e.g. 30% to aim at head at range 1, only 10% at range 3
// or 20% to aim at torso at range 1, no penalty at range 3
// NB torso aim position is 2, so (5-aimpos) is 3, for legs it's 2, for head 4
iChance -= (5 - ubAdjAimPos - iRange / CELL_X_SIZE) * 10;
iChance -= (INT32)((5 - ubAdjAimPos - iRange / CELL_X_SIZE) * 10 * iPenalty);
}
break;
default:
@@ -8421,7 +8435,7 @@ INT32 CalcBodyImpactReduction( UINT8 ubAmmoType, UINT8 ubHitLocation )
return( iReduction );
}
INT32 ArmourProtection( SOLDIERTYPE * pTarget, UINT16 ubArmourType, INT16 * pbStatus, INT32 iImpact, UINT8 ubAmmoType, BOOLEAN *plateHit )
INT32 ArmourProtection( SOLDIERTYPE * pTarget, UINT16 ubArmourType, INT16 * pbStatus, INT32 iImpact, UINT8 ubAmmoType, BOOLEAN *plateHit)
{
INT32 iProtection, iAppliedProtection, iFailure, iCoverage;
@@ -8498,7 +8512,7 @@ INT32 ArmourProtection( SOLDIERTYPE * pTarget, UINT16 ubArmourType, INT16 * pbSt
else if ( AmmoTypes[ubAmmoType].ignoreArmour )
{
// knives and darts damage armour but are not stopped by kevlar
if (Armour[ ubArmourType ].ubArmourClass == ARMOURCLASS_VEST || Armour[ ubArmourType ].ubArmourClass == ARMOURCLASS_LEGGINGS)
if ( Armour[ ubArmourType ].ubArmourClass == ARMOURCLASS_VEST || Armour[ ubArmourType ].ubArmourClass == ARMOURCLASS_LEGGINGS )
{
iProtection = 0;
}
@@ -8624,6 +8638,13 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget,
INT8 bStatLoss = 0;
UINT8 ubAmmoType;
if ( pTarget->IsZombie() && gGameExternalOptions.fZombieOnlyHeadshotsWork )
{
// if bullet does not hits anything other than the head, it doesn't do any damage
if ( ubHitLocation != AIM_SHOT_HEAD )
return 0;
}
// NOTE: reduction of bullet impact due to range and obstacles is handled
// in MoveBullet.
@@ -8769,7 +8790,7 @@ INT32 BulletImpact( SOLDIERTYPE *pFirer, BULLET *pBullet, SOLDIERTYPE * pTarget,
AdjustImpactByHitLocation( iImpact, ubHitLocation, &iImpact, &iImpactForCrits );
switch( ubHitLocation )
{
case AIM_SHOT_HEAD:
@@ -9346,7 +9367,22 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
if (pTarget->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget ) )
{
iImpact = (INT32)((iImpact * 140 / 100) + 0.5); // 30% incresed damage on suprising attacks
}
}
}
// Flugente: power armour reduces damage taken
INT8 iSlot = VESTPOS;
switch( pSoldier->bAimShotLocation )
{
case AIM_SHOT_HEAD:
iSlot = HELMETPOS;
break;
case AIM_SHOT_LEGS:
iSlot = LEGPOS;
break;
default:
iSlot = VESTPOS;
break;
}
}
// DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL
@@ -9369,6 +9405,21 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO
iImpact = (INT32)(iImpact * 125 / 100); // 40% incresed damage to lying characters
}
}
// Flugente: power armour reduces damage taken
INT8 iSlot = VESTPOS;
switch( pSoldier->bAimShotLocation )
{
case AIM_SHOT_HEAD:
iSlot = HELMETPOS;
break;
case AIM_SHOT_LEGS:
iSlot = LEGPOS;
break;
default:
iSlot = VESTPOS;
break;
}
}
// bonus damage for aggressive characters
@@ -9501,7 +9552,7 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi
// We need to be agile and dexterous
iAttRating = ( 2 * EffectiveDexterity( pAttacker ) + // coordination, accuracy *
2 * EffectiveAgility( pAttacker ) + // speed & reflexes
pAttacker->stats.bStrength + // physical strength
pAttacker->stats.bStrength + // physical strength
(10 * EffectiveExpLevel( pAttacker ) ) ); // experience, knowledge
}
else
+3
View File
@@ -211,6 +211,7 @@ typedef struct
INT16 lockBustingPower;
BOOLEAN tracerEffect;
FLOAT temperatureModificator; // Flugente FTW 1.1: modificator for weapon temperature
INT16 poisonPercentage; // Flugente FTW 1.1: modificator for weapon temperature
//zilpin: pellet spread patterns externalized in XML
INT32 spreadPattern;
@@ -428,6 +429,8 @@ extern void GetTargetWorldPositions( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo,
extern BOOLEAN OKFireWeapon( SOLDIERTYPE *pSoldier );
extern BOOLEAN CheckForGunJam( SOLDIERTYPE * pSoldier );
extern FLOAT GetGunOverheatDamagePercentage( FLOAT usTemperature, UINT16 usIndx ); // Flugente FTW 1: Get percentage: temperature/damagethreshold
extern FLOAT GetGunOverheatJamPercentage( FLOAT usTemperature, UINT16 usIndx ); // Flugente FTW 1: Get percentage: temperature/jamthreshold
extern INT32 CalcMaxTossRange( SOLDIERTYPE * pSoldier, UINT16 usItem, BOOLEAN fArmed );
extern UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos );
+4 -4
View File
@@ -844,7 +844,7 @@ void CoolDownWorldItems( BOOLEAN fSetZero )
{
for(INT16 i = 0; i < pObj->ubNumberOfObjects; ++i) // ... there might be multiple items here (item stack), so for each one ...
{
FLOAT newguntemperature = 0.0;
FLOAT newguntemperature = 0.0f;
if ( !fSetZero && gGameExternalOptions.fSetZeroUponNewSector )
{
@@ -855,7 +855,7 @@ void CoolDownWorldItems( BOOLEAN fSetZero )
if ( Item[gWorldItems[ uiCount ].object.usItem].barrel == TRUE ) // ... a barrel lying around cools down a bit faster ...
cooldownfactor *= gGameExternalOptions.iCooldownModificatorLonelyBarrel;
newguntemperature = max(0.0, guntemperature - cooldownfactor); // ... calculate new temperature ...
newguntemperature = max(0.0f, guntemperature - cooldownfactor); // ... calculate new temperature ...
}
(*pObj)[i]->data.bTemperature = newguntemperature; // ... set new temperature
@@ -869,7 +869,7 @@ void CoolDownWorldItems( BOOLEAN fSetZero )
{
if ( iter->exists() && Item[ iter->usItem ].usItemClass & (IC_GUN|IC_LAUNCHER) )
{
FLOAT newtemperature = 0.0;
FLOAT newtemperature = 0.0f;
if ( !fSetZero && gGameExternalOptions.fSetZeroUponNewSector )
{
@@ -877,7 +877,7 @@ void CoolDownWorldItems( BOOLEAN fSetZero )
FLOAT cooldownfactor = GetItemCooldownFactor( &(*iter) ); // ... get cooldown factor ...
newtemperature = max(0.0, temperature - cooldownfactor); // ... calculate new temperature ...
newtemperature = max(0.0f, temperature - cooldownfactor); // ... calculate new temperature ...
}
(*iter)[i]->data.bTemperature = newtemperature; // ... set new temperature
+12 -1
View File
@@ -79,7 +79,8 @@ ammotypeStartElementHandle(void *userData, const XML_Char *name, const XML_Char
strcmp(name, "acidic") == 0 ||
strcmp(name, "tracerEffect") == 0 ||
strcmp(name, "monsterSpit") == 0 ||
strcmp(name, "temperatureModificator") == 0 ))
strcmp(name, "temperatureModificator") == 0 ||
strcmp(name, "PoisonPercentage") == 0 ))
{
pData->curElement = ELEMENT_PROPERTY;
@@ -282,6 +283,15 @@ ammotypeEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = ELEMENT;
pData->curAmmoType.temperatureModificator = (FLOAT) atof(pData->szCharData);
}
else if(strcmp(name, "PoisonPercentage") == 0)
{
pData->curElement = ELEMENT;
pData->curAmmoType.poisonPercentage = (INT16) atol(pData->szCharData);
// check: poisonPercentage must be between 0 and 100, fit bad values
pData->curAmmoType.poisonPercentage = max(0, pData->curAmmoType.poisonPercentage);
pData->curAmmoType.poisonPercentage = min(100, pData->curAmmoType.poisonPercentage);
}
pData->maxReadDepth--;
}
@@ -404,6 +414,7 @@ BOOLEAN WriteAmmoTypeStats()
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</AMMOTYPE>\r\n");
+1
View File
@@ -4764,6 +4764,7 @@ void DebugSoldierPage4( )
case SOLDIER_CLASS_REG_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Reg Militia)" ); break;
case SOLDIER_CLASS_ELITE_MILITIA: gprintf( 320, LINE_HEIGHT * ubLine, L"(Elite Militia)" ); break;
case SOLDIER_CLASS_MINER: gprintf( 320, LINE_HEIGHT * ubLine, L"(Miner)" ); break;
case SOLDIER_CLASS_ZOMBIE: gprintf( 320, LINE_HEIGHT * ubLine, L"(Zombie)" ); break;
default: break; //don't care (don't write anything)
}
ubLine++;
+1
View File
@@ -262,6 +262,7 @@ public:
UINT16 usKillsAdmins;
UINT16 usKillsHostiles;
UINT16 usKillsCreatures;
UINT16 usKillsZombies;
UINT16 usKillsTanks;
UINT16 usKillsOthers;