diff --git a/GameSettings.cpp b/GameSettings.cpp index 107df5337..03b86c15e 100644 --- a/GameSettings.cpp +++ b/GameSettings.cpp @@ -1119,6 +1119,19 @@ void LoadGameExternalOptions() gGameExternalOptions.fAllowWalkingWithWeaponRaised = iniReader.ReadBoolean("Tactical Gameplay Settings","ALLOW_WALKING_WITH_WEAPON_RAISED", TRUE); + // SANDRO - Alternative weapon holding (rifles fired from hip / pistols fired one-handed) + gGameExternalOptions.ubAllowAlternativeWeaponHolding = iniReader.ReadInteger("Tactical Gameplay Settings","ALLOW_ALTERNATIVE_WEAPON_HOLDING", 3, 0, 3); + gGameExternalOptions.ubToAltWeaponHoldReadyAPsPerc = iniReader.ReadInteger("Tactical Gameplay Settings","RAISE_TO_ALTWEAPHOLD_READY_APS_PERC", 25, 0, 100); + gGameExternalOptions.ubFromAltWeaponHoldReadyAPsPerc = iniReader.ReadInteger("Tactical Gameplay Settings","RAISE_FROM_ALTWEAPHOLD_READY_APS_PERCENTAGE", 75, 0, 100); + gGameExternalOptions.ubAltWeaponHoldingFireSpeedBonus = iniReader.ReadInteger("Tactical Gameplay Settings","FASTER_SHOT_FROM_ALTWEAPHOLD_PERC", 10, 0, 90); + gGameExternalOptions.ubAltWeaponHoldingCtHPenaly = iniReader.ReadInteger("Tactical Gameplay Settings","CTH_PENALTY_FROM_ALTWEAPHOLD", 30, 0, 90); + gGameExternalOptions.ubAltWeaponHoldingAimingPenaly = iniReader.ReadInteger("Tactical Gameplay Settings","AIMING_PENALY_FROM_ALTWEAPHOLD", 30, 0, 90); + gGameExternalOptions.ubAltWeaponHoldingAimLevelsReduced = iniReader.ReadInteger("Tactical Gameplay Settings","AIMING_LEVELS_REDUCTION_ON_ALTWEAPHOLD", 50, 0, 90); + + // Sandro: Energy cost on weapon manipulation + gGameExternalOptions.ubEnergyCostForWeaponWeight = iniReader.ReadInteger("Tactical Gameplay Settings","ENERGY_COST_FOR_WEAPON_WEIGHT", 100, 0, 250); + gGameExternalOptions.ubEnergyCostForWeaponRecoilKick = iniReader.ReadInteger("Tactical Gameplay Settings","ENERGY_COST_FOR_WEAPON_RECOIL_KICK", 100, 0, 250); + gGameExternalOptions.fWeaponResting = iniReader.ReadBoolean("Tactical Gameplay Settings","WEAPON_RESTING",TRUE); gGameExternalOptions.fDisplayWeaponRestingIndicator = iniReader.ReadBoolean("Tactical Gameplay Settings","WEAPON_RESTING_DISPLAY",TRUE); gGameExternalOptions.ubProneModifierPercentage = iniReader.ReadInteger("Tactical Gameplay Settings","WEAPON_RESTING_PRONE_BONI_PERCENTAGE", 50, 0, 100); @@ -1279,6 +1292,8 @@ void LoadGameExternalOptions() gGameExternalOptions.fAllowCollectiveInterrupts = iniReader.ReadBoolean("Tactical Gameplay Settings", "ALLOW_COLLECTIVE_INTERRUPTS", TRUE); gGameExternalOptions.fAllowInstantInterruptsOnSight = iniReader.ReadBoolean("Tactical Gameplay Settings", "ALLOW_INSTANT_INTERRUPTS_ON_SPOTTING", FALSE); + gGameExternalOptions.fNoEnemyAutoReadyWeapon = iniReader.ReadInteger("Tactical Gameplay Settings", "NO_ENEMY_AUTOMATIC_WEAPON_READYING", 1, 0, 2); + //################# Tactical Cover System Settings ################## // CPT: Cover System Settings @@ -1989,7 +2004,7 @@ void LoadSkillTraitsExternalSettings() gSkillTraitValues.ubMAAPsChangeStanceReduction = iniReader.ReadInteger("Martial Arts","APS_CHANGE_STANCE_REDUCTION", 25, 0, 100); gSkillTraitValues.ubMAApsTurnAroundReduction = iniReader.ReadInteger("Martial Arts","APS_TURN_AROUND_REDUCTION", 25, 0, 100); gSkillTraitValues.ubMAAPsClimbOrJumpReduction = iniReader.ReadInteger("Martial Arts","APS_CLIMB_OR_JUMP_REDUCTION", 25, 0, 100); - gSkillTraitValues.ubMAReducedAPsRegisteredWhenMoving = iniReader.ReadInteger("Martial Arts","REDUCED_CHANCE_TO_BE_INTERRUPTED_WHEN_MOVING", 35, 0, 100); + gSkillTraitValues.ubMAReducedAPsRegisteredWhenMoving = iniReader.ReadInteger("Martial Arts","REDUCED_CHANCE_TO_BE_INTERRUPTED_WHEN_CHARGING_IN", 40, 0, 100); gSkillTraitValues.ubMAChanceToCkickDoors = iniReader.ReadInteger("Martial Arts","CHANCE_KICK_DOORS_BONUS", 25, 0, 250); gSkillTraitValues.fPermitExtraAnimationsOnlyToMA = iniReader.ReadBoolean("Martial Arts","PERMIT_EXTRA_ANIMATIONS_TO_EXPERT_MARTIAL_ARTS_ONLY", TRUE); @@ -2081,7 +2096,7 @@ void LoadSkillTraitsExternalSettings() gSkillTraitValues.ubSTStealthModeSpeedBonus = iniReader.ReadInteger("Stealthy","STEALTH_MODE_SPEED_BONUS", 50, 0, 100); gSkillTraitValues.ubSTBonusToMoveQuietly = iniReader.ReadInteger("Stealthy","BONUS_TO_MOVE_STEALTHILY", 40, 0, 250); gSkillTraitValues.ubSTStealthBonus = iniReader.ReadInteger("Stealthy","STEALTH_BONUS", 25, 0, 200); - gSkillTraitValues.ubSTReducedAPsRegistered = iniReader.ReadInteger("Stealthy","REDUCED_CHANCE_TO_BE_INTERRUPTED", 30, 0, 100); + gSkillTraitValues.ubSTReducedAPsRegistered = iniReader.ReadInteger("Stealthy","REDUCED_CHANCE_TO_BE_INTERRUPTED", 20, 0, 100); gSkillTraitValues.ubSTStealthPenaltyForMovingReduction = iniReader.ReadInteger("Stealthy","CHANCE_TO_BE_SPOTTED_FOR_MOVING_REDUCTION", 25, 0, 100); // ATHLETICS diff --git a/GameSettings.h b/GameSettings.h index 0f37420dc..549413048 100644 --- a/GameSettings.h +++ b/GameSettings.h @@ -352,6 +352,8 @@ typedef struct BOOLEAN fAllowCollectiveInterrupts; BOOLEAN fAllowInstantInterruptsOnSight; + BOOLEAN fNoEnemyAutoReadyWeapon; + UINT16 usAwardSpecialExpForQuests; BOOLEAN fAllowWalkingWithWeaponRaised; @@ -1141,6 +1143,19 @@ typedef struct // Flugente: External Feeding UINT8 ubExternalFeeding; // allow external feeding of guns (0 = no, 1 = only for others, 2 = we can also fed ourselves) + // Sandro: Alternative weapon holding (rifles fired from hip / pistols fired one-handed) + UINT8 ubAllowAlternativeWeaponHolding; + UINT8 ubToAltWeaponHoldReadyAPsPerc; + UINT8 ubFromAltWeaponHoldReadyAPsPerc; + UINT8 ubAltWeaponHoldingFireSpeedBonus; + UINT8 ubAltWeaponHoldingCtHPenaly; + UINT8 ubAltWeaponHoldingAimingPenaly; + UINT8 ubAltWeaponHoldingAimLevelsReduced; + + // Sandro: Energy cost on weapon manipulation + UINT8 ubEnergyCostForWeaponWeight; + UINT8 ubEnergyCostForWeaponRecoilKick; + BOOLEAN gBriefingRoom; BOOLEAN gEncyclopedia; diff --git a/GameVersion.h b/GameVersion.h index 05edfcfa9..c01e04a0a 100644 --- a/GameVersion.h +++ b/GameVersion.h @@ -20,9 +20,10 @@ extern CHAR16 zTrackingNumber[16]; // // Keeps track of the saved game version. Increment the saved game version whenever // you will invalidate the saved game file -#define SAVE_GAME_VERSION 134 // 133 // 132 //131 //125 //124 //114 //113 //112 //111 //110 //109 //108 //107 //106 //105 //104 //103 //102 //101 //100 // 99 +#define SAVE_GAME_VERSION 135 // 134 // 133 // 132 //131 //125 //124 //114 //113 //112 //111 //110 //109 //108 //107 //106 //105 //104 //103 //102 //101 //100 // 99 -#define MORE_ROOMS 134 // changed room numbers from 8 to 16 bit by DBrot +#define DUAL_BURST_ADDED 135 +#define MORE_ROOMS 134 // changed room numbers from 8 to 16 bit by DBrot #define FOOD_CHANGES 133 // changes for food system #define ZOMBIE_CHANGES 132 // Included some changes for Zombies #define JA25_UB_INTEGRATION 131 // Before this, the JA25 Unfinished Business code was not integrated (see "Builddefines.h" JA2UB) diff --git a/Laptop/IMP Skill Trait.cpp b/Laptop/IMP Skill Trait.cpp index e4573b7a5..13eecbf57 100644 --- a/Laptop/IMP Skill Trait.cpp +++ b/Laptop/IMP Skill Trait.cpp @@ -1925,11 +1925,20 @@ void AssignSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLevel ) } if( gSkillTraitValues.ubSNAimClicksAdded != 0 ) { - if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel) - swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + if( UsingNewCTHSystem() == true ) + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[17]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[18], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + } else - swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); - + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + } wcscat( apStr, atStr ); } break; diff --git a/Laptop/personnel.cpp b/Laptop/personnel.cpp index 7df733812..0de7a775e 100644 --- a/Laptop/personnel.cpp +++ b/Laptop/personnel.cpp @@ -7182,11 +7182,20 @@ void AssignPersonnelSkillTraitHelpText( UINT8 ubTraitNumber, BOOLEAN fExpertLeve } if( gSkillTraitValues.ubSNAimClicksAdded != 0 ) { - if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel ) - swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + if( UsingNewCTHSystem() == true ) + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[17]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[18], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + } else - swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); - + { + if( gSkillTraitValues.ubSNAimClicksAdded == 1 && !fExpertLevel ) + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[15]); + else + swprintf( atStr, gzIMPMajorTraitsHelpTextsSniper[16], ( gSkillTraitValues.ubSNAimClicksAdded * (fExpertLevel ? 2 : 1))); + } wcscat( apStr, atStr ); } break; diff --git a/SaveLoadGame.cpp b/SaveLoadGame.cpp index de46ab585..01ff3440e 100644 --- a/SaveLoadGame.cpp +++ b/SaveLoadGame.cpp @@ -1750,6 +1750,14 @@ BOOLEAN SOLDIERTYPE::Load(HWFILE hFile) buffer += sizeof(FLOAT); buffer += sizeof(FLOAT); } + // SANDRO: my attempt at making older save games compatible (usually fails, dunno why) + // with dual bursts, dPrevMuzzleOffsetX,dPrevMuzzleOffsetY,dPrevCounterForceX,dPrevCounterForceY was made dPrevMuzzleOffsetX[2], etc. + if(guiCurrentSaveGameVersion < DUAL_BURST_ADDED) { + buffer += sizeof(FLOAT); + buffer += sizeof(FLOAT); + buffer += sizeof(FLOAT); + buffer += sizeof(FLOAT); + } if(guiCurrentSaveGameVersion >= NCTH_AUTOFIRE_UPDATE){ numBytesRead = ReadFieldByField(hFile, &this->dInitialMuzzleOffsetX, sizeof(dInitialMuzzleOffsetX), sizeof(FLOAT), numBytesRead); numBytesRead = ReadFieldByField(hFile, &this->dInitialMuzzleOffsetY, sizeof(dInitialMuzzleOffsetY), sizeof(FLOAT), numBytesRead); diff --git a/Strategic/Map Screen Interface Map Inventory.cpp b/Strategic/Map Screen Interface Map Inventory.cpp index 8a30f2fb9..33b82a2ac 100644 --- a/Strategic/Map Screen Interface Map Inventory.cpp +++ b/Strategic/Map Screen Interface Map Inventory.cpp @@ -1217,7 +1217,7 @@ void MapInvenPoolSlots(MOUSE_REGION * pRegion, INT32 iReason ) } else { - if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[twItem->object.usItem].usItemClass == IC_GUN && !(Item[twItem->object.usItem].singleshotrocketlauncher)) + if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[twItem->object.usItem].usItemClass == IC_GUN && (twItem->object)[0]->data.gun.ubGunShotsLeft && !(Item[twItem->object.usItem].singleshotrocketlauncher)) { EmptyWeaponMagazine( &twItem->object, &gItemPointer ); InternalMAPBeginItemPointer( MercPtrs[gCharactersList[bSelectedInfoChar].usSolID] ); diff --git a/Strategic/mapscreen.cpp b/Strategic/mapscreen.cpp index baef233c4..981000bfc 100644 --- a/Strategic/mapscreen.cpp +++ b/Strategic/mapscreen.cpp @@ -9741,9 +9741,9 @@ void MAPInvClickCallback( MOUSE_REGION *pRegion, INT32 iReason ) { if ( !InItemDescriptionBox( ) ) { - if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[pSoldier->inv[ uiHandPos ].usItem].usItemClass == IC_GUN && !(Item[pSoldier->inv[ uiHandPos ].usItem].singleshotrocketlauncher) ) + if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[pSoldier->inv[ uiHandPos ].usItem].usItemClass == IC_GUN && (pSoldier->inv[ uiHandPos ])[uiHandPos]->data.gun.ubGunShotsLeft > 0 && !(Item[pSoldier->inv[ uiHandPos ].usItem].singleshotrocketlauncher) ) { - EmptyWeaponMagazine( &(pSoldier->inv[ uiHandPos ]), &gItemPointer ); + EmptyWeaponMagazine( &(pSoldier->inv[ uiHandPos ]), &gItemPointer, uiHandPos ); InternalMAPBeginItemPointer( pSoldier ); } else diff --git a/Tactical/Animation Control.cpp b/Tactical/Animation Control.cpp index 243d28e40..cb40d8952 100644 --- a/Tactical/Animation Control.cpp +++ b/Tactical/Animation Control.cpp @@ -19,6 +19,7 @@ #include "points.h" #include "Debug Control.h" #include "Random.h" +#include "Soldier Control.h" #endif #include "connect.h" @@ -74,8 +75,29 @@ static UINT16 THROW_KNIFE_SP_BM_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,1,1 static UINT16 PRONE_START_FIRST_AID_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,442,1033,0,0,0,0 }; static UINT16 PRONE_GIVE_FIRST_AID_AnimationScript[MAX_FRAMES_PER_ANIM] = { 4,5,6,7,6,5,4,3,4,5,6,6,5,7,6,5,4,3,4,5,5,6,7,6,7,6,5,7,6,5,4,3,2,3,2,4,501,0,0,0,0 }; +static UINT16 DUAL_BURST_ST_CR_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,459,441,448,430,17,477,458,441,448,430,21,19,24,477,1101,449,753,473,1102,999,0,0,0,0 }; +static UINT16 DUAL_BURST_PRONE_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,4,459,441,448,430,5,477,458,441,448,430,9,7,11,477,1101,449,753,473,1102,999,0,0,0,0 }; +//static UINT16 SHOOT_ALTERNATIVE_STAND_LOW_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,3,4,470,441,430,5,6,477,7,8,4,3,753,473,612,999,0,0,0,0 }; +//static UINT16 BURST_ALTERNATIVE_STAND_LOW_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,3,4,441,448,430,5,4,477,441,448,430,5,4,477,441,448,430,5,4,477,441,448,430,5,4,477,441,448,430,5,4,477,441,448,430,5,6,7,477,8,4,3,449,753,473,612,999,0,0,0,0 }; +static UINT16 START_COWER_CROUCHED_AnimationScript[MAX_FRAMES_PER_ANIM] = { 4,5,442,922,999,0,0,0,0 }; +static UINT16 END_COWER_CROUCHED_AnimationScript[MAX_FRAMES_PER_ANIM] = { 5,4,442,499,999,0,0,0,0 }; +static UINT16 START_COWER_PRONE_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,442,1054,999,0,0,0,0 }; +static UINT16 COWER_PRONE_AnimationScript[MAX_FRAMES_PER_ANIM] = { 5,6,7,8,9,10,9,8,5,4,5,6,501,999,0,0,0,0 }; +static UINT16 END_COWER_PRONE_AnimationScript[MAX_FRAMES_PER_ANIM] = { 4,3,2,1,442,499,999,0,0,0,0 }; + +static UINT16 F_IDLE_ANIM_KICKSN_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,601,0,0,0,0 }; +static UINT16 F_IDLE_ANIM_LOOK_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,13,12,11,10,9,8,7,6,5,4,3,2,1,601,0,0,0,0 }; +static UINT16 NINJA_SPINKICK_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,727,492,32,33,34,430,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,753,442,468,999,0,0,0,0 }; + +static UINT16 FOCUSED_PUNCH_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,12,12,12,12,13,13,14,14,727,492,15,16,17,430,18,19,19,19,19,20,20,20,20,21,21,21,22,22,22,23,23,23,24,24,24,753,442,468,999,0,0,0,0 }; +static UINT16 FOCUSED_STAB_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,5,5,5,6,6,7,727,492,8,9,430,10,10,10,10,11,11,11,11,12,12,12,13,13,13,14,14,14,442,912,499,0,0,0,0 }; +static UINT16 HTH_KICK_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,1,2,3,4,5,6,7,727,492,8,9,10,430,11,11,12,13,14,15,16,17,18,19,442,468,999,0,0,0,0 }; +static UINT16 FOCUSED_HTH_KICK_AnimationScript[MAX_FRAMES_PER_ANIM] = { 757,1,1,1,2,2,2,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,7,7,7,7,7,727,492,8,8,9,10,430,10,10,11,11,11,11,12,12,12,13,13,13,14,14,14,15,15,16,16,17,17,18,18,19,19,442,468,999,0,0,0,0 }; + +//static UINT16 LONG_JUMP_AnimationScript[MAX_FRAMES_PER_ANIM] = { 1,2,3,703,4,5,6,6,7,8,9,10,11,704,12,13,14,501,999,0,0,0,0 }; +static UINT16 LONG_JUMP_AnimationScript[MAX_FRAMES_PER_ANIM] = { 2,703,3,4,5,6,6,7,7,8,704,9,501,999,0,0,0,0 }; ANI_SPEED_DEF gubAnimCrawlSpeeds[ TOTALBODYTYPES ]; //Block for anim file @@ -410,10 +432,10 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = {"NOT USED 1" , 20, 20, (FLOAT)0.9, ANIM_MOVING | ANIM_TURNING | ANIM_NORESTART | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, // BIG GUY FLEX - {"BIG GUY FLEX" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"BIG GUY FLEX" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, // BIG GUY STRECH - {"BIG GUY STRECH" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"BIG GUY STRECH" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, // BIG GUY SOEDUST {"BIG GUY SHOE DUST" , 0, 90, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, @@ -464,15 +486,15 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = {"FEM CLEAN" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, - {"FEM KICKSN" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"FEM KICKSN" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, {"FEM LOOK" , 0, 180, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, - {"FEM WIPE" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"FEM WIPE" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, - {"REG SQUISH" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"REG SQUISH" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, - {"REG PULL" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"REG PULL" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_LOWER_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, {"REG SPIT" , 0, 130, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, @@ -704,13 +726,13 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = "Use Remote" , 0, 80, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_FIREREADY | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NONINTERRUPT, ANIM_STAND, ANIM_STAND, -1, //COWER - "START Cower" , 0, 80, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_FIREREADY | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NONINTERRUPT | ANIM_IGNORE_AUTOSTANCE, ANIM_STAND, ANIM_CROUCH, -1, + "START Cower" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NONINTERRUPT | ANIM_IGNORE_AUTOSTANCE, ANIM_STAND, ANIM_CROUCH, -1, //COWER - "Cowering" , 0, 80, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_FIREREADY | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_IGNORE_AUTOSTANCE , ANIM_CROUCH, ANIM_CROUCH, -1, + "Cowering" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON , ANIM_CROUCH, ANIM_CROUCH, -1, //END COWER - "End Cower" , 0, 80, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_FIREREADY | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_IGNORE_AUTOSTANCE, ANIM_CROUCH, ANIM_STAND, -1, + "End Cower" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_IGNORE_AUTOSTANCE, ANIM_CROUCH, ANIM_STAND, -1, //STEAL ITEM "STEAL ITEM" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LOWER_WEAPON | ANIM_LIGHT_EFFORT | ANIM_ATTACK , ANIM_STAND, ANIM_STAND, -1, @@ -999,12 +1021,10 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = {"RUN WITH PISTOL" , 0, 0, (FLOAT)2.6, ANIM_MOVING | ANIM_TURNING | ANIM_NORESTART | ANIM_RAISE_WEAPON | ANIM_MODERATE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, //SIDE STEPPING WITH READIED WEAPON - "SIDE STEPPING WITH PISTOL RDY" , 0, 50, (FLOAT)0.4, ANIM_MOVING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1, "SIDE STEPPING WITH RIFLE RDY" , 0, 50, (FLOAT)0.4, ANIM_MOVING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1, "SIDE STEPPING WITH DUAL RDY" , 0, 50, (FLOAT)0.4, ANIM_MOVING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1, //WALKING WITH READIED WEAPON - {"WALKING WITH PISTOL RDY" , 20, 0, (FLOAT)1.6, ANIM_MOVING | ANIM_TURNING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, {"WALKING WITH RIFLE RDY" , 20, 0, (FLOAT)1.6, ANIM_MOVING | ANIM_TURNING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, {"WALKING WITH DUAL RDY" , 20, 0, (FLOAT)1.6, ANIM_MOVING | ANIM_TURNING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, @@ -1018,6 +1038,47 @@ ANIMCONTROLTYPE gAnimControl[ NUMANIMATIONSTATES ] = //STEAL ITEM CROUCHED "STEAL ITEM CROUCHED" , 0, 100, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LOWER_WEAPON | ANIM_LIGHT_EFFORT, ANIM_CROUCH, ANIM_CROUCH, -1, + // STAND BURST DUAL + {"STAND BURST DUAL" , 0, 0, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + // CROUCH BURST DUAL + {"CROUCH BURST DUAL" , 0, 0, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_ATTACK, ANIM_CROUCH, ANIM_CROUCH, -1}, + // PRONE BURST DUAL + {"PRONE BURST DUAL" , 0, 0, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_ATTACK, ANIM_PRONE, ANIM_PRONE, -1}, + + // firing from hip animations + {"ALTERNATIVE READY" , 0, 100, (FLOAT)0, ANIM_OK_CHARGE_AP_FOR_TURN | ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_FASTTURN | ANIM_RAISE_WEAPON | ANIM_MIN_EFFORT , ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE AIM" , 0, 250, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_FIREREADY | ANIM_FASTTURN | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE SHOOT" , 0, 100, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_RT_NONINTERRUPT | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE BURST" , 0, 0, (FLOAT)0, ANIM_NORESTART | ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_FIRE | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE LOW" , 0, 100, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE LOW BURST" , 0, 0, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_RAISE_WEAPON | ANIM_LIGHT_EFFORT | ANIM_FIRE | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE UNREADY" , 0, 80, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_RAISE_WEAPON | ANIM_NOCHANGE_PENDINGCOUNT | ANIM_MIN_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE UNJAM" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_FASTTURN | ANIM_NOCHANGE_WEAPON | ANIM_MIN_EFFORT | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE LOW UNJAM" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_FASTTURN | ANIM_NOCHANGE_WEAPON | ANIM_MIN_EFFORT | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE WALKING" , 20, 0, (FLOAT)1.6, ANIM_MOVING | ANIM_TURNING | ANIM_ALT_WEAPON_HOLDING | ANIM_NORESTART | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + {"ALTERNATIVE SIDE STEP" , 0, 50, (FLOAT)0.4, ANIM_MOVING | ANIM_NORESTART | ANIM_ALT_WEAPON_HOLDING | ANIM_FIREREADY | ANIM_RAISE_WEAPON | ANIM_VARIABLE_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + + //COWER CROUCHED + {"COWER CROUCHED" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NONINTERRUPT, ANIM_CROUCH, ANIM_CROUCH, -1}, + //END COWER CROUCHED + {"END COWER CROUCHED" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_LIGHT_EFFORT | ANIM_NOCHANGE_WEAPON, ANIM_CROUCH, ANIM_CROUCH, -1}, + //COWER PRONE + {"START COWER PRONE" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_MIN_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NONINTERRUPT, ANIM_PRONE, ANIM_PRONE, -1}, + //COWER PRONE + {"COWER PRONE" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_MIN_EFFORT | ANIM_NOCHANGE_WEAPON, ANIM_PRONE, ANIM_PRONE, -1}, + //END COWER PRONE + {"End COWER PRONE" , 0, 150, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_FASTTURN | ANIM_NORESTART | ANIM_MIN_EFFORT | ANIM_NOCHANGE_WEAPON, ANIM_PRONE, ANIM_PRONE, -1}, + + {"BIGMERC IDLE NECK 2" , 0, 110, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_MERCIDLE | ANIM_NOCHANGE_WEAPON | ANIM_NO_EFFORT, ANIM_STAND, ANIM_STAND, -1}, + + {"FOCUSED PUNCH" , 0, 40, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_NONINTERRUPT | ANIM_MODERATE_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NORESTART | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"FOCUSED STAB" , 0, 40, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_NONINTERRUPT | ANIM_MODERATE_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NORESTART | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"HTH KICK" , 0, 70, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_NONINTERRUPT | ANIM_MODERATE_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NORESTART | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + {"FOCUSED HTH KICK" , 0, 40, (FLOAT)0, ANIM_STATIONARY | ANIM_TURNING | ANIM_NONINTERRUPT | ANIM_MODERATE_EFFORT | ANIM_NOCHANGE_WEAPON | ANIM_NORESTART | ANIM_ATTACK, ANIM_STAND, ANIM_STAND, -1}, + + // LONG JUMP + "LONG JUMP" , 0, 100, (FLOAT)3.4, ANIM_SPECIALMOVE | ANIM_NORESTART | ANIM_LOWER_WEAPON | ANIM_MODERATE_EFFORT | ANIM_TURNING, ANIM_STAND, ANIM_STAND, -1, + }; ANI_SPEED_DEF gubAnimWalkSpeeds[ TOTALBODYTYPES ] = @@ -1419,12 +1480,10 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ REGMALE ][ JUMPWINDOWS ] = RGMJUMPWINDOWS; - gubAnimSurfaceIndex[ REGMALE ][ SIDE_STEP_PISTOL_RDY ] = RGMSIDESTEP_P_RDY; - gubAnimSurfaceIndex[ REGMALE ][ SIDE_STEP_RIFLE_RDY ] = RGMSIDESTEP_R_RDY; + gubAnimSurfaceIndex[ REGMALE ][ SIDE_STEP_WEAPON_RDY ] = RGMSIDESTEP_R_RDY; gubAnimSurfaceIndex[ REGMALE ][ SIDE_STEP_DUAL_RDY ] = RGMSIDESTEP_D_RDY; - gubAnimSurfaceIndex[ REGMALE ][ WALKING_PISTOL_RDY ] = RGMWALK_P_RDY; - gubAnimSurfaceIndex[ REGMALE ][ WALKING_RIFLE_RDY ] = RGMWALK_R_RDY; + gubAnimSurfaceIndex[ REGMALE ][ WALKING_WEAPON_RDY ] = RGMWALK_R_RDY; gubAnimSurfaceIndex[ REGMALE ][ WALKING_DUAL_RDY ] = RGMWALK_D_RDY; gubAnimSurfaceIndex[ REGMALE ][ START_AID_PRN ] = RGMMEDICPRN; @@ -1433,6 +1492,35 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ REGMALE ][ ADJACENT_GET_ITEM_CROUCHED ] = RGMMEDIC; gubAnimSurfaceIndex[ REGMALE ][ STEAL_ITEM_CROUCHED ] = RGMMEDIC; + + gubAnimSurfaceIndex[ REGMALE ][ BURST_DUAL_STAND ] = RGMSTANDDWALAIM; + gubAnimSurfaceIndex[ REGMALE ][ BURST_DUAL_CROUCH ] = RGMCDBLSHOT; + gubAnimSurfaceIndex[ REGMALE ][ BURST_DUAL_PRONE ] = RGMDWPRONE; + + gubAnimSurfaceIndex[ REGMALE ][ READY_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ AIM_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ BURST_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ REGMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ REGMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ REGMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ REGMALE ][ WALKING_ALTERNATIVE_RDY ] = RGMBASICWALKING; + gubAnimSurfaceIndex[ REGMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGMSIDESTEP; + + gubAnimSurfaceIndex[ REGMALE ][ START_COWER_CROUCHED ] = RGMCOWER; + gubAnimSurfaceIndex[ REGMALE ][ END_COWER_CROUCHED ] = RGMCOWER; + gubAnimSurfaceIndex[ REGMALE ][ START_COWER_PRONE ] = RGM_COWER_PRONE; + gubAnimSurfaceIndex[ REGMALE ][ COWERING_PRONE ] = RGM_COWER_PRONE; + gubAnimSurfaceIndex[ REGMALE ][ END_COWER_PRONE ] = RGM_COWER_PRONE; + + gubAnimSurfaceIndex[ REGMALE ][ FOCUSED_PUNCH ] = RGMPUNCH; + gubAnimSurfaceIndex[ REGMALE ][ FOCUSED_STAB ] = RGMSTAB; + gubAnimSurfaceIndex[ REGMALE ][ HTH_KICK ] = RGMKICKDOOR; + gubAnimSurfaceIndex[ REGMALE ][ FOCUSED_HTH_KICK ] = RGMKICKDOOR; + + gubAnimSurfaceIndex[ REGMALE ][ LONG_JUMP ] = RGMJUMPOVER; gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ STANDING][0] = RGMWATER_R_STD; gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ WALKING ][0] = RGMWATER_R_WALK; @@ -1462,47 +1550,53 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ THROW_ITEM ][1] = RGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ LOB_ITEM ][0] = RGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ LOB_ITEM ][1] = RGMWATERTHROW; - + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ BURST_DUAL_STAND ][1] = RGMWATER_DBLSHT; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ READY_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ AIM_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ SHOOT_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ BURST_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ UNREADY_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGMALE ][ UNJAM_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; //Setup some random stuff gRandomAnimDefs[ REGMALE ][ 0 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ REGMALE ][ 0 ].sAnimID = REG_SPIT; gRandomAnimDefs[ REGMALE ][ 0 ].ubStartRoll = 0; - gRandomAnimDefs[ REGMALE ][ 0 ].ubEndRoll = 3; + gRandomAnimDefs[ REGMALE ][ 0 ].ubEndRoll = 9; gRandomAnimDefs[ REGMALE ][ 0 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ REGMALE ][ 0 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGMALE ][ 1 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ REGMALE ][ 1 ].sAnimID = REG_SQUISH; gRandomAnimDefs[ REGMALE ][ 1 ].ubStartRoll = 10; - gRandomAnimDefs[ REGMALE ][ 1 ].ubEndRoll = 13; + gRandomAnimDefs[ REGMALE ][ 1 ].ubEndRoll = 19; gRandomAnimDefs[ REGMALE ][ 1 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ REGMALE ][ 1 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGMALE ][ 2 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ REGMALE ][ 2 ].sAnimID = FEM_LOOK; - gRandomAnimDefs[ REGMALE ][ 2 ].ubStartRoll = 20; - gRandomAnimDefs[ REGMALE ][ 2 ].ubEndRoll = 23; - gRandomAnimDefs[ REGMALE ][ 2 ].ubFlags = 0; + gRandomAnimDefs[ REGMALE ][ 2 ].ubStartRoll = 10; + gRandomAnimDefs[ REGMALE ][ 2 ].ubEndRoll = 29; + gRandomAnimDefs[ REGMALE ][ 2 ].ubFlags = RANDOM_ANIM_LOOKAROUND; gRandomAnimDefs[ REGMALE ][ 2 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGMALE ][ 3 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ REGMALE ][ 3 ].sAnimID = REG_PULL; gRandomAnimDefs[ REGMALE ][ 3 ].ubStartRoll = 30; - gRandomAnimDefs[ REGMALE ][ 3 ].ubEndRoll = 33; + gRandomAnimDefs[ REGMALE ][ 3 ].ubEndRoll = 39; gRandomAnimDefs[ REGMALE ][ 3 ].ubFlags = 0; gRandomAnimDefs[ REGMALE ][ 3 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGMALE ][ 4 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; gRandomAnimDefs[ REGMALE ][ 4 ].sAnimID = MERC_HURT_IDLE_ANIM; - gRandomAnimDefs[ REGMALE ][ 4 ].ubStartRoll = 40; - gRandomAnimDefs[ REGMALE ][ 4 ].ubEndRoll = 100; + gRandomAnimDefs[ REGMALE ][ 4 ].ubStartRoll = 0; + gRandomAnimDefs[ REGMALE ][ 4 ].ubEndRoll = 60; gRandomAnimDefs[ REGMALE ][ 4 ].ubFlags = RANDOM_ANIM_INJURED; gRandomAnimDefs[ REGMALE ][ 4 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGMALE ][ 5 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; gRandomAnimDefs[ REGMALE ][ 5 ].sAnimID = DRUNK_IDLE; - gRandomAnimDefs[ REGMALE ][ 5 ].ubStartRoll = 40; + gRandomAnimDefs[ REGMALE ][ 5 ].ubStartRoll = 61; gRandomAnimDefs[ REGMALE ][ 5 ].ubEndRoll = 100; gRandomAnimDefs[ REGMALE ][ 5 ].ubFlags = RANDOM_ANIM_DRUNK; gRandomAnimDefs[ REGMALE ][ 5 ].ubAnimHeight = ANIM_STAND; @@ -1548,6 +1642,20 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceItemSubIndex[ REGMALE ][ WALK_BACKWARDS ] = RGMNOTHING_WALK; gubAnimSurfaceItemSubIndex[ REGMALE ][ DRUNK_IDLE ] = RGMPISTOLDRUNK; gubAnimSurfaceItemSubIndex[ REGMALE ][ RUNNING_W_PISTOL ] = RGMPISTOL_RUN; + gubAnimSurfaceItemSubIndex[ REGMALE ][ SIDE_STEP_WEAPON_RDY ] = RGMSIDESTEP_P_RDY; + gubAnimSurfaceItemSubIndex[ REGMALE ][ WALKING_WEAPON_RDY ] = RGMWALK_P_RDY; + + gubAnimSurfaceItemSubIndex[ REGMALE ][ READY_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ AIM_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ BURST_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGMALE ][ WALKING_ALTERNATIVE_RDY ] = RGMWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ REGMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGMSIDESTEP_P_RDY; gubAnimSurfaceCorpseID[ REGMALE ][ GENERIC_HIT_DEATH ] = SMERC_FWD; @@ -1791,9 +1899,8 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ BIGMALE ][ LOCKPICK_CROUCHED ] = BGMMEDIC; // crouch throwing - gubAnimSurfaceIndex[ BIGMALE ][ THROW_ITEM_CROUCHED ] = BGMCRTHROW; - // -//dddd + gubAnimSurfaceIndex[ BIGMALE ][ THROW_ITEM_CROUCHED ] = BGMCRTHROW; + // //dddd gubAnimSurfaceIndex[ BIGMALE ][ BIGGUY_STONE ] = BGMWITHSTONE; gubAnimSurfaceIndex[ BIGMALE ][ SHOOT_ROCKET_CROUCHED ] = BGMCRROCKET; gubAnimSurfaceIndex[ BIGMALE ][ SWATTING_WK ] = BGMSWKNIFE; @@ -1811,12 +1918,10 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ BIGMALE ][ JUMPWINDOWS ] = BGMJUMPWINDOWS; - gubAnimSurfaceIndex[ BIGMALE ][ SIDE_STEP_PISTOL_RDY ] = BGMSIDESTEP_P_RDY; - gubAnimSurfaceIndex[ BIGMALE ][ SIDE_STEP_RIFLE_RDY ] = BGMSIDESTEP_R_RDY; + gubAnimSurfaceIndex[ BIGMALE ][ SIDE_STEP_WEAPON_RDY ] = BGMSIDESTEP_R_RDY; gubAnimSurfaceIndex[ BIGMALE ][ SIDE_STEP_DUAL_RDY ] = BGMSIDESTEP_D_RDY; - gubAnimSurfaceIndex[ BIGMALE ][ WALKING_PISTOL_RDY ] = BGMWALK_P_RDY; - gubAnimSurfaceIndex[ BIGMALE ][ WALKING_RIFLE_RDY ] = BGMWALK_R_RDY; + gubAnimSurfaceIndex[ BIGMALE ][ WALKING_WEAPON_RDY ] = BGMWALK_R_RDY; gubAnimSurfaceIndex[ BIGMALE ][ WALKING_DUAL_RDY ] = BGMWALK_D_RDY; gubAnimSurfaceIndex[ BIGMALE ][ START_AID_PRN ] = BGMMEDICPRN; @@ -1826,6 +1931,37 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ BIGMALE ][ ADJACENT_GET_ITEM_CROUCHED ] = BGMMEDIC; gubAnimSurfaceIndex[ BIGMALE ][ STEAL_ITEM_CROUCHED ] = BGMMEDIC; + gubAnimSurfaceIndex[ BIGMALE ][ BURST_DUAL_STAND ] = BGMSTANDDWALAIM; + gubAnimSurfaceIndex[ BIGMALE ][ BURST_DUAL_CROUCH ] = BGMCDBLSHOT; + gubAnimSurfaceIndex[ BIGMALE ][ BURST_DUAL_PRONE ] = BGMDWPRONE; + + gubAnimSurfaceIndex[ BIGMALE ][ READY_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ AIM_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ SHOOT_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ BURST_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = BGMSHOOT_LOW; + gubAnimSurfaceIndex[ BIGMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = BGMSHOOT_LOW; + gubAnimSurfaceIndex[ BIGMALE ][ UNREADY_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ UNJAM_ALTERNATIVE_STAND ] = BGM_HIP_AIM; + gubAnimSurfaceIndex[ BIGMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = BGMSHOOT_LOW; + gubAnimSurfaceIndex[ BIGMALE ][ WALKING_ALTERNATIVE_RDY ] = BGMWALKING; + gubAnimSurfaceIndex[ BIGMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = BGMSIDESTEP; + + gubAnimSurfaceIndex[ BIGMALE ][ START_COWER_CROUCHED ] = BGMCOWER; + gubAnimSurfaceIndex[ BIGMALE ][ END_COWER_CROUCHED ] = BGMCOWER; + gubAnimSurfaceIndex[ BIGMALE ][ START_COWER_PRONE ] = BGM_COWER_PRONE; + gubAnimSurfaceIndex[ BIGMALE ][ COWERING_PRONE ] = BGM_COWER_PRONE; + gubAnimSurfaceIndex[ BIGMALE ][ END_COWER_PRONE ] = BGM_COWER_PRONE; + + gubAnimSurfaceIndex[ BIGMALE ][ BIGMERC_IDLE_NECK2 ] = BGMIDLENECK2; + + gubAnimSurfaceIndex[ BIGMALE ][ FOCUSED_PUNCH ] = BGMPUNCH; + gubAnimSurfaceIndex[ BIGMALE ][ FOCUSED_STAB ] = BGMSTAB; + gubAnimSurfaceIndex[ BIGMALE ][ HTH_KICK ] = BGMKICKDOOR; + gubAnimSurfaceIndex[ BIGMALE ][ FOCUSED_HTH_KICK ] = BGMKICKDOOR; + + gubAnimSurfaceIndex[ BIGMALE ][ LONG_JUMP ] = BGMJUMPOVER; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ STANDING ] = BGMPISTOLBREATH; gubAnimSurfaceItemSubIndex[ BIGMALE ][ WALKING ] = BGMNOTHING_WALK; gubAnimSurfaceItemSubIndex[ BIGMALE ][ RUNNING ] = BGMNOTHING_RUN; @@ -1866,7 +2002,20 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceItemSubIndex[ BIGMALE ][ WALK_BACKWARDS ] = BGMNOTHING_WALK; gubAnimSurfaceItemSubIndex[ BIGMALE ][ DRUNK_IDLE ] = BGMPISTOLDRUNK; gubAnimSurfaceItemSubIndex[ BIGMALE ][ RUNNING_W_PISTOL ] = BGMPISTOL_RUN; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ SIDE_STEP_WEAPON_RDY ] = BGMSIDESTEP_P_RDY; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ WALKING_WEAPON_RDY ] = BGMWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ READY_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ AIM_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ SHOOT_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ BURST_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = BGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = BGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ UNREADY_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ UNJAM_ALTERNATIVE_STAND ] = BGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = BGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ WALKING_ALTERNATIVE_RDY ] = BGMWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ BIGMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = BGMSIDESTEP_P_RDY; gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ STANDING][0] = BGMWATER_R_STD; gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ WALKING ][0] = BGMWATER_R_WALK; @@ -1896,65 +2045,78 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ THROW_ITEM ][1] = BGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ LOB_ITEM ][0] = BGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ LOB_ITEM ][1] = BGMWATERTHROW; - + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ BURST_DUAL_STAND ][1] = BGMWATER_DBLSHT; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ READY_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ AIM_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ SHOOT_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ BURST_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ UNREADY_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ BIGMALE ][ UNJAM_ALTERNATIVE_STAND ][0] = BGM_WATER_HIP_AIM; //Setup some random stuff gRandomAnimDefs[ BIGMALE ][ 0 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ BIGMALE ][ 0 ].sAnimID = BIGBUY_FLEX; gRandomAnimDefs[ BIGMALE ][ 0 ].ubStartRoll = 0; - gRandomAnimDefs[ BIGMALE ][ 0 ].ubEndRoll = 3; + gRandomAnimDefs[ BIGMALE ][ 0 ].ubEndRoll = 9; gRandomAnimDefs[ BIGMALE ][ 0 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ BIGMALE ][ 0 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ BIGMALE ][ 1 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ BIGMALE ][ 1 ].sAnimID = BIGBUY_STRECH; gRandomAnimDefs[ BIGMALE ][ 1 ].ubStartRoll = 10; - gRandomAnimDefs[ BIGMALE ][ 1 ].ubEndRoll = 13; + gRandomAnimDefs[ BIGMALE ][ 1 ].ubEndRoll = 19; gRandomAnimDefs[ BIGMALE ][ 1 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ BIGMALE ][ 1 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ BIGMALE ][ 2 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ BIGMALE ][ 2 ].sAnimID = BIGBUY_SHOEDUST; - gRandomAnimDefs[ BIGMALE ][ 2 ].ubStartRoll = 20; - gRandomAnimDefs[ BIGMALE ][ 2 ].ubEndRoll = 23; + gRandomAnimDefs[ BIGMALE ][ 2 ].ubStartRoll = 0; //20; + gRandomAnimDefs[ BIGMALE ][ 2 ].ubEndRoll = 0; //29; gRandomAnimDefs[ BIGMALE ][ 2 ].ubFlags = RANDOM_ANIM_CASUAL | RANDOM_ANIM_FIRSTBIGMERC; gRandomAnimDefs[ BIGMALE ][ 2 ].ubAnimHeight = ANIM_STAND; - gRandomAnimDefs[ BIGMALE ][ 3 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; - gRandomAnimDefs[ BIGMALE ][ 3 ].sAnimID = BIGBUY_HEADTURN; + ///ddd big guy with stone + gRandomAnimDefs[ BIGMALE ][ 3 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; + gRandomAnimDefs[ BIGMALE ][ 3 ].sAnimID = BIGGUY_STONE; gRandomAnimDefs[ BIGMALE ][ 3 ].ubStartRoll = 30; - gRandomAnimDefs[ BIGMALE ][ 3 ].ubEndRoll = 33; - gRandomAnimDefs[ BIGMALE ][ 3 ].ubFlags = RANDOM_ANIM_FIRSTBIGMERC; + gRandomAnimDefs[ BIGMALE ][ 3 ].ubEndRoll = 39; + gRandomAnimDefs[ BIGMALE ][ 3 ].ubFlags = RANDOM_ANIM_CASUAL ; gRandomAnimDefs[ BIGMALE ][ 3 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ BIGMALE ][ 4 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; - gRandomAnimDefs[ BIGMALE ][ 4 ].sAnimID = BIGMERC_IDLE_NECK; + gRandomAnimDefs[ BIGMALE ][ 4 ].sAnimID = BIGBUY_HEADTURN; gRandomAnimDefs[ BIGMALE ][ 4 ].ubStartRoll = 30; - gRandomAnimDefs[ BIGMALE ][ 4 ].ubEndRoll = 36; - gRandomAnimDefs[ BIGMALE ][ 4 ].ubFlags = RANDOM_ANIM_SECONDBIGMERC; + gRandomAnimDefs[ BIGMALE ][ 4 ].ubEndRoll = 49; + gRandomAnimDefs[ BIGMALE ][ 4 ].ubFlags = RANDOM_ANIM_FIRSTBIGMERC | RANDOM_ANIM_LOOKAROUND; gRandomAnimDefs[ BIGMALE ][ 4 ].ubAnimHeight = ANIM_STAND; - - gRandomAnimDefs[ BIGMALE ][ 5 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; - gRandomAnimDefs[ BIGMALE ][ 5 ].sAnimID = MERC_HURT_IDLE_ANIM; - gRandomAnimDefs[ BIGMALE ][ 5 ].ubStartRoll = 40; - gRandomAnimDefs[ BIGMALE ][ 5 ].ubEndRoll = 100; - gRandomAnimDefs[ BIGMALE ][ 5 ].ubFlags = RANDOM_ANIM_INJURED; + + gRandomAnimDefs[ BIGMALE ][ 5 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; + gRandomAnimDefs[ BIGMALE ][ 5 ].sAnimID = BIGMERC_IDLE_NECK2; + gRandomAnimDefs[ BIGMALE ][ 5 ].ubStartRoll = 50; + gRandomAnimDefs[ BIGMALE ][ 5 ].ubEndRoll = 59; + gRandomAnimDefs[ BIGMALE ][ 5 ].ubFlags = RANDOM_ANIM_FIRSTBIGMERC; gRandomAnimDefs[ BIGMALE ][ 5 ].ubAnimHeight = ANIM_STAND; - - gRandomAnimDefs[ BIGMALE ][ 6 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; - gRandomAnimDefs[ BIGMALE ][ 6 ].sAnimID = DRUNK_IDLE; - gRandomAnimDefs[ BIGMALE ][ 6 ].ubStartRoll = 40; - gRandomAnimDefs[ BIGMALE ][ 6 ].ubEndRoll = 100; - gRandomAnimDefs[ BIGMALE ][ 6 ].ubFlags = RANDOM_ANIM_DRUNK; + + gRandomAnimDefs[ BIGMALE ][ 6 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; + gRandomAnimDefs[ BIGMALE ][ 6 ].sAnimID = BIGMERC_IDLE_NECK; + gRandomAnimDefs[ BIGMALE ][ 6 ].ubStartRoll = 50; + gRandomAnimDefs[ BIGMALE ][ 6 ].ubEndRoll = 59; + gRandomAnimDefs[ BIGMALE ][ 6 ].ubFlags = RANDOM_ANIM_SECONDBIGMERC; gRandomAnimDefs[ BIGMALE ][ 6 ].ubAnimHeight = ANIM_STAND; - - ///ddd big guy with stone - gRandomAnimDefs[ BIGMALE ][ 7 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; - gRandomAnimDefs[ BIGMALE ][ 7 ].sAnimID = BIGGUY_STONE; - gRandomAnimDefs[ BIGMALE ][ 7 ].ubStartRoll = 20; - gRandomAnimDefs[ BIGMALE ][ 7 ].ubEndRoll = 26; - gRandomAnimDefs[ BIGMALE ][ 7 ].ubFlags = RANDOM_ANIM_CASUAL ; + + gRandomAnimDefs[ BIGMALE ][ 7 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; + gRandomAnimDefs[ BIGMALE ][ 7 ].sAnimID = MERC_HURT_IDLE_ANIM; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubStartRoll = 0; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubEndRoll = 60; + gRandomAnimDefs[ BIGMALE ][ 7 ].ubFlags = RANDOM_ANIM_INJURED; gRandomAnimDefs[ BIGMALE ][ 7 ].ubAnimHeight = ANIM_STAND; + + gRandomAnimDefs[ BIGMALE ][ 8 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; + gRandomAnimDefs[ BIGMALE ][ 8 ].sAnimID = DRUNK_IDLE; + gRandomAnimDefs[ BIGMALE ][ 8 ].ubStartRoll = 61; + gRandomAnimDefs[ BIGMALE ][ 8 ].ubEndRoll = 100; + gRandomAnimDefs[ BIGMALE ][ 8 ].ubFlags = RANDOM_ANIM_DRUNK; + gRandomAnimDefs[ BIGMALE ][ 8 ].ubAnimHeight = ANIM_STAND; gubAnimSurfaceCorpseID[ BIGMALE ][ GENERIC_HIT_DEATH ] = MMERC_FWD; @@ -2219,12 +2381,10 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ STOCKYMALE ][ JUMPWINDOWS ] = RGMJUMPWINDOWS; - gubAnimSurfaceIndex[ STOCKYMALE ][ SIDE_STEP_PISTOL_RDY ] = RGMSIDESTEP_P_RDY; - gubAnimSurfaceIndex[ STOCKYMALE ][ SIDE_STEP_RIFLE_RDY ] = RGMSIDESTEP_R_RDY; + gubAnimSurfaceIndex[ STOCKYMALE ][ SIDE_STEP_WEAPON_RDY ] = RGMSIDESTEP_R_RDY; gubAnimSurfaceIndex[ STOCKYMALE ][ SIDE_STEP_DUAL_RDY ] = RGMSIDESTEP_D_RDY; - gubAnimSurfaceIndex[ STOCKYMALE ][ WALKING_PISTOL_RDY ] = RGMWALK_P_RDY; - gubAnimSurfaceIndex[ STOCKYMALE ][ WALKING_RIFLE_RDY ] = RGMWALK_R_RDY; + gubAnimSurfaceIndex[ STOCKYMALE ][ WALKING_WEAPON_RDY ] = RGMWALK_R_RDY; gubAnimSurfaceIndex[ STOCKYMALE ][ WALKING_DUAL_RDY ] = RGMWALK_D_RDY; gubAnimSurfaceIndex[ STOCKYMALE ][ START_AID_PRN ] = RGMMEDICPRN; @@ -2234,6 +2394,35 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ STOCKYMALE ][ ADJACENT_GET_ITEM_CROUCHED ] = RGMMEDIC; gubAnimSurfaceIndex[ STOCKYMALE ][ STEAL_ITEM_CROUCHED ] = RGMMEDIC; + gubAnimSurfaceIndex[ STOCKYMALE ][ BURST_DUAL_STAND ] = RGMSTANDDWALAIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ BURST_DUAL_CROUCH ] = RGMCDBLSHOT; + gubAnimSurfaceIndex[ STOCKYMALE ][ BURST_DUAL_PRONE ] = RGMDWPRONE; + + gubAnimSurfaceIndex[ STOCKYMALE ][ READY_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ AIM_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ BURST_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ STOCKYMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ STOCKYMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGM_HIP_AIM; + gubAnimSurfaceIndex[ STOCKYMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGM_HIP_LOW; + gubAnimSurfaceIndex[ STOCKYMALE ][ WALKING_ALTERNATIVE_RDY ] = RGMBASICWALKING; + gubAnimSurfaceIndex[ STOCKYMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGMSIDESTEP; + + gubAnimSurfaceIndex[ STOCKYMALE ][ START_COWER_CROUCHED ] = RGMCOWER; + gubAnimSurfaceIndex[ STOCKYMALE ][ END_COWER_CROUCHED ] = RGMCOWER; + gubAnimSurfaceIndex[ STOCKYMALE ][ START_COWER_PRONE ] = RGM_COWER_PRONE; + gubAnimSurfaceIndex[ STOCKYMALE ][ COWERING_PRONE ] = RGM_COWER_PRONE; + gubAnimSurfaceIndex[ STOCKYMALE ][ END_COWER_PRONE ] = RGM_COWER_PRONE; + + gubAnimSurfaceIndex[ STOCKYMALE ][ FOCUSED_PUNCH ] = RGMPUNCH; + gubAnimSurfaceIndex[ STOCKYMALE ][ FOCUSED_STAB ] = RGMSTAB; + gubAnimSurfaceIndex[ STOCKYMALE ][ HTH_KICK ] = RGMKICKDOOR; + gubAnimSurfaceIndex[ STOCKYMALE ][ FOCUSED_HTH_KICK ] = RGMKICKDOOR; + + gubAnimSurfaceIndex[ STOCKYMALE ][ LONG_JUMP ] = RGMJUMPOVER; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ STANDING ] = RGMPISTOLBREATH; gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ WALKING ] = RGMNOTHING_WALK; gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ RUNNING] = RGMNOTHING_RUN; @@ -2274,6 +2463,20 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ WALK_BACKWARDS ] = RGMNOTHING_WALK; gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ DRUNK_IDLE ] = RGMPISTOLDRUNK; gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ RUNNING_W_PISTOL ] = RGMPISTOL_RUN; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ SIDE_STEP_WEAPON_RDY ] = RGMSIDESTEP_P_RDY; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ WALKING_WEAPON_RDY ] = RGMWALK_P_RDY; + + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ READY_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ AIM_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ BURST_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGM_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGMPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ WALKING_ALTERNATIVE_RDY ] = RGMWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ STOCKYMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGMSIDESTEP_P_RDY; gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ STANDING][0] = RGMWATER_R_STD; @@ -2304,7 +2507,13 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ THROW_ITEM ][1] = RGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ LOB_ITEM ][0] = RGMWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ LOB_ITEM ][1] = RGMWATERTHROW; - + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ BURST_DUAL_STAND ][1] = RGMWATER_DBLSHT; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ READY_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ AIM_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ SHOOT_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ BURST_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ UNREADY_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ STOCKYMALE ][ UNJAM_ALTERNATIVE_STAND ][0] = RGM_WATER_HIP_AIM; gubAnimSurfaceCorpseID[ STOCKYMALE ][ GENERIC_HIT_DEATH ] = SMERC_FWD; @@ -2337,41 +2546,41 @@ void InitAnimationSurfacesPerBodytype( ) gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ STOCKYMALE ][ 0 ].sAnimID = REG_SPIT; gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubStartRoll = 0; - gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubEndRoll = 3; + gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubEndRoll = 9; gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ STOCKYMALE ][ 0 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ STOCKYMALE ][ 1 ].sAnimID = REG_SQUISH; gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubStartRoll = 10; - gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubEndRoll = 13; + gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubEndRoll = 19; gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ STOCKYMALE ][ 1 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ STOCKYMALE ][ 2 ].sAnimID = FEM_LOOK; - gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubStartRoll = 20; - gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubEndRoll = 23; - gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubFlags = 0; + gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubStartRoll = 10; + gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubEndRoll = 29; + gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubFlags = RANDOM_ANIM_LOOKAROUND; gRandomAnimDefs[ STOCKYMALE ][ 2 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ STOCKYMALE ][ 3 ].sAnimID = REG_PULL; gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubStartRoll = 30; - gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubEndRoll = 33; + gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubEndRoll = 39; gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubFlags = 0; gRandomAnimDefs[ STOCKYMALE ][ 3 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; gRandomAnimDefs[ STOCKYMALE ][ 4 ].sAnimID = MERC_HURT_IDLE_ANIM; - gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubStartRoll = 40; - gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubEndRoll = 100; + gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubStartRoll = 0; + gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubEndRoll = 60; gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubFlags = RANDOM_ANIM_INJURED; gRandomAnimDefs[ STOCKYMALE ][ 4 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; gRandomAnimDefs[ STOCKYMALE ][ 5 ].sAnimID = DRUNK_IDLE; - gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubStartRoll = 40; + gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubStartRoll = 61; gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubEndRoll = 100; gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubFlags = RANDOM_ANIM_DRUNK; gRandomAnimDefs[ STOCKYMALE ][ 5 ].ubAnimHeight = ANIM_STAND; @@ -2606,12 +2815,10 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ REGFEMALE ][ JUMPWINDOWS ] = RGFJUMPWINDOWS; - gubAnimSurfaceIndex[ REGFEMALE ][ SIDE_STEP_PISTOL_RDY ] = RGFSIDESTEP_P_RDY; - gubAnimSurfaceIndex[ REGFEMALE ][ SIDE_STEP_RIFLE_RDY ] = RGFSIDESTEP_R_RDY; + gubAnimSurfaceIndex[ REGFEMALE ][ SIDE_STEP_WEAPON_RDY ] = RGFSIDESTEP_R_RDY; gubAnimSurfaceIndex[ REGFEMALE ][ SIDE_STEP_DUAL_RDY ] = RGFSIDESTEP_D_RDY; - gubAnimSurfaceIndex[ REGFEMALE ][ WALKING_PISTOL_RDY ] = RGFWALK_P_RDY; - gubAnimSurfaceIndex[ REGFEMALE ][ WALKING_RIFLE_RDY ] = RGFWALK_R_RDY; + gubAnimSurfaceIndex[ REGFEMALE ][ WALKING_WEAPON_RDY ] = RGFWALK_R_RDY; gubAnimSurfaceIndex[ REGFEMALE ][ WALKING_DUAL_RDY ] = RGFWALK_D_RDY; gubAnimSurfaceIndex[ REGFEMALE ][ START_AID_PRN ] = RGFMEDICPRN; @@ -2621,6 +2828,35 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceIndex[ REGFEMALE ][ ADJACENT_GET_ITEM_CROUCHED ] = RGFMEDIC; gubAnimSurfaceIndex[ REGFEMALE ][ STEAL_ITEM_CROUCHED ] = RGFMEDIC; + gubAnimSurfaceIndex[ REGFEMALE ][ BURST_DUAL_STAND ] = RGFSTANDDWALAIM; + gubAnimSurfaceIndex[ REGFEMALE ][ BURST_DUAL_CROUCH ] = RGFCDBLSHOT; + gubAnimSurfaceIndex[ REGFEMALE ][ BURST_DUAL_PRONE ] = RGFDWPRONE; + + gubAnimSurfaceIndex[ REGFEMALE ][ READY_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ AIM_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ BURST_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGF_HIP_AIM; + gubAnimSurfaceIndex[ REGFEMALE ][ WALKING_ALTERNATIVE_RDY ] = RGFWALKING; + gubAnimSurfaceIndex[ REGFEMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGFSIDESTEP; + + gubAnimSurfaceIndex[ REGFEMALE ][ START_COWER_CROUCHED ] = RGFCOWER; + gubAnimSurfaceIndex[ REGFEMALE ][ END_COWER_CROUCHED ] = RGFCOWER; + gubAnimSurfaceIndex[ REGFEMALE ][ START_COWER_PRONE ] = RGF_COWER_PRONE; + gubAnimSurfaceIndex[ REGFEMALE ][ COWERING_PRONE ] = RGF_COWER_PRONE; + gubAnimSurfaceIndex[ REGFEMALE ][ END_COWER_PRONE ] = RGF_COWER_PRONE; + + gubAnimSurfaceIndex[ REGFEMALE ][ FOCUSED_PUNCH ] = RGFPUNCH; + gubAnimSurfaceIndex[ REGFEMALE ][ FOCUSED_STAB ] = RGFSTAB; + gubAnimSurfaceIndex[ REGFEMALE ][ HTH_KICK ] = RGFKICKDOOR; + gubAnimSurfaceIndex[ REGFEMALE ][ FOCUSED_HTH_KICK ] = RGFKICKDOOR; + + gubAnimSurfaceIndex[ REGFEMALE ][ LONG_JUMP ] = RGFJUMPOVER; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ STANDING ] = RGFPISTOLBREATH; gubAnimSurfaceItemSubIndex[ REGFEMALE ][ WALKING ] = RGFNOTHING_WALK; gubAnimSurfaceItemSubIndex[ REGFEMALE ][ RUNNING ] = RGFNOTHING_RUN; @@ -2661,7 +2897,20 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceItemSubIndex[ REGFEMALE ][ WALK_BACKWARDS ] = RGFNOTHING_WALK; gubAnimSurfaceItemSubIndex[ REGFEMALE ][ DRUNK_IDLE ] = RGMPISTOLDRUNK; gubAnimSurfaceItemSubIndex[ REGFEMALE ][ RUNNING_W_PISTOL ] = RGFPISTOL_RUN; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ SIDE_STEP_WEAPON_RDY ] = RGFSIDESTEP_P_RDY; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ WALKING_WEAPON_RDY ] = RGFWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ READY_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ AIM_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ SHOOT_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ BURST_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ LOW_SHOT_ALTERNATIVE_STAND ] = RGFPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ LOW_BURST_ALTERNATIVE_STAND ] = RGFPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ UNREADY_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ UNJAM_ALTERNATIVE_STAND ] = RGF_PFSHOT_AIM; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ LOW_UNJAM_ALTERNATIVE_STAND ] = RGFPISTOLSHOOTLOW; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ WALKING_ALTERNATIVE_RDY ] = RGFWALK_P_RDY; + gubAnimSurfaceItemSubIndex[ REGFEMALE ][ SIDE_STEP_ALTERNATIVE_RDY ] = RGFSIDESTEP_P_RDY; gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ STANDING][0] = RGFWATER_R_STD; gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ WALKING ][0] = RGFWATER_R_WALK; @@ -2691,7 +2940,13 @@ void InitAnimationSurfacesPerBodytype( ) gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ THROW_ITEM ][1] = RGFWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ LOB_ITEM ][0] = RGFWATERTHROW; gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ LOB_ITEM ][1] = RGFWATERTHROW; - + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ BURST_DUAL_STAND ][1] = RGFWATER_DBLSHT; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ READY_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ AIM_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ SHOOT_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ BURST_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ UNREADY_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; + gubAnimSurfaceMidWaterSubIndex[ REGFEMALE ][ UNJAM_ALTERNATIVE_STAND ][0] = RGF_WATER_HIP_AIM; gubAnimSurfaceCorpseID[ REGFEMALE ][ GENERIC_HIT_DEATH ] = FMERC_FWD; gubAnimSurfaceCorpseID[ REGFEMALE ][ FALLBACK_HIT_DEATH ] = FMERC_BCK; @@ -2723,38 +2978,45 @@ void InitAnimationSurfacesPerBodytype( ) gRandomAnimDefs[ REGFEMALE ][ 0 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ REGFEMALE ][ 0 ].sAnimID = FEM_CLEAN; gRandomAnimDefs[ REGFEMALE ][ 0 ].ubStartRoll = 0; - gRandomAnimDefs[ REGFEMALE ][ 0 ].ubEndRoll = 3; + gRandomAnimDefs[ REGFEMALE ][ 0 ].ubEndRoll = 9; gRandomAnimDefs[ REGFEMALE ][ 0 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ REGFEMALE ][ 0 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGFEMALE ][ 1 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ REGFEMALE ][ 1 ].sAnimID = FEM_KICKSN; gRandomAnimDefs[ REGFEMALE ][ 1 ].ubStartRoll = 10; - gRandomAnimDefs[ REGFEMALE ][ 1 ].ubEndRoll = 13; + gRandomAnimDefs[ REGFEMALE ][ 1 ].ubEndRoll = 19; gRandomAnimDefs[ REGFEMALE ][ 1 ].ubFlags = RANDOM_ANIM_CASUAL; gRandomAnimDefs[ REGFEMALE ][ 1 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGFEMALE ][ 2 ].ubHandRestriction = RANDOM_ANIM_RIFLEINHAND; gRandomAnimDefs[ REGFEMALE ][ 2 ].sAnimID = FEM_LOOK; - gRandomAnimDefs[ REGFEMALE ][ 2 ].ubStartRoll = 20; - gRandomAnimDefs[ REGFEMALE ][ 2 ].ubEndRoll = 23; - gRandomAnimDefs[ REGFEMALE ][ 2 ].ubFlags = 0; + gRandomAnimDefs[ REGFEMALE ][ 2 ].ubStartRoll = 10; + gRandomAnimDefs[ REGFEMALE ][ 2 ].ubEndRoll = 29; + gRandomAnimDefs[ REGFEMALE ][ 2 ].ubFlags = RANDOM_ANIM_LOOKAROUND; gRandomAnimDefs[ REGFEMALE ][ 2 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGFEMALE ][ 3 ].ubHandRestriction = RANDOM_ANIM_NOTHINGINHAND; gRandomAnimDefs[ REGFEMALE ][ 3 ].sAnimID = FEM_WIPE; gRandomAnimDefs[ REGFEMALE ][ 3 ].ubStartRoll = 30; - gRandomAnimDefs[ REGFEMALE ][ 3 ].ubEndRoll = 33; + gRandomAnimDefs[ REGFEMALE ][ 3 ].ubEndRoll = 39; gRandomAnimDefs[ REGFEMALE ][ 3 ].ubFlags = 0; gRandomAnimDefs[ REGFEMALE ][ 3 ].ubAnimHeight = ANIM_STAND; gRandomAnimDefs[ REGFEMALE ][ 4 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; gRandomAnimDefs[ REGFEMALE ][ 4 ].sAnimID = MERC_HURT_IDLE_ANIM; - gRandomAnimDefs[ REGFEMALE ][ 4 ].ubStartRoll = 40; - gRandomAnimDefs[ REGFEMALE ][ 4 ].ubEndRoll = 100; + gRandomAnimDefs[ REGFEMALE ][ 4 ].ubStartRoll = 0; + gRandomAnimDefs[ REGFEMALE ][ 4 ].ubEndRoll = 60; gRandomAnimDefs[ REGFEMALE ][ 4 ].ubFlags = RANDOM_ANIM_INJURED; gRandomAnimDefs[ REGFEMALE ][ 4 ].ubAnimHeight = ANIM_STAND; + gRandomAnimDefs[ REGFEMALE ][ 5 ].ubHandRestriction = RANDOM_ANIM_IRRELEVENTINHAND; + gRandomAnimDefs[ REGFEMALE ][ 5 ].sAnimID = DRUNK_IDLE; + gRandomAnimDefs[ REGFEMALE ][ 5 ].ubStartRoll = 61; + gRandomAnimDefs[ REGFEMALE ][ 5 ].ubEndRoll = 100; + gRandomAnimDefs[ REGFEMALE ][ 5 ].ubFlags = RANDOM_ANIM_DRUNK; + gRandomAnimDefs[ REGFEMALE ][ 5 ].ubAnimHeight = ANIM_STAND; + //////////////////////////////////////////////////// // MONSTERS @@ -3302,72 +3564,89 @@ BOOLEAN LoadAnimationStateInstructions( ) memcpy(gusAnimInst[i],fuckTheBoundz[i],sizeof(fuckTheBoundz[i])); //gusAnimInst[i][0] = fuckTheBoundz[i][0]; - // For conversion into readable format (?) -// char gS[22]; -// UINT32 uiNumBytesWritten = 64000; -// int ggg[MAX_ANIMATIONS][MAX_FRAMES_PER_ANIM]; -// sprintf(gS, "%s\\%s", "c:", "zzz"); -// hFile = FileOpen( gS, FILE_ACCESS_WRITE | FILE_CREATE_ALWAYS, FALSE ); -// -// for(int i=0;i<=MAX_ANIMATIONS;i++) -// { -// FilePrintf(hFile,"\r\n :%02d === \r\n",i); -// for(int ii=0;ii<=MAX_FRAMES_PER_ANIM;ii++) -// FilePrintf(hFile,"%02d ",gusAnimInst[i][ii]); -// -// } -// //ggg[i][ii]=gusAnimInst[i][ii]; -// //FileWrite( hFile, &ggg, sizeof( ggg ), &uiNumBytesWritten ); -//FileClose( hFile ); -//! -//strcpy(NULL, "crash"); + // SANDRO - changes to standard animations frame read + memcpy(gusAnimInst[ FEM_KICKSN ],F_IDLE_ANIM_KICKSN_AnimationScript,sizeof(F_IDLE_ANIM_KICKSN_AnimationScript)); + memcpy(gusAnimInst[ FEM_LOOK ],F_IDLE_ANIM_LOOK_AnimationScript,sizeof(F_IDLE_ANIM_LOOK_AnimationScript)); + memcpy(gusAnimInst[ NINJA_SPINKICK ],NINJA_SPINKICK_AnimationScript,sizeof(NINJA_SPINKICK_AnimationScript)); - // crouch throwing - memcpy(gusAnimInst[ THROW_ITEM_CROUCHED ],CrouchedThrowAnimationScript,sizeof(CrouchedThrowAnimationScript)); - // crouch throwing - - //ddd - memcpy(gusAnimInst[ BIGGUY_STONE ],StoneAnimationScript,sizeof(StoneAnimationScript)); - memcpy(gusAnimInst[ SHOOT_ROCKET_CROUCHED ],CrouchedShootRocketScript,sizeof(CrouchedShootRocketScript)); - memcpy(gusAnimInst[ SWATTING_WK ],SwatWithKnifeScript,sizeof(SwatWithKnifeScript)); - memcpy(gusAnimInst[ SWAT_BACKWARDS_WK ],SwatBackWithKnifeScript,sizeof(SwatBackWithKnifeScript)); - memcpy(gusAnimInst[ SWAT_BACKWARDS_NOTHING ],SwatBackWithNothingScript,sizeof(SwatBackWithNothingScript)); + // NEW ANIMATION SCRIPTS - memcpy(gusAnimInst[ THROW_GRENADE_STANCE ],ThrowGrenadeStanceAnimationScript,sizeof(ThrowGrenadeStanceAnimationScript)); - memcpy(gusAnimInst[ LOB_GRENADE_STANCE ],LobGrenadeStanceAnimationScript,sizeof(LobGrenadeStanceAnimationScript)); + // crouch throwing + memcpy(gusAnimInst[ THROW_ITEM_CROUCHED ],CrouchedThrowAnimationScript,sizeof(CrouchedThrowAnimationScript)); + // crouch throwing + //ddd + memcpy(gusAnimInst[ BIGGUY_STONE ],StoneAnimationScript,sizeof(StoneAnimationScript)); + memcpy(gusAnimInst[ SHOOT_ROCKET_CROUCHED ],CrouchedShootRocketScript,sizeof(CrouchedShootRocketScript)); + memcpy(gusAnimInst[ SWATTING_WK ],SwatWithKnifeScript,sizeof(SwatWithKnifeScript)); + memcpy(gusAnimInst[ SWAT_BACKWARDS_WK ],SwatBackWithKnifeScript,sizeof(SwatBackWithKnifeScript)); + memcpy(gusAnimInst[ SWAT_BACKWARDS_NOTHING ],SwatBackWithNothingScript,sizeof(SwatBackWithNothingScript)); + + memcpy(gusAnimInst[ THROW_GRENADE_STANCE ],ThrowGrenadeStanceAnimationScript,sizeof(ThrowGrenadeStanceAnimationScript)); + memcpy(gusAnimInst[ LOB_GRENADE_STANCE ],LobGrenadeStanceAnimationScript,sizeof(LobGrenadeStanceAnimationScript)); + + memcpy(gusAnimInst[ ROLL_PRONE_L ],ROLL_L_AnimationScript,sizeof(ROLL_L_AnimationScript)); + memcpy(gusAnimInst[ ROLL_PRONE_R ],ROLL_R_AnimationScript,sizeof(ROLL_R_AnimationScript)); - memcpy(gusAnimInst[ ROLL_PRONE_L ],ROLL_L_AnimationScript,sizeof(ROLL_L_AnimationScript)); - memcpy(gusAnimInst[ ROLL_PRONE_R ],ROLL_R_AnimationScript,sizeof(ROLL_R_AnimationScript)); - - memcpy(gusAnimInst[JUMPUPWALL],fuckTheBoundz[32],sizeof(fuckTheBoundz[32])); // copy CLIMBROOF to JUMPUPWALL - - memcpy(gusAnimInst[JUMPDOWNWALL],fuckTheBoundz[35],sizeof(fuckTheBoundz[35])); // copy CLIMBDOWNROOF to JUMPDOWNWALL - - memcpy(gusAnimInst[JUMPWINDOWS],fuckTheBoundz[HOPFENCE],sizeof(fuckTheBoundz[HOPFENCE])); // copy HOPFENCE to JUMPDOWNWALL - - //memcpy(gusAnimInst[ JUMPUPWALL ],JUMP_WALL_UP_AnimationScript,sizeof(JUMP_WALL_UP_AnimationScript)); - //memcpy(gusAnimInst[ JUMPDOWNWALL ],JUMP_WALL_DOWN_AnimationScript,sizeof(JUMP_WALL_DOWN_AnimationScript)); - - memcpy(gusAnimInst[USE_REMOTE],REMOTE_DET_AnimationScript,sizeof(REMOTE_DET_AnimationScript)); // SANDRO - new animation of remote detonator by PasHancock + memcpy(gusAnimInst[JUMPUPWALL],fuckTheBoundz[32],sizeof(fuckTheBoundz[32])); // copy CLIMBROOF to JUMPUPWALL + + memcpy(gusAnimInst[JUMPDOWNWALL],fuckTheBoundz[35],sizeof(fuckTheBoundz[35])); // copy CLIMBDOWNROOF to JUMPDOWNWALL + + memcpy(gusAnimInst[JUMPWINDOWS],fuckTheBoundz[HOPFENCE],sizeof(fuckTheBoundz[HOPFENCE])); // copy HOPFENCE to JUMPDOWNWALL + + //memcpy(gusAnimInst[ JUMPUPWALL ],JUMP_WALL_UP_AnimationScript,sizeof(JUMP_WALL_UP_AnimationScript)); + //memcpy(gusAnimInst[ JUMPDOWNWALL ],JUMP_WALL_DOWN_AnimationScript,sizeof(JUMP_WALL_DOWN_AnimationScript)); + + memcpy(gusAnimInst[USE_REMOTE],REMOTE_DET_AnimationScript,sizeof(REMOTE_DET_AnimationScript)); // SANDRO - new animation of remote detonator by PasHancock - memcpy(gusAnimInst[THROW_KNIFE_SP_BM],THROW_KNIFE_SP_BM_AnimationScript,sizeof(THROW_KNIFE_SP_BM_AnimationScript)); // SANDRO - new animation of remote detonator by PasHancock - - memcpy(gusAnimInst[RUNNING_W_PISTOL],fuckTheBoundz[RUNNING],sizeof(fuckTheBoundz[RUNNING])); + memcpy(gusAnimInst[THROW_KNIFE_SP_BM],THROW_KNIFE_SP_BM_AnimationScript,sizeof(THROW_KNIFE_SP_BM_AnimationScript)); // SANDRO - new animation of remote detonator by PasHancock + + memcpy(gusAnimInst[RUNNING_W_PISTOL],fuckTheBoundz[RUNNING],sizeof(fuckTheBoundz[RUNNING])); - memcpy(gusAnimInst[SIDE_STEP_PISTOL_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); - memcpy(gusAnimInst[SIDE_STEP_RIFLE_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); - memcpy(gusAnimInst[SIDE_STEP_DUAL_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); - - memcpy(gusAnimInst[WALKING_PISTOL_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); - memcpy(gusAnimInst[WALKING_RIFLE_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); - memcpy(gusAnimInst[WALKING_DUAL_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); + memcpy(gusAnimInst[SIDE_STEP_WEAPON_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); + memcpy(gusAnimInst[SIDE_STEP_DUAL_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); + + memcpy(gusAnimInst[WALKING_WEAPON_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); + memcpy(gusAnimInst[WALKING_DUAL_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); - memcpy(gusAnimInst[START_AID_PRN],PRONE_START_FIRST_AID_AnimationScript,sizeof(PRONE_START_FIRST_AID_AnimationScript)); - memcpy(gusAnimInst[GIVING_AID_PRN],PRONE_GIVE_FIRST_AID_AnimationScript,sizeof(PRONE_GIVE_FIRST_AID_AnimationScript)); - memcpy(gusAnimInst[END_AID_PRN],fuckTheBoundz[END_AID],sizeof(fuckTheBoundz[END_AID])); + memcpy(gusAnimInst[START_AID_PRN],PRONE_START_FIRST_AID_AnimationScript,sizeof(PRONE_START_FIRST_AID_AnimationScript)); + memcpy(gusAnimInst[GIVING_AID_PRN],PRONE_GIVE_FIRST_AID_AnimationScript,sizeof(PRONE_GIVE_FIRST_AID_AnimationScript)); + memcpy(gusAnimInst[END_AID_PRN],fuckTheBoundz[END_AID],sizeof(fuckTheBoundz[END_AID])); - memcpy(gusAnimInst[ADJACENT_GET_ITEM_CROUCHED],fuckTheBoundz[ADJACENT_GET_ITEM],sizeof(fuckTheBoundz[ADJACENT_GET_ITEM])); - memcpy(gusAnimInst[STEAL_ITEM_CROUCHED],fuckTheBoundz[STEAL_ITEM],sizeof(fuckTheBoundz[STEAL_ITEM])); + memcpy(gusAnimInst[ADJACENT_GET_ITEM_CROUCHED],fuckTheBoundz[ADJACENT_GET_ITEM],sizeof(fuckTheBoundz[ADJACENT_GET_ITEM])); + memcpy(gusAnimInst[STEAL_ITEM_CROUCHED],fuckTheBoundz[STEAL_ITEM],sizeof(fuckTheBoundz[STEAL_ITEM])); + + memcpy(gusAnimInst[BURST_DUAL_STAND],DUAL_BURST_ST_CR_AnimationScript,sizeof(DUAL_BURST_ST_CR_AnimationScript)); + memcpy(gusAnimInst[BURST_DUAL_CROUCH],DUAL_BURST_ST_CR_AnimationScript,sizeof(DUAL_BURST_ST_CR_AnimationScript)); + memcpy(gusAnimInst[BURST_DUAL_PRONE],DUAL_BURST_PRONE_AnimationScript,sizeof(DUAL_BURST_PRONE_AnimationScript)); + + memcpy(gusAnimInst[READY_ALTERNATIVE_STAND],fuckTheBoundz[READY_RIFLE_STAND],sizeof(fuckTheBoundz[READY_RIFLE_STAND])); + memcpy(gusAnimInst[AIM_ALTERNATIVE_STAND],fuckTheBoundz[AIM_RIFLE_STAND],sizeof(fuckTheBoundz[AIM_RIFLE_STAND])); + memcpy(gusAnimInst[SHOOT_ALTERNATIVE_STAND],fuckTheBoundz[SHOOT_RIFLE_STAND],sizeof(fuckTheBoundz[SHOOT_RIFLE_STAND])); + memcpy(gusAnimInst[BURST_ALTERNATIVE_STAND],fuckTheBoundz[STANDING_BURST],sizeof(fuckTheBoundz[STANDING_BURST])); + memcpy(gusAnimInst[LOW_SHOT_ALTERNATIVE_STAND],fuckTheBoundz[FIRE_LOW_STAND],sizeof(fuckTheBoundz[FIRE_LOW_STAND])); + memcpy(gusAnimInst[LOW_BURST_ALTERNATIVE_STAND],fuckTheBoundz[FIRE_BURST_LOW_STAND],sizeof(fuckTheBoundz[FIRE_BURST_LOW_STAND])); + memcpy(gusAnimInst[UNREADY_ALTERNATIVE_STAND],fuckTheBoundz[END_RIFLE_STAND],sizeof(fuckTheBoundz[END_RIFLE_STAND])); + memcpy(gusAnimInst[UNJAM_ALTERNATIVE_STAND],fuckTheBoundz[STANDING_SHOOT_UNJAM],sizeof(fuckTheBoundz[STANDING_SHOOT_UNJAM])); + memcpy(gusAnimInst[LOW_UNJAM_ALTERNATIVE_STAND],fuckTheBoundz[STANDING_SHOOT_LOW_UNJAM],sizeof(fuckTheBoundz[STANDING_SHOOT_LOW_UNJAM])); + memcpy(gusAnimInst[WALKING_ALTERNATIVE_RDY],fuckTheBoundz[WALKING],sizeof(fuckTheBoundz[WALKING])); + memcpy(gusAnimInst[SIDE_STEP_ALTERNATIVE_RDY],fuckTheBoundz[SIDE_STEP],sizeof(fuckTheBoundz[SIDE_STEP])); + + memcpy(gusAnimInst[START_COWER_CROUCHED],START_COWER_CROUCHED_AnimationScript,sizeof(START_COWER_CROUCHED_AnimationScript)); + memcpy(gusAnimInst[END_COWER_CROUCHED],END_COWER_CROUCHED_AnimationScript,sizeof(END_COWER_CROUCHED_AnimationScript)); + memcpy(gusAnimInst[START_COWER_PRONE],START_COWER_PRONE_AnimationScript,sizeof(START_COWER_PRONE_AnimationScript)); + memcpy(gusAnimInst[COWERING_PRONE],COWER_PRONE_AnimationScript,sizeof(COWER_PRONE_AnimationScript)); + memcpy(gusAnimInst[END_COWER_PRONE],END_COWER_PRONE_AnimationScript,sizeof(END_COWER_PRONE_AnimationScript)); + + memcpy(gusAnimInst[BIGMERC_IDLE_NECK2],fuckTheBoundz[BIGMERC_IDLE_NECK],sizeof(fuckTheBoundz[BIGMERC_IDLE_NECK])); + + memcpy(gusAnimInst[FOCUSED_PUNCH],FOCUSED_PUNCH_AnimationScript,sizeof(FOCUSED_PUNCH_AnimationScript)); + memcpy(gusAnimInst[FOCUSED_STAB],FOCUSED_STAB_AnimationScript,sizeof(FOCUSED_STAB_AnimationScript)); + memcpy(gusAnimInst[HTH_KICK],HTH_KICK_AnimationScript,sizeof(HTH_KICK_AnimationScript)); + memcpy(gusAnimInst[FOCUSED_HTH_KICK],FOCUSED_HTH_KICK_AnimationScript,sizeof(FOCUSED_HTH_KICK_AnimationScript)); + + memcpy(gusAnimInst[LONG_JUMP],LONG_JUMP_AnimationScript,sizeof(LONG_JUMP_AnimationScript)); + + // NOTE: Careful here... keep in mind you have to increase MAX_ANIMATIONS whenever you would go over 399(currently) animation numbers return( TRUE ); } @@ -3750,64 +4029,67 @@ UINT16 DetermineSoldierAnimationSurface( SOLDIERTYPE *pSoldier, UINT16 usAnimSta } // SWITCH TO DIFFERENT AIM ANIMATION FOR BIG GUY! - if ( usAnimSurface == BGMSTANDAIM2 ) + if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) // badass rifle holding animation { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) + switch ( usAnimSurface ) { + case BGMSTANDAIM2: usAnimSurface = BGMSTANDAIM; -// if(Random(2)) usAnimSurface = BGMSTANDAIM; //ddd -// else usAnimSurface = BGMSTANDAIM2; - } - } - if ( usAnimSurface == BGMSIDESTEP_R_RDY ) - { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) - { + break; + case BGMSIDESTEP_R_RDY: usAnimSurface = BGMSIDESTEP_R_RDY2; - } - } - if ( usAnimSurface == BGMWALK_R_RDY ) - { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) - { + break; + case BGMWALK_R_RDY: usAnimSurface = BGMWALK_R_RDY2; + break; + default: + break; } } // SWITCH TO DIFFERENT STAND ANIMATION FOR BIG GUY! - if ( usAnimSurface == BGMSTANDING ) + switch (usAnimSurface) { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) - { - usAnimSurface = BGMTHREATENSTAND; - } + case BGMSTANDING: + if ( !DecideAltAnimForBigMerc( pSoldier ) ) + { + usAnimSurface = BGMTHREATENSTAND; + } + break; + case BGMWALKING: + if ( !DecideAltAnimForBigMerc( pSoldier ) ) + { + usAnimSurface = BGMWALK2; + } + break; + case BGMRUNNING: + if ( !DecideAltAnimForBigMerc( pSoldier ) ) + { + usAnimSurface = BGMRUN2; + } + break; + case BGMRAISE: + if ( !DecideAltAnimForBigMerc( pSoldier ) ) + { + usAnimSurface = BGMRAISE2; + } + break; + case BGM_HIP_AIM: + if ( DecideAltAnimForBigMerc( pSoldier ) ) + { + usAnimSurface = BGMHIPAIMALT; + } + break; + case BGMSTANDAIM2: + if ( DecideAltAnimForBigMerc( pSoldier ) && !( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 )) + { + usAnimSurface = BGMSRAIMALT; + } + break; + default: + break; } - if ( usAnimSurface == BGMWALKING ) - { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) - { - usAnimSurface = BGMWALK2; - } - } - - if ( usAnimSurface == BGMRUNNING ) - { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) - { - usAnimSurface = BGMRUN2; - } - } - - if ( usAnimSurface == BGMRAISE ) - { - if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) - { - usAnimSurface = BGMRAISE2; - } - } - - // ADJUST ANIMATION SURFACE BASED ON TERRAIN // CHECK FOR WATER diff --git a/Tactical/Animation Control.h b/Tactical/Animation Control.h index 4f9b7363c..ef16584df 100644 --- a/Tactical/Animation Control.h +++ b/Tactical/Animation Control.h @@ -7,13 +7,13 @@ // Defines // ####################################################### -#define MAX_ANIMATIONS 350 //!!!!!ddd added 30 new animations +#define MAX_ANIMATIONS 400 //!!!!!ddd added 30 new animations // SANDRO - added 50 more #define MAX_FRAMES_PER_ANIM 100 -#define MAX_RANDOM_ANIMS_PER_BODYTYPE 8 +#define MAX_RANDOM_ANIMS_PER_BODYTYPE 10 -#define RANDOM_ANIM_NOTHINGINHAND 0 -#define RANDOM_ANIM_RIFLEINHAND 1 -#define RANDOM_ANIM_IRRELEVENTINHAND 2 +#define RANDOM_ANIM_NOTHINGINHAND 0 +#define RANDOM_ANIM_RIFLEINHAND 1 +#define RANDOM_ANIM_IRRELEVENTINHAND 2 #define RANDOM_ANIM_SOUND 250 @@ -23,6 +23,7 @@ #define RANDOM_ANIM_FIRSTBIGMERC 0x04 #define RANDOM_ANIM_INJURED 0x08 #define RANDOM_ANIM_DRUNK 0x10 +#define RANDOM_ANIM_LOOKAROUND 0x20 #define INJURED_CHANGE_THREASHOLD 30 @@ -75,8 +76,9 @@ #define ANIM_UPDATEMOVEMENTMODE 0x10000000 #define ANIM_FIRE 0x20000000 #define ANIM_BREATH 0x40000000 -#define ANIM_IGNOREHITFINISH 0x80000000 - +// SANDRO - this flag is not assigned to any animation, so I am taking it for the hip fire feature +//#define ANIM_IGNOREHITFINISH 0x80000000 +#define ANIM_ALT_WEAPON_HOLDING 0x80000000 //ANIMATION HEIGHT VALUES #define ANIM_STAND 6 @@ -242,7 +244,6 @@ enum AnimationStates STAB, CROUCH_STAB, - START_AID, GIVING_AID, END_AID, @@ -563,12 +564,10 @@ enum AnimationStates THROW_KNIFE_SP_BM, RUNNING_W_PISTOL, - SIDE_STEP_PISTOL_RDY, - SIDE_STEP_RIFLE_RDY, + SIDE_STEP_WEAPON_RDY, SIDE_STEP_DUAL_RDY, - WALKING_PISTOL_RDY, - WALKING_RIFLE_RDY, + WALKING_WEAPON_RDY, WALKING_DUAL_RDY, START_AID_PRN, @@ -577,7 +576,38 @@ enum AnimationStates ADJACENT_GET_ITEM_CROUCHED, STEAL_ITEM_CROUCHED, + + BURST_DUAL_STAND, + BURST_DUAL_CROUCH, + BURST_DUAL_PRONE, + READY_ALTERNATIVE_STAND, + AIM_ALTERNATIVE_STAND, + SHOOT_ALTERNATIVE_STAND, + BURST_ALTERNATIVE_STAND, + LOW_SHOT_ALTERNATIVE_STAND, + LOW_BURST_ALTERNATIVE_STAND, + UNREADY_ALTERNATIVE_STAND, + UNJAM_ALTERNATIVE_STAND, + LOW_UNJAM_ALTERNATIVE_STAND, + WALKING_ALTERNATIVE_RDY, + SIDE_STEP_ALTERNATIVE_RDY, + + START_COWER_CROUCHED, + END_COWER_CROUCHED, + START_COWER_PRONE, + COWERING_PRONE, + END_COWER_PRONE, + + BIGMERC_IDLE_NECK2, + + FOCUSED_PUNCH, + FOCUSED_STAB, + HTH_KICK, + FOCUSED_HTH_KICK, + + LONG_JUMP, + NUMANIMATIONSTATES }; diff --git a/Tactical/Animation Data.cpp b/Tactical/Animation Data.cpp index 4c083112c..600510e80 100644 --- a/Tactical/Animation Data.cpp +++ b/Tactical/Animation Data.cpp @@ -66,7 +66,7 @@ AnimationSurfaceType gAnimSurfaceDatabase[ NUMANIMATIONSURFACETYPES ] = RGMNOTHING_RUN, "ANIMS\\S_MERC\\S_N_RUN.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGMNOTHING_SWAT, "ANIMS\\S_MERC\\S_N_SWAT.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGMNOTHING_CROUCH, "ANIMS\\S_MERC\\S_N_CRCH.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, - RGMHANDGUN_S_SHOT, "ANIMS\\S_MERC\\S_N_SHOT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGMHANDGUN_S_SHOT, "ANIMS\\S_MERC\\S_N_SHOT2.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGMHANDGUN_C_SHOT, "ANIMS\\S_MERC\\S_N_C_AI.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGMHANDGUN_PRONE, "ANIMS\\S_MERC\\S_N_PRNE.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGMDIE_JFK, "ANIMS\\S_MERC\\S_DIEJFK.STI", F_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, @@ -158,7 +158,7 @@ AnimationSurfaceType gAnimSurfaceDatabase[ NUMANIMATIONSURFACETYPES ] = BGMNOTHING_RUN, "ANIMS\\M_MERC\\M_N_RUN.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, BGMNOTHING_SWAT, "ANIMS\\M_MERC\\M_N_SWAT.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, BGMNOTHING_CROUCH, "ANIMS\\M_MERC\\M_N_CRCH.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, - BGMHANDGUN_S_SHOT, "ANIMS\\M_MERC\\M_N_SHOT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMHANDGUN_S_SHOT, "ANIMS\\M_MERC\\M_N_SHOT2.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, BGMHANDGUN_C_SHOT, "ANIMS\\M_MERC\\M_N_C_AI.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, BGMHANDGUN_PRONE, "ANIMS\\M_MERC\\M_N_PRNE.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, BGMDIE_JFK, "ANIMS\\M_MERC\\M_DIEJFK.STI", F_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, @@ -548,9 +548,30 @@ AnimationSurfaceType gAnimSurfaceDatabase[ NUMANIMATIONSURFACETYPES ] = RGFWALK_R_RDY, "ANIMS\\F_MERC\\F_R_RDY_WALK.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, RGFWALK_D_RDY, "ANIMS\\F_MERC\\F_DBL_RDY_WALK.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, - RGMMEDICPRN, "ANIMS\\S_MERC\\S_PRN_MED.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, - BGMMEDICPRN, "ANIMS\\M_MERC\\M_PRN_MED.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, - RGFMEDICPRN, "ANIMS\\F_MERC\\F_PRN_MED.STI", C_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGMMEDICPRN, "ANIMS\\S_MERC\\S_PRN_MED.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMMEDICPRN, "ANIMS\\M_MERC\\M_PRN_MED.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGFMEDICPRN, "ANIMS\\F_MERC\\F_PRN_MED.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + RGM_HIP_AIM, "ANIMS\\S_MERC\\S_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGM_HIP_LOW, "ANIMS\\S_MERC\\S_SR_HIP_LOW.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGM_HIP_AIM, "ANIMS\\M_MERC\\M_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGF_HIP_AIM, "ANIMS\\F_MERC\\F_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + RGM_WATER_HIP_AIM, "ANIMS\\S_MERC\\SW_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGM_WATER_HIP_AIM, "ANIMS\\M_MERC\\MW_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGF_WATER_HIP_AIM, "ANIMS\\F_MERC\\FW_SR_HIP_AIM.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + RGM_COWER_PRONE, "ANIMS\\S_MERC\\S_PRNCOW.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGM_COWER_PRONE, "ANIMS\\M_MERC\\M_PRNCOW.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGF_COWER_PRONE, "ANIMS\\F_MERC\\F_PRNCOW.STI", P_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + BGMIDLENECK2, "ANIMS\\M_MERC\\M_NECK2.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMHIPAIMALT, "ANIMS\\M_MERC\\M_SR_HIP_AIM_ALT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGMSRAIMALT, "ANIMS\\M_MERC\\M_SR_AM2_ALT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + + RGM_PFSHOT_AIM, "ANIMS\\S_MERC\\S_N_SHOT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + BGM_PFSHOT_AIM, "ANIMS\\M_MERC\\M_N_SHOT.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, + RGF_PFSHOT_AIM, "ANIMS\\F_MERC\\1_HND_N.STI", S_STRUCT, 0, 8, TO_INIT, NULL, NULL, 0, -1, }; diff --git a/Tactical/Animation Data.h b/Tactical/Animation Data.h index 40f3632b7..19f338d5f 100644 --- a/Tactical/Animation Data.h +++ b/Tactical/Animation Data.h @@ -581,6 +581,27 @@ BGMWITHSTONE, BGMMEDICPRN, RGFMEDICPRN, + RGM_HIP_AIM, + RGM_HIP_LOW, + BGM_HIP_AIM, + RGF_HIP_AIM, + + RGM_WATER_HIP_AIM, + BGM_WATER_HIP_AIM, + RGF_WATER_HIP_AIM, + + RGM_COWER_PRONE, + BGM_COWER_PRONE, + RGF_COWER_PRONE, + + BGMIDLENECK2, + BGMHIPAIMALT, + BGMSRAIMALT, + + RGM_PFSHOT_AIM, + BGM_PFSHOT_AIM, + RGF_PFSHOT_AIM, + NUMANIMATIONSURFACETYPES } AnimationSurfaceTypes; diff --git a/Tactical/Civ Quotes.cpp b/Tactical/Civ Quotes.cpp index ef5fc64a0..e09fe84dd 100644 --- a/Tactical/Civ Quotes.cpp +++ b/Tactical/Civ Quotes.cpp @@ -1081,6 +1081,10 @@ void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ) iTauntNumber = Random(7); sTauntText = sEnemyTauntsGotHit[iTauntNumber]; break; + case TAUNT_NOTICED_UNSEEN_MERC: + iTauntNumber = Random(7); + sTauntText = sEnemyTauntsNoticedMerc[iTauntNumber]; + break; default: return; break; diff --git a/Tactical/Civ Quotes.h b/Tactical/Civ Quotes.h index 2df9cfb6f..5eff520b8 100644 --- a/Tactical/Civ Quotes.h +++ b/Tactical/Civ Quotes.h @@ -83,7 +83,8 @@ enum //enemy taunts - SANDRO TAUNT_RUN_AWAY, TAUNT_SEEK_NOISE, TAUNT_ALERT, - TAUNT_GOT_HIT + TAUNT_GOT_HIT, + TAUNT_NOTICED_UNSEEN_MERC, }; void StartEnemyTaunt( SOLDIERTYPE *pCiv, INT8 iTauntType ); //enemy taunts - SANDRO diff --git a/Tactical/Food.cpp b/Tactical/Food.cpp index b8ef6404c..7b86a13f3 100644 --- a/Tactical/Food.cpp +++ b/Tactical/Food.cpp @@ -431,7 +431,9 @@ void HourlyFoodSituationUpdate( SOLDIERTYPE *pSoldier ) { UINT8 numberofreduces = 1; // if starving, we lose stats a LOT faster - if ( foodsituation == FOOD_STARVING ) + // SANDRO - shouldn't it be "watersituation" here? + //if ( foodsituation == FOOD_STARVING ) + if ( watersituation == FOOD_STARVING ) numberofreduces += Random(2); INT8 oldval = pSoldier->stats.bStrength; @@ -457,7 +459,9 @@ void HourlyFoodSituationUpdate( SOLDIERTYPE *pSoldier ) { UINT8 numberofreduces = 1; // if starving, we lose stats a LOT faster - if ( foodsituation == FOOD_STARVING ) + // SANDRO - shouldn't it be "watersituation" here? + //if ( foodsituation == FOOD_STARVING ) + if ( watersituation == FOOD_STARVING ) numberofreduces += 1 + 2 * Random(2); INT8 oldlife = pSoldier->stats.bLife; diff --git a/Tactical/Handle Items.cpp b/Tactical/Handle Items.cpp index f33dbfb52..ba0088202 100644 --- a/Tactical/Handle Items.cpp +++ b/Tactical/Handle Items.cpp @@ -416,9 +416,9 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, TRUE, pSoldier->aiData.bAimTime ); - GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sTargetGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost ); + GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sTargetGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, pSoldier->aiData.bAimTime ); usTurningCost = CalculateTurningCost(pSoldier, usHandItem, fAddingTurningCost); - usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost); + usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sTargetGridNo, pSoldier->aiData.bAimTime); // If we are standing and are asked to turn AND raise gun, ignore raise gun... //CHRISL: Actually, the display value is based on the higher of turn and raise gun so we should do the same @@ -1451,7 +1451,7 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa sTargetGridNo = sGridNo; } - sAPCost = MinAPsToAttack( pSoldier, sTargetGridNo, TRUE ); + sAPCost = MinAPsToAttack( pSoldier, sTargetGridNo, TRUE, pSoldier->aiData.bAimTime, 0 ); // Check if these is room to place mortar! if ( Item[usHandItem].mortar ) @@ -1470,9 +1470,9 @@ INT32 HandleItem( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bLevel, UINT16 usHa } else if ( Item[usHandItem].grenadelauncher )//usHandItem == GLAUNCHER || usHandItem == UNDER_GLAUNCHER ) { - GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sTargetGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost ); + GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sTargetGridNo, TRUE, &fAddingTurningCost, &fAddingRaiseGunCost, pSoldier->aiData.bAimTime ); usTurningCost = CalculateTurningCost(pSoldier, usHandItem, fAddingTurningCost); - usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost); + usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sTargetGridNo, pSoldier->aiData.bAimTime ); // If we are standing and are asked to turn AND raise gun, ignore raise gun... //CHRISL: Actually, the display value is based on the higher of turn and raise gun so we should do the same diff --git a/Tactical/Handle UI Plan.cpp b/Tactical/Handle UI Plan.cpp index 81140b3e5..02279f601 100644 --- a/Tactical/Handle UI Plan.cpp +++ b/Tactical/Handle UI Plan.cpp @@ -287,11 +287,25 @@ void SelectPausedFireAnimation( SOLDIERTYPE *pSoldier ) if ( pSoldier->bDoBurst > 0 ) { - pSoldier->ChangeSoldierState( STANDING_BURST, 2 , FALSE ); + if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) ) + { + pSoldier->ChangeSoldierState( BURST_ALTERNATIVE_STAND, 2 , FALSE ); + } + else + { + pSoldier->ChangeSoldierState( STANDING_BURST, 2 , FALSE ); + } } else { - pSoldier->ChangeSoldierState( SHOOT_RIFLE_STAND, 2 , FALSE ); + if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) ) + { + pSoldier->ChangeSoldierState( SHOOT_ALTERNATIVE_STAND, 2 , FALSE ); + } + else + { + pSoldier->ChangeSoldierState( SHOOT_RIFLE_STAND, 2 , FALSE ); + } } break; diff --git a/Tactical/Handle UI.cpp b/Tactical/Handle UI.cpp index cb618fdc1..9b06ab61b 100644 --- a/Tactical/Handle UI.cpp +++ b/Tactical/Handle UI.cpp @@ -106,7 +106,7 @@ ////////////////////////////////////////////////////////////////////// //extern BOOLEAN gfDisplayFullCountRingBurst; -extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); //#define AP_TO_AIM_TILE_IF_GETTING_READY 1 #define AP_TO_AIM_TILE_IF_ALREADY_READY ( Weapon[ Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex ].ubReadyTime ? 2 : 1 ) @@ -1714,7 +1714,7 @@ UINT32 UIHandleMovementMenu( UI_EVENT *pUIEvent ) { case MOVEMENT_MENU_RUN: - if ( pSoldier->usUIMovementMode != WALKING && pSoldier->usUIMovementMode != RUNNING && pSoldier->usUIMovementMode != WALKING_PISTOL_RDY && pSoldier->usUIMovementMode != WALKING_RIFLE_RDY && pSoldier->usUIMovementMode != WALKING_DUAL_RDY ) + if ( pSoldier->usUIMovementMode != WALKING && pSoldier->usUIMovementMode != RUNNING && pSoldier->usUIMovementMode != WALKING_WEAPON_RDY && pSoldier->usUIMovementMode != WALKING_DUAL_RDY && pSoldier->usUIMovementMode != WALKING_ALTERNATIVE_RDY ) { UIHandleSoldierStanceChange( pSoldier->ubID, ANIM_STAND ); pSoldier->flags.fUIMovementFast = 1; @@ -2823,7 +2823,7 @@ UINT32 UIHandleAEndAction( UI_EVENT *pUIEvent ) ConvertGridNoToXY( usMapPos, &sTargetXPos, &sTargetYPos ); // UNReady weapon - pSoldier->SoldierReadyWeapon( sTargetXPos, sTargetYPos, TRUE ); + pSoldier->SoldierReadyWeapon( sTargetXPos, sTargetYPos, TRUE, FALSE ); gUITargetReady = FALSE; } @@ -3897,9 +3897,9 @@ BOOLEAN HandleUIMovementCursor( SOLDIERTYPE *pSoldier, UINT32 uiCursorFlags, INT switch ( pSoldier->usUIMovementMode ) { case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: gUIDisplayActionPointsOffY = 10; gUIDisplayActionPointsOffX = 10; @@ -4205,7 +4205,7 @@ INT8 DrawUIMovementPath( SOLDIERTYPE *pSoldier, INT32 usMapPos, UINT32 uiFlags ) if (!TileIsOutOfBounds(sGotLocation)) { - sAPCost += MinAPsToAttack( pSoldier, sAdjustedGridNo, TRUE ); + sAPCost += MinAPsToAttack( pSoldier, sAdjustedGridNo, TRUE, pSoldier->aiData.bShownAimTime, 0 ); // WANNE: Turn around APs were missing, I think .... //sAPCost += APsToTurnAround(pSoldier, sAdjustedGridNo); @@ -4722,9 +4722,9 @@ void SetMovementModeCursor( SOLDIERTYPE *pSoldier ) switch ( pSoldier->usUIMovementMode ) { case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: guiNewUICursor = MOVE_WALK_UICURSOR; break; @@ -4785,9 +4785,9 @@ void SetConfirmMovementModeCursor( SOLDIERTYPE *pSoldier, BOOLEAN fFromMove ) switch ( pSoldier->usUIMovementMode ) { case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: guiNewUICursor = ALL_MOVE_WALK_UICURSOR; break; @@ -4817,9 +4817,9 @@ void SetConfirmMovementModeCursor( SOLDIERTYPE *pSoldier, BOOLEAN fFromMove ) switch ( pSoldier->usUIMovementMode ) { case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: guiNewUICursor = CONFIRM_MOVE_WALK_UICURSOR; break; @@ -4908,7 +4908,10 @@ UINT32 UIHandleLCOnTerrain( UI_EVENT *pUIEvent ) } else { - usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE ); + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE, TRUE ); + else + usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ); gsCurrentActionPoints = 0; @@ -4956,6 +4959,7 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) { INT16 sFacingDir, sAPCost, sAPCostToReady; UINT16 usAnimState; + INT32 iBPCpst = 0; // Make sure the merc is not collapsed! if (!IsValidStance(pSoldier, ANIM_CROUCH) ) @@ -5013,7 +5017,10 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) } else { - usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE ); + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE, TRUE ); + else + usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ); sAPCostToReady = sAPCost = 0; @@ -5025,6 +5032,9 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) if( pSoldier->sLastTarget != sXPos + (MAXCOL * sYPos ) && pTarget != NULL ) sAPCost = APBPConstants[AP_CHANGE_TARGET]; + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + sAPCost /= 2; + if( usAnimState != INVALID_ANIMATION ) { sAPCostToReady = GetAPsToReadyWeapon( pSoldier, usAnimState ); @@ -5037,7 +5047,12 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) } if( usAnimState != INVALID_ANIMATION ) - pSoldier->SoldierReadyWeapon( sXPos, sYPos, FALSE ); + { + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->SoldierReadyWeapon( sXPos, sYPos, FALSE, TRUE ); + else + pSoldier->SoldierReadyWeapon( sXPos, sYPos, FALSE, FALSE ); + } pSoldier->bTurningFromUI = TRUE; guiOldEvent = LA_BEGINUIOURTURNLOCK; @@ -5045,7 +5060,14 @@ BOOLEAN MakeSoldierTurn( SOLDIERTYPE *pSoldier, INT16 sXPos, INT16 sYPos ) // Setting "Last Target" pSoldier->sLastTarget = sXPos + (MAXCOL * sYPos); - DeductPoints( pSoldier, sAPCost, 0, AFTERACTION_INTERRUPT ); + + // SANDRO - get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight) + iBPCpst = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCpst = 0; + + DeductPoints( pSoldier, sAPCost, iBPCpst, AFTERACTION_INTERRUPT ); return( TRUE ); } @@ -5731,7 +5753,10 @@ UINT32 UIHandleJumpOver( UI_EVENT *pUIEvent ) pSoldier->flags.fTurningUntilDone = TRUE; // ATE: Reset flag to go back to prone... //pSoldier->flags.fTurningFromPronePosition = TURNING_FROM_PRONE_OFF; - pSoldier->usPendingAnimation = JUMP_OVER_BLOCKING_PERSON; + if (SpacesAway(pSoldier->sGridNo, usMapPos) == 3 ) + pSoldier->usPendingAnimation = LONG_JUMP; + else + pSoldier->usPendingAnimation = JUMP_OVER_BLOCKING_PERSON; return( GAME_SCREEN ); @@ -6691,16 +6716,22 @@ BOOLEAN ValidQuickExchangePosition( ) // to jump over people. BOOLEAN IsValidJumpLocation( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fCheckForPath ) { - INT32 sFourGrids[4], sDistance=0, sSpot, sIntSpot; + // SANDRO: been here, did mess + INT32 sFourGrids[4], sDistance=0, sSpot, sInBetween, sInBetween2, iDoorGridNo; static const UINT8 sDirs[4] = { NORTH, EAST, SOUTH, WEST }; //INT32 cnt; - UINT8 ubGuyThere; - UINT8 ubMovementCost; - INT32 iDoorGridNo; + UINT8 ubGuyThere, ubMovementCost, ubDirection; + INT8 bTileHeight = 0; + // SANDRO: commented out to allow jumping even in cases we could get to the destination normally // First check that action point cost is zero so far // ie: NO PATH! - if ( gsCurrentActionPoints != 0 && fCheckForPath ) + /*if ( gsCurrentActionPoints != 0 && fCheckForPath ) + { + return( FALSE ); + }*/ + + if( !(_KeyDown( SHIFT )) ) { return( FALSE ); } @@ -6709,25 +6740,26 @@ BOOLEAN IsValidJumpLocation( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fChec for (INT8 cnt = 0; cnt < 4; cnt++) { // MOVE OUT TWO DIRECTIONS - sIntSpot = NewGridNo( sGridNo, DirectionInc( sDirs[ cnt ] ) ); + sInBetween = NewGridNo( sGridNo, DirectionInc( sDirs[ cnt ] ) ); - // ATE: Check our movement costs for going through walls! - ubMovementCost = gubWorldMovementCosts[ sIntSpot ][ sDirs[ cnt ] ][ pSoldier->pathing.bLevel ]; - if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) - { - ubMovementCost = DoorTravelCost( pSoldier, sIntSpot, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); - } + // SANDRO: moved this someplace else and made it more fluid + // ATE: Check our movement costs for going through walls! + /*ubMovementCost = gubWorldMovementCosts[ sIntSpot ][ sDirs[ cnt ] ][ pSoldier->pathing.bLevel ]; + if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) + { + ubMovementCost = DoorTravelCost( pSoldier, sIntSpot, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); + }*/ // If we have hit an obstacle, STOP HERE - if ( ubMovementCost >= TRAVELCOST_BLOCKED ) - { - // no good, continue - continue; - } + //if ( ubMovementCost >= TRAVELCOST_BLOCKED ) + //{ + // // no good, continue + // continue; + //} // TWICE AS FAR! - sFourGrids[cnt] = sSpot = NewGridNo( sIntSpot, DirectionInc( sDirs[ cnt ] ) ); + sFourGrids[cnt] = sSpot = NewGridNo( sInBetween, DirectionInc( sDirs[ cnt ] ) ); // Is the soldier we're looking at here? ubGuyThere = WhoIsThere2( sSpot, pSoldier->pathing.bLevel ); @@ -6736,21 +6768,214 @@ BOOLEAN IsValidJumpLocation( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fChec if ( ubGuyThere == pSoldier->ubID ) { // Double check OK destination...... - if ( NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel ) ) + if ( NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel ) && IsLocationSittable( sGridNo, pSoldier->pathing.bLevel ) ) { // If the soldier in the middle of doing stuff? if ( !pSoldier->flags.fTurningUntilDone ) { // OK, NOW check if there is a guy in between us // + // SANDRO: made this a bit different - if we hold down the shift key, and pointing at a spot 2 tiles away, we check if jumping + // there is possible for all cases, and if it is, then we juuuuumpppp! + // So we don't care if there is a guy on the ground there, and the cursor wont appear atutomatically anymore // - ubGuyThere = WhoIsThere2( sIntSpot, pSoldier->pathing.bLevel ); - + //ubGuyThere = WhoIsThere2( sIntSpot, pSoldier->pathing.bLevel ); // Is there a guy and is he prone? - if ( ubGuyThere != NOBODY && ubGuyThere != pSoldier->ubID && gAnimControl[ MercPtrs[ ubGuyThere ]->usAnimState ].ubHeight == ANIM_PRONE ) + //if ( ubGuyThere != NOBODY && ubGuyThere != pSoldier->ubID && gAnimControl[ MercPtrs[ ubGuyThere ]->usAnimState ].ubHeight == ANIM_PRONE ) + //{ + // // It's a GO! + // return( TRUE ); + //} + //else + + // Can't jump from a water tile (but we can jumpt TO a water tile) + if ( pSoldier->MercInWater() ) { - // It's a GO! - return( TRUE ); + return( FALSE ); + } + + // check for cliffs and similar oddities + if ( gpWorldLevelData[ sGridNo ].sHeight != gpWorldLevelData[ sSpot ].sHeight ) + { + return( FALSE ); + } + + // If there's a guy here, and he's not prone, we can't jump over him (maybe the way we hop over fence? lol) + ubGuyThere = WhoIsThere2( sInBetween, pSoldier->pathing.bLevel ); + if ( ubGuyThere != NOBODY && ubGuyThere != pSoldier->ubID && gAnimControl[ MercPtrs[ ubGuyThere ]->usAnimState ].ubHeight != ANIM_PRONE ) + { + return( FALSE ); + } + + // Get the height of stuff on the tile, we can only jump over low obstacles like this + bTileHeight = GetTallestStructureHeight( sInBetween, pSoldier->pathing.bLevel ); + if ( bTileHeight > 0 && !IsLocationSittableExcludingPeople( sInBetween, pSoldier->pathing.bLevel ) && !( pSoldier->pathing.bLevel && FlatRoofAboveGridNo( sInBetween ) )) + { + return( FALSE ); + } + + // Check again for these structures as they may have odd height preset + if (( FindStructure( sInBetween, STRUCTURE_TREE ) != NULL || FindStructure( sInBetween, STRUCTURE_FENCE ) != NULL || + FindStructure( sInBetween, STRUCTURE_WIREFENCE ) != NULL || FindStructure( sInBetween, STRUCTURE_VEHICLE ) != NULL || + FindStructure( sInBetween, STRUCTURE_CAVEWALL ) != NULL ) && !IsLocationSittableExcludingPeople( sInBetween, pSoldier->pathing.bLevel )) + { + return( FALSE ); + } + + // Now check for walls between the tiles + // Between our tile and the middle tile... + ubDirection = GetDirectionToGridNoFromGridNo( sInBetween, pSoldier->sGridNo ); + ubMovementCost = gubWorldMovementCosts[ pSoldier->sGridNo ][ ubDirection ][ pSoldier->pathing.bLevel ]; + if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) + { + ubMovementCost = DoorTravelCost( pSoldier, pSoldier->sGridNo, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); + } + if ( ubMovementCost >= TRAVELCOST_BLOCKED ) + { + return( FALSE ); + } + // Between destination tile and the middle tile... + ubDirection = GetDirectionToGridNoFromGridNo( sInBetween, sGridNo ); + ubMovementCost = gubWorldMovementCosts[ sGridNo ][ ubDirection ][ pSoldier->pathing.bLevel ]; + if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) + { + ubMovementCost = DoorTravelCost( pSoldier, sGridNo, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); + } + if ( ubMovementCost >= TRAVELCOST_BLOCKED ) + { + return( FALSE ); + } + + // If we got here, we are good to go + return ( TRUE ); + } + } + } + // Attempt to long jump + else + { + // 3 TILES FAR! + sInBetween2 = sSpot; + sSpot = NewGridNo( sInBetween2, DirectionInc( sDirs[ cnt ] ) ); + + // Is the soldier we're looking at here? + ubGuyThere = WhoIsThere2( sSpot, pSoldier->pathing.bLevel ); + + // Alright folks, here we are! + if ( ubGuyThere == pSoldier->ubID ) + { + // Double check OK destination...... + if ( NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel ) && IsLocationSittable( sGridNo, pSoldier->pathing.bLevel ) ) + { + // If the soldier in the middle of doing stuff? + if ( !pSoldier->flags.fTurningUntilDone ) + { + // Can't jump from a water tile (but we can jumpt TO a water tile) + if ( pSoldier->MercInWater() ) + { + return( FALSE ); + } + + // This ain't gonna happen with backpack + if((UsingNewInventorySystem() == true) && FindBackpackOnSoldier( pSoldier ) != ITEM_NOT_FOUND ) + { + return( FALSE ); + } + + // check for cliffs and similar oddities + if ( gpWorldLevelData[ sGridNo ].sHeight != gpWorldLevelData[ sSpot ].sHeight ) + { + return( FALSE ); + } + + // If there's a guy on any of the two middle tiles, and he's not prone, we can't jump over him + ubGuyThere = WhoIsThere2( sInBetween, pSoldier->pathing.bLevel ); + if ( ubGuyThere != NOBODY && ubGuyThere != pSoldier->ubID && gAnimControl[ MercPtrs[ ubGuyThere ]->usAnimState ].ubHeight != ANIM_PRONE ) + { + return( FALSE ); + } + ubGuyThere = WhoIsThere2( sInBetween2, pSoldier->pathing.bLevel ); + if ( ubGuyThere != NOBODY && ubGuyThere != pSoldier->ubID && gAnimControl[ MercPtrs[ ubGuyThere ]->usAnimState ].ubHeight != ANIM_PRONE ) + { + return( FALSE ); + } + + // Get the height of stuff on both middle tiles, we can only jump over low obstacles + bTileHeight = GetTallestStructureHeight( sInBetween, pSoldier->pathing.bLevel ); + if ( bTileHeight > 0 && !IsLocationSittableExcludingPeople( sInBetween, pSoldier->pathing.bLevel ) && !( pSoldier->pathing.bLevel && FlatRoofAboveGridNo( sInBetween ) )) + { + return( FALSE ); + } + bTileHeight = GetTallestStructureHeight( sInBetween2, pSoldier->pathing.bLevel ); + if ( bTileHeight > 0 && !IsLocationSittableExcludingPeople( sInBetween2, pSoldier->pathing.bLevel ) && !( pSoldier->pathing.bLevel && FlatRoofAboveGridNo( sInBetween2 ) )) + { + return( FALSE ); + } + + // Check again for these structures as they may have odd height preset + if (( FindStructure( sInBetween, STRUCTURE_TREE ) != NULL || FindStructure( sInBetween, STRUCTURE_FENCE ) != NULL || + FindStructure( sInBetween, STRUCTURE_WIREFENCE ) != NULL || FindStructure( sInBetween, STRUCTURE_VEHICLE ) != NULL || + FindStructure( sInBetween, STRUCTURE_CAVEWALL ) != NULL ) && !IsLocationSittableExcludingPeople( sInBetween, pSoldier->pathing.bLevel )) + { + return( FALSE ); + } + if (( FindStructure( sInBetween2, STRUCTURE_TREE ) != NULL || FindStructure( sInBetween2, STRUCTURE_FENCE ) != NULL || + FindStructure( sInBetween2, STRUCTURE_WIREFENCE ) != NULL || FindStructure( sInBetween2, STRUCTURE_VEHICLE ) != NULL || + FindStructure( sInBetween2, STRUCTURE_CAVEWALL ) != NULL ) && !IsLocationSittableExcludingPeople( sInBetween2, pSoldier->pathing.bLevel )) + { + return( FALSE ); + } + + // Now check for walls between the tiles + // Between our tile and the middle tile next to us... + ubDirection = GetDirectionToGridNoFromGridNo( sInBetween2, pSoldier->sGridNo ); + ubMovementCost = gubWorldMovementCosts[ pSoldier->sGridNo ][ ubDirection ][ pSoldier->pathing.bLevel ]; + if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) + { + ubMovementCost = DoorTravelCost( pSoldier, pSoldier->sGridNo, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); + } + if ( ubMovementCost >= TRAVELCOST_BLOCKED ) + { + return( FALSE ); + } + // Between destination tile and the middle tile next to it... + ubDirection = GetDirectionToGridNoFromGridNo( sInBetween, sGridNo ); + ubMovementCost = gubWorldMovementCosts[ sGridNo ][ ubDirection ][ pSoldier->pathing.bLevel ]; + if ( IS_TRAVELCOST_DOOR( ubMovementCost ) ) + { + ubMovementCost = DoorTravelCost( pSoldier, sGridNo, ubMovementCost, (BOOLEAN) (pSoldier->bTeam == gbPlayerNum), &iDoorGridNo ); + } + if ( ubMovementCost >= TRAVELCOST_BLOCKED ) + { + return( FALSE ); + } + // Now we need to check if there is not a wall between the two middle tiles + ubDirection = GetDirectionToGridNoFromGridNo( sInBetween2, sInBetween ); + switch (ubDirection) + { + case NORTH: + if ( WallOrClosedDoorExistsOfTopLeftOrientation( sInBetween ) ) + return( FALSE ); + break; + case EAST: + if ( WallOrClosedDoorExistsOfTopRightOrientation( sInBetween2 ) ) + return( FALSE ); + break; + case SOUTH: + if ( WallOrClosedDoorExistsOfTopLeftOrientation( sInBetween2 ) ) + return( FALSE ); + break; + case WEST: + if ( WallOrClosedDoorExistsOfTopRightOrientation( sInBetween ) ) + return( FALSE ); + break; + default: + return( FALSE ); + break; + } + + // If we got here, we are good to go + return ( TRUE ); } } } diff --git a/Tactical/Interface Dialogue.cpp b/Tactical/Interface Dialogue.cpp index d0df3541b..6beb53696 100644 --- a/Tactical/Interface Dialogue.cpp +++ b/Tactical/Interface Dialogue.cpp @@ -2024,7 +2024,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum if (pSoldier && pSoldier->inv[HANDPOS].exists() == true) { sGridNo = pSoldier->sGridNo + DirectionInc( pSoldier->ubDirection ); - pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE ); + pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE, FALSE ); } break; @@ -2295,7 +2295,7 @@ void HandleNPCDoAction( UINT8 ubTargetNPC, UINT16 usActionCode, UINT8 ubQuoteNum { SwapObjs( pSoldier, HANDPOS, bItemIn, TRUE ); sGridNo = pSoldier->sGridNo + DirectionInc( pSoldier->ubDirection ); - pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE ); + pSoldier->SoldierReadyWeapon( (INT16) (sGridNo % WORLD_COLS), (INT16) (sGridNo / WORLD_COLS), FALSE, FALSE ); } // fall through so that the person faces the nearest merc! case NPC_ACTION_TURN_TO_FACE_NEAREST_MERC: diff --git a/Tactical/Interface Items.cpp b/Tactical/Interface Items.cpp index fec217845..02e1eb662 100644 --- a/Tactical/Interface Items.cpp +++ b/Tactical/Interface Items.cpp @@ -3735,7 +3735,7 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec // Flugente: If we display the thermometer for overheating, move the ammo counter a bit to the right if ( gGameOptions.fWeaponOverheating == TRUE && gGameExternalOptions.fDisplayOverheatThermometer == TRUE ) - sNewX = sX + 6; + sNewX = sX + 2; //6; // SANDRO - 6 ps too much, 2 are fine // Flugente: check for underbarrel weapons and use that object if necessary OBJECTTYPE* pObjShown = pObject; @@ -3942,8 +3942,19 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec std::map ObjList; GetScopeLists(&pSoldier->inv[HANDPOS], ObjList); - - if (ObjList[pSoldier->bScopeMode] != NULL && IsAttachmentClass(ObjList[pSoldier->bScopeMode]->usItem, AC_SCOPE ) ) + + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD ) + { + BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 55, sNewX, sNewY, VO_BLT_TRANSSHADOW, NULL ); + + SetFontForeground( FONT_ORANGE ); + + if ( uiBuffer == guiSAVEBUFFER ) + { + RestoreExternBackgroundRect( sNewX, sNewY, 15, 15 ); + } + } + else if (ObjList[pSoldier->bScopeMode] != NULL && IsAttachmentClass(ObjList[pSoldier->bScopeMode]->usItem, AC_SCOPE ) ) { BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 54, sNewX, sNewY, VO_BLT_TRANSSHADOW, NULL ); @@ -3990,7 +4001,7 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec mprintf( sMagX, sNewY, pStr ); gprintfinvalidate( sMagX, sNewY, pStr ); } - else if (ObjList[pSoldier->bScopeMode] != NULL && IsAttachmentClass(ObjList[pSoldier->bScopeMode]->usItem, AC_SIGHT ) ) + else if (ObjList[pSoldier->bScopeMode] != NULL && IsAttachmentClass(ObjList[pSoldier->bScopeMode]->usItem, AC_SIGHT ) ) { BltVideoObjectFromIndex( guiSAVEBUFFER, guiItemInfoAdvancedIcon, 53, sNewX, sNewY, VO_BLT_TRANSSHADOW, NULL ); @@ -4086,6 +4097,36 @@ void INVRenderItem( UINT32 uiBuffer, SOLDIERTYPE * pSoldier, OBJECTTYPE *pObjec gprintfinvalidate( sNewX, sNewY, pStr ); } + // 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) && + Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN && + !(Item[ pSoldier->inv[HANDPOS ].usItem ].twohanded ) && + pSoldier->IsValidSecondHandBurst() ) + { + sNewY = sY + 13; // rather arbitrary + if ( pSoldier->bWeaponMode == WM_BURST ) + { + swprintf( pStr, New113Message[MSG113_BRST] ); + SetFontForeground( FONT_RED ); + } + else + { + swprintf( pStr, New113Message[MSG113_AUTO] ); + SetFontForeground( FONT_RED ); + } + // Get length of string + uiStringLength=StringPixLength(pStr, ITEM_FONT ); + + sNewX = sX + sWidth - uiStringLength - 4; + + if ( uiBuffer == guiSAVEBUFFER ) + { + RestoreExternBackgroundRect( sNewX, sNewY, 15, 15 ); + } + mprintf( sNewX, sNewY, pStr ); + gprintfinvalidate( sNewX, sNewY, pStr ); + } // Flugente: display the time left/frequencies on armed bombs (as we can now arm them in our inventory) if( ( (Item[pObject->usItem].usItemClass & (IC_BOMB)) && ( ( (*pObject)[0]->data.misc.bDetonatorType == BOMB_TIMED ) || ( (*pObject)[0]->data.misc.bDetonatorType == BOMB_REMOTE ) ) ) ) @@ -6074,7 +6115,7 @@ void ItemDescAttachmentsCallback( MOUSE_REGION * pRegion, INT32 iReason ) // Flugente: if we altered a gun's attachments, re-evaluate the scope mode and sight if ( gGameExternalOptions.fScopeModes && gpItemPointerSoldier && Item[gpItemDescObject->usItem].usItemClass == IC_GUN ) { - ChangeScopeMode( gpItemPointerSoldier ); + ChangeScopeMode( gpItemPointerSoldier, 0 ); // reevaluate sight ManLooksForOtherTeams( gpItemPointerSoldier ); @@ -9938,7 +9979,7 @@ void ItemPopupRegionCallback( MOUSE_REGION * pRegion, INT32 iReason ) } else { - if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpItemPopupObject->usItem].usItemClass == IC_GUN ) + if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpItemPopupObject->usItem].usItemClass == IC_GUN && (*gpItemPopupObject)[uiItemPos]->data.gun.ubGunShotsLeft > 0 && !(Item[gpItemPopupObject->usItem].singleshotrocketlauncher) ) { EmptyWeaponMagazine( gpItemPopupObject, &gItemPointer, uiItemPos ); InternalMAPBeginItemPointer( gpItemPopupSoldier ); @@ -9949,7 +9990,7 @@ void ItemPopupRegionCallback( MOUSE_REGION * pRegion, INT32 iReason ) } else { - if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpItemPopupObject->usItem].usItemClass == IC_GUN && !(Item[gpItemPopupObject->usItem].singleshotrocketlauncher) && !( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) ) + if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpItemPopupObject->usItem].usItemClass == IC_GUN && (*gpItemPopupObject)[uiItemPos]->data.gun.ubGunShotsLeft > 0 && !(Item[gpItemPopupObject->usItem].singleshotrocketlauncher) && !( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) ) { EmptyWeaponMagazine( gpItemPopupObject, &gItemPointer, uiItemPos ); gpItemPointer = &gItemPointer; diff --git a/Tactical/Interface Panels.cpp b/Tactical/Interface Panels.cpp index 1af9d6020..b624d362a 100644 --- a/Tactical/Interface Panels.cpp +++ b/Tactical/Interface Panels.cpp @@ -2974,7 +2974,7 @@ void RenderSMPanel( BOOLEAN *pfDirty ) { SetFont( TINYFONT1 ); //if ( gpSMCurrentMerc->sLastTarget != NOWHERE && !EnoughPoints( gpSMCurrentMerc, MinAPsToAttack( gpSMCurrentMerc, gpSMCurrentMerc->sLastTarget, FALSE ), 0, FALSE ) || GetUIApsToDisplay( gpSMCurrentMerc ) < 0 ) - if ( !EnoughPoints( gpSMCurrentMerc, MinAPsToAttack( gpSMCurrentMerc, gpSMCurrentMerc->sLastTarget, FALSE ), 0, FALSE ) || GetUIApsToDisplay( gpSMCurrentMerc ) < 0 ) + if ( !EnoughPoints( gpSMCurrentMerc, MinAPsToAttack( gpSMCurrentMerc, gpSMCurrentMerc->sLastTarget, FALSE, 0 ), 0, FALSE ) || GetUIApsToDisplay( gpSMCurrentMerc ) < 0 ) { SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_DKRED ); @@ -4049,9 +4049,9 @@ void SMInvClickCallback( MOUSE_REGION * pRegion, INT32 iReason ) { if ( !InItemDescriptionBox( ) ) { - if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpSMCurrentMerc->inv[ uiHandPos ].usItem].usItemClass == IC_GUN && !( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) ) + if ( _KeyDown(SHIFT) && gpItemPointer == NULL && Item[gpSMCurrentMerc->inv[ uiHandPos ].usItem].usItemClass == IC_GUN && (gpSMCurrentMerc->inv[ uiHandPos ])[uiHandPos]->data.gun.ubGunShotsLeft > 0 && !(Item[gpSMCurrentMerc->inv[ uiHandPos ].usItem].singleshotrocketlauncher) && !( guiTacticalInterfaceFlags & INTERFACE_SHOPKEEP_INTERFACE ) ) { - EmptyWeaponMagazine( &(gpSMCurrentMerc->inv[ uiHandPos ]), &gItemPointer ); + EmptyWeaponMagazine( &(gpSMCurrentMerc->inv[ uiHandPos ]), &gItemPointer, uiHandPos ); gpItemPointer = &gItemPointer; gpItemPointerSoldier = gpSMCurrentMerc; } @@ -5556,7 +5556,7 @@ void RenderTEAMPanel( BOOLEAN fDirty ) SetFont( TINYFONT1 ); //if ( pSoldier->sLastTarget != NOWHERE && !EnoughPoints( pSoldier, MinAPsToAttack( pSoldier, pSoldier->sLastTarget, TRUE ), 0, FALSE ) || GetUIApsToDisplay( pSoldier ) < 0 ) - if ( !EnoughPoints( pSoldier, MinAPsToAttack( pSoldier, pSoldier->sLastTarget, TRUE ), 0, FALSE ) || GetUIApsToDisplay( pSoldier ) < 0 ) + if ( !EnoughPoints( pSoldier, MinAPsToAttack( pSoldier, pSoldier->sLastTarget, TRUE, 0 ), 0, FALSE ) || GetUIApsToDisplay( pSoldier ) < 0 ) { SetFontBackground( FONT_MCOLOR_BLACK ); SetFontForeground( FONT_MCOLOR_DKRED ); diff --git a/Tactical/Interface.cpp b/Tactical/Interface.cpp index 11d7292aa..aeff049f2 100644 --- a/Tactical/Interface.cpp +++ b/Tactical/Interface.cpp @@ -2645,6 +2645,10 @@ BOOLEAN DrawCTHIndicator() // How many bullets are left in the gun? UINT32 uiBulletsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + uiBulletsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), uiBulletsLeft ); + } UINT32 uiCurBullet = uiBulletsLeft; while( uiCurBullet > 0 ) @@ -2899,8 +2903,17 @@ BOOLEAN DrawCTHIndicator() } else { - // grey empty tick - BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 0, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + if (pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) && + ubAllowedLevels - abs((ubAllowedLevels-(x+1))) <= GetNumberAltFireAimLevels( pSoldier, gCTHDisplay.iTargetGridNo ) ) + { + // yellow empty tick + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 2, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + // grey empty tick + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 0, sLeft + sOffset, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } } } @@ -2911,22 +2924,50 @@ BOOLEAN DrawCTHIndicator() INT16 sNewLeft = sLeft + (ubAimFinalOffset * (pSoldier->aiData.bShownAimTime-1)); if (gfDisplayFullCountRing) { - BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } } else { - BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } } // Tick on the right sNewLeft = sLeft + (ubAimFinalOffset * (ubNumSpaces-(pSoldier->aiData.bShownAimTime-1))); if (gfDisplayFullCountRing) { - BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 5, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } } else { - BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bShownAimTime, gCTHDisplay.iTargetGridNo ) ) + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 3, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } + else + { + BltVideoObjectFromIndex( FRAME_BUFFER, guiCTHImage, 1, sNewLeft, sTop, VO_BLT_SRCTRANSPARENCY, NULL ); + } } } diff --git a/Tactical/Items.cpp b/Tactical/Items.cpp index adab0bd0c..c8c35a54e 100644 --- a/Tactical/Items.cpp +++ b/Tactical/Items.cpp @@ -6205,7 +6205,10 @@ BOOLEAN PlaceObject( SOLDIERTYPE * pSoldier, INT8 bPos, OBJECTTYPE * pObj ) pSoldier->bDoBurst = TRUE; pSoldier->bDoAutofire = TRUE; } - pSoldier->bScopeMode = USE_BEST_SCOPE; + if ( Item[pObj->usItem].twohanded && Weapon[pObj->usItem].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; } // Lesh: end @@ -7947,7 +7950,10 @@ BOOLEAN OBJECTTYPE::RemoveAttachment( OBJECTTYPE* pAttachment, OBJECTTYPE * pNew pSoldier->bDoBurst = TRUE; pSoldier->bDoAutofire = 1; } - pSoldier->bScopeMode = USE_BEST_SCOPE; + if ( Item[pSoldier->inv[ HANDPOS ].usItem].twohanded && Weapon[pSoldier->inv[ HANDPOS ].usItem].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; } } @@ -9504,7 +9510,7 @@ INT16 GetAimBonus( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, INT32 iRange, INT1 GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD) bonus = BonusReduceMore( GetItemAimBonus( &Item[ObjList[pSoldier->bScopeMode]->usItem], iRange, ubAimTime ), (*ObjList[pSoldier->bScopeMode])[0]->data.objectStatus ); } else @@ -10271,7 +10277,7 @@ INT16 GetPercentAPReduction( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) bonus += BonusReduceMore( Item[ObjList[pSoldier->bScopeMode]->usItem].percentapreduction, (*ObjList[pSoldier->bScopeMode])[0]->data.objectStatus ); } } @@ -10514,7 +10520,7 @@ INT16 GetVisionRangeBonus( SOLDIERTYPE * pSoldier ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use sScopebonus += BonusReduceMore( Item[ObjList[pSoldier->bScopeMode]->usItem].visionrangebonus, (*ObjList[pSoldier->bScopeMode])[0]->data.objectStatus ); } @@ -10623,7 +10629,7 @@ INT16 GetNightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use sScopebonus += BonusReduceMore( NightBonusScale( Item[ObjList[pSoldier->bScopeMode]->usItem].nightvisionrangebonus, bLightLevel ), @@ -10723,7 +10729,7 @@ INT16 GetCaveVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use sScopebonus += BonusReduceMore( NightBonusScale( Item[ObjList[pSoldier->bScopeMode]->usItem].cavevisionrangebonus, bLightLevel ), @@ -10829,7 +10835,7 @@ INT16 GetDayVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use sScopebonus += BonusReduceMore( idiv( Item[ObjList[pSoldier->bScopeMode]->usItem].dayvisionrangebonus * (NORMAL_LIGHTLEVEL_NIGHT - __max(bLightLevel,NORMAL_LIGHTLEVEL_DAY)), (NORMAL_LIGHTLEVEL_NIGHT-NORMAL_LIGHTLEVEL_DAY) ), @@ -10931,7 +10937,7 @@ INT16 GetBrightLightVisionRangeBonus( SOLDIERTYPE * pSoldier, UINT8 bLightLevel GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use sScopebonus += BonusReduceMore( idiv( Item[ObjList[pSoldier->bScopeMode]->usItem].brightlightvisionrangebonus * (NORMAL_LIGHTLEVEL_DAY - bLightLevel), NORMAL_LIGHTLEVEL_DAY ), @@ -11080,7 +11086,7 @@ UINT8 GetPercentTunnelVision( SOLDIERTYPE * pSoldier ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use bonus += Item[ObjList[pSoldier->bScopeMode]->usItem].percenttunnelvision; } @@ -12153,7 +12159,7 @@ INT16 GetMinRangeForAimBonus( SOLDIERTYPE* pSoldier, OBJECTTYPE * pObj ) GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) bonus = Item[ObjList[pSoldier->bScopeMode]->usItem].minrangeforaimbonus; } else @@ -12184,7 +12190,7 @@ FLOAT GetScopeMagnificationFactor( SOLDIERTYPE *pSoldier, OBJECTTYPE * pObj, FLO GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use BestFactor = Item[ObjList[pSoldier->bScopeMode]->usItem].scopemagfactor; @@ -12227,7 +12233,7 @@ FLOAT GetBestScopeMagnificationFactor( SOLDIERTYPE *pSoldier, OBJECTTYPE * pObj, GetScopeLists(pObj, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL ) + if ( (&pSoldier->inv[HANDPOS]) == pObj && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) // now apply the bonus from the scope we use return max(1.0f, Item[ObjList[pSoldier->bScopeMode]->usItem].scopemagfactor); else @@ -12443,19 +12449,29 @@ UINT8 AllowedAimingLevelsNCTH( SOLDIERTYPE *pSoldier, INT32 sGridNo ) } } - // HEADROCK HAM 4: This modifier from the weapon and its attachments replaces the generic bipod bonus. - UINT8 stance = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; + // SANDRO - scopes are not gonna give us any aim levels when firing from hip etc. + if ( pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) + { + // HEADROCK HAM 4: This modifier from the weapon and its attachments replaces the generic bipod bonus. + UINT8 stance = gAnimControl[ pSoldier->usAnimState ].ubEndHeight; - // Flugente: new feature: if the next tile in our sight direction has a height so that we could rest our weapon on it, we do that, thereby gaining the prone boni instead. This includes bipods - if ( gGameExternalOptions.fWeaponResting && pSoldier->IsWeaponMounted() ) - stance = ANIM_PRONE; + // Flugente: new feature: if the next tile in our sight direction has a height so that we could rest our weapon on it, we do that, thereby gaining the prone boni instead. This includes bipods + if ( gGameExternalOptions.fWeaponResting && pSoldier->IsWeaponMounted() ) + stance = ANIM_PRONE; + + INT32 moda = GetAimLevelsModifier( &pSoldier->inv[pSoldier->ubAttackingHand], stance ); + INT32 modb = GetAimLevelsModifier( &pSoldier->inv[pSoldier->ubAttackingHand], gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); + aimLevels += (INT32) ((gGameExternalOptions.ubProneModifierPercentage * moda + (100 - gGameExternalOptions.ubProneModifierPercentage) * modb)/100); + } - INT32 moda = GetAimLevelsModifier( &pSoldier->inv[pSoldier->ubAttackingHand], stance ); - INT32 modb = GetAimLevelsModifier( &pSoldier->inv[pSoldier->ubAttackingHand], gAnimControl[ pSoldier->usAnimState ].ubEndHeight ); - aimLevels += (INT32) ((gGameExternalOptions.ubProneModifierPercentage * moda + (100 - gGameExternalOptions.ubProneModifierPercentage) * modb)/100); - aimLevels += GetAimLevelsTraitModifier( pSoldier, &pSoldier->inv[pSoldier->ubAttackingHand]); + // however, the alternative stance, reduces number of aim levels on its own + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD ) + { + aimLevels = (aimLevels * (100 - gGameExternalOptions.ubAltWeaponHoldingAimLevelsReduced) + 50) / 100; // round up + } + aimLevels = __max(1, aimLevels); aimLevels = __min(8, aimLevels); @@ -12467,8 +12483,6 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo) if(UsingNewCTHSystem() == true) return AllowedAimingLevelsNCTH(pSoldier, sGridNo); - // SANDRO was here - changed a few things around - UINT8 aimLevels = 4; UINT16 sScopeBonus = 0; BOOLEAN allowed = TRUE; @@ -12602,54 +12616,59 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo) { fUsingBipod = TRUE; } - - // don't break compatibility, let the users choose - if (gGameExternalOptions.iAimLevelsCompatibilityOption != 0) + // SANDRO - scopes are not gonna give us any aim levels when firing from hip etc. + if ( pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) { - sScopeBonus = OldWayOfCalculatingScopeBonus(pSoldier); - } - //WarmSteel - Using scope aimbonus instead, as it is used elsewhere like this too. - //Also, you won't get extra aimclicks anymore if you're too close to use your scope. - //I've externalized the scope types. - else if ( gGameExternalOptions.fAimLevelsDependOnDistance ) - { - if ( gGameExternalOptions.fScopeModes && pSoldier && pSoldier->bTeam == gbPlayerNum && (&pSoldier->inv[pSoldier->ubAttackingHand])->exists() == true && Item[(&pSoldier->inv[pSoldier->ubAttackingHand])->usItem].usItemClass == IC_GUN) + // don't break compatibility, let the users choose + if (gGameExternalOptions.iAimLevelsCompatibilityOption != 0) { - // Flugente: check for scope mode - std::map ObjList; - GetScopeLists(&pSoldier->inv[pSoldier->ubAttackingHand], ObjList); - - // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == &pSoldier->inv[pSoldier->ubAttackingHand] && ObjList[pSoldier->bScopeMode] != NULL ) - sScopeBonus = Item[ObjList[pSoldier->bScopeMode]->usItem].aimbonus; + sScopeBonus = OldWayOfCalculatingScopeBonus(pSoldier); + } + //WarmSteel - Using scope aimbonus instead, as it is used elsewhere like this too. + //Also, you won't get extra aimclicks anymore if you're too close to use your scope. + //I've externalized the scope types. + else if ( gGameExternalOptions.fAimLevelsDependOnDistance ) + { + if ( gGameExternalOptions.fScopeModes && pSoldier && pSoldier->bTeam == gbPlayerNum && (&pSoldier->inv[pSoldier->ubAttackingHand])->exists() == true && Item[(&pSoldier->inv[pSoldier->ubAttackingHand])->usItem].usItemClass == IC_GUN) + { + // Flugente: check for scope mode + std::map ObjList; + GetScopeLists(&pSoldier->inv[pSoldier->ubAttackingHand], ObjList); + + // only use scope mode if gun is in hand, otherwise an error might occur! + if ( (&pSoldier->inv[HANDPOS]) == &pSoldier->inv[pSoldier->ubAttackingHand] && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) + sScopeBonus = Item[ObjList[pSoldier->bScopeMode]->usItem].aimbonus; + } + else + sScopeBonus = GetBaseScopeAimBonus( &pSoldier->inv[pSoldier->ubAttackingHand], uiRange ); } else - sScopeBonus = GetBaseScopeAimBonus( &pSoldier->inv[pSoldier->ubAttackingHand], uiRange ); + { + sScopeBonus = GetMinRangeForAimBonus( pSoldier, &pSoldier->inv[pSoldier->ubAttackingHand]); + } + + if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) + { + aimLevels *= 2; + } + else if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) + { + aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5); + } + else if ( sScopeBonus >= gGameExternalOptions.sMediumPowerScope ) + { + aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.3); + } + // Smaller scopes increase by one. + else if ( sScopeBonus > 0 ) + { + aimLevels++; + } } + // SANDRO - if using alternative weapon holding, we reduce the aim levels available else { - sScopeBonus = GetMinRangeForAimBonus( pSoldier, &pSoldier->inv[pSoldier->ubAttackingHand]); - } - - if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) - { - aimLevels *= 2; - } - - else if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) - { - aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.5); - } - - else if ( sScopeBonus >= gGameExternalOptions.sMediumPowerScope ) - { - aimLevels = (UINT8)((float)(aimLevels+1) * (float)1.3); - } - - // Smaller scopes increase by one. - else if ( sScopeBonus > 0 ) - { - aimLevels++; + aimLevels = (aimLevels * (100 - gGameExternalOptions.ubAltWeaponHoldingAimLevelsReduced) + 50) / 100; // round up } // Make sure not over maximum allowed for weapon type. @@ -12669,47 +12688,51 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo) if ( !IsScoped( pAttackingWeapon ) ) { // No scope. 4 Allowed. - return (4); + aimLevels = 4; } - - //CHRRISL: yeah, this doesn't work. GetMinRangeForAimBonus returns a range value in units while GetBaseScopeAimBonus returns a small number. - // The result is that if fAimLevelsDependOnDistance is false, all scopes are going to grant +4 aim clicks which is definitely not what - // we want to happen. What we do want is simply to know whether we should send the range or use an extreme range value to guarantee that - // the scope is factored. -// sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? -// GetBaseScopeAimBonus( pAttackingWeapon, iRange ) -// : GetMinRangeForAimBonus( pAttackingWeapon ); - if (gGameExternalOptions.iAimLevelsCompatibilityOption != 0) - sScopeBonus = OldWayOfCalculatingScopeBonus(pSoldier); - else + // SANDRO - scopes are not gonna give us any aim levels when firing from hip etc. + else if ( pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) { - if ( gGameExternalOptions.fScopeModes && pSoldier && pSoldier->bTeam == gbPlayerNum && pAttackingWeapon->exists() == true && Item[pAttackingWeapon->usItem].usItemClass == IC_GUN) - { - // Flugente: check for scope mode - std::map ObjList; - GetScopeLists(pAttackingWeapon, ObjList); - - // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pSoldier->inv[HANDPOS]) == pAttackingWeapon && ObjList[pSoldier->bScopeMode] != NULL ) - sScopeBonus = Item[ObjList[pSoldier->bScopeMode]->usItem].aimbonus; - } + //CHRRISL: yeah, this doesn't work. GetMinRangeForAimBonus returns a range value in units while GetBaseScopeAimBonus returns a small number. + // The result is that if fAimLevelsDependOnDistance is false, all scopes are going to grant +4 aim clicks which is definitely not what + // we want to happen. What we do want is simply to know whether we should send the range or use an extreme range value to guarantee that + // the scope is factored. + // sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? + // GetBaseScopeAimBonus( pAttackingWeapon, iRange ) + // : GetMinRangeForAimBonus( pAttackingWeapon ); + if (gGameExternalOptions.iAimLevelsCompatibilityOption != 0) + sScopeBonus = OldWayOfCalculatingScopeBonus(pSoldier); else - sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? GetBaseScopeAimBonus( pAttackingWeapon, uiRange ) : GetBaseScopeAimBonus( pAttackingWeapon, 25000 ); - } + { + if ( gGameExternalOptions.fScopeModes && pSoldier && pSoldier->bTeam == gbPlayerNum && pAttackingWeapon->exists() == true && Item[pAttackingWeapon->usItem].usItemClass == IC_GUN) + { + // Flugente: check for scope mode + std::map ObjList; + GetScopeLists(pAttackingWeapon, ObjList); + + // only use scope mode if gun is in hand, otherwise an error might occur! + if ( (&pSoldier->inv[HANDPOS]) == pAttackingWeapon && ObjList[pSoldier->bScopeMode] != NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD ) + sScopeBonus = Item[ObjList[pSoldier->bScopeMode]->usItem].aimbonus; + } + else + sScopeBonus = gGameExternalOptions.fAimLevelsDependOnDistance ? GetBaseScopeAimBonus( pAttackingWeapon, uiRange ) : GetBaseScopeAimBonus( pAttackingWeapon, 25000 ); + } - if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) - { - aimLevels += 2; - } - if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) - { - aimLevels += 2; - } - // SANDRO - STOMP traits - Sniper bonus aim clicks - if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && - gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) - { - aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + if ( sScopeBonus >= gGameExternalOptions.sVeryHighPowerScope ) + { + aimLevels += 2; + } + if ( sScopeBonus >= gGameExternalOptions.sHighPowerScope ) + { + aimLevels += 2; + } + + // SANDRO - STOMP traits - Sniper bonus aim clicks + if ((weaponType == GUN_AS_RIFLE || weaponType == GUN_RIFLE || weaponType == GUN_SN_RIFLE) && + gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, SNIPER_NT ) ) + { + aimLevels += (gSkillTraitValues.ubSNAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, SNIPER_NT )); + } } // SANDRO - STOMP traits - Gunslinger bonus aim clicks if ((weaponType == GUN_PISTOL || weaponType == GUN_M_PISTOL) && @@ -12717,6 +12740,13 @@ UINT8 AllowedAimingLevels(SOLDIERTYPE * pSoldier, INT32 sGridNo) { aimLevels += (gSkillTraitValues.ubGSAimClicksAdded * NUM_SKILL_TRAITS( pSoldier, GUNSLINGER_NT )); } + + // SANDRO - if using alternative weapon holding, we reduce the aim levels available + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && gGameExternalOptions.fScopeModes ) + { + aimLevels /= 2; + } + //CHRISL: The system can't currently support more then 8 aim levels so make sure we can never have more then 8 aimLevels = min(8, aimLevels); } @@ -14209,4 +14239,69 @@ BOOLEAN DeductBulletViaExternalFeeding(SOLDIERTYPE* pSoldier, OBJECTTYPE * pObje } return( FALSE ); +} + +INT8 GetNumberAltFireAimLevels( SOLDIERTYPE * pSoldier, INT32 iGridNo ) +{ + if ( !gGameExternalOptions.ubAllowAlternativeWeaponHolding || (gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_STAND) ) + { + return -1; + } + + UINT16 usInHand = pSoldier->inv[ HANDPOS ].usItem; + + // If we are in water and having a pistol, don't allow alternative fire at all + if ( !Item[usInHand].twohanded && pSoldier->MercInWater() ) + { + return -1; + } + + UINT8 ubStandardAimLvls = AllowedAimingLevels( pSoldier, iGridNo ); + + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 1 ) + { + // only with no aim clicks at all + return 0; + } + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + { + // with this mode, we always switch aaiming type manually + return ubStandardAimLvls; + } + else if ( Weapon[usInHand].HeavyGun && Item[usInHand].twohanded) + { + // if this gun is flagged as too heavy to shoulder, return the same as standard aim levels + return ubStandardAimLvls; + } + + // from here, we assume we are using "hybrid" aiming mechanism, so calculate how many alternative aim levels we have + INT8 bAltAimLevels = 0; + switch ( ubStandardAimLvls ) + { + case 8: + case 7: + bAltAimLevels = 3; + break; + case 6: + case 5: + bAltAimLevels = 2; + break; + case 4: + case 3: + bAltAimLevels = 1; + break; + default: + bAltAimLevels = 0; + break; + } + // make LMGs more likely to be fired from hip + if ( Weapon[usInHand].ubWeaponType == GUN_LMG && ubStandardAimLvls > 6 ) + bAltAimLevels += 1; + if ( Weapon[usInHand].ubWeaponType == GUN_LMG && ubStandardAimLvls > 2 ) + bAltAimLevels += 1; + // shotguns may also be more a little more suitable for it + if ( Weapon[usInHand].ubWeaponType == GUN_SHOTGUN && ubStandardAimLvls > 4 ) + bAltAimLevels += 1; + + return bAltAimLevels ; } \ No newline at end of file diff --git a/Tactical/Items.h b/Tactical/Items.h index 436852f39..768075244 100644 --- a/Tactical/Items.h +++ b/Tactical/Items.h @@ -481,4 +481,10 @@ BOOLEAN DeductBulletViaExternalFeeding(SOLDIERTYPE* pSoldier, OBJECTTYPE * pObje //DBrot: get the volume of all attached pouches UINT8 GetVolumeAlreadyTaken(OBJECTTYPE * pObj); INT16 GetPocketFromAttachment(OBJECTTYPE * pObj, UINT8 pMap); + +INT8 GetNumberAltFireAimLevels( SOLDIERTYPE * pSoldier, INT32 iGridNo ); + #endif + + + diff --git a/Tactical/LOS.cpp b/Tactical/LOS.cpp index a06d1ad68..8a997fcf1 100644 --- a/Tactical/LOS.cpp +++ b/Tactical/LOS.cpp @@ -2694,7 +2694,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend } // check to see if the guy is a friendly?..if so, up the number of times wounded - if( ( pTarget->bTeam == gbPlayerNum ) ) + if( ( pTarget->bTeam == gbPlayerNum ) && iDamage > 1 ) // damage of 1 is just a scratch, not a real wound { if ( pBullet->usFlags & BULLET_FLAG_BUCKSHOT ) { @@ -2702,7 +2702,7 @@ BOOLEAN BulletHitMerc( BULLET * pBullet, STRUCTURE * pStructure, BOOLEAN fIntend if ( pTarget->bNumPelletsHitBy == 0 ) gMercProfiles[ pTarget->ubProfile ].records.usTimesWoundedShot++; } - else if ( iDamage > 1 ) // damage of 1 is just a scratch, not a real wound + else { if ( pBullet->usFlags & BULLET_FLAG_KNIFE ) gMercProfiles[ pTarget->ubProfile ].records.usTimesWoundedStabbed++; @@ -4141,6 +4141,10 @@ INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, OBJECTTYPE* pObjAttHand = pFirer->GetUsedWeapon( &(pFirer->inv[pFirer->ubAttackingHand]) ); + BOOLEAN fSecondHandBurst = FALSE; + if ( pFirer->ubAttackingHand == SECONDHANDPOS && pFirer->IsValidSecondHandBurst() ) + fSecondHandBurst = TRUE; + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBulletGivenTarget")); CalculateSoldierZPos( pFirer, FIRING_POS, &dStartZ ); @@ -4468,7 +4472,7 @@ INT8 FireBulletGivenTargetNCTH( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, pBullet->ddHorizAngle = ddHorizAngle; - if (ubLoop == 0 && pFirer->bDoBurst < 2) + if (ubLoop == 0 && (pFirer->bDoBurst < 2 || (fSecondHandBurst && pFirer->bDoBurst == 2))) { pBullet->fAimed = TRUE; } @@ -4617,6 +4621,10 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA OBJECTTYPE* pObjAttHand = pFirer->GetUsedWeapon( &(pFirer->inv[pFirer->ubAttackingHand]) ); + BOOLEAN fSecondHandBurst = FALSE; + if ( pFirer->ubAttackingHand == SECONDHANDPOS && pFirer->IsValidSecondHandBurst() ) + fSecondHandBurst = TRUE; + //DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("FireBulletGivenTarget")); CalculateSoldierZPos( pFirer, FIRING_POS, &dStartZ ); @@ -4970,7 +4978,7 @@ INT8 FireBulletGivenTarget( SOLDIERTYPE * pFirer, FLOAT dEndX, FLOAT dEndY, FLOA pBullet->ddHorizAngle = ddHorizAngle; - if (ubLoop == 0 && pFirer->bDoBurst < 2) + if (ubLoop == 0 && pFirer->bDoBurst < 2 || (fSecondHandBurst && pFirer->bDoBurst == 2)) { pBullet->fAimed = TRUE; } @@ -7360,6 +7368,10 @@ BOOLEAN CalculateLOSNormal( STRUCTURE *pStructure, INT8 bLOSX, INT8 bLOSY, INT8 void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT *dEndX, FLOAT *dEndY, FLOAT *dEndZ, OBJECTTYPE *pWeapon, UINT32 uiMuzzleSway, INT16 *sApertureRatio ) { SOLDIERTYPE *pTarget = SimpleFindSoldier( iTargetGridNo, pShooter->bTargetLevel ); + BOOLEAN fSecondHandBurst = FALSE; + + if ( pShooter->ubAttackingHand == SECONDHANDPOS && pShooter->IsValidSecondHandBurst() ) + fSecondHandBurst = TRUE; /////////////////////////////////////////// // Calculate shooter's coordinates @@ -7452,7 +7464,7 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT // Note that both optical magnification devices (like scopes) and dot-projection devices (like lasers and // reflex sights) provide this sort of bonus. - FLOAT iMagFactor = CalcMagFactor( pShooter, pWeapon, d2DDistance, (UINT8)pShooter->aiData.bAimTime ); + FLOAT iMagFactor = CalcMagFactor( pShooter, pWeapon, d2DDistance, iTargetGridNo, (UINT8)pShooter->aiData.bAimTime ); // Next step is to apply scope/projection factor to decrease the size of the aperture. This gives us the "Max // Aperture" value - the size of the shooting circle if the gun is as unstable as possible. @@ -7483,7 +7495,7 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT // As you'll see, this allows the shooter to readjust the weapon WHILE it is firing, rather than randomize // muzzle movements every time. - if (pShooter->bDoBurst <= 1) + if (pShooter->bDoBurst <= 1 || (fSecondHandBurst && pShooter->bDoBurst == 2)) { /////////////////////////////////////////////////////////////////////////////////////////// @@ -7520,12 +7532,14 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT ///////////////////////////////////////////// // First shot in a burst/auto volley - if (pShooter->bDoBurst == 1 || pShooter->bDoAutofire > 1) + if (pShooter->bDoBurst == 1 || pShooter->bDoAutofire > 1 || (fSecondHandBurst && pShooter->bDoBurst == 2)) { // A shooter does not get to exercise counter-force on the first few bullets in a volley. // These commands reset the counter-force. - pShooter->dPrevCounterForceX = 0.0; - pShooter->dPrevCounterForceY = 0.0; + pShooter->dPrevCounterForceX[0] = 0.0; + pShooter->dPrevCounterForceX[1] = 0.0; + pShooter->dPrevCounterForceY[0] = 0.0; + pShooter->dPrevCounterForceY[1] = 0.0; //////////////////////////////////////////////////////////////////////////////////////////// // STEP 4: Pre-Compensating for Future Recoil @@ -7552,8 +7566,16 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT // In a Burst/Autofire volley, we do not need to recalculate muzzle sway or target movement offsets and // other related muzzle movements. Instead, we inherit the muzzle offset variables from the previous bullet // in the volley. - dMuzzleOffsetX = pShooter->dPrevMuzzleOffsetX; - dMuzzleOffsetY = pShooter->dPrevMuzzleOffsetY; + if ( fSecondHandBurst ) + { + dMuzzleOffsetX = pShooter->dPrevMuzzleOffsetX[1]; + dMuzzleOffsetY = pShooter->dPrevMuzzleOffsetY[1]; + } + else + { + dMuzzleOffsetX = pShooter->dPrevMuzzleOffsetX[0]; + dMuzzleOffsetY = pShooter->dPrevMuzzleOffsetY[0]; + } //////////////////////////////////////////////////////////////////////////////////////////// // STEP 4: Recoil Offset @@ -7580,15 +7602,25 @@ void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT // just remember were our muzzle was pointed last, and proceed from there. This allows volleys to be adjusted // while they're being fired, with the hope of redirecting the muzzle towards the center of the target if // the first shot was off-center. - pShooter->dPrevMuzzleOffsetX = dMuzzleOffsetX; - pShooter->dPrevMuzzleOffsetY = dMuzzleOffsetY; + if ( fSecondHandBurst ) + { + pShooter->dPrevMuzzleOffsetX[1] = dMuzzleOffsetX; + pShooter->dPrevMuzzleOffsetY[1] = dMuzzleOffsetY; + } + else + { + pShooter->dPrevMuzzleOffsetX[0] = dMuzzleOffsetX; + pShooter->dPrevMuzzleOffsetY[0] = dMuzzleOffsetY; + } } else { // Single-shot fire does not require storing Muzzle Offset for later use. The next fired bullet will calculate // its own offsets. To be on the safe side, we reset the Muzzle Offset values stored in the shooter's data. - pShooter->dPrevMuzzleOffsetX = 0; - pShooter->dPrevMuzzleOffsetY = 0; + pShooter->dPrevMuzzleOffsetX[0] = 0; + pShooter->dPrevMuzzleOffsetX[1] = 0; + pShooter->dPrevMuzzleOffsetY[0] = 0; + pShooter->dPrevMuzzleOffsetY[1] = 0; } UINT16 uiRange = GunRange(pWeapon, pShooter); @@ -7727,7 +7759,7 @@ FLOAT CalcProjectionFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2 GetScopeLists(pWeapon, ObjList); // only use scope mode if gun is in hand, otherwise an error might occur! - if ( (&pShooter->inv[HANDPOS]) == pWeapon ) + if ( (&pShooter->inv[HANDPOS]) == pWeapon && ObjList[pShooter->bScopeMode] != NULL && pShooter->bScopeMode != USE_ALT_WEAPON_HOLD ) iProjectionFactor = Item[ObjList[pShooter->bScopeMode]->usItem].projectionfactor; } else @@ -7743,16 +7775,18 @@ FLOAT CalcProjectionFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2 return iProjectionFactor; } -FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, UINT8 ubAimTime ) +FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, INT32 iTargetGridNo, UINT8 ubAimTime ) { FLOAT iFinalMagFactor = 1.0; - FLOAT iScopeFactor = 0; + FLOAT iScopeFactor = 1.0; FLOAT iProjectionFactor = 0; // Flugente: if scope modes are allowed, player team uses them. We either use a scope or we don't, so the magnification factor isn't fitted to range (this is actually bad) if ( gGameExternalOptions.fScopeModes && pShooter && pShooter->bTeam == gbPlayerNum && pWeapon->exists() == true && Item[pWeapon->usItem].usItemClass == IC_GUN ) { - iScopeFactor = GetBestScopeMagnificationFactor( pShooter, pWeapon, d2DDistance ); + if (!pShooter->IsValidAlternativeFireMode( ubAimTime, iTargetGridNo ) ) + iScopeFactor = GetBestScopeMagnificationFactor( pShooter, pWeapon, d2DDistance ); + iProjectionFactor = CalcProjectionFactor(pShooter, pWeapon, d2DDistance, ubAimTime); iFinalMagFactor = __max(iScopeFactor, iProjectionFactor); } @@ -7763,8 +7797,11 @@ FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistan if (ubAimTime > 0) { - iScopeFactor = GetBestScopeMagnificationFactor( pShooter, pWeapon, d2DDistance ); - iScopeFactor = __min(iScopeFactor, __max(1.0f, iTargetMagFactor/rangeModifier)); + if (!pShooter->IsValidAlternativeFireMode( ubAimTime, iTargetGridNo ) ) + { + iScopeFactor = GetBestScopeMagnificationFactor( pShooter, pWeapon, d2DDistance ); + iScopeFactor = __min(iScopeFactor, __max(1.0f, iTargetMagFactor/rangeModifier)); + } iProjectionFactor = CalcProjectionFactor(pShooter, pWeapon, d2DDistance, ubAimTime); iFinalMagFactor = __max(iScopeFactor, iProjectionFactor); } @@ -8420,6 +8457,21 @@ UINT32 CalcCounterForceFrequency(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon) gGameCTHConstants.RECOIL_COUNTER_FREQUENCY_EXP_LEVEL; iCounterForceFrequency /= iDivisor; + // SAMDRO - shooting dual bursts is somehow harder to control, unless we are ambidextrous + if ( pShooter->IsValidSecondHandBurst() ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if ( !(HAS_SKILL_TRAIT( pShooter, AMBIDEXTROUS_NT )) ) + iCounterForceFrequency = iCounterForceFrequency*9/10; // -10% + } + else + { + if ( !(HAS_SKILL_TRAIT( pShooter, AMBIDEXT_OT )) ) + iCounterForceFrequency = iCounterForceFrequency*9/10; // -10% + } + } + // Bridge the gap to 100 with the help of the AUTO-WEAPONS skill if(gGameOptions.fNewTraitSystem) traitLoop = NUM_SKILL_TRAITS( pShooter, AUTO_WEAPONS_NT ); @@ -8520,6 +8572,21 @@ UINT32 CalcCounterForceAccuracy(SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, UINT UINT32 uiCounterForceAccuracy = (UINT32)(iCounterForceAccuracy + ((iCounterForceAccuracy * iModifier) / 100)); + // SANDRO - shooting dual bursts is somehow harder to control, unless we are ambidextrous + if ( pShooter->IsValidSecondHandBurst() ) + { + if ( gGameOptions.fNewTraitSystem ) + { + if ( !(HAS_SKILL_TRAIT( pShooter, AMBIDEXTROUS_NT )) ) + uiCounterForceAccuracy = uiCounterForceAccuracy*9/10; // -10% + } + else + { + if ( !(HAS_SKILL_TRAIT( pShooter, AMBIDEXT_OT )) ) + uiCounterForceAccuracy = uiCounterForceAccuracy*9/10; // -10% + } + } + // Now add the effect of the AutoWeapons skill. It "bridges" a portion of the gap between shooter's actual accuracy // and 100% accuracy. For instance, if the divisor is set to 2 in the INI, the first skill level will close 50% of // the gap, the second skill level closes another 25%. @@ -8811,14 +8878,27 @@ void CalcPreRecoilOffset( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT *dMu // Also, lets set our shooter's Counter Force variables. These will apply for the next bullet in the // volley. - pShooter->dPrevCounterForceX = dCounterForceX; - pShooter->dPrevCounterForceY = dCounterForceY; + if ( pShooter->ubAttackingHand == SECONDHANDPOS && pShooter->IsValidSecondHandBurst() ) + { + pShooter->dPrevCounterForceX[1] = dCounterForceX; + pShooter->dPrevCounterForceY[1] = dCounterForceY; + } + else + { + pShooter->dPrevCounterForceX[0] = dCounterForceX; + pShooter->dPrevCounterForceY[0] = dCounterForceY; + } } // Calculate Recoil Offset void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuzzleOffsetY, OBJECTTYPE *pWeapon, UINT32 uiRange ) { + FLOAT dAppliedCounterForceX, dAppliedCounterForceY; + FLOAT dCounterForceChangeX, dCounterForceChangeY; + BOOLEAN fSecondHandBurst = FALSE; + if ( pShooter->ubAttackingHand == SECONDHANDPOS && pShooter->IsValidSecondHandBurst() ) + fSecondHandBurst = TRUE; ////////////////////////////////////////////////////////////////////////////////////// // Recoil Calculation // @@ -8838,7 +8918,10 @@ void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuz INT8 bGunRecoilX; INT8 bGunRecoilY; - GetRecoil( pShooter, pWeapon, &bGunRecoilX, &bGunRecoilY, pShooter->bDoBurst-1 ); + if( fSecondHandBurst ) + GetRecoil( pShooter, pWeapon, &bGunRecoilX, &bGunRecoilY, (pShooter->bDoBurst/2-2) ); + else + GetRecoil( pShooter, pWeapon, &bGunRecoilX, &bGunRecoilY, pShooter->bDoBurst-1 ); // If no recoil, then we shouldn't be here anyway. if(bGunRecoilX == 0 && bGunRecoilY == 0) @@ -8847,8 +8930,16 @@ void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuz FLOAT dDistanceRatio = (FLOAT)uiRange / (FLOAT)gGameCTHConstants.NORMAL_RECOIL_DISTANCE; // These variables will hold the amount of X/Y force our shooter exerts to try to fight recoil. - FLOAT dAppliedCounterForceX = pShooter->dPrevCounterForceX; - FLOAT dAppliedCounterForceY = pShooter->dPrevCounterForceY; + if ( fSecondHandBurst ) + { + dAppliedCounterForceX = pShooter->dPrevCounterForceX[1]; + dAppliedCounterForceY = pShooter->dPrevCounterForceY[1]; + } + else + { + dAppliedCounterForceX = pShooter->dPrevCounterForceX[0]; + dAppliedCounterForceY = pShooter->dPrevCounterForceY[0]; + } BOOLEAN fTracer = WasPrevBulletATracer( pShooter, pWeapon ); @@ -8940,11 +9031,24 @@ void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuz // target regardless of CF accuracy. // For more explanation read the comments inside the following function: - - // CALCULATE FOR X - FLOAT dCounterForceChangeX = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetX / dDistanceRatio, bGunRecoilX, pShooter->dPrevCounterForceX, uiIntendedBullets ); - // CALCULATE FOR Y - FLOAT dCounterForceChangeY = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetY / dDistanceRatio, bGunRecoilY, pShooter->dPrevCounterForceY, uiIntendedBullets ); + if ( fSecondHandBurst ) + { + dAppliedCounterForceX = pShooter->dPrevCounterForceX[1]; + dAppliedCounterForceY = pShooter->dPrevCounterForceY[1]; + // CALCULATE FOR X + dCounterForceChangeX = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetX / dDistanceRatio, bGunRecoilX, pShooter->dPrevCounterForceX[1], uiIntendedBullets ); + // CALCULATE FOR Y + dCounterForceChangeY = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetY / dDistanceRatio, bGunRecoilY, pShooter->dPrevCounterForceY[1], uiIntendedBullets ); + } + else + { + dAppliedCounterForceX = pShooter->dPrevCounterForceX[0]; + dAppliedCounterForceY = pShooter->dPrevCounterForceY[0]; + // CALCULATE FOR X + dCounterForceChangeX = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetX / dDistanceRatio, bGunRecoilX, pShooter->dPrevCounterForceX[0], uiIntendedBullets ); + // CALCULATE FOR Y + dCounterForceChangeY = CalcCounterForceChange( pShooter, uiCounterForceAccuracy, dCounterForceMax, *dMuzzleOffsetY / dDistanceRatio, bGunRecoilY, pShooter->dPrevCounterForceY[0], uiIntendedBullets ); + } dAppliedCounterForceX += dCounterForceChangeX; dAppliedCounterForceY += dCounterForceChangeY; @@ -8966,8 +9070,16 @@ void CalcRecoilOffset( SOLDIERTYPE *pShooter, FLOAT *dMuzzleOffsetX, FLOAT *dMuz // Record how much counter force was applied this time. It will be used for the next few shots until the // shooter can recalculate. - pShooter->dPrevCounterForceX = dAppliedCounterForceX; - pShooter->dPrevCounterForceY = dAppliedCounterForceY; + if ( fSecondHandBurst ) + { + pShooter->dPrevCounterForceX[1] = dAppliedCounterForceX; + pShooter->dPrevCounterForceY[1] = dAppliedCounterForceY; + } + else + { + pShooter->dPrevCounterForceX[0] = dAppliedCounterForceX; + pShooter->dPrevCounterForceY[0] = dAppliedCounterForceY; + } dAppliedCounterForceX += (FLOAT)bGunRecoilX; dAppliedCounterForceY += (FLOAT)bGunRecoilY; @@ -9221,7 +9333,12 @@ FLOAT CalcCounterForceChange( SOLDIERTYPE * pShooter, UINT32 uiCounterForceAccur // However, before using these values we need to ask: are we actually intending to // fire that many bullets? - UINT32 uiRoundsRemaining = uiIntendedBullets - (pShooter->bDoBurst - 1); + UINT32 uiRoundsRemaining; + if ( pShooter->ubAttackingHand == SECONDHANDPOS && pShooter->IsValidSecondHandBurst() ) + uiRoundsRemaining = uiIntendedBullets - (pShooter->bDoBurst/2 - 2); + else + uiRoundsRemaining = uiIntendedBullets - (pShooter->bDoBurst - 1); + BOOLEAN fEnoughBullets = true; if (uiRoundsRemaining < uiStepsToReachTargetWhileDecelerating) { diff --git a/Tactical/LOS.h b/Tactical/LOS.h index 834a0610e..2a405758d 100644 --- a/Tactical/LOS.h +++ b/Tactical/LOS.h @@ -219,7 +219,7 @@ extern INT32 GetSpreadPattern( OBJECTTYPE * pObj ); // HEADROCK HAM 4: The following functions are all part of the NCTH project, // which completely redesigns the way we calculate and handle CTH for the purposes of firing weapons. void AdjustTargetCenterPoint( SOLDIERTYPE *pShooter, INT32 iTargetGridNo, FLOAT *dEndX, FLOAT *dEndY, FLOAT *dEndZ, OBJECTTYPE *pWeapon, UINT32 uiMuzzleSway, INT16 *sApertureRatio ); -FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, UINT8 ubAimTime ); +FLOAT CalcMagFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, INT32 iTargetGridNo, UINT8 ubAimTime ); FLOAT CalcProjectionFactor( SOLDIERTYPE *pShooter, OBJECTTYPE *pWeapon, FLOAT d2DDistance, UINT8 ubAimTime ); FLOAT CalcBasicAperture(); void CalcTargetMovementOffset( SOLDIERTYPE *pShooter, SOLDIERTYPE *pTarget, OBJECTTYPE *pWeapon, FLOAT *dMuzzleOffsetX, DOUBLE ddShootingAngle, INT32 iAperture ); diff --git a/Tactical/Overhead Types.h b/Tactical/Overhead Types.h index baf80fa03..0fdca13f9 100644 --- a/Tactical/Overhead Types.h +++ b/Tactical/Overhead Types.h @@ -12,7 +12,8 @@ #define REFINE_AIM_4 6 #define REFINE_AIM_MID4 7 #define REFINE_AIM_5 8 -#define REFINE_AIM_BURST 10 +#define REFINE_AIM_BURST -1 // SANDRO - I've changed this from 10 to -1, so when the code asks about how much we aim, it does not return this high value when we don't aim at all + // hopefully, it will not cause any troubles anywhere .. it shouldn't #define AIM_SHOT_RANDOM 0 #define AIM_SHOT_HEAD 1 diff --git a/Tactical/Overhead.cpp b/Tactical/Overhead.cpp index f04c7edda..6727fc397 100644 --- a/Tactical/Overhead.cpp +++ b/Tactical/Overhead.cpp @@ -197,7 +197,7 @@ void MilitiaChangesSides( void ); extern void CheckForAlertWhenEnemyDies( SOLDIERTYPE * pDyingSoldier ); extern void PlaySoldierFootstepSound( SOLDIERTYPE *pSoldier ); extern void HandleKilledQuote( SOLDIERTYPE *pKilledSoldier, SOLDIERTYPE *pKillerSoldier, INT32 sGridNo, INT8 bLevel ); -extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); extern void PlayStealthySoldierFootstepSound( SOLDIERTYPE *pSoldier ); @@ -1388,8 +1388,13 @@ BOOLEAN ExecuteOverhead( ) pSoldier->bReverse = FALSE; BOOLEAN fAimAfterMove = FALSE; - if ( pSoldier->usAnimState == SIDE_STEP_PISTOL_RDY || pSoldier->usAnimState == SIDE_STEP_RIFLE_RDY || - pSoldier->usAnimState == WALKING_PISTOL_RDY || pSoldier->usAnimState == WALKING_RIFLE_RDY ) + if ( pSoldier->usAnimState == WALKING_ALTERNATIVE_RDY || pSoldier->usAnimState == SIDE_STEP_ALTERNATIVE_RDY ) + { + fAimAfterMove = TRUE; + pSoldier->usPendingAnimation = AIM_ALTERNATIVE_STAND; + pSoldier->ubPendingDirection = pSoldier->ubDirection; + } + else if ( pSoldier->usAnimState == SIDE_STEP_WEAPON_RDY || pSoldier->usAnimState == WALKING_WEAPON_RDY ) { fAimAfterMove = TRUE; pSoldier->usPendingAnimation = AIM_RIFLE_STAND; @@ -1409,7 +1414,7 @@ BOOLEAN ExecuteOverhead( ) } // ATE: Play landing sound..... - if ( pSoldier->usAnimState == JUMP_OVER_BLOCKING_PERSON ) + if ( pSoldier->usAnimState == JUMP_OVER_BLOCKING_PERSON || pSoldier->usAnimState == LONG_JUMP ) { PlaySoldierFootstepSound( pSoldier ); } @@ -1842,9 +1847,9 @@ BOOLEAN ExecuteOverhead( ) // For walking, base it on body type! if ( pSoldier->usAnimState == WALKING || - pSoldier->usAnimState == WALKING_PISTOL_RDY || - pSoldier->usAnimState == WALKING_RIFLE_RDY || - pSoldier->usAnimState == WALKING_DUAL_RDY ) + pSoldier->usAnimState == WALKING_WEAPON_RDY || + pSoldier->usAnimState == WALKING_DUAL_RDY || + pSoldier->usAnimState == WALKING_ALTERNATIVE_RDY ) { pSoldier->MoveMerc( gubAnimWalkSpeeds[ pSoldier->ubBodyType ].dMovementChange, dAngle, TRUE ); @@ -2270,6 +2275,9 @@ BOOLEAN HandleGotoNewGridNo( SOLDIERTYPE *pSoldier, BOOLEAN *pfKeepMoving, BOOLE // Find out how much it takes to move here! sAPCost = ActionPointCost( pSoldier, usNewGridNo, (INT8)pSoldier->pathing.usPathingData[ pSoldier->pathing.usPathIndex ], usAnimState ); sBPCost = TerrainBreathPoints( pSoldier, usNewGridNo, (INT8)pSoldier->pathing.usPathingData[ pSoldier->pathing.usPathIndex ], usAnimState ); + // SANDRO: add BP cost for weapon holding (additional for APBPConstants[BP_MOVEMENT_READY]), this one is specifically based on the weapon itself + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + sBPCost += sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; // CHECK IF THIS TILE IS A GOOD ONE! if ( !HandleNextTile( pSoldier, (INT8)pSoldier->pathing.usPathingData[ pSoldier->pathing.usPathIndex ], usNewGridNo, pSoldier->pathing.sFinalDestination ) ) @@ -6899,7 +6907,7 @@ BOOLEAN CheckForEndOfBattle( BOOLEAN fAnEnemyRetreated ) else { // If they are aiming, end aim! - usAnimState = PickSoldierReadyAnimation( pTeamSoldier, TRUE ); + usAnimState = PickSoldierReadyAnimation( pTeamSoldier, TRUE, FALSE ); if ( usAnimState != INVALID_ANIMATION ) { @@ -7808,6 +7816,48 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) //HEADROCK HAM 3.5: Ratio between AP Loss and Suppression Shock UINT16 uiShockPerAPLossDivisor = APBPConstants[AP_SUPPRESSION_SHOCK_DIVISOR]; + //////////////////////////////////////////////////////////////////////////////////////////////////// + // SANDRO - modify suppression effectiveness based on weapon caliber (i.e. damage) + INT16 sFinalSuppressionEffectiveness = gGameExternalOptions.sSuppressionEffectiveness; + pSoldier = MercPtrs[ubCausedAttacker]; + if ( Item[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].usItemClass == IC_GUN ) + { + // +1% per point above 20 impact + if ( Weapon[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].ubImpact > 20 ) + { + sFinalSuppressionEffectiveness += (Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubImpact - 20); + } + // +2% per point above 30 impact + if ( Weapon[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].ubImpact > 30 ) + { + sFinalSuppressionEffectiveness += (Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubImpact - 30); + } + // +3% per point above 40 impact + if ( Weapon[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].ubImpact > 40 ) + { + sFinalSuppressionEffectiveness += (Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubImpact - 40); + } + // +4% per point above 50 impact, some crazy gun here + if ( Weapon[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].ubImpact > 50 ) + { + sFinalSuppressionEffectiveness += (Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubImpact - 50); + } + + // add a small bonus to effectiveness based on weapon loudness + UINT8 ubGunVolume = Weapon[ pSoldier->inv[pSoldier->ubAttackingHand].usItem ].ubAttackVolume; + ubGunVolume = __max( 1, ( ubGunVolume * GetPercentNoiseVolume( pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] ) ) ) / 100 ); + if ( ubGunVolume >= 50 ) + { + if ( ubGunVolume < 70 ) // up to 5% + sFinalSuppressionEffectiveness += ((ubGunVolume - 50)/4); + else if ( ubGunVolume < 85 ) // 5% to 10% + sFinalSuppressionEffectiveness += (5 + (ubGunVolume - 70)/3); + else // 10% to 25% (extremely noisy weaponry) + sFinalSuppressionEffectiveness += (10 + (ubGunVolume - 85)); + } + } + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Loop through every character. for (uiLoop = 0; uiLoop < guiNumMercSlots; uiLoop++) { @@ -7846,7 +7896,7 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) // To turn off the entire Suppression system, simply set the INI value to 0. (0% AP Loss) // The default is obviously 100%. You can increase or decrease it, at will. // PLEASE NOTE that AP loss governs ALL OTHER SUPPRESSION EFFECTS. - ubPointsLost = ( ubPointsLost * gGameExternalOptions.sSuppressionEffectiveness ) / 100; + ubPointsLost = ( ubPointsLost * sFinalSuppressionEffectiveness ) / 100; // This is an upper cap for the number of APs we can lose per attack. if (usLimitSuppressionAPsLostPerAttack > 0) @@ -7907,16 +7957,13 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) } // Else, original shock was already over the limit. No more shock is added. } - } // HEADROCK: Cowering is the panic that grips a character due to suffering too much suppression shock. If // enough shock has been accumulated, the soldier goes into this panic. Generally, cowering will cause // the character to drop a stance if he can, overriding other conditions for a stance-change (see below). // Cowering characters may become considerably easier to suppress with additional firepower. In other // words, if you're cowering, you've effectively turned from a bad-ass to a wimp. - fCower = false; - if ( gGameExternalOptions.usSuppressionShockEffect > 0 ) - { + fCower = false; // SANDRO - STOMP traits INT8 bShockForCower = pSoldier->aiData.bShock; if ( gGameOptions.fNewTraitSystem ) @@ -7969,16 +8016,53 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) { case ANIM_PRONE: // can't change stance below prone! + // SANDRO - added cower animation when prone (made by Pashancock) + if ( fCower ) + { + if ( pSoldier->usAnimState == COWERING_PRONE ) // if cowering alread, do nothing + { + ubNewStance = 0; + } + else + { + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_PRONE, 0 , FALSE ); + ubNewStance = 0; + } + } break; case ANIM_CROUCH: - if (ubPointsLost >= GetAPsProne(pSoldier, TRUE) && IsValidStance( pSoldier, ANIM_PRONE ) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) // SANDRO - changed to GetAPsProne + if (ubPointsLost >= GetAPsProne(pSoldier, TRUE) && IsValidStance( pSoldier, ANIM_PRONE ) ) { sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL ); // HEADROCK: Added cowering. if (TileIsOutOfBounds(sClosestOpponent) || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower) - { - ubPointsLost -= GetAPsProne(pSoldier, TRUE); - ubNewStance = ANIM_PRONE; + { + if ( fCower ) + { + // SANDRO - added cowering animation + //if ( Random(4) == 0 ) + //{ + // pSoldier->usPendingAnimation = START_COWER_PRONE; + // pSoldier->ubDesiredHeight = ANIM_PRONE; + // pSoldier->EVENT_InitNewSoldierAnim( PRONE_DOWN, 0 , FALSE ); + // ubNewStance = 0; + //} + //else + if ( pSoldier->usAnimState == COWERING ) // if cowering alread, do nothing + { + ubNewStance = 0; + } + else + { + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_CROUCHED, 0 , FALSE ); + ubNewStance = 0; + } + } + else + { + ubPointsLost -= GetAPsProne(pSoldier, TRUE); + ubNewStance = ANIM_PRONE; + } } } break; @@ -7988,33 +8072,47 @@ void HandleSuppressionFire( UINT8 ubTargetedMerc, UINT8 ubCausedAttacker ) // can't change stance here! break; } - else if (ubPointsLost >= (GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE)) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_PRONE ) && IsValidStance( pSoldier, ANIM_PRONE ) ) // SANDRO - changed to GetAPsCrouch/Prone + else if (ubPointsLost >= (GetAPsCrouch(pSoldier, TRUE) + GetAPsProne(pSoldier, TRUE)) && IsValidStance( pSoldier, ANIM_PRONE ) ) { sClosestOpponent = ClosestKnownOpponent( pSoldier, &sClosestOppLoc, NULL ); // HEADROCK: Added cowering. - if (TileIsOutOfBounds(sClosestOpponent) || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 ||fCower ) + if (TileIsOutOfBounds(sClosestOpponent) || SpacesAway( pSoldier->sGridNo, sClosestOppLoc ) > 8 || fCower ) { - if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND ) + if ( fCower ) { - // can only crouch for now - ubNewStance = ANIM_CROUCH; + // SANDRO - added cowering animation + DeductPoints( pSoldier, GetAPsCrouch(pSoldier, TRUE), APBPConstants[BP_CROUCH], DISABLED_INTERRUPT ); + pSoldier->EVENT_InitNewSoldierAnim( START_COWER, 0 , FALSE ); + ubNewStance = 0; } else { - // lie prone! - ubNewStance = ANIM_PRONE; + // can only crouch for now + ubPointsLost -= GetAPsCrouch(pSoldier, TRUE); + ubNewStance = ANIM_CROUCH; } } - else if ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND && IsValidStance( pSoldier, ANIM_CROUCH ) ) + else if ( IsValidStance( pSoldier, ANIM_CROUCH ) ) { - // crouch, at least! + // crouch! + ubPointsLost -= GetAPsCrouch(pSoldier, TRUE); ubNewStance = ANIM_CROUCH; } } - else if ( ubPointsLost >= GetAPsCrouch(pSoldier, TRUE) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) ) // SANDRO - changed to GetAPsCrouch + else if ( ubPointsLost >= GetAPsCrouch(pSoldier, TRUE) && ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_CROUCH ) && IsValidStance( pSoldier, ANIM_CROUCH ) ) { - // crouch! - ubNewStance = ANIM_CROUCH; + if ( fCower ) + { + DeductPoints( pSoldier, GetAPsCrouch(pSoldier, TRUE), APBPConstants[BP_CROUCH], DISABLED_INTERRUPT ); + pSoldier->EVENT_InitNewSoldierAnim( START_COWER, 0 , FALSE ); + ubNewStance = 0; + } + else + { + // crouch! + ubPointsLost -= GetAPsCrouch(pSoldier, TRUE); + ubNewStance = ANIM_CROUCH; + } } break; } @@ -8301,7 +8399,7 @@ BOOLEAN ProcessImplicationsOfPCAttack( SOLDIERTYPE * pSoldier, SOLDIERTYPE ** pp pTarget->flags.fDontChargeReadyAPs = TRUE; // Ready weapon - pTarget->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE ); + pTarget->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE, AIDecideHipOrShoulderStance( pTarget, pSoldier->sGridNo ) ); // ATE: Depending on personality, fire back..... @@ -8736,7 +8834,11 @@ SOLDIERTYPE *InternalReduceAttackBusyCount( ) pSoldier->bDoAutofire = 1; pSoldier->bDoBurst = TRUE; } - pSoldier->bScopeMode = USE_BEST_SCOPE; + if ( Item[pSoldier->inv[ HANDPOS ].usItem].twohanded && Weapon[pSoldier->inv[ HANDPOS ].usItem].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; + DirtyMercPanelInterface(pSoldier, DIRTYLEVEL2 ); } diff --git a/Tactical/PATHAI.cpp b/Tactical/PATHAI.cpp index 4e64a23e5..bb4703a13 100644 --- a/Tactical/PATHAI.cpp +++ b/Tactical/PATHAI.cpp @@ -3539,11 +3539,13 @@ if(!GridNoOnVisibleWorldTile(iDestination)) ubAPCost += APBPConstants[AP_MODIFIER_RUN]; //ubAPCost = (INT16)(DOUBLE)( (sTileCost / RUNDIVISOR) ); break; break; - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: ubAPCost += APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY]; //WALKCOST); break; + case WALKING_ALTERNATIVE_RDY: + ubAPCost += APBPConstants[AP_MODIFIER_WALK]; //WALKCOST); + break; case WALKING: ubAPCost += APBPConstants[AP_MODIFIER_WALK]; //WALKCOST); if (!(s->MercInWater()) && ( (gAnimControl[ s->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ s->usAnimState ].uiFlags & ANIM_FIRE ) )) @@ -3584,17 +3586,17 @@ if(!GridNoOnVisibleWorldTile(iDestination)) { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY : // Here pessimistically assume the path will continue after hopping the fence - ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed + ubAPCost += GetAPsCrouch( s, TRUE ); break; case SWATTING: // Add cost to stand once there BEFORE jumping.... - ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed + ubAPCost += GetAPsCrouch( s, TRUE ); break; case CRAWLING: @@ -3609,11 +3611,11 @@ if(!GridNoOnVisibleWorldTile(iDestination)) { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY : // charge crouch APs for ducking head! - ubAPCost += GetAPsCrouch( s, TRUE ); // SANDRO - changed + ubAPCost += GetAPsCrouch( s, TRUE ); break; default: @@ -3622,7 +3624,7 @@ if(!GridNoOnVisibleWorldTile(iDestination)) } else if (fGoingThroughDoor) { - ubAPCost += GetAPsToOpenDoor( s ); // changed by SANDRO + ubAPCost += GetAPsToOpenDoor( s ); fGoingThroughDoor = FALSE; } @@ -4477,15 +4479,15 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY : // Add here cost to go from crouch to stand AFTER fence hop.... // Since it's AFTER.. make sure we will be moving after jump... if ( ( iCnt + 2 ) < iLastGrid ) { - sExtraCostStand += GetAPsCrouch(pSold, TRUE); // changed by SANDRO + sExtraCostStand += GetAPsCrouch(pSold, TRUE); // ATE: if running, charge extra point to srart again if ( usMovementModeToUseForAPs== RUNNING ) @@ -4500,7 +4502,7 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl case SWATTING: // Add cost to stand once there BEFORE.... - sExtraCostSwat += GetAPsCrouch(pSold, TRUE); // changed by SANDRO + sExtraCostSwat += GetAPsCrouch(pSold, TRUE); sPoints = sPoints + sExtraCostSwat; break; @@ -4521,11 +4523,11 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY : // charge crouch APs for ducking head! - sExtraCostStand += GetAPsCrouch(pSold, TRUE); // changed by SANDRO + sExtraCostStand += GetAPsCrouch(pSold, TRUE); break; default: @@ -4553,8 +4555,10 @@ INT32 PlotPath( SOLDIERTYPE *pSold, INT32 sDestGridNo, INT8 bCopyRoute, INT8 bPl sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK]; } break; - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_ALTERNATIVE_RDY : + sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK]; + break; + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: sMovementAPsCost = sTileCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY]; break; diff --git a/Tactical/Points.cpp b/Tactical/Points.cpp index 9191ef70f..de6c00922 100644 --- a/Tactical/Points.cpp +++ b/Tactical/Points.cpp @@ -44,11 +44,8 @@ //end rain extern BOOLEAN IsValidSecondHandShot( SOLDIERTYPE *pSoldier ); +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); -////////////////////////////////////////////////////////////////////////////// -// SANDRO - In this file, all APBPConstants[AP_CROUCH] and APBPConstants[AP_PRONE] were changed to GetAPsCrouch() and GetAPsProne() -// On the bottom here, there are these functions made -////////////////////////////////////////////////////////////////////// INT16 GetBreathPerAP( SOLDIERTYPE *pSoldier, UINT16 usAnimState ); @@ -278,7 +275,7 @@ INT16 TerrainBreathPoints(SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bDir, UINT return(0); } - if ( ubMovementCost == WALKING_PISTOL_RDY || ubMovementCost == WALKING_RIFLE_RDY || ubMovementCost == WALKING_DUAL_RDY ) + if ( ubMovementCost == WALKING_WEAPON_RDY || ubMovementCost == WALKING_DUAL_RDY ) { iPoints += APBPConstants[BP_MOVEMENT_READY]; } @@ -308,17 +305,17 @@ INT16 TerrainBreathPoints(SOLDIERTYPE * pSoldier, INT32 sGridNo, INT8 bDir, UINT iPoints *= APBPConstants[BP_RUN_ENERGYCOSTFACTOR]; break; case SIDE_STEP: - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: + case SIDE_STEP_ALTERNATIVE_RDY: case WALK_BACKWARDS: case BLOODCAT_WALK_BACKWARDS: case MONSTER_WALK_BACKWARDS: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: - case WALKING : iPoints *= APBPConstants[BP_WALK_ENERGYCOSTFACTOR]; break; - + case WALKING_ALTERNATIVE_RDY: + case WALKING : + iPoints *= APBPConstants[BP_WALK_ENERGYCOSTFACTOR]; break; case START_SWAT: case SWATTING: case SWAT_BACKWARDS: @@ -407,17 +404,17 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u case MONSTER_WALK_BACKWARDS: case LARVAE_WALK: case WALKING : + case WALKING_ALTERNATIVE_RDY: + case SIDE_STEP_ALTERNATIVE_RDY: sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK]; if ( usMovementMode == WALKING && !(pSoldier->MercInWater()) && ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) )) { sPoints += APBPConstants[AP_MODIFIER_READY]; } break; - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY]; break; @@ -477,15 +474,15 @@ INT16 ActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, UINT16 u { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: case LARVAE_WALK: case SIDE_STEP: - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: case WALK_BACKWARDS: + case WALKING_ALTERNATIVE_RDY: + case SIDE_STEP_ALTERNATIVE_RDY: // charge crouch APs for ducking head! sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed break; @@ -557,17 +554,17 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, case MONSTER_WALK_BACKWARDS: case LARVAE_WALK: case WALKING : + case WALKING_ALTERNATIVE_RDY : + case SIDE_STEP_ALTERNATIVE_RDY : sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK]; - if (!(pSoldier->MercInWater()) && ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) )) + if (!(pSoldier->MercInWater()) && ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) ) && !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) ) { sPoints += APBPConstants[AP_MODIFIER_READY]; } break; - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: sPoints = sTileCost + APBPConstants[AP_MODIFIER_WALK] + APBPConstants[AP_MODIFIER_READY]; break; @@ -633,15 +630,15 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, switch(usMovementMode) { case SIDE_STEP: - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: case WALK_BACKWARDS: case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY : + case SIDE_STEP_ALTERNATIVE_RDY: // Add here cost to go from crouch to stand AFTER fence hop.... // Since it's AFTER.. make sure we will be moving after jump... @@ -671,14 +668,14 @@ INT16 EstimateActionPointCost( SOLDIERTYPE *pSoldier, INT32 sGridNo, INT8 bDir, { case RUNNING: case WALKING : - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: case SIDE_STEP: - case SIDE_STEP_PISTOL_RDY: - case SIDE_STEP_RIFLE_RDY: + case SIDE_STEP_WEAPON_RDY: case SIDE_STEP_DUAL_RDY: case WALK_BACKWARDS: + case WALKING_ALTERNATIVE_RDY : + case SIDE_STEP_ALTERNATIVE_RDY: // charge crouch APs for ducking head! sPoints += GetAPsCrouch(pSoldier, TRUE); // SANDRO changed.. break; @@ -929,10 +926,35 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ub if ( gGameOptions.fNewTraitSystem ) { - // Martial Arts trait reduces the points registered when moving - if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && (ubInterruptType == SP_MOVEMENT_INTERRUPT || ubInterruptType == MOVEMENT_INTERRUPT )) + // without Night Ops, we get small penalty for interrupting a target in dark + if ( !(HAS_SKILL_TRAIT( pOpponent, NIGHT_OPS_NT )) && pOpponent->aiData.bOppList[pSoldier->ubID] == SEEN_CURRENTLY) { - ubPointsRegistered -= gSkillTraitValues.ubMAReducedAPsRegisteredWhenMoving * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ); + INT8 bLightLevel = LightTrueLevel(pSoldier->sGridNo, pSoldier->pathing.bLevel); + if ( bLightLevel > 6) // 7+ lightlevel is darkness + { + ubPointsRegistered -= bLightLevel; // -7 to -12% + } + } + + // Martial Arts trait reduces the points registered when moving + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && (ubInterruptType == SP_MOVEMENT_INTERRUPT || ubInterruptType == MOVEMENT_INTERRUPT ) && + Item[pSoldier->inv[HANDPOS].usItem].usItemClass & (IC_PUNCH|IC_BLADE|IC_NONE)) // only get this if we have no weapon or blade in hands + { + // check how far we are, we only get this bonus at certain range + INT16 sTileDistance = PythSpacesAway(pSoldier->sGridNo, pOpponent->sGridNo); + if ( (sTileDistance <= 9) && (pOpponent->bTargetLevel == pSoldier->bTargetLevel)) // we must be on the same ground level as well + { + UINT8 ubBonus = gSkillTraitValues.ubMAReducedAPsRegisteredWhenMoving * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ); + if (sTileDistance > 6) // make it gradually effective based on distance + ubBonus = ubBonus * (10 - sTileDistance) / 4; // at 9th tile it is only 25% of the trait bonus, from 7th tile it is 100% + + // check direction, we get full bonus if running towards the victim, but others around watching the scene have somehow better chance to interfere + if ( pSoldier->ubDirection != GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, pOpponent->sGridNo ) ) + { + ubBonus = ubBonus *2/3; // two thirds only sound reasonable + } + ubPointsRegistered -= ubBonus; + } } // Stealhty trait reduced the points registered on all actions if ( HAS_SKILL_TRAIT( pSoldier, STEALTHY_NT ) ) @@ -976,7 +998,7 @@ void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ub -INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost) +INT32 AdjustBreathPts( SOLDIERTYPE * pSoldier , INT32 iBPCost ) { INT16 sBreathFactor = 100; UINT8 ubBandaged; @@ -995,17 +1017,17 @@ INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost) // adjust breath factor for current breath deficiency - sBreathFactor += (100 - pSold->bBreath); + sBreathFactor += (100 - pSoldier->bBreath); // adjust breath factor for current life deficiency (but add 1/2 bandaging) - ubBandaged = pSold->stats.bLifeMax - pSold->stats.bLife - pSold->bBleeding; - //sBreathFactor += (pSold->stats.bLifeMax - (pSold->stats.bLife + (ubBandaged / 2))); - sBreathFactor += 100 * (pSold->stats.bLifeMax - (pSold->stats.bLife + (ubBandaged / 2))) / pSold->stats.bLifeMax; + ubBandaged = pSoldier->stats.bLifeMax - pSoldier->stats.bLife - pSoldier->bBleeding; + //sBreathFactor += (pSoldier->stats.bLifeMax - (pSoldier->stats.bLife + (ubBandaged / 2))); + sBreathFactor += 100 * (pSoldier->stats.bLifeMax - (pSoldier->stats.bLife + (ubBandaged / 2))) / pSoldier->stats.bLifeMax; - if ( pSold->stats.bStrength > 80 ) + if ( pSoldier->stats.bStrength > 80 ) { // give % reduction to breath costs for high strength mercs - sBreathFactor -= (pSold->stats.bStrength - 80) / 2; + sBreathFactor -= (pSoldier->stats.bStrength - 80) / 2; } /* THIS IS OLD JAGGED ALLIANCE STUFF (left for possible future reference) @@ -1020,20 +1042,20 @@ INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost) */ // SANDRO - added heat intolerant penalty - if ( MercIsHot( pSold ) ) + if ( MercIsHot( pSoldier ) ) { sBreathFactor += 100; } // SANDRO - Less breath consumption for Primitive chars - if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSold->ubProfile].bCharacterTrait == CHAR_TRAIT_PRIMITIVE ) + if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_PRIMITIVE ) { sBreathFactor -= 15; // -15% breath consumption } // if a non-swimmer type is thrashing around in deep water - if ( (pSold->ubProfile != NO_PROFILE ) && (gMercProfiles[ pSold->ubProfile ].bDisability == NONSWIMMER) ) + if ( (pSoldier->ubProfile != NO_PROFILE ) && (gMercProfiles[ pSoldier->ubProfile ].bDisability == NONSWIMMER) ) { - if ( pSold->usAnimState == DEEP_WATER_TRED || pSold->usAnimState == DEEP_WATER_SWIM) + if ( pSoldier->usAnimState == DEEP_WATER_TRED || pSoldier->usAnimState == DEEP_WATER_SWIM) { sBreathFactor *= 7; // lose breath 5 times faster in deep water! } @@ -1056,7 +1078,7 @@ INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost) -void UnusedAPsToBreath(SOLDIERTYPE *pSold) +void UnusedAPsToBreath( SOLDIERTYPE * pSoldier ) { INT16 sUnusedAPs, sBreathPerAP = 0, sBreathChange, sRTBreathMod; // Note to Andrew (or whomever else it may concern): @@ -1077,7 +1099,7 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) // If we are not in turn-based combat... - if ( pSold->flags.uiStatusFlags & SOLDIER_VEHICLE ) + if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) { return; } @@ -1085,17 +1107,17 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) if ( !( gTacticalStatus.uiFlags & TURNBASED ) || !(gTacticalStatus.uiFlags & INCOMBAT ) ) { // ALRIGHT, GIVE A FULL AMOUNT BACK, UNLES MODIFIED BY WHAT ACTIONS WE WERE DOING - sBreathPerAP = GetBreathPerAP( pSold, pSold->usAnimState ); + sBreathPerAP = GetBreathPerAP( pSoldier, pSoldier->usAnimState ); // adjust for carried weight - sBreathPerAP = sBreathPerAP * 100 / BreathPointAdjustmentForCarriedWeight( pSold ); + sBreathPerAP = sBreathPerAP * 100 / BreathPointAdjustmentForCarriedWeight( pSoldier ); // If this value is -ve, we have a gain, else we have a loos which we should not really do // We just want to limit this to no gain if we were doing stuff... sBreathChange = 3 * sBreathPerAP; // Adjust for on drugs - HandleBPEffectDueToDrugs( pSold, &sBreathChange ); + HandleBPEffectDueToDrugs( pSoldier, &sBreathChange ); if ( sBreathChange > 0 ) { @@ -1105,13 +1127,13 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) { // We have a gain, now limit this depending on what we were doing... // OK for RT, look at how many tiles we have moved, our last move anim - if ( pSold->ubTilesMovedPerRTBreathUpdate > 0 ) + if ( pSoldier->ubTilesMovedPerRTBreathUpdate > 0 ) { // How long have we done this for? // And what anim were we doing? - sBreathPerAP = GetBreathPerAP( pSold, pSold->usLastMovementAnimPerRTBreathUpdate ); + sBreathPerAP = GetBreathPerAP( pSoldier, pSoldier->usLastMovementAnimPerRTBreathUpdate ); - sRTBreathMod = sBreathPerAP * pSold->ubTilesMovedPerRTBreathUpdate; + sRTBreathMod = sBreathPerAP * pSoldier->ubTilesMovedPerRTBreathUpdate; // Deduct some if we were exerting ourselves // We add here because to gain breath, sBreathChange needs to be -ve @@ -1131,43 +1153,65 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) // as fast as the TB values do sBreathChange *= TB_BREATH_RECOVER_MODIFIER; + // SANDRO: get BP *cost* for weapon holding (reduce breath gain, or even make it breath loss) + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + { + sBreathChange += 3 * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + + // if we are actually losing breath by holding a very heavy gun up, lower it if breath already at critical line + if ( sBreathChange > 0 && pSoldier->bBreath < OKBREATH ) + { + // ok, if this gun is rather heavy, and cost us at least 3 energy points per turn + if ( (GetBPCostPer10APsForGunHolding( pSoldier ) * 10) >= (300 * gGameExternalOptions.ubEnergyCostForWeaponWeight / 100) ) + { + // throw quote + if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) ) + { + TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_BREATH ); + pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH; + } + // Put gun down.... + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE ); + } + } + } // adjust breath only, don't touch action points! - DeductPoints(pSold,0,(INT16)sBreathChange ); + DeductPoints(pSoldier,0,(INT16)sBreathChange ); // Reset value for RT breath update - pSold->ubTilesMovedPerRTBreathUpdate = 0; + pSoldier->ubTilesMovedPerRTBreathUpdate = 0; } else { // if merc has any APs left unused this turn (that aren't carrying over) - if (pSold->bActionPoints > APBPConstants[MAX_AP_CARRIED]) + if (pSoldier->bActionPoints > APBPConstants[MAX_AP_CARRIED]) { // SANDRO - don't reduce the APs if collapsed - if ( pSold->bCollapsed || pSold->bBreathCollapsed ) - sUnusedAPs = pSold->bActionPoints; + if ( pSoldier->bCollapsed || pSoldier->bBreathCollapsed ) + sUnusedAPs = pSoldier->bActionPoints; else - sUnusedAPs = pSold->bActionPoints - APBPConstants[MAX_AP_CARRIED]; + sUnusedAPs = pSoldier->bActionPoints - APBPConstants[MAX_AP_CARRIED]; - sBreathPerAP = GetBreathPerAP( pSold, pSold->usAnimState ); + sBreathPerAP = GetBreathPerAP( pSoldier, pSoldier->usAnimState ); if (sBreathPerAP < 0) { // can't gain any breath when we've just been gassed, OR // if standing in tear gas without a gas mask on - if ( pSold->flags.uiStatusFlags & SOLDIER_GASSED ) + if ( pSoldier->flags.uiStatusFlags & SOLDIER_GASSED ) { return; // can't breathe here, so get no breath back! } } // adjust for carried weight - sBreathPerAP = sBreathPerAP * 100 / BreathPointAdjustmentForCarriedWeight( pSold ); + sBreathPerAP = sBreathPerAP * 100 / BreathPointAdjustmentForCarriedWeight( pSoldier ); - // SANDRO - what the hell!?! This calculation is not correct, it means the less APs you have the more Breath you gain, - // when the exact opposite should happen according to the function of this entire procedure!!! - //if ( pSold->bTeam != CIV_TEAM && pSold->bTeam != gbPlayerNum) + // SANDRO: what the hell? This calculation is not correct, it means the less APs you have the more Breath you gain, + // when the exact opposite should happen according to the function of this entire procedure! + //if ( pSoldier->bTeam != CIV_TEAM && pSoldier->bTeam != gbPlayerNum) //{ // switch( gGameOptions.ubDifficultyLevel ) // { @@ -1195,8 +1239,8 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) //{ // sBreathChange = ((APBPConstants[AP_MAXIMUM] + gGameExternalOptions.iPlayerAPBonus)- sUnusedAPs) * sBreathPerAP; //} - // SANDRO - if we want to make difference between difficulty levels, the just make it so with higher difficulty the enemy regenerate faster: - if ( pSold->bTeam == ENEMY_TEAM ) + // SANDRO: if we want to make difference between difficulty levels, then just make it so with higher difficulty the enemy regenerate faster: + if ( pSoldier->bTeam == ENEMY_TEAM ) { switch( gGameOptions.ubDifficultyLevel ) { @@ -1214,33 +1258,56 @@ void UnusedAPsToBreath(SOLDIERTYPE *pSold) break; } } - // SANDRO - this simple thing is the correct calculation + // SANDRO: this simple thing is the correct calculation sBreathChange = (sUnusedAPs * sBreathPerAP); + + // SANDRO: get BP *cost* for weapon holding (reduce breath gain, or even make it breath loss) + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + { + sBreathChange += sUnusedAPs * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + + // if we are actually losing breath by holding a very heavy gun up, lower it if breath already at critical line + if ( sBreathChange > 0 && pSoldier->bBreath < OKBREATH ) + { + // ok, if this gun is rather heavy, and cost us at least 3 energy points per turn + if ( (GetBPCostPer10APsForGunHolding( pSoldier ) * 10) >= (300 * gGameExternalOptions.ubEnergyCostForWeaponWeight / 100) ) + { + // throw quote + if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) ) + { + TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_BREATH ); + pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH; + } + // Put gun down.... + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE ); + } + } + } } else { sBreathChange = 0; } // Adjust for on drugs - HandleBPEffectDueToDrugs( pSold, &sBreathChange ); + HandleBPEffectDueToDrugs( pSoldier, &sBreathChange ); // SANDRO - Penalty for breath regain for being hit by Martial artist - if ((pSold->lUnregainableBreath > 0) && (sBreathChange < 0) && gGameOptions.fNewTraitSystem) + if ((pSoldier->lUnregainableBreath > 0) && (sBreathChange < 0) && gGameOptions.fNewTraitSystem) { - if (pSold->lUnregainableBreath >= (0 - sBreathChange)) + if (pSoldier->lUnregainableBreath >= (0 - sBreathChange)) { - pSold->lUnregainableBreath += sBreathChange; + pSoldier->lUnregainableBreath += sBreathChange; sBreathChange = 0; } else { - sBreathChange += (INT16)(pSold->lUnregainableBreath); - pSold->lUnregainableBreath = 0; + sBreathChange += (INT16)(pSoldier->lUnregainableBreath); + pSoldier->lUnregainableBreath = 0; } } // adjust breath only, don't touch action points! - DeductPoints(pSold,0,(INT16)sBreathChange ); + DeductPoints(pSoldier,0,(INT16)sBreathChange ); } } @@ -1287,9 +1354,9 @@ INT16 GetBreathPerAP( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) break; case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: sBreathPerAP = APBPConstants[BP_PER_AP_LT_EFFORT]; break; @@ -1497,7 +1564,7 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur if ( uiItemClass == IC_GUN || uiItemClass == IC_LAUNCHER || uiItemClass == IC_TENTACLES || uiItemClass == IC_THROWING_KNIFE ) { - sAPCost = MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost ); + sAPCost = MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost, bAimTime ); if ( pSoldier->bDoBurst ) { @@ -1513,7 +1580,7 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur // HEADROCK HAM B2.6: Changed the number of APs to attack when aiming. if (bAimTime > 0) { - GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost ); + GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost, bAimTime ); if(fAddingRaiseGunCost == TRUE) { // HEADROCK HAM 3: No idea what should come here... For now I've put my extra gun-raise costs @@ -1534,8 +1601,8 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur // If the weapon has a scope, and the target is within eligible range for scope use - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus( pSoldier, &pSoldier->inv[HANDPOS])) - || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(pSoldier, &pSoldier->inv[HANDPOS], (FLOAT)GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) > 1.0 )) ) + if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) >= GetMinRangeForAimBonus( pSoldier, &pSoldier->inv[HANDPOS]) && !pSoldier->IsValidAlternativeFireMode(bAimTime,sGridNo)) + || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(pSoldier, &pSoldier->inv[HANDPOS], (FLOAT)GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ) > 1.0 ) && !pSoldier->IsValidAlternativeFireMode(bAimTime,sGridNo)) ) { // Add an individual cost for EACH click, as necessary. @@ -1577,7 +1644,7 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur //ATE: HERE, need to calculate APs! if ( uiItemClass & IC_EXPLOSV ) { - sAPCost = MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost ); + sAPCost = MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost, bAimTime, 0 ); //sAPCost = 5; } @@ -1668,14 +1735,14 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur pSoldier->sWalkToAttackGridNo = sGridNo; // Add points to attack - sAPCost += MinAPsToAttack( pSoldier, sAdjustedGridNo, ubAddTurningCost ); + sAPCost += MinAPsToAttack( pSoldier, sAdjustedGridNo, ubAddTurningCost, bAimTime, 0 ); //sAPCost += APsToTurnAround(pSoldier, sAdjustedGridNo); } else { // Add points to attack // Use our gridno - sAPCost += MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost ); + sAPCost += MinAPsToAttack( pSoldier, sGridNo, ubAddTurningCost, bAimTime, 0 ); } // Add aim time... @@ -1686,7 +1753,7 @@ INT16 CalcTotalAPsToAttack( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTur return( sAPCost ); } -INT16 MinAPsToAttack(SOLDIERTYPE *pSoldier, INT32 sGridno, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost) +INT16 MinAPsToAttack(SOLDIERTYPE *pSoldier, INT32 sGridno, UINT8 ubAddTurningCost, INT16 bAimTime, UINT8 ubForceRaiseGunCost ) { INT16 sAPCost = 0; UINT32 uiItemClass; @@ -1718,7 +1785,7 @@ INT16 MinAPsToAttack(SOLDIERTYPE *pSoldier, INT32 sGridno, UINT8 ubAddTurningCos if ( uiItemClass == IC_BLADE || uiItemClass == IC_GUN || uiItemClass == IC_LAUNCHER || uiItemClass == IC_TENTACLES || uiItemClass == IC_THROWING_KNIFE ) { - sAPCost = MinAPsToShootOrStab( pSoldier, sGridno, ubAddTurningCost, ubForceRaiseGunCost ); + sAPCost = MinAPsToShootOrStab( pSoldier, sGridno, bAimTime, ubAddTurningCost, ubForceRaiseGunCost ); } else if ( uiItemClass & ( IC_GRENADE | IC_THROWN ) ) { @@ -1835,7 +1902,7 @@ INT16 BaseAPsToShootOrStabNoModifier( INT16 bAPs, INT16 bAimSkill, OBJECTTYPE * return baseAPsToShootOrStab; } -void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise ) +void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise, INT16 bAimTime ) { UINT8 ubDirection; UINT32 uiMercFlags; @@ -1878,11 +1945,44 @@ void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo } else { - // Do we need to ready weapon? - if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ) ) + // SANDRO - alternative weapon holding feature + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) { - fAddingRaiseGunCost = TRUE; + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_ALT_WEAPON_HOLDING ) )) + { + fAddingRaiseGunCost = TRUE; + } + else if ( pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD && ( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_ALT_WEAPON_HOLDING ) || !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ) )) + { + fAddingRaiseGunCost = TRUE; + } } + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 2 ) + { + if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ) || + ((gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_ALT_WEAPON_HOLDING )) && + (bAimTime > GetNumberAltFireAimLevels( pSoldier, sGridNo )) )) + { + fAddingRaiseGunCost = TRUE; + } + } + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 1 ) + { + if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ) || + ((gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_ALT_WEAPON_HOLDING )) && + (bAimTime > 0) )) + { + fAddingRaiseGunCost = TRUE; + } + } + else + { + if ( !( gAnimControl[ pSoldier->usAnimState ].uiFlags &( ANIM_FIREREADY | ANIM_FIRE ) ) ) + { + fAddingRaiseGunCost = TRUE; + } + } + //CHRISL: Handle ready weapon with facing changes based on stance if(fAddingTurningCost && !fAddingRaiseGunCost) { @@ -1926,20 +2026,40 @@ UINT16 CalculateTurningCost(SOLDIERTYPE *pSoldier, UINT16 usItem, BOOLEAN fAddin return usTurningCost; } -UINT16 CalculateRaiseGunCost(SOLDIERTYPE *pSoldier, BOOLEAN fAddingRaiseGunCost) +UINT16 CalculateRaiseGunCost(SOLDIERTYPE *pSoldier, BOOLEAN fAddingRaiseGunCost, INT32 iTargetGridNum, INT16 bAimTime ) { - UINT16 usRaiseGunCost = 0; + UINT16 usRaiseGunCost = 0, usAnimState; if (fAddingRaiseGunCost ) { - usRaiseGunCost = GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ); + BOOLEAN fAltFireMode = FALSE; + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding ) + { + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 && pSoldier->bTeam == gbPlayerNum ) + { + if ( pSoldier->bScopeMode == -1 ) + fAltFireMode = TRUE; + } + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 1 ) + { + if ( bAimTime == 0 ) + fAltFireMode = TRUE; + } + else + { + if ( bAimTime <= GetNumberAltFireAimLevels( pSoldier, iTargetGridNum ) ) + fAltFireMode = TRUE; + } + } + usAnimState = PickSoldierReadyAnimation( pSoldier, FALSE, fAltFireMode ); + usRaiseGunCost = GetAPsToReadyWeapon( pSoldier, usAnimState ); pSoldier->flags.fDontChargeReadyAPs = FALSE; } return usRaiseGunCost; } -INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost) +INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 bAimTime, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost ) { UINT32 uiMercFlags; UINT16 usTargID; @@ -1968,9 +2088,7 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &(pSoldier->inv[HANDPOS]) ); - GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost ); - - // THE LINES FROM HERE HAVE BEEN MOVED DOWN - SANDRO + GetAPChargeForShootOrStabWRTGunRaises( pSoldier, sGridNo, ubAddTurningCost, &fAddingTurningCost, &fAddingRaiseGunCost, bAimTime ); // Snap: reversed DIGICRAB's change. // bFullAPs are BASE APs, which do not include APs caried over from the previous turn. @@ -1979,6 +2097,15 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni // aim skill is the same whether we are using 1 or 2 guns bAimSkill = CalcAimSkill( pSoldier, usItem ); + if (!TileIsOutOfBounds(sGridNo)) + { + // Given a gridno here, check if we are on a guy - if so - get his gridno + if ( FindSoldier( sGridNo, &usTargID, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) + { + sGridNo = MercPtrs[ usTargID ]->sGridNo; + } + } + if ( pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO ) { INT16 glItem; @@ -2044,6 +2171,11 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni { bAPCost += BaseAPsToShootOrStab( bFullAPs, bAimSkill, pObjUsed, pSoldier ); } + // If we are using alternative weapon holding (from hip rifle/one-handed pistol), the shot can be faster if set in the ini + if ( gGameExternalOptions.ubAltWeaponHoldingFireSpeedBonus > 0 && pSoldier->IsValidAlternativeFireMode( bAimTime, sGridNo )) + { + bAPCost = (INT16)((bAPCost * (100 - gGameExternalOptions.ubAltWeaponHoldingFireSpeedBonus ) / 100)+ 0.5); + } ///////////////////////////////////////////////////////////////////////////////////// // SANDRO - STOMP traits //////////////////////////////////////////////////// @@ -2088,9 +2220,6 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni ///////////////////////////////////////////////////////////////////////////////////// } - ///////////////////////////////////////////////////////////////////////// - // THESE MODIFIERS HAVE BEEN JUST MOVED HERE FROM ABOVE - SANDRO - if (ubForceRaiseGunCost) { fAddingRaiseGunCost = TRUE; @@ -2111,7 +2240,7 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni usTurningCost = CalculateTurningCost(pSoldier, usItem, fAddingTurningCost); //Calculate usRaiseGunCost - usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost); + usRaiseGunCost = CalculateRaiseGunCost(pSoldier, fAddingRaiseGunCost, sGridNo, bAimTime ); //charge for turn and/or raise based on the results of fAddingTurningCost & fAddingRaiseGunCost // silversurfer: this was different from HandleItem() and therefore it displayed different values @@ -2132,22 +2261,15 @@ INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurni else bAPCost += (usTurningCost + usRaiseGunCost); - if (!TileIsOutOfBounds(sGridNo)) - { - // Given a gridno here, check if we are on a guy - if so - get his gridno - if ( FindSoldier( sGridNo, &usTargID, &uiMercFlags, FIND_SOLDIER_GRIDNO ) ) - { - sGridNo = MercPtrs[ usTargID ]->sGridNo; - } - } - // if attacking a new target (or if the specific target is uncertain) // Added check if the weapon is a throwing knife - otherwise it would add APs for change taregt on cursor but not actually deduct them afterwards - SANDRO if (ubForceRaiseGunCost || (( sGridNo != pSoldier->sLastTarget ) && !Item[usUBItem].rocketlauncher && (Item[ usUBItem ].usItemClass != IC_THROWING_KNIFE) )) { - bAPCost += APBPConstants[AP_CHANGE_TARGET]; + if ( pSoldier->IsValidAlternativeFireMode( bAimTime, sGridNo ) ) + bAPCost += (APBPConstants[AP_CHANGE_TARGET] / 2); + else + bAPCost += APBPConstants[AP_CHANGE_TARGET]; } - ///////////////////////////////////////////////////////////////////////// // the minimum AP cost of ANY shot can NEVER be more than merc's maximum APs! if ( bAPCost > bFullAPs ) @@ -2312,8 +2434,7 @@ INT8 MinAPsToStartMovement( SOLDIERTYPE * pSoldier, UINT16 usMovementMode ) { case RUNNING: case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) { @@ -2962,6 +3083,7 @@ BOOLEAN CheckForMercContMove( SOLDIERTYPE *pSoldier ) INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) { UINT16 usItem; + UINT8 ubReadyAPs = 0; usItem = pSoldier->inv[ HANDPOS ].usItem; @@ -2991,7 +3113,7 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) rt1 = Weapon[usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) / 100; rt2 = Weapon[pSoldier->inv[SECONDHANDPOS].usItem].ubReadyTime * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ SECONDHANDPOS ]) ) / 100; } - return( max(rt1,rt2) + APBPConstants[AP_READY_DUAL] ); + ubReadyAPs = ( max(rt1,rt2) + APBPConstants[AP_READY_DUAL] ); } @@ -3006,34 +3128,65 @@ INT16 GetAPsToReadyWeapon( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) // CHECK FOR RIFLE if ( Item[ usItem ].usItemClass == IC_GUN ) { + ubReadyAPs = Weapon[ usItem ].ubReadyTime; + //ADB if 0, which it normally is, avoid the function call and division - if (Weapon[ usItem ].ubReadyTime == 0) { + if (ubReadyAPs == 0) + { return 0; } else - { - // SANDRO - STOMP traits + { + // Get bonus to draw speed from attachments + ubReadyAPs = (( ubReadyAPs * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) ) / 100); + + // alternative weapon holding? + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding ) + { + // If we are told to go to the alt weapon holding mode + if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) ) + { + if ( Item[ usItem ].twohanded ) + { + // Raising only to hip, either charge no APs or a portion of them + ubReadyAPs = ((ubReadyAPs * gGameExternalOptions.ubToAltWeaponHoldReadyAPsPerc) + 99) / 100 ; // round up for rifles + } + else + { + // raising pistol one-handed, make it faster + ubReadyAPs = (ubReadyAPs * gGameExternalOptions.ubToAltWeaponHoldReadyAPsPerc) / 100 ; // round down for pistols + } + } + // If we are told to go from alternative to standard weapon holding + else if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) ) + { + if ( Item[ usItem ].twohanded ) + { + ubReadyAPs = ubReadyAPs * gGameExternalOptions.ubFromAltWeaponHoldReadyAPsPerc / 100; // round down for rifles + } + else + { + ubReadyAPs = ((ubReadyAPs * gGameExternalOptions.ubFromAltWeaponHoldReadyAPsPerc)+ 99) / 100; // round up for pistols + } + } + } + + // STOMP traits // Decrease APs to ready LMG if having Auto Weapon trait if ( (Weapon[usItem].ubWeaponType == GUN_LMG) && HAS_SKILL_TRAIT(pSoldier, AUTO_WEAPONS_NT) && ( gGameOptions.fNewTraitSystem )) { - return (INT16)(( Weapon[ usItem ].ubReadyTime - * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubAWPercentReadyLMGReduction * NUM_SKILL_TRAITS(pSoldier, AUTO_WEAPONS_NT) ) ) / 100)); // -10% per trait + ubReadyAPs = (( ubReadyAPs * max(0, (100 - gSkillTraitValues.ubAWPercentReadyLMGReduction * NUM_SKILL_TRAITS(pSoldier, AUTO_WEAPONS_NT) ) ) / 100)); // -10% per trait } // Decrease APs to ready pistols and revolvers if having Gunslinger trait else if ( (Weapon[usItem].ubWeaponType == GUN_PISTOL) && HAS_SKILL_TRAIT(pSoldier, GUNSLINGER_NT) && ( gGameOptions.fNewTraitSystem )) { - return (INT16)(( Weapon[ usItem ].ubReadyTime - * max(0, (100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) - gSkillTraitValues.ubGSPercentReadyPistolsReduction * NUM_SKILL_TRAITS(pSoldier, GUNSLINGER_NT) ) ) / 100)); // -15% per trait + ubReadyAPs = (( ubReadyAPs * max(0, (100 - gSkillTraitValues.ubGSPercentReadyPistolsReduction * NUM_SKILL_TRAITS(pSoldier, GUNSLINGER_NT) ) ) / 100)); // -15% per trait } - //Normal ready time - else - return (INT16)(( Weapon[ usItem ].ubReadyTime - * ( 100 - GetPercentReadyTimeAPReduction(&pSoldier->inv[ HANDPOS ]) ) ) / 100); } } } - return( 0 ); + return( (INT16)max( 0, ubReadyAPs ) ); } @@ -3533,6 +3686,16 @@ INT32 CalcAPCostForAiming( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, INT8 bAim Assert(pSoldier != NULL); Assert(&pSoldier->inv[HANDPOS] != NULL); + if (!( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE ))) + { + // Weapon not ready, check aiming from hip, else add raise gun cost + //if (!pSoldier->IsValidShotFromHip(bAimTime,sTargetGridNo)) + { + sAPCost += CalculateRaiseGunCost( pSoldier, TRUE, sTargetGridNo, bAimTime ); + } + } + + if (gGameExternalOptions.fIncreasedAimingCost ) { // HEADROCK HAM B2.6: Changed the number of APs to attack when aiming. @@ -3553,8 +3716,8 @@ INT32 CalcAPCostForAiming( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, INT8 bAim // If the weapon has a scope, and the target is within eligible range for scope use - if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) >= GetMinRangeForAimBonus(pSoldier, &pSoldier->inv[HANDPOS])) - || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(pSoldier, &pSoldier->inv[HANDPOS], (FLOAT)GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) > 1.0 ))) + if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS]) && GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) >= GetMinRangeForAimBonus(pSoldier, &pSoldier->inv[HANDPOS]) && !pSoldier->IsValidAlternativeFireMode(bAimTime,sTargetGridNo)) + || (UsingNewCTHSystem() == true && GetBestScopeMagnificationFactor(pSoldier, &pSoldier->inv[HANDPOS], (FLOAT)GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sTargetGridNo ) > 1.0 ) && !pSoldier->IsValidAlternativeFireMode(bAimTime,sTargetGridNo))) { // Add an individual cost for EACH click, as necessary. @@ -3719,4 +3882,291 @@ INT16 GetAPsToDisarmMine( SOLDIERTYPE *pSoldier ) return( max( 1, (INT16)((APBPConstants[AP_DISARM_MINE] * (100 - gSkillTraitValues.ubAMHandleBombsAPsReduction)/100) + 0.5 )) ); else return( APBPConstants[AP_DISARM_MINE] ); +} + +INT32 GetBPCostPer10APsForGunHolding( SOLDIERTYPE * pSoldier, BOOLEAN fEstimate ) +{ + if ( !gGameExternalOptions.ubEnergyCostForWeaponWeight ) + return 0; + if ( pSoldier == NULL ) + return 0; + if ( Item[pSoldier->inv[HANDPOS].usItem].usItemClass != IC_GUN && Item[pSoldier->inv[HANDPOS].usItem].usItemClass != IC_LAUNCHER ) + return 0; + if ( !(gAnimControl[ pSoldier->usAnimState ].uiFlags & (ANIM_FIRE | ANIM_FIREREADY) ) && !fEstimate ) // don't if weapon not raised, but do if we are gonna estimate the cost + return 0; + if ( TANK( pSoldier ) || AM_A_ROBOT( pSoldier ) ) + return 0; + ////////////////////////////////////////////////////////////////////////////// + // THE BASIC COST FOR HOLDING THE GUN RAISED (per AP) + ////////////////////////////////////////////////////////////////////////////// + // This somehow represents the effort we must make to keep the gun shouldered and pointing on a target. + // The cost is not directly generated by firing, but is applied on the fire, as we spend APs.. it is also applied + // on shouldering the gun and keeping the gun shouldered over the turns, as well as walking with it up, or turning around. + + INT32 iBPcost = 0; + + // Get weapon total weight + INT16 sWeaponWeight = CalculateObjectWeight(&pSoldier->inv[pSoldier->ubAttackingHand]); + + // Make the weight impact exponential, so lightweight guns cost very little or nearly no energy, + // but as the gun weight goes up, the impact raises dramatically + + // this divisor controls the final value and is adjusted by our strength + INT8 bDivisor = 30; + double dModifier = 0; + // +0.25 per strength between 70 and 80, +0.5 per strength between 80 and 90, +0.75 per strength over 90 + // --> max modifier +15 at 100 strength, which equals cca -33% energy cost compared to a merc with 60-70 strength + INT16 sOurStrength = EffectiveStrength( pSoldier, FALSE ); + if ( sOurStrength > 70 ) + { + dModifier += (sOurStrength - 70)/4; + if ( sOurStrength > 80 ) + { + dModifier += (sOurStrength - 80)/4; + if ( sOurStrength > 90 ) + dModifier += (sOurStrength - 90)/4; + } + } + // -0.25 per strength below 60, further -0.25 per strength below 50, and further -0.25 per strength below 40 + // --> max modifier -15 at 40- strength, which equals doubled energy cost compared to a merc with 60-70 strength + else if ( sOurStrength < 60 ) + { + dModifier -= (60 - sOurStrength)/4; + if ( sOurStrength < 50 ) + { + dModifier -= (50 - sOurStrength)/4; + if ( sOurStrength < 40 ) + dModifier -= (40 - sOurStrength)/4; + } + } + // Round the number properly + if (dModifier) + bDivisor += (INT8)(dModifier + 0.5); + else + bDivisor += (INT8)(dModifier - 0.5); + + // Calculate the basic cost + // Note: we are multiplying it by 10 here because the final cost is per 10 APs, and because we need some precision in the calculation + iBPcost = 10 * sWeaponWeight * sWeaponWeight / bDivisor; + + // ------------------------------------ + // APPLY MODIFIERS FOR STANCE AND BIPOD + dModifier = 0; + // Alternative weapon holding? + if (( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) || (fEstimate && pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD) ) + { + if ( Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded ) // firing from hip is not nearly n effort + dModifier += 80; // only 20% cost if on hip + else // holding pistol in one hand is worse in this case + dModifier -= 25; // increased cost by 25% + } + // If weapon is rested on something or we are prone, reduce the power + if ( gGameExternalOptions.fWeaponResting && pSoldier->IsWeaponMounted() || ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) ) + { + dModifier += 90; // only 10% of the regular cost if prone or rested + if ( GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand]) > 0) + iBPcost = 0; // with bipod on top, there is no bp cost + } + else if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_CROUCH ) + dModifier += 50; // only 50% of the cost if crouching + + if ( dModifier != 0 ) + { + dModifier = min( 99, dModifier ); + iBPcost = (INT32)(iBPcost * (100 - dModifier) / 100); + } + iBPcost = max(0, iBPcost); + + // What the hell, can't shoulder these, return some crazy breath cost + if ( Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding && (!(gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING) || (fEstimate && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD )) ) + { + iBPcost = (iBPcost + 25) * 5; + } + + // For enemies, modify by difficulty + if ( pSoldier->bTeam == ENEMY_TEAM ) + { + switch( gGameOptions.ubDifficultyLevel ) + { + case DIF_LEVEL_EASY: + break; + case DIF_LEVEL_MEDIUM: + iBPcost = (iBPcost * 9)/10; // -10% + break; + case DIF_LEVEL_HARD: + iBPcost = (iBPcost * 3)/4; // -25% + break; + case DIF_LEVEL_INSANE: + iBPcost /= 2; // -50% + break; + } + } + + // Adjust by predefined ini setting + iBPcost = (iBPcost * gGameExternalOptions.ubEnergyCostForWeaponWeight / 100); + + // Now we have a number, but we must convert this number to represent BP cost PER 1 AP + // This is roughly "a guess" + iBPcost /= 25; + // this can make the cost zero, but that's what we actully want - with very light guns, there is no effort at all + + // ::: overview ::: + // a merc with 85 strength (+5 modifier to divisor)... + // 1) a gun weighting 3 kilos (lightweight ARs), generates cca 25 points = 1 BP per AP = 100 BPs per full turn = pretty much nothing + // 2) a gun weighting 5 kilos (most ARs with some attachments), generates cca 71 points = 3 BPs per AP = 300 BPs per full turn = still ok, similar to climb down a roof once + // 3) a gun weighting 8 kilos ("lighter" LMGs like PKM, or heavier ARs with lots of attachments), generates cca 183 points = 7 BPs per AP = 700 BPs per full turn = you can handle it, its just like climb roof up and then down once + // 4) a gun weighting 11 kilos (Rheinmetall MG3, FN MAG), generates cca 346 points = 13 BPs per AP = 1300 BPs per full turn = starts to feel rather heavy soon + // 5) s gun weighting 15 kilos (you trying to shoulder Barrett? or Browning M1919?), generates cca 643 points = 26 BPs per AP = 2600 BPs per turn = uhh, + + // after testing, a gun weighting 12 kilos, shouldered in standing position, with 85 strength, together with recoil kick (small one on this one though)... + // took 5-6 whole turns to totaly exhaust the merc, if one turn is equal 20-30 seconds, then it is 2-3 minutes... I think that's reasonable + + return ( iBPcost ); +} + +INT32 GetBPCostForRecoilkick( SOLDIERTYPE * pSoldier ) +{ + if ( !gGameExternalOptions.ubEnergyCostForWeaponRecoilKick ) + return 0; + if ( pSoldier == NULL ) + return 0; + if ( Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usItemClass != IC_GUN && Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].usItemClass != IC_LAUNCHER ) + return 0; + if ( TANK( pSoldier ) || AM_A_ROBOT( pSoldier ) ) + return 0; + ////////////////////////////////////////////////////////////////////////////// + // THE GUN RECOIL KICK ENERGY COST + ////////////////////////////////////////////////////////////////////////////// + // This is not about how heavy is the gun, but how much it kicks our shoulder. + // Single shots may not prove much effect, but on autofire this may incure some nasty energy loss with certain guns. + + // Impact indirectly speaks of the size of the bullet, and thus strength of the backforce, theoretically.. so take it to the account. + // (Other than that, we have nothing to base our calculation on by now, the solution would be to make a new tag in weapons.xml, but that's modder-unfriendly.) + INT32 iKickPower = (INT32)(Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].ubImpact); + + // get weapon total weight + // Weapon weight here actually helps us, since it absorbs the power of the backforce. + INT16 sWeaponWeight = CalculateObjectWeight(&pSoldier->inv[pSoldier->ubAttackingHand]); + + // -------------------------- + // CALCULATE BASIC KICK POWER + // "Standard weapon" impact is around 30, "standard weapon" weight plus some attachments is 3-5 kilos, + // so for 30 and less impact make the kick power equal to it, then exponentially rise, so 40 impact makes double the amount. + // Some crazy weapons with 50 (or more) impact then have more than 5x more kick power than "reasonable" guns. + if ( iKickPower > 30 ) + iKickPower = 30 + ((iKickPower - 30) * (iKickPower - 30) / 3); + + // reduce it by 1% per 0,2 kilo of weapon weight + sWeaponWeight = min(99,(sWeaponWeight / 2)); + iKickPower = iKickPower * (100 - sWeaponWeight) / 100; + + // If one-handed gun, reduce it a bit, since the whole thing is somewhat different. + if ( !Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded ) + iKickPower = iKickPower * 3 / 4; // -25% + + // ::: overview ::: + // Glock 17 generates cca 18 points + // Colt M4 (with some attachemnts) generates cca 25 points + // .50 Beowulf (with some attachments) generates cca 40 points + // OSV-96 generates cca 115 points + + double dModifier = 0; + + // ---------------------------- + // APPLY REDUCTION FOR STRENGTH + // Furthermore reduce the kicking power by our strength (with "exceptionally" low strength, we get a penalty though). + // -1,5% per strength over 90, -1% per strength between 80 and 90, and -0.5% per strength between 70 and 80 + // --> max reduction -30% at 100 strength + INT16 sOurStrength = EffectiveStrength( pSoldier, FALSE ); + if ( sOurStrength < 55 ) + { + dModifier -= (55 - sOurStrength) / 2; //-0.5% per strength below 55 + if ( sOurStrength < 35 ) + dModifier -= (35 - sOurStrength) / 2; //-1% total per strength below 35 + } + else if ( sOurStrength > 70 ) + { + dModifier += (sOurStrength - 70) / 2; //-0.5% per strength over 70 + if ( sOurStrength > 80 ) + { + dModifier += (sOurStrength - 80) / 2; //-1% total per strength over 80 + if ( sOurStrength > 90 ) + dModifier += (sOurStrength - 90) / 2; //-1,5% total per strength over 90 + } + } + if ( dModifier != 0 ) + { + dModifier = min( 99, dModifier ); + iKickPower = (INT32)(iKickPower * (100 - dModifier) / 100); + } + + // ------------------------------------ + // APPLY MODIFIERS FOR STANCE AND BIPOD + dModifier = 0; + // Alternative weapon holding? + if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) + { + if ( Item[pSoldier->inv[pSoldier->ubAttackingHand].usItem].twohanded ) // firing from hip makes the kicking rather diminishing + dModifier += 80; // only 20% of the regular kick power + else // holding pistol in one hand is worse in this case + dModifier -= 33; // plus 33% power + } + // If weapon is rested on something or we are prone, reduce the power + if ( gGameExternalOptions.fWeaponResting && pSoldier->IsWeaponMounted() || ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE ) ) + { + dModifier += 40; // only 60% of the regular kick power if prone + dModifier += (2 * GetBipodBonus(&pSoldier->inv[pSoldier->ubAttackingHand])); // minus up to 20% for bipod + } + else if ( gAnimControl[ pSoldier->usAnimState ].ubHeight == ANIM_CROUCH ) + dModifier += 20; // only 80% of the regular kick power if crouching + + if ( dModifier != 0 ) + { + dModifier = min( 99, dModifier ); + iKickPower = (INT32)(iKickPower * (100 - dModifier) / 100); + } + + // --------------------------- + // APPLY MODIFIER FOR AUTOFIRE + // Now, on autofire this becomes real thing.. the kick power evolves by the length of the autofire + // Depending somehow on the weapon autofire penalty, the 4th-6th bullet can already deal double the amount of energy loss. + if ( pSoldier->bDoBurst > 1 ) + { + // per every shot after the first one, the power increases by an amount based on the weapon steadiness (autopenalty - reduction of it) + // the additional kick factor is 5% base + half the auto penalty, but is itself also reduced by the above adjustments + INT16 sSteadiness = Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].AutoPenalty - GetAutoToHitBonus(&pSoldier->inv[pSoldier->ubAttackingHand], FALSE ); + dModifier = (INT32)((3 + (sSteadiness / 2)) * (100 - dModifier) / 100); + if ( dModifier > 0 ) + { + for ( INT16 i = 1; i < pSoldier->bDoBurst; i++ ) + { + iKickPower = (INT32)(iKickPower * ( 100 + dModifier ) / 100); + } + } + } + + // For enemies, modify by difficulty + if ( pSoldier->bTeam == ENEMY_TEAM ) + { + switch( gGameOptions.ubDifficultyLevel ) + { + case DIF_LEVEL_EASY: + break; + case DIF_LEVEL_MEDIUM: + iKickPower = (iKickPower * 9)/10; // -10% + break; + case DIF_LEVEL_HARD: + iKickPower = (iKickPower * 3)/4; // -25% + break; + case DIF_LEVEL_INSANE: + iKickPower /= 2; // -50% + break; + } + } + + // adjust by predefined ini setting + iKickPower = (iKickPower * gGameExternalOptions.ubEnergyCostForWeaponRecoilKick / 100); + iKickPower = max(0, iKickPower); + + return ( iKickPower ); } \ No newline at end of file diff --git a/Tactical/Points.h b/Tactical/Points.h index a9be7f803..55a8ee86a 100644 --- a/Tactical/Points.h +++ b/Tactical/Points.h @@ -288,16 +288,16 @@ BOOLEAN SelectedMercCanAffordMove( ); BOOLEAN EnoughPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, BOOLEAN fDisplayMsg ); void DeductPoints( SOLDIERTYPE *pSoldier, INT16 sAPCost, INT32 iBPCost, UINT8 ubInterruptType = 2 ); // SANDRO - change for improved interrupt system (ubInterruptType = 2 = UNDEFINED_INTERRUPT) -INT32 AdjustBreathPts(SOLDIERTYPE *pSold, INT32 iBPCost); -void UnusedAPsToBreath(SOLDIERTYPE *pSold); +INT32 AdjustBreathPts( SOLDIERTYPE * pSoldier , INT32 iBPCost ); +void UnusedAPsToBreath( SOLDIERTYPE * pSoldier ); INT16 TerrainBreathPoints(SOLDIERTYPE * pSoldier, INT32 sGridNo,INT8 bDir, UINT16 usMovementMode); -INT16 MinAPsToAttack(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost = 0); +INT16 MinAPsToAttack(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, INT16 bAimTime, UINT8 ubForceRaiseGunCost = 0 ); INT16 MinPtsToMove(SOLDIERTYPE *pSoldier); INT8 MinAPsToStartMovement( SOLDIERTYPE * pSoldier, UINT16 usMovementMode ); INT8 PtsToMoveDirection(SOLDIERTYPE *pSoldier, INT8 bDirection ); UINT16 CalculateTurningCost(SOLDIERTYPE *pSoldier, UINT16 usItem, BOOLEAN fAddingTurningCost); -UINT16 CalculateRaiseGunCost(SOLDIERTYPE *pSoldier, BOOLEAN fAddingRaiseGunCost); -INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost = 0 ); +UINT16 CalculateRaiseGunCost(SOLDIERTYPE *pSoldier, BOOLEAN fAddingRaiseGunCost, INT32 iTargetGridNum, INT16 bAimTime ); +INT16 MinAPsToShootOrStab(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 bAimTime, UINT8 ubAddTurningCost, UINT8 ubForceRaiseGunCost = 0 ); BOOLEAN EnoughAmmo( SOLDIERTYPE *pSoldier, BOOLEAN fDisplay, INT8 bInvPos ); void DeductAmmo( SOLDIERTYPE *pSoldier, INT8 bInvPos ); @@ -360,7 +360,7 @@ INT16 GetAPsToBuildFortification( SOLDIERTYPE *pSoldier, INT32 usMapPos ); // ad INT16 GetAPsToJumpOver( SOLDIERTYPE *pSoldier ); -void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise ); +void GetAPChargeForShootOrStabWRTGunRaises( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubAddTurningCost, BOOLEAN *pfChargeTurning, BOOLEAN *pfChargeRaise, INT16 bAimTime ); UINT16 GetAPsToReloadRobot( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pRobot ); INT16 GetAPsToReloadGunWithAmmo( SOLDIERTYPE *pSoldier, OBJECTTYPE * pGun, OBJECTTYPE * pAmmo, BOOLEAN usAllAPs = TRUE ); @@ -383,4 +383,7 @@ INT16 GetAPsToDisarmMine( SOLDIERTYPE *pSoldier ); INT16 GetAPsToJumpWall( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ); INT16 GetBPsToJumpWall( SOLDIERTYPE *pSoldier, BOOLEAN fClimbDown ); +INT32 GetBPCostPer10APsForGunHolding( SOLDIERTYPE * pSoldier, BOOLEAN fEstimate = FALSE ); +INT32 GetBPCostForRecoilkick( SOLDIERTYPE * pSoldier ); + #endif diff --git a/Tactical/Soldier Ani.cpp b/Tactical/Soldier Ani.cpp index c7ad9866e..d7c4696e8 100644 --- a/Tactical/Soldier Ani.cpp +++ b/Tactical/Soldier Ani.cpp @@ -61,6 +61,7 @@ #include "GameSettings.h" #include "interface dialogue.h" #include "Strategic Status.h" +#include "Food.h" #endif //forward declarations of common classes to eliminate includes @@ -71,7 +72,7 @@ class SOLDIERTYPE; #define NO_JUMP 0 #define MAX_ANIFRAMES_PER_FLASH 2 //#define TIME_FOR_RANDOM_ANIM_CHECK 10 -#define TIME_FOR_RANDOM_ANIM_CHECK 2 +#define TIME_FOR_RANDOM_ANIM_CHECK 1 BOOLEAN gfLastMercTalkedAboutKillingID = NOBODY; @@ -104,7 +105,7 @@ extern BOOLEAN gfKillingGuysForLosingBattle; extern UINT8 gubInterruptProvoker; -extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); // Animation code explanations! // @@ -381,16 +382,13 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) //DIGICRAB: Burst UnCap //Loop around in the animation if we still have burst rounds to fire - if (pSoldier->bDoBurst - && ( - pSoldier->bDoBurst <= ( (pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand )) ) - || (( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst <= Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst)) - ) - ) + if (pSoldier->bDoBurst && !(pSoldier->IsValidSecondHandBurst()) + && ( pSoldier->bDoBurst <= ( (pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand )) ) + || (( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst <= Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst)) )) { - if(pSoldier->usAnimState == 44 || pSoldier->usAnimState == 109 || pSoldier->usAnimState == 108 && pSoldier->usAniCode == 33) //we are standing, crounching or prone, firing the fast shot + if(pSoldier->usAnimState == STANDING_BURST || pSoldier->usAnimState == CROUCHED_BURST || pSoldier->usAnimState == PRONE_BURST || pSoldier->usAnimState == BURST_ALTERNATIVE_STAND && pSoldier->usAniCode == 33) //we are standing, crounching or prone, firing the fast shot pSoldier->usAniCode = 3; - else if(pSoldier->usAnimState == 175 && pSoldier->usAniCode == 37) //we are firing down to something very close, last shot + else if(pSoldier->usAnimState == FIRE_BURST_LOW_STAND || pSoldier->usAnimState == LOW_BURST_ALTERNATIVE_STAND && pSoldier->usAniCode == 37) //we are firing down to something very close, last shot pSoldier->usAniCode = 14; } @@ -781,10 +779,21 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) OBJECTTYPE* pObjHand = pSoldier->GetUsedWeapon( &pSoldier->inv[HANDPOS] ); - if ( ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst) - || (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand )))) ) + if ( ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST && pSoldier->bDoBurst > Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst) ) { - DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because burst size too large"); + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because gl max burst size reached"); + fStop = TRUE; + fFreeUpAttacker = TRUE; + } + else if (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && !(pSoldier->IsValidSecondHandBurst()) && (pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(pSoldier->bDoAutofire):(GetShotsPerBurst( pObjHand ))))) + { + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because gun max burst size reached"); + fStop = TRUE; + fFreeUpAttacker = TRUE; + } + else if (pSoldier->bWeaponMode != WM_ATTACHED_GL_BURST && pSoldier->IsValidSecondHandBurst() && (pSoldier->bDoBurst > ((pSoldier->bDoAutofire)?(2*pSoldier->bDoAutofire):(2*GetShotsPerBurst( pObjHand ))))) + { + DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"AdjustToNextAnimationFrame: Burst case 448, stopping because dual max burst size reached"); fStop = TRUE; fFreeUpAttacker = TRUE; } @@ -880,15 +889,26 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) { case ANIM_STAND: - pSoldier->ChangeSoldierState( AIM_RIFLE_STAND, 0 , FALSE ); + if ( pSoldier->usAnimState == BURST_DUAL_STAND ) + pSoldier->ChangeSoldierState( AIM_DUAL_STAND, 0 , FALSE ); + else if ( pSoldier->usAnimState == BURST_ALTERNATIVE_STAND || pSoldier->usAnimState == LOW_BURST_ALTERNATIVE_STAND ) + pSoldier->ChangeSoldierState( AIM_ALTERNATIVE_STAND, 0 , FALSE ); + else + pSoldier->ChangeSoldierState( AIM_RIFLE_STAND, 0 , FALSE ); break; case ANIM_PRONE: - pSoldier->ChangeSoldierState( AIM_RIFLE_PRONE, 0 , FALSE ); + if ( pSoldier->usAnimState == BURST_DUAL_PRONE ) + pSoldier->ChangeSoldierState( AIM_DUAL_PRONE, 0 , FALSE ); + else + pSoldier->ChangeSoldierState( AIM_RIFLE_PRONE, 0 , FALSE ); break; case ANIM_CROUCH: - pSoldier->ChangeSoldierState( AIM_RIFLE_CROUCH, 0 , FALSE ); + if ( pSoldier->usAnimState == BURST_DUAL_CROUCH ) + pSoldier->ChangeSoldierState( AIM_DUAL_CROUCH, 0 , FALSE ); + else + pSoldier->ChangeSoldierState( AIM_RIFLE_CROUCH, 0 , FALSE ); break; } @@ -1324,33 +1344,68 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) case 472: { - BOOLEAN fGoBackToAimAfterHit; + INT8 bGoBackToAimAfterHit; // Save old flag, then reset. If we do nothing special here, at least go back // to aim if we were. - fGoBackToAimAfterHit = pSoldier->flags.fGoBackToAimAfterHit; - pSoldier->flags.fGoBackToAimAfterHit = FALSE; - - if ( !( pSoldier->flags.uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) - { - switch( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) - { - case ANIM_STAND: - - // OK, we can do some cool things here - first is to make guy walkl back a bit... - // pSoldier->ChangeSoldierState( STANDING_HIT_BEGINCROUCHDOWN, 0, FALSE ); - // return( TRUE ); - break; - - } - } + bGoBackToAimAfterHit = pSoldier->flags.bGoBackToAimAfterHit; + pSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT; // CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO..... - if ( fGoBackToAimAfterHit ) + if ( pSoldier->stats.bLife >= OKLIFE && bGoBackToAimAfterHit) { - if ( pSoldier->stats.bLife >= OKLIFE ) - { - pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE ); + if ( bGoBackToAimAfterHit == GO_TO_AIM_AFTER_HIT ) + { + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, FALSE ); + } + else if ( bGoBackToAimAfterHit == GO_TO_ALTERNATIVE_AIM_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) ) + { + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, TRUE ); + } + else if ( bGoBackToAimAfterHit == GO_TO_HTH_BREATH_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND)) + { + if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_NONE | IC_PUNCH) ) + { + if ((((NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + (HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && pSoldier->ubBodyType == REGMALE ) + { + if(is_networked) + pSoldier->ChangeSoldierState( NINJA_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( NINJA_BREATH, 0 , FALSE ); + } + else + { + if(is_networked) + pSoldier->ChangeSoldierState( PUNCH_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( PUNCH_BREATH, 0 , FALSE ); + } + } + else if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE) ) + { + if(is_networked) + pSoldier->ChangeSoldierState( KNIFE_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( KNIFE_BREATH, 0 , FALSE ); + } + } + else if ( bGoBackToAimAfterHit == GO_TO_COWERING_AFTER_HIT ) + { + if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH) + { + if(is_networked) + pSoldier->ChangeSoldierState( START_COWER_CROUCHED, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_CROUCHED, 0 , FALSE ); + } + else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) + { + if(is_networked) + pSoldier->ChangeSoldierState( START_COWER_PRONE, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_PRONE, 0 , FALSE ); + } } return( TRUE ); } @@ -1632,6 +1687,7 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) break; case 491: + // SANDRO - I've been here, messing with stuff... // CODE: HANDLE RANDOM BREATH ANIMATION //if ( pSoldier->stats.bLife > INJURED_CHANGE_THREASHOLD ) @@ -1644,141 +1700,229 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) { pSoldier->uiTimeOfLastRandomAction = 0; - // Don't do any in water! - if ( !pSoldier->MercInWater( ) ) + // Don't play these generally if this is the guy selected by player, as this one is "awaiting orders" + if (pSoldier->ubID != (UINT8)gusSelectedSoldier || Random( 10 ) == 0 ) { - // OK, make a dice roll - ubDiceRoll = (UINT8)Random( 100 ); - - // Determine what is in our hand; - usItem = pSoldier->inv[ HANDPOS ].usItem; - - // Default to nothing in hand ( nothing in quotes, we do have something but not just visible ) - ubRandomHandIndex = RANDOM_ANIM_NOTHINGINHAND; - - if ( pSoldier->inv[ HANDPOS ].exists() == true ) + // Don't do any in water! + // Also don't play if we are in the middle of something + if ( !pSoldier->MercInWater( ) && !pSoldier->flags.fTurningUntilDone ) { - if ( Item[ usItem ].usItemClass == IC_GUN ) + // OK, make a dice roll + ubDiceRoll = (UINT8)Random( 100 ); + + // Determine what is in our hand; + usItem = pSoldier->inv[ HANDPOS ].usItem; + + // Default to nothing in hand ( nothing in quotes, we do have something but not just visible ) + ubRandomHandIndex = RANDOM_ANIM_NOTHINGINHAND; + + if ( pSoldier->inv[ HANDPOS ].exists() == true ) { - // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) - if ( (Item[ usItem ].twohanded ) ) + if ( Item[ usItem ].usItemClass == IC_GUN ) { - // Set to rifle - ubRandomHandIndex = RANDOM_ANIM_RIFLEINHAND; - } - else - { - // Don't EVER do a trivial anim... - break; + // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) + if ( (Item[ usItem ].twohanded ) ) + { + // Set to rifle + ubRandomHandIndex = RANDOM_ANIM_RIFLEINHAND; + } + //else + //{ + // // Don't EVER do a trivial anim... + // break; + // ubRandomHandIndex = RANDOM_ANIM_NOTHINGORPISTOLINHAND; + //} } } - } - // Check which animation to play.... - for ( cnt = 0; cnt < MAX_RANDOM_ANIMS_PER_BODYTYPE; cnt++ ) - { - pAnimDef = &( gRandomAnimDefs[ pSoldier->ubBodyType ][ cnt ] ); - - if ( pAnimDef->sAnimID != 0 ) + // Check which animation to play.... + for ( cnt = 0; cnt < MAX_RANDOM_ANIMS_PER_BODYTYPE; cnt++ ) { - // If it's an injured animation and we are not in the threashold.... - if ( ( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->stats.bLife >= INJURED_CHANGE_THREASHOLD ) - { - continue; - } + pAnimDef = &( gRandomAnimDefs[ pSoldier->ubBodyType ][ cnt ] ); - // If we need to do an injured one, don't do any others... - if ( !( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->stats.bLife < INJURED_CHANGE_THREASHOLD ) + if ( pAnimDef->sAnimID != 0 ) { - continue; - } + BOOLEAN fStarving = FALSE; + UINT8 foodsituation; + UINT8 watersituation; + GetFoodSituation( pSoldier, &foodsituation, &watersituation ); + if ( foodsituation >= FOOD_VERY_LOW || watersituation >= FOOD_VERY_LOW ) + fStarving = TRUE; - // If it's a drunk animation and we are not in the threashold.... - if ( ( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) < BORDERLINE ) - { - continue; - } - - // If we need to do an injured one, don't do any others... - if ( !( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) >= BORDERLINE ) - { - continue; - } - - // Check if it's our hand - if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex ) - { - continue; - } - - // Check if it's casual and we're in combat and it's not our guy - if ( ( pAnimDef->ubFlags & RANDOM_ANIM_CASUAL ) ) - { - // If he's a bad guy, do not do it! - if ( pSoldier->bTeam != gbPlayerNum || ( gTacticalStatus.uiFlags & INCOMBAT ) ) + // If it's an injured animation and we are not in the threashold.... + if ( ( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && pSoldier->stats.bLife >= INJURED_CHANGE_THREASHOLD && pSoldier->bPoisonSum <= 0 && !fStarving ) { continue; } - } - // If we are an alternate big guy and have been told to use a normal big merc ani... - if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) - { - continue; - } - - // If we are a normal big guy and have been told to use an alternate big merc ani... - if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && !( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) - { - continue; - } - - // Check if it's the proper height - if ( pAnimDef->ubAnimHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) - { - // OK, If we rolled a value that lies within the range for this random animation, use this one! - if ( ubDiceRoll >= pAnimDef->ubStartRoll && ubDiceRoll <= pAnimDef->ubEndRoll ) + // If we need to do an injured one, don't do any others... + if ( !( pAnimDef->ubFlags & RANDOM_ANIM_INJURED ) && (pSoldier->stats.bLife < INJURED_CHANGE_THREASHOLD || pSoldier->bPoisonSum > 0 || fStarving) ) { - // Are we playing a sound - if ( pAnimDef->sAnimID == RANDOM_ANIM_SOUND ) + continue; + } + + // If it's a drunk animation and we are not in the threashold.... + if ( ( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && GetDrunkLevel( pSoldier ) < BORDERLINE && pSoldier->bPoisonSum <= 0 && !fStarving ) + { + continue; + } + + // If we need to do an injured one, don't do any others... + if ( !( pAnimDef->ubFlags & RANDOM_ANIM_DRUNK ) && (GetDrunkLevel( pSoldier ) >= BORDERLINE || pSoldier->bPoisonSum > 0 || fStarving) ) + { + continue; + } + + // Check if it's our hand + /*if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex ) + { + continue; + }*/ + + // Don't do this if a pistol in hand + if ( ubRandomHandIndex == RANDOM_ANIM_RIFLEINHAND && pAnimDef->sAnimID == BIGGUY_STONE ) + { + continue; + } + + // Check if it's casual and we're in combat and it's not our guy + if ( ( pAnimDef->ubFlags & RANDOM_ANIM_CASUAL ) ) + { + // If he's a bad guy, do not do it! + if ( pSoldier->bTeam != gbPlayerNum || ( gTacticalStatus.uiFlags & INCOMBAT ) ) { - if ( pSoldier->ubBodyType == COW ) + continue; + } + } + + // If it is lookaround animation, don't play it if we see at least one enemy + if ( pAnimDef->ubFlags & RANDOM_ANIM_LOOKAROUND ) + { + // enemy on sight, don't pretend we don't see him! + if ( pSoldier->aiData.bOppCnt > 0 ) + { + continue; + } + } + + // If we are an alternate big guy and have been told to use a normal big merc ani... + //if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) + if ( ( pAnimDef->ubFlags & RANDOM_ANIM_FIRSTBIGMERC ) && !( DecideAltAnimForBigMerc( pSoldier )) ) + { + continue; + } + + // If we are a normal big guy and have been told to use an alternate big merc ani... + //if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && !( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) ) + if ( ( pAnimDef->ubFlags & RANDOM_ANIM_SECONDBIGMERC ) && ( DecideAltAnimForBigMerc( pSoldier )) ) + { + continue; + } + + // Check if it's the proper height + if ( pAnimDef->ubAnimHeight == gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + { + // OK, If we rolled a value that lies within the range for this random animation, use this one! + if ( ubDiceRoll >= pAnimDef->ubStartRoll && ubDiceRoll <= pAnimDef->ubEndRoll ) + { + // Are we playing a sound + if ( pAnimDef->sAnimID == RANDOM_ANIM_SOUND ) { - if ( Random( 2 ) == 1 ) + if ( pSoldier->ubBodyType == COW ) { - if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 ) + if ( Random( 10 ) == 1 ) { - // DO this every 10th time or so... - if ( Random( 100 ) < 10 ) + if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 ) { + // DO this every 10th time or so... + if ( Random( 100 ) < 10 ) + { + // Play sound + PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + } + else + { + // Play sound - PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); } } - else + } + else if ( pSoldier->ubBodyType == CROW ) + { + if ( Random( 4 ) == 1 ) { + if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && pSoldier->bVisible == -1 ) + { + // DO this every 10th time or so... + if ( Random( 100 ) < 10 ) + { + // Play sound + PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } + } + else + { - // Play sound - PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + // Play sound + PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } } } + else + { + // Play sound + PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + } } else { - // Play sound - PlayJA2SampleFromFile( pAnimDef->zSoundFile, RATE_11025, SoundVolume( MIDVOLUME, pSoldier->sGridNo ), 1, SoundDir( pSoldier->sGridNo ) ); + if ( pAnimDef->ubHandRestriction != RANDOM_ANIM_IRRELEVENTINHAND && pAnimDef->ubHandRestriction != ubRandomHandIndex ) + { + // only if we are told to play an anim without rifle and we have a rifle (we can lower it for an instance), not vice versa + if ( pAnimDef->ubHandRestriction == RANDOM_ANIM_RIFLEINHAND && ubRandomHandIndex != RANDOM_ANIM_RIFLEINHAND ) + { + continue; + } + // this is not for enemy fools, only for cool mercs + if ( pSoldier->bTeam != gbPlayerNum ) + { + continue; + } + // these funny moves are not likely to be used in combat + if ( ( gTacticalStatus.uiFlags & INCOMBAT ) ) + { + if ( pSoldier->aiData.bMorale < 95 ) // .. unless we are really confident about ourselves + { + continue; + } + else + { + if ( Random( 2 ) == 1 ) // even if we are, still make them show seldomly + continue; + } + } + if ( Random( 4 ) == 1 ) // make this rare as we need to lower the weapon -> make the move -> raise the weapon again... rather show off + { + continue; + } + } + // generally make funny moves less common in combat, we need to focus! + if ( ( gTacticalStatus.uiFlags & INCOMBAT ) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_INJURED )) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_DRUNK )) && !( pAnimDef->ubFlags & ( RANDOM_ANIM_LOOKAROUND )) ) + { + if ( Random( 3 ) == 1 ) + continue; + } + // finally if we got here, send state change + pSoldier->ChangeSoldierState( pAnimDef->sAnimID, 0 , FALSE ); } + return( TRUE ); } - else - { - pSoldier->ChangeSoldierState( pAnimDef->sAnimID, 0 , FALSE ); - } - return( TRUE ); } } } } - } } } @@ -1815,6 +1959,33 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) CancelAIAction( pTSoldier, TRUE ); } + // SANDRO - Set goback to aim after hit flag + if (( Item[ pTSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE | IC_PUNCH | IC_NONE) ) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (gAnimControl[ pTSoldier->usAnimState ].ubEndHeight == ANIM_STAND) ) + { + if ( pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 ) + { + pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_HTH_BREATH_AFTER_HIT; + } + } + // If we were aiming + // actually no... favor htH a bit more, by making the opponent drop his readied stance when attacked in close combat, regardless he will dodge it or not + //else if ( gAnimControl[ pTSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) + //{ + // if ( gAnimControl[ pTSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) // alternative weapon holding stance + // pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_ALTERNATIVE_AIM_AFTER_HIT; + // else // standard + // pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_AIM_AFTER_HIT; + //} + // if we were cowering (this is different from the bellow, we don't use that status flag for this animation) + else if ( pTSoldier->usAnimState == COWERING ) + { + pTSoldier->flags.bGoBackToAimAfterHit = GO_TO_COWERING_AFTER_HIT; + } + else + { + pTSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT; + } + // Turn towards the person! pTSoldier->EVENT_SetSoldierDesiredDirection( GetDirectionFromGridNo( pSoldier->sGridNo, pTSoldier ) ); @@ -1822,25 +1993,25 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) pTSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE ); // SANDRO - after dodging melee attack go to apropriate stance - if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH)) - { - if ((((NUM_SKILL_TRAITS( pTSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || - (HAS_SKILL_TRAIT( pTSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && - pTSoldier->ubBodyType == REGMALE ) - { - //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; - pTSoldier->usPendingAnimation = NINJA_BREATH ; - } - else - { - pTSoldier->usPendingAnimation = PUNCH_BREATH ; - } - } - else if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) - { - //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; - pTSoldier->usPendingAnimation = KNIFE_BREATH ; - } + //if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH || Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_NONE)) + //{ + // if ((((NUM_SKILL_TRAITS( pTSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + // (HAS_SKILL_TRAIT( pTSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && + // pTSoldier->ubBodyType == REGMALE ) + // { + // //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; + // pTSoldier->usPendingAnimation = NINJA_BREATH ; + // } + // else + // { + // pTSoldier->usPendingAnimation = PUNCH_BREATH ; + // } + //} + //else if ( (gAnimControl[ pTSoldier->usAnimState ].ubHeight == ANIM_STAND) && pTSoldier->stats.bLife > 30 && pTSoldier->bBreath > 25 && (Item[pTSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) + //{ + // //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; + // pTSoldier->usPendingAnimation = KNIFE_BREATH ; + //} } } } @@ -2146,6 +2317,70 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) } } + if (pSoldier->usAnimState == DODGE_ONE && pSoldier->usPendingAnimation == NO_PENDING_ANIMATION ) + { + INT8 bGoBackToAimAfterHit = pSoldier->flags.bGoBackToAimAfterHit; + pSoldier->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT; + + // CODE: HANDLE ANY RANDOM HIT VARIATIONS WE WISH TO DO..... + if ( pSoldier->stats.bLife >= OKLIFE && bGoBackToAimAfterHit ) + { + if ( bGoBackToAimAfterHit == GO_TO_AIM_AFTER_HIT ) + { + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, FALSE ); + } + else if ( bGoBackToAimAfterHit == GO_TO_ALTERNATIVE_AIM_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND) ) + { + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, FALSE, TRUE ); + } + else if ( bGoBackToAimAfterHit == GO_TO_HTH_BREATH_AFTER_HIT && (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND)) + { + if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_NONE | IC_PUNCH) ) + { + if ((((NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + (HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && pSoldier->ubBodyType == REGMALE ) + { + if(is_networked) + pSoldier->ChangeSoldierState( NINJA_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( NINJA_BREATH, 0 , FALSE ); + } + else + { + if(is_networked) + pSoldier->ChangeSoldierState( PUNCH_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( PUNCH_BREATH, 0 , FALSE ); + } + } + else if ( Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & (IC_BLADE) ) + { + if(is_networked) + pSoldier->ChangeSoldierState( KNIFE_BREATH, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( KNIFE_BREATH, 0 , FALSE ); + } + } + else if ( bGoBackToAimAfterHit == GO_TO_COWERING_AFTER_HIT ) + { + if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_CROUCH) + { + if(is_networked) + pSoldier->ChangeSoldierState( START_COWER_CROUCHED, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_CROUCHED, 0 , FALSE ); + } + else if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) + { + if(is_networked) + pSoldier->ChangeSoldierState( START_COWER_PRONE, 0 , FALSE ); + else + pSoldier->EVENT_InitNewSoldierAnim( START_COWER_PRONE, 0 , FALSE ); + } + } + return( TRUE ); + } + } pSoldier->ubDesiredHeight = NO_DESIRED_HEIGHT; @@ -2338,6 +2573,34 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) } else if ( sNewAniFrame > 599 && sNewAniFrame <= 699 ) { + // SANDRO - added some hacking in here, so I don't need to overwrite all those animation frame scripts + switch(pSoldier->usAnimState) + { + // go to apropriate stance for alternative weapon holding + case READY_ALTERNATIVE_STAND: + case SHOOT_ALTERNATIVE_STAND: + case BURST_ALTERNATIVE_STAND: + case LOW_SHOT_ALTERNATIVE_STAND: + case LOW_BURST_ALTERNATIVE_STAND: + pSoldier->EVENT_InitNewSoldierAnim( AIM_ALTERNATIVE_STAND, 0 , FALSE ); + return( TRUE ); + break; + // hack to raise rifle after using idle animation without one in hand + case REG_SQUISH: + case REG_PULL: + case BIGBUY_FLEX: + case BIGBUY_STRECH: + case FEM_KICKSN: + case FEM_WIPE: + if ( pSoldier->inv[ HANDPOS ].exists() == true && Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_GUN && Item[ pSoldier->inv[ HANDPOS ].usItem ].twohanded ) + { + pSoldier->EVENT_InitNewSoldierAnim( RAISE_RIFLE, 0 , FALSE ); + return( TRUE ); + } + break; + default: + break; + } // Jump, to animation script pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 600 ), 0 , FALSE ); return( TRUE ); @@ -3023,12 +3286,54 @@ BOOLEAN AdjustToNextAnimationFrame( SOLDIERTYPE *pSoldier ) pSoldier->usAniCode = 0; } - else if ( sNewAniFrame > 999 ) + else if ( sNewAniFrame > 999 && sNewAniFrame <= 1099 ) { // Jump, to animation script ( in the 300+ range ) pSoldier->EVENT_InitNewSoldierAnim( (UINT16)(sNewAniFrame - 700 ), 0 , FALSE ); return( TRUE ); } + else if ( sNewAniFrame > 1099 ) + { + switch( sNewAniFrame ) + { + + case 1101: + // SANDRO - dual burst check for repeating animation + { + OBJECTTYPE* pObjHand = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] ); + + if (pSoldier->bDoBurst && ( pSoldier->bDoBurst <= ( (pSoldier->bDoAutofire)?(2*pSoldier->bDoAutofire):(2*GetShotsPerBurst( pObjHand )) ) )) + { + if ( pSoldier->usAnimState == BURST_DUAL_PRONE ) + pSoldier->usAniCode = 2; + else + pSoldier->usAniCode = 1; + } + else + { + pSoldier->usAniCode++; + } + break; + } + case 1102: + // SANDRO - end dual burst check for going to proper aim state + + switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) + { + case ANIM_STAND: + pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_STAND, 0 , FALSE ); + break; + case ANIM_CROUCH: + pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_CROUCH, 0 , FALSE ); + break; + case ANIM_PRONE: + pSoldier->EVENT_InitNewSoldierAnim( AIM_DUAL_PRONE, 0 , FALSE ); + break; + } + return( TRUE ); + break; + } + } // Loop here until we break on a real item! } while ( TRUE ); @@ -4018,7 +4323,33 @@ BOOLEAN CheckForImproperFireGunEnd( SOLDIERTYPE *pSoldier ) if ( Item[ pSoldier->inv[ SECONDHANDPOS ].usItem ].usItemClass != IC_GUN ) { // OK, put gun down.... - pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE ); + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE ); + return( TRUE ); + } + } + + // SANDRO: if we are holding up a very heavy gun, and can't do it anymore, lower it + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight && pSoldier->bBreath < OKBREATH ) + { + // Check for breath collapse, though this should rarely happen + if ( pSoldier->CheckForBreathCollapse( ) ) + { + UnSetUIBusy( pSoldier->ubID ); + SoldierCollapse( pSoldier ); + pSoldier->bBreathCollapsed = FALSE; + return( TRUE ); + } + // ok, if this gun is rather heavy, and cost us at least 3 energy points per turn, and we got very low on breath + else if ( (GetBPCostPer10APsForGunHolding( pSoldier ) * 10) >= (300 * gGameExternalOptions.ubEnergyCostForWeaponWeight / 100) ) + { + // throw quote + if ( !(pSoldier->usQuoteSaidFlags & SOLDIER_QUOTE_SAID_LOW_BREATH ) ) + { + TacticalCharacterDialogue( pSoldier, QUOTE_OUT_OF_BREATH ); + pSoldier->usQuoteSaidFlags |= SOLDIER_QUOTE_SAID_LOW_BREATH; + } + // Put gun down.... + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection, TRUE, FALSE ); return( TRUE ); } } @@ -4076,18 +4407,21 @@ BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier ) return( TRUE ); case SHOOT_DUAL_STAND: + case BURST_DUAL_STAND: // Normal shoot rifle.... play pSoldier->ChangeSoldierState( STANDING_SHOOT_DWEL_UNJAM, 0 , FALSE ); return( TRUE ); case SHOOT_DUAL_PRONE: + case BURST_DUAL_PRONE: // Normal shoot rifle.... play pSoldier->ChangeSoldierState( PRONE_SHOOT_DWEL_UNJAM, 0 , FALSE ); return( TRUE ); case SHOOT_DUAL_CROUCH: + case BURST_DUAL_CROUCH: // Normal shoot rifle.... play pSoldier->ChangeSoldierState( CROUCH_SHOOT_DWEL_UNJAM, 0 , FALSE ); @@ -4100,6 +4434,20 @@ BOOLEAN HandleUnjamAnimation( SOLDIERTYPE *pSoldier ) pSoldier->ChangeSoldierState( STANDING_SHOOT_LOW_UNJAM, 0 , FALSE ); return( TRUE ); + case SHOOT_ALTERNATIVE_STAND: + case BURST_ALTERNATIVE_STAND: + + // Normal shoot rifle.... play + pSoldier->ChangeSoldierState( UNJAM_ALTERNATIVE_STAND, 0 , FALSE ); + return( TRUE ); + + case LOW_SHOT_ALTERNATIVE_STAND: + case LOW_BURST_ALTERNATIVE_STAND: + + // Normal shoot rifle.... play + pSoldier->ChangeSoldierState( LOW_UNJAM_ALTERNATIVE_STAND, 0 , FALSE ); + return( TRUE ); + } return( FALSE ); diff --git a/Tactical/Soldier Control.cpp b/Tactical/Soldier Control.cpp index a9027ec9a..03f2ad872 100644 --- a/Tactical/Soldier Control.cpp +++ b/Tactical/Soldier Control.cpp @@ -472,7 +472,7 @@ void STRUCT_Flags::ConvertFrom_101_To_102(const OLDSOLDIERTYPE_101& src) this->fBeginFade = src.fBeginFade; this->fDontChargeReadyAPs = src.fDontChargeReadyAPs; this->fPrevInWater = src.fPrevInWater; - this->fGoBackToAimAfterHit = src.fGoBackToAimAfterHit; + this->bGoBackToAimAfterHit = src.fGoBackToAimAfterHit; this->fDisplayDamage = src.fDisplayDamage; this->fUIMovementFast = src.fUIMovementFast; this->fDeadSoundPlayed = src.fDeadSoundPlayed; @@ -734,10 +734,14 @@ SOLDIERTYPE& SOLDIERTYPE::operator=(const OLDSOLDIERTYPE_101& src) this->sLastTarget = src.sLastTarget; // HEADROCK HAM 4: TODO: Added four new variables to soldiertype. MAke sure they don't screw it all up! - this->dPrevMuzzleOffsetX = 0.0; - this->dPrevMuzzleOffsetY = 0.0; - this->dPrevCounterForceX = 0.0; - this->dPrevCounterForceY = 0.0; + this->dPrevMuzzleOffsetX[0] = 0.0; + this->dPrevMuzzleOffsetX[1] = 0.0; + this->dPrevMuzzleOffsetY[0] = 0.0; + this->dPrevMuzzleOffsetY[1] = 0.0; + this->dPrevCounterForceX[0] = 0.0; + this->dPrevCounterForceX[1] = 0.0; + this->dPrevCounterForceY[0] = 0.0; + this->dPrevCounterForceY[1] = 0.0; this->bTilesMoved = src.bTilesMoved; this->dNextBleed = src.dNextBleed; @@ -1672,7 +1676,7 @@ BOOLEAN gfGetNewPathThroughPeople = FALSE; // LOCAL FUNCTIONS // DO NOT CALL UNLESS THROUGH EVENT_SetSoldierPosition -UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); +UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fAltWeaponHolding ); BOOLEAN CheckForFullStruct( INT32 sGridNo, UINT16 *pusIndex ); void SetSoldierLocatorOffsets( SOLDIERTYPE *pSoldier ); void CheckForFullStructures( SOLDIERTYPE *pSoldier ); @@ -2277,7 +2281,7 @@ void SOLDIERTYPE::DoNinjaAttack( void ) ubTargetStance = gAnimControl[ pTSoldier->usAnimState ].ubEndHeight; // Get his life...if < certain value, do finish! - // SANDRO - Enhanced Close Combat System - Spinning kick is performed on focuse attack + // SANDRO - Enhanced Close Combat System - Spinning kick is performed on focused attack if (gGameExternalOptions.fEnhancedCloseCombatSystem && ( ( this->aiData.bAimTime > 0 ) && ubTargetStance != ANIM_PRONE )) { this->ChangeSoldierState( NINJA_SPINKICK, 0 , FALSE ); @@ -2841,17 +2845,46 @@ BOOLEAN ReevaluateEnemyStance( SOLDIERTYPE *pSoldier, UINT16 usAnimState ) } } - if (iClosestEnemy != NOBODY) + if (iClosestEnemy != NOBODY ) { - // Change to fire ready animation - ConvertGridNoToXY( MercPtrs[ iClosestEnemy ]->sGridNo, &sTargetXPos, &sTargetYPos ); + + // SANDRO - do we want this to be happening at all? It is somehow unwelcomed in IIS and for alternative weapon holding, + // besides it is rather illogical... well, I've made an ini setting for it + if ( gGameExternalOptions.fNoEnemyAutoReadyWeapon == 0 ) + { + // Change to fire ready animation + ConvertGridNoToXY( MercPtrs[ iClosestEnemy ]->sGridNo, &sTargetXPos, &sTargetYPos ); - pSoldier->flags.fDontChargeReadyAPs = TRUE; + pSoldier->flags.fDontChargeReadyAPs = TRUE; - // Ready weapon - fReturnVal = pSoldier->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE ); + // Ready weapon + fReturnVal = pSoldier->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE, AIDecideHipOrShoulderStance( pSoldier, MercPtrs[ iClosestEnemy ]->sGridNo ) ); - return( fReturnVal ); + return( fReturnVal ); + } + // this makes the soldier to only turn towards our direction, instead of raising his weapon + else if ( gGameExternalOptions.fNoEnemyAutoReadyWeapon == 2 ) + { + //ConvertGridNoToXY( MercPtrs[ iClosestEnemy ]->sGridNo, &sTargetXPos, &sTargetYPos ); + //sFacingDir = GetDirectionFromXY( sXPos, sYPos, pSoldier ); + INT16 sFacingDir = GetDirectionToGridNoFromGridNo( pSoldier->sGridNo, MercPtrs[ iClosestEnemy ]->sGridNo ); + + if ( sFacingDir != pSoldier->ubDirection ) + { + INT16 sAPCost = GetAPsToLook( pSoldier ); + + // Check AP cost... + if ( !EnoughPoints( pSoldier, sAPCost, 0, TRUE ) ) + { + return( FALSE ); + } + + SendSoldierSetDesiredDirectionEvent( pSoldier, sFacingDir ); + //fReturnVal = MakeSoldierTurn( pSoldier, sXPos, sYPos ); + + return( TRUE ); + } + } } } @@ -2875,7 +2908,8 @@ void CheckForFreeupFromHit( SOLDIERTYPE *pSoldier, UINT32 uiOldAnimFlags, UINT32 return; } - if ( usOldAniState != usNewState && ( uiOldAnimFlags & ANIM_HITSTART ) && !( uiNewAnimFlags & ANIM_HITFINISH ) && !( uiNewAnimFlags & ANIM_IGNOREHITFINISH ) && !(pSoldier->flags.uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) + //if ( usOldAniState != usNewState && ( uiOldAnimFlags & ANIM_HITSTART ) && !( uiNewAnimFlags & ANIM_HITFINISH ) && !( uiNewAnimFlags & ANIM_IGNOREHITFINISH ) && !(pSoldier->flags.uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) + if ( usOldAniState != usNewState && ( uiOldAnimFlags & ANIM_HITSTART ) && !( uiNewAnimFlags & ANIM_HITFINISH ) && !(pSoldier->flags.uiStatusFlags & SOLDIER_TURNINGFROMHIT ) ) { // 0verhaul: Yet again, this is handled by the state transition code. // Release attacker @@ -2923,7 +2957,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart DebugMsg(TOPIC_JA2,DBG_LEVEL_3,"EVENT_InitNewSoldierAnim"); INT32 usNewGridNo = 0; INT16 sAPCost = 0; - INT16 sBPCost = 0; + INT32 sBPCost = 0; UINT32 uiOldAnimFlags; UINT32 uiNewAnimFlags; UINT16 usSubState; @@ -3012,6 +3046,23 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart } } } + + // Going from hip stance to shoulder stance, skip first 2 frames for smoother graphic look + if ( usNewState == READY_RIFLE_STAND && (gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING )) ) + { + if ( this->ubBodyType == BIGMALE ) + usStartingAniCode = 1; // this looks better for big mercs + else + usStartingAniCode = 2; + } + // Going from shoulder stance to hip stance + else if ( usNewState == READY_ALTERNATIVE_STAND && (gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE )) ) + { + if ( Item[this->inv[HANDPOS].usItem].twohanded ) + usStartingAniCode = 1; + else + usStartingAniCode = 2; + } } if ( usNewState == ADJACENT_GET_ITEM ) @@ -3112,6 +3163,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // ATE: Don't raise/lower automatically if we are low on health, // as our gun looks lowered anyway.... //if ( this->stats.bLife > INJURED_CHANGE_THREASHOLD ) + if (!this->MercInWater()) { // Don't do some of this if we are a monster! // ATE: LOWER AIMATION IS GOOD, RAISE ONE HOWEVER MAY CAUSE PROBLEMS FOR AI.... @@ -3166,11 +3218,30 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart } // Are we cowering and are tyring to move, getup first... - if ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING && this->usAnimState == COWERING && gAnimControl[ usNewState ].ubEndHeight == ANIM_STAND ) + //if ( gAnimControl[ usNewState ].uiFlags & ANIM_MOVING && this->usAnimState == COWERING && gAnimControl[ usNewState ].ubEndHeight == ANIM_STAND ) + if ( this->usAnimState == COWERING ) { - this->usPendingAnimation = usNewState; - // Set new state to be animation to move to new stance - usNewState = END_COWER; + if ( gAnimControl[ usNewState ].ubEndHeight == ANIM_STAND ) + { + this->usPendingAnimation = usNewState; + this->ubDesiredHeight = ANIM_STAND; + usNewState = END_COWER; + } + else if ( gAnimControl[ usNewState ].ubEndHeight == ANIM_CROUCH ) + { + this->usPendingAnimation = usNewState; + this->ubDesiredHeight = ANIM_CROUCH; + usNewState = END_COWER_CROUCHED; + } + } + else if( this->usAnimState == COWERING_PRONE ) + { + if ( gAnimControl[ usNewState ].ubEndHeight == ANIM_PRONE ) + { + this->usPendingAnimation = usNewState; + this->ubDesiredHeight = ANIM_PRONE; + usNewState = END_COWER_PRONE; + } } // If we want to start swatting, put a pending animation @@ -3242,43 +3313,48 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart } // OK, make guy transition if a big merc... - if ( this->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) + //if ( ( this->uiAnimSubFlags & SUB_ANIM_BIGGUYTHREATENSTANCE ) && !( this->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) ) + if ( this->ubBodyType == BIGMALE ) { - if ( usNewState == KNEEL_DOWN && this->usAnimState != BIGMERC_CROUCH_TRANS_INTO ) + // SANDRO - we are changing crouching animation here to the old vanilla one, don't do that if alt animations are used + if ( !DecideAltAnimForBigMerc( this ) ) { - //UINT16 usItem; - - // Do we have a rifle? - //usItem = this->inv[ HANDPOS ].usItem; - - if ( this->inv[ HANDPOS ].exists() == true ) + if ( usNewState == KNEEL_DOWN && this->usAnimState != BIGMERC_CROUCH_TRANS_INTO ) { - if ( Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher ) + //UINT16 usItem; + + // Do we have a rifle? + //usItem = this->inv[ HANDPOS ].usItem; + + if ( this->inv[ HANDPOS ].exists() == true ) { - // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) - if ( (Item[ usItem ].twohanded ) ) + if ( Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher ) { - usNewState = BIGMERC_CROUCH_TRANS_INTO; + // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) + if ( (Item[ usItem ].twohanded ) ) + { + usNewState = BIGMERC_CROUCH_TRANS_INTO; + } } } } - } - if ( usNewState == KNEEL_UP && this->usAnimState != BIGMERC_CROUCH_TRANS_OUTOF ) - { - //UINT16 usItem; - - // Do we have a rifle? - //usItem = this->inv[ HANDPOS ].usItem; - - if ( this->inv[ HANDPOS ].exists() == true ) + if ( usNewState == KNEEL_UP && this->usAnimState != BIGMERC_CROUCH_TRANS_OUTOF ) { - if ( Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher ) + //UINT16 usItem; + + // Do we have a rifle? + //usItem = this->inv[ HANDPOS ].usItem; + + if ( this->inv[ HANDPOS ].exists() == true ) { - // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) - if ( (Item[ usItem ].twohanded ) ) + if ( Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher ) { - usNewState = BIGMERC_CROUCH_TRANS_OUTOF; + // if ( (Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) + if ( (Item[ usItem ].twohanded ) ) + { + usNewState = BIGMERC_CROUCH_TRANS_OUTOF; + } } } } @@ -3299,24 +3375,20 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart // SANDRO - wait wait wait!!! We need to determine if gonna sidestep with weapon raised if (( (gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIREREADY ) || (gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIRE ) ) && gGameExternalOptions.fAllowWalkingWithWeaponRaised ) - //if ( WeaponReady( this ) ) { if ( this->inv[ HANDPOS ].exists() == true && Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher) { - if ( !(Item[ usItem ].twohanded ) ) + if ( this->IsValidSecondHandShot() ) { - if ( this->IsValidSecondHandShot() ) - { - usNewState = SIDE_STEP_DUAL_RDY; - } - else - { - usNewState = SIDE_STEP_PISTOL_RDY; - } + usNewState = SIDE_STEP_DUAL_RDY; + } + else if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) + { + usNewState = SIDE_STEP_ALTERNATIVE_RDY; } else { - usNewState = SIDE_STEP_RIFLE_RDY; + usNewState = SIDE_STEP_WEAPON_RDY; } } } @@ -3403,20 +3475,17 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart { if ( this->inv[ HANDPOS ].exists() == true && Item[ usItem ].usItemClass == IC_GUN && !Item[usItem].rocketlauncher) { - if ( !(Item[ usItem ].twohanded ) ) + if ( this->IsValidSecondHandShot() ) { - if ( this->IsValidSecondHandShot() ) - { - usNewState = WALKING_DUAL_RDY; - } - else - { - usNewState = WALKING_PISTOL_RDY; - } + usNewState = WALKING_DUAL_RDY; } - else + else if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) { - usNewState = WALKING_RIFLE_RDY; + usNewState = WALKING_ALTERNATIVE_RDY; + } + else + { + usNewState = WALKING_WEAPON_RDY; } } } @@ -3609,7 +3678,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart { // ATE: Also check for the transition anims to not reset this // this should have used a flag but we're out of them.... - if ( usNewState != READY_RIFLE_STAND && usNewState != READY_RIFLE_PRONE && usNewState != READY_RIFLE_CROUCH && usNewState != ROBOT_SHOOT ) + if ( usNewState != READY_ALTERNATIVE_STAND && usNewState != READY_RIFLE_STAND && usNewState != READY_RIFLE_PRONE && usNewState != READY_RIFLE_CROUCH && usNewState != ROBOT_SHOOT ) { this->sLastTarget = NOWHERE; } @@ -3667,11 +3736,17 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart case READY_DUAL_STAND: case READY_DUAL_CROUCH: case READY_DUAL_PRONE: + case READY_ALTERNATIVE_STAND: // OK, get points to ready weapon.... if ( !this->flags.fDontChargeReadyAPs ) { sAPCost = GetAPsToReadyWeapon( this, usNewState ); + // SANDRO - get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + sBPCost = sAPCost * GetBPCostPer10APsForGunHolding( this ) / 10; + else + sBPCost = 0; DeductPoints( this, sAPCost, sBPCost, BEFORESHOT_INTERRUPT ); } else @@ -3681,9 +3756,9 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart break; case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: this->usPendingAnimation = NO_PENDING_ANIMATION; this->aiData.ubPendingActionAnimCount = 0; @@ -3935,12 +4010,11 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart break; case JUMP_OVER_BLOCKING_PERSON: - // Set path.... { - INT32 usNewGridNo; + INT32 usNewGridNo; - DeductPoints( this, GetAPsToJumpOver( this ), APBPConstants[BP_JUMP_OVER], SP_MOVEMENT_INTERRUPT ); // changed by SANDRO + DeductPoints( this, GetAPsToJumpOver( this ), APBPConstants[BP_JUMP_OVER], SP_MOVEMENT_INTERRUPT ); usNewGridNo = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); usNewGridNo = NewGridNo( usNewGridNo, DirectionInc( this->ubDirection ) ); @@ -3960,6 +4034,34 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart } break; + case LONG_JUMP: + // Set path.... + { + INT32 usNewGridNo; + + DeductPoints( this, GetAPsToJumpOver( this ), APBPConstants[BP_JUMP_OVER], SP_MOVEMENT_INTERRUPT ); + + usNewGridNo = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); + usNewGridNo = NewGridNo( usNewGridNo, DirectionInc( this->ubDirection ) ); + usNewGridNo = NewGridNo( usNewGridNo, DirectionInc( this->ubDirection ) ); + + this->sPlotSrcGrid = this->sGridNo; + this->flags.fPastXDest = FALSE; + this->flags.fPastYDest = FALSE; + this->pathing.usPathDataSize = 0; + this->pathing.usPathIndex = 0; + this->pathing.usPathingData[ this->pathing.usPathDataSize ] = this->ubDirection; + this->pathing.usPathDataSize++; + this->pathing.usPathingData[ this->pathing.usPathDataSize ] = this->ubDirection; + this->pathing.usPathDataSize++; + this->pathing.usPathingData[ this->pathing.usPathDataSize ] = this->ubDirection; + this->pathing.usPathDataSize++; + this->pathing.sFinalDestination = usNewGridNo; + // Set direction + this->EVENT_InternalSetSoldierDestination( (UINT8) this->pathing.usPathingData[ this->pathing.usPathIndex ], FALSE, LONG_JUMP ); + } + break; + case GENERIC_HIT_STAND: case GENERIC_HIT_CROUCH: @@ -4122,7 +4224,8 @@ BOOLEAN SOLDIERTYPE::EVENT_InitNewSoldierAnim( UINT16 usNewState, UINT16 usStart if ( ( gAnimControl[ this->usOldAniState ].uiFlags & ANIM_RAISE_WEAPON) && (gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIREREADY) ) //equivalent if ( (this->usAnimState == AIM_RIFLE_PRONE) || (this->usAnimState == AIM_RIFLE_CROUCH) || (this->usAnimState == AIM_RIFLE_STAND) ) { - if ( (this->usOldAniState == READY_RIFLE_STAND) || (this->usOldAniState == READY_RIFLE_CROUCH) || (this->usOldAniState == READY_RIFLE_PRONE) ) + if ( (this->usOldAniState == READY_RIFLE_STAND) || (this->usOldAniState == READY_RIFLE_CROUCH) || (this->usOldAniState == READY_RIFLE_PRONE) || + (this->usOldAniState == READY_DUAL_STAND) || (this->usOldAniState == READY_DUAL_CROUCH) || (this->usOldAniState == READY_DUAL_PRONE) ) { HandleSight(this,SIGHT_LOOK); } @@ -4594,9 +4697,9 @@ void SOLDIERTYPE::SetSoldierGridNo( INT32 sNewGridNo, BOOLEAN fForceRemove ) switch( this->usAnimState ) { case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: case RUNNING: // IN deep water, swim! // Make transition from low to deep @@ -4778,7 +4881,14 @@ void SOLDIERTYPE::EVENT_FireSoldierWeapon( INT32 sTargetGridNo ) // Change to fire animation // Ready weapon - this->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE ); + //if (this->bTeam == gbPlayerNum) + //{ + this->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE, IsValidAlternativeFireMode( this->aiData.bAimTime, sTargetGridNo ) ); + //} + //else + //{ + // this->SoldierReadyWeapon( sTargetXPos, sTargetYPos, FALSE, AIDecideHipOrShoulderStance( this, sTargetGridNo ) ); + //} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SANDRO - hack! - an interrupt pending before shot @@ -4960,12 +5070,12 @@ UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight ) usItem = pSoldier->inv[ HANDPOS ].usItem; // CHECK 2ND HAND! - if ( pSoldier->IsValidSecondHandShot( ) ) + if ( pSoldier->IsValidSecondHandBurst() ) + { + return( BURST_DUAL_STAND ); + } + else if ( pSoldier->IsValidSecondHandShot() && !pSoldier->bDoBurst ) { - // Increment the number of people busy doing stuff because of an attack - //gTacticalStatus.ubAttackBusyCount++; - //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack with 2 guns, attack count now %d", gTacticalStatus.ubAttackBusyCount) ); - return( SHOOT_DUAL_STAND ); } else @@ -4983,12 +5093,6 @@ UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight ) fDoLowShot = TRUE; } - // ATE: Made distence away long for psitols such that they never use this.... - //if ( !(Item[ usItem ].fFlags & ITEM_TWO_HANDED) ) - //{ - // fDoLowShot = FALSE; - //} - // Don't do any low shots if in water if ( pSoldier->MercInWater( ) ) { @@ -5000,62 +5104,69 @@ UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight ) { if ( fDoLowShot ) { - return( FIRE_BURST_LOW_STAND ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, pSoldier->sTargetGridNo ) ) + { + return( LOW_BURST_ALTERNATIVE_STAND ); + } + else + { + return( FIRE_BURST_LOW_STAND ); + } } else { - return( STANDING_BURST ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, pSoldier->sTargetGridNo ) ) + { + return( BURST_ALTERNATIVE_STAND ); + } + else + { + return( STANDING_BURST ); + } } } else { if ( fDoLowShot ) { - return( FIRE_LOW_STAND ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, pSoldier->sTargetGridNo ) ) + { + return( LOW_SHOT_ALTERNATIVE_STAND ); + } + else + { + return( FIRE_LOW_STAND ); + } } else { - return( SHOOT_RIFLE_STAND ); + if ( pSoldier->IsValidAlternativeFireMode( pSoldier->aiData.bAimTime, pSoldier->sTargetGridNo ) ) + { + return( SHOOT_ALTERNATIVE_STAND ); + } + else + { + return( SHOOT_RIFLE_STAND ); + } } } } break; - case ANIM_PRONE: - - if ( pSoldier->bDoBurst > 0 ) - { - // pSoldier->flags.fBurstCompleted = FALSE; - return( PRONE_BURST ); - } - else - { - if ( pSoldier->IsValidSecondHandShot( ) ) - { - return( SHOOT_DUAL_PRONE ); - } - else - { - return( SHOOT_RIFLE_PRONE ); - } - } - break; - case ANIM_CROUCH: - if ( pSoldier->IsValidSecondHandShot( ) ) + if ( pSoldier->IsValidSecondHandShot() && pSoldier->bDoBurst > 0 && pSoldier->IsValidSecondHandBurst() ) + { + return( BURST_DUAL_CROUCH ); + } + else if ( pSoldier->IsValidSecondHandShot() && !pSoldier->bDoBurst ) { - // Increment the number of people busy doing stuff because of an attack - //gTacticalStatus.ubAttackBusyCount++; - //DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("!!!!!!! Starting attack with 2 guns, attack count now %d", gTacticalStatus.ubAttackBusyCount) ); - return( SHOOT_DUAL_CROUCH ); } else { if ( pSoldier->bDoBurst > 0 ) { - // pSoldier->flags.fBurstCompleted = FALSE; return( CROUCHED_BURST ); } else @@ -5065,6 +5176,29 @@ UINT16 SelectFireAnimation( SOLDIERTYPE *pSoldier, UINT8 ubHeight ) } break; + case ANIM_PRONE: + + if ( pSoldier->IsValidSecondHandShot() && pSoldier->bDoBurst > 0 && pSoldier->IsValidSecondHandBurst() ) + { + return( BURST_DUAL_PRONE ); + } + else if ( pSoldier->IsValidSecondHandShot() && !pSoldier->bDoBurst ) + { + return( SHOOT_DUAL_PRONE ); + } + else + { + if ( pSoldier->bDoBurst > 0 ) + { + return( PRONE_BURST ); + } + else + { + return( SHOOT_RIFLE_PRONE ); + } + } + break; + default: AssertMsg( FALSE, String( "SelectFireAnimation: ERROR - Invalid height %d", ubHeight ) ); break; @@ -5155,20 +5289,20 @@ void SelectFallAnimation( SOLDIERTYPE *pSoldier ) BOOLEAN SOLDIERTYPE::SoldierReadyWeapon( void ) { - return( this->InternalSoldierReadyWeapon( (INT8)this->ubDirection, FALSE ) ); + return( this->InternalSoldierReadyWeapon( (INT8)this->ubDirection, FALSE, FALSE ) ); } -BOOLEAN SOLDIERTYPE::SoldierReadyWeapon( INT16 sTargetXPos, INT16 sTargetYPos, BOOLEAN fEndReady ) +BOOLEAN SOLDIERTYPE::SoldierReadyWeapon( INT16 sTargetXPos, INT16 sTargetYPos, BOOLEAN fEndReady, BOOLEAN fRaiseToHipOnly ) { INT16 sFacingDir; sFacingDir = GetDirectionFromXY( sTargetXPos , sTargetYPos, this ); - return( this->InternalSoldierReadyWeapon( (INT8)sFacingDir, fEndReady ) ); + return( this->InternalSoldierReadyWeapon( (INT8)sFacingDir, fEndReady, fRaiseToHipOnly ) ); } -BOOLEAN SOLDIERTYPE::InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndReady ) +BOOLEAN SOLDIERTYPE::InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndReady, BOOLEAN fRaiseToHipOnly ) { UINT16 usAnimState; BOOLEAN fReturnVal = FALSE; @@ -5184,7 +5318,7 @@ BOOLEAN SOLDIERTYPE::InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndR } DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("InternalSoldierReadyWeapon: PickingAnimation")); - usAnimState = PickSoldierReadyAnimation( this, fEndReady ); + usAnimState = PickSoldierReadyAnimation( this, fEndReady, fRaiseToHipOnly ); if ( usAnimState != INVALID_ANIMATION ) { @@ -5221,7 +5355,7 @@ BOOLEAN SOLDIERTYPE::InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndR return( fReturnVal ); } -UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ) +UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fAltWeaponHolding ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("PickSoldierReadyAnimation")); @@ -5274,7 +5408,18 @@ UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ) } else { - return( END_RIFLE_STAND ); + if ( gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) )//&& Item[ pSoldier->inv[HANDPOS].usItem ].twohanded) + { + return( UNREADY_ALTERNATIVE_STAND ); + } + //else if (gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING ) && !Item[ pSoldier->inv[HANDPOS].usItem ].twohanded) + //{ + // return( PISTOL_FASTSHOT_UNREADY ); + //} + else + { + return( END_RIFLE_STAND ); + } } break; @@ -5309,56 +5454,78 @@ UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ) } else { - - // IF our gun is already drawn, do not change animation, just direction - if ( !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE ) ) ) + // if our gun is in alternative holding (hip rifle/one-hand pistol) and we are going to shoulder + if ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING )) && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND && !fAltWeaponHolding && !Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].HeavyGun) { - + return( READY_RIFLE_STAND ); + } + // this is a specific situation when we have a gun in standard holding (shouldered rifle/two-hand pistol) and was told to go to alternative holding + else if ((gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE )) && !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING )) + && fAltWeaponHolding && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 && pSoldier->bScopeMode == -1 && gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_STAND + && ((!Item[ pSoldier->inv[HANDPOS].usItem ].twohanded && !pSoldier->IsValidSecondHandShot() && !pSoldier->MercInWater() ) || Item[ pSoldier->inv[HANDPOS].usItem ].twohanded ) ) + { + return( READY_ALTERNATIVE_STAND ); + } + // IF our gun is already drawn, do not change animation, just direction + else if ( !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE ) ) ) + { + switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) { - switch ( gAnimControl[ pSoldier->usAnimState ].ubEndHeight ) - { - case ANIM_STAND: + case ANIM_STAND: - // CHECK 2ND HAND! - if ( pSoldier->IsValidSecondHandShot( ) ) + // CHECK 2ND HAND! + if ( pSoldier->IsValidSecondHandShot( ) ) + { + return( READY_DUAL_STAND ); + } + else + { + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding ) { - return( READY_DUAL_STAND ); + if (fAltWeaponHolding || (Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].HeavyGun && Item[ pSoldier->inv[HANDPOS].usItem ].twohanded) ) + { + return( READY_ALTERNATIVE_STAND ); + } + else + { + return( READY_RIFLE_STAND ); + } } else { return( READY_RIFLE_STAND ); } - break; - - case ANIM_PRONE: - // Go into crouch, turn, then go into prone again - //pSoldier->ChangeSoldierStance( ANIM_CROUCH ); - //pSoldier->ubDesiredHeight = ANIM_PRONE; - //pSoldier->ChangeSoldierState( PRONE_UP ); - if ( pSoldier->IsValidSecondHandShot( ) ) - { - return( READY_DUAL_PRONE ); - } - else - { - return( READY_RIFLE_PRONE ); - } - break; - - case ANIM_CROUCH: - - // CHECK 2ND HAND! - if ( pSoldier->IsValidSecondHandShot( ) ) - { - return( READY_DUAL_CROUCH ); - } - else - { - return( READY_RIFLE_CROUCH ); - } - break; - } + break; + + case ANIM_PRONE: + // Go into crouch, turn, then go into prone again + //pSoldier->ChangeSoldierStance( ANIM_CROUCH ); + //pSoldier->ubDesiredHeight = ANIM_PRONE; + //pSoldier->ChangeSoldierState( PRONE_UP ); + if ( pSoldier->IsValidSecondHandShot( ) ) + { + return( READY_DUAL_PRONE ); + } + else + { + return( READY_RIFLE_PRONE ); + } + break; + + case ANIM_CROUCH: + + // CHECK 2ND HAND! + if ( pSoldier->IsValidSecondHandShot( ) ) + { + return( READY_DUAL_CROUCH ); + } + else + { + return( READY_RIFLE_CROUCH ); + } + break; + } } @@ -5824,10 +5991,32 @@ void SOLDIERTYPE::EVENT_SoldierGotHit( UINT16 usWeaponIndex, INT16 sDamage, INT1 } // Set goback to aim after hit flag! - // Only if we were aiming! - if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIREREADY ) + // SANDRO - added more cases, alternative weapon holding, go back to cowering, and go back to hth/blade stance + // If we were in hth or blade stance, and we were hit by HtH or blade attack, go back to the fighting stance (if we can still keep up) + if (( Item[ usWeaponIndex ].usItemClass & (IC_BLADE | IC_PUNCH) ) && Item[ this->inv[HANDPOS].usItem ].usItemClass & (IC_NONE | IC_BLADE | IC_PUNCH) && + (this->usAnimState == PUNCH_BREATH || this->usAnimState == KNIFE_BREATH || this->usAnimState == NINJA_BREATH) && (gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND) ) { - this->flags.fGoBackToAimAfterHit = TRUE; + if ( this->stats.bLife > 30 && this->bBreath > 25 ) + { + this->flags.bGoBackToAimAfterHit = GO_TO_HTH_BREATH_AFTER_HIT; + } + } + // If we were aiming + else if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIREREADY ) + { + if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) // alternative weapon holding stance + this->flags.bGoBackToAimAfterHit = GO_TO_ALTERNATIVE_AIM_AFTER_HIT; + else // standard + this->flags.bGoBackToAimAfterHit = GO_TO_AIM_AFTER_HIT; + } + // if we were cowering (this is different from the bellow, we don't use that status flag for this animation) + else if ( this->usAnimState == COWERING ) + { + this->flags.bGoBackToAimAfterHit = GO_TO_COWERING_AFTER_HIT; + } + else + { + this->flags.bGoBackToAimAfterHit = NO_SPEC_STANCE_AFTER_HIT; } // IF COWERING, PLAY SPECIFIC GENERIC HIT STAND... @@ -6590,7 +6779,7 @@ BOOLEAN SOLDIERTYPE::EVENT_InternalGetNewSoldierPath( INT32 sDestGridNo, UINT16 } else { - usAnimState = PickSoldierReadyAnimation( this, TRUE ); + usAnimState = PickSoldierReadyAnimation( this, TRUE, FALSE ); } // Add a pending animation first! @@ -6795,8 +6984,8 @@ void SOLDIERTYPE::EVENT_InternalSetSoldierDestination( UINT16 usNewDirection, BO // OK, ATE: If we are side_stepping, calculate a NEW desired direction.... - if ( this->bReverse && (usAnimState == SIDE_STEP || usAnimState == ROLL_PRONE_R || usAnimState == ROLL_PRONE_L - || usAnimState == SIDE_STEP_PISTOL_RDY || usAnimState == SIDE_STEP_RIFLE_RDY || usAnimState == SIDE_STEP_DUAL_RDY ) ) + if ( this->bReverse && (usAnimState == SIDE_STEP || usAnimState == ROLL_PRONE_R || usAnimState == ROLL_PRONE_L || usAnimState == SIDE_STEP_ALTERNATIVE_RDY + || usAnimState == SIDE_STEP_WEAPON_RDY || usAnimState == SIDE_STEP_DUAL_RDY ) ) { UINT8 ubPerpDirection; @@ -6903,9 +7092,12 @@ INT8 MultiTiledTurnDirection( SOLDIERTYPE * pSoldier, INT8 bStartDirection, INT8 void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT8 ubNewDirection, BOOLEAN fInitalMove, UINT16 usAnimState ) { + INT16 sAPCost = 0; + INT32 iBPCost = 0; + //if ( usAnimState == WALK_BACKWARDS ) if ( pSoldier->bReverse && (usAnimState != SIDE_STEP && usAnimState != ROLL_PRONE_R && usAnimState != ROLL_PRONE_L - && usAnimState != SIDE_STEP_PISTOL_RDY && usAnimState != SIDE_STEP_RIFLE_RDY && usAnimState != SIDE_STEP_DUAL_RDY ) ) + && usAnimState != SIDE_STEP_WEAPON_RDY && usAnimState != SIDE_STEP_DUAL_RDY && usAnimState != SIDE_STEP_ALTERNATIVE_RDY )) { // OK, check if we are going to go in the exact opposite than our facing.... ubNewDirection = gOppositeDirection[ ubNewDirection ]; @@ -6931,37 +7123,38 @@ void EVENT_InternalSetSoldierDesiredDirection( SOLDIERTYPE *pSoldier, UINT8 ubNe { if ( gAnimControl[ usAnimState ].uiFlags & ( ANIM_BREATH | ANIM_OK_CHARGE_AP_FOR_TURN | ANIM_FIREREADY ) && !fInitalMove && !pSoldier->flags.fDontChargeTurningAPs ) { - // SANDRO - hey, we have a function for this around, why not to use it, hm? + // SANDRO: hey, we have a function for this around, why not to use it, hm? // silversurfer: we better don't do that. GetAPsToLook( ... ) will charge APs for getting to crouched/prone position // which is already done by SOLDIERTYPE::EVENT_InitNewSoldierAnim( ... ), we would charge twice... + // SANDRO: I see. Thanks. // DeductPoints( pSoldier, GetAPsToLook( pSoldier ), 0 ); // Deduct points for initial turn! switch( gAnimControl[ usAnimState ].ubEndHeight ) { // Now change to appropriate animation case ANIM_STAND: - // martial artists can turn faster - if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) - DeductPoints( pSoldier, ( max( 1, (INT16)((APBPConstants[AP_LOOK_STANDING] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))), 0 ); - else - DeductPoints( pSoldier, APBPConstants[AP_LOOK_STANDING], 0 ); + sAPCost = APBPConstants[AP_LOOK_STANDING]; break; case ANIM_CROUCH: - if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) - DeductPoints( pSoldier, ( max( 1, (INT16)((APBPConstants[AP_LOOK_CROUCHED] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 ))), 0 ); - else - DeductPoints( pSoldier, APBPConstants[AP_LOOK_CROUCHED], 0 ); + sAPCost = APBPConstants[AP_LOOK_CROUCHED]; break; case ANIM_PRONE: - if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) - DeductPoints( pSoldier, (max( 1, (INT16)((APBPConstants[AP_LOOK_PRONE] * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5))), 0 ); - else - DeductPoints( pSoldier, APBPConstants[AP_LOOK_PRONE], 0 ); + sAPCost = APBPConstants[AP_LOOK_PRONE]; break; } + // martial artists can turn faster + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) && gGameOptions.fNewTraitSystem ) + sAPCost = max( 1, (INT16)((sAPCost * (100 - gSkillTraitValues.ubMAApsTurnAroundReduction * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT )) / 100) + 0.5 )); + // SANDRO: get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + iBPCost = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCost = 0; + + DeductPoints( pSoldier, sAPCost, iBPCost ); } pSoldier->flags.fDontChargeTurningAPs = FALSE; @@ -8122,10 +8315,17 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier case TANK_BURST: case CROUCHED_BURST: case PRONE_BURST: + case BURST_ALTERNATIVE_STAND: + case LOW_BURST_ALTERNATIVE_STAND: pSoldier->sAniDelay = Weapon[Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex].sAniDelay; AdjustAniSpeed( pSoldier ); return; - // Lesh: end + case BURST_DUAL_STAND: + case BURST_DUAL_CROUCH: + case BURST_DUAL_PRONE: + pSoldier->sAniDelay = (Weapon[Item[pSoldier->inv[HANDPOS].usItem].ubClassIndex].sAniDelay)/2; + AdjustAniSpeed( pSoldier ); + return; case PRONE: case STANDING: @@ -8153,9 +8353,9 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier return; case WALKING: - case WALKING_PISTOL_RDY: - case WALKING_RIFLE_RDY: + case WALKING_WEAPON_RDY: case WALKING_DUAL_RDY: + case WALKING_ALTERNATIVE_RDY: // Adjust based on body type bAdditional = (UINT8)( gubAnimWalkSpeeds[ pStatsSoldier->ubBodyType ].sSpeed ); @@ -8202,11 +8402,11 @@ void CalculateSoldierAniSpeed( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pStatsSoldier if ( pSoldier->aiData.bAimTime == 0 ) { // Quick shot - pSoldier->sAniDelay = 70; + pSoldier->sAniDelay = 100; } else { - pSoldier->sAniDelay = 150; + pSoldier->sAniDelay = 200; } AdjustAniSpeed( pSoldier ); return; @@ -11399,19 +11599,35 @@ void SOLDIERTYPE::EVENT_SoldierBeginBladeAttack( INT32 sGridNo, UINT8 ubDirectio // CHECK IF HE CAN SEE US, IF SO RANDOMIZE if ( pTSoldier->aiData.bOppList[ this->ubID ] == 0 && pTSoldier->bTeam != this->bTeam ) { - // WE ARE NOT SEEN - this->EVENT_InitNewSoldierAnim( STAB, 0 , FALSE ); - } - else - { - // WE ARE SEEN - if ( Random( 50 ) > 25 ) + // WE ARE NOT SEEN + // SANDRO - use focused stab animation on aimed blade attacks + if ( gGameExternalOptions.fEnhancedCloseCombatSystem && ( this->aiData.bAimTime > 0 ) ) { - this->EVENT_InitNewSoldierAnim( STAB, 0 , FALSE ); + this->EVENT_InitNewSoldierAnim( FOCUSED_STAB, 0 , FALSE ); } else { - this->EVENT_InitNewSoldierAnim( SLICE, 0 , FALSE ); + this->EVENT_InitNewSoldierAnim( STAB, 0 , FALSE ); + } + } + else + { + // WE ARE SEEN + // SANDRO - use focused stab animation on aimed blade attacks + if ( gGameExternalOptions.fEnhancedCloseCombatSystem && ( this->aiData.bAimTime > 0 ) ) + { + this->EVENT_InitNewSoldierAnim( FOCUSED_STAB, 0 , FALSE ); + } + else + { + if ( Random( 50 ) > 25 ) + { + this->EVENT_InitNewSoldierAnim( STAB, 0 , FALSE ); + } + else + { + this->EVENT_InitNewSoldierAnim( SLICE, 0 , FALSE ); + } } // IF WE ARE SEEN, MAKE SURE GUY TURNS! @@ -11644,7 +11860,88 @@ void SOLDIERTYPE::EVENT_SoldierBeginPunchAttack( INT32 sGridNo, UINT8 ubDirectio if ( !Item[usItem].crowbar ) { - this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE ); + BOOLEAN fCannotKick = ( ubDirection & 1 ); + // SANDRO - we will determine here what type of punch we are gonna use + if ( gGameExternalOptions.fEnhancedCloseCombatSystem && ( this->aiData.bAimTime > 0 ) ) + { + if ( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight == ANIM_STAND ) + { + // if we aim for legs, always use kick + if ( this->bAimShotLocation == AIM_SHOT_LEGS && !(ubDirection & 1) ) + { + this->EVENT_InitNewSoldierAnim( FOCUSED_HTH_KICK, 0 , FALSE ); + } + // if we aim for head, always use punch animation + else if ( this->bAimShotLocation == AIM_SHOT_HEAD || (ubDirection & 1) ) + { + this->EVENT_InitNewSoldierAnim( FOCUSED_PUNCH, 0 , FALSE ); + } + // otherwise make it random, but favor the punch a bit + else + { + if ( Random(20) > 8 ) + this->EVENT_InitNewSoldierAnim( FOCUSED_PUNCH, 0 , FALSE ); + else + this->EVENT_InitNewSoldierAnim( FOCUSED_HTH_KICK, 0 , FALSE ); + } + } + else // if crouching enemy + { + // random if aiming on head, favor kick though + if ( this->bAimShotLocation == AIM_SHOT_HEAD || (ubDirection & 1) ) + { + if ( Random(20) > 12 || (ubDirection & 1)) + this->EVENT_InitNewSoldierAnim( FOCUSED_PUNCH, 0 , FALSE ); + else + this->EVENT_InitNewSoldierAnim( FOCUSED_HTH_KICK, 0 , FALSE ); + } + // otherwise always use kick + else + { + this->EVENT_InitNewSoldierAnim( FOCUSED_HTH_KICK, 0 , FALSE ); + } + } + } + else + { + if ( gAnimControl[ pTSoldier->usAnimState ].ubEndHeight == ANIM_STAND ) + { + // if we aim for legs, always use kick + if ( this->bAimShotLocation == AIM_SHOT_LEGS && !(ubDirection & 1)) + { + this->EVENT_InitNewSoldierAnim( HTH_KICK, 0 , FALSE ); + } + // if we aim for head, always use punch animation + else if ( this->bAimShotLocation == AIM_SHOT_HEAD || (ubDirection & 1)) + { + this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE ); + } + // otherwise make it random, but favor the punch a bit + else + { + if ( Random(20) > 8 ) + this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE ); + else + this->EVENT_InitNewSoldierAnim( HTH_KICK, 0 , FALSE ); + } + } + else // if crouching enemy + { + // random if aiming on head, favor kick though + if ( this->bAimShotLocation == AIM_SHOT_HEAD || (ubDirection & 1)) + { + if ( Random(20) > 12 || (ubDirection & 1)) + this->EVENT_InitNewSoldierAnim( PUNCH, 0 , FALSE ); + else + this->EVENT_InitNewSoldierAnim( HTH_KICK, 0 , FALSE ); + } + // otherwise always use kick + else + { + this->EVENT_InitNewSoldierAnim( HTH_KICK, 0 , FALSE ); + } + } + } } else { @@ -12688,7 +12985,10 @@ void SOLDIERTYPE::ReLoadSoldierAnimationDueToHandItemChange( UINT16 usOldItem, U this->bWeaponMode = WM_AUTOFIRE; this->bDoAutofire = 1; } - this->bScopeMode = USE_BEST_SCOPE; + if ( Item[ usNewItem ].twohanded && Weapon[ usNewItem ].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + this->bScopeMode = USE_ALT_WEAPON_HOLD; + else + this->bScopeMode = USE_BEST_SCOPE; if ( gAnimControl[ this->usAnimState ].uiFlags & ANIM_FIREREADY ) { @@ -13355,7 +13655,8 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) INT8 adjacenttileheight = GetTallestStructureHeight( nextGridNoinSight, FALSE ); // if the tile actually has a bit of height, we can rest our gun on it - if ( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH && (adjacenttileheight == 1 || adjacenttileheight == 2 ) ) + if (( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH && (adjacenttileheight == 1 || adjacenttileheight == 2 ) ) || + ( adjacenttileheight == 2 && (gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND && (gAnimControl[ this->usAnimState ].uiFlags &(ANIM_ALT_WEAPON_HOLDING))))) { // now we really want to check the next tile nextGridNoinSight = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); @@ -13372,7 +13673,7 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) applybipod = TRUE; } } - else if ( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH && adjacenttileheight == 4) + else if ( adjacenttileheight == 4 && (gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_CROUCH || (gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND && (gAnimControl[ this->usAnimState ].uiFlags &(ANIM_ALT_WEAPON_HOLDING))))) { // tile is as high as a building, but there might be a window, we could look through that // note that we also check for STRUCTURE_OPEN - the window has to be open (smashed) @@ -13400,7 +13701,7 @@ BOOLEAN SOLDIERTYPE::IsWeaponMounted( void ) } } } - else if ( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND && adjacenttileheight == 3 ) + else if ( gAnimControl[ this->usAnimState ].ubEndHeight == ANIM_STAND && adjacenttileheight == 3 && !(gAnimControl[ this->usAnimState ].uiFlags &(ANIM_ALT_WEAPON_HOLDING)) ) { // now we really want to check the next tile nextGridNoinSight = NewGridNo( this->sGridNo, DirectionInc( this->ubDirection ) ); @@ -15216,9 +15517,10 @@ BOOLEAN SOLDIERTYPE::IsValidSecondHandShot( void ) { if ( Item[ this->inv[ SECONDHANDPOS ].usItem ].usItemClass == IC_GUN && !(Item[ this->inv[SECONDHANDPOS ].usItem ].twohanded ) && - !this->bDoBurst && + (!this->bDoBurst || this->IsValidSecondHandBurst() )&& !Item[this->inv[ HANDPOS ].usItem].grenadelauncher && Item[ this->inv[HANDPOS].usItem ].usItemClass == IC_GUN && + !(Item[ this->inv[HANDPOS ].usItem ].twohanded ) && this->inv[SECONDHANDPOS][0]->data.gun.bGunStatus >= USABLE && this->inv[SECONDHANDPOS][0]->data.gun.ubGunShotsLeft > 0 ) { @@ -15228,12 +15530,46 @@ BOOLEAN SOLDIERTYPE::IsValidSecondHandShot( void ) return( FALSE ); } +BOOLEAN SOLDIERTYPE::IsValidSecondHandBurst( void ) +{ + // SANDRO - a function to determine if we can autofire with both weapons + if ( Item[ this->inv[ SECONDHANDPOS ].usItem ].usItemClass == IC_GUN && + !(Item[ this->inv[SECONDHANDPOS ].usItem ].twohanded ) && + !Item[this->inv[ HANDPOS ].usItem].grenadelauncher && + this->bDoBurst && + Item[ this->inv[HANDPOS].usItem ].usItemClass == IC_GUN && + !(Item[ this->inv[HANDPOS ].usItem ].twohanded ) && + this->inv[SECONDHANDPOS][0]->data.gun.bGunStatus >= USABLE && + this->inv[SECONDHANDPOS][0]->data.gun.ubGunShotsLeft > 0 ) + { + if (this->bDoAutofire) + { + // if second gun cannot use atuofire mode + if (!IsGunAutofireCapable( &this->inv[SECONDHANDPOS] )) + { + return( FALSE ); + } + } + else + { + // if second gun cannot use burst mode or the burst size is different + if (!(IsGunBurstCapable( &this->inv[SECONDHANDPOS], FALSE, NULL )) || (GetShotsPerBurst(&this->inv[HANDPOS]) != GetShotsPerBurst(&this->inv[SECONDHANDPOS]))) + { + return( FALSE ); + } + } + return( TRUE ); + } + + return( FALSE ); +} + BOOLEAN SOLDIERTYPE::IsValidSecondHandShotForReloadingPurposes( void ) { // should be maintained as same as function above with line // about ammo taken out! if ( Item[ this->inv[ SECONDHANDPOS ].usItem ].usItemClass == IC_GUN && - !this->bDoBurst && + //!this->bDoBurst && !Item[this->inv[ HANDPOS ].usItem].grenadelauncher && Item[ this->inv[HANDPOS].usItem ].usItemClass == IC_GUN && this->inv[SECONDHANDPOS][0]->data.gun.bGunStatus >= USABLE //&& @@ -15247,8 +15583,124 @@ BOOLEAN SOLDIERTYPE::IsValidSecondHandShotForReloadingPurposes( void ) return( FALSE ); } +BOOLEAN SOLDIERTYPE::IsValidAlternativeFireMode( INT16 bAimTime, INT32 iTrgGridNo ) +{ + if ( this->IsValidShotFromHip( bAimTime, iTrgGridNo ) || this->IsValidPistolFastShot( bAimTime, iTrgGridNo ) ) + { + return( TRUE ); + } + return( FALSE ); +} +BOOLEAN SOLDIERTYPE::IsValidShotFromHip( INT16 bAimTime, INT32 iTrgGridNo ) +{ + // not allowed, or not gun in hand, or not standing + if ( !gGameExternalOptions.ubAllowAlternativeWeaponHolding || Item[ this->inv[ HANDPOS ].usItem ].usItemClass != IC_GUN || gAnimControl[ this->usAnimState ].ubEndHeight != ANIM_STAND ) + { + return( FALSE ); + } + // robots cannot do this + if ( AM_A_ROBOT( this ) ) + { + return( FALSE ); + } + // must be two handed for this + if ( !Item[ this->inv[ HANDPOS ].usItem ].twohanded ) + { + return( FALSE ); + } + // with hybrid aiming behaviour, our stance is important, we don't go from shoulder to hip + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 2 ) + { + // shouldered already? + if ( (gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE )) && !(gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING )) ) + { + return( FALSE ); + } + // aiming over hip (yellow) indicated levels (and not heavy gun - those are always fired from hip, if aiming from hip allowed) + if ( bAimTime > GetNumberAltFireAimLevels( this, iTrgGridNo ) && !Weapon[this->inv[ HANDPOS ].usItem].HeavyGun ) + { + return( FALSE ); + } + } + // "scope mode" behaviour lets us select firing from hip manually + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + { + // we don't care about the stance here, as the player should know what he's doing, we just care about his fire mode selected + if ( this->bScopeMode != USE_ALT_WEAPON_HOLD ) + { + return( FALSE ); + } + // we go through, only if scope mode is set on "alternative fire mode" + } + else if ( bAimTime > 0 ) + { + // no aiming allowed with this + return( FALSE ); + } + + // if we are here, assume we are going to fire from hip + return( TRUE ); + +} + +BOOLEAN SOLDIERTYPE::IsValidPistolFastShot( INT16 bAimTime, INT32 iTrgGridNo ) +{ + // not allowed, or not gun in hand, or not standing + if ( !gGameExternalOptions.ubAllowAlternativeWeaponHolding || Item[ this->inv[ HANDPOS ].usItem ].usItemClass != IC_GUN || gAnimControl[ this->usAnimState ].ubEndHeight != ANIM_STAND ) + { + return( FALSE ); + } + // robots cannot do this + if ( AM_A_ROBOT( this ) ) + { + return( FALSE ); + } + // don't do this in water (yet), and not if firing from 2 guns + if ( this->MercInWater() || this->IsValidSecondHandShot() ) + { + return( FALSE ); + } + // must be one handed for this + if ( Item[ this->inv[ HANDPOS ].usItem ].twohanded ) + { + return( FALSE ); + } + // with hybrid aiming behaviour, our stance is important, we don't go from two-handed to one-handed grip + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 2 ) + { + // raised already? + if ( (gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_FIREREADY | ANIM_FIRE )) && !(gAnimControl[ this->usAnimState ].uiFlags & ( ANIM_ALT_WEAPON_HOLDING )) ) + { + return( FALSE ); + } + // aiming over alternative (yellow) indicated levels + if ( bAimTime > GetNumberAltFireAimLevels( this, iTrgGridNo ) ) + { + return( FALSE ); + } + } + // "scope mode" behaviour lets us select alternative firing manually + else if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + { + // we don't care about the stance here, as the player should know what he's doing, we just care about his fire mode selected + if ( this->bScopeMode != USE_ALT_WEAPON_HOLD ) + { + return( FALSE ); + } + // we go through, only if scope mode is set on "alternative fire mode" + } + else if ( bAimTime > 0 ) + { + // no aiming allowed with this + return( FALSE ); + } + + // if we are here, assume we are going to fire from alternative stance + return( TRUE ); + +} BOOLEAN SOLDIERTYPE::CanRobotBeControlled( void ) { SOLDIERTYPE *pController; @@ -16554,4 +17006,101 @@ BOOLEAN ResolvePendingInterrupt( SOLDIERTYPE * pSoldier, UINT8 ubInterruptType ) } } return( FALSE ); -} \ No newline at end of file +} + +BOOLEAN AIDecideHipOrShoulderStance( SOLDIERTYPE * pSoldier, INT32 iGridNo ) +{ + // TO DO: this should be much more sophisticated + + UINT16 usInHand = pSoldier->usAttackingWeapon; + + // not 2-handed or not standing + if (gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_STAND || !Item[ pSoldier->inv[HANDPOS].usItem ].twohanded) + { + return FALSE; + } + // heavy gun only from hip if standing + if (Weapon[usInHand].HeavyGun) + { + return TRUE; + } + // we want to make an aimed shot + if (pSoldier->aiData.bAimTime > GetNumberAltFireAimLevels( pSoldier, iGridNo)) + { + return FALSE; + } + + INT8 bChanceHip = 0; + + if( pSoldier->bDoBurst > 0 ) + bChanceHip += 25; + if( Weapon[usInHand].ubWeaponType == GUN_LMG ) + bChanceHip += 30; + if( Weapon[usInHand].ubWeaponType == GUN_SHOTGUN ) + bChanceHip += 15; + + // chance to hit with no aiming, add it to the chance to fire from hip + if ( !TileIsOutOfBounds( iGridNo ) ) + { + bChanceHip += CalcChanceToHitGun( pSoldier, iGridNo, 0, AIM_SHOT_TORSO ); + } + + if ( PreChance(bChanceHip)) + { + return TRUE; + } + else + { + return FALSE; + } + +} + +BOOLEAN DecideAltAnimForBigMerc( SOLDIERTYPE * pSoldier ) +{ + if ( pSoldier->ubBodyType != BIGMALE ) + { + // WTF! + return FALSE; + } + + //always use the other anim for badass mercs + if ( pSoldier->uiAnimSubFlags & SUB_ANIM_BIGGUYSHOOT2 ) + { + return TRUE; + } + + // if it is player controlled merc + if (pSoldier->flags.uiStatusFlags & SOLDIER_PC) + { + // are we in combat? + if ( gTacticalStatus.uiFlags & INCOMBAT ) + { + // then only use it if morale is very high (we are definately winning) + if ( pSoldier->aiData.bMorale > 95 ) + { + return TRUE; + } + } + else + { + // if not we use this with slightly above avarage morale + if ( pSoldier->aiData.bMorale > 65 ) + { + return TRUE; + } + } + } + // enemy guy + else + { + //never use this for regular enemies, only elites with high morale and level can sometimes show this animation + if ( ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA ) && + ( pSoldier->aiData.bAIMorale >= MORALE_FEARLESS ) && ( pSoldier->stats.bExpLevel > 8 ) ) + { + return TRUE; + } + } + + return FALSE; +} diff --git a/Tactical/Soldier Control.h b/Tactical/Soldier Control.h index c1a4862b8..9b6573d57 100644 --- a/Tactical/Soldier Control.h +++ b/Tactical/Soldier Control.h @@ -284,6 +284,16 @@ enum NUM_DAMAGABLE_STATS, }; +// SANDRO - this is for determining what stance to go back after being hit +enum +{ + NO_SPEC_STANCE_AFTER_HIT, + GO_TO_AIM_AFTER_HIT, + GO_TO_ALTERNATIVE_AIM_AFTER_HIT, + GO_TO_HTH_BREATH_AFTER_HIT, + GO_TO_COWERING_AFTER_HIT, +}; + // vehicle/human path structure struct path { @@ -556,7 +566,7 @@ public: INT8 bTurningFromPronePosition; BOOLEAN fDontChargeReadyAPs; BOOLEAN fPrevInWater; - BOOLEAN fGoBackToAimAfterHit; + INT8 bGoBackToAimAfterHit; BOOLEAN fForceRenderColor; BOOLEAN fForceNoRenderPaletteCycle; BOOLEAN fStopPendingNextTile; @@ -877,11 +887,11 @@ public: INT8 bTargetCubeLevel; INT32 sLastTarget; // HEADROCK HAM 4: the muzzle offset of the shooter's previous bullet. (NCTH) - FLOAT dPrevMuzzleOffsetX; - FLOAT dPrevMuzzleOffsetY; + FLOAT dPrevMuzzleOffsetX[2]; + FLOAT dPrevMuzzleOffsetY[2]; // HEADROCK HAM 4: Two more values. These record the shooter's previous Counter Force applied on the gun. - FLOAT dPrevCounterForceX; - FLOAT dPrevCounterForceY; + FLOAT dPrevCounterForceX[2]; + FLOAT dPrevCounterForceY[2]; // CHRISL: Track initial offsets for autofire FLOAT dInitialMuzzleOffsetX; FLOAT dInitialMuzzleOffsetY; @@ -1392,16 +1402,20 @@ public: - BOOLEAN SoldierReadyWeapon( INT16 sTargetXPos, INT16 sTargetYPos, BOOLEAN fEndReady ); + BOOLEAN SoldierReadyWeapon( INT16 sTargetXPos, INT16 sTargetYPos, BOOLEAN fEndReady, BOOLEAN fRaiseToHipOnly ); BOOLEAN SoldierReadyWeapon( void ); - BOOLEAN InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndReady ); + BOOLEAN InternalSoldierReadyWeapon( UINT8 sFacingDir, BOOLEAN fEndReady, BOOLEAN fRaiseToHipOnly ); BOOLEAN CheckSoldierHitRoof( void ); BOOLEAN CheckForBreathCollapse( void ); BOOLEAN PlayerSoldierStartTalking( UINT8 ubTargetID, BOOLEAN fValidate ); BOOLEAN InternalIsValidStance( INT8 bDirection, INT8 bNewStance ); BOOLEAN IsValidSecondHandShot( void ); + BOOLEAN IsValidSecondHandBurst( void ); BOOLEAN IsValidSecondHandShotForReloadingPurposes( void ); + BOOLEAN IsValidAlternativeFireMode( INT16 bAimTime, INT32 iTrgGridNo ); + BOOLEAN IsValidShotFromHip( INT16 bAimTime, INT32 iTrgGridNo ); + BOOLEAN IsValidPistolFastShot( INT16 bAimTime, INT32 iTrgGridNo ); BOOLEAN SoldierCarriesTwoHandedWeapon( void ); void SoldierInventoryCoolDown( void ); // Flugente: Cool down/decay all items in inventory BOOLEAN IsWeaponMounted( void ); // determine if we receive a bonus for mounting our weapon on something @@ -1560,6 +1574,8 @@ UINT8 GetSquadleadersCountInVicinity( SOLDIERTYPE * pSoldier, BOOLEAN fWithHighe UINT16 NumberOfDamagedStats( SOLDIERTYPE * pSoldier ); UINT8 RegainDamagedStats( SOLDIERTYPE * pSoldier, UINT16 usAmountRegainedHundredths ); BOOLEAN ResolvePendingInterrupt( SOLDIERTYPE * pSoldier, UINT8 ubInterruptType ); +BOOLEAN AIDecideHipOrShoulderStance( SOLDIERTYPE * pSoldier, INT32 iGridNo ); +BOOLEAN DecideAltAnimForBigMerc( SOLDIERTYPE * pSoldier ); //typedef struct class OLDSOLDIERTYPE_101 diff --git a/Tactical/Spread Burst.cpp b/Tactical/Spread Burst.cpp index e854ae3e6..1bc4505ff 100644 --- a/Tactical/Spread Burst.cpp +++ b/Tactical/Spread Burst.cpp @@ -217,6 +217,9 @@ void AIPickBurstLocations( SOLDIERTYPE *pSoldier, INT8 bTargets, SOLDIERTYPE *pT else ubShotsPerBurst = __min(GetShotsPerBurst (&pSoldier->inv[ HANDPOS ]),MAX_BURST_SPREAD_TARGETS); + if ( pSoldier->IsValidSecondHandBurst() ) + ubShotsPerBurst = ubShotsPerBurst*2; + if ( ubShotsPerBurst <= 0 ) ubShotsPerBurst = 1; diff --git a/Tactical/TeamTurns.cpp b/Tactical/TeamTurns.cpp index 5aef83231..fa1451e93 100644 --- a/Tactical/TeamTurns.cpp +++ b/Tactical/TeamTurns.cpp @@ -894,7 +894,7 @@ void StartInterrupt( void ) pTempSoldier = Squad[ iSquad ][ iCounter ]; if ( pTempSoldier && pTempSoldier->bActive && pTempSoldier->bInSector && !pTempSoldier->aiData.bMoved ) { - INT16 ubMinAPcost = MinAPsToAttack(pSoldier,pInterruptedSoldier->sGridNo,ADDTURNCOST); + INT16 ubMinAPcost = MinAPsToAttack(pSoldier,pInterruptedSoldier->sGridNo,ADDTURNCOST, 0); // if we don't have enough APs left to shoot even a snap-shot at this guy if (ubMinAPcost < pSoldier->bActionPoints) { @@ -1127,7 +1127,7 @@ void EndInterrupt( BOOLEAN fMarkInterruptOccurred ) { if ( pTempSoldier->bActive && pTempSoldier->bInSector && !pTempSoldier->aiData.bMoved && (pTempSoldier->bActionPoints == pTempSoldier->aiData.bIntStartAPs)) { - ubMinAPsToAttack = MinAPsToAttack( pTempSoldier, pTempSoldier->sLastTarget, FALSE ); + ubMinAPsToAttack = MinAPsToAttack( pTempSoldier, pTempSoldier->sLastTarget, FALSE, 0 ); if ( (ubMinAPsToAttack <= pTempSoldier->bActionPoints) && (ubMinAPsToAttack > 0) ) { pTempSoldier->aiData.bPassedLastInterrupt = TRUE; diff --git a/Tactical/Turn Based Input.cpp b/Tactical/Turn Based Input.cpp index 9e9b9d1a1..7389dcba6 100644 --- a/Tactical/Turn Based Input.cpp +++ b/Tactical/Turn Based Input.cpp @@ -224,7 +224,7 @@ void ToggleTreeTops(); void ToggleZBuffer(); void TogglePlanningMode(); void SetBurstMode(); -void SetScopeMode(); +void SetScopeMode( INT32 usMapPos ); void ObliterateSector(); void RandomizeMercProfile(); void CreateNextCivType(); @@ -4137,10 +4137,11 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) if ( !MercPtrs[ gusSelectedSoldier ]->MercInWater( ) && !(MercPtrs[ gusSelectedSoldier ]->flags.uiStatusFlags & SOLDIER_ROBOT ) ) { //change selected merc to run - if ( MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != RUNNING - && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_PISTOL_RDY - && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_RIFLE_RDY - && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_DUAL_RDY ) + if ( MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING + && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != RUNNING + && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_WEAPON_RDY + && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_DUAL_RDY + && MercPtrs[ gusSelectedSoldier ]->usUIMovementMode != WALKING_ALTERNATIVE_RDY ) { UIHandleSoldierStanceChange( (UINT8)gusSelectedSoldier, ANIM_STAND ); MercPtrs[ gusSelectedSoldier ]->flags.fUIMovementFast = 1; @@ -4481,7 +4482,7 @@ void GetKeyboardInput( UINT32 *puiNewEvent ) } else { - SetScopeMode(); + SetScopeMode( usMapPos ); } break; @@ -5032,11 +5033,15 @@ void CycleSelectedMercsItem() // Get soldier... pSoldier = MercPtrs[ gusSelectedSoldier ]; + UINT16 usOldHandItem = pSoldier->inv[HANDPOS].usItem; + // Cycle item.... usOldItem = CycleItems(pSoldier->inv[ HANDPOS ].usItem); CreateItem( (UINT16)usOldItem, 100, &( pSoldier->inv[ HANDPOS ]) ); + pSoldier->ReLoadSoldierAnimationDueToHandItemChange( usOldHandItem, pSoldier->inv[HANDPOS].usItem ); + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); } @@ -5258,11 +5263,14 @@ void SetBurstMode() } } -void SetScopeMode() +void SetScopeMode( INT32 usMapPos ) { if ( gusSelectedSoldier != NOBODY ) { - ChangeScopeMode( MercPtrs[ gusSelectedSoldier ] ); + if ( GetMouseMapPos( &usMapPos )) + ChangeScopeMode( MercPtrs[ gusSelectedSoldier ], usMapPos ); + else + ChangeScopeMode( MercPtrs[ gusSelectedSoldier ], 0 ); // reevaluate sight ManLooksForOtherTeams( MercPtrs[ gusSelectedSoldier ] ); diff --git a/Tactical/UI Cursors.cpp b/Tactical/UI Cursors.cpp index 8b313166c..d987b0d1f 100644 --- a/Tactical/UI Cursors.cpp +++ b/Tactical/UI Cursors.cpp @@ -388,6 +388,11 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA if(pSoldier->bDoAutofire == 1) //try to maximize the # of bullets because 1 may not be optimal { INT16 sCurAPCosts, sAPCosts; + UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); + } sCurAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -396,13 +401,17 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire); pSoldier->bDoAutofire--; } gfUIAutofireBulletCount = TRUE; gsBulletCount = pSoldier->bDoAutofire; gsTotalBulletCount = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + gsTotalBulletCount = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), gsTotalBulletCount ); + } if(pSoldier->flags.autofireLastStep) //set the orange tint on the numbers if we at the last step gTintBulletCounts = TRUE; @@ -425,7 +434,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA } // If we don't have any points and we are at the first refine, do nothing but warn! - if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) ) + if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) && (pSoldier->aiData.bShownAimTime == 0)) { gfUIDisplayActionPointsInvalid = TRUE; @@ -441,7 +450,8 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA if (reverse == 0) { // WANNE: Current AP costs for targeting - sAPCosts = MinAPsToAttack( pSoldier, usMapPos, TRUE ) + ( bFutureAim ); + //sAPCosts = MinAPsToAttack( pSoldier, usMapPos, TRUE, bFutureAim ) + ( bFutureAim ); + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bFutureAim ); //gsCurrentActionPoints = sAPCosts; @@ -453,11 +463,13 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA } else { - sAPCosts = MinAPsToAttack( pSoldier, usMapPos, TRUE ) + maxAimLevels - (bFutureAim + 1); + //sAPCosts = MinAPsToAttack( pSoldier, usMapPos, TRUE, (maxAimLevels - (bFutureAim + 1)) ) + maxAimLevels - (bFutureAim + 1); + sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (maxAimLevels - (bFutureAim + 1)) ); gsCurrentActionPoints = sAPCosts; - sAPCostsMin = MinAPsToAttack( pSoldier, usMapPos, TRUE ); + //sAPCostsMin = MinAPsToAttack( pSoldier, usMapPos, TRUE, 0 ); + sAPCostsMin = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, 0 ); if (sAPCosts < sAPCostsMin) { fEnoughPoints = FALSE; @@ -545,13 +557,18 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA if(gbNumBurstLocations > pSoldier->bDoAutofire) { INT16 sAPCosts; + UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); + } do { pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, gsBurstLocations[0].sGridNo, TRUE, pSoldier->aiData.bShownAimTime); } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && gbNumBurstLocations >= pSoldier->bDoAutofire); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && usShotsLeft >= pSoldier->bDoAutofire && gbNumBurstLocations >= pSoldier->bDoAutofire); pSoldier->bDoAutofire--; gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, gsBurstLocations[0].sGridNo, TRUE, pSoldier->aiData.bShownAimTime ); @@ -614,7 +631,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); - CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos ); pSoldier->bTargetLevel = bTempTargetLevel; } @@ -720,7 +737,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); - CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos ); pSoldier->bTargetLevel = bTempTargetLevel; } @@ -822,7 +839,7 @@ UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEA FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos )); FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY)); - CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime ); + CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos ); } pSoldier->bTargetLevel = bTempTargetLevel; @@ -2351,6 +2368,11 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) else if(pSoldier->bDoAutofire) { INT16 sCurAPCosts; + UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); + } if(pSoldier->flags.autofireLastStep) { @@ -2360,11 +2382,11 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) } - if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + if(usShotsLeft > pSoldier->bDoAutofire ) { //Calculate how many bullets we need to fire to add at least one more AP sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && usShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP { pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -2379,7 +2401,7 @@ void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos ) pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire); pSoldier->bDoAutofire--; sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -3211,6 +3233,11 @@ void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta INT32 sGridNo; INT8 bTargetLevel; + UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); + } usInHand = pSoldier->inv[HANDPOS].usItem; @@ -3239,11 +3266,11 @@ void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta if(pSoldier->bDoAutofire==1 && sDelta<0) return; - if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + if(usShotsLeft > pSoldier->bDoAutofire ) { //Calculate how many bullets we need to fire to add at least one more AP sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && usShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP { pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -3258,7 +3285,7 @@ void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta pSoldier->bDoAutofire+=sDelta; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire); pSoldier->bDoAutofire--; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -3427,6 +3454,11 @@ void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sD INT32 sGridNo; INT8 bTargetLevel; + UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft; + if (pSoldier->IsValidSecondHandBurst()) + { + usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft ); + } usInHand = pSoldier->inv[HANDPOS].usItem; @@ -3457,11 +3489,11 @@ void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sD if(pSoldier->bDoAutofire==1 && sDelta<0) return; - if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire ) + if(usShotsLeft > pSoldier->bDoAutofire ) { //Calculate how many bullets we need to fire to add at least one more AP sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts <= sCurAPCosts && usShotsLeft > pSoldier->bDoAutofire) //Increment the bullet count until we run out of APs or we spend the whole AP { pSoldier->bDoAutofire++; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); @@ -3476,7 +3508,7 @@ void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sD pSoldier->bDoAutofire+=sDelta; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); } - while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire); + while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire); pSoldier->bDoAutofire--; sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime); diff --git a/Tactical/Weapons.cpp b/Tactical/Weapons.cpp index d337651a0..48ec603d6 100644 --- a/Tactical/Weapons.cpp +++ b/Tactical/Weapons.cpp @@ -421,7 +421,8 @@ weaponStartElementHandle(void *userData, const XML_Char *name, const XML_Char ** strcmp(name, "Handling") == 0 || // CHRISL HAM 4 strcmp(name, "usOverheatingJamThreshold") == 0 || // Flugente FTW 1 strcmp(name, "usOverheatingDamageThreshold") == 0 || // Flugente FTW 1 - strcmp(name, "usOverheatingSingleShotTemperature") == 0)) // Flugente FTW 1 + strcmp(name, "usOverheatingSingleShotTemperature") == 0 || // Flugente FTW 1 + strcmp(name, "HeavyGun") == 0)) // SANDRO - cannot be shouldered while standing { pData->curElement = WEAPON_ELEMENT_WEAPON_PROPERY; @@ -701,6 +702,11 @@ weaponEndElementHandle(void *userData, const XML_Char *name) pData->curElement = WEAPON_ELEMENT_WEAPON; pData->curWeapon.usOverheatingSingleShotTemperature = (FLOAT) atof(pData->szCharData); } + else if(strcmp(name, "HeavyGun") == 0) + { + pData->curElement = WEAPON_ELEMENT_WEAPON; + pData->curWeapon.HeavyGun = (BOOLEAN) atof(pData->szCharData); + } pData->maxReadDepth--; } @@ -877,6 +883,7 @@ BOOLEAN WriteWeaponStats() FilePrintf(hFile,"\t\t%4.2f\r\n", Weapon[cnt].usOverheatingJamThreshold); // Flugente FTW 1 FilePrintf(hFile,"\t\t%4.2f\r\n", Weapon[cnt].usOverheatingDamageThreshold); FilePrintf(hFile,"\t\t%4.2f\r\n", Weapon[cnt].usOverheatingSingleShotTemperature); + FilePrintf(hFile,"\t\t%d\r\n", Weapon[cnt].HeavyGun); FilePrintf(hFile,"\t\r\n"); @@ -1181,7 +1188,11 @@ BOOLEAN CheckForGunJam( SOLDIERTYPE * pSoldier ) invertedBaseJamChance = 0; else if (invertedBaseJamChance > 100) invertedBaseJamChance = 100; - int jamChance = 100 - (int)sqrt((double)invertedBaseJamChance * ((75.0-(int)(pSoldier->bDoBurst>1)*15) + (double)invertedBaseJamChance / 2.0)); + int jamChance = 100; + if ( pSoldier->ubAttackingHand == SECONDHANDPOS && pSoldier->IsValidSecondHandBurst() ) + jamChance -= (int)sqrt((double)invertedBaseJamChance * ((75.0-(int)((pSoldier->bDoBurst/2)>1)*15) + (double)invertedBaseJamChance / 2.0)); + else + jamChance -= (int)sqrt((double)invertedBaseJamChance * ((75.0-(int)(pSoldier->bDoBurst>1)*15) + (double)invertedBaseJamChance / 2.0)); if (jamChance < 0) jamChance = 0; else if (jamChance > maxJamChance - reliability) @@ -1290,10 +1301,10 @@ BOOLEAN OKFireWeapon( SOLDIERTYPE *pSoldier ) // 1) Are we attacking with our second hand? if ( pSoldier->ubAttackingHand == SECONDHANDPOS ) { - if ( Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].NoSemiAuto ) // Madd: no autofire w/second hand (yet) - { - return( FALSE ); - } + //if ( Weapon[pSoldier->inv[pSoldier->ubAttackingHand].usItem].NoSemiAuto ) // Madd: no autofire w/second hand (yet) + //{ + // return( FALSE ); + //} if ( !EnoughAmmo( pSoldier, FALSE, pSoldier->ubAttackingHand ) ) { @@ -1599,6 +1610,7 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) UINT32 uiMuzzleSway; INT16 sXMapPos, sYMapPos; INT16 sAPCost; + INT32 iBPCost; FLOAT dTargetX; FLOAT dTargetY; FLOAT dTargetZ; @@ -1618,6 +1630,11 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) // Calculate total APs required to complete the entire attack, including all relevant weapon AP costs // with possible turning and gun-raising costs as well. sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, FALSE, pSoldier->aiData.bAimTime ); + // SANDRO - get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight && !IsAutoResolveActive() ) // rather not in atuoresolve, since we can't choose stance there + iBPCost = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCost = 0; usItemNum = pSoldier->usAttackingWeapon; @@ -1655,6 +1672,8 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) if ( pSoldier->bDoBurst == 1 ) { INT8 bShotsToFire = pSoldier->bDoAutofire ? pSoldier->bDoAutofire : GetShotsPerBurst(pObjHand); + //if (pSoldier->IsValidSecondHandBurst()) + // bShotsToFire = bShotsToFire*2; if ( Weapon[ usUBItem ].sBurstSound != NO_WEAPON_SOUND ) { @@ -1693,7 +1712,7 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) */ } - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } } @@ -1705,12 +1724,12 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) // only deduct APs when the main gun fires if ( pSoldier->ubAttackingHand == HANDPOS ) { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } } else { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } //PLAY SOUND @@ -1745,7 +1764,13 @@ BOOLEAN UseGunNCTH( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) } } -//ddd{ . silencer + // SANDRO - pay BP cost for weapon recoil kick + if ( gGameExternalOptions.ubEnergyCostForWeaponRecoilKick && !IsAutoResolveActive() ) // rather not in atuoresolve, since we can't choose stance there + { + iBPCost = GetBPCostForRecoilkick( pSoldier ); + DeductPoints( pSoldier, 0, iBPCost ); + } + if ( (Item[ usUBItem ].usItemClass == IC_GUN) && gGameExternalOptions.bAllowWearSuppressor ) { if ( IsFlashSuppressor(pObjAttHand, pSoldier ) ) @@ -2166,6 +2191,7 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) UINT32 uiHitChance, uiDiceRoll; INT16 sXMapPos, sYMapPos; INT16 sAPCost; + INT32 iBPCost; FLOAT dTargetX; FLOAT dTargetY; FLOAT dTargetZ; @@ -2183,6 +2209,11 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("UseGun") ); // Deduct points! sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, FALSE, pSoldier->aiData.bAimTime ); + // SANDRO: get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight && !IsAutoResolveActive() ) // rather not in atuoresolve, since we can't choose stance there + iBPCost = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCost = 0; // Flugente: check for underbarrel weapons and use that object if necessary OBJECTTYPE* pObjUsed = pSoldier->GetUsedWeapon( &pSoldier->inv[pSoldier->ubAttackingHand] ); @@ -2190,12 +2221,15 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) usItemNum = pSoldier->usAttackingWeapon; + // DEDUCT APs if ( pSoldier->bDoBurst ) { // ONly deduct points once if ( pSoldier->bDoBurst == 1 ) { INT8 bShotsToFire = pSoldier->bDoAutofire ? pSoldier->bDoAutofire : GetShotsPerBurst(pObjUsed); + //if (pSoldier->IsValidSecondHandBurst()) + // bShotsToFire = bShotsToFire*2; if ( Weapon[ usUBItem ].sBurstSound != NO_WEAPON_SOUND ) { @@ -2233,7 +2267,7 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) */ } - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } } @@ -2245,12 +2279,12 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) // only deduct APs when the main gun fires if ( pSoldier->ubAttackingHand == HANDPOS ) { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } } else { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } //PLAY SOUND @@ -2285,6 +2319,12 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) } } + // SANDRO: pay BP cost for weapon recoil kick + if ( gGameExternalOptions.ubEnergyCostForWeaponRecoilKick && !IsAutoResolveActive() ) // rather not in atuoresolve, since we can't choose stance there + { + iBPCost = GetBPCostForRecoilkick( pSoldier ); + DeductPoints( pSoldier, 0, iBPCost ); + } // CALC CHANCE TO HIT if ( Item[ usUBItem ].usItemClass == IC_THROWING_KNIFE ) @@ -2678,7 +2718,7 @@ BOOLEAN UseGun( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo ) } else { - ubVolume = __max( 1, ( ubVolume * GetPercentNoiseVolume( pObjUsed ) ) / 100 ); + ubVolume = __max( 1, ( ubVolume * noisefactor ) / 100 ); } } @@ -3491,31 +3531,31 @@ BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo, BOOLEAN fStea } // SANDRO - Enhanced Close Combat System - Add dodge animation of target if missed ninja spin kick - if ( (iDiceRoll >= iHitChance) && pSoldier->usAnimState == NINJA_SPINKICK && gGameExternalOptions.fEnhancedCloseCombatSystem - && gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND && IS_MERC_BODY_TYPE( pTargetSoldier )) - { - pTargetSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE ); - // after dodging melee attack go to apropriate stance - if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass == IC_PUNCH)) - { - if ((((NUM_SKILL_TRAITS( pTargetSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || - (HAS_SKILL_TRAIT( pTargetSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && - pTargetSoldier->ubBodyType == REGMALE ) - { - //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; - pTargetSoldier->usPendingAnimation = NINJA_BREATH ; - } - else - { - pTargetSoldier->usPendingAnimation = PUNCH_BREATH ; - } - } - else if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) - { - //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; - pTargetSoldier->usPendingAnimation = KNIFE_BREATH ; - } - } + //if ( (iDiceRoll >= iHitChance) && pSoldier->usAnimState == NINJA_SPINKICK && gGameExternalOptions.fEnhancedCloseCombatSystem + // && gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND && IS_MERC_BODY_TYPE( pTargetSoldier )) + //{ + // pTargetSoldier->ChangeSoldierState( DODGE_ONE, 0 , FALSE ); + // // after dodging melee attack go to apropriate stance + // if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass & (IC_NONE | IC_PUNCH)) && pTargetSoldier->stats.bLife > 30 && pTargetSoldier->bBreath > 25 ) + // { + // if ((((NUM_SKILL_TRAITS( pTargetSoldier, MARTIAL_ARTS_NT ) >= ((gSkillTraitValues.fPermitExtraAnimationsOnlyToMA) ? 2 : 1 )) && gGameOptions.fNewTraitSystem ) || + // (HAS_SKILL_TRAIT( pTargetSoldier, MARTIALARTS_OT ) && !gGameOptions.fNewTraitSystem ) ) && + // pTargetSoldier->ubBodyType == REGMALE ) + // { + // //pTSoldier->usPendingAnimation = NINJA_GOTOBREATH; + // pTargetSoldier->usPendingAnimation = NINJA_BREATH ; + // } + // else + // { + // pTargetSoldier->usPendingAnimation = PUNCH_BREATH ; + // } + // } + // else if ( (gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_STAND) && (Item[pTargetSoldier->inv[HANDPOS].usItem].usItemClass == IC_BLADE)) + // { + // //pTSoldier->usPendingAnimation = KNIFE_GOTOBREATH; + // pTargetSoldier->usPendingAnimation = KNIFE_BREATH ; + // } + //} // WDS 07/19/2008 - Random number use fix #if (defined JA2UB || defined JA113NODEMO) //Ja25 no meanwhiles @@ -3701,6 +3741,7 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) { UINT32 uiHitChance, uiDiceRoll; INT16 sAPCost = 0; + INT32 iBPCost = 0; OBJECTTYPE Launchable; OBJECTTYPE * pObj; UINT16 usItemNum; @@ -3816,12 +3857,22 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) //sAPCost = MinAPsToAttack( pSoldier, sTargetGridNo, TRUE ); sAPCost = CalcTotalAPsToAttack( pSoldier, sTargetGridNo, FALSE, pSoldier->aiData.bShownAimTime ); + // SANDRO: get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + iBPCost = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCost = 0; } else { // Throw.... sAPCost = MinAPsToThrow( pSoldier, sTargetGridNo, FALSE ); + // SANDRO: get BP cost for weapon manipulating + if ( gGameExternalOptions.ubEnergyCostForWeaponWeight ) + iBPCost = sAPCost * GetBPCostPer10APsForGunHolding( pSoldier ) / 10; + else + iBPCost = 0; } if ( pSoldier->bDoBurst ) @@ -3829,12 +3880,12 @@ BOOLEAN UseLauncher( SOLDIERTYPE *pSoldier, INT32 sTargetGridNo ) // ONly deduct points once if ( pSoldier->bDoBurst == 1 ) { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } } else { - DeductPoints( pSoldier, sAPCost, 0, AFTERSHOT_INTERRUPT ); + DeductPoints( pSoldier, sAPCost, iBPCost, AFTERSHOT_INTERRUPT ); } ///////////////////////////////////////////////////////////////////////////////////// @@ -4721,7 +4772,8 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi ///////////////////////////////////////////////////////////////////////////////////////////////////// //CHRISL: We have a new way to do this using a global variable - gbForceWeaponReady = true; + if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) // ignore scopes when firing from hip or on fast shot with pistol + gbForceWeaponReady = true; sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; @@ -4789,7 +4841,7 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi INT8 bMarksmanship = EffectiveMarksmanship( pSoldier ); INT16 bDexterity = EffectiveDexterity( pSoldier, FALSE ); INT16 bWisdom = EffectiveWisdom( pSoldier ); - + if ( bMarksmanship == 0 || bDexterity == 0 ) { return( gGameExternalOptions.ubMinimumCTH ); @@ -4821,6 +4873,12 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi // We now begin adding up factors that may increase or decrease Base CTH. They are pooled together to form a percentage // value. + + // FIRING FROM ALTERNATIVE WEAPON HOLDING (faster shot, less accuracy) + if ( pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + { + iBaseModifier -= gGameExternalOptions.ubAltWeaponHoldingCtHPenaly; + } // MORALE INT8 iCurrentMorale = GetMoraleModifier(pSoldier); @@ -4957,7 +5015,7 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) { if (( pSoldier->bDoBurst || pSoldier->bDoAutofire ) && !ubAimTime ) - iTraitModifier += 5; + iTraitModifier += 10; } // Show-off - better performance if some babes around to impress else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) @@ -5011,6 +5069,48 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi if (sGridNo == pSoldier->sLastTarget ) iBaseModifier += (FLOAT)gGameCTHConstants.BASE_SAME_TARGET; + ///////////////////////////////////////////////////////////////////////////////////// + // SANDRO - Bonus CtH for Militia + if (pSoldier->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA && gGameExternalOptions.sGreenMilitiaCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sGreenMilitiaCtHBonusPercent; + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA && gGameExternalOptions.sRegularMilitiaCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sRegularMilitiaCtHBonusPercent; + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA && gGameExternalOptions.sVeteranMilitiaCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sVeteranMilitiaCtHBonusPercent; + // bonus for enemy + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ADMINISTRATOR && gGameExternalOptions.sEnemyAdminCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sEnemyAdminCtHBonusPercent; + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ARMY && gGameExternalOptions.sEnemyRegularCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sEnemyRegularCtHBonusPercent; + else if (pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE && gGameExternalOptions.sEnemyEliteCtHBonusPercent != 0) + iBaseModifier += gGameExternalOptions.sEnemyEliteCtHBonusPercent; + // SANDRO - option to make special NPCs stronger - chance to hit + if (gGameExternalOptions.usSpecialNPCStronger > 0) + { + switch( pSoldier->ubProfile ) + { + case CARMEN: + case QUEEN: + case JOE: + case ANNIE: + case CHRIS: + case KINGPIN: + case TIFFANY: + case T_REX: + case DRUGGIST: + case GENERAL: + case JACK: + case OLAF: + case RAY: + case OLGA: + case TYRONE: + case MIKE: + iBaseModifier += gGameExternalOptions.usSpecialNPCStronger; + break; + } + } + ///////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////// // Gun Difficulty Modifiers @@ -5022,13 +5122,21 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi if ( pSoldier->IsValidSecondHandShot( ) ) { // Penalty for shooting two pistols. Ambidextrous trait halves this, once per skill level. + // SANDRO - Ambidextrous trait has only one level FLOAT iTempPenalty = (gGameCTHConstants.BASE_TWO_GUNS * iGunBaseDifficulty) - iGunBaseDifficulty; - INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); - - for (INT32 x = 0; x < traitLoop; x++) + //INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); + if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT )) { - iTempPenalty /= 2; + iTempPenalty = iTempPenalty * (100 - gSkillTraitValues.ubAMPenaltyDoubleReduction) / 100; } + else if (!gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT )) + { + iTempPenalty = 0; + } + //for (INT32 x = 0; x < traitLoop; x++) + //{ + // iTempPenalty /= 2; + //} iGunBaseDifficulty += iTempPenalty; } @@ -5266,7 +5374,7 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi { // Are we using a scope? If so, what's the range factor? - FLOAT iScopeMagFactor = GetBestScopeMagnificationFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance ); + FLOAT iScopeMagFactor, rangeModifier; //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 @@ -5280,11 +5388,29 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi // 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, &(pSoldier->inv[pSoldier->ubAttackingHand]), (FLOAT)iRange); + + if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) // ignore scopes when firing from hip/fast shot from pistol + { + iScopeMagFactor = GetBestScopeMagnificationFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance ); + rangeModifier = GetScopeRangeMultiplier(pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), (FLOAT)iRange); + } + else + { + iScopeMagFactor = 1.0f; + rangeModifier = gGameCTHConstants.SCOPE_RANGE_MULTIPLIER; + } + UINT32 uiBestScopeRange = (UINT32)(iScopeMagFactor * gGameCTHConstants.NORMAL_SHOOTING_DISTANCE * rangeModifier); FLOAT iAimModifier = 0; + // "AIMING" FROM ALTERNATIVE WEAPON HOLDING (faster shots, no scopes, less accuracy) + if ( pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo )) + { + //due to the way aiming levels are handled in NCTH, this penalty is increased here by 1/3 (it is harmonized by reduced aiming clicks) + iAimModifier -= gGameExternalOptions.ubAltWeaponHoldingAimingPenaly * 4 / 3; + } + // WEAPON CONDITION if ( (*pInHand)[0]->data.objectStatus < 50 ) { @@ -5342,13 +5468,21 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi if ( pSoldier->IsValidSecondHandShot( ) ) { // Penalty for shooting two pistols. Ambidextrous trait halves this, once per skill level. + // SANDRO - Ambidextrous trait has only one level FLOAT iTempPenalty = (gGameCTHConstants.AIM_TWO_GUNS * iGunAimDifficulty) - iGunAimDifficulty; - INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); - - for (INT32 x = 0; x < traitLoop; x++) + //INT8 traitLoop = (gGameOptions.fNewTraitSystem?NUM_SKILL_TRAITS( pSoldier, AMBIDEXTROUS_NT ):NUM_SKILL_TRAITS( pSoldier, AMBIDEXT_OT )); + if (gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT )) { - iTempPenalty /= 2; + iTempPenalty = iTempPenalty * (100 - gSkillTraitValues.ubAMPenaltyDoubleReduction) / 100; } + else if (!gGameOptions.fNewTraitSystem && HAS_SKILL_TRAIT( pSoldier, AMBIDEXTROUS_NT )) + { + iTempPenalty = 0; + } + //for (INT32 x = 0; x < traitLoop; x++) + //{ + // iTempPenalty /= 2; + //} iGunAimDifficulty += iTempPenalty; } @@ -5567,7 +5701,7 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi //uiCap += gSkillTraitValues.ubTHBladesCtHBonusPerClick*2; } } - else + else if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) { if (uiCap < gGameExternalOptions.ubMaximumCTH && iScopeMagFactor > 1.0 && iRange >= (INT32)uiBestScopeRange ) { @@ -5615,22 +5749,24 @@ UINT32 CalcNewChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi iMaxAimBonus = __max(0, iMaxAimBonus); // can't get less than 0 points for aiming... // factor in scopes under their range - if (iScopeMagFactor > 1.0 && iRange < (INT32)uiBestScopeRange) + if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) { - // Calculate how much penalty this scope should give at this range - FLOAT dScopePenaltyRatio = ((FLOAT)uiBestScopeRange / (FLOAT)iRange); - INT32 iScopePenalty = (INT32)(dScopePenaltyRatio * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE * (iScopeMagFactor /2)); - iMaxAimBonus += iScopePenalty; - } - else if (iScopeMagFactor == 1.0f && GetHighestScopeMagnificationFactor( &(pSoldier->inv[pSoldier->ubAttackingHand]) ) > 1.0f ) - { - // Not using a scope, but it's still there. Give half the penalty based on the size of the scope. - INT32 iScopePenalty = (INT32)(((GetHighestScopeMagnificationFactor( &(pSoldier->inv[pSoldier->ubAttackingHand]) )/2) * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE)/2); - iMaxAimBonus += iScopePenalty; - } - - iMaxAimBonus = __max(0, iMaxAimBonus); // can't get less than 0 points for aiming... + if (iScopeMagFactor > 1.0 && iRange < (INT32)uiBestScopeRange) + { + // Calculate how much penalty this scope should give at this range + FLOAT dScopePenaltyRatio = ((FLOAT)uiBestScopeRange / (FLOAT)iRange); + INT32 iScopePenalty = (INT32)(dScopePenaltyRatio * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE * (iScopeMagFactor /2)); + iMaxAimBonus += iScopePenalty; + } + else if (iScopeMagFactor == 1.0f && GetHighestScopeMagnificationFactor( &(pSoldier->inv[pSoldier->ubAttackingHand]) ) > 1.0f ) + { + // Not using a scope, but it's still there. Give half the penalty based on the size of the scope. + INT32 iScopePenalty = (INT32)(((GetHighestScopeMagnificationFactor( &(pSoldier->inv[pSoldier->ubAttackingHand]) )/2) * gGameCTHConstants.AIM_TOO_CLOSE_SCOPE)/2); + iMaxAimBonus += iScopePenalty; + } + iMaxAimBonus = __max(0, iMaxAimBonus); // can't get less than 0 points for aiming... + } // Now let's find out how many CTH points we get per aiming level. UINT8 ubAllowedAimingLevels = AllowedAimingLevels( pSoldier, sGridNo ); if(ubAimTime == ubAllowedAimingLevels) @@ -6087,7 +6223,10 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, ///////////////////////////////////////////////////////////////////////////////////// // Assign range variables -- all range values are in units (10 units = 1 tile) iRange = GetRangeInCellCoordsFromGridNoDiff( pSoldier->sGridNo, sGridNo ); // calculate actual range + + if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) // ignore scopes when firing from hip gbForceWeaponReady = true; + sDistVis = pSoldier->GetMaxDistanceVisible(sGridNo, pSoldier->bTargetLevel, CALC_FROM_ALL_DIRS ) * CELL_X_SIZE; iScopeVisionRangeBonus = GetTotalVisionRangeBonus(pSoldier, bLightLevel); // not an actual range value, simply a modifier for range calculations if (ubTargetID != NOBODY && pSoldier->aiData.bOppList[ubTargetID] == SEEN_CURRENTLY || gbPublicOpplist[pSoldier->bTeam][ubTargetID] == SEEN_CURRENTLY) @@ -6129,7 +6268,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, ///////////////////////////////////////////////////////////////////////////////////// // Modify Sight and Physical Range iSightRange = (INT32)(iSightRange / scopeRangeMod); - if(iSightRange > 0){ + if(iSightRange > 0 && !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ){ //CHRISL: The LOS system, which determines whether to display an enemy unit, does not factor in the AimBonus tag during it's calculations. So having // the CTH system use that tag to adjust iSightRange for AimBonus applied from armor might not be the best option. Especially as it can sometimes // result in 0% CTH when everything looks like you could actually hit the target. Let's try applying this penalty to CTH at the same point we would @@ -6186,6 +6325,10 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, // if shooting same target as the last shot if (sGridNo == pSoldier->sLastTarget ) // give a bonus to hit iChance += AIM_BONUS_SAME_TARGET; + // if shooting from alternative weapon holding, apply the preset penalty + if ( pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + iChance -= gGameExternalOptions.ubAltWeaponHoldingCtHPenaly; + ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// @@ -6218,7 +6361,8 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, } iChance += iPenalty; //CHRISL: Applying the Gear AimBonus (penalty) here, and directly to iChance as a flat penalty, instead of altering iSightRange above. - iChance += GetGearAimBonus ( pSoldier, iSightRange, ubAimTime ); + if ( !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + iChance += GetGearAimBonus ( pSoldier, iSightRange, ubAimTime ); //CHRISL: We should probably include these target size penalties even if we can't see the target so that shooting a "hidden" head is harder then a "hidden" body // if aiming at the head, reduce chance to hit @@ -6370,7 +6514,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, } // Flugente: check for scope mode - if ( Item[(&(pSoldier->inv[pSoldier->ubAttackingHand]))->usItem].usItemClass == IC_GUN ) + if ( Item[(&(pSoldier->inv[pSoldier->ubAttackingHand]))->usItem].usItemClass == IC_GUN && !pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) { std::map ObjList; GetScopeLists((&(pSoldier->inv[pSoldier->ubAttackingHand])), ObjList); @@ -6500,7 +6644,7 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) { if (( pSoldier->bDoBurst || pSoldier->bDoAutofire ) && !ubAimTime ) - iChance += 5; + iChance += 10; } // Show-off - better performance if some babes around to impress else if ( gMercProfiles[ pSoldier->ubProfile ].bCharacterTrait == CHAR_TRAIT_SHOWOFF ) @@ -6683,6 +6827,12 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, iPenalty += Weapon[usInHand].ubBurstPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; } + // SAMDRO - shooting dual bursts is somehow harder to control + if ( pSoldier->IsValidSecondHandBurst() ) + { + iPenalty = iPenalty*6/5; // +10% + } + // halve the penalty for people with the autofire trait if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO { @@ -6725,6 +6875,12 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, iPenalty += Weapon[usInHand].AutoPenalty * (pSoldier->bDoBurst - 1) * gGameExternalOptions.uAimedBurstPenalty; } + // SAMDRO - shooting dual bursts is somehow harder to control + if ( pSoldier->IsValidSecondHandBurst() ) + { + iPenalty = iPenalty*6/5; // +10% + } + // halve the penalty for people with the autofire trait if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO { @@ -6805,6 +6961,11 @@ UINT32 CalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, maxBonus = 20+((FLOAT)iMarksmanship/20*pSoldier->stats.bExpLevel)+(accuracyheatmultiplicator * Weapon[Item[pInHand->usItem].ubClassIndex].bAccuracy*2)+(NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT )*10); } iAimBonus = (float)GetAimBonus( pSoldier, pInHand, 100, 1 ); + + // penalty when aiming from alternative weapon holding + if ( pSoldier->IsValidAlternativeFireMode( ubAimTime, sGridNo ) ) + iAimBonus = iAimBonus * (100 - gGameExternalOptions.ubAltWeaponHoldingAimingPenaly) / 100; + for(int i = 0; i < ubAimTime; i++) { aimTimeBonus = __min((maxBonus*bonusProgression[i]/1000),maxClickBonus); maxBonus -= aimTimeBonus; @@ -8358,7 +8519,7 @@ UINT32 AICalcChanceToHitGun(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTim // we need to take other factors into consideration. FLOAT d2DDistance = (FLOAT) PythSpacesAway( pSoldier->sGridNo, sGridNo ) * 10.0f; - FLOAT dMagFactor = CalcMagFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance, (UINT8)ubAimTime ); + FLOAT dMagFactor = CalcMagFactor( pSoldier, &(pSoldier->inv[pSoldier->ubAttackingHand]), d2DDistance, sGridNo, (UINT8)ubAimTime ); FLOAT dDistanceFactor = (d2DDistance / gGameCTHConstants.NORMAL_SHOOTING_DISTANCE); uiChance = (UINT32)((uiChance * dMagFactor) / dDistanceFactor); @@ -9292,85 +9453,117 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO iImpact = iImpact * (100 + iFluke + iBonus) / 100; + iBonus = 0; + if (!fBladeAttack) { if ( gGameOptions.fNewTraitSystem ) { if (!pSoldier->usAttackingWeapon || Item[pSoldier->inv[HANDPOS].usItem].brassknuckles) { - // add bonuses for martial arts - if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) { - iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); - - // The Spinning kicks or aimed punch bonus - SANDRO - if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6))) + // add bonus for martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) { - iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait + iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); + } + // add bonus for focused punch + if (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK ) + { + iBonus += 50; + + // ...and martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + //iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait + iBonus += ( gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); + } + } + } + else + { + // add bonuses for martial arts + if ( HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT ) ) + { + iBonus += ( gSkillTraitValues.ubMABonusDamageHandToHand * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); + + // The Spinning kicks or aimed punch bonus - SANDRO + if (pSoldier->usAnimState == NINJA_SPINKICK || (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6))) + { + //iImpact = (INT32)((iImpact * (100 + gSkillTraitValues.usMAAimedPunchDamageBonus * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ) / 100) + 0.5); // +75% damage per trait + iBonus += ( (gSkillTraitValues.ubMABonusDamageHandToHand + 25 )* NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT ) ); + } } } } else { - // +30% damage of blunt weapons for melee character + // bonus damage of blunt weapons for melee character if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT )) { - iImpact = (INT32)(iImpact * (100 + gSkillTraitValues.ubMEDamageBonusBlunt)/100); + iBonus += gSkillTraitValues.ubMEDamageBonusBlunt; - if (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6)) + // bonus for aimed attack + if ( pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6) ) { - iImpact = (INT32)(iImpact * (100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus) / 100); // 50% incresed damage if focused melee attack + iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // incresed damage if focused melee attack } } } } else // original code { + if ( gGameExternalOptions.fEnhancedCloseCombatSystem && (pSoldier->usAnimState == NINJA_SPINKICK || pSoldier->usAnimState == FOCUSED_PUNCH || pSoldier->usAnimState == FOCUSED_HTH_KICK )) + { + iBonus += 50; + } // add bonuses for hand-to-hand and martial arts if ( HAS_SKILL_TRAIT( pSoldier, MARTIALARTS_OT ) ) { - iImpact = iImpact * ( 100 + gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ) ) / 100; + iBonus += gbSkillTraitBonus[MARTIALARTS_OT] * NUM_SKILL_TRAITS( pSoldier, MARTIALARTS_OT ); if (pSoldier->usAnimState == NINJA_SPINKICK) { - iImpact *= 2; + iBonus += 100; } } if ( HAS_SKILL_TRAIT( pSoldier, HANDTOHAND_OT ) ) { // SPECIAL - give TRIPLE bonus for damage for hand-to-hand trait // because the HTH bonus is half that of martial arts, and gets only 1x for to-hit bonus - iImpact = iImpact * ( 100 + 3 * gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ) ) / 100; + iBonus += 3 * gbSkillTraitBonus[HANDTOHAND_OT] * NUM_SKILL_TRAITS( pSoldier, HANDTOHAND_OT ); } } // Enhanced Close Combat System - aiming at body parts makes difference if (gGameExternalOptions.fEnhancedCloseCombatSystem) { - if (pSoldier->bAimShotLocation == AIM_SHOT_HEAD) + if ( pSoldier->bAimShotLocation == AIM_SHOT_HEAD ) { - iImpact = (INT32)((iImpact * 125 / 100) + 0.5); // Punch or kick to head deal more damage (as bonus for -20% accuracy ) + iBonus += 25; // Punch or kick to head deal more damage (vs -20% accuracy) } else if ( pSoldier->bAimShotLocation == AIM_SHOT_LEGS ) { // Punch or kick to legs deal less damage but takes some AP per damage out of target adjusted by AP_MAXIMUM - // NO, better to make hit to legs have a much better chance to hit, while only 50% damage - iImpact = (INT32)((iImpact * 60 / 100) + 0.5); + // NO, better to make hit to legs have a much better chance to hit, while only 50% damage is dealt + iBonus -= 50; //DeductPoints( pTarget, (APBPConstants[AP_MAXIMUM] / 10), 0 ); } else if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE) { - iImpact = (INT32)((iImpact * 130 / 100) + 0.5); // 30% incresed damage to lying characters + iBonus += 30; // 30% incresed damage to lying characters } // Surprising attack deals more damage if (pTarget->aiData.bOppList[ pSoldier->ubID ] == NOT_HEARD_OR_SEEN && !CREATURE_OR_BLOODCAT( pTarget ) ) { - iImpact = (INT32)((iImpact * 140 / 100) + 0.5); // 30% incresed damage on suprising attacks + iBonus += 50; // 50% incresed damage on suprising attacks } } // Flugente: power armour reduces damage taken - INT8 iSlot = VESTPOS; + // SANDRO - huh?! + /*INT8 iSlot = VESTPOS; switch( pSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: @@ -9382,18 +9575,18 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO default: iSlot = VESTPOS; break; - } + }*/ } // DAMAGE BONUS TO KNIFE ATTACK WITH MELEE SKILL else { if ( HAS_SKILL_TRAIT( pSoldier, MELEE_NT ) && ( gGameOptions.fNewTraitSystem )) { - iImpact = (INT32)(iImpact * ( 100 + gSkillTraitValues.ubMEDamageBonusBlades ) / 100); // +30% damage + iBonus += gSkillTraitValues.ubMEDamageBonusBlades; // +30% damage - if (pSoldier->aiData.bAimTime >= (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6)) + if (pSoldier->usAnimState == FOCUSED_STAB) { - iImpact = (INT32)(iImpact * ( 100 + gSkillTraitValues.usMEAimedMeleeAttackDamageBonus ) / 100); // 50% incresed damage if focused melee attack + iBonus += gSkillTraitValues.usMEAimedMeleeAttackDamageBonus; // 50% incresed damage if focused melee attack } } // Enhanced Close Combat System @@ -9401,12 +9594,13 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO { if (gAnimControl[ pTarget->usAnimState ].ubEndHeight == ANIM_PRONE) { - iImpact = (INT32)(iImpact * 125 / 100); // 40% incresed damage to lying characters + iBonus += 30; // incresed damage to lying characters } } // Flugente: power armour reduces damage taken - INT8 iSlot = VESTPOS; + // SANDRO - huh?! + /*INT8 iSlot = VESTPOS; switch( pSoldier->bAimShotLocation ) { case AIM_SHOT_HEAD: @@ -9418,15 +9612,18 @@ INT32 HTHImpact( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pTarget, INT32 iHitBy, BO default: iSlot = VESTPOS; break; - } + }*/ } // bonus damage for aggressive characters if ( gGameOptions.fNewTraitSystem && gMercProfiles[pSoldier->ubProfile].bCharacterTrait == CHAR_TRAIT_AGGRESSIVE ) { - iImpact = (INT32)((iImpact * 11 / 10) + 0.5); // +10% + iBonus += 10; // +10% } + // apply all bonuses + iImpact = (iImpact * (100 + iBonus) + 50) / 100; // round it properly + // Flugente: moved the damage calculation into a separate function BOOLEAN autoresolve = IsAutoResolveActive(); iImpact = max( 1, (INT32)(iImpact * (100 - pTarget->GetDamageResistance(autoresolve, FALSE)) / 100 ) ); @@ -9596,10 +9793,20 @@ UINT32 CalcChanceHTH( SOLDIERTYPE * pAttacker,SOLDIERTYPE *pDefender, INT16 ubAi // use only HALF of the normal aiming bonus for knife aiming. // since there's no range penalty, the bonus is otherwise too generous // SANDRO - Enhanced Close Combat System - Because you can only aim once, I've rather put here a flat number + // SANDRO again - changed this to behave differenty... on focused punches we go for DAMAGE, but the hit may be more predictable, so don't add any CtH + // if we want more CtH, just use the APs to try to punch again, while the focused punch is good either on weakened or unaware enemies + // on focused stabs however, we go for the opposite, we want to hit at all cost, since the knife deals good damage always if (gGameExternalOptions.fEnhancedCloseCombatSystem) - iAttRating += 20; + { + if (ubMode == HTH_MODE_STAB) + iAttRating += 30; + //else + //iAttRating += 20; + } else + { iAttRating += ((AIM_BONUS_PER_AP * ubAimTime) / 2); //bonus for aiming + } } if (! (pAttacker->flags.uiStatusFlags & SOLDIER_PC) ) // if attacker is a computer AI controlled enemy @@ -10230,7 +10437,10 @@ void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInv pSoldier->bDoBurst = TRUE; pSoldier->bDoAutofire = 1; } - pSoldier->bScopeMode = USE_BEST_SCOPE; + if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].twohanded && Weapon[ pSoldier->inv[ HANDPOS ].usItem ].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; } // if he is loaded tactically @@ -10268,7 +10478,10 @@ void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInv pSoldier->bDoAutofire = 1; pSoldier->bDoBurst = TRUE; } - pSoldier->bScopeMode = USE_BEST_SCOPE; + if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].twohanded && Weapon[ pSoldier->inv[ HANDPOS ].usItem ].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; } } @@ -10515,6 +10728,11 @@ UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTi - GetBurstToHitBonus(&pSoldier->inv[HANDPOS], gAnimControl[ pSoldier->usAnimState ].ubEndHeight == ANIM_PRONE) ) * (pSoldier->bDoBurst - 1); + // SAMDRO - shooting dual bursts is somehow harder to control + if ( pSoldier->IsValidSecondHandBurst() ) + { + iPenalty = iPenalty*6/5; // +10% + } // halve the penalty for people with the autofire trait ///////////////////////////////////////////////////////////////////////// // SANDRO - old/new traits @@ -10749,7 +10967,7 @@ void ChangeWeaponMode( SOLDIERTYPE * pSoldier ) } // Flugente: use a different scope -void ChangeScopeMode( SOLDIERTYPE * pSoldier ) +void ChangeScopeMode( SOLDIERTYPE * pSoldier, INT32 iTrgGridNo ) { // just to be safe... if ( !pSoldier ) @@ -10761,20 +10979,49 @@ void ChangeScopeMode( SOLDIERTYPE * pSoldier ) if ( (&pSoldier->inv[HANDPOS])->exists() != true ) return; - - std::map ObjList; - GetScopeLists(&pSoldier->inv[HANDPOS], ObjList); - do + INT8 bOldAimTime = pSoldier->aiData.bShownAimTime; + + // SANDRO - if the gun is flagged as HeavyGun, then we can only fire it from hip, thus no scopes to use at all, not even iron sights + if ( Item[pSoldier->inv[HANDPOS].usItem].twohanded && Weapon[pSoldier->inv[HANDPOS].usItem].HeavyGun && gGameExternalOptions.ubAllowAlternativeWeaponHolding == 3 ) { - pSoldier->bScopeMode++; - if(pSoldier->bScopeMode == NUM_SCOPE_MODES) + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + } + else + { + std::map ObjList; + GetScopeLists(&pSoldier->inv[HANDPOS], ObjList); + + do { + pSoldier->bScopeMode++; + if(pSoldier->bScopeMode == NUM_SCOPE_MODES) + { + // SANDRO - this is where we offer firing from alternative weapon hold + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; // USE_BEST_SCOPE; + } + } + while( ObjList[pSoldier->bScopeMode] == NULL && pSoldier->bScopeMode != USE_ALT_WEAPON_HOLD); //USE_BEST_SCOPE); + + // If this mode is not allowed, or we are not standing, or holding something weird, skip it + if ( pSoldier->bScopeMode == USE_ALT_WEAPON_HOLD && ( gGameExternalOptions.ubAllowAlternativeWeaponHolding != 3 || gAnimControl[ pSoldier->usAnimState ].ubEndHeight != ANIM_STAND || AM_A_ROBOT(pSoldier) || Item[pSoldier->inv[HANDPOS].usItem].rocketlauncher || Item[pSoldier->inv[HANDPOS].usItem].singleshotrocketlauncher ) ) pSoldier->bScopeMode = USE_BEST_SCOPE; + } + // changing scope mode can change number of aiming levels, we should reset the aiming variable here + // for the luxury of the payer, I've made it so if he had aiming set to a higher value, we give him the maximum value for the new scope mode, + // assuming he wants to go for the most accurate shot + if ( iTrgGridNo != 0 ) + { + if ( bOldAimTime > AllowedAimingLevels(pSoldier, iTrgGridNo) ) + { + pSoldier->aiData.bShownAimTime = AllowedAimingLevels(pSoldier, iTrgGridNo); } } - while( ObjList[pSoldier->bScopeMode] == NULL && pSoldier->bScopeMode != USE_BEST_SCOPE); - + else // wtf, reset to zero just to be sure + { + pSoldier->aiData.bShownAimTime = 0; + } + DirtyMercPanelInterface( pSoldier, DIRTYLEVEL2 ); gfUIForceReExamineCursorData = TRUE; } @@ -11067,8 +11314,9 @@ bool WeaponReady(SOLDIERTYPE * pSoldier) return false; if (gbForceWeaponReady) return true; - if ( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || - (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) ) + if (( (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIREREADY ) || + (gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_FIRE ) ) && + !(gAnimControl[ pSoldier->usAnimState ].uiFlags & ANIM_ALT_WEAPON_HOLDING ) ) return true; else return false; @@ -11222,7 +11470,7 @@ void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ) } // HEADROCK HAM 4: Calculate the ratio between current Mag Factor and Target Factor. Used for the CTH bars. -void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime ) +void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime, INT32 iGridNo ) { OBJECTTYPE *pWeapon = &(pSoldier->inv[pSoldier->ubAttackingHand]); @@ -11234,7 +11482,10 @@ void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTi // Flugente: if scope modes are allowed, player team uses them. We either use a scope or we don't, so the magnification factor isn't fitted to range (this is actually bad) if ( gGameExternalOptions.fScopeModes && pSoldier && pSoldier->bTeam == gbPlayerNum && pWeapon->exists() == true && Item[pWeapon->usItem].usItemClass == IC_GUN ) { - iScopeFactor = GetBestScopeMagnificationFactor( pSoldier, pWeapon, d2DDistance ); + if ( !pSoldier->IsValidAlternativeFireMode( bAimTime, iGridNo ) ) + iScopeFactor = GetBestScopeMagnificationFactor( pSoldier, pWeapon, d2DDistance ); + else + iScopeFactor = 1.0f; // Set a display variable gCTHDisplay.ScopeMagFactor = iScopeFactor; @@ -11252,7 +11503,10 @@ void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTi if (bAimTime > 0) { - iScopeFactor = GetBestScopeMagnificationFactor( pSoldier, pWeapon, d2DDistance ); + if ( !pSoldier->IsValidAlternativeFireMode( bAimTime, iGridNo ) ) + iScopeFactor = GetBestScopeMagnificationFactor( pSoldier, pWeapon, d2DDistance ); + else + iScopeFactor = 1.0f; // Set a display variable gCTHDisplay.ScopeMagFactor = iScopeFactor; diff --git a/Tactical/Weapons.h b/Tactical/Weapons.h index 834b3d01d..d41b44cae 100644 --- a/Tactical/Weapons.h +++ b/Tactical/Weapons.h @@ -32,6 +32,7 @@ enum ScopeMode USE_SCOPE_10, NUM_SCOPE_MODES }; +#define USE_ALT_WEAPON_HOLD -1 // SANDRO - using this for hip/onehandpistol fire //ADB moved from Interface Panels.h void HandleTacticalEffectsOfEquipmentChange( SOLDIERTYPE *pSoldier, UINT32 uiInvPos, UINT16 usOldItem, UINT16 usNewItem ); @@ -337,12 +338,15 @@ typedef struct UINT8 ubAimLevels; // HEADROCK HAM 4: Dictates how many aiming levels this gun supports. If 0, the program // chooses automatically based on the type of gun (see AllowedAimingLevels() ). + UINT8 ubHandling; // CHRISL HAM 4: This value replaces ubReadyTime for determining a weapons base handling characteristics. // Flugente FTW 1 FLOAT usOverheatingJamThreshold; // if a gun's temperature is above this treshold, it is increasingly prone to jamming FLOAT usOverheatingDamageThreshold; // if a gun is fired while its temperature is above this value, it degrades much faster FLOAT usOverheatingSingleShotTemperature; // a single shot raises a gun's temperature by this amount + + BOOLEAN HeavyGun; // SANDRO - a gun with this cannot be shouldered in standing position, part of shooting from hip feature } WEAPONTYPE; typedef struct @@ -439,7 +443,7 @@ extern INT32 CalcMaxTossRange( SOLDIERTYPE * pSoldier, UINT16 usItem, BOOLEAN fA extern UINT32 CalcThrownChanceToHit(SOLDIERTYPE *pSoldier, INT32 sGridNo, INT16 ubAimTime, UINT8 ubAimPos ); extern void ChangeWeaponMode( SOLDIERTYPE * pSoldier ); -extern void ChangeScopeMode( SOLDIERTYPE * pSoldier ); // Flugente: use different scope +extern void ChangeScopeMode( SOLDIERTYPE * pSoldier, INT32 iTrgGridNo ); // Flugente: use different scope extern BOOLEAN UseHandToHand( SOLDIERTYPE *pSoldier , INT32 sTargetGridNo, BOOLEAN fStealing ); @@ -469,7 +473,7 @@ void EstimateBulletsLeft( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObj ); extern CHAR16 gBulletCount[10]; // HEADROCK HAM 4: This function generates a mag-factor bar percentage. -void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime ); +void CalcMagFactorSimple( SOLDIERTYPE *pSoldier, FLOAT d2DDistance, INT16 bAimTime, INT32 iGridNo ); // HEADROCK HAM 4: This gets the Z of a target regardless of what's there. FLOAT GetTargetZPos( SOLDIERTYPE *pShooter, INT32 sTargetGridNo ); diff --git a/Tactical/opplist.cpp b/Tactical/opplist.cpp index 1c4e17916..ed2c4173a 100644 --- a/Tactical/opplist.cpp +++ b/Tactical/opplist.cpp @@ -85,6 +85,7 @@ void HandleManNoLongerSeen( SOLDIERTYPE * pSoldier, SOLDIERTYPE * pOpponent, INT // The_Bob - real time sneaking code 01/06/09 extern void CancelItemPointer(void); extern BOOLEAN NobodyAlerted(void); +extern void ShowRadioLocator( UINT8 ubID, UINT8 ubLocatorSpeed ); //#define TESTOPPLIST // for ManSeesMan() @@ -870,7 +871,7 @@ void HandleSight(SOLDIERTYPE *pSoldier, UINT8 ubSightFlags) if ((gTacticalStatus.uiFlags & TURNBASED) && (gTacticalStatus.uiFlags & INCOMBAT) && (ubSightFlags & SIGHT_INTERRUPT) && - (!gGameOptions.fImprovedInterruptSystem || gGameExternalOptions.fAllowInstantInterruptsOnSight ) ) + (!gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) ) ) { ResolveInterruptsVs( pSoldier, SIGHTINTERRUPT ); } @@ -2509,6 +2510,15 @@ void ManSeesMan(SOLDIERTYPE *pSoldier, SOLDIERTYPE *pOpponent, INT32 sOppGridNo, #ifdef TESTOPPLIST DebugMsg( TOPIC_JA2OPPLIST, DBG_LEVEL_3, String( "ManSeesMan: ID %d(%S) to ID %d NEW TO ME",pSoldier->ubID,pSoldier->name,pOpponent->ubID) ); #endif + // SANDRO - if this is an enemy guy, who was unaware of us till now, and the combat didn't started yet, throw "taunt" and indicator we have been seen + if ( IS_MERC_BODY_TYPE( pSoldier ) && pSoldier->bTeam != gbPlayerNum ) + { + if ( pSoldier->aiData.bOppList[pOpponent->ubID] <= NOT_HEARD_OR_SEEN && pSoldier->aiData.bAlertStatus != STATUS_RED && pSoldier->aiData.bAlertStatus != STATUS_BLACK ) + { + StartEnemyTaunt( pSoldier, TAUNT_NOTICED_UNSEEN_MERC ); + } + ShowRadioLocator( pSoldier->ubID, 1 ); + } // if we also haven't seen him earlier this turn if (pSoldier->aiData.bOppList[pOpponent->ubID] != SEEN_THIS_TURN) @@ -7184,46 +7194,49 @@ void NoticeUnseenAttacker( SOLDIERTYPE * pAttacker, SOLDIERTYPE * pDefender, INT } } - if ( StandardInterruptConditionsMet( pDefender, pAttacker->ubID, bOldOppList ) ) + if ( !gGameOptions.fImprovedInterruptSystem || (gGameOptions.fImprovedInterruptSystem && gGameExternalOptions.fAllowInstantInterruptsOnSight) ) { - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, standard conditions are met; defender %d, attacker %d", pDefender->ubID, pAttacker->ubID ) ); - - // calculate the interrupt duel points - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for defender in NUA" ); - pDefender->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pDefender, pAttacker->ubID, FALSE); - } - else - { - pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; - } - - // say quote - - if (pDefender->aiData.bInterruptDuelPts != NO_INTERRUPT) - { - // check for possible interrupt and handle control change if it happens - // this code is basically ResolveInterruptsVs for 1 man only... - - // calculate active soldier's dueling pts for the upcoming interrupt duel - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for attacker in NUA" ); - pAttacker->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pAttacker, pDefender->ubID, FALSE ); - if ( InterruptDuel( pDefender, pAttacker ) ) + if ( StandardInterruptConditionsMet( pDefender, pAttacker->ubID, bOldOppList ) ) { - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, defender pts %d, attacker pts %d, defender gets interrupt", pDefender->aiData.bInterruptDuelPts, pAttacker->aiData.bInterruptDuelPts ) ); - AddToIntList( pAttacker->ubID, FALSE, TRUE); - AddToIntList( pDefender->ubID, TRUE, TRUE); - DoneAddingToIntList( pDefender, TRUE, SIGHTINTERRUPT ); - } - // either way, clear out both sides' duelPts fields to prepare next duel - pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; - #ifdef DEBUG_INTERRUPTS - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pDefender->ubID ) ); - #endif - pAttacker->aiData.bInterruptDuelPts = NO_INTERRUPT; - #ifdef DEBUG_INTERRUPTS - DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pAttacker->ubID ) ); - #endif + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, standard conditions are met; defender %d, attacker %d", pDefender->ubID, pAttacker->ubID ) ); + // calculate the interrupt duel points + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for defender in NUA" ); + pDefender->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pDefender, pAttacker->ubID, FALSE); + } + else + { + pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; + } + + // say quote + + if (pDefender->aiData.bInterruptDuelPts != NO_INTERRUPT) + { + // check for possible interrupt and handle control change if it happens + // this code is basically ResolveInterruptsVs for 1 man only... + + // calculate active soldier's dueling pts for the upcoming interrupt duel + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, "Calculating int duel pts for attacker in NUA" ); + pAttacker->aiData.bInterruptDuelPts = CalcInterruptDuelPts( pAttacker, pDefender->ubID, FALSE ); + if ( InterruptDuel( pDefender, pAttacker ) ) + { + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("INTERRUPT: NoticeUnseenAttacker, defender pts %d, attacker pts %d, defender gets interrupt", pDefender->aiData.bInterruptDuelPts, pAttacker->aiData.bInterruptDuelPts ) ); + AddToIntList( pAttacker->ubID, FALSE, TRUE); + AddToIntList( pDefender->ubID, TRUE, TRUE); + DoneAddingToIntList( pDefender, TRUE, SIGHTINTERRUPT ); + } + // either way, clear out both sides' duelPts fields to prepare next duel + pDefender->aiData.bInterruptDuelPts = NO_INTERRUPT; + #ifdef DEBUG_INTERRUPTS + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pDefender->ubID ) ); + #endif + pAttacker->aiData.bInterruptDuelPts = NO_INTERRUPT; + #ifdef DEBUG_INTERRUPTS + DebugMsg( TOPIC_JA2, DBG_LEVEL_3, String("Resetting int pts for %d in NUA", pAttacker->ubID ) ); + #endif + + } } } diff --git a/TacticalAI/AIInternals.h b/TacticalAI/AIInternals.h index 9b43c07c6..b49e3c737 100644 --- a/TacticalAI/AIInternals.h +++ b/TacticalAI/AIInternals.h @@ -131,6 +131,7 @@ typedef struct INT8 bTargetLevel; // target level of this attack INT16 ubAPCost; // how many APs the attack will use up INT8 bWeaponIn; // the inv slot of the weapon in question + INT8 bScopeMode; // SANDRO: added for scope mode and alternative weapon holding } ATTACKTYPE; extern THREATTYPE Threat[MAXMERCS]; diff --git a/TacticalAI/AIMain.cpp b/TacticalAI/AIMain.cpp index e25f3e920..7f2a0fad5 100644 --- a/TacticalAI/AIMain.cpp +++ b/TacticalAI/AIMain.cpp @@ -2764,7 +2764,7 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) case AI_ACTION_LOWER_GUN: // for now, just do "action done" - pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection,TRUE); + pSoldier->InternalSoldierReadyWeapon(pSoldier->ubDirection,TRUE,FALSE); HandleSight(pSoldier, SIGHT_LOOK ); ActionDone( pSoldier ); break; @@ -2774,7 +2774,8 @@ INT8 ExecuteAction(SOLDIERTYPE *pSoldier) HandleSight(pSoldier, SIGHT_LOOK | SIGHT_RADIO); //AXP 23.03.2007: Sniper deadlock fix - if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->aiData.bLastAction == AI_ACTION_RAISE_GUN) + //if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->aiData.bLastAction == AI_ACTION_RAISE_GUN) + if ( pSoldier->aiData.bLastAction == AI_ACTION_RAISE_GUN) { pSoldier->aiData.bNextAction = AI_ACTION_END_TURN; } diff --git a/TacticalAI/AIUtils.cpp b/TacticalAI/AIUtils.cpp index b33469c5d..7855988a8 100644 --- a/TacticalAI/AIUtils.cpp +++ b/TacticalAI/AIUtils.cpp @@ -39,7 +39,7 @@ // InWaterOrGas - gas stuff // RoamingRange - point patrol stuff -extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady ); +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); UINT8 Urgency[NUM_STATUS_STATES][NUM_MORALE_STATES] = { @@ -189,7 +189,7 @@ UINT8 ShootingStanceChange( SOLDIERTYPE * pSoldier, ATTACKTYPE * pAttack, INT8 b UINT16 usRealAnimState, usBestAnimState; INT8 bBestStanceDiff=-1; - INT8 bLoop, bStanceNum, bStanceDiff, bAPsAfterAttack, bCurAimTime; + INT8 bLoop, bStanceNum, bStanceDiff, bAPsAfterAttack, bCurAimTime, bSetScopeMode; UINT32 uiChanceOfDamage, uiBestChanceOfDamage, uiCurrChanceOfDamage; UINT32 uiStanceBonus, uiMinimumStanceBonusPerChange = 20 - 3 * pAttack->ubAimTime; INT32 iRange; @@ -197,7 +197,10 @@ UINT8 ShootingStanceChange( SOLDIERTYPE * pSoldier, ATTACKTYPE * pAttack, INT8 b bStanceNum = 0; uiCurrChanceOfDamage = 0; - bAPsAfterAttack = pSoldier->bActionPoints - MinAPsToAttack( pSoldier, pAttack->sTarget, ADDTURNCOST, 1); + bSetScopeMode = pSoldier->bScopeMode; + pSoldier->bScopeMode = pAttack->bScopeMode; + bAPsAfterAttack = pSoldier->bActionPoints - MinAPsToAttack( pSoldier, pAttack->sTarget, ADDTURNCOST, pAttack->ubAimTime, 1); + pSoldier->bScopeMode = bSetScopeMode; if (bAPsAfterAttack < GetAPsCrouch(pSoldier, TRUE)) { return( 0 ); @@ -511,7 +514,7 @@ BOOLEAN IsActionAffordable(SOLDIERTYPE *pSoldier) case AI_ACTION_KNIFE_MOVE: // preparing to stab adjacent opponent case AI_ACTION_THROW_KNIFE: // only FIRE_GUN currently actually pays extra turning costs! - bMinPointsNeeded = MinAPsToAttack(pSoldier,pSoldier->aiData.usActionData,ADDTURNCOST); + bMinPointsNeeded = MinAPsToAttack(pSoldier,pSoldier->aiData.usActionData,ADDTURNCOST,pSoldier->aiData.bAimTime); #ifdef BETAVERSION if (ptsNeeded > pSoldier->bActionPoints) diff --git a/TacticalAI/Attacks.cpp b/TacticalAI/Attacks.cpp index 0e26ee439..f572969b4 100644 --- a/TacticalAI/Attacks.cpp +++ b/TacticalAI/Attacks.cpp @@ -156,9 +156,10 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns UINT8 ubMaxPossibleAimTime; INT16 ubAimTime,ubMinAPcost,ubRawAPCost; UINT8 ubChanceToReallyHit = 0; - INT16 ubChanceToHit,ubBestAimTime,ubChanceToGetThrough,ubBestChanceToHit; + INT16 ubChanceToHit,ubChanceToHit2,ubBestAimTime,ubChanceToGetThrough,ubBestChanceToHit; SOLDIERTYPE *pOpponent; INT16 ubBurstAPs; + INT8 bScopeMode; DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CalcBestShot"); @@ -210,7 +211,15 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns // calculate minimum action points required to shoot at this opponent // if ( !Weapon[pSoldier->usAttackingWeapon].NoSemiAuto ) - ubMinAPcost = MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST); + // SANDRO - calculate this with the alternative mode, as it is faster, decide the actual bScopeMode later + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding ) + { + if (!WeaponReady( pSoldier )) // but only if we are not already in raised weapon stance + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + else + pSoldier->bScopeMode = USE_BEST_SCOPE; + } + ubMinAPcost = MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0); // What the.... The APs to attack on the HandleItem side does not make a test like this. It always uses the MinAPs as a base. // else // ubMinAPcost = CalcAPsToAutofire( pSoldier->CalcActionPoints( ), &(pSoldier->inv[HANDPOS]), 3 ); @@ -269,18 +278,76 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns } } - // calc next attack's minimum shooting cost (excludes readying & turning) - ubRawAPCost = MinAPsToShootOrStab(pSoldier,pOpponent->sGridNo,FALSE); - - if (pOpponent->sGridNo == pSoldier->sLastTarget) - { - // raw AP cost calculation included cost of changing target! - // Not unless we really needed to change targets! - //ubRawAPCost -= APBPConstants[AP_CHANGE_TARGET]; - } + //if (pOpponent->sGridNo == pSoldier->sLastTarget) + //{ + // // raw AP cost calculation included cost of changing target! + // // Not unless we really needed to change targets! + // //ubRawAPCost -= APBPConstants[AP_CHANGE_TARGET]; + //} iBestHitRate = 0; // reset best hit rate to minimum + // SANDRO: decide here, whether to use the alternative holding or normal holding + bScopeMode = USE_BEST_SCOPE; + if ( gGameExternalOptions.ubAllowAlternativeWeaponHolding ) + { + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier,pOpponent->sGridNo,0, AIM_SHOT_TORSO); // get CtH from alternative hold, without aiming + pSoldier->bScopeMode = USE_BEST_SCOPE; + // CASE #1 - Enemy very close, or we have very good chance to hit from hip with no aiming + if (( PythSpacesAway( pSoldier->sGridNo, pOpponent->sGridNo ) < 5 || ubChanceToHit > 80 ) && !WeaponReady(pSoldier) ) + bScopeMode = USE_ALT_WEAPON_HOLD; + // CASE #2 - HeavyGun tag, or heavy LMG in hand + if (Weapon[pSoldier->usAttackingWeapon].HeavyGun || (Weapon[pSoldier->usAttackingWeapon].ubWeaponType == GUN_LMG && GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) > 50)) + bScopeMode = USE_ALT_WEAPON_HOLD; + // reset the mode back + // CASE #3 - We don't have enough APs for shot from regular stance, and there is at least some reasonable chance we hit target from alternative mode + if ( (MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0) > pSoldier->bActionPoints) && (ubChanceToHit > 30) ) + bScopeMode = USE_ALT_WEAPON_HOLD; + // CASE #4 - CtH with alternative hold is simply better than with normal hold (probably due to scope giving penalty on short range) + else if ( !WeaponReady(pSoldier) ) // ... and we are not in ready weapon stance yet + { + pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; + ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier,pOpponent->sGridNo,AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO); + pSoldier->bScopeMode = USE_BEST_SCOPE; + ubChanceToHit2 = (INT16) AICalcChanceToHitGun(pSoldier,pOpponent->sGridNo,AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO); + if ( ubChanceToHit > ubChanceToHit2 && ubChanceToHit > 30 && (ubChanceToHit-ubChanceToHit2) >= 15 ) + bScopeMode = USE_ALT_WEAPON_HOLD; + } + } + if ( gGameExternalOptions.fScopeModes ) + { + // Now try to decide which scope mode is better + // we simply compare the chance to hit with various scopes at full aiming, sometimes, we get penalty for using a scope at close range + // in case the best scope is not actually the "best" (at this distance), we will use the other one + if ( bScopeMode == USE_BEST_SCOPE ) + { + ubChanceToHit = (INT16) AICalcChanceToHitGun(pSoldier,pOpponent->sGridNo,AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO); + std::map ObjList; + GetScopeLists(&pSoldier->inv[HANDPOS], ObjList); + do + { + pSoldier->bScopeMode++; + if ( ObjList[pSoldier->bScopeMode] != NULL ) + { + ubChanceToHit2 = (INT16) AICalcChanceToHitGun(pSoldier,pOpponent->sGridNo,AllowedAimingLevels( pSoldier, pOpponent->sGridNo ), AIM_SHOT_TORSO); + if ( ubChanceToHit2 > ubChanceToHit ) + { + bScopeMode = pSoldier->bScopeMode; + ubChanceToHit = ubChanceToHit2; + } + } + } + while( ObjList[pSoldier->bScopeMode] == NULL && pSoldier->bScopeMode != NUM_SCOPE_MODES); + + } + } + pSoldier->bScopeMode = bScopeMode; // just for later calculations + // recalculate MinAPsToAttack with our selected scope mode + ubMinAPcost = MinAPsToAttack(pSoldier,pOpponent->sGridNo,ADDTURNCOST,0); + // calc next attack's minimum shooting cost (excludes readying & turning) + ubRawAPCost = MinAPsToShootOrStab(pSoldier,pOpponent->sGridNo,0,FALSE); + // calculate the maximum possible aiming time if ( TANK( pSoldier ) ) @@ -417,8 +484,10 @@ void CalcBestShot(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN shootUns pBestShot->bTargetLevel = pOpponent->pathing.bLevel; pBestShot->iAttackValue = iAttackValue; pBestShot->ubAPCost = ubMinAPcost; + pBestShot->bScopeMode = bScopeMode; } } + pSoldier->bScopeMode = USE_BEST_SCOPE; // better reset this back } // JA2Gold: added @@ -931,7 +1000,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) } // calculate minimum action points required to throw at this gridno - ubMinAPcost = MinAPsToAttack(pSoldier,sGridNo,ADDTURNCOST); + ubMinAPcost = MinAPsToAttack(pSoldier,sGridNo,ADDTURNCOST,0); DebugMsg(TOPIC_JA2 , DBG_LEVEL_3 , String("MinAPcost to attack = %d",ubMinAPcost)); // if we don't have enough APs left to throw even without aiming @@ -1105,7 +1174,7 @@ void CalcBestThrow(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"calcbestthrow: checking chance to hit"); if ( EXPLOSIVE_GUN( usInHand ) ) { - ubRawAPCost = MinAPsToShootOrStab( pSoldier, sGridNo, FALSE); + ubRawAPCost = MinAPsToShootOrStab( pSoldier, sGridNo,ubMaxPossibleAimTime,FALSE); ubChanceToHit = (UINT8) AICalcChanceToHitGun(pSoldier, sGridNo, ubMaxPossibleAimTime, AIM_SHOT_TORSO ); } else @@ -1287,7 +1356,7 @@ void CalcBestStab(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab, BOOLEAN fBladeAt // calc next attack's minimum stabbing cost (excludes movement & turning) //ubRawAPCost = MinAPsToShootOrStab(pSoldier,pOpponent->sGridNo, FALSE) - APBPConstants[AP_CHANGE_TARGET]; - ubRawAPCost = MinAPsToAttack(pSoldier,pOpponent->sGridNo, FALSE) - APBPConstants[AP_CHANGE_TARGET]; + ubRawAPCost = MinAPsToAttack(pSoldier,pOpponent->sGridNo, FALSE,0) - APBPConstants[AP_CHANGE_TARGET]; //NumMessage("ubRawAPCost to stab this opponent = ",ubRawAPCost); @@ -1479,7 +1548,7 @@ void CalcTentacleAttack(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestStab ) // calc next attack's minimum stabbing cost (excludes movement & turning) //ubRawAPCost = MinAPsToShootOrStab(pSoldier,pOpponent->sGridNo, FALSE) - APBPConstants[AP_CHANGE_TARGET]; - ubRawAPCost = MinAPsToAttack(pSoldier,pOpponent->sGridNo, FALSE) - APBPConstants[AP_CHANGE_TARGET]; + ubRawAPCost = MinAPsToAttack(pSoldier,pOpponent->sGridNo, FALSE,0) - APBPConstants[AP_CHANGE_TARGET]; //NumMessage("ubRawAPCost to stab this opponent = ",ubRawAPCost); // determine if this is a surprise stab (for tentacles, enemy must not see us, no dist limit) @@ -2264,7 +2333,7 @@ void CheckIfTossPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestThrow) DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"checkiftosspossible: get minapstoattack"); // get the minimum cost to attack with this tossable item - ubMinAPcost = MinAPsToAttack( pSoldier, pSoldier->sLastTarget, DONTADDTURNCOST); + ubMinAPcost = MinAPsToAttack( pSoldier, pSoldier->sLastTarget, DONTADDTURNCOST,0); // if we can afford the minimum AP cost to throw this tossable item if (pSoldier->bActionPoints >= ubMinAPcost) @@ -2589,7 +2658,7 @@ INT16 AdvanceToFiringRange( SOLDIERTYPE * pSoldier, INT16 sClosestOpponent ) INT16 bAttackCost, bTrueActionPoints; UINT16 usActionData; - bAttackCost = MinAPsToAttack(pSoldier, sClosestOpponent, ADDTURNCOST); + bAttackCost = MinAPsToAttack(pSoldier, sClosestOpponent, ADDTURNCOST,pSoldier->aiData.bAimTime); if (bAttackCost >= pSoldier->bActionPoints) { @@ -2656,7 +2725,7 @@ void CheckIfShotPossible(SOLDIERTYPE *pSoldier, ATTACKTYPE *pBestShot, BOOLEAN s { // get the minimum cost to attack with this item DebugMsg (TOPIC_JA2,DBG_LEVEL_3,"CheckIfShotPossible: getting min aps"); - ubMinAPcost = MinAPsToAttack( pSoldier, pSoldier->sLastTarget, ADDTURNCOST); + ubMinAPcost = MinAPsToAttack( pSoldier, pSoldier->sLastTarget, ADDTURNCOST,pBestShot->ubAimTime); DebugMsg (TOPIC_JA2,DBG_LEVEL_3,String("CheckIfShotPossible: min AP cost: %d", ubMinAPcost)); // if we can afford the minimum AP cost diff --git a/TacticalAI/CreatureDecideAction.cpp b/TacticalAI/CreatureDecideAction.cpp index d46e6cb84..c664ad898 100644 --- a/TacticalAI/CreatureDecideAction.cpp +++ b/TacticalAI/CreatureDecideAction.cpp @@ -1138,7 +1138,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier ) // now it better be a gun, or the guy can't shoot (but has other attack(s)) // get the minimum cost to attack the same target with this gun - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0); // if we have enough action points to shoot with this gun if (pSoldier->bActionPoints >= ubMinAPCost) @@ -1250,7 +1250,7 @@ INT8 CreatureDecideActionBlack( SOLDIERTYPE * pSoldier ) } // get the minimum cost to attack with this knife - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0); //sprintf(tempstr,"%s - ubMinAPCost = %d",pSoldier->name,ubMinAPCost); //PopMessage(tempstr); diff --git a/TacticalAI/DecideAction.cpp b/TacticalAI/DecideAction.cpp index d9c8ed607..a695d7585 100644 --- a/TacticalAI/DecideAction.cpp +++ b/TacticalAI/DecideAction.cpp @@ -43,6 +43,7 @@ extern BOOLEAN gfHiddenInterrupt; extern BOOLEAN gfUseAlternateQueenPosition; +extern UINT16 PickSoldierReadyAnimation( SOLDIERTYPE *pSoldier, BOOLEAN fEndReady, BOOLEAN fHipStance ); // global status time counters to determine what takes the most time @@ -1240,7 +1241,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) //////////////////////////////////////////////////////////////////////////// DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: Snipers like to raise weapons, sniper = %d",pSoldier->sniper)); - if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->sniper == 0 && ( pSoldier->pathing.bLevel == 1 || Random(100) < 40 ) ) + if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->sniper == 0 && ( pSoldier->pathing.bLevel == 1 || Random(100) < 40 ) && (pSoldier->bBreath > 30 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 20) ) { if ( !(WeaponReady(pSoldier)) ) // SANDRO - only call this if we are not in readied position yet { @@ -1268,7 +1269,8 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) { if (!(WeaponReady(pSoldier))) { - if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) + if ((!gfTurnBasedAI || ((GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) ) <= pSoldier->bActionPoints)) && + (pSoldier->bBreath > 30 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 20) ) { iChance = 25; if ( pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA || pSoldier->ubSoldierClass == SOLDIER_CLASS_ELITE ) @@ -1284,7 +1286,10 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) } else // if the weapon is ready already, maybe unready it { - if ( Random(100) < 40 ) + iChance = 30; + // is it a heavy gun? And we have energy cost for shooting enabled? + iChance += GetBPCostPer10APsForGunHolding( pSoldier ); // don't overexagerate yourself + if ( Random(100) < iChance ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionGreen: Soldier deciding to lower weapon")); return(AI_ACTION_LOWER_GUN); @@ -1319,7 +1324,7 @@ INT8 DecideActionGreen(SOLDIERTYPE *pSoldier) if ( pSoldier->aiData.bOrders == SNIPER && pSoldier->pathing.bLevel == 1) iChance += 35; - if ( WeaponReady(pSoldier) ) // SANDRO - if readied weapon, make him more likelz to turn around + if ( WeaponReady(pSoldier) ) // SANDRO - if readied weapon, make him more likely to turn around iChance += 30; if ((INT16)PreRandom(100) < iChance) @@ -1489,7 +1494,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) sprintf(tempstr,"%s - TURNS TOWARDS NOISE to face direction %d",pSoldier->name,pSoldier->aiData.usActionData); AIPopMessage(tempstr); #endif - if ( pSoldier->aiData.bOrders == SNIPER ) + if ( pSoldier->aiData.bOrders == SNIPER && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -1497,13 +1502,13 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) } } //////////////////////////////////////////////////////////////////////////// - // SANDRO - allow regular soldiers to raise scoped weapons to see rather away too + // SANDRO - allow regular soldiers to raise scoped weapons to see farther away too if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) { - if (!(WeaponReady(pSoldier))) + if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) { - if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) + if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) <= pSoldier->bActionPoints) { if ( Random(100) < 35 ) { @@ -1597,6 +1602,14 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) { // take a breather for gods sake! pSoldier->aiData.usActionData = NOWHERE; + + // is it a heavy gun? And we have energy cost for shooting enabled? + if ( WeaponReady(pSoldier) && GetBPCostPer10APsForGunHolding( pSoldier ) > 0 ) + { + // unready + return(AI_ACTION_LOWER_GUN); + } + return(AI_ACTION_NONE); } @@ -1764,7 +1777,7 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) // if ( CanClimbFromHere ( pSoldier, fUp ) ) if ( pSoldier->sGridNo == sNoiseGridNo) { - if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sNoiseGridNo, ADDTURNCOST))) + if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sNoiseGridNo, ADDTURNCOST,0))) { return( AI_ACTION_CLIMB_ROOF ); } @@ -2033,17 +2046,12 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir) // if we are facing the direction of where the noise came from + if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) // if we are facing the direction of where the noise came from { - if (!gfTurnBasedAI || (GetAPsToReadyWeapon( pSoldier, ANIM_CROUCH ) + GetAPsToChangeStance( pSoldier, ANIM_CROUCH )) <= pSoldier->bActionPoints) + if (!gfTurnBasedAI || (((GetAPsToReadyWeapon( pSoldier, PickSoldierReadyAnimation( pSoldier, FALSE, FALSE ) ) ) + GetAPsToChangeStance( pSoldier, ANIM_CROUCH )) <= pSoldier->bActionPoints)) { - iChance = 20; if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) - { - iChance += 30; - } - if ( Random(100) < (UINT32)iChance ) { pSoldier->aiData.bNextAction = AI_ACTION_RAISE_GUN; } @@ -2059,19 +2067,17 @@ INT8 DecideActionYellow(SOLDIERTYPE *pSoldier) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir) // if we are facing the direction of where the noise came from + if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubNoiseDir && (pSoldier->bBreath > 25 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 30)) // if we are facing the direction of where the noise came from { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) { - iChance = 20; if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) { - iChance += 30; - } - if ( Random(100) < (UINT32)iChance ) - { - return( AI_ACTION_RAISE_GUN ); + if ( Random(100) < 35 ) + { + return( AI_ACTION_RAISE_GUN ); + } } } } @@ -2458,6 +2464,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) pSoldier->aiData.usActionData = BestShot.sTarget; //POSSIBLE STRUCTURE CHANGE PROBLEM. GOTTHARD 7/14/08 pSoldier->aiData.bAimTime = BestShot.ubAimTime; + pSoldier->bScopeMode = BestShot.bScopeMode; ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, New113Message[ MSG113_SNIPER ] ); return(AI_ACTION_FIRE_GUN ); } @@ -2586,6 +2593,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) // HEADROCK HAM 4: This is the stupidest thing ever. // Menptr[BestShot.ubOpponent].ubSuppressionPoints += pSoldier->bDoAutofire; Menptr[BestShot.ubOpponent].ubSuppressorID = pSoldier->ubID; + if (!WeaponReady( pSoldier ) && gGameExternalOptions.ubAllowAlternativeWeaponHolding){ pSoldier->bScopeMode = USE_ALT_WEAPON_HOLD; } return( AI_ACTION_FIRE_GUN ); } else @@ -2705,6 +2713,13 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) #endif pSoldier->aiData.usActionData = NOWHERE; + + // is it a heavy gun? And we have energy cost for shooting enabled? + if ( WeaponReady(pSoldier) && GetBPCostPer10APsForGunHolding( pSoldier ) > 0 ) + { + // unready + return(AI_ACTION_LOWER_GUN); + } return(AI_ACTION_NONE); } @@ -2896,7 +2911,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, tempGridNo, pSoldier->pathing.bLevel, TRUE) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, tempGridNo, (INT8) (MinAPsToAttack( pSoldier, tempGridNo, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, tempGridNo, (INT8) (MinAPsToAttack( pSoldier, tempGridNo, ADDTURNCOST,0) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -3061,7 +3076,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) //if ( CanClimbFromHere ( pSoldier, fUp ) ) if (pSoldier->sGridNo == sClosestDisturbance) { - if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST))) + if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST,0))) { return( AI_ACTION_CLIMB_ROOF ); } @@ -3126,7 +3141,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( PythSpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, sClosestDisturbance, pSoldier->pathing.bLevel, TRUE ) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST,0) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -3164,7 +3179,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( PythSpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, sClosestDisturbance, pSoldier->pathing.bLevel, TRUE ) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST,0) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -3287,7 +3302,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) //if ( CanClimbFromHere ( pSoldier, fUp ) ) if (pSoldier->sGridNo == sClosestFriend) { - if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestFriend, ADDTURNCOST))) + if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestFriend, ADDTURNCOST,0))) { return( AI_ACTION_CLIMB_ROOF ); } @@ -3352,7 +3367,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) { // either moving significantly closer or into very close range // ensure will we have enough APs for a possible crouch plus a shot - if ( InternalGoAsFarAsPossibleTowards( pSoldier, pSoldier->aiData.usActionData, (INT8) (MinAPsToAttack( pSoldier, sClosestOpponent, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_TAKE_COVER, 0 ) == pSoldier->aiData.usActionData ) + if ( InternalGoAsFarAsPossibleTowards( pSoldier, pSoldier->aiData.usActionData, (INT8) (MinAPsToAttack( pSoldier, sClosestOpponent, ADDTURNCOST,0) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_TAKE_COVER, 0 ) == pSoldier->aiData.usActionData ) { return(AI_ACTION_TAKE_COVER); } @@ -3502,7 +3517,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) sprintf(tempstr,"%s - TURNS TOWARDS CLOSEST ENEMY to face direction %d",pSoldier->name,pSoldier->aiData.usActionData); AIPopMessage(tempstr); #endif - if ( pSoldier->aiData.bOrders == SNIPER && !(WeaponReady(pSoldier)) ) + if ( pSoldier->aiData.bOrders == SNIPER && !(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50) ) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -3514,7 +3529,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) else if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) { - if (!(WeaponReady(pSoldier))) + if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) { @@ -3531,10 +3546,10 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) } } //////////////////////////////////////////////////////////////////////////// - // SANDRO - allow regular soldiers to raise scoped weapons to see rather away too + // SANDRO - allow regular soldiers to raise scoped weapons to see farther away too else if ( pSoldier->ubDirection == ubOpponentDir && !(WeaponReady(pSoldier))) { - if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) + if ((!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { if ( pSoldier->aiData.bOrders == SNIPER ) { @@ -3706,7 +3721,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) #endif //////////////////////////////////////////////////////////////////////////// - // SANDRO - allow regular soldiers to raise scoped weapons to see rather away too + // SANDRO - allow regular soldiers to raise scoped weapons to see farther away too if (!gfTurnBasedAI || (GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) + GetAPsToChangeStance( pSoldier, ANIM_CROUCH )) <= pSoldier->bActionPoints) { // determine direction from this soldier to the closest opponent @@ -3714,15 +3729,13 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if (!(WeaponReady(pSoldier)) && pSoldier->ubDirection == ubOpponentDir ) { - iChance = 25; if ( (UsingNewCTHSystem() == false && IsScoped(&pSoldier->inv[HANDPOS])) || (UsingNewCTHSystem() == true && NCTHIsScoped(&pSoldier->inv[HANDPOS])) ) { - iChance += 25; - } - if ( Random(100) < (UINT32)iChance ) - { - pSoldier->aiData.bNextAction = AI_ACTION_RAISE_GUN; + if ( Random(100) < 40 ) + { + pSoldier->aiData.bNextAction = AI_ACTION_RAISE_GUN; + } } } } @@ -3773,7 +3786,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) if ( pSoldier->sniper == 0 ) { DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("DecideActionRed: sniper raising gun...")); - if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) + if ((!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, READY_RIFLE_CROUCH ) <= pSoldier->bActionPoints) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) { if (!(WeaponReady(pSoldier))) { @@ -3792,7 +3805,7 @@ INT8 DecideActionRed(SOLDIERTYPE *pSoldier, UINT8 ubUnconsciousOK) { //////////////////////////////////////////////////////////////////////////// // SANDRO - raise weapon maybe - if (!(WeaponReady(pSoldier))) // if we are facing the direction of where the noise came from + if (!(WeaponReady(pSoldier)) && (pSoldier->bBreath > 15 || GetBPCostPer10APsForGunHolding( pSoldier, TRUE ) < 50)) // if we are facing the direction of where the noise came from { if (!gfTurnBasedAI || GetAPsToReadyWeapon( pSoldier, pSoldier->usAnimState ) <= pSoldier->bActionPoints) { @@ -4229,7 +4242,7 @@ INT16 ubMinAPCost; if (Item[pSoldier->inv[HANDPOS].usItem].usItemClass == IC_GUN && pSoldier->inv[HANDPOS][0]->data.gun.bGunStatus >= USABLE) { // get the minimum cost to attack the same target with this gun - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,ADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,ADDTURNCOST,0); // if we have enough action points to shoot with this gun if (pSoldier->bActionPoints >= ubMinAPCost) @@ -4373,7 +4386,7 @@ INT16 ubMinAPCost; } // get the minimum cost to attack with this knife - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0,0); // if we can afford the minimum AP cost to stab with/throw this knife weapon if (pSoldier->bActionPoints >= ubMinAPCost) @@ -4448,7 +4461,7 @@ INT16 ubMinAPCost; } // get the minimum cost to attack with punch - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0,0); // if we can afford the minimum AP cost to punch if (pSoldier->bActionPoints >= ubMinAPCost) { @@ -4595,7 +4608,7 @@ INT16 ubMinAPCost; } // get the minimum cost to attack by HTH - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0,0); // if we can afford the minimum AP cost to use HTH combat if (pSoldier->bActionPoints >= ubMinAPCost) @@ -4800,6 +4813,7 @@ INT16 ubMinAPCost; // default settings //POSSIBLE STRUCTURE CHANGE PROBLEM, NOT CURRENTLY CHANGED. GOTTHARD 7/14/08 pSoldier->aiData.bAimTime = BestAttack.ubAimTime; + pSoldier->bScopeMode = BestAttack.bScopeMode; pSoldier->bDoBurst = 0; // HEADROCK HAM 3.6: bAimTime represents how MANY aiming levels are used, not how much APs they cost necessarily. @@ -4808,7 +4822,7 @@ INT16 ubMinAPCost; if (ubBestAttackAction == AI_ACTION_FIRE_GUN) { // Do we need to change stance? NB We'll have to ready our gun again - if ( !TANK( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 1 ) ) ) + if ( !TANK( pSoldier ) && ( pSoldier->bActionPoints >= BestAttack.ubAPCost + GetAPsCrouch( pSoldier, TRUE) + MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST,0, 1 ) ) ) { // since the AI considers shooting chance from standing primarily, if we are not // standing we should always consider a stance change @@ -4863,7 +4877,7 @@ INT16 ubMinAPCost; // account for increased AP cost and having to re-ready weapon ubStanceCost = (UINT8) GetAPsToChangeStance( pSoldier, ubBestStance ); - BestAttack.ubAPCost = MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 1) + ubStanceCost; + BestAttack.ubAPCost = MinAPsToAttack( pSoldier, BestAttack.sTarget, ADDTURNCOST, 0, 1) + ubStanceCost; // Clip the aim time if necessary // HEADROCK HAM 3.6: Use Actual Aiming Costs, without assuming that each aim level = 1 AP. @@ -4918,6 +4932,10 @@ INT16 ubMinAPCost; case ATTACKSLAYONLY:iChance += 30; break; } + // SANDRO: more likely to burst when firing from hip + if ( BestAttack.bScopeMode == USE_ALT_WEAPON_HOLD && Item[pSoldier->inv[BestAttack.bWeaponIn].usItem].twohanded ) + iChance += 40; + // CHRISL: Changed from a simple flag to two externalized values for more modder control over AI suppression if ( GetMagSize(&pSoldier->inv[BestAttack.bWeaponIn], 0) >= gGameExternalOptions.ubAISuppressionMinimumMagSize && pSoldier->inv[BestAttack.bWeaponIn][0]->data.gun.ubGunShotsLeft >= gGameExternalOptions.ubAISuppressionMinimumAmmo ) @@ -5013,6 +5031,9 @@ INT16 ubMinAPCost; case ATTACKSLAYONLY:iChance += 30; break; } + // SANDRO: more likely to burst when firing from hip + if ( BestAttack.bScopeMode == USE_ALT_WEAPON_HOLD && Item[pSoldier->inv[BestAttack.bWeaponIn].usItem].twohanded ) + iChance += 40; // CHRISL: Changed from a simple flag to two externalized values for more modder control over AI suppression if ( GetMagSize(&pSoldier->inv[BestAttack.bWeaponIn], 0) >= gGameExternalOptions.ubAISuppressionMinimumMagSize && @@ -5150,25 +5171,30 @@ INT16 ubMinAPCost; else if (ubBestAttackAction == AI_ACTION_KNIFE_MOVE && gGameOptions.fNewTraitSystem) { pSoldier->aiData.bAimTime = 0; + iChance = 0; if (Item[pSoldier->inv[BestAttack.bWeaponIn].usItem].usItemClass == IC_PUNCH) { - if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT)) + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) + iChance += 30; + if (HAS_SKILL_TRAIT( pSoldier, MARTIAL_ARTS_NT) ) + iChance += 30 * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT); + + if( PreRandom( 100 ) <= iChance ) { - if( PreRandom( (gGameExternalOptions.fEnhancedCloseCombatSystem ? 2 : 0) + 2 * NUM_SKILL_TRAITS( pSoldier, MARTIAL_ARTS_NT) ) > 2 ) - { - pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6); - } + pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : 6); } } else { + if ( gGameExternalOptions.fEnhancedCloseCombatSystem ) + iChance += 30; if (HAS_SKILL_TRAIT( pSoldier, MELEE_NT)) + iChance += 30; + + if( PreRandom( 100 ) <= iChance ) { - if( PreRandom( gGameExternalOptions.fEnhancedCloseCombatSystem ? 3 : 1 ) > 0 ) - { - pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6); - } + pSoldier->aiData.bAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : 6); } } } @@ -6842,7 +6868,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) //if ( CanClimbFromHere ( pSoldier, fUp ) ) if (pSoldier->sGridNo == sClosestDisturbance) { - if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST))) + if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST, 0))) { return( AI_ACTION_CLIMB_ROOF ); } @@ -6945,7 +6971,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) if ( PythSpacesAway( pSoldier->aiData.usActionData, sClosestDisturbance ) < 5 || LocationToLocationLineOfSightTest( pSoldier->aiData.usActionData, pSoldier->pathing.bLevel, sClosestDisturbance, pSoldier->pathing.bLevel, TRUE ) ) { // reserve APs for a possible crouch plus a shot - pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); + pSoldier->aiData.usActionData = InternalGoAsFarAsPossibleTowards(pSoldier, sClosestDisturbance, (INT8) (MinAPsToAttack( pSoldier, sClosestDisturbance, ADDTURNCOST, 0) + GetAPsCrouch( pSoldier, TRUE)), AI_ACTION_SEEK_OPPONENT, FLAG_CAUTIOUS ); if (!TileIsOutOfBounds(pSoldier->aiData.usActionData)) { @@ -7055,7 +7081,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) //if ( CanClimbFromHere ( pSoldier, fUp ) ) if (pSoldier->sGridNo == sClosestFriend) { - if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestFriend, ADDTURNCOST))) + if (IsActionAffordable(pSoldier) && pSoldier->bActionPoints >= ( APBPConstants[AP_CLIMBROOF] + MinAPsToAttack( pSoldier, sClosestFriend, ADDTURNCOST, 0))) { return( AI_ACTION_CLIMB_ROOF ); } @@ -7443,7 +7469,7 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) } // get the minimum cost to attack with punch - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0); // if we can afford the minimum AP cost to punch if (pSoldier->bActionPoints >= ubMinAPCost) { @@ -7553,8 +7579,8 @@ void DecideAlertStatus( SOLDIERTYPE *pSoldier ) RearrangePocket(pSoldier,HANDPOS,bWeaponIn,TEMPORARILY); } - // get the minimum cost to attack by HTH - ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST); + // get the minimum cost to attack by HTH + ubMinAPCost = MinAPsToAttack(pSoldier,pSoldier->sLastTarget,DONTADDTURNCOST,0,0); // if we can afford the minimum AP cost to use HTH combat if (pSoldier->bActionPoints >= ubMinAPCost) diff --git a/Utils/Text.h b/Utils/Text.h index 6914fa053..c70ddcee6 100644 --- a/Utils/Text.h +++ b/Utils/Text.h @@ -312,6 +312,7 @@ extern STR16 sEnemyTauntsRunAway[]; extern STR16 sEnemyTauntsSeekNoise[]; extern STR16 sEnemyTauntsAlert[]; extern STR16 sEnemyTauntsGotHit[]; +extern STR16 sEnemyTauntsNoticedMerc[]; //**** // HEADROCK HAM 3.6: New arrays for facility operation messages diff --git a/Utils/_ChineseText.cpp b/Utils/_ChineseText.cpp index 49c9e8bad..2553ba16d 100644 --- a/Utils/_ChineseText.cpp +++ b/Utils/_ChineseText.cpp @@ -6820,6 +6820,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7089,8 +7102,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \n该物品能够用于爆破锁具。\n \n使用它需要爆破技能以避免过早引爆。\n \n使用炸药是一个相对简单的破锁手段,但是会\n发出很大噪音,并且对于大部分佣兵来说过于\n危险。", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_DutchText.cpp b/Utils/_DutchText.cpp index 40d97d6bd..ccc8ab85d 100644 --- a/Utils/_DutchText.cpp +++ b/Utils/_DutchText.cpp @@ -6816,6 +6816,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7085,8 +7098,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_EnglishText.cpp b/Utils/_EnglishText.cpp index 141493efa..33f67bae7 100644 --- a/Utils/_EnglishText.cpp +++ b/Utils/_EnglishText.cpp @@ -6808,6 +6808,18 @@ STR16 sEnemyTauntsGotHit[]= }; +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7078,8 +7090,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.", L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_FrenchText.cpp b/Utils/_FrenchText.cpp index 0b05ca1d4..f562db36b 100644 --- a/Utils/_FrenchText.cpp +++ b/Utils/_FrenchText.cpp @@ -6791,6 +6791,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7060,8 +7073,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nCet objet peut être utilisé pour faire sauter les portes\nou containeurs vérouillés.\n \nDes compétences en explosion sont nécessaire pour éviter\nune explosion prématurée.\n \nExploser les serrures est relativement facile et rapide\nà faire. Cependant, c'est très bruyant et dangereux pour\nla plupart des mercernaires.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_GermanText.cpp b/Utils/_GermanText.cpp index 47908ccab..69daaae9d 100644 --- a/Utils/_GermanText.cpp +++ b/Utils/_GermanText.cpp @@ -6634,6 +6634,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips @@ -6904,8 +6917,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nDieser Gegenstand kann dazu benutzt werden verschlossene\nTüren/Behälter zu sprengen.\n \nExplosionsfertigkeit ist erforderlich um\nvorzeitige Detonationen zu vermeiden.\n \nSchlösser zu sprengen ist der einfache Weg um schnell\ndurch verschlossene Türen/Behälter zu kommen. Wie auch immer,\nes ist Laut und für die meisten Personen gefährlich.", L"\n \nMan kann das trinken.", L"\n \nMan kann das essen.", - L"\n \Ein externer Munitionsgurt für MGs.", - L"\n \In diese Weste passen auch Munitionsgurte.", + L"\n \nEin externer Munitionsgurt für MGs.", + L"\n \nIn diese Weste passen auch Munitionsgurte.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_ItalianText.cpp b/Utils/_ItalianText.cpp index 6ac1ec465..c12e04051 100644 --- a/Utils/_ItalianText.cpp +++ b/Utils/_ItalianText.cpp @@ -6803,6 +6803,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7072,8 +7085,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_Ja25ChineseText.cpp b/Utils/_Ja25ChineseText.cpp index 0d8561bd7..668e62a5f 100644 --- a/Utils/_Ja25ChineseText.cpp +++ b/Utils/_Ja25ChineseText.cpp @@ -134,6 +134,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"栓动步枪拉栓所需行动点 -%d%s \n",// L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"步枪精确瞄准次数增加 1次\n",// L"Adds one more aim click for rifle-type guns\n", L"步枪精确瞄准次数增加 %d次\n",// L"Adds %d more aim clicks for rifle-type guns\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25DutchText.cpp b/Utils/_Ja25DutchText.cpp index 580d7085f..7b1ed558d 100644 --- a/Utils/_Ja25DutchText.cpp +++ b/Utils/_Ja25DutchText.cpp @@ -134,6 +134,8 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"Adds one more aim click for rifle-type guns\n", L"Adds %d more aim clicks for rifle-type guns\n", + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25EnglishText.cpp b/Utils/_Ja25EnglishText.cpp index dc34f26df..cea380c5c 100644 --- a/Utils/_Ja25EnglishText.cpp +++ b/Utils/_Ja25EnglishText.cpp @@ -134,6 +134,8 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"Adds one more aim click for rifle-type guns\n", L"Adds %d more aim clicks for rifle-type guns\n", + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= @@ -192,7 +194,7 @@ STR16 gzIMPMajorTraitsHelpTextsMartialArts[]= L"-%d%s APs needed to climb on/off roof and jump obstacles\n", L"+%d%s chance to kick doors in\n", // MINTY - Changed to "kick doors in" L"You gain special animations for hand to hand combat\n", - L"-%d%s chance to be interrupted when moving\n", + L"-%d%s chance to be interrupted when charging towards an enemy on close range\n", }; STR16 gzIMPMajorTraitsHelpTextsSquadleader[]= diff --git a/Utils/_Ja25FrenchText.cpp b/Utils/_Ja25FrenchText.cpp index ebe94f2f7..5e6cbf01b 100644 --- a/Utils/_Ja25FrenchText.cpp +++ b/Utils/_Ja25FrenchText.cpp @@ -134,6 +134,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s du nombre de PA nécessaire pour recharger avec le fusil de précision\n", L"Ajoute un niveau de visée en plus pour chaque fusil de précision\n", L"Ajoute %d niveaux de visée pour chaque fusil de précision\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25GermanText.cpp b/Utils/_Ja25GermanText.cpp index 28fd23176..275d56b0b 100644 --- a/Utils/_Ja25GermanText.cpp +++ b/Utils/_Ja25GermanText.cpp @@ -132,6 +132,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs benötigt um ein Repetiergewehr erneut fertigzuladen.\n", L"Gibt einen weiteren Ziel-Klick für gewehrartige Waffen\n", L"Gibt weitere %d Ziel-Klicks für gewehrartige Waffen\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25ItalianText.cpp b/Utils/_Ja25ItalianText.cpp index 5e2a62f35..926f83b3b 100644 --- a/Utils/_Ja25ItalianText.cpp +++ b/Utils/_Ja25ItalianText.cpp @@ -132,6 +132,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"Adds one more aim click for rifle-type guns\n", L"Adds %d more aim clicks for rifle-type guns\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25PolishText.cpp b/Utils/_Ja25PolishText.cpp index 566398c4f..b9d9e0170 100644 --- a/Utils/_Ja25PolishText.cpp +++ b/Utils/_Ja25PolishText.cpp @@ -134,6 +134,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"Adds one more aim click for rifle-type guns\n", L"Adds %d more aim clicks for rifle-type guns\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25RussianText.cpp b/Utils/_Ja25RussianText.cpp index ef617b141..156af531d 100644 --- a/Utils/_Ja25RussianText.cpp +++ b/Utils/_Ja25RussianText.cpp @@ -133,6 +133,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s ОД на передёргивание затвора магазинных винтовок\n", L"Плюс 1 клик-прицеливания к оружию типа винтовки\n", L"Плюс %d клик-прицеливания к оружию типа винтовки\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_Ja25TaiwaneseText.cpp b/Utils/_Ja25TaiwaneseText.cpp index 8312bf675..b82c63c77 100644 --- a/Utils/_Ja25TaiwaneseText.cpp +++ b/Utils/_Ja25TaiwaneseText.cpp @@ -135,6 +135,9 @@ STR16 gzIMPMajorTraitsHelpTextsSniper[]= L"-%d%s APs needed to chamber a round with bolt-action rifles \n", L"Adds one more aim click for rifle-type guns\n", L"Adds %d more aim clicks for rifle-type guns\n", + // TO DO - translate + L"Makes aiming faster with rifle-type guns by one aim click\n", + L"Makes aiming faster with rifle-type guns by %d aim clicks\n", }; STR16 gzIMPMajorTraitsHelpTextsRanger[]= diff --git a/Utils/_PolishText.cpp b/Utils/_PolishText.cpp index 500d08f62..55dcd8738 100644 --- a/Utils/_PolishText.cpp +++ b/Utils/_PolishText.cpp @@ -6815,6 +6815,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7084,8 +7097,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_RussianText.cpp b/Utils/_RussianText.cpp index 6546ab5bf..3571c0d8c 100644 --- a/Utils/_RussianText.cpp +++ b/Utils/_RussianText.cpp @@ -6783,6 +6783,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7052,8 +7065,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]= diff --git a/Utils/_TaiwaneseText.cpp b/Utils/_TaiwaneseText.cpp index dd21e9a5a..02365e8e5 100644 --- a/Utils/_TaiwaneseText.cpp +++ b/Utils/_TaiwaneseText.cpp @@ -6820,6 +6820,19 @@ STR16 sEnemyTauntsGotHit[]= }; +// TODO.Translate +STR16 sEnemyTauntsNoticedMerc[]= +{ + L"Da'ffff...!", + L"Oh my God!", + L"Holy crap!", + L"Enemy!!!", + L"Alert! Alert!", + L"There is one!", + L"Attack!", + +}; + ////////////////////////////////////////////////////// // HEADROCK HAM 4: Begin new UDB texts and tooltips ////////////////////////////////////////////////////// @@ -7089,8 +7102,8 @@ STR16 szUDBGenSecondaryStatsExplanationsTooltipText[]= L"\n \nThis item can be used to blast open locked\ndoors and containers.\n \nExplosives skill is required to avoid\npremature detonation.\n \nBlowing locks is a relatively easy way of quickly\ngetting through locked doors. However,\nit is very loud, and dangerous to most characters.", L"\n \nThis item will still your thirst\nif you drink it.",// TODO. Translate L"\n \nThis item will still your hunger\nif you eat it.", - L"\n \With this ammo belt you can\nfeed someone else's MG.", - L"\n \You can feed an MG with ammo\nbelts stored in this vest.", + L"\n \nWith this ammo belt you can\nfeed someone else's MG.", + L"\n \nYou can feed an MG with ammo\nbelts stored in this vest.", }; STR16 szUDBAdvStatsTooltipText[]=