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

778 lines
20 KiB
Plaintext

object vehicle_magog_npc {
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 vSetDeploymentParms( float deploymentItemIndex, float playerIndex, vector target, float rotation ) {
OnSetDeploymentParms( deploymentItemIndex, playerIndex, target, rotation );
}
void ClearRequest();
void OnItemChanged();
void OnStateTimeChanged();
// utility
void SetupCrate();
void SetupCommandMap();
boolean PerformDrop();
void UpdateEffects( vector pos );
// virtuals
boolean vIgnoreMagogCollsion();
// threads
void UpdateRotors();
void KillAllInBoundingBox();
void RopeThread();
// void CheckDeployable();
vector GetItemAttachPoint();
// deployment stuff
float deployIndex;
float deployPlayerIndex;
entity item;
vector targetPos;
float itemRotation;
float startTime;
float dropTime;
float returnTime;
vector gdfCorner;
vector matchPosition;
// local data
float maxHealth;
float commandMapHandle;
// rotor blades
float rearUpperRotorJoint;
float rearLowerRotorJoint;
float leftUpperRotorJoint;
float leftLowerRotorJoint;
float rightUpperRotorJoint;
float rightLowerRotorJoint;
float bladeRotationSpeed;
// rope stuff
float attachJoint;
float ropeJoint;
float hatchJoint;
float itemAttachJoint;
// physics
float maxZAccel;
float maxZVel;
boolean cancelDrop;
boolean dropped;
vector renderMins;
vector renderMaxs;
// rotor ground fx
boolean groundEffects;
float groundEffectsThreshhold;
float lastGroundEffectsTime;
entity vGetItem() {
return item;
}
void CacheItemInfoThread();
vector cachedItemOrigin;
vector cachedItemAngles;
}
void vehicle_magog_npc::SetupCommandMap() {
commandMapHandle = sys.allocCMIcon( self, 1 );
float commandMapSize = 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 );
}
void vehicle_magog_npc::syncFields() {
syncBroadcast( "item" );
syncBroadcast( "dropTime" );
syncBroadcast( "returnTime" );
syncBroadcast( "targetPos" );
syncBroadcast( "itemRotation" );
syncBroadcast( "gdfCorner" );
syncBroadcast( "startTime" );
syncBroadcast( "matchPosition" );
syncCallback( "item", "OnItemChanged" );
syncCallback( "startTime", "OnStateTimeChanged" );
syncCallback( "dropTime", "OnStateTimeChanged" );
syncCallback( "returnTime", "OnStateTimeChanged" );
}
void vehicle_magog_npc::OnItemChanged() {
SetupCrate();
if ( sys.isClient() ) {
thread CacheItemInfoThread();
}
}
void vehicle_magog_npc::OnStateTimeChanged() {
if ( returnTime != -1 ) {
setState( "Return" );
} else if ( dropTime != -1 ) {
setState( "Drop" );
} else if ( startTime != -1 ) {
setState( "Deliver" );
}
}
void vehicle_magog_npc::preinit() {
deployPlayerIndex = -1;
commandMapHandle = -1;
startTime = -1;
dropTime = -1;
returnTime = -1;
maxHealth = getFloatKey( "health" );
SetupCommandMap();
rearUpperRotorJoint = getJointHandle( "rear_upper_rotor" );
rearLowerRotorJoint = getJointHandle( "rear_lower_rotor" );
leftUpperRotorJoint = getJointHandle( "front_left_upper_rotor" );
leftLowerRotorJoint = getJointHandle( "front_left_lower_rotor" );
rightUpperRotorJoint = getJointHandle( "front_right_upper_rotor" );
rightLowerRotorJoint = getJointHandle( "front_right_lower_rotor" );
bladeRotationSpeed = getFloatKey( "blade_speed" );
if ( bladeRotationSpeed <= 0 ) {
bladeRotationSpeed = 1440.f;
}
// this is to account for rotor spooling etc
maxZAccel = getFloatKey( "max_thrust" );
maxZVel = getFloatKey( "max_z_vel" );
gdfCorner = g_vectorZero;
cancelDrop = false;
dropped = false;
// stop the comedy knock back from the deployable exploding when the magog is delivering it
disableKnockback();
startSound( "snd_rotor", SND_VEHICLE_START );
attachJoint = getJointHandle( getKey( "joint_attach" ) );
ropeJoint = getJointHandle( getKey( "joint_rope" ) );
hatchJoint = getJointHandle( getKey( "joint_hatch" ) );
itemAttachJoint = INVALID_JOINT;
groundEffects = false;
groundEffectsThreshhold = getFloatKey( "groundeffects_threshhold" );
lastGroundEffectsTime = 0.f;
setCoverage( 0.f );
thread UpdateRotors();
thread KillAllInBoundingBox();
thread RopeThread();
renderMins = getMins();
renderMaxs = getMaxs();
}
void vehicle_magog_npc::ClearRequest() {
if ( sys.isClient() ) {
return;
}
if ( deployPlayerIndex != -1 ) {
sys.clearDeployRequest( deployPlayerIndex );
deployPlayerIndex = -1;
}
}
void vehicle_magog_npc::destroy() {
if ( item != $null_entity && !sys.isClient() ) {
item.remove();
}
sys.freeCMIcon( self, commandMapHandle );
ClearRequest();
}
#define HOVER_HEIGHT_MIN 400
#define HOVER_HEIGHT_AIM 2300
void vehicle_magog_npc::Deliver() {
if ( sys.isClient() ) {
pathFind( getKey( "path_type" ), targetPos, startTime, 1.0f, gdfCorner_x, gdfCorner_y, 0, false );
pathLevel( 20, -1, -1 );
pathStraighten();
}
float numPoints = pathGetNumPoints();
if ( numPoints < 2 ) {
return;
}
// thread CheckDeployable();
float pathSpeed = getFloatKeyWithDefault( "path_speed", 1024 );
float pathLength = pathGetLength();
vector endPoint = pathGetPoint( numPoints - 1 );
endPoint_z += HOVER_HEIGHT_MIN;
vector endAngles = g_vectorZero;
endAngles_y = sys.angleNormalize180( itemRotation );
// find the actual end point
float fraction = 1.0f;
while ( fraction == 1.0f ) {
fraction = sys.traceOriented( endPoint, endPoint - '0 0 3000', renderMins, renderMaxs, endAngles, MASK_SOLID | MASK_OPAQUE, self );
endPoint = sys.getTraceEndPos();
}
endPoint_z += HOVER_HEIGHT_AIM;
matchPosition = endPoint;
startMagogDelivery( startTime, pathSpeed, 2.0f, endPoint, itemRotation );
float coverage = 0.f;
while ( true ) {
if ( sys.isServer() ) {
if ( item == $null_entity ) {
sys.warning( "DEPLOYABLE GONE" );
}
}
float frameTime = sys.getFrameTime();
setCoverage( coverage );
coverage = coverage + frameTime;
vector origin = getWorldOrigin();
if ( !sys.isClient() ) {
float distToEnd = sys.vecLength( origin - endPoint );
if ( sys.vecLength( origin - endPoint ) < 64.0f ) {
vector velocity = getLinearVelocity();
velocity_z = 0.0f;
if ( sys.vecLength( velocity ) < 50.0f ) {
setState( "Drop" );
}
}
if ( cancelDrop ) {
ClearRequest();
setState( "Return" );
}
}
sys.waitFrame();
}
}
void vehicle_magog_npc::CacheItemInfoThread() {
sys.threadName( "CacheItemInfoThread_" + getName() );
while ( true ) {
if ( item != $null_entity ) {
if ( item.isBound() ) {
cachedItemOrigin = item.getWorldOrigin();
cachedItemAngles = item.getAngles();
}
}
sys.waitFrame();
}
}
void vehicle_magog_npc::Drop() {
if( !sys.isClient() ) {
if ( !PerformDrop() ) {
// the player has switched sides or class since requesting the deployable
ClearRequest();
setState( "Return" );
}
}
if ( !sys.isClient() ) {
dropTime = sys.getTime();
} else {
while ( dropTime == -1 ) {
sys.waitFrame();
}
}
vector origin = getWorldOrigin();
vector endAngles = g_vectorZero;
endAngles_y = sys.angleNormalize180( itemRotation );
if ( item.isBound() ) {
cachedItemOrigin = item.getWorldOrigin();
cachedItemAngles = item.getAngles();
item.unbind();
}
sys.killThread( "CacheItemInfoThread_" + getName() );
// setting this back again ensures a seamless drop for all clients
item.setOrigin( cachedItemOrigin );
item.setAngles( cachedItemAngles );
item.vStartMagogDrop();
if ( item.getFloatKey( "no_drop" ) == 0.f ) {
float timeToDrop = 4.0f;
vector dropOrigin = item.getWorldOrigin();
vector dropDelta = targetPos - dropOrigin;
vector dropAngles = item.getAngles();
vector dropAngleDelta = endAngles - dropAngles;
dropAngleDelta_y = sys.angleNormalize180( dropAngleDelta_y );
float time;
float doneNess;
vector spot;
vector angles;
vector ropeModelSpot;
vector hookModelSpot;
// expand the bounds while dropping the item
vector mins = getRenderMins();
vector maxs = getRenderMaxs();
mins_z += dropDelta_z;
setRenderBounds( mins, maxs );
if ( !sys.isClient() ) {
item.vStartBoundsKillThread();
}
vector hookStartSpot = getJointPos( attachJoint );
vector ropeStartSpot = getJointPos( ropeJoint );
vector hookStartModelSpot = worldToModelSpace( hookStartSpot - origin );
vector ropeStartModelSpot = worldToModelSpace( ropeStartSpot - origin );
while ( true ) {
time = sys.getTime() - dropTime;
doneNess = time / timeToDrop;
if ( doneNess > 1.0f ) {
doneNess = 1.0f;
}
doneNess = 1 - ( sys.cos( doneNess * 180 ) + 1 ) * 0.5;
spot = dropOrigin + dropDelta * doneNess;
angles = dropAngles + dropAngleDelta * doneNess;
item.setWorldOrigin( spot );
item.setAngles( angles );
item.setLinearVelocity( vec3_origin );
item.setAngularVelocity( vec3_origin );
// use the joint position to position the hook
vector hookSpot = GetItemAttachPoint(); //item.getJointPos( itemAttachJoint );
vector ropeSpot = ( hookSpot + dropOrigin ) * 0.5f;
origin = getWorldOrigin();
hookModelSpot = worldToModelSpace( hookSpot - origin );
ropeModelSpot = worldToModelSpace( ropeSpot - origin );
setJointPos( attachJoint, JOINTMOD_WORLD_OVERRIDE, hookModelSpot );
setJointPos( ropeJoint, JOINTMOD_WORLD_OVERRIDE, ropeModelSpot );
vector resultHookSpot = getJointPos( attachJoint );
sys.waitFrame();
if ( doneNess == 1.0f ) {
break;
}
}
if ( !sys.isClient() ) {
ClearRequest();
if ( item != $null_entity ) {
item.vOnDeploy();
item = $null_entity;
}
}
// bring the hook back up
vector hookEndSpot = getJointPos( attachJoint );
vector ropeEndSpot = getJointPos( ropeJoint );
float raiseTime = sys.getTime() + 1;
while ( true ) {
time = sys.getTime() - raiseTime;
doneNess = time / ( timeToDrop * 0.75f );
CLAMP( doneNess, 0.0f, 1.0f );
doneNess = 1 - ( sys.cos( doneNess * 180 ) + 1 ) * 0.5;
origin = getWorldOrigin();
ropeStartSpot = sys.toWorldSpace( ropeStartModelSpot, self );
hookStartSpot = sys.toWorldSpace( hookStartModelSpot, self );
ropeModelSpot = worldToModelSpace( ( ropeStartSpot - ropeEndSpot ) * doneNess + ropeEndSpot - origin );
hookModelSpot = worldToModelSpace( ( hookStartSpot - hookEndSpot ) * doneNess + hookEndSpot - origin );
setJointPos( attachJoint, JOINTMOD_WORLD_OVERRIDE, hookModelSpot );
setJointPos( ropeJoint, JOINTMOD_WORLD_OVERRIDE, ropeModelSpot );
vector resultHookSpot2 = getJointPos( attachJoint );
vector hookPooSpot = ( hookStartSpot - hookEndSpot ) * doneNess + hookEndSpot - origin;
sys.waitFrame();
if ( doneNess == 1.0f ) {
break;
}
}
// restore the original render bounds
mins_z -= dropDelta_z;
setRenderBounds( mins, maxs );
}
dropped = true;
if ( !sys.isClient() ) {
setState( "Return" );
}
}
void vehicle_magog_npc::Return() {
if ( !sys.isClient() ) {
returnTime = sys.getTime();
} else {
while ( returnTime == -1 ) {
sys.waitFrame();
}
}
pathFind( getKey( "path_type" ), targetPos, returnTime, -1.0f, gdfCorner_x, gdfCorner_y, 0, false );
float numPoints = pathGetNumPoints();
if ( numPoints < 2 ) {
return;
}
pathLevel( 20, -1, -1 );
pathStraighten();
float pathSpeed = getFloatKeyWithDefault( "path_speed", 1024 );
float pathLength = pathGetLength();
vector hoverOffset = g_vectorZero;
hoverOffset_z = HOVER_HEIGHT_MIN;
vector endPoint = pathGetPoint( numPoints - 1 ) + hoverOffset;
startMagogReturn( returnTime, pathSpeed, 2.0f, endPoint );
while ( true ) {
float time = sys.getTime() - returnTime;
float position = time * pathSpeed;
float coverage = ( pathLength - 1 - position ) / pathSpeed;
setCoverage( coverage );
if ( !sys.isClient() ) {
if ( position > pathLength ) {
remove();
}
}
sys.waitFrame();
}
}
void vehicle_magog_npc::UpdateRotors() {
vector ang;
ang_y = 0.f;
while ( true ) {
sys.waitFrame();
ang_y += bladeRotationSpeed * sys.getFrameTime();
setJointAngle( rearUpperRotorJoint, JOINTMOD_WORLD, ang );
setJointAngle( rearLowerRotorJoint, JOINTMOD_WORLD, ang );
setJointAngle( leftUpperRotorJoint, JOINTMOD_WORLD, ang * 0.99f );
setJointAngle( leftLowerRotorJoint, JOINTMOD_WORLD, ang * 0.99f );
setJointAngle( rightUpperRotorJoint, JOINTMOD_WORLD, ang * 1.01f );
setJointAngle( rightLowerRotorJoint, JOINTMOD_WORLD, ang * 1.01f );
vector absMins = getAbsMins();
vector traceOrg = ( absMins + getAbsMaxs() ) * 0.5f;
UpdateEffects( traceOrg );
}
}
void vehicle_magog_npc::OnSetDeploymentParms( float deploymentItemIndex, float playerIndex, vector target, float rotation ) {
deployPlayerIndex = playerIndex;
targetPos = target;
itemRotation = sys.angleNormalize180( rotation );
if( !PerformDrop() ) {
// player has switched sides since calling in the deployable
ClearRequest();
remove();
return;
}
player p = sys.getClient( playerIndex );
item = sys.spawnType( deploymentItemIndex );
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 );
}
SetupCrate();
// setup the delivery path
startTime = sys.getTime();
gdfCorner = objManager.GetGDFBasePosition();
pathFind( getKey( "path_type" ), targetPos, startTime, 1.0f, gdfCorner_x, gdfCorner_y, 0, false );
pathLevel( 20, -1, -1 );
pathStraighten();
vector startPoint = pathGetPoint( 0 );
startPoint_z += HOVER_HEIGHT_MIN;
vector startDir = pathGetDirection( 0 );
startDir = sys.vecNormalize( startDir );
vector startAngles = sys.vecToAngles( startDir );
setWorldOrigin( startPoint );
setAngles( startAngles );
setState( "Deliver" );
}
void vehicle_magog_npc::SetupCrate() {
if ( item == $null_entity ) {
return;
}
vector org;
itemAttachJoint = item.getJointHandle( item.getKey( "joint_attach" ) );
org = GetItemAttachPoint();
org = item.worldToModelSpace( org - item.getWorldOrigin() );
if ( item != $null_entity ) {
item.setOrigin( getLocalJointPos( attachJoint ) - org );
item.bindToJoint( self, getKey( "joint_attach" ), 1 );
item.setGameTeam( getGameTeam() );
item.vSetManualDeploy();
}
}
vector vehicle_magog_npc::GetItemAttachPoint() {
if ( item == $null_entity ) {
return '0 0 0';
}
vector org;
if ( itemAttachJoint != -1 ) {
org = item.getJointPos( itemAttachJoint );
} else {
org = item.getWorldOrigin();
org_z += item.getFloatKey( "attach_height" );
}
return org;
}
void vehicle_magog_npc::KillAllInBoundingBox() {
sys.wait( 3 );
eachFrame {
vector mins = getAbsMins();
vector maxs = getAbsMaxs();
// sys.debugBounds( '1 1 1', mins, maxs, 0.f );
entitiesInBounds( mins, maxs, MASK_ALL, 1 );
float 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() ) {
if ( touchesBounds( ent ) ) {
ent.applyDamage( $null_entity, self, '0 1 0', GetDamage( "damage_magog_npc_collide" ), 60000.f, $null_entity );
}
}
}
}
}
boolean vehicle_magog_npc::vIgnoreMagogCollsion() {
return true;
}
#define MAGOC_NPC_SWINGLENGTHSCALE 2
#define MAGOC_NPC_SWINGMASS 1000
#define MAGOC_NPC_SWINGMASSEMPTY 1000
#define MAGOC_NPC_SWINGSCALE 75
#define MAGOC_NPC_SWINGSCALEEMPTY 75
#define MAGOC_NPC_SWINGFRICTION 1
void vehicle_magog_npc::RopeThread() {
vector dist = getLocalJointPos( hatchJoint ) - getLocalJointPos( ropeJoint );
vector pos = dist;
float length = sys.vecLength( dist );
vector momentum = g_vectorZero;
// sys.print( "dist:" + dist + "\n" );
while ( true ) {
sys.waitFrame();
float mass = MAGOC_NPC_SWINGMASS;
float swingScale = MAGOC_NPC_SWINGSCALE;
if ( item == $null_entity ) {
mass = MAGOC_NPC_SWINGMASSEMPTY;
swingScale = MAGOC_NPC_SWINGSCALEEMPTY;
}
float inverseMass = 1 / mass;
float gravity = 1066 * mass;
float len = length * MAGOC_NPC_SWINGLENGTHSCALE;
len = len * len;
float frameTime = sys.getFrameTime();
vector selfV = getLinearVelocity();
selfV_z = 0;
vector force = selfV * swingScale;
force_z += gravity;
vector path = sys.vecNormalize( pos );
path = path * ( -force_z / path_z );
force += path;
momentum += ( ( force - ( momentum * MAGOC_NPC_SWINGFRICTION ) ) * frameTime );
vector v = momentum * inverseMass;
pos_x = pos_x + ( v_x * frameTime );
pos_y = pos_y + ( v_y * frameTime );
pos_z = sys.sqrt( len - ( ( pos_x * pos_x ) + ( pos_y * pos_y ) ) );
// sys.print( "pos_x: " + pos_x + "\n" );
// sys.print( "v: " + v + "\n" );
vector modelPos = worldToModelSpace( pos );
setJointPos( ropeJoint, JOINTMOD_WORLD_OVERRIDE, getLocalJointPos( hatchJoint ) - modelPos );
modelPos = sys.vecNormalize( modelPos );
vector forward = '1 0 0' - ( modelPos_x * modelPos );
forward = sys.vecNormalize( forward );
forward = sys.vecToAngles( forward );
// objectStable = sys.vecLength( v ) < 0.5f && sys.fabs( pos_z - ( length * MAGOC_NPC_SWINGLENGTHSCALE ) ) < 0.5f;
setJointAngle( attachJoint, JOINTMOD_WORLD, forward );
// sys.debugLine( g_colorRed, getJointPos( hatchJoint ), getJointPos( hatchJoint ) - pos, 0.f );
}
}
boolean vehicle_magog_npc::PerformDrop() {
// special cases
if ( deployPlayerIndex == -1 ) {
return true;
}
if ( item != $null_entity ) {
if ( item.getIntKey( "always_drop" ) == 1 ) {
return true;
}
}
player p = sys.getClient( deployPlayerIndex );
if ( getEntityAllegiance( p ) != TA_FRIEND ) {
return false;
}
if( sys.getTerritoryForPoint( targetPos, getGameTeam(), 1.f, 0.f ) == $null_entity ) {
return false;
}
return true;
}
void vehicle_magog_npc::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();
if ( !sys.isClient() ) {
setState( "Return" );
}
}
void vehicle_magog_npc::UpdateEffects( vector pos ) {
groundEffects = true;//( absMins.z - traceObject.endpos.z ) < groundEffectsThreshhold;
vector end = pos;
end_z -= groundEffectsThreshhold;
sys.tracePoint( pos, end, MASK_SOLID | MASK_OPAQUE, self );
if ( sys.getTime() >= ( lastGroundEffectsTime + 0.1f )
&& groundEffects && sys.getTraceFraction() < 1.0f ) {
string surfaceTypeName = sys.getTraceSurfaceType();
playOriginEffect( "fx_groundeffect", surfaceTypeName, sys.getTraceEndPos(), sys.getTraceNormal(), 0 );
lastGroundEffectsTime = sys.getTime();
}
}