separated single file.converted to sdk style, initial CE compat on going.
This commit is contained in:
parent
28345a1b5f
commit
b34353deae
Binary file not shown.
Binary file not shown.
@ -4,7 +4,29 @@
|
||||
<name>Implants</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:LTS_Implants.HarmonyPatches">
|
||||
<member name="M:Implants.Biotech.BiotechMechanitorPatches.Pawn_MechanitorTracker_CanCommandTo_Patch.CanCommandToPostfix(Verse.LocalTargetInfo,RimWorld.Pawn_MechanitorTracker,System.Boolean@)">
|
||||
<summary>
|
||||
pushed always commandable check to front to reduct compute.
|
||||
TODO perhaps need a custom patch order to make sure this logic always works.
|
||||
</summary>
|
||||
<param name="target">target mech to command</param>
|
||||
<param name="__instance">should be mechanitor, but not always the mechanitor for example like Dead man switch ctrl mechs </param>
|
||||
<param name="__result">Commandable result from original code.</param>
|
||||
</member>
|
||||
<member name="M:Implants.Biotech.BiotechMechanitorPatches.Pawn_MechanitorTracker_DrawCommandRadius_Patch.DrawCommandRadiusPrefix">
|
||||
<summary>
|
||||
Skip original draw radius using a prefix.
|
||||
TODO may need specify fixed patch order to make sure this works.
|
||||
</summary>
|
||||
<returns>return false to skip original draw.</returns>
|
||||
</member>
|
||||
<member name="M:Implants.Biotech.BiotechMechanitorPatches.Pawn_MechanitorTracker_DrawCommandRadius_Patch.DrawCommandRadiusPostfix(RimWorld.Pawn_MechanitorTracker)">
|
||||
<summary>
|
||||
Postfix the draw radius by apply our extended radius on top.
|
||||
</summary>
|
||||
<param name="__instance"></param>
|
||||
</member>
|
||||
<member name="T:LTS_Implants.StatPart_FertilityByGenderAge_AgeFactor_Patch">
|
||||
<summary>
|
||||
Bootstrap class to do the harmony patches.
|
||||
</summary>
|
||||
@ -22,27 +44,5 @@
|
||||
Why don`t let them render their own instead?
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:LTS_Implants.Pawn_MechanitorTracker_CanCommandTo_Patch.CanCommandToPostfix(Verse.LocalTargetInfo,RimWorld.Pawn_MechanitorTracker,System.Boolean@)">
|
||||
<summary>
|
||||
pushed always commandable check to front to reduct compute.
|
||||
TODO perhaps need a custom patch order to make sure this logic always works.
|
||||
</summary>
|
||||
<param name="target">target mech to command</param>
|
||||
<param name="__instance">should be mechanitor, but not always the mechanitor for example like Deadmanswitch </param>
|
||||
<param name="__result">Commandable result from original code.</param>
|
||||
</member>
|
||||
<member name="M:LTS_Implants.Pawn_MechanitorTracker_DrawCommandRadius_Patch.DrawCommandRadiusPrefix">
|
||||
<summary>
|
||||
Skip original draw radius using a prefix.
|
||||
TODO may need specify fixed patch order to make sure this works.
|
||||
</summary>
|
||||
<returns>return false to skip original draw.</returns>
|
||||
</member>
|
||||
<member name="M:LTS_Implants.Pawn_MechanitorTracker_DrawCommandRadius_Patch.DrawCommandRadiusPostfix(RimWorld.Pawn_MechanitorTracker)">
|
||||
<summary>
|
||||
Postfix the draw radius by apply our extended radius on top.
|
||||
</summary>
|
||||
<param name="__instance"></param>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
|
308
1.5/Assemblies/Implants/Anomaly/AnomalyGeneral.cs
Normal file
308
1.5/Assemblies/Implants/Anomaly/AnomalyGeneral.cs
Normal file
@ -0,0 +1,308 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using LTS_Implants;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Implants.Anomaly
|
||||
{
|
||||
|
||||
public class LTS_Hediff_PsychicReaper : Hediff
|
||||
{
|
||||
private int previousHumanKills = -1;
|
||||
|
||||
public override void PostAdd(DamageInfo? dinfo)
|
||||
{
|
||||
base.PostAdd(dinfo);
|
||||
previousHumanKills = (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes);
|
||||
}
|
||||
|
||||
public override void Notify_Spawned()
|
||||
{
|
||||
base.Notify_Spawned();
|
||||
PostAdd(null);
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
//Log.Message("Psychic Reaper Tick");
|
||||
if (Find.TickManager.TicksGame % 10 == 0)
|
||||
{
|
||||
if ((int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes) > previousHumanKills)
|
||||
{
|
||||
//Log.Message("Previous kills: " + previousHumanKills);
|
||||
//Log.Message("Current kills: "+ (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes));
|
||||
pawn.psychicEntropy.OffsetPsyfocusDirectly(0.05f*((int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes) - previousHumanKills));//add 5 psyfocus per humanlike kill
|
||||
}
|
||||
previousHumanKills = (int)pawn.records.GetValue(RecordDefOf.KillsHumanlikes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LTS_Hediff_Voidlink : Hediff
|
||||
{
|
||||
public override bool ShouldRemove => false;
|
||||
public override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
if (Find.TickManager.TicksGame % 30 == 0)
|
||||
{
|
||||
Severity = Find.Anomaly.LevelDef.level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LTS_HediffCompProperties_MetalhorrorEmerge : HediffCompProperties
|
||||
{
|
||||
public string letterLabel;
|
||||
|
||||
public string letterText;
|
||||
|
||||
public LTS_HediffCompProperties_MetalhorrorEmerge()
|
||||
{
|
||||
compClass = typeof(LTS_HediffComp_MetalhorrorEmerge);
|
||||
}
|
||||
}
|
||||
|
||||
public class LTS_HediffComp_MetalhorrorEmerge : HediffComp
|
||||
{
|
||||
private static readonly IntRange StunDuration = new IntRange(120, 240);
|
||||
|
||||
public LTS_HediffCompProperties_MetalhorrorEmerge Props => (LTS_HediffCompProperties_MetalhorrorEmerge)props;
|
||||
|
||||
public override void Notify_SurgicallyRemoved(Pawn surgeon)
|
||||
{
|
||||
TentacleAttack(surgeon);
|
||||
}
|
||||
|
||||
public override void Notify_SurgicallyReplaced(Pawn surgeon)
|
||||
{
|
||||
TentacleAttack(surgeon);
|
||||
}
|
||||
|
||||
private void TentacleAttack(Pawn surgeon)
|
||||
{
|
||||
if (ModsConfig.AnomalyActive)
|
||||
{
|
||||
Pawn pawn = parent.pawn;
|
||||
Pawn pawn2 = PawnGenerator.GeneratePawn(new PawnGenerationRequest(PawnKindDefOf.Metalhorror, 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, 0f));
|
||||
GenSpawn.Spawn(pawn2, CellFinder.StandableCellNear(pawn.Position, pawn.Map, 2f), pawn.Map);
|
||||
pawn2.stances.stunner.StunFor(StunDuration.RandomInRange, surgeon);
|
||||
CompInspectStringEmergence compInspectStringEmergence = pawn2.TryGetComp<CompInspectStringEmergence>();
|
||||
if (compInspectStringEmergence != null)
|
||||
{
|
||||
compInspectStringEmergence.sourcePawn = pawn;
|
||||
}
|
||||
TaggedString label = Props.letterLabel.Formatted(pawn.Named("PAWN"));
|
||||
TaggedString text = Props.letterText.Formatted(pawn.Named("PAWN"));
|
||||
Find.LetterStack.ReceiveLetter(label, text, LetterDefOf.ThreatBig, pawn2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class LTS_Hediff_HyperAdrenalineGland : Hediff
|
||||
{
|
||||
private float totalDamageTaken;
|
||||
|
||||
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
|
||||
if (pawn.Dead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield")) != null && ((pawn.health.hediffSet.GetFirstHediffOfDef(HediffDef.Named("PsychokeneticShield"))) as LTS_ShieldHediff).PsychicShieldCurrentHealth > 0)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
totalDamageTaken += totalDamageDealt;
|
||||
if (!pawn.Dead && totalDamageTaken > 0f && !pawn.health.hediffSet.HasHediff(HediffDefOf.RageSpeed) && !pawn.health.Downed)
|
||||
{
|
||||
pawn.health.AddHediff(HediffMaker.MakeHediff(HediffDefOf.RageSpeed, pawn));
|
||||
if (pawn.Spawned)
|
||||
{
|
||||
EffecterDefOf.ChimeraRage.Spawn(pawn.Position, pawn.Map).Cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Notify_Downed()
|
||||
{
|
||||
Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.RageSpeed);
|
||||
if (firstHediffOfDef != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(firstHediffOfDef);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
if (!pawn.Dead && pawn.health.summaryHealth.SummaryHealthPercent >= 0.98f)
|
||||
{
|
||||
Hediff firstHediffOfDef = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.RageSpeed);
|
||||
if (firstHediffOfDef != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(firstHediffOfDef);
|
||||
totalDamageTaken = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref totalDamageTaken, "totalDamageTaken", 0f);
|
||||
}
|
||||
}
|
||||
|
||||
public class LTS_Hediff_DefensiveImpaler : Hediff
|
||||
{
|
||||
public override void Notify_PawnPostApplyDamage(DamageInfo dinfo, float totalDamageDealt)
|
||||
{
|
||||
base.Notify_PawnPostApplyDamage(dinfo, totalDamageDealt);
|
||||
if (pawn.Dead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (dinfo.Instigator != null && pawn.Position.InHorDistOf(dinfo.Instigator.Position, 1.5f))//attacker next to user //apply 6 stab damage, 20% penetration
|
||||
{
|
||||
//SoundDefOf..PlayOneShot(pawn);
|
||||
//BattleLogEntry_DamageTaken battleLogEntry_DamageTaken = new BattleLogEntry_DamageTaken(pawn, RulePackDefOf.DamageEvent_UnnaturalDarkness);
|
||||
//Find.BattleLog.Add(battleLogEntry_DamageTaken);
|
||||
//dinfo.Instigator.TakeDamage(new DamageInfo(DamageDefOf.Stab, 6)).AssociateWithLog(battleLogEntry_DamageTaken);
|
||||
dinfo.Instigator.TakeDamage(new DamageInfo(DamageDefOf.Stab, 6));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region The Cube
|
||||
|
||||
|
||||
public class CompProperties_PsychicBeguile : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_PsychicBeguile()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_PsychicBeguile);
|
||||
}
|
||||
public PawnRelationDef pawnRelationDef;
|
||||
}
|
||||
|
||||
public class CompAbilityEffect_PsychicBeguile : CompAbilityEffect
|
||||
{
|
||||
public new CompProperties_PsychicBeguile Props
|
||||
{
|
||||
get
|
||||
{
|
||||
return (CompProperties_PsychicBeguile)this.props;
|
||||
}
|
||||
}
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
if (target.Pawn.Faction != parent.pawn.Faction)
|
||||
{
|
||||
target.Pawn.SetFaction(parent.pawn.Faction);
|
||||
IncidentWorker.SendIncidentLetter(target.Pawn.Name + " beguiled!", parent.pawn.Name + " has used " + parent.pawn.Possessive() + " psychic beguiler to psychically manipulate " + target.Pawn.Name + ". " + target.Pawn.Name + " has become obsessed with " + parent.pawn.Name + " and is joining " + parent.pawn.Possessive() + " faction.", LetterDefOf.PositiveEvent, new IncidentParms(), target.Pawn, IncidentDefOf.WandererJoin);
|
||||
}
|
||||
target.Pawn.relations.AddDirectRelation(Props.pawnRelationDef, parent.pawn);
|
||||
if(target.Pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeComa, out Hediff cubeComa))
|
||||
{
|
||||
target.Pawn.health.RemoveHediff(cubeComa);
|
||||
}
|
||||
if (target.Pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeInterest, out Hediff cubeInterest))
|
||||
{
|
||||
target.Pawn.health.RemoveHediff(cubeInterest);
|
||||
}
|
||||
if (target.Pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeWithdrawal, out Hediff cubeWithdrawal))
|
||||
{
|
||||
target.Pawn.health.RemoveHediff(cubeWithdrawal);
|
||||
}
|
||||
if (target.Pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeRage, out Hediff cubeRage))
|
||||
{
|
||||
target.Pawn.health.RemoveHediff(cubeRage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LTS_Hediff_ObsessionBerserkOnDeath : HediffWithComps
|
||||
{
|
||||
|
||||
public override void Notify_PawnCorpseSpawned()
|
||||
{
|
||||
base.Notify_PawnCorpseSpawned();
|
||||
List<Pawn> allHumanlikeSpawned = pawn.Corpse.Map.mapPawns.AllHumanlikeSpawned;
|
||||
for (int i = 0; i < allHumanlikeSpawned.Count; i++)
|
||||
{
|
||||
Pawn otherPawn = allHumanlikeSpawned[i];
|
||||
if (otherPawn.RaceProps.Humanlike && otherPawn.relations.GetDirectRelation(I_DefOf.PsychicBeguileObsessed, pawn) != null)
|
||||
{
|
||||
MentalBreakDefOf.BerserkShort.Worker.TryStart(otherPawn, "Target of obsession died", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void PostAdd(DamageInfo? dinfo)
|
||||
{
|
||||
base.PostAdd(dinfo);
|
||||
RemoveCubeHediffs(pawn);
|
||||
}
|
||||
|
||||
public void RemoveCubeHediffs(Pawn pawn)
|
||||
{
|
||||
if (pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeComa, out Hediff cubeComa))
|
||||
{
|
||||
pawn.health.RemoveHediff(cubeComa);
|
||||
}
|
||||
if (pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeInterest, out Hediff cubeInterest))
|
||||
{
|
||||
pawn.health.RemoveHediff(cubeInterest);
|
||||
}
|
||||
if (pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeWithdrawal, out Hediff cubeWithdrawal))
|
||||
{
|
||||
pawn.health.RemoveHediff(cubeWithdrawal);
|
||||
}
|
||||
if (pawn.health.hediffSet.TryGetHediff(HediffDefOf.CubeRage, out Hediff cubeRage))
|
||||
{
|
||||
pawn.health.RemoveHediff(cubeRage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public class LTS_Hediff_DeathRaiseAsShambler : HediffWithComps
|
||||
{
|
||||
//PawnKindDef spawnedPawn = PawnKindDefOf.Metalhorror;
|
||||
|
||||
public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
|
||||
{
|
||||
base.Notify_PawnDied(dinfo, culprit);
|
||||
if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.ShamblerCorpse) == null)
|
||||
{
|
||||
//Faction faction;
|
||||
//if (pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.ShamblerCorpse) != null)
|
||||
//{
|
||||
// faction = pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("ScratchDeadlife"))
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// faction = pawn.Faction;
|
||||
//}
|
||||
|
||||
|
||||
Faction faction = dinfo.GetValueOrDefault().Instigator?.Faction ?? pawn.Faction;
|
||||
if (pawn?.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("DeadlifeCollar")) != null) { faction = pawn.Faction; }
|
||||
GasUtility.AddDeadifeGas(pawn.Position, pawn.MapHeld, faction, Mathf.CeilToInt(255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
129
1.5/Assemblies/Implants/Biotech/Gene_Deathrest.cs
Normal file
129
1.5/Assemblies/Implants/Biotech/Gene_Deathrest.cs
Normal file
@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HarmonyLib;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace Implants.Biotech
|
||||
{
|
||||
[HarmonyPatch(typeof(Gene_Deathrest))]
|
||||
[HarmonyPatch(nameof(Gene_Deathrest.RemoveOldDeathrestBonuses))]
|
||||
class Gene_Deathrest_RemoveOldDeathrestBonuses_Patch //offsets the pawn's hemogen capacity by their BaseHemogenOffset stat after reset
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void RemoveOldDeathrestBonusesPostfix(Gene_Deathrest __instance)
|
||||
{
|
||||
if (__instance?.pawn?.genes?.GetFirstGeneOfType<Gene_Hemogen>() != null)
|
||||
{
|
||||
__instance.pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().SetMax(__instance.pawn.genes.GetFirstGeneOfType<Gene_Hemogen>().Max + __instance.pawn.GetStatValue(StatDef.Named("BaseHemogenOffset")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Need_Deathrest))]
|
||||
[HarmonyPatch(nameof(Need_Deathrest.NeedInterval))]
|
||||
class Need_Deathrest_NeedInterval_Patch//reduces and increases the time left for and between death rests for the DeathrestApparatus and DeathrestCapacitor respectively
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void NeedIntervalPostfix(Need_Deathrest __instance, Pawn ___pawn)
|
||||
{
|
||||
bool IsFrozen = ___pawn.Suspended || (__instance.def.freezeWhileSleeping && !___pawn.Awake()) || (__instance.def.freezeInMentalState && ___pawn.InMentalState);
|
||||
|
||||
if (!IsFrozen)
|
||||
{
|
||||
float deathrestingOffset = (((___pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f)) - 1f) * 0.2f; // + 1.2 0r 1 -1 *0.2 //also total factor = implant factor * gene factor * (___pawn.genes.GetFirstGeneOfType<Gene_Deathrest>()?.DeathrestEfficiency ?? 1f)
|
||||
float notDeathrestingOffset = (1f / 30f); // cancels out base function
|
||||
|
||||
deathrestingOffset += (float)(___pawn.genes.GetFirstGeneOfType<Gene_Deathrest>()?.DeathrestEfficiency-0.5) * 0.2f; //-0.5 is an arbritrary, place holder number until I find the correct maths
|
||||
//Log.Message(___pawn.genes.GetFirstGeneOfType<Gene_Deathrest>()?.DeathrestEfficiency);
|
||||
notDeathrestingOffset += (1 / (___pawn?.GetStatValue(StatDef.Named("DeathrestIntervalFactor")) ?? 1f)) * (-1f / 30f); // 1/stat*base, so 200% = decrease at half the rate and 50% = decrease at double
|
||||
|
||||
|
||||
__instance.CurLevel += (__instance.Deathresting ? deathrestingOffset : notDeathrestingOffset) / 400f;
|
||||
//__instance.CurLevel += (__instance.Deathresting ? (0.2f * ((___pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f) - 1f)) : (((___pawn?.GetStatValue(StatDef.Named("DeathrestIntervalFactor")) ?? 1f) - 1f) / 30f)) / 400f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Gene_Deathrest))]
|
||||
[HarmonyPatch(nameof(Gene_Deathrest.TickDeathresting))]
|
||||
class Gene_Deathrest_TickDeathresting_patch//makes deathrest hediff go up. and death res need.
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void TickDeathrestingPostfix(bool paused, Gene_Deathrest __instance, Pawn ___pawn, Need_Deathrest ___cachedDeathrestNeed)
|
||||
{
|
||||
int everyXTicks = (int)(1 / ((___pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f) - 1f));
|
||||
if (Find.TickManager.TicksGame % everyXTicks == 0)
|
||||
{
|
||||
__instance.deathrestTicks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(Need_Deathrest))]
|
||||
[HarmonyPatch(nameof(Need_Deathrest.GetTipString))]
|
||||
class Need_Deathrest_GetTipString_Patch //increases the displayed time left between deathresting if the pawn has a DeathrestCapacitor
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void GetTipStringPostfix(Need_Deathrest __instance, Pawn ___pawn, ref string __result)
|
||||
{
|
||||
string text = (__instance.LabelCap + ": " + __instance.CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor) + "\n";
|
||||
if (!__instance.Deathresting)
|
||||
{
|
||||
if (__instance.CurLevelPercentage > 0.1f)
|
||||
{
|
||||
float num = (__instance.CurLevelPercentage - 0.1f) / (0.033333335f * (1f / ___pawn?.GetStatValue(StatDef.Named("DeathrestIntervalFactor")) ?? 1f));//multiplies listed time until next deathrest by DeathrestIntervalFactor
|
||||
text += "NextDeathrestNeed".Translate(___pawn.Named("PAWN"), "PeriodDays".Translate(num.ToString("F1")).Named("DURATION")).Resolve().CapitalizeFirst();
|
||||
}
|
||||
else
|
||||
{
|
||||
text += "PawnShouldDeathrestNow".Translate(___pawn.Named("PAWN")).CapitalizeFirst().Colorize(ColorLibrary.RedReadable);
|
||||
}
|
||||
text += "\n\n";
|
||||
}
|
||||
__result = text + __instance.def.description;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(SanguophageUtility))]
|
||||
[HarmonyPatch(nameof(SanguophageUtility.DeathrestJobReport))]
|
||||
class SanguophageUtility_DeathrestJobReport_Patch //reduces the displayed time left while deathresting if the pawn has a DeathrestApparatus
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void DeathrestJobReportPostfix(Pawn pawn, ref string __result)
|
||||
{
|
||||
Hediff_Deathrest hediff_Deathrest = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.Deathrest, false) as Hediff_Deathrest;
|
||||
if (hediff_Deathrest != null && hediff_Deathrest.Paused)
|
||||
{
|
||||
__result = "DeathrestPaused".Translate() + ": " + "LethalInjuries".Translate();
|
||||
return;
|
||||
}
|
||||
Gene_Deathrest firstGeneOfType = pawn.genes.GetFirstGeneOfType<Gene_Deathrest>();
|
||||
TaggedString taggedString = "Deathresting".Translate().CapitalizeFirst() + ": ";
|
||||
float deathrestPercent = firstGeneOfType.DeathrestPercent;
|
||||
if (deathrestPercent < 1f)
|
||||
{
|
||||
taggedString += Mathf.Min(deathrestPercent, 0.99f).ToStringPercent("F0");
|
||||
}
|
||||
else
|
||||
{
|
||||
taggedString += string.Format("{0} - {1}", "Complete".Translate().CapitalizeFirst(), "CanWakeSafely".Translate());
|
||||
}
|
||||
if (deathrestPercent < 1f)
|
||||
{
|
||||
//taggedString += ", " + "DurationLeft".Translate((Mathf.RoundToInt(firstGeneOfType.MinDeathrestTicks * (1f / pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f) - firstGeneOfType.deathrestTicks)).ToStringTicksToPeriod(true, false, true, true, false));
|
||||
//taggedString += ", " + "DurationLeft".Translate((Mathf.RoundToInt(firstGeneOfType.MinDeathrestTicks * (1f / pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f) - firstGeneOfType.deathrestTicks)).ToStringTicksToPeriod(true, false, true, true, false));
|
||||
|
||||
taggedString += ", " + "DurationLeft".Translate((firstGeneOfType.MinDeathrestTicks - (Mathf.RoundToInt(firstGeneOfType.deathrestTicks * (1f / pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")) ?? 1f)))).ToStringTicksToPeriod(true, false, true, true, false));
|
||||
|
||||
|
||||
//Log.Message(pawn?.GetStatValue(StatDef.Named("DeathrestEffectivenessFactor")));
|
||||
//Log.Message(firstGeneOfType.deathrestTicks);
|
||||
}
|
||||
__result = taggedString.Resolve();
|
||||
}
|
||||
}
|
||||
}
|
557
1.5/Assemblies/Implants/Biotech/Mechanitor.cs
Normal file
557
1.5/Assemblies/Implants/Biotech/Mechanitor.cs
Normal file
@ -0,0 +1,557 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using HarmonyLib;
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI.Group;
|
||||
|
||||
namespace Implants.Biotech
|
||||
{
|
||||
#region Command Range
|
||||
|
||||
[HarmonyPatchCategory("Biotech")]
|
||||
class BiotechMechanitorPatches
|
||||
{
|
||||
[HarmonyPatch(typeof(Pawn_MechanitorTracker))]
|
||||
[HarmonyPatch(nameof(Pawn_MechanitorTracker.CanCommandTo))]
|
||||
class
|
||||
Pawn_MechanitorTracker_CanCommandTo_Patch //increases the mechanitor's range by MechRemoteControlDistanceOffset
|
||||
{
|
||||
/// <summary>
|
||||
/// pushed always commandable check to front to reduct compute.
|
||||
/// TODO perhaps need a custom patch order to make sure this logic always works.
|
||||
/// </summary>
|
||||
/// <param name="target">target mech to command</param>
|
||||
/// <param name="__instance">should be mechanitor, but not always the mechanitor for example like Dead man switch ctrl mechs </param>
|
||||
/// <param name="__result">Commandable result from original code.</param>
|
||||
[HarmonyPostfix]
|
||||
public static void CanCommandToPostfix(LocalTargetInfo target, Pawn_MechanitorTracker __instance,
|
||||
ref bool __result)
|
||||
{
|
||||
if (__result)
|
||||
return;
|
||||
float SignalBoosterRange =
|
||||
__instance.Pawn?.GetStatValue(StatDef.Named("MechRemoteControlDistanceOffset")) ?? 0f;
|
||||
__result = target.Cell.InBounds(__instance.Pawn.MapHeld) &&
|
||||
(float)__instance.Pawn.Position.DistanceToSquared(target.Cell) <
|
||||
(24.9f + SignalBoosterRange) *
|
||||
(24.9f +
|
||||
SignalBoosterRange); //last line should mean that if something else makes it true, then it is(?)
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(Pawn_MechanitorTracker))]
|
||||
[HarmonyPatch(nameof(Pawn_MechanitorTracker.DrawCommandRadius))]
|
||||
class
|
||||
Pawn_MechanitorTracker_DrawCommandRadius_Patch //increases the displayed mechanitor range by MechRemoteControlDistanceOffset
|
||||
{
|
||||
/// <summary>
|
||||
/// Skip original draw radius using a prefix.
|
||||
/// TODO may need specify fixed patch order to make sure this works.
|
||||
/// </summary>
|
||||
/// <returns>return false to skip original draw.</returns>
|
||||
[HarmonyPrefix]
|
||||
static bool DrawCommandRadiusPrefix()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Postfix the draw radius by apply our extended radius on top.
|
||||
/// </summary>
|
||||
/// <param name="__instance"></param>
|
||||
[HarmonyPostfix]
|
||||
public static void DrawCommandRadiusPostfix(Pawn_MechanitorTracker __instance)
|
||||
{
|
||||
if (__instance.Pawn.Spawned && __instance.AnySelectedDraftedMechs)
|
||||
{
|
||||
//GenDraw.DrawRadiusRing(___pawn.Position, 24.9f + (3f*___pawn.health?.hediffSet?.GetFirstHediffOfDef(HediffDef.Named("SignalBoosterImplant"))?.Severity ?? 0f), Color.white, (IntVec3 c) => __instance.CanCommandTo(c));
|
||||
if (!ModsConfig.IsActive("swwu.MechanitorCommandRange") &&
|
||||
!ModsConfig.IsActive(
|
||||
"Neronix17.TweaksGalore")) //for tweaks galore, it'd be better to try to find the setting specifically, with an inverted result and a null check true
|
||||
{
|
||||
IntVec3 position = __instance.Pawn.Position;
|
||||
float radius = 24.9f +
|
||||
(__instance.Pawn?.GetStatValue(
|
||||
StatDef.Named("MechRemoteControlDistanceOffset")) ?? 0f);
|
||||
//Make our command circle yellow. And make sure this postfix implemented draw follows vanilla impl.
|
||||
GenDraw.DrawRadiusRing(position, radius, Color.yellow,
|
||||
(IntVec3 c) => __instance.CanCommandTo((LocalTargetInfo)c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resurrect
|
||||
|
||||
public class CompProperties_MechanitorResurrectMech : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_MechanitorResurrectMech()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_MechanitorResurrectMech);
|
||||
}
|
||||
|
||||
public int maxCorpseAgeTicks = int.MaxValue;
|
||||
|
||||
public EffecterDef appliedEffecterDef;
|
||||
|
||||
public EffecterDef resolveEffecterDef;
|
||||
|
||||
//public EffecterDef centerEffecterDef;
|
||||
}
|
||||
|
||||
public class CompAbilityEffect_MechanitorResurrectMech : CompAbilityEffect
|
||||
{
|
||||
public new CompProperties_MechanitorResurrectMech Props
|
||||
{
|
||||
get { return (CompProperties_MechanitorResurrectMech)this.props; }
|
||||
}
|
||||
|
||||
public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
Corpse corpse;
|
||||
bool bandwidthCheck = (target.Thing as Corpse).InnerPawn.GetStatValue(StatDef.Named("BandwidthCost")) <=
|
||||
this.parent.pawn.mechanitor.TotalBandwidth -
|
||||
this.parent.pawn.mechanitor.UsedBandwidth;
|
||||
bool canApplyOnCheck = (base.CanApplyOn(target, dest) && target.HasThing &&
|
||||
(corpse = target.Thing as Corpse) != null && this.CanResurrect(corpse) &&
|
||||
bandwidthCheck);
|
||||
//Log.Message("CanApplyOn check: " + canApplyOnCheck);
|
||||
|
||||
|
||||
if ((target.Thing as Corpse).InnerPawn.Faction != this.parent.pawn.Faction)
|
||||
{
|
||||
Messages.Message("Can only resurrect allied mechs", (target.Thing as Pawn),
|
||||
MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
else if ((target.Thing as Corpse).timeOfDeath <=
|
||||
Find.TickManager.TicksGame - this.Props.maxCorpseAgeTicks)
|
||||
{
|
||||
Messages.Message("Target has been dead too long", (target.Thing as Pawn),
|
||||
MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
else if (!bandwidthCheck)
|
||||
{
|
||||
Messages.Message("Insufficient bandwidth", (target.Thing as Pawn), MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
|
||||
|
||||
return canApplyOnCheck;
|
||||
}
|
||||
|
||||
|
||||
private bool CanResurrect(Corpse corpse)
|
||||
{
|
||||
//return corpse.InnerPawn.RaceProps.IsMechanoid && corpse.InnerPawn.RaceProps.mechWeightClass < MechWeightClass.UltraHeavy && corpse.InnerPawn.Faction == this.parent.pawn.Faction && (corpse.InnerPawn.kindDef.abilities == null || !corpse.InnerPawn.kindDef.abilities.Contains(AbilityDefOf.ResurrectionMech)) && corpse.timeOfDeath >= Find.TickManager.TicksGame - this.Props.maxCorpseAgeTicks;
|
||||
return corpse.InnerPawn.RaceProps.IsMechanoid && corpse.InnerPawn.Faction == this.parent.pawn.Faction &&
|
||||
(corpse.InnerPawn.kindDef.abilities == null ||
|
||||
!corpse.InnerPawn.kindDef.abilities.Contains(AbilityDefOf.ResurrectionMech)) &&
|
||||
corpse.timeOfDeath >= Find.TickManager.TicksGame - this.Props.maxCorpseAgeTicks;
|
||||
}
|
||||
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
//Log.Message("Apply called");
|
||||
base.Apply(target, dest);
|
||||
Corpse corpse = (Corpse)target.Thing;
|
||||
if (!this.CanResurrect(corpse))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Pawn innerPawn = corpse.InnerPawn;
|
||||
ResurrectionUtility.TryResurrect(innerPawn, null);
|
||||
if (this.Props.appliedEffecterDef != null)
|
||||
{
|
||||
Effecter effecter = this.Props.appliedEffecterDef.SpawnAttached(innerPawn, innerPawn.MapHeld, 1f);
|
||||
effecter.Trigger(innerPawn, innerPawn, -1);
|
||||
effecter.Cleanup();
|
||||
this.parent.pawn.relations.AddDirectRelation(PawnRelationDefOf.Overseer,
|
||||
innerPawn); //if resurrection successful, immediately takes control of resurrected mech.
|
||||
}
|
||||
|
||||
innerPawn.stances.stagger.StaggerFor(60, 0.17f);
|
||||
}
|
||||
|
||||
public override bool GizmoDisabled(out string reason)
|
||||
{
|
||||
reason = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override IEnumerable<Mote> CustomWarmupMotes(LocalTargetInfo target)
|
||||
{
|
||||
foreach (LocalTargetInfo localTargetInfo in this.parent.GetAffectedTargets(target))
|
||||
{
|
||||
Thing thing = localTargetInfo.Thing;
|
||||
yield return MoteMaker.MakeAttachedOverlay(thing, ThingDefOf.Mote_MechResurrectWarmupOnTarget,
|
||||
Vector3.zero, 1f, -1f);
|
||||
}
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
public override void PostApplied(List<LocalTargetInfo> targets, Map map)
|
||||
{
|
||||
//Log.Message("PostApplied called");
|
||||
Vector3 vector = Vector3.zero;
|
||||
foreach (LocalTargetInfo localTargetInfo in targets)
|
||||
{
|
||||
vector += localTargetInfo.Cell.ToVector3Shifted();
|
||||
}
|
||||
|
||||
vector /= (float)targets.Count<LocalTargetInfo>();
|
||||
IntVec3 intVec = vector.ToIntVec3();
|
||||
this.Props.resolveEffecterDef.Spawn(intVec, map, 1f).EffectTick(new TargetInfo(intVec, map, false),
|
||||
new TargetInfo(intVec, map, false));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Remote Dominate
|
||||
|
||||
public class CompProperties_MechanitorDominateMech : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_MechanitorDominateMech()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_MechanitorDominateMech);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompAbilityEffect_MechanitorDominateMech : CompAbilityEffect
|
||||
{
|
||||
public new CompProperties_MechanitorDominateMech Props
|
||||
{
|
||||
get { return (CompProperties_MechanitorDominateMech)this.props; }
|
||||
}
|
||||
|
||||
public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
Pawn pawn;
|
||||
|
||||
bool bandwidthCheck = (target.Thing as Pawn).GetStatValue(StatDef.Named("BandwidthCost")) <=
|
||||
this.parent.pawn.mechanitor.TotalBandwidth -
|
||||
this.parent.pawn.mechanitor.UsedBandwidth;
|
||||
bool notTempMech = target.Thing.TryGetComp<CompMechPowerCell>() == null;
|
||||
bool canApplyOnCheck = (base.CanApplyOn(target, dest) && target.HasThing &&
|
||||
(pawn = target.Thing as Pawn) != null && bandwidthCheck &&
|
||||
this.CanDominate(pawn) && notTempMech);
|
||||
|
||||
|
||||
if (!notTempMech)
|
||||
{
|
||||
Messages.Message("Cannot target temporary mech", (target.Thing as Pawn),
|
||||
MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
else if ((target.Thing as Pawn).RaceProps.mechWeightClass >= MechWeightClass.UltraHeavy)
|
||||
{
|
||||
Messages.Message("Cannot target superheavy mech", (target.Thing as Pawn),
|
||||
MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
else if (!bandwidthCheck)
|
||||
{
|
||||
Messages.Message("Insufficient bandwidth", (target.Thing as Pawn), MessageTypeDefOf.NegativeEvent);
|
||||
}
|
||||
|
||||
return canApplyOnCheck;
|
||||
}
|
||||
|
||||
|
||||
private bool CanDominate(Pawn pawn)
|
||||
{
|
||||
return pawn.RaceProps.IsMechanoid && pawn.RaceProps.mechWeightClass < MechWeightClass.UltraHeavy &&
|
||||
(pawn.kindDef.abilities == null ||
|
||||
!pawn.kindDef.abilities.Contains(AbilityDefOf.ResurrectionMech));
|
||||
}
|
||||
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
//Log.Message("Apply called");
|
||||
base.Apply(target, dest);
|
||||
Pawn pawn = (Pawn)target;
|
||||
if (!this.CanDominate(pawn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
pawn.SetFaction(this.parent.pawn.Faction); //convert pawn
|
||||
|
||||
this.parent.pawn.relations.AddDirectRelation(PawnRelationDefOf.Overseer, pawn);
|
||||
pawn.stances.stagger.StaggerFor(60, 0.17f);
|
||||
}
|
||||
|
||||
public override bool GizmoDisabled(out string reason)
|
||||
{
|
||||
reason = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
//public override IEnumerable<Mote> CustomWarmupMotes(LocalTargetInfo target)
|
||||
//{
|
||||
// foreach (LocalTargetInfo localTargetInfo in this.parent.GetAffectedTargets(target))
|
||||
// {
|
||||
// Thing thing = localTargetInfo.Thing;
|
||||
// yield return MoteMaker.MakeAttachedOverlay(thing, ThingDefOf.Mote_MechResurrectWarmupOnTarget, Vector3.zero, 1f, -1f);
|
||||
// }
|
||||
// IEnumerator<LocalTargetInfo> enumerator = null;
|
||||
// yield break;
|
||||
// yield break;
|
||||
//}
|
||||
|
||||
public override void PostApplied(List<LocalTargetInfo> targets, Map map)
|
||||
{
|
||||
//Log.Message("PostApplied called");
|
||||
//Vector3 vector = Vector3.zero;
|
||||
//foreach (LocalTargetInfo localTargetInfo in targets)
|
||||
//{
|
||||
// vector += localTargetInfo.Cell.ToVector3Shifted();
|
||||
//}
|
||||
//vector /= (float)targets.Count<LocalTargetInfo>();
|
||||
//IntVec3 intVec = vector.ToIntVec3();
|
||||
//this.Props.resolveEffecterDef.Spawn(intVec, map, 1f).EffectTick(new TargetInfo(intVec, map, false), new TargetInfo(intVec, map, false));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mech carrier
|
||||
|
||||
public class CompProperties_MechanitorMechCarrier : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_MechanitorMechCarrier()
|
||||
{
|
||||
this.compClass = typeof(CompAbilityEffect_MechanitorMechCarrier);
|
||||
}
|
||||
|
||||
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 override void CompTick()
|
||||
{
|
||||
base.CompTick();
|
||||
//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());
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
TrySpawnPawns();
|
||||
}
|
||||
|
||||
public int maxspawn()
|
||||
{
|
||||
//Log.Message("RemainingCharges: " + parent.RemainingCharges+1);
|
||||
int max = parent.RemainingCharges +
|
||||
1; //requires +1 to account for the charge that's automatically used upon ability activation, prior to this.
|
||||
if (max > 2)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
||||
public void TrySpawnPawns()
|
||||
{
|
||||
int maxCanSpawn = maxspawn();
|
||||
//Log.Message("max spawns: "+ maxCanSpawn);
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
if (maxCanSpawn == 2) //subtract an extra charge, as we're summoning 2
|
||||
{
|
||||
parent.RemainingCharges--;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Pawn> GetSpawnedPawns()
|
||||
{
|
||||
return spawnedPawns;
|
||||
}
|
||||
|
||||
private int cooldownTicksRemaining;
|
||||
private List<Pawn> spawnedPawns = new List<Pawn>();
|
||||
public SoundDef soundReload;
|
||||
}
|
||||
|
||||
public class HediffCompProperties_KillSpawnedPawns : HediffCompProperties
|
||||
{
|
||||
public AbilityDef abilityDef;
|
||||
|
||||
public HediffCompProperties_KillSpawnedPawns()
|
||||
{
|
||||
compClass = typeof(HediffComp_KillSpawnedPawns);
|
||||
}
|
||||
}
|
||||
|
||||
public class HediffComp_KillSpawnedPawns : HediffComp
|
||||
{
|
||||
public HediffCompProperties_KillSpawnedPawns Props => (HediffCompProperties_KillSpawnedPawns)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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Call a cluster
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
88
1.5/Assemblies/Implants/CaptiveControl.cs
Normal file
88
1.5/Assemblies/Implants/CaptiveControl.cs
Normal file
@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using Verse.Sound;
|
||||
|
||||
namespace Implants
|
||||
{
|
||||
|
||||
public class LTS_CompProperties_CaptiveControl : CompProperties_AbilityEffect
|
||||
{
|
||||
public LTS_CompProperties_CaptiveControl()
|
||||
{
|
||||
this.compClass = typeof(LTS_CompAbilityEffect_CaptiveControl);
|
||||
}
|
||||
public HediffDef hediffDef;
|
||||
public float StartSeverity;
|
||||
public string location = null;
|
||||
public int duration = 3600; // 1 hour
|
||||
public bool headExploder = false;
|
||||
public bool hediffToggle = false;
|
||||
}
|
||||
|
||||
public class LTS_CompAbilityEffect_CaptiveControl : CompAbilityEffect
|
||||
{
|
||||
public new LTS_CompProperties_CaptiveControl Props
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LTS_CompProperties_CaptiveControl)this.props;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
|
||||
if (target.Pawn != null)
|
||||
{
|
||||
if (Props.headExploder)
|
||||
{
|
||||
if (EffecterDefOf.MeatExplosion != null)
|
||||
{
|
||||
EffecterDefOf.MeatExplosion.Spawn(parent.pawn.PositionHeld, parent.pawn.MapHeld).Cleanup();
|
||||
}
|
||||
SoundDefOf.CocoonDestroyed.PlayOneShot(new TargetInfo(target.Pawn.Position, target.Pawn.Map));
|
||||
target.Pawn.TakeDamage(new DamageInfo(DamageDefOf.Crush, 100, 0, -1, null, target.Pawn.health.hediffSet.GetBodyPartRecord(BodyPartDefOf.Head)));
|
||||
//target.Pawn.TakeDamage(new DamageInfo(DamageDefOf.Bomb, 100, 0, -1, null, target.Pawn.health.hediffSet.GetBodyPartRecord(BodyPartDefOf.Head)));
|
||||
}
|
||||
else if (Props.hediffToggle)
|
||||
{
|
||||
if (target.Pawn.health?.hediffSet?.GetFirstHediffOfDef(this.Props.hediffDef) != null)
|
||||
{
|
||||
target.Pawn.health.RemoveHediff(target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.hediffDef));
|
||||
}
|
||||
else
|
||||
{
|
||||
target.Pawn.health.AddHediff(this.Props.hediffDef, location(target));
|
||||
if (target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.hediffDef).TryGetComp<HediffComp_Lactating>() != null)
|
||||
{
|
||||
target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.hediffDef).TryGetComp<HediffComp_Lactating>().TryCharge(-0.124f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
target.Pawn.health.AddHediff(this.Props.hediffDef, location(target));
|
||||
if (target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.hediffDef).TryGetComp<HediffComp_Disappears>() != null)
|
||||
{
|
||||
target.Pawn.health.hediffSet.GetFirstHediffOfDef(this.Props.hediffDef).TryGetComp<HediffComp_Disappears>().ticksToDisappear = Props.duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.defName == Props.location).ToList()[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,68 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A5BB73F5-2B73-4464-9585-5553F3695021}</ProjectGuid>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Implants</RootNamespace>
|
||||
<AssemblyName>Implants</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AssemblyTitle>Implants</AssemblyTitle>
|
||||
<Product>Implants</Product>
|
||||
<Copyright>Copyright © 2024</Copyright>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
|
||||
<DocumentationFile>..\Implants.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="0Harmony, Version=2.3.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>packages\Lib.Harmony.2.3.3\lib\net472\0Harmony.dll</HintPath>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Lib.Harmony" Version="2.3.3">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Assembly-CSharp">
|
||||
<HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\..\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="UnityEngine">
|
||||
<HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\..\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>..\..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<HintPath>..\..\..\..\..\..\..\SteamLibrary\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="LTS_Implants.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
File diff suppressed because it is too large
Load Diff
51
1.5/Assemblies/Implants/PatchBootStrap.cs
Normal file
51
1.5/Assemblies/Implants/PatchBootStrap.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using Verse;
|
||||
|
||||
namespace LTS_Implants
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public static class HarmonyPatches
|
||||
{
|
||||
public static bool IsCombatExtended = false;
|
||||
static HarmonyPatches()
|
||||
{
|
||||
Harmony harmony = new Harmony("rimworld.LTS.implants");
|
||||
Harmony.DEBUG = false;
|
||||
//Check if we are in a CE enabled env
|
||||
if(ModLister.GetModWithIdentifier("ceteam.combatextended")!=null)
|
||||
IsCombatExtended = true;
|
||||
if (ModLister.BiotechInstalled)
|
||||
{
|
||||
Verse.Log.Message("[LTS Intrgated Implants Forked]Biotech found, harmony patch running");
|
||||
harmony.PatchCategory("Biotech");
|
||||
}
|
||||
|
||||
harmony.PatchAllUncategorized(Assembly.GetExecutingAssembly());
|
||||
#if DEBUG
|
||||
foreach (var method in harmony.GetPatchedMethods())
|
||||
{
|
||||
Verse.Log.Message($"[LTS Implants]Patched Method {method.Name}");
|
||||
var patchinfo = Harmony.GetPatchInfo(method);
|
||||
foreach (var VARIABLE in patchinfo.Owners)
|
||||
{
|
||||
Verse.Log.Message("The Method has been patched by:" + VARIABLE);
|
||||
}
|
||||
foreach (var VARIABLE in patchinfo.Prefixes)
|
||||
{
|
||||
Verse.Log.Message("has Prefix:" + VARIABLE.PatchMethod);
|
||||
}
|
||||
foreach (var VARIABLE in patchinfo.Postfixes)
|
||||
{
|
||||
Verse.Log.Message("has Postfix:" + VARIABLE.PatchMethod);
|
||||
}
|
||||
foreach (var VARIABLE in patchinfo.Transpilers)
|
||||
{
|
||||
Verse.Log.Message("has Transpiler:" + VARIABLE.PatchMethod);
|
||||
}
|
||||
Verse.Log.Message("Displaying next method");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Implants")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Implants")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2024")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@ -21,16 +11,3 @@ using System.Runtime.InteropServices;
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a5bb73f5-2b73-4464-9585-5553f3695021")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Lib.Harmony" version="2.3.3" targetFramework="net472" />
|
||||
</packages>
|
Loading…
Reference in New Issue
Block a user