11
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user