游戏版本 756039
首页 › 游戏机制 › 战斗

战斗 Combat

机制战斗攻击护甲仇恨 又名 战斗系统又名 战斗机制

战斗由攻击者的战斗组件、目标的生命组件,以及状态图和移动组件共同完成。一次攻击会依次经过命中距离检查、伤害计算、护甲吸收与抗性、无敌判定,最后扣除生命值;追击行为则通过仇恨目标和移动到攻击范围来实现。

概述

《饥荒联机版》的战斗不是单一数值判定,而是一条由多个组件组成的处理链:

  1. 攻击者通过 combat:CanAttack 检查目标是否合法、是否在冷却、是否允许攻击以及是否处于攻击距离内。
  2. 状态图收到 doattack 事件后,在攻击动作的合适时机调用 combat:DoAttack。
  3. DoAttack 再检查实际命中距离;近战直接把伤害交给目标,远程武器则发射投射物。
  4. 目标的 combat:GetAttacked 先处理闪避、护甲、鞍具、伤害类型抗性和外部减伤,之后调用 health:DoDelta 扣除生命值。

因此,“攻击力”与“实际掉血”不是同一个值:武器、攻击者倍率、伤害类型、护甲和目标的减伤效果都会参与计算。

攻击伤害与攻击间隔

伤害来源

没有武器时,基础伤害来自攻击者战斗组件的 defaultdamage;装备武器时,基础伤害改由武器的 weapon:GetDamage 提供。常规伤害随后按以下因素相乘,再加上不受倍率影响的额外伤害:

基础伤害 × 战斗组件伤害倍率 × 外部伤害倍率 × 伤害类型倍率 × 本次攻击倍率 × 对玩家倍率 × PVP 倍率 + 额外伤害

实际代码还会根据骑乘状态改用坐骑的基础伤害、伤害倍率和外部伤害倍率,并叠加鞍具的额外伤害。武器和攻击者自身的伤害类型加成会叠加;位面伤害等特殊伤害则单独收集,并在命中后经过特殊防御处理。

攻击带有电击刺激时,代码会根据目标的潮湿倍率计算额外的电击伤害倍率;免疫电击的目标不会使用这项加成。

攻击间隔

攻击开始时,StartAttack 会记录开始时间并重置攻击冷却。CanAttack 只有在冷却结束、canattack 为真、状态图不处于阻塞状态,并且目标位于攻击范围内时才会允许发出 doattack。攻击间隔由实体设置的 min_attack_period 决定;它不是所有生物共用的固定值,应以对应实体的 prefab、状态图或脑文件设置为准。

攻击动作本身也可能因为状态图动画尚未到达伤害帧而暂时不能命中,所以“可以开始攻击”和“伤害已经结算”是两个不同阶段。

命中距离、攻击范围与走位

攻击范围和实际命中范围分开计算。CanAttack 使用攻击范围判断能否开始攻击;DoAttack 使用命中范围和目标的物理半径进行实际命中检查。攻击还可以设置扇形角度,目标只有位于攻击者朝向的有效扇区内才会命中。投射物在近距离检查失败时,会改用投射物当前位置、目标物理半径和投射物命中距离判断。

常见的追击行为 ChaseAndAttack 会持续执行以下逻辑:

  • 目标无效或死亡时清除目标并停止移动;
  • 不在攻击距离内时,通过 locomotor:GoToPoint 朝目标移动;
  • 进入攻击范围后停止移动,并在状态允许时朝向目标;
  • 调用 combat:TryAttack,由战斗组件决定是否真正发出攻击;
  • 超出放弃距离或追击时间后放弃目标。

这也是近战走位的核心:保持在攻击范围内,同时避免在攻击动作尚未结束时重复发起攻击。对玩家而言,LocomotorCanAttack 还会检查某些较大攻击范围下前方地面是否可通行;没有远程武器时,跨越无效地面到达目标可能被判定为尚未到位。移动速度由 locomotor 的行走/奔跑速度、外部速度倍率、装备、坐骑和地面倍率共同决定。

护甲、抗性与实际掉血

目标受到攻击时,处理顺序大致如下:

  1. 若目标有攻击闪避组件且成功闪避,普通伤害与特殊伤害都会被清零。
  2. inventory:ApplyDamage 检查装备上的完全抵抗效果;满足条件时可直接把此次伤害变为零。
  3. 装备上的伤害类型抗性先乘到伤害上。
  4. 普通护甲按各护甲的吸收率计算。普通伤害使用所有护甲中的最高吸收率作为吸收比例;吸收掉的伤害再按各护甲吸收率占总吸收率的比例分摊,用于计算护甲承受的额外损耗。
  5. 鞍具可以继续吸收伤害。
  6. 目标的伤害类型抗性、外部受击倍率和条件受击倍率继续生效。
  7. 穿过护甲后的伤害,才会叠加攻击者的额外伤害函数;特殊伤害则经过特殊防御后加入总伤害。
  8. 最后调用 health:DoDelta,由生命组件处理无敌、吸收、外部减伤和每次受击上限。

