暂存
This commit is contained in:
@@ -267,6 +267,10 @@
|
||||
<Compile Include="Buildings\Building_CatastropheMissileSilo\WorldObject_CatastropheMissile.cs" />
|
||||
<Compile Include="HarmonyPatches\Patch_ForceTargetable.cs" />
|
||||
<Compile Include="Building_Comps\CompForceTargetable.cs" />
|
||||
<Compile Include="PowerArmor\ARA_PowerArmor.cs" />
|
||||
<Compile Include="PowerArmor\CompPowerArmorStation.cs" />
|
||||
<Compile Include="PowerArmor\Gizmo_StructurePanel.cs" />
|
||||
<Compile Include="PowerArmor\JobDriver_EnterPowerArmor.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Jobs\JobDriver_SuperCarry\SuperCarryExtension.cs" />
|
||||
|
||||
153
Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
Normal file
153
Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public interface IStructurePoints
|
||||
{
|
||||
float StructurePoints { get; }
|
||||
float StructurePointsMax { get; }
|
||||
float StructurePointsPercent { get; }
|
||||
string Label { get; }
|
||||
}
|
||||
|
||||
public class PowerArmorExtension : DefModExtension
|
||||
{
|
||||
public ThingDef buildingDef;
|
||||
public float structurePointsMax = 500f;
|
||||
}
|
||||
|
||||
[StaticConstructorOnStartup]
|
||||
public class ARA_PowerArmor : Apparel, IStructurePoints
|
||||
{
|
||||
#region Properties
|
||||
private PowerArmorExtension ext;
|
||||
public PowerArmorExtension Ext => ext ??= def.GetModExtension<PowerArmorExtension>();
|
||||
public override string Label => base.Label;
|
||||
|
||||
private float structurePoints = -1f;
|
||||
public float StructurePointsMax => Ext?.structurePointsMax ?? 500f;
|
||||
|
||||
public float StructurePoints
|
||||
{
|
||||
get
|
||||
{
|
||||
if (structurePoints < 0)
|
||||
{
|
||||
structurePoints = StructurePointsMax;
|
||||
}
|
||||
return structurePoints;
|
||||
}
|
||||
set
|
||||
{
|
||||
structurePoints = Mathf.Clamp(value, 0, StructurePointsMax);
|
||||
}
|
||||
}
|
||||
|
||||
public float StructurePointsPercent => StructurePoints / StructurePointsMax;
|
||||
|
||||
public Building sourceBuilding;
|
||||
#endregion
|
||||
|
||||
#region Data
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
Scribe_Values.Look(ref structurePoints, "structurePoints", -1f);
|
||||
Scribe_References.Look(ref sourceBuilding, "sourceBuilding");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Gizmo
|
||||
public override IEnumerable<Gizmo> GetWornGizmos()
|
||||
{
|
||||
foreach (var gizmo in base.GetWornGizmos())
|
||||
{
|
||||
yield return gizmo;
|
||||
}
|
||||
yield return new Gizmo_StructurePanel(this);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region State-Switching
|
||||
public override void Notify_Unequipped(Pawn pawn)
|
||||
{
|
||||
base.Notify_Unequipped(pawn);
|
||||
|
||||
ThingDef buildingToSpawn = sourceBuilding?.def ?? Ext?.buildingDef;
|
||||
|
||||
if (buildingToSpawn == null)
|
||||
{
|
||||
Log.Error($"[ArachnaeSwarm] Power Armor {this.def.defName} unequipped, but has no buildingDef defined in its PowerArmorExtension or a source building.");
|
||||
return;
|
||||
}
|
||||
|
||||
Building building = (Building)ThingMaker.MakeThing(buildingToSpawn);
|
||||
building.HitPoints = Mathf.RoundToInt(this.StructurePoints);
|
||||
GenPlace.TryPlaceThing(building, pawn.Position, pawn.Map, ThingPlaceMode.Near);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Damage Handling - THE FINAL, CORRECT IMPLEMENTATION
|
||||
public override bool CheckPreAbsorbDamage(DamageInfo dinfo)
|
||||
{
|
||||
if (this.Wearer == null || !dinfo.Def.harmsHealth || dinfo.Amount <= 0.001f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float finalDamage = GetPostArmorDamage(ref dinfo);
|
||||
|
||||
if (finalDamage > 0)
|
||||
{
|
||||
this.StructurePoints -= finalDamage;
|
||||
EffecterDefOf.DamageDiminished_Metal.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
|
||||
|
||||
if (this.StructurePoints <= 0)
|
||||
{
|
||||
Messages.Message("PowerArmorBroken".Translate(this.Label, this.Wearer.LabelShort), this, MessageTypeDefOf.NegativeEvent);
|
||||
this.Destroy(DestroyMode.KillFinalize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EffecterDefOf.Deflect_Metal_Bullet.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
|
||||
}
|
||||
|
||||
// By returning true, we tell the game the damage has been fully handled and should not proceed to the pawn.
|
||||
return true;
|
||||
}
|
||||
|
||||
private float GetPostArmorDamage(ref DamageInfo dinfo)
|
||||
{
|
||||
float amount = dinfo.Amount;
|
||||
if (dinfo.Def.armorCategory != null)
|
||||
{
|
||||
StatDef armorRatingStat = dinfo.Def.armorCategory.armorRatingStat;
|
||||
float armorRating = this.GetStatValue(armorRatingStat);
|
||||
|
||||
float armorPenetration = dinfo.ArmorPenetrationInt;
|
||||
float num = Mathf.Max(armorRating - armorPenetration, 0f);
|
||||
float value = Rand.Value;
|
||||
float num2 = num * 0.5f;
|
||||
float num3 = num;
|
||||
if (value < num2)
|
||||
{
|
||||
amount = 0f;
|
||||
}
|
||||
else if (value < num3)
|
||||
{
|
||||
amount = GenMath.RoundRandom(amount / 2f);
|
||||
if (dinfo.Def.armorCategory == DamageArmorCategoryDefOf.Sharp)
|
||||
{
|
||||
dinfo.Def = DamageDefOf.Blunt;
|
||||
}
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
20
Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
Normal file
20
Source/ArachnaeSwarm/PowerArmor/CompPowerArmorStation.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_PowerArmorStation : CompProperties
|
||||
{
|
||||
public ThingDef apparelDef;
|
||||
|
||||
public CompProperties_PowerArmorStation()
|
||||
{
|
||||
compClass = typeof(CompPowerArmorStation);
|
||||
}
|
||||
}
|
||||
|
||||
public class CompPowerArmorStation : ThingComp
|
||||
{
|
||||
public CompProperties_PowerArmorStation Props => (CompProperties_PowerArmorStation)props;
|
||||
}
|
||||
}
|
||||
55
Source/ArachnaeSwarm/PowerArmor/Gizmo_StructurePanel.cs
Normal file
55
Source/ArachnaeSwarm/PowerArmor/Gizmo_StructurePanel.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
[StaticConstructorOnStartup]
|
||||
public class Gizmo_StructurePanel : Gizmo
|
||||
{
|
||||
private static readonly Texture2D FullBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.2f, 0.8f, 0.2f));
|
||||
private static readonly Texture2D EmptyBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.1f, 0.1f));
|
||||
private static readonly Texture2D UnderflowBarTex = SolidColorMaterials.NewSolidColorTexture(new Color(0.9f, 0.1f, 0.1f));
|
||||
|
||||
private IStructurePoints armor;
|
||||
|
||||
public Gizmo_StructurePanel(IStructurePoints armor)
|
||||
{
|
||||
this.armor = armor;
|
||||
this.Order = -100f; // Correctly use the 'Order' property
|
||||
}
|
||||
|
||||
public override float GetWidth(float maxWidth)
|
||||
{
|
||||
return 140f;
|
||||
}
|
||||
|
||||
public override GizmoResult GizmoOnGUI(Vector2 topLeft, float maxWidth, GizmoRenderParms parms)
|
||||
{
|
||||
Rect overRect = new Rect(topLeft.x, topLeft.y, GetWidth(maxWidth), 75f);
|
||||
Find.WindowStack.ImmediateWindow(984988, overRect, WindowLayer.GameUI, delegate
|
||||
{
|
||||
Rect rect = overRect.AtZero().ContractedBy(6f);
|
||||
|
||||
// Draw label
|
||||
Rect labelRect = rect;
|
||||
labelRect.height = overRect.height / 2f;
|
||||
Text.Font = GameFont.Tiny;
|
||||
Widgets.Label(labelRect, armor.Label);
|
||||
|
||||
// Draw bar
|
||||
Rect barRect = rect;
|
||||
barRect.yMin = overRect.height / 2f;
|
||||
float fillPercent = armor.StructurePointsPercent;
|
||||
|
||||
Widgets.FillableBar(barRect, fillPercent, FullBarTex, EmptyBarTex, false);
|
||||
|
||||
// Draw text on bar
|
||||
Text.Font = GameFont.Small;
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(barRect, $"{armor.StructurePoints:F0} / {armor.StructurePointsMax:F0}");
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
});
|
||||
return new GizmoResult(GizmoState.Clear);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
Normal file
60
Source/ArachnaeSwarm/PowerArmor/JobDriver_EnterPowerArmor.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class JobDriver_EnterPowerArmor : JobDriver
|
||||
{
|
||||
private const TargetIndex BuildingInd = TargetIndex.A;
|
||||
private Building PowerArmorBuilding => (Building)job.GetTarget(BuildingInd).Thing;
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(PowerArmorBuilding, job, 1, -1, null, errorOnFailed);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDespawnedNullOrForbidden(BuildingInd);
|
||||
this.FailOnSomeonePhysicallyInteracting(BuildingInd);
|
||||
|
||||
yield return Toils_Goto.GotoThing(BuildingInd, PathEndMode.InteractionCell);
|
||||
yield return Toils_General.Wait(120, BuildingInd).WithProgressBarToilDelay(BuildingInd);
|
||||
|
||||
Toil enter = new Toil();
|
||||
enter.initAction = () =>
|
||||
{
|
||||
Pawn actor = enter.actor;
|
||||
var building = (Building)actor.CurJob.GetTarget(BuildingInd).Thing;
|
||||
|
||||
// Get the CompProperties from the building's new component
|
||||
var compProps = building.GetComp<CompPowerArmorStation>()?.Props;
|
||||
if (compProps != null && compProps.apparelDef != null)
|
||||
{
|
||||
// Create the apparel
|
||||
ARA_PowerArmor apparel = (ARA_PowerArmor)ThingMaker.MakeThing(compProps.apparelDef);
|
||||
|
||||
// CRITICAL STEP: Link the apparel back to the building
|
||||
apparel.sourceBuilding = building;
|
||||
|
||||
// Sync health from building to apparel
|
||||
apparel.StructurePoints = building.HitPoints;
|
||||
|
||||
// Wear the apparel
|
||||
actor.apparel.Wear(apparel, true, true);
|
||||
|
||||
// Despawn the building
|
||||
building.DeSpawn();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[ArachnaeSwarm] Power Armor Building {building.def.defName} is missing CompProperties_PowerArmorStation or apparelDef.");
|
||||
}
|
||||
};
|
||||
enter.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||
yield return enter;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user