public override void Launch(IElementAttackable target, AWeapon weapon, Topography topography) { base.Launch(target, weapon, topography); AdjustHeadingForInaccuracy(); InitializeVelocity(); enabled = true; _collider.enabled = true; }
/// <summary> /// Confirms the provided enemyTarget is in range prior to launching the weapon's ordnance. /// </summary> /// <param name="enemyTarget">The target.</param> /// <returns></returns> public override bool ConfirmInRangeForLaunch(IElementAttackable enemyTarget) { float distanceToPushover = TempGameValues.__ReqdMissileTravelDistanceBeforePushover; Vector3 launchDirection = MuzzleFacing; Vector3 vectorToPushover = launchDirection * distanceToPushover; Vector3 launchPosition = MuzzleLocation; Vector3 pushoverPosition = launchPosition + vectorToPushover; Vector3 vectorToTargetFromPushover = enemyTarget.Position - pushoverPosition; float targetDistanceFromPushover = vectorToTargetFromPushover.magnitude; return distanceToPushover + targetDistanceFromPushover < Weapon.RangeDistance; }
/// <summary> /// Tries to develop a firing solution from this WeaponMount to the provided target. If successful, returns <c>true</c> and provides the /// firing solution, otherwise <c>false</c>. /// </summary> /// <param name="enemyTarget">The enemy target.</param> /// <param name="firingSolution"></param> /// <returns></returns> public override bool TryGetFiringSolution(IElementAttackable enemyTarget, out WeaponFiringSolution firingSolution) { D.Assert(enemyTarget.IsOperational); D.Assert(enemyTarget.IsAttackByAllowed(Weapon.Owner)); if (!ConfirmInRangeForLaunch(enemyTarget)) { //D.Log("{0}.CheckFiringSolution({1}) has determined target is out of range.", DebugName, enemyTarget.DebugName); firingSolution = null; return false; } firingSolution = new WeaponFiringSolution(Weapon, enemyTarget); return true; }
/// <summary> /// Called by the weapon's ordnance when this weapon's firing process against <c>targetFiredOn</c> has begun. /// </summary> /// <param name="targetFiredOn">The target fired on.</param> /// <param name="ordnanceFired">The ordnance fired.</param> public virtual void HandleFiringInitiated(IElementAttackable targetFiredOn, IOrdnance ordnanceFired) { if (!IsOperational) { D.Error("{0} fired at {1} while not operational.", Name, targetFiredOn.DebugName); } if (!_qualifiedEnemyTargets.Contains(targetFiredOn)) { D.Error("{0} fired at {1} but not in list of targets.", Name, targetFiredOn.DebugName); } //D.Log(ShowDebugLog, "{0}.HandleFiringInitiated(Target: {1}, Ordnance: {2}) called.", DebugName, targetFiredOn.DebugName, ordnanceFired.Name); RecordFiredOrdnance(ordnanceFired); ordnanceFired.deathOneShot += OrdnanceDeathEventHandler; RecordShotFired(targetFiredOn); _isLoaded = false; AssessReadiness(); }
public override void Launch(IElementAttackable target, AWeapon weapon, Topography topography) { base.Launch(target, weapon, topography); _positionLastRangeCheck = Position; _rigidbody.velocity = ElementVelocityAtLaunch; _courseUpdatePeriod = new GameTimeDuration(1F / CourseUpdateFrequency); SteeringInaccuracy = CalcSteeringInaccuracy(); target.deathOneShot += TargetDeathEventHandler; _driftCorrector = new DriftCorrector(FullName, transform, _rigidbody); enabled = true; }
/// <summary> /// Applies accumulated damage to the _impactedTarget, if any. /// </summary> private void AssessApplyDamage() { //D.Log(ShowDebugLog, "{0}.AssessApplyDamage() called.", DebugName); if (_impactedTarget == null) { // no target that can take damage has been hit, so _cumImpactTime should be zero D.AssertEqual(Constants.ZeroF, _cumHoursOfImpactOnImpactedTarget); return; } if (!_impactedTarget.IsOperational) { // target is dead so don't apply more damage _cumHoursOfImpactOnImpactedTarget = Constants.ZeroF; _impactedTarget = null; return; } DamageStrength cumDamageToApply = DamagePotential * (_cumHoursOfImpactOnImpactedTarget / Weapon.Duration); //D.Log(ShowDebugLog, "{0} is applying hit of strength {1} to {2}.", DebugName, cumDamageToApply, _impactedTarget.DisplayName); _impactedTarget.TakeHit(cumDamageToApply); if (_impactedTarget == Target) { D.Log(ShowDebugLog, "{0} has hit its intended target {1}.", DebugName, _impactedTarget.DebugName); _isIntendedTargetHit = true; } else { _isInterdicted = true; } _cumHoursOfImpactOnImpactedTarget = Constants.ZeroF; _impactedTarget = null; }
private void HandleImpact(RaycastHit impactInfo, float deltaTimeInHours) { //D.Log(ShowDebugLog, "{0} impacted on {1}.", DebugName, impactInfo.collider.name); RefreshImpactLocation(impactInfo); var impactedGo = impactInfo.collider.gameObject; if (impactedGo.layer == (int)Layers.Shields) { var shield = impactedGo.GetComponent<Shield>(); D.AssertNotNull(shield); AssessApplyDamage(); // hit a shield so apply cumDamage to previous valid target, if any HandleShieldImpact(shield, deltaTimeInHours); // for now, no impact force will be applied to the shield's parentElement return; } Profiler.BeginSample("Editor-only GC allocation (GetComponent returns null)", gameObject); var impactedTarget = impactedGo.GetComponent<IElementAttackable>(); Profiler.EndSample(); if (impactedTarget != null) { // hit an attackableTarget //D.Log(ShowDebugLog, "{0} has hit {1} {2}.", DebugName, typeof(IElementAttackable).Name, impactedTarget.DebugName); if (impactedTarget != _impactedTarget) { // hit a new target that can take damage, so apply cumDamage to previous impactedTarget, if any AssessApplyDamage(); } _impactedTarget = impactedTarget; float percentOfBeamDuration = deltaTimeInHours / Weapon.Duration; // the percentage of the beam's duration that deltaTime represents Profiler.BeginSample("Editor-only GC allocation (GetComponent returns null)", gameObject); var impactedTargetRigidbody = impactedGo.GetComponent<Rigidbody>(); Profiler.EndSample(); if (impactedTargetRigidbody != null && !impactedTargetRigidbody.isKinematic) { // target has a normal rigidbody so apply impact force float forceMagnitude = DamagePotential.Total * percentOfBeamDuration; Vector3 force = transform.forward * forceMagnitude; //D.Log(ShowDebugLog, "{0} applying impact force of {1} to {2}.", DebugName, force, impactedTarget.DisplayName); impactedTargetRigidbody.AddForceAtPosition(force, impactInfo.point, ForceMode.Impulse); } // accumulate total impact time on _impactedTarget _cumHoursOfImpactOnImpactedTarget += deltaTimeInHours; } else { // hit something else that can't take damage so apply cumDamage to previous valid target, if any AssessApplyDamage(); } }
void ExecuteAttackOrder_ExitState() { LogEvent(); //bool isUnsubscribed = __AttemptFsmTgtSubscriptionChg(FsmTgtEventSubscriptionMode.TargetDeath, _fsmPrimaryAttackTgt, toSubscribe: false); //D.Assert(isUnsubscribed); //isUnsubscribed = __AttemptFsmTgtSubscriptionChg(FsmTgtEventSubscriptionMode.InfoAccessChg, _fsmPrimaryAttackTgt, toSubscribe: false); //D.Assert(isUnsubscribed); _fsmPrimaryAttackTgt = null; }
/// <summary> /// Tries to develop a firing solution from this WeaponMount to the provided target. If successful, returns <c>true</c> and provides the /// firing solution, otherwise <c>false</c>. /// </summary> /// <param name="enemyTarget">The enemy target.</param> /// <param name="firingSolution"></param> /// <returns></returns> public override bool TryGetFiringSolution(IElementAttackable enemyTarget, out WeaponFiringSolution firingSolution) { D.Assert(enemyTarget.IsOperational); D.Assert(enemyTarget.IsAttackByAllowed(Weapon.Owner)); firingSolution = null; if (!ConfirmInRangeForLaunch(enemyTarget)) { //D.Log(ShowDebugLog, "{0}: Target {1} is out of range.", DebugName, enemyTarget.DebugName); return false; } Vector3 targetPosition = enemyTarget.Position; Quaternion reqdHubRotation, reqdBarrelElevation; bool canTraverseToTarget = TryCalcTraverse(targetPosition, out reqdHubRotation, out reqdBarrelElevation); if (!canTraverseToTarget) { //D.Log(ShowDebugLog, "{0}: Target {1} is out of traverse range.", DebugName, enemyTarget.DebugName); return false; } bool isLosClear = CheckLineOfSight(enemyTarget); if (!isLosClear) { return false; } firingSolution = new LosWeaponFiringSolution(Weapon, enemyTarget, reqdHubRotation, reqdBarrelElevation); return true; }
private void ReportCombatResults(IElementAttackable target) { if (DebugSettings.Instance.EnableCombatResultLogging) { CombatResult combatResult; if (_combatResults.TryGetValue(target, out combatResult)) { // if the weapon never fired, there won't be a combat result D.Log(combatResult.ToString()); //_combatResults.Remove(target); // for now let these accumulate so logging of hits and misses after the target } // is out of the monitor's range doesn't encounter a Dictionary key not found error } }
/// <summary> /// Called by fired ordnance when it is fatally interdicted by a Countermeasure /// (ActiveCM or Shield) or some other obstacle that was not its target. /// </summary> /// <param name="target">The target.</param> public void HandleOrdnanceInterdicted(IElementAttackable target) { var combatResult = _combatResults[target]; combatResult.Interdictions++; }
/// <summary> /// Called by fired ordnance when it misses its intended target without being fatally interdicted. /// </summary> /// <param name="target">The target.</param> public void HandleTargetMissed(IElementAttackable target) { var combatResult = _combatResults[target]; combatResult.Misses++; }
/// <summary> /// Called by fired ordnance when it hits its intended target. /// </summary> /// <param name="target">The target.</param> public void HandleTargetHit(IElementAttackable target) { var combatResult = _combatResults[target]; combatResult.Hits++; }
/// <summary> /// Records a shot was fired for purposes of tracking CombatResults. /// </summary> /// <param name="target">The target.</param> private void RecordShotFired(IElementAttackable target) { string targetName = target.DebugName; CombatResult combatResult; if (!_combatResults.TryGetValue(target, out combatResult)) { combatResult = new CombatResult(DebugName, targetName); _combatResults.Add(target, combatResult); } combatResult.ShotsTaken++; }
private bool IsQualifiedEnemyTarget(IElementAttackable enemyTarget) { return true; // UNDONE }
private void UponOrderOutcome(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target, UnitItemOrderFailureCause failCause) { RelayToCurrentState(directive, facility, isSuccess, target, failCause); }
public void Launch(IElementAttackable target, AWeapon weapon) { PrepareForLaunch(target, weapon); D.Assert((Layers)gameObject.layer == Layers.TransparentFX, "{0} is not on Layer {1}.".Inject(Name, Layers.TransparentFX.GetValueName())); weapon.isOperationalChanged += WeaponIsOperationalChangedEventHandler; _operatingEffectRenderer.SetPosition(index: 0, position: Vector3.zero); // start beam where ordnance located _beamEnd = TrackingWidgetFactory.Instance.MakeTrackableLocation(parent: gameObject); _beamEndListener = TrackingWidgetFactory.Instance.MakeInvisibleCameraLosChangedListener(_beamEnd, Layers.Cull_15); _beamEndListener.inCameraLosChanged += BeamEndInCameraLosChangedEventHandler; AssessShowMuzzleEffects(); AssessShowOperatingEffects(); enabled = true; }
/// <summary> /// Confirms the provided enemyTarget is in range prior to launching the weapon's ordnance. /// </summary> /// <param name="enemyTarget">The target.</param> /// <returns></returns> public override bool ConfirmInRangeForLaunch(IElementAttackable enemyTarget) { float weaponRange = Weapon.RangeDistance; return Vector3.SqrMagnitude(enemyTarget.Position - _hub.position) < weaponRange * weaponRange; }
public void Launch(IElementAttackable target, AWeapon weapon) { PrepareForLaunch(target, weapon); D.AssertEqual(Layers.TransparentFX, (Layers)gameObject.layer, ((Layers)gameObject.layer).GetValueName()); _operatingEffectRenderer.SetPosition(index: 0, position: Vector3.zero); AdjustHeadingForInaccuracy(); AssessShowMuzzleEffects(); AssessShowOperatingEffects(); enabled = true; }
/// <summary> /// Checks the line of sight from this LOSWeaponMount to the provided enemy target, returning <c>true</c> /// if there is a clear line of sight in the direction of the target, otherwise <c>false</c>. /// </summary> /// <param name="enemyTarget">The enemy target.</param> /// <returns></returns> private bool CheckLineOfSight(IElementAttackable enemyTarget) { Vector3 turretPosition = _hub.position; Vector3 vectorToTarget = enemyTarget.Position - turretPosition; Vector3 targetDirection = vectorToTarget.normalized; float targetDistance = vectorToTarget.magnitude; RaycastHit raycastHitInfo; if (Physics.Raycast(turretPosition, targetDirection, out raycastHitInfo, targetDistance, _defaultOnlyLayerMask)) { Profiler.BeginSample("Editor-only GC allocation (GetComponent returns null)", gameObject); var attackableTgtEncountered = raycastHitInfo.transform.GetComponent<IElementAttackable>(); Profiler.EndSample(); if (attackableTgtEncountered != null) { if (attackableTgtEncountered == enemyTarget) { //D.Log(ShowDebugLog, "{0}: CheckLineOfSight({1}) found its target.", DebugName, enemyTarget.DebugName); return true; } if (attackableTgtEncountered.IsAttackByAllowed(Weapon.Owner)) { D.Log(ShowDebugLog, "{0}: CheckLineOfSight({1}) found interfering attackable target {2} on {3}.", DebugName, enemyTarget.DebugName, attackableTgtEncountered.DebugName, _gameTime.CurrentDate); return false; } D.Log(ShowDebugLog, "{0}: CheckLineOfSight({1}) found interfering non-attackable target {2} on {3}.", DebugName, enemyTarget.DebugName, attackableTgtEncountered.DebugName, _gameTime.CurrentDate); return false; } D.Log(ShowDebugLog, "{0}: CheckLineOfSight({1}) didn't find target but found {2} on {3}.", DebugName, enemyTarget.DebugName, raycastHitInfo.transform.name, _gameTime.CurrentDate); return false; } //D.Log(ShowDebugLog, "{0}: CheckLineOfSight({1}) didn't find anything. Date: {2}.", DebugName, enemyTarget.DebugName, _gameTime.CurrentDate); return true; }
protected override void OnDespawned() { base.OnDespawned(); _cumHoursOperating = Constants.ZeroF; _cumHoursOfImpactOnImpactedTarget = Constants.ZeroF; _impactedTarget = null; _isCurrentImpact = false; _isIntendedTargetHit = false; _isInterdicted = false; _animateOperatingEffectJob = null; _impactLocation = Vector3.zero; _operatingAudioSource = null; }
public virtual void Launch(IElementAttackable target, AWeapon weapon, Topography topography) { PrepareForLaunch(target, weapon); D.Assert((Layers)gameObject.layer == Layers.Projectiles, "{0} is not on Layer {1}.".Inject(Name, Layers.Projectiles.GetValueName())); _launchPosition = transform.position; _rigidbody.drag = OpenSpaceDrag * topography.GetRelativeDensity(); _rigidbody.mass = Mass; AssessShowMuzzleEffects(); _hasWeaponFired = true; weapon.HandleFiringComplete(this); _displayMgr = InitializeDisplayMgr(); }
protected void PrepareForLaunch(IElementAttackable target, AWeapon weapon) { //D.Log(ShowDebugLog, "{0} is assigning target {1}.", DebugName, target.DebugName); Target = target; Weapon = weapon; Subscribe(); DeliveryVehicleStrength = weapon.DeliveryVehicleStrength; AssignName(); weapon.HandleFiringInitiated(target, this); _range = weapon.RangeDistance; IsOperational = true; }
public override void HandleFiringInitiated(IElementAttackable targetFiredOn, IOrdnance ordnanceFired) { base.HandleFiringInitiated(targetFiredOn, ordnanceFired); // IMPROVE Track target with turret }
protected void PrepareForLaunch(IElementAttackable target, AWeapon weapon) { Target = target; Weapon = weapon; SubscribeToWeaponChanges(); DeliveryVehicleStrength = weapon.DeliveryVehicleStrength; SyncName(); weapon.HandleFiringInitiated(target, this); _range = weapon.RangeDistance; IsOperational = true; }
public override void Launch(IElementAttackable target, AWeapon weapon, Topography topography) { base.Launch(target, weapon, topography); InitializeVelocity(); enabled = true; }
protected void ExecuteAttackOrder_UponOrderOutcome(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target, UnitItemOrderFailureCause failCause) { LogEvent(); if (directive != FacilityDirective.Attack) { D.Warn("{0} State {1} erroneously received OrderOutcome callback with {2} {3}.", DebugName, CurrentState.GetValueName(), typeof(FacilityDirective).Name, directive.GetValueName()); return; } // TODO What? It will be common for an attack by a facility to fail for cause unreachable as its target moves out of range... }
/// <summary> /// Handles the results of the facility's attempt to execute the provided directive. /// </summary> /// <param name="directive">The directive.</param> /// <param name="facility">The facility.</param> /// <param name="isSuccess">if set to <c>true</c> the directive was successfully completed. May still be ongoing.</param> /// <param name="target">The target. Can be null.</param> /// <param name="failCause">The failure cause if not successful.</param> internal void HandleOrderOutcome(FacilityDirective directive, FacilityItem facility, bool isSuccess, IElementAttackable target = null, UnitItemOrderFailureCause failCause = UnitItemOrderFailureCause.None) { UponOrderOutcome(directive, facility, isSuccess, target, failCause); }
public WeaponFiringSolution(AWeapon weapon, IElementAttackable enemyTgt) { Weapon = weapon; EnemyTarget = enemyTgt; }
/// <summary> /// Confirms the provided enemyTarget is in range PRIOR to launching the weapon's ordnance. /// <remarks>12.15.16 Got a HandleFiringInitiated error so added _qualifiedEnemyTgt criteria as /// WeaponMount range confirmation is not exactly the same thing. I'm theorizing that the target was /// barely in range of the mount (measured from the mount's hub), but just outside of the Weapon's /// Monitor range implying that the target had already been removed via OnTriggerExit().</remarks> /// </summary> /// <param name="enemyTarget">The target.</param> /// <returns></returns> public bool ConfirmInRangeForLaunch(IElementAttackable enemyTarget) { return _qualifiedEnemyTargets.Contains(enemyTarget) && WeaponMount.ConfirmInRangeForLaunch(enemyTarget); }