refactor(fight): 重构战斗准备逻辑并优化战斗启动流程

将 ReadyFight 方法拆分为多个职责清晰的子方法:
- buildFightStartInfo: 构建战斗初始信息
- checkBothPlayersReady: 检查PVP双方是否就绪
- handleNPCFightSpecial: 处理NPC战斗特殊逻辑(如可捕捉标记)
- startBattle: 统一启动战斗流程

同时修复部分逻辑顺序问题,增强代码可读性和扩展性。

feat(fight): 新增精灵王挑战协议支持

增加 StartPetWarInboundInfo 结构体用于接收精灵王挑战请求,
为后续实现相关功能提供基础。

fix(effect): 修正多个技能效果数值引用错误

- effect_37: 技能威力计算使用正确参数索引
- effect_50: 固定减伤比例调整为除以2
- effect_65: 正确比较技能分类类型
- effect_68: 致死保护改为锁定剩余1点生命值
- effect_77: 回复目标由敌方改为己方
- effect_93: 固定伤害值直接取参数

refactor(effect): 移除冗余效果类文件

删除 effect_133.go 和 effect_90.go 文件,其功能已被统一条件伤害和倍率系统取代;
移除 effect_74.go、effect_75.go 中重复的状态随机施加逻辑。

refactor(effect): 更新能力操作枚举命名一致性

重命名 AbilityOpType 枚举项名称,去除前缀,提升语义清晰度:
- AbilityOpStealStrengthen → StealStrengthen
- AbilityOpReverse → Reverse
- AbilityOpBounceWeaken → BounceWeaken

chore(fight): 完善 BattlePetEntity 属性初始化逻辑

在创建 BattlePetEntity 时即设置 PType,避免后续多次查询 PetMAP;
移除 Type() 方法中的冗余配置查找逻辑。

fix(skill): 确保必中技能不参与命中率计算

在 AttackTimeC 方法中添加 return 防止必中技能继续执行命中率公式计算。

refactor(fight): 调整战斗回合结束逻辑

进入新回合时允许玩家更换精灵,并提前跳出循环防止多余处理。

style(effect): 更正拼写及变量命名风格

修改 BaseSataus.Switch 方法签名中的参数命名;
更正 Effect58 中 can 字段首字母大写;
This commit is contained in:
2025-11-14 23:09:16 +08:00
parent efa7ad6f76
commit a86782b1ea
34 changed files with 808 additions and 676 deletions

View File

@@ -1,205 +0,0 @@
package controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/logic/service/player"
"blazing/modules/blazing/model"
"github.com/gogf/gf/v2/util/gconv"
)
// 挑战地图boss
func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
var petid int
var mo *model.PetInfo
moinfo := &model.PlayerInfo{}
if c.Info.MapID == 515 && data.BossId == 0 { //说明是新手,随机生成
switch c.Info.PetList[0].ID {
case 1:
petid = 4
case 7:
petid = 1
case 4:
petid = 7
}
mo = c.GenPetInfo(
int(petid), 24, //24个体
-1,
0, //野怪没特性
0,
50)
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
moinfo.PetList = append(moinfo.PetList, *mo)
} else {
mdata, ok := xmlres.MonsterMap[int(c.Info.MapID)]
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if len(mdata.Bosses) == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
for _, bc := range mdata.Bosses {
if bc.Id == nil {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if uint32(*bc.Id) == data.BossId {
for _, bm := range bc.BossMon {
mo = c.GenPetInfo(
gconv.Int(bm.MonID), 24, //24个体
-1,
0, //野怪没特性
0,
bm.Lv)
// mo.Level = uint32(bm.Lv)
mo.CalculatePetPane()
mo.Hp = uint32(bm.Hp)
mo.MaxHp = uint32(bm.Hp)
moinfo.PetList = append(moinfo.PetList, *mo)
}
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
break
}
}
}
ai := player.NewAI_player(moinfo)
fight.NewFight(info.BattleMode.MULTI_MODE, info.BattleStatus.FIGHT_WITH_BOSS, c, ai)
return nil, -1
}
// 战斗野怪
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
refpet := c.OgreInfo.Data[data.Number]
if refpet.Id == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
mo := c.GenPetInfo(
int(refpet.Id), -1,
-1,
0, //野怪没特性
int(refpet.Shiny),
int(refpet.Lv))
moinfo := &model.PlayerInfo{}
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
moinfo.PetList = append(moinfo.PetList, *mo)
ai := player.NewAI_player(moinfo)
fight.NewFight(info.BattleMode.MULTI_MODE, info.BattleStatus.FIGHT_WITH_NPC, c, ai)
return nil, -1
}
// 准备战斗
func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.FightC.ReadyFight(c)
return nil, -1
}
// 接收战斗或者取消战斗的包
func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if ok, p1 := c.AgreeBattle(data.UserID, data.Flag, data.Mode); ok {
fight.NewFight(data.Mode, info.BattleStatus.FIGHT_WITH_PLAYER, c, p1) ///开始对战,房主方以及被邀请方
}
return nil, -1
}
// 邀请其他人进行战斗
func (h Controller) OnPlayerInviteOtherFight(data *fight.InviteToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
c.InvitePlayerToBattle(&info.PVPinfo{PlayerID: data.UserID, Mode: data.Mode})
return nil, 0
}
// 取消和他人战斗
func (h Controller) OnPlayerCanceledOtherInviteFight(data *fight.InviteFightCancelInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.CancelBattle()
return nil, 0
}
// 使用技能包
func (h Controller) UseSkill(data *fight.UseSkillInInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.UseSkill(c, int32(data.SkillId))
}
return nil, 0
}
// 战斗逃跑
func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC == nil {
return nil, 0
}
if !c.FightC.CanEscape() {
return nil, 0
}
c.FightC.Over(c, info.BattleOverReason.PlayerEscape)
return nil, 0
}
// 切换精灵
func (h Controller) ChangePet(data *fight.ChangePetInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.ChangePet(c, data.CatchTime)
}
return nil, -1
}
// 切换精灵
func (h Controller) Capture(data *fight.CatchMonsterInboundInfo, c *player.Player) (result *info.CatchMonsterOutboundInfo, err errorcode.ErrorCode) {
c.FightC.Capture(c, data.CapsuleId)
return nil, -1
}
// 加载进度
func (h Controller) LoadPercent(data *fight.LoadPercentInboundInfo, c *player.Player) (result *info.LoadPercentOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.LoadPercent(c, int32(data.Percent))
}
return nil, -1
}
func (h Controller) UsePetItemInboundInfo(data *fight.UsePetItemInboundInfo, c *player.Player) (result *info.UsePetIteminfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.UseItem(c, data.CatchTime, data.ItemId)
}
return nil, -1
}

View File

@@ -0,0 +1,72 @@
package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/logic/service/player"
)
// 准备战斗
func (h Controller) OnReadyToFight(data *fight.ReadyToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.FightC.ReadyFight(c)
return nil, -1
}
// 使用技能包
func (h Controller) UseSkill(data *fight.UseSkillInInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.UseSkill(c, int32(data.SkillId))
}
return nil, 0
}
// 战斗逃跑
func (h Controller) Escape(data *fight.EscapeFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC == nil {
return nil, 0
}
if !c.FightC.CanEscape() {
return nil, 0
}
c.FightC.Over(c, info.BattleOverReason.PlayerEscape)
return nil, 0
}
// 切换精灵
func (h Controller) ChangePet(data *fight.ChangePetInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.ChangePet(c, data.CatchTime)
}
return nil, -1
}
// 切换精灵
func (h Controller) Capture(data *fight.CatchMonsterInboundInfo, c *player.Player) (result *info.CatchMonsterOutboundInfo, err errorcode.ErrorCode) {
c.FightC.Capture(c, data.CapsuleId)
return nil, -1
}
// 加载进度
func (h Controller) LoadPercent(data *fight.LoadPercentInboundInfo, c *player.Player) (result *info.LoadPercentOutboundInfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.LoadPercent(c, int32(data.Percent))
}
return nil, -1
}
func (h Controller) UsePetItemInboundInfo(data *fight.UsePetItemInboundInfo, c *player.Player) (result *info.UsePetIteminfo, err errorcode.ErrorCode) {
if c.FightC != nil {
c.FightC.UseItem(c, data.CatchTime, data.ItemId)
}
return nil, -1
}

