public static void Postfix(Building_TurretGun __instance, TurretTop ___top) { // Determine which way the turret initially faces when spawned var turretFrameworkExtension = TurretFrameworkExtension.Get(__instance.def); switch (turretFrameworkExtension.gunFaceDirectionOnSpawn) { case TurretGunFaceDirection.North: NonPublicProperties.TurretTop_set_CurRotation(___top, Rot4.North.AsAngle); break; case TurretGunFaceDirection.East: NonPublicProperties.TurretTop_set_CurRotation(___top, Rot4.East.AsAngle); break; case TurretGunFaceDirection.South: NonPublicProperties.TurretTop_set_CurRotation(___top, Rot4.South.AsAngle); break; case TurretGunFaceDirection.West: NonPublicProperties.TurretTop_set_CurRotation(___top, Rot4.West.AsAngle); break; default: NonPublicProperties.TurretTop_set_CurRotation(___top, __instance.Rotation.AsAngle); break; } }
public static int AdjustedTurretBurstWarmupTicks(int warmupTicks, Building_Turret turret) { var extensionValues = TurretFrameworkExtension.Get(turret.def); float warmupTicksFloat = warmupTicks; // Multiply the burstWarmupTicksLeft by the manning pawn's aiming delay factor if applicable if (extensionValues.useManningPawnAimingDelayFactor) { var mannableComp = turret.TryGetComp <CompMannable>(); if (mannableComp != null) { var manningPawn = mannableComp.ManningPawn; if (manningPawn != null) { float manningPawnAimingDelayFactor = manningPawn.GetStatValue(StatDefOf.AimingDelayFactor); warmupTicksFloat *= manningPawnAimingDelayFactor; } } } // Multiply based on upgrade if (turret.IsUpgraded(out CompUpgradable upgradableComp)) { warmupTicksFloat *= upgradableComp.Props.turretBurstWarmupTimeFactor; } return(Mathf.RoundToInt(warmupTicksFloat)); }
public static void Postfix(Building_TurretGun __instance, ref bool __result) { // If the turret isn't mannable, is player-controlled and is set to be able to force target, do so if (__instance.Faction != Faction.OfPlayer) { return; } var extensionValues = TurretFrameworkExtension.Get(__instance.def); var upgradableComp = __instance.TryGetComp <CompUpgradable>(); // Upgradable comp doesn't exist/isn't upgraded and can force attack, or exists and upgraded and can force attack if (upgradableComp == null || upgradableComp.Props.canForceAttack != null && (upgradableComp.upgraded || !extensionValues.canForceAttack) && (!upgradableComp.upgraded || !upgradableComp.Props.canForceAttack.Value)) { return; } if (!__instance.def.HasComp(typeof(CompMannable))) { __result = true; } else { Log.Warning($"Turret (defName={__instance.def.defName}) has canForceAttack set to true and CompMannable; canForceAttack is redundant in this case."); } }
public override void TransformValue(StatRequest req, ref float val) { if (ShouldApply(req, out Building_Turret turret)) { var extensionValues = TurretFrameworkExtension.Get(turret.def); val += turret.IsUpgraded(out var upgradableComp) ? upgradableComp.Props.manningPawnShootingAccuracyOffset : extensionValues.manningPawnShootingAccuracyOffset; } }
private bool ShouldApply(StatRequest req, out CompMannable mannableComp) { mannableComp = null; if (req.Thing is Building_Turret turret && TurretFrameworkExtension.Get(turret.def).useManningPawnShootingAccuracy) { mannableComp = turret.GetComp <CompMannable>(); } return(mannableComp != null); }
public static float FiringArcFor(Thing thing) { // Upgraded and defined firing arc if (thing.IsUpgraded(out CompUpgradable upgradableComp)) { return(upgradableComp.Props.FiringArc); } // Defined firing arc return(TurretFrameworkExtension.Get(thing.def).FiringArc); }
public static bool AffectedByEMP(this Building_Turret turret) { // If turret is upgraded and affectedByEMP is defined, return upgradeComp' affectedByEMP if (turret.IsUpgraded(out var upgradableComp) && upgradableComp.Props.affectedByEMP.HasValue) { return(upgradableComp.Props.affectedByEMP.Value); } // Otherwise return the DefModExtension's value return(TurretFrameworkExtension.Get(turret.def).affectedByEMP); }
public override string ExplanationPart(StatRequest req) { if (!ShouldApply(req, out var turret)) { return(null); } var extensionValues = TurretFrameworkExtension.Get(req.Def); var offset = turret.IsUpgraded(out var upgradableComp) ? upgradableComp.Props.manningPawnShootingAccuracyOffset : extensionValues.manningPawnShootingAccuracyOffset; return(offset != 0 ? $"{turret.def.LabelCap}: {offset.ToStringByStyle(parentStat.ToStringStyleUnfinalized, ToStringNumberSense.Offset)}" : null); }
public override void ResolveReferences(ThingDef parentDef) { base.ResolveReferences(parentDef); var extensionValues = TurretFrameworkExtension.Get(parentDef); // If canForceAttack is unassigned, match it to DefModExtension if (!canForceAttack.HasValue) { canForceAttack = extensionValues.canForceAttack; } // If firing arc is unchanged, match it to DefModExtension if (firingArc == -1) { firingArc = extensionValues.FiringArc; } }
public static bool Prefix(BuildableDef checkingDef, IntVec3 loc, Rot4 rot, ref AcceptanceReport __result) { // Draw cones instead of circles if firing arc is limited float firingArc = TurretFrameworkExtension.Get(checkingDef).FiringArc; if (firingArc < 360) { var verbProps = ((ThingDef)checkingDef).building.turretGunDef.Verbs.Find((VerbProperties v) => v.verbClass == typeof(Verb_Shoot)); if (verbProps.range > 0) { TurretExtensionsUtility.TryDrawFiringCone(loc, rot, verbProps.range, firingArc); } if (verbProps.minRange > 0) { TurretExtensionsUtility.TryDrawFiringCone(loc, rot, verbProps.minRange, firingArc); } __result = true; return(false); } return(true); }
public static void Postfix(ThingDef __instance, StatRequest req, ref IEnumerable <StatDrawEntry> __result) { // Add mortar shell stats to the list of stat draw entries if (__instance.IsShell) { var shellThing = ThingMaker.MakeThing(__instance.projectileWhenLoaded); var shellProps = __instance.projectileWhenLoaded.projectile; var shellDamage = shellProps.GetDamageAmount(shellThing); var shellArmorPenetration = shellProps.GetArmorPenetration(shellThing); var shellStoppingPower = shellProps.StoppingPower; var shellDamageDef = shellProps.damageDef.label.CapitalizeFirst(); var shellExplosionRadius = shellProps.explosionRadius; __result = __result.AddItem(new StatDrawEntry(StatCategoryDefOf.TurretAmmo, "Damage".Translate(), shellDamage.ToString(), "Stat_Thing_Damage_Desc".Translate(), 20)); __result = __result.AddItem(new StatDrawEntry(StatCategoryDefOf.TurretAmmo, "TurretExtensions.ShellDamageType".Translate(), shellDamageDef, "TurretExtensions.ShellDamageType_Desc".Translate(), 19)); __result = __result.AddItem(new StatDrawEntry(StatCategoryDefOf.TurretAmmo, "ArmorPenetration".Translate(), shellArmorPenetration.ToStringPercent(), "ArmorPenetrationExplanation".Translate(), 18)); __result = __result.AddItem(new StatDrawEntry(StatCategoryDefOf.TurretAmmo, "StoppingPower".Translate(), shellStoppingPower.ToString(), "StoppingPowerExplanation".Translate(), 17)); if (shellExplosionRadius > 0) { __result = __result.AddItem(new StatDrawEntry(StatCategoryDefOf.TurretAmmo, "TurretExtensions.ShellExplosionRadius".Translate(), shellExplosionRadius.ToString(), "TurretExtensions.ShellExplosionRadius_Desc".Translate(), 16)); } } // Minimum range if (__instance.Verbs.FirstOrDefault(v => v.isPrimary) is VerbProperties verb) { var verbStatCategory = __instance.category != ThingCategory.Pawn ? RimWorld.StatCategoryDefOf.Weapon : RimWorld.StatCategoryDefOf.PawnCombat; if (verb.LaunchesProjectile) { if (verb.minRange > default(float)) { __result = __result.AddItem(new StatDrawEntry(verbStatCategory, "MinimumRange".Translate(), verb.minRange.ToString("F0"), "TurretExtensions.MinimumRange_Desc".Translate(), 5385)); } } } // Add turret weapons stats to the list of SpecialDisplayStats var buildingProps = __instance.building; if (buildingProps == null || !buildingProps.IsTurret) { return; } var gunStatList = new List <StatDrawEntry>(); if (req.Def is ThingDef tDef) { // Add upgradability string upgradableString; CompProperties_Upgradable upgradableCompProps; if (req.HasThing && req.Thing.IsUpgradable(out var upgradableComp)) { upgradableString = (upgradableComp.upgraded ? "TurretExtensions.NoAlreadyUpgraded" : "TurretExtensions.YesClickForDetails").Translate(); upgradableCompProps = upgradableComp.Props; } else { upgradableString = (tDef.IsUpgradable(out upgradableCompProps) ? "TurretExtensions.YesClickForDetails" : "No").Translate(); } var upgradeHyperlinks = new List <Dialog_InfoCard.Hyperlink>(); if (upgradableCompProps?.turretGunDef != null) { upgradeHyperlinks.Add(new Dialog_InfoCard.Hyperlink(upgradableCompProps.turretGunDef)); } gunStatList.Add(new StatDrawEntry(RimWorld.StatCategoryDefOf.BasicsNonPawn, "TurretExtensions.Upgradable".Translate(), upgradableString, TurretExtensionsUtility.UpgradeReadoutReportText(req), 999, hyperlinks: upgradeHyperlinks)); // Add firing arc var firingArc = req.HasThing ? TurretExtensionsUtility.FiringArcFor(req.Thing) : TurretFrameworkExtension.Get(tDef).FiringArc; gunStatList.Add(new StatDrawEntry(RimWorld.StatCategoryDefOf.Weapon, "TurretExtensions.FiringArc".Translate(), firingArc.ToStringDegrees(), "TurretExtensions.FiringArc_Desc".Translate(), 5380)); } // Replace cooldown __result = __result.Where(s => s.stat != StatDefOf.RangedWeapon_Cooldown); var cooldownStat = StatDefOf.RangedWeapon_Cooldown; gunStatList.Add(new StatDrawEntry(cooldownStat.category, cooldownStat, TurretCooldown(req, buildingProps), StatRequest.ForEmpty(), cooldownStat.toStringNumberSense)); // Replace warmup __result = __result.Where(s => s.LabelCap != "WarmupTime".Translate().CapitalizeFirst()); gunStatList.Add(new StatDrawEntry(RimWorld.StatCategoryDefOf.Weapon, "WarmupTime".Translate(), $"{TurretWarmup(req, buildingProps).ToString("0.##")} s", "Stat_Thing_Weapon_MeleeWarmupTime_Desc".Translate(), StatDisplayOrder.Thing_Weapon_MeleeWarmupTime)); __result = __result.Concat(gunStatList); }
public static string UpgradeReadoutReportText(StatRequest req) { var tDef = (ThingDef)req.Def; var upgradeProps = tDef.GetCompProperties <CompProperties_Upgradable>(); // First paragraph var reportBuilder = new StringBuilder(); reportBuilder.AppendLine("TurretExtensions.TurretUpgradeBenefitsMain".Translate()); reportBuilder.AppendLine(); // Upgradable if (upgradeProps != null) { var upgradeComp = req.Thing?.TryGetComp <CompUpgradable>(); var extensionValues = TurretFrameworkExtension.Get(tDef); var defaultStuff = GenStuff.DefaultStuffFor(tDef); bool hasThing = req.HasThing; // Description reportBuilder.AppendLine($"{"Description".Translate()}: {upgradeProps.description}"); // Resource requirements if (upgradeProps.costStuffCount > 0 || !upgradeProps.costList.NullOrEmpty()) { reportBuilder.AppendLine(); reportBuilder.AppendLine($"{"TurretExtensions.TurretResourceRequirements".Translate()}:"); var usedCostList = upgradeComp != null ? upgradeComp.finalCostList : upgradeProps.costList; for (int i = 0; i < usedCostList.Count; i++) { var curCost = usedCostList[i]; reportBuilder.AppendLine($"- {curCost.count}x {curCost.thingDef.LabelCap}"); } if (!hasThing && upgradeProps.costStuffCount > 0) { reportBuilder.AppendLine($"- {upgradeProps.costStuffCount}x {"StatsReport_Material".Translate()}"); } } // Construction skill requirement if (upgradeProps.constructionSkillPrerequisite > 0) { reportBuilder.AppendLine(); reportBuilder.AppendLine($"{"ConstructionNeeded".Translate()}: {upgradeProps.constructionSkillPrerequisite}"); } // Research requirements if (!upgradeProps.researchPrerequisites.NullOrEmpty()) { reportBuilder.AppendLine(); reportBuilder.AppendLine($"{"ResearchPrerequisites".Translate()}:"); for (int i = 0; i < upgradeProps.researchPrerequisites.Count; i++) { reportBuilder.AppendLine($"- {upgradeProps.researchPrerequisites[i].LabelCap}"); } } // Upgrade bonuses reportBuilder.AppendLine(); reportBuilder.AppendLine($"{"TurretExtensions.TurretUpgradeBenefitsUpgradable".Translate()}:"); // Weapon if (upgradeProps.turretGunDef != null) { reportBuilder.AppendLine($"- {"Stat_Weapon_Name".Translate()}: {tDef.building.turretGunDef.LabelCap} => {upgradeProps.turretGunDef.LabelCap}"); } // Stat modifiers var statsModified = new List <StatDef>(); if (!upgradeProps.statOffsets.NullOrEmpty()) { statsModified.AddRange(upgradeProps.statOffsets.Select(s => s.stat)); } if (!upgradeProps.statFactors.NullOrEmpty()) { statsModified.AddRange(upgradeProps.statFactors.Select(s => s.stat)); } if (statsModified.Any()) { statsModified = statsModified.Distinct().ToList(); statsModified.SortBy(s => s.LabelCap.RawText); for (int i = 0; i < statsModified.Count; i++) { var curStat = statsModified[i]; var stringStyle = curStat.toStringStyle; var numberSense = curStat.toStringNumberSense; var preStatValue = hasThing ? req.Thing.GetStatValue(curStat) : tDef.GetStatValueAbstract(curStat, defaultStuff); float postStatValue = preStatValue; if (upgradeProps.statOffsets?.StatListContains(curStat) == true) { postStatValue += upgradeProps.statOffsets.GetStatOffsetFromList(curStat); } if (upgradeProps.statFactors?.StatListContains(curStat) == true) { postStatValue *= upgradeProps.statFactors.GetStatFactorFromList(curStat); } reportBuilder.AppendLine($"- {curStat.LabelCap}: {preStatValue.ToStringByStyle(stringStyle, numberSense)} => {postStatValue.ToStringByStyle(stringStyle, numberSense)}"); } } // Fuel capacity if (upgradeProps.fuelCapacityFactor != 1 && tDef.GetCompProperties <CompProperties_Refuelable>() is CompProperties_Refuelable refuelProps) { reportBuilder.AppendLine($"- {refuelProps.FuelGizmoLabel}: {refuelProps.fuelCapacity} => {Mathf.Round(refuelProps.fuelCapacity * upgradeProps.fuelCapacityFactor)}"); } // Power consumption if (upgradeProps.basePowerConsumptionFactor != 1 && tDef.GetCompProperties <CompProperties_Power>() is CompProperties_Power powerProps) { reportBuilder.AppendLine($"- {"PowerConsumption".Translate()}: {powerProps.basePowerConsumption.ToString("F0")} =>" + $" {Mathf.Round(powerProps.basePowerConsumption * upgradeProps.basePowerConsumptionFactor)}"); } // Warmup if (upgradeProps.turretBurstWarmupTimeFactor != 1) { reportBuilder.AppendLine($"- {"WarmupTime".Translate()}: {upgradeProps.turretBurstWarmupTimeFactor.ToStringByStyle(ToStringStyle.PercentZero, ToStringNumberSense.Factor)}"); } // Cooldown if (upgradeProps.turretBurstCooldownTimeFactor != 1) { reportBuilder.AppendLine($"- {"StatsReport_Cooldown".Translate()}: {upgradeProps.turretBurstCooldownTimeFactor.ToStringByStyle(ToStringStyle.PercentZero, ToStringNumberSense.Factor)}"); } // Firing arc if (upgradeProps.FiringArc != extensionValues.FiringArc) { reportBuilder.AppendLine($"- {"TurretExtensions.FiringArc".Translate()}: {extensionValues.FiringArc.ToStringDegrees()} => {upgradeProps.FiringArc.ToStringDegrees()}"); } // User accuracy modifier if ((extensionValues.manningPawnShootingAccuracyOffset != 0 || upgradeProps.manningPawnShootingAccuracyOffset != 0) && tDef.HasComp(typeof(CompMannable))) { reportBuilder.AppendLine($"- {"TurretExtensions.UserShootingAccuracyModifier".Translate()}: " + $"{extensionValues.manningPawnShootingAccuracyOffset.ToStringByStyle(ToStringStyle.FloatOne, ToStringNumberSense.Offset)} => " + $"{(upgradeProps.manningPawnShootingAccuracyOffset).ToStringByStyle(ToStringStyle.FloatOne, ToStringNumberSense.Offset)}"); } // Manually controllable if (extensionValues.canForceAttack != upgradeProps.canForceAttack && !tDef.HasComp(typeof(CompMannable))) { if (upgradeProps.canForceAttack.Value) { reportBuilder.AppendLine($"- {"TurretExtensions.TurretManuallyControllable".Translate()}"); } else { reportBuilder.AppendLine($"- {"TurretExtensions.TurretNotManuallyControllable".Translate()}"); } } } // Not upgradable :( else { reportBuilder.AppendLine("TurretExtensions.TurretUpgradeBenefitsNotUpgradable".Translate()); } // Return report text return(reportBuilder.ToString()); }
public static float FiringArcFor(Thing thing) { // Upgraded and defined firing arc return(thing.IsUpgraded(out var upgradableComp) ? upgradableComp.Props.FiringArc : TurretFrameworkExtension.Get(thing.def).FiringArc); }