diff --git a/GameSettings.cpp b/GameSettings.cpp index 5d3362e1..4b9232de 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1025,6 +1025,11 @@ void LoadGameExternalOptions() // HEADROCK HAM B2.6/2/1: Toggle new Burst/Auto Targeting Cursors: 0=neither, 1=both, 2=Burst, 3=Auto gGameExternalOptions.ubNewCTHBars = iniReader.ReadInteger("Tactical Interface Settings","USE_NEW_BURST-AUTO_TARGETING_CURSORS", 0, 0, 3); + // sevenfm: default autofire bullets + gGameExternalOptions.ubSetDefaultAutofireBulletsSMG = iniReader.ReadInteger("Tactical Interface Settings","SET_DEFAULT_AUTOFIRE_BULLETS_SMG", 1, 0, 10); + gGameExternalOptions.ubSetDefaultAutofireBulletsAR = iniReader.ReadInteger("Tactical Interface Settings","SET_DEFAULT_AUTOFIRE_BULLETS_AR", 1, 0, 10); + gGameExternalOptions.ubSetDefaultAutofireBulletsMG = iniReader.ReadInteger("Tactical Interface Settings","SET_DEFAULT_AUTOFIRE_BULLETS_MG", 1, 0, 10); + // HEADROCK HAM B2.7: When turned on, this will give a CTH approximation instead of an exact value, on CTH Bars and "F" key feedback. gGameExternalOptions.fApproximateCTH = iniReader.ReadBoolean("Tactical Interface Settings","INACCURATE_CTH_READOUT", FALSE); diff --git a/GameSettings.h b/GameSettings.h index 5b813f4f..6b030855 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -932,6 +932,11 @@ typedef struct // HEADROCK HAM B2.6/2/1: Toggle new Burst/Auto CTH bars: 0=neither, 1=both, 2=Burst, 3=Auto UINT8 ubNewCTHBars; + // sevenfm: default autofire bullets + UINT8 ubSetDefaultAutofireBulletsSMG; + UINT8 ubSetDefaultAutofireBulletsAR; + UINT8 ubSetDefaultAutofireBulletsMG; + // CHRISL: Changed from a simple flag to two externalized values for more modder control over AI suppression UINT16 ubAISuppressionMinimumMagSize; UINT16 ubAISuppressionMinimumAmmo; diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index fbface33..8bbf2be8 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -115,7 +115,7 @@ void RemoveBlueFlagDialogueCallBack( UINT8 ubExitValue ); INT32 CheckBombDisarmChance(void); void ExtendedDisarmMessageBox(void); void ExtendedBoobyTrapMessageBoxCallBack( UINT8 ubExitValue ); -void HandleTakeNewBombFromIventory(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj); +void HandleTakeNewBombFromInventory(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj); void MineSpottedMessageBoxCallBack( UINT8 ubExitValue ); void CheckForPickedOwnership( void ); void BoobyTrapInMapScreenMessageBoxCallBack( UINT8 ubExitValue ); @@ -235,6 +235,12 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa // "attached weapon" pSoldier->usAttackingWeapon = usHandItem; + // sevenfm: set shift flag for auto-taking of next item from inventory + if( fFromUI && _KeyDown(SHIFT) ) + gfShiftBombPlant = TRUE; + else + gfShiftBombPlant = FALSE; + // Find soldier flags depend on if it's our own merc firing or a NPC //if ( FindSoldier( sGridNo, &usSoldierIndex, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) if ( ( usSoldierIndex = WhoIsThere2( sGridNo, bLevel ) ) != NOBODY ) @@ -1517,13 +1523,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa if ( fDropBomb ) { // Save gridno.... - pSoldier->aiData.sPendingActionData2 = sGridNo; - - // sevenfm: set shift flag for auto-taking of next mine from inventory (Improved Bomb Planting) - if( fFromUI && _KeyDown(SHIFT) ) - gfShiftBombPlant = TRUE; - else - gfShiftBombPlant = FALSE; + pSoldier->aiData.sPendingActionData2 = sGridNo; if ( pSoldier->sGridNo != sGridNo ) { @@ -1842,7 +1842,7 @@ void HandleSoldierDropBomb( SOLDIERTYPE *pSoldier, INT32 sGridNo ) { AddItemToPool( sGridNo, &gTempObject, BURIED, pSoldier->pathing.bLevel, WORLD_ITEM_ARMED_BOMB, 0 ); // sevenfm: take another item with same id from inventory, only REALTIME - HandleTakeNewBombFromIventory(pSoldier, &gTempObject); + HandleTakeNewBombFromInventory(pSoldier, &gTempObject); // sevenfm: change cursor back to action if successfully taken new bomb if ( gfShiftBombPlant && pSoldier->inv[ pSoldier->ubAttackingHand ].exists() ) guiPendingOverrideEvent = M_CHANGE_TO_ACTION; @@ -5123,7 +5123,7 @@ void BombMessageBoxCallBack( UINT8 ubExitValue ) AddItemToPool( gsTempGridNo, &gTempObject, BURIED, gpTempSoldier->pathing.bLevel, WORLD_ITEM_ARMED_BOMB, 0 ); // sevenfm: set flag only if planting tripwire gpWorldLevelData[ gsTempGridNo ].uiFlags |= MAPELEMENT_PLAYER_MINE_PRESENT; - HandleTakeNewBombFromIventory(gpTempSoldier, &gTempObject); + HandleTakeNewBombFromInventory(gpTempSoldier, &gTempObject); // sevenfm: change cursor back to action if successfully taken new bomb (also change mode back to action if using tripwire roll) if ( gfShiftBombPlant && gpTempSoldier->inv[ gpTempSoldier->ubAttackingHand ].exists() ) guiPendingOverrideEvent = M_CHANGE_TO_ACTION; @@ -7000,11 +7000,11 @@ void ExtendedBoobyTrapMessageBoxCallBack( UINT8 ubExitValue ) } } -void HandleTakeNewBombFromIventory(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj) +void HandleTakeNewBombFromInventory(SOLDIERTYPE* pSoldier, OBJECTTYPE* pObj) { if( !( (gTacticalStatus.uiFlags & TURNBASED ) && (gTacticalStatus.uiFlags & INCOMBAT) ) && !pSoldier->inv[HANDPOS].exists() && gfShiftBombPlant ) { - pSoldier->TakeNewBombFromIventory(pObj->usItem); + pSoldier->TakeNewBombFromInventory(pObj->usItem); } } diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index 30a5919a..0425809f 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -103,6 +103,7 @@ ////////////////////////////////////////////////////////////////////// //extern BOOLEAN gfDisplayFullCountRingBurst; +extern BOOLEAN gfAutofireInitBulletNum; extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); //#define AP_TO_AIM_TILE_IF_GETTING_READY 1 @@ -1846,6 +1847,9 @@ UINT32 UIHandleMChangeToAction( UI_EVENT *pUIEvent ) //guiNewUICursor = CONFIRM_MOVE_UICURSOR; + // sevenfm: this flag means that we'll need to initialize number of bullets for autofire + gfAutofireInitBulletNum = FALSE; + return( GAME_SCREEN ); } diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index 47ed0865..04328455 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -130,6 +130,9 @@ UINT16 usForceAnimState = INVALID_ANIMATION;//dnl ch70 170913 extern INT16 DirIncrementer[8]; +// sevenfm: used in auto taking concertina/sandbag items from inventory +extern BOOLEAN gfShiftBombPlant; + #define PALETTEFILENAME "BINARYDATA\\ja2pal.dat" #define LOW_MORALE_BATTLE_SND_THREASHOLD 35 @@ -16108,8 +16111,14 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction() // Build the thing if ( BuildFortification( this->sMTActionGridNo, Item[ pObj->usItem ].usItemFlag ) ) { + UINT16 usItem = pObj->usItem; // Erase 'material' item from our hand - we 'use' it to build the structure DeleteObj( &(this->inv[HANDPOS]) ); + // sevenfm: auto-taking of items + if( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) + { + TakeNewItemFromInventory( usItem ); + } // we gain a bit of experience... StatChange( this, STRAMT, 4, TRUE ); @@ -16141,13 +16150,23 @@ BOOLEAN SOLDIERTYPE::UpdateMultiTurnAction() { // eventually search for the number of a sandbag item if ( HasItemFlag(fullsandbagnr, FULL_SANDBAG) || GetFirstItemWithFlag(&fullsandbagnr, FULL_SANDBAG) ) - { - // Erase 'material' item from our hand - we 'used' it to build the structure + { INT8 bObjSlot = HANDPOS; + UINT16 usItem = pObj->usItem; CreateItem( fullsandbagnr, 100, &gTempObject ); - + if( !(gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) && gfShiftBombPlant ) + { // sevenfm: drop filled sandbag to the ground and take new empty from inventory + AddItemToPool( this->sGridNo, &gTempObject, 1, 0, 0, -1 ); + DeleteObj( &(this->inv[HANDPOS]) ); + TakeNewItemFromInventory( usItem ); + } + else + { SwapObjs( this, bObjSlot, &gTempObject, TRUE ); + } + // sevenfm: added this to correctly update interface + DirtyMercPanelInterface( this, DIRTYLEVEL2 ); // we gain a bit of experience... StatChange( this, STRAMT, 1, TRUE ); @@ -16250,7 +16269,7 @@ void SOLDIERTYPE::DropSectorEquipment() } // sevenfm: take item from inventory to HANDPOS -void SOLDIERTYPE::TakeNewBombFromIventory(UINT16 item) +void SOLDIERTYPE::TakeNewItemFromInventory(UINT16 usItem) { INT8 i; OBJECTTYPE* pObj = NULL; @@ -16258,6 +16277,10 @@ void SOLDIERTYPE::TakeNewBombFromIventory(UINT16 item) if ( !UsingNewInventorySystem() ) return; + + // this feature works now only in realtime + if( (gTacticalStatus.uiFlags & TURNBASED && gTacticalStatus.uiFlags & INCOMBAT) ) + return; if(this->inv[HANDPOS].exists()) return; @@ -16265,12 +16288,36 @@ void SOLDIERTYPE::TakeNewBombFromIventory(UINT16 item) // search for item with same id for ( i = 0; i < invsize; i++) { - if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == item ) ) + if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == usItem ) ) { this->inv[i].MoveThisObjectTo(this->inv[HANDPOS], 1, this); return; } } +} + +// sevenfm: take item from inventory to HANDPOS +void SOLDIERTYPE::TakeNewBombFromInventory(UINT16 usItem) +{ + INT8 i; + OBJECTTYPE* pObj = NULL; + INT8 invsize = (INT8)this->inv.size(); + + if ( !UsingNewInventorySystem() ) + return; + + if(this->inv[HANDPOS].exists()) + return; + + // search for item with same id + for ( i = 0; i < invsize; i++) + { + if ( ( this->inv[i].exists() == true ) && ( this->inv[i].usItem == usItem ) ) + { + this->inv[i].MoveThisObjectTo(this->inv[HANDPOS], 1, this); + return; + } + } // search for any item with class IC_BOMB // take tripwire-activated item only if used item is tripwire activated @@ -16280,8 +16327,8 @@ void SOLDIERTYPE::TakeNewBombFromIventory(UINT16 item) Item[ this->inv[i].usItem ].usItemClass == IC_BOMB && Item[ this->inv[i].usItem ].ubCursor == BOMBCURS && !Item[ this->inv[i].usItem ].tripwire && - ( ( Item[ this->inv[i].usItem ].tripwireactivation && Item[item].tripwireactivation ) || - ( !Item[ this->inv[i].usItem ].tripwireactivation && !Item[item].tripwireactivation ) ) ) + ( ( Item[ this->inv[i].usItem ].tripwireactivation && Item[usItem].tripwireactivation ) || + ( !Item[ this->inv[i].usItem ].tripwireactivation && !Item[usItem].tripwireactivation ) ) ) { this->inv[i].MoveThisObjectTo(this->inv[HANDPOS], 1, this); return; diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index 0859ea1c..c4742b45 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -1751,7 +1751,8 @@ public: void DropSectorEquipment(); // sevenfm: Take new bomb with id = usItem from iventory to HANDPOS - void TakeNewBombFromIventory(UINT16 usItem); + void TakeNewBombFromInventory(UINT16 usItem); + void TakeNewItemFromInventory(UINT16 usItem); // Flugente: switch hand item for gunsling weapon, or pistol, or knife void SwitchWeapons( BOOLEAN fKnife = FALSE, BOOLEAN fSideArm = FALSE ); diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 28640d55..5c88e252 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -60,10 +60,12 @@ UINT8 HandleApplyItemCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCurs extern BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel ); +UINT8 DefaultAutofireBulletsByGunClass( SOLDIERTYPE* pSoldier ); // added by Sevenfm BOOLEAN gfCannotGetThrough = FALSE; extern UINT32 guiUITargetSoldierId; BOOLEAN gfDisplayFullCountRing = FALSE; +BOOLEAN gfAutofireInitBulletNum = FALSE; UINT8 gubAimRingRanges[] = {30, 55, 75, 90}; // These are the cutoff ranges for the aiming rings extern INT8 gbNumBurstLocations; //number of burst points @@ -164,7 +166,6 @@ UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos sTargetGridNo = usMapPos; } - ubItemCursor = GetActionModeCursor( pSoldier ); switch( ubItemCursor ) @@ -393,12 +394,14 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA { DetermineCursorBodyLocation( (UINT8)gusSelectedSoldier, TRUE, TRUE ); } - + UINT8 ubMaxBullets = 1; + INT8 bMaxAim; if ( gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) ) { if(pSoldier->bDoAutofire) { - if(pSoldier->bDoAutofire == 1) //try to maximize the # of bullets because 1 may not be optimal + // sevenfm: change number of autofire bullets only once when switching cursor to action mode or changing firing mode + if( !gfAutofireInitBulletNum ) { INT16 sCurAPCosts, sAPCosts; UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; @@ -406,16 +409,27 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA { usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); } + bMaxAim = pSoldier->aiData.bShownAimTime; - sCurAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); + // sevenfm: change default number of bullets in autofire according to ini settings + ubMaxBullets = DefaultAutofireBulletsByGunClass( pSoldier ); + if( ubMaxBullets == 0 ) + { + ubMaxBullets = usShotsLeft; + bMaxAim = maxAimLevels; + } + + sCurAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bMaxAim); do { pSoldier->bDoAutofire++; - sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); - } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire); + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bMaxAim); + } // sevenfm: removed (sAPCosts <= sCurAPCosts) because EnoughPoints() is enough + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && usShotsLeft >= pSoldier->bDoAutofire && pSoldier->bDoAutofire <= ubMaxBullets ); pSoldier->bDoAutofire--; + + gfAutofireInitBulletNum = TRUE; } gfUIAutofireBulletCount = TRUE; @@ -1283,9 +1297,15 @@ UINT8 HandleNonActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos , BO if(gusUIFullTargetID == NOBODY && pSoldier->bDoAutofire && !pSoldier->flags.fDoSpread) //reset autofire if we move the mouse off the target, however don't reset it if we are spread-bursting { if(gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT )) + { pSoldier->bDoAutofire = 1; + // sevenfm: init autofire bullet num next time when the cursor will be on target + gfAutofireInitBulletNum = FALSE; + } else + { pSoldier->bDoAutofire = 6; + } pSoldier->flags.autofireLastStep = FALSE; } @@ -3605,7 +3625,6 @@ void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta } } -//обработка колеса без прицельной очереди if прицельная очередь отключена в .ини void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta ) { UINT16 usInHand; @@ -3798,4 +3817,42 @@ void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sD ErasePath( TRUE ); } +} + +UINT8 DefaultAutofireBulletsByGunClass( SOLDIERTYPE* pSoldier ) +{ + UINT32 usItemClass; + UINT16 usItem; + UINT8 ubBullets = 1; + + if( !pSoldier ) + return 1; + if( !pSoldier->inv[ pSoldier->ubAttackingHand ].exists() ) + return 1; + + usItem = pSoldier->inv[ pSoldier->ubAttackingHand ].usItem; + usItemClass = Item[ usItem ].usItemClass; + + if( usItemClass != IC_GUN ) + return 1; + + switch( Weapon[ Item[ usItem ].ubClassIndex ].ubWeaponType ) + { + case GUN_M_PISTOL: + case GUN_PISTOL: + case GUN_SMG: + ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsSMG; + break; + case GUN_AS_RIFLE: + case GUN_RIFLE: + case GUN_SN_RIFLE : + case GUN_SHOTGUN: + ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsAR; + break; + case GUN_LMG: + ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsMG; + break; + } + + return ubBullets; } \ No newline at end of file diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index 5fb3822d..31770e46 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -65,6 +65,9 @@ class SOLDIERTYPE; extern INT8 gbCurrentRainIntensity; //end rain +// sevenfm: this global variable is needed to correctly set default number of bullets for autofire +extern BOOLEAN gfAutofireInitBulletNum; + extern SECTOR_EXT_DATA SectorExternalData[256][4]; // added by Flugente // HEADROCK HAM B1: Externalized both values to INI @@ -11674,6 +11677,9 @@ void ChangeWeaponMode( SOLDIERTYPE * pSoldier ) if (pSoldier->bWeaponMode == WM_AUTOFIRE || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO || pSoldier->bWeaponMode == WM_ATTACHED_UB_AUTO) { + // sevenfm: this flag means that we'll need to initialize number of bullets for autofire + gfAutofireInitBulletNum = FALSE; + pSoldier->bDoAutofire = 1; pSoldier->bDoBurst = 1; }