public void OnEventDidTrigger(RuleAttackRoll evt) { if (did_swap) { ThrowAnything.toggleThrown(base.Owner.Body.PrimaryHand.Weapon, evt.Initiator); } did_swap = false; RuleAttackRoll.ParryData parry = evt.Parry; if (((parry != null) ? parry.Initiator : null) != base.Owner.Unit) { return; } if (!evt.Parry.IsTriggered) { return; } evt.Target.Descriptor.Resources.Spend(resource, cost); if (evt.Result == AttackResult.Parried && evt.Target.Descriptor.Resources.GetResourceAmount(resource) >= cost) { Game.Instance.CombatEngagementController.ForceAttackOfOpportunity(base.Owner.Unit, evt.Initiator); } //base.Owner.RemoveFact(base.Fact); Unsure what this does in context of original parry IFactContextOwner factContextOwner = base.Fact as IFactContextOwner; if (factContextOwner != null) { factContextOwner.RunActionInContext(CreateActionList(Create <ContextActionRemoveSelf>()), evt.Initiator); } }
static bool Prefix(RuleAttackRoll __instance, RulebookEventContext context) { FlankingParameters flankedParameters = new FlankingParameters(typeof(RuleAttackRoll_OnTrigger_Patch), __instance.Initiator); UnitCombatState_get_IsFlanked_Patch.PushFlankingParameters(flankedParameters); return(true); }
static void Postfix(ref bool __result, RuleAttackRoll __instance) { if (UnitEntityDataUtils.CheckUnitEntityData(__instance.Initiator, settings.allHitsCritical)) { __result = true; } }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { if (evt.Target.Descriptor == Descriptor) { evt.AddTemporaryModifier(evt.Initiator.Stats.AdditionalAttackBonus.AddModifier(_bonus, Source, (string)null, ModifierDescriptor.FavoredEnemy)); } }
public override IEnumerator <AbilityDeliveryTarget> Deliver(AbilityExecutionContext context, TargetWrapper target) { UnitEntityData caster = context.MaybeCaster; if (caster == null) { UberDebug.LogError("Caster is missing", Array.Empty <object>()); yield break; } RulebookEventContext rulebookContext = context.RulebookContext; RuleAttackWithWeapon attackWithWeapon = (rulebookContext != null) ? rulebookContext.AllEvents.LastOfType <RuleAttackWithWeapon>() : null; RuleAttackWithWeapon ruleAttackWithWeapon = attackWithWeapon; RuleAttackRoll attackRoll = (ruleAttackWithWeapon != null) ? ruleAttackWithWeapon.AttackRoll : null; attackRoll = (attackRoll ?? context.TriggerRule <RuleAttackRoll>(new RuleAttackRoll(caster, target.Unit, caster.GetFirstWeapon(), 0))); if (attackWithWeapon == null) { attackRoll.ConsumeMirrorImageIfNecessary(); } yield return(new AbilityDeliveryTarget(target) { AttackRoll = attackRoll }); yield break; }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { if (this.Owner.Wielder == null || evt.Weapon != this.Owner) { return; } evt.AttackType = AttackType.Touch; }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { if (evt.Target.Descriptor.Resources.GetResourceAmount(resource) < cost) { return; } if ((base.Owner.Body.PrimaryHand.Weapon.Blueprint.Category == WeaponCategory.Dagger || base.Owner.Body.PrimaryHand.Weapon.Blueprint.Category == WeaponCategory.Starknife) && base.Owner.Body.PrimaryHand.Weapon.Blueprint.IsRanged) { ThrowAnything.toggleThrown(base.Owner.Body.PrimaryHand.Weapon, evt.Initiator); did_swap = true; } if (!evt.Weapon.Blueprint.IsMelee || evt.Parry != null || !base.Owner.Unit.IsEnemy(evt.Initiator)) { return; } if (evt.Target != base.Owner.Unit) { return; } if (!base.Owner.Unit.IsReach(evt.Target, base.Owner.Body.PrimaryHand)) { return; } //TODO - Conditions? /* * if (this.AttackerCondition.HasConditions) * { * MechanicsContext maybeContext = base.Fact.MaybeContext; * using ((maybeContext != null) ? maybeContext.GetDataScope(evt.Initiator) : null) * { * if (!this.AttackerCondition.Check(null)) * { * return; * } * } * } */ evt.TryParry(base.Owner.Unit, base.Owner.Body.PrimaryHand.Weapon, 0); if (evt.Parry == null) { return; } ModifiableValue additionalAttackBonus = base.Owner.Stats.AdditionalAttackBonus; int num = evt.Initiator.Descriptor.State.Size - base.Owner.State.Size; if (num > 0) { int value = -2 * num; evt.AddTemporaryModifier(additionalAttackBonus.AddModifier(value, this, ModifierDescriptor.Penalty)); } }
public void OnEventDidTrigger(RuleAttackRoll evt) { if (!remove_after_attack) { return; } if (evt.Initiator == this.Fact.MaybeContext?.MaybeCaster) { this.Buff.Remove(); } }
static bool Prefix(RuleAttackRoll __instance, int value) { if (value > 0 && __instance.Target.IsPlayerFaction && Kineticist.hurricane_queen_feat != null && __instance.Target.Descriptor.Progression.Features.HasFact(Kineticist.hurricane_queen_feat)) { Harmony12.AccessTools.Property(typeof(RuleAttackRoll), "MissChance").SetValue(__instance, Math.Min(value, 100)); return(false); } return(true); }
public static Concealment Calculate([NotNull] UnitEntityData initiator, [NotNull] UnitEntityData target, bool attack = false) { UnitPartConcealment unitPartConcealment = initiator.Get <UnitPartConcealment>(); UnitPartOutgoingConcealment unitPartOutgoingConcealment = initiator.Get <UnitPartOutgoingConcealment>(); if (unitPartOutgoingConcealment?.m_Concealments == null) { return(Concealment.None); //no concelement update } bool has_true_seeing = initiator.Descriptor.State.HasCondition(UnitCondition.TrueSeeing); Concealment a = Concealment.None; var ignore_fog_concealement_part = initiator.Get <UnitPartIgnoreFogConcealement>(); foreach (UnitPartConcealment.ConcealmentEntry concealment in unitPartOutgoingConcealment.m_Concealments) { if (concealment.Descriptor == ConcealmentDescriptor.Fog && ignore_fog_concealement_part != null && ignore_fog_concealement_part.active()) { continue; } if (concealment.Descriptor != ConcealmentDescriptor.Fog && concealment.Descriptor != ConcealmentDescriptor.InitiatorIsBlind && has_true_seeing) { continue; } if (!concealment.OnlyForAttacks || attack) { if (concealment.DistanceGreater > 0.Feet()) { float num1 = initiator.DistanceTo(target); float num2 = initiator.View.Corpulence + target.View.Corpulence; if ((double)num1 <= (double)concealment.DistanceGreater.Meters + (double)num2) { continue; } } if (concealment.RangeType.HasValue) { RuleAttackRoll ruleAttackRoll = Rulebook.CurrentContext.LastEvent <RuleAttackRoll>(); ItemEntityWeapon itemEntityWeapon = ruleAttackRoll == null?initiator.GetFirstWeapon() : ruleAttackRoll.Weapon; if (itemEntityWeapon == null || !AttackTypeAttackBonus.CheckRangeType(itemEntityWeapon.Blueprint, concealment.RangeType.Value)) { continue; } } a = UnitPartOutgoingConcealment.Max(a, concealment.Concealment); } } return(a); }
static bool Prefix(OutflankProvokeAttack __instance, RuleAttackRoll evt) { if (!evt.IsCriticalConfirmed || !evt.Target.isFlankedByAttacker(__instance.Owner.Unit)) { return(false); } foreach (UnitEntityData attacker in evt.Target.CombatState.EngagedBy) { if ((((attacker.Descriptor.HasFact(__instance.OutflankFact) || (bool)__instance.Owner.State.Features.SoloTactics) && attacker != __instance.Owner.Unit)) && evt.Target.isFlankedByAttacker(attacker)) { Game.Instance.CombatEngagementController.ForceAttackOfOpportunity(attacker, evt.Target); } } return(false); }
//force to always calcualte ruleAttackBonus static bool Prefix(RuleAttackRoll __instance) { var tr = Harmony12.Traverse.Create(__instance); if (!__instance.WeaponStats.IsTriggererd) { Rulebook.Trigger <RuleCalculateWeaponStats>(__instance.WeaponStats); } tr.Property("ACRule").SetValue(Rulebook.Trigger <RuleCalculateAC>(new RuleCalculateAC(__instance.Initiator, __instance.Target, __instance.AttackType))); tr.Property("IsTargetFlatFooted").SetValue(__instance.ACRule.IsTargetFlatFooted); tr.Property("TargetAC").SetValue(__instance.ACRule.TargetAC); tr.Property("AttackBonusRule").SetValue(Rulebook.Trigger <RuleCalculateAttackBonus>(new RuleCalculateAttackBonus(__instance.Initiator, __instance.Target, __instance.Weapon, __instance.AttackBonusPenalty))); tr.Property("AttackBonus").SetValue(__instance.AttackBonusRule.Result); return(true); }
private void TryRunActions(RuleAttackRoll rule) { if (!this.CheckCondition(rule)) { return; } if (!this.ActionsOnInitiator) { using (new ContextAttackData(rule, (Projectile)null)) (this.Fact as IFactContextOwner)?.RunActionInContext(this.Action, (TargetWrapper)rule.Target); } else { using (new ContextAttackData(rule, (Projectile)null)) (this.Fact as IFactContextOwner)?.RunActionInContext(this.Action, (TargetWrapper)rule.Initiator); } }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { var unit_part_fe = this.Owner.Get <UnitPartFavoredEnemy>(); if (unit_part_fe == null) { return; } foreach (var fe in unit_part_fe.Entries) { if ((fe.CheckedFeatures).Any <BlueprintUnitFact>((Func <BlueprintUnitFact, bool>)(p => evt.Initiator.Descriptor.HasFact(p)))) { evt.AddTemporaryModifier(evt.Target.Stats.AC.AddModifier(this.value.Calculate(this.Fact.MaybeContext) * this.Fact.GetRank(), (GameLogicComponent)this, this.descriptor)); break; } } }
internal static void OutflankProvokeAttackPatch(RuleAttackRoll attackRollInstance, RulebookEventContext context) { if (!attackRollInstance.IsCriticalConfirmed) { return; } var outflankFeature = library.Get <BlueprintFeature>("422dab7309e1ad343935f33a4d6e9f11"); Func <UnitEntityData, UnitEntityData, UnitEntityData, bool> outflankParticipantConditions = (target, aooTestUnit, attacker) => aooTestUnit.Descriptor.State.Features.SoloTactics || aooTestUnit.Descriptor.HasFact(outflankFeature) && attacker.Descriptor.HasFact(outflankFeature); foreach (UnitEntityData aooTestUnit in attackRollInstance.Target.CombatState.EngagedBy) { if (attackRollInstance.Target.IsFlankedByUnits(aooTestUnit, attackRollInstance.Initiator, outflankParticipantConditions)) { Main.Logger?.Write("Outflank provoked AoO"); Game.Instance.CombatEngagementController.ForceAttackOfOpportunity(aooTestUnit, attackRollInstance.Target); } } }
private bool CheckCondition(RuleAttackRoll evt) { Main.logger.Log(evt.Weapon.Blueprint.name); ItemEntity owner = (this.Fact as ItemEnchantment)?.Owner; if (owner != null && owner != evt.Weapon || (this.WeaponType != null && this.WeaponType != evt.Weapon.Blueprint.Type || this.CheckWeaponCategory && this.Category != evt.Weapon.Blueprint.Category) || (this.CheckWeaponRangeType && !AttackTypeAttackBonus.CheckRangeType(evt.Weapon.Blueprint, this.RangeType)) || this.AllNaturalAndUnarmed && !evt.Weapon.Blueprint.Type.IsNatural && !evt.Weapon.Blueprint.Type.IsUnarmed) { return(false); } if (this.CheckDistance && (double)evt.Target.DistanceTo(evt.Initiator) > (double)this.DistanceLessEqual.Meters) { return(false); } bool flag = evt.Weapon.Blueprint.Category.HasSubCategory(WeaponSubCategory.Light) || evt.Weapon.Blueprint.Category.HasSubCategory(WeaponSubCategory.OneHandedPiercing) || (bool)evt.Initiator.Descriptor.State.Features.DuelingMastery && evt.Weapon.Blueprint.Category == WeaponCategory.DuelingSword || evt.Initiator.Descriptor.Ensure <DamageGracePart>().HasEntry(evt.Weapon.Blueprint.Category); return(!this.DuelistWeapon || flag); }
internal static bool ignoreMirrorImage(UnitEntityData initiator, RuleAttackRoll rule_attack_roll) { var target = rule_attack_roll.Target; if (initiator.Descriptor.IsImmuneToVisualEffects) { return(true); } var unit_part_concealement = initiator.Get <UnitPartConcealment>(); if (unit_part_concealement == null) { return(false); } List <Feet> m_BlindsightRanges = Harmony12.Traverse.Create(unit_part_concealement).Field("m_BlindsightRanges").GetValue <List <Feet> >(); if (m_BlindsightRanges != null) { Feet feet = 0.Feet(); foreach (Feet blindsightRange in m_BlindsightRanges) { if (feet < blindsightRange) { feet = blindsightRange; } } float num = initiator.View.Corpulence + target.View.Corpulence; if ((double)initiator.DistanceTo(target) - (double)num <= (double)feet.Meters) { return(true); } } return(false); }
public static bool Prefix(UnitEntityData initiator, UnitEntityData target, bool attack, ref Concealment __result) { UnitPartConcealment unitPartConcealment1 = initiator.Get <UnitPartConcealment>(); UnitPartConcealment unitPartConcealment2 = target.Get <UnitPartConcealment>(); bool has_true_seeing = initiator.Descriptor.State.HasCondition(UnitCondition.TrueSeeing); if (unitPartConcealment1 != null && unitPartConcealment1.IgnoreAll) { __result = Concealment.None; return(false); } List <Feet> m_BlindsightRanges = Harmony12.Traverse.Create(unitPartConcealment1).Field("m_BlindsightRanges").GetValue <List <Feet> >(); if (m_BlindsightRanges != null) { Feet feet = 0.Feet(); foreach (Feet blindsightRange in m_BlindsightRanges) { if (feet < blindsightRange) { feet = blindsightRange; } } float num = initiator.View.Corpulence + target.View.Corpulence; if ((double)initiator.DistanceTo(target) - (double)num <= (double)feet.Meters) { __result = Concealment.None; return(false); } } Concealment a = Concealment.None; if (!initiator.Descriptor.IsSeeInvisibility && target.Descriptor.State.HasCondition(UnitCondition.Invisible)) { a = Concealment.Total; } var ignore_fog_concealement_part = initiator.Get <UnitPartIgnoreFogConcealement>(); List <UnitPartConcealment.ConcealmentEntry> m_Concealments = Harmony12.Traverse.Create(unitPartConcealment2).Field("m_Concealments").GetValue <List <UnitPartConcealment.ConcealmentEntry> >(); var all_concealements = m_Concealments?.ToArray() ?? new UnitPartConcealment.ConcealmentEntry[0]; var specific_concealment_part = target.Get <UnitPartISpecificConcealment>(); if (specific_concealment_part != null) { all_concealements = all_concealements.AddToArray(specific_concealment_part.GetConcealments(initiator)); } if (a < Concealment.Total && !all_concealements.Empty()) { foreach (UnitPartConcealment.ConcealmentEntry concealment in all_concealements) { if (concealment.Descriptor == ConcealmentDescriptor.Fog && ignore_fog_concealement_part != null && ignore_fog_concealement_part.active()) { continue; } if (concealment.Descriptor != ConcealmentDescriptor.Fog && concealment.Descriptor != ConcealmentDescriptor.InitiatorIsBlind && has_true_seeing) { continue; } if (!concealment.OnlyForAttacks || attack) { if (concealment.DistanceGreater > 0.Feet()) { float num1 = initiator.DistanceTo(target); float num2 = initiator.View.Corpulence + target.View.Corpulence; if ((double)num1 <= (double)concealment.DistanceGreater.Meters + (double)num2) { continue; } } if (concealment.RangeType.HasValue) { RuleAttackRoll ruleAttackRoll = Rulebook.CurrentContext.LastEvent <RuleAttackRoll>(); ItemEntityWeapon itemEntityWeapon = ruleAttackRoll == null?initiator.GetFirstWeapon() : ruleAttackRoll.Weapon; if (itemEntityWeapon == null || !AttackTypeAttackBonus.CheckRangeType(itemEntityWeapon.Blueprint, concealment.RangeType.Value)) { continue; } } a = a > concealment.Concealment ? a : concealment.Concealment; } } } if (unitPartConcealment2 != null && unitPartConcealment2.Disable) { a = Concealment.None; } if (initiator.Descriptor.State.HasCondition(UnitCondition.Blindness)) { a = Concealment.Total; } if (initiator.Descriptor.State.HasCondition(UnitCondition.PartialConcealmentOnAttacks)) { a = Concealment.Partial; } if (a == Concealment.None && (ignore_fog_concealement_part == null || !ignore_fog_concealement_part.active()) && Game.Instance.Player.Weather.ActualWeather >= BlueprintRoot.Instance.WeatherSettings.ConcealmentBeginsOn) { RuleAttackRoll ruleAttackRoll = Rulebook.CurrentContext.LastEvent <RuleAttackRoll>(); ItemEntityWeapon itemEntityWeapon = ruleAttackRoll == null?initiator.GetFirstWeapon() : ruleAttackRoll.Weapon; if (itemEntityWeapon != null && AttackTypeAttackBonus.CheckRangeType(itemEntityWeapon.Blueprint, AttackTypeAttackBonus.WeaponRangeType.Ranged)) { a = Concealment.Partial; } } a = UnitPartOutgoingConcealment.Max(UnitPartOutgoingConcealment.Calculate(initiator, target, attack), a); if (unitPartConcealment1 != null && unitPartConcealment1.IgnorePartial && a == Concealment.Partial) { a = Concealment.None; } if (unitPartConcealment1 != null && unitPartConcealment1.TreatTotalAsPartial && a == Concealment.Total) { a = Concealment.Partial; } __result = a; return(false); }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { evt.AutoMiss = true; }
static bool Prefix(OutflankProvokeAttack __instance, RuleAttackRoll evt) { return(false); }
static void Postfix(RuleAttackRoll __instance, RulebookEventContext context) { OutflankPatch.OutflankProvokeAttackPatch(__instance, context); }
static void Postfix(ProjectileController __instance, UnitEntityData launcher, TargetWrapper target, BlueprintProjectile projectileBlueprint, RuleAttackRoll attackRoll, RulebookEvent ruleOnHit, Projectile __result) { if (projectileBlueprint == thrown_weapon_proj) { var weapon = attackRoll.Weapon; GameObject gameObject = UnityEngine.Object.Instantiate <GameObject>(weapon.Blueprint.VisualParameters.Model, __result.View.transform); gameObject.transform.localPosition = Vector3.zero; gameObject.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); gameObject.transform.localScale = Vector3.one; __result.MaxRange = weapon.AttackRange.Meters; } }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { evt.AttackType = AttackType.Touch; }
public void OnEventDidTrigger(RuleAttackRoll evt) { }
static void Postfix(RuleAttackRoll __instance, RulebookEventContext context) { UnitCombatState_get_IsFlanked_Patch.PopFlankingParametersIfTypeMatches(typeof(RuleAttackRoll_OnTrigger_Patch)); }
public static Concealment Calculate([NotNull] UnitEntityData initiator, [NotNull] UnitEntityData target, bool attack = false) { UnitPartConcealment unitPartConcealment = initiator.Get <UnitPartConcealment>(); UnitPartOutgoingConcealment unitPartOutgoingConcealment = initiator.Get <UnitPartOutgoingConcealment>(); if (unitPartOutgoingConcealment?.m_Concealments == null) { return(Concealment.None); //no concelement update } if (unitPartConcealment != null) { List <Feet> m_BlindsightRanges = Harmony12.Traverse.Create(unitPartConcealment).Field("m_BlindsightRanges").GetValue <List <Feet> >(); if (m_BlindsightRanges != null) { Feet feet = 0.Feet(); foreach (Feet blindsightRange in m_BlindsightRanges) { if (feet < blindsightRange) { feet = blindsightRange; } } float num = initiator.View.Corpulence + target.View.Corpulence; if ((double)initiator.DistanceTo(target) - (double)num <= (double)feet.Meters) { return(Concealment.None); } } } Concealment a = Concealment.None; foreach (UnitPartConcealment.ConcealmentEntry concealment in unitPartOutgoingConcealment.m_Concealments) { if (!concealment.OnlyForAttacks || attack) { if (concealment.DistanceGreater > 0.Feet()) { float num1 = initiator.DistanceTo(target); float num2 = initiator.View.Corpulence + target.View.Corpulence; if ((double)num1 <= (double)concealment.DistanceGreater.Meters + (double)num2) { continue; } } if (concealment.RangeType.HasValue) { RuleAttackRoll ruleAttackRoll = Rulebook.CurrentContext.LastEvent <RuleAttackRoll>(); ItemEntityWeapon itemEntityWeapon = ruleAttackRoll == null?initiator.GetFirstWeapon() : ruleAttackRoll.Weapon; if (itemEntityWeapon == null || !AttackTypeAttackBonus.CheckRangeType(itemEntityWeapon.Blueprint, concealment.RangeType.Value)) { continue; } } a = UnitPartOutgoingConcealment.Max(a, concealment.Concealment); } } return(a); }
public override void RunAction() { //Main.DebugLog($"[ActionDealDamage2] Target:{Target?.Unit?.CharacterName} AC:{Target?.Unit?.Stats?.AC?.ModifiedValue} Flat-AC:{Target?.Unit?.Stats?.AC?.FlatFooted} Touch-AC:{Target?.Unit?.Stats?.AC?.Touch} Caster:{Context?.MaybeCaster?.CharacterName}"); //Main.DebugLog("Context[0] " + this.Context[AbilityRankType.Default].ToString()); //AbilityRankType.DamageDice [1] //AbilitySharedValue.Damage [0] //AbilitySharedValue.Duration [2] only composite //for (int i = 0; i < 7; i++) //{ // Main.DebugLog("AbilitySharedValue:" + Context[(AbilitySharedValue)i].ToString()); //} //for (int i = 0; i < 7; i++) //{ // Main.DebugLog("AbilityRankType:" + Context[(AbilityRankType)i].ToString()); //} if (this.Target.Unit == null) { UberDebug.LogError(this, "Invalid target for effect '{0}'", this.GetType().Name); } else if (this.Context.MaybeCaster == null) { UberDebug.LogError(this, "Invalid caster for effect '{0}'", this.GetType().Name); } else { bool saveSuccess = this.Context.SavingThrow != null && (this.Context.SavingThrow.IsPassed || this.Context.SavingThrow.ImprovedEvasion) && this.HalfIfSaved; if (saveSuccess && this.Context.SavingThrow.Evasion && this.Context.SavingThrow.IsPassed) { EventBus.RaiseEvent <IUnitEvasionHandler>(h => h.HandleEffectEvaded(this.Target.Unit, this.Context)); } else { RuleAttackRoll attackRoll; if (WeaponOverride != null) { attackRoll = new RuleAttackRoll(Context.MaybeCaster, this.Target.Unit, WeaponOverride, 0); if (this.Context[AbilitySharedValue.Heal] == 0) // if this is the first attack this context { this.Context.TriggerRule(attackRoll); this.Context[AbilitySharedValue.Heal] = attackRoll.Roll; // save this for other targets } else { //attackRoll.ImmuneToCriticalHit = true; // only the first target may get a crit attackRoll.SuspendCombatLog = true; // don't print, since the roll would be different this.Context.TriggerRule(attackRoll); } int d20 = this.Context[AbilitySharedValue.Heal]; // result of attack roll Main.DebugLog($"Attack:{d20} total:{d20 + attackRoll.AttackBonus} AC:{attackRoll.TargetAC} result:{attackRoll.Result.ToString()}"); if (attackRoll.Result == AttackResult.MirrorImage) { // battlelog notification that Mirror Image was hit? attackRoll.ConsumeMirrorImageIfNecessary(); return; } if (!this.IsSuccessRoll(d20, attackRoll.AttackBonus, attackRoll.TargetAC)) { return; } if (attackRoll.Result == AttackResult.Concealment) { // battlelog notification that concealment prevented hit Kingmaker.Game.Instance.UI.BattleLogManager.LogView.AddLogEntry(attackRoll.AttackLogEntry); return; } } else { attackRoll = ElementsContext.GetData <ContextAttackData>()?.AttackRoll; } ContextActionDealDamage2.DamageInfo info = new ContextActionDealDamage2.DamageInfo() { Dices = new DiceFormula(this.Value.DiceCountValue.Calculate(this.Context), this.Value.DiceType), Bonus = this.Value.BonusValue.Calculate(this.Context), PreRolledValue = !this.ReadPreRolledFromSharedValue ? new int?() : new int?(this.Context[this.PreRolledSharedValue]), HalfBecauseSavingThrow = saveSuccess, Empower = this.Context.HasMetamagic(Metamagic.Empower), Maximize = this.Context.HasMetamagic(Metamagic.Maximize), CriticalModifier = this.IgnoreCritical || attackRoll == null || !attackRoll.IsCriticalConfirmed ? new DamageCriticalModifierType?() : new DamageCriticalModifierType?(this.AbilityContext == null ? attackRoll.Weapon.Blueprint.CriticalModifier : DamageCriticalModifierType.X2) }; int num; switch (this.M_Type) { case ContextActionDealDamage2.Type.Damage: num = this.DealHitPointsDamage(info); break; case ContextActionDealDamage2.Type.AbilityDamage: num = this.DealAbilityScoreDamage(info); break; case ContextActionDealDamage2.Type.EnergyDrain: num = this.DrainEnergy(info); break; default: throw new ArgumentOutOfRangeException(); } if (this.WriteResultToSharedValue) { this.Context[this.ResultSharedValue] = num; } if (!this.WriteCriticalToSharedValue || attackRoll == null || !attackRoll.IsCriticalConfirmed) { return; } this.Context[this.CriticalSharedValue] = 1; } } }
public override void RunAction() { UnitEntityData maybeCaster = this.Context.MaybeCaster; if (maybeCaster == null) { UberDebug.LogError((object)"Caster is missing", (object[])Array.Empty <object>()); } else { var target = this.Target; if (target == null) { return; } var weapon = maybeCaster.Body.PrimaryHand.MaybeWeapon; RuleAttackRoll attackWithWeapon = new RuleAttackRoll(maybeCaster, target.Unit, weapon, 0); attackWithWeapon.Reason = (RuleReason)this.Context; attackWithWeapon.AttackType = AttackType.RangedTouch; RuleAttackRoll rule = attackWithWeapon; this.Context.TriggerRule <RuleAttackRoll>(rule); RuleCalculateWeaponStats weaponRule = new RuleCalculateWeaponStats(maybeCaster, weapon, (RuleAttackWithWeapon)null); this.Context.TriggerRule <RuleCalculateWeaponStats>(weaponRule); DamageBundle damage = (DamageBundle)null; foreach (DamageDescription damageDescription in weaponRule.DamageDescription) { damageDescription.TypeDescription = new DamageTypeDescription() { Type = DamageType.Energy, Energy = this.damageType }; if (damage == null) { damage = new DamageBundle(weapon, weaponRule.WeaponSize, damageDescription.CreateDamage()); } else { damage.Add(damageDescription.CreateDamage()); } } if (rule.IsHit) { action_on_success?.Run(); if (this.damageType == DamageEnergyType.PositiveEnergy) { if (target.Unit.Descriptor.HasFact(library.Get <BlueprintUnitFact>("734a29b693e9ec346ba2951b27987e33"))) { this.Context.TriggerRule <RuleDealDamage>(new RuleDealDamage(this.Context.MaybeCaster, this.Target.Unit, damage)); } else { foreach (var i in damage) { this.Context.TriggerRule <RuleHealDamage>(new RuleHealDamage(this.Context.MaybeCaster, this.Target.Unit, i.Dice, i.Bonus)); } } } else { if (target.Unit.Descriptor.HasFact(library.Get <BlueprintUnitFact>("734a29b693e9ec346ba2951b27987e33"))) { foreach (var i in damage) { this.Context.TriggerRule <RuleHealDamage>(new RuleHealDamage(this.Context.MaybeCaster, this.Target.Unit, i.Dice, i.Bonus)); } } else { this.Context.TriggerRule <RuleDealDamage>(new RuleDealDamage(this.Context.MaybeCaster, this.Target.Unit, damage)); } } } else { action_on_miss?.Run(); } } }
public void OnEventAboutToTrigger(RuleAttackRoll evt) { }
static void RunTest(string name, UnitEntityData initiator, UnitEntityData target) { var weapon = initiator.GetFirstWeapon(); var rolls = new ushort[NumberOfTests]; var resultBuckets = new uint[Enum.GetNames(typeof(AttackResult)).Length]; var weaponStats = new RuleCalculateWeaponStats(initiator, weapon, null); Rulebook.Trigger(weaponStats); using (var sw = new StreamWriter($"{ModEntry.Path}/{name}_rolls.txt")) { for (int i = 0; i < NumberOfTests; i++) { var rule = new RuleAttackRoll(initiator, target, weaponStats, 0); rule.SuspendCombatLog = true; var roll = Rulebook.Trigger(rule); if (roll.Roll.Value > 20 || roll.Roll.Value < 1) { Error("Roll out of range"); return; } rolls[i] = (ushort)roll.Roll.Value; resultBuckets[(int)roll.Result] += 1; sw.WriteLine("Roll: {0} Result: {1}", roll.Roll.Value, roll.Result); } } var buckets = new ulong[20]; ulong sum = 0; var max1Seq = new SequenceCounter(SequenceType.LessThen, 2); var max20Seq = new SequenceCounter(SequenceType.GreaterThen, 19); var maxHighSeq = new SequenceCounter(SequenceType.GreaterThen, 13); var maxLowSeq = new SequenceCounter(SequenceType.LessThen, 8); foreach (var roll in rolls) { buckets[roll - 1] += 1; var prevSum = sum; sum += roll; if (sum < prevSum) { Error("Overflow while calculating sum"); break; } max1Seq.Add(roll); max20Seq.Add(roll); maxHighSeq.Add(roll); maxLowSeq.Add(roll); } var maxBucket = buckets.Max(); var minBucket = buckets.Min(); var bucketDifference = maxBucket - minBucket; var average = sum / (double)NumberOfTests; using (var sw = new StreamWriter($"{ModEntry.Path}/{name}_summary.txt")) { sw.WriteLine("Initiator: {0}", initiator.CharacterName); sw.WriteLine("Target: {0}", target.CharacterName); sw.WriteLine("Weapon: {0}", weapon.Name); sw.WriteLine("Number of rolls: {0}", NumberOfTests); sw.WriteLine("Sum: {0}", sum); sw.WriteLine("Average: {0}", average); for (int i = 0; i < 20; i++) { sw.WriteLine("Number of {0}: {1}", i + 1, buckets[i]); } sw.WriteLine("Highest count in set {0}", maxBucket); sw.WriteLine("Lowest count in set {0}", minBucket); sw.WriteLine("Difference {0}", bucketDifference); sw.WriteLine("Max 1 in a row: {0}", max1Seq.MaxLength); sw.WriteLine("Max 20 in a row: {0}", max20Seq.MaxLength); sw.WriteLine("Max > 13 in a row: {0}", maxHighSeq.MaxLength); sw.WriteLine("Max < 8 in a row: {0}", maxLowSeq.MaxLength); var resultNames = Enum.GetNames(typeof(AttackResult)); for (int i = 0; i < resultNames.Length; i++) { sw.WriteLine("{0} count: {1} ({2}%)", resultNames[i], resultBuckets[i], resultBuckets[i] / (float)NumberOfTests * 100f); } var rule = new RuleAttackRoll(initiator, target, weaponStats, 0); rule.SuspendCombatLog = true; var roll = Rulebook.Trigger(rule); sw.WriteLine("AttackBonus: {0}", roll.AttackBonus); sw.WriteLine("IsTargetFlatFooted: {0}", roll.IsTargetFlatFooted); sw.WriteLine("TargetAC: {0}", roll.TargetAC); sw.WriteLine("IsSneakAttack: {0}", roll.IsSneakAttack); sw.WriteLine("Target.IsFlanked: {0}", roll.Target.CombatState.IsFlanked); sw.WriteLine("Weapon.CriticalEdge: {0}", roll.WeaponStats.CriticalEdge); sw.WriteLine("ImmuneToCriticalHit: {0}", roll.ImmuneToCriticalHit); sw.WriteLine("ImmuneToSneakAttack: {0}", roll.ImmuneToSneakAttack); sw.WriteLine("TargetUseFortification: {0}", roll.TargetUseFortification); } var imageSize = (int)Math.Sqrt(NumberOfTests); if (imageSize > 2800) { imageSize = 2800; } if (imageSize > 0 && imageSize <= 2800) { var texture = new Texture2D(imageSize, imageSize); int pixelIndex = 0; for (int y = 0; y < texture.height; y++) { for (int x = 0; x < texture.width; x++) { texture.SetPixel(x, y, rolls[pixelIndex++] > 10 ? Color.white : Color.black); } } var data = texture.EncodeToPNG(); File.WriteAllBytes($"{ModEntry.Path}/{name}_image.png", data); } }