Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 163 additions & 71 deletions Tactical/Soldier Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "Animation Data.h"
#include "Animation Control.h"
#include "container.h"
#define _USE_MATH_DEFINES // for C
#include <math.h>
Comment thread
CptMoore marked this conversation as resolved.
#include "pathai.h"
#include "Random.h"
Expand Down Expand Up @@ -17688,78 +17689,13 @@ void SOLDIERTYPE::HandleFlashLights( )
fLightChanged = TRUE;
}

// not possible to get this bonus on a roof, due to our lighting system
if ( !this->pathing.bLevel )
{
UINT8 flashlightrange = this->GetBestEquippedFlashLightRange( );

// if no flashlight is found, this will be 0
if ( flashlightrange )
{
// the range at which we create additional light sources to the side
UINT8 firstexpand = 8;
UINT8 secondexpand = 12;

// depending on our direction, alter range
if ( this->ubDirection == NORTHEAST || this->ubDirection == NORTHWEST || this->ubDirection == SOUTHEAST || this->ubDirection == SOUTHWEST )
{
flashlightrange = sqrt( (FLOAT)flashlightrange*(FLOAT)flashlightrange / 2.0f );
firstexpand = sqrt( (FLOAT)firstexpand*(FLOAT)firstexpand / 2.0f );
secondexpand = sqrt( (FLOAT)secondexpand*(FLOAT)secondexpand / 2.0f );
}

// we determine the height of the next tile in our direction. Because of the way structures are handled, we sometimes have to take the very tile we're occupying right now
INT32 nextGridNoinSight = this->sGridNo;

for ( UINT8 i = 0; i < flashlightrange; ++i )
{
nextGridNoinSight = NewGridNo( nextGridNoinSight, DirectionInc( this->ubDirection ) );

if ( SoldierToVirtualSoldierLineOfSightTest( this, nextGridNoinSight, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE ) )
CreatePersonalLight( nextGridNoinSight, this->ubID );

// after a certain range, add new lights to the side to simulate a light cone
if ( i > firstexpand )
{
INT8 sidedir1 = (this->ubDirection + 2) % NUM_WORLD_DIRECTIONS;
INT8 sidedir2 = (this->ubDirection - 2) % NUM_WORLD_DIRECTIONS;

INT32 sideGridNo1 = NewGridNo( nextGridNoinSight, DirectionInc( sidedir1 ) );
sideGridNo1 = NewGridNo( sideGridNo1, DirectionInc( sidedir1 ) );

if ( SoldierToVirtualSoldierLineOfSightTest( this, sideGridNo1, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE, NO_DISTANCE_LIMIT ) )
CreatePersonalLight( sideGridNo1, this->ubID );

if ( i > secondexpand )
{
sideGridNo1 = NewGridNo( sideGridNo1, DirectionInc( sidedir1 ) );

if ( SoldierToVirtualSoldierLineOfSightTest( this, sideGridNo1, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE, NO_DISTANCE_LIMIT ) )
CreatePersonalLight( sideGridNo1, this->ubID );
}

INT32 sideGridNo2 = NewGridNo( nextGridNoinSight, DirectionInc( sidedir2 ) );
sideGridNo2 = NewGridNo( sideGridNo2, DirectionInc( sidedir2 ) );
if ( AddBestFlashLight() )
{
// take note: we own a light source
this->usSoldierFlagMask |= SOLDIER_LIGHT_OWNER;

if ( SoldierToVirtualSoldierLineOfSightTest( this, sideGridNo2, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE, NO_DISTANCE_LIMIT ) )
CreatePersonalLight( sideGridNo2, this->ubID );

if ( i > secondexpand )
{
sideGridNo2 = NewGridNo( sideGridNo2, DirectionInc( sidedir2 ) );

if ( SoldierToVirtualSoldierLineOfSightTest( this, sideGridNo2, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, FALSE, NO_DISTANCE_LIMIT ) )
CreatePersonalLight( sideGridNo2, this->ubID );
}
}
}

// take note: we own a light source
this->usSoldierFlagMask |= SOLDIER_LIGHT_OWNER;

fLightChanged = TRUE;
}
}
fLightChanged = TRUE;
}

