2025-06-11 22:17:19 +08:00

345 lines
8.7 KiB
Go

package model
import (
"math/rand"
"rocommon/util"
"roserver/serverproto"
"sort"
"strconv"
)
const (
ROOM_STAGE_BET = 1 //押注阶段
ROOM_STAGE_SETTLE = 2 //开奖阶段
DURATION_BET_SEC = 2
DURATION_SETTLE_SEC = 1
MAX_POOL_CHIP = 10000
MAX_SETTLE_HISTORY_COUNT = 7
AWARD_TYPE_NORMAL = 1
AWARD_TYPE_SPECIAL = 2
)
type FruitRoom struct {
roomId int32
stage int32
sec int32
uidList []uint64
PoolChipNum int32
TotalBetInfo map[int32]int32
settleHistory []int32
currAwardType int32
currAwardSlots []int32
currStartSlot int32
currTargetSlot int32
}
type FruitRateInfo struct {
AwardType int32
SlotTypes []string
Rate int32
DRate int32
ZRate int32
FinalRate int32
}
func newFruitRoom(roomId int32) *FruitRoom {
room := &FruitRoom{
roomId: roomId,
stage: ROOM_STAGE_BET,
sec: 0,
uidList: make([]uint64, 0),
PoolChipNum: 0,
TotalBetInfo: make(map[int32]int32),
settleHistory: make([]int32, 0),
currAwardType: 16,
currAwardSlots: []int32{4},
currStartSlot: 4,
currTargetSlot: 4,
}
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)
}
}
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)
}
func (self *FruitRoom) Bet(uid uint64, betInfo []*serverproto.FruitSlotBetInfo) serverproto.ErrorCode {
if self.stage != ROOM_STAGE_BET {
return serverproto.ErrorCode_ERROR_FRUIT_CURR_STAGE_CANNOT_BET
}
player := FruitMgr.GetPlayer(uid)
for _, v := range betInfo {
slot := v.Slot
betNum := v.BetNum
if player.ChipNum >= betNum {
player.ChipNum -= betNum
player.CurrBetInfo[slot] += betNum
self.TotalBetInfo[slot] += betNum
self.PoolChipNum += betNum
} else {
return serverproto.ErrorCode_ERROR_FRUIT_CHIP_INSUFFICIENT
}
}
return serverproto.ErrorCode_ERROR_OK
}
func (self *FruitRoom) JumpStage(stage int32) {
self.stage = stage
self.sec = 0
switch stage {
case ROOM_STAGE_BET:
self.StartBet()
case ROOM_STAGE_SETTLE:
self.Settle()
}
}
// 开始押注
func (self *FruitRoom) StartBet() {
self.ResetTotalBetInfo()
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
player.ResetBetInfo()
}
}
// 开奖
func (self *FruitRoom) Roll(rateItems []*FruitRateInfo) *FruitRateInfo {
var sumRate int32 = 0
for i := 0; i < len(rateItems); i++ {
rateItems[i].FinalRate = rateItems[i].Rate + rateItems[i].DRate*int32(self.PoolChipNum)/MAX_POOL_CHIP
sumRate += rateItems[i].FinalRate
}
randomVal := rand.Intn(int(sumRate))
var tmpSumRate int32 = 1
for i := 0; i < len(rateItems); i++ {
tmpSumRate += rateItems[i].FinalRate
if randomVal <= int(tmpSumRate) {
return rateItems[i]
}
}
util.InfoF("ERR: Roll Fail, Use the First Element")
return rateItems[0]
}
func (self *FruitRoom) CheckPlayerAward(playerBetInfo map[int32]int32, slotTypes []string) int32 {
var sumAwardChip int32 = 0
for _, v := range slotTypes {
slotType, _ := strconv.Atoi(v)
slotTypeCfg := serverproto.FruitSlotTypeCfgLoader[int32(slotType)]
idx := slotType
if slotType > 8 {
idx = slotType - 8
}
betChipNum := playerBetInfo[int32(idx)]
sumAwardChip = betChipNum * slotTypeCfg.Times
}
return sumAwardChip
}
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
}
func (self *FruitRoom) Settle() {
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)
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)
}
tempAwardSlots := make([]int32, 0)
for _, v := range awardSlots {
slot, _ := strconv.Atoi(v)
tempAwardSlots = append(tempAwardSlots, int32(slot))
}
self.currAwardType = rollResult.AwardType
self.currAwardSlots = tempAwardSlots
self.currStartSlot = self.currTargetSlot
if self.currAwardType >= 1 && self.currAwardType <= 8 {
// normal small award
self.currTargetSlot = self.currAwardSlots[len(self.currAwardSlots)-1]
} else if self.currAwardType >= 9 && self.currAwardType <= 16 {
// normal big award
self.currTargetSlot = self.currAwardSlots[len(self.currAwardSlots)-1]
} else {
// special award
self.currTargetSlot = self.currAwardSlots[len(self.currAwardSlots)-1]
}
awardRank := make([]*serverproto.FruitPlayerAwardInfo, 0)
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
player.CurrAwardChipNum = self.CheckPlayerAward(player.CurrBetInfo, rollResult.SlotTypes)
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
})
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
player := FruitMgr.GetPlayer(uid)
ntfMsg := &serverproto.SCFruitSettleNtf{
Uid: uid,
MyChipNum: player.ChipNum,
AwardType: self.currAwardType,
AwardChipNum: player.CurrAwardChipNum,
AwardSlots: self.currAwardSlots,
SettleHistory: self.settleHistory,
StartSlot: self.currStartSlot,
TargetSlot: self.currTargetSlot,
AwardItems: make([]int32, 0),
}
SendToAllGame(ntfMsg)
}
awardPlayerRank := self.GetPlayerRank(awardRank)
if len(awardPlayerRank) > 0 {
for _, player := range FruitMgr.players {
awardRankNtfMsg := serverproto.SCFruitAwardRankNtf{
Uid: player.Uid,
AwardType: self.currAwardType,
AwardRank: awardPlayerRank,
}
SendToAllGame(awardRankNtfMsg)
}
}
}
func (self *FruitRoom) RecordSettleHistory(awardType int32) {
if len(self.settleHistory) < MAX_SETTLE_HISTORY_COUNT {
self.settleHistory = append(self.settleHistory, awardType)
} else {
newSettleHistory := make([]int32, 0)
for i := 1; i < len(self.settleHistory); i++ {
newSettleHistory = append(newSettleHistory, self.settleHistory[i])
}
newSettleHistory = append(newSettleHistory, awardType)
self.settleHistory = newSettleHistory
}
}
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]
}
func (self *FruitRoom) SecTick() {
totalBetInfo := make([]*serverproto.FruitSlotBetInfo, 0)
var i int32
for i = 1; i <= 8; i++ {
slotTotalBetNum := self.TotalBetInfo[i]
totalBetInfo = append(totalBetInfo, &serverproto.FruitSlotBetInfo{
Slot: i,
BetNum: slotTotalBetNum,
})
}
for i := 0; i < len(self.uidList); i++ {
uid := self.uidList[i]
ntfMsg := &serverproto.SCFruitSecTickNtf{
Uid: uid,
Sec: self.sec,
PoolChipNum: uint32(self.PoolChipNum),
TotalBetInfo: totalBetInfo,
}
SendToAllGame(ntfMsg)
}
}
func (self *FruitRoom) Update() {
if len(self.uidList) == 0 {
//return
}
self.sec++
//log.Println(self.stage, self.sec)
switch self.stage {
case ROOM_STAGE_BET:
if self.sec > DURATION_BET_SEC {
self.JumpStage(ROOM_STAGE_SETTLE)
break
}
self.SecTick()
case ROOM_STAGE_SETTLE:
if self.sec > DURATION_SETTLE_SEC {
self.JumpStage(ROOM_STAGE_BET)
break
}
}
}