static void Postfix(RuleCalculateCMD __instance)
        {
            //add attacker dependent ac bonuses/penalties
            var rule_ac  = new RuleCalculateAC(__instance.Initiator, __instance.Target, AttackType.Touch);
            var ac       = Rulebook.Trigger <RuleCalculateAC>(rule_ac).TargetAC;
            int delta_ac = ac - (__instance.IsTargetFlatFooted ? __instance.Target.Stats.AC.FlatFootedTouch : __instance.Target.Stats.AC.Touch);

            var tr = Harmony12.Traverse.Create(__instance);

            tr.Property("Result").SetValue(__instance.Result + delta_ac);
        }
        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);
        }