尸织技能

This commit is contained in:
2025-10-15 17:19:35 +08:00
parent 7fb2a0e03e
commit cf08c6525c
13 changed files with 861 additions and 218 deletions

View File

@@ -3,28 +3,12 @@
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_sacrificialfueltank\\building_sacrificialfueltank.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_sacrificialfueltank\\building_sacrificialfueltank.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_nutrientvat\\building_nutrientvat.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\thing_comps\\ara_compextraincubationinfo\\compextraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_compextraincubationinfo\\compextraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\thing_comps\\ara_compextraincubationinfo\\compproperties_extraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:thing_comps\\ara_compextraincubationinfo\\compproperties_extraincubationinfo.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_buildingterrainspawn\\compdelayedterrainspawn.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
}
],
"DocumentGroupContainers": [
@@ -43,78 +27,28 @@
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Building_NutrientVat.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"RelativeToolTip": "Building_Comps\\ARA_NutrientVat\\Building_NutrientVat.cs",
"ViewState": "AgIAAGMAAAAAAAAAAAAowHkAAABTAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-14T08:54:07.96Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "Building_SacrificialFuelTank.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_SacrificialFuelTank\\Building_SacrificialFuelTank.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_SacrificialFuelTank\\Building_SacrificialFuelTank.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_SacrificialFuelTank\\Building_SacrificialFuelTank.cs*",
"RelativeToolTip": "Building_Comps\\ARA_SacrificialFuelTank\\Building_SacrificialFuelTank.cs*",
"ViewState": "AgIAAEoAAAAAAAAAAAAAAGMAAAAzAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-14T08:53:19.337Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "CompRefuelableNutrition.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeDocumentMoniker": "Building_Comps\\CompRefuelableNutrition.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeToolTip": "Building_Comps\\CompRefuelableNutrition.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAwAAAAAAAAAA==",
"ViewState": "AgIAABAAAAAAAAAAAAAuwBYAAAAhAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-14T08:38:13.803Z",
"WhenOpened": "2025-10-15T08:04:45.513Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "CompProperties_ExtraIncubationInfo.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
"RelativeDocumentMoniker": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
"RelativeToolTip": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompProperties_ExtraIncubationInfo.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAA==",
"DocumentIndex": 0,
"Title": "CompAbilityEffect_TransformCorpse.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs",
"RelativeToolTip": "Abilities\\CompAbilityEffect_TransformCorpse.cs",
"ViewState": "AgIAAMoAAAAAAAAAAAAtwF4AAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-13T03:27:00.382Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "CompExtraIncubationInfo.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
"RelativeDocumentMoniker": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
"RelativeToolTip": "Thing_Comps\\ARA_CompExtraIncubationInfo\\CompExtraIncubationInfo.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAoAAAAXAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-13T03:26:37.426Z",
"WhenOpened": "2025-10-15T08:02:12.842Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "CompDelayedTerrainSpawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"RelativeToolTip": "Building_Comps\\ARA_BuildingTerrainSpawn\\CompDelayedTerrainSpawn.cs",
"ViewState": "AgIAAA4AAAAAAAAAAAAAwD0AAAAhAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-12T15:30:31.391Z"
}
]
}

View File

