mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
* Use ConvertGridNoToCenterCellXY instead of CenterX & CenterY * Add direction utility function We have a lot of places in the code that calculate direction based on center cell coordinates, but lack a utility function for it similar to other direction methods. * Use utility function for calculating direction * Use ConvertGridNoToCenterCellXY * Use utility function for direction * Use ConvertGridNoToCenterCellXY instead of CenterX & CenterY * Use ConvertGridNoToCenterCellXY instead of CenterX & CenterY * Remove CenterX & CenterY functions Use ConvertGridNoToCenterCellXY instead * Remove CenterX & CenterY calls from UB configuration * Address review feedback * Remove duplicate function ConvertGridNoToCenterCellXY and ConvertMapPosToWorldTileCenter do the exact same thing * Use PythSpacesAway instead of GetRangeFromGridNoDiff Both functions calculate the same thing * Remove GetRangeFromGridNoDiff * Remove calls to abs() The values end up being squared anyways making these unnecessary
1073 lines
27 KiB
C++
1073 lines
27 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "stdlib.h"
|
|
#include "debug.h"
|
|
#include "math.h"
|
|
#include "worlddef.h"
|
|
#include "worldman.h"
|
|
#include "renderworld.h"
|
|
#include "Assignments.h"
|
|
#include "Soldier Control.h"
|
|
#include "Animation Control.h"
|
|
#include "Animation Data.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Event Pump.h"
|
|
#include "Render Fun.h"
|
|
#include "mousesystem.h"
|
|
#include "interface.h"
|
|
#include "sysutil.h"
|
|
#include "FileMan.h"
|
|
#include "Random.h"
|
|
#include "ai.h"
|
|
#include "Interactive Tiles.h"
|
|
#include "english.h"
|
|
#include "overhead.h"
|
|
//#include "Sound Control.h"
|
|
#include "lighting.h"
|
|
#include "pathai.h"
|
|
#include "screenids.h"
|
|
#include "weapons.h"
|
|
#include "lighting.h"
|
|
#include "Handle UI Plan.h"
|
|
#include "structure.h"
|
|
#include "message.h"
|
|
#include "items.h"
|
|
#include "Soldier Profile.h"
|
|
#include "fov.h"
|
|
#include "Soldier macros.h"
|
|
#include "soldier tile.h"
|
|
#include "soldier find.h"
|
|
#include "Vehicles.h"
|
|
#include "GameSettings.h"
|
|
#include "ui cursors.h"
|
|
|
|
|
|
BOOLEAN IsGridNoInScreenRect( INT32 sGridNo, SGPRect *pRect );
|
|
BOOLEAN IsPointInScreenRect( INT16 sXPos, INT16 sYPos, SGPRect *pRect );
|
|
void GetSoldierScreenRect( SOLDIERTYPE *pSoldier, SGPRect *pRect );
|
|
|
|
// This value is used to keep a small static array of uBID's which are stacked
|
|
#define MAX_STACKED_MERCS 10
|
|
|
|
|
|
UINT32 gScrollSlideInertiaDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
3,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
3,
|
|
3,
|
|
};
|
|
|
|
// Struct used for cycling through multiple mercs per mouse position
|
|
typedef struct
|
|
{
|
|
INT8 bNum;
|
|
UINT8 ubIDs[ MAX_STACKED_MERCS ];
|
|
INT8 bCur;
|
|
BOOLEAN fUseGridNo;
|
|
INT32 sUseGridNoGridNo;
|
|
|
|
} SOLDIER_STACK_TYPE;
|
|
|
|
SOLDIER_STACK_TYPE gSoldierStack;
|
|
BOOLEAN gfHandleStack = FALSE;
|
|
|
|
extern BOOLEAN gUIActionModeChangeDueToMouseOver;
|
|
extern UINT32 guiUITargetSoldierId;
|
|
|
|
|
|
BOOLEAN FindSoldierFromMouse( UINT16 *pusSoldierIndex, UINT32 *pMercFlags )
|
|
{
|
|
INT32 usMapPos;
|
|
|
|
*pMercFlags = 0;
|
|
|
|
if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
if ( FindSoldier( usMapPos, pusSoldierIndex, pMercFlags ,FINDSOLDIERSAMELEVEL( gsInterfaceLevel ) ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN SelectiveFindSoldierFromMouse( UINT16 *pusSoldierIndex, UINT32 *pMercFlags )
|
|
{
|
|
INT32 usMapPos;
|
|
|
|
*pMercFlags = 0;
|
|
|
|
if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
if ( FindSoldier( usMapPos, pusSoldierIndex, pMercFlags , FINDSOLDIERSAMELEVEL( gsInterfaceLevel ) ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
UINT32 GetSoldierFindFlags( UINT16 ubID )
|
|
{
|
|
UINT32 MercFlags = 0;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
// Get pSoldier!
|
|
pSoldier = MercPtrs[ ubID ];
|
|
|
|
// FInd out and set flags
|
|
if ( ubID == gusSelectedSoldier )
|
|
{
|
|
MercFlags |= SELECTED_MERC;
|
|
}
|
|
if ( ubID >= gTacticalStatus.Team[ gbPlayerNum ].bFirstID && ubID <= gTacticalStatus.Team[ gbPlayerNum ].bLastID )
|
|
{
|
|
if ( ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE ) && !GetNumberInVehicle( pSoldier->bVehicleID ) )
|
|
{
|
|
// Don't do anything!
|
|
}
|
|
else
|
|
{
|
|
// It's our own merc
|
|
MercFlags |= OWNED_MERC;
|
|
|
|
if ( pSoldier->bAssignment < ON_DUTY )
|
|
{
|
|
MercFlags |= ONDUTY_MERC;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Check the side, etc
|
|
if ( !pSoldier->aiData.bNeutral && (pSoldier->bSide != gbPlayerNum ) )
|
|
{
|
|
// It's an enemy merc
|
|
MercFlags |= ENEMY_MERC;
|
|
}
|
|
else
|
|
{
|
|
// It's not an enemy merc
|
|
MercFlags |= NEUTRAL_MERC;
|
|
}
|
|
}
|
|
|
|
// Check for a guy who does not have an iterrupt ( when applicable! )
|
|
if ( !OK_INTERRUPT_MERC( pSoldier ) )
|
|
{
|
|
MercFlags |= NOINTERRUPT_MERC;
|
|
}
|
|
|
|
if ( pSoldier->stats.bLife < OKLIFE )
|
|
{
|
|
MercFlags |= UNCONSCIOUS_MERC;
|
|
}
|
|
|
|
if ( pSoldier->usSkillCooldown[SOLDIER_COOLDOWN_CRYO] )
|
|
MercFlags |= UNCONSCIOUS_MERC;
|
|
|
|
if ( pSoldier->stats.bLife == 0 )
|
|
{
|
|
MercFlags |= DEAD_MERC;
|
|
}
|
|
|
|
if ( pSoldier->bVisible != -1 || (gTacticalStatus.uiFlags&SHOW_ALL_MERCS) )
|
|
{
|
|
MercFlags |= VISIBLE_MERC;
|
|
}
|
|
|
|
return( MercFlags );
|
|
}
|
|
|
|
extern BOOLEAN CheckVideoObjectScreenCoordinateInData( HVOBJECT hSrcVObject, UINT16 usIndex, INT32 iTextX, INT32 iTestY );
|
|
|
|
|
|
// THIS FUNCTION IS CALLED FAIRLY REGULARLY
|
|
BOOLEAN FindSoldier( INT32 sGridNo, UINT16 *pusSoldierIndex, UINT32 *pMercFlags, UINT32 uiFlags )
|
|
{
|
|
UINT32 cnt;
|
|
SOLDIERTYPE *pSoldier;
|
|
SGPRect aRect;
|
|
BOOLEAN fSoldierFound = FALSE;
|
|
INT16 sXMapPos, sYMapPos, sScreenX, sScreenY;
|
|
INT16 sMaxScreenMercY, sHeighestMercScreenY = -32000;
|
|
BOOLEAN fDoFull;
|
|
UINT8 ubBestMerc = NOBODY;
|
|
UINT16 usAnimSurface;
|
|
INT32 iMercScreenX, iMercScreenY;
|
|
BOOLEAN fInScreenRect = FALSE;
|
|
BOOLEAN fInGridNo = FALSE;
|
|
|
|
|
|
*pusSoldierIndex = NOBODY;
|
|
*pMercFlags = 0;
|
|
|
|
if ( _KeyDown( SHIFT ) )
|
|
{
|
|
uiFlags = FIND_SOLDIER_GRIDNO;
|
|
}
|
|
|
|
// Set some values
|
|
if ( uiFlags & FIND_SOLDIER_BEGINSTACK )
|
|
{
|
|
gSoldierStack.bNum = 0;
|
|
gSoldierStack.fUseGridNo = FALSE;
|
|
}
|
|
|
|
|
|
// Loop through all mercs and make go
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
pSoldier = MercSlots[ cnt ];
|
|
fInScreenRect = FALSE;
|
|
fInGridNo = FALSE;
|
|
|
|
if ( pSoldier != NULL )
|
|
{
|
|
|
|
if ( pSoldier->bActive && !( pSoldier->flags.uiStatusFlags & SOLDIER_DEAD ) && ( pSoldier->bVisible != -1 || (gTacticalStatus.uiFlags&SHOW_ALL_MERCS) ) )
|
|
{
|
|
// OK, ignore if we are a passenger...
|
|
if ( pSoldier->flags.uiStatusFlags & ( SOLDIER_PASSENGER | SOLDIER_DRIVER ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// If we want same level, skip if buggy's not on the same level!
|
|
if ( uiFlags & FIND_SOLDIER_SAMELEVEL )
|
|
{
|
|
if ( pSoldier->pathing.bLevel != (UINT8)( uiFlags >> 16 ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
// If we are selective.... do our own guys FULL and other with gridno!
|
|
// First look for owned soldiers, by way of the full method
|
|
if ( uiFlags & FIND_SOLDIER_GRIDNO )
|
|
{
|
|
fDoFull = FALSE;
|
|
}
|
|
else if ( uiFlags & FIND_SOLDIER_SELECTIVE )
|
|
{
|
|
if ( pSoldier->ubID >= gTacticalStatus.Team[ gbPlayerNum ].bFirstID && pSoldier->ubID <= gTacticalStatus.Team[ gbPlayerNum ].bLastID )
|
|
{
|
|
fDoFull = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fDoFull = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fDoFull = TRUE;
|
|
}
|
|
|
|
if ( fDoFull )
|
|
{
|
|
// Get Rect contained in the soldier
|
|
GetSoldierScreenRect( pSoldier, &aRect );
|
|
|
|
// Get XY From gridno
|
|
ConvertGridNoToXY( sGridNo, &sXMapPos, &sYMapPos );
|
|
|
|
// Get screen XY pos from map XY
|
|
// Be carefull to convert to cell cords
|
|
//CellXYToScreenXY( (INT16)((sXMapPos*CELL_X_SIZE)), (INT16)((sYMapPos*CELL_Y_SIZE)), &sScreenX, &sScreenY);
|
|
|
|
// Set mouse stuff
|
|
sScreenX = gusMouseXPos;
|
|
sScreenY = gusMouseYPos;
|
|
|
|
if ( IsPointInScreenRect( sScreenX, sScreenY, &aRect ) )
|
|
{
|
|
fInScreenRect = TRUE;
|
|
}
|
|
|
|
if ( pSoldier->sGridNo == sGridNo )
|
|
{
|
|
fInGridNo = TRUE;
|
|
}
|
|
|
|
// ATE: If we are an enemy....
|
|
if ( !gGameSettings.fOptions[ TOPTION_SMART_CURSOR ] )
|
|
{
|
|
if ( pSoldier->ubID >= gTacticalStatus.Team[ gbPlayerNum ].bFirstID && pSoldier->ubID <= gTacticalStatus.Team[ gbPlayerNum ].bLastID )
|
|
{
|
|
// ATE: NOT if we are in action or comfirm action mode
|
|
if ( gCurrentUIMode != ACTION_MODE && gCurrentUIMode != CONFIRM_ACTION_MODE || gUIActionModeChangeDueToMouseOver )
|
|
{
|
|
fInScreenRect = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ATE: Refine this further....
|
|
// Check if this is the selected guy....
|
|
if ( pSoldier->ubID == gusSelectedSoldier )
|
|
{
|
|
// Are we in action mode...
|
|
if ( gCurrentUIMode == ACTION_MODE || gCurrentUIMode == CONFIRM_ACTION_MODE )
|
|
{
|
|
// Are we in medic mode?
|
|
if ( GetActionModeCursor( pSoldier ) != AIDCURS )
|
|
{
|
|
fInScreenRect = FALSE;
|
|
fInGridNo = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Make sure we are always on guy if we are on same gridno
|
|
if ( fInScreenRect || fInGridNo )
|
|
{
|
|
// Check if we are a vehicle and refine if so....
|
|
if ( pSoldier->flags.uiStatusFlags & SOLDIER_VEHICLE )
|
|
{
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
if ( usAnimSurface != INVALID_ANIMATION_SURFACE )
|
|
{
|
|
iMercScreenX = (INT32)( sScreenX - aRect.iLeft );
|
|
iMercScreenY = (INT32)( -1 * ( sScreenY - aRect.iBottom ) );
|
|
|
|
if ( !CheckVideoObjectScreenCoordinateInData( gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject, pSoldier->usAniFrame, iMercScreenX, iMercScreenY ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If thgis is from a gridno, use mouse pos!
|
|
if ( pSoldier->sGridNo == sGridNo )
|
|
{
|
|
|
|
}
|
|
|
|
// Only break here if we're not creating a stack of these fellas
|
|
if ( uiFlags & FIND_SOLDIER_BEGINSTACK )
|
|
{
|
|
gfHandleStack = TRUE;
|
|
|
|
// Add this one!
|
|
gSoldierStack.ubIDs[ gSoldierStack.bNum ] = pSoldier->ubID;
|
|
gSoldierStack.bNum++;
|
|
|
|
// Determine if it's the current
|
|
if ( aRect.iBottom > sHeighestMercScreenY )
|
|
{
|
|
sMaxScreenMercY = (UINT16)aRect.iBottom;
|
|
sHeighestMercScreenY = sMaxScreenMercY;
|
|
|
|
gSoldierStack.bCur = gSoldierStack.bNum - 1;
|
|
}
|
|
}
|
|
//Are we handling a stack right now?
|
|
else if ( gfHandleStack )
|
|
{
|
|
// Are we the selected stack?
|
|
if ( gSoldierStack.fUseGridNo )
|
|
{
|
|
fSoldierFound = FALSE;
|
|
break;
|
|
}
|
|
else if ( gSoldierStack.ubIDs[ gSoldierStack.bCur ] == pSoldier->ubID )
|
|
{
|
|
// Set it!
|
|
ubBestMerc = pSoldier->ubID;
|
|
|
|
fSoldierFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Determine if it's the best one
|
|
if ( aRect.iBottom > sHeighestMercScreenY )
|
|
{
|
|
sMaxScreenMercY = (UINT16)aRect.iBottom;
|
|
sHeighestMercScreenY = sMaxScreenMercY;
|
|
|
|
// Set it!
|
|
ubBestMerc = pSoldier->ubID;
|
|
}
|
|
|
|
fSoldierFound = TRUE;
|
|
// Don't break here, find the rest!
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
//Otherwise, look for a bad guy by way of gridno]
|
|
// Selective means don't give out enemy mercs if they are not visible
|
|
|
|
///&& !NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel )
|
|
if ( pSoldier->sGridNo == sGridNo && !NewOKDestination( pSoldier, sGridNo, TRUE, (INT8)gsInterfaceLevel ) )
|
|
{
|
|
// Set it!
|
|
ubBestMerc = pSoldier->ubID;
|
|
|
|
fSoldierFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fSoldierFound && ubBestMerc != NOBODY )
|
|
{
|
|
*pusSoldierIndex = (UINT16)ubBestMerc;
|
|
|
|
(*pMercFlags) = GetSoldierFindFlags( ubBestMerc );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
else
|
|
{
|
|
// If we were handling a stack, and we have not found anybody, end
|
|
if ( gfHandleStack && !( uiFlags & ( FIND_SOLDIER_BEGINSTACK | FIND_SOLDIER_SELECTIVE ) ) )
|
|
{
|
|
if ( gSoldierStack.fUseGridNo )
|
|
{
|
|
if ( gSoldierStack.sUseGridNoGridNo != sGridNo )
|
|
{
|
|
gfHandleStack = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gfHandleStack = FALSE;
|
|
}
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN CycleSoldierFindStack( INT32 usMapPos )
|
|
{
|
|
UINT16 usSoldierIndex;
|
|
UINT32 uiMercFlags;
|
|
|
|
// Have we initalized for this yet?
|
|
if ( !gfHandleStack )
|
|
{
|
|
if ( FindSoldier( usMapPos, &usSoldierIndex, &uiMercFlags , FINDSOLDIERSAMELEVEL( gsInterfaceLevel ) | FIND_SOLDIER_BEGINSTACK ) )
|
|
{
|
|
gfHandleStack = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
if ( gfHandleStack )
|
|
{
|
|
// we are cycling now?
|
|
if ( !gSoldierStack.fUseGridNo )
|
|
{
|
|
gSoldierStack.bCur++;
|
|
}
|
|
|
|
gfUIForceReExamineCursorData = TRUE;
|
|
|
|
if ( gSoldierStack.bCur == gSoldierStack.bNum )
|
|
{
|
|
if ( !gSoldierStack.fUseGridNo )
|
|
{
|
|
gSoldierStack.fUseGridNo = TRUE;
|
|
gUIActionModeChangeDueToMouseOver = FALSE;
|
|
gSoldierStack.sUseGridNoGridNo = usMapPos;
|
|
}
|
|
else
|
|
{
|
|
gSoldierStack.bCur = 0;
|
|
gSoldierStack.fUseGridNo = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
if ( !gSoldierStack.fUseGridNo )
|
|
{
|
|
gusUIFullTargetID = gSoldierStack.ubIDs[ gSoldierStack.bCur ];
|
|
guiUIFullTargetFlags = GetSoldierFindFlags( gusUIFullTargetID );
|
|
guiUITargetSoldierId = gusUIFullTargetID;
|
|
gfUIFullTargetFound = TRUE;
|
|
}
|
|
else
|
|
{
|
|
gfUIFullTargetFound = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// Return if we are in the cycle mode now...
|
|
return( gfHandleStack );
|
|
}
|
|
|
|
|
|
SOLDIERTYPE * SimpleFindSoldier( INT32 sGridNo, INT8 bLevel )
|
|
{
|
|
UINT8 ubID;
|
|
|
|
ubID = WhoIsThere2( sGridNo, bLevel );
|
|
if ( ubID == NOBODY )
|
|
{
|
|
return( NULL );
|
|
}
|
|
else
|
|
{
|
|
return( MercPtrs[ ubID ] );
|
|
}
|
|
}
|
|
|
|
BOOLEAN IsValidTargetMerc( UINT8 ubSoldierID )
|
|
{
|
|
SOLDIERTYPE *pSoldier = MercPtrs[ ubSoldierID ];
|
|
|
|
|
|
// CHECK IF ACTIVE!
|
|
if ( !pSoldier->bActive )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// CHECK IF DEAD
|
|
if( pSoldier->stats.bLife == 0 )
|
|
{
|
|
//return( FALSE );
|
|
}
|
|
|
|
// IF BAD GUY - CHECK VISIVILITY
|
|
if ( pSoldier->bTeam != gbPlayerNum )
|
|
{
|
|
if ( pSoldier->bVisible == -1 && !(gTacticalStatus.uiFlags&SHOW_ALL_MERCS) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN IsGridNoInScreenRect( INT32 sGridNo, SGPRect *pRect )
|
|
{
|
|
INT32 iXTrav, iYTrav;
|
|
INT32 sMapPos;
|
|
|
|
// Start with top left corner
|
|
iXTrav = pRect->iLeft;
|
|
iYTrav = pRect->iTop;
|
|
|
|
do
|
|
{
|
|
do
|
|
{
|
|
GetScreenXYGridNo( (INT16)iXTrav, (INT16)iYTrav, &sMapPos );
|
|
|
|
if ( sMapPos == sGridNo )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
iXTrav += WORLD_TILE_X;
|
|
|
|
} while( iXTrav < pRect->iRight );
|
|
|
|
iYTrav += WORLD_TILE_Y;
|
|
iXTrav = pRect->iLeft;
|
|
|
|
} while( iYTrav < pRect->iBottom );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
void GetSoldierScreenRect( SOLDIERTYPE *pSoldier, SGPRect *pRect )
|
|
{
|
|
INT16 sMercScreenX, sMercScreenY;
|
|
UINT16 usAnimSurface;
|
|
// ETRLEObject *pTrav;
|
|
// UINT32 usHeight, usWidth;
|
|
|
|
GetSoldierScreenPos( pSoldier, &sMercScreenX, &sMercScreenY );
|
|
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
|
|
{
|
|
pRect->iLeft = sMercScreenX;
|
|
pRect->iTop = sMercScreenY;
|
|
pRect->iBottom = sMercScreenY + 5;
|
|
pRect->iRight = sMercScreenX + 5;
|
|
|
|
return;
|
|
}
|
|
|
|
//pTrav = &(gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pETRLEObject[ pSoldier->usAniFrame ] );
|
|
//usHeight = (UINT32)pTrav->usHeight;
|
|
//usWidth = (UINT32)pTrav->usWidth;
|
|
|
|
pRect->iLeft = sMercScreenX;
|
|
pRect->iTop = sMercScreenY;
|
|
pRect->iBottom = sMercScreenY + pSoldier->sBoundingBoxHeight;
|
|
pRect->iRight = sMercScreenX + pSoldier->sBoundingBoxWidth;
|
|
}
|
|
|
|
void GetSoldierAnimDims( SOLDIERTYPE *pSoldier, INT16 *psHeight, INT16 *psWidth )
|
|
{
|
|
UINT16 usAnimSurface;
|
|
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
|
|
{
|
|
*psHeight = (INT16)5;
|
|
*psWidth = (INT16)5;
|
|
|
|
return;
|
|
}
|
|
|
|
// OK, noodle here on what we should do... If we take each frame, it will be different slightly
|
|
// depending on the frame and the value returned here will vary thusly. However, for the
|
|
// uses of this function, we should be able to use just the first frame...
|
|
|
|
*psHeight = (INT16)pSoldier->sBoundingBoxHeight;
|
|
*psWidth = (INT16)pSoldier->sBoundingBoxWidth;
|
|
}
|
|
|
|
void GetSoldierAnimOffsets( SOLDIERTYPE *pSoldier, INT16 *sOffsetX, INT16 *sOffsetY )
|
|
{
|
|
UINT16 usAnimSurface;
|
|
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
|
|
{
|
|
*sOffsetX = (INT16)0;
|
|
*sOffsetY = (INT16)0;
|
|
|
|
return;
|
|
}
|
|
|
|
*sOffsetX = (INT16)pSoldier->sBoundingBoxOffsetX;
|
|
*sOffsetY = (INT16)pSoldier->sBoundingBoxOffsetY;
|
|
}
|
|
|
|
void GetSoldierScreenPos( SOLDIERTYPE *pSoldier, INT16 *psScreenX, INT16 *psScreenY )
|
|
{
|
|
INT16 sMercScreenX, sMercScreenY;
|
|
FLOAT dOffsetX, dOffsetY;
|
|
FLOAT dTempX_S, dTempY_S;
|
|
UINT16 usAnimSurface;
|
|
// ETRLEObject *pTrav;
|
|
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
|
|
{
|
|
*psScreenX = 0;
|
|
*psScreenY = 0;
|
|
return;
|
|
}
|
|
|
|
// Get 'TRUE' merc position
|
|
dOffsetX = pSoldier->dXPos - gsRenderCenterX;
|
|
dOffsetY = pSoldier->dYPos - gsRenderCenterY;
|
|
|
|
FloatFromCellToScreenCoordinates( dOffsetX, dOffsetY, &dTempX_S, &dTempY_S );
|
|
|
|
//pTrav = &(gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->pETRLEObject[ pSoldier->usAniFrame ] );
|
|
|
|
sMercScreenX = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) + (INT16)dTempX_S;
|
|
sMercScreenY = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + (INT16)dTempY_S;
|
|
|
|
// Adjust starting screen coordinates
|
|
sMercScreenX -= gsRenderWorldOffsetX;
|
|
sMercScreenY -= gsRenderWorldOffsetY;
|
|
sMercScreenY -= gpWorldLevelData[ pSoldier->sGridNo ].sHeight;
|
|
|
|
// Adjust for render height
|
|
sMercScreenY += gsRenderHeight;
|
|
|
|
// Add to start position of dest buffer
|
|
//sMercScreenX += pTrav->sOffsetX;
|
|
//sMercScreenY += pTrav->sOffsetY;
|
|
sMercScreenX += pSoldier->sBoundingBoxOffsetX;
|
|
sMercScreenY += pSoldier->sBoundingBoxOffsetY;
|
|
|
|
|
|
sMercScreenY -= pSoldier->sHeightAdjustment;
|
|
|
|
*psScreenX = sMercScreenX;
|
|
*psScreenY = sMercScreenY;
|
|
}
|
|
|
|
// THE TRUE SCREN RECT DOES NOT TAKE THE OFFSETS OF BUDDY INTO ACCOUNT!
|
|
void GetSoldierTRUEScreenPos( SOLDIERTYPE *pSoldier, INT16 *psScreenX, INT16 *psScreenY )
|
|
{
|
|
INT16 sMercScreenX, sMercScreenY;
|
|
FLOAT dOffsetX, dOffsetY;
|
|
FLOAT dTempX_S, dTempY_S;
|
|
UINT16 usAnimSurface;
|
|
|
|
usAnimSurface = GetSoldierAnimationSurface( pSoldier, pSoldier->usAnimState );
|
|
|
|
if ( usAnimSurface == INVALID_ANIMATION_SURFACE )
|
|
{
|
|
*psScreenX = 0;
|
|
*psScreenY = 0;
|
|
return;
|
|
}
|
|
|
|
// Get 'TRUE' merc position
|
|
dOffsetX = pSoldier->dXPos - gsRenderCenterX;
|
|
dOffsetY = pSoldier->dYPos - gsRenderCenterY;
|
|
|
|
FloatFromCellToScreenCoordinates( dOffsetX, dOffsetY, &dTempX_S, &dTempY_S );
|
|
|
|
sMercScreenX = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) + (INT16)dTempX_S;
|
|
sMercScreenY = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + (INT16)dTempY_S;
|
|
|
|
// Adjust starting screen coordinates
|
|
sMercScreenX -= gsRenderWorldOffsetX;
|
|
sMercScreenY -= gsRenderWorldOffsetY;
|
|
|
|
// Adjust for render height
|
|
sMercScreenY += gsRenderHeight;
|
|
sMercScreenY -= gpWorldLevelData[ pSoldier->sGridNo ].sHeight;
|
|
|
|
sMercScreenY -= pSoldier->sHeightAdjustment;
|
|
|
|
|
|
*psScreenX = sMercScreenX;
|
|
*psScreenY = sMercScreenY;
|
|
}
|
|
|
|
|
|
BOOLEAN GridNoOnScreen( INT32 sGridNo )
|
|
{
|
|
INT16 sNewCenterWorldX, sNewCenterWorldY;
|
|
INT16 sWorldX;
|
|
INT16 sWorldY;
|
|
INT16 sAllowance = 20;
|
|
|
|
if ( gsVIEWPORT_WINDOW_START_Y == 20 )
|
|
{
|
|
sAllowance = 40;
|
|
}
|
|
|
|
ConvertGridNoToXY( sGridNo, &sNewCenterWorldX, &sNewCenterWorldY );
|
|
|
|
// Get screen coordinates for current position of soldier
|
|
GetWorldXYAbsoluteScreenXY( (INT16)(sNewCenterWorldX), (INT16)(sNewCenterWorldY), &sWorldX, &sWorldY);
|
|
|
|
// ATE: OK, here, adjust the top value so that it's a tile and a bit over, because of our mercs!
|
|
if ( sWorldX >= gsTopLeftWorldX && sWorldX <= gsBottomRightWorldX &&
|
|
sWorldY >= ( gsTopLeftWorldY + sAllowance ) && sWorldY <= ( gsBottomRightWorldY + 20 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN SoldierOnScreen( UINT16 usID )
|
|
{
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
// Get pointer of soldier
|
|
pSoldier = MercPtrs[ usID ];
|
|
|
|
return( GridNoOnScreen( pSoldier->sGridNo ) );
|
|
}
|
|
|
|
|
|
BOOLEAN SoldierOnVisibleWorldTile( SOLDIERTYPE *pSoldier )
|
|
{
|
|
return( GridNoOnVisibleWorldTile( pSoldier->sGridNo ) );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN SoldierLocationRelativeToScreen( INT32 sGridNo, UINT16 usReasonID, INT8 *pbDirection, UINT32 *puiScrollFlags )
|
|
{
|
|
INT16 sWorldX;
|
|
INT16 sWorldY;
|
|
INT16 sY, sX;
|
|
static BOOLEAN fCountdown = 0;
|
|
INT16 sScreenCenterX, sScreenCenterY;
|
|
INT16 sDistToCenterY, sDistToCenterX;
|
|
|
|
*puiScrollFlags = 0;
|
|
|
|
ConvertGridNoToCenterCellXY(sGridNo, &sX, &sY);
|
|
|
|
// Get screen coordinates for current position of soldier
|
|
GetWorldXYAbsoluteScreenXY( (INT16)(sX/CELL_X_SIZE), (INT16)(sY/CELL_Y_SIZE), &sWorldX, &sWorldY);
|
|
|
|
// Find the diustance from render center to true world center
|
|
sDistToCenterX = gsRenderCenterX - gCenterWorldX;
|
|
sDistToCenterY = gsRenderCenterY - gCenterWorldY;
|
|
|
|
// From render center in world coords, convert to render center in "screen" coords
|
|
FromCellToScreenCoordinates( sDistToCenterX , sDistToCenterY, &sScreenCenterX, &sScreenCenterY );
|
|
|
|
// Subtract screen center
|
|
sScreenCenterX += gsCX;
|
|
sScreenCenterY += gsCY;
|
|
|
|
// Adjust for offset origin!
|
|
sScreenCenterX += 0;
|
|
sScreenCenterY += 10;
|
|
|
|
// Get direction
|
|
//*pbDirection = atan8( sScreenCenterX, sScreenCenterY, sWorldX, sWorldY );
|
|
*pbDirection = atan8( gsRenderCenterX, gsRenderCenterY, (INT16)(sX), (INT16)(sY) );
|
|
|
|
// Check values!
|
|
if ( sWorldX > ( sScreenCenterX + 20 ) )
|
|
{
|
|
(*puiScrollFlags) |= SCROLL_RIGHT;
|
|
}
|
|
if ( sWorldX < ( sScreenCenterX - 20 ) )
|
|
{
|
|
(*puiScrollFlags) |= SCROLL_LEFT;
|
|
}
|
|
if ( sWorldY > ( sScreenCenterY + 20 ) )
|
|
{
|
|
(*puiScrollFlags) |= SCROLL_DOWN;
|
|
}
|
|
if ( sWorldY < ( sScreenCenterY - 20 ) )
|
|
{
|
|
(*puiScrollFlags) |= SCROLL_UP;
|
|
}
|
|
|
|
|
|
// If we are on screen, stop
|
|
if ( sWorldX >= gsTopLeftWorldX && sWorldX <= gsBottomRightWorldX &&
|
|
sWorldY >= gsTopLeftWorldY && sWorldY <= ( gsBottomRightWorldY + 20 ) )
|
|
{
|
|
// CHECK IF WE ARE DONE...
|
|
if ( fCountdown > gScrollSlideInertiaDirection[ *pbDirection ] )
|
|
{
|
|
fCountdown = 0;
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
fCountdown++;
|
|
}
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN IsPointInSoldierBoundingBox( SOLDIERTYPE *pSoldier, INT16 sX, INT16 sY )
|
|
{
|
|
SGPRect aRect;
|
|
|
|
// Get Rect contained in the soldier
|
|
GetSoldierScreenRect( pSoldier, &aRect );
|
|
|
|
if ( IsPointInScreenRect( sX, sY, &aRect ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN FindRelativeSoldierPosition( SOLDIERTYPE *pSoldier, UINT16 *usFlags, INT16 sX, INT16 sY )
|
|
{
|
|
SGPRect aRect;
|
|
INT16 sRelX, sRelY;
|
|
FLOAT dRelPer;
|
|
|
|
// Get Rect contained in the soldier
|
|
GetSoldierScreenRect( pSoldier, &aRect );
|
|
|
|
if ( IsPointInScreenRectWithRelative( sX, sY, &aRect, &sRelX, &sRelY ) )
|
|
{
|
|
dRelPer = (FLOAT)sRelY / ( aRect.iBottom - aRect.iTop );
|
|
|
|
// Determine relative positions
|
|
switch( gAnimControl[ pSoldier->usAnimState ].ubHeight )
|
|
{
|
|
case ANIM_STAND:
|
|
|
|
if ( dRelPer < .2 )
|
|
{
|
|
(*usFlags )= TILE_FLAG_HEAD;
|
|
return( TRUE );
|
|
}
|
|
else if ( dRelPer < .6 )
|
|
{
|
|
(*usFlags )= TILE_FLAG_MID;
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
(*usFlags )= TILE_FLAG_FEET;
|
|
return( TRUE );
|
|
}
|
|
break;
|
|
|
|
case ANIM_CROUCH:
|
|
|
|
if ( dRelPer < .2 )
|
|
{
|
|
(*usFlags )= TILE_FLAG_HEAD;
|
|
return( TRUE );
|
|
}
|
|
else if ( dRelPer < .7 )
|
|
{
|
|
(*usFlags )= TILE_FLAG_MID;
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
(*usFlags )= TILE_FLAG_FEET;
|
|
return( TRUE );
|
|
}
|
|
break;
|
|
|
|
case ANIM_PRONE:
|
|
{
|
|
// Flugente: if we are prone, determining what part of the body we are aiming for is trickier.
|
|
// Instead of focusing on relative height, we simply determine whether we are looking at the gridno the body itself is at, or an adjacent gridno.
|
|
// Then, depending on whether this is the gridno we are looking at, this will be head or legs
|
|
if ( gGameExternalOptions.fAllowTargetHeadAndLegIfProne )
|
|
{
|
|
INT16 sWorldX, sWorldY, sX, sY;
|
|
GetMouseWorldCoords( &sWorldX, &sWorldY );
|
|
|
|
// Flugente: we measure the distance of the bullet's location to the location of the soldier, and to the 2 gridnos his head and leg occupy
|
|
// From this we can decide what body part was hit
|
|
ConvertGridNoToCenterCellXY(pSoldier->sGridNo, &sX, &sY);
|
|
FLOAT bodycenterX = (FLOAT) sX;
|
|
FLOAT bodycenterY = (FLOAT) sY;
|
|
|
|
FLOAT difftobodycenter = sqrt( (bodycenterX - sWorldX) * (bodycenterX - sWorldX) + (bodycenterY - sWorldY) * (bodycenterY - sWorldY) );
|
|
|
|
INT32 viewdirectiongridno = NewGridNo( pSoldier->sGridNo, DirectionInc( pSoldier->ubDirection ) );
|
|
ConvertGridNoToCenterCellXY(viewdirectiongridno, &sX, &sY);
|
|
FLOAT nextgridnocenterX = (FLOAT) sX;
|
|
FLOAT nextgridnocenterY = (FLOAT) sY;
|
|
|
|
FLOAT difftonextgridno = sqrt( (nextgridnocenterX - sWorldX) * (nextgridnocenterX - sWorldX) + (nextgridnocenterY - sWorldY) * (nextgridnocenterY - sWorldY) );
|
|
|
|
INT32 oppositeviewdirectiongridno = NewGridNo( pSoldier->sGridNo, DirectionInc( gOppositeDirection[pSoldier->ubDirection] ) );
|
|
ConvertGridNoToCenterCellXY(oppositeviewdirectiongridno, &sX, &sY);
|
|
FLOAT oppositenextgridnocenterX = (FLOAT) sX;
|
|
FLOAT oppositenextgridnocenterY = (FLOAT) sY;
|
|
|
|
FLOAT difftooppositenextgridno = sqrt( (oppositenextgridnocenterX - sWorldX) * (oppositenextgridnocenterX - sWorldX) + (oppositenextgridnocenterY - sWorldY) * (oppositenextgridnocenterY - sWorldY) );
|
|
|
|
if ( difftobodycenter < difftonextgridno )
|
|
{
|
|
if ( difftobodycenter < difftooppositenextgridno )
|
|
{
|
|
(*usFlags) = TILE_FLAG_MID;
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
(*usFlags) = TILE_FLAG_FEET;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*usFlags) = TILE_FLAG_HEAD;
|
|
return(TRUE);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
// VERY quickly finds a soldier at gridno , ( that is visible )
|
|
UINT8 QuickFindSoldier( INT32 sGridNo )
|
|
{
|
|
UINT32 cnt;
|
|
SOLDIERTYPE *pSoldier = NULL;
|
|
|
|
// Loop through all mercs and make go
|
|
for ( cnt = 0; cnt < guiNumMercSlots; cnt++ )
|
|
{
|
|
pSoldier = MercSlots[ cnt ];
|
|
|
|
if ( pSoldier != NULL )
|
|
{
|
|
if ( pSoldier->sGridNo == sGridNo && pSoldier->bVisible != -1 )
|
|
{
|
|
return( (UINT8)cnt );
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return( NOBODY );
|
|
}
|
|
|
|
|
|
void GetGridNoScreenPos( INT32 sGridNo, UINT8 ubLevel, INT16 *psScreenX, INT16 *psScreenY )
|
|
{
|
|
INT16 sScreenX, sScreenY, sX, sY;
|
|
FLOAT dOffsetX, dOffsetY;
|
|
FLOAT dTempX_S, dTempY_S;
|
|
|
|
ConvertGridNoToCenterCellXY(sGridNo, &sX, &sY);
|
|
|
|
// Get 'TRUE' merc position
|
|
dOffsetX = (FLOAT)( sX - gsRenderCenterX );
|
|
dOffsetY = (FLOAT)( sY - gsRenderCenterY );
|
|
|
|
// OK, DONT'T ASK... CONVERSION TO PROPER Y NEEDS THIS...
|
|
dOffsetX -= CELL_Y_SIZE;
|
|
|
|
FloatFromCellToScreenCoordinates( dOffsetX, dOffsetY, &dTempX_S, &dTempY_S );
|
|
|
|
sScreenX = ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ) + (INT16)dTempX_S;
|
|
sScreenY = ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + (INT16)dTempY_S;
|
|
|
|
// Adjust starting screen coordinates
|
|
sScreenX -= gsRenderWorldOffsetX;
|
|
sScreenY -= gsRenderWorldOffsetY;
|
|
|
|
sScreenY += gsRenderHeight;
|
|
|
|
// Adjust for world height
|
|
sScreenY -= gpWorldLevelData[ sGridNo ].sHeight;
|
|
|
|
// Adjust for level height
|
|
if ( ubLevel )
|
|
{
|
|
sScreenY -= ROOF_LEVEL_HEIGHT;
|
|
}
|
|
|
|
*psScreenX = sScreenX;
|
|
*psScreenY = sScreenY;
|
|
}
|
|
|
|
|