This commit is contained in:
2025-12-18 17:30:36 +08:00
parent 6a938abcb7
commit ad42832aa7
14 changed files with 1809 additions and 586 deletions

View File

@@ -0,0 +1,106 @@
// File: CompPawnBodyWeapon.cs
using RimWorld;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_PawnBodyWeapon : CompProperties
{
// 基础伤害设置
public float cleaveAngle = 90f;
public float cleaveRange = 2.5f;
public float cleaveDamageFactor = 0.7f;
public bool damageDowned = false;
public DamageDef cleaveDamageDef = null;
// 攻击效果
public EffecterDef attackEffecter = null;
public EffecterDef cleaveEffecter = null;
public SoundDef attackSound = null;
// 特殊效果
public HediffDef applyHediffOnHit = null; // 命中时附加的效果
public float hediffSeverity = 0.1f;
public float hediffChance = 1.0f;
// 条件触发
public bool requiresMeleeSkill = false; // 是否需要近战技能
public int minMeleeSkillLevel = 0;
public bool onlyWhenDrafted = false; // 是否只在征召时生效
public CompProperties_PawnBodyWeapon()
{
this.compClass = typeof(CompPawnBodyWeapon);
}
}
public class CompPawnBodyWeapon : ThingComp
{
public CompProperties_PawnBodyWeapon Props => (CompProperties_PawnBodyWeapon)this.props;
private Pawn Pawn => this.parent as Pawn;
// 检查是否可以使用身体武器
public bool CanUseBodyWeapon(Verb verb = null)
{
if (Pawn == null || Pawn.Dead || Pawn.Downed)
return false;
// 检查是否被征召
if (Props.onlyWhenDrafted && !Pawn.Drafted)
return false;
// 检查近战技能
if (Props.requiresMeleeSkill && Pawn.skills != null)
{
var meleeSkill = Pawn.skills.GetSkill(SkillDefOf.Melee);
if (meleeSkill.Level < Props.minMeleeSkillLevel)
return false;
}
return true;
}
// 获取实际伤害系数(可以基于技能、状态等调整)
public float GetDamageFactor(Verb verb = null)
{
float factor = Props.cleaveDamageFactor;
// 如果有近战技能加成
if (Pawn.skills != null)
{
var meleeSkill = Pawn.skills.GetSkill(SkillDefOf.Melee);
factor *= (1.0f + (meleeSkill.Level * 0.02f)); // 每级增加2%伤害
}
// 检查是否有增强状态
if (Pawn.health?.hediffSet != null)
{
// 这里可以添加基于hediff的伤害加成
// 例如:狂暴状态增加伤害
}
return factor;
}
// 获取攻击范围
public float GetCleaveRange(Verb verb = null)
{
float range = Props.cleaveRange;
// 基于体型调整范围
if (Pawn.BodySize > 1.0f)
{
range *= Pawn.BodySize * 0.5f;
}
return range;
}
// 获取攻击角度
public float GetCleaveAngle(Verb verb = null)
{
return Props.cleaveAngle;
}
}
}

View File

