340 lines
11 KiB
Go
340 lines
11 KiB
Go
package caishen
|
||
|
||
import (
|
||
"encoding/json"
|
||
"math"
|
||
"math/rand"
|
||
"time"
|
||
|
||
"mongo.games.com/goserver/core/basic"
|
||
"mongo.games.com/goserver/core/task"
|
||
|
||
"mongo.games.com/game/common"
|
||
rule "mongo.games.com/game/gamerule/caishen"
|
||
"mongo.games.com/game/gamesrv/base"
|
||
"mongo.games.com/game/model"
|
||
"mongo.games.com/game/proto"
|
||
"mongo.games.com/game/protocol/caishen"
|
||
"mongo.games.com/game/protocol/gamehall"
|
||
"mongo.games.com/goserver/core/logger"
|
||
)
|
||
|
||
type CaiShenJackpot struct {
|
||
createdTime time.Time
|
||
userName string
|
||
priceValue int64
|
||
roomID int64
|
||
spinID string
|
||
}
|
||
|
||
type CaiShenSceneData struct {
|
||
*base.Scene //房间信息
|
||
players map[int32]*CaiShenPlayerData //玩家信息
|
||
jackpot *base.SlotJackpotPool //奖池
|
||
lastJackpotValue int64 //上一次奖池变化时的值
|
||
lastJackPot time.Time //增加奖池时间
|
||
lastBurstJackPot map[int32]time.Time //爆池时间
|
||
}
|
||
|
||
func NewCaiShenSceneData(s *base.Scene) *CaiShenSceneData {
|
||
return &CaiShenSceneData{
|
||
Scene: s,
|
||
players: make(map[int32]*CaiShenPlayerData),
|
||
jackpot: &base.SlotJackpotPool{},
|
||
}
|
||
}
|
||
|
||
func (this *CaiShenSceneData) SaveData(force bool) {
|
||
}
|
||
|
||
func (this *CaiShenSceneData) OnPlayerLeave(p *base.Player, reason int) {
|
||
if p, exist := this.players[p.SnId]; exist {
|
||
delete(this.players, p.SnId)
|
||
}
|
||
}
|
||
|
||
func (this *CaiShenSceneData) SceneDestroy(force bool) {
|
||
//销毁房间
|
||
this.Scene.Destroy(force)
|
||
}
|
||
|
||
func (this *CaiShenSceneData) 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.CAISHEN_JACKPOT_InitJackpot]) * int64(this.GetDBGameFree().GetBaseScore())
|
||
}
|
||
str := base.XSlotsPoolMgr.GetPool(this.GetGameFreeId(), this.Platform)
|
||
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.Platform, this.jackpot)
|
||
}
|
||
this.lastJackPot = time.Now()
|
||
this.lastBurstJackPot = make(map[int32]time.Time)
|
||
this.SetLastBurstJackPot()
|
||
return true
|
||
}
|
||
|
||
type CaiShenSpinResult struct {
|
||
LinesInfo []*caishen.CaiShenLinesInfo
|
||
SlotsData []int32
|
||
TotalPrizeLine int64 // 线条总金额
|
||
TotalPrizeJackpot int64 // 爆奖总金额
|
||
JackpotCnt int // 爆奖的次数
|
||
AddFreeTimes int32 // 新增免费次数
|
||
IsJackpot bool // 是否爆奖
|
||
BonusGame caishen.CaiShenBonusGameInfo
|
||
BonusX []int32
|
||
TotalWinRate int32 // 中奖总倍率
|
||
TotalTaxScore int64 // 税收
|
||
WinLines []int // 赢分的线
|
||
}
|
||
|
||
func (this *CaiShenSceneData) CalcLinePrize(cards []int, betLines []int64, betValue int64) (spinRes CaiShenSpinResult) {
|
||
taxRate := this.GetDBGameFree().GetTaxRate()
|
||
calcTaxScore := func(score int64, taxScore *int64) int64 {
|
||
newScore := int64(float64(score) * float64(10000-taxRate) / 10000.0)
|
||
if taxScore != nil {
|
||
*taxScore += score - newScore
|
||
}
|
||
return newScore
|
||
}
|
||
|
||
lines := rule.CalcLine(cards, betLines)
|
||
for _, line := range lines {
|
||
if line.Element == rule.Element_JACKPOT && line.Count == rule.LINE_CELL {
|
||
spinRes.IsJackpot = true
|
||
spinRes.JackpotCnt++
|
||
}
|
||
|
||
curScore := betValue * int64(line.Score)
|
||
curScore = calcTaxScore(curScore, &spinRes.TotalTaxScore)
|
||
spinRes.TotalPrizeLine += curScore
|
||
spinRes.TotalWinRate += int32(line.Score)
|
||
|
||
lineInfo := &caishen.CaiShenLinesInfo{
|
||
LineId: proto.Int32(int32(line.Index)),
|
||
Position: line.Position,
|
||
PrizeValue: proto.Int64(curScore),
|
||
}
|
||
spinRes.LinesInfo = append(spinRes.LinesInfo, lineInfo)
|
||
spinRes.WinLines = append(spinRes.WinLines, int(lineInfo.GetLineId()))
|
||
}
|
||
|
||
if spinRes.IsJackpot { // 爆奖只计一条线
|
||
spinRes.TotalPrizeJackpot = calcTaxScore(this.jackpot.VirtualJK, &spinRes.TotalTaxScore)
|
||
}
|
||
|
||
var countBonus, countFree int
|
||
for _, card := range cards {
|
||
if card == rule.Element_BONUS {
|
||
countBonus++
|
||
}
|
||
if card == rule.Element_SCATTER {
|
||
countFree++
|
||
}
|
||
spinRes.SlotsData = append(spinRes.SlotsData, int32(card))
|
||
}
|
||
|
||
// bonus game
|
||
if countBonus >= 3 {
|
||
if countBonus == 3 {
|
||
spinRes.BonusX = []int32{1, 2, 3}
|
||
} else if countBonus == 4 {
|
||
spinRes.BonusX = []int32{2, 3, 4}
|
||
} else {
|
||
spinRes.BonusX = []int32{3, 4, 5}
|
||
countBonus = 5
|
||
}
|
||
totalBet := int64(len(betLines)) * betValue
|
||
bonusGame := rule.GenerateBonusGame(int(totalBet), countBonus-2)
|
||
var totalBonusValue int64
|
||
bonusData := make([]int64, 0)
|
||
for _, value := range bonusGame.BonusData {
|
||
value = calcTaxScore(value, nil)
|
||
totalBonusValue += value
|
||
bonusData = append(bonusData, value)
|
||
}
|
||
spinRes.BonusGame = caishen.CaiShenBonusGameInfo{
|
||
TotalPrizeValue: proto.Int64(totalBonusValue * int64(bonusGame.Mutiplier)),
|
||
Mutiplier: proto.Int32(int32(bonusGame.Mutiplier)),
|
||
DataMultiplier: proto.Int64(int64(totalBonusValue)),
|
||
BonusData: bonusData,
|
||
}
|
||
// 小游戏税收
|
||
bonusTax := (bonusGame.DataMultiplier - totalBonusValue) * int64(bonusGame.Mutiplier)
|
||
spinRes.TotalTaxScore += bonusTax
|
||
}
|
||
|
||
// add free
|
||
if countFree >= 3 {
|
||
spinRes.AddFreeTimes = int32(countFree-2) * 4
|
||
}
|
||
return
|
||
}
|
||
func (this *CaiShenSceneData) 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 caishen", pack)
|
||
base.PlayerMgrSington.BroadcastMessageToGroup(int(gamehall.HundredScenePacketID_PACKET_SC_GAMEJACKPOT), pack, tags)
|
||
}
|
||
}
|
||
|
||
func (this *CaiShenSceneData) 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 *CaiShenSceneData) 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 *CaiShenSceneData) 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 *CaiShenSceneData) BurstHistory(player *CaiShenPlayerData) {
|
||
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 []*caishen.CaiShenBurstHistoryInfo
|
||
if data != nil {
|
||
logs := data.([]model.BurstJackpotLog)
|
||
if len(logs) > 0 {
|
||
for _, log := range logs {
|
||
logsp = append(logsp, &caishen.CaiShenBurstHistoryInfo{
|
||
UserName: log.Name,
|
||
PriceValue: log.WinCoin,
|
||
TotalBet: log.TotalBet,
|
||
Ts: log.Ts,
|
||
})
|
||
}
|
||
}
|
||
}
|
||
pack := &caishen.SCCaiShenBurstHistory{
|
||
BurstLog: logsp,
|
||
}
|
||
logger.Logger.Trace("SCCaiShenBurstHistory:", pack)
|
||
player.SendToClient(int(caishen.CaiShenPacketID_PACKET_SC_CAISHEN_BURSTHISTORY), pack)
|
||
}), "BurstHistory").Start()
|
||
}
|
||
func (this *CaiShenSceneData) GetLastBurstJackPot() time.Time {
|
||
return this.lastBurstJackPot[this.GetGameFreeId()]
|
||
}
|
||
func (this *CaiShenSceneData) 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(46800-32400+1) + 32400
|
||
case 3:
|
||
randT = rand.Intn(108000-72000+1) + 72000
|
||
case 4:
|
||
randT = rand.Intn(180000-108000+1) + 108000
|
||
}
|
||
this.lastBurstJackPot[this.GetGameFreeId()] = time.Now().Add(time.Second * time.Duration(randT))
|
||
}
|
||
|
||
func (this *CaiShenSceneData) 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(6-1) + 2
|
||
case 3:
|
||
randT = rand.Intn(12-5) + 6
|
||
case 4:
|
||
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 *CaiShenSceneData) AIBurstJackPot() {
|
||
if time.Now().Sub(this.GetLastBurstJackPot()) > 0 {
|
||
this.SetLastBurstJackPot()
|
||
jackpotParams := this.GetDBGameFree().GetJackpot()
|
||
var jackpotInit = int64(jackpotParams[rule.CAISHEN_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, int64(bet))
|
||
}
|
||
}
|
||
func (this *CaiShenSceneData) 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)
|
||
}
|
||
}
|
||
}
|
||
}
|