static bool Prefix(RuleCalculateAttackBonus __instance, RulebookEventContext context)
        {
            FlankingParameters flankedParameters = new FlankingParameters(typeof(RuleCalculateAttackBonus_OnTrigger_Patch), __instance.Initiator);

            UnitCombatState_get_IsFlanked_Patch.PushFlankingParameters(flankedParameters);
            return(true);
        }
Example #2
0
        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;
        }
        //static public Dictionary<(MechanicsContext, UnitEntityData), bool> spell_target_map = new Dictionary<(MechanicsContext, UnitEntityData), bool>();
        static bool Prefix(RulePrepareDamage __instance, RulebookEventContext context)
        {
            if (!Main.settings.one_sneak_attack_per_target_per_spell)
            {
                return(true);
            }
            AbilityData ability = __instance.ParentRule?.Reason?.Ability;

            if (ability == null || __instance.Target == null)
            {
                return(true);
            }

            var context2 = __instance.ParentRule?.Reason?.Context;

            if (context2 == null)
            {
                return(true);
            }

            var unit_part_affected_by_spell = __instance.Target.Ensure <UnitPartAffectedBySpell>();

            if (!unit_part_affected_by_spell.contexts.Contains(context2))
            {
                unit_part_affected_by_spell.contexts.Add(context2);
                return(true);
            }

            __instance.IsSurpriseSpell = false;
            __instance.ParentRule.AttackRoll?.UseSneakAttack();
            return(true);
        }
Example #4
0
        static bool Prefix(RuleCheckCastingDefensively __instance, RulebookEventContext context)
        {
            if (__instance.Spell.Blueprint.GetComponent <AbilityKineticist>() == null)
            {
                return(true);
            }
            var kineticist_part = __instance.Initiator.Get <UnitPartKineticist>();

            if (kineticist_part == null)
            {
                return(true);
            }

            var tr             = Harmony12.Traverse.Create(__instance);
            var rule           = Rulebook.Trigger <RuleCalculateAbilityParams>(new RuleCalculateAbilityParams(__instance.Initiator, __instance.Spell));
            var ability_params = rule.Result;

            tr.Property("DC").SetValue(15 + ability_params.SpellLevel * 2);

            var bonus_concentration = Helpers.GetField <int>(rule, "m_BonusConcentration");

            tr.Property("Concentration").SetValue(bonus_concentration + kineticist_part.ClassLevel + kineticist_part.MainStatBonus);
            tr.Property("ResultRollRaw").SetValue(RulebookEvent.Dice.D20);
            return(false);
        }
        static bool Prefix(RulePrepareDamage __instance, RulebookEventContext context)
        {
            FlankingParameters flankedParameters = new FlankingParameters(typeof(RulePrepareDamage_OnTrigger_Patch), __instance.Initiator, true, null, null);

            UnitCombatState_get_IsFlanked_Patch.PushFlankingParameters(flankedParameters);
            return(true);
        }
