364 lines
9.4 KiB
Go
364 lines
9.4 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 = 15
|
|
DURATION_SETTLE_SEC = 5
|
|
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
|
|
CurrPlayerAwardRank []*serverproto.FruitPlayerAwardInfo
|
|
}
|
|
|
|
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)
|
|
self.CurrAwardType = rollResult.AwardType
|
|
if rollResult.AwardType == 100 {
|
|
slotTypeStr := rollResult.SlotTypes[rand.Intn(len(rollResult.SlotTypes))]
|
|
slotType, _ := strconv.Atoi(slotTypeStr)
|
|
awardSlots := make([]string, 0)
|
|
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.CurrAwardSlots = tempAwardSlots
|
|
self.CurrStartSlot = self.CurrTargetSlot
|
|
} else if rollResult.AwardType >= 101 {
|
|
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.CurrAwardSlots = tempAwardSlots
|
|
self.CurrStartSlot = self.CurrTargetSlot
|
|
}
|
|
|
|
if self.CurrAwardType >= 1 && self.CurrAwardType <= 16 {
|
|
// normal award
|
|
self.CurrTargetSlot = self.CurrAwardSlots[0]
|
|
} else {
|
|
// special award
|
|
if rand.Intn(2) == 0 {
|
|
self.CurrTargetSlot = 10
|
|
} else {
|
|
self.CurrTargetSlot = 22
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
self.CurrPlayerAwardRank = self.GetPlayerRank(awardRank)
|
|
if len(self.CurrPlayerAwardRank) > 0 {
|
|
for _, player := range FruitMgr.players {
|
|
awardRankNtfMsg := &serverproto.SCFruitPlayerAwardRankNtf{
|
|
Uid: player.Uid,
|
|
AwardType: self.CurrAwardType,
|
|
PlayerAwardRank: self.CurrPlayerAwardRank,
|
|
}
|
|
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: DURATION_BET_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
|
|
}
|
|
}
|
|
|
|
}
|