package cardholder import ( "apigame/configs/confcardholder" "apigame/models" "apigame/service-common/svmysql" "apigame/service/code-msg" "apigame/util/util-lx/lxalilog" "apigame/util/util-lx/lxtime" "apigame/util/utslice" "apigame/util/utstring" "apigame/util/zjson" "github.com/samber/lo" "sort" ) // CheckStatus 判断活动是否开启 func CheckStatus(conf *confcardholder.ActivityConfig) string { sec := lxtime.NowUninx() if conf.Id == 0 { return code_msg.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR } if sec < conf.StartTime { return code_msg.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR } if sec > conf.EndTime { return code_msg.RECODE_MERGE_CARDHOLDER_NOTOPEN2_ERROR } return code_msg.RECODE_OK } // CheckGameData 检查游戏数据 轮次等 func CheckGameData(d *Player, conf *confcardholder.ActivityConfig) string { if d.Details.Round > conf.Round { return code_msg.RECODE_MERGE_CARDHOLDER_ROUNDFINISH_ERROR } return code_msg.RECODE_OK } // GetUserSequenceIdAndCohort 获取 用户序列组ID(sequenceId) 用户分组(cohort) func GetUserSequenceIdAndCohort(uid int64) (sequenceId, cohort int) { // todo 这里后续要对接 用户序列组ID(sequenceId) 用户分组(cohort) sequenceId = 1 cohort = 1 return } // GetOneFromArray 从配置的数组里获取一个值 scale=之前刻度 func GetOneFromArray(array []int, scale int) int { length := len(array) if length < 1 { return 0 } if length == 1 { return array[0] } return array[scale%length] } // GetListFromArray 从配置的数组里获取一组值 scale=之前刻度 count=数目 func GetListFromArray(array []int, scale, count int) []int { list := make([]int, 0) if count < 0 { return list } s := scale for i := 0; i < count; i++ { one := GetOneFromArray(array, s) list = append(list, one) s++ } return list } // GetNewCard 按顺序查找数目最少的一张卡抽取 func GetNewCard(player *Player, conf *confcardholder.ActivityConfig) int { if len(conf.CardConfig) < 1 { return 0 } rate := int64(100000000) list := make([]int64, 0) for id, _ := range conf.CardConfig { count, _ := player.Details.Cards[id] index := int64(count)*rate + int64(id) list = append(list, index) } indexMin := lo.Min(list) return int(indexMin % rate) } // CheckAlbumFinish 判断卡组是否已集齐 func CheckAlbumFinish(albumId int, player *Player, config *confcardholder.ActivityConfig) bool { for _, conf := range config.CardConfig { if conf.SetId == albumId { count := player.Details.Cards[conf.Id] if count < 1 { return false } } } return true } // CheckRoundFinish 判断轮次是否已集齐(所有卡组集齐) func CheckRoundFinish(player *Player, config *confcardholder.ActivityConfig) bool { for _, conf := range config.AlbumConfig { count := player.Details.Album[conf.SetId] if count < 1 { return false } } return true } // HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度 func HandleNextRound(player *Player) { player.Details.Round += 1 player.Details.Cards = make(map[int]int) player.Details.Album = make(map[int]int) } // GetInfo 玩家卡牌活动信息 func GetInfo(player *Player, config *confcardholder.ActivityConfig) models.CardHolderInfo { info := models.CardHolderInfo{ Cards: make(map[int]int), Album: make(map[int]int), Round: 0, } for i, i2 := range player.Details.Cards { info.Cards[i] = i2 } for i, i2 := range player.Details.Album { info.Album[i] = i2 } info.StarCount = player.Details.StarCount info.Round = player.Details.Round return info } // DoOpen 封装的抽卡逻辑 // openMode:开包类型0客户端驱动1星星商店购买2剩余星星兑换 func DoOpen(gameId string, player *Player, config *confcardholder.ActivityConfig, confCardholder confcardholder.OpenCardholderConfig, sequenceId, cohort int, openMode int) (newCards []int) { newCards = make([]int, 0) // 如果是新卡包 按顺序查找数目最少的一张卡抽取 // 2024年4月25日 新卡包只是多一张新卡 其余的逻辑相同 if confCardholder.IsNew != 0 { cardId := GetNewCard(player, config) // 增加卡牌 player.Details.Cards[cardId] += 1 newCards = append(newCards, cardId) } { getCardFunc := func(cardConfigId int) { confCardSequence, hasCardSequence := config.FindCardSequenceConfig(cardConfigId, sequenceId, cohort) if hasCardSequence { combineId := confcardholder.CombineIdSequenceIdCohort(cardConfigId, sequenceId, cohort) scale := player.Details.CardSequenceScales[combineId] cardId := GetOneFromArray(confCardSequence.CardIdList, scale) // 增加刻度 player.Details.CardSequenceScales[combineId] = scale + 1 // 增加卡牌 player.Details.Cards[cardId] += 1 newCards = append(newCards, cardId) } } // 正常抽卡 // 先抽保底卡 if confCardholder.GuaranteedStarCardId != 0 { getCardFunc(confCardholder.GuaranteedStarCardId) } // 非保底卡 if confCardholder.NormalCardNumber > 0 { count := confCardholder.NormalCardNumber confNormalCardStar, hasNormalCardStar := config.FindNormalCardStarConfig(confCardholder.MinimumGuaranteeCardId, sequenceId, cohort) if hasNormalCardStar { combineIdStar := confcardholder.CombineIdSequenceIdCohort(confCardholder.MinimumGuaranteeCardId, sequenceId, cohort) scaleStar := player.Details.StarSequenceScales[combineIdStar] starIds := GetListFromArray(confNormalCardStar.NormalCardSequenceId, scaleStar, count) // 增加星级刻度 player.Details.StarSequenceScales[combineIdStar] = scaleStar + count // 遍历星级刻度抽取n张卡牌 for _, id := range starIds { getCardFunc(id) } } } } // 记录开卡包日志 { recordBase := NewRecordBase(player.Uid, sequenceId, cohort, config.Id, player.Details.Round) _ = svmysql.Create(NewRecordOpen(recordBase, openMode, confCardholder.Id, zjson.Str(newCards)), gameId) } return } // DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑 func DoOpenCheckAward(gameId string, player *Player, config *confcardholder.ActivityConfig, sequenceId, cohort int, newCards []int, openMode int) (awardAlbum map[int]string, awardRound string) { awardAlbum = make(map[int]string) awardRound = "" if openMode == 0 || openMode == 1 { // 根据新获得卡牌列表 判断 触发的卡组奖励列表 for _, cardId := range newCards { confCard, hasConfCard := config.CardConfig[cardId] if !hasConfCard { lxalilog.Errors("CardConfig cant find cardId", cardId) continue } albumId := confCard.SetId // 是否已领过 countGot := player.Details.Album[albumId] if countGot > 0 { continue } confAlbum, hasConfAlbum := config.AlbumConfig[albumId] if !hasConfAlbum { lxalilog.Errors("AlbumConfig cant find albumId", albumId) continue } // 检查卡组内卡是否集齐 if !CheckAlbumFinish(albumId, player, config) { continue } // 集齐处理发奖 player.Details.Album[albumId] += 1 award := confAlbum.Rewards[utstring.IntToString(player.Details.Round)] awardAlbum[albumId] = award { // 记录日志 recordBase := NewRecordBase(player.Uid, sequenceId, cohort, config.Id, player.Details.Round) _ = svmysql.Create(NewRecordRewardAlbum(recordBase, albumId, award), gameId) } } // 判断 处理 发放轮次奖励 轮次完成 if CheckRoundFinish(player, config) { // 返回奖励 awardRound = config.Awards[utstring.IntToString(player.Details.Round)] // 记录日志 recordBase := NewRecordBase(player.Uid, sequenceId, cohort, config.Id, player.Details.Round) _ = svmysql.Create(NewRecordRewardRound(recordBase, awardRound), gameId) // 处理轮次完成 HandleNextRound(player) } } return } // CalculateStarCount 计算星星点数 func CalculateStarCount(player *Player, config *confcardholder.ActivityConfig) { starCount := 0 for cardId, cardCount := range player.Details.Cards { if cardCount <= 1 { continue } confCard, hasConfCard := config.CardConfig[cardId] if !hasConfCard { continue } // 1. 普卡 :卡的等级数=可累计 的星星数 // 2. 金币: 卡的等级数+1=可累计 的星星数 if confCard.IsGold == 1 { starCount += (cardCount - 1) * (confCard.Star + 1) } else { starCount += (cardCount - 1) * confCard.Star } } player.Details.StarCount = starCount } // GetStarCardList 按照规则扣除星星数找到需要扣除的卡牌列表 func GetStarCardList(player *Player, config *confcardholder.ActivityConfig, needStar int) (enough bool, cardList map[int]int) { enough = false cardList = make(map[int]int) starAmount := 0 levelMax := 5 // 等级依次从低到高 // 先普卡 for i := 1; i <= levelMax; i++ { for cardId, cardCount := range player.Details.Cards { if starAmount >= needStar { enough = true return } if cardCount <= 1 { continue } confCard, hasConfCard := config.CardConfig[cardId] if !hasConfCard { continue } if confCard.IsGold == 1 { continue } star := confCard.Star need := needStar - starAmount needCardCount := need / star if cardCount-1 < needCardCount { needCardCount = cardCount - 1 } cardList[cardId] = needCardCount starAmount += needCardCount * star } } // 金卡 for i := 1; i <= levelMax; i++ { for cardId, cardCount := range player.Details.Cards { if starAmount >= needStar { enough = true return } if cardCount <= 1 { continue } confCard, hasConfCard := config.CardConfig[cardId] if !hasConfCard { continue } if confCard.IsGold != 1 { continue } star := confCard.Star + 1 need := needStar - starAmount needCardCount := need / star if cardCount-1 < needCardCount { needCardCount = cardCount - 1 } cardList[cardId] = needCardCount starAmount += needCardCount * star } } if starAmount >= needStar { enough = true return } return } // NextActivityAutoExchange 活动切换时自动兑换卡包 func NextActivityAutoExchange(gameId string, player *Player, config *confcardholder.ActivityConfig) { // 把星星的配置按照需要的星星数降序排列 list := lo.Values[int, confcardholder.StarShopConfig](config.StarShopConfig) sort.Slice(list, func(i, j int) bool { return list[i].NeedStarNumber < list[j].NeedStarNumber }) list = lo.Reverse(list) // 遍历 for _, config := range list { if player.Details.LastStarCount >= config.NeedStarNumber { player.Details.AutoExchangeHolder = config.Id break } } // 开始处理抽卡 openMode := 2 sequenceId, cohort := GetUserSequenceIdAndCohort(player.Uid) allNewCards := make([]int, 0) if player.Details.AutoExchangeHolder != 0 { confCardholder, _ := config.CardholderConfig[player.Details.AutoExchangeHolder] newCards := DoOpen(gameId, player, config, confCardholder, sequenceId, cohort, openMode) // 打乱顺序 utslice.Shuffle(newCards) for _, i3 := range newCards { allNewCards = append(allNewCards, i3) } } _, _ = DoOpenCheckAward(gameId, player, config, sequenceId, cohort, allNewCards, openMode) // 计算星星点数 CalculateStarCount(player, config) }