@@ -0,0 +1,226 @@
// File: Verb_MeleeAttack_BodyWeapon.cs
using RimWorld;
using Verse;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace ArachnaeSwarm
{
public class Verb_MeleeAttack_BodyWeapon : Verb_MeleeAttack
{
private CompPawnBodyWeapon Comp
{
get
{
return this.CasterPawn?.GetComp<CompPawnBodyWeapon>();
}
}
protected override DamageWorker.DamageResult ApplyMeleeDamageToTarget(LocalTargetInfo target)
{
DamageWorker.DamageResult result = new DamageWorker.DamageResult();
// 播放攻击特效
PlayAttackEffecter(target);
// 1. 对主目标造成伤害
DamageInfo dinfo = new DamageInfo(
this.verbProps.meleeDamageDef,
this.verbProps.AdjustedMeleeDamageAmount(this, this.CasterPawn),
this.verbProps.AdjustedArmorPenetration(this, this.CasterPawn),
-1f,
this.CasterPawn,
null,
null // 身体武器没有装备
);
dinfo.SetTool(this.tool);
if (target.HasThing)
{
result = target.Thing.TakeDamage(dinfo);
// 附加特殊效果
ApplySpecialEffects(target.Thing);
}
// 2. 执行溅射伤害
Pawn casterPawn = this.CasterPawn;
if (casterPawn == null || !target.HasThing)
{
return result;
}
Thing mainTarget = target.Thing;
Vector3 attackDirection = (mainTarget.Position - casterPawn.Position).ToVector3().normalized;
bool mainTargetIsHostile = mainTarget.HostileTo(casterPawn);
// 获取溅射参数
float cleaveRange = this.Comp.GetCleaveRange(this);
float cleaveAngle = this.Comp.GetCleaveAngle(this);
float damageFactor = this.Comp.GetDamageFactor(this);
// 查找施法者周围的潜在目标
IEnumerable<Thing> potentialTargets = GenRadial.RadialDistinctThingsAround(
casterPawn.Position,
casterPawn.Map,
cleaveRange,
useCenter: true
);
foreach (Thing thing in potentialTargets)
{
// 跳过主目标、自己和非生物
if (thing == mainTarget || thing == casterPawn || !(thing is Pawn secondaryTargetPawn))
{
continue;
}
// 根据XML配置决定是否跳过倒地的生物
if (!this.Comp.Props.damageDowned && secondaryTargetPawn.Downed)
{
continue;
}
// 智能溅射:次要目标的敌对状态必须与主目标一致
if (secondaryTargetPawn.HostileTo(casterPawn) != mainTargetIsHostile)
{
continue;
}
// 检查目标是否在攻击扇形范围内
Vector3 directionToTarget = (thing.Position - casterPawn.Position).ToVector3().normalized;
float angle = Vector3.Angle(attackDirection, directionToTarget);
if (angle <= cleaveAngle / 2f)
{
// 对次要目标造成伤害
DamageInfo cleaveDinfo = new DamageInfo(
this.verbProps.meleeDamageDef,
this.verbProps.AdjustedMeleeDamageAmount(this, casterPawn) * damageFactor,
this.verbProps.AdjustedArmorPenetration(this, casterPawn) * damageFactor,
-1f,
casterPawn,
null,
null // 身体武器没有装备
);
cleaveDinfo.SetTool(this.tool);
secondaryTargetPawn.TakeDamage(cleaveDinfo);
// 附加特殊效果
ApplySpecialEffects(secondaryTargetPawn);
}
}
return result;
}
/// <summary>
/// 播放攻击特效
/// </summary>
private void PlayAttackEffecter(LocalTargetInfo target)
{
if (this.CasterPawn == null || this.CasterPawn.Map == null || this.Comp == null)
return;
// 播放攻击特效
if (this.Comp.Props.attackEffecter != null)
{
Effecter attackEffect = this.Comp.Props.attackEffecter.Spawn();
attackEffect.Trigger(new TargetInfo(this.CasterPawn.Position, this.CasterPawn.Map), target.ToTargetInfo(this.CasterPawn.Map));
attackEffect.Cleanup();
}
// 播放溅射特效
if (this.Comp.Props.cleaveEffecter != null && target.HasThing)
{
PlayCleaveEffecter(target.Thing);
}
}
/// <summary>
/// 播放溅射特效
/// </summary>
private void PlayCleaveEffecter(Thing mainTarget)
{
if (this.CasterPawn == null || this.CasterPawn.Map == null || mainTarget == null || this.Comp == null)
return;
Pawn casterPawn = this.CasterPawn;
// 播放主要的溅射特效
Effecter cleaveEffect = this.Comp.Props.cleaveEffecter.Spawn();
cleaveEffect.Trigger(new TargetInfo(casterPawn.Position, casterPawn.Map), new TargetInfo(mainTarget.Position, casterPawn.Map));
cleaveEffect.Cleanup();
}
/// <summary>
/// 附加特殊效果
/// </summary>
private void ApplySpecialEffects(Thing target)
{
if (this.Comp == null || this.Comp.Props.applyHediffOnHit == null)
return;
if (target is Pawn targetPawn)
{
if (Rand.Chance(this.Comp.Props.hediffChance))
{
Hediff hediff = HediffMaker.MakeHediff(this.Comp.Props.applyHediffOnHit, targetPawn);
hediff.Severity = this.Comp.Props.hediffSeverity;
targetPawn.health.AddHediff(hediff);
}
}
}
public override void DrawHighlight(LocalTargetInfo target)
{
base.DrawHighlight(target);
if (target.IsValid && CasterPawn != null && this.Comp != null && this.Comp.CanUseBodyWeapon(this))
{
GenDraw.DrawFieldEdges(GetCleaveCells(target.Cell));
}
}
private List<IntVec3> GetCleaveCells(IntVec3 center)
{
if (this.Comp == null || !this.Comp.CanUseBodyWeapon(this))
{
return new List<IntVec3>();
}
IntVec3 casterPos = this.CasterPawn.Position;
Map map = this.CasterPawn.Map;
Vector3 attackDirection = (center - casterPos).ToVector3().normalized;
float cleaveRange = this.Comp.GetCleaveRange(this);
float cleaveAngle = this.Comp.GetCleaveAngle(this);
return GenRadial.RadialCellsAround(casterPos, cleaveRange, useCenter: true)
.Where(cell => {
if (!cell.InBounds(map)) return false;
Vector3 directionToCell = (cell - casterPos).ToVector3();
if (directionToCell.sqrMagnitude <= 0.001f) return false; // 排除施法者自身位置
return Vector3.Angle(attackDirection, directionToCell) <= cleaveAngle / 2f;
}).ToList();
}
// 重写此方法以在攻击前检查身体武器状态
protected override bool TryCastShot()
{
if (this.Comp != null && !this.Comp.CanUseBodyWeapon(this))
{
// 不能使用身体武器,使用普通攻击
if (this.CasterPawn != null)
{
// 播放效果(可选)
Messages.Message("ARA_BodyWeapon_CannotUse".Translate(this.CasterPawn.LabelShortCap),
MessageTypeDefOf.NeutralEvent);
}
return base.TryCastShot();
}
return base.TryCastShot();
}
}
}