mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
Added missing #includes Added LUA scripting and console Changed the way tracers are visualized, so they work more like real tracers instead of a light fountain Fixed signedness of many grid variables used in GetMouseMapPos calls Fixed enemy weapon choosing: Sometimes a mortar is chosen but later rejected, but the grenade class was not reset. Caused assertion failure Added checks so enemies don't try to chuck RPG grenades with their hands Now possible to shoot a someone in the head if he's in water Fixed InitSightArrays to also clear soldier interrupt duel points. This was causing an assertion failure elsewhere in the code because the interrupt list still had soldiers on it sometimes when this function was called. Soldiers are much less willing to forfeit their turn over an attempt to use more APs than they have Removed early setting of muzzle flash. This would allow enemies to get an interrupt before you even fired. Fixed item dropping by AI. If AI tried to drop something while standing it would cause deadlock Change to greatly speed up closing the sector inventory window in an unloaded sector Added conditional compile flag to always give robot weapon ready advantage, even for 360 degree sighting Check builddefines.h for the conditional flags. Of greatest interest might be LUA_CONSOLE. This will cause the game to bring up a command console when run. However this console is severely lacking in many areas. If anybody knows of an open-source terminal/console that could be used instead, it would be appreciated. The existing console does bad things when you try to close it, and since it counts as a separate app, it pauses the game while it has focus. LUA scripting is very limited, basically just proof of concept. There is one global variable, the Soldiers array. An array index gives you the soldier in that slot in the currently loaded sector. The soldier has a few things that can be accessed: name (short name); fullname (long name); grid (current grid #, can be changed); walkto(grid) (function to walk to another grid); runto(grid) (function to run to another grid) git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@924 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1035 lines
25 KiB
C++
1035 lines
25 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Tactical All.h"
|
|
#else
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "wcheck.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 "Timer Control.h"
|
|
#include "Render Fun.h"
|
|
#include "Render Dirty.h"
|
|
#include "mousesystem.h"
|
|
#include "interface.h"
|
|
#include "sysutil.h"
|
|
#include "FileMan.h"
|
|
#include "points.h"
|
|
#include "Random.h"
|
|
#include "ai.h"
|
|
#include "Interactive Tiles.h"
|
|
#include "soldier ani.h"
|
|
#include "english.h"
|
|
#include "overhead.h"
|
|
#include "opplist.h"
|
|
#include "Sound Control.h"
|
|
#include "Font Control.h"
|
|
#include "lighting.h"
|
|
#include "pathai.h"
|
|
#include "screenids.h"
|
|
#include "interface cursors.h"
|
|
#include "weapons.h"
|
|
#include "lighting.h"
|
|
#include "Handle UI Plan.h"
|
|
#include "structure.h"
|
|
#include "interface panels.h"
|
|
#include "message.h"
|
|
#include "items.h"
|
|
#include "Soldier Profile.h"
|
|
#include "fov.h"
|
|
#include "Soldier macros.h"
|
|
#include "EditorMercs.h"
|
|
#include "soldier tile.h"
|
|
#include "soldier find.h"
|
|
#include "Vehicles.h"
|
|
#include "GameSettings.h"
|
|
#include "ui cursors.h"
|
|
#endif
|
|
|
|
|
|
BOOLEAN IsGridNoInScreenRect( INT16 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;
|
|
UINT16 sUseGridNoGridNo;
|
|
|
|
} SOLDIER_STACK_TYPE;
|
|
|
|
SOLDIER_STACK_TYPE gSoldierStack;
|
|
BOOLEAN gfHandleStack = FALSE;
|
|
|
|
extern BOOLEAN gUIActionModeChangeDueToMouseOver;
|
|
extern UINT32 guiUITargetSoldierId;
|
|
|
|
|
|
BOOLEAN FindSoldierFromMouse( UINT16 *pusSoldierIndex, UINT32 *pMercFlags )
|
|
{
|
|
UINT16 usMapPos;
|
|
|
|
*pMercFlags = 0;
|
|
|
|
if ( GetMouseMapPos( &usMapPos ) )
|
|
{
|
|
if ( FindSoldier( usMapPos, pusSoldierIndex, pMercFlags ,FINDSOLDIERSAMELEVEL( gsInterfaceLevel ) ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN SelectiveFindSoldierFromMouse( UINT16 *pusSoldierIndex, UINT32 *pMercFlags )
|
|
{
|
|
UINT16 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->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->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->bLife < OKLIFE )
|
|
{
|
|
MercFlags |= UNCONSCIOUS_MERC;
|
|
}
|
|
|
|
if ( pSoldier->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( INT16 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->uiStatusFlags & SOLDIER_DEAD ) && ( pSoldier->bVisible != -1 || (gTacticalStatus.uiFlags&SHOW_ALL_MERCS) ) )
|
|
{
|
|
// OK, ignore if we are a passenger...
|
|
if ( pSoldier->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->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->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( UINT16 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( INT16 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->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( INT16 sGridNo, SGPRect *pRect )
|
|
{
|
|
INT32 iXTrav, iYTrav;
|
|
INT16 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...
|
|
|
|
if ( pSoldier->usAniFrame >= gAnimSurfaceDatabase[ usAnimSurface ].hVideoObject->usNumberOfObjects )
|
|
{
|
|
int i = 0;
|
|
}
|
|
|
|
*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( INT16 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( INT16 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;
|
|
|
|
sX = CenterX( sGridNo );
|
|
sY = CenterY( sGridNo );
|
|
|
|
// 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;
|
|
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
// VERY quickly finds a soldier at gridno , ( that is visible )
|
|
UINT8 QuickFindSoldier( INT16 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( INT16 sGridNo, UINT8 ubLevel, INT16 *psScreenX, INT16 *psScreenY )
|
|
{
|
|
INT16 sScreenX, sScreenY;
|
|
FLOAT dOffsetX, dOffsetY;
|
|
FLOAT dTempX_S, dTempY_S;
|
|
|
|
// Get 'TRUE' merc position
|
|
dOffsetX = (FLOAT)( CenterX( sGridNo ) - gsRenderCenterX );
|
|
dOffsetY = (FLOAT)( CenterY( sGridNo ) - 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;
|
|
}
|
|
|