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
2316 lines
64 KiB
C++
2316 lines
64 KiB
C++
#ifdef PRECOMPILEDHEADERS
|
|
#include "Strategic All.h"
|
|
#else
|
|
#include "Map Screen Helicopter.h"
|
|
#include "LaptopSave.h"
|
|
#include "Vehicles.h"
|
|
#include "Finances.h"
|
|
#include "Quests.h"
|
|
#include "Game Clock.h"
|
|
#include "strategic.h"
|
|
#include "Queen Command.h"
|
|
#include "Strategic Pathing.h"
|
|
#include "Random.h"
|
|
#include "Game Event Hook.h"
|
|
#include "String.h"
|
|
#include "Dialogue Control.h"
|
|
#include "Message.h"
|
|
#include "Strategic Movement.h"
|
|
#include "Soldier Profile.h"
|
|
#include "Assignments.h"
|
|
#include "PreBattle Interface.h"
|
|
#include "strategicmap.h"
|
|
#include "worlddef.h"
|
|
#include "worldman.h"
|
|
#include "tiledat.h"
|
|
#include "Map Screen Interface.h"
|
|
#include "Text.h"
|
|
#include "Squads.h"
|
|
#include "Player Command.h"
|
|
#include "Sound Control.h"
|
|
#include "GameSettings.h"
|
|
#include "meanwhile.h"
|
|
#include "Map Screen Interface Border.h"
|
|
#include "Strategic Event Handler.h"
|
|
#include "Overhead.h"
|
|
#include "Soldier Create.h"
|
|
#include "renderworld.h"
|
|
#include "soundman.h"
|
|
#include "Isometric Utils.h"
|
|
#include "Scheduling.h"
|
|
#endif
|
|
|
|
|
|
// the amounts of time to wait for hover stuff
|
|
#define TIME_DELAY_FOR_HOVER_WAIT 10 // minutes
|
|
#define TIME_DELAY_FOR_HOVER_WAIT_TOO_LONG 20 // mintues
|
|
|
|
|
|
#define MIN_DAYS_BETWEEN_SKYRIDER_MONOLOGUES 1
|
|
|
|
// refuel delay
|
|
#define REFUEL_HELICOPTER_DELAY 30 // minutes
|
|
|
|
// total number of sectors one can go
|
|
//#define MAX_HELICOPTER_DISTANCE 25
|
|
|
|
// maximum chance out of a hundred per unsafe sector that a SAM site in decent working condition will hit Skyrider
|
|
#define MAX_SAM_SITE_ACCURACY 33
|
|
|
|
|
|
extern FACETYPE *gpCurrentTalkingFace;
|
|
extern UINT8 gubCurrentTalkingID;
|
|
|
|
// current temp path for dest char
|
|
extern PathStPtr pTempHelicopterPath;
|
|
|
|
extern UINT8 ubSAMControlledSectors[ MAP_WORLD_Y ][ MAP_WORLD_X ];
|
|
|
|
// the seating capacities
|
|
extern INT32 iSeatingCapacities[];
|
|
|
|
// the static NPC dialogue faces
|
|
extern UINT32 uiExternalStaticNPCFaces[];
|
|
|
|
// the squad mvt groups
|
|
extern INT8 SquadMovementGroups[ ];
|
|
|
|
|
|
// whether helicopted variables have been set up
|
|
BOOLEAN fSkyRiderSetUp = FALSE;
|
|
|
|
// plotting for a helicopter
|
|
BOOLEAN fPlotForHelicopter = FALSE;
|
|
|
|
// is the helicopter available to player?
|
|
BOOLEAN fHelicopterAvailable = FALSE;
|
|
|
|
// helicopter vehicle id
|
|
INT32 iHelicopterVehicleId = -1;
|
|
|
|
// helicopter icon
|
|
UINT32 guiHelicopterIcon;
|
|
|
|
// total distance travelled
|
|
//INT32 iTotalHeliDistanceSinceRefuel = 0;
|
|
|
|
// total owed to player
|
|
INT32 iTotalAccumulatedCostByPlayer = 0;
|
|
|
|
// whether or not skyrider is alive and well? and on our side yet?
|
|
BOOLEAN fSkyRiderAvailable = FALSE;
|
|
|
|
#ifdef JA2TESTVERSION
|
|
BOOLEAN fSAMSitesDisabledFromAttackingPlayer = FALSE;
|
|
#endif
|
|
|
|
// helicopter destroyed
|
|
BOOLEAN fHelicopterDestroyed = FALSE;
|
|
|
|
// list of sector locations where SkyRider can be refueled
|
|
UINT8 ubRefuelList[ NUMBER_OF_REFUEL_SITES ][ 2 ] =
|
|
{
|
|
{ 13, 2 }, // Drassen airport
|
|
{ 6, 9 }, // Estoni
|
|
};
|
|
|
|
|
|
INT16 sRefuelStartGridNo[ NUMBER_OF_REFUEL_SITES ] ={
|
|
9001, // drassen
|
|
13068, // estoni
|
|
};
|
|
|
|
// whether or not helicopter can refuel at this site
|
|
BOOLEAN fRefuelingSiteAvailable[ NUMBER_OF_REFUEL_SITES ] = { FALSE, FALSE };
|
|
|
|
// is the heli in the air?
|
|
BOOLEAN fHelicopterIsAirBorne = FALSE;
|
|
|
|
// is the pilot returning straight to base?
|
|
BOOLEAN fHeliReturnStraightToBase = FALSE;
|
|
|
|
// heli hovering
|
|
BOOLEAN fHoveringHelicopter = FALSE;
|
|
|
|
// time started hovering
|
|
UINT32 uiStartHoverTime = 0;
|
|
|
|
// what state are skyrider's monologues in in?
|
|
UINT32 guiHelicopterSkyriderTalkState = 0;
|
|
|
|
// the flags for skyrider events
|
|
BOOLEAN fShowEstoniRefuelHighLight = FALSE;
|
|
BOOLEAN fShowOtherSAMHighLight = FALSE;
|
|
BOOLEAN fShowDrassenSAMHighLight = FALSE;
|
|
BOOLEAN fShowCambriaHospitalHighLight = FALSE;
|
|
|
|
UINT32 guiTimeOfLastSkyriderMonologue = 0;
|
|
|
|
UINT8 gubHelicopterHitsTaken = 0;
|
|
|
|
BOOLEAN gfSkyriderSaidCongratsOnTakingSAM = FALSE;
|
|
UINT8 gubPlayerProgressSkyriderLastCommentedOn = 0;
|
|
|
|
// skyrider placeholder
|
|
SOLDIERTYPE SoldierSkyRider;
|
|
|
|
SOLDIERTYPE *pSkyRider;
|
|
|
|
|
|
|
|
// helicopter char dialogue
|
|
BOOLEAN HeliCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum );
|
|
|
|
// does skyrider notice bad guys in sector?
|
|
BOOLEAN DoesSkyriderNoticeEnemiesInSector( UINT8 ubNumEnemies );
|
|
|
|
// are we at the end of the path for the helicopter
|
|
BOOLEAN EndOfHelicoptersPath( void );
|
|
|
|
// find the location sector of closest refuel point for heli..and the criteria if the sector must be under the players control
|
|
INT32 FindLocationOfClosestRefuelSite( BOOLEAN fMustBeAvailable );
|
|
|
|
|
|
// add the tactical heli graphic
|
|
void AddHelicopterToMaps( BOOLEAN fAdd, UINT8 ubSite );
|
|
|
|
void PaySkyriderBill( void );
|
|
void MakeHeliReturnToBase( void );
|
|
|
|
void HandleSkyRiderMonologueAboutDrassenSAMSite( UINT32 uiSpecialCode );
|
|
void HandleSkyRiderMonologueAboutCambriaHospital( UINT32 uiSpecialCode );
|
|
void HandleSkyRiderMonologueAboutOtherSAMSites( UINT32 uiSpecialCode );
|
|
void HandleSkyRiderMonologueAboutEstoniRefuel( UINT32 uiSpecialCode );
|
|
|
|
|
|
|
|
void InitializeHelicopter( void )
|
|
{
|
|
// must be called whenever a new game starts up!
|
|
fHelicopterAvailable = FALSE;
|
|
iHelicopterVehicleId = -1;
|
|
|
|
fSkyRiderAvailable = FALSE;
|
|
fSkyRiderSetUp = FALSE;
|
|
pSkyRider = NULL;
|
|
memset ( &SoldierSkyRider, 0, sizeof( SoldierSkyRider ) );
|
|
|
|
fHelicopterIsAirBorne = FALSE;
|
|
fHeliReturnStraightToBase = FALSE;
|
|
|
|
fHoveringHelicopter = FALSE;
|
|
uiStartHoverTime = 0;
|
|
|
|
fPlotForHelicopter = FALSE;
|
|
pTempHelicopterPath = NULL;
|
|
|
|
// iTotalHeliDistanceSinceRefuel = 0;
|
|
iTotalAccumulatedCostByPlayer = 0;
|
|
|
|
fHelicopterDestroyed = FALSE;
|
|
|
|
guiHelicopterSkyriderTalkState = 0;
|
|
guiTimeOfLastSkyriderMonologue = 0;
|
|
|
|
fShowEstoniRefuelHighLight = FALSE;
|
|
fShowOtherSAMHighLight = FALSE;
|
|
fShowDrassenSAMHighLight = FALSE;
|
|
fShowCambriaHospitalHighLight = FALSE;
|
|
|
|
gfSkyriderEmptyHelpGiven = FALSE;
|
|
|
|
gubHelicopterHitsTaken = 0;
|
|
|
|
gfSkyriderSaidCongratsOnTakingSAM = FALSE;
|
|
gubPlayerProgressSkyriderLastCommentedOn = 0;
|
|
}
|
|
|
|
|
|
BOOLEAN AddSoldierToHelicopter( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// attempt to add soldier to helicopter
|
|
if( iHelicopterVehicleId == -1 )
|
|
{
|
|
// no heli yet
|
|
return( FALSE );
|
|
}
|
|
|
|
// check if heli is in motion or if on the ground
|
|
if( ( fHelicopterIsAirBorne == TRUE ) && (fHoveringHelicopter == FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is the heli returning to base?..he ain't waiting if so
|
|
if( fHeliReturnStraightToBase == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// attempt to add to vehicle
|
|
return( PutSoldierInVehicle( pSoldier, ( INT8 )iHelicopterVehicleId ) );
|
|
}
|
|
|
|
|
|
BOOLEAN RemoveSoldierFromHelicopter( SOLDIERTYPE *pSoldier )
|
|
{
|
|
// attempt to add soldier to helicopter
|
|
if( iHelicopterVehicleId == -1 )
|
|
{
|
|
// no heli yet
|
|
return( FALSE );
|
|
}
|
|
|
|
// check if heli is in motion or if on the ground
|
|
if( ( fHelicopterIsAirBorne == TRUE ) && (fHoveringHelicopter == FALSE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// is the heli returning to base?..he ain't waiting if so
|
|
if( fHeliReturnStraightToBase == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pSoldier -> sSectorX = pVehicleList[ iHelicopterVehicleId ].sSectorX;
|
|
pSoldier -> sSectorY = pVehicleList[ iHelicopterVehicleId ].sSectorY;
|
|
pSoldier -> bSectorZ = 0;
|
|
|
|
// reset between sectors
|
|
pSoldier->fBetweenSectors = FALSE;
|
|
|
|
|
|
// remove from the vehicle
|
|
return( TakeSoldierOutOfVehicle( pSoldier ) );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN HandleHeliEnteringSector( INT16 sX, INT16 sY )
|
|
{
|
|
UINT8 ubNumEnemies;
|
|
|
|
|
|
// check for SAM attack upon the chopper. If it's destroyed by the attack, do nothing else here
|
|
if( HandleSAMSiteAttackOfHelicopterInSector( sX, sY ) == TRUE )
|
|
{
|
|
// destroyed
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
// count how many enemies are camped there or passing through
|
|
ubNumEnemies = NumEnemiesInSector( sX, sY );
|
|
|
|
// any baddies?
|
|
if( ubNumEnemies > 0 )
|
|
{
|
|
// if the player didn't know about these prior to the chopper's arrival
|
|
if( WhatPlayerKnowsAboutEnemiesInSector( sX, sY ) == KNOWS_NOTHING )
|
|
{
|
|
// but Skyrider notices them
|
|
if ( DoesSkyriderNoticeEnemiesInSector( ubNumEnemies ) == TRUE )
|
|
{
|
|
// if just passing through (different quotes are used below if it's his final destination)
|
|
if( !EndOfHelicoptersPath( ) )
|
|
{
|
|
// stop time compression and inform player that there are enemies in the sector below
|
|
StopTimeCompression();
|
|
|
|
if( Random( 2 ) )
|
|
{
|
|
HeliCharacterDialogue( pSkyRider, ENEMIES_SPOTTED_EN_ROUTE_IN_FRIENDLY_SECTOR_A );
|
|
}
|
|
else
|
|
{
|
|
HeliCharacterDialogue( pSkyRider, ENEMIES_SPOTTED_EN_ROUTE_IN_FRIENDLY_SECTOR_B );
|
|
}
|
|
}
|
|
|
|
// make their presence appear on the map while Skyrider remains in the sector
|
|
SectorInfo[ SECTOR( sX, sY ) ].uiFlags |= SF_SKYRIDER_NOTICED_ENEMIES_HERE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// player pays for travel if Skyrider is NOT returning to base (even if empty while scouting/going for pickup)
|
|
if ( fHeliReturnStraightToBase == FALSE )
|
|
{
|
|
// charge cost for flying another sector
|
|
iTotalAccumulatedCostByPlayer += GetCostOfPassageForHelicopter( sX, sY );
|
|
}
|
|
|
|
// accumulate distance travelled
|
|
// AddSectorToHelicopterDistanceTravelled( );
|
|
|
|
|
|
// check if heli has any real path left
|
|
if( EndOfHelicoptersPath( ) )
|
|
{
|
|
// start hovering
|
|
StartHoverTime( );
|
|
|
|
// if sector is safe, or Skyrider MUST land anyway (returning to base)
|
|
if ( ( ubNumEnemies == 0 ) || fHeliReturnStraightToBase )
|
|
{
|
|
// if he has passengers, or he's not going straight to base, tell player he's arrived
|
|
// (i.e. don't say anything nor stop time compression if he's empty and just returning to base)
|
|
if ( ( GetNumberOfPassengersInHelicopter() > 0 ) || !fHeliReturnStraightToBase )
|
|
{
|
|
// arrived at destination
|
|
if(gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] == FALSE) HeliCharacterDialogue( pSkyRider, ARRIVED_IN_NON_HOSTILE_SECTOR );
|
|
StopTimeCompression();
|
|
}
|
|
|
|
// destination reached, payment due. If player can't pay, mercs get kicked off and heli flies to base!
|
|
PaySkyriderBill();
|
|
}
|
|
else
|
|
{
|
|
// Say quote: "Gonna have to abort. Enemies below"
|
|
if(gGameSettings.fOptions[ TOPTION_SILENT_SKYRIDER ] == FALSE) HeliCharacterDialogue( pSkyRider, ARRIVED_IN_HOSTILE_SECTOR );
|
|
StopTimeCompression();
|
|
}
|
|
|
|
if( CheckForArrivalAtRefuelPoint( ) )
|
|
{
|
|
ReFuelHelicopter( );
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
/*
|
|
INT32 GetTotalDistanceHelicopterCanTravel( void )
|
|
{
|
|
return( MAX_HELICOPTER_DISTANCE );
|
|
}
|
|
|
|
INT32 HowFarHelicopterhasTravelledSinceRefueling( void )
|
|
{
|
|
// return total distance
|
|
return( iTotalHeliDistanceSinceRefuel );
|
|
}
|
|
|
|
INT32 HowFurtherCanHelicopterTravel( void )
|
|
{
|
|
// how many sectors further can we go on remaining fuel?
|
|
return( MAX_HELICOPTER_DISTANCE - ( HowFarHelicopterhasTravelledSinceRefueling( ) + DistanceOfIntendedHelicopterPath( ) ) );
|
|
}
|
|
|
|
void AddSectorToHelicopterDistanceTravelled( void )
|
|
{
|
|
// up the distance
|
|
iTotalHeliDistanceSinceRefuel++;
|
|
|
|
//reset hover time
|
|
uiStartHoverTime = 0;
|
|
|
|
return;
|
|
}
|
|
*/
|
|
|
|
INT32 LocationOfNearestRefuelPoint( BOOLEAN fNotifyPlayerIfNoSafeLZ )
|
|
{
|
|
INT32 iClosestLocation = -1;
|
|
|
|
// try to find one, any one under the players control
|
|
iClosestLocation = FindLocationOfClosestRefuelSite( TRUE );
|
|
|
|
// no go?...then find
|
|
if( iClosestLocation == -1 )
|
|
{
|
|
if( fNotifyPlayerIfNoSafeLZ )
|
|
{
|
|
// no refueling sites available, might wanna warn player about this
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pHelicopterEtaStrings[ 5 ] );
|
|
}
|
|
|
|
// find the closest location regardless
|
|
iClosestLocation = FindLocationOfClosestRefuelSite( FALSE );
|
|
}
|
|
|
|
// always returns a valid refuel point, picking a hostile one if unavoidable
|
|
Assert( iClosestLocation != -1 );
|
|
|
|
return( iClosestLocation );
|
|
}
|
|
|
|
INT32 FindLocationOfClosestRefuelSite( BOOLEAN fMustBeAvailable )
|
|
{
|
|
INT32 iShortestDistance = 9999;
|
|
INT32 iCounter = 0;
|
|
INT32 iDistance = 9999;
|
|
INT32 iClosestLocation = -1;
|
|
|
|
// find shortest distance to refuel site
|
|
for( iCounter = 0; iCounter < NUMBER_OF_REFUEL_SITES; iCounter++ )
|
|
{
|
|
// if this refuelling site is available
|
|
if( ( fRefuelingSiteAvailable[ iCounter ] ) || ( fMustBeAvailable == FALSE ) )
|
|
{
|
|
// find if sector is under control, find distance from heli to it
|
|
iDistance = ( INT32 )FindStratPath( ( INT16 )( CALCULATE_STRATEGIC_INDEX( pVehicleList[ iHelicopterVehicleId ].sSectorX , pVehicleList[ iHelicopterVehicleId ].sSectorY ) ), ( INT16 )( CALCULATE_STRATEGIC_INDEX( ubRefuelList[ iCounter ][ 0 ], ubRefuelList[ iCounter ][ 1 ] ) ) , pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, FALSE );
|
|
|
|
if( iDistance < iShortestDistance )
|
|
{
|
|
// shorter, copy over
|
|
iShortestDistance = iDistance;
|
|
iClosestLocation = iCounter;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return the location
|
|
return( iClosestLocation );
|
|
}
|
|
|
|
|
|
INT32 DistanceToNearestRefuelPoint( INT16 sX, INT16 sY )
|
|
{
|
|
INT32 iClosestLocation;
|
|
INT32 iDistance;
|
|
|
|
// don't notify player during these checks!
|
|
iClosestLocation = LocationOfNearestRefuelPoint( FALSE );
|
|
|
|
iDistance = ( INT32 )FindStratPath( ( INT16 )( CALCULATE_STRATEGIC_INDEX( sX, sY ) ), ( INT16 )( CALCULATE_STRATEGIC_INDEX( ubRefuelList[ iClosestLocation ][ 0 ], ubRefuelList[ iClosestLocation ][ 1 ] ) ) , pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, FALSE );
|
|
return( iDistance );
|
|
}
|
|
|
|
|
|
/*
|
|
BOOLEAN IsSectorOutOfTheWay( INT16 sX, INT16 sY )
|
|
{
|
|
// check distance to nearest refuel point
|
|
if( DistanceToNearestRefuelPoint( sX, sY ) > HowFurtherCanHelicopterTravel( ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
return( FALSE );
|
|
}
|
|
*/
|
|
|
|
|
|
|
|
void ReFuelHelicopter( void )
|
|
{
|
|
// land, pay the man, and refuel
|
|
|
|
LandHelicopter( );
|
|
|
|
/*
|
|
AddStrategicEvent( EVENT_HELICOPTER_DONE_REFUELING, GetWorldTotalMin() + REFUEL_HELICOPTER_DELAY, 0 );
|
|
|
|
// reset distance traveled
|
|
iTotalHeliDistanceSinceRefuel = 0;
|
|
*/
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
INT32 GetCostOfPassageForHelicopter( INT16 sX, INT16 sY )
|
|
{
|
|
// check if sector is air controlled or not, if so, then normal cost, otherwise increase the cost
|
|
INT32 iCost = 0;
|
|
|
|
// if they don't control it
|
|
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( sX, sY ) ].fEnemyAirControlled == FALSE )
|
|
{
|
|
iCost = COST_AIRSPACE_SAFE;
|
|
}
|
|
else
|
|
{
|
|
iCost = COST_AIRSPACE_UNSAFE;
|
|
}
|
|
|
|
return( iCost );
|
|
}
|
|
|
|
|
|
void SkyriderDestroyed( void )
|
|
{
|
|
// remove any arrival events for the helicopter's group
|
|
DeleteStrategicEvent( EVENT_GROUP_ARRIVAL, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
// kill eveyone on board
|
|
KillAllInVehicle( iHelicopterVehicleId );
|
|
|
|
// kill skyrider
|
|
fSkyRiderAvailable = FALSE;
|
|
SoldierSkyRider.bLife = 0;
|
|
gMercProfiles[ SKYRIDER ].bLife = 0;
|
|
|
|
// heli no longer available
|
|
fHelicopterAvailable = FALSE;
|
|
|
|
// destroy helicopter
|
|
fHelicopterDestroyed = TRUE;
|
|
|
|
// zero out balance due
|
|
gMercProfiles[ SKYRIDER ].iBalance = 0;
|
|
// iTotalHeliDistanceSinceRefuel = 0;
|
|
iTotalAccumulatedCostByPlayer = 0;
|
|
|
|
// remove vehicle and reset
|
|
RemoveVehicleFromList( iHelicopterVehicleId );
|
|
iHelicopterVehicleId = -1;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN CanHelicopterFly( void )
|
|
{
|
|
// check if heli is available for flight?
|
|
|
|
// is the heli available
|
|
if( fHelicopterAvailable == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( VehicleIdIsValid( iHelicopterVehicleId ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
/*
|
|
// travelled too far?
|
|
if( iTotalHeliDistanceSinceRefuel > MAX_HELICOPTER_DISTANCE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
*/
|
|
|
|
// is the pilot alive, well, and willing to help us?
|
|
if( IsHelicopterPilotAvailable( ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( fHeliReturnStraightToBase == TRUE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// grounded by enemies in sector?
|
|
if ( CanHelicopterTakeOff() == FALSE )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
// everything A-OK!
|
|
return( TRUE );
|
|
}
|
|
|
|
BOOLEAN IsHelicopterPilotAvailable( void )
|
|
{
|
|
// what is state of skyrider?
|
|
if( fSkyRiderAvailable == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// owe any money to skyrider?
|
|
if( gMercProfiles[ SKYRIDER ].iBalance < 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// Drassen too disloyal to wanna help player?
|
|
if ( CheckFact( FACT_LOYALTY_LOW, SKYRIDER ) )
|
|
{
|
|
return ( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
void LandHelicopter( void )
|
|
{
|
|
// set the helictoper down, call arrive callback for this mvt group
|
|
fHelicopterIsAirBorne = FALSE;
|
|
|
|
// no longer hovering
|
|
fHoveringHelicopter = FALSE;
|
|
|
|
// reset fact that we might have returned straight here
|
|
fHeliReturnStraightToBase = FALSE;
|
|
|
|
HandleHelicopterOnGroundGraphic( );
|
|
HandleHelicopterOnGroundSkyriderProfile( );
|
|
|
|
// if we'll be unable to take off again (because there are enemies in the sector, or we owe pilot money)
|
|
if ( CanHelicopterFly() == FALSE )
|
|
{
|
|
// kick everyone out!
|
|
MoveAllInHelicopterToFootMovementGroup( );
|
|
}
|
|
else
|
|
{
|
|
// play meanwhile scene if it hasn't been used yet
|
|
HandleKillChopperMeanwhileScene();
|
|
}
|
|
}
|
|
|
|
|
|
void TakeOffHelicopter( void )
|
|
{
|
|
// heli in the air
|
|
fHelicopterIsAirBorne = TRUE;
|
|
|
|
// no longer hovering
|
|
fHoveringHelicopter = FALSE;
|
|
|
|
HandleHelicopterOnGroundGraphic( );
|
|
HandleHelicopterOnGroundSkyriderProfile( );
|
|
}
|
|
|
|
|
|
|
|
void StartHoverTime( void )
|
|
{
|
|
// start hover in this sector
|
|
fHoveringHelicopter = TRUE;
|
|
|
|
// post event for x mins in future, save start time, if event time - delay = start time, then hover has gone on too long
|
|
uiStartHoverTime = GetWorldTotalMin( );
|
|
|
|
// post event..to call handle hover
|
|
AddStrategicEvent( EVENT_HELICOPTER_HOVER_TOO_LONG, GetWorldTotalMin() + TIME_DELAY_FOR_HOVER_WAIT, 0 );
|
|
|
|
return;
|
|
}
|
|
|
|
void HandleHeliHoverLong( void )
|
|
{
|
|
// post message about hovering too long
|
|
if( fHoveringHelicopter )
|
|
{
|
|
// proper event, post next one
|
|
AddStrategicEvent( EVENT_HELICOPTER_HOVER_WAY_TOO_LONG, uiStartHoverTime + TIME_DELAY_FOR_HOVER_WAIT_TOO_LONG, 0 );
|
|
|
|
// inform player
|
|
HeliCharacterDialogue( pSkyRider, HOVERING_A_WHILE );
|
|
|
|
// stop time compression if it's on
|
|
StopTimeCompression( );
|
|
}
|
|
else
|
|
{
|
|
// reset
|
|
uiStartHoverTime = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void HandleHeliHoverTooLong( void )
|
|
{
|
|
// reset hover time
|
|
uiStartHoverTime = 0;
|
|
|
|
if( fHoveringHelicopter == FALSE )
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// hovered too long, inform player heli is returning to base
|
|
HeliCharacterDialogue( pSkyRider, RETURN_TO_BASE );
|
|
|
|
// If the sector is safe
|
|
if ( NumEnemiesInSector( pVehicleList[ iHelicopterVehicleId ].sSectorX, pVehicleList[ iHelicopterVehicleId ].sSectorY ) == 0 )
|
|
{
|
|
// kick everyone out!
|
|
MoveAllInHelicopterToFootMovementGroup( );
|
|
}
|
|
|
|
MakeHeliReturnToBase();
|
|
}
|
|
|
|
|
|
// check if anyone in the chopper sees any baddies in sector
|
|
BOOLEAN DoesSkyriderNoticeEnemiesInSector( UINT8 ubNumEnemies )
|
|
{
|
|
UINT8 ubChance;
|
|
|
|
// is the pilot and heli around?
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// if there aren't any, he obviously won't see them
|
|
if( ubNumEnemies == 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// figure out what the chance is of seeing them
|
|
// make this relatively accurate most of the time, to encourage helicopter scouting by making it useful
|
|
ubChance = 60 + ubNumEnemies;
|
|
|
|
if( PreRandom( 100 ) < ubChance )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// if the heli is on the move, what is the distance it will move..the length of the merc path, less the first node
|
|
INT32 DistanceOfIntendedHelicopterPath( void )
|
|
{
|
|
PathStPtr pNode = NULL;
|
|
INT32 iLength = 0;
|
|
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
// big number, no go
|
|
return( 9999 );
|
|
}
|
|
|
|
pNode = pVehicleList[ iHelicopterVehicleId ].pMercPath;
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode -> pNext )
|
|
{
|
|
iLength++;
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
pNode = MoveToBeginningOfPathList( pTempHelicopterPath );
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode -> pNext )
|
|
{
|
|
iLength++;
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
return( iLength );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN CheckForArrivalAtRefuelPoint( void )
|
|
{
|
|
// check if this is our final destination
|
|
if ( GetLengthOfPath( pVehicleList[ iHelicopterVehicleId ].pMercPath ) > 0 )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// check if we're at a refuel site
|
|
if( DistanceToNearestRefuelPoint( pVehicleList[ iHelicopterVehicleId ].sSectorX, pVehicleList[ iHelicopterVehicleId ].sSectorY ) > 0 )
|
|
{
|
|
// not at a refuel point
|
|
return( FALSE );
|
|
}
|
|
|
|
// we are at a refuel site
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
|
|
void SetUpHelicopterForMovement( void )
|
|
{
|
|
// check if helicopter vehicle has a mvt group, if not, assign one in this sector
|
|
INT32 iCounter = 0;
|
|
|
|
// if no group, create one for vehicle
|
|
if( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup == 0 )
|
|
{
|
|
// get the vehicle a mvt group
|
|
pVehicleList[ iHelicopterVehicleId ].ubMovementGroup = CreateNewVehicleGroupDepartingFromSector( ( UINT8 )( pVehicleList[ iHelicopterVehicleId ].sSectorX ), ( UINT8 )( pVehicleList[ iHelicopterVehicleId ].sSectorY ), iHelicopterVehicleId );
|
|
|
|
// add everyone in vehicle to this mvt group
|
|
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iHelicopterVehicleId ].ubVehicleType ]; iCounter++ )
|
|
{
|
|
if( pVehicleList[ iHelicopterVehicleId ].pPassengers[ iCounter ] != NULL )
|
|
{
|
|
// add character
|
|
AddPlayerToGroup( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, pVehicleList[ iHelicopterVehicleId ].pPassengers[ iCounter ] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN HeliCharacterDialogue( SOLDIERTYPE *pSoldier, UINT16 usQuoteNum )
|
|
{
|
|
// ARM: we could just return, but since various flags are often being set it's safer to honk so it gets fixed right!
|
|
Assert( fSkyRiderAvailable );
|
|
|
|
return( CharacterDialogue( SKYRIDER, usQuoteNum, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE ) );
|
|
}
|
|
|
|
|
|
INT32 GetNumberOfPassengersInHelicopter( void )
|
|
{
|
|
INT32 iNumber = 0;
|
|
|
|
if( iHelicopterVehicleId != -1 )
|
|
{
|
|
iNumber = GetNumberInVehicle( iHelicopterVehicleId );
|
|
}
|
|
|
|
return( iNumber );
|
|
}
|
|
|
|
|
|
BOOLEAN IsRefuelSiteInSector( INT16 sMapX, INT16 sMapY )
|
|
{
|
|
INT32 iCounter = 0;
|
|
|
|
for( iCounter = 0; iCounter < NUMBER_OF_REFUEL_SITES; iCounter++ )
|
|
{
|
|
if ( ( ubRefuelList[ iCounter ][ 0 ] == sMapX ) && ( ubRefuelList[ iCounter ][ 1 ] == sMapY ) )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
void UpdateRefuelSiteAvailability( void )
|
|
{
|
|
INT32 iCounter = 0;
|
|
|
|
// Generally, only Drassen is initially available for refuelling
|
|
// Estoni must first be captured (although player may already have it when he gets Skyrider!)
|
|
|
|
for( iCounter = 0; iCounter < NUMBER_OF_REFUEL_SITES; iCounter++ )
|
|
{
|
|
// if enemy controlled sector (ground OR air, don't want to fly into enemy air territory)
|
|
if( ( StrategicMap[ CALCULATE_STRATEGIC_INDEX( ubRefuelList[ iCounter ][ 0 ], ubRefuelList[ iCounter ][ 1 ] ) ].fEnemyControlled == TRUE ) ||
|
|
( StrategicMap[ CALCULATE_STRATEGIC_INDEX( ubRefuelList[ iCounter ][ 0 ], ubRefuelList[ iCounter ][ 1 ] ) ].fEnemyAirControlled == TRUE ) ||
|
|
( ( iCounter == ESTONI_REFUELING_SITE ) && ( CheckFact( FACT_ESTONI_REFUELLING_POSSIBLE, 0 ) == FALSE ) ) )
|
|
{
|
|
// mark refueling site as unavailable
|
|
fRefuelingSiteAvailable[ iCounter ] = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// mark refueling site as available
|
|
fRefuelingSiteAvailable[ iCounter ] = TRUE;
|
|
|
|
// reactivate a grounded helicopter, if here
|
|
if ( !fHelicopterAvailable && !fHelicopterDestroyed && fSkyRiderAvailable && ( iHelicopterVehicleId != -1 ) )
|
|
{
|
|
if( ( pVehicleList[ iHelicopterVehicleId ].sSectorX == ubRefuelList[ iCounter ][ 0 ]) &&
|
|
( pVehicleList[ iHelicopterVehicleId ].sSectorY == ubRefuelList[ iCounter ][ 1 ]) )
|
|
{
|
|
// no longer grounded
|
|
DoScreenIndependantMessageBox( pSkyriderText[ 5 ], MSG_BOX_FLAG_OK, NULL );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SetUpHelicopterForPlayer( INT16 sX, INT16 sY )
|
|
{
|
|
if( fSkyRiderSetUp == FALSE )
|
|
{
|
|
fHelicopterAvailable = TRUE;
|
|
fSkyRiderAvailable = TRUE;
|
|
|
|
iHelicopterVehicleId = AddVehicleToList( sX, sY, 0, HELICOPTER );
|
|
|
|
Assert( iHelicopterVehicleId != -1 );
|
|
|
|
memset( &SoldierSkyRider, 0, sizeof( SOLDIERTYPE ) );
|
|
SoldierSkyRider.ubProfile = SKYRIDER;
|
|
SoldierSkyRider.bLife = 80;
|
|
|
|
pSkyRider = &( SoldierSkyRider );
|
|
|
|
// set up for movement
|
|
SetUpHelicopterForMovement( );
|
|
UpdateRefuelSiteAvailability( );
|
|
|
|
fSkyRiderSetUp = TRUE;
|
|
|
|
gMercProfiles[ SKYRIDER ].fUseProfileInsertionInfo = FALSE;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
UINT8 MoveAllInHelicopterToFootMovementGroup( void )
|
|
{
|
|
// take everyone out of heli and add to movement group
|
|
INT32 iCounter = 0;
|
|
UINT8 ubGroupId = 0;
|
|
SOLDIERTYPE *pSoldier;
|
|
INT8 bNewSquad;
|
|
BOOLEAN fAnyoneAboard = FALSE;
|
|
BOOLEAN fSuccess;
|
|
UINT8 ubInsertionCode;
|
|
BOOLEAN fInsertionCodeSet = FALSE;
|
|
UINT16 usInsertionData;
|
|
|
|
|
|
// put these guys on their own squad (we need to return their group ID, and can only return one, so they need a unique one
|
|
bNewSquad = GetFirstEmptySquad();
|
|
if ( bNewSquad == -1 )
|
|
{
|
|
return( 0 );
|
|
}
|
|
|
|
// go through list of everyone in helicopter
|
|
for( iCounter = 0; iCounter < iSeatingCapacities[ pVehicleList[ iHelicopterVehicleId ].ubVehicleType ]; iCounter++ )
|
|
{
|
|
// get passenger
|
|
pSoldier = pVehicleList[ iHelicopterVehicleId ].pPassengers[ iCounter ];
|
|
|
|
if( pSoldier != NULL )
|
|
{
|
|
// better really be in there!
|
|
Assert ( pSoldier->bAssignment == VEHICLE );
|
|
Assert ( pSoldier->iVehicleId == iHelicopterVehicleId );
|
|
|
|
fAnyoneAboard = TRUE;
|
|
|
|
fSuccess = RemoveSoldierFromHelicopter( pSoldier );
|
|
Assert( fSuccess );
|
|
|
|
AddCharacterToSquad( pSoldier, bNewSquad );
|
|
|
|
// ATE: OK - the ubStrategicInsertionCode is set 'cause groupArrivesInsector has been
|
|
// called when buddy is added to a squad. However, the insertion code onlt sets set for
|
|
// the first merc, so the rest are going to use whatever they had previously....
|
|
if ( !fInsertionCodeSet )
|
|
{
|
|
ubInsertionCode = pSoldier->ubStrategicInsertionCode;
|
|
usInsertionData = pSoldier->usStrategicInsertionData;
|
|
fInsertionCodeSet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pSoldier->ubStrategicInsertionCode = ubInsertionCode;
|
|
pSoldier->usStrategicInsertionData = usInsertionData;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fAnyoneAboard )
|
|
{
|
|
ubGroupId = SquadMovementGroups[ bNewSquad ];
|
|
}
|
|
|
|
return( ubGroupId );
|
|
}
|
|
|
|
|
|
|
|
void SkyRiderTalk( UINT16 usQuoteNum )
|
|
{
|
|
// have skyrider talk to player
|
|
HeliCharacterDialogue( pSkyRider, usQuoteNum );
|
|
|
|
fTeamPanelDirty = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleSkyRiderMonologueEvent( UINT32 uiEventCode, UINT32 uiSpecialCode )
|
|
{
|
|
// will handle the skyrider monologue about where the SAM sites are and what not
|
|
|
|
TurnOnAirSpaceMode();
|
|
|
|
switch( uiEventCode )
|
|
{
|
|
case( SKYRIDER_MONOLOGUE_EVENT_DRASSEN_SAM_SITE ):
|
|
SetExternMapscreenSpeechPanelXY( DEFAULT_EXTERN_PANEL_X_POS, 117 );
|
|
HandleSkyRiderMonologueAboutDrassenSAMSite( uiSpecialCode );
|
|
break;
|
|
case SKYRIDER_MONOLOGUE_EVENT_CAMBRIA_HOSPITAL:
|
|
SetExternMapscreenSpeechPanelXY( DEFAULT_EXTERN_PANEL_X_POS, 172 );
|
|
HandleSkyRiderMonologueAboutCambriaHospital( uiSpecialCode );
|
|
break;
|
|
case( SKYRIDER_MONOLOGUE_EVENT_OTHER_SAM_SITES ):
|
|
SetExternMapscreenSpeechPanelXY( 335, DEFAULT_EXTERN_PANEL_Y_POS );
|
|
HandleSkyRiderMonologueAboutOtherSAMSites( uiSpecialCode );
|
|
break;
|
|
case( SKYRIDER_MONOLOGUE_EVENT_ESTONI_REFUEL ):
|
|
SetExternMapscreenSpeechPanelXY( DEFAULT_EXTERN_PANEL_X_POS, DEFAULT_EXTERN_PANEL_Y_POS );
|
|
HandleSkyRiderMonologueAboutEstoniRefuel( uiSpecialCode );
|
|
break;
|
|
}
|
|
|
|
// update time
|
|
guiTimeOfLastSkyriderMonologue = GetWorldTotalMin();
|
|
}
|
|
|
|
|
|
void HandleSkyRiderMonologueAboutEstoniRefuel( UINT32 uiSpecialCode )
|
|
{
|
|
// once estoni is free tell player about refueling
|
|
|
|
switch( uiSpecialCode )
|
|
{
|
|
case( 0 ):
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, SPIEL_ABOUT_ESTONI_AIRSPACE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_ESTONI_REFUEL, 1 );
|
|
// if special event data 2 is true, then do dialogue, else this is just a trigger for an event
|
|
CharacterDialogue( SKYRIDER, SPIEL_ABOUT_ESTONI_AIRSPACE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, SPIEL_ABOUT_ESTONI_AIRSPACE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_ESTONI_REFUEL, 2 );
|
|
break;
|
|
|
|
case( 1 ):
|
|
// highlight Estoni
|
|
fShowEstoniRefuelHighLight = TRUE;
|
|
break;
|
|
|
|
case( 2 ):
|
|
fShowEstoniRefuelHighLight = FALSE;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleSkyRiderMonologueAboutDrassenSAMSite( UINT32 uiSpecialCode )
|
|
{
|
|
switch( uiSpecialCode )
|
|
{
|
|
case( 0 ):
|
|
//gpCurrentTalkingFace = &gFacesData[ uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] ];
|
|
//gubCurrentTalkingID = SKYRIDER;
|
|
|
|
// if special event data 2 is true, then do dialogue, else this is just a trigger for an event
|
|
CharacterDialogue( SKYRIDER, MENTION_DRASSEN_SAM_SITE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, MENTION_DRASSEN_SAM_SITE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI , FALSE , TRUE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_DRASSEN_SAM_SITE, 1 );
|
|
|
|
if( SAMSitesUnderPlayerControl( SAM_2_X, SAM_2_Y ) == FALSE )
|
|
{
|
|
CharacterDialogue( SKYRIDER, SECOND_HALF_OF_MENTION_DRASSEN_SAM_SITE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
}
|
|
else
|
|
{
|
|
// Ian says don't use the SAM site quote unless player has tried flying already
|
|
if ( CheckFact( FACT_SKYRIDER_USED_IN_MAPSCREEN, SKYRIDER ) )
|
|
{
|
|
CharacterDialogue( SKYRIDER, SAM_SITE_TAKEN, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
gfSkyriderSaidCongratsOnTakingSAM = TRUE;
|
|
}
|
|
}
|
|
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, MENTION_DRASSEN_SAM_SITE, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI , FALSE , TRUE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_DRASSEN_SAM_SITE, 2 );
|
|
break;
|
|
|
|
case( 1 ):
|
|
// highlight Drassen SAM site sector
|
|
fShowDrassenSAMHighLight = TRUE;
|
|
SetSAMSiteAsFound( SAM_SITE_TWO );
|
|
break;
|
|
|
|
case( 2 ):
|
|
fShowDrassenSAMHighLight = FALSE;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleSkyRiderMonologueAboutCambriaHospital( UINT32 uiSpecialCode )
|
|
{
|
|
switch( uiSpecialCode )
|
|
{
|
|
case( 0 ):
|
|
//gpCurrentTalkingFace = &gFacesData[ uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] ];
|
|
//gubCurrentTalkingID = SKYRIDER;
|
|
|
|
// if special event data 2 is true, then do dialogue, else this is just a trigger for an event
|
|
CharacterDialogue( SKYRIDER, MENTION_HOSPITAL_IN_CAMBRIA, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, MENTION_HOSPITAL_IN_CAMBRIA, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI , FALSE , TRUE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_CAMBRIA_HOSPITAL, 1 );
|
|
|
|
// highlight Drassen hospital sector
|
|
fShowCambriaHospitalHighLight = TRUE;
|
|
break;
|
|
|
|
case( 1 ):
|
|
fShowCambriaHospitalHighLight = FALSE;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void HandleSkyRiderMonologueAboutOtherSAMSites( UINT32 uiSpecialCode )
|
|
{
|
|
// handle skyrider telling player about other sam sites..on fifth hiring or after one near drassen is taken out
|
|
|
|
switch( uiSpecialCode )
|
|
{
|
|
case( 0 ):
|
|
// do quote 21
|
|
gpCurrentTalkingFace = &gFacesData[ uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] ];
|
|
gubCurrentTalkingID = SKYRIDER;
|
|
|
|
// if special event data 2 is true, then do dialogue, else this is just a trigger for an event
|
|
CharacterDialogue( SKYRIDER, SPIEL_ABOUT_OTHER_SAM_SITES, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, SPIEL_ABOUT_OTHER_SAM_SITES, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_OTHER_SAM_SITES, 1 );
|
|
|
|
CharacterDialogue( SKYRIDER, SECOND_HALF_OF_SPIEL_ABOUT_OTHER_SAM_SITES, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ], DIALOGUE_EXTERNAL_NPC_UI, FALSE, FALSE );
|
|
CharacterDialogueWithSpecialEvent( SKYRIDER, SPIEL_ABOUT_OTHER_SAM_SITES, uiExternalStaticNPCFaces[ SKYRIDER_EXTERNAL_FACE ] , DIALOGUE_EXTERNAL_NPC_UI , FALSE , FALSE , DIALOGUE_SPECIAL_EVENT_SKYRIDERMAPSCREENEVENT ,SKYRIDER_MONOLOGUE_EVENT_OTHER_SAM_SITES, 2 );
|
|
|
|
break;
|
|
|
|
case( 1 ):
|
|
// highlight other SAMs
|
|
fShowOtherSAMHighLight = TRUE;
|
|
// reveal other 3 SAM sites
|
|
SetSAMSiteAsFound( SAM_SITE_ONE );
|
|
SetSAMSiteAsFound( SAM_SITE_THREE );
|
|
SetSAMSiteAsFound( SAM_SITE_FOUR );
|
|
break;
|
|
|
|
case( 2 ):
|
|
fShowOtherSAMHighLight = FALSE;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
void CheckAndHandleSkyriderMonologues( void )
|
|
{
|
|
// wait at least this many days between Skyrider monologues
|
|
if ( ( GetWorldTotalMin() - guiTimeOfLastSkyriderMonologue ) >= ( MIN_DAYS_BETWEEN_SKYRIDER_MONOLOGUES * 24 * 60 ) )
|
|
{
|
|
if( guiHelicopterSkyriderTalkState == 0 )
|
|
{
|
|
HandleSkyRiderMonologueEvent( SKYRIDER_MONOLOGUE_EVENT_DRASSEN_SAM_SITE, 0 );
|
|
guiHelicopterSkyriderTalkState = 1;
|
|
}
|
|
else if( guiHelicopterSkyriderTalkState == 1 )
|
|
{
|
|
// if enemy still controls the Cambria hospital sector
|
|
if( StrategicMap[ CALCULATE_STRATEGIC_INDEX( HOSPITAL_SECTOR_X, HOSPITAL_SECTOR_Y ) ].fEnemyControlled )
|
|
{
|
|
HandleSkyRiderMonologueEvent( SKYRIDER_MONOLOGUE_EVENT_CAMBRIA_HOSPITAL, 0 );
|
|
}
|
|
// advance state even if player already has Cambria's hospital sector!!!
|
|
guiHelicopterSkyriderTalkState = 2;
|
|
}
|
|
else if( guiHelicopterSkyriderTalkState == 2 )
|
|
{
|
|
// wait until player has taken over a SAM site before saying this and advancing state
|
|
if ( gfSkyriderSaidCongratsOnTakingSAM )
|
|
{
|
|
HandleSkyRiderMonologueEvent( SKYRIDER_MONOLOGUE_EVENT_OTHER_SAM_SITES, 0 );
|
|
guiHelicopterSkyriderTalkState = 3;
|
|
}
|
|
}
|
|
else if( guiHelicopterSkyriderTalkState == 3 )
|
|
{
|
|
// wait until Estoni refuelling site becomes available
|
|
if ( fRefuelingSiteAvailable[ ESTONI_REFUELING_SITE ] )
|
|
{
|
|
HandleSkyRiderMonologueEvent( SKYRIDER_MONOLOGUE_EVENT_ESTONI_REFUEL, 0 );
|
|
guiHelicopterSkyriderTalkState = 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void HandleAnimationOfSectors( void )
|
|
{
|
|
BOOLEAN fSkipSpeakersLocator = FALSE;
|
|
// these don't need to be saved, they merely turn off the highlights after they stop flashing
|
|
static BOOLEAN fOldShowDrassenSAMHighLight = FALSE;
|
|
static BOOLEAN fOldShowCambriaHospitalHighLight = FALSE;
|
|
static BOOLEAN fOldShowEstoniRefuelHighLight = FALSE;
|
|
static BOOLEAN fOldShowOtherSAMHighLight = FALSE;
|
|
|
|
// find out which mode we are in and animate for that mode
|
|
|
|
// Drassen SAM site
|
|
if( fShowDrassenSAMHighLight )
|
|
{
|
|
fOldShowDrassenSAMHighLight = TRUE;
|
|
// Drassen's SAM site is #3
|
|
HandleBlitOfSectorLocatorIcon( SAM_2_X, SAM_2_Y, 0, LOCATOR_COLOR_RED );
|
|
fSkipSpeakersLocator = TRUE;
|
|
}
|
|
else if( fOldShowDrassenSAMHighLight )
|
|
{
|
|
fOldShowDrassenSAMHighLight = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
// Cambria hospital
|
|
if( fShowCambriaHospitalHighLight )
|
|
{
|
|
fOldShowCambriaHospitalHighLight = TRUE;
|
|
HandleBlitOfSectorLocatorIcon( HOSPITAL_SECTOR_X, HOSPITAL_SECTOR_Y, 0, LOCATOR_COLOR_RED );
|
|
fSkipSpeakersLocator = TRUE;
|
|
}
|
|
else if( fOldShowCambriaHospitalHighLight )
|
|
{
|
|
fOldShowCambriaHospitalHighLight = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
// show other SAM sites
|
|
if( fShowOtherSAMHighLight )
|
|
{
|
|
fOldShowOtherSAMHighLight = TRUE;
|
|
HandleBlitOfSectorLocatorIcon( SAM_1_X, SAM_1_Y, 0, LOCATOR_COLOR_RED );
|
|
HandleBlitOfSectorLocatorIcon( SAM_3_X, SAM_3_Y, 0, LOCATOR_COLOR_RED );
|
|
HandleBlitOfSectorLocatorIcon( SAM_4_X, SAM_4_Y, 0, LOCATOR_COLOR_RED );
|
|
fSkipSpeakersLocator = TRUE;
|
|
}
|
|
else if( fOldShowOtherSAMHighLight )
|
|
{
|
|
fOldShowOtherSAMHighLight = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
// show Estoni site
|
|
if( fShowEstoniRefuelHighLight )
|
|
{
|
|
fOldShowEstoniRefuelHighLight = TRUE;
|
|
HandleBlitOfSectorLocatorIcon( ubRefuelList[ ESTONI_REFUELING_SITE ][ 0 ], ubRefuelList[ ESTONI_REFUELING_SITE ][ 1 ], 0, LOCATOR_COLOR_RED );
|
|
fSkipSpeakersLocator = TRUE;
|
|
}
|
|
else if( fOldShowEstoniRefuelHighLight )
|
|
{
|
|
fOldShowEstoniRefuelHighLight = FALSE;
|
|
fMapPanelDirty = TRUE;
|
|
}
|
|
|
|
|
|
// don't show sector locator over the speaker's sector if he is talking about another sector - it's confusing
|
|
if ( !fSkipSpeakersLocator )
|
|
{
|
|
switch( gubBlitSectorLocatorCode )
|
|
{
|
|
case LOCATOR_COLOR_RED: // normal one used for mines (will now be overriden with yellow)
|
|
HandleBlitOfSectorLocatorIcon( gsSectorLocatorX, gsSectorLocatorY, 0, LOCATOR_COLOR_RED );
|
|
break;
|
|
case LOCATOR_COLOR_YELLOW: // used for all other dialogues
|
|
HandleBlitOfSectorLocatorIcon( gsSectorLocatorX, gsSectorLocatorY, 0, LOCATOR_COLOR_YELLOW );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
INT16 LastSectorInHelicoptersPath( void )
|
|
{
|
|
// get the last sector value in the helictoper's path
|
|
PathStPtr pNode = NULL;
|
|
UINT32 uiLocation = 0;
|
|
|
|
// if the heli is on the move, what is the distance it will move..the length of the merc path, less the first node
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
// big number, no go
|
|
return( 0 );
|
|
}
|
|
|
|
uiLocation = pVehicleList[ iHelicopterVehicleId ].sSectorX + pVehicleList[ iHelicopterVehicleId ].sSectorY * MAP_WORLD_X;
|
|
|
|
pNode = pVehicleList[ iHelicopterVehicleId ].pMercPath;
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode)
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
pNode = MoveToBeginningOfPathList( pTempHelicopterPath );
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode )
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
return( ( INT16 )uiLocation );
|
|
}
|
|
|
|
|
|
/*
|
|
INT32 GetTotalCostOfHelicopterTrip( void )
|
|
{
|
|
// get cost of helicopter trip
|
|
|
|
PathStPtr pNode = NULL, pTempNode = NULL;
|
|
UINT32 uiCost = 0;
|
|
UINT32 uiLastTempPathSectorId = 0;
|
|
UINT32 iClosestRefuelPoint = 0;
|
|
UINT32 uiStartSectorNum = 0;
|
|
UINT32 uiLength = 0;
|
|
|
|
// if the heli is on the move, what is the distance it will move..the length of the merc path, less the first node
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
// big number, no go
|
|
return( 0 );
|
|
}
|
|
|
|
pNode = pVehicleList[ iHelicopterVehicleId ].pMercPath;
|
|
|
|
// any path yet?
|
|
uiLastTempPathSectorId = pVehicleList[ iHelicopterVehicleId ].sSectorX + pVehicleList[ iHelicopterVehicleId ].sSectorY * MAP_WORLD_X;
|
|
uiStartSectorNum = uiLastTempPathSectorId;
|
|
|
|
if( pNode )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode)
|
|
{
|
|
if( uiLength == 0 )
|
|
{
|
|
if( pNode->pNext )
|
|
{
|
|
if( uiLastTempPathSectorId == pNode->pNext->uiSectorId )
|
|
{
|
|
// do nothing
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
|
|
uiLength++;
|
|
|
|
uiLastTempPathSectorId = pNode ->uiSectorId;
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
pNode = NULL;
|
|
|
|
if( pTempHelicopterPath )
|
|
{
|
|
pNode = MoveToBeginningOfPathList( pTempHelicopterPath );
|
|
}
|
|
|
|
if( pNode )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
while( pNode )
|
|
{
|
|
if( uiLength == 0 )
|
|
{
|
|
if( pNode->pNext )
|
|
{
|
|
if( uiLastTempPathSectorId == pNode->pNext->uiSectorId )
|
|
{
|
|
// do nothing
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
|
|
uiLength++;
|
|
|
|
//uiCost += GetCostOfPassageForHelicopter( ( UINT16 ) ( pNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pNode->uiSectorId / MAP_WORLD_X ) );
|
|
uiLastTempPathSectorId = pNode ->uiSectorId;
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
iClosestRefuelPoint = ( INT16 )( CALCULATE_STRATEGIC_INDEX( ubRefuelList[ LocationOfNearestRefuelPoint( FALSE ) ][ 0 ], ubRefuelList[ LocationOfNearestRefuelPoint( FALSE ) ][ 1 ] ) );
|
|
|
|
pNode = NULL;
|
|
|
|
if( uiLastTempPathSectorId != iClosestRefuelPoint )
|
|
{
|
|
pNode = BuildAStrategicPath( pNode, ( INT16 )( uiLastTempPathSectorId ), ( INT16 )iClosestRefuelPoint, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, FALSE );
|
|
// pNode = BuildAStrategicPath( pNode, ( INT16 )( uiLastTempPathSectorId ), ( INT16 )iClosestRefuelPoint, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, FALSE, TRUE );
|
|
|
|
pNode = MoveToBeginningOfPathList( pNode );
|
|
}
|
|
|
|
pTempNode = pNode;
|
|
uiLength = 0;
|
|
|
|
if( pTempNode )
|
|
{
|
|
pTempNode = pTempNode->pNext;
|
|
}
|
|
|
|
while( pTempNode )
|
|
{
|
|
if( uiLength == 0 )
|
|
{
|
|
if( pTempNode->pNext )
|
|
{
|
|
if( uiLastTempPathSectorId == pNode->pNext->uiSectorId )
|
|
{
|
|
// do nothing
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pTempNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pTempNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pTempNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pTempNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uiCost += GetCostOfPassageForHelicopter( ( UINT16 )( pTempNode -> uiSectorId % MAP_WORLD_X ), ( UINT16 ) ( pTempNode->uiSectorId / MAP_WORLD_X ) );
|
|
}
|
|
|
|
uiLength++;
|
|
pTempNode = pTempNode->pNext;
|
|
}
|
|
|
|
return( ( INT32 )uiCost );
|
|
}
|
|
*/
|
|
|
|
|
|
void HandleHelicopterOnGroundGraphic( void )
|
|
{
|
|
UINT8 ubSite = 0;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
// no worries if underground
|
|
if (gbWorldSectorZ != 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for( ubSite = 0; ubSite < NUMBER_OF_REFUEL_SITES; ubSite++ )
|
|
{
|
|
// is this refueling site sector the loaded sector ?
|
|
if ( ( ubRefuelList[ ubSite ][ 0 ] == gWorldSectorX ) && ( ubRefuelList[ ubSite ][ 1 ] == gWorldSectorY ) )
|
|
{
|
|
// YES, so find out if the chopper is landed here
|
|
if ( IsHelicopterOnGroundAtRefuelingSite( ubSite ) )
|
|
{
|
|
// Add....
|
|
AddHelicopterToMaps( TRUE, ubSite );
|
|
// ATE: Add skyridder too
|
|
// ATE: only if hired......
|
|
if ( fHelicopterAvailable )
|
|
{
|
|
gMercProfiles[ SKYRIDER ].sSectorX = gWorldSectorX;
|
|
gMercProfiles[ SKYRIDER ].sSectorY = gWorldSectorY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddHelicopterToMaps( FALSE, ubSite );
|
|
// ATE: Remove skyridder....
|
|
if ( fHelicopterAvailable )
|
|
{
|
|
gMercProfiles[ SKYRIDER ].sSectorX = 0;
|
|
gMercProfiles[ SKYRIDER ].sSectorY = 0;
|
|
|
|
// see if we can find him and remove him if so....
|
|
pSoldier = FindSoldierByProfileID( SKYRIDER, FALSE );
|
|
|
|
// ATE: Don't do this if buddy is on our team!
|
|
if ( pSoldier != NULL && pSoldier->bTeam != gbPlayerNum )
|
|
{
|
|
TacticalRemoveSoldier( pSoldier->ubID );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Invalidate rendering
|
|
InvalidateWorldRedundency( );
|
|
|
|
// can't be 2 places at once!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void HandleHelicopterOnGroundSkyriderProfile( void )
|
|
{
|
|
UINT8 ubSite = 0;
|
|
SOLDIERTYPE *pSoldier;
|
|
|
|
// no worries if underground
|
|
if (gbWorldSectorZ != 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for( ubSite = 0; ubSite < NUMBER_OF_REFUEL_SITES; ubSite++ )
|
|
{
|
|
// is this refueling site sector the loaded sector ?
|
|
if ( ( ubRefuelList[ ubSite ][ 0 ] == gWorldSectorX ) && ( ubRefuelList[ ubSite ][ 1 ] == gWorldSectorY ) )
|
|
{
|
|
// YES, so find out if the chopper is landed here
|
|
if ( IsHelicopterOnGroundAtRefuelingSite( ubSite ) )
|
|
{
|
|
// ATE: Add skyridder too
|
|
// ATE: only if hired......
|
|
if ( fHelicopterAvailable )
|
|
{
|
|
gMercProfiles[ SKYRIDER ].sSectorX = gWorldSectorX;
|
|
gMercProfiles[ SKYRIDER ].sSectorY = gWorldSectorY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ATE: Remove skyridder....
|
|
if ( fHelicopterAvailable )
|
|
{
|
|
gMercProfiles[ SKYRIDER ].sSectorX = 0;
|
|
gMercProfiles[ SKYRIDER ].sSectorY = 0;
|
|
|
|
// see if we can find him and remove him if so....
|
|
pSoldier = FindSoldierByProfileID( SKYRIDER, FALSE );
|
|
|
|
// ATE: Don't do this if buddy is on our team!
|
|
if ( pSoldier != NULL && pSoldier->bTeam != gbPlayerNum )
|
|
{
|
|
TacticalRemoveSoldier( pSoldier->ubID );
|
|
}
|
|
}
|
|
}
|
|
|
|
// can't be 2 places at once!
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN IsHelicopterOnGroundAtRefuelingSite( UINT8 ubRefuelingSite )
|
|
{
|
|
if ( fHelicopterDestroyed )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
if ( fHelicopterIsAirBorne )
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// if we haven't even met SkyRider
|
|
if ( !fSkyRiderSetUp )
|
|
{
|
|
// then it's always at Drassen
|
|
if ( ubRefuelingSite == DRASSEN_REFUELING_SITE )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
else
|
|
{
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
// skyrider is setup, helicopter isn't destroyed, so this ought to be a valid vehicle id
|
|
Assert( iHelicopterVehicleId != -1 );
|
|
|
|
// on the ground, but is it at this site or at another one?
|
|
if ( ( ubRefuelList[ ubRefuelingSite ][ 0 ] == pVehicleList[ iHelicopterVehicleId ].sSectorX ) &&
|
|
( ubRefuelList[ ubRefuelingSite ][ 1 ] == pVehicleList[ iHelicopterVehicleId ].sSectorY ) )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
// not here
|
|
return(FALSE);
|
|
}
|
|
|
|
// drassen airport sector
|
|
#define AIRPORT_X 13
|
|
#define AIRPORT_Y 2
|
|
|
|
// meduna airport sector
|
|
#define AIRPORT2_X 3
|
|
#define AIRPORT2_Y 14
|
|
|
|
BOOLEAN WillAirRaidBeStopped( INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
UINT8 ubSamNumber = 0;
|
|
INT8 bSAMCondition;
|
|
UINT8 ubChance;
|
|
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: enemy air controlled = %d",StrategicMap[CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].fEnemyAirControlled));
|
|
// if enemy controls this SAM site, then it can't stop an air raid
|
|
if( StrategicMap[CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].fEnemyAirControlled == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if( !StrategicMap[ ( AIRPORT_X + ( MAP_WORLD_X * AIRPORT_Y ) ) ].fEnemyControlled && !StrategicMap[ ( AIRPORT2_X + ( MAP_WORLD_X * AIRPORT2_Y ) ) ].fEnemyControlled )
|
|
{
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: enemy has no more airports"));
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
// which SAM controls this sector?
|
|
ubSamNumber = ubSAMControlledSectors[ sSectorY ][ sSectorX ];
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: SAM number = %d",ubSamNumber));
|
|
// if none of them
|
|
if (ubSamNumber == 0)
|
|
{
|
|
return( FALSE);
|
|
}
|
|
|
|
// get the condition of that SAM site (NOTE: SAM #s are 1-4, but indexes are 0-3!!!)
|
|
Assert( ubSamNumber <= NUMBER_OF_SAMS );
|
|
bSAMCondition = StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( pSamList[ ubSamNumber - 1 ] ) ].bSAMCondition;
|
|
|
|
// if it's too busted to work, then it can't stop an air raid
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: SAM condition = %d",bSAMCondition));
|
|
if( bSAMCondition < MIN_CONDITION_FOR_SAM_SITE_TO_WORK )
|
|
{
|
|
// no problem, SAM site not working
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// Friendly airspace controlled by a working SAM site, so SAM site fires a SAM at air raid bomber
|
|
|
|
// calc chance that chopper will be shot down
|
|
ubChance = bSAMCondition;
|
|
|
|
// there's a fair chance of a miss even if the SAM site is in perfect working order
|
|
if (ubChance > MAX_SAM_SITE_ACCURACY * 3) // Madd - since this is only used for enemy air raids, we'll say that good guy SAMs can have a max of 99% to hit instead of 33%
|
|
{
|
|
ubChance = MAX_SAM_SITE_ACCURACY * 3;
|
|
}
|
|
|
|
if( PreRandom( 100 ) < ubChance)
|
|
{
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: return true"));
|
|
return( TRUE );
|
|
}
|
|
|
|
DebugMsg(TOPIC_JA2,DBG_LEVEL_3,String("WillAirRaidBeStopped: return false"));
|
|
return( FALSE );
|
|
}
|
|
|
|
void HeliCrashSoundStopCallback( void *pData )
|
|
{
|
|
SkyriderDestroyed( );
|
|
}
|
|
|
|
|
|
BOOLEAN HandleSAMSiteAttackOfHelicopterInSector( INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
UINT8 ubSamNumber = 0;
|
|
INT8 bSAMCondition;
|
|
UINT8 ubChance;
|
|
|
|
// if this sector is in friendly airspace, we're safe
|
|
if( StrategicMap[CALCULATE_STRATEGIC_INDEX( sSectorX, sSectorY ) ].fEnemyAirControlled == FALSE )
|
|
{
|
|
// no problem, friendly airspace
|
|
return( FALSE );
|
|
}
|
|
|
|
// which SAM controls this sector?
|
|
ubSamNumber = ubSAMControlledSectors[ sSectorY ][ sSectorX ];
|
|
|
|
// if none of them
|
|
if (ubSamNumber == 0)
|
|
{
|
|
return( FALSE);
|
|
}
|
|
|
|
// get the condition of that SAM site (NOTE: SAM #s are 1-4, but indexes are 0-3!!!)
|
|
Assert( ubSamNumber <= NUMBER_OF_SAMS );
|
|
bSAMCondition = StrategicMap[ SECTOR_INFO_TO_STRATEGIC_INDEX( pSamList[ ubSamNumber - 1 ] ) ].bSAMCondition;
|
|
|
|
// if the SAM site is too damaged to be a threat
|
|
if( bSAMCondition < MIN_CONDITION_FOR_SAM_SITE_TO_WORK )
|
|
{
|
|
// no problem, SAM site not working
|
|
return( FALSE );
|
|
}
|
|
|
|
#ifdef JA2TESTVERSION
|
|
if( fSAMSitesDisabledFromAttackingPlayer == TRUE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
#endif
|
|
// Hostile airspace controlled by a working SAM site, so SAM site fires a SAM at Skyrider!!!
|
|
|
|
// calc chance that chopper will be shot down
|
|
ubChance = bSAMCondition;
|
|
|
|
// there's a fair chance of a miss even if the SAM site is in perfect working order
|
|
if (ubChance > MAX_SAM_SITE_ACCURACY)
|
|
{
|
|
ubChance = MAX_SAM_SITE_ACCURACY;
|
|
}
|
|
|
|
if( PreRandom( 100 ) < ubChance)
|
|
{
|
|
// another hit!
|
|
gubHelicopterHitsTaken++;
|
|
|
|
// Took a hit! Pause time so player can reconsider
|
|
StopTimeCompression();
|
|
|
|
// first hit?
|
|
if ( gubHelicopterHitsTaken == 1 )
|
|
{
|
|
HeliCharacterDialogue( pSkyRider, HELI_TOOK_MINOR_DAMAGE );
|
|
}
|
|
// second hit?
|
|
else if ( gubHelicopterHitsTaken == 2 )
|
|
{
|
|
// going back to base (no choice, dialogue says so)
|
|
HeliCharacterDialogue( pSkyRider, HELI_TOOK_MAJOR_DAMAGE );
|
|
MakeHeliReturnToBase();
|
|
}
|
|
// third hit!
|
|
else
|
|
{
|
|
// Important: Skyrider must still be alive when he talks, so must do this before heli is destroyed!
|
|
HeliCharacterDialogue( pSkyRider, HELI_GOING_DOWN );
|
|
|
|
// everyone die die die
|
|
// play sound
|
|
if ( PlayJA2StreamingSampleFromFile( "stsounds\\blah2.wav", RATE_11025, HIGHVOLUME, 1, MIDDLEPAN, HeliCrashSoundStopCallback ) == SOUND_ERROR )
|
|
{
|
|
// Destroy here if we cannot play streamed sound sample....
|
|
SkyriderDestroyed( );
|
|
}
|
|
else
|
|
{
|
|
// otherwise it's handled in the callback
|
|
// remove any arrival events for the helicopter's group
|
|
DeleteStrategicEvent( EVENT_GROUP_ARRIVAL, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
}
|
|
|
|
// special return code indicating heli was destroyed
|
|
return( TRUE );
|
|
}
|
|
}
|
|
|
|
// still flying
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// are we at the end of the path for the heli?
|
|
BOOLEAN EndOfHelicoptersPath( void )
|
|
{
|
|
if( pVehicleList[ iHelicopterVehicleId ].pMercPath == NULL )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
if( pVehicleList[ iHelicopterVehicleId ].pMercPath->pNext == NULL )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
// check if helicopter can take off?
|
|
BOOLEAN CanHelicopterTakeOff( void )
|
|
{
|
|
INT16 sHelicopterSector = 0;
|
|
|
|
// if it's already in the air
|
|
if( fHelicopterIsAirBorne == TRUE )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
// grab location
|
|
sHelicopterSector = pVehicleList[ iHelicopterVehicleId ].sSectorX + pVehicleList[ iHelicopterVehicleId ].sSectorY * MAP_WORLD_X;
|
|
// if it's not in enemy control, we can take off
|
|
if( StrategicMap[ sHelicopterSector ].fEnemyControlled == FALSE )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
void AddHeliPeice( INT16 sGridNo, UINT16 sOStruct )
|
|
{
|
|
UINT16 usDummy;
|
|
|
|
// ATE: Check first if already exists....
|
|
if ( !TypeExistsInStructLayer( sGridNo, sOStruct, &usDummy ) )
|
|
{
|
|
// place in the world
|
|
AddStructToTail( sGridNo, sOStruct );
|
|
}
|
|
}
|
|
|
|
|
|
void AddHelicopterToMaps( BOOLEAN fAdd, UINT8 ubSite )
|
|
{
|
|
INT16 sGridNo = sRefuelStartGridNo[ ubSite ];
|
|
INT16 sOStruct = 0;
|
|
INT16 usGridNo;
|
|
INT16 sGridX, sGridY;
|
|
INT16 sCentreGridX, sCentreGridY;
|
|
|
|
// find out what slot it is by which site
|
|
if( ubSite == 0 )
|
|
{
|
|
// drassen
|
|
sOStruct = FIRSTOSTRUCT1;
|
|
}
|
|
else
|
|
{
|
|
// estoni
|
|
sOStruct = FOURTHOSTRUCT1;
|
|
}
|
|
|
|
|
|
// are we adding or taking away
|
|
if( fAdd )
|
|
{
|
|
AddHeliPeice( sGridNo, sOStruct );
|
|
AddHeliPeice( sGridNo, ( UINT16 )( sOStruct + 1));
|
|
AddHeliPeice( (INT16)( sGridNo - 800 ), ( UINT16 )( sOStruct + 2 ));
|
|
AddHeliPeice( sGridNo, ( UINT16 )(sOStruct + 3 ));
|
|
AddHeliPeice( sGridNo, ( UINT16 )(sOStruct + 4));
|
|
AddHeliPeice( (INT16)( sGridNo - 800 ), ( UINT16 )(sOStruct + 5));
|
|
|
|
InvalidateWorldRedundency();
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
// ATE: If any mercs here, bump them off!
|
|
ConvertGridNoToXY( sGridNo, &sCentreGridX, &sCentreGridY );
|
|
|
|
for( sGridY = sCentreGridY - 5; sGridY < sCentreGridY + 5; sGridY++ )
|
|
{
|
|
for( sGridX = sCentreGridX - 5; sGridX < sCentreGridX + 5; sGridX++ )
|
|
{
|
|
usGridNo = MAPROWCOLTOPOS( sGridY, sGridX );
|
|
|
|
BumpAnyExistingMerc( usGridNo );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// remove from the world
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ], ( UINT16 )(sOStruct ));
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ], ( UINT16 )(sOStruct + 1 ));
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ] - 800, ( UINT16 )(sOStruct + 2));
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ], ( UINT16 )(sOStruct + 3));
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ], ( UINT16 )(sOStruct + 4));
|
|
RemoveStruct( sRefuelStartGridNo[ ubSite ] - 800, ( UINT16 )(sOStruct +5));
|
|
|
|
InvalidateWorldRedundency();
|
|
SetRenderFlags( RENDER_FLAG_FULL );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN IsSkyriderIsFlyingInSector( INT16 sSectorX, INT16 sSectorY )
|
|
{
|
|
GROUP *pGroup;
|
|
|
|
// up and about?
|
|
if ( fHelicopterAvailable && ( iHelicopterVehicleId != -1 ) && CanHelicopterFly() && fHelicopterIsAirBorne )
|
|
{
|
|
pGroup = GetGroup( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
// the right sector?
|
|
if ( ( sSectorX == pGroup->ubSectorX ) && ( sSectorY == pGroup->ubSectorY ) )
|
|
{
|
|
return(TRUE);
|
|
}
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN IsGroupTheHelicopterGroup( GROUP *pGroup )
|
|
{
|
|
if( ( iHelicopterVehicleId != -1 ) && VehicleIdIsValid( iHelicopterVehicleId ) &&
|
|
( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup != 0 ) &&
|
|
( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup == pGroup->ubGroupID ) )
|
|
{
|
|
return( TRUE );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
|
|
INT16 GetNumSafeSectorsInPath( void )
|
|
{
|
|
// get the last sector value in the helictoper's path
|
|
PathStPtr pNode = NULL;
|
|
UINT32 uiLocation = 0;
|
|
UINT32 uiCount = 0;
|
|
INT32 iHeliSector = -1;
|
|
GROUP *pGroup;
|
|
|
|
// if the heli is on the move, what is the distance it will move..the length of the merc path, less the first node
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
// big number, no go
|
|
return( 0 );
|
|
}
|
|
|
|
|
|
// may need to skip the sector the chopper is currently in
|
|
iHeliSector = CALCULATE_STRATEGIC_INDEX( pVehicleList[ iHelicopterVehicleId ].sSectorX, pVehicleList[ iHelicopterVehicleId ].sSectorY );
|
|
|
|
// get chopper's group ptr
|
|
pGroup = GetGroup( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
pNode = pVehicleList[ iHelicopterVehicleId ].pMercPath;
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
// first node: skip it if that's the sector the chopper is currently in, AND
|
|
// we're NOT gonna be changing directions (not actually performed until waypoints are rebuilt AFTER plotting is done)
|
|
if ( ( ( INT32 ) pNode->uiSectorId == iHeliSector ) && ( pNode->pNext != NULL ) &&
|
|
!GroupBetweenSectorsAndSectorXYIsInDifferentDirection( pGroup, ( UINT8 ) GET_X_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ), ( UINT8 ) GET_Y_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ) ) )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
while( pNode)
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
if ( !StrategicMap[ uiLocation ].fEnemyAirControlled )
|
|
{
|
|
uiCount++;
|
|
}
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
pNode = MoveToBeginningOfPathList( pTempHelicopterPath );
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
// first node: skip it if that's the sector the chopper is currently in, AND
|
|
// we're NOT gonna be changing directions (not actually performed until waypoints are rebuilt AFTER plotting is done)
|
|
// OR if the chopper has a mercpath, in which case this a continuation of it that would count the sector twice
|
|
if ( ( ( ( INT32 ) pNode->uiSectorId == iHeliSector ) && ( pNode->pNext != NULL ) &&
|
|
!GroupBetweenSectorsAndSectorXYIsInDifferentDirection( pGroup, ( UINT8 ) GET_X_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ), ( UINT8 ) GET_Y_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ) ) ) ||
|
|
( GetLengthOfPath( pVehicleList[ iHelicopterVehicleId ].pMercPath ) > 0 ) )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
while( pNode)
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
if ( !StrategicMap[ uiLocation ].fEnemyAirControlled )
|
|
{
|
|
uiCount++;
|
|
}
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
return( (INT16)uiCount );
|
|
}
|
|
|
|
|
|
INT16 GetNumUnSafeSectorsInPath( void )
|
|
{
|
|
// get the last sector value in the helictoper's path
|
|
PathStPtr pNode = NULL;
|
|
UINT32 uiLocation = 0;
|
|
UINT32 uiCount = 0;
|
|
INT32 iHeliSector = -1;
|
|
GROUP *pGroup;
|
|
|
|
|
|
// if the heli is on the move, what is the distance it will move..the length of the merc path, less the first node
|
|
if( CanHelicopterFly( ) == FALSE )
|
|
{
|
|
// big number, no go
|
|
return( 0 );
|
|
}
|
|
|
|
|
|
// may need to skip the sector the chopper is currently in
|
|
iHeliSector = CALCULATE_STRATEGIC_INDEX( pVehicleList[ iHelicopterVehicleId ].sSectorX, pVehicleList[ iHelicopterVehicleId ].sSectorY );
|
|
|
|
// get chopper's group ptr
|
|
pGroup = GetGroup( pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
pNode = pVehicleList[ iHelicopterVehicleId ].pMercPath;
|
|
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
// first node: skip it if that's the sector the chopper is currently in, AND
|
|
// we're NOT gonna be changing directions (not actually performed until waypoints are rebuilt AFTER plotting is done)
|
|
if ( ( ( INT32 ) pNode->uiSectorId == iHeliSector ) && ( pNode->pNext != NULL ) &&
|
|
!GroupBetweenSectorsAndSectorXYIsInDifferentDirection( pGroup, ( UINT8 ) GET_X_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ), ( UINT8 ) GET_Y_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ) ) )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
while( pNode)
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
if ( StrategicMap[ uiLocation ].fEnemyAirControlled )
|
|
{
|
|
uiCount++;
|
|
}
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
pNode = MoveToBeginningOfPathList( pTempHelicopterPath );
|
|
// any path yet?
|
|
if( pNode != NULL )
|
|
{
|
|
// first node: skip it if that's the sector the chopper is currently in, AND
|
|
// we're NOT gonna be changing directions (not actually performed until waypoints are rebuilt AFTER plotting is done)
|
|
// OR if the chopper has a mercpath, in which case this a continuation of it that would count the sector twice
|
|
if ( ( ( ( INT32 ) pNode->uiSectorId == iHeliSector ) && ( pNode->pNext != NULL ) &&
|
|
!GroupBetweenSectorsAndSectorXYIsInDifferentDirection( pGroup, ( UINT8 ) GET_X_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ), ( UINT8 ) GET_Y_FROM_STRATEGIC_INDEX( pNode->pNext->uiSectorId ) ) ) ||
|
|
( GetLengthOfPath( pVehicleList[ iHelicopterVehicleId ].pMercPath ) > 0 ) )
|
|
{
|
|
pNode = pNode->pNext;
|
|
}
|
|
|
|
while( pNode)
|
|
{
|
|
uiLocation = pNode -> uiSectorId;
|
|
|
|
if ( StrategicMap[ uiLocation ].fEnemyAirControlled )
|
|
{
|
|
uiCount++;
|
|
}
|
|
|
|
pNode = pNode ->pNext;
|
|
}
|
|
}
|
|
|
|
return( (INT16)uiCount );
|
|
}
|
|
|
|
|
|
|
|
void PaySkyriderBill( void)
|
|
{
|
|
// if we owe anything for the trip
|
|
if ( iTotalAccumulatedCostByPlayer > 0 )
|
|
{
|
|
// if player can afford to pay the Skyrider bill
|
|
if( LaptopSaveInfo.iCurrentBalance >= iTotalAccumulatedCostByPlayer )
|
|
{
|
|
// no problem, pay the man
|
|
// add the transaction
|
|
AddTransactionToPlayersBook( PAYMENT_TO_NPC, SKYRIDER, GetWorldTotalMin( ), -iTotalAccumulatedCostByPlayer );
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 0 ], iTotalAccumulatedCostByPlayer );
|
|
}
|
|
else
|
|
{
|
|
// money owed
|
|
if( LaptopSaveInfo.iCurrentBalance > 0 )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 0 ], LaptopSaveInfo.iCurrentBalance );
|
|
gMercProfiles[ SKYRIDER ].iBalance = LaptopSaveInfo.iCurrentBalance - iTotalAccumulatedCostByPlayer;
|
|
// add the transaction
|
|
AddTransactionToPlayersBook( PAYMENT_TO_NPC, SKYRIDER, GetWorldTotalMin( ), -LaptopSaveInfo.iCurrentBalance );
|
|
}
|
|
else
|
|
{
|
|
gMercProfiles[ SKYRIDER ].iBalance = - iTotalAccumulatedCostByPlayer;
|
|
}
|
|
|
|
HeliCharacterDialogue( pSkyRider, OWED_MONEY_TO_SKYRIDER );
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 1 ], -gMercProfiles[ SKYRIDER ].iBalance );
|
|
|
|
// kick everyone out! (we know we're in a safe sector if we're paying)
|
|
MoveAllInHelicopterToFootMovementGroup( );
|
|
|
|
MakeHeliReturnToBase();
|
|
}
|
|
|
|
iTotalAccumulatedCostByPlayer = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void PayOffSkyriderDebtIfAny( )
|
|
{
|
|
INT32 iAmountOwed;
|
|
INT32 iPayAmount;
|
|
|
|
|
|
iAmountOwed = - gMercProfiles[ SKYRIDER ].iBalance;
|
|
|
|
// if we owe him anything, and have any money
|
|
if ( ( iAmountOwed > 0 ) && ( LaptopSaveInfo.iCurrentBalance > 0 ) )
|
|
{
|
|
iPayAmount = min( iAmountOwed, LaptopSaveInfo.iCurrentBalance );
|
|
|
|
// pay the man what we can
|
|
gMercProfiles[ SKYRIDER ].iBalance += iPayAmount;
|
|
// add the transaction
|
|
AddTransactionToPlayersBook( PAYMENT_TO_NPC, SKYRIDER, GetWorldTotalMin( ), -iPayAmount );
|
|
// tell player
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 0 ], iPayAmount );
|
|
|
|
// now whaddawe owe?
|
|
iAmountOwed = - gMercProfiles[ SKYRIDER ].iBalance;
|
|
|
|
// if it wasn't enough
|
|
if ( iAmountOwed > 0 )
|
|
{
|
|
ScreenMsg( FONT_MCOLOR_DKRED, MSG_INTERFACE, pSkyriderText[ 1 ], iAmountOwed );
|
|
HeliCharacterDialogue( pSkyRider, OWED_MONEY_TO_SKYRIDER );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void MakeHeliReturnToBase( void )
|
|
{
|
|
INT32 iLocation = 0;
|
|
|
|
|
|
// if already at a refueling point
|
|
if ( CheckForArrivalAtRefuelPoint() )
|
|
{
|
|
ReFuelHelicopter( );
|
|
}
|
|
else
|
|
{
|
|
// choose destination (closest refueling sector)
|
|
iLocation = LocationOfNearestRefuelPoint( TRUE );
|
|
|
|
// null out path
|
|
pVehicleList[ iHelicopterVehicleId ].pMercPath = ClearStrategicPathList( pVehicleList[ iHelicopterVehicleId ].pMercPath, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
// plot path to that sector
|
|
pVehicleList[ iHelicopterVehicleId ].pMercPath = AppendStrategicPath( MoveToBeginningOfPathList( BuildAStrategicPath( NULL, GetLastSectorIdInVehiclePath( iHelicopterVehicleId ) , ( INT16 )( CALCULATE_STRATEGIC_INDEX( ubRefuelList[ iLocation ][ 0 ], ubRefuelList[ iLocation ][ 1 ] ) ) , pVehicleList[ iHelicopterVehicleId ].ubMovementGroup, FALSE /*, FALSE */ ) ), pVehicleList[ iHelicopterVehicleId ].pMercPath );
|
|
pVehicleList[ iHelicopterVehicleId ].pMercPath = MoveToBeginningOfPathList( pVehicleList[ iHelicopterVehicleId ].pMercPath );
|
|
|
|
// rebuild the movement waypoints
|
|
RebuildWayPointsForGroupPath( pVehicleList[ iHelicopterVehicleId ].pMercPath, pVehicleList[ iHelicopterVehicleId ].ubMovementGroup );
|
|
|
|
fHeliReturnStraightToBase = TRUE;
|
|
fHoveringHelicopter = FALSE;
|
|
}
|
|
|
|
// stop time compression if it's on so player can digest this
|
|
StopTimeCompression( );
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN SoldierAboardAirborneHeli( SOLDIERTYPE *pSoldier )
|
|
{
|
|
Assert( pSoldier );
|
|
|
|
// if not in a vehicle, or not aboard the helicopter
|
|
if ( ( pSoldier->bAssignment != VEHICLE ) || ( pSoldier->iVehicleId != iHelicopterVehicleId ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
// he's in the heli - is it airborne?
|
|
if ( !fHelicopterIsAirBorne )
|
|
{
|
|
// nope, it's currently on the ground
|
|
return( FALSE );
|
|
}
|
|
|
|
// yes, airborne
|
|
return( TRUE );
|
|
}
|