diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 59b7d73..29adbd5 100644
Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ
diff --git a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
index cd192df..c72e24d 100644
--- a/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
+++ b/1.6/1.6/Defs/AbilityDefs/ARA_Abilities.xml
@@ -26,6 +26,15 @@
ARA_Proj_EggSac
+
+ Food
+ 4
+ 食物不足
+
+
+ ARA_Ovary
+ 卵巢受损或缺失,无法生育
+
@@ -59,6 +68,11 @@
32
3
+
+ Food
+ 0.5
+ 食物不足
+
diff --git a/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml b/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
index 7a842ab..844e66b 100644
--- a/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
+++ b/1.6/1.6/Defs/BodyAndPartDefs/ARA_Bodyparts.xml
@@ -14,7 +14,7 @@
ARA_Dorsum
- 0.036
+ 0
Torso
@@ -42,7 +42,7 @@
ARA_Sternum
- 0.036
+ 0
Torso
@@ -154,7 +154,7 @@
ARA_Tail
- 0.025
+ 0
Bottom
Inside
@@ -355,6 +355,7 @@
true
Hands
+ HeadClaw
@@ -410,6 +411,7 @@
true
Hands
+ HeadClaw
diff --git a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
index 31c8b5c..27c43c8 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml
@@ -33,6 +33,7 @@
true
false
+
6
@@ -47,8 +48,13 @@
ARA_ArachnaeQueen
- 300
+ 300
true
+
+ Things/Building/Natural/Hive
+ Graphic_Random
+ 1.6
+
CocoonDestroyed
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 1ee6c58..115002f 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -73,7 +73,10 @@
+
+
+
diff --git a/Source/ArachnaeSwarm/Building_Incubator.cs b/Source/ArachnaeSwarm/Building_Incubator.cs
new file mode 100644
index 0000000..cb2e948
--- /dev/null
+++ b/Source/ArachnaeSwarm/Building_Incubator.cs
@@ -0,0 +1,22 @@
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class Building_Incubator : Building
+ {
+ public CompSpawnPawnFromList SpawnComp => GetComp();
+
+ public override Graphic Graphic
+ {
+ get
+ {
+ if (SpawnComp != null && SpawnComp.IsHatching && SpawnComp.Props.hatchingGraphicData != null)
+ {
+ return SpawnComp.Props.hatchingGraphicData.Graphic;
+ }
+ return base.Graphic;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompAbilityEffect_BodyPartCheck.cs b/Source/ArachnaeSwarm/CompAbilityEffect_BodyPartCheck.cs
new file mode 100644
index 0000000..91ab139
--- /dev/null
+++ b/Source/ArachnaeSwarm/CompAbilityEffect_BodyPartCheck.cs
@@ -0,0 +1,49 @@
+using System.Linq;
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_AbilityBodyPartCheck : CompProperties_AbilityEffect
+ {
+ public BodyPartDef requiredPart;
+ public float minimumHealth = 0.8f;
+ public string failMessage = "Missing or damaged body part.";
+
+ public CompProperties_AbilityBodyPartCheck()
+ {
+ compClass = typeof(CompAbilityEffect_BodyPartCheck);
+ }
+ }
+
+ public class CompAbilityEffect_BodyPartCheck : CompAbilityEffect
+ {
+ public new CompProperties_AbilityBodyPartCheck Props => (CompProperties_AbilityBodyPartCheck)props;
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ Pawn caster = parent.pawn;
+ if (caster != null && caster.health != null && caster.health.hediffSet != null)
+ {
+ var part = caster.health.hediffSet.GetNotMissingParts()
+ .FirstOrDefault(p => p.def == Props.requiredPart);
+
+ if (part == null)
+ {
+ reason = Props.failMessage;
+ return true;
+ }
+
+ float partHealth = caster.health.hediffSet.GetPartHealth(part) / part.def.GetMaxHealth(caster);
+ if (partHealth < Props.minimumHealth)
+ {
+ reason = Props.failMessage;
+ return true;
+ }
+ }
+
+ reason = null;
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompAbilityEffect_NeedCost.cs b/Source/ArachnaeSwarm/CompAbilityEffect_NeedCost.cs
new file mode 100644
index 0000000..41613ba
--- /dev/null
+++ b/Source/ArachnaeSwarm/CompAbilityEffect_NeedCost.cs
@@ -0,0 +1,54 @@
+using RimWorld;
+using RimWorld.Planet;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_AbilityNeedCost : CompProperties_AbilityEffect
+ {
+ public NeedDef needDef;
+ public float needCost;
+ public string failMessage;
+
+ public CompProperties_AbilityNeedCost()
+ {
+ compClass = typeof(CompAbilityEffect_NeedCost);
+ }
+ }
+
+ public class CompAbilityEffect_NeedCost : CompAbilityEffect
+ {
+ public new CompProperties_AbilityNeedCost Props => (CompProperties_AbilityNeedCost)props;
+
+ public override bool GizmoDisabled(out string reason)
+ {
+ Pawn caster = parent.pawn;
+ if (caster != null && caster.needs != null)
+ {
+ if (caster.needs.TryGetNeed(Props.needDef, out Need need))
+ {
+ if (need.CurLevel < Props.needCost)
+ {
+ reason = Props.failMessage;
+ return true;
+ }
+ }
+ }
+ reason = null;
+ return false;
+ }
+
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+ Pawn caster = parent.pawn;
+ if (caster != null && caster.needs != null)
+ {
+ if (caster.needs.TryGetNeed(Props.needDef, out Need need))
+ {
+ need.CurLevel -= Props.needCost;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompProperties_SpawnPawnFromList.cs b/Source/ArachnaeSwarm/CompProperties_SpawnPawnFromList.cs
index efef87f..c69bf18 100644
--- a/Source/ArachnaeSwarm/CompProperties_SpawnPawnFromList.cs
+++ b/Source/ArachnaeSwarm/CompProperties_SpawnPawnFromList.cs
@@ -13,6 +13,7 @@ namespace ArachnaeSwarm
public bool destroyOnSpawn = false;
public IntRange spawnCount = new IntRange(1, 1);
public Type lordJob;
+ public GraphicData hatchingGraphicData;
public CompProperties_SpawnPawnFromList()
{
diff --git a/Source/ArachnaeSwarm/CompSpawnPawnFromList.cs b/Source/ArachnaeSwarm/CompSpawnPawnFromList.cs
index 07027e4..ce05723 100644
--- a/Source/ArachnaeSwarm/CompSpawnPawnFromList.cs
+++ b/Source/ArachnaeSwarm/CompSpawnPawnFromList.cs
@@ -13,6 +13,7 @@ namespace ArachnaeSwarm
private int spawnUntilTick = -1;
private PawnKindDef spawningPawnKind;
private PawnKindDef selectedPawnKind;
+ public bool IsHatching => spawnUntilTick > 0;
public override IEnumerable CompFloatMenuOptions(Pawn selPawn)
{
@@ -40,6 +41,7 @@ namespace ArachnaeSwarm
}
}
+
public void StartIncubation()
{
spawningPawnKind = selectedPawnKind;
@@ -55,6 +57,8 @@ namespace ArachnaeSwarm
}
}
+
+
private void SpawnPawn(PawnKindDef pawnKind)
{
try
@@ -71,34 +75,38 @@ namespace ArachnaeSwarm
return;
}
- Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKind, parent.Faction));
- if (pawn == null)
+ int count = Props.spawnCount.RandomInRange;
+ for (int i = 0; i < count; i++)
{
- Log.Error($"CompSpawnPawnFromList: Failed to generate pawn of kind {pawnKind.defName} for faction {parent.Faction?.Name ?? "null"}.");
- return;
- }
-
- if (GenSpawn.Spawn(pawn, parent.Position, parent.Map) == null)
- {
- Log.Error($"CompSpawnPawnFromList: Failed to spawn pawn {pawn} at {parent.Position}.");
- if (!pawn.Destroyed)
+ Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKind, parent.Faction));
+ if (pawn == null)
{
- pawn.Destroy();
+ Log.Error($"CompSpawnPawnFromList: Failed to generate pawn of kind {pawnKind.defName} for faction {parent.Faction?.Name ?? "null"}.");
+ continue;
}
- return;
- }
- if (Props.lordJob != null)
- {
- try
+ if (GenSpawn.Spawn(pawn, parent.Position, parent.Map) == null)
{
- LordJob lordJobInstance = (LordJob)System.Activator.CreateInstance(Props.lordJob);
- Lord lord = LordMaker.MakeNewLord(parent.Faction, lordJobInstance, parent.Map);
- lord.AddPawn(pawn);
+ Log.Error($"CompSpawnPawnFromList: Failed to spawn pawn {pawn} at {parent.Position}.");
+ if (!pawn.Destroyed)
+ {
+ pawn.Destroy();
+ }
+ continue;
}
- catch (System.Exception e)
+
+ if (Props.lordJob != null)
{
- Log.Error($"CompSpawnPawnFromList: Error creating LordJob {Props.lordJob?.Name ?? "null"} or assigning pawn {pawn}. Exception: {e}");
+ try
+ {
+ LordJob lordJobInstance = (LordJob)System.Activator.CreateInstance(Props.lordJob);
+ Lord lord = LordMaker.MakeNewLord(parent.Faction, lordJobInstance, parent.Map);
+ lord.AddPawn(pawn);
+ }
+ catch (System.Exception e)
+ {
+ Log.Error($"CompSpawnPawnFromList: Error creating LordJob {Props.lordJob?.Name ?? "null"} or assigning pawn {pawn}. Exception: {e}");
+ }
}
}
@@ -114,6 +122,7 @@ namespace ArachnaeSwarm
}
}
+
public override string CompInspectStringExtra()
{
if (spawnUntilTick > 0)
@@ -136,6 +145,7 @@ namespace ArachnaeSwarm
base.PostExposeData();
Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1);
Scribe_Defs.Look(ref spawningPawnKind, "spawningPawnKind");
+ Scribe_Defs.Look(ref selectedPawnKind, "selectedPawnKind");
}
}
}
\ No newline at end of file
diff --git a/Source/Documents/Project_Summary.md b/Source/Documents/Project_Summary.md
new file mode 100644
index 0000000..605fe2a
--- /dev/null
+++ b/Source/Documents/Project_Summary.md
@@ -0,0 +1,38 @@
+# 项目:可交互的虫卵囊
+
+## 1. 核心目标
+
+创建一个可交互的虫卵囊,它允许一个特定的 Pawn(阿拉克涅女皇种)通过右键菜单与它交互,从一个可配置的列表中选择一个 Pawn,并在经过一段可配置的延迟后,生成这个 Pawn。
+
+## 2. 已完成的功能
+
+* **创建了新的 VS 项目**: [`ArachnaeSwarm.csproj`](Source/ArachnaeSwarm/ArachnaeSwarm.csproj)
+* **实现了核心的生成逻辑**:
+ * `CompProperties_SpawnPawnFromList.cs`: 定义了 XML 中可配置的属性,包括:
+ * `pawnKinds`: 可生成的 Pawn 列表。
+ * `whitelist`: 可以与虫卵囊交互的 Pawn 列表。
+ * `delay`: 孵化延迟。
+ * `spawnCount`: 生成数量。
+ * `destroyOnSpawn`: 生成后是否摧毁自身。
+ * `lordJob`: 生成的 Pawn 要执行的集体任务。
+ * `CompSpawnPawnFromList.cs`: 实现了核心的生成逻辑,包括:
+ * 生成右键菜单。
+ * 处理孵化倒计时。
+ * 生成指定数量的 Pawn。
+ * 在检查面板上显示孵化状态和提示信息。
+* **实现了交互的 Job**:
+ * `ARA_Jobs.xml`: 定义了 `ARA_IncubateJob`。
+ * `JobDriver_Incubate.cs`: 实现了让 Pawn 走到虫卵囊旁边并启动孵化过程的逻辑。
+* **实现了动态的图形切换**:
+ * `Building_Incubator.cs`: 创建了一个新的建筑基类,它会根据虫卵囊是否正在孵化来动态地改变自身的图形。
+* **创建了测试用的 Defs**:
+ * `ARA_InteractiveEggSac.xml`: 定义了一个可交互的虫卵囊,用于在游戏中测试新功能。
+ * `ArachnaeSwarm_Keys.xml`: 定义了相关的本地化 `key`。
+
+## 3. 当前状态
+
+目前,项目已经基本完成了所有的核心功能,并且能够成功编译。但是,在最后一次构建时,我们遇到了一个编译错误,导致我们无法进行最终的测试。
+
+## 4. 下一步计划
+
+解决当前的编译错误,并成功构建项目,以便在游戏中进行最终的测试。
\ No newline at end of file