static bool Prefix(UnitCombatState __instance, UnitEntityData target, ref bool __result) { __result = false; if (__instance.PreventAttacksOfOpporunityNextFrame || target.CombatState.PreventAttacksOfOpporunityNextFrame || !__instance.CanActInCombat && !__instance.Unit.Descriptor.State.HasCondition(UnitCondition.AttackOfOpportunityBeforeInitiative) || (!__instance.CanAttackOfOpportunity || !__instance.Unit.Descriptor.State.CanAct)) { return(false); } UnitPartForceMove unitPartForceMove = target.Get <UnitPartForceMove>(); if (unitPartForceMove && !unitPartForceMove.ProvokeAttackOfOpportunity || (UnitCommand.CommandTargetUntargetable(__instance.Unit, target, null) || __instance.Unit.HasMotionThisTick) || (__instance.Unit.GetThreatHand() == null || __instance.AttackOfOpportunityCount <= 0 || (!target.Memory.Contains(__instance.Unit) || target.Descriptor.State.HasCondition(UnitCondition.ImmuneToAttackOfOpportunity)))) { return(false); } if (target.Descriptor.State.HasCondition(UnitCondition.UseMobilityToNegateAttackOfOpportunity)) { RuleCalculateCMD ruleCalculateCmd = Rulebook.Trigger(new RuleCalculateCMD(target, __instance.Unit, CombatManeuver.None)); if (Rulebook.Trigger(new RuleSkillCheck(target, StatType.SkillMobility, ruleCalculateCmd.Result)).IsPassed) { return(false); } } // Changed code: instantly trigger AoO check (from UnitAttackOfOpportunity.OnAction) // === Original Start === // __instance.Unit.Commands.Run((UnitCommand) new UnitAttackOfOpportunity(target)); // EventBus.RaiseEvent<IAttackOfOpportunityHandler>((Action<IAttackOfOpportunityHandler>)(h => h.HandleAttackOfOpportunity(__instance.Unit, target))); // === Original End === // === Changed Start === RuleAttackWithWeapon aoo = new RuleAttackWithWeapon(__instance.Unit, target, __instance.Unit.GetThreatHand().Weapon, 0) { IsAttackOfOpportunity = true }; var combatManeuver = Rulebook.Trigger(new RuleCheckCombatManeuverReplaceAttack(__instance.Unit, target, __instance.Unit.GetThreatHand().Weapon.Blueprint)).Result; if (!target.Descriptor.State.IsDead) { EventBus.RaiseEvent <IAttackOfOpportunityHandler>(h => h.HandleAttackOfOpportunity(__instance.Unit, target)); if (combatManeuver != CombatManeuver.None) { __instance.Unit.TriggerAttackReplacementCombatManeuver(target, __instance.Unit.GetThreatHand().Weapon, 0, combatManeuver); } else { Rulebook.Trigger(aoo); } } // === Changed End === if (__instance.AttackOfOpportunityCount == __instance.AttackOfOpportunityPerRound) { __instance.Cooldown.AttackOfOpportunity = 5.4f; } --__instance.AttackOfOpportunityCount; // === Added start === (from UnitAttack.TriggerAttackRule) if (combatManeuver == CombatManeuver.None && target.View != null && target.View.HitFxManager != null) { target.View.HitFxManager.HandleAttackHit(aoo); } // === Added end === __result = true; return(false); }