虫洞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="Patch_DispenserFoodSearch.cs" />
|
||||
</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" />
|
||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||
<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