Example #6
0
            static public bool Prefix(RuleDealDamage __instance, RulebookEventContext context)
            {
                if (__instance.Target == null)
                {
                    return(true);
                }

                var context2 = __instance.Reason.Context;

                if (context2?.AssociatedBlueprint != null && context2.AssociatedBlueprint is BlueprintBuff)
                {//do not apply shadow twice
                    return(true);
                }
                var summoned_context = ShadowSpells.getShadowBuff(__instance.Initiator.Descriptor)?.MaybeContext;

                if (context2 == null && summoned_context == null)
                {
                    return(true);
                }

                var shadow_descriptor2 = (context2?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;
                var shadow_summon      = (summoned_context?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;

                if (shadow_summon == SpellDescriptor.None && shadow_descriptor2 == SpellDescriptor.None)
                {
                    return(true);
                }

                if (shadow_summon > shadow_descriptor2)
                {
                    context2 = summoned_context;
                }

                if (!__instance.Target.Ensure <UnitPartDisbelief>().disbelief_contexts.ContainsKey(context2))
                {
                    RuleSavingThrow ruleSavingThrow = context2.TriggerRule <RuleSavingThrow>(new RuleSavingThrow(__instance.Target, SavingThrowType.Will, context2.Params.DC));
                    __instance.Target.Ensure <UnitPartDisbelief>().disbelief_contexts[context2] = ruleSavingThrow.IsPassed;
                }

                if (__instance.Target.Ensure <UnitPartDisbelief>().disbelief_contexts[context2])
                {
                    if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow20)
                    {
                        __instance.ReducedBecauseOfShadowEvocation = true;
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow60)
                    {
                        __instance.ReducedBecauseOfShadowEvocationGreater = true;
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow80)
                    {
                        __instance.Modifier = new float?((__instance.Modifier.HasValue ? __instance.Modifier.GetValueOrDefault() : 1f) * 0.8f);
                    }
                }
                return(true);
            }
Example #7
0
        public override void OnTrigger(RulebookEventContext context)
        {
            if (!Weapon.IsMelee)
            {
                return;
            }

            Result = Initiator.GetActiveCombatManeuverToggle();

            if (Result == CombatManeuver.Trip)
            {
                UnitState state = 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))
                {
                    Result = CombatManeuver.None;
                }
            }
            else if (Result == CombatManeuver.Disarm)
            {
                bool canBeDisarmed = false;
                // same checks as in RuleCombatManeuver. If the unit cannot be disarmed (further), don't attempt to disarm.
                ItemEntityWeapon maybeWeapon  = Target.Body.PrimaryHand.MaybeWeapon;
                ItemEntityWeapon maybeWeapon2 = Target.Body.SecondaryHand.MaybeWeapon;

                if (maybeWeapon != null && !maybeWeapon.Blueprint.IsUnarmed && !maybeWeapon.Blueprint.IsNatural && !Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DisarmMainHandBuff))
                {
                    canBeDisarmed = true;
                }
                else if (maybeWeapon2 != null && !maybeWeapon2.Blueprint.IsUnarmed && !maybeWeapon2.Blueprint.IsNatural && !Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.DisarmOffHandBuff))
                {
                    canBeDisarmed = true;
                }

                if (!canBeDisarmed)
                {
                    Result = CombatManeuver.None;
                }
            }
            else if (Result == CombatManeuver.SunderArmor)
            {
                if (Target.Descriptor.Buffs.HasFact(BlueprintRoot.Instance.SystemMechanics.SunderArmorBuff))
                {
                    Result = CombatManeuver.None;
                }
            }

            if (ForceNormalAttack)
            {
                Result = CombatManeuver.None;
            }
        }
Example #8
0
        static bool Prefix(RuleCalculateAC __instance, RulebookEventContext context)
        {
            Cover cover = Rulebook.Trigger(new RuleCheckSoftCover(__instance.Initiator, __instance.Target, __instance.AttackType)).Result;

            if (cover == Cover.Full)
            {
                __instance.AddBonus(4, SoftCoverFact);
            }
            else if (cover == Cover.Partial)
            {
                __instance.AddBonus(2, SoftCoverPartialFact);
            }
            return(true);
        }
        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);
        }
Example #10
0
        static bool Prefix(RuleCalculateAC __instance, RulebookEventContext context)
        {
            var current_cover = __instance.Target.hasCoverFrom(__instance.Initiator, __instance.AttackType);

            //Main.logger.Log(current_cover.ToString() + " "  + __instance.AttackType.ToString());
            if (current_cover.isFull())
            {
                __instance.AddBonus(Cover.cover_ac_bonus, Cover.soft_cover_fact);
            }
            else if (current_cover.isPartial())
            {
                __instance.AddBonus(Cover.partial_cover_ac_bonus, Cover.partial_soft_cover_fact);
            }

            return(true);
        }
Example #11
0
        static bool Prefix(RuleCalculateAC __instance, RulebookEventContext context)
        {
            if (__instance.AttackType == Kingmaker.RuleSystem.AttackType.Melee || __instance.AttackType == Kingmaker.RuleSystem.AttackType.Touch)
            {
                var  state = __instance.Target.Descriptor.State;
                bool target_unable_to_fly = !state.CanMove || __instance.IsTargetFlatFooted;

                bool target_fly   = __instance.Target.Ensure <UnitPartFlying>().isFlying() && !target_unable_to_fly;
                bool attacker_fly = __instance.Initiator.Ensure <UnitPartFlying>().isFlying() && __instance.Initiator.Descriptor.State.CanMove;

                if (target_fly && !attacker_fly)
                {
                    __instance.AddBonus(FixFlying.fly_ac_bonus, FixFlying.flying_fact);
                }
            }
            return(true);
        }
