public static bool TriggerAttackReplacementCombatManeuver(this UnitEntityData initiator, UnitEntityData target, ItemEntityWeapon weapon, int attackBonusPenalty, CombatManeuver combatManeuver) { var combatManeuverRule = new RuleCombatManeuver(initiator, target, combatManeuver); combatManeuverRule.ReplaceAttackBonus = new int?(initiator.Stats.BaseAttackBonus + attackBonusPenalty); BlueprintAbility combatManeuverAbility = Main.Library.Get <BlueprintAbility>(CombatManeuverData.combatManeuverActionIds[combatManeuver]); var abilityData = new Kingmaker.UnitLogic.Abilities.AbilityData(combatManeuverAbility, initiator.Descriptor); var context = abilityData.CreateExecutionContext(target); Game.Instance.UI.BattleLogManager.HandleUseAbility(abilityData, null); var combatTextManager = initiator.GetCombatTextManager(); if (combatTextManager != null) { /*MethodInfo settingsForbidsMethod = combatTextManager.GetType().GetMethod("SettingForbids", BindingFlags.NonPublic | BindingFlags.Instance); * bool forbids = (bool)settingsForbidsMethod.Invoke(combatTextManager, new object[] { SettingsRoot.Instance.ShowSpellNameInCombatText }); * if (!forbids) * combatTextManager.AddCombatText(combatManeuverAbility.Name, combatTextManager.DefaultColor, true, combatManeuverAbility.Icon);*/ var mockSpellRule = new RuleCastSpell(abilityData, target); combatTextManager.OnEventDidTrigger(mockSpellRule); } return(context.TriggerRule(combatManeuverRule).Success); }
static void Postfix(RuleCombatManeuver __instance, ref bool __result) { if (__instance.AutoFailure || //already includes immunity to specific maneuvers __instance.Target.Descriptor.State.HasCondition(UnitCondition.ImmuneToCombatManeuvers) || (__instance.Target.Descriptor.State.HasConditionImmunity(UnitCondition.Prone) && (__instance.Type == CombatManeuver.Trip || __instance.Type == CombatManeuverTypeExtender.AwesomeBlow.ToCombatManeuverType()) ) ) { //TODO: should probably add checks for validity of other maneuvers but currently it is only used in greater trip, greater bull rush, so it looks sufficient __result = false; } }
static bool Prefix(RuleCombatManeuver __instance, RulebookEventContext context) { bool provokeAoO; if (!provokeAoOOnCombatManeuverAttempt.TryGetValue(__instance.Initiator.UniqueId, out provokeAoO) || provokeAoO) { if (!__instance.Target.CombatState.IsEngage(__instance.Initiator)) { return(true); } __instance.Target.CombatState.AttackOfOpportunity(__instance.Initiator); } return(true); }
static bool checkExtraManeuvers(RuleCombatManeuver evt) { switch (evt.Type) { case (CombatManeuver)CombatManeuverTypeExtender.AwesomeBlow: { if (evt.Target.CanBeKnockedOff()) { evt.Target.Descriptor.State.Prone.ShouldBeActive = true; EventBus.RaiseEvent <IKnockOffHandler>((Action <IKnockOffHandler>)(h => h.HandleKnockOff(evt.Initiator, evt.Target))); } } break; default: throw new Exception("Unsupported combat maneuver type: " + (object)evt.Type); } return(true); }
internal static bool CheckTandemTrip(ModifyD20 modifyD20Instance, RuleCombatManeuver evt) { if (evt.Type != CombatManeuver.Trip || !modifyD20Instance.Owner.Unit.IsEngage(evt.Target)) { return(false); } if (modifyD20Instance.Owner.State.Features.SoloTactics) { return(true); } foreach (UnitEntityData unitEntityData in evt.Target.CombatState.EngagedBy) { if (unitEntityData != modifyD20Instance.Owner.Unit && unitEntityData.Descriptor.HasFact(modifyD20Instance.TandemTripFeature)) { return(true); } } return(false); }
public override void OnEventDidTrigger(RuleAttackWithWeapon evt) { if (evt.Weapon == null) { return; } if (use_swift_action && evt.Initiator.CombatState.Cooldown.SwiftAction > 0.0f) { return; } if (!categories.Empty() && !categories.Contains(evt.Weapon.Blueprint.Category)) { return; } if (!evt.AttackRoll.IsHit) { return; } if (this.maneuver == CombatManeuver.Trip && (evt.Target.Descriptor.State.Prone.Active || (bool)(evt.Target.View) && evt.Target.View.IsGetUp)) { return; } var rule = new RuleCombatManeuver(this.Owner.Unit, evt.Target, this.maneuver); rule.AddBonus(this.bonus.Calculate(this.Fact.MaybeContext), this.Fact); Rulebook.Trigger <RuleCombatManeuver>(new RuleCombatManeuver(this.Owner.Unit, evt.Target, this.maneuver)); if (use_swift_action) { evt.Initiator.CombatState.Cooldown.SwiftAction = 6.0f; } }
static void Postfix(RuleCombatManeuver __instance, RulebookEventContext context) { provokeAoOOnCombatManeuverAttempt[__instance.Initiator.UniqueId] = true; }
static bool Prefix(ModifyD20 __instance, RuleCombatManeuver evt, ref bool __result) { __result = TandemTrip.CheckTandemTrip(__instance, evt); return(false); }
public override bool maybeReplaceAttackWithAction(RuleAttackWithWeapon attack_rule) { //Main.logger.Log("Checking for replacement with: " + maneuver.ToString() ); if (!attack_rule.IsFullAttack && only_full_attack) { return(false); } if (!attack_rule.IsCharge && only_charge) { return(false); } if (attack_rule.AttackNumber != 0 && only_first_attack) { return(false); } if (!attack_rule.Weapon.Blueprint.IsMelee) { return(false); } //Main.logger.Log("First Conditions Ok"); if (maneuver == CombatManeuver.Trip) { UnitState state = attack_rule.Target.Descriptor.State; // same checks as in UnitProneController, if this is true (and the unit is not in a cutscene), state.Prone.Active will be true on the next tick and we also don't want to trip again. if (state.Prone.Active || state.Prone.ShouldBeActive || !state.IsConscious || state.HasCondition(UnitCondition.Prone) || state.HasCondition(UnitCondition.Sleeping) || state.HasCondition(UnitCondition.Unconscious)) { return(false); } } else if (maneuver == CombatManeuver.Disarm) { // same checks as in RuleCombatManeuver. If the unit cannot be disarmed (further), don't attempt to disarm. ItemEntityWeapon maybe_weapon = attack_rule.Target.Body.PrimaryHand.MaybeWeapon; ItemEntityWeapon maybe_weapon2 = attack_rule.Target.Body.SecondaryHand.MaybeWeapon; bool can_disarm = false; if (maybe_weapon != null && !maybe_weapon.Blueprint.IsUnarmed && !maybe_weapon.Blueprint.IsNatural && !attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DisarmMainHandBuff)) { can_disarm = true; } else if (maybe_weapon2 != null && !maybe_weapon2.Blueprint.IsUnarmed && !maybe_weapon2.Blueprint.IsNatural && !attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DisarmOffHandBuff)) { can_disarm = true; } if (!can_disarm) { return(false); } } else if (maneuver == CombatManeuver.SunderArmor) { if (attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.SunderArmorBuff)) { return(false); } } else if (maneuver == CombatManeuver.DirtyTrickBlind) { if (attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DirtyTrickBlindnessBuff)) { return(false); } } else if (maneuver == CombatManeuver.DirtyTrickEntangle) { if (attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DirtyTrickEntangledBuff)) { return(false); } } else if (maneuver == CombatManeuver.DirtyTrickSickened) { if (attack_rule.Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DirtyTrickSickenedBuff)) { return(false); } } else if (maneuver == CombatManeuver.BullRush) { //no checks should always work ? } else { Main.logger.Log("Trying to replace attack with unsupported maneuver type: " + maneuver.ToString()); return(false); } //Main.logger.Log("Second Conditions Ok"); attack_rule.Initiator.Ensure <CombatManeuverBonus.UnitPartUseWeaponForCombatManeuver>().force(attack_rule.Weapon, attack_rule.AttackBonusPenalty); RuleCombatManeuver rule = new RuleCombatManeuver(this.Context.MaybeCaster, attack_rule.Target, maneuver); var result = Rulebook.CurrentContext.Trigger <RuleCombatManeuver>(rule); attack_rule.Initiator.Ensure <CombatManeuverBonus.UnitPartUseWeaponForCombatManeuver>().unForce(); //Main.logger.Log("Maneuver Ok"); Harmony12.Traverse.Create(attack_rule).Property("AttackRoll").SetValue(new RuleAttackRoll(attack_rule.Initiator, attack_rule.Target, attack_rule.Weapon, attack_rule.AttackBonusPenalty)); Harmony12.Traverse.Create(attack_rule).Property("AttackRoll").Property("Result").SetValue(result.Success ? AttackResult.Hit : AttackResult.Miss); Harmony12.Traverse.Create(attack_rule).Property("AttackRoll").Property("Roll").SetValue(result.InitiatorRoll); Harmony12.Traverse.Create(attack_rule).Property("AttackRoll").Property("AttackBonus").SetValue(result.InitiatorCMB); Harmony12.Traverse.Create(attack_rule).Property("AttackRoll").Property("TargetAC").SetValue(result.TargetCMD); //Main.logger.Log("Attack Rule Updated"); return(true); }