2025-09-16 22:51:22 +08:00
|
|
|
|
package effect
|
2025-09-23 20:53:47 +00:00
|
|
|
|
|
|
|
|
|
|
import (
|
2025-11-16 20:30:17 +00:00
|
|
|
|
element "blazing/common/data/Element"
|
2025-11-20 05:57:29 +08:00
|
|
|
|
"blazing/common/utils"
|
2025-11-13 21:36:18 +08:00
|
|
|
|
"blazing/logic/service/fight/action"
|
2025-09-23 20:53:47 +00:00
|
|
|
|
"blazing/logic/service/fight/info"
|
|
|
|
|
|
"blazing/logic/service/fight/input"
|
|
|
|
|
|
"blazing/logic/service/fight/node"
|
2025-09-26 13:33:55 +08:00
|
|
|
|
|
2025-12-05 00:24:02 +08:00
|
|
|
|
"github.com/alpacahq/alpacadecimal"
|
2025-09-23 20:53:47 +00:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 修正拼写错误:BaseSataus -> BaseStatus
|
|
|
|
|
|
type BaseStatus struct {
|
2025-11-13 02:43:00 +08:00
|
|
|
|
node.EffectNode
|
2025-11-16 20:30:17 +00:00
|
|
|
|
Status info.EnumPetStatus // 状态类型枚举
|
2025-11-13 02:43:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 重写切换事件:我方单位切换时清除状态
|
2025-12-26 03:51:24 +08:00
|
|
|
|
func (e *BaseStatus) SwitchOut(in *input.Input) bool {
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 我方单位下场时,状态失效
|
2026-04-04 06:27:15 +08:00
|
|
|
|
if in == e.CarrierInput() {
|
2025-11-13 02:43:00 +08:00
|
|
|
|
e.Alive(false)
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 不能出手的基础状态(如麻痹、疲惫等)
|
|
|
|
|
|
type StatusCannotAct struct {
|
|
|
|
|
|
BaseStatus
|
2025-09-24 16:36:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 技能命中前拦截:阻止出手
|
2026-01-05 23:00:42 +08:00
|
|
|
|
func (e *StatusCannotAct) ActionStart(attacker, defender *action.SelectSkillAction) bool {
|
2025-09-23 21:01:30 +00:00
|
|
|
|
return false
|
2025-09-26 02:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-13 21:06:45 +08:00
|
|
|
|
// 疲惫状态:仅限制攻击技能,本回合属性技能仍可正常使用。
|
|
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 睡眠状态:受击后解除
|
|
|
|
|
|
type StatusSleep struct {
|
|
|
|
|
|
StatusCannotAct
|
2026-04-13 21:06:45 +08:00
|
|
|
|
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
|
2025-10-26 20:56:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-05 23:00:42 +08:00
|
|
|
|
func (e *StatusSleep) ActionStart(attacker, defender *action.SelectSkillAction) bool {
|
2026-04-13 21:06:45 +08:00
|
|
|
|
if e.Duration() <= 0 {
|
|
|
|
|
|
e.hasTriedAct = false
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
e.hasTriedAct = true
|
2026-01-05 23:00:42 +08:00
|
|
|
|
return e.StatusCannotAct.ActionStart(attacker, defender)
|
2025-11-09 02:29:21 +00:00
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
|
2025-11-11 05:54:24 +00:00
|
|
|
|
func (e *StatusSleep) Skill_Use_ex() bool {
|
2025-11-16 20:30:17 +00:00
|
|
|
|
if !e.hasTriedAct {
|
2025-11-09 02:29:21 +00:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
2026-04-13 21:06:45 +08:00
|
|
|
|
if e.Duration() <= 0 && e.Ctx().SkillEntity != nil && e.Ctx().Category() != info.Category.STATUS {
|
2025-11-13 05:05:05 +08:00
|
|
|
|
e.Alive(false)
|
2025-11-08 19:48:59 +08:00
|
|
|
|
}
|
2026-04-13 21:06:45 +08:00
|
|
|
|
e.hasTriedAct = false
|
2025-10-26 20:56:03 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-13 21:06:45 +08:00
|
|
|
|
func (e *StatusSleep) TurnEnd() {
|
|
|
|
|
|
e.hasTriedAct = false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 持续伤害状态基类(中毒、冻伤、烧伤等)
|
|
|
|
|
|
type ContinuousDamage struct {
|
|
|
|
|
|
BaseStatus
|
2026-03-08 10:34:23 +08:00
|
|
|
|
isheal bool //是否回血
|
2025-09-26 02:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-14 15:21:47 +08:00
|
|
|
|
// 回合开始触发持续伤害,保证吃药/空过回合时也会正常结算。
|
|
|
|
|
|
func (e *ContinuousDamage) TurnStart(attacker, defender *action.SelectSkillAction) {
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier := e.CarrierInput()
|
|
|
|
|
|
source := e.SourceInput()
|
2026-04-05 02:25:44 +08:00
|
|
|
|
opp := e.TargetInput()
|
2026-04-04 06:27:15 +08:00
|
|
|
|
if carrier == nil {
|
2026-04-14 15:21:47 +08:00
|
|
|
|
return
|
2026-04-04 06:27:15 +08:00
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
damage := e.calculateDamage()
|
2026-01-20 02:25:02 +08:00
|
|
|
|
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier.Damage(source, &info.DamageZone{
|
2025-11-11 05:54:24 +00:00
|
|
|
|
Type: info.DamageType.True,
|
2025-11-16 20:30:17 +00:00
|
|
|
|
Damage: damage,
|
2025-11-11 05:54:24 +00:00
|
|
|
|
})
|
2026-03-08 10:34:23 +08:00
|
|
|
|
if len(e.SideEffectArgs) == 0 {
|
2026-04-14 15:21:47 +08:00
|
|
|
|
return
|
2026-03-08 10:34:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
// 额外效果
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier.Damage(source, &info.DamageZone{
|
2026-03-08 10:34:23 +08:00
|
|
|
|
Type: info.DamageType.True,
|
|
|
|
|
|
Damage: damage,
|
|
|
|
|
|
})
|
2026-04-04 06:27:15 +08:00
|
|
|
|
if opp == nil || opp.CurPet[0].GetHP().IntPart() == 0 {
|
2026-04-14 15:21:47 +08:00
|
|
|
|
return
|
2026-03-08 10:34:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 给对方回血(不受回血限制影响)
|
2026-04-04 06:27:15 +08:00
|
|
|
|
opp.Heal(carrier, nil, damage)
|
2025-09-26 02:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 计算伤害:最大生命值的1/8
|
2025-12-05 00:24:02 +08:00
|
|
|
|
func (e *ContinuousDamage) calculateDamage() alpacadecimal.Decimal {
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier := e.CarrierInput()
|
|
|
|
|
|
if carrier == nil || carrier.CurPet[0] == nil {
|
|
|
|
|
|
return alpacadecimal.Zero
|
|
|
|
|
|
}
|
|
|
|
|
|
return alpacadecimal.NewFromInt(int64(carrier.CurPet[0].Info.MaxHp)).
|
2025-12-05 00:24:02 +08:00
|
|
|
|
Div(alpacadecimal.NewFromInt(8))
|
2025-09-26 02:09:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 05:57:29 +08:00
|
|
|
|
type Burned struct {
|
|
|
|
|
|
ContinuousDamage //继承扣血类
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-04 22:10:34 +08:00
|
|
|
|
func (e *Burned) SkillHit() bool {
|
2025-11-20 05:57:29 +08:00
|
|
|
|
|
2026-03-09 18:49:51 +08:00
|
|
|
|
e.Ctx().SkillEntity.XML.Power /= 2
|
2025-11-20 05:57:29 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 寄生种子状态:扣血同时给对方回血
|
|
|
|
|
|
type ParasiticSeed struct {
|
2025-12-26 03:51:24 +08:00
|
|
|
|
node.EffectNode
|
|
|
|
|
|
Status info.EnumPetStatus // 状态类型枚举
|
2025-11-16 20:30:17 +00:00
|
|
|
|
}
|
2025-11-08 23:26:10 +08:00
|
|
|
|
|
2026-01-23 20:18:58 +00:00
|
|
|
|
func (e *ParasiticSeed) SwitchOut(in *input.Input) bool {
|
2026-02-01 01:01:16 +08:00
|
|
|
|
//如果我放切换
|
2026-04-04 06:27:15 +08:00
|
|
|
|
if in == e.CarrierInput() {
|
2026-01-23 20:18:58 +00:00
|
|
|
|
e.Alive(false)
|
|
|
|
|
|
}
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-13 21:06:45 +08:00
|
|
|
|
// 回合开始触发寄生效果。寄生属于完整回合流程的一部分,不依赖本回合是否成功出手。
|
|
|
|
|
|
func (e *ParasiticSeed) TurnStart(attacker, defender *action.SelectSkillAction) {
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier := e.CarrierInput()
|
|
|
|
|
|
source := e.SourceInput()
|
|
|
|
|
|
if carrier == nil {
|
2026-04-13 21:06:45 +08:00
|
|
|
|
return
|
2026-04-04 06:27:15 +08:00
|
|
|
|
}
|
2025-10-15 14:24:46 +00:00
|
|
|
|
|
2026-04-04 06:27:15 +08:00
|
|
|
|
damage := alpacadecimal.NewFromInt(int64(carrier.CurPet[0].Info.MaxHp)).
|
2025-12-05 00:24:02 +08:00
|
|
|
|
Div(alpacadecimal.NewFromInt(8))
|
2025-09-26 13:33:55 +08:00
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 对我方造成真实伤害
|
2026-04-04 06:27:15 +08:00
|
|
|
|
carrier.Damage(source, &info.DamageZone{
|
2025-11-16 20:30:17 +00:00
|
|
|
|
Type: info.DamageType.True,
|
|
|
|
|
|
Damage: damage,
|
|
|
|
|
|
})
|
2026-04-13 21:06:45 +08:00
|
|
|
|
if source == nil || source.CurPet[0] == nil || source.CurPet[0].GetHP().IntPart() == 0 {
|
|
|
|
|
|
return
|
2026-02-02 01:01:01 +08:00
|
|
|
|
}
|
2025-09-26 02:09:33 +00:00
|
|
|
|
|
2026-04-13 21:06:45 +08:00
|
|
|
|
// 给寄生种子的施放者回血(不受回血限制影响)
|
|
|
|
|
|
source.Heal(carrier, nil, damage)
|
2025-09-23 21:01:30 +00:00
|
|
|
|
}
|
2025-09-23 20:53:47 +00:00
|
|
|
|
|
2025-11-20 05:57:29 +08:00
|
|
|
|
type Flammable struct {
|
|
|
|
|
|
BaseStatus
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-05 23:00:42 +08:00
|
|
|
|
func (e *Flammable) ActionStart(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) bool {
|
2025-11-20 05:57:29 +08:00
|
|
|
|
if e.Ctx().SkillEntity == nil {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2026-03-09 18:49:51 +08:00
|
|
|
|
e.Ctx().SkillEntity.Accuracy.Sub(alpacadecimal.NewFromInt(30))
|
2025-11-20 05:57:29 +08:00
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
func (e *Flammable) Skill_Use_ex() bool {
|
|
|
|
|
|
if e.Ctx().SkillEntity == nil {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-11-25 18:25:52 +08:00
|
|
|
|
|
2026-03-09 18:49:51 +08:00
|
|
|
|
if e.Ctx().SkillEntity.XML.Type != int(element.ElementTypeFire) {
|
2025-11-20 05:57:29 +08:00
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
// 获取状态效果
|
2025-12-11 19:12:54 +00:00
|
|
|
|
eff := e.Ctx().Our.InitEffect(input.EffectType.Status, int(info.PetStatus.Burned))
|
2025-11-20 05:57:29 +08:00
|
|
|
|
if eff == nil {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2025-12-11 19:12:54 +00:00
|
|
|
|
|
2025-11-20 05:57:29 +08:00
|
|
|
|
e.Ctx().Our.AddEffect(e.Ctx().Our, eff)
|
|
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type Confused struct {
|
|
|
|
|
|
BaseStatus
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-05 23:00:42 +08:00
|
|
|
|
func (e *Confused) ActionStart(fattack *action.SelectSkillAction, sattack *action.SelectSkillAction) bool {
|
2025-11-20 05:57:29 +08:00
|
|
|
|
if e.Ctx().SkillEntity == nil {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
2026-03-09 18:49:51 +08:00
|
|
|
|
e.Ctx().SkillEntity.Accuracy.Sub(alpacadecimal.NewFromInt(80))
|
2025-11-20 05:57:29 +08:00
|
|
|
|
ok, _, _ := e.Input.Player.Roll(5, 100)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
e.Ctx().Our.Damage(e.Ctx().Our, &info.DamageZone{
|
|
|
|
|
|
Type: info.DamageType.Fixed,
|
2025-12-05 00:24:02 +08:00
|
|
|
|
Damage: alpacadecimal.NewFromInt(50),
|
2025-11-20 05:57:29 +08:00
|
|
|
|
})
|
|
|
|
|
|
return true
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-29 01:17:18 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 05:57:29 +08:00
|
|
|
|
type Weakened struct {
|
|
|
|
|
|
BaseStatus
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-04 22:10:34 +08:00
|
|
|
|
func (e *Weakened) DamageDivEx(t *info.DamageZone) bool {
|
2025-11-20 05:57:29 +08:00
|
|
|
|
// 1. 定义衰弱等级对应的倍率表(索引对应等级,0级无倍率)
|
|
|
|
|
|
// 索引0: 0%(未衰弱)、1:25%、2:50%、3:100%、4:250%、5:500%
|
2025-12-05 00:24:02 +08:00
|
|
|
|
weakenedMultiples := []alpacadecimal.Decimal{
|
2026-01-23 20:18:58 +00:00
|
|
|
|
alpacadecimal.Zero, // 0级
|
2025-12-05 00:24:02 +08:00
|
|
|
|
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%)
|
2025-11-20 05:57:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 校验并限制衰弱等级(≤0 直接返回,≥5 按5级算)
|
2025-11-29 19:26:56 +08:00
|
|
|
|
level := e.Stack()
|
2025-11-20 05:57:29 +08:00
|
|
|
|
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
|
|
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
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{}) // 冻伤
|
2025-11-20 05:57:29 +08:00
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Burned), &Burned{}) // 烧伤
|
2026-03-29 19:00:08 +08:00
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Bleeding), &ContinuousDamage{}) // 流血
|
2025-11-20 05:57:29 +08:00
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Weakened), &Weakened{}) // 衰弱
|
|
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Confused), &Confused{}) // 混乱
|
2026-03-29 01:17:18 +08:00
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Blind), &Blind{}) // 失明
|
2025-11-20 05:57:29 +08:00
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Flammable), &Flammable{}) // 易燃
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 批量注册不能行动的状态
|
|
|
|
|
|
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)
|
2025-09-23 20:53:47 +00:00
|
|
|
|
}
|
2025-11-16 20:30:17 +00:00
|
|
|
|
|
2026-04-13 21:06:45 +08:00
|
|
|
|
tired := &StatusTired{}
|
|
|
|
|
|
tired.Status = info.PetStatus.Tired
|
|
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Tired), tired)
|
|
|
|
|
|
|
2025-11-16 20:30:17 +00:00
|
|
|
|
// 注册睡眠状态(使用枚举常量替代硬编码8)
|
|
|
|
|
|
input.InitEffect(input.EffectType.Status, int(info.PetStatus.Sleep), &StatusSleep{})
|
2025-09-23 20:53:47 +00:00
|
|
|
|
}
|