// Zappor: Strogg thing that calls down a giant airstrike #define ZA_DEPLOY 1 #define ZA_IDLE_DAMAGED 2 #define ZA_STARTFIRE 3 #define ZA_FIRING 4 #define ZA_FIRED 5 object mining_laser_beacon { void SetEntities( entity o, entity l ); } object mining_laser_objective : constructible_materials { void preinit(); void SetupConstruction(); void OnConstructionFinished( entity p ); void DoZap( entity p ); void SetEntities( entity o, entity l ); float OnUpdateCrosshairInfo( entity p ); boolean IsPrimaryConstruction() { return true; } entity vGetSpectateEntity(); boolean vIsObjectiveComplete(); entity deployer; entity laser; boolean hasZapped; handle constructedMessage; handle objectName; } void mining_laser_objective::preinit() { forceShowProgress = true; constructedMessage = sys.localizeString( "maps/generic/zappor/constructed" ); objectName = sys.localizeString( getKey( "object_name" ) ); } void mining_laser_objective::SetupConstruction() { multipleStages = false; if ( sys.isClient() ) { OnStateChanged(); return; } firstStage = sys.spawn( getKey( "def_construction" ) ); firstStage.setOrigin( getWorldOrigin() ); firstStage.setAngles( getAngles() ); firstStage.setGameTeam( getGameTeam() ); firstStage.vSetOwner( self ); SetConstructionState( CSTATE_NONE ); } void mining_laser_objective::OnConstructionFinished( entity p ) { OnFinishCurrentState( p ); counter = constructionCount; if ( !sys.isClient() ) { objManager.PushCPrintString( p.getUserName() ); objManager.CPrintEvent( constructedMessage, $null ); objManager.OnMiningLaserConstructed( self ); firstStage.remove(); DoZap( p ); } } void mining_laser_objective::DoZap( entity p ) { if ( deployer == $null_entity || hasZapped ) { return; } mining_laser_beacon targ = deployer.getEntityKey( "target" ); if ( targ == $null_entity ) { sys.error( "mining_laser_objective::DoZap could not find target" ); } targ.SetEntities( p, laser ); targ.vOnDeploy(); hasZapped = true; } void mining_laser_objective::SetEntities( entity o, entity l ) { deployer = o; laser = l; if ( deployer != $null_entity ) { vStartObjective(); } } float mining_laser_objective::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.f; } float allegiance = getEntityAllegiance( p ); float distance; if ( deployer != $null_entity ) { distance = deployer.chGetDistance(); } else { distance = chGetDistance(); } float range = InchesToMetres( distance ); chSetNumLines( 0 ); team_base team; if ( p != $null_entity ) { if ( p.isLocalPlayer() && objectiveIndex != -1 ) { p.sendToolTip( GetToolTip( getKey( "tt_intro_info" ) ) ); } // see if theres a valid action to perform float code = GetActivateCode( p, distance ); if ( code != AK_NONE && p.vHasActionItem( code ) ) { float index = chAddLine(); chSetLineMaterial( index, p.vGetActionIcon( code ) ); chSetLineType( index, CI_IMAGE ); chSetLineSize( index, 64, 64 ); chSetLineColor( index, g_colorWhite, 0.9f ); if ( p.isLocalPlayer() ) { if ( !p.isToolTipPlaying() ) { if ( sys.getTime() - p.getCrosshairStartTime() > 1.f ) { if ( p.getCurrentWeapon() != p.vGetActionItem( code ) ) { p.sendToolTip( useMeToolTip1 ); } else { p.sendToolTip( useMeToolTip2 ); } } } } } } vector color = GetAllegianceColor( allegiance ); index = chAddLine(); chSetLineTextIndex( index, objectName ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); if( range <= 100 ) { index = chAddLine(); chSetLineText( index, G_BuildRangeStr( range ) ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); } return 1.f; } entity mining_laser_objective::vGetSpectateEntity() { float time = sys.getTime(); if ( lastConstructTime >= time - 0.5f ) { return constructor; } return $null_entity; } boolean mining_laser_objective::vIsObjectiveComplete() { if ( multipleStages ) { if ( state == CSTATE_FIRST_SECOND ) { return true; } } else { if ( state == CSTATE_FIRST ) { return true; } } return false; } object mining_laser { void init(); void syncFields(); void vOnDeploy(); void vSetManualDeploy(); void vSetOwner( entity o ); void DoDeployAnim(); float AnimState( float state ); void OnAnimStateChanged(); void BoundsKillThread(); float OnUpdateCrosshairInfo( entity p ); boolean manualDeploy; entity deployer; boolean deployed; float currentAnimState; handle objectName; } void mining_laser::syncFields() { syncBroadcast( "deployed" ); syncCallback( "deployed", "vOnDeploy" ); syncBroadcast( "currentAnimState" ); syncCallback( "currentAnimState", "OnAnimStateChanged" ); } void mining_laser::init() { setContents( CONTENTS_PLAYERCLIP | CONTENTS_VEHICLECLIP | CONTENTS_FLYERHIVECLIP ); objectName = sys.localizeString( getKey( "object_name" ) ); if ( !sys.isClient() ) { thread BoundsKillThread(); if ( !manualDeploy ) { vOnDeploy(); } } disableImpact(); } void mining_laser::OnAnimStateChanged() { AnimState( currentAnimState ); } void mining_laser::vOnDeploy() { deployed = true; putToRest(); disableImpact(); if ( !sys.isClient() ) { sys.killThread( "BoundsKillThread_" + getName() ); mining_laser_objective objectiveThing = sys.spawn( getKey( "def_objective" ) ); if ( objectiveThing == $null ) { sys.error( "mining_laser::vOnDeploy failed to spawn objective" ); } objectiveThing.setOrigin( getWorldOrigin() ); objectiveThing.setAngles( getAngles() ); objectiveThing.setGameTeam( getGameTeam() ); objectiveThing.SetEntities( deployer, self ); objectiveThing.vOnDeploy(); objManager.OnMiningLaserDeployed( objectiveThing ); thread DoDeployAnim(); } } float mining_laser::AnimState( float state ) { currentAnimState = state; if ( currentAnimState == ZA_DEPLOY ) { return playAnim( ANIMCHANNEL_ALL, "deploy" ); } if ( currentAnimState == ZA_IDLE_DAMAGED ) { return playAnim( ANIMCHANNEL_ALL, "idle_damaged" ); } if ( currentAnimState == ZA_STARTFIRE ) { return playAnim( ANIMCHANNEL_ALL, "startfire" ); } if ( currentAnimState == ZA_FIRING ) { return playAnim( ANIMCHANNEL_ALL, "fire" ); } if ( currentAnimState == ZA_FIRED ) { return playAnim( ANIMCHANNEL_ALL, "idle_after_firing" ); } return 0.f; } void mining_laser::DoDeployAnim() { sys.wait( AnimState( ZA_DEPLOY ) ); AnimState( ZA_IDLE_DAMAGED ); } void mining_laser::vSetOwner( entity o ) { deployer = o; } void mining_laser::vSetManualDeploy() { manualDeploy = true; } void mining_laser::BoundsKillThread() { float damageIndex = GetDamage( getKey( "dmg_crush" ) ); while ( true ) { BoundsDamage( self, damageIndex ); sys.waitFrame(); } } float mining_laser::OnUpdateCrosshairInfo( entity p ) { if ( !sys.doClientSideStuff() ) { return 1.0f; } float allegiance = getEntityAllegiance( p ); vector color = GetAllegianceColor( allegiance ); float distance; if ( deployer != $null_entity ) { distance = deployer.chGetDistance(); } else { distance = chGetDistance(); } float range = InchesToMetres( distance ); chSetNumLines( 0 ); float index; index = chAddLine(); chSetLineTextIndex( index, objectName ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); if( range <= 100 ) { index = chAddLine(); chSetLineText( index, G_BuildRangeStr( range ) ); chSetLineColor( index, color, 1.f ); chSetLineType( index, CI_TEXT ); chSetLineSize( index, 0, 0 ); } return 1.f; } object mining_laser_beacon { void preinit(); void init(); void destroy(); void syncFields(); void Idle(); void Update(); void vOnDeploy(); void OnFiringChanged(); boolean vInhibitStats() { return true; } entity destroyTarget; entity destroyTarget2; float beamEndTime; float beamRotationSpeed; object beamEffect; float damageIndex; float splashDamageIndex; boolean hasFired; boolean firing; float muzzleJoint; entity caller; mining_laser laser; vector target_offset; } void mining_laser_beacon::preinit() { beamRotationSpeed = getFloatKey( "beam_rotation_speed" ); damageIndex = GetDamage( getKey( "dmg_damage" ) ); splashDamageIndex = GetDamage( getKey( "dmg_splash_damage" ) ); target_offset = getVectorKey( "target_offset" ); } void mining_laser_beacon::init() { destroyTarget = getEntityKey( "target" ); destroyTarget2 = getEntityKey( "target_secondary" ); } void mining_laser_beacon::destroy() { stopEffect( "fx_beam_impact" ); if ( beamEffect != $null_entity ) { beamEffect.remove(); beamEffect = $null_entity; } } void mining_laser_beacon::syncFields() { syncBroadcast( "laser" ); syncBroadcast( "firing" ); syncCallback( "firing", "OnFiringChanged" ); } void mining_laser_beacon::vOnDeploy() { setState( "Idle" ); } void mining_laser_beacon::OnFiringChanged() { if ( firing ) { setState( "Idle" ); } } void mining_laser_beacon::SetEntities( entity o, entity l ) { caller = o; laser = l; } void mining_laser_beacon::Idle() { if ( !sys.isClient() ) { sys.wait( laser.AnimState( ZA_STARTFIRE ) ); beamEndTime = sys.getTime() + laser.AnimState( ZA_FIRING ); firing = true; } muzzleJoint = laser.getJointHandle( "muzzle" ); while ( firing ) { Update(); sys.waitFrame(); } if ( !sys.isClient() ) { laser.AnimState( ZA_FIRED ); } else { stopEffect( "fx_beam_impact" ); playOriginEffect( "fx_explode", "", getWorldOrigin(), getWorldAxis( 0 ), 0 ); startSound( "snd_beam_stop", SND_WEAPON_FIRE2 ); if ( beamEffect != $null_entity ) { beamEffect.remove(); beamEffect = $null_entity; } } sys.wait( 10.f ); stopEffect( "fx_beam_impact" ); if ( beamEffect != $null_entity ) { beamEffect.remove(); beamEffect = $null_entity; } } void mining_laser_beacon::Update() { float currentTime = sys.getTime(); vector endPos = getWorldOrigin(); vector startPos = laser.getJointPos( muzzleJoint ); float count = entitiesInTranslation( startPos, endPos, MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, $null_entity ); boolean doFire; if ( sys.isClient() ) { doFire = firing; } else { doFire = currentTime < beamEndTime; } if ( doFire ) { if ( beamEffect == $null_entity ) { beamEffect = spawnClientEffect( "fx_beam" ); if ( beamEffect != $null_entity ) { beamEffect.setEffectLooping( 1 ); beamEffect.setOrigin( startPos ); beamEffect.setEffectEndOrigin( endPos ); } playOriginEffect( "fx_beam_impact", "", endPos + target_offset, getWorldAxis( 0 ), true ); startSound( "snd_beam_start", SND_WEAPON_FIRE2 ); } float i; for ( i = 0; i < count; i++ ) { entity ent = getBoundsCacheEntity( i ); if ( ent == $null_entity ) { continue; } if ( ent == destroyTarget || ent == destroyTarget2 ) { continue; } ent.applyDamage( self, $null_entity, vec3_down, damageIndex, 1.0f, $null_entity ); } } else { firing = false; if ( beamEffect != $null_entity ) { beamEffect.endEffect( false ); } if ( !hasFired ) { stopEffect( "fx_beam_impact" ); playOriginEffect( "fx_explode", "", endPos, getWorldAxis( 0 ), 0 ); startSound( "snd_beam_stop", SND_WEAPON_FIRE2 ); if ( destroyTarget != $null_entity ) { destroyTarget.applyDamage( self, caller, '0 0 1', damageIndex, 1.0f, $null_entity ); } if ( destroyTarget2 != $null_entity ) { destroyTarget2.applyDamage( self, caller, '0 0 1', damageIndex, 1.0f, $null_entity ); } sys.applyRadiusDamage( endPos, self, caller, $null_entity, self, splashDamageIndex, 1.f, 1.f ); hasFired = true; } } if ( beamEffect != $null_entity ) { vector forward = sys.vecNormalize(endPos - startPos); vector up = '0 0 1'; vector right = sys.crossProduct( up, forward ); up = sys.crossProduct( forward, right ); beamEffect.setWorldAxis( forward, right, up ); } }