LTS.Integrated_Implants-Forked/1.5/Assemblies/Implants/LTS_Implants.cs

3874 lines
164 KiB
C#

using HarmonyLib;
using Microsoft.SqlServer.Server;
using Mono.Cecil.Cil;
using RimWorld;
using RimWorld.Planet;
using RimWorld.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Linq.Expressions;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Remoting.Messaging;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Verse;
using Verse.AI;
using Verse.AI.Group;
using Verse.Noise;
using Verse.Sound;
using static HarmonyLib.Code;
using static RimWorld.FoodUtility;
using static System.Net.Mime.MediaTypeNames;
using static UnityEngine.GraphicsBuffer;
using static UnityEngine.Scripting.GarbageCollector;
namespace LTS_Implants
{
public class LTS_ChangeHediff : HediffWithComps
{
public override void Tick()
{
base.Tick();
if (Find.TickManager.TicksGame % (def.GetModExtension<LTS_IModExtension>()?.LTS_TicksBetweenPulse ?? 900) == 0)//pulses every 15 seconds, or LTS_TicksBetweenPulse
{
Hediff hediff = this.pawn.health?.hediffSet?.GetFirstHediffOfDef(def.GetModExtension<LTS_IModExtension>()?.LTS_Hediff);//LTS_Hediff is the effected hediff
if (hediff != null)
{
hediff.Severity += (def.GetModExtension<LTS_IModExtension>()?.LTS_Severity ?? -0.005f);//heal by 0.005/0.5%, or LTS_Severity
//Log.Message("I am affecting " + hediff + " By " + (def.GetModExtension<LTS_IModExtension>()?.LTS_Severity ?? -0.005f));
}
else
{
//Log.Message("I can't find the hediff");
}
}
}
}
public class RitualOutcomeComp_PawnHasHediff : RitualOutcomeComp_Quality
{
public override QualityFactor GetQualityFactor(Precept_Ritual ritual, TargetInfo ritualTarget, RitualObligation obligation, RitualRoleAssignments assignments, RitualOutcomeComp_Data data)
{
Hediff pawn = this.TargetHasHediff(assignments);
if (pawn == null)//this makes it not show up in the list if the pawn doesn't have the hediff
{
return null;
}
bool flag = pawn != null;
float num = (flag ? this.qualityOffset : 0f);
return new QualityFactor
{
label = labelMet,
present = flag,
qualityChange = this.ExpectedOffsetDesc(true, num),
quality = num,
positive = true,
priority = 4f,
count = specialMessage,
toolTip = tipMessage,
};
}
private Hediff TargetHasHediff(RitualRoleAssignments assignments)//returns true if the target have the hediff
{
Pawn mother = assignments.FirstAssignedPawn(this.role);
return mother.health?.hediffSet?.GetFirstHediffOfDef(this.hediff);
}
public override string GetDesc(LordJob_Ritual ritual = null, RitualOutcomeComp_Data data = null)
{
string text = ((this.qualityOffset < 0f) ? "" : "+");
return ((this.TargetHasHediff(ritual.assignments) != null) ? this.label : this.labelNotMet).CapitalizeFirst().Formatted(Array.Empty<NamedArgument>()) + ": " + "OutcomeBonusDesc_QualitySingleOffset".Translate(text + this.qualityOffset.ToStringPercent()) + ".";
}
public override float QualityOffset(LordJob_Ritual ritual, RitualOutcomeComp_Data data)
{
if (this.TargetHasHediff(ritual.assignments) == null)
{
return 0f;
}
return this.qualityOffset;
}
protected override string ExpectedOffsetDesc(bool positive, float quality = 0f)
{
if (!positive)
{
return "";
}
return quality.ToStringWithSign("0.#%");
}
public class test
{
public string chance = "1";
}
public override float Count(LordJob_Ritual ritual, RitualOutcomeComp_Data data)
{
return (float)((this.TargetHasHediff(ritual.assignments) != null) ? 1 : 0);
}
public string tipMessage;
public string labelNotMet;
public string specialMessage;
public string labelMet;
[NoTranslate]
public string role;
[NoTranslate]
public HediffDef hediff;
}
public class Recipe_InstallImplantNeedingGene : Recipe_InstallImplant
{
public override bool AvailableOnNow(Thing thing, BodyPartRecord part = null)
{
Pawn pawn;
//return (pawn = thing as Pawn) != null && (this.recipe.genderPrerequisite ?? pawn.gender) == pawn.gender && (!this.recipe.mustBeFertile || !pawn.Sterile(false)) && (this.recipe.allowedForQuestLodgers || !pawn.IsQuestLodger()) && (this.recipe.minAllowedAge <= 0 || pawn.ageTracker.AgeBiologicalYears >= this.recipe.minAllowedAge) && (this.recipe.developmentalStageFilter == null || this.recipe.developmentalStageFilter.Value.Has(pawn.DevelopmentalStage)) && pawn.genes.HasGene(recipe.GetModExtension<LTS_IModExtension>()?.LTS_Gene);
if ((pawn = thing as Pawn) == null)
{
return false;
}
if ((this.recipe.genderPrerequisite ?? pawn.gender) != pawn.gender)
{
return false;
}
if (this.recipe.mustBeFertile && pawn.Sterile())
{
return false;
}
if (!this.recipe.allowedForQuestLodgers && pawn.IsQuestLodger())
{
return false;
}
if (this.recipe.minAllowedAge > 0 && pawn.ageTracker.AgeBiologicalYears < this.recipe.minAllowedAge)
{
return false;
}
if (this.recipe.developmentalStageFilter != null && !this.recipe.developmentalStageFilter.Value.Has(pawn.DevelopmentalStage))
{
return false;
}
if (ModsConfig.AnomalyActive)
{
if (this.recipe.mutantBlacklist != null && pawn.IsMutant && this.recipe.mutantBlacklist.Contains(pawn.mutant.Def))
{
return false;
}
if (this.recipe.mutantPrerequisite != null && (!pawn.IsMutant || !this.recipe.mutantPrerequisite.Contains(pawn.mutant.Def)))
{
return false;
}
}
//if (!(recipe.GetModExtension<LTS_IModExtension>()?.LTS_GenePreventsInstall ?? false) && !(pawn?.genes?.HasGene(recipe.GetModExtension<LTS_IModExtension>()?.LTS_Gene) ?? false))
//if ((recipe.GetModExtension<LTS_IModExtension>()?.LTS_GenePreventsInstall ?? false) == (pawn?.genes?.HasActiveGene(recipe.GetModExtension<LTS_IModExtension>()?.LTS_Gene) ?? false))//returns false if needs gene (false) but doesn't have it (false) or gene prevents (true) and has gene (true)
List<GeneDef> genes = recipe?.GetModExtension<LTS_IModExtension>()?.LTS_Genes;
if (genes.Count > 0)
{
for (int i = 0; i <= genes.Count - 1; i++)
{
if ((recipe.GetModExtension<LTS_IModExtension>()?.LTS_GenePreventsInstall ?? false) == (pawn?.genes?.HasActiveGene(genes[i]) ?? false))//returns false if needs gene (false) but doesn't have it (false) or gene prevents (true)
{
return false;
}
}
}
//foreach (GeneDef gen in genes)
//{
// Log.Message("no issues so far.");
//}
//foreach (GeneDef gen in pawn.genes.GenesListForReading)
//{
// Log.Message("no issues so far.");
//}
return true;
}
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
{
if (billDoer != null)
{
if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
{
return;
}
TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[] { billDoer, pawn });
}
pawn.health.AddHediff(this.recipe.addsHediff, part, null, null);
if (pawn.genes?.GetFirstGeneOfType<Gene_Hemogen>() != null)
{
pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().SetMax(pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().Max + recipe.GetModExtension<LTS_IModExtension>()?.LTS_HemogenMaxOffset ?? 0); //Offsets max hemogen by LTS_HemogenMaxOffset, or 0 if LTS_HemogenMaxOffset is null.
}
}
}
public class Recipe_RemoveImplantWithMaxHemogenEffect : Recipe_RemoveImplant
{
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
{
MedicalRecipesUtility.IsClean(pawn, part);
bool flag = this.IsViolationOnPawn(pawn, part, Faction.OfPlayer);
if (billDoer != null)
{
if (base.CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
{
return;
}
TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[] { billDoer, pawn });
if (!pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined, null, null).Contains(part))
{
return;
}
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault((Hediff x) => x.def == this.recipe.removesHediff);
if (hediff != null)
{
if (hediff.def.spawnThingOnRemoved != null)
{
GenSpawn.Spawn(hediff.def.spawnThingOnRemoved, billDoer.Position, billDoer.Map, WipeMode.Vanish);
}
pawn.health.RemoveHediff(hediff);
pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().SetMax(pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().Max + recipe.GetModExtension<LTS_IModExtension>()?.LTS_HemogenMaxOffset ?? 0); //Offsets max hemogen by LTS_HemogenMaxOffset, or 0 if LTS_HemogenMaxOffset is null.
}
}
if (flag)
{
base.ReportViolation(pawn, billDoer, pawn.HomeFaction, -70, null);
}
}
}
public class CompProperties_AbilityMechCluster : CompProperties_AbilityEffect
{
public CompProperties_AbilityMechCluster()
{
this.compClass = typeof(CompAbilityEffect_MechCluster);
}
public float displayRadius;
}
public class CompAbilityEffect_MechCluster : CompAbilityEffect
{
public new CompProperties_AbilityMechCluster Props
{
get
{
return (CompProperties_AbilityMechCluster)this.props;
}
}
public bool ShouldHaveInspectString
{
get
{
return ModsConfig.BiotechActive && this.parent.pawn.RaceProps.IsMechanoid;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
if (Faction.OfMechanoids == null)
{
Messages.Message("MessageNoFactionForVerbMechCluster".Translate(), this.parent.pawn, MessageTypeDefOf.RejectInput, null, false);
}
else
{
MechClusterUtility.SpawnCluster(target.Cell, this.parent.pawn.MapHeld, MechClusterGenerator.GenerateClusterSketch(2500f, this.parent.pawn.MapHeld, true, true), true, false, null);
}
}
public override void PostApplied(List<LocalTargetInfo> targets, Map map)
{
base.PostApplied(targets, map);
if (this.parent.def.defName == "MechhiveSatelliteUplink") //add field for cooldownFactorStat. Change this if statement to if it's not null. change the contents of getstatvalue on the next line to that field.
{
this.parent.StartCooldown(Mathf.RoundToInt(this.parent.def.cooldownTicksRange.RandomInRange * this.parent.pawn?.GetStatValue(StatDef.Named("MechhiveSatelliteUplinkCooldownFactor")) ?? 1f));
}
}
public override void DrawEffectPreview(LocalTargetInfo target)
{
GenDraw.DrawRadiusRing(target.Cell, this.Props.displayRadius);
}
public override string CompInspectStringExtra()
{
if (!this.ShouldHaveInspectString)
{
return null;
}
if (this.parent.CanCast)
{
return "AbilityMechSmokepopCharged".Translate();
}
return "AbilityMechSmokepopRecharging".Translate(this.parent.CooldownTicksRemaining.ToStringTicksToPeriod(true, false, true, true, false));
}
}
//public class CompProperties_MechanitorMechCarrier : CompProperties_AbilityEffect
//{
// public CompProperties_MechanitorMechCarrier()
// {
// this.compClass = typeof(CompAbilityEffect_MechanitorMechCarrier);
// }
// public ThingDef fixedIngredient;
// public int costPerPawn;
// //public int maxIngredientCount;
// public StatDef maxIngredientStat;
// public SoundDef soundReload;
// public int startingIngredientCount;
// public PawnKindDef spawnPawnKind;
// public int cooldownTicks = 900;
// public int maxPawnsToSpawn = 2;
// public EffecterDef spawnEffecter;
// public EffecterDef spawnedMechEffecter;
// public bool attachSpawnedEffecter;
// public bool attachSpawnedMechEffecter;
//}
//public class CompAbilityEffect_MechanitorMechCarrier : CompAbilityEffect
//{
// public new CompProperties_MechanitorMechCarrier Props
// {
// get
// {
// return (CompProperties_MechanitorMechCarrier)this.props;
// }
// }
// //public int remainingCharges
// //{
// // get
// // {
// // return this.ingredientCountRemaining / this.Props.costPerPawn;
// // }
// //}
// public override void CompTick()
// {
// base.CompTick();
// if (Find.TickManager.TicksGame % 3000 == 0 && this.ingredientCountRemaining != MaxIngredients)//60,000 ticks in a day. 20 steel a day would be 1/3000 //temporary steel regeneration for untill I can work up the will to figure out jobdrivers.
// {
// this.ingredientCountRemaining++;
// }
// if (Find.Selector.IsSelected(parent.pawn) && (int)Find.TickManager.CurTimeSpeed != 0 && Find.TickManager.TicksGame % (int)Find.TickManager.CurTimeSpeed == 0)//if the mechanitor is selected, and once erry 60/1 irl seconds
// {
// for (int i = 0; i < spawnedPawns.Count; i++)
// {
// if (!spawnedPawns[i].Dead)
// {
// GenDraw.DrawLineBetween(this.parent.pawn.TrueCenter(), spawnedPawns[i].TrueCenter());
// }
// }
// }
// //Log.Message("ingredients: " + ingredientCountRemaining);
// }
// public override void DrawEffectPreview(LocalTargetInfo target)
// {
// base.DrawEffectPreview(target);
// }
// //public override void CompTick()
// //{
// // if (Find.TickManager.TicksGame % 3000 == 0 && this.ingredientCountRemaining != MaxIngredients)//60,000 ticks in a day. 20 steel a day would be 1/3000 //temporary steel regeneration for untill I can work up the will to figure out jobdrivers.
// // {
// // this.ingredientCountRemaining++;
// // }
// // if (!Find.Selector.IsSelected(parent))
// // {
// // return;
// // }
// // for (int i = 0; i < spawnedPawns.Count; i++)
// // {
// // if (!spawnedPawns[i].Dead)
// // {
// // GenDraw.DrawLineBetween(this.parent.pawn.TrueCenter(), spawnedPawns[i].TrueCenter());
// // }
// // }
// //}
// public override void Initialize(AbilityCompProperties props)
// {
// //Log.Error("Mechwomb ");
// base.Initialize(props);
// if (ingredientCountRemaining == -1)
// {
// //ingredientCountRemaining = this.Props.startingIngredientCount;
// }
// }
// public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
// {
// //Log.Message("Apply called");
// base.Apply(target, dest);
// TrySpawnPawns();
// }
// public int maxspawn()
// {
// int max = (int)this.ingredientCountRemaining / this.Props.costPerPawn;
// if (max > 2) { return 2; }
// else { return max; }
// }
// public void TrySpawnPawns()
// {
// int maxCanSpawn = maxspawn();
// if (maxCanSpawn <= 0)
// {
// return;
// }
// PawnGenerationRequest pawnGenerationRequest = new PawnGenerationRequest(this.Props.spawnPawnKind, this.parent.pawn.Faction, PawnGenerationContext.NonPlayer, -1, true, false, false, true, false, 1f, false, true, false, true, true, false, false, false, false, 0f, 0f, null, 1f, null, null, null, null, null, null, null, null, null, null, null, null, false, false, false, false, null, null, null, null, null, 0f, DevelopmentalStage.Newborn, null, null, null, false, false, false, -1, 0, false);
// Pawn pawn;
// Lord lord = (((pawn = this.parent.pawn as Pawn) != null) ? pawn.GetLord() : null);
// for (int i = 0; i < maxCanSpawn; i++)
// {
// Pawn pawn2 = PawnGenerator.GeneratePawn(pawnGenerationRequest);
// GenSpawn.Spawn(pawn2, this.parent.pawn.Position, this.parent.pawn.Map, WipeMode.Vanish);
// this.spawnedPawns.Add(pawn2);
// if (lord != null)
// {
// lord.AddPawn(pawn2);
// }
// ingredientCountRemaining -= this.Props.costPerPawn; // removes the amount of steel needed to make a mech from the stored steel
// if (this.Props.spawnedMechEffecter != null)
// {
// Effecter effecter = new Effecter(this.Props.spawnedMechEffecter);
// effecter.Trigger(this.Props.attachSpawnedMechEffecter ? pawn2 : new TargetInfo(pawn2.Position, pawn2.Map, false), TargetInfo.Invalid, -1);
// effecter.Cleanup();
// }
// }
// this.cooldownTicksRemaining = this.Props.cooldownTicks;
// if (this.Props.spawnEffecter != null)
// {
// Effecter effecter2 = new Effecter(this.Props.spawnEffecter);
// effecter2.Trigger(this.Props.attachSpawnedEffecter ? this.parent.pawn : new TargetInfo(this.parent.pawn.Position, this.parent.pawn.Map, false), TargetInfo.Invalid, -1);
// effecter2.Cleanup();
// }
// }
// //go reload this
// public bool NeedsReload(bool allowForcedReload)
// {
// if (this.Props.fixedIngredient == null) //if no ingredient is set
// {
// return false;
// }
// if (MaxIngredients - ingredientCountRemaining == 0) // if it's full
// {
// return remainingCharges != MaxCharges;
// }
// if (!allowForcedReload)
// {
// return this.remainingCharges == 0;
// }
// return remainingCharges != MaxCharges;
// }
// public void ReloadFrom(Thing ammo)//I think that represents the specific stack, not the type
// {
// if (this.NeedsReload(false))
// {
// return;
// }
// if (ammo.stackCount < this.Props.costPerPawn)
// {
// return;
// }
// int num = Mathf.Clamp(ammo.stackCount / this.Props.costPerPawn, 0, MaxCharges - remainingCharges);
// ammo.SplitOff(num * this.Props.costPerPawn).Destroy(DestroyMode.Vanish);
// //this.remainingCharges += num;
// this.ingredientCountRemaining += num * this.Props.costPerPawn;
// if (this.Props.soundReload != null)
// {
// this.Props.soundReload.PlayOneShot(new TargetInfo(this.parent.pawn.Position, this.parent.pawn.Map, false));
// }
// }
// public override bool GizmoDisabled(out string reason)
// {
// //Log.Warning(ingredientCountRemaining + " out of "+ Props.costPerPawn + " steel.");
// if (ingredientCountRemaining < Props.costPerPawn)
// {
// reason = parent.def.label + " requires " + Props.costPerPawn + " " + Props.fixedIngredient + " but " + parent.pawn.Name + " only has " + ingredientCountRemaining + " " + Props.fixedIngredient;
// return true;
// }
// return base.GizmoDisabled(out reason);
// }
// public int remainingCharges
// {
// get
// {
// return this.ingredientCountRemaining / this.Props.costPerPawn;
// }
// }
// public int MaxCharges
// {
// get
// {
// return MaxIngredients / this.Props.costPerPawn;
// }
// }
// public int MaxIngredients
// {
// get
// {
// return (int)this.parent.pawn.GetStatValue(this.Props.maxIngredientStat);// Current max ingredients
// }
// }
// public string LabelRemaining
// {
// get
// {
// return string.Format("{0} / {1}", remainingCharges, MaxCharges);
// }
// } // string of current/max spawnable grubs.
// public List<Pawn> GetSpawnedPawns()
// {
// return spawnedPawns;
// }
// private int replenishInTicks = -1;
// private int cooldownTicksRemaining;
// //private ThingOwner innerContainer;
// private List<Pawn> spawnedPawns = new List<Pawn>();
// //public ThingDef ammoDef;
// //public int ingredientCountRemaining = -1;
// public int ingredientCountRemaining;
// public int ammoCountToRefill;
// public int ammoCountPerCharge;
// public SoundDef soundReload;
// public override void PostExposeData()//used for saving data between game loads
// {
// base.PostExposeData();
// Scribe_Values.Look(ref ingredientCountRemaining, "ingredientCountRemaining", this.Props.startingIngredientCount);
// }
//}
//public class Command_AbilityReloadable : Command_Ability
//{
// public Command_AbilityReloadable(Ability ability, Pawn pawn) : base(ability, pawn)
// {
// }
// public override string TopRightLabel
// {
// get
// {
// //AbilityDef def = this.ability.def;
// //string text = "";
// //if (def.EntropyGain > 1E-45f)
// //{
// // text += "NeuralHeatLetter".Translate() + ": " + def.EntropyGain.ToString() + "\n";
// //}
// return this.ability.CompOfType<CompAbilityEffect_MechanitorMechCarrier>().LabelRemaining;
// //return "Test";
// }
// }
//}
//public class AbilityReloadable : Ability
//{
// public AbilityReloadable() : base() { }
// public AbilityReloadable(Pawn pawn) : base(pawn) { }
// public AbilityReloadable(Pawn pawn, AbilityDef abilityDef) : base(pawn, abilityDef) { }
// public AbilityReloadable(Pawn pawn, Precept sourcePrecept) : base(pawn, sourcePrecept) { }
// public AbilityReloadable(Pawn pawn, Precept sourcePrecept, AbilityDef abilityDef) : base(pawn, sourcePrecept, abilityDef) { }
// //public AbilityReloadable() : base() { }
// public override IEnumerable<Command> GetGizmos() // sets the gismo to my editable one.
// {
// //if (!ModLister.RoyaltyInstalled)
// //{
// // yield break;
// //}
// if (this.gizmo == null)
// {
// this.gizmo = new Command_AbilityReloadable(this, this.pawn);
// }
// yield return this.gizmo;
// }
// //public override bool CanCast // checks if the ability can cast.
// //{
// // get
// // {
// // if (!base.CanCast)
// // {
// // return false;
// // }
// // return this.CompOfType<CompAbilityEffect_MechanitorMechCarrier>().maxspawn() > 0; //ability needs to be able to spawn at least 1 grub.
// // }
// //}
//}
//public class LTS_ShieldHediff : Hediff_Implant
//{
// public float PsychicShieldCurrentHealth;
// public float PsychicShieldMaxHealth;
// public int PsychicShieldRegenInteruptedTicks;
// public string Mode;//full, recharging, broken, steady
// public override void PostAdd(DamageInfo? dinfo)
// {
// base.PostAdd(dinfo);
// UpdatePsychicShieldMaxHealth();
// PsychicShieldCurrentHealth = PsychicShieldMaxHealth;
// //PsychicShieldCurrentHealth = 0;//for testing
// }
// public void UpdatePsychicShieldMaxHealth()
// {
// PsychicShieldMaxHealth = pawn?.GetStatValue(StatDef.Named("PsychicShieldMaxHealth")) ?? 0f;
// }
// public override void Tick()
// {
// base.Tick();
// //if (Find.TickManager.TicksGame % 10 == 0 && PsychicShieldCurrentHealth != PsychicShieldMaxHealth && PsychicShieldRegenInteruptedTicks <= 0)
// if (PsychicShieldCurrentHealth != PsychicShieldMaxHealth && PsychicShieldRegenInteruptedTicks <= 0)
// {
// //PsychicShieldCurrentHealth++;
// PsychicShieldCurrentHealth += PsychicShieldMaxHealth / 300; //full regen in 5 seconds
// if (PsychicShieldCurrentHealth > PsychicShieldMaxHealth)
// {
// PsychicShieldCurrentHealth = PsychicShieldMaxHealth;
// }
// }
// else
// {
// PsychicShieldRegenInteruptedTicks--;
// }
// UpdatePsychicShieldMaxHealth();
// //60 tick/second
// //regenerate in 5 seconds
// //regenerate in 300 ticks.
// }
// public override string LabelInBrackets //add (x/y) health information next to hediff
// {
// get
// {
// return ((int)PsychicShieldCurrentHealth).ToString() + "/" + ((int)PsychicShieldMaxHealth).ToString();
// }
// }
// public bool CheckForShield()
// {
// return true;
// }
// public override void ExposeData()//used for saving data between game loads
// {
// base.ExposeData();
// Scribe_Values.Look(ref PsychicShieldCurrentHealth, "PsychicShieldCurrentHealth", 0f);
// Scribe_Values.Look(ref PsychicShieldMaxHealth, "PsychicShieldMaxHealth", 0f);
// Scribe_Values.Look(ref PsychicShieldRegenInteruptedTicks, "PsychicShieldRegenInteruptedTicks", 0);
// }
//}
public class LTS_HediffCompProperties_Mote : HediffCompProperties
{
//public AbilityDef abilityDef;
public LTS_HediffCompProperties_Mote()
{
compClass = typeof(LTS_HediffComp_Mote);
}
}
public class LTS_HediffComp_Mote : HediffComp
{
public LTS_HediffCompProperties_Mote Props => (LTS_HediffCompProperties_Mote)props;
//public override void Notify_PawnKilled()
//{
// foreach (Pawn i in base.Pawn.abilities.GetAbility(Props.abilityDef).CompOfType<CompAbilityEffect_MechanitorMechCarrier>().GetSpawnedPawns())
// {
// if (!i.Dead)
// {
// i.Kill(null, null);
// }
// }
//}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (this.I_ArchicHaloMote != null && (parent.pawn.Rotation != PreviousRotation))
{
if (parent.pawn.Rotation == Rot4.East) RotationOffset = new Vector3(0.1f, 0, 0.04f); //horizontal, depth, vertical //nevermind, it changes per direction
else if (parent.pawn.Rotation == Rot4.West) RotationOffset = -new Vector3(0.1f, 0, -0.04f);
else if (parent.pawn.Rotation == Rot4.North) RotationOffset = new Vector3(0, 0, 0.08f);
else RotationOffset = new Vector3(0, 0, 0);
}
//Log.Message(HorizontalOffset);
if (((this.I_ArchicHaloMote == null) || (this.I_ArchicHaloMote.Destroyed) || (parent.pawn.Rotation != PreviousRotation)) && (!parent.pawn.InBed() && parent.pawn.Awake() && !parent.pawn.Downed))
{
ThingDef I_ArchicHaloMoteDef = I_DefOf.I_ArchicHaloMote;
if (this.I_ArchicHaloMote != null) // if a halo exists
{
exactRotation = I_ArchicHaloMote.exactRotation;
if (parent.pawn.Rotation != PreviousRotation) //if the pawn's changed direction
{
I_ArchicHaloMoteDef.mote.fadeInTime = 0.2f;
//this.I_ArchicHaloMote.Destroy();
I_ArchicHaloMote.def.mote.fadeOutTime = 0.2f;
}
}
this.I_ArchicHaloMote = MoteMaker.MakeAttachedOverlay(parent.pawn, I_ArchicHaloMoteDef, Vector3.zero - parent.pawn.Rotation.FacingCell.ToVector3() * 0.05f + RotationOffset, 1f, -1f); //Vec3(vetrtical), scale, existence override.
I_ArchicHaloMote.exactRotation = exactRotation;
}
if (!parent.pawn.InBed() && parent.pawn.Awake() && !parent.pawn.Downed)
{
this.I_ArchicHaloMote.Maintain();
}
//this.I_ArchicHaloMote.rotationRate = 1f;
//this.I_ArchicHaloMote.Rotation.Rotate(RotationDirection.Clockwise);
I_ArchicHaloMote.exactRotation += 0.2f;
//I_ArchicHaloMote.exactPosition += new Vector3(1, 0.01f, 0);
//Log.Message(this.I_ArchicHaloMote.exactRotation);
PreviousRotation = parent.pawn.Rotation;
}
private Mote I_ArchicHaloMote;
private Vector3 RotationOffset = new Vector3(0, 0, 0);
private Rot4 PreviousRotation;
private float exactRotation = 0;
private bool appearInstantly = false;
public override void CompExposeData()
{
base.CompExposeData();
Scribe_Deep.Look(ref I_ArchicHaloMote, "I_ArchicHaloMote");
}
}
public class LTS_CompProperties_ToggleHediff : CompProperties_AbilityEffect
{
public LTS_CompProperties_ToggleHediff()
{
this.compClass = typeof(LTS_CompAbilityEffect_ToggleHediff);
}
public HediffDef ToggleHediff;
public float StartSeverity;
//public string location = null;
public BodyPartDef location = null;
}
public class LTS_CompAbilityEffect_ToggleHediff : CompAbilityEffect //if the pawn doesn't have the hediff, add it. If the pawn does have the hediff, remove it. If this is removed and the pawn has the hediff, remove it.
{
public new LTS_CompProperties_ToggleHediff Props
{
get
{
return (LTS_CompProperties_ToggleHediff)this.props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
if (target.Pawn != null)
{
if (target.Pawn.health?.hediffSet?.GetFirstHediffOfDef(this.Props.ToggleHediff) != null)
{
target.Pawn.health.RemoveHediff(target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff));
}
else
{
target.Pawn.health.AddHediff(this.Props.ToggleHediff, location(target));
if (target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff).TryGetComp<HediffComp_Lactating>() != null)
{
target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff).TryGetComp<HediffComp_Lactating>().TryCharge(-0.124f);
}
}
}
}
public BodyPartRecord location(LocalTargetInfo target)
{
if (Props.location == null) { return null; }
//return target.Pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Where(part => part.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbSegment)).ToList()[0];
//return target.Pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Where(part => part.def.label == Props.location).ToList()[0];
return target.Pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Where(part => part.def == Props.location).ToList()[0];
}
}
public class Recipe_RemoveImplantWithToggleHediff : Recipe_RemoveImplant
{
public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List<Thing> ingredients, Bill bill)
{
MedicalRecipesUtility.IsClean(pawn, part);
bool flag = IsViolationOnPawn(pawn, part, Faction.OfPlayer);
if (billDoer != null)
{
if (CheckSurgeryFail(billDoer, pawn, ingredients, part, bill))
{
return;
}
TaleRecorder.RecordTale(TaleDefOf.DidSurgery, billDoer, pawn);
if (!pawn.health.hediffSet.GetNotMissingParts().Contains(part))
{
return;
}
Hediff hediff = pawn.health.hediffSet.hediffs.FirstOrDefault((Hediff x) => x.def == recipe.removesHediff);
if (hediff != null)
{
if (hediff.def.spawnThingOnRemoved != null)
{
GenSpawn.Spawn(hediff.def.spawnThingOnRemoved, billDoer.Position, billDoer.Map);
}
pawn.health.RemoveHediff(hediff);
}
if (recipe.GetModExtension<LTS_IModExtension>().LTS_Hediff != null)
{
}
Hediff toggleableHediff = pawn.health.hediffSet.GetFirstHediffOfDef(recipe.GetModExtension<LTS_IModExtension>().LTS_Hediff); //if the optional hediff is there, remove it.
if (toggleableHediff != null)
{
pawn.health.RemoveHediff(toggleableHediff);
}
}
if (flag)
{
ReportViolation(pawn, billDoer, pawn.HomeFaction, -70);
}
}
}
public class LTS_CompProperties_Dreadheart : HediffCompProperties
{
public LTS_CompProperties_Dreadheart()
{
this.compClass = typeof(LTS_HediffComp_Dreadheart);
}
public int ticksBetweenBurst;
public int pointsPerBurst;
}
public class LTS_HediffComp_Dreadheart : HediffComp //rampancy
{
//public new LTS_CompProperties_Dreadheart Props
//{
// get
// {
// return (LTS_CompProperties_Dreadheart)this.props;
// }
//}
private new LTS_CompProperties_Dreadheart Props => props as LTS_CompProperties_Dreadheart;
public List<PawnKindDef> fleshbeastSpawnList = new List<PawnKindDef>();
public bool firstWaveNotGenerated = true;
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (firstWaveNotGenerated)
{
//Messages.Message("Rampant regeneration!", (parent.pawn), MessageTypeDefOf.NegativeEvent);
SendLetter();
GenerateFleshBeastSpawnList(this.Props.pointsPerBurst);
foreach (IntVec3 position in GenRadial.RadialCellsAround(parent.pawn.Position, 2, true))
{
//GenSpawn.Spawn(ThingDefOf.Filth_TwistedFlesh, position, parent.pawn.Map);
//ThingDef blood = ThingDefOf.Filth_Blood;
FilthMaker.TryMakeFilth(position, parent.pawn.MapHeld, ThingDefOf.Filth_TwistedFlesh, parent.pawn.LabelIndefinite());
FilthMaker.TryMakeFilth(position, parent.pawn.MapHeld, ThingDefOf.Filth_Blood, parent.pawn.LabelIndefinite());
}
firstWaveNotGenerated = false;
}
if (Find.TickManager.TicksGame % this.Props.ticksBetweenBurst == 0)//every (ticksBetweenBurst), generate a list of fleshbeasts to spawn with (fleshbeastPoints).
{
GenerateFleshBeastSpawnList(this.Props.pointsPerBurst);
foreach (IntVec3 position in GenRadial.RadialCellsAround(parent.pawn.Position, 2, true))
{
FilthMaker.TryMakeFilth(position, parent.pawn.MapHeld, ThingDefOf.Filth_TwistedFlesh, parent.pawn.LabelIndefinite());
FilthMaker.TryMakeFilth(position, parent.pawn.MapHeld, ThingDefOf.Filth_Blood, parent.pawn.LabelIndefinite());
}
}
if (Find.TickManager.TicksGame % 60 == 0 && fleshbeastSpawnList.Count > 0) // every second, if the spawningFleshbeasts list isn't empty, spawn one and remove it from the list. Maybespawn flesh filth too.
{
SpawnFleshBeast();
fleshbeastSpawnList.Remove(fleshbeastSpawnList[0]);
EffecterDefOf.MeatExplosion.Spawn(parent.pawn.PositionHeld, parent.pawn.MapHeld).Cleanup();
}
}
public void SpawnFleshBeast()
{
Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(fleshbeastSpawnList[0], Faction.OfEntities, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: false, allowDead: false, allowDowned: false, canGeneratePawnRelations: true, mustBeCapableOfViolence: false, 1f, forceAddFreeWarmLayerIfNeeded: false, allowGay: true, allowPregnant: false, allowFood: true, allowAddictions: true, inhabitant: false, certainlyBeenInCryptosleep: false, forceRedressWorldPawnIfFormerColonist: false, worldPawnFactionDoesntMatter: false, 0f, 0f, null, 1f, null, null, null, null, null, 0f));
FleshbeastUtility.SpawnPawnAsFlyer(pawn, parent.pawn.MapHeld, parent.pawn.PositionHeld);
}
private void GenerateFleshBeastSpawnList(int points)
{
while (points >= PawnKindDefOf.Fingerspike.combatPower)
{
PawnKindDef pawnKindDef = FleshbeastUtility.AllFleshbeasts.RandomElement();
while (pawnKindDef.combatPower > 100)//prevents bulbfreaks
{
pawnKindDef = FleshbeastUtility.AllFleshbeasts.RandomElement();
}
fleshbeastSpawnList.Add(pawnKindDef);
points -= (int)pawnKindDef.combatPower;
}
}
private void SendLetter()
{
//IncidentWorker.SendIncidentLetter("Rampant regeneration!", parent.pawn.Name + " drops to the ground, screaming in agony. " + parent.pawn.Possessive() + " flesh roils and writhes as great pillars of meat shoot forth from it, twisting and contorting into horrific fleshbeasts.", LetterDefOf.ThreatBig, new IncidentParms(), parent.pawn, IncidentDefOf.RaidEnemy);
Find.LetterStack.ReceiveLetter(LetterMaker.MakeLetter("Rampant regeneration!", parent.pawn.NameShortColored + " drops to the ground, screaming in agony. " + parent.pawn.Possessive().CapitalizeFirst() + " flesh roils and writhes as great pillars of meat shoot forth from it, twisting and contorting into horrific fleshbeasts.", LetterDefOf.ThreatBig, parent.pawn));
}
}
public class CompProperties_DreadheartRegeneration : CompProperties_AbilityEffect
{
public CompProperties_DreadheartRegeneration()
{
this.compClass = typeof(CompAbilityEffect_DreadheartRegeneration);
}
public float severityPerUse;
}
public class CompAbilityEffect_DreadheartRegeneration : CompAbilityEffect
{
public new CompProperties_DreadheartRegeneration Props
{
get
{
return (CompProperties_DreadheartRegeneration)this.props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Pawn pawn = parent.pawn;
Hediff RampantRegenerationBuildup;
pawn.health.AddHediff(HediffDef.Named("DreadheartRegeneration"), null, null, null);
if ((RampantRegenerationBuildup = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("RampantRegenerationBuildup"))) != null)
{
RampantRegenerationBuildup.Severity += Props.severityPerUse;
if (RampantRegenerationBuildup.Severity >= 1)//rampancy check
{
pawn.health.RemoveHediff(RampantRegenerationBuildup);
pawn.health.AddHediff(HediffDef.Named("RampantRegeneration"), null, null, null);
}
}
else
{
//RampantRegenerationBuildup = HediffMaker.MakeHediff(HediffDef.Named("RampantRegenerationBuildup"), pawn);
RampantRegenerationBuildup = pawn.health.AddHediff(HediffDef.Named("RampantRegenerationBuildup"), null, null, null);
RampantRegenerationBuildup.Severity = Props.severityPerUse;
}
}
}
public class HediffCompProperties_PsychicPainFeedbackLoop : HediffCompProperties
{
public float range;
public HediffDef hediff;
public HediffCompProperties_PsychicPainFeedbackLoop()
{
compClass = typeof(LTS_HediffComp_PsychicPainFeedbackLoop);
}
}
public class LTS_HediffComp_PsychicPainFeedbackLoop : HediffComp
{
public new HediffCompProperties_PsychicPainFeedbackLoop Props
{
get
{
return (HediffCompProperties_PsychicPainFeedbackLoop)this.props;
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (parent.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychicPainFeedbackLoop")) != null)
{
parent.pawn.health.RemoveHediff(parent.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychicPainFeedbackLoop")));
}
//if (!parent.pawn.IsHashIntervalTick(30) || parent.pawn.health.hediffSet.PainTotal == 0) // only if the pawn is in pain
if (!(Find.TickManager.TicksGame % 30 == 0) || parent.pawn.health.hediffSet.PainTotal == 0)
{
return;
}
List<Pawn> allHumanlikeSpawned = parent.pawn.Map.mapPawns.AllHumanlikeSpawned;
for (int i = 0; i < allHumanlikeSpawned.Count; i++)
{
Pawn pawn = allHumanlikeSpawned[i];
if (pawn.RaceProps.Humanlike && parent.pawn.Position.InHorDistOf(pawn.PositionHeld, Props.range))
{
((Hediff_PainFeedbackLoop)pawn.health.GetOrAddHediff(HediffDef.Named("PsychicPainFeedbackLoop"))).lastTickInRangeOfAgonizer = GenTicks.TicksGame;
}
}
}
}
public class Hediff_PainFeedbackLoop : Hediff
{
public int lastTickInRangeOfAgonizer;
private const float FallRatePerHour = 0.33f;
private const float GainRatePerHour = 0.16f;
private const int AgonizerBufferTicks = 60;
public bool InRangeOfAgonizer => GenTicks.TicksGame <= lastTickInRangeOfAgonizer + AgonizerBufferTicks;
public override bool ShouldRemove
{
get
{
if (!InRangeOfAgonizer)
{
return base.ShouldRemove;
}
return false;
}
}
public override void Tick()
{
base.Tick();
if (!InRangeOfAgonizer)
{
Severity -= FallRatePerHour / 2500;
}
else
{
Severity += (GainRatePerHour / 2500) * pawn.GetStatValue(StatDefOf.PsychicSensitivity);
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref lastTickInRangeOfAgonizer, "lastTickInRangeOfAgonizer", 0);
}
}
public class Hediff_Blacksight : HediffWithComps
{
private const float ExposurePerSecond_Lit = -0.25f;
private const float ExposurePerSecond_Unlit = 0.25f;
public ThingDef moteDef = ThingDef.Named("Mote_HumanNoctolEyes");
private Mote mote;
public float EyeBrightness;
public override bool ShouldRemove => false;
public override void Tick()
{
base.Tick();
ChangeSeverity();
if (pawn.Spawned)
{
if (mote == null || mote.Destroyed)
{
mote = MoteMaker.MakeAttachedOverlay(pawn, moteDef, Vector3.zero);
mote.link1.rotateWithTarget = true;
}
if (!pawn.Downed)
{
EyeBrightness = Severity - 1f;
}
else EyeBrightness = 0f;
mote.instanceColor = new Color(1f, 1f, 1f, EyeBrightness);
mote.Maintain();
if (this.TryGetComp<HediffComp_Disappears>().ticksToDisappear <= 0) //if remaining time <= 0, remove hediff
{
pawn.health.RemoveHediff(this);
}
}
}
public void ChangeSeverity()
{
if (pawn.SpawnedOrAnyParentSpawned && pawn.IsHashIntervalTick(60) && !pawn.Dead)
{
if (pawn.MapHeld.glowGrid.PsychGlowAt(pawn.PositionHeld) != PsychGlow.Dark)
{
Severity += ExposurePerSecond_Lit;
}
else
{
Severity += ExposurePerSecond_Unlit;
if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.DarknessExposure) != null)//dangerous darkness check
{
pawn.health.RemoveHediff(pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.DarknessExposure));
}
}
}
}
}
public class LTS_Hediff_OnRemovalSpawner : HediffWithComps
{
PawnKindDef spawnedPawn = PawnKindDefOf.Metalhorror;
//public override void Notify_PawnCorpseSpawned()
//{
// base.Notify_PawnCorpseSpawned();
// Pawn pawnSpawned = PawnGenerator.GeneratePawn(new PawnGenerationRequest(spawnedPawn, Faction.OfEntities, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: false, allowDead: false, allowDowned: false, canGeneratePawnRelations: true, mustBeCapableOfViolence: false, 1f, forceAddFreeWarmLayerIfNeeded: false, allowGay: true, allowPregnant: false, allowFood: true, allowAddictions: true, inhabitant: false, certainlyBeenInCryptosleep: false, forceRedressWorldPawnIfFormerColonist: false, worldPawnFactionDoesntMatter: false, 0f, 0f, null, 1f, null, null, null, null, null, 1f, 0f));
// GenSpawn.Spawn(pawnSpawned, pawn.Position, pawn.MapHeld, WipeMode.Vanish);
// pawn.health.RemoveHediff(this);
//}
public override void PreRemoved()
{
base.PreRemoved();
Pawn pawnSpawned = PawnGenerator.GeneratePawn(new PawnGenerationRequest(spawnedPawn, Faction.OfEntities, PawnGenerationContext.NonPlayer, -1, forceGenerateNewPawn: false, allowDead: false, allowDowned: false, canGeneratePawnRelations: true, mustBeCapableOfViolence: false, 1f, forceAddFreeWarmLayerIfNeeded: false, allowGay: true, allowPregnant: false, allowFood: true, allowAddictions: true, inhabitant: false, certainlyBeenInCryptosleep: false, forceRedressWorldPawnIfFormerColonist: false, worldPawnFactionDoesntMatter: false, 0f, 0f, null, 1f, null, null, null, null, null, 1f, 0f));
GenSpawn.Spawn(pawnSpawned, pawn.Position, pawn.MapHeld, WipeMode.Vanish);
//Find.LetterStack.ReceiveLetter(LetterMaker.MakeLetter("Metalhorror operation", pawn.NameShortColored + " drops to the ground, screaming in agony. " + pawn.Possessive().CapitalizeFirst() + " flesh roils and writhes as great pillars of meat shoot forth from it, twisting and contorting into horrific fleshbeasts.", LetterDefOf.ThreatBig, pawn));
DoEmergingEffects();
if (pawn.Dead)
{
//Find.LetterStack.ReceiveLetter(LetterMaker.MakeLetter("Metalhorror emerging", "The death of " + pawn.NameShortColored + " has allowed " + pawn.Possessive() + " metalhorror symbiont to tear it's way out of " + pawn.Possessive() + " corpse. Free of " + pawn.NameShortColored + "'s control and full of fury, it will attack anyone it sees.", LetterDefOf.ThreatBig, pawn));
if (pawn.Faction == Faction.OfPlayer)
{
Find.LetterStack.ReceiveLetter(LetterMaker.MakeLetter("Metalhorror emerging", "A metalhorror is emerging! Slicing through flesh and skin, this nightmarish bladed creature is cutting its way out of its host. The metalhorror is emerging from " + pawn.NameShortColored + " as " + pawn.Possessive() + " death has caused it's containment mechanisms to fail.", LetterDefOf.ThreatBig, pawn));
}
}
else
{
Find.LetterStack.ReceiveLetter(LetterMaker.MakeLetter("Metalhorror operation", "Attempting to remove " + pawn.NameShortColored + "'s metalhorror symbiont has caused the twisting mass of liquid metal and filaments to attack. The symbiont has emerged from " + pawn.NameShortColored + " and morphed into a full metalhorror!", LetterDefOf.ThreatBig, pawn));
}
//pawn.health.RemoveHediff(this);
}
private void DoEmergingEffects()
{
EffecterDefOf.MetalhorrorEmerging.Spawn(pawn.PositionHeld, pawn.MapHeld).Cleanup();
IntVec3 positionHeld = pawn.PositionHeld;
Map mapHeld = pawn.MapHeld;
CellRect cellRect = new CellRect(positionHeld.x, positionHeld.z, 3, 3);
for (int i = 0; i < 5; i++)
{
IntVec3 randomCell = cellRect.RandomCell;
if (randomCell.InBounds(mapHeld) && GenSight.LineOfSight(randomCell, positionHeld, mapHeld))
{
FilthMaker.TryMakeFilth(randomCell, mapHeld, (i % 2 == 0) ? ThingDefOf.Filth_Blood : ThingDefOf.Filth_GrayFlesh);
}
}
}
}
public class LTS_Hediff_HeadFitter : HediffWithComps //on creation: get hair and head type, then set them to bald and narrow. on removal, set hair type to orignal (null check, check this works for newly spawning ghouls). Deep save. don't forget to null check due to xenobionic patcher
{
HairDef originalHair;
HeadTypeDef originalHeadTypeDef;
public override void PostMake()
{
base.PostMake();
if (pawn?.story?.hairDef != null)
{
if (pawn.story.hairDef != HairDefOf.Bald)
{
originalHair = pawn.story.hairDef;
pawn.story.hairDef = HairDefOf.Bald;
}
}
if (pawn?.story?.headType != null)
{
if (pawn.story.headType != def.GetModExtension<LTS_IModExtension>().LTS_HeadTypeDef)
{
originalHeadTypeDef = pawn.story.headType;
pawn.story.headType = def.GetModExtension<LTS_IModExtension>().LTS_HeadTypeDef;
}
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void Notify_Spawned()
{
base.Notify_Spawned();
PostMake();
}
public override void PostRemoved()
{
base.PostRemoved();
if (pawn?.story?.hairDef != null && originalHair != null)
{
pawn.story.hairDef = originalHair;
}
if (pawn?.story?.headType != null && originalHeadTypeDef != null)
{
pawn.story.headType = originalHeadTypeDef;
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Defs.Look(ref originalHair, "originalHair");
Scribe_Defs.Look(ref originalHeadTypeDef, "originalHeadTypeDef");
}
}
public class AbilityWhileDowned : Ability
{
public AbilityWhileDowned() : base() { }
public AbilityWhileDowned(Pawn pawn) : base(pawn) { }
public AbilityWhileDowned(Pawn pawn, AbilityDef abilityDef) : base(pawn, abilityDef) { }
public AbilityWhileDowned(Pawn pawn, Precept sourcePrecept) : base(pawn, sourcePrecept) { }
public AbilityWhileDowned(Pawn pawn, Precept sourcePrecept, AbilityDef abilityDef) : base(pawn, sourcePrecept, abilityDef) { }
public override bool GizmoDisabled(out string reason)
{
if (!CanCast)
{
if (CanCooldown)
{
reason = "AbilityOnCooldown".Translate(CooldownTicksRemaining.ToStringTicksToPeriod()).Resolve();
return true;
}
if (UsesCharges && RemainingCharges <= 0)
{
reason = "AbilityNoCharges".Translate();
return true;
}
reason = "AbilityAlreadyQueued".Translate();
return true;
}
if (!CanQueueCast)
{
reason = "AbilityAlreadyQueued".Translate();
return true;
}
if (!pawn.Drafted && def.disableGizmoWhileUndrafted && pawn.GetCaravan() == null && !DebugSettings.ShowDevGizmos)
{
reason = "AbilityDisabledUndrafted".Translate();
return true;
}
if (pawn.DevelopmentalStage.Baby())
{
reason = "IsIncapped".Translate(pawn.LabelShort, pawn);
return true;
}
//if (pawn.Downed)
//{
// reason = "CommandDisabledUnconscious".TranslateWithBackup("CommandCallRoyalAidUnconscious").Formatted(pawn);
// return true;
//}
if (pawn.Deathresting)
{
reason = "CommandDisabledDeathresting".Translate(pawn);
return true;
}
if (def.casterMustBeCapableOfViolence && pawn.WorkTagIsDisabled(WorkTags.Violent))
{
reason = "IsIncapableOfViolence".Translate(pawn.LabelShort, pawn);
return true;
}
if (!comps.NullOrEmpty())
{
for (int i = 0; i < comps.Count; i++)
{
if (comps[i].GizmoDisabled(out reason))
{
return true;
}
}
}
Lord lord;
if ((lord = pawn.GetLord()) != null)
{
AcceptanceReport acceptanceReport = lord.AbilityAllowed(this);
if (!acceptanceReport)
{
reason = acceptanceReport.Reason;
return true;
}
}
reason = null;
return false;
}
}
public class LTS_Hediff_MakeHulk : HediffWithComps
{
BodyTypeDef originalBody;
public override void PostAdd(DamageInfo? dinfo)
{
base.PostAdd(dinfo);
if (pawn?.story?.bodyType != null)
{
if (pawn.story.bodyType != BodyTypeDefOf.Hulk)
{
originalBody = pawn.story.bodyType;
pawn.story.bodyType = BodyTypeDefOf.Hulk;
}
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void Notify_Spawned()
{
base.Notify_Spawned();
PostAdd(null);
}
public override void PostRemoved()
{
base.PostRemoved();
if (pawn?.story?.bodyType != null && originalBody != null)
{
pawn.story.bodyType = originalBody;
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Defs.Look(ref originalBody, "originalBody");
}
}
public class LTS_HediffCompProperties_SpawnItemAtInterval : HediffCompProperties
{
public ThingDef item;
public int itemCount = 1;
public int intervalTicks;
public LTS_HediffCompProperties_SpawnItemAtInterval()
{
compClass = typeof(LTS_HediffComp_SpawnItemAtInterval);
}
}
public class LTS_HediffComp_SpawnItemAtInterval : HediffComp
{
public new LTS_HediffCompProperties_SpawnItemAtInterval Props
{
get
{
return (LTS_HediffCompProperties_SpawnItemAtInterval)this.props;
}
}
public override void CompPostTick(ref float severityAdjustment)
{
base.CompPostTick(ref severityAdjustment);
if (parent.pawn.IsHashIntervalTick(Props.intervalTicks) && parent.pawn.Spawned)
{
Thing thing = ThingMaker.MakeThing(Props.item);
thing.stackCount = Props.itemCount;
GenPlace.TryPlaceThing(thing, parent.pawn.Position, parent.pawn.MapHeld, ThingPlaceMode.Direct);
}
}
}
public class LTS_HediffCompProperties_HediffApparel : HediffCompProperties
{
public HediffDef maleHediffDef;
public HediffDef femaleHediffDef;
public HediffDef thinHediffDef;
public HediffDef hulkHediffDef;
public HediffDef fatHediffDef;
public LTS_HediffCompProperties_HediffApparel()
{
compClass = typeof(LTS_HediffComp_HediffApparel);
}
}
public class LTS_HediffComp_HediffApparel : HediffComp
{
public new LTS_HediffCompProperties_HediffApparel Props
{
get
{
return (LTS_HediffCompProperties_HediffApparel)this.props;
}
}
public override void CompPostMake()
{
base.CompPostMake();
CompPostPostAdd(null);
}
public override void CompPostPostAdd(DamageInfo? dinfo)
{
base.CompPostPostAdd(dinfo);
if (parent.pawn.story.bodyType == BodyTypeDefOf.Thin && parent.def.defName != Props.thinHediffDef.defName)
{
changingType = true;
parent.pawn.health.RemoveHediff(parent);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Hulk && parent.def.defName != Props.hulkHediffDef.defName)
{
changingType = true;
parent.pawn.health.RemoveHediff(parent);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Fat && parent.def.defName != Props.fatHediffDef.defName)
{
changingType = true;
parent.pawn.health.RemoveHediff(parent);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Female && parent.def.defName != Props.femaleHediffDef.defName)
{
changingType = true;
parent.pawn.health.RemoveHediff(parent);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Male && parent.def.defName != Props.maleHediffDef.defName)
{
changingType = true;
parent.pawn.health.RemoveHediff(parent);
}
}
private bool changingType = false;
public override void CompPostPostRemoved()
{
base.CompPostPostRemoved();
if (changingType)
{
if (parent.pawn.story.bodyType == BodyTypeDefOf.Thin && parent.def != Props.thinHediffDef)
{
parent.pawn.health.AddHediff(Props.thinHediffDef, parent.Part, null, null);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Hulk && parent.def != Props.hulkHediffDef)
{
parent.pawn.health.AddHediff(Props.hulkHediffDef, parent.Part, null, null);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Fat && parent.def != Props.fatHediffDef)
{
parent.pawn.health.AddHediff(Props.fatHediffDef, parent.Part, null, null);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Female && parent.def != Props.femaleHediffDef)
{
parent.pawn.health.AddHediff(Props.femaleHediffDef, parent.Part, null, null);
}
else if (parent.pawn.story.bodyType == BodyTypeDefOf.Male && parent.def != Props.maleHediffDef)
{
parent.pawn.health.AddHediff(Props.maleHediffDef, parent.Part, null, null);
}
}
}
}
public class CompProperties_DetonateImplantedBomb : CompProperties_AbilityEffect
{
public CompProperties_DetonateImplantedBomb()
{
this.compClass = typeof(CompAbilityEffect_DetonateImplantedBomb);
}
//public float explosiveRadius;
//public DamageDef explosiveDamageType;
public HediffDef hediffDef;
public ThingDef item;
public int itemCount = 1;
}
public class CompAbilityEffect_DetonateImplantedBomb : CompAbilityEffect
{
public new CompProperties_DetonateImplantedBomb Props
{
get
{
return (CompProperties_DetonateImplantedBomb)this.props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Pawn pawn = parent.pawn;
Thing thing = ThingMaker.MakeThing(Props.item);
thing.stackCount = Props.itemCount;
GenPlace.TryPlaceThing(thing, parent.pawn.Position, parent.pawn.MapHeld, ThingPlaceMode.Direct);
thing.TryGetComp<CompExplosive>().StartWick();
//DamageInfo triggerdamage = new DamageInfo();
//triggerdamage.SetAmount(50);
if (thing != null) { thing.TakeDamage(new DamageInfo(DamageDefOf.Bomb, 100)); }
//thing.TryGetComp<CompExplosive>().wickTicksLeft = -1;
//thing.TryGetComp<CompExplosive>().StopWick();
pawn.health.RemoveHediff(pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef));
//float num = Props.explosiveRadius;
//Thing thing = pawn;
//DamageDef explosiveDamageType = Props.explosiveDamageType;
//if (pawn.Map == null)
//{
// Log.Warning("Tried to detonate implanted explosive in a null map.");
// return;
//}
//GenExplosion.DoExplosion(pawn.PositionHeld, pawn.Map, num, explosiveDamageType, thing, explosiveDamageType.defaultDamage, explosiveDamageType.defaultArmorPenetration, explosiveDamageType.soundExplosion, null, null, null, null, 0, 0, null, true, null, 0, 0, 0, false, null, null, null, explosiveDamageType.explosionCenterEffecter, doSoundEffects: explosiveDamageType.soundExplosion, propagationSpeed: explosiveDamageType.expolosionPropagationSpeed);
}
}
//public class LTS_HediffCompProperties_TurretGun : HediffCompProperties
//{
// public int ticksBetweenBursts;
// public int ticksShots;
// public int shotsInBurst;
// public CompProperties_TurretGun turretGunProps;
// public LTS_HediffCompProperties_TurretGun()
// {
// compClass = typeof(LTS_HediffCompTurretGun);
// }
//}
//public class LTS_HediffCompTurretGun : HediffComp
//{
// public override void CompPostPostAdd(DamageInfo? dinfo)
// {
// base.CompPostPostAdd(dinfo);
// CompProperties_TurretGun turretProperties = new CompProperties_TurretGun(); //get these from xml/LTS_HediffCompProperties_TurretGun?
// CompTurretGun turret = new CompTurretGun();
// turret.props = turretProperties;
// Pawn.AllComps.Add(turret);
// }
//}
public class LTS_CompProperties_ToggleTurret : CompProperties_AbilityEffect
{
public LTS_CompProperties_ToggleTurret()
{
this.compClass = typeof(LTS_CompAbilityEffect_ToggleTurret);
}
public HediffDef ToggleHediff;
public float StartSeverity;
public string location = null;
}
public class LTS_CompAbilityEffect_ToggleTurret : CompAbilityEffect //if the pawn doesn't have the hediff, add it. If the pawn does have the hediff, remove it. If this is removed and the pawn has the hediff, remove it.
{
public new LTS_CompProperties_ToggleTurret Props
{
get
{
return (LTS_CompProperties_ToggleTurret)this.props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
if (target.Pawn != null)
{
if (target.Pawn.health?.hediffSet?.GetFirstHediffOfDef(this.Props.ToggleHediff) != null)
{
target.Pawn.health.RemoveHediff(target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff));
}
else
{
target.Pawn.health.AddHediff(this.Props.ToggleHediff, location(target));
if (target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff).TryGetComp<HediffComp_Lactating>() != null)
{
target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.ToggleHediff).TryGetComp<HediffComp_Lactating>().TryCharge(-0.124f);
}
}
}
}
public BodyPartRecord location(LocalTargetInfo target)
{
if (Props.location == null) { return null; }
//return target.Pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Where(part => part.def.tags.Contains(BodyPartTagDefOf.ManipulationLimbSegment)).ToList()[0];
return target.Pawn.health.hediffSet.GetNotMissingParts(BodyPartHeight.Undefined, BodyPartDepth.Undefined).Where(part => part.def.label == Props.location).ToList()[0];
}
}
public class LTS_Hediff_SlayersCollar : Hediff
{
private int humanKillsForNextDeathRefusal = -1;
private const int killsNeeded = 50;//50
public Hediff_DeathRefusal deathRefusal;
public override bool ShouldRemove => false;
public override void PostAdd(DamageInfo? dinfo)//if it's not already been set, set next kill goal
{
base.PostAdd(dinfo);
if (humanKillsForNextDeathRefusal == -1)
{
humanKillsForNextDeathRefusal = (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes) + killsNeeded;
}
}
public override void Notify_Spawned()
{
base.Notify_Spawned();
PostAdd(null);
}
public override void Tick()
{
base.Tick();
if (Find.TickManager.TicksGame % 30 == 0)
{
//needed: 10
//neededxlevel: 5
//kills: 5: 0
//kills: 6: 0.2
//kills: 7: 0.4
//kills: 8: 0.6
//kills: 9: 0.8
//kills: 10: 1
//needed-kills = 5, 4, 3, 2, 1, 0
//(needed-kills)/neededxlevel = 1, 0.8, 0.6, 0.4, 0.2, 0
//1-((needed-kills)/neededxlevel) = 0, 0.2, 0.4, 0.6, 0.8, 1
Severity = 1 - Mathf.Clamp01((humanKillsForNextDeathRefusal - pawn.records.GetValue(RecordDefOf.KillsHumanlikes)) / killsNeeded);
//Log.Warning("Severity: " + Severity);
//Log.Warning("humanKillsForNextDeathRefusal: "+ humanKillsForNextDeathRefusal);
//Log.Warning("KillsHumanlikes: " + (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes));
if (Severity == 1)
{
//deathRefusal = pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDefOf.DeathRefusal) as Hediff_DeathRefusal ?? pawn.health.AddHediff(HediffDefOf.DeathRefusal, null, null, null) as Hediff_DeathRefusal;
if (pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDefOf.DeathRefusal) != null)
{
deathRefusal = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.DeathRefusal) as Hediff_DeathRefusal;
if (deathRefusal.UsesLeft < deathRefusal.MaxUses)
{
deathRefusal.SetUseAmountDirect(deathRefusal.UsesLeft + 1);
humanKillsForNextDeathRefusal = (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes) + killsNeeded;
}
}
else
{
deathRefusal = pawn.health.AddHediff(HediffDefOf.DeathRefusal, null, null, null) as Hediff_DeathRefusal;
humanKillsForNextDeathRefusal = (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes) + killsNeeded;
}
}
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref humanKillsForNextDeathRefusal, "humanKillsForNextDeathRefusal", -1);
}
}
public class LTS_Hediff_MakeThin : HediffWithComps
{
BodyTypeDef originalBody;
public override void PostAdd(DamageInfo? dinfo)
{
base.PostAdd(dinfo);
if (pawn?.story?.bodyType != null)
{
if (pawn.story.bodyType != BodyTypeDefOf.Thin)
{
originalBody = pawn.story.bodyType;
pawn.story.bodyType = BodyTypeDefOf.Thin;
}
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void Notify_Spawned()
{
base.Notify_Spawned();
PostAdd(null);
}
public override void PostRemoved()
{
base.PostRemoved();
if (pawn?.story?.bodyType != null && originalBody != null)
{
pawn.story.bodyType = originalBody;
}
pawn.Drawer.renderer.SetAllGraphicsDirty();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Defs.Look(ref originalBody, "originalBody");
}
}
public class LTS_PawnRenderSubWorker_ChangeColourToApparel : PawnRenderSubWorker
{
public override void EditMaterialPropertyBlock(PawnRenderNode node, Material material, PawnDrawParms parms, ref MaterialPropertyBlock block)
{
Apparel middleLayer = node?.hediff?.pawn?.apparel?.WornApparel?.Find(x => x.def.apparel.layers.Contains(ApparelLayerDefOf.Middle)) ?? null;
if (middleLayer != null)
{
block.SetColor(ShaderPropertyIDs.Color, middleLayer.DrawColor);
}
//else
//{
// block.SetColor(ShaderPropertyIDs.Color, Color.white);
//}
}
//public override void EditMaterial(PawnRenderNode node, PawnDrawParms parms, ref Material material)
//{
// Apparel middleLayer = node?.hediff?.pawn?.apparel?.WornApparel?.Find(x => x.def.apparel.layers.Contains(ApparelLayerDefOf.Middle)) ?? null;
// if (middleLayer != null)
// {
// material.SetColor(ShaderPropertyIDs.Color, middleLayer.DrawColor);
// }
// else
// {
// material.SetColor(ShaderPropertyIDs.Color, Color.white);
// }
//}
}
public class LTS_Hediff_PsychicSustainer : Hediff
{
public override void Tick()
{
base.Tick();
if (Find.TickManager.TicksGame % 30 == 0)
{
bool shouldHave = pawn?.CurJobDef == JobDefOf.Meditate || pawn?.CurJobDef == JobDefOf.MeditatePray || pawn?.mindState?.duty?.def == DutyDefOf.PsychicRitualDance || pawn?.mindState?.duty?.def == DutyDefOf.Invoke;// || pawn?.mindState?.duty?.def == DutyDefOf.PerformHateChant; // this successfully returns true when the pawin is meditating or part of a psychic ritual (and isn't the target).
//Log.Message(pawn.CurJob);
//Log.Message(shouldHave);
Hediff hediff = pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("LTS_PsychicTrance"));
if (hediff == null && shouldHave)
{
pawn.health.AddHediff(HediffDef.Named("LTS_PsychicTrance"));
}
else if (hediff != null && !shouldHave)
{
pawn.health.RemoveHediff(hediff);
}
}
}
}
public class LTS_HediffCompProperties_RemoteGizmo : HediffCompProperties
{
public AbilityDef abilityDef;
public LTS_HediffCompProperties_RemoteGizmo()
{
compClass = typeof(LTS_HediffComp_RemoteGizmo);
}
}
public class LTS_HediffComp_RemoteGizmo : HediffComp
{
public new LTS_HediffCompProperties_RemoteGizmo Props
{
get
{
return (LTS_HediffCompProperties_RemoteGizmo)this.props;
}
}
public Gizmo RemoteGizmo()
{
Ability ability = parent?.pawn?.abilities?.AllAbilitiesForReading?.First(x => x.def == Props.abilityDef);
Gizmo gizmo = null;
if (ability != null)
{
gizmo = new Command_Ability(ability, parent.pawn);
}
return gizmo;
}
}
public class LTS_HediffCompProperties_AddExtraHediffOnNPCSpawn : HediffCompProperties
{
public HediffDef hediffDef;
public LTS_HediffCompProperties_AddExtraHediffOnNPCSpawn()
{
compClass = typeof(LTS_HediffComp_AddExtraHediffOnNPCSpawn);
}
}
public class LTS_HediffComp_AddExtraHediffOnNPCSpawn : HediffComp
{
public new LTS_HediffCompProperties_AddExtraHediffOnNPCSpawn Props
{
get
{
return (LTS_HediffCompProperties_AddExtraHediffOnNPCSpawn)this.props;
}
}
public override void CompPostMake()
{
base.CompPostMake();
if (!parent.pawn.IsPlayerControlled && Pawn.health?.hediffSet?.GetFirstHediffOfDef(Props.hediffDef) == null)
{
Pawn.health.AddHediff(Props.hediffDef, parent.Part);
}
}
//public override void CompPostTick(ref float severityAdjustment)
//{
// base.CompPostTick(ref severityAdjustment);
// if (parent.pawn.IsPlayerControlled || Find.TickManager.TicksGame % 60 != 0)
// {
// return;
// }
// //Log.Error("Working up until here.");
// if (Pawn.health?.hediffSet?.GetFirstHediffOfDef(Props.hediffDef) == null)
// {
// Pawn.health.AddHediff(Props.hediffDef, parent.Part);
// }
//}
}
public class LTS_CompProperties_AbilityReloadable : CompProperties_AbilityEffect
{
public ThingDef ammoDef;
public int ammoCountPerCharge;
public SoundDef soundReload;
public int baseReloadTicks;
[MustTranslate]
public string cooldownGerund = "on cooldown";
public NamedArgument CooldownVerbArgument => cooldownGerund.CapitalizeFirst().Named("COOLDOWNGERUND");
public LTS_CompProperties_AbilityReloadable()
{
compClass = typeof(LTS_CompAbilityEffect_Reloadable);
}
}
public class LTS_CompAbilityEffect_Reloadable : CompAbilityEffect
{
private new LTS_CompProperties_AbilityReloadable Props => props as LTS_CompProperties_AbilityReloadable;
public virtual ThingDef ammoDef => Props.ammoDef;
public virtual int ammoCountPerCharge => Props.ammoCountPerCharge;
public virtual int baseReloadTicks => Props.baseReloadTicks;
public virtual int ammoCountToRefill
{
get
{
return ammoCountPerCharge * (parent.maxCharges - parent.RemainingCharges);
}
}
public bool NeedsReload()
{
//Log.Message("Needs reload: " + (ammoCountToRefill != 0));
if (Props.ammoDef == null)
{
return false;
}
return parent.RemainingCharges != parent.maxCharges;
}
//public void ReloadFrom(Thing ammo)
//{
// //Log.Message("test");
// if (!NeedsReload())
// {
// return;
// }
// if (ammoCountToRefill != 0)
// {
// if (ammo.stackCount < ammoCountToRefill)
// {
// return;
// }
// ammo.SplitOff(ammoCountToRefill).Destroy();
// parent.RemainingCharges = parent.maxCharges;
// }
// else
// {
// if (ammo.stackCount < Props.ammoCountPerCharge)
// {
// return;
// }
// int num = Mathf.Clamp(ammo.stackCount / Props.ammoCountPerCharge, 0, parent.maxCharges - parent.RemainingCharges);
// ammo.SplitOff(num * Props.ammoCountPerCharge).Destroy();
// parent.RemainingCharges += num;
// }
// if (Props.soundReload != null)
// {
// Props.soundReload.PlayOneShot(new TargetInfo(parent.pawn.Position, parent.pawn.Map));
// }
//}
public void ReloadFrom(Thing ammo)
{
if (!NeedsReload())
{
return;
}
if (ammo.stackCount >= ammoCountToRefill) //if there's enough to fully refill
{
ammo.SplitOff(ammoCountToRefill).Destroy();
parent.RemainingCharges = parent.maxCharges;
}
else
{
if (ammo.stackCount < Props.ammoCountPerCharge)
{
return;
}
int num = Mathf.Clamp(ammo.stackCount / Props.ammoCountPerCharge, 0, parent.maxCharges - parent.RemainingCharges);
ammo.SplitOff(num * Props.ammoCountPerCharge).Destroy();
parent.RemainingCharges += num;
}
if (Props.soundReload != null)
{
Props.soundReload.PlayOneShot(new TargetInfo(parent.pawn.Position, parent.pawn.Map));
}
}
public int MinAmmoNeeded()
{
//Log.Message("test");
if (!NeedsReload())
{
return 0;
}
if (ammoCountToRefill != 0)
{
return ammoCountToRefill;
}
return Props.ammoCountPerCharge;
}
public int MaxAmmoNeeded(bool allowForcedReload)
{
//Log.Message("test");
if (!NeedsReload())
{
return 0;
}
if (ammoCountToRefill != 0)
{
return ammoCountToRefill;
}
return Props.ammoCountPerCharge * (parent.maxCharges - parent.RemainingCharges);
}
public int MaxAmmoAmount()
{
//Log.Message("test");
if (Props.ammoDef == null)
{
return 0;
}
if (ammoCountToRefill == 0)
{
return Props.ammoCountPerCharge * parent.maxCharges;
}
return ammoCountToRefill;
}
public virtual List<Thing> FindAmmo()
{
return RefuelWorkGiverUtility.FindEnoughReservableThings(parent.pawn, parent.pawn.Position, new IntRange(Props.ammoCountPerCharge, ammoCountToRefill), (Thing ammo) => ammo.def == Props.ammoDef);
}
}
//public class LTS_JobDriver_ReloadAbility : JobDriver
//{
// private LTS_CompAbilityEffect_Reloadable Comp
// {
// get
// {
// //Log.Message("test1");
// //for (int i = pawn.abilities.abilities.Count - 1; i >= 0; i--)
// for (int i = 0; i < pawn.abilities.AllAbilitiesForReading.Count; i++)
// {
// //Log.Message("test1.01");
// Ability ability = pawn.abilities.AllAbilitiesForReading[i];
// for (int j = 0; j < ability.comps.Count; j++)
// {
// //Log.Message("test1.02");
// //if (ability.comps[j] is LTS_CompAbilityEffect_Reloadable reloadComp && pawn.carryTracker.AvailableStackSpace(reloadComp.ammoDef) >= reloadComp.ammoCountPerCharge && reloadComp.NeedsReload(reloadComp.allowForcedReload))
// if (ability.comps[j] is LTS_CompAbilityEffect_Reloadable reloadComp && pawn.carryTracker.AvailableStackSpace(reloadComp.ammoDef) >= reloadComp.ammoCountPerCharge && reloadComp.NeedsReload())
// {
// //Log.Message("test1.03");
// return reloadComp;
// }
// }
// }
// //Log.Message("test1.1");
// return null;
// }
// }
// public override bool TryMakePreToilReservations(bool errorOnFailed)
// {
// //Log.Message("test2");
// pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.A), job);
// return true;
// }
// protected override IEnumerable<Toil> MakeNewToils()//eh?
// {
// //Log.Message("test3");
// LTS_CompAbilityEffect_Reloadable comp = Comp;
// this.FailOn(() => comp == null);
// this.FailOn(() => comp.parent.pawn != pawn);
// this.FailOn(() => !comp.NeedsReload());
// this.FailOnIncapable(PawnCapacityDefOf.Manipulation);
// Toil getNextIngredient = Toils_General.Label();
// yield return getNextIngredient;
// foreach (Toil item in ReloadAsMuchAsPossible(comp))
// {
// yield return item;
// }
// yield return Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A);
// yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnSomeonePhysicallyInteracting(TargetIndex.A);
// yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true).FailOnDestroyedNullOrForbidden(TargetIndex.A);
// yield return Toils_Jump.JumpIf(getNextIngredient, () => !job.GetTargetQueue(TargetIndex.A).NullOrEmpty());
// foreach (Toil item2 in ReloadAsMuchAsPossible(comp))
// {
// yield return item2;
// }
// Toil toil = ToilMaker.MakeToil("MakeNewToils");
// toil.initAction = delegate
// {
// Thing carriedThing = pawn.carryTracker.CarriedThing;
// if (carriedThing != null && !carriedThing.Destroyed)
// {
// pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out var _);
// }
// };
// toil.defaultCompleteMode = ToilCompleteMode.Instant;
// yield return toil;
// }
// public IEnumerable<Toil> ReloadAsMuchAsPossible(LTS_CompAbilityEffect_Reloadable comp)
// {
// //Log.Message("test4");
// Toil done = Toils_General.Label();
// yield return Toils_Jump.JumpIf(done, () => pawn.carryTracker.CarriedThing == null || pawn.carryTracker.CarriedThing.stackCount < comp.ammoCountPerCharge);
// yield return Toils_General.Wait(comp.baseReloadTicks).WithProgressBarToilDelay(TargetIndex.A);
// Toil toil = ToilMaker.MakeToil("ReloadAsMuchAsPossible");
// toil.initAction = delegate
// {
// Thing carriedThing = pawn.carryTracker.CarriedThing;
// comp.ReloadFrom(carriedThing);
// };
// toil.defaultCompleteMode = ToilCompleteMode.Instant;
// yield return toil;
// yield return done;
// }
//}
public class LTS_JobDriver_ReloadAbility : JobDriver
{
private LTS_CompAbilityEffect_Reloadable Comp
{
get
{
for (int i = 0; i < pawn.abilities.AllAbilitiesForReading.Count; i++)
{
Ability ability = pawn.abilities.AllAbilitiesForReading[i];
if (ability.comps != null)
{
for (int j = 0; j < ability.comps.Count; j++)
{
if (ability.comps[j] is LTS_CompAbilityEffect_Reloadable reloadComp && pawn.carryTracker.AvailableStackSpace(reloadComp.ammoDef) >= reloadComp.ammoCountPerCharge && reloadComp.NeedsReload())
{
return reloadComp;
}
}
}
}
return null;
}
}
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
pawn.ReserveAsManyAsPossible(job.GetTargetQueue(TargetIndex.A), job);
return true;
}
//protected override IEnumerable<Toil> MakeNewToils()
//{
// //LTS_CompAbilityEffect_Reloadable comp = Comp;
// //this.FailOn(() => comp == null);
// //this.FailOn(() => comp.parent.pawn != pawn);
// //this.FailOn(() => !comp.NeedsReload());
// //this.FailOnIncapable(PawnCapacityDefOf.Manipulation);
// //Toil getNextIngredient = Toils_General.Label();
// //yield return getNextIngredient;
// //foreach (Toil item in ReloadAsMuchAsPossible(comp))
// //{
// // yield return item;
// //}
// //yield return Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A);
// //yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnSomeonePhysicallyInteracting(TargetIndex.A);
// //yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true).FailOnDestroyedNullOrForbidden(TargetIndex.A);
// //yield return Toils_Jump.JumpIf(getNextIngredient, () => !job.GetTargetQueue(TargetIndex.A).NullOrEmpty());
// //foreach (Toil item2 in ReloadAsMuchAsPossible(comp))
// //{
// // yield return item2;
// //}
// Toil toil = ToilMaker.MakeToil("MakeNewToils");
// //toil.initAction = delegate
// //{
// // Thing carriedThing = pawn.carryTracker.CarriedThing;
// // if (carriedThing != null && !carriedThing.Destroyed)
// // {
// // pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out var _);
// // }
// //};
// toil.defaultCompleteMode = ToilCompleteMode.Instant;
// yield return toil;
//}
protected override IEnumerable<Toil> MakeNewToils()
{
LTS_CompAbilityEffect_Reloadable comp = Comp;
this.FailOn(() => comp == null);
this.FailOn(() => comp.parent.pawn != pawn);
this.FailOn(() => !comp.NeedsReload());
this.FailOnIncapable(PawnCapacityDefOf.Manipulation);
Toil getNextIngredient = Toils_General.Label();
yield return getNextIngredient;
foreach (Toil item in ReloadAsMuchAsPossible(comp))
{
yield return item;
}
yield return Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A);
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch).FailOnDespawnedNullOrForbidden(TargetIndex.A).FailOnSomeonePhysicallyInteracting(TargetIndex.A);
yield return Toils_Haul.StartCarryThing(TargetIndex.A, putRemainderInQueue: false, subtractNumTakenFromJobCount: true).FailOnDestroyedNullOrForbidden(TargetIndex.A);
yield return Toils_Jump.JumpIf(getNextIngredient, () => !job.GetTargetQueue(TargetIndex.A).NullOrEmpty());
foreach (Toil item2 in ReloadAsMuchAsPossible(comp))
{
yield return item2;
}
Toil toil = ToilMaker.MakeToil("MakeNewToils");
toil.initAction = delegate
{
Thing carriedThing = pawn.carryTracker.CarriedThing;
if (carriedThing != null && !carriedThing.Destroyed)
{
pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out var _);
}
};
toil.defaultCompleteMode = ToilCompleteMode.Instant;
yield return toil;
}
public IEnumerable<Toil> ReloadAsMuchAsPossible(LTS_CompAbilityEffect_Reloadable comp)
{
Toil done = Toils_General.Label();
yield return Toils_Jump.JumpIf(done, () => pawn.carryTracker.CarriedThing == null || pawn.carryTracker.CarriedThing.stackCount < comp.ammoCountPerCharge);
yield return Toils_General.Wait(comp.baseReloadTicks).WithProgressBarToilDelay(TargetIndex.A);
Toil toil = ToilMaker.MakeToil("LTS_ReloadAsMuchAsPossible");
toil.initAction = delegate
{
Thing carriedThing = pawn.carryTracker.CarriedThing;
comp.ReloadFrom(carriedThing);
};
toil.defaultCompleteMode = ToilCompleteMode.Instant;
yield return toil;
yield return done;
}
}
public class LTS_JobGiver_ReloadAbility : ThinkNode_JobGiver
{
private const bool ForceReloadWhenLookingForWork = false;
public override float GetPriority(Pawn pawn)
{
return 5.9f;
}
protected override Job TryGiveJob(Pawn pawn)
{
if (pawn == null)
{
return null;
}
if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation))
{
return null;
}
LTS_CompAbilityEffect_Reloadable comp = null;
List<Thing> ammo = null;
for (int i = 0; i < pawn.abilities.AllAbilitiesForReading.Count; i++)
{
Ability ability = pawn.abilities.AllAbilitiesForReading[i];
if (ability.comps != null)
{
for (int j = 0; j < ability.comps.Count; j++)
{
if (ability.comps[j] is LTS_CompAbilityEffect_Reloadable compReloadable)
{
if (compReloadable.NeedsReload())
{
if (pawn.carryTracker.AvailableStackSpace(compReloadable.ammoDef) >= compReloadable.ammoCountPerCharge)
{
List<Thing> list = compReloadable.FindAmmo();
if (!list.NullOrEmpty())
{
comp = compReloadable;
ammo = list;
}
}
}
}
}
}
if (comp != null)
{
break;
}
}
if (comp == null)
{
return null;
}
return MakeReloadJob(comp, ammo);
}
public static Job MakeReloadJob(LTS_CompAbilityEffect_Reloadable comp, List<Thing> chosenAmmo)
{
Job job = JobMaker.MakeJob(I_DefOf.LTS_ReloadAbility);
job.targetQueueA = chosenAmmo.Select((Thing ammo) => new LocalTargetInfo(ammo)).ToList();
job.count = chosenAmmo.Sum((Thing ammo) => ammo.stackCount);
job.count = Math.Min(job.count, comp.ammoCountToRefill);
return job;
}
}
public class AbilityChargesStatable : Ability
{
public AbilityChargesStatable() : base() { }
public AbilityChargesStatable(Pawn pawn) : base(pawn) { }
public AbilityChargesStatable(Pawn pawn, AbilityDef abilityDef) : base(pawn, abilityDef) { }
public AbilityChargesStatable(Pawn pawn, Precept sourcePrecept) : base(pawn, sourcePrecept) { }
public AbilityChargesStatable(Pawn pawn, Precept sourcePrecept, AbilityDef abilityDef) : base(pawn, sourcePrecept, abilityDef) { }
public override void AbilityTick()
{
base.AbilityTick();
//if (Find.TickManager.TicksGame % 30 == 0)
//{
// maxCharges = def.charges * (int)pawn.GetStatValue(def.GetModExtension<LTS_IModExtension>().LTS_StatDef);
//}
maxCharges = def.charges * (int)pawn.GetStatValue(def.GetModExtension<LTS_IModExtension>().LTS_StatDef);
}
}
//public class LTS_PawnRenderSubWorker_DraftOrHostileColourChange : PawnRenderSubWorker
//{
// //public static Color passive = new Color(0.59f, 0.91f, 0.52f);
// //public static Color aggressive = new Color(0.87f, 0.3f, 0.24f);
// //public static Color off = new Color(0, 0, 0, 0);
// //public override void EditMaterialPropertyBlock(PawnRenderNode node, Material material, PawnDrawParms parms, ref MaterialPropertyBlock block)
// //{
// // if (node?.hediff?.pawn?.Dead ?? false)
// // {
// // block.SetColor(ShaderPropertyIDs.Color, off);
// // }
// // else if ((node?.hediff?.pawn?.HostileTo(Faction.OfPlayer) ?? false) || (node?.hediff?.pawn?.Drafted ?? false))
// // {
// // block.SetColor(ShaderPropertyIDs.Color, aggressive);
// // }
// // else
// // {
// // block.SetColor(ShaderPropertyIDs.Color, passive);
// // }
// //}
// public override void EditMaterialPropertyBlock(PawnRenderNode node, Material material, PawnDrawParms parms, ref MaterialPropertyBlock block)
// {
// //def.GetModExtension<LTS_IModExtension>()?.LTS_TicksBetweenPulse ?? 900
// if (node?.hediff?.pawn?.Dead ?? false)
// {
// block.SetColor(ShaderPropertyIDs.Color, Color.black);
// }
// else if ((node?.hediff?.pawn?.HostileTo(Faction.OfPlayer) ?? false) || (node?.hediff?.pawn?.Drafted ?? false))
// {
// block.SetColor(ShaderPropertyIDs.Color, node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_BrightColor);
// }
// else
// {
// block.SetColor(ShaderPropertyIDs.Color, node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_DimColor);
// }
// }
//}
public class LTS_PawnRenderSubWorker_HediffAgressionColour : PawnRenderSubWorker
{
public static Color passive = new Color(0.59f, 0.91f, 0.52f);
public static Color aggressive = new Color(0.87f, 0.3f, 0.24f);
public static Color off = new Color(0, 0, 0, 0);
public override void EditMaterialPropertyBlock(PawnRenderNode node, Material material, PawnDrawParms parms, ref MaterialPropertyBlock block)
{
if (!node.hediff.pawn.Awake())
{
block.SetColor(ShaderPropertyIDs.Color, off);
}
else if (node.hediff.pawn.HostileTo(Faction.OfPlayer) || node.hediff.pawn.Drafted || (node.hediff.pawn.MentalStateDef?.IsAggro ?? false))
{
block.SetColor(ShaderPropertyIDs.Color, aggressive);
}
else
{
block.SetColor(ShaderPropertyIDs.Color, passive);
}
}
}
public class LTS_PawnRenderSubWorker_InvisibleIfUnconscious : PawnRenderSubWorker
{
public override void EditMaterialPropertyBlock(PawnRenderNode node, Material material, PawnDrawParms parms, ref MaterialPropertyBlock block)
{
if ((node?.hediff?.pawn?.Dead ?? false) || !(node?.hediff?.pawn?.Awake() ?? false))
{
block.SetColor(ShaderPropertyIDs.Color, new Color(0, 0, 0, 0));
}
else
{
block.SetColor(ShaderPropertyIDs.Color, node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_Colour);
}
}
}
public class LTS_PawnRenderSubWorker_ShifttFrontForHeadType : PawnRenderSubWorker
{
public override void TransformOffset(PawnRenderNode node, PawnDrawParms parms, ref Vector3 offset, ref Vector3 pivot)
{
if (node?.hediff?.pawn?.story.headType.narrow ?? false)
{
if (node.hediff.pawn.Rotation == Rot4.East)
{
offset += new Vector3(-0.05f, 0, 0);
}
else if (node.hediff.pawn.Rotation == Rot4.West)
{
offset += new Vector3(0.05f, 0, 0);
}
}
}
}
public class LTS_PawnRenderNodeWorker_HediffApparelGraphics : PawnRenderNodeWorker
{
protected override Graphic GetGraphic(PawnRenderNode node, PawnDrawParms parms)
{
if (node.hediff.pawn.story.bodyType == BodyTypeDefOf.Thin)
{
return GraphicDatabase.Get<Graphic_Multi>(node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_TexPathThin, node.ShaderFor(node.hediff.pawn), Vector2.one, Color.white);
}
else if (node.hediff.pawn.story.bodyType == BodyTypeDefOf.Hulk)
{
return GraphicDatabase.Get<Graphic_Multi>(node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_TexPathHulk, node.ShaderFor(node.hediff.pawn), Vector2.one, Color.white);
}
else if (node.hediff.pawn.story.bodyType == BodyTypeDefOf.Fat)
{
return GraphicDatabase.Get<Graphic_Multi>(node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_TexPathFat, node.ShaderFor(node.hediff.pawn), Vector2.one, Color.white);
}
else if (node.hediff.pawn.story.bodyType == BodyTypeDefOf.Male)
{
return GraphicDatabase.Get<Graphic_Multi>(node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_TexPathMale, node.ShaderFor(node.hediff.pawn), Vector2.one, Color.white);
}
else if (node.hediff.pawn.story.bodyType == BodyTypeDefOf.Female)
{
return GraphicDatabase.Get<Graphic_Multi>(node.hediff.def.GetModExtension<LTS_IModExtension>().LTS_TexPathFemale, node.ShaderFor(node.hediff.pawn), Vector2.one, Color.white);
}
else
{
return node.Graphic;
}
}
}
public class CompProperties_AbilityAddOrBuildHediffSeverity : CompProperties_AbilityEffect
{
public CompProperties_AbilityAddOrBuildHediffSeverity()
{
this.compClass = typeof(CompAbilityEffect_AbilityAddOrBuildHediffSeverity);
}
public float severityPerUse;
public HediffDef hediffDef;
}
public class CompAbilityEffect_AbilityAddOrBuildHediffSeverity : CompAbilityEffect
{
public new CompProperties_AbilityAddOrBuildHediffSeverity Props
{
get
{
return (CompProperties_AbilityAddOrBuildHediffSeverity)this.props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Pawn pawn = parent.pawn;
Hediff hediff;
if ((hediff = pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef)) != null)
{
hediff.Severity += Props.severityPerUse;
}
else
{
hediff = pawn.health.AddHediff(Props.hediffDef, null, null, null);
hediff.Severity = Props.severityPerUse;
}
}
}
public class LTS_Hediff_CellularAdapter : LTS_Hediff_DontRemove
{
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
{
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
if (pawn.Dead)
{
return;
}
//if (!pawn.health.hediffSet.HasHediff(HediffDef.Named("LTS_CellularAdaptation")))
//{
// pawn.health.AddHediff(HediffMaker.MakeHediff(HediffDef.Named("LTS_CellularAdaptation"), pawn));
//}
//pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_CellularAdaptation")).Severity += totalDamageDealt / 500; // +0.02 severity / 10 damage
Severity += totalDamageDealt / 500; //+0.02 severity (2%) / 10 damage
}
}
public class LTS_Hediff_DontRemove : HediffWithComps
{
public override bool ShouldRemove => false;
}
public class LTS_CompProperties_LinkedAbility : CompProperties_AbilityEffect
{
public LTS_CompProperties_LinkedAbility()
{
compClass = typeof(LTS_CompAbilityEffect_LinkedAbility);
}
public AbilityDef abilityDef;
public int cooldown;
}
public class LTS_CompAbilityEffect_LinkedAbility : CompAbilityEffect
{
public new LTS_CompProperties_LinkedAbility Props
{
get
{
return (LTS_CompProperties_LinkedAbility)props;
}
}
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Log.Message(parent.CooldownTicksTotal);
//int cooldown = Props?.cooldown ?? (parent?.CooldownTicksTotal ?? 2500); //unless there's a specific cooldown set, use this ability's maximum cooldown, or an an hour if there isn't one
//int cooldown = Props?.cooldown ?? parent.CooldownTicksTotal; //unless there's a specific cooldown set, use this ability's maximum cooldown
int cooldown = parent?.CooldownTicksTotal ?? Props.cooldown; //use this ability's maximum cooldown
try
{
parent.pawn.abilities.GetAbility(Props.abilityDef, true).StartCooldown(cooldown); //put linked ability on cooldown
//Log.Message("Ability '" + parent.def.label + "' is linked to ability '" + Props.abilityDef.label + "' which should be on cooldown for " + cooldown + " ticks");
}
catch
{
Log.Warning("Ability '" + parent.def.label + "' failed to find linked ability '" + Props.abilityDef.label + "'");
}
}
}
public class LTS_HediffCompProperties_ExtraHediff : HediffCompProperties
{
public HediffDef hediffDef;
public BodyPartDef location = null;
public LTS_HediffCompProperties_ExtraHediff()
{
compClass = typeof(LTS_HediffComp_ExtraHediff);
}
}
public class LTS_HediffComp_ExtraHediff : HediffComp
{
public new LTS_HediffCompProperties_ExtraHediff Props
{
get
{
return (LTS_HediffCompProperties_ExtraHediff)this.props;
}
}
public override void CompPostPostAdd(DamageInfo? dinfo)
{
base.CompPostPostAdd(dinfo);
if (Pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef) == null)
{
Pawn.health.AddHediff(Props.hediffDef);
}
}
public override void CompPostPostRemoved()
{
base.CompPostPostRemoved();
if (Pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef) != null)
{
Pawn.health.RemoveHediff(Pawn.health.hediffSet.GetFirstHediffOfDef(Props.hediffDef));
}
}
}
public class LTS_IModExtension : DefModExtension
{
public int LTS_TicksBetweenPulse;
public HediffDef LTS_Hediff;
public float LTS_Severity;
public GeneDef LTS_Gene;
public List<GeneDef> LTS_Genes;
public float LTS_HemogenMaxOffset;
public bool LTS_MakesShield;
//public bool LTS_DoSomethingOnDeath;
public HeadTypeDef LTS_HeadTypeDef;
//public AbilityDef LTS_Ability;
public bool LTS_GenePreventsInstall = false;
public StatDef LTS_StatDef;
//public Color LTS_BrightColor;
//public Color LTS_DimColor;
public Color LTS_Colour;
public string LTS_TexPathMale;
public string LTS_TexPathFemale;
public string LTS_TexPathThin;
public string LTS_TexPathHulk;
public string LTS_TexPathFat;
}
[DefOf]
public static class I_DefOf
{
public static ThingDef I_ArchicHaloMote;
public static PawnRelationDef PsychicBeguileObsessed;
public static PawnRenderNodeTagDef LTS_ColourableRenderNode;
//public static ThingDef Mote_HediffApparel;
public static JobDef LTS_ReloadAbility;
static I_DefOf()
{
DefOfHelper.EnsureInitializedInCtor(typeof(I_DefOf));
}
}
/// <summary>
/// Bootstrap class to do the harmony patches.
/// </summary>
[HarmonyPatch(typeof(StatPart_FertilityByGenderAge), "AgeFactor")]
class StatPart_FertilityByGenderAge_AgeFactor_Patch
{
[HarmonyPostfix]
public static void StatPart_FertilityByGenderAge_AgeFactor_Postfix(Pawn pawn, ref float __result)
{
//if (pawn.gender == Gender.Female)
__result = 1 - ((1 - __result) * pawn.GetStatValue(StatDef.Named("LTS_AgeFertilityImpactFactor")));
// e.g.:
//
// AgeFactor = 0.7,
// LTS_AgeFertilityImpactFactor = 0
//
// expected result = 1
// __result = 1 - ((1 - 0.7) * 0) = 1
//
//
// AgeFactor = 0.4,
// LTS_AgeFertilityImpactFactor = 0.5
//
// expected result = 0.7
// __result = 1 - ((1 - 0.4) * 0.5) = 0.7
//
//
// AgeFactor = 0,
// LTS_AgeFertilityImpactFactor = 1
//
// expected result = 0
// __result = 1 - ((1 - 0) * 1 = 0
//
//
// AgeFactor = 0.6,
// LTS_AgeFertilityImpactFactor = 1
//
// expected result = 0.6
// __result = 1 - ((1 - 0.6) * 1 = 0.6
}
}
[HarmonyPatch(typeof(SkillRecord))]
[HarmonyPatch("Interval")]
internal static class Patch_SkillRecordInterval//multiplies skill decay by pawn's LTS_SkillDecayFactor
{
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> lines)
{
List<CodeInstruction> newLines = lines.ToList();
List<CodeInstruction> newLinesInjection = new List<CodeInstruction>();
int referenceLineNumber = newLines.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Stloc_0);
if (referenceLineNumber != -1)//if we found the injection location
{
newLinesInjection.Add(new CodeInstruction(OpCodes.Ldloc_0, (object)null)); //adds num to evaluation stack
newLinesInjection.Add(new CodeInstruction(OpCodes.Ldarg_0, (object)null));
newLinesInjection.Add(CodeInstruction.Call(typeof(Patch_SkillRecordInterval), "GetExperienceDecayFactor", (Type[])null, (Type[])null));
newLinesInjection.Add(new CodeInstruction(OpCodes.Mul, (object)null)); //multiplies num and GetExperienceDecayFactor
newLinesInjection.Add(new CodeInstruction(OpCodes.Stloc_0, (object)null)); //sets num to top of evaluation stack
//List<CodeInstruction> collection = newLinesInjection;
newLines.InsertRange(referenceLineNumber + 1, newLinesInjection);
return newLines.AsEnumerable();
}
else
{
Log.Error("LTS Implants: Failed to apply skill decay transpile, returning base");
}
return lines;
}
public static float GetExperienceDecayFactor(this SkillRecord skillRecord)
{
return skillRecord.Pawn.GetStatValue(StatDef.Named("LTS_SkillDecayFactor"));
}
}
//[HarmonyPatch(typeof(SkillRecord))]
//[HarmonyPatch("Interval")]
//class SkillRecord_Interval_Patch
//{
// [HarmonyTranspiler]
// static IEnumerable<CodeInstruction> SkillRecord_Interval_Transpile(IEnumerable<CodeInstruction> code, ILGenerator il)
// {
// List<CodeInstruction> lines = new List<CodeInstruction>(code);
// List<CodeInstruction> newLines = new List<CodeInstruction>();
// int referenceLineNumber = lines?.FindLastIndex((CodeInstruction instruction) => instruction.opcode == OpCodes.Stloc_0) ?? -1;
// //Log.Message("BEGINNING OF OUTPUT");
// //for (int lineNumber = 0; lineNumber < lines.Count; lineNumber++) //finds the line number of the line after the one we want to inject
// //{
// // if (lineNumber >= 0 && lineNumber < 100)
// // {
// // Log.Message("Line " + (lineNumber).ToString() + ": " + lines[lineNumber].ToString());
// // }
// //}
// //Log.Message("END OF OUTPUT");
// if (referenceLineNumber != -1)//if we found the lineAfterLineNumber
// {
// for (int lineNumber = 0; lineNumber < referenceLineNumber + 1; lineNumber++)//add all the lines before our injection to the empty newLines
// {
// newLines.Add(lines[lineNumber]);
// }
// //relatively certain location 0 is num, which is the float skill loss is multiplied by
// //newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 0));//feeds num?
// newLines.Add(new CodeInstruction(OpCodes.Ldloc_0)); //gets num?
// newLines.Add(new CodeInstruction(OpCodes.Ldarg_0));
// //newLines.Add(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(SkillRecord_Interval_Patch), "GetExperienceDecayFactor")));//return pawn's experience decay factor as a float
// newLines.Add(CodeInstruction.Call(typeof(SkillRecord_Interval_Patch), "GetExperienceDecayFactor", (Type[])null, (Type[])null));
// newLines.Add(new CodeInstruction(OpCodes.Mul)); //multiplies ExperienceDecayFactor and num
// newLines.Add(new CodeInstruction(OpCodes.Stloc_0)); //sets num
// for (int lineNumber = referenceLineNumber + 1; lineNumber < lines.Count; lineNumber++)//add all the lines after our injection to the newLines
// {
// newLines.Add(lines[lineNumber]);
// }
// //Log.Message("RETURNING NEWLINES");
// return newLines.AsEnumerable();
// }
// else
// {
// Log.Error("LTS Implants: Failed to apply skill decay transpile, returning base");
// }
// return lines.AsEnumerable();
// }
// public float GetExperienceDecayFactor(SkillRecord skillRecord)
// {
// Log.Warning("LTS_SkillDecayFactor = " + skillRecord.Pawn.GetStatValue(StatDef.Named("LTS_SkillDecayFactor")));
// return skillRecord.Pawn.GetStatValue(StatDef.Named("LTS_SkillDecayFactor"));
// }
// [HarmonyPostfix]
// public static void SkillRecord_Interval_Postfix()
// {
// Log.Warning("SkillRecord_Interval ping!");
// }
//}
//[HarmonyPatch(typeof(PawnRenderer), "PawnNeedsHediffMaterial")]
//class PawnRenderNodeWorker_GetMaterial_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderNodeWorker_GetMaterial_Postfix(ref PawnRenderFlags renderFlags, ref bool __result, Pawn ___pawn)
// {
// if (___pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// renderFlags = PawnRenderFlags.Invisible;
// __result = true;
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderNodeWorker), "GetMaterial")]
//class PawnRenderNodeWorker_GetMaterial_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderNodeWorker_GetMaterial_Postfix(PawnRenderNode node, PawnDrawParms parms, ref Material __result)
// {
// try
// {
// if (node.tree.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// //__result = ShaderDatabase.Invisible;
// __result.shader = ShaderDatabase.Invisible;
// }
// }
// catch
// {
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderNode), nameof(PawnRenderNode.ShaderFor))]
//class PawnRenderNode_Shader_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderNode_Shader_Postfix(Pawn pawn, ref Shader __result)
// {
// if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// __result = ShaderDatabase.Invisible;
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderNode), nameof(PawnRenderNode.ColorFor))]
//class PawnRenderNode_ColorFor_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderNode_ColorFor_Postfix(Pawn pawn, ref Color __result)
// {
// if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// __result = __result;
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderNode), nameof(PawnRenderNode.ColorFor))]
//class PawnRenderUtility_SetMatPropBlockOverlay_Patch
//{
// [HarmonyPrefix]
// public static bool PawnRenderUtility_SetMatPropBlockOverlay_Prefix(PawnDrawParms parms, PawnRenderTree __instance, ref List<PawnGraphicDrawRequest> ___drawRequests)
// {
// if (__instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// foreach (PawnGraphicDrawRequest i in ___drawRequests)
// {
// //i.material.color = Color.blue;
// //i.material = InvisibilityMatPool.GetInvisibleMat(i.material);MoteGlow
// try
// {
// //i.material.shader = ShaderDatabase.Invisible;
// i.material.shader = ShaderDatabase.Invisible;
// }
// catch
// {
// }
// }
// }
// return true;
// }
//}
//[HarmonyPatch(typeof(PawnRenderTree), nameof(PawnRenderTree.Draw))]
//class PawnRenderUtility_SetMatPropBlockOverlay_Patch
//{
// [HarmonyPrefix]
// public static bool PawnRenderUtility_SetMatPropBlockOverlay_Prefix(PawnDrawParms parms, PawnRenderTree __instance, ref List<PawnGraphicDrawRequest> ___drawRequests)
// {
// if (__instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// foreach (PawnGraphicDrawRequest i in ___drawRequests)
// {
// //i.material.color = Color.blue;
// //i.material = InvisibilityMatPool.GetInvisibleMat(i.material);MoteGlow
// try
// {
// //i.material.shader = ShaderDatabase.Invisible;
// i.material.shader = ShaderDatabase.Invisible;
// }
// catch
// {
// }
// }
// }
// return true;
// }
//}
//[HarmonyPatch(typeof(PawnRenderUtility), nameof(PawnRenderUtility.SetMatPropBlockOverlay))]
//class PawnRenderUtility_SetMatPropBlockOverlay_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderUtility_SetMatPropBlockOverlay_Postfix(MaterialPropertyBlock block, Color color, float opacity = 0.5f)
// {
// //if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// block.SetColor(ShaderPropertyIDs.OverlayColor, Color.red);
// block.SetFloat(ShaderPropertyIDs.OverlayOpacity, 0.5f);
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderNode), nameof(PawnRenderNode.GraphicFor))]
//class PawnRenderNode_GraphicFor_Patch
//{
// [HarmonyPostfix]
// public static void PawnRenderNode_GraphicFor_Postfix(Pawn pawn, ref Graphic __result, PawnRenderNode __instance)
// {
// if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// //__result.Color = Color.red;
// //__result.color = Color.red;
// __result = null;
// }
// }
//}
//[HarmonyPatch(typeof(PawnRenderer), "OverrideMaterialIfNeeded")]
//class PawnRenderer_OverrideMaterialIfNeeded_Patch //
//{
// [HarmonyPostfix]
// public static void PawnRenderer_OverrideMaterialIfNeeded_Postfix(Material original, PawnRenderFlags flags, ref Material __result, PawnRenderer __instance, Pawn ___pawn)
// {
// //if (___pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// //{
// // __result = InvisibilityMatPool.GetInvisibleMat(original);
// // __result.color = new Color((original.color.r + __result.color.r) / 2, (original.color.g + __result.color.g) / 2, (original.color.b + __result.color.b) / 2);
// //}
// Log.Error("Ping");
// __result = InvisibilityMatPool.GetInvisibleMat(original);
// }
//}
//[HarmonyPatch(typeof(PawnRenderer), "GetDrawParms")]
//class PawnRenderer_GetDrawParms_Patch //
//{
// [HarmonyPostfix]
// public static void PawnRenderer_GetDrawParms_Postfix(ref PawnDrawParms __result, PawnRenderer __instance, ref DamageFlasher ___flasher)
// {
// if (__result.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_StealthSystem_LowPower")) != null)
// {
// //__result.tint = __instance.flasher.CurColor.ToTransparent(0.5f);
// //Color floorColour = __result.pawn.MapHeld.terrainGrid.TerrainAt(__result.pawn.PositionHeld).color;
// //__result.tint = new Color((__instance.flasher.CurColor.r + floorColour.r) / 2, (__instance.flasher.CurColor.g + floorColour.g) / 2, (__instance.flasher.CurColor.b + floorColour.b) / 2);
// //__result.tint = floorColour;
// //__result.tint = ___flasher.CurColor.ToTransparent(0.5f);
// //__result.tint = Color.red;
// __result.tint = __result.pawn.MapHeld.terrainGrid.TerrainAt(__result.pawn.PositionHeld).color;
// }
// }
// //public Color transparencyBlender(Color a, Color b, float ratio = 0.1f)
// //{
// // return
// //}
//}
[HarmonyPatch(typeof(ShotReport), "AimOnTargetChance_StandardTarget", MethodType.Getter)]
class ShotReport_AimOnTargetChance_StandardTarget_Patch //adds hit chance offset effect
{
[HarmonyPostfix]
public static void ShotReport_AimOnTargetChance_StandardTarget_Postfix(ref float __result, TargetInfo ___target)
{
//if (___target.Thing?.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")) != 1)
//if ((___target.Thing as Pawn).GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")) != null)
if ((___target.Thing is Pawn) && ___target.Thing.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")) != 1)
{
__result *= ___target.Thing.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor"));
if (__result < 0.0201f)
{
__result = 0.0201f;
}
}
}
}
[HarmonyPatch(typeof(ShotReport), nameof(ShotReport.GetTextReadout))]
class ShotReport_GetTextReadout_Patch //adds hit chance offset text to hover over lable
{
[HarmonyPostfix]
public static void ShotReport_GetTextReadout_Postfix(ref string __result, TargetInfo ___target)
{
//if (___target.HasThing && ___target.Thing?.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")) != 1)
if (___target.Thing?.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")) != 1)
{
__result += " Target factor: " + ___target.Thing.GetStatValue(StatDef.Named("LTS_HediffAimOnTargetFactor")).ToStringPercent();
//"n\"
}
}
}
/// <summary>
/// This patch is horrifying performance heavy especially when you playing with a large gene collection mods.
/// TODO make this patch optional in future logs.
/// for now, just comment this part out.
/// </summary>
/*
[HarmonyPatch(typeof(Gene), "Active", MethodType.Getter)]
class Gene_Active_Patch //disables any gene that has the tail exclusion tag while an implant with the LTS_BionicTail tag is present//make this more modular in future?
{
[HarmonyPostfix]
public static void Gene_Active_Patch_Postfix(Gene __instance, ref bool __result)
{
if (__instance.def?.exclusionTags?.Contains("Tail")??false)
{
foreach (Hediff hediff in __instance.pawn.health.hediffSet.hediffs)
{
if (hediff.def?.tags?.Contains("LTS_BionicTail") ?? false)
{
__result = false;
}
}
}
}
}
*/
//[HarmonyPatch(typeof(Pawn_CarryTracker))]
//[HarmonyPatch(nameof(Pawn_CarryTracker.TryDropCarriedThing))]
//class Pawn_CarryTracker_TryDropCarriedThing_patch //prevents dropping of drugs if pawn has medical injector module
//{
// [HarmonyPrefix]
// public static bool Pawn_CarryTracker_TryDropCarriedThing_Prefix(ThingOwner<ThingWithComps> ___equipment, Pawn ___pawn)
// {
// if (___pawn.health.Downed && !___pawn.health.Dead)
// {
// if (___pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_ModuleArm_DeathGrip")) != null && ___equipment.InnerListForReading.Any((ThingWithComps thing) => thing.def.IsWeapon))
// {
// return false;
// }
// //if (___pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_ModuleSpine_MedicalInjector")) != null && ___equipment.InnerListForReading.Any((ThingWithComps thing) => thing.def.IsDrug))
// //{
// // return false;
// //}
// }
// return true;
// }
//}
//[HarmonyPatch(typeof(Pawn_InventoryTracker), "DropAllNearPawnHelper")]
//class Pawn_InventoryTracker_DropAllNearPawnHelper_Patch ///prevents dropping of drugs if pawn has medical injector module
//{
// [HarmonyPrefix]
// public static bool Pawn_EquipmentTracker_DropAllEquipment_Prefix(Pawn_InventoryTracker __instance, List<Thing> ___tmpThingList, List<Thing> ___unpackedCaravanItems, IntVec3 pos, bool forbid = false, bool unforbid = false, bool caravanHaulOnly = false)
// {
// if (__instance.pawn.MapHeld == null)
// {
// Log.Error("Tried to drop all inventory near pawn but the pawn is unspawned. pawn=" + __instance.pawn);
// }
// else
// {
// ___tmpThingList.Clear();
// if (caravanHaulOnly)
// {
// ___tmpThingList.AddRange(___unpackedCaravanItems);
// }
// else
// {
// ___tmpThingList.AddRange(__instance.innerContainer);
// }
// int i;
// for (i = 0; i < ___tmpThingList.Count; i++)
// {
// if (caravanHaulOnly && !__instance.innerContainer.Contains(___tmpThingList[i]))
// {
// ___unpackedCaravanItems.Remove(___tmpThingList[i]);
// Log.Warning("Could not drop unpacked caravan item " + ___tmpThingList[i].Label + ", inventory no longer contains it");
// continue;
// }
// //if (!(__instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_ModuleSpine_MedicalInjector")) != null && ___equipment.InnerListForReading.Any((ThingWithComps thing) => thing.def.IsDrug))
// //if (!(___tmpThingList[i].def.IsDrug && __instance.pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("LTS_ModuleSpine_MedicalInjector")) != null))
// }
// }
// return true;
// }
//}
[HarmonyPatch(typeof(CompSightstealer), "GetPawnSightRadius")]
class CompSightstealer_GetPawnSightRadius_Patch //spotting sightstealer accounts for hediff night vision
{
[HarmonyPostfix]
public static void CompSightstealer_GetPawnSightRadius_Postfix(Pawn pawn, Pawn sightstealer, ref float __result)
{
if (pawn.GetStatValue(StatDef.Named("LTS_DarkVision")) != 0)
{
__result = 14f * pawn.health.capacities.GetLevel(PawnCapacityDefOf.Sight);
}
}
}
[HarmonyPatch(typeof(StatPart_Glow), "ActiveFor")]
class StatPart_Glow_ActiveFor_Patch
{
[HarmonyPostfix]
public static void StatPart_Glow_ActiveFor_Postfix(Thing t, ref bool __result, bool ___ignoreIfPrefersDarkness)
{
if (__result == true && t is Pawn pawn && ___ignoreIfPrefersDarkness && pawn.GetStatValue(StatDef.Named("LTS_DarkVision")) != 0)//this makes it so that any dark vision will give the pawn full dark vision, which is suboptimal, but will do for now.
{
__result = !__result;
}
}
}
/// <summary>
/// Those remote control part.
/// Why don`t let them render their own instead?
/// </summary>
[HarmonyPatch(typeof(Pawn))]
[HarmonyPatch(nameof(Pawn.GetGizmos))]
class Pawn_GetGizmos_Patch
{
[HarmonyPostfix]
private static void Pawn_GetGizmos_Postfix(Pawn __instance, ref IEnumerable<Gizmo> __result)
{
__result = __result.Concat(Gizmos(__instance));
}
internal static IEnumerable<Gizmo> Gizmos(Pawn pawn)
{
if (pawn.IsColonist || pawn.IsSlaveOfColony || pawn.IsPrisonerOfColony)
{
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.TryGetComp<LTS_HediffComp_RemoteGizmo>() != null)
{
yield return hediff.TryGetComp<LTS_HediffComp_RemoteGizmo>().RemoteGizmo();
}
}
}
}
}
[HarmonyPatch(typeof(ThoughtWorker))]
[HarmonyPatch(nameof(ThoughtWorker.MoodMultiplier))]
class ThoughtWorker_MoodMultiplier_Patch
{
[HarmonyPostfix]
public static void ThoughtWorker_MoodMultiplier_Postfix(Pawn p, ref float __result)
{
__result *= p?.GetStatValue(StatDef.Named("I_MoodFactor")) ?? 1f;
}
}
[HarmonyPatch(typeof(CompBiocodable))]
[HarmonyPatch(nameof(CompBiocodable.IsBiocodedFor))]
class CompBiocodable_IsBiocodedFor_Patch
{
[HarmonyPostfix]
public static void Hediff_PostAdd_Postfix(Thing thing, Pawn pawn, ref bool __result)
{
if (pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("BiochameleonDevice")) != null)
{
__result = true;
}
}
}
//[HarmonyPatch(typeof(Pawn_AbilityTracker), "GetGizmos")]
//[HarmonyPatch(typeof(Pawn_AbilityTracker))]
//[HarmonyPatch(nameof(Pawn_AbilityTracker.GetGizmos))]
//public static class Pawn_AbilityTracker_GetGizmos_Patch
//{
// [HarmonyPostfix]
// private static void Pawn_AbilityTracker_GetGizmos_Postfix(Pawn_AbilityTracker __instance, ref IEnumerable<Gizmo> __result)
// {
// foreach (Ability ability in __instance.AllAbilitiesForReading)
// {
// //if (ability.pawn.Faction == Faction.OfPlayer && ability.CompOfType<LTS_CompAbilityEffect_CaptiveControl>() != null)
// if (ability.CompOfType<LTS_CompAbilityEffect_CaptiveControl>() != null)
// {
// foreach (Command gizmo in ability.GetGizmos())
// {
// if (!__result.Contains(gizmo))
// {
// __result.AddItem(gizmo);
// }
// }
// }
// }
// }
//}
[HarmonyPatch(typeof(Hediff))]
[HarmonyPatch(nameof(Hediff.PostAdd))]
class Hediff_PostAdd_Patch_CryptosleepSickness
{
[HarmonyPostfix]
public static void Hediff_PostAdd_Postfix(DamageInfo? dinfo, Hediff __instance)
{
if (__instance.def == HediffDefOf.CryptosleepSickness && __instance.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("CryptoWakeImplant")) != null)
{
__instance.pawn.health.RemoveHediff(__instance);
}
}
}
//[HarmonyPatch(typeof(Hediff))]
//[HarmonyPatch(nameof(Hediff.PostAdd))]
//class Hediff_PostAdd_Patch_DeathRefusal
//{
// [HarmonyPostfix]
// public static void Hediff_PostAdd_Postfix(DamageInfo? dinfo, Hediff __instance)
// {
// if (__instance.def == HediffDefOf.DeathRefusalSickness && __instance.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("MortalCollar")) != null)
// {
// //__instance.pawn.health.RemoveHediff(__instance);
// __instance.pawn.health.AddHediff(HediffDef.Named("LTS_HoraxianKnowledge"), null, null, null);
// //__instance.pawn.psychicEntropy?.OffsetPsyfocusDirectly(1);
// }
// }
//}
[HarmonyPatch(typeof(Hediff))]
[HarmonyPatch(nameof(Hediff.PostAdd))]
class Hediff_PostAdd_Patch_EMP //add a chance equal to EMPResistance to immediately remove brain shock
{
[HarmonyPostfix]
public static void Hediff_PostAdd_Postfix(DamageInfo? dinfo, Hediff __instance)
{
float EMPResistance = __instance.pawn?.GetStatValue(StatDef.Named("I_BrainShockResistance")) ?? 0f;
//if (__instance.Label == "brain shock" && new System.Random().Next(0, 100) < EMPResistance * 100)
if (__instance.def.defName == "BrainShock" && new System.Random().Next(0, 100) < EMPResistance * 100)
{
__instance.pawn.health.RemoveHediff(__instance);
MoteMaker.ThrowText(new Vector3((float)__instance.pawn.Position.x + 1f, __instance.pawn.Position.y, (float)__instance.pawn.Position.z + 1f), text: ((string)"Resisted".Translate()), map: __instance.pawn.Map, color: Color.white);
}
}
}
[HarmonyPatch(typeof(CompDevourer))]
[HarmonyPatch(nameof(CompDevourer.CompTick))]
class CompDevourer_CompTick_Patch // 1/900 chance to escape every tick (15 second average) //now 1/1200, 20 second average // 1/1800 30 seconds
{
[HarmonyPostfix]
public static void CompTickPostfix(CompDevourer __instance)
{
if (new System.Random().Next(0, 1800) == 1799)
{
__instance.DigestJobFinished();
}
}
}
[HarmonyPatch(typeof(Hediff_Shambler), "FinishRising")]
class Pawn_MutantTracker_Hediff_Patch //if pawn has collar, remove timer and add super shambler.
{
[HarmonyPostfix]
public static void Hediff_Postfix(Hediff_Shambler __instance)
{
Log.Message(__instance.pawn.Name + " has collar?: " + __instance.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("DeadlifeCollar")) != null);
if (__instance.pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("DeadlifeCollar")) != null)
{
//__result = HediffMaker.MakeHediff(HediffDef.Named("LTS_SuperShambler"), ___pawn);
Hediff mutantHediff = __instance.pawn.mutant.Hediff;
mutantHediff.def = HediffDef.Named("LTS_SuperShambler");
//mutantHediff.TryGetComp(HediffCompDisappearsAndKills).
//mutantHediff.TryGetComp<HediffComp_DisappearsAndKills_Shambler>().disappearsAfterTicks = -1;
//mutantHediff.TryGetComp<HediffComp_DisappearsAndKills_Shambler>().disappearsAfterTicks = 600000;
//mutantHediff.TryGetComp<HediffComp_DisappearsAndKills_Shambler>().ticksToDisappear = 600000;
mutantHediff.TryGetComp<HediffComp_DisappearsAndKills_Shambler>().disabled = true;
}
}
}
[HarmonyPatch(typeof(CompDevourer))]
[HarmonyPatch(nameof(CompDevourer.GetDigestionTicks))]
class CompDevourer_GetDigestionTicks_Patch //multiply the time it takes to digest a pawn by 1/(acid damage they take%)
{
[HarmonyPostfix]
public static void GetDigestionTicksPostfix(CompDevourer __instance, ref int __result)
{
__result = (int)(__result / __instance.DigestingPawn.health.FactorForDamage(new DamageInfo(DamageDefOf.AcidBurn, 1, 0))); //should multiply the time it takes to digest a pawn by 1/(acid damage they take%)
}
}
//[HarmonyPatch(typeof(Pawn_GeneTracker), "AffectedByDarkness", MethodType.Getter)]
//class Pawn_GeneTracker_AffectedByDarkness_Patch //if pawn has something that should give them night vision, give them night vision.
//{
// [HarmonyPostfix]
// public static void AffectedByDarknessPostfix(Pawn_GeneTracker __instance, ref bool __result)
// {
// //bool pawnHasDarkvisionHediff = false;
// //foreach (HediffComp hediffComp in __instance.pawn.health.hediffSet.GetAllComps())
// //{
// // if ((hediffComp as LTS_CompDarkVision) != null) { pawnHasDarkvisionHediff = true; }
// //}
// if (ModLister.BiotechInstalled && __instance.pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("Blacksight")) != null || __instance.pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("ArchotechEye")) != null)
// {
// __result = false;
// }
// }
//}
[HarmonyPatch(typeof(Toils_Ingest))]
[HarmonyPatch(nameof(Toils_Ingest.FinalizeIngest))]
class Toils_Ingest_FinalizeIngest_Patch //add gourmand tongue mood buff if user had gourmand tongue
{
[HarmonyPrefix]
static bool FinalizeIngest_Prefix(Pawn ingester, TargetIndex ingestibleInd, ref Toil __result)
{
Toil toil = ToilMaker.MakeToil("FinalizeIngest");
toil.initAction = delegate
{
Pawn actor = toil.actor;
Job curJob = actor.jobs.curJob;
Thing thing = curJob.GetTarget(ingestibleInd).Thing;
if (ingester.needs.mood != null && thing.def.IsNutritionGivingIngestible && thing.def.ingestible.chairSearchRadius > 10f)
{
if (!(ingester.Position + ingester.Rotation.FacingCell).HasEatSurface(actor.Map) && ingester.GetPosture() == PawnPosture.Standing && !ingester.IsWildMan() && thing.def.ingestible.tableDesired)
{
ingester.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.AteWithoutTable);
}
if (ingester.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("GourmandTongue")) != null) // if the pawn has the tongue, give the thought
{
ingester.needs.mood.thoughts.memories.TryGainMemory(ThoughtDef.Named("AteMealWithGourmandTongue"));
}
Room room = ingester.GetRoom();
if (room != null)
{
int scoreStageIndex = RoomStatDefOf.Impressiveness.GetScoreStageIndex(room.GetStat(RoomStatDefOf.Impressiveness));
if (ThoughtDefOf.AteInImpressiveDiningRoom.stages[scoreStageIndex] != null)
{
ingester.needs.mood.thoughts.memories.TryGainMemory(ThoughtMaker.MakeThought(ThoughtDefOf.AteInImpressiveDiningRoom, scoreStageIndex));
}
}
}
float num = ingester.needs?.food?.NutritionWanted ?? (thing.GetStatValue(StatDefOf.Nutrition) * (float)thing.stackCount);
if (curJob.ingestTotalCount)
{
num = thing.GetStatValue(StatDefOf.Nutrition) * (float)thing.stackCount;
}
else if (curJob.overeat)
{
num = Mathf.Max(num, 0.75f);
}
float num2 = thing.Ingested(ingester, num);
if (!ingester.Dead && ingester.needs?.food != null)
{
ingester.needs.food.CurLevel += num2;
ingester.records.AddTo(RecordDefOf.NutritionEaten, num2);
}
};
toil.defaultCompleteMode = ToilCompleteMode.Instant;
__result = toil;
return false;
}
}
//[HarmonyPatch(typeof(Pawn))]
//[HarmonyPatch(nameof(Pawn.PreApplyDamage))]
//class Pawn_PreApplyDamage_Patch //remove remaining shield health damage. reduce shield health by damage it absorbed.
//{
// [HarmonyPrefix]
// public static bool PreApplyDamage_Prefix()
// {
// return false;
// }
// [HarmonyPostfix]
// public static void CanCommandToPostfix(ref DamageInfo dinfo, out bool absorbed, Pawn __instance)
// {
// float PsychicShieldMaxHealth = __instance.GetStatValue(StatDef.Named("PsychicShieldMaxHealth"));
// float damageMultiplier = 1f;
// float damage = dinfo.Amount;
// if (PsychicShieldMaxHealth > 0 && __instance.Awake())
// {
// if (__instance.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) as LTS_ShieldHediff != null)
// {
// LTS_ShieldHediff shieldHediff = __instance.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) as LTS_ShieldHediff;
// if (shieldHediff.PsychicShieldCurrentHealth > (dinfo).Amount) //if our shield has more health than the damage
// {
// damage = 0;
// shieldHediff.PsychicShieldCurrentHealth -= ((DamageInfo)dinfo).Amount;//
// shieldHediff.PsychicShieldRegenInteruptedTicks = 300;
// SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(__instance.Position, __instance.Map));
// }
// else //remove all the damage it can.
// {
// damage -= shieldHediff.PsychicShieldCurrentHealth;
// if (shieldHediff.PsychicShieldCurrentHealth != 0)
// {
// SoundDef.Named("EnergyShield_Broken").PlayOneShot(new TargetInfo(__instance.Position, __instance.Map));
// }
// shieldHediff.PsychicShieldCurrentHealth = 0;
// shieldHediff.PsychicShieldRegenInteruptedTicks = 1200;//20 seconds
// }
// }
// }
// if (ModsConfig.BiotechActive && __instance.genes != null)
// {
// damageMultiplier *= __instance.genes.FactorForDamage(dinfo);
// }
// damageMultiplier *= __instance.health.FactorForDamage(dinfo);
// dinfo.SetAmount(damage * damageMultiplier);
// new ThingWithComps().PreApplyDamage(ref dinfo, out absorbed);
// if (!absorbed)
// {
// __instance.health.PreApplyDamage(dinfo, out absorbed);
// }
// }
//}
//[HarmonyPatch(typeof(Hediff))]
//[HarmonyPatch(nameof(Hediff.PostAdd))]
//class Hediff_PostAdd_Patch //remove remaining shield health damage. reduce shield health by damage it absorbed. \\currently stops all damage if PsychicShieldMaxHealth > 0.
//{
// [HarmonyPostfix]
// public static void Hediff_PostAdd_Postfix(DamageInfo? dinfo, Hediff __instance)//, ref bool __result)
// {
// float PsychicShieldMaxHealth = __instance.pawn?.GetStatValue(StatDef.Named("PsychicShieldMaxHealth")) ?? 0f;
// //PsychicShieldMaxHealth = 0;PsychicShieldCurrentHealth
// if (dinfo != null)
// {
// if (((DamageInfo)dinfo).Def.harmsHealth)
// {
// if (PsychicShieldMaxHealth > 0 && __instance.pawn.Awake())
// {
// //LTS_ShieldHediff shieldHediff = __instance.pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) as LTS_ShieldHediff;
// if (__instance.pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) as LTS_ShieldHediff != null)
// {
// LTS_ShieldHediff shieldHediff = __instance.pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) as LTS_ShieldHediff;
// if (shieldHediff.PsychicShieldCurrentHealth > ((DamageInfo)dinfo).Amount) //if our shield has more health than the damage
// {
// __instance.pawn.health.RemoveHediff(__instance);//remove the damage
// shieldHediff.PsychicShieldCurrentHealth -= ((DamageInfo)dinfo).Amount;//
// shieldHediff.PsychicShieldRegenInteruptedTicks = 300;
// SoundDefOf.EnergyShield_AbsorbDamage.PlayOneShot(new TargetInfo(__instance.pawn.Position, __instance.pawn.Map));
// }
// else //remove all the damage it can.
// {
// //DamageInfo reducedDamage = (DamageInfo)dinfo;
// //DamageInfo reducedDamage = new DamageInfo((DamageInfo)dinfo);
// DamageInfo reducedDamage = new DamageInfo();
// //reducedDamage
// reducedDamage.SetAmount(((DamageInfo)dinfo).Amount - shieldHediff.PsychicShieldCurrentHealth);
// //reducedDamage.
// //Ok, lets try changing things one by one to see what's breaking it.
// reducedDamage.SetAllowDamagePropagation(false);
// //reducedDamage.Def = ((DamageInfo)dinfo).Def;
// DamageDef reducedDamageDef = new DamageDef();
// reducedDamage.Def = reducedDamageDef;
// //reducedDamageDef.
// Hediff newWound = HediffMaker.MakeHediff(__instance.def, __instance.pawn);
// DamageWorker.DamageResult reducedDamageResult = new DamageWorker.DamageResult();
// //__instance.pawn.health.AddHediff(newWound, ((DamageInfo)dinfo).HitPart, null);//having the third argument be 'reducedDamage' is the problem.
// //__instance.pawn.health.hediffSet.AddDirect(newWound, reducedDamage);
// //__instance.pawn.health.RemoveHediff(__instance);
// //__instance.pawn.health.hediffSet.HasHediff;
// __instance.Heal(shieldHediff.PsychicShieldCurrentHealth);
// if (shieldHediff.PsychicShieldCurrentHealth != 0)
// {
// SoundDef.Named("EnergyShield_Broken").PlayOneShot(new TargetInfo(__instance.pawn.Position, __instance.pawn.Map));
// }
// shieldHediff.PsychicShieldCurrentHealth = 0;
// shieldHediff.PsychicShieldRegenInteruptedTicks = 1200;//20 seconds
// }
// }
// }
// //else Log.Error("Shield on 0 HP");
// }
// //else Log.Error("Doesn't harm health");
// }
// //else Log.Error("No damageInfo");
// }
//}
[HarmonyPatch(typeof(DamageWorker_AddInjury))] //change to bite?
[HarmonyPatch(nameof(DamageWorker_AddInjury.Apply))]
class DamageWorker_AddInjury_Apply_Patch
{
[HarmonyPostfix]
public static void ApplyPostfix(DamageInfo dinfo, Thing thing, DamageWorker_AddInjury __instance)
{
//Log.Message("ApplyPostfix triggered");
HediffDef LTS_Hediff = __instance.def.GetModExtension<LTS_IModExtension>()?.LTS_Hediff;
float? LTS_Severity = __instance.def.GetModExtension<LTS_IModExtension>()?.LTS_Severity;
GeneDef LTS_Gene = __instance.def.GetModExtension<LTS_IModExtension>()?.LTS_Gene;
Pawn victim = thing as Pawn;
Pawn instigator = dinfo.Instigator as Pawn;
if (victim != null && instigator != null) //if the target is a pawn and the attacker is attacking their target (don't ask)
{
//Log.Message("There's a victim and perpetrator");
if (LTS_Hediff != null && LTS_Severity != null && LTS_Gene != null)//if we have a hediff and severity to inflict
{
//Log.Message("Mod extensions detected");
if (victim.RaceProps.IsFlesh)//if target is fleshy
{
//Log.Message("Pawn is fleshy");
if (victim.health?.hediffSet?.GetFirstHediffOfDef(LTS_Hediff) != null) //if victim already has hediff, increase it by severity
{
//Log.Message("Increased hediff");
victim.health.hediffSet.GetFirstHediffOfDef(LTS_Hediff).Severity += (LTS_Severity ?? 0.2f) / victim.BodySize;
}
else //else add hediff then set severity
{
//Log.Message("Added hediff");
victim.health.AddHediff(__instance.def.GetModExtension<LTS_IModExtension>()?.LTS_Hediff, null, null, null);
victim.health.hediffSet.GetFirstHediffOfDef(LTS_Hediff).Severity = (LTS_Severity ?? 0.2f) / victim.BodySize;
}
if (instigator.genes.HasActiveGene(LTS_Gene))//if perp is hemogenic
{
if (victim.genes?.HasActiveGene(LTS_Gene) != null)
{
//Log.Message("Genes detected.");
if (!victim.genes.HasActiveGene(LTS_Gene) && victim.RaceProps.Humanlike)//if target isn't hemogenic but is humanoid
{
//Log.Message("Normal humanlike detected.");
instigator.needs.food.CurLevel += (LTS_Severity ?? 0.2f) / 2;
GeneUtility.OffsetHemogen(instigator, (LTS_Severity ?? 0.2f) / 2);
if (ModsConfig.IsActive("vanillaracesexpanded.sanguophage")) //set hemogen to normal if VRES
{
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen"))); }
else if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen"))); }
else if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen"))); }
}
}
else if (victim.genes.HasActiveGene(LTS_Gene) && ModsConfig.IsActive("vanillaracesexpanded.sanguophage"))//victim is hemogenic and VRES is active
{
//if (victim.genes.GetFirstGeneOfType<Gene_Hemogen>().Value >= 0)//if they've got any hemogen left
//Log.Message("Sangophage detected.");
instigator.needs.food.CurLevel += (LTS_Severity ?? 0.2f) / 2;
GeneUtility.OffsetHemogen(instigator, (LTS_Severity ?? 0.2f) / 2);
//GeneResourceDrainUtility.OffsetResource(gene_HemogenDrain, offset)
GeneUtility.OffsetHemogen(victim, -(LTS_Severity ?? 0.2f) / 2, false);
{
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen")) == null) { instigator.health.AddHediff(HediffDef.Named("VRE_ConsumedSanguophageHemogen"), null, null, null); }
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen"))); }
else if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen"))); }
}
}
}
else if (victim.RaceProps.Animal && ModsConfig.IsActive("vanillaracesexpanded.sanguophage"))//victim is animal
{
//Log.Message("Animal detected.");
instigator.needs.food.CurLevel += (LTS_Severity ?? 0.2f) / 2;
GeneUtility.OffsetHemogen(instigator, (LTS_Severity ?? 0.2f) / 2);
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen")) == null) { instigator.health.AddHediff(HediffDef.Named("VRE_ConsumedAnimalHemogen"), null, null, null); }
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen"))); }
else if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen"))); }
}
else if (false && ModsConfig.IsActive("vanillaracesexpanded.sanguophage"))//victim is zombie/rotting? Lets wait for ANOMALY for this.
{
//Log.Message("Corpse detected.");
instigator.needs.food.CurLevel += (LTS_Severity ?? 0.2f) / 2;
GeneUtility.OffsetHemogen(instigator, (LTS_Severity ?? 0.2f) / 2);
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedCorpseHemogen")) == null) { instigator.health.AddHediff(HediffDef.Named("VRE_ConsumedCorpseHemogen"), null, null, null); }
if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedSanguophageHemogen"))); }
else if (instigator.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen")) != null) { instigator.health.RemoveHediff(instigator.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("VRE_ConsumedAnimalHemogen"))); }
}
}
}
}
}
}
} //hemo-fangs
[HarmonyPatch(typeof(PregnancyUtility))]
[HarmonyPatch(nameof(PregnancyUtility.ApplyBirthOutcome_NewTemp))]
class PregnancyUtility_ApplyBirthOutcome_Patch
{
[HarmonyPostfix]
public static void ApplyBirthOutcomePostfix(RitualOutcomePossibility outcome, float quality, Precept_Ritual ritual, List<GeneDef> genes, Pawn geneticMother, Thing birtherThing, Pawn father = null, Pawn doctor = null, LordJob_Ritual lordJobRitual = null, RitualRoleAssignments assignments = null)
{
//if (birtherThing == geneticMother)//if the mother is the thing giving birth (i.e. not a tube)
if (birtherThing as Pawn != null)//if a pawn is the thing giving birth (i.e. not a tube)
{
if (PawnHasArchowomb(birtherThing as Pawn))//if the one giving birth has an archowomb
{
geneticMother.relations.Children.Last().health.AddHediff(HediffDef.Named("Archoborn"), null, null, null);//give the newest child the hediff
}
}
}
static public bool PawnHasArchowomb(Pawn pawn)
{
return (pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null);
}
static public bool PawnHasArchowombAndIsGivingBirth(Pawn pawn, Thing thing)
{
//Log.Message("PawnHasArchowombAndIsGivingBirth HAS BEEN CALLED AND RETURNED: " + ((thing == pawn && pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null) || Find.Storyteller.difficulty.babiesAreHealthy));
//return (thing == pawn && pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null) || Find.Storyteller.difficulty.babiesAreHealthy;//if the mother is the one giving birth and the mother has an archowomb or babiesAreHealthy is on, return true.
if (thing as Pawn != null)
{
return (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null) || Find.Storyteller.difficulty.babiesAreHealthy;
}
return false;
}
static public int PawnHasArchowombAndIsGivingBirthInt(RitualOutcomePossibility outcome, Pawn pawn, Thing thing)//if the mother is the one giving birth and the mother has an archowomb or babiesAreHealthy is on, return true.
{
//if ((thing == pawn && pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null) || Find.Storyteller.difficulty.babiesAreHealthy)
// return 1;
//else
//{
// return outcome.positivityIndex;
//}
if (thing as Pawn != null)
{
if ((thing as Pawn).health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("Archowomb")) != null || Find.Storyteller.difficulty.babiesAreHealthy)
{
return 1;
}
}
return outcome.positivityIndex;
}
[HarmonyTranspiler]
static IEnumerable<CodeInstruction> AddLineToApplyBirthOutcome(IEnumerable<CodeInstruction> code, ILGenerator il)
{
List<CodeInstruction> lines = new List<CodeInstruction>(code);
List<CodeInstruction> newLines = new List<CodeInstruction>();
string referenceLine = "call static System.Single RimWorld.PregnancyUtility::ChanceMomDiesDuringBirth(System.Single quality)";//well, actually it's the line after the line after where we want our code to go, but we've added '-1's to the 'lineAfterLineNumber' to account for that.
int referenceLineNumber = 0;
//Log.Message("BEGINNING OF OUTPUT");
for (int lineNumber = 0; lineNumber < lines.Count; lineNumber++) //finds the line number of the line after the one we want to inject
{
//if (lineNumber >= 0 && lineNumber < 100)
//{
// Log.Message("Line " + (lineNumber).ToString() + ": " + lines[lineNumber].ToString());
//}
if (lines[lineNumber].ToString() == referenceLine)
{
referenceLineNumber = lineNumber;
}
}
//Log.Message("END OF OUTPUT");
if (referenceLineNumber != 0)//if we found the lineAfterLineNumber
{
for (int lineNumber = 0; lineNumber < referenceLineNumber - 4; lineNumber++)//add all the lines before our injection to the empty newLines
{
newLines.Add(lines[lineNumber]);
}
//stloc.2 //evaluation stack to babiesAreHealthy to, incase i want to
//stloc.3 //evaluation stack to positivity index
//ldarg.s geneticMother
//ldarg.s birtherThing
//call bool LTS_Implants.PregnancyUtility_ApplyBirthOutcome_Patch::PawnHasArchowombAndIsGivingBirth(class ['Assembly-CSharp'] Verse.Pawn, class ['Assembly-CSharp'] Verse.Thing)
//stloc.3
newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 4));//feeds geneticMother
newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 5));//feeds birtherThing
newLines.Add(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PregnancyUtility_ApplyBirthOutcome_Patch), nameof(PregnancyUtility_ApplyBirthOutcome_Patch.PawnHasArchowombAndIsGivingBirth))));
newLines.Add(new CodeInstruction(OpCodes.Stloc_2));//sets babiesAreHealthy
newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 0));//feeds outcome
newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 4));//feeds geneticMother
newLines.Add(new CodeInstruction(OpCodes.Ldarg_S, 5));//feeds birtherThing
newLines.Add(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(PregnancyUtility_ApplyBirthOutcome_Patch), nameof(PregnancyUtility_ApplyBirthOutcome_Patch.PawnHasArchowombAndIsGivingBirthInt))));
newLines.Add(new CodeInstruction(OpCodes.Stloc_3));//sets positivityIndex
for (int lineNumber = referenceLineNumber - 4; lineNumber < lines.Count; lineNumber++)//add all the lines after our injection to the newLines
{
newLines.Add(lines[lineNumber]);
}
//Log.Message("RETURNING NEWLINES");
return newLines.AsEnumerable();
//Log.Message("HERE!");
//Log.Message(lines[lineAfterLineNumber-4].ToString());
//Log.Message(lines[lineAfterLineNumber-3].ToString());
//Log.Message(lines[lineAfterLineNumber-2].ToString());
//Log.Message("Here's where things get added");
//Log.Message(lines[lineAfterLineNumber-1].ToString());
//Log.Message(lines[lineAfterLineNumber].ToString());
//Log.Message(newLines[referenceLineNumber -4].ToString());
//Log.Message(newLines[referenceLineNumber -3].ToString());
//Log.Message(newLines[referenceLineNumber -2].ToString());
//Log.Message(newLines[referenceLineNumber -1].ToString());
//Log.Message(newLines[referenceLineNumber].ToString());
//Log.Message(newLines[referenceLineNumber +1].ToString());
//Log.Message(newLines[referenceLineNumber +2].ToString());
//Log.Message(newLines[referenceLineNumber +3].ToString());
//Log.Message(newLines[referenceLineNumber + 4].ToString());
//Log.Message(newLines[referenceLineNumber + 5].ToString());
//Log.Message(newLines[referenceLineNumber + 6].ToString());
}
else
{
//Log.Message("LTS Implants: Failed to apply transpile, returning base");
Log.Error("LTS Implants: Failed to apply birth transpile, returning base");
}
return lines.AsEnumerable();
}
}//Apply hediff to child and force healthy birth with archowomb
}