#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" ); }