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 }