static FloatRange GetInsulationStats(Apparel apparel) { var insulationCold = apparel.GetStatValue(StatDefOf.Insulation_Cold); var insulationHeat = apparel.GetStatValue(StatDefOf.Insulation_Heat); return(new FloatRange(-insulationCold, insulationHeat)); }
public static float ApparelScoreRaw_ProtectionBaseStat(Apparel ap) { var num = ap.GetStatValue(StatDefOf.ArmorRating_Sharp) + (ap.GetStatValue(StatDefOf.ArmorRating_Blunt) * 0.5f); return(num * 0.1f); }
static bool Prefix(ref float __result, JobGiver_OptimizeApparel __instance, Pawn pawn, Apparel ap) { Log.Message("1 pawn is " + ((pawn == null) ? "null" : "not null")); if (pawn != null) { return(true); } Log.Message("2"); if (HitPointsPercentScoreFactorCurve == null) { HitPointsPercentScoreFactorCurve = typeof(JobGiver_OptimizeApparel).GetField("HitPointsPercentScoreFactorCurve", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as SimpleCurve; InsulationColdScoreFactorCurve_NeedWarm = typeof(JobGiver_OptimizeApparel).GetField("InsulationColdScoreFactorCurve_NeedWarm", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as SimpleCurve; NeedWarmthFI = typeof(JobGiver_OptimizeApparel).GetField("neededWarmth", BindingFlags.Static | BindingFlags.NonPublic); } Log.Message("HitPointsPercentScoreFactorCurve is " + ((HitPointsPercentScoreFactorCurve == null) ? "null" : "not null")); Log.Message("InsulationColdScoreFactorCurve_NeedWarm is " + ((InsulationColdScoreFactorCurve_NeedWarm == null) ? "null" : "not null")); Log.Message("NeedWarmthFI is " + ((NeedWarmthFI == null) ? "null" : "not null")); Log.Message("NeedWarmth is " + NeedWarmthFI.GetValue(null)); float result = 0.1f + ap.GetStatValue(StatDefOf.ArmorRating_Sharp) + ap.GetStatValue(StatDefOf.ArmorRating_Blunt); if (ap.def.useHitPoints) { float x = (float)ap.HitPoints / (float)ap.MaxHitPoints; result *= HitPointsPercentScoreFactorCurve.Evaluate(x); } result += ap.GetSpecialApparelScoreOffset(); float num3 = 1f; if ((NeededWarmth)NeedWarmthFI.GetValue(null) == NeededWarmth.Warm) { float statValue = ap.GetStatValue(StatDefOf.Insulation_Cold); num3 *= InsulationColdScoreFactorCurve_NeedWarm.Evaluate(statValue); } result *= num3; if (ap.WornByCorpse) { result -= 0.5f; if (result > 0f) { result *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { result -= 0.5f; if (result > 0f) { result *= 0.1f; } } __result = result; return(false); }
public float CalculateApparelScoreRawInsulationColdAjust(Apparel ap) { float num3 = 1f; if (this.needWarmCurve != null) { float statValueAbstract = ap.GetStatValue(StatDefOf.Insulation_Cold); num3 *= this.needWarmCurve.Evaluate(statValueAbstract); } if (this.needCoolCurve != null) { float statValueAbstract = ap.GetStatValue(StatDefOf.Insulation_Heat); num3 *= this.needCoolCurve.Evaluate(statValueAbstract); } return(num3); }
public static int GetPostArmorDamage(Pawn pawn, int amountInt, BodyPartRecord part, DamageDef damageDef) { float num = (float)amountInt; if (damageDef.armorCategory == null) { return(amountInt); } StatDef deflectionStat = damageDef.armorCategory.deflectionStat; if (pawn.apparel != null) { List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { Apparel apparel = wornApparel[i]; if (apparel.def.apparel.CoversBodyPart(part)) { ArmorUtility.ApplyArmor(ref num, apparel.GetStatValue(deflectionStat, true), apparel, damageDef); if (num < 0.001f) { return(0); } } } } ArmorUtility.ApplyArmor(ref num, pawn.GetStatValue(deflectionStat, true), null, damageDef); return(GenMath.RoundRandom(num)); }
public static float CalculateArmorByPartsCE(Pawn pawn, StatDef stat, ref string text, string unit) { text = ""; float num = 0f; List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { num += wornApparel[i].GetStatValue(stat, true) * wornApparel[i].def.apparel.HumanBodyCoverage; } if (num > 0.005f) { List <BodyPartRecord> bpList = pawn.RaceProps.body.AllParts; for (int i = 0; i < bpList.Count; i++) { float armorValue = 0f; BodyPartRecord part = bpList[i]; if (part.depth == BodyPartDepth.Outside && (part.coverage >= 0.1 || (part.def == BodyPartDefOf.Eye || part.def == BodyPartDefOf.Neck))) { text += part.LabelCap + ": "; for (int j = wornApparel.Count - 1; j >= 0; j--) { Apparel apparel = wornApparel[j]; if (apparel.def.apparel.CoversBodyPart(part)) { armorValue += apparel.GetStatValue(stat, true); } } text += formatArmorValue(armorValue, unit) + "\n"; } } } return(num); }
static float ApparelScoreAutoWorkPriorities(Pawn pawn, Apparel apparel) { return(WorkPriorities.WorktypeStatPriorities(pawn) .Select(sp => (apparel.def.equippedStatOffsets.GetStatOffsetFromList(sp.Stat) + apparel.GetStatValue(sp.Stat) - sp.Stat.defaultBaseValue) * sp.Weight) .Sum()); // NOTE: weights were already normalized to sum to 1. }
public static void ShieldFromApparel(ref float armourImportance, StatDef stat, Apparel apparel, BodyPartRecord part) { if (apparel.IsShield(out var shieldComp) && shieldComp.UsableNow && shieldComp.CoversBodyPart(part)) { var shieldRating = Mathf.Clamp01(apparel.GetStatValue(stat) / 2); armourImportance *= 1 - shieldRating; } }
public bool IncludeAppareL(Apparel a) { if (this.Name.Length > 0) { if (a.Label.ToLower().IndexOf(this.Name) == -1 && a.def.defName.ToLower().IndexOf(this.Name) == -1) { return(false); } } if (this.Layer != null) { if (!a.def.apparel.layers.Contains(this.Layer)) { return(false); } } if (this.Quality != QualityRange.All) { QualityCategory q; if (a.TryGetQuality(out q)) { if (this.Quality.min > q || this.Quality.max < q) { return(false); } } } if (this.HP > 0) { float percent = (float)a.HitPoints / a.MaxHitPoints; float filter = this.HP * 0.01f; if (percent < filter) { return(false); } } foreach (StatDefValue sdv in this.StatDefs) { if (sdv.Value > 0) { float v = Math.Abs(a.GetStatValue(sdv.Def)); if (sdv.Value > v) { return(false); } } } return(true); }
public static float GetPostArmorDamage(Pawn pawn, float amount, float armorPenetration, BodyPartRecord part, ref DamageDef damageDef, out bool deflectedByMetalArmor, out bool diminishedByMetalArmor) { deflectedByMetalArmor = false; diminishedByMetalArmor = false; float result; if (damageDef.armorCategory == null) { result = amount; } else { StatDef armorRatingStat = damageDef.armorCategory.armorRatingStat; if (pawn.apparel != null) { List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int i = wornApparel.Count - 1; i >= 0; i--) { Apparel apparel = wornApparel[i]; if (apparel.def.apparel.CoversBodyPart(part)) { float num = amount; bool flag; ArmorUtility.ApplyArmor(ref amount, armorPenetration, apparel.GetStatValue(armorRatingStat, true), apparel, ref damageDef, pawn, out flag); if (amount < 0.001f) { deflectedByMetalArmor = flag; return(0f); } if (amount < num && flag) { diminishedByMetalArmor = true; } } } } float num2 = amount; bool flag2; ArmorUtility.ApplyArmor(ref amount, armorPenetration, pawn.GetStatValue(armorRatingStat, true), null, ref damageDef, pawn, out flag2); if (amount < 0.001f) { deflectedByMetalArmor = flag2; result = 0f; } else { if (amount < num2 && flag2) { diminishedByMetalArmor = true; } result = amount; } } return(result); }
public static float GetApparelScore(Pawn pawn, Thing thing) { Apparel apparel = thing as Apparel; if (apparel is ShieldBelt && pawn.equipment.Primary != null && pawn.equipment.Primary.def.IsWeaponUsingProjectiles) { return(-1000f); } float score = 0.1f + apparel.def.apparel.scoreOffset; float armorScore = apparel.GetStatValue(StatDefOf.ArmorRating_Sharp) + apparel.GetStatValue(StatDefOf.ArmorRating_Blunt) + apparel.GetStatValue(StatDefOf.ArmorRating_Heat); score += armorScore; if (apparel.def.useHitPoints) { float x = (float)apparel.HitPoints / (float)apparel.MaxHitPoints; score *= HitPointsPercentScoreFactorCurve.Evaluate(x); } score += apparel.GetSpecialApparelScoreOffset(); //float warmthScore = 1f; //if (neededWarmth == NeededWarmth.Warm) //{ // float statValue = apparel.GetStatValue(StatDefOf.Insulation_Cold); // warmthScore *= InsulationColdScoreFactorCurve_NeedWarm.Evaluate(statValue); //} //score *= warmthScore; // Human body is close enough float coverageScore = apparel.def.apparel.HumanBodyCoverage * 10.0f; score *= coverageScore; return(score); }
private void GetInsulationStats(Apparel apparel, out float insulationCold, out float insulationHeat) { if (Outfitter.Cache.InsulationDict.TryGetValue(apparel, out var range)) { insulationCold = range.min; insulationHeat = range.max; return; } // offsets on apparel insulationCold = apparel.GetStatValue(StatDefOf.Insulation_Cold) * -1; insulationHeat = apparel.GetStatValue(StatDefOf.Insulation_Heat); insulationCold -= apparel.def.equippedStatOffsets.GetStatOffsetFromList(StatDefOf.Insulation_Cold); insulationHeat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(StatDefOf.Insulation_Heat); // offsets on apparel infusions DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.ComfyTemperatureMin, out var infInsulationCold); DoApparelScoreRaw_PawnStatsHandlers(apparel, StatDefOf.ComfyTemperatureMax, out var infInsulationHeat); insulationCold += infInsulationCold; insulationHeat += infInsulationHeat; Outfitter.Cache.InsulationDict.Add(apparel, new FloatRange(insulationCold, insulationHeat)); }
/// <summary> /// When notified job is about to start, calculate unequip delay for underlying apparel. /// </summary> public override void Notify_Starting() { base.Notify_Starting(); _apparel = TargetThingA as Apparel; _duration = (int)(_apparel.GetStatValue(StatDefOf.EquipDelay) * 60f); List <Apparel> wornApparel = pawn.apparel.WornApparel; for (int num = wornApparel.Count - 1; num >= 0; num--) { if (!ApparelUtility.CanWearTogether(_apparel.def, wornApparel[num].def, pawn.RaceProps.body)) { _duration += (int)(wornApparel[num].GetStatValue(StatDefOf.EquipDelay) * 60f); } } }
public void UpdateResists() { float envResist = 0; List <Apparel> wornApparels = pawn.apparel.WornApparel; envResist += pawn.GetStatValue(StatDef.Named("ArmorRating_Enviromental")); for (int i = 0; i < wornApparels.Count; i++) { Apparel wornApparel = wornApparels[i]; envResist += wornApparel.GetStatValue(StatDef.Named("ArmorRating_Enviromental")); } //Log.Message(pawn + " ArmorRating_Enviromental = " + envResist); pawn.TryMakeImmune(envResist, 1, HediffDefOf.ToxicImmunity); Hediff hediff_OxygenAtmosphere = pawn.health.hediffSet.hediffs.Find((Hediff x) => x.def == HediffDefOf.OxygenAtmosphere); if (envResist < minEnvResist) { if (pawn.IsColonist || pawn.IsPrisoner) { if (hediff_OxygenAtmosphere != null) { hediff_OxygenAtmosphere.Severity += 0.001f; } else { pawn.health.AddHediff(HediffDefOf.OxygenAtmosphere); //Hediff hediff = pawn.health.hediffSet.hediffs.Find((Hediff x) => x.def == HediffDefOf.OxygenAtmosphere); //float severity = Rand.Range(10, 100); //hediff.Severity = severity / 1000; } } } else { if (hediff_OxygenAtmosphere != null) { hediff_OxygenAtmosphere.Severity -= 0.001f; if (hediff_OxygenAtmosphere.Severity <= 0.001f) { pawn.health.RemoveHediff(hediff_OxygenAtmosphere); } } } }
/// <summary> /// Draw overall armor in a format as "Sharp 100 Rha", wihout the double quotes /// </summary> /// <param name="selPawn"></param> /// <param name="curY"></param> /// <param name="width"></param> /// <param name="stat"></param> /// <param name="label"></param> /// <param name="unit"></param> public static void TryDrawOverallArmor(Pawn selPawn, ref float curY, float width, StatDef stat, string label, string unit) { if (selPawn.RaceProps.body != BodyDefOf.Human) { return; } float num = 0f; List <Apparel> wornApparel = selPawn.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { num += wornApparel[i].GetStatValue(stat, true) * wornApparel[i].def.apparel.HumanBodyCoverage; } if (num > 0.005f) { Rect rect = new Rect(0f, curY, width, _standardLineHeight); List <BodyPartRecord> bpList = selPawn.RaceProps.body.AllParts; string text = ""; for (int i = 0; i < bpList.Count; i++) { float armorValue = 0f; BodyPartRecord part = bpList[i]; if (part.depth == BodyPartDepth.Outside && (part.coverage >= 0.1 || part.def == BodyPartDefOf.Eye || part.def == BodyPartDefOf.Neck)) { text += part.LabelCap + ": "; for (int j = wornApparel.Count - 1; j >= 0; j--) { Apparel apparel = wornApparel[j]; if (apparel.def.apparel.CoversBodyPart(part)) { armorValue += apparel.GetStatValue(stat, true); } } text += FormatArmorValue(armorValue, unit) + "\n"; } } TooltipHandler.TipRegion(rect, text); // Draw Label Widgets.Label(rect, label.Truncate(200f, null)); // Draw armor value rect.xMin += 200; Widgets.Label(rect, FormatArmorValue(num, unit)); curY += _standardLineHeight; } }
// RimWorld.ITab_Pawn_Gear private void TryDrawOverallArmor(ref float curY, float width, StatDef stat, string label) { if (SelPawnForGear.RaceProps.body != BodyDefOf.Human) { return; } float num = 0f; List <Apparel> wornApparel = SelPawnForGear.apparel.WornApparel; for (int i = 0; i < wornApparel.Count; i++) { num += Mathf.Clamp01(wornApparel[i].GetStatValue(stat, true)) * wornApparel[i].def.apparel.HumanBodyCoverage; } num = Mathf.Clamp01(num); if (num > 0.005f) { Rect rect = new Rect(0f, curY, width, _standardLineHeight); BodyPartRecord bpr = new BodyPartRecord(); List <BodyPartRecord> bpList = SelPawnForGear.RaceProps.body.AllParts; string text = ""; for (int i = 0; i < bpList.Count; i++) { float armorValue = 0f; BodyPartRecord part = bpList[i]; if (part.depth == BodyPartDepth.Outside && (part.coverage >= 0.1 || (part.def == BodyPartDefOf.Eye || part.def == BodyPartDefOf.Neck))) { text += part.LabelCap + ": "; for (int j = wornApparel.Count - 1; j >= 0; j--) { Apparel apparel = wornApparel[j]; if (apparel.def.apparel.CoversBodyPart(part)) { armorValue += Mathf.Clamp01(apparel.GetStatValue(stat, true)); } } text += Mathf.Clamp01(armorValue).ToStringPercent() + "\n"; } } TooltipHandler.TipRegion(rect, text); Widgets.Label(rect, label.Truncate(200f, null)); rect.xMin += 200; Widgets.Label(rect, num.ToStringPercent()); curY += _standardLineHeight; } }
public float GetStatValue(Apparel apparel, Saveable_StatDef stat) { float baseStat = apparel.GetStatValue(stat.statDef, true); float currentStat = baseStat; currentStat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.statDef); PawnCalcForApparel.DoApparelScoreRawStatsHandlers(pawn, apparel, stat.statDef, ref currentStat); if (baseStat == 0) { return(currentStat); } else { return(currentStat / baseStat); } }
private static bool PawnWearingRelevantGear(StatRequest req, Pawn pawn, StatDef apparelStat) { if (pawn.apparel != null) { for (int i = 0; i < pawn.apparel.WornApparel.Count; i++) { Apparel apparel = pawn.apparel.WornApparel[i]; if (apparel.GetStatValue(apparelStat, true) != 0f) { return(true); } if (StatWorker.StatOffsetFromGear(apparel, apparelStat) != 0f) { return(true); } } } return(false); }
public static void ApparelScoreRaw_Postfix(Pawn pawn, Apparel ap, ref float __result) { //NeededWarmth neededCold = PawnApparelGenerator.CalculateNeededWarmth(pawn, pawn.Map.Tile, GenLocalDate.Twelfth(pawn)); float num = GenTemperature.AverageTemperatureAtTileForTwelfth(pawn.Map.Tile, GenLocalDate.Twelfth(pawn)); SimpleCurve InsulationHeatScoreFactorCurve_NeedCold = new SimpleCurve { { new CurvePoint(0f, 1f), true }, { new CurvePoint(30f, 8f), true } }; // This version uses ComfyTemperatureMax to find if needCool, not comfyTemperatureMin if (num < pawn.def.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax, null) - 4f) { float statValue = ap.GetStatValue(StatDefOf.Insulation_Heat, true); float coldFactor = 1f; coldFactor *= InsulationHeatScoreFactorCurve_NeedCold.Evaluate(statValue); __result *= coldFactor; } //if (neededCold == NeededWarmth.Cool) //{ // float statValue = ap.GetStatValue(StatDefOf.Insulation_Heat, true); // float coldFactor = 1f; // coldFactor *= InsulationHeatScoreFactorCurve_NeedCold.Evaluate(statValue); // __result *= coldFactor; //} }
public static bool IgnoreInsulationWhenWet(StatRequest req, ref float val, StatDef ___apparelStat, bool ___subtract) { if (___apparelStat != StatDefOf.Insulation_Cold || !___subtract) { return(true); } if (req.HasThing && req.Thing != null) { Pawn pawn = req.Thing as Pawn; if (pawn != null) { Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(DefOf_WaterIsCold.WetCold, false); if (firstHediffOfDef == null) { return(true); } float multiplier = Mathf.Clamp(1f - firstHediffOfDef.Severity, ModSettings_WaterIsCold.wetInsFactor / 100f, 1f); if (pawn.apparel != null && multiplier > 0) { for (int i = 0; i < pawn.apparel.WornApparel.Count; i++) { Apparel apparel = pawn.apparel.WornApparel[i]; float num = apparel.GetStatValue(___apparelStat, true); num += StatWorker.StatOffsetFromGear(apparel, ___apparelStat); if (!apparel.def.HasModExtension <WaterGear>()) { num *= multiplier; } val -= num; } } return(false); } } return(true); }
public override void Notify_Starting() { base.Notify_Starting(); apparel = TargetThingA as Apparel; mode = job.count; duration = (int)(apparel.GetStatValue(StatDefOf.EquipDelay) * 60f); if (mode > 0) { List <Apparel> wornApparel = pawn.apparel.WornApparel; int count = wornApparel.Count; Log.Message("wornApparel.Count: " + wornApparel.Count); Log.Message("Count: " + count); for (int num = 0; num < count; ++num) { Log.Message("wornApparel.Count2: " + wornApparel.Count); Log.Message("num: " + num); if (!ApparelUtility.CanWearTogether(apparel.def, wornApparel[num].def, pawn.RaceProps.body)) { duration += (int)(wornApparel[num].GetStatValue(StatDefOf.EquipDelay) * 60f); } } } }
protected override IEnumerable <Toil> MakeNewToils() { yield return(Toils_General.Wait(10, TargetIndex.None)); yield return(new Toil { initAction = delegate() { Thing MarkedThing = CompUnloadChecker.getFirstMarked(pawn); if (MarkedThing == null) { EndJobWith(JobCondition.Succeeded); return; } // if (pawn.equipment.Contains(MarkedThing)) { Equipment = (ThingWithComps)MarkedThing; Apparel = null; } else { Apparel = pawn.apparel.Contains(MarkedThing) ? (Apparel)MarkedThing : null; Equipment = null; } ThingCount firstUnloadableThing = MarkedThing == null ? default(ThingCount) : new ThingCount(MarkedThing, MarkedThing.stackCount); IntVec3 c; if (!StoreUtility.TryFindStoreCellNearColonyDesperate(firstUnloadableThing.Thing, pawn, out c)) { Thing thing; pawn.inventory.innerContainer.TryDrop(firstUnloadableThing.Thing, ThingPlaceMode.Near, firstUnloadableThing.Count, out thing, null, null); EndJobWith(JobCondition.Succeeded); return; } job.SetTarget(TargetIndex.A, firstUnloadableThing.Thing); job.SetTarget(TargetIndex.B, c); countToDrop = firstUnloadableThing.Count; } }); yield return(Toils_Reserve.Reserve(TargetIndex.B, 1, -1, null)); yield return(Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.Touch).FailOnDestroyedOrNull(TargetIndex.A).FailOn(delegate() { return !stillUnloadable(pawn.CurJob.GetTarget(TargetIndex.A).Thing); })); //preintiating unequip-delay Toil unequip = new Toil { initAction = delegate() { if (Equipment != null) { pawn.equipment.TryTransferEquipmentToContainer(Equipment, pawn.inventory.innerContainer); } else if (Apparel != null) { ThingOwner <Apparel> a = Traverse.Create(pawn.apparel).Field("wornApparel").GetValue <ThingOwner <Apparel> >(); a.TryTransferToContainer(Apparel, pawn.inventory.innerContainer); } } }; //if equiped, wait unequipping time Toil wait = new Toil(); wait.initAction = delegate() { ticker = 0; duration = Apparel != null?Apparel.GetStatValue(StatDefOf.EquipDelay, true) * 60f : Equipment != null ? 30 : 0; pawn.pather.StopDead(); }; wait.tickAction = delegate() { if (ticker >= duration) { ReadyForNextToil(); } ticker++; }; wait.defaultCompleteMode = ToilCompleteMode.Never; wait.WithProgressBar(TargetIndex.A, () => ticker / duration); //unequip to inventory yield return(wait); yield return(unequip); //hold in hands yield return(new Toil { initAction = delegate() { Thing thing = job.GetTarget(TargetIndex.A).Thing; CompUnloadChecker c = thing.TryGetComp <CompUnloadChecker>(); if (c == null || !c.ShouldUnload) { EndJobWith(JobCondition.Incompletable); return; } if (thing == null || !pawn.inventory.innerContainer.Contains(thing)) { EndJobWith(JobCondition.Incompletable); return; } if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !thing.def.EverStorable(false)) { pawn.inventory.innerContainer.TryDrop(thing, ThingPlaceMode.Near, countToDrop, out thing, null, null); EndJobWith(JobCondition.Succeeded); } else { pawn.inventory.innerContainer.TryTransferToContainer(thing, pawn.carryTracker.innerContainer, countToDrop, out thing, true); job.count = countToDrop; job.SetTarget(TargetIndex.A, thing); } thing.SetForbidden(false, false); } }); Toil carryToCell = Toils_Haul.CarryHauledThingToCell(TargetIndex.B).FailOnDestroyedOrNull(TargetIndex.A).FailOn(delegate() { return(!stillUnloadable(pawn.CurJob.GetTarget(TargetIndex.A).Thing)); }); yield return(carryToCell); yield return(Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, carryToCell, true)); yield break; }
public float GetStatValue(Apparel apparel, Saveable_StatDef stat) { float baseStat = apparel.GetStatValue(stat.statDef, true); float currentStat = baseStat; currentStat += apparel.def.equippedStatOffsets.GetStatOffsetFromList(stat.statDef); PawnCalcForApparel.DoApparelScoreRawStatsHandlers(pawn, apparel, stat.statDef, ref currentStat); if (baseStat == 0) return currentStat; else return currentStat / baseStat; }
public float ApparelScoreRaw([NotNull] Apparel ap) { if (RawScoreDict.ContainsKey(ap)) { return(RawScoreDict[ap]); } // only allow shields to be considered if a primary weapon is equipped and is melee var thisPawn = _pawn; if (ap.def.thingClass == typeof(ShieldBelt) && thisPawn.equipment.Primary?.def.IsRangedWeapon == true) { return(-1f); } // Fail safe to prevent pawns get out of the regular temperature. // Might help making pawn drop equipped apparel if it's too cold/warm. // this.GetInsulationStats(ap, out float insulationCold, out float insulationHeat); // FloatRange temperatureRange = this.pawn.ComfortableTemperatureRange(); // if (ap.Wearer != thisPawn) // { // temperatureRange.min += insulationCold; // temperatureRange.max += insulationHeat; // } // if (temperatureRange.min > 12 && insulationCold > 0 || temperatureRange.max < 32 && insulationHeat < 0) // { // return -3f; // } // relevant apparel stats var entry = GetAllOffsets(ap); var statBases = entry.StatBases; var equippedOffsets = entry.EquippedOffsets; var infusedOffsets = entry.InfusedOffsets; // start score at 1 float score = 1; // add values for each statdef modified by the apparel var stats = thisPawn.GetApparelStatCache().StatCache; foreach (var statPriority in stats.Where(statPriority => statPriority != null)) { var stat = statPriority.Stat; if (statBases.Contains(stat)) { var apStat = ap.GetStatValue(stat); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, apStat, ref score); } else { // add stat to base score before offsets are handled // (the pawn's apparel stat cache always has armors first as it is initialized with it). score += apStat * statPriority.Weight; } } // equipped offsets, e.g. movement speeds if (equippedOffsets.Contains(stat)) { var apStat = ap.GetEquippedStatValue(_pawn, stat); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, apStat, ref score); } else { score += apStat * statPriority.Weight; } // multiply score to favour items with multiple offsets // score *= adjusted; // debug.AppendLine( statWeightPair.Key.LabelCap + ": " + score ); } // infusions if (!infusedOffsets.Contains(stat)) { continue; } // float statInfused = StatInfused(infusionSet, statPriority, ref dontcare); DoApparelScoreRaw_PawnStatsHandlers(ap, stat, out var statInfused); if (SpecialStats.Contains(stat)) { CalculateScoreForSpecialStats(ap, statPriority, thisPawn, statInfused, ref score); } else { // Bug with Infused and "Ancient", it completely kills the pawn's armor if (statInfused < 0 && (stat == StatDefOf.ArmorRating_Blunt || stat == StatDefOf.ArmorRating_Sharp)) { score = -2f; return(score); } score += statInfused * statPriority.Weight; } } score += ap.GetSpecialApparelScoreOffset(); score += ApparelScoreRaw_ProtectionBaseStat(ap); // offset for apparel hitpoints if (ap.def.useHitPoints) { var x = ap.HitPoints / (float)ap.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); } if (ap.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought_NewTemp(thisPawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } } score *= ApparelScoreRaw_Temperature(ap); RawScoreDict.Add(ap, score); return(score); }
public static float ApparelScoreRaw( Apparel apparel, Pawn pawn ) { // relevant apparel stats HashSet<StatDef> equippedOffsets = new HashSet<StatDef>(); if ( apparel.def.equippedStatOffsets != null ) { foreach ( StatModifier equippedStatOffset in apparel.def.equippedStatOffsets ) { equippedOffsets.Add( equippedStatOffset.stat ); } } HashSet<StatDef> statBases = new HashSet<StatDef>(); if ( apparel.def.statBases != null ) { foreach ( StatModifier statBase in apparel.def.statBases ) { statBases.Add( statBase.stat ); } } // start score at 1 float score = 1; // make infusions ready InfusionSet infusions; bool infused = false; StatMod mod; InfusionDef prefix = null; InfusionDef suffix = null; if ( apparel.TryGetInfusions( out infusions ) ) { infused = true; prefix = infusions.Prefix.ToInfusionDef(); suffix = infusions.Suffix.ToInfusionDef(); } // add values for each statdef modified by the apparel foreach( ApparelStatCache.StatPriority statPriority in pawn.GetApparelStatCache().StatCache ) { // statbases, e.g. armor if ( statBases.Contains( statPriority.Stat ) ) { // add stat to base score before offsets are handled ( the pawn's apparel stat cache always has armors first as it is initialized with it). score += apparel.GetStatValue( statPriority.Stat ) * statPriority.Weight; } // equipped offsets, e.g. movement speeds if ( equippedOffsets.Contains( statPriority.Stat ) ) { // base value float norm = apparel.GetStatValue( statPriority.Stat ); float adjusted = norm; // add offset adjusted += apparel.def.equippedStatOffsets.GetStatOffsetFromList( statPriority.Stat ) * statPriority.Weight; // normalize if ( norm != 0 ) { adjusted /= norm; } // multiply score to favour items with multiple offsets score *= adjusted; //debug.AppendLine( statWeightPair.Key.LabelCap + ": " + score ); } // infusions if( infused ) { // prefix if ( !infusions.PassPre && prefix.GetStatValue( statPriority.Stat, out mod ) ) { score += mod.offset * statPriority.Weight; score += score * ( mod.multiplier - 1 ) * statPriority.Weight; //debug.AppendLine( statWeightPair.Key.LabelCap + " infusion: " + score ); } if ( !infusions.PassSuf && suffix.GetStatValue( statPriority.Stat, out mod ) ) { score += mod.offset * statPriority.Weight; score += score * ( mod.multiplier - 1 ) * statPriority.Weight; //debug.AppendLine( statWeightPair.Key.LabelCap + " infusion: " + score ); } } } // offset for apparel hitpoints if ( apparel.def.useHitPoints ) { // durability on 0-1 scale float x = apparel.HitPoints / (float)apparel.MaxHitPoints; score *= HitPointsPercentScoreFactorCurve.Evaluate( x ); } // temperature FloatRange targetTemperatures = pawn.GetApparelStatCache().TargetTemperatures; float minComfyTemperature = pawn.GetStatValue( StatDefOf.ComfyTemperatureMin ); float maxComfyTemperature = pawn.GetStatValue( StatDefOf.ComfyTemperatureMax ); // offsets on apparel float insulationCold = apparel.GetStatValue( StatDefOf.Insulation_Cold ); float insulationHeat = apparel.GetStatValue( StatDefOf.Insulation_Heat ); // offsets on apparel infusions if( infused ) { // prefix if( !infusions.PassPre && prefix.GetStatValue( StatDefOf.ComfyTemperatureMin, out mod ) ) { insulationCold += mod.offset; } if( !infusions.PassPre && prefix.GetStatValue( StatDefOf.ComfyTemperatureMax, out mod ) ) { insulationHeat += mod.offset; } // suffix if( !infusions.PassSuf && suffix.GetStatValue( StatDefOf.ComfyTemperatureMin, out mod ) ) { insulationCold += mod.offset; } if( !infusions.PassSuf && suffix.GetStatValue( StatDefOf.ComfyTemperatureMax, out mod ) ) { insulationHeat += mod.offset; } } // if this gear is currently worn, we need to make sure the contribution to the pawn's comfy temps is removed so the gear is properly scored if ( pawn.apparel.WornApparel.Contains( apparel ) ) { minComfyTemperature -= insulationCold; maxComfyTemperature -= insulationHeat; } // now for the interesting bit. float temperatureScoreOffset = 0f; float tempWeight = pawn.GetApparelStatCache().TemperatureWeight; float neededInsulation_Cold = targetTemperatures.TrueMin - minComfyTemperature; // isolation_cold is given as negative numbers < 0 means we're underdressed float neededInsulation_Warmth = targetTemperatures.TrueMax - maxComfyTemperature; // isolation_warm is given as positive numbers. // currently too cold if ( neededInsulation_Cold < 0 ) { temperatureScoreOffset += -insulationCold * tempWeight; } // currently warm enough else { // this gear would make us too cold if ( insulationCold > neededInsulation_Cold ) { temperatureScoreOffset += ( neededInsulation_Cold - insulationCold ) * tempWeight; } } // currently too warm if( neededInsulation_Warmth > 0 ) { temperatureScoreOffset += insulationHeat * tempWeight; } // currently cool enough else { // this gear would make us too warm if( insulationHeat < neededInsulation_Warmth ) { temperatureScoreOffset += -( neededInsulation_Warmth - insulationHeat ) * tempWeight; } } // adjust for temperatures score += temperatureScoreOffset / 10f; return score; }
/// <summary> /// Get bulk value for <paramref name="apparel"/>. /// </summary> /// <param name="apparel"> Apparel to inspect. </param> /// <returns> WornBulk value on <paramref name="apparel"/>. </returns> public static float WornBulkFor(Apparel apparel) { return(apparel.GetStatValue(CE_StatDefOf.WornBulk)); }
public static float ApparelScoreRaw(Pawn pawn, Apparel ap) { float num = 0.1f + ap.def.apparel.scoreOffset; float num2 = ap.GetStatValue(StatDefOf.ArmorRating_Sharp) + ap.GetStatValue(StatDefOf.ArmorRating_Blunt) + ap.GetStatValue(StatDefOf.ArmorRating_Heat); num += num2; if (ap.def.useHitPoints) { float x = (float)ap.HitPoints / (float)ap.MaxHitPoints; num *= HitPointsPercentScoreFactorCurve.Evaluate(x); } num += ap.GetSpecialApparelScoreOffset(); float num3 = 1f; //if (neededWarmth == NeededWarmth.Warm) //{ // float statValue = ap.GetStatValue(StatDefOf.Insulation_Cold); // num3 *= InsulationColdScoreFactorCurve_NeedWarm.Evaluate(statValue); //} num *= num3; if (ap.WornByCorpse && (pawn == null || ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.DeadMansApparel, checkIfNullified: true))) { num -= 0.5f; if (num > 0f) { num *= 0.1f; } } if (ap.Stuff == ThingDefOf.Human.race.leatherDef) { if (pawn == null || ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.HumanLeatherApparelSad, checkIfNullified: true)) { num -= 0.5f; if (num > 0f) { num *= 0.1f; } } if (pawn != null && ThoughtUtility.CanGetThought(pawn, ThoughtDefOf.HumanLeatherApparelHappy, checkIfNullified: true)) { num += 0.12f; } } if (pawn != null && !ap.def.apparel.CorrectGenderForWearing(pawn.gender)) { num *= 0.01f; } if (pawn != null && pawn.royalty != null && pawn.royalty.AllTitlesInEffectForReading.Count > 0) { tmpAllowedApparels.Clear(); tmpRequiredApparels.Clear(); tmpBodyPartGroupsWithRequirement.Clear(); QualityCategory qualityCategory = QualityCategory.Awful; foreach (RoyalTitle item in pawn.royalty.AllTitlesInEffectForReading) { if (item.def.requiredApparel != null) { for (int i = 0; i < item.def.requiredApparel.Count; i++) { tmpAllowedApparels.AddRange(item.def.requiredApparel[i].AllAllowedApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpRequiredApparels.AddRange(item.def.requiredApparel[i].AllRequiredApparelForPawn(pawn, ignoreGender: false, includeWorn: true)); tmpBodyPartGroupsWithRequirement.AddRange(item.def.requiredApparel[i].bodyPartGroupsMatchAny); } } if ((int)item.def.requiredMinimumApparelQuality > (int)qualityCategory) { qualityCategory = item.def.requiredMinimumApparelQuality; } } bool num4 = ap.def.apparel.bodyPartGroups.Any((BodyPartGroupDef bp) => tmpBodyPartGroupsWithRequirement.Contains(bp)); if (ap.TryGetQuality(out QualityCategory qc) && (int)qc < (int)qualityCategory) { num *= 0.25f; } if (num4) { foreach (ThingDef tmpRequiredApparel in tmpRequiredApparels) { tmpAllowedApparels.Remove(tmpRequiredApparel); } if (tmpAllowedApparels.Contains(ap.def)) { num *= 10f; } if (tmpRequiredApparels.Contains(ap.def)) { num *= 25f; } } } return(num); }
/// <summary> /// When notified job is about to start, calculate unequip delay for underlying apparel. /// </summary> public override void Notify_Starting() { base.Notify_Starting(); _apparel = TargetThingA as Apparel; _duration = (int)(_apparel.GetStatValue(StatDefOf.EquipDelay) * 60f); }
public float CalculateApparelScoreRawInsulationColdAjust(Apparel ap) { float num3 = 1f; if (this.needWarmCurve != null) { float statValueAbstract = ap.GetStatValue(StatDefOf.Insulation_Cold); num3 *= this.needWarmCurve.Evaluate(statValueAbstract); } if (this.needCoolCurve != null) { float statValueAbstract = ap.GetStatValue(StatDefOf.Insulation_Heat); num3 *= this.needCoolCurve.Evaluate(statValueAbstract); } return num3; }
public static float ApparelScoreRaw(Apparel apparel, Pawn pawn) { // relevant apparel stats HashSet <StatDef> equippedOffsets = new HashSet <StatDef>(); if (apparel.def.equippedStatOffsets != null) { foreach (StatModifier equippedStatOffset in apparel.def.equippedStatOffsets) { equippedOffsets.Add(equippedStatOffset.stat); } } HashSet <StatDef> statBases = new HashSet <StatDef>(); if (apparel.def.statBases != null) { foreach (StatModifier statBase in apparel.def.statBases) { statBases.Add(statBase.stat); } } // start score at 1 float score = 1; // make infusions ready InfusionSet infusions; bool infused = false; StatMod mod; InfusionDef prefix = null; InfusionDef suffix = null; if (apparel.TryGetInfusions(out infusions)) { infused = true; prefix = infusions.Prefix.ToInfusionDef(); suffix = infusions.Suffix.ToInfusionDef(); } // add values for each statdef modified by the apparel foreach (ApparelStatCache.StatPriority statPriority in pawn.GetApparelStatCache().StatCache) { // statbases, e.g. armor if (statBases.Contains(statPriority.Stat)) { // add stat to base score before offsets are handled ( the pawn's apparel stat cache always has armors first as it is initialized with it). score += apparel.GetStatValue(statPriority.Stat) * statPriority.Weight; } // equipped offsets, e.g. movement speeds if (equippedOffsets.Contains(statPriority.Stat)) { // base value float norm = apparel.GetStatValue(statPriority.Stat); float adjusted = norm; // add offset adjusted += apparel.def.equippedStatOffsets.GetStatOffsetFromList(statPriority.Stat) * statPriority.Weight; // normalize if (norm != 0) { adjusted /= norm; } // multiply score to favour items with multiple offsets score *= adjusted; //debug.AppendLine( statWeightPair.Key.LabelCap + ": " + score ); } // infusions if (infused) { // prefix if (!infusions.PassPre && prefix.GetStatValue(statPriority.Stat, out mod)) { score += mod.offset * statPriority.Weight; score += score * (mod.multiplier - 1) * statPriority.Weight; //debug.AppendLine( statWeightPair.Key.LabelCap + " infusion: " + score ); } if (!infusions.PassSuf && suffix.GetStatValue(statPriority.Stat, out mod)) { score += mod.offset * statPriority.Weight; score += score * (mod.multiplier - 1) * statPriority.Weight; //debug.AppendLine( statWeightPair.Key.LabelCap + " infusion: " + score ); } } } // offset for apparel hitpoints if (apparel.def.useHitPoints) { // durability on 0-1 scale float x = apparel.HitPoints / (float)apparel.MaxHitPoints; score *= HitPointsPercentScoreFactorCurve.Evaluate(x); } // temperature FloatRange targetTemperatures = pawn.GetApparelStatCache().TargetTemperatures; float minComfyTemperature = pawn.GetStatValue(StatDefOf.ComfyTemperatureMin); float maxComfyTemperature = pawn.GetStatValue(StatDefOf.ComfyTemperatureMax); // offsets on apparel float insulationCold = apparel.GetStatValue(StatDefOf.Insulation_Cold); float insulationHeat = apparel.GetStatValue(StatDefOf.Insulation_Heat); // offsets on apparel infusions if (infused) { // prefix if (!infusions.PassPre && prefix.GetStatValue(StatDefOf.ComfyTemperatureMin, out mod)) { insulationCold += mod.offset; } if (!infusions.PassPre && prefix.GetStatValue(StatDefOf.ComfyTemperatureMax, out mod)) { insulationHeat += mod.offset; } // suffix if (!infusions.PassSuf && suffix.GetStatValue(StatDefOf.ComfyTemperatureMin, out mod)) { insulationCold += mod.offset; } if (!infusions.PassSuf && suffix.GetStatValue(StatDefOf.ComfyTemperatureMax, out mod)) { insulationHeat += mod.offset; } } // if this gear is currently worn, we need to make sure the contribution to the pawn's comfy temps is removed so the gear is properly scored if (pawn.apparel.WornApparel.Contains(apparel)) { minComfyTemperature -= insulationCold; maxComfyTemperature -= insulationHeat; } // now for the interesting bit. float temperatureScoreOffset = 0f; float tempWeight = pawn.GetApparelStatCache().TemperatureWeight; float neededInsulation_Cold = targetTemperatures.TrueMin - minComfyTemperature; // isolation_cold is given as negative numbers < 0 means we're underdressed float neededInsulation_Warmth = targetTemperatures.TrueMax - maxComfyTemperature; // isolation_warm is given as positive numbers. // currently too cold if (neededInsulation_Cold < 0) { temperatureScoreOffset += -insulationCold * tempWeight; } // currently warm enough else { // this gear would make us too cold if (insulationCold > neededInsulation_Cold) { temperatureScoreOffset += (neededInsulation_Cold - insulationCold) * tempWeight; } } // currently too warm if (neededInsulation_Warmth > 0) { temperatureScoreOffset += insulationHeat * tempWeight; } // currently cool enough else { // this gear would make us too warm if (insulationHeat < neededInsulation_Warmth) { temperatureScoreOffset += -(neededInsulation_Warmth - insulationHeat) * tempWeight; } } // adjust for temperatures score += temperatureScoreOffset / 10f; return(score); }
/// <summary> /// Calculates damage through armor, depending on damage type, target and natural resistance. Also calculates deflection and adjusts damage type and impacted body part accordingly. /// </summary> /// <param name="originalDinfo">The pre-armor damage info</param> /// <param name="pawn">The damaged pawn</param> /// <param name="hitPart">The pawn's body part that has been hit</param> /// <param name="shieldAbsorbed">Returns true if attack did not penetrate pawn's melee shield</param> /// <returns>If shot is deflected returns a new dinfo cloned from the original with damage amount, Def and ForceHitPart adjusted for deflection, otherwise a clone with only the damage adjusted</returns> public static DamageInfo GetAfterArmorDamage(DamageInfo originalDinfo, Pawn pawn, BodyPartRecord hitPart, out bool shieldAbsorbed) { shieldAbsorbed = false; if (originalDinfo.Def.armorCategory == null) { return(originalDinfo); } DamageInfo dinfo = new DamageInfo(originalDinfo); float dmgAmount = dinfo.Amount; bool involveArmor = dinfo.Def.harmAllLayersUntilOutside; bool isAmbientDamage = dinfo.IsAmbientDamage(); // In case of ambient damage (fire, electricity) we apply a percentage reduction formula based on the sum of all applicable armor if (isAmbientDamage) { dinfo.SetAmount(Mathf.CeilToInt(GetAmbientPostArmorDamage(dmgAmount, originalDinfo.Def.armorCategory.deflectionStat, pawn, hitPart))); return(dinfo); } float penAmount = GetPenetrationValue(originalDinfo); // Apply worn armor if (involveArmor && pawn.apparel != null && !pawn.apparel.WornApparel.NullOrEmpty()) { List <Apparel> apparel = pawn.apparel.WornApparel; // Check for shields first Apparel shield = apparel.FirstOrDefault(x => x is Apparel_Shield); if (shield != null) { // Determine whether the hit is blocked by the shield bool blockedByShield = false; if (!(dinfo.WeaponGear?.IsMeleeWeapon ?? false)) { var shieldDef = shield.def.GetModExtension <ShieldDefExtension>(); if (shieldDef == null) { Log.ErrorOnce("CE :: shield " + shield.def.ToString() + " is Apparel_Shield but has no ShieldDefExtension", shield.def.GetHashCode() + 12748102); } else { bool hasCoverage = shieldDef.PartIsCoveredByShield(hitPart, pawn); if (hasCoverage) { // Right arm is vulnerable during warmup/attack/cooldown blockedByShield = !((pawn.stances?.curStance as Stance_Busy)?.verb != null && hitPart.IsInGroup(CE_BodyPartGroupDefOf.RightArm)); } } } // Try to penetrate the shield if (blockedByShield && !TryPenetrateArmor(dinfo.Def, shield.GetStatValue(dinfo.Def.armorCategory.deflectionStat), ref penAmount, ref dmgAmount, shield)) { shieldAbsorbed = true; dinfo.SetAmount(0); // Apply secondary damage to shield var props = dinfo.WeaponGear.projectile as ProjectilePropertiesCE; if (props != null && !props.secondaryDamage.NullOrEmpty()) { foreach (SecondaryDamage sec in props.secondaryDamage) { if (shield.Destroyed) { break; } var secDinfo = sec.GetDinfo(); var pen = GetPenetrationValue(originalDinfo); var dmg = (float)secDinfo.Amount; TryPenetrateArmor(secDinfo.Def, shield.GetStatValue(secDinfo.Def.armorCategory.deflectionStat), ref pen, ref dmg, shield); } } return(dinfo); } } // Apparel is arranged in draw order, we run through reverse to go from Shell -> OnSkin for (int i = apparel.Count - 1; i >= 0; i--) { if (apparel[i].def.apparel.CoversBodyPart(hitPart) && !TryPenetrateArmor(dinfo.Def, apparel[i].GetStatValue(dinfo.Def.armorCategory.deflectionStat), ref penAmount, ref dmgAmount, apparel[i])) { // Hit was deflected, convert damage type dinfo = GetDeflectDamageInfo(dinfo, hitPart); i++; // We apply this piece of apparel twice on conversion, this means we can't use deflection on Blunt or else we get an infinite loop of eternal deflection } if (dmgAmount <= 0) { dinfo.SetAmount(0); return(dinfo); } } } // Apply natural armor List <BodyPartRecord> partsToHit = new List <BodyPartRecord>() { hitPart }; if (involveArmor) { BodyPartRecord curPart = hitPart; while (curPart.parent != null && curPart.depth == BodyPartDepth.Inside) { curPart = curPart.parent; partsToHit.Add(curPart); } } for (int i = partsToHit.Count - 1; i >= 0; i--) { BodyPartRecord curPart = partsToHit[i]; bool coveredByArmor = curPart.IsInGroup(CE_BodyPartGroupDefOf.CoveredByNaturalArmor); float partArmor = pawn.HealthScale * 0.05f; // How much armor is provided by sheer meat if (coveredByArmor) { partArmor += pawn.GetStatValue(dinfo.Def.armorCategory.deflectionStat); } float unused = dmgAmount; // Only apply damage reduction when penetrating armored body parts if (coveredByArmor ? !TryPenetrateArmor(dinfo.Def, partArmor, ref penAmount, ref dmgAmount) : !TryPenetrateArmor(dinfo.Def, partArmor, ref penAmount, ref unused)) { dinfo.SetForcedHitPart(curPart); /* * if(coveredByArmor && pawn.RaceProps.IsMechanoid) * { * // For Mechanoid natural armor, apply deflection and blunt armor * dinfo = GetDeflectDamageInfo(dinfo, curPart); * TryPenetrateArmor(dinfo.Def, partArmor, ref penAmount, ref dmgAmount); * } */ break; } if (dmgAmount <= 0) { dinfo.SetAmount(0); return(dinfo); } } dinfo.SetAmount(Mathf.CeilToInt(dmgAmount)); return(dinfo); }
public override void DoWindowContents(Rect inRect) { var conf = _pawn.GetApparelStatCache(); var conRect = new Rect(inRect); conRect.height -= 50f; BeginArea(conRect); // begin main group BeginVertical(); Label(GetTitle(), _headline); Text.Font = GameFont.Small; // GUI.BeginGroup(contentRect); var labelWidth = conRect.width - BaseValue - BaseValue - BaseValue - 48f; DrawLine("Status", labelWidth, "BaseMod", "Strength", "Score", _fontBold); Space(6f); Label(string.Empty, _whiteLine, Height(1)); Space(6f); var apparelEntry = conf.GetAllOffsets(_apparel); var equippedOffsets = apparelEntry.EquippedOffsets; var statBases = apparelEntry.StatBases; var infusedOffsets = apparelEntry.InfusedOffsets; _scrollPosition = BeginScrollView(_scrollPosition, Width(conRect.width)); // relevant apparel stats // start score at 1 float score = 1; // add values for each statdef modified by the apparel foreach (var statPriority in _pawn.GetApparelStatCache().StatCache .OrderBy(i => i.Stat.LabelCap)) { var stat = statPriority.Stat; string statLabel = stat.LabelCap; // statbases, e.g. armor // StatCache.DoApparelScoreRaw_PawnStatsHandlers(_pawn, _apparel, statPriority.Stat, ref currentStat); if (statBases.Contains(stat)) { var statValue = _apparel.GetStatValue(stat); var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { // statValue += StatCache.StatInfused(infusionSet, statPriority, ref baseInfused); statScore = statValue * statPriority.Weight; } score += statScore; DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (equippedOffsets.Contains(stat)) { var statValue = _apparel.GetEquippedStatValue(_pawn, stat); // statValue += StatCache.StatInfused(infusionSet, statPriority, ref equippedInfused); var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { statScore = statValue * statPriority.Weight; } score += statScore; DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); } if (!infusedOffsets.Contains(stat)) { continue; } { GUI.color = Color.green; // new Color(0.5f, 1f, 1f, 1f); // float statInfused = StatCache.StatInfused(infusionSet, statPriority, ref dontcare); ApparelStatCache.DoApparelScoreRaw_PawnStatsHandlers(_apparel, stat, out var statValue); var flag = true; var statScore = 0f; if (ApparelStatCache.SpecialStats.Contains(stat)) { ApparelStatCache.CalculateScoreForSpecialStats(_apparel, statPriority, _pawn, statValue, ref statScore); } else { // Bug with Infused and "Ancient", it completely kills the pawn's armor if (statValue < 0 && (stat == StatDefOf.ArmorRating_Blunt || stat == StatDefOf.ArmorRating_Sharp)) { score = -2f; flag = false; } statScore = statValue * statPriority.Weight; } DrawLine( statLabel, labelWidth, statValue.ToStringPercent("N1"), statPriority.Weight.ToString("N2"), statScore.ToString("N2")); GUI.color = Color.white; if (flag) { score += statScore; } else { break; } } } GUI.color = Color.white; // end upper group EndScrollView(); // begin lower group FlexibleSpace(); Space(6f); Label(string.Empty, _whiteLine, Height(1)); Space(6f); DrawLine(string.Empty, labelWidth, "Modifier", string.Empty, "Subtotal"); DrawLine("BasicStatusOfApparel".Translate(), labelWidth, "1.00", "+", score.ToString("N2")); var special = _apparel.GetSpecialApparelScoreOffset(); if (Math.Abs(special) > 0f) { score += special; DrawLine( "OutfitterSpecialScore".Translate(), labelWidth, special.ToString("N2"), "+", score.ToString("N2")); } var armor = ApparelStatCache.ApparelScoreRaw_ProtectionBaseStat(_apparel); if (Math.Abs(armor) > 0.01f) { score += armor; DrawLine("OutfitterArmor".Translate(), labelWidth, armor.ToString("N2"), "+", score.ToString("N2")); } if (_apparel.def.useHitPoints) { // durability on 0-1 scale var x = _apparel.HitPoints / (float)_apparel.MaxHitPoints; score *= ApparelStatsHelper.HitPointsPercentScoreFactorCurve.Evaluate(x); DrawLine( "OutfitterHitPoints".Translate(), labelWidth, x.ToString("N2"), "weighted", score.ToString("N2")); GUI.color = Color.white; } if (_apparel.WornByCorpse && ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.DeadMansApparel)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } DrawLine( "OutfitterWornByCorpse".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } if (_apparel.Stuff == ThingDefOf.Human.race.leatherDef) { if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelSad)) { score -= 0.5f; if (score > 0f) { score *= 0.1f; } } if (ThoughtUtility.CanGetThought_NewTemp(_pawn, ThoughtDefOf.HumanLeatherApparelHappy)) { score *= 2f; } DrawLine( "OutfitterHumanLeather".Translate(), labelWidth, "modified", "weighted", score.ToString("N2")); } var temperature = conf.ApparelScoreRaw_Temperature(_apparel); if (Math.Abs(temperature - 1f) > 0) { score *= temperature; DrawLine( "OutfitterTemperature".Translate(), labelWidth, temperature.ToString("N2"), "*", score.ToString("N2")); } DrawLine( "OutfitterTotal".Translate(), labelWidth, string.Empty, "=", conf.ApparelScoreRaw(_apparel).ToString("N2")); GUI.color = Color.white; Text.Anchor = TextAnchor.UpperLeft; // end main group EndVertical(); EndArea(); }
private static void ApplyInsulationScoring(Pawn pawn, Apparel apparel, ref float score) { #if DEBUG Log.Message("OutfitManager: Calculating scores for insulation", true); #endif if (pawn.apparel.WornApparel.Contains(apparel)) { score += 0f; } else { var currentRange = pawn.ComfortableTemperatureRange(); var candidateRange = currentRange; var seasonalTemp = pawn.Map.mapTemperature.SeasonalTemp; var targetRange = new FloatRange(seasonalTemp - TemperatureRangeOffset, seasonalTemp + TemperatureRangeOffset); var apparelOffset = new FloatRange(-apparel.GetStatValue(StatDefOf.Insulation_Cold), apparel.GetStatValue(StatDefOf.Insulation_Heat)); candidateRange.min += apparelOffset.min; candidateRange.max += apparelOffset.max; foreach (var wornApparel in pawn.apparel.WornApparel.Where(wornApparel => !ApparelUtility.CanWearTogether(apparel.def, wornApparel.def, pawn.RaceProps.body))) { var wornInsulationRange = new FloatRange(-wornApparel.GetStatValue(StatDefOf.Insulation_Cold), wornApparel.GetStatValue(StatDefOf.Insulation_Heat)); candidateRange.min -= wornInsulationRange.min; candidateRange.max -= wornInsulationRange.max; } var insulationScore = 0f; var coldBenefit = candidateRange.min <currentRange.min ? currentRange.min <= targetRange.min ? 0 : candidateRange.min <= targetRange.min && currentRange.min> targetRange.min ? currentRange.min - targetRange.min : currentRange.min - candidateRange.min : candidateRange.min <= targetRange.min ? 0 : currentRange.min <= targetRange.min && candidateRange.min > targetRange.min ? targetRange.min - candidateRange.min : currentRange.min - candidateRange.min; insulationScore += InsulationScoreCurve.Evaluate(coldBenefit); var heatBenefit = candidateRange.max < currentRange.max ? currentRange.max < targetRange.max ? candidateRange.max - currentRange.max : candidateRange.max < targetRange.max && currentRange.max >= targetRange.max ? candidateRange.max - targetRange.max : 0 : candidateRange.max < targetRange.max ? candidateRange.max - currentRange.max : currentRange.max < targetRange.max && candidateRange.max >= targetRange.max ? targetRange.max - currentRange.max : 0; insulationScore += InsulationScoreCurve.Evaluate(heatBenefit); #if DEBUG Log.Message( $"OutfitManager: target range: {targetRange}, current range: {currentRange}, candidate range: {candidateRange}", true); Log.Message( $"OutfitManager: cold benefit = {coldBenefit}, heat benefit = {heatBenefit}), insulation score = {insulationScore}", true); #endif score += insulationScore; } }