126 lines
4.7 KiB
C#
126 lines
4.7 KiB
C#
using RimWorld;
|
||
using Verse;
|
||
using Verse.AI;
|
||
using UnityEngine;
|
||
|
||
namespace ArachnaeSwarm
|
||
{
|
||
public class JobGiver_AIFollowProducer : JobGiver_AIFollowPawn
|
||
{
|
||
public const float DefaultFollowRadius = 3f;
|
||
public const float ExtendedFollowRadius = 10f;
|
||
|
||
protected override int FollowJobExpireInterval => 200;
|
||
|
||
protected override Pawn GetFollowee(Pawn pawn)
|
||
{
|
||
// 获取生产者Comp
|
||
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
|
||
if (producerComp == null || !producerComp.HasValidProducer)
|
||
return null;
|
||
|
||
Thing producer = producerComp.Producer;
|
||
|
||
// 如果生产者是Pawn,返回它(但需要检查征召状态)
|
||
if (producer is Pawn pawnProducer)
|
||
{
|
||
// 只在生产者被征召时才返回
|
||
return pawnProducer.Drafted ? pawnProducer : null;
|
||
}
|
||
|
||
// 对于非Pawn生产者,返回null,我们将使用自定义逻辑
|
||
return null;
|
||
}
|
||
|
||
protected override float GetRadius(Pawn pawn)
|
||
{
|
||
// 如果有特殊需求,可以调整跟随半径
|
||
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
|
||
if (producerComp == null || !producerComp.HasValidProducer)
|
||
return DefaultFollowRadius;
|
||
|
||
// 如果生产者是建筑,可能需要更大的跟随半径
|
||
if (producerComp.Producer is Building)
|
||
return ExtendedFollowRadius;
|
||
|
||
return DefaultFollowRadius;
|
||
}
|
||
|
||
// 重写以支持非Pawn生产者
|
||
protected override Job TryGiveJob(Pawn pawn)
|
||
{
|
||
CompProducedByMechCarrier producerComp = pawn.TryGetComp<CompProducedByMechCarrier>();
|
||
if (producerComp == null || !producerComp.HasValidProducer)
|
||
return null;
|
||
|
||
Thing producer = producerComp.Producer;
|
||
|
||
// 如果生产者是Pawn,检查征召状态
|
||
if (producer is Pawn pawnProducer)
|
||
{
|
||
// 只在生产者被征召时才跟随
|
||
if (!pawnProducer.Drafted)
|
||
return null;
|
||
|
||
// 使用基类逻辑
|
||
return base.TryGiveJob(pawn);
|
||
}
|
||
|
||
// 对于非Pawn生产者,创建自定义跟随逻辑
|
||
return CreateFollowNonPawnJob(pawn, producer);
|
||
}
|
||
|
||
private Job CreateFollowNonPawnJob(Pawn pawn, Thing producer)
|
||
{
|
||
if (producer == null || producer.Destroyed)
|
||
return null;
|
||
|
||
// 检查是否已经在跟随半径内
|
||
float radius = GetRadius(pawn);
|
||
if (pawn.Position.DistanceTo(producer.Position) <= radius)
|
||
{
|
||
// 已经在范围内,不需要移动
|
||
return null;
|
||
}
|
||
|
||
// 创建移动到生产者附近的工作
|
||
IntVec3 targetCell = GetFollowTargetCell(pawn, producer, radius);
|
||
|
||
if (!targetCell.IsValid || !pawn.CanReach(targetCell, PathEndMode.OnCell, Danger.Deadly))
|
||
return null;
|
||
|
||
Job job = JobMaker.MakeJob(JobDefOf.Goto, targetCell);
|
||
job.expiryInterval = FollowJobExpireInterval;
|
||
job.checkOverrideOnExpire = true;
|
||
return job;
|
||
}
|
||
|
||
private IntVec3 GetFollowTargetCell(Pawn pawn, Thing producer, float radius)
|
||
{
|
||
// 获取生产者位置附近的随机单元格
|
||
IntVec3 producerPos = producer.Position;
|
||
|
||
// 在半径范围内寻找可到达的单元格
|
||
for (int i = 0; i < 20; i++)
|
||
{
|
||
// 修复:正确生成偏移量
|
||
Vector2 randomOffset = Random.insideUnitCircle * (radius * 0.5f);
|
||
IntVec3 candidate = producerPos + new IntVec3(Mathf.RoundToInt(randomOffset.x), 0, Mathf.RoundToInt(randomOffset.y));
|
||
|
||
if (candidate.InBounds(pawn.Map) &&
|
||
candidate.Walkable(pawn.Map) &&
|
||
pawn.CanReach(candidate, PathEndMode.OnCell, Danger.Deadly))
|
||
{
|
||
return candidate;
|
||
}
|
||
}
|
||
|
||
// 如果找不到合适的单元格,返回生产者的交互单元格
|
||
if (producer is Building building)
|
||
return building.InteractionCell;
|
||
|
||
return producerPos;
|
||
}
|
||
}
|
||
}
|