Files
bl/logic/service/fight/fightc.go
2025-11-15 22:17:43 +00:00

376 lines
10 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 fight
import (
"blazing/common/utils"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/modules/blazing/model"
"fmt"
"reflect"
"github.com/barkimedes/go-deepcopy"
"github.com/shopspring/decimal"
)
// 处理技能攻击逻辑
func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *info.SkillEntity) {
//oldpet := f.copypet(attacker.CurrentPet)
a.AttackTimeC(attacker.GetProp(5, true)) //计算命中
defender.Exec(func(t input.Effect) bool { //计算闪避 ,然后修改对方命中),同时相当于计算属性无效这种
t.Ctx().SkillEntity = a
t.Skill_Hit_ex()
return true
})
attacker.AttackValue.AttackTime = a.AttackTime //是否命中赋值
// attacker.Exec(func(t input.Effect) bool { //计算命中 miss改命中
// //计算视为效果
// t.Ctx().SkillEntity = a
// t.Calculate_Pre() //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
// return true
// })
attacker.Exec(func(t input.Effect) bool {
//计算变威力
t.Ctx().SkillEntity = a
t.Skill_Hit() //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
return true
})
//技能命中+效果失效 这里就是修改效果命中为false
//技能miss+效果生效 这里属于强制改命中效果,但是正常来说,技能miss掉后效果也应该失效
//技能失效+效果失效
// 记录技能信息
attacker.SkillID = uint32(a.ID) //获取技能ID
if attacker.AttackTime > 0 { //如果命中
attacker.CalculateCrit(defender, a) //暴击计算
attacker.IsCritical = a.Crit
attacker.DamageZone.Damage = attacker.CalculatePower(defender, a)
//睡眠受击消除
if attacker.IsCritical == 1 {
//暴击破防
if a.Category() == info.Category.PHYSICAL && defender.Prop[1] > 0 {
defender.Prop[1] = 0
} else if a.Category() == info.Category.SPECIAL && defender.Prop[3] > 0 {
defender.Prop[3] = 0
}
//暴击翻倍
attacker.DamageZone.Damage = attacker.DamageZone.Damage.Mul(decimal.NewFromInt(2))
}
}
// attacker.AddEffects(attacker.EffectCache...) //命中再添加效果
for _, e := range attacker.EffectCache {
//这里实现应该参考本地技能是否命中,然后
e.Hit(attacker.AttackTime != 0) //我方效果命中
}
// 扣减防御方血量
attacker.Exec(func(t input.Effect) bool {
t.Ctx().SkillEntity = a
t.OnSkill() //调用伤害计算
return true
})
defender.Damage(attacker, &info.DamageZone{
Damage: attacker.DamageZone.Damage,
},
)
//这里其实是受到致死伤害
//然后先触发死亡效果消除所有buff
//然后触发回神效果
}
func IsNil(x interface{}) bool {
if x == nil {
return true
}
rv := reflect.ValueOf(x)
return rv.Kind() == reflect.Ptr && rv.IsNil()
}
func (f *FightC) copyskill(t *action.SelectSkillAction) *info.SkillEntity {
if t == nil {
return nil
}
if t.SkillEntity == nil {
return nil
}
oldskill, _ := deepcopy.Anything(t.SkillEntity) //备份技能
oldskill.(*info.SkillEntity).Rand = f.rand //拷贝后随机数丢失
return oldskill.(*info.SkillEntity)
}
func (f *FightC) copypet(t *model.PetInfo) *model.PetInfo {
oldskill, _ := deepcopy.Anything(t) //备份技能
// oldskill.(*info.BattlePetEntity).Rand = f.rand //拷贝后随机数丢失
return oldskill.(*model.PetInfo)
}
//回合有先手方和后手方,同时有攻击方和被攻击方
func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
//双方首发精灵登场时,依挑战方机制:房主方先判定,挑战方后判定
//双方非首发精灵登场时,根据切换先后判定(看手速)
// 神罗、圣华登场时魂免“登场时xx”等效果
//阿枫的效果也在这里判断
// var oldpet [2]*model.PetInfo
// var oldhp [2]uint32
// var oldskill [2][]model.SkillInfo
// oldpet[0], oldpet[1] = f.copypet(f.Our.CurrentPet.Info), f.copypet(f.Opp.CurrentPet.Info)
// fmt.Println("开始时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
// defer func() {
// oldhp[0], oldhp[1] = f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp
// oldskill[0], oldskill[1] = f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList
// f.Our.CurrentPet.Info, f.Opp.CurrentPet.Info = oldpet[0], oldpet[1] //还原精灵信息
// f.Opp.CurrentPet.Info.Hp, f.Our.CurrentPet.Info.Hp = oldhp[0], oldhp[1]
// f.Opp.CurrentPet.Info.SkillList, f.Our.CurrentPet.Info.SkillList = oldskill[0], oldskill[1]
// fmt.Println("结束时对方最大体力值", f.Opp.CurrentPet.Info.MaxHp)
// }()
f.Our.Exec(func(t input.Effect) bool { //回合开始前
//结算状态
t.Turn_Start(fattack, sattack)
return true
})
f.Opp.Exec(func(t input.Effect) bool { //回合开始前
//结算状态
t.Turn_Start(fattack, sattack)
return true
})
// 伤害值
if fattack != nil { //如果首技能是空的,说明都空过了
if fattack.GetPlayerID() == f.ownerID {
//是否miss都应该施加解析effect
f.Our.Parseskill(fattack) //解析到临时数据
f.Opp.Parseskill(sattack) //解析到临时数据
} else {
f.Opp.Parseskill(fattack)
f.Our.Parseskill(sattack)
}
}
f.Our.Exec(func(t input.Effect) bool { //回合开始前
//结算状态
t.Compare_Pre(fattack, sattack) //先结算技能的优先级
return true
})
f.Opp.Exec(func(t input.Effect) bool { //回合开始前
//结算状态
t.Compare_Pre(fattack, sattack) //先结算技能的优先级
return true
})
// 根据攻击方归属设置当前战斗的主/次攻击方属性
if fattack != nil {
if fattack.GetPlayerID() == f.ownerID {
f.First, f.Second = f.Our, f.Opp // 攻击方为我方时,主攻击方是我方
} else {
f.First, f.Second = f.Opp, f.Our // 攻击方为对方时,主攻击方是对方
}
} else {
f.First, f.Second = f.Our, f.Opp
}
f.First.ResetAttackValue()
f.Second.ResetAttackValue()
if fattack != nil && sattack != nil {
switch {
case fattack.SkillEntity.Priority < sattack.SkillEntity.Priority:
fattack, sattack = sattack, fattack //互换先手权
f.First, f.Second = f.Second, f.First
case fattack.SkillEntity.Priority == sattack.SkillEntity.Priority:
if f.Second.GetProp(4, false) > f.First.GetProp(4, false) {
fattack, sattack = sattack, fattack //互换先手权
f.First, f.Second = f.Second, f.First
}
}
}
var attacker, defender *input.Input
//开始回合操作
for i := 0; i < 2; i++ {
var oldskill *info.SkillEntity //原始技能
var currentskill *info.SkillEntity //当前技能
if i == 0 { //
attacker, defender = f.First, f.Second
oldskill = f.copyskill(fattack)
} else {
attacker, defender = f.Second, f.First
oldskill = f.copyskill(sattack)
}
currentskill = oldskill
canuseskill := attacker.Exec(func(t input.Effect) bool { //这个是能否使用技能
//结算状态
//然后这里还可以处理自爆类
t.Ctx().SkillEntity = currentskill
return t.Skill_Hit_Pre(fattack, sattack) //返回本身结算,如果false,说明不能使用技能了
})
canuse := canuseskill && //
action.CanUse(currentskill) && //pp还在
attacker.CurrentPet.Info.Hp > 0
if !canuse {
//根本没释放技能,这些效果全部失效
for _, e := range attacker.EffectCache {
e.Alive(false)
}
//这时候将被覆盖的效果全部装回来enterturn
for _, e := range attacker.Effect_Lost {
e.Alive(true)
}
}
// 结算状态
// 然后这里还可以处理自爆类
if canuse { //可以使用技能
f.processSkillAttack(attacker, defender, currentskill)
currentskill = oldskill //还原技能
// if oldskill != nil {
// fmt.Println("结束攻击_old", oldskill.Power)
// fmt.Println("结束攻击_new", currentskill.Power)
// }
_, skill, ok := utils.FindWithIndex(attacker.CurrentPet.Info.SkillList, func(item model.SkillInfo) bool {
return item.ID == currentskill.Info.ID
})
if ok {
skill.PP--
}
}
//技能使用后
defender.Exec(func(t input.Effect) bool {
t.Ctx().SkillEntity = currentskill
t.Skill_Use_ex()
return true
})
//技能使用后
attacker.Exec(func(t input.Effect) bool { //技能使用后的我方效果
t.Ctx().SkillEntity = currentskill
t.Skill_Useed()
return true
})
fmt.Println(i,
// "玩家技能:", oldskill.(*info.SkillEntity).ID,
"玩家技能伤害:", attacker.DamageZone.Damage,
"自身剩余血量:", attacker.CurrentPet.Info.Hp,
"对手剩余血量:", defender.CurrentPet.Info.Hp,
)
if attacker.CurrentPet.Info.Hp <= 0 {
if defender.CurrentPet.Info.Hp == 0 { //先手方死亡,触发反同归于尽
defender.CurrentPet.Info.Hp = 1
}
if f.IsWin(defender, attacker.CurrentPet.Info.CatchTime) { //然后检查是否战斗结束
f.FightOverInfo.WinnerId = defender.UserID
f.closefight = true
// break
}
attacker.CanChange = true
break
}
if defender.CurrentPet.Info.Hp == 0 {
if attacker.CurrentPet.Info.Hp == 0 { //先手方死亡,触发反同归于尽
attacker.CurrentPet.Info.Hp = 1
}
defender.CanChange = true //被打死就可以切精灵了
if f.IsWin(attacker, defender.CurrentPet.Info.CatchTime) { //然后检查是否战斗结束
var WinnerId uint32
if i == 0 {
WinnerId = f.First.Player.GetInfo().UserID
} else {
WinnerId = f.Second.Player.GetInfo().UserID
}
f.FightOverInfo.WinnerId = WinnerId
f.closefight = true
break
}
}
}
f.Broadcast(func(ff *input.Input) {
ff.GenSataus()
ff.Exec(func(t input.Effect) bool { //这个是能否使用技能
//结算状态
t.Turn_End() //返回本身结算,如果false,说明不能使用技能了
return true
})
ff.GenInfo()
})
ret := info.AttackValueS{
FAttack: *f.First.AttackValue,
SAttack: *f.Second.AttackValue,
}
f.Broadcast(func(ff *input.Input) {
for _, v := range f.Switch {
if ff.Player.GetInfo().UserID != v.PlayerID {
ff.Player.SendChangePet(v.Reason)
}
}
ff.Player.SendAttackValue(ret)
})
f.Switch = []*action.ActiveSwitchAction{}
}