82 行
1.8 KiB
Go
82 行
1.8 KiB
Go
|
|
package battle
|
||
|
|
|
||
|
|
import (
|
||
|
|
"math/rand"
|
||
|
|
"sort"
|
||
|
|
)
|
||
|
|
|
||
|
|
// DefaultNormalAttack 返回普通攻击兜底技能
|
||
|
|
func DefaultNormalAttack(f *Fighter) *SkillInstance {
|
||
|
|
elem := f.Element
|
||
|
|
if elem == "" {
|
||
|
|
elem = "none"
|
||
|
|
}
|
||
|
|
return &SkillInstance{
|
||
|
|
InstanceID: "normal_attack",
|
||
|
|
SkillID: "normal_attack",
|
||
|
|
Name: "普通攻击",
|
||
|
|
DamageType: DamageTypePhysical,
|
||
|
|
Element: elem,
|
||
|
|
Alignment: f.Alignment,
|
||
|
|
ScalingAttr: "str",
|
||
|
|
BaseCoef: cfgFloat("combat.skill.normal_attack_coef", 1.0),
|
||
|
|
CD: 0,
|
||
|
|
Cost: 0,
|
||
|
|
TriggerRate: 1.0,
|
||
|
|
TargetType: TargetSingle,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// SelectSkill 按 GDD-03 ✅24 触发率机制选择技能
|
||
|
|
// 1. 候选池 = CD=0 且内力够的主动技能
|
||
|
|
// 2. 触发率 ≥100% 的候选必定释放,取最高者
|
||
|
|
// 3. 否则对每个候选独立掷骰,命中者取触发率最高者
|
||
|
|
// 4. 全部未命中或候选池为空则普通攻击
|
||
|
|
func SelectSkill(actor *Fighter, opponent *Fighter, normal *SkillInstance, rng *rand.Rand) *SkillInstance {
|
||
|
|
candidates := make([]*SkillInstance, 0, len(actor.Skills))
|
||
|
|
for _, s := range actor.Skills {
|
||
|
|
if s == nil {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if s.CDRemaining <= 0 && actor.CanSpendMana(s.Cost) {
|
||
|
|
candidates = append(candidates, s)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if len(candidates) == 0 {
|
||
|
|
return normal
|
||
|
|
}
|
||
|
|
|
||
|
|
// 按触发率降序
|
||
|
|
sort.Slice(candidates, func(i, j int) bool {
|
||
|
|
return candidates[i].TriggerRate > candidates[j].TriggerRate
|
||
|
|
})
|
||
|
|
|
||
|
|
// 必发技能
|
||
|
|
if candidates[0].TriggerRate >= 1.0 {
|
||
|
|
return candidates[0]
|
||
|
|
}
|
||
|
|
|
||
|
|
// 独立掷骰
|
||
|
|
var best *SkillInstance
|
||
|
|
bestRate := 0.0
|
||
|
|
for _, s := range candidates {
|
||
|
|
rate := s.TriggerRate
|
||
|
|
if rate <= 0 {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if rate > 1.0 {
|
||
|
|
rate = 1.0
|
||
|
|
}
|
||
|
|
if rng.Float64() < rate {
|
||
|
|
if best == nil || s.TriggerRate > bestRate {
|
||
|
|
best = s
|
||
|
|
bestRate = s.TriggerRate
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if best != nil {
|
||
|
|
return best
|
||
|
|
}
|
||
|
|
return normal
|
||
|
|
}
|