package cardholder import ( "apigame/common/svdto" "apigame/common/svmysql" "apigame/configs" "apigame/models" "apigame/service/constd" "apigame/util/util-lx/lxalilog" "apigame/util/util-lx/lxtime" "apigame/util/utjson" "apigame/util/utslice" "apigame/util/utstring" "github.com/samber/lo" "sort" "strconv" ) // SaveData 存储数据 func SaveData(gameId string, d *DataCardHolder) { d.UpdateTime = lxtime.NowUninx() d.Encode() _ = svmysql.Save(d, gameId) } func _LoadData(gameId string, uid int64) (d *DataCardHolder) { d = NewDataCardHolder(uid) has, err := svmysql.First(d, gameId) if err != nil { return } if has { d.Decode() } else { d.Init(uid) _ = svmysql.Insert(d, gameId) } return } // LoadData 获取数据 外部接口 func LoadData(gameId string, uid int64, config *configs.CardActivityConfig) (d *DataCardHolder) { configId := config.Id d = _LoadData(gameId, uid) // 如果当前有上线活动(活动ID不为0),且活动ID和玩家数据不同,说明活动已切换 需更新 if configId != 0 && configId != d.ActivityId { // 剩余的星星数 starCount := d.Details.StarCount d.ActivityId = configId d.Details = NewDataCardHolderDetails() // 使用剩余的星星数来自动兑换卡包 d.Details.LastStarCount = starCount NextActivityAutoExchange(gameId, d, config) SaveData(gameId, d) } return } // CheckStatus 判断活动是否开启 func CheckStatus(conf *configs.CardActivityConfig) string { sec := lxtime.NowUninx() if conf.Id == 0 { return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR } if sec < conf.StartTime { return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR } if sec > conf.EndTime { return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN2_ERROR } return constd.RECODE_OK } // CheckGameData 检查游戏数据 轮次等 func CheckGameData(d *DataCardHolder, conf *configs.CardActivityConfig) string { if d.Details.Round > conf.Round { return constd.RECODE_MERGE_CARDHOLDER_ROUNDFINISH_ERROR } return constd.RECODE_OK } // GetUserSequenceIdAndCohort 获取 用户序列组ID(sequenceId) 用户分组(cohort) func GetUserSequenceIdAndCohort(uid int64) (sequenceId, cohort string) { // todo 这里后续要对接 sequenceId = "1" cohort = "1" return } // GetOneFromArray 从配置的数组里获取一个值 scale=之前刻度 func GetOneFromArray(array []string, scale int) string { length := len(array) if length < 1 { return "" } if length == 1 { return array[0] } return array[scale%length] } // GetListFromArray 从配置的数组里获取一组值 scale=之前刻度 count=数目 func GetListFromArray(array []string, scale, count int) []string { list := make([]string, 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(gameData *DataCardHolder, conf *configs.CardActivityConfig) int { if len(conf.CardConfig) < 1 { return 0 } rate := int64(100000000) list := make([]int64, 0) for id, _ := range conf.CardConfig { count, _ := gameData.Details.Cards[id] index := int64(count)*rate + int64(id) list = append(list, index) } indexMin := utslice.Min(list) return int(indexMin % rate) } // CheckAlbumFinish 判断卡组是否已集齐 func CheckAlbumFinish(albumId int, gameData *DataCardHolder, config *configs.CardActivityConfig) bool { for _, conf := range config.CardConfig { if conf.SetId == albumId { count := gameData.Details.Cards[conf.Id] if count < 1 { return false } } } return true } // CheckRoundFinish 判断轮次是否已集齐(所有卡组集齐) func CheckRoundFinish(gameData *DataCardHolder, config *configs.CardActivityConfig) bool { for _, conf := range config.AlbumConfig { count := gameData.Details.Album[conf.SetId] if count < 1 { return false } } return true } // HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度 func HandleNextRound(gameData *DataCardHolder) { gameData.Details.Round += 1 gameData.Details.Cards = make(map[int]int) gameData.Details.Album = make(map[int]int) } // GetInfo 玩家卡牌活动信息 func GetInfo(gameData *DataCardHolder, conf *configs.CardActivityConfig) models.CardHolderInfo { info := models.CardHolderInfo{ Cards: make(map[int]int), Album: make(map[int]int), Round: 0, } for i, i2 := range gameData.Details.Cards { info.Cards[i] = i2 } for i, i2 := range gameData.Details.Album { info.Album[i] = i2 } info.StarCount = gameData.Details.StarCount info.Round = gameData.Details.Round return info } // DoOpen 封装的抽卡逻辑 // openMode:开包类型0客户端驱动1星星商店购买2剩余星星兑换 func DoOpen(gameId string, gameData *DataCardHolder, config *configs.CardActivityConfig, confCardholder configs.OpenCardholderConfig, sequenceId, cohort string, openMode int) (newCards []int) { newCards = make([]int, 0) if confCardholder.IsNew != 0 { // 如果是新卡包 按顺序查找数目最少的一张卡抽取 cardId := GetNewCard(gameData, config) // 增加卡牌 gameData.Details.Cards[cardId] += 1 newCards = append(newCards, cardId) } else { getCardFunc := func(cardConfigId string) { confCardSequence, hasCardSequence := config.FindCardSequenceConfig(cardConfigId, sequenceId, cohort) if hasCardSequence { combineId := configs.CombineIdSequenceIdCohort(cardConfigId, sequenceId, cohort) scale := gameData.Details.CardSequenceScales[combineId] cardId := GetOneFromArray(confCardSequence.CardIdLists, scale) cardIdInt := utstring.StringToInt(cardId) // 增加刻度 gameData.Details.CardSequenceScales[combineId] = scale + 1 // 增加卡牌 gameData.Details.Cards[cardIdInt] += 1 newCards = append(newCards, cardIdInt) } } // 正常抽卡 // 先抽保底卡 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 := configs.CombineIdSequenceIdCohort(confCardholder.MinimumGuaranteeCardId, sequenceId, cohort) scaleStar := gameData.Details.StarSequenceScales[combineIdStar] starIds := GetListFromArray(confNormalCardStar.NormalCardSequenceIds, scaleStar, count) // 增加星级刻度 gameData.Details.StarSequenceScales[combineIdStar] = scaleStar + count // 遍历星级刻度抽取n张卡牌 for _, id := range starIds { getCardFunc(id) } } } } // 记录开卡包日志 { recordBase := NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round) svdto.SaveRecord(gameId, NewCardHolderRecordOpen(recordBase, openMode, utstring.StringToInt(confCardholder.Id), utjson.JsonString(newCards))) } return } // DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑 func DoOpenCheckAward(gameId string, gameData *DataCardHolder, config *configs.CardActivityConfig, sequenceId, cohort string, 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 := gameData.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, gameData, config) { continue } // 集齐处理发奖 gameData.Details.Album[albumId] += 1 award := confAlbum.Rewards[utstring.IntToString(gameData.Details.Round)] awardAlbum[albumId] = award { // 记录日志 recordBase := NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round) svdto.SaveRecord(gameId, NewCardHolderRecordRewardAlbum(recordBase, albumId, award)) } } // 判断 处理 发放轮次奖励 轮次完成 if CheckRoundFinish(gameData, config) { // 返回奖励 awardRound = config.Awards[utstring.IntToString(gameData.Details.Round)] // 记录日志 recordBase := NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round) svdto.SaveRecord(gameId, NewCardHolderRecordRewardRound(recordBase, awardRound)) // 处理轮次完成 HandleNextRound(gameData) } } return } // CalculateStarCount 计算星星点数 func CalculateStarCount(gameData *DataCardHolder, config *configs.CardActivityConfig) { starCount := 0 for cardId, cardCount := range gameData.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 } } gameData.Details.StarCount = starCount } // GetStarCardList 按照规则扣除星星数找到需要扣除的卡牌列表 func GetStarCardList(gameData *DataCardHolder, config *configs.CardActivityConfig, 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 gameData.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 gameData.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, gameData *DataCardHolder, config *configs.CardActivityConfig) { starCount := gameData.Details.LastStarCount // 把星星的配置按照需要的星星数降序排列 list := lo.Values[int, configs.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 { for starCount >= config.NeedStarNumber { gameData.Details.AutoExchangeHolder = append(gameData.Details.AutoExchangeHolder, config.Id) starCount -= config.NeedStarNumber } } // 开始处理抽卡 openMode := 2 sequenceId, cohort := GetUserSequenceIdAndCohort(gameData.Uid) allNewCards := make([]int, 0) for _, idCardholder := range gameData.Details.AutoExchangeHolder { confCardholder, _ := config.CardholderConfig[strconv.Itoa(idCardholder)] newCards := DoOpen(gameId, gameData, config, confCardholder, sequenceId, cohort, openMode) // 打乱顺序 utslice.Shuffle(newCards) for _, i3 := range newCards { allNewCards = append(allNewCards, i3) } } _, _ = DoOpenCheckAward(gameId, gameData, config, sequenceId, cohort, allNewCards, openMode) // 计算星星点数 CalculateStarCount(gameData, config) }