Example #12
0
        public override void OnTrigger(RulebookEventContext context)
        {
            float multiplier = Modifier ?? 1f;
            int   healAmount = Math.Max(0, (int)((Dice.D(HealFormula) + Bonus) * multiplier));
            var   value      = Math.Min(healAmount, Target.Damage);

            setValue(this, value);
            Target.Damage -= value;
            Log.Write($"{GetType().Name}: healed {Target.CharacterName} for {Value} HP ({value}), damage now at: {Target.Damage}");
            UnitPartDualCompanion.HandleHealing(Target, healAmount);
            EventBus.RaiseEvent((IHealingHandler h) => h.HandleHealing(Initiator, Target, Value));
            var overflow = healAmount - Target.Damage;

            if (overflow > 0)
            {
                OverflowHealing = overflow;
            }
        }
Example #13
0
            static public bool Prefix(RuleHealDamage __instance, RulebookEventContext context)
            {
                if (__instance.Target == null)
                {
                    return(true);
                }

                var context2 = __instance.Reason.Context;

                if (context2?.AssociatedBlueprint != null && context2.AssociatedBlueprint is BlueprintBuff)
                {//do not apply shadow twice
                    return(true);
                }
                context2 = ShadowSpells.extractMainContext(context2, __instance.Initiator);
                if (context2 == null)
                {
                    return(true);
                }

                if (!__instance.Target.Ensure <UnitPartDisbelief>().attemptedDisbelief(context2))
                {
                    if (__instance.Target.Descriptor.State.HasCondition(UnitCondition.TrueSeeing))
                    {
                        __instance.Target.Ensure <UnitPartDisbelief>().register(context2, true);
                    }
                    else
                    {
                        __instance.Target.Ensure <UnitPartDisbelief>().register(context2, ShadowSpells.makeDisbeliefSave(context2, __instance.Target));
                    }
                }

                if (__instance.Target.Ensure <UnitPartDisbelief>().disbelieved(context2))
                {
                    int illusion_reality = ShadowSpells.getSpellReality(context2);

                    if (illusion_reality > 0)
                    {
                        __instance.Modifier = new float?((__instance.Modifier.HasValue ? __instance.Modifier.GetValueOrDefault() : 1f) * 0.01f * illusion_reality);
                        Common.AddBattleLogMessage(__instance.Target.CharacterName + " reduces healing from "
                                                   + context2.SourceAbility.Name + " to " + illusion_reality.ToString() + "% due to disbelief");
                    }
                }
                return(true);
            }
        /*static IEnumerable<Harmony12.CodeInstruction> Transpiler(IEnumerable<Harmony12.CodeInstruction> instructions)
         * {
         *  var codes = instructions.ToList();
         *  var check_is_unarmed = codes.FindIndex(x => x.opcode == System.Reflection.Emit.OpCodes.Callvirt && x.operand.ToString().Contains("IsUnarmed")); //checking is unarmed on weapon on primary hand
         *
         *  codes[check_is_unarmed] = new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Ldarg_0);
         *  codes.Insert(check_is_unarmed + 1, new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Call, new Func<BlueprintItemWeapon, RuleCalculateAttacksCount, bool>(considerUnarmedAndIgnore).Method));
         *
         *  check_is_unarmed = codes.IndexOf(codes.FindAll(x => x.opcode == System.Reflection.Emit.OpCodes.Callvirt && x.operand.ToString().Contains("IsUnarmed"))[2]);
         *  codes[check_is_unarmed] = new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Ldarg_0);
         *  codes.Insert(check_is_unarmed + 1, new Harmony12.CodeInstruction(System.Reflection.Emit.OpCodes.Call, new Func<BlueprintItemWeapon, RuleCalculateAttacksCount, bool>(considerUnarmedAndIgnoreOffHand).Method));
         *  return codes.AsEnumerable();
         * }*/

        static bool Prefix(RuleCalculateAttacksCount __instance, RulebookEventContext context)
        {
            int                 bab = (int)__instance.Initiator.Stats.BaseAttackBonus;
            int                 num_penalized_attacks = Math.Min(Math.Max(0, bab / 5 - (bab % 5 == 0 ? 1 : 0)), 3);
            HandSlot            primary_hand          = __instance.Initiator.Body.PrimaryHand;
            HandSlot            secondary_hand        = __instance.Initiator.Body.SecondaryHand;
            BlueprintItemWeapon blueprint1            = primary_hand.MaybeWeapon?.Blueprint;
            BlueprintItemWeapon blueprint2            = secondary_hand.MaybeShield != null ? ((bool)__instance.Initiator.Descriptor.State.Features.ShieldBash ? secondary_hand.MaybeShield.WeaponComponent?.Blueprint : null) : secondary_hand.MaybeWeapon?.Blueprint;
            int                 num = primary_hand.MaybeWeapon == null ? 0 : (primary_hand.MaybeWeapon.HoldInTwoHands ? 1 : 0);

            if ((secondary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == false &&
                (blueprint1 != null) &&
                (!considerUnarmedAndIgnore(blueprint1, __instance) || blueprint2 == null || blueprint2.IsUnarmed)
                )
            {
                ++__instance.PrimaryHand.MainAttacks;
                if (!blueprint1.IsNatural || (bool)__instance.Initiator.Descriptor.State.Features.IterativeNaturalAttacks || __instance.ForceIterativeNaturealAttacks || blueprint1.IsUnarmed)
                {
                    __instance.PrimaryHand.PenalizedAttacks += Math.Max(0, num_penalized_attacks);
                }
            }
            if ((secondary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == true ||
                (blueprint2 == null) ||
                considerUnarmedAndIgnoreOffHand(blueprint2, __instance) && (blueprint1 != null) ||
                (primary_hand.MaybeWeapon?.HoldInTwoHands).GetValueOrDefault() == true
                )
            {
                return(false);
            }
            ++__instance.SecondaryHand.MainAttacks;
            if (blueprint1 == null || !considerUnarmedAndIgnore(blueprint1, __instance) &&
                (blueprint1 == null || !blueprint1.IsNatural || !(bool)__instance.Initiator.Descriptor.State.Features.IterativeNaturalAttacks && !__instance.ForceIterativeNaturealAttacks) ||
                (blueprint2.IsUnarmed)
                )
            {
                return(false);
            }
            __instance.SecondaryHand.PenalizedAttacks += Math.Max(0, num_penalized_attacks);
            return(false);
        }
Example #15
0
            static public bool Prefix(RuleApplyBuff __instance, RulebookEventContext context)
            {
                if (ShadowSpells.isShadowBuff(__instance.Blueprint))
                {
                    return(true);
                }
                var context2 = __instance.Reason.Context;

                if (context2?.AssociatedBlueprint != null && context2.AssociatedBlueprint is BlueprintBuff)
                {//do not apply shadow twice
                    return(true);
                }
                var summoned_context = ShadowSpells.getShadowBuff(__instance.Initiator.Descriptor)?.MaybeContext;

                if (context2 == null && summoned_context == null)
                {
                    return(true);
                }


                var shadow_descriptor2 = (context2?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;
                var shadow_summon      = (summoned_context?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;

                if (shadow_summon == SpellDescriptor.None && shadow_descriptor2 == SpellDescriptor.None)
                {
                    return(true);
                }


                if (shadow_summon > shadow_descriptor2)
                {
                    context2 = summoned_context;
                }

                if (__instance.Initiator == null)
                {
                    return(true);
                }

                if (!__instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts.ContainsKey(context2))
                {
                    RuleSavingThrow ruleSavingThrow = context2.TriggerRule <RuleSavingThrow>(new RuleSavingThrow(__instance.Initiator, SavingThrowType.Will, context2.Params.DC));
                    __instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts[context2] = ruleSavingThrow.IsPassed;
                }

                if (__instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts[context2])
                {
                    if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow20)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 20)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow60)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 60)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow80)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 80)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                }

                return(true);
            }
