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