if ( fLightChanged )
{
Expand Down Expand Up @@ -17805,6 +17741,162 @@ UINT8 SOLDIERTYPE::GetBestEquippedFlashLightRange( )
return(bestrange);
}

bool SOLDIERTYPE::AddBestFlashLight()
{
// not possible to get this bonus on a roof, due to our lighting system
if ( this->pathing.bLevel != 0 )
{
return false;
}

UINT8 maxRange = this->GetBestEquippedFlashLightRange();
if ( maxRange < 1 )
{
return false;
}

// we don't use the flashlight to run better at night (light up our shoes), we use it to find enemies!
UINT8 minRange = 4;
if ( minRange > maxRange )
{
minRange = maxRange;
}

float maxAngle = 45;
maxAngle *= PI / 180 / 2; // convert to rad and halven

auto forward = DirectionInc(this->ubDirection);
auto left = DirectionInc(DirectionIfTurnedClockwise(this->ubDirection, 6));
auto leftLeft = DirectionInc(DirectionIfTurnedClockwise(this->ubDirection, 5));
auto right = DirectionInc(DirectionIfTurnedClockwise(this->ubDirection, 2));
auto rightRight = DirectionInc(DirectionIfTurnedClockwise(this->ubDirection, 3));

bool isDiagonal = this->ubDirection == NORTHEAST || this->ubDirection == NORTHWEST || this->ubDirection == SOUTHEAST || this->ubDirection == SOUTHWEST;

struct position_2d
{
INT16 x, y;

position_2d(INT32 gridNo)
{
ConvertGridNoToXY(gridNo, &x, &y);
}
position_2d(INT16 _x, INT16 _y) : x{_x}, y{_y}
{
}
};
struct vector_2d
{
INT16 dx, dy;
float length;

vector_2d(INT8 direction)
{
ConvertDirectionToVectorInXY(direction, &dx, &dy);
length = CalcLength(dx, dy);
}
vector_2d(position_2d from, position_2d to)
{
dx = to.x - from.x;
dy = to.y - from.y;
length = CalcLength(dx, dy);
}
vector_2d(INT16 _dx, INT16 _dy) : dx{_dx}, dy{_dy}
{
length = CalcLength(dx, dy);
}

float GetAngle( vector_2d other )
{
auto dot = dx * other.dx + dy * other.dy;
return acos(dot / (length * other.length));
}

static float CalcLength(float dx, float dy)
{
return sqrt(powf(dx, 2) + powf(dy, 2));
}
};

position_2d soldierPos(this->sGridNo);
vector_2d soldierDir(this->ubDirection);

auto is_in_area = [&](INT32 sGridNoToTest) -> bool
{
vector_2d v(soldierPos, position_2d(sGridNoToTest));

if (v.length > maxRange)
{
return false;
}

if (v.length < minRange)
{
return false;
}

auto coneAngle = soldierDir.GetAngle( v );
if (coneAngle > maxAngle)
{
return false;
}

return true;
};

auto add_light_if_in_line_of_sight = [&, this]( INT32 sGridNoToTest, bool allowSkip ) -> void
{
if (allowSkip) // improve performance by skipping 3/4 of the lights
{
INT16 sXPos, sYPos;
ConvertGridNoToXY( sGridNoToTest, &sXPos, &sYPos );
if (!(sXPos % 2 == 0 && sYPos % 2 == 0))
{
return;
}
}

if ( SoldierToVirtualSoldierLineOfSightTest( this, sGridNoToTest, this->pathing.bLevel, gAnimControl[this->usAnimState].ubEndHeight, false, NO_DISTANCE_LIMIT ) )
{
CreatePersonalLight( sGridNoToTest, this->ubID );
}
};

auto travel_direction_to_add_light = [&]( INT32 startingGridNo, INT16 directionIncrementer )
{
for ( auto currentGridNo = startingGridNo; !OutOfBounds( currentGridNo, -1 ) && is_in_area( currentGridNo ); currentGridNo += directionIncrementer )
{
add_light_if_in_line_of_sight( currentGridNo, true);
}
};

for ( auto currentGridNo = this->sGridNo; !OutOfBounds( currentGridNo, -1 ); currentGridNo += forward )
{
vector_2d v(soldierPos, position_2d(currentGridNo));
if ( v.length < minRange )
{
continue;
}
else if (v.length > maxRange)
{
break;
}

add_light_if_in_line_of_sight( currentGridNo, false );

travel_direction_to_add_light( currentGridNo, left );
travel_direction_to_add_light( currentGridNo, right );

if ( isDiagonal )
{
travel_direction_to_add_light( NewGridNo( currentGridNo, leftLeft ), left );
travel_direction_to_add_light( NewGridNo( currentGridNo, rightRight ), right );
}
}

return true;
}

