369 lines
11 KiB
Go
369 lines
11 KiB
Go
package fight
|
||
|
||
import (
|
||
"blazing/common/utils"
|
||
|
||
"blazing/logic/service/fight/action"
|
||
"blazing/logic/service/fight/info"
|
||
"blazing/logic/service/fight/input"
|
||
"blazing/modules/player/model"
|
||
"reflect"
|
||
|
||
"github.com/alpacahq/alpacadecimal"
|
||
"github.com/barkimedes/go-deepcopy"
|
||
"github.com/gogf/gf/v2/util/grand"
|
||
)
|
||
|
||
// processSkillAttack 处理技能攻击逻辑
|
||
func (f *FightC) processSkillAttack(attacker, defender *input.Input, skill *info.SkillEntity) {
|
||
skill.AttackTimeC(attacker.Prop[5]) //计算命中
|
||
|
||
defender.Exec(func(effect input.Effect) bool { //计算闪避,然后修改对方命中),同时相当于计算属性无效这种
|
||
effect.Ctx().SkillEntity = skill
|
||
effect.SkillHit_ex()
|
||
return true
|
||
})
|
||
|
||
attacker.Exec(func(effect input.Effect) bool {
|
||
//计算变威力
|
||
effect.Ctx().SkillEntity = skill
|
||
effect.SkillHit() //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
|
||
return true
|
||
})
|
||
var originalProps [2][6]int8
|
||
var originalPetInfo [2]model.PetInfo
|
||
//复制属性
|
||
originalProps[0], originalProps[1] = f.Our.Prop, f.Opp.Prop //先复制能力提升
|
||
originalPetInfo[0], originalPetInfo[1] = f.Our.CurrentPet.Info, f.Opp.CurrentPet.Info //先复制宠物信息
|
||
attacker.Exec(func(effect input.Effect) bool {
|
||
//计算变威力
|
||
effect.Ctx().SkillEntity = skill
|
||
effect.CalculatePre() //相当于先调整基础命中,不光调整命中,这里还能调整技能属性,暴击率
|
||
return true
|
||
})
|
||
//技能命中+效果失效 这里就是修改效果命中为false
|
||
//技能miss+效果生效 这里属于强制改命中效果,但是正常来说,技能miss掉后效果也应该失效
|
||
//技能失效+效果失效
|
||
attacker.AttackTime = skill.AttackTime
|
||
attacker.SkillID = uint32(skill.XML.ID) //获取技能ID
|
||
var SumDamage alpacadecimal.Decimal
|
||
if skill.AttackTime != 0 { //如果命中
|
||
|
||
SumDamage = attacker.CalculatePower(defender, skill)
|
||
attacker.CalculateCrit(defender, skill) //暴击计算
|
||
attacker.IsCritical = skill.Crit
|
||
}
|
||
|
||
//还原属性
|
||
f.Our.Prop, f.Opp.Prop = originalProps[0], originalProps[1]
|
||
f.Our.CurrentPet.Info, f.Opp.CurrentPet.Info = originalPetInfo[0], originalPetInfo[1]
|
||
|
||
if attacker.IsCritical == 1 { //命中了才有暴击
|
||
//暴击破防
|
||
if skill.Category() == info.Category.PHYSICAL && defender.Prop[1] > 0 {
|
||
defender.Prop[1] = 0
|
||
} else if skill.Category() == info.Category.SPECIAL && defender.Prop[3] > 0 {
|
||
defender.Prop[3] = 0
|
||
}
|
||
//暴击翻倍
|
||
SumDamage = SumDamage.Mul(alpacadecimal.NewFromInt(2))
|
||
}
|
||
|
||
//到这里已经是强制miss或者命中,所以根本不存在强制miss改命中的情况,因为miss的时候不会执行到这里
|
||
if !skill.Hit {
|
||
|
||
for _, effect := range attacker.EffectCache {
|
||
effect.Alive(false) //我方效果命中
|
||
}
|
||
//这时候将被覆盖的效果全部装回来enterturn
|
||
for _, effect := range attacker.EffectLost {
|
||
if effect.Duration() > 0 || effect.Duration() == -1 {
|
||
//effect.Alive(true)
|
||
attacker.AddEffect(effect.GetInput(), effect)
|
||
}
|
||
}
|
||
}
|
||
|
||
// 扣减防御方血量
|
||
attacker.Exec(func(effect input.Effect) bool {
|
||
effect.Ctx().SkillEntity = skill
|
||
effect.OnSkill() //调用伤害计算
|
||
return true
|
||
})
|
||
|
||
defender.Damage(attacker, &info.DamageZone{
|
||
Damage: SumDamage,
|
||
Type: info.DamageType.Red,
|
||
})
|
||
}
|
||
|
||
// IsNil 检查值是否为nil
|
||
func IsNil(x interface{}) bool {
|
||
if x == nil {
|
||
return true
|
||
}
|
||
rv := reflect.ValueOf(x)
|
||
return rv.Kind() == reflect.Ptr && rv.IsNil()
|
||
}
|
||
|
||
// copySkill 复制技能实体
|
||
func (f *FightC) copySkill(action *action.SelectSkillAction) *info.SkillEntity {
|
||
if action == nil {
|
||
return nil
|
||
}
|
||
if action.SkillEntity == nil {
|
||
return nil
|
||
}
|
||
|
||
originalSkill, _ := deepcopy.Anything(action.SkillEntity) //备份技能
|
||
originalSkill.(*info.SkillEntity).Accuracy = action.SkillEntity.Accuracy //拷贝后命中丢失
|
||
return originalSkill.(*info.SkillEntity)
|
||
}
|
||
|
||
// enterturn 处理战斗回合逻辑
|
||
// 回合有先手方和后手方,同时有攻击方和被攻击方
|
||
func (f *FightC) enterturn(firstAttack, secondAttack *action.SelectSkillAction) {
|
||
//双方首发精灵登场时,依挑战方机制:房主方先判定,挑战方后判定
|
||
//双方非首发精灵登场时,根据切换先后判定(看手速)
|
||
// 神罗、圣华登场时魂免,“登场时xx”等效果
|
||
//阿枫的效果也在这里判断
|
||
|
||
if f.closefight {
|
||
return
|
||
}
|
||
|
||
f.Broadcast(func(ff *input.Input) {
|
||
|
||
ff.EffectCache = make([]input.Effect, 0) //先把上一回合数据清空,但是应该把本身延续类效果集成过来
|
||
ff.EffectLost = make([]input.Effect, 0)
|
||
ff.Exec(func(effect input.Effect) bool { //回合开始前
|
||
effect.TurnStart(firstAttack, secondAttack)
|
||
return true
|
||
})
|
||
})
|
||
|
||
if firstAttack != nil { //如果首技能是空的,说明都空过了
|
||
if firstAttack.GetPlayerID() == f.ownerID {
|
||
//是否miss都应该施加解析effect
|
||
f.Our.Parseskill(firstAttack) //解析到临时数据
|
||
f.Opp.Parseskill(secondAttack) //解析到临时数据
|
||
} else {
|
||
f.Opp.Parseskill(firstAttack)
|
||
f.Our.Parseskill(secondAttack)
|
||
}
|
||
}
|
||
f.Broadcast(func(fighter *input.Input) {
|
||
fighter.Exec(func(effect input.Effect) bool { //回合开始前
|
||
effect.ComparePre(firstAttack, secondAttack) //先结算技能的优先级
|
||
return true
|
||
})
|
||
fighter.ResetAttackValue()
|
||
})
|
||
f.First, f.Second = f.Our, f.Opp
|
||
if firstAttack != nil {
|
||
if firstAttack.GetPlayerID() != f.ownerID {
|
||
f.First, f.Second = f.Opp, f.Our // 攻击方为对方时,主攻击方是对方
|
||
}
|
||
}
|
||
|
||
if firstAttack != nil && secondAttack != nil {
|
||
switch {
|
||
case firstAttack.SkillEntity.XML.Priority < secondAttack.SkillEntity.XML.Priority:
|
||
firstAttack, secondAttack = secondAttack, firstAttack //互换先手权
|
||
f.First, f.Second = f.Second, f.First
|
||
case firstAttack.SkillEntity.XML.Priority == secondAttack.SkillEntity.XML.Priority:
|
||
if f.Second.GetProp(4).Cmp(f.First.GetProp(4)) > 0 {
|
||
firstAttack, secondAttack = secondAttack, firstAttack //互换先手权
|
||
f.First, f.Second = f.Second, f.First
|
||
}
|
||
if f.Second.GetProp(4).Cmp(f.First.GetProp(4)) == 0 {
|
||
if grand.Meet(1, 2) { //随机出手
|
||
firstAttack, secondAttack = secondAttack, firstAttack //互换先手权
|
||
f.First, f.Second = f.Second, f.First
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if firstAttack == nil && secondAttack == nil {
|
||
firstAttack, secondAttack = secondAttack, firstAttack //互换先手权
|
||
f.First, f.Second = f.Second, f.First
|
||
}
|
||
var attacker, defender *input.Input
|
||
f.TrueFirst = f.First
|
||
//开始回合操作
|
||
for i := 0; i < 2; i++ {
|
||
var originalSkill *info.SkillEntity //原始技能
|
||
var currentSkill *info.SkillEntity //当前技能
|
||
if i == 0 {
|
||
attacker, defender = f.First, f.Second
|
||
originalSkill = f.copySkill(firstAttack)
|
||
//先手阶段,先修复后手效果
|
||
f.Second.RecoverEffect()
|
||
} else {
|
||
attacker, defender = f.Second, f.First
|
||
originalSkill = f.copySkill(secondAttack)
|
||
//取消后手历史效果
|
||
f.Second.ReactvieEffect()
|
||
}
|
||
|
||
currentSkill = originalSkill
|
||
defender.Exec(func(effect input.Effect) bool { //这个是能否使用技能
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
return effect.ActionStartEx(firstAttack, secondAttack)
|
||
})
|
||
canUseSkill := attacker.Exec(func(effect input.Effect) bool { //这个是能否使用技能
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
return effect.ActionStart(firstAttack, secondAttack)
|
||
})
|
||
|
||
canUse := canUseSkill && action.CanUse(currentSkill) && attacker.CurrentPet.Info.Hp > 0
|
||
|
||
if !canUse {
|
||
|
||
attacker.RecoverEffect()
|
||
currentSkill = nil
|
||
if i == 0 { //先手方被控,这时候应该算做未出手状态
|
||
f.TrueFirst = defender
|
||
for _, effect := range defender.EffectCache {
|
||
effect.IsFirst(true)
|
||
}
|
||
|
||
}
|
||
//先手权不一定出手
|
||
|
||
} else {
|
||
|
||
for _, effect := range attacker.EffectCache {
|
||
effect.IsFirst(true)
|
||
}
|
||
f.processSkillAttack(attacker, defender, currentSkill)
|
||
currentSkill = originalSkill //还原技能
|
||
|
||
_, skill, ok := utils.FindWithIndex(attacker.CurrentPet.Info.SkillList, func(item model.SkillInfo) bool {
|
||
return item.ID == currentSkill.Info.ID
|
||
})
|
||
if ok {
|
||
usecount := 1
|
||
attacker.Exec(func(effect input.Effect) bool { //技能使用后的我方效果
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
effect.HookPP(&usecount)
|
||
return true
|
||
})
|
||
skill.Use(usecount)
|
||
}
|
||
}
|
||
if defender.CurrentPet.Info.Hp > 0 {
|
||
//技能使用后
|
||
defender.Exec(func(effect input.Effect) bool { //技能使用后的我方效果
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
effect.Skill_Use_ex()
|
||
return true
|
||
})
|
||
}
|
||
|
||
if attacker.CurrentPet.Info.Hp > 0 {
|
||
//技能使用后
|
||
attacker.Exec(func(effect input.Effect) bool { //技能使用后的我方效果
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
effect.Skill_Use()
|
||
return true
|
||
})
|
||
}
|
||
//技能使用后
|
||
defender.Exec(func(effect input.Effect) bool { //技能使用后的我方效果
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
effect.Action_end_ex()
|
||
return true
|
||
})
|
||
//技能使用后
|
||
attacker.Exec(func(effect input.Effect) bool { //技能使用后的我方效果
|
||
effect.Ctx().SkillEntity = currentSkill
|
||
effect.Action_end()
|
||
return true
|
||
})
|
||
|
||
if defender.CurrentPet.Info.Hp <= 0 && attacker.CurrentPet.Info.Hp <= 0 { //先手方死亡,触发反同归于尽
|
||
attacker.CurrentPet.Info.Hp = 1
|
||
}
|
||
if defender.CurrentPet.Info.Hp <= 0 {
|
||
|
||
f.TURNOVER(defender)
|
||
|
||
break
|
||
}
|
||
if attacker.CurrentPet.Info.Hp <= 0 {
|
||
f.TURNOVER(attacker)
|
||
|
||
break
|
||
}
|
||
|
||
}
|
||
|
||
f.Broadcast(func(ff *input.Input) {
|
||
ff.GenSataus()
|
||
ff.Exec(func(t input.Effect) bool { //这个是能否使用技能
|
||
//结算状态
|
||
t.TurnEnd() //返回本身结算,如果false,说明不能使用技能了
|
||
return true
|
||
})
|
||
ff.GenInfo()
|
||
ff.SnapshotTurnProp()
|
||
})
|
||
if f.TrueFirst != f.First {
|
||
f.First, f.Second = f.Second, f.First
|
||
|
||
}
|
||
|
||
attackValueResult := info.AttackValueS{
|
||
FAttack: *f.First.AttackValue,
|
||
SAttack: *f.Second.AttackValue,
|
||
}
|
||
//因为切完才能广播,所以必须和回合结束分开结算
|
||
f.Broadcast(func(fighter *input.Input) {
|
||
for _, switchAction := range f.Switch {
|
||
if fighter.Player.GetInfo().UserID != switchAction.Reason.UserId {
|
||
// println("切精灵", switchAction.Reason.UserId, switchAction.Reason.ID)
|
||
fighter.Player.SendPackCmd(2407, &switchAction.Reason)
|
||
}
|
||
}
|
||
})
|
||
f.Switch = make(map[uint32]*action.ActiveSwitchAction)
|
||
if f.closefight && f.Info.Mode == info.BattleMode.PET_MELEE {
|
||
// f.Broadcast(func(fighter *input.Input) {
|
||
// if fighter.UserID != f.WinnerId {
|
||
// fighter.Player.SendPackCmd(2505, &attackValueResult)
|
||
// }
|
||
|
||
// })
|
||
return
|
||
}
|
||
f.Broadcast(func(fighter *input.Input) {
|
||
fighter.Player.SendPackCmd(2505, &attackValueResult)
|
||
fighter.CanChange = 0
|
||
})
|
||
if f.closefight {
|
||
return
|
||
}
|
||
|
||
}
|
||
func (f *FightC) TURNOVER(cur *input.Input) {
|
||
|
||
f.Broadcast(func(ff *input.Input) {
|
||
|
||
ff.Exec(func(t input.Effect) bool {
|
||
|
||
t.SwitchOut(cur)
|
||
|
||
return true
|
||
})
|
||
})
|
||
if f.IsWin(f.GetInputByPlayer(cur.Player, true)) { //然后检查是否战斗结束
|
||
|
||
f.FightOverInfo.WinnerId = f.GetInputByPlayer(cur.Player, true).UserID
|
||
|
||
f.closefight = true
|
||
// break
|
||
}
|
||
}
|