logic.go 10.7 KB
package cardholder

import (
	"apigame/common/svconst"
	"apigame/common/svdto"
	"apigame/dto"
	"apigame/models"
	"apigame/service/constd"
	"apigame/util/util-lx/lxalilog"
	"apigame/util/util-lx/lxtime"
	"apigame/util/utslice"
	"apigame/util/utstring"
	"apigame/util/zjson"
)

// SaveData 存储数据
func SaveData(gameId string, d *dto.CardHolderData) {
	d.UpdateTime = lxtime.NowUninx()
	d.Encode()

	svdto.Save(svconst.DbCommon, d, gameId)
}

func _LoadData(gameId string, uid int64) (d *dto.CardHolderData) {
	d = dto.NewCardHolderData(uid)
	has, err := svdto.First(svconst.DbCommon, d, gameId)
	if err != nil {
		return
	}
	if has {
		d.Decode()
	} else {
		d.Init(uid)
		svdto.Insert(svconst.DbCommon, d, gameId)
	}
	return
}

// LoadData 获取数据 外部接口
func LoadData(gameId string, uid int64, configId int64) (d *dto.CardHolderData) {
	d = _LoadData(gameId, uid)
	// 如果当前有上线活动(活动ID不为0),且活动ID和玩家数据不同,说明活动已切换 需更新
	if configId != 0 &&
		configId != d.ActivityId {
		d.ActivityId = configId
		d.Details = dto.NewCardHolderDataDetails()
		SaveData(gameId, d)
	}
	return
}

// CheckStatus 判断活动是否开启
func CheckStatus(conf *CardActivityConfig) string {
	sec := lxtime.NowUninx()
	if conf.Id == 0 {
		return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR
	}
	if sec < conf.Raw.StartTime {
		return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN1_ERROR
	}
	if sec > conf.Raw.EndTime {
		return constd.RECODE_MERGE_CARDHOLDER_NOTOPEN2_ERROR
	}
	return constd.RECODE_OK
}

// CheckGameData 检查游戏数据 轮次等
func CheckGameData(d *dto.CardHolderData, conf *CardActivityConfig) string {
	if d.Details.Round > conf.Raw.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 *dto.CardHolderData, conf *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 *dto.CardHolderData, config *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 *dto.CardHolderData, config *CardActivityConfig) bool {
	for _, conf := range config.AlbumConfig {
		count := gameData.Details.Album[conf.SetId]
		if count < 1 {
			return false
		}
	}
	return true
}

// HandleNextRound 处理轮次完成 星级序列刻度 卡牌序列刻度
func HandleNextRound(gameData *dto.CardHolderData) {
	gameData.Details.Round += 1
	gameData.Details.Cards = make(map[int]int)
	gameData.Details.Album = make(map[int]int)
}

// GetInfo 玩家卡牌活动信息
func GetInfo(gameData *dto.CardHolderData, conf *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 *dto.CardHolderData,
	config *CardActivityConfig,
	confCardholder 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 := 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 := 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 := dto.NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round)
		svdto.SaveRecord(gameId, dto.NewCardHolderRecordOpen(recordBase,
			openMode, utstring.StringToInt(confCardholder.Id), zjson.Str(newCards)))
	}

	return
}

// DoOpenCheckAward 封装的新卡判断是否出发卡组和轮次奖励的逻辑
func DoOpenCheckAward(gameId string,
	gameData *dto.CardHolderData,
	config *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 := dto.NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round)
				svdto.SaveRecord(gameId, dto.NewCardHolderRecordRewardAlbum(recordBase,
					albumId, award))
			}
		}
		// 判断 处理 发放轮次奖励 轮次完成
		if CheckRoundFinish(gameData, config) {
			// 返回奖励
			awardRound = config.Awards[utstring.IntToString(gameData.Details.Round)]

			// 记录日志
			recordBase := dto.NewCardHolderRecordBase(gameData.Uid, sequenceId, cohort, config.Id, gameData.Details.Round)
			svdto.SaveRecord(gameId, dto.NewCardHolderRecordRewardRound(recordBase,
				awardRound))

			// 处理轮次完成
			HandleNextRound(gameData)
		}
	}

	return
}

// CalculateStarCount 计算星星点数
func CalculateStarCount(gameData *dto.CardHolderData, config *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 *dto.CardHolderData, config *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
}