View File

@@ -0,0 +1,114 @@
package controller
import (
"blazing/common/data/xmlres"
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/logic/service/player"
"blazing/modules/blazing/model"
"github.com/gogf/gf/v2/util/gconv"
)
// 挑战地图boss
func (h Controller) PlayerFightBoss(data *fight.ChallengeBossInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
var petid int
var mo *model.PetInfo
moinfo := &model.PlayerInfo{}
if c.Info.MapID == 515 && data.BossId == 0 { //说明是新手,随机生成
switch c.Info.PetList[0].ID {
case 1:
petid = 4
case 7:
petid = 1
case 4:
petid = 7
}
mo = c.GenPetInfo(
int(petid), 24, //24个体
-1,
0, //野怪没特性
0,
50)
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
moinfo.PetList = append(moinfo.PetList, *mo)
} else {
mdata, ok := xmlres.MonsterMap[int(c.Info.MapID)]
if !ok {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if len(mdata.Bosses) == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
for _, bc := range mdata.Bosses {
if bc.Id == nil {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
if uint32(*bc.Id) == data.BossId {
for _, bm := range bc.BossMon {
mo = c.GenPetInfo(
gconv.Int(bm.MonID), 24, //24个体
-1,
0, //野怪没特性
0,
bm.Lv)
// mo.Level = uint32(bm.Lv)
mo.CalculatePetPane()
mo.Hp = uint32(bm.Hp)
mo.MaxHp = uint32(bm.Hp)
moinfo.PetList = append(moinfo.PetList, *mo)
}
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
break
}
}
}
ai := player.NewAI_player(moinfo)
fight.NewFight(info.BattleMode.MULTI_MODE, info.BattleStatus.FIGHT_WITH_BOSS, c, ai)
return nil, -1
}
// 战斗野怪
func (h Controller) OnPlayerFightNpcMonster(data *fight.FightNpcMonsterInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
refpet := c.OgreInfo.Data[data.Number]
if refpet.Id == 0 {
return nil, errorcode.ErrorCodes.ErrPokemonNotExists
}
mo := c.GenPetInfo(
int(refpet.Id), -1,
-1,
0, //野怪没特性
int(refpet.Shiny),
int(refpet.Lv))
moinfo := &model.PlayerInfo{}
moinfo.Nick = xmlres.PetMAP[int(mo.ID)].DefName
moinfo.PetList = append(moinfo.PetList, *mo)
ai := player.NewAI_player(moinfo)
fight.NewFight(info.BattleMode.MULTI_MODE, info.BattleStatus.FIGHT_WITH_NPC, c, ai)
return nil, -1
}

View File

@@ -0,0 +1,16 @@
package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/player"
)
//精灵王之战
func (h Controller) PvpKingFight(data *fight.StartPetWarInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
return
}

View File

@@ -0,0 +1,41 @@
package controller
import (
"blazing/common/socket/errorcode"
"blazing/logic/service/fight"
"blazing/logic/service/fight/info"
"blazing/logic/service/player"
)
// 接收战斗或者取消战斗的包
func (h Controller) OnPlayerHandleFightInvite(data *fight.HandleFightInviteInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if ok, p1 := c.AgreeBattle(data.UserID, data.Flag, data.Mode); ok {
fight.NewFight(data.Mode, info.BattleStatus.FIGHT_WITH_PLAYER, p1, c) ///开始对战,房主方以及被邀请方
}
return nil, -1
}
// 邀请其他人进行战斗
func (h Controller) OnPlayerInviteOtherFight(data *fight.InviteToFightInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
if !c.CanFight() {
return nil, errorcode.ErrorCodes.ErrPokemonNotEligible
}
//进入邀请,以及确认对战模式
c.PVPinfo = &info.PVPinfo{PlayerID: data.UserID,
Mode: data.Mode,
Status: info.BattleStatus.FIGHT_WITH_PLAYER}
c.InvitePlayerToBattle()
return nil, 0
}
// 取消和他人战斗
func (h Controller) OnPlayerCanceledOtherInviteFight(data *fight.InviteFightCancelInboundInfo, c *player.Player) (result *fight.NullOutboundInfo, err errorcode.ErrorCode) {
c.CancelBattle()
return nil, 0
}

View File

@@ -9,6 +9,7 @@ import (
"blazing/logic/service/fight/input"
"blazing/logic/service/player"
"context"
"log"
"github.com/gogf/gf/v2/util/gconv"
"github.com/jinzhu/copier"
@@ -136,57 +137,92 @@ func (f *FightC) UseItem(c common.PlayerI, cacthid, itemid uint32) {
f.actionChan <- &action.UseItemAction{BaseAction: action.NewBaseAction(c.GetInfo().UserID), ItemID: itemid, CacthTime: cacthid}
}
// 战斗准备
// ReadyFight 处理玩家战斗准备逻辑,当满足条件时启动战斗循环
func (f *FightC) ReadyFight(c common.PlayerI) {
// 1. 构建战斗开始信息(整理双方初始宠物信息)
fightStartInfo := f.buildFightStartInfo()
rett := info.FightStartOutboundInfo{}
// 2. 标记当前玩家已准备完成
input := f.GetInputByPlayer(c, false)
input.Finished = true
copier.Copy(&rett.Info1, &f.Info.OurPetList[0]) // 复制自己的信息
copier.Copy(&rett.Info2, &f.Info.OpponentPetList[0])
rett.Info1.UserID = f.Info.OurInfo.UserID //
rett.Info2.UserID = f.Info.OpponentInfo.UserID
rrsult := func() { //传回函数
// i := Fightpool.Free()
// if i <= 0 {
// Fightpool.Tune(Fightpool.Cap() + 1)
// cool.Loger.Error(context.Background(), "Fightpool is full")
// }
rr := Fightpool.Submit(f.battleLoop)
if rr != nil {
panic(rr)
}
f.Our.Player.SendReadyToFightInfo(rett)
f.Opp.Player.SendReadyToFightInfo(rett)
//f.runing = true
//然后开始战斗循环
}
f.GetInputByPlayer(c, false).Finished = true
// 3. 根据战斗类型判断是否满足战斗启动条件,满足则启动
switch f.Info.Status {
case info.BattleStatus.FIGHT_WITH_PLAYER: //pvp
if f.GetInputByPlayer(c, true).Finished {
rrsult()
case info.BattleStatus.FIGHT_WITH_PLAYER: // PVP战斗需双方都准备完成
if f.checkBothPlayersReady(c) {
f.startBattle(fightStartInfo)
}
case info.BattleStatus.FIGHT_WITH_BOSS: // 6v6
rrsult()
case info.BattleStatus.FIGHT_WITH_NPC: // 野怪战斗
if gconv.Int(xmlres.PetMAP[int(f.Info.OpponentPetList[0].ID)].CatchRate) > 0 {
rett.Info2.Catchable = 1
t, _ := f.Opp.Player.(*player.AI_player)
t.CanCapture = true
}
rrsult()
case info.BattleStatus.FIGHT_WITH_BOSS: // BOSS战单方准备完成即可启动
f.startBattle(fightStartInfo)
case info.BattleStatus.FIGHT_WITH_NPC: // NPC/野怪战斗:处理捕捉相关逻辑后启动
f.handleNPCFightSpecial(&fightStartInfo)
f.startBattle(fightStartInfo)
}
}
// buildFightStartInfo 构建战斗开始时需要发送给双方的信息
func (f *FightC) buildFightStartInfo() info.FightStartOutboundInfo {
var startInfo info.FightStartOutboundInfo
// 复制双方初始宠物信息(取列表第一个宠物)
if len(f.Info.OurPetList) > 0 {
_ = copier.Copy(&startInfo.Info1, &f.Info.OurPetList[0])
startInfo.Info1.UserID = f.Info.OurInfo.UserID
}
if len(f.Info.OpponentPetList) > 0 {
_ = copier.Copy(&startInfo.Info2, &f.Info.OpponentPetList[0])
startInfo.Info2.UserID = f.Info.OpponentInfo.UserID
}
return startInfo
}
// checkBothPlayersReady 检查PVP战斗中双方是否都已准备完成
// 参数c为当前准备的玩家返回true表示双方均准备完成
func (f *FightC) checkBothPlayersReady(currentPlayer common.PlayerI) bool {
// 这里的第二个参数true含义需结合业务确认推测为"检查对手"),建议用常量替代
opponentInput := f.GetInputByPlayer(currentPlayer, true)
return opponentInput.Finished
}
// handleNPCFightSpecial 处理NPC战斗的特殊逻辑如可捕捉标记
func (f *FightC) handleNPCFightSpecial(startInfo *info.FightStartOutboundInfo) {
// 检查野怪是否可捕捉根据宠物ID获取捕捉率
if len(f.Info.OpponentPetList) == 0 {
return
}
npcPetID := int(f.Info.OpponentPetList[0].ID)
petCfg, ok := xmlres.PetMAP[npcPetID]
if !ok {
// log.Error(context.Background(), "NPC宠物配置不存在", "petID", npcPetID)
return
}
catchRate := gconv.Int(petCfg.CatchRate)
if catchRate > 0 {
startInfo.Info2.Catchable = 1 // 标记为可捕捉
// 标记AI对手允许被捕捉类型断言确保安全
if oppAI, ok := f.Opp.Player.(*player.AI_player); ok {
oppAI.CanCapture = true
}
}
}
// startBattle 启动战斗核心逻辑:提交战斗循环任务并通知双方
func (f *FightC) startBattle(startInfo info.FightStartOutboundInfo) {
// 提交战斗循环到战斗池(处理战斗池容量问题)
if err := Fightpool.Submit(f.battleLoop); err != nil {
log.Panic(context.Background(), "战斗循环提交失败", "error", err)
}
// 通知双方玩家准备完成,即将开始战斗
f.Our.Player.SendReadyToFightInfo(startInfo)
f.Opp.Player.SendReadyToFightInfo(startInfo)
// 标记战斗已启动(原注释逻辑)
// f.running = true
}
var Fightpool *ants.Pool
func init() {

View File

@@ -30,6 +30,11 @@ type EscapeFightInboundInfo struct {
Head player.TomeeHeader `cmd:"2410" struc:"[0]pad"`
}
// 精灵王
type StartPetWarInboundInfo struct {
Head player.TomeeHeader `cmd:"2431" struc:"[0]pad"`
}
// HandleFightInviteInboundInfo 处理战斗邀请的入站消息
type HandleFightInviteInboundInfo struct {
@@ -45,7 +50,6 @@ type InviteToFightInboundInfo struct {
UserID uint32 `codec:"true"`
// Mode 战斗类型 1 = 1v1 2 = 6v6
Mode info.EnumBattleMode `codec:"true"`
}
type InviteFightCancelInboundInfo struct {

View File

@@ -17,7 +17,7 @@ func (e *Effect37) Skill_Hit() bool {
cmphp := e.GetInput().CurrentPet.GetMaxHP().Div(decimal.NewFromInt(int64(e.Args()[0])))
if e.GetInput().CurrentPet.GetHP().Cmp(cmphp) == -1 {
e.Ctx().SkillEntity.Power *= e.Args()[0]
e.Ctx().SkillEntity.Power *= e.Args()[1]
}
return true
}

View File

@@ -8,7 +8,7 @@ import (
"github.com/shopspring/decimal"
)
// "可完全抵挡n次攻击伤害 百分百减伤 ,后面还有锁伤
// 可以抵挡n点伤害
// ---- Effect49 ----
type Effect49 struct {
node.EffectNode
@@ -37,9 +37,7 @@ func (e *Effect49) Damage_SUB_ex(t *info.DamageZone) bool {
}
func (e *Effect49) SetArgs(t *input.Input, a ...int) {
//e.CanStack(-1)//后续的不会顶掉这个效果
e.EffectNode.SetArgs(t, a...)
//e.Duration(-1) //次数类,无限回合
}

View File

@@ -29,7 +29,7 @@ func (e *Effect50) Damage_DIV_ex(t *info.DamageZone) bool {
//fmt.Println("Effect50_o", t.Damage)
if t.Type == info.DamageType.Red {
t.Damage = t.Damage.Div(decimal.NewFromInt(int64(e.Args()[1])))
t.Damage = t.Damage.Div(decimal.NewFromInt(2))
}
//fmt.Println("Effect50_n", t.Damage)

View File

@@ -0,0 +1,48 @@
package effect
import (
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* n回合若本方先手攻击: 使得技能miss (但MustHit有效)
*/
func init() {
t := &Effect52{
EffectNode: node.EffectNode{},
}
// t.Duration(-1) //设置成无限回合,到回合数就停止
input.InitEffect(input.EffectType.Skill, 52, t)
}
type Effect52 struct {
node.EffectNode
}
// 默认添加回合
func (e *Effect52) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[0])
}
func (e *Effect52) Skill_Hit_ex() bool {
//fmt.Println(e.Ctx().SkillEntity)
if e.Ctx().SkillEntity == nil {
return true
}
if !e.Input.FightC.IsFirst(e.Ctx().Our.Player) {
return true
}
if e.Ctx().SkillEntity.AttackTime == 1 {
e.Ctx().SkillEntity.AttackTime = 0
}
return true
}

View File

@@ -28,7 +28,7 @@ func (e *Effect90) Damage_Mul(t *info.DamageZone) bool {
if t.Type == info.DamageType.Red {
e.Ctx().Our.DamageZone.Damage = e.Ctx().Our.DamageZone.Damage.Mul(decimal.NewFromInt(int64(e.SideEffectArgs[1])))
t.Damage = t.Damage.Mul(decimal.NewFromInt(int64(e.SideEffectArgs[1])))
}

View File

@@ -18,14 +18,14 @@ func init() {
type Effect58 struct {
node.EffectNode
can bool
Can bool
}
func (e *Effect58) OnSkill() bool {
if !e.Hit() {
return true
}
e.can = true
e.Can = true
return true
}
@@ -34,7 +34,7 @@ func (e *Effect58) Skill_Hit_Pre(a, b *action.SelectSkillAction) bool {
if !e.Hit() {
return true
}
if !e.can {
if !e.Can {
return true
}
//fmt.Println(e.Ctx().SkillEntity)

View File

@@ -26,7 +26,7 @@ func (e *Effect65) Skill_Hit() bool {
return true
}
if e.Ctx().SkillEntity.Category() != info.EnumCategory(e.Args()[1]) {
if info.EnumCategory(e.Ctx().SkillEntity.Move.Type) != info.EnumCategory(e.Args()[1]) {
return true
}
//技能威力=【165-65*【当前体力百分比】】,任意体力百分比对应的威力浮动范围∈[-10+10]

View File

@@ -4,6 +4,8 @@ import (
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
"github.com/shopspring/decimal"
)
// 1回合内受到致死攻击时则余下1点体力
@@ -13,7 +15,7 @@ type Effect68 struct {
StatusID int
}
func (e *Effect68) Skill_Use_ex() bool {
func (e *Effect68) Damage_Lock_ex(t *info.DamageZone) bool {
if !e.Hit() {
return true
}
@@ -26,19 +28,13 @@ func (e *Effect68) Skill_Use_ex() bool {
//fmt.Println("Effect68_o", t.Damage)
//伤害溢出
if e.Ctx().Opp.DamageZone.Damage.Cmp(e.Ctx().Our.CurrentPet.GetHP()) == 1 {
e.Ctx().Our.CurrentPet.Info.Hp = 1
if t.Type == info.DamageType.Red && t.Damage.Cmp(e.Ctx().Our.CurrentPet.GetHP()) == 1 {
//e.Ctx().Our.CurrentPet.Info.Hp = 1
t.Damage = e.Ctx().Our.CurrentPet.GetHP().Sub(decimal.NewFromInt(1))
}
//fmt.Println("Effect68_n", t.Damage)
return true
}
func (e *Effect68) SetArgs(t *input.Input, a ...int) {
e.EffectNode.SetArgs(t, a...)
e.EffectNode.Duration(e.EffectNode.SideEffectArgs[1])
}
// ---- 注册所有效果 ----
func init() {

View File

@@ -1,6 +1,7 @@
package effect
import (
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
@@ -18,7 +19,7 @@ type Effect71 struct {
func init() {
input.InitEffect(input.EffectType.Skill, 59, &Effect71{})
input.InitEffect(input.EffectType.Skill, 71, &Effect71{})
}
func (e *Effect71) SetArgs(t *input.Input, a ...int) {
@@ -50,13 +51,29 @@ func (e *Effect71) Switch(in *input.Input, at info.AttackValue, oldpet *info.Bat
if in != e.Ctx().Our {
return true
}
t := &Effect71_sub{}
t.Duration(2)
t.ID(e.ID() + int(input.EffectType.Sub))
e.Ctx().Our.AddEffect(e.Ctx().Our, t)
t := input.Geteffect(input.EffectType.Skill, 58)
if t != nil {
e.SetArgs(e.Ctx().Our, 2)
e.Ctx().Our.AddEffect(e.Ctx().Our, e)
}
e.Alive(false)
return true
}
type Effect71_sub struct {
node.EffectNode
}
func (e *Effect71_sub) Skill_Hit_Pre(a, b *action.SelectSkillAction) bool {
//fmt.Println(e.Ctx().SkillEntity)
if e.Ctx().SkillEntity == nil {
return true
}
if e.Ctx().SkillEntity.Category() == info.Category.STATUS {
return true
}
e.Ctx().SkillEntity.CritRate = 16
return true
}

View File

@@ -43,7 +43,7 @@ func (e *Effect73) Skill_Use_ex() bool {
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Fixed,
Damage: e.Ctx().Opp.DamageZone.Damage.Div(decimal.NewFromInt(2)),
Damage: e.Ctx().Opp.DamageZone.Damage.Mul(decimal.NewFromInt(2)),
})
return true

View File

@@ -1,58 +0,0 @@
package effect
import (
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* 10%中毒、10%烧伤、10%冻伤剩下70%无效果)
*/
type Effect74 struct {
node.EffectNode
}
func init() {
ret := &Effect74{}
input.InitEffect(input.EffectType.Skill, 74, ret)
}
// 命中之后
func (e *Effect74) OnSkill() bool {
if !e.Hit() {
return true
}
Status := info.PetStatus.NULL
// 生成0-99的随机数共100种可能
switch t := e.Input.FightC.GetRand().Int31n(100); {
case t < 10: // 0-910个数占10%
Status = info.PetStatus.Poisoned
case t < 20: // 10-1910个数占10%
// 触发睡眠效果
Status = info.PetStatus.Burned
case t < 30: // 20-2910个数占10%
// 触发害怕效果
Status = info.PetStatus.Frozen
default: // 30-9970个数占70%
// 无效果
}
if Status == info.PetStatus.NULL {
return true
}
// 获取状态效果
eff := input.Geteffect(input.EffectType.Status, int(Status))
if eff == nil {
return true
}
duration := int(e.Input.FightC.GetRand().Int31n(2)) // 默认随机 2~3 回合
duration++
eff.Duration(duration)
eff.SetArgs(e.Ctx().Our) //输入参数是对方
e.Ctx().Opp.AddEffect(e.Ctx().Our, eff)
return true
}

View File

@@ -0,0 +1,81 @@
package effect
import (
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
// 定义状态区间配置包含概率上限0-100和对应的状态
type statusRange struct {
upper int // 概率区间上限例如10表示0-9区间
status info.EnumPetStatus // 该区间触发的状态
}
// 通用随机状态效果结构体
type EffectRandomStatus struct {
node.EffectNode
ranges []statusRange // 当前效果的状态概率配置
}
// 工厂函数:创建通用随机状态效果实例(接收状态配置)
func newEffectRandomStatus(ranges []statusRange) *EffectRandomStatus {
return &EffectRandomStatus{
ranges: ranges,
}
}
// 通用逻辑:命中后按概率随机触发状态
func (e *EffectRandomStatus) OnSkill() bool {
if !e.Hit() {
return true
}
// 生成0-99的随机数100种可能
randVal := int(e.Input.FightC.GetRand().Int31n(100))
targetStatus := info.PetStatus.NULL
// 根据配置匹配对应的状态
for _, r := range e.ranges {
if randVal < r.upper {
targetStatus = r.status
break
}
}
// 未匹配到任何状态(概率外情况)
if targetStatus == info.PetStatus.NULL {
return true
}
// 获取状态效果并设置参数
eff := input.Geteffect(input.EffectType.Status, int(targetStatus))
if eff == nil {
return true
}
// 持续时间随机2-3回合与原逻辑一致
duration := int(e.Input.FightC.GetRand().Int31n(2)) + 2
eff.Duration(duration)
eff.SetArgs(e.Ctx().Our)
e.Ctx().Opp.AddEffect(e.Ctx().Our, eff)
return true
}
// 初始化注册Effect74和Effect75通过不同配置区分
func init() {
// Effect7410%中毒、10%烧伤、10%冻伤70%无效果)
input.InitEffect(input.EffectType.Skill, 74, newEffectRandomStatus([]statusRange{
{upper: 10, status: info.PetStatus.Poisoned}, // 0-9中毒
{upper: 20, status: info.PetStatus.Burned}, // 10-19烧伤
{upper: 30, status: info.PetStatus.Frozen}, // 20-29冻伤
}))
// Effect7510%麻痹、10%睡眠、10%害怕70%无效果)
input.InitEffect(input.EffectType.Skill, 75, newEffectRandomStatus([]statusRange{
{upper: 10, status: info.PetStatus.Paralysis}, // 0-9麻痹
{upper: 20, status: info.PetStatus.Sleep}, // 10-19睡眠
{upper: 30, status: info.PetStatus.Fear}, // 20-29害怕
}))
}

View File

@@ -1,58 +0,0 @@
package effect
import (
"blazing/logic/service/fight/info"
"blazing/logic/service/fight/input"
"blazing/logic/service/fight/node"
)
/**
* 10%麻痹、10%睡眠、10%害怕剩下70%无效果)
*/
type Effect75 struct {
node.EffectNode
}
func init() {
ret := &Effect75{}
input.InitEffect(input.EffectType.Skill, 75, ret)
}
// 命中之后
func (e *Effect75) OnSkill() bool {
if !e.Hit() {
return true
}
Status := info.PetStatus.NULL
// 生成0-99的随机数共100种可能
switch t := e.Input.FightC.GetRand().Int31n(100); {
case t < 10: // 0-910个数占10%
Status = info.PetStatus.Paralysis
case t < 20: // 10-1910个数占10%
// 触发睡眠效果
Status = info.PetStatus.Sleep
case t < 30: // 20-2910个数占10%
// 触发害怕效果
Status = info.PetStatus.Fear
default: // 30-9970个数占70%
// 无效果
}
if Status == info.PetStatus.NULL {
return true
}
// 获取状态效果
eff := input.Geteffect(input.EffectType.Status, int(Status))
if eff == nil {
return true
}
duration := int(e.Input.FightC.GetRand().Int31n(2)) // 默认随机 2~3 回合
duration++
eff.Duration(duration)
eff.SetArgs(e.Ctx().Our) //输入参数是对方
e.Ctx().Opp.AddEffect(e.Ctx().Our, eff)
return true
}

View File

@@ -34,6 +34,6 @@ func (e *Effect77) OnSkill() bool {
if !e.Hit() {
return true
}
e.Ctx().Opp.Heal(e.Ctx().Our, &action.SelectSkillAction{}, decimal.NewFromInt(int64(e.Args()[0])))
e.Ctx().Our.Heal(e.Ctx().Our, &action.SelectSkillAction{}, decimal.NewFromInt(int64(e.Args()[1])))
return true
}

View File

@@ -34,7 +34,7 @@ func (e *Effect93) OnSkill() bool {
}
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Fixed,
Damage: decimal.NewFromInt(int64(e.Ctx().Opp.CurrentPet.Info.Hp)).Div(decimal.NewFromInt(int64(e.SideEffectArgs[0]))),
Damage: decimal.NewFromInt(int64(e.SideEffectArgs[0])),
})
return true
}

View File

@@ -11,19 +11,20 @@ import (
// -----------------------------------------------------------
// 通用效果满足特定条件时附加n点固定伤害
// -----------------------------------------------------------
// 条件回调函数判断对方是否满足触发条件返回true则触发伤害
type conditionFunc func(e *EffectConditionalAddDamage) bool
// 全局映射关联效果ID与对应的条件函数
var conditionMap = make(map[int]conditionFunc)
type EffectConditionalAddDamage struct {
node.EffectNode
condition conditionFunc // 差异化:判断触发条件的函数
node.EffectNode // 仅继承基础效果节点,不嵌入条件函数
}
// 工厂函数:创建"条件附加伤害"效果实例,传入条件判断函数
func newEffectConditionalAddDamage(cond conditionFunc) *EffectConditionalAddDamage {
return &EffectConditionalAddDamage{
condition: cond,
}
// 工厂函数:创建"条件附加伤害"效果实例(无需传入函数
func newEffectConditionalAddDamage() *EffectConditionalAddDamage {
return &EffectConditionalAddDamage{}
}
// 初始化:批量注册所有"条件附加伤害"类效果
@@ -33,19 +34,20 @@ func init() {
// 批量注册绑定效果ID与对应的条件函数可扩展
func registerConditionalAddDamageEffects() {
// 效果ID与条件函数的映射
// 133: 对方烧伤时附加伤害134:对方冻伤时附加伤害135:对方是X属性时附加伤害136:对方处于异常状态时附加伤害
// 效果ID与条件函数的映射
effectMap := map[int]conditionFunc{
133: conditionIsBurned, // Effect133对方烧伤
141: conditionIsFrozen, // 新增:对方伤时
135: conditionIsAbnormal, // 新增对方是X属性时示例需根据实际属性枚举调整
130: conditionIsTypeX, // 新增:对方处于任意异常状态时
167: conditionprop, //167 若对手处于能力下降状态则附加n点伤害
130: conditionIsTypeX, // 对方是X属性
133: conditionIsBurned, // 对方伤时
141: conditionIsFrozen, // 对方冻伤时
162: conditionIsAbnormal, // 对方处于任意异常状态时
167: conditionPropDown, // 对方处于能力下降状态时
}
// 循环注册所有效果
// 注册到全局映射,并初始化效果
for effectID, cond := range effectMap {
input.InitEffect(input.EffectType.Skill, effectID, newEffectConditionalAddDamage(cond))
conditionMap[effectID] = cond
input.InitEffect(input.EffectType.Skill, effectID, newEffectConditionalAddDamage())
}
}
@@ -58,12 +60,18 @@ func (e *EffectConditionalAddDamage) OnSkill() bool {
return true
}
// 2. 检查是否满足触发条件(调用差异化的条件函数
if !e.condition(e) {
// 2. 获取当前效果ID对应的条件函数
cond, ok := conditionMap[e.ID()-int(input.EffectType.Skill)]
if !ok {
return true // 无对应条件函数,不触发
}
// 3. 检查是否满足触发条件
if !cond(e) {
return true
}
// 3. 附加固定伤害(伤害值从SideEffectArgs[0]获取与原Effect133一致
// 4. 附加固定伤害从SideEffectArgs[0]获取伤害值
damageValue := decimal.NewFromInt(int64(e.SideEffectArgs[0]))
e.Ctx().Opp.Damage(e.Ctx().Our, &info.DamageZone{
Type: info.DamageType.Fixed,
@@ -77,37 +85,33 @@ func (e *EffectConditionalAddDamage) OnSkill() bool {
// 差异化条件函数的实现(对应不同效果的判断逻辑)
// -----------------------------------------------------------
// conditionIsBurned判断对方是否处于烧伤状态对应原Effect133
// conditionIsBurned判断对方是否处于烧伤状态
func conditionIsBurned(e *EffectConditionalAddDamage) bool {
return e.Ctx().Opp.StatEffect_Exist(info.PetStatus.Burned)
}
// conditionIsFrozen判断对方是否处于冻伤状态(新增效果)
// conditionIsFrozen判断对方是否处于冻伤状态
func conditionIsFrozen(e *EffectConditionalAddDamage) bool {
return e.Ctx().Opp.StatEffect_Exist(info.PetStatus.Frozen)
}
// conditionIsTypeX判断对方是否为X属性示例,需根据实际属性枚举调整)
// 假设属性枚举为info.PetTypeX属性为info.PetType.X
// conditionIsTypeX判断对方是否为X属性需根据实际属性枚举调整
func conditionIsTypeX(e *EffectConditionalAddDamage) bool {
return e.Ctx().Opp.CurrentPet.Gender == e.Args()[0]
// 示例假设Args[0]为目标属性值,判断对方属性是否匹配
return e.Ctx().Opp.CurrentPet.PType == e.Args()[0]
}
// conditionIsAbnormal判断对方是否处于任意异常状态(新增效果)
// 假设异常状态包含烧伤、冻伤、麻痹等,通过检查是否存在任意异常状态实现
// conditionIsAbnormal判断对方是否处于任意异常状态
func conditionIsAbnormal(e *EffectConditionalAddDamage) bool {
return e.Ctx().Opp.StatEffect_Exist_all()
}
func conditionprop(e *EffectConditionalAddDamage) bool {
// conditionPropDown判断对方是否处于能力下降状态
func conditionPropDown(e *EffectConditionalAddDamage) bool {
for _, v := range e.Ctx().Opp.Prop {
if v < 0 {
return true
}
}
return false
}

View File

@@ -57,11 +57,11 @@ func init() {
level int8
opType info.EnumAbilityOpType
}{
{3, false, -1, info.AbilityOpType.RESET}, // 解除自身能力下降状态
{33, true, 1, info.AbilityOpType.RESET}, // 消除对手能力提升状态
{63, false, 0, info.AbilityOpType.AbilityOpBounceWeaken}, // 将能力下降反馈给对手
{85, false, -1, info.AbilityOpType.AbilityOpStealStrengthen}, // 将对手提升效果转移到自己
{143, true, 1, info.AbilityOpType.AbilityOpReverse}, // 反转对手能力提升为下降
{3, false, -1, info.AbilityOpType.RESET}, // 解除自身能力下降状态
{33, true, 1, info.AbilityOpType.RESET}, // 消除对手能力提升状态
{63, false, 0, info.AbilityOpType.BounceWeaken}, // 将能力下降反馈给对手
{85, false, -1, info.AbilityOpType.StealStrengthen}, // 将对手提升效果转移到自己
{143, true, 1, info.AbilityOpType.Reverse}, // 反转对手能力提升为下降
}
for _, e := range effects {

View File

@@ -16,10 +16,10 @@ type BaseSataus struct {
}
// /重写切换事件
func (e *BaseSataus) Switch(*input.Input, info.AttackValue, *info.BattlePetEntity) bool {
func (e *BaseSataus) Switch(in *input.Input, _ info.AttackValue, _ *info.BattlePetEntity) bool {
//状态如果是我方切换,那么就消除掉状态效果
if e.Input == e.Ctx().Our {
if in == e.Ctx().Our {
//下场,执行消回合效果
// e.ctx.Our.CancelAll()
///我放下场
@@ -91,7 +91,7 @@ type DrainedHP struct {
func (e *DrainedHP) Skill_Hit_Pre(a, b *action.SelectSkillAction) bool {
if gconv.Int(e.Input.CurrentPet.Type) == 1 {
if gconv.Int(e.Ctx().Our.CurrentPet.Type) == 1 {
return true
}
e.DrainHP.Skill_Hit_Pre(a, b) //先调用父类扣血

View File

@@ -45,9 +45,9 @@ func (f *FightC) processSkillAttack(attacker, defender *input.Input, a *info.Ski
//技能miss+效果生效 这里属于强制改命中效果,但是正常来说,技能miss掉后效果也应该失效
//技能失效+效果失效
// 记录技能信息
attacker.SkillID = uint32(a.ID) //获取技能ID
if attacker.AttackTime > 0 { //如果命中
if attacker.AttackTime > 0 { //如果命中
attacker.SkillID = uint32(a.ID) //获取技能ID
attacker.CalculateCrit(defender, a) //暴击计算
attacker.IsCritical = a.Crit
@@ -323,6 +323,8 @@ func (f *FightC) enterturn(fattack, sattack *action.SelectSkillAction) {
f.closefight = true
// break
}
attacker.CanChange = true
break
}
if defender.CurrentPet.Info.Hp == 0 {

View File

@@ -49,6 +49,15 @@ func CreateBattlePetEntity(info *model.PetInfo, rand *rand.Rand) *BattlePetEntit
}
ret.PType = 8
for _, v := range xmlres.PetMAP {
if v.ID == int(ret.Info.ID) {
ret.PType = v.Type
break
}
}
return ret
}
@@ -89,22 +98,6 @@ func (u *BattlePetEntity) GetMaxHP() decimal.Decimal {
}
func (u *BattlePetEntity) Type() *element.ElementCombination {
// 1. 遍历宠物配置查找对应元素类型ID
found := false
if u.PType == 0 {
for _, v := range xmlres.PetMAP {
if v.ID == int(u.Info.ID) {
u.PType = v.Type
found = true
break
}
}
}
// 2. 未找到配置时,默认使用"普通8"
if !found {
u.PType = 8
}
// 3. 从预加载的组合池中获取实例(无需创建,直接读取)
combo, err := element.Calculator.GetCombination(u.PType)

View File

@@ -154,6 +154,7 @@ func (s *SkillEntity) AttackTimeC(level int) {
if s.MustHit != 0 {
s.AttackTime = 2
return
}
a := int64(s.GetAccuracy(level))

View File

@@ -96,8 +96,8 @@ var AbilityOpType = enum.New[struct {
COPY EnumAbilityOpType `enum:"3"` // 复制强化/弱化
RESET EnumAbilityOpType `enum:"4"` // 能力重置
AbilityOpStealStrengthen EnumAbilityOpType `enum:"6"` // 吸取强化
AbilityOpReverse EnumAbilityOpType `enum:"7"` // 反转强化/弱化
StealStrengthen EnumAbilityOpType `enum:"6"` // 吸取强化
Reverse EnumAbilityOpType `enum:"7"` // 反转强化/弱化
AbilityOpBounceWeaken EnumAbilityOpType `enum:"10"` // 弹弱(反弹弱化效果)
BounceWeaken EnumAbilityOpType `enum:"10"` // 弹弱(反弹弱化效果)
}]()

View File

@@ -46,6 +46,7 @@ type S2C_NOTE_HANDLE_FIGHT_INVITE struct {
type PVPinfo struct {
PlayerID uint32
Mode EnumBattleMode
Status EnumBattleMode
}
// FightPetInfo 战斗精灵信息结构体FightPetInfo类

View File

@@ -6,7 +6,6 @@ import (
"blazing/common/utils"
"blazing/logic/service/fight/action"
"blazing/logic/service/fight/info"
"fmt"
"math/rand"
"github.com/shopspring/decimal"
@@ -186,148 +185,6 @@ func (our *Input) Damage(in *Input, sub *info.DamageZone) {
}
// 攻击,防御,特供,特防,速度,命中
// 施加方,类型,等级,操作类别,是否成功
func (our *Input) SetProp(in *Input, prop, level int8, ptype info.EnumAbilityOpType) (ret bool) {
//in.Our = our //设置属性的角色是我方
canuseskill := our.Exec(func(t Effect) bool { //这个是能否使用技能
//结算状态
return t.Prop_Befer(in, prop, level, ptype) //返回本身结算,如果false,说明不能使用技能了
})
if !canuseskill {
return false
}
var newValue int8
abfunc := func(prop, level int8, ptype info.EnumAbilityOpType) (ret bool) {
switch ptype {
case info.AbilityOpType.ADD:
newValue = utils.Min(our.AttackValue.Prop[prop]+int8(level), 6)
if newValue > our.AttackValue.Prop[prop] {
fmt.Println("属性值会增加")
return true
} else {
fmt.Println("属性值不会增加")
return false
}
case info.AbilityOpType.SUB:
newValue = utils.Max(our.AttackValue.Prop[prop]+int8(level), -6)
if newValue < our.AttackValue.Prop[prop] {
fmt.Println("属性值会减少")
return true
} else {
fmt.Println("属性值不会增加")
return false
}
case info.AbilityOpType.RESET:
if level > 0 && our.AttackValue.Prop[prop] > 0 { //消强
newValue = 0
return true
}
if level < 0 && our.AttackValue.Prop[prop] < 0 { //解弱
newValue = 0
return true
}
}
return false
}
switch ptype {
case info.AbilityOpType.AbilityOpStealStrengthen:
temp := our.Opp.AttackValue.Prop[prop]
if temp <= 0 { //对方没有强化
return false
}
if abfunc(prop, temp, info.AbilityOpType.ADD) { //把对面的强化等级添加自身
our.AttackValue.Prop[prop] = newValue //成功把 强化更新
our.Opp.SetProp(our, prop, 1, info.AbilityOpType.RESET) //吸取后消除对面强化
}
case info.AbilityOpType.AbilityOpReverse:
temp := our.AttackValue.Prop[prop]
switch {
case level > 0: //反转强化
if temp <= 0 { //没有强化
return false
}
if abfunc(prop, temp*2, info.AbilityOpType.SUB) {
our.AttackValue.Prop[prop] = newValue
if temp == -our.AttackValue.Prop[prop] { //成功到对应弱化
return true
} else {
return true
}
} else { //自身免弱或已到-6
return false
}
default: //反转弱化
if temp >= 0 { //没有弱化
return false
}
if abfunc(prop, -temp*2, info.AbilityOpType.ADD) {
our.AttackValue.Prop[prop] = newValue
if temp == -our.AttackValue.Prop[prop] { //成功到对应强化
return true
} else {
return true
}
} else { //自身免弱或已到-6
return false
}
}
case info.AbilityOpType.AbilityOpBounceWeaken:
temp := our.AttackValue.Prop[prop]
if temp >= 0 { //没有弱化
return false
}
if our.Opp.SetProp(our, prop, temp, info.AbilityOpType.SUB) {
our.SetProp(our, prop, -1, info.AbilityOpType.RESET) //消除自身弱化
return true
}
case info.AbilityOpType.COPY:
temp := our.Opp.AttackValue.Prop[prop]
if temp >= 0 {
our.SetProp(our, prop, temp, info.AbilityOpType.ADD)
} else {
our.SetProp(our, prop, -temp, info.AbilityOpType.SUB)
}
default: //增加减少重置
if abfunc(prop, level, ptype) {
// 执行赋值
our.AttackValue.Prop[prop] = newValue
return true
}
}
return false
}
func (our *Input) GetAction(opp *Input) {
// 获取己方当前宠物和对方当前宠物
selfPet := our.FightC.GetCurrPET(our.Player)

View File

@@ -0,0 +1,173 @@
package input
import (
"blazing/common/utils"
"blazing/logic/service/fight/info"
"fmt"
)
// SetProp 处理属性操作(提升/下降/消除/偷取等)
// our当前执行操作的主体操作发起方
// target输入源操作的源头输入对象可能是我方或对方
// prop属性类型
// level操作幅度强化/弱化的程度)
// opType操作类型明确区分提升/下降/消除等)
func (our *Input) SetProp(target *Input, prop int8, level int8, opType info.EnumAbilityOpType) bool {
// 前置检查:输入源是否允许该操作(基于输入源的状态)
if !our.checkPreCondition(target, prop, level, opType) {
return false
}
// 根据操作类型处理(明确区分不同操作的逻辑)
switch opType {
case info.AbilityOpType.ADD: // 能力提升(强化):仅正向增加,不处理负数
return our.handleStrengthen(target, prop, level)
case info.AbilityOpType.SUB: // 能力下降(弱化):仅负向减少,不处理正数
return our.handleWeaken(target, prop, level)
case info.AbilityOpType.RESET: // 能力消除重置清除强化或弱化恢复0
return our.handleReset(target, prop, level)
case info.AbilityOpType.StealStrengthen: // 偷取强化:从对方输入源偷取到自身
return our.handleStealStrengthen(target, prop)
case info.AbilityOpType.Reverse: // 反转:强化转弱化,弱化转强化
return our.handleReverse(target, prop, level)
case info.AbilityOpType.BounceWeaken: // 反弹弱化:将输入源的弱化反弹给对方
return our.handleBounceWeaken(target, prop)
case info.AbilityOpType.COPY: // 复制:复制对方属性到输入源
return our.handleCopy(target, prop)
default:
return false
}
}
// checkPreCondition 检查输入源是否允许操作(基于输入源的状态)
func (our *Input) checkPreCondition(inputSource *Input, prop, level int8, opType info.EnumAbilityOpType) bool {
return our.Exec(func(e Effect) bool {
// 检查输入源是否允许该操作e.Prop_Befer的参数是输入源
return e.Prop_Befer(inputSource, prop, level, opType)
})
}
// ------------------------------
// 1. 能力提升强化仅处理正向增加上限6
// ------------------------------
func (our *Input) handleStrengthen(inputSource *Input, prop, level int8) bool {
if level <= 0 {
fmt.Printf("强化失败幅度必须为正数level=%d\n", level)
return false
}
current := inputSource.AttackValue.Prop[prop]
newVal := utils.Min(current+level, 6) // 强化上限6
if newVal == current {
fmt.Printf("属性[%d]强化无变化(当前%d已达上限6\n", prop, current)
return false
}
inputSource.AttackValue.Prop[prop] = newVal
fmt.Printf("属性[%d]强化:%d → %d+%d\n", prop, current, newVal, level)
return true
}
// ------------------------------
// 2. 能力下降(弱化):仅处理负向减少,下限-6
// ------------------------------
func (our *Input) handleWeaken(inputSource *Input, prop, level int8) bool {
if level >= 0 {
fmt.Printf("弱化失败幅度必须为负数level=%d\n", level)
return false
}
current := inputSource.AttackValue.Prop[prop]
newVal := utils.Max(current+level, -6) // 弱化下限-6
if newVal == current {
fmt.Printf("属性[%d]弱化无变化(当前%d已达下限-6\n", prop, current)
return false
}
inputSource.AttackValue.Prop[prop] = newVal
fmt.Printf("属性[%d]弱化:%d → %d%d\n", prop, current, newVal, level)
return true
}
// ------------------------------
// 3. 能力消除(重置):仅清除对应状态(强化/弱化),不影响正常状态
// ------------------------------
func (our *Input) handleReset(inputSource *Input, prop, level int8) bool {
current := inputSource.AttackValue.Prop[prop]
// 规则level>0清除强化current>0level<0清除弱化current<0不处理正常状态current=0
if (level > 0 && current <= 0) || (level < 0 && current >= 0) {
fmt.Printf("重置失败:属性[%d]当前状态(%d与操作level=%d不匹配\n", prop, current, level)
return false
}
inputSource.AttackValue.Prop[prop] = 0
fmt.Printf("属性[%d]重置:%d → 0level=%d\n", prop, current, level)
return true
}
// ------------------------------
// 4. 偷取强化:从对方输入源偷取强化到自身输入源
// ------------------------------
func (our *Input) handleStealStrengthen(inputSource *Input, prop int8) bool {
// 对方输入源的强化值(必须为正)
oppProp := our.Opp.AttackValue.Prop[prop]
if oppProp <= 0 {
fmt.Printf("偷取失败:对方属性[%d]无强化(%d\n", prop, oppProp)
return false
}
// 自身输入源增加偷取的强化值
if !our.handleStrengthen(inputSource, prop, oppProp) {
return false
}
// 清除对方输入源的强化用level>0重置
our.Opp.SetProp(our.Opp, prop, 1, info.AbilityOpType.RESET)
return true
}
// ------------------------------
// 5. 反转:输入源的强化转弱化,或弱化转强化
// ------------------------------
func (our *Input) handleReverse(inputSource *Input, prop, level int8) bool {
current := inputSource.AttackValue.Prop[prop]
switch {
case level > 0 && current > 0: // 强化转弱化幅度为当前强化值的2倍
// 例:当前+2 → 弱化-4level>0指定强化转弱化
return our.handleWeaken(inputSource, prop, -current*2)
case level < 0 && current < 0: // 弱化转强化幅度为当前弱化值的2倍
// 例:当前-2 → 强化+4level<0指定弱化转强化
return our.handleStrengthen(inputSource, prop, -current*2)
default:
fmt.Printf("反转失败:当前值(%d与操作方向level=%d不匹配\n", current, level)
return false
}
}
// ------------------------------
// 6. 反弹弱化:将输入源的弱化反弹给对方,同时清除输入源的弱化
// ------------------------------
func (our *Input) handleBounceWeaken(inputSource *Input, prop int8) bool {
// 输入源的弱化值(必须为负)
currentWeak := inputSource.AttackValue.Prop[prop]
if currentWeak >= 0 {
fmt.Printf("反弹失败:输入源属性[%d]无弱化(%d\n", prop, currentWeak)
return false
}
// 反弹给对方:对方输入源承受相同弱化(用弱化操作)
if !our.Opp.SetProp(our.Opp, prop, currentWeak, info.AbilityOpType.SUB) {
return false
}
// 清除输入源的弱化用level<0重置
return our.handleReset(inputSource, prop, -1)
}
// ------------------------------
// 7. 复制:将对方属性复制到输入源(强化/弱化均复制)
// ------------------------------
func (our *Input) handleCopy(inputSource *Input, prop int8) bool {
oppProp := our.Opp.AttackValue.Prop[prop]
if oppProp == 0 {
fmt.Printf("复制无变化:对方属性[%d]为0\n", prop)
return true // 无变化也算成功
}
// 根据对方属性类型选择强化/弱化操作
if oppProp > 0 {
return our.handleStrengthen(inputSource, prop, oppProp) // 复制强化
} else {
return our.handleWeaken(inputSource, prop, oppProp) // 复制弱化oppProp是负数
}
}

View File

@@ -3,14 +3,16 @@ package player
import (
"blazing/logic/service/common"
"blazing/logic/service/fight/info"
"blazing/logic/service/space"
)
// 邀请玩家加入战斗 邀请者,被邀请者,邀请模式
func (lw *Player) InvitePlayerToBattle(pinfo *info.PVPinfo) {
lw.PVPinfo = pinfo
Mainplayer.Range(func(key uint32, value *Player) bool {
func (lw *Player) InvitePlayerToBattle() {
pinfo := lw.PVPinfo
space.GetSpace(lw.Info.MapID).User.IterCb(func(key uint32, v common.PlayerI) {
if key == uint32(pinfo.PlayerID) {
value := v.(*Player)
if key == uint32(pinfo.PlayerID) { //说明这里是针对玩家邀请的
value.HavePVPinfo = append([]*Player{lw}, value.HavePVPinfo...)
t1 := NewTomeeHeader(2501, value.Info.UserID)
@@ -20,10 +22,9 @@ func (lw *Player) InvitePlayerToBattle(pinfo *info.PVPinfo) {
Mode: pinfo.Mode,
}
value.SendPack(t1.Pack(&t))
return false
return
}
return true
})
}
@@ -31,24 +32,6 @@ func (lw *Player) InvitePlayerToBattle(pinfo *info.PVPinfo) {
// 取消对战邀请
func (lw *Player) CancelBattle() {
if lw.PVPinfo == nil {
return
}
Mainplayer.Range(func(key uint32, value *Player) bool {
if key == uint32(lw.PVPinfo.PlayerID) {
for idx, v := range value.HavePVPinfo {
if v != nil && v.GetInfo().UserID == lw.PVPinfo.PlayerID {
value.HavePVPinfo = append(value.HavePVPinfo[:idx], value.HavePVPinfo[idx+1:]...)
}
}
return false
}
return true
})
lw.PVPinfo = nil
}
@@ -59,51 +42,80 @@ func (p *Player) SendLoadPercent(b info.LoadPercentOutboundInfo) {
}
// 同意对战
// AgreeBattle 处理战斗邀请响应(同意/拒绝)
// 参数:
//
// userid邀请者ID
// flag0-拒绝1-同意
// mode战斗模式
//
// 返回:
//
// bool是否成功仅同意且符合条件时为true
// common.PlayerI对应的邀请者玩家成功时有效
func (lw *Player) AgreeBattle(userid, flag uint32, mode info.EnumBattleMode) (bool, common.PlayerI) {
// 处理完毕后清空收到的邀请列表原defer逻辑保留
defer func() {
lw.HavePVPinfo = make([]*Player, 0)
}()
defer func(p *Player) {
p.HavePVPinfo = make([]*Player, 0)
}(lw) //删除对方的邀请信息
for _, v := range lw.HavePVPinfo {
if v == nil || v.Info.UserID != userid || v.PVPinfo == nil {
continue
}
t1 := NewTomeeHeader(2502, v.Info.UserID)
ret := &info.S2C_NOTE_HANDLE_FIGHT_INVITE{
UserID: lw.Info.UserID,
Nick: lw.Info.Nick,
}
if flag == 0 { //拒绝对战
v.SendPack(t1.Pack(ret))
return false, nil
}
if !lw.IsLogin { //玩家未登录
ret.Result = 4
v.SendPack(t1.Pack(ret))
return false, nil
}
if v.Info.UserID == userid && v.PVPinfo.Mode == mode { //成功找到,同意对战
if lw.CanFight() &&v.CanFight(){
ret.Result = 1
v.SendPack(t1.Pack(ret))
return true, v
} else {
ret.Result = 3
v.SendPack(t1.Pack(ret))
return false, nil
}
// 遍历收到的邀请,寻找目标邀请者
var inviter *Player
for _, p := range lw.HavePVPinfo {
if p == nil || p.Info.UserID != userid {
continue // 跳过空指针或非目标邀请者
}
inviter = p
break // 找到目标后退出循环
}
// 未找到对应的邀请者(如邀请已过期、不存在)
if inviter == nil {
return false, nil
}
} //如果对方掉线
return false, nil
// 构建响应消息(统一创建,避免重复代码)
respHeader := NewTomeeHeader(2502, inviter.Info.UserID)
resp := &info.S2C_NOTE_HANDLE_FIGHT_INVITE{
UserID: lw.Info.UserID,
Nick: lw.Info.Nick,
}
// 检查邀请者的邀请是否有效(对方已取消邀请)
if inviter.PVPinfo == nil {
resp.Result = 4 // 邀请已取消
inviter.SendPack(respHeader.Pack(resp))
return false, nil
}
// 检查战斗模式是否匹配
if inviter.PVPinfo.Mode != mode {
return false, nil // 模式不匹配,不响应(或根据业务加错误码)
}
// 处理拒绝逻辑
if flag == 0 {
resp.Result = 0 // 拒绝邀请
inviter.SendPack(respHeader.Pack(resp))
return false, nil
}
// 处理同意逻辑:检查自身状态
if !lw.IsLogin {
resp.Result = 4 // 玩家未登录(复用原错误码)
inviter.SendPack(respHeader.Pack(resp))
return false, nil
}
// 检查双方是否可战斗
if !lw.CanFight() || !inviter.CanFight() {
resp.Result = 3 // 不可战斗(如正在战斗中)
inviter.SendPack(respHeader.Pack(resp))
return false, nil
}
// 所有条件满足,同意战斗
resp.Result = 1 // 成功同意
inviter.SendPack(respHeader.Pack(resp))
return true, inviter
}

View File

@@ -27,19 +27,6 @@ func NewSpace() *Space {
}
}
// // Range 遍历所有玩家并执行回调函数
// // 读操作使用RLock遍历过程中不会阻塞其他读操作
// func (m *Space) Range(f func(playerID uint32, player common.PlayerI) bool) {
// m.mu.RLock()
// defer m.mu.RUnlock()
// for id, player := range m.User {
// // 若回调返回false则停止遍历
// if !f(id, player) {
// break
// }
// }
// }
// 获取星球
func GetSpace(id uint32) *Space {