@@ -0,0 +1,232 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace ArachnaeSwarm
{
public class CompProperties_AbilityTransformCorpse : CompProperties_AbilityEffect
{
public ThingDef buildingDef; // 要生成的建筑定义
public float nutritionToFuelRatio = 1.0f; // 尸体营养值到燃料的转换率
public bool requireFreshCorpse = false; // 是否要求新鲜尸体
public RotStage maxRotStage = RotStage.Dessicated; // 最大腐烂阶段
public CompProperties_AbilityTransformCorpse()
{
compClass = typeof(CompAbilityEffect_TransformCorpse);
}
}
public class CompAbilityEffect_TransformCorpse : CompAbilityEffect
{
public new CompProperties_AbilityTransformCorpse Props => (CompProperties_AbilityTransformCorpse)props;
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Corpse corpse = target.Thing as Corpse;
if (corpse == null)
{
Messages.Message("AbilityMustTargetCorpse".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
return;
}
if (!IsValidCorpse(corpse, true))
return;
if (!CanSpawnBuildingAt(corpse.Position, corpse.Map))
{
Messages.Message("NotEnoughSpaceForBuilding".Translate(Props.buildingDef.label), parent.pawn, MessageTypeDefOf.RejectInput, false);
return;
}
TransformCorpseToBuilding(corpse);
}
private void TransformCorpseToBuilding(Corpse corpse)
{
Map map = corpse.Map;
IntVec3 position = corpse.Position;
Pawn innerPawn = corpse.InnerPawn;
float calculatedFuel = CalculateFuelFromCorpse(corpse);
corpse.Destroy(DestroyMode.Vanish);
Building building = (Building)GenSpawn.Spawn(Props.buildingDef, position, map, WipeMode.Vanish);
building.SetFaction(parent.pawn.Faction);
// 设置 CompRefuelableNutrition 的初始燃料
SetupRefuelableNutrition(building, calculatedFuel);
var morphableComp = building.GetComp<CompMorphable>();
if (morphableComp != null && innerPawn != null)
{
morphableComp.SetStoredPawn(innerPawn);
}
Messages.Message("CorpseTransformedToBuilding".Translate(innerPawn?.LabelShort ?? "Unknown", Props.buildingDef.label),
building, MessageTypeDefOf.PositiveEvent);
}
private void SetupRefuelableNutrition(Building building, float calculatedFuel)
{
var refuelableNutritionComp = building.GetComp<CompRefuelableNutrition>();
if (refuelableNutritionComp != null)
{
// 直接设置燃料值,而不是通过 Refuel 方法
refuelableNutritionComp.Refuel(calculatedFuel);
}
else
{
// 回退到普通的 CompRefuelable
var refuelableComp = building.GetComp<CompRefuelable>();
if (refuelableComp != null && calculatedFuel > 0)
{
refuelableComp.Refuel(calculatedFuel);
}
}
}
private float CalculateFuelFromCorpse(Corpse corpse)
{
if (corpse.InnerPawn == null) return 0f;
float baseNutrition = corpse.InnerPawn.GetStatValue(StatDefOf.Nutrition);
float rotMultiplier = GetRotMultiplier(corpse.GetRotStage());
float calculatedFuel = baseNutrition * Props.nutritionToFuelRatio * rotMultiplier;
// 获取建筑的燃料容量限制
var buildingDef = Props.buildingDef;
if (buildingDef != null)
{
var refuelableProps = buildingDef.GetCompProperties<CompProperties_RefuelableNutrition>();
if (refuelableProps != null)
{
// 确保计算的燃料不超过建筑容量
calculatedFuel = Mathf.Min(calculatedFuel, refuelableProps.fuelCapacity);
}
}
return calculatedFuel;
}
private float GetRotMultiplier(RotStage rotStage)
{
switch (rotStage)
{
case RotStage.Fresh: return 1.0f;
case RotStage.Rotting: return 0.5f;
case RotStage.Dessicated: return 0.25f;
default: return 0f;
}
}
private bool CanSpawnBuildingAt(IntVec3 position, Map map)
{
CellRect cellRect = GenAdj.OccupiedRect(position, Rot4.North, Props.buildingDef.Size);
foreach (IntVec3 cell in cellRect)
{
if (!cell.InBounds(map) || !cell.Walkable(map) || cell.GetEdifice(map) != null)
{
return false;
}
}
return true;
}
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
{
if (!base.Valid(target, throwMessages))
return false;
Corpse corpse = target.Thing as Corpse;
if (corpse == null)
{
if (throwMessages)
{
Messages.Message("AbilityMustTargetCorpse".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
return IsValidCorpse(corpse, throwMessages);
}
private bool IsValidCorpse(Corpse corpse, bool throwMessages)
{
if (corpse.InnerPawn == null)
{
if (throwMessages)
{
Messages.Message("CorpseHasNoPawn".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
RotStage rotStage = corpse.GetRotStage();
if (rotStage > Props.maxRotStage)
{
if (throwMessages)
{
Messages.Message("CorpseTooRotated".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
if (Props.requireFreshCorpse && rotStage != RotStage.Fresh)
{
if (throwMessages)
{
Messages.Message("RequiresFreshCorpse".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
if (!IsValidPawnRace(corpse.InnerPawn))
{
if (throwMessages)
{
Messages.Message("InvalidPawnRace".Translate(), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
if (!CanSpawnBuildingAt(corpse.Position, corpse.Map))
{
if (throwMessages)
{
Messages.Message("NotEnoughSpaceForBuilding".Translate(Props.buildingDef.label), parent.pawn, MessageTypeDefOf.RejectInput, false);
}
return false;
}
return true;
}
private bool IsValidPawnRace(Pawn pawn)
{
return true;
}
public override void DrawEffectPreview(LocalTargetInfo target)
{
if (target.IsValid && target.Thing is Corpse corpse && IsValidCorpse(corpse, false))
{
// 绘制目标单元格的高亮
GenDraw.DrawFieldEdges(new List<IntVec3> { target.Cell }, Valid(target) ? Color.green : Color.red);
if (Props.buildingDef != null)
{
// 绘制建筑占用的所有单元格
CellRect cellRect = GenAdj.OccupiedRect(target.Cell, Rot4.North, Props.buildingDef.Size);
GenDraw.DrawFieldEdges(cellRect.Cells.ToList(), Valid(target) ? Color.green : Color.red);
}
}
}
}
}

View File

@@ -99,6 +99,7 @@
<Compile Include="Abilities\ARA_ShowInteractiveThing\CompProperties_AbilityShowInteractiveThing.cs" />
<Compile Include="Abilities\ARA_ShowSpawnablePawnsList\CompAbilityEffect_AbilityShowSpawnablePawns.cs" />
<Compile Include="Abilities\ARA_ShowSpawnablePawnsList\CompProperties_AbilityShowSpawnablePawns.cs" />
<Compile Include="Abilities\CompAbilityEffect_TransformCorpse.cs" />
<Compile Include="Buildings\Building_TurretGunHasSpeed.cs" />
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\Building_RefuelingVat.cs" />
<Compile Include="Building_Comps\ARA_Building_RefuelingVat\CompProperties_RefuelingVat.cs" />

View File

@@ -319,7 +319,7 @@ namespace ArachnaeSwarm
yield return new FloatMenuOption(label, () =>
{
this._selectedProcess = process;
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_StartResearchProduction"), parent);
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("ARA_StartInteractiveProduction"), parent);
selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
});
}