// Flugente: soldier profiles
// retrieves the correct sub-array
INT8 SOLDIERTYPE::GetSoldierProfileType( UINT8 usTeam )
Expand Down
3 changes: 2 additions & 1 deletion Tactical/Soldier Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -1935,7 +1935,8 @@ class SOLDIERTYPE//last edited at version 102
//void AddDrugValues(UINT8 uDrugType, UINT8 usEffect, UINT8 usTravelRate, UINT8 usSideEffect );

void HandleFlashLights();
UINT8 GetBestEquippedFlashLightRange();
bool AddBestFlashLight();
UINT8 GetBestEquippedFlashLightRange();

// Flugente: soldier profiles
INT8 GetSoldierProfileType(UINT8 usTeam); // retrieves the correct sub-array
Expand Down
14 changes: 14 additions & 0 deletions TileEngine/Isometric Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ UINT8 gOneCCDirection[ NUM_WORLD_DIRECTIONS ] =
WEST
};

UINT8 DirectionIfTurnedClockwise(UINT8 facing, UINT8 times)
{
return (facing + times) % NUM_WORLD_DIRECTIONS;
}

// DIRECTION FACING DIRECTION WE WANT TO GOTO
UINT8 gPurpendicularDirection[ NUM_WORLD_DIRECTIONS ][ NUM_WORLD_DIRECTIONS ] =
{
Expand Down Expand Up @@ -912,6 +917,15 @@ INT16 sDeltaScreenX, sDeltaScreenY;

}

INT16 DirectionToVectorX[NUM_WORLD_DIRECTIONS] = {0, 1, 1, 1, 0, -1, -1, -1};
INT16 DirectionToVectorY[NUM_WORLD_DIRECTIONS] = {-1, -1, 0, 1, 1, 1, 0, -1};
void ConvertDirectionToVectorInXY( UINT8 ubDirection, INT16* sXDir, INT16* sYDir )
{
Assert(ubDirection >= 0 && ubDirection < NUM_WORLD_DIRECTIONS);
*sXDir = DirectionToVectorX[ubDirection];
*sYDir = DirectionToVectorY[ubDirection];
}

void ConvertGridNoToXY( INT32 sGridNo, INT16 *sXPos, INT16 *sYPos )
{
*sYPos = sGridNo / WORLD_COLS;
Expand Down
3 changes: 3 additions & 0 deletions TileEngine/Isometric Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ extern UINT8 gTwoCDirection[ NUM_WORLD_DIRECTIONS ];
extern UINT8 gOneCDirection[ NUM_WORLD_DIRECTIONS ];
extern UINT8 gOneCCDirection[ NUM_WORLD_DIRECTIONS ];

UINT8 DirectionIfTurnedClockwise(UINT8 facing, UINT8 times);

extern UINT8 gPurpendicularDirection[ NUM_WORLD_DIRECTIONS ][ NUM_WORLD_DIRECTIONS ];

// Macros
Expand All @@ -40,6 +42,7 @@ extern UINT8 gPurpendicularDirection[ NUM_WORLD_DIRECTIONS ][ NUM_WORLD_DIRECTIO

#define GETWORLDINDEXFROMWORLDCOORDS( y, x ) ( (INT32) ( x / CELL_X_SIZE ) ) + WORLD_COLS * ( (INT32) ( y / CELL_Y_SIZE ) )

void ConvertDirectionToVectorInXY(UINT8 ubDirection, INT16* sXDir, INT16* sYDir);
void ConvertGridNoToXY( INT32 sGridNo, INT16 *sXPos, INT16 *sYPos );
void ConvertGridNoToCellXY( INT32 sGridNo, INT16 *sXPos, INT16 *sYPos );
void ConvertGridNoToCenterCellXY( INT32 sGridNo, INT16 *sXPos, INT16 *sYPos );
Expand Down