Example #16
0
 static void Postfix(RuleAttackRoll __instance, RulebookEventContext context)
 {
     OutflankPatch.OutflankProvokeAttackPatch(__instance, context);
 }
Example #17
0
        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);
                }
            }
        }
Example #18
0
            static public bool Prefix(RuleApplyBuff __instance, RulebookEventContext context)
            {
                if (__instance.Blueprint?.GetComponent <IgnoreShadowReality>() != null)
                {
                    return(true);
                }
                var rule_summon = Rulebook.CurrentContext.AllEvents.LastOfType <RuleSummonUnit>();

                if (rule_summon != null)
                {//do not interrupt summon buffs
                    return(true);
                }

                var context2 = __instance.Reason.Context;
                //there are also actions after summon that should not be affected
                //we need to check if we are still inside SpawnMonsterComponent
                var summon_context = __instance.Initiator.Buffs?.GetBuff(Game.Instance.BlueprintRoot.SystemMechanics.SummonedUnitBuff)?.MaybeContext?.ParentContext;

                if (summon_context == context2)
                {
                    return(true);
                }

                if (context2?.AssociatedBlueprint != null && context2.AssociatedBlueprint is BlueprintBuff)
                {//do not apply shadow twice
                    return(true);
                }

                context2 = ShadowSpells.extractMainContext(context2, context2?.MaybeCaster);
                if (context2 == null)
                {
                    return(true);
                }

                if (__instance.Initiator == null)
                {
                    return(true);
                }

                if (!__instance.Initiator.Ensure <UnitPartDisbelief>().attemptedDisbelief(context2))
                {
                    if (__instance.Initiator.Descriptor.State.HasCondition(UnitCondition.TrueSeeing))
                    {
                        __instance.Initiator.Ensure <UnitPartDisbelief>().register(context2, true);
                    }
                    else
                    {
                        __instance.Initiator.Ensure <UnitPartDisbelief>().register(context2, ShadowSpells.makeDisbeliefSave(context2, __instance.Initiator));
                    }
                }

                if (__instance.Initiator.Ensure <UnitPartDisbelief>().disbelieved(context2))
                {
                    int illusion_reality = ShadowSpells.getSpellReality(context2);
                    int result           = RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100));
                    if (illusion_reality > 0 && result > illusion_reality)
                    {
                        __instance.CanApply = false;
                        Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name
                                                   + $" effect due to disbelief (rolled {result} vs {illusion_reality}%)");
                        return(false);
                    }
                }

                return(true);
            }
