feat(fight): 优化战斗系统命中率计算和捕捉逻辑
- 新增 AI_player 结构体的 CanCapture 字段,用于判断是否可捕捉 - 优化 BattlePetEntity 的 Accuracy 方法,增加对负强化等级的处理 - 修改 BattleSkillEntity 的 AttackTime 方法,增加必中判断 - 更新 FightC 中的捕捉逻辑,支持 AI 玩家的捕捉判断 - 重构战斗流程中的技能攻击逻辑,优化命中率计算和效果执行
This commit is contained in:
@@ -7,9 +7,9 @@ import (
|
||||
)
|
||||
|
||||
type AI_player struct {
|
||||
FightC *FightC //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool
|
||||
petinfo []model.PetInfo //精灵信息
|
||||
|
||||
FightC *FightC //绑定战斗标识 替代本身的是否战斗标记 //IsFighting bool
|
||||
petinfo []model.PetInfo //精灵信息
|
||||
CanCapture bool
|
||||
}
|
||||
|
||||
func NewAI_player(m model.PetInfo) *AI_player {
|
||||
|
||||
@@ -67,3 +67,8 @@ func (this *EffectNode) GetArgSize() int {
|
||||
return this.ArgSize
|
||||
|
||||
}
|
||||
func (this *EffectNode) AttackTime() bool {
|
||||
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
@@ -59,9 +59,50 @@ func (a *BattlePetEntity) SDefense() uint32 {
|
||||
return uint32(calculateRealValue(int64(a.Info.SpecialDefence), int(a.Prop.SpecialDefence)))
|
||||
|
||||
}
|
||||
func (a *BattlePetEntity) Accuracy(b int64) uint32 {
|
||||
return uint32(calculateRealValue(b, int(a.Prop.Accuracy)))
|
||||
|
||||
// Accuracy 优化版命中率计算(用绝对值和正负判断处理等级)
|
||||
func (a *BattlePetEntity) Accuracy(b int64) uint32 {
|
||||
// 基础参数校验
|
||||
if b <= 0 {
|
||||
return 0
|
||||
}
|
||||
if b >= 100 {
|
||||
return 100
|
||||
}
|
||||
level := a.Prop.Accuracy
|
||||
if level > 6 || level == 0 { //强化等级
|
||||
return uint32(calculateRealValue(int64(b), int(a.Prop.Accuracy)))
|
||||
}
|
||||
var temp float64
|
||||
switch level {
|
||||
case -1:
|
||||
temp = 0.85
|
||||
case -2:
|
||||
temp = 0.7
|
||||
case -3:
|
||||
temp = 0.55
|
||||
case -4:
|
||||
temp = 0.45
|
||||
case -5:
|
||||
temp = 0.35
|
||||
case -6:
|
||||
temp = 0.25
|
||||
|
||||
}
|
||||
return uint32(
|
||||
decimal.NewFromInt(int64(b)). // 将b转为decimal类型
|
||||
Mul(decimal.NewFromFloat(temp)). // 精确乘以0.85
|
||||
Round(0). // 四舍五入到整数
|
||||
IntPart(), // 转为int64
|
||||
)
|
||||
}
|
||||
|
||||
// 辅助函数:取整数绝对值(处理负等级)
|
||||
func abs(x int8) int8 {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
type BattlePetEntity struct {
|
||||
|
||||
@@ -164,6 +164,9 @@ var DamageC = enum.New[struct {
|
||||
|
||||
// 计算是否命中
|
||||
func (s *BattleSkillEntity) AttackTime() uint32 {
|
||||
if s.MustHit != 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
if int64(s.Pet.Accuracy(int64(s.Accuracy))) > s.Rand.Int63n(100) {
|
||||
return 1
|
||||
|
||||
@@ -91,48 +91,48 @@ type AttackValue struct {
|
||||
}
|
||||
|
||||
type WeakenedS struct {
|
||||
Stack byte `struc:"skip"`
|
||||
Round byte
|
||||
Stack int8 `struc:"skip"`
|
||||
Round int8
|
||||
}
|
||||
type StatusDict struct {
|
||||
Paralysis_0 byte // 0: 麻痹
|
||||
Poisoned_1 byte // 1: 中毒
|
||||
Burned_2 byte // 2: 烧伤
|
||||
DrainHP_3 byte // 3: 吸取对方的体力
|
||||
DrainedHP_4 byte // 4: 被对方吸取体力
|
||||
Frozen_5 byte // 5: 冻伤
|
||||
Fear_6 byte // 6: 害怕
|
||||
Tired_7 byte // 7: 疲惫
|
||||
Sleep_8 byte // 8: 睡眠
|
||||
Petrified_9 byte // 9: 石化
|
||||
Confused_10 byte // 10: 混乱
|
||||
Paralysis_0 int8 // 0: 麻痹
|
||||
Poisoned_1 int8 // 1: 中毒
|
||||
Burned_2 int8 // 2: 烧伤
|
||||
DrainHP_3 int8 // 3: 吸取对方的体力
|
||||
DrainedHP_4 int8 // 4: 被对方吸取体力
|
||||
Frozen_5 int8 // 5: 冻伤
|
||||
Fear_6 int8 // 6: 害怕
|
||||
Tired_7 int8 // 7: 疲惫
|
||||
Sleep_8 int8 // 8: 睡眠
|
||||
Petrified_9 int8 // 9: 石化
|
||||
Confused_10 int8 // 10: 混乱
|
||||
Weakened_11 WeakenedS // 11: 衰弱
|
||||
MountainGodGuard_12 byte // 12: 山神守护
|
||||
Flammable_13 byte // 13: 易燃
|
||||
Berserk_14 byte // 14: 狂暴
|
||||
IceBound_15 byte // 15: 冰封
|
||||
Bleeding_16 byte // 16: 流血
|
||||
ImmuneToStatDrop_17 byte // 17: 免疫能力下降
|
||||
ImmuneToAbnormal_18 byte // 18: 免疫异常状态
|
||||
Paralyzed_19 byte // 19: 瘫痪
|
||||
MountainGodGuard_12 int8 // 12: 山神守护
|
||||
Flammable_13 int8 // 13: 易燃
|
||||
Berserk_14 int8 // 14: 狂暴
|
||||
IceBound_15 int8 // 15: 冰封
|
||||
Bleeding_16 int8 // 16: 流血
|
||||
ImmuneToStatDrop_17 int8 // 17: 免疫能力下降
|
||||
ImmuneToAbnormal_18 int8 // 18: 免疫异常状态
|
||||
Paralyzed_19 int8 // 19: 瘫痪
|
||||
//Blind_20 byte // 20: 失明
|
||||
}
|
||||
|
||||
// 精灵的能力提升
|
||||
type PropDict struct {
|
||||
// 攻击(@UInt long → uint32)
|
||||
Attack byte
|
||||
Attack int8
|
||||
// 防御(@UInt long → uint32)
|
||||
Defence byte
|
||||
Defence int8
|
||||
// 特攻(@UInt long → uint32)
|
||||
SpecialAttack byte
|
||||
SpecialAttack int8
|
||||
// 特防(@UInt long → uint32)
|
||||
SpecialDefence byte
|
||||
SpecialDefence int8
|
||||
|
||||
// 速度(@UInt long → uint32)
|
||||
Speed byte
|
||||
Speed int8
|
||||
// 命中(@UInt long → uint32)
|
||||
Accuracy byte
|
||||
Accuracy int8
|
||||
}
|
||||
|
||||
// BattleLevels 战斗属性等级结构体,对应原6字节数组
|
||||
|
||||
@@ -19,9 +19,9 @@ type Effect interface {
|
||||
OnDamage() bool // 造成伤害时触发
|
||||
SetArgs(param []int) //设置参数
|
||||
|
||||
Shield() bool // 护盾值变化时触发
|
||||
PostDamage() bool // 伤害结算后触发(血量扣除后)
|
||||
|
||||
Shield() bool // 护盾值变化时触发
|
||||
PostDamage() bool // 伤害结算后触发(血量扣除后)
|
||||
AttackTime() bool //闪避率计算,,实际上是修改命中的判断
|
||||
OnCritPostDamage() bool // 暴击伤害结算后触发
|
||||
|
||||
OnHit() bool // 技能命中时触发
|
||||
|
||||
@@ -175,6 +175,9 @@ func (f *FightC) ReadyFight(c PlayerI) {
|
||||
//判断捕捉率大于0
|
||||
if gconv.Int(xmlres.PetMAP[int(f.Info.OpponentPetList[0].ID)].CatchRate) > 0 {
|
||||
rett.Info2.Catchable = 1
|
||||
t, _ := f.Opp.Player.(*AI_player)
|
||||
t.CanCapture = true
|
||||
|
||||
}
|
||||
|
||||
rrsult()
|
||||
@@ -347,12 +350,19 @@ func (f *FightC) battleLoop() {
|
||||
f.Broadcast(func(ff *Input) {
|
||||
//todo 将血量和技能pp传回enterturn
|
||||
tt, ok := ff.Player.(*Player)
|
||||
if ok {
|
||||
tt.Service.PetAdd(*f.Opp.CurrentPet.Info)
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{
|
||||
CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime),
|
||||
PetId: uint32(f.Opp.CurrentPet.ID),
|
||||
})
|
||||
mo, ism := f.Opp.Player.(*AI_player)
|
||||
|
||||
if ok { //如果获取玩家
|
||||
|
||||
if ism && mo.CanCapture { //如果获取到IA
|
||||
tt.Service.PetAdd(*f.Opp.CurrentPet.Info)
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{
|
||||
CatchTime: uint32(f.Opp.CurrentPet.Info.CatchTime),
|
||||
PetId: uint32(f.Opp.CurrentPet.ID),
|
||||
})
|
||||
} else { //说明不是可以捕捉的
|
||||
tt.CatchPetInfo(info.CatchMonsterOutboundInfo{})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -483,49 +493,64 @@ func (f *FightC) initAttackers(fattack, sattack info.BattleActionI) {
|
||||
|
||||
// 处理技能攻击逻辑
|
||||
func (f *FightC) processSkillAttack(attacker, defender *BPET, skill *info.SelectSkillAction) {
|
||||
f.parseskill(skill)
|
||||
spower := skill.Skill.CalculatePower(defender.BattlePetEntity)
|
||||
attacker.Damage = spower
|
||||
|
||||
f.parseskill(skill) //解析effect
|
||||
// 记录技能信息
|
||||
attacker.AttackValue.SkillID = uint32(skill.Skill.ID)
|
||||
attacker.AttackValue.AttackTime = skill.Skill.AttackTime()
|
||||
attacker.AttackValue.SkillID = uint32(skill.Skill.ID) //获取技能ID
|
||||
attacker.AttackValue.AttackTime = skill.Skill.AttackTime() //计算命中
|
||||
|
||||
CritRate := utils.Max(skill.Skill.CritRate, 1)
|
||||
CritRateR := f.rand.Int31n(16)
|
||||
//CritAtkFirst: 先出手时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritAtkFirst != 0 && attacker == f.First {
|
||||
CritRate = 16
|
||||
}
|
||||
//CritAtkSecond: 后出手时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritAtkSecond != 0 && attacker != f.First {
|
||||
CritRate = 16
|
||||
}
|
||||
// CritSelfHalfHp: 自身体力低于一半时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritSelfHalfHp != 0 && (attacker.CurrentPet.HP < int(attacker.CurrentPet.Info.MaxHp)/2) {
|
||||
CritRate = 16
|
||||
}
|
||||
// CritFoeHalfHp: 对方体力低于一半时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritSelfHalfHp != 0 && (defender.CurrentPet.HP < int(defender.CurrentPet.Info.MaxHp)/2) {
|
||||
CritRate = 16
|
||||
}
|
||||
f.EffectS.Exec(func(t info.Effect) bool { //计算闪避 闪避就是命中率重新计算的结果
|
||||
//闪避本质上是算对方的命中重写函数?
|
||||
|
||||
//todo 暴击伤害
|
||||
if CritRateR <= int32(CritRate) {
|
||||
attacker.AttackValue.IsCritical = 1
|
||||
}
|
||||
if attacker.UserID == f.Our.Player.ID() {
|
||||
|
||||
if attacker.AttackValue.IsCritical == 1 {
|
||||
attacker.Damage.Mul(decimal.NewFromInt(2)) //暴击翻倍
|
||||
}
|
||||
}
|
||||
if !t.GetOwner() { //先获取对方的
|
||||
return t.AttackTime()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if uint32(attacker.Damage.IntPart()) > defender.CurrentPet.Info.Hp {
|
||||
defender.CurrentPet.Info.Hp = 0
|
||||
} else {
|
||||
defender.CurrentPet.Info.Hp = defender.CurrentPet.Info.Hp - uint32(attacker.Damage.IntPart())
|
||||
}
|
||||
if attacker.AttackValue.AttackTime == 1 { //如果命中
|
||||
|
||||
// 扣减防御方血量
|
||||
spower := skill.Skill.CalculatePower(defender.BattlePetEntity)
|
||||
attacker.Damage = spower
|
||||
CritRate := utils.Max(skill.Skill.CritRate, 1)
|
||||
CritRateR := f.rand.Int31n(16)
|
||||
//CritAtkFirst: 先出手时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritAtkFirst != 0 && attacker == f.First {
|
||||
CritRate = 16
|
||||
}
|
||||
//CritAtkSecond: 后出手时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritAtkSecond != 0 && attacker != f.First {
|
||||
CritRate = 16
|
||||
}
|
||||
// CritSelfHalfHp: 自身体力低于一半时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritSelfHalfHp != 0 && (attacker.CurrentPet.HP < int(attacker.CurrentPet.Info.MaxHp)/2) {
|
||||
CritRate = 16
|
||||
}
|
||||
// CritFoeHalfHp: 对方体力低于一半时必定致命一击; 默认: 0
|
||||
if skill.Skill.CritSelfHalfHp != 0 && (defender.CurrentPet.HP < int(defender.CurrentPet.Info.MaxHp)/2) {
|
||||
CritRate = 16
|
||||
}
|
||||
|
||||
//todo 暴击伤害
|
||||
if CritRateR <= int32(CritRate) {
|
||||
attacker.AttackValue.IsCritical = 1
|
||||
}
|
||||
|
||||
if attacker.AttackValue.IsCritical == 1 {
|
||||
attacker.Damage.Mul(decimal.NewFromInt(2)) //暴击翻倍
|
||||
}
|
||||
|
||||
if uint32(attacker.Damage.IntPart()) > defender.CurrentPet.Info.Hp {
|
||||
defender.CurrentPet.Info.Hp = 0
|
||||
} else {
|
||||
defender.CurrentPet.Info.Hp = defender.CurrentPet.Info.Hp - uint32(attacker.Damage.IntPart())
|
||||
}
|
||||
|
||||
// 扣减防御方血量
|
||||
} //todo 处理未命中效果
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user