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
1084 lines
24 KiB
C++
1084 lines
24 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "TileEngine All.h"
|
|
#else
|
|
#include <stdio.h>
|
|
#include "debug.h"
|
|
#include "wcheck.h"
|
|
#include "mousesystem.h"
|
|
#include "jascreens.h"
|
|
#include "worlddef.h"
|
|
#include "renderworld.h"
|
|
#include "Isometric Utils.h"
|
|
#include "interface.h"
|
|
#include "math.h"
|
|
#include "worldman.h"
|
|
#include "Structure Wrap.h"
|
|
#include "sys globals.h"
|
|
#include "overhead.h"
|
|
#include "Random.h"
|
|
#include "Pathai.h"
|
|
#endif
|
|
|
|
|
|
UINT32 guiForceRefreshMousePositionCalculation = 0;
|
|
|
|
// GLOBALS
|
|
INT16 DirIncrementer[8] =
|
|
{
|
|
-MAPWIDTH, //N
|
|
1-MAPWIDTH, //NE
|
|
1, //E
|
|
1+MAPWIDTH, //SE
|
|
MAPWIDTH, //S
|
|
MAPWIDTH-1, //SW
|
|
-1, //W
|
|
-MAPWIDTH-1 //NW
|
|
|
|
};
|
|
|
|
// Opposite directions
|
|
UINT8 gOppositeDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST
|
|
|
|
};
|
|
|
|
UINT8 gTwoCCDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST
|
|
|
|
};
|
|
|
|
UINT8 gTwoCDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
EAST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST
|
|
|
|
};
|
|
|
|
|
|
UINT8 gOneCDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH
|
|
};
|
|
|
|
UINT8 gOneCCDirection[ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
WEST
|
|
};
|
|
|
|
// DIRECTION FACING DIRECTION WE WANT TO GOTO
|
|
UINT8 gPurpendicularDirection[ NUM_WORLD_DIRECTIONS ][ NUM_WORLD_DIRECTIONS ] =
|
|
{
|
|
// NORTH
|
|
WEST, // EITHER
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST,
|
|
EAST, // EITHER
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST,
|
|
|
|
// NORTH EAST
|
|
NORTHWEST,
|
|
NORTHWEST, // EITHER
|
|
SOUTH,
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST, // EITHER
|
|
NORTH,
|
|
NORTHEAST,
|
|
|
|
// EAST
|
|
EAST,
|
|
SOUTHEAST,
|
|
NORTH, // EITHER
|
|
NORTHEAST,
|
|
EAST,
|
|
SOUTHEAST,
|
|
NORTH, // EITHER
|
|
NORTHEAST,
|
|
|
|
// SOUTHEAST
|
|
EAST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST, // EITHER
|
|
SOUTHWEST,
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST, // EITHER
|
|
|
|
// SOUTH
|
|
WEST, // EITHER
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
EAST, // EITHER
|
|
SOUTHEAST,
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
|
|
// SOUTHWEST
|
|
WEST,
|
|
NORTHWEST, // EITHER
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
WEST,
|
|
SOUTHEAST, // EITHER
|
|
SOUTH,
|
|
SOUTHWEST,
|
|
|
|
// WEST
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH, // EITHER
|
|
SOUTHWEST,
|
|
WEST,
|
|
NORTHWEST,
|
|
SOUTH, // EITHER
|
|
SOUTHWEST,
|
|
|
|
// NORTHWEST
|
|
WEST,
|
|
NORTHWEST,
|
|
NORTH,
|
|
SOUTHWEST, // EITHER
|
|
SOUTHWEST,
|
|
NORTHWEST,
|
|
NORTH,
|
|
NORTHEAST, // EITHER
|
|
};
|
|
|
|
|
|
void FromCellToScreenCoordinates( INT16 sCellX, INT16 sCellY, INT16 *psScreenX, INT16 *psScreenY )
|
|
{
|
|
*psScreenX = ( 2 * sCellX ) - ( 2 * sCellY );
|
|
*psScreenY = sCellX + sCellY;
|
|
|
|
}
|
|
|
|
void FromScreenToCellCoordinates( INT16 sScreenX, INT16 sScreenY, INT16 *psCellX, INT16 *psCellY )
|
|
{
|
|
*psCellX = ( ( sScreenX + ( 2 * sScreenY ) ) / 4 );
|
|
*psCellY = ( ( 2 * sScreenY ) - sScreenX ) / 4;
|
|
}
|
|
|
|
// These two functions take into account that our world is projected and attached
|
|
// to the screen (0,0) in a specific way, and we MUSt take that into account then
|
|
// determining screen coords
|
|
|
|
void FloatFromCellToScreenCoordinates( FLOAT dCellX, FLOAT dCellY, FLOAT *pdScreenX, FLOAT *pdScreenY )
|
|
{
|
|
FLOAT dScreenX, dScreenY;
|
|
|
|
dScreenX = ( 2 * dCellX ) - ( 2 * dCellY );
|
|
dScreenY = dCellX + dCellY;
|
|
|
|
*pdScreenX = dScreenX;
|
|
*pdScreenY = dScreenY;
|
|
}
|
|
|
|
void FloatFromScreenToCellCoordinates( FLOAT dScreenX, FLOAT dScreenY, FLOAT *pdCellX, FLOAT *pdCellY )
|
|
{
|
|
FLOAT dCellX, dCellY;
|
|
|
|
dCellX = ( ( dScreenX + ( 2 * dScreenY ) ) / 4 );
|
|
dCellY = ( ( 2 * dScreenY ) - dScreenX ) / 4;
|
|
|
|
*pdCellX = dCellX;
|
|
*pdCellY = dCellY;
|
|
}
|
|
|
|
|
|
BOOLEAN GetMouseXY( INT16 *psMouseX, INT16 *psMouseY )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
|
|
if ( !GetMouseWorldCoords( &sWorldX, &sWorldY ) )
|
|
{
|
|
(*psMouseX) = 0;
|
|
(*psMouseY) = 0;
|
|
return( FALSE );
|
|
}
|
|
|
|
// Find start block
|
|
(*psMouseX) = ( sWorldX / CELL_X_SIZE );
|
|
(*psMouseY) = ( sWorldY / CELL_Y_SIZE );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN GetMouseXYWithRemainder( INT16 *psMouseX, INT16 *psMouseY, INT16 *psCellX, INT16 *psCellY )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
|
|
if ( !GetMouseWorldCoords( &sWorldX, &sWorldY ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Find start block
|
|
(*psMouseX) = ( sWorldX / CELL_X_SIZE );
|
|
(*psMouseY) = ( sWorldY / CELL_Y_SIZE );
|
|
|
|
(*psCellX ) = sWorldX - ( (*psMouseX) * CELL_X_SIZE );
|
|
(*psCellY ) = sWorldY - ( (*psMouseY) * CELL_Y_SIZE );
|
|
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN GetMouseWorldCoords( INT16 *psMouseX, INT16 *psMouseY )
|
|
{
|
|
INT16 sOffsetX, sOffsetY;
|
|
INT16 sTempPosX_W, sTempPosY_W;
|
|
INT16 sStartPointX_W, sStartPointY_W;
|
|
|
|
// Convert mouse screen coords into offset from center
|
|
if ( ! ( gViewportRegion.uiFlags & MSYS_MOUSE_IN_AREA ) )
|
|
{
|
|
*psMouseX = 0;
|
|
*psMouseY = 0;
|
|
return( FALSE );
|
|
}
|
|
|
|
sOffsetX = gViewportRegion.MouseXPos - ( ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2 ); // + gsRenderWorldOffsetX;
|
|
sOffsetY = gViewportRegion.MouseYPos - ( ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2 ) + 10;// + gsRenderWorldOffsetY;
|
|
|
|
// OK, Let's offset by a value if our interfac level is changed!
|
|
if ( gsInterfaceLevel != 0 )
|
|
{
|
|
//sOffsetY -= 50;
|
|
}
|
|
|
|
|
|
FromScreenToCellCoordinates( sOffsetX, sOffsetY, &sTempPosX_W, &sTempPosY_W );
|
|
|
|
// World start point is Render center plus this distance
|
|
sStartPointX_W = gsRenderCenterX + sTempPosX_W;
|
|
sStartPointY_W = gsRenderCenterY + sTempPosY_W;
|
|
|
|
|
|
// check if we are out of bounds..
|
|
if ( sStartPointX_W < 0 || sStartPointX_W >= WORLD_COORD_ROWS || sStartPointY_W < 0 || sStartPointY_W >= WORLD_COORD_COLS )
|
|
{
|
|
*psMouseX = 0;
|
|
*psMouseY = 0;
|
|
return( FALSE );
|
|
}
|
|
|
|
// Determine Start block and render offsets
|
|
// Find start block
|
|
// Add adjustment for render origin as well
|
|
(*psMouseX) = sStartPointX_W;
|
|
(*psMouseY) = sStartPointY_W;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
BOOLEAN GetMouseWorldCoordsInCenter( INT16 *psMouseX, INT16 *psMouseY )
|
|
{
|
|
INT16 sMouseX, sMouseY;
|
|
|
|
// Get grid position
|
|
if ( !GetMouseXY( &sMouseX, &sMouseY ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Now adjust these cell coords into world coords
|
|
*psMouseX = ( ( sMouseX ) * CELL_X_SIZE ) + ( CELL_X_SIZE / 2 );
|
|
*psMouseY = ( ( sMouseY ) * CELL_Y_SIZE ) + ( CELL_Y_SIZE / 2 );
|
|
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
#if 0
|
|
// 0verhaul
|
|
// I did that (or actually uncasted a bunch of stuff and re-typed others to correct them), so
|
|
// no worries
|
|
// (jonathanl) to save me having to cast all the previous code
|
|
BOOLEAN GetMouseMapPos( UINT16 *psMapPos )
|
|
{
|
|
return GetMouseMapPos( (INT16 *)psMapPos );
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN GetMouseMapPos( UINT16 *pusMapPos )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
static INT16 sSameCursorPos;
|
|
static UINT32 uiOldFrameNumber = 99999;
|
|
|
|
// Check if this is the same frame as before, return already calculated value if so!
|
|
if ( uiOldFrameNumber == guiGameCycleCounter && !guiForceRefreshMousePositionCalculation )
|
|
{
|
|
( *pusMapPos ) = sSameCursorPos;
|
|
|
|
if ( sSameCursorPos == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
uiOldFrameNumber = guiGameCycleCounter;
|
|
guiForceRefreshMousePositionCalculation = FALSE;
|
|
|
|
|
|
if ( GetMouseXY( &sWorldX, &sWorldY ) )
|
|
{
|
|
*pusMapPos = MAPROWCOLTOPOS( sWorldY, sWorldX );
|
|
sSameCursorPos = (*pusMapPos);
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
*pusMapPos = 0;
|
|
sSameCursorPos = (*pusMapPos);
|
|
return( FALSE );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN ConvertMapPosToWorldTileCenter( UINT16 usMapPos, INT16 *psXPos, INT16 *psYPos )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
INT16 sCellX, sCellY;
|
|
|
|
// Get X, Y world GRID Coordinates
|
|
sWorldY = ( usMapPos / WORLD_COLS );
|
|
sWorldX = usMapPos - ( sWorldY * WORLD_COLS );
|
|
|
|
// Convert into cell coords
|
|
sCellY = sWorldY * CELL_Y_SIZE;
|
|
sCellX = sWorldX * CELL_X_SIZE;
|
|
|
|
// Add center tile positions
|
|
*psXPos = sCellX + ( CELL_X_SIZE / 2 );
|
|
*psYPos = sCellY + ( CELL_Y_SIZE / 2 );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
void GetScreenXYWorldCoords( INT16 sScreenX, INT16 sScreenY, INT16 *psWorldX, INT16 *psWorldY )
|
|
{
|
|
INT16 sOffsetX, sOffsetY;
|
|
INT16 sTempPosX_W, sTempPosY_W;
|
|
INT16 sStartPointX_W, sStartPointY_W;
|
|
|
|
// Convert mouse screen coords into offset from center
|
|
sOffsetX = sScreenX - ( gsVIEWPORT_END_X - gsVIEWPORT_START_X ) /2;
|
|
sOffsetY = sScreenY - ( gsVIEWPORT_END_Y - gsVIEWPORT_START_Y ) /2;
|
|
|
|
FromScreenToCellCoordinates( sOffsetX, sOffsetY, &sTempPosX_W, &sTempPosY_W );
|
|
|
|
// World start point is Render center plus this distance
|
|
sStartPointX_W = gsRenderCenterX + sTempPosX_W;
|
|
sStartPointY_W = gsRenderCenterY + sTempPosY_W;
|
|
|
|
// Determine Start block and render offsets
|
|
// Find start block
|
|
// Add adjustment for render origin as well
|
|
(*psWorldX) = sStartPointX_W;
|
|
(*psWorldY) = sStartPointY_W;
|
|
|
|
}
|
|
|
|
|
|
void GetScreenXYWorldCell( INT16 sScreenX, INT16 sScreenY, INT16 *psWorldCellX, INT16 *psWorldCellY )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
|
|
GetScreenXYWorldCoords( sScreenX, sScreenY, &sWorldX, &sWorldY );
|
|
|
|
// Find start block
|
|
(*psWorldCellX) = ( sWorldX / CELL_X_SIZE );
|
|
(*psWorldCellY) = ( sWorldY / CELL_Y_SIZE );
|
|
|
|
}
|
|
|
|
|
|
void GetScreenXYGridNo( INT16 sScreenX, INT16 sScreenY, INT16 *psMapPos )
|
|
{
|
|
INT16 sWorldX, sWorldY;
|
|
|
|
GetScreenXYWorldCell( sScreenX, sScreenY, &sWorldX, &sWorldY );
|
|
|
|
*psMapPos = MAPROWCOLTOPOS( sWorldY, sWorldX );
|
|
|
|
}
|
|
|
|
void GetWorldXYAbsoluteScreenXY( INT32 sWorldCellX, INT32 sWorldCellY, INT16 *psWorldScreenX, INT16 *psWorldScreenY )
|
|
{
|
|
INT16 sScreenCenterX, sScreenCenterY;
|
|
INT16 sDistToCenterY, sDistToCenterX;
|
|
|
|
// Find the diustance from render center to true world center
|
|
sDistToCenterX = ( sWorldCellX * CELL_X_SIZE ) - gCenterWorldX;
|
|
sDistToCenterY = ( sWorldCellY * CELL_Y_SIZE ) - gCenterWorldY;
|
|
|
|
|
|
// From render center in world coords, convert to render center in "screen" coords
|
|
|
|
// ATE: We should call the fowllowing function but I'm putting it here verbatim for speed
|
|
//FromCellToScreenCoordinates( sDistToCenterX , sDistToCenterY, &sScreenCenterX, &sScreenCenterY );
|
|
sScreenCenterX = ( 2 * sDistToCenterX ) - ( 2 * sDistToCenterY );
|
|
sScreenCenterY = sDistToCenterX + sDistToCenterY;
|
|
|
|
// Subtract screen center
|
|
*psWorldScreenX = sScreenCenterX + gsCX - gsTLX;
|
|
*psWorldScreenY = sScreenCenterY + gsCY - gsTLY;
|
|
|
|
}
|
|
|
|
|
|
void GetFromAbsoluteScreenXYWorldXY( INT32 *psWorldCellX, INT32* psWorldCellY, INT16 sWorldScreenX, INT16 sWorldScreenY )
|
|
{
|
|
INT16 sWorldCenterX, sWorldCenterY;
|
|
INT16 sDistToCenterY, sDistToCenterX;
|
|
|
|
// Subtract screen center
|
|
sDistToCenterX = sWorldScreenX - gsCX + gsTLX;
|
|
sDistToCenterY = sWorldScreenY - gsCY + gsTLY;
|
|
|
|
// From render center in world coords, convert to render center in "screen" coords
|
|
|
|
// ATE: We should call the fowllowing function but I'm putting it here verbatim for speed
|
|
//FromCellToScreenCoordinates( sDistToCenterX , sDistToCenterY, &sScreenCenterX, &sScreenCenterY );
|
|
sWorldCenterX = ( ( sDistToCenterX + ( 2 * sDistToCenterY ) ) / 4 );
|
|
sWorldCenterY = ( ( 2 * sDistToCenterY ) - sDistToCenterX ) / 4;
|
|
|
|
// Goto center again
|
|
*psWorldCellX = sWorldCenterX + gCenterWorldX;
|
|
*psWorldCellY = sWorldCenterY + gCenterWorldY;
|
|
|
|
}
|
|
|
|
|
|
// UTILITY FUNTIONS
|
|
|
|
INT32 OutOfBounds(INT16 sGridno, INT16 sProposedGridno)
|
|
{
|
|
INT16 sMod,sPropMod;
|
|
|
|
// get modulas of our origin
|
|
sMod = sGridno % MAXCOL;
|
|
|
|
if (sMod != 0) // if we're not on leftmost grid
|
|
if (sMod != RIGHTMOSTGRID) // if we're not on rightmost grid
|
|
if (sGridno < LASTROWSTART) // if we're above bottom row
|
|
if (sGridno > MAXCOL) // if we're below top row
|
|
// Everything's OK - we're not on the edge of the map
|
|
return(FALSE);
|
|
|
|
|
|
// if we've got this far, there's a potential problem - check it out!
|
|
|
|
if (sProposedGridno < 0)
|
|
return(TRUE);
|
|
|
|
sPropMod = sProposedGridno % MAXCOL;
|
|
|
|
if (sMod == 0 && sPropMod == RIGHTMOSTGRID)
|
|
return(TRUE);
|
|
else
|
|
if (sMod == RIGHTMOSTGRID && sPropMod == 0)
|
|
return(TRUE);
|
|
else
|
|
if (sGridno >= LASTROWSTART && sProposedGridno >= GRIDSIZE)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
|
|
INT16 NewGridNo(INT16 sGridno, INT16 sDirInc)
|
|
{
|
|
INT16 sProposedGridno = sGridno + sDirInc;
|
|
|
|
// now check for out-of-bounds
|
|
if (OutOfBounds(sGridno,sProposedGridno))
|
|
// return ORIGINAL gridno to user
|
|
sProposedGridno = sGridno;
|
|
|
|
return(sProposedGridno);
|
|
}
|
|
|
|
|
|
INT16 DirectionInc(INT16 sDirection)
|
|
{
|
|
if ((sDirection < 0) || (sDirection > 7))
|
|
{
|
|
|
|
//#ifdef BETAVERSION
|
|
// NumMessage("DirectionInc: Invalid direction received, = ",direction);
|
|
//#endif
|
|
|
|
//direction = random(8); // replace garbage with random direction
|
|
sDirection = 1;
|
|
}
|
|
|
|
|
|
return(DirIncrementer[sDirection]);
|
|
}
|
|
|
|
BOOLEAN CellXYToScreenXY(INT16 sCellX, INT16 sCellY, INT16 *sScreenX, INT16 *sScreenY)
|
|
{
|
|
INT16 sDeltaCellX, sDeltaCellY;
|
|
INT16 sDeltaScreenX, sDeltaScreenY;
|
|
|
|
sDeltaCellX=sCellX-gsRenderCenterX;
|
|
sDeltaCellY=sCellY-gsRenderCenterY;
|
|
|
|
FromCellToScreenCoordinates(sDeltaCellX, sDeltaCellY, &sDeltaScreenX, &sDeltaScreenY);
|
|
|
|
*sScreenX=(((gsVIEWPORT_END_X-gsVIEWPORT_START_X)/2)+sDeltaScreenX);
|
|
*sScreenY=(((gsVIEWPORT_END_Y-gsVIEWPORT_START_Y)/2)+sDeltaScreenY);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
void ConvertGridNoToXY( INT16 sGridNo, INT16 *sXPos, INT16 *sYPos )
|
|
{
|
|
*sYPos = sGridNo / WORLD_COLS;
|
|
*sXPos = ( sGridNo - ( *sYPos * WORLD_COLS ) );
|
|
}
|
|
|
|
void ConvertGridNoToCellXY( INT16 sGridNo, INT16 *sXPos, INT16 *sYPos )
|
|
{
|
|
*sYPos = ( sGridNo / WORLD_COLS );
|
|
*sXPos = sGridNo - ( *sYPos * WORLD_COLS );
|
|
|
|
*sYPos = ( *sYPos * CELL_Y_SIZE );
|
|
*sXPos = ( *sXPos * CELL_X_SIZE );
|
|
}
|
|
|
|
void ConvertGridNoToCenterCellXY( INT16 sGridNo, INT16 *sXPos, INT16 *sYPos )
|
|
{
|
|
*sYPos = ( sGridNo / WORLD_COLS );
|
|
*sXPos = ( sGridNo - ( *sYPos * WORLD_COLS ) );
|
|
|
|
*sYPos = ( *sYPos * CELL_Y_SIZE ) + ( CELL_Y_SIZE / 2 );
|
|
*sXPos = ( *sXPos * CELL_X_SIZE ) + ( CELL_X_SIZE / 2 );
|
|
}
|
|
|
|
INT32 GetRangeFromGridNoDiff( INT16 sGridNo1, INT16 sGridNo2 )
|
|
{
|
|
INT32 uiDist;
|
|
INT16 sXPos, sYPos, sXPos2, sYPos2;
|
|
|
|
// Convert our grid-not into an XY
|
|
ConvertGridNoToXY( sGridNo1, &sXPos, &sYPos );
|
|
|
|
// Convert our grid-not into an XY
|
|
ConvertGridNoToXY( sGridNo2, &sXPos2, &sYPos2 );
|
|
|
|
uiDist = (INT16)sqrt((double) ( sXPos2 - sXPos )*( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos ) );
|
|
|
|
return( uiDist );
|
|
}
|
|
|
|
INT32 GetRangeInCellCoordsFromGridNoDiff( INT16 sGridNo1, INT16 sGridNo2 )
|
|
{
|
|
INT16 sXPos, sYPos, sXPos2, sYPos2;
|
|
|
|
// Convert our grid-not into an XY
|
|
ConvertGridNoToXY( sGridNo1, &sXPos, &sYPos );
|
|
|
|
// Convert our grid-not into an XY
|
|
ConvertGridNoToXY( sGridNo2, &sXPos2, &sYPos2 );
|
|
|
|
return( (INT32)( sqrt((double) ( sXPos2 - sXPos ) * ( sXPos2 - sXPos ) + ( sYPos2 - sYPos ) * ( sYPos2 - sYPos ) ) ) * CELL_X_SIZE );
|
|
|
|
}
|
|
|
|
BOOLEAN IsPointInScreenRect( INT16 sXPos, INT16 sYPos, SGPRect *pRect )
|
|
{
|
|
if ( (sXPos >= pRect->iLeft) && (sXPos <= pRect->iRight) && (sYPos >= pRect->iTop) && (sYPos <= pRect->iBottom) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
BOOLEAN IsPointInScreenRectWithRelative( INT16 sXPos, INT16 sYPos, SGPRect *pRect, INT16 *sXRel, INT16 *sYRel )
|
|
{
|
|
if ( (sXPos >= pRect->iLeft) && (sXPos <= pRect->iRight) && (sYPos >= pRect->iTop) && (sYPos <= pRect->iBottom) )
|
|
{
|
|
(*sXRel) = pRect->iLeft - sXPos;
|
|
(*sYRel) = sYPos - (INT16)pRect->iTop;
|
|
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
INT16 PythSpacesAway(INT16 sOrigin, INT16 sDest)
|
|
{
|
|
INT16 sRows,sCols,sResult;
|
|
|
|
sRows = abs((sOrigin / MAXCOL) - (sDest / MAXCOL));
|
|
sCols = abs((sOrigin % MAXROW) - (sDest % MAXROW));
|
|
|
|
|
|
// apply Pythagoras's theorem for right-handed triangle:
|
|
// dist^2 = rows^2 + cols^2, so use the square root to get the distance
|
|
sResult = (INT16)sqrt((double) (sRows * sRows) + (sCols * sCols));
|
|
|
|
return(sResult);
|
|
}
|
|
|
|
|
|
INT16 SpacesAway(INT16 sOrigin, INT16 sDest)
|
|
{
|
|
INT16 sRows,sCols;
|
|
|
|
sRows = abs((sOrigin / MAXCOL) - (sDest / MAXCOL));
|
|
sCols = abs((sOrigin % MAXROW) - (sDest % MAXROW));
|
|
|
|
return( __max( sRows, sCols ) );
|
|
}
|
|
|
|
INT16 CardinalSpacesAway(INT16 sOrigin, INT16 sDest)
|
|
// distance away, ignoring diagonals!
|
|
{
|
|
INT16 sRows,sCols;
|
|
|
|
sRows = abs((sOrigin / MAXCOL) - (sDest / MAXCOL));
|
|
sCols = abs((sOrigin % MAXROW) - (sDest % MAXROW));
|
|
|
|
return( (INT16)( sRows + sCols ) );
|
|
}
|
|
|
|
INT8 FindNumTurnsBetweenDirs( INT8 sDir1, INT8 sDir2 )
|
|
{
|
|
INT16 sDirection;
|
|
INT16 sNumTurns = 0;
|
|
|
|
sDirection = sDir1;
|
|
|
|
do
|
|
{
|
|
|
|
sDirection = sDirection + QuickestDirection( sDir1, sDir2 );
|
|
|
|
if (sDirection > 7)
|
|
{
|
|
sDirection = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( sDirection < 0 )
|
|
{
|
|
sDirection = 7;
|
|
}
|
|
}
|
|
|
|
if ( sDirection == sDir2 )
|
|
{
|
|
break;
|
|
}
|
|
|
|
sNumTurns++;
|
|
|
|
// SAFEGUARD ! - if we (somehow) do not get to were we want!
|
|
if ( sNumTurns > 100 )
|
|
{
|
|
sNumTurns = 0;
|
|
break;
|
|
}
|
|
} while( TRUE );
|
|
|
|
return( (INT8)sNumTurns );
|
|
}
|
|
|
|
|
|
BOOLEAN FindHeigherLevel( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bStartingDir, INT8 *pbDirection )
|
|
{
|
|
INT32 cnt;
|
|
INT16 sNewGridNo;
|
|
BOOLEAN fFound = FALSE;
|
|
UINT8 bMinNumTurns = 100;
|
|
INT8 bNumTurns;
|
|
INT8 bMinDirection = 0;
|
|
|
|
// IF there is a roof over our heads, this is an ivalid....
|
|
// return ( FALSE );l
|
|
if ( FindStructure( sGridNo, STRUCTURE_ROOF ) != NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// LOOP THROUGH ALL 8 DIRECTIONS
|
|
for ( cnt = 0; cnt < 8; cnt+= 2 )
|
|
{
|
|
sNewGridNo = NewGridNo( (UINT16)sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) );
|
|
|
|
if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 1 ) )
|
|
{
|
|
// Check if this tile has a higher level
|
|
if ( IsHeigherLevel( sNewGridNo ) )
|
|
{
|
|
fFound = TRUE;
|
|
|
|
// FInd how many turns we should go to get here
|
|
bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir );
|
|
|
|
if ( bNumTurns < bMinNumTurns )
|
|
{
|
|
bMinNumTurns = bNumTurns;
|
|
bMinDirection = (INT8)cnt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fFound )
|
|
{
|
|
*pbDirection = bMinDirection;
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
BOOLEAN FindLowerLevel( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bStartingDir, INT8 *pbDirection )
|
|
{
|
|
INT32 cnt;
|
|
INT16 sNewGridNo;
|
|
BOOLEAN fFound = FALSE;
|
|
UINT8 bMinNumTurns = 100;
|
|
INT8 bNumTurns;
|
|
INT8 bMinDirection = 0;
|
|
|
|
// LOOP THROUGH ALL 8 DIRECTIONS
|
|
for ( cnt = 0; cnt < 8; cnt+= 2 )
|
|
{
|
|
sNewGridNo = NewGridNo( (UINT16)sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) );
|
|
|
|
// Make sure there is NOT a roof here...
|
|
// Check OK destination
|
|
if ( NewOKDestination( pSoldier, sNewGridNo, TRUE, 0 ) )
|
|
{
|
|
if ( FindStructure( sNewGridNo, STRUCTURE_ROOF ) == NULL )
|
|
{
|
|
{
|
|
fFound = TRUE;
|
|
|
|
// FInd how many turns we should go to get here
|
|
bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir );
|
|
|
|
if ( bNumTurns < bMinNumTurns )
|
|
{
|
|
bMinNumTurns = bNumTurns;
|
|
bMinDirection = (INT8)cnt;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fFound )
|
|
{
|
|
*pbDirection = bMinDirection;
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
INT16 QuickestDirection(INT16 origin, INT16 dest)
|
|
{
|
|
INT16 v1,v2;
|
|
|
|
if (origin==dest)
|
|
return(0);
|
|
|
|
if ((abs(origin - dest)) == 4)
|
|
return(1); // this could be made random
|
|
else
|
|
if (origin > dest)
|
|
{
|
|
v1 = abs(origin - dest);
|
|
v2 = (8 - origin) + dest;
|
|
if (v1 > v2)
|
|
return(1);
|
|
else
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
v1 = abs(origin - dest);
|
|
v2 = (8 - dest) + origin;
|
|
if (v1 > v2)
|
|
return(-1);
|
|
else
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
|
|
INT16 ExtQuickestDirection(INT16 origin, INT16 dest)
|
|
{
|
|
INT16 v1,v2;
|
|
|
|
if (origin==dest)
|
|
return(0);
|
|
|
|
if ((abs(origin - dest)) == 16)
|
|
return(1); // this could be made random
|
|
else
|
|
if (origin > dest)
|
|
{
|
|
v1 = abs(origin - dest);
|
|
v2 = (32 - origin) + dest;
|
|
if (v1 > v2)
|
|
return(1);
|
|
else
|
|
return(-1);
|
|
}
|
|
else
|
|
{
|
|
v1 = abs(origin - dest);
|
|
v2 = (32 - dest) + origin;
|
|
if (v1 > v2)
|
|
return(-1);
|
|
else
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
|
|
// Returns the (center ) cell coordinates in X
|
|
INT16 CenterX( INT16 sGridNo )
|
|
{
|
|
INT16 sYPos, sXPos;
|
|
|
|
sYPos = sGridNo / WORLD_COLS;
|
|
sXPos = ( sGridNo - ( sYPos * WORLD_COLS ) );
|
|
|
|
return( ( sXPos * CELL_X_SIZE ) + ( CELL_X_SIZE / 2 ) );
|
|
}
|
|
|
|
|
|
// Returns the (center ) cell coordinates in Y
|
|
INT16 CenterY( INT16 sGridNo )
|
|
{
|
|
INT16 sYPos, sXPos;
|
|
|
|
sYPos = sGridNo / WORLD_COLS;
|
|
sXPos = ( sGridNo - ( sYPos * WORLD_COLS ) );
|
|
|
|
return( ( sYPos * CELL_Y_SIZE ) + ( CELL_Y_SIZE / 2 ) );
|
|
}
|
|
|
|
|
|
INT16 MapX( INT16 sGridNo )
|
|
{
|
|
INT16 sYPos, sXPos;
|
|
|
|
sYPos = sGridNo / WORLD_COLS;
|
|
sXPos = ( sGridNo - ( sYPos * WORLD_COLS ) );
|
|
|
|
return( sXPos );
|
|
}
|
|
|
|
|
|
INT16 MapY( INT16 sGridNo )
|
|
{
|
|
INT16 sYPos, sXPos;
|
|
|
|
sYPos = sGridNo / WORLD_COLS;
|
|
sXPos = ( sGridNo - ( sYPos * WORLD_COLS ) );
|
|
|
|
return( sYPos );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN GridNoOnVisibleWorldTile( INT16 sGridNo )
|
|
{
|
|
INT16 sWorldX;
|
|
INT16 sWorldY;
|
|
INT16 sXMapPos, sYMapPos;
|
|
|
|
// Check for valid gridno...
|
|
ConvertGridNoToXY( sGridNo, &sXMapPos, &sYMapPos );
|
|
|
|
// Get screen coordinates for current position of soldier
|
|
GetWorldXYAbsoluteScreenXY( sXMapPos, sYMapPos, &sWorldX, &sWorldY);
|
|
|
|
if ( sWorldX > 0 && sWorldX < ( gsTRX - gsTLX - 20 ) &&
|
|
sWorldY > 20 && sWorldY < ( gsBLY - gsTLY - 20 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// This function is used when we care about astetics with the top Y portion of the
|
|
// gma eplay area
|
|
// mostly due to UI bar that comes down....
|
|
BOOLEAN GridNoOnVisibleWorldTileGivenYLimits( INT16 sGridNo )
|
|
{
|
|
INT16 sWorldX;
|
|
INT16 sWorldY;
|
|
INT16 sXMapPos, sYMapPos;
|
|
|
|
// Check for valid gridno...
|
|
ConvertGridNoToXY( sGridNo, &sXMapPos, &sYMapPos );
|
|
|
|
// Get screen coordinates for current position of soldier
|
|
GetWorldXYAbsoluteScreenXY( sXMapPos, sYMapPos, &sWorldX, &sWorldY);
|
|
|
|
if ( sWorldX > 0 && sWorldX < ( gsTRX - gsTLX - 20 ) &&
|
|
sWorldY > 40 && sWorldY < ( gsBLY - gsTLY - 20 ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN GridNoOnEdgeOfMap( INT16 sGridNo, INT8 * pbDirection )
|
|
{
|
|
INT8 bDir;
|
|
|
|
// check NE, SE, SW, NW because of tilt of isometric display
|
|
|
|
for (bDir = NORTHEAST; bDir < NUM_WORLD_DIRECTIONS; bDir += 2 )
|
|
{
|
|
if (gubWorldMovementCosts[ (sGridNo + DirectionInc( bDir ) ) ][ bDir ][ 0 ] == TRAVELCOST_OFF_MAP)
|
|
//if ( !GridNoOnVisibleWorldTile( (INT16) (sGridNo + DirectionInc( bDir ) ) ) )
|
|
{
|
|
*pbDirection = bDir;
|
|
return( TRUE );
|
|
}
|
|
}
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
BOOLEAN FindFenceJumpDirection( SOLDIERTYPE *pSoldier, INT16 sGridNo, INT8 bStartingDir, INT8 *pbDirection )
|
|
{
|
|
INT32 cnt;
|
|
INT16 sNewGridNo, sOtherSideOfFence;
|
|
BOOLEAN fFound = FALSE;
|
|
UINT8 bMinNumTurns = 100;
|
|
INT8 bNumTurns;
|
|
INT8 bMinDirection = 0;
|
|
|
|
// IF there is a fence in this gridno, return false!
|
|
if ( IsJumpableFencePresentAtGridno( sGridNo ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// LOOP THROUGH ALL 8 DIRECTIONS
|
|
for ( cnt = 0; cnt < 8; cnt+= 2 )
|
|
{
|
|
// go out *2* tiles
|
|
sNewGridNo = NewGridNo( (UINT16)sGridNo, (UINT16)DirectionInc( (UINT8)cnt ) );
|
|
sOtherSideOfFence = NewGridNo( (UINT16)sNewGridNo, (UINT16)DirectionInc( (UINT8)cnt ) );
|
|
|
|
if ( NewOKDestination( pSoldier, sOtherSideOfFence, TRUE, 0 ) )
|
|
{
|
|
// ATE: Check if there is somebody waiting here.....
|
|
|
|
|
|
// Check if we have a fence here
|
|
if ( IsJumpableFencePresentAtGridno( sNewGridNo ) )
|
|
{
|
|
fFound = TRUE;
|
|
|
|
// FInd how many turns we should go to get here
|
|
bNumTurns = FindNumTurnsBetweenDirs( (INT8)cnt, bStartingDir );
|
|
|
|
if ( bNumTurns < bMinNumTurns )
|
|
{
|
|
bMinNumTurns = bNumTurns;
|
|
bMinDirection = (INT8)cnt;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fFound )
|
|
{
|
|
*pbDirection = bMinDirection;
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
//Simply chooses a random gridno within valid boundaries (for dropping things in unloaded sectors)
|
|
INT16 RandomGridNo()
|
|
{
|
|
INT32 iMapXPos, iMapYPos, iMapIndex;
|
|
do
|
|
{
|
|
iMapXPos = Random( WORLD_COLS );
|
|
iMapYPos = Random( WORLD_ROWS );
|
|
iMapIndex = iMapYPos * WORLD_COLS + iMapXPos;
|
|
}while( !GridNoOnVisibleWorldTile( (INT16)iMapIndex ) );
|
|
return (INT16)iMapIndex;
|
|
}
|