Example #19
0
 public override void OnTrigger(RulebookEventContext context)
 {
     CanTargetUnit = !IsImmune;
     //Log.Write($"RuleSpellTargetCheck: caster {Initiator} can target {Target}? {CanTargetUnit}");
 }
            static public bool Prefix(RuleApplyBuff __instance, RulebookEventContext context)
            {
                /*if (ShadowSpells.isShadowBuff(__instance.Blueprint))
                 * {
                 *  return true;
                 * }*/
                var rule_summon = Rulebook.CurrentContext.AllEvents.LastOfType <RuleSummonUnit>();

                if (rule_summon != null)
                {//do not interrupt summon buffs
                    return(true);
                }

                var context2 = __instance.Reason.Context;
                //there are also actions after summon that should not be affected
                //we need to check if we are still inside SpawnMonsterComponent
                var summon_context = __instance.Initiator.Buffs?.GetBuff(Game.Instance.BlueprintRoot.SystemMechanics.SummonedUnitBuff)?.MaybeContext?.ParentContext;

                if (summon_context == context2)
                {
                    return(true);
                }


                if (context2?.AssociatedBlueprint != null && context2.AssociatedBlueprint is BlueprintBuff)
                {//do not apply shadow twice
                    return(true);
                }
                var summoned_context = ShadowSpells.getShadowBuff(__instance.Initiator.Descriptor)?.MaybeContext;

                if (context2 == null && summoned_context == null)
                {
                    return(true);
                }


                var shadow_descriptor2 = (context2?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;
                var shadow_summon      = (summoned_context?.SpellDescriptor).GetValueOrDefault() & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow;

                if (shadow_summon == SpellDescriptor.None && shadow_descriptor2 == SpellDescriptor.None)
                {
                    return(true);
                }


                if (shadow_summon > shadow_descriptor2)
                {
                    context2 = summoned_context;
                }

                if (__instance.Initiator == null)
                {
                    return(true);
                }

                if (!__instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts.ContainsKey(context2))
                {
                    RuleSavingThrow ruleSavingThrow = context2.TriggerRule <RuleSavingThrow>(new RuleSavingThrow(__instance.Initiator, SavingThrowType.Will, context2.Params.DC));
                    __instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts[context2] = ruleSavingThrow.IsPassed;
                }

                if (__instance.Initiator.Ensure <UnitPartDisbelief>().disbelief_contexts[context2])
                {
                    if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow20)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 20)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow60)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 60)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                    else if ((context2.SpellDescriptor & (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow) == (SpellDescriptor)AdditionalSpellDescriptors.ExtraSpellDescriptor.Shadow80)
                    {
                        if (RulebookEvent.Dice.D(new DiceFormula(1, DiceType.D100)) > 80)
                        {
                            __instance.CanApply = false;
                            Common.AddBattleLogMessage(__instance.Initiator.CharacterName + " avoids " + context2.SourceAbility.Name + " effect due to disbelief");
                            return(false);
                        }
                    }
                }

                return(true);
            }
