暂存
This commit is contained in:
569
Source/Documents/Possession_Implementation_Guide.md
Normal file
569
Source/Documents/Possession_Implementation_Guide.md
Normal file
@@ -0,0 +1,569 @@
|
||||
# “抱脸虫夺舍”技能实现说明书 (V3 - 最终版)
|
||||
|
||||
## 1. 功能概述
|
||||
|
||||
本功能实现了一个名为“阿拉克涅寄生”的特殊技能,允许一个特定的“阿拉克涅原虫”(抱脸虫)Pawn将自己的意识(灵魂)注入另一个生物的身体,从而完全占据并控制它。
|
||||
|
||||
**核心玩法循环:**
|
||||
1. **夺舍**: 抱脸虫使用技能后,其物理实体消失,其“灵魂”(名字、背景、技能、特性等)将完全覆盖目标的身体。
|
||||
2. **成长**: 玩家将控制这个新的身体进行游戏,所有获得的经验、技能和记忆都将积累在这个身体上。
|
||||
3. **重生**: 当被夺舍的身体死亡时,抱脸虫的灵魂会带着所有新的成长,从尸体中“重生”,变回一个独立的、更强大的阿拉克涅原虫Pawn,准备寻找下一个宿主。
|
||||
|
||||
这是一个高风险、高回报的玩法,允许玩家以一种独特的方式延续一个核心角色的“生命”和成长。
|
||||
|
||||
## 2. 实现流程
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[抱脸虫] -- 使用“阿拉克涅寄生”技能 --> B(目标Pawn);
|
||||
B -- 添加 Hediff_Possession --> C{执行灵魂覆盖};
|
||||
C -- 1. 存储抱脸虫Pawn的完整数据 --> D[Hediff容器];
|
||||
C -- 2. 将抱脸虫的“灵魂”数据覆盖到目标身上 --> E[被夺舍的身体];
|
||||
D -- 3. 抱脸虫物理实体消失 --> F([Vanish]);
|
||||
E -- 玩家控制,积累经验和记忆 --> E;
|
||||
E -- 受到致命伤害 --> G{身体死亡};
|
||||
G -- 触发Hediff.Notify_PawnDied --> H{反向同步成长};
|
||||
D -- 获取存储的抱脸虫数据 --> H;
|
||||
E -- 获取身体上的成长数据 --> H;
|
||||
H -- 将成长更新到抱脸虫数据上 --> I[更新后的抱脸虫];
|
||||
I -- 从Hediff中释放 --> J(更强大的抱脸虫重生);
|
||||
J -- 等待下一次夺舍 --> A;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 代码详解
|
||||
|
||||
### 3.1 `CompAbilityEffect_Possess.cs` - 技能效果的起点
|
||||
|
||||
这是技能被使用时第一个被调用的C#文件。它的职责是创建`Hediff_Possession`并将其附加到目标身上,从而启动整个夺舍流程。
|
||||
|
||||
```csharp
|
||||
// 路径: Source/ArachnaeSwarm/Possession/CompAbilityEffect_Possess.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
// 继承自CompAbilityEffect,这是所有技能效果组件的基类
|
||||
public class CompAbilityEffect_Possess : CompAbilityEffect
|
||||
{
|
||||
// 当技能成功施放时,游戏会调用这个Apply方法
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest); // 调用基类方法,确保标准流程执行
|
||||
|
||||
// 获取施法者 (我们的抱脸虫)
|
||||
Pawn caster = this.parent.pawn;
|
||||
// 获取目标Pawn
|
||||
Pawn targetPawn = target.Pawn;
|
||||
|
||||
// 安全检查:如果目标不是一个Pawn,则直接返回
|
||||
if (targetPawn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: 在此可以添加更多的限制条件,例如:
|
||||
// 1. 不能夺舍机械体
|
||||
// if (targetPawn.RaceProps.IsMechanoid) { ... }
|
||||
// 2. 不能夺舍已经被夺舍的目标
|
||||
// if (targetPawn.health.hediffSet.HasHediff(HediffDef.Named("ARA_Possession"))) { ... }
|
||||
|
||||
// 步骤1: 创建Hediff实例
|
||||
// HediffMaker.MakeHediff会根据XML定义创建一个新的Hediff对象
|
||||
Hediff_Possession hediff = (Hediff_Possession)HediffMaker.MakeHediff(HediffDef.Named("ARA_Possession"), targetPawn);
|
||||
|
||||
// 步骤2: 注入施法者灵魂
|
||||
// 在Hediff被正式添加到目标身上之前,将施法者的引用传递进去。
|
||||
// 这是关键一步,确保Hediff在执行PostAdd逻辑时能知道谁是施法者。
|
||||
hediff.SetCaster(caster);
|
||||
|
||||
// 步骤3: 将Hediff添加到目标身上
|
||||
// 这会触发Hediff_Possession类中的PostAdd方法,从而启动真正的夺舍逻辑。
|
||||
targetPawn.health.AddHediff(hediff);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 `Hediff_Possession.cs` - 夺舍与重生的核心
|
||||
|
||||
这个Hediff是整个功能的核心。它作为“灵魂容器”,负责存储抱脸虫的本体,并在恰当的时机执行“夺舍”和“重生”的逻辑。
|
||||
|
||||
```csharp
|
||||
// 路径: Source/ArachnaeSwarm/Possession/Hediff_Possession.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
// 继承HediffWithComps以支持组件,并实现IThingHolder接口来表明自己是容器
|
||||
public class Hediff_Possession : HediffWithComps, IThingHolder
|
||||
{
|
||||
// --- 核心字段 ---
|
||||
private ThingOwner innerContainer; // 实际存储灵魂(抱脸虫Pawn)的容器
|
||||
private Pawn originalCaster; // 临时保存对原始施法者的引用
|
||||
|
||||
// --- 构造与属性 ---
|
||||
public Hediff_Possession()
|
||||
{
|
||||
// 初始化容器。LookMode.Deep是关键,它能确保Pawn的所有数据都被完整保存。
|
||||
this.innerContainer = new ThingOwner<Thing>(this, false, LookMode.Deep);
|
||||
}
|
||||
|
||||
// 提供一个方便的只读属性来获取容器中存储的Pawn
|
||||
public Pawn StoredCasterPawn => innerContainer.Count > 0 ? innerContainer[0] as Pawn : null;
|
||||
|
||||
// --- IThingHolder 接口实现 ---
|
||||
public IThingHolder ParentHolder => this.pawn; // 容器的父级就是持有该Hediff的Pawn
|
||||
|
||||
public void GetChildHolders(List<IThingHolder> outChildren)
|
||||
{
|
||||
ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, this.GetDirectlyHeldThings());
|
||||
}
|
||||
|
||||
public ThingOwner GetDirectlyHeldThings()
|
||||
{
|
||||
return innerContainer;
|
||||
}
|
||||
|
||||
// --- 核心逻辑 ---
|
||||
|
||||
// 当Hediff被成功添加到目标身上后,此方法被自动调用
|
||||
public override void PostAdd(DamageInfo? dinfo)
|
||||
{
|
||||
base.PostAdd(dinfo);
|
||||
|
||||
if (this.originalCaster == null)
|
||||
{
|
||||
Log.Error("Hediff_Possession was added without an original caster.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 存储灵魂:将施法者的Pawn对象完整地存入容器
|
||||
this.innerContainer.TryAdd(this.originalCaster);
|
||||
|
||||
// 2. 灵魂覆盖:调用工具类,执行数据迁移
|
||||
PawnDataUtility.TransferSoul(this.originalCaster, this.pawn);
|
||||
|
||||
// 3. 销毁施法者的物理实体,因为它现在“活”在目标的身体里了
|
||||
if (!this.originalCaster.Destroyed)
|
||||
{
|
||||
this.originalCaster.Destroy(DestroyMode.Vanish);
|
||||
}
|
||||
|
||||
Log.Message($"{this.pawn.LabelShort} has been possessed by {StoredCasterPawn.LabelShort}!");
|
||||
}
|
||||
|
||||
// 当持有此Hediff的Pawn(即宿主)死亡时,此方法被自动调用
|
||||
public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
|
||||
{
|
||||
base.Notify_PawnDied(dinfo, culprit);
|
||||
|
||||
Pawn deadBody = this.pawn;
|
||||
Pawn storedCaster = this.StoredCasterPawn;
|
||||
|
||||
if (storedCaster == null)
|
||||
{
|
||||
Log.Error("Possessed pawn died, but no caster soul was found inside.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Message($"Host {deadBody.LabelShort} died. Transferring experience back to {storedCaster.LabelShort} and ejecting.");
|
||||
|
||||
// 1. 灵魂更新:反向调用工具类,将宿主身体上的成长同步回抱脸虫的灵魂
|
||||
PawnDataUtility.TransferSoul(deadBody, storedCaster);
|
||||
|
||||
// 2. 重生:将更新后的抱脸虫灵魂从容器中释放到地图上
|
||||
this.EjectContents();
|
||||
}
|
||||
|
||||
// --- 公共方法 ---
|
||||
|
||||
// 由CompAbilityEffect调用,用于在添加Hediff前设置施法者
|
||||
public void SetCaster(Pawn caster)
|
||||
{
|
||||
this.originalCaster = caster;
|
||||
}
|
||||
|
||||
// 将容器内的东西(抱脸虫)扔到地图上
|
||||
public void EjectContents()
|
||||
{
|
||||
if (StoredCasterPawn != null)
|
||||
{
|
||||
this.innerContainer.TryDropAll(this.pawn.Position, this.pawn.Map, ThingPlaceMode.Near);
|
||||
}
|
||||
}
|
||||
|
||||
// --- 存档/读档 ---
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
// Scribe_Deep是关键,确保容器内的Pawn被深度保存
|
||||
Scribe_Deep.Look(ref innerContainer, "innerContainer", this);
|
||||
// 保存对原始施法者的引用(虽然它很快会被销毁,但以防万一)
|
||||
Scribe_References.Look(ref originalCaster, "originalCaster");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 `PawnDataUtility.cs` - “灵魂”数据迁移的执行者
|
||||
|
||||
这是一个静态工具类,集中处理所有与Pawn数据复制相关的复杂逻辑,使得其他部分的代码更整洁。
|
||||
|
||||
```csharp
|
||||
// 路径: Source/ArachnaeSwarm/Possession/PawnDataUtility.cs
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
public static class PawnDataUtility
|
||||
{
|
||||
// 核心方法:将soulSource的“灵魂”数据转移到bodyTarget上
|
||||
public static void TransferSoul(Pawn soulSource, Pawn bodyTarget)
|
||||
{
|
||||
if (soulSource == null || bodyTarget == null)
|
||||
{
|
||||
Log.Error("Cannot transfer soul: source or target is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Message($"Beginning soul transfer from {soulSource.LabelShort} to {bodyTarget.LabelShort}.");
|
||||
|
||||
// --- 1. 核心身份数据 ---
|
||||
|
||||
// 姓名
|
||||
bodyTarget.Name = soulSource.Name;
|
||||
|
||||
// 故事 (背景和特性)
|
||||
bodyTarget.story.Childhood = soulSource.story.Childhood;
|
||||
bodyTarget.story.Adulthood = soulSource.story.Adulthood;
|
||||
// 先清空目标的所有特性,再逐一添加源的特性
|
||||
bodyTarget.story.traits.allTraits.Clear();
|
||||
foreach (Trait trait in soulSource.story.traits.allTraits)
|
||||
{
|
||||
bodyTarget.story.traits.GainTrait(trait);
|
||||
}
|
||||
|
||||
// 技能
|
||||
// 同样地,清空后逐一添加
|
||||
bodyTarget.skills.skills.Clear();
|
||||
foreach (SkillRecord skill in soulSource.skills.skills)
|
||||
{
|
||||
SkillRecord newSkill = new SkillRecord(bodyTarget, skill.def)
|
||||
{
|
||||
levelInt = skill.levelInt,
|
||||
xpSinceLastLevel = skill.xpSinceLastLevel,
|
||||
passion = skill.passion
|
||||
};
|
||||
bodyTarget.skills.skills.Add(newSkill);
|
||||
}
|
||||
|
||||
// 阵营
|
||||
if (bodyTarget.Faction != soulSource.Faction)
|
||||
{
|
||||
bodyTarget.SetFaction(soulSource.Faction, soulSource);
|
||||
}
|
||||
|
||||
// --- 2. 思想、社交和设定 ---
|
||||
|
||||
// 思想和记忆
|
||||
// 清空目标的记忆,然后复制源的记忆
|
||||
if (bodyTarget.needs.mood?.thoughts?.memories != null)
|
||||
{
|
||||
bodyTarget.needs.mood.thoughts.memories.Memories.Clear();
|
||||
}
|
||||
if (soulSource.needs.mood?.thoughts?.memories != null)
|
||||
{
|
||||
foreach (Thought_Memory memory in soulSource.needs.mood.thoughts.memories.Memories)
|
||||
{
|
||||
bodyTarget.needs.mood.thoughts.memories.TryGainMemory(memory);
|
||||
}
|
||||
}
|
||||
|
||||
// 工作设置
|
||||
if (soulSource.workSettings != null && bodyTarget.workSettings != null)
|
||||
{
|
||||
bodyTarget.workSettings.EnableAndInitialize();
|
||||
foreach (WorkTypeDef workDef in DefDatabase<WorkTypeDef>.AllDefs)
|
||||
{
|
||||
bodyTarget.workSettings.SetPriority(workDef, soulSource.workSettings.GetPriority(workDef));
|
||||
}
|
||||
}
|
||||
|
||||
// 时间表
|
||||
if (soulSource.timetable != null && bodyTarget.timetable != null)
|
||||
{
|
||||
bodyTarget.timetable.times = new List<TimeAssignmentDef>(soulSource.timetable.times);
|
||||
}
|
||||
|
||||
// 社交关系 (简化处理)
|
||||
// 警告: 直接复制关系可能很危险,这里采用清空再添加直接关系的方式
|
||||
if (soulSource.relations != null && bodyTarget.relations != null)
|
||||
{
|
||||
bodyTarget.relations.ClearAllRelations();
|
||||
foreach (DirectPawnRelation relation in soulSource.relations.DirectRelations)
|
||||
{
|
||||
bodyTarget.relations.AddDirectRelation(relation.def, relation.otherPawn);
|
||||
}
|
||||
}
|
||||
|
||||
// 访客/囚犯状态
|
||||
if (soulSource.guest != null && bodyTarget.guest != null)
|
||||
{
|
||||
// 使用游戏提供的标准方法来设置,而不是直接赋值
|
||||
bodyTarget.guest.SetGuestStatus(soulSource.guest.HostFaction, soulSource.guest.GuestStatus);
|
||||
if (soulSource.guest.IsPrisoner)
|
||||
{
|
||||
bodyTarget.guest.SetExclusiveInteraction(soulSource.guest.ExclusiveInteractionMode);
|
||||
}
|
||||
bodyTarget.guest.joinStatus = soulSource.guest.joinStatus;
|
||||
}
|
||||
|
||||
// --- 3. 收尾工作 ---
|
||||
|
||||
// 强制刷新Pawn的渲染缓存,确保外观(如名字)能立刻更新
|
||||
bodyTarget.Drawer.renderer.SetAllGraphicsDirty();
|
||||
|
||||
Log.Message("Soul transfer complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 `CompProperties_AbilityPossess.cs` - 技能属性类
|
||||
|
||||
这是一个简单的属性类,用于将我们的技能效果组件(`CompAbilityEffect_Possess`)连接到XML定义上。
|
||||
|
||||
```csharp
|
||||
// 路径: Source/ArachnaeSwarm/Possession/CompProperties_AbilityPossess.cs
|
||||
using RimWorld;
|
||||
|
||||
namespace ArachnaeSwarm.Possession
|
||||
{
|
||||
// CompProperties类用于在XML中配置Comp组件的参数
|
||||
public class CompProperties_AbilityPossess : CompProperties_AbilityEffect
|
||||
{
|
||||
public CompProperties_AbilityPossess()
|
||||
{
|
||||
// 将这个属性类与我们的技能效果实现类关联起来
|
||||
this.compClass = typeof(CompAbilityEffect_Possess);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. XML 定义详解
|
||||
|
||||
### 4.1 `ARA_Hediffs_Possession.xml` - 定义Hediff
|
||||
|
||||
```xml
|
||||
<!-- 路径: 1.6/1.6/Defs/HediffDefs/ARA_Hediffs_Possession.xml -->
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Defs>
|
||||
|
||||
<HediffDef>
|
||||
<!-- 内部唯一的定义名 -->
|
||||
<defName>ARA_Possession</defName>
|
||||
<!-- 游戏中显示的标签 -->
|
||||
<label>阿拉克涅原虫寄生</label>
|
||||
<!-- 鼠标悬浮时的描述 -->
|
||||
<description>这个生物的身体正被另一个实体所控制。</description>
|
||||
<!-- 关键:将这个XML定义与我们的C#实现类关联起来 -->
|
||||
<hediffClass>ArachnaeSwarm.Possession.Hediff_Possession</hediffClass>
|
||||
<!-- 其他标准Hediff属性 -->
|
||||
<isBad>false</isBad>
|
||||
<scenarioCanAdd>false</scenarioCanAdd>
|
||||
<maxSeverity>1.0</maxSeverity>
|
||||
<stages>
|
||||
<li>
|
||||
<label>被寄生</label>
|
||||
</li>
|
||||
</stages>
|
||||
</HediffDef>
|
||||
|
||||
</Defs>
|
||||
```
|
||||
|
||||
### 4.2 `ARA_Possession_Defs.xml` - 定义技能、种族和身体
|
||||
|
||||
这个文件定义了技能本身,以及我们的“阿拉克涅原虫”作为一个完整的生物所需的一切。
|
||||
|
||||
```xml
|
||||
<!-- 路径: 1.6/1.6/Defs/Misc/ARA_Possession_Defs.xml -->
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Defs>
|
||||
|
||||
<!-- ==================== 技能定义 ==================== -->
|
||||
<AbilityDef>
|
||||
<defName>ARA_Ability_Possess</defName>
|
||||
<label>阿拉克涅寄生</label>
|
||||
<description>将你的意识注入另一个生物的身体,完全占据它。</description>
|
||||
<iconPath>UI/Abilities/Possess</iconPath> <!-- TODO: 需要一张图标 -->
|
||||
<cooldownTicks>600</cooldownTicks>
|
||||
<verbProperties>
|
||||
<verbClass>Verb_CastAbility</verbClass>
|
||||
<warmupTime>1.5</warmupTime>
|
||||
<range>5.9</range>
|
||||
<targetParams>
|
||||
<canTargetPawns>true</canTargetPawns>
|
||||
<canTargetBuildings>false</canTargetBuildings>
|
||||
<canTargetSelf>false</canTargetSelf>
|
||||
<canTargetLocations>false</canTargetLocations>
|
||||
</targetParams>
|
||||
</verbProperties>
|
||||
<comps>
|
||||
<!-- 关键:将这个技能与我们的C#属性类关联起来 -->
|
||||
<li Class="ArachnaeSwarm.Possession.CompProperties_AbilityPossess"/>
|
||||
</comps>
|
||||
</AbilityDef>
|
||||
|
||||
<!-- ==================== 生物AI定义 (可选) ==================== -->
|
||||
<ThinkTreeDef>
|
||||
<defName>ARA_Facehugger</defName>
|
||||
<insertTag>Humanlike_PostMentalState</insertTag>
|
||||
<insertPriority>100</insertPriority>
|
||||
<thinkRoot Class="ThinkNode_Priority">
|
||||
<subNodes>
|
||||
<!-- 在这里可以为抱脸虫添加自定义AI,例如当它空闲时自动寻找宿主 -->
|
||||
</subNodes>
|
||||
</thinkRoot>
|
||||
</ThinkTreeDef>
|
||||
|
||||
<!-- ==================== 生物类型定义 ==================== -->
|
||||
<PawnKindDef>
|
||||
<defName>ARA_Facehugger</defName>
|
||||
<label>阿拉克涅原虫</label>
|
||||
<!-- 关联下面的种族定义 -->
|
||||
<race>ARA_FacehuggerRace</race>
|
||||
<combatPower>25</combatPower>
|
||||
<lifeStages>
|
||||
<li>
|
||||
<bodyGraphicData>
|
||||
<texPath>Things/Pawn/Animal/ARA_Facehugger</texPath> <!-- TODO: 需要贴图 -->
|
||||
<drawSize>0.8</drawSize>
|
||||
</bodyGraphicData>
|
||||
<dessicatedBodyGraphicData>
|
||||
<texPath>Things/Pawn/Animal/Dessicated/CritterDessicated</texPath>
|
||||
<drawSize>0.8</drawSize>
|
||||
</dessicatedBodyGraphicData>
|
||||
</li>
|
||||
</lifeStages>
|
||||
<aiThinkTree>ARA_Facehugger</aiThinkTree>
|
||||
<abilities>
|
||||
<!-- 赋予该生物我们的夺舍技能 -->
|
||||
<li>ARA_Ability_Possess</li>
|
||||
</abilities>
|
||||
</PawnKindDef>
|
||||
|
||||
<!-- ==================== 种族定义 ==================== -->
|
||||
<ThingDef ParentName="AnimalThingBase">
|
||||
<defName>ARA_FacehuggerRace</defName>
|
||||
<label>阿拉克涅原虫</label>
|
||||
<description>一种小型的、脆弱的寄生生物,其唯一的生存目的就是寻找并占据一个更强大的宿主。它通过将自己的意识注入目标来完成这一过程。</description>
|
||||
<statBases>
|
||||
<MoveSpeed>4.0</MoveSpeed>
|
||||
<MarketValue>50</MarketValue>
|
||||
<ComfyTemperatureMin>-10</ComfyTemperatureMin>
|
||||
<ComfyTemperatureMax>50</ComfyTemperatureMax>
|
||||
</statBases>
|
||||
<tools>
|
||||
<li>
|
||||
<label>tiny claws</label>
|
||||
<capacities>
|
||||
<li>Scratch</li>
|
||||
</capacities>
|
||||
<power>2</power>
|
||||
<cooldownTime>1.5</cooldownTime>
|
||||
</li>
|
||||
</tools>
|
||||
<race>
|
||||
<thinkTreeMain>Animal</thinkTreeMain>
|
||||
<!-- 关联下面的身体定义 -->
|
||||
<body>ARA_FacehuggerBody</body>
|
||||
<baseBodySize>0.2</baseBodySize>
|
||||
<baseHealthScale>0.3</baseHealthScale>
|
||||
<baseHungerRate>0.1</baseHungerRate>
|
||||
<lifeStageAges>
|
||||
<li>
|
||||
<def>AnimalAdult</def>
|
||||
<minAge>0</minAge>
|
||||
</li>
|
||||
</lifeStageAges>
|
||||
</race>
|
||||
</ThingDef>
|
||||
|
||||
<!-- ==================== 身体结构定义 ==================== -->
|
||||
<BodyDef>
|
||||
<defName>ARA_FacehuggerBody</defName>
|
||||
<label>facehugger</label>
|
||||
<corePart>
|
||||
<def>Body</def>
|
||||
<height>20</height>
|
||||
<depth>20</depth>
|
||||
<parts>
|
||||
<li>
|
||||
<def>Head</def>
|
||||
<coverage>0.3</coverage>
|
||||
<parts>
|
||||
<li>
|
||||
<def>Skull</def>
|
||||
<coverage>0.2</coverage>
|
||||
<depth>Inside</depth>
|
||||
<parts>
|
||||
<li>
|
||||
<def>Brain</def>
|
||||
<coverage>0.1</coverage>
|
||||
<depth>Inside</depth>
|
||||
</li>
|
||||
</parts>
|
||||
</li>
|
||||
<li>
|
||||
<def>Eye</def>
|
||||
<customLabel>left eye</customLabel>
|
||||
<coverage>0.07</coverage>
|
||||
</li>
|
||||
<li>
|
||||
<def>Eye</def>
|
||||
<customLabel>right eye</customLabel>
|
||||
<coverage>0.07</coverage>
|
||||
</li>
|
||||
</parts>
|
||||
</li>
|
||||
<li>
|
||||
<def>Leg</def>
|
||||
<customLabel>front left leg</customLabel>
|
||||
<coverage>0.1</coverage>
|
||||
</li>
|
||||
<li>
|
||||
<def>Leg</def>
|
||||
<customLabel>front right leg</customLabel>
|
||||
<coverage>0.1</coverage>
|
||||
</li>
|
||||
<li>
|
||||
<def>Leg</def>
|
||||
<customLabel>rear left leg</customLabel>
|
||||
<coverage>0.1</coverage>
|
||||
</li>
|
||||
<li>
|
||||
<def>Leg</def>
|
||||
<customLabel>rear right leg</customLabel>
|
||||
<coverage>0.1</coverage>
|
||||
</li>
|
||||
</parts>
|
||||
</corePart>
|
||||
</BodyDef>
|
||||
|
||||
</Defs>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
这份详尽的文档现在包含了我们所有的最终代码和XML,并附有详细的注释,解释了每一步的作用和它们之间的关联。
|
||||
Reference in New Issue
Block a user