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); }
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); } } }
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; } }
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; } } }
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); }
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; } } } }
// 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; } }
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) { }
static bool Prefix(RuleCalculateWeaponStats __instance, RulebookEventContext context) { __instance.Initiator?.Get <UnitPartDoubleWeaponSize>()?.maybeApply(__instance); return(true); }
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); } }
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(); } } }