mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@7998 3b4a5df2-a311-0410-b5c6-a8a6f20db521
3836 lines
107 KiB
C++
3836 lines
107 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include "items.h"
|
|
#include "weapons.h"
|
|
#include "Interface Cursors.h"
|
|
|
|
#include "overhead.h"
|
|
#include "Handle UI.h"
|
|
#include "Animation Control.h"
|
|
#include "points.h"
|
|
#include "Sound Control.h"
|
|
#include "Sys globals.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Animation Data.h"
|
|
#include "worldman.h"
|
|
#include "ui cursors.h"
|
|
#include "los.h"
|
|
#include "renderworld.h"
|
|
#include "interface.h"
|
|
#include "ui cursors.h"
|
|
#include "cursors.h"
|
|
#include "cursor control.h"
|
|
#include "structure wrap.h"
|
|
#include "physics.h"
|
|
#include "soldier macros.h"
|
|
#include "text.h"
|
|
#include "spread burst.h"
|
|
#include "GameSettings.h"
|
|
#include "Interactive Tiles.h"
|
|
#include "PATHAI.H"
|
|
#include "SkillCheck.h" // added by SANDRO
|
|
#include "message.H" //ddd
|
|
#include "english.h" // added by Flugente
|
|
#endif
|
|
|
|
//forward declarations of common classes to eliminate includes
|
|
class OBJECTTYPE;
|
|
class SOLDIERTYPE;
|
|
|
|
|
|
// FUNCTIONS FOR ITEM CURSOR HANDLING
|
|
UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEAN fShowAPs, BOOLEAN fRecalc, UINT32 uiCursorFlags );
|
|
UINT8 HandleNonActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEAN fShowAPs, BOOLEAN fRecalc, UINT32 uiCursorFlags );
|
|
UINT8 HandleKnifeCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
|
UINT8 HandlePunchCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlagsl );
|
|
UINT8 HandleAidCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
|
UINT8 HandleActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubCursor );
|
|
UINT8 HandleNonActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fRecalc, UINT32 uiCursorFlags, UINT8 ubCursor );
|
|
UINT8 HandleWirecutterCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
|
UINT8 HandleRepairCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
|
UINT8 HandleRefuelCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
|
UINT8 HandleRemoteCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
|
UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags );
|
|
UINT8 HandleJarCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
|
UINT8 HandleTinCanCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags );
|
|
UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
|
UINT8 HandleHandcuffCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
|
UINT8 HandleApplyItemCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags ); //added by Flugente
|
|
|
|
extern BOOLEAN HandleCheckForBadChangeToGetThrough( SOLDIERTYPE *pSoldier, SOLDIERTYPE *pTargetSoldier, INT32 sTargetGridNo , INT8 bLevel );
|
|
|
|
UINT8 DefaultAutofireBulletsByGunClass( SOLDIERTYPE* pSoldier ); // added by Sevenfm
|
|
|
|
BOOLEAN gfCannotGetThrough = FALSE;
|
|
extern UINT32 guiUITargetSoldierId;
|
|
BOOLEAN gfDisplayFullCountRing = FALSE;
|
|
BOOLEAN gfAutofireInitBulletNum = FALSE;
|
|
|
|
UINT8 gubAimRingRanges[] = {30, 55, 75, 90}; // These are the cutoff ranges for the aiming rings
|
|
extern INT8 gbNumBurstLocations; //number of burst points
|
|
|
|
|
|
BOOLEAN GetMouseRecalcAndShowAPFlags( UINT32 *puiCursorFlags, BOOLEAN *pfShowAPs )
|
|
{
|
|
UINT32 uiCursorFlags;
|
|
static BOOLEAN fDoNewTile = FALSE;
|
|
BOOLEAN fRecalc = FALSE;
|
|
BOOLEAN fShowAPs = FALSE;
|
|
|
|
// SET FLAGS FOR CERTAIN MOUSE MOVEMENTS
|
|
GetCursorMovementFlags( &uiCursorFlags );
|
|
|
|
// Force if we are currently cycling guys...
|
|
if ( gfUIForceReExamineCursorData )
|
|
{
|
|
fDoNewTile = TRUE;
|
|
fRecalc = TRUE;
|
|
gfUIForceReExamineCursorData = FALSE;
|
|
}
|
|
|
|
// IF CURSOR IS MOVING
|
|
if ( uiCursorFlags & MOUSE_MOVING )
|
|
{
|
|
// IF CURSOR WAS PREVIOUSLY STATIONARY, MAKE THE ADDITIONAL CHECK OF GRID POS CHANGE
|
|
//if ( uiCursorFlags & MOUSE_MOVING_NEW_TILE )
|
|
{
|
|
// Reset counter
|
|
RESETCOUNTER( PATHFINDCOUNTER );
|
|
fDoNewTile = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( uiCursorFlags & MOUSE_STATIONARY )
|
|
{
|
|
// ONLY DIPSLAY APS AFTER A DELAY
|
|
if ( COUNTERDONE( PATHFINDCOUNTER ) )
|
|
{
|
|
// Don't reset counter: One when we move again do we do this!
|
|
fShowAPs = TRUE;
|
|
|
|
if ( fDoNewTile )
|
|
{
|
|
fDoNewTile = FALSE;
|
|
fRecalc = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( puiCursorFlags )
|
|
{
|
|
(*puiCursorFlags) = uiCursorFlags;
|
|
}
|
|
|
|
if ( pfShowAPs )
|
|
{
|
|
(*pfShowAPs) = fShowAPs;
|
|
}
|
|
|
|
return( fRecalc );
|
|
}
|
|
|
|
|
|
// FUNCTIONS FOR CURSOR DETERMINATION!
|
|
UINT8 GetProperItemCursor( UINT8 ubSoldierID, UINT16 ubItemIndex, INT32 usMapPos, BOOLEAN fActivated )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
UINT32 uiCursorFlags;
|
|
BOOLEAN fShowAPs = FALSE;
|
|
BOOLEAN fRecalc = FALSE;
|
|
INT32 sTargetGridNo = usMapPos;
|
|
UINT8 ubCursorID=0;
|
|
UINT8 ubItemCursor;
|
|
|
|
pSoldier = MercPtrs[ ubSoldierID ];
|
|
|
|
fRecalc = GetMouseRecalcAndShowAPFlags( &uiCursorFlags, &fShowAPs );
|
|
|
|
// ATE: Update attacking weapon!
|
|
// CC has added this attackingWeapon stuff and I need to update it constantly for
|
|
// CTGH algorithms
|
|
if ( gTacticalStatus.ubAttackBusyCount == 0 && Item[ pSoldier->inv[HANDPOS].usItem ].usItemClass & IC_WEAPON )
|
|
{
|
|
pSoldier->usAttackingWeapon = pSoldier->inv[HANDPOS].usItem;
|
|
}
|
|
|
|
// Calculate target gridno!
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
sTargetGridNo = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
}
|
|
else
|
|
{
|
|
sTargetGridNo = usMapPos;
|
|
}
|
|
|
|
ubItemCursor = GetActionModeCursor( pSoldier );
|
|
|
|
switch( ubItemCursor )
|
|
{
|
|
case PUNCHCURS:
|
|
|
|
// Determine whether gray or red!
|
|
ubCursorID = HandlePunchCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
|
break;
|
|
|
|
case KNIFECURS:
|
|
//Madd: quick hack to make wirecutter cursor appear when using a knife that can cut through wire
|
|
if ( Item[ubItemIndex].wirecutters && IsCuttableWireFenceAtGridNo( sTargetGridNo ) && pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
ubCursorID = GOOD_WIRECUTTER_UICURSOR;
|
|
}
|
|
else
|
|
ubCursorID = HandleKnifeCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
|
break;
|
|
|
|
case AIDCURS:
|
|
|
|
ubCursorID = HandleAidCursor( pSoldier, usMapPos, fActivated, uiCursorFlags );
|
|
break;
|
|
|
|
case TARGETCURS:
|
|
|
|
// Set merc glow script
|
|
SetMercGlowFast( );
|
|
|
|
if ( fActivated )
|
|
{
|
|
ubCursorID = HandleActivatedTargetCursor( pSoldier, sTargetGridNo, fShowAPs, fRecalc, uiCursorFlags );
|
|
}
|
|
else
|
|
{
|
|
ubCursorID = HandleNonActivatedTargetCursor( pSoldier, sTargetGridNo, fShowAPs, fRecalc, uiCursorFlags );
|
|
}
|
|
|
|
|
|
// ATE: Only do this if we are in combat!
|
|
if ( gCurrentUIMode == ACTION_MODE && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
// Alrighty, let's change the cursor!
|
|
if ( fRecalc && gfUIFullTargetFound )
|
|
{
|
|
// ATE: Check for ammo
|
|
if ( IsValidTargetMerc( (UINT8)gusUIFullTargetID ) && EnoughAmmo( pSoldier, FALSE, HANDPOS ) &&
|
|
(!pSoldier->IsValidSecondHandShotForReloadingPurposes( ) || EnoughAmmo( pSoldier, FALSE, SECONDHANDPOS) ) )
|
|
{
|
|
// IF it's an ememy, goto confirm action mode
|
|
if ( ( guiUIFullTargetFlags & ENEMY_MERC ) && ( guiUIFullTargetFlags & VISIBLE_MERC ) && !( guiUIFullTargetFlags & DEAD_MERC ) && !gfCannotGetThrough )
|
|
{
|
|
guiPendingOverrideEvent = A_CHANGE_TO_CONFIM_ACTION;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
case TRAJECTORYCURS:
|
|
|
|
if ( fActivated )
|
|
{
|
|
if ( !gfUIHandlePhysicsTrajectory )
|
|
{
|
|
ubCursorID = HandleNonActivatedTossCursor( pSoldier, sTargetGridNo, fRecalc, uiCursorFlags, ubItemCursor );
|
|
}
|
|
else
|
|
{
|
|
ubCursorID = HandleActivatedTossCursor( pSoldier, sTargetGridNo, ubItemCursor );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ubCursorID = HandleNonActivatedTossCursor( pSoldier, sTargetGridNo, fRecalc, uiCursorFlags, ubItemCursor );
|
|
}
|
|
|
|
#if 0
|
|
if ( gCurrentUIMode == ACTION_MODE && ubItemCursor == TRAJECTORYCURS && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
// Alrighty, let's change the cursor!
|
|
if ( fRecalc && gfUIFullTargetFound )
|
|
{
|
|
// ATE: Check for ammo
|
|
if ( IsValidTargetMerc( (UINT8)gusUIFullTargetID ) && EnoughAmmo( pSoldier, FALSE, HANDPOS ) )
|
|
{
|
|
// IF it's an ememy, goto confirm action mode
|
|
if ( ( guiUIFullTargetFlags & ENEMY_MERC ) && ( guiUIFullTargetFlags & VISIBLE_MERC ) && !( guiUIFullTargetFlags & DEAD_MERC ) && !gfCannotGetThrough )
|
|
{
|
|
guiPendingOverrideEvent = A_CHANGE_TO_CONFIM_ACTION;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case BOMBCURS:
|
|
|
|
ubCursorID = HandleBombCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
|
break;
|
|
|
|
case REMOTECURS:
|
|
|
|
ubCursorID = HandleRemoteCursor( pSoldier, sTargetGridNo, fActivated, uiCursorFlags );
|
|
break;
|
|
|
|
case WIRECUTCURS:
|
|
|
|
ubCursorID = HandleWirecutterCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
|
|
case REPAIRCURS:
|
|
|
|
ubCursorID = HandleRepairCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case JARCURS:
|
|
|
|
ubCursorID = HandleJarCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case TINCANCURS:
|
|
|
|
ubCursorID = HandleTinCanCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case REFUELCURS:
|
|
|
|
ubCursorID = HandleRefuelCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case FORTICURS:
|
|
|
|
ubCursorID = HandleFortificationCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case HANDCUFFCURS:
|
|
|
|
ubCursorID = HandleHandcuffCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case APPLYITEMCURS:
|
|
|
|
ubCursorID = HandleApplyItemCursor( pSoldier, sTargetGridNo, uiCursorFlags );
|
|
break;
|
|
|
|
case INVALIDCURS:
|
|
|
|
ubCursorID = INVALID_ACTION_UICURSOR;
|
|
break;
|
|
|
|
}
|
|
|
|
if ( !( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
PauseRT( TRUE );
|
|
}
|
|
else
|
|
{
|
|
PauseRT( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
return( ubCursorID );
|
|
}
|
|
|
|
|
|
// WANNE: Shows the target cursor over the enemy soldier
|
|
UINT8 HandleActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos, BOOLEAN fShowAPs, BOOLEAN fRecalc, UINT32 uiCursorFlags )
|
|
{
|
|
UINT8 switchVal;
|
|
BOOLEAN fEnoughPoints = TRUE;
|
|
UINT8 bFutureAim;
|
|
INT16 sAPCosts;
|
|
INT16 sAPCostsMin;
|
|
UINT16 usCursor=0;
|
|
BOOLEAN fMaxPointLimitHit = FALSE;
|
|
UINT16 usInHand;
|
|
|
|
UINT16 reverse = 0;
|
|
|
|
// HEADROCK HAM 4: Required for new Aiming Level Limit function
|
|
UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, usMapPos);
|
|
|
|
usInHand = pSoldier->inv[ HANDPOS ].usItem;
|
|
|
|
if ( Item[ usInHand ].usItemClass != IC_THROWING_KNIFE )
|
|
{
|
|
// If we are in realtime, follow!
|
|
if ( ( !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
if ( ( gAnimControl[ MercPtrs[ gusSelectedSoldier ]->usAnimState ].uiFlags & ANIM_STATIONARY ) )
|
|
{
|
|
if ( gUITargetShotWaiting )
|
|
{
|
|
guiPendingOverrideEvent = CA_MERC_SHOOT;
|
|
}
|
|
}
|
|
|
|
//SoldierFollowGridNo( pSoldier, sMapPos );
|
|
}
|
|
|
|
// Check if we are reloading
|
|
if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
if ( pSoldier->flags.fReloading || pSoldier->flags.fPauseAim )
|
|
{
|
|
return( ACTION_TARGET_RELOADING );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Determine where we are shooting / aiming
|
|
//if ( fRecalc )
|
|
{
|
|
DetermineCursorBodyLocation( (UINT8)gusSelectedSoldier, TRUE, TRUE );
|
|
}
|
|
UINT8 ubMaxBullets = 1;
|
|
INT8 bMaxAim;
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if(pSoldier->bDoAutofire)
|
|
{
|
|
// sevenfm: change number of autofire bullets only once when switching cursor to action mode or changing firing mode
|
|
if( !gfAutofireInitBulletNum )
|
|
{
|
|
INT16 sCurAPCosts, sAPCosts;
|
|
UINT16 usShotsLeft = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft;
|
|
if (pSoldier->IsValidSecondHandBurst())
|
|
{
|
|
usShotsLeft = min( (pSoldier->inv[ SECONDHANDPOS ][0]->data.gun.ubGunShotsLeft), usShotsLeft );
|
|
}
|
|
bMaxAim = pSoldier->aiData.bShownAimTime;
|
|
|
|
// sevenfm: change default number of bullets in autofire according to ini settings
|
|
ubMaxBullets = DefaultAutofireBulletsByGunClass( pSoldier );
|
|
if( ubMaxBullets == 0 )
|
|
{
|
|
ubMaxBullets = (UINT8)usShotsLeft;
|
|
bMaxAim = maxAimLevels;
|
|
}
|
|
|
|
sCurAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bMaxAim);
|
|
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire++;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bMaxAim);
|
|
} // sevenfm: removed (sAPCosts <= sCurAPCosts) because EnoughPoints() is enough
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && usShotsLeft >= pSoldier->bDoAutofire && pSoldier->bDoAutofire <= ubMaxBullets );
|
|
pSoldier->bDoAutofire--;
|
|
|
|
gfAutofireInitBulletNum = TRUE;
|
|
}
|
|
|
|
gfUIAutofireBulletCount = TRUE;
|
|
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;
|
|
else
|
|
gTintBulletCounts = FALSE;
|
|
|
|
}
|
|
else
|
|
gfUIAutofireBulletCount = FALSE;
|
|
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
|
|
while(!EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) && pSoldier->bDoAutofire > 1) //oops, we don't have enough points if we are in auto-fire try to decrease bulletcount
|
|
{
|
|
pSoldier->bDoAutofire--;
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
}
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) && (pSoldier->aiData.bShownAimTime == 0))
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
|
|
fMaxPointLimitHit = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// WANNE: How oft increased?
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + 1 );
|
|
|
|
if ( bFutureAim <= maxAimLevels )
|
|
{
|
|
if (reverse == 0)
|
|
{
|
|
// WANNE: Current AP costs for targeting
|
|
//sAPCosts = MinAPsToAttack( pSoldier, usMapPos, TRUE, bFutureAim ) + ( bFutureAim );
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bFutureAim );
|
|
|
|
//gsCurrentActionPoints = sAPCosts;
|
|
|
|
// Determine if we can afford!
|
|
if ( !EnoughPoints( pSoldier, (INT16)sAPCosts, 0 , FALSE ) )
|
|
{
|
|
fEnoughPoints = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//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, 0 );
|
|
sAPCostsMin = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, 0 );
|
|
if (sAPCosts < sAPCostsMin)
|
|
{
|
|
fEnoughPoints = FALSE;
|
|
}
|
|
}
|
|
|
|
//// Determine if we can afford!
|
|
//if ( !EnoughPoints( pSoldier, (INT16)sAPCosts, 0 , FALSE ) )
|
|
//{
|
|
// fEnoughPoints = FALSE;
|
|
//}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
if ( !pSoldier->flags.fPauseAim )
|
|
{
|
|
if ( COUNTERDONE( TARGETREFINE ) )
|
|
{
|
|
// Reset counter
|
|
RESETCOUNTER( TARGETREFINE );
|
|
|
|
if ( pSoldier->bDoBurst )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime++;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime > maxAimLevels )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = maxAimLevels;
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->aiData.bShownAimTime % 2 )
|
|
{
|
|
PlayJA2Sample( TARG_REFINE_BEEP, RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fRecalc )
|
|
{
|
|
if ( gusUIFullTargetID != NOBODY )
|
|
{
|
|
if ( SoldierToSoldierBodyPartChanceToGetThrough( pSoldier, MercPtrs[ gusUIFullTargetID ], pSoldier->bAimShotLocation ) < OK_CHANCE_TO_GET_THROUGH )
|
|
{
|
|
gfCannotGetThrough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gfCannotGetThrough = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( SoldierToLocationChanceToGetThrough( pSoldier, usMapPos, (INT8) gsInterfaceLevel, pSoldier->bTargetCubeLevel, NOBODY ) < OK_CHANCE_TO_GET_THROUGH )
|
|
{
|
|
gfCannotGetThrough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gfCannotGetThrough = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OK, if we begin to move, reset the cursor...
|
|
if ( uiCursorFlags & MOUSE_MOVING )
|
|
{
|
|
//gfCannotGetThrough = FALSE;
|
|
}
|
|
|
|
if ( pSoldier->flags.fDoSpread && pSoldier->bDoAutofire) //approximate spread-auto costs
|
|
{
|
|
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 ) && usShotsLeft >= pSoldier->bDoAutofire && gbNumBurstLocations >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, gsBurstLocations[0].sGridNo, TRUE, pSoldier->aiData.bShownAimTime );
|
|
}
|
|
}
|
|
|
|
if ( fMaxPointLimitHit )
|
|
{
|
|
// Check if we're in burst mode!
|
|
if ( pSoldier->bDoBurst )
|
|
{
|
|
usCursor = ACTION_TARGETREDBURST_UICURSOR;
|
|
}
|
|
else if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
usCursor = RED_THROW_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETRED_UICURSOR;
|
|
}
|
|
}
|
|
else if ( pSoldier->bDoBurst )
|
|
{
|
|
if ( pSoldier->flags.fDoSpread )
|
|
{
|
|
usCursor = ACTION_TARGETREDBURST_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
//usCursor = ACTION_TARGETREDBURST_UICURSOR;
|
|
usCursor = ACTION_TARGETCONFIRMBURST_UICURSOR;
|
|
|
|
// HEADROCK HAM B1: Burst cursor now shows multiple CTH bars (one for each bullet)
|
|
// and also a Targetted Bodypart indicator.
|
|
//if(pSoldier->bDoAutofire == 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
if(pSoldier->bDoAutofire == 0)
|
|
{
|
|
if(UsingNewCTHSystem() == true)
|
|
{
|
|
//AXP 29.03.2007: Rooftop CtH fix. See below.
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
UINT32 uiHitChance;
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
gfUICtHBar = TRUE;
|
|
gbCtHBurstCount = 0;
|
|
gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2;
|
|
gCTHDisplay.iShooterGridNo = pSoldier->sGridNo;
|
|
gCTHDisplay.iTargetGridNo = usMapPos;
|
|
|
|
// Calculate distance to target
|
|
FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos ));
|
|
FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos ));
|
|
FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY));
|
|
|
|
CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos );
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
}
|
|
else if(gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
{
|
|
if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2)
|
|
{
|
|
// Burst mode only
|
|
OBJECTTYPE * pInHand;
|
|
pInHand = &(pSoldier->inv[pSoldier->ubAttackingHand]);
|
|
// Burst size
|
|
gbCtHBurstCount = GetShotsPerBurst(pInHand);
|
|
UINT8 i, saveDoBurst;
|
|
// Save original burst value (should be 1 always, before the burst has been fired, but
|
|
// this is just a failsafe
|
|
saveDoBurst = pSoldier->bDoBurst;
|
|
|
|
// For each bullet in the burst
|
|
for (i=0;i<gbCtHBurstCount;i++)
|
|
{
|
|
//AXP 29.03.2007: Rooftop CtH fix. See below.
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
// Calculate hit chance (using the current bDoBurst for burst-penalty calculations)
|
|
UINT32 uiHitChance;
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
|
|
// Put result (burst CTH) into the array
|
|
gbCtH[i] = (gbCtH[i]+uiHitChance)/2;
|
|
|
|
// Increase burst size, so that the next time we run CalcChanceToHitGun we'll get a lower
|
|
// result, based on our Burst Penalty
|
|
pSoldier->bDoBurst++;
|
|
}
|
|
// Reset original burst status
|
|
pSoldier->bDoBurst = saveDoBurst;
|
|
// Activate CTH bar display
|
|
gfUICtHBar = TRUE;
|
|
}
|
|
else // One "BASE CTH" bar, JA2 1.13 vanilla
|
|
{
|
|
//AXP 29.03.2007: Rooftop CtH fix. See below.
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
UINT32 uiHitChance;
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
|
|
gfUICtHBar = TRUE;
|
|
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
|
|
gbCtHBurstCount = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// HEADROCK HAM B2: Now autofire will show both its starting CTH and the CTH of the last
|
|
// bullet in the volley.
|
|
|
|
//else if(pSoldier->bDoAutofire > 0 && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
else if(pSoldier->bDoAutofire > 0)
|
|
{
|
|
if(UsingNewCTHSystem() == true)
|
|
{
|
|
//AXP 29.03.2007: Rooftop CtH fix. See below.
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
UINT32 uiHitChance;
|
|
// Calculate CTH for the first bullet
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
// CTH for the first bullet is entered into this array, and later displayed
|
|
gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2;
|
|
gCTHDisplay.iShooterGridNo = pSoldier->sGridNo;
|
|
gCTHDisplay.iTargetGridNo = usMapPos;
|
|
|
|
// Flag to tell the program to draw two CTH bars.
|
|
gfUICtHBar = TRUE;
|
|
gbCtHBurstCount = 0;
|
|
|
|
// Calculate distance to target
|
|
FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos ));
|
|
FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos ));
|
|
FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY));
|
|
|
|
CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos );
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
}
|
|
else if(gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
{
|
|
if (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3)
|
|
{
|
|
gbCtHBurstCount = 1;
|
|
|
|
//AXP 29.03.2007: Rooftop CtH fix. See below.
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
UINT32 uiHitChance;
|
|
// Calculate CTH for the first bullet
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
// CTH for the first bullet is entered into this array, and later displayed
|
|
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
|
|
|
|
// Fool the CTH formula into thinking we're already firing the last bullet in the volley,
|
|
// by artificially altering bDoBurst (which tracks actual burst progression). The CTH formula
|
|
// calculates Auto Penalty based on bDoBurst - (Autopen * (bDoBurst-1), basically).
|
|
UINT8 saveDoBurst = pSoldier->bDoBurst;
|
|
pSoldier->bDoBurst = pSoldier->bDoAutofire;
|
|
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
// Return Burst State to original value
|
|
pSoldier->bDoBurst = saveDoBurst;
|
|
|
|
// CTH for the last bullet is entered into this array and later displayed.
|
|
gbCtH[1] = (gbCtH[1]+uiHitChance)/2;
|
|
|
|
// Flag to tell the program to draw two CTH bars.
|
|
gbCtHAutoFire = TRUE;
|
|
gfUICtHBar = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//DIGICRAB: Graphical CtH
|
|
//if(gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
{
|
|
//AXP 29.03.2007: Rooftop CtH fix. Temporarily set soldier targetlevel to the real interface
|
|
//level (selected with TAB), so the first shot after switching TL is calculated correctly
|
|
INT8 bTempTargetLevel = pSoldier->bTargetLevel;
|
|
pSoldier->bTargetLevel = (INT8) gsInterfaceLevel;
|
|
|
|
UINT32 uiHitChance;
|
|
// SANDRO - precise calculation for throwing knives added
|
|
if(UsingNewCTHSystem() == true)
|
|
{
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
}
|
|
else
|
|
{
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
uiHitChance = CalcThrownChanceToHit( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
}
|
|
else
|
|
{
|
|
uiHitChance = CalcChanceToHitGun( pSoldier, usMapPos, (INT8)(pSoldier->aiData.bShownAimTime ), pSoldier->bAimShotLocation );
|
|
}
|
|
}
|
|
// HEADROCK HAM B2.7: CTH approximation?
|
|
if (gGameExternalOptions.fApproximateCTH)
|
|
{
|
|
uiHitChance = ChanceToHitApproximation( pSoldier, uiHitChance );
|
|
}
|
|
|
|
if(UsingNewCTHSystem() == true)
|
|
{
|
|
gfUICtHBar = TRUE;
|
|
gbCtHBurstCount = 0;
|
|
|
|
// CTH for the first bullet is entered into this array, and later displayed
|
|
gCTHDisplay.MuzzleSwayPercentage = (gCTHDisplay.MuzzleSwayPercentage + uiHitChance)/2;
|
|
gCTHDisplay.iShooterGridNo = pSoldier->sGridNo;
|
|
gCTHDisplay.iTargetGridNo = usMapPos;
|
|
|
|
// Calculate distance to target
|
|
FLOAT dDeltaX = (FLOAT)(CenterX( pSoldier->sGridNo ) - CenterX( usMapPos ));
|
|
FLOAT dDeltaY = (FLOAT)(CenterY( pSoldier->sGridNo ) - CenterY( usMapPos ));
|
|
FLOAT d2DDistance = sqrt((dDeltaX*dDeltaX)+(dDeltaY*dDeltaY));
|
|
|
|
CalcMagFactorSimple( pSoldier, d2DDistance, pSoldier->aiData.bShownAimTime, usMapPos );
|
|
}
|
|
|
|
pSoldier->bTargetLevel = bTempTargetLevel;
|
|
|
|
if(UsingNewCTHSystem() == false && gGameSettings.fOptions[ TOPTION_CTH_CURSOR ])
|
|
{
|
|
gfUICtHBar = TRUE;
|
|
gbCtHBurstCount = 1;
|
|
gbCtH[0] = (gbCtH[0]+uiHitChance)/2;
|
|
}
|
|
}
|
|
switchVal = pSoldier->aiData.bShownAimTime;
|
|
|
|
switch( switchVal )
|
|
{
|
|
case REFINE_AIM_1:
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW1_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM1_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT1_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW1_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM1_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT1_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_2:
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW2_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM3_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT2_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW2_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM3_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT2_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_3:
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW3_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM5_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT3_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW3_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM5_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT3_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_4:
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW4_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM7_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT4_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW4_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM7_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT4_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_5:
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMFULL_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM9_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT5_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMFULL_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM9_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT5_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_MID1:
|
|
|
|
//usCursor = ACTION_TARGETAIM2_UICURSOR;
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW1_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM2_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT1_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW1_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM2_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT1_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case REFINE_AIM_MID2:
|
|
|
|
//usCursor = ACTION_TARGETAIM4_UICURSOR;
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW3_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM4_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT3_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW3_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM4_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT3_UICURSOR;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case REFINE_AIM_MID3:
|
|
|
|
//usCursor = ACTION_TARGETAIM6_UICURSOR;
|
|
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMYELLOW4_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM6_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT4_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMYELLOW4_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM6_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT4_UICURSOR;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case REFINE_AIM_MID4:
|
|
//usCursor = ACTION_TARGETAIM8_UICURSOR;
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_THROWAIMFULL_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_THROWAIM8_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_THROWAIMCANT5_UICURSOR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
usCursor = ACTION_TARGETAIMFULL_UICURSOR;
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
usCursor = ACTION_TARGETAIM8_UICURSOR;
|
|
}
|
|
else
|
|
{
|
|
usCursor = ACTION_TARGETAIMCANT5_UICURSOR;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !fMaxPointLimitHit )
|
|
{
|
|
// Remove flash flag!
|
|
RemoveCursorFlags( gUICursors[ usCursor ].usFreeCursorName, CURSOR_TO_FLASH );
|
|
RemoveCursorFlags( gUICursors[ usCursor ].usFreeCursorName, CURSOR_TO_PLAY_SOUND );
|
|
|
|
if ( gfCannotGetThrough )
|
|
{
|
|
SetCursorSpecialFrame( gUICursors[ usCursor ].usFreeCursorName, 1 );
|
|
}
|
|
else
|
|
{
|
|
if ( !InRange( pSoldier, usMapPos ) )
|
|
{
|
|
// OK, make buddy flash!
|
|
SetCursorFlags( gUICursors[ usCursor ].usFreeCursorName, CURSOR_TO_FLASH );
|
|
SetCursorFlags( gUICursors[ usCursor ].usFreeCursorName, CURSOR_TO_PLAY_SOUND );
|
|
}
|
|
else
|
|
{
|
|
SetCursorSpecialFrame( gUICursors[ usCursor ].usFreeCursorName, 0 );
|
|
}
|
|
}
|
|
}
|
|
return( (UINT8)usCursor );
|
|
}
|
|
|
|
|
|
|
|
// WANNE: Shows the target cursor if we are not hovering over an enemy soldier
|
|
UINT8 HandleNonActivatedTargetCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos , BOOLEAN fShowAPs, BOOLEAN fRecalc, UINT32 uiCursorFlags )
|
|
{
|
|
UINT16 usInHand;
|
|
|
|
usInHand = pSoldier->inv[ HANDPOS ].usItem;
|
|
|
|
if ( Item[ usInHand ].usItemClass != IC_THROWING_KNIFE )
|
|
{
|
|
if (( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
//DetermineCursorBodyLocation( (UINT8)gusSelectedSoldier, FALSE, fRecalc );
|
|
DetermineCursorBodyLocation( (UINT8)gusSelectedSoldier, fShowAPs, fRecalc );
|
|
|
|
if ( pSoldier->flags.fReloading || pSoldier->flags.fPauseAim )
|
|
{
|
|
return( ACTION_TARGET_RELOADING );
|
|
}
|
|
}
|
|
|
|
//CHRISL: We need to only check the second hand if the weapon in the second hand is onehanded
|
|
// Check for enough ammo...
|
|
if ( !EnoughAmmo( pSoldier, FALSE, HANDPOS ) || (pSoldier->IsValidSecondHandShotForReloadingPurposes( ) && !EnoughAmmo( pSoldier, FALSE, SECONDHANDPOS) && !Item[pSoldier->inv[SECONDHANDPOS].usItem].twohanded ) )
|
|
{
|
|
// Check if ANY ammo exists.....
|
|
if ( FindAmmoToReload( pSoldier, HANDPOS, NO_SLOT ) == NO_SLOT )
|
|
{
|
|
// OK, use BAD reload cursor.....
|
|
return( BAD_RELOAD_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
// Check APs to reload...
|
|
gsCurrentActionPoints = GetAPsToAutoReload( pSoldier );
|
|
|
|
gfUIDisplayActionPoints = TRUE;
|
|
//gUIDisplayActionPointsOffX = 14;
|
|
//gUIDisplayActionPointsOffY = 7;
|
|
|
|
// OK, use GOOD reload cursor.....
|
|
return( GOOD_RELOAD_UICURSOR );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
DetermineCursorBodyLocation( (UINT8)gusSelectedSoldier, fShowAPs, fRecalc );
|
|
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
if ( fShowAPs )
|
|
{
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//gfUIDisplayActionPointsBlack = TRUE;
|
|
gfUIDisplayActionPoints = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if(gusUIFullTargetID == NOBODY && pSoldier->bDoAutofire && !pSoldier->flags.fDoSpread) //reset autofire if we move the mouse off the target, however don't reset it if we are spread-bursting
|
|
{
|
|
if(gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ))
|
|
{
|
|
pSoldier->bDoAutofire = 1;
|
|
// sevenfm: init autofire bullet num next time when the cursor will be on target
|
|
gfAutofireInitBulletNum = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->bDoAutofire = 6;
|
|
}
|
|
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
}
|
|
|
|
//if ( gTacticalStatus.uiFlags & TURNBASED && !(gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if ( fRecalc )
|
|
{
|
|
if ( SoldierToLocationChanceToGetThrough( pSoldier, usMapPos, (INT8) gsInterfaceLevel, pSoldier->bTargetCubeLevel, NOBODY ) < OK_CHANCE_TO_GET_THROUGH )
|
|
{
|
|
gfCannotGetThrough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gfCannotGetThrough = FALSE;
|
|
}
|
|
}
|
|
|
|
// OK, if we begin to move, reset the cursor...
|
|
if ( uiCursorFlags & MOUSE_MOVING )
|
|
{
|
|
gfCannotGetThrough = FALSE;
|
|
}
|
|
|
|
if ( gfCannotGetThrough )
|
|
{
|
|
if ( pSoldier->bDoBurst )
|
|
{
|
|
return( ACTION_NOCHANCE_BURST_UICURSOR );
|
|
}
|
|
else if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
return( BAD_THROW_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( ACTION_NOCHANCE_SHOOT_UICURSOR );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Determine if good range
|
|
if ( !InRange( pSoldier, usMapPos ) )
|
|
{
|
|
// Flash cursor!
|
|
// Check if we're in burst mode!
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
return( FLASH_THROW_UICURSOR );
|
|
}
|
|
else if ( pSoldier->bDoBurst )
|
|
{
|
|
//return( ACTION_FIRSTAID_RED );
|
|
return( ACTION_FLASH_BURST_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
//return( ACTION_FIRSTAID_RED );
|
|
return( ACTION_FLASH_SHOOT_UICURSOR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check if we're in burst mode!
|
|
if ( Item[ usInHand ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
return( GOOD_THROW_UICURSOR );
|
|
}
|
|
else if ( pSoldier->bDoBurst )
|
|
{
|
|
//return( ACTION_FIRSTAID_RED );
|
|
return( ACTION_TARGETBURST_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
//return( ACTION_FIRSTAID_RED );
|
|
return( ACTION_SHOOT_UICURSOR );
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void DetermineCursorBodyLocation( UINT8 ubSoldierID, BOOLEAN fDisplay, BOOLEAN fRecalc )
|
|
{
|
|
INT32 usMapPos;
|
|
SOLDIERTYPE *pTargetSoldier = NULL, *pSoldier;
|
|
UINT16 usFlags;
|
|
INT16 sMouseX, sMouseY, sCellX, sCellY, sScreenX, sScreenY;
|
|
BOOLEAN fOnGuy = FALSE;
|
|
LEVELNODE *pNode;
|
|
|
|
pSoldier = MercPtrs[ ubSoldierID ];
|
|
|
|
if ( gTacticalStatus.ubAttackBusyCount > 0 )
|
|
{
|
|
// ATE: Return if attacker busy count > 0, this
|
|
// helps in RT with re-setting the flag to random...
|
|
return;
|
|
}
|
|
|
|
if ( fRecalc )
|
|
{
|
|
// ALWAYS SET AIM LOCATION TO NOTHING
|
|
pSoldier->bAimShotLocation = AIM_SHOT_RANDOM;
|
|
|
|
if( !GetMouseMapPos( &usMapPos) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Determine which body part it's on
|
|
pNode = GetAnimProfileFlags( usMapPos, &usFlags, &pTargetSoldier, NULL );
|
|
|
|
while( pNode != NULL )
|
|
{
|
|
if ( pTargetSoldier != NULL )
|
|
{
|
|
// ATE: Check their stance - if prone - return!
|
|
if ( gAnimControl[ pTargetSoldier->usAnimState ].ubHeight == ANIM_PRONE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
fOnGuy = TRUE;
|
|
|
|
// Check if we have a half tile profile
|
|
if ( usFlags & TILE_FLAG_NORTH_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
if ( sCellY > (CELL_Y_SIZE / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
// Check if we have a half tile profile
|
|
if ( usFlags & TILE_FLAG_SOUTH_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
if ( sCellY <= (CELL_Y_SIZE / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
// Check if we have a half tile profile
|
|
if ( usFlags & TILE_FLAG_WEST_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
if ( sCellX > (CELL_X_SIZE / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
if ( usFlags & TILE_FLAG_EAST_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
if ( sCellX <= (CELL_X_SIZE / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
if ( usFlags & TILE_FLAG_TOP_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
// Convert these to screen corrdinates
|
|
FromCellToScreenCoordinates( sCellX, sCellY, &sScreenX, &sScreenY );
|
|
|
|
// Check for Below...
|
|
if ( sScreenX > (WORLD_TILE_Y / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
if ( usFlags & TILE_FLAG_BOTTOM_HALF )
|
|
{
|
|
// Check if we are in north half of tile!
|
|
GetMouseXYWithRemainder( &sMouseX, &sMouseY, &sCellX, &sCellY );
|
|
|
|
// Convert these to screen corrdinates
|
|
FromCellToScreenCoordinates( sCellX, sCellY, &sScreenX, &sScreenY );
|
|
|
|
// Check for Below...
|
|
if ( sScreenX <= (WORLD_TILE_Y / 2) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
// Check if mouse is iin bounding box of soldier
|
|
if ( !IsPointInSoldierBoundingBox( pTargetSoldier, gusMouseXPos, gusMouseYPos ) )
|
|
{
|
|
fOnGuy = FALSE;
|
|
}
|
|
}
|
|
|
|
if ( fOnGuy )
|
|
break;
|
|
|
|
pNode = GetAnimProfileFlags( usMapPos, &usFlags, &pTargetSoldier, pNode );
|
|
|
|
}
|
|
|
|
|
|
if ( !fOnGuy )
|
|
{
|
|
// Check if we can find a soldier here
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
pTargetSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
|
|
if ( FindRelativeSoldierPosition( pTargetSoldier, &usFlags, gusMouseXPos, gusMouseYPos ) )
|
|
{
|
|
fOnGuy = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if ( fOnGuy )
|
|
{
|
|
if ( IsValidTargetMerc( pTargetSoldier->ubID ) )
|
|
{
|
|
if ( usFlags & TILE_FLAG_FEET )
|
|
{
|
|
pSoldier->bAimShotLocation = AIM_SHOT_LEGS;
|
|
}
|
|
if ( usFlags & TILE_FLAG_MID )
|
|
{
|
|
pSoldier->bAimShotLocation = AIM_SHOT_TORSO;
|
|
}
|
|
if ( usFlags & TILE_FLAG_HEAD )
|
|
{
|
|
pSoldier->bAimShotLocation = AIM_SHOT_HEAD;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
// HEADROCK HAM B2: Now shows targetted bodypart for ALL firing modes. Note that the external toggle is not
|
|
// taken into account yet.
|
|
// if ( fDisplay && !pSoldier->bDoAutofire )
|
|
if ( fDisplay )
|
|
{
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
pTargetSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
|
|
if ( pTargetSoldier->ubBodyType == CROW )
|
|
{
|
|
pSoldier->bAimShotLocation = AIM_SHOT_LEGS;
|
|
|
|
wcscpy( gzLocation, TacticalStr[ CROW_HIT_LOCATION_STR ] );
|
|
|
|
if ( !pSoldier->bDoBurst )
|
|
gfUIBodyHitLocation = TRUE;
|
|
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
|
|
// CTH cursors.
|
|
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
return;
|
|
}
|
|
|
|
if ( !IS_MERC_BODY_TYPE( pTargetSoldier ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch( pSoldier->bAimShotLocation )
|
|
{
|
|
case AIM_SHOT_HEAD:
|
|
|
|
// If we have a knife in hand, change string
|
|
if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_BLADE )
|
|
{
|
|
wcscpy( gzLocation, TacticalStr[ NECK_HIT_LOCATION_STR ] );
|
|
}
|
|
else
|
|
{
|
|
wcscpy( gzLocation, TacticalStr[ HEAD_HIT_LOCATION_STR ] );
|
|
}
|
|
if ( !pSoldier->bDoBurst )
|
|
gfUIBodyHitLocation = TRUE;
|
|
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
|
|
// CTH cursors.
|
|
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
break;
|
|
|
|
case AIM_SHOT_TORSO:
|
|
wcscpy( gzLocation, TacticalStr[ TORSO_HIT_LOCATION_STR ] );
|
|
if ( !pSoldier->bDoBurst )
|
|
gfUIBodyHitLocation = TRUE;
|
|
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
|
|
// CTH cursors.
|
|
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
break;
|
|
|
|
case AIM_SHOT_LEGS:
|
|
wcscpy( gzLocation, TacticalStr[ LEGS_HIT_LOCATION_STR ] );
|
|
if ( !pSoldier->bDoBurst )
|
|
gfUIBodyHitLocation = TRUE;
|
|
// HEADROCK: This'll toggle whether the bodypart targetting indicator shows up in the burst/auto
|
|
// CTH cursors.
|
|
else if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 2) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
else if ( pSoldier->bDoBurst && pSoldier->bDoAutofire && (gGameExternalOptions.ubNewCTHBars == 1 || gGameExternalOptions.ubNewCTHBars == 3) )
|
|
gfUIBodyHitLocation = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UINT8 HandleKnifeCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
|
{
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
BOOLEAN fEnoughPoints = TRUE;
|
|
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_MERCS );
|
|
|
|
// Flugente: if we are using a bayonet, adjust aimtime
|
|
if ( pSoldier->bWeaponMode == WM_ATTACHED_BAYONET && pSoldier->aiData.bShownAimTime != REFINE_KNIFE_1 )
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2;
|
|
|
|
if ( fActivated )
|
|
{
|
|
DetermineCursorBodyLocation( pSoldier->ubID, TRUE, TRUE );
|
|
|
|
if ( gfUIHandleShowMoveGrid )
|
|
{
|
|
gfUIHandleShowMoveGrid = 2;
|
|
}
|
|
|
|
// Calculate action points
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime == REFINE_KNIFE_1 )
|
|
{
|
|
return( KNIFE_HIT_UICURSOR );
|
|
}
|
|
}
|
|
|
|
// SANDRO - changed this
|
|
bFutureAim = (INT8)( gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2 );
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( !EnoughPoints( pSoldier, (INT16)sAPCosts, 0 , FALSE ) )
|
|
{
|
|
fEnoughPoints = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
if ( !pSoldier->flags.fPauseAim )
|
|
{
|
|
if ( COUNTERDONE( NONGUNTARGETREFINE ) )
|
|
{
|
|
// Reset counter
|
|
RESETCOUNTER( NONGUNTARGETREFINE );
|
|
|
|
if ( pSoldier->aiData.bShownAimTime == REFINE_KNIFE_1 )
|
|
{
|
|
PlayJA2Sample( TARG_REFINE_BEEP, RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// SANDRO - slightly changed the formula here
|
|
if( pSoldier->aiData.bShownAimTime == REFINE_KNIFE_1 )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
return( KNIFE_YELLOW_AIM1_UICURSOR );
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
return( KNIFE_HIT_AIM1_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( KNIFE_NOGO_AIM1_UICURSOR );
|
|
}
|
|
}
|
|
else if( pSoldier->aiData.bShownAimTime == ( gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2 ) )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
return( KNIFE_YELLOW_AIM2_UICURSOR );
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
return( KNIFE_HIT_AIM2_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( KNIFE_NOGO_AIM2_UICURSOR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert( FALSE );
|
|
// no return value!
|
|
return(0);
|
|
}
|
|
//////////////////////////////////////////////////////////////
|
|
}
|
|
else
|
|
{
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// CHECK IF WE ARE ON A GUY ( THAT'S NOT SELECTED )!
|
|
if ( gfUIFullTargetFound && !( guiUIFullTargetFlags & SELECTED_MERC ) )
|
|
{
|
|
DetermineCursorBodyLocation( pSoldier->ubID, TRUE, TRUE );
|
|
return( KNIFE_HIT_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( KNIFE_REG_UICURSOR );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
UINT8 HandlePunchCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
|
{
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
BOOLEAN fEnoughPoints = TRUE;
|
|
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_MERCS );
|
|
|
|
if ( fActivated )
|
|
{
|
|
DetermineCursorBodyLocation( pSoldier->ubID, TRUE, TRUE );
|
|
|
|
if ( gfUIHandleShowMoveGrid )
|
|
{
|
|
gfUIHandleShowMoveGrid = 2;
|
|
}
|
|
|
|
// Calculate action points
|
|
if ( gTacticalStatus.uiFlags & TURNBASED )
|
|
{
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime == REFINE_PUNCH_1 )
|
|
{
|
|
return( ACTION_PUNCH_RED );
|
|
}
|
|
}
|
|
|
|
bFutureAim = (INT8)( REFINE_PUNCH_2 );
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( !EnoughPoints( pSoldier, (INT16)sAPCosts, 0 , FALSE ) )
|
|
{
|
|
fEnoughPoints = FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ( ( gTacticalStatus.uiFlags & REALTIME ) || !( gTacticalStatus.uiFlags & INCOMBAT ) ) )
|
|
{
|
|
if ( !pSoldier->flags.fPauseAim )
|
|
{
|
|
if ( COUNTERDONE( NONGUNTARGETREFINE ) )
|
|
{
|
|
// Reset counter
|
|
RESETCOUNTER( NONGUNTARGETREFINE );
|
|
|
|
if ( pSoldier->aiData.bShownAimTime == REFINE_PUNCH_1 )
|
|
{
|
|
PlayJA2Sample( TARG_REFINE_BEEP, RATE_11025, MIDVOLUME, 1, MIDDLEPAN );
|
|
}
|
|
|
|
// SANDRO - make aimed punch less expensive for APS
|
|
pSoldier->aiData.bShownAimTime = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// SANDRO - slightly changed the formula here
|
|
if( pSoldier->aiData.bShownAimTime == REFINE_PUNCH_1)
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
return( ACTION_PUNCH_YELLOW_AIM1_UICURSOR );
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
return( ACTION_PUNCH_RED_AIM1_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( ACTION_PUNCH_NOGO_AIM1_UICURSOR );
|
|
}
|
|
}
|
|
else if ( pSoldier->aiData.bShownAimTime == (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2) )
|
|
{
|
|
if ( gfDisplayFullCountRing )
|
|
{
|
|
return( ACTION_PUNCH_YELLOW_AIM2_UICURSOR );
|
|
}
|
|
else if ( fEnoughPoints )
|
|
{
|
|
return( ACTION_PUNCH_RED_AIM2_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( ACTION_PUNCH_NOGO_AIM2_UICURSOR );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Assert( FALSE );
|
|
// no return value!
|
|
return(0);
|
|
}
|
|
//////////////////////////////////////////////////////////////
|
|
}
|
|
else
|
|
{
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// CHECK IF WE ARE ON A GUY ( THAT'S NOT SELECTED )!
|
|
if ( gfUIFullTargetFound && !( guiUIFullTargetFlags & SELECTED_MERC ) )
|
|
{
|
|
DetermineCursorBodyLocation( pSoldier->ubID, TRUE, TRUE );
|
|
return( ACTION_PUNCH_RED );
|
|
}
|
|
else
|
|
{
|
|
return( ACTION_PUNCH_GRAY );
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT8 HandleAidCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_MERCSFORAID );
|
|
|
|
if ( fActivated )
|
|
{
|
|
return( ACTION_FIRSTAID_RED );
|
|
}
|
|
else
|
|
{
|
|
// CHECK IF WE ARE ON A GUY ( THAT'S NOT SELECTED )!
|
|
if ( gfUIFullTargetFound ) // && !( guiUIFullTargetFlags & SELECTED_MERC ) )
|
|
{
|
|
return( ACTION_FIRSTAID_RED );
|
|
}
|
|
else
|
|
{
|
|
return( ACTION_FIRSTAID_GRAY );
|
|
}
|
|
}
|
|
}
|
|
|
|
UINT8 HandleActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT8 ubItemCursor )
|
|
{
|
|
return( ACTION_TOSS_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleNonActivatedTossCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fRecalc, UINT32 uiCursorFlags, UINT8 ubItemCursor )
|
|
{
|
|
INT32 sFinalGridNo;
|
|
static BOOLEAN fBadCTGH = FALSE;
|
|
BOOLEAN fArmed = FALSE;
|
|
INT8 bLevel;
|
|
OBJECTTYPE * pObj;
|
|
|
|
// Check for enough ammo...
|
|
if ( ubItemCursor == TRAJECTORYCURS )
|
|
{
|
|
fArmed = TRUE;
|
|
|
|
if ( !EnoughAmmo( pSoldier, FALSE, HANDPOS ) )
|
|
{
|
|
// Check if ANY ammo exists.....
|
|
if ( FindAmmoToReload( pSoldier, HANDPOS, NO_SLOT ) == NO_SLOT )
|
|
{
|
|
// OK, use BAD reload cursor.....
|
|
return( BAD_RELOAD_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
// Check APs to reload...
|
|
gsCurrentActionPoints = GetAPsToAutoReload( pSoldier );
|
|
|
|
gfUIDisplayActionPoints = TRUE;
|
|
//gUIDisplayActionPointsOffX = 14;
|
|
//gUIDisplayActionPointsOffY = 7;
|
|
|
|
// OK, use GOOD reload cursor.....
|
|
return( GOOD_RELOAD_UICURSOR );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add APs....
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && ( gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
if ( ubItemCursor == TRAJECTORYCURS )
|
|
{
|
|
gsCurrentActionPoints = CalcTotalAPsToAttack( pSoldier, sGridNo, TRUE, (INT8)(pSoldier->aiData.bShownAimTime ) );
|
|
}
|
|
else
|
|
{
|
|
gsCurrentActionPoints = MinAPsToThrow( pSoldier, sGridNo, TRUE );
|
|
}
|
|
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
// OK, if we begin to move, reset the cursor...
|
|
if ( uiCursorFlags & MOUSE_MOVING )
|
|
{
|
|
EndPhysicsTrajectoryUI( );
|
|
}
|
|
|
|
gfUIHandlePhysicsTrajectory = TRUE;
|
|
|
|
if ( fRecalc )
|
|
{
|
|
// Calculate chance to throw here.....
|
|
if ( sGridNo == pSoldier->sGridNo )
|
|
{
|
|
fBadCTGH = FALSE;
|
|
}
|
|
else
|
|
{
|
|
UINT16 glItem = GetAttachedGrenadeLauncher( &(pSoldier->inv[HANDPOS]));
|
|
if ((pSoldier->bWeaponMode == WM_ATTACHED_GL || pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO )&& glItem != NONE )
|
|
{
|
|
OBJECTTYPE* pAttachment = FindAttachment( &(pSoldier->inv[HANDPOS]), glItem );
|
|
|
|
if ( pAttachment )
|
|
{
|
|
if ( !CalculateLaunchItemChanceToGetThrough( pSoldier, pAttachment, sGridNo, (INT8)gsInterfaceLevel, (INT16)( gsInterfaceLevel * 256 ), &sFinalGridNo, fArmed, &bLevel, TRUE ) )
|
|
{
|
|
fBadCTGH = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fBadCTGH = FALSE;
|
|
}
|
|
BeginPhysicsTrajectoryUI( sFinalGridNo, bLevel, fBadCTGH );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OBJECTTYPE* pObject = &(pSoldier->inv[HANDPOS]);
|
|
// Do we have a launcable?
|
|
pObj = &(pSoldier->inv[HANDPOS]);
|
|
//sevenfm this should be checked only for guns because we can throw items with attached explosives
|
|
if(Item[pObj->usItem].usItemClass & IC_WEAPON )
|
|
for (attachmentList::iterator iter = (*pObj)[0]->attachments.begin(); iter != (*pObj)[0]->attachments.end(); ++iter) {
|
|
if ( Item[ iter->usItem ].usItemClass & IC_EXPLOSV && iter->exists())
|
|
{
|
|
pObject = &(*iter);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !CalculateLaunchItemChanceToGetThrough( pSoldier, pObject, sGridNo, (INT8)gsInterfaceLevel, (INT16)( gsInterfaceLevel * 256 ), &sFinalGridNo, fArmed, &bLevel, TRUE ) )
|
|
{
|
|
fBadCTGH = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fBadCTGH = FALSE;
|
|
}
|
|
BeginPhysicsTrajectoryUI( sFinalGridNo, bLevel, fBadCTGH );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fBadCTGH )
|
|
{
|
|
return( BAD_THROW_UICURSOR );
|
|
}
|
|
return( GOOD_THROW_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleWirecutterCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_WIREFENCE );
|
|
|
|
// Are we over a cuttable fence?
|
|
if ( IsCuttableWireFenceAtGridNo( sGridNo ) && pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
return( GOOD_WIRECUTTER_UICURSOR );
|
|
}
|
|
|
|
return( BAD_WIRECUTTER_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleRepairCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_REPAIR );
|
|
|
|
// Are we over a cuttable fence?
|
|
if ( IsRepairableStructAtGridNo( sGridNo, NULL ) && pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
return( GOOD_REPAIR_UICURSOR );
|
|
}
|
|
|
|
return( BAD_REPAIR_UICURSOR );
|
|
}
|
|
|
|
UINT8 HandleRefuelCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_REFUEL );
|
|
|
|
// Are we over a cuttable fence?
|
|
if ( IsRefuelableStructAtGridNo( sGridNo, NULL ) && pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
return( REFUEL_RED_UICURSOR );
|
|
}
|
|
|
|
return( REFUEL_GREY_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleJarCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_JAR );
|
|
|
|
// Are we over a cuttable fence?
|
|
if ( IsCorpseAtGridNo( sGridNo, pSoldier->pathing.bLevel ) )
|
|
{
|
|
return( GOOD_JAR_UICURSOR );
|
|
}
|
|
|
|
return( BAD_JAR_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleTinCanCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
STRUCTURE *pStructure;
|
|
INT32 sIntTileGridNo;
|
|
LEVELNODE *pIntTile;
|
|
|
|
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_CAN );
|
|
|
|
// Check if a door exists here.....
|
|
pIntTile = GetCurInteractiveTileGridNoAndStructure( &sIntTileGridNo, &pStructure );
|
|
|
|
// We should not have null here if we are given this flag...
|
|
if ( pIntTile != NULL )
|
|
{
|
|
if (pStructure->fFlags & STRUCTURE_ANYDOOR)
|
|
{
|
|
return( PLACE_TINCAN_GREY_UICURSOR );
|
|
}
|
|
}
|
|
|
|
return( PLACE_TINCAN_RED_UICURSOR );
|
|
}
|
|
|
|
|
|
UINT8 HandleRemoteCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
|
{
|
|
|
|
// Calculate action points
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
gsCurrentActionPoints = GetAPsToUseRemote( pSoldier );
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( fActivated )
|
|
{
|
|
return( PLACE_REMOTE_RED_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( PLACE_REMOTE_GREY_UICURSOR );
|
|
}
|
|
}
|
|
|
|
|
|
UINT8 HandleBombCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, BOOLEAN fActivated, UINT32 uiCursorFlags )
|
|
{
|
|
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_BOMB );
|
|
|
|
// Calculate action points
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT) )
|
|
{
|
|
gsCurrentActionPoints = GetTotalAPsToDropBomb( pSoldier, sGridNo );
|
|
gfUIDisplayActionPoints = TRUE;
|
|
gfUIDisplayActionPointsCenter = TRUE;
|
|
|
|
// If we don't have any points and we are at the first refine, do nothing but warn!
|
|
if ( !EnoughPoints( pSoldier, gsCurrentActionPoints, 0 , FALSE ) )
|
|
{
|
|
gfUIDisplayActionPointsInvalid = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( fActivated )
|
|
{
|
|
return( PLACE_BOMB_RED_UICURSOR );
|
|
}
|
|
else
|
|
{
|
|
return( PLACE_BOMB_GREY_UICURSOR );
|
|
}
|
|
}
|
|
|
|
UINT8 HandleFortificationCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_FORTIFICATION );
|
|
|
|
if ( pSoldier->pathing.bLevel != 0 )
|
|
return( FORTIFICATION_RED_UICURSOR );
|
|
|
|
if ( IsFortificationPossibleAtGridNo( sGridNo ) && IsStructureConstructItem( pSoldier->inv[HANDPOS].usItem, sGridNo, pSoldier ) )
|
|
{
|
|
return( FORTIFICATION_GREY_UICURSOR );
|
|
}
|
|
else if ( IsStructureDeconstructItem( pSoldier->inv[HANDPOS].usItem, sGridNo, pSoldier ) )
|
|
{
|
|
STRUCTURE* pStruct = FindStructure( sGridNo, (STRUCTURE_GENERIC | STRUCTURE_WIREFENCE));
|
|
|
|
if ( pStruct )
|
|
{
|
|
return(FORTIFICATION_GREY_UICURSOR);
|
|
}
|
|
}
|
|
|
|
return( FORTIFICATION_RED_UICURSOR );
|
|
}
|
|
|
|
UINT8 HandleHandcuffCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_HANDCUFF );
|
|
|
|
// do we have handcuffs in our hand?
|
|
if ( HasItemFlag( (&(pSoldier->inv[HANDPOS]))->usItem, HANDCUFFS ) )
|
|
{
|
|
// is there a person here?
|
|
UINT8 usSoldierIndex = WhoIsThere2( sGridNo, pSoldier->pathing.bLevel );
|
|
if ( usSoldierIndex != NOBODY && MercPtrs[usSoldierIndex]->CanBeCaptured( ) )
|
|
{
|
|
return( HANDCUFF_GREY_UICURSOR );
|
|
}
|
|
}
|
|
|
|
return( HANDCUFF_RED_UICURSOR );
|
|
}
|
|
|
|
UINT8 HandleApplyItemCursor( SOLDIERTYPE *pSoldier, INT32 sGridNo, UINT32 uiCursorFlags )
|
|
{
|
|
// DRAW PATH TO GUY
|
|
HandleUIMovementCursor( pSoldier, uiCursorFlags, sGridNo, MOVEUI_TARGET_APPLYITEM );
|
|
|
|
if ( ItemCanBeAppliedToOthers( (&(pSoldier->inv[HANDPOS]))->usItem ) )
|
|
{
|
|
// is there a person here?
|
|
UINT8 usSoldierIndex = WhoIsThere2( sGridNo, pSoldier->pathing.bLevel );
|
|
if ( usSoldierIndex != NOBODY )
|
|
{
|
|
return( APPLYITEM_GREY_UICURSOR );
|
|
}
|
|
}
|
|
|
|
return( APPLYITEM_RED_UICURSOR );
|
|
}
|
|
|
|
void HandleEndConfirmCursor( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT16 usInHand;
|
|
UINT8 ubItemCursor;
|
|
|
|
// LOOK IN GUY'S HAND TO CHECK LOCATION
|
|
usInHand = pSoldier->inv[HANDPOS].usItem;
|
|
|
|
ubItemCursor = GetActionModeCursor( pSoldier );
|
|
|
|
if ( ubItemCursor == TOSSCURS )
|
|
{
|
|
// EndAimCubeUI( );
|
|
}
|
|
}
|
|
|
|
void HandleLeftClickCursor( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT16 usInHand;
|
|
UINT8 ubItemCursor;
|
|
INT32 usGridNo;
|
|
|
|
// LOOK IN GUY'S HAND TO CHECK LOCATION
|
|
usInHand = pSoldier->inv[HANDPOS].usItem;
|
|
|
|
ubItemCursor = GetActionModeCursor( pSoldier );
|
|
|
|
// OK, if we are i realtime.. goto directly to shoot
|
|
if ( ( ( gTacticalStatus.uiFlags & TURNBASED ) && !( gTacticalStatus.uiFlags & INCOMBAT ) ) )//&& ubItemCursor != TOSSCURS && ubItemCursor != TRAJECTORYCURS )
|
|
{
|
|
// GOTO DIRECTLY TO USING ITEM
|
|
// ( only if not burst mode.. )
|
|
if ( !pSoldier->bDoBurst )
|
|
{
|
|
guiPendingOverrideEvent = CA_MERC_SHOOT;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!GetMouseMapPos( &usGridNo ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
gfUIForceReExamineCursorData = TRUE;
|
|
|
|
gfDisplayFullCountRing = FALSE;
|
|
|
|
switch( ubItemCursor )
|
|
{
|
|
case TARGETCURS:
|
|
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
}
|
|
// Reset counter
|
|
RESETCOUNTER( TARGETREFINE );
|
|
break;
|
|
|
|
case PUNCHCURS:
|
|
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
|
|
}
|
|
// Reset counter
|
|
RESETCOUNTER( NONGUNTARGETREFINE );
|
|
break;
|
|
|
|
|
|
case KNIFECURS:
|
|
|
|
if ( gTacticalStatus.uiFlags & TURNBASED && (gTacticalStatus.uiFlags & INCOMBAT ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
pSoldier->flags.fPauseAim = FALSE;
|
|
|
|
}
|
|
// Reset counter
|
|
RESETCOUNTER( NONGUNTARGETREFINE );
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
|
|
//BeginAimCubeUI( pSoldier, sGridNo, (INT8)gsInterfaceLevel, 0, 0 );
|
|
//break;
|
|
|
|
default:
|
|
|
|
// GOTO DIRECTLY TO USING ITEM
|
|
guiPendingOverrideEvent = CA_MERC_SHOOT;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HandleRightClickAdjustCursor( SOLDIERTYPE *pSoldier, INT32 usMapPos )
|
|
{
|
|
UINT16 usInHand;
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
UINT8 ubCursor;
|
|
SOLDIERTYPE *pTSoldier;
|
|
INT32 sGridNo;
|
|
INT8 bTargetLevel;
|
|
// SANDRO - added these two
|
|
INT8 bAimTimeAddedForPunch = 2;
|
|
INT8 bAimTimeAddedForKnife = 2;
|
|
|
|
|
|
usInHand = pSoldier->inv[HANDPOS].usItem;
|
|
|
|
ubCursor = GetActionModeCursor( pSoldier );
|
|
|
|
// HEADROCK HAM 4: Required for new Aiming Level Limit function
|
|
UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, usMapPos);
|
|
|
|
// 'snap' cursor to target tile....
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
usMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
}
|
|
|
|
|
|
switch( ubCursor )
|
|
{
|
|
case TARGETCURS:
|
|
|
|
// CHECK IF GUY HAS IN HAND A WEAPON
|
|
if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire && !gGameExternalOptions.bAimedBurstEnabled)
|
|
{
|
|
// Do nothing for aimed burst deactivated
|
|
// pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST;
|
|
}
|
|
else if(pSoldier->bDoAutofire)
|
|
{
|
|
// aiming in auto mode using hotkey for mousewheel not working
|
|
if( gfKeyState[ COMMA ] && gGameExternalOptions.bAimedBurstEnabled )
|
|
{
|
|
sGridNo = usMapPos;
|
|
bTargetLevel = (INT8)gsInterfaceLevel;
|
|
|
|
// Look for a target here...
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
// Get target soldier, if one exists
|
|
pTSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
sGridNo = pTSoldier->sGridNo;
|
|
bTargetLevel = pSoldier->pathing.bLevel;
|
|
|
|
if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + 1 );
|
|
|
|
if ( bFutureAim <= maxAimLevels )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim ) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= 1;
|
|
if ( pSoldier->aiData.bShownAimTime > maxAimLevels )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = maxAimLevels;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
// adjust number of bullets in auto mode
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
pSoldier->bDoAutofire = 1; //reset the bullet counter
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
return;
|
|
}
|
|
|
|
|
|
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 && 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);
|
|
}
|
|
|
|
//we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets
|
|
|
|
sCurAPCosts = sAPCosts;
|
|
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire++;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
}
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
|
|
if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets
|
|
{
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false
|
|
}
|
|
else
|
|
{
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
}
|
|
}
|
|
}
|
|
// single fire mode
|
|
else
|
|
{
|
|
sGridNo = usMapPos;
|
|
bTargetLevel = (INT8)gsInterfaceLevel;
|
|
|
|
// Look for a target here...
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
// Get target soldier, if one exists
|
|
pTSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
sGridNo = pTSoldier->sGridNo;
|
|
bTargetLevel = pSoldier->pathing.bLevel;
|
|
|
|
if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + 1 );
|
|
|
|
if ( bFutureAim <= maxAimLevels )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim ) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= 1;
|
|
if ( pSoldier->aiData.bShownAimTime > maxAimLevels )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = maxAimLevels;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_AIM_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case PUNCHCURS:
|
|
|
|
// SANDRO - changed the formula here to make aimed punch less expensive for APS
|
|
bAimTimeAddedForPunch = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedPunches : REFINE_PUNCH_2);
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + bAimTimeAddedForPunch );
|
|
|
|
if ( bFutureAim <= bAimTimeAddedForPunch )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= bAimTimeAddedForPunch;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime > bAimTimeAddedForPunch )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = bAimTimeAddedForPunch;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case KNIFECURS:
|
|
|
|
// SANDRO - changed the formula here to make aimed blade attack less expensive for APS
|
|
bAimTimeAddedForKnife = (gGameExternalOptions.fEnhancedCloseCombatSystem ? gSkillTraitValues.ubModifierForAPsAddedOnAimedBladedAttackes : REFINE_KNIFE_2);
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + bAimTimeAddedForKnife );
|
|
|
|
if ( bFutureAim <= bAimTimeAddedForKnife )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= bAimTimeAddedForKnife;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime > bAimTimeAddedForKnife )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = bAimTimeAddedForKnife;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
|
|
//IncrementAimCubeUI( );
|
|
break;
|
|
|
|
default:
|
|
|
|
ErasePath( TRUE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
UINT8 GetActionModeCursor( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT8 ubCursor;
|
|
UINT16 usInHand;
|
|
|
|
// If we are an EPC, do nothing....
|
|
//if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) )
|
|
//{
|
|
// return( INVALIDCURS );
|
|
//}
|
|
|
|
// AN EPC is always not - attackable unless they are a robot!
|
|
if ( AM_AN_EPC( pSoldier ) && !( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT ) )
|
|
{
|
|
return( INVALIDCURS );
|
|
}
|
|
|
|
// ATE: if a vehicle.... same thing
|
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
|
|
{
|
|
return( INVALIDCURS );
|
|
}
|
|
|
|
// If we can't be controlled, returninvalid...
|
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_ROBOT )
|
|
{
|
|
if ( !pSoldier->CanRobotBeControlled( ) )
|
|
{
|
|
// Display message that robot cannot be controlled....
|
|
return( INVALIDCURS );
|
|
}
|
|
}
|
|
|
|
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL )
|
|
{
|
|
// Flugente: if using a rifle grenade, only allow firing if there is a bullet in the gun's magazine (required for firing)
|
|
if ( HasAttachmentOfClass( &(pSoldier->inv[HANDPOS]), AC_RIFLEGRENADE) )
|
|
{
|
|
OBJECTTYPE* pObj = &(pSoldier->inv[HANDPOS]);
|
|
if ( (*pObj)[0]->data.gun.ubGunShotsLeft> 0 )
|
|
return( TRAJECTORYCURS );
|
|
else
|
|
return( INVALIDCURS );
|
|
}
|
|
|
|
return( TRAJECTORYCURS );
|
|
}
|
|
|
|
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST || ( pSoldier->bWeaponMode == WM_BURST && Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher ) )
|
|
{
|
|
if ( gGameSettings.fOptions [ TOPTION_GL_BURST_CURSOR ] )
|
|
return( TARGETCURS );
|
|
else
|
|
return ( TRAJECTORYCURS );
|
|
}
|
|
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_AUTO || ( pSoldier->bWeaponMode == WM_AUTOFIRE && Item[pSoldier->inv[HANDPOS].usItem].grenadelauncher ) )
|
|
{
|
|
if ( gGameSettings.fOptions [ TOPTION_GL_BURST_CURSOR ] )
|
|
return( TARGETCURS );
|
|
else
|
|
return ( TRAJECTORYCURS );
|
|
}
|
|
|
|
usInHand = pSoldier->GetUsedWeaponNumber( &pSoldier->inv[HANDPOS] );
|
|
// Start off with what is in our hand
|
|
ubCursor = Item[ usInHand ].ubCursor;
|
|
|
|
// OK, check if what is in our hands has a detonator attachment...
|
|
// Detonators can only be on invalidcurs things...
|
|
if ( ubCursor == INVALIDCURS )
|
|
{
|
|
if ( HasAttachmentOfClass( &(pSoldier->inv[HANDPOS]), AC_DETONATOR ) )
|
|
{
|
|
ubCursor = BOMBCURS;
|
|
}
|
|
else if ( HasAttachmentOfClass( &(pSoldier->inv[HANDPOS]), AC_REMOTEDET ) )
|
|
{
|
|
ubCursor = BOMBCURS;
|
|
}
|
|
else if ( HasAttachmentOfClass( &(pSoldier->inv[HANDPOS]), AC_DEFUSE) )
|
|
{
|
|
ubCursor = BOMBCURS;
|
|
}
|
|
}
|
|
|
|
// Flugente: cursor for constructing/deconstructing
|
|
// at the moment the gridno is not required in these functions, thus 1 suffices
|
|
if ( IsStructureConstructItem( usInHand, 1, pSoldier ) || IsStructureDeconstructItem( usInHand, 1, pSoldier ) )
|
|
ubCursor = FORTICURS;
|
|
|
|
// Flugente: cursor for handcuffs
|
|
if ( gGameExternalOptions.fAllowPrisonerSystem && HasItemFlag(usInHand, HANDCUFFS) )
|
|
ubCursor = HANDCUFFCURS;
|
|
|
|
// Flugente: apply misc items to other soldiers
|
|
if ( ItemCanBeAppliedToOthers( usInHand ) )
|
|
{
|
|
// if item is a bomb, only allow apply if hovering over a soldier (otherwise we cannot mine anymore)
|
|
if ( Item[ usInHand ].usItemClass & IC_BOMB )
|
|
{
|
|
INT32 usMapPos = NOWHERE;
|
|
if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
// is there a person here?
|
|
if ( WhoIsThere2( usMapPos, pSoldier->pathing.bLevel ) != NOBODY )
|
|
ubCursor = APPLYITEMCURS;
|
|
}
|
|
}
|
|
else
|
|
ubCursor = APPLYITEMCURS;
|
|
}
|
|
|
|
// WANNE.WATER: Allow shooting if we are on a "water" tile, but on level > 0
|
|
// Now check our terrain to see if we cannot do the action now...
|
|
if ( WaterTooDeepForAttacks( pSoldier->sGridNo) && pSoldier->pathing.bLevel == 0 )
|
|
{
|
|
ubCursor = INVALIDCURS;
|
|
}
|
|
|
|
// If we are out of breath, no cursor...
|
|
if ( pSoldier->bBreath < OKBREATH && pSoldier->bCollapsed )
|
|
{
|
|
ubCursor = INVALIDCURS;
|
|
}
|
|
|
|
return( ubCursor );
|
|
}
|
|
|
|
// Switch on item, display appropriate feedback cursor for a click....
|
|
void HandleUICursorRTFeedback( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT8 ubItemCursor;
|
|
|
|
ubItemCursor = GetActionModeCursor( pSoldier );
|
|
|
|
switch( ubItemCursor )
|
|
{
|
|
case TARGETCURS:
|
|
|
|
if ( pSoldier->bDoBurst )
|
|
{
|
|
//BeginDisplayTimedCursor( ACTION_TARGETREDBURST_UICURSOR, 500 );
|
|
}
|
|
else
|
|
{
|
|
if ( Item[ pSoldier->inv[ HANDPOS ].usItem ].usItemClass == IC_THROWING_KNIFE )
|
|
{
|
|
BeginDisplayTimedCursor( RED_THROW_UICURSOR, 500 );
|
|
}
|
|
else
|
|
{
|
|
BeginDisplayTimedCursor( ACTION_TARGETRED_UICURSOR, 500 );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* good code from lesh
|
|
BOOLEAN CanSoldierAffordAimTime( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bAimTime )
|
|
{
|
|
INT8 maxAimLevels;
|
|
INT16 sAPCosts;
|
|
|
|
maxAimLevels = AllowedAimingLevels(pSoldier);
|
|
|
|
if ( bAimTime < REFINE_AIM_1 || bAimTime > maxAimLevels )
|
|
return FALSE;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bAimTime );
|
|
|
|
if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN CanSoldierAffordPunching( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bRefineTime )
|
|
{
|
|
INT16 sAPCosts;
|
|
|
|
if ( bRefineTime < REFINE_PUNCH_1 || bRefineTime > REFINE_PUNCH_2 )
|
|
return FALSE;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bRefineTime );
|
|
|
|
if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN CanSoldierAffordKnifing( SOLDIERTYPE *pSoldier, INT16 usMapPos, INT8 bRefineTime )
|
|
{
|
|
INT16 sAPCosts;
|
|
|
|
if ( bRefineTime < REFINE_KNIFE_1 || bRefineTime > REFINE_KNIFE_2 )
|
|
return FALSE;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, bRefineTime );
|
|
|
|
if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN CanSoldierAffordBurstBullets( SOLDIERTYPE *pSoldier, INT16 usMapPos )
|
|
{
|
|
INT16 sAPCosts;
|
|
INT8 bSaveDoAutofire;
|
|
|
|
if ( pSoldier->bDoAutofire < 1 )
|
|
{
|
|
pSoldier->bDoAutofire = 1;
|
|
return FALSE;
|
|
}
|
|
|
|
if ( pSoldier->bDoAutofire > pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft )
|
|
{
|
|
pSoldier->bDoAutofire = pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft;
|
|
return FALSE;
|
|
}
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, usMapPos, TRUE, 0);
|
|
|
|
if ( !EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, INT16 sDelta )
|
|
{
|
|
UINT8 ubCursor;
|
|
INT8 bFutureAim;
|
|
|
|
ubCursor = GetActionModeCursor( pSoldier );
|
|
|
|
// 'snap' cursor to target tile....
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
}
|
|
|
|
switch( ubCursor )
|
|
{
|
|
case TARGETCURS:
|
|
// warn if bad chance to get through
|
|
if ( gfUIFullTargetFound &&
|
|
!HandleCheckForBadChangeToGetThrough( pSoldier, MercPtrs[ gusUIFullTargetID ],
|
|
MercPtrs[ gusUIFullTargetID ]->sGridNo , MercPtrs[ gusUIFullTargetID ]->pathing.bLevel ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire )
|
|
{
|
|
}
|
|
else if( pSoldier->bDoAutofire )
|
|
{
|
|
// AUTOFIRE section
|
|
INT16 sCurAPCosts, sFutureAPCost;
|
|
|
|
if(pSoldier->flags.autofireLastStep)
|
|
{
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
}
|
|
|
|
// change burst length until AP difference is shown
|
|
sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire += sDelta;
|
|
sFutureAPCost = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
} while ( CanSoldierAffordBurstBullets( pSoldier, sMapPos ) && (sFutureAPCost - sCurAPCosts) == 0 );
|
|
|
|
// complement burst by adding bullets, until next bullet produce AP difference
|
|
sFutureAPCost = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
while ( CanSoldierAffordBurstBullets( pSoldier, sMapPos ) && (sFutureAPCost - sCurAPCosts) == 0 )
|
|
{
|
|
pSoldier->bDoAutofire += 1; // now it goes as future burst length
|
|
sFutureAPCost = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
}
|
|
|
|
// display red numbers, if it is last possible burst ap spenditure
|
|
pSoldier->flags.autofireLastStep = !CanSoldierAffordBurstBullets( pSoldier, sMapPos );
|
|
|
|
// restore last iteration bullet count (before ap difference)
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
{
|
|
// SINGLE SHOT section
|
|
bFutureAim = pSoldier->aiData.bShownAimTime + sDelta;
|
|
|
|
if ( CanSoldierAffordAimTime( pSoldier, sMapPos, bFutureAim) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime += sDelta;
|
|
// display yellow circle, if it is last possible aim level
|
|
gfDisplayFullCountRing = !CanSoldierAffordAimTime( pSoldier, sMapPos, bFutureAim + 1);
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PUNCHCURS:
|
|
// PUNCHING section
|
|
bFutureAim = pSoldier->aiData.bShownAimTime + sDelta * REFINE_PUNCH_2; // possibly dirty hack
|
|
|
|
if ( CanSoldierAffordPunching( pSoldier, sMapPos, bFutureAim) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime += sDelta * REFINE_PUNCH_2;
|
|
// display yellow circle, if it is last possible aim level
|
|
gfDisplayFullCountRing = !CanSoldierAffordPunching( pSoldier, sMapPos, bFutureAim + 1);
|
|
}
|
|
break;
|
|
|
|
case KNIFECURS:
|
|
// KNIFING section
|
|
bFutureAim = pSoldier->aiData.bShownAimTime + sDelta * REFINE_KNIFE_2; // possibly dirty hack
|
|
|
|
if ( CanSoldierAffordKnifing( pSoldier, sMapPos, bFutureAim) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime += sDelta * REFINE_KNIFE_2;
|
|
// display yellow circle, if it is last possible aim level
|
|
gfDisplayFullCountRing = !CanSoldierAffordKnifing( pSoldier, sMapPos, bFutureAim + 1);
|
|
}
|
|
break;
|
|
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
*/
|
|
// HEADROCK HAM B2.7: This function gives us an "approximate" CTH bar, that doesn't show the exact value of
|
|
// CTH unless the character is well-trained. The worse trained a character is, the wilder the speculation.
|
|
|
|
UINT32 ChanceToHitApproximation( SOLDIERTYPE * pSoldier, UINT32 uiChance )
|
|
{
|
|
UINT16 bExpLevelValue = EffectiveExpLevel(pSoldier); // SANDRO - changed to effective level calc
|
|
UINT16 bMarksmanship = pSoldier->stats.bMarksmanship;
|
|
UINT16 bWisdom = pSoldier->stats.bWisdom;
|
|
UINT16 iNumStages, iNumStagesBase, StageSize, SubStageSize;
|
|
UINT8 iSniper;
|
|
UINT16 uiNewChance;
|
|
UINT16 i;
|
|
|
|
if ( pSoldier->ubProfile != NO_PROFILE )
|
|
{
|
|
if ( gGameOptions.fNewTraitSystem ) // old/new traits - SANDRO
|
|
iSniper = NUM_SKILL_TRAITS( pSoldier, SNIPER_NT );
|
|
else
|
|
iSniper = NUM_SKILL_TRAITS( pSoldier, PROF_SNIPER_OT );
|
|
}
|
|
else
|
|
{
|
|
// Dunno, but I get the strong feeling that we don't want CTH bars for non-mercs.
|
|
return(0);
|
|
}
|
|
|
|
if (uiChance == 100)
|
|
{
|
|
// Sure hit. The player needs to set Maximum_CTH to 100 for this to happen. Normally, the
|
|
// max chance is only 99.
|
|
return(100);
|
|
}
|
|
if (uiChance == 0)
|
|
{
|
|
// Sure Miss. The player needs to set Minimum_CTH to 0 for this to happen. Normally, the
|
|
// min chance is 1.
|
|
return(0);
|
|
}
|
|
|
|
uiNewChance = uiChance;
|
|
iNumStagesBase = __min(165,__max(0, ((bExpLevelValue * 10) - 30) + (bMarksmanship - 25) + (bWisdom - 50)));
|
|
//iNumStagesBase = __max(255, iNumStagesBase);
|
|
|
|
iNumStagesBase = __min(165, iNumStagesBase + (10 * iSniper));
|
|
|
|
iNumStagesBase = (UINT16)((float)iNumStagesBase * (float)((float)iNumStagesBase / 195.0));
|
|
|
|
// Gives a number between 2 and 51.
|
|
iNumStages = __max(2,(100 * iNumStagesBase) / 300);
|
|
|
|
// Find out how large the slices are
|
|
StageSize = 100/iNumStages;
|
|
// Correct iNumStages to match StageSize, +1 compensates for the rounding down of StageSize.
|
|
iNumStages = (100/StageSize) + 1;
|
|
// These sub-stages are used to determine which way to round the results.
|
|
SubStageSize = __max(1, StageSize / 2);
|
|
|
|
if (StageSize == 1)
|
|
// CTH assessment is perfect. No need for the rest of this function
|
|
return (uiChance);
|
|
|
|
// Jump each "stage" and see whether the CTH is within this slice of the scale
|
|
for (i=0; i<iNumStages; i++)
|
|
{
|
|
UINT16 CurrentStage = i * StageSize;
|
|
UINT16 NextStage = (i+1) * StageSize;
|
|
// Check whether the CTH should be rounded down or up.
|
|
if ( (CurrentStage <= (UINT16) uiChance) && (CurrentStage + SubStageSize > (UINT16) uiChance) )
|
|
{
|
|
return (CurrentStage);
|
|
}
|
|
else if ( (CurrentStage + SubStageSize <= (UINT16) uiChance) && (NextStage > (UINT16) uiChance))
|
|
{
|
|
return (NextStage);
|
|
}
|
|
}
|
|
|
|
// Something went wrong. Return 50, as in "God Knows"
|
|
return (50);
|
|
}
|
|
|
|
|
|
/* //nearly debugged Headrock code, need to finish aiming for fist and knife
|
|
void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT16 sMapPos, INT16 sDelta )
|
|
{
|
|
UINT16 usInHand;
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
UINT8 ubCursor;
|
|
SOLDIERTYPE *pTSoldier;
|
|
INT16 sGridNo;
|
|
INT8 bTargetLevel;
|
|
|
|
|
|
usInHand = pSoldier->inv[HANDPOS].usItem;
|
|
|
|
ubCursor = GetActionModeCursor( pSoldier );
|
|
|
|
UINT8 maxAimLevels = AllowedAimingLevels(pSoldier);
|
|
|
|
// 'snap' cursor to target tile....
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
}
|
|
|
|
|
|
switch( ubCursor )
|
|
{
|
|
case TARGETCURS:
|
|
|
|
// CHECK IF GUY HAS IN HAND A WEAPON
|
|
if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire)
|
|
{
|
|
// Do nothing!
|
|
// pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST;
|
|
}
|
|
else if(pSoldier->bDoAutofire)
|
|
{
|
|
INT16 sCurAPCosts;
|
|
|
|
if(pSoldier->bDoAutofire==1 && sDelta<0) return;
|
|
|
|
if(pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft > pSoldier->bDoAutofire )
|
|
{
|
|
//Calculate how many bullets we need to fire to add at least one more AP
|
|
sAPCosts = sCurAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
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
|
|
{
|
|
pSoldier->bDoAutofire++;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
}
|
|
|
|
//we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets
|
|
|
|
sCurAPCosts = sAPCosts;
|
|
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire+=sDelta;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
}
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, 0);
|
|
|
|
if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets
|
|
{
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false
|
|
}
|
|
else
|
|
{
|
|
if(sDelta<0)
|
|
{
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
}
|
|
}
|
|
else //single shoot
|
|
{
|
|
sGridNo = sMapPos;
|
|
bTargetLevel = (INT8)gsInterfaceLevel;
|
|
|
|
// Look for a target here...
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
// Get target soldier, if one exists
|
|
pTSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
sGridNo = pTSoldier->sGridNo;
|
|
bTargetLevel = pSoldier->pathing.bLevel;
|
|
|
|
if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) )
|
|
return;
|
|
}
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + sDelta );
|
|
if(bFutureAim <0)return;
|
|
|
|
if ( bFutureAim <= maxAimLevels )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim ) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= sDelta;
|
|
if ( pSoldier->aiData.bShownAimTime > maxAimLevels )
|
|
pSoldier->aiData.bShownAimTime = maxAimLevels;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
|
|
else // Else - goto first level!
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
case PUNCHCURS:
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + REFINE_PUNCH_2 );
|
|
|
|
if ( bFutureAim <= REFINE_PUNCH_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2);
|
|
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case KNIFECURS:
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) );
|
|
|
|
if ( bFutureAim <= REFINE_KNIFE_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2;
|
|
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 )
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2;
|
|
}
|
|
}
|
|
// Else - goto first level!
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( !gfDisplayFullCountRing )
|
|
{
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_1;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
|
|
//IncrementAimCubeUI( );
|
|
break;
|
|
|
|
default:
|
|
|
|
ErasePath( TRUE );
|
|
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
void HandleWheelAdjustCursor( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta, INT16 brstmode )
|
|
{
|
|
UINT16 usInHand;
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
UINT8 ubCursor;
|
|
SOLDIERTYPE *pTSoldier;
|
|
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;
|
|
|
|
ubCursor = GetActionModeCursor( pSoldier );
|
|
|
|
UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, sMapPos);
|
|
|
|
// 'snap' cursor to target tile....
|
|
if ( gfUIFullTargetFound )
|
|
sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
|
|
int aimlevelchange = 1;
|
|
int maxAimCanAfford = 0;
|
|
int oldAim = pSoldier->aiData.bShownAimTime;
|
|
int hitChance = 0;
|
|
int maxCtH = 0; //maximum chance to hit
|
|
int minAimForCtH = 0; //minimum AP needed to get maximum CtH
|
|
switch( ubCursor )
|
|
{
|
|
case TARGETCURS:
|
|
{
|
|
if(pSoldier->bDoAutofire && (gfKeyState[ ALT ] || brstmode) ) //add bullets to autofire
|
|
{
|
|
INT16 sCurAPCosts;
|
|
|
|
if(pSoldier->bDoAutofire==1 && sDelta<0)
|
|
return;
|
|
|
|
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 && 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);
|
|
}
|
|
|
|
//we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets
|
|
|
|
sCurAPCosts = sAPCosts;
|
|
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire+=sDelta;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
}
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
|
|
if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets
|
|
{
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false
|
|
}
|
|
else
|
|
{
|
|
if(sDelta<0)
|
|
{
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
sGridNo = sMapPos;
|
|
bTargetLevel = (INT8)gsInterfaceLevel;
|
|
|
|
// Look for a target here...
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
// Get target soldier, if one exists
|
|
pTSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
sGridNo = pTSoldier->sGridNo;
|
|
bTargetLevel = pSoldier->pathing.bLevel;
|
|
|
|
if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
bFutureAim = maxAimLevels;
|
|
|
|
//Find the actual maximum aim that can be done.
|
|
while( bFutureAim > 0 )
|
|
{
|
|
//Can afford this many?
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, bFutureAim );
|
|
if( !maxAimCanAfford && EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
maxAimCanAfford = bFutureAim;
|
|
}
|
|
//Find the least amount of aiming needed to get maximum CtH
|
|
//Give some slack, but don't let the slack accumulate.
|
|
//dd???{
|
|
//hitChance = CalcChanceToHitGun( pSoldier, sMapPos, bFutureAim, pSoldier->bAimShotLocation );
|
|
//if( hitChance >= maxCtH - 3){
|
|
// minAimForCtH = bFutureAim;
|
|
// if(hitChance >= maxCtH) maxCtH = hitChance;
|
|
//}
|
|
//ddd???}
|
|
//Loop to 0.
|
|
--bFutureAim;
|
|
}
|
|
|
|
bFutureAim = oldAim + sDelta;
|
|
if( bFutureAim < REFINE_AIM_1 )
|
|
return;
|
|
|
|
//Do it.
|
|
if( bFutureAim < REFINE_AIM_1 )
|
|
{
|
|
//Went too low. Set to max aim.
|
|
bFutureAim = maxAimCanAfford;
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else if( bFutureAim <= maxAimCanAfford )
|
|
{
|
|
//Aim level is doable. No modification needed.
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//Aim too high. Give indicator that is is maxed, then reset aim refinement.
|
|
if ( gfDisplayFullCountRing )
|
|
return;
|
|
else{
|
|
//Display ring to indicate maximum aim reached.
|
|
bFutureAim = oldAim;
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
}
|
|
//Apply.
|
|
pSoldier->aiData.bShownAimTime = bFutureAim;
|
|
|
|
//ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, L"caft=%d",CalcChanceToHitGun( pSoldier, sMapPos, pSoldier->aiData.bShownAimTime, pSoldier->bAimShotLocation ) );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PUNCHCURS:
|
|
{
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_PUNCH_2) );
|
|
if(bFutureAim < 0 )
|
|
return;
|
|
|
|
if ( bFutureAim <= REFINE_PUNCH_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2);
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 )
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
break;
|
|
|
|
case KNIFECURS:
|
|
{
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) );
|
|
if(bFutureAim<0)
|
|
return;
|
|
|
|
if ( bFutureAim <= REFINE_KNIFE_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2;
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 )
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
//IncrementAimCubeUI( );
|
|
break;
|
|
|
|
default:
|
|
ErasePath( TRUE );
|
|
}
|
|
}
|
|
|
|
void HandleWheelAdjustCursorWOAB( SOLDIERTYPE *pSoldier, INT32 sMapPos, INT32 sDelta )
|
|
{
|
|
UINT16 usInHand;
|
|
INT16 sAPCosts;
|
|
INT8 bFutureAim;
|
|
UINT8 ubCursor;
|
|
SOLDIERTYPE *pTSoldier;
|
|
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;
|
|
|
|
ubCursor = GetActionModeCursor( pSoldier );
|
|
|
|
UINT8 maxAimLevels = AllowedAimingLevels(pSoldier, sMapPos);
|
|
|
|
// 'snap' cursor to target tile....
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
sMapPos = MercPtrs[ gusUIFullTargetID ]->sGridNo;
|
|
}
|
|
|
|
|
|
switch( ubCursor )
|
|
{
|
|
case TARGETCURS:
|
|
|
|
// CHECK IF GUY HAS IN HAND A WEAPON
|
|
if ( pSoldier->bDoBurst && !pSoldier->bDoAutofire)
|
|
{
|
|
// Do nothing!
|
|
// pSoldier->aiData.bShownAimTime = REFINE_AIM_BURST;
|
|
}
|
|
else if(pSoldier->bDoAutofire)
|
|
{
|
|
INT16 sCurAPCosts;
|
|
|
|
if(pSoldier->bDoAutofire==1 && sDelta<0) return;
|
|
|
|
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 && 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);
|
|
}
|
|
|
|
//we've stepped over the border and used up one more ap, now let's make sure that it is spent to maximize the bullets
|
|
|
|
sCurAPCosts = sAPCosts;
|
|
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire+=sDelta;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
}
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && sAPCosts == sCurAPCosts && usShotsLeft >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, pSoldier->aiData.bShownAimTime);
|
|
|
|
if(!EnoughPoints( pSoldier, sAPCosts, 0, FALSE )) //We've not enough points to fire those bullets
|
|
{
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = FALSE; //both last step conditions are false
|
|
}
|
|
else
|
|
{
|
|
if(sDelta<0)
|
|
{
|
|
pSoldier->flags.autofireLastStep = FALSE;
|
|
pSoldier->bDoAutofire--;
|
|
}
|
|
else
|
|
pSoldier->flags.autofireLastStep = TRUE;
|
|
}
|
|
}
|
|
else //single shoot
|
|
{
|
|
sGridNo = sMapPos;
|
|
bTargetLevel = (INT8)gsInterfaceLevel;
|
|
|
|
// Look for a target here...
|
|
if ( gfUIFullTargetFound )
|
|
{
|
|
// Get target soldier, if one exists
|
|
pTSoldier = MercPtrs[ gusUIFullTargetID ];
|
|
sGridNo = pTSoldier->sGridNo;
|
|
bTargetLevel = pSoldier->pathing.bLevel;
|
|
|
|
if ( !HandleCheckForBadChangeToGetThrough( pSoldier, pTSoldier, sGridNo , bTargetLevel ) )
|
|
return;
|
|
}
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + sDelta );
|
|
if(bFutureAim <0)return;
|
|
|
|
if ( bFutureAim <= maxAimLevels )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim ) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= sDelta;
|
|
if ( pSoldier->aiData.bShownAimTime > maxAimLevels )
|
|
pSoldier->aiData.bShownAimTime = maxAimLevels;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
|
|
else // Else - goto first level!
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
|
|
}
|
|
break;
|
|
|
|
case PUNCHCURS:
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_PUNCH_2) );
|
|
if(bFutureAim<0)
|
|
return;
|
|
if ( bFutureAim <= REFINE_PUNCH_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= (sDelta*REFINE_PUNCH_2);
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_PUNCH_2 )
|
|
pSoldier->aiData.bShownAimTime = REFINE_PUNCH_2;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KNIFECURS:
|
|
|
|
bFutureAim = (INT8)( pSoldier->aiData.bShownAimTime + (sDelta*REFINE_KNIFE_2) );
|
|
if(bFutureAim<0)
|
|
return;
|
|
if ( bFutureAim <= REFINE_KNIFE_2 )
|
|
{
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, sMapPos, TRUE, (INT8)(bFutureAim / 2) );
|
|
|
|
// Determine if we can afford!
|
|
if ( EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) )
|
|
{
|
|
pSoldier->aiData.bShownAimTime+= REFINE_KNIFE_2;
|
|
if ( pSoldier->aiData.bShownAimTime > REFINE_KNIFE_2 )
|
|
pSoldier->aiData.bShownAimTime = REFINE_KNIFE_2;
|
|
gfDisplayFullCountRing = FALSE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
}
|
|
else
|
|
gfDisplayFullCountRing = TRUE;
|
|
|
|
break;
|
|
|
|
case TOSSCURS:
|
|
|
|
//IncrementAimCubeUI( );
|
|
break;
|
|
|
|
default:
|
|
|
|
ErasePath( TRUE );
|
|
|
|
}
|
|
}
|
|
|
|
UINT8 DefaultAutofireBulletsByGunClass( SOLDIERTYPE* pSoldier )
|
|
{
|
|
UINT32 usItemClass;
|
|
UINT16 usItem;
|
|
UINT8 ubBullets = 1;
|
|
|
|
if( !pSoldier )
|
|
return 1;
|
|
if( !pSoldier->inv[ pSoldier->ubAttackingHand ].exists() )
|
|
return 1;
|
|
|
|
usItem = pSoldier->inv[ pSoldier->ubAttackingHand ].usItem;
|
|
usItemClass = Item[ usItem ].usItemClass;
|
|
|
|
if( usItemClass != IC_GUN )
|
|
return 1;
|
|
|
|
switch( Weapon[ Item[ usItem ].ubClassIndex ].ubWeaponType )
|
|
{
|
|
case GUN_M_PISTOL:
|
|
case GUN_PISTOL:
|
|
case GUN_SMG:
|
|
ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsSMG;
|
|
break;
|
|
case GUN_AS_RIFLE:
|
|
case GUN_RIFLE:
|
|
case GUN_SN_RIFLE :
|
|
case GUN_SHOTGUN:
|
|
ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsAR;
|
|
break;
|
|
case GUN_LMG:
|
|
ubBullets = gGameExternalOptions.ubSetDefaultAutofireBulletsMG;
|
|
break;
|
|
}
|
|
|
|
return ubBullets;
|
|
} |