diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index ee29dbb2..4d98b7f6 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml b/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml index 3984d8e2..b786355c 100644 --- a/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml +++ b/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml @@ -143,6 +143,9 @@ +
  • + WULA_Light_Fighter_Drone_Technology +
  • WULA_Fighter_Drone_Entity 5000 @@ -189,6 +192,9 @@ +
  • + WULA_Light_Fighter_Drone_Technology +
  • WULA_Fighter_Drone_Entity 5000 @@ -243,6 +249,9 @@ +
  • + WULA_Striker_Technology +
  • WULA_Striker_Entity 5000 @@ -277,7 +286,7 @@ WULA_Spawn_Striker_RailGun - 指挥乌拉帝国的战机,高速掠过战场,使用机腹的两台高射速机炮打击目标地点——因为速度原因,打击区会很狭长。 + 指挥乌拉帝国的攻击机,高速掠过战场,使用机腹的两台高射速机炮打击目标地点——因为速度原因,打击区会很狭长。 Wula/UI/Abilities/WULA_Spawn_Striker_RailGun 1 Misc12 @@ -295,6 +304,9 @@ +
  • + WULA_Striker_Technology +
  • WULA_Striker_Entity 5000 @@ -340,7 +352,7 @@ WULA_Spawn_Striker_EMP - 指挥乌拉帝国的战机,高速掠过战场,快速丢下一组EMP炸弹——因为速度原因,打击区会很狭长。 + 指挥乌拉帝国的攻击机,高速掠过战场,快速丢下一组EMP炸弹——因为速度原因,打击区会很狭长。 Wula/UI/Abilities/WULA_Spawn_Striker_EMP 1 Misc12 @@ -358,6 +370,9 @@ +
  • + WULA_Striker_Technology +
  • WULA_Striker_Entity 5000 @@ -421,6 +436,9 @@ +
  • + WULA_Bomber_Technology +
  • WULA_Bomber_Entity 10000 @@ -484,6 +502,9 @@ +
  • + WULA_Bomber_Technology +
  • WULA_Bomber_Entity 5000 @@ -547,6 +568,9 @@ +
  • + WULA_Bomber_Technology +
  • WULA_Bomber_Entity 10000 @@ -592,9 +616,9 @@ - WULA_Spawn_ShipChunkIncoming - - 我炸死你 + WULA_Firepower_Minigun_Strafe + + 以战舰上的自动链炮对目标区域进行可选方向的扫射,射击速度和冷却都很快,但是威力欠佳。 1 Misc12 @@ -612,6 +636,10 @@ +
  • + 1000 + BombardmentFacility +
  • 5 35 @@ -624,7 +652,7 @@ true 1.5 1.0,0.3,0.1,0.3 - ShipChunkIncoming + WULA_Firepower_Minigun_Strafe_Skyfaller
  • diff --git a/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml index ef7f940a..16f2232c 100644 --- a/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml +++ b/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml @@ -73,7 +73,7 @@
  • -
  • WULA_Spawn_ShipChunkIncoming
  • +
  • WULA_Firepower_Minigun_Strafe
  • diff --git a/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml b/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml index cc7d750c..6f7f7f98 100644 --- a/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml +++ b/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml @@ -56,7 +56,7 @@ WULA_Striker_Technology - 允许殖民地建立信标增加攻击机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的攻击机是强大的对地支援火力,挂载了大量导弹和强大的机炮,对敌方目标实施精准收割。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。 + 允许殖民地建立信标增加攻击机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的攻击机是强大的对地支援火力,挂载了大量导弹、EMP炸弹和强大的机炮,对敌方目标实施精准收割。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。 600 5.00 4.40 @@ -81,7 +81,7 @@ WULA_Bomber_Technology - 允许殖民地建立信标增加轰炸机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的轰炸机是可以进入大气层的最大的飞行载具,除了可以使用机炮监视航路外,还能投下大量炸弹夷平帝国之敌。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。 + 允许殖民地建立信标增加轰炸机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的轰炸机是可以进入大气层的最大的飞行载具,除了投掷功能性的烟雾弹外,也能投下大量炸弹或是发射一枚暗物质导弹夷平帝国之敌。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。 600 9.00 4.40 diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml index f1b2bc4f..400634de 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml @@ -71,7 +71,7 @@ WULA_Fake_Fighter_Drone_Building - 111 + 一台小型无人机,装备了激光炮和汽油弹,可以为殖民地提供廉价但有效的空中支援。和那些大家伙不同,蜂群无人机不需要机库,并且可以通过舰队的电磁网补充能量,实现永久滞空作战。 Building true Building @@ -182,7 +182,7 @@ WULA_Fake_Striker_Beacon_Building - 111 + 用于向乌拉帝国舰队提交资源的信标,可以换取一台乌拉帝国攻击机的支援。若想调动大型战机入场,需要轨道上有携带<color=#BD952F><i>机库</i></color>的战舰。\n\n乌拉帝国的攻击机是强大的对地支援火力,挂载了大量导弹、EMP炸弹和强大的机炮,对敌方目标实施精准收割。 Building true Building @@ -252,7 +252,7 @@ WULA_Fake_Bomber_Beacon_Building - 111 + 用于向乌拉帝国舰队提交资源的信标,可以换取一台乌拉帝国轰炸机的支援。若想调动大型战机入场,需要轨道上有携带<color=#BD952F><i>机库</i></color>的战舰。\n\n乌拉帝国的轰炸机是可以进入大气层的最大的飞行载具,除了投掷功能性的烟雾弹外,也能投下大量炸弹或是发射一枚暗物质导弹夷平帝国之敌。 Building true Building diff --git a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml index 30604387..a4b52107 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml @@ -63,6 +63,10 @@
  • BuildingdropperFacility
  • + +
  • + 60000 +
  • @@ -125,6 +129,10 @@
  • BombardmentFacility
  • + +
  • + 60000 +
  • @@ -191,6 +199,7 @@ + WulaFallenEmpire.FlyOver Normal @@ -695,4 +704,49 @@ + + + + WULA_Firepower_Minigun_Strafe_Skyfaller + + (1, 1) + + Wula/Projectile/WULA_Bullet_ChargeLanceShot_Red + Graphic_Single + MoteGlow + 5 + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (1, 1) + DropPod_Fall + 100 + Explosion_Bomb + 0.05 + 1 + 1 + + +
  • (0,180)
  • +
  • (1, 181)
  • +
    +
    + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + 4 + WULA_Firepower_Minigun_Strafe_Damage + 1 +
    +
    + + WULA_Firepower_Minigun_Strafe_Damage + + 25 + Explosion_Bomb + \ No newline at end of file diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml index 26a3ea77..6fb8295d 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml @@ -1,5 +1,25 @@ + + 获得航空器 + 获得对应的航空器 + 启用自动发射 + 启用战机自动发射功能 + 取消自动发射 + 取消预定的自动发射 + + 状态:已发射 + 自动发射:{0}秒后 + 自动发射:就绪 + + 战机自动发射预定:{0} 将在 {1} 秒后发射 + 检测到威胁 {0},预定战机自动发射 + 检测到狂躁动物 {0},预定战机自动发射 + 自动发射已取消 + + 已获得 {0} {1} + 机库已损坏 + 战机管理器未找到! 空中打击已启动:{0} diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml index 3bf492b8..245d42a7 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml @@ -187,25 +187,6 @@ 需要拥有-生产设施-的战舰部署在殖民地轨道上才能空投 当前地图上没有拥有-生产设施-的战舰部署在殖民地轨道上,无法进行空投 - - 发射战机 - 手动发射战机到战机库 - 启用自动发射 - 启用战机自动发射功能 - 取消自动发射 - 取消预定的自动发射 - - 状态:已发射 - 自动发射:{0}秒后 - 自动发射:就绪 - - 战机自动发射预定:{0} 将在 {1} 秒后发射 - 检测到威胁 {0},预定战机自动发射 - 检测到狂躁动物 {0},预定战机自动发射 - 自动发射已取消 - - 已发射 {0} 架 {1} - 机库已损坏 发射到乌拉帝国舰队 将物品发送到乌拉帝国舰队,以便其使用这些材料进行加工。\n\n如果装备、武器和尸体被送到乌拉帝国舰队,则它们会在下一次成品空投被扔回来,其他的物资若被乌拉帝国舰队接收则一概不退。 @@ -331,4 +312,27 @@ 超出经验已存储 吸收了 {0} 经验,{1} 转换为溢出数据包 所有 {0} 经验转换为溢出数据包(已达到最大品质) + + 使用该技能需要研究科技 {0} + + + 选择轰炸起点 + 选择轰炸方向 + 无法在此位置进行轰炸 + 轰炸进行中 + 轰炸完成 + + 无法在地图外使用 + 轨道上的战舰没有可用的武器阵列(共{0}个,全部冷却中) + 武器阵列:{0}个就绪,{1}个冷却中 + 设施状态错误 + 武器阵列:{0}个就绪,{1}个冷却中 + 冷却时间:{0} + 没有可用的武器阵列 + + + 就绪 + 冷却:{0} + 武器阵列:{0} + 武器阵列:就绪 \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Ability/CompAbilityEffect_ResearchPrereq.cs b/Source/WulaFallenEmpire/Ability/CompAbilityEffect_ResearchPrereq.cs new file mode 100644 index 00000000..9b95aad9 --- /dev/null +++ b/Source/WulaFallenEmpire/Ability/CompAbilityEffect_ResearchPrereq.cs @@ -0,0 +1,32 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_AbilityResearchPrereq : CompProperties_AbilityEffect + { + public ResearchProjectDef requiredResearch; + + public CompProperties_AbilityResearchPrereq() + { + compClass = typeof(CompAbilityEffect_ResearchPrereq); + } + } + + public class CompAbilityEffect_ResearchPrereq : CompAbilityEffect + { + public new CompProperties_AbilityResearchPrereq Props => (CompProperties_AbilityResearchPrereq)props; + + public override bool GizmoDisabled(out string reason) + { + if (Props.requiredResearch != null && !Props.requiredResearch.IsFinished) + { + reason = "WULA_ResearchRequired".Translate(Props.requiredResearch.LabelCap); + return true; + } + + reason = null; + return false; + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompAbilityEffect_Bombardment.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompAbilityEffect_Bombardment.cs index ca361ec1..ea9d84bf 100644 --- a/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompAbilityEffect_Bombardment.cs +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompAbilityEffect_Bombardment.cs @@ -1,4 +1,3 @@ -// CompAbilityEffect_Bombardment.cs using RimWorld; using Verse; using UnityEngine; @@ -7,7 +6,7 @@ using System.Linq; namespace WulaFallenEmpire { - public class CompAbilityEffect_Bombardment : CompAbilityEffect + public class CompAbilityEffect_Bombardment : CompAbilityEffect_WithDest { public new CompProperties_AbilityBombardment Props => (CompProperties_AbilityBombardment)props; @@ -16,7 +15,7 @@ namespace WulaFallenEmpire private List targetCells = new List(); private List bombardmentRows = new List(); private IntVec3 bombardmentCenter; - private Vector3 bombardmentDirection; // 轰炸前进方向(长度方向) + private Vector3 bombardmentDirection; // 轰炸前进方向 private int currentRowIndex = 0; private int currentCellIndex = 0; private int warmupTicksRemaining = 0; @@ -37,15 +36,15 @@ namespace WulaFallenEmpire try { - Log.Message($"[Bombardment] Starting bombardment at {target.Cell}"); + Log.Message($"[Bombardment] Starting bombardment at {target.Cell} with direction to {dest.Cell}"); - // 计算轰炸区域和方向 - CalculateBombardmentArea(target.Cell); + // 计算轰炸区域和方向(基于两个目标点) + CalculateBombardmentArea(target.Cell, dest.Cell); // 选择目标格子 SelectTargetCells(); - // 组织成排 + // 组织成排 - 修复:确保正确的排序 OrganizeTargetCellsIntoRows(); // 开始前摇 @@ -59,6 +58,7 @@ namespace WulaFallenEmpire } } + // 重写:绘制双目标预览 public override void DrawEffectPreview(LocalTargetInfo target) { base.DrawEffectPreview(target); @@ -68,11 +68,15 @@ namespace WulaFallenEmpire try { - // 动态计算轰炸区域 - CalculateDynamicBombardmentArea(target.Cell); - - // 绘制轰炸区域预览 - DrawBombardmentAreaPreview(target.Cell); + // 如果正在选择第二个目标(方向点),则显示轰炸区域预览 + if (selectedTarget.IsValid) + { + // 动态计算轰炸区域(基于第一个目标和当前鼠标位置) + CalculateDynamicBombardmentArea(selectedTarget.Cell, target.Cell); + + // 绘制轰炸区域预览 + DrawBombardmentAreaPreview(selectedTarget.Cell, target.Cell); + } } catch (System.Exception) { @@ -80,29 +84,26 @@ namespace WulaFallenEmpire } } - // 修复:动态计算轰炸区域,确保矩形长边垂直于施法者-目标连线 - private void CalculateDynamicBombardmentArea(IntVec3 targetCell) + // 新增:基于两个目标点动态计算轰炸区域 + private void CalculateDynamicBombardmentArea(IntVec3 startCell, IntVec3 directionCell) { Map map = parent.pawn.Map; - // 计算施法者到目标的方向 - Vector3 casterToTarget = (targetCell.ToVector3() - parent.pawn.Position.ToVector3()).normalized; + // 计算轰炸方向(从起点指向方向点) + Vector3 direction = (directionCell.ToVector3() - startCell.ToVector3()).normalized; // 如果方向为零向量,使用默认方向 - if (casterToTarget == Vector3.zero) + if (direction == Vector3.zero) { - casterToTarget = Vector3.forward; + direction = Vector3.forward; } - // 修复:计算垂直于施法者-目标连线的方向(作为轰炸区域的长边方向) - Vector3 perpendicularDirection = new Vector3(-casterToTarget.z, 0, casterToTarget.x).normalized; - - // 计算轰炸区域的所有单元格(使用正确的方向) - currentPreviewCells = CalculateBombardmentAreaCells(targetCell, perpendicularDirection, casterToTarget); + // 计算轰炸区域的所有单元格 + currentPreviewCells = CalculateBombardmentAreaCells(startCell, direction); } - // 绘制轰炸区域预览 - private void DrawBombardmentAreaPreview(IntVec3 targetCell) + // 绘制轰炸区域预览(基于两个目标点) + private void DrawBombardmentAreaPreview(IntVec3 startCell, IntVec3 directionCell) { Map map = parent.pawn.Map; @@ -116,37 +117,40 @@ namespace WulaFallenEmpire } // 绘制轰炸区域边界 - DrawBombardmentBoundaries(targetCell); + DrawBombardmentBoundaries(startCell, directionCell); } - // 修复:绘制轰炸区域边界,确保矩形长边垂直于施法者-目标连线 - private void DrawBombardmentBoundaries(IntVec3 targetCell) + // 绘制轰炸区域边界(基于两个目标点) + private void DrawBombardmentBoundaries(IntVec3 startCell, IntVec3 directionCell) { Map map = parent.pawn.Map; - // 计算施法者到目标的方向 - Vector3 casterToTarget = (targetCell.ToVector3() - parent.pawn.Position.ToVector3()).normalized; + // 计算轰炸方向 + Vector3 direction = (directionCell.ToVector3() - startCell.ToVector3()).normalized; // 如果方向为零向量,使用默认方向 - if (casterToTarget == Vector3.zero) + if (direction == Vector3.zero) { - casterToTarget = Vector3.forward; + direction = Vector3.forward; } - // 修复:计算垂直于施法者-目标连线的方向(作为轰炸区域的长边方向) - Vector3 lengthDirection = new Vector3(-casterToTarget.z, 0, casterToTarget.x).normalized; - Vector3 widthDirection = casterToTarget; // 宽度方向沿着施法者-目标连线 + // 计算垂直于轰炸方向的方向(作为轰炸区域的宽度方向) + Vector3 perpendicularDirection = new Vector3(-direction.z, 0, direction.x).normalized; // 计算轰炸区域的四个角 - Vector3 targetCenter = targetCell.ToVector3(); + Vector3 startCenter = startCell.ToVector3(); float halfWidth = Props.bombardmentWidth * 0.5f; - float halfLength = Props.bombardmentLength * 0.5f; + float totalLength = Props.bombardmentLength; - Vector3 startLeft = targetCenter - lengthDirection * halfLength + widthDirection * halfWidth; - Vector3 startRight = targetCenter - lengthDirection * halfLength - widthDirection * halfWidth; - Vector3 endLeft = targetCenter + lengthDirection * halfLength + widthDirection * halfWidth; - Vector3 endRight = targetCenter + lengthDirection * halfLength - widthDirection * halfWidth; + // 轰炸起点 + Vector3 startLeft = startCenter + perpendicularDirection * halfWidth; + Vector3 startRight = startCenter - perpendicularDirection * halfWidth; + + // 轰炸终点(沿方向前进轰炸长度) + Vector3 endCenter = startCenter + direction * totalLength; + Vector3 endLeft = endCenter + perpendicularDirection * halfWidth; + Vector3 endRight = endCenter - perpendicularDirection * halfWidth; // 转换为 IntVec3 并确保在地图范围内 IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map); @@ -166,18 +170,39 @@ namespace WulaFallenEmpire if (endLeftCell.InBounds(map) && endRightCell.InBounds(map)) GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f); + + // 绘制方向箭头 + DrawDirectionArrow(startCell, directionCell); } - // 修复:计算轰炸区域的所有单元格,确保正确的方向 - private List CalculateBombardmentAreaCells(IntVec3 centerCell, Vector3 lengthDirection, Vector3 widthDirection) + // 绘制方向箭头 + private void DrawDirectionArrow(IntVec3 startCell, IntVec3 directionCell) + { + Map map = parent.pawn.Map; + + Vector3 startPos = startCell.ToVector3Shifted(); + Vector3 directionPos = directionCell.ToVector3Shifted(); + + // 绘制从起点到方向点的连线 + GenDraw.DrawLineBetween(startPos, directionPos, SimpleColor.Yellow, 0.1f); + + // 在方向点绘制箭头标记 + GenDraw.DrawTargetHighlight(directionCell); + } + + // 计算轰炸区域的所有单元格(基于起点和方向) + private List CalculateBombardmentAreaCells(IntVec3 startCell, Vector3 direction) { var areaCells = new List(); Map map = parent.pawn.Map; - Vector3 center = centerCell.ToVector3(); + Vector3 start = startCell.ToVector3(); + + // 计算垂直于轰炸方向的方向(宽度方向) + Vector3 perpendicularDirection = new Vector3(-direction.z, 0, direction.x).normalized; float halfWidth = Props.bombardmentWidth * 0.5f; - float halfLength = Props.bombardmentLength * 0.5f; + float totalLength = Props.bombardmentLength; // 使用浮点步进计算所有单元格 int widthSteps = Mathf.Max(1, Props.bombardmentWidth); @@ -186,15 +211,15 @@ namespace WulaFallenEmpire for (int l = 0; l <= lengthSteps; l++) { float lengthProgress = (float)l / lengthSteps; - float lengthOffset = Mathf.Lerp(-halfLength, halfLength, lengthProgress); + float lengthOffset = Mathf.Lerp(0, totalLength, lengthProgress); for (int w = 0; w <= widthSteps; w++) { float widthProgress = (float)w / widthSteps; float widthOffset = Mathf.Lerp(-halfWidth, halfWidth, widthProgress); - // 修复:使用正确的方向计算单元格位置 - Vector3 cellPos = center + lengthDirection * lengthOffset + widthDirection * widthOffset; + // 计算单元格位置 + Vector3 cellPos = start + direction * lengthOffset + perpendicularDirection * widthOffset; IntVec3 cell = new IntVec3( Mathf.RoundToInt(cellPos.x), @@ -212,44 +237,29 @@ namespace WulaFallenEmpire return areaCells; } - // 修复:计算轰炸区域和方向,确保轰炸前进方向垂直于施法者-目标连线 - private void CalculateBombardmentArea(IntVec3 targetCell) + // 计算轰炸区域和方向(基于两个目标点) + private void CalculateBombardmentArea(IntVec3 startCell, IntVec3 directionCell) { - bombardmentCenter = targetCell; + bombardmentCenter = startCell; - // 计算施法者到目标的方向 - Vector3 casterToTarget = (targetCell.ToVector3() - parent.pawn.Position.ToVector3()).normalized; + // 计算轰炸方向(从起点指向方向点) + Vector3 direction = (directionCell.ToVector3() - startCell.ToVector3()).normalized; // 如果方向为零向量,使用默认方向 - if (casterToTarget == Vector3.zero) + if (direction == Vector3.zero) { - casterToTarget = Vector3.forward; + direction = Vector3.forward; } - // 修复:计算垂直于施法者-目标连线的两个方向(作为可能的轰炸前进方向) - Vector3 perpendicular1 = new Vector3(-casterToTarget.z, 0, casterToTarget.x).normalized; - Vector3 perpendicular2 = new Vector3(casterToTarget.z, 0, -casterToTarget.x).normalized; + bombardmentDirection = direction; - // 随机选择轰炸前进方向(垂直于施法者-目标连线) - bombardmentDirection = Rand.Value < 0.5f ? perpendicular1 : perpendicular2; - - Log.Message($"[Bombardment] Bombardment direction: {bombardmentDirection} (perpendicular to caster-target line)"); + Log.Message($"[Bombardment] Bombardment direction: {bombardmentDirection} (from {startCell} to {directionCell})"); } private void SelectTargetCells() { - // 计算施法者到目标的方向 - Vector3 casterToTarget = (bombardmentCenter.ToVector3() - parent.pawn.Position.ToVector3()).normalized; - - // 如果方向为零向量,使用默认方向 - if (casterToTarget == Vector3.zero) - { - casterToTarget = Vector3.forward; - } - - // 修复:使用正确的方向计算轰炸区域 - Vector3 widthDirection = casterToTarget; // 宽度方向沿着施法者-目标连线 - var areaCells = CalculateBombardmentAreaCells(bombardmentCenter, bombardmentDirection, widthDirection); + // 计算轰炸区域的所有单元格 + var areaCells = CalculateBombardmentAreaCells(bombardmentCenter, bombardmentDirection); var selectedCells = new List(); var missedCells = new List(); @@ -287,21 +297,20 @@ namespace WulaFallenEmpire Log.Message($"[Bombardment] Selected {targetCells.Count} target cells from {areaCells.Count} area cells"); } - // 修复:组织目标格子成排,按照轰炸前进方向分组 + // 修复:重新组织目标格子成排,确保正确的渐进顺序 private void OrganizeTargetCellsIntoRows() { bombardmentRows.Clear(); - // 计算施法者到目标的方向(作为宽度方向) - Vector3 casterToTarget = (bombardmentCenter.ToVector3() - parent.pawn.Position.ToVector3()).normalized; - Vector3 widthDirection = casterToTarget; + // 计算垂直于轰炸方向的方向(宽度方向) + Vector3 perpendicularDirection = new Vector3(-bombardmentDirection.z, 0, bombardmentDirection.x).normalized; // 根据轰炸前进方向将格子分组到不同的排 var rows = new Dictionary>(); foreach (var cell in targetCells) { - // 计算格子相对于轰炸中心的"行索引"(在轰炸前进方向上的投影) + // 计算格子相对于轰炸起点的"行索引"(在轰炸前进方向上的投影) Vector3 cellVector = cell.ToVector3() - bombardmentCenter.ToVector3(); float dotProduct = Vector3.Dot(cellVector, bombardmentDirection); int rowIndex = Mathf.RoundToInt(dotProduct); @@ -313,22 +322,28 @@ namespace WulaFallenEmpire rows[rowIndex].Add(cell); } - // 按行索引排序并创建 BombardmentRow + // 修复:按照轰炸方向正确排序行索引 + // 从起点(行索引=0)开始,向轰炸方向前进 var sortedRowIndices = rows.Keys.OrderBy(x => x).ToList(); + foreach (var rowIndex in sortedRowIndices) { + // 修复:在每排内按照宽度方向正确排序 + // 从轰炸区域的一侧到另一侧 + var sortedCells = rows[rowIndex].OrderBy(cell => + { + Vector3 cellVector = cell.ToVector3() - bombardmentCenter.ToVector3(); + return Vector3.Dot(cellVector, perpendicularDirection); + }).ToList(); + bombardmentRows.Add(new BombardmentRow { rowIndex = rowIndex, - cells = rows[rowIndex].OrderBy(cell => - { - Vector3 cellVector = cell.ToVector3() - bombardmentCenter.ToVector3(); - return Vector3.Dot(cellVector, widthDirection); // 在宽度方向上排序 - }).ToList() + cells = sortedCells }); } - Log.Message($"[Bombardment] Organized into {bombardmentRows.Count} rows"); + Log.Message($"[Bombardment] Organized into {bombardmentRows.Count} rows in progressive order"); } private void StartWarmup() @@ -356,7 +371,7 @@ namespace WulaFallenEmpire // 前摇结束,开始轰炸 currentState = BombardmentState.Bombarding; nextBombardmentTick = Find.TickManager.TicksGame; - Log.Message($"[Bombardment] Warmup completed, starting bombardment"); + Log.Message($"[Bombardment] Warmup completed, starting progressive bombardment"); } } @@ -369,7 +384,7 @@ namespace WulaFallenEmpire { // 所有排都轰炸完毕 currentState = BombardmentState.Completed; - Log.Message($"[Bombardment] Bombardment completed"); + Log.Message($"[Bombardment] Progressive bombardment completed"); return; } @@ -381,7 +396,7 @@ namespace WulaFallenEmpire currentRowIndex++; currentCellIndex = 0; nextBombardmentTick = Find.TickManager.TicksGame + Props.rowDelayTicks; - Log.Message($"[Bombardment] Moving to row {currentRowIndex + 1}/{bombardmentRows.Count}"); + Log.Message($"[Bombardment] Moving to next row {currentRowIndex + 1}/{bombardmentRows.Count}"); return; } @@ -391,6 +406,9 @@ namespace WulaFallenEmpire currentCellIndex++; nextBombardmentTick = Find.TickManager.TicksGame + Props.impactDelayTicks; + + // 记录轰炸进度 + Log.Message($"[Bombardment] Bombarding cell {currentCellIndex}/{currentRow.cells.Count} in row {currentRowIndex + 1}/{bombardmentRows.Count}"); } private void LaunchBombardment(IntVec3 targetCell) @@ -511,6 +529,80 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref warmupTicksRemaining, "warmupTicksRemaining", 0); Scribe_Values.Look(ref nextBombardmentTick, "nextBombardmentTick", 0); } + + // 重写:获取目标参数 + public override TargetingParameters targetParams => new TargetingParameters + { + canTargetLocations = true, + canTargetPawns = false, + canTargetBuildings = false, + canTargetItems = false, + mapObjectTargetsMustBeAutoAttackable = false + }; + + // 重写:验证目标 + public override bool ValidateTarget(LocalTargetInfo target, bool showMessages = true) + { + if (!target.IsValid) + { + return false; + } + + // 检查是否可以放置目标 + if (!CanPlaceSelectedTargetAt(target)) + { + if (showMessages) + { + // 修复:使用 LookTargets 而不是 LocalTargetInfo + Messages.Message("CannotBombardInvalidLocation".Translate(), new LookTargets(target.Cell, parent.pawn.Map), MessageTypeDefOf.RejectInput); + } + return false; + } + + return true; + } + + // 修复:使用 new 而不是 override,因为基类方法不是 virtual + public new void DrawHighlight(LocalTargetInfo target) + { + if (selectedTarget.IsValid) + { + // 当选择第二个目标时,显示轰炸区域 + CalculateDynamicBombardmentArea(selectedTarget.Cell, target.Cell); + DrawBombardmentAreaPreview(selectedTarget.Cell, target.Cell); + } + else + { + // 当选择第一个目标时,显示普通高亮 + GenDraw.DrawTargetHighlight(target); + } + } + + // 修复:使用 new 而不是 override,因为基类方法不是 virtual + public new void OnGUI(LocalTargetInfo target) + { + Texture2D icon = ((!target.IsValid) ? TexCommand.CannotShoot : parent.def.uiIcon); + GenUI.DrawMouseAttachment(icon); + + string text = ExtraLabelMouseAttachment(target); + if (!text.NullOrEmpty()) + { + Widgets.MouseAttachedLabel(text); + } + } + + // 重写:额外标签 + public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + { + if (selectedTarget.IsValid) + { + return "SelectBombardmentDirection".Translate(); + } + else + { + return "SelectBombardmentStart".Translate(); + } + } } // 轰炸状态枚举 diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompProperties_AbilityBombardment.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompProperties_AbilityBombardment.cs index c21b7a61..9ad967b8 100644 --- a/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompProperties_AbilityBombardment.cs +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilityBombardment/CompProperties_AbilityBombardment.cs @@ -1,11 +1,10 @@ -// CompProperties_AbilityBombardment.cs using RimWorld; using Verse; using UnityEngine; namespace WulaFallenEmpire { - public class CompProperties_AbilityBombardment : CompProperties_AbilityEffect + public class CompProperties_AbilityBombardment : CompProperties_EffectWithDest { // 轰炸区域配置 public int bombardmentWidth = 5; // 轰炸区域宽度 @@ -33,6 +32,8 @@ namespace WulaFallenEmpire public CompProperties_AbilityBombardment() { this.compClass = typeof(CompAbilityEffect_Bombardment); + // 设置双目标选择 + this.destination = AbilityEffectDestination.Selected; } } } diff --git a/Source/WulaFallenEmpire/Flyover/WULA_FlyOverFacilities/CompFlyOverFacilities.cs b/Source/WulaFallenEmpire/Flyover/WULA_FlyOverFacilities/CompFlyOverFacilities.cs index b2404442..8615ee26 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_FlyOverFacilities/CompFlyOverFacilities.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_FlyOverFacilities/CompFlyOverFacilities.cs @@ -7,6 +7,27 @@ namespace WulaFallenEmpire { public class CompFlyOverFacilities : ThingComp { + // 在 CompFlyOverFacilities 类中添加以下方法 + public bool IsFacilityReady(string facilityName) + { + if (!HasFacility(facilityName)) + return false; + + var cooldownComp = parent.GetComp(); + return cooldownComp == null || !cooldownComp.IsOnCooldown; + } + + public string GetFacilityStatus(string facilityName) + { + if (!HasFacility(facilityName)) + return "Not Available"; + + var cooldownComp = parent.GetComp(); + if (cooldownComp == null) + return "Ready (No Cooldown)"; + + return cooldownComp.IsOnCooldown ? $"Cooldown: {cooldownComp.CooldownTicksRemaining.ToStringTicksToPeriod()}" : "Ready"; + } public CompProperties_FlyOverFacilities Props => (CompProperties_FlyOverFacilities)props; // 当前激活的设施列表 @@ -62,6 +83,8 @@ namespace WulaFallenEmpire } } + + public class CompProperties_FlyOverFacilities : CompProperties { // 可用的设施列表(简单的字符串列表) diff --git a/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompAbilityEffect_GlobalFlyOverCooldown.cs b/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompAbilityEffect_GlobalFlyOverCooldown.cs new file mode 100644 index 00000000..1ef6a3fa --- /dev/null +++ b/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompAbilityEffect_GlobalFlyOverCooldown.cs @@ -0,0 +1,238 @@ +using RimWorld; +using Verse; +using System.Collections.Generic; +using System.Linq; + +namespace WulaFallenEmpire +{ + public class CompAbilityEffect_GlobalFlyOverCooldown : CompAbilityEffect + { + public new CompProperties_GlobalFlyOverCooldown Props => (CompProperties_GlobalFlyOverCooldown)props; + + public override void Apply(LocalTargetInfo target, LocalTargetInfo dest) + { + base.Apply(target, dest); + + if (parent.pawn == null || parent.pawn.Map == null) + return; + + // 获取所有可用的轰炸设施FlyOver + var availableFlyOvers = GetAvailableFlyOvers(); + + if (availableFlyOvers.Count == 0) + { + Log.Error($"[GlobalFlyOverCooldown] No available FlyOver with BombardmentFacility found"); + return; + } + + // 随机选择一个FlyOver来执行任务 + var selectedFlyOver = availableFlyOvers.RandomElement(); + var facilitiesComp = selectedFlyOver.GetComp(); + + if (facilitiesComp == null) + { + Log.Error($"[GlobalFlyOverCooldown] Selected FlyOver has no CompFlyOverFacilities"); + return; + } + + // 设置冷却时间 + SetCooldown(selectedFlyOver, Props.globalCooldownTicks); + + Log.Message($"[GlobalFlyOverCooldown] Set cooldown on FlyOver at {selectedFlyOver.Position} for {Props.globalCooldownTicks} ticks"); + } + + public override bool GizmoDisabled(out string reason) + { + if (parent.pawn?.Map == null) + { + reason = "WULA_GlobalFlyOverCooldown.CannotUseOutsideMap".Translate(); + return true; + } + + var availableFlyOvers = GetAvailableFlyOvers(); + var totalFlyOvers = GetTotalFlyOvers(); + + if (availableFlyOvers.Count == 0) + { + reason = "WULA_GlobalFlyOverCooldown.NoAvailableFacilities".Translate(totalFlyOvers.Count); + return true; + } + + return base.GizmoDisabled(out reason); + } + + public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + { + try + { + var availableFlyOvers = GetAvailableFlyOvers(); + var totalFlyOvers = GetTotalFlyOvers(); + var cooldownFlyOvers = totalFlyOvers.Count - availableFlyOvers.Count; + + return "WULA_GlobalFlyOverCooldown.FacilityStatus".Translate(availableFlyOvers.Count, cooldownFlyOvers); + } + catch (System.Exception ex) + { + Log.Error($"[GlobalFlyOverCooldown] Error in ExtraLabelMouseAttachment: {ex}"); + return "WULA_GlobalFlyOverCooldown.FacilityStatusError".Translate(); + } + } + + // 重写:添加额外的工具提示信息 + public override string ExtraTooltipPart() + { + var availableFlyOvers = GetAvailableFlyOvers(); + var totalFlyOvers = GetTotalFlyOvers(); + var cooldownFlyOvers = totalFlyOvers.Count - availableFlyOvers.Count; + + var baseTooltip = base.ExtraTooltipPart() ?? ""; + var facilityDesc = "\n" + "WULA_GlobalFlyOverCooldown.FacilityStatusDetailed".Translate(availableFlyOvers.Count, cooldownFlyOvers); + + if (availableFlyOvers.Count > 0) + { + var cooldownComp = availableFlyOvers[0].GetComp(); + if (cooldownComp != null) + { + facilityDesc += "\n" + "WULA_GlobalFlyOverCooldown.CooldownTime".Translate(Props.globalCooldownTicks.ToStringTicksToPeriod()); + } + } + + return baseTooltip + facilityDesc; + } + + // 重写:验证目标时检查设施可用性 + public override bool Valid(LocalTargetInfo target, bool throwMessages = false) + { + if (!base.Valid(target, throwMessages)) + return false; + + var availableFlyOvers = GetAvailableFlyOvers(); + + if (availableFlyOvers.Count == 0) + { + if (throwMessages) + { + Messages.Message("WULA_GlobalFlyOverCooldown.NoAvailableFacilitiesSimple".Translate(), parent.pawn, MessageTypeDefOf.RejectInput); + } + return false; + } + + return true; + } + + // 获取可用的FlyOver(不在冷却中的) + private List GetAvailableFlyOvers() + { + var availableFlyOvers = new List(); + + if (parent.pawn?.Map == null) + return availableFlyOvers; + + try + { + var allFlyOvers = GetTotalFlyOvers(); + + foreach (var flyOver in allFlyOvers) + { + if (!IsOnCooldown(flyOver)) + { + availableFlyOvers.Add(flyOver); + } + } + + return availableFlyOvers; + } + catch (System.Exception ex) + { + Log.Error($"[GlobalFlyOverCooldown] Error in GetAvailableFlyOvers: {ex}"); + return new List(); + } + } + + // 获取所有具有轰炸设施的FlyOver + private List GetTotalFlyOvers() + { + var totalFlyOvers = new List(); + + if (parent.pawn?.Map == null) + return totalFlyOvers; + + try + { + // 获取地图上所有FlyOver + var allFlyOvers = new List(); + var dynamicObjects = parent.pawn.Map.dynamicDrawManager.DrawThings; + + foreach (var thing in dynamicObjects) + { + if (thing is FlyOver flyOver && !flyOver.Destroyed) + { + allFlyOvers.Add(thing); + } + } + + // 筛选具有轰炸设施的FlyOver + foreach (var thing in allFlyOvers) + { + if (thing is FlyOver flyOver) + { + var facilitiesComp = flyOver.GetComp(); + if (facilitiesComp != null && facilitiesComp.HasFacility("BombardmentFacility")) + { + totalFlyOvers.Add(flyOver); + } + } + } + + return totalFlyOvers; + } + catch (System.Exception ex) + { + Log.Error($"[GlobalFlyOverCooldown] Error in GetTotalFlyOvers: {ex}"); + return new List(); + } + } + + // 检查FlyOver是否在冷却中 + private bool IsOnCooldown(FlyOver flyOver) + { + if (flyOver == null) + return true; + + // 从FlyOver的comps中查找冷却组件 + var cooldownComp = flyOver.GetComp(); + return cooldownComp?.IsOnCooldown ?? false; + } + + // 设置FlyOver的冷却时间 + private void SetCooldown(FlyOver flyOver, int cooldownTicks) + { + if (flyOver == null) + return; + + // 获取或添加冷却组件 + var cooldownComp = flyOver.GetComp(); + if (cooldownComp == null) + { + Log.Error($"[GlobalFlyOverCooldown] FlyOver at {flyOver.Position} has no CompFlyOverCooldown"); + return; + } + + cooldownComp.StartCooldown(cooldownTicks); + } + } + + public class CompProperties_GlobalFlyOverCooldown : CompProperties_AbilityEffect + { + // 全局冷却时间(ticks) + public int globalCooldownTicks = 60000; // 默认1天 + + // 必需的设施名称 + public string requiredFacility = "BombardmentFacility"; + + public CompProperties_GlobalFlyOverCooldown() + { + compClass = typeof(CompAbilityEffect_GlobalFlyOverCooldown); + } + } +} diff --git a/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompFlyOverCooldown.cs b/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompFlyOverCooldown.cs new file mode 100644 index 00000000..4f9a0b80 --- /dev/null +++ b/Source/WulaFallenEmpire/Flyover/WULA_GlobalFlyOverCooldown/CompFlyOverCooldown.cs @@ -0,0 +1,96 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompFlyOverCooldown : ThingComp + { + public CompProperties_FlyOverCooldown Props => (CompProperties_FlyOverCooldown)props; + + // 冷却结束的tick + private int cooldownEndTick = -1; + + // 是否在冷却中 + public bool IsOnCooldown => Find.TickManager.TicksGame < cooldownEndTick; + + // 剩余冷却时间(ticks) + public int CooldownTicksRemaining => IsOnCooldown ? cooldownEndTick - Find.TickManager.TicksGame : 0; + + // 冷却进度(0-1) + public float CooldownProgress + { + get + { + if (!IsOnCooldown) return 0f; + int totalCooldown = cooldownEndTick - (cooldownEndTick - Props.baseCooldownTicks); + return 1f - ((float)CooldownTicksRemaining / Props.baseCooldownTicks); + } + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref cooldownEndTick, "cooldownEndTick", -1); + } + + // 开始冷却 + public void StartCooldown(int cooldownTicks = -1) + { + int actualCooldown = cooldownTicks > 0 ? cooldownTicks : Props.baseCooldownTicks; + cooldownEndTick = Find.TickManager.TicksGame + actualCooldown; + + Log.Message($"[FlyOverCooldown] Cooldown started for {actualCooldown} ticks, ends at tick {cooldownEndTick}"); + } + + // 强制结束冷却 + public void EndCooldown() + { + cooldownEndTick = -1; + } + + // 获取冷却状态描述 + public string GetCooldownStatus() + { + if (!IsOnCooldown) + return "WULA_FlyOverCooldown.Ready".Translate(); + + return "WULA_FlyOverCooldown.CooldownRemaining".Translate(CooldownTicksRemaining.ToStringTicksToPeriod()); + } + + public override void CompTick() + { + base.CompTick(); + + // 可以在这里添加冷却期间的视觉效果或逻辑 + if (IsOnCooldown && Find.TickManager.TicksGame % 60 == 0) // 每60ticks检查一次 + { + // 可选:在冷却期间添加一些视觉效果 + if (Rand.MTBEventOccurs(10f, 1f, 1f)) + { + FleckMaker.ThrowMetaIcon(parent.Position, parent.Map, FleckDefOf.SleepZ); + } + } + } + + // 在检视面板中显示冷却信息 + public override string CompInspectStringExtra() + { + if (IsOnCooldown) + { + return "WULA_FlyOverCooldown.BombardmentFacilityStatus".Translate(GetCooldownStatus()); + } + return "WULA_FlyOverCooldown.BombardmentFacilityReady".Translate(); + } + } + + public class CompProperties_FlyOverCooldown : CompProperties + { + // 基础冷却时间(ticks) + public int baseCooldownTicks = 60000; // 默认1天 + + public CompProperties_FlyOverCooldown() + { + compClass = typeof(CompFlyOverCooldown); + } + } +} diff --git a/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs b/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs index 7d268b2e..c1022496 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs @@ -62,7 +62,7 @@ namespace WulaFallenEmpire BombingRun, // 轰炸飞越 Reconnaissance, // 侦察飞越 GroundStrafing, // 地面扫射 - SectorSurveillance // 扇形区域监视 + SectorSurveillance, // 扇形区域监视 } // 进场类型枚举 diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index b0f02265..9a2ece80 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -71,6 +71,7 @@ + @@ -102,6 +103,9 @@ + + +