package iceage import ( "encoding/json" "math" "math/rand" "time" "mongo.games.com/goserver/core/basic" "mongo.games.com/goserver/core/logger" "mongo.games.com/goserver/core/task" "mongo.games.com/game/common" rule "mongo.games.com/game/gamerule/iceage" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/model" "mongo.games.com/game/proto" "mongo.games.com/game/protocol/gamehall" "mongo.games.com/game/protocol/iceage" "mongo.games.com/game/protocol/server" "mongo.games.com/game/srvdata" ) type IceAgeJackpot struct { createdTime time.Time userName string priceValue int64 roomID int64 spinID string } type IceAgeSceneData struct { *base.Scene //房间信息 players map[int32]*IceAgePlayerData //玩家信息 jackpot *base.SlotJackpotPool //奖池 lastJackpotValue int64 //上一次奖池变化时的值 lastJackPot time.Time //增加奖池时间 lastBurstJackPot map[int32]time.Time //爆池时间 } func NewIceAgeSceneData(s *base.Scene) *IceAgeSceneData { return &IceAgeSceneData{ Scene: s, players: make(map[int32]*IceAgePlayerData), } } func (this *IceAgeSceneData) SaveData(force bool) { } func (this *IceAgeSceneData) OnPlayerLeave(p *base.Player, reason int) { if p, exist := this.players[p.SnId]; exist { delete(this.players, p.SnId) } } func (this *IceAgeSceneData) SceneDestroy(force bool) { //销毁房间 this.Scene.Destroy(force) } func (this *IceAgeSceneData) init() bool { if this.GetDBGameFree() == nil { return false } params := this.GetDBGameFree().GetJackpot() this.jackpot = &base.SlotJackpotPool{} if this.jackpot.Small <= 0 { this.jackpot.Small = 0 this.jackpot.VirtualJK = int64(params[rule.ICEAGE_JACKPOT_InitJackpot]) * int64(this.GetDBGameFree().GetBaseScore()) } str := base.SlotsPoolMgr.GetPool(this.GetGameFreeId(), this.GetPlatform()) if str != "" { jackpot := &base.SlotJackpotPool{} err := json.Unmarshal([]byte(str), jackpot) if err == nil { this.jackpot = jackpot } } if this.jackpot != nil { base.SlotsPoolMgr.SetPool(this.GetGameFreeId(), this.GetPlatform(), this.jackpot) } this.lastJackPot = time.Now() this.lastBurstJackPot = make(map[int32]time.Time) this.SetLastBurstJackPot() return true } const ( SlotsData = "SlotsData" SlotsData_V2 = "SlotsData_V2" BonusData = "BonusData" BonusData_V2 = "BonusData_V2" DefaultData = "DefaultData" DefaultData_v1 = "DefaultData_v1" ) func getElementDistributionByName(name string) *server.DB_IceAgeElementRate { for i := range srvdata.PBDB_IceAgeElementRateMgr.Datas.Arr { item := srvdata.PBDB_IceAgeElementRateMgr.GetData(int32(i + 1)) if item.GetModeName() == name { return item } } return nil } func getSlotsDataByElementDistribution(data []int32) []int { var t = make([]int, rule.ELEMENT_TOTAL) for i, _ := range t { t[i] = int(data[rand.Intn(len(data))]) } return t } func getSlotsDataByGroupName(name string) []int { cardLib := rule.MissData[name] if len(cardLib) > 0 { return cardLib[rand.Intn(len(cardLib))] } return nil } type SpinResult struct { LinesInfo []*iceage.IceAgeLinesInfo SlotsData []*iceage.IceAgeCards TotalPrizeLine int64 // 线条总金额+爆奖 TotalPrizeBonus int64 // 小游戏总金额 BonusGameCnt int32 // 小游戏次数 TotalPrizeJackpot int64 // 爆奖总金额 JackpotCnt int // 爆奖的次数 AddFreeTimes int32 // 新增免费次数 IsJackpot bool // 是否爆奖 TotalWinRate int32 // 中奖总倍率 TotalTaxScore int64 // 税收 WinLines [][]int // 赢分的线 } func (this *IceAgeSceneData) CalcSpinsPrize(cards []int, betLines []int64, distributionData []int32, bonusParams []int32, betValue int64, taxRate int32) (spinRes SpinResult) { tmpCards := make([]int, len(cards)) copy(tmpCards, cards) calcTaxScore := func(score int64, taxScore *int64) int64 { tmpTaxScore := int64(float64(score) * float64(taxRate) / 10000.0) *taxScore += tmpTaxScore return score - tmpTaxScore } for loopIndex := 0; loopIndex < 99; loopIndex++ { // 避免死循环 var winLines []int slotData := &iceage.IceAgeCards{} for _, card := range tmpCards { slotData.Card = append(slotData.Card, int32(card)) } spinRes.SlotsData = append(spinRes.SlotsData, slotData) lineCount := 0 for _, lineNum := range betLines { lineTemplate := rule.AllLineArray[int(lineNum)-1] edata := []int{} epos := []int32{} for _, pos := range lineTemplate { edata = append(edata, tmpCards[pos]) epos = append(epos, int32(pos)+1) } head, count := rule.IsLine(edata) if head == 0 || count <= 0 { continue } var spinFree, prizeJackpot, bonus int64 var prizesBonus = make([]int64, 0) if head == rule.Element_FREESPIN { spinFree = int64(rule.FreeSpinTimesRate[count-1]) } else if head == rule.Element_JACKPOT && count == 5 { spinRes.IsJackpot = true spinRes.JackpotCnt++ if spinRes.TotalPrizeJackpot == 0 { // 第一个爆奖 获取当前奖池所有 prizeJackpot = this.jackpot.VirtualJK } else { // 之后的爆奖 奖励为奖池初值 prizeJackpot = int64(this.GetDBGameFree().GetJackpot()[rule.ICEAGE_JACKPOT_InitJackpot]) * int64(this.GetDBGameFree().GetBaseScore()) } prizeJackpot = calcTaxScore(prizeJackpot, &spinRes.TotalTaxScore) spinRes.TotalPrizeJackpot += prizeJackpot } else if head == rule.Element_BONUS && count >= 3 { bonus = betValue * int64(len(betLines)) * int64(bonusParams[rand.Intn(len(bonusParams))]) bonus = calcTaxScore(bonus, &spinRes.TotalTaxScore) prizesBonus = []int64{bonus, bonus, bonus} // len大于0即可 spinRes.BonusGameCnt++ } curScore := int64(rule.LineScore[head][count-1]) * betValue curScore = calcTaxScore(curScore, &spinRes.TotalTaxScore) spinRes.TotalWinRate += int32(rule.LineScore[head][count-1]) spinRes.TotalPrizeLine += curScore + prizeJackpot spinRes.TotalPrizeBonus += bonus spinRes.AddFreeTimes += int32(spinFree) line := &iceage.IceAgeLinesInfo{ LineID: proto.Int32(int32(lineNum)), Turn: proto.Int32(int32(loopIndex + 1)), PrizeValue: proto.Int64(curScore + prizeJackpot), PrizesFreespin: proto.Int64(spinFree), PrizesJackport: proto.Int64(prizeJackpot), PrizesBonus: prizesBonus, Items: epos[:count], RoleID: proto.Int32(int32(head)), } spinRes.LinesInfo = append(spinRes.LinesInfo, line) winLines = append(winLines, int(line.GetLineID())) lineCount++ } if winLines != nil { spinRes.WinLines = append(spinRes.WinLines, winLines) } if loopIndex == 98 { logger.Logger.Error("IceAgeSpinTimes99", cards, betLines, distributionData, bonusParams, betValue, taxRate) } // 没有匹配的线条 不用消除处理 if lineCount == 0 { break } // 获取消除后的新线 tmpCards = rule.MakePlan(tmpCards, distributionData, betLines) if len(tmpCards) == 0 { break } } return } func (this *IceAgeSceneData) BroadcastJackpot(sync bool) { if this.lastJackpotValue != this.jackpot.VirtualJK || sync { this.lastJackpotValue = this.jackpot.VirtualJK pack := &gamehall.SCHundredSceneGetGameJackpot{} jpfi := &gamehall.GameJackpotFundInfo{ GameFreeId: proto.Int32(this.GetDBGameFree().Id), JackPotFund: proto.Int64(this.jackpot.VirtualJK), } pack.GameJackpotFund = append(pack.GameJackpotFund, jpfi) proto.SetDefaults(pack) //以平台为标识向该平台内所有玩家广播奖池变动消息,游戏内外的玩家可监听该消息,减少由gamesrv向worldsrv转发这一步 tags := []string{this.Platform} logger.Logger.Trace("jackpot avengers", pack) base.PlayerMgrSington.BroadcastMessageToGroup(int(gamehall.HundredScenePacketID_PACKET_SC_GAMEJACKPOT), pack, tags) } } func (this *IceAgeSceneData) PushCoinPool(prizeFundAdd int64, IsNovice bool) { if IsNovice { base.CoinPoolMgr.PushCoinNovice(this.GetGameFreeId(), this.GroupId, this.Platform, prizeFundAdd) } else { base.CoinPoolMgr.PushCoin(this.GetGameFreeId(), this.GroupId, this.Platform, prizeFundAdd) } } func (this *IceAgeSceneData) PopCoinPool(winCoin int64, IsNovice bool) { if IsNovice { base.CoinPoolMgr.PopCoinNovice(this.GetGameFreeId(), this.GroupId, this.Platform, winCoin) } else { base.CoinPoolMgr.PopCoin(this.GetGameFreeId(), this.GroupId, this.Platform, winCoin) } } func (this *IceAgeSceneData) RecordBurstLog(name string, wincoin, totalbet int64) { log := model.NewBurstJackpotLog(this.Platform, this.GetDBGameFree().GameId, this.GetGameFreeId(), name, wincoin, totalbet) task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { return model.InsertBurstJackpotLogs(log) }), nil, "InsertBurstJackpotLogs").Start() } func (this *IceAgeSceneData) BurstHistory(player *IceAgePlayerData) { task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { return model.GetBurstJackpotLog(this.Platform, this.GetDBGameFree().GameId) }), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) { var logsp []*iceage.IceAgeBurstHistoryInfo if data != nil { logs := data.([]model.BurstJackpotLog) if len(logs) > 0 { for _, log := range logs { logsp = append(logsp, &iceage.IceAgeBurstHistoryInfo{ UserName: log.Name, PriceValue: log.WinCoin, TotalBet: log.TotalBet, Ts: log.Ts, }) } } } pack := &iceage.SCIceAgeBurstHistoryInfo{ BurstLog: logsp, } logger.Logger.Trace("SCIceAgeBurstHistoryInfo:", pack) player.SendToClient(int(iceage.IceAgePacketID_PACKET_SC_ICEAGE_BURSTHISTORY), pack) }), "BurstHistory").Start() } func (this *IceAgeSceneData) GetLastBurstJackPot() time.Time { return this.lastBurstJackPot[this.GetGameFreeId()] } func (this *IceAgeSceneData) SetLastBurstJackPot() { var randT = rand.Intn(25200-7200+1) + 7200 switch this.GetDBGameFree().SceneType { case 1: randT = rand.Intn(25200-7200+1) + 7200 case 2: randT = rand.Intn(108000-72000+1) + 72000 case 3: randT = rand.Intn(180000-108000+1) + 108000 } this.lastBurstJackPot[this.GetGameFreeId()] = time.Now().Add(time.Second * time.Duration(randT)) } func (this *IceAgeSceneData) AIAddJackPot() { if time.Now().Sub(this.lastJackPot) > 0 { var randT = rand.Intn(3) + 1 switch this.GetDBGameFree().SceneType { case 1: randT = rand.Intn(3) + 1 case 2: randT = rand.Intn(12-5) + 6 case 3: randT = rand.Intn(20-9) + 10 default: randT = rand.Intn(3) + 1 } this.lastJackPot = time.Now().Add(time.Second * time.Duration(randT)) val := int64(math.Floor(float64(this.GetDBGameFree().GetBaseScore()) * float64(rule.LINENUM) * float64(500) / 10000)) this.jackpot.VirtualJK += val } } func (this *IceAgeSceneData) AIBurstJackPot() { if time.Now().Sub(this.GetLastBurstJackPot()) > 0 { this.SetLastBurstJackPot() jackpotParams := this.GetDBGameFree().GetJackpot() var jackpotInit = int64(jackpotParams[rule.ICEAGE_JACKPOT_InitJackpot]) * int64(this.GetDBGameFree().GetBaseScore()) //奖池初始值 //AI机器人爆奖 val := this.jackpot.VirtualJK this.jackpot.VirtualJK = jackpotInit bet := int64(this.GetDBGameFree().GetBaseScore()) * int64(rule.LINENUM) this.RecordBurstLog(this.RandNickName(), val, bet) } } func (this *IceAgeSceneData) KickPlayerByTime() { if time.Now().Sub(this.GameStartTime) > time.Second*3 { this.GameStartTime = time.Now() for _, p := range this.players { if p.IsOnLine() { p.leavetime = 0 continue } p.leavetime++ if p.leavetime < 60 { continue } //踢出玩家 this.PlayerLeave(p.Player, common.PlayerLeaveReason_LongTimeNoOp, true) } //for _, p := range this.players { // //游戏次数达到目标值 // todayGamefreeIDSceneData, _ := p.GetDaliyGameData(int(this.GetDBGameFree().GetId())) // if !p.IsRob && // todayGamefreeIDSceneData != nil && // this.GetDBGameFree().GetPlayNumLimit() != 0 && // todayGamefreeIDSceneData.GameTimes >= int64(this.GetDBGameFree().GetPlayNumLimit()) { // this.PlayerLeave(p.Player, common.PlayerLeaveReason_GameTimes, true) // } //} if this.CheckNeedDestroy() { for _, player := range this.players { if !player.IsRob { if time.Now().Sub(player.LastOPTimer) > 10*time.Second { //离开有统计 this.PlayerLeave(player.Player, common.PlayerLeaveReason_OnDestroy, true) } } } if this.GetRealPlayerCnt() == 0 { this.SceneDestroy(true) } } } }