/// <summary> /// For use with misc DamageWorker functions /// </summary> public static int GetAfterArmorDamage(Pawn pawn, int amountInt, BodyPartRecord part, DamageInfo dinfo) { bool flag = false; return Utility.GetAfterArmorDamage(pawn, amountInt, part, dinfo, false, ref flag); }
protected abstract void PostSuccessfulApply(Pawn pawn, BodyPartRecord part, Pawn billDoer, List <Thing> ingredients, Bill bill);
public override void CompPostTick(ref float severityAdjustment) { base.CompPostTick(ref severityAdjustment); if (base.Pawn != null & base.parent != null) { if (!initialized) { initialized = true; this.Initialize(); } } this.age++; if (!this.Pawn.DestroyedOrNull() && !this.Pawn.Dead) { if (age > lastRegen + regenRate) { HealthUtility.AdjustSeverity(base.Pawn, this.Def, -0.3f); this.lastRegen = this.age; Pawn pawn = this.Pawn; TM_MoteMaker.ThrowRegenMote(pawn.DrawPos, pawn.Map, 1f); bool flag = TM_Calc.IsUndead(pawn); if (!flag) { ModOptions.SettingsRef settingsRef = new ModOptions.SettingsRef(); int num = 1; // + ver.level; if (settingsRef.AIHardMode && !pawn.IsColonist) { num = 2; } using (IEnumerator <BodyPartRecord> enumerator = pawn.health.hediffSet.GetInjuredParts().GetEnumerator()) { while (enumerator.MoveNext()) { BodyPartRecord rec = enumerator.Current; bool flag2 = num > 0; if (flag2) { int num2 = 1; // + ver.level; if (settingsRef.AIHardMode && !pawn.IsColonist) { num2 = 2; } IEnumerable <Hediff_Injury> arg_BB_0 = pawn.health.hediffSet.GetHediffs <Hediff_Injury>(); Func <Hediff_Injury, bool> arg_BB_1; arg_BB_1 = ((Hediff_Injury injury) => injury.Part == rec); foreach (Hediff_Injury current in arg_BB_0.Where(arg_BB_1)) { bool flag4 = num2 > 0; if (flag4) { bool flag5 = current.CanHealNaturally() && !current.IsPermanent(); if (flag5) { if (!pawn.IsColonist) { current.Heal(10f + (1.5f * hediffPwr)); } else { current.Heal(4f + (.5f * hediffPwr)); } num--; num2--; } } } } } } } else { TM_Action.DamageUndead(pawn, (2f + 1f * hediffPwr), null); } } } }
/// <summary>Tries to apply the given hediff to the given pawn</summary> /// <param name="pawn">The pawn.</param> /// <param name="hediff">The hediff.</param> /// <param name="partsToAffect">The parts to affect.</param> /// <param name="canAffectAnyLivePart">if set to <c>true</c> [can affect any live part].</param> /// <param name="countToAffect">The count to affect.</param> /// <param name="outAddedHediffs">The out added hediffs.</param> /// <returns></returns> public static bool TryApply(Pawn pawn, HediffDef hediff, List <BodyPartDef> partsToAffect = null, bool canAffectAnyLivePart = false, int countToAffect = 1, List <Hediff> outAddedHediffs = null) { try { if (canAffectAnyLivePart || partsToAffect != null) { bool result = false; for (int i = 0; i < countToAffect; i++) { IEnumerable <BodyPartRecord> source = pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null); if (partsToAffect != null) { source = from p in source where partsToAffect.Contains(p.def) select p; } if (canAffectAnyLivePart) { source = from p in source where p.def.alive select p; } source = from p in source where !pawn.health.hediffSet.HasHediff(hediff, p, false) && !pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(p) select p; _scratchList.Clear(); _scratchList.AddRange(source); //use a scratch list here, can't enumerate over IEnumerable more then once in all cases if (_scratchList.Count == 0) { break; } BodyPartRecord partRecord = _scratchList[0]; Hediff hediff2 = HediffMaker.MakeHediff(hediff, pawn, partRecord); pawn.health.AddHediff(hediff2, null, null, null); if (outAddedHediffs != null) { outAddedHediffs.Add(hediff2); } result = true; } return(result); } if (!pawn.health.hediffSet.HasHediff(hediff, false)) { Hediff hediff3 = HediffMaker.MakeHediff(hediff, pawn, null); pawn.health.AddHediff(hediff3, null, null, null); if (outAddedHediffs != null) { outAddedHediffs.Add(hediff3); } return(true); } return(false); } catch (Exception exception) { Log.Warning($"exception {exception.GetType().Name} caught while giving {hediff.defName} to {pawn.Name}, message follows \n{exception}"); return(false); } }
public override string GetLabelWhenUsedOn(Pawn pawn, BodyPartRecord part) { return(recipe.label); }
private static bool Prefix(HediffDef diseaseDef, out HediffDef immunityCause, BodyPartRecord part, ref float __result, Pawn ___pawn) { immunityCause = null; var diseaseImmunity = ___pawn.GetPawnExtensions()?.diseaseImmunity; if (diseaseImmunity != null && diseaseImmunity.hediffs.Contains(diseaseDef) != diseaseImmunity.restrict) { __result = 0f; return(false); } return(true); }
public void DrawAddButton() { if (RectButtonAdd.Contains(Event.current.mousePosition)) { GUI.color = Style.ColorButtonHighlight; } else { GUI.color = Style.ColorButton; } GUI.DrawTexture(RectButtonAdd, Textures.TextureButtonAdd); // Add button. if (Widgets.ButtonInvisible(RectButtonAdd, false)) { CustomPawn customPawn = PrepareCarefully.Instance.State.CurrentPawn; Action addEntryAction = () => { }; OptionsHealth healthOptions = PrepareCarefully.Instance.Providers.Health.GetOptions(customPawn); string selectedHediffType = this.selectedHediffType; RecipeDef selectedRecipe = null; InjuryOption selectedInjury = null; BodyPartRecord selectedBodyPart = null; bool bodyPartSelectionRequired = true; InjurySeverity selectedSeverity = null; Dialog_Options <InjurySeverity> severityDialog; Dialog_Options <BodyPartRecord> bodyPartDialog; Dialog_Options <InjuryOption> injuryOptionDialog; //Dialog_Options<RecipeDef> implantRecipeDialog; DialogManageImplants manageImplantsDialog; Dialog_Options <string> hediffTypeDialog; ResetDisabledInjuryOptions(customPawn); Action addInjuryAction = () => { if (bodyPartSelectionRequired) { AddInjuryToPawn(selectedInjury, selectedSeverity, selectedBodyPart); } else { if (selectedInjury.ValidParts != null && selectedInjury.ValidParts.Count > 0) { foreach (var p in selectedInjury.ValidParts) { var part = healthOptions.FindBodyPartsForDef(p).FirstOrDefault(); if (part != null) { AddInjuryToPawn(selectedInjury, selectedSeverity, part.Record); } else { Log.Warning("Could not find body part record for definition: " + p.defName); } } } else { AddInjuryToPawn(selectedInjury, selectedSeverity, null); } } }; severityDialog = new Dialog_Options <InjurySeverity>(severityOptions) { ConfirmButtonLabel = "EdB.PC.Common.Add".Translate(), CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(), HeaderLabel = "EdB.PC.Panel.Health.SelectSeverity".Translate(), NameFunc = (InjurySeverity option) => { if (!string.IsNullOrEmpty(option.Label)) { return(option.Label); } else { return(selectedInjury.HediffDef.LabelCap); } }, SelectedFunc = (InjurySeverity option) => { return(option == selectedSeverity); }, SelectAction = (InjurySeverity option) => { selectedSeverity = option; }, ConfirmValidation = () => { if (selectedSeverity == null) { return("EdB.PC.Error.MustSelectSeverity"); } else { return(null); } }, CloseAction = () => { addInjuryAction(); } }; bodyPartDialog = new Dialog_Options <BodyPartRecord>(null) { ConfirmButtonLabel = "EdB.PC.Common.Add".Translate(), CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(), HeaderLabel = "EdB.PC.Dialog.BodyPart.Header".Translate(), NameFunc = (BodyPartRecord option) => { return(option.LabelCap); }, SelectedFunc = (BodyPartRecord option) => { return(option == selectedBodyPart); }, SelectAction = (BodyPartRecord option) => { selectedBodyPart = option; }, EnabledFunc = (BodyPartRecord option) => { return(!disabledBodyParts.Contains(option)); }, ConfirmValidation = () => { if (selectedBodyPart == null) { return("EdB.PC.Dialog.BodyPart.Error.Required"); } else { return(null); } }, CloseAction = () => { if (selectedHediffType == HediffTypeInjury) { if (this.severityOptions.Count > 1) { Find.WindowStack.Add(severityDialog); } else { if (severityOptions.Count > 0) { selectedSeverity = this.severityOptions[0]; } addInjuryAction(); } } else if (selectedHediffType == HediffTypeImplant) { ImplantAdded(new Implant(selectedBodyPart, selectedRecipe)); } } }; injuryOptionDialog = new Dialog_Options <InjuryOption>(healthOptions.InjuryOptions) { ConfirmButtonLabel = "EdB.PC.Common.Next".Translate(), CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(), HeaderLabel = "EdB.PC.Dialog.Injury.Header".Translate(), NameFunc = (InjuryOption option) => { return(option.Label); }, SelectedFunc = (InjuryOption option) => { return(selectedInjury == option); }, SelectAction = (InjuryOption option) => { selectedInjury = option; if (option.ValidParts == null && !option.WholeBody) { bodyPartSelectionRequired = true; } else { bodyPartSelectionRequired = false; } }, EnabledFunc = (InjuryOption option) => { return(!disabledInjuryOptions.Contains(option)); }, ConfirmValidation = () => { if (selectedInjury == null) { return("EdB.PC.Dialog.Injury.Error.Required"); } else { return(null); } }, CloseAction = () => { ResetSeverityOptions(selectedInjury); if (bodyPartSelectionRequired) { bodyPartDialog.Options = healthOptions.BodyPartsForInjury(selectedInjury); ResetDisabledBodyParts(bodyPartDialog.Options, customPawn); Find.WindowStack.Add(bodyPartDialog); } else if (severityOptions.Count > 1) { Find.WindowStack.Add(severityDialog); } else { if (severityOptions.Count > 0) { selectedSeverity = this.severityOptions[0]; } addInjuryAction(); } } }; hediffTypeDialog = new Dialog_Options <string>(new string[] { HediffTypeInjury, HediffTypeImplant }) { ConfirmButtonLabel = "EdB.PC.Common.Next".Translate(), CancelButtonLabel = "EdB.PC.Common.Cancel".Translate(), NameFunc = (string type) => { return(("EdB.PC.Panel.Health." + type).Translate()); }, SelectedFunc = (string type) => { return(selectedHediffType == type); }, SelectAction = (string type) => { selectedHediffType = type; }, ConfirmValidation = () => { if (selectedHediffType == null) { return("EdB.PC.Panel.Health.Error.MustSelectOption"); } else { return(null); } }, CloseAction = () => { this.selectedHediffType = selectedHediffType; if (selectedHediffType == HediffTypeInjury) { Find.WindowStack.Add(injuryOptionDialog); } else { ResetDisabledImplantRecipes(customPawn); manageImplantsDialog = new DialogManageImplants(customPawn) { HeaderLabel = "EdB.PC.Dialog.Implant.Header".Translate(), CloseAction = (List <Implant> implants) => { ApplyImplantsToPawn(customPawn, implants); } }; Find.WindowStack.Add(manageImplantsDialog); } } }; Find.WindowStack.Add(hediffTypeDialog); } }
private static float GetListPriority([CanBeNull] BodyPartRecord record) => record == null ? 9999999f : (float)record.height * 10000 + record.coverageAbsWithChildren;
// Token: 0x0600001F RID: 31 RVA: 0x000033AC File Offset: 0x000015AC internal static bool HediffEffect(HediffDef hediffdef, float SeverityToApply, Pawn pawn, BodyPartRecord part, out bool immune) { immune = false; if (pawn.RaceProps.IsMechanoid || hediffdef == null) { return(false); } if (!ImmuneTo(pawn, hediffdef, out _)) { if (pawn.health.WouldDieAfterAddingHediff(hediffdef, part, SeverityToApply)) { return(false); } var health = pawn.health; Hediff hediff; if (health == null) { hediff = null; } else { var hediffSet = health.hediffSet; hediff = hediffSet?.GetFirstHediffOfDef(hediffdef); } var hashediff = hediff; if (hashediff != null) { hashediff.Severity += SeverityToApply; return(true); } var addhediff = HediffMaker.MakeHediff(hediffdef, pawn, part); addhediff.Severity = SeverityToApply; pawn.health.AddHediff(addhediff, part); return(true); } immune = true; return(false); }
public static void DamageInfosToApply_ForceWeapon_Postfix(ref Verb_MeleeAttackDamage __instance, LocalTargetInfo target, ref IEnumerable <DamageInfo> __result) { if (__instance.EquipmentSource != null) { if (!__instance.EquipmentSource.AllComps.NullOrEmpty()) { if (__instance.EquipmentSource.GetComp <CompWeapon_MeleeSpecialRules>() != null) { if (__instance.EquipmentSource.GetComp <CompWeapon_MeleeSpecialRules>() is CompWeapon_MeleeSpecialRules WeaponRules) { if (AMSettings.Instance.AllowForceWeaponEffect) { bool ForceAttack = __result.Any(x => x.Def.forceWeapon()); if (WeaponRules.ForceWeapon && ForceAttack && __instance.CasterPawn is Pawn Caster) { bool casterPsychiclySensitive = Caster.RaceProps.Humanlike ? Caster.story.traits.HasTrait(TraitDefOf.PsychicSensitivity) : false; bool Activate = false; if ((casterPsychiclySensitive || !WeaponRules.ForceEffectRequiresPsyker) && target.Thing.def.category == ThingCategory.Pawn && target.Thing is Pawn Victim) { int casterPsychiclySensitiveDegree = casterPsychiclySensitive ? Caster.story.traits.DegreeOfTrait(TraitDefOf.PsychicSensitivity) : 0; if ((casterPsychiclySensitiveDegree >= 1 || !WeaponRules.ForceEffectRequiresPsyker)) { float?casterPsychicSensitivity = Caster.GetStatValue(StatDefOf.PsychicSensitivity, true) * 100f; bool targetPsychiclySensitive = Victim.RaceProps.Humanlike ? Victim.story.traits.HasTrait(TraitDefOf.PsychicSensitivity) : false; float?targetPsychicSensitivity = Victim.GetStatValue(StatDefOf.PsychicSensitivity, true) * 100f; if (targetPsychiclySensitive == true) { int targetPsychiclySensitiveDegree = Victim.story.traits.DegreeOfTrait(TraitDefOf.PsychicSensitivity); if (targetPsychiclySensitiveDegree == -1) { targetPsychicSensitivity = Victim.def.statBases.GetStatValueFromList(StatDefOf.PsychicSensitivity, 1.5f) * 100f; } else if (targetPsychiclySensitiveDegree == -2) { targetPsychicSensitivity = Victim.def.statBases.GetStatValueFromList(StatDefOf.PsychicSensitivity, 2f) * 100f; } } else { int targetPsychiclySensitiveDegree = 0; } if (__result.Any(x => x.Def.forceWeapon())) { Log.Message(string.Format("1")); float CasterMood = Caster.needs.mood.CurLevelPercentage; float VictimMood = Victim?.needs?.mood != null ? Victim.needs.mood.CurLevelPercentage : 1; foreach (var item in __result.Where(x => x.Def.forceWeapon())) { float?casterRoll = Rand.Range(0, (int)casterPsychicSensitivity) * CasterMood; float?targetRoll = Rand.Range(0, (int)targetPsychicSensitivity) * VictimMood; casterRoll = (casterRoll - (targetPsychicSensitivity / 2)); Activate = (casterRoll > targetRoll); Log.Message(string.Format("Caster:{0}, Victim:{1}", casterRoll, targetRoll)); if (Activate) { DamageDef damDef = WeaponRules.ForceWeaponEffect; float damAmount = __instance.verbProps.AdjustedMeleeDamageAmount(__instance, __instance.CasterPawn); float armorPenetration = __instance.verbProps.AdjustedArmorPenetration(__instance, __instance.CasterPawn); BodyPartRecord bodyPart = Rand.Chance(0.05f) && Victim.RaceProps.body.AllParts.Any(x => x.def.defName.Contains("Brain")) ? Victim.RaceProps.body.AllParts.Find(x => x.def.defName.Contains("Brain")) : null; BodyPartGroupDef bodyPartGroupDef = null; HediffDef hediffDef = WeaponRules.ForceWeaponHediff; damAmount = Rand.Range(damAmount * 0.1f, damAmount * 0.5f); ThingDef source = __instance.EquipmentSource.def; Thing caster = __instance.caster; Vector3 direction = (target.Thing.Position - __instance.CasterPawn.Position).ToVector3(); float num = damAmount; float num2 = armorPenetration; DamageInfo mainDinfo = new DamageInfo(damDef, num, num2, -1f, caster, bodyPart, source, DamageInfo.SourceCategory.ThingOrUnknown, null); mainDinfo.SetBodyRegion(BodyPartHeight.Undefined, BodyPartDepth.Outside); mainDinfo.SetWeaponBodyPartGroup(bodyPartGroupDef); mainDinfo.SetWeaponHediff(hediffDef); mainDinfo.SetAngle(direction); Victim.TakeDamage(mainDinfo); Map map = Caster.Map; IntVec3 position = target.Cell; Map map2 = map; float explosionRadius = 0f; Thing launcher = __instance.EquipmentSource; SoundDef soundExplode = WeaponRules.ForceWeaponTriggerSound; Thing thing = target.Thing; GenExplosion.DoExplosion(position, map2, explosionRadius, damDef, launcher, (int)damAmount, armorPenetration, soundExplode, source, null, thing, null, 0f, 0, false, null, 0, 0, 0, false); float KillChance = WeaponRules.ForceWeaponKillChance; if (KillChance != 0) { float KillRoll = Rand.Range(0, 100); if (Rand.Chance(WeaponRules.ForceWeaponKillChance)) { string msg = string.Format("{0} was slain by a force strike", target.Thing.LabelCap); target.Thing.Kill(mainDinfo); if (target.Thing.Faction == Faction.OfPlayer) { Messages.Message(msg, MessageTypeDefOf.PawnDeath); } } } /* */ } } } } } } } } } } } }
private void AddPartMutations() { var mutationsAdded = 0; while (_curIndex < _checkList.Count) { BodyPartRecord part = _checkList[_curIndex]; if (!pawn.RaceProps.body.AllParts.Contains(part)) { //if the pawn's race changes the mutation order may no longer be valid //need to reset it and try again later break; } var lst = _scratchDict.TryGetValue(part.def); if (lst == null) //end check early if there are no parts that can be added { _curIndex++; _curMutationIndex = 0; continue; } //make sure we try each mutation per part while (_curMutationIndex < lst.Count) { var mutation = lst[_curMutationIndex]; //check if the mutation can actually be added if (!mutation.mutation.CanApplyMutations(pawn, part)) { _curMutationIndex++; continue; } else if (Rand.Value < mutation.addChance) { var result = MutationUtilities.AddMutation(pawn, mutation.mutation, part); if (result) //make sure the mutation was actually added before doing this { var mutagen = def.GetMutagenDef(); mutagen.TryApplyAspects(pawn); mutationsAdded++; } } else if (mutation.blocks) { return; //wait here until the blocking mutation is added } _curMutationIndex++; //check if we added enough mutations to break early if (mutationsAdded >= MinMutationsPerCheck) { goto loopBreak;//break both loops } } _curIndex++; //increment after so mutations can 'block' _curMutationIndex = 0; //reset the mutation index every time we move up a part //check if we have added enough mutations to end the loop early if (mutationsAdded >= MinMutationsPerCheck) { break; } } loopBreak: //label so we can break both loops if (mutationsAdded > 0) { OnMutationsAdded(mutationsAdded); } }
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List <Thing> ingredients, Bill bill) { base.ApplyOnPawn(pawn, part, billDoer, ingredients, bill); }
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List <Thing> ingredients, Bill bill) { HealthUtility.AdjustSeverity(pawn, HediffDefOf.BloodLoss, -0.20f); }
/// <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="armorReduced">Whether sharp damage was deflected by armor</param> /// <param name="shieldAbsorbed">Returns true if attack did not penetrate pawn's melee shield</param> /// <param name="armorDeflected">Whether the attack was completely absorbed by the armor</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 armorDeflected, out bool armorReduced, out bool shieldAbsorbed) { shieldAbsorbed = false; armorDeflected = false; armorReduced = false; if (originalDinfo.Def.armorCategory == null || (!(originalDinfo.Weapon?.projectile is ProjectilePropertiesCE) && Verb_MeleeAttackCE.LastAttackVerb == null && originalDinfo.Weapon == null && originalDinfo.Instigator == null)) { return(originalDinfo); } var dinfo = new DamageInfo(originalDinfo); var dmgAmount = dinfo.Amount; var involveArmor = dinfo.Def.harmAllLayersUntilOutside || hitPart.depth == BodyPartDepth.Outside; 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.armorRatingStat, pawn, hitPart))); armorDeflected = dinfo.Amount <= 0; return(dinfo); } var penAmount = originalDinfo.ArmorPenetrationInt; //GetPenetrationValue(originalDinfo); // Apply worn armor if (involveArmor && pawn.apparel != null && !pawn.apparel.WornApparel.NullOrEmpty()) { var apparel = pawn.apparel.WornApparel; // Check for shields first var shield = apparel.FirstOrDefault(x => x is Apparel_Shield); if (shield != null) { // Determine whether the hit is blocked by the shield var blockedByShield = false; if (!(dinfo.Weapon?.IsMeleeWeapon ?? false)) { var shieldDef = shield.def.GetModExtension <ShieldDefExtension>(); if (shieldDef == null) { Log.ErrorOnce("Combat Extended :: shield " + shield.def.ToString() + " is Apparel_Shield but has no ShieldDefExtension", shield.def.GetHashCode() + 12748102); } else { var 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.armorRatingStat), ref penAmount, ref dmgAmount, shield)) { shieldAbsorbed = true; armorDeflected = true; dinfo.SetAmount(0); // Apply secondary damage to shield if (dinfo.Weapon?.projectile is ProjectilePropertiesCE props && !props.secondaryDamage.NullOrEmpty()) { foreach (var sec in props.secondaryDamage) { if (shield.Destroyed || !Rand.Chance(sec.chance)) { break; } var secDinfo = sec.GetDinfo(); var pen = secDinfo.ArmorPenetrationInt; //GetPenetrationValue(originalDinfo); var dmg = (float)secDinfo.Amount; TryPenetrateArmor(secDinfo.Def, shield.GetStatValue(secDinfo.Def.armorCategory.armorRatingStat), ref pen, ref dmg, shield); } } return(dinfo); } } // Apparel is arranged in draw order, we run through reverse to go from Shell -> OnSkin for (var i = apparel.Count - 1; i >= 0; i--) { var app = apparel[i]; if (app != null && app.def.apparel.CoversBodyPart(hitPart) && !TryPenetrateArmor(dinfo.Def, app.GetStatValue(dinfo.Def.armorCategory.armorRatingStat), ref penAmount, ref dmgAmount, app)) { // Hit was deflected, convert damage type //armorReduced = true; dinfo = GetDeflectDamageInfo(dinfo, hitPart, ref dmgAmount, ref penAmount); if (app == apparel.ElementAtOrDefault(i)) //Check whether the "deflecting" apparel is still in the WornApparel - if not, the next loop checks again and errors out because the index is out of range { 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); armorDeflected = true; return(dinfo); } } } // Apply natural armor var partsToHit = new List <BodyPartRecord>() { hitPart }; if (dinfo.Def.harmAllLayersUntilOutside) { var curPart = hitPart; while (curPart.parent != null && curPart.depth == BodyPartDepth.Inside) { curPart = curPart.parent; partsToHit.Add(curPart); } } var isSharp = dinfo.Def.armorCategory.armorRatingStat == StatDefOf.ArmorRating_Sharp; var partDensityStat = isSharp ? CE_StatDefOf.BodyPartSharpArmor : CE_StatDefOf.BodyPartBluntArmor; var partDensity = pawn.GetStatValue(partDensityStat); // How much armor is provided by sheer meat for (var i = partsToHit.Count - 1; i >= 0; i--) { var curPart = partsToHit[i]; var coveredByArmor = curPart.IsInGroup(CE_BodyPartGroupDefOf.CoveredByNaturalArmor); var armorAmount = coveredByArmor ? pawn.GetStatValue(dinfo.Def.armorCategory.armorRatingStat) : 0; // Only apply damage reduction when penetrating armored body parts if (!TryPenetrateArmor(dinfo.Def, armorAmount, ref penAmount, ref dmgAmount, null, partDensity)) { dinfo.SetHitPart(curPart); if (isSharp && coveredByArmor) { // For Mechanoid natural armor, apply deflection and blunt armor dinfo = GetDeflectDamageInfo(dinfo, curPart, ref dmgAmount, ref penAmount); // Fetch armor rating stat again in case of deflection conversion to blunt TryPenetrateArmor(dinfo.Def, pawn.GetStatValue(dinfo.Def.armorCategory.armorRatingStat), ref penAmount, ref dmgAmount, null, partDensity); } break; } if (dmgAmount <= 0) { dinfo.SetAmount(0); armorDeflected = true; return(dinfo); } } // Applies blunt damage from partial penetrations. if (isSharp && (dinfo.Amount > Mathf.CeilToInt(dmgAmount))) { pawn.TakeDamage(GetDeflectDamageInfo(dinfo, hitPart, ref dmgAmount, ref penAmount, true)); } // Return damage info. dinfo.SetAmount(Mathf.CeilToInt(dmgAmount)); return(dinfo); }
public void ApplyHediffDefOn( Pawn pawn, HediffDef hediffDef, BodyPartRecord bodyPartRecord ) { if( ( pawn == null )|| ( hediffDef == null )|| ( bodyPartRecord == null ) ) { return; } if( pawn.health.hediffSet.HasHediff( hediffDef, bodyPartRecord ) ) { return; } pawn.health.AddHediff( hediffDef, bodyPartRecord ); }
public override void CompPostTick(ref float severityAdjustment) { base.CompPostTick(ref severityAdjustment); bool flag = base.Pawn != null; if (flag) { if (initializing) { initializing = false; this.Initialize(); } } bool flag4 = Find.TickManager.TicksGame % 600 == 0; if (flag4) { Pawn pawn = base.Pawn; int num = 1; int num2 = 1; using (IEnumerator <BodyPartRecord> enumerator = pawn.health.hediffSet.GetInjuredParts().GetEnumerator()) { while (enumerator.MoveNext()) { BodyPartRecord rec = enumerator.Current; bool flag2 = num > 0; if (flag2) { IEnumerable <Hediff_Injury> arg_BB_0 = pawn.health.hediffSet.GetHediffs <Hediff_Injury>(); Func <Hediff_Injury, bool> arg_BB_1; arg_BB_1 = ((Hediff_Injury injury) => injury.Part == rec); foreach (Hediff_Injury current in arg_BB_0.Where(arg_BB_1)) { bool flag3 = num2 > 0; if (flag3) { bool flag5 = current.CanHealNaturally() && !current.IsPermanent(); if (flag5) { current.Heal(1.0f + this.parent.Severity / 3f); num--; num2--; } else { current.Heal(.2f); num--; num2--; } } } } } } if (this.bonderPawn != null && !this.bonderPawn.Destroyed && !this.bonderPawn.Dead) { RefreshBond(); UpdateBond(); } else { this.Pawn.health.RemoveHediff(this.Pawn.health.hediffSet.GetFirstHediffOfDef(this.parent.def)); if (this.Pawn.def.thingClass == typeof(TMPawnSummoned)) { if (this.Pawn.Map != null) { FleckMaker.ThrowSmoke(this.Pawn.DrawPos, this.Pawn.Map, 1f); TM_MoteMaker.ThrowGenericMote(TorannMagicDefOf.Mote_Ghost, this.Pawn.DrawPos, this.Pawn.Map, 1.3f, .25f, .1f, .45f, 0, Rand.Range(1f, 2f), 0, 0); } this.Pawn.Destroy(DestroyMode.Vanish); } //this.Pawn.SetFactionDirect(null); } } }
/// <summary> /// Creates a new DamageInfo from a deflected one. Changes damage type to Blunt and hit part to the outermost parent of the originally hit part. /// </summary> /// <param name="dinfo">The dinfo that was deflected</param> /// <param name="hitPart">The originally hit part</param> /// <param name="partialPen">Is this is supposed to be a partial penetration</param> /// <returns>DamageInfo copied from dinfo with Def and forceHitPart adjusted</returns> private static DamageInfo GetDeflectDamageInfo(DamageInfo dinfo, BodyPartRecord hitPart, ref float dmgAmount, ref float penAmount, bool partialPen = false) { if (dinfo.Def.armorCategory != DamageArmorCategoryDefOf.Sharp) { if (!partialPen) { dmgAmount = 0; penAmount = 0; } dinfo.SetAmount(0); return(dinfo); } //Creating local variables as we don't want to edit the pass-by-reference parameters in the case of partial penetrations. float localDmgAmount = dmgAmount; float localPenAmount = penAmount; //Calculating blunt damage from sharp damage: if it's a deflected sharp attack, then the penetration amount is directly localPenAmount. //However, if it's a partially-penetrating sharp attack, then we're using the blocked values of penetration amount and damage amount instead //and because localPenAmount is the sharp attack's remaining penetration amount and localDmgAmount is the sharp attack's remaining damage amount, //we have to take that amount away from the base penetration amount and damage amount. float penMulti = (partialPen ? ((dinfo.ArmorPenetrationInt - localPenAmount) * (dinfo.Amount - Mathf.CeilToInt(localDmgAmount)) / dinfo.Amount) : localPenAmount) / dinfo.ArmorPenetrationInt; if (dinfo.Weapon?.projectile is ProjectilePropertiesCE projectile) { localPenAmount = projectile.armorPenetrationBlunt * penMulti; } else if (dinfo.Instigator.def.thingClass == typeof(Building_TrapDamager)) { //Temporarily deriving spike trap blunt AP based on their vanilla stats, just so they're not entirely broken //TODO proper integration var trapAP = dinfo.Instigator.GetStatValue(StatDefOf.TrapMeleeDamage, true) * SpikeTrapAPModifierBlunt; localPenAmount = trapAP * penMulti; } else { if (Verb_MeleeAttackCE.LastAttackVerb != null) { localPenAmount = Verb_MeleeAttackCE.LastAttackVerb.ArmorPenetrationBlunt; } else { //LastAttackVerb is already checked in GetAfterArmorDamage(). Only known case of code arriving here is with the ancient soldiers //spawned at the start of the game: their wounds are usually applied with Weapon==null and Instigator==null, so they skip CE's armor system, //but on rare occasions, one of the soldiers gets Bite injuries with with Weapon==null and the instigator set as *himself*. //Warning message below to identify any other situations where this might be happening. -LX7 Log.Warning($"[CE] Deflection for Instigator:{dinfo.Instigator} Target:{dinfo.IntendedTarget} DamageDef:{dinfo.Def} Weapon:{dinfo.Weapon} has null verb, overriding AP."); localPenAmount = 50; } } localDmgAmount = Mathf.Pow(localPenAmount * 10000, 1 / 3f) / 10; var newDinfo = new DamageInfo(DamageDefOf.Blunt, localDmgAmount, localPenAmount, dinfo.Angle, dinfo.Instigator, GetOuterMostParent(hitPart), partialPen ? null : dinfo.Weapon); //To not apply the secondary damage twice on partial penetrations. newDinfo.SetBodyRegion(dinfo.Height, dinfo.Depth); newDinfo.SetWeaponBodyPartGroup(dinfo.WeaponBodyPartGroup); newDinfo.SetWeaponHediff(dinfo.WeaponLinkedHediff); newDinfo.SetInstantPermanentInjury(dinfo.InstantPermanentInjury); newDinfo.SetAllowDamagePropagation(dinfo.AllowDamagePropagation); if (!partialPen) //If it was a deflect, update dmgAmount and penAmount. { dmgAmount = localDmgAmount; penAmount = localPenAmount; } return(newDinfo); }
public static bool IsCleanAndDroppable(Pawn pawn, BodyPartRecord part) { return(!pawn.RaceProps.Animal && !pawn.RaceProps.IsMechanoid && part.def.spawnThingOnRemoved != null && !pawn.health.hediffSet.hediffs.Any(x => x.Part == part)); }
public override void CompPostTick(ref float severityAdjustment) { base.CompPostTick(ref severityAdjustment); bool flag = base.Pawn != null; if (flag) { if (initializing) { initializing = false; this.Initialize(); } } if (Find.TickManager.TicksGame % 16 == 0) { IEnumerable <Hediff> hdEnum = this.Pawn.health.hediffSet.GetHediffs <Hediff>(); foreach (Hediff hd in hdEnum) { if (hd.def.defName == "SpaceHypoxia") { this.Pawn.health.RemoveHediff(hd); break; } } } bool flag4 = Find.TickManager.TicksGame % 600 == 0; if (flag4) { List <Need> needs = base.Pawn.needs.AllNeeds; for (int i = 0; i < needs.Count; i++) { if (needs[i].def.defName != "Joy" && needs[i].def.defName != "Mood" && needs[i].def.defName != "TM_Mana" && needs[i].def.defName != "TM_Stamina" && needs[i].def.defName != "ROMV_Blood") { needs[i].CurLevel = needs[i].MaxLevel; } } Pawn pawn = base.Pawn; int num = 1; int num2 = 1; using (IEnumerator <BodyPartRecord> enumerator = pawn.health.hediffSet.GetInjuredParts().GetEnumerator()) { while (enumerator.MoveNext()) { BodyPartRecord rec = enumerator.Current; bool flag2 = num > 0; if (flag2) { IEnumerable <Hediff_Injury> arg_BB_0 = pawn.health.hediffSet.GetHediffs <Hediff_Injury>(); Func <Hediff_Injury, bool> arg_BB_1; arg_BB_1 = (Hediff_Injury injury) => injury.Part == rec; foreach (Hediff_Injury current in arg_BB_0.Where(arg_BB_1)) { bool flag3 = num2 > 0; if (flag3) { bool flag5 = current.CanHealNaturally() && !current.IsPermanent(); if (flag5) { current.Heal(2.0f); num--; num2--; } else { current.Heal(1.0f); num--; num2--; } } } } } } using (IEnumerator <Hediff> enumerator = pawn.health.hediffSet.GetHediffsTendable().GetEnumerator()) { while (enumerator.MoveNext()) { Hediff rec = enumerator.Current; if (rec.TendableNow()) // && !currentTendable.IsPermanent() { rec.Tended(1, 1); } } } using (IEnumerator <Hediff> enumerator = pawn.health.hediffSet.GetHediffs <Hediff>().GetEnumerator()) { while (enumerator.MoveNext()) { Hediff rec = enumerator.Current; if (!rec.IsPermanent()) { if (rec.def.defName == "Cataract" || rec.def.defName == "HearingLoss" || rec.def.defName.Contains("ToxicBuildup")) { pawn.health.RemoveHediff(rec); } if (rec.def.defName == "Blindness" || rec.def.defName.Contains("Asthma") || rec.def.defName == "Cirrhosis" || rec.def.defName == "ChemicalDamageModerate") { pawn.health.RemoveHediff(rec); } if (rec.def.defName == "Frail" || rec.def.defName == "BadBack" || rec.def.defName.Contains("Carcinoma") || rec.def.defName == "ChemicalDamageSevere") { pawn.health.RemoveHediff(rec); } if (rec.def.defName.Contains("Alzheimers") || rec.def.defName == "Dementia" || rec.def.defName.Contains("HeartArteryBlockage") || rec.def.defName == "CatatonicBreakdown") { pawn.health.RemoveHediff(rec); } } if (rec.def.makesSickThought) { pawn.health.RemoveHediff(rec); } } } } }
/// <summary> /// Checks if the given source mutation blocks the given otherMutation being added at the given part /// </summary> /// <param name="sourceMutation">The source mutation.</param> /// <param name="otherMutation">The other mutation.</param> /// <param name="addPart">The add part.</param> /// <returns></returns> public bool Blocks([NotNull] Hediff_AddedMutation sourceMutation, [NotNull] MutationDef otherMutation, [CanBeNull] BodyPartRecord addPart) { if (sourceMutation == null) { throw new ArgumentNullException(nameof(sourceMutation)); } if (otherMutation == null) { throw new ArgumentNullException(nameof(otherMutation)); } if (otherMutation != mutation) { return(false); } return(blockOnAnyPart || addPart == sourceMutation.Part); }
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List <Thing> ingredients, Bill bill) { CompUseEffect_HealCPUSerum.Apply(pawn); }
private static void CheckPart(List <BodyPartRecord> body, Hediff hediff, [CanBeNull] CompFace face, [CanBeNull] CompBodyAnimator anim, bool missing) { if (body.NullOrEmpty() || hediff.def == null) { Log.Message("Body list or hediff.def is null or empty"); return; } if (!hediff.Visible) { return; } BodyPartRecord leftEye = body.Find(x => x.customLabel == "left eye"); BodyPartRecord rightEye = body.Find(x => x.customLabel == "right eye"); BodyPartRecord jaw = body.Find(x => x.def == BodyPartDefOf.Jaw); //BodyPartRecord leftArm = body.Find(x => x.def == BodyPartDefOf.LeftArm); //BodyPartRecord rightArm = body.Find(x => x.def == DefDatabase<BodyPartDef>.GetNamed("RightShoulder")); BodyPartRecord leftHand = body.Find(x => x.customLabel == "left hand"); BodyPartRecord rightHand = body.Find(x => x.customLabel == "right hand"); BodyPartRecord leftFoot = body.Find(x => x.customLabel == "left foot"); BodyPartRecord rightFoot = body.Find(x => x.customLabel == "right foot"); BodyPartRecord leftArm = body.Find(x => x.customLabel == "left arm"); BodyPartRecord rightArm = body.Find(x => x.customLabel == "right arm"); BodyPartRecord leftLeg = body.Find(x => x.customLabel == "left foot"); BodyPartRecord rightLeg = body.Find(x => x.customLabel == "right foot"); if (missing) { CheckMissingParts(new BodyProps(hediff, face, anim, leftEye, rightEye, leftHand, rightHand, leftFoot, rightFoot)); return; } // Missing parts first, hands and feet can be replaced by arms/legs // Log.Message("Checking missing parts."); AddedBodyPartProps addedPartProps = hediff.def?.addedPartProps; if (addedPartProps == null) { // Log.Message("No added parts found."); return; } if (hediff.def?.defName == null) { return; } // Log.Message("Checking face for added parts."); if (anim != null && anim.Pawn.RaceProps.Humanlike && face != null) { CheckFaceForAddedParts(hediff, face, leftEye, rightEye, jaw); } // Log.Message("Checking body for added parts."); CheckBodyForAddedParts(hediff, anim, leftHand, leftArm, rightHand, rightArm, leftFoot, leftLeg, rightFoot, rightLeg); }
public override bool IsViolationOnPawn(Pawn pawn, BodyPartRecord part, Faction billDoerFaction) { return(false); }
public BodyProps(Hediff hediff, CompFace face, CompBodyAnimator anim, BodyPartRecord leftEye, BodyPartRecord rightEye, BodyPartRecord leftHand, BodyPartRecord rightHand, BodyPartRecord leftFoot, BodyPartRecord rightFoot) { this._hediff = hediff; this._face = face; this._anim = anim; this._leftEye = leftEye; this._rightEye = rightEye; this._leftHand = leftHand; this._rightHand = rightHand; this._leftFoot = leftFoot; this._rightFoot = rightFoot; }
protected virtual void HackingFailEvent(Pawn hacker, Pawn hackee, BodyPartRecord part, System.Random r) { }
private static void CheckBodyForAddedParts(Hediff hediff, CompBodyAnimator anim, BodyPartRecord leftHand, BodyPartRecord leftArm, BodyPartRecord rightHand, BodyPartRecord rightArm, BodyPartRecord leftFoot, BodyPartRecord leftLeg, BodyPartRecord rightFoot, BodyPartRecord rightLeg) { if (anim == null) { return; } if (anim.Props.bipedWithHands) { if (hediff.Part.parts.Contains(leftHand) || hediff.Part.parts.Contains(leftArm)) { anim.BodyStat.HandLeft = PartStatus.Artificial; } if (hediff.Part.parts.Contains(rightHand) || hediff.Part.parts.Contains(rightArm)) { anim.BodyStat.HandRight = PartStatus.Artificial; } } if (hediff.Part.parts.Contains(leftFoot) || hediff.Part.parts.Contains(leftLeg)) { anim.BodyStat.FootLeft = PartStatus.Artificial; } if (hediff.Part.parts.Contains(rightFoot) || hediff.Part.parts.Contains(rightLeg)) { anim.BodyStat.FootRight = PartStatus.Artificial; } }
static bool RulesForBodyPartRecordPrefix(ref IEnumerable <Rule> __result, string prefix, BodyPartRecord part) { // if the current language is not the target, do nothing if (!LanguageWorkerPatcher.IsTargetLanguage(LanguageDatabase.activeLanguage.FriendlyNameEnglish)) { return(true); } // Rewrite the method entirely since it is short enough __result = LanguageWorker_Spanish.FixRulesForBodyPartRecord(prefix, part); #if DEBUG LanguageWorkerPatcher.LogMessage("--RulesForBodyPartRecordPrefix called..."); LanguageWorkerPatcher.LogMessage("result: " + __result); foreach (Rule r in __result) { LanguageWorkerPatcher.LogMessage(r.ToString()); } #endif // DO NOT CONTINUE to the original GrammarUtility.RulesforPawn return(false); }
protected override bool TryCastShot() { bool result = false; bool arg_40_0; Pawn pawn = this.CasterPawn; Map map = this.CasterPawn.Map; CompAbilityUserMagic comp = pawn.GetComp <CompAbilityUserMagic>(); int verVal = pawn.GetComp <CompAbilityUserMagic>().MagicData.MagicPowerSkill_BloodGift.FirstOrDefault((MagicPowerSkill x) => x.label == "TM_BloodGift_ver").level; int bloodGain = 0; List <BodyPartRecord> bodyparts = new List <BodyPartRecord>(); bodyparts.Clear(); bodyparts = this.CasterPawn.def.race.body.AllParts; List <ThingDef> bloodDefs = TM_Calc.GetAllRaceBloodTypes(); ModOptions.SettingsRef settingsRef = new ModOptions.SettingsRef(); if (pawn != null && !pawn.Downed && bodyparts != null && bloodDefs != null) { if (verVal > 0) { List <IntVec3> cellList = GenRadial.RadialCellsAround(this.CasterPawn.Position, (2 * verVal) - 1, true).ToList(); for (int i = 0; i < cellList.Count; i++) { IntVec3 curcell = cellList[i]; List <Thing> thingList = curcell.GetThingList(this.CasterPawn.Map); for (int j = 0; j < thingList.Count; j++) { if (thingList[j].def == ThingDefOf.Filth_Blood || (settingsRef.unrestrictedBloodTypes && bloodDefs.Contains(thingList[j].def))) { bloodGain += thingList[j].stackCount; thingList[j].Destroy(DestroyMode.Vanish); } } } } List <BodyPartRecord> validParts = new List <BodyPartRecord>(); validParts.Clear(); for (int i = 0; i < bodyparts.Count; i++) { if (bodyparts[i].def.bleedRate != 0 && bodyparts[i].depth == BodyPartDepth.Outside && bodyparts[i].coverageAbs > 0) { validParts.Add(bodyparts[i]); } } if (validParts.Count > 0) { if (this.CasterPawn.RaceProps.BloodDef != null && (this.CasterPawn.RaceProps.BloodDef == ThingDefOf.Filth_Blood || settingsRef.unrestrictedBloodTypes)) { BodyPartRecord damagePart = validParts.RandomElement(); TM_Action.DamageEntities(this.CasterPawn, damagePart, 4f, 10f, TMDamageDefOf.DamageDefOf.TM_BloodyCut, this.CasterPawn); damagePart = validParts.RandomElement(); TM_Action.DamageEntities(this.CasterPawn, damagePart, 2f, 10f, TMDamageDefOf.DamageDefOf.TM_BloodyCut, this.CasterPawn); bloodGain += 18; List <Need> needs = this.CasterPawn.needs.AllNeeds; for (int n = 0; n < needs.Count; n++) { Need need = needs[n]; if (need.def.defName == "ROMV_Blood") { need.CurLevel--; } } TM_MoteMaker.ThrowGenericMote(ThingDef.Named("Mote_CrossStrike"), this.CasterPawn.DrawPos, this.CasterPawn.Map, Rand.Range(.4f, 0.6f), .45f, .05f, .20f, 0, 0, 0, Rand.Range(0, 360)); for (int j = 0; j < 4; j++) { IntVec3 rndPos = this.CasterPawn.Position; rndPos.x += Mathf.RoundToInt(Rand.Range(-1.5f, 1.5f)); rndPos.z += Mathf.RoundToInt(Rand.Range(-1.5f, 1.5f)); FilthMaker.MakeFilth(rndPos, this.CasterPawn.Map, this.CasterPawn.RaceProps.BloodDef, Rand.RangeInclusive(1, 2)); TM_MoteMaker.ThrowGenericMote(ThingDef.Named("Mote_BloodSquirt"), this.CasterPawn.DrawPos, this.CasterPawn.Map, Rand.Range(.7f, 1.1f), .15f, .05f, .66f, Rand.Range(-100, 100), Rand.Range(1, 2), Rand.Range(0, 360), Rand.Range(0, 360)); } } } else { if (bloodGain == 0) { Messages.Message("TM_NoExternalBodyPartsCanBleed".Translate(this.CasterPawn.LabelShort), MessageTypeDefOf.RejectInput, false); } } HealthUtility.AdjustSeverity(this.CasterPawn, HediffDef.Named("TM_BloodHD"), bloodGain * (1 + (.1f * verVal))); arg_40_0 = true; } else { arg_40_0 = false; } bool flag = arg_40_0; if (flag) { } else { Log.Warning("failed to TryCastShot"); } this.burstShotsLeft = 0; return(result); }
private void RemoveHediffsAddictionsAndPermanentInjuries(Pawn pawn) { List <Hediff> removeList = new List <Hediff>(); removeList.Clear(); using (IEnumerator <BodyPartRecord> enumerator = pawn.health.hediffSet.GetInjuredParts().GetEnumerator()) { while (enumerator.MoveNext()) { BodyPartRecord rec = enumerator.Current; IEnumerable <Hediff_Injury> arg_BB_0 = pawn.health.hediffSet.GetHediffs <Hediff_Injury>(); Func <Hediff_Injury, bool> arg_BB_1; arg_BB_1 = ((Hediff_Injury injury) => injury.Part == rec); foreach (Hediff_Injury current in arg_BB_0.Where(arg_BB_1)) { bool flag5 = !current.CanHealNaturally() && current.IsPermanent(); if (flag5) { removeList.Add(current); } } } } if (removeList.Count > 0) { for (int i = 0; i < removeList.Count; i++) { pawn.health.RemoveHediff(removeList[i]); } } removeList.Clear(); using (IEnumerator <Hediff_Addiction> enumerator = pawn.health.hediffSet.GetHediffs <Hediff_Addiction>().GetEnumerator()) { while (enumerator.MoveNext()) { Hediff_Addiction rec = enumerator.Current; removeList.Add(rec); } } if (removeList.Count > 0) { for (int i = 0; i < removeList.Count; i++) { pawn.health.RemoveHediff(removeList[i]); } } removeList.Clear(); using (IEnumerator <Hediff> enumerator = pawn.health.hediffSet.GetHediffs <Hediff>().GetEnumerator()) { while (enumerator.MoveNext()) { Hediff hd = enumerator.Current; if (hd.IsPermanent() || (hd.IsTended() || hd.TendableNow()) || (hd.source == null && hd.sourceBodyPartGroup == null)) { removeList.Add(hd); } } } if (removeList.Count > 0) { for (int i = 0; i < removeList.Count; i++) { pawn.health.RemoveHediff(removeList[i]); } } removeList.Clear(); }
static void Postfix(Pawn_HealthTracker __instance) { Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue <Pawn>(); if (!pawn.RaceProps.IsMechanoid) { return; } ExtendedPawnData pawnData = Base.Instance.GetExtendedDataStorage().GetExtendedDataFor(pawn); if (pawnData.shouldExplodeNow) { GenExplosion.DoExplosion(pawn.Position, pawn.Map, 4.5f, DamageDefOf.Bomb, pawn, DamageDefOf.Bomb.defaultDamage, DamageDefOf.Bomb.defaultArmorPenetration, DamageDefOf.Bomb.soundExplosion, null, null, null, null, 0f, 1, false, null, 0f, 1, 0f, false); pawn.jobs.startingNewJob = false; BodyPartRecord reactorPart = pawn.health.hediffSet.GetNotMissingParts().FirstOrDefault((BodyPartRecord r) => r.def.defName == "Reactor"); pawn.TakeDamage(new DamageInfo(DamageDefOf.Bomb, reactorPart.def.GetMaxHealth(pawn), 9999, -1, null, reactorPart)); pawnData.shouldExplodeNow = false; } if (pawn.HasValidCaravanPlatform() && pawn.GetCaravan() != null && pawn.GetCaravan().HasFuel()) { float powerPerTick = 0.5f * WTH_DefOf.WTH_PortableChargingPlatform.GetCompProperties <CompProperties_Refuelable>().fuelConsumptionRate * 15 / GenDate.TicksPerDay; //TODO: no magic number RechargeMechanoid(pawn, pawn.needs.TryGetNeed(WTH_DefOf.WTH_Mechanoid_Power), powerPerTick); } if (pawn.health.hediffSet.HasHediff(WTH_DefOf.WTH_VanometricModule)) { RechargeMechanoid(pawn, pawn.needs.TryGetNeed(WTH_DefOf.WTH_Mechanoid_Power), 0.0085f);//TODO: no magic number } if (pawn.health.hediffSet.HasHediff(WTH_DefOf.WTH_Repairing)) { if (pawn.IsHashIntervalTick(10)) { TryHealRandomInjury(__instance, pawn, 4000f / RimWorld.GenDate.TicksPerDay); } } if (!(pawn.CurrentBed() is Building_BaseMechanoidPlatform)) { return; } Building_BaseMechanoidPlatform platform = (Building_BaseMechanoidPlatform)pawn.CurrentBed(); if (platform.RepairActive && __instance.hediffSet.HasNaturallyHealingInjury() && !pawn.health.hediffSet.HasHediff(WTH_DefOf.WTH_Repairing)) { if (pawn.IsHashIntervalTick(10) && platform.CanHealNow()) { TryHealRandomInjury(__instance, pawn, WTH_DefOf.WTH_MechanoidPlatform.building.bed_healPerDay * 10 / RimWorld.GenDate.TicksPerDay, platform); } } if (!__instance.hediffSet.HasNaturallyHealingInjury() && platform.RegenerateActive && pawn.IsHashIntervalTick(100) && platform.refuelableComp.Fuel > 4f) //TODO: no magic number { TryRegeneratePart(pawn, platform); RegainWeapon(pawn); } if (platform.HasPowerNow()) { Need powerNeed = pawn.needs.TryGetNeed(WTH_DefOf.WTH_Mechanoid_Power); float powerPerTick = 0; if (platform.PowerComp != null) { powerPerTick = 0.75f * platform.PowerComp.Props.basePowerConsumption / GenDate.TicksPerDay; //TODO: no magic number } else { platform.refuelableComp.ConsumeFuel(platform.refuelableComp.Props.fuelConsumptionRate / GenDate.TicksPerDay); powerPerTick = 0.75f * platform.refuelableComp.Props.fuelConsumptionRate * 15 / GenDate.TicksPerDay; //TODO: no magic number } RechargeMechanoid(pawn, powerNeed, powerPerTick); } }
/// <summary> /// Calculates deflection chance and damage through armor /// </summary> public static int GetAfterArmorDamage(Pawn pawn, int amountInt, BodyPartRecord part, DamageInfo dinfo, bool damageArmor, ref bool deflected) { DamageDef damageDef = dinfo.Def; if (damageDef.armorCategory == DamageArmorCategory.IgnoreArmor) { return amountInt; } float damageAmount = (float)amountInt; StatDef deflectionStat = damageDef.armorCategory.DeflectionStat(); float pierceAmount = 0f; //Check if the projectile has the armor-piercing comp CompProperties_AP props = null; if (dinfo.Source != null) { VerbProperties verbProps = dinfo.Source.Verbs.Where(x => x.isPrimary).First(); if (verbProps != null) { ThingDef projectile = verbProps.projectileDef; if (projectile != null && projectile.HasComp(typeof(CompAP))) { props = (CompProperties_AP)projectile.GetCompProperties(typeof(CompAP)); } } //Check weapon for comp if projectile doesn't have it if (props == null && dinfo.Source.HasComp(typeof(CompAP))) { props = (CompProperties_AP)dinfo.Source.GetCompProperties(typeof(CompAP)); } } if (props != null) { pierceAmount = props.armorPenetration; } //Run armor calculations on all apparel if (pawn.apparel != null) { List<Apparel> wornApparel = new List<Apparel>(pawn.apparel.WornApparel); for (int i = wornApparel.Count - 1; i >= 0; i--) { if (wornApparel[i].def.apparel.CoversBodyPart(part)) { Thing armorThing = damageArmor ? wornApparel[i] : null; //Check for deflection if (Utility.ApplyArmor(ref damageAmount, ref pierceAmount, wornApparel[i].GetStatValue(deflectionStat, true), armorThing, damageDef)) { deflected = true; if (damageDef != absorbDamageDef) { damageDef = absorbDamageDef; deflectionStat = damageDef.armorCategory.DeflectionStat(); i++; } } if (damageAmount < 0.001) { return 0; } } } } //Check for pawn racial armor if (Utility.ApplyArmor(ref damageAmount, ref pierceAmount, pawn.GetStatValue(deflectionStat, true), null, damageDef)) { deflected = true; if (damageAmount < 0.001) { return 0; } damageDef = absorbDamageDef; deflectionStat = damageDef.armorCategory.DeflectionStat(); Utility.ApplyArmor(ref damageAmount, ref pierceAmount, pawn.GetStatValue(deflectionStat, true), pawn, damageDef); } return Mathf.RoundToInt(damageAmount); }
public static bool HasDirectlyAddedPartFor(HediffSet __instance, ref bool __result, BodyPartRecord part) { List <Hediff> hediffs = __instance.hediffs; for (int index = 0; index < hediffs.Count; ++index) { Hediff hediff = hediffs[index]; if (hediff != null && hediff.Part == part && hediff is Hediff_AddedPart) { __result = true; return(false); } } __result = false; return(false); }
public void RemoveHediffDefOn( Pawn pawn, HediffDef hediffDef, BodyPartRecord bodyPartRecord ) { if( ( pawn == null )|| ( hediffDef == null )|| ( bodyPartRecord == null ) ) { return; } var hediff = pawn.health.hediffSet.hediffs.FirstOrDefault( diff => ( ( diff.Part == bodyPartRecord )&& ( diff.def == hediffDef ) ) ); if( hediff == null ) { return; } pawn.health.hediffSet.hediffs.Remove( hediff ); }
/// <summary> /// Calculates damage reduction for ambient damage types (fire, electricity) versus natural and worn armor of a pawn. Adds up the total armor percentage (clamped at 0-100%) and multiplies damage by that amount. /// </summary> /// <param name="dmgAmount">The original amount of damage</param> /// <param name="armorRatingStat">The armor stat to use for damage reduction</param> /// <param name="pawn">The damaged pawn</param> /// <param name="part">The body part affected</param> /// <returns>The post-armor damage ranging from 0 to the original amount</returns> private static float GetAmbientPostArmorDamage(float dmgAmount, StatDef armorRatingStat, Pawn pawn, BodyPartRecord part) { var dmgMult = 1f; if (part.IsInGroup(CE_BodyPartGroupDefOf.CoveredByNaturalArmor)) { dmgMult -= pawn.GetStatValue(armorRatingStat); } if (dmgMult <= 0) { return(0); } if (pawn.apparel != null && !pawn.apparel.WornApparel.NullOrEmpty()) { var apparelList = pawn.apparel.WornApparel; foreach (var apparel in apparelList) { if (apparel.def.apparel.CoversBodyPart(part)) { dmgMult -= apparel.GetStatValue(armorRatingStat); } if (dmgMult <= 0) { dmgMult = 0; break; } } } return(dmgAmount * dmgMult); }