暂存
This commit is contained in:
122
Source/Documents/Milira_Fortress.cs
Normal file
122
Source/Documents/Milira_Fortress.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using AncotLibrary;
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace Milira
|
||||
{
|
||||
public class JobDriver_FortressMode : JobDriver
|
||||
{
|
||||
private Thing thing;
|
||||
|
||||
public virtual ThingDef TurretDef => MiliraDefOf.Milian_Fortress;
|
||||
|
||||
public CompThingContainer CompThingContainer => thing?.TryGetComp<CompThingContainer>();
|
||||
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
// 检查部署区域是否合适
|
||||
Toil check = Toils_General.Do(() =>
|
||||
{
|
||||
foreach (var cell in GenRadial.RadialCellsAround(pawn.Position, 1.5f, false))
|
||||
{
|
||||
if (!cell.IsValid || !cell.InBounds(pawn.Map) || !cell.Walkable(pawn.Map) ||
|
||||
!cell.GetEdifice(pawn.Map).DestroyedOrNull() || cell.Roofed(pawn.Map))
|
||||
{
|
||||
// 空间不足或有障碍,技能冷却重置并结束任务
|
||||
var ability = pawn.abilities.abilities.FirstOrDefault(a => a.def.defName == "Milira_Fortress");
|
||||
ability?.StartCooldown(0);
|
||||
EndJobWith(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
yield return check;
|
||||
|
||||
// 部署炮台
|
||||
yield return Toils_General.Do(DeployPod);
|
||||
|
||||
// 角色进入炮台
|
||||
Toil enterPod = ToilMaker.MakeToil("EnterPod");
|
||||
enterPod.initAction = () =>
|
||||
{
|
||||
if (thing == null)
|
||||
{
|
||||
EndJobWith(JobCondition.Incompletable);
|
||||
return;
|
||||
}
|
||||
|
||||
bool pawnSelected = Find.Selector.IsSelected(pawn);
|
||||
|
||||
// 角色从地图消失并进入炮台容器
|
||||
if (pawn.DeSpawnOrDeselect())
|
||||
{
|
||||
CompThingContainer?.GetDirectlyHeldThings().TryAdd(pawn);
|
||||
}
|
||||
|
||||
// 如果之前选中了角色,现在改为选中炮台
|
||||
if (pawnSelected)
|
||||
{
|
||||
Find.Selector.Select(thing, playSound: false, forceDesignatorDeselect: false);
|
||||
}
|
||||
};
|
||||
yield return enterPod;
|
||||
}
|
||||
|
||||
private void DeployPod()
|
||||
{
|
||||
var carrierComp = pawn.TryGetComp<CompThingCarrier_Custom>();
|
||||
if (carrierComp == null) return;
|
||||
|
||||
FleckMaker.Static(pawn.TrueCenter(), pawn.Map, FleckDefOf.Milian_FortressFormed);
|
||||
thing = GenSpawn.Spawn(TurretDef, pawn.Position, pawn.Map);
|
||||
thing.SetFaction(pawn.Faction);
|
||||
|
||||
bool hasRapidDeployment = ModsConfig.IsActive("Ancot.MilianModification") &&
|
||||
pawn.health.hediffSet.GetFirstHediffOfDef(MiliraDefOf.MilianFitting_RapidDeployment) != null;
|
||||
|
||||
if (hasRapidDeployment)
|
||||
{
|
||||
SetHitPointAndRemoveResourceInCarrier(carrierComp, 200, 60);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetHitPointAndRemoveResourceInCarrier(carrierComp, 1200, 600);
|
||||
}
|
||||
|
||||
var containerMilian = thing.TryGetComp<CompThingContainer_Milian>();
|
||||
if (containerMilian != null)
|
||||
{
|
||||
containerMilian.hitPointMax = thing.HitPoints;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetHitPointAndRemoveResourceInCarrier(CompThingCarrier_Custom comp, int hitPoint, int initiationDelayTicks)
|
||||
{
|
||||
if (comp.IngredientCount > hitPoint + 400)
|
||||
{
|
||||
comp.TryRemoveThingInCarrier(hitPoint);
|
||||
thing.HitPoints = hitPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
int halfResources = comp.IngredientCount / 2;
|
||||
comp.TryRemoveThingInCarrier(halfResources);
|
||||
thing.HitPoints = halfResources;
|
||||
}
|
||||
|
||||
var initiatableComp = thing.TryGetComp<CompInitiatable>();
|
||||
if (initiatableComp != null)
|
||||
{
|
||||
initiatableComp.initiationDelayTicksOverride = initiationDelayTicks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
558
Source/Documents/PawnBuildingTransformer_Design.md
Normal file
558
Source/Documents/PawnBuildingTransformer_Design.md
Normal file
@@ -0,0 +1,558 @@
|
||||
# Pawn 与 Building 双向转换系统设计文档
|
||||
|
||||
本文档旨在详细阐述一个通用的、可配置的系统,用于在《边缘世界》中实现角色(Pawn)与建筑(Building)之间的双向转换。
|
||||
|
||||
## 1. 核心目标
|
||||
|
||||
- **通用性**: 任何Pawn或Building都可以通过简单的XML配置获得变形能力。
|
||||
- **健壮性**: 确保在各种情况下(主动触发、被动摧毁、存档读档)Pawn的状态都能被正确保存和恢复。
|
||||
- **可扩展性**: 方便开发者添加自定义的转换条件、资源消耗和效果。
|
||||
- **状态保持**: 明确Pawn的关键状态(如健康、技能、装备、意识形态等)在转换过程中通过保存Pawn实例本身而得以完整保留。
|
||||
|
||||
## 2. 系统架构
|
||||
|
||||
系统由以下几个核心部分组成:
|
||||
|
||||
- **`CompProperties_Morphable`**: 在XML中定义的配置组件,用于指定变形的目标、效果和耗时。
|
||||
- **`CompMorphable`**: 附加在物体上的核心逻辑组件,管理变形状态和触发器。
|
||||
- **`CompThingContainer`**: 用于在建筑形态下实际“存储”Pawn对象的容器。
|
||||
- **`JobDriver_Transforming`**: 一个自定义的`JobDriver`,用于处理从Pawn到Building的、有持续时间的转换过程。
|
||||
- **自定义Building类**: 需要一个继承自`Building`的子类,以重写`Destroy`方法来处理被动转换。
|
||||
|
||||
### 架构图
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Pawn
|
||||
A[Pawn_Character] -- Has --> B[CompMorphable];
|
||||
end
|
||||
|
||||
subgraph Building
|
||||
D[Building_Morphed] -- Has --> E[CompMorphable];
|
||||
D -- Also has --> C[CompThingContainer];
|
||||
C -- Contains --> F[Stored Pawn Instance];
|
||||
end
|
||||
|
||||
subgraph User_Interface
|
||||
G[Gizmo Button 'Transform'] -- Triggers --> H{StartTransform};
|
||||
end
|
||||
|
||||
A -- Transform --> D;
|
||||
D -- Transform Back --> A;
|
||||
|
||||
B -- Initiates Job --> J[JobDriver_Transforming];
|
||||
E -- Calls method --> K[TransformBackLogic];
|
||||
|
||||
subgraph XML_Configuration
|
||||
L[ThingDef: Pawn_Character] -- Defines --> B;
|
||||
M[ThingDef: Building_Morphed] -- Defines --> E & C;
|
||||
end
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 实现细节与代码示例
|
||||
|
||||
### 3.1 XML 配置 (`CompProperties_Morphable`)
|
||||
|
||||
为你的Pawn和Building `ThingDef` 添加以下组件。
|
||||
|
||||
**Pawn Def:**
|
||||
```xml
|
||||
<ThingDef ParentName="BasePawn">
|
||||
<!-- ... other pawn properties ... -->
|
||||
<comps>
|
||||
<li Class="YourNamespace.CompProperties_Morphable">
|
||||
<buildingDef>Your_BuildingDef_Name</buildingDef>
|
||||
<transformSound>Your_TransformSound</transformSound>
|
||||
<transformEffect>Your_TransformEffect</transformEffect>
|
||||
<transformTicks>120</transformTicks> <!-- 2 seconds -->
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
```
|
||||
|
||||
**Building Def:**
|
||||
```xml
|
||||
<ThingDef ParentName="BuildingBase">
|
||||
<!-- ... other building properties ... -->
|
||||
<comps>
|
||||
<!-- 容器组件,必须有 -->
|
||||
<li Class="CompProperties_ThingContainer">
|
||||
<compClass>CompThingContainer</compClass>
|
||||
</li>
|
||||
<!-- 变形逻辑组件 -->
|
||||
<li Class="YourNamespace.CompProperties_Morphable">
|
||||
<!-- pawnDef是可选的,如果为空则恢复被存储的pawn -->
|
||||
<pawnDef>Your_PawnDef_Name</pawnDef>
|
||||
<transformSound>Your_TransformBackSound</transformSound>
|
||||
<transformEffect>Your_TransformBackEffect</transformEffect>
|
||||
</li>
|
||||
</comps>
|
||||
</ThingDef>
|
||||
```
|
||||
|
||||
### 3.2 核心逻辑组件 (`CompMorphable`)
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
public class CompMorphable : ThingComp
|
||||
{
|
||||
private Pawn storedPawn;
|
||||
public CompProperties_Morphable Props => (CompProperties_Morphable)props;
|
||||
|
||||
public bool IsMorphed => parent.def == Props.buildingDef;
|
||||
public Pawn StoredPawn => storedPawn;
|
||||
|
||||
public void SetStoredPawn(Pawn pawn)
|
||||
{
|
||||
this.storedPawn = pawn;
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
// 确保Pawn引用在存档/读档时被正确保存
|
||||
Scribe_References.Look(ref storedPawn, "storedPawn");
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
// 为Pawn添加“变形”按钮
|
||||
if (parent is Pawn pawn)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "变形",
|
||||
action = () => {
|
||||
// 创建并分配变形任务
|
||||
var job = new Job(JobDefOf.Your_TransformingJob, parent);
|
||||
pawn.jobs.TryTakeOrderedJob(job);
|
||||
}
|
||||
};
|
||||
}
|
||||
// 为Building添加“恢复”按钮
|
||||
else if (parent is Building)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "恢复人形",
|
||||
action = () => { TransformBackToPawn(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void TransformBackToPawn()
|
||||
{
|
||||
// ... (此处实现Building -> Pawn的逻辑) ...
|
||||
// 检查空间、移除建筑、重新生成Pawn
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Pawn -> Building 转换 (`JobDriver_Transforming`)
|
||||
|
||||
这个`JobDriver`负责有过程的转换。
|
||||
|
||||
```csharp
|
||||
public class JobDriver_Transforming : JobDriver
|
||||
{
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||
|
||||
// 1. 检查空间
|
||||
yield return Toils_General.Do(() => {
|
||||
// ... 检查逻辑 ...
|
||||
// 如果失败: EndJobWith(JobCondition.Incompletable);
|
||||
});
|
||||
|
||||
// 2. 等待并播放特效
|
||||
var props = pawn.GetComp<CompMorphable>().Props;
|
||||
yield return Toils_General.Wait(props.transformTicks)
|
||||
.WithProgressBarToilDelay(TargetIndex.A);
|
||||
|
||||
// 3. 执行核心转换
|
||||
Toil transform = Toils_General.Do(() => {
|
||||
// 移除Pawn
|
||||
pawn.DeSpawn(DestroyMode.Vanish);
|
||||
// 生成Building
|
||||
Building building = (Building)GenSpawn.Spawn(props.buildingDef, pawn.Position, pawn.Map);
|
||||
building.SetFaction(pawn.Faction);
|
||||
// 存储Pawn
|
||||
building.GetComp<CompThingContainer>().GetDirectlyHeldThings().TryAdd(pawn);
|
||||
building.GetComp<CompMorphable>().SetStoredPawn(pawn);
|
||||
});
|
||||
yield return transform;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 Building -> Pawn 转换 (被动触发)
|
||||
|
||||
需要一个自定义的Building类来处理被摧毁时的情况。
|
||||
|
||||
```csharp
|
||||
public class Building_Morphable : Building
|
||||
{
|
||||
public override void Destroy(DestroyMode mode)
|
||||
{
|
||||
var comp = this.GetComp<CompMorphable>();
|
||||
if (comp != null && comp.StoredPawn != null)
|
||||
{
|
||||
Pawn pawn = comp.StoredPawn;
|
||||
// 在建筑消失前,先把Pawn生成出来
|
||||
GenSpawn.Spawn(pawn, this.Position, this.Map);
|
||||
|
||||
// 可选:对Pawn施加伤害
|
||||
if (mode == DestroyMode.KillFinalize)
|
||||
{
|
||||
pawn.TakeDamage(new DamageInfo(DamageDefOf.Bomb, 20));
|
||||
}
|
||||
}
|
||||
base.Destroy(mode);
|
||||
}
|
||||
}
|
||||
```
|
||||
**注意**: 你的Building `ThingDef` 的 `thingClass` 需要指向这个新的 `Building_Morphable` 类。
|
||||
|
||||
---
|
||||
|
||||
## 4. 流程图
|
||||
|
||||
### Pawn -> Building
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Player
|
||||
participant Pawn
|
||||
participant Gizmo
|
||||
participant JobDriver_Transforming
|
||||
|
||||
Player->>Gizmo: 点击“变形”按钮
|
||||
Gizmo->>Pawn: 分配 "Transforming" 任务
|
||||
Pawn->>JobDriver_Transforming: 开始执行任务
|
||||
JobDriver_Transforming->>JobDriver_Transforming: Toil 1: 检查空间
|
||||
JobDriver_Transforming->>JobDriver_Transforming: Toil 2: 等待 & 播放特效
|
||||
JobDriver_Transforming->>JobDriver_Transforming: Toil 3: DeSpawn Pawn, Spawn Building, Store Pawn
|
||||
JobDriver_Transforming->>Pawn: 任务结束
|
||||
```
|
||||
|
||||
### Building -> Pawn
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Active_Trigger [主动触发]
|
||||
A[Player Clicks Gizmo] --> B{TransformBackToPawn};
|
||||
B --> C[Check Spawn Area];
|
||||
C -- OK --> E[DeSpawn Building];
|
||||
E --> F[Spawn Pawn at Position];
|
||||
end
|
||||
|
||||
subgraph Passive_Trigger [被动触发]
|
||||
H[Building HP <= 0] --> I{Override 'Destroy' method};
|
||||
I --> J[Get Stored Pawn];
|
||||
J --> K[Spawn Pawn at Position];
|
||||
K --> L[Apply Damage to Pawn];
|
||||
L --> M[Call base.Destroy()];
|
||||
end
|
||||
```
|
||||
|
||||
这份文档提供了从设计理念到具体实现的全套方案,您可以根据此指南开始编码工作。
|
||||
|
||||
---
|
||||
|
||||
## 5. 完整C#代码实现
|
||||
|
||||
以下是实现此系统所需的全部C#脚本。建议将它们放置在项目的一个新子目录中(例如 `Source/Morphable/`)。
|
||||
|
||||
### 5.1 `CompProperties_Morphable.cs`
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
public class CompProperties_Morphable : CompProperties
|
||||
{
|
||||
// 变形为建筑的目标ThingDef
|
||||
public ThingDef buildingDef;
|
||||
|
||||
// 从建筑恢复时,指定要生成的PawnDef(可选,为空则恢复原Pawn)
|
||||
public ThingDef pawnDef;
|
||||
|
||||
// 变形时的音效
|
||||
public SoundDef transformSound;
|
||||
|
||||
// 变形时的视觉效果
|
||||
public EffecterDef transformEffect;
|
||||
|
||||
// 变形过程所需的tick数
|
||||
public int transformTicks = 60;
|
||||
|
||||
public CompProperties_Morphable()
|
||||
{
|
||||
compClass = typeof(CompMorphable);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 `CompMorphable.cs`
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
public class CompMorphable : ThingComp
|
||||
{
|
||||
private Pawn storedPawn;
|
||||
public CompProperties_Morphable Props => (CompProperties_Morphable)props;
|
||||
|
||||
public bool IsMorphed => parent.def == Props.buildingDef;
|
||||
public Pawn StoredPawn => storedPawn;
|
||||
|
||||
public void SetStoredPawn(Pawn pawn)
|
||||
{
|
||||
this.storedPawn = pawn;
|
||||
}
|
||||
|
||||
public override void PostExposeData()
|
||||
{
|
||||
base.PostExposeData();
|
||||
Scribe_References.Look(ref storedPawn, "storedPawn", false);
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||
{
|
||||
if (parent is Pawn pawn && pawn.Faction == Faction.OfPlayer)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "变形",
|
||||
defaultDesc = "将此单位转换为建筑形态。",
|
||||
icon = TexCommand.Attack, // TODO: Replace with a proper icon
|
||||
action = () => {
|
||||
// 添加配置验证
|
||||
if (Props.buildingDef == null)
|
||||
{
|
||||
Log.Error($"CompMorphable on {parent.def.defName} has no buildingDef defined.");
|
||||
return;
|
||||
}
|
||||
var job = JobMaker.MakeJob(JobDefOf.Your_TransformingJob, parent);
|
||||
pawn.jobs.TryTakeOrderedJob(job);
|
||||
}
|
||||
};
|
||||
}
|
||||
else if (parent is Building building && building.Faction == Faction.OfPlayer && storedPawn != null)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "恢复人形",
|
||||
defaultDesc = "将此建筑恢复为人形。",
|
||||
icon = TexCommand.ReleaseAnimals, // TODO: Replace with a proper icon
|
||||
action = () => { TransformBackToPawn(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void TransformBackToPawn()
|
||||
{
|
||||
Building building = (Building)this.parent;
|
||||
Map map = building.Map;
|
||||
|
||||
// 播放特效
|
||||
if (Props.transformEffect != null)
|
||||
{
|
||||
Effecter eff = Props.transformEffect.Spawn();
|
||||
eff.Trigger(building, building);
|
||||
}
|
||||
if (Props.transformSound != null)
|
||||
{
|
||||
Props.transformSound.PlayOneShot(new TargetInfo(building.Position, map));
|
||||
}
|
||||
|
||||
// 移除建筑
|
||||
building.DeSpawn(DestroyMode.Vanish);
|
||||
|
||||
// 重新生成Pawn
|
||||
GenSpawn.Spawn(storedPawn, building.Position, map, WipeMode.Vanish);
|
||||
|
||||
// 选中Pawn
|
||||
if (Find.Selector.IsSelected(building))
|
||||
{
|
||||
Find.Selector.Select(storedPawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 `JobDriver_Transforming.cs`
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
public class JobDriver_Transforming : JobDriver
|
||||
{
|
||||
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||
{
|
||||
return pawn.Reserve(pawn.Position, job);
|
||||
}
|
||||
|
||||
protected override IEnumerable<Toil> MakeNewToils()
|
||||
{
|
||||
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||
var comp = pawn.GetComp<CompMorphable>();
|
||||
if (comp == null) yield break;
|
||||
|
||||
// 1. 检查空间是否足够
|
||||
Toil checkSpace = Toils_General.Do(() => {
|
||||
foreach (var cell in GenRadial.RadialCellsAround(pawn.Position, comp.Props.buildingDef.Size.x / 2f, true))
|
||||
{
|
||||
if (!cell.InBounds(Map) || !cell.Walkable(Map) || cell.GetEdifice(Map) != null)
|
||||
{
|
||||
pawn.jobs.EndCurrentJob(JobCondition.Incompletable, true);
|
||||
if (pawn.Faction == Faction.OfPlayer)
|
||||
{
|
||||
Messages.Message("PawnTransformer_SpaceBlocked".Translate(pawn.Named("PAWN")), pawn, MessageTypeDefOf.RejectInput, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
yield return checkSpace;
|
||||
|
||||
// 2. 等待并播放特效
|
||||
Toil waitingToil = Toils_General.Wait(comp.Props.transformTicks, TargetIndex.None)
|
||||
.WithProgressBarToilDelay(TargetIndex.A);
|
||||
|
||||
waitingToil.tickAction = () =>
|
||||
{
|
||||
if (comp.Props.transformEffect != null && pawn.IsHashIntervalTick(5))
|
||||
{
|
||||
Effecter eff = comp.Props.transformEffect.Spawn();
|
||||
eff.Trigger(pawn, pawn);
|
||||
}
|
||||
};
|
||||
if (comp.Props.transformSound != null)
|
||||
{
|
||||
waitingToil.initAction = () => { comp.Props.transformSound.PlayOneShot(new TargetInfo(pawn.Position, pawn.Map)); };
|
||||
}
|
||||
yield return waitingToil;
|
||||
|
||||
// 3. 执行核心转换
|
||||
Toil transform = Toils_General.Do(() => {
|
||||
IntVec3 position = pawn.Position;
|
||||
Map map = pawn.Map;
|
||||
|
||||
// 移除Pawn
|
||||
pawn.DeSpawn(DestroyMode.Vanish);
|
||||
|
||||
// 生成Building
|
||||
Building building = (Building)GenSpawn.Spawn(comp.Props.buildingDef, position, map, WipeMode.Vanish);
|
||||
building.SetFaction(pawn.Faction);
|
||||
|
||||
// 继承Pawn的名称
|
||||
if (pawn.Name != null)
|
||||
{
|
||||
building.TryGetComp<CompAssignableToPawn>().TryAssignPawn(pawn);
|
||||
}
|
||||
|
||||
// 存储Pawn
|
||||
var container = building.GetComp<CompThingContainer>();
|
||||
if (container != null)
|
||||
{
|
||||
container.GetDirectlyHeldThings().TryAdd(pawn);
|
||||
}
|
||||
|
||||
var newMorphComp = building.GetComp<CompMorphable>();
|
||||
if (newMorphComp != null)
|
||||
{
|
||||
newMorphComp.SetStoredPawn(pawn);
|
||||
}
|
||||
});
|
||||
yield return transform;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 `Building_Morphable.cs`
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
public class Building_Morphable : Building
|
||||
{
|
||||
public override void Destroy(DestroyMode mode)
|
||||
{
|
||||
var comp = this.GetComp<CompMorphable>();
|
||||
if (comp != null && comp.StoredPawn != null)
|
||||
{
|
||||
Pawn pawn = comp.StoredPawn;
|
||||
Map map = this.Map;
|
||||
IntVec3 position = this.Position;
|
||||
|
||||
// 在建筑消失前,先把Pawn生成出来
|
||||
GenSpawn.Spawn(pawn, position, map, WipeMode.Vanish);
|
||||
|
||||
// 如果是被摧毁,对Pawn施加伤害
|
||||
if (mode == DestroyMode.KillFinalize)
|
||||
{
|
||||
Messages.Message($"{pawn.LabelShort} 从被摧毁的建筑中弹出!", pawn, MessageTypeDefOf.NegativeEvent);
|
||||
pawn.TakeDamage(new DamageInfo(DamageDefOf.Bomb, 20, 1, -1, this));
|
||||
}
|
||||
}
|
||||
base.Destroy(mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.5 `JobDefOf.cs` (用于定义JobDef)
|
||||
|
||||
```csharp
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
[DefOf]
|
||||
public static class JobDefOf
|
||||
{
|
||||
public static JobDef Your_TransformingJob;
|
||||
|
||||
static JobDefOf()
|
||||
{
|
||||
DefOfHelper.EnsureInitializedInCtor(typeof(JobDefOf));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**最后,您还需要在 `Defs/JobDefs/` 目录下创建一个XML文件来定义 `Your_TransformingJob`:**
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Defs>
|
||||
<JobDef>
|
||||
<defName>Your_TransformingJob</defName>
|
||||
<driverClass>YourNamespace.JobDriver_Transforming</driverClass>
|
||||
<reportString>正在变形...</reportString>
|
||||
</JobDef>
|
||||
</Defs>
|
||||
```
|
||||
Reference in New Issue
Block a user