514 lines
No EOL
12 KiB
Text
514 lines
No EOL
12 KiB
Text
|
|
#define DROP_DIST '0 0 32768'
|
|
|
|
void G_Jotun_DropItem( float requestId, entity item, vector targetPos ) {
|
|
if ( sys.isClient() ) {
|
|
return;
|
|
}
|
|
|
|
sys.waitFrame();
|
|
|
|
vector dropOrigin = item.getWorldOrigin();
|
|
dropOrigin_x = targetPos_x;
|
|
dropOrigin_y = targetPos_y;
|
|
|
|
entity parachute;
|
|
|
|
vector down = dropOrigin - DROP_DIST;
|
|
float frac;
|
|
if ( item.vDropItemTrace( dropOrigin, down, item, targetPos ) ) {
|
|
if ( !item.vAllowDrop() ) {
|
|
if ( requestId != -1 ) {
|
|
sys.clearDeployRequest( requestId );
|
|
requestId = -1;
|
|
}
|
|
item.remove();
|
|
return;
|
|
}
|
|
frac = sys.getTraceFraction();
|
|
} else {
|
|
frac = sys.tracePoint( dropOrigin, down, CONTENTS_SOLID | CONTENTS_MOVEABLECLIP, item );
|
|
}
|
|
|
|
if ( frac == 1.f ) {
|
|
sys.warning( "G_Jotun_DropItem did not find the ground" );
|
|
}
|
|
|
|
vector finalDestinationII = sys.getTraceEndPos();
|
|
item.setComeToRest( false );
|
|
item.setGroundPosition( finalDestinationII );
|
|
item.disableKnockback();
|
|
|
|
entity traceEnt = sys.getTraceEntity();
|
|
if ( traceEnt != $null_entity && traceEnt != sys.getEntity( "worldspawn" ) ) {
|
|
item.vBindToEntity( traceEnt );
|
|
}
|
|
|
|
float parachuteDelay = item.getFloatKeyWithDefault( "parachute_deploy_delay", 3.f );
|
|
|
|
float parachuteTime = sys.getTime() + parachuteDelay;
|
|
float parachuteZ = finalDestinationII_z + 4196;
|
|
|
|
while( 1 ) {
|
|
sys.waitFrame();
|
|
|
|
if ( item == $null_entity ) { // Gordon: map restart may have happened, or something else that removes the entity, don't want to spin forever
|
|
return;
|
|
}
|
|
|
|
vector origin = item.getWorldOrigin();
|
|
vector velocity = item.getLinearVelocity();
|
|
vector delta = origin - finalDestinationII;
|
|
|
|
if ( parachuteTime != -1 && sys.getTime() > parachuteTime && origin_z < parachuteZ ) {
|
|
// spawn a parachute on the dropped vehicle
|
|
string paraDef = item.getKeyWithDefault( "def_parachute", "round_parachute" );
|
|
|
|
if ( paraDef != "" ) {
|
|
parachute = sys.spawn( paraDef );
|
|
if ( parachute != $null_entity ) {
|
|
parachute.vSetOwner( item );
|
|
parachute.vForceStayOpen( true );
|
|
}
|
|
}
|
|
|
|
parachuteTime = -1;
|
|
|
|
if ( item.vSkipDeployDrop() ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
float count = item.entitiesInBounds( item.getAbsMins(), item.getAbsMaxs(), -1, 0 );
|
|
float index;
|
|
for ( index = 0; index < count; index++ ) {
|
|
entity other = item.getBoundsCacheEntity( index );
|
|
other.applyDamage( $null_entity, item, down, GetDamage( "damage_magog_npc_collide" ), 1.f, $null_entity ); // FIXME: Get damage decl
|
|
}
|
|
|
|
if ( delta_z <= 1 ) {
|
|
break;
|
|
}
|
|
|
|
if ( velocity_z != 0.f ) {
|
|
// drift the item towards its destination to account for error in launch origin
|
|
float estTimeToHit = sys.fabs( delta_z / velocity_z );
|
|
vector newVelocity = delta * ( velocity_z / delta_z );
|
|
newVelocity_z = velocity_z;
|
|
item.setLinearVelocity( newVelocity );
|
|
}
|
|
}
|
|
|
|
item.enableKnockback();
|
|
if ( parachute != $null_entity ) {
|
|
parachute.vForceStayOpen( false );
|
|
}
|
|
|
|
if ( requestId != -1 ) {
|
|
sys.clearDeployRequest( requestId );
|
|
requestId = -1;
|
|
}
|
|
|
|
if ( item != $null_entity ) {
|
|
item.vOnDeploy();
|
|
item = $null_entity;
|
|
}
|
|
}
|
|
|
|
object vehicle_jotun {
|
|
void preinit();
|
|
void init();
|
|
void destroy();
|
|
void syncFields();
|
|
|
|
// states
|
|
void Deliver();
|
|
void Drop();
|
|
void Return();
|
|
|
|
// callbacks
|
|
void OnSetDeploymentParms( float deploymentItemIndex, float playerIndex, vector target, float rotation );
|
|
void OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location );
|
|
void ClearRequest();
|
|
void OnItemChanged();
|
|
void OnStartTimeChanged();
|
|
|
|
// utility
|
|
void DoSound();
|
|
void SetupCommandMap();
|
|
boolean PerformDrop();
|
|
|
|
// virtuals
|
|
boolean vIgnoreMagogCollsion();
|
|
|
|
// threads
|
|
void KillAllInBoundingBox();
|
|
|
|
// deployment stuff
|
|
float deployIndex;
|
|
float deployPlayerIndex;
|
|
float itemIndex;
|
|
entity item;
|
|
vector targetPos;
|
|
float itemRotation;
|
|
float startTime;
|
|
float dropTime;
|
|
float returnTime;
|
|
vector gdfCorner;
|
|
|
|
float deliveryPathLength;
|
|
float returnPathLength;
|
|
|
|
// local data
|
|
float maxHealth;
|
|
float damageIndex;
|
|
|
|
boolean cancelDrop;
|
|
boolean dropped;
|
|
|
|
boolean playedFlyBySound;
|
|
boolean playingFlySound;
|
|
float flyOverSoundRange;
|
|
};
|
|
|
|
|
|
void vehicle_jotun::SetupCommandMap() {
|
|
|
|
}
|
|
|
|
void vehicle_jotun::syncFields() {
|
|
syncBroadcast( "item" );
|
|
syncBroadcast( "dropTime" );
|
|
syncBroadcast( "returnTime" );
|
|
syncBroadcast( "targetPos" );
|
|
syncBroadcast( "itemRotation" );
|
|
syncBroadcast( "gdfCorner" );
|
|
syncBroadcast( "startTime" );
|
|
syncCallback( "item", "OnItemChanged" );
|
|
syncCallback( "startTime", "OnStartTimeChanged" );
|
|
}
|
|
|
|
void vehicle_jotun::OnItemChanged() {
|
|
}
|
|
|
|
void vehicle_jotun::OnStartTimeChanged() {
|
|
if ( startTime != -1 ) {
|
|
setState( "Deliver" );
|
|
}
|
|
}
|
|
|
|
void vehicle_jotun::preinit() {
|
|
deployPlayerIndex = -1;
|
|
startTime = -1;
|
|
dropTime = -1;
|
|
returnTime = -1;
|
|
maxHealth = getFloatKey( "health" );
|
|
|
|
SetupCommandMap();
|
|
|
|
float damageDeclIndex = sys.getDeclType( "damageDef" );
|
|
damageIndex = sys.getDeclIndex( damageDeclIndex, getKey( "dmg_drop_damage" ) );
|
|
|
|
gdfCorner = '0 0 0';
|
|
|
|
cancelDrop = false;
|
|
dropped = false;
|
|
|
|
playedFlyBySound = false;
|
|
playingFlySound = false;
|
|
|
|
flyOverSoundRange = getFloatKey( "flyover_sndrange" );
|
|
flyOverSoundRange = flyOverSoundRange * flyOverSoundRange;
|
|
|
|
setCoverage( 0.f );
|
|
|
|
disableKnockback();
|
|
hide();
|
|
}
|
|
|
|
void vehicle_jotun::init() {
|
|
thread KillAllInBoundingBox();
|
|
}
|
|
|
|
void vehicle_jotun::ClearRequest() {
|
|
if ( sys.isClient() ) {
|
|
return;
|
|
}
|
|
|
|
if ( deployPlayerIndex != -1 ) {
|
|
sys.clearDeployRequest( deployPlayerIndex );
|
|
deployPlayerIndex = -1;
|
|
}
|
|
}
|
|
|
|
void vehicle_jotun::destroy() {
|
|
sys.killThread( "KillAllInBoundingBox_" + getName() );
|
|
|
|
ClearRequest();
|
|
}
|
|
|
|
#define JOTUN_FLY_HEIGHT 4096
|
|
|
|
void vehicle_jotun::Deliver() {
|
|
show();
|
|
|
|
if ( !sys.isClient() ) {
|
|
startTime = sys.getTime();
|
|
gdfCorner = objManager.GetGDFBasePosition();
|
|
}
|
|
|
|
float pathSpeed = getFloatKeyWithDefault( "path_speed", 1024 );
|
|
string pathType = getKey( "path_type" );
|
|
|
|
// find the delivery path & level it out
|
|
pathFind( pathType, targetPos, startTime, 1.0f, gdfCorner_x, gdfCorner_y, 256.0f, false );
|
|
pathLevel( 13, -1, -1 );
|
|
float numPoints = pathGetNumPoints();
|
|
if ( numPoints < 2 ) {
|
|
return;
|
|
}
|
|
|
|
deliveryPathLength = pathGetLength();
|
|
|
|
// get the return path & level that out
|
|
pathFind( pathType, targetPos, startTime + deliveryPathLength / pathSpeed, -1.0f, gdfCorner_x, gdfCorner_y, 1024.0f, true );
|
|
float newNumPoints = pathGetNumPoints();
|
|
pathLevel( 13, numPoints - 1, newNumPoints - 1 );
|
|
|
|
returnPathLength = pathGetLength() - deliveryPathLength;
|
|
|
|
float pathLength = deliveryPathLength;
|
|
float leadTime = 2.0f;
|
|
|
|
vector flyOffset = '0 0 0';
|
|
flyOffset_z = JOTUN_FLY_HEIGHT;
|
|
|
|
// setup the start
|
|
vector startPoint = pathGetPoint( 0 ) + flyOffset;
|
|
vector endPoint = pathGetPoint( numPoints - 1 ) + flyOffset;
|
|
vector startDir = sys.vecNormalize( endPoint - startPoint );
|
|
vector startAngles = sys.vecToAngles( startDir );
|
|
|
|
setWorldOrigin( startPoint );
|
|
setAngles( startAngles );
|
|
|
|
startJotunDelivery( startTime, pathSpeed, leadTime );
|
|
|
|
float minDistance = 9999999999.0f;
|
|
float coverage = 0.f;
|
|
while ( true ) {
|
|
float time = sys.getTime() - startTime;
|
|
float frameTime = sys.getFrameTime();
|
|
|
|
setCoverage( coverage );
|
|
coverage = coverage + frameTime;
|
|
|
|
//sys.debugCircle( '1 0 0', startPoint, '0 0 1', 256.0f, 16, 0 );
|
|
//sys.debugCircle( '1 0 0', endPoint, '0 0 1', 128.0f, 16, 0 );
|
|
|
|
float aheadPosition = ( time + leadTime )* pathSpeed;
|
|
|
|
DoSound();
|
|
|
|
if ( !sys.isClient() ) {
|
|
vector origin = getWorldOrigin();
|
|
vector delta = origin - endPoint;
|
|
delta_z = 0.0f;
|
|
float distance = sys.vecLength( delta );
|
|
|
|
if ( distance < minDistance ) {
|
|
minDistance = distance;
|
|
} else if ( aheadPosition > pathLength ) {
|
|
Drop();
|
|
}
|
|
} else if ( returnTime != -1 ) {
|
|
setState( "Return" );
|
|
}
|
|
|
|
if ( cancelDrop ) {
|
|
ClearRequest();
|
|
setState( "Return" );
|
|
}
|
|
|
|
sys.waitFrame();
|
|
}
|
|
}
|
|
|
|
void vehicle_jotun::Drop() {
|
|
|
|
player p = sys.getClient( deployPlayerIndex );
|
|
item = sys.spawnType( itemIndex );
|
|
item.vSetDeployableOwner( p );
|
|
|
|
deployable_base deployable = item;
|
|
if ( deployable != $null_entity ) {
|
|
p.SetTargetingItem( item );
|
|
}
|
|
|
|
string statName = item.getKey( "stat_name" );
|
|
if ( statName != "" ) {
|
|
sys.increaseStatInt( sys.allocStatInt( statName + "_deployed" ), deployPlayerIndex, 1 );
|
|
}
|
|
|
|
if( PerformDrop() ) {
|
|
vector temp = getWorldOrigin();
|
|
|
|
vector angles;
|
|
angles_y = itemRotation;
|
|
|
|
item.setOrigin( temp - ( g_vectorDown * 256 ) );
|
|
item.setAngles( angles );
|
|
item.setGameTeam( getGameTeam() );
|
|
item.vSetManualDeploy();
|
|
thread G_Jotun_DropItem( deployPlayerIndex, item, targetPos );
|
|
} else {
|
|
item.remove();
|
|
ClearRequest();
|
|
}
|
|
|
|
deployPlayerIndex = -1;
|
|
dropped = true;
|
|
|
|
setState( "Return" );
|
|
}
|
|
|
|
void vehicle_jotun::Return() {
|
|
if ( !sys.isClient() ) {
|
|
returnTime = sys.getTime();
|
|
} else {
|
|
while ( returnTime == -1 ) {
|
|
sys.waitFrame();
|
|
}
|
|
}
|
|
|
|
float numPoints = pathGetNumPoints();
|
|
if ( numPoints < 2 ) {
|
|
return;
|
|
}
|
|
|
|
float pathSpeed = getFloatKeyWithDefault( "path_speed", 1024 );
|
|
float pathLength = returnPathLength;
|
|
float leadTime = 2.0f;
|
|
|
|
vector flyOffset = '0 0 0';
|
|
flyOffset_z = JOTUN_FLY_HEIGHT;
|
|
|
|
vector endPoint = pathGetPoint( numPoints - 1 ) + flyOffset;
|
|
startJotunReturn( returnTime, pathSpeed, leadTime );
|
|
|
|
while ( true ) {
|
|
DoSound();
|
|
|
|
float time = sys.getTime() - returnTime;
|
|
float position = time * pathSpeed;
|
|
setCoverage( ( pathLength - 1 - position ) / pathSpeed );
|
|
|
|
if ( !sys.isClient() ) {
|
|
if ( position > pathLength ) {
|
|
remove();
|
|
}
|
|
}
|
|
|
|
sys.waitFrame();
|
|
}
|
|
}
|
|
|
|
void vehicle_jotun::DoSound() {
|
|
if( !playingFlySound ) {
|
|
playingFlySound = true;
|
|
fadeSound( SND_VEHICLE_IDLE, -60.f, 0.f );
|
|
startSound( "snd_flyby_far", SND_VEHICLE_IDLE );
|
|
fadeSound( SND_VEHICLE_IDLE, 0.f, 2.f );
|
|
}
|
|
|
|
// check distance to local player
|
|
if( !playedFlyBySound ) {
|
|
entity p = sys.getLocalPlayer();
|
|
if( p != $null_entity ) {
|
|
vector playerOrigin = p.getWorldOrigin();
|
|
playerOrigin -= getWorldOrigin();
|
|
playerOrigin_z = 0.f;
|
|
|
|
if( sys.vecLengthSquared( playerOrigin ) < flyOverSoundRange ) {
|
|
sys.startSoundDirect( getKey( "snd_flyby" ), SND_VEHICLE_IDLE );
|
|
playedFlyBySound = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void vehicle_jotun::OnSetDeploymentParms( float deploymentItemIndex, float playerIndex, vector target, float rotation ) {
|
|
|
|
deployPlayerIndex = playerIndex;
|
|
targetPos = target;
|
|
itemRotation = sys.angleNormalize180( rotation );
|
|
itemIndex = deploymentItemIndex;
|
|
|
|
if( !PerformDrop() ) {
|
|
// player has switched sides since calling in the deployable
|
|
ClearRequest();
|
|
remove();
|
|
return;
|
|
}
|
|
|
|
player p = sys.getClient( playerIndex );
|
|
|
|
setState( "Deliver" );
|
|
}
|
|
|
|
void vehicle_jotun::OnKilled( entity inflictor, entity attacker, float damage, vector direction, float location ) {
|
|
}
|
|
|
|
void vehicle_jotun::KillAllInBoundingBox() {
|
|
sys.threadName( "KillAllInBoundingBox_" + getName() );
|
|
|
|
sys.wait( 3 );
|
|
|
|
eachFrame {
|
|
|
|
vector mins = getAbsMins();
|
|
vector maxs = getAbsMaxs();
|
|
|
|
// sys.debugBounds( '1 1 1', mins, maxs, 0.f );
|
|
|
|
float count = entitiesInBounds( mins, maxs, MASK_ALL, 1 );
|
|
count = filterEntitiesByClass( "sdTransport", 1 );
|
|
|
|
float i;
|
|
for( i = 0; i < count; i++ ) {
|
|
entity ent = getBoundsCacheEntity( i );
|
|
if( ent == self || ent == item || ent == $null_entity ) {
|
|
continue;
|
|
}
|
|
|
|
if( !ent.vIgnoreMagogCollsion() ) {
|
|
ent.applyDamage( $null_entity, self, '0 1 0', GetDamage( "damage_magog_npc_collide" ), 60000.f, $null_entity );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean vehicle_jotun::vIgnoreMagogCollsion() {
|
|
return true;
|
|
}
|
|
|
|
boolean vehicle_jotun::PerformDrop() {
|
|
return true;
|
|
}
|
|
|
|
void vehicle_jotun::vCancelDeployForPlayer( float playerIndex ) {
|
|
if ( playerIndex != deployPlayerIndex ) {
|
|
return;
|
|
}
|
|
|
|
// deployables already gone
|
|
if ( dropped ) {
|
|
return;
|
|
}
|
|
|
|
player p = sys.getClient( deployPlayerIndex );
|
|
objManager.PlaySoundForPlayer( getKey( "snd_cancel_deploy" ), p );
|
|
|
|
ClearRequest();
|
|
setState( "Return" );
|
|
} |