feat: 增强 Boss 脚本 HookAction 接入能力
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
引入 BossHookActionContext 封装战斗上下文,并支持脚本调用 useSkill 和 switchPet 函数控制战斗行为。
This commit is contained in:
@@ -4,30 +4,28 @@ import (
|
||||
"blazing/logic/service/fight/info"
|
||||
"blazing/logic/service/player"
|
||||
configmodel "blazing/modules/config/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-- {
|
||||
// 生成 0 到 i 之间的随机索引
|
||||
j := grand.Intn(i + 1)
|
||||
// 交换 i 和 j 位置的元素
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
}
|
||||
|
||||
func (our *Input) GetAction() {
|
||||
|
||||
next := our.Exec(func(t Effect) bool {
|
||||
|
||||
return t.HookAction()
|
||||
})
|
||||
|
||||
scriptCtx := buildBossHookActionContext(our, next)
|
||||
if aiPlayer, ok := our.Player.(*player.AI_player); ok && aiPlayer.BossScript != "" {
|
||||
scriptBoss := &configmodel.BossConfig{Script: aiPlayer.BossScript}
|
||||
nextByScript, err := scriptBoss.RunHookActionScript(next)
|
||||
nextByScript, err := scriptBoss.RunHookActionScript(scriptCtx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -37,28 +35,30 @@ func (our *Input) GetAction() {
|
||||
if !next {
|
||||
return
|
||||
}
|
||||
// 获取己方当前宠物和对方当前宠物
|
||||
|
||||
if applyBossScriptAction(our, scriptCtx) {
|
||||
return
|
||||
}
|
||||
|
||||
selfPet := our.FightC.GetCurrPET(our.Player)
|
||||
//没血就切换精灵
|
||||
if selfPet == nil {
|
||||
return
|
||||
}
|
||||
if selfPet.Info.Hp <= 0 {
|
||||
for _, v := range our.AllPet {
|
||||
if v.Info.Hp > 0 {
|
||||
// println("AI出手,切换宠物")
|
||||
our.FightC.ChangePet(our.Player, v.Info.CatchTime)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 如果没有可用宠物,则直接返回,不执行任何操作
|
||||
return
|
||||
}
|
||||
//oppPet := opp.FightC.GetCurrPET(opp.Player)
|
||||
skills := selfPet.Skills
|
||||
|
||||
// 空技能列表直接返回,避免错误
|
||||
skills := selfPet.Skills
|
||||
if len(skills) == 0 {
|
||||
return
|
||||
}
|
||||
//println("AI出手,选择技能")
|
||||
|
||||
var usedskill *info.SkillEntity
|
||||
for _, s := range skills {
|
||||
if s == nil {
|
||||
@@ -67,30 +67,25 @@ func (our *Input) GetAction() {
|
||||
if !s.CanUse() {
|
||||
continue
|
||||
}
|
||||
// 计算技能对对方的伤害(假设CalculatePower返回伤害值,或需从技能中获取)
|
||||
s.DamageValue = our.CalculatePower(our.Opp, s)
|
||||
|
||||
oppPet := our.Opp.CurrentPet()
|
||||
if oppPet == nil {
|
||||
continue
|
||||
}
|
||||
// 判断是否能秒杀(伤害 >= 对方当前生命值)
|
||||
if s.DamageValue.Cmp(oppPet.GetHP()) != -1 { // 假设oppPet.HP为对方当前剩余生命值
|
||||
|
||||
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
|
||||
@@ -99,14 +94,87 @@ func (our *Input) GetAction() {
|
||||
continue
|
||||
}
|
||||
usedskill = s
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if usedskill != nil {
|
||||
our.FightC.UseSkill(our.Player, uint32(usedskill.XML.ID))
|
||||
} else {
|
||||
our.FightC.UseSkill(our.Player, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func buildBossHookActionContext(our *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.Opp != nil {
|
||||
if oppPet := our.Opp.CurrentPet(); oppPet != nil {
|
||||
ctx.Opp = &configmodel.BossHookPetContext{
|
||||
PetID: oppPet.Info.ID,
|
||||
CatchTime: oppPet.Info.CatchTime,
|
||||
Hp: oppPet.Info.Hp,
|
||||
MaxHp: oppPet.Info.MaxHp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
func applyBossScriptAction(our *Input, ctx *configmodel.BossHookActionContext) 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.UseSkill(our.Player, ctx.SkillID)
|
||||
return true
|
||||
case "switch", "change_pet", "changepet":
|
||||
our.FightC.ChangePet(our.Player, ctx.CatchTime)
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user