mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
313 lines
8.6 KiB
C++
313 lines
8.6 KiB
C++
#include "stdlib.h"
|
|
#include "DEBUG.H"
|
|
#include "Weapons.h"
|
|
#include "Soldier Find.h"
|
|
#include "Isometric Utils.h"
|
|
#include "renderworld.h"
|
|
#include "Render Dirty.h"
|
|
#include "Interface.h"
|
|
#include "Spread burst.h"
|
|
#include "Points.h"
|
|
|
|
//forward declarations of common classes to eliminate includes
|
|
class OBJECTTYPE;
|
|
class SOLDIERTYPE;
|
|
|
|
|
|
|
|
BURST_LOCATIONS gsBurstLocations[ MAX_BURST_LOCATIONS ];
|
|
INT8 gbNumBurstLocations = 0;
|
|
|
|
extern BOOLEAN gfBeginBurstSpreadTracking;
|
|
|
|
|
|
void ResetBurstLocations( )
|
|
{
|
|
gbNumBurstLocations = 0;
|
|
}
|
|
|
|
|
|
void InternalAccumulateBurstLocation( INT32 sGridNo )
|
|
{
|
|
INT32 cnt;
|
|
if ( gbNumBurstLocations < MAX_BURST_LOCATIONS )
|
|
{
|
|
// Check if it already exists!
|
|
for ( cnt = 0; cnt < gbNumBurstLocations; cnt++ )
|
|
{
|
|
if ( gsBurstLocations[ cnt ].sGridNo == sGridNo )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
gsBurstLocations[ gbNumBurstLocations ].sGridNo = sGridNo;
|
|
|
|
// Get cell X, Y from mouse...
|
|
GetMouseWorldCoords( &( gsBurstLocations[ gbNumBurstLocations ].sX ), &( gsBurstLocations[ gbNumBurstLocations ].sY ) );
|
|
|
|
gbNumBurstLocations++;
|
|
}
|
|
}
|
|
|
|
//Madd: to add a bit more usefulness to spread fire, I'm making it so that
|
|
//it will automatically latch onto enemies within iSearchRange tiles of the mouse drag.
|
|
void AccumulateBurstLocation( INT32 sGridNo )
|
|
{
|
|
SOLDIERTYPE* pTarget;
|
|
int iSearchRange = 2; // number of tiles beside the mouse drag to look at
|
|
INT32 sMaxLeft, sMaxRight, sMaxUp, sMaxDown, sXOffset, sYOffset, sAdjacentGridNo;
|
|
BOOLEAN foundTarget = FALSE;
|
|
|
|
//first see if we can find a guy standing right on the spot
|
|
pTarget = SimpleFindSoldier(sGridNo,0);
|
|
if (!pTarget)
|
|
pTarget = SimpleFindSoldier(sGridNo, 1); //try on a roof
|
|
|
|
if (pTarget)
|
|
{
|
|
InternalAccumulateBurstLocation(sGridNo);
|
|
foundTarget = TRUE;
|
|
}
|
|
//let's now look around this square - maybe there are some adjacent enemies we can latch onto
|
|
|
|
// stay away from the edges
|
|
|
|
// determine maximum horizontal limits
|
|
sMaxLeft = min( iSearchRange, (sGridNo % MAXCOL));
|
|
sMaxRight = min( iSearchRange, MAXCOL - ((sGridNo % MAXCOL) + 1));
|
|
|
|
// determine maximum vertical limits
|
|
sMaxUp = min( iSearchRange, (sGridNo / MAXROW));
|
|
sMaxDown = min( iSearchRange, MAXROW - ((sGridNo / MAXROW) + 1));
|
|
|
|
// reset the "reachable" flags in the region we're looking at
|
|
for (sYOffset = -sMaxUp; sYOffset <= sMaxDown; sYOffset++)
|
|
{
|
|
for (sXOffset = -sMaxLeft; sXOffset <= sMaxRight; sXOffset++)
|
|
{
|
|
sAdjacentGridNo = sGridNo + sXOffset + (MAXCOL * sYOffset);
|
|
if ( !(sAdjacentGridNo >=0 && sAdjacentGridNo < WORLD_MAX) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pTarget = SimpleFindSoldier(sAdjacentGridNo,0); // look for a guy in that gridno
|
|
|
|
if (!pTarget)
|
|
pTarget = SimpleFindSoldier(sAdjacentGridNo, 1); //try on a roof
|
|
|
|
if (pTarget)
|
|
{
|
|
InternalAccumulateBurstLocation(sAdjacentGridNo); //there's somebody there! let's latch onto him
|
|
foundTarget = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ( !foundTarget )
|
|
{
|
|
//didn't find anyone nearby, but we should target this space anyway to prevent players from abusing this feature
|
|
InternalAccumulateBurstLocation(sGridNo);
|
|
}
|
|
}
|
|
|
|
|
|
void PickBurstLocations( SOLDIERTYPE *pSoldier )
|
|
{
|
|
UINT8 ubShotsPerBurst = 0;
|
|
FLOAT dAccumulator = 0;
|
|
FLOAT dStep = 0;
|
|
INT32 cnt;
|
|
UINT8 ubLocationNum;
|
|
|
|
// OK, using the # of locations, spread them evenly between our current weapon shots per burst value
|
|
|
|
// Get shots per burst
|
|
//DIGICRAB: Burst UnCap
|
|
//if we fire more than MAX_BURST_SPREAD_TARGETS bullets, make sure there's no buffer overflow
|
|
if(pSoldier->bDoAutofire)
|
|
{
|
|
INT16 sAPCosts;
|
|
|
|
if ( pSoldier->bDoAutofire <= gbNumBurstLocations )
|
|
{
|
|
pSoldier->bDoAutofire = 1;
|
|
do
|
|
{
|
|
pSoldier->bDoAutofire++;
|
|
sAPCosts = CalcTotalAPsToAttack( pSoldier, gsBurstLocations[0].sGridNo, TRUE, pSoldier->aiData.bShownAimTime);
|
|
}
|
|
while(EnoughPoints( pSoldier, sAPCosts, 0, FALSE ) && pSoldier->inv[ pSoldier->ubAttackingHand ][0]->data.gun.ubGunShotsLeft >= pSoldier->bDoAutofire && gbNumBurstLocations >= pSoldier->bDoAutofire);
|
|
pSoldier->bDoAutofire--;
|
|
|
|
ubShotsPerBurst = pSoldier->bDoAutofire;
|
|
}
|
|
else if ( gbNumBurstLocations > 0 )
|
|
ubShotsPerBurst = pSoldier->bDoAutofire; // / gbNumBurstLocations;
|
|
|
|
}
|
|
else
|
|
{
|
|
if ( pSoldier->bWeaponMode == WM_ATTACHED_GL_BURST )
|
|
ubShotsPerBurst = Weapon[GetAttachedGrenadeLauncher(&pSoldier->inv[HANDPOS])].ubShotsPerBurst;
|
|
else
|
|
ubShotsPerBurst = GetShotsPerBurst(&pSoldier->inv[ HANDPOS ]);
|
|
}
|
|
|
|
ubShotsPerBurst = __min( ubShotsPerBurst, MAX_BURST_SPREAD_TARGETS);
|
|
|
|
if (ubShotsPerBurst == 1)
|
|
{
|
|
pSoldier->flags.fDoSpread = FALSE;
|
|
return;
|
|
}
|
|
|
|
// Use # gridnos accululated and # burst shots to determine accululator
|
|
// Calculate it so that the actual last chosen shot location is the last spread point
|
|
dStep = (gbNumBurstLocations-1) / (FLOAT)(ubShotsPerBurst-1);
|
|
|
|
//Loop through our shots!
|
|
for ( cnt = 0; cnt < ubShotsPerBurst; cnt++ )
|
|
{
|
|
// Get index into list
|
|
ubLocationNum = (UINT8)( dAccumulator );
|
|
|
|
// Add to merc location
|
|
pSoldier->sSpreadLocations[ cnt ] = gsBurstLocations[ ubLocationNum ].sGridNo;
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("PickBurstLocations: loc#%d = %d", cnt, pSoldier->sSpreadLocations[ cnt ]));
|
|
// Acculuate index value
|
|
dAccumulator += dStep;
|
|
}
|
|
|
|
for (; cnt < MAX_BURST_SPREAD_TARGETS; cnt++)
|
|
{
|
|
pSoldier->sSpreadLocations[ cnt ] = 0;
|
|
}
|
|
|
|
// OK, they have been added
|
|
}
|
|
|
|
void AIPickBurstLocations( SOLDIERTYPE *pSoldier, INT8 bTargets, SOLDIERTYPE *pTargets[5] )
|
|
{
|
|
UINT8 ubShotsPerBurst;
|
|
FLOAT dAccululator = 0;
|
|
FLOAT dStep = 0;
|
|
INT32 cnt;
|
|
UINT8 ubLocationNum;
|
|
|
|
// OK, using the # of locations, spread them evenly between our current weapon shots per burst value
|
|
|
|
// Get shots per burst
|
|
//DIGICRAB: Burst UnCap
|
|
//if we fire more than MAX_BURST_SPREAD_TARGETS bullets, make sure there's no buffer overflow
|
|
if(pSoldier->bDoAutofire)
|
|
ubShotsPerBurst = __min(pSoldier->bDoAutofire,MAX_BURST_SPREAD_TARGETS);
|
|
else
|
|
ubShotsPerBurst = __min(GetShotsPerBurst (&pSoldier->inv[ HANDPOS ]),MAX_BURST_SPREAD_TARGETS);
|
|
|
|
if ( pSoldier->IsValidSecondHandBurst() )
|
|
ubShotsPerBurst = ubShotsPerBurst*2;
|
|
|
|
if ( ubShotsPerBurst <= 0 )
|
|
ubShotsPerBurst = 1;
|
|
|
|
// Use # gridnos accululated and # burst shots to determine accululator
|
|
//dStep = gbNumBurstLocations / (FLOAT)ubShotsPerBurst;
|
|
// CJC: tweak!
|
|
dStep = bTargets / (FLOAT)ubShotsPerBurst;
|
|
|
|
//Loop through our shots!
|
|
for ( cnt = 0; cnt < ubShotsPerBurst; cnt++ )
|
|
{
|
|
// Get index into list
|
|
ubLocationNum = (UINT8)( dAccululator );
|
|
|
|
// Add to merc location
|
|
pSoldier->sSpreadLocations[ cnt ] = pTargets[ubLocationNum]->sGridNo;
|
|
|
|
// Acculuate index value
|
|
dAccululator += dStep;
|
|
}
|
|
|
|
for (; cnt < MAX_BURST_SPREAD_TARGETS; cnt++)
|
|
{
|
|
pSoldier->sSpreadLocations[ cnt ] = 0;
|
|
}
|
|
// OK, they have been added
|
|
}
|
|
|
|
|
|
extern HVOBJECT GetCursorFileVideoObject( UINT32 uiCursorFile );
|
|
|
|
|
|
void RenderAccumulatedBurstLocations( )
|
|
{
|
|
INT32 cnt;
|
|
INT32 sGridNo;
|
|
HVOBJECT hVObject;
|
|
|
|
if ( !gfBeginBurstSpreadTracking )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( gbNumBurstLocations == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Loop through each location...
|
|
GetVideoObject( &hVObject, guiBURSTACCUM );
|
|
|
|
// If on screen, render
|
|
|
|
// Check if it already exists!
|
|
for ( cnt = 0; cnt < gbNumBurstLocations; cnt++ )
|
|
{
|
|
sGridNo = gsBurstLocations[ cnt ].sGridNo;
|
|
|
|
if ( GridNoOnScreen( sGridNo ) )
|
|
{
|
|
FLOAT dOffsetX, dOffsetY;
|
|
FLOAT dTempX_S, dTempY_S;
|
|
INT16 sXPos, sYPos;
|
|
INT32 iBack;
|
|
|
|
dOffsetX = (FLOAT)( gsBurstLocations[ cnt ].sX - gsRenderCenterX );
|
|
dOffsetY = (FLOAT)( gsBurstLocations[ cnt ].sY - gsRenderCenterY );
|
|
|
|
// Calculate guy's position
|
|
FloatFromCellToScreenCoordinates( dOffsetX, dOffsetY, &dTempX_S, &dTempY_S );
|
|
|
|
sXPos = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) + (INT16)dTempX_S;
|
|
sYPos = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + (INT16)dTempY_S - gpWorldLevelData[ sGridNo ].sHeight;
|
|
|
|
// Adjust for offset position on screen
|
|
sXPos -= gsRenderWorldOffsetX;
|
|
sYPos -= gsRenderWorldOffsetY;
|
|
|
|
// Adjust for render height
|
|
sYPos += gsRenderHeight;
|
|
|
|
//sScreenY -= gpWorldLevelData[ sGridNo ].sHeight;
|
|
|
|
// Center circle!
|
|
//sXPos -= 10;
|
|
//sYPos -= 10;
|
|
|
|
iBack = RegisterBackgroundRect( BGND_FLAG_SINGLE, NULL, sXPos, sYPos, (INT16)(sXPos +40 ), (INT16)(sYPos + 40 ) );
|
|
if ( iBack != -1 )
|
|
{
|
|
SetBackgroundRectFilled( iBack );
|
|
}
|
|
|
|
BltVideoObject( FRAME_BUFFER, hVObject, 1, sXPos, sYPos, VO_BLT_SRCTRANSPARENCY, NULL );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|