diff --git a/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/Assemblies/WulaFallenEmpire.dll index 23dcb6dc..a6de9b87 100644 Binary files a/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/Defs/ThingDefs_Misc/WULA_Apparel.xml b/1.6/Defs/ThingDefs_Misc/WULA_Apparel.xml index 631c6d3f..8f3f41d6 100644 --- a/1.6/Defs/ThingDefs_Misc/WULA_Apparel.xml +++ b/1.6/Defs/ThingDefs_Misc/WULA_Apparel.xml @@ -479,13 +479,31 @@ -
  • - 3600 - 2.5 - 2.8 - 0.01 - 4.0 - false +
  • + + + 2.5 + 500 + 2800 + + + true + false + true + + + (0.9, 0.8, 0.2, 0.5) + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + + false + 600 + + + 60 +
  • @@ -533,13 +551,31 @@
  • RewardStandardHighFreq
  • -
  • - 3600 - 2.5 - 2.8 - 0.01 - 4.0 - false +
  • + + + 2.5 + 500 + 2800 + + + true + false + false + + + (0.9, 0.8, 0.2, 0.5) + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + + false + 600 + + + 60 +
  • @@ -904,13 +940,31 @@ 炮弹 false -
  • - 3600 - 2.5 - 2.8 - 0.01 - 4.0 - false +
  • + + + 2.5 + 500 + 2800 + + + true + false + false + + + (0.9, 0.8, 0.2, 0.5) + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + + false + 600 + + + 60 +
  • @@ -1039,13 +1093,31 @@ 炮弹 false -
  • - 3600 - 2.5 - 2.8 - 0.01 - 4.0 - false +
  • + + + 2.5 + 500 + 2800 + + + true + false + false + + + (0.9, 0.8, 0.2, 0.5) + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + + false + 600 + + + 60 +
  • WULA_Heavy_Infantry_PowerArmor_PowerFist @@ -1290,13 +1362,31 @@ 梭镖 false
  • -
  • - 3600 - 2.5 - 2.8 - 0.01 - 4.0 - false +
  • + + + 2.5 + 500 + 2800 + + + true + false + false + + + (0.9, 0.8, 0.2, 0.5) + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + + false + 600 + + + 60 +
  • @@ -1345,4 +1435,4 @@ 275 - \ No newline at end of file + diff --git a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo index f4e6a586..d3416850 100644 Binary files a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo and b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/.suo differ diff --git a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json index 225913d5..1d9714bd 100644 --- a/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json +++ b/Source/WulaFallenEmpire/.vs/WulaFallenEmpire/v17/DocumentLayout.json @@ -3,20 +3,28 @@ "WorkspaceRootPath": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\compapparelinterceptor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:compapparelinterceptor.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\harmonypatches\\projectile_launch_patch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:harmonypatches\\projectile_launch_patch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\compuseeffect_wulaskilltrainer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:compuseeffect_wulaskilltrainer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|c:\\steam\\steamapps\\common\\rimworld\\mods\\3516260226\\source\\wulafallenempire\\ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:ingestpatch.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\building_wula_darkenergy_engine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:building_wula_darkenergy_engine.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\compuseeffect_wulaskilltrainer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:compuseeffect_wulaskilltrainer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|solutionrelative:hediffcomp_regeneratebackstory.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { "AbsoluteMoniker": "D:0:0:{F5AE8C3B-0221-4C16-A128-9A62D521A8FF}|WulaFallenEmpire.csproj|C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\wulafallenempiremod.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", @@ -34,15 +42,41 @@ "DocumentGroups": [ { "DockedWidth": 200, - "SelectedChildIndex": 1, + "SelectedChildIndex": 2, "Children": [ { "$type": "Bookmark", "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" }, + { + "$type": "Document", + "DocumentIndex": 1, + "Title": "Projectile_Launch_Patch.cs", + "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\HarmonyPatches\\Projectile_Launch_Patch.cs", + "RelativeDocumentMoniker": "HarmonyPatches\\Projectile_Launch_Patch.cs", + "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\HarmonyPatches\\Projectile_Launch_Patch.cs", + "RelativeToolTip": "HarmonyPatches\\Projectile_Launch_Patch.cs", + "ViewState": "AQIAAAAAAAAAAAAAAAAAABwAAAAAAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2025-07-23T10:23:38.948Z", + "EditorCaption": "" + }, { "$type": "Document", "DocumentIndex": 0, + "Title": "CompApparelInterceptor.cs", + "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\CompApparelInterceptor.cs", + "RelativeDocumentMoniker": "CompApparelInterceptor.cs", + "ToolTip": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\CompApparelInterceptor.cs", + "RelativeToolTip": "CompApparelInterceptor.cs", + "ViewState": "AQIAABoAAAAAAAAAAADwv2UBAAABAAAA", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2025-07-23T10:03:31.989Z", + "EditorCaption": "" + }, + { + "$type": "Document", + "DocumentIndex": 3, "Title": "IngestPatch.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\IngestPatch.cs", "RelativeDocumentMoniker": "IngestPatch.cs", @@ -55,7 +89,7 @@ }, { "$type": "Document", - "DocumentIndex": 3, + "DocumentIndex": 2, "Title": "CompUseEffect_WulaSkillTrainer.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\CompUseEffect_WulaSkillTrainer.cs", "RelativeDocumentMoniker": "CompUseEffect_WulaSkillTrainer.cs", @@ -63,11 +97,12 @@ "RelativeToolTip": "CompUseEffect_WulaSkillTrainer.cs", "ViewState": "AQIAAEAAAAAAAAAAAAAUwFMAAAABAAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-07-22T07:52:56.407Z" + "WhenOpened": "2025-07-22T07:52:56.407Z", + "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 2, + "DocumentIndex": 4, "Title": "Building_Wula_DarkEnergy_Engine.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\Building_Wula_DarkEnergy_Engine.cs", "RelativeDocumentMoniker": "Building_Wula_DarkEnergy_Engine.cs", @@ -79,7 +114,7 @@ }, { "$type": "Document", - "DocumentIndex": 1, + "DocumentIndex": 5, "Title": "HediffComp_RegenerateBackstory.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\HediffComp_RegenerateBackstory.cs", "RelativeDocumentMoniker": "HediffComp_RegenerateBackstory.cs", @@ -91,7 +126,7 @@ }, { "$type": "Document", - "DocumentIndex": 4, + "DocumentIndex": 6, "Title": "WulaFallenEmpireMod.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\WulaFallenEmpireMod.cs", "RelativeDocumentMoniker": "WulaFallenEmpireMod.cs", @@ -101,13 +136,9 @@ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-07-18T10:23:17.898Z" }, - { - "$type": "Bookmark", - "Name": "ST:0:0:{269a02dc-6af8-11d3-bdc4-00c04f688e50}" - }, { "$type": "Document", - "DocumentIndex": 5, + "DocumentIndex": 7, "Title": "MechanitorPatch.cs", "DocumentMoniker": "C:\\Steam\\steamapps\\common\\RimWorld\\Mods\\3516260226\\Source\\WulaFallenEmpire\\MechanitorPatch.cs", "RelativeDocumentMoniker": "MechanitorPatch.cs", @@ -116,6 +147,10 @@ "ViewState": "AQIAAAAAAAAAAAAAAAAAACEAAAAJAAAA", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-07-18T10:20:31.368Z" + }, + { + "$type": "Bookmark", + "Name": "ST:0:0:{269a02dc-6af8-11d3-bdc4-00c04f688e50}" } ] } diff --git a/Source/WulaFallenEmpire/CompApparelInterceptor.cs b/Source/WulaFallenEmpire/CompApparelInterceptor.cs new file mode 100644 index 00000000..c4395323 --- /dev/null +++ b/Source/WulaFallenEmpire/CompApparelInterceptor.cs @@ -0,0 +1,358 @@ +using HarmonyLib; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; +using Verse; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class CompProperties_ApparelInterceptor : CompProperties + { + public float radius = 3f; + public int startupDelay = 0; + public int rechargeDelay = 3200; + public int hitPoints = 100; + + public bool interceptGroundProjectiles = false; + public bool interceptNonHostileProjectiles = false; + public bool interceptAirProjectiles = true; + + public SoundDef soundIntercept; + public SoundDef soundBreak; + public EffecterDef reactivateEffect; + + public Color color = new Color(0.5f, 0.5f, 0.9f); + public bool drawWithNoSelection = true; + public bool isImmuneToEMP = false; + + public int cooldownTicks = 0; + public int chargeDurationTicks = 0; + public int chargeIntervalTicks = 0; + public bool startWithMaxHitPoints = true; + public bool hitPointsRestoreInstantlyAfterCharge = true; + public int rechargeHitPointsIntervalTicks = 60; + public bool activated = false; + public int activeDuration = 0; + public SoundDef activeSound; + public bool alwaysShowHitpointsGizmo = false; + public float minAlpha = 0f; + public float idlePulseSpeed = 0.02f; + public float minIdleAlpha = 0.05f; + public int disarmedByEmpForTicks = 0; + + public CompProperties_ApparelInterceptor() + { + compClass = typeof(CompApparelInterceptor); + } + } + + [StaticConstructorOnStartup] + public class CompApparelInterceptor : ThingComp + { + // ״̬ + private int lastInterceptTicks = -999999; + private int startedChargingTick = -1; + private bool shutDown; + private StunHandler stunner; + private Sustainer sustainer; + public int currentHitPoints = -1; + private int ticksToReset; + private int activatedTick = -999999; + + // ӾЧ + private float lastInterceptAngle; + private bool drawInterceptCone; + + // ̬Դ + private static readonly Material ForceFieldMat = MaterialPool.MatFrom("Other/ForceField", ShaderDatabase.MoteGlow); + private static readonly Material ForceFieldConeMat = MaterialPool.MatFrom("Other/ForceFieldCone", ShaderDatabase.MoteGlow); + private static readonly MaterialPropertyBlock MatPropertyBlock = new MaterialPropertyBlock(); + private static readonly Color InactiveColor = new Color(0.2f, 0.2f, 0.2f); + + // + public CompProperties_ApparelInterceptor Props => (CompProperties_ApparelInterceptor)props; + private Pawn PawnOwner => (parent as Apparel)?.Wearer; + + public bool Active + { + get + { + if (PawnOwner == null || !PawnOwner.Spawned) return false; + if (OnCooldown || Charging || stunner.Stunned || shutDown || currentHitPoints <= 0) return false; + if (Props.activated && Find.TickManager.TicksGame > activatedTick + Props.activeDuration) return false; + return true; + } + } + + protected bool ShouldDisplay + { + get + { + if (PawnOwner == null || !PawnOwner.Spawned || PawnOwner.Dead || PawnOwner.Downed || !Active) + { + return false; + } + if (PawnOwner.Drafted || PawnOwner.InAggroMentalState || (PawnOwner.Faction != null && PawnOwner.Faction.HostileTo(Faction.OfPlayer) && !PawnOwner.IsPrisoner)) + { + return true; + } + if (Find.Selector.IsSelected(PawnOwner)) + { + return true; + } + return false; + } + } + + public bool OnCooldown => ticksToReset > 0; + public bool Charging => startedChargingTick >= 0 && Find.TickManager.TicksGame < startedChargingTick + Props.startupDelay; + public int CooldownTicksLeft => ticksToReset; + public int ChargingTicksLeft => (startedChargingTick < 0) ? 0 : Mathf.Max(startedChargingTick + Props.startupDelay - Find.TickManager.TicksGame, 0); + public int HitPointsMax => Props.hitPoints; + protected virtual int HitPointsPerInterval => 1; + + public override void PostPostMake() + { + base.PostPostMake(); + stunner = new StunHandler(parent); + if (Props.startupDelay > 0) + { + startedChargingTick = Find.TickManager.TicksGame; + currentHitPoints = 0; + } + else + { + currentHitPoints = HitPointsMax; + } + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref lastInterceptTicks, "lastInterceptTicks", -999999); + Scribe_Values.Look(ref shutDown, "shutDown", defaultValue: false); + Scribe_Values.Look(ref startedChargingTick, "startedChargingTick", -1); + Scribe_Values.Look(ref currentHitPoints, "currentHitPoints", -1); + Scribe_Values.Look(ref ticksToReset, "ticksToReset", 0); + Scribe_Values.Look(ref activatedTick, "activatedTick", -999999); + Scribe_Deep.Look(ref stunner, "stunner", parent); + + if (Scribe.mode == LoadSaveMode.PostLoadInit) + { + if (stunner == null) stunner = new StunHandler(parent); + if (currentHitPoints == -1) currentHitPoints = HitPointsMax; + } + } + + public bool TryIntercept(Projectile projectile, Vector3 lastExactPos, Vector3 newExactPos) + { + if (PawnOwner == null || !PawnOwner.Spawned || !Active) + { + return false; + } + + if (!GenGeo.IntersectLineCircleOutline(PawnOwner.Position.ToVector2(), Props.radius, lastExactPos.ToVector2(), newExactPos.ToVector2())) + { + return false; + } + + if (!InterceptsProjectile(Props, projectile)) + { + return false; + } + + bool isHostile = (projectile.Launcher != null && projectile.Launcher.HostileTo(PawnOwner)) || (projectile.Launcher == null && Props.interceptNonHostileProjectiles); + if (!isHostile) + { + return false; + } + + // --- Interception Success --- + lastInterceptAngle = projectile.ExactPosition.AngleToFlat(PawnOwner.TrueCenter()); + lastInterceptTicks = Find.TickManager.TicksGame; + drawInterceptCone = true; + if (Props.soundIntercept != null) Props.soundIntercept.PlayOneShot(new TargetInfo(PawnOwner.Position, PawnOwner.Map)); + EffecterDefOf.Interceptor_BlockedProjectile.Spawn(PawnOwner.Position, PawnOwner.Map); + + if (projectile.DamageDef == DamageDefOf.EMP && !Props.isImmuneToEMP) + { + BreakShieldEmp(new DamageInfo(projectile.DamageDef, projectile.DamageAmount, instigator: projectile.Launcher)); + } + else if (HitPointsMax > 0) + { + currentHitPoints -= projectile.DamageAmount; + if (currentHitPoints <= 0) + { + BreakShieldHitpoints(new DamageInfo(projectile.DamageDef, projectile.DamageAmount, instigator: projectile.Launcher)); + } + } + return true; + } + + public override void CompTick() + { + base.CompTick(); + if (PawnOwner == null || !PawnOwner.Spawned) return; + + stunner.StunHandlerTick(); + + if (OnCooldown) + { + ticksToReset--; + if (ticksToReset <= 0) Reset(); + } + else if (Charging) + { + // Charging logic handled by property + } + else if (currentHitPoints < HitPointsMax && parent.IsHashIntervalTick(Props.rechargeHitPointsIntervalTicks)) + { + currentHitPoints = Mathf.Clamp(currentHitPoints + HitPointsPerInterval, 0, HitPointsMax); + } + + if (Props.activeSound != null) + { + if (Active && (sustainer == null || sustainer.Ended)) sustainer = Props.activeSound.TrySpawnSustainer(SoundInfo.InMap(parent)); + sustainer?.Maintain(); + if (!Active && sustainer != null && !sustainer.Ended) sustainer.End(); + } + } + + public void Reset() + { + if (PawnOwner.Spawned) Props.reactivateEffect?.Spawn(PawnOwner.Position, PawnOwner.Map).Cleanup(); + currentHitPoints = HitPointsMax; + ticksToReset = 0; + } + + private void BreakShieldHitpoints(DamageInfo dinfo) + { + if (PawnOwner.Spawned) + { + if (Props.soundBreak != null) Props.soundBreak.PlayOneShot(new TargetInfo(PawnOwner.Position, PawnOwner.Map)); + EffecterDefOf.Shield_Break.SpawnAttached(PawnOwner, PawnOwner.MapHeld, Props.radius); + } + currentHitPoints = 0; + ticksToReset = Props.rechargeDelay; + } + + private void BreakShieldEmp(DamageInfo dinfo) + { + BreakShieldHitpoints(dinfo); + if (Props.disarmedByEmpForTicks > 0) stunner.Notify_DamageApplied(new DamageInfo(DamageDefOf.EMP, (float)Props.disarmedByEmpForTicks / 30f)); + } + + public static bool InterceptsProjectile(CompProperties_ApparelInterceptor props, Projectile projectile) + { + if (projectile.def.projectile.flyOverhead) return props.interceptAirProjectiles; + return props.interceptGroundProjectiles; + } + + // --- DRAWING LOGIC --- + public override void CompDrawWornExtras() + { + base.CompDrawWornExtras(); + if (PawnOwner == null || !PawnOwner.Spawned || !ShouldDisplay) return; + + Vector3 drawPos = PawnOwner.Drawer.DrawPos; + drawPos.y = AltitudeLayer.MoteOverhead.AltitudeFor(); + + float alpha = GetCurrentAlpha(); + if (alpha > 0f) + { + Color color = Props.color; + color.a *= alpha; + MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); + Matrix4x4 matrix = default(Matrix4x4); + matrix.SetTRS(drawPos, Quaternion.identity, new Vector3(Props.radius * 2f * 1.1601562f, 1f, Props.radius * 2f * 1.1601562f)); + Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldMat, 0, null, 0, MatPropertyBlock); + } + + float coneAlpha = GetCurrentConeAlpha_RecentlyIntercepted(); + if (coneAlpha > 0f) + { + Color color = Props.color; + color.a *= coneAlpha; + MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); + Matrix4x4 matrix = default(Matrix4x4); + matrix.SetTRS(drawPos, Quaternion.Euler(0f, lastInterceptAngle - 90f, 0f), new Vector3(Props.radius * 2f, 1f, Props.radius * 2f)); + Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldConeMat, 0, null, 0, MatPropertyBlock); + } + } + + private float GetCurrentAlpha() + { + float idleAlpha = Mathf.Lerp(0.3f, 0.6f, (Mathf.Sin((float)Gen.HashCombineInt(parent.thingIDNumber, 35990913) + Time.realtimeSinceStartup * 2f) + 1f) / 2f); + float interceptAlpha = Mathf.Clamp01(1f - (float)(Find.TickManager.TicksGame - lastInterceptTicks) / 40f); + return Mathf.Max(idleAlpha, interceptAlpha); + } + + private float GetCurrentConeAlpha_RecentlyIntercepted() + { + if (!drawInterceptCone) return 0f; + return Mathf.Clamp01(1f - (float)(Find.TickManager.TicksGame - lastInterceptTicks) / 40f) * 0.82f; + } + + // --- GIZMO --- + public override IEnumerable CompGetWornGizmosExtra() + { + if (PawnOwner != null && Find.Selector.SingleSelectedThing == PawnOwner) + { + yield return new Gizmo_EnergyShieldStatus { shield = this }; + } + } + + public override string CompInspectStringExtra() + { + StringBuilder sb = new StringBuilder(); + if (OnCooldown) + { + sb.Append("Cooldown: " + CooldownTicksLeft.ToStringTicksToPeriod()); + } + else if (stunner.Stunned) + { + sb.Append("EMP Shutdown: " + stunner.StunTicksLeft.ToStringTicksToPeriod()); + } + return sb.ToString(); + } + } + + public class Gizmo_EnergyShieldStatus : Gizmo + { + public CompApparelInterceptor shield; + private static readonly Texture2D FullShieldBarTex = SolidColorMaterials.NewSolidColorMaterial(new Color(0.2f, 0.8f, 0.85f), ShaderDatabase.MetaOverlay).mainTexture as Texture2D; + private static readonly Texture2D EmptyShieldBarTex = SolidColorMaterials.NewSolidColorMaterial(new Color(0.2f, 0.2f, 0.24f), ShaderDatabase.MetaOverlay).mainTexture as Texture2D; + + public override float GetWidth(float maxWidth) => 140f; + + public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms) + { + Rect rect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f); + Rect rect2 = rect.ContractedBy(6f); + Widgets.DrawWindowBackground(rect); + + Rect labelRect = rect2; + labelRect.height = rect.height / 2f; + Text.Font = GameFont.Tiny; + Widgets.Label(labelRect, shield.parent.LabelCap); + + Rect barRect = rect2; + barRect.yMin = rect2.y + rect2.height / 2f; + float fillPercent = (float)shield.currentHitPoints / shield.HitPointsMax; + Widgets.FillableBar(barRect, fillPercent, FullShieldBarTex, EmptyShieldBarTex, false); + + Text.Font = GameFont.Small; + Text.Anchor = TextAnchor.MiddleCenter; + + TaggedString statusText = shield.OnCooldown ? "Broken".Translate() : new TaggedString(shield.currentHitPoints + " / " + shield.HitPointsMax); + Widgets.Label(barRect, statusText); + + Text.Anchor = TextAnchor.UpperLeft; + + return new GizmoResult(GizmoState.Clear); + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/HarmonyPatches/Projectile_Launch_Patch.cs b/Source/WulaFallenEmpire/HarmonyPatches/Projectile_Launch_Patch.cs new file mode 100644 index 00000000..8b094b13 --- /dev/null +++ b/Source/WulaFallenEmpire/HarmonyPatches/Projectile_Launch_Patch.cs @@ -0,0 +1,42 @@ +using HarmonyLib; +using RimWorld; +using System.Linq; +using System.Reflection; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire.HarmonyPatches +{ + [HarmonyPatch(typeof(Projectile), "CheckForFreeInterceptBetween")] + public static class Projectile_CheckForFreeInterceptBetween_Patch + { + private static readonly MethodInfo ImpactMethod = AccessTools.Method(typeof(Projectile), "Impact"); + + public static bool Prefix(Projectile __instance, Vector3 lastExactPos, Vector3 newExactPos) + { + if (__instance.Map == null || __instance.Destroyed) return true; + + foreach (Pawn pawn in __instance.Map.mapPawns.AllPawnsSpawned) + { + if (pawn.apparel != null) + { + foreach (Apparel apparel in pawn.apparel.WornApparel) + { + if (apparel.TryGetComp(out var interceptor)) + { + if (interceptor.TryIntercept(__instance, lastExactPos, newExactPos)) + { + + ImpactMethod.Invoke(__instance, new object[] { null, true }); + + return false; + } + } + } + } + } + + return true; + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 97b2c355..9eb95358 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -62,6 +62,7 @@ + @@ -86,6 +87,7 @@ + @@ -94,4 +96,4 @@ - \ No newline at end of file +