540 lines
12 KiB
Text
540 lines
12 KiB
Text
|
|
||
|
// 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 );
|
||
|
}
|
||
|
}
|