diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index fa152df..d72881c 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/ThingDefs_Buildings/ThingDef_Building_CatastropheMissileSilo.xml b/1.6/1.6/Defs/ThingDefs_Buildings/ThingDef_Building_CatastropheMissileSilo.xml
index 7425847..e601863 100644
--- a/1.6/1.6/Defs/ThingDefs_Buildings/ThingDef_Building_CatastropheMissileSilo.xml
+++ b/1.6/1.6/Defs/ThingDefs_Buildings/ThingDef_Building_CatastropheMissileSilo.xml
@@ -6,10 +6,19 @@
一个多功能导弹发射平台。它装备的武器系统既可以作为自动炮塔进行本地防御,也可以在操作员的指引下,将“天灾”级巡航导弹发射到全球任何一个角落。
ArachnaeSwarm.Building_CatastropheMissileSilo
+ MapMeshAndRealTime
- Things/Building/Security/TurretMortar_Base
+ Things/Building/Security/TurretHeavy_Base
Graphic_Single
- (6,6)
+ (3, 3)
+ (0,0,-0.1)
+
+ (0.2,0.2,0.6,0.6)
+
+
+ (1.5,0.35,1.4)
+ (0,0,-0.05)
+
(2,2)
Building
@@ -38,7 +47,7 @@
ComponentSpacer
- 1
+ 10
0
1
true
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/ThingDef_Projectile_CatastropheMissile.xml b/1.6/1.6/Defs/ThingDefs_Misc/ThingDef_Projectile_CatastropheMissile.xml
index 5a7b84a..92b1f4b 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/ThingDef_Projectile_CatastropheMissile.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/ThingDef_Projectile_CatastropheMissile.xml
@@ -10,15 +10,15 @@
Graphic_Single
- Bomb
+ ARA_AcidBurn
200
- 30
+ 50
5.9
MortarBomb_Explode
- Bomb
+ ARA_AcidBurn
150
5.9
MortarBomb_Explode
@@ -27,7 +27,7 @@
2.9
50
15
- Bomb
+ ARA_AcidBurn
Mortar_Explode
0.05
5
diff --git a/Source/ArachnaeSwarm/Buildings/Building_CatastropheMissileSilo.cs b/Source/ArachnaeSwarm/Buildings/Building_CatastropheMissileSilo.cs
index 1ce483e..bfe7480 100644
--- a/Source/ArachnaeSwarm/Buildings/Building_CatastropheMissileSilo.cs
+++ b/Source/ArachnaeSwarm/Buildings/Building_CatastropheMissileSilo.cs
@@ -5,6 +5,7 @@ using RimWorld;
using RimWorld.Planet;
using UnityEngine;
using Verse;
+using Verse.AI;
using Verse.Sound;
namespace ArachnaeSwarm
@@ -12,49 +13,57 @@ namespace ArachnaeSwarm
[StaticConstructorOnStartup]
public class Building_CatastropheMissileSilo : Building_TurretGun
{
- public GlobalTargetInfo longTarget;
-
public static readonly Texture2D FireMissionTex = ContentFinder.Get("UI/Commands/Attack", true);
public override void ExposeData()
{
base.ExposeData();
- Scribe_TargetInfo.Look(ref this.longTarget, "longTarget");
+ }
+
+ protected override void Tick()
+ {
+ base.Tick();
}
public override IEnumerable GetGizmos()
{
+ // Add the default turret gizmos (like "Set forced target")
foreach (Gizmo c in base.GetGizmos())
{
yield return c;
}
- // Gizmo to set the long range target
- Command_Action setTarget = new Command_Action
+ // Add our custom global strike gizmo
+ Command_Action launch = new Command_Action
{
- defaultLabel = "CommandSetGlobalTarget".Translate(),
- defaultDesc = "CommandSetGlobalTargetDesc".Translate(),
+ defaultLabel = "CommandFireGlobal".Translate(),
+ defaultDesc = "CommandFireGlobalDesc".Translate(),
icon = FireMissionTex,
action = new Action(this.StartChoosingDestination)
};
- if (!this.powerComp.PowerOn)
- {
- setTarget.Disable("NoPower".Translate().CapitalizeFirst());
- }
- yield return setTarget;
- // Gizmo to clear the long range target
- if (this.longTarget.IsValid)
+ if (!CanFireGlobal(out string reason))
{
- Command_Action clearTarget = new Command_Action
- {
- defaultLabel = "CommandClearGlobalTarget".Translate(),
- defaultDesc = "CommandClearGlobalTargetDesc".Translate(),
- icon = ContentFinder.Get("UI/Commands/Cancel"),
- action = () => { this.longTarget = GlobalTargetInfo.Invalid; }
- };
- yield return clearTarget;
+ launch.Disable(reason);
}
+ yield return launch;
+ }
+
+ private bool CanFireGlobal(out string reason)
+ {
+ if (!this.powerComp.PowerOn)
+ {
+ reason = "NoPower".Translate().CapitalizeFirst();
+ return false;
+ }
+ var refuelableComp = this.TryGetComp();
+ if (refuelableComp != null && !refuelableComp.HasFuel)
+ {
+ reason = "NoFuel".Translate().CapitalizeFirst();
+ return false;
+ }
+ reason = "";
+ return true;
}
private void StartChoosingDestination()
@@ -84,7 +93,6 @@ namespace ArachnaeSwarm
return false;
}
- // The target must be a map parent that has a loaded map.
if (target.WorldObject is MapParent mapParent && mapParent.HasMap)
{
var originalMap = this.Map;
@@ -93,16 +101,16 @@ namespace ArachnaeSwarm
};
Current.Game.CurrentMap = mapParent.Map;
- Find.Targeter.BeginTargeting(new TargetingParameters { canTargetLocations = true },
- (LocalTargetInfo localTarget) => // This is called when the user clicks a cell in the target map
+ Find.Targeter.BeginTargeting(new TargetingParameters { canTargetLocations = true },
+ (LocalTargetInfo localTarget) =>
{
this.FireMission(new GlobalTargetInfo(localTarget.Cell, mapParent.Map));
- },
+ },
null, onFinished, FireMissionTex, true);
return true;
}
- else
+ else
{
Messages.Message("MessageTargetMustBeMap".Translate(), MessageTypeDefOf.RejectInput, true);
return false;
@@ -111,9 +119,35 @@ namespace ArachnaeSwarm
public void FireMission(GlobalTargetInfo target)
{
- this.longTarget = target;
- this.OrderAttack(new LocalTargetInfo(this));
- Messages.Message("Global target acquired. Firing sequence initiated.", MessageTypeDefOf.PositiveEvent);
+ if (!CanFireGlobal(out _)) return;
+
+ var refuelableComp = this.TryGetComp();
+
+ // --- Launch Logic starts here ---
+
+ // 1. Create the world-traveling object immediately
+ WorldObject_CatastropheMissile missile = (WorldObject_CatastropheMissile)WorldObjectMaker.MakeWorldObject(
+ DefDatabase.GetNamed("CatastropheMissile_Flying")
+ );
+ missile.Tile = this.Map.Tile;
+ missile.destinationTile = target.Tile;
+ missile.destinationCell = target.Cell;
+ missile.Projectile = DefDatabase.GetNamed("Projectile_CatastropheMissile");
+ Find.WorldObjects.Add(missile);
+
+ // 2. Launch a local dummy projectile for visual effect, that will never impact.
+ if (CellFinder.TryFindRandomEdgeCellWith(c => this.Map.reachability.CanReach(this.Position, c, PathEndMode.OnCell, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly)), this.Map, 0f, out IntVec3 edgeCell))
+ {
+ Projectile dummy = (Projectile)GenSpawn.Spawn(DefDatabase.GetNamed("Projectile_CatastropheMissile"), this.Position, this.Map);
+ dummy.Launch(this, this.DrawPos, new LocalTargetInfo(edgeCell), new LocalTargetInfo(edgeCell), ProjectileHitFlags.None);
+ }
+
+ // 3. Consume resources and start cooldown
+ if(refuelableComp != null)
+ {
+ refuelableComp.ConsumeFuel(1);
+ }
+ SoundDef.Named("RocketLaunch").PlayOneShot(new TargetInfo(this.Position, this.Map));
}
}
}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Verbs/Verb_LaunchCatastropheMissile.cs b/Source/ArachnaeSwarm/Verbs/Verb_LaunchCatastropheMissile.cs
index e963a9a..c451d9e 100644
--- a/Source/ArachnaeSwarm/Verbs/Verb_LaunchCatastropheMissile.cs
+++ b/Source/ArachnaeSwarm/Verbs/Verb_LaunchCatastropheMissile.cs
@@ -2,77 +2,17 @@ using RimWorld;
using RimWorld.Planet;
using UnityEngine;
using Verse;
+using Verse.AI;
using Verse.Sound;
namespace ArachnaeSwarm
{
public class Verb_LaunchCatastropheMissile : Verb_Shoot
{
- public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ)
- {
- var silo = this.Caster as Building_CatastropheMissileSilo;
- if (silo != null && silo.longTarget.IsValid)
- {
- return true;
- }
- return base.CanHitTargetFrom(root, targ);
- }
-
+ // This verb is now only for local defense. The global launch is handled by the Building.
protected override bool TryCastShot()
{
- var silo = this.Caster as Building_CatastropheMissileSilo;
-
- if (silo != null && silo.longTarget.IsValid)
- {
- return this.TryCastGlobalShot(silo);
- }
-
- // If no long target, perform a normal local shot
return base.TryCastShot();
}
-
- private bool TryCastGlobalShot(Building_CatastropheMissileSilo silo)
- {
- var refuelableComp = silo.TryGetComp();
- if (refuelableComp != null && !refuelableComp.HasFuel)
- {
- Messages.Message("NoMissileToLaunch".Translate(), silo, MessageTypeDefOf.RejectInput);
- return false;
- }
-
- WorldObject_CatastropheMissile missile = (WorldObject_CatastropheMissile)WorldObjectMaker.MakeWorldObject(
- DefDatabase.GetNamed("CatastropheMissile_Flying")
- );
-
- missile.Tile = silo.Map.Tile;
- missile.destinationTile = silo.longTarget.Tile;
- missile.destinationCell = silo.longTarget.Cell;
- missile.Projectile = DefDatabase.GetNamed("Projectile_CatastropheMissile");
-
- Find.WorldObjects.Add(missile);
-
- if(refuelableComp != null)
- {
- refuelableComp.ConsumeFuel(1);
- }
-
- SoundDef.Named("RocketLaunch").PlayOneShot(new TargetInfo(silo.Position, silo.Map));
-
- // Reset target after launch
- silo.longTarget = GlobalTargetInfo.Invalid;
-
- // Manually reset cooldown
- if (this.burstShotsLeft < this.verbProps.burstShotCount)
- {
- this.burstShotsLeft = 0;
- }
- if (this.verbProps.burstShotCount > 0)
- {
- this.ticksToNextBurstShot = this.verbProps.ticksBetweenBurstShots;
- }
- this.state = VerbState.Idle;
-
- return true;
- }
}
}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/World/WorldObject_CatastropheMissile.cs b/Source/ArachnaeSwarm/World/WorldObject_CatastropheMissile.cs
index 7c99942..4d5a3d0 100644
--- a/Source/ArachnaeSwarm/World/WorldObject_CatastropheMissile.cs
+++ b/Source/ArachnaeSwarm/World/WorldObject_CatastropheMissile.cs
@@ -13,7 +13,7 @@ namespace ArachnaeSwarm
private int initialTile = -1;
private float traveledPct;
- private const float TravelSpeed = 0.0002f; // Faster than sabot
+ private const float TravelSpeed = 0.0002f;
public override void ExposeData()
{
@@ -60,11 +60,14 @@ namespace ArachnaeSwarm
Map targetMap = Current.Game.FindMap(this.destinationTile);
if (targetMap != null)
{
- // Target is a loaded map, spawn the projectile to hit it
+ // Find a random entry point at the edge of the target map
IntVec3 entryCell = CellFinder.RandomEdgeCell(targetMap);
-
+
+ // Spawn the final projectile (the cruise missile) at the entry point
Projectile_CruiseMissile missile = (Projectile_CruiseMissile)GenSpawn.Spawn(this.Projectile, entryCell, targetMap, WipeMode.Vanish);
- missile.Launch(null, this.destinationCell, this.destinationCell, ProjectileHitFlags.IntendedTarget);
+
+ // Launch it from the entry point towards the final destination cell
+ missile.Launch(null, entryCell.ToVector3Shifted(), new LocalTargetInfo(this.destinationCell), new LocalTargetInfo(this.destinationCell), ProjectileHitFlags.IntendedTarget);
}
Find.WorldObjects.Remove(this);