The new <BarrelConfiguration>-tag specifies how many bullets a gun shoots at once. Several values can be used. If no value is set, 1 will be used.

Toggling fire modes cycles between barrel configurations if several have been set.

Requires GameDir >= r2461

git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@8652 3b4a5df2-a311-0410-b5c6-a8a6f20db521
This commit is contained in:
Flugente
2019-01-27 19:48:18 +00:00
parent 61553feb57
commit a5e5ff6bd8
15 changed files with 338 additions and 50 deletions
+18 -5
View File
@@ -2348,7 +2348,10 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile)
{
numBytesRead = ReadFieldByField( hFile, &this->sDiseasePoints, sizeof(sDiseasePoints), sizeof(INT32), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->sDiseaseFlag, sizeof(sDiseaseFlag), sizeof(UINT8), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->ubFiller, sizeof(ubFiller), sizeof(UINT8), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->ubFiller, sizeof( ubFiller ), sizeof( UINT8 ), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->ubFiller1, sizeof( ubFiller1 ), sizeof( UINT8 ), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->usBarrelMode, sizeof( usBarrelMode ), sizeof( UINT8 ), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->usBarrelCounter, sizeof( usBarrelCounter ), sizeof( UINT8 ), numBytesRead );
numBytesRead = ReadFieldByField( hFile, &this->sFocusGridNo, sizeof(sFocusGridNo), sizeof(INT32), numBytesRead );
}
else
@@ -2363,11 +2366,16 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile)
this->sDiseasePoints[i] = 0;
this->sDiseaseFlag[i] = 0;
}
buffer += sizeof(sFocusGridNo);
while ( (buffer % 4) > 0 ) ++buffer;
numBytesRead = ReadFieldByField( hFile, &this->ubFiller, sizeof(ubFiller), sizeof(UINT8), numBytesRead );
buffer += sizeof( ubFiller1 );
buffer += sizeof( usBarrelMode );
buffer += sizeof( usBarrelCounter );
while ( ( buffer % 4 ) > 0 ) ++buffer;
buffer += sizeof( sFocusGridNo );
while ( ( buffer % 4 ) > 0 ) ++buffer;
}
}
else
@@ -2408,6 +2416,11 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile)
while((buffer%4) > 0)
buffer++;
buffer += sizeof( ubFiller1 );
buffer += sizeof( usBarrelMode );
buffer += sizeof( usBarrelCounter );
while ( ( buffer % 4 ) > 0 ) ++buffer;
for ( int i = 0; i < sizeof(sFocusGridNo); ++i )
buffer++;
while ( (buffer % 4) > 0 )
+75 -1
View File
@@ -4084,6 +4084,21 @@ void InternalInitEDBTooltipRegion( OBJECTTYPE * gpItemDescObject, UINT32 guiCurr
++cnt;
}
///////////////////// MULTIPLE BARRELS
if ( ( Item[gpItemDescObject->usItem].usItemClass & IC_BOBBY_GUN ) )
{
if ( !fDrawGenIndexes )
fDrawGenIndexes = ++cnt; // new index line here?
if ( cnt >= sFirstLine && cnt < sLastLine )
{
swprintf( pStr, L"%s%s", szUDBAdvStatsTooltipText[67], szUDBAdvStatsExplanationsTooltipText[67] );
SetRegionFastHelpText( &( gUDBFasthelpRegions[iFirstDataRegion + ( cnt - sFirstLine )] ), pStr );
MSYS_EnableRegion( &gUDBFasthelpRegions[iFirstDataRegion + ( cnt - sFirstLine )] );
}
++cnt;
}
if ( UsingFoodSystem() && Item[gpItemDescObject->usItem].foodtype > 0 )
{
if (!fDrawGenIndexes)
@@ -5766,6 +5781,16 @@ void DrawAdvancedStats( OBJECTTYPE * gpItemDescObject )
++cnt;
}
///////////////////// MULTIPLE BARRELS
if ( ( ( Item[gpItemDescObject->usItem].usItemClass & IC_BOBBY_GUN ) || ( fComparisonMode && ( Item[gpComparedItemDescObject->usItem].usItemClass & IC_BOBBY_GUN ) ) ) )
{
if ( cnt >= sFirstLine && cnt < sLastLine )
{
BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 66, gItemDescAdvRegions[cnt - sFirstLine][0].sLeft + sOffsetX, gItemDescAdvRegions[cnt - sFirstLine][0].sTop + sOffsetY, VO_BLT_SRCTRANSPARENCY, NULL );
}
++cnt;
}
if ( UsingFoodSystem() )
{
if ( ( Item[gpItemDescObject->usItem].foodtype > 0 ) ||
@@ -10075,7 +10100,7 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
INT16 sLastLine = gubDescBoxLine + NUM_UDB_ADV_LINES;
INT16 cnt = 0;
static CHAR16 pStr[ 100 ];
static CHAR16 pStr[ 100 ], pStr2[100];
INT16 usY;
INT16 usX;
INT16 sLeft, sTop, sWidth, sHeight;
@@ -14095,6 +14120,55 @@ void DrawAdvancedValues( OBJECTTYPE *gpItemDescObject )
++cnt;
}
///////////////////// MULTIPLE BARRELS
if ( ( ( Item[gpItemDescObject->usItem].usItemClass & ( IC_GUN | IC_LAUNCHER ) ) || ( fComparisonMode && Item[gpComparedItemDescObject->usItem].usItemClass & ( IC_GUN | IC_LAUNCHER ) ) ) )
{
if ( !fDrawGenIndexes )
fDrawGenIndexes = ++cnt; //insert Indexes here?
if ( cnt >= sFirstLine && cnt < sLastLine )
{
// Set Y coordinates
sTop = gItemDescAdvRegions[cnt - sFirstLine][1].sTop;
sHeight = gItemDescAdvRegions[cnt - sFirstLine][1].sBottom - sTop;
// list all modes
swprintf( pStr, L"" );
swprintf( pStr2, L"" );
std::vector<UINT8> tmp = Weapon[Item[gpItemDescObject->usItem].ubClassIndex].barrelconfigurations;
for ( std::vector<UINT8>::iterator it = tmp.begin(); it != tmp.end(); ++it )
{
UINT8 bla = ( *it );
swprintf( pStr2, L"%s x%d", pStr, bla );
swprintf( pStr, L"%s", pStr2 );
}
if ( ( fComparisonMode && Item[gpComparedItemDescObject->usItem].usItemClass & ( IC_GUN | IC_LAUNCHER ) ) )
{
wcscat( pStr, L" / " );
std::vector<UINT8> tmp2 = Weapon[Item[gpComparedItemDescObject->usItem].ubClassIndex].barrelconfigurations;
for ( std::vector<UINT8>::iterator it = tmp2.begin(); it != tmp2.end(); ++it )
{
swprintf( pStr2, L"%s x%d", pStr, ( *it ) );
swprintf( pStr, L"%s", pStr2 );
}
}
SetFontForeground( 5 );
sLeft = gItemDescAdvRegions[cnt - sFirstLine][1].sLeft;
sWidth = gItemDescAdvRegions[cnt - sFirstLine][1].sRight - sLeft;
FindFontCenterCoordinates( sLeft, sTop, sWidth, sHeight, pStr, BLOCKFONT2, &usX, &usY );
mprintf( usX, usY, pStr );
}
++cnt;
}
////////////////////// FOOD
if ( UsingFoodSystem() )
{
+18 -5
View File
@@ -4191,10 +4191,16 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec
}
}
if ( pSoldier && pObject == &(pSoldier->inv[HANDPOS] ) && pSoldier->bWeaponMode != WM_NORMAL && Item[pSoldier->inv[HANDPOS].usItem].usItemClass & IC_GUN )
if ( pSoldier && pObject == &(pSoldier->inv[HANDPOS] ) && Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_GUN|IC_LAUNCHER) )
{
sNewY = sY + 13; // rather arbitrary
if ( pSoldier->bWeaponMode == WM_BURST )
if ( pSoldier->bWeaponMode == WM_NORMAL )
{
swprintf( pStr, L"" );
SetFontForeground( FONT_RED );
}
else if ( pSoldier->bWeaponMode == WM_BURST )
{
swprintf( pStr, New113Message[MSG113_BRST] );
SetFontForeground( FONT_RED );
@@ -4239,9 +4245,15 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec
swprintf( pStr, New113Message[MSG113_BAYONET] );
SetFontForeground( FONT_ORANGE );
}
// Flugente: display barrel mode if necessary
if ( pSoldier->usBarrelMode > 1 )
swprintf( pStr2, L"%s x%d", pStr, pSoldier->usBarrelMode );
else
swprintf( pStr2, L"%s", pStr );
// Get length of string
uiStringLength=StringPixLength(pStr, ITEM_FONT );
uiStringLength=StringPixLength( pStr2, ITEM_FONT );
sNewX = sX + sWidth - uiStringLength - 4;
@@ -4249,10 +4261,11 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec
{
RestoreExternBackgroundRect( sNewX, sNewY, 15, 15 );
}
mprintf( sNewX, sNewY, pStr );
gprintfinvalidate( sNewX, sNewY, pStr );
mprintf( sNewX, sNewY, pStr2 );
gprintfinvalidate( sNewX, sNewY, pStr2 );
}
// SANDRO - display BRST/AUTO on the second weapon too, if we are going to fire dual bursts
if ( pSoldier && pObject == &(pSoldier->inv[SECONDHANDPOS] ) &&
(pSoldier->bWeaponMode == WM_BURST || pSoldier->bWeaponMode == WM_AUTOFIRE) &&
+4
View File
@@ -13842,6 +13842,10 @@ void SOLDIERTYPE::ReLoadSoldierAnimationDueToHandItemChange( UINT16 usOldItem, U
else
this->bScopeMode = USE_BEST_SCOPE;
// Flugente: use lowest valid barrel configuration
this->usBarrelMode = 1;
this->usBarrelMode = GetNextBarrelMode( usNewItem, this->usBarrelMode );
if ( gAnimControl[this->usAnimState].uiFlags & ANIM_FIREREADY )
{
// Stop aiming!
+6 -1
View File
@@ -1549,7 +1549,12 @@ public:
// Flugente: Decrease this filler by 1 for each new UINT8 / BOOLEAN variable, so we can maintain savegame compatibility!!
// Note that we also have to account for padding, so you might need to substract more than just the size of the new variables
UINT8 ubFiller[16];
UINT8 ubFiller[12];
UINT8 ubFiller1[2];
// Flugente: keep track of data for multi-barrel guns
UINT8 usBarrelMode; // states how many barrels we are currently using as modifier for our fire mode
UINT8 usBarrelCounter; // states which barrel we are currently firing from (used during the firing process)
// Flugente: focus skill gridno
INT32 sFocusGridNo;
+193 -38
View File
@@ -103,10 +103,15 @@ extern BOOLEAN gfNextFireJam;
BOOLEAN WillExplosiveWeaponFail( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj );
// Flugente: this function calls UseGun and handles the firing of severeal shots at once
BOOLEAN UseGunWrapper( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo );
BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
BOOLEAN UseBlade( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
BOOLEAN UseThrown( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
// Flugente: this function calls UseLauncher and handles the firing of severeal shots at once
BOOLEAN UseLauncherWrapper( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo );
BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo );
// new subroutines for NCTH calculation
@@ -374,6 +379,9 @@ struct
}
typedef weaponParseData;
// for compliation reasons, this may not be a part of weaponParseData
std::vector<UINT8> barrelconfigurationvector;
static void XMLCALL
weaponStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
{
@@ -443,7 +451,8 @@ weaponStartElementHandle(void *userData, const XML_Char *name, const XML_Char **
strcmp(name, "usOverheatingDamageThreshold") == 0 || // Flugente
strcmp(name, "usOverheatingSingleShotTemperature") == 0 || // Flugente
strcmp(name, "HeavyGun") == 0 || // SANDRO - cannot be shouldered while standing
strcmp(name, "fBurstOnlyByFanTheHammer" ) == 0))
strcmp(name, "fBurstOnlyByFanTheHammer" ) == 0 ||
strcmp(name, "BarrelConfiguration" ) == 0))
{
pData->curElement = WEAPON_ELEMENT_WEAPON_PROPERY;
@@ -488,6 +497,21 @@ weaponEndElementHandle(void *userData, const XML_Char *name)
if(pData->curWeapon.uiIndex < pData->maxWeapons)
{
pData->curWeaponList[pData->curWeapon.uiIndex] = pData->curWeapon; //write the weapon into the table
if ( !barrelconfigurationvector.empty() )
{
for ( std::vector<UINT8>::iterator it = barrelconfigurationvector.begin(), itend = barrelconfigurationvector.end(); it != itend; ++it )
{
pData->curWeaponList[pData->curWeapon.uiIndex].barrelconfigurations.push_back( (*it) );
}
barrelconfigurationvector.clear();
}
// if no configuration is set, assume one barrel is possible
else
{
pData->curWeaponList[pData->curWeapon.uiIndex].barrelconfigurations.push_back( 1 );
}
}
}
else if(strcmp(name, "uiIndex") == 0)
@@ -733,6 +757,14 @@ weaponEndElementHandle(void *userData, const XML_Char *name)
pData->curElement = WEAPON_ELEMENT_WEAPON;
pData->curWeapon.fBurstOnlyByFanTheHammer = (BOOLEAN)atof( pData->szCharData );
}
else if ( strcmp( name, "BarrelConfiguration" ) == 0 )
{
pData->curElement = WEAPON_ELEMENT_WEAPON;
UINT8 barrelmode = (UINT8)atol( pData->szCharData );
if ( barrelmode )
barrelconfigurationvector.push_back( barrelmode );
}
pData->maxReadDepth--;
}
@@ -906,13 +938,17 @@ BOOLEAN WriteWeaponStats()
FilePrintf(hFile,"\t\t<ubAimLevels>%d</ubAimLevels>\r\n", Weapon[cnt].ubAimLevels );
FilePrintf(hFile,"\t\t<EasyUnjam>%d</EasyUnjam>\r\n", Weapon[cnt].EasyUnjam);
FilePrintf(hFile,"\t\t<Handling>%d</Handling>\r\n", Weapon[cnt].ubHandling);
FilePrintf(hFile,"\t\t<usOverheatingJamThreshold>%4.2f</usOverheatingJamThreshold>\r\n", Weapon[cnt].usOverheatingJamThreshold); // Flugente FTW 1
FilePrintf(hFile,"\t\t<usOverheatingJamThreshold>%4.2f</usOverheatingJamThreshold>\r\n", Weapon[cnt].usOverheatingJamThreshold);
FilePrintf(hFile,"\t\t<usOverheatingDamageThreshold>%4.2f</usOverheatingDamageThreshold>\r\n", Weapon[cnt].usOverheatingDamageThreshold);
FilePrintf(hFile,"\t\t<usOverheatingSingleShotTemperature>%4.2f</usOverheatingSingleShotTemperature>\r\n", Weapon[cnt].usOverheatingSingleShotTemperature);
FilePrintf(hFile,"\t\t<HeavyGun>%d</HeavyGun>\r\n", Weapon[cnt].HeavyGun);
FilePrintf(hFile,"\t\t<fBurstOnlyByFanTheHammer>%d</fBurstOnlyByFanTheHammer>\r\n", Weapon[cnt].fBurstOnlyByFanTheHammer );
for ( std::vector<UINT8>::iterator it = Weapon[cnt].barrelconfigurations.begin(), itend = Weapon[cnt].barrelconfigurations.end(); it != itend; ++it )
{
FilePrintf( hFile, "\t\t<BarrelConfiguration>%d</BarrelConfiguration>\r\n", (*it) );
}
FilePrintf(hFile,"\t</WEAPON>\r\n");
}
FilePrintf(hFile,"</WEAPONLIST>\r\n");
@@ -1496,7 +1532,7 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
case IC_GUN:
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL )
UseLauncher ( pSoldier, sTargetGridNo );
UseLauncherWrapper ( pSoldier, sTargetGridNo );
else
{
// ATE: PAtch up - bookkeeping for spreading done out of whak
@@ -1530,15 +1566,14 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
}
}
if ( pSoldier->flags.fDoSpread )
{
UseGun( pSoldier, pSoldier->sSpreadLocations[ pSoldier->flags.fDoSpread - 1 ] );
UseGunWrapper( pSoldier, pSoldier->sSpreadLocations[pSoldier->flags.fDoSpread - 1] );
pSoldier->flags.fDoSpread++;
}
else
{
UseGun( pSoldier, sTargetGridNo );
UseGunWrapper( pSoldier, sTargetGridNo );
}
}
break;
@@ -1552,7 +1587,7 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
case IC_LAUNCHER:
if ( Item[pSoldier->usAttackingWeapon].rocketlauncher ){
UseGun( pSoldier, sTargetGridNo );
UseGunWrapper( pSoldier, sTargetGridNo );
} else {
// ATE: PAtch up - bookkeeping for spreading done out of whak
if ( pSoldier->flags.fDoSpread)
@@ -1584,12 +1619,12 @@ BOOLEAN FireWeapon( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
if ( pSoldier->flags.fDoSpread )
{
UseLauncher( pSoldier, pSoldier->sSpreadLocations[ pSoldier->flags.fDoSpread - 1 ] );
UseLauncherWrapper( pSoldier, pSoldier->sSpreadLocations[ pSoldier->flags.fDoSpread - 1 ] );
pSoldier->flags.fDoSpread++;
}
else
{
UseLauncher( pSoldier, sTargetGridNo );
UseLauncherWrapper( pSoldier, sTargetGridNo );
}
}
@@ -2304,7 +2339,8 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_GUNFIRE );
if ( pSoldier->bDoBurst )
// Flugente: if we fire multiple barrels, only do this on first one
if ( pSoldier->bDoBurst && !pSoldier->usBarrelCounter )
{
// done, if bursting, increment
pSoldier->bDoBurst++;
@@ -2420,6 +2456,77 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
return( TRUE );
}
// Flugente: functions for using several barrels at once
UINT8 GetNextBarrelMode( UINT16 usItem, UINT8 aBarrelMode )
{
if ( ( Item[usItem].usItemClass & IC_BOBBY_GUN ) )
{
std::vector<UINT8> tmp = Weapon[Item[usItem].ubClassIndex].barrelconfigurations;
for ( std::vector<UINT8>::iterator it = tmp.begin(); it != tmp.end(); ++it )
{
if ( ( *it ) > aBarrelMode )
return ( *it );
}
// if nothing was found, take the first result
if ( !tmp.empty() )
return tmp[0];
}
return 1;
}
// Flugente: return a number of barrels this gun can fire, equal or below aBarrelMode
UINT8 GetFittingBarrelMode( UINT16 usItem, UINT8 aBarrelMode )
{
UINT8 bestfound = 1;
if ( ( Item[usItem].usItemClass & IC_BOBBY_GUN ) )
{
std::vector<UINT8> tmp = Weapon[Item[usItem].ubClassIndex].barrelconfigurations;
for ( std::vector<UINT8>::reverse_iterator it = tmp.rbegin(); it != tmp.rend(); ++it )
{
if ( ( *it ) == aBarrelMode )
return ( *it );
if ( ( *it ) < aBarrelMode )
{
if ( ( *it ) > bestfound )
bestfound = ( *it );
}
}
}
return bestfound;
}
// Flugente: this function calls UseGun and handles the firing of severeal shots at once
BOOLEAN UseGunWrapper( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
{
// determine how many barrels to fire - if we want more than 1, check whether the gun supports this, if not, adjust
UINT8 barrelstofire = 1;
pSoldier->usBarrelMode = max( 1, pSoldier->usBarrelMode );
if ( pSoldier->usBarrelMode > barrelstofire )
{
// determine how many barrels the gun can fire in the first place (we need this check in case the weapon changed in our hands or we firing a different weapon from the second hand)
OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] );
barrelstofire = GetFittingBarrelMode( pObjUsed->usItem, pSoldier->usBarrelMode );
// limit shots by ammo
barrelstofire = min( barrelstofire, ( *pObjUsed )[0]->data.gun.ubGunShotsLeft );
}
for ( pSoldier->usBarrelCounter = 0; pSoldier->usBarrelCounter < barrelstofire; ++pSoldier->usBarrelCounter )
{
UseGun( pSoldier, sTargetGridNo );
}
return TRUE;
}
BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
{
if(UsingNewCTHSystem() == true)
@@ -2504,7 +2611,9 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
*/
}
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
// Flugente: if we fire multiple barrels, only deduct points APs on the first one
if ( !pSoldier->usBarrelCounter )
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
}
@@ -2516,12 +2625,16 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
// only deduct APs when the main gun fires
if ( pSoldier->ubAttackingHand == HANDPOS )
{
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
// Flugente: if we fire multiple barrels, only deduct points APs on the first one
if ( !pSoldier->usBarrelCounter )
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
}
else
{
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
// Flugente: if we fire multiple barrels, only deduct points APs on the first one
if ( !pSoldier->usBarrelCounter )
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
//PLAY SOUND
@@ -3003,7 +3116,8 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo )
MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_GUNFIRE );
if ( pSoldier->bDoBurst )
// Flugente: if we fire multiple barrels, only do this on first one
if ( pSoldier->bDoBurst && !pSoldier->usBarrelCounter )
{
// done, if bursting, increment
pSoldier->bDoBurst++;
@@ -4183,6 +4297,30 @@ BOOLEAN UseThrown( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
return( TRUE );
}
// Flugente: this function calls UseLauncher and handles the firing of severeal shots at once
BOOLEAN UseLauncherWrapper( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
{
// determine how many barrels to fire - if we want more than 1, check whether the gun supports this, if not, adjust
UINT8 barrelstofire = 1;
pSoldier->usBarrelMode = max( 1, pSoldier->usBarrelMode );
if ( pSoldier->usBarrelMode > barrelstofire )
{
// determine how many barrels the gun can fire in the first place (we need this check in case the weapon changed in our hands or we firing a different weapon from the second hand)
OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] );
barrelstofire = GetFittingBarrelMode( pObjUsed->usItem, pSoldier->usBarrelMode );
// limit shots by ammo
//barrelstofire = min( barrelstofire, ( *pObjUsed )[0]->data.gun.ubGunShotsLeft );
}
for ( pSoldier->usBarrelCounter = 0; pSoldier->usBarrelCounter < barrelstofire; ++pSoldier->usBarrelCounter )
{
UseLauncher( pSoldier, sTargetGridNo );
}
return TRUE;
}
BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
{
@@ -4338,18 +4476,21 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
iBPCost = 0;
}
if ( pSoldier->bDoBurst )
if ( !pSoldier->usBarrelCounter )
{
// ONly deduct points once
if ( pSoldier->bDoBurst == 1 )
if ( pSoldier->bDoBurst )
{
// ONly deduct points once
if ( pSoldier->bDoBurst == 1 )
{
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
}
else
{
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
}
else
{
DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT );
}
/////////////////////////////////////////////////////////////////////////////////////
// SANDRO - new mercs' records
@@ -4381,7 +4522,7 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo )
MemFree( pSoldier->pThrowParams );
pSoldier->pThrowParams = NULL;
if ( pSoldier->bDoBurst )
if ( pSoldier->bDoBurst && !pSoldier->usBarrelCounter )
{
// done, if bursting, increment
pSoldier->bDoBurst++;
@@ -9470,7 +9611,6 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi
return (iChance);
}
void ChangeWeaponMode( SOLDIERTYPE * pSoldier )
{
// ATE: Don't do this if in a fire amimation.....
@@ -9479,30 +9619,45 @@ void ChangeWeaponMode( SOLDIERTYPE * pSoldier )
return;
}
do
// Flugente: if there is a higher barrel configuration, use that
// otherwise, go back to one barrel and try next mode
pSoldier->usBarrelMode = max( 1, pSoldier->usBarrelMode );
UINT8 nextbarrelmode = GetNextBarrelMode( pSoldier->inv[HANDPOS].usItem, pSoldier->usBarrelMode );
if ( nextbarrelmode > pSoldier->usBarrelMode )
{
pSoldier->bWeaponMode++;
if(pSoldier->bWeaponMode == NUM_WEAPON_MODES)
pSoldier->usBarrelMode = nextbarrelmode;
}
else
{
// start again with the first barrel configuration
pSoldier->usBarrelMode = nextbarrelmode;
do
{
if ( Weapon[pSoldier->inv[HANDPOS].usItem].NoSemiAuto )
pSoldier->bWeaponMode = WM_AUTOFIRE;
else
pSoldier->bWeaponMode = WM_NORMAL;
pSoldier->bWeaponMode++;
if ( HasAttachmentOfClass( &(pSoldier->inv[HANDPOS]), AC_RIFLEGRENADE) )
if ( pSoldier->bWeaponMode == NUM_WEAPON_MODES )
{
OBJECTTYPE* pRifleGrenadeDeviceObj = FindAttachment_GrenadeLauncher( &(pSoldier->inv[HANDPOS]) );
if ( Weapon[pSoldier->inv[HANDPOS].usItem].NoSemiAuto )
pSoldier->bWeaponMode = WM_AUTOFIRE;
else
pSoldier->bWeaponMode = WM_NORMAL;
if ( pRifleGrenadeDeviceObj && FindLaunchableAttachment( &(pSoldier->inv[HANDPOS]), pRifleGrenadeDeviceObj->usItem) )
if ( HasAttachmentOfClass( &( pSoldier->inv[HANDPOS] ), AC_RIFLEGRENADE ) )
{
pSoldier->bWeaponMode = WM_ATTACHED_GL;
OBJECTTYPE* pRifleGrenadeDeviceObj = FindAttachment_GrenadeLauncher( &( pSoldier->inv[HANDPOS] ) );
if ( pRifleGrenadeDeviceObj && FindLaunchableAttachment( &( pSoldier->inv[HANDPOS] ), pRifleGrenadeDeviceObj->usItem ) )
{
pSoldier->bWeaponMode = WM_ATTACHED_GL;
}
}
}
}
// Changed by ADB, rev 1513
//while(IsGunWeaponModeCapable( pSoldier, HANDPOS, pSoldier->bWeaponMode ) == FALSE && pSoldier->bWeaponMode != WM_NORMAL);
while ( IsGunWeaponModeCapable( &pSoldier->inv[HANDPOS], static_cast<WeaponMode>( pSoldier->bWeaponMode ), pSoldier ) == FALSE && pSoldier->bWeaponMode != WM_NORMAL );
}
// Changed by ADB, rev 1513
//while(IsGunWeaponModeCapable( pSoldier, HANDPOS, pSoldier->bWeaponMode ) == FALSE && pSoldier->bWeaponMode != WM_NORMAL);
while(IsGunWeaponModeCapable( &pSoldier->inv[HANDPOS], static_cast<WeaponMode>(pSoldier->bWeaponMode), pSoldier ) == FALSE && pSoldier->bWeaponMode != WM_NORMAL);
if (pSoldier->bWeaponMode == WM_AUTOFIRE || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
{
+8
View File
@@ -393,6 +393,10 @@ typedef struct
// this is intended for guns that normally don't possess burst mode, like revolvers
BOOLEAN fBurstOnlyByFanTheHammer;
// Flugente: multi-barrel weapons can fire a variety of barrels at once in all firemodes.
// This vector stores the possible configurations
std::vector<UINT8> barrelconfigurations;
} WEAPONTYPE;
typedef struct
{
@@ -537,4 +541,8 @@ FLOAT GetOverheatDamageThreshold( OBJECTTYPE *pObj );
BOOLEAN ArtilleryStrike( UINT16 usItem, UINT8 ubOwnerID, UINT32 usStartingGridNo, UINT32 usTargetMapPos );
// Flugente: functions for using several barrels at once
UINT8 GetNextBarrelMode( UINT16 usItem, UINT8 aBarrelMode );
UINT8 GetFittingBarrelMode( UINT16 usItem, UINT8 aBarrelMode ); // return a number of barrels this gun can fire, equal or below aBarrelMode
#endif
+2
View File
@@ -8567,6 +8567,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|最|佳|激|光|距|离",//L"|B|e|s|t |L|a|s|e|r |R|a|n|g|e",
L"|后|坐|修|正|比|例",//L"|P|e|r|c|e|n|t |R|e|c|o|i|l |M|o|d|i|f|i|e|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8639,6 +8640,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \n当该附件装配到可以点射及自动射击的远程武\n器上时,会按照所述比例修正武器的后座力。\n后座力越小,枪口在瞄准目标扫射时越稳定。\n该值越低越好。",//L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Recoil by the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8583,6 +8583,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|B|e|s|t |L|a|s|e|r |R|a|n|g|e",// TODO.Translate
L"|P|e|r|c|e|n|t |R|e|c|o|i|l |M|o|d|i|f|i|e|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8655,6 +8656,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Recoil by the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8567,6 +8567,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|B|e|s|t |L|a|s|e|r |R|a|n|g|e",
L"|P|e|r|c|e|n|t |R|e|c|o|i|l |M|o|d|i|f|i|e|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r",
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8639,6 +8640,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Recoil by the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.",
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8570,6 +8570,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|P|o|r|t|é|e |O|p|t|i|m|a|l|e |d|u |L|a|s|e|r",
L"|F|a|c|t|e|u|r |d|u |R|e|c|u|l |P|o|u|r |c|e|n|t", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8641,6 +8642,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nLorsqu'il est attaché à une arme qui a le mode\nrafale ou auto, cet objet modifie le recul de\nl'arme par le pourcentage indiqué. Réduire le\nrecul permet de mieux garder la bouche de l'arme\npointée sur la cible lors d'une rafale.\n \nValeur faible recommandée.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8399,6 +8399,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|B|e|s|t|e |L|a|s|e|r |R|e|i|c|h|w|e|i|t|e",
L"|P|r|o|z|e|n|t|u|a|l|e|r |R|ü|c|k|s|t|o|ß |M|o|d|i|f|i|k|a|t|o|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8471,6 +8472,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[] =
L"",
L"\n \nWenn befestigt an Feuerstoß oder Dauerfeuer fähigen Fernwaffen\nverändert dieser Gegenstand den Rückstoß um den genannten Prozentwert.\n\n Ein geringerer Rückstoß macht es einfacher, die Waffe im Dauerfeuer auf das Ziel gerichtet zu halten.\n \nNiedriger ist besser.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8573,6 +8573,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|B|e|s|t |L|a|s|e|r |R|a|n|g|e",// TODO.Translate
L"|P|e|r|c|e|n|t |R|e|c|o|i|l |M|o|d|i|f|i|e|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8645,6 +8646,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Recoil by the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8585,6 +8585,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|B|e|s|t |L|a|s|e|r |R|a|n|g|e",// TODO.Translate
L"|P|e|r|c|e|n|t |R|e|c|o|i|l |M|o|d|i|f|i|e|r", // 65
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8657,6 +8658,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nWhen attached to a ranged weapon capable\nof Burst or Autofire modes, this item modifies\nthe weapon's Recoil by the listed percentage.\n \nReducing recoil makes it easier to keep the gun's\nmuzzle pointed at the target during a volley.\n \nLower is better.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=
+2
View File
@@ -8567,6 +8567,7 @@ STR16 szUDBAdvStatsTooltipText[]=
L"|О|п|т|и|м|а|л|ь|н|а|я |д|а|л|ь|н|о|с|т|ь |л|а|з|е|р|а",
L"|М|о|д|и|ф|и|к|а|т|о|р |о|т|д|а|ч|и |в |%",
L"|F|a|n |t|h|e |H|a|m|m|e|r", // TODO.Translate
L"|B|a|r|r|e|l |C|o|n|f|i|g|u|r|a|t|i|o|n|s",
};
// Alternate tooltip text for weapon Advanced Stats. Just different wording, nothing spectacular.
@@ -8639,6 +8640,7 @@ STR16 szUDBAdvStatsExplanationsTooltipText[]=
L"",
L"\n \nПрисоединенный к огнестрельному оружию,\nспособному вести огонь очередями, этот\nпредмет изменяет отдачу оружия на\nуказанный процент.\n \nСнижение отдачи позволяет дольше\nудерживать ствол оружия в направлении цели\nво время залпа.\n \nМеньше - лучше.", // 65
L"\n \nIf a gunslinger wields this gun two-handed,\nthey can burst in hipfire.", // TODO.Translate
L"\n \nToggling firemodes also toggles how many\nbarrels you can fire at the same time.",
};
STR16 szUDBAdvStatsExplanationsTooltipTextForWeapons[]=