public override void OnApplicationOrIncrease() { var stacksOfFlammable = OwnerUnit.GetStatusEffect <FumesStatusEffect>(); if (stacksOfFlammable != null) { var stacks = stacksOfFlammable.Stacks; ActionManager.Instance.RemoveStatusEffect <FumesStatusEffect>(OwnerUnit); ActionManager.Instance.ApplyStatusEffect(OwnerUnit, new BurningStatusEffect(), stacks); } }
public override void OnStruck(AbstractBattleUnit unitStriking, AbstractCard cardUsedIfAny, int totalDamageTaken) { this.OwnerUnit.ApplyStatusEffect <DealtDamageThisTurnMarker>(new DealtDamageThisTurnMarker(), 1); if (OwnerUnit.GetStatusEffect <DealtDamageThisTurnMarker>().Stacks == 3) { foreach (var combatant in state().AllyUnitsInBattle) { action().DamageUnitNonAttack(combatant, null, Stacks); } foreach (var combatant in state().EnemyUnitsInBattle) { action().DamageUnitNonAttack(combatant, null, Stacks); } } }
public override void OnApplicationOrIncrease() { if (Stacks > 100) { if (OwnerUnit.HasStatusEffect <SnappedStatusEffect>()) { OwnerUnit.CurrentHp = 0; } else { Stacks = 0; action().ApplyStatusEffect(OwnerUnit, new SnappedStatusEffect(), 1); // todo: Madness card to character deck. action().AddCardToPersistentDeck(GetMadnessCard(), OwnerUnit); } } }
public override IEnumerator ActuallyUse() { var dmg = damage + OwnerUnit.Stats.Intelligence; var hits = Physics2D.OverlapCircleAll(Owner.transform.position, radius, LayerMask.GetMask("Enemies")); foreach (var hit in hits) { OwnerUnit.TakeDamage(-(dmg * healRatio), hit.gameObject, hit); hit.GetComponent <Unit>().TakeDamage(dmg, Owner, hit); } ParticleSpawner.instance.SpawnParticleEffect( where : Owner.transform.position, effect: ParticleTypes.SiphonBloodAbility, parent: Owner.transform, lifetime: 2 ); yield return(null); }
public override bool AttemptDetectUnit(BaseUnit unit, double distanceM) { // CZ etc: http://www.fas.org/man/dod-101/navy/docs/es310/SNR_PROP/snr_prop.htm //calculate blind zone: if (!IsAbleToDetectUnit(unit, distanceM)) { return(false); } double bearingDegSensor = GetCurrentSensorBearingDeg(); double bearingDegToTarget = MapHelper.CalculateCombinedBearingDeg(bearingDegSensor, MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate, unit.Position.Coordinate)); //needs to distinguish sensors: dipping, hull mounted, towed, etc: switch (this.SensorClass.SonarType) //accounting for baffle arcs ie blind zones { case GameConstants.SonarType.HullMountedBow: if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 150, 210)) { return(false); } break; case GameConstants.SonarType.HullMountedKeel: if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 135, 225)) { return(false); } break; case GameConstants.SonarType.HullMountedFlankArray: //assumes both starbord and port if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 330, 30)) { return(false); } if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 150, 210)) { return(false); } break; case GameConstants.SonarType.DippingOrSonobuoy: //no bafflezones if (OwnerUnit.ActualSpeedKph > 30) //these sonars do not operate if moving { return(false); } break; case GameConstants.SonarType.TowedArray: if (MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 315, 45)) //MapHelper.IsAngleWithinRangeDeg(bearingDegToTarget, 135, 225)) { return(false); } if (OwnerUnit.ActualSpeedKph > GameConstants.DEFAULT_SLOW_SPEED) //do not operate above 15 kph { return(false); } break; default: break; } double noiseLevelTargetPercent = unit.GetCurrentNoiseLevelPercentage(); double noiseLevelPlatformPercent = OwnerUnit.GetCurrentNoiseLevelPercentage(); double detectionRangeM = 0; int currentSeaState = 0; var weather = unit.GetWeatherSystem(); if (weather != null) { currentSeaState = weather.SeaState; } double sensorDepthM = (double)OwnerUnit.Position.HeightOverSeaLevelM - unit.UnitClass.DraftM; double targetDepthM = (double)unit.Position.HeightOverSeaLevelM; if (this.SensorClass.IsVariableDepthSensor && this.IsDeployedIntermediateDepth && sensorDepthM < GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M) { sensorDepthM = GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M - 10; } TerrainLineSummary terrainLineSummary = GetTerrainHeightSummaryToTarget(unit); if (sensorDepthM < terrainLineSummary.MaxHeightM && targetDepthM < terrainLineSummary.MaxHeightM) { return(false); //higher terrain between objects - cannot detect } if (this.IsActive) { detectionRangeM = this.SensorClass.SonarActiveReferenceRangeM; if (OwnerUnit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M || unit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M) { if (currentSeaState > 8) { detectionRangeM *= 0.1; } else if (currentSeaState > 6) { detectionRangeM *= 0.25; } else if (currentSeaState > 4) { detectionRangeM *= 0.5; } } CurrentEffectiveActiveDetectionRangeM = detectionRangeM; if (terrainLineSummary.MaxHeightBehindM > targetDepthM) { detectionRangeM *= 0.5; } if (unit.UnitClass.IsSonarShielded) { detectionRangeM *= 0.5; } detectionRangeM = (detectionRangeM / noiseLevelPlatformPercent) * 100.0; //hmm double detectionStrength = detectionRangeM / distanceM; if (IsOnDifferentSidesOfThermalLayer(unit.Position)) //TODO: Calculate angle to layer and calculate detection based on it { detectionStrength *= 0.5; } if (detectionStrength > 1) { DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM, 0, 0); //check! return(detect != null); } //unit.UnitClass.IsSonarShielded //remember, cannot identify } else //passive detection { detectionRangeM = this.SensorClass.SonarPassiveReferenceRangeM; if (unit.HasActiveSonar) { noiseLevelTargetPercent = 800; } detectionRangeM = (detectionRangeM / noiseLevelPlatformPercent) * 100.0; //hmm if (distanceM > detectionRangeM) { return(false); } if (sensorDepthM <= GameConstants.DEFAULT_DEPTH_THERMAL_LAYER_M && unit.Position.HeightOverSeaLevelM >= GameConstants.DEPTH_PERISCOPE_MIN_M) //sound channels { detectionRangeM *= 3.0; } if (OwnerUnit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M || unit.Position.HeightOverSeaLevelM > GameConstants.DEPTH_SHALLOW_MIN_M) { if (currentSeaState > 8) { detectionRangeM *= 0.1; } else if (currentSeaState > 6) { detectionRangeM *= 0.25; } else if (currentSeaState > 4) { detectionRangeM *= 0.5; } else if (currentSeaState > 2) { detectionRangeM *= 0.8; } } if (terrainLineSummary.MaxHeightBehindM > targetDepthM) { detectionRangeM *= 0.5; } CurrentEffectivePassiveDetectionRangeM = detectionRangeM; detectionRangeM *= noiseLevelTargetPercent / 100.0; double detectionStrength = detectionRangeM / distanceM; if (IsOnDifferentSidesOfThermalLayer(unit.Position)) { detectionStrength *= 0.5; } if (detectionStrength > 1) { DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM, 0, 0); //check! return(detect != null); } //can identify, but not fix } return(false); //return base.AttemptDetectUnit(unit, distanceM); }
//ESM detection calculator: http://www.y1pwe.co.uk/AppletCD/Prop2.htm public override bool AttemptDetectUnit(BaseUnit unit, double distanceM) { if (!IsAbleToDetectUnit(unit, distanceM)) { return(false); } if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M || (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M) //under sea level { return(false); } //TODO: Take into account over-the horizon capabilities of some radars double sensorHeightOverSeaLevelM = (double)OwnerUnit.Position.HeightOverSeaLevelM + OwnerUnit.UnitClass.HeightM; double targetMaxHeightOverSeaLevelM = (double)unit.Position.HeightOverSeaLevelM + unit.UnitClass.HeightM; double LineOfSightM = MapHelper.CalculateMaxRadarLineOfSightM(sensorHeightOverSeaLevelM, targetMaxHeightOverSeaLevelM); TerrainLineSummary terrainLineSummary = null; if (IsActive) { if (distanceM <= LineOfSightM) { GameConstants.DirectionCardinalPoints direction = MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate, unit.Position.Coordinate).ToCardinalMark(); double targetApparentSizeArcSec = unit.CalculateRadarCorrectedSizeArcSec(direction, distanceM); double minDetectableSizeArcSec = SensorClass.MinimumTargetSurfaceSizeArcSec; double degradationPercent = 0; if (targetMaxHeightOverSeaLevelM > 90) { minDetectableSizeArcSec = SensorClass.MinimumTargetAirSizeArcSec; } else { degradationPercent = GameManager.Instance.GetRadarDegradationFromSeaStatePercent( OwnerUnit.GetEffectiveSeaState()); } terrainLineSummary = GetTerrainHeightSummaryToTarget(unit); if (sensorHeightOverSeaLevelM < GameConstants.MAX_HEIGHT_TERRAIN_M) { if (sensorHeightOverSeaLevelM < terrainLineSummary.MaxHeightM && targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM) { return(false); //no radar detection through terrain } if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM * 1.2 && terrainLineSummary.HeightVarianceM > 0) { degradationPercent += 10; } } if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightBehindM) { degradationPercent += 75; } if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M || unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M) //only if any below cloud cover { degradationPercent += GameManager.Instance.GetRadarDegradationFromWeatherPercent( unit.GetWeatherSystem()); } degradationPercent += OwnerUnit.GetDegradationFromJammingPercent(this.SensorClass.SensorType); if (unit.UnitClass.UnitType == GameConstants.UnitType.Missile && unit.Position.HeightOverSeaLevelM < 20) { degradationPercent += 40; //make sea skimming missiles much harder to detect } if (degradationPercent > 100) { degradationPercent = 100; } var degradationFactor = (1.0 - (degradationPercent / 100.0)); if (degradationFactor < 0.001) { degradationFactor = 0.001; } minDetectableSizeArcSec = minDetectableSizeArcSec * degradationFactor; if (targetApparentSizeArcSec >= minDetectableSizeArcSec) { double detectionStrength = targetApparentSizeArcSec / minDetectableSizeArcSec; //(SensorClass.MaxRangeM - DistanceM) / SensorClass.MaxRangeM; DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM, targetApparentSizeArcSec, minDetectableSizeArcSec); if (detect != null) { return(true); } } } } //Even if active detection attempt has been made and failed, test for esm (passive) if (SensorClass.IsEsmDetector) { GameConstants.EsmRadiationLevel esmRad = unit.GetCurrentEsmRadiation(); if (esmRad == GameConstants.EsmRadiationLevel.EsmNone) { return(false); } else { LineOfSightM = (LineOfSightM * SensorClass.EsmDetectionOverHorizonPercent) / 100.0; if (esmRad == GameConstants.EsmRadiationLevel.EsmLow) { LineOfSightM *= 0.1; } else if (esmRad == GameConstants.EsmRadiationLevel.EsmMedium) { LineOfSightM *= 0.25; } if (sensorHeightOverSeaLevelM < GameConstants.MAX_HEIGHT_TERRAIN_M) { // Get terrain summary if not already gotten if (terrainLineSummary == null) { terrainLineSummary = GetTerrainHeightSummaryToTarget(unit); } if (sensorHeightOverSeaLevelM < terrainLineSummary.MaxHeightM && targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM) { return(false); //no radar detection through terrain } if (targetMaxHeightOverSeaLevelM < terrainLineSummary.MaxHeightM * 1.2 && terrainLineSummary.HeightVarianceM > 0) { LineOfSightM *= 0.75; } } if (unit.UnitClass.UnitType == GameConstants.UnitType.Missile && unit.Position.HeightOverSeaLevelM < 20) //sea skimmers { LineOfSightM *= 0.25; } var degrJammingPercent = OwnerUnit.GetDegradationFromJammingPercent(this.SensorClass.SensorType); LineOfSightM *= (100.0 - degrJammingPercent); if (distanceM <= LineOfSightM) { DetectedUnit detect = CreateOrUpdateDetectionReport(unit, (LineOfSightM / distanceM), distanceM, 3600, 60); return(detect != null); } } } return(false); }
public override void OnTurnStart() { SecondaryStacks = Stacks; OwnerUnit.RemoveStatusEffect <FlightEffectOnFirstHitTakenThisTurn>(); OwnerUnit.ApplyStatusEffect(new FlightEffectOnFirstHitTakenThisTurn(), 1); }
public override void OnTurnStart() { OwnerUnit.RemoveStatusEffect <StrengthStatusEffect>(); }
public void Use() { LastAttack = Time.time; OwnerUnit.StartCoroutine(ActuallyUse()); }
//public virtual void Sweep() //{ // if (!IsReady) // { // return; // } // if (OwnerUnit.CarriedByUnit != null) // { // return; // } // System.Diagnostics.Debug.Assert(OwnerPlayer != null, "BaseSensor.Sweep: Sensor OwnerPlayer should never be null."); // System.Diagnostics.Debug.Assert(OwnerUnit != null, "BaseSensor.Sweep: Sensor OwnerUnit should never be null."); // System.Diagnostics.Debug.Assert(SensorClass != null, "BaseSensor.Sweep: Sensor SensorClass should never be null."); //} public virtual bool AttemptDetectUnit(BaseUnit unit, double distanceM) { //TODO: Hit test on detection if (!IsAbleToDetectUnit(unit, distanceM)) { return(false); } if (SensorClass.MaxHeightDeployedM > 0 && OwnerUnit.ActualHeightOverSeaLevelM > SensorClass.MaxHeightDeployedM) { ReadyInSec = 120; return(false); } if (SensorClass.MaxSpeedDeployedKph > 0 && OwnerUnit.ActualSpeedKph > SensorClass.MaxSpeedDeployedKph) { ReadyInSec = 120; return(false); } //if (!OwnerPlayer.IsComputerPlayer) //{ // GameManager.Instance.Log.LogDebug(string.Format( // "PLAYER {0}, UNIT {1}, SENSOR {2} attemtping to detect unit {3}.", // OwnerPlayer.ToString(), OwnerUnit.ToString(), this.ToString(), unit.ToString())); //} GameConstants.DirectionCardinalPoints DirectionToTarget = MapHelper.CalculateBearingDegrees(OwnerUnit.Position.Coordinate, unit.Position.Coordinate).ToCardinalMark(); TerrainLineSummary terrainLineSummary = GetTerrainHeightSummaryToTarget(unit); //No sensor can see through terrain if (terrainLineSummary.MaxHeightM > OwnerUnit.Position.HeightOverSeaLevelM && terrainLineSummary.MaxHeightM > unit.Position.HeightOverSeaLevelM) { return(false); } double targetApparentSizeArcSec = unit.CalculateRadarCorrectedSizeArcSec(DirectionToTarget, distanceM); if (SensorClass.SensorType == GameConstants.SensorType.Visual) { if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M || (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_SHALLOW_MIN_M) //under sea level { return(false); } double lineOfSightM = MapHelper.CalculateMaxLineOfSightM( (double)OwnerUnit.Position.HeightOverSeaLevelM + OwnerUnit.UnitClass.HeightM, (double)unit.Position.HeightOverSeaLevelM + unit.UnitClass.HeightM); double minimumTargetSizeArcSec = SensorClass.MinimumTargetSurfaceSizeArcSec; if (unit.Position.HeightOverSeaLevelM > 10) { minimumTargetSizeArcSec = SensorClass.MinimumTargetAirSizeArcSec; } if (distanceM <= lineOfSightM && targetApparentSizeArcSec >= minimumTargetSizeArcSec) { double degradationPercent = 0; WeatherSystem wsystem = OwnerUnit.GetWeatherSystem(); if (wsystem != null && SensorClass.SensorType == GameConstants.SensorType.Visual) { degradationPercent = 100 - wsystem.TotalLightPercent; } if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M || unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M) //only if any below cloud cover { degradationPercent += GameManager.Instance.GetRadarDegradationFromWeatherPercent(wsystem); } //double MinDetectableSizeArcSec = SensorClass.MinimumTargetSurfaceSizeArcSec; minimumTargetSizeArcSec = minimumTargetSizeArcSec * (1.0 + (degradationPercent / 100)); double DetectionStrength = targetApparentSizeArcSec / minimumTargetSizeArcSec; //(LineOfSightM - DistanceM) / LineOfSightM; DetectedUnit detect = CreateOrUpdateDetectionReport(unit, DetectionStrength, distanceM, targetApparentSizeArcSec, minimumTargetSizeArcSec); return(detect != null); } else { return(false); //does not detect it } } else if (SensorClass.SensorType == GameConstants.SensorType.Infrared) { if ((double)OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_PERISCOPE_MIN_M || (double)unit.Position.HeightOverSeaLevelM < GameConstants.DEPTH_SHALLOW_MIN_M) //under sea level { return(false); } double irDegradationPercent = 0; WeatherSystem weatherSystem = OwnerUnit.GetWeatherSystem(); if (OwnerUnit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M || unit.Position.HeightOverSeaLevelM < GameConstants.HEIGHT_MEDIUM_MIN_M) //only if any below cloud cover { irDegradationPercent += GameManager.Instance.GetIRDegradationFromWeatherPercent(weatherSystem); } double maxTargetDetectionDistanceM = unit.GetMaxIrDetectionDistanceM(); double LineOfSightM = MapHelper.CalculateMaxLineOfSightM( (double)OwnerUnit.Position.HeightOverSeaLevelM + OwnerUnit.UnitClass.HeightM, (double)unit.Position.HeightOverSeaLevelM) + unit.UnitClass.HeightM; if (maxTargetDetectionDistanceM > LineOfSightM) { maxTargetDetectionDistanceM = LineOfSightM; } double detectionStrength = distanceM / maxTargetDetectionDistanceM; if (detectionStrength > 1.0) { DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM, 0, 0); return(detect != null); } else { return(false); } } else if (SensorClass.SensorType == GameConstants.SensorType.MAD) { if (unit.Position == null || !unit.Position.HasHeightOverSeaLevel || unit.Position.HeightOverSeaLevelM >= GameConstants.DEPTH_SHALLOW_MIN_M) { return(false); } var unitDepthM = (double)unit.Position.HeightOverSeaLevelM; if (OwnerUnit.Position == null || !OwnerUnit.Position.HasHeightOverSeaLevel || OwnerUnit.Position.HeightOverSeaLevelM >= GameConstants.HEIGHT_MEDIUM_MIN_M) { return(false); } if (unitDepthM <= GameConstants.DEPTH_DEEP_MIN_M) { return(false); } double maxDetectionDistanceM = 1000.0; if (unitDepthM <= GameConstants.DEPTH_MEDIUM_MIN_M) { maxDetectionDistanceM = 500; } double detectionStrength = distanceM / maxDetectionDistanceM; if (detectionStrength > 1.0) { DetectedUnit detect = CreateOrUpdateDetectionReport(unit, detectionStrength, distanceM, 0, 0); return(detect != null); } else { return(false); } } return(false); }