383 lines
10 KiB
Go
Raw Normal View History

package model
2025-06-10 21:56:29 +08:00
import (
"math/rand"
"rocommon/util"
"roserver/serverproto"
2025-06-11 22:17:19 +08:00
"sort"
"strconv"
2025-06-10 21:56:29 +08:00
)
const (
2025-06-11 22:17:19 +08:00
ROOM_STAGE_BET = 1 //押注阶段
ROOM_STAGE_SETTLE = 2 //开奖阶段
2025-06-12 22:04:02 +08:00
DURATION_BET_SEC = 15
DURATION_SETTLE_SEC = 5
2025-06-11 22:17:19 +08:00
MAX_POOL_CHIP = 10000
MAX_SETTLE_HISTORY_COUNT = 7
AWARD_TYPE_NORMAL = 1
AWARD_TYPE_SPECIAL = 2
)
type FruitRoom struct {
2025-06-12 22:04:02 +08:00
roomId int32
Stage int32
Sec int32
uidList []uint64
PoolChipNum int32
TotalBetInfo map[int32]int32
SettleHistory []int32
CurrAwardType int32
CurrAwardSlots []int32
CurrStartSlot int32
CurrTargetSlot int32
CurrPlayerAwardRank []*serverproto.FruitPlayerAwardInfo
2025-06-10 21:56:29 +08:00
}
type FruitRateInfo struct {
AwardType int32
2025-06-11 22:17:19 +08:00
SlotTypes []string
2025-06-10 21:56:29 +08:00
Rate int32
2025-06-11 22:17:19 +08:00
DRate int32
ZRate int32
2025-06-10 21:56:29 +08:00
FinalRate int32
}
func newFruitRoom(roomId int32) *FruitRoom {
2025-06-10 21:56:29 +08:00
room := &FruitRoom{
2025-06-11 22:17:19 +08:00
roomId: roomId,
2025-06-12 22:04:02 +08:00
Stage: ROOM_STAGE_BET,
Sec: 0,
2025-06-11 22:17:19 +08:00
uidList: make([]uint64, 0),
PoolChipNum: 0,
TotalBetInfo: make(map[int32]int32),
2025-06-12 22:04:02 +08:00
SettleHistory: make([]int32, 0),
CurrAwardType: 16,
CurrAwardSlots: []int32{4},
CurrStartSlot: 4,
CurrTargetSlot: 4,
2025-06-10 21:56:29 +08:00
}
room.ResetTotalBetInfo()
return room
}
func (self *FruitRoom) ResetTotalBetInfo() {
var i int32
for i = 1; i <= 8; i++ {
self.TotalBetInfo[i] = 0
}
}
func (self *FruitRoom) Join(uid uint64) {
isExist := false
for _, v := range self.uidList {
if v == uid {
isExist = true
}
}
if isExist == false {
self.uidList = append(self.uidList, uid)
}
}
2025-06-10 21:56:29 +08:00
func sliceRemoveValueFast(slice []uint64, value uint64) []uint64 {
for i := 0; i < len(slice); {
if slice[i] == value {
slice[i] = slice[len(slice)-1]
slice = slice[:len(slice)-1]
} else {
i++
}
}
return slice
}
func (self *FruitRoom) Leave(uid uint64) {
self.uidList = sliceRemoveValueFast(self.uidList, uid)
}
2025-06-14 22:49:29 +08:00
func (self *FruitRoom) Bet(uid uint64, betInfo []*serverproto.FruitSlotInfo) serverproto.ErrorCode {
2025-06-12 22:04:02 +08:00
if self.Stage != ROOM_STAGE_BET {
2025-06-10 21:56:29 +08:00
return serverproto.ErrorCode_ERROR_FRUIT_CURR_STAGE_CANNOT_BET
}
player := FruitMgr.GetPlayer(uid)
for _, v := range betInfo {
slot := v.Slot
2025-06-14 22:49:29 +08:00
betNum := v.Num
2025-06-10 21:56:29 +08:00
if player.ChipNum >= betNum {
player.ChipNum -= betNum
player.CurrBetInfo[slot] += betNum
self.TotalBetInfo[slot] += betNum
2025-06-11 22:17:19 +08:00
self.PoolChipNum += betNum
2025-06-10 21:56:29 +08:00
} else {
return serverproto.ErrorCode_ERROR_FRUIT_CHIP_INSUFFICIENT
}
}
return serverproto.ErrorCode_ERROR_OK
}
func (self *FruitRoom) JumpStage(stage int32) {
2025-06-12 22:04:02 +08:00
self.Stage = stage
self.Sec = 0
switch stage {
case ROOM_STAGE_BET:
2025-06-11 22:17:19 +08:00
self.StartBet()
case ROOM_STAGE_SETTLE:
2025-06-10 21:56:29 +08:00
self.Settle()
}
}
2025-06-11 22:17:19 +08:00
// 开始押注
func (self *FruitRoom) StartBet() {
self.ResetTotalBetInfo()
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
player.ResetBetInfo()
}
}
2025-06-10 21:56:29 +08:00
// 开奖
func (self *FruitRoom) Roll(rateItems []*FruitRateInfo) *FruitRateInfo {
var sumRate int32 = 0
for i := 0; i < len(rateItems); i++ {
2025-06-11 22:17:19 +08:00
rateItems[i].FinalRate = rateItems[i].Rate + rateItems[i].DRate*int32(self.PoolChipNum)/MAX_POOL_CHIP
2025-06-10 21:56:29 +08:00
sumRate += rateItems[i].FinalRate
}
2025-06-11 22:17:19 +08:00
randomVal := rand.Intn(int(sumRate))
2025-06-10 21:56:29 +08:00
var tmpSumRate int32 = 1
for i := 0; i < len(rateItems); i++ {
tmpSumRate += rateItems[i].FinalRate
2025-06-11 22:17:19 +08:00
if randomVal <= int(tmpSumRate) {
2025-06-10 21:56:29 +08:00
return rateItems[i]
}
}
util.InfoF("ERR: Roll Fail, Use the First Element")
return rateItems[0]
}
2025-06-14 22:49:29 +08:00
func (self *FruitRoom) CheckPlayerAward(playerBetInfo map[int32]int32, awardType_2_awardSlot map[int32]string, slotTypes []string) (int32, []*serverproto.FruitSlotInfo) {
awardInfo := make([]*serverproto.FruitSlotInfo, 0)
2025-06-11 22:17:19 +08:00
var sumAwardChip int32 = 0
for _, v := range slotTypes {
slotType, _ := strconv.Atoi(v)
slotTypeCfg := serverproto.FruitSlotTypeCfgLoader[int32(slotType)]
2025-06-14 22:49:29 +08:00
betSlotId := slotType
2025-06-11 22:17:19 +08:00
if slotType > 8 {
2025-06-14 22:49:29 +08:00
betSlotId = slotType - 8
}
betChipNum := playerBetInfo[int32(betSlotId)]
if betChipNum > 0 {
awardChip := betChipNum * slotTypeCfg.Times
slot, _ := strconv.Atoi(awardType_2_awardSlot[int32(slotType)])
awardInfo = append(awardInfo, &serverproto.FruitSlotInfo{
Slot: int32(slot),
Num: awardChip,
})
sumAwardChip += awardChip
2025-06-11 22:17:19 +08:00
}
}
2025-06-14 22:49:29 +08:00
return sumAwardChip, awardInfo
2025-06-11 22:17:19 +08:00
}
func (self *FruitRoom) GetPlayerRank(rank []*serverproto.FruitPlayerAwardInfo) []*serverproto.FruitPlayerAwardInfo {
playerRank := make([]*serverproto.FruitPlayerAwardInfo, 0)
for i := 0; i < len(rank); i++ {
playerRank = append(playerRank, rank[i])
if len(playerRank) == 3 {
break
}
}
return playerRank
}
2025-06-10 21:56:29 +08:00
func (self *FruitRoom) Settle() {
2025-06-11 22:17:19 +08:00
awardCfg := serverproto.FruitAwardCfgLoader
rateItems := make([]*FruitRateInfo, 0)
for _, v := range awardCfg {
rateItems = append(rateItems, &FruitRateInfo{AwardType: v.Id, SlotTypes: v.SlotTypes, Rate: v.Rate, DRate: v.DRate})
}
rollResult := self.Roll(rateItems)
self.RecordSettleHistory(rollResult.AwardType)
2025-06-12 22:04:02 +08:00
self.CurrAwardType = rollResult.AwardType
2025-06-14 22:49:29 +08:00
awardSlotType_2_awardSlotId := make(map[int32]string, 0)
if rollResult.AwardType == 100 || rollResult.AwardType == 101 {
2025-06-12 22:04:02 +08:00
slotTypeStr := rollResult.SlotTypes[rand.Intn(len(rollResult.SlotTypes))]
slotType, _ := strconv.Atoi(slotTypeStr)
awardSlots := make([]string, 0)
2025-06-11 22:17:19 +08:00
slotTypeCfg := serverproto.FruitSlotTypeCfgLoader[int32(slotType)]
awardSlot := self.RandomSlot(slotTypeCfg.Slots, awardSlots)
awardSlots = append(awardSlots, awardSlot)
2025-06-12 22:04:02 +08:00
tempAwardSlots := make([]int32, 0)
for _, v := range awardSlots {
slot, _ := strconv.Atoi(v)
tempAwardSlots = append(tempAwardSlots, int32(slot))
}
2025-06-14 22:49:29 +08:00
awardSlotType_2_awardSlotId[int32(slotType)] = awardSlot
2025-06-12 22:04:02 +08:00
self.CurrAwardSlots = tempAwardSlots
self.CurrStartSlot = self.CurrTargetSlot
2025-06-14 22:49:29 +08:00
} else {
2025-06-12 22:04:02 +08:00
awardSlots := make([]string, 0)
for _, v := range rollResult.SlotTypes {
slotType, _ := strconv.Atoi(v)
slotTypeCfg := serverproto.FruitSlotTypeCfgLoader[int32(slotType)]
awardSlot := self.RandomSlot(slotTypeCfg.Slots, awardSlots)
awardSlots = append(awardSlots, awardSlot)
2025-06-14 22:49:29 +08:00
awardSlotType_2_awardSlotId[int32(slotType)] = awardSlot
2025-06-12 22:04:02 +08:00
}
tempAwardSlots := make([]int32, 0)
for _, v := range awardSlots {
slot, _ := strconv.Atoi(v)
tempAwardSlots = append(tempAwardSlots, int32(slot))
}
self.CurrAwardSlots = tempAwardSlots
self.CurrStartSlot = self.CurrTargetSlot
2025-06-11 22:17:19 +08:00
}
2025-06-12 22:04:02 +08:00
if self.CurrAwardType >= 1 && self.CurrAwardType <= 16 {
// normal award
self.CurrTargetSlot = self.CurrAwardSlots[0]
2025-06-14 22:49:29 +08:00
} else if self.CurrAwardType == 100 {
self.CurrTargetSlot = 10
} else if self.CurrAwardType == 101 {
self.CurrTargetSlot = 22
2025-06-11 22:17:19 +08:00
} else {
// special award
2025-06-12 22:04:02 +08:00
if rand.Intn(2) == 0 {
self.CurrTargetSlot = 10
} else {
self.CurrTargetSlot = 22
}
2025-06-11 22:17:19 +08:00
}
awardRank := make([]*serverproto.FruitPlayerAwardInfo, 0)
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
2025-06-14 22:49:29 +08:00
sumAwardChipNum, awardChipInfo := self.CheckPlayerAward(player.CurrBetInfo, awardSlotType_2_awardSlotId, rollResult.SlotTypes)
player.CurrAwardChipNum = sumAwardChipNum
player.CurrAwardChipInfo = awardChipInfo
2025-06-11 22:17:19 +08:00
player.ChipNum += player.CurrAwardChipNum
self.PoolChipNum = self.PoolChipNum - player.CurrAwardChipNum
if self.PoolChipNum < 0 {
self.PoolChipNum = 0
}
if player.CurrAwardChipNum > 0 {
awardRank = append(awardRank, &serverproto.FruitPlayerAwardInfo{
Uid: player.Uid,
Name: player.Name,
AwardChipNum: player.CurrAwardChipNum,
})
}
}
sort.Slice(awardRank, func(i, j int) bool {
return awardRank[i].AwardChipNum > awardRank[j].AwardChipNum
2025-06-10 21:56:29 +08:00
})
2025-06-11 22:17:19 +08:00
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
ntfMsg := &serverproto.SCFruitSettleNtf{
Uid: uid,
MyChipNum: player.ChipNum,
2025-06-12 22:04:02 +08:00
AwardType: self.CurrAwardType,
2025-06-11 22:17:19 +08:00
AwardChipNum: player.CurrAwardChipNum,
2025-06-12 22:04:02 +08:00
AwardSlots: self.CurrAwardSlots,
2025-06-14 22:49:29 +08:00
AwardChipInfo: player.CurrAwardChipInfo,
2025-06-12 22:04:02 +08:00
SettleHistory: self.SettleHistory,
StartSlot: self.CurrStartSlot,
TargetSlot: self.CurrTargetSlot,
2025-06-11 22:17:19 +08:00
AwardItems: make([]int32, 0),
}
SendToAllGame(ntfMsg)
}
2025-06-12 22:04:02 +08:00
self.CurrPlayerAwardRank = self.GetPlayerRank(awardRank)
if len(self.CurrPlayerAwardRank) > 0 {
2025-06-11 22:17:19 +08:00
for _, player := range FruitMgr.players {
2025-06-12 22:04:02 +08:00
awardRankNtfMsg := &serverproto.SCFruitPlayerAwardRankNtf{
Uid: player.Uid,
AwardType: self.CurrAwardType,
PlayerAwardRank: self.CurrPlayerAwardRank,
2025-06-11 22:17:19 +08:00
}
SendToAllGame(awardRankNtfMsg)
}
}
}
func (self *FruitRoom) RecordSettleHistory(awardType int32) {
2025-06-12 22:04:02 +08:00
if len(self.SettleHistory) < MAX_SETTLE_HISTORY_COUNT {
self.SettleHistory = append(self.SettleHistory, awardType)
2025-06-11 22:17:19 +08:00
} else {
newSettleHistory := make([]int32, 0)
2025-06-12 22:04:02 +08:00
for i := 1; i < len(self.SettleHistory); i++ {
newSettleHistory = append(newSettleHistory, self.SettleHistory[i])
2025-06-11 22:17:19 +08:00
}
newSettleHistory = append(newSettleHistory, awardType)
2025-06-12 22:04:02 +08:00
self.SettleHistory = newSettleHistory
2025-06-11 22:17:19 +08:00
}
}
func (self *FruitRoom) RandomSlot(slots []string, excludeSlots []string) string {
tempSlots := make([]string, 0)
for _, v := range slots {
isFind := false
for _, vv := range excludeSlots {
if vv == v {
isFind = true
break
}
}
if isFind == false {
tempSlots = append(tempSlots, v)
}
}
idx := rand.Intn(len(tempSlots))
return tempSlots[idx]
}
2025-06-10 21:56:29 +08:00
func (self *FruitRoom) SecTick() {
2025-06-14 22:49:29 +08:00
totalBetInfo := make([]*serverproto.FruitSlotInfo, 0)
2025-06-10 21:56:29 +08:00
var i int32
for i = 1; i <= 8; i++ {
slotTotalBetNum := self.TotalBetInfo[i]
2025-06-14 22:49:29 +08:00
totalBetInfo = append(totalBetInfo, &serverproto.FruitSlotInfo{
Slot: i,
Num: slotTotalBetNum,
2025-06-10 21:56:29 +08:00
})
}
2025-06-11 22:17:19 +08:00
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
ntfMsg := &serverproto.SCFruitSecTickNtf{
Uid: uid,
2025-06-12 22:04:02 +08:00
Sec: DURATION_BET_SEC - self.Sec,
2025-06-11 22:17:19 +08:00
PoolChipNum: uint32(self.PoolChipNum),
TotalBetInfo: totalBetInfo,
}
SendToAllGame(ntfMsg)
2025-06-10 21:56:29 +08:00
}
}
func (self *FruitRoom) Update() {
2025-06-10 21:56:29 +08:00
if len(self.uidList) == 0 {
//return
}
2025-06-12 22:04:02 +08:00
self.Sec++
2025-06-10 21:56:29 +08:00
//log.Println(self.stage, self.sec)
2025-06-12 22:04:02 +08:00
switch self.Stage {
case ROOM_STAGE_BET:
2025-06-12 22:04:02 +08:00
if self.Sec > DURATION_BET_SEC {
2025-06-10 21:56:29 +08:00
self.JumpStage(ROOM_STAGE_SETTLE)
break
}
2025-06-10 21:56:29 +08:00
self.SecTick()
case ROOM_STAGE_SETTLE:
2025-06-12 22:04:02 +08:00
if self.Sec > DURATION_SETTLE_SEC {
2025-06-10 21:56:29 +08:00
self.JumpStage(ROOM_STAGE_BET)
break
}
}
}