345 lines
8.7 KiB
Go
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
|
|
}
|
|
}
|
|
|
|
}
|