internal static float GetHitChanceFactor(VerbProperties props, Thing equipment, float dist) { float num; if (dist <= 4f) { num = AdjustedAccuracy(props, RangeCategory.Touch, equipment); } else if (dist <= 15f) { num = Mathf.Lerp(AdjustedAccuracy(props, RangeCategory.Touch, equipment), AdjustedAccuracy(props, RangeCategory.Short, equipment), (dist - 4f) / 11f); } else if (dist <= 30f) { num = Mathf.Lerp(AdjustedAccuracy(props, RangeCategory.Short, equipment), AdjustedAccuracy(props, RangeCategory.Medium, equipment), (dist - 15f) / 15f); } else if (dist <= 50f) { num = Mathf.Lerp(AdjustedAccuracy(props, RangeCategory.Medium, equipment), AdjustedAccuracy(props, RangeCategory.Long, equipment), (dist - 30f) / 20f); } else { num = AdjustedAccuracy(props, RangeCategory.Long, equipment); } if (num < 0.01f) { num = 0.01f; } if (num > 1f) { num = 1f; } return(num); }
public static IEnumerable <VerbProperties> AllVerbDefs() { VerbProperties verbProperties = new VerbProperties(); verbProperties.verbClass = typeof(Verb_BeatFire); verbProperties.category = VerbCategory.BeatFire; verbProperties.range = 1.42f; verbProperties.noiseRadius = 3f; verbProperties.targetParams.canTargetFires = true; verbProperties.targetParams.canTargetPawns = false; verbProperties.targetParams.canTargetBuildings = false; verbProperties.targetParams.mapObjectTargetsMustBeAutoAttackable = false; verbProperties.warmupTime = 0f; verbProperties.defaultCooldownTime = 1.1f; verbProperties.soundCast = SoundDefOf.Interact_BeatFire; yield return(verbProperties); verbProperties = new VerbProperties(); verbProperties.verbClass = typeof(Verb_Ignite); verbProperties.category = VerbCategory.Ignite; verbProperties.range = 1.42f; verbProperties.noiseRadius = 3f; verbProperties.targetParams.onlyTargetFlammables = true; verbProperties.targetParams.canTargetBuildings = true; verbProperties.targetParams.canTargetPawns = false; verbProperties.targetParams.mapObjectTargetsMustBeAutoAttackable = false; verbProperties.warmupTime = 3f; verbProperties.defaultCooldownTime = 1.3f; verbProperties.soundCast = SoundDefOf.Interact_Ignite; yield return(verbProperties); }
static void Postfix(VerbProperties __instance, ref Thing equipment, ref float __result) { if (equipment == null || equipment.holdingOwner == null || !(equipment.holdingOwner.Owner is Pawn_EquipmentTracker)) { return; } if (equipment == null || equipment.holdingOwner == null || equipment.holdingOwner.Owner == null) { return; } Pawn_EquipmentTracker eqt = (Pawn_EquipmentTracker)equipment.holdingOwner.Owner; Pawn pawn = Traverse.Create(eqt).Field("pawn").GetValue <Pawn>(); if (pawn == null || pawn.stances == null) { return; } Pawn mount = Base.Instance.GetExtendedDataStorage().GetExtendedDataFor(pawn).mount; if (mount == null) { return; } float adjustedLevel = 5; if (pawn.skills != null && pawn.skills.GetSkill(SkillDefOf.Animals) is SkillRecord record) { adjustedLevel = record.levelInt - Mathf.RoundToInt(mount.GetStatValue(StatDefOf.MinimumHandlingSkill, true)); } float animalHandlingOffset = adjustedLevel * Base.handlingAccuracyImpact; float factor = (100f - ((float)Base.accuracyPenalty.Value - animalHandlingOffset)) / 100f; __result *= factor; }
static void Postfix(VerbProperties __instance, ref Thing equipment, ref float __result) { if (equipment == null || equipment.holdingOwner == null || !(equipment.holdingOwner.Owner is Pawn_EquipmentTracker)) { return; } if (equipment == null || equipment.holdingOwner == null || equipment.holdingOwner.Owner == null) { return; } Pawn_EquipmentTracker eqt = (Pawn_EquipmentTracker)equipment.holdingOwner.Owner; Pawn pawn = Traverse.Create(eqt).Field("pawn").GetValue <Pawn>(); if (pawn == null || pawn.stances == null) { return; } if (Base.Instance.GetExtendedDataStorage().GetExtendedDataFor(pawn).mount == null) { return; } float factor = ((float)(100 - Base.accuracyPenalty.Value) / 100); __result *= factor; }
public static void Postfix(VerbProperties __instance, ref int __result) { if (!__instance.IsMeleeAttack) { __result = Mathf.RoundToInt(__result / _modifier); } }
public static float RangedDPS(ThingWithComps weapon, float speedBias, float averageSpeed, float range) { Verb atkVerb = (weapon.GetComp <CompEquippable>()).PrimaryVerb; VerbProperties atkProps = atkVerb.verbProps; if (atkProps.range * atkProps.range < range || atkProps.minRange * atkProps.minRange > range) { return(-1); } float hitChance = atkProps.GetHitChanceFactor(weapon, range); float damage = (atkProps.defaultProjectile == null) ? 0 : atkProps.defaultProjectile.projectile.GetDamageAmount(weapon); int burstShot = atkProps.burstShotCount; float speedFactor = RangedSpeed(weapon); float speedFactorBase = speedFactor; float diffFromAverage = speedFactor - averageSpeed; diffFromAverage *= (speedBias - 1); speedFactor += diffFromAverage; float rawDps = (damage * burstShot) / speedFactor; float Dps = rawDps * hitChance; //Log.Message(weapon.LabelCap + " dps:" + rawDps + "dam:"+damage*burstShot + " spdfac:" + speedFactor + " spdFacBase:" + speedFactorBase); return(Dps); }
public RangedWeaponStats(Building_TurretGun turret) { weapon = turret.gun; shootVerb = GetShootVerb(weapon.def); // Get the damage from the loaded projectile if the weapon is loadable or the default projectile otherwise var projectile = weapon.TryGetComp <CompChangeableProjectile>()?.Projectile?.projectile ?? shootVerb?.defaultProjectile?.projectile; // Default to zero damage if we can't find a projectile. // Not an error as unloaded mortars don't have projectiles shotDamage = projectile?.GetDamageAmount(weapon) ?? 0; // Note that turrets completely ignore the warmup and cooldown stat of the weapon warmup = turret.def.building.turretBurstWarmupTime; // Logic duplicated from Building_TurretGun.BurstCooldownTime() if (turret.def.building.turretBurstCooldownTime >= 0f) { cooldown = turret.def.building.turretBurstCooldownTime; } else { cooldown = turret.AttackVerb.verbProps.defaultCooldownTime; } }
static void Postfix(VerbProperties __instance, ref Thing equipment, ref float __result) { if (equipment == null || equipment.holdingOwner == null || !(equipment.holdingOwner.Owner is Pawn_EquipmentTracker)) { return; } if (equipment == null || equipment.holdingOwner == null || equipment.holdingOwner.Owner == null) { return; } Pawn_EquipmentTracker eqt = (Pawn_EquipmentTracker)equipment.holdingOwner.Owner; Pawn pawn = Traverse.Create(eqt).Field("pawn").GetValue <Pawn>(); if (pawn == null || pawn.stances == null) { return; } if (pawn.stances.curStance is Stance_RunAndGun || pawn.stances.curStance is Stance_RunAndGun_Cooldown) { ModSettingsPack settings = HugsLibController.SettingsManager.GetModSettings("RunAndGun"); int value = settings.GetHandle <int>("accuracyPenalty").Value; float factor = ((float)(100 - value) / 100); __result *= factor; } }
public static float RangedDPSAverage(ThingWithComps weapon, float speedBias, float averageSpeed) { if (weapon == null) { return(0); } Verb atkVerb = (weapon.GetComp <CompEquippable>()).PrimaryVerb; VerbProperties atkProps = atkVerb.verbProps; float damage = (atkProps.defaultProjectile == null) ? 0 : atkProps.defaultProjectile.projectile.GetDamageAmount(weapon); int burstShot = atkProps.burstShotCount; float speedFactor = RangedSpeed(weapon); float speedFactorBase = speedFactor; float diffFromAverage = speedFactor - averageSpeed; diffFromAverage *= (speedBias - 1); speedFactor += diffFromAverage; float rawDps = (damage * burstShot) / speedFactor; //Log.Message(weapon.LabelCap + " dps:" + rawDps + "dam:" + damage * burstShot + " spdfac:" + speedFactor + " spdFacBase:" + speedFactorBase); float DpsAvg = 0f; DpsAvg += rawDps * AdjustedAccuracy(atkProps, RangeCategory.Short, weapon); DpsAvg += rawDps * AdjustedAccuracy(atkProps, RangeCategory.Medium, weapon); DpsAvg += rawDps * AdjustedAccuracy(atkProps, RangeCategory.Long, weapon); return(DpsAvg / 3f); }
public static void AdjustedAccuracyPostfix(VerbProperties __instance, ref float __result, RangeCategory cat) { if (__instance is VerbProperties_Custom) { switch (cat) { case RangeCategory.Touch: __result += __instance.accuracyTouch; break; case RangeCategory.Short: __result += __instance.accuracyShort; break; case RangeCategory.Medium: __result += __instance.accuracyMedium; break; case RangeCategory.Long: __result += __instance.accuracyLong; break; default: throw new InvalidOperationException(); } } }
public override void ResolveReferences() { base.ResolveReferences(); if (this.modExtensions == null) { this.modExtensions = new List <DefModExtension>(); } if (this.verbProperties == null) { this.verbProperties = new VerbProperties { verbClass = typeof(Verb_CastAbility), label = this.label, category = VerbCategory.Misc, range = this.range, noiseRadius = 3f, targetParams = this.targetingParameters, warmupTime = this.castTime / (float)GenTicks.TicksPerRealSecond, defaultCooldownTime = this.cooldownTime, meleeDamageBaseAmount = Mathf.RoundToInt(this.power), meleeDamageDef = DamageDefOf.Blunt } } ; } }
// FIXME: CanBeAppliedToThing restriction for burst damage and thrown weapons public override void ModifyVerbProperty(ThingWithComps parentThing, VerbProperties verbProperties) { float val = ConvertHelper.Convert <float>(fieldInfo.GetValue(verbProperties)); val = valueModifier.ChangeValue(val); SetVerbProperty(verbProperties, ConvertHelper.Convert(val, fieldType)); }
private static float GetAccuracy(Thing weapon, VerbProperties verb, ProjectileProperties projectile, float dist, Pawn pawn = null) { float forcedMissRadius = CalculateAdjustedForcedMissDist(verb.ForcedMissRadius, dist); float baseAimOn = verb.GetHitChanceFactor(weapon, dist); if (pawn != null) { baseAimOn *= ShotReport.HitFactorFromShooter(pawn, dist); } int affectedCellCount = (verb.CausesExplosion) ? GenRadial.NumCellsInRadius(projectile.explosionRadius) : 1; float accuracy; if (forcedMissRadius > 0.5f) { int affectableCellCount = GenRadial.NumCellsInRadius(forcedMissRadius); accuracy = (float)affectedCellCount / affectableCellCount; } else { float medianToWildRadius = ShootTuning.MissDistanceFromAimOnChanceCurves.Evaluate(baseAimOn, 0.5f); float indirectHitChance = (float)(affectedCellCount - 1) / GenRadial.NumCellsInRadius(medianToWildRadius); accuracy = baseAimOn + (1f - baseAimOn) * indirectHitChance; } return(Mathf.Clamp01(accuracy)); }
// The def's chance is the overall chance against the whole shot period. The combined probability // needs to be separated out for each shot in the burst. public override float GetRealChance(ThingWithComps thing, bool usePreModProps = false) { var comp = thing?.TryGetComp <CompLootAffixableThing>(); if (comp == null) { return(chance); } VerbProperties modVerbProps = usePreModProps ? comp.PrimaryVerbPropsFromDef : comp.PrimaryVerbProps; if (modVerbProps == null) { return(chance); } // Give one-use items a 100% chance if (modVerbProps.verbClass == typeof(Verb_ShootOneUse)) { return(1); } // 1 - (1 - chance) to the count-th root float realChance = 1f - Mathf.Pow(1f - chance, 1f / modVerbProps.burstShotCount); if (realChance >= 0.95f) { realChance = 1; } return(realChance); }
public static IEnumerable <VerbProperties> AllVerbDefs() { VerbProperties d = new VerbProperties(); d.category = VerbCategory.BeatFire; d.label = "Beat fire"; d.range = 1.42f; d.noiseRadius = 3f; d.targetParams.canTargetFires = true; d.targetParams.canTargetPawns = false; d.targetParams.canTargetBuildings = false; d.targetParams.mapObjectTargetsMustBeAutoAttackable = false; d.warmupTime = 0f; d.defaultCooldownTime = 1.1f; d.soundCast = SoundDefOf.Interact_BeatFire; yield return(d); d = new VerbProperties(); d.category = VerbCategory.Ignite; d.label = "Ignite"; d.range = 1.42f; d.noiseRadius = 3f; d.targetParams.onlyTargetFlammables = true; d.targetParams.canTargetBuildings = true; d.targetParams.canTargetPawns = false; d.targetParams.mapObjectTargetsMustBeAutoAttackable = false; d.warmupTime = 3f; d.defaultCooldownTime = 1.3f; d.soundCast = SoundDefOf.Interact_Ignite; yield return(d); yield break; }
public Verb CopyAndReturnNewVerb(Verb newVerb = null) { if (newVerb != null) { deflectVerb = null; deflectVerb = (Verb_Deflected)Activator.CreateInstance(typeof(Verb_Deflected)); deflectVerb.caster = GetPawn; //Initialize VerbProperties VerbProperties newVerbProps = new VerbProperties(); //Copy values over to a new verb props newVerbProps.hasStandardCommand = newVerb.verbProps.hasStandardCommand; newVerbProps.projectileDef = newVerb.verbProps.projectileDef; newVerbProps.range = newVerb.verbProps.range; newVerbProps.muzzleFlashScale = newVerb.verbProps.muzzleFlashScale; newVerbProps.warmupTime = 0; newVerbProps.defaultCooldownTime = 0; newVerbProps.soundCast = this.Props.deflectSound; //Apply values deflectVerb.verbProps = newVerbProps; } else { if (deflectVerb == null) { deflectVerb = (Verb_Deflected)Activator.CreateInstance(typeof(Verb_Deflected)); deflectVerb.caster = GetPawn; deflectVerb.verbProps = this.Props.DeflectVerb; } } return(deflectVerb); }
internal static void Postfix(VerbProperties __instance, ref bool __result) { if (!__result) { __result = typeof(Verb_LaunchProjectileCE).IsAssignableFrom(__instance.verbClass); } }
public void SetVerbProperty(VerbProperties verbProperties, object value) { if (AppliesTo != ModifierTarget.VerbProperties) { return; } fieldInfo.SetValue(verbProperties, ConvertHelper.Convert(value, fieldType)); }
public override bool Compare(Object x, Object y) { VerbProperties verbX = x as VerbProperties; VerbProperties verbY = y as VerbProperties; return(verbX != null && verbY != null && verbX.linkedBodyPartsGroup == verbY.linkedBodyPartsGroup); }
public override void ResetVerbProperty(ThingWithComps parentThing, VerbProperties srcVerbProps, VerbProperties destVerbProps) { if (AppliesTo != ModifierTarget.VerbProperties) { return; } SetVerbProperty(destVerbProps, fieldInfo.GetValue(srcVerbProps)); }
public static void Postfix(VerbProperties __instance, IntVec3 center) { IAdvancedVerb verbProperties = __instance as IAdvancedVerb; if (AMAMod.settings.AllowRapidFire && verbProperties != null) { verbProperties.DrawExtraRadiusRings(center); } }
public static void Postfix(VerbProperties __instance, IntVec3 center) { IAdvancedVerb verbProperties = __instance as IAdvancedVerb; if (verbProperties != null) { verbProperties.DrawExtraRadiusRings(center); } }
private void InitVerb(Verb verb, VerbProperties properties, VerbTracker verbTracker, Tool tool, ManeuverDef maneuver, string id) { verb.loadID = id; verb.verbProps = properties; verb.verbTracker = verbTracker; verb.tool = tool; verb.maneuver = maneuver; verb.caster = this; }
public static VerbProperties VerbWithCategory(VerbCategory id) { VerbProperties verbProperties = allVerbDefs.Where((VerbProperties v) => v.category == id).FirstOrDefault(); if (verbProperties == null) { Log.Error("Failed to find Verb with id " + id); } return(verbProperties); }
private static float GetWarmup(VerbProperties verb, Pawn pawn = null) { float warmup = verb.warmupTime; if (pawn != null) { warmup *= pawn.GetStatValue(StatDefOf.AimingDelayFactor); } return(warmup.SecondsToTicks().TicksToSeconds()); }
public static bool Prefix(VerbProperties __instance, Thing equipment, float dist, ref float __result) { IAdvancedVerb verbProperties = __instance as IAdvancedVerb; if (verbProperties != null) { __result = verbProperties.GetHitChanceFactor(equipment, dist); return(false); } return(true); }
/* XXX: Yes, we are dynamically modifying a value here via reflection, based on data some rando * provided via XML. Is it dangerous? Sure. But, this is the best way to change whatever value * we want. */ public override void ModifyVerbProperty(ThingWithComps parentThing) { if (AppliesTo != ModifierTarget.VerbProperties) { return; } VerbProperties modVerbProps = parentThing.TryGetComp <CompLootAffixableThing>().PrimaryVerbProps; ModifyVerbProperty(parentThing, modVerbProps); }
private static void FillRowCombatExtended(Row row, ThingDef d, VerbProperties verb) { var ceAmmo = d.GetCompProperties <CompProperties_AmmoUser>(); row["DamageType".ParserTranslate()] = ceAmmo != null ? ceAmmo.ammoSet.LabelCap : verb.defaultProjectile.projectile.damageDef.label; // TODO: check full stat dump row["CE_SightsEfficiency".ParserTranslate()] = d.GetStatValueAbstract(StatDef.Named("SightsEfficiency")).ToPercent(); row["CE_ShotSpread".ParserTranslate()] = d.GetStatValueAbstract(StatDef.Named("ShotSpread")); row["CE_SwayFactor".ParserTranslate()] = d.GetStatValueAbstract(StatDef.Named("SwayFactor")); row["CE_OneHanded".ParserTranslate()] = d.weaponTags?.Contains("CE_OneHandedWeapon") ?? false; }
public void ModifyVerbProperties(ThingWithComps parentThing, VerbProperties verbProperties) { foreach (LootAffixModifier modifier in modifiers.Where(lam => lam.AppliesTo == ModifierTarget.VerbProperties)) { // Only set permanent changes here. Otherwise, it gets changed dynamically. if (modifier.GetRealChance(parentThing) >= 0.95f) { modifier.ModifyVerbProperty(parentThing, verbProperties); } } }
public VerbStats(VerbProperties v) { this.category = v.category; this.label = v.label; this.isPrimary = v.isPrimary; this.minRange = v.minRange; this.range = v.range; this.burstShotCount = v.burstShotCount; this.ticksBetweenBurstShots = v.ticksBetweenBurstShots; this.noiseRadius = v.noiseRadius; this.hasStandardCommand = v.hasStandardCommand; this.targetable = v.targetable; this.requireLineOfSight = v.requireLineOfSight; this.mustCastOnOpenGround = v.mustCastOnOpenGround; this.forceNormalTimeSpeed = v.forceNormalTimeSpeed; this.onlyManualCast = v.onlyManualCast; this.stopBurstWithoutLos = v.stopBurstWithoutLos; this.commonality = v.commonality; this.minIntelligence = v.minIntelligence; this.consumeFuelPerShot = v.consumeFuelPerShot; this.warmupTime = v.warmupTime; this.defaultCooldownTime = v.defaultCooldownTime; this.muzzleFlashScale = v.muzzleFlashScale; this.ensureLinkedBodyPartsGroupAlwaysUsable = v.ensureLinkedBodyPartsGroupAlwaysUsable; this.meleeDamageBaseAmount = v.meleeDamageBaseAmount; this.meleeArmorPenetrationBase = v.meleeArmorPenetrationBase; this.ai_IsWeapon = v.ai_IsWeapon; this.ai_IsBuildingDestroyer = v.ai_IsBuildingDestroyer; this.ai_AvoidFriendlyFireRadius = v.ai_AvoidFriendlyFireRadius; //this.forcedMissRadius = v.forcedMissRadius; this.accuracyTouch = v.accuracyTouch; this.accuracyShort = v.accuracyShort; this.accuracyMedium = v.accuracyMedium; this.accuracyLong = v.accuracyLong; if (v.targetParams != null) { this.targetParams = new TargetingParameterStats(v.targetParams); } if (v.surpriseAttack != null) { this.surpriseAttack = new SurpriseAttackPropStats(v.surpriseAttack); } Util.AssignDefStat(v.soundCast, out this.soundCast); Util.AssignDefStat(v.soundCastTail, out this.soundCastTail); Util.AssignDefStat(v.soundAiming, out this.soundAiming); Util.AssignDefStat(v.meleeDamageDef, out this.meleeDamageDef); Util.AssignDefStat(v.impactMote, out this.impactMote); Util.AssignDefStat(v.linkedBodyPartsGroup, out this.linkedBodyPartsGroup); Util.AssignDefStat(v.defaultProjectile, out this.defaultProjectile); Util.AssignDefStat(v.spawnDef, out this.spawnDef); Util.AssignDefStat(v.colonyWideTaleDef, out this.colonyWideTaleDef); Util.AssignDefStat(v.bodypartTagTarget, out this.bodypartTagTarget); Util.AssignDefStat(v.rangedFireRulepack, out this.rangedFireRulepack); }