package input import ( "blazing/logic/service/fight/info" "blazing/logic/service/player" configmodel "blazing/modules/config/model" playermodel "blazing/modules/player/model" "strings" "github.com/gogf/gf/v2/util/grand" ) // Shuffle 打乱切片顺序,使用 Fisher-Yates 洗牌算法,泛型支持任意类型 func Shuffle[T any](slice []T) { for i := len(slice) - 1; i > 0; i-- { j := grand.Intn(i + 1) slice[i], slice[j] = slice[j], slice[i] } } func (our *Input) GetAction() { actorIndex := our.TeamSlotIndex() targetIndex := our.RandomOpponentSlotIndex() target := our.OpponentSlotAt(targetIndex) next := our.Exec(func(t Effect) bool { return t.HookAction() }) scriptCtx := buildBossHookActionContext(our, target, next) if aiPlayer, ok := our.Player.(*player.AI_player); ok && aiPlayer.BossScript != "" { scriptBoss := &configmodel.BossConfig{Script: aiPlayer.BossScript} nextByScript, err := scriptBoss.RunHookActionScript(scriptCtx) if err != nil { return } next = nextByScript } if !next { return } if applyBossScriptAction(our, scriptCtx, actorIndex, targetIndex) { return } selfPet := our.FightC.GetCurrPETAt(our.Player, actorIndex) if selfPet == nil { return } if selfPet.Info.Hp <= 0 { for _, v := range our.AllPet { if v.Info.Hp > 0 { our.FightC.ChangePetAt(our.Player, v.Info.CatchTime, actorIndex) return } } return } skills := selfPet.Skills if len(skills) == 0 { return } var usedskill *info.SkillEntity for _, s := range skills { if s == nil { continue } if !s.CanUse() { continue } if target == nil { continue } s.DamageValue = our.CalculatePower(target, s) oppPet := target.CurrentPet() if oppPet == nil { continue } if s.DamageValue.Cmp(oppPet.GetHP()) != -1 { if usedskill != nil { if s.DamageValue.Cmp(usedskill.DamageValue) != -1 { usedskill = s } } else { usedskill = s } } } Shuffle(skills) if usedskill == nil { for _, s := range skills { if s == nil { continue } if !s.CanUse() { continue } usedskill = s } } if usedskill != nil { our.FightC.UseSkillAt(our.Player, uint32(usedskill.XML.ID), actorIndex, targetIndex) } else { our.FightC.UseSkillAt(our.Player, 0, actorIndex, targetIndex) } } func buildBossHookActionContext(our, opponent *Input, hookAction bool) *configmodel.BossHookActionContext { ctx := &configmodel.BossHookActionContext{ HookAction: hookAction, Action: "auto", } ctx.UseSkillFn = func(skillID uint32) { ctx.Action = "skill" ctx.SkillID = skillID } ctx.SwitchPetFn = func(catchTime uint32) { ctx.Action = "switch" ctx.CatchTime = catchTime } if our == nil || our.FightC == nil || our.Player == nil { return ctx } overInfo := our.FightC.GetOverInfo() ctx.Round = overInfo.Round ctx.IsFirst = our.FightC.IsFirst(our.Player) if selfPet := our.CurrentPet(); selfPet != nil { ctx.Our = &configmodel.BossHookPetContext{ PetID: selfPet.Info.ID, CatchTime: selfPet.Info.CatchTime, Hp: selfPet.Info.Hp, MaxHp: selfPet.Info.MaxHp, } ctx.Skills = make([]configmodel.BossHookSkillContext, 0, len(selfPet.Skills)) for _, s := range selfPet.Skills { if s == nil || s.Info == nil { continue } ctx.Skills = append(ctx.Skills, configmodel.BossHookSkillContext{ SkillID: s.Info.ID, PP: s.Info.PP, CanUse: s.CanUse(), }) } } if our.AttackValue != nil { ctx.OurAttack = convertAttackValue(our.AttackValue) } if opponent != nil { if oppPet := opponent.CurrentPet(); oppPet != nil { ctx.Opp = &configmodel.BossHookPetContext{ PetID: oppPet.Info.ID, CatchTime: oppPet.Info.CatchTime, Hp: oppPet.Info.Hp, MaxHp: oppPet.Info.MaxHp, } } if opponent.AttackValue != nil { ctx.OppAttack = convertAttackValue(opponent.AttackValue) } } return ctx } func convertAttackValue(src *playermodel.AttackValue) *configmodel.BossHookAttackContext { if src == nil { return nil } status := make([]int8, len(src.Status)) for i := range src.Status { status[i] = src.Status[i] } prop := make([]int8, len(src.Prop)) for i := range src.Prop { prop[i] = src.Prop[i] } return &configmodel.BossHookAttackContext{ SkillID: src.SkillID, AttackTime: src.AttackTime, IsCritical: src.IsCritical, LostHp: src.LostHp, GainHp: src.GainHp, RemainHp: src.RemainHp, MaxHp: src.MaxHp, State: src.State, Offensive: src.Offensive, Status: status, Prop: prop, } } func applyBossScriptAction(our *Input, ctx *configmodel.BossHookActionContext, actorIndex, targetIndex int) bool { if our == nil || ctx == nil { return false } switch strings.ToLower(strings.TrimSpace(ctx.Action)) { case "", "auto": return false case "skill", "use_skill", "useskill": our.FightC.UseSkillAt(our.Player, ctx.SkillID, actorIndex, targetIndex) return true case "switch", "change_pet", "changepet": our.FightC.ChangePetAt(our.Player, ctx.CatchTime, actorIndex) return true default: return false } }