diff --git a/1.6/Assemblies/FCP_Enlist.dll b/1.6/Assemblies/FCP_Enlist.dll index 0338185..df1ea99 100644 Binary files a/1.6/Assemblies/FCP_Enlist.dll and b/1.6/Assemblies/FCP_Enlist.dll differ diff --git a/Common/Languages/English/Keyed/FCPToolsKeyed.xml b/Common/Languages/English/Keyed/FCPToolsKeyed.xml index 40716f0..99b8881 100644 --- a/Common/Languages/English/Keyed/FCPToolsKeyed.xml +++ b/Common/Languages/English/Keyed/FCPToolsKeyed.xml @@ -29,4 +29,8 @@ Requires xenotype: {0} Requires apparel: {0} + + New Enemy + By enlisting with {ENLISTED_name}, you have become an enemy of {HOSTILE_name}. They are now hostile toward your colony. + \ No newline at end of file diff --git a/Source/Enlist/Enlist.csproj b/Source/Enlist/Enlist.csproj index 68e9fc3..2a1ad50 100644 --- a/Source/Enlist/Enlist.csproj +++ b/Source/Enlist/Enlist.csproj @@ -36,4 +36,11 @@ + + + ..\..\1.6\Assemblies\FCP_Core.dll + False + + + \ No newline at end of file diff --git a/Source/Enlist/FactionEnlistWorker.cs b/Source/Enlist/FactionEnlistWorker.cs index a8ec431..809a51e 100644 --- a/Source/Enlist/FactionEnlistWorker.cs +++ b/Source/Enlist/FactionEnlistWorker.cs @@ -54,6 +54,27 @@ public class FactionEnlistWorker factionOptions.factionsStorages[def] = factionStorage; } def.enlistedSoundDef?.PlayOneShotOnCamera(); + + Faction player = Faction.OfPlayer; + foreach (Faction faction in Find.FactionManager.AllFactionsListForReading) + { + if (faction == toEnlist || faction == player || faction.defeated || faction.IsPlayer) continue; + + FactionRelation rel = toEnlist.RelationWith(faction, false); + if (rel == null || rel.kind != FactionRelationKind.Hostile) continue; + if (faction.HostileTo(player)) continue; + + int goodwill = faction.GoodwillWith(player); + if (goodwill > -75) + { + faction.TryAffectGoodwillWith(player, -75 - goodwill, false, true); + } + + Find.LetterStack.ReceiveLetter( + "FCP_Enemy_Of_Enlist_Faction".Translate(), + "FCP_Enemy_Of_Enlist_Faction_Desc".Translate(toEnlist.Named("ENLISTED"), faction.Named("HOSTILE")), + LetterDefOf.NegativeEvent); + } } diff --git a/Source/Enlist/WorldObjectCompEnlist.cs b/Source/Enlist/WorldObjectCompEnlist.cs index 84df4e7..df6debd 100644 --- a/Source/Enlist/WorldObjectCompEnlist.cs +++ b/Source/Enlist/WorldObjectCompEnlist.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using UnityEngine; using Verse; +using FCP.Core.Shuttles; namespace FCP.Enlist; @@ -493,7 +494,7 @@ public class WorldObjectCompEnlist : WorldObjectComp { defaultLabel = optionDef.shuttleServiceLabelKey.Translate(faction.Named("FACTION")), defaultDesc = optionDef.shuttleServiceDescKey.Translate(faction.Named("FACTION")), - icon = ContentFinder.Get(optionDef.shuttleServiceButtonIconTexPath), + icon = ContentFinder.Get(optionDef.shuttleServiceButtonIconTexPath, reportFailure: false) ?? BaseContent.BadTex, action = delegate { StartChoosingShuttleDestination(caravan, optionDef); @@ -692,7 +693,7 @@ public class WorldObjectCompEnlist : WorldObjectComp Messages.Message("TransportPodDestinationBeyondMaximumRange".Translate(), MessageTypeDefOf.RejectInput, historical: false); return false; } - IEnumerable source = GetTransportPodsFloatMenuOptionsAt(target.Tile, caravan); + IEnumerable source = GetTransportPodsFloatMenuOptionsAt(target.Tile, caravan, launchAction); if (!source.Any()) { if (Find.World.Impassable(target.Tile)) @@ -783,92 +784,63 @@ public class WorldObjectCompEnlist : WorldObjectComp } ExtractMoneyFromCaravan(caravan, curFactionEnlistOptionsDef.shuttleServiceCost, curFactionEnlistOptionsDef); - // Try to get custom shuttle from faction using reflection - TransportShipDef transportShipDef = null; - - if (parent.Faction?.def?.modExtensions != null) + // Get custom shuttle from faction extension - direct type access (no reflection) + FactionModExtension factionExtension = parent.Faction?.def?.GetModExtension(); + TransportShipDef transportShipDef = factionExtension?.transportShipDef; + + if (transportShipDef != null && transportShipDef.worldObject != null) { - foreach (var extension in parent.Faction.def.modExtensions) + // Create the shuttle thing - it's a Building with CompTransporter, not an ActiveTransporter + Thing shuttleThing = ThingMaker.MakeThing(transportShipDef.shipThing); + CompTransporter compTransporter = shuttleThing.TryGetComp(); + + if (compTransporter == null) { - if (extension.GetType().Name == "FactionModExtension") - { - var transportShipDefField = extension.GetType().GetField("transportShipDef"); - if (transportShipDefField != null) - { - transportShipDef = transportShipDefField.GetValue(extension) as TransportShipDef; - break; - } - } + Log.Error($"[FCP Enlist] Shuttle thing {shuttleThing.def.defName} has no CompTransporter!"); + TryLaunch(destinationTile, arrivalAction, caravan); + return; } - } - - Thing transportThing; - ThingDef skyfallerDef; - WorldObjectDef worldObjectDef; - - if (transportShipDef != null) - { - // Use custom shuttle - transportThing = ThingMaker.MakeThing(transportShipDef.shipThing); - skyfallerDef = transportShipDef.leavingSkyfaller; - worldObjectDef = transportShipDef.worldObject; - } - else - { - // Fall back to drop pods - transportThing = ThingMaker.MakeThing(ThingDefOf.ActiveDropPod); - skyfallerDef = ThingDefOf.DropPodLeaving; - worldObjectDef = WorldObjectDefOf.TravellingTransporters; - } - - // Load the transport - CompTransporter compTransporter = transportThing.TryGetComp(); - if (compTransporter != null) - { - compTransporter.GetDirectlyHeldThings().TryAddRangeOrTransfer(caravan.GetDirectlyHeldThings(), canMergeWithExistingStacks: true, destroyLeftover: true); - } - - // Create the skyfaller - Skyfaller skyfaller = (Skyfaller)SkyfallerMaker.MakeSkyfaller(skyfallerDef, transportThing); - if (skyfaller is FlyShipLeaving flyShip) - { - flyShip.groupID = 1; - flyShip.destinationTile = destinationTile; - flyShip.arrivalAction = arrivalAction; - flyShip.worldObjectDef = worldObjectDef; - } - - // Create traveling world object - WorldObject travelingPods = WorldObjectMaker.MakeWorldObject(worldObjectDef); - travelingPods.Tile = base.parent.Tile; - travelingPods.SetFaction(Faction.OfPlayer); - - // Set destination using reflection since we don't know the exact type - var destTileField = travelingPods.GetType().GetField("destinationTile"); - if (destTileField != null) - { - destTileField.SetValue(travelingPods, destinationTile); - } - - var arrivalActionField = travelingPods.GetType().GetField("arrivalAction"); - if (arrivalActionField != null) - { - arrivalActionField.SetValue(travelingPods, arrivalAction); - } - - Find.WorldObjects.Add(travelingPods); - - // Add pods using reflection - if (compTransporter != null) - { - var addPodMethod = travelingPods.GetType().GetMethod("AddPod"); - if (addPodMethod != null) + + // Transfer caravan contents to shuttle's transporter + compTransporter.GetDirectlyHeldThings().TryAddRangeOrTransfer( + caravan.GetDirectlyHeldThings(), + canMergeWithExistingStacks: true, + destroyLeftover: true); + + // Create the traveling world object - cast to TravellingTransporters for direct property access + TravellingTransporters travelingShuttle = (TravellingTransporters)WorldObjectMaker.MakeWorldObject(transportShipDef.worldObject); + travelingShuttle.Tile = parent.Tile; + travelingShuttle.SetFaction(Faction.OfPlayer); + travelingShuttle.destinationTile = destinationTile; + + // Use custom arrival action that forces map loading to show shuttle landing + travelingShuttle.arrivalAction = arrivalAction ?? new TransportersArrivalAction_FormCaravan(); + // Set the transport ship def (still need reflection for this private field) + var transportShipField = typeof(TravellingTransporters).GetField("transportShip", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + if (transportShipField != null) { - addPodMethod.Invoke(travelingPods, new object[] { compTransporter.GetDirectlyHeldThings().ToList(), true }); + transportShipField.SetValue(travelingShuttle, transportShipDef); } + + Find.WorldObjects.Add(travelingShuttle); + + // Wrap the cargo in ActiveTransporterInfo for AddTransporter + ActiveTransporterInfo transporterInfo = new ActiveTransporterInfo(); + transporterInfo.innerContainer.TryAddRangeOrTransfer( + compTransporter.GetDirectlyHeldThings(), + canMergeWithExistingStacks: true, + destroyLeftover: false); + + travelingShuttle.AddTransporter(transporterInfo, true); + + caravan.Destroy(); + return; } - - caravan.Destroy(); + + // Fallback to drop pods + Log.Warning("[FCP Enlist] Failed to launch shuttle, falling back to drop pods"); + TryLaunch(destinationTile, arrivalAction, caravan); } } @@ -901,15 +873,19 @@ public class WorldObjectCompEnlist : WorldObjectComp } } } - private IEnumerable GetTransportPodsFloatMenuOptionsAt(int tile, Caravan caravan) + private IEnumerable GetTransportPodsFloatMenuOptionsAt(int tile, Caravan caravan, Action launchAction = null) { + // Default to TryLaunch if no launchAction specified (for drop pods) + if (launchAction == null) + launchAction = TryLaunch; + bool anything = false; if (!Find.World.Impassable(tile) && !Find.WorldObjects.AnySettlementBaseAt(tile) && !Find.WorldObjects.AnySiteAt(tile)) { anything = true; yield return new FloatMenuOption("FormCaravanHere".Translate(), delegate { - TryLaunch(tile, new TransportersArrivalAction_FormCaravan(), caravan); + launchAction(tile, new TransportersArrivalAction_FormCaravan(), caravan); }); } //List worldObjects = Find.WorldObjects.AllWorldObjects; @@ -928,7 +904,7 @@ public class WorldObjectCompEnlist : WorldObjectComp { yield return new FloatMenuOption("TransportPodsContentsWillBeLost".Translate(), delegate { - TryLaunch(tile, null, caravan); + launchAction(tile, null, caravan); }); } }