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 } } }