生命组件中的吸收修正以“减少伤害”的形式作用于负的生命变化量;外部固定减伤会让扣血量进一步靠近零。实体还可以设置每次受击的最大扣血量,用于限制单次伤害。护甲吸收与生命组件的外部减伤是不同阶段,不能把两者简单相加。

无敌、闪避与受击状态

生命组件的 IsInvincible 在两种情况下返回真:实体被显式设置为无敌,或状态图带有 temp_invincible 状态标签。普通 health:DoDelta 在未要求忽略无敌时会直接返回零,不扣除生命;传送中的实体也会走这一保护分支。

无敌状态不等于仇恨一定清除。战斗组件在维持目标时,会特别处理带有 iframeskeepaggro 状态标签的目标:目标暂时处于无敌/不可攻击状态时,可以保留攻击者的仇恨,而不是因为暂时不可攻击就立刻丢失目标。相反,invisible、noattack、flight、playerghost 等标签会影响目标是否可被攻击;具体是否生效还取决于攻击者、目标和PVP状态。

部分实体还通过攻击闪避组件完全避开一次攻击;这与护甲吸收不同,闪避会在护甲处理前把伤害置零。受击后的硬直、击退和恢复时间主要由实体的状态图、hit_recovery 等实体级设置控制,战斗组件本身只负责触发 attacked 或 blocked 事件。

仇恨、目标与阵营

目标由 combat:SetTarget 管理。设置目标时,代码会先检查目标是否有效并通过仇恨规则;带有 notarget、不可见、无敌保护或阵营关系不允许攻击的目标可能被拒绝。

实体可以通过 SetRetargetFunction 周期性寻找新目标。重新选目标时,强制切换会立即替换当前目标;当当前目标是建筑而新目标不是建筑时,也会优先切换。ShareTarget 可以在一定范围内把目标建议给附近的其他战斗实体,但接收者仍需通过自己的目标条件。

目标维持函数会定期确认目标仍然有效、没有进入虚空,并且仍可被攻击;检查失败时会触发 losttarget 并丢弃目标。目标进入 iframeskeepaggro 状态时,代码会临时允许维持仇恨,即使普通的可攻击检查会失败。

阵营判断由 CanBeAlly 和 IsAlly 完成,考虑玩家、跟随者、领导者、驯化状态、玩家阵营标签以及PVP设置。非PVP状态下,玩家及其阵营单位通常会被视为同阵营;PVP开启后,玩家之间的友方判断会改变。骑乘和平和坐骑还会限制玩家攻击,除非使用远程武器。

实战要点

  • 先看攻击间隔,再看攻击力:攻击频率由 min_attack_period 和状态图动作共同决定,不能只用面板伤害判断输出。
  • 近战要把目标保持在命中范围内:能开始攻击不代表动画结算时目标仍在范围内;移动、击退和目标位移都可能造成未命中。
  • 护甲优先处理普通伤害:普通护甲吸收发生在生命组件减伤之前;特殊伤害还要单独检查对应的特殊防御。
  • 利用攻击后空档走位:追击行为会在攻击范围内停止移动,玩家可以利用敌方攻击动作、攻击冷却和受击恢复时间离开命中范围。
  • 不要把无敌帧当作清仇恨:带有 iframeskeepaggro 的实体可以在无敌期间继续保留目标;需要真正脱离仇恨,还要满足目标无效、不可维持或行为树主动放弃等条件。
  • 远程攻击改变走位要求:远程武器通过投射物命中检查,不必像普通近战一样贴近目标,但仍会受到目标可攻击性、投射物命中距离和地形路径的影响。

代码参考

  • scripts/components/combat.lua:目标管理、攻击冷却、攻击范围、伤害计算、命中、受击与仇恨维持;主要函数包括 CanAttack、CalcDamage、DoAttack、GetAttacked、SetTarget、TryRetarget。
  • scripts/components/combat_replica.lua:目标有效性、阵营关系、可攻击性和客户端侧范围判断。
  • scripts/components/health.lua:无敌判定、生命扣除、吸收与外部减伤、单次受击上限;主要函数包括 IsInvincible、DoDelta、SetMaxDamageTakenPerHit。
  • scripts/components/inventory.lua:装备抵抗、护甲吸收和特殊伤害防御。
  • scripts/components/locomotor.lua:移动速度、追击移动和到达目标的移动控制。
  • scripts/behaviours/chaseandattack.lua:常见生物的追击、停步、转向、攻击和放弃目标流程。

相关条目

生命值

版本记录

  • 首次收录:build 756039;正文编写:build 756039;核对至:build 756039

依据源码:scripts/components/combat.lua scripts/components/combat_replica.lua scripts/components/health.lua scripts/components/inventory.lua scripts/components/locomotor.lua scripts/behaviours/chaseandattack.lua

涉及实体:combat(combat)