static bool Prefix(VitalStrike __instance, RuleCalculateWeaponStats evt, ref int ___m_DamageMod)
        {
            //allow it to work with elemental damage (?)
            DamageDescription damageDescription = evt.DamageDescription.FirstItem <DamageDescription>();

            if (damageDescription == null)
            {
                return(false);
            }

            int bonus = evt.Initiator.Ensure <UnitPartVitalStrikeScalingDamageBonus>().getDamageBonus();

            bonus *= (___m_DamageMod - 1);
            damageDescription.Bonus += bonus;
            //make vital strike damage not multipliable on critical hit
            var vital_strike_damage = new DamageDescription();

            vital_strike_damage.TypeDescription = damageDescription.TypeDescription;
            vital_strike_damage.Dice            = new DiceFormula(damageDescription.Dice.Rolls * (___m_DamageMod - 1), damageDescription.Dice.Dice);
            if (evt.DamageDescription.Count() <= 1)
            {
                evt.DamageDescription.Add(vital_strike_damage);
            }
            else
            {
                evt.DamageDescription.Insert(1, vital_strike_damage);
            }
            //damageDescription.Dice = new DiceFormula(damageDescription.Dice.Rolls * ___m_DamageMod, damageDescription.Dice.Dice);
            return(false);
        }
        static bool Prefix(TwoWeaponFightingDamagePenalty __instance, RuleCalculateWeaponStats evt)
        {
            ItemEntityWeapon maybeWeapon1 = evt.Initiator.Body.PrimaryHand.MaybeWeapon;
            ItemEntityWeapon maybeWeapon2 = evt.Initiator.Body.SecondaryHand.MaybeWeapon;

            var brawler_part = evt.Initiator?.Get <Brawler.UnitPartBrawler>();

            if ((brawler_part?.checkTwoWeapponFlurry()).GetValueOrDefault())
            {
                is_off_hand = false;
                return(false);
            }

            if (evt.Weapon == null ||
                maybeWeapon1 == null ||
                maybeWeapon2 == null ||
                (maybeWeapon1.Blueprint.IsNatural && (!maybeWeapon1.Blueprint.IsUnarmed || Aux.isMainHandUnarmedAndCanBeIgnored(maybeWeapon1.Blueprint, evt.Initiator.Descriptor))) ||
                (maybeWeapon2.Blueprint.IsNatural && (!maybeWeapon2.Blueprint.IsUnarmed || Aux.isOffHandUnarmedAndCanBeIgnored(maybeWeapon2.Blueprint, evt.Initiator.Descriptor))) ||
                maybeWeapon2 != evt.Weapon ||
                (bool)evt.Initiator.Descriptor.State.Features.DoubleSlice ||
                ((evt.Weapon?.Blueprint.IsUnarmed).GetValueOrDefault() && !is_off_hand)
                )
            {
                is_off_hand = false;
                return(false);
            }
            evt.SecondaryWeapon = true;
            is_off_hand         = false;
            return(false);
        }
 static void Postfix(VitalStrike __instance, RuleCalculateWeaponStats evt, ref int ___m_DamageMod)
 {
     if (evt.AttackWithWeapon != null)
     {
         evt.AttackWithWeapon.IsFirstAttack = true;
         evt.AttackWithWeapon.AttacksCount  = 1;
     }
 }
        public void OnEventAboutToTrigger(RuleCalculateWeaponStats evt)
        {
            WeaponCategory category = evt.Weapon.Blueprint.Type.Category;

            if (category != WeaponCategory.Dagger)
            {
                return;
            }
            evt.AddBonusDamage(1);
        }
예제 #5
0
        private readonly BlueprintWeaponType _weaponType = Main.library.Get <BlueprintWeaponType>("5a939137fc039084580725b2b0845c3f"); // Starknife

        public void OnEventAboutToTrigger(RuleCalculateWeaponStats evt)
        {
            if (evt.Weapon.Blueprint.Type == _weaponType)
            {
                var charisma     = evt.Initiator.Descriptor.Stats.Charisma;
                var existingStat = !evt.DamageBonusStat.HasValue ? null : (Owner.Unit.Descriptor.Stats.GetStat(evt.DamageBonusStat.Value) as ModifiableValueAttributeStat);
                if (charisma != null && (existingStat == null || charisma.Bonus > existingStat.Bonus))
                {
                    evt.OverrideDamageBonusStat(StatType.Charisma);
                }
            }
        }
예제 #6
0
 static void Postfix(VitalStrike __instance, RuleCalculateWeaponStats evt, ref int ___m_DamageMod)
 {
     if (!(evt.Initiator?.Get <UnitPartVitalStrikeTracker>()?.isEnabled()).GetValueOrDefault())
     {
         return;
     }
     if (evt.AttackWithWeapon != null)
     {
         evt.AttackWithWeapon.IsFirstAttack = true;
         evt.AttackWithWeapon.AttacksCount  = 1;
     }
 }
예제 #7
0
        public new void OnEventAboutToTrigger(RuleCalculateWeaponStats evt)
        {
            if (evt.Weapon != this.Owner)
            {
                return;
            }

            int bonus = EnhancementBonus - evt.Enhancement;

            added_bonus = bonus > 0 ? bonus : 0;


            evt.AddBonusDamage(added_bonus);
            evt.Enhancement += added_bonus;
        }
 private static void Prefix(RuleCalculateWeaponStats __instance, ref int ___m_SizeShift, ref int __state, ref Size __result)
 {
     __state = ___m_SizeShift;
     foreach (var enchantment in __instance.Weapon.Enchantments)
     {
         var component = enchantment.Blueprint.GetComponent <WeaponSizeChange>();
         if (component != null)
         {
             if ((component.SizeCategoryChange > 0 && ___m_SizeShift > 0) ||
                 (component.SizeCategoryChange < 0 && ___m_SizeShift < 0))
             {
                 ___m_SizeShift = 0;
             }
             break;
         }
     }
 }
