Files
bl/logic/service/fight/effect/effect_status.go
昔念 f95fd49efd
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
```
feat(fight): 新增疲惫状态并优化睡眠状态机制

- 实现疲惫状态(StatusTired),仅限制攻击技能,允许属性技能正常使用
- 重构睡眠状态,改为在被攻击且未miss时立即解除,而非技能使用后
- 修复寄生种子效果触发时机,改为回合开始时触发
- 调整寄生效果的目标为技能施放者而非
2026-04-13 21:06:45 +08:00

316 lines
8.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package effect
import (
element "blazing/common/data/Element"
"blazing/common/utils"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
"github.com/alpacahq/alpacadecimal"
)
// 修正拼写错误BaseSataus -> BaseStatus
type BaseStatus struct {
node.EffectNode
Status info.EnumPetStatus // 状态类型枚举
}
// 重写切换事件:我方单位切换时清除状态
func (e *BaseStatus) SwitchOut(in *input.Input) bool {
// 我方单位下场时,状态失效
if in == e.CarrierInput() {
e.Alive(false)
}
return true
}
// 不能出手的基础状态(如麻痹、疲惫等)
type StatusCannotAct struct {
BaseStatus
}
// 技能命中前拦截:阻止出手
func (e *StatusCannotAct) ActionStart(attacker, defender *action.SelectSkillAction) bool {
return false
}
// 疲惫状态:仅限制攻击技能,本回合属性技能仍可正常使用。
type StatusTired struct {
BaseStatus
}
func (e *StatusTired) ActionStart(attacker, defender *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return false
}
return e.Ctx().SkillEntity.Category() == info.Category.STATUS
}
// 睡眠状态:受击后解除
type StatusSleep struct {
StatusCannotAct
hasTriedAct bool
}
// 睡眠在“被攻击且未 miss”后立即解除而不是等到技能使用后节点。
func (e *StatusSleep) DamageSubEx(zone *info.DamageZone) bool {
if zone == nil || e.Ctx().SkillEntity == nil {
return true
}
if e.Ctx().SkillEntity.Category() != info.Category.STATUS {
e.Alive(false)
}
return true
}
func (e *StatusSleep) ActionStart(attacker, defender *action.SelectSkillAction) bool {
if e.Duration() <= 0 {
e.hasTriedAct = false
return true
}
e.hasTriedAct = true
return e.StatusCannotAct.ActionStart(attacker, defender)
}
func (e *StatusSleep) Skill_Use_ex() bool {
if !e.hasTriedAct {
return true
}
if e.Duration() <= 0 && e.Ctx().SkillEntity != nil && e.Ctx().Category() != info.Category.STATUS {
e.Alive(false)
}
e.hasTriedAct = false
return true
}
func (e *StatusSleep) TurnEnd() {
e.hasTriedAct = false
}
// 持续伤害状态基类(中毒、冻伤、烧伤等)
type ContinuousDamage struct {
BaseStatus
isheal bool //是否回血
}
// 技能命中前触发伤害1/8最大生命值真实伤害
func (e *ContinuousDamage) ActionStart(attacker, defender *action.SelectSkillAction) bool {
carrier := e.CarrierInput()
source := e.SourceInput()
opp := e.TargetInput()
if carrier == nil {
return true
}
damage := e.calculateDamage()
carrier.Damage(source, &info.DamageZone{
Type: info.DamageType.True,
Damage: damage,
})
if len(e.SideEffectArgs) == 0 {
return true
}
// 额外效果
carrier.Damage(source, &info.DamageZone{
Type: info.DamageType.True,
Damage: damage,
})
if opp == nil || opp.CurPet[0].GetHP().IntPart() == 0 {
return true
}
// 给对方回血(不受回血限制影响)
opp.Heal(carrier, nil, damage)
return true
}
// 计算伤害最大生命值的1/8
func (e *ContinuousDamage) calculateDamage() alpacadecimal.Decimal {
carrier := e.CarrierInput()
if carrier == nil || carrier.CurPet[0] == nil {
return alpacadecimal.Zero
}
return alpacadecimal.NewFromInt(int64(carrier.CurPet[0].Info.MaxHp)).
Div(alpacadecimal.NewFromInt(8))
}
type Burned struct {
ContinuousDamage //继承扣血类
}
func (e *Burned) SkillHit() bool {
e.Ctx().SkillEntity.XML.Power /= 2
return true
}
// 寄生种子状态:扣血同时给对方回血
type ParasiticSeed struct {
node.EffectNode
Status info.EnumPetStatus // 状态类型枚举
}
func (e *ParasiticSeed) SwitchOut(in *input.Input) bool {
//如果我放切换
if in == e.CarrierInput() {
e.Alive(false)
}
return true
}
// 回合开始触发寄生效果。寄生属于完整回合流程的一部分,不依赖本回合是否成功出手。
func (e *ParasiticSeed) TurnStart(attacker, defender *action.SelectSkillAction) {
carrier := e.CarrierInput()
source := e.SourceInput()
if carrier == nil {
return
}
damage := alpacadecimal.NewFromInt(int64(carrier.CurPet[0].Info.MaxHp)).
Div(alpacadecimal.NewFromInt(8))
// 对我方造成真实伤害
carrier.Damage(source, &info.DamageZone{
Type: info.DamageType.True,
Damage: damage,
})
if source == nil || source.CurPet[0] == nil || source.CurPet[0].GetHP().IntPart() == 0 {
return
}
// 给寄生种子的施放者回血(不受回血限制影响)
source.Heal(carrier, nil, damage)
}
type Flammable struct {
BaseStatus
}
func (e *Flammable) ActionStart(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return true
}
e.Ctx().SkillEntity.Accuracy.Sub(alpacadecimal.NewFromInt(30))
return true
}
func (e *Flammable) Skill_Use_ex() bool {
if e.Ctx().SkillEntity == nil {
return true
}
if e.Ctx().SkillEntity.XML.Type != int(element.ElementTypeFire) {
return true
}
// 获取状态效果
eff := e.Ctx().Our.InitEffect(input.EffectType.Status, int(info.PetStatus.Burned))
if eff == nil {
return true
}
e.Ctx().Our.AddEffect(e.Ctx().Our, eff)
return true
}
type Confused struct {
BaseStatus
}
func (e *Confused) ActionStart(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return true
}
e.Ctx().SkillEntity.Accuracy.Sub(alpacadecimal.NewFromInt(80))
ok, _, _ := e.Input.Player.Roll(5, 100)
if !ok {
return true
}
e.Ctx().Our.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Fixed,
Damage: alpacadecimal.NewFromInt(50),
})
return true
}
type Blind struct {
BaseStatus
}
func (e *Blind) ActionStart(fattack, sattack *action.SelectSkillAction) bool {
if e.Ctx().SkillEntity == nil {
return true
}
e.Ctx().SkillEntity.Accuracy = e.Ctx().SkillEntity.Accuracy.Mul(alpacadecimal.NewFromFloat(0.5))
return true
}
type Weakened struct {
BaseStatus
}
func (e *Weakened) DamageDivEx(t *info.DamageZone) bool {
// 1. 定义衰弱等级对应的倍率表索引对应等级0级无倍率
// 索引0: 0%未衰弱、1:25%、2:50%、3:100%、4:250%、5:500%
weakenedMultiples := []alpacadecimal.Decimal{
alpacadecimal.Zero, // 0级
alpacadecimal.NewFromFloat(0.25), // 1级25%
alpacadecimal.NewFromFloat(0.5), // 2级50%
alpacadecimal.NewFromFloat(1.0), // 3级100%
alpacadecimal.NewFromFloat(2.5), // 4级250%
alpacadecimal.NewFromFloat(5.0), // 5级500%
}
// 2. 校验并限制衰弱等级≤0 直接返回≥5 按5级算
level := e.Stack()
if level <= 0 {
return true
}
// 等级上限限制为5避免越界
level = utils.Min(level, 5)
// 3. 获取对应等级的倍率,计算最终伤害
multiple := weakenedMultiples[level]
// 伤害计算公式:原伤害 + 原伤害 × 倍率(等价于 原伤害 × (1+倍率)
t.Damage = t.Damage.Add(t.Damage.Mul(multiple))
return true
}
func init() {
// 注册持续伤害类状态
input.InitEffect(input.EffectType.Status, int(info.PetStatus.DrainedHP), &ParasiticSeed{}) // 寄生种子
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Poisoned), &ContinuousDamage{}) // 中毒
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Frozen), &ContinuousDamage{}) // 冻伤
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Burned), &Burned{}) // 烧伤
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Bleeding), &ContinuousDamage{}) // 流血
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Weakened), &Weakened{}) // 衰弱
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Confused), &Confused{}) // 混乱
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Blind), &Blind{}) // 失明
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Flammable), &Flammable{}) // 易燃
// 批量注册不能行动的状态
nonActingStatuses := []info.EnumPetStatus{
info.PetStatus.Paralysis, // 麻痹
info.PetStatus.Fear, // 害怕
info.PetStatus.Petrified, // 石化
}
for _, status := range nonActingStatuses {
effect := &StatusCannotAct{}
effect.Status = status
input.InitEffect(input.EffectType.Status, int(status), effect)
}
tired := &StatusTired{}
tired.Status = info.PetStatus.Tired
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Tired), tired)
// 注册睡眠状态使用枚举常量替代硬编码8
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Sleep), &StatusSleep{})
}