Home » MODDING HQ 1.13 » v1.13 Coding Talk » Under Barrel Weapons [Implemented by Flugente]
Under Barrel Weapons [Implemented by Flugente][message #297524]
|
Tue, 31 January 2012 15:42
|
|
JMich |
|
Messages:546
Registered:January 2011 Location: Greece |
|
|
A couple of months ago, I started for the second time working on Under Barrel Weapons for JA2. The first time was back in July, and I did make a mess of it, so I decided to start it over from scratch. While I started with a lot of momentum, during the Christmas holidays the momentum burned out, and I left the project alone for a month or so, so I obviously had no idea how to continue it (my log keeping is a bit worse than my code commenting, since at least I do add the occasional comment).
So, since I don't see myself able to continue working on this project in the foreseeable future, I am posting my current Work In Progress here, in case anyone else is interested in continuing it. So, on to the code part.
DISCLAIMER:
As far as I've checked, the game should work and behave as normal. I have added the new weapon modes, that require an attachment to have an item class of either gun or blade, it supports semi-auto, burst or full auto attachment, and it should reload correctly. I can't recall if the bullet fired is from the UB weapon, since I think I had fixed it but I'm not sure. The last part I was working on, until I saw exactly how much needed change was the NCTH values, since I had to see which values should be taken from the weapon being fired (base weapon or underbarrel weapon) and which should be taken from the base weapon (raise cost, attachments etc). I have modified a few of them, but I have no knowledge of the NCTH system, so I can't really help.
So, tl;dr disclaimer, "Should work, no guarantees".
Patch based on revision 4826
The patch is also copied in the spoiler, in case anyone wants to skim through it.
[spoiler][code]Index: Tactical/Handle UI.cpp
===================================================================
--- Tactical/Handle UI.cpp (revision 4826)
+++ Tactical/Handle UI.cpp (working copy)
@@ -2548,8 +2548,14 @@
// Set aim time to one in UI
pSoldier->aiData.bAimTime = (pSoldier->aiData.bShownAimTime );
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ usItem = GetAttachedUnderBarrel(&pSoldier->inv[HANDPOS]);
+ }
+ else
+ {
usItem = pSoldier->inv[ HANDPOS ].usItem;
-
+ }
// ATE: Check if we are targeting an interactive tile, and adjust gridno accordingly...
pIntNode = GetCurInteractiveTileGridNoAndStructure( &sGridNo, &pStructure );
@@ -2637,6 +2643,10 @@
{
iHandleReturn = HandleItem( pSoldier, sTargetGridNo, bTargetLevel, GetAttachedGrenadeLauncher(&pSoldier->inv[ HANDPOS ]), TRUE );
}
+ else if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ iHandleReturn = HandleItem( pSoldier, sTargetGridNo, bTargetLevel, GetAttachedUnderBarrel(&pSoldier->inv[ HANDPOS ]), TRUE );
+ }
else
{
iHandleReturn = HandleItem( pSoldier, sTargetGridNo, bTargetLevel, pSoldier->inv[ HANDPOS ].usItem, TRUE );
Index: Tactical/Interface Items.cpp
===================================================================
--- Tactical/Interface Items.cpp (revision 4826)
+++ Tactical/Interface Items.cpp (working copy)
@@ -2738,6 +2738,73 @@
}
#endif
// FIRST DISPLAY FREE ROUNDS REMIANING
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ OBJECTTYPE *pObjectUnderBarrel = FindAttachment_UnderBarrel( pObject );
+ INVTYPE *pItemUnderBarrel;
+ if ( ubStatusIndex < RENDER_ITEM_ATTACHMENT1 )
+ {
+ pItemUnderBarrel = &Item[ pObjectUnderBarrel->usItem ];
+ }
+ else
+ {
+ pItemUnderBarrel = &Item[ (*pObjectUnderBarrel)[iter]->GetAttachmentAtIndex( ubStatusIndex - RENDER_ITEM_ATTACHMENT1 )->usItem ];
+ }
+ if ( pItemUnderBarrel->usItemClass == IC_GUN && !Item[pObjectUnderBarrel->usItem].rocketlauncher )
+ {
+ sNewY = sY + sHeight - 10;
+ sNewX = sX + 1;
+
+ SetFontForeground ( AmmoTypes[(*pObjectUnderBarrel)[iter]->data.gun.ubGunAmmoType].fontColour );
+
+
+ // HEADROCK HAM 3.4: Get estimate of bullets left.
+ if ( (gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) )
+ {
+ // Soldier doesn't know.
+ EstimateBulletsLeft( pSoldier, pObjectUnderBarrel );
+ swprintf( pStr, L"%s", gBulletCount );
+ }
+ else
+ {
+ swprintf( pStr, L"%d", (*pObjectUnderBarrel)[iter]->data.gun.ubGunShotsLeft );
+ }
+
+ //swprintf( pStr, L"%d", (*pObject)[iter]->data.gun.ubGunShotsLeft );
+ //swprintf( pStr, L"%d", GetEstimateBulletsLeft(pSoldier, pObject) );
+
+ if ( uiBuffer == guiSAVEBUFFER )
+ {
+ RestoreExternBackgroundRect( sNewX, sNewY, 20, 15 );
+ }
+ mprintf( sNewX, sNewY, pStr );
+ gprintfinvalidate( sNewX, sNewY, pStr );
+
+ SetFontForeground( FONT_MCOLOR_DKGRAY );
+
+ // Display 'JAMMED' if we are jammed
+ if ( (*pObjectUnderBarrel)[iter]->data.gun.bGunAmmoStatus < 0 )
+ {
+ SetFontForeground( FONT_MCOLOR_RED );
+
+ if ( sWidth >= ( BIG_INV_SLOT_WIDTH - 10 ) )
+ {
+ swprintf( pStr, TacticalStr[ JAMMED_ITEM_STR ] );
+ }
+ else
+ {
+ swprintf( pStr, TacticalStr[ SHORT_JAMMED_GUN ] );
+ }
+
+ VarFindFontCenterCoordinates( sX, sY, sWidth, sHeight , ITEM_FONT, &sNewX, &sNewY, pStr );
+
+ mprintf( sNewX, sNewY, pStr );
+ gprintfinvalidate( sNewX, sNewY, pStr );
+ }
+ }
+ }
+ else
+ {
if ( pItem->usItemClass == IC_GUN && !Item[pObject->usItem].rocketlauncher )
{
sNewY = sY + sHeight - 10;
@@ -2812,6 +2879,7 @@
gprintfinvalidate( sNewX, sNewY, pStr );
}
}
+ }
#if 0
else
{
@@ -2922,6 +2990,21 @@
swprintf( pStr, New113Message[MSG113_GL_AUTO] );
SetFontForeground( FONT_YELLOW );
}
+ else if(pSoldier->bWeaponMode == WM_ATTACHED_UB)
+ {
+ swprintf( pStr, New113Message[MSG113_UB] );
+ SetFontForeground( FONT_BLUE );
+ }
+ else if(pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST)
+ {
+ swprintf( pStr, New113Message[MSG113_UB_BRST] );
+ SetFontForeground( FONT_BLUE );
+ }
+ else if(pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ swprintf( pStr, New113Message[MSG113_UB_AUTO] );
+ SetFontForeground( FONT_BLUE );
+ }
// Get length of string
uiStringLength=StringPixLength(pStr, ITEM_FONT );
Index: Tactical/Items.cpp
===================================================================
--- Tactical/Items.cpp (revision 4826)
+++ Tactical/Items.cpp (working copy)
@@ -3585,8 +3585,14 @@
{
return( NO_SLOT );
}
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ pObj = FindAttachment_UnderBarrel(&pSoldier->inv[bWeaponIn]);
+ }
+ else
+ {
pObj = &(pSoldier->inv[bWeaponIn]);
-
+ }
// manual recharge
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
return bWeaponIn;
@@ -3655,7 +3661,14 @@
BOOLEAN fRet;
CHECKF( pSoldier );
+ if ((pSoldier->bWeaponMode == WM_ATTACHED_UB) || (pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST) || (pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO))
+ {
+ pObj = FindAttachment_UnderBarrel(&(pSoldier->inv[HANDPOS]));
+ }
+ else
+ {
pObj = &(pSoldier->inv[HANDPOS]);
+ }
// manual recharge
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
@@ -3745,7 +3758,14 @@
// then do a reload of both guns!
if ( (fRet == TRUE) && pSoldier->IsValidSecondHandShotForReloadingPurposes( ) )
{
+ if ((pSoldier->bWeaponMode == WM_ATTACHED_UB) || (pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST) || (pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO))
+ {
+ pObj = FindAttachment_UnderBarrel(&(pSoldier->inv[SECONDHANDPOS]));
+ }
+ else
+ {
pObj = &(pSoldier->inv[SECONDHANDPOS]);
+ }
bSlot = FindAmmoToReload( pSoldier, SECONDHANDPOS, NO_SLOT );
if (bSlot != NO_SLOT)
{
@@ -9467,8 +9487,10 @@
// Apply a percentage-based modifier. This can increase or decrease BOTH axes. At most, it can eliminate
// recoil on the gun.
- INT16 sPercentRecoilModifier = GetPercentRecoilModifier( pObj );
+ //INT16 sPercentRecoilModifier = GetPercentRecoilModifier( pObj );
+ INT16 sPercentRecoilModifier = __max(-100, (GetBasePercentRecoilModifier( pObj ) + GetAttachmentPercentRecoilModifier( &pSoldier->inv[HANDPOS])));
+
*bRecoilX += (*bRecoilX * sPercentRecoilModifier ) / 100;
*bRecoilY += (*bRecoilY * sPercentRecoilModifier ) / 100;
@@ -9478,7 +9500,10 @@
INT8 bRecoilAdjustX = 0;
INT8 bRecoilAdjustY = 0;
- GetFlatRecoilModifier( pObj, &bRecoilAdjustX, &bRecoilAdjustY );
+ //GetFlatRecoilModifier( pObj, &bRecoilAdjustX, &bRecoilAdjustY );
+ GetBaseFlatRecoilModifier( pObj, &bRecoilAdjustX, &bRecoilAdjustY );
+ GetAttachmentFlatRecoilModifier( &pSoldier->inv[HANDPOS], &bRecoilAdjustX, &bRecoilAdjustY);
+ //JMich TODO: Currently no check for dual wielding
*bRecoilX = __max(0, *bRecoilX + bRecoilAdjustX);
*bRecoilY = __max(0, *bRecoilY + bRecoilAdjustY);
@@ -9490,6 +9515,44 @@
// HEADROCK HAM 4: This function calculates the flat recoil adjustment for a gun. Flat adjustment increases
// or decreases recoil by a specific number of points in either the vertical or horizontal axes (or both).
// It can potentially cause a weapon it reverse its recoil direction.
+void GetBaseFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY )
+{
+ INT8 bRecoilAdjustX = 0;
+ INT8 bRecoilAdjustY = 0;
+ if (pObj->exists() == true && UsingNewCTHSystem() == true)
+ {
+ // Inherent item modifiers
+ bRecoilAdjustX += BonusReduceMore( Item[pObj->usItem].RecoilModifierX, (*pObj)[0]->data.objectStatus );
+ bRecoilAdjustY += BonusReduceMore( Item[pObj->usItem].RecoilModifierY, (*pObj)[0]->data.objectStatus );
+
+ // Ammo item modifiers
+ bRecoilAdjustX += Item[(*pObj)[0]->data.gun.usGunAmmoItem].RecoilModifierX;
+ bRecoilAdjustY += Item[(*pObj)[0]->data.gun.usGunAmmoItem].RecoilModifierY;
+ }
+
+ *bRecoilModifierX = bRecoilAdjustX;
+ *bRecoilModifierY = bRecoilAdjustY;
+}
+void GetAttachmentFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY )
+{
+ INT8 bRecoilAdjustX = 0;
+ INT8 bRecoilAdjustY = 0;
+ if (pObj->exists() == true && UsingNewCTHSystem() == true)
+ {
+ // Attachment item modifiers
+ for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
+ {
+ if (iter->exists())
+ {
+ bRecoilAdjustX += BonusReduceMore( Item[iter->usItem].RecoilModifierX, (*iter)[0]->data.objectStatus );
+ bRecoilAdjustY += BonusReduceMore( Item[iter->usItem].RecoilModifierY, (*iter)[0]->data.objectStatus );
+ }
+ }
+ }
+
+ *bRecoilModifierX += bRecoilAdjustX;
+ *bRecoilModifierY += bRecoilAdjustY;
+}
void GetFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY )
{
@@ -9526,6 +9589,39 @@
// This adjustment either increases or decreases the gun's vertical and horizontal recoil at the same time. Due to
// the percentage-based nature of this modifier, it cannot cause a gun to reverse its recoil - only diminish it to
// zero.
+INT16 GetBasePercentRecoilModifier( OBJECTTYPE *pObj)
+{
+ INT16 sRecoilAdjust = 0;
+
+ if (pObj->exists() == true && UsingNewCTHSystem() == true)
+ {
+ // Inherent item modifiers
+ sRecoilAdjust += BonusReduceMore( Item[pObj->usItem].PercentRecoilModifier, (*pObj)[0]->data.objectStatus );
+
+ // Ammo item modifiers
+ sRecoilAdjust += Item[(*pObj)[0]->data.gun.usGunAmmoItem].PercentRecoilModifier;
+ }
+
+ return (sRecoilAdjust);
+}
+INT16 GetAttachmentPercentRecoilModifier( OBJECTTYPE *pObj)
+{
+ INT16 sRecoilAdjust = 0;
+
+ if (pObj->exists() == true && UsingNewCTHSystem() == true)
+ {
+ for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter)
+ {
+ if (iter->exists())
+ {
+ sRecoilAdjust += BonusReduceMore( Item[iter->usItem].PercentRecoilModifier, (*iter)[0]->data.objectStatus );
+ }
+ }
+ }
+
+ return (sRecoilAdjust);
+
+}
INT16 GetPercentRecoilModifier( OBJECTTYPE *pObj )
{
INT16 sRecoilAdjust = 0;
@@ -10523,7 +10619,59 @@
return( NONE );
}
+UINT16 GetAttachedUnderBarrel( OBJECTTYPE * pObj )
+{
+ if (pObj->exists() == true) {
+ for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
+ if ((Item[iter->usItem].usItemClass & (IC_GUN | IC_BLADE) ) && iter->exists())
+ {
+ return( (UINT16) Item[iter->usItem].uiIndex );
+ }
+ }
+ }
+ return( NONE );
+}
+BOOLEAN IsUnderBarrelAttached( OBJECTTYPE * pObj, UINT8 subObject )
+{
+ if (pObj->exists() == true) {
+
+ for (attachmentList::iterator iter = (*pObj)[subObject]->attachments.begin(); iter != (*pObj)[subObject]->attachments.end(); ++iter) {
+ if (Item[iter->usItem].usItemClass & (IC_GUN | IC_BLADE) && iter->exists() )
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+OBJECTTYPE* FindAttachment_UnderBarrel( OBJECTTYPE * pObj )
+{
+ if (pObj->exists() == true) {
+
+ for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
+ if (Item[iter->usItem].usItemClass & (IC_GUN | IC_BLADE) && iter->exists() )
+ {
+ return( &(*iter) );
+ }
+ }
+ }
+ return( 0 );
+}
+INT16 GetUnderBarrelStatus( OBJECTTYPE * pObj )
+{
+ if (pObj->exists() == true) {
+
+ for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
+ if (Item[iter->usItem].usItemClass & (IC_GUN | IC_BLADE) && iter->exists())
+ {
+ return( (*iter)[0]->data.objectStatus );
+ }
+ }
+ }
+ return( ITEM_NOT_FOUND );
+}
INT16 GetAttachedArmourBonus( OBJECTTYPE * pObj )
{
INT16 bonus=0;
Index: Tactical/Items.h
===================================================================
--- Tactical/Items.h (revision 4826)
+++ Tactical/Items.h (working copy)
@@ -296,7 +296,11 @@
// HEADROCK HAM 4: This function now calculates and returns the weapon's recoil as X/Y offsets.
void GetRecoil( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj, INT8 *bRecoilX, INT8 *bRecoilY, UINT8 ubNumBullet );
+void GetBaseFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY);
+void GetAttachmentFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY);
void GetFlatRecoilModifier( OBJECTTYPE *pObj, INT8 *bRecoilModifierX, INT8 *bRecoilModifierY );
+INT16 GetBasePercentRecoilModifier( OBJECTTYPE *pObj );
+INT16 GetAttachmentPercentRecoilModifier( OBJECTTYPE *pObj);
INT16 GetPercentRecoilModifier( OBJECTTYPE *pObj );
// HEADROCK HAM 4: This function returns whether the last bullet in a burst/autofire volley was a tracer.
BOOLEAN WasPrevBulletATracer( SOLDIERTYPE *pSoldier, OBJECTTYPE *pWeapon );
@@ -333,6 +337,11 @@
BOOLEAN IsGrenadeLauncherAttached( OBJECTTYPE * pObj, UINT8 subObject = 0 );
OBJECTTYPE* FindAttachment_GrenadeLauncher( OBJECTTYPE * pObj );
UINT16 GetAttachedGrenadeLauncher( OBJECTTYPE * pObj );
+INT8 IsUnderBarrel( OBJECTTYPE * pObj );
+INT16 GetUnderBarrelStatus( OBJECTTYPE * pObj );
+BOOLEAN IsUnderBarrelAttached( OBJECTTYPE * pObj, UINT8 subObject = 0 );
+OBJECTTYPE* FindAttachment_UnderBarrel( OBJECTTYPE * pObj );
+UINT16 GetAttachedUnderBarrel( OBJECTTYPE * pObj );
INT8 FindRocketLauncher( SOLDIERTYPE * pSoldier );
INT8 FindRocketLauncherOrCannon( SOLDIERTYPE * pSoldier );
INT8 FindNonSmokeLaunchable( SOLDIERTYPE * pSoldier, UINT16 usWeapon );
Index: Tactical/Points.cpp
===================================================================
--- Tactical/Points.cpp (revision 4826)
+++ Tactical/Points.cpp (working copy)
@@ -1450,9 +1450,19 @@
UINT32 uiItemClass;
BOOLEAN fAddingTurningCost = FALSE;
BOOLEAN fAddingRaiseGunCost = FALSE;
+ OBJECTTYPE* AttackingWeapon;
// LOOK IN BUDDY'S HAND TO DETERMINE WHAT TO DO HERE
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ AttackingWeapon = FindAttachment_UnderBarrel(&pSoldier->inv[HANDPOS]);
+ usItemNum = GetAttachedUnderBarrel(&pSoldier->inv[HANDPOS]);
+ }
+ else
+ {
+ AttackingWeapon = &pSoldier->inv[HANDPOS];
usItemNum = pSoldier->inv[HANDPOS].usItem;
+ }
uiItemClass = Item[ usItemNum ].usItemClass;
if ( uiItemClass == IC_GUN || uiItemClass == IC_LAUNCHER || uiItemClass == IC_TENTACLES || uiItemClass == IC_THROWING_KNIFE )
@@ -1461,10 +1471,10 @@
if ( pSoldier->bDoBurst )
{
- if(pSoldier->bDoAutofire && GetAutofireShotsPerFiveAPs(&pSoldier->inv[HANDPOS]) > 0 )
- sAPCost += CalcAPsToAutofire( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]), pSoldier->bDoAutofire );
+ if(pSoldier->bDoAutofire && GetAutofireShotsPerFiveAPs(AttackingWeapon) > 0 )
+ sAPCost += CalcAPsToAutofire( pSoldier->CalcActionPoints( ), AttackingWeapon, pSoldier->bDoAutofire );
else
- sAPCost += CalcAPsToBurst( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]) );
+ sAPCost += CalcAPsToBurst( pSoldier->CalcActionPoints( ), AttackingWeapon );
}
//else //ddd comment for aimed burst
{
@@ -1487,7 +1497,7 @@
UINT16 usWeaponReadyTime;
UINT8 ubReadyTimeDivisor;
- usWeaponReadyTime = Weapon[ usItemNum ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[HANDPOS])) / 100;
+ usWeaponReadyTime = Weapon[ pSoldier->inv[HANDPOS].usItem ].ubReadyTime * (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[HANDPOS])) / 100;
ubReadyTimeDivisor = gGameExternalOptions.ubFirstAimReadyCostDivisor;
sAPCost += usWeaponReadyTime / ubReadyTimeDivisor;
}
@@ -1668,8 +1678,20 @@
uiItemClass = Item[ glItem ].usItemClass;
}
}
+ else if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ INT16 undbarItem = GetAttachedUnderBarrel( &(pSoldier->inv[ HANDPOS ]) );
+ if ( undbarItem == NONE )
+ {
+ uiItemClass = Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass;
+ }
else
{
+ uiItemClass = Item[ undbarItem ].usItemClass;
+ }
+ }
+ else
+ {
// LOOK IN BUDDY'S HAND TO DETERMINE WHAT TO DO HERE
uiItemClass = Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass;
}
@@ -1915,6 +1937,10 @@
{
usItem = GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS] );//UNDER_GLAUNCHER;
}
+ else if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ usItem = GetAttachedUnderBarrel(&pSoldier->inv[HANDPOS] );
+ }
else
{
usItem = pSoldier->inv[ HANDPOS ].usItem;
@@ -1988,13 +2014,23 @@
}
else
{
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier > 0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && GetBipodBonus(&(pSoldier->inv[HANDPOS])) > 0){
+ bAPCost += (BaseAPsToShootOrStab( bFullAPs, bAimSkill, FindAttachment_UnderBarrel(&(pSoldier->inv[HANDPOS])) ) * (100 - GetBipodBonus(&(pSoldier->inv[HANDPOS]))) / 100);
+ } else {
+ bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, FindAttachment_UnderBarrel(&(pSoldier->inv[HANDPOS])) );
+ }
+ }
+ else
+ {
//CHRISL: When prone and using a bipod, bipod should help compensate for recoil. To reflect this, our shot AP cost should be minimially reduced
if(gGameExternalOptions.ubFlatAFTHBtoPrecentMultiplier > 0 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE && GetBipodBonus(&(pSoldier->inv[HANDPOS])) > 0){
bAPCost += (BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) ) * (100 - GetBipodBonus(&(pSoldier->inv[HANDPOS]))) / 100);
} else {
bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, &(pSoldier->inv[HANDPOS]) );
}
-
+ }
/////////////////////////////////////////////////////////////////////////////////////
// SANDRO - STOMP traits
////////////////////////////////////////////////////
@@ -2314,6 +2350,30 @@
else
return FALSE;
}
+ else if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ OBJECTTYPE* UnderBarrelItem = FindAttachment_UnderBarrel(&(pSoldier->inv[bInvPos]));
+ if (Item[UnderBarrelItem->usItem].usItemClass == IC_GUN)
+ {
+ if ((*UnderBarrelItem)[0]->data.gun.ubGunShotsLeft == 0)
+ {
+ if ( fDisplay )
+ {
+ TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_AMMO );
+ }
+ return( FALSE );
+ }
+
+ // manual recharge
+ if( pSoldier->bTeam == OUR_TEAM )
+ {
+ if ( !( (*UnderBarrelItem)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER ) )
+ {
+ return( FALSE );
+ }
+ }
+ }
+ }
else
{
if ( Item[pSoldier->inv[ bInvPos ].usItem].singleshotrocketlauncher )
@@ -2420,6 +2480,14 @@
}
else
{
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ OBJECTTYPE* UnderBarrelItem = FindAttachment_UnderBarrel(&(pSoldier->inv[bInvPos]));
+ if (Item[UnderBarrelItem->usItem].usItemClass == IC_GUN && ((*UnderBarrelItem)[0]->data.gun.ubGunShotsLeft != 0))
+ {
+ (*UnderBarrelItem)[0]->data.gun.ubGunShotsLeft--;
+ }
+ }
// firing an attachment?
}
}
@@ -2614,8 +2682,14 @@
INT16 bAPCost = 0, bAPCost2 = 0;;
CHECKF( pSoldier );
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ pObj = FindAttachment_UnderBarrel(&pSoldier->inv[HANDPOS]);
+ }
+ else
+ {
pObj = &(pSoldier->inv[HANDPOS]);
-
+ }
// manual recharge
if ((*pObj)[0]->data.gun.ubGunShotsLeft && !((*pObj)[0]->data.gun.ubGunState & GS_CARTRIDGE_IN_CHAMBER) )
{
@@ -2651,7 +2725,14 @@
if ( pSoldier->IsValidSecondHandShotForReloadingPurposes( ) )
{
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ pObj = FindAttachment_UnderBarrel(&pSoldier->inv[SECONDHANDPOS]);
+ }
+ else
+ {
pObj = &(pSoldier->inv[SECONDHANDPOS]);
+ }
bExcludeSlot = NO_SLOT;
bSlot2 = NO_SLOT;
Index: Tactical/Turn Based Input.cpp
===================================================================
--- Tactical/Turn Based Input.cpp (revision 4826)
+++ Tactical/Turn Based Input.cpp (working copy)
@@ -3729,11 +3729,49 @@
{
AutoReload( pTeamSoldier );
}
+ if (IsUnderBarrelAttached(pGun))
+ {
+ OBJECTTYPE *pGun2 = FindAttachment_UnderBarrel(pGun);
+ if ( (*pGun2)[0]->data.gun.ubGunShotsLeft < GetMagSize( pGun2 ) )
+ {
+
+ // Search for ammo in sector
+ for ( UINT32 uiLoop = 0; uiLoop < guiNumWorldItems; uiLoop++ )
+ {
+ if ( (gWorldItems[ uiLoop ].bVisible == TRUE) && (gWorldItems[ uiLoop ].fExists) && (gWorldItems[ uiLoop ].usFlags & WORLD_ITEM_REACHABLE) && !(gWorldItems[ uiLoop ].usFlags & WORLD_ITEM_ARMED_BOMB) )//item exists, is reachable, is visible and is not trapped
+ {
+ if ( ( Item[ gWorldItems[ uiLoop ].object.usItem ].usItemClass & IC_AMMO ) ) // the item is ammo
+ {
+ pAmmo = &( gWorldItems[ uiLoop ].object );
+
+ if ( CompatibleAmmoForGun( pAmmo, pGun2 ) ) // can use the ammo with this gun
+ {
+ // same ammo type in gun and magazine
+ if ( Magazine[Item[(*pGun2)[0]->data.gun.usGunAmmoItem].ubClassIndex].ubAmmoType == Magazine[Item[pAmmo->usItem].ubClassIndex].ubAmmoType )
+ {
+ ReloadGun( pTeamSoldier, pGun2, pAmmo );
}
+
+ if ((*pAmmo)[0]->data.ubShotsLeft == 0)
+ {
+ RemoveItemFromPool( gWorldItems[ uiLoop ].sGridNo, uiLoop, gWorldItems[ uiLoop ].ubLevel );
}
}
}
}
+ }
+ }
+ //CHRISL: if not enough ammo in sector, reload using ammo carried in inventory
+ if ( (*pGun2)[0]->data.gun.ubGunShotsLeft < GetMagSize( pGun2 ) )
+ {
+ AutoReload( pTeamSoldier );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
else
{
SOLDIERTYPE *pTeamSoldier;
@@ -3748,8 +3786,14 @@
{
if ( ( gTacticalStatus.uiFlags & INCOMBAT ) )
{
+ if ((pTeamSoldier->bWeaponMode == WM_ATTACHED_UB) || (pTeamSoldier->bWeaponMode == WM_ATTACHED_UB_BURST) || (pTeamSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO))
+ {
+ pGun = FindAttachment_UnderBarrel(&(pTeamSoldier->inv[HANDPOS]));
+ }
+ else
+ {
pGun = &(pTeamSoldier->inv[HANDPOS]);
-
+ }
//magazine is not full
if ( (*pGun)[0]->data.gun.ubGunShotsLeft < GetMagSize( pGun ) )
{
Index: Tactical/UI Cursors.cpp
===================================================================
--- Tactical/UI Cursors.cpp (revision 4826)
+++ Tactical/UI Cursors.cpp (working copy)
@@ -2573,9 +2573,14 @@
else
return ( TRAJECTORYCURS );
}
-
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ usInHand = GetAttachedUnderBarrel(&pSoldier->inv[HANDPOS]);
+ }
+ else
+ {
usInHand = pSoldier->inv[HANDPOS].usItem;
-
+ }
// Start off with what is in our hand
ubCursor = Item[ usInHand ].ubCursor;
Index: Tactical/Weapons.cpp
===================================================================
--- Tactical/Weapons.cpp (revision 4826)
+++ Tactical/Weapons.cpp (working copy)
@@ -1139,7 +1139,14 @@
{
if ( Item[pSoldier->usAttackingWeapon].usItemClass == IC_GUN && !EXPLOSIVE_GUN( pSoldier->usAttackingWeapon ) )
{
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ pObj = FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]);
+ }
+ else
+ {
pObj = &(pSoldier->inv[pSoldier->ubAttackingHand]);
+ }
if ((*pObj)[0]->data.gun.bGunAmmoStatus > 0)
{
// Algorithm for jamming
@@ -1214,11 +1221,20 @@
{
DeductPoints(pSoldier, APBPConstants[AP_UNJAM], APBPConstants[BP_UNJAM] );
INT8 bChanceMod;
-
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ if ( Weapon[(FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand])->usItem)].EasyUnjam )
+ bChanceMod = 100;
+ else
+ bChanceMod = (INT8) (GetReliability( pObj )* 4);
+ }
+ else
+ {
if ( Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].EasyUnjam )
bChanceMod = 100;
else
bChanceMod = (INT8) (GetReliability( pObj )* 4);
+ }
int iResult = SkillCheck( pSoldier, UNJAM_GUN_CHECK, bChanceMod);
@@ -1604,14 +1620,32 @@
// Only deduct points once for Burst and Autofire (on firing the first bullet).
if ( pSoldier->bDoBurst == 1 )
{
- INT8 bShotsToFire = pSoldier->bDoAutofire ?
+ INT8 bShotsToFire;
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ bShotsToFire = pSoldier->bDoAutofire ?
pSoldier->bDoAutofire :
+ GetShotsPerBurst(FindAttachment_UnderBarrel (&pSoldier->inv[HANDPOS]));
+ }
+ else
+ {
+ bShotsToFire = pSoldier->bDoAutofire ?
+ pSoldier->bDoAutofire :
GetShotsPerBurst(&pSoldier->inv[HANDPOS]);
+ }
if ( Weapon[ usItemNum ].sBurstSound != NO_WEAPON_SOUND )
{
+ UINT16 noisefactor;
// IF we are silenced?
- UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ noisefactor = GetPercentNoiseVolume(FindAttachment_UnderBarrel (&pSoldier->inv[pSoldier->ubAttackingHand] ));
+ }
+ else
+ {
+ noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
+ }
if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ usItemNum ].ubAttackVolume <= 10 )
{
// Pick sound file baed on how many bullets we are going to fire...
@@ -1696,7 +1730,7 @@
}
//ddd{θηνξρ ξαϊεκςξβ ρ μσηηλε τλΰψ. silencer
- if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor)
+ if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor && pSoldier->bWeaponMode != WM_ATTACHED_UB && pSoldier->bWeaponMode != WM_ATTACHED_UB_BURST && pSoldier->bWeaponMode != WM_ATTACHED_UB_AUTO)
{
OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) )
@@ -1723,7 +1757,7 @@
//DIGICRAB: Barrel extender wear code
// Relocated from CalcChanceToHitGun
- if ( Item[ usItemNum ].usItemClass == IC_GUN )
+ if ( Item[ usItemNum ].usItemClass == IC_GUN && pSoldier->bWeaponMode != WM_ATTACHED_UB && pSoldier->bWeaponMode != WM_ATTACHED_UB_BURST && pSoldier->bWeaponMode != WM_ATTACHED_UB_AUTO )
{
OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
@@ -1815,41 +1849,27 @@
DeductAmmo( pSoldier, pSoldier->ubAttackingHand );
// ATE: Check if we should say quote...
- if ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft == 0 && !Item[pSoldier->usAttackingWeapon].rocketlauncher )
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
{
+ if ( ((*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.gun.ubGunShotsLeft == 0) && !Item[pSoldier->usAttackingWeapon].rocketlauncher )
+ {
if ( pSoldier->bTeam == gbPlayerNum )
{
pSoldier->flags.fSayAmmoQuotePending = TRUE;
}
}
-
- // set buckshot and muzzle flash
- fBuckshot = FALSE;
- if (!CREATURE_OR_BLOODCAT( pSoldier ) )
+ }
+ else
{
- if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) )
- pSoldier->flags.fMuzzleFlash = FALSE;
- else
- pSoldier->flags.fMuzzleFlash = TRUE;
-
- DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: Muzzle flash = %d",pSoldier->flags.fMuzzleFlash));
-
- if ( AmmoTypes[pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].numberOfBullets > 1 )
- fBuckshot = TRUE;
-
- //switch ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType )
- //{
- // case AMMO_BUCKSHOT:
- // fBuckshot = TRUE;
- // break;
- // case AMMO_SLEEP_DART:
- // pSoldier->flags.fMuzzleFlash = FALSE;
- // break;
- // default:
- // break;
- //}
+ if ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft == 0 && !Item[pSoldier->usAttackingWeapon].rocketlauncher )
+ {
+ if ( pSoldier->bTeam == gbPlayerNum )
+ {
+ pSoldier->flags.fSayAmmoQuotePending = TRUE;
}
}
+ }
+ }
else // throwing knife
{
fBuckshot = FALSE;
@@ -1908,8 +1928,15 @@
INT16 sApertureRatio = 0;
if ( !AreInMeanwhile() )
{
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ AdjustTargetCenterPoint( pSoldier, sTargetGridNo, &dTargetX, &dTargetY, &dTargetZ, FindAttachment_UnderBarrel(&pSoldier->inv[ pSoldier->ubAttackingHand ]), uiMuzzleSway, &sApertureRatio );
+ }
+ else
+ {
AdjustTargetCenterPoint( pSoldier, sTargetGridNo, &dTargetX, &dTargetY, &dTargetZ, &pSoldier->inv[ pSoldier->ubAttackingHand ], uiMuzzleSway, &sApertureRatio );
}
+ }
//////////////////////////////////////////////////////////////////////////////////////////////
// HEADROCK HAM 4: Basic Experience Gain
@@ -2056,6 +2083,20 @@
else
{
// Snap: get cumulative noise reduction from the weapon and its attachments
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ UINT16 noisefactor = GetPercentNoiseVolume( FindAttachment_UnderBarrel(&pSoldier->inv[ pSoldier->ubAttackingHand ] ) );
+ if ( ubVolume * noisefactor > 25000 )
+ { // Snap: hack this to prevent overflow (damn miserly programmers!)
+ ubVolume = 250;
+ }
+ else
+ {
+ ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( FindAttachment_UnderBarrel(&pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) ) / 100 );
+ }
+ }
+ else
+ {
UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
if ( ubVolume * noisefactor > 25000 )
{ // Snap: hack this to prevent overflow (damn miserly programmers!)
@@ -2066,6 +2107,7 @@
ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) / 100 );
}
}
+ }
MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_GUNFIRE );
@@ -2084,13 +2126,22 @@
// ammoReliability = Item[(*pGun)[0]->data.gun.usGunAmmoItem].bReliability;
//}
- uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * GetReliability( &(pSoldier->inv[pSoldier->ubAttackingHand]) ), 0);
-
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( & ( *FindAttachment_UnderBarrel( &pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) ) ), 0);
+ if ( !PreRandom( uiDepreciateTest ) && ( (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.objectStatus > 1) )
+ {
+ (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.objectStatus--;
+ }
+ }
+ else
+ {
+ uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ) ), 0);
if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) )
{
pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus--;
}
-
+ }
// reduce monster smell (gunpowder smell)
if ( pSoldier->aiData.bMonsterSmell > 0 && Random( 2 ) == 0 )
{
@@ -2099,7 +2150,14 @@
// manual recharge
if (Weapon[Item[usItemNum].ubClassIndex].APsToReloadManually > 0)
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER;
+ }
+ else
+ {
pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER;
+ }
//
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: done"));
return( TRUE );
@@ -2138,14 +2196,31 @@
// ONly deduct points once
if ( pSoldier->bDoBurst == 1 )
{
- INT8 bShotsToFire = pSoldier->bDoAutofire ?
+ INT8 bShotsToFire;
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ bShotsToFire = pSoldier->bDoAutofire ?
pSoldier->bDoAutofire :
+ GetShotsPerBurst(FindAttachment_UnderBarrel (&pSoldier->inv[HANDPOS]));
+ }
+ else
+ {
+ bShotsToFire = pSoldier->bDoAutofire ?
+ pSoldier->bDoAutofire :
GetShotsPerBurst(&pSoldier->inv[HANDPOS]);
-
+ }
if ( Weapon[ usItemNum ].sBurstSound != NO_WEAPON_SOUND )
{
+ UINT16 noisefactor;
// IF we are silenced?
- UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ noisefactor = GetPercentNoiseVolume(FindAttachment_UnderBarrel (&pSoldier->inv[pSoldier->ubAttackingHand] ));
+ }
+ else
+ {
+ noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
+ }
if( noisefactor < MAX_PERCENT_NOISE_VOLUME_FOR_SILENCED_SOUND || Weapon[ usItemNum ].ubAttackVolume <= 10 )
{
// Pick sound file baed on how many bullets we are going to fire...
@@ -2247,7 +2322,7 @@
fCalculateCTHDuringGunfire = FALSE;
//ddd{θηνξρ ξαϊεκςξβ ρ μσηηλε τλΰψ. silencer
- if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor)
+ if ( (Item[ usItemNum ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor && pSoldier->bWeaponMode != WM_ATTACHED_UB && pSoldier->bWeaponMode != WM_ATTACHED_UB_BURST && pSoldier->bWeaponMode != WM_ATTACHED_UB_AUTO)
{
OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) )
@@ -2274,7 +2349,7 @@
//DIGICRAB: Barrel extender wear code
// Relocated from CalcChanceToHitGun
- if ( Item[ usItemNum ].usItemClass == IC_GUN )
+ if ( Item[ usItemNum ].usItemClass == IC_GUN && pSoldier->bWeaponMode != WM_ATTACHED_UB && pSoldier->bWeaponMode != WM_ATTACHED_UB_BURST && pSoldier->bWeaponMode != WM_ATTACHED_UB_AUTO )
{
OBJECTTYPE * pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
@@ -2400,6 +2475,18 @@
DeductAmmo( pSoldier, pSoldier->ubAttackingHand );
// ATE: Check if we should say quote...
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ if ( ((*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.gun.ubGunShotsLeft == 0) && !Item[pSoldier->usAttackingWeapon].rocketlauncher )
+ {
+ if ( pSoldier->bTeam == gbPlayerNum )
+ {
+ pSoldier->flags.fSayAmmoQuotePending = TRUE;
+ }
+ }
+ }
+ else
+ {
if ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft == 0 && !Item[pSoldier->usAttackingWeapon].rocketlauncher )
{
if ( pSoldier->bTeam == gbPlayerNum )
@@ -2407,7 +2494,7 @@
pSoldier->flags.fSayAmmoQuotePending = TRUE;
}
}
-
+ }
// NB bDoBurst will be 2 at this point for the first shot since it was incremented
// above
if ( PTR_OURTEAM && pSoldier->ubTargetID != NOBODY && (!pSoldier->bDoBurst || pSoldier->bDoBurst == 2 ) && (gTacticalStatus.uiFlags & INCOMBAT ) && ( SoldierToSoldierBodyPartChanceToGetThrough( pSoldier, MercPtrs[ pSoldier->ubTargetID ], pSoldier->bAimShotLocation ) > 0 ) )
@@ -2455,16 +2542,23 @@
fBuckshot = FALSE;
if (!CREATURE_OR_BLOODCAT( pSoldier ) )
{
- if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) )
+ if ( IsFlashSuppressor(&pSoldier->inv[ pSoldier->ubAttackingHand ], pSoldier ) && pSoldier->bWeaponMode != WM_ATTACHED_UB && pSoldier->bWeaponMode != WM_ATTACHED_UB_BURST && pSoldier->bWeaponMode != WM_ATTACHED_UB_AUTO )
pSoldier->flags.fMuzzleFlash = FALSE;
else
pSoldier->flags.fMuzzleFlash = TRUE;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: Muzzle flash = %d",pSoldier->flags.fMuzzleFlash));
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ if ( AmmoTypes[(*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.gun.ubGunAmmoType].numberOfBullets > 1 )
+ fBuckshot = TRUE;
+ }
+ else
+ {
if ( AmmoTypes[pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].numberOfBullets > 1 )
fBuckshot = TRUE;
-
+ }
//switch ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType )
//{
// case AMMO_BUCKSHOT:
@@ -2606,6 +2700,20 @@
else
{
// Snap: get cumulative noise reduction from the weapon and its attachments
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ UINT16 noisefactor = GetPercentNoiseVolume( FindAttachment_UnderBarrel(&pSoldier->inv[ pSoldier->ubAttackingHand ] ) );
+ if ( ubVolume * noisefactor > 25000 )
+ { // Snap: hack this to prevent overflow (damn miserly programmers!)
+ ubVolume = 250;
+ }
+ else
+ {
+ ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( FindAttachment_UnderBarrel(&pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) ) / 100 );
+ }
+ }
+ else
+ {
UINT16 noisefactor = GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] );
if ( ubVolume * noisefactor > 25000 )
{ // Snap: hack this to prevent overflow (damn miserly programmers!)
@@ -2616,6 +2724,7 @@
ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( &pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) / 100 );
}
}
+ }
MakeNoise( pSoldier->ubID, pSoldier->sGridNo, pSoldier->pathing.bLevel, pSoldier->bOverTerrainType, ubVolume, NOISE_GUNFIRE );
@@ -2637,13 +2746,22 @@
}
*/
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( & ( *FindAttachment_UnderBarrel( &pSoldier->inv[ pSoldier->ubAttackingHand ] ) ) ) ), 0);
+ if ( !PreRandom( uiDepreciateTest ) && ( (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.objectStatus > 1) )
+ {
+ (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.objectStatus--;
+ }
+ }
+ else
+ {
uiDepreciateTest = max( BASIC_DEPRECIATE_CHANCE + 3 * ( GetReliability( &(pSoldier->inv[ pSoldier->ubAttackingHand ]) ) ), 0);
-
if ( !PreRandom( uiDepreciateTest ) && ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > 1) )
{
pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus--;
}
-
+ }
// reduce monster smell (gunpowder smell)
if ( pSoldier->aiData.bMonsterSmell > 0 && Random( 2 ) == 0 )
{
@@ -2652,7 +2770,14 @@
// manual recharge
if (Weapon[Item[usItemNum].ubClassIndex].APsToReloadManually > 0)
+ if (pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ (*FindAttachment_UnderBarrel(&pSoldier->inv[pSoldier->ubAttackingHand]))[0]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER;
+ }
+ else
+ {
pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunState &= ~GS_CARTRIDGE_IN_CHAMBER;
+ }
//
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("UseGun: done"));
return( TRUE );
@@ -2726,7 +2851,14 @@
iImpact = HTHImpact( pSoldier, pTargetSoldier, (iHitChance - iDiceRoll), TRUE );
// modify this by the knife's condition (if it's dull, not much good)
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ iImpact = ( iImpact * WEAPON_STATUS_MOD( GetUnderBarrelStatus ( &pSoldier->inv[pSoldier->ubAttackingHand] ) ) ) / 100;
+ }
+ else
+ {
iImpact = ( iImpact * WEAPON_STATUS_MOD(pSoldier->inv[pSoldier->ubAttackingHand][0]->data.objectStatus) ) / 100;
+ }
// modify by hit location
AdjustImpactByHitLocation( iImpact, pSoldier->bAimShotLocation, &iImpact, &iImpactForCrits );
@@ -2742,7 +2874,23 @@
{
iImpact = 1;
}
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ if ( GetUnderBarrelStatus ( &pSoldier->inv[pSoldier->ubAttackingHand] ) > USABLE )
+ {
+ bMaxDrop = (iImpact / 20);
+ // the duller they get, the slower they get any worse...
+ bMaxDrop = __min( bMaxDrop, GetUnderBarrelStatus ( &pSoldier->inv[pSoldier->ubAttackingHand] ) / 10 );
+
+ // as long as its still > USABLE, it drops another point 1/2 the time
+ bMaxDrop = __max( bMaxDrop, 2 );
+
+ (* FindAttachment_UnderBarrel ( &pSoldier->inv[pSoldier->ubAttackingHand] ) )[0]->data.objectStatus -= (INT8) Random ( bMaxDrop ); // 0 to (maxDrop - 1)
+ }
+ }
+ else
+ {
if ( pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus > USABLE )
{
bMaxDrop = (iImpact / 20);
@@ -2755,7 +2903,7 @@
pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.objectStatus -= (INT8) Random( bMaxDrop ); // 0 to (maxDrop - 1)
}
-
+ }
// SANDRO - new merc records - times wounded (stabbed)
if ( pTargetSoldier->ubProfile != NO_PROFILE )
gMercProfiles[ pTargetSoldier->ubProfile ].records.usTimesWoundedStabbed++;
@@ -3767,9 +3915,16 @@
ANITILE_PARAMS AniParams;
UINT8 ubAmmoType;
UINT16 usItem;
-
+ if ( MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB || MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB_BURST || MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ ubAmmoType = (*FindAttachment_UnderBarrel ( &MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ] ) )[0]->data.gun.ubGunAmmoType;
+ usItem = (*FindAttachment_UnderBarrel ( &MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ]) ).usItem;
+ }
+ else
+ {
ubAmmoType = MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ][0]->data.gun.ubGunAmmoType;
usItem = MercPtrs[ ubAttackerID ]->inv[ MercPtrs[ ubAttackerID ]->ubAttackingHand ].usItem;
+ }
memset( &AniParams, 0, sizeof( ANITILE_PARAMS ) );
@@ -3922,24 +4077,31 @@
void WeaponHit( UINT16 usSoldierID, UINT16 usWeaponIndex, INT16 sDamage, INT16 sBreathLoss, UINT16 usDirection, INT16 sXPos, INT16 sYPos, INT16 sZPos, INT16 sRange , UINT8 ubAttackerID, BOOLEAN fHit, UINT8 ubSpecial, UINT8 ubHitLocation )
{
SOLDIERTYPE *pTargetSoldier, *pSoldier;
-
+ OBJECTTYPE *pObj;
// Get attacker
pSoldier = MercPtrs[ ubAttackerID ];
-
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ pObj = FindAttachment_UnderBarrel ( &pSoldier->inv[pSoldier->ubAttackingHand] );
+ }
+ else
+ {
+ pObj = &pSoldier->inv[pSoldier->ubAttackingHand];
+ }
// Get Target
pTargetSoldier = MercPtrs[ usSoldierID ];
MakeNoise( ubAttackerID, pTargetSoldier->sGridNo, pTargetSoldier->pathing.bLevel, gpWorldLevelData[pTargetSoldier->sGridNo].ubTerrainID, Weapon[ usWeaponIndex ].ubHitVolume, NOISE_BULLET_IMPACT );
// CALLAHAN START BUGFIX
- if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1)
+ if ( EXPLOSIVE_GUN( usWeaponIndex ) || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
// CALLAHAN END BUGFIX
{
// Reduce attacker count!
//TODO: Madd --- I don't think this code will ever get called for the HE ammo -- the EXPLOSIVE_GUN check filters out regular guns
// marke test mag ammo type: pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType
// 2cond 'or' added
- if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1 )
+ if ( Item[usWeaponIndex].rocketlauncher || AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1 )
{
if ( Item[usWeaponIndex].singleshotrocketlauncher )
{
@@ -3947,6 +4109,7 @@
}
// changed rpg type to work only with two flags matching
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
+ //we shouldn't be able to have an underbarrel firing mode in this step, so we keep the original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("WeaponHit: RPG7 item: %d, Ammo: %d",pSoldier->inv[HANDPOS].usItem , pSoldier->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
@@ -3960,10 +4123,10 @@
pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
- else if ( AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1)
+ else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
- IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
+ IgniteExplosion( ubAttackerID, sXPos, sYPos, 0, GETWORLDINDEXFROMWORLDCOORDS( sYPos, sXPos ), AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].highExplosive , pTargetSoldier->pathing.bLevel );
// pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
@@ -4009,9 +4172,18 @@
BOOLEAN fHitSameStructureAsBefore;
BULLET * pBullet;
SOLDIERTYPE * pAttacker = NULL;
+ OBJECTTYPE * pObj;
pBullet = GetBulletPtr( iBullet );
+ if ( MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB || MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB_BURST || MercPtrs[ ubAttackerID ]->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ pObj = FindAttachment_UnderBarrel ( &MercPtrs [ ubAttackerID ]->inv[&MercPtrs[ubAttackerID]->ubAttackingHand]);
+ }
+ else
+ {
+ pObj = &MercPtrs [ ubAttackerID ]->inv[&MercPtrs[ubAttackerID]->ubAttackingHand];
+ }
if ( fStopped && ubAttackerID != NOBODY )
{
pAttacker = MercPtrs[ ubAttackerID ];
@@ -4076,6 +4248,7 @@
}
// changed too to use 2 flag to determine
else if ( !Item[usWeaponIndex].singleshotrocketlauncher && Item[usWeaponIndex].rocketlauncher)
+ //there shouldn't be a way to enter here with an UnderBarrel weapon, so retaining original code :JMich
{
DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("StructureHit: RPG7 item: %d, Ammo: %d",pAttacker->inv[HANDPOS].usItem , pAttacker->inv[HANDPOS][0]->data.gun.usGunAmmoItem ) );
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem , (INT8)( sZPos >= WALL_HEIGHT ) );
@@ -4088,7 +4261,7 @@
pAttacker->inv[pAttacker->ubAttackingHand ][0]->data.gun.usGunAmmoItem = NONE;
}
}
- else if ( AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].explosionSize > 1)
+ else if ( AmmoTypes[(*pObj)[0]->data.gun.ubGunAmmoType].explosionSize > 1)
{
// re-routed the Highexplosive value to define exposion type
IgniteExplosion( ubAttackerID, CenterX( sGridNo ), CenterY( sGridNo ), 0, sGridNo, AmmoTypes[pSoldier->inv[pSoldier->ubAttackingHand ][0]->data.gun.ubGunAmmoType].highExplosive , (INT8)( sZPos >= WALL_HEIGHT ) );
@@ -4439,9 +4612,17 @@
{
INT32 sRange;
UINT16 usInHand;
-
+ OBJECTTYPE *pObj;
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("InRange"));
- usInHand = pSoldier->inv[HANDPOS].usItem;
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO)
+ {
+ pObj = FindAttachment_UnderBarrel( &pSoldier->inv[HANDPOS]);
+ }
+ else
+ {
+ pObj = &pSoldier->inv[HANDPOS];
+ }
+ usInHand = (*pObj).usItem;
INVTYPE* pItemInHand = &Item[ usInHand ];
if ( pItemInHand->usItemClass == IC_GUN || pItemInHand->usItemClass == IC_THROWING_KNIFE || (pItemInHand->rocketlauncher && !pItemInHand->singleshotrocketlauncher))
@@ -4460,7 +4641,7 @@
else
{
// For given weapon, check range
- if ( sRange <= GunRange( &(pSoldier->inv[HANDPOS]), pSoldier ) ) // SANDRO - added argument
+ if ( sRange <= GunRange( pObj, pSoldier ) ) // SANDRO - added argument
{
return( TRUE );
}
@@ -4497,7 +4678,14 @@
FLOAT scopeRangeMod;
// make sure the guy's actually got a weapon in his hand!
+ if ( pSoldier->bWeaponMode == WM_ATTACHED_UB || pSoldier->bWeaponMode == WM_ATTACHED_UB_BURST || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO )
+ {
+ pInHand = FindAttachment_UnderBarrel(&(pSoldier->inv[pSoldier->ubAttackingHand]));
+ }
+ else
+ {
pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
+ }
usInHand = pSoldier->usAttackingWeapon;
gCTHDisplay.fMaxAimReached = FALSE;
@@ -4618,7 +4806,7 @@
iChance = (INT32)iCombinedSkill;
// Add a flat Base bonus from the item and its attachments.
- iChance += GetFlatBaseModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
+ iChance += GetFlatBaseModifier( &(pSoldier->inv[pSoldier->ubAttackingHand]), gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
// We now begin adding up factors that may increase or decrease Base CTH. They are pooled together to form a percentage
// value.
@@ -4805,7 +4993,7 @@
// Gun Difficulty Modifiers
// FIRING 1-HANDED WEAPONS
- if ( !(Item[ usInHand ].twohanded ) )
+ if ( !(Item[ usInHand ].twohanded ) ) //JMich todo: underbarrel
{
if (pSoldier->inv[SECONDHANDPOS].exists() != false)
{
@@ -5013,7 +5201,7 @@
}
// Percentage based-modifier from the weapon and its attachments
- iBaseModifier += GetPercentBaseModifier( pInHand, gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
+ iBaseModifier += GetPercentBaseModifier( &(pSoldier->inv[pSoldier->ubAttackingHand]), gAnimControl[ pSoldier->usAnimState ].ubEndHeight );
////////////////////////////////////
@@ -5051,7 +5239,7 @@
{
// Are we using a scope? If so, what's the range factor?
- FLOAT iScopeMagFactor = GetBestScopeMagnificationFactor( pSoldier, pInHand, d2DDistance );
+ FLOAT iScopeMagFactor = GetBestScopeMagnificationFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance );
//CHRISL: This does make sense but it effectively makes high powered scopes worthless if a target is actually visible. As an example, a Battle Scope
// is going to have a iScopeMagFactor of 7. With a "NORMAL_SHOOTING_DISTANCE" also of 7, we're going to end up with uiBestScopeRange of 49. That's
// effectilvey saying that any target within 490m is "too close" for the scope to be effective. That by itself isn't realistic. But in JA2 it's also
@@ -5065,15 +5253,15 @@
// uiBestScopeRange value in half. This should allow a Battle Scope to reach full effeciency at 24 tiles and a Sniper scope will be fully effecient at
// 35 tiles. ACOG becomes fully effecient at 14 tiles and 2x is fully effeciency at 7 tiles (compared to 28 and 14 respectively). This does mean that a
// 2x scope reaches full effeciency at the same point as "scopeless" shooting, but I don't think this will be a serious problem.
- FLOAT rangeModifier = GetScopeRangeMultiplier(pSoldier, pInHand, (FLOAT)iRange);
+ FLOAT rangeModifier = GetScopeRangeMultiplier(pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), (FLOAT)iRange);
UINT32 uiBestScopeRange = (UINT32)(iScopeMagFactor * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE * rangeModifier);
FLOAT iAimModifier = 0;
/
[Updated on: Tue, 10 April 2012 09:12] by Moderator Report message to a moderator
|
First Sergeant
|
|
|
Re: [WIP] Under Barrel Weapons[message #302441]
|
Mon, 26 March 2012 22:51
|
|
Flugente |
|
Messages:3507
Registered:April 2009 Location: Germany |
|
|
Update: I inherited JMich's code and got it working on recent code (r5123, which is today). It works with both OCTH and NCTH, I should have tweaked all the important spots for this.
In this picture you can see Kelly firing a shotgun attached to his M16A1 (The bullet graphic proves it ain't a normal shot if you don't believe it
This is the masterkey shotgun. I plan to at least add the M26 MASS and some kind of underbarrel pistol/MP/smg, if such a thing exists. I'll then release a .exe, and a patch if people think this this should go to the trunk (I do).
However, two things are missing before I do that.
1) Pictures. For the Masterkey I only have the BigItem pic (thanks to smeag for providing this!), for the other weapons I have no pics. I currently use the Ithaca pics, which isn't bad but not correct. I'd be glad if pics could be provided, as I am inept at making non-icon pics.
2) I found a strange bug (system limit?): I can't attach any attachments to an attached weapon. To clarify: If i attach a silencer to an SMG, it's ok. If I attach that SMG to an AR, the silencer gets taken off. And I can' reattach it while the SMG itself is attached.
Same with ammunition: I can't replace ammo in the UDB while a weapon is attached. The clip I get is correct, but the new ammo is written. However, reloading an empty attached gun bay clicking into the environment works. I also made a change that lets you reload your attached gun simply by clicking with ammunition onto the weapon when its in an alternative fire-mode. As this is way easier, the reloading issue is kinda minor.
However, not being able to attach anything to an underbarrel gun is annoying. If anybody could give any insight into attachment behaviour if attachments are attached to attachments themselves, I'd be thankful. I remember not being able to reload a pistol that was attached to pants in the past,
So yeah. Help me with these issues and we'll have these new toys in the game in no-time
Report message to a moderator
|
|
|
|
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #302487]
|
Tue, 27 March 2012 21:19
|
|
Flugente |
|
Messages:3507
Registered:April 2009 Location: Germany |
|
|
As it currently is, boni from sights/scopes/lasers of the main weapon also apply to the underbarrel weapon. This is done code-wise, I had to go through all routines of OCTH/NCTH that have anything to do with aiming and firing a gun. Basically aiming is done via the main weapon, physical values (like gun range, recoil) are taken from the underbarrel one. This wasn't always easy, as sometimes it isn't clear for what a certain bonus is applied.
Theoretically, the underbarrel shotgun might feel a bit powerful, as its draw cost is that of the main gun (you raise that, the underbarrel one is of course raised too) and you can aim with a 7x scope... But in my eyes that is a clear deficit of the current CTH systems ( a shotgun shouldn't be super acurate, no matter the scope used).
I did not change anything for underbarrel grenade launchers, as they don't really work like normal guns.
The tags don't really help me. I can easily differentiate between attachments to the main gun and attachments to the underbarrel gun. Problem is getting the attachments there in NAS.
I didn't implement bayonets, that would require additional coding (gun changes into melee weapon in a certain fire-mode). without proper animations, this might look rather dumb.
Report message to a moderator
|
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #302492]
|
Tue, 27 March 2012 21:50
|
|
Wil473 |
|
Messages:2815
Registered:September 2004 Location: Canada |
|
|
If it is easy to differentiate between attachments, then it may be better to isolate the attachments on 2ndary weapons to its own interface screen. ie. stuff attached to the 2ndary weapon are only visible when you bring up its details.
Wil's bad idea hidden (EDIT6)
Toggle SpoilerNAS already has two attachment classes that may not be customized: 1024 and 2048 These two attachment classes are used for launchers launchables (grenades and rockets). I'm thinking that anything classed as one of these two attachment classes should have its attachments visible only when you look at the detail view of the attachments.
Pro: no new hard coded attachment classes. No slot conflicts when attachment is a weapon (with its own set of slots). Possible benefit, the loaded grenade/rocket is moved off the main weapon's attachment screen.
Con: while it should be possible to load an attached launcher by simply clicking the round on the primary weapon, unloading the attached launcher will require going down an additional level to reach the launcher's attachment screen.
EDIT: ChrisL or Warmsteel probably would be able to advise on the NAS code, all I know is the XML side of things, and I've lost touch with the so-called "stock" v1.13 XML's as I've got my own ideas on how things should be done...
EDIT2: fitting sort of on the pro side of things more than con, by moving the 2ndary weapon's attachment to its own details screen, Smeagol's plan to individualize 20mm rounds for the OICW would have a cleaner interface as you wouldn't see the rounds unless you accessed the magazine's details (the magazine is actually the launcher).
EDIT3: actually, you may want to have only one of the two attachment classes have the behaviour of not transferring/making visible attachments on the main weapon interface. I think the the 2nd hardcoded NAS Attachment Class ended up being redundant as both Grenade Launchers and Rockets can use the same attachment class... well that's how I think I have things setup.
EDIT4: took a look at my XML's, sorry mixed up launcher and launchables. Also I seem to have the two separate, but I still think that is purely a notation thing. Still, one option is to sacrifice one attachment class for attachments that do not transfer attachments/make them visible on the main item's interface - and my money is on 2048 being the least disruptive.
EDIT5: or 33554432 (as it is the next bitmask one up from the last attachment class used in my projects, there's a limit but I don't remember what it is...)
EDIT6: the more I think about it, my idea to use hardcoded attachment classes to control whether an attachment transfers attachments and NAS slots to the primary item is a really bad idea, sorry. Better ideas:
1) simply have it when the attachment is a weapon item, no attachments and slots are added to the primary weapon. Question is whether to exclude launchers from this, as there are pro's and cons to having the launcher round(s) available in the primary weapon's information screen.
2) have a new tag in items.XML governing if an attachment will transfer attachment/add its attachment slots onto the main weapon (DepressiveBrot's idea)
Under both ideas, if you want access to the attachment's attachments and NAS slots, you have to open up the details screen for the attachment. This also avoids the ever present problem of NAS slot conflict: different layouts with different slots that happen to have the same coordinates. Just keep the layouts on different interface screens.
Sorry for the mess above.
[Updated on: Tue, 27 March 2012 23:11] by Moderator Report message to a moderator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #303136]
|
Tue, 10 April 2012 09:11
|
|
JMich |
|
Messages:546
Registered:January 2011 Location: Greece |
|
|
@Wil
Not sure how Flugente implemented it, since that was the point I gave up, but depending on what the bonus is, it should check either the Weapon in Hand (AR) or the Weapon Fired (Shotgun). So assuming we (or more importantly, Flugente, since I only skimmed that part) didn't miss any check, the bonuses should apply only to the weapons that they should apply to. For aiming levels, I think only the WiH should be counted, not the weapon fired, since when you are aiming a masterkey, you are actually aiming and shooting an AR.
Report message to a moderator
|
First Sergeant
|
|
|
Re: [WIP] Under Barrel Weapons[message #303280]
|
Wed, 11 April 2012 21:54
|
|
Flugente |
|
Messages:3507
Registered:April 2009 Location: Germany |
|
|
The bonus to the Ranger trait is applied for reloading, and chambering rounds. It is not giving aiming boni to _underbarrel_ shotguns, as the aiming is done via the main gun (it does in OCTH, my mistake, will correct that).
The ranger trait doesn't reduce the aiming levels.
[Updated on: Wed, 11 April 2012 22:34] by Moderator Report message to a moderator
|
|
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #305756]
|
Sat, 09 June 2012 00:55
|
|
Wil473 |
|
Messages:2815
Registered:September 2004 Location: Canada |
|
|
Finally gotten around to implementing the UnderBarrelWeapons, and ran into a bit of a problem, though it may have been fixed by now: Under Rev.5280 the underbarrel is not recognized as an available firing mode on single shot only weapons.
Background: I was taking a break from cleaning up the attachments, and decided to see if I could get the Neostead to have two "magazines" by using the UnderBarrelWeapons system. Made a copy of the NeoStead ("Dual Feed Magazine"), got it to appear as a default attachment, and couldn't figure out how to fire it. Spent half an hour comparing my XML's to Data-1.13 and didn't see any material differences between the Masterkey and the "Dual Feed." Finally broke down and started a stock v1.13 game with Raider, and noticed that the only difference is that his primary weapon had burst/autofire modes. Set my Neostead to have a 1 shot burst, and the 2nd barrel became available.
Now I'm still waiting for the SVN to download a copy of the latest code/XML's, but I'm wondering if this has been noticed before?
[Updated on: Sat, 09 June 2012 00:57] by Moderator Report message to a moderator
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #305757]
|
Sat, 09 June 2012 01:10
|
|
Flugente |
|
Messages:3507
Registered:April 2009 Location: Germany |
|
|
Never seen that behaviour... I'll check it.
Edit: found the problem. I'll send a fix to RoWa that repairs both SingleShot and Auto-only guns. Thx for spotting that!
[Updated on: Sat, 09 June 2012 01:36] by Moderator Report message to a moderator
|
|
|
|
|
|
|
|
|
Re: [WIP] Under Barrel Weapons[message #306166]
|
Tue, 19 June 2012 17:13
|
|
Wil473 |
|
Messages:2815
Registered:September 2004 Location: Canada |
|
|
Yeah, I vaguely knew there was a problem with reloading the UB weapon - just not the specifics, and I thought it was fixed. Is there anyway to disable the UB weapon's unload button? Right now it is quite an exploit to be able to magically produce magazines of shotgun shells.
Last night, I had time to produce the Cobra Titan Derringer and some test rounds for it - and looks like it will need to be shelved for now.
The Good:
- the game didn't CTD on transforming to variants with a different barrel
The Bad:
- the UB weapon's bullet, as expected, did not eject if the UB barrel changed calibres, and due to the bug the player does not have the option to unload the round
- the UB weapon seems to arrive loaded, (emptied both barrels, did a transform that changed the UB barrel and it appeared loaded)
EDIT: I won't be cutting it completely, I'll leave the five items in the XML as something to test future edits of the UB Weapon feature.
[Updated on: Tue, 19 June 2012 17:31] by Moderator Report message to a moderator
|
|
|
|
|
|
|
|
|
|
Goto Forum:
Current Time: Sat Nov 30 11:08:29 GMT+2 2024
Total time taken to generate the page: 0.02714 seconds
|