private static string ApparelPart(ApparelFlags effectMask, Comp_NightVision comp) { var builder = new StringBuilder(); builder.AppendLine(value: "StatsReport_RelevantGear".Translate()); var nvApparel = Settings.Store.NVApparel; foreach (Apparel app in comp.PawnsNVApparel ?? Enumerable.Empty <Apparel>()) { if (nvApparel.TryGetValue(key: app.def, value: out ApparelVisionSetting setting) && setting.HasEffect(effectMask)) { builder.AppendLine(value: app.LabelCap); } } return(builder.ToString()); }
/// <summary> /// Tries to find the nightvision comp of the given pawn. /// Returns null if the pawn is null or pawn does not have comp. /// </summary> /// <param name="pawn"></param> /// <returns>the pawn's comp or NULL</returns> public static Comp_NightVision CompFor(Pawn pawn) { if (pawn == null) { return(null); } if (pawn.GetHashCode() == cachedPawnHash) { return(cachedComp); } else if (pawn.TryGetComp <Comp_NightVision>() is Comp_NightVision comp) { cachedComp = comp; cachedPawnHash = pawn.GetHashCode(); return(comp); } else { return(null); } }
/// <summary> /// For the pawn's stat inspect tab. Cleaned up a bit, still about as elegant as a panda doing the can-can /// </summary> /// <param name="glow"></param> /// <param name="usedApparelSetting">if apparel had an effect</param> /// <param name="comp"></param> /// <param name="needsFinalValue">if final value is added externally or we need to add it</param> /// <returns></returns> private static string BasicExplanation(float glow, out bool usedApparelSetting, Comp_NightVision comp, bool needsFinalValue = false) { var nvsum = 0f; var pssum = 0f; var sum = 0f; float[] caps = LightModifiersBase.GetCapsAtGlow(glow: glow); var foundSomething = false; float effect; var basevalue = 0f; bool lowLight = glow.GlowIsDarkness(); usedApparelSetting = false; var explanation = new StringBuilder(); StringBuilder nvexplanation = new StringBuilder().AppendFormat( format: Str.ExpIntro, "", Str.MaxAtGlow(glow: glow), caps[2], Str.NightVision ).AppendLine(); StringBuilder psexplanation = new StringBuilder().AppendFormat( format: Str.ExpIntro, "", Str.MaxAtGlow(glow: glow), caps[3], Str.Photosens ).AppendLine(); explanation.AppendLine(); if (lowLight) { basevalue = Constants.DEFAULT_FULL_LIGHT_MULTIPLIER + (Constants.DEFAULT_ZERO_LIGHT_MULTIPLIER - Constants.DEFAULT_FULL_LIGHT_MULTIPLIER) * (0.3f - glow) / 0.3f; if (comp.ApparelGrantsNV) { foundSomething = true; } } else { basevalue = Constants.DEFAULT_FULL_LIGHT_MULTIPLIER; if (glow.GlowIsBright() && comp.ApparelNullsPS) { foundSomething = true; } } explanation.AppendFormat(format: " " + Str.MultiplierLine, arg0: "StatsReport_BaseValue".Translate(), arg1: basevalue).AppendLine() .AppendLine(); string StringToAppend; if (comp.NaturalLightModifiers.HasAnyModifier() && comp.NumberOfRemainingEyes > 0) { effect = comp.NaturalLightModifiers.GetEffectAtGlow(glow: glow); if (effect.IsNonTrivial()) { foundSomething = true; var NumToAdd = (float)Math.Round( value: effect * comp.NumberOfRemainingEyes, digits: Constants.NUMBER_OF_DIGITS, mode: Constants.ROUNDING ); StringToAppend = string.Format( format: " " + Str.ModifierLine, arg0: $"{comp.ParentPawn.def.LabelCap} {comp.RaceSightParts.First().LabelShort} x{comp.NumberOfRemainingEyes}", arg1: effect * comp.NumberOfRemainingEyes ); switch (comp.NaturalLightModifiers.Setting) { case VisionType.NVNightVision: nvsum += NumToAdd; nvexplanation.AppendLine(value: StringToAppend); break; case VisionType.NVPhotosensitivity: pssum += NumToAdd; psexplanation.AppendLine(value: StringToAppend); break; case VisionType.NVCustom: sum += NumToAdd; explanation.AppendLine(value: StringToAppend); break; } } } foreach (List <HediffDef> value in comp.PawnsNVHediffs.Values) { if (value.NullOrEmpty()) { continue; } var hediffLightMods = Settings.Store.HediffLightMods; foreach (HediffDef hediffDef in value) { if (hediffLightMods.TryGetValue(key: hediffDef, value: out Hediff_LightModifiers hediffSetting)) { effect = hediffSetting.GetEffectAtGlow(glow: glow, numOfEyesNormalisedFor: comp.EyeCount); if (effect.IsNonTrivial()) { foundSomething = true; effect = (float)Math.Round( value: effect, digits: Constants.NUMBER_OF_DIGITS, mode: Constants.ROUNDING ); StringToAppend = string.Format(format: " " + Str.ModifierLine, arg0: hediffDef.LabelCap, arg1: effect); switch (hediffSetting.IntSetting) { case VisionType.NVNightVision: nvsum += effect; nvexplanation.AppendLine(value: StringToAppend); break; case VisionType.NVPhotosensitivity: pssum += effect; psexplanation.AppendLine(value: StringToAppend); break; case VisionType.NVCustom: sum += effect; explanation.AppendLine(value: StringToAppend); break; } } } } } void AppendPreSumIfNeeded(ref bool needed) { if (!needed) { return; } explanation.AppendFormat( format: Str.MultiplierLine, arg0: "NVTotal".Translate() + " " + "NVMultiplier".Translate(), arg1: sum + basevalue ); explanation.AppendLine(); needed = false; } if (foundSomething) { if (nvsum.IsNonTrivial()) { explanation.Append(value: nvexplanation); explanation.AppendLine(); } if (pssum.IsNonTrivial()) { explanation.Append(value: psexplanation); explanation.AppendLine(); } sum += pssum + nvsum; explanation.AppendFormat(format: Str.ModifierLine, arg0: "NVTotal".Translate() + " " + "NVModifier".Translate(), arg1: sum); explanation.AppendLine(); var needed = true; if (!comp.CanCheat) { if (sum - Constants.NV_EPSILON > caps[0] || sum + Constants.NV_EPSILON < caps[1]) { AppendPreSumIfNeeded(needed: ref needed); explanation.AppendFormat( format: Str.Maxline, arg0: "NVTotal".Translate() + " ", arg1: "max".Translate(), arg2: sum > caps[0] ? caps[0] : caps[1] ); explanation.AppendLine(); } if (lowLight && comp.ApparelGrantsNV && sum + Constants.NV_EPSILON < caps[2]) { AppendPreSumIfNeeded(needed: ref needed); explanation.Append(value: "NVGearPresent".Translate(arg1: $"{basevalue + caps[2]:0%}")); usedApparelSetting = true; sum = caps[2]; } else if (comp.ApparelNullsPS && sum + Constants.NV_EPSILON < 0) { AppendPreSumIfNeeded(needed: ref needed); explanation.Append(value: "PSGearPresent".Translate(arg1: $"{Constants.DEFAULT_FULL_LIGHT_MULTIPLIER:0%}")); usedApparelSetting = true; sum = 0; } } explanation.AppendLine(); if (needsFinalValue) { sum += basevalue; explanation.AppendFormat( format: Str.MultiplierLine, arg0: "NVStatReport_FinalMulti".Translate(), arg1: sum > caps[0] + basevalue ? caps[0] + basevalue : sum < caps[1] + basevalue ? caps[1] + basevalue : sum ); } return(explanation.ToString()); } //Fallback if (needsFinalValue) { return(comp.FactorFromGlow(glow: glow).ToStringPercent()); } return(string.Empty); }
public static string ShortStatReport(float glow, Comp_NightVision comp) { return(BasicExplanation(glow: glow, usedApparelSetting: out _, comp: comp, needsFinalValue: true)); }
public static string CompleteStatReport(StatDef stat, ApparelFlags effectMask, Comp_NightVision comp, float relevantGlow) { float factorFromGlow = comp.FactorFromGlow(glow: relevantGlow); return(BasicExplanation(glow: relevantGlow, usedApparelSetting: out bool UsedApparel, comp: comp) + FinalValue(stat: stat, value: factorFromGlow) + (effectMask != ApparelFlags.None && UsedApparel ? ApparelPart(effectMask: effectMask, comp: comp) : "")); }
public static string CombatPart(Pawn pawn, Comp_NightVision comp) { var strHelper = new CombatStatStrHelper(); const float NoLight = 0f; const float FullLight = 1f; float noLightFactor = comp.FactorFromGlow(glow: NoLight); float fullLightFactor = comp.FactorFromGlow(glow: FullLight); strHelper.AddMainHeader(); if (Settings.CombatStore.RangedHitEffectsEnabled.Value) { if (ShowRangedEffectsForPawn(pawn)) { strHelper.AddLine(Str_Combat.ShootTargetAtGlow()); for (var i = 1; i <= 4; i++) { float hit = ShotReport.HitFactorFromShooter(caster: pawn, distance: i * 5); strHelper.AddLine( Str_Combat.ShotChanceTransform( distance: i * 5, hitChance: hit, nvResult: CombatHelpers.HitChanceGlowTransform(hitChance: hit, attGlowFactor: noLightFactor), psResult: CombatHelpers.HitChanceGlowTransform(hitChance: hit, attGlowFactor: fullLightFactor) ) ); } strHelper.NextLine(); } else { // TODO add line reporting why effects are not appearing } } if (Settings.CombatStore.MeleeHitEffectsEnabled.Value) { if (ShowMeleeEffectsForPawn(pawn)) { float pawnDodgeVal = pawn.GetStatValue(stat: Defs_Rimworld.MeleeDodgeStat); float meleeHit = pawn.GetStatValue(stat: Defs_Rimworld.MeleeHitStat, applyPostProcess: true); var caps = Settings.Store.MultiplierCaps; strHelper.AddLine(Str_Combat.StrikeTargetAtGlow()); strHelper.AddLine( Str_Combat.StrikeChanceTransform( hitChance: meleeHit, nvResult: CombatHelpers.HitChanceGlowTransform(hitChance: meleeHit, attGlowFactor: noLightFactor), psResult: CombatHelpers.HitChanceGlowTransform(hitChance: meleeHit, attGlowFactor: fullLightFactor) ) ); strHelper.NextLine(); strHelper.AddSurpriseAttackHeader(); /////////////////////////////////////////// //// Surprise attack stats at 0% light //// float noLightSurpAttChance = CombatHelpers.SurpriseAttackChance(atkGlowFactor: noLightFactor, defGlowFactor: caps.min); // attack vs pawn with minimum LM strHelper.AddSurpriseAttackRow(NoLight, noLightFactor, caps.min); // skip if we need more room to show dodge stats if (pawnDodgeVal.IsTrivial()) { //skip if chance was 0% vs pawn with min LM (as it won't be different if (noLightSurpAttChance.IsNonTrivial()) { // attack vs pawn with normal LM noLightSurpAttChance = CombatHelpers.SurpriseAttackChance(atkGlowFactor: noLightFactor, defGlowFactor: 1f); strHelper.AddSurpriseAttackRow(NoLight, noLightFactor, 1); // skip as above if (noLightSurpAttChance.IsNonTrivial()) { // attack vs pawn with max LM strHelper.AddSurpriseAttackRow(0, noLightFactor, caps.max); } } } //////////////////////////////////////////// ///////////////////////////////////////////// //// Surprise attack stats at 100% light //// // skip if we need more room to show dodge stats if (pawnDodgeVal.IsTrivial()) { // attack vs pawn with min LM strHelper.AddSurpriseAttackRow(fullLightFactor, fullLightFactor, caps.min); } // attack vs pawn with normal LM strHelper.AddSurpriseAttackRow(fullLightFactor, fullLightFactor, 1f); strHelper.NextLine(); ///////////////////////////////////////////// ///////////////////////////////////////////// //// Dodge Stats //// strHelper.AddDodgeHeader(); // This pawns chance to dodge when attacked // attacked by pawn with min LM in no light strHelper.AddDodgeRow(NoLight, caps.min, noLightFactor, pawnDodgeVal); // skip if pawns dodge value is zero if (pawnDodgeVal.IsNonTrivial()) { // attacked by pawn with normal LM in no light strHelper.AddDodgeRow(NoLight, 1f, noLightFactor, pawnDodgeVal); // attacked by pawn with max LM in no light strHelper.AddDodgeRow(NoLight, caps.max, noLightFactor, pawnDodgeVal); // attacked by pawn with min LM in no light strHelper.AddDodgeRow(FullLight, caps.min, fullLightFactor, pawnDodgeVal); } //attacked by pawn with normal LM in full light strHelper.AddDodgeRow(FullLight, 1, fullLightFactor, pawnDodgeVal); } } return(strHelper.ToString()); }