Example #21
0
        public override void OnTrigger(RulebookEventContext context)
        {
            if (!Main.Settings.UseSoftCover)
            {
                Main.Logger?.Write("Soft Cover Rules disabled, result of soft cover check is Cover.None");
                Result = Cover.None;
                return;
            }

            Main.Logger?.Append("RuleCheckSoftCover Triggered");
            Main.Logger?.Append($"Attacker = {Initiator.CharacterName} ({Initiator.UniqueId})");
            Main.Logger?.Append($"Target = {Target.CharacterName} ({Target.UniqueId})");
            Main.Logger?.Append($"#IgnoreUnits = {IgnoreUnits.Count}");
            Main.Logger?.Append($"AttackerIgnoresCover = {AttackerIgnoresCover}");
            Main.Logger?.Append($"AttackType = {AttackType}");

            if (AttackerIgnoresCover)
            {
                Main.Logger?.Flush();
                return;
            }


            Vector2 toPosition   = Target.Position.To2D();
            Vector2 fromPosition = Initiator.Position.To2D();

            int i = 0;

            List <UnitEntityData> unitsToCheck = new List <UnitEntityData>();

            Main.Logger?.Append("Looping over units in combat...");
            foreach (UnitEntityData unit in Game.Instance.State.AwakeUnits)
            {
                i++;
                if (unit == Initiator || unit == Target)
                {
                    Main.Logger?.Append($"{i}: unit {unit.CharacterName} ({unit.UniqueId}) is either the Initiator or the Target and does not count for cover");
                    continue;
                }

                if (IgnoreUnits.Contains(unit))
                {
                    Main.Logger?.Append($"{i}: unit {unit.CharacterName} ({unit.UniqueId}) is in the IgnoreUnits list and does not count for cover");
                    continue;
                }

                if (unit.Descriptor.State.IsDead)
                {
                    Main.Logger?.Append($"{i}: unit {unit.CharacterName} ({unit.UniqueId}) is dead and does not count for cover");
                    continue;
                }

                if (unit.Descriptor.State.Prone.Active)
                {
                    Main.Logger?.Append($"{i}: unit {unit.CharacterName} ({unit.UniqueId}) is prone and does not count for cover");
                    continue;
                }

                int sizeDifference = Target.Descriptor.State.Size - unit.Descriptor.State.Size;

                // e.g. a Small character cannot provide soft cover for a Large character
                if (sizeDifference >= 2)
                {
                    Main.Logger?.Append($"{i}: the target is of size {Target.Descriptor.State.Size}, while unit {unit.CharacterName} ({unit.UniqueId}) is of size {unit.Descriptor.State.Size}, so the unit does not count for cover.");
                    continue;
                }

                Vector2 unitPosition = unit.Position.To2D();
                // A unit that is closer to the attacker than to the target and is smaller than the attacker does not provide cover to the target
                if (unit.Descriptor.State.Size < Initiator.Descriptor.State.Size && Vector2.Distance(fromPosition, unitPosition) < Vector2.Distance(unitPosition, toPosition))
                {
                    Main.Logger?.Append($"{i}: the attacker is of size {Initiator.Descriptor.State.Size}, the unit is of size {unit.Descriptor.State.Size}, and the unit is {Vector2.Distance(fromPosition, unitPosition)} away from the attacker and {Vector2.Distance(unitPosition, toPosition)} away from the target, so the unit does not count for cover.");
                    continue;
                }

                // Filter nonsensical cases
                if (Vector2.Distance(fromPosition, toPosition) < Vector2.Distance(fromPosition, unitPosition) || VectorMath.AngleBetweenPoints(unitPosition, fromPosition, toPosition) < 90.0f)
                {
                    Main.Logger?.Append($"{i}: Possibility of {unit.CharacterName} ({unit.UniqueId}) providing cover considered nonsensical: ");
                    Main.Logger?.Append($" - Distance from attacker to target: {Vector2.Distance(fromPosition, toPosition)}");
                    Main.Logger?.Append($" - Distance from attacker to unit: {Vector2.Distance(fromPosition, unitPosition)}");
                    Main.Logger?.Append($" - Angle between attacker - unit - target: {VectorMath.AngleBetweenPoints(unitPosition, fromPosition, toPosition)}");
                    continue;
                }

                unitsToCheck.Add(unit);
                Main.Logger?.Append($"{i}: unit {unit.CharacterName} ({unit.UniqueId}) added to list of potential cover-providing units");
            }

            if (unitsToCheck.Count < 1)
            {
                Main.Logger?.Append("No units could possibly provide cover.");
                Main.Logger?.Flush();
                return;
            }


            Vector2 direction = (toPosition - fromPosition).normalized;
            Vector2 up        = new Vector2(direction.y, -direction.x);
            Vector2 down      = new Vector2(-direction.y, direction.x);

            Vector2 fromPointsStart = fromPosition + up * Initiator.Corpulence;
            Vector2 fromPointsEnd   = fromPosition + down * Initiator.Corpulence;

            Vector2 tangent1 = Vector2.zero;
            Vector2 tangent2 = Vector2.zero;

            VectorMath.TangentPointsOnCircleFromPoint(fromPointsStart, toPosition, Target.Corpulence, out tangent1, out tangent2);

            Vector2 toPointsStart = Vector2.zero;

            float normDist = 0.0f;

            if (Pathfinding.VectorMath.SegmentsIntersect2D(fromPosition, toPosition, fromPointsStart, tangent1, out normDist))
            {
                toPointsStart = tangent2;
            }
            else
            {
                toPointsStart = tangent1;
            }

            Vector2 tangent3 = Vector2.zero;
            Vector2 tangent4 = Vector2.zero;

            VectorMath.TangentPointsOnCircleFromPoint(fromPointsEnd, toPosition, Target.Corpulence, out tangent3, out tangent4);

            Vector2 toPointsEnd = Vector2.zero;

            if (Pathfinding.VectorMath.SegmentsIntersect2D(fromPosition, toPosition, fromPointsEnd, tangent3, out normDist))
            {
                toPointsEnd = tangent4;
            }
            else
            {
                toPointsEnd = tangent3;
            }

            Vector2[] fromPoints = VectorMath.FindEquidistantPointsOnArc(fromPointsStart, fromPointsEnd, fromPosition, Initiator.Corpulence, 10);
            Vector2[] toPoints   = VectorMath.FindEquidistantPointsOnArc(toPointsStart, toPointsEnd, toPosition, Target.Corpulence, 10);

            Main.Logger?.Append("Looping over lines...");
            int raysBlocked = 0;

            for (i = 0; i < fromPoints.Length; i++)
            {
                Main.Logger?.Append($" - Checking line {i} ({fromPoints[i]} to {toPoints[i]})...");
#if DEBUG
                if (i > 0)
                {
                    Main.Logger?.Append($"   * Validate: lines {i} and {i - 1} intersect: {Pathfinding.VectorMath.SegmentsIntersect2D(fromPoints[i - 1], toPoints[i - 1], fromPoints[i], toPoints[i], out normDist)}");
                }
#endif
                for (int j = 0; j < unitsToCheck.Count; j++)
                {
                    var p = VectorMath.NearestPointOnSegmentToPoint(fromPoints[i], toPoints[i], unitsToCheck[j].Position.To2D());
                    var d = Vector2.Distance(p, unitsToCheck[j].Position.To2D());
                    Main.Logger?.Append($"   * closest distance of line {i} to unit {unitsToCheck[j].CharacterName} ({unitsToCheck[j].UniqueId}): {d}. Unit's corpulence: {unitsToCheck[j].Corpulence}");
                    if (Vector2.Distance(p, unitsToCheck[j].Position.To2D()) < unitsToCheck[j].Corpulence)
                    {
                        raysBlocked++;
                        Main.Logger?.Append($"   * line {i} is obstructed by unit {unitsToCheck[j].CharacterName} ({unitsToCheck[j].UniqueId}). Number of obstructed lines so far = {raysBlocked}. Continuing to next line...");
                        break;
                    }
                    else
                    {
                        Main.Logger?.Append($"   * line {i} is not obstructed by unit {unitsToCheck[j].CharacterName} ({unitsToCheck[j].UniqueId})");
                    }
                }

                if (raysBlocked > 6)
                {
                    break;
                }
            }

            Main.Logger?.Append($"Finished looping over target lines. Total lines blocked: {raysBlocked}");
            if (raysBlocked > 6)
            {
                Result = Cover.Full;
            }
            else if (raysBlocked > 2)
            {
                Result = Cover.Partial;
            }
            else
            {
                Result = Cover.None;
            }


            Main.Logger?.Append($"Final cover result: {Result}");
            Main.Logger?.Flush();
        }
Example #22
0
 static bool Prefix(RuleCalculateWeaponStats __instance, RulebookEventContext context)
 {
     __instance.Initiator?.Get <UnitPartDoubleWeaponSize>()?.maybeApply(__instance);
     return(true);
 }
 static void Postfix(RuleCombatManeuver __instance, RulebookEventContext context)
 {
     provokeAoOOnCombatManeuverAttempt[__instance.Initiator.UniqueId] = true;
 }
        internal static bool Prefix(RuleCalculateAttackBonusWithoutTarget __instance, RulebookEventContext context)
        {
            if (__instance.Weapon == null || !__instance.Weapon.Blueprint.IsMelee)
            {
                return(true);
            }
            var blade_tutor_part = __instance?.Initiator?.Get <BladeTutorUnitPart>();

            if (blade_tutor_part == null)
            {
                return(true);
            }

            var res = blade_tutor_part.getValue();

            if (res.Item2 == null || res.Item1 == 0)
            {
                return(true);
            }

            int total_penalty = 0;
            var attack_bonus  = __instance.Initiator.Stats.GetStat(StatType.AdditionalAttackBonus);

            foreach (var m in attack_bonus.Modifiers)
            {
                if (m.Source?.Blueprint != null && facts.Contains(m.Source.Blueprint))
                {
                    total_penalty -= m.ModValue;
                }
            }

            foreach (var m in __instance.BonusSources)
            {
                if (m.Source?.Blueprint != null && facts.Contains(m.Source.Blueprint))
                {
                    total_penalty -= m.Bonus;
                }
            }

            int bonus = Math.Min(total_penalty, res.Item1);

            __instance.AddBonus(bonus, res.Item2);


            return(true);
        }
 public override void OnTrigger(RulebookEventContext context)
 {
 }
 static void Postfix(RulePrepareDamage __instance, RulebookEventContext context)
 {
     UnitCombatState_get_IsFlanked_Patch.PopFlankingParametersIfTypeMatches(typeof(RulePrepareDamage_OnTrigger_Patch));
 }