etqw-sdk/base/script/vehicles/base.script

1595 lines
41 KiB
Plaintext
Raw Permalink Normal View History

2008-05-29 00:00:00 +00:00
#define VWS_SHUTDOWN 0
#define VWS_POWERED 1
#define VPT_PART 1
#define VPT_SIMPLE_PART 2
#define VPT_WHEEL 4
#define VPT_ROTOR 8
#define VPT_HOVER 16
#define VPT_MASS 32
#define VPT_TRACK 64
#define VPT_THRUSTER 128
#define VPT_SUSPENSION 256
#define VPT_VTOL 512
#define FASTER_DECOY_SCALE 0.66
object vehicle_base {
void preinit();
void init();
void destroy();
void syncFields();
void OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location );
void OnKilledRemove( entity inflictor, entity attacker, float damage, vector dir, float location );
void OnDecayed();
float OnUpdateCrosshairInfo( entity p );
void OnUsed( entity user );
float OnActivate( entity p, float distance );
void OnRouteKickPlayer();
float GetActivateCode( entity p, float distance );
float VehicleBase_OnActivate( entity p, float distance );
void vSetDeployer( entity other );
void OnSpotted( entity spotter );
void OnCollision_Base( object traceObject, float velocity, vector mins, vector maxs );
void NotifyBoundEntitiesOfDestruction();
void vTargetLockAlarm( entity other );
void vStopTargetLockAlarm( entity other );
float vGetTargetLockCount();
float vGetTargetLockCountBasedefence();
void vCheckProficiency();
boolean vSkipDeployDrop();
void vOnContextRepair( entity p );
void vOnContextKill( entity p );
void vOnContextNeedPassenger( entity p );
void vOnRemovePlayersKillTask( player p );
void vOnEndGame();
void CheckArmor();
void FireDecoy( entity p );
void OnPostDamage( entity attacker, float oldHealth, float newHealth );
void ShowDamageEffects( float oldHealth, float newHealth );
void OnSetTeam( object oldTeam, object newTeam );
void InitRadarValues() { ; }
float vGetPliersProgressBarValue( float action );
boolean vCheckActionCode( entity p, float actionCode );
void UpdateHealth( float oldHealth, float newHealth );
void VehicleBase_UpdateHealth( float oldHealth, float newHealth );
void SetupCommandMap();
void SetupRequestIcon( string key, string requirement );
void FreeRequestIcon();
void RequestIconThread( float timeout );
void InitDestroyTask( boolean highCommand );
void FreeDestroyTask();
void CompleteDestroyTask();
void InitRepairTask( boolean highCommand );
void FreeRepairTask();
void CompleteRepairTask();
void InitNeedPassengerTask( entity p );
void FreeRequestTask();
void vRepair( float count, entity other );
vector vGetLastRepairOrigin();
boolean vBlockVehicleSpawn() { return true; }
void ApplyEmpDamage_Base( entity attacker, float time, float weaponTime );
void vApplyEmpDamage( entity attacker, float time, float weaponTime );
void OnPlayerEntered( entity p, float position );
void OnPlayerEntered_Base( entity p, float position );
void OnPlayerExited( entity p, float position );
void OnPlayerExited_Base( entity p, float position );
void OnDecoyChargeTimeChanged();
void OnDecoyLaunched();
void DestroyThread();
void DecayThread();
void DamageEffectThread();
void OnTeleportEntityChanged( entity other );
void OnLastRepairTimeChanged();
void CheckFireTeamInfo( boolean localExiting );
void DecoyUseCharge();
boolean DecoyHasCharge();
float CalcDecoyChargeUsed();
void StartDecoyChargeThread();
void StopDecoyChargeThread();
void DecoyChargeThread();
boolean NeedGunner();
string vGetQuickChatString( entity p );
void FlashCMIcon( entity p, float requiredTeam, float flashTime );
void EMPEffectThread( float time );
float nextDecoyTime;
float decoyChargeMax;
float baseDecoyChargePerUse;
float decoyChargeTime;
float decoyFireRate;
float decoyJointHandle;
vector decoyLaunchVelocity;
float decoyProjectileIndex;
boolean decoyChargeThreadActive;
float decoyChargePerUse;
float commandMapRequest;
task destroyTask;
task requestTask;
task repairTask;
player killTaskRequestee;
string jointEffectSmoke;
string jointEffectFire;
float damageLevelSmoke;
float damageLevel1;
float damageLevel2;
float damageLevel3;
float destroyDelay;
float repairThreshold;
float commandMapHandle;
float commandMapFireTeamInfo;
handle crosshairName;
float targetLockCount;
float targetLockCountBasedefence;
float damageEffectLevel;
handle damageEffectHandle;
handle damageSmokeEffectHandle;
float disableProficiency;
// variables for the repair drone
boolean orbitUnderneath;
float orbitRadius;
float repairMultiplier;
boolean vCustomOrbitRadius();
float vGetOrbitRadius();
boolean vOrbitUnderneath();
void SetArmorBonus( boolean value );
entity deployer;
boolean hasArmorBonus;
float healthBarLength;
float toolTipVehicle_enter;
float lastTooltipTime;
float toolTipCannotRepair;
float toolTipNoEntry;
boolean playingKlaxon;
float klaxonThreshold;
float drownHeight;
float maxEnterDistance;
float nextCollisionEffectTime;
float spiralHealthFrac;
boolean EnemyHasLockedOnPlayer() { return ( targetLockCount > 0 ); }
float empEffectThreadId;
float empJointHandle;
boolean spawnInvulnerable;
void OnSpawnInvulnerableChanged();
boolean normallyHaveKnockback;
cvar g_drawVehicleIcons;
entity lastRepairer;
float lastRepairTime;
}
void vehicle_base::syncFields() {
sync( "lastRepairTime" );
syncBroadcast( "lastRepairer" );
syncBroadcast( "decoyChargeTime" );
syncBroadcast( "spawnInvulnerable" );
syncCallback( "lastRepairTime", "OnLastRepairTimeChanged" );
syncCallback( "decoyChargeTime", "OnDecoyChargeTimeChanged" );
syncCallback( "spawnInvulnerable", "OnSpawnInvulnerableChanged" );
}
void vehicle_base::preinit() {
decoyFireRate = getFloatKey( "projectile_decoy_rate" );
decoyJointHandle = getJointHandle( getKey( "projectile_decoy_joint" ) );
decoyLaunchVelocity = getVectorKey( "projectile_decoy_velocity" );
decoyProjectileIndex = GetEntityDef( getKey( "def_projectile_decoy" ) );
crosshairName = sys.localizeString( getKey( "info_name" ) );
damageLevelSmoke = getFloatKey( "damage_smoke" ) / 100;
damageLevel1 = getFloatKey( "damage_level1" ) / 100;
damageLevel2 = getFloatKey( "damage_level2" ) / 100;
damageLevel3 = getFloatKey( "damage_level3" ) / 100;
disableProficiency = GetProficiency( getKey( "prof_disable" ) );
toolTipCannotRepair = GetToolTip( getKey( "tt_cannot_repair" ) );
toolTipNoEntry = GetToolTip( getKey( "tt_noentry" ) );
repairMultiplier = getFloatKeyWithDefault( "repair_multiplier", 1.f );
jointEffectSmoke = getKey( "joint_damage_smoke" );
jointEffectFire = getKey( "joint_damage_fire" );
destroyDelay = getFloatKey( "destroy_delay" );
repairThreshold = getFloatKey( "repair_threshold" ) / 100;
commandMapRequest = -1;
damageEffectLevel = 0;
damageEffectHandle = 0;
damageSmokeEffectHandle = 0;
commandMapHandle = -1;
commandMapFireTeamInfo = -1;
SetupCommandMap();
if ( commandMapFireTeamInfo != -1 ) {
sys.hideCMIcon( commandMapFireTeamInfo );
}
orbitUnderneath = getFloatKey( "drone_orbit_underneath" );
orbitRadius = getFloatKey( "drone_orbit_radius" );
decoyChargeMax = getFloatKey( "projectile_decoy_max" );
baseDecoyChargePerUse = getFloatKey( "projectile_decoy_charge" );
baseDecoyChargePerUse = ( baseDecoyChargePerUse / 100 ) * decoyChargeMax;
toolTipVehicle_enter = GetToolTip( getKey( "tt_use_vehicle" ) );
klaxonThreshold = getFloatKey( "klaxon_threshold" );
drownHeight = getFloatKeyWithDefault( "drown_height", 0.5 );
maxEnterDistance = getFloatKeyWithDefault( "max_enter_distance", 128 );
empEffectThreadId = -1;
empJointHandle = getJointHandle( getKey( "emp_effect_joint" ) );
float maxHealth = getMaxHealth();
if ( maxHealth >= 3000.f ) {
healthBarLength = 150.f;
} else if ( maxHealth >= 2000.f ) {
healthBarLength = 125.f;
} else if ( maxHealth >= 500.f ) {
healthBarLength = 100.f;
} else {
healthBarLength = 75.f;
}
g_drawVehicleIcons = sys.getCVar( "g_drawVehicleIcons", "1" );
normallyHaveKnockback = true;
}
void vehicle_base::OnDecoyChargeTimeChanged() {
OnDecoyLaunched();
}
void vehicle_base::OnDecoyLaunched() {
entity driver = getDriver();
if ( driver != $null_entity ) {
if ( driver == sys.getLocalViewPlayer() ) {
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.decoyLaunchedTime", sys.getTime() );
StartDecoyChargeThread();
}
}
}
void vehicle_base::SetupCommandMap() {
commandMapHandle = sys.allocCMIcon( self, getFloatKey( "icon_sort_cm" ) );
float commandMapSize = 14;// getFloatKeyWithDefault( "icon_size_cm", 16.f );
sys.setCMIconDrawMode( commandMapHandle, DM_ROTATED_MATERIAL );
sys.setCMIconSize( commandMapHandle, commandMapSize );
sys.setCMIconColorMode( commandMapHandle, CM_ALLEGIANCE );
sys.setCMIconMaterial( commandMapHandle, GetMaterial( getKey( "mtr_commandmap" ) ) );
sys.setCMIconUnknownMaterial( commandMapHandle, GetMaterial( getKey( "mtr_commandmap_unknown" ) ) );
sys.setCMIconUnknownSize( commandMapHandle, getFloatKeyWithDefault( "icon_unknown_size_cm", commandMapSize / 2.0f ) );
sys.setCMIconFlag( commandMapHandle, CMF_FOLLOWROTATION );
sys.setCMIconFlag( commandMapHandle, CMF_FIRETEAMCOLORING );
// fire team ring
/*
commandMapFireTeamInfo = sys.allocCMIcon( self, getFloatKey( "icon_sort_cm_ft_ring" ) );
sys.setCMIconDrawMode( commandMapFireTeamInfo, DM_ROTATED_MATERIAL );
sys.setCMIconMaterial( commandMapFireTeamInfo, GetMaterial( getKey( "mtr_icon_team_ring" ) ) );
sys.setCMIconSize( commandMapFireTeamInfo, commandMapSize * getFloatKey( "team_ring_size" ) );
sys.setCMIconFlag( commandMapFireTeamInfo, CMF_TEAMONLY );
sys.setCMIconFlag( commandMapFireTeamInfo, CMF_FOLLOWROTATION );
sys.setCMIconFlag( commandMapFireTeamInfo, CMF_ALWAYSKNOWN );
sys.setCMIconColorMode( commandMapFireTeamInfo, CM_NORMAL );
sys.setCMIconColor( commandMapFireTeamInfo, g_colorWhite, 1.0f );
*/
}
void vehicle_base::NotifyBoundEntitiesOfDestruction() {
entity next;
entity current;
for ( current = getNextTeamEntity(); current != $null_entity; current = next ) {
next = current.getNextTeamEntity();
current.vOnBindMasterDestroyed();
}
}
void vehicle_base::destroy() {
sys.freeCMIcon( self, commandMapHandle );
if ( commandMapFireTeamInfo != -1 ) {
sys.freeCMIcon( self, commandMapFireTeamInfo );
}
FreeRequestIcon();
NotifyBoundEntitiesOfDestruction();
if ( deployer != $null_entity ) {
deployer.vOnVehicleDestroyed();
}
if ( playingKlaxon ) {
sys.startSoundDirect( "", SND_VEHICLE_INTERIOR_LOWHEALTH );
playingKlaxon = false;
}
FreeDestroyTask();
FreeRequestTask();
FreeRepairTask();
}
void vehicle_base::SetupRequestIcon( string key, string requirement ) {
FreeRequestIcon();
commandMapRequest = sys.allocCMIcon( self, getFloatKey( "icon_sort_cm_request" ) );
sys.setCMIconMaterial( commandMapRequest, GetMaterial( getKey( key ) ) );
sys.setCMIconUnknownMaterial( commandMapRequest, GetMaterial( getKey( key ) ) );
sys.addCMIconRequirement( commandMapRequest, getKey( requirement ) );
sys.setCMIconColorMode( commandMapRequest, CM_NORMAL );
sys.setCMIconDrawMode( commandMapRequest, DM_ROTATED_MATERIAL );
sys.setCMIconSize( commandMapRequest, 24.0f );
sys.setCMIconUnknownSize( commandMapRequest, 16.0f );
sys.setCMIconColor( commandMapRequest, '1 1 1', 1.0f );
sys.flashCMIcon( commandMapRequest, -1, SPOTTED_FLASH_TIME, -1 );
}
void vehicle_base::FreeRequestIcon() {
if( commandMapRequest != -1 ) {
sys.freeCMIcon( self, commandMapRequest );
commandMapRequest = -1;
}
sys.killThread( "RequestIconThread_" + getName() );
}
void vehicle_base::RequestIconThread( float timeout ) {
sys.wait( timeout );
FreeRequestIcon();
}
void vehicle_base::InitDestroyTask( boolean highCommand ) {
if ( sys.isClient() ) {
return;
}
if ( destroyTask != $null_entity ) {
if ( !highCommand ) {
return;
}
if ( !destroyTask.isUserCreated() ) {
return;
}
destroyTask.free();
}
float taskHandle = GetPlayerTask( getKey( "task_destroy" ) );
if ( taskHandle != -1 ) {
destroyTask = taskManager.allocEntityTask( taskHandle, self );
if ( !highCommand ) {
destroyTask.setUserCreated();
}
}
}
void vehicle_base::FreeDestroyTask() {
if ( destroyTask != $null_entity ) {
destroyTask.free();
}
}
void vehicle_base::CompleteRepairTask() {
if ( repairTask != $null_entity ) {
repairTask.complete();
repairTask.free();
}
}
void vehicle_base::CompleteDestroyTask() {
if ( destroyTask != $null_entity ) {
destroyTask.complete();
destroyTask.free();
}
}
void vehicle_base::InitRepairTask( boolean highCommand ) {
if ( sys.isClient() ) {
return;
}
if ( repairTask != $null ) {
if ( !highCommand ) {
return;
}
if ( !repairTask.isUserCreated() ) {
return;
}
FreeRepairTask();
}
float taskHandle = GetPlayerTask( getKey( "task_repair" ) );
if ( taskHandle != -1 ) {
repairTask = taskManager.allocEntityTask( taskHandle, self );
if ( !highCommand ) {
repairTask.setUserCreated();
}
}
}
void vehicle_base::FreeRepairTask() {
if ( repairTask != $null_entity ) {
repairTask.free();
repairTask = $null_entity;
}
}
void vehicle_base::InitNeedPassengerTask( entity p ) {
if ( sys.isClient() ) {
return;
}
if ( p == $null_entity ) {
return;
}
float spots = getNumPositions();
float usedSpots = getNumOccupiedPositions();
if ( spots - usedSpots <= 0 ) {
return;
}
if ( requestTask != $null ) {
if ( !requestTask.isUserCreated() ) {
return;
}
FreeRequestTask();
}
float pickupTaskInfo;
if ( getDriver() == $null_entity ) {
pickupTaskInfo = GetPlayerTask( getKey( "task_need_pilot" ) );
} else if ( NeedGunner() ) {
pickupTaskInfo = GetPlayerTask( getKey( "task_need_gunner" ) );
} else {
pickupTaskInfo = GetPlayerTask( getKey( "task_need_passenger" ) );
}
if ( pickupTaskInfo != -1 ) {
requestTask = taskManager.allocEntityTask( pickupTaskInfo, self );
}
}
void vehicle_base::FreeRequestTask() {
if ( requestTask != $null ) {
requestTask.free();
requestTask = $null;
}
}
void vehicle_base::OnSpotted( entity spotter ) {
InitDestroyTask( false );
G_GiveSpottingProficiency( spotter );
}
float vehicle_base::OnUpdateCrosshairInfo( entity p ) {
if ( !sys.doClientSideStuff() ) {
return 1.f;
}
float allegiance = getEntityAllegiance( p );
vector color = GetAllegianceColor( allegiance );
float distance = chGetDistance();
float range = InchesToMetres( distance );
float minHealth = getMinDisplayHealth();
float maxHealth = getMaxHealth() - minHealth;
float health = getHealth() - minHealth;
chSetNumLines( 0 );
float index;
if ( p != $null_entity ) {
// see if theres a valid action to perform
float code = GetActivateCode( p, distance );
if ( code != AK_NONE && p.vHasActionItem( code ) ) {
if ( code == AK_USEVEHICLE ) {
if ( distance > maxEnterDistance ) {
return 0.f;
}
}
index = chAddLine();
chSetLineMaterial( index, p.vGetActionIcon( code ) );
chSetLineType( index, CI_IMAGE );
chSetLineSize( index, 64, 64 );
chSetLineColor( index, g_colorWhite, 0.9f );
}
}
index = chAddLine();
chSetLineTextIndex( index, crosshairName );
chSetLineColor( index, color, 1.f );
chSetLineType( index, CI_TEXT );
chSetLineSize( index, 0, 0 );
if( health <= 0 ) {
index = chAddLine();
chSetLineTextIndex( index, g_locStr_Destroyed );
chSetLineColor( index, color, 1.f );
chSetLineType( index, CI_TEXT );
chSetLineSize( index, 0, 0 );
} else {
if( isEMPed() ) {
index = chAddLine();
sys.pushLocString( int( getRemainingEMP() ) );
chSetLineText( index, sys.localizeStringArgs( "game/disabled_info" ) );
chSetLineColor( index, color, 1.f );
chSetLineType( index, CI_TEXT );
chSetLineSize( index, 0, 0 );
}
index = chAddLine();
chSetLineColor( index, color, 0.5f );
chSetLineType( index, CI_BAR );
chSetLineFraction( index, health / maxHealth );
chSetLineSize( index, healthBarLength, CROSSHAIR_INFO_BAR_HEIGHT );
if( range <= 100 ) {
if( getNumOccupiedPositions() > 0 ) {
index = chAddLine();
chSetLineText( index, getPassengerNames() );
chSetLineColor( index, color, 1.f );
chSetLineType( index, CI_TEXT );
chSetLineSize( index, 0, 0 );
}
index = chAddLine();
chSetLineText( index, G_BuildRangeStr( range ) );
chSetLineColor( index, color, 1.f );
chSetLineType( index, CI_TEXT );
chSetLineSize( index, 0, 0 );
}
}
if ( p != $null_entity ) {
// show enter vehicle tooltip
if ( p.isLocalPlayer()) {
if ( distance <= 128.f ) {
if ( allegiance == TA_FRIEND ) {
if ( !p.isToolTipPlaying() ) {
if ( sys.getTime() - lastTooltipTime > 5.f ) {
if ( sys.getTime() - p.getCrosshairStartTime() > 1.f ) {
p.sendToolTip( toolTipVehicle_enter );
lastTooltipTime = sys.getTime();
}
}
}
}
}
}
}
return 1.f;
}
void vehicle_base::OnUsed( entity user ) {
entity team = user.getGameTeam();
if ( team == $null_entity ) {
return;
}
if ( getHealth() <= 0 ) {
if ( user == sys.getLocalViewPlayer() ) {
user.sendToolTip( toolTipNoEntry );
}
return;
}
if ( getEntityAllegiance( user ) != TA_ENEMY && user.getHealth() > 0 ) {
if ( isPlayerBanned( user ) ) {
float toolTipIndex = GetToolTip( getKey( "tt_player_banned" ) );
sys.broadcastToolTip( toolTipIndex, user, wstr_empty, wstr_empty, wstr_empty, wstr_empty );
return;
}
user.enter( self );
return;
}
}
void vehicle_base::init() {
thread DamageEffectThread();
}
void vehicle_base::OnKilled( entity inflictor, entity attacker, float damage, vector dir, float location ) {
NotifyBoundEntitiesOfDestruction();
OnKilledRemove( inflictor, attacker, damage, dir, location );
}
void vehicle_base::OnKilledRemove( entity inflictor, entity attacker, float damage, vector dir, float location ) {
CompleteDestroyTask();
kickPlayer( -1, EF_KILL_PLAYERS );
stopEffectHandle( damageEffectHandle );
stopEffectHandle( damageSmokeEffectHandle );
damageEffectHandle = 0;
damageSmokeEffectHandle = 0;
float water = isInWater();
if( water == 1.0f ) {
playOriginEffect( "fx_destroy_submerged", "", getWorldOrigin() , '0 0 1', 0 );
} else if( water > 0.5f ) {
playOriginEffect( "fx_destroy_water", "", getWorldOrigin() , '0 0 1', 0 );
} else {
playOriginEffect( "fx_destroy", "", getWorldOrigin() , '0 0 1', 0 );
}
destroyParts( 0 );
// the body would start falling here, so disable the model
disableModel( 1 );
thread DestroyThread();
}
void vehicle_base::OnPostDamage( entity attacker, float oldHealth, float newHealth ) {
float maxHealth = getMaxHealth();
UpdateHealth( oldHealth / maxHealth, newHealth / maxHealth );
resetDecayTime();
}
void vehicle_base::ShowDamageEffects( float oldHealth, float newHealth ) {
float newDamageEffectLevel;
// Figure out damage level
if ( isInWater() < 0.5f && newHealth > 0.f ) {
if ( newHealth > damageLevelSmoke ) {
newDamageEffectLevel = 0;
} else if( newHealth > damageLevel1 ) {
newDamageEffectLevel = 1;
} else if( newHealth > damageLevel2 ) {
newDamageEffectLevel = 2;
} else if( newHealth > damageLevel3 ) {
newDamageEffectLevel = 3;
} else {
newDamageEffectLevel = 4;
}
} else {
newDamageEffectLevel = 0;
}
// Apply if it changed
if ( damageEffectLevel != newDamageEffectLevel ) {
stopEffectHandle( damageEffectHandle );
damageEffectHandle = 0;
if ( newDamageEffectLevel != 0 ) {
if ( !damageSmokeEffectHandle ) {
damageSmokeEffectHandle = playEffect( "fx_damage_level_smoke", jointEffectFire, 1 );
}
} else {
stopEffectHandle( damageSmokeEffectHandle );
damageSmokeEffectHandle = 0;
}
if ( newDamageEffectLevel == 2 ) {
damageEffectHandle = playEffect( "fx_damage_level1", jointEffectFire, 1 );
} else if ( newDamageEffectLevel == 3 ) {
damageEffectHandle = playEffect( "fx_damage_level2", jointEffectFire, 1 );
} else if ( newDamageEffectLevel == 4 ) {
damageEffectHandle = playEffect( "fx_damage_level3", jointEffectFire, 1 );
}
damageEffectLevel = newDamageEffectLevel;
}
// issue a repair task if damage was inflicted & we're below 30%
if ( newHealth < oldHealth ) {
if ( newHealth <= spiralHealthFrac ) {
FreeRepairTask();
} else if ( newHealth <= repairThreshold ) {
SetupRequestIcon( "mtr_cm_icon_need_repair", "require_view_repair" );
thread RequestIconThread( 5.f );
InitRepairTask( true );
}
}
if ( newHealth > oldHealth && newHealth >= 1.f ) {
if ( repairTask != $null_entity ) {
FreeRequestIcon();
CompleteRepairTask();
}
}
}
void vehicle_base::DamageEffectThread( ) {
float oldWaterLevel;
while ( true ) {
vector vel = getLinearVelocity();
float speed = sys.vecLength( vel );
if ( speed > 400 ) {
speed = 400;
}
float attenuation = speed / 400;
if ( damageEffectHandle ) {
setEffectAttenuation( damageEffectHandle, attenuation );
}
if ( damageSmokeEffectHandle ) {
setEffectAttenuation( damageSmokeEffectHandle, attenuation );
}
float newWaterLevel = isInWater();
if ( newWaterLevel != oldWaterLevel ) {
float health = getHealth() / getMaxHealth();
ShowDamageEffects( health, health );
oldWaterLevel = newWaterLevel;
}
sys.wait( 0.25f );
}
}
float vehicle_base::vGetPliersProgressBarValue( float action ) {
if ( action == AC_REPAIR ) {
float minHealth = getMinDisplayHealth();
return ( getHealth() - minHealth ) / ( getMaxHealth() - minHealth );
}
return 0.f;
}
void vehicle_base::vTargetLockAlarm( entity other ) {
boolean isBaseDefence;
if ( other.inCollection( "basedefence" ) ) {
targetLockCountBasedefence++;
isBaseDefence = true;
} else {
targetLockCount++;
player p = getDriver();
if ( p != $null_entity ) {
if ( p.isLocalPlayer() ) {
if ( other != $null_entity ) {
float toolTip = GetToolTip( getKey( "tt_decoy" ) );
p.sendToolTip( toolTip );
}
}
}
}
if ( isBaseDefence == false || ( g_aptWarning.getIntValue() == 2 || g_aptWarning.getIntValue() == 3 ) ) {
setLockAlarmActive( true );
}
}
void vehicle_base::vStopTargetLockAlarm( entity other ) {
if ( other.inCollection( "basedefence" ) ) {
targetLockCountBasedefence--;
} else {
targetLockCount--;
}
if( targetLockCount <= 0 && targetLockCountBasedefence <= 0 ) {
targetLockCount = 0;
targetLockCountBasedefence = 0;
setLockAlarmActive( false );
}
}
boolean vehicle_base::vCheckActionCode( entity p, float actionCode ) {
if ( getEntityAllegiance( p ) == TA_ENEMY ) {
if ( actionCode == AC_ENEMY_REPAIR ) {
return true;
}
return false;
}
if ( actionCode == AC_REPAIR ) {
if ( isInWater() < drownHeight ) {
float health = getHealth();
return ( health >= getMinDisplayHealth() ) && ( ( health < getMaxHealth() ) || hasHiddenParts() );
}
}
return false;
}
void vehicle_base::vRepair( float count, entity other ) {
count = count * repairMultiplier;
player p = other;
team_base team;
if ( p != $null_entity ) {
team = p.getGameTeam();
}
if ( team != $null_entity ) {
if ( team.HasConstructionBonus( p ) ) {
count = count * 1.25f;
}
}
float oldHealth = getHealth();
if ( repair( count ) < 0 ) {
if ( other == sys.getLocalPlayer() ) {
other.sendToolTip( toolTipCannotRepair );
}
}
float maxHealth = getMaxHealth();
float newHealth = getHealth();
float teamDamageCount = getTeamDamageDone();
float diff = newHealth - oldHealth;
float repairCount = diff - teamDamageCount;
if ( repairCount > 0 ) {
if ( team != $null_entity ) {
task_repair_vehicle t = requestTask;
team.GiveRepairProficiency( p, t, repairCount );
}
}
setTeamDamageDone( teamDamageCount - diff );
UpdateHealth( oldHealth / maxHealth, newHealth / maxHealth );
lastRepairer = other;
lastRepairTime = sys.getTime();
OnLastRepairTimeChanged();
resetDecayTime();
}
vector vehicle_base::vGetLastRepairOrigin() {
return getLastRepairOrigin();
}
boolean vehicle_base::vCustomOrbitRadius() {
return true;
}
float vehicle_base::vGetOrbitRadius() {
if ( orbitRadius == 0 ) {
vector size = getAbsMaxs() - getAbsMins();
orbitRadius = 0.7 * sys.sqrt( size_x * size_x + size_y * size_x );
}
return orbitRadius;
}
boolean vehicle_base::vOrbitUnderneath() {
return orbitUnderneath;
}
void vehicle_base::ApplyEmpDamage_Base( entity attacker, float time, float weaponTime ) {
if ( applyEMPDamage( time, weaponTime ) ) {
if ( disableProficiency != -1 ) {
attacker.giveProficiency( disableProficiency, getDamageScale(), $null, "emp on vehicle" );
}
if ( empEffectThreadId != -1 ) {
sys.terminate( empEffectThreadId );
empEffectThreadId = -1;
}
empEffectThreadId = thread EMPEffectThread( time );
player playerAttacker = attacker;
if ( playerAttacker != $null_entity ) {
team_base team = attacker.getGameTeam();
if ( team != $null ) {
team.LogEmpUsage( playerAttacker );
}
}
}
}
void vehicle_base::vApplyEmpDamage( entity attacker, float time, float weaponTime ) {
ApplyEmpDamage_Base( attacker, time, weaponTime );
}
void vehicle_base::OnPlayerEntered( entity p, float position ) {
OnPlayerEntered_Base( p, position );
}
object vehicle_weapon_base;
void vehicle_base::OnPlayerEntered_Base( entity p, float position ) {
if ( p.isDisguised() ) {
p.disguise( $null_entity );
}
if ( p == sys.getLocalViewPlayer() ) {
if ( !p.isSinglePlayerToolTipPlaying() ) {
p.cancelToolTips();
}
sys.setGUIString( GUI_GLOBALS_HANDLE, "gameHud.weaponCrosshair", "none" );
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.energySegments", 1 );
sys.setGUIHandle( GUI_GLOBALS_HANDLE, "vehicles.siegeMode", invalid_handle );
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.weaponReloadTime", 0 );
if ( position == 0 ) {
if ( CalcDecoyChargeUsed() > 0 ) {
StartDecoyChargeThread();
} else {
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.decoyChargeFraction", 1 );
}
}
float healthFrac = getHealth() / getMaxHealth();
if ( healthFrac < klaxonThreshold ) {
sys.startSoundDirect( getKey( "snd_health_warn" ), SND_VEHICLE_INTERIOR_LOWHEALTH );
playingKlaxon = true;
}
}
vCheckProficiency();
CheckFireTeamInfo( false );
if ( spawnInvulnerable ) {
spawnInvulnerable = false;
OnSpawnInvulnerableChanged();
}
}
void vehicle_base::OnPlayerExited( entity p, float position ) {
OnPlayerExited_Base( p, position );
}
void vehicle_base::OnPlayerExited_Base( entity p, float position ) {
if ( p == sys.getLocalViewPlayer() ) {
if ( !p.isSinglePlayerToolTipPlaying() ) {
p.cancelToolTips();
}
StopDecoyChargeThread();
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.cooling", 0 );
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.energySegments", 1 );
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.decoyChargeFraction", 1 );
sys.startSoundDirect( "", SND_VEHICLE_INTERIOR_LOWHEALTH );
playingKlaxon = false;
}
vCheckProficiency();
if ( p == sys.getLocalPlayer() ) {
CheckFireTeamInfo( true );
} else {
CheckFireTeamInfo( false );
}
}
float vehicle_base::vGetTargetLockCount() {
return targetLockCount;
}
float vehicle_base::vGetTargetLockCountBasedefence() {
if ( g_aptWarning.getIntValue() == 1 || g_aptWarning.getIntValue() == 3 ) {
return targetLockCountBasedefence;
}
return 0;
}
void vehicle_base::DestroyThread() {
sys.wait( destroyDelay );
// totally submerged vehicles don't explode
float water = isInWater();
if( water < 1.0f ) {
vector middle = ( getMins() + getMaxs() ) * 0.5f;
middle = sys.toWorldSpace( middle, self );
sys.applyRadiusDamage( middle, self, self, $null_entity, self, GetDamage( "damage_vehicle_explode" ), 1.f, 1.f );
}
if( !sys.isClient() ) {
remove();
}
}
void vehicle_base::OnDecayed() {
CompleteDestroyTask();
thread DecayThread();
}
void vehicle_base::DecayThread() {
stopEffectHandle( damageEffectHandle );
stopEffectHandle( damageSmokeEffectHandle );
damageEffectHandle = 0;
damageSmokeEffectHandle = 0;
float decayRandom = sys.random( 2 );
if( decayRandom >= 1 ) {
decayLeftWheels();
} else {
decayRightWheels();
}
playEffect( "fx_decay", "", 0 );
sys.wait( 0.6 );
if( decayRandom >= 1 ) {
decayRightWheels();
} else {
decayLeftWheels();
}
sys.wait( 0.6 );
decayNonWheels();
// the body would start falling here, so disable the model
disableModel( 1 );
sys.wait( destroyDelay );
if( !sys.isClient() ) {
remove();
}
}
void vehicle_base::UpdateHealth( float oldHealth, float newHealth ) {
VehicleBase_UpdateHealth( oldHealth, newHealth );
}
void vehicle_base::VehicleBase_UpdateHealth( float oldHealth, float newHealth ) {
ShowDamageEffects( oldHealth, newHealth );
if ( newHealth < klaxonThreshold ) {
if ( !playingKlaxon ) {
player p = sys.getLocalPlayer();
if ( p != $null_entity ) {
if ( p.getVehicle() == self ) {
sys.startSoundDirect( getKey( "snd_health_warn" ), SND_VEHICLE_INTERIOR_LOWHEALTH );
playingKlaxon = true;
}
}
}
} else {
if ( playingKlaxon ) {
sys.startSoundDirect( "", SND_VEHICLE_INTERIOR_LOWHEALTH );
playingKlaxon = false;
}
}
}
void vehicle_base::FireDecoy( entity p ) {
if ( getPositionPlayer( 0 ) != p ) {
return;
}
vector xAxis = getWorldAxis( 0 );
vector yAxis = getWorldAxis( 1 );
vector zAxis = getWorldAxis( 2 );
vector localAxis;
localAxis = decoyLaunchVelocity_x * xAxis;
localAxis += decoyLaunchVelocity_y * yAxis;
localAxis += decoyLaunchVelocity_z * zAxis;
if ( sys.getTime() > nextDecoyTime ) {
if ( DecoyHasCharge() ) {
vector origin = getJointPos( decoyJointHandle );
entity projectileEntity = launchMissileSimple( p, self, $null_entity, decoyProjectileIndex, -1, 0, origin, localAxis );
if ( projectileEntity != $null_entity ) {
projectileEntity.vSetOwner( self );
DecoyUseCharge();
}
team_base team = p.getGameTeam();
if ( team != $null && team.HasEfficientDecoys( p ) ) {
nextDecoyTime = sys.getTime() + decoyFireRate * FASTER_DECOY_SCALE;
} else {
nextDecoyTime = sys.getTime() + decoyFireRate;
}
OnDecoyLaunched();
}
}
}
void vehicle_base::DecoyUseCharge() {
decoyChargeTime = CalcDecoyChargeUsed() + sys.getTime() + decoyChargePerUse;
}
boolean vehicle_base::DecoyHasCharge() {
return ( CalcDecoyChargeUsed() + decoyChargePerUse ) <= decoyChargeMax;
}
float vehicle_base::CalcDecoyChargeUsed() {
float used = decoyChargeTime - sys.getTime();
if ( used < 0 ) {
return 0;
}
return used;
}
void vehicle_base::StartDecoyChargeThread() {
if ( decoyChargeThreadActive ) {
return;
}
decoyChargeThreadActive = true;
thread DecoyChargeThread();
}
void vehicle_base::StopDecoyChargeThread() {
if ( !decoyChargeThreadActive ) {
return;
}
decoyChargeThreadActive = false;
sys.killThread( "DecoyChargeThread_" + getName() );
}
void vehicle_base::DecoyChargeThread() {
while ( true ) {
float used = CalcDecoyChargeUsed();
float frac = ( decoyChargeMax - used ) / decoyChargeMax;
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.decoyChargeFraction", frac );
if ( used == 0 ) {
break;
}
sys.waitFrame();
}
decoyChargeThreadActive = false;
}
boolean vehicle_base::NeedGunner() {
float numWeapons = getNumVehicleWeapons();
float index = 0;
for ( index = 0; index < numWeapons; index++ ) {
vehicle_weapon_base weapon = getVehicleWeapon( index );
player user = weapon.getPlayer();
if ( user == $null_entity ) {
return true;
}
}
return false;
}
float vehicle_base::GetActivateCode( entity p, float distance ) {
if ( p.getViewingEntity() != p ) {
return AK_NONE;
}
if ( p.getHealth() <= 0 ) {
return AK_NONE;
}
if ( p.getProxyEntity() != $null_entity ) {
return AK_NONE;
}
float allegiance = getEntityAllegiance( p );
if ( allegiance == TA_FRIEND ) {
if ( distance < DISTANCE_FOR_ACTION ) {
if ( isInWater() < drownHeight ) {
float health = getHealth();
if ( health >= getMinDisplayHealth() && ( ( health < getMaxHealth() ) || hasHiddenParts() ) ) {
if ( p.vHasActionItem( AK_REPAIR ) ) {
return AK_REPAIR;
}
}
}
}
if ( distance < maxEnterDistance ) {
float spots = getNumPositions();
float usedSpots = getNumOccupiedPositions();
if ( spots - usedSpots > 0 ) {
return AK_USEVEHICLE;
}
}
}
return AK_NONE;
}
float vehicle_base::VehicleBase_OnActivate( entity p, float distance ) {
if ( p.getVehicle() == self ) {
swapPosition( p );
return 1.f;
}
if ( distance < DISTANCE_FOR_ACTION ) {
if ( p.vSelectActionItem( GetActivateCode( p, distance ) ) ) {
return 1.f;
}
}
return 0.f;
}
float vehicle_base::OnActivate( entity p, float distance ) {
return VehicleBase_OnActivate( p, distance );
}
void vehicle_base::OnSetTeam( object oldTeam, object newTeam ) {
InitRadarValues();
}
void vehicle_base::vSetDeployer( entity other ) {
deployer = other;
if ( g_noVehicleSpawnInvulnerability.getBoolValue() == false ) {
spawnInvulnerable = other.getFloatKey( "spawn_invulnerable" );
OnSpawnInvulnerableChanged();
}
}
void vehicle_base::CheckArmor() {
team_base team = getGameTeam();
float index;
for ( index = 0; index < getNumPositions(); index++ ) {
entity p = getPositionPlayer( index );
if ( p == $null_entity ) {
continue;
}
if ( team.HasVehicleArmorBonus( p ) ) {
SetArmorBonus( true );
return;
}
}
SetArmorBonus( false );
}
void vehicle_base::vCheckProficiency() {
CheckArmor();
decoyChargePerUse = baseDecoyChargePerUse;
entity driver = getDriver();
if ( driver != $null_entity ) {
team_base team = driver.getGameTeam();
if ( team != $null ) {
if ( team.HasEfficientDecoys( driver ) ) {
decoyChargePerUse = decoyChargePerUse * FASTER_DECOY_SCALE;
}
}
}
float count = getNumVehicleWeapons();
float index;
for ( index = 0; index < count; index++ ) {
object weapon = getVehicleWeapon( index );
weapon.vCheckProficiency();
}
}
void vehicle_base::SetArmorBonus( boolean value ) {
if ( hasArmorBonus == value ) {
return;
}
hasArmorBonus = value;
if ( hasArmorBonus ) {
setArmor( getArmor() + 0.1f );
} else {
setArmor( getArmor() - 0.1f );
}
}
boolean vehicle_base::vSkipDeployDrop() {
return true;
}
void vehicle_base::OnTeleportEntityChanged( entity other ) {
if ( !sys.isClient() ) {
entitiesOfCollection( "decoy_target" );
float count = getBoundsCacheCount();
entity target;
float i;
for( i = 0; i < count; i++ ) {
target = getBoundsCacheEntity( i );
if ( target.vGetCurrentTarget() != self ) {
continue;
}
target.vSetNewTarget( $null_entity );
}
}
// force a physics update so player origin is correct while teleporting
if ( other != $null_entity ) {
forceRunPhysics();
}
player p = sys.getLocalPlayer();
if ( p != $null_entity ) {
if ( p.getProxyEntity() == self ) {
float flags;
if ( other != $null_entity ) {
flags = sys.getGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.activeCrosshairInfoFlags" );
flags = flags & ~( CF_TASKS | CF_OBJ_MIS | CF_PLAYER_ICONS );
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.activeCrosshairInfoFlags", flags );
} else {
flags = sys.getGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.activeCrosshairInfoFlags" );
flags = flags | CF_TASKS | CF_OBJ_MIS | CF_PLAYER_ICONS;
sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.activeCrosshairInfoFlags", flags );
}
}
}
}
void vehicle_base::vOnContextRepair( entity p ) {
SetupRequestIcon( "mtr_cm_icon_need_repair", "require_view_repair" );
thread RequestIconThread( 5.f );
InitRepairTask( false );
}
void vehicle_base::vOnContextKill( entity p ) {
if ( destroyTask == $null ) {
InitDestroyTask( false );
killTaskRequestee = p;
}
FlashCMIcon( p, TA_ENEMY, -1 );
}
void vehicle_base::vOnContextNeedPassenger( entity p ) {
InitNeedPassengerTask( p );
FlashCMIcon( p, TA_FRIEND, -1 );
}
void vehicle_base::vOnRemovePlayersKillTask( player p ) {
if ( p == killTaskRequestee ) {
FreeDestroyTask();
}
}
void vehicle_base::OnRouteKickPlayer() {
entity driver = getDriver();
if ( driver != $null_entity ) {
float toolTipIndex = GetToolTip( getKey( "tt_player_kicked" ) );
sys.broadcastToolTip( toolTipIndex, driver, wstr_empty, wstr_empty, wstr_empty, wstr_empty );
kickPlayer( 0, 0 );
banPlayer( driver, 30.f );
}
}
void vehicle_base::CheckFireTeamInfo( boolean localExiting ) {
player localPlayer = sys.getLocalPlayer();
if ( localPlayer == $null_entity ) {
return;
}
boolean showMapFireTeamInfo = false;
float index;
for ( index = 0; index < getNumPositions(); index++ ) {
player other = getPositionPlayer( index );
if ( other == $null_entity ) {
continue;
}
if ( other == localPlayer ) {
continue;
}
if ( other.sameFireTeam( localPlayer ) ) {
showMapFireTeamInfo = true;
break;
}
}
if ( localExiting || localPlayer.getVehicle() != self ) {
if ( showMapFireTeamInfo ) {
if ( commandMapFireTeamInfo != -1 ) {
sys.showCMIcon( commandMapFireTeamInfo );
return;
}
}
}
if ( commandMapFireTeamInfo != -1 ) {
sys.hideCMIcon( commandMapFireTeamInfo );
}
}
string vehicle_base::vGetQuickChatString( entity p ) {
if ( getEntityAllegiance( p ) == TA_ENEMY ) {
return getKey( "qc_spotted" );
}
return "";
}
void vehicle_base::FlashCMIcon( entity p, float requiredTeam, float flashTime ) {
entity local = sys.getLocalViewPlayer();
if ( local == $null_entity ) {
return;
}
if ( flashTime == -1 ) {
flashTime = SPOTTED_FLASH_TIME;
}
if ( getEntityAllegiance( local ) == requiredTeam ) {
if ( requiredTeam == TA_ENEMY ) {
float flags = sys.getCMIconFlags( commandMapHandle );
flags = flags | CMF_ENEMYALWAYSKNOWN;
sys.flashCMIcon( commandMapHandle, -1, flashTime, flags );
} else {
sys.flashCMIcon( commandMapHandle, -1, flashTime, -1 );
}
}
}
void vehicle_base::OnCollision_Base( object traceObject, float velocity, vector mins, vector maxs ) {
if( sys.getTime() < nextCollisionEffectTime ) {
return;
}
velocity = UPStoKPH( velocity );
string surfaceType = traceObject.getTraceSurfaceType();
if ( surfaceType == "" ) {
entity other = traceObject.getTraceEntity();
if ( other != $null_entity ) {
surfaceType = other.getDefaultSurfaceType();
}
}
string severity;
if( velocity < 15 ) {
return;
} else if( velocity < 30 ) {
severity = "light";
} else if( velocity < 60 ) {
severity = "medium";
} else {
severity = "heavy";
}
vector point = traceObject.getTracePoint();
playOriginEffect( "fx_crash_" + severity, surfaceType, point, '0 0 1', 0 );
nextCollisionEffectTime = sys.getTime() + 2.f;
}
void vehicle_base::vOnEndGame() {
if ( !sys.isClient() ) {
remove();
}
}
void vehicle_base::EMPEffectThread( float time ) {
if ( empJointHandle != -1 ) {
playJointEffect( "fx_emped", empJointHandle, 1 );
}
sys.wait( time );
stopEffect( "fx_emped" );
empEffectThreadId = -1;
}
void vehicle_base::OnSpawnInvulnerableChanged() {
if ( spawnInvulnerable ) {
// make ourself invulnerable
setTakesDamage( false );
disableCollisionPush();
disableKnockback();
if ( g_drawVehicleIcons.getBoolValue() ) {
// enable the icon
float size = getFloatKeyWithDefault( "world_icon_size", 16 );
float cutoff = getFloatKeyWithDefault( "world_icon_cutoff_dist", 512 );
setIconEnabled( true );
setIconMaterial( "mtr_worldicon" );
setIconSize( size, size );
setIconColorMode( EI_NONE );
setIconPosition( EI_ABOVE );
setIconCutoff( cutoff );
}
} else {
// no longer invulnerable
setTakesDamage( true );
// disable the icon
setIconEnabled( false );
if ( normallyHaveKnockback ) {
enableCollisionPush();
enableKnockback();
}
}
}
void vehicle_base::OnLastRepairTimeChanged() {
player p = sys.getLocalPlayer();
if ( p != $null_entity && getDriver() == p && lastRepairer != $null_entity ) {
vector repairDir = lastRepairer.getWorldOrigin() - p.getWorldOrigin();
repairDir = sys.vecToAngles( repairDir );
repairDir_y = sys.angleNormalize180( repairDir_y );
p.addDamageEvent( sys.getTime(), repairDir_y, -10, true );
}
}