虫洞1
This commit is contained in:
Binary file not shown.
98
1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
Normal file
98
1.6/1.6/Defs/Thing_building/ARA_WormholeDefs.xml
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<!-- ==================== A端传送门 ==================== -->
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>ARA_WormholePortal_A</defName>
|
||||||
|
<label>wormhole portal (A)</label>
|
||||||
|
<description>The primary control unit of a wormhole network. It can launch a secondary portal to a distant location, establishing a stable connection.</description>
|
||||||
|
<thingClass>ArachnaeSwarm.Building_WormholePortal_A</thingClass>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/Misc/LongRangeMineralScanner</texPath>
|
||||||
|
<graphicClass>Graphic_Multi</graphicClass>
|
||||||
|
<drawSize>(4,4)</drawSize>
|
||||||
|
<damageData>
|
||||||
|
<cornerTL>Damage/Corner</cornerTL>
|
||||||
|
<cornerTR>Damage/Corner</cornerTR>
|
||||||
|
<cornerBL>Damage/Corner</cornerBL>
|
||||||
|
<cornerBR>Damage/Corner</cornerBR>
|
||||||
|
</damageData>
|
||||||
|
</graphicData>
|
||||||
|
<altitudeLayer>Building</altitudeLayer>
|
||||||
|
<passability>Impassable</passability>
|
||||||
|
<tickerType>Normal</tickerType>
|
||||||
|
<category>Building</category>
|
||||||
|
<pathCost>50</pathCost>
|
||||||
|
<fillPercent>0.5</fillPercent>
|
||||||
|
<statBases>
|
||||||
|
<MaxHitPoints>250</MaxHitPoints>
|
||||||
|
<WorkToBuild>8000</WorkToBuild>
|
||||||
|
<Flammability>0.5</Flammability>
|
||||||
|
<Mass>100</Mass>
|
||||||
|
</statBases>
|
||||||
|
<size>(2,2)</size>
|
||||||
|
<costList>
|
||||||
|
<Plasteel>100</Plasteel>
|
||||||
|
<ComponentSpacer>6</ComponentSpacer>
|
||||||
|
</costList>
|
||||||
|
<comps>
|
||||||
|
<li Class="CompProperties_Power">
|
||||||
|
<compClass>CompPowerTrader</compClass>
|
||||||
|
<basePowerConsumption>500</basePowerConsumption>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_Flickable"/>
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_RefuelableNutrition">
|
||||||
|
<fuelCapacity>500.0</fuelCapacity>
|
||||||
|
<fuelFilter>
|
||||||
|
<thingDefs>
|
||||||
|
<li>ARA_InsectJelly</li>
|
||||||
|
</thingDefs>
|
||||||
|
</fuelFilter>
|
||||||
|
<fuelGizmoLabel>虫蜜</fuelGizmoLabel>
|
||||||
|
<showAllowAutoRefuelToggle>true</showAllowAutoRefuelToggle>
|
||||||
|
<targetFuelLevelConfigurable>true</targetFuelLevelConfigurable>
|
||||||
|
</li>
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_LaunchableWormhole">
|
||||||
|
<fuelNeededToLaunch>50</fuelNeededToLaunch>
|
||||||
|
<maxLaunchDistance>100</maxLaunchDistance>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
<designationCategory>Misc</designationCategory>
|
||||||
|
<building>
|
||||||
|
<ai_chillDestination>false</ai_chillDestination>
|
||||||
|
</building>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
<!-- ==================== B端传送门 ==================== -->
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>ARA_WormholePortal_B</defName>
|
||||||
|
<label>wormhole portal (B)</label>
|
||||||
|
<description>A remotely deployed secondary portal. It is linked to a primary portal (A) and allows for two-way travel.</description>
|
||||||
|
<thingClass>ArachnaeSwarm.Building_WormholePortal_B</thingClass>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/Misc/LongRangeMineralScanner</texPath>
|
||||||
|
<graphicClass>Graphic_Multi</graphicClass>
|
||||||
|
<color>(150, 150, 250)</color> <!-- A different color to distinguish -->
|
||||||
|
<drawSize>(4,4)</drawSize>
|
||||||
|
</graphicData>
|
||||||
|
<altitudeLayer>Building</altitudeLayer>
|
||||||
|
<passability>Impassable</passability>
|
||||||
|
<statBases>
|
||||||
|
<MaxHitPoints>250</MaxHitPoints>
|
||||||
|
<Flammability>0.5</Flammability>
|
||||||
|
</statBases>
|
||||||
|
<size>(2,2)</size>
|
||||||
|
<comps>
|
||||||
|
<li Class="CompProperties_Power">
|
||||||
|
<compClass>CompPowerTrader</compClass>
|
||||||
|
<basePowerConsumption>200</basePowerConsumption>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_Flickable"/>
|
||||||
|
</comps>
|
||||||
|
<tradeability>None</tradeability>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
<!-- CompProperties for our custom launchable -->
|
||||||
|
<!-- This is referenced by the li Class above -->
|
||||||
|
|
||||||
|
</Defs>
|
||||||
@@ -205,6 +205,15 @@
|
|||||||
<Compile Include="ARAFoodDispenserProperties.cs" />
|
<Compile Include="ARAFoodDispenserProperties.cs" />
|
||||||
<Compile Include="Patch_DispenserFoodSearch.cs" />
|
<Compile Include="Patch_DispenserFoodSearch.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Wormhole\Building_WormholePortal_A.cs" />
|
||||||
|
<Compile Include="Wormhole\Building_WormholePortal_B.cs" />
|
||||||
|
<Compile Include="Wormhole\CompLaunchableWormhole.cs" />
|
||||||
|
<Compile Include="Wormhole\Dialog_WormholeTransfer.cs" />
|
||||||
|
<Compile Include="HarmonyPatches\Patch_Site_ShouldRemoveMapNow.cs" />
|
||||||
|
<Compile Include="HarmonyPatches\Patch_SettlementDefeatUtility_CheckDefeated.cs" />
|
||||||
|
<Compile Include="HarmonyPatches\Patch_Game_DeinitAndRemoveMap.cs" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||||
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
<Target Name="CleanDebugFiles" AfterTargets="Build">
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Verse;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Game), "DeinitAndRemoveMap")]
|
||||||
|
public static class Patch_Game_DeinitAndRemoveMap
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool Prefix(Map map)
|
||||||
|
{
|
||||||
|
// 如果地图上存在B端传送门,则阻止该地图被销毁
|
||||||
|
if (map != null && map.listerBuildings.AllBuildingsColonistOfClass<Building_WormholePortal_B>().Any())
|
||||||
|
{
|
||||||
|
return false; // 返回 false, 阻止原版方法执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则,正常执行原版方法
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using RimWorld;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using Verse;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(SettlementDefeatUtility), "CheckDefeated")]
|
||||||
|
public static class Patch_SettlementDefeatUtility_CheckDefeated
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
public static bool Prefix(Settlement factionBase)
|
||||||
|
{
|
||||||
|
// 如果目标没有地图,或者地图上存在B端传送门,则跳过原版的失败检查
|
||||||
|
if (!factionBase.HasMap || factionBase.Map.listerBuildings.AllBuildingsColonistOfClass<Building_WormholePortal_B>().Any())
|
||||||
|
{
|
||||||
|
return false; // 返回 false, 阻止原版方法执行
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则,正常执行原版方法
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using Verse;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
[HarmonyPatch(typeof(Site), "ShouldRemoveMapNow")]
|
||||||
|
public static class Patch_Site_ShouldRemoveMapNow
|
||||||
|
{
|
||||||
|
[HarmonyPostfix]
|
||||||
|
public static void Postfix(MapParent __instance, ref bool __result)
|
||||||
|
{
|
||||||
|
// 如果原方法已经决定不移除,我们就不需要干预
|
||||||
|
if (!__result)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果地图上存在B端传送门,则推翻原方法的决定,阻止地图被移除
|
||||||
|
if (__instance.HasMap && __instance.Map.listerBuildings.AllBuildingsColonistOfClass<Building_WormholePortal_B>().Any())
|
||||||
|
{
|
||||||
|
__result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs
Normal file
108
Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_A.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public enum WormholePortalStatus
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Linked
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Building_WormholePortal_A : Building
|
||||||
|
{
|
||||||
|
private Building_WormholePortal_B linkedPortalB;
|
||||||
|
public WormholePortalStatus status = WormholePortalStatus.Idle;
|
||||||
|
|
||||||
|
private CompRefuelable refuelableComp;
|
||||||
|
|
||||||
|
public Building_WormholePortal_B LinkedPortal => linkedPortalB;
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
Scribe_References.Look(ref linkedPortalB, "linkedPortalB");
|
||||||
|
Scribe_Values.Look(ref status, "status", WormholePortalStatus.Idle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||||
|
{
|
||||||
|
base.SpawnSetup(map, respawningAfterLoad);
|
||||||
|
refuelableComp = GetComp<CompRefuelable>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
|
||||||
|
{
|
||||||
|
if (linkedPortalB != null && !linkedPortalB.Destroyed)
|
||||||
|
{
|
||||||
|
linkedPortalB.Notify_A_Destroyed();
|
||||||
|
linkedPortalB.Destroy(DestroyMode.Vanish);
|
||||||
|
}
|
||||||
|
base.DeSpawn(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLinkedPortal(Building_WormholePortal_B portalB)
|
||||||
|
{
|
||||||
|
if (portalB == null)
|
||||||
|
{
|
||||||
|
Notify_B_Destroyed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
linkedPortalB = portalB;
|
||||||
|
status = WormholePortalStatus.Linked;
|
||||||
|
Messages.Message("WormholePortalLinked".Translate(this.Label, portalB.Map.Parent.LabelCap), this, MessageTypeDefOf.PositiveEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Notify_B_Destroyed()
|
||||||
|
{
|
||||||
|
linkedPortalB = null;
|
||||||
|
status = WormholePortalStatus.Idle;
|
||||||
|
Messages.Message("WormholePortalB_Destroyed".Translate(this.Label), this, MessageTypeDefOf.NegativeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Gizmo> GetGizmos()
|
||||||
|
{
|
||||||
|
foreach (Gizmo g in base.GetGizmos())
|
||||||
|
{
|
||||||
|
yield return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status == WormholePortalStatus.Linked)
|
||||||
|
{
|
||||||
|
if (linkedPortalB == null || linkedPortalB.Destroyed)
|
||||||
|
{
|
||||||
|
// 安全检查,处理幽灵链接
|
||||||
|
Notify_B_Destroyed();
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_Action enterCommand = new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = "EnterWormhole".Translate(),
|
||||||
|
defaultDesc = "EnterWormholeDesc".Translate(),
|
||||||
|
icon = ContentFinder<UnityEngine.Texture2D>.Get("UI/Commands/EnterCave"),
|
||||||
|
action = BeginTeleportation
|
||||||
|
};
|
||||||
|
yield return enterCommand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetInspectString()
|
||||||
|
{
|
||||||
|
string text = base.GetInspectString();
|
||||||
|
text += "\n" + "Status".Translate() + ": " + status.ToString().Translate();
|
||||||
|
if (linkedPortalB != null && !linkedPortalB.Destroyed)
|
||||||
|
{
|
||||||
|
text += "\n" + "LinkedTo".Translate() + ": " + linkedPortalB.Map.Parent.LabelCap;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginTeleportation()
|
||||||
|
{
|
||||||
|
Find.WindowStack.Add(new Dialog_WormholeTransfer(this, this.LinkedPortal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
79
Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs
Normal file
79
Source/ArachnaeSwarm/Wormhole/Building_WormholePortal_B.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using RimWorld.Planet;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class Building_WormholePortal_B : Building
|
||||||
|
{
|
||||||
|
private Building_WormholePortal_A linkedPortalA;
|
||||||
|
|
||||||
|
public Building_WormholePortal_A LinkedPortal => linkedPortalA;
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
Scribe_References.Look(ref linkedPortalA, "linkedPortalA");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DeSpawn(DestroyMode mode = DestroyMode.Vanish)
|
||||||
|
{
|
||||||
|
// 如果B被摧毁,通知A
|
||||||
|
if (linkedPortalA != null && !linkedPortalA.Destroyed)
|
||||||
|
{
|
||||||
|
linkedPortalA.Notify_B_Destroyed();
|
||||||
|
}
|
||||||
|
base.DeSpawn(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这个方法在A端被摧毁时由A端调用,避免B端重复通知
|
||||||
|
public void Notify_A_Destroyed()
|
||||||
|
{
|
||||||
|
linkedPortalA = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLinkedPortal(Building_WormholePortal_A portalA)
|
||||||
|
{
|
||||||
|
linkedPortalA = portalA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Gizmo> GetGizmos()
|
||||||
|
{
|
||||||
|
foreach (Gizmo g in base.GetGizmos())
|
||||||
|
{
|
||||||
|
yield return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linkedPortalA != null && !linkedPortalA.Destroyed)
|
||||||
|
{
|
||||||
|
Command_Action enterCommand = new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = "EnterWormhole".Translate(),
|
||||||
|
defaultDesc = "EnterWormholeDesc".Translate(),
|
||||||
|
icon = ContentFinder<UnityEngine.Texture2D>.Get("UI/Commands/EnterCave"),
|
||||||
|
action = BeginTeleportation
|
||||||
|
};
|
||||||
|
yield return enterCommand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetInspectString()
|
||||||
|
{
|
||||||
|
string text = base.GetInspectString();
|
||||||
|
if (linkedPortalA != null && !linkedPortalA.Destroyed)
|
||||||
|
{
|
||||||
|
text += "\n" + "LinkedTo".Translate() + ": " + linkedPortalA.Map.Parent.LabelCap;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text += "\n" + "ConnectionLost".Translate();
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginTeleportation()
|
||||||
|
{
|
||||||
|
Find.WindowStack.Add(new Dialog_WormholeTransfer(this, this.LinkedPortal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
115
Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs
Normal file
115
Source/ArachnaeSwarm/Wormhole/CompLaunchableWormhole.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
using RimWorld;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class CompLaunchableWormhole : ThingComp
|
||||||
|
{
|
||||||
|
private CompRefuelableNutrition refuelableComp;
|
||||||
|
|
||||||
|
public Building_WormholePortal_A PortalA => this.parent as Building_WormholePortal_A;
|
||||||
|
public CompProperties_LaunchableWormhole Props => (CompProperties_LaunchableWormhole)props;
|
||||||
|
|
||||||
|
public override void Initialize(CompProperties props)
|
||||||
|
{
|
||||||
|
base.Initialize(props);
|
||||||
|
this.refuelableComp = this.parent.GetComp<CompRefuelableNutrition>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||||
|
{
|
||||||
|
if (PortalA?.status == WormholePortalStatus.Linked)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_Action launchCommand = new Command_Action();
|
||||||
|
launchCommand.defaultLabel = "CommandDeployWormholePortalB".Translate();
|
||||||
|
launchCommand.defaultDesc = "CommandDeployWormholePortalBDesc".Translate();
|
||||||
|
launchCommand.icon = ContentFinder<Texture2D>.Get("UI/Commands/LaunchShip");
|
||||||
|
|
||||||
|
if (refuelableComp.Fuel < this.Props.fuelNeededToLaunch)
|
||||||
|
{
|
||||||
|
launchCommand.Disable("NotEnoughFuel".Translate());
|
||||||
|
}
|
||||||
|
|
||||||
|
launchCommand.action = delegate
|
||||||
|
{
|
||||||
|
StartChoosingDestination();
|
||||||
|
};
|
||||||
|
yield return launchCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartChoosingDestination()
|
||||||
|
{
|
||||||
|
CameraJumper.TryJump(CameraJumper.GetWorldTarget(this.parent));
|
||||||
|
Find.WorldSelector.ClearSelection();
|
||||||
|
int tile = this.parent.Map.Tile;
|
||||||
|
Find.WorldTargeter.BeginTargeting(ChoseWorldTarget, true, CompLaunchable.TargeterMouseAttachment, true, delegate
|
||||||
|
{
|
||||||
|
GenDraw.DrawWorldRadiusRing(tile, this.Props.maxLaunchDistance);
|
||||||
|
}, (GlobalTargetInfo t) => "Select target tile");
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ChoseWorldTarget(GlobalTargetInfo t)
|
||||||
|
{
|
||||||
|
if (!t.IsValid)
|
||||||
|
{
|
||||||
|
Messages.Message("MessageTransportPodsDestinationIsInvalid".Translate(), MessageTypeDefOf.RejectInput);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (Find.World.Impassable(t.Tile))
|
||||||
|
{
|
||||||
|
Messages.Message("MessageTransportPodsDestinationIsImpassable".Translate(), MessageTypeDefOf.RejectInput);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapParent mapParent = Find.World.worldObjects.MapParentAt(t.Tile);
|
||||||
|
if (mapParent?.HasMap ?? false)
|
||||||
|
{
|
||||||
|
Deploy(mapParent, t);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LongEventHandler.QueueLongEvent(delegate
|
||||||
|
{
|
||||||
|
var newMap = GetOrGenerateMapUtility.GetOrGenerateMap(t.Tile, WorldObjectDefOf.Camp);
|
||||||
|
Deploy(newMap.Parent, t);
|
||||||
|
}, "GeneratingMap", doAsynchronously: false, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void Deploy(MapParent mapParent, GlobalTargetInfo t)
|
||||||
|
{
|
||||||
|
refuelableComp.ConsumeFuel(this.Props.fuelNeededToLaunch);
|
||||||
|
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);
|
||||||
|
|
||||||
|
EffecterDefOf.Skip_Exit.Spawn(cell, mapParent.Map);
|
||||||
|
|
||||||
|
PortalA.SetLinkedPortal(portalB);
|
||||||
|
portalB.SetLinkedPortal(PortalA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CompProperties_LaunchableWormhole : CompProperties
|
||||||
|
{
|
||||||
|
public float fuelNeededToLaunch;
|
||||||
|
public int maxLaunchDistance;
|
||||||
|
|
||||||
|
public CompProperties_LaunchableWormhole()
|
||||||
|
{
|
||||||
|
this.compClass = typeof(CompLaunchableWormhole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
214
Source/ArachnaeSwarm/Wormhole/Dialog_WormholeTransfer.cs
Normal file
214
Source/ArachnaeSwarm/Wormhole/Dialog_WormholeTransfer.cs
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using RimWorld;
|
||||||
|
using RimWorld.Planet;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
using Verse.Sound;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class Dialog_WormholeTransfer : Window
|
||||||
|
{
|
||||||
|
private enum Tab
|
||||||
|
{
|
||||||
|
Pawns,
|
||||||
|
Items
|
||||||
|
}
|
||||||
|
|
||||||
|
private const float TitleRectHeight = 35f;
|
||||||
|
private const float BottomAreaHeight = 55f;
|
||||||
|
private readonly Vector2 BottomButtonSize = new Vector2(160f, 40f);
|
||||||
|
|
||||||
|
private Building sourcePortal; // 通用源传送门
|
||||||
|
private Building destinationPortal; // 通用目标传送门
|
||||||
|
|
||||||
|
private List<TransferableOneWay> transferables;
|
||||||
|
private TransferableOneWayWidget pawnsTransfer;
|
||||||
|
private TransferableOneWayWidget itemsTransfer;
|
||||||
|
private Tab tab;
|
||||||
|
|
||||||
|
private static List<TabRecord> tabsList = new List<TabRecord>();
|
||||||
|
|
||||||
|
public override Vector2 InitialSize => new Vector2(1024f, UI.screenHeight);
|
||||||
|
protected override float Margin => 0f;
|
||||||
|
|
||||||
|
public Dialog_WormholeTransfer(Building sourcePortal, Building destinationPortal)
|
||||||
|
{
|
||||||
|
this.sourcePortal = sourcePortal;
|
||||||
|
this.destinationPortal = destinationPortal;
|
||||||
|
forcePause = true;
|
||||||
|
absorbInputAroundWindow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostOpen()
|
||||||
|
{
|
||||||
|
base.PostOpen();
|
||||||
|
CalculateAndRecacheTransferables();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DoWindowContents(Rect inRect)
|
||||||
|
{
|
||||||
|
Rect rect = new Rect(0f, 0f, inRect.width, TitleRectHeight);
|
||||||
|
Text.Font = GameFont.Medium;
|
||||||
|
Text.Anchor = TextAnchor.MiddleCenter;
|
||||||
|
Widgets.Label(rect, "EnterWormhole".Translate());
|
||||||
|
Text.Font = GameFont.Small;
|
||||||
|
Text.Anchor = TextAnchor.UpperLeft;
|
||||||
|
|
||||||
|
tabsList.Clear();
|
||||||
|
tabsList.Add(new TabRecord("PawnsTab".Translate(), () => tab = Tab.Pawns, tab == Tab.Pawns));
|
||||||
|
tabsList.Add(new TabRecord("ItemsTab".Translate(), () => tab = Tab.Items, tab == Tab.Items));
|
||||||
|
|
||||||
|
inRect.yMin += 67f;
|
||||||
|
Widgets.DrawMenuSection(inRect);
|
||||||
|
TabDrawer.DrawTabs(inRect, tabsList);
|
||||||
|
inRect = inRect.ContractedBy(17f);
|
||||||
|
|
||||||
|
Widgets.BeginGroup(inRect);
|
||||||
|
Rect rect2 = inRect.AtZero();
|
||||||
|
DoBottomButtons(rect2);
|
||||||
|
Rect inRect2 = rect2;
|
||||||
|
inRect2.yMax -= 76f;
|
||||||
|
|
||||||
|
bool anythingChanged = false;
|
||||||
|
switch (tab)
|
||||||
|
{
|
||||||
|
case Tab.Pawns:
|
||||||
|
pawnsTransfer.OnGUI(inRect2, out anythingChanged);
|
||||||
|
break;
|
||||||
|
case Tab.Items:
|
||||||
|
itemsTransfer.OnGUI(inRect2, out anythingChanged);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (anythingChanged)
|
||||||
|
{
|
||||||
|
// 可以添加一些计数或质量更新的逻辑
|
||||||
|
}
|
||||||
|
Widgets.EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoBottomButtons(Rect rect)
|
||||||
|
{
|
||||||
|
float buttonY = rect.height - BottomAreaHeight + 17;
|
||||||
|
|
||||||
|
if (Widgets.ButtonText(new Rect(rect.width / 2f - BottomButtonSize.x / 2f, buttonY, BottomButtonSize.x, BottomButtonSize.y), "ResetButton".Translate()))
|
||||||
|
{
|
||||||
|
SoundDefOf.Tick_Low.PlayOneShotOnCamera();
|
||||||
|
CalculateAndRecacheTransferables();
|
||||||
|
}
|
||||||
|
if (Widgets.ButtonText(new Rect(0f, buttonY, BottomButtonSize.x, BottomButtonSize.y), "CancelButton".Translate()))
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
if (Widgets.ButtonText(new Rect(rect.width - BottomButtonSize.x, buttonY, BottomButtonSize.x, BottomButtonSize.y), "AcceptButton".Translate()))
|
||||||
|
{
|
||||||
|
if (TryAccept())
|
||||||
|
{
|
||||||
|
SoundDefOf.Tick_High.PlayOneShotOnCamera();
|
||||||
|
Close(doCloseSound: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryAccept()
|
||||||
|
{
|
||||||
|
List<TransferableOneWay> toTransfer = transferables.Where(x => x.CountToTransfer > 0).ToList();
|
||||||
|
if (!toTransfer.Any())
|
||||||
|
{
|
||||||
|
Messages.Message("NothingToTransfer".Translate(), MessageTypeDefOf.RejectInput);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var trans in toTransfer)
|
||||||
|
{
|
||||||
|
// 传送逻辑
|
||||||
|
var things = trans.things.Take(trans.CountToTransfer).ToList();
|
||||||
|
foreach (var thing in things)
|
||||||
|
{
|
||||||
|
Pawn pawn = thing as Pawn;
|
||||||
|
if (pawn != null)
|
||||||
|
{
|
||||||
|
pawn.DeSpawn();
|
||||||
|
GenSpawn.Spawn(pawn, CellFinder.RandomClosewalkCellNear(destinationPortal.Position, destinationPortal.Map, 5), destinationPortal.Map, WipeMode.Vanish);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thing.DeSpawn();
|
||||||
|
GenSpawn.Spawn(thing, CellFinder.RandomClosewalkCellNear(destinationPortal.Position, destinationPortal.Map, 5), destinationPortal.Map, WipeMode.Vanish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换视角
|
||||||
|
if (toTransfer.Any(x => x.ThingDef.category == ThingCategory.Pawn))
|
||||||
|
{
|
||||||
|
var firstPawn = toTransfer.First(x => x.ThingDef.category == ThingCategory.Pawn).AnyThing as Pawn;
|
||||||
|
CameraJumper.TryJump(new GlobalTargetInfo(destinationPortal.Position, destinationPortal.Map));
|
||||||
|
if (firstPawn != null)
|
||||||
|
{
|
||||||
|
CameraJumper.TrySelect(firstPawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.Message("WormholeTransferComplete".Translate(), MessageTypeDefOf.PositiveEvent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateAndRecacheTransferables()
|
||||||
|
{
|
||||||
|
transferables = new List<TransferableOneWay>();
|
||||||
|
AddPawnsToTransferables();
|
||||||
|
AddItemsToTransferables();
|
||||||
|
|
||||||
|
pawnsTransfer = new TransferableOneWayWidget(transferables.Where(x => x.ThingDef.category == ThingCategory.Pawn), null, null, "TransferableCount".Translate(),
|
||||||
|
drawMass: true,
|
||||||
|
ignorePawnInventoryMass: IgnorePawnsInventoryMode.Ignore,
|
||||||
|
includePawnsMassInMassUsage: true,
|
||||||
|
availableMassGetter: () => float.MaxValue, // 无质量限制
|
||||||
|
extraHeaderSpace: 0f,
|
||||||
|
ignoreSpawnedCorpseGearAndInventoryMass: false,
|
||||||
|
tile: sourcePortal.Map.Tile,
|
||||||
|
drawMarketValue: true,
|
||||||
|
drawEquippedWeapon: true);
|
||||||
|
|
||||||
|
itemsTransfer = new TransferableOneWayWidget(transferables.Where(x => x.ThingDef.category != ThingCategory.Pawn), null, null, "TransferableCount".Translate(),
|
||||||
|
drawMass: true,
|
||||||
|
ignorePawnInventoryMass: IgnorePawnsInventoryMode.Ignore,
|
||||||
|
includePawnsMassInMassUsage: true,
|
||||||
|
availableMassGetter: () => float.MaxValue,
|
||||||
|
extraHeaderSpace: 0f,
|
||||||
|
ignoreSpawnedCorpseGearAndInventoryMass: false,
|
||||||
|
tile: sourcePortal.Map.Tile,
|
||||||
|
drawMarketValue: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToTransferables(Thing t)
|
||||||
|
{
|
||||||
|
var transferable = TransferableUtility.TransferableMatching(t, transferables, TransferAsOneMode.PodsOrCaravanPacking);
|
||||||
|
if (transferable == null)
|
||||||
|
{
|
||||||
|
transferable = new TransferableOneWay();
|
||||||
|
transferables.Add(transferable);
|
||||||
|
}
|
||||||
|
transferable.things.Add(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPawnsToTransferables()
|
||||||
|
{
|
||||||
|
foreach (Pawn p in sourcePortal.Map.mapPawns.AllPawnsSpawned.Where(p => p.Faction == Faction.OfPlayer))
|
||||||
|
{
|
||||||
|
AddToTransferables(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddItemsToTransferables()
|
||||||
|
{
|
||||||
|
foreach (Thing t in sourcePortal.Map.listerThings.AllThings.Where(t => t.def.category == ThingCategory.Item && t.def.EverHaulable && t.Position.IsValid && !t.Position.Fogged(t.Map)))
|
||||||
|
{
|
||||||
|
AddToTransferables(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user