diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 9e1a2e1..6832e8c 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/JobDefs/ARA_Jobs_Wormhole.xml b/1.6/1.6/Defs/JobDefs/ARA_Jobs_Wormhole.xml
index be5bd2f..e619ef0 100644
--- a/1.6/1.6/Defs/JobDefs/ARA_Jobs_Wormhole.xml
+++ b/1.6/1.6/Defs/JobDefs/ARA_Jobs_Wormhole.xml
@@ -4,7 +4,7 @@
ARA_DeployWormhole
ArachnaeSwarm.JobDriver_DeployWormhole
- deploying wormhole.
+ 正在部署虫洞。
true
diff --git a/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml b/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
index 699bcd6..995fca1 100644
--- a/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
+++ b/1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
@@ -4,19 +4,18 @@
ARA_WormholePortal_A
-
- The primary control unit of a wormhole network. It can launch a secondary portal to a distant location, establishing a stable connection.
+
+ 阿拉克涅虫洞网络的主体组成部分。它可以向远方发射尾巴作为虫洞出口,它是阿拉克涅坑道虫头部的一部分,装入虫洞的物体会被坑道虫加压移动从而快速旅行,虫洞允许双向通行。
ArachnaeSwarm.Building_WormholePortal_A
- Things/Building/Misc/LongRangeMineralScanner
- Graphic_Multi
- (4,4)
-
- Damage/Corner
- Damage/Corner
- Damage/Corner
- Damage/Corner
-
+ ArachnaeSwarm/Building/ARA_Wormhole_A
+ Graphic_Single
+ CutoutComplex
+ (2.2,2.2)
+
+ (1.6, 0.5, 1.6)
+ (0,0,-0.1)
+
Building
Impassable
@@ -35,10 +34,6 @@
6
-
- CompPowerTrader
- 500
-
500.0
@@ -52,11 +47,10 @@
true
- 50
- 100
+ 2.5
- Misc
+ ARA_Buildings
false
@@ -68,14 +62,18 @@
ARA_WormholePortal_B
-
- A remotely deployed secondary portal. It is linked to a primary portal (A) and allows for two-way travel.
+
+ 一个被远程部署的虫洞出口。它是阿拉克涅坑道虫尾巴的一部分,装入虫洞的物体会被坑道虫加压移动从而快速旅行,虫洞允许双向通行。
ArachnaeSwarm.Building_WormholePortal_B
- Things/Building/Misc/LongRangeMineralScanner
- Graphic_Multi
- (150, 150, 250)
- (4,4)
+ ArachnaeSwarm/Building/ARA_Wormhole_B
+ Graphic_Single
+ CutoutComplex
+ (2.2,2.2)
+
+ (1.6, 0.5, 1.6)
+ (0,0,-0.1)
+
Building
Impassable
@@ -85,10 +83,6 @@
(2,2)
-
- CompPowerTrader
- 200
-
None
diff --git a/1.6/1.6/Defs/WorldObjectDefs/ARA_Wormhole_WorldObjects.xml b/1.6/1.6/Defs/WorldObjectDefs/ARA_Wormhole_WorldObjects.xml
new file mode 100644
index 0000000..7e27f22
--- /dev/null
+++ b/1.6/1.6/Defs/WorldObjectDefs/ARA_Wormhole_WorldObjects.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ ARA_TravelingWormhole
+
+ ArachnaeSwarm.TravelingWormhole
+ World/WorldObjects/Caravan
+ true
+ true
+ World/WorldObjects/Expanding/Caravan
+ 100
+ true
+
+
+ 10
+
+
+
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Wormhole_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Wormhole_Keys.xml
new file mode 100644
index 0000000..12fc1e7
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Wormhole_Keys.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ 部署虫洞传送门
+ 选择一名驾驶员来启动一个B端传送门。
+ 没有可用的驾驶员
+
+
\ No newline at end of file
diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Wormhole_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Wormhole_Keys.xml
new file mode 100644
index 0000000..12fc1e7
--- /dev/null
+++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Wormhole_Keys.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ 部署虫洞传送门
+ 选择一名驾驶员来启动一个B端传送门。
+ 没有可用的驾驶员
+
+
\ No newline at end of file
diff --git a/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_A.png b/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_A.png
new file mode 100644
index 0000000..34706c0
Binary files /dev/null and b/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_A.png differ
diff --git a/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_B.png b/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_B.png
new file mode 100644
index 0000000..392f68d
Binary files /dev/null and b/Content/Textures/ArachnaeSwarm/Building/ARA_Wormhole_B.png differ
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 874f0b2..d70bb6c 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -210,6 +210,8 @@
+
+
diff --git a/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs b/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs
index ab64112..e50fb9a 100644
--- a/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs
+++ b/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs
@@ -137,59 +137,21 @@ namespace ArachnaeSwarm
}
}
- public override IEnumerable GetFloatMenuOptions(Pawn selPawn)
- {
- foreach (var option in base.GetFloatMenuOptions(selPawn))
- {
- yield return option;
- }
-
- if (status == WormholePortalStatus.Linked)
- {
- yield break;
- }
-
- if (!selPawn.CanReach(this, PathEndMode.Touch, Danger.Deadly))
- {
- yield return new FloatMenuOption("CannotUseNoPath".Translate(), null);
- yield break;
- }
-
- var compLaunchable = this.GetComp();
- var compRefuelable = this.GetComp();
-
- if (compRefuelable.Fuel < compLaunchable.Props.fuelNeededToLaunch)
- {
- yield return new FloatMenuOption("CommandDeployWormholePortalB_Pilot".Translate() + " (" + "NotEnoughFuel".Translate() + ")", null);
- yield break;
- }
-
- // TODO: Create ARA_DeployWormhole JobDef
- var jobDef = DefDatabase.GetNamed("ARA_DeployWormhole", false);
- if (jobDef == null)
- {
- yield return new FloatMenuOption("DEV: JobDef ARA_DeployWormhole not found", null);
- yield break;
- }
-
- void action()
- {
- var job = JobMaker.MakeJob(jobDef, this);
- selPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
- }
-
- yield return new FloatMenuOption("CommandDeployWormholePortalB_Pilot".Translate(), action);
- }
public override string GetInspectString()
{
- string text = base.GetInspectString();
- text += "\n" + "Status".Translate() + ": " + status.ToString().Translate();
+ System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
+ stringBuilder.Append(base.GetInspectString());
+
+ if (stringBuilder.Length > 0) stringBuilder.AppendLine();
+ stringBuilder.Append("Status".Translate() + ": " + status.ToString().Translate());
+
if (linkedPortalB != null && !linkedPortalB.Destroyed)
{
- text += "\n" + "LinkedTo".Translate() + ": " + linkedPortalB.Map.Parent.LabelCap;
+ stringBuilder.AppendLine();
+ stringBuilder.Append("LinkedTo".Translate() + ": " + linkedPortalB.Map.Parent.LabelCap);
}
- return text;
+ return stringBuilder.ToString();
}
}
diff --git a/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs b/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs
index 7117118..0c25494 100644
--- a/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs
+++ b/Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs
@@ -106,16 +106,20 @@ namespace ArachnaeSwarm
public override string GetInspectString()
{
- string text = base.GetInspectString();
+ System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder();
+ stringBuilder.Append(base.GetInspectString());
+
if (linkedPortalA != null && !linkedPortalA.Destroyed)
{
- text += "\n" + "LinkedTo".Translate() + ": " + linkedPortalA.Map.Parent.LabelCap;
+ if (stringBuilder.Length > 0) stringBuilder.AppendLine();
+ stringBuilder.Append("LinkedTo".Translate() + ": " + linkedPortalA.Map.Parent.LabelCap);
}
else
{
- text += "\n" + "ConnectionLost".Translate();
+ if (stringBuilder.Length > 0) stringBuilder.AppendLine();
+ stringBuilder.Append("ConnectionLost".Translate());
}
- return text;
+ return stringBuilder.ToString();
}
}
diff --git a/Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs b/Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs
index 6501727..d28c6cb 100644
--- a/Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs
+++ b/Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs
@@ -1,8 +1,10 @@
using System.Collections.Generic;
+using System.Linq;
using RimWorld;
using RimWorld.Planet;
using UnityEngine;
using Verse;
+using Verse.AI;
namespace ArachnaeSwarm
{
@@ -21,8 +23,49 @@ namespace ArachnaeSwarm
public override IEnumerable CompGetGizmosExtra()
{
- // The gizmo is now replaced by a float menu option.
- yield break;
+ if (PortalA?.status == WormholePortalStatus.Linked)
+ {
+ yield break;
+ }
+
+ Command_Action launchCommand = new Command_Action();
+ launchCommand.defaultLabel = "CommandDeployWormholePortalB_Pilot".Translate();
+ launchCommand.defaultDesc = "CommandDeployWormholePortalB_PilotDesc".Translate();
+ launchCommand.icon = ContentFinder.Get("UI/Commands/LaunchShip");
+
+ // Fuel check is now more complex, we can show max range or check on target selection.
+ // For simplicity, we'll disable if there's basically no fuel.
+ if (refuelableComp.Fuel < Props.fuelPerTile)
+ {
+ launchCommand.Disable("NotEnoughFuel".Translate());
+ }
+
+ List pilots = parent.Map.mapPawns.AllPawnsSpawned
+ .Where(p => p.IsColonistPlayerControlled && !p.Downed && !p.IsBurning() && p.CanReach(parent, PathEndMode.Touch, Danger.Deadly))
+ .ToList();
+
+ if (!pilots.Any())
+ {
+ launchCommand.Disable("NoPilotAvailable".Translate());
+ }
+
+ launchCommand.action = delegate
+ {
+ List options = new List();
+ foreach (Pawn p in pilots)
+ {
+ void pilotAction()
+ {
+ var jobDef = DefDatabase.GetNamed("ARA_DeployWormhole");
+ var job = JobMaker.MakeJob(jobDef, parent);
+ p.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+ }
+ options.Add(new FloatMenuOption(p.LabelCap, pilotAction));
+ }
+ Find.WindowStack.Add(new FloatMenu(options));
+ };
+
+ yield return launchCommand;
}
public void StartChoosingDestination(Pawn pilot)
@@ -30,13 +73,14 @@ namespace ArachnaeSwarm
CameraJumper.TryJump(CameraJumper.GetWorldTarget(this.parent));
Find.WorldSelector.ClearSelection();
int tile = this.parent.Map.Tile;
- Find.WorldTargeter.BeginTargeting((GlobalTargetInfo t) => ChoseWorldTarget(t, pilot), true, CompLaunchable.TargeterMouseAttachment, true, delegate
+ int maxDist = (int)(refuelableComp.Fuel / Props.fuelPerTile);
+ Find.WorldTargeter.BeginTargeting((GlobalTargetInfo t) => ChoseWorldTarget(t, pilot, maxDist), true, CompLaunchable.TargeterMouseAttachment, true, delegate
{
- GenDraw.DrawWorldRadiusRing(tile, this.Props.maxLaunchDistance);
+ GenDraw.DrawWorldRadiusRing(tile, maxDist);
}, (GlobalTargetInfo t) => "Select target tile");
}
- private bool ChoseWorldTarget(GlobalTargetInfo t, Pawn pilot)
+ private bool ChoseWorldTarget(GlobalTargetInfo t, Pawn pilot, int maxDist)
{
if (!t.IsValid)
{
@@ -49,51 +93,35 @@ namespace ArachnaeSwarm
return false;
}
- MapParent mapParent = Find.World.worldObjects.MapParentAt(t.Tile);
- if (mapParent?.HasMap ?? false)
+ int distance = Find.WorldGrid.TraversalDistanceBetween(parent.Map.Tile, t.Tile, true);
+ if (distance > maxDist)
{
- Deploy(mapParent, pilot);
- }
- else
- {
- LongEventHandler.QueueLongEvent(delegate
- {
- var newMap = GetOrGenerateMapUtility.GetOrGenerateMap(t.Tile, WorldObjectDefOf.Camp);
- Deploy(newMap.Parent, pilot);
- }, "GeneratingMap", doAsynchronously: false, null);
+ Messages.Message("NotEnoughFuel".Translate(), MessageTypeDefOf.RejectInput);
+ return false;
}
- return true;
- }
-
- private void Deploy(MapParent mapParent, Pawn pilot)
- {
- refuelableComp.ConsumeFuel(this.Props.fuelNeededToLaunch);
+ float fuelCost = distance * Props.fuelPerTile;
+ refuelableComp.ConsumeFuel(fuelCost);
- // 传送驾驶员
+ // Despawn pilot from the source map
pilot.DeSpawn();
EffecterDefOf.Skip_Entry.Spawn(this.parent.Position, this.parent.Map);
- Building_WormholePortal_B portalB = (Building_WormholePortal_B)ThingMaker.MakeThing(ThingDef.Named("ARA_WormholePortal_B"));
- IntVec3 cell = DropCellFinder.RandomDropSpot(mapParent.Map);
- GenSpawn.Spawn(portalB, cell, mapParent.Map, WipeMode.Vanish);
-
- // 在B端生成驾驶员
- IntVec3 pilotSpawnCell = CellFinder.RandomSpawnCellForPawnNear(portalB.Position, mapParent.Map, 5);
- GenSpawn.Spawn(pilot, pilotSpawnCell, mapParent.Map, WipeMode.Vanish);
-
- EffecterDefOf.Skip_Exit.Spawn(cell, mapParent.Map);
+ // Create the traveling object
+ var travelingWormhole = (TravelingWormhole)WorldObjectMaker.MakeWorldObject(DefDatabase.GetNamed("ARA_TravelingWormhole"));
+ travelingWormhole.sourcePortal = this.PortalA;
+ travelingWormhole.StartMove(parent.Map.Tile, t.Tile, pilot);
- PortalA.SetLinkedPortal(portalB);
- portalB.SetLinkedPortal(PortalA);
+ Find.WorldObjects.Add(travelingWormhole);
+
+ return true;
}
}
public class CompProperties_LaunchableWormhole : CompProperties
{
- public float fuelNeededToLaunch;
- public int maxLaunchDistance;
+ public float fuelPerTile = 1f; // Default fuel cost per tile
public CompProperties_LaunchableWormhole()
{
diff --git a/Source/ArachnaeSwarm/Wormhole/DefModExtension_TravelingWormhole.cs b/Source/ArachnaeSwarm/Wormhole/DefModExtension_TravelingWormhole.cs
new file mode 100644
index 0000000..532ff50
--- /dev/null
+++ b/Source/ArachnaeSwarm/Wormhole/DefModExtension_TravelingWormhole.cs
@@ -0,0 +1,9 @@
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ public class DefModExtension_TravelingWormhole : DefModExtension
+ {
+ public float travelSpeed = 20f; // Default speed in tiles per day
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Wormhole/TravelingWormhole.cs b/Source/ArachnaeSwarm/Wormhole/TravelingWormhole.cs
new file mode 100644
index 0000000..3c4258a
--- /dev/null
+++ b/Source/ArachnaeSwarm/Wormhole/TravelingWormhole.cs
@@ -0,0 +1,97 @@
+using RimWorld;
+using RimWorld.Planet;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ [StaticConstructorOnStartup]
+ public class TravelingWormhole : WorldObject, IThingHolder
+ {
+ public Building_WormholePortal_A sourcePortal;
+ public int destinationTile;
+
+ private int initialTile;
+ private float traveledPct;
+
+ private ThingOwner contents;
+
+ public override Material Material => def.Material;
+
+ public override Vector3 DrawPos => Vector3.Slerp(
+ Find.WorldGrid.GetTileCenter(initialTile),
+ Find.WorldGrid.GetTileCenter(destinationTile),
+ traveledPct);
+
+ public TravelingWormhole()
+ {
+ contents = new ThingOwner(this, true, LookMode.Deep);
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_References.Look(ref sourcePortal, "sourcePortal");
+ Scribe_Values.Look(ref destinationTile, "destinationTile", 0);
+ Scribe_Values.Look(ref initialTile, "initialTile", 0);
+ Scribe_Values.Look(ref traveledPct, "traveledPct", 0f);
+ Scribe_Deep.Look(ref contents, "contents", this);
+ }
+
+ public void StartMove(int startTile, int destTile, Pawn pilot)
+ {
+ initialTile = startTile;
+ destinationTile = destTile;
+
+ this.Tile = startTile;
+ contents.TryAdd(pilot, true);
+ }
+
+ protected override void Tick()
+ {
+ base.Tick();
+ var speed = def.GetModExtension()?.travelSpeed ?? 20f;
+ traveledPct += (1f / GenDate.TicksPerDay) * speed;
+ if (traveledPct >= 1f)
+ {
+ traveledPct = 1f;
+ Arrived();
+ }
+ }
+
+ private void Arrived()
+ {
+ if (contents.Any)
+ {
+ Pawn pilot = contents.First() as Pawn;
+ if (pilot != null)
+ {
+ Map targetMap = GetOrGenerateMapUtility.GetOrGenerateMap(destinationTile, null);
+
+ Building_WormholePortal_B portalB = (Building_WormholePortal_B)ThingMaker.MakeThing(ThingDef.Named("ARA_WormholePortal_B"));
+ IntVec3 cell = DropCellFinder.RandomDropSpot(targetMap);
+ GenSpawn.Spawn(portalB, cell, targetMap, WipeMode.Vanish);
+
+ IntVec3 pilotSpawnCell = CellFinder.RandomClosewalkCellNear(portalB.Position, targetMap, 5);
+ GenSpawn.Spawn(pilot, pilotSpawnCell, targetMap, WipeMode.Vanish);
+
+ contents.Remove(pilot);
+
+ EffecterDefOf.Skip_Exit.Spawn(cell, targetMap);
+
+ if (sourcePortal != null && !sourcePortal.Destroyed)
+ {
+ sourcePortal.SetLinkedPortal(portalB);
+ portalB.SetLinkedPortal(sourcePortal);
+ }
+ }
+ }
+ Find.WorldObjects.Remove(this);
+ }
+
+ public ThingOwner GetDirectlyHeldThings() => contents;
+ public void GetChildHolders(List outChildren) => ThingOwnerUtility.AppendThingHoldersFromThings(outChildren, GetDirectlyHeldThings());
+ }
+}
\ No newline at end of file