diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 15fffd0b..4c9b51c4 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 85eaf6f1..4233a8cc 100644 --- a/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml +++ b/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml @@ -217,6 +217,56 @@ + + WULA_Spawn_BattleShip_Artillery + + 申请沿指定航道发起全域封锁,一整只乌拉帝国舰队将在大量战机编队的掩护下沿着航道行进,并使用所有的可用武器进行轰炸,以彻底粉碎一切抵抗。 + Wula/UI/Abilities/WULA_Spawn_Fighter_Drone_Laser + 1 + Misc12 + false + + Verb_CastAbility + false + false + 0 + 120 + true + + false + true + + + + + +
  • + WULA_MotherShip_Planet_Interdiction + GroundStrafing + 0.005 + 20 + true + Perpendicular + + + true + + + false + + + true + (0.3,0.7,1.0,0.3) +
  • +
    +
    + WULA_Spawn_Fighter_Drone_Laser diff --git a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml index 28342a2f..deabc91d 100644 --- a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml +++ b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml @@ -13,7 +13,7 @@
  • - + true (255,255,255,255) (157,201,185,195) @@ -23,6 +23,24 @@
  • +
  • + 陆行舰正在逼近 + 艾妮西娅按照要求,吸引了一艘乌拉帝国的陆行舰机械体攻击我们的殖民地! + 100 + Mechanoid + ImmediateAttack + EdgeWalkIn + Combat + +
  • + Combat + 100 + + 100 + +
  • + + 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 9aef23a2..9c358982 100644 --- a/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml +++ b/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml @@ -105,6 +105,7 @@
  • WULA_CallAircraftCarrier
  • WULA_CallConstructionShip
  • WULA_ClearFlightPath
  • +
  • WULA_Spawn_BattleShip_Artillery
  • diff --git a/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml b/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml index e27f8ab8..388414f8 100644 --- a/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml +++ b/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml @@ -181,17 +181,22 @@ 1 - -
  • + +
  • 1 - WULA_GiveQuest_Intro_Spy - WULA_Intro_Spy + WULA_GiveQuest_Intro_Spy + WULA_Intro_Spy + true + Allow + +
  • WULA_Awakened_Synth
  • + +
  • Map_PlayerHome
  • - -
  • Ludeon.RimWorld.Odyssey
  • -
    diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml index f6ad8e3c..75899fcc 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml @@ -750,7 +750,7 @@ true 52 - 32 + 99999 1 WULA_RW_Handle_Cannon_Burn 1 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 5b285193..92672aa3 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 @@ -673,6 +673,549 @@ + + + WULA_MotherShip_Planet_Interdiction + + WulaFallenEmpire.FlyOver + Normal + RealtimeOnly + + Wula/FlyoverThing/WULA_MotherShip_Shadow + Graphic_Single + TransparentPostLight + (100,250) + (195,195,195,45) + + + Wula/Weapon/WULA_Weapon_Empty + (0, 0) + 0 + FlyOver/Flying + + + +
  • + Wula/Weapon/WULA_Weapon_Empty + true + 0.8 + 0 + 0 + 0 + 0 + + + false + false + false + true + 1 + 50 +
  • +
    + true + false + false + false + MetaOverlays + +
  • + 300 + 30 + 65 + WULA_Firepower_Primary_Cannon_Strafe_Skyfaller + 3 + + + true + true +
  • + +
  • + 60 + 全域封锁 + 全域封锁舰队已抵达,请自行寻找掩护! + PositiveEvent + true + true + false +
  • + +
  • + WULA_MotherShip_Planet_Interdiction_Escort + + + 3000 + 2 + 1 + + + 0 + 40 + 5 + true + 10 + 70 + + + 1 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.5 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
  • + WULA_BattleShip_Planet_Interdiction + + + 4000 + 5 + 1 + + + 0 + 70 + 5 + true + 10 + 70 + + + 1 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.5 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
  • + WULA_Striker_Escort + + + 1000 + 20 + 1 + + + 0 + 100 + 5 + true + 10 + 70 + + + 8 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
  • + WULA_Bomber_Escort + + + 1350 + 10 + 1 + + + 0 + 130 + 5 + true + 10 + 70 + + + 5 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
    +
    + + WULA_MotherShip_Planet_Interdiction_Escort + + WulaFallenEmpire.FlyOver + Normal + RealtimeOnly + + Wula/FlyoverThing/WULA_MotherShip_Shadow + Graphic_Single + TransparentPostLight + (100,250) + (195,195,195,45) + + + Wula/Weapon/WULA_Weapon_Empty + (0, 0) + 0 + FlyOver/Flying + + + +
  • + Wula/Weapon/WULA_Weapon_Empty + true + 0.8 + 0 + 0 + 0 + 0 + + + false + false + false + true + 1 + 50 +
  • +
    + true + false + false + false + MetaOverlays + +
  • + 300 + 300 + 65 + WULA_Firepower_Cannon_Salvo_Skyfaller + 12 + + + true + true +
  • + +
  • + WULA_Striker_Escort + + + 1000 + 20 + 1 + + + 0 + 100 + 5 + true + 10 + 70 + + + 8 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
  • + WULA_Bomber_Escort + + + 1350 + 10 + 1 + + + 0 + 130 + 5 + true + 10 + 70 + + + 5 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
    +
    + + WULA_BattleShip_Planet_Interdiction + + WulaFallenEmpire.FlyOver + Normal + RealtimeOnly + + Wula/FlyoverThing/WULA_BattleShip_Shadow + Graphic_Single + TransparentPostLight + (70,100) + (195,195,195,45) + + + Wula/Weapon/WULA_Weapon_Empty + (0, 0) + 0 + FlyOver/Flying + + + +
  • + Wula/Weapon/WULA_Weapon_Empty + true + 0.8 + 0 + 0 + 0 + 0 + + + false + false + false + true + 1 + 50 +
  • +
    + true + false + false + false + MetaOverlays + +
  • + 300 + 30 + 25 + WULA_Planet_Interdiction_EnergyLance_Skyfaller + 1 + + + true + true +
  • +
    +
    + + WULA_Planet_Interdiction_EnergyLance_Skyfaller + + (1,1) + + Wula/Weapon/WULA_Weapon_Empty + Graphic_Single + TransparentPostLight + (1,1) + (255,255,255,150) + + false + + + + Decelerate + Things/Skyfaller/SkyfallerShadowDropPod + (0, 0) + DropPod_Fall + 100 + + 0.05 + 0 + 0 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + WULA_Firepower_EnergyLance_Surveillance_Beacon +
    +
    + + WULA_Planet_Interdiction_EnergyLance_Beacon + + 一枚标定监视区的轰炸信标,进入此处的敌对势力都会被乌拉帝国舰队的舰炮狠狠打击。 + Wula/Building/WULA_WeaponArmor_Productor + Normal + false + false + (1,1) + + Wula/Weapon/WULA_Weapon_Empty + Graphic_Single + TransparentPostLight + (72,72) + (255,255,255,150) + + false + + + Building + Standable + false + 0.5 + false + 0 + false + false + + 1 + 0 + 0 + + 0 + + false + BuildingDestroyed_Metal_Small + + +
  • + WULA_EnergyLance_Surveillance + 600 + 25 + 36 + 30 + 20 + 45 + 180 +
  • +
  • + + true + false +
  • +
  • + 600 +
  • +
    +
    + WulaFallenEmpire.FlyOver diff --git a/Source/WulaFallenEmpire/Flyover/WULA_DestroyFlyOverByFacilities/CompProperties_DestroyFlyOverByFacilities.cs b/Source/WulaFallenEmpire/Flyover/WULA_DestroyFlyOverByFacilities/CompProperties_DestroyFlyOverByFacilities.cs index 3063c5d8..745a8c87 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_DestroyFlyOverByFacilities/CompProperties_DestroyFlyOverByFacilities.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_DestroyFlyOverByFacilities/CompProperties_DestroyFlyOverByFacilities.cs @@ -24,33 +24,110 @@ namespace WulaFallenEmpire if (parent.pawn?.Map == null) return; - // 销毁所有 FlyOver 物体 - DestroyAllFlyOvers(); + // 只销毁带有 CompFlyOverFacilities 的 FlyOver + DestroyFlyOversWithFacilities(); } - // 销毁所有 FlyOver - private void DestroyAllFlyOvers() + // 只销毁带有设施的 FlyOver + private void DestroyFlyOversWithFacilities() { - List flyOvers = new List(); + List flyOversWithFacilities = new List(); - // 获取地图上所有的 FlyOver - foreach (Thing thing in parent.pawn.Map.listerThings.AllThings) + // 使用 CompFlyOverFacilities 的静态方法来获取所有带有设施的 FlyOver + var allFlyOvers = CompFlyOverFacilities.GetAllFlyOversWithFacilities(parent.pawn.Map); + + if (allFlyOvers.Count > 0) { - if (thing is FlyOver flyOver) + foreach (var flyOver in allFlyOvers) { - flyOvers.Add(flyOver); + if (flyOver != null && !flyOver.Destroyed) + { + flyOversWithFacilities.Add(flyOver); + } } } - // 销毁找到的 FlyOver - foreach (FlyOver flyOver in flyOvers) + // 销毁找到的带有设施的 FlyOver + foreach (FlyOver flyOver in flyOversWithFacilities) { flyOver.EmergencyDestroy(); + Log.Message($"[DestroyFlyOverByFacilities] Destroyed FlyOver with facilities at {flyOver.Position}"); } - if (flyOvers.Count > 0) + if (flyOversWithFacilities.Count > 0) { - Messages.Message($"WULA_DestroyFlyOver".Translate(), parent.pawn, MessageTypeDefOf.PositiveEvent); + Messages.Message($"WULA_DestroyFlyOver".Translate(flyOversWithFacilities.Count), parent.pawn, MessageTypeDefOf.PositiveEvent); + } + else + { + Messages.Message("WULA_NoFlyOverWithFacilities".Translate(), parent.pawn, MessageTypeDefOf.NeutralEvent); + } + } + + // 添加验证方法,确保只在有相关 FlyOver 时可用 + public override bool Valid(LocalTargetInfo target, bool throwMessages = false) + { + if (!base.Valid(target, throwMessages)) + return false; + + // 检查是否有带有设施的 FlyOver + if (parent.pawn?.Map == null) + return false; + + var flyOversWithFacilities = CompFlyOverFacilities.GetAllFlyOversWithFacilities(parent.pawn.Map); + + if (flyOversWithFacilities.Count == 0) + { + if (throwMessages) + { + Messages.Message("WULA_NoFlyOverWithFacilities".Translate(), parent.pawn, MessageTypeDefOf.RejectInput); + } + return false; + } + + return true; + } + + public override bool GizmoDisabled(out string reason) + { + if (parent.pawn?.Map == null) + { + reason = "Cannot use outside of map"; + return true; + } + + // 检查是否有带有设施的 FlyOver + var flyOversWithFacilities = CompFlyOverFacilities.GetAllFlyOversWithFacilities(parent.pawn.Map); + + if (flyOversWithFacilities.Count == 0) + { + reason = "No FlyOver with facilities found"; + return true; + } + + return base.GizmoDisabled(out reason); + } + + public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + { + try + { + if (parent.pawn?.Map == null) + return "Cannot use outside of map"; + + var flyOversWithFacilities = CompFlyOverFacilities.GetAllFlyOversWithFacilities(parent.pawn.Map); + + if (flyOversWithFacilities.Count > 0) + { + return $"Will destroy {flyOversWithFacilities.Count} FlyOver(s) with facilities"; + } + + return "No FlyOver with facilities found"; + } + catch (System.Exception ex) + { + Log.Error($"[DestroyFlyOverByFacilities] Error in ExtraLabelMouseAttachment: {ex}"); + return "Error checking FlyOver status"; } } } diff --git a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompProperties_ShipArtillery.cs b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompProperties_ShipArtillery.cs index 7963c01c..328dd556 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompProperties_ShipArtillery.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompProperties_ShipArtillery.cs @@ -42,11 +42,16 @@ namespace WulaFallenEmpire public bool avoidHittingFlyOver = true; // 信件通知 - public bool sendAttackLetter = true; // 是否发送攻击信件 + public bool sendAttackLetter = false; // 是否发送攻击信件 public string customLetterLabel; // 自定义信件标题 public string customLetterText; // 自定义信件内容 public LetterDef letterDef = LetterDefOf.ThreatBig; // 信件类型 + // 新增:派系甄别系统 + public bool useFactionDiscrimination = false; // 是否使用派系甄别 + public FactionDef targetFaction; // 目标派系(友军派系) + public bool useMicroTracking = false; // 是否启用微追踪 + public CompProperties_ShipArtillery() { compClass = typeof(CompShipArtillery); diff --git a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs index 82f5a275..309e052f 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs @@ -24,6 +24,16 @@ namespace WulaFallenEmpire // 目标跟踪 private List previousTargets = new List(); + // 新增:微追踪目标列表 + private List microTrackingTargets = new List(); + private List microTrackingWeights = new List(); // 新增:权重列表 + + // 新增:目标类型权重配置 + private const float PAWN_WEIGHT = 5.0f; // Pawn权重:5倍 + private const float OWNED_BUILDING_WEIGHT = 1.0f; // 有主建筑权重:1倍 + private const float UNOWNED_BUILDING_WEIGHT = 0.01f; // 无主建筑权重:0.01倍 + private const float OTHER_WEIGHT = 1.0f; // 其他目标权重:1倍 + public override void Initialize(CompProperties props) { base.Initialize(props); @@ -31,6 +41,7 @@ namespace WulaFallenEmpire ticksUntilNextAttack = Props.ticksBetweenAttacks; Log.Message($"Ship Artillery initialized: {Props.ticksBetweenAttacks} ticks between attacks, {Props.attackRadius} radius"); + Log.Message($"Faction Discrimination: {Props.useFactionDiscrimination}, Target Faction: {Props.targetFaction?.defName ?? "None"}, Micro Tracking: {Props.useMicroTracking}"); } public override void CompTick() @@ -40,6 +51,12 @@ namespace WulaFallenEmpire if (parent is not FlyOver flyOver || !flyOver.Spawned || flyOver.Map == null) return; + // 更新微追踪目标列表(如果需要) + if (Props.useMicroTracking && Props.useFactionDiscrimination) + { + UpdateMicroTrackingTargets(flyOver); + } + // 更新预热状态 if (isWarmingUp) { @@ -65,6 +82,173 @@ namespace WulaFallenEmpire } } + // 新增:更新微追踪目标列表 + private void UpdateMicroTrackingTargets(FlyOver flyOver) + { + microTrackingTargets.Clear(); + microTrackingWeights.Clear(); + + Faction targetFaction = GetTargetFaction(flyOver); + if (targetFaction == null) return; + + // 获取飞越物体当前位置 + IntVec3 center = GetFlyOverPosition(flyOver); + + // 搜索范围内的所有潜在目标 + foreach (IntVec3 cell in GenRadial.RadialCellsAround(center, Props.attackRadius, true)) + { + if (!cell.InBounds(flyOver.Map)) continue; + + // 检查建筑 + Building building = cell.GetEdifice(flyOver.Map); + if (building != null && IsValidMicroTrackingTarget(building, targetFaction)) + { + microTrackingTargets.Add(new LocalTargetInfo(building)); + float weight = GetTargetWeight(building); + microTrackingWeights.Add(weight); + } + + // 检查生物 + List thingList = cell.GetThingList(flyOver.Map); + foreach (Thing thing in thingList) + { + if (thing is Pawn pawn && IsValidMicroTrackingTarget(pawn, targetFaction)) + { + microTrackingTargets.Add(new LocalTargetInfo(pawn)); + float weight = GetTargetWeight(pawn); + microTrackingWeights.Add(weight); + } + } + } + + // 移除重复目标(基于位置) + for (int i = microTrackingTargets.Count - 1; i >= 0; i--) + { + for (int j = 0; j < i; j++) + { + if (microTrackingTargets[i].Cell == microTrackingTargets[j].Cell) + { + microTrackingTargets.RemoveAt(i); + microTrackingWeights.RemoveAt(i); + break; + } + } + } + + if (DebugSettings.godMode) + { + Log.Message($"MicroTracking: Found {microTrackingTargets.Count} targets for faction {targetFaction.def.defName}"); + // 输出目标统计信息 + var targetStats = GetTargetStatistics(); + Log.Message($"Target Statistics - Pawns: {targetStats.pawnCount}, Owned Buildings: {targetStats.ownedBuildingCount}, Unowned Buildings: {targetStats.unownedBuildingCount}, Others: {targetStats.otherCount}"); + } + } + + // 新增:获取目标权重 + private float GetTargetWeight(Thing thing) + { + if (thing is Pawn) + { + return PAWN_WEIGHT; + } + else if (thing is Building building) + { + if (building.Faction == null) + { + return UNOWNED_BUILDING_WEIGHT; + } + else + { + return OWNED_BUILDING_WEIGHT; + } + } + else + { + return OTHER_WEIGHT; + } + } + + // 新增:获取目标统计信息 + private (int pawnCount, int ownedBuildingCount, int unownedBuildingCount, int otherCount) GetTargetStatistics() + { + int pawnCount = 0; + int ownedBuildingCount = 0; + int unownedBuildingCount = 0; + int otherCount = 0; + + for (int i = 0; i < microTrackingTargets.Count; i++) + { + Thing thing = microTrackingTargets[i].Thing; + if (thing == null) continue; + + if (thing is Pawn) + { + pawnCount++; + } + else if (thing is Building building) + { + if (building.Faction == null) + { + unownedBuildingCount++; + } + else + { + ownedBuildingCount++; + } + } + else + { + otherCount++; + } + } + + return (pawnCount, ownedBuildingCount, unownedBuildingCount, otherCount); + } + + // 新增:检查是否为有效的微追踪目标 + private bool IsValidMicroTrackingTarget(Thing thing, Faction targetFaction) + { + if (thing == null || thing.Destroyed) return false; + + // 检查派系关系:目标派系的友军不应该被攻击 + if (thing.Faction != null) + { + if (thing.Faction == targetFaction) return false; + if (thing.Faction.RelationKindWith(targetFaction) == FactionRelationKind.Ally) return false; + } + + // 检查是否在保护范围内 + if (Props.avoidPlayerAssets && IsNearPlayerAssets(thing.Position, thing.Map)) + { + return false; + } + + // 避免击中飞越物体本身 + if (Props.avoidHittingFlyOver && thing.Position.DistanceTo(parent.Position) < 10f) + { + return false; + } + + return true; + } + + // 新增:获取目标派系 + private Faction GetTargetFaction(FlyOver flyOver) + { + if (!Props.useFactionDiscrimination) + return null; + + // 如果指定了目标派系,使用指定的派系 + if (Props.targetFaction != null) + { + Faction faction = Find.FactionManager.FirstFactionOfDef(Props.targetFaction); + if (faction != null) return faction; + } + + // 否则使用玩家当前派系 + return Faction.OfPlayer; + } + private void StartAttack(FlyOver flyOver) { if (!CanAttack(flyOver)) @@ -195,8 +379,16 @@ namespace WulaFallenEmpire return; } - // 直接选择随机目标 - IntVec3 shellTarget = SelectRandomTarget(flyOver); + // 选择目标 + IntVec3 shellTarget; + if (Props.useMicroTracking && Props.useFactionDiscrimination && microTrackingTargets.Count > 0) + { + shellTarget = SelectMicroTrackingTarget(flyOver); + } + else + { + shellTarget = SelectRandomTarget(flyOver); + } // 关键修复:使用 SkyfallerMaker 创建并立即生成 Skyfaller SkyfallerMaker.SpawnSkyfaller(shellDef, shellTarget, flyOver.Map); @@ -216,6 +408,79 @@ namespace WulaFallenEmpire } } + // 修改:微追踪目标选择 - 现在使用权重系统 + private IntVec3 SelectMicroTrackingTarget(FlyOver flyOver) + { + if (microTrackingTargets.Count == 0) + { + Log.Warning("MicroTracking: No targets available, falling back to random target"); + return SelectRandomTarget(flyOver); + } + + // 使用权重系统选择目标 + LocalTargetInfo selectedTarget = SelectTargetByWeight(); + IntVec3 targetCell = selectedTarget.Cell; + + // 在目标周围添加随机偏移,避免过于精确 + float offsetDistance = Rand.Range(0f, 2f); + float angle = Rand.Range(0f, 360f); + + IntVec3 offsetTarget = targetCell; + offsetTarget.x += Mathf.RoundToInt(Mathf.Cos(angle * Mathf.Deg2Rad) * offsetDistance); + offsetTarget.z += Mathf.RoundToInt(Mathf.Sin(angle * Mathf.Deg2Rad) * offsetDistance); + + // 确保目标在地图内 + if (!offsetTarget.InBounds(flyOver.Map)) + { + offsetTarget = targetCell; + } + + if (DebugSettings.godMode) + { + Thing selectedThing = selectedTarget.Thing; + string targetType = selectedThing is Pawn ? "Pawn" : + selectedThing is Building building ? + (building.Faction == null ? "Unowned Building" : "Owned Building") : "Other"; + + Log.Message($"MicroTracking: Targeting {selectedThing?.Label ?? "unknown"} ({targetType}) at {targetCell}, final target: {offsetTarget}"); + } + + return offsetTarget; + } + + // 新增:基于权重的目标选择 + private LocalTargetInfo SelectTargetByWeight() + { + if (microTrackingTargets.Count == 0) + return LocalTargetInfo.Invalid; + + if (microTrackingTargets.Count == 1) + return microTrackingTargets[0]; + + // 计算总权重 + float totalWeight = 0f; + foreach (float weight in microTrackingWeights) + { + totalWeight += weight; + } + + // 随机选择 + float randomValue = Rand.Range(0f, totalWeight); + float currentSum = 0f; + + for (int i = 0; i < microTrackingTargets.Count; i++) + { + currentSum += microTrackingWeights[i]; + if (randomValue <= currentSum) + { + return microTrackingTargets[i]; + } + } + + // 回退到最后一个目标 + return microTrackingTargets[microTrackingTargets.Count - 1]; + } + private ThingDef SelectShellDef() { if (Props.skyfallerDefs != null && Props.skyfallerDefs.Count > 0) @@ -352,6 +617,45 @@ namespace WulaFallenEmpire if (!Props.avoidPlayerAssets) return false; + // 如果启用了派系甄别,检查目标派系 + if (Props.useFactionDiscrimination) + { + Faction targetFaction = GetTargetFaction(parent as FlyOver); + if (targetFaction != null) + { + foreach (IntVec3 checkCell in GenRadial.RadialCellsAround(cell, Props.playerAssetAvoidanceRadius, true)) + { + if (!checkCell.InBounds(map)) + continue; + + // 检查目标派系建筑 + var building = checkCell.GetEdifice(map); + if (building != null && building.Faction == targetFaction) + return true; + + // 检查目标派系殖民者 + var pawn = map.thingGrid.ThingAt(checkCell); + if (pawn != null && pawn.Faction == targetFaction && pawn.RaceProps.Humanlike) + return true; + + // 检查目标派系动物 + var animal = map.thingGrid.ThingAt(checkCell); + if (animal != null && animal.Faction == targetFaction && animal.RaceProps.Animal) + return true; + + // 检查目标派系物品 + var items = checkCell.GetThingList(map); + foreach (var item in items) + { + if (item.Faction == targetFaction && item.def.category == ThingCategory.Item) + return true; + } + } + return false; + } + } + + // 默认行为:检查玩家资产 foreach (IntVec3 checkCell in GenRadial.RadialCellsAround(cell, Props.playerAssetAvoidanceRadius, true)) { if (!checkCell.InBounds(map)) @@ -470,6 +774,8 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref isWarmingUp, "isWarmingUp", false); Scribe_Values.Look(ref currentTarget, "currentTarget"); Scribe_Collections.Look(ref previousTargets, "previousTargets", LookMode.Value); + Scribe_Collections.Look(ref microTrackingTargets, "microTrackingTargets", LookMode.LocalTargetInfo); + Scribe_Collections.Look(ref microTrackingWeights, "microTrackingWeights", LookMode.Value); } public override IEnumerable CompGetGizmosExtra() @@ -504,9 +810,44 @@ namespace WulaFallenEmpire IntVec3 flyOverPos = GetFlyOverPosition(flyOver); Log.Message($"FlyOver - DrawPos: {flyOver.DrawPos}, Position: {flyOver.Position}, Calculated: {flyOverPos}"); Log.Message($"Current Target: {currentTarget}, Distance: {flyOverPos.DistanceTo(currentTarget):F1}"); + + // 显示派系甄别信息 + Faction targetFaction = GetTargetFaction(flyOver); + Log.Message($"Faction Discrimination: {Props.useFactionDiscrimination}, Target Faction: {targetFaction?.def.defName ?? "None"}"); + Log.Message($"Micro Tracking: {Props.useMicroTracking}, Targets Found: {microTrackingTargets.Count}"); + + // 显示目标统计 + var stats = GetTargetStatistics(); + Log.Message($"Target Stats - Pawns: {stats.pawnCount}, Owned Buildings: {stats.ownedBuildingCount}, Unowned Buildings: {stats.unownedBuildingCount}, Others: {stats.otherCount}"); } } }; + + // 显示微追踪目标信息 + if (Props.useMicroTracking && Props.useFactionDiscrimination) + { + yield return new Command_Action + { + defaultLabel = $"Dev: Show Micro Targets ({microTrackingTargets.Count})", + action = () => + { + if (parent is FlyOver flyOver) + { + for (int i = 0; i < microTrackingTargets.Count; i++) + { + var target = microTrackingTargets[i]; + float weight = microTrackingWeights[i]; + Thing thing = target.Thing; + string type = thing is Pawn ? "Pawn" : + thing is Building building ? + (building.Faction == null ? "Unowned Building" : "Owned Building") : "Other"; + + Log.Message($"Micro Target: {thing?.Label ?? "Unknown"} ({type}) at {target.Cell}, Weight: {weight:F2}"); + } + } + } + }; + } } } diff --git a/Source/WulaFallenEmpire/Storyteller/StorytellerCompProperties_ImportantQuestWithFactionFilter.cs b/Source/WulaFallenEmpire/Storyteller/StorytellerCompProperties_ImportantQuestWithFactionFilter.cs new file mode 100644 index 00000000..8617a331 --- /dev/null +++ b/Source/WulaFallenEmpire/Storyteller/StorytellerCompProperties_ImportantQuestWithFactionFilter.cs @@ -0,0 +1,33 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; + +namespace WulaFallenEmpire +{ + public class StorytellerCompProperties_ImportantQuestWithFactionFilter : StorytellerCompProperties_ImportantQuest + { + // 派系类型白名单 - 只有这些派系类型的殖民地会触发任务 + public List factionTypeWhitelist; + + // 派系类型黑名单 - 这些派系类型的殖民地不会触发任务 + public List factionTypeBlacklist; + + // 是否启用派系过滤 + public bool useFactionFilter = false; + + // 默认行为(当派系不在白名单中时的处理方式) + public FactionFilterDefaultBehavior defaultBehavior = FactionFilterDefaultBehavior.Allow; + + public StorytellerCompProperties_ImportantQuestWithFactionFilter() + { + compClass = typeof(StorytellerComp_ImportantQuestWithFactionFilter); + } + } + + // 派系过滤的默认行为枚举 + public enum FactionFilterDefaultBehavior + { + Allow, // 允许不在列表中的派系 + Deny // 拒绝不在列表中的派系 + } +} diff --git a/Source/WulaFallenEmpire/Storyteller/StorytellerComp_ImportantQuestWithFactionFilter.cs b/Source/WulaFallenEmpire/Storyteller/StorytellerComp_ImportantQuestWithFactionFilter.cs new file mode 100644 index 00000000..001a29aa --- /dev/null +++ b/Source/WulaFallenEmpire/Storyteller/StorytellerComp_ImportantQuestWithFactionFilter.cs @@ -0,0 +1,175 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; +using System.Text; +using System.Linq; +using RimWorld.Planet; + +namespace WulaFallenEmpire +{ + public class StorytellerComp_ImportantQuestWithFactionFilter : StorytellerComp + { + private StorytellerCompProperties_ImportantQuestWithFactionFilter FilterProps => + (StorytellerCompProperties_ImportantQuestWithFactionFilter)props; + + // 重新实现基类的私有属性 + private static int IntervalsPassed => Find.TickManager.TicksGame / 1000; + + private bool BeenGivenQuest => Find.QuestManager.QuestsListForReading.Any((Quest q) => q.root == FilterProps.questDef); + + public override IEnumerable MakeIntervalIncidents(IIncidentTarget target) + { + // 先检查基础条件(天数、是否已给任务等) + if (IntervalsPassed <= FilterProps.fireAfterDaysPassed * 60 || BeenGivenQuest) + yield break; + + // 检查派系过滤条件 + if (!PassesFactionFilter(target)) + yield break; + + IncidentDef questIncident = FilterProps.questIncident; + if (questIncident.TargetAllowed(target)) + { + yield return new FiringIncident(questIncident, this, GenerateParms(questIncident.category, target)); + } + } + + /// + /// 检查目标是否符合派系过滤条件 + /// + private bool PassesFactionFilter(IIncidentTarget target) + { + // 如果不启用派系过滤,直接通过 + if (!FilterProps.useFactionFilter) + return true; + + // 获取目标的派系 + Faction faction = GetTargetFaction(target); + if (faction == null) + return false; + + // 检查黑名单 + if (FilterProps.factionTypeBlacklist != null && + FilterProps.factionTypeBlacklist.Contains(faction.def)) + { + Log.Message($"[FactionFilter] Quest blocked: {faction.def.defName} is in blacklist"); + return false; + } + + // 检查白名单 + if (FilterProps.factionTypeWhitelist != null && + FilterProps.factionTypeWhitelist.Count > 0) + { + bool inWhitelist = FilterProps.factionTypeWhitelist.Contains(faction.def); + + switch (FilterProps.defaultBehavior) + { + case FactionFilterDefaultBehavior.Allow: + // 白名单模式:在白名单中或默认允许 + if (!inWhitelist) + { + Log.Message($"[FactionFilter] Quest allowed: {faction.def.defName} not in whitelist, but default behavior is Allow"); + } + return true; + + case FactionFilterDefaultBehavior.Deny: + // 白名单模式:只有在白名单中才允许 + if (inWhitelist) + { + Log.Message($"[FactionFilter] Quest allowed: {faction.def.defName} is in whitelist"); + return true; + } + else + { + Log.Message($"[FactionFilter] Quest blocked: {faction.def.defName} not in whitelist and default behavior is Deny"); + return false; + } + } + } + + // 如果没有设置白名单,根据默认行为决定 + switch (FilterProps.defaultBehavior) + { + case FactionFilterDefaultBehavior.Allow: + Log.Message($"[FactionFilter] Quest allowed: No whitelist, default behavior is Allow"); + return true; + case FactionFilterDefaultBehavior.Deny: + Log.Message($"[FactionFilter] Quest blocked: No whitelist, default behavior is Deny"); + return false; + default: + return true; + } + } + + /// + /// 获取目标的派系 + /// + private Faction GetTargetFaction(IIncidentTarget target) + { + if (target is Map map) + { + return map.ParentFaction ?? Faction.OfPlayer; + } + else if (target is World world) + { + return Faction.OfPlayer; + } + else if (target is Caravan caravan) + { + return caravan.Faction; + } + + return Faction.OfPlayer; + } + + /// + /// 调试方法:显示当前过滤状态 + /// + public string GetFactionFilterStatus(IIncidentTarget target) + { + if (!FilterProps.useFactionFilter) + return "Faction filter: DISABLED"; + + Faction faction = GetTargetFaction(target); + if (faction == null) + return "Faction filter: NO FACTION"; + + StringBuilder status = new StringBuilder(); + status.AppendLine($"Faction filter: {faction.def.defName}"); + + // 黑名单检查 + if (FilterProps.factionTypeBlacklist != null && + FilterProps.factionTypeBlacklist.Contains(faction.def)) + { + status.AppendLine("❌ BLACKLISTED"); + return status.ToString(); + } + + // 白名单检查 + if (FilterProps.factionTypeWhitelist != null && + FilterProps.factionTypeWhitelist.Count > 0) + { + bool inWhitelist = FilterProps.factionTypeWhitelist.Contains(faction.def); + + if (inWhitelist) + { + status.AppendLine("✅ WHITELISTED"); + } + else + { + status.AppendLine(FilterProps.defaultBehavior == FactionFilterDefaultBehavior.Allow ? + "⚠️ NOT IN WHITELIST (Allowed by default)" : + "❌ NOT IN WHITELIST (Denied by default)"); + } + } + else + { + status.AppendLine(FilterProps.defaultBehavior == FactionFilterDefaultBehavior.Allow ? + "✅ NO WHITELIST (Allowed by default)" : + "❌ NO WHITELIST (Denied by default)"); + } + + return status.ToString(); + } + } +} diff --git a/Source/WulaFallenEmpire/Storyteller/StorytellerComp_SingleOnceFixed_FactionFilter.cs b/Source/WulaFallenEmpire/Storyteller/StorytellerComp_SingleOnceFixed_FactionFilter.cs deleted file mode 100644 index 685fe4d9..00000000 --- a/Source/WulaFallenEmpire/Storyteller/StorytellerComp_SingleOnceFixed_FactionFilter.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Collections.Generic; -using RimWorld; -using Verse; - -namespace WulaFallenEmpire -{ - public class StorytellerComp_SingleOnceFixed_FactionFilter : StorytellerComp_SingleOnceFixed - { - private StorytellerCompProperties_SingleOnceFixed_FactionFilter PropsFilter => (StorytellerCompProperties_SingleOnceFixed_FactionFilter)props; - - public override IEnumerable MakeIntervalIncidents(IIncidentTarget target) - { - // 检查派系过滤条件 - if (!CheckFactionFilter()) - { - yield break; - } - - // 调用父类的逻辑 - foreach (var incident in base.MakeIntervalIncidents(target)) - { - yield return incident; - } - } - - private bool CheckFactionFilter() - { - if (Faction.OfPlayer == null) - return false; - - var playerFactionDef = Faction.OfPlayer.def; - - // 优先检查白名单:如果白名单有内容,只有白名单内的派系才能触发 - if (PropsFilter.allowedFactionTypes != null && PropsFilter.allowedFactionTypes.Count > 0) - { - return PropsFilter.allowedFactionTypes.Contains(playerFactionDef); - } - - // 然后检查黑名单:如果黑名单有内容,黑名单内的派系不能触发 - if (PropsFilter.excludedFactionTypes != null && PropsFilter.excludedFactionTypes.Count > 0) - { - return !PropsFilter.excludedFactionTypes.Contains(playerFactionDef); - } - - // 如果既没有白名单也没有黑名单,所有派系都能触发 - return true; - } - } - - public class StorytellerCompProperties_SingleOnceFixed_FactionFilter : StorytellerCompProperties_SingleOnceFixed - { - // 黑名单:这些派系类型不会触发事件 - public List excludedFactionTypes; - - // 白名单:只有这些派系类型会触发事件(优先级高于黑名单) - public List allowedFactionTypes; - - public StorytellerCompProperties_SingleOnceFixed_FactionFilter() - { - compClass = typeof(StorytellerComp_SingleOnceFixed_FactionFilter); - } - } -} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 149827e0..37906a23 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -208,7 +208,8 @@ - + +