Files
bl/logic/service/fight/input/team.go
xinian 3a7f593105
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful
fix: 修复 Effect201 在单人战斗中误生效的问题
2026-04-11 22:22:23 +08:00

253 lines
5.4 KiB
Go

package input
import "github.com/gogf/gf/v2/util/grand"
func compactSlots(slots []*Input) []*Input {
if len(slots) == 0 {
return nil
}
ret := make([]*Input, 0, len(slots))
for _, slot := range slots {
if slot == nil {
continue
}
ret = append(ret, slot)
}
return ret
}
func uniqueControllerCount(slots []*Input) int {
if len(slots) == 0 {
return 0
}
seen := make(map[uint32]struct{}, len(slots))
count := 0
for _, slot := range slots {
if slot == nil || slot.Player == nil {
continue
}
userID := slot.Player.GetInfo().UserID
if _, ok := seen[userID]; ok {
continue
}
seen[userID] = struct{}{}
count++
}
return count
}
// TeamSlots 返回当前输入所在阵营的全部有效战斗位视图。
func (our *Input) TeamSlots() []*Input {
if our == nil {
return nil
}
if len(our.Team) == 0 {
return []*Input{our}
}
return compactSlots(our.Team)
}
// TeamSlotIndex 返回当前输入在本阵营中的原始站位下标。
func (our *Input) TeamSlotIndex() int {
if our == nil || len(our.Team) == 0 {
return 0
}
for idx, teammate := range our.Team {
if teammate == our {
return idx
}
}
return 0
}
// Teammates 返回队友列表,不包含自己。
func (our *Input) Teammates() []*Input {
if our == nil {
return nil
}
teammates := make([]*Input, 0, len(our.Team))
for _, teammate := range our.TeamSlots() {
if teammate == nil || teammate == our {
continue
}
teammates = append(teammates, teammate)
}
return teammates
}
// LivingTeammates 返回当前仍有存活出战精灵的队友列表。
func (our *Input) LivingTeammates() []*Input {
if our == nil {
return nil
}
teammates := make([]*Input, 0, len(our.Team))
for _, teammate := range our.Teammates() {
currentPet := teammate.CurrentPet()
if currentPet == nil || currentPet.Info.Hp == 0 {
continue
}
teammates = append(teammates, teammate)
}
return teammates
}
// HasLivingTeammate 用于快速判断当前战斗位是否还有存活队友。
func (our *Input) HasLivingTeammate() bool {
return len(our.LivingTeammates()) > 0
}
// TeamInputCount 返回当前阵营有效 input 数量。
func (our *Input) TeamInputCount() int {
return len(our.TeamSlots())
}
// OpponentInputCount 返回敌方阵营有效 input 数量。
func (our *Input) OpponentInputCount() int {
if our == nil {
return 0
}
if len(our.OppTeam) == 0 {
if our.Opp != nil {
return 1
}
return 0
}
return len(compactSlots(our.OppTeam))
}
// IsMultiInputSide 判断当前阵营是否为多 input。
func (our *Input) IsMultiInputSide() bool {
return our.TeamInputCount() > 1
}
// IsMultiInputBattle 判断当前战斗是否包含多 input 站位。
func (our *Input) IsMultiInputBattle() bool {
if our == nil {
return false
}
return our.TeamInputCount() > 1 || our.OpponentInputCount() > 1
}
// TeamControllerCount 返回当前阵营实际操作者数量。
func (our *Input) TeamControllerCount() int {
if our == nil {
return 0
}
return uniqueControllerCount(our.TeamSlots())
}
// IsSingleControllerMultiInputSide 判断当前阵营是否为“单人控制的多 input”。
func (our *Input) IsSingleControllerMultiInputSide() bool {
return our.IsMultiInputSide() && our.TeamControllerCount() <= 1
}
// TeamSlotAt 返回指定己方站位。
func (our *Input) TeamSlotAt(index int) *Input {
if our == nil {
return nil
}
if index >= 0 && index < len(our.Team) {
return our.Team[index]
}
if index == 0 {
return our
}
return nil
}
// OpponentSlotAt 返回指定敌方站位。
func (our *Input) OpponentSlotAt(index int) *Input {
if our == nil {
return nil
}
if index >= 0 && index < len(our.OppTeam) {
return our.OppTeam[index]
}
if index == 0 {
return our.Opp
}
return nil
}
func nextLivingSlotIndex(slots []*Input, start int) int {
if len(slots) == 0 {
return -1
}
if start < 0 {
start = 0
}
if start >= len(slots) {
start = 0
}
availableIndex := -1
for offset := 0; offset < len(slots); offset++ {
idx := (start + offset) % len(slots)
slot := slots[idx]
if slot == nil {
continue
}
if availableIndex < 0 {
availableIndex = idx
}
current := slot.CurrentPet()
if current != nil && current.Info.Hp > 0 {
return idx
}
}
return availableIndex
}
// OpponentSlotAtOrNextLiving 返回指定敌方站位;若该目标已死亡,则顺延到下一只存活精灵。
func (our *Input) OpponentSlotAtOrNextLiving(index int) (*Input, int) {
if our == nil {
return nil, -1
}
if len(our.OppTeam) == 0 {
return our.OpponentSlotAt(index), index
}
resolvedIndex := nextLivingSlotIndex(our.OppTeam, index)
if resolvedIndex < 0 {
return nil, -1
}
return our.OppTeam[resolvedIndex], resolvedIndex
}
// RandomOpponentSlotIndex 返回一个可用的敌方站位下标,优先从存活站位中随机。
func (our *Input) RandomOpponentSlotIndex() int {
if our == nil {
return 0
}
if len(our.OppTeam) == 0 {
if our.Opp != nil {
return 0
}
return 0
}
living := make([]int, 0, len(our.OppTeam))
available := make([]int, 0, len(our.OppTeam))
for idx, opponent := range our.OppTeam {
if opponent == nil {
continue
}
available = append(available, idx)
current := opponent.CurrentPet()
if current != nil && current.Info.Hp > 0 {
living = append(living, idx)
}
}
candidates := living
if len(candidates) == 0 {
candidates = available
}
if len(candidates) == 0 {
return 0
}
if len(candidates) == 1 {
return candidates[0]
}
return candidates[grand.Intn(len(candidates))]
}