This commit is contained in:
Tourswen
2025-12-16 23:54:36 +08:00
parent 18fd9ec2d9
commit 3706bdb241
37 changed files with 3212 additions and 407 deletions

View File

@@ -0,0 +1,281 @@
using System;
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class Verb_ShootSelfUnderfoot : Verb_LaunchProjectile
{
// 重写ShotsPerBurst与Verb_Shoot相同
protected override int ShotsPerBurst => base.BurstShotCount;
// 重写WarmupComplete添加射击技能学习
public override void WarmupComplete()
{
base.WarmupComplete();
// 只有在目标是Pawn时才学习射击技能
if (currentTarget.Thing is Pawn targetPawn &&
!targetPawn.Downed &&
!targetPawn.IsColonyMech &&
CasterIsPawn &&
CasterPawn.skills != null)
{
float xp = targetPawn.HostileTo(caster) ? 170f : 20f;
float num2 = verbProps.AdjustedFullCycleTime(this, CasterPawn);
CasterPawn.skills.Learn(SkillDefOf.Shooting, xp * num2);
}
}
// 核心重写:将目标改为脚下
protected override bool TryCastShot()
{
// 保存原始目标
LocalTargetInfo originalTarget = currentTarget;
try
{
// 将目标改为施法者自己的位置
currentTarget = new LocalTargetInfo(caster.Position);
// 调用基类方法,但使用修改后的目标(脚下)
bool result = base.TryCastShot();
// 如果成功发射,记录射击次数
if (result && CasterIsPawn)
{
CasterPawn.records.Increment(RecordDefOf.ShotsFired);
}
return result;
}
finally
{
// 恢复原始目标(对于连续射击可能重要)
currentTarget = originalTarget;
}
}
// 重写CanHitTarget因为目标是脚下总是可以命中
public override bool CanHitTarget(LocalTargetInfo targ)
{
// 对于向脚下射击,我们总是允许(只要施法者存在)
if (caster == null || !caster.Spawned)
return false;
// 如果目标就是施法者自己,允许
if (targ == caster)
return true;
// 对于其他目标,使用默认逻辑
return base.CanHitTarget(targ);
}
// 重写CanHitTargetFrom对于脚下射击总是返回true
public override bool CanHitTargetFrom(IntVec3 root, LocalTargetInfo targ)
{
// 如果目标是施法者自己(或脚下),总是可以命中
if (targ.Thing == caster || (targ.IsValid && targ.Cell == caster.Position))
return true;
return base.CanHitTargetFrom(root, targ);
}
// 重写TryFindShootLineFromTo对于脚下射击简化逻辑
public new bool TryFindShootLineFromTo(IntVec3 root, LocalTargetInfo targ, out ShootLine resultingLine, bool ignoreRange = false)
{
// 如果目标是脚下,直接返回射击线
if (targ.IsValid && targ.Cell == caster.Position)
{
resultingLine = new ShootLine(root, targ.Cell);
return true;
}
// 否则使用基类逻辑
return base.TryFindShootLineFromTo(root, targ, out resultingLine, ignoreRange);
}
// 重写DrawHighlight简化高亮显示
public override void DrawHighlight(LocalTargetInfo target)
{
// 绘制标准射程环
verbProps.DrawRadiusRing(caster.Position, this);
// 如果目标是有效的,绘制目标高亮
if (target.IsValid)
{
GenDraw.DrawTargetHighlight(target);
// 绘制目标周围的场半径
DrawHighlightFieldRadiusAroundTarget(target);
}
}
// 辅助方法:绘制彩色目标高亮
private void GenDraw_DrawTargetHighlightWithColor(LocalTargetInfo target, Color color)
{
GenDraw.DrawTargetHighlight(target);
}
// 重写OnGUI显示自定义鼠标图标
public override void OnGUI(LocalTargetInfo target)
{
// 使用自定义图标或默认攻击图标
Texture2D icon;
if (!target.IsValid)
{
icon = TexCommand.CannotShoot;
}
else if (target.Cell == caster.Position)
{
// 可以使用自定义图标,这里使用攻击图标
icon = TexCommand.Attack;
}
else
{
icon = (UIIcon != BaseContent.BadTex) ? UIIcon : TexCommand.Attack;
}
GenUI.DrawMouseAttachment(icon);
}
// 重写ValidateTarget允许向自己脚下射击
public override bool ValidateTarget(LocalTargetInfo target, bool showMessages = true)
{
// 如果目标是脚下,总是允许
if (target.IsValid && target.Cell == caster.Position)
return true;
// 否则使用基类验证逻辑
return base.ValidateTarget(target, showMessages);
}
// 重写Available确保有抛射体并允许在近战状态下使用
public override bool Available()
{
// 首先调用基类检查
if (!base.Available())
return false;
// 检查是否有抛射体
if (Projectile == null)
return false;
// 特殊处理:允许在近战威胁下使用
if (CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
{
return true;
}
return true;
}
// 重写OrderForceTarget允许在近战距离内强制使用
public override void OrderForceTarget(LocalTargetInfo target)
{
// 如果是近战攻击,使用近战逻辑
if (verbProps.IsMeleeAttack)
{
Job job = JobMaker.MakeJob(JobDefOf.AttackMelee, target);
job.playerForced = true;
if (target.Thing is Pawn pawn)
{
job.killIncappedTarget = pawn.Downed;
}
CasterPawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
return;
}
// 检查是否在近战范围内,但允许向脚下射击
float minRange = verbProps.EffectiveMinRange(target, CasterPawn);
if (CasterIsPawn &&
(float)CasterPawn.Position.DistanceToSquared(target.Cell) < minRange * minRange &&
CasterPawn.Position.AdjacentTo8WayOrInside(target.Cell))
{
// 如果是向脚下射击,允许
if (target.IsValid && target.Cell == CasterPawn.Position)
{
// 允许向脚下射击
}
else
{
Messages.Message("MessageCantShootInMelee".Translate(), CasterPawn, MessageTypeDefOf.RejectInput, historical: false);
return;
}
}
// 创建射击工作
Job job2 = JobMaker.MakeJob(verbProps.ai_IsWeapon ? JobDefOf.AttackStatic : JobDefOf.UseVerbOnThing);
job2.verbToUse = this;
job2.targetA = target;
job2.endIfCantShootInMelee = false; // 设置为false允许在近战中射击
CasterPawn.jobs.TryTakeOrderedJob(job2, JobTag.Misc);
}
// 重写TryStartCastOn允许在近战状态下开始射击
public override bool TryStartCastOn(LocalTargetInfo castTarg, LocalTargetInfo destTarg, bool surpriseAttack = false, bool canHitNonTargetPawns = true, bool preventFriendlyFire = false, bool nonInterruptingSelfCast = false)
{
// 调用基类方法,但设置一个标志表示这是向脚下射击
bool isShootingUnderfoot = castTarg.IsValid && castTarg.Cell == caster.Position;
// 如果是向脚下射击,临时修改一些属性以允许近战射击
if (isShootingUnderfoot && CasterIsPawn && CasterPawn.mindState != null && CasterPawn.mindState.MeleeThreatStillThreat)
{
// 临时忽略近战威胁检查
bool originalAIProjectileLaunchingIgnoresMeleeThreats = verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats;
verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = true;
try
{
return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
}
finally
{
// 恢复原始值
verbProps.ai_ProjectileLaunchingIgnoresMeleeThreats = originalAIProjectileLaunchingIgnoresMeleeThreats;
}
}
return base.TryStartCastOn(castTarg, destTarg, surpriseAttack, canHitNonTargetPawns, preventFriendlyFire, nonInterruptingSelfCast);
}
// 添加一个方法,检查是否在近战状态下
public bool IsInMeleeCombat()
{
if (!CasterIsPawn)
return false;
return CasterPawn.mindState?.MeleeThreatStillThreat == true;
}
// 重写BurstingTick在近战状态下也继续射击
public override void BurstingTick()
{
base.BurstingTick();
// 在近战状态下也继续射击逻辑
if (IsInMeleeCombat() && state == VerbState.Bursting)
{
// 可以在这里添加近战状态下的特殊效果
}
}
// 添加自定义属性,用于控制是否总是向脚下发射
private bool alwaysShootUnderfoot = true;
public bool AlwaysShootUnderfoot
{
get => alwaysShootUnderfoot;
set => alwaysShootUnderfoot = value;
}
// 添加一个方法,允许临时关闭向脚下射击
public void SetShootUnderfoot(bool shootUnderfoot)
{
alwaysShootUnderfoot = shootUnderfoot;
}
}
}