private void UpdateResults(object sender, EventArgs e) { if (!AllowUpdate) { return; } int AttackerSize = 0; if (rbAttackerSizeLLL.Checked) { AttackerSize = 30; } else if (rbAttackerSizeLL.Checked) { AttackerSize = 20; } else if (rbAttackerSizeL.Checked) { AttackerSize = 10; } else if (rbAttackerSizeM.Checked) { AttackerSize = 0; } else if (rbAttackerSizeS.Checked) { AttackerSize = -10; } else if (rbAttackerSizeSS.Checked) { AttackerSize = -20; } int DefenderSize = 0; if (rbDefenderSizeLLL.Checked) { DefenderSize = 30; } else if (rbDefenderSizeLL.Checked) { DefenderSize = 20; } else if (rbDefenderSizeL.Checked) { DefenderSize = 10; } else if (rbDefenderSizeM.Checked) { DefenderSize = 0; } else if (rbDefenderSizeS.Checked) { DefenderSize = -10; } else if (rbDefenderSizeSS.Checked) { DefenderSize = -20; } int SizeCompare = AttackerSize - DefenderSize; int WeaponTerrain = 0; int DefenderTerrain = 0; int DefenderPilotTerrain = 0; int AttackerTerrain = 0; int AttackerPilotTerrain = 0; #region Terrain Values char WeaponTerrainLetter = 'B'; if (rbDefenderMovementAir.Checked && !String.IsNullOrEmpty(cbWeaponAirRank.Text)) { WeaponTerrainLetter = cbWeaponAirRank.Text[0]; } else if (rbDefenderMovementLand.Checked && !String.IsNullOrEmpty(cbWeaponLandRank.Text)) { WeaponTerrainLetter = cbWeaponLandRank.Text[0]; } else if (rbDefenderMovementSea.Checked && !String.IsNullOrEmpty(cbWeaponSeaRank.Text)) { WeaponTerrainLetter = cbWeaponSeaRank.Text[0]; } else if (rbDefenderMovementSpace.Checked && !String.IsNullOrEmpty(cbWeaponSpaceRank.Text)) { WeaponTerrainLetter = cbWeaponSpaceRank.Text[0]; } switch (WeaponTerrainLetter) { case 'S': WeaponTerrain = 20; break; case 'A': WeaponTerrain = 0; break; case 'B': WeaponTerrain = -20; break; case 'C': WeaponTerrain = -40; break; case 'D': WeaponTerrain = -60; break; } #region Defender char DefenderTerrainLetter = 'B'; if (rbDefenderMovementAir.Checked && !String.IsNullOrEmpty(cbDefenderTerrainAir.Text)) { DefenderTerrainLetter = cbDefenderTerrainAir.Text[0]; } else if (rbDefenderMovementLand.Checked && !String.IsNullOrEmpty(cbDefenderTerrainLand.Text)) { DefenderTerrainLetter = cbDefenderTerrainLand.Text[0]; } else if (rbDefenderMovementSea.Checked && !String.IsNullOrEmpty(cbDefenderTerrainSea.Text)) { DefenderTerrainLetter = cbDefenderTerrainSea.Text[0]; } else if (rbDefenderMovementSpace.Checked && !String.IsNullOrEmpty(cbDefenderTerrainSpace.Text)) { DefenderTerrainLetter = cbDefenderTerrainSpace.Text[0]; } switch (DefenderTerrainLetter) { case 'S': DefenderTerrain = 20; break; case 'A': DefenderTerrain = 10; break; case 'B': DefenderTerrain = 0; break; case 'C': DefenderTerrain = -10; break; case 'D': DefenderTerrain = -20; break; } char DefenderPilotTerrainLetter = 'B'; if (rbDefenderMovementAir.Checked && !String.IsNullOrEmpty(cbDefenderAirRank.Text)) { DefenderPilotTerrainLetter = cbDefenderAirRank.Text[0]; } else if (rbDefenderMovementLand.Checked && !String.IsNullOrEmpty(cbDefenderLandRank.Text)) { DefenderPilotTerrainLetter = cbDefenderLandRank.Text[0]; } else if (rbDefenderMovementSea.Checked && !String.IsNullOrEmpty(cbDefenderSeaRank.Text)) { DefenderPilotTerrainLetter = cbDefenderSeaRank.Text[0]; } else if (rbDefenderMovementSpace.Checked && !String.IsNullOrEmpty(cbDefenderSpaceRank.Text)) { DefenderPilotTerrainLetter = cbDefenderSpaceRank.Text[0]; } switch (DefenderPilotTerrainLetter) { case 'S': DefenderPilotTerrain = 20; break; case 'A': DefenderPilotTerrain = 10; break; case 'B': DefenderPilotTerrain = 0; break; case 'C': DefenderPilotTerrain = -10; break; case 'D': DefenderPilotTerrain = -20; break; } #endregion #region Attacker char AttackerTerrainLetter = 'B'; if (rbAttackerMovementAir.Checked && !String.IsNullOrEmpty(cbAttackerTerrainAir.Text)) { AttackerTerrainLetter = cbAttackerTerrainAir.Text[0]; } else if (rbAttackerMovementLand.Checked && !String.IsNullOrEmpty(cbAttackerTerrainLand.Text)) { AttackerTerrainLetter = cbAttackerTerrainLand.Text[0]; } else if (rbAttackerMovementSea.Checked && !String.IsNullOrEmpty(cbAttackerTerrainSea.Text)) { AttackerTerrainLetter = cbAttackerTerrainSea.Text[0]; } else if (rbAttackerMovementSpace.Checked && !String.IsNullOrEmpty(cbAttackerTerrainSpace.Text)) { AttackerTerrainLetter = cbAttackerTerrainSpace.Text[0]; } switch (AttackerTerrainLetter) { case 'S': AttackerTerrain = 20; break; case 'A': AttackerTerrain = 10; break; case 'B': AttackerTerrain = 0; break; case 'C': AttackerTerrain = -10; break; case 'D': AttackerTerrain = -20; break; } char AttackerPilotTerrainLetter = 'B'; if (rbAttackerMovementAir.Checked && !String.IsNullOrEmpty(cbAttackerAirRank.Text)) { AttackerPilotTerrainLetter = cbAttackerAirRank.Text[0]; } else if (rbAttackerMovementLand.Checked && !String.IsNullOrEmpty(cbAttackerLandRank.Text)) { AttackerPilotTerrainLetter = cbAttackerLandRank.Text[0]; } else if (rbAttackerMovementSea.Checked && !String.IsNullOrEmpty(cbAttackerSeaRank.Text)) { AttackerPilotTerrainLetter = cbAttackerSeaRank.Text[0]; } else if (rbAttackerMovementSpace.Checked && !String.IsNullOrEmpty(cbAttackerSpaceRank.Text)) { AttackerPilotTerrainLetter = cbAttackerSpaceRank.Text[0]; } switch (AttackerPilotTerrainLetter) { case 'S': AttackerPilotTerrain = 20; break; case 'A': AttackerPilotTerrain = 10; break; case 'B': AttackerPilotTerrain = 0; break; case 'C': AttackerPilotTerrain = -10; break; case 'D': AttackerPilotTerrain = -20; break; } #endregion int FinalAttackerTerrainMultiplier = 0; switch (AttackerTerrain + AttackerPilotTerrain) { case -40: case -30: FinalAttackerTerrainMultiplier = -60; break; case -20: case -10: FinalAttackerTerrainMultiplier = -40; break; case 0: case 10: FinalAttackerTerrainMultiplier = -20; break; case 20: case 30: FinalAttackerTerrainMultiplier = 0; break; case 40: FinalAttackerTerrainMultiplier = 20; break; } int FinalDefenderTerrainMultiplier = 0; switch (DefenderTerrain + DefenderPilotTerrain) { case -40: case -30: FinalDefenderTerrainMultiplier = -60; break; case -20: case -10: FinalDefenderTerrainMultiplier = -40; break; case 0: case 10: FinalDefenderTerrainMultiplier = -20; break; case 20: case 30: FinalDefenderTerrainMultiplier = 0; break; case 40: FinalDefenderTerrainMultiplier = 20; break; } #endregion #region Attack Formula int PilotPower; if (rbWeaponMelee.Checked) { PilotPower = (int)txtAttackerPilotMEL.Value; } else { PilotPower = (int)txtAttackerPilotRNG.Value; } //ATTACK = (((Attack Power * ((Pilot Will + Pilot Stat)/ 200) *Attack Side Terrain Performance) +Additive Base Damage Bonuses) *Base Damage Multiplier Bonuses int AttackFormula = (int)((int)txtWeaponDamage.Value * ((int)txtAttackerPilotMorale.Value + PilotPower) / 200f * (1 + WeaponTerrain / 100f)); txtAttackFormula.Text = AttackFormula.ToString(); #endregion #region Defense Formula int Armor = (int)txtDefenderArmor.Value; //DEFENSE = ((Robot Armor Stat * ((Pilot Will + Pilot Def)/200) * Defense Side Terrain Performance) + Additive Base Defense Bonuses * Multiplying base defense bonuses) * Tile Bonus int DefenseFormula = (int)(Armor * (((int)txtAttackerPilotMorale.Value + (int)txtDefenderPilotDEF.Value) / 200f) * (1 + FinalDefenderTerrainMultiplier / 100f)); txtDefenseFormula.Text = DefenseFormula.ToString(); #endregion #region Damage Formula // FINAL DAMAGE = (((ATTACK - DEFENSE) * (ATTACKED AND DEFENDER SIZE COMPARISON)) + Additive Final Damage Bonuses) * Final Damage Multiplier Bonuses int DamageResult; if (DefenderBoosts.FinalDamageTakenFixedModifier > 0) { DamageResult = DefenderBoosts.FinalDamageTakenFixedModifier; } else { float Damage = Math.Max(0, (AttackFormula - DefenseFormula) * (1 + SizeCompare / 100f)); DamageResult = (int)Damage + AttackerBoosts.FinalDamageModifier; if (DefenderBoosts.ShieldModifier) { DamageResult = (int)(DamageResult * 0.4); } DamageResult = (int)(DamageResult * AttackerBoosts.FinalDamageMultiplier); } txtDamageFormula.Text = DamageResult.ToString(); #endregion #region Accuracy //(((Pilot Hit Stat/2 + 130) * Final Terrain Multiplier) + Weapon Hit Rate) + Base Hit Rate Effect int Accuracy = (int)(((((int)txtAttackerPilotHIT.Value / 2 + 130) * ((100 + FinalAttackerTerrainMultiplier) / 100.0)) + (int)txtWeaponAccuracy.Value + AttackerBoosts.AccuracyModifier) * AttackerBoosts.AccuracyMultiplier); txtAccuracyFormula.Text = Accuracy.ToString(); #endregion #region Evasion //((Pilot Evasion/2)+Robot Mobility) * Final Terrain Multiplier) + Base Evasion Effect int Evasion = (int)((int)(txtDefenderPilotEVA.Value / 2 + txtDefenderMobility.Value) * ((100 + FinalDefenderTerrainMultiplier) / 100.0)) + DefenderBoosts.EvasionModifier; txtEvasionFormula.Text = Evasion.ToString(); #endregion #region Hit Rate //(((Attacker Hit Rate + Defender Evasion) * Size Difference Multiplier) + Additive final hit rate effect) * Multiplying final hit rate effect int BaseHitRate; //If the Attacker have an accuracy modifier, use it. if (AttackerBoosts.AccuracyFixedModifier > 0) { BaseHitRate = AttackerBoosts.AccuracyFixedModifier; } //If the Defender have an accuracy modifier, use it. else if (DefenderBoosts.EvasionFixedModifier > 0) { BaseHitRate = 100 - DefenderBoosts.EvasionFixedModifier; } //Force the defender to dodge the attack. else if (DefenderBoosts.AutoDodgeModifier) { BaseHitRate = 0; } else//No particular modifier, use basic hit rate formula. { BaseHitRate = (int)((Accuracy - Evasion) * (1 + -SizeCompare / 100f)); } BaseHitRate = Math.Max(0, Math.Min(100, BaseHitRate)); txtHitRateForumla.Text = BaseHitRate.ToString(); #endregion }
protected override IList <GameEvent> ReceiveWeaponAttackEvent(GameEvent arg) { var result = new List <GameEvent>(); var evt = arg as WeaponAttackEvent ?? throw ReceiverArgumentMismatch(nameof(arg), arg.GetType(), MethodBase.GetCurrentMethod().Name, typeof(AttackEvent)); // Unit receives event if: // a) WeaponAttack is assigned to this Unit's Formation // b) Attack's percentile roll is within this Unit's PercentileRange if (evt.TargetingData.Target.FormationId == this.unitFormationInfo.FormationId && this.unitFormationInfo.CoversPercentile(evt.UnitAssignmentPercentile)) { var target = evt.TargetingData.Target.UnitActor.unitFormationInfo; GameFormation targetFormation = target.GetFormationReference(); GameUnit targetUnit = target.GetUnitReference(); GameFormation attackerFormation = this.unitFormationInfo.GetFormationReference(); GameUnit attackerUnit = this.unitFormationInfo.GetUnitReference(); int firingRange = evt.TargetingData.FormationRange; result.Add(new UnitStatusEvent() { Description = $"UnitStatus: [{this.UnitId}]{this.UnitName}", Message = $"[{targetFormation.FormationId}]{targetFormation.FormationName}:[{targetUnit.IdNumeric}]{targetUnit.Name}" + $" covers percentile range {this.unitFormationInfo.PercentileLowerBound}-{this.unitFormationInfo.PercentileUpperBound}," + $" so incoming attack with percentile roll {evt.UnitAssignmentPercentile} targets it.", Exchange = evt.Exchange, Volley = evt.Volley }); WeaponSystem weapon = evt.AttackData.Weapon; // TODO: Add ability to override this from AttackData and/or TargetingData? Constants.DamageType effectiveDamageType = weapon.GetDamageType(); int evasionDRM = -1 * targetFormation.GetOrdersForVolley(evt.Volley).EvasionSuccesses; int otherDRM = targetFormation.GetDRMVersusWeaponType(weapon.GetType()) + targetUnit.GetDRMVersusWeaponType(weapon.GetType()); var localScreens = targetUnit.GetLocalScreenRating(); var areaScreens = targetFormation.GetFormationAreaScreenRating(); ScreenRating totalScreenRating = ScreenRating.Combine(localScreens, areaScreens); DamageResult weaponAttackResult = this.ResolveWeaponAttack(weapon, firingRange, totalScreenRating, evasionDRM, otherDRM); var statusMsg = $"[{attackerUnit.IdNumeric}]{attackerUnit.Name} fires [{weapon.Id}]{weapon.SystemName} at [{targetUnit.IdNumeric}]{targetUnit.Name}" + $"\n\t\t -- Net modifiers: Range {firingRange}" + $", Screen {weapon.FinalizeScreenValue(totalScreenRating)}" + $", Evasion DRM {weapon.FinalizeEvasionDRM(evasionDRM)}" + $", Other DRM {otherDRM}" + $"\n\t\t -- Rolls {weaponAttackResult.RollString()}" + $"\n\t\t -- Deals {weaponAttackResult.ToString()}"; result.Add(new UnitStatusEvent() { Description = $"UnitStatus: [{this.UnitId}]{this.UnitName}", Message = statusMsg, Exchange = evt.Exchange, Volley = evt.Volley }); } return(result); }
public static object HandleDamageAgainstStructure(User attacker, BaseEntity entity, HitInfo hit) { Area area = Instance.Areas.GetByEntityPosition(entity); if (area == null) { Instance.PrintWarning("An entity was damaged in an unknown area. This shouldn't happen."); return(null); } DamageResult result = DetermineDamageResult(attacker, area, entity); if (EnableTestMode) { Instance.Log("Damage from a player to structure with prefab {0}: {1}", entity.ShortPrefabName, result.ToString()); } if (result == DamageResult.NotProtected || result == DamageResult.Friendly) { return(null); } if (result == DamageResult.Prevent) { return(false); } float reduction = area.GetDefensiveBonus(); if (reduction >= 1) { return(false); } if (reduction > 0) { hit.damageTypes.ScaleAll(reduction); } if (Instance.Options.Zones.Enabled) { BuildingPrivlidge cupboard = entity.GetBuildingPrivilege(); if (cupboard != null && IsRaidTriggeringEntity(entity)) { float remainingHealth = entity.Health() - hit.damageTypes.Total(); if (remainingHealth < 1) { Instance.Zones.CreateForRaid(cupboard); } } } return(null); }