etqw-sdk/base/script/deployables/plasmamortar.script

424 lines
8.9 KiB
Plaintext

object deployable_plasmamortar : deployable_base {
void preinit();
void init();
void destroy();
void syncFields();
void ServerIdle();
void ServerAiming();
void ServerFiring();
void ClientIdle();
void ClientFiring();
void vTargetSetTarget( vector targetPos, entity targetEnt );
boolean vTargetGetValid( vector targetPos );
boolean vTargetPlayerEligible( entity p );
//
boolean InRange( vector targetPos );
boolean InFiringRange( vector targetPos ) { return InRange( targetPos ); }
boolean CalcTargetAngles( vector targetPos );
// utility funcs ( none of these should be blocking )
void Launch();
void FireMissile();
boolean PitchValid( float pitch );
void ReloadThread( float delay );
void OnFireSupportStateChanged();
float vGetFireSupportMode();
target_marker vCreateTargetMarker();
void ClearFiringDecal();
void CreateFiringDecal();
float recycle;
float fireCount;
float reloadWait;
float fireSyncDelay;
float nextFire;
float jointMuzzle;
float minPitch;
float maxPitch;
float minRange;
float maxRange;
float missileSpeed;
float spread;
float clientState;
float targetYaw;
float targetPitch;
vector targetDiff;
float barrelPitch;
vector firingVelocity;
boolean hasTarget;
entity targetPlayerEnemy;
float projectileIndex;
vector targetLocation;
boolean playingPitchSound;
boolean playingYawSound;
generic_target_marker firingDecal;
entity firingMarker;
};
void deployable_plasmamortar::syncFields() {
syncBroadcast( "nextFire" );
syncBroadcast( "fireSupportState" );
syncCallback( "fireSupportState", "OnFireSupportStateChanged" );
}
void deployable_plasmamortar::destroy() {
delete fsStatus;
}
float deployable_plasmamortar::vGetFireSupportMode() {
return TARGET_ROCKETS;
}
void deployable_plasmamortar::preinit() {
vector barrel;
float entityDeclIndex;
float i;
float muzzleHandle;
vector pitchJointPos;
recycle = getFloatKey( "missile_recycle" );
fireCount = getFloatKey( "missile_firecount" );
reloadWait = getFloatKey( "missile_reload" );
fireSyncDelay = getFloatKey( "sync_delay" );
spread = getFloatKey( "spread" );
if ( fireCount <= 0 ) {
fireCount = 6;
}
if ( reloadWait <= 0 ) {
reloadWait = 30;
}
if ( fireSyncDelay <= 0 ) {
fireSyncDelay = 0.5;
}
jointMuzzle = getJointHandle( getKey( "missile_barrel" ) );
entityDeclIndex = sys.getDeclType( "entityDef" );
projectileIndex = sys.getDeclIndex( entityDeclIndex, getKey( "def_projectile" ) );
minPitch = getFloatKey( "min_pitch" );
maxPitch = getFloatKey( "max_pitch" );
minRange = getFloatKey( "range_min" );
maxRange = getFloatKey( "range_max" );
missileSpeed = getFloatKey( "missile_speed" );
hasTarget = false;
nextFire = 0;
fsStatus = new fireSupportStatus;
}
void deployable_plasmamortar::init() {
vector angles;
angles = getAngles();
if ( sys.isClient() ) {
setState( "ClientIdle" );
} else {
setState( "ServerIdle" );
}
}
void deployable_plasmamortar::OnFireSupportStateChanged() {
if ( fireSupportState == MPS_FIRING ) {
if ( clientState != ART_CS_FIRING ) {
setState( "ClientFiring" );
}
} else {
if ( clientState != ART_CS_IDLE ) {
setState( "ClientIdle" );
}
}
}
// ==========================================
// States
// ==========================================
void deployable_plasmamortar::ClientIdle() {
clientState = ART_CS_IDLE;
}
void deployable_plasmamortar::ServerIdle() {
hasTarget = false;
while( true ) {
if ( hasTarget ) {
setState( "ServerAiming" );
}
sys.waitFrame();
}
}
void deployable_plasmamortar::ReloadThread( float delay ) {
fireSupportState = MPS_RELOADING;
sys.wait( delay );
fireSupportState = MPS_READY;
}
void deployable_plasmamortar::ServerAiming() {
setState( "ServerFiring" );
}
void deployable_plasmamortar::ClientFiring() {
float nextMiniFire = 0;
float baseFireTime = 0;
clientState = ART_CS_FIRING;
while( true ) {
if ( nextFire < sys.getTime() ) {
baseFireTime = sys.getTime();
nextFire = baseFireTime + recycle;
Launch();
}
sys.waitFrame();
}
}
void deployable_plasmamortar::ServerFiring() {
float count = 0;
float nextMiniFire = 0;
float baseFireTime = 0;
fireSupportState = MPS_FIRING;
nextFire = sys.getTime() + 1.f;
while( true ) {
if ( disabledState ) {
break;
}
if ( nextFire < sys.getTime() ) {
baseFireTime = sys.getTime();
nextFire = baseFireTime + recycle;
count = count + 1;
Launch();
if ( count >= fireCount ) {
break;
}
}
sys.waitFrame();
}
nextFire = 0;
thread ReloadThread( reloadWait );
setState( "ServerIdle" );
}
// ==========================================
// Utility Funcs
// ==========================================
void deployable_plasmamortar::FireMissile() {
vector org = getJointPos( jointMuzzle );
launchMissileSimple( owner, self, targetPlayerEnemy, projectileIndex, -1, spread, org, firingVelocity );
playJointEffect( "fx_fire", jointMuzzle, 0 );
}
void deployable_plasmamortar::Launch() {
string anim;
float channel;
FireMissile();
anim = getKey( "launch_anim" );
if ( anim != "" ) {
channel = getIntKey( "launch_channel" );
playAnim( channel, anim );
}
}
// ==========================================
// ==========================================
void deployable_plasmamortar::vTargetSetTarget( vector targetPos, entity targetEnt ) {
float firingPitch;
float t;
vector gravity;
vector velocity;
vector temp;
float i;
if ( !CalcTargetAngles( targetPos ) ) {
return;
}
gravity_x = 0;
gravity_y = 0;
gravity_z = -1066;
// make target pitch more vertical
targetPitch = targetPitch + ( 90 - targetPitch ) * 0.5;
firingPitch = targetPitch;
firingVelocity = targetDiff * ( sys.cos( targetPitch ) * missileSpeed );
firingVelocity_z = sys.sin( targetPitch ) * missileSpeed;
targetPlayerEnemy = owner.getEnemy();
hasTarget = true;
Base_TargetSetTarget( targetPos, targetEnt );
}
boolean deployable_plasmamortar::vTargetGetValid( vector targetPos ) {
if ( !InRange( targetPos ) ) {
return 0.f;
}
return CalcTargetAngles( targetPos );
}
boolean deployable_plasmamortar::CalcTargetAngles( vector targetPos ) {
vector barrelOrg;
vector temp;
float diffY;
float diffX;
float rootA;
float count;
float root1;
float root2;
vector modelOffset = targetPos;
barrelOrg = getJointPos( jointMuzzle );
targetDiff = modelOffset - barrelOrg;
targetYaw = sys.angleNormalize180( sys.atan2( targetDiff_y, targetDiff_x ) );
temp = targetDiff;
diffY = temp_z;
temp_z = 0.f;
targetDiff = sys.vecNormalize( temp );
diffX = sys.vecLength( temp );
// FIXME: Expose default gravity
rootA = ( 1066 * diffX * diffX ) / ( 2 * missileSpeed * missileSpeed );
count = sys.solveRoots( rootA, -diffX, rootA + diffY );
if ( count == 0 ) {
return false;
}
if ( count == 1 ) {
targetPitch = sys.atan( sys.getRoot( 0 ) );
return PitchValid( targetPitch );
}
targetPitch = sys.atan( sys.getRoot( 0 ) );
if ( PitchValid( targetPitch ) ) {
return true;
}
targetPitch = sys.atan( sys.getRoot( 1 ) );
return PitchValid( targetPitch );
}
boolean deployable_plasmamortar::PitchValid( float pitch ) {
return pitch < maxPitch && pitch > minPitch;
}
boolean deployable_plasmamortar::InRange( vector targetPos ) {
return true;
}
boolean deployable_plasmamortar::vTargetPlayerEligible( entity p ) {
if ( disabledState || !finishedDeploying ) {
return 0.f;
}
return 1.f;
}
target_marker deployable_plasmamortar::vCreateTargetMarker() {
string entityDef = getKey( "def_marker" );
if ( entityDef == "" ) {
return $null;
}
generic_target_marker marker = new generic_target_marker;
marker.Init( self, entityDef, getKey( "mtr_marker_cm" ), getFloatKey( "cm_marker_sort" ) );
if ( vGetFireSupportMode() == TARGET_ROCKETS ) {
marker.SetLocalOnly( true );
}
return marker;
}
void deployable_plasmamortar::ClearFiringDecal() {
if ( firingDecal != $null_entity ) {
delete firingDecal;
}
if ( firingMarker != $null_entity ) {
thread G_DelayRemoveEntity( firingMarker, 5.f );
firingMarker = $null_entity;
}
}
void deployable_plasmamortar::CreateFiringDecal() {
if ( !sys.isClient() ) {
firingMarker = G_CreateFiringMarker( self, firingMarker, targetLocation );
}
if ( vGetFireSupportMode() == TARGET_ROCKETS ) {
return;
}
entity p = sys.getLocalPlayer();
if ( p == $null_entity ) {
return;
}
if ( getEntityAllegiance( p ) != TA_FRIEND ) {
return;
}
if ( firingDecal == $null_entity ) {
firingDecal = vCreateTargetMarker();
}
if ( firingDecal != $null_entity ) {
firingDecal.SetTargetPosition( targetLocation );
}
}