예제 #9
0
        static bool Prefix(VitalStrike __instance, RuleCalculateWeaponStats evt, ref int ___m_DamageMod)
        {
            if (!(evt.Initiator?.Get <UnitPartVitalStrikeTracker>()?.isEnabled()).GetValueOrDefault())
            {
                return(false);
            }

            evt.Initiator?.Get <UnitPartVitalStrikeTracker>()?.disable();

            int dmg_mod = ___m_DamageMod;

            if (Main.settings.balance_fixes)
            {
                var bab = evt.Initiator.Stats.BaseAttackBonus.ModifiedValue;
                dmg_mod = 2 + Math.Min(2, (Math.Max(bab - 6, 0) / 5));
            }

            //allow it to work with elemental damage (?)
            DamageDescription damageDescription = evt.DamageDescription.FirstItem <DamageDescription>();

            if (damageDescription == null)
            {
                return(false);
            }

            int bonus = evt.Initiator.Ensure <UnitPartVitalStrikeScalingDamageBonus>().getDamageBonus();

            bonus *= (dmg_mod - 1);
            damageDescription.Bonus += bonus;
            //make vital strike damage not multipliable on critical hit
            var vital_strike_damage = new DamageDescription();

            vital_strike_damage.TypeDescription = damageDescription.TypeDescription;
            vital_strike_damage.Dice            = new DiceFormula(damageDescription.Dice.Rolls * (dmg_mod - 1), damageDescription.Dice.Dice);
            if (evt.DamageDescription.Count() <= 1)
            {
                evt.DamageDescription.Add(vital_strike_damage);
            }
            else
            {
                evt.DamageDescription.Insert(1, vital_strike_damage);
            }
            //damageDescription.Dice = new DiceFormula(damageDescription.Dice.Rolls * ___m_DamageMod, damageDescription.Dice.Dice);
            return(false);
        }
예제 #10
0
        public void maybeApply(RuleCalculateWeaponStats evt)
        {
            if (evt.Weapon?.Blueprint == null)
            {
                return;
            }

            bool res = false;

            foreach (var b in buffs)
            {
                b.CallComponents <DoubleWeaponSize>(a => res = a.apply(evt));
                {
                    if (res)
                    {
                        return;
                    }
                }
            }
        }
예제 #11
0
            // ReSharper disable once UnusedMember.Local
            private static void Postfix(RuleCalculateWeaponStats __instance, ref Size __result)
            {
                var adjustment = 0;

                foreach (var enchantment in __instance.Weapon.Enchantments)
                {
                    var baseSizeChange = enchantment.Blueprint.GetComponent <WeaponBaseSizeChange>();
                    if (baseSizeChange)
                    {
                        adjustment += baseSizeChange.SizeCategoryChange;
                    }
                }

                if (adjustment > 0)
                {
                    __result += 1;
                }
                else if (adjustment < 0)
                {
                    __result -= 1;
                }
            }
예제 #12
0
        public bool apply(RuleCalculateWeaponStats evt)
        {
            if (!categories.Empty() && !categories.Contains(evt.Weapon.Blueprint.Category))
            {
                return(false);
            }

            if (evt.DoNotScaleDamage)
            {
                return(false);
            }
            var wielder_size = evt.Initiator.Descriptor.State.Size;

            evt.DoNotScaleDamage = true;

            //scale weapon to the wielder size if need (note polymophs do not change their size, so their weapon dice is not supposed to scale)
            var         base_weapon_dice = evt.Initiator.Body.IsPolymorphed ? evt.Weapon.Blueprint.Damage : evt.Weapon.Blueprint.ScaleDamage(wielder_size);
            DiceFormula baseDice         = !evt.WeaponDamageDiceOverride.HasValue ? base_weapon_dice : (evt.Initiator.Body.IsPolymorphed ? evt.WeaponDamageDiceOverride.Value : WeaponDamageScaleTable.Scale(evt.WeaponDamageDiceOverride.Value, wielder_size));


            if (wielder_size == Size.Colossal || wielder_size == Size.Gargantuan)
            {
                //double damage dice
                DiceFormula double_damage = new DiceFormula(2 * baseDice.Rolls, baseDice.Dice);
                evt.WeaponDamageDiceOverride = new DiceFormula?(double_damage);
            }
            else
            {
                var new_dice = WeaponDamageScaleTable.Scale(baseDice, wielder_size + 2, wielder_size, evt.Weapon.Blueprint);
                if (new_dice == baseDice)
                {
                    //no scaling available
                    new_dice = new DiceFormula(2 * baseDice.Rolls, baseDice.Dice);
                }
                evt.WeaponDamageDiceOverride = new DiceFormula?(new_dice);
            }
            return(true);
        }
 public void OnEventDidTrigger(RuleCalculateWeaponStats evt)
 {
 }
예제 #14
0
 static bool Prefix(RuleCalculateWeaponStats __instance, RulebookEventContext context)
 {
     __instance.Initiator?.Get <UnitPartDoubleWeaponSize>()?.maybeApply(__instance);
     return(true);
 }
예제 #15
0
        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);
            }
        }
예제 #16
0
